Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "plbase64.h"
7 : #include "prlog.h" /* For PR_NOT_REACHED */
8 : #include "prmem.h" /* for malloc / PR_MALLOC */
9 :
10 : #include <string.h> /* for strlen */
11 :
12 : static unsigned char *base = (unsigned char *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
13 :
14 : static void
15 120 : encode3to4
16 : (
17 : const unsigned char *src,
18 : unsigned char *dest
19 : )
20 : {
21 120 : PRUint32 b32 = (PRUint32)0;
22 120 : PRIntn i, j = 18;
23 :
24 480 : for( i = 0; i < 3; i++ )
25 : {
26 360 : b32 <<= 8;
27 360 : b32 |= (PRUint32)src[i];
28 : }
29 :
30 600 : for( i = 0; i < 4; i++ )
31 : {
32 480 : dest[i] = base[ (PRUint32)((b32>>j) & 0x3F) ];
33 480 : j -= 6;
34 : }
35 :
36 120 : return;
37 : }
38 :
39 : static void
40 4 : encode2to4
41 : (
42 : const unsigned char *src,
43 : unsigned char *dest
44 : )
45 : {
46 4 : dest[0] = base[ (PRUint32)((src[0]>>2) & 0x3F) ];
47 4 : dest[1] = base[ (PRUint32)(((src[0] & 0x03) << 4) | ((src[1] >> 4) & 0x0F)) ];
48 4 : dest[2] = base[ (PRUint32)((src[1] & 0x0F) << 2) ];
49 4 : dest[3] = (unsigned char)'=';
50 4 : return;
51 : }
52 :
53 : static void
54 0 : encode1to4
55 : (
56 : const unsigned char *src,
57 : unsigned char *dest
58 : )
59 : {
60 0 : dest[0] = base[ (PRUint32)((src[0]>>2) & 0x3F) ];
61 0 : dest[1] = base[ (PRUint32)((src[0] & 0x03) << 4) ];
62 0 : dest[2] = (unsigned char)'=';
63 0 : dest[3] = (unsigned char)'=';
64 0 : return;
65 : }
66 :
67 : static void
68 5 : encode
69 : (
70 : const unsigned char *src,
71 : PRUint32 srclen,
72 : unsigned char *dest
73 : )
74 : {
75 130 : while( srclen >= 3 )
76 : {
77 120 : encode3to4(src, dest);
78 120 : src += 3;
79 120 : dest += 4;
80 120 : srclen -= 3;
81 : }
82 :
83 5 : switch( srclen )
84 : {
85 : case 2:
86 4 : encode2to4(src, dest);
87 4 : break;
88 : case 1:
89 0 : encode1to4(src, dest);
90 0 : break;
91 : case 0:
92 1 : break;
93 : default:
94 0 : PR_NOT_REACHED("coding error");
95 : }
96 :
97 5 : return;
98 : }
99 :
100 : /*
101 : * PL_Base64Encode
102 : *
103 : * If the destination argument is NULL, a return buffer is
104 : * allocated, and the data therein will be null-terminated.
105 : * If the destination argument is not NULL, it is assumed to
106 : * be of sufficient size, and the contents will not be null-
107 : * terminated by this routine.
108 : *
109 : * Returns null if the allocation fails.
110 : */
111 :
112 : PR_IMPLEMENT(char *)
113 : PL_Base64Encode
114 : (
115 : const char *src,
116 : PRUint32 srclen,
117 : char *dest
118 : )
119 : {
120 5 : if( 0 == srclen )
121 : {
122 0 : size_t len = strlen(src);
123 0 : srclen = len;
124 : /* Detect truncation. */
125 0 : if( srclen != len )
126 : {
127 0 : return (char *)0;
128 : }
129 : }
130 :
131 5 : if( (char *)0 == dest )
132 : {
133 : PRUint32 destlen;
134 : /* Ensure all PRUint32 values stay within range. */
135 4 : if( srclen > (PR_UINT32_MAX/4) * 3 )
136 : {
137 0 : return (char *)0;
138 : }
139 4 : destlen = ((srclen + 2)/3) * 4;
140 4 : dest = (char *)PR_MALLOC(destlen + 1);
141 4 : if( (char *)0 == dest )
142 : {
143 0 : return (char *)0;
144 : }
145 4 : dest[ destlen ] = (char)0; /* null terminate */
146 : }
147 :
148 5 : encode((const unsigned char *)src, srclen, (unsigned char *)dest);
149 5 : return dest;
150 : }
151 :
152 : static PRInt32
153 13765 : codetovalue
154 : (
155 : unsigned char c
156 : )
157 : {
158 13765 : if( (c >= (unsigned char)'A') && (c <= (unsigned char)'Z') )
159 : {
160 8122 : return (PRInt32)(c - (unsigned char)'A');
161 : }
162 5643 : else if( (c >= (unsigned char)'a') && (c <= (unsigned char)'z') )
163 : {
164 4338 : return ((PRInt32)(c - (unsigned char)'a') +26);
165 : }
166 1305 : else if( (c >= (unsigned char)'0') && (c <= (unsigned char)'9') )
167 : {
168 1233 : return ((PRInt32)(c - (unsigned char)'0') +52);
169 : }
170 72 : else if( (unsigned char)'+' == c )
171 : {
172 23 : return (PRInt32)62;
173 : }
174 49 : else if( (unsigned char)'/' == c )
175 : {
176 49 : return (PRInt32)63;
177 : }
178 : else
179 : {
180 0 : return -1;
181 : }
182 : }
183 :
184 : static PRStatus
185 3360 : decode4to3
186 : (
187 : const unsigned char *src,
188 : unsigned char *dest
189 : )
190 : {
191 3360 : PRUint32 b32 = (PRUint32)0;
192 : PRInt32 bits;
193 : PRIntn i;
194 :
195 16800 : for( i = 0; i < 4; i++ )
196 : {
197 13440 : bits = codetovalue(src[i]);
198 13440 : if( bits < 0 )
199 : {
200 0 : return PR_FAILURE;
201 : }
202 :
203 13440 : b32 <<= 6;
204 13440 : b32 |= bits;
205 : }
206 :
207 3360 : dest[0] = (unsigned char)((b32 >> 16) & 0xFF);
208 3360 : dest[1] = (unsigned char)((b32 >> 8) & 0xFF);
209 3360 : dest[2] = (unsigned char)((b32 ) & 0xFF);
210 :
211 3360 : return PR_SUCCESS;
212 : }
213 :
214 : static PRStatus
215 47 : decode3to2
216 : (
217 : const unsigned char *src,
218 : unsigned char *dest
219 : )
220 : {
221 47 : PRUint32 b32 = (PRUint32)0;
222 : PRInt32 bits;
223 : PRUint32 ubits;
224 :
225 47 : bits = codetovalue(src[0]);
226 47 : if( bits < 0 )
227 : {
228 0 : return PR_FAILURE;
229 : }
230 :
231 47 : b32 = (PRUint32)bits;
232 47 : b32 <<= 6;
233 :
234 47 : bits = codetovalue(src[1]);
235 47 : if( bits < 0 )
236 : {
237 0 : return PR_FAILURE;
238 : }
239 :
240 47 : b32 |= (PRUint32)bits;
241 47 : b32 <<= 4;
242 :
243 47 : bits = codetovalue(src[2]);
244 47 : if( bits < 0 )
245 : {
246 0 : return PR_FAILURE;
247 : }
248 :
249 47 : ubits = (PRUint32)bits;
250 47 : b32 |= (ubits >> 2);
251 :
252 47 : dest[0] = (unsigned char)((b32 >> 8) & 0xFF);
253 47 : dest[1] = (unsigned char)((b32 ) & 0xFF);
254 :
255 47 : return PR_SUCCESS;
256 : }
257 :
258 : static PRStatus
259 92 : decode2to1
260 : (
261 : const unsigned char *src,
262 : unsigned char *dest
263 : )
264 : {
265 : PRUint32 b32;
266 : PRUint32 ubits;
267 : PRInt32 bits;
268 :
269 92 : bits = codetovalue(src[0]);
270 92 : if( bits < 0 )
271 : {
272 0 : return PR_FAILURE;
273 : }
274 :
275 92 : ubits = (PRUint32)bits;
276 92 : b32 = (ubits << 2);
277 :
278 92 : bits = codetovalue(src[1]);
279 92 : if( bits < 0 )
280 : {
281 0 : return PR_FAILURE;
282 : }
283 :
284 92 : ubits = (PRUint32)bits;
285 92 : b32 |= (ubits >> 4);
286 :
287 92 : dest[0] = (unsigned char)b32;
288 :
289 92 : return PR_SUCCESS;
290 : }
291 :
292 : static PRStatus
293 172 : decode
294 : (
295 : const unsigned char *src,
296 : PRUint32 srclen,
297 : unsigned char *dest
298 : )
299 : {
300 : PRStatus rv;
301 :
302 3704 : while( srclen >= 4 )
303 : {
304 3360 : rv = decode4to3(src, dest);
305 3360 : if( PR_SUCCESS != rv )
306 : {
307 0 : return PR_FAILURE;
308 : }
309 :
310 3360 : src += 4;
311 3360 : dest += 3;
312 3360 : srclen -= 4;
313 : }
314 :
315 172 : switch( srclen )
316 : {
317 : case 3:
318 47 : rv = decode3to2(src, dest);
319 47 : break;
320 : case 2:
321 92 : rv = decode2to1(src, dest);
322 92 : break;
323 : case 1:
324 0 : rv = PR_FAILURE;
325 0 : break;
326 : case 0:
327 33 : rv = PR_SUCCESS;
328 33 : break;
329 : default:
330 0 : PR_NOT_REACHED("coding error");
331 : }
332 :
333 172 : return rv;
334 : }
335 :
336 : /*
337 : * PL_Base64Decode
338 : *
339 : * If the destination argument is NULL, a return buffer is
340 : * allocated and the data therein will be null-terminated.
341 : * If the destination argument is not null, it is assumed
342 : * to be of sufficient size, and the data will not be null-
343 : * terminated by this routine.
344 : *
345 : * Returns null if the allocation fails, or if the source string is
346 : * not well-formed.
347 : */
348 :
349 : PR_IMPLEMENT(char *)
350 : PL_Base64Decode
351 : (
352 : const char *src,
353 : PRUint32 srclen,
354 : char *dest
355 : )
356 : {
357 : PRStatus status;
358 172 : PRBool allocated = PR_FALSE;
359 :
360 172 : if( (char *)0 == src )
361 : {
362 0 : return (char *)0;
363 : }
364 :
365 172 : if( 0 == srclen )
366 : {
367 0 : size_t len = strlen(src);
368 0 : srclen = len;
369 : /* Detect truncation. */
370 0 : if( srclen != len )
371 : {
372 0 : return (char *)0;
373 : }
374 : }
375 :
376 172 : if( srclen && (0 == (srclen & 3)) )
377 : {
378 172 : if( (char)'=' == src[ srclen-1 ] )
379 : {
380 139 : if( (char)'=' == src[ srclen-2 ] )
381 : {
382 92 : srclen -= 2;
383 : }
384 : else
385 : {
386 47 : srclen -= 1;
387 : }
388 : }
389 : }
390 :
391 172 : if( (char *)0 == dest )
392 : {
393 : /* The following computes ((srclen * 3) / 4) without overflow. */
394 0 : PRUint32 destlen = (srclen / 4) * 3 + ((srclen % 4) * 3) / 4;
395 0 : dest = (char *)PR_MALLOC(destlen + 1);
396 0 : if( (char *)0 == dest )
397 : {
398 0 : return (char *)0;
399 : }
400 0 : dest[ destlen ] = (char)0; /* null terminate */
401 0 : allocated = PR_TRUE;
402 : }
403 :
404 172 : status = decode((const unsigned char *)src, srclen, (unsigned char *)dest);
405 172 : if( PR_SUCCESS != status )
406 : {
407 0 : if( PR_TRUE == allocated )
408 : {
409 0 : PR_DELETE(dest);
410 : }
411 :
412 0 : return (char *)0;
413 : }
414 :
415 172 : return dest;
416 : }
|