1 /*
2 * Redistribution and use in source and binary forms, with or
3 * without modification, are permitted provided that the following
4 * conditions are met:
5 *
6 * 1. Redistributions of source code must retain the above
7 * copyright notice, this list of conditions and the
8 * following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following
12 * disclaimer in the documentation and/or other materials
13 * provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
19 * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
26 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29 #include "base64.h"
30 /*
31 * This is part of the libb64 project, and has been placed in the
32 * public domain. For details, see
33 * http://sourceforge.net/projects/libb64
34 */
35
36 /* {{{ encode */
37
38 enum base64_encodestep { step_A, step_B, step_C };
39
40 struct base64_encodestate {
41 enum base64_encodestep step;
42 char result;
43 int stepcount;
44 };
45
46 static inline void
base64_encodestate_init(struct base64_encodestate * state)47 base64_encodestate_init(struct base64_encodestate *state)
48 {
49 state->step = step_A;
50 state->result = 0;
51 state->stepcount = 0;
52 }
53
54 static inline char
base64_encode_value(char value)55 base64_encode_value(char value)
56 {
57 static const char encoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
58 unsigned codepos = (unsigned) value;
59 if (codepos > sizeof(encoding) - 1)
60 return '=';
61 return encoding[codepos];
62 }
63
64 static int
base64_encode_block(const char * in_bin,int in_len,char * out_base64,int out_len,struct base64_encodestate * state)65 base64_encode_block(const char *in_bin, int in_len,
66 char *out_base64, int out_len,
67 struct base64_encodestate *state)
68 {
69 const char *const in_end = in_bin + in_len;
70 const char *in_pos = in_bin;
71 char *out_pos = out_base64;
72 char *out_end = out_base64 + out_len;
73 char result;
74 char fragment;
75
76 result = state->result;
77
78 switch (state->step)
79 {
80 while (1)
81 {
82 case step_A:
83 if (in_pos == in_end || out_pos >= out_end) {
84 state->result = result;
85 state->step = step_A;
86 return out_pos - out_base64;
87 }
88 fragment = *in_pos++;
89 result = (fragment & 0x0fc) >> 2;
90 *out_pos++ = base64_encode_value(result);
91 result = (fragment & 0x003) << 4;
92 /* fallthrough */
93 case step_B:
94 if (in_pos == in_end || out_pos >= out_end) {
95 state->result = result;
96 state->step = step_B;
97 return out_pos - out_base64;
98 }
99 fragment = *in_pos++;
100 result |= (fragment & 0x0f0) >> 4;
101 *out_pos++ = base64_encode_value(result);
102 result = (fragment & 0x00f) << 2;
103 /* fallthrough */
104 case step_C:
105 if (in_pos == in_end || out_pos + 2 >= out_end) {
106 state->result = result;
107 state->step = step_C;
108 return out_pos - out_base64;
109 }
110 fragment = *in_pos++;
111 result |= (fragment & 0x0c0) >> 6;
112 *out_pos++ = base64_encode_value(result);
113 result = (fragment & 0x03f) >> 0;
114 *out_pos++ = base64_encode_value(result);
115
116 /*
117 * Each full step (A->B->C) yields
118 * 4 characters.
119 */
120 if (++state->stepcount * 4 == BASE64_CHARS_PER_LINE) {
121 if (out_pos >= out_end)
122 return out_pos - out_base64;
123 *out_pos++ = '\n';
124 state->stepcount = 0;
125 }
126 }
127 }
128 /* control should not reach here */
129 return out_pos - out_base64;
130 }
131
132 static int
base64_encode_blockend(char * out_base64,int out_len,struct base64_encodestate * state)133 base64_encode_blockend(char *out_base64, int out_len,
134 struct base64_encodestate *state)
135 {
136 char *out_pos = out_base64;
137 char *out_end = out_base64 + out_len;
138
139 switch (state->step) {
140 case step_B:
141 if (out_pos + 2 >= out_end)
142 return out_pos - out_base64;
143 *out_pos++ = base64_encode_value(state->result);
144 *out_pos++ = '=';
145 *out_pos++ = '=';
146 break;
147 case step_C:
148 if (out_pos + 1 >= out_end)
149 return out_pos - out_base64;
150 *out_pos++ = base64_encode_value(state->result);
151 *out_pos++ = '=';
152 break;
153 case step_A:
154 break;
155 }
156 if (out_pos >= out_end)
157 return out_pos - out_base64;
158 #if 0
159 /* Sometimes the output is useful without a newline. */
160 *out_pos++ = '\n';
161 if (out_pos >= out_end)
162 return out_pos - out_base64;
163 #endif
164 *out_pos = '\0';
165 return out_pos - out_base64;
166 }
167
168 int
base64_encode(const char * in_bin,int in_len,char * out_base64,int out_len)169 base64_encode(const char *in_bin, int in_len,
170 char *out_base64, int out_len)
171 {
172 struct base64_encodestate state;
173 base64_encodestate_init(&state);
174 int res = base64_encode_block(in_bin, in_len, out_base64,
175 out_len, &state);
176 return res + base64_encode_blockend(out_base64 + res, out_len - res,
177 &state);
178 }
179
180 /* }}} */
181
182 /* {{{ decode */
183
184 enum base64_decodestep { step_a, step_b, step_c, step_d };
185
186 struct base64_decodestate
187 {
188 enum base64_decodestep step;
189 char result;
190 };
191
192 static char
base64_decode_value(char value)193 base64_decode_value(char value)
194 {
195 static const char decoding[] = {
196 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58,
197 59, 60, 61, -1, -1, -1, -2, -1, -1, -1, 0, 1,
198 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
199 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
200 -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31,
201 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
202 44, 45, 46, 47, 48, 49, 50, 51
203 };
204 static const char decoding_size = sizeof(decoding);
205 int codepos = (signed char) value;
206 codepos -= 43;
207 if (codepos < 0 || codepos > decoding_size)
208 return -1;
209 return decoding[codepos];
210 }
211
212 static inline void
base64_decodestate_init(struct base64_decodestate * state)213 base64_decodestate_init(struct base64_decodestate *state)
214 {
215 state->step = step_a;
216 state->result = 0;
217 }
218
219 static int
base64_decode_block(const char * in_base64,int in_len,char * out_bin,int out_len,struct base64_decodestate * state)220 base64_decode_block(const char *in_base64, int in_len,
221 char *out_bin, int out_len,
222 struct base64_decodestate *state)
223 {
224 const char *in_pos = in_base64;
225 const char *in_end = in_base64 + in_len;
226 char *out_pos = out_bin;
227 char *out_end = out_bin + out_len;
228 char fragment;
229
230 *out_pos = state->result;
231
232 switch (state->step)
233 {
234 while (1)
235 {
236 case step_a:
237 do {
238 if (in_pos == in_end || out_pos >= out_end)
239 {
240 state->step = step_a;
241 state->result = *out_pos;
242 return out_pos - out_bin;
243 }
244 fragment = base64_decode_value(*in_pos++);
245 } while (fragment < 0);
246 *out_pos = (fragment & 0x03f) << 2;
247 /* fallthrough */
248 case step_b:
249 do {
250 if (in_pos == in_end || out_pos >= out_end)
251 {
252 state->step = step_b;
253 state->result = *out_pos;
254 return out_pos - out_bin;
255 }
256 fragment = base64_decode_value(*in_pos++);
257 } while (fragment < 0);
258 *out_pos++ |= (fragment & 0x030) >> 4;
259 if (out_pos < out_end)
260 *out_pos = (fragment & 0x00f) << 4;
261 /* fallthrough */
262 case step_c:
263 do {
264 if (in_pos == in_end || out_pos >= out_end)
265 {
266 state->step = step_c;
267 state->result = *out_pos;
268 return out_pos - out_bin;
269 }
270 fragment = base64_decode_value(*in_pos++);
271 } while (fragment < 0);
272 *out_pos++ |= (fragment & 0x03c) >> 2;
273 if (out_pos < out_end)
274 *out_pos = (fragment & 0x003) << 6;
275 /* fallthrough */
276 case step_d:
277 do {
278 if (in_pos == in_end || out_pos >= out_end)
279 {
280 state->step = step_d;
281 state->result = *out_pos;
282 return out_pos - out_bin;
283 }
284 fragment = base64_decode_value(*in_pos++);
285 } while (fragment < 0);
286 *out_pos++ |= (fragment & 0x03f);
287 }
288 }
289 /* control should not reach here */
290 return out_pos - out_bin;
291 }
292
293
294
295 int
base64_decode(const char * in_base64,int in_len,char * out_bin,int out_len)296 base64_decode(const char *in_base64, int in_len,
297 char *out_bin, int out_len)
298 {
299 struct base64_decodestate state;
300 base64_decodestate_init(&state);
301 return base64_decode_block(in_base64, in_len,
302 out_bin, out_len, &state);
303 }
304
305 /* }}} */
306