| OLD | NEW |
| (Empty) |
| 1 /* This Source Code Form is subject to the terms of the Mozilla Public | |
| 2 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
| 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
| 4 | |
| 5 /* | |
| 6 * Base64 encoding (binary to ascii). | |
| 7 */ | |
| 8 | |
| 9 #include "nssb64.h" | |
| 10 #include "nspr.h" | |
| 11 #include "secitem.h" | |
| 12 #include "secerr.h" | |
| 13 | |
| 14 /* | |
| 15 * XXX See the big comment at the top of nssb64d.c about moving the | |
| 16 * bulk of this code over into NSPR (the PL part). It all applies | |
| 17 * here but I didn't want to duplicate it, to avoid divergence problems. | |
| 18 */ | |
| 19 | |
| 20 /* | |
| 21 ************************************************************** | |
| 22 * XXX Beginning of base64 encoding code to be moved into NSPR. | |
| 23 */ | |
| 24 | |
| 25 | |
| 26 struct PLBase64EncodeStateStr { | |
| 27 unsigned chunks; | |
| 28 unsigned saved; | |
| 29 unsigned char buf[3]; | |
| 30 }; | |
| 31 | |
| 32 /* | |
| 33 * This typedef would belong in the NSPR header file (i.e. plbase64.h). | |
| 34 */ | |
| 35 typedef struct PLBase64EncoderStr PLBase64Encoder; | |
| 36 | |
| 37 /* | |
| 38 * The following implementation of base64 encoding was based on code | |
| 39 * found in libmime (specifically, in mimeenc.c). It has been adapted to | |
| 40 * use PR types and naming as well as to provide other necessary semantics | |
| 41 * (like buffer-in/buffer-out in addition to "streaming" without undue | |
| 42 * performance hit of extra copying if you made the buffer versions | |
| 43 * use the output_fn). It also incorporates some aspects of the current | |
| 44 * NSPR base64 encoding code. As such, you may find similarities to | |
| 45 * both of those implementations. I tried to use names that reflected | |
| 46 * the original code when possible. For this reason you may find some | |
| 47 * inconsistencies -- libmime used lots of "in" and "out" whereas the | |
| 48 * NSPR version uses "src" and "dest"; sometimes I changed one to the other | |
| 49 * and sometimes I left them when I thought the subroutines were at least | |
| 50 * self-consistent. | |
| 51 */ | |
| 52 | |
| 53 PR_BEGIN_EXTERN_C | |
| 54 | |
| 55 /* | |
| 56 * Opaque object used by the encoder to store state. | |
| 57 */ | |
| 58 struct PLBase64EncoderStr { | |
| 59 /* | |
| 60 * The one or two bytes pending. (We need 3 to create a "token", | |
| 61 * and hold the leftovers here. in_buffer_count is *only* ever | |
| 62 * 0, 1, or 2. | |
| 63 */ | |
| 64 unsigned char in_buffer[2]; | |
| 65 int in_buffer_count; | |
| 66 | |
| 67 /* | |
| 68 * If the caller wants linebreaks added, line_length specifies | |
| 69 * where they come out. It must be a multiple of 4; if the caller | |
| 70 * provides one that isn't, we round it down to the nearest | |
| 71 * multiple of 4. | |
| 72 * | |
| 73 * The value of current_column counts how many characters have been | |
| 74 * added since the last linebreaks (or since the beginning, on the | |
| 75 * first line). It is also always a multiple of 4; it is unused when | |
| 76 * line_length is 0. | |
| 77 */ | |
| 78 PRUint32 line_length; | |
| 79 PRUint32 current_column; | |
| 80 | |
| 81 /* | |
| 82 * Where to write the encoded data (used when streaming, not when | |
| 83 * doing all in-memory (buffer) operations). | |
| 84 * | |
| 85 * Note that this definition is chosen to be compatible with PR_Write. | |
| 86 */ | |
| 87 PRInt32 (*output_fn) (void *output_arg, const char *buf, PRInt32 size); | |
| 88 void *output_arg; | |
| 89 | |
| 90 /* | |
| 91 * Where the encoded output goes -- either temporarily (in the streaming | |
| 92 * case, staged here before it goes to the output function) or what will | |
| 93 * be the entire buffered result for users of the buffer version. | |
| 94 */ | |
| 95 char *output_buffer; | |
| 96 PRUint32 output_buflen; /* the total length of allocated buffer */ | |
| 97 PRUint32 output_length; /* the length that is currently populated */ | |
| 98 }; | |
| 99 | |
| 100 PR_END_EXTERN_C | |
| 101 | |
| 102 | |
| 103 /* | |
| 104 * Table to convert a binary value to its corresponding ascii "code". | |
| 105 */ | |
| 106 static unsigned char base64_valuetocode[64] = | |
| 107 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | |
| 108 | |
| 109 #define B64_PAD '=' | |
| 110 #define B64_CR '\r' | |
| 111 #define B64_LF '\n' | |
| 112 | |
| 113 static PRStatus | |
| 114 pl_base64_encode_buffer (PLBase64Encoder *data, const unsigned char *in, | |
| 115 PRUint32 size) | |
| 116 { | |
| 117 const unsigned char *end = in + size; | |
| 118 char *out = data->output_buffer + data->output_length; | |
| 119 unsigned int i = data->in_buffer_count; | |
| 120 PRUint32 n = 0; | |
| 121 int off; | |
| 122 PRUint32 output_threshold; | |
| 123 | |
| 124 /* If this input buffer is too small, wait until next time. */ | |
| 125 if (size < (3 - i)) { | |
| 126 data->in_buffer[i++] = in[0]; | |
| 127 if (size > 1) | |
| 128 data->in_buffer[i++] = in[1]; | |
| 129 PR_ASSERT(i < 3); | |
| 130 data->in_buffer_count = i; | |
| 131 return PR_SUCCESS; | |
| 132 } | |
| 133 | |
| 134 /* If there are bytes that were put back last time, take them now. */ | |
| 135 if (i > 0) { | |
| 136 n = data->in_buffer[0]; | |
| 137 if (i > 1) | |
| 138 n = (n << 8) | data->in_buffer[1]; | |
| 139 data->in_buffer_count = 0; | |
| 140 } | |
| 141 | |
| 142 /* If our total is not a multiple of three, put one or two bytes back. */ | |
| 143 off = (size + i) % 3; | |
| 144 if (off > 0) { | |
| 145 size -= off; | |
| 146 data->in_buffer[0] = in[size]; | |
| 147 if (off > 1) | |
| 148 data->in_buffer[1] = in[size + 1]; | |
| 149 data->in_buffer_count = off; | |
| 150 end -= off; | |
| 151 } | |
| 152 | |
| 153 output_threshold = data->output_buflen - 3; | |
| 154 | |
| 155 /* | |
| 156 * Populate the output buffer with base64 data, one line (or buffer) | |
| 157 * at a time. | |
| 158 */ | |
| 159 while (in < end) { | |
| 160 int j, k; | |
| 161 | |
| 162 while (i < 3) { | |
| 163 n = (n << 8) | *in++; | |
| 164 i++; | |
| 165 } | |
| 166 i = 0; | |
| 167 | |
| 168 if (data->line_length > 0) { | |
| 169 if (data->current_column >= data->line_length) { | |
| 170 data->current_column = 0; | |
| 171 *out++ = B64_CR; | |
| 172 *out++ = B64_LF; | |
| 173 data->output_length += 2; | |
| 174 } | |
| 175 data->current_column += 4; /* the bytes we are about to add */ | |
| 176 } | |
| 177 | |
| 178 for (j = 18; j >= 0; j -= 6) { | |
| 179 k = (n >> j) & 0x3F; | |
| 180 *out++ = base64_valuetocode[k]; | |
| 181 } | |
| 182 n = 0; | |
| 183 data->output_length += 4; | |
| 184 | |
| 185 if (data->output_length >= output_threshold) { | |
| 186 PR_ASSERT(data->output_length <= data->output_buflen); | |
| 187 if (data->output_fn != NULL) { | |
| 188 PRInt32 output_result; | |
| 189 | |
| 190 output_result = data->output_fn (data->output_arg, | |
| 191 data->output_buffer, | |
| 192 (PRInt32) data->output_length); | |
| 193 if (output_result < 0) | |
| 194 return PR_FAILURE; | |
| 195 | |
| 196 out = data->output_buffer; | |
| 197 data->output_length = 0; | |
| 198 } else { | |
| 199 /* | |
| 200 * Check that we are about to exit the loop. (Since we | |
| 201 * are over the threshold, there isn't enough room in the | |
| 202 * output buffer for another trip around.) | |
| 203 */ | |
| 204 PR_ASSERT(in == end); | |
| 205 if (in < end) { | |
| 206 PR_SetError (PR_BUFFER_OVERFLOW_ERROR, 0); | |
| 207 return PR_FAILURE; | |
| 208 } | |
| 209 } | |
| 210 } | |
| 211 } | |
| 212 | |
| 213 return PR_SUCCESS; | |
| 214 } | |
| 215 | |
| 216 static PRStatus | |
| 217 pl_base64_encode_flush (PLBase64Encoder *data) | |
| 218 { | |
| 219 int i = data->in_buffer_count; | |
| 220 | |
| 221 if (i == 0 && data->output_length == 0) | |
| 222 return PR_SUCCESS; | |
| 223 | |
| 224 if (i > 0) { | |
| 225 char *out = data->output_buffer + data->output_length; | |
| 226 PRUint32 n; | |
| 227 int j, k; | |
| 228 | |
| 229 n = ((PRUint32) data->in_buffer[0]) << 16; | |
| 230 if (i > 1) | |
| 231 n |= ((PRUint32) data->in_buffer[1] << 8); | |
| 232 | |
| 233 data->in_buffer_count = 0; | |
| 234 | |
| 235 if (data->line_length > 0) { | |
| 236 if (data->current_column >= data->line_length) { | |
| 237 data->current_column = 0; | |
| 238 *out++ = B64_CR; | |
| 239 *out++ = B64_LF; | |
| 240 data->output_length += 2; | |
| 241 } | |
| 242 } | |
| 243 | |
| 244 /* | |
| 245 * This will fill in more than we really have data for, but the | |
| 246 * valid parts will end up in the correct position and the extras | |
| 247 * will be over-written with pad characters below. | |
| 248 */ | |
| 249 for (j = 18; j >= 0; j -= 6) { | |
| 250 k = (n >> j) & 0x3F; | |
| 251 *out++ = base64_valuetocode[k]; | |
| 252 } | |
| 253 | |
| 254 /* Pad with equal-signs. */ | |
| 255 if (i == 1) | |
| 256 out[-2] = B64_PAD; | |
| 257 out[-1] = B64_PAD; | |
| 258 | |
| 259 data->output_length += 4; | |
| 260 } | |
| 261 | |
| 262 if (data->output_fn != NULL) { | |
| 263 PRInt32 output_result; | |
| 264 | |
| 265 output_result = data->output_fn (data->output_arg, data->output_buffer, | |
| 266 (PRInt32) data->output_length); | |
| 267 data->output_length = 0; | |
| 268 | |
| 269 if (output_result < 0) | |
| 270 return PR_FAILURE; | |
| 271 } | |
| 272 | |
| 273 return PR_SUCCESS; | |
| 274 } | |
| 275 | |
| 276 | |
| 277 /* | |
| 278 * The maximum space needed to hold the output of the encoder given input | |
| 279 * data of length "size", and allowing for CRLF added at least every | |
| 280 * line_length bytes (we will add it at nearest lower multiple of 4). | |
| 281 * There is no trailing CRLF. | |
| 282 */ | |
| 283 static PRUint32 | |
| 284 PL_Base64MaxEncodedLength (PRUint32 size, PRUint32 line_length) | |
| 285 { | |
| 286 PRUint32 tokens, tokens_per_line, full_lines, line_break_chars, remainder; | |
| 287 | |
| 288 tokens = (size + 2) / 3; | |
| 289 | |
| 290 if (line_length == 0) | |
| 291 return tokens * 4; | |
| 292 | |
| 293 if (line_length < 4) /* too small! */ | |
| 294 line_length = 4; | |
| 295 | |
| 296 tokens_per_line = line_length / 4; | |
| 297 full_lines = tokens / tokens_per_line; | |
| 298 remainder = (tokens - (full_lines * tokens_per_line)) * 4; | |
| 299 line_break_chars = full_lines * 2; | |
| 300 if (remainder == 0) | |
| 301 line_break_chars -= 2; | |
| 302 | |
| 303 return (full_lines * tokens_per_line * 4) + line_break_chars + remainder; | |
| 304 } | |
| 305 | |
| 306 | |
| 307 /* | |
| 308 * A distinct internal creation function for the buffer version to use. | |
| 309 * (It does not want to specify an output_fn, and we want the normal | |
| 310 * Create function to require that.) All common initialization of the | |
| 311 * encoding context should be done *here*. | |
| 312 * | |
| 313 * Save "line_length", rounded down to nearest multiple of 4 (if not | |
| 314 * already even multiple). Allocate output_buffer, if not provided -- | |
| 315 * based on given size if specified, otherwise based on line_length. | |
| 316 */ | |
| 317 static PLBase64Encoder * | |
| 318 pl_base64_create_encoder (PRUint32 line_length, char *output_buffer, | |
| 319 PRUint32 output_buflen) | |
| 320 { | |
| 321 PLBase64Encoder *data; | |
| 322 PRUint32 line_tokens; | |
| 323 | |
| 324 data = PR_NEWZAP(PLBase64Encoder); | |
| 325 if (data == NULL) | |
| 326 return NULL; | |
| 327 | |
| 328 if (line_length > 0 && line_length < 4) /* too small! */ | |
| 329 line_length = 4; | |
| 330 | |
| 331 line_tokens = line_length / 4; | |
| 332 data->line_length = line_tokens * 4; | |
| 333 | |
| 334 if (output_buffer == NULL) { | |
| 335 if (output_buflen == 0) { | |
| 336 if (data->line_length > 0) /* need to include room for CRLF */ | |
| 337 output_buflen = data->line_length + 2; | |
| 338 else | |
| 339 output_buflen = 64; /* XXX what is a good size? */ | |
| 340 } | |
| 341 | |
| 342 output_buffer = (char *) PR_Malloc(output_buflen); | |
| 343 if (output_buffer == NULL) { | |
| 344 PR_Free(data); | |
| 345 return NULL; | |
| 346 } | |
| 347 } | |
| 348 | |
| 349 data->output_buffer = output_buffer; | |
| 350 data->output_buflen = output_buflen; | |
| 351 return data; | |
| 352 } | |
| 353 | |
| 354 /* | |
| 355 * Function to start a base64 encoding context. | |
| 356 * An "output_fn" is required; the "output_arg" parameter to that is optional. | |
| 357 * If linebreaks in the encoded output are desired, "line_length" specifies | |
| 358 * where to place them -- it will be rounded down to the nearest multiple of 4 | |
| 359 * (if it is not already an even multiple of 4). If it is zero, no linebreaks | |
| 360 * will be added. (FYI, a linebreak is CRLF -- two characters.) | |
| 361 */ | |
| 362 static PLBase64Encoder * | |
| 363 PL_CreateBase64Encoder (PRInt32 (*output_fn) (void *, const char *, PRInt32), | |
| 364 void *output_arg, PRUint32 line_length) | |
| 365 { | |
| 366 PLBase64Encoder *data; | |
| 367 | |
| 368 if (output_fn == NULL) { | |
| 369 PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0); | |
| 370 return NULL; | |
| 371 } | |
| 372 | |
| 373 data = pl_base64_create_encoder (line_length, NULL, 0); | |
| 374 if (data == NULL) | |
| 375 return NULL; | |
| 376 | |
| 377 data->output_fn = output_fn; | |
| 378 data->output_arg = output_arg; | |
| 379 | |
| 380 return data; | |
| 381 } | |
| 382 | |
| 383 | |
| 384 /* | |
| 385 * Push data through the encoder, causing the output_fn (provided to Create) | |
| 386 * to be called with the encoded data. | |
| 387 */ | |
| 388 static PRStatus | |
| 389 PL_UpdateBase64Encoder (PLBase64Encoder *data, const unsigned char *buffer, | |
| 390 PRUint32 size) | |
| 391 { | |
| 392 /* XXX Should we do argument checking only in debug build? */ | |
| 393 if (data == NULL || buffer == NULL || size == 0) { | |
| 394 PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0); | |
| 395 return PR_FAILURE; | |
| 396 } | |
| 397 | |
| 398 return pl_base64_encode_buffer (data, buffer, size); | |
| 399 } | |
| 400 | |
| 401 | |
| 402 /* | |
| 403 * When you're done encoding, call this to free the data. If "abort_p" | |
| 404 * is false, then calling this may cause the output_fn to be called | |
| 405 * one last time (as the last buffered data is flushed out). | |
| 406 */ | |
| 407 static PRStatus | |
| 408 PL_DestroyBase64Encoder (PLBase64Encoder *data, PRBool abort_p) | |
| 409 { | |
| 410 PRStatus status = PR_SUCCESS; | |
| 411 | |
| 412 /* XXX Should we do argument checking only in debug build? */ | |
| 413 if (data == NULL) { | |
| 414 PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0); | |
| 415 return PR_FAILURE; | |
| 416 } | |
| 417 | |
| 418 /* Flush out the last few buffered characters. */ | |
| 419 if (!abort_p) | |
| 420 status = pl_base64_encode_flush (data); | |
| 421 | |
| 422 if (data->output_buffer != NULL) | |
| 423 PR_Free(data->output_buffer); | |
| 424 PR_Free(data); | |
| 425 | |
| 426 return status; | |
| 427 } | |
| 428 | |
| 429 | |
| 430 /* | |
| 431 * Perform base64 encoding from an input buffer to an output buffer. | |
| 432 * The output buffer can be provided (as "dest"); you can also pass in | |
| 433 * a NULL and this function will allocate a buffer large enough for you, | |
| 434 * and return it. If you do provide the output buffer, you must also | |
| 435 * provide the maximum length of that buffer (as "maxdestlen"). | |
| 436 * The actual encoded length of output will be returned to you in | |
| 437 * "output_destlen". | |
| 438 * | |
| 439 * If linebreaks in the encoded output are desired, "line_length" specifies | |
| 440 * where to place them -- it will be rounded down to the nearest multiple of 4 | |
| 441 * (if it is not already an even multiple of 4). If it is zero, no linebreaks | |
| 442 * will be added. (FYI, a linebreak is CRLF -- two characters.) | |
| 443 * | |
| 444 * Return value is NULL on error, the output buffer (allocated or provided) | |
| 445 * otherwise. | |
| 446 */ | |
| 447 static char * | |
| 448 PL_Base64EncodeBuffer (const unsigned char *src, PRUint32 srclen, | |
| 449 PRUint32 line_length, char *dest, PRUint32 maxdestlen, | |
| 450 PRUint32 *output_destlen) | |
| 451 { | |
| 452 PRUint32 need_length; | |
| 453 PLBase64Encoder *data = NULL; | |
| 454 PRStatus status; | |
| 455 | |
| 456 PR_ASSERT(srclen > 0); | |
| 457 if (srclen == 0) | |
| 458 return dest; | |
| 459 | |
| 460 /* | |
| 461 * How much space could we possibly need for encoding this input? | |
| 462 */ | |
| 463 need_length = PL_Base64MaxEncodedLength (srclen, line_length); | |
| 464 | |
| 465 /* | |
| 466 * Make sure we have at least that much, if output buffer provided. | |
| 467 */ | |
| 468 if (dest != NULL) { | |
| 469 PR_ASSERT(maxdestlen >= need_length); | |
| 470 if (maxdestlen < need_length) { | |
| 471 PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0); | |
| 472 return NULL; | |
| 473 } | |
| 474 } else { | |
| 475 maxdestlen = need_length; | |
| 476 } | |
| 477 | |
| 478 data = pl_base64_create_encoder(line_length, dest, maxdestlen); | |
| 479 if (data == NULL) | |
| 480 return NULL; | |
| 481 | |
| 482 status = pl_base64_encode_buffer (data, src, srclen); | |
| 483 | |
| 484 /* | |
| 485 * We do not wait for Destroy to flush, because Destroy will also | |
| 486 * get rid of our encoder context, which we need to look at first! | |
| 487 */ | |
| 488 if (status == PR_SUCCESS) | |
| 489 status = pl_base64_encode_flush (data); | |
| 490 | |
| 491 if (status != PR_SUCCESS) { | |
| 492 (void) PL_DestroyBase64Encoder (data, PR_TRUE); | |
| 493 return NULL; | |
| 494 } | |
| 495 | |
| 496 dest = data->output_buffer; | |
| 497 | |
| 498 /* Must clear this or Destroy will free it. */ | |
| 499 data->output_buffer = NULL; | |
| 500 | |
| 501 *output_destlen = data->output_length; | |
| 502 status = PL_DestroyBase64Encoder (data, PR_FALSE); | |
| 503 if (status == PR_FAILURE) { | |
| 504 PR_Free(dest); | |
| 505 return NULL; | |
| 506 } | |
| 507 | |
| 508 return dest; | |
| 509 } | |
| 510 | |
| 511 /* | |
| 512 * XXX End of base64 encoding code to be moved into NSPR. | |
| 513 ******************************************************** | |
| 514 */ | |
| 515 | |
| 516 /* | |
| 517 * This is the beginning of the NSS cover functions. These will | |
| 518 * provide the interface we want to expose as NSS-ish. For example, | |
| 519 * they will operate on our Items, do any special handling or checking | |
| 520 * we want to do, etc. | |
| 521 */ | |
| 522 | |
| 523 | |
| 524 PR_BEGIN_EXTERN_C | |
| 525 | |
| 526 /* | |
| 527 * A boring cover structure for now. Perhaps someday it will include | |
| 528 * some more interesting fields. | |
| 529 */ | |
| 530 struct NSSBase64EncoderStr { | |
| 531 PLBase64Encoder *pl_data; | |
| 532 }; | |
| 533 | |
| 534 PR_END_EXTERN_C | |
| 535 | |
| 536 | |
| 537 /* | |
| 538 * Function to start a base64 encoding context. | |
| 539 */ | |
| 540 NSSBase64Encoder * | |
| 541 NSSBase64Encoder_Create (PRInt32 (*output_fn) (void *, const char *, PRInt32), | |
| 542 void *output_arg) | |
| 543 { | |
| 544 PLBase64Encoder *pl_data; | |
| 545 NSSBase64Encoder *nss_data; | |
| 546 | |
| 547 nss_data = PORT_ZNew(NSSBase64Encoder); | |
| 548 if (nss_data == NULL) | |
| 549 return NULL; | |
| 550 | |
| 551 pl_data = PL_CreateBase64Encoder (output_fn, output_arg, 64); | |
| 552 if (pl_data == NULL) { | |
| 553 PORT_Free(nss_data); | |
| 554 return NULL; | |
| 555 } | |
| 556 | |
| 557 nss_data->pl_data = pl_data; | |
| 558 return nss_data; | |
| 559 } | |
| 560 | |
| 561 | |
| 562 /* | |
| 563 * Push data through the encoder, causing the output_fn (provided to Create) | |
| 564 * to be called with the encoded data. | |
| 565 */ | |
| 566 SECStatus | |
| 567 NSSBase64Encoder_Update (NSSBase64Encoder *data, const unsigned char *buffer, | |
| 568 PRUint32 size) | |
| 569 { | |
| 570 PRStatus pr_status; | |
| 571 | |
| 572 /* XXX Should we do argument checking only in debug build? */ | |
| 573 if (data == NULL) { | |
| 574 PORT_SetError (SEC_ERROR_INVALID_ARGS); | |
| 575 return SECFailure; | |
| 576 } | |
| 577 | |
| 578 pr_status = PL_UpdateBase64Encoder (data->pl_data, buffer, size); | |
| 579 if (pr_status == PR_FAILURE) | |
| 580 return SECFailure; | |
| 581 | |
| 582 return SECSuccess; | |
| 583 } | |
| 584 | |
| 585 | |
| 586 /* | |
| 587 * When you're done encoding, call this to free the data. If "abort_p" | |
| 588 * is false, then calling this may cause the output_fn to be called | |
| 589 * one last time (as the last buffered data is flushed out). | |
| 590 */ | |
| 591 SECStatus | |
| 592 NSSBase64Encoder_Destroy (NSSBase64Encoder *data, PRBool abort_p) | |
| 593 { | |
| 594 PRStatus pr_status; | |
| 595 | |
| 596 /* XXX Should we do argument checking only in debug build? */ | |
| 597 if (data == NULL) { | |
| 598 PORT_SetError (SEC_ERROR_INVALID_ARGS); | |
| 599 return SECFailure; | |
| 600 } | |
| 601 | |
| 602 pr_status = PL_DestroyBase64Encoder (data->pl_data, abort_p); | |
| 603 | |
| 604 PORT_Free(data); | |
| 605 | |
| 606 if (pr_status == PR_FAILURE) | |
| 607 return SECFailure; | |
| 608 | |
| 609 return SECSuccess; | |
| 610 } | |
| 611 | |
| 612 | |
| 613 /* | |
| 614 * Perform base64 encoding of binary data "inItem" to an ascii string. | |
| 615 * The output buffer may be provided (as "outStrOpt"); you can also pass | |
| 616 * in a NULL and the buffer will be allocated for you. The result will | |
| 617 * be null-terminated, and if the buffer is provided, "maxOutLen" must | |
| 618 * specify the maximum length of the buffer and will be checked to | |
| 619 * supply sufficient space space for the encoded result. (If "outStrOpt" | |
| 620 * is NULL, "maxOutLen" is ignored.) | |
| 621 * | |
| 622 * If "outStrOpt" is NULL, allocation will happen out of the passed-in | |
| 623 * "arenaOpt", if *it* is non-NULL, otherwise standard allocation (heap) | |
| 624 * will be used. | |
| 625 * | |
| 626 * Return value is NULL on error, the output buffer (allocated or provided) | |
| 627 * otherwise. | |
| 628 */ | |
| 629 char * | |
| 630 NSSBase64_EncodeItem (PLArenaPool *arenaOpt, char *outStrOpt, | |
| 631 unsigned int maxOutLen, SECItem *inItem) | |
| 632 { | |
| 633 char *out_string = outStrOpt; | |
| 634 PRUint32 max_out_len; | |
| 635 PRUint32 out_len = 0; | |
| 636 void *mark = NULL; | |
| 637 char *dummy; | |
| 638 | |
| 639 PORT_Assert(inItem != NULL && inItem->data != NULL && inItem->len != 0); | |
| 640 if (inItem == NULL || inItem->data == NULL || inItem->len == 0) { | |
| 641 PORT_SetError (SEC_ERROR_INVALID_ARGS); | |
| 642 return NULL; | |
| 643 } | |
| 644 | |
| 645 max_out_len = PL_Base64MaxEncodedLength (inItem->len, 64); | |
| 646 | |
| 647 if (arenaOpt != NULL) | |
| 648 mark = PORT_ArenaMark (arenaOpt); | |
| 649 | |
| 650 if (out_string == NULL) { | |
| 651 if (arenaOpt != NULL) | |
| 652 out_string = PORT_ArenaAlloc (arenaOpt, max_out_len + 1); | |
| 653 else | |
| 654 out_string = PORT_Alloc (max_out_len + 1); | |
| 655 | |
| 656 if (out_string == NULL) { | |
| 657 if (arenaOpt != NULL) | |
| 658 PORT_ArenaRelease (arenaOpt, mark); | |
| 659 return NULL; | |
| 660 } | |
| 661 } else { | |
| 662 if ((max_out_len + 1) > maxOutLen) { | |
| 663 PORT_SetError (SEC_ERROR_OUTPUT_LEN); | |
| 664 return NULL; | |
| 665 } | |
| 666 max_out_len = maxOutLen; | |
| 667 } | |
| 668 | |
| 669 | |
| 670 dummy = PL_Base64EncodeBuffer (inItem->data, inItem->len, 64, | |
| 671 out_string, max_out_len, &out_len); | |
| 672 if (dummy == NULL) { | |
| 673 if (arenaOpt != NULL) { | |
| 674 PORT_ArenaRelease (arenaOpt, mark); | |
| 675 } else { | |
| 676 PORT_Free (out_string); | |
| 677 } | |
| 678 return NULL; | |
| 679 } | |
| 680 | |
| 681 if (arenaOpt != NULL) | |
| 682 PORT_ArenaUnmark (arenaOpt, mark); | |
| 683 | |
| 684 out_string[out_len] = '\0'; | |
| 685 return out_string; | |
| 686 } | |
| 687 | |
| 688 | |
| 689 /* | |
| 690 * XXX Everything below is deprecated. If you add new stuff, put it | |
| 691 * *above*, not below. | |
| 692 */ | |
| 693 | |
| 694 /* | |
| 695 * XXX The following "BTOA" functions are provided for backward compatibility | |
| 696 * with current code. They should be considered strongly deprecated. | |
| 697 * When we can convert all our code over to using the new NSSBase64Encoder_ | |
| 698 * functions defined above, we should get rid of these altogether. (Remove | |
| 699 * protoypes from base64.h as well -- actually, remove that file completely). | |
| 700 * If someone thinks either of these functions provides such a very useful | |
| 701 * interface (though, as shown, the same functionality can already be | |
| 702 * obtained by calling NSSBase64_EncodeItem directly), fine -- but then | |
| 703 * that API should be provided with a nice new NSSFoo name and using | |
| 704 * appropriate types, etc. | |
| 705 */ | |
| 706 | |
| 707 #include "base64.h" | |
| 708 | |
| 709 /* | |
| 710 ** Return an PORT_Alloc'd ascii string which is the base64 encoded | |
| 711 ** version of the input string. | |
| 712 */ | |
| 713 char * | |
| 714 BTOA_DataToAscii(const unsigned char *data, unsigned int len) | |
| 715 { | |
| 716 SECItem binary_item; | |
| 717 | |
| 718 binary_item.data = (unsigned char *)data; | |
| 719 binary_item.len = len; | |
| 720 | |
| 721 return NSSBase64_EncodeItem (NULL, NULL, 0, &binary_item); | |
| 722 } | |
| 723 | |
| 724 /* | |
| 725 ** Convert from binary encoding of an item to ascii. | |
| 726 */ | |
| 727 char * | |
| 728 BTOA_ConvertItemToAscii (SECItem *binary_item) | |
| 729 { | |
| 730 return NSSBase64_EncodeItem (NULL, NULL, 0, binary_item); | |
| 731 } | |
| OLD | NEW |