IBR-DTNSuite  0.10
Base64Stream.cpp
Go to the documentation of this file.
1 /*
2  * Base64Stream.cpp
3  *
4  * Copyright (C) 2011 IBR, TU Braunschweig
5  *
6  * Written-by: Johannes Morgenroth <morgenroth@ibr.cs.tu-bs.de>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21 
23 #include "ibrcommon/data/Base64.h"
24 #include <string.h>
25 
26 namespace ibrcommon
27 {
28  Base64Stream::Base64Stream(std::ostream &stream, bool decode, const size_t linebreak, const size_t buffer)
29  : std::ostream(this), _decode(decode), _stream(stream), data_buf_(buffer), data_size_(buffer), _base64_state(0), _char_counter(0), _base64_padding(0), _linebreak(linebreak)
30  {
31  setp(&data_buf_[0], &data_buf_[0] + data_size_ - 1);
32  }
33 
35  {
36  }
37 
38  void Base64Stream::set_byte(char val)
39  {
40  switch (_base64_state)
41  {
42  case 0:
43  _group.set_0(val);
44  _base64_state++;
45  break;
46 
47  case 1:
48  _group.set_1(val);
49  _base64_state++;
50  break;
51 
52  case 2:
53  _group.set_2(val);
54  _base64_state++;
55  break;
56  }
57  }
58 
59  void Base64Stream::set_b64(char val)
60  {
61  switch (_base64_state)
62  {
63  case 0:
64  _group.b64_0(val);
65  _base64_state++;
66  break;
67 
68  case 1:
69  _group.b64_1(val);
70  _base64_state++;
71  break;
72 
73  case 2:
74  _group.b64_2(val);
75  _base64_state++;
76  break;
77 
78  case 3:
79  _group.b64_3(val);
80  _base64_state++;
81  break;
82  }
83  }
84 
86  {
87  int ret = std::char_traits<char>::eq_int_type(this->overflow(
88  std::char_traits<char>::eof()), std::char_traits<char>::eof()) ? -1
89  : 0;
90 
91  if (!_decode && (_base64_state > 0))
92  {
93  __flush_encoder__();
94  }
95 
96  return ret;
97  }
98 
99  std::char_traits<char>::int_type Base64Stream::overflow(std::char_traits<char>::int_type c)
100  {
101  char *ibegin = &data_buf_[0];
102  char *iend = pptr();
103 
104  if (!std::char_traits<char>::eq_int_type(c, std::char_traits<char>::eof()))
105  {
106  *iend++ = std::char_traits<char>::to_char_type(c);
107  }
108 
109  // mark the buffer as free
110  setp(&data_buf_[0], &data_buf_[0] + data_size_ - 1);
111 
112  // available data
113  size_t len = (iend - ibegin);
114 
115  // if there is nothing to send, just return
116  if (len == 0)
117  {
118  return std::char_traits<char>::not_eof(c);
119  }
120 
121  // for each byte...
122  for (size_t i = 0; i < len; ++i)
123  {
124  // do cipher stuff
125  if (_decode)
126  {
127  const int c = Base64::getCharType( ibegin[i] );
128 
129  switch (c)
130  {
131  case Base64::UNKOWN_CHAR:
132  // skip unknown chars
133  continue;
134 
135  case Base64::EQUAL_CHAR:
136  {
137  switch (_base64_state)
138  {
139  case 0:
140  // error - first character can not be a '='
141  return std::char_traits<char>::eof();
142 
143  case 1:
144  // error - second character can not be a '='
145  return std::char_traits<char>::eof();
146 
147  case 2:
148  // only one byte left
149  _base64_padding = 2;
150  break;
151 
152  case 3:
153  // only one byte left
154  if (_base64_padding == 0)
155  {
156  _base64_padding = 3;
157  }
158  break;
159  }
160 
161  set_b64(0);
162  break;
163  }
164 
165  default:
166  {
167  // put char into the decode buffer
168  set_b64(static_cast<char>(c));
169  break;
170  }
171  }
172 
173  // when finished
174  if (_base64_state == 4)
175  {
176  if (_base64_padding == 0)
177  {
178  _stream.put( _group.get_0() );
179  _stream.put( _group.get_1() );
180  _stream.put( _group.get_2() );
181  }
182  else if (_base64_padding == 3)
183  {
184  _stream.put( _group.get_0() );
185  _stream.put( _group.get_1() );
186  }
187  else if (_base64_padding == 2)
188  {
189  _stream.put( _group.get_0() );
190  }
191 
192  _base64_state = 0;
193  _base64_padding = 0;
194  _group.zero();
195  }
196  }
197  else
198  {
199  // put char into the encode buffer
200  set_byte(ibegin[i]);
201 
202  if (_base64_state == 3)
203  {
204  __flush_encoder__();
205  _group.zero();
206  }
207  }
208  }
209 
210  return std::char_traits<char>::not_eof(c);
211  }
212 
213  void Base64Stream::__flush_encoder__()
214  {
215  switch (_base64_state)
216  {
217  default:
218  break;
219 
220  case 1:
221  _stream.put( Base64::encodeCharacterTable[ _group.b64_0() ] );
222  _stream.put( Base64::encodeCharacterTable[ _group.b64_1() ] );
223  _stream.put( '=' );
224  _stream.put( '=' );
225  break;
226 
227  case 2:
228  _stream.put( Base64::encodeCharacterTable[ _group.b64_0() ] );
229  _stream.put( Base64::encodeCharacterTable[ _group.b64_1() ] );
230  _stream.put( Base64::encodeCharacterTable[ _group.b64_2() ] );
231  _stream.put( '=' );
232  break;
233 
234  case 3:
235  _stream.put( Base64::encodeCharacterTable[ _group.b64_0() ] );
236  _stream.put( Base64::encodeCharacterTable[ _group.b64_1() ] );
237  _stream.put( Base64::encodeCharacterTable[ _group.b64_2() ] );
238  _stream.put( Base64::encodeCharacterTable[ _group.b64_3() ] );
239  break;
240  }
241 
242  _base64_state = 0;
243  _char_counter += 4;
244 
245  if (_char_counter >= _linebreak)
246  {
247  _stream.put('\n');
248  _char_counter = 0;
249  }
250  }
251 }