IBR-DTNSuite
0.8
|
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 }