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