|
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 encode3to4 |
|
16 ( |
|
17 const unsigned char *src, |
|
18 unsigned char *dest |
|
19 ) |
|
20 { |
|
21 PRUint32 b32 = (PRUint32)0; |
|
22 PRIntn i, j = 18; |
|
23 |
|
24 for( i = 0; i < 3; i++ ) |
|
25 { |
|
26 b32 <<= 8; |
|
27 b32 |= (PRUint32)src[i]; |
|
28 } |
|
29 |
|
30 for( i = 0; i < 4; i++ ) |
|
31 { |
|
32 dest[i] = base[ (PRUint32)((b32>>j) & 0x3F) ]; |
|
33 j -= 6; |
|
34 } |
|
35 |
|
36 return; |
|
37 } |
|
38 |
|
39 static void |
|
40 encode2to4 |
|
41 ( |
|
42 const unsigned char *src, |
|
43 unsigned char *dest |
|
44 ) |
|
45 { |
|
46 dest[0] = base[ (PRUint32)((src[0]>>2) & 0x3F) ]; |
|
47 dest[1] = base[ (PRUint32)(((src[0] & 0x03) << 4) | ((src[1] >> 4) & 0x0F)) ]; |
|
48 dest[2] = base[ (PRUint32)((src[1] & 0x0F) << 2) ]; |
|
49 dest[3] = (unsigned char)'='; |
|
50 return; |
|
51 } |
|
52 |
|
53 static void |
|
54 encode1to4 |
|
55 ( |
|
56 const unsigned char *src, |
|
57 unsigned char *dest |
|
58 ) |
|
59 { |
|
60 dest[0] = base[ (PRUint32)((src[0]>>2) & 0x3F) ]; |
|
61 dest[1] = base[ (PRUint32)((src[0] & 0x03) << 4) ]; |
|
62 dest[2] = (unsigned char)'='; |
|
63 dest[3] = (unsigned char)'='; |
|
64 return; |
|
65 } |
|
66 |
|
67 static void |
|
68 encode |
|
69 ( |
|
70 const unsigned char *src, |
|
71 PRUint32 srclen, |
|
72 unsigned char *dest |
|
73 ) |
|
74 { |
|
75 while( srclen >= 3 ) |
|
76 { |
|
77 encode3to4(src, dest); |
|
78 src += 3; |
|
79 dest += 4; |
|
80 srclen -= 3; |
|
81 } |
|
82 |
|
83 switch( srclen ) |
|
84 { |
|
85 case 2: |
|
86 encode2to4(src, dest); |
|
87 break; |
|
88 case 1: |
|
89 encode1to4(src, dest); |
|
90 break; |
|
91 case 0: |
|
92 break; |
|
93 default: |
|
94 PR_NOT_REACHED("coding error"); |
|
95 } |
|
96 |
|
97 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 if( 0 == srclen ) |
|
121 { |
|
122 size_t len = strlen(src); |
|
123 srclen = len; |
|
124 /* Detect truncation. */ |
|
125 if( srclen != len ) |
|
126 { |
|
127 return (char *)0; |
|
128 } |
|
129 } |
|
130 |
|
131 if( (char *)0 == dest ) |
|
132 { |
|
133 PRUint32 destlen; |
|
134 /* Ensure all PRUint32 values stay within range. */ |
|
135 if( srclen > (PR_UINT32_MAX/4) * 3 ) |
|
136 { |
|
137 return (char *)0; |
|
138 } |
|
139 destlen = ((srclen + 2)/3) * 4; |
|
140 dest = (char *)PR_MALLOC(destlen + 1); |
|
141 if( (char *)0 == dest ) |
|
142 { |
|
143 return (char *)0; |
|
144 } |
|
145 dest[ destlen ] = (char)0; /* null terminate */ |
|
146 } |
|
147 |
|
148 encode((const unsigned char *)src, srclen, (unsigned char *)dest); |
|
149 return dest; |
|
150 } |
|
151 |
|
152 static PRInt32 |
|
153 codetovalue |
|
154 ( |
|
155 unsigned char c |
|
156 ) |
|
157 { |
|
158 if( (c >= (unsigned char)'A') && (c <= (unsigned char)'Z') ) |
|
159 { |
|
160 return (PRInt32)(c - (unsigned char)'A'); |
|
161 } |
|
162 else if( (c >= (unsigned char)'a') && (c <= (unsigned char)'z') ) |
|
163 { |
|
164 return ((PRInt32)(c - (unsigned char)'a') +26); |
|
165 } |
|
166 else if( (c >= (unsigned char)'0') && (c <= (unsigned char)'9') ) |
|
167 { |
|
168 return ((PRInt32)(c - (unsigned char)'0') +52); |
|
169 } |
|
170 else if( (unsigned char)'+' == c ) |
|
171 { |
|
172 return (PRInt32)62; |
|
173 } |
|
174 else if( (unsigned char)'/' == c ) |
|
175 { |
|
176 return (PRInt32)63; |
|
177 } |
|
178 else |
|
179 { |
|
180 return -1; |
|
181 } |
|
182 } |
|
183 |
|
184 static PRStatus |
|
185 decode4to3 |
|
186 ( |
|
187 const unsigned char *src, |
|
188 unsigned char *dest |
|
189 ) |
|
190 { |
|
191 PRUint32 b32 = (PRUint32)0; |
|
192 PRInt32 bits; |
|
193 PRIntn i; |
|
194 |
|
195 for( i = 0; i < 4; i++ ) |
|
196 { |
|
197 bits = codetovalue(src[i]); |
|
198 if( bits < 0 ) |
|
199 { |
|
200 return PR_FAILURE; |
|
201 } |
|
202 |
|
203 b32 <<= 6; |
|
204 b32 |= bits; |
|
205 } |
|
206 |
|
207 dest[0] = (unsigned char)((b32 >> 16) & 0xFF); |
|
208 dest[1] = (unsigned char)((b32 >> 8) & 0xFF); |
|
209 dest[2] = (unsigned char)((b32 ) & 0xFF); |
|
210 |
|
211 return PR_SUCCESS; |
|
212 } |
|
213 |
|
214 static PRStatus |
|
215 decode3to2 |
|
216 ( |
|
217 const unsigned char *src, |
|
218 unsigned char *dest |
|
219 ) |
|
220 { |
|
221 PRUint32 b32 = (PRUint32)0; |
|
222 PRInt32 bits; |
|
223 PRUint32 ubits; |
|
224 |
|
225 bits = codetovalue(src[0]); |
|
226 if( bits < 0 ) |
|
227 { |
|
228 return PR_FAILURE; |
|
229 } |
|
230 |
|
231 b32 = (PRUint32)bits; |
|
232 b32 <<= 6; |
|
233 |
|
234 bits = codetovalue(src[1]); |
|
235 if( bits < 0 ) |
|
236 { |
|
237 return PR_FAILURE; |
|
238 } |
|
239 |
|
240 b32 |= (PRUint32)bits; |
|
241 b32 <<= 4; |
|
242 |
|
243 bits = codetovalue(src[2]); |
|
244 if( bits < 0 ) |
|
245 { |
|
246 return PR_FAILURE; |
|
247 } |
|
248 |
|
249 ubits = (PRUint32)bits; |
|
250 b32 |= (ubits >> 2); |
|
251 |
|
252 dest[0] = (unsigned char)((b32 >> 8) & 0xFF); |
|
253 dest[1] = (unsigned char)((b32 ) & 0xFF); |
|
254 |
|
255 return PR_SUCCESS; |
|
256 } |
|
257 |
|
258 static PRStatus |
|
259 decode2to1 |
|
260 ( |
|
261 const unsigned char *src, |
|
262 unsigned char *dest |
|
263 ) |
|
264 { |
|
265 PRUint32 b32; |
|
266 PRUint32 ubits; |
|
267 PRInt32 bits; |
|
268 |
|
269 bits = codetovalue(src[0]); |
|
270 if( bits < 0 ) |
|
271 { |
|
272 return PR_FAILURE; |
|
273 } |
|
274 |
|
275 ubits = (PRUint32)bits; |
|
276 b32 = (ubits << 2); |
|
277 |
|
278 bits = codetovalue(src[1]); |
|
279 if( bits < 0 ) |
|
280 { |
|
281 return PR_FAILURE; |
|
282 } |
|
283 |
|
284 ubits = (PRUint32)bits; |
|
285 b32 |= (ubits >> 4); |
|
286 |
|
287 dest[0] = (unsigned char)b32; |
|
288 |
|
289 return PR_SUCCESS; |
|
290 } |
|
291 |
|
292 static PRStatus |
|
293 decode |
|
294 ( |
|
295 const unsigned char *src, |
|
296 PRUint32 srclen, |
|
297 unsigned char *dest |
|
298 ) |
|
299 { |
|
300 PRStatus rv; |
|
301 |
|
302 while( srclen >= 4 ) |
|
303 { |
|
304 rv = decode4to3(src, dest); |
|
305 if( PR_SUCCESS != rv ) |
|
306 { |
|
307 return PR_FAILURE; |
|
308 } |
|
309 |
|
310 src += 4; |
|
311 dest += 3; |
|
312 srclen -= 4; |
|
313 } |
|
314 |
|
315 switch( srclen ) |
|
316 { |
|
317 case 3: |
|
318 rv = decode3to2(src, dest); |
|
319 break; |
|
320 case 2: |
|
321 rv = decode2to1(src, dest); |
|
322 break; |
|
323 case 1: |
|
324 rv = PR_FAILURE; |
|
325 break; |
|
326 case 0: |
|
327 rv = PR_SUCCESS; |
|
328 break; |
|
329 default: |
|
330 PR_NOT_REACHED("coding error"); |
|
331 } |
|
332 |
|
333 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 PRBool allocated = PR_FALSE; |
|
359 |
|
360 if( (char *)0 == src ) |
|
361 { |
|
362 return (char *)0; |
|
363 } |
|
364 |
|
365 if( 0 == srclen ) |
|
366 { |
|
367 size_t len = strlen(src); |
|
368 srclen = len; |
|
369 /* Detect truncation. */ |
|
370 if( srclen != len ) |
|
371 { |
|
372 return (char *)0; |
|
373 } |
|
374 } |
|
375 |
|
376 if( srclen && (0 == (srclen & 3)) ) |
|
377 { |
|
378 if( (char)'=' == src[ srclen-1 ] ) |
|
379 { |
|
380 if( (char)'=' == src[ srclen-2 ] ) |
|
381 { |
|
382 srclen -= 2; |
|
383 } |
|
384 else |
|
385 { |
|
386 srclen -= 1; |
|
387 } |
|
388 } |
|
389 } |
|
390 |
|
391 if( (char *)0 == dest ) |
|
392 { |
|
393 /* The following computes ((srclen * 3) / 4) without overflow. */ |
|
394 PRUint32 destlen = (srclen / 4) * 3 + ((srclen % 4) * 3) / 4; |
|
395 dest = (char *)PR_MALLOC(destlen + 1); |
|
396 if( (char *)0 == dest ) |
|
397 { |
|
398 return (char *)0; |
|
399 } |
|
400 dest[ destlen ] = (char)0; /* null terminate */ |
|
401 allocated = PR_TRUE; |
|
402 } |
|
403 |
|
404 status = decode((const unsigned char *)src, srclen, (unsigned char *)dest); |
|
405 if( PR_SUCCESS != status ) |
|
406 { |
|
407 if( PR_TRUE == allocated ) |
|
408 { |
|
409 PR_DELETE(dest); |
|
410 } |
|
411 |
|
412 return (char *)0; |
|
413 } |
|
414 |
|
415 return dest; |
|
416 } |