1*0a6a1f1dSLionel Sambuc /*********************************************************************\
2*0a6a1f1dSLionel Sambuc
3*0a6a1f1dSLionel Sambuc MODULE NAME: b64.c
4*0a6a1f1dSLionel Sambuc
5*0a6a1f1dSLionel Sambuc AUTHOR: Bob Trower 08/04/01
6*0a6a1f1dSLionel Sambuc
7*0a6a1f1dSLionel Sambuc PROJECT: Crypt Data Packaging
8*0a6a1f1dSLionel Sambuc
9*0a6a1f1dSLionel Sambuc COPYRIGHT: Copyright (c) Trantor Standard Systems Inc., 2001
10*0a6a1f1dSLionel Sambuc
11*0a6a1f1dSLionel Sambuc NOTE: This source code may be used as you wish, subject to
12*0a6a1f1dSLionel Sambuc the MIT license. See the LICENCE section below.
13*0a6a1f1dSLionel Sambuc
14*0a6a1f1dSLionel Sambuc DESCRIPTION:
15*0a6a1f1dSLionel Sambuc This little utility implements the Base64
16*0a6a1f1dSLionel Sambuc Content-Transfer-Encoding standard described in
17*0a6a1f1dSLionel Sambuc RFC1113 (http://www.faqs.org/rfcs/rfc1113.html).
18*0a6a1f1dSLionel Sambuc
19*0a6a1f1dSLionel Sambuc This is the coding scheme used by MIME to allow
20*0a6a1f1dSLionel Sambuc binary data to be transferred by SMTP mail.
21*0a6a1f1dSLionel Sambuc
22*0a6a1f1dSLionel Sambuc Groups of 3 bytes from a binary stream are coded as
23*0a6a1f1dSLionel Sambuc groups of 4 bytes in a text stream.
24*0a6a1f1dSLionel Sambuc
25*0a6a1f1dSLionel Sambuc The input stream is 'padded' with zeros to create
26*0a6a1f1dSLionel Sambuc an input that is an even multiple of 3.
27*0a6a1f1dSLionel Sambuc
28*0a6a1f1dSLionel Sambuc A special character ('=') is used to denote padding so
29*0a6a1f1dSLionel Sambuc that the stream can be decoded back to its exact size.
30*0a6a1f1dSLionel Sambuc
31*0a6a1f1dSLionel Sambuc Encoded output is formatted in lines which should
32*0a6a1f1dSLionel Sambuc be a maximum of 72 characters to conform to the
33*0a6a1f1dSLionel Sambuc specification. This program defaults to 72 characters,
34*0a6a1f1dSLionel Sambuc but will allow more or less through the use of a
35*0a6a1f1dSLionel Sambuc switch. The program enforces a minimum line size
36*0a6a1f1dSLionel Sambuc of 4 characters.
37*0a6a1f1dSLionel Sambuc
38*0a6a1f1dSLionel Sambuc Example encoding:
39*0a6a1f1dSLionel Sambuc
40*0a6a1f1dSLionel Sambuc The stream 'ABCD' is 32 bits long. It is mapped as
41*0a6a1f1dSLionel Sambuc follows:
42*0a6a1f1dSLionel Sambuc
43*0a6a1f1dSLionel Sambuc ABCD
44*0a6a1f1dSLionel Sambuc
45*0a6a1f1dSLionel Sambuc A (65) B (66) C (67) D (68) (None) (None)
46*0a6a1f1dSLionel Sambuc 01000001 01000010 01000011 01000100
47*0a6a1f1dSLionel Sambuc
48*0a6a1f1dSLionel Sambuc 16 (Q) 20 (U) 9 (J) 3 (D) 17 (R) 0 (A) NA (=) NA (=)
49*0a6a1f1dSLionel Sambuc 010000 010100 001001 000011 010001 000000 000000 000000
50*0a6a1f1dSLionel Sambuc
51*0a6a1f1dSLionel Sambuc
52*0a6a1f1dSLionel Sambuc QUJDRA==
53*0a6a1f1dSLionel Sambuc
54*0a6a1f1dSLionel Sambuc Decoding is the process in reverse. A 'decode' lookup
55*0a6a1f1dSLionel Sambuc table has been created to avoid string scans.
56*0a6a1f1dSLionel Sambuc
57*0a6a1f1dSLionel Sambuc DESIGN GOALS: Specifically:
58*0a6a1f1dSLionel Sambuc Code is a stand-alone utility to perform base64
59*0a6a1f1dSLionel Sambuc encoding/decoding. It should be genuinely useful
60*0a6a1f1dSLionel Sambuc when the need arises and it meets a need that is
61*0a6a1f1dSLionel Sambuc likely to occur for some users.
62*0a6a1f1dSLionel Sambuc Code acts as sample code to show the author's
63*0a6a1f1dSLionel Sambuc design and coding style.
64*0a6a1f1dSLionel Sambuc
65*0a6a1f1dSLionel Sambuc Generally:
66*0a6a1f1dSLionel Sambuc This program is designed to survive:
67*0a6a1f1dSLionel Sambuc Everything you need is in a single source file.
68*0a6a1f1dSLionel Sambuc It compiles cleanly using a vanilla ANSI C compiler.
69*0a6a1f1dSLionel Sambuc It does its job correctly with a minimum of fuss.
70*0a6a1f1dSLionel Sambuc The code is not overly clever, not overly simplistic
71*0a6a1f1dSLionel Sambuc and not overly verbose.
72*0a6a1f1dSLionel Sambuc Access is 'cut and paste' from a web page.
73*0a6a1f1dSLionel Sambuc Terms of use are reasonable.
74*0a6a1f1dSLionel Sambuc
75*0a6a1f1dSLionel Sambuc VALIDATION: Non-trivial code is never without errors. This
76*0a6a1f1dSLionel Sambuc file likely has some problems, since it has only
77*0a6a1f1dSLionel Sambuc been tested by the author. It is expected with most
78*0a6a1f1dSLionel Sambuc source code that there is a period of 'burn-in' when
79*0a6a1f1dSLionel Sambuc problems are identified and corrected. That being
80*0a6a1f1dSLionel Sambuc said, it is possible to have 'reasonably correct'
81*0a6a1f1dSLionel Sambuc code by following a regime of unit test that covers
82*0a6a1f1dSLionel Sambuc the most likely cases and regression testing prior
83*0a6a1f1dSLionel Sambuc to release. This has been done with this code and
84*0a6a1f1dSLionel Sambuc it has a good probability of performing as expected.
85*0a6a1f1dSLionel Sambuc
86*0a6a1f1dSLionel Sambuc Unit Test Cases:
87*0a6a1f1dSLionel Sambuc
88*0a6a1f1dSLionel Sambuc case 0:empty file:
89*0a6a1f1dSLionel Sambuc CASE0.DAT -> ->
90*0a6a1f1dSLionel Sambuc (Zero length target file created
91*0a6a1f1dSLionel Sambuc on both encode and decode.)
92*0a6a1f1dSLionel Sambuc
93*0a6a1f1dSLionel Sambuc case 1:One input character:
94*0a6a1f1dSLionel Sambuc CASE1.DAT A -> QQ== -> A
95*0a6a1f1dSLionel Sambuc
96*0a6a1f1dSLionel Sambuc case 2:Two input characters:
97*0a6a1f1dSLionel Sambuc CASE2.DAT AB -> QUJD -> AB
98*0a6a1f1dSLionel Sambuc
99*0a6a1f1dSLionel Sambuc case 3:Three input characters:
100*0a6a1f1dSLionel Sambuc CASE3.DAT ABC -> QUJD -> ABC
101*0a6a1f1dSLionel Sambuc
102*0a6a1f1dSLionel Sambuc case 4:Four input characters:
103*0a6a1f1dSLionel Sambuc case4.dat ABCD -> QUJDRA== -> ABCD
104*0a6a1f1dSLionel Sambuc
105*0a6a1f1dSLionel Sambuc case 5:All chars from 0 to ff, linesize set to 50:
106*0a6a1f1dSLionel Sambuc
107*0a6a1f1dSLionel Sambuc AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIj
108*0a6a1f1dSLionel Sambuc JCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZH
109*0a6a1f1dSLionel Sambuc SElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWpr
110*0a6a1f1dSLionel Sambuc bG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6P
111*0a6a1f1dSLionel Sambuc kJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKz
112*0a6a1f1dSLionel Sambuc tLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX
113*0a6a1f1dSLionel Sambuc 2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7
114*0a6a1f1dSLionel Sambuc /P3+/w==
115*0a6a1f1dSLionel Sambuc
116*0a6a1f1dSLionel Sambuc case 6:Mime Block from e-mail:
117*0a6a1f1dSLionel Sambuc (Data same as test case 5)
118*0a6a1f1dSLionel Sambuc
119*0a6a1f1dSLionel Sambuc case 7: Large files:
120*0a6a1f1dSLionel Sambuc Tested 28 MB file in/out.
121*0a6a1f1dSLionel Sambuc
122*0a6a1f1dSLionel Sambuc case 8: Random Binary Integrity:
123*0a6a1f1dSLionel Sambuc This binary program (b64.exe) was encoded to base64,
124*0a6a1f1dSLionel Sambuc back to binary and then executed.
125*0a6a1f1dSLionel Sambuc
126*0a6a1f1dSLionel Sambuc case 9 Stress:
127*0a6a1f1dSLionel Sambuc All files in a working directory encoded/decoded
128*0a6a1f1dSLionel Sambuc and compared with file comparison utility to
129*0a6a1f1dSLionel Sambuc ensure that multiple runs do not cause problems
130*0a6a1f1dSLionel Sambuc such as exhausting file handles, tmp storage, etc.
131*0a6a1f1dSLionel Sambuc
132*0a6a1f1dSLionel Sambuc -------------
133*0a6a1f1dSLionel Sambuc
134*0a6a1f1dSLionel Sambuc Syntax, operation and failure:
135*0a6a1f1dSLionel Sambuc All options/switches tested. Performs as
136*0a6a1f1dSLionel Sambuc expected.
137*0a6a1f1dSLionel Sambuc
138*0a6a1f1dSLionel Sambuc case 10:
139*0a6a1f1dSLionel Sambuc No Args -- Shows Usage Screen
140*0a6a1f1dSLionel Sambuc Return Code 1 (Invalid Syntax)
141*0a6a1f1dSLionel Sambuc case 11:
142*0a6a1f1dSLionel Sambuc One Arg (invalid) -- Shows Usage Screen
143*0a6a1f1dSLionel Sambuc Return Code 1 (Invalid Syntax)
144*0a6a1f1dSLionel Sambuc case 12:
145*0a6a1f1dSLionel Sambuc One Arg Help (-?) -- Shows detailed Usage Screen.
146*0a6a1f1dSLionel Sambuc Return Code 0 (Success -- help request is valid).
147*0a6a1f1dSLionel Sambuc case 13:
148*0a6a1f1dSLionel Sambuc One Arg Help (-h) -- Shows detailed Usage Screen.
149*0a6a1f1dSLionel Sambuc Return Code 0 (Success -- help request is valid).
150*0a6a1f1dSLionel Sambuc case 14:
151*0a6a1f1dSLionel Sambuc One Arg (valid) -- Uses stdin/stdout (filter)
152*0a6a1f1dSLionel Sambuc Return Code 0 (Sucess)
153*0a6a1f1dSLionel Sambuc case 15:
154*0a6a1f1dSLionel Sambuc Two Args (invalid file) -- shows system error.
155*0a6a1f1dSLionel Sambuc Return Code 2 (File Error)
156*0a6a1f1dSLionel Sambuc case 16:
157*0a6a1f1dSLionel Sambuc Encode non-existent file -- shows system error.
158*0a6a1f1dSLionel Sambuc Return Code 2 (File Error)
159*0a6a1f1dSLionel Sambuc case 17:
160*0a6a1f1dSLionel Sambuc Out of disk space -- shows system error.
161*0a6a1f1dSLionel Sambuc Return Code 3 (File I/O Error)
162*0a6a1f1dSLionel Sambuc
163*0a6a1f1dSLionel Sambuc -------------
164*0a6a1f1dSLionel Sambuc
165*0a6a1f1dSLionel Sambuc Compile/Regression test:
166*0a6a1f1dSLionel Sambuc gcc compiled binary under Cygwin
167*0a6a1f1dSLionel Sambuc Microsoft Visual Studio under Windows 2000
168*0a6a1f1dSLionel Sambuc Microsoft Version 6.0 C under Windows 2000
169*0a6a1f1dSLionel Sambuc
170*0a6a1f1dSLionel Sambuc DEPENDENCIES: None
171*0a6a1f1dSLionel Sambuc
172*0a6a1f1dSLionel Sambuc LICENCE: Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc.
173*0a6a1f1dSLionel Sambuc
174*0a6a1f1dSLionel Sambuc Permission is hereby granted, free of charge, to any person
175*0a6a1f1dSLionel Sambuc obtaining a copy of this software and associated
176*0a6a1f1dSLionel Sambuc documentation files (the "Software"), to deal in the
177*0a6a1f1dSLionel Sambuc Software without restriction, including without limitation
178*0a6a1f1dSLionel Sambuc the rights to use, copy, modify, merge, publish, distribute,
179*0a6a1f1dSLionel Sambuc sublicense, and/or sell copies of the Software, and to
180*0a6a1f1dSLionel Sambuc permit persons to whom the Software is furnished to do so,
181*0a6a1f1dSLionel Sambuc subject to the following conditions:
182*0a6a1f1dSLionel Sambuc
183*0a6a1f1dSLionel Sambuc The above copyright notice and this permission notice shall
184*0a6a1f1dSLionel Sambuc be included in all copies or substantial portions of the
185*0a6a1f1dSLionel Sambuc Software.
186*0a6a1f1dSLionel Sambuc
187*0a6a1f1dSLionel Sambuc THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
188*0a6a1f1dSLionel Sambuc KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
189*0a6a1f1dSLionel Sambuc WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
190*0a6a1f1dSLionel Sambuc PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
191*0a6a1f1dSLionel Sambuc OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
192*0a6a1f1dSLionel Sambuc OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
193*0a6a1f1dSLionel Sambuc OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
194*0a6a1f1dSLionel Sambuc SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
195*0a6a1f1dSLionel Sambuc
196*0a6a1f1dSLionel Sambuc VERSION HISTORY:
197*0a6a1f1dSLionel Sambuc Bob Trower 08/04/01 -- Create Version 0.00.00B
198*0a6a1f1dSLionel Sambuc
199*0a6a1f1dSLionel Sambuc \******************************************************************* */
200*0a6a1f1dSLionel Sambuc
201*0a6a1f1dSLionel Sambuc #include <inttypes.h>
202*0a6a1f1dSLionel Sambuc #include <stdio.h>
203*0a6a1f1dSLionel Sambuc #include <stdlib.h>
204*0a6a1f1dSLionel Sambuc
205*0a6a1f1dSLionel Sambuc #include "b64.h"
206*0a6a1f1dSLionel Sambuc
207*0a6a1f1dSLionel Sambuc /*
208*0a6a1f1dSLionel Sambuc ** Translation Table as described in RFC1113
209*0a6a1f1dSLionel Sambuc */
210*0a6a1f1dSLionel Sambuc static const char cb64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
211*0a6a1f1dSLionel Sambuc
212*0a6a1f1dSLionel Sambuc /*
213*0a6a1f1dSLionel Sambuc ** Translation Table to decode (created by author)
214*0a6a1f1dSLionel Sambuc */
215*0a6a1f1dSLionel Sambuc static const char cd64[] = "|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
216*0a6a1f1dSLionel Sambuc
217*0a6a1f1dSLionel Sambuc /*
218*0a6a1f1dSLionel Sambuc ** encodeblock
219*0a6a1f1dSLionel Sambuc **
220*0a6a1f1dSLionel Sambuc ** encode 3 8-bit binary bytes as 4 '6-bit' characters
221*0a6a1f1dSLionel Sambuc */
222*0a6a1f1dSLionel Sambuc static void
encodeblock(uint8_t * wordin,uint8_t * wordout,int wordlen)223*0a6a1f1dSLionel Sambuc encodeblock(uint8_t *wordin, uint8_t *wordout, int wordlen)
224*0a6a1f1dSLionel Sambuc {
225*0a6a1f1dSLionel Sambuc wordout[0] = cb64[(unsigned)wordin[0] >> 2];
226*0a6a1f1dSLionel Sambuc wordout[1] = cb64[((unsigned)(wordin[0] & 0x03) << 4) | ((unsigned)(wordin[1] & 0xf0) >> 4)];
227*0a6a1f1dSLionel Sambuc wordout[2] = (uint8_t)(wordlen > 1) ?
228*0a6a1f1dSLionel Sambuc cb64[((unsigned)(wordin[1] & 0x0f) << 2) | ((unsigned)(wordin[2] & 0xc0) >> 6)] : '=';
229*0a6a1f1dSLionel Sambuc wordout[3] = (uint8_t)(wordlen > 2) ? cb64[wordin[2] & 0x3f] : '=';
230*0a6a1f1dSLionel Sambuc }
231*0a6a1f1dSLionel Sambuc
232*0a6a1f1dSLionel Sambuc /*
233*0a6a1f1dSLionel Sambuc ** encode
234*0a6a1f1dSLionel Sambuc **
235*0a6a1f1dSLionel Sambuc ** base64 encode a stream adding padding and line breaks as per spec.
236*0a6a1f1dSLionel Sambuc */
237*0a6a1f1dSLionel Sambuc int
b64encode(const char * in,const size_t insize,void * vp,size_t outsize,int linesize)238*0a6a1f1dSLionel Sambuc b64encode(const char *in, const size_t insize, void *vp, size_t outsize, int linesize)
239*0a6a1f1dSLionel Sambuc {
240*0a6a1f1dSLionel Sambuc const char *inp;
241*0a6a1f1dSLionel Sambuc unsigned i;
242*0a6a1f1dSLionel Sambuc uint8_t wordout[4];
243*0a6a1f1dSLionel Sambuc uint8_t wordin[3];
244*0a6a1f1dSLionel Sambuc char *out = vp;
245*0a6a1f1dSLionel Sambuc char *outp;
246*0a6a1f1dSLionel Sambuc int blocksout;
247*0a6a1f1dSLionel Sambuc int wordlen;
248*0a6a1f1dSLionel Sambuc
249*0a6a1f1dSLionel Sambuc if (in == NULL || vp == NULL) {
250*0a6a1f1dSLionel Sambuc return 0;
251*0a6a1f1dSLionel Sambuc }
252*0a6a1f1dSLionel Sambuc wordlen = 0;
253*0a6a1f1dSLionel Sambuc for (blocksout = 0, inp = in, outp = out; (size_t)(inp - in) < insize && (size_t)(outp - out) < outsize;) {
254*0a6a1f1dSLionel Sambuc for (wordlen = 0, i = 0; i < sizeof(wordin); i++) {
255*0a6a1f1dSLionel Sambuc wordin[i] = (uint8_t) *inp++;
256*0a6a1f1dSLionel Sambuc if ((size_t)(inp - in) <= insize) {
257*0a6a1f1dSLionel Sambuc wordlen++;
258*0a6a1f1dSLionel Sambuc } else {
259*0a6a1f1dSLionel Sambuc wordin[i] = 0x0;
260*0a6a1f1dSLionel Sambuc }
261*0a6a1f1dSLionel Sambuc }
262*0a6a1f1dSLionel Sambuc if (wordlen > 0) {
263*0a6a1f1dSLionel Sambuc encodeblock(wordin, wordout, wordlen);
264*0a6a1f1dSLionel Sambuc for (i = 0; i < sizeof(wordout) ; i++) {
265*0a6a1f1dSLionel Sambuc *outp++ = wordout[i];
266*0a6a1f1dSLionel Sambuc }
267*0a6a1f1dSLionel Sambuc blocksout++;
268*0a6a1f1dSLionel Sambuc }
269*0a6a1f1dSLionel Sambuc if (linesize > 0) {
270*0a6a1f1dSLionel Sambuc if (blocksout >= (int)(linesize / sizeof(wordout)) ||
271*0a6a1f1dSLionel Sambuc (size_t)(inp - in) >= insize) {
272*0a6a1f1dSLionel Sambuc if (blocksout) {
273*0a6a1f1dSLionel Sambuc *outp++ = '\r';
274*0a6a1f1dSLionel Sambuc *outp++ = '\n';
275*0a6a1f1dSLionel Sambuc }
276*0a6a1f1dSLionel Sambuc blocksout = 0;
277*0a6a1f1dSLionel Sambuc }
278*0a6a1f1dSLionel Sambuc }
279*0a6a1f1dSLionel Sambuc }
280*0a6a1f1dSLionel Sambuc return (int)(outp - out);
281*0a6a1f1dSLionel Sambuc }
282*0a6a1f1dSLionel Sambuc
283*0a6a1f1dSLionel Sambuc /*
284*0a6a1f1dSLionel Sambuc ** decodeblock
285*0a6a1f1dSLionel Sambuc **
286*0a6a1f1dSLionel Sambuc ** decode 4 '6-bit' characters into 3 8-bit binary bytes
287*0a6a1f1dSLionel Sambuc */
288*0a6a1f1dSLionel Sambuc static void
decodeblock(uint8_t wordin[4],uint8_t wordout[3])289*0a6a1f1dSLionel Sambuc decodeblock(uint8_t wordin[4], uint8_t wordout[3])
290*0a6a1f1dSLionel Sambuc {
291*0a6a1f1dSLionel Sambuc wordout[0] = (uint8_t) ((unsigned)wordin[0] << 2 | (unsigned)wordin[1] >> 4);
292*0a6a1f1dSLionel Sambuc wordout[1] = (uint8_t) ((unsigned)wordin[1] << 4 | (unsigned)wordin[2] >> 2);
293*0a6a1f1dSLionel Sambuc wordout[2] = (uint8_t) (((wordin[2] << 6) & 0xc0) | wordin[3]);
294*0a6a1f1dSLionel Sambuc }
295*0a6a1f1dSLionel Sambuc
296*0a6a1f1dSLionel Sambuc /*
297*0a6a1f1dSLionel Sambuc ** decode
298*0a6a1f1dSLionel Sambuc **
299*0a6a1f1dSLionel Sambuc ** decode a base64 encoded stream discarding padding, line breaks and noise
300*0a6a1f1dSLionel Sambuc */
301*0a6a1f1dSLionel Sambuc int
b64decode(const char * in,const size_t insize,void * vp,size_t outsize)302*0a6a1f1dSLionel Sambuc b64decode(const char *in, const size_t insize, void *vp, size_t outsize)
303*0a6a1f1dSLionel Sambuc {
304*0a6a1f1dSLionel Sambuc const char *inp;
305*0a6a1f1dSLionel Sambuc unsigned wordlen;
306*0a6a1f1dSLionel Sambuc unsigned i;
307*0a6a1f1dSLionel Sambuc uint8_t wordout[3];
308*0a6a1f1dSLionel Sambuc uint8_t wordin[4];
309*0a6a1f1dSLionel Sambuc uint8_t v;
310*0a6a1f1dSLionel Sambuc char *out = vp;
311*0a6a1f1dSLionel Sambuc char *outp;
312*0a6a1f1dSLionel Sambuc
313*0a6a1f1dSLionel Sambuc if (in == NULL || vp == NULL) {
314*0a6a1f1dSLionel Sambuc return 0;
315*0a6a1f1dSLionel Sambuc }
316*0a6a1f1dSLionel Sambuc for (inp = in, outp = out ; (size_t)(inp - in) < insize && (size_t)(outp - out) < outsize ; ) {
317*0a6a1f1dSLionel Sambuc for (wordlen = 0, i = 0 ; i < sizeof(wordin) && (size_t)(inp - in) < insize ; i++) {
318*0a6a1f1dSLionel Sambuc /* get a single character */
319*0a6a1f1dSLionel Sambuc for (v = 0; (size_t)(inp - in) <= insize && v == 0 ; ) {
320*0a6a1f1dSLionel Sambuc if (*inp == '\r' && *(inp + 1) == '\n') {
321*0a6a1f1dSLionel Sambuc inp += 2;
322*0a6a1f1dSLionel Sambuc } else {
323*0a6a1f1dSLionel Sambuc v = (uint8_t) *inp++;
324*0a6a1f1dSLionel Sambuc v = (uint8_t) ((v < 43 || v > 122) ? 0 : cd64[v - 43]);
325*0a6a1f1dSLionel Sambuc if (v) {
326*0a6a1f1dSLionel Sambuc v = (uint8_t) ((v == '$') ? 0 : v - 61);
327*0a6a1f1dSLionel Sambuc }
328*0a6a1f1dSLionel Sambuc }
329*0a6a1f1dSLionel Sambuc }
330*0a6a1f1dSLionel Sambuc /* perhaps 0x0 pad */
331*0a6a1f1dSLionel Sambuc if ((size_t)(inp - in) <= insize) {
332*0a6a1f1dSLionel Sambuc wordlen += 1;
333*0a6a1f1dSLionel Sambuc if (v) {
334*0a6a1f1dSLionel Sambuc wordin[i] = (uint8_t) (v - 1);
335*0a6a1f1dSLionel Sambuc }
336*0a6a1f1dSLionel Sambuc } else {
337*0a6a1f1dSLionel Sambuc wordin[i] = 0x0;
338*0a6a1f1dSLionel Sambuc }
339*0a6a1f1dSLionel Sambuc }
340*0a6a1f1dSLionel Sambuc if (wordlen > 0) {
341*0a6a1f1dSLionel Sambuc decodeblock(wordin, wordout);
342*0a6a1f1dSLionel Sambuc for (i = 0; i < wordlen - 1 ; i++) {
343*0a6a1f1dSLionel Sambuc *outp++ = wordout[i];
344*0a6a1f1dSLionel Sambuc }
345*0a6a1f1dSLionel Sambuc }
346*0a6a1f1dSLionel Sambuc }
347*0a6a1f1dSLionel Sambuc return (int)(outp - out);
348*0a6a1f1dSLionel Sambuc }
349*0a6a1f1dSLionel Sambuc
350*0a6a1f1dSLionel Sambuc /* return the encoded size for n bytes input */
351*0a6a1f1dSLionel Sambuc int
b64_encsize(unsigned n)352*0a6a1f1dSLionel Sambuc b64_encsize(unsigned n)
353*0a6a1f1dSLionel Sambuc {
354*0a6a1f1dSLionel Sambuc return ((4 * n) / 3) + 4;
355*0a6a1f1dSLionel Sambuc }
356