base64.cc

00001 /*
00002  * Encode or decode file as MIME base64 (RFC 1341)
00003  * Public domain by John Walker, August 11 1997
00004  *           http://www.fourmilab.ch/
00005  * Modified slightly for the Citadel/UX system, June 1999
00006  *
00007  * Taken from the Citadel/UX GPL source tree, at version 6.01
00008  * Modified into a C++ API by Chris Frey for Net Direct Inc., November 2005
00009  *           http://www.netdirect.ca/
00010  *
00011  */
00012 
00013 #include "base64.h"
00014 #include <string>
00015 #include <iterator>
00016 
00017 #define TRUE  1
00018 #define FALSE 0
00019 
00020 #define LINELEN 72                    /* Encoded line length (max 76) */
00021 
00022 typedef unsigned char byte;           /* Byte type */
00023 
00024 static byte dtable[256];              /* Encode / decode table */
00025 //static char eol[] = "\r\n";           /* End of line sequence */
00026 static int errcheck = TRUE;           /* Check decode input for errors ? */
00027 
00028 
00029 /*  INCHAR  --  Return next character from input  */
00030 
00031 class base64_input
00032 {
00033         std::string::const_iterator begin, end;
00034 public:
00035         base64_input(const std::string &input)
00036                 : begin(input.begin()), end(input.end()) {}
00037         
00038         int operator()()
00039         {
00040                 if (begin == end) {
00041                         return EOF;
00042                 }
00043                 return *begin++;
00044         }
00045 };
00046 
00047 
00048 /*  OCHAR  --  Output an encoded character, inserting line breaks
00049                where required.  */
00050 
00051 class base64_output
00052 {
00053         std::back_insert_iterator<std::string> insert;
00054         int linelength;                 /* Length of encoded output line */
00055 
00056 public:
00057         base64_output(std::string &output)
00058                 : insert(back_inserter(output)),
00059                 linelength(0)
00060         {}
00061 
00062         void operator()(int c)
00063         {
00064                 if (linelength >= LINELEN) {
00065                         *insert++ = '\n';
00066                         *insert++ = ' ';
00067                         linelength = 0;
00068                 }
00069                 *insert++ = (unsigned char) c;
00070                 linelength++;
00071         }
00072 };
00073 
00074 /*  ENCODE  --  Encode binary file into base64.  */
00075 
00076 static bool encode(base64_input &inchar, base64_output &ochar)
00077 {
00078     int i, hiteof = FALSE;
00079 
00080     /*  Fill dtable with character encodings.  */
00081 
00082     for (i = 0; i < 26; i++) {
00083         dtable[i] = 'A' + i;
00084         dtable[26 + i] = 'a' + i;
00085     }
00086     for (i = 0; i < 10; i++) {
00087         dtable[52 + i] = '0' + i;
00088     }
00089     dtable[62] = '+';
00090     dtable[63] = '/';
00091 
00092     while (!hiteof) {
00093         byte igroup[3], ogroup[4];
00094         int c, n;
00095 
00096         igroup[0] = igroup[1] = igroup[2] = 0;
00097         for (n = 0; n < 3; n++) {
00098             c = inchar();
00099             if (c == EOF) {
00100                 hiteof = TRUE;
00101                 break;
00102             }
00103             igroup[n] = (byte) c;
00104         }
00105         if (n > 0) {
00106             ogroup[0] = dtable[igroup[0] >> 2];
00107             ogroup[1] = dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
00108             ogroup[2] = dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
00109             ogroup[3] = dtable[igroup[2] & 0x3F];
00110 
00111             /* Replace characters in output stream with "=" pad
00112                characters if fewer than three characters were
00113                read from the end of the input stream. */
00114 
00115             if (n < 3) {
00116                 ogroup[3] = '=';
00117                 if (n < 2) {
00118                     ogroup[2] = '=';
00119                 }
00120             }
00121             for (i = 0; i < 4; i++) {
00122                 ochar(ogroup[i]);
00123             }
00124         }
00125     }
00126     return true;
00127 }
00128 
00129 /*  INSIG  --  Return next significant input  */
00130 
00131 static int insig(base64_input &inchar)
00132 {
00133     int c;
00134 
00135     /*CONSTANTCONDITION*/
00136     while (TRUE) {
00137         c = inchar();
00138         if (c == EOF || (c > ' ')) {
00139             return c;
00140         }
00141     }
00142     /*NOTREACHED*/
00143 }
00144 
00145 /*  DECODE  --  Decode base64.  */
00146 
00147 static bool decode(base64_input &inchar, base64_output &ochar)
00148 {
00149     int i;
00150 
00151     for (i = 0; i < 255; i++) {
00152         dtable[i] = 0x80;
00153     }
00154     for (i = 'A'; i <= 'Z'; i++) {
00155         dtable[i] = 0 + (i - 'A');
00156     }
00157     for (i = 'a'; i <= 'z'; i++) {
00158         dtable[i] = 26 + (i - 'a');
00159     }
00160     for (i = '0'; i <= '9'; i++) {
00161         dtable[i] = 52 + (i - '0');
00162     }
00163     dtable[(int)'+'] = 62;
00164     dtable[(int)'/'] = 63;
00165     dtable[(int)'='] = 0;
00166 
00167     /*CONSTANTCONDITION*/
00168     while (TRUE) {
00169         byte a[4], b[4], o[3];
00170 
00171         for (i = 0; i < 4; i++) {
00172             int c = insig(inchar);
00173 
00174             if (c == EOF) {
00175                 // fprintf(stderr, "Input file incomplete.\n");
00176                 return false;
00177             }
00178             if (dtable[c] & 0x80) {
00179                 if (errcheck) {
00180                     //fprintf(stderr, "Illegal character '%c' in input file.\n", c);
00181                     return false;
00182                 }
00183                 /* Ignoring errors: discard invalid character. */
00184                 i--;
00185                 continue;
00186             }
00187             a[i] = (byte) c;
00188             b[i] = (byte) dtable[c];
00189         }
00190         o[0] = (b[0] << 2) | (b[1] >> 4);
00191         o[1] = (b[1] << 4) | (b[2] >> 2);
00192         o[2] = (b[2] << 6) | b[3];
00193         i = a[2] == '=' ? 1 : (a[3] == '=' ? 2 : 3);
00194         for (int w = 0; w < i; w++ )
00195             ochar(o[w]);
00196         if (i < 3) {
00197             return true;
00198         }
00199     }
00200 }
00201 
00202 // in-memory encode / decode API
00203 bool base64_encode(const std::string &in, std::string &out)
00204 {
00205         out.clear();
00206         base64_input input(in);
00207         base64_output output(out);
00208         return encode(input, output);
00209 }
00210 
00211 bool base64_decode(const std::string &in, std::string &out)
00212 {
00213         out.clear();
00214         base64_input input(in);
00215         base64_output output(out);
00216         return decode(input, output);
00217 }
00218 
00219 
00220 #ifdef __TEST_MODE__
00221 
00222 #include <iostream>
00223 using namespace std;
00224 
00225 /*  Main program  */
00226 
00227 int main()
00228 {
00229         string test = "This is a test.", encoded, decoded;
00230         base64_encode(test, encoded);
00231         base64_decode(encoded, decoded);
00232         if( test != decoded )
00233                 cerr << "Test failed" << endl;
00234         else
00235                 cerr << "Success" << endl;
00236 }
00237 
00238 #endif
00239 

Generated on Mon Jan 12 10:51:12 2009 for Barry by  doxygen 1.5.7.1