initial load of upstream version 1.06.32
[xmlrpc-c] / src / xmlrpc_data.c
diff --git a/src/xmlrpc_data.c b/src/xmlrpc_data.c
new file mode 100644 (file)
index 0000000..15889b7
--- /dev/null
@@ -0,0 +1,852 @@
+/* Copyright information is at end of file */
+
+#include "xmlrpc_config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "bool.h"
+#include "mallocvar.h"
+
+#include "xmlrpc-c/base.h"
+#include "xmlrpc-c/base_int.h"
+
+
+
+static void
+destroyValue(xmlrpc_value * const valueP) {
+
+    /* First, we need to destroy this value's contents, if any. */
+    switch (valueP->_type) {
+    case XMLRPC_TYPE_INT:
+        break;
+        
+    case XMLRPC_TYPE_BOOL:
+        break;
+
+    case XMLRPC_TYPE_DOUBLE:
+        break;
+
+    case XMLRPC_TYPE_DATETIME:
+        xmlrpc_mem_block_clean(&valueP->_block);
+        break;
+
+    case XMLRPC_TYPE_STRING:
+        if (valueP->_wcs_block)
+            xmlrpc_mem_block_free(valueP->_wcs_block);
+        xmlrpc_mem_block_clean(&valueP->_block);
+        break;
+        
+    case XMLRPC_TYPE_BASE64:
+        xmlrpc_mem_block_clean(&valueP->_block);
+        break;
+
+    case XMLRPC_TYPE_ARRAY:
+        xmlrpc_destroyArrayContents(valueP);
+        break;
+        
+    case XMLRPC_TYPE_STRUCT:
+        xmlrpc_destroyStruct(valueP);
+        break;
+
+    case XMLRPC_TYPE_C_PTR:
+        break;
+
+    case XMLRPC_TYPE_NIL:
+        break;
+
+    case XMLRPC_TYPE_DEAD:
+        XMLRPC_ASSERT(false); /* Can't happen, per entry conditions */
+
+    default:
+        XMLRPC_ASSERT(false); /* There are no other possible values */
+    }
+
+    /* Next, we mark this value as invalid, to help catch refcount
+        ** errors. */
+    valueP->_type = XMLRPC_TYPE_DEAD;
+
+    /* Finally, we destroy the value itself. */
+    free(valueP);
+}
+
+
+
+/*=========================================================================
+**  Reference Counting
+**=========================================================================
+**  Some simple reference-counting code. The xmlrpc_DECREF routine is in
+**  charge of destroying values when their reference count equals zero.
+*/
+
+void 
+xmlrpc_INCREF (xmlrpc_value * const valueP) {
+
+    XMLRPC_ASSERT_VALUE_OK(valueP);
+    XMLRPC_ASSERT(valueP->_refcount > 0);
+    
+    ++valueP->_refcount;
+}
+
+
+
+void 
+xmlrpc_DECREF (xmlrpc_value * const valueP) {
+
+    XMLRPC_ASSERT_VALUE_OK(valueP);
+    XMLRPC_ASSERT(valueP->_refcount > 0);
+    XMLRPC_ASSERT(valueP->_type != XMLRPC_TYPE_DEAD);
+
+    valueP->_refcount--;
+
+    /* If we have no more refs, we need to deallocate this value. */
+    if (valueP->_refcount == 0)
+        destroyValue(valueP);
+}
+
+
+
+/*=========================================================================
+    Utiltiies
+=========================================================================*/
+
+const char *
+xmlrpc_typeName(xmlrpc_type const type) {
+
+    switch(type) {
+
+    case XMLRPC_TYPE_INT:      return "INT";
+    case XMLRPC_TYPE_BOOL:     return "BOOL";
+    case XMLRPC_TYPE_DOUBLE:   return "DOUBLE";
+    case XMLRPC_TYPE_DATETIME: return "DATETIME";
+    case XMLRPC_TYPE_STRING:   return "STRING";
+    case XMLRPC_TYPE_BASE64:   return "BASE64";
+    case XMLRPC_TYPE_ARRAY:    return "ARRAY";
+    case XMLRPC_TYPE_STRUCT:   return "STRUCT";
+    case XMLRPC_TYPE_C_PTR:    return "C_PTR";
+    case XMLRPC_TYPE_NIL:      return "NIL";
+    case XMLRPC_TYPE_DEAD:     return "DEAD";
+    default:                   return "???";
+    }
+}
+
+
+
+static void
+verifyNoNulls(xmlrpc_env * const envP,
+              const char * const contents,
+              unsigned int const len) {
+/*----------------------------------------------------------------------------
+   Verify that the character array 'contents', which is 'len' bytes long,
+   does not contain any NUL characters, which means it can be made into
+   a passable ASCIIZ string just by adding a terminating NUL.
+
+   Fail if the array contains a NUL.
+-----------------------------------------------------------------------------*/
+    unsigned int i;
+
+    for (i = 0; i < len && !envP->fault_occurred; i++)
+        if (contents[i] == '\0')
+            xmlrpc_env_set_fault_formatted(
+                envP, XMLRPC_TYPE_ERROR, 
+                "String must not contain NUL characters");
+}
+
+
+
+#if HAVE_UNICODE_WCHAR
+
+static void
+verifyNoNullsW(xmlrpc_env *    const envP,
+               const wchar_t * const contents,
+               unsigned int    const len) {
+/*----------------------------------------------------------------------------
+   Same as verifyNoNulls(), but for wide characters.
+-----------------------------------------------------------------------------*/
+    unsigned int i;
+
+    for (i = 0; i < len && !envP->fault_occurred; i++)
+        if (contents[i] == '\0')
+            xmlrpc_env_set_fault_formatted(
+                envP, XMLRPC_TYPE_ERROR, 
+                "String must not contain NUL characters");
+}
+#endif
+
+
+
+static void
+validateType(xmlrpc_env *         const envP,
+             const xmlrpc_value * const valueP,
+             xmlrpc_type          const expectedType) {
+
+    if (valueP->_type != expectedType) {
+        xmlrpc_env_set_fault_formatted(
+            envP, XMLRPC_TYPE_ERROR, "Value of type %s supplied where "
+            "type %s was expected.", 
+            xmlrpc_typeName(valueP->_type), xmlrpc_typeName(expectedType));
+    }
+}
+
+
+
+/*=========================================================================
+    Extracting XML-RPC value
+===========================================================================
+  These routines extract XML-RPC values into ordinary C data types.
+
+  For array and struct values, see the separates files xmlrpc_array.c
+  and xmlrpc_struct.c.
+=========================================================================*/
+
+void 
+xmlrpc_read_int(xmlrpc_env *         const envP,
+                const xmlrpc_value * const valueP,
+                xmlrpc_int32 *       const intValueP) {
+
+    validateType(envP, valueP, XMLRPC_TYPE_INT);
+    if (!envP->fault_occurred)
+        *intValueP = valueP->_value.i;
+}
+
+
+
+void
+xmlrpc_read_bool(xmlrpc_env *         const envP,
+                 const xmlrpc_value * const valueP,
+                 xmlrpc_bool *        const boolValueP) {
+
+    validateType(envP, valueP, XMLRPC_TYPE_BOOL);
+    if (!envP->fault_occurred)
+        *boolValueP = valueP->_value.b;
+}
+
+
+
+void
+xmlrpc_read_double(xmlrpc_env *         const envP,
+                   const xmlrpc_value * const valueP,
+                   xmlrpc_double *      const doubleValueP) {
+    
+    validateType(envP, valueP, XMLRPC_TYPE_DOUBLE);
+    if (!envP->fault_occurred)
+        *doubleValueP = valueP->_value.d;
+
+}
+
+
+/* datetime stuff is in xmlrpc_datetime.c */
+
+static void
+accessStringValue(xmlrpc_env *         const envP,
+                  const xmlrpc_value * const valueP,
+                  size_t *             const lengthP,
+                  const char **        const contentsP) {
+    
+    validateType(envP, valueP, XMLRPC_TYPE_STRING);
+    if (!envP->fault_occurred) {
+        unsigned int const size = 
+            XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block);
+        const char * const contents = 
+            XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block);
+        unsigned int const len = size - 1;
+            /* The memblock has a null character added to the end */
+
+        verifyNoNulls(envP, contents, len);
+
+        *lengthP = len;
+        *contentsP = contents;
+    }
+}
+             
+
+
+void
+xmlrpc_read_string(xmlrpc_env *         const envP,
+                   const xmlrpc_value * const valueP,
+                   const char **        const stringValueP) {
+/*----------------------------------------------------------------------------
+   Read the value of an XML-RPC string as an ASCIIZ string.
+
+   Return the string in newly malloc'ed storage that Caller must free.
+
+   Fail if the string contains null characters (which means it wasn't
+   really a string, but XML-RPC doesn't seem to understand what a string
+   is, and such values are possible).
+-----------------------------------------------------------------------------*/
+    size_t length;
+    const char * contents;
+
+    accessStringValue(envP, valueP, &length, &contents);
+
+    if (!envP->fault_occurred) {
+        char * stringValue;
+            
+        stringValue = malloc(length+1);
+        if (stringValue == NULL)
+            xmlrpc_env_set_fault_formatted(
+                envP, XMLRPC_INTERNAL_ERROR, "Unable to allocate space "
+                "for %u-character string", length);
+        else {
+            memcpy(stringValue, contents, length);
+            stringValue[length] = '\0';
+
+            *stringValueP = stringValue;
+        }
+    }
+}
+
+
+
+void
+xmlrpc_read_string_old(xmlrpc_env *         const envP,
+                       const xmlrpc_value * const valueP,
+                       const char **        const stringValueP) {
+
+    size_t length;
+    accessStringValue(envP, valueP, &length, stringValueP);
+}
+
+
+
+void
+xmlrpc_read_string_lp(xmlrpc_env *         const envP,
+                      const xmlrpc_value * const valueP,
+                      size_t *             const lengthP,
+                      const char **        const stringValueP) {
+
+    validateType(envP, valueP, XMLRPC_TYPE_STRING);
+    if (!envP->fault_occurred) {
+        unsigned int const size = 
+            XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block);
+        const char * const contents = 
+            XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block);
+
+        char * stringValue;
+
+        stringValue = malloc(size);
+        if (stringValue == NULL)
+            xmlrpc_env_set_fault_formatted(
+                envP, XMLRPC_INTERNAL_ERROR, "Unable to allocate %u bytes "
+                "for string.", size);
+        else {
+            memcpy(stringValue, contents, size);
+            *stringValueP = stringValue;
+            *lengthP = size - 1;  /* Size includes terminating NUL */
+        }
+    }
+}
+
+
+
+void
+xmlrpc_read_string_lp_old(xmlrpc_env *         const envP,
+                          const xmlrpc_value * const valueP,
+                          size_t *             const lengthP,
+                          const char **        const stringValueP) {
+
+    validateType(envP, valueP, XMLRPC_TYPE_STRING);
+    if (!envP->fault_occurred) {
+        *lengthP =      XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block) - 1;
+        *stringValueP = XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block);
+    }
+}
+
+
+
+static __inline__ void
+setupWcsBlock(xmlrpc_env *   const envP,
+              xmlrpc_value * const valueP) {
+/*----------------------------------------------------------------------------
+   Add a wcs block (wchar_t string) to the indicated xmlrpc_value if it
+   doesn't have one already.
+-----------------------------------------------------------------------------*/
+    if (!valueP->_wcs_block) {
+        char * const contents = 
+            XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block);
+        size_t const len = 
+            XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block) - 1;
+        valueP->_wcs_block = 
+            xmlrpc_utf8_to_wcs(envP, contents, len + 1);
+    }
+}
+
+
+
+#if HAVE_UNICODE_WCHAR
+
+static void
+accessStringValueW(xmlrpc_env *     const envP,
+                   xmlrpc_value *   const valueP,
+                   size_t *         const lengthP,
+                   const wchar_t ** const stringValueP) {
+
+    validateType(envP, valueP, XMLRPC_TYPE_STRING);
+    if (!envP->fault_occurred) {
+        setupWcsBlock(envP, valueP);
+
+        if (!envP->fault_occurred) {
+            wchar_t * const wcontents = 
+                XMLRPC_MEMBLOCK_CONTENTS(wchar_t, valueP->_wcs_block);
+            size_t const len = 
+                XMLRPC_MEMBLOCK_SIZE(wchar_t, valueP->_wcs_block) - 1;
+            
+            verifyNoNullsW(envP, wcontents, len);
+
+            *lengthP = len;
+            *stringValueP = wcontents;
+        }
+    }
+}
+
+
+              
+void
+xmlrpc_read_string_w(xmlrpc_env *     const envP,
+                     xmlrpc_value *   const valueP,
+                     const wchar_t ** const stringValueP) {
+
+    size_t length;
+    const wchar_t * wcontents;
+    
+    accessStringValueW(envP, valueP, &length, &wcontents);
+
+    if (!envP->fault_occurred) {
+        wchar_t * stringValue;
+        stringValue = malloc((length + 1) * sizeof(wchar_t));
+        if (stringValue == NULL)
+            xmlrpc_env_set_fault_formatted(
+                envP, XMLRPC_INTERNAL_ERROR, 
+                "Unable to allocate space for %u-byte string", 
+                length);
+        else {
+            memcpy(stringValue, wcontents, length * sizeof(wchar_t));
+            stringValue[length] = '\0';
+            
+            *stringValueP = stringValue;
+        }
+    }
+}
+
+
+
+void
+xmlrpc_read_string_w_old(xmlrpc_env *     const envP,
+                         xmlrpc_value *   const valueP,
+                         const wchar_t ** const stringValueP) {
+
+    size_t length;
+
+    accessStringValueW(envP, valueP, &length, stringValueP);
+}
+
+
+
+void
+xmlrpc_read_string_w_lp(xmlrpc_env *     const envP,
+                        xmlrpc_value *   const valueP,
+                        size_t *         const lengthP,
+                        const wchar_t ** const stringValueP) {
+
+    validateType(envP, valueP, XMLRPC_TYPE_STRING);
+    if (!envP->fault_occurred) {
+        setupWcsBlock(envP, valueP);
+
+        if (!envP->fault_occurred) {
+            wchar_t * const wcontents = 
+                XMLRPC_MEMBLOCK_CONTENTS(wchar_t, valueP->_wcs_block);
+            size_t const size = 
+                XMLRPC_MEMBLOCK_SIZE(wchar_t, valueP->_wcs_block);
+
+            wchar_t * stringValue;
+            
+            stringValue = malloc(size * sizeof(wchar_t));
+            if (stringValue == NULL)
+                xmlrpc_env_set_fault_formatted(
+                    envP, XMLRPC_INTERNAL_ERROR, 
+                    "Unable to allocate space for %u-byte string", 
+                    size);
+            else {
+                memcpy(stringValue, wcontents, size * sizeof(wchar_t));
+                
+                *lengthP      = size - 1; /* size includes terminating NUL */
+                *stringValueP = stringValue;
+            }
+        }
+    }
+}
+
+
+
+void
+xmlrpc_read_string_w_lp_old(xmlrpc_env *     const envP,
+                            xmlrpc_value *   const valueP,
+                            size_t *         const lengthP,
+                            const wchar_t ** const stringValueP) {
+
+    validateType(envP, valueP, XMLRPC_TYPE_STRING);
+    if (!envP->fault_occurred) {
+        setupWcsBlock(envP, valueP);
+
+        if (!envP->fault_occurred) {
+            wchar_t * const wcontents = 
+                XMLRPC_MEMBLOCK_CONTENTS(wchar_t, valueP->_wcs_block);
+            size_t const size = 
+                XMLRPC_MEMBLOCK_SIZE(wchar_t, valueP->_wcs_block);
+            
+            *lengthP      = size - 1;  /* size includes terminatnig NUL */
+            *stringValueP = wcontents;
+        }
+    }
+}
+#endif
+
+
+
+void
+xmlrpc_read_base64(xmlrpc_env *           const envP,
+                   const xmlrpc_value *   const valueP,
+                   size_t *               const lengthP,
+                   const unsigned char ** const byteStringValueP) {
+
+    validateType(envP, valueP, XMLRPC_TYPE_BASE64);
+    if (!envP->fault_occurred) {
+        size_t const size = 
+            XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block);
+        const char * const contents = 
+            XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block);
+
+        char * byteStringValue;
+
+        byteStringValue = malloc(size);
+        if (byteStringValue == NULL)
+            xmlrpc_env_set_fault_formatted(
+                envP, XMLRPC_INTERNAL_ERROR, "Unable to allocate %u bytes "
+                "for byte string.", size);
+        else {
+            memcpy(byteStringValue, contents, size);
+            *byteStringValueP = (const unsigned char *)byteStringValue;
+            *lengthP = size;
+        }
+    }
+}
+
+
+
+void
+xmlrpc_read_base64_old(xmlrpc_env *           const envP,
+                       const xmlrpc_value *   const valueP,
+                       size_t *               const lengthP,
+                       const unsigned char ** const byteStringValueP) {
+
+    validateType(envP, valueP, XMLRPC_TYPE_BASE64);
+    if (!envP->fault_occurred) {
+        *lengthP =
+            XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block);
+        *byteStringValueP = (const unsigned char *)
+            XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block);
+    }
+}
+
+
+
+void
+xmlrpc_read_base64_size(xmlrpc_env *           const envP,
+                        const xmlrpc_value *   const valueP,
+                        size_t *               const lengthP) {
+
+    validateType(envP, valueP, XMLRPC_TYPE_BASE64);
+    if (!envP->fault_occurred)
+        *lengthP = XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block);
+}
+
+
+
+void
+xmlrpc_read_nil(xmlrpc_env *   const envP,
+                xmlrpc_value * const valueP) {
+/*----------------------------------------------------------------------------
+   Read out the value of a nil value.  It doesn't have one, of course, so
+   this is essentially a no-op.  But it does validate the type and is
+   necessary to match all the other types.
+-----------------------------------------------------------------------------*/
+    validateType(envP, valueP, XMLRPC_TYPE_NIL);
+}
+
+
+
+void
+xmlrpc_read_cptr(xmlrpc_env *         const envP,
+                 const xmlrpc_value * const valueP,
+                 void **              const ptrValueP) {
+
+    validateType(envP, valueP, XMLRPC_TYPE_C_PTR);
+    if (!envP->fault_occurred)
+        *ptrValueP = valueP->_value.c_ptr;
+}
+
+
+
+xmlrpc_type xmlrpc_value_type (xmlrpc_value* value)
+{
+    XMLRPC_ASSERT_VALUE_OK(value);
+    return value->_type;
+}
+
+
+
+void
+xmlrpc_createXmlrpcValue(xmlrpc_env *    const envP,
+                         xmlrpc_value ** const valPP) {
+/*----------------------------------------------------------------------------
+   Create a blank xmlrpc_value to be filled in.
+
+   Set the reference count to 1.
+-----------------------------------------------------------------------------*/
+    xmlrpc_value * valP;
+
+    MALLOCVAR(valP);
+    if (!valP)
+        xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR,
+                             "Could not allocate memory for xmlrpc_value");
+    else
+        valP->_refcount = 1;
+
+    *valPP = valP;
+}
+
+
+
+xmlrpc_value *
+xmlrpc_int_new(xmlrpc_env * const envP, 
+               xmlrpc_int32 const value) {
+
+    xmlrpc_value * valP;
+
+    xmlrpc_createXmlrpcValue(envP, &valP);
+
+    if (!envP->fault_occurred) {
+        valP->_type    = XMLRPC_TYPE_INT;
+        valP->_value.i = value;
+    }
+    return valP;
+}
+
+
+
+xmlrpc_value *
+xmlrpc_bool_new(xmlrpc_env * const envP, 
+                xmlrpc_bool  const value) {
+
+    xmlrpc_value * valP;
+
+    xmlrpc_createXmlrpcValue(envP, &valP);
+
+    if (!envP->fault_occurred) {
+        valP->_type = XMLRPC_TYPE_BOOL;
+        valP->_value.b = value;
+    }
+    return valP;
+}
+
+
+
+xmlrpc_value *
+xmlrpc_double_new(xmlrpc_env * const envP, 
+                  double       const value) {
+
+    xmlrpc_value * valP;
+
+    xmlrpc_createXmlrpcValue(envP, &valP);
+
+    if (!envP->fault_occurred) {
+        valP->_type = XMLRPC_TYPE_DOUBLE;
+        valP->_value.d = value;
+    }
+    return valP;
+}
+
+
+
+xmlrpc_value *
+xmlrpc_string_new_lp(xmlrpc_env * const envP, 
+                     size_t       const length,
+                     const char * const value) {
+
+    xmlrpc_value * valP;
+
+    xmlrpc_createXmlrpcValue(envP, &valP);
+
+    if (!envP->fault_occurred) {
+        valP->_type = XMLRPC_TYPE_STRING;
+        valP->_wcs_block = NULL;
+        XMLRPC_MEMBLOCK_INIT(char, envP, &valP->_block, length + 1);
+        if (!envP->fault_occurred) {
+            char * const contents =
+                XMLRPC_MEMBLOCK_CONTENTS(char, &valP->_block);
+            memcpy(contents, value, length);
+            contents[length] = '\0';
+        }
+        if (envP->fault_occurred)
+            free(valP);
+    }
+    return valP;
+}
+
+
+
+xmlrpc_value *
+xmlrpc_string_new(xmlrpc_env * const envP,
+                  const char * const value) {
+
+    return xmlrpc_string_new_lp(envP, strlen(value), value);
+}
+
+
+#if HAVE_UNICODE_WCHAR
+xmlrpc_value *
+xmlrpc_string_w_new_lp(xmlrpc_env *    const envP, 
+                       size_t          const length,
+                       const wchar_t * const value) {
+
+    xmlrpc_value * valP;
+
+    /* Initialize our XML-RPC value. */
+    xmlrpc_createXmlrpcValue(envP, &valP);
+
+    if (!envP->fault_occurred) {
+        valP->_type = XMLRPC_TYPE_STRING;
+
+        /* Build our wchar_t block first. */
+        valP->_wcs_block =
+            XMLRPC_MEMBLOCK_NEW(wchar_t, envP, length + 1);
+        if (!envP->fault_occurred) {
+            wchar_t * const wcs_contents =
+                XMLRPC_MEMBLOCK_CONTENTS(wchar_t, valP->_wcs_block);
+
+            xmlrpc_mem_block * utf8P;
+
+            memcpy(wcs_contents, value, length * sizeof(wchar_t));
+            wcs_contents[length] = '\0';
+    
+            /* Convert the wcs block to UTF-8. */
+            utf8P = xmlrpc_wcs_to_utf8(envP, wcs_contents, length + 1);
+            if (!envP->fault_occurred) {
+                char * const utf8_contents =
+                    XMLRPC_MEMBLOCK_CONTENTS(char, utf8P);
+                size_t const utf8_len = XMLRPC_MEMBLOCK_SIZE(char, utf8P);
+
+                /* XXX - We need an extra memcopy to initialize _block. */
+                XMLRPC_MEMBLOCK_INIT(char, envP, &valP->_block, utf8_len);
+                if (!envP->fault_occurred) {
+                    char * contents;
+                    contents = XMLRPC_MEMBLOCK_CONTENTS(char, &valP->_block);
+                    memcpy(contents, utf8_contents, utf8_len);
+                }
+                XMLRPC_MEMBLOCK_FREE(char, utf8P);
+            }
+            if (envP->fault_occurred)
+                XMLRPC_MEMBLOCK_FREE(wchar_t, valP->_wcs_block);
+        }
+        if (envP->fault_occurred)
+            free(valP);
+    }
+    return valP;
+}
+
+
+
+xmlrpc_value *
+xmlrpc_string_w_new(xmlrpc_env *    const envP,
+                    const wchar_t * const value) {
+    return xmlrpc_string_w_new_lp(envP, wcslen(value), value);
+}
+#endif
+
+xmlrpc_value *
+xmlrpc_base64_new(xmlrpc_env *          const envP, 
+                  size_t                const length,
+                  const unsigned char * const value) {
+
+    xmlrpc_value * valP;
+
+    xmlrpc_createXmlrpcValue(envP, &valP);
+
+    if (!envP->fault_occurred) {
+        valP->_type = XMLRPC_TYPE_BASE64;
+
+        xmlrpc_mem_block_init(envP, &valP->_block, length);
+        if (!envP->fault_occurred) {
+            char * const contents = 
+                xmlrpc_mem_block_contents(&valP->_block);
+            memcpy(contents, value, length);
+        }
+        if (envP->fault_occurred)
+            free(valP);
+    }
+    return valP;
+}
+
+
+
+/* array stuff is in xmlrpc_array.c */
+
+
+
+xmlrpc_value *
+xmlrpc_cptr_new(xmlrpc_env *    const envP,
+                void *          const value) {
+
+    xmlrpc_value * valP;
+
+    xmlrpc_createXmlrpcValue(envP, &valP);
+
+    if (!envP->fault_occurred) {
+        valP->_type = XMLRPC_TYPE_C_PTR;
+        valP->_value.c_ptr = value;
+    }
+    return valP;
+}
+
+
+
+xmlrpc_value *
+xmlrpc_nil_new(xmlrpc_env *    const envP) {
+    xmlrpc_value * valP;
+
+    xmlrpc_createXmlrpcValue(envP, &valP);
+    if (!envP->fault_occurred)
+        valP->_type = XMLRPC_TYPE_NIL;
+
+    return valP;
+}
+
+
+
+/* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
+** Copyright (C) 2001 by Eric Kidd. 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. */