]> diplodocus.org Git - nmh/blob - sbr/base64.c
Remove mhbuild backup files at end of a couple of tests, if successful.
[nmh] / sbr / base64.c
1 /*
2 * base64.c -- routines for converting to base64
3 *
4 * This code is Copyright (c) 2012, by the authors of nmh. See the
5 * COPYRIGHT file in the root directory of the nmh distribution for
6 * complete copyright information.
7 */
8
9 #include <h/mh.h>
10 #include <h/mime.h>
11
12 static char nib2b64[0x40+1] =
13 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
14
15 int
16 writeBase64aux (FILE *in, FILE *out, int crlf)
17 {
18 unsigned int cc, n;
19 unsigned char inbuf[3];
20 int skipnl = 0;
21
22 n = BPERLIN;
23 while ((cc = fread (inbuf, sizeof(*inbuf), sizeof(inbuf), in)) > 0) {
24 unsigned long bits;
25 char *bp;
26 char outbuf[4];
27
28 if (cc < sizeof(inbuf)) {
29 inbuf[2] = 0;
30 if (cc < sizeof(inbuf) - 1)
31 inbuf[1] = 0;
32 }
33
34 /*
35 * Convert a LF to a CRLF if desired. That means we need to push
36 * data back into the input stream.
37 */
38
39 if (crlf) {
40 unsigned int i;
41
42 for (i = 0; i < cc; i++) {
43 if (inbuf[i] == '\n' && !skipnl) {
44 inbuf[i] = '\r';
45 /*
46 * If it's the last character in the buffer, we can just
47 * substitute a \r and push a \n back. Otherwise shuffle
48 * everything down and push the last character back.
49 */
50 if (i == cc - 1) {
51 /*
52 * If we're at the end of the input, there might be
53 * more room in inbuf; if so, add it there. Otherwise
54 * push it back to the input.
55 */
56 if (cc < sizeof(inbuf))
57 inbuf[cc++] = '\n';
58 else
59 ungetc('\n', in);
60 skipnl = 1;
61 } else {
62 /* This only works as long as sizeof(inbuf) == 3 */
63 ungetc(inbuf[cc - 1], in);
64 if (cc == 3 && i == 0)
65 inbuf[2] = inbuf[1];
66 inbuf[++i] = '\n';
67 }
68 } else {
69 skipnl = 0;
70 }
71 }
72 }
73
74 bits = (inbuf[0] & 0xff) << 16;
75 bits |= (inbuf[1] & 0xff) << 8;
76 bits |= inbuf[2] & 0xff;
77
78 for (bp = outbuf + sizeof(outbuf); bp > outbuf; bits >>= 6)
79 *--bp = nib2b64[bits & 0x3f];
80 if (cc < sizeof(inbuf)) {
81 outbuf[3] = '=';
82 if (cc < sizeof inbuf - 1)
83 outbuf[2] = '=';
84 }
85
86 fwrite (outbuf, sizeof(*outbuf), sizeof(outbuf), out);
87
88 if (cc < sizeof(inbuf)) {
89 putc ('\n', out);
90 return OK;
91 }
92
93 if (--n <= 0) {
94 n = BPERLIN;
95 putc ('\n', out);
96 }
97 }
98 if (n != BPERLIN)
99 putc ('\n', out);
100
101 return OK;
102 }
103
104
105 /* Caller is responsible for ensuring that the out array is long
106 enough. Given length is that of in, out should be have at
107 least this capacity:
108 4 * [length/3] + length/57 + 2
109 But double the length will certainly be sufficient. */
110 int
111 writeBase64 (unsigned char *in, size_t length, unsigned char *out)
112 {
113 unsigned int n = BPERLIN;
114
115 while (1) {
116 unsigned long bits;
117 unsigned char *bp;
118 unsigned int cc;
119 for (cc = 0, bp = in; length > 0 && cc < 3; ++cc, ++bp, --length)
120 /* empty */ ;
121
122 if (cc == 0) {
123 break;
124 } else {
125 bits = (in[0] & 0xff) << 16;
126 if (cc > 1) {
127 bits |= (in[1] & 0xff) << 8;
128 if (cc > 2) {
129 bits |= in[2] & 0xff;
130 }
131 }
132 }
133
134 for (bp = out + 4; bp > out; bits >>= 6)
135 *--bp = nib2b64[bits & 0x3f];
136 if (cc < 3) {
137 out[3] = '=';
138 if (cc < 2)
139 out[2] = '=';
140 out += 4;
141 n = 0;
142 break;
143 }
144
145 in += 3;
146 out += 4;
147 if (--n <= 0) {
148 n = BPERLIN;
149 *out++ = '\n';
150 }
151 }
152 if (n != BPERLIN)
153 *out++ = '\n';
154
155 *out = '\0';
156
157 return OK;
158 }
159
160 /*
161 * Essentially a duplicate of writeBase64, but without line wrapping or
162 * newline termination (note: string IS NUL terminated)
163 */
164
165 int
166 writeBase64raw (unsigned char *in, size_t length, unsigned char *out)
167 {
168 while (1) {
169 unsigned long bits;
170 unsigned char *bp;
171 unsigned int cc;
172 for (cc = 0, bp = in; length > 0 && cc < 3; ++cc, ++bp, --length)
173 /* empty */ ;
174
175 if (cc == 0) {
176 break;
177 } else {
178 bits = (in[0] & 0xff) << 16;
179 if (cc > 1) {
180 bits |= (in[1] & 0xff) << 8;
181 if (cc > 2) {
182 bits |= in[2] & 0xff;
183 }
184 }
185 }
186
187 for (bp = out + 4; bp > out; bits >>= 6)
188 *--bp = nib2b64[bits & 0x3f];
189 if (cc < 3) {
190 out[3] = '=';
191 if (cc < 2)
192 out[2] = '=';
193 out += 4;
194 break;
195 }
196
197 in += 3;
198 out += 4;
199 }
200
201 *out = '\0';
202
203 return OK;
204 }