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

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

#1 add base64 and arrange hex-decoding more fast

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