Mime.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 $Id$
00004 
00005 */
00006 
00007 #include <bzlib.h>
00008 
00009 #include "Error.h"
00010 #include "Memory.h"
00011 
00012 #include "Mime.h"
00013 
00014 const char *const Mime::cb64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00015 const char *const Mime::cd64 = "|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
00016 
00017 // Public methods.
00018 
00019 MimeEncoding Mime::encoding(const String &name)
00020 {
00021   if (strcasecmp(CSTRING(name), MIME_ENC_NAME_NONE) == 0)
00022     return MIME_ENC_NONE;
00023   else
00024     if (strcasecmp(CSTRING(name), MIME_ENC_NAME_BASE64) == 0)
00025       return MIME_ENC_BASE64;
00026     else
00027       if (strcasecmp(CSTRING(name), MIME_ENC_NAME_ZBASE64) == 0)
00028         return MIME_ENC_ZBASE64;
00029       else
00030         if (strcasecmp(CSTRING(name), MIME_ENC_NAME_BZ2BASE64) == 0)
00031           return MIME_ENC_BZ2BASE64;
00032   return MIME_ENC_UNKNOWN;
00033 }
00034 
00035 // Base64 encode adding padding and line breaks as per spec.
00036 int Mime::encodeBase64(const String &source, String &destination, unsigned int lineWidth)
00037 {
00038   unsigned char in[3], out[4];
00039   unsigned int i, j = 0, len, blocksOut = 0;
00040   unsigned int srcLen = source.length();
00041 
00042   destination.clear();
00043   while (j < srcLen) {
00044     len = 0;
00045     for (i = 0; i < 3; ++i) {
00046       if (j < srcLen) {
00047         in[i] = (unsigned char)source[j];
00048         ++len;
00049       } else
00050           in[i] = 0;
00051       ++j;
00052     }
00053     if (len) {
00054       encodeBlock(in, out, len);
00055       for(i = 0; i < 4; ++i)
00056         destination += out[i];
00057       ++blocksOut;
00058     }
00059 
00060     if (blocksOut >= (lineWidth / 4) || j >= source.size()) {
00061       if (blocksOut)
00062         destination += '\n';
00063       blocksOut = 0;
00064     }
00065   }
00066 
00067   return OK;
00068 }
00069 
00070 // Decode a base64 encoded stream discarding padding, line breaks and noise.
00071 int Mime::decodeBase64(const String &source, String &destination)
00072 {
00073   unsigned char in[4], out[3], v;
00074   unsigned int i, len, j = 0;
00075   unsigned int srcLen = source.length();
00076 
00077   destination.clear();
00078   while (j < srcLen) {
00079     for (len = 0, i = 0; i < 4 && j < srcLen; ++i) {
00080       v = 0;
00081       while (j < srcLen && v == 0) {
00082         v = (unsigned char)source[j];
00083         ++j;
00084         v = (unsigned char)((v < 43 || v > 122) ? 0 : cd64[v - 43]);
00085         if (v)
00086           v = (unsigned char)((v == '$') ? 0 : v - 61);
00087       }
00088       if (j < srcLen) {
00089         ++len;
00090         if (v)
00091           in[i] = (unsigned char)(v - 1);
00092       } else
00093           in[i] = 0;
00094     }
00095     if (len) {
00096       decodeBlock(in, out);
00097       for (i = 0; i < len - 1; ++i)
00098         destination += out[i];
00099     }
00100   }
00101 
00102   return OK;
00103 }
00104 
00105 int Mime::encodeData(const String &source, String &destination, const MimeEncoding encoding)
00106 {
00107   unsigned int destLen;
00108   int res;
00109 
00110   switch (encoding) {
00111     case MIME_ENC_NONE:
00112       destination = source;
00113       return OK;
00114       break;
00115     case MIME_ENC_BASE64:
00116       if (FAILED(res = encodeBase64(source, destination)))
00117         return ERROR_BACKTRACE(res);
00118       break;
00119     case MIME_ENC_ZBASE64:
00120       destination = source;
00121       return ERROR(MSG_NOT_IMPLEMENTED, "Mime::encodeData for ZBASE64 encoding");
00122       break;
00123     case MIME_ENC_BZ2BASE64:
00124       unsigned int destSize = (unsigned int)((double)source.size() * 1.1f) + 6;
00125       char *buf;
00126 
00127       if (!(buf = (char *)MEM_ALLOC(destSize)))
00128         return ERROR(MSG_MEMORY_CANNOT_ALLOCATE, destSize, strerror(errno));
00129 
00130       if (BZ2_bzBuffToBuffCompress(buf, &destLen, (char *)source.data(), source.size(), 9, 0, 0) != BZ_OK) {
00131         MEM_FREE(buf);
00132         return ERROR(MSG_BZIP2_COMPRESSION);
00133       }
00134       if (FAILED(res = encodeBase64(String(buf, destLen), destination))) {
00135         MEM_FREE(buf);
00136         return ERROR_BACKTRACE(res);
00137       }
00138       MEM_FREE(buf);
00139       break;
00140     default:
00141       break;
00142   }
00143   return OK;
00144 }
00145 
00146 // Private methods.
00147 
00148 // Encode 3 8-bit binary bytes as 4 '6-bit' characters.
00149 void Mime::encodeBlock(unsigned char in[3], unsigned char out[4], int len)
00150 {
00151   out[0] = cb64[in[0] >> 2];
00152   out[1] = cb64[((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4)];
00153   out[2] = (unsigned char)(len > 1 ? cb64[((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6)] : '=');
00154   out[3] = (unsigned char)(len > 2 ? cb64[in[2] & 0x3f] : '=');
00155 }
00156 
00157 // Decode 4 '6-bit' characters into 3 8-bit binary bytes.
00158 void Mime::decodeBlock(unsigned char in[4], unsigned char out[3])
00159 {
00160   out[0] = (unsigned char)(in[0] << 2 | in[1] >> 4);
00161   out[1] = (unsigned char)(in[1] << 4 | in[2] >> 2);
00162   out[2] = (unsigned char)(((in[2] << 6) & 0xc0) | in[3]);
00163 }

Generated on Thu Sep 6 20:11:25 2007 for Pylon Application Platform by  doxygen 1.5.1