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

Last change on this file since 165 was 165, checked in by cheese, 9 years ago

#1 fix compilation error

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