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