00001 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
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> 
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,
00058       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00059       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,
00060       52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,
00061       -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
00062       15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,
00063       -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
00064       41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,
00065       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00066       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00067       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00068       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00069       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00070       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00071       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00072       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
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]; 
00093   unsigned char enc4[4]; 
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           
00110           
00111           
00112           
00113           
00114           
00115           
00116           
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); 
00231                   
00232 
00233   if (i == 2)
00234     {
00235       
00236       
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       
00246       
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