2006-12-21 03:57:49 +00:00
|
|
|
/* 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:
|
2008-05-23 20:56:24 +00:00
|
|
|
xmlrpc_destroyString(valueP);
|
2006-12-21 03:57:49 +00:00
|
|
|
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;
|
|
|
|
|
2008-05-23 20:56:24 +00:00
|
|
|
case XMLRPC_TYPE_I8:
|
|
|
|
break;
|
|
|
|
|
2006-12-21 03:57:49 +00:00
|
|
|
case XMLRPC_TYPE_DEAD:
|
2008-05-23 20:56:24 +00:00
|
|
|
XMLRPC_ASSERT(false); /* Can't happen, per entry conditions */
|
2006-12-21 03:57:49 +00:00
|
|
|
|
|
|
|
default:
|
2008-05-23 20:56:24 +00:00
|
|
|
XMLRPC_ASSERT(false); /* There are no other possible values */
|
2006-12-21 03:57:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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 *
|
2008-05-23 20:56:24 +00:00
|
|
|
xmlrpc_type_name(xmlrpc_type const type) {
|
2006-12-21 03:57:49 +00:00
|
|
|
|
2008-05-23 20:56:24 +00:00
|
|
|
switch (type) {
|
2006-12-21 03:57:49 +00:00
|
|
|
|
|
|
|
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";
|
2008-05-23 20:56:24 +00:00
|
|
|
case XMLRPC_TYPE_I8: return "I8";
|
2006-12-21 03:57:49 +00:00
|
|
|
case XMLRPC_TYPE_DEAD: return "DEAD";
|
|
|
|
default: return "???";
|
|
|
|
|
2008-05-23 20:56:24 +00:00
|
|
|
}
|
2006-12-21 03:57:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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.",
|
2008-05-23 20:56:24 +00:00
|
|
|
xmlrpc_type_name(valueP->_type), xmlrpc_type_name(expectedType));
|
2006-12-21 03:57:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*=========================================================================
|
|
|
|
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;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-05-23 20:56:24 +00:00
|
|
|
/* datetime stuff is in xmlrpc_datetime.c */
|
2006-12-21 03:57:49 +00:00
|
|
|
|
2008-05-23 20:56:24 +00:00
|
|
|
/* string stuff is in xmlrpc_string.c */
|
2006-12-21 03:57:49 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-05-23 20:56:24 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2006-12-21 03:57:49 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-05-23 20:56:24 +00:00
|
|
|
void
|
|
|
|
xmlrpc_read_i8(xmlrpc_env * const envP,
|
|
|
|
const xmlrpc_value * const valueP,
|
|
|
|
xmlrpc_int64 * const intValueP) {
|
2006-12-21 03:57:49 +00:00
|
|
|
|
2008-05-23 20:56:24 +00:00
|
|
|
validateType(envP, valueP, XMLRPC_TYPE_I8);
|
2006-12-21 03:57:49 +00:00
|
|
|
if (!envP->fault_occurred)
|
2008-05-23 20:56:24 +00:00
|
|
|
*intValueP = valueP->_value.i8;
|
2006-12-21 03:57:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-05-23 20:56:24 +00:00
|
|
|
xmlrpc_type xmlrpc_value_type (xmlrpc_value* const value)
|
2006-12-21 03:57:49 +00:00
|
|
|
{
|
|
|
|
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 *
|
2008-05-23 20:56:24 +00:00
|
|
|
xmlrpc_i8_new(xmlrpc_env * const envP,
|
|
|
|
xmlrpc_int64 const value) {
|
2006-12-21 03:57:49 +00:00
|
|
|
|
|
|
|
xmlrpc_value * valP;
|
|
|
|
|
|
|
|
xmlrpc_createXmlrpcValue(envP, &valP);
|
|
|
|
|
|
|
|
if (!envP->fault_occurred) {
|
2008-05-23 20:56:24 +00:00
|
|
|
valP->_type = XMLRPC_TYPE_I8;
|
|
|
|
valP->_value.i8 = value;
|
2006-12-21 03:57:49 +00:00
|
|
|
}
|
|
|
|
return valP;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
xmlrpc_value *
|
2008-05-23 20:56:24 +00:00
|
|
|
xmlrpc_bool_new(xmlrpc_env * const envP,
|
|
|
|
xmlrpc_bool const value) {
|
2006-12-21 03:57:49 +00:00
|
|
|
|
|
|
|
xmlrpc_value * valP;
|
|
|
|
|
|
|
|
xmlrpc_createXmlrpcValue(envP, &valP);
|
|
|
|
|
|
|
|
if (!envP->fault_occurred) {
|
2008-05-23 20:56:24 +00:00
|
|
|
valP->_type = XMLRPC_TYPE_BOOL;
|
|
|
|
valP->_value.b = value;
|
2006-12-21 03:57:49 +00:00
|
|
|
}
|
|
|
|
return valP;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
xmlrpc_value *
|
2008-05-23 20:56:24 +00:00
|
|
|
xmlrpc_double_new(xmlrpc_env * const envP,
|
|
|
|
double const value) {
|
2006-12-21 03:57:49 +00:00
|
|
|
|
|
|
|
xmlrpc_value * valP;
|
|
|
|
|
|
|
|
xmlrpc_createXmlrpcValue(envP, &valP);
|
|
|
|
|
|
|
|
if (!envP->fault_occurred) {
|
2008-05-23 20:56:24 +00:00
|
|
|
valP->_type = XMLRPC_TYPE_DOUBLE;
|
|
|
|
valP->_value.d = value;
|
2006-12-21 03:57:49 +00:00
|
|
|
}
|
|
|
|
return valP;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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. */
|