WvStreams
wvbase64.cc
1 /*
2  * Worldvisions Weaver Software:
3  * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
4  *
5  * Functions for encoding and decoding strings in MIME's Base64 notation.
6  *
7  * Base 64 is pretty easy. The input is processed in groups of three bytes.
8  * These 24 bits are split into 4 groups of 6 bits. Each group of six bits
9  * is represented by one character in the base64 alphabet, in the encoded
10  * output. The alphabet is as follows:
11  * ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=
12  * Where 'A' through '/' represent 000000 through 011111, the 64 different
13  * combinations. The '=' (100000) is padding and has no value when decoded.
14  */
15 #include "wvbase64.h"
16 
17 // maps codes to the Base64 alphabet
18 static char alphabet[67] =
19  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n";
20 
21 // finds codes in the Base64 alphabet
22 static int lookup(char ch)
23 {
24  if (ch >= 'A' && ch <= 'Z')
25  return ch - 'A';
26  if (ch >= 'a' && ch <= 'z')
27  return ch - 'a' + 26;
28  if (ch >= '0' && ch <= '9')
29  return ch - '0' + 52;
30  if (ch == '+')
31  return 62;
32  if (ch == '/')
33  return 63;
34  if (ch == '=')
35  return 64; // padding
36  if (ch == '\n' || ch == ' ' || ch == '\r' || ch == '\t' ||
37  ch == '\f' || ch == '\v')
38  return 65; // whitespace
39  return -1;
40 }
41 
42 
43 /***** WvBase64Encoder *****/
44 
46 {
47  _reset();
48 }
49 
50 
52 {
53  state = ATBIT0;
54  bits = 0;
55  return true;
56 }
57 
58 
59 bool WvBase64Encoder::_encode(WvBuf &in, WvBuf &out, bool flush)
60 {
61  // base 64 encode the entire buffer
62  while (in.used() != 0)
63  {
64  unsigned char next = in.getch();
65  bits = (bits << 8) | next;
66  switch (state)
67  {
68  case ATBIT0:
69  out.putch(alphabet[bits >> 2]);
70  bits &= 0x03;
71  state = ATBIT2;
72  break;
73  case ATBIT2:
74  out.putch(alphabet[bits >> 4]);
75  bits &= 0x0f;
76  state = ATBIT4;
77  break;
78  case ATBIT4:
79  out.putch(alphabet[bits >> 6]);
80  out.putch(alphabet[bits & 0x3f]);
81  bits = 0;
82  state = ATBIT0;
83  break;
84  }
85  }
86  // do not consider the data flushed if we need padding
87  if (flush && state != ATBIT0)
88  return false;
89  return true;
90 }
91 
92 
94 {
95  // pad text if needed
96  switch (state)
97  {
98  case ATBIT2:
99  out.putch(alphabet[bits << 4]);
100  out.putch('=');
101  out.putch('=');
102  break;
103  case ATBIT4:
104  out.putch(alphabet[bits << 2]);
105  out.putch('=');
106  break;
107  case ATBIT0:
108  break;
109  }
110  return true;
111 }
112 
113 
114 
115 /***** WvBase64Decoder *****/
116 
118 {
119  _reset();
120 }
121 
122 
124 {
125  state = ATBIT0;
126  bits = 0;
127  return true;
128 }
129 
130 
131 bool WvBase64Decoder::_encode(WvBuf &in, WvBuf &out, bool flush)
132 {
133  // base 64 decode the entire buffer
134  while (in.used() != 0)
135  {
136  unsigned char next = in.getch();
137  int symbol = lookup(next);
138  switch (symbol)
139  {
140  case -1: // invalid character
141  seterror("invalid character #%s in base64 input", next);
142  return false;
143 
144  case 64: // padding
145  // strip out any remaining padding
146  // we are lenient in that we do not track how much padding we skip
147  setfinished();
148  state = PAD;
149  break;
150 
151  case 65: // whitespace
152  break;
153 
154  default: // other symbol
155  bits = (bits << 6) | symbol;
156  switch (state)
157  {
158  case ATBIT0:
159  state = ATBIT2;
160  break;
161  case ATBIT2:
162  out.putch(bits >> 4);
163  bits &= 0x0f;
164  state = ATBIT4;
165  break;
166  case ATBIT4:
167  out.putch(bits >> 2);
168  bits &= 0x03;
169  state = ATBIT6;
170  break;
171  case ATBIT6:
172  out.putch(bits);
173  bits = 0;
174  state = ATBIT0;
175  break;
176 
177  case PAD:
178  seterror("invalid character #%s "
179  "after base64 padding", next);
180  return false;
181  }
182  break;
183  }
184  }
185  // if flushing and we did not get sufficient padding, then fail
186  if (flush && (state == ATBIT2 || state == ATBIT4 || state == ATBIT6))
187  return false; // insufficient padding to flush!
188  return true;
189 }
WvBase64Decoder::WvBase64Decoder
WvBase64Decoder()
Creates a base 64 decoder.
Definition: wvbase64.cc:117
lookup
int lookup(const char *str, const char *const *table, bool case_sensitive=false)
Finds a string in an array and returns its index.
Definition: strutils.cc:850
WvBufBase< unsigned char >::putch
void putch(int ch)
Puts a single character into the buffer as an int.
Definition: wvbuf.h:76
WvBase64Encoder::_encode
virtual bool _encode(WvBuf &in, WvBuf &out, bool flush)
Template method implementation of encode().
Definition: wvbase64.cc:59
WvBase64Encoder::_reset
virtual bool _reset()
Template method implementation of reset().
Definition: wvbase64.cc:51
WvBufBase< unsigned char >::getch
int getch()
Returns a single character from the buffer as an int.
Definition: wvbuf.h:66
WvBase64Encoder::WvBase64Encoder
WvBase64Encoder()
Creates a base 64 encoder.
Definition: wvbase64.cc:45
WvBase64Decoder::_encode
virtual bool _encode(WvBuf &in, WvBuf &out, bool flush)
Template method implementation of encode().
Definition: wvbase64.cc:131
WvBufBase< unsigned char >
Specialization of WvBufBase for unsigned char type buffers intended for use with raw memory buffers.
Definition: wvbuf.h:22
WvBase64Decoder::_reset
virtual bool _reset()
Template method implementation of reset().
Definition: wvbase64.cc:123
WvBase64Encoder::_finish
virtual bool _finish(WvBuf &out)
Template method implementation of finish().
Definition: wvbase64.cc:93
WvEncoder::flush
bool flush(WvBuf &inbuf, WvBuf &outbuf, bool finish=false)
Flushes the encoder and optionally finishes it.
Definition: wvencoder.h:163
WvEncoder::setfinished
void setfinished()
Sets 'finished' to true explicitly.
Definition: wvencoder.h:383
WvBufBaseCommonImpl::used
size_t used() const
Returns the number of elements in the buffer currently available for reading.
Definition: wvbufbase.h:92
WvEncoder::seterror
void seterror(WvStringParm message)
Sets an error condition, then setnotok().
Definition: wvencoder.h:375