1 /* This program is free software; you can redistribute it and/or modify it
2 * under the terms of the GNU General Public License as published by the Free
3 * Software Foundation; either version 2 of the License, or (at your option) any
6 * This program is distributed in the hope that it will be useful, but WITHOUT
7 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
8 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11 * You should have received a copy of the GNU General Public License along with
12 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
13 * Place - Suite 330, Boston, MA 02111-1307, USA.
15 * Adapted from code written by Eric S. Raymond <esr@snark.thyrsus.com>
19 /* Pair of functions to convert to/from base64.
20 * Also can be used to build a standalone utility and a loopback test.
21 * see http://www.faqs.org/rfcs/rfc3548.html
27 static const char base64digits
[] =
28 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
31 static const char base64val
[] = {
32 BAD
,BAD
,BAD
,BAD
, BAD
,BAD
,BAD
,BAD
, BAD
,BAD
,BAD
,BAD
, BAD
,BAD
,BAD
,BAD
,
33 BAD
,BAD
,BAD
,BAD
, BAD
,BAD
,BAD
,BAD
, BAD
,BAD
,BAD
,BAD
, BAD
,BAD
,BAD
,BAD
,
34 BAD
,BAD
,BAD
,BAD
, BAD
,BAD
,BAD
,BAD
, BAD
,BAD
,BAD
, 62, BAD
,BAD
,BAD
, 63,
35 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,BAD
,BAD
, BAD
,BAD
,BAD
,BAD
,
36 BAD
, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
37 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,BAD
, BAD
,BAD
,BAD
,BAD
,
38 BAD
, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
39 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,BAD
, BAD
,BAD
,BAD
,BAD
41 #define DECODE64(c) (isascii(c) ? base64val[c] : BAD)
43 /* convert inlen raw bytes at in to base64 string (NUL-terminated) at out.
44 * out size should be at least 4*inlen/3 + 4.
45 * return length of out (sans trailing NUL).
48 to64frombits(unsigned char *out
, const unsigned char *in
, int inlen
)
50 unsigned char *out0
= out
;
52 for (; inlen
>= 3; inlen
-= 3)
54 *out
++ = base64digits
[in
[0] >> 2];
55 *out
++ = base64digits
[((in
[0] << 4) & 0x30) | (in
[1] >> 4)];
56 *out
++ = base64digits
[((in
[1] << 2) & 0x3c) | (in
[2] >> 6)];
57 *out
++ = base64digits
[in
[2] & 0x3f];
62 unsigned char fragment
;
64 *out
++ = base64digits
[in
[0] >> 2];
65 fragment
= (in
[0] << 4) & 0x30;
67 fragment
|= in
[1] >> 4;
68 *out
++ = base64digits
[fragment
];
69 *out
++ = (inlen
< 2) ? '=' : base64digits
[(in
[1] << 2) & 0x3c];
77 /* convert base64 at in to raw bytes out, returning count or <0 on error.
78 * base64 may contain any embedded whitespace.
79 * out should be at least 3/4 the length of in.
82 from64tobits(char *out
, const char *in
)
85 register unsigned char digit1
, digit2
, digit3
, digit4
;
88 do {digit1
= *in
++;} while (isspace(digit1
));
89 if (DECODE64(digit1
) == BAD
)
91 do {digit2
= *in
++;} while (isspace(digit2
));
92 if (DECODE64(digit2
) == BAD
)
94 do {digit3
= *in
++;} while (isspace(digit3
));
95 if (digit3
!= '=' && DECODE64(digit3
) == BAD
)
97 do {digit4
= *in
++;} while (isspace(digit4
));
98 if (digit4
!= '=' && DECODE64(digit4
) == BAD
)
100 *out
++ = (DECODE64(digit1
) << 2) | (DECODE64(digit2
) >> 4);
104 *out
++ = ((DECODE64(digit2
) << 4) & 0xf0) | (DECODE64(digit3
) >> 2);
108 *out
++ = ((DECODE64(digit3
) << 6) & 0xc0) | DECODE64(digit4
);
114 } while (*in
&& digit4
!= '=');
119 #ifdef BASE64_PROGRAM
120 /* standalone program that converts to/from base64.
121 * cc -o base64 -DBASE64_PROGRAM base64.c
131 fprintf (stderr
, "Purpose: convert stdin to/from base64 on stdout\n");
132 fprintf (stderr
, "Usage: %s {-t,-f}\n", me
);
137 main (int ac
, char *av
[])
141 /* decide whether to or from base64 */
142 if (ac
== 2 && strcmp (av
[1], "-f") == 0)
144 else if (ac
!= 1 && (ac
!= 2 || strcmp (av
[1], "-t")))
148 unsigned char *rawin
, *b64
;
149 int i
, n
, nrawin
, nb64
;
151 /* read raw on stdin until EOF */
152 rawin
= malloc(4096);
154 while ((n
= fread (rawin
+nrawin
, 1, 4096, stdin
)) > 0)
155 rawin
= realloc (rawin
, (nrawin
+=n
)+4096);
157 /* convert to base64 */
158 b64
= malloc (4*nrawin
/3+4);
159 nb64
= to64frombits(b64
, rawin
, nrawin
);
162 for (i
= 0; i
< nb64
; i
+= 72)
163 printf ("%.*s\n", 72, b64
+i
);
165 unsigned char *raw
, *b64
;
168 /* read base64 on stdin until EOF */
171 while ((n
= fread (b64
+nb64
, 1, 4096, stdin
)) > 0)
172 b64
= realloc (b64
, (nb64
+=n
)+4096);
176 raw
= malloc (3*nb64
/4);
177 nraw
= from64tobits(raw
, b64
);
179 fprintf (stderr
, "base64 conversion error: %d\n", nraw
);
184 fwrite (raw
, 1, nraw
, stdout
);
193 /* standalone test that reads binary on stdin, converts to base64 and back,
194 * then compares. exit 0 if compares the same else 1
202 main (int ac
, char *av
[])
204 unsigned char *rawin
, *b64
, *rawback
;
205 int n
, nrawin
, nrawback
, nb64
;
207 /* read raw on stdin until EOF */
208 rawin
= malloc(4096);
210 while ((n
= fread (rawin
+nrawin
, 1, 4096, stdin
)) > 0)
211 rawin
= realloc (rawin
, (nrawin
+=n
)+4096);
213 /* convert to base64 */
214 b64
= malloc (4*nrawin
*3 + 4);
215 nb64
= to64frombits(b64
, rawin
, nrawin
);
217 /* convert back to raw */
218 rawback
= malloc (3*nb64
/4);
219 nrawback
= from64tobits(rawback
, b64
);
221 fprintf (stderr
, "base64 error: %d\n", nrawback
);
224 if (nrawback
!= nrawin
) {
225 fprintf (stderr
, "base64 back length %d != %d\n", nrawback
, nrawin
);
230 if (memcmp (rawback
, rawin
, nrawin
)) {
231 fprintf (stderr
, "compare error\n");
239 /* For RCS Only -- Do Not Edit */
240 static char *rcsid
[2] = {(char *)rcsid
, "@(#) $RCSfile$ $Date$ $Revision$ $Name: $"};