]> diplodocus.org Git - nmh/blob - sbr/base64.c
Another pass at cleaning up (some of) the manpages.
[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 if (fwrite (outbuf, sizeof(*outbuf), sizeof(outbuf), out) <
87 sizeof outbuf) {
88 advise ("writeBase64aux", "fwrite");
89 }
90
91 if (cc < sizeof(inbuf)) {
92 putc ('\n', out);
93 return OK;
94 }
95
96 if (--n <= 0) {
97 n = BPERLIN;
98 putc ('\n', out);
99 }
100 }
101 if (n != BPERLIN)
102 putc ('\n', out);
103
104 return OK;
105 }
106
107
108 /* Caller is responsible for ensuring that the out array is long
109 enough. Given length is that of in, out should be have at
110 least this capacity:
111 4 * [length/3] + length/57 + 2
112 But double the length will certainly be sufficient. */
113 int
114 writeBase64 (unsigned char *in, size_t length, unsigned char *out)
115 {
116 unsigned int n = BPERLIN;
117
118 while (1) {
119 unsigned long bits;
120 unsigned char *bp;
121 unsigned int cc;
122 for (cc = 0, bp = in; length > 0 && cc < 3; ++cc, ++bp, --length)
123 /* empty */ ;
124
125 if (cc == 0) {
126 break;
127 } else {
128 bits = (in[0] & 0xff) << 16;
129 if (cc > 1) {
130 bits |= (in[1] & 0xff) << 8;
131 if (cc > 2) {
132 bits |= in[2] & 0xff;
133 }
134 }
135 }
136
137 for (bp = out + 4; bp > out; bits >>= 6)
138 *--bp = nib2b64[bits & 0x3f];
139 if (cc < 3) {
140 out[3] = '=';
141 if (cc < 2)
142 out[2] = '=';
143 out += 4;
144 n = 0;
145 break;
146 }
147
148 in += 3;
149 out += 4;
150 if (--n <= 0) {
151 n = BPERLIN;
152 *out++ = '\n';
153 }
154 }
155 if (n != BPERLIN)
156 *out++ = '\n';
157
158 *out = '\0';
159
160 return OK;
161 }
162
163 /*
164 * Essentially a duplicate of writeBase64, but without line wrapping or
165 * newline termination (note: string IS NUL terminated)
166 */
167
168 int
169 writeBase64raw (unsigned char *in, size_t length, unsigned char *out)
170 {
171 while (1) {
172 unsigned long bits;
173 unsigned char *bp;
174 unsigned int cc;
175 for (cc = 0, bp = in; length > 0 && cc < 3; ++cc, ++bp, --length)
176 /* empty */ ;
177
178 if (cc == 0) {
179 break;
180 } else {
181 bits = (in[0] & 0xff) << 16;
182 if (cc > 1) {
183 bits |= (in[1] & 0xff) << 8;
184 if (cc > 2) {
185 bits |= in[2] & 0xff;
186 }
187 }
188 }
189
190 for (bp = out + 4; bp > out; bits >>= 6)
191 *--bp = nib2b64[bits & 0x3f];
192 if (cc < 3) {
193 out[3] = '=';
194 if (cc < 2)
195 out[2] = '=';
196 out += 4;
197 break;
198 }
199
200 in += 3;
201 out += 4;
202 }
203
204 *out = '\0';
205
206 return OK;
207 }