base64.c (7027B)
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 encode3to4(const unsigned char* src, unsigned char* dest) { 15 PRUint32 b32 = (PRUint32)0; 16 PRIntn i, j = 18; 17 18 for (i = 0; i < 3; i++) { 19 b32 <<= 8; 20 b32 |= (PRUint32)src[i]; 21 } 22 23 for (i = 0; i < 4; i++) { 24 dest[i] = base[(PRUint32)((b32 >> j) & 0x3F)]; 25 j -= 6; 26 } 27 28 return; 29 } 30 31 static void encode2to4(const unsigned char* src, unsigned char* dest) { 32 dest[0] = base[(PRUint32)((src[0] >> 2) & 0x3F)]; 33 dest[1] = base[(PRUint32)(((src[0] & 0x03) << 4) | ((src[1] >> 4) & 0x0F))]; 34 dest[2] = base[(PRUint32)((src[1] & 0x0F) << 2)]; 35 dest[3] = (unsigned char)'='; 36 return; 37 } 38 39 static void encode1to4(const unsigned char* src, unsigned char* dest) { 40 dest[0] = base[(PRUint32)((src[0] >> 2) & 0x3F)]; 41 dest[1] = base[(PRUint32)((src[0] & 0x03) << 4)]; 42 dest[2] = (unsigned char)'='; 43 dest[3] = (unsigned char)'='; 44 return; 45 } 46 47 static void encode(const unsigned char* src, PRUint32 srclen, 48 unsigned char* dest) { 49 while (srclen >= 3) { 50 encode3to4(src, dest); 51 src += 3; 52 dest += 4; 53 srclen -= 3; 54 } 55 56 switch (srclen) { 57 case 2: 58 encode2to4(src, dest); 59 break; 60 case 1: 61 encode1to4(src, dest); 62 break; 63 case 0: 64 break; 65 default: 66 PR_NOT_REACHED("coding error"); 67 } 68 69 return; 70 } 71 72 /* 73 * PL_Base64Encode 74 * 75 * If the destination argument is NULL, a return buffer is 76 * allocated, and the data therein will be null-terminated. 77 * If the destination argument is not NULL, it is assumed to 78 * be of sufficient size, and the contents will not be null- 79 * terminated by this routine. 80 * 81 * Returns null if the allocation fails. 82 */ 83 84 PR_IMPLEMENT(char*) 85 PL_Base64Encode(const char* src, PRUint32 srclen, char* dest) { 86 if (0 == srclen) { 87 size_t len = strlen(src); 88 srclen = len; 89 /* Detect truncation. */ 90 if (srclen != len) { 91 return (char*)0; 92 } 93 } 94 95 if ((char*)0 == dest) { 96 PRUint32 destlen; 97 /* Ensure all PRUint32 values stay within range. */ 98 if (srclen > (PR_UINT32_MAX / 4) * 3) { 99 return (char*)0; 100 } 101 destlen = ((srclen + 2) / 3) * 4; 102 dest = (char*)PR_MALLOC(destlen + 1); 103 if ((char*)0 == dest) { 104 return (char*)0; 105 } 106 dest[destlen] = (char)0; /* null terminate */ 107 } 108 109 encode((const unsigned char*)src, srclen, (unsigned char*)dest); 110 return dest; 111 } 112 113 static PRInt32 codetovalue(unsigned char c) { 114 if ((c >= (unsigned char)'A') && (c <= (unsigned char)'Z')) { 115 return (PRInt32)(c - (unsigned char)'A'); 116 } else if ((c >= (unsigned char)'a') && (c <= (unsigned char)'z')) { 117 return ((PRInt32)(c - (unsigned char)'a') + 26); 118 } else if ((c >= (unsigned char)'0') && (c <= (unsigned char)'9')) { 119 return ((PRInt32)(c - (unsigned char)'0') + 52); 120 } else if ((unsigned char)'+' == c) { 121 return (PRInt32)62; 122 } else if ((unsigned char)'/' == c) { 123 return (PRInt32)63; 124 } else { 125 return -1; 126 } 127 } 128 129 static PRStatus decode4to3(const unsigned char* src, unsigned char* dest) { 130 PRUint32 b32 = (PRUint32)0; 131 PRInt32 bits; 132 PRIntn i; 133 134 for (i = 0; i < 4; i++) { 135 bits = codetovalue(src[i]); 136 if (bits < 0) { 137 return PR_FAILURE; 138 } 139 140 b32 <<= 6; 141 b32 |= bits; 142 } 143 144 dest[0] = (unsigned char)((b32 >> 16) & 0xFF); 145 dest[1] = (unsigned char)((b32 >> 8) & 0xFF); 146 dest[2] = (unsigned char)((b32) & 0xFF); 147 148 return PR_SUCCESS; 149 } 150 151 static PRStatus decode3to2(const unsigned char* src, unsigned char* dest) { 152 PRUint32 b32 = (PRUint32)0; 153 PRInt32 bits; 154 PRUint32 ubits; 155 156 bits = codetovalue(src[0]); 157 if (bits < 0) { 158 return PR_FAILURE; 159 } 160 161 b32 = (PRUint32)bits; 162 b32 <<= 6; 163 164 bits = codetovalue(src[1]); 165 if (bits < 0) { 166 return PR_FAILURE; 167 } 168 169 b32 |= (PRUint32)bits; 170 b32 <<= 4; 171 172 bits = codetovalue(src[2]); 173 if (bits < 0) { 174 return PR_FAILURE; 175 } 176 177 ubits = (PRUint32)bits; 178 b32 |= (ubits >> 2); 179 180 dest[0] = (unsigned char)((b32 >> 8) & 0xFF); 181 dest[1] = (unsigned char)((b32) & 0xFF); 182 183 return PR_SUCCESS; 184 } 185 186 static PRStatus decode2to1(const unsigned char* src, unsigned char* dest) { 187 PRUint32 b32; 188 PRUint32 ubits; 189 PRInt32 bits; 190 191 bits = codetovalue(src[0]); 192 if (bits < 0) { 193 return PR_FAILURE; 194 } 195 196 ubits = (PRUint32)bits; 197 b32 = (ubits << 2); 198 199 bits = codetovalue(src[1]); 200 if (bits < 0) { 201 return PR_FAILURE; 202 } 203 204 ubits = (PRUint32)bits; 205 b32 |= (ubits >> 4); 206 207 dest[0] = (unsigned char)b32; 208 209 return PR_SUCCESS; 210 } 211 212 static PRStatus decode(const unsigned char* src, PRUint32 srclen, 213 unsigned char* dest) { 214 PRStatus rv; 215 216 while (srclen >= 4) { 217 rv = decode4to3(src, dest); 218 if (PR_SUCCESS != rv) { 219 return PR_FAILURE; 220 } 221 222 src += 4; 223 dest += 3; 224 srclen -= 4; 225 } 226 227 switch (srclen) { 228 case 3: 229 rv = decode3to2(src, dest); 230 break; 231 case 2: 232 rv = decode2to1(src, dest); 233 break; 234 case 1: 235 rv = PR_FAILURE; 236 break; 237 case 0: 238 rv = PR_SUCCESS; 239 break; 240 default: 241 PR_NOT_REACHED("coding error"); 242 } 243 244 return rv; 245 } 246 247 /* 248 * PL_Base64Decode 249 * 250 * If the destination argument is NULL, a return buffer is 251 * allocated and the data therein will be null-terminated. 252 * If the destination argument is not null, it is assumed 253 * to be of sufficient size, and the data will not be null- 254 * terminated by this routine. 255 * 256 * Returns null if the allocation fails, or if the source string is 257 * not well-formed. 258 */ 259 260 PR_IMPLEMENT(char*) 261 PL_Base64Decode(const char* src, PRUint32 srclen, char* dest) { 262 PRStatus status; 263 PRBool allocated = PR_FALSE; 264 265 if ((char*)0 == src) { 266 return (char*)0; 267 } 268 269 if (0 == srclen) { 270 size_t len = strlen(src); 271 srclen = len; 272 /* Detect truncation. */ 273 if (srclen != len) { 274 return (char*)0; 275 } 276 } 277 278 if (srclen && (0 == (srclen & 3))) { 279 if ((char)'=' == src[srclen - 1]) { 280 if ((char)'=' == src[srclen - 2]) { 281 srclen -= 2; 282 } else { 283 srclen -= 1; 284 } 285 } 286 } 287 288 if ((char*)0 == dest) { 289 /* The following computes ((srclen * 3) / 4) without overflow. */ 290 PRUint32 destlen = (srclen / 4) * 3 + ((srclen % 4) * 3) / 4; 291 dest = (char*)PR_MALLOC(destlen + 1); 292 if ((char*)0 == dest) { 293 return (char*)0; 294 } 295 dest[destlen] = (char)0; /* null terminate */ 296 allocated = PR_TRUE; 297 } 298 299 status = decode((const unsigned char*)src, srclen, (unsigned char*)dest); 300 if (PR_SUCCESS != status) { 301 if (PR_TRUE == allocated) { 302 PR_DELETE(dest); 303 } 304 305 return (char*)0; 306 } 307 308 return dest; 309 }