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 it's Base-64 stringified
49 * representation. By calling this functions multiple times you can convert data
50 * in chunks to avoid having to have the full encoded data in memory.
52 * When all the data has been converted you must call g_base64_encode_close()
53 * 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 * 4 / 3 + 6 bytes. If you enable line-breaking you will
58 * need at least: @len * 4 / 3 + @len * 4 / (3 * 72) + 7 bytes.
60 * @break_lines is typically used when putting base64-encoded data in emails.
61 * It breaks the lines at 72 columns instead of putting all text on the same
62 * line. This avoids problems with long lines in the email system.
64 * Return value: The number of bytes of output that was written
69 g_base64_encode_step (const guchar *in,
85 if (len + ((char *) save) [0] > 2)
87 const guchar *inend = in+len-2;
93 switch (((char *) save) [0])
96 c1 = ((unsigned char *) save) [1];
99 c1 = ((unsigned char *) save) [1];
100 c2 = ((unsigned char *) save) [2];
105 * yes, we jump into the loop, no i'm not going to change it,
108 while (inptr < inend)
115 *outptr++ = base64_alphabet [ c1 >> 2 ];
116 *outptr++ = base64_alphabet [ c2 >> 4 |
118 *outptr++ = base64_alphabet [ ((c2 &0x0f) << 2) |
120 *outptr++ = base64_alphabet [ c3 & 0x3f ];
121 /* this is a bit ugly ... */
122 if (break_lines && (++already) >= 19)
129 ((char *)save)[0] = 0;
130 len = 2 - (inptr - inend);
138 /* points to the slot for the next char to save */
139 saveout = & (((char *)save)[1]) + ((char *)save)[0];
141 /* len can only be 0 1 or 2 */
144 case 2: *saveout++ = *inptr++;
145 case 1: *saveout++ = *inptr++;
147 ((char *)save)[0] += len;
154 * g_base64_encode_close:
155 * @break_lines: whether to break long lines
156 * @out: pointer to destination buffer
157 * @state: Saved state from g_base64_encode_step()
158 * @save: Saved state from g_base64_encode_step()
160 * Flush the status from a sequence of calls to g_base64_encode_step().
162 * Return value: The number of bytes of output that was written
167 g_base64_encode_close (gboolean break_lines,
175 c1 = ((unsigned char *) save) [1];
176 c2 = ((unsigned char *) save) [2];
178 switch (((char *) save) [0])
181 outptr [2] = base64_alphabet[ ( (c2 &0x0f) << 2 ) ];
182 g_assert (outptr [2] != 0);
187 outptr [0] = base64_alphabet [ c1 >> 2 ];
188 outptr [1] = base64_alphabet [ c2 >> 4 | ( (c1&0x3) << 4 )];
204 * @data: the binary data to encode.
205 * @len: the length of @data.
207 * Encode a sequence of binary data into it's Base-64 stringified
210 * Return value: a newly allocated, zero-terminated Base-64 encoded
211 * string representing @data.
216 g_base64_encode (const guchar *data,
220 gint state = 0, outlen;
223 /* We can use a smaller limit here, since we know the saved state is 0 */
224 out = g_malloc (len * 4 / 3 + 4);
225 outlen = g_base64_encode_step (data, len, FALSE, out, &state, &save);
226 outlen += g_base64_encode_close (FALSE,
231 return (gchar *) out;
234 static const unsigned char mime_base64_rank[256] = {
235 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
236 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
237 255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63,
238 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255, 0,255,255,
239 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
240 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255,
241 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
242 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255,
243 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
244 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
245 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
246 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
247 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
248 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
249 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
250 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
254 * g_base64_decode_step:
255 * @in: binary input data
256 * @len: max length of @in data to decode
257 * @out: output buffer
258 * @state: Saved state between steps, initialize to 0
259 * @save: Saved state between steps, initialize to 0
261 * Incrementally decode a sequence of binary data from it's Base-64 stringified
262 * representation. By calling this functions multiple times you can convert data
263 * in chunks to avoid having to have the full encoded data in memory.
265 * The output buffer must be large enough to fit all the data that will
266 * be written to it. Since base64 encodes 3 bytes in 4 chars you need
267 * at least: @len * 3 / 4 bytes.
269 * Return value: The number of bytes of output that was written
274 g_base64_decode_step (const gchar *in,
287 inend = (const guchar *)in+len;
290 /* convert 4 base64 bytes to 3 normal bytes */
293 inptr = (const guchar *)in;
294 while (inptr < inend)
296 c = mime_base64_rank [*inptr++];
314 /* quick scan back for '=' on the end somewhere */
315 /* fortunately we can drop 1 output char for each trailing = (upto 2) */
317 while (inptr > (const guchar *)in && i)
320 if (mime_base64_rank [*inptr] != 0xff)
328 /* if i!= 0 then there is a truncation error! */
334 * @text: zero-terminated string with base64 text to decode.
335 * @out_len: The lenght of the decoded data is written here.
337 * Decode a sequence of Base-64 encoded text into binary data
339 * Return value: a newly allocated, buffer containing the binary data
340 * that @text represents
345 g_base64_decode (const gchar *text,
349 gint inlen, state = 0;
352 inlen = strlen (text);
353 ret = g_malloc0 (inlen * 3 / 4);
355 *out_len = g_base64_decode_step (text, inlen, ret, &state, &save);
360 #define __G_BASE64_C__
361 #include "galiasdef.c"