Browse code

- added fast base64 and base16 encoders/decoders along with test program and some results

Andrei Pelinescu-Onciul authored on 01/07/2008 20:33:20
Showing 4 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,230 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ * convert/decode to/from ascii using various bases
4
+ *
5
+ * Copyright (C) 2008 iptelorg GmbH
6
+ *
7
+ * Permission to use, copy, modify, and distribute this software for any
8
+ * purpose with or without fee is hereby granted, provided that the above
9
+ * copyright notice and this permission notice appear in all copies.
10
+ *
11
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
+ */
19
+/*
20
+ * Defines:
21
+ *  BASE64_LOOKUP_TABLE - use small lookup tables for conversions (faster
22
+ *                         in general)
23
+ *
24
+ * History:
25
+ * --------
26
+ *  2008-06-11  created by andrei
27
+ */
28
+
29
+#include "basex.h"
30
+
31
+#ifdef BASE16_LOOKUP_TABLE
32
+#ifdef BASE16_LOOKUP_LARGE
33
+
34
+unsigned char _bx_hexdig_hi[256]={
35
+	'0', '0', '0', '0', '0', '0', '0', '0',
36
+	'0', '0', '0', '0', '0', '0', '0', '0',
37
+	'1', '1', '1', '1', '1', '1', '1', '1',
38
+	'1', '1', '1', '1', '1', '1', '1', '1',
39
+	'2', '2', '2', '2', '2', '2', '2', '2',
40
+	'2', '2', '2', '2', '2', '2', '2', '2',
41
+	'3', '3', '3', '3', '3', '3', '3', '3',
42
+	'3', '3', '3', '3', '3', '3', '3', '3',
43
+	'4', '4', '4', '4', '4', '4', '4', '4',
44
+	'4', '4', '4', '4', '4', '4', '4', '4',
45
+	'5', '5', '5', '5', '5', '5', '5', '5',
46
+	'5', '5', '5', '5', '5', '5', '5', '5',
47
+	'6', '6', '6', '6', '6', '6', '6', '6',
48
+	'6', '6', '6', '6', '6', '6', '6', '6',
49
+	'7', '7', '7', '7', '7', '7', '7', '7',
50
+	'7', '7', '7', '7', '7', '7', '7', '7',
51
+	'8', '8', '8', '8', '8', '8', '8', '8',
52
+	'8', '8', '8', '8', '8', '8', '8', '8',
53
+	'9', '9', '9', '9', '9', '9', '9', '9',
54
+	'9', '9', '9', '9', '9', '9', '9', '9',
55
+	'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
56
+	'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
57
+	'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
58
+	'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
59
+	'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
60
+	'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
61
+	'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
62
+	'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
63
+	'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
64
+	'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
65
+	'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F',
66
+	'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F'
67
+};
68
+
69
+unsigned char _bx_hexdig_low[256]={
70
+	'0', '1', '2', '3', '4', '5', '6', '7',
71
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
72
+	'0', '1', '2', '3', '4', '5', '6', '7',
73
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
74
+	'0', '1', '2', '3', '4', '5', '6', '7',
75
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
76
+	'0', '1', '2', '3', '4', '5', '6', '7',
77
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
78
+	'0', '1', '2', '3', '4', '5', '6', '7',
79
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
80
+	'0', '1', '2', '3', '4', '5', '6', '7',
81
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
82
+	'0', '1', '2', '3', '4', '5', '6', '7',
83
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
84
+	'0', '1', '2', '3', '4', '5', '6', '7',
85
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
86
+	'0', '1', '2', '3', '4', '5', '6', '7',
87
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
88
+	'0', '1', '2', '3', '4', '5', '6', '7',
89
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
90
+	'0', '1', '2', '3', '4', '5', '6', '7',
91
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
92
+	'0', '1', '2', '3', '4', '5', '6', '7',
93
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
94
+	'0', '1', '2', '3', '4', '5', '6', '7',
95
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
96
+	'0', '1', '2', '3', '4', '5', '6', '7',
97
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
98
+	'0', '1', '2', '3', '4', '5', '6', '7',
99
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
100
+	'0', '1', '2', '3', '4', '5', '6', '7',
101
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
102
+};
103
+
104
+unsigned char _bx_unhexdig256[256]={
105
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
106
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
107
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
108
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
109
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 
110
+0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xff, 0xff, 
111
+0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 
112
+0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
113
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
114
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0b, 0x0c, 
115
+0x0d, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
116
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
117
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
118
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
119
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
120
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
121
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
122
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
123
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
124
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
125
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
126
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
127
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
128
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
129
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
130
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
131
+
132
+#else /* BASE16_LOOKUP_LARGE */
133
+
134
+unsigned char _bx_hexdig[16+1]="0123456789ABCDEF";
135
+
136
+unsigned char _bx_unhexdig32[32]={
137
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 
138
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0b, 0x0c,
139
+	0x0d, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
140
+	0xff };
141
+
142
+#endif /*  BASE16_LOOKUP_LARGE */
143
+#endif /* BASE16_LOOKUP_TABLE */
144
+
145
+#ifdef BASE64_LOOKUP_TABLE
146
+
147
+#ifdef BASE64_LOOKUP_LARGE
148
+/* large lookup tables, 2.5 k */
149
+
150
+unsigned char _bx_b64_first[256];
151
+unsigned char _bx_b64_second[4][256];
152
+unsigned char _bx_b64_third[4][256];
153
+unsigned char _bx_b64_fourth[256];
154
+
155
+unsigned char _bx_ub64[256];
156
+
157
+#elif defined BASE64_LOOKUP_8K
158
+unsigned short _bx_b64_12[4096];
159
+unsigned char _bx_ub64[256];
160
+
161
+#else /*  BASE64_LOOKUP_LARGE */
162
+/* very small lookup, 65 bytes */
163
+
164
+unsigned char _bx_b64[64+1]=
165
+		"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
166
+
167
+
168
+unsigned char _bx_ub64[0x54+1]={
169
+		                              0x3e, 0xff, 0xff, 0xff, 0x3f,
170
+		0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d,
171
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02,
172
+		0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
173
+		0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
174
+		0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1a,
175
+		0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
176
+		0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e,
177
+		0x2f, 0x30, 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff };
178
+
179
+#endif /*  BASE64_LOOKUP_LARGE */
180
+
181
+#endif /* BASE64_LOOKUP_TABLE */
182
+
183
+#define b64_enc_char(c) base64_enc_char(c)
184
+#define b64_dec_char(c) base64_dec_char(c)
185
+
186
+int init_basex()
187
+{
188
+#ifdef BASE64_LOOKUP_TABLE
189
+#if defined BASE64_LOOKUP_LARGE || defined BASE64_LOOKUP_8K
190
+	int r;
191
+#endif
192
+#ifdef BASE64_LOOKUP_LARGE
193
+	int i;
194
+	
195
+	/* encode tables */
196
+	for (r=0; r<256; r++)
197
+		_bx_b64_first[r]=b64_enc_char(((unsigned char)r)>>2);
198
+	for(i=0; i<4; i++){
199
+		for (r=0; r<256; r++)
200
+			_bx_b64_second[i][r]=
201
+					b64_enc_char((unsigned char)((i<<4)|(r>>4)));
202
+	}
203
+	for(i=0; i<4; i++){
204
+		for (r=0; r<256; r++)
205
+			_bx_b64_third[i][r]=
206
+				b64_enc_char((unsigned char)(((r<<2)&0x3f)|i));
207
+	}
208
+	for (r=0; r<256; r++)
209
+		_bx_b64_fourth[r]=b64_enc_char(((unsigned char)r&0x3f));
210
+	
211
+	/* decode */
212
+	for (r=0; r<256; r++)
213
+		_bx_ub64[r]=b64_dec_char((unsigned char)r);
214
+#elif defined BASE64_LOOKUP_8K
215
+	for (r=0; r< 4096; r++)
216
+#if defined __IS_LITTLE_ENDIAN
217
+		_bx_b64_12[r]=b64_enc_char(r>>6)|(b64_enc_char(r&0x3f)<<8);
218
+#elif defined __IS_BIG_ENDIAN /* __IS_LITTLE_ENDIAN */
219
+		_bx_b64_12[r]=(b64_enc_char(r>>6)<<8)|b64_enc_char(r&0x3f);
220
+#else /* __IS_LITTLE_ENDIAN */
221
+#error Neither __IS_LITTE_ENDIAN nor __IS_BIG_ENDIAN  defined
222
+#endif
223
+	/* decode */
224
+	for (r=0; r<256; r++)
225
+		_bx_ub64[r]=b64_dec_char((unsigned char)r);
226
+#endif
227
+#endif
228
+	return 0;
229
+}
0 230
new file mode 100644
... ...
@@ -0,0 +1,869 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ * convert/decode to/from ascii using various bases
4
+ *
5
+ * Copyright (C) 2008 iptelorg GmbH
6
+ *
7
+ * Permission to use, copy, modify, and distribute this software for any
8
+ * purpose with or without fee is hereby granted, provided that the above
9
+ * copyright notice and this permission notice appear in all copies.
10
+ *
11
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
+ */
19
+/*
20
+ * Functions:
21
+ *  init_basex()                              - inits internal lookup tables
22
+ *  HEX_HI(unsigned char c)                   - returns the first 4 bits of
23
+ *                                              c converted to a hex digit
24
+ *  HEX_LOW(unsigned char c)                  - returns the low 4 bits of
25
+ *                                              c converted to a hex digit
26
+ *  UNHEX(unsigned char hex_digit)            - converts hex_digit to a
27
+ *                                              number (0..15); it might
28
+ *                                              return 0xff for invalid 
29
+ *                                              digit (but with some compile
30
+ *                                              option it won't check)
31
+ *
32
+ *  base16_enc(src, src_len, dst, dst_len)    - encode to standard hex
33
+ *  base16_dec(src, src_len, dst, dst_len)    - decode from standard hex
34
+ *  base16_enc_len(len)                       - length needed to encode len
35
+ *                                              bytes (macro)
36
+ *  base16_max_dec_len(len)                   - length needed to decode a 
37
+ *                                              string of size len
38
+ *
39
+ *  base64_enc(src, src_len, dst, dst_len)    - encode to base64, standard
40
+ *                                              alphabet
41
+ *  base64_dec(src, src_len, dst, dst_len)    - decode from base64, standard
42
+ *                                              alphabet
43
+ *  base64_enc_len(len)                       - length needed to encode
44
+ *                                               len bytes (macro)
45
+ *  base64_max_dec_len(len)                   - maximum length needed to
46
+ *                                               decode len bytes (macro)
47
+ *  base64_dec_len(str, len)                  - size of the decoded str 
48
+ *
49
+ *
50
+ *  q_base64_enc(src, src_len, dst, dst_len)  - encode to special base64
51
+ *                                              alphabet (non standard)
52
+ *
53
+ *  q_base64_dec(src, src_len, dst, dst_len)  - decode from special non-
54
+ *                                              standard base64 alphabet
55
+ *  All the above functions return the size used (in dst) on success and
56
+ *   0 or a negative number (which is -1*size_needed) on error.
57
+ *
58
+ * There are close to no checks for validity, an unexpected char will lead
59
+ * to a corrupted result, but the functions won't return error.
60
+ *
61
+ * Notes:
62
+ *  on a core2 duo the versions with lookup tables are way faster (see
63
+ *  http://www.experts-exchange.com/Programming/Languages/CPP/Q_21988706.html
64
+ *  for some interesting tests and ideeas).
65
+ *
66
+ *  Test results for 40 bytes  (typical ser nounce) in average cpu cycles:
67
+ *                    lookup   lookup_large lookup8k no-lookup
68
+ *  base16_enc           211/231  218/199      -       1331
69
+ *  base16_dec           252/251  236          -       1226
70
+ *  base64_enc           209      186         156      1005
71
+ *  base64_dec           208      207         207      1242
72
+ *  q_base64_enc         -                              288
73
+ *  q_base64_dec         -                              281
74
+ *  (see test/basex.txt for more results)
75
+ *
76
+ * Defines:
77
+ *  BASE64_LOOKUP_TABLE/NO_BASE64_LOOKUP_TABLE - use (default)/don't use
78
+ *     small lookup tables for conversions (faster in general).
79
+ *  BASE64_LOOKUP_LARGE    - use large lookup tables (2560 bytes for 
80
+ *    encoding and 256 bytes for decoding; without it 64 bytes are used for
81
+ *    encoding and 85 bytes for decoding.
82
+ *  BASE64_LOOKUP_8K - use even larger lookup tables (8K for encoding and
83
+ *    256 for decoding); also try to write 2 bytes at a time (short) if
84
+ *    the destination is 2 byte aligned
85
+ *
86
+ *  BASE16_LOOKUP_TABLE/NO_BASE16_LOOKUP_TABLE - use (default)/don't use
87
+ *     small lookup tables for conversions (faster in general).
88
+ *  BASE16_LOOKUP_LARGE  - use large lookup tables (512 bytes for 
89
+ *    encoding and 256 bytes for decoding
90
+ *  BASE16_READ_WHOLE_INTS - read an int at a time
91
+ *
92
+ * History:
93
+ * --------
94
+ *  2008-06-11  created by andrei
95
+ */
96
+ 
97
+
98
+
99
+#ifndef _basex_h
100
+#define _basex_h
101
+
102
+#include "compiler_opt.h"
103
+
104
+/* defaults */
105
+#ifndef NO_BASE16_LOOKUP_TABLE
106
+#define BASE16_LOOKUP_TABLE
107
+#endif
108
+
109
+#ifndef NO_BASE64_LOOKUP_TABLE
110
+#define BASE64_LOOKUP_TABLE
111
+#endif
112
+
113
+#ifndef NO_BASE64_LOOKUP_8K
114
+#define BASE64_LOOKUP_8K
115
+#endif
116
+
117
+#ifndef NO_BASE16_LOOKUP_LARGE
118
+#define BASE16_LOOKUP_LARGE
119
+#endif
120
+
121
+#if !defined NO_BASE64_LOOKUP_LARGE && !defined BASE64_LOOKUP_8K
122
+#define BASE64_LOOKUP_LARGE
123
+#endif
124
+
125
+
126
+
127
+#if defined BASE16_READ_WHOLE_INTS || defined BASE64_READ_WHOLE_INTS || \
128
+	defined BASE64_LOOKUP_8K
129
+#include "endianness.h"
130
+
131
+/* aligns p to a type* pointer, type must have a 2^k size */
132
+#define ALIGN_POINTER(p, type) \
133
+	((type*) ((long)((char*)(p)+sizeof(type)-1)&~(long)(sizeof(type)-1)))
134
+
135
+#define ALIGN_UINT_POINTER(p) ALIGN_POINTER(p, unsigned int)
136
+
137
+#endif
138
+
139
+
140
+#ifdef BASE16_LOOKUP_TABLE
141
+
142
+#ifdef BASE16_LOOKUP_LARGE
143
+/* use large tables: 512 for lookup and 256 for decode */
144
+
145
+extern unsigned char _bx_hexdig_hi[256];
146
+extern unsigned char _bx_hexdig_low[256];
147
+
148
+#define HEX_HI(h)	_bx_hexdig_hi[(unsigned char)(h)]
149
+#define HEX_LOW(h)	_bx_hexdig_low[(unsigned char)(h)]
150
+
151
+extern unsigned char _bx_unhexdig256[256];
152
+
153
+#define UNHEX(h)	_bx_unhexdig256[(h)]
154
+
155
+#else /* BASE16_LOOKUP_LARGE */
156
+/* use small tabes: 16 bytes for lookup and 32 for decode */
157
+
158
+extern unsigned char _bx_hexdig[16+1];
159
+
160
+#define HEX_4BITS(h) _bx_hexdig[(h)]
161
+#define HEX_HI(h)	HEX_4BITS(((unsigned char)(h))>>4)
162
+#define HEX_LOW(h)	HEX_4BITS((h)&0xf)
163
+
164
+extern unsigned char _bx_unhexdig32[32];
165
+#define UNHEX(h) _bx_unhexdig32[(((h))-'0')&0x1f]
166
+
167
+#endif /* BASE16_LOOKUP_LARGE */
168
+
169
+#else /* BASE16_LOOKUP_TABLE */
170
+/* no lookup tables */
171
+#if 0
172
+#define HEX_4BITS(h) (unsigned char)((unlikely((h)>=10))?((h)-10+'A'):(h)+'0')
173
+#define UNHEX(c) (unsigned char)((unlikely((c)>='A'))?(c)-'A'+10:(c)-'0')
174
+#else
175
+#define HEX_4BITS(hc) (unsigned char)( ((((hc)>=10)-1)&((hc)+'0')) | \
176
+									((((hc)<10)-1)&((hc)+'A')) )
177
+#define UNHEX(c) (unsigned char) ( ((((c)>'9')-1)& ((c)-'0')) | \
178
+								((((c)<='9')-1)&((c)-'A')) )
179
+#endif 
180
+
181
+#define HEX_HI(h)	HEX_4BITS(((unsigned char)(h))>>4)
182
+#define HEX_LOW(h)	HEX_4BITS((h)&0xf)
183
+
184
+#endif /* BASE16_LOOKUP_TABLE */
185
+
186
+
187
+#ifdef BASE64_LOOKUP_TABLE
188
+#ifdef BASE64_LOOKUP_LARGE
189
+/* large lookup tables, 2.5 k */
190
+
191
+extern unsigned char _bx_b64_first[256];
192
+extern unsigned char _bx_b64_second[4][256];
193
+extern unsigned char _bx_b64_third[4][256];
194
+extern unsigned char _bx_b64_fourth[256];
195
+
196
+#define BASE64_1(a) _bx_b64_first[(a)]
197
+#define BASE64_2(a,b) _bx_b64_second[(a)&0x3][(b)]
198
+#define BASE64_3(b,c) _bx_b64_third[(c)>>6][(b)]
199
+#define BASE64_4(c) _bx_b64_fourth[(c)]
200
+
201
+extern unsigned char _bx_ub64[256];
202
+#define UNBASE64(v) _bx_ub64[(v)]
203
+
204
+#elif defined BASE64_LOOKUP_8K
205
+/* even larger encode tables: 8k */
206
+extern unsigned short _bx_b64_12[4096];
207
+
208
+/* return a word (16 bits) */
209
+#define BASE64_12(a,b)	_bx_b64_12[((a)<<4)|((b)>>4)]
210
+#define BASE64_34(b,c)	_bx_b64_12[(((b)&0xf)<<8)|(c)]
211
+#ifdef __IS_LITTLE_ENDIAN
212
+#define FIRST_8B(s)	((unsigned char)(s))
213
+#define LAST_8B(s)	((s)>>8)
214
+#elif defined __IS_BIG_ENDIAN
215
+#define FIRST_8B(s)	((s)>>8)
216
+#define LAST_8B(s)	((unsigned char)(s))
217
+#else
218
+#error neither __IS_LITTLE_ENDIAN nor __IS_BIG_ENDIAN are defined
219
+#endif
220
+
221
+
222
+extern unsigned char _bx_ub64[256];
223
+#define UNBASE64(v) _bx_ub64[(v)]
224
+
225
+#else /* BASE64_LOOKUP_LARGE */
226
+/* small lookup tables */
227
+extern unsigned char _bx_b64[64+1];
228
+
229
+#define BASE64_DIG(v)	_bx_b64[(v)]
230
+
231
+#define BASE64_1(a)		BASE64_DIG((a)>>2)
232
+#define BASE64_2(a, b)	BASE64_DIG( (((a)<<4)&0x3f) | ((b)>>4))
233
+#define BASE64_3(b, c)	BASE64_DIG( (((b)<<2)&0x3f) | ((c)>>6))
234
+#define BASE64_4(c)		BASE64_DIG((c)&0x3f)
235
+
236
+extern unsigned char _bx_ub64[0x54+1];
237
+#define UNBASE64(v) _bx_ub64[(((v)&0x7f)-0x2b)]
238
+
239
+#endif /* BASE64_LOOKUP_LARGE */
240
+
241
+
242
+#else /* BASE64_LOOKUP_TABLE */
243
+
244
+#define BASE64_DIG(v) base64_enc_char(v)
245
+#define BASE64_1(a)		BASE64_DIG((a)>>2)
246
+#define BASE64_2(a, b)	BASE64_DIG( (((a)<<4)&0x3f) | ((b)>>4))
247
+#define BASE64_3(b, c)	BASE64_DIG( (((b)<<2)&0x3f) | ((c)>>6))
248
+#define BASE64_4(c)		BASE64_DIG((c)&0x3f)
249
+
250
+#define UNBASE64(v) base64_dec_char(v)
251
+
252
+#endif /* BASE64_LOOKUP_TABLE */
253
+
254
+
255
+
256
+/* lenght needed for encoding l bytes */
257
+#define base16_enc_len(l) (l*2)
258
+/* maximum lenght needed for decoding l bytes */
259
+#define base16_max_dec_len(l) (l/2)
260
+/* actual space needed for decoding a string b of size l */
261
+#define base16_dec_len(b, l) base16_max_dec_len(l)
262
+/* minimum valid source len for decoding */
263
+#define base16_dec_min_len() 2
264
+/* minimum valid source len for encoding */
265
+#define base16_enc_min_len() 0
266
+
267
+/* space needed for encoding l bytes */
268
+#define base64_enc_len(l) (((l)+2)/3*4)
269
+/* maximum space needed for encoding l bytes */
270
+#define base64_max_dec_len(l) ((l)/4*3)
271
+/* actual space needed for decoding a string b of size l, l>=4 */
272
+#define base64_dec_len(b, l) \
273
+	(base64_max_dec_len(l)-((b)[(l)-2]=='=') -((b)[(l)-1]=='='))
274
+/* minimum valid source len for decoding */
275
+#define base64_dec_min_len() 4
276
+/* minimum valid source len for encoding */
277
+#define base64_enc_min_len() 0
278
+
279
+
280
+#ifdef BASE16_READ_WHOLE_INTS
281
+
282
+/* params: 
283
+ * returns: size used from the output buffer (dst) on success,
284
+ *          -size_needed on error
285
+ * WARNING: the output string is not 0-term
286
+ */
287
+inline static int base16_enc(unsigned char* src, int slen,
288
+							 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
+/* params: 
457
+ * returns: size used from the output buffer (dst) on success,
458
+ *          -size_needed on error
459
+ * WARNING: the output string is not 0-term
460
+ */
461
+inline static int base16_enc(unsigned char* src, int slen,
462
+							 unsigned char*  dst, int dlen)
463
+{
464
+	unsigned char* end;
465
+	int osize;
466
+	
467
+	osize=2*slen;
468
+	if (unlikely(dlen<osize))
469
+		return -osize;
470
+	end=src+slen;
471
+	for (;src<end; src++,dst+=2){
472
+		*dst=HEX_HI(*src);
473
+		*(dst+1)=HEX_LOW(*src);
474
+	}
475
+	return osize;
476
+}
477
+
478
+
479
+#endif /* BASE16_READ_WHOLE_INTS */
480
+
481
+inline static int base16_dec(unsigned char* src, int slen,
482
+							 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
+/* helper internal function: encodes v (6 bits value)
501
+ * returns 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
+/* helper internal function: decodes a base64 "digit",
522
+ * returns 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
+/* params: 
560
+ * returns: size used from the output buffer (dst) on success ((slen+2)/3*4)
561
+ *          -size_needed on error
562
+ * WARNING: the output string is not 0-term
563
+ */
564
+inline static int base64_enc(unsigned char* src, int slen,
565
+							unsigned char* dst,  int dlen)
566
+{
567
+	unsigned char* end;
568
+	int osize;
569
+	
570
+	osize=(slen+2)/3*4;
571
+	if (unlikely(dlen<osize))
572
+		return -osize;
573
+	end=src+slen/3*3;
574
+	if (unlikely((long)dst%2)){
575
+		for (;src<end; src+=3,dst+=4){
576
+			dst[0]=FIRST_8B(BASE64_12(src[0], src[1]));
577
+			dst[1]=LAST_8B(BASE64_12(src[0], src[1]));
578
+			dst[2]=FIRST_8B(BASE64_34(src[1], src[2]));
579
+			dst[3]=LAST_8B(BASE64_34(src[1], src[2]));
580
+		}
581
+		switch(slen%3){
582
+			case 2:
583
+				dst[0]=FIRST_8B(BASE64_12(src[0], src[1]));
584
+				dst[1]=LAST_8B(BASE64_12(src[0], src[1]));
585
+				dst[2]=FIRST_8B(BASE64_34(src[1], 0));
586
+				dst[3]='=';
587
+				break;
588
+			case 1:
589
+				dst[0]=FIRST_8B(BASE64_12(src[0], 0));
590
+				dst[1]=LAST_8B(BASE64_12(src[0], 0));
591
+				dst[2]='=';
592
+				dst[3]='=';
593
+				break;
594
+		}
595
+	}else{
596
+		for (;src<end; src+=3,dst+=4){
597
+			*(unsigned short*)(dst+0)=_bx_b64_12[(src[0]<<4)|(src[1]>>4)];
598
+			*(unsigned short*)(dst+2)=_bx_b64_12[((src[1]&0xf)<<8)|src[2]];
599
+		}
600
+		switch(slen%3){
601
+			case 2:
602
+				*(unsigned short*)(dst+0)=_bx_b64_12[(src[0]<<4)|(src[1]>>4)];
603
+				*(unsigned short*)(dst+2)=_bx_b64_12[((src[1]&0xf)<<8)|0];
604
+				dst[3]='=';
605
+				break;
606
+			case 1:
607
+				*(unsigned short*)(dst+0)=_bx_b64_12[(src[0]<<4)|0];
608
+				dst[2]='=';
609
+				dst[3]='=';
610
+				break;
611
+		}
612
+	}
613
+	return osize;
614
+}
615
+#else /*BASE64_LOOKUP_8K*/
616
+/* params: 
617
+ * returns: size used from the output buffer (dst) on success ((slen+2)/3*4)
618
+ *          -size_needed on error
619
+ * WARNING: the output string is not 0-term
620
+ */
621
+inline static int base64_enc(unsigned char* src, int slen,
622
+							unsigned char* dst,  int dlen)
623
+{
624
+	unsigned char* end;
625
+	int osize;
626
+	
627
+	osize=(slen+2)/3*4;
628
+	if (unlikely(dlen<osize))
629
+		return -osize;
630
+	end=src+slen/3*3;
631
+	for (;src<end; src+=3,dst+=4){
632
+		dst[0]=BASE64_1(src[0]);
633
+		dst[1]=BASE64_2(src[0], src[1]);
634
+		dst[2]=BASE64_3(src[1], src[2]);
635
+		dst[3]=BASE64_4(src[2]);
636
+	}
637
+	switch(slen%3){
638
+		case 2:
639
+			dst[0]=BASE64_1(src[0]);
640
+			dst[1]=BASE64_2(src[0], src[1]);
641
+			dst[2]=BASE64_3(src[1], 0);
642
+			dst[3]='=';
643
+			break;
644
+		case 1:
645
+			dst[0]=BASE64_1(src[0]);
646
+			dst[1]=BASE64_2(src[0], 0);
647
+			dst[2]='=';
648
+			dst[3]='=';
649
+			break;
650
+	}
651
+	return osize;
652
+}
653
+#endif /*BASE64_LOOKUP_8K*/
654
+
655
+
656
+
657
+/* params: 
658
+ * returns: size used from the output buffer (dst) on success (max: slen/4*3)
659
+ *          -size_needed on error or 0 on bad base64 encoded string
660
+ * WARNING: the output string is not 0-term
661
+ */
662
+inline static int base64_dec(unsigned char* src, int slen,
663
+							unsigned char* dst,  int dlen)
664
+{
665
+	
666
+	unsigned char* end;
667
+	int osize;
668
+	register unsigned a, b, c, d; /* more registers used, but allows for
669
+									 paralles execution */
670
+	
671
+	if (unlikely((slen<4) || (slen%4) || 
672
+				(src[slen-2]=='=' && src[slen-1]!='=')))
673
+		return 0; /* invalid base64 enc. */
674
+	osize=(slen/4*3)-(src[slen-2]=='=')-(src[slen-1]=='=');
675
+	if (unlikely(dlen<osize))
676
+		return -osize;
677
+	end=src+slen-4;
678
+	for (;src<end; src+=4,dst+=3){
679
+#if 0
680
+		u=	(UNBASE64(src[0])<<18) | (UNBASE64(src[1])<<12) | 
681
+			(UNBASE64(src[2])<<6)  |  UNBASE64(src[3]);
682
+		dst[0]=u>>16;
683
+		dst[1]=u>>8;
684
+		dst[3]=u;
685
+#endif
686
+		a=UNBASE64(src[0]);
687
+		b=UNBASE64(src[1]);
688
+		c=UNBASE64(src[2]);
689
+		d=UNBASE64(src[3]);
690
+		dst[0]=(a<<2) | (b>>4);
691
+		dst[1]=(b<<4) | (c>>2);
692
+		dst[2]=(c<<6) | d;
693
+	}
694
+	switch(osize%3){
695
+		case 0: /* no '=' => 3 output bytes at the end */
696
+			a=UNBASE64(src[0]);
697
+			b=UNBASE64(src[1]);
698
+			c=UNBASE64(src[2]);
699
+			d=UNBASE64(src[3]);
700
+			dst[0]=(a<<2) | (b>>4);
701
+			dst[1]=(b<<4) | (c>>2);
702
+			dst[2]=(c<<6) | d;
703
+			break;
704
+		case 2: /* 1  '=' => 2 output bytes at the end */
705
+			a=UNBASE64(src[0]);
706
+			b=UNBASE64(src[1]);
707
+			c=UNBASE64(src[2]);
708
+			dst[0]=(a<<2) | (b>>4);
709
+			dst[1]=(b<<4) | (c>>2);
710
+			break;
711
+		case 1: /* 2  '=' => 1 output byte at the end */
712
+			a=UNBASE64(src[0]);
713
+			b=UNBASE64(src[1]);
714
+			dst[0]=(a<<2) | (b>>4);
715
+			break;
716
+	}
717
+	return osize;
718
+}
719
+
720
+
721
+
722
+
723
+/*
724
+ * same as base64_enc but with a different alphabet, that allows simpler and
725
+ *  faster enc/dec
726
+ * params: 
727
+ * returns: size used from the output buffer (dst) on success ((slen+2)/3*4)
728
+ *          -size_needed on error
729
+ * 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
+/*
772
+ * same as base64_enc but with a different alphabet, that allows simpler and
773
+ *  faster enc/dec
774
+ * params: 
775
+ * params: 
776
+ * returns: size used from the output buffer (dst) on success (max: slen/4*3)
777
+ *          -size_needed on error or 0 on bad base64 encoded string
778
+ * WARNING: the output string is not 0-term
779
+ */
780
+inline static int q_base64_dec(unsigned char* src, int slen,
781
+							unsigned char* dst,  int dlen)
782
+{
783
+#define Q_UNBASE64(v) (unsigned char)((v)-q_b64_base)
784
+	
785
+	unsigned char* end;
786
+	int osize;
787
+#ifdef SINGLE_REG
788
+	register unsigned u;
789
+#else
790
+	register unsigned a, b, c, d; /* more registers used, but allows for
791
+									 paralles execution */
792
+#endif
793
+	
794
+	if (unlikely((slen<4) || (slen%4) || 
795
+				(src[slen-2]==q_b64_pad && src[slen-1]!=q_b64_pad)))
796
+		return 0; /* invalid base64 enc. */
797
+	osize=(slen/4*3)-(src[slen-2]==q_b64_pad)-(src[slen-1]==q_b64_pad);
798
+	if (unlikely(dlen<osize))
799
+		return -osize;
800
+	end=src+slen-4;
801
+	for (;src<end; src+=4,dst+=3){
802
+#ifdef SINGLE_REG
803
+		u=	(Q_UNBASE64(src[0])<<18) | (Q_UNBASE64(src[1])<<12) | 
804
+			(Q_UNBASE64(src[2])<<6)  |  Q_UNBASE64(src[3]);
805
+		dst[0]=u>>16;
806
+		dst[1]=u>>8;
807
+		dst[2]=u;
808
+#else
809
+		a=Q_UNBASE64(src[0]);
810
+		b=Q_UNBASE64(src[1]);
811
+		c=Q_UNBASE64(src[2]);
812
+		d=Q_UNBASE64(src[3]);
813
+		dst[0]=(a<<2) | (b>>4);
814
+		dst[1]=(b<<4) | (c>>2);
815
+		dst[2]=(c<<6) | d;
816
+#endif
817
+	}
818
+	switch(osize%3){
819
+		case 0: /* no '=' => 3 output bytes at the end */
820
+#ifdef SINGLE_REG
821
+			u=	(Q_UNBASE64(src[0])<<18) | (Q_UNBASE64(src[1])<<12) | 
822
+				(Q_UNBASE64(src[2])<<6)  |  Q_UNBASE64(src[3]);
823
+			dst[0]=u>>16;
824
+			dst[1]=u>>8;
825
+			dst[2]=u;
826
+#else
827
+			a=Q_UNBASE64(src[0]);
828
+			b=Q_UNBASE64(src[1]);
829
+			c=Q_UNBASE64(src[2]);
830
+			d=Q_UNBASE64(src[3]);
831
+			dst[0]=(a<<2) | (b>>4);
832
+			dst[1]=(b<<4) | (c>>2);
833
+			dst[2]=(c<<6) | d;
834
+#endif
835
+			break;
836
+		case 2: /* 1  '=' => 2 output bytes at the end */
837
+#ifdef SINGLE_REG
838
+			u=	(Q_UNBASE64(src[0])<<12) | (Q_UNBASE64(src[1])<<6) | 
839
+				(Q_UNBASE64(src[2]));
840
+			dst[0]=u>>10;
841
+			dst[1]=u>>2;
842
+#else
843
+			a=Q_UNBASE64(src[0]);
844
+			b=Q_UNBASE64(src[1]);
845
+			c=Q_UNBASE64(src[2]);
846
+			dst[0]=(a<<2) | (b>>4);
847
+			dst[1]=(b<<4) | (c>>2);
848
+#endif
849
+			break;
850
+		case 1: /* 2  '=' => 1 output byte at the end */
851
+#ifdef SINGLE_REG
852
+			dst[0]=(Q_UNBASE64(src[0])<<2) | (Q_UNBASE64(src[1])>>4); 
853
+#else
854
+			a=Q_UNBASE64(src[0]);
855
+			b=Q_UNBASE64(src[1]);
856
+			dst[0]=(a<<2) | (b>>4);
857
+#endif
858
+			break;
859
+	}
860
+	return osize;
861
+#undef q_b64_base
862
+#undef q_b64_pad
863
+}
864
+
865
+int init_basex();
866
+
867
+
868
+#endif /* _basex_h */
0 869
new file mode 100644
... ...
@@ -0,0 +1,401 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ * Tests for basex.h
4
+ *
5
+ * Copyright (C) 2008 iptelorg GmbH
6
+ *
7
+ * Permission to use, copy, modify, and distribute this software for any
8
+ * purpose with or without fee is hereby granted, provided that the above
9
+ * copyright notice and this permission notice appear in all copies.
10
+ *
11
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
+ */
19
+
20
+
21
+/*#define NO_BASE64_LOOKUP_TABLE
22
+ #define SINGLE_REG */
23
+
24
+#include "../basex.h"
25
+#include "profile.h"
26
+
27
+#include <stdio.h>
28
+#include <stdlib.h>
29
+#include <unistd.h>
30
+#include <sys/types.h>
31
+#include <sys/stat.h>
32
+#include <fcntl.h>
33
+#include <errno.h>
34
+#include <string.h>
35
+#include <time.h>
36
+#include <ctype.h>
37
+
38
+
39
+#ifndef MIN
40
+#define MIN(a,b) (((a)<(b))?(a):(b))
41
+#endif
42
+
43
+#define BASE64 64
44
+#define Q_BASE64 640
45
+#define BASE16 16
46
+
47
+#ifndef BASEX
48
+#define BASEX BASE16
49
+#endif
50
+
51
+#if BASEX == Q_BASE64
52
+
53
+#warning Q_BASE64
54
+#define B_ENC	q_base64_enc
55
+#define B_DEC	q_base64_dec
56
+#define B_ENC_LEN(l)	(((l)+2)/3*4)
57
+
58
+#elif BASEX == BASE16
59
+
60
+#warning BASE16
61
+#define B_ENC	base16_enc
62
+#define B_DEC	base16_dec
63
+#define B_ENC_LEN(l)	((l)*2)
64
+
65
+#else
66
+
67
+#warning BASE64
68
+#define B_ENC	base64_enc
69
+#define B_DEC	base64_dec
70
+#define B_ENC_LEN(l)	(((l)+2)/3*4)
71
+
72
+
73
+#endif
74
+
75
+
76
+#define QUOTE_MACRO(x) QUOTEME(x)
77
+#define QUOTEME(x) #x
78
+
79
+static char* id="$Id$";
80
+static char* version="basex test 0.1 " 
81
+"BASE" QUOTE_MACRO(BASEX)  ": " QUOTE_MACRO(B_ENC) ", " QUOTE_MACRO(B_DEC) ""
82
+#if defined BASE64_LOOKUP_TABLE 
83
+#ifdef BASE64_LOOKUP_LARGE
84
+" (large b64 lookup table)"
85
+#else
86
+" (lookup b64 table)"
87
+#endif
88
+#else
89
+" (no b64 lookup table)"
90
+#endif
91
+#if defined BASE16_LOOKUP_TABLE
92
+#ifdef BASE16_LOOKUP_LARGE
93
+" (large b16 lookup table)"
94
+#else
95
+" (lookup b16 table)"
96
+#endif
97
+#else
98
+" (no b16 lookup table)"
99
+#endif
100
+#if defined BASE64_READ_WHOLE_INTS || defined BASE16_READ_WHOLE_INTS
101
+" (read 4 bytes at a time)"
102
+#else
103
+" (read 1 byte at a time)"
104
+#endif
105
+;
106
+
107
+static char* help_msg="\
108
+Usage: basex  [-hv] ... [options]\n\
109
+Options:\n\
110
+    -m min        minimum length\n\
111
+    -M max        maximum length\n\
112
+    -o offset     offset from the start of the buffer (alignment tests)\n\
113
+    -e offset     offset from the start of the dst. buf. (alignment tests)\n\
114
+    -n no.        number of test loops\n\
115
+    -v            increase verbosity\n\
116
+    -V            version number\n\
117
+    -h            this help message\n\
118
+";
119
+
120
+
121
+/* profiling */
122
+struct profile_data pf1, pf2, pf3, pf4, pf5, pf6;
123
+
124
+
125
+void dump_profile_info(struct profile_data* pd)
126
+{
127
+	printf("profiling for %s (%ld/%ld):  %lld/%lld/%lld (max/avg/last),"
128
+			" total %lld\n",
129
+			pd->name, pd->entries, pd->exits, pd->max_cycles, 
130
+			pd->entries?pd->total_cycles/pd->entries:0, pd->cycles,
131
+			pd->total_cycles);
132
+}
133
+
134
+
135
+
136
+int seed_prng()
137
+{
138
+	int seed, rfd;
139
+	
140
+	if ((rfd=open("/dev/urandom", O_RDONLY))!=-1){
141
+try_again:
142
+		if (read(rfd, (void*)&seed, sizeof(seed))==-1){
143
+			if (errno==EINTR) goto try_again; /* interrupted by signal */
144
+				fprintf(stderr, "WARNING: could not read from /dev/urandom: "
145
+								" %s (%d)\n", strerror(errno), errno);
146
+		}
147
+		close(rfd);
148
+	}else{
149
+		fprintf(stderr, "WARNING: could not open /dev/urandom: %s (%d)\n",
150
+						strerror(errno), errno);
151
+	}
152
+	seed+=getpid()+time(0);
153
+	srand(seed);
154
+	return 0;
155
+}
156
+
157
+
158
+/* fill buf with random data*/
159
+void fill_rand(unsigned char* buf, int len)
160
+{
161
+	unsigned char* end;
162
+	int v;
163
+
164
+/* find out how many random bytes we can get from rand() */
165
+#if RAND_MAX >= 0xffffffff
166
+#define RAND_BYTES 4
167
+#warning RAND_BYTES is 4
168
+#elif RAND_MAX >= 0xffffff
169
+#define RAND_BYTES 3
170
+#warning RAND_BYTES is 3
171
+#elif RAND_MAX >= 0xffff
172
+#define RAND_BYTES 2
173
+#warning RAND_BYTES is 2
174
+#else
175
+#define RAND_BYTES 1
176
+#endif
177
+
178
+	end=buf+len/RAND_BYTES*RAND_BYTES;
179
+	for(;buf<end;buf+=RAND_BYTES){
180
+		v=rand();
181
+		buf[0]=v;
182
+#if RAND_BYTES > 1
183
+		buf[1]=v>>8;
184
+#endif
185
+#if RAND_BYTES > 2
186
+		buf[2]=v>>16;
187
+#endif
188
+#if RAND_BYTES > 4
189
+		buf[3]=v>>24;
190
+#endif
191
+	}
192
+	v=rand();
193
+	switch(end-buf){
194
+		case 3:
195
+#if RAND_BYTES > 2
196
+			buf[2]=v>>16;
197
+#else
198
+			buf[2]=rand();
199
+#endif
200
+		case 2:
201
+#if RAND_BYTES > 1
202
+			buf[1]=v>>8;
203
+#else
204
+			buf[1]=rand();
205
+#endif
206
+		case 1:
207
+			buf[0]=v;
208
+		case 0:
209
+			break;
210
+	}
211
+}
212
+
213
+
214
+
215
+int main(int argc, char** argv)
216
+{
217
+
218
+	int loops, min_len, max_len, offset, e_offset;
219
+	unsigned char* ibuf;
220
+	unsigned char* enc_buf;
221
+	unsigned char* dec_buf;
222
+	int ibuf_len, enc_buf_len, dec_buf_len;
223
+	int offs, c_len, e_len, l;
224
+	int r;
225
+	int verbose;
226
+	int c;
227
+	char* tmp;
228
+
229
+	verbose=0;
230
+	min_len=max_len=offset=-1;
231
+	e_offset=0;
232
+	loops=1024;
233
+	opterr=0;
234
+	while ((c=getopt(argc, argv, "n:m:M:o:e:vhV"))!=-1){
235
+		switch(c){
236
+			case 'n':
237
+				loops=strtol(optarg, &tmp, 0);
238
+				if ((tmp==0)||(*tmp)||(loops<0)){
239
+					fprintf(stderr, "bad number: -%c %s\n", c, optarg);
240
+					goto error;
241
+				}
242
+				break;
243
+			case 'm':
244
+				min_len=strtol(optarg, &tmp, 0);
245
+				if ((tmp==0)||(*tmp)||(min_len<0)){
246
+					fprintf(stderr, "bad number: -%c %s\n", c, optarg);
247
+					goto error;
248
+				}
249
+				break;
250
+			case 'M':
251
+				max_len=strtol(optarg, &tmp, 0);
252
+				if ((tmp==0)||(*tmp)||(max_len<0)){
253
+					fprintf(stderr, "bad number: -%c %s\n", c, optarg);
254
+					goto error;
255
+				}
256
+				break;
257
+			case 'o':
258
+				offset=strtol(optarg, &tmp, 0);
259
+				if ((tmp==0)||(*tmp)||(offset<0)){
260
+					fprintf(stderr, "bad number: -%c %s\n", c, optarg);
261
+					goto error;
262
+				}
263
+				break;
264
+			case 'e':
265
+				e_offset=strtol(optarg, &tmp, 0);
266
+				if ((tmp==0)||(*tmp)||(e_offset<0)){
267
+					fprintf(stderr, "bad number: -%c %s\n", c, optarg);
268
+					goto error;
269
+				}
270
+				break;
271
+			case 'v':
272
+				verbose++;
273
+				break;
274
+			case 'V':
275
+				printf("version: %s\n", version);
276
+				printf("%s\n", id);
277
+				exit(0);
278
+				break;
279
+			case 'h':
280
+				printf("version: %s\n", version);
281
+				printf("%s", help_msg);
282
+				exit(0);
283
+				break;
284
+			case '?':
285
+				if (isprint(optopt))
286
+					fprintf(stderr, "Unknown option `-%c\n", optopt);
287
+				else
288
+					fprintf(stderr, "Unknown character `\\x%x\n", optopt);
289
+				goto error;
290
+			case ':':
291
+				fprintf(stderr, "Option `-%c requires an argument.\n",
292
+						optopt);
293
+				goto error;
294
+				break;
295
+			default:
296
+				abort();
297
+		}
298
+	}
299
+	if (min_len==-1 && max_len==-1){
300
+		min_len=0;
301
+		max_len=4*1024*1024;
302
+	}else if (min_len==-1)
303
+		min_len=0;
304
+	else if (max_len==-1)
30