Base64Codec.h
1 /*
2  * Copyright (C) 2005 by Marc Boris Duerner
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * As a special exception, you may use this file as part of a free
10  * software library without restriction. Specifically, if other files
11  * instantiate templates or use macros or inline functions from this
12  * file, or you compile this file and link it with other files to
13  * produce an executable, this file does not by itself cause the
14  * resulting executable to be covered by the GNU General Public
15  * License. This exception does not however invalidate any other
16  * reasons why the executable file might be covered by the GNU Library
17  * General Public License.
18  *
19  * This library is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22  * Lesser General Public License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public
25  * License along with this library; if not, write to the Free Software
26  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27  */
28 
29 #ifndef Pt_Base64Codec_h
30 #define Pt_Base64Codec_h
31 
32 #include <Pt/Api.h>
33 #include <Pt/Types.h>
34 #include <Pt/TextCodec.h>
35 
36 namespace Pt {
37 
42 class Base64Codec : public TextCodec<char, char>
43 {
44  public:
47  explicit Base64Codec(std::size_t ref = 0)
48  : TextCodec<char, char>(ref)
49  {}
50 
53  virtual ~Base64Codec()
54  {}
55 
56  protected:
57  // inherit docs
58  result do_in(MBState& s,
59  const char* fromBegin,
60  const char* fromEnd,
61  const char*& fromNext,
62  char* toBegin,
63  char* toEnd,
64  char*& toNext) const;
65 
66  // inherit docs
67  result do_out(MBState& s,
68  const char* fromBegin,
69  const char* fromEnd,
70  const char*& fromNext,
71  char* toBegin,
72  char* toEnd,
73  char*& toNext) const;
74 
75  // inherit docs
76  result do_unshift(MBState& state,
77  char* toBegin,
78  char* toEnd,
79  char*& toNext) const;
80 
81  // inherit docs
82  bool do_always_noconv() const throw()
83  {
84  return false;
85  }
86 
87  // inherit docs
88  int do_length(MBState& s, const char* fromBegin,
89  const char* fromEnd, std::size_t max) const
90  {
91  const int from = static_cast<int>( (fromEnd - fromBegin) / 4 );
92  const int to = static_cast<int>( max / 3 );
93  return to > from ? from * 4 : to * 4;
94  }
95 
96  // inherit docs
97  int do_encoding() const throw()
98  {
99  // stateful encoding
100  return -1;
101  }
102 
103  // inherit docs
104  int do_max_length() const throw()
105  {
106  //worst case: XX== -> x
107  return 4;
108  }
109 };
110 
112 inline char toBase64(uint8_t n)
113 {
114  static const char b64enc[]
115  = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
116 
117  return b64enc[n];
118 }
119 
121 inline uint8_t fromBase64(char b64)
122 {
123  static const uint8_t b64dec[]
124  = { 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
125  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
126  255,255,255,255,255,255,255,255,255,255,255,62,255,255,255,63,
127  52,53,54,55,56,57,58,59,60,61,255,255,255,64,255,255,
128  255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
129  15,16,17,18,19,20,21,22,23,24,25,255,255,255,255,255,
130  255,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
131  41,42,43,44,45,46,47,48,49,50,51,255,255,255,255,255,
132  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
133  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
134  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
135  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
136  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
137  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
138  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
139  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 };
140 
141  return b64dec[(int)b64];
142 }
143 
144 
145 inline Base64Codec::result Base64Codec::do_in(MBState& s,
146  const char* fromBegin,
147  const char* fromEnd,
148  const char*& fromNext,
149  char* toBegin,
150  char* toEnd,
151  char*& toNext) const
152 {
153  fromNext = fromBegin;
154  toNext = toBegin;
155 
156  while( (fromEnd - fromNext) >= 4 && (toEnd - toNext) >= 3 )
157  {
158  Pt::uint8_t first = fromBase64( *(fromNext++) );
159  Pt::uint8_t second = fromBase64( *(fromNext++) );
160  Pt::uint8_t third = fromBase64( *(fromNext++) );
161  Pt::uint8_t fourth = fromBase64( *(fromNext++) );
162 
163  *(toNext++) = (first << 2) + (second >> 4);
164 
165  if(third != 64)
166  *(toNext++) = (second << 4) + (third >> 2);
167 
168  if(fourth != 64)
169  *(toNext++) = (third << 6) + (fourth);
170  }
171 
172  if( fromEnd == fromNext )
173  return std::codecvt_base::ok;
174 
175  return std::codecvt_base::partial;
176 }
177 
178 
179 inline Base64Codec::result Base64Codec::do_out(Pt::MBState& state,
180  const char* fromBegin,
181  const char* fromEnd,
182  const char*& fromNext,
183  char* toBegin,
184  char* toEnd,
185  char*& toNext) const
186 {
187  fromNext = fromBegin;
188  toNext = toBegin;
189 
190  const char* first = 0;
191  const char* second = 0;
192  const char* third = 0;
193 
194  if(fromEnd - fromNext < 1)
195  return std::codecvt_base::partial;
196 
197  if(toEnd - toNext < 4)
198  return std::codecvt_base::partial;
199 
200  switch( state.n )
201  {
202  case 2:
203  first = &state.value.mbytes[0];
204  second = &state.value.mbytes[1];
205  third = fromNext++;
206  break;
207 
208  case 1:
209  if(fromEnd - fromNext < 2)
210  {
211  state.value.mbytes[1] = *fromNext++;
212  state.n = 2;
213  return std::codecvt_base::partial;
214  }
215 
216  first = &state.value.mbytes[0];
217  second = fromNext++;
218  third = fromNext++;
219  break;
220 
221  default:
222  if(fromEnd - fromNext == 1)
223  {
224  state.value.mbytes[0] = *fromNext++;
225  state.n = 1;
226  return std::codecvt_base::partial;
227  }
228 
229  if(fromEnd - fromNext == 2)
230  {
231  state.value.mbytes[0] = *fromNext++;
232  state.value.mbytes[1] = *fromNext++;
233  state.n = 2;
234  return std::codecvt_base::partial;
235  }
236 
237  first = fromNext++;
238  second = fromNext++;
239  third = fromNext++;
240  break;
241  }
242 
243  while (true)
244  {
245  *toNext++ = toBase64( (uint8_t(*first) >> 2) & 0x3f );
246  *(toNext++) = toBase64( ((uint8_t(*first) << 4) + (uint8_t(*second) >> 4)) & 0x3f );
247  *(toNext++) = toBase64( ((uint8_t(*second) << 2) + (uint8_t(*third) >> 6)) & 0x3f );
248  *(toNext++) = toBase64( uint8_t(*third) & 0x3f );
249 
250  if(toEnd - toNext < 4)
251  {
252  state = MBState();
253  return std::codecvt_base::partial;
254  }
255 
256  if( fromEnd - fromNext < 3 )
257  break;
258 
259  first = fromNext++;
260  second = fromNext++;
261  third = fromNext++;
262  }
263 
264  switch( fromEnd - fromNext )
265  {
266  case 2:
267  state.value.mbytes[0] = *fromNext++;
268  state.value.mbytes[1] = *fromNext++;
269  state.n = 2;
270  break;
271 
272  case 1:
273  state.value.mbytes[0] = *fromNext++;
274  state.n = 1;
275  break;
276 
277  default:
278  state = MBState();
279  break;
280  }
281 
282  return std::codecvt_base::ok;
283 }
284 
285 
286 inline Base64Codec::result Base64Codec::do_unshift(MBState& state,
287  char* toBegin,
288  char* toEnd,
289  char*& toNext) const
290 {
291  toNext = toBegin;
292 
293  if(toEnd - toBegin < 4)
294  {
295  return std::codecvt_base::partial;
296  }
297 
298  switch(state.n)
299  {
300  case 2:
301  *toNext++ = toBase64( (uint8_t(state.value.mbytes[0]) >> 2) & 0x3f );
302  *(toNext++) = toBase64( ((uint8_t(state.value.mbytes[0]) << 4) + (uint8_t(state.value.mbytes[1]) >> 4)) & 0x3f );
303  *(toNext++) = toBase64( (uint8_t(state.value.mbytes[1]) << 2) & 0x3f );
304  *(toNext++) = '=';
305  break;
306 
307  case 1:
308  *toNext++ = toBase64( (uint8_t(state.value.mbytes[0]) >> 2) & 0x3f );
309  *(toNext++) = toBase64( (uint8_t(state.value.mbytes[0]) << 4) & 0x3f );
310  *(toNext++) = '=';
311  *(toNext++) = '=';
312  break;
313 
314  case 0:
315  return std::codecvt_base::noconv;
316  }
317 
318  state = MBState();
319  return std::codecvt_base::ok;
320 }
321 
322 } //namespace Pt
323 
324 #endif
Base64Codec(std::size_t ref=0)
Default constructor.
Definition: Base64Codec.h:47
A codec for base-64 encoding.
Definition: Base64Codec.h:42
Converts between character encodings.
Definition: TextCodec.h:38
virtual ~Base64Codec()
Destructor.
Definition: Base64Codec.h:53
uint_type uint8_t
Unsigned 8-bit integer type.
Definition: Types.h:18