1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/lib/libc/src/base64.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,416 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "plbase64.h" 1.10 +#include "prlog.h" /* For PR_NOT_REACHED */ 1.11 +#include "prmem.h" /* for malloc / PR_MALLOC */ 1.12 + 1.13 +#include <string.h> /* for strlen */ 1.14 + 1.15 +static unsigned char *base = (unsigned char *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 1.16 + 1.17 +static void 1.18 +encode3to4 1.19 +( 1.20 + const unsigned char *src, 1.21 + unsigned char *dest 1.22 +) 1.23 +{ 1.24 + PRUint32 b32 = (PRUint32)0; 1.25 + PRIntn i, j = 18; 1.26 + 1.27 + for( i = 0; i < 3; i++ ) 1.28 + { 1.29 + b32 <<= 8; 1.30 + b32 |= (PRUint32)src[i]; 1.31 + } 1.32 + 1.33 + for( i = 0; i < 4; i++ ) 1.34 + { 1.35 + dest[i] = base[ (PRUint32)((b32>>j) & 0x3F) ]; 1.36 + j -= 6; 1.37 + } 1.38 + 1.39 + return; 1.40 +} 1.41 + 1.42 +static void 1.43 +encode2to4 1.44 +( 1.45 + const unsigned char *src, 1.46 + unsigned char *dest 1.47 +) 1.48 +{ 1.49 + dest[0] = base[ (PRUint32)((src[0]>>2) & 0x3F) ]; 1.50 + dest[1] = base[ (PRUint32)(((src[0] & 0x03) << 4) | ((src[1] >> 4) & 0x0F)) ]; 1.51 + dest[2] = base[ (PRUint32)((src[1] & 0x0F) << 2) ]; 1.52 + dest[3] = (unsigned char)'='; 1.53 + return; 1.54 +} 1.55 + 1.56 +static void 1.57 +encode1to4 1.58 +( 1.59 + const unsigned char *src, 1.60 + unsigned char *dest 1.61 +) 1.62 +{ 1.63 + dest[0] = base[ (PRUint32)((src[0]>>2) & 0x3F) ]; 1.64 + dest[1] = base[ (PRUint32)((src[0] & 0x03) << 4) ]; 1.65 + dest[2] = (unsigned char)'='; 1.66 + dest[3] = (unsigned char)'='; 1.67 + return; 1.68 +} 1.69 + 1.70 +static void 1.71 +encode 1.72 +( 1.73 + const unsigned char *src, 1.74 + PRUint32 srclen, 1.75 + unsigned char *dest 1.76 +) 1.77 +{ 1.78 + while( srclen >= 3 ) 1.79 + { 1.80 + encode3to4(src, dest); 1.81 + src += 3; 1.82 + dest += 4; 1.83 + srclen -= 3; 1.84 + } 1.85 + 1.86 + switch( srclen ) 1.87 + { 1.88 + case 2: 1.89 + encode2to4(src, dest); 1.90 + break; 1.91 + case 1: 1.92 + encode1to4(src, dest); 1.93 + break; 1.94 + case 0: 1.95 + break; 1.96 + default: 1.97 + PR_NOT_REACHED("coding error"); 1.98 + } 1.99 + 1.100 + return; 1.101 +} 1.102 + 1.103 +/* 1.104 + * PL_Base64Encode 1.105 + * 1.106 + * If the destination argument is NULL, a return buffer is 1.107 + * allocated, and the data therein will be null-terminated. 1.108 + * If the destination argument is not NULL, it is assumed to 1.109 + * be of sufficient size, and the contents will not be null- 1.110 + * terminated by this routine. 1.111 + * 1.112 + * Returns null if the allocation fails. 1.113 + */ 1.114 + 1.115 +PR_IMPLEMENT(char *) 1.116 +PL_Base64Encode 1.117 +( 1.118 + const char *src, 1.119 + PRUint32 srclen, 1.120 + char *dest 1.121 +) 1.122 +{ 1.123 + if( 0 == srclen ) 1.124 + { 1.125 + size_t len = strlen(src); 1.126 + srclen = len; 1.127 + /* Detect truncation. */ 1.128 + if( srclen != len ) 1.129 + { 1.130 + return (char *)0; 1.131 + } 1.132 + } 1.133 + 1.134 + if( (char *)0 == dest ) 1.135 + { 1.136 + PRUint32 destlen; 1.137 + /* Ensure all PRUint32 values stay within range. */ 1.138 + if( srclen > (PR_UINT32_MAX/4) * 3 ) 1.139 + { 1.140 + return (char *)0; 1.141 + } 1.142 + destlen = ((srclen + 2)/3) * 4; 1.143 + dest = (char *)PR_MALLOC(destlen + 1); 1.144 + if( (char *)0 == dest ) 1.145 + { 1.146 + return (char *)0; 1.147 + } 1.148 + dest[ destlen ] = (char)0; /* null terminate */ 1.149 + } 1.150 + 1.151 + encode((const unsigned char *)src, srclen, (unsigned char *)dest); 1.152 + return dest; 1.153 +} 1.154 + 1.155 +static PRInt32 1.156 +codetovalue 1.157 +( 1.158 + unsigned char c 1.159 +) 1.160 +{ 1.161 + if( (c >= (unsigned char)'A') && (c <= (unsigned char)'Z') ) 1.162 + { 1.163 + return (PRInt32)(c - (unsigned char)'A'); 1.164 + } 1.165 + else if( (c >= (unsigned char)'a') && (c <= (unsigned char)'z') ) 1.166 + { 1.167 + return ((PRInt32)(c - (unsigned char)'a') +26); 1.168 + } 1.169 + else if( (c >= (unsigned char)'0') && (c <= (unsigned char)'9') ) 1.170 + { 1.171 + return ((PRInt32)(c - (unsigned char)'0') +52); 1.172 + } 1.173 + else if( (unsigned char)'+' == c ) 1.174 + { 1.175 + return (PRInt32)62; 1.176 + } 1.177 + else if( (unsigned char)'/' == c ) 1.178 + { 1.179 + return (PRInt32)63; 1.180 + } 1.181 + else 1.182 + { 1.183 + return -1; 1.184 + } 1.185 +} 1.186 + 1.187 +static PRStatus 1.188 +decode4to3 1.189 +( 1.190 + const unsigned char *src, 1.191 + unsigned char *dest 1.192 +) 1.193 +{ 1.194 + PRUint32 b32 = (PRUint32)0; 1.195 + PRInt32 bits; 1.196 + PRIntn i; 1.197 + 1.198 + for( i = 0; i < 4; i++ ) 1.199 + { 1.200 + bits = codetovalue(src[i]); 1.201 + if( bits < 0 ) 1.202 + { 1.203 + return PR_FAILURE; 1.204 + } 1.205 + 1.206 + b32 <<= 6; 1.207 + b32 |= bits; 1.208 + } 1.209 + 1.210 + dest[0] = (unsigned char)((b32 >> 16) & 0xFF); 1.211 + dest[1] = (unsigned char)((b32 >> 8) & 0xFF); 1.212 + dest[2] = (unsigned char)((b32 ) & 0xFF); 1.213 + 1.214 + return PR_SUCCESS; 1.215 +} 1.216 + 1.217 +static PRStatus 1.218 +decode3to2 1.219 +( 1.220 + const unsigned char *src, 1.221 + unsigned char *dest 1.222 +) 1.223 +{ 1.224 + PRUint32 b32 = (PRUint32)0; 1.225 + PRInt32 bits; 1.226 + PRUint32 ubits; 1.227 + 1.228 + bits = codetovalue(src[0]); 1.229 + if( bits < 0 ) 1.230 + { 1.231 + return PR_FAILURE; 1.232 + } 1.233 + 1.234 + b32 = (PRUint32)bits; 1.235 + b32 <<= 6; 1.236 + 1.237 + bits = codetovalue(src[1]); 1.238 + if( bits < 0 ) 1.239 + { 1.240 + return PR_FAILURE; 1.241 + } 1.242 + 1.243 + b32 |= (PRUint32)bits; 1.244 + b32 <<= 4; 1.245 + 1.246 + bits = codetovalue(src[2]); 1.247 + if( bits < 0 ) 1.248 + { 1.249 + return PR_FAILURE; 1.250 + } 1.251 + 1.252 + ubits = (PRUint32)bits; 1.253 + b32 |= (ubits >> 2); 1.254 + 1.255 + dest[0] = (unsigned char)((b32 >> 8) & 0xFF); 1.256 + dest[1] = (unsigned char)((b32 ) & 0xFF); 1.257 + 1.258 + return PR_SUCCESS; 1.259 +} 1.260 + 1.261 +static PRStatus 1.262 +decode2to1 1.263 +( 1.264 + const unsigned char *src, 1.265 + unsigned char *dest 1.266 +) 1.267 +{ 1.268 + PRUint32 b32; 1.269 + PRUint32 ubits; 1.270 + PRInt32 bits; 1.271 + 1.272 + bits = codetovalue(src[0]); 1.273 + if( bits < 0 ) 1.274 + { 1.275 + return PR_FAILURE; 1.276 + } 1.277 + 1.278 + ubits = (PRUint32)bits; 1.279 + b32 = (ubits << 2); 1.280 + 1.281 + bits = codetovalue(src[1]); 1.282 + if( bits < 0 ) 1.283 + { 1.284 + return PR_FAILURE; 1.285 + } 1.286 + 1.287 + ubits = (PRUint32)bits; 1.288 + b32 |= (ubits >> 4); 1.289 + 1.290 + dest[0] = (unsigned char)b32; 1.291 + 1.292 + return PR_SUCCESS; 1.293 +} 1.294 + 1.295 +static PRStatus 1.296 +decode 1.297 +( 1.298 + const unsigned char *src, 1.299 + PRUint32 srclen, 1.300 + unsigned char *dest 1.301 +) 1.302 +{ 1.303 + PRStatus rv; 1.304 + 1.305 + while( srclen >= 4 ) 1.306 + { 1.307 + rv = decode4to3(src, dest); 1.308 + if( PR_SUCCESS != rv ) 1.309 + { 1.310 + return PR_FAILURE; 1.311 + } 1.312 + 1.313 + src += 4; 1.314 + dest += 3; 1.315 + srclen -= 4; 1.316 + } 1.317 + 1.318 + switch( srclen ) 1.319 + { 1.320 + case 3: 1.321 + rv = decode3to2(src, dest); 1.322 + break; 1.323 + case 2: 1.324 + rv = decode2to1(src, dest); 1.325 + break; 1.326 + case 1: 1.327 + rv = PR_FAILURE; 1.328 + break; 1.329 + case 0: 1.330 + rv = PR_SUCCESS; 1.331 + break; 1.332 + default: 1.333 + PR_NOT_REACHED("coding error"); 1.334 + } 1.335 + 1.336 + return rv; 1.337 +} 1.338 + 1.339 +/* 1.340 + * PL_Base64Decode 1.341 + * 1.342 + * If the destination argument is NULL, a return buffer is 1.343 + * allocated and the data therein will be null-terminated. 1.344 + * If the destination argument is not null, it is assumed 1.345 + * to be of sufficient size, and the data will not be null- 1.346 + * terminated by this routine. 1.347 + * 1.348 + * Returns null if the allocation fails, or if the source string is 1.349 + * not well-formed. 1.350 + */ 1.351 + 1.352 +PR_IMPLEMENT(char *) 1.353 +PL_Base64Decode 1.354 +( 1.355 + const char *src, 1.356 + PRUint32 srclen, 1.357 + char *dest 1.358 +) 1.359 +{ 1.360 + PRStatus status; 1.361 + PRBool allocated = PR_FALSE; 1.362 + 1.363 + if( (char *)0 == src ) 1.364 + { 1.365 + return (char *)0; 1.366 + } 1.367 + 1.368 + if( 0 == srclen ) 1.369 + { 1.370 + size_t len = strlen(src); 1.371 + srclen = len; 1.372 + /* Detect truncation. */ 1.373 + if( srclen != len ) 1.374 + { 1.375 + return (char *)0; 1.376 + } 1.377 + } 1.378 + 1.379 + if( srclen && (0 == (srclen & 3)) ) 1.380 + { 1.381 + if( (char)'=' == src[ srclen-1 ] ) 1.382 + { 1.383 + if( (char)'=' == src[ srclen-2 ] ) 1.384 + { 1.385 + srclen -= 2; 1.386 + } 1.387 + else 1.388 + { 1.389 + srclen -= 1; 1.390 + } 1.391 + } 1.392 + } 1.393 + 1.394 + if( (char *)0 == dest ) 1.395 + { 1.396 + /* The following computes ((srclen * 3) / 4) without overflow. */ 1.397 + PRUint32 destlen = (srclen / 4) * 3 + ((srclen % 4) * 3) / 4; 1.398 + dest = (char *)PR_MALLOC(destlen + 1); 1.399 + if( (char *)0 == dest ) 1.400 + { 1.401 + return (char *)0; 1.402 + } 1.403 + dest[ destlen ] = (char)0; /* null terminate */ 1.404 + allocated = PR_TRUE; 1.405 + } 1.406 + 1.407 + status = decode((const unsigned char *)src, srclen, (unsigned char *)dest); 1.408 + if( PR_SUCCESS != status ) 1.409 + { 1.410 + if( PR_TRUE == allocated ) 1.411 + { 1.412 + PR_DELETE(dest); 1.413 + } 1.414 + 1.415 + return (char *)0; 1.416 + } 1.417 + 1.418 + return dest; 1.419 +}