Pico Headers
Loading...
Searching...
No Matches
pico_b64.h
Go to the documentation of this file.
1
45#ifndef PICO_B64_H
46#define PICO_B64_H
47
48#include <stddef.h>
49
50#ifdef __cplusplus
51extern "C" {
52#endif
53
60size_t b64_encoded_size(size_t len);
61
70size_t b64_decoded_size(const char* src, size_t len);
71
81size_t b64_encode(char* dst, const unsigned char* src, size_t len);
82
92size_t b64_decode(unsigned char* dst, const char* src, size_t len);
93
94#ifdef __cplusplus
95}
96#endif
97
98#endif // PICO_B64_H
99
100#ifdef PICO_B64_IMPLEMENTATION
101
102#ifndef PICO_B64_ISALNUM
103#include <ctype.h>
104#define PICO_B64_ISALNUM isalnum
105#endif // PICO_B64_ISALNUM
106
107#ifndef PICO_B64_FLOOR
108#include <math.h>
109#define PICO_B64_FLOOR floor
110#endif // PICO_B64_FLOOR
111
112#ifndef PICO_B64_CEIL
113#include <math.h>
114#define PICO_B64_CEIL ceil
115#endif // PICO_B64_CEIL
116
117/*=============================================================================
118 * Look-up table
119 *============================================================================*/
120
121static const char b64_table[] =
122{
123 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
124 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
125 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
126 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
127 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
128 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
129 'w', 'x', 'y', 'z', '0', '1', '2', '3',
130 '4', '5', '6', '7', '8', '9', '+', '/'
131};
132
133/*=============================================================================
134 * Buffer size functions
135 *============================================================================*/
136
137size_t b64_encoded_size(size_t len)
138{
139 return 4 * PICO_B64_CEIL(len / 3.0);
140}
141
142size_t b64_decoded_size(const char* src, size_t len)
143{
144 // Input must be padded and large enough
145 if (len > 0 && len % 4 != 0)
146 return 0;
147
148 if (0 == len)
149 return 0;
150
151 size_t padding = 0;
152
153 if ('=' == src[len - 2])
154 padding = 2;
155 else if ('=' == src[len - 1])
156 padding = 1;
157
158 return PICO_B64_FLOOR(3.0 * (len - padding) / 4.0);
159}
160
161/*=============================================================================
162 * Buffer encoding/decoding functions
163 *============================================================================*/
164static inline void b64_encode_tmp(unsigned char* buf, unsigned char* tmp)
165{
166 buf[0] = (tmp[0] & 0xfc) >> 2;
167 buf[1] = ((tmp[0] & 0x03) << 4) + ((tmp[1] & 0xf0) >> 4);
168 buf[2] = ((tmp[1] & 0x0f) << 2) + ((tmp[2] & 0xc0) >> 6);
169 buf[3] = tmp[2] & 0x3f;
170}
171
172static inline void b64_decode_tmp(unsigned char* buf, unsigned char* tmp)
173{
174 buf[0] = (tmp[0] << 2) + ((tmp[1] & 0x30) >> 4);
175 buf[1] = ((tmp[1] & 0xf) << 4) + ((tmp[2] & 0x3c) >> 2);
176 buf[2] = ((tmp[2] & 0x3) << 6) + tmp[3];
177}
178
179/*=============================================================================
180 * Encoding
181 *============================================================================*/
182
183size_t b64_encode(char* dst, const unsigned char* src, size_t len)
184{
185 int i = 0;
186 int j = 0;
187 size_t size = 0;
188 unsigned char buf[4];
189 unsigned char tmp[3];
190
191 // Parse until end of source
192 while (len--)
193 {
194 // Read up to 3 bytes at a time into 'tmp'
195 tmp[i++] = *(src++);
196
197 // If 3 bytes read then encode them
198 if (3 == i)
199 {
200 b64_encode_tmp(buf, tmp);
201
202 // Translate buffer
203 for (i = 0; i < 4; ++i)
204 {
205 dst[size++] = b64_table[buf[i]];
206 }
207
208 // reset index
209 i = 0;
210 }
211 }
212
213 // Remainder
214 if (i > 0)
215 {
216 // Fill 'tmp' with '\0' at most twice
217 for (j = i; j < 3; ++j)
218 {
219 tmp[j] = '\0';
220 }
221
222 // Perform same transformation as above
223 b64_encode_tmp(buf, tmp);
224
225 // Translate buffer
226 for (j = 0; j < i + 1; ++j)
227 {
228 dst[size++] = b64_table[buf[j]];
229 }
230
231 // While there is still a remainder append '=' to 'dst'
232 while (i++ < 3)
233 {
234 dst[size++] = '=';
235 }
236 }
237
238 return size;
239}
240
241/*=============================================================================
242 * Decoding
243 *============================================================================*/
244
245static inline size_t b64_table_lookup(char symbol)
246{
247 size_t i;
248
249 for (i = 0; i < 64; ++i)
250 {
251 if (symbol == b64_table[i])
252 return i;
253 }
254
255 return 0;
256}
257
258size_t b64_decode(unsigned char* dst, const char * src, size_t len)
259{
260 int i = 0;
261 int j = 0;
262 size_t size = 0;
263 unsigned char buf[3];
264 unsigned char tmp[4];
265
266 // Parse until end of source
267 while (len--) {
268 // Break if char is padding ('=') or not base64 char
269 if ('=' == src[j])
270 break;
271
272 // Break if char is not base64
273 if (!PICO_B64_ISALNUM((int)src[j]) && '+' != src[j] && '/' != src[j])
274 break;
275
276 // Read up to 4 bytes at a time into 'tmp'
277 tmp[i++] = src[j++];
278
279 // If 4 bytes read then decode into 'buf'
280 if (4 == i)
281 {
282 // Translate values in 'tmp' from table
283 for (i = 0; i < 4; ++i)
284 {
285 tmp[i] = b64_table_lookup(tmp[i]);
286 }
287
288 // Decode transform
289 b64_decode_tmp(buf, tmp);
290
291 // Write into result
292 for (i = 0; i < 3; ++i)
293 {
294 dst[size++] = buf[i];
295 }
296
297 // Reset
298 i = 0;
299 }
300 }
301
302 // Remainder
303 if (i > 0)
304 {
305 // Fill 'tmp' with '\0' at most 3 times
306 for (j = i; j < 4; ++j)
307 {
308 tmp[j] = '\0';
309 }
310
311 // Translate remainder
312 for (j = 0; j < 4; ++j)
313 {
314 // find translation char in 'b64_table'
315 tmp[j] = b64_table_lookup(tmp[j]);
316 }
317
318 // Decode transform
319 b64_decode_tmp(buf, tmp);
320
321 // Write into result
322 for (j = 0; j < i - 1; ++j)
323 {
324 dst[size++] = buf[j];
325 }
326 }
327
328 return size;
329}
330
331#endif // PICO_B64_IMPLEMENTATION
332
333/*
334The MIT License (MIT)
335
336Copyright (c) 2022 James McLean
337Copyright (c) 2014 Little Star Media, Inc. (Joseph Werle)
338
339Permission is hereby granted, free of charge, to any person obtaining a copy
340of this software and associated documentation files (the "Software"), to deal
341in the Software without restriction, including without limitation the rights
342to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
343copies of the Software, and to permit persons to whom the Software is
344furnished to do so, subject to the following conditions:
345
346The above copyright notice and this permission notice shall be included in all
347copies or substantial portions of the Software.
348
349THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
350IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
351FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
352AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
353LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
354OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
355SOFTWARE.
356*/
size_t b64_encode(char *dst, const unsigned char *src, size_t len)
Encodes an array of bytes into a Base64 encoded string (NOTE: A null terminator is not appended)
size_t b64_encoded_size(size_t len)
Returns the Base64 encoded size of an array of bytes (NOTE: This does not include a null terminator)
size_t b64_decode(unsigned char *dst, const char *src, size_t len)
Decodes a Base64 encoded string into an array of bytes (NOTE: A null terminator is not appended)
size_t b64_decoded_size(const char *src, size_t len)
Returns the decoded size of a Base64 string (NOTE: This does not include a null terminator)