IBR-DTNSuite  0.8
ibrcommon/ibrcommon/data/Base64Reader.cpp
Go to the documentation of this file.
00001 /*
00002  * Base64Reader.cpp
00003  *
00004  *  Created on: 21.06.2011
00005  *      Author: morgenro
00006  */
00007 
00008 #include "ibrcommon/data/Base64Reader.h"
00009 #include "ibrcommon/Logger.h"
00010 #include <stdio.h>
00011 
00012 namespace ibrcommon
00013 {
00014         Base64Reader::Base64Reader(std::istream &stream, const size_t limit, const size_t buffer)
00015          : std::istream(this), _stream(stream), data_buf_(new char[buffer]), data_size_(buffer), _base64_state(0), _base64_padding(0), _byte_read(0), _byte_limit(limit)
00016         {
00017                 setg(0, 0, 0);
00018         }
00019 
00020         Base64Reader::~Base64Reader()
00021         {
00022                 delete[] data_buf_;
00023         }
00024 
00025         void Base64Reader::set_b64(char val)
00026         {
00027                 switch (_base64_state)
00028                 {
00029                 case 0:
00030                         _group.b64_0(val);
00031                         _base64_state++;
00032                         break;
00033 
00034                 case 1:
00035                         _group.b64_1(val);
00036                         _base64_state++;
00037                         break;
00038 
00039                 case 2:
00040                         _group.b64_2(val);
00041                         _base64_state++;
00042                         break;
00043 
00044                 case 3:
00045                         _group.b64_3(val);
00046                         _base64_state++;
00047                         break;
00048                 }
00049         }
00050 
00051         std::char_traits<char>::int_type Base64Reader::underflow()
00052         {
00053                 // signal EOF if end of stream is reached
00054                 if (_stream.eof())
00055                 {
00056                         return std::char_traits<char>::eof();
00057                 }
00058 
00059                 if ((_byte_limit > 0) && (_byte_read >= _byte_limit))
00060                 {
00061                         return std::char_traits<char>::eof();
00062                 }
00063 
00064                 // read some data
00065                 char buffer[data_size_];
00066 
00067                 if (_byte_limit > 0)
00068                 {
00069                         // get the remaining bytes
00070                         size_t bytes_to_read = _byte_limit - _byte_read;
00071 
00072                         // calculate base64 length for given plaintext length
00073                         bytes_to_read = Base64::getLength(bytes_to_read);
00074 
00075                         // minus pending bytes in the buffer
00076                         bytes_to_read -= _base64_state;
00077 
00078                         // debug
00079                         IBRCOMMON_LOGGER_DEBUG(30) <<
00080                                         "[Base64Reader] base64 bytes to read: " << bytes_to_read <<
00081                                         "; payload bytes: " << (_byte_limit - _byte_read) <<
00082                                         "; byte in buffer: " << (int)_base64_state << IBRCOMMON_LOGGER_ENDL;
00083 
00084                         // choose buffer size of remaining bytes
00085                         if (bytes_to_read > data_size_) bytes_to_read = data_size_;
00086 
00087                         // read from the stream
00088                         _stream.read((char*)&buffer, bytes_to_read);
00089                 }
00090                 else
00091                 {
00092                         _stream.read((char*)&buffer, data_size_);
00093                 }
00094 
00095                 size_t len = _stream.gcount();
00096 
00097                 // position in array
00098                 size_t decoded_bytes = 0;
00099 
00100                 for (size_t i = 0; i < len; i++)
00101                 {
00102                         const int c = Base64::getCharType( buffer[i] );
00103 
00104                         switch (c)
00105                         {
00106                                 case Base64::UNKOWN_CHAR:
00107                                         // skip unknown chars
00108                                         continue;
00109 
00110                                 case Base64::EQUAL_CHAR:
00111                                 {
00112                                         switch (_base64_state)
00113                                         {
00114                                         case 0:
00115                                                 // error - first character can not be a '='
00116                                                 return std::char_traits<char>::eof();
00117 
00118                                         case 1:
00119                                                 // error - second character can not be a '='
00120                                                 return std::char_traits<char>::eof();
00121 
00122                                         case 2:
00123                                                 // only one byte left
00124                                                 _base64_padding = 2;
00125                                                 break;
00126 
00127                                         case 3:
00128                                                 // only one byte left
00129                                                 if (_base64_padding == 0)
00130                                                 {
00131                                                         _base64_padding = 3;
00132                                                 }
00133                                                 break;
00134                                         }
00135 
00136                                         set_b64(0);
00137                                         break;
00138                                 }
00139 
00140                                 default:
00141                                 {
00142                                         // put char into the decode buffer
00143                                         set_b64(c);
00144                                         break;
00145                                 }
00146                         }
00147 
00148                         // when finished
00149                         if (_base64_state == 4)
00150                         {
00151                                 switch (_base64_padding)
00152                                 {
00153                                 case 0:
00154                                         data_buf_[decoded_bytes] = _group.get_0(); decoded_bytes++;
00155                                         data_buf_[decoded_bytes] = _group.get_1(); decoded_bytes++;
00156                                         data_buf_[decoded_bytes] = _group.get_2(); decoded_bytes++;
00157                                         break;
00158 
00159                                 case 3:
00160                                         data_buf_[decoded_bytes] = _group.get_0(); decoded_bytes++;
00161                                         data_buf_[decoded_bytes] = _group.get_1(); decoded_bytes++;
00162                                         break;
00163 
00164                                 case 2:
00165                                         data_buf_[decoded_bytes] = _group.get_0(); decoded_bytes++;
00166                                         break;
00167                                 }
00168 
00169                                 _base64_state = 0;
00170                                 _base64_padding = 0;
00171                                 _group.zero();
00172                         }
00173                 }
00174 
00175                 // if we could not decode any byte, we have to get more input bytes
00176                 if (decoded_bytes == 0)
00177                 {
00178                         // call underflow() recursively
00179                         return underflow();
00180                 }
00181 
00182                 // Since the input buffer content is now valid (or is new)
00183                 // the get pointer should be initialized (or reset).
00184                 setg(data_buf_, data_buf_, data_buf_ + decoded_bytes);
00185 
00186                 if (_byte_limit > 0)
00187                 {
00188                         _byte_read += decoded_bytes;
00189                 }
00190 
00191                 return std::char_traits<char>::not_eof((unsigned char) data_buf_[0]);
00192         }
00193 }