////////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2008 The Regents of the University of California
//
// This file is part of Qbox
//
// Qbox is distributed under the terms of the GNU General Public License
// as published by the Free Software Foundation, either version 2 of
// the License, or (at your option) any later version.
// See the file COPYING in the root directory of this distribution
// or .
//
////////////////////////////////////////////////////////////////////////////////
//
// Base64Transcoder.C
//
////////////////////////////////////////////////////////////////////////////////
#include "Base64Transcoder.h"
#include
#include
#include
#include // memcpy
#include
using namespace std;
////////////////////////////////////////////////////////////////////////////////
Base64Transcoder::Base64Transcoder()
{
// initialize encoding/decoding tables
for (int i = 0; i < 26; i++)
{
etable[i] = 'A' + i;
etable[26 + i] = 'a' + i;
}
for (int i = 0; i < 10; i++)
{
etable[52 + i] = '0' + i;
}
etable[62] = '+';
etable[63] = '/';
for (int i = 0; i < 255; i++)
{
dtable[i] = 0x80;
}
for (int i = 'A'; i <= 'Z'; i++)
{
dtable[i] = 0 + (i - 'A');
}
for (int i = 'a'; i <= 'z'; i++)
{
dtable[i] = 26 + (i - 'a');
}
for (int i = '0'; i <= '9'; i++)
{
dtable[i] = 52 + (i - '0');
}
dtable['+'] = 62;
dtable['/'] = 63;
dtable['='] = 0;
}
////////////////////////////////////////////////////////////////////////////////
int Base64Transcoder::encode(int nbytes, const byte* const from, char* const to)
{
const byte* fptr = from;
char* tptr = to;
int n3 = nbytes / 3; // number of groups of three bytes
while ( n3-- > 0 )
{
byte ig0 = *fptr++;
byte ig1 = *fptr++;
byte ig2 = *fptr++;
*tptr++ = etable[ig0 >> 2];
*tptr++ = etable[((ig0 & 3) << 4) | (ig1 >> 4)];
*tptr++ = etable[((ig1 & 0xF) << 2) | (ig2 >> 6)];
*tptr++ = etable[ig2 & 0x3F];
}
int nr = nbytes % 3; // remaining bytes
if ( nr == 2 )
{
byte ig0 = *fptr++;
byte ig1 = *fptr++;
byte ig2 = 0;
*tptr++ = etable[ig0 >> 2];
*tptr++ = etable[((ig0 & 3) << 4) | (ig1 >> 4)];
*tptr++ = etable[((ig1 & 0xF) << 2) | (ig2 >> 6)];
*tptr++ = '=';
}
else if ( nr == 1 )
{
byte ig0 = *fptr++;
byte ig1 = 0;
*tptr++ = etable[ig0 >> 2];
*tptr++ = etable[((ig0 & 3) << 4) | (ig1 >> 4)];
*tptr++ = '=';
*tptr++ = '=';
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
int Base64Transcoder::decode(const int nchars, const char* const from,
byte* const to)
{
// Decode Base64 chars in array "from" into bytes in array "to"
// White space and new lines are skipped
// extra characters at end that do not form a valid group of 4 chars are
// ignored.
// nchars: number of chars in array "from"
// the number of bytes successfully translated is returned
byte a2,a3,b0,b1,b2,b3;
int c;
const char* fptr = from;
const char* const fptr_end = from+nchars+1;
byte* tptr = to;
while ( fptr < fptr_end-4 )
{
// get 4 valid characters from input string
do
{
c = *fptr++;
}
while ( (c <= ' ') && (fptr < fptr_end) );
if ( fptr >= fptr_end )
{
#ifdef DEBUG
cerr << " Base64Transcoder::decode: end of string reached reading c0 "
<< endl;
#endif
break;
}
// a0 = (byte) c;
b0 = (byte) dtable[c];
do
{
c = *fptr++;
}
while ( (c <= ' ') && (fptr < fptr_end) );
if ( fptr >= fptr_end )
{
#ifdef DEBUG
cerr << " Base64Transcoder::decode: end of string reached reading c1 "
<< endl;
#endif
break;
}
// a1 = (byte) c;
b1 = (byte) dtable[c];
do
{
c = *fptr++;
}
while ( (c <= ' ') && (fptr < fptr_end) );
if ( fptr >= fptr_end )
{
#ifdef DEBUG
cerr << " Base64Transcoder::decode: end of string reached reading c2 "
<< endl;
#endif
break;
}
a2 = (byte) c;
b2 = (byte) dtable[c];
do
{
c = *fptr++;
}
while ( (c <= ' ') && (fptr < fptr_end) );
if ( (c <= ' ') && fptr >= fptr_end )
{
#ifdef DEBUG
cerr << " Base64Transcoder::decode: end of string reached reading c3\n"
<< " (without reading a valid c3) " << endl;
#endif
break;
}
a3 = (byte) c;
b3 = (byte) dtable[c];
if ((b0|b1|b2|b3) & 0x80)
{
#ifdef DEBUG
cerr << " Base64Transcoder::decode: Illegal character in input: "
<< endl;
#endif
return tptr - to;
}
if ( a3 == '=' )
{
if ( a2 == '=' )
{
// write 1 byte only
*tptr++ = (b0 << 2) | (b1 >> 4);
}
else
{
// write 2 bytes only
*tptr++ = (b0 << 2) | (b1 >> 4);
*tptr++ = (b1 << 4) | (b2 >> 2);
}
}
else
{
// write 3 bytes
*tptr++ = (b0 << 2) | (b1 >> 4);
*tptr++ = (b1 << 4) | (b2 >> 2);
*tptr++ = (b2 << 6) | b3;
}
}
#ifdef DEBUG
if ( fptr >= fptr_end )
{
cerr << " Base64Transcoder::decode: end of string reached in input: "
<< endl;
}
#endif
return tptr - to;
}
////////////////////////////////////////////////////////////////////////////////
void Base64Transcoder::byteswap_double(size_t n, double* const x)
{
if (n==0) return;
unsigned char* c = (unsigned char*) x;
while ( n-- > 0 )
{
unsigned char tmp;
tmp = c[7]; c[7] = c[0]; c[0] = tmp;
tmp = c[6]; c[6] = c[1]; c[1] = tmp;
tmp = c[5]; c[5] = c[2]; c[2] = tmp;
tmp = c[4]; c[4] = c[3]; c[3] = tmp;
c+=8;
}
}
////////////////////////////////////////////////////////////////////////////////
void Base64Transcoder::byteswap_int(size_t n, int* const x)
{
if (n==0) return;
unsigned char* c = (unsigned char*) x;
while ( n-- > 0 )
{
unsigned char tmp;
tmp = c[3]; c[3] = c[0]; c[0] = tmp;
tmp = c[2]; c[2] = c[1]; c[1] = tmp;
c+=4;
}
}
////////////////////////////////////////////////////////////////////////////////
int Base64Transcoder::print(const string buf, ostream& o)
{
return print(buf.size(),buf.c_str(),o);
}
////////////////////////////////////////////////////////////////////////////////
int Base64Transcoder::print(int nchars, const char* const buf, ostream& o)
{
const char* b = buf;
int nl = nchars / 72;
// compute total size of output string including newline chars
int outstr_size = nchars + nl;
if ( nchars%72 != 0 )
outstr_size++;
char* outstr = new char[outstr_size];
char* p = outstr;
// assemble output string
for ( int i = 0; i < nl; i++ )
{
memcpy(p,b,72*sizeof(char));
p[72] = '\n';
b += 72;
p += 73;
}
if ( nchars%72 != 0 )
{
int size = nchars%72;
memcpy(p,b,size*sizeof(char));
p[size] = '\n';
}
o.write(outstr,outstr_size);
delete [] outstr;
return 0;
}
////////////////////////////////////////////////////////////////////////////////
int Base64Transcoder::print(const string buf, FILE* outfile)
{
return print(buf.size(),buf.c_str(),outfile);
}
////////////////////////////////////////////////////////////////////////////////
int Base64Transcoder::print(int nchars, const char* const buf, FILE* outfile)
{
const char* b = buf;
int nl = nchars / 72;
// compute total size of output string including newline chars
int outstr_size = nchars + nl;
if ( nchars%72 != 0 )
outstr_size++;
char* outstr = new char[outstr_size];
char* p = outstr;
// assemble output string
for ( int i = 0; i < nl; i++ )
{
memcpy(p,b,72*sizeof(char));
p[72] = '\n';
b += 72;
p += 73;
}
if ( nchars%72 != 0 )
{
int size = nchars%72;
memcpy(p,b,size*sizeof(char));
p[size] = '\n';
}
fwrite(outstr,sizeof(char),outstr_size,outfile);
delete [] outstr;
return 0;
}