diff options
Diffstat (limited to 'Utilities/cmxmlrpc/xmlrpc_data.c')
-rw-r--r-- | Utilities/cmxmlrpc/xmlrpc_data.c | 1334 |
1 files changed, 0 insertions, 1334 deletions
diff --git a/Utilities/cmxmlrpc/xmlrpc_data.c b/Utilities/cmxmlrpc/xmlrpc_data.c deleted file mode 100644 index 456d8e4..0000000 --- a/Utilities/cmxmlrpc/xmlrpc_data.c +++ /dev/null @@ -1,1334 +0,0 @@ -/* 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 "xmlrpc.h" -#include "xmlrpc_int.h" - -/* Borrowed from Python 1.5.2. -** MPW pushes 'extended' for float and double types with varargs */ -#ifdef MPW -typedef extended va_double; -#else -typedef double va_double; -#endif - -/* Borrowed from Python 1.5.2. -** Python copies its va_list objects before using them in certain -** tricky fashions. We don't why Python does this, but since we're -** abusing our va_list objects in a similar fashion, we'll copy them -** too. */ -#ifdef HAS_VA_COPY -# define VA_LIST_COPY(dest,src) va_copy((dest), (src)) -#else -# if VA_LIST_IS_ARRAY -# define VA_LIST_COPY(dest,src) memcpy((dest), (src), sizeof(va_list)) -# else -# define VA_LIST_COPY(dest,src) ((dest) = (src)) -# endif -#endif - - -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: - case XMLRPC_TYPE_BOOL: - case XMLRPC_TYPE_DOUBLE: - break; - - case XMLRPC_TYPE_ARRAY: - xmlrpc_destroyArrayContents(valueP); - break; - - case XMLRPC_TYPE_STRING: -#ifdef HAVE_UNICODE_WCHAR - if (valueP->_wcs_block) - xmlrpc_mem_block_free(valueP->_wcs_block); -#endif /* HAVE_UNICODE_WCHAR */ - /* Fall through. */ - - case XMLRPC_TYPE_DATETIME: - case XMLRPC_TYPE_BASE64: - xmlrpc_mem_block_clean(&valueP->_block); - break; - - case XMLRPC_TYPE_STRUCT: - xmlrpc_destroyStruct(valueP); - break; - - case XMLRPC_TYPE_C_PTR: - 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 -=========================================================================*/ - -static const char * -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_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"); -} - - - -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"); -} - - - -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.", - typeName(valueP->_type), 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_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; - -} - - - -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_string(xmlrpc_env * const envP, - const xmlrpc_value * const valueP, - const char ** const stringValueP) { -/*---------------------------------------------------------------------------- - Read the value of an XML-RPC string an ASCIIZ string. - - 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). ------------------------------------------------------------------------------*/ - validateType(envP, valueP, XMLRPC_TYPE_STRING); - if (!envP->fault_occurred) { - size_t const size = - XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block); - const char * const contents = - XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block); - - verifyNoNulls(envP, contents, (unsigned int)size); - if (!envP->fault_occurred) { - char * stringValue; - - stringValue = malloc(size+1); - if (stringValue == NULL) - xmlrpc_env_set_fault_formatted( - envP, XMLRPC_INTERNAL_ERROR, "Unable to allocate space " - "for %u-character string", size); - else { - memcpy(stringValue, - XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block), size); - stringValue[size] = '\0'; - - *stringValueP = stringValue; - } - } - } -} - - - -void -xmlrpc_read_string_lp(xmlrpc_env * const envP, - const xmlrpc_value * const valueP, - unsigned int * const lengthP, - const char ** const stringValueP) { - - validateType(envP, valueP, XMLRPC_TYPE_STRING); - 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 * 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 = (unsigned int)size; - } - } -} - - - -/*========================================================================= -** Building XML-RPC values. -**========================================================================= -** Build new XML-RPC values from a format string. This code is heavily -** inspired by Py_BuildValue from Python 1.5.2. In particular, our -** particular abuse of the va_list data type is copied from the equivalent -** Python code in modsupport.c. Since Python is portable, our code should -** (in theory) also be portable. -*/ - - -xmlrpc_type xmlrpc_value_type (xmlrpc_value* value) -{ - XMLRPC_ASSERT_VALUE_OK(value); - return value->_type; -} - - - -static void -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; - - valP = (xmlrpc_value*) malloc(sizeof(xmlrpc_value)); - if (!valP) - xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR, - "Could not allocate memory for xmlrpc_value"); - else - valP->_refcount = 1; - - *valPP = valP; -} - - - -static void -mkInt(xmlrpc_env * const envP, - xmlrpc_int32 const value, - xmlrpc_value ** const valPP) { - - xmlrpc_value * valP; - - createXmlrpcValue(envP, &valP); - - if (!envP->fault_occurred) { - valP->_type = XMLRPC_TYPE_INT; - valP->_value.i = value; - } - *valPP = valP; -} - - - -static void -mkBool(xmlrpc_env * const envP, - xmlrpc_bool const value, - xmlrpc_value ** const valPP) { - - xmlrpc_value * valP; - - createXmlrpcValue(envP, &valP); - - if (!envP->fault_occurred) { - valP->_type = XMLRPC_TYPE_BOOL; - valP->_value.b = value; - } - *valPP = valP; -} - - - -static void -mkDouble(xmlrpc_env * const envP, - double const value, - xmlrpc_value ** const valPP) { - - xmlrpc_value * valP; - - createXmlrpcValue(envP, &valP); - - if (!envP->fault_occurred) { - valP->_type = XMLRPC_TYPE_DOUBLE; - valP->_value.d = value; - } - *valPP = valP; -} - - - -#ifdef HAVE_UNICODE_WCHAR -#define MAKE_WCS_BLOCK_NULL(val) ((val)->_wcs_block = NULL) -#else -#define MAKE_WCS_BLOCK_NULL(val) do {} while(0) -#endif - - - -static void -mkString(xmlrpc_env * const envP, - const char * const value, - unsigned int const length, - xmlrpc_value ** const valPP) { - - xmlrpc_value * valP; - - createXmlrpcValue(envP, &valP); - - if (!envP->fault_occurred) { - valP->_type = XMLRPC_TYPE_STRING; - MAKE_WCS_BLOCK_NULL(valP); - 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); - } - *valPP = valP; -} - - - -static void -getString(xmlrpc_env * const envP, - const char ** const formatP, - va_list * const args, - xmlrpc_value ** const valPP) { - - const char * str; - size_t len; - - str = (const char*) va_arg(*args, char*); - if (**formatP == '#') { - (*formatP)++; - len = (size_t) va_arg(*args, size_t); - } else - len = strlen(str); - - mkString(envP, str, (unsigned int)len, valPP); -} - - - -#ifdef HAVE_UNICODE_WCHAR -static void -mkWideString(xmlrpc_env * const envP, - wchar_t * const wcs, - size_t const wcs_len, - xmlrpc_value ** const valPP) { - - xmlrpc_value * valP; - char *contents; - wchar_t *wcs_contents; - int block_is_inited; - xmlrpc_mem_block *utf8_block; - char *utf8_contents; - size_t utf8_len; - - /* Error-handling preconditions. */ - utf8_block = NULL; - block_is_inited = 0; - - /* Initialize our XML-RPC value. */ - valP = (xmlrpc_value*) malloc(sizeof(xmlrpc_value)); - XMLRPC_FAIL_IF_NULL(valP, envP, XMLRPC_INTERNAL_ERROR, - "Could not allocate memory for wide string"); - valP->_refcount = 1; - valP->_type = XMLRPC_TYPE_STRING; - - /* More error-handling preconditions. */ - valP->_wcs_block = NULL; - - /* Build our wchar_t block first. */ - valP->_wcs_block = - XMLRPC_TYPED_MEM_BLOCK_NEW(wchar_t, envP, wcs_len + 1); - XMLRPC_FAIL_IF_FAULT(envP); - wcs_contents = - XMLRPC_TYPED_MEM_BLOCK_CONTENTS(wchar_t, valP->_wcs_block); - memcpy(wcs_contents, wcs, wcs_len * sizeof(wchar_t)); - wcs_contents[wcs_len] = '\0'; - - /* Convert the wcs block to UTF-8. */ - utf8_block = xmlrpc_wcs_to_utf8(envP, wcs_contents, wcs_len + 1); - XMLRPC_FAIL_IF_FAULT(envP); - utf8_contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, utf8_block); - utf8_len = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, utf8_block); - - /* XXX - We need an extra memcopy to initialize _block. */ - XMLRPC_TYPED_MEM_BLOCK_INIT(char, envP, &valP->_block, utf8_len); - XMLRPC_FAIL_IF_FAULT(envP); - block_is_inited = 1; - contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, &valP->_block); - memcpy(contents, utf8_contents, utf8_len); - - cleanup: - if (utf8_block) - xmlrpc_mem_block_free(utf8_block); - if (envP->fault_occurred) { - if (valP) { - if (valP->_wcs_block) - xmlrpc_mem_block_free(valP->_wcs_block); - if (block_is_inited) - xmlrpc_mem_block_clean(&valP->_block); - free(valP); - } - } - *valPP = valP; -} -#endif /* HAVE_UNICODE_WCHAR */ - - - -static void -getWideString(xmlrpc_env * const envP, - const char ** const formatP, - va_list * const args, - xmlrpc_value ** const valPP) { -#ifdef HAVE_UNICODE_WCHAR - - wchar_t *wcs; - size_t len; - - wcs = (wchar_t*) va_arg(*args, wchar_t*); - if (**formatP == '#') { - (*formatP)++; - len = (size_t) va_arg(*args, size_t); - } else - len = wcslen(wcs); - - mkWideString(envP, wcs, len, valPP); - -#endif /* HAVE_UNICODE_WCHAR */ -} - - - -static void -mkDatetime(xmlrpc_env * const envP, - const char * const value, - xmlrpc_value ** const valPP) { - - xmlrpc_value * valP; - - createXmlrpcValue(envP, &valP); - - if (!envP->fault_occurred) { - valP->_type = XMLRPC_TYPE_DATETIME; - - XMLRPC_TYPED_MEM_BLOCK_INIT( - char, envP, &valP->_block, strlen(value) + 1); - if (!envP->fault_occurred) { - char * const contents = - XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, &valP->_block); - strcpy(contents, value); - } - if (envP->fault_occurred) - free(valP); - } - *valPP = valP; -} - - - -static void -mkBase64(xmlrpc_env * const envP, - const unsigned char * const value, - size_t const length, - xmlrpc_value ** const valPP) { - - xmlrpc_value * valP; - - 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); - } - *valPP = valP; -} - - - -static void -getBase64(xmlrpc_env * const envP, - va_list * const args, - xmlrpc_value ** const valPP) { - - unsigned char * value; - size_t length; - - value = (unsigned char*) va_arg(*args, unsigned char*); - length = (size_t) va_arg(*args, size_t); - - mkBase64(envP, value, length, valPP); -} - - - -static void -mkCPtr(xmlrpc_env * const envP, - void * const value, - xmlrpc_value ** const valPP) { - - xmlrpc_value * valP; - - createXmlrpcValue(envP, &valP); - - if (!envP->fault_occurred) { - valP->_type = XMLRPC_TYPE_C_PTR; - valP->_value.c_ptr = value; - } - *valPP = valP; -} - - - -static void -mkArrayFromVal(xmlrpc_env * const envP, - xmlrpc_value * const value, - xmlrpc_value ** const valPP) { - - if (xmlrpc_value_type(value) != XMLRPC_TYPE_ARRAY) - xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR, - "Array format ('A'), non-array xmlrpc_value"); - else - xmlrpc_INCREF(value); - - *valPP = value; -} - - - -static void -mkStructFromVal(xmlrpc_env * const envP, - xmlrpc_value * const value, - xmlrpc_value ** const valPP) { - - if (xmlrpc_value_type(value) != XMLRPC_TYPE_STRUCT) - xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR, - "Struct format ('S'), non-struct xmlrpc_value"); - else - xmlrpc_INCREF(value); - - *valPP = value; -} - - - -static void -getValue(xmlrpc_env * const envP, - const char** const format, - va_list * const args, - xmlrpc_value ** const valPP); - - - -static void -createXmlrpcArray(xmlrpc_env * const envP, - xmlrpc_value ** const arrayPP) { -/*---------------------------------------------------------------------------- - Create an empty array xmlrpc_value. ------------------------------------------------------------------------------*/ - xmlrpc_value * arrayP; - - createXmlrpcValue(envP, &arrayP); - if (!envP->fault_occurred) { - arrayP->_type = XMLRPC_TYPE_ARRAY; - XMLRPC_TYPED_MEM_BLOCK_INIT(xmlrpc_value*, envP, &arrayP->_block, 0); - if (envP->fault_occurred) - free(arrayP); - } - *arrayPP = arrayP; -} - - - -static void -getArray(xmlrpc_env * const envP, - const char ** const formatP, - char const delimiter, - va_list * const args, - xmlrpc_value ** const arrayPP) { - - xmlrpc_value * arrayP; - - createXmlrpcArray(envP, &arrayP); - - /* Add items to the array until we hit our delimiter. */ - - while (**formatP != delimiter && !envP->fault_occurred) { - - xmlrpc_value * itemP; - - if (**formatP == '\0') - xmlrpc_env_set_fault( - envP, XMLRPC_INTERNAL_ERROR, - "format string ended before closing ')'."); - else { - getValue(envP, formatP, args, &itemP); - if (!envP->fault_occurred) { - xmlrpc_array_append_item(envP, arrayP, itemP); - xmlrpc_DECREF(itemP); - } - } - } - if (envP->fault_occurred) - xmlrpc_DECREF(arrayP); - - *arrayPP = arrayP; -} - - - -static void -getStructMember(xmlrpc_env * const envP, - const char ** const formatP, - va_list * const args, - xmlrpc_value ** const keyPP, - xmlrpc_value ** const valuePP) { - - - /* Get the key */ - getValue(envP, formatP, args, keyPP); - if (!envP->fault_occurred) { - if (**formatP != ':') - xmlrpc_env_set_fault( - envP, XMLRPC_INTERNAL_ERROR, - "format string does not have ':' after a " - "structure member key."); - else { - /* Skip over colon that separates key from value */ - (*formatP)++; - - /* Get the value */ - getValue(envP, formatP, args, valuePP); - } - if (envP->fault_occurred) - xmlrpc_DECREF(*keyPP); - } -} - - - -static void -getStruct(xmlrpc_env * const envP, - const char ** const formatP, - char const delimiter, - va_list * const args, - xmlrpc_value ** const structPP) { - - xmlrpc_value * structP; - - structP = xmlrpc_struct_new(envP); - if (!envP->fault_occurred) { - while (**formatP != delimiter && !envP->fault_occurred) { - xmlrpc_value * keyP; - xmlrpc_value * valueP; - - getStructMember(envP, formatP, args, &keyP, &valueP); - - if (!envP->fault_occurred) { - if (**formatP == ',') - (*formatP)++; /* Skip over the comma */ - else if (**formatP == delimiter) { - /* End of the line */ - } else - xmlrpc_env_set_fault( - envP, XMLRPC_INTERNAL_ERROR, - "format string does not have ',' or ')' after " - "a structure member"); - - if (!envP->fault_occurred) - /* Add the new member to the struct. */ - xmlrpc_struct_set_value_v(envP, structP, keyP, valueP); - - xmlrpc_DECREF(valueP); - xmlrpc_DECREF(keyP); - } - } - if (envP->fault_occurred) - xmlrpc_DECREF(structP); - } - *structPP = structP; -} - - - -static void -getValue(xmlrpc_env * const envP, - const char** const formatP, - va_list * const args, - xmlrpc_value ** const valPP) { -/*---------------------------------------------------------------------------- - Get the next value from the list. *formatP points to the specifier - for the next value in the format string (i.e. to the type code - character) and we move *formatP past the whole specifier for the - next value. We read the required arguments from 'args'. We return - the value as *valPP with a reference to it. - - For example, if *formatP points to the "i" in the string "sis", - we read one argument from 'args' and return as *valP an integer whose - value is the argument we read. We advance *formatP to point to the - last 's' and advance 'args' to point to the argument that belongs to - that 's'. ------------------------------------------------------------------------------*/ - char const formatChar = *(*formatP)++; - - switch (formatChar) { - case 'i': - mkInt(envP, (xmlrpc_int32) va_arg(*args, xmlrpc_int32), valPP); - break; - - case 'b': - mkBool(envP, (xmlrpc_bool) va_arg(*args, xmlrpc_bool), valPP); - break; - - case 'd': - mkDouble(envP, (double) va_arg(*args, va_double), valPP); - break; - - case 's': - getString(envP, formatP, args, valPP); - break; - - case 'w': - getWideString(envP, formatP, args, valPP); - break; - - /* The code 't' is reserved for a better, time_t based - implementation of dateTime conversion. - */ - case '8': - mkDatetime(envP, (char*) va_arg(*args, char*), valPP); - break; - - case '6': - getBase64(envP, args, valPP); - break; - - case 'p': - /* We might someday want to use the code 'p!' to read in a - cleanup function for this pointer. - */ - mkCPtr(envP, (void*) va_arg(*args, void*), valPP); - break; - - case 'A': - mkArrayFromVal(envP, (xmlrpc_value*) va_arg(*args, xmlrpc_value*), - valPP); - break; - - case 'S': - mkStructFromVal(envP, (xmlrpc_value*) va_arg(*args, xmlrpc_value*), - valPP); - break; - - case 'V': - *valPP = (xmlrpc_value*) va_arg(*args, xmlrpc_value*); - xmlrpc_INCREF(*valPP); - break; - - case '(': - getArray(envP, formatP, ')', args, valPP); - if (!envP->fault_occurred) { - XMLRPC_ASSERT(**formatP == ')'); - (*formatP)++; /* Skip over closing parenthesis */ - } - break; - - case '{': - getStruct(envP, formatP, '}', args, valPP); - if (!envP->fault_occurred) { - XMLRPC_ASSERT(**formatP == '}'); - (*formatP)++; /* Skip over closing brace */ - } - break; - - default: { - const char * const badCharacter = xmlrpc_makePrintableChar(formatChar); - xmlrpc_env_set_fault_formatted( - envP, XMLRPC_INTERNAL_ERROR, - "Unexpected character '%s' in format string", badCharacter); - xmlrpc_strfree(badCharacter); - } - } -} - - - -void -xmlrpc_build_value_va(xmlrpc_env * const envP, - const char * const format, - va_list args, - xmlrpc_value ** const valPP, - const char ** const tailP) { - - const char * formatCursor; - va_list args_copy; - - XMLRPC_ASSERT_ENV_OK(envP); - XMLRPC_ASSERT(format != NULL); - - if (strlen(format) == 0) - xmlrpc_env_set_fault_formatted( - envP, XMLRPC_INTERNAL_ERROR, "Format string is empty."); - else { - formatCursor = &format[0]; - VA_LIST_COPY(args_copy, args); - getValue(envP, &formatCursor, &args_copy, valPP); - - if (!envP->fault_occurred) - XMLRPC_ASSERT_VALUE_OK(*valPP); - - *tailP = formatCursor; - } -} - - - -xmlrpc_value * -xmlrpc_build_value(xmlrpc_env * const envP, - const char * const format, - ...) { - - va_list args; - xmlrpc_value* retval; - const char * suffix; - - va_start(args, format); - xmlrpc_build_value_va(envP, format, args, &retval, &suffix); - va_end(args); - - if (!envP->fault_occurred) { - if (*suffix != '\0') - xmlrpc_env_set_fault_formatted( - envP, XMLRPC_INTERNAL_ERROR, "Junk after the argument " - "specifier: '%s'. There must be exactly one arument.", - suffix); - - if (envP->fault_occurred) - xmlrpc_DECREF(retval); - } - return retval; -} - - -/*========================================================================= -** Parsing XML-RPC values. -**========================================================================= -** Parse an XML-RPC value based on a format string. This code is heavily -** inspired by Py_BuildValue from Python 1.5.2. -*/ - -/* Prototype for recursive invocation: */ - -static void -parsevalue(xmlrpc_env * const env, - xmlrpc_value * const val, - const char ** const format, - va_list * args); - -static void -parsearray(xmlrpc_env * const env, - const xmlrpc_value * const array, - const char ** const format, - char const delimiter, - va_list * args) { - - int size, i; - xmlrpc_value *item; - - /* Fetch the array size. */ - size = xmlrpc_array_size(env, array); - XMLRPC_FAIL_IF_FAULT(env); - - /* Loop over the items in the array. */ - for (i = 0; i < size; i++) { - /* Bail out if the caller didn't care about the rest of the items. */ - if (**format == '*') - break; - - item = xmlrpc_array_get_item(env, array, i); - XMLRPC_FAIL_IF_FAULT(env); - - XMLRPC_ASSERT(**format != '\0'); - if (**format == delimiter) - XMLRPC_FAIL(env, XMLRPC_INDEX_ERROR, "Too many items in array"); - parsevalue(env, item, format, args); - XMLRPC_FAIL_IF_FAULT(env); - } - if (**format == '*') - (*format)++; - if (**format != delimiter) - XMLRPC_FAIL(env, XMLRPC_INDEX_ERROR, "Not enough items in array"); - - cleanup: - return; -} - - - -static void -parsestruct(xmlrpc_env * const env, - xmlrpc_value * const strct, - const char ** const format, - char const delimiter, - va_list * args) { - - xmlrpc_value *key, *value; - char *keystr; - size_t keylen; - - /* Set up error handling preconditions. */ - key = NULL; - - /* Build the members of our struct. */ - while (**format != '*' && **format != delimiter && **format != '\0') { - - /* Get our key, and skip over the ':' character. Notice the - ** sudden call to getValue--we're going in the opposite direction. */ - getValue(env, format, args, &key); - XMLRPC_FAIL_IF_FAULT(env); - XMLRPC_ASSERT(**format == ':'); - (*format)++; - - /* Look up the value for our key. */ - xmlrpc_parse_value(env, key, "s#", &keystr, &keylen); - XMLRPC_FAIL_IF_FAULT(env); - value = xmlrpc_struct_get_value_n(env, strct, keystr, keylen); - XMLRPC_FAIL_IF_FAULT(env); - - /* Get our value, and skip over the ',' character (if present). */ - parsevalue(env, value, format, args); - XMLRPC_FAIL_IF_FAULT(env); - XMLRPC_ASSERT(**format == ',' || **format == delimiter); - if (**format == ',') - (*format)++; - - /* Release our reference, and restore our invariant. */ - xmlrpc_DECREF(key); - key = NULL; - } - if (**format == '*') { - (*format)++; - if (**format != delimiter && **format != '\0') - XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, - "* can appear only at the end " - "of a structure format specifier"); - } else { - /* Here we're supposed to fail if he didn't extract all the - members. But we don't know how to determine whether he - specified all the members, so we always fail. - */ - XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "You must specify '*' as the " - "last member of a structure in a format specifier " - "used for parsing an xmlrpc_value"); - } - XMLRPC_ASSERT(**format == delimiter || **format == '\0'); - -cleanup: - if (key) - xmlrpc_DECREF(key); -} - - -static void -parsevalue(xmlrpc_env * const envP, - xmlrpc_value * const valueP, - const char ** const format, - va_list * args) { - - char formatSpecChar; - - formatSpecChar = *(*format)++; - - switch (formatSpecChar) { - case 'i': - validateType(envP, valueP, XMLRPC_TYPE_INT); - if (!envP->fault_occurred) { - xmlrpc_int32 * const int32ptr = - (xmlrpc_int32*) va_arg(*args, xmlrpc_int32*); - *int32ptr = valueP->_value.i; - } - break; - - case 'b': - validateType(envP, valueP, XMLRPC_TYPE_BOOL); - if (!envP->fault_occurred) { - xmlrpc_bool * const boolptr = - (xmlrpc_bool*) va_arg(*args, xmlrpc_bool*); - *boolptr = valueP->_value.b; - } - break; - - case 'd': - validateType(envP, valueP, XMLRPC_TYPE_DOUBLE); - if (!envP->fault_occurred) { - double * const doubleptr = (double*) va_arg(*args, double*); - *doubleptr = valueP->_value.d; - } - break; - - case 's': - validateType(envP, valueP, XMLRPC_TYPE_STRING); - if (!envP->fault_occurred) { - char * const contents = - XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block); - size_t const len = XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block) - 1; - - char ** const strptr = (char**) va_arg(*args, char**); - if (**format == '#') { - size_t * const sizeptr = (size_t*) va_arg(*args, size_t**); - (*format)++; - *sizeptr = len; - } else - verifyNoNulls(envP, contents, (unsigned int)len); - *strptr = contents; - } - break; - -#ifdef HAVE_UNICODE_WCHAR - case 'w': - validateType(envP, valueP, XMLRPC_TYPE_STRING); - if (!envP->fault_occurred) { - if (!valueP->_wcs_block) { - /* Allocate a wchar_t string if we don't have one. */ - 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 (!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; - - wchar_t ** const wcsptr = (wchar_t**) va_arg(*args, wchar_t**); - if (**format == '#') { - size_t * const sizeptr = (size_t*) va_arg(*args, size_t**); - (*format)++; - *sizeptr = len; - } else - verifyNoNullsW(envP, wcontents, (unsigned int)len); - *wcsptr = wcontents; - } - } - break; -#endif /* HAVE_UNICODE_WCHAR */ - - case '8': - /* The code 't' is reserved for a better, time_t based - ** implementation of dateTime conversion. */ - validateType(envP, valueP, XMLRPC_TYPE_DATETIME); - if (!envP->fault_occurred) { - char * const contents = - XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block); - char ** const strptr = (char**) va_arg(*args, char**); - *strptr = contents; - } - break; - - case '6': - validateType(envP, valueP, XMLRPC_TYPE_BASE64); - if (!envP->fault_occurred) { - unsigned char * const bin_data = - XMLRPC_MEMBLOCK_CONTENTS(unsigned char, - &valueP->_block); - size_t const len = XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block); - unsigned char ** const binptr = - (unsigned char**) va_arg(*args, unsigned char**); - size_t * const sizeptr = (size_t*) va_arg(*args, size_t**); - *binptr = bin_data; - *sizeptr = len; - } - break; - - case 'p': - validateType(envP, valueP, XMLRPC_TYPE_C_PTR); - if (!envP->fault_occurred) { - void ** const voidptrptr = (void**) va_arg(*args, void**); - *voidptrptr = valueP->_value.c_ptr; - } - break; - - case 'V': { - xmlrpc_value ** const valptr = - (xmlrpc_value**) va_arg(*args, xmlrpc_value**); - *valptr = valueP; - } - break; - - case 'A': - validateType(envP, valueP, XMLRPC_TYPE_ARRAY); - if (!envP->fault_occurred) { - xmlrpc_value ** const valptr = - (xmlrpc_value**) va_arg(*args, xmlrpc_value**); - *valptr = valueP; - } - break; - - case 'S': - validateType(envP, valueP, XMLRPC_TYPE_STRUCT); - if (!envP->fault_occurred) { - xmlrpc_value ** const valptr = - (xmlrpc_value**) va_arg(*args, xmlrpc_value**); - *valptr = valueP; - } - break; - - case '(': - validateType(envP, valueP, XMLRPC_TYPE_ARRAY); - if (!envP->fault_occurred) { - parsearray(envP, valueP, format, ')', args); - (*format)++; - } - break; - - case '{': - validateType(envP, valueP, XMLRPC_TYPE_STRUCT); - if (!envP->fault_occurred) { - parsestruct(envP, valueP, format, '}', args); - (*format)++; - } - break; - - default: - xmlrpc_env_set_fault_formatted( - envP, XMLRPC_INTERNAL_ERROR, "Invalid format character '%c'", - formatSpecChar); - } -} - - - -void -xmlrpc_parse_value_va(xmlrpc_env * const envP, - xmlrpc_value * const value, - const char * const format, - va_list args) { - - const char *format_copy; - va_list args_copy; - - XMLRPC_ASSERT_ENV_OK(envP); - XMLRPC_ASSERT_VALUE_OK(value); - XMLRPC_ASSERT(format != NULL); - - format_copy = format; - VA_LIST_COPY(args_copy, args); - parsevalue(envP, value, &format_copy, &args_copy); - if (!envP->fault_occurred) { - XMLRPC_ASSERT(*format_copy == '\0'); - } -} - - - -void -xmlrpc_parse_value(xmlrpc_env * const envP, - xmlrpc_value * const value, - const char * const format, - ...) { - - va_list args; - - va_start(args, format); - xmlrpc_parse_value_va(envP, value, format, args); - va_end(args); -} - - - -/* 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. */ |