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

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

#1 more fix and arrange doxygen comments

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