]> git.sur5r.net Git - glabels/blob - src/base64.c
Imported Upstream version 2.2.8
[glabels] / src / base64.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2
3 /*
4  *  (GLABELS) Label and Business Card Creation program for GNOME
5  *
6  *  base64.c:  GLabels base64 encode/decode module
7  *
8  *  Copyright (C)  2003  Jim Evins <evins@snaught.com>
9  *
10  *  This module is based on base64.c from fetchmail:
11  *
12  *  Copyright (C)2002 by Eric S. Raymond.
13  *  Portions are copyrighted by Carl E. Harris and George M. Sipe.
14  *
15  *  This program is free software; you can redistribute it and/or modify
16  *  it under the terms of the GNU General Public License as published by
17  *  the Free Software Foundation; either version 2 of the License, or
18  *  (at your option) any later version.
19  *
20  *  This program is distributed in the hope that it will be useful,
21  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
22  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  *  GNU General Public License for more details.
24  *
25  *  You should have received a copy of the GNU General Public License
26  *  along with this program; if not, write to the Free Software
27  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
28  */
29
30 /*
31  * This base 64 encoding is defined in RFC2045 section 6.8.
32  */
33 #include <config.h>
34
35 #include "base64.h"
36
37 #include <glib/gmem.h>
38 #include <ctype.h>
39 #include <string.h>
40
41 /*========================================================*/
42 /* Private macros and constants.                          */
43 /*========================================================*/
44
45 #define LINE_LENGTH 76 /* Must be <= 76 and must be a multiple of 4 */
46 #define BAD     -1
47
48 #define DECODE64(c)  (isascii(c) ? base64val[c] : BAD)
49
50 /*========================================================*/
51 /* Private types.                                         */
52 /*========================================================*/
53
54 /*========================================================*/
55 /* Private globals.                                       */
56 /*========================================================*/
57
58 static const gchar base64digits[] =
59    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
60
61 static const gchar base64val[] = {
62     BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD,
63     BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD,
64     BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD, 62, BAD,BAD,BAD, 63,
65      52, 53, 54, 55,  56, 57, 58, 59,  60, 61,BAD,BAD, BAD,BAD,BAD,BAD,
66     BAD,  0,  1,  2,   3,  4,  5,  6,   7,  8,  9, 10,  11, 12, 13, 14,
67      15, 16, 17, 18,  19, 20, 21, 22,  23, 24, 25,BAD, BAD,BAD,BAD,BAD,
68     BAD, 26, 27, 28,  29, 30, 31, 32,  33, 34, 35, 36,  37, 38, 39, 40,
69      41, 42, 43, 44,  45, 46, 47, 48,  49, 50, 51,BAD, BAD,BAD,BAD,BAD
70 };
71
72 /*========================================================*/
73 /* Private function prototypes.                           */
74 /*========================================================*/
75
76 \f
77 /*****************************************************************************/
78 /* Encode to Base64 string.                                                  */
79 /*****************************************************************************/
80 gchar *
81 gl_base64_encode (const guchar *in, guint inlen)
82 {
83         gchar *out, *p_out;
84         gint   buf_size;
85         gint   i;
86
87         /* Calculate output buffer size */
88         buf_size  = 4*((inlen+2)/3);            /* Encoded characters */
89         buf_size += buf_size / LINE_LENGTH + 2; /* Line breaks */
90         buf_size += 1;                          /* null termination */
91         
92         /* Allocate output buffer */
93         out = g_new0 (gchar, buf_size);
94         p_out=out;
95
96         /* Now do the encoding */
97         *p_out++ = '\n';
98         for ( i=0; inlen >= 3; inlen-=3 ) {
99
100                 *p_out++ = base64digits[in[0] >> 2];
101                 *p_out++ = base64digits[((in[0] << 4) & 0x30) | (in[1] >> 4)];
102                 *p_out++ = base64digits[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
103                 *p_out++ = base64digits[in[2] & 0x3f];
104                 in += 3;
105
106                 i += 4;
107                 if ( (i % LINE_LENGTH) == 0 ) {
108                         *p_out++ = '\n';
109                 }
110
111         }
112         if (inlen > 0) {
113                 guchar fragment;
114     
115                 *p_out++ = base64digits[in[0] >> 2];
116                 fragment = (in[0] << 4) & 0x30;
117                 if (inlen > 1)
118                         fragment |= in[1] >> 4;
119                 *p_out++ = base64digits[fragment];
120                 *p_out++ = (inlen < 2) ? '=' : base64digits[(in[1] << 2) & 0x3c];
121                 *p_out++ = '=';
122
123                 *p_out++ = '\n';
124         }
125         *p_out++ = '\0';
126
127         return out;
128 }
129
130 /*****************************************************************************/
131 /* Decode from a Base64 string.                                              */
132 /*****************************************************************************/
133 guchar *
134 gl_base64_decode (const gchar *in, guint *outlen)
135 {
136         gchar           *out, *p_out;
137         gint             buf_size;
138         register guchar  digit1, digit2, digit3, digit4;
139
140         /* Calculate output buffer size */
141         buf_size = strlen (in) * 3 / 4;
142
143         /* Allocate output buffer */
144         out = g_new0 (gchar, buf_size);
145
146         *outlen = 0;
147         p_out = out;
148
149         /* Skip non-printable characters */
150         while ( (*in == '\n') || (*in == '\r') || (*in == ' ') ) {
151                 in ++;
152         }
153         if (!*in) {
154                 g_free (out);
155                 return NULL;
156         }
157
158         /* Now do the decoding */
159         do {
160                 digit1 = in[0];
161                 if (DECODE64(digit1) == BAD) {
162                         g_free (out);
163                         return NULL;
164                 }
165                 digit2 = in[1];
166                 if (DECODE64(digit2) == BAD) {
167                         g_free (out);
168                         return NULL;
169                 }
170                 digit3 = in[2];
171                 if (digit3 != '=' && DECODE64(digit3) == BAD) {
172                         g_free (out);
173                         return NULL;
174                 }
175                 digit4 = in[3];
176                 if (digit4 != '=' && DECODE64(digit4) == BAD) {
177                         g_free (out);
178                         return NULL;
179                 }
180                 in += 4;
181
182                 *p_out++ = (DECODE64(digit1)<<2) | (DECODE64(digit2) >> 4);
183                 (*outlen)++;
184                 if (digit3 != '=')
185                 {
186                         *p_out++ = ((DECODE64(digit2)<<4)&0xf0) | (DECODE64(digit3)>>2);
187                         (*outlen)++;
188                         if (digit4 != '=')
189                         {
190                                 *p_out++ = ((DECODE64(digit3)<<6)&0xc0) | DECODE64(digit4);
191                                 (*outlen)++;
192                         }
193                 }
194
195                 /* Skip non-printable characters */
196                 while ( (*in == '\n') || (*in == '\r') || (*in == ' ') ) {
197                         in ++;
198                 }
199
200         } while (*in && digit4 != '=');
201
202         return (guchar *)out;
203 }
204