Main Page   Class Hierarchy   Alphabetical List   Compound List   Examples  
base64.h
00001 /***************************************************************************
00002     copyright            : (C) 2002-2008 by Stefano Barbato
00003     email                : stefano@codesink.org
00004 
00005     $Id: base64.h,v 1.15 2008-10-07 11:06:26 tat Exp $
00006  ***************************************************************************/
00007 #ifndef _MIMETIC_CODEC_BASE64_H_
00008 #define _MIMETIC_CODEC_BASE64_H_
00009 #include <mimetic/circular_buffer.h>
00010 #include <mimetic/codec/codec_base.h>
00011 #include <mimetic/codec/codec_chain.h>
00012 
00013 namespace mimetic
00014 {
00015 
00016 
00017 class Base64
00018 {
00019     enum { LF = 0xA, CR = 0xD, NL = '\n' };
00020     enum { default_maxlen = 76 };
00021     enum { eq_sign = 100 };
00022     static const char sEncTable[];
00023     static const char sDecTable[];
00024     static const int sDecTableSz;
00025 public:
00026     class Encoder; class Decoder;
00027     typedef Encoder encoder_type;
00028     typedef Decoder decoder_type;
00029 
00030 
00031 /// Base64 encoder
00032 /*!
00033 
00034  \sa encode decode
00035  */
00036 class Encoder: public buffered_codec, public chainable_codec<Encoder>
00037 {
00038     enum { pad_idx = 64 };
00039     char_type m_ch[3];
00040     int m_cidx;
00041     int m_pos, m_maxlen;
00042 
00043     template<typename OutIt>
00044     inline void writeBuf(OutIt& out)
00045     {
00046         int pad_count = 3 - m_cidx;
00047         m_cidx = 0;    
00048         int idx[4];
00049         idx[0] = m_ch[0] >> 2;
00050         switch(pad_count)
00051         {
00052         case 0:
00053             idx[1] = (((m_ch[0] & 3) << 4) |  (m_ch[1] >> 4));
00054             idx[2] = ((m_ch[1] & 0xf) << 2) | (m_ch[2] >> 6);
00055             idx[3] = m_ch[2] & 0x3f;
00056             break;
00057         case 1:
00058             idx[1] = (((m_ch[0] & 3) << 4) |  (m_ch[1] >> 4));
00059             idx[2] = (m_ch[1] & 0xf) << 2 ;
00060             idx[3] = pad_idx;
00061             break;
00062         case 2:
00063             idx[1] = (m_ch[0] & 3) << 4;
00064             idx[2] = idx[3] = pad_idx;
00065             break;
00066         }
00067         for(int i = 0; i < 4; ++i)
00068         {
00069             *out = sEncTable[ idx[i] ]; ++out;
00070             if(m_maxlen && ++m_pos > m_maxlen)
00071             {
00072                 *out = NL; ++out;
00073                 m_pos = 1;
00074             }
00075         }
00076     }
00077 public:
00078     /*! return the multiplier of the required (max) size of the output buffer 
00079      * when encoding */
00080     double codeSizeMultiplier() const
00081     {
00082         return 1.5;
00083     }
00084     /*! Constructor, maxlen is the maximum length of every encoded line */
00085     Encoder(int maxlen = default_maxlen)
00086     : m_cidx(0), m_pos(1), m_maxlen(maxlen)
00087     {
00088     }
00089     /*! Returns the name of the codec ("Base64") */
00090     const char* name() const { return "Base64"; }
00091     /*! 
00092      Encodes [\p bit,\p eit) and write any encoded char to \p out.
00093      */
00094     template<typename InIt, typename OutIt>
00095     void process(InIt bit, InIt eit, OutIt out)
00096     {
00097         for(; bit != eit; ++bit)
00098         {
00099             m_ch[m_cidx++] = (char_type)*bit; 
00100             if(m_cidx < 3)
00101                 continue;
00102             writeBuf(out);
00103         } 
00104         if(m_cidx > 0)
00105             writeBuf(out);
00106     }
00107     /*! 
00108      Encodes \p c and write any encoded output char to \p out.
00109      \warning You must call flush() when all chars have been 
00110      processed by the encode funcion.
00111      \n
00112      \code
00113         while( (c = getchar()) != EOF )
00114             b64.encode(c, out);    
00115         b64.flush();
00116      \endcode
00117      \n
00118      \sa flush()
00119      */
00120     template<typename OutIt>
00121     void process(char_type c, OutIt& out)
00122     {
00123         m_ch[m_cidx++] = c;
00124         if(m_cidx < 3)
00125             return;
00126         writeBuf(out);
00127     }
00128     /*!
00129     Write to \p out any buffered encoded char.
00130      */
00131     template<typename OutIt>
00132     void flush(OutIt& out)
00133     {
00134         if(m_cidx > 0)
00135             writeBuf(out);
00136     }
00137 };
00138 
00139 /// Base64 decoder
00140 /*!
00141 
00142  \sa encode decode
00143  */
00144 class Decoder: public buffered_codec, public chainable_codec<Decoder>
00145 {
00146     int m_cidx;
00147     char_type m_ch[4];
00148 
00149     template<typename OutIt>
00150     inline void writeBuf(OutIt& out)
00151     {
00152         if(m_cidx < 4)
00153         {  // malformed, missing chars will be cosidered pad 
00154             switch(m_cidx)
00155             {
00156             case 0:
00157             case 1:
00158                 return; // ignore;
00159             case 2:
00160                 m_ch[2] = m_ch[3] = eq_sign;
00161                 break;
00162             case 3:
00163                 m_ch[3] = eq_sign;
00164                 break;
00165             }
00166         }
00167         m_cidx = 0;    
00168         *out = (m_ch[0] << 2 | ((m_ch[1] >> 4) & 0x3) ); ++out;
00169         if(m_ch[2] == eq_sign) return;
00170         *out = (m_ch[1] << 4 | ((m_ch[2] >> 2) & 0xF) ); ++out;
00171         if(m_ch[3] == eq_sign) return;
00172         *out = (m_ch[2] << 6 | m_ch[3]); ++out;
00173     }
00174 public:
00175     /*! Constructor */
00176     Decoder()
00177     : m_cidx(0)
00178     {
00179     }
00180     /*! Returns the name of the codec ("Base64") */
00181     const char* name() const { return "Base64"; }
00182 
00183     /*! 
00184      Decodes [\p bit,\p eit) and write any decoded char to \p out.
00185      */
00186     template<typename InIt, typename OutIt>
00187     inline void process(InIt bit, InIt eit, OutIt out)
00188     {
00189         char_type c;
00190 
00191         for(; bit != eit; ++bit)
00192         {
00193             c = *bit; 
00194             if(c > sDecTableSz || sDecTable[c] == -1)
00195                 continue; // malformed or newline
00196             m_ch[m_cidx++] = sDecTable[c]; 
00197             if(m_cidx < 4)
00198                 continue;
00199             writeBuf(out);
00200         } 
00201         if(m_cidx > 0)
00202             writeBuf(out);
00203     }
00204     /*! 
00205      Decodes \p c and write any decoded output char to \p out.
00206      
00207      \warning You must call flush() when all chars have been 
00208      processed by the decode funcion.
00209      \n
00210      \code
00211         while( (c = getchar()) != EOF )
00212             b64.decode(c, out);    
00213         b64.flush();
00214      \endcode
00215      \n
00216      \sa flush()
00217      */
00218     template<typename OutIt>
00219     void process(char_type c, OutIt& out)
00220     {
00221         if(c > sDecTableSz || sDecTable[c] == -1)
00222             return; // malformed or newline
00223         m_ch[m_cidx++] = sDecTable[c];
00224         if(m_cidx < 4)
00225             return;
00226         writeBuf(out);
00227     }
00228     /*!
00229     Write to \p out any buffered decoded char.
00230      */
00231     template<typename OutIt>
00232     void flush(OutIt& out)
00233     {
00234         if(m_cidx > 0)
00235             writeBuf(out);
00236     }
00237 };
00238 
00239 }; // Base64
00240 
00241 }
00242 #endif
00243