collect.c: fix compiler warnings..
[s-mailx.git] / base64.c
blob83f657e59e83610c89a322139ed1e9a2783eaa62
1 /*
2 * Heirloom mailx - a mail user agent derived from Berkeley Mail.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 Steffen "Daode" Nurpmeso.
6 */
7 /*
8 * These base64 routines are derived from the metamail-2.7 sources which
9 * state the following copyright notice:
11 * Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)
13 * Permission to use, copy, modify, and distribute this material
14 * for any purpose and without fee is hereby granted, provided
15 * that the above copyright notice and this permission notice
16 * appear in all copies, and that the name of Bellcore not be
17 * used in advertising or publicity pertaining to this
18 * material without the specific, prior written permission
19 * of an authorized representative of Bellcore. BELLCORE
20 * MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY
21 * OF THIS MATERIAL FOR ANY PURPOSE. IT IS PROVIDED "AS IS",
22 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
25 #ifndef lint
26 #ifdef DOSCCS
27 static char sccsid[] = "@(#)base64.c 2.14 (gritter) 4/21/06";
28 #endif
29 #endif /* not lint */
32 * Mail -- a mail program
34 * base64 functions
37 #include "rcv.h"
38 #include "extern.h"
40 static const char b64table[] =
41 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
42 static const signed char b64index[] = {
43 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
44 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
45 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
46 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
47 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
48 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
49 -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
50 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
53 #define char64(c) ((c) < 0 ? -1 : b64index[(int)(c)])
55 static signed char *ctob64(unsigned char *p, int pad);
58 * Convert three characters to base64.
60 static signed char *
61 ctob64(unsigned char *p, int pad)
63 static signed char b64[4];
65 b64[0] = b64table[p[0] >> 2];
66 b64[1] = b64table[((p[0] & 0x3) << 4) | ((p[1] & 0xF0) >> 4)];
67 if (pad == 2) {
68 b64[1] = b64table[(p[0] & 0x3) << 4];
69 b64[2] = b64[3] = '=';
70 } else if (pad == 1) {
71 b64[2] = b64table[((p[1] & 0xF) << 2)];
72 b64[3] = '=';
73 } else {
74 b64[2] = b64table[((p[1] & 0xF) << 2) | ((p[2] & 0xC0) >> 6)];
75 b64[3] = b64table[p[2] & 0x3F];
77 return b64;
80 char *
81 strtob64(const char *p)
83 return memtob64(p, strlen(p));
86 char *
87 memtob64(const void *vp, size_t isz)
89 char q[3];
90 const char *p = vp;
91 signed char *h;
92 size_t c = 0;
93 int i, l = 0, sz = 0, pads;
94 char *rs = NULL;
96 if (isz == 0) {
97 rs = smalloc(1);
98 *rs = '\0';
99 return rs;
101 do {
102 for (pads = 2, i = 0; i <= 2; i++, pads--) {
103 q[i] = p[c++];
104 if (c == isz)
105 break;
107 h = ctob64((unsigned char *)q, pads);
108 if (l + 5 >= sz)
109 rs = srealloc(rs, sz = l + 100);
110 for (i = 0; i < 4; i++)
111 rs[l++] = h[i];
112 } while (c < isz);
113 rs[l] = '\0';
114 return rs;
118 * Write to a file converting to base64. The input must be aligned
119 * e.g. at 972 character bounds.
121 size_t
122 mime_write_tob64(struct str *in, FILE *fo, int is_header)
124 char *p, *upper, q[3];
125 signed char *h;
126 int i, l, pads;
127 size_t sz;
129 sz = 0;
130 upper = in->s + in->l;
131 for (p = in->s, l = 0; p < upper; ) {
132 for (pads = 2, i = 0; i <= 2; i++, pads--) {
133 q[i] = *p++;
134 if (p == upper)
135 break;
137 h = ctob64((unsigned char *)q, pads);
138 fwrite(h, sizeof(char), 4, fo);
139 sz += 4, l += 4;
140 if (l >= 71) {
141 putc('\n', fo), sz++;
142 l = 0;
145 if (l != 0 && !is_header) {
146 putc('\n', fo), sz++;
148 return sz;
152 * Decode from base64.
154 void
155 mime_fromb64(struct str *in, struct str *out, int is_text)
157 char *p, *q, *upper;
158 signed char c, d, e, f, g;
159 int done = 0, newline = 0;
161 out->s = smalloc(in->l * 3 / 4 + 2);
162 out->l = 0;
163 upper = in->s + in->l;
164 for (p = in->s, q = out->s; p < upper; ) {
165 while (c = *p++, whitechar(c));
166 if (p >= upper) break;
167 if (done) continue;
168 while (d = *p++, whitechar(d));
169 if (p >= upper) break;
170 while (e = *p++, whitechar(e));
171 if (p >= upper) break;
172 while (f = *p++, whitechar(f));
173 if (c == '=' || d == '=') {
174 done = 1;
175 continue;
177 c = char64(c);
178 d = char64(d);
179 g = ((c << 2) | ((d & 0x30) >> 4));
180 if (is_text) {
181 if (g == '\r') {
182 newline = 1;
183 } else if (g == '\n' && newline) {
184 q--;
185 out->l--;
186 newline = 0;
187 } else {
188 newline = 0;
191 *q++ = g;
192 out->l++;
193 if (e == '=') {
194 done = 1;
195 } else {
196 e = char64(e);
197 g = (((d & 0xF) << 4) | ((e & 0x3C) >> 2));
198 if (is_text) {
199 if (g == '\r') {
200 newline = 1;
201 } else if (g == '\n' && newline) {
202 q--;
203 out->l--;
204 newline = 0;
205 } else {
206 newline = 0;
209 *q++ = g;
210 out->l++;
211 if (f == '=') {
212 done = 1;
213 } else {
214 f = char64(f);
215 g = (((e & 0x03) << 6) | f);
216 if (is_text) {
217 if (g == '\r') {
218 newline = 1;
219 } else if (g == '\n' && newline) {
220 q--;
221 out->l--;
222 newline = 0;
223 } else {
224 newline = 0;
227 *q++ = g;
228 out->l++;
232 return;
236 * Buffer the base64 input so mime_fromb64 gets always multiples of
237 * 4 characters.
238 * As we have only one buffer, this function is not reentrant.
240 void
241 mime_fromb64_b(struct str *in, struct str *out, int is_text, FILE *f)
243 static signed char b[4];
244 static size_t n;
245 static FILE *f_b = (FILE *)-1;
246 signed char c;
247 size_t i;
248 struct str nin;
250 nin.s = smalloc(in->l + n);
251 if (n != 0 && f_b == f) {
252 for (nin.l = 0; nin.l < n; nin.l++)
253 nin.s[nin.l] = b[nin.l];
254 } else {
255 nin.l = 0;
256 n = 0;
259 for (i = 0; i <= in->l; i++) {
260 c = in->s[i];
261 if (char64(c) == -1 && c != '=')
262 continue;
263 b[n] = nin.s[nin.l++] = c;
264 if (n >= 3)
265 n = 0;
266 else
267 n++;
269 nin.l -= n;
270 mime_fromb64(&nin, out, is_text);
271 free(nin.s);
272 f_b = f;