/src/kamailio/src/core/basex.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * convert/decode to/from ascii using various bases |
3 | | * |
4 | | * Copyright (C) 2008 iptelorg GmbH |
5 | | * |
6 | | * Permission to use, copy, modify, and distribute this software for any |
7 | | * purpose with or without fee is hereby granted, provided that the above |
8 | | * copyright notice and this permission notice appear in all copies. |
9 | | * |
10 | | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 | | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 | | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 | | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 | | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 | | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 | | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 | | */ |
18 | | |
19 | | /*! |
20 | | * \file |
21 | | * \brief Kamailio core :: convert/decode to/from ascii using various bases |
22 | | * |
23 | | * Copyright (C) 2008 iptelorg GmbH |
24 | | * \ingroup core |
25 | | * |
26 | | * Module: \ref core |
27 | | * |
28 | | * |
29 | | * Functions: |
30 | | * - base16_enc(src, src_len, dst, dst_len) : encode to standard hex |
31 | | * - base16_dec(src, src_len, dst, dst_len) : decode from standard hex |
32 | | * - base16_enc_len(len) : length needed to encode len bytes (macro) |
33 | | * - base16_max_dec_len(len) : length needed to decode a string of size len |
34 | | * |
35 | | * - base64_enc(src, src_len, dst, dst_len) : encode to base64, standard alphabet |
36 | | * - base64_dec(src, src_len, dst, dst_len) : decode from base64, standard alphabet |
37 | | * - base64_enc_len(len) : length needed to encode len bytes (macro) |
38 | | * - base64_max_dec_len(len) : maximum length needed to decode len bytes (macro) |
39 | | * - base64_dec_len(str, len) : size of the decoded str |
40 | | * - q_base64_enc(src, src_len, dst, dst_len) : encode to special base64 alphabet (non standard) |
41 | | * - q_base64_dec(src, src_len, dst, dst_len) - decode from special non-standard base64 alphabet |
42 | | * |
43 | | * All the above functions return the size used (in dst) on success and |
44 | | * 0 or a negative number (which is -1*size_needed) on error. |
45 | | * |
46 | | * There are close to no checks for validity, an unexpected char will lead |
47 | | * to a corrupted result, but the functions won't return error. |
48 | | * |
49 | | * Notes: |
50 | | * on a core2 duo the versions with lookup tables are way faster (see |
51 | | * http://www.experts-exchange.com/Programming/Languages/CPP/Q_21988706.html |
52 | | * for some interesting tests and ideeas). |
53 | | * |
54 | | * Test results for 40 bytes (typical ser nounce) in average cpu cycles: |
55 | | \verbatim |
56 | | * lookup lookup_large lookup8k no-lookup |
57 | | * base16_enc 211/231 218/199 - 1331 |
58 | | * base16_dec 252/251 236 - 1226 |
59 | | * base64_enc 209 186 156 1005 |
60 | | * base64_dec 208 207 207 1242 |
61 | | * q_base64_enc - 288 |
62 | | * q_base64_dec - 281 |
63 | | * (see test/basex.txt for more results) |
64 | | \endverbatim |
65 | | * |
66 | | * Defines: |
67 | | * - BASE64_LOOKUP_TABLE/NO_BASE64_LOOKUP_TABLE : use (default)/don't use |
68 | | * small lookup tables for conversions (faster in general). |
69 | | * - BASE64_LOOKUP_LARGE : use large lookup tables (2560 bytes for |
70 | | * encoding and 256 bytes for decoding; without it 64 bytes are used for |
71 | | * encoding and 85 bytes for decoding. |
72 | | * - BASE64_LOOKUP_8K : use even larger lookup tables (8K for encoding and |
73 | | * 256 for decoding); also try to write 2 bytes at a time (short) if |
74 | | * the destination is 2 byte aligned |
75 | | * |
76 | | * - BASE16_LOOKUP_TABLE/NO_BASE16_LOOKUP_TABLE : use (default)/don't use |
77 | | * small lookup tables for conversions (faster in general). |
78 | | * - BASE16_LOOKUP_LARGE : use large lookup tables (512 bytes for |
79 | | * encoding and 256 bytes for decoding |
80 | | * - BASE16_READ_WHOLE_INTS : read an int at a time |
81 | | * |
82 | | * History: |
83 | | * -------- |
84 | | * 2008-06-11 created by andrei |
85 | | */ |
86 | | |
87 | | |
88 | | #ifndef _basex_h |
89 | | #define _basex_h |
90 | | |
91 | | #include "compiler_opt.h" |
92 | | |
93 | | /* defaults */ |
94 | | #ifndef NO_BASE16_LOOKUP_TABLE |
95 | | #define BASE16_LOOKUP_TABLE |
96 | | #endif |
97 | | |
98 | | #ifndef NO_BASE64_LOOKUP_TABLE |
99 | | #define BASE64_LOOKUP_TABLE |
100 | | #endif |
101 | | |
102 | | #ifndef NO_BASE64_LOOKUP_8K |
103 | | #define BASE64_LOOKUP_8K |
104 | | #endif |
105 | | |
106 | | #ifndef NO_BASE16_LOOKUP_LARGE |
107 | | #define BASE16_LOOKUP_LARGE |
108 | | #endif |
109 | | |
110 | | #if !defined NO_BASE64_LOOKUP_LARGE && !defined BASE64_LOOKUP_8K |
111 | | #define BASE64_LOOKUP_LARGE |
112 | | #endif |
113 | | |
114 | | |
115 | | #if defined BASE16_READ_WHOLE_INTS || defined BASE64_READ_WHOLE_INTS \ |
116 | | || defined BASE64_LOOKUP_8K |
117 | | #include "endianness.h" |
118 | | |
119 | | /*! \brief aligns p to a type* pointer, type must have a 2^k size */ |
120 | | #define ALIGN_POINTER(p, type) \ |
121 | | ((type *)((long)((char *)(p) + sizeof(type) - 1) \ |
122 | | & ~(long)(sizeof(type) - 1))) |
123 | | |
124 | | #define ALIGN_UINT_POINTER(p) ALIGN_POINTER(p, unsigned int) |
125 | | |
126 | | #endif |
127 | | |
128 | | |
129 | | #ifdef BASE16_LOOKUP_TABLE |
130 | | |
131 | | #ifdef BASE16_LOOKUP_LARGE |
132 | | /*! \brief use large tables: 512 for lookup and 256 for decode */ |
133 | | |
134 | | extern unsigned char _bx_hexdig_hi[256]; |
135 | | extern unsigned char _bx_hexdig_low[256]; |
136 | | |
137 | | /*! \brief returns the first 4 bits of c converted to a hex digit */ |
138 | | #define HEX_HI(h) _bx_hexdig_hi[(unsigned char)(h)] |
139 | | /*! \brief returns the low 4 bits of converted to a hex digit */ |
140 | | #define HEX_LOW(h) _bx_hexdig_low[(unsigned char)(h)] |
141 | | |
142 | | extern unsigned char _bx_unhexdig256[256]; |
143 | | |
144 | | /*! \brief converts hex_digit to a number (0..15); it might |
145 | | * \return 0xff for invalid digit (but with some compile |
146 | | * option it won't check) |
147 | | */ |
148 | | #define UNHEX(h) _bx_unhexdig256[(h)] |
149 | | |
150 | | #else /* BASE16_LOOKUP_LARGE */ |
151 | | /*! \brief use small tabes: 16 bytes for lookup and 32 for decode */ |
152 | | |
153 | | extern unsigned char _bx_hexdig[16 + 1]; |
154 | | |
155 | | #define HEX_4BITS(h) _bx_hexdig[(h)] |
156 | | #define HEX_HI(h) HEX_4BITS(((unsigned char)(h)) >> 4) |
157 | | #define HEX_LOW(h) HEX_4BITS((h)&0xf) |
158 | | |
159 | | extern unsigned char _bx_unhexdig32[32]; |
160 | | #define UNHEX(h) _bx_unhexdig32[(((h)) - '0') & 0x1f] |
161 | | |
162 | | #endif /* BASE16_LOOKUP_LARGE */ |
163 | | |
164 | | #else /* BASE16_LOOKUP_TABLE */ |
165 | | /* no lookup tables */ |
166 | | #if 0 |
167 | | #define HEX_4BITS(h) \ |
168 | | (unsigned char)((unlikely((h) >= 10)) ? ((h)-10 + 'A') : (h) + '0') |
169 | | #define UNHEX(c) \ |
170 | | (unsigned char)((unlikely((c) >= 'A')) ? (c) - 'A' + 10 : (c) - '0') |
171 | | #else |
172 | | #define HEX_4BITS(hc) \ |
173 | | (unsigned char)(((((hc) >= 10) - 1) & ((hc) + '0')) \ |
174 | | | ((((hc) < 10) - 1) & ((hc) + 'A'))) |
175 | | #define UNHEX(c) \ |
176 | | (unsigned char)(((((c) > '9') - 1) & ((c) - '0')) \ |
177 | | | ((((c) <= '9') - 1) & ((c) - 'A'))) |
178 | | #endif |
179 | | |
180 | | #define HEX_HI(h) HEX_4BITS(((unsigned char)(h)) >> 4) |
181 | | #define HEX_LOW(h) HEX_4BITS((h)&0xf) |
182 | | |
183 | | #endif /* BASE16_LOOKUP_TABLE */ |
184 | | |
185 | | |
186 | | #ifdef BASE64_LOOKUP_TABLE |
187 | | #ifdef BASE64_LOOKUP_LARGE |
188 | | /* large lookup tables, 2.5 k */ |
189 | | |
190 | | extern unsigned char _bx_b64_first[256]; |
191 | | extern unsigned char _bx_b64_second[4][256]; |
192 | | extern unsigned char _bx_b64_third[4][256]; |
193 | | extern unsigned char _bx_b64_fourth[256]; |
194 | | |
195 | | #define BASE64_1(a) _bx_b64_first[(a)] |
196 | | #define BASE64_2(a, b) _bx_b64_second[(a)&0x3][(b)] |
197 | | #define BASE64_3(b, c) _bx_b64_third[(c) >> 6][(b)] |
198 | | #define BASE64_4(c) _bx_b64_fourth[(c)] |
199 | | |
200 | | extern unsigned char _bx_ub64[256]; |
201 | | #define UNBASE64(v) _bx_ub64[(v)] |
202 | | |
203 | | #elif defined BASE64_LOOKUP_8K |
204 | | /* even larger encode tables: 8k */ |
205 | | extern unsigned short _bx_b64_12[4096]; |
206 | | |
207 | | /* return a word (16 bits) */ |
208 | | #define BASE64_12(a, b) _bx_b64_12[((a) << 4) | ((b) >> 4)] |
209 | | #define BASE64_34(b, c) _bx_b64_12[(((b)&0xf) << 8) | (c)] |
210 | | #ifdef __IS_LITTLE_ENDIAN |
211 | | #define FIRST_8B(s) ((unsigned char)(s)) |
212 | | #define LAST_8B(s) ((s) >> 8) |
213 | | #elif defined __IS_BIG_ENDIAN |
214 | | #define FIRST_8B(s) ((s) >> 8) |
215 | | #define LAST_8B(s) ((unsigned char)(s)) |
216 | | #else |
217 | | #error neither __IS_LITTLE_ENDIAN nor __IS_BIG_ENDIAN are defined |
218 | | #endif |
219 | | |
220 | | |
221 | | extern unsigned char _bx_ub64[256]; |
222 | | #define UNBASE64(v) _bx_ub64[(v)] |
223 | | |
224 | | #else /* BASE64_LOOKUP_LARGE */ |
225 | | /* small lookup tables */ |
226 | | extern unsigned char _bx_b64[64 + 1]; |
227 | | |
228 | | #define BASE64_DIG(v) _bx_b64[(v)] |
229 | | |
230 | | #define BASE64_1(a) BASE64_DIG((a) >> 2) |
231 | | #define BASE64_2(a, b) BASE64_DIG((((a) << 4) & 0x3f) | ((b) >> 4)) |
232 | | #define BASE64_3(b, c) BASE64_DIG((((b) << 2) & 0x3f) | ((c) >> 6)) |
233 | | #define BASE64_4(c) BASE64_DIG((c)&0x3f) |
234 | | |
235 | | extern unsigned char _bx_ub64[0x54 + 1]; |
236 | | #define UNBASE64(v) _bx_ub64[(((v)&0x7f) - 0x2b)] |
237 | | |
238 | | #endif /* BASE64_LOOKUP_LARGE */ |
239 | | |
240 | | |
241 | | #else /* BASE64_LOOKUP_TABLE */ |
242 | | |
243 | | #define BASE64_DIG(v) base64_enc_char(v) |
244 | | #define BASE64_1(a) BASE64_DIG((a) >> 2) |
245 | | #define BASE64_2(a, b) BASE64_DIG((((a) << 4) & 0x3f) | ((b) >> 4)) |
246 | | #define BASE64_3(b, c) BASE64_DIG((((b) << 2) & 0x3f) | ((c) >> 6)) |
247 | | #define BASE64_4(c) BASE64_DIG((c)&0x3f) |
248 | | |
249 | | #define UNBASE64(v) base64_dec_char(v) |
250 | | |
251 | | #endif /* BASE64_LOOKUP_TABLE */ |
252 | | |
253 | | |
254 | | /*! \brief length needed for encoding l bytes */ |
255 | | #define base16_enc_len(l) (l * 2) |
256 | | /*! \brief maximum length needed for decoding l bytes */ |
257 | | #define base16_max_dec_len(l) (l / 2) |
258 | | /*! \brief actual space needed for decoding a string b of size l */ |
259 | | #define base16_dec_len(b, l) base16_max_dec_len(l) |
260 | | /*! \brief minimum valid source len for decoding */ |
261 | | #define base16_dec_min_len() 2 |
262 | | /*! \brief minimum valid source len for encoding */ |
263 | | #define base16_enc_min_len() 0 |
264 | | |
265 | | /*! \brief space needed for encoding l bytes */ |
266 | | #define base64_enc_len(l) (((l) + 2) / 3 * 4) |
267 | | /*! \brief maximum space needed for encoding l bytes */ |
268 | | #define base64_max_dec_len(l) ((l) / 4 * 3) |
269 | | /*! \brief actual space needed for decoding a string b of size l, l>=4 */ |
270 | | #define base64_dec_len(b, l) \ |
271 | | (base64_max_dec_len(l) - ((b)[(l)-2] == '=') - ((b)[(l)-1] == '=')) |
272 | | /*! \brief minimum valid source len for decoding */ |
273 | | #define base64_dec_min_len() 4 |
274 | | /*! \brief minimum valid source len for encoding */ |
275 | | #define base64_enc_min_len() 0 |
276 | | |
277 | | |
278 | | #ifdef BASE16_READ_WHOLE_INTS |
279 | | |
280 | | /*! |
281 | | * \params: |
282 | | * \return: size used from the output buffer (dst) on success, |
283 | | * -size_needed on error |
284 | | * |
285 | | * WARNING: the output string is not 0-term |
286 | | */ |
287 | | inline static int base16_enc( |
288 | | unsigned char *src, int slen, unsigned char *dst, int dlen) |
289 | | { |
290 | | unsigned int *p; |
291 | | unsigned char *end; |
292 | | int osize; |
293 | | unsigned short us; |
294 | | |
295 | | osize = 2 * slen; |
296 | | if(unlikely(dlen < osize)) |
297 | | return -osize; |
298 | | end = src + slen; |
299 | | p = ALIGN_UINT_POINTER(src); |
300 | | if(likely((unsigned char *)p < end)) { |
301 | | switch((unsigned char)((unsigned char *)p - src)) { |
302 | | case 3: |
303 | | *dst = HEX_HI(*src); |
304 | | *(dst + 1) = HEX_LOW(*src); |
305 | | dst += 2; |
306 | | src++; |
307 | | /* no break */ |
308 | | case 2: |
309 | | us = *(unsigned short *)(src); |
310 | | #if defined __IS_LITTLE_ENDIAN |
311 | | *(dst + 0) = HEX_HI(us); |
312 | | *(dst + 1) = HEX_LOW(us); |
313 | | *(dst + 2) = HEX_HI(us >> 8); |
314 | | *(dst + 3) = HEX_LOW(us >> 8); |
315 | | #elif defined __IS_BIG_ENDIAN |
316 | | *(dst + 2) = HEX_HI(us); |
317 | | *(dst + 3) = HEX_LOW(us); |
318 | | *(dst + 0) = HEX_HI(us >> 8); |
319 | | *(dst + 1) = HEX_LOW(us >> 8); |
320 | | #endif |
321 | | dst += 4; |
322 | | /* no need to inc src */ |
323 | | break; |
324 | | case 1: |
325 | | *dst = HEX_HI(*src); |
326 | | *(dst + 1) = HEX_LOW(*src); |
327 | | dst += 2; |
328 | | /* no need to inc src */ |
329 | | case 0: |
330 | | break; |
331 | | } |
332 | | for(; (unsigned char *)p <= (end - 4); p++, dst += 8) { |
333 | | #if defined __IS_LITTLE_ENDIAN |
334 | | *(dst + 0) = HEX_HI(*p); |
335 | | *(dst + 1) = HEX_LOW(*p); |
336 | | *(dst + 2) = HEX_HI(((*p) >> 8)); |
337 | | *(dst + 3) = HEX_LOW(((*p) >> 8)); |
338 | | *(dst + 4) = HEX_HI(((*p) >> 16)); |
339 | | *(dst + 5) = HEX_LOW(((*p) >> 16)); |
340 | | *(dst + 6) = HEX_HI(((*p) >> 24)); |
341 | | *(dst + 7) = HEX_LOW(((*p) >> 24)); |
342 | | #elif defined __IS_BIG_ENDIAN |
343 | | *(dst + 6) = HEX_HI(*p); |
344 | | *(dst + 7) = HEX_LOW(*p); |
345 | | *(dst + 4) = HEX_HI(((*p) >> 8)); |
346 | | *(dst + 5) = HEX_LOW(((*p) >> 8)); |
347 | | *(dst + 2) = HEX_HI(((*p) >> 16)); |
348 | | *(dst + 3) = HEX_LOW(((*p) >> 16)); |
349 | | *(dst + 0) = HEX_HI(((*p) >> 24)); |
350 | | *(dst + 1) = HEX_LOW(((*p) >> 24)); |
351 | | #else |
352 | | #error neither BIG ro LITTLE endian defined |
353 | | #endif /* __IS_*_ENDIAN */ |
354 | | } |
355 | | src = (unsigned char *)p; |
356 | | /* src is 2-bytes aligned (short) */ |
357 | | switch((unsigned char)((unsigned char *)end - src)) { |
358 | | case 3: |
359 | | case 2: |
360 | | us = *(unsigned short *)(src); |
361 | | #if defined __IS_LITTLE_ENDIAN |
362 | | *(dst + 0) = HEX_HI(us); |
363 | | *(dst + 1) = HEX_LOW(us); |
364 | | *(dst + 2) = HEX_HI(us >> 8); |
365 | | *(dst + 3) = HEX_LOW(us >> 8); |
366 | | #elif defined __IS_BIG_ENDIAN |
367 | | *(dst + 2) = HEX_HI(us); |
368 | | *(dst + 3) = HEX_LOW(us); |
369 | | *(dst + 0) = HEX_HI(us >> 8); |
370 | | *(dst + 1) = HEX_LOW(us >> 8); |
371 | | #endif |
372 | | if((end - src) == 3) { |
373 | | *(dst + 4) = HEX_HI(*(src + 2)); |
374 | | *(dst + 5) = HEX_LOW(*(src + 2)); |
375 | | } |
376 | | /* no need to inc anything */ |
377 | | break; |
378 | | case 1: |
379 | | *dst = HEX_HI(*src); |
380 | | *(dst + 1) = HEX_LOW(*src); |
381 | | /* no need to inc anything */ |
382 | | case 0: |
383 | | break; |
384 | | } |
385 | | } else if(unlikely((long)src & 1)) { |
386 | | /* src is not 2-bytes (short) aligned */ |
387 | | switch((unsigned char)((unsigned char *)end - src)) { |
388 | | case 3: |
389 | | *dst = HEX_HI(*src); |
390 | | *(dst + 1) = HEX_LOW(*src); |
391 | | dst += 2; |
392 | | src++; |
393 | | /* no break */ |
394 | | case 2: |
395 | | us = *(unsigned short *)(src); |
396 | | #if defined __IS_LITTLE_ENDIAN |
397 | | *(dst + 0) = HEX_HI(us); |
398 | | *(dst + 1) = HEX_LOW(us); |
399 | | *(dst + 2) = HEX_HI(us >> 8); |
400 | | *(dst + 3) = HEX_LOW(us >> 8); |
401 | | #elif defined __IS_BIG_ENDIAN |
402 | | *(dst + 2) = HEX_HI(us); |
403 | | *(dst + 3) = HEX_LOW(us); |
404 | | *(dst + 0) = HEX_HI(us >> 8); |
405 | | *(dst + 1) = HEX_LOW(us >> 8); |
406 | | #endif |
407 | | /* no need to inc anything */ |
408 | | break; |
409 | | case 1: |
410 | | *dst = HEX_HI(*src); |
411 | | *(dst + 1) = HEX_LOW(*src); |
412 | | /* no need to inc anything */ |
413 | | case 0: |
414 | | break; |
415 | | } |
416 | | } else { |
417 | | /* src is 2-bytes aligned (short) */ |
418 | | switch((unsigned char)((unsigned char *)end - src)) { |
419 | | case 3: |
420 | | case 2: |
421 | | us = *(unsigned short *)(src); |
422 | | #if defined __IS_LITTLE_ENDIAN |
423 | | *(dst + 0) = HEX_HI(us); |
424 | | *(dst + 1) = HEX_LOW(us); |
425 | | *(dst + 2) = HEX_HI(us >> 8); |
426 | | *(dst + 3) = HEX_LOW(us >> 8); |
427 | | #elif defined __IS_BIG_ENDIAN |
428 | | *(dst + 2) = HEX_HI(us); |
429 | | *(dst + 3) = HEX_LOW(us); |
430 | | *(dst + 0) = HEX_HI(us >> 8); |
431 | | *(dst + 1) = HEX_LOW(us >> 8); |
432 | | #endif |
433 | | if((end - src) == 3) { |
434 | | *(dst + 4) = HEX_HI(*(src + 2)); |
435 | | *(dst + 5) = HEX_LOW(*(src + 2)); |
436 | | } |
437 | | /* no need to inc anything */ |
438 | | break; |
439 | | case 1: |
440 | | *dst = HEX_HI(*src); |
441 | | *(dst + 1) = HEX_LOW(*src); |
442 | | /* no need to inc anything */ |
443 | | case 0: |
444 | | break; |
445 | | } |
446 | | } |
447 | | |
448 | | return osize; |
449 | | } |
450 | | |
451 | | |
452 | | #else /* BASE16_READ_WHOLE_INTS */ |
453 | | |
454 | | |
455 | | /*! |
456 | | * \return : size used from the output buffer (dst) on success, |
457 | | * -size_needed on error |
458 | | * |
459 | | * \note WARNING: the output string is not 0-term |
460 | | */ |
461 | | inline static int base16_enc( |
462 | | unsigned char *src, int slen, unsigned char *dst, int dlen) |
463 | 0 | { |
464 | 0 | unsigned char *end; |
465 | 0 | int osize; |
466 | 0 |
|
467 | 0 | osize = 2 * slen; |
468 | 0 | if(unlikely(dlen < osize)) |
469 | 0 | return -osize; |
470 | 0 | end = src + slen; |
471 | 0 | for(; src < end; src++, dst += 2) { |
472 | 0 | *dst = HEX_HI(*src); |
473 | 0 | *(dst + 1) = HEX_LOW(*src); |
474 | 0 | } |
475 | 0 | return osize; |
476 | 0 | } Unexecuted instantiation: main.c:base16_enc Unexecuted instantiation: basex.c:base16_enc |
477 | | |
478 | | |
479 | | #endif /* BASE16_READ_WHOLE_INTS */ |
480 | | |
481 | | inline static int base16_dec( |
482 | | unsigned char *src, int slen, unsigned char *dst, int dlen) |
483 | 0 | { |
484 | 0 | unsigned char *end; |
485 | 0 | int osize; |
486 | 0 |
|
487 | 0 | osize = slen / 2; |
488 | 0 | if(unlikely(dlen < osize)) |
489 | 0 | return -osize; |
490 | 0 | end = src + 2 * osize; |
491 | 0 | for(; src < end; src += 2, dst++) |
492 | 0 | *dst = (UNHEX(*src) << 4) | UNHEX(*(src + 1)); |
493 | 0 | return osize; |
494 | 0 | } Unexecuted instantiation: main.c:base16_dec Unexecuted instantiation: basex.c:base16_dec |
495 | | |
496 | | |
497 | | /*! \brief helper internal function: encodes v (6 bits value) |
498 | | * \return char ascii encoding on success and 0xff on error |
499 | | * (value out of range) */ |
500 | | inline static unsigned char base64_enc_char(unsigned char v) |
501 | 0 | { |
502 | 0 | switch(v) { |
503 | 0 | case 0x3f: |
504 | 0 | return '/'; |
505 | 0 | case 0x3e: |
506 | 0 | return '+'; |
507 | 0 | default: |
508 | 0 | if(v <= 25) |
509 | 0 | return v + 'A'; |
510 | 0 | else if(v <= 51) |
511 | 0 | return v - 26 + 'a'; |
512 | 0 | else if(v <= 61) |
513 | 0 | return v - 52 + '0'; |
514 | 0 | } |
515 | 0 | return 0xff; |
516 | 0 | } Unexecuted instantiation: main.c:base64_enc_char Unexecuted instantiation: basex.c:base64_enc_char |
517 | | |
518 | | /*! \brief helper internal function: decodes a base64 "digit", |
519 | | * \return value on success (0-63) and 0xff on error (invalid)*/ |
520 | | inline static unsigned base64_dec_char(unsigned char v) |
521 | 0 | { |
522 | 0 | switch(v) { |
523 | 0 | case '/': |
524 | 0 | return 0x3f; |
525 | 0 | case '+': |
526 | 0 | return 0x3e; |
527 | 0 | case ':': |
528 | 0 | case ';': |
529 | 0 | case '<': |
530 | 0 | case '=': |
531 | 0 | case '>': |
532 | 0 | case '?': |
533 | 0 | case '@': |
534 | 0 | case '[': |
535 | 0 | case '\\': |
536 | 0 | case ']': |
537 | 0 | case '^': |
538 | 0 | case '_': |
539 | 0 | case '`': |
540 | 0 | return 0xff; |
541 | 0 | default: |
542 | 0 | if((v) < '0') |
543 | 0 | return 0xff; |
544 | 0 | if((v) <= '9') |
545 | 0 | return (v) - '0' + 0x34; |
546 | 0 | else if((v) <= 'Z') |
547 | 0 | return (v) - 'A'; |
548 | 0 | else if((v) <= 'z') |
549 | 0 | return (v) - 'a' + 0x1a; |
550 | 0 | } |
551 | 0 | return 0xff; |
552 | 0 | } Unexecuted instantiation: main.c:base64_dec_char Unexecuted instantiation: basex.c:base64_dec_char |
553 | | |
554 | | |
555 | | #ifdef BASE64_LOOKUP_8K |
556 | | /*! |
557 | | * \return : size used from the output buffer (dst) on success ((slen+2)/3*4) |
558 | | * -size_needed on error |
559 | | * |
560 | | * \note WARNING: the output string is not 0-term |
561 | | */ |
562 | | inline static int base64_enc( |
563 | | unsigned char *src, int slen, unsigned char *dst, int dlen) |
564 | 0 | { |
565 | 0 | unsigned char *end; |
566 | 0 | int osize; |
567 | 0 |
|
568 | 0 | osize = (slen + 2) / 3 * 4; |
569 | 0 | if(unlikely(dlen < osize)) |
570 | 0 | return -osize; |
571 | 0 | end = src + slen / 3 * 3; |
572 | 0 | if(unlikely((long)dst % 2)) { |
573 | 0 | for(; src < end; src += 3, dst += 4) { |
574 | 0 | dst[0] = FIRST_8B(BASE64_12(src[0], src[1])); |
575 | 0 | dst[1] = LAST_8B(BASE64_12(src[0], src[1])); |
576 | 0 | dst[2] = FIRST_8B(BASE64_34(src[1], src[2])); |
577 | 0 | dst[3] = LAST_8B(BASE64_34(src[1], src[2])); |
578 | 0 | } |
579 | 0 | switch(slen % 3) { |
580 | 0 | case 2: |
581 | 0 | dst[0] = FIRST_8B(BASE64_12(src[0], src[1])); |
582 | 0 | dst[1] = LAST_8B(BASE64_12(src[0], src[1])); |
583 | 0 | dst[2] = FIRST_8B(BASE64_34(src[1], 0)); |
584 | 0 | dst[3] = '='; |
585 | 0 | break; |
586 | 0 | case 1: |
587 | 0 | dst[0] = FIRST_8B(BASE64_12(src[0], 0)); |
588 | 0 | dst[1] = LAST_8B(BASE64_12(src[0], 0)); |
589 | 0 | dst[2] = '='; |
590 | 0 | dst[3] = '='; |
591 | 0 | break; |
592 | 0 | } |
593 | 0 | } else { |
594 | 0 | for(; src < end; src += 3, dst += 4) { |
595 | 0 | *(unsigned short *)(dst + 0) = |
596 | 0 | _bx_b64_12[(src[0] << 4) | (src[1] >> 4)]; |
597 | 0 | *(unsigned short *)(dst + 2) = |
598 | 0 | _bx_b64_12[((src[1] & 0xf) << 8) | src[2]]; |
599 | 0 | } |
600 | 0 | switch(slen % 3) { |
601 | 0 | case 2: |
602 | 0 | *(unsigned short *)(dst + 0) = |
603 | 0 | _bx_b64_12[(src[0] << 4) | (src[1] >> 4)]; |
604 | 0 | *(unsigned short *)(dst + 2) = |
605 | 0 | _bx_b64_12[((src[1] & 0xf) << 8) | 0]; |
606 | 0 | dst[3] = '='; |
607 | 0 | break; |
608 | 0 | case 1: |
609 | 0 | *(unsigned short *)(dst + 0) = _bx_b64_12[(src[0] << 4) | 0]; |
610 | 0 | dst[2] = '='; |
611 | 0 | dst[3] = '='; |
612 | 0 | break; |
613 | 0 | } |
614 | 0 | } |
615 | 0 | return osize; |
616 | 0 | } Unexecuted instantiation: main.c:base64_enc Unexecuted instantiation: basex.c:base64_enc |
617 | | #else /*BASE64_LOOKUP_8K*/ |
618 | | /*! \brief Convert to base64 |
619 | | * \return size used from the output buffer (dst) on success ((slen+2)/3*4) |
620 | | * -size_needed on error |
621 | | * \note WARNING: the output string is not 0-term |
622 | | */ |
623 | | inline static int base64_enc( |
624 | | unsigned char *src, int slen, unsigned char *dst, int dlen) |
625 | | { |
626 | | unsigned char *end; |
627 | | int osize; |
628 | | |
629 | | osize = (slen + 2) / 3 * 4; |
630 | | if(unlikely(dlen < osize)) |
631 | | return -osize; |
632 | | end = src + slen / 3 * 3; |
633 | | for(; src < end; src += 3, dst += 4) { |
634 | | dst[0] = BASE64_1(src[0]); |
635 | | dst[1] = BASE64_2(src[0], src[1]); |
636 | | dst[2] = BASE64_3(src[1], src[2]); |
637 | | dst[3] = BASE64_4(src[2]); |
638 | | } |
639 | | switch(slen % 3) { |
640 | | case 2: |
641 | | dst[0] = BASE64_1(src[0]); |
642 | | dst[1] = BASE64_2(src[0], src[1]); |
643 | | dst[2] = BASE64_3(src[1], 0); |
644 | | dst[3] = '='; |
645 | | break; |
646 | | case 1: |
647 | | dst[0] = BASE64_1(src[0]); |
648 | | dst[1] = BASE64_2(src[0], 0); |
649 | | dst[2] = '='; |
650 | | dst[3] = '='; |
651 | | break; |
652 | | } |
653 | | return osize; |
654 | | } |
655 | | #endif /*BASE64_LOOKUP_8K*/ |
656 | | |
657 | | |
658 | | /*! \brief |
659 | | * \return size used from the output buffer (dst) on success (max: slen/4*3) |
660 | | * -size_needed on error or 0 on bad base64 encoded string |
661 | | * \note WARNING: the output string is not 0-term |
662 | | */ |
663 | | inline static int base64_dec( |
664 | | unsigned char *src, int slen, unsigned char *dst, int dlen) |
665 | 0 | { |
666 | 0 |
|
667 | 0 | unsigned char *end; |
668 | 0 | int osize; |
669 | 0 | register unsigned a, b, c, d; /* more registers used, but allows for |
670 | 0 | parallel execution */ |
671 | 0 |
|
672 | 0 | if(unlikely((slen < 4) || (slen % 4) |
673 | 0 | || (src[slen - 2] == '=' && src[slen - 1] != '='))) |
674 | 0 | return 0; /* invalid base64 enc. */ |
675 | 0 | osize = (slen / 4 * 3) - (src[slen - 2] == '=') - (src[slen - 1] == '='); |
676 | 0 | if(unlikely(dlen < osize)) |
677 | 0 | return -osize; |
678 | 0 | end = src + slen - 4; |
679 | 0 | for(; src < end; src += 4, dst += 3) { |
680 | 0 | #if 0 |
681 | 0 | u= (UNBASE64(src[0])<<18) | (UNBASE64(src[1])<<12) | |
682 | 0 | (UNBASE64(src[2])<<6) | UNBASE64(src[3]); |
683 | 0 | dst[0]=u>>16; |
684 | 0 | dst[1]=u>>8; |
685 | 0 | dst[3]=u; |
686 | 0 | #endif |
687 | 0 | a = UNBASE64(src[0]); |
688 | 0 | b = UNBASE64(src[1]); |
689 | 0 | c = UNBASE64(src[2]); |
690 | 0 | d = UNBASE64(src[3]); |
691 | 0 | dst[0] = (a << 2) | (b >> 4); |
692 | 0 | dst[1] = (b << 4) | (c >> 2); |
693 | 0 | dst[2] = (c << 6) | d; |
694 | 0 | } |
695 | 0 | switch(osize % 3) { |
696 | 0 | case 0: /* no '=' => 3 output bytes at the end */ |
697 | 0 | a = UNBASE64(src[0]); |
698 | 0 | b = UNBASE64(src[1]); |
699 | 0 | c = UNBASE64(src[2]); |
700 | 0 | d = UNBASE64(src[3]); |
701 | 0 | dst[0] = (a << 2) | (b >> 4); |
702 | 0 | dst[1] = (b << 4) | (c >> 2); |
703 | 0 | dst[2] = (c << 6) | d; |
704 | 0 | break; |
705 | 0 | case 2: /* 1 '=' => 2 output bytes at the end */ |
706 | 0 | a = UNBASE64(src[0]); |
707 | 0 | b = UNBASE64(src[1]); |
708 | 0 | c = UNBASE64(src[2]); |
709 | 0 | dst[0] = (a << 2) | (b >> 4); |
710 | 0 | dst[1] = (b << 4) | (c >> 2); |
711 | 0 | break; |
712 | 0 | case 1: /* 2 '=' => 1 output byte at the end */ |
713 | 0 | a = UNBASE64(src[0]); |
714 | 0 | b = UNBASE64(src[1]); |
715 | 0 | dst[0] = (a << 2) | (b >> 4); |
716 | 0 | break; |
717 | 0 | } |
718 | 0 | return osize; |
719 | 0 | } Unexecuted instantiation: main.c:base64_dec Unexecuted instantiation: basex.c:base64_dec |
720 | | |
721 | | |
722 | | /*! \brief |
723 | | * same as \ref base64_enc() but with a different alphabet, that allows simpler and |
724 | | * faster enc/dec |
725 | | * \return size used from the output buffer (dst) on success ((slen+2)/3*4) |
726 | | * -size_needed on error |
727 | | * \note WARNING: the alphabet includes ":;<>?@[]\`", so it might not be suited |
728 | | * in all cases (e.g. encoding something in a sip uri). |
729 | | */ |
730 | | inline static int q_base64_enc( |
731 | | unsigned char *src, int slen, unsigned char *dst, int dlen) |
732 | 0 | { |
733 | 0 | #define q_b64_base '0' |
734 | 0 | #define q_b64_pad 'z' |
735 | 0 | #define Q_BASE64(v) (unsigned char)((v) + q_b64_base) |
736 | 0 | unsigned char *end; |
737 | 0 | int osize; |
738 | 0 |
|
739 | 0 | osize = (slen + 2) / 3 * 4; |
740 | 0 | if(unlikely(dlen < osize)) |
741 | 0 | return -osize; |
742 | 0 | end = src + slen / 3 * 3; |
743 | 0 | for(; src < end; src += 3, dst += 4) { |
744 | 0 | dst[0] = Q_BASE64(src[0] >> 2); |
745 | 0 | dst[1] = (Q_BASE64((src[0] << 4) & 0x3f) | (src[1] >> 4)); |
746 | 0 | dst[2] = (Q_BASE64((src[1] << 2) & 0x3f) | (src[2] >> 6)); |
747 | 0 | dst[3] = Q_BASE64(src[2] & 0x3f); |
748 | 0 | } |
749 | 0 | switch(slen % 3) { |
750 | 0 | case 2: |
751 | 0 | dst[0] = Q_BASE64(src[0] >> 2); |
752 | 0 | dst[1] = (Q_BASE64((src[0] << 4) & 0x3f) | (src[1] >> 4)); |
753 | 0 | dst[2] = Q_BASE64((src[1] << 2) & 0x3f); |
754 | 0 | dst[3] = q_b64_pad; |
755 | 0 | break; |
756 | 0 | case 1: |
757 | 0 | dst[0] = Q_BASE64(src[0] >> 2); |
758 | 0 | dst[1] = Q_BASE64((src[0] << 4) & 0x3f); |
759 | 0 | dst[2] = q_b64_pad; |
760 | 0 | dst[3] = q_b64_pad; |
761 | 0 | break; |
762 | 0 | } |
763 | 0 | return osize; |
764 | 0 | #undef Q_BASE64 |
765 | 0 | } Unexecuted instantiation: main.c:q_base64_enc Unexecuted instantiation: basex.c:q_base64_enc |
766 | | |
767 | | |
768 | | /*! \brief |
769 | | * same as \ref base64_enc() but with a different alphabet, that allows simpler and |
770 | | * faster enc/dec |
771 | | * |
772 | | * \return size used from the output buffer (dst) on success (max: slen/4*3) |
773 | | * -size_needed on error or 0 on bad base64 encoded string |
774 | | * \note WARNING: the output string is not 0-term |
775 | | */ |
776 | | inline static int q_base64_dec( |
777 | | unsigned char *src, int slen, unsigned char *dst, int dlen) |
778 | 0 | { |
779 | 0 | #define Q_UNBASE64(v) (unsigned char)((v)-q_b64_base) |
780 | 0 |
|
781 | 0 | unsigned char *end; |
782 | 0 | int osize; |
783 | 0 | #ifdef SINGLE_REG |
784 | 0 | register unsigned u; |
785 | 0 | #else |
786 | 0 | register unsigned a, b, c, d; /* more registers used, but allows for |
787 | 0 | parallel execution */ |
788 | 0 | #endif |
789 | 0 |
|
790 | 0 | if(unlikely((slen < 4) || (slen % 4) |
791 | 0 | || (src[slen - 2] == q_b64_pad && src[slen - 1] != q_b64_pad))) |
792 | 0 | return 0; /* invalid base64 enc. */ |
793 | 0 | osize = (slen / 4 * 3) - (src[slen - 2] == q_b64_pad) |
794 | 0 | - (src[slen - 1] == q_b64_pad); |
795 | 0 | if(unlikely(dlen < osize)) |
796 | 0 | return -osize; |
797 | 0 | end = src + slen - 4; |
798 | 0 | for(; src < end; src += 4, dst += 3) { |
799 | 0 | #ifdef SINGLE_REG |
800 | 0 | u = (Q_UNBASE64(src[0]) << 18) | (Q_UNBASE64(src[1]) << 12) |
801 | 0 | | (Q_UNBASE64(src[2]) << 6) | Q_UNBASE64(src[3]); |
802 | 0 | dst[0] = u >> 16; |
803 | 0 | dst[1] = u >> 8; |
804 | 0 | dst[2] = u; |
805 | 0 | #else |
806 | 0 | a = Q_UNBASE64(src[0]); |
807 | 0 | b = Q_UNBASE64(src[1]); |
808 | 0 | c = Q_UNBASE64(src[2]); |
809 | 0 | d = Q_UNBASE64(src[3]); |
810 | 0 | dst[0] = (a << 2) | (b >> 4); |
811 | 0 | dst[1] = (b << 4) | (c >> 2); |
812 | 0 | dst[2] = (c << 6) | d; |
813 | 0 | #endif |
814 | 0 | } |
815 | 0 | switch(osize % 3) { |
816 | 0 | case 0: /* no '=' => 3 output bytes at the end */ |
817 | 0 | #ifdef SINGLE_REG |
818 | 0 | u = (Q_UNBASE64(src[0]) << 18) | (Q_UNBASE64(src[1]) << 12) |
819 | 0 | | (Q_UNBASE64(src[2]) << 6) | Q_UNBASE64(src[3]); |
820 | 0 | dst[0] = u >> 16; |
821 | 0 | dst[1] = u >> 8; |
822 | 0 | dst[2] = u; |
823 | 0 | #else |
824 | 0 | a = Q_UNBASE64(src[0]); |
825 | 0 | b = Q_UNBASE64(src[1]); |
826 | 0 | c = Q_UNBASE64(src[2]); |
827 | 0 | d = Q_UNBASE64(src[3]); |
828 | 0 | dst[0] = (a << 2) | (b >> 4); |
829 | 0 | dst[1] = (b << 4) | (c >> 2); |
830 | 0 | dst[2] = (c << 6) | d; |
831 | 0 | #endif |
832 | 0 | break; |
833 | 0 | case 2: /* 1 '=' => 2 output bytes at the end */ |
834 | 0 | #ifdef SINGLE_REG |
835 | 0 | u = (Q_UNBASE64(src[0]) << 12) | (Q_UNBASE64(src[1]) << 6) |
836 | 0 | | (Q_UNBASE64(src[2])); |
837 | 0 | dst[0] = u >> 10; |
838 | 0 | dst[1] = u >> 2; |
839 | 0 | #else |
840 | 0 | a = Q_UNBASE64(src[0]); |
841 | 0 | b = Q_UNBASE64(src[1]); |
842 | 0 | c = Q_UNBASE64(src[2]); |
843 | 0 | dst[0] = (a << 2) | (b >> 4); |
844 | 0 | dst[1] = (b << 4) | (c >> 2); |
845 | 0 | #endif |
846 | 0 | break; |
847 | 0 | case 1: /* 2 '=' => 1 output byte at the end */ |
848 | 0 | #ifdef SINGLE_REG |
849 | 0 | dst[0] = (Q_UNBASE64(src[0]) << 2) | (Q_UNBASE64(src[1]) >> 4); |
850 | 0 | #else |
851 | 0 | a = Q_UNBASE64(src[0]); |
852 | 0 | b = Q_UNBASE64(src[1]); |
853 | 0 | dst[0] = (a << 2) | (b >> 4); |
854 | 0 | #endif |
855 | 0 | break; |
856 | 0 | } |
857 | 0 | return osize; |
858 | 0 | #undef q_b64_base |
859 | 0 | #undef q_b64_pad |
860 | 0 | } Unexecuted instantiation: main.c:q_base64_dec Unexecuted instantiation: basex.c:q_base64_dec |
861 | | |
862 | | /*! \brief inits internal lookup tables */ |
863 | | int init_basex(void); |
864 | | |
865 | | char *b58_encode(char *b58, int *b58sz, char *data, int binsz); |
866 | | char *b58_decode(char *outb, int *outbszp, char *b58, int b58sz); |
867 | | |
868 | | int base64url_enc(char *in, int ilen, char *out, int osize); |
869 | | int base64url_dec(char *in, int ilen, char *out, int osize); |
870 | | |
871 | | #endif /* _basex_h */ |