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 @@
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
+ * Defines:
22
+ *  BASE64_LOOKUP_TABLE - use small lookup tables for conversions (faster
23
+ *                         in general)
24
+ *
25
+ * History:
26
+ * --------
27
+ *  2008-06-11  created by andrei
28
+ */
29
+
30
+#include "basex.h"
31
+
32
+#ifdef BASE16_LOOKUP_TABLE
33
+#ifdef BASE16_LOOKUP_LARGE
34
+
35
+unsigned char _bx_hexdig_hi[256]={
36
+	'0', '0', '0', '0', '0', '0', '0', '0',
37
+	'0', '0', '0', '0', '0', '0', '0', '0',
38
+	'1', '1', '1', '1', '1', '1', '1', '1',
39
+	'1', '1', '1', '1', '1', '1', '1', '1',
40
+	'2', '2', '2', '2', '2', '2', '2', '2',
41
+	'2', '2', '2', '2', '2', '2', '2', '2',
42
+	'3', '3', '3', '3', '3', '3', '3', '3',
43
+	'3', '3', '3', '3', '3', '3', '3', '3',
44
+	'4', '4', '4', '4', '4', '4', '4', '4',
45
+	'4', '4', '4', '4', '4', '4', '4', '4',
46
+	'5', '5', '5', '5', '5', '5', '5', '5',
47
+	'5', '5', '5', '5', '5', '5', '5', '5',
48
+	'6', '6', '6', '6', '6', '6', '6', '6',
49
+	'6', '6', '6', '6', '6', '6', '6', '6',
50
+	'7', '7', '7', '7', '7', '7', '7', '7',
51
+	'7', '7', '7', '7', '7', '7', '7', '7',
52
+	'8', '8', '8', '8', '8', '8', '8', '8',
53
+	'8', '8', '8', '8', '8', '8', '8', '8',
54
+	'9', '9', '9', '9', '9', '9', '9', '9',
55
+	'9', '9', '9', '9', '9', '9', '9', '9',
56
+	'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
57
+	'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
58
+	'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
59
+	'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
60
+	'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
61
+	'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
62
+	'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
63
+	'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
64
+	'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
65
+	'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
66
+	'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F',
67
+	'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F'
68
+};
69
+
70
+unsigned char _bx_hexdig_low[256]={
71
+	'0', '1', '2', '3', '4', '5', '6', '7',
72
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
73
+	'0', '1', '2', '3', '4', '5', '6', '7',
74
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
75
+	'0', '1', '2', '3', '4', '5', '6', '7',
76
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
77
+	'0', '1', '2', '3', '4', '5', '6', '7',
78
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
79
+	'0', '1', '2', '3', '4', '5', '6', '7',
80
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
81
+	'0', '1', '2', '3', '4', '5', '6', '7',
82
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
83
+	'0', '1', '2', '3', '4', '5', '6', '7',
84
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
85
+	'0', '1', '2', '3', '4', '5', '6', '7',
86
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
87
+	'0', '1', '2', '3', '4', '5', '6', '7',
88
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
89
+	'0', '1', '2', '3', '4', '5', '6', '7',
90
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
91
+	'0', '1', '2', '3', '4', '5', '6', '7',
92
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
93
+	'0', '1', '2', '3', '4', '5', '6', '7',
94
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
95
+	'0', '1', '2', '3', '4', '5', '6', '7',
96
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
97
+	'0', '1', '2', '3', '4', '5', '6', '7',
98
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
99
+	'0', '1', '2', '3', '4', '5', '6', '7',
100
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
101
+	'0', '1', '2', '3', '4', '5', '6', '7',
102
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
103
+};
104
+
105
+unsigned char _bx_unhexdig256[256]={
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, 0xff, 0xff, 
110
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 
111
+0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xff, 0xff, 
112
+0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 
113
+0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
114
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
115
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0b, 0x0c, 
116
+0x0d, 0x0e, 0x0f, 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, 0xff, 0xff, 0xff, 0xff, 
131
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
132
+
133
+#else /* BASE16_LOOKUP_LARGE */
134
+
135
+unsigned char _bx_hexdig[16+1]="0123456789ABCDEF";
136
+
137
+unsigned char _bx_unhexdig32[32]={
138
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 
139
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0b, 0x0c,
140
+	0x0d, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
141
+	0xff };
142
+
143
+#endif /*  BASE16_LOOKUP_LARGE */
144
+#endif /* BASE16_LOOKUP_TABLE */
145
+
146
+#ifdef BASE64_LOOKUP_TABLE
147
+
148
+#ifdef BASE64_LOOKUP_LARGE
149
+/* large lookup tables, 2.5 k */
150
+
151
+unsigned char _bx_b64_first[256];
152
+unsigned char _bx_b64_second[4][256];
153
+unsigned char _bx_b64_third[4][256];
154
+unsigned char _bx_b64_fourth[256];
155
+
156
+unsigned char _bx_ub64[256];
157
+
158
+#elif defined BASE64_LOOKUP_8K
159
+unsigned short _bx_b64_12[4096];
160
+unsigned char _bx_ub64[256];
161
+
162
+#else /*  BASE64_LOOKUP_LARGE */
163
+/* very small lookup, 65 bytes */
164
+
165
+unsigned char _bx_b64[64+1]=
166
+		"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
167
+
168
+
169
+unsigned char _bx_ub64[0x54+1]={
170
+		                              0x3e, 0xff, 0xff, 0xff, 0x3f,
171
+		0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d,
172
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02,
173
+		0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
174
+		0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
175
+		0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1a,
176
+		0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
177
+		0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e,
178
+		0x2f, 0x30, 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff };
179
+
180
+#endif /*  BASE64_LOOKUP_LARGE */
181
+
182
+#endif /* BASE64_LOOKUP_TABLE */
183
+
184
+#define b64_enc_char(c) base64_enc_char(c)
185
+#define b64_dec_char(c) base64_dec_char(c)
186
+
187
+int init_basex()
188
+{
189
+#ifdef BASE64_LOOKUP_TABLE
190
+#if defined BASE64_LOOKUP_LARGE || defined BASE64_LOOKUP_8K
191
+	int r;
192
+#endif
193
+#ifdef BASE64_LOOKUP_LARGE
194
+	int i;
195
+	
196
+	/* encode tables */
197
+	for (r=0; r<256; r++)
198
+		_bx_b64_first[r]=b64_enc_char(((unsigned char)r)>>2);
199
+	for(i=0; i<4; i++){
200
+		for (r=0; r<256; r++)
201
+			_bx_b64_second[i][r]=
202
+					b64_enc_char((unsigned char)((i<<4)|(r>>4)));
203
+	}
204
+	for(i=0; i<4; i++){
205
+		for (r=0; r<256; r++)
206
+			_bx_b64_third[i][r]=
207
+				b64_enc_char((unsigned char)(((r<<2)&0x3f)|i));
208
+	}
209
+	for (r=0; r<256; r++)
210
+		_bx_b64_fourth[r]=b64_enc_char(((unsigned char)r&0x3f));
211
+	
212
+	/* decode */
213
+	for (r=0; r<256; r++)
214
+		_bx_ub64[r]=b64_dec_char((unsigned char)r);
215
+#elif defined BASE64_LOOKUP_8K
216
+	for (r=0; r< 4096; r++)
217
+#if defined __IS_LITTLE_ENDIAN
218
+		_bx_b64_12[r]=b64_enc_char(r>>6)|(b64_enc_char(r&0x3f)<<8);
219
+#elif defined __IS_BIG_ENDIAN /* __IS_LITTLE_ENDIAN */
220
+		_bx_b64_12[r]=(b64_enc_char(r>>6)<<8)|b64_enc_char(r&0x3f);
221
+#else /* __IS_LITTLE_ENDIAN */
222
+#error Neither __IS_LITTE_ENDIAN nor __IS_BIG_ENDIAN  defined
223
+#endif
224
+	/* decode */
225
+	for (r=0; r<256; r++)
226
+		_bx_ub64[r]=b64_dec_char((unsigned char)r);
227
+#endif
228
+#endif
229
+	return 0;
230
+}
0 231
new file mode 100644
... ...
@@ -0,0 +1,869 @@
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 */
0 870
new file mode 100644
... ...
@@ -0,0 +1,401 @@
1
+/*
2
+ * $Id$
3
+ *
4
+ * Tests for basex.h
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
+
22
+/*#define NO_BASE64_LOOKUP_TABLE
23
+ #define SINGLE_REG */
24
+
25
+#include "../basex.h"
26
+#include "profile.h"
27
+
28
+#include <stdio.h>
29
+#include <stdlib.h>
30
+#include <unistd.h>
31
+#include <sys/types.h>
32
+#include <sys/stat.h>
33
+#include <fcntl.h>
34
+#include <errno.h>
35
+#include <string.h>
36
+#include <time.h>
37
+#include <ctype.h>
38
+
39
+
40
+#ifndef MIN
41
+#define MIN(a,b) (((a)<(b))?(a):(b))
42
+#endif
43
+
44
+#define BASE64 64
45
+#define Q_BASE64 640
46
+#define BASE16 16
47
+
48
+#ifndef BASEX
49
+#define BASEX BASE16
50
+#endif
51
+
52
+#if BASEX == Q_BASE64
53
+
54
+#warning Q_BASE64
55
+#define B_ENC	q_base64_enc
56
+#define B_DEC	q_base64_dec
57
+#define B_ENC_LEN(l)	(((l)+2)/3*4)
58
+
59
+#elif BASEX == BASE16
60
+
61
+#warning BASE16
62
+#define B_ENC	base16_enc
63
+#define B_DEC	base16_dec
64
+#define B_ENC_LEN(l)	((l)*2)
65
+
66
+#else
67
+
68
+#warning BASE64
69
+#define B_ENC	base64_enc
70
+#define B_DEC	base64_dec
71
+#define B_ENC_LEN(l)	(((l)+2)/3*4)
72
+
73
+
74
+#endif
75
+
76
+
77
+#define QUOTE_MACRO(x) QUOTEME(x)
78
+#define QUOTEME(x) #x
79
+
80
+static char* id="$Id$";
81
+static char* version="basex test 0.1 " 
82
+"BASE" QUOTE_MACRO(BASEX)  ": " QUOTE_MACRO(B_ENC) ", " QUOTE_MACRO(B_DEC) ""
83
+#if defined BASE64_LOOKUP_TABLE 
84
+#ifdef BASE64_LOOKUP_LARGE
85
+" (large b64 lookup table)"
86
+#else
87
+" (lookup b64 table)"
88
+#endif
89
+#else
90
+" (no b64 lookup table)"
91
+#endif
92
+#if defined BASE16_LOOKUP_TABLE
93
+#ifdef BASE16_LOOKUP_LARGE
94
+" (large b16 lookup table)"
95
+#else
96
+" (lookup b16 table)"
97
+#endif
98
+#else
99
+" (no b16 lookup table)"
100
+#endif
101
+#if defined BASE64_READ_WHOLE_INTS || defined BASE16_READ_WHOLE_INTS
102
+" (read 4 bytes at a time)"
103
+#else
104
+" (read 1 byte at a time)"
105
+#endif
106
+;
107
+
108
+static char* help_msg="\
109
+Usage: basex  [-hv] ... [options]\n\
110
+Options:\n\
111
+    -m min        minimum length\n\
112
+    -M max        maximum length\n\
113
+    -o offset     offset from the start of the buffer (alignment tests)\n\
114
+    -e offset     offset from the start of the dst. buf. (alignment tests)\n\
115
+    -n no.        number of test loops\n\
116
+    -v            increase verbosity\n\
117
+    -V            version number\n\
118
+    -h            this help message\n\
119
+";
120
+
121
+
122
+/* profiling */
123
+struct profile_data pf1, pf2, pf3, pf4, pf5, pf6;
124
+
125
+
126
+void dump_profile_info(struct profile_data* pd)
127
+{
128
+	printf("profiling for %s (%ld/%ld):  %lld/%lld/%lld (max/avg/last),"
129
+			" total %lld\n",
130
+			pd->name, pd->entries, pd->exits, pd->max_cycles, 
131
+			pd->entries?pd->total_cycles/pd->entries:0, pd->cycles,
132
+			pd->total_cycles);
133
+}
134
+
135
+
136
+
137
+int seed_prng()
138
+{
139
+	int seed, rfd;
140
+	
141
+	if ((rfd=open("/dev/urandom", O_RDONLY))!=-1){
142
+try_again:
143
+		if (read(rfd, (void*)&seed, sizeof(seed))==-1){
144
+			if (errno==EINTR) goto try_again; /* interrupted by signal */
145
+				fprintf(stderr, "WARNING: could not read from /dev/urandom: "
146
+								" %s (%d)\n", strerror(errno), errno);
147
+		}
148
+		close(rfd);
149
+	}else{
150
+		fprintf(stderr, "WARNING: could not open /dev/urandom: %s (%d)\n",
151
+						strerror(errno), errno);
152
+	}
153
+	seed+=getpid()+time(0);
154
+	srand(seed);
155
+	return 0;
156
+}
157
+
158
+
159
+/* fill buf with random data*/
160
+void fill_rand(unsigned char* buf, int len)
161
+{
162
+	unsigned char* end;
163
+	int v;
164
+
165
+/* find out how many random bytes we can get from rand() */
166
+#if RAND_MAX >= 0xffffffff
167
+#define RAND_BYTES 4
168
+#warning RAND_BYTES is 4
169
+#elif RAND_MAX >= 0xffffff
170
+#define RAND_BYTES 3
171
+#warning RAND_BYTES is 3
172
+#elif RAND_MAX >= 0xffff
173
+#define RAND_BYTES 2
174
+#warning RAND_BYTES is 2
175
+#else
176
+#define RAND_BYTES 1
177
+#endif
178
+
179
+	end=buf+len/RAND_BYTES*RAND_BYTES;
180
+	for(;buf<end;buf+=RAND_BYTES){
181
+		v=rand();
182
+		buf[0]=v;
183
+#if RAND_BYTES > 1
184
+		buf[1]=v>>8;
185
+#endif
186
+#if RAND_BYTES > 2
187
+		buf[2]=v>>16;
188
+#endif
189
+#if RAND_BYTES > 4
190
+		buf[3]=v>>24;
191
+#endif
192
+	}
193
+	v=rand();
194
+	switch(end-buf){
195
+		case 3:
196
+#if RAND_BYTES > 2
197
+			buf[2]=v>>16;
198
+#else
199
+			buf[2]=rand();
200
+#endif
201
+		case 2:
202
+#if RAND_BYTES > 1
203
+			buf[1]=v>>8;
204
+#else
205
+			buf[1]=rand();
206
+#endif
207
+		case 1:
208
+			buf[0]=v;
209
+		case 0:
210
+			break;
211
+	}
212
+}
213
+
214
+
215
+
216
+int main(int argc, char** argv)
217
+{
218
+
219
+	int loops, min_len, max_len, offset, e_offset;
220
+	unsigned char* ibuf;
221
+	unsigned char* enc_buf;
222
+	unsigned char* dec_buf;
223
+	int ibuf_len, enc_buf_len, dec_buf_len;
224
+	int offs, c_len, e_len, l;
225
+	int r;
226
+	int verbose;
227
+	int c;
228
+	char* tmp;
229
+
230
+	verbose=0;
231
+	min_len=max_len=offset=-1;
232
+	e_offset=0;
233
+	loops=1024;
234
+	opterr=0;
235
+	while ((c=getopt(argc, argv, "n:m:M:o:e:vhV"))!=-1){
236
+		switch(c){
237
+			case 'n':
238
+				loops=strtol(optarg, &tmp, 0);
239
+				if ((tmp==0)||(*tmp)||(loops<0)){
240
+					fprintf(stderr, "bad number: -%c %s\n", c, optarg);
241
+					goto error;
242
+				}
243
+				break;
244
+			case 'm':
245
+				min_len=strtol(optarg, &tmp, 0);
246
+				if ((tmp==0)||(*tmp)||(min_len<0)){
247
+					fprintf(stderr, "bad number: -%c %s\n", c, optarg);
248
+					goto error;
249
+				}
250
+				break;
251
+			case 'M':
252
+				max_len=strtol(optarg, &tmp, 0);
253
+				if ((tmp==0)||(*tmp)||(max_len<0)){
254
+					fprintf(stderr, "bad number: -%c %s\n", c, optarg);
255
+					goto error;
256
+				}
257
+				break;
258
+			case 'o':
259
+				offset=strtol(optarg, &tmp, 0);
260
+				if ((tmp==0)||(*tmp)||(offset<0)){
261
+					fprintf(stderr, "bad number: -%c %s\n", c, optarg);
262
+					goto error;
263
+				}
264
+				break;
265
+			case 'e':
266
+				e_offset=strtol(optarg, &tmp, 0);
267
+				if ((tmp==0)||(*tmp)||(e_offset<0)){
268
+					fprintf(stderr, "bad number: -%c %s\n", c, optarg);
269
+					goto error;
270
+				}
271
+				break;
272
+			case 'v':
273
+				verbose++;
274
+				break;
275
+			case 'V':
276
+				printf("version: %s\n", version);
277
+				printf("%s\n", id);
278
+				exit(0);
279
+				break;
280
+			case 'h':
281
+				printf("version: %s\n", version);
282
+				printf("%s", help_msg);
283
+				exit(0);
284
+				break;
285
+			case '?':
286
+				if (isprint(optopt))
287
+					fprintf(stderr, "Unknown option `-%c\n", optopt);
288
+				else
289
+					fprintf(stderr, "Unknown character `\\x%x\n", optopt);
290
+				goto error;
291
+			case ':':
292
+				fprintf(stderr, "Option `-%c requires an argument.\n",
293
+						optopt);
294
+				goto error;
295
+				break;
296
+			default:
297
+				abort();
298
+		}
299
+	}
300
+	if (min_len==-1 && max_len==-1){
301
+		min_len=0;
302
+		max_len=4*1024*1024;
303
+	}else if (min_len==-1)
304
+		min_len=0;
305
+	else if (max_len==-1)