initial load of upstream version 1.06.32
[xmlrpc-c] / src / xmlrpc_base64.c
diff --git a/src/xmlrpc_base64.c b/src/xmlrpc_base64.c
new file mode 100644 (file)
index 0000000..2f54377
--- /dev/null
@@ -0,0 +1,266 @@
+/* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+**    notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+**    notice, this list of conditions and the following disclaimer in the
+**    documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+**    derived from this software without specific prior written permission. 
+**  
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+** SUCH DAMAGE.
+**
+** There is more copyright information in the bottom half of this file. 
+** Please see it for more details. */
+
+
+/*=========================================================================
+**  XML-RPC Base64 Utilities
+**=========================================================================
+**  This code was swiped from Jack Jansen's code in Python 1.5.2 and
+**  modified to work with our data types.
+*/
+
+#include "xmlrpc_config.h"
+
+#include "xmlrpc-c/base.h"
+
+#define CRLF    "\015\012"
+#define CR      '\015'
+#define LF      '\012'
+
+
+/***********************************************************
+Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum,
+Amsterdam, The Netherlands.
+
+                        All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Stichting Mathematisch
+Centrum or CWI or Corporation for National Research Initiatives or
+CNRI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+While CWI is the initial source for this software, a modified version
+is made available by the Corporation for National Research Initiatives
+(CNRI) at the Internet address ftp://ftp.python.org.
+
+STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
+CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+******************************************************************/
+
+static char table_a2b_base64[] = {
+    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
+    52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1, /* Note PAD->0 */
+    -1, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
+    15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
+    -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
+    41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
+};
+
+#define BASE64_PAD '='
+#define BASE64_MAXBIN 57    /* Max binary chunk size (76 char line) */
+#define BASE64_LINE_SZ 128      /* Buffer size for a single line. */    
+
+static unsigned char table_b2a_base64[] =
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static xmlrpc_mem_block *
+xmlrpc_base64_encode_internal (xmlrpc_env *env,
+                               unsigned char *bin_data,
+                               size_t bin_len,
+                               int want_newlines)
+{
+    size_t chunk_start, chunk_left;
+    unsigned char *ascii_data;
+    int leftbits;
+    unsigned char this_ch;
+    unsigned int leftchar;
+    xmlrpc_mem_block *output;
+    unsigned char line_buffer[BASE64_LINE_SZ];
+
+    /* Create a block to hold our lines when we finish them. */
+    output = xmlrpc_mem_block_new(env, 0);
+    XMLRPC_FAIL_IF_FAULT(env);
+
+    /* Deal with empty data blocks gracefully. Yuck. */
+    if (bin_len == 0) {
+        if (want_newlines)
+            XMLRPC_TYPED_MEM_BLOCK_APPEND(char, env, output, CRLF, 2);
+        goto cleanup;
+    }
+
+    /* Process our binary data in line-sized chunks. */
+    for (chunk_start=0; chunk_start < bin_len; chunk_start += BASE64_MAXBIN) {
+
+        /* Set up our per-line state. */
+        ascii_data = &line_buffer[0];
+        chunk_left = bin_len - chunk_start;
+        if (chunk_left > BASE64_MAXBIN)
+            chunk_left = BASE64_MAXBIN;
+        leftbits = 0;
+        leftchar = 0;
+
+        for(; chunk_left > 0; chunk_left--, bin_data++) {
+            /* Shift the data into our buffer */
+            leftchar = (leftchar << 8) | *bin_data;
+            leftbits += 8;
+
+            /* See if there are 6-bit groups ready */
+            while (leftbits >= 6) {
+                this_ch = (leftchar >> (leftbits-6)) & 0x3f;
+                leftbits -= 6;
+                *ascii_data++ = table_b2a_base64[this_ch];
+            }
+        }
+        if (leftbits == 2) {
+            *ascii_data++ = table_b2a_base64[(leftchar&3) << 4];
+            *ascii_data++ = BASE64_PAD;
+            *ascii_data++ = BASE64_PAD;
+        } else if (leftbits == 4) {
+            *ascii_data++ = table_b2a_base64[(leftchar&0xf) << 2];
+            *ascii_data++ = BASE64_PAD;
+        } 
+
+        /* Append a courtesy CRLF. */
+        if (want_newlines) {
+            *ascii_data++ = CR;
+            *ascii_data++ = LF;
+        }
+    
+        /* Save our line. */
+        XMLRPC_TYPED_MEM_BLOCK_APPEND(char, env, output, line_buffer,
+                                      ascii_data - &line_buffer[0]);
+        XMLRPC_FAIL_IF_FAULT(env);
+    }
+
+ cleanup:
+    if (env->fault_occurred) {
+        if (output)
+            xmlrpc_mem_block_free(output);
+        return NULL;
+    }
+    return output;
+}
+
+
+xmlrpc_mem_block *
+xmlrpc_base64_encode (xmlrpc_env *env, unsigned char *bin_data, size_t bin_len)
+{
+    return xmlrpc_base64_encode_internal(env, bin_data, bin_len, 1);
+}
+
+
+xmlrpc_mem_block *
+xmlrpc_base64_encode_without_newlines (xmlrpc_env *env,
+                                       unsigned char *bin_data,
+                                       size_t bin_len)
+{
+    return xmlrpc_base64_encode_internal(env, bin_data, bin_len, 0);
+}
+
+
+xmlrpc_mem_block *
+xmlrpc_base64_decode (xmlrpc_env * const env,
+                      const char * const ascii_data,
+                      size_t       const ascii_len) {
+
+    unsigned char *bin_data;
+    int leftbits;
+    unsigned char this_ch;
+    unsigned int leftchar;
+    size_t npad;
+    size_t bin_len, buffer_size;
+    xmlrpc_mem_block *output;
+    const char * next_char;
+    size_t remaining_len;
+
+    /* Create a block to hold our chunks when we finish them.
+    ** We overestimate the size now, and fix it later. */
+    buffer_size = ((ascii_len+3)/4)*3;
+    output = xmlrpc_mem_block_new(env, buffer_size);
+    XMLRPC_FAIL_IF_FAULT(env);
+
+    /* Set up our decoder state. */
+    leftbits = 0;
+    leftchar = 0;
+    npad = 0;
+    bin_data = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(unsigned char, output);
+    bin_len = 0;
+
+    for (remaining_len = ascii_len, next_char = ascii_data;
+         remaining_len > 0; 
+         --remaining_len, ++next_char) {
+
+        /* Skip some punctuation. */
+        this_ch = (*next_char & 0x7f);
+        if ( this_ch == '\r' || this_ch == '\n' || this_ch == ' ' )
+            continue;
+        if ( this_ch == BASE64_PAD )
+            npad++;
+        this_ch = table_a2b_base64[(*next_char) & 0x7f];
+
+        /* XXX - We just throw away invalid characters. Is this right? */
+        if ( this_ch == (unsigned char) -1 ) continue;
+
+        /* Shift it in on the low end, and see if there's
+        ** a byte ready for output. */
+        leftchar = (leftchar << 6) | (this_ch);
+        leftbits += 6;
+        if ( leftbits >= 8 ) {
+            leftbits -= 8;
+            XMLRPC_ASSERT(bin_len < buffer_size);
+            *bin_data++ = (leftchar >> leftbits) & 0xFF;
+            leftchar &= ((1 << leftbits) - 1);
+            bin_len++;
+        }
+    }
+
+    /* Check that no bits are left. */
+    if ( leftbits )
+        XMLRPC_FAIL(env, XMLRPC_PARSE_ERROR, "Incorrect Base64 padding");
+
+    /* Check to make sure we have a sane amount of padding. */
+    if (npad > bin_len || npad > 2)
+        XMLRPC_FAIL(env, XMLRPC_PARSE_ERROR, "Malformed Base64 data");
+
+    /* Remove any padding and set the correct size. */
+    bin_len -= npad;
+    XMLRPC_TYPED_MEM_BLOCK_RESIZE(char, env, output, bin_len);
+    XMLRPC_ASSERT(!env->fault_occurred);
+
+                      cleanup:
+    if (env->fault_occurred) {
+        if (output)
+            xmlrpc_mem_block_free(output);
+        return NULL;
+    }
+    return output;
+}