Hall-D Software  alpha
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
base64.cpp
Go to the documentation of this file.
1 #include <xstream/config.h>
2 #include <xstream/base64.h>
4 
5 #include "debug.h"
6 
7 namespace xstream
8 {
9  namespace base64
10  {
11 
12  static const char dictionary[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
13 
14  static const int eof = std::streambuf::traits_type::eof();
15 
16  ostreambuf::ostreambuf(std::streambuf* sb, unsigned int w, char c)
17  : _sb(sb), delim(c), delim_w(w), col(0) {
18  LOG("base64::ostreambuf (streambuf*)");
19  reset();
20  }
21 
23  LOG("base64::ostreambuf::reset");
24  setp(buf,buf+sizeof(buf)/sizeof(char));
25  }
26 
27  //no flush of base64 data, just flushes the streambuf it writes to
29  LOG("base64::ostreambuf::sync");
30  return _sb->pubsync();
31  }
32 
33  static inline void encode(const char* in, char* out) {
34  LOG("base64::encode");
35  static const unsigned int hi6 = ((1 << 6) -1 ) << 2;
36  static const unsigned int lo2 = (1 << 2) - 1;
37  static const unsigned int hi4 = ((1 << 4) - 1) << 4;
38  static const unsigned int lo4 = (1 << 4) - 1;
39  static const unsigned int hi2 = ((1 << 2) - 1) << 6;
40  static const unsigned int lo6 = (1 << 6) - 1;
41 
42  out[0] = dictionary[(hi6 & in[0]) >> 2];
43  out[1] = dictionary[(lo2 & in[0]) << 4 | (hi4 & in[1]) >> 4];
44  out[2] = dictionary[(lo4 & in[1]) << 2 | (hi2 & in[2]) >> 6];
45  out[3] = dictionary[lo6 & in[2]];
46  }
47 
48  int ostreambuf::write(const char* buf, size_t len) {
49  unsigned int rcol = delim_w - col;
50  int ret = 0;
51 
52  //XXX all these sputn calls need to be checked
53  if (delim_w > 0 && rcol <= len) {
54  LOG("\t" << rcol << " columns to padding");
55  ret += _sb->sputn(buf, rcol);
56  ret += (_sb->sputc(delim) == delim)? 1 : 0;
57  ret += _sb->sputn(buf + rcol, len - rcol);
58  col = len - rcol;
59  LOG("\tcol = " << col);
60  }
61  else {
62  ret += _sb->sputn(buf,len);
63  col += len;
64  }
65 
66  reset();
67 
68  return ret;
69  }
70 
72  LOG("base64::ostreambuf::overflow (" << c << ")\n\t[" << *buf << *(buf+1) << *(buf+2) << "]");
73 
74  char enc[4]; //encoded buffer
75  encode(buf, enc);
76 
77  write(enc, 4);
78 
79  *pptr() = static_cast < char >(c);
80  pbump(1);
81 
82  return c;
83  }
84 
86  LOG("base64::~ostreambuf");
87  int av = available();
88 
89  if (3 == av) {
90  //no need to do anything
91  }
92  else {
93  char enc[4];
94  for(int i=0; i < av; ++i) {
95  //pad to zero
96  buf[2-i] = '\0';
97  }
98  encode(buf,enc);
99 
100  if (1 <= av) {
101  enc[3] = '=';
102  }
103  if (2 <= av) {
104  enc[2] = '=';
105  }
106 
107  //XXX need to check return code
108  write(enc,4);
109  }
110 
111  _sb->pubsync();
112  }
113 
114  //should search in constant time
115  static inline char index(char c) {
116  static const int window = 'Z'- 'A' + 1 ;
117 
118  //if c is not in dict throw exception
119  //could be a lot cleaner if no debugging was needed
120 
121  int d = c - 'A';
122  int ret = -1;
123 
124  if (d >= 0 && d < window) {
125  ret = d;
126  }
127  else {
128  d = c - 'a';
129  if (d >= 0 && d < window) {
130  ret = d + window;
131  }
132  else {
133  d = c - '0';
134  if (d >= 0 && d < 10) {
135  ret = d + 2 * window;
136  }
137  else {
138  if ('+' == c) {
139  ret = 62;
140  }
141  else {
142  if ('/' == c) {
143  ret = 63;
144  }
145  }
146  }
147  }
148  }
149 
150  if (-1 == ret) {
151  LOG("base64::index (" << c << ") [unknown]");
152  throw(decode_error(std::string("character '") + c + "' not part of base64 alphabet"));
153  }
154  else {
155  return ret;
156  }
157  }
158 
159  static inline void decode(const char* in, char* out) {
160  LOG("base64::decode");
161  static const unsigned char hi2 = ((1 << 2) - 1) << 4;
162  static const unsigned char lo4 = ((1 << 4) - 1);
163  static const unsigned char hi4 = ((1 << 4) - 1) << 2;
164  static const unsigned char lo2 = ((1 << 2) - 1);
165 
166  char _in[4];
167 
168  for (int i=0; i < 4; ++i) {
169  _in[i] = index(in[i]);
170  }
171 
172  char c;
173  c = _in[0] << 2;
174  c |= (_in[1] & hi2) >> 4;
175  out[0] = c;
176 
177  c = (_in[1] & lo4) << 4;
178  c |= (_in[2] & hi4) >> 2;
179  out[1] = c;
180 
181  c = (_in[2] & lo2) << 6;
182  c |= _in[3];
183  out[2] = c;
184  }
185 
186  istreambuf::istreambuf(std::streambuf* sb, unsigned int d_w, char d)
187  : _sb(sb), end(false), delim(d), delim_w(d_w), col(0) {
188  LOG("base64::istreambuf (streambuf*)");
189  setg(buf, buf, buf);
190  }
191 
193  LOG("base64::istreambuf::underflow");
194 
195  if (end) {
196  LOG("\tattempt to read from an ended stream");
197  return eof;
198  }
199  else {
200  char enc[4 + 1];
201  int av = (delim_w - col);
202  if (delim_w > 0 && av <= 4) {
203  LOG("\texpecting delimiter at " << av);
204  int ret = _sb->sgetn(enc, 5);
205  LOG("\tenc=" << enc);
206  if (5 != ret) {
207  LOG("\tread " << ret << " but wanted " << 5);
208  //XXX throw exception?
209  end = true;
210  return eof;
211  }
212  if (delim != enc[av]) {
213  LOG("\texpected delimiter " << delim << " but got " << enc[av]);
214  end = true;
215  throw decode_error("expected delimiter missing");
216  return eof;
217  }
218  else {
219  col = 4 - av;
220  for (int i=av; i < 4; ++i) {
221  enc[i] = enc[i + 1];
222  }
223  }
224  }
225  else {
226  int ret = _sb->sgetn(enc, 4);
227  col += 4;
228 
229  if (4 != ret) {
230  //XXX maybe I should throw an exception
231  end = true;
232  return eof;
233  }
234  }
235  int len=3;
236  if ('=' == enc[3]) {
237  enc[3] = 'A'; //guard
238  if ('=' == enc[2]) {
239  len = 1;
240  enc[2] = 'A'; //guard
241  } else {
242  len = 2;
243  }
244  }
245  if (3 != len) {
246  end = true;
247  }
248 
249  decode(enc, buf);
250  setg(buf, buf, buf + len);
251  return 0;
252  }
253  }
254 
256  LOG("base64::~istreambuf");
257  }
258 
259  }//namespace base64
260 }//namespace xstream
std::streambuf * _sb
Definition: base64.h:108
int sync()
flush as much data as possible (overloaded from streambuf)
Definition: base64.cpp:28
void reset()
reset input buffer
Definition: base64.cpp:22
debugging/logging support
ostreambuf(std::streambuf *sb, unsigned int width=76, char delimiter='\n')
construct using a streambuf
Definition: base64.cpp:16
char string[256]
#define c
std::streambuf * _sb
Definition: base64.h:35
static void encode(const char *in, char *out)
Definition: base64.cpp:33
~ostreambuf()
closes the base64 stream
Definition: base64.cpp:85
static char index(char c)
Definition: base64.cpp:115
int write(const char *buf, size_t len)
Takes care of inserting delimiters every delim_w characters.
Definition: base64.cpp:48
general base64 decoding errors
Definition: except/base64.h:57
static void decode(const char *in, char *out)
Definition: base64.cpp:159
istreambuf(std::streambuf *sb, unsigned int width=76, char delimiter='\n')
construct using a streambuf
Definition: base64.cpp:186
static const int eof
Definition: base64.cpp:14
int underflow()
requests that input buffer be reloaded (overloaded from streambuf)
Definition: base64.cpp:192
unsigned int delim_w
Definition: base64.h:37
int overflow(int c)
write a character that surpasses buffer end (overloaded from streambuf)
Definition: base64.cpp:71
C++ streambuf interface to encode/decode base64 data.
std::streamsize available() const
remaining characters in the buffer
Definition: common.h:28
unsigned int delim_w
Definition: base64.h:111
~istreambuf()
closes the base64 stream
Definition: base64.cpp:255
static const char dictionary[]
Definition: base64.cpp:12
#define LOG(s)
Definition: debug.h:30
exception related to base64 encode/decode, xstream::base64 namespace