/** * @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[] = { #define ASCN '0' /* ascii number */ #define ASCU 'A' /* ascii upper */ #define ASCL 'a' /* ascii lower */ 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 */ ASCN,ASCN,ASCN,ASCN,ASCN,ASCN,ASCN,ASCN,ASCN,ASCN,0x00,0x00,0x00,0x00,0x00,0x00, /* 48 - 63 */ 0x00,ASCU,ASCU,ASCU,ASCU,ASCU,ASCU,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,ASCL,ASCL,ASCL,ASCL,ASCL,ASCL,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 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[] = { 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, /* 00 - 15 */ 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, /* 16 - 31 */ 99,99,99,99,99,99,99,99,99,99,99,62,99,99,99,63, /* 32 - 47 */ 52,53,54,55,56,57,58,59,60,61,99,99,99,64,99,99, /* 48 - 63 */ 99, 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,99,99,99,99,99, /* 80 - 95 */ 99,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,99,99,99,99,99, /* 112 - 127 */ /* end of ascii character */ 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, /* 128 - 143 */ 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, /* 144 - 159 */ 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, /* 160 - 175 */ 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, /* 176 - 191 */ 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, /* 192 - 207 */ 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, /* 208 - 223 */ 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, /* 224 - 239 */ 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, /* 240 - 255 */ }; /** * hex-encode * * @return 성공 시, CF_OK; 실패 시, 오류 코드 * * @param bin 바이너리 데이터 * @param len 바이너리 데이터 길이 * @param hex 16진수 문자열을 저장할 주소 * * @remark * hex는 할당된 메모리이며, 크기는 '\0'를 포함하여 len * 2 + 1 */ 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 성공 시, CF_OK; 실패 시, 오류 코드 * * @param hex 16진수 문자열 * @param bin 바이너리 데이터를 저장할 주소 * @param len 바이너리 데이터의 길이를 저장할 주소 * * @remark * bin는 할당된 메모리이며, 크기는 strlen (hex) / 2 */ int CF_Codec_Hex_Decode (const char * hex, unsigned char * bin, size_t * len) { int result = 0; size_t length = strlen (hex); /* absolutely even-number */ size_t iter = 0; size_t binlen = 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); ASSERT_ARGS (len == 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 == ASCN ? 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; } *len = binlen; return result; } /** * Base64-encode * * @return 성공 시, CF_OK; 실패 시, 오류 코드 * * @param bin 바이너리 데이터 * @param len 바이너리 데이터 길이 * @param base64 base64 문자열을 저장할 주소 * * @remark * base64는 할당된 메모리이며, 크기는 '\0'를 포함하여 (((len + 2) / 3) * 4) + 1 * * @see http://sourceforge.net/p/predef/wiki/Endianness/ */ int CF_Codec_Base64_Encode (const unsigned char * bin, const size_t len, char * base64) { size_t iter = 0; char * ptr = base64; ASSERT_ARGS (bin == NULL); ASSERT_ARGS (base64 == NULL); #define SEXTUPLE_E_1(__x,_idx) ((__x[_idx ] >> 2) & 0x3f) #define SEXTUPLE_E_2(__x,_idx) ((__x[_idx ] << 4) & 0x30) #define SEXTUPLE_E_3(__x,_idx) ((__x[_idx + 1] >> 4) & 0x0f) #define SEXTUPLE_E_4(__x,_idx) ((__x[_idx + 1] << 2) & 0x3c) #define SEXTUPLE_E_5(__x,_idx) ((__x[_idx + 2] >> 6) & 0x03) #define SEXTUPLE_E_6(__x,_idx) ((__x[_idx + 2] ) & 0x3f) for (iter = 0 ; iter < len - 2 ; iter += 3) { *ptr++ = g_table_Base64Encode[SEXTUPLE_E_1 (bin, iter)]; *ptr++ = g_table_Base64Encode[SEXTUPLE_E_2 (bin, iter)| SEXTUPLE_E_3 (bin, iter)]; *ptr++ = g_table_Base64Encode[SEXTUPLE_E_4 (bin, iter)| SEXTUPLE_E_5 (bin, iter)]; *ptr++ = g_table_Base64Encode[SEXTUPLE_E_6 (bin, iter)]; } if (iter < len) { *ptr++ = g_table_Base64Encode[SEXTUPLE_E_1 (bin, iter)]; if (iter == (len - 1)) { *ptr++ = g_table_Base64Encode[SEXTUPLE_E_2 (bin, iter)]; *ptr++ = g_table_Base64Encode[PADDING_CHAR_INDEX]; } else { *ptr++ = g_table_Base64Encode[SEXTUPLE_E_2 (bin, iter)| SEXTUPLE_E_3 (bin, iter)]; *ptr++ = g_table_Base64Encode[SEXTUPLE_E_4 (bin, iter)]; } *ptr++ = g_table_Base64Encode[PADDING_CHAR_INDEX]; } *ptr = '\0'; return CF_OK; } /** * Base64-decode * * @return 성공 시, CF_OK; 실패 시, 오류 코드 * * @param base64 base64 문자열 * @param bin 바이너리 데이터를 저장할 주소 * @param len 바이너리 데이터의 길이를 저장할 주소 * * @remark * base64는 할당된 메모리이며, 크기는 (strlen (base64) - <'=' 개수>) / 4 * 3 * * @see http://sourceforge.net/p/predef/wiki/Endianness/ */ int CF_Codec_Base64_Decode (const char * base64, unsigned char * bin, size_t * len) { size_t remain = 0; const char * src = base64; unsigned char * dst = bin; size_t binlen = 0; ASSERT_ARGS (base64 == NULL); ASSERT_ARGS (bin == NULL); ASSERT_ARGS (len == NULL); while (*src && g_ascii_Base64Decode[(int)*src] < PADDING_CHAR_INDEX) src++; if (*src) return CF_ERROR_CODEC_NOT_BASE64; remain = (size_t)(src - base64); binlen = ((remain + 3) / 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, dst = bin ; 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)); *dst++ = '\0'; *len = binlen; return CF_OK; }