1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is the Netscape Portable Runtime (NSPR).
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998-2000
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "plbase64.h"
39 : #include "prlog.h" /* For PR_NOT_REACHED */
40 : #include "prmem.h" /* for malloc / PR_MALLOC */
41 :
42 : #include <string.h> /* for strlen */
43 :
44 : static unsigned char *base = (unsigned char *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
45 :
46 : static void
47 104661 : encode3to4
48 : (
49 : const unsigned char *src,
50 : unsigned char *dest
51 : )
52 : {
53 104661 : PRUint32 b32 = (PRUint32)0;
54 104661 : PRIntn i, j = 18;
55 :
56 418644 : for( i = 0; i < 3; i++ )
57 : {
58 313983 : b32 <<= 8;
59 313983 : b32 |= (PRUint32)src[i];
60 : }
61 :
62 523305 : for( i = 0; i < 4; i++ )
63 : {
64 418644 : dest[i] = base[ (PRUint32)((b32>>j) & 0x3F) ];
65 418644 : j -= 6;
66 : }
67 :
68 : return;
69 : }
70 :
71 : static void
72 1728 : encode2to4
73 : (
74 : const unsigned char *src,
75 : unsigned char *dest
76 : )
77 : {
78 1728 : dest[0] = base[ (PRUint32)((src[0]>>2) & 0x3F) ];
79 1728 : dest[1] = base[ (PRUint32)(((src[0] & 0x03) << 4) | ((src[1] >> 4) & 0x0F)) ];
80 1728 : dest[2] = base[ (PRUint32)((src[1] & 0x0F) << 2) ];
81 1728 : dest[3] = (unsigned char)'=';
82 : return;
83 : }
84 :
85 : static void
86 789 : encode1to4
87 : (
88 : const unsigned char *src,
89 : unsigned char *dest
90 : )
91 : {
92 789 : dest[0] = base[ (PRUint32)((src[0]>>2) & 0x3F) ];
93 789 : dest[1] = base[ (PRUint32)((src[0] & 0x03) << 4) ];
94 789 : dest[2] = (unsigned char)'=';
95 789 : dest[3] = (unsigned char)'=';
96 : return;
97 : }
98 :
99 : static void
100 12536 : encode
101 : (
102 : const unsigned char *src,
103 : PRUint32 srclen,
104 : unsigned char *dest
105 : )
106 : {
107 129733 : while( srclen >= 3 )
108 : {
109 104661 : encode3to4(src, dest);
110 104661 : src += 3;
111 104661 : dest += 4;
112 104661 : srclen -= 3;
113 : }
114 :
115 12536 : switch( srclen )
116 : {
117 : case 2:
118 1728 : encode2to4(src, dest);
119 1728 : break;
120 : case 1:
121 789 : encode1to4(src, dest);
122 789 : break;
123 : case 0:
124 10019 : break;
125 : default:
126 0 : PR_NOT_REACHED("coding error");
127 : }
128 :
129 : return;
130 : }
131 :
132 : /*
133 : * PL_Base64Encode
134 : *
135 : * If the destination argument is NULL, a return buffer is
136 : * allocated, and the data therein will be null-terminated.
137 : * If the destination argument is not NULL, it is assumed to
138 : * be of sufficient size, and the contents will not be null-
139 : * terminated by this routine.
140 : *
141 : * Returns null if the allocation fails.
142 : */
143 :
144 : PR_IMPLEMENT(char *)
145 12536 : PL_Base64Encode
146 : (
147 : const char *src,
148 : PRUint32 srclen,
149 : char *dest
150 : )
151 : {
152 12536 : if( 0 == srclen )
153 : {
154 1 : size_t len = strlen(src);
155 1 : srclen = len;
156 : /* Detect truncation. */
157 1 : if( srclen != len )
158 : {
159 0 : return (char *)0;
160 : }
161 : }
162 :
163 12536 : if( (char *)0 == dest )
164 : {
165 : PRUint32 destlen;
166 : /* Ensure all PRUint32 values stay within range. */
167 415 : if( srclen > (PR_UINT32_MAX/4) * 3 )
168 : {
169 0 : return (char *)0;
170 : }
171 415 : destlen = ((srclen + 2)/3) * 4;
172 415 : dest = (char *)PR_MALLOC(destlen + 1);
173 415 : if( (char *)0 == dest )
174 : {
175 0 : return (char *)0;
176 : }
177 415 : dest[ destlen ] = (char)0; /* null terminate */
178 : }
179 :
180 12536 : encode((const unsigned char *)src, srclen, (unsigned char *)dest);
181 12536 : return dest;
182 : }
183 :
184 : static PRInt32
185 357277 : codetovalue
186 : (
187 : unsigned char c
188 : )
189 : {
190 357277 : if( (c >= (unsigned char)'A') && (c <= (unsigned char)'Z') )
191 : {
192 218231 : return (PRInt32)(c - (unsigned char)'A');
193 : }
194 139046 : else if( (c >= (unsigned char)'a') && (c <= (unsigned char)'z') )
195 : {
196 108557 : return ((PRInt32)(c - (unsigned char)'a') +26);
197 : }
198 30489 : else if( (c >= (unsigned char)'0') && (c <= (unsigned char)'9') )
199 : {
200 25442 : return ((PRInt32)(c - (unsigned char)'0') +52);
201 : }
202 5047 : else if( (unsigned char)'+' == c )
203 : {
204 1682 : return (PRInt32)62;
205 : }
206 3365 : else if( (unsigned char)'/' == c )
207 : {
208 3365 : return (PRInt32)63;
209 : }
210 : else
211 : {
212 0 : return -1;
213 : }
214 : }
215 :
216 : static PRStatus
217 88533 : decode4to3
218 : (
219 : const unsigned char *src,
220 : unsigned char *dest
221 : )
222 : {
223 88533 : PRUint32 b32 = (PRUint32)0;
224 : PRInt32 bits;
225 : PRIntn i;
226 :
227 442665 : for( i = 0; i < 4; i++ )
228 : {
229 354132 : bits = codetovalue(src[i]);
230 354132 : if( bits < 0 )
231 : {
232 0 : return PR_FAILURE;
233 : }
234 :
235 354132 : b32 <<= 6;
236 354132 : b32 |= bits;
237 : }
238 :
239 88533 : dest[0] = (unsigned char)((b32 >> 16) & 0xFF);
240 88533 : dest[1] = (unsigned char)((b32 >> 8) & 0xFF);
241 88533 : dest[2] = (unsigned char)((b32 ) & 0xFF);
242 :
243 88533 : return PR_SUCCESS;
244 : }
245 :
246 : static PRStatus
247 511 : decode3to2
248 : (
249 : const unsigned char *src,
250 : unsigned char *dest
251 : )
252 : {
253 511 : PRUint32 b32 = (PRUint32)0;
254 : PRInt32 bits;
255 : PRUint32 ubits;
256 :
257 511 : bits = codetovalue(src[0]);
258 511 : if( bits < 0 )
259 : {
260 0 : return PR_FAILURE;
261 : }
262 :
263 511 : b32 = (PRUint32)bits;
264 511 : b32 <<= 6;
265 :
266 511 : bits = codetovalue(src[1]);
267 511 : if( bits < 0 )
268 : {
269 0 : return PR_FAILURE;
270 : }
271 :
272 511 : b32 |= (PRUint32)bits;
273 511 : b32 <<= 4;
274 :
275 511 : bits = codetovalue(src[2]);
276 511 : if( bits < 0 )
277 : {
278 0 : return PR_FAILURE;
279 : }
280 :
281 511 : ubits = (PRUint32)bits;
282 511 : b32 |= (ubits >> 2);
283 :
284 511 : dest[0] = (unsigned char)((b32 >> 8) & 0xFF);
285 511 : dest[1] = (unsigned char)((b32 ) & 0xFF);
286 :
287 511 : return PR_SUCCESS;
288 : }
289 :
290 : static PRStatus
291 806 : decode2to1
292 : (
293 : const unsigned char *src,
294 : unsigned char *dest
295 : )
296 : {
297 : PRUint32 b32;
298 : PRUint32 ubits;
299 : PRInt32 bits;
300 :
301 806 : bits = codetovalue(src[0]);
302 806 : if( bits < 0 )
303 : {
304 0 : return PR_FAILURE;
305 : }
306 :
307 806 : ubits = (PRUint32)bits;
308 806 : b32 = (ubits << 2);
309 :
310 806 : bits = codetovalue(src[1]);
311 806 : if( bits < 0 )
312 : {
313 0 : return PR_FAILURE;
314 : }
315 :
316 806 : ubits = (PRUint32)bits;
317 806 : b32 |= (ubits >> 4);
318 :
319 806 : dest[0] = (unsigned char)b32;
320 :
321 806 : return PR_SUCCESS;
322 : }
323 :
324 : static PRStatus
325 4099 : decode
326 : (
327 : const unsigned char *src,
328 : PRUint32 srclen,
329 : unsigned char *dest
330 : )
331 : {
332 : PRStatus rv;
333 :
334 96731 : while( srclen >= 4 )
335 : {
336 88533 : rv = decode4to3(src, dest);
337 88533 : if( PR_SUCCESS != rv )
338 : {
339 0 : return PR_FAILURE;
340 : }
341 :
342 88533 : src += 4;
343 88533 : dest += 3;
344 88533 : srclen -= 4;
345 : }
346 :
347 4099 : switch( srclen )
348 : {
349 : case 3:
350 511 : rv = decode3to2(src, dest);
351 511 : break;
352 : case 2:
353 806 : rv = decode2to1(src, dest);
354 806 : break;
355 : case 1:
356 0 : rv = PR_FAILURE;
357 0 : break;
358 : case 0:
359 2782 : rv = PR_SUCCESS;
360 2782 : break;
361 : default:
362 0 : PR_NOT_REACHED("coding error");
363 : }
364 :
365 4099 : return rv;
366 : }
367 :
368 : /*
369 : * PL_Base64Decode
370 : *
371 : * If the destination argument is NULL, a return buffer is
372 : * allocated and the data therein will be null-terminated.
373 : * If the destination argument is not null, it is assumed
374 : * to be of sufficient size, and the data will not be null-
375 : * terminated by this routine.
376 : *
377 : * Returns null if the allocation fails, or if the source string is
378 : * not well-formed.
379 : */
380 :
381 : PR_IMPLEMENT(char *)
382 4099 : PL_Base64Decode
383 : (
384 : const char *src,
385 : PRUint32 srclen,
386 : char *dest
387 : )
388 : {
389 : PRStatus status;
390 4099 : PRBool allocated = PR_FALSE;
391 :
392 4099 : if( (char *)0 == src )
393 : {
394 0 : return (char *)0;
395 : }
396 :
397 4099 : if( 0 == srclen )
398 : {
399 9 : size_t len = strlen(src);
400 9 : srclen = len;
401 : /* Detect truncation. */
402 9 : if( srclen != len )
403 : {
404 0 : return (char *)0;
405 : }
406 : }
407 :
408 4099 : if( srclen && (0 == (srclen & 3)) )
409 : {
410 4090 : if( (char)'=' == src[ srclen-1 ] )
411 : {
412 1317 : if( (char)'=' == src[ srclen-2 ] )
413 : {
414 806 : srclen -= 2;
415 : }
416 : else
417 : {
418 511 : srclen -= 1;
419 : }
420 : }
421 : }
422 :
423 4099 : if( (char *)0 == dest )
424 : {
425 : /* The following computes ((srclen * 3) / 4) without overflow. */
426 3027 : PRUint32 destlen = (srclen / 4) * 3 + ((srclen % 4) * 3) / 4;
427 3027 : dest = (char *)PR_MALLOC(destlen + 1);
428 3027 : if( (char *)0 == dest )
429 : {
430 0 : return (char *)0;
431 : }
432 3027 : dest[ destlen ] = (char)0; /* null terminate */
433 3027 : allocated = PR_TRUE;
434 : }
435 :
436 4099 : status = decode((const unsigned char *)src, srclen, (unsigned char *)dest);
437 4099 : if( PR_SUCCESS != status )
438 : {
439 0 : if( PR_TRUE == allocated )
440 : {
441 0 : PR_DELETE(dest);
442 : }
443 :
444 0 : return (char *)0;
445 : }
446 :
447 4099 : return dest;
448 : }
|