source: libcf++/trunk/src/codec.cpp@ 18

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

#1 unify descriptor for initializing

File size: 8.7 KB
Line 
1/**
2 * @file codec.cpp
3 * @author myusgun@gmail.com
4 * @brief codec
5 */
6#include "cf/codec.h"
7#include "cf/memory.h"
8
9#define BASE64_PADDING_CHAR_INDEX 64
10
11cf::codec::base64 * cf::codec::base64::getInstance()
12{
13 static cf::codec::base64 instance;
14
15 return &instance;
16}
17
18std::string cf::codec::base64::encode(const cf::bin & in) const
19 throw (cf::exception)
20{
21 if (in.size() == 0)
22 THROW_EXCEPTION("input is empty");
23
24 try
25 {
26 cf::size_t inlen = in.size();
27 cf::char_t * buf = NULL;
28 cf::size_t memsize = (((inlen + 2) / 3) * 4) + 1;
29 cf::memory mem(memsize);
30
31 buf = reinterpret_cast<cf::char_t *>(mem.buffer());
32
33 /*--------------------------------------------------------------*/
34 cf::char_t * dst = buf;
35 const cf::uint8_t * src = in.buffer();
36 const cf::uint8_t * ptr = src;
37
38 const static cf::char_t base64enc[] = {
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
50#define SEXTUPLE_E_1(__x) (((__x[0]) >> 2) & 0x3f)
51#define SEXTUPLE_E_2(__x) (((__x[0]) << 4) & 0x30)
52#define SEXTUPLE_E_3(__x) (((__x[1]) >> 4) & 0x0f)
53#define SEXTUPLE_E_4(__x) (((__x[1]) << 2) & 0x3c)
54#define SEXTUPLE_E_5(__x) (((__x[2]) >> 6) & 0x03)
55#define SEXTUPLE_E_6(__x) (((__x[2]) ) & 0x3f)
56
57 for ( ; static_cast<cf::size_t>(ptr - src) < (inlen - 2) ; ptr += 3)
58 {
59 *dst++ = base64enc[SEXTUPLE_E_1 (ptr)];
60 *dst++ = base64enc[SEXTUPLE_E_2 (ptr) | SEXTUPLE_E_3 (ptr)];
61 *dst++ = base64enc[SEXTUPLE_E_4 (ptr) | SEXTUPLE_E_5 (ptr)];
62 *dst++ = base64enc[SEXTUPLE_E_6 (ptr)];
63 }
64
65 if (static_cast<cf::size_t>(ptr - src) < inlen)
66 {
67 *dst++ = base64enc[SEXTUPLE_E_1 (ptr)];
68
69 if (static_cast<cf::size_t>(ptr - src) == (inlen - 1))
70 {
71 *dst++ = base64enc[SEXTUPLE_E_2 (ptr)];
72 *dst++ = base64enc[BASE64_PADDING_CHAR_INDEX];
73 }
74 else
75 {
76 *dst++ = base64enc[SEXTUPLE_E_2 (ptr) | SEXTUPLE_E_3 (ptr)];
77 *dst++ = base64enc[SEXTUPLE_E_4 (ptr)];
78 }
79
80 *dst++ = base64enc[BASE64_PADDING_CHAR_INDEX];
81 }
82 *dst = '\0';
83 /*--------------------------------------------------------------*/
84
85 return std::string(buf);
86 }
87 catch (cf::exception &e)
88 {
89 FORWARD_EXCEPTION(e);
90 }
91}
92
93cf::bin cf::codec::base64::decode(const std::string & in) const
94 throw (cf::exception)
95{
96 if (in.empty())
97 THROW_EXCEPTION("base64 string is empty");
98
99 try
100 {
101 cf::uint8_t * buf = NULL;
102 cf::long_t outlen = 0;
103 cf::size_t memsize = static_cast<cf::size_t>(in.size()) / 4 * 3;
104 cf::memory mem(memsize);
105
106 buf = reinterpret_cast<cf::uint8_t *>(mem.buffer());
107
108 /*--------------------------------------------------------------*/
109 const cf::char_t * src = in.c_str();
110 const cf::char_t * ptr = src;
111 cf::uint8_t * dst = buf;
112 cf::long_t remain = 0;
113 cf::long_t binlen = 0;
114
115 const static cf::uint8_t base64dec[] = {
116 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 00 - 07 */
117 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 08 - 15 */
118 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 16 - 23 */
119 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 24 - 31 */
120 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 32 - 39 */
121 0xff,0xff,0xff, 62,0xff,0xff,0xff, 63, /* 40 - 47 */
122 52, 53, 54, 55, 56, 57, 58, 59, /* 48 - 55 */
123 60, 61,0xff,0xff,0xff, 64,0xff,0xff, /* 56 - 63 */
124 0xff, 0, 1, 2, 3, 4, 5, 6, /* 64 - 71 */
125 7, 8, 9, 10, 11, 12, 13, 14, /* 71 - 79 */
126 15, 16, 17, 18, 19, 20, 21, 22, /* 80 - 87 */
127 23, 24, 25,0xff,0xff,0xff,0xff,0xff, /* 88 - 95 */
128 0xff, 26, 27, 28, 29, 30, 31, 32, /* 96 - 103 */
129 33, 34, 35, 36, 37, 38, 39, 40, /* 104 - 111 */
130 41, 42, 43, 44, 45, 46, 47, 48, /* 112 - 119 */
131 49, 50, 51,0xff,0xff,0xff,0xff,0xff /* 120 - 127 */
132 };
133
134 while (base64dec[(int)*ptr] < BASE64_PADDING_CHAR_INDEX) ptr++;
135
136 if (*ptr == 0xff)
137 THROW_EXCEPTION("input string is not base64-encoded");
138
139 remain = static_cast<cf::long_t>(ptr - src);
140 binlen = ((remain + 2/* max padding length */) / 4) * 3;
141
142#define SEXTUPLE_D_1(src) (base64dec[(int)src[0]] << 2)
143#define SEXTUPLE_D_2(src) (base64dec[(int)src[1]] >> 4)
144#define SEXTUPLE_D_3(src) (base64dec[(int)src[1]] << 4)
145#define SEXTUPLE_D_4(src) (base64dec[(int)src[2]] >> 2)
146#define SEXTUPLE_D_5(src) (base64dec[(int)src[2]] << 6)
147#define SEXTUPLE_D_6(src) (base64dec[(int)src[3]] )
148
149 for (ptr = src ; remain > 4 ; remain -= 4, ptr += 4)
150 {
151 *dst++ = (cf::uint8_t)(SEXTUPLE_D_1(ptr) | SEXTUPLE_D_2(ptr));
152 *dst++ = (cf::uint8_t)(SEXTUPLE_D_3(ptr) | SEXTUPLE_D_4(ptr));
153 *dst++ = (cf::uint8_t)(SEXTUPLE_D_5(ptr) | SEXTUPLE_D_6(ptr));
154 }
155
156 if (remain > 1)
157 *dst++ = (cf::uint8_t)(SEXTUPLE_D_1(ptr) | SEXTUPLE_D_2(ptr));
158 if (remain > 2)
159 *dst++ = (cf::uint8_t)(SEXTUPLE_D_3(ptr) | SEXTUPLE_D_4(ptr));
160 if (remain > 3)
161 *dst++ = (cf::uint8_t)(SEXTUPLE_D_5(ptr) | SEXTUPLE_D_6(ptr));
162
163 outlen = binlen - (4 - remain);
164 /*--------------------------------------------------------------*/
165
166 return cf::bin(buf, static_cast<cf::size_t>(outlen));
167 }
168 catch (cf::exception &e)
169 {
170 FORWARD_EXCEPTION(e);
171 }
172}
173
174cf::codec::hex * cf::codec::hex::getInstance()
175{
176 static cf::codec::hex instance;
177
178 return &instance;
179}
180
181std::string cf::codec::hex::encode(const cf::bin & in) const
182 throw (cf::exception)
183{
184 if (in.size() == 0)
185 THROW_EXCEPTION("input is empty");
186
187 try
188 {
189 cf::char_t * buf = NULL;
190 cf::size_t memsize = in.size() * 2 + 1;
191 cf::memory mem(memsize);
192
193 buf = reinterpret_cast<cf::char_t *>(mem.buffer());
194
195 /*--------------------------------------------------------------*/
196 const cf::uint8_t * src = in.buffer();
197 cf::char_t * dst = buf;
198
199 const static cf::char_t hexenc[] = {
200 '0', '1', '2', '3', '4', '5', '6', '7',
201 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
202 };
203
204 for ( ; static_cast<cf::size_t>(src - in.buffer()) < in.size() ; src++)
205 {
206 *dst++ = hexenc[((*src) >> 4) & 0x0f];
207 *dst++ = hexenc[((*src) ) & 0x0f];
208 }
209 *dst = '\0';
210 /*--------------------------------------------------------------*/
211
212 return std::string(buf);
213 }
214 catch (cf::exception &e)
215 {
216 FORWARD_EXCEPTION(e);
217 }
218}
219
220cf::bin cf::codec::hex::decode(const std::string & in) const
221 throw (cf::exception)
222{
223 if (in.empty())
224 THROW_EXCEPTION("hex string is empty");
225
226 try
227 {
228 cf::uint8_t * buf = NULL;
229 cf::int32_t len = 0;
230 cf::size_t memsize = static_cast<cf::size_t>(in.size()) / 2;
231 cf::memory mem(memsize);
232
233 buf = reinterpret_cast<cf::uint8_t *>(mem.buffer());
234
235 /*--------------------------------------------------------------*/
236 cf::int32_t length = 0; /* even-number */
237
238 const cf::char_t * src = in.c_str();
239 const cf::char_t * ptr = src;
240 cf::uint8_t * dst = buf;
241 cf::uint8_t val = 0;
242 cf::uint8_t sum = 0;
243 cf::uint8_t asciiHex = 0;
244
245 const static cf::uint8_t hexdec[] = {
246 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00 - 07 */
247 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 08 - 15 */
248 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16 - 23 */
249 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24 - 31 */
250 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 32 - 39 */
251 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 40 - 47 */
252 '0', '0', '0', '0', '0', '0', '0', '0', /* 48 - 55 */
253 '0', '0',0x00,0x00,0x00,0x00,0x00,0x00, /* 56 - 63 */
254 0x00, 'A', 'A', 'A', 'A', 'A', 'A',0x00, /* 64 - 71 */
255 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 71 - 79 */
256 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 80 - 87 */
257 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 88 - 95 */
258 0x00, 'a', 'a', 'a', 'a', 'a', 'a',0x00, /* 96 - 103 */
259 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 104 - 111 */
260 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 112 - 119 */
261 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 /* 120 - 127 */
262 };
263
264 for ( ; hexdec[(int)*ptr] && *ptr ; ptr++, length++);
265
266 if (*ptr)
267 THROW_EXCEPTION("input string is not hex-encoded");
268
269 for (ptr = src ; *ptr ; )
270 {
271 sum = 0; /* init/re-init decoding-buffer */
272
273 /* decode one character */
274#define DECODE_HEX(x) \
275 do { \
276 val = static_cast<cf::uint8_t>(*(x)); \
277 sum = (cf::uint8_t)(sum << 4); \
278 asciiHex = hexdec[val]; \
279 \
280 sum |= (cf::uint8_t) \
281 (val - asciiHex + (asciiHex == '0' ? 0 : 10)); \
282 } while (0)
283
284 /* decode one byte by decode two character */
285 DECODE_HEX(ptr++);
286 DECODE_HEX(ptr++);
287
288 *dst++ = sum;
289 }
290 len = length / 2;
291 /*--------------------------------------------------------------*/
292
293 return cf::bin(buf, len);
294 }
295 catch (cf::exception &e)
296 {
297 FORWARD_EXCEPTION(e);
298 }
299}
Note: See TracBrowser for help on using the repository browser.