2 * base64.c: libb64 compressed code. Public domain.
3 * See http://libb64.sourceforge.net/ for original code and infos.
5 * Modified and fixed by Lynx <lynx@lynxlynx.ru> 03Jun2016:
6 * - Single TU, minimal external dependencies
7 * - Stream operation, no newline insertions
8 * - Fixed code style to pure K&R
9 * - Fixed integer overflows and fixed size types
10 * - Fixed out of bounds access in base64_decode_block
11 * - Force specify output size for output buffer when decoding
12 * - Fixed signed/unsigned issue on ARM
13 * - Added generic memory converter wrappers which do not expose internals
14 * - All functions calculate number of processed characters and return them to caller
20 enum base64_decodestep {
21 estep_a, estep_b, estep_c, estep_d
24 struct base64_decodestate {
25 enum base64_decodestep step;
30 enum base64_encodestep {
31 dstep_a, dstep_b, dstep_c
34 struct base64_encodestate {
35 enum base64_encodestep step;
40 int base64_decode_value(signed char value_in)
42 static const signed char decoding[] = {
43 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1,
44 -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
45 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34,
46 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
48 static const char decoding_size = sizeof(decoding);
49 if (value_in < 43) return -1;
51 if (value_in >= decoding_size) return -1;
52 return decoding[(int)value_in];
55 void base64_init_decodestate(struct base64_decodestate *state_in)
57 state_in->step = estep_a;
58 state_in->plainchar = 0;
62 #define CHECK_BOUNDS do { if (plainchar-plaintext_out >= plaintext_outl) goto _ret; } while (0)
64 size_t base64_decode_block(const char *code_in, size_t length_in, char *plaintext_out, size_t plaintext_outl, struct base64_decodestate *state_in)
66 const char *codechar = code_in;
67 char *plainchar = plaintext_out;
70 *plainchar = state_in->plainchar;
72 switch (state_in->step) {
76 if (codechar == code_in+length_in) {
77 state_in->step = estep_a;
78 state_in->plainchar = *plainchar;
79 state_in->count += (plainchar - plaintext_out);
80 return plainchar - plaintext_out;
82 fragment = base64_decode_value(*codechar++);
83 } while (fragment < 0);
84 *plainchar = (fragment & 0x3f) << 2;
87 if (codechar == code_in+length_in) {
88 state_in->step = estep_b;
89 state_in->plainchar = *plainchar;
90 state_in->count += (plainchar - plaintext_out);
91 return plainchar - plaintext_out;
93 fragment = base64_decode_value(*codechar++);
94 } while (fragment < 0);
95 *plainchar++ |= (fragment & 0x30) >> 4;
97 *plainchar = (fragment & 0x0f) << 4;
100 if (codechar == code_in+length_in) {
101 state_in->step = estep_c;
102 state_in->plainchar = *plainchar;
103 state_in->count += (plainchar - plaintext_out);
104 return plainchar - plaintext_out;
106 fragment = base64_decode_value(*codechar++);
107 } while (fragment < 0);
108 *plainchar++ |= (fragment & 0x3c) >> 2;
110 *plainchar = (fragment & 0x03) << 6;
113 if (codechar == code_in+length_in) {
114 state_in->step = estep_d;
115 state_in->plainchar = *plainchar;
116 state_in->count += (plainchar - plaintext_out);
117 return plainchar - plaintext_out;
119 fragment = base64_decode_value(*codechar++);
120 } while (fragment < 0);
121 *plainchar++ |= (fragment & 0x3f);
125 _ret: state_in->count += (plainchar - plaintext_out);
126 return plainchar - plaintext_out;
129 void base64_init_encodestate(struct base64_encodestate *state_in)
131 state_in->step = dstep_a;
132 state_in->result = 0;
136 char base64_encode_value(char value_in)
138 static const char *encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
139 if (value_in > 63) return '=';
140 return encoding[(int)value_in];
143 size_t base64_encode_block(const char *plaintext_in, size_t length_in, char *code_out, struct base64_encodestate *state_in)
145 const char *plainchar = plaintext_in;
146 const char *const plaintextend = plaintext_in + length_in;
147 char *codechar = code_out;
151 result = state_in->result;
153 switch (state_in->step) {
156 if (plainchar == plaintextend) {
157 state_in->result = result;
158 state_in->step = dstep_a;
159 state_in->count += (codechar - code_out);
160 return codechar - code_out;
162 fragment = *plainchar++;
163 result = (fragment & 0xfc) >> 2;
164 *codechar++ = base64_encode_value(result);
165 result = (fragment & 0x03) << 4;
167 if (plainchar == plaintextend) {
168 state_in->result = result;
169 state_in->step = dstep_b;
170 state_in->count += (codechar - code_out);
171 return codechar - code_out;
173 fragment = *plainchar++;
174 result |= (fragment & 0xf0) >> 4;
175 *codechar++ = base64_encode_value(result);
176 result = (fragment & 0x0f) << 2;
178 if (plainchar == plaintextend) {
179 state_in->result = result;
180 state_in->step = dstep_c;
181 state_in->count += (codechar - code_out);
182 return codechar - code_out;
184 fragment = *plainchar++;
185 result |= (fragment & 0xc0) >> 6;
186 *codechar++ = base64_encode_value(result);
187 result = (fragment & 0x3f) >> 0;
188 *codechar++ = base64_encode_value(result);
191 /* control should not reach here */
192 state_in->count += (codechar - code_out);
193 return codechar - code_out;
196 size_t base64_encode_blockend(char *code_out, struct base64_encodestate *state_in)
198 char *codechar = code_out + state_in->count;
200 switch (state_in->step) {
202 *codechar++ = base64_encode_value(state_in->result);
205 state_in->count += 3;
208 *codechar++ = base64_encode_value(state_in->result);
210 state_in->count += 2;
216 return codechar - code_out;
219 /* Process single block of memory */
220 size_t base64_decode(char *output, size_t outputl, const char *input, size_t inputl)
222 struct base64_decodestate dstate;
225 base64_init_decodestate(&dstate);
226 base64_decode_block(input, inputl, output, outputl, &dstate);
229 memset(&dstate, 0, sizeof(struct base64_decodestate));
234 size_t base64_encode(char *output, const char *input, size_t inputl)
236 struct base64_encodestate estate;
239 base64_init_encodestate(&estate);
240 base64_encode_block(input, inputl, output, &estate);
241 base64_encode_blockend(output, &estate);
244 memset(&estate, 0, sizeof(struct base64_encodestate));