Documentation improvements. (#496518, Stefan Schulze Frielinghaus)
[platform/upstream/glib.git] / glib / gbase64.c
1 /* gbase64.c - Base64 encoding/decoding
2  *
3  *  Copyright (C) 2006 Alexander Larsson <alexl@redhat.com>
4  *  Copyright (C) 2000-2003 Ximian Inc.
5  *
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.
10  *
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.
15  *
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.
20  *
21  * This is based on code in camel, written by:
22  *    Michael Zucchi <notzed@ximian.com>
23  *    Jeffrey Stedfast <fejj@ximian.com>
24  */
25
26 #include "config.h"
27
28 #include <string.h>
29
30 #include "gbase64.h"
31 #include "glib.h"
32 #include "glibintl.h"
33
34 #include "galias.h"
35
36 static const char base64_alphabet[] =
37         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
38
39 /**
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
47  *
48  * Incrementally encode a sequence of binary data into it's 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.
51  *
52  * When all of the data has been converted you must call 
53  * g_base64_encode_close() to flush the saved state.
54  *
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.
59  *
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 of the text on 
62  * the same line. This avoids problems with long lines in the email system.
63  *
64  * Return value: The number of bytes of output that was written
65  *
66  * Since: 2.12
67  */
68 gsize
69 g_base64_encode_step (const guchar *in, 
70                       gsize         len, 
71                       gboolean      break_lines, 
72                       gchar        *out, 
73                       gint         *state, 
74                       gint         *save)
75 {
76   char *outptr;
77   const guchar *inptr;
78   
79   g_return_val_if_fail (in != NULL, 0);
80   g_return_val_if_fail (out != NULL, 0);
81   g_return_val_if_fail (state != NULL, 0);
82   g_return_val_if_fail (save != NULL, 0);
83
84   if (len <= 0)
85     return 0;
86   
87   inptr = in;
88   outptr = out;
89   
90   if (len + ((char *) save) [0] > 2)
91     {
92       const guchar *inend = in+len-2;
93       int c1, c2, c3;
94       int already;
95       
96       already = *state;
97       
98       switch (((char *) save) [0])
99         {       
100         case 1: 
101           c1 = ((unsigned char *) save) [1]; 
102           goto skip1;
103         case 2: 
104           c1 = ((unsigned char *) save) [1];
105           c2 = ((unsigned char *) save) [2]; 
106           goto skip2;
107         }
108       
109       /* 
110        * yes, we jump into the loop, no i'm not going to change it, 
111        * it's beautiful! 
112        */
113       while (inptr < inend)
114         {
115           c1 = *inptr++;
116         skip1:
117           c2 = *inptr++;
118         skip2:
119           c3 = *inptr++;
120           *outptr++ = base64_alphabet [ c1 >> 2 ];
121           *outptr++ = base64_alphabet [ c2 >> 4 | 
122                                         ((c1&0x3) << 4) ];
123           *outptr++ = base64_alphabet [ ((c2 &0x0f) << 2) | 
124                                         (c3 >> 6) ];
125           *outptr++ = base64_alphabet [ c3 & 0x3f ];
126           /* this is a bit ugly ... */
127           if (break_lines && (++already) >= 19)
128             {
129               *outptr++ = '\n';
130               already = 0;
131             }
132         }
133       
134       ((char *)save)[0] = 0;
135       len = 2 - (inptr - inend);
136       *state = already;
137     }
138   
139   if (len>0)
140     {
141       char *saveout;
142       
143       /* points to the slot for the next char to save */
144       saveout = & (((char *)save)[1]) + ((char *)save)[0];
145       
146       /* len can only be 0 1 or 2 */
147       switch(len)
148         {
149         case 2: *saveout++ = *inptr++;
150         case 1: *saveout++ = *inptr++;
151         }
152       ((char *)save)[0] += len;
153     }
154   
155   return outptr - out;
156 }
157
158 /**
159  * g_base64_encode_close:
160  * @break_lines: whether to break long lines
161  * @out: pointer to destination buffer
162  * @state: Saved state from g_base64_encode_step()
163  * @save: Saved state from g_base64_encode_step()
164  *
165  * Flush the status from a sequence of calls to g_base64_encode_step().
166  *
167  * Return value: The number of bytes of output that was written
168  *
169  * Since: 2.12
170  */
171 gsize
172 g_base64_encode_close (gboolean  break_lines,
173                        gchar    *out, 
174                        gint     *state, 
175                        gint     *save)
176 {
177   int c1, c2;
178   char *outptr = out;
179
180   g_return_val_if_fail (out != NULL, 0);
181   g_return_val_if_fail (state != NULL, 0);
182   g_return_val_if_fail (save != NULL, 0);
183
184   c1 = ((unsigned char *) save) [1];
185   c2 = ((unsigned char *) save) [2];
186   
187   switch (((char *) save) [0])
188     {
189     case 2:
190       outptr [2] = base64_alphabet[ ( (c2 &0x0f) << 2 ) ];
191       g_assert (outptr [2] != 0);
192       goto skip;
193     case 1:
194       outptr[2] = '=';
195     skip:
196       outptr [0] = base64_alphabet [ c1 >> 2 ];
197       outptr [1] = base64_alphabet [ c2 >> 4 | ( (c1&0x3) << 4 )];
198       outptr [3] = '=';
199       outptr += 4;
200       break;
201     }
202   if (break_lines)
203     *outptr++ = '\n';
204   
205   *save = 0;
206   *state = 0;
207   
208   return outptr - out;
209 }
210
211 /**
212  * g_base64_encode:
213  * @data: the binary data to encode
214  * @len: the length of @data
215  *
216  * Encode a sequence of binary data into its Base-64 stringified
217  * representation.
218  *
219  * Return value: a newly allocated, zero-terminated Base-64 encoded
220  *               string representing @data. The returned string must 
221  *               be freed with g_free().
222  *
223  * Since: 2.12
224  */
225 gchar *
226 g_base64_encode (const guchar *data, 
227                  gsize         len)
228 {
229   gchar *out;
230   gint state = 0, outlen;
231   gint save = 0;
232
233   g_return_val_if_fail (data != NULL, NULL);
234   g_return_val_if_fail (len > 1, NULL);
235
236   /* We can use a smaller limit here, since we know the saved state is 0 */
237   out = g_malloc (len * 4 / 3 + 4);
238   outlen = g_base64_encode_step (data, len, FALSE, out, &state, &save);
239   outlen += g_base64_encode_close (FALSE,
240                                    out + outlen, 
241                                    &state, 
242                                    &save);
243   out[outlen] = '\0';
244   return (gchar *) out;
245 }
246
247 static const unsigned char mime_base64_rank[256] = {
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, 62,255,255,255, 63,
251    52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255,  0,255,255,
252   255,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
253    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255,
254   255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
255    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255,
256   255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
257   255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
258   255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
259   255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
260   255,255,255,255,255,255,255,255,255,255,255,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 };
265
266 /**
267  * g_base64_decode_step: 
268  * @in: binary input data
269  * @len: max length of @in data to decode
270  * @out: output buffer
271  * @state: Saved state between steps, initialize to 0
272  * @save: Saved state between steps, initialize to 0
273  *
274  * Incrementally decode a sequence of binary data from its Base-64 stringified
275  * representation. By calling this function multiple times you can convert 
276  * data in chunks to avoid having to have the full encoded data in memory.
277  *
278  * The output buffer must be large enough to fit all the data that will
279  * be written to it. Since base64 encodes 3 bytes in 4 chars you need
280  * at least: @len * 3 / 4 bytes.
281  * 
282  * Return value: The number of bytes of output that was written
283  *
284  * Since: 2.12
285  **/
286 gsize
287 g_base64_decode_step (const gchar  *in, 
288                       gsize         len, 
289                       guchar       *out, 
290                       gint         *state, 
291                       guint        *save)
292 {
293   const guchar *inptr;
294   guchar *outptr;
295   const guchar *inend;
296   guchar c, rank;
297   guchar last[2];
298   unsigned int v;
299   int i;
300
301   g_return_val_if_fail (in != NULL, 0);
302   g_return_val_if_fail (out != NULL, 0);
303   g_return_val_if_fail (state != NULL, 0);
304   g_return_val_if_fail (save != NULL, 0);
305
306   if (len <= 0)
307     return 0;
308   
309   inend = (const guchar *)in+len;
310   outptr = out;
311   
312   /* convert 4 base64 bytes to 3 normal bytes */
313   v=*save;
314   i=*state;
315   inptr = (const guchar *)in;
316   last[0] = last[1] = 0;
317   while (inptr < inend)
318     {
319       c = *inptr++;
320       rank = mime_base64_rank [c];
321       if (rank != 0xff)
322         {
323           last[1] = last[0];
324           last[0] = c;
325           v = (v<<6) | rank;
326           i++;
327           if (i==4)
328             {
329               *outptr++ = v>>16;
330               if (last[1] != '=')
331                 *outptr++ = v>>8;
332               if (last[0] != '=')
333                 *outptr++ = v;
334               i=0;
335             }
336         }
337     }
338   
339   *save = v;
340   *state = i;
341   
342   return outptr - out;
343 }
344
345 /**
346  * g_base64_decode:
347  * @text: zero-terminated string with base64 text to decode
348  * @out_len: The length of the decoded data is written here
349  *
350  * Decode a sequence of Base-64 encoded text into binary data
351  *
352  * Return value: a newly allocated buffer containing the binary data
353  *               that @text represents. The returned buffer must
354  *               be freed with g_free().
355  *
356  * Since: 2.12
357  */
358 guchar *
359 g_base64_decode (const gchar *text,
360                  gsize       *out_len)
361 {
362   guchar *ret;
363   gint input_length, state = 0;
364   guint save = 0;
365   
366   g_return_val_if_fail (text != NULL, NULL);
367   g_return_val_if_fail (out_len != NULL, NULL);
368
369   input_length = strlen (text);
370
371   g_return_val_if_fail (input_length > 1, NULL);
372
373   ret = g_malloc0 (input_length * 3 / 4);
374   
375   *out_len = g_base64_decode_step (text, input_length, ret, &state, &save);
376   
377   return ret; 
378 }
379
380 #define __G_BASE64_C__
381 #include "galiasdef.c"