1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2008 The Regents of the University of California
4 //
5 // This file is part of Qbox
6 //
7 // Qbox is distributed under the terms of the GNU General Public License
8 // as published by the Free Software Foundation, either version 2 of
9 // the License, or (at your option) any later version.
10 // See the file COPYING in the root directory of this distribution
11 // or <http://www.gnu.org/licenses/>.
12 //
13 ////////////////////////////////////////////////////////////////////////////////
14 //
15 // Base64Transcoder.cpp
16 //
17 ////////////////////////////////////////////////////////////////////////////////
18
19 #include "Base64Transcoder.h"
20 #include <iostream>
21 #include <cstdio>
22 #include <string>
23 #include <cstring> // memcpy
24 #include <cassert>
25 using namespace std;
26
27 ////////////////////////////////////////////////////////////////////////////////
Base64Transcoder()28 Base64Transcoder::Base64Transcoder()
29 {
30 // initialize encoding/decoding tables
31
32 for (int i = 0; i < 26; i++)
33 {
34 etable[i] = 'A' + i;
35 etable[26 + i] = 'a' + i;
36 }
37 for (int i = 0; i < 10; i++)
38 {
39 etable[52 + i] = '0' + i;
40 }
41 etable[62] = '+';
42 etable[63] = '/';
43
44 for (int i = 0; i < 255; i++)
45 {
46 dtable[i] = 0x80;
47 }
48 for (int i = 'A'; i <= 'Z'; i++)
49 {
50 dtable[i] = 0 + (i - 'A');
51 }
52 for (int i = 'a'; i <= 'z'; i++)
53 {
54 dtable[i] = 26 + (i - 'a');
55 }
56 for (int i = '0'; i <= '9'; i++)
57 {
58 dtable[i] = 52 + (i - '0');
59 }
60 dtable['+'] = 62;
61 dtable['/'] = 63;
62 dtable['='] = 0;
63 }
64
65 ////////////////////////////////////////////////////////////////////////////////
encode(int nbytes,const byte * const from,char * const to)66 int Base64Transcoder::encode(int nbytes, const byte* const from, char* const to)
67 {
68 const byte* fptr = from;
69 char* tptr = to;
70
71 int n3 = nbytes / 3; // number of groups of three bytes
72
73 while ( n3-- > 0 )
74 {
75 byte ig0 = *fptr++;
76 byte ig1 = *fptr++;
77 byte ig2 = *fptr++;
78
79 *tptr++ = etable[ig0 >> 2];
80 *tptr++ = etable[((ig0 & 3) << 4) | (ig1 >> 4)];
81 *tptr++ = etable[((ig1 & 0xF) << 2) | (ig2 >> 6)];
82 *tptr++ = etable[ig2 & 0x3F];
83 }
84
85 int nr = nbytes % 3; // remaining bytes
86
87 if ( nr == 2 )
88 {
89 byte ig0 = *fptr++;
90 byte ig1 = *fptr++;
91 byte ig2 = 0;
92
93 *tptr++ = etable[ig0 >> 2];
94 *tptr++ = etable[((ig0 & 3) << 4) | (ig1 >> 4)];
95 *tptr++ = etable[((ig1 & 0xF) << 2) | (ig2 >> 6)];
96 *tptr++ = '=';
97 }
98 else if ( nr == 1 )
99 {
100 byte ig0 = *fptr++;
101 byte ig1 = 0;
102
103 *tptr++ = etable[ig0 >> 2];
104 *tptr++ = etable[((ig0 & 3) << 4) | (ig1 >> 4)];
105 *tptr++ = '=';
106 *tptr++ = '=';
107 }
108
109 return 0;
110 }
111
112 ////////////////////////////////////////////////////////////////////////////////
decode(const int nchars,const char * const from,byte * const to)113 int Base64Transcoder::decode(const int nchars, const char* const from,
114 byte* const to)
115 {
116 // Decode Base64 chars in array "from" into bytes in array "to"
117 // White space and new lines are skipped
118 // extra characters at end that do not form a valid group of 4 chars are
119 // ignored.
120 // nchars: number of chars in array "from"
121 // the number of bytes successfully translated is returned
122
123 byte a2,a3,b0,b1,b2,b3;
124 int c;
125 const char* fptr = from;
126 const char* const fptr_end = from+nchars+1;
127 byte* tptr = to;
128
129 while ( fptr < fptr_end-4 )
130 {
131 // get 4 valid characters from input string
132 do
133 {
134 c = *fptr++;
135 }
136 while ( (c <= ' ') && (fptr < fptr_end) );
137 if ( fptr >= fptr_end )
138 {
139 #ifdef DEBUG
140 cerr << " Base64Transcoder::decode: end of string reached reading c0 "
141 << endl;
142 #endif
143 break;
144 }
145 // a0 = (byte) c;
146 b0 = (byte) dtable[c];
147
148 do
149 {
150 c = *fptr++;
151 }
152 while ( (c <= ' ') && (fptr < fptr_end) );
153 if ( fptr >= fptr_end )
154 {
155 #ifdef DEBUG
156 cerr << " Base64Transcoder::decode: end of string reached reading c1 "
157 << endl;
158 #endif
159 break;
160 }
161 // a1 = (byte) c;
162 b1 = (byte) dtable[c];
163
164 do
165 {
166 c = *fptr++;
167 }
168 while ( (c <= ' ') && (fptr < fptr_end) );
169 if ( fptr >= fptr_end )
170 {
171 #ifdef DEBUG
172 cerr << " Base64Transcoder::decode: end of string reached reading c2 "
173 << endl;
174 #endif
175 break;
176 }
177 a2 = (byte) c;
178 b2 = (byte) dtable[c];
179
180 do
181 {
182 c = *fptr++;
183 }
184 while ( (c <= ' ') && (fptr < fptr_end) );
185 if ( (c <= ' ') && fptr >= fptr_end )
186 {
187 #ifdef DEBUG
188 cerr << " Base64Transcoder::decode: end of string reached reading c3\n"
189 << " (without reading a valid c3) " << endl;
190 #endif
191 break;
192 }
193 a3 = (byte) c;
194 b3 = (byte) dtable[c];
195
196 if ((b0|b1|b2|b3) & 0x80)
197 {
198 #ifdef DEBUG
199 cerr << " Base64Transcoder::decode: Illegal character in input: "
200 << endl;
201 #endif
202 return tptr - to;
203 }
204
205 if ( a3 == '=' )
206 {
207 if ( a2 == '=' )
208 {
209 // write 1 byte only
210 *tptr++ = (b0 << 2) | (b1 >> 4);
211 }
212 else
213 {
214 // write 2 bytes only
215 *tptr++ = (b0 << 2) | (b1 >> 4);
216 *tptr++ = (b1 << 4) | (b2 >> 2);
217 }
218 }
219 else
220 {
221 // write 3 bytes
222 *tptr++ = (b0 << 2) | (b1 >> 4);
223 *tptr++ = (b1 << 4) | (b2 >> 2);
224 *tptr++ = (b2 << 6) | b3;
225 }
226
227 }
228 #ifdef DEBUG
229 if ( fptr >= fptr_end )
230 {
231 cerr << " Base64Transcoder::decode: end of string reached in input: "
232 << endl;
233 }
234 #endif
235
236 return tptr - to;
237 }
238
239 ////////////////////////////////////////////////////////////////////////////////
byteswap_double(size_t n,double * const x)240 void Base64Transcoder::byteswap_double(size_t n, double* const x)
241 {
242 if (n==0) return;
243 unsigned char* c = (unsigned char*) x;
244 while ( n-- > 0 )
245 {
246 unsigned char tmp;
247 tmp = c[7]; c[7] = c[0]; c[0] = tmp;
248 tmp = c[6]; c[6] = c[1]; c[1] = tmp;
249 tmp = c[5]; c[5] = c[2]; c[2] = tmp;
250 tmp = c[4]; c[4] = c[3]; c[3] = tmp;
251
252 c+=8;
253 }
254 }
255
256 ////////////////////////////////////////////////////////////////////////////////
byteswap_int(size_t n,int * const x)257 void Base64Transcoder::byteswap_int(size_t n, int* const x)
258 {
259 if (n==0) return;
260 unsigned char* c = (unsigned char*) x;
261 while ( n-- > 0 )
262 {
263 unsigned char tmp;
264 tmp = c[3]; c[3] = c[0]; c[0] = tmp;
265 tmp = c[2]; c[2] = c[1]; c[1] = tmp;
266
267 c+=4;
268 }
269 }
270
271 ////////////////////////////////////////////////////////////////////////////////
print(const string buf,ostream & o)272 int Base64Transcoder::print(const string buf, ostream& o)
273 {
274 return print(buf.size(),buf.c_str(),o);
275 }
276
277 ////////////////////////////////////////////////////////////////////////////////
print(int nchars,const char * const buf,ostream & o)278 int Base64Transcoder::print(int nchars, const char* const buf, ostream& o)
279 {
280 const char* b = buf;
281 int nl = nchars / 72;
282
283 // compute total size of output string including newline chars
284 int outstr_size = nchars + nl;
285 if ( nchars%72 != 0 )
286 outstr_size++;
287 char* outstr = new char[outstr_size];
288 char* p = outstr;
289
290 // assemble output string
291 for ( int i = 0; i < nl; i++ )
292 {
293 memcpy(p,b,72*sizeof(char));
294 p[72] = '\n';
295 b += 72;
296 p += 73;
297 }
298
299 if ( nchars%72 != 0 )
300 {
301 int size = nchars%72;
302 memcpy(p,b,size*sizeof(char));
303 p[size] = '\n';
304 }
305
306 o.write(outstr,outstr_size);
307 delete [] outstr;
308 return 0;
309 }
310
311 ////////////////////////////////////////////////////////////////////////////////
print(const string buf,FILE * outfile)312 int Base64Transcoder::print(const string buf, FILE* outfile)
313 {
314 return print(buf.size(),buf.c_str(),outfile);
315 }
316
317 ////////////////////////////////////////////////////////////////////////////////
print(int nchars,const char * const buf,FILE * outfile)318 int Base64Transcoder::print(int nchars, const char* const buf, FILE* outfile)
319 {
320 const char* b = buf;
321 int nl = nchars / 72;
322
323 // compute total size of output string including newline chars
324 int outstr_size = nchars + nl;
325 if ( nchars%72 != 0 )
326 outstr_size++;
327 char* outstr = new char[outstr_size];
328 char* p = outstr;
329
330 // assemble output string
331 for ( int i = 0; i < nl; i++ )
332 {
333 memcpy(p,b,72*sizeof(char));
334 p[72] = '\n';
335 b += 72;
336 p += 73;
337 }
338
339 if ( nchars%72 != 0 )
340 {
341 int size = nchars%72;
342 memcpy(p,b,size*sizeof(char));
343 p[size] = '\n';
344 }
345
346 fwrite(outstr,sizeof(char),outstr_size,outfile);
347 delete [] outstr;
348 return 0;
349 }
350