base64.cc

Go to the documentation of this file.
00001 
00003 
00004 //
00005 // Copyright (c) 2004-2007 University of Southern California
00006 // Rob Peters <rjpeters at usc dot edu>
00007 //
00008 // created: Fri Oct  8 13:44:09 2004
00009 // commit: $Id: base64.cc 10065 2007-04-12 05:54:56Z rjpeters $
00010 // $HeadURL: file:///lab/rjpeters/svnrepo/code/trunk/groovx/src/rutz/base64.cc $
00011 //
00012 // --------------------------------------------------------------------
00013 //
00014 // This file is part of GroovX.
00015 //   [http://ilab.usc.edu/rjpeters/groovx/]
00016 //
00017 // GroovX is free software; you can redistribute it and/or modify it
00018 // under the terms of the GNU General Public License as published by
00019 // the Free Software Foundation; either version 2 of the License, or
00020 // (at your option) any later version.
00021 //
00022 // GroovX is distributed in the hope that it will be useful, but
00023 // WITHOUT ANY WARRANTY; without even the implied warranty of
00024 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00025 // General Public License for more details.
00026 //
00027 // You should have received a copy of the GNU General Public License
00028 // along with GroovX; if not, write to the Free Software Foundation,
00029 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00030 //
00032 
00033 #ifndef GROOVX_RUTZ_BASE64_CC_UTC20050626084020_DEFINED
00034 #define GROOVX_RUTZ_BASE64_CC_UTC20050626084020_DEFINED
00035 
00036 #include "base64.h"
00037 
00038 #include "rutz/bytearray.h"
00039 #include "rutz/error.h"
00040 #include "rutz/mappedfile.h"
00041 
00042 #include <cctype> // for isspace()
00043 
00044 #include "rutz/trace.h"
00045 #include "rutz/debug.h"
00046 GVX_DBG_REGISTER
00047 
00048 namespace
00049 {
00050   const char base64_chars[65] =
00051     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
00052     "abcdefghijklmnopqrstuvwxyz"
00053     "0123456789+/";
00054 
00055   const int base64_to_num2[256] =
00056     {
00057       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,//   0.. 15
00058       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,//  16.. 31
00059       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,//  32.. 47
00060       52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,//  48.. 63
00061       -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,//  64.. 79
00062       15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,//  80.. 95
00063       -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,//  96..111
00064       41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,// 112..127
00065       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,// 128..143
00066       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,// 144..159
00067       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,// 160..175
00068       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,// 176..191
00069       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,// 192..207
00070       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,// 208..223
00071       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,// 224..239
00072       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,// 240..255
00073     };
00074 }
00075 
00076 void rutz::base64_encode(const unsigned char* src,
00077                          unsigned int src_len,
00078                          rutz::byte_array& dst,
00079                          unsigned int line_width)
00080 {
00081 GVX_TRACE("rutz::base64_encode");
00082   dst.vec.resize(0);
00083 
00084   if (src_len == 0) return;
00085 
00086   unsigned int reserve_size = ((src_len+2)/3) * 4;
00087   if (line_width > 0)
00088     reserve_size += 2*(src_len/line_width + 2);
00089   dst.vec.reserve(reserve_size);
00090   int i = 0;
00091   unsigned int c = 0;
00092   unsigned char dec3[3]; // three characters of decoded string
00093   unsigned char enc4[4]; // four characters of encoded string
00094 
00095   if (line_width > 0)
00096     {
00097       dst.vec.push_back('\n');
00098       dst.vec.push_back('\t');
00099     }
00100 
00101   const unsigned char* const stop = src + src_len;
00102 
00103   for (const unsigned char* p = src; p < stop; ++p)
00104     {
00105       dec3[i++] = *p;
00106 
00107       if (i == 3)
00108         {
00109           //         123456781234567812345678
00110           // dec3[0] 00000000
00111           // dec3[1]         11111111
00112           // dec3[2]                 22222222
00113           // enc4[0] 000000
00114           // enc4[1]       111111
00115           // enc4[2]             222222
00116           // enc4[3]                   333333
00117 
00118           enc4[0] = (dec3[0] & 0xfc) >> 2;
00119           enc4[1] = ((dec3[0] & 0x03) << 4) + ((dec3[1] & 0xf0) >> 4);
00120           enc4[2] = ((dec3[1] & 0x0f) << 2) + ((dec3[2] & 0xc0) >> 6);
00121           enc4[3] = dec3[2] & 0x3f;
00122 
00123           for (i = 0; i < 4; ++i)
00124             dst.vec.push_back(base64_chars[enc4[i]]);
00125 
00126           i = 0;
00127 
00128           c += 4;
00129 
00130           if (line_width > 0 && c > line_width)
00131             {
00132               c = 0;
00133               dst.vec.push_back('\n');
00134               dst.vec.push_back('\t');
00135             }
00136         }
00137     }
00138 
00139   GVX_ASSERT(i >= 0 && i <= 2);
00140 
00141   if (i == 1)
00142     {
00143       enc4[0] = (dec3[0] & 0xfc) >> 2;
00144       enc4[1] = (dec3[0] & 0x03) << 4;
00145 
00146       dst.vec.push_back(base64_chars[enc4[0]]);
00147       dst.vec.push_back(base64_chars[enc4[1]]);
00148       dst.vec.push_back('=');
00149       dst.vec.push_back('=');
00150     }
00151   else if (i == 2)
00152     {
00153       enc4[0] = (dec3[0] & 0xfc) >> 2;
00154       enc4[1] = ((dec3[0] & 0x03) << 4) + ((dec3[1] & 0xf0) >> 4);
00155       enc4[2] = (dec3[1] & 0x0f) << 2;
00156 
00157       dst.vec.push_back(base64_chars[enc4[0]]);
00158       dst.vec.push_back(base64_chars[enc4[1]]);
00159       dst.vec.push_back(base64_chars[enc4[2]]);
00160       dst.vec.push_back('=');
00161     }
00162 }
00163 
00164 void rutz::base64_encode_string(const char* str,
00165                                 rutz::byte_array& dst,
00166                                 unsigned int line_width)
00167 {
00168   rutz::base64_encode(reinterpret_cast<const unsigned char*>(str),
00169                       strlen(str),
00170                       dst,
00171                       line_width);
00172 }
00173 
00174 void rutz::base64_encode_file(const char* filename,
00175                               rutz::byte_array& dst,
00176                               unsigned int line_width)
00177 {
00178   rutz::mapped_infile m(filename);
00179   rutz::base64_encode(static_cast<const unsigned char*>(m.memory()),
00180                       m.length(),
00181                       dst,
00182                       line_width);
00183 }
00184 
00185 void rutz::base64_decode(const char* src,
00186                          unsigned int in_len,
00187                          rutz::byte_array& dst)
00188 {
00189 GVX_TRACE("rutz::base64_decode");
00190   dst.vec.resize(0);
00191   dst.vec.reserve((in_len / 4) * 3);
00192 
00193   int i = 0;
00194   unsigned char enc4[4];
00195   unsigned char dec3[3];
00196 
00197   const char* const stop = src+in_len;
00198 
00199   for (const char* p = src; p < stop; ++p)
00200     {
00201       int n = base64_to_num2[static_cast<unsigned char>(*p)];
00202       if (n >= 0)
00203         {
00204           enc4[i++] = n;
00205 
00206           if (i == 4)
00207             {
00208               dec3[0] = (enc4[0] << 2) + ((enc4[1] & 0x30) >> 4);
00209               dec3[1] = ((enc4[1] & 0xf) << 4) + ((enc4[2] & 0x3c) >> 2);
00210               dec3[2] = ((enc4[2] & 0x3) << 6) + enc4[3];
00211 
00212               for (i = 0; i < 3; ++i)
00213                 dst.vec.push_back(dec3[i]);
00214 
00215               i = 0;
00216             }
00217         }
00218 
00219       else if (*p == '=')
00220         break;
00221 
00222       else if (isspace(*p))
00223         continue;
00224 
00225       else
00226         throw rutz::error("invalid character within base64 string",
00227                           SRC_POS);
00228     }
00229 
00230   GVX_ASSERT(i != 1); // can't happen; this would be an extra 6 bits
00231                   // encoded, implying zero extra bits decoded
00232 
00233   if (i == 2)
00234     {
00235       // extra 12 bits (2 chars) encoded
00236       // extra 8 bits (1 char) decoded
00237 
00238       dec3[0] = (enc4[0] << 2) + ((enc4[1] & 0x30) >> 4);
00239 
00240       dst.vec.push_back(dec3[0]);
00241     }
00242 
00243   else if (i == 3)
00244     {
00245       // extra 18 bits (3 chars) encoded
00246       // extra 16 bits (2 chars) decoded
00247       dec3[0] = (enc4[0] << 2) + ((enc4[1] & 0x30) >> 4);
00248       dec3[1] = ((enc4[1] & 0xf) << 4) + ((enc4[2] & 0x3c) >> 2);
00249 
00250       dst.vec.push_back(dec3[0]);
00251       dst.vec.push_back(dec3[1]);
00252     }
00253 }
00254 
00255 void rutz::base64_decode(const rutz::byte_array& src,
00256                          rutz::byte_array& dst)
00257 {
00258   base64_decode(reinterpret_cast<const char*>(&src.vec[0]),
00259                 src.vec.size(),
00260                 dst);
00261 }
00262 
00263 static const char __attribute__((used)) vcid_groovx_rutz_base64_cc_utc20050626084020[] = "$Id: base64.cc 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00264 #endif // !GROOVX_RUTZ_BASE64_CC_UTC20050626084020_DEFINED

The software described here is Copyright (c) 1998-2005, Rob Peters.
This page was generated Wed Dec 3 06:49:40 2008 by Doxygen version 1.5.5.