| 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 | 
|---|