Main Page Data Structures File List Data Fields Globals Related Pages

# inet/base64.cpp

Go to the documentation of this file.

    00001 /*  base64.cpp
    00002     Encoding of binary data according to RFC2045 base64 encoding
    00003
    00004     13.08.2001: tk, initial implementation, based on base64.c
    00005                     from the PHP 4.06 source code.
    00006
    00007     Copyright (c)2000 by Thomas Kindler, thomas.kindler@gmx.de
    00008
    00009     This program is free software; you can redistribute it and/or
    00010     modify it under the terms of the GNU General Public License as
    00011     published by the Free Software Foundation; either version 2 of
    00012     the License, or (at your option) any later version. Read the
    00013     full License at http://www.gnu.org/copyleft for more details.
    00014 */
    00015
    00016 // include files ----------
    00017 //
    00018 #include <stdlib.h>
    00019 #include <string.h>
    00020 #include <stdio.h>
    00021 #include <assert.h>
    00022 #include "inet/base64.h"
    00023
    00024 static char base64_table[] =
    00025   { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
    00026     'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
    00027     'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
    00028     'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
    00029     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '\0'
    00030   };
    00031
    00032 static char base64_pad = '=';
    00033
    00051 unsigned char *base64encode(const unsigned char *str,
    00052                             unsigned   length,
    00053                             unsigned  *ret_length)
    00054 {
    00055   const unsigned char *current = str;
    00056   unsigned char *result;
    00057
    00058   result = (unsigned char *)malloc((length+3 - length%3)*4/3 + 1);
    00059   if (!result)
    00060     return NULL;
    00061
    00062   // keep going until we have less than 24 bits
    00063   //
    00064   unsigned i = 0;
    00065
    00066   while (length > 2) {
    00067     result[i++] = base64_table[current[0] >> 2];
    00068     result[i++] = base64_table[((current[0] & 0x03) << 4) + (current[1] >> 4)];
    00069     result[i++] = base64_table[((current[1] & 0x0f) << 2) + (current[2] >> 6)];
    00070     result[i++] = base64_table[current[2] & 0x3f];
    00071
    00072     current += 3;
    00073     length  -= 3;   // we just handle 3 octets of data
    00074   }
    00075
    00076   // now deal with the tail end of things
    00077   //
    00078   if (length != 0) {
    00079     result[i++] = base64_table[current[0] >> 2];
    00080     if (length > 1) {
    00081       result[i++] = base64_table[((current[0] & 0x03) << 4) + (current[1] >> 4)];
    00082       result[i++] = base64_table[(current[1] & 0x0f) << 2];
    00083       result[i++] = base64_pad;
    00084     }
    00085     else {
    00086       result[i++] = base64_table[(current[0] & 0x03) << 4];
    00087       result[i++] = base64_pad;
    00088       result[i++] = base64_pad;
    00089     }
    00090   }
    00091   if(ret_length)
    00092     *ret_length = i;
    00093
    00094   result[i]='\0';
    00095   return result;
    00096 }
    00097
    00098
    00116 unsigned char *base64decode( const unsigned char *str,
    00117                              unsigned  length,
    00118                              unsigned *ret_length)
    00119 {
    00120   static int  reverse_table[256];
    00121   static bool table_built = false;
    00122
    00123   if (!table_built) {
    00124     for(int ch = 0; ch < 256; ch++) {
    00125       char *chp = strchr(base64_table, ch);
    00126       if (chp) {
    00127         reverse_table[ch] = (int)(chp - base64_table);
    00128       }
    00129       else
    00130         reverse_table[ch] = -1;
    00131     }
    00132     table_built = true;
    00133   }
    00134
    00135   unsigned char *result;
    00136   result = (unsigned char *)malloc(length + 1);
    00137   if (result == NULL)
    00138     return NULL;
    00139
    00140   // run through the whole string, converting as we go
    00141   //
    00142   const unsigned char *current = str;
    00143   int   ch, i = 0, j = 0, k;
    00144
    00145   // run through the whole string, converting as we go
    00146   while ((ch = *current++) != '\0') {
    00147     if (ch == base64_pad)
    00148       break;
    00149
    00150     // When Base64 gets POSTed, all pluses are interpreted as spaces.
    00151     // This line changes them back.  It's not exactly the Base64 spec,
    00152     // but it is completely compatible with it (the spec says that
    00153     // spaces are invalid).  This will also save many people considerable
    00154     // headache.  - Turadg Aleahmad <turadg@wise.berkeley.edu>
    00155     //
    00156     if (ch == ' ')
    00157       ch = '+';
    00158
    00159     ch = reverse_table[ch];
    00160     if (ch < 0)
    00161       continue;
    00162
    00163     switch(i % 4) {
    00164       case 0:
    00165         result[j] = ch << 2;
    00166         break;
    00167       case 1:
    00168         result[j++] |= ch >> 4;
    00169         result[j] = (ch & 0x0f) << 4;
    00170         break;
    00171       case 2:
    00172         result[j++] |= ch >>2;
    00173         result[j] = (ch & 0x03) << 6;
    00174         break;
    00175       case 3:
    00176         result[j++] |= ch;
    00177         break;
    00178     }
    00179     i++;
    00180   }
    00181
    00182   // mop things up if we ended on a boundary
    00183   //
    00184   k = j;
    00185   if (ch == base64_pad) {
    00186     switch(i % 4) {
    00187       case 0:
    00188       case 1:
    00189         free(result);
    00190         return NULL;
    00191       case 2:
    00192         k++;
    00193       case 3:
    00194         result[k++] = 0;
    00195     }
    00196   }
    00197   assert(j<length);
    00198
    00199   if (ret_length)
    00200     *ret_length = j;
    00201
    00202   result[k] = '\0';
    00203   return result;
    00204 }
    00205