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