source: libcf/trunk/src/cf_codec.c@ 129

Last change on this file since 129 was 129, checked in by cheese, 11 years ago

#1 fix argument order

File size: 9.7 KB
RevLine 
[66]1/**
[128]2 * \file cf_codec.c
[117]3 *
[128]4 * \author myusgun <myusgun@gmail.com>
5 *
[119]6 * \brief 데이터 변환 구현
[66]7 */
8#include "cf_codec.h"
[128]9#include "cf_type.h"
[66]10#include "cf_error.h"
11
12#include <string.h>
13#include <stdio.h>
14
[85]15#define ASSERT_ARGS(x) \
16 if ((x)) \
[66]17 return CF_ERROR_CODEC_INVALID_ARGS
18
[128]19const static cf_byte g_ascii_HexDecode[] = {
[88]20 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00 - 15 */
21 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16 - 31 */
22 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 32 - 47 */
[89]23 '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',0x00,0x00,0x00,0x00,0x00,0x00, /* 48 - 63 */
24 0x00, 'A', 'A', 'A', 'A', 'A', 'A',0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 64 - 79 */
[88]25 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 80 - 95 */
[89]26 0x00, 'a', 'a', 'a', 'a', 'a', 'a',0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 96 - 111 */
[88]27 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 112 - 127 */
28 /* end of ascii character */
29 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128 - 143 */
30 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144 - 159 */
31 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160 - 175 */
32 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176 - 191 */
33 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192 - 207 */
34 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208 - 223 */
35 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224 - 239 */
36 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240 - 255 */
37};
[66]38
[88]39const static char g_table_Base64Encode[] = {
[90]40#define BASE64_PADDING_CHAR_INDEX 64
[88]41 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', /* 00 - 07 */
42 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 08 - 15 */
43 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', /* 16 - 23 */
44 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', /* 24 - 31 */
45 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', /* 32 - 39 */
46 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', /* 40 - 47 */
47 'w', 'x', 'y', 'z', '0', '1', '2', '3', /* 48 - 55 */
48 '4', '5', '6', '7', '8', '9', '+', '/', /* 56 - 63 */
49 '=' /* padding */
50};
[72]51
[128]52const static cf_byte g_ascii_Base64Decode[] = {
[89]53 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 00 - 15 */
54 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 16 - 31 */
55 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 62,0xff,0xff,0xff, 63, /* 32 - 47 */
56 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,0xff,0xff,0xff, 64,0xff,0xff, /* 48 - 63 */
57 0xff, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 64 - 79 */
58 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,0xff,0xff,0xff,0xff,0xff, /* 80 - 95 */
59 0xff, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 96 - 111 */
60 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,0xff,0xff,0xff,0xff,0xff, /* 112 - 127 */
[88]61 /* end of ascii character */
[89]62 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 128 - 143 */
63 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 144 - 159 */
64 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 160 - 175 */
65 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 176 - 191 */
66 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 192 - 207 */
67 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 208 - 223 */
68 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 224 - 239 */
69 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 240 - 255 */
[88]70};
71
72
[66]73/**
[88]74 * hex-encode
[66]75 *
[119]76 * \return 성공 시, CF_OK; 실패 시, 오류 코드
[66]77 *
[119]78 * \param bin 바이너리 데이터
79 * \param len 바이너리 데이터의 길이
80 * \param hex 16진수 문자열을 저장할 주소
[66]81 *
[119]82 * \remarks
[91]83 * hex는 할당된 메모리이며, 크기는 '\0'를 제외하고 len * 2
[66]84 */
85int
[128]86CF_Codec_Hex_Encode (const cf_byte * bin,
87 const size_t len,
88 char * hex)
[66]89{
[88]90 size_t iter = 0;
91 size_t hexlen = len * 2 + 1;
[66]92
[128]93 const cf_byte * ptr = bin;
[66]94
[88]95 const static char hexchar[] = {'0', '1', '2', '3',
96 '4', '5', '6', '7',
97 '8', '9', 'a', 'b',
98 'c', 'd', 'e', 'f'};
[66]99
100 ASSERT_ARGS (bin == NULL);
101 ASSERT_ARGS (hex == NULL);
102
[88]103 for (iter = 0 ; iter < hexlen ; iter += 2, ptr++)
[66]104 {
105 hex[iter ] = hexchar[((*(ptr)) >> 4) & 0x0f];
106 hex[iter + 1] = hexchar[((*(ptr)) ) & 0x0f];
107 }
[88]108 hex[hexlen - 1] = '\0';
[66]109
110 return CF_OK;
111}
112
113/**
[88]114 * hex-decode
[66]115 *
[119]116 * \return 성공 시, 디코딩된 바이너리 데이터의 길이; 실패 시, 오류 코드
[66]117 *
[119]118 * \param hex 16진수 문자열
119 * \param bin 바이너리 데이터를 저장할 주소
120 * \param len 바이너리 데이터의 길이를 저장할 주소
[66]121 *
[119]122 * \remarks
[88]123 * bin는 할당된 메모리이며, 크기는 strlen (hex) / 2
[66]124 */
125int
[128]126CF_Codec_Hex_Decode (const char * hex,
127 cf_byte * bin,
128 size_t * len)
[66]129{
[128]130 size_t length = 0; /* absolutely even-number */
131 size_t iter = 0;
132 size_t binlen = 0;
[66]133
[128]134 const char * ptr = hex;
135 char buf = 0;
136 cf_byte val = 0;
137 cf_byte asciiHex = 0;
[66]138
139 ASSERT_ARGS (hex == NULL);
140 ASSERT_ARGS (bin == NULL);
[96]141 ASSERT_ARGS (len == NULL);
[66]142
[96]143 *len = 0;
144
145 for ( ; g_ascii_HexDecode[(int)*ptr] && *ptr ; ptr++, length++);
146
147 if (*ptr)
148 return CF_ERROR_CODEC_NOT_HEXSTRING;
149
150 binlen = length / 2;
151
152 for (iter = 0, ptr = hex ; *ptr ; iter++)
[66]153 {
[88]154 val = 0; /* init/re-init docoding-buffer */
[66]155
[88]156 /* decode one character */
157#define DECODE_HEX(x) \
158 do { \
159 buf = *(x); \
[128]160 val = (cf_byte)(val << 4); \
[88]161 asciiHex = g_ascii_HexDecode[(int)buf]; \
162 \
[128]163 val |= (cf_byte) \
[96]164 (buf - asciiHex + (asciiHex == '0' ? 0 : 10)); \
[88]165 } while (0)
[66]166
[88]167 /* decode one byte by decode two character */
168 DECODE_HEX (ptr++);
169 DECODE_HEX (ptr++);
170
[66]171 bin[iter] = val;
172 }
173
[96]174 * len = binlen;
175
176 return CF_OK;
[66]177}
[88]178
179/**
180 * Base64-encode
181 *
[119]182 * \return 성공 시, CF_OK; 실패 시, 오류 코드
[88]183 *
[119]184 * \param bin 바이너리 데이터
185 * \param len 바이너리 데이터 길이
186 * \param base64 base64 문자열을 저장할 주소
[88]187 *
[119]188 * \remarks
[91]189 * base64는 할당된 메모리이며, 크기는 '\0'를 제외하고 ((len + 2) / 3) * 4
[88]190 */
191int
[128]192CF_Codec_Base64_Encode (const cf_byte * bin,
[129]193 const size_t len,
194 char * base64)
[88]195{
[128]196 const cf_byte * src = bin;
197 char * dst = base64;
[88]198
[90]199 ASSERT_ARGS (src == NULL);
200 ASSERT_ARGS (dst == NULL);
[88]201
[90]202#define SEXTUPLE_E_1(__x) (((__x[0]) >> 2) & 0x3f)
203#define SEXTUPLE_E_2(__x) (((__x[0]) << 4) & 0x30)
204#define SEXTUPLE_E_3(__x) (((__x[1]) >> 4) & 0x0f)
205#define SEXTUPLE_E_4(__x) (((__x[1]) << 2) & 0x3c)
206#define SEXTUPLE_E_5(__x) (((__x[2]) >> 6) & 0x03)
207#define SEXTUPLE_E_6(__x) (((__x[2]) ) & 0x3f)
[88]208
[90]209 for ( ; src - bin < len - 2 ; src += 3)
[88]210 {
[90]211 *dst++ = g_table_Base64Encode[SEXTUPLE_E_1 (src)];
212 *dst++ = g_table_Base64Encode[SEXTUPLE_E_2 (src)|
213 SEXTUPLE_E_3 (src)];
214 *dst++ = g_table_Base64Encode[SEXTUPLE_E_4 (src)|
215 SEXTUPLE_E_5 (src)];
216 *dst++ = g_table_Base64Encode[SEXTUPLE_E_6 (src)];
[88]217 }
218
[90]219 if (src - bin < len)
[88]220 {
[90]221 *dst++ = g_table_Base64Encode[SEXTUPLE_E_1 (src)];
[88]222
[90]223 if (src - bin == len - 1)
[88]224 {
[91]225 *dst++ = g_table_Base64Encode[SEXTUPLE_E_2 (src)];
[90]226 *dst++ = g_table_Base64Encode[BASE64_PADDING_CHAR_INDEX];
[88]227 }
228 else
229 {
[91]230 *dst++ = g_table_Base64Encode[SEXTUPLE_E_2 (src)|
231 SEXTUPLE_E_3 (src)];
232 *dst++ = g_table_Base64Encode[SEXTUPLE_E_4 (src)];
[88]233 }
234
[90]235 *dst++ = g_table_Base64Encode[BASE64_PADDING_CHAR_INDEX];
[88]236 }
[90]237 *dst = '\0';
[88]238
239 return CF_OK;
240}
241
242/**
243 * Base64-decode
244 *
[119]245 * \return 성공 시, 디코딩된 바이너리 데이터의 길이; 실패 시, 오류 코드
[88]246 *
[119]247 * \param base64 base64 문자열
248 * \param bin 바이너리 데이터를 저장할 주소
249 * \param len 바이너리 데이터의 길이를 저장할 주소
[88]250 *
[119]251 * \remarks
[91]252 * base64는 할당된 메모리이며, 크기는 (strlen (base64)) / 4 * 3
[88]253 */
254int
[129]255CF_Codec_Base64_Decode (const char * base64,
256 cf_byte * bin,
257 size_t * len)
[88]258{
[128]259 const char * src = base64;
260 cf_byte * dst = bin;
261 int remain = 0;
262 int binlen = 0;
[88]263
[90]264 ASSERT_ARGS (src == NULL);
265 ASSERT_ARGS (dst == NULL);
[96]266 ASSERT_ARGS (len == NULL);
[88]267
[96]268 *len = 0;
269
[90]270 while (g_ascii_Base64Decode[(int)*src] < BASE64_PADDING_CHAR_INDEX) src++;
[88]271
[91]272 if (*src == 0xff)
[88]273 return CF_ERROR_CODEC_NOT_BASE64;
274
[90]275 remain = (int)(src - base64);
[91]276 binlen = ((remain + 2/* max padding length */) / 4) * 3;
[88]277
278#define SEXTUPLE_D_1(src) (g_ascii_Base64Decode[(int)src[0]] << 2)
279#define SEXTUPLE_D_2(src) (g_ascii_Base64Decode[(int)src[1]] >> 4)
280#define SEXTUPLE_D_3(src) (g_ascii_Base64Decode[(int)src[1]] << 4)
281#define SEXTUPLE_D_4(src) (g_ascii_Base64Decode[(int)src[2]] >> 2)
282#define SEXTUPLE_D_5(src) (g_ascii_Base64Decode[(int)src[2]] << 6)
283#define SEXTUPLE_D_6(src) (g_ascii_Base64Decode[(int)src[3]] )
284
[91]285 for (src = base64 ; remain > 4 ; remain -= 4, src += 4)
[88]286 {
[128]287 *dst++ = (cf_byte)(SEXTUPLE_D_1 (src) | SEXTUPLE_D_2 (src));
288 *dst++ = (cf_byte)(SEXTUPLE_D_3 (src) | SEXTUPLE_D_4 (src));
289 *dst++ = (cf_byte)(SEXTUPLE_D_5 (src) | SEXTUPLE_D_6 (src));
[88]290 }
291
292 if (remain > 1)
[128]293 *dst++ = (cf_byte)(SEXTUPLE_D_1 (src) | SEXTUPLE_D_2 (src));
[88]294 if (remain > 2)
[128]295 *dst++ = (cf_byte)(SEXTUPLE_D_3 (src) | SEXTUPLE_D_4 (src));
[88]296 if (remain > 3)
[128]297 *dst++ = (cf_byte)(SEXTUPLE_D_5 (src) | SEXTUPLE_D_6 (src));
[88]298
[92]299 return binlen - (4 - remain);
[88]300}
Note: See TracBrowser for help on using the repository browser.