| OLD | NEW |
| (Empty) |
| 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 *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefg
hijklmnopqrstuvwxyz0123456789+/"; | |
| 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 } | |
| OLD | NEW |