1 /* gbase64.c - Base64 encoding/decoding
3 * Copyright (C) 2006 Alexander Larsson <alexl@redhat.com>
4 * Copyright (C) 2000-2003 Ximian Inc.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
21 * This is based on code in camel, written by:
22 * Michael Zucchi <notzed@ximian.com>
23 * Jeffrey Stedfast <fejj@ximian.com>
36 static const char base64_alphabet[] =
37 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
40 * g_base64_encode_step:
41 * @in: the binary data to encode
42 * @len: the length of @in
43 * @break_lines: whether to break long lines
44 * @out: pointer to destination buffer
45 * @state: Saved state between steps, initialize to 0
46 * @save: Saved state between steps, initialize to 0
48 * Incrementally encode a sequence of binary data into its Base-64 stringified
49 * representation. By calling this function multiple times you can convert
50 * data in chunks to avoid having to have the full encoded data in memory.
52 * When all of the data has been converted you must call
53 * g_base64_encode_close() to flush the saved state.
55 * The output buffer must be large enough to fit all the data that will
56 * be written to it. Due to the way base64 encodes you will need
57 * at least: (@len / 3 + 1) * 4 + 4 bytes (+ 4 may be needed in case of
58 * non-zero state). If you enable line-breaking you will need at least:
59 * ((@len / 3 + 1) * 4 + 4) / 72 + 1 bytes of extra space.
61 * @break_lines is typically used when putting base64-encoded data in emails.
62 * It breaks the lines at 72 columns instead of putting all of the text on
63 * the same line. This avoids problems with long lines in the email system.
65 * Return value: The number of bytes of output that was written
70 g_base64_encode_step (const guchar *in,
80 g_return_val_if_fail (in != NULL, 0);
81 g_return_val_if_fail (out != NULL, 0);
82 g_return_val_if_fail (state != NULL, 0);
83 g_return_val_if_fail (save != NULL, 0);
91 if (len + ((char *) save) [0] > 2)
93 const guchar *inend = in+len-2;
99 switch (((char *) save) [0])
102 c1 = ((unsigned char *) save) [1];
105 c1 = ((unsigned char *) save) [1];
106 c2 = ((unsigned char *) save) [2];
111 * yes, we jump into the loop, no i'm not going to change it,
114 while (inptr < inend)
121 *outptr++ = base64_alphabet [ c1 >> 2 ];
122 *outptr++ = base64_alphabet [ c2 >> 4 |
124 *outptr++ = base64_alphabet [ ((c2 &0x0f) << 2) |
126 *outptr++ = base64_alphabet [ c3 & 0x3f ];
127 /* this is a bit ugly ... */
128 if (break_lines && (++already) >= 19)
135 ((char *)save)[0] = 0;
136 len = 2 - (inptr - inend);
144 /* points to the slot for the next char to save */
145 saveout = & (((char *)save)[1]) + ((char *)save)[0];
147 /* len can only be 0 1 or 2 */
150 case 2: *saveout++ = *inptr++;
151 case 1: *saveout++ = *inptr++;
153 ((char *)save)[0] += len;
160 * g_base64_encode_close:
161 * @break_lines: whether to break long lines
162 * @out: pointer to destination buffer
163 * @state: Saved state from g_base64_encode_step()
164 * @save: Saved state from g_base64_encode_step()
166 * Flush the status from a sequence of calls to g_base64_encode_step().
168 * Return value: The number of bytes of output that was written
173 g_base64_encode_close (gboolean break_lines,
181 g_return_val_if_fail (out != NULL, 0);
182 g_return_val_if_fail (state != NULL, 0);
183 g_return_val_if_fail (save != NULL, 0);
185 c1 = ((unsigned char *) save) [1];
186 c2 = ((unsigned char *) save) [2];
188 switch (((char *) save) [0])
191 outptr [2] = base64_alphabet[ ( (c2 &0x0f) << 2 ) ];
192 g_assert (outptr [2] != 0);
197 outptr [0] = base64_alphabet [ c1 >> 2 ];
198 outptr [1] = base64_alphabet [ c2 >> 4 | ( (c1&0x3) << 4 )];
214 * @data: the binary data to encode
215 * @len: the length of @data
217 * Encode a sequence of binary data into its Base-64 stringified
220 * Return value: a newly allocated, zero-terminated Base-64 encoded
221 * string representing @data. The returned string must
222 * be freed with g_free().
227 g_base64_encode (const guchar *data,
231 gint state = 0, outlen;
234 g_return_val_if_fail (data != NULL, NULL);
235 g_return_val_if_fail (len > 0, NULL);
237 /* We can use a smaller limit here, since we know the saved state is 0,
238 +1 is needed for trailing \0, also check for unlikely integer overflow */
239 if (len >= ((G_MAXSIZE - 1) / 4 - 1) * 3)
240 g_error("%s: input too large for Base64 encoding (%"G_GSIZE_FORMAT" chars)",
243 out = g_malloc ((len / 3 + 1) * 4 + 1);
245 outlen = g_base64_encode_step (data, len, FALSE, out, &state, &save);
246 outlen += g_base64_encode_close (FALSE, out + outlen, &state, &save);
249 return (gchar *) out;
252 static const unsigned char mime_base64_rank[256] = {
253 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
254 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255 255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63,
256 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255, 0,255,255,
257 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
258 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255,
259 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
260 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255,
261 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
262 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
263 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
264 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
265 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
266 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
267 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
268 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
272 * g_base64_decode_step:
273 * @in: binary input data
274 * @len: max length of @in data to decode
275 * @out: output buffer
276 * @state: Saved state between steps, initialize to 0
277 * @save: Saved state between steps, initialize to 0
279 * Incrementally decode a sequence of binary data from its Base-64 stringified
280 * representation. By calling this function multiple times you can convert
281 * data in chunks to avoid having to have the full encoded data in memory.
283 * The output buffer must be large enough to fit all the data that will
284 * be written to it. Since base64 encodes 3 bytes in 4 chars you need
285 * at least: (@len / 4) * 3 + 3 bytes (+ 3 may be needed in case of non-zero
288 * Return value: The number of bytes of output that was written
293 g_base64_decode_step (const gchar *in,
307 g_return_val_if_fail (in != NULL, 0);
308 g_return_val_if_fail (out != NULL, 0);
309 g_return_val_if_fail (state != NULL, 0);
310 g_return_val_if_fail (save != NULL, 0);
315 inend = (const guchar *)in+len;
318 /* convert 4 base64 bytes to 3 normal bytes */
321 inptr = (const guchar *)in;
322 last[0] = last[1] = 0;
323 while (inptr < inend)
326 rank = mime_base64_rank [c];
353 * @text: zero-terminated string with base64 text to decode
354 * @out_len: The length of the decoded data is written here
356 * Decode a sequence of Base-64 encoded text into binary data
358 * Return value: a newly allocated buffer containing the binary data
359 * that @text represents. The returned buffer must
360 * be freed with g_free().
365 g_base64_decode (const gchar *text,
373 g_return_val_if_fail (text != NULL, NULL);
374 g_return_val_if_fail (out_len != NULL, NULL);
376 input_length = strlen (text);
378 g_return_val_if_fail (input_length > 1, NULL);
380 /* We can use a smaller limit here, since we know the saved state is 0,
381 +1 used to avoid calling g_malloc0(0), and hence retruning NULL */
382 ret = g_malloc0 ((input_length / 4) * 3 + 1);
384 *out_len = g_base64_decode_step (text, input_length, ret, &state, &save);
390 * g_base64_decode_inplace:
391 * @text: zero-terminated string with base64 text to decode
392 * @out_len: The length of the decoded data is written here
394 * Decode a sequence of Base-64 encoded text into binary data
395 * by overwriting the input data.
397 * Return value: The binary data that @text responds. This pointer
398 * is the same as the input @text.
403 g_base64_decode_inplace (gchar *text,
406 gint input_length, state = 0;
409 g_return_val_if_fail (text != NULL, NULL);
410 g_return_val_if_fail (out_len != NULL, NULL);
412 input_length = strlen (text);
414 g_return_val_if_fail (input_length > 1, NULL);
416 *out_len = g_base64_decode_step (text, input_length, (guchar *) text, &state, &save);
422 #define __G_BASE64_C__
423 #include "galiasdef.c"