- Doxygen updates on core files
[sip-router] / basex.h
1 /*
2  * $Id$
3  *
4  * convert/decode to/from ascii using various bases
5  *
6  * Copyright (C) 2008 iptelorg GmbH
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 /*!
21  * \file
22  * \brief SIP-router core :: convert/decode to/from ascii using various bases
23  *
24  * \ingroup core
25  *
26  * Module: \ref core
27  *
28  *
29  * Functions:
30  *  - init_basex()                    : inits internal lookup tables
31  *  - HEX_HI(unsigned char c)         : returns the first 4 bits of c converted to a hex digit
32  *  - HEX_LOW(unsigned char c)         : returns the low 4 bits of converted to a hex digit
33  *  - UNHEX(unsigned char hex_digit)            : converts hex_digit to a
34  *                                              number (0..15); it might
35  *                                              return 0xff for invalid 
36  *                                              digit (but with some compile
37  *                                              option it won't check)
38  *
39  *  - base16_enc(src, src_len, dst, dst_len)    : encode to standard hex
40  *  - base16_dec(src, src_len, dst, dst_len)    : decode from standard hex
41  *  - base16_enc_len(len)                       : length needed to encode len bytes (macro)
42  *  - base16_max_dec_len(len)                   : length needed to decode a string of size len
43  *
44  *  - base64_enc(src, src_len, dst, dst_len)    : encode to base64, standard alphabet
45  *  - base64_dec(src, src_len, dst, dst_len)    : decode from base64, standard  alphabet
46  *  - base64_enc_len(len)                       : length needed to encode len bytes (macro)
47  *  - base64_max_dec_len(len)                   : maximum length needed to decode len bytes (macro)
48  *  - base64_dec_len(str, len)                  : size of the decoded str 
49  *  - q_base64_enc(src, src_len, dst, dst_len)  : encode to special base64 alphabet (non standard)
50  *  - q_base64_dec(src, src_len, dst, dst_len)  - decode from special non-standard base64 alphabet
51  *
52  *  All the above functions return the size used (in dst) on success and
53  *   0 or a negative number (which is -1*size_needed) on error.
54  *
55  * There are close to no checks for validity, an unexpected char will lead
56  * to a corrupted result, but the functions won't return error.
57  *
58  * Notes:
59  *  on a core2 duo the versions with lookup tables are way faster (see
60  *  http://www.experts-exchange.com/Programming/Languages/CPP/Q_21988706.html
61  *  for some interesting tests and ideeas).
62  *
63  *  Test results for 40 bytes  (typical ser nounce) in average cpu cycles:
64 <verbatim>
65  *                    lookup   lookup_large lookup8k no-lookup
66  *  base16_enc           211/231  218/199      -       1331
67  *  base16_dec           252/251  236          -       1226
68  *  base64_enc           209      186         156      1005
69  *  base64_dec           208      207         207      1242
70  *  q_base64_enc         -                              288
71  *  q_base64_dec         -                              281
72  *  (see test/basex.txt for more results)
73 </verbatim>
74  *
75  * Defines:
76  *  - BASE64_LOOKUP_TABLE/NO_BASE64_LOOKUP_TABLE : use (default)/don't use
77  *     small lookup tables for conversions (faster in general).
78  *  - BASE64_LOOKUP_LARGE    : use large lookup tables (2560 bytes for 
79  *    encoding and 256 bytes for decoding; without it 64 bytes are used for
80  *    encoding and 85 bytes for decoding.
81  *  - BASE64_LOOKUP_8K : use even larger lookup tables (8K for encoding and
82  *    256 for decoding); also try to write 2 bytes at a time (short) if
83  *    the destination is 2 byte aligned
84  *
85  *  - BASE16_LOOKUP_TABLE/NO_BASE16_LOOKUP_TABLE : use (default)/don't use
86  *     small lookup tables for conversions (faster in general).
87  *  - BASE16_LOOKUP_LARGE  : use large lookup tables (512 bytes for 
88  *    encoding and 256 bytes for decoding
89  *  - BASE16_READ_WHOLE_INTS : read an int at a time
90  *
91  * History:
92  * --------
93  *  2008-06-11  created by andrei
94  */
95  
96
97
98 #ifndef _basex_h
99 #define _basex_h
100
101 #include "compiler_opt.h"
102
103 /* defaults */
104 #ifndef NO_BASE16_LOOKUP_TABLE
105 #define BASE16_LOOKUP_TABLE
106 #endif
107
108 #ifndef NO_BASE64_LOOKUP_TABLE
109 #define BASE64_LOOKUP_TABLE
110 #endif
111
112 #ifndef NO_BASE64_LOOKUP_8K
113 #define BASE64_LOOKUP_8K
114 #endif
115
116 #ifndef NO_BASE16_LOOKUP_LARGE
117 #define BASE16_LOOKUP_LARGE
118 #endif
119
120 #if !defined NO_BASE64_LOOKUP_LARGE && !defined BASE64_LOOKUP_8K
121 #define BASE64_LOOKUP_LARGE
122 #endif
123
124
125
126 #if defined BASE16_READ_WHOLE_INTS || defined BASE64_READ_WHOLE_INTS || \
127         defined BASE64_LOOKUP_8K
128 #include "endianness.h"
129
130 /*! \brief aligns p to a type* pointer, type must have a 2^k size */
131 #define ALIGN_POINTER(p, type) \
132         ((type*) ((long)((char*)(p)+sizeof(type)-1)&~(long)(sizeof(type)-1)))
133
134 #define ALIGN_UINT_POINTER(p) ALIGN_POINTER(p, unsigned int)
135
136 #endif
137
138
139 #ifdef BASE16_LOOKUP_TABLE
140
141 #ifdef BASE16_LOOKUP_LARGE
142 /*! \brief use large tables: 512 for lookup and 256 for decode */
143
144 extern unsigned char _bx_hexdig_hi[256];
145 extern unsigned char _bx_hexdig_low[256];
146
147 #define HEX_HI(h)       _bx_hexdig_hi[(unsigned char)(h)]
148 #define HEX_LOW(h)      _bx_hexdig_low[(unsigned char)(h)]
149
150 extern unsigned char _bx_unhexdig256[256];
151
152 #define UNHEX(h)        _bx_unhexdig256[(h)]
153
154 #else /* BASE16_LOOKUP_LARGE */
155 /*! \brief use small tabes: 16 bytes for lookup and 32 for decode */
156
157 extern unsigned char _bx_hexdig[16+1];
158
159 #define HEX_4BITS(h) _bx_hexdig[(h)]
160 #define HEX_HI(h)       HEX_4BITS(((unsigned char)(h))>>4)
161 #define HEX_LOW(h)      HEX_4BITS((h)&0xf)
162
163 extern unsigned char _bx_unhexdig32[32];
164 #define UNHEX(h) _bx_unhexdig32[(((h))-'0')&0x1f]
165
166 #endif /* BASE16_LOOKUP_LARGE */
167
168 #else /* BASE16_LOOKUP_TABLE */
169 /* no lookup tables */
170 #if 0
171 #define HEX_4BITS(h) (unsigned char)((unlikely((h)>=10))?((h)-10+'A'):(h)+'0')
172 #define UNHEX(c) (unsigned char)((unlikely((c)>='A'))?(c)-'A'+10:(c)-'0')
173 #else
174 #define HEX_4BITS(hc) (unsigned char)( ((((hc)>=10)-1)&((hc)+'0')) | \
175                                                                         ((((hc)<10)-1)&((hc)+'A')) )
176 #define UNHEX(c) (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
255 /*! \brief lenght needed for encoding l bytes */
256 #define base16_enc_len(l) (l*2)
257 /*! \brief maximum lenght needed for decoding l bytes */
258 #define base16_max_dec_len(l) (l/2)
259 /*! \brief actual space needed for decoding a string b of size l */
260 #define base16_dec_len(b, l) base16_max_dec_len(l)
261 /*! \brief minimum valid source len for decoding */
262 #define base16_dec_min_len() 2
263 /*! \brief minimum valid source len for encoding */
264 #define base16_enc_min_len() 0
265
266 /*! \brief space needed for encoding l bytes */
267 #define base64_enc_len(l) (((l)+2)/3*4)
268 /*! \brief maximum space needed for encoding l bytes */
269 #define base64_max_dec_len(l) ((l)/4*3)
270 /*! \brief actual space needed for decoding a string b of size l, l>=4 */
271 #define base64_dec_len(b, l) \
272         (base64_max_dec_len(l)-((b)[(l)-2]=='=') -((b)[(l)-1]=='='))
273 /*! \brief minimum valid source len for decoding */
274 #define base64_dec_min_len() 4
275 /*! \brief minimum valid source len for encoding */
276 #define base64_enc_min_len() 0
277
278
279 #ifdef BASE16_READ_WHOLE_INTS
280
281 /*! 
282  * \params: 
283  * \return: size used from the output buffer (dst) on success,
284  *          -size_needed on error
285  *
286  * WARNING: the output string is not 0-term
287  */
288 inline static int base16_enc(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
453 #else /* BASE16_READ_WHOLE_INTS */
454
455
456 /*!
457  * \return : size used from the output buffer (dst) on success,
458  *          -size_needed on error
459  *
460  * \note WARNING: the output string is not 0-term
461  */
462 inline static int base16_enc(unsigned char* src, int slen,
463                                                          unsigned char*  dst, int dlen)
464 {
465         unsigned char* end;
466         int osize;
467         
468         osize=2*slen;
469         if (unlikely(dlen<osize))
470                 return -osize;
471         end=src+slen;
472         for (;src<end; src++,dst+=2){
473                 *dst=HEX_HI(*src);
474                 *(dst+1)=HEX_LOW(*src);
475         }
476         return osize;
477 }
478
479
480 #endif /* BASE16_READ_WHOLE_INTS */
481
482 inline static int base16_dec(unsigned char* src, int slen, unsigned char* dst, int dlen)
483 {
484         unsigned char* end;
485         int osize;
486         
487         osize=slen/2;
488         if (unlikely(dlen<osize))
489                 return -osize;
490         end=src+2*osize;
491         for (; src<end; src+=2, dst++)
492                 *dst=(UNHEX(*src)<<4) | UNHEX(*(src+1));
493         return osize;
494 }
495
496
497
498
499
500 /*! \brief helper internal function: encodes v (6 bits value)
501  * \return char ascii encoding on success and 0xff on error
502  * (value out of range) */
503 inline static unsigned char base64_enc_char(unsigned char v)
504 {
505         switch(v){
506                 case 0x3f:
507                         return '/';
508                 case 0x3e:
509                         return '+';
510                 default:
511                         if (v<=25)
512                                 return v+'A';
513                         else if (v<=51)
514                                 return v-26+'a';
515                         else if (v<=61)
516                                 return v-52+'0';
517         }
518         return 0xff;
519 }
520
521 /*! \brief helper internal function: decodes a base64 "digit",
522  * \return value on success (0-63) and 0xff on error (invalid)*/
523 inline static unsigned base64_dec_char(unsigned char v)
524 {
525         switch(v){
526                 case '/':
527                         return 0x3f;
528                 case '+':
529                         return 0x3e;
530                 case ':':
531                 case ';':
532                 case '<':
533                 case '=':
534                 case '>':
535                 case '?':
536                 case '@':
537                 case '[':
538                 case '\\':
539                 case ']':
540                 case '^':
541                 case '_':
542                 case '`':
543                         return 0xff;
544                 default:
545                         if ((v)<'0')
546                                 return 0xff;
547                         if ((v)<='9')
548                                 return (v)-'0'+0x34;
549                         else if ((v)<='Z')
550                                 return (v)-'A';
551                         else if ((v) <='z')
552                                 return (v)-'a'+0x1a;
553         }
554         return 0xff;
555 }
556
557
558 #ifdef BASE64_LOOKUP_8K
559 /*!
560  * \return : size used from the output buffer (dst) on success ((slen+2)/3*4)
561  *          -size_needed on error
562  *
563  * \note WARNING: the output string is not 0-term
564  */
565 inline static int base64_enc(unsigned char* src, int slen,
566                                                         unsigned char* dst,  int dlen)
567 {
568         unsigned char* end;
569         int osize;
570         
571         osize=(slen+2)/3*4;
572         if (unlikely(dlen<osize))
573                 return -osize;
574         end=src+slen/3*3;
575         if (unlikely((long)dst%2)){
576                 for (;src<end; src+=3,dst+=4){
577                         dst[0]=FIRST_8B(BASE64_12(src[0], src[1]));
578                         dst[1]=LAST_8B(BASE64_12(src[0], src[1]));
579                         dst[2]=FIRST_8B(BASE64_34(src[1], src[2]));
580                         dst[3]=LAST_8B(BASE64_34(src[1], src[2]));
581                 }
582                 switch(slen%3){
583                         case 2:
584                                 dst[0]=FIRST_8B(BASE64_12(src[0], src[1]));
585                                 dst[1]=LAST_8B(BASE64_12(src[0], src[1]));
586                                 dst[2]=FIRST_8B(BASE64_34(src[1], 0));
587                                 dst[3]='=';
588                                 break;
589                         case 1:
590                                 dst[0]=FIRST_8B(BASE64_12(src[0], 0));
591                                 dst[1]=LAST_8B(BASE64_12(src[0], 0));
592                                 dst[2]='=';
593                                 dst[3]='=';
594                                 break;
595                 }
596         }else{
597                 for (;src<end; src+=3,dst+=4){
598                         *(unsigned short*)(dst+0)=_bx_b64_12[(src[0]<<4)|(src[1]>>4)];
599                         *(unsigned short*)(dst+2)=_bx_b64_12[((src[1]&0xf)<<8)|src[2]];
600                 }
601                 switch(slen%3){
602                         case 2:
603                                 *(unsigned short*)(dst+0)=_bx_b64_12[(src[0]<<4)|(src[1]>>4)];
604                                 *(unsigned short*)(dst+2)=_bx_b64_12[((src[1]&0xf)<<8)|0];
605                                 dst[3]='=';
606                                 break;
607                         case 1:
608                                 *(unsigned short*)(dst+0)=_bx_b64_12[(src[0]<<4)|0];
609                                 dst[2]='=';
610                                 dst[3]='=';
611                                 break;
612                 }
613         }
614         return osize;
615 }
616 #else /*BASE64_LOOKUP_8K*/
617 /*! \brief Convert to base64
618  * \return size used from the output buffer (dst) on success ((slen+2)/3*4)
619  *          -size_needed on error
620  * \note WARNING: the output string is not 0-term
621  */
622 inline static int base64_enc(unsigned char* src, int slen,
623                                                         unsigned char* dst,  int dlen)
624 {
625         unsigned char* end;
626         int osize;
627         
628         osize=(slen+2)/3*4;
629         if (unlikely(dlen<osize))
630                 return -osize;
631         end=src+slen/3*3;
632         for (;src<end; src+=3,dst+=4){
633                 dst[0]=BASE64_1(src[0]);
634                 dst[1]=BASE64_2(src[0], src[1]);
635                 dst[2]=BASE64_3(src[1], src[2]);
636                 dst[3]=BASE64_4(src[2]);
637         }
638         switch(slen%3){
639                 case 2:
640                         dst[0]=BASE64_1(src[0]);
641                         dst[1]=BASE64_2(src[0], src[1]);
642                         dst[2]=BASE64_3(src[1], 0);
643                         dst[3]='=';
644                         break;
645                 case 1:
646                         dst[0]=BASE64_1(src[0]);
647                         dst[1]=BASE64_2(src[0], 0);
648                         dst[2]='=';
649                         dst[3]='=';
650                         break;
651         }
652         return osize;
653 }
654 #endif /*BASE64_LOOKUP_8K*/
655
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(unsigned char* src, int slen,
664                                                         unsigned char* dst,  int dlen)
665 {
666         
667         unsigned char* end;
668         int osize;
669         register unsigned a, b, c, d; /* more registers used, but allows for
670                                                                          paralles execution */
671         
672         if (unlikely((slen<4) || (slen%4) || 
673                                 (src[slen-2]=='=' && src[slen-1]!='=')))
674                 return 0; /* invalid base64 enc. */
675         osize=(slen/4*3)-(src[slen-2]=='=')-(src[slen-1]=='=');
676         if (unlikely(dlen<osize))
677                 return -osize;
678         end=src+slen-4;
679         for (;src<end; src+=4,dst+=3){
680 #if 0
681                 u=      (UNBASE64(src[0])<<18) | (UNBASE64(src[1])<<12) | 
682                         (UNBASE64(src[2])<<6)  |  UNBASE64(src[3]);
683                 dst[0]=u>>16;
684                 dst[1]=u>>8;
685                 dst[3]=u;
686 #endif
687                 a=UNBASE64(src[0]);
688                 b=UNBASE64(src[1]);
689                 c=UNBASE64(src[2]);
690                 d=UNBASE64(src[3]);
691                 dst[0]=(a<<2) | (b>>4);
692                 dst[1]=(b<<4) | (c>>2);
693                 dst[2]=(c<<6) | d;
694         }
695         switch(osize%3){
696                 case 0: /* no '=' => 3 output bytes at the end */
697                         a=UNBASE64(src[0]);
698                         b=UNBASE64(src[1]);
699                         c=UNBASE64(src[2]);
700                         d=UNBASE64(src[3]);
701                         dst[0]=(a<<2) | (b>>4);
702                         dst[1]=(b<<4) | (c>>2);
703                         dst[2]=(c<<6) | d;
704                         break;
705                 case 2: /* 1  '=' => 2 output bytes at the end */
706                         a=UNBASE64(src[0]);
707                         b=UNBASE64(src[1]);
708                         c=UNBASE64(src[2]);
709                         dst[0]=(a<<2) | (b>>4);
710                         dst[1]=(b<<4) | (c>>2);
711                         break;
712                 case 1: /* 2  '=' => 1 output byte at the end */
713                         a=UNBASE64(src[0]);
714                         b=UNBASE64(src[1]);
715                         dst[0]=(a<<2) | (b>>4);
716                         break;
717         }
718         return osize;
719 }
720
721
722
723
724 /*! \brief
725  * same as \ref base64_enc() but with a different alphabet, that allows simpler and
726  *  faster enc/dec
727  * \return size used from the output buffer (dst) on success ((slen+2)/3*4)
728  *          -size_needed on error
729  * \note WARNING: the alphabet includes ":;<>?@[]\`", so it might not be suited
730  *  in all cases (e.g. encoding something in a sip uri).
731  */
732 inline static int q_base64_enc(unsigned char* src, int slen,
733                                                         unsigned char* dst,  int dlen)
734 {
735 #define q_b64_base      '0'
736 #define q_b64_pad       'z'
737 #define Q_BASE64(v)     (unsigned char)((v)+q_b64_base)
738         unsigned char* end;
739         int osize;
740         
741         osize=(slen+2)/3*4;
742         if (unlikely(dlen<osize))
743                 return -osize;
744         end=src+slen/3*3;
745         for (;src<end; src+=3,dst+=4){
746                 dst[0]=Q_BASE64(src[0]>>2);
747                 dst[1]=(Q_BASE64((src[0]<<4)&0x3f) | (src[1]>>4));
748                 dst[2]=(Q_BASE64((src[1]<<2)&0x3f) | (src[2]>>6) );
749                 dst[3]=Q_BASE64(src[2]&0x3f);
750         }
751         switch(slen%3){
752                 case 2:
753                         dst[0]=Q_BASE64(src[0]>>2);
754                         dst[1]=(Q_BASE64((src[0]<<4)&0x3f) | (src[1]>>4));
755                         dst[2]=Q_BASE64((src[1]<<2)&0x3f);
756                         dst[3]=q_b64_pad;
757                         break;
758                 case 1:
759                         dst[0]=Q_BASE64(src[0]>>2);
760                         dst[1]=Q_BASE64((src[0]<<4)&0x3f);
761                         dst[2]=q_b64_pad;
762                         dst[3]=q_b64_pad;
763                         break;
764         }
765         return osize;
766 #undef Q_BASE64
767 }
768
769
770
771 /*! \brief
772  * same as \ref base64_enc() but with a different alphabet, that allows simpler and
773  *  faster enc/dec
774  *
775  * \return size used from the output buffer (dst) on success (max: slen/4*3)
776  *          -size_needed on error or 0 on bad base64 encoded string
777  * \note WARNING: the output string is not 0-term
778  */
779 inline static int q_base64_dec(unsigned char* src, int slen,
780                                                         unsigned char* dst,  int dlen)
781 {
782 #define Q_UNBASE64(v) (unsigned char)((v)-q_b64_base)
783         
784         unsigned char* end;
785         int osize;
786 #ifdef SINGLE_REG
787         register unsigned u;
788 #else
789         register unsigned a, b, c, d; /* more registers used, but allows for
790                                                                          paralles execution */
791 #endif
792         
793         if (unlikely((slen<4) || (slen%4) || 
794                                 (src[slen-2]==q_b64_pad && src[slen-1]!=q_b64_pad)))
795                 return 0; /* invalid base64 enc. */
796         osize=(slen/4*3)-(src[slen-2]==q_b64_pad)-(src[slen-1]==q_b64_pad);
797         if (unlikely(dlen<osize))
798                 return -osize;
799         end=src+slen-4;
800         for (;src<end; src+=4,dst+=3){
801 #ifdef SINGLE_REG
802                 u=      (Q_UNBASE64(src[0])<<18) | (Q_UNBASE64(src[1])<<12) | 
803                         (Q_UNBASE64(src[2])<<6)  |  Q_UNBASE64(src[3]);
804                 dst[0]=u>>16;
805                 dst[1]=u>>8;
806                 dst[2]=u;
807 #else
808                 a=Q_UNBASE64(src[0]);
809                 b=Q_UNBASE64(src[1]);
810                 c=Q_UNBASE64(src[2]);
811                 d=Q_UNBASE64(src[3]);
812                 dst[0]=(a<<2) | (b>>4);
813                 dst[1]=(b<<4) | (c>>2);
814                 dst[2]=(c<<6) | d;
815 #endif
816         }
817         switch(osize%3){
818                 case 0: /* no '=' => 3 output bytes at the end */
819 #ifdef SINGLE_REG
820                         u=      (Q_UNBASE64(src[0])<<18) | (Q_UNBASE64(src[1])<<12) | 
821                                 (Q_UNBASE64(src[2])<<6)  |  Q_UNBASE64(src[3]);
822                         dst[0]=u>>16;
823                         dst[1]=u>>8;
824                         dst[2]=u;
825 #else
826                         a=Q_UNBASE64(src[0]);
827                         b=Q_UNBASE64(src[1]);
828                         c=Q_UNBASE64(src[2]);
829                         d=Q_UNBASE64(src[3]);
830                         dst[0]=(a<<2) | (b>>4);
831                         dst[1]=(b<<4) | (c>>2);
832                         dst[2]=(c<<6) | d;
833 #endif
834                         break;
835                 case 2: /* 1  '=' => 2 output bytes at the end */
836 #ifdef SINGLE_REG
837                         u=      (Q_UNBASE64(src[0])<<12) | (Q_UNBASE64(src[1])<<6) | 
838                                 (Q_UNBASE64(src[2]));
839                         dst[0]=u>>10;
840                         dst[1]=u>>2;
841 #else
842                         a=Q_UNBASE64(src[0]);
843                         b=Q_UNBASE64(src[1]);
844                         c=Q_UNBASE64(src[2]);
845                         dst[0]=(a<<2) | (b>>4);
846                         dst[1]=(b<<4) | (c>>2);
847 #endif
848                         break;
849                 case 1: /* 2  '=' => 1 output byte at the end */
850 #ifdef SINGLE_REG
851                         dst[0]=(Q_UNBASE64(src[0])<<2) | (Q_UNBASE64(src[1])>>4); 
852 #else
853                         a=Q_UNBASE64(src[0]);
854                         b=Q_UNBASE64(src[1]);
855                         dst[0]=(a<<2) | (b>>4);
856 #endif
857                         break;
858         }
859         return osize;
860 #undef q_b64_base
861 #undef q_b64_pad
862 }
863
864 int init_basex();
865
866
867 #endif /* _basex_h */