nssb64e.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 763 行 · 第 1/2 页

C
763
字号
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ *  * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. *  * The Original Code is the Netscape security libraries. *  * The Initial Developer of the Original Code is Netscape * Communications Corporation.  Portions created by Netscape are  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All * Rights Reserved. *  * Contributor(s): *  * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable  * instead of those above.  If you wish to allow use of your  * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL.  If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. *//* * Base64 encoding (binary to ascii). * * $Id: nssb64e.c,v 1.1 2000/04/06 00:39:49 repka%netscape.com Exp $ */#include "nssb64.h"#include "nspr.h"#include "secitem.h"#include "secerr.h"/* * XXX See the big comment at the top of nssb64d.c about moving the * bulk of this code over into NSPR (the PL part).  It all applies * here but I didn't want to duplicate it, to avoid divergence problems. */ /* ************************************************************** * XXX Beginning of base64 encoding code to be moved into NSPR. */struct PLBase64EncodeStateStr {    unsigned chunks;    unsigned saved;    unsigned char buf[3];};/* * This typedef would belong in the NSPR header file (i.e. plbase64.h). */typedef struct PLBase64EncoderStr PLBase64Encoder;/* * The following implementation of base64 encoding was based on code * found in libmime (specifically, in mimeenc.c).  It has been adapted to * use PR types and naming as well as to provide other necessary semantics * (like buffer-in/buffer-out in addition to "streaming" without undue * performance hit of extra copying if you made the buffer versions * use the output_fn).  It also incorporates some aspects of the current * NSPR base64 encoding code.  As such, you may find similarities to * both of those implementations.  I tried to use names that reflected * the original code when possible.  For this reason you may find some * inconsistencies -- libmime used lots of "in" and "out" whereas the * NSPR version uses "src" and "dest"; sometimes I changed one to the other * and sometimes I left them when I thought the subroutines were at least * self-consistent. */PR_BEGIN_EXTERN_C/* * Opaque object used by the encoder to store state. */struct PLBase64EncoderStr {    /*     * The one or two bytes pending.  (We need 3 to create a "token",     * and hold the leftovers here.  in_buffer_count is *only* ever     * 0, 1, or 2.     */    unsigned char in_buffer[2];    int in_buffer_count;    /*     * If the caller wants linebreaks added, line_length specifies     * where they come out.  It must be a multiple of 4; if the caller     * provides one that isn't, we round it down to the nearest     * multiple of 4.     *     * The value of current_column counts how many characters have been     * added since the last linebreaks (or since the beginning, on the     * first line).  It is also always a multiple of 4; it is unused when     * line_length is 0.     */     PRUint32 line_length;    PRUint32 current_column;    /*     * Where to write the encoded data (used when streaming, not when     * doing all in-memory (buffer) operations).     *     * Note that this definition is chosen to be compatible with PR_Write.     */    PRInt32 (*output_fn) (void *output_arg, const char *buf, PRInt32 size);    void *output_arg;    /*     * Where the encoded output goes -- either temporarily (in the streaming     * case, staged here before it goes to the output function) or what will     * be the entire buffered result for users of the buffer version.     */    char *output_buffer;    PRUint32 output_buflen;	/* the total length of allocated buffer */    PRUint32 output_length;	/* the length that is currently populated */};PR_END_EXTERN_C/* * Table to convert a binary value to its corresponding ascii "code". */static unsigned char base64_valuetocode[64] =    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";#define B64_PAD	'='#define B64_CR	'\r'#define B64_LF	'\n'static PRStatuspl_base64_encode_buffer (PLBase64Encoder *data, const unsigned char *in,			 PRUint32 size){    const unsigned char *end = in + size;    char *out = data->output_buffer + data->output_length;    int i = data->in_buffer_count;    PRUint32 n = 0;    int off;    PRUint32 output_threshold;    /* If this input buffer is too small, wait until next time. */    if (size < (3 - i)) {	data->in_buffer[i++] = in[0];	if (size > 1)	    data->in_buffer[i++] = in[1];	PR_ASSERT(i < 3);	data->in_buffer_count = i;	return PR_SUCCESS;    }    /* If there are bytes that were put back last time, take them now. */    if (i > 0) {	n = data->in_buffer[0];	if (i > 1)	    n = (n << 8) | data->in_buffer[1];	data->in_buffer_count = 0;    }    /* If our total is not a multiple of three, put one or two bytes back. */    off = (size + i) % 3;    if (off > 0) {	size -= off;	data->in_buffer[0] = in[size];	if (off > 1)	    data->in_buffer[1] = in[size + 1];	data->in_buffer_count = off;	end -= off;    }    output_threshold = data->output_buflen - 3;    /*     * Populate the output buffer with base64 data, one line (or buffer)     * at a time.     */    while (in < end) {	int j, k;	while (i < 3) {	    n = (n << 8) | *in++;	    i++;	}	i = 0;	if (data->line_length > 0) {	    if (data->current_column >= data->line_length) {		data->current_column = 0;		*out++ = B64_CR;		*out++ = B64_LF;		data->output_length += 2;	    }	    data->current_column += 4;	/* the bytes we are about to add */	}	for (j = 18; j >= 0; j -= 6) {	    k = (n >> j) & 0x3F;	    *out++ = base64_valuetocode[k];	}	n = 0;	data->output_length += 4;	if (data->output_length >= output_threshold) {	    PR_ASSERT(data->output_length <= data->output_buflen);	    if (data->output_fn != NULL) {		PRInt32 output_result;		output_result = data->output_fn (data->output_arg,						 data->output_buffer,						 (PRInt32) data->output_length);		if (output_result < 0)		    return PR_FAILURE;		out = data->output_buffer;		data->output_length = 0;	    } else {		/*		 * Check that we are about to exit the loop.  (Since we		 * are over the threshold, there isn't enough room in the		 * output buffer for another trip around.)		 */		PR_ASSERT(in == end);		if (in < end) {		    PR_SetError (PR_BUFFER_OVERFLOW_ERROR, 0);		    return PR_FAILURE;		}	    }	}    }    return PR_SUCCESS;}static PRStatuspl_base64_encode_flush (PLBase64Encoder *data){    int i = data->in_buffer_count;    if (i == 0 && data->output_length == 0)	return PR_SUCCESS;    if (i > 0) {	char *out = data->output_buffer + data->output_length;	PRUint32 n;	int j, k;	n = ((PRUint32) data->in_buffer[0]) << 16;	if (i > 1)	    n |= ((PRUint32) data->in_buffer[1] << 8);	data->in_buffer_count = 0;	if (data->line_length > 0) {	    if (data->current_column >= data->line_length) {		data->current_column = 0;		*out++ = B64_CR;		*out++ = B64_LF;		data->output_length += 2;	    }	}	/*	 * This will fill in more than we really have data for, but the	 * valid parts will end up in the correct position and the extras	 * will be over-written with pad characters below.	 */	for (j = 18; j >= 0; j -= 6) {	    k = (n >> j) & 0x3F;	    *out++ = base64_valuetocode[k];	}	/* Pad with equal-signs. */	if (i == 1)	    out[-2] = B64_PAD;	out[-1] = B64_PAD;	data->output_length += 4;    }    if (data->output_fn != NULL) {	PRInt32 output_result;	output_result = data->output_fn (data->output_arg, data->output_buffer,					 (PRInt32) data->output_length);	data->output_length = 0;	if (output_result < 0)	    return PR_FAILURE;    }    return PR_SUCCESS;}/* * The maximum space needed to hold the output of the encoder given input * data of length "size", and allowing for CRLF added at least every * line_length bytes (we will add it at nearest lower multiple of 4). * There is no trailing CRLF. */static PRUint32PL_Base64MaxEncodedLength (PRUint32 size, PRUint32 line_length){    PRUint32 tokens, tokens_per_line, full_lines, line_break_chars, remainder;    tokens = (size + 2) / 3;    if (line_length == 0)	return tokens * 4;    if (line_length < 4)	/* too small! */	line_length = 4;    tokens_per_line = line_length / 4;    full_lines = tokens / tokens_per_line;    remainder = (tokens - (full_lines * tokens_per_line)) * 4;    line_break_chars = full_lines * 2;    if (remainder == 0)	line_break_chars -= 2;    return (full_lines * tokens_per_line * 4) + line_break_chars + remainder;}/* * A distinct internal creation function for the buffer version to use. * (It does not want to specify an output_fn, and we want the normal * Create function to require that.)  All common initialization of the * encoding context should be done *here*. * * Save "line_length", rounded down to nearest multiple of 4 (if not * already even multiple).  Allocate output_buffer, if not provided -- * based on given size if specified, otherwise based on line_length. */static PLBase64Encoder *pl_base64_create_encoder (PRUint32 line_length, char *output_buffer,			  PRUint32 output_buflen){    PLBase64Encoder *data;    PRUint32 line_tokens;    data = PR_NEWZAP(PLBase64Encoder);    if (data == NULL)	return NULL;    if (line_length > 0 && line_length < 4)	/* too small! */	line_length = 4;    line_tokens = line_length / 4;    data->line_length = line_tokens * 4;    if (output_buffer == NULL) {	if (output_buflen == 0) {	    if (data->line_length > 0)	/* need to include room for CRLF */		output_buflen = data->line_length + 2;	    else		output_buflen = 64;		/* XXX what is a good size? */	}	output_buffer = (char *) PR_Malloc(output_buflen);	if (output_buffer == NULL) {	    PR_Free(data);	    return NULL;	}    }    data->output_buffer = output_buffer;    data->output_buflen = output_buflen;    return data;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?