IBR-DTNSuite  0.8
ibrcommon/ibrcommon/data/Base64Stream.cpp
Go to the documentation of this file.
00001 /*
00002  * Base64Stream.cpp
00003  *
00004  *  Created on: 16.06.2011
00005  *      Author: morgenro
00006  */
00007 
00008 #include "ibrcommon/data/Base64Stream.h"
00009 #include "ibrcommon/data/Base64.h"
00010 #include <string.h>
00011 
00012 namespace ibrcommon
00013 {
00014         Base64Stream::Base64Stream(std::ostream &stream, bool decode, const size_t linebreak, const size_t buffer)
00015          : std::ostream(this), _decode(decode), _stream(stream), data_buf_(new char[buffer]), data_size_(buffer), _base64_state(0), _char_counter(0), _base64_padding(0), _linebreak(linebreak)
00016         {
00017                 setp(data_buf_, data_buf_ + data_size_ - 1);
00018         }
00019 
00020         Base64Stream::~Base64Stream()
00021         {
00022                 delete[] data_buf_;
00023         }
00024 
00025         void Base64Stream::set_byte(char val)
00026         {
00027                 switch (_base64_state)
00028                 {
00029                 case 0:
00030                         _group.set_0(val);
00031                         _base64_state++;
00032                         break;
00033 
00034                 case 1:
00035                         _group.set_1(val);
00036                         _base64_state++;
00037                         break;
00038 
00039                 case 2:
00040                         _group.set_2(val);
00041                         _base64_state++;
00042                         break;
00043                 }
00044         }
00045 
00046         void Base64Stream::set_b64(char val)
00047         {
00048                 switch (_base64_state)
00049                 {
00050                 case 0:
00051                         _group.b64_0(val);
00052                         _base64_state++;
00053                         break;
00054 
00055                 case 1:
00056                         _group.b64_1(val);
00057                         _base64_state++;
00058                         break;
00059 
00060                 case 2:
00061                         _group.b64_2(val);
00062                         _base64_state++;
00063                         break;
00064 
00065                 case 3:
00066                         _group.b64_3(val);
00067                         _base64_state++;
00068                         break;
00069                 }
00070         }
00071 
00072         int Base64Stream::sync()
00073         {
00074                 int ret = std::char_traits<char>::eq_int_type(this->overflow(
00075                                 std::char_traits<char>::eof()), std::char_traits<char>::eof()) ? -1
00076                                 : 0;
00077 
00078                 if (!_decode && (_base64_state > 0))
00079                 {
00080                         __flush_encoder__();
00081                 }
00082 
00083                 return ret;
00084         }
00085 
00086         std::char_traits<char>::int_type Base64Stream::overflow(std::char_traits<char>::int_type c)
00087         {
00088                 char *ibegin = data_buf_;
00089                 char *iend = pptr();
00090 
00091                 if (!std::char_traits<char>::eq_int_type(c, std::char_traits<char>::eof()))
00092                 {
00093                         *iend++ = std::char_traits<char>::to_char_type(c);
00094                 }
00095 
00096                 // mark the buffer as free
00097                 setp(data_buf_, data_buf_ + data_size_ - 1);
00098 
00099                 // available data
00100                 size_t len = (iend - ibegin);
00101 
00102                 // if there is nothing to send, just return
00103                 if (len == 0)
00104                 {
00105                         return std::char_traits<char>::not_eof(c);
00106                 }
00107 
00108                 // for each byte...
00109                 for (size_t i = 0; i < len; i++)
00110                 {
00111                         // do cipher stuff
00112                         if (_decode)
00113                         {
00114                                 const int c = Base64::getCharType( ibegin[i] );
00115 
00116                                 switch (c)
00117                                 {
00118                                         case Base64::UNKOWN_CHAR:
00119                                                 // skip unknown chars
00120                                                 continue;
00121 
00122                                         case Base64::EQUAL_CHAR:
00123                                         {
00124                                                 switch (_base64_state)
00125                                                 {
00126                                                 case 0:
00127                                                         // error - first character can not be a '='
00128                                                         return std::char_traits<char>::eof();
00129 
00130                                                 case 1:
00131                                                         // error - second character can not be a '='
00132                                                         return std::char_traits<char>::eof();
00133 
00134                                                 case 2:
00135                                                         // only one byte left
00136                                                         _base64_padding = 2;
00137                                                         break;
00138 
00139                                                 case 3:
00140                                                         // only one byte left
00141                                                         if (_base64_padding == 0)
00142                                                         {
00143                                                                 _base64_padding = 3;
00144                                                         }
00145                                                         break;
00146                                                 }
00147 
00148                                                 set_b64(0);
00149                                                 break;
00150                                         }
00151 
00152                                         default:
00153                                         {
00154                                                 // put char into the decode buffer
00155                                                 set_b64(c);
00156                                                 break;
00157                                         }
00158                                 }
00159 
00160                                 // when finished
00161                                 if (_base64_state == 4)
00162                                 {
00163                                         if (_base64_padding == 0)
00164                                         {
00165                                                 _stream.put( _group.get_0() );
00166                                                 _stream.put( _group.get_1() );
00167                                                 _stream.put( _group.get_2() );
00168                                         }
00169                                         else if (_base64_padding == 3)
00170                                         {
00171                                                 _stream.put( _group.get_0() );
00172                                                 _stream.put( _group.get_1() );
00173                                         }
00174                                         else if (_base64_padding == 2)
00175                                         {
00176                                                 _stream.put( _group.get_0() );
00177                                         }
00178 
00179                                         _base64_state = 0;
00180                                         _base64_padding = 0;
00181                                         _group.zero();
00182                                 }
00183                         }
00184                         else
00185                         {
00186                                 // put char into the encode buffer
00187                                 set_byte(ibegin[i]);
00188 
00189                                 if (_base64_state == 3)
00190                                 {
00191                                         __flush_encoder__();
00192                                         _group.zero();
00193                                 }
00194                         }
00195                 }
00196 
00197                 return std::char_traits<char>::not_eof(c);
00198         }
00199 
00200         void Base64Stream::__flush_encoder__()
00201         {
00202                 switch (_base64_state)
00203                 {
00204                 default:
00205                         break;
00206 
00207                 case 1:
00208                         _stream.put( Base64::encodeCharacterTable[ _group.b64_0() ] );
00209                         _stream.put( Base64::encodeCharacterTable[ _group.b64_1() ] );
00210                         _stream.put( '=' );
00211                         _stream.put( '=' );
00212                         break;
00213 
00214                 case 2:
00215                         _stream.put( Base64::encodeCharacterTable[ _group.b64_0() ] );
00216                         _stream.put( Base64::encodeCharacterTable[ _group.b64_1() ] );
00217                         _stream.put( Base64::encodeCharacterTable[ _group.b64_2() ] );
00218                         _stream.put( '=' );
00219                         break;
00220 
00221                 case 3:
00222                         _stream.put( Base64::encodeCharacterTable[ _group.b64_0() ] );
00223                         _stream.put( Base64::encodeCharacterTable[ _group.b64_1() ] );
00224                         _stream.put( Base64::encodeCharacterTable[ _group.b64_2() ] );
00225                         _stream.put( Base64::encodeCharacterTable[ _group.b64_3() ] );
00226                         break;
00227                 }
00228 
00229                 _base64_state = 0;
00230                 _char_counter += 4;
00231 
00232                 if (_char_counter >= _linebreak)
00233                 {
00234                         _stream.put('\n');
00235                         _char_counter = 0;
00236                 }
00237         }
00238 }