Merge kamailio modules into sip-router master branch
[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  * Functions:
22  *  init_basex()                              - inits internal lookup tables
23  *  HEX_HI(unsigned char c)                   - returns the first 4 bits of
24  *                                              c converted to a hex digit
25  *  HEX_LOW(unsigned char c)                  - returns the low 4 bits of
26  *                                              c converted to a hex digit
27  *  UNHEX(unsigned char hex_digit)            - converts hex_digit to a
28  *                                              number (0..15); it might
29  *                                              return 0xff for invalid 
30  *                                              digit (but with some compile
31  *                                              option it won't check)
32  *
33  *  base16_enc(src, src_len, dst, dst_len)    - encode to standard hex
34  *  base16_dec(src, src_len, dst, dst_len)    - decode from standard hex
35  *  base16_enc_len(len)                       - length needed to encode len
36  *                                              bytes (macro)
37  *  base16_max_dec_len(len)                   - length needed to decode a 
38  *                                              string of size len
39  *
40  *  base64_enc(src, src_len, dst, dst_len)    - encode to base64, standard
41  *                                              alphabet
42  *  base64_dec(src, src_len, dst, dst_len)    - decode from base64, standard
43  *                                              alphabet
44  *  base64_enc_len(len)                       - length needed to encode
45  *                                               len bytes (macro)
46  *  base64_max_dec_len(len)                   - maximum length needed to
47  *                                               decode len bytes (macro)
48  *  base64_dec_len(str, len)                  - size of the decoded str 
49  *
50  *
51  *  q_base64_enc(src, src_len, dst, dst_len)  - encode to special base64
52  *                                              alphabet (non standard)
53  *
54  *  q_base64_dec(src, src_len, dst, dst_len)  - decode from special non-
55  *                                              standard base64 alphabet
56  *  All the above functions return the size used (in dst) on success and
57  *   0 or a negative number (which is -1*size_needed) on error.
58  *
59  * There are close to no checks for validity, an unexpected char will lead
60  * to a corrupted result, but the functions won't return error.
61  *
62  * Notes:
63  *  on a core2 duo the versions with lookup tables are way faster (see
64  *  http://www.experts-exchange.com/Programming/Languages/CPP/Q_21988706.html
65  *  for some interesting tests and ideeas).
66  *
67  *  Test results for 40 bytes  (typical ser nounce) in average cpu cycles:
68  *                    lookup   lookup_large lookup8k no-lookup
69  *  base16_enc           211/231  218/199      -       1331
70  *  base16_dec           252/251  236          -       1226
71  *  base64_enc           209      186         156      1005
72  *  base64_dec           208      207         207      1242
73  *  q_base64_enc         -                              288
74  *  q_base64_dec         -                              281
75  *  (see test/basex.txt for more results)
76  *
77  * Defines:
78  *  BASE64_LOOKUP_TABLE/NO_BASE64_LOOKUP_TABLE - use (default)/don't use
79  *     small lookup tables for conversions (faster in general).
80  *  BASE64_LOOKUP_LARGE    - use large lookup tables (2560 bytes for 
81  *    encoding and 256 bytes for decoding; without it 64 bytes are used for
82  *    encoding and 85 bytes for decoding.
83  *  BASE64_LOOKUP_8K - use even larger lookup tables (8K for encoding and
84  *    256 for decoding); also try to write 2 bytes at a time (short) if
85  *    the destination is 2 byte aligned
86  *
87  *  BASE16_LOOKUP_TABLE/NO_BASE16_LOOKUP_TABLE - use (default)/don't use
88  *     small lookup tables for conversions (faster in general).
89  *  BASE16_LOOKUP_LARGE  - use large lookup tables (512 bytes for 
90  *    encoding and 256 bytes for decoding
91  *  BASE16_READ_WHOLE_INTS - read an int at a time
92  *
93  * History:
94  * --------
95  *  2008-06-11  created by andrei
96  */
97  
98
99
100 #ifndef _basex_h
101 #define _basex_h
102
103 #include "compiler_opt.h"
104
105 /* defaults */
106 #ifndef NO_BASE16_LOOKUP_TABLE
107 #define BASE16_LOOKUP_TABLE
108 #endif
109
110 #ifndef NO_BASE64_LOOKUP_TABLE
111 #define BASE64_LOOKUP_TABLE
112 #endif
113
114 #ifndef NO_BASE64_LOOKUP_8K
115 #define BASE64_LOOKUP_8K
116 #endif
117
118 #ifndef NO_BASE16_LOOKUP_LARGE
119 #define BASE16_LOOKUP_LARGE
120 #endif
121
122 #if !defined NO_BASE64_LOOKUP_LARGE && !defined BASE64_LOOKUP_8K
123 #define BASE64_LOOKUP_LARGE
124 #endif
125
126
127
128 #if defined BASE16_READ_WHOLE_INTS || defined BASE64_READ_WHOLE_INTS || \
129         defined BASE64_LOOKUP_8K
130 #include "endianness.h"
131
132 /* aligns p to a type* pointer, type must have a 2^k size */
133 #define ALIGN_POINTER(p, type) \
134         ((type*) ((long)((char*)(p)+sizeof(type)-1)&~(long)(sizeof(type)-1)))
135
136 #define ALIGN_UINT_POINTER(p) ALIGN_POINTER(p, unsigned int)
137
138 #endif
139
140
141 #ifdef BASE16_LOOKUP_TABLE
142
143 #ifdef BASE16_LOOKUP_LARGE
144 /* use large tables: 512 for lookup and 256 for decode */
145
146 extern unsigned char _bx_hexdig_hi[256];
147 extern unsigned char _bx_hexdig_low[256];
148
149 #define HEX_HI(h)       _bx_hexdig_hi[(unsigned char)(h)]
150 #define HEX_LOW(h)      _bx_hexdig_low[(unsigned char)(h)]
151
152 extern unsigned char _bx_unhexdig256[256];
153
154 #define UNHEX(h)        _bx_unhexdig256[(h)]
155
156 #else /* BASE16_LOOKUP_LARGE */
157 /* use small tabes: 16 bytes for lookup and 32 for decode */
158
159 extern unsigned char _bx_hexdig[16+1];
160
161 #define HEX_4BITS(h) _bx_hexdig[(h)]
162 #define HEX_HI(h)       HEX_4BITS(((unsigned char)(h))>>4)
163 #define HEX_LOW(h)      HEX_4BITS((h)&0xf)
164
165 extern unsigned char _bx_unhexdig32[32];
166 #define UNHEX(h) _bx_unhexdig32[(((h))-'0')&0x1f]
167
168 #endif /* BASE16_LOOKUP_LARGE */
169
170 #else /* BASE16_LOOKUP_TABLE */
171 /* no lookup tables */
172 #if 0
173 #define HEX_4BITS(h) (unsigned char)((unlikely((h)>=10))?((h)-10+'A'):(h)+'0')
174 #define UNHEX(c) (unsigned char)((unlikely((c)>='A'))?(c)-'A'+10:(c)-'0')
175 #else
176 #define HEX_4BITS(hc) (unsigned char)( ((((hc)>=10)-1)&((hc)+'0')) | \
177                                                                         ((((hc)<10)-1)&((hc)+'A')) )
178 #define UNHEX(c) (unsigned char) ( ((((c)>'9')-1)& ((c)-'0')) | \
179                                                                 ((((c)<='9')-1)&((c)-'A')) )
180 #endif 
181
182 #define HEX_HI(h)       HEX_4BITS(((unsigned char)(h))>>4)
183 #define HEX_LOW(h)      HEX_4BITS((h)&0xf)
184
185 #endif /* BASE16_LOOKUP_TABLE */
186
187
188 #ifdef BASE64_LOOKUP_TABLE
189 #ifdef BASE64_LOOKUP_LARGE
190 /* large lookup tables, 2.5 k */
191
192 extern unsigned char _bx_b64_first[256];
193 extern unsigned char _bx_b64_second[4][256];
194 extern unsigned char _bx_b64_third[4][256];
195 extern unsigned char _bx_b64_fourth[256];
196
197 #define BASE64_1(a) _bx_b64_first[(a)]
198 #define BASE64_2(a,b) _bx_b64_second[(a)&0x3][(b)]
199 #define BASE64_3(b,c) _bx_b64_third[(c)>>6][(b)]
200 #define BASE64_4(c) _bx_b64_fourth[(c)]
201
202 extern unsigned char _bx_ub64[256];
203 #define UNBASE64(v) _bx_ub64[(v)]
204
205 #elif defined BASE64_LOOKUP_8K
206 /* even larger encode tables: 8k */
207 extern unsigned short _bx_b64_12[4096];
208
209 /* return a word (16 bits) */
210 #define BASE64_12(a,b)  _bx_b64_12[((a)<<4)|((b)>>4)]
211 #define BASE64_34(b,c)  _bx_b64_12[(((b)&0xf)<<8)|(c)]
212 #ifdef __IS_LITTLE_ENDIAN
213 #define FIRST_8B(s)     ((unsigned char)(s))
214 #define LAST_8B(s)      ((s)>>8)
215 #elif defined __IS_BIG_ENDIAN
216 #define FIRST_8B(s)     ((s)>>8)
217 #define LAST_8B(s)      ((unsigned char)(s))
218 #else
219 #error neither __IS_LITTLE_ENDIAN nor __IS_BIG_ENDIAN are defined
220 #endif
221
222
223 extern unsigned char _bx_ub64[256];
224 #define UNBASE64(v) _bx_ub64[(v)]
225
226 #else /* BASE64_LOOKUP_LARGE */
227 /* small lookup tables */
228 extern unsigned char _bx_b64[64+1];
229
230 #define BASE64_DIG(v)   _bx_b64[(v)]
231
232 #define BASE64_1(a)             BASE64_DIG((a)>>2)
233 #define BASE64_2(a, b)  BASE64_DIG( (((a)<<4)&0x3f) | ((b)>>4))
234 #define BASE64_3(b, c)  BASE64_DIG( (((b)<<2)&0x3f) | ((c)>>6))
235 #define BASE64_4(c)             BASE64_DIG((c)&0x3f)
236
237 extern unsigned char _bx_ub64[0x54+1];
238 #define UNBASE64(v) _bx_ub64[(((v)&0x7f)-0x2b)]
239
240 #endif /* BASE64_LOOKUP_LARGE */
241
242
243 #else /* BASE64_LOOKUP_TABLE */
244
245 #define BASE64_DIG(v) base64_enc_char(v)
246 #define BASE64_1(a)             BASE64_DIG((a)>>2)
247 #define BASE64_2(a, b)  BASE64_DIG( (((a)<<4)&0x3f) | ((b)>>4))
248 #define BASE64_3(b, c)  BASE64_DIG( (((b)<<2)&0x3f) | ((c)>>6))
249 #define BASE64_4(c)             BASE64_DIG((c)&0x3f)
250
251 #define UNBASE64(v) base64_dec_char(v)
252
253 #endif /* BASE64_LOOKUP_TABLE */
254
255
256
257 /* lenght needed for encoding l bytes */
258 #define base16_enc_len(l) (l*2)
259 /* maximum lenght needed for decoding l bytes */
260 #define base16_max_dec_len(l) (l/2)
261 /* actual space needed for decoding a string b of size l */
262 #define base16_dec_len(b, l) base16_max_dec_len(l)
263 /* minimum valid source len for decoding */
264 #define base16_dec_min_len() 2
265 /* minimum valid source len for encoding */
266 #define base16_enc_min_len() 0
267
268 /* space needed for encoding l bytes */
269 #define base64_enc_len(l) (((l)+2)/3*4)
270 /* maximum space needed for encoding l bytes */
271 #define base64_max_dec_len(l) ((l)/4*3)
272 /* actual space needed for decoding a string b of size l, l>=4 */
273 #define base64_dec_len(b, l) \
274         (base64_max_dec_len(l)-((b)[(l)-2]=='=') -((b)[(l)-1]=='='))
275 /* minimum valid source len for decoding */
276 #define base64_dec_min_len() 4
277 /* minimum valid source len for encoding */
278 #define base64_enc_min_len() 0
279
280
281 #ifdef BASE16_READ_WHOLE_INTS
282
283 /* params: 
284  * returns: size used from the output buffer (dst) on success,
285  *          -size_needed on error
286  * WARNING: the output string is not 0-term
287  */
288 inline static int base16_enc(unsigned char* src, int slen,
289                                                          unsigned char*  dst, int dlen)
290 {
291         unsigned int* p;
292         unsigned char* end;
293         int osize;
294         unsigned short us;
295         
296         osize=2*slen;
297         if (unlikely(dlen<osize))
298                 return -osize;
299         end=src+slen;
300         p=ALIGN_UINT_POINTER(src);
301         if (likely((unsigned char*)p<end)){
302                 switch((unsigned char)((unsigned char*)p-src)){
303                         case 3:
304                                 *dst=HEX_HI(*src);
305                                 *(dst+1)=HEX_LOW(*src);
306                                 dst+=2;
307                                 src++;
308                                 /* no break */
309                         case 2:
310                                 us=*(unsigned short*)(src);
311 #if   defined __IS_LITTLE_ENDIAN
312                                 *(dst+0)=HEX_HI(us);
313                                 *(dst+1)=HEX_LOW(us);
314                                 *(dst+2)=HEX_HI(us>>8);
315                                 *(dst+3)=HEX_LOW(us>>8);
316 #elif defined __IS_BIG_ENDIAN
317                                 *(dst+2)=HEX_HI(us);
318                                 *(dst+3)=HEX_LOW(us);
319                                 *(dst+0)=HEX_HI(us>>8);
320                                 *(dst+1)=HEX_LOW(us>>8);
321 #endif
322                                 dst+=4;
323                                 /* no need to inc src */
324                                 break;
325                         case 1:
326                                 *dst=HEX_HI(*src);
327                                 *(dst+1)=HEX_LOW(*src);
328                                 dst+=2;
329                                 /* no need to inc src */
330                         case 0:
331                                 break;
332                 }
333                 for(;(unsigned char*)p<=(end-4);p++,dst+=8){
334 #if   defined __IS_LITTLE_ENDIAN
335                         *(dst+0)=HEX_HI(*p);
336                         *(dst+1)=HEX_LOW(*p);
337                         *(dst+2)=HEX_HI(((*p)>>8));
338                         *(dst+3)=HEX_LOW(((*p)>>8));
339                         *(dst+4)=HEX_HI(((*p)>>16));
340                         *(dst+5)=HEX_LOW(((*p)>>16));
341                         *(dst+6)=HEX_HI(((*p)>>24));
342                         *(dst+7)=HEX_LOW(((*p)>>24));
343 #elif defined __IS_BIG_ENDIAN
344                         *(dst+6)=HEX_HI(*p);
345                         *(dst+7)=HEX_LOW(*p);
346                         *(dst+4)=HEX_HI(((*p)>>8));
347                         *(dst+5)=HEX_LOW(((*p)>>8));
348                         *(dst+2)=HEX_HI(((*p)>>16));
349                         *(dst+3)=HEX_LOW(((*p)>>16));
350                         *(dst+0)=HEX_HI(((*p)>>24));
351                         *(dst+1)=HEX_LOW(((*p)>>24));
352 #else
353 #error neither BIG ro LITTLE endian defined
354 #endif /* __IS_*_ENDIAN */
355                 }
356                 src=(unsigned char*)p;
357                 /* src is 2-bytes aligned (short) */
358                 switch((unsigned char)((unsigned char*)end-src)){
359                         case 3:
360                         case 2:
361                                 us=*(unsigned short*)(src);
362 #if   defined __IS_LITTLE_ENDIAN
363                                 *(dst+0)=HEX_HI(us);
364                                 *(dst+1)=HEX_LOW(us);
365                                 *(dst+2)=HEX_HI(us>>8);
366                                 *(dst+3)=HEX_LOW(us>>8);
367 #elif defined __IS_BIG_ENDIAN
368                                 *(dst+2)=HEX_HI(us);
369                                 *(dst+3)=HEX_LOW(us);
370                                 *(dst+0)=HEX_HI(us>>8);
371                                 *(dst+1)=HEX_LOW(us>>8);
372 #endif
373                                 if ((end-src)==3){
374                                         *(dst+4)=HEX_HI(*(src+2));
375                                         *(dst+5)=HEX_LOW(*(src+2));
376                                 }
377                                 /* no need to inc anything */
378                                 break;
379                         case 1:
380                                 *dst=HEX_HI(*src);
381                                 *(dst+1)=HEX_LOW(*src);
382                                 /* no need to inc anything */
383                         case 0:
384                                 break;
385                 }
386         }else if (unlikely((long)src&1)){
387                 /* src is not 2-bytes (short) aligned */
388                 switch((unsigned char)((unsigned char*)end-src)){
389                         case 3:
390                                 *dst=HEX_HI(*src);
391                                 *(dst+1)=HEX_LOW(*src);
392                                 dst+=2;
393                                 src++;
394                                 /* no break */
395                         case 2:
396                                 us=*(unsigned short*)(src);
397 #if   defined __IS_LITTLE_ENDIAN
398                                 *(dst+0)=HEX_HI(us);
399                                 *(dst+1)=HEX_LOW(us);
400                                 *(dst+2)=HEX_HI(us>>8);
401                                 *(dst+3)=HEX_LOW(us>>8);
402 #elif defined __IS_BIG_ENDIAN
403                                 *(dst+2)=HEX_HI(us);
404                                 *(dst+3)=HEX_LOW(us);
405                                 *(dst+0)=HEX_HI(us>>8);
406                                 *(dst+1)=HEX_LOW(us>>8);
407 #endif
408                                 /* no need to inc anything */
409                                 break;
410                         case 1:
411                                 *dst=HEX_HI(*src);
412                                 *(dst+1)=HEX_LOW(*src);
413                                 /* no need to inc anything */
414                         case 0:
415                                 break;
416                 }
417         }else{
418                 /* src is 2-bytes aligned (short) */
419                 switch((unsigned char)((unsigned char*)end-src)){
420                         case 3:
421                         case 2:
422                                 us=*(unsigned short*)(src);
423 #if   defined __IS_LITTLE_ENDIAN
424                                 *(dst+0)=HEX_HI(us);
425                                 *(dst+1)=HEX_LOW(us);
426                                 *(dst+2)=HEX_HI(us>>8);
427                                 *(dst+3)=HEX_LOW(us>>8);
428 #elif defined __IS_BIG_ENDIAN
429                                 *(dst+2)=HEX_HI(us);
430                                 *(dst+3)=HEX_LOW(us);
431                                 *(dst+0)=HEX_HI(us>>8);
432                                 *(dst+1)=HEX_LOW(us>>8);
433 #endif
434                                 if ((end-src)==3){
435                                         *(dst+4)=HEX_HI(*(src+2));
436                                         *(dst+5)=HEX_LOW(*(src+2));
437                                 }
438                                 /* no need to inc anything */
439                                 break;
440                         case 1:
441                                 *dst=HEX_HI(*src);
442                                 *(dst+1)=HEX_LOW(*src);
443                                 /* no need to inc anything */
444                         case 0:
445                                 break;
446                 }
447         }
448         
449         return osize;
450 }
451
452
453
454 #else /* BASE16_READ_WHOLE_INTS */
455
456
457 /* params: 
458  * returns: size used from the output buffer (dst) on success,
459  *          -size_needed on error
460  * 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,
483                                                          unsigned char* dst, int dlen)
484 {
485         unsigned char* end;
486         int osize;
487         
488         osize=slen/2;
489         if (unlikely(dlen<osize))
490                 return -osize;
491         end=src+2*osize;
492         for (; src<end; src+=2, dst++)
493                 *dst=(UNHEX(*src)<<4) | UNHEX(*(src+1));
494         return osize;
495 }
496
497
498
499
500
501 /* helper internal function: encodes v (6 bits value)
502  * returns char ascii encoding on success and 0xff on error
503  * (value out of range) */
504 inline static unsigned char base64_enc_char(unsigned char v)
505 {
506         switch(v){
507                 case 0x3f:
508                         return '/';
509                 case 0x3e:
510                         return '+';
511                 default:
512                         if (v<=25)
513                                 return v+'A';
514                         else if (v<=51)
515                                 return v-26+'a';
516                         else if (v<=61)
517                                 return v-52+'0';
518         }
519         return 0xff;
520 }
521
522 /* helper internal function: decodes a base64 "digit",
523  * returns value on success (0-63) and 0xff on error (invalid)*/
524 inline static unsigned base64_dec_char(unsigned char v)
525 {
526         switch(v){
527                 case '/':
528                         return 0x3f;
529                 case '+':
530                         return 0x3e;
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                 case '`':
544                         return 0xff;
545                 default:
546                         if ((v)<'0')
547                                 return 0xff;
548                         if ((v)<='9')
549                                 return (v)-'0'+0x34;
550                         else if ((v)<='Z')
551                                 return (v)-'A';
552                         else if ((v) <='z')
553                                 return (v)-'a'+0x1a;
554         }
555         return 0xff;
556 }
557
558
559 #ifdef BASE64_LOOKUP_8K
560 /* params: 
561  * returns: size used from the output buffer (dst) on success ((slen+2)/3*4)
562  *          -size_needed on error
563  * 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 /* params: 
618  * returns: size used from the output buffer (dst) on success ((slen+2)/3*4)
619  *          -size_needed on error
620  * 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 /* params: 
659  * returns: 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  * 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 /*
725  * same as base64_enc but with a different alphabet, that allows simpler and
726  *  faster enc/dec
727  * params: 
728  * returns: size used from the output buffer (dst) on success ((slen+2)/3*4)
729  *          -size_needed on error
730  * WARNING: the alphabet includes ":;<>?@[]\`", so it might not be suited
731  *  in all cases (e.g. encoding something in a sip uri).
732  */
733 inline static int q_base64_enc(unsigned char* src, int slen,
734                                                         unsigned char* dst,  int dlen)
735 {
736 #define q_b64_base      '0'
737 #define q_b64_pad       'z'
738 #define Q_BASE64(v)     (unsigned char)((v)+q_b64_base)
739         unsigned char* end;
740         int osize;
741         
742         osize=(slen+2)/3*4;
743         if (unlikely(dlen<osize))
744                 return -osize;
745         end=src+slen/3*3;
746         for (;src<end; src+=3,dst+=4){
747                 dst[0]=Q_BASE64(src[0]>>2);
748                 dst[1]=(Q_BASE64((src[0]<<4)&0x3f) | (src[1]>>4));
749                 dst[2]=(Q_BASE64((src[1]<<2)&0x3f) | (src[2]>>6) );
750                 dst[3]=Q_BASE64(src[2]&0x3f);
751         }
752         switch(slen%3){
753                 case 2:
754                         dst[0]=Q_BASE64(src[0]>>2);
755                         dst[1]=(Q_BASE64((src[0]<<4)&0x3f) | (src[1]>>4));
756                         dst[2]=Q_BASE64((src[1]<<2)&0x3f);
757                         dst[3]=q_b64_pad;
758                         break;
759                 case 1:
760                         dst[0]=Q_BASE64(src[0]>>2);
761                         dst[1]=Q_BASE64((src[0]<<4)&0x3f);
762                         dst[2]=q_b64_pad;
763                         dst[3]=q_b64_pad;
764                         break;
765         }
766         return osize;
767 #undef Q_BASE64
768 }
769
770
771
772 /*
773  * same as base64_enc but with a different alphabet, that allows simpler and
774  *  faster enc/dec
775  * params: 
776  * params: 
777  * returns: size used from the output buffer (dst) on success (max: slen/4*3)
778  *          -size_needed on error or 0 on bad base64 encoded string
779  * WARNING: the output string is not 0-term
780  */
781 inline static int q_base64_dec(unsigned char* src, int slen,
782                                                         unsigned char* dst,  int dlen)
783 {
784 #define Q_UNBASE64(v) (unsigned char)((v)-q_b64_base)
785         
786         unsigned char* end;
787         int osize;
788 #ifdef SINGLE_REG
789         register unsigned u;
790 #else
791         register unsigned a, b, c, d; /* more registers used, but allows for
792                                                                          paralles execution */
793 #endif
794         
795         if (unlikely((slen<4) || (slen%4) || 
796                                 (src[slen-2]==q_b64_pad && src[slen-1]!=q_b64_pad)))
797                 return 0; /* invalid base64 enc. */
798         osize=(slen/4*3)-(src[slen-2]==q_b64_pad)-(src[slen-1]==q_b64_pad);
799         if (unlikely(dlen<osize))
800                 return -osize;
801         end=src+slen-4;
802         for (;src<end; src+=4,dst+=3){
803 #ifdef SINGLE_REG
804                 u=      (Q_UNBASE64(src[0])<<18) | (Q_UNBASE64(src[1])<<12) | 
805                         (Q_UNBASE64(src[2])<<6)  |  Q_UNBASE64(src[3]);
806                 dst[0]=u>>16;
807                 dst[1]=u>>8;
808                 dst[2]=u;
809 #else
810                 a=Q_UNBASE64(src[0]);
811                 b=Q_UNBASE64(src[1]);
812                 c=Q_UNBASE64(src[2]);
813                 d=Q_UNBASE64(src[3]);
814                 dst[0]=(a<<2) | (b>>4);
815                 dst[1]=(b<<4) | (c>>2);
816                 dst[2]=(c<<6) | d;
817 #endif
818         }
819         switch(osize%3){
820                 case 0: /* no '=' => 3 output bytes at the end */
821 #ifdef SINGLE_REG
822                         u=      (Q_UNBASE64(src[0])<<18) | (Q_UNBASE64(src[1])<<12) | 
823                                 (Q_UNBASE64(src[2])<<6)  |  Q_UNBASE64(src[3]);
824                         dst[0]=u>>16;
825                         dst[1]=u>>8;
826                         dst[2]=u;
827 #else
828                         a=Q_UNBASE64(src[0]);
829                         b=Q_UNBASE64(src[1]);
830                         c=Q_UNBASE64(src[2]);
831                         d=Q_UNBASE64(src[3]);
832                         dst[0]=(a<<2) | (b>>4);
833                         dst[1]=(b<<4) | (c>>2);
834                         dst[2]=(c<<6) | d;
835 #endif
836                         break;
837                 case 2: /* 1  '=' => 2 output bytes at the end */
838 #ifdef SINGLE_REG
839                         u=      (Q_UNBASE64(src[0])<<12) | (Q_UNBASE64(src[1])<<6) | 
840                                 (Q_UNBASE64(src[2]));
841                         dst[0]=u>>10;
842                         dst[1]=u>>2;
843 #else
844                         a=Q_UNBASE64(src[0]);
845                         b=Q_UNBASE64(src[1]);
846                         c=Q_UNBASE64(src[2]);
847                         dst[0]=(a<<2) | (b>>4);
848                         dst[1]=(b<<4) | (c>>2);
849 #endif
850                         break;
851                 case 1: /* 2  '=' => 1 output byte at the end */
852 #ifdef SINGLE_REG
853                         dst[0]=(Q_UNBASE64(src[0])<<2) | (Q_UNBASE64(src[1])>>4); 
854 #else
855                         a=Q_UNBASE64(src[0]);
856                         b=Q_UNBASE64(src[1]);
857                         dst[0]=(a<<2) | (b>>4);
858 #endif
859                         break;
860         }
861         return osize;
862 #undef q_b64_base
863 #undef q_b64_pad
864 }
865
866 int init_basex();
867
868
869 #endif /* _basex_h */