/** * @file cf_codec.c * @author myusgun */ #include "cf_codec.h" #include "cf_error.h" #include #include #define ASSERT_ARGS(x) \ if ((x)) \ return CF_ERROR_CODEC_INVALID_ARGS const static unsigned char g_ascii_HexDecode[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00 - 15 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16 - 31 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 32 - 47 */ '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',0x00,0x00,0x00,0x00,0x00,0x00, /* 48 - 63 */ 0x00, 'A', 'A', 'A', 'A', 'A', 'A',0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 64 - 79 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 80 - 95 */ 0x00, 'a', 'a', 'a', 'a', 'a', 'a',0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 96 - 111 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 112 - 127 */ /* end of ascii character */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128 - 143 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144 - 159 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160 - 175 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176 - 191 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192 - 207 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208 - 223 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224 - 239 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240 - 255 */ }; const static char g_table_Base64Encode[] = { #define BASE64_PADDING_CHAR_INDEX 64 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', /* 00 - 07 */ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 08 - 15 */ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', /* 16 - 23 */ 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', /* 24 - 31 */ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', /* 32 - 39 */ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', /* 40 - 47 */ 'w', 'x', 'y', 'z', '0', '1', '2', '3', /* 48 - 55 */ '4', '5', '6', '7', '8', '9', '+', '/', /* 56 - 63 */ '=' /* padding */ }; const static unsigned char g_ascii_Base64Decode[] = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 00 - 15 */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 16 - 31 */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 62,0xff,0xff,0xff, 63, /* 32 - 47 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,0xff,0xff,0xff, 64,0xff,0xff, /* 48 - 63 */ 0xff, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 64 - 79 */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,0xff,0xff,0xff,0xff,0xff, /* 80 - 95 */ 0xff, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 96 - 111 */ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,0xff,0xff,0xff,0xff,0xff, /* 112 - 127 */ /* end of ascii character */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 128 - 143 */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 144 - 159 */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 160 - 175 */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 176 - 191 */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 192 - 207 */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 208 - 223 */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 224 - 239 */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 240 - 255 */ }; /** * hex-encode * * @return 성공 시, CF_OK; 실패 시, 오류 코드 * * @param bin 바이너리 데이터 * @param len 바이너리 데이터 길이 * @param hex 16진수 문자열을 저장할 주소 * * @remark * hex는 할당된 메모리이며, 크기는 '\0'를 제외하고 len * 2 */ int CF_Codec_Hex_Encode (const unsigned char * bin, const size_t len, char * hex) { size_t iter = 0; size_t hexlen = len * 2 + 1; const unsigned char * ptr = bin; const static char hexchar[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; ASSERT_ARGS (bin == NULL); ASSERT_ARGS (hex == NULL); for (iter = 0 ; iter < hexlen ; iter += 2, ptr++) { hex[iter ] = hexchar[((*(ptr)) >> 4) & 0x0f]; hex[iter + 1] = hexchar[((*(ptr)) ) & 0x0f]; } hex[hexlen - 1] = '\0'; return CF_OK; } /** * hex-decode * * @return 성공 시, 디코딩된 바이너리 데이터의 길이; 실패 시, 오류 코드 * * @param hex 16진수 문자열 * @param bin 바이너리 데이터를 저장할 주소 * * @remark * bin는 할당된 메모리이며, 크기는 strlen (hex) / 2 */ int CF_Codec_Hex_Decode (const char * hex, unsigned char * bin) { size_t length = strlen (hex); /* absolutely even-number */ size_t iter = 0; int binlen = (int)length / 2; const char * ptr = hex; char buf = 0; unsigned char val = 0; unsigned char asciiHex = 0; ASSERT_ARGS (hex == NULL); ASSERT_ARGS (bin == NULL); for (iter = 0 ; iter < binlen ; iter++) { val = 0; /* init/re-init docoding-buffer */ /* decode one character */ #define DECODE_HEX(x) \ do { \ buf = *(x); \ val = (unsigned char)(val << 4); \ asciiHex = g_ascii_HexDecode[(int)buf]; \ \ if (buf) \ val |= (unsigned char) \ (buf - asciiHex + (asciiHex == '0' ? 0 : 10)); \ else \ return CF_ERROR_CODEC_NOT_HEXSTRING; \ } while (0) /* decode one byte by decode two character */ DECODE_HEX (ptr++); DECODE_HEX (ptr++); bin[iter] = val; } return binlen; } /** * Base64-encode * * @return 성공 시, CF_OK; 실패 시, 오류 코드 * * @param bin 바이너리 데이터 * @param len 바이너리 데이터 길이 * @param base64 base64 문자열을 저장할 주소 * * @remark * base64는 할당된 메모리이며, 크기는 '\0'를 제외하고 ((len + 2) / 3) * 4 */ int CF_Codec_Base64_Encode (const unsigned char * bin, const size_t len, char * base64) { const unsigned char * src = bin; char * dst = base64; ASSERT_ARGS (src == NULL); ASSERT_ARGS (dst == NULL); #define SEXTUPLE_E_1(__x) (((__x[0]) >> 2) & 0x3f) #define SEXTUPLE_E_2(__x) (((__x[0]) << 4) & 0x30) #define SEXTUPLE_E_3(__x) (((__x[1]) >> 4) & 0x0f) #define SEXTUPLE_E_4(__x) (((__x[1]) << 2) & 0x3c) #define SEXTUPLE_E_5(__x) (((__x[2]) >> 6) & 0x03) #define SEXTUPLE_E_6(__x) (((__x[2]) ) & 0x3f) for ( ; src - bin < len - 2 ; src += 3) { *dst++ = g_table_Base64Encode[SEXTUPLE_E_1 (src)]; *dst++ = g_table_Base64Encode[SEXTUPLE_E_2 (src)| SEXTUPLE_E_3 (src)]; *dst++ = g_table_Base64Encode[SEXTUPLE_E_4 (src)| SEXTUPLE_E_5 (src)]; *dst++ = g_table_Base64Encode[SEXTUPLE_E_6 (src)]; } if (src - bin < len) { *dst++ = g_table_Base64Encode[SEXTUPLE_E_1 (src)]; if (src - bin == len - 1) { *dst++ = g_table_Base64Encode[SEXTUPLE_E_2 (src)]; *dst++ = g_table_Base64Encode[BASE64_PADDING_CHAR_INDEX]; } else { *dst++ = g_table_Base64Encode[SEXTUPLE_E_2 (src)| SEXTUPLE_E_3 (src)]; *dst++ = g_table_Base64Encode[SEXTUPLE_E_4 (src)]; } *dst++ = g_table_Base64Encode[BASE64_PADDING_CHAR_INDEX]; } *dst = '\0'; return CF_OK; } /** * Base64-decode * * @return 성공 시, 디코딩된 바이너리 데이터의 길이; 실패 시, 오류 코드 * * @param base64 base64 문자열 * @param bin 바이너리 데이터를 저장할 주소 * * @remark * base64는 할당된 메모리이며, 크기는 (strlen (base64)) / 4 * 3 */ int CF_Codec_Base64_Decode (const char * base64, unsigned char * bin) { const char * src = base64; unsigned char * dst = bin; int remain = 0; int binlen = 0; ASSERT_ARGS (src == NULL); ASSERT_ARGS (dst == NULL); while (g_ascii_Base64Decode[(int)*src] < BASE64_PADDING_CHAR_INDEX) src++; if (*src == 0xff) return CF_ERROR_CODEC_NOT_BASE64; remain = (int)(src - base64); binlen = ((remain + 2/* max padding length */) / 4) * 3; #define SEXTUPLE_D_1(src) (g_ascii_Base64Decode[(int)src[0]] << 2) #define SEXTUPLE_D_2(src) (g_ascii_Base64Decode[(int)src[1]] >> 4) #define SEXTUPLE_D_3(src) (g_ascii_Base64Decode[(int)src[1]] << 4) #define SEXTUPLE_D_4(src) (g_ascii_Base64Decode[(int)src[2]] >> 2) #define SEXTUPLE_D_5(src) (g_ascii_Base64Decode[(int)src[2]] << 6) #define SEXTUPLE_D_6(src) (g_ascii_Base64Decode[(int)src[3]] ) for (src = base64 ; remain > 4 ; remain -= 4, src += 4) { *dst++ = (unsigned char)(SEXTUPLE_D_1 (src) | SEXTUPLE_D_2 (src)); *dst++ = (unsigned char)(SEXTUPLE_D_3 (src) | SEXTUPLE_D_4 (src)); *dst++ = (unsigned char)(SEXTUPLE_D_5 (src) | SEXTUPLE_D_6 (src)); } if (remain > 1) *dst++ = (unsigned char)(SEXTUPLE_D_1 (src) | SEXTUPLE_D_2 (src)); if (remain > 2) *dst++ = (unsigned char)(SEXTUPLE_D_3 (src) | SEXTUPLE_D_4 (src)); if (remain > 3) *dst++ = (unsigned char)(SEXTUPLE_D_5 (src) | SEXTUPLE_D_6 (src)); return binlen - (4 - remain); }