mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-08-13 17:38:59 +00:00
merged new xmlrpc-c revision 1472 from https://xmlrpc-c.svn.sourceforge.net/svnroot/xmlrpc-c/trunk
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@8545 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
751
libs/xmlrpc-c/src/parse_value.c
Normal file
751
libs/xmlrpc-c/src/parse_value.c
Normal file
@@ -0,0 +1,751 @@
|
||||
#include "xmlrpc_config.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <float.h>
|
||||
|
||||
#include "bool.h"
|
||||
|
||||
#include "xmlrpc-c/base.h"
|
||||
#include "xmlrpc-c/base_int.h"
|
||||
#include "xmlrpc-c/string_int.h"
|
||||
#include "xmlrpc-c/util.h"
|
||||
#include "xmlrpc-c/xmlparser.h"
|
||||
|
||||
#include "parse_value.h"
|
||||
|
||||
|
||||
|
||||
static void
|
||||
setParseFault(xmlrpc_env * const envP,
|
||||
const char * const format,
|
||||
...) {
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
xmlrpc_set_fault_formatted_v(envP, XMLRPC_PARSE_ERROR, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
parseArrayDataChild(xmlrpc_env * const envP,
|
||||
xml_element * const childP,
|
||||
unsigned int const maxRecursion,
|
||||
xmlrpc_value * const arrayP) {
|
||||
|
||||
const char * const elemName = xml_element_name(childP);
|
||||
|
||||
if (!xmlrpc_streq(elemName, "value"))
|
||||
setParseFault(envP, "<data> element has <%s> child. "
|
||||
"Only <value> makes sense.", elemName);
|
||||
else {
|
||||
xmlrpc_value * itemP;
|
||||
|
||||
xmlrpc_parseValue(envP, maxRecursion-1, childP, &itemP);
|
||||
|
||||
if (!envP->fault_occurred) {
|
||||
xmlrpc_array_append_item(envP, arrayP, itemP);
|
||||
|
||||
xmlrpc_DECREF(itemP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
parseArray(xmlrpc_env * const envP,
|
||||
unsigned int const maxRecursion,
|
||||
xml_element * const arrayElemP,
|
||||
xmlrpc_value ** const arrayPP) {
|
||||
|
||||
xmlrpc_value * arrayP;
|
||||
|
||||
XMLRPC_ASSERT_ENV_OK(envP);
|
||||
XMLRPC_ASSERT(arrayElemP != NULL);
|
||||
|
||||
arrayP = xmlrpc_array_new(envP);
|
||||
if (!envP->fault_occurred) {
|
||||
unsigned int const childCount = xml_element_children_size(arrayElemP);
|
||||
|
||||
if (childCount != 1)
|
||||
setParseFault(envP,
|
||||
"<array> element has %u children. Only one <data> "
|
||||
"makes sense.", childCount);
|
||||
else {
|
||||
xml_element * const dataElemP =
|
||||
xml_element_children(arrayElemP)[0];
|
||||
const char * const elemName = xml_element_name(dataElemP);
|
||||
|
||||
if (!xmlrpc_streq(elemName, "data"))
|
||||
setParseFault(envP,
|
||||
"<array> element has <%s> child. Only <data> "
|
||||
"makes sense.", elemName);
|
||||
else {
|
||||
xml_element ** const values = xml_element_children(dataElemP);
|
||||
unsigned int const size = xml_element_children_size(dataElemP);
|
||||
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < size && !envP->fault_occurred; ++i)
|
||||
parseArrayDataChild(envP, values[i], maxRecursion, arrayP);
|
||||
}
|
||||
}
|
||||
if (envP->fault_occurred)
|
||||
xmlrpc_DECREF(arrayP);
|
||||
else
|
||||
*arrayPP = arrayP;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
parseName(xmlrpc_env * const envP,
|
||||
xml_element * const nameElemP,
|
||||
xmlrpc_value ** const valuePP) {
|
||||
|
||||
unsigned int const childCount = xml_element_children_size(nameElemP);
|
||||
|
||||
if (childCount > 0)
|
||||
setParseFault(envP, "<name> element has %u children. "
|
||||
"Should have none.", childCount);
|
||||
else {
|
||||
const char * const cdata = xml_element_cdata(nameElemP);
|
||||
size_t const cdataSize = xml_element_cdata_size(nameElemP);
|
||||
|
||||
*valuePP = xmlrpc_string_new_lp(envP, cdataSize, cdata);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
getNameChild(xmlrpc_env * const envP,
|
||||
xml_element * const parentP,
|
||||
xml_element * * const childPP) {
|
||||
|
||||
xml_element ** const children = xml_element_children(parentP);
|
||||
size_t const childCount = xml_element_children_size(parentP);
|
||||
|
||||
xml_element * childP;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0, childP = NULL; i < childCount && !childP; ++i) {
|
||||
if (xmlrpc_streq(xml_element_name(children[i]), "name"))
|
||||
childP = children[i];
|
||||
}
|
||||
if (!childP)
|
||||
xmlrpc_env_set_fault(envP, XMLRPC_PARSE_ERROR,
|
||||
"<member> has no <name> child");
|
||||
else
|
||||
*childPP = childP;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
getValueChild(xmlrpc_env * const envP,
|
||||
xml_element * const parentP,
|
||||
xml_element * * const childPP) {
|
||||
|
||||
xml_element ** const children = xml_element_children(parentP);
|
||||
size_t const childCount = xml_element_children_size(parentP);
|
||||
|
||||
xml_element * childP;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0, childP = NULL; i < childCount && !childP; ++i) {
|
||||
if (xmlrpc_streq(xml_element_name(children[i]), "value"))
|
||||
childP = children[i];
|
||||
}
|
||||
if (!childP)
|
||||
xmlrpc_env_set_fault(envP, XMLRPC_PARSE_ERROR,
|
||||
"<member> has no <value> child");
|
||||
else
|
||||
*childPP = childP;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
parseMember(xmlrpc_env * const envP,
|
||||
xml_element * const memberP,
|
||||
unsigned int const maxRecursion,
|
||||
xmlrpc_value ** const keyPP,
|
||||
xmlrpc_value ** const valuePP) {
|
||||
|
||||
unsigned int const childCount = xml_element_children_size(memberP);
|
||||
|
||||
if (childCount != 2)
|
||||
setParseFault(envP,
|
||||
"<member> element has %u children. Only one <name> and "
|
||||
"one <value> make sense.", childCount);
|
||||
else {
|
||||
xml_element * nameElemP;
|
||||
|
||||
getNameChild(envP, memberP, &nameElemP);
|
||||
|
||||
if (!envP->fault_occurred) {
|
||||
parseName(envP, nameElemP, keyPP);
|
||||
|
||||
if (!envP->fault_occurred) {
|
||||
xml_element * valueElemP;
|
||||
|
||||
getValueChild(envP, memberP, &valueElemP);
|
||||
|
||||
if (!envP->fault_occurred)
|
||||
xmlrpc_parseValue(envP, maxRecursion-1, valueElemP,
|
||||
valuePP);
|
||||
|
||||
if (envP->fault_occurred)
|
||||
xmlrpc_DECREF(*keyPP);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
parseStruct(xmlrpc_env * const envP,
|
||||
unsigned int const maxRecursion,
|
||||
xml_element * const elemP,
|
||||
xmlrpc_value ** const structPP) {
|
||||
/*----------------------------------------------------------------------------
|
||||
Parse the <struct> element 'elemP'.
|
||||
-----------------------------------------------------------------------------*/
|
||||
xmlrpc_value * structP;
|
||||
|
||||
XMLRPC_ASSERT_ENV_OK(envP);
|
||||
XMLRPC_ASSERT(elemP != NULL);
|
||||
|
||||
structP = xmlrpc_struct_new(envP);
|
||||
if (!envP->fault_occurred) {
|
||||
/* Iterate over our children, extracting key/value pairs. */
|
||||
|
||||
xml_element ** const members = xml_element_children(elemP);
|
||||
unsigned int const size = xml_element_children_size(elemP);
|
||||
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < size && !envP->fault_occurred; ++i) {
|
||||
const char * const elemName = xml_element_name(members[i]);
|
||||
|
||||
if (!xmlrpc_streq(elemName, "member"))
|
||||
setParseFault(envP, "<%s> element found where only <member> "
|
||||
"makes sense", elemName);
|
||||
else {
|
||||
xmlrpc_value * keyP;
|
||||
xmlrpc_value * valueP;
|
||||
|
||||
parseMember(envP, members[i], maxRecursion, &keyP, &valueP);
|
||||
|
||||
if (!envP->fault_occurred) {
|
||||
xmlrpc_struct_set_value_v(envP, structP, keyP, valueP);
|
||||
|
||||
xmlrpc_DECREF(keyP);
|
||||
xmlrpc_DECREF(valueP);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (envP->fault_occurred)
|
||||
xmlrpc_DECREF(structP);
|
||||
else
|
||||
*structPP = structP;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
parseInt(xmlrpc_env * const envP,
|
||||
const char * const str,
|
||||
xmlrpc_value ** const valuePP) {
|
||||
/*----------------------------------------------------------------------------
|
||||
Parse the content of a <int> XML-RPC XML element, e.g. "34".
|
||||
|
||||
'str' is that content.
|
||||
-----------------------------------------------------------------------------*/
|
||||
XMLRPC_ASSERT_ENV_OK(envP);
|
||||
XMLRPC_ASSERT_PTR_OK(str);
|
||||
|
||||
if (str[0] == '\0')
|
||||
setParseFault(envP, "<int> XML element content is empty");
|
||||
else if (isspace(str[0]))
|
||||
setParseFault(envP, "<int> content '%s' starts with white space",
|
||||
str);
|
||||
else {
|
||||
long i;
|
||||
char * tail;
|
||||
|
||||
errno = 0;
|
||||
i = strtol(str, &tail, 10);
|
||||
|
||||
/* Look for ERANGE. */
|
||||
if (errno == ERANGE)
|
||||
setParseFault(envP, "<int> XML element value '%s' represents a "
|
||||
"number beyond the range that "
|
||||
"XML-RPC allows (%d - %d)", str,
|
||||
XMLRPC_INT32_MIN, XMLRPC_INT32_MAX);
|
||||
else if (errno != 0)
|
||||
setParseFault(envP, "unexpected error parsing <int> XML element "
|
||||
"value '%s'. strtol() failed with errno %d (%s)",
|
||||
str, errno, strerror(errno));
|
||||
else {
|
||||
/* Look for out-of-range errors which didn't produce ERANGE. */
|
||||
if (i < XMLRPC_INT32_MIN)
|
||||
setParseFault(envP,
|
||||
"<int> value %d is below the range allowed "
|
||||
"by XML-RPC (minimum is %d)",
|
||||
i, XMLRPC_INT32_MIN);
|
||||
else if (i > XMLRPC_INT32_MAX)
|
||||
setParseFault(envP,
|
||||
"<int> value %d is above the range allowed "
|
||||
"by XML-RPC (maximum is %d)",
|
||||
i, XMLRPC_INT32_MAX);
|
||||
else {
|
||||
if (tail[0] != '\0')
|
||||
setParseFault(envP,
|
||||
"<int> value '%s' contains non-numerical "
|
||||
"junk: '%s'", str, tail);
|
||||
else
|
||||
*valuePP = xmlrpc_int_new(envP, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
parseBoolean(xmlrpc_env * const envP,
|
||||
const char * const str,
|
||||
xmlrpc_value ** const valuePP) {
|
||||
/*----------------------------------------------------------------------------
|
||||
Parse the content of a <boolean> XML-RPC XML element, e.g. "1".
|
||||
|
||||
'str' is that content.
|
||||
-----------------------------------------------------------------------------*/
|
||||
XMLRPC_ASSERT_ENV_OK(envP);
|
||||
XMLRPC_ASSERT_PTR_OK(str);
|
||||
|
||||
if (xmlrpc_streq(str, "0") || xmlrpc_streq(str, "1"))
|
||||
*valuePP = xmlrpc_bool_new(envP, xmlrpc_streq(str, "1") ? 1 : 0);
|
||||
else
|
||||
setParseFault(envP, "<boolean> XML element content must be either "
|
||||
"'0' or '1' according to XML-RPC. This one has '%s'",
|
||||
str);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
scanAndValidateDoubleString(xmlrpc_env * const envP,
|
||||
const char * const string,
|
||||
const char ** const mantissaP,
|
||||
const char ** const mantissaEndP,
|
||||
const char ** const fractionP,
|
||||
const char ** const fractionEndP) {
|
||||
|
||||
const char * mantissa;
|
||||
const char * dp;
|
||||
const char * p;
|
||||
|
||||
if (string[0] == '-' || string[0] == '+')
|
||||
mantissa = &string[1];
|
||||
else
|
||||
mantissa = &string[0];
|
||||
|
||||
for (p = mantissa, dp = NULL; *p; ++p) {
|
||||
char const c = *p;
|
||||
if (c == '.') {
|
||||
if (dp) {
|
||||
setParseFault(envP, "Two decimal points");
|
||||
return;
|
||||
} else
|
||||
dp = p;
|
||||
} else if (c < '0' || c > '9') {
|
||||
setParseFault(envP, "Garbage (not sign, digit, or period) "
|
||||
"starting at '%s'", p);
|
||||
return;
|
||||
}
|
||||
}
|
||||
*mantissaP = mantissa;
|
||||
if (dp) {
|
||||
*mantissaEndP = dp;
|
||||
*fractionP = dp+1;
|
||||
*fractionEndP = p;
|
||||
} else {
|
||||
*mantissaEndP = p;
|
||||
*fractionP = p;
|
||||
*fractionEndP = p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool
|
||||
isInfinite(double const value) {
|
||||
|
||||
return value > DBL_MAX;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
parseDoubleString(xmlrpc_env * const envP,
|
||||
const char * const string,
|
||||
double * const valueP) {
|
||||
/*----------------------------------------------------------------------------
|
||||
Turn e.g. "4.3" into 4.3 .
|
||||
-----------------------------------------------------------------------------*/
|
||||
/* strtod() is no good for this because it is designed for human
|
||||
interfaces; it parses according to locale. As a practical
|
||||
matter that sometimes means that it does not recognize "." as a
|
||||
decimal point. In XML-RPC, "." is a decimal point.
|
||||
|
||||
Design note: in my experiments, using strtod() was 10 times
|
||||
slower than using this function.
|
||||
*/
|
||||
const char * mantissa;
|
||||
const char * mantissaEnd;
|
||||
const char * fraction;
|
||||
const char * fractionEnd;
|
||||
|
||||
scanAndValidateDoubleString(envP, string, &mantissa, &mantissaEnd,
|
||||
&fraction, &fractionEnd);
|
||||
|
||||
if (!envP->fault_occurred) {
|
||||
double accum;
|
||||
|
||||
accum = 0.0;
|
||||
|
||||
if (mantissa == mantissaEnd && fraction == fractionEnd) {
|
||||
setParseFault(envP, "No digits");
|
||||
return;
|
||||
}
|
||||
{
|
||||
/* Add in the whole part */
|
||||
const char * p;
|
||||
|
||||
for (p = mantissa; p < mantissaEnd; ++p) {
|
||||
accum *= 10;
|
||||
accum += (*p - '0');
|
||||
}
|
||||
}
|
||||
{
|
||||
/* Add in the fractional part */
|
||||
double significance;
|
||||
const char * p;
|
||||
for (significance = 0.1, p = fraction;
|
||||
p < fractionEnd;
|
||||
++p, significance *= 0.1) {
|
||||
|
||||
accum += (*p - '0') * significance;
|
||||
}
|
||||
}
|
||||
if (isInfinite(accum))
|
||||
setParseFault(envP, "Value exceeds the size allowed by XML-RPC");
|
||||
else
|
||||
*valueP = string[0] == '-' ? (- accum) : accum;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
parseDoubleStringStrtod(const char * const str,
|
||||
bool * const failedP,
|
||||
double * const valueP) {
|
||||
|
||||
if (strlen(str) == 0) {
|
||||
/* strtod() happily interprets empty string as 0.0. We don't think
|
||||
the user will appreciate that XML-RPC extension.
|
||||
*/
|
||||
*failedP = true;
|
||||
} else {
|
||||
char * tail;
|
||||
|
||||
errno = 0;
|
||||
|
||||
*valueP = strtod(str, &tail);
|
||||
|
||||
if (errno != 0)
|
||||
*failedP = true;
|
||||
else {
|
||||
if (tail[0] != '\0')
|
||||
*failedP = true;
|
||||
else
|
||||
*failedP = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
parseDouble(xmlrpc_env * const envP,
|
||||
const char * const str,
|
||||
xmlrpc_value ** const valuePP) {
|
||||
/*----------------------------------------------------------------------------
|
||||
Parse the content of a <double> XML-RPC XML element, e.g. "34.5".
|
||||
|
||||
'str' is that content.
|
||||
-----------------------------------------------------------------------------*/
|
||||
xmlrpc_env parseEnv;
|
||||
double valueDouble;
|
||||
|
||||
XMLRPC_ASSERT_ENV_OK(envP);
|
||||
XMLRPC_ASSERT_PTR_OK(str);
|
||||
|
||||
xmlrpc_env_init(&parseEnv);
|
||||
|
||||
parseDoubleString(&parseEnv, str, &valueDouble);
|
||||
|
||||
if (parseEnv.fault_occurred) {
|
||||
/* As an alternative, try a strtod() parsing. strtod()
|
||||
accepts other forms, e.g. "3.4E6"; "3,4"; " 3.4". These
|
||||
are not permitted by XML-RPC, but an almost-XML-RPC partner
|
||||
might use one. In fact, for many years, Xmlrpc-c generated
|
||||
such alternatives (by mistake).
|
||||
*/
|
||||
bool failed;
|
||||
parseDoubleStringStrtod(str, &failed, &valueDouble);
|
||||
if (failed)
|
||||
setParseFault(envP, "<double> element value '%s' is not a valid "
|
||||
"floating point number. %s",
|
||||
str, parseEnv.fault_string);
|
||||
}
|
||||
|
||||
if (!envP->fault_occurred)
|
||||
*valuePP = xmlrpc_double_new(envP, valueDouble);
|
||||
|
||||
xmlrpc_env_clean(&parseEnv);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
parseBase64(xmlrpc_env * const envP,
|
||||
const char * const str,
|
||||
size_t const strLength,
|
||||
xmlrpc_value ** const valuePP) {
|
||||
/*----------------------------------------------------------------------------
|
||||
Parse the content of a <base64> XML-RPC XML element, e.g. "FD32YY".
|
||||
|
||||
'str' is that content.
|
||||
-----------------------------------------------------------------------------*/
|
||||
xmlrpc_mem_block * decoded;
|
||||
|
||||
XMLRPC_ASSERT_ENV_OK(envP);
|
||||
XMLRPC_ASSERT_PTR_OK(str);
|
||||
|
||||
decoded = xmlrpc_base64_decode(envP, str, strLength);
|
||||
if (!envP->fault_occurred) {
|
||||
unsigned char * const bytes =
|
||||
XMLRPC_MEMBLOCK_CONTENTS(unsigned char, decoded);
|
||||
size_t const byteCount =
|
||||
XMLRPC_MEMBLOCK_SIZE(unsigned char, decoded);
|
||||
|
||||
*valuePP = xmlrpc_base64_new(envP, byteCount, bytes);
|
||||
|
||||
XMLRPC_MEMBLOCK_FREE(unsigned char, decoded);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
parseI8(xmlrpc_env * const envP,
|
||||
const char * const str,
|
||||
xmlrpc_value ** const valuePP) {
|
||||
/*----------------------------------------------------------------------------
|
||||
Parse the content of a <i8> XML-RPC XML element, e.g. "34".
|
||||
|
||||
'str' is that content.
|
||||
-----------------------------------------------------------------------------*/
|
||||
XMLRPC_ASSERT_ENV_OK(envP);
|
||||
XMLRPC_ASSERT_PTR_OK(str);
|
||||
|
||||
if (str[0] == '\0')
|
||||
setParseFault(envP, "<i8> XML element content is empty");
|
||||
else if (isspace(str[0]))
|
||||
setParseFault(envP,
|
||||
"<i8> content '%s' starts with white space", str);
|
||||
else {
|
||||
xmlrpc_int64 i;
|
||||
char * tail;
|
||||
|
||||
errno = 0;
|
||||
i = strtoll(str, &tail, 10);
|
||||
|
||||
if (errno == ERANGE)
|
||||
setParseFault(envP, "<i8> XML element value '%s' represents a "
|
||||
"number beyond the range that "
|
||||
"XML-RPC allows (%d - %d)", str,
|
||||
XMLRPC_INT64_MIN, XMLRPC_INT64_MAX);
|
||||
else if (errno != 0)
|
||||
setParseFault(envP, "unexpected error parsing <i8> XML element "
|
||||
"value '%s'. strtoll() failed with errno %d (%s)",
|
||||
str, errno, strerror(errno));
|
||||
else {
|
||||
/* Look for out-of-range errors which didn't produce ERANGE. */
|
||||
if (i < XMLRPC_INT64_MIN)
|
||||
setParseFault(envP, "<i8> value %d is below the range allowed "
|
||||
"by XML-RPC (minimum is %d)",
|
||||
i, XMLRPC_INT64_MIN);
|
||||
else if (i > XMLRPC_INT64_MAX)
|
||||
setParseFault(envP, "<i8> value %d is above the range allowed "
|
||||
"by XML-RPC (maximum is %d)",
|
||||
i, XMLRPC_INT64_MAX);
|
||||
else {
|
||||
if (tail[0] != '\0')
|
||||
setParseFault(envP,
|
||||
"<i8> value '%s' contains non-numerical "
|
||||
"junk: '%s'", str, tail);
|
||||
else
|
||||
*valuePP = xmlrpc_i8_new(envP, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
parseSimpleValueCdata(xmlrpc_env * const envP,
|
||||
const char * const elementName,
|
||||
const char * const cdata,
|
||||
size_t const cdataLength,
|
||||
xmlrpc_value ** const valuePP) {
|
||||
/*----------------------------------------------------------------------------
|
||||
Parse an XML element is supposedly a data type element such as
|
||||
<string>. Its name is 'elementName', and it has no children, but
|
||||
contains cdata 'cdata', which is 'dataLength' characters long.
|
||||
-----------------------------------------------------------------------------*/
|
||||
/* We need to straighten out the whole character set / encoding thing
|
||||
some day. What is 'cdata', and what should it be? Does it have
|
||||
embedded NUL? Some of the code here assumes it doesn't. Is it
|
||||
text?
|
||||
|
||||
The <string> parser assumes it's UTF 8 with embedded NULs.
|
||||
But the <int> parser will get terribly confused if there are any
|
||||
UTF-8 multibyte sequences or NUL characters. So will most of the
|
||||
others.
|
||||
|
||||
The "ex.XXX" element names are what the Apache XML-RPC facility
|
||||
uses: http://ws.apache.org/xmlrpc/types.html. i1 and i2 are just
|
||||
from my imagination.
|
||||
*/
|
||||
|
||||
if (xmlrpc_streq(elementName, "int") ||
|
||||
xmlrpc_streq(elementName, "i4") ||
|
||||
xmlrpc_streq(elementName, "i1") ||
|
||||
xmlrpc_streq(elementName, "i2") ||
|
||||
xmlrpc_streq(elementName, "ex.i1") ||
|
||||
xmlrpc_streq(elementName, "ex.i2"))
|
||||
parseInt(envP, cdata, valuePP);
|
||||
else if (xmlrpc_streq(elementName, "boolean"))
|
||||
parseBoolean(envP, cdata, valuePP);
|
||||
else if (xmlrpc_streq(elementName, "double"))
|
||||
parseDouble(envP, cdata, valuePP);
|
||||
else if (xmlrpc_streq(elementName, "dateTime.iso8601"))
|
||||
*valuePP = xmlrpc_datetime_new_str(envP, cdata);
|
||||
else if (xmlrpc_streq(elementName, "string"))
|
||||
*valuePP = xmlrpc_string_new_lp(envP, cdataLength, cdata);
|
||||
else if (xmlrpc_streq(elementName, "base64"))
|
||||
parseBase64(envP, cdata, cdataLength, valuePP);
|
||||
else if (xmlrpc_streq(elementName, "nil") ||
|
||||
xmlrpc_streq(elementName, "ex.nil"))
|
||||
*valuePP = xmlrpc_nil_new(envP);
|
||||
else if (xmlrpc_streq(elementName, "i8") ||
|
||||
xmlrpc_streq(elementName, "ex.i8"))
|
||||
parseI8(envP, cdata, valuePP);
|
||||
else
|
||||
setParseFault(envP, "Unknown value type -- XML element is named "
|
||||
"<%s>", elementName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
parseSimpleValue(xmlrpc_env * const envP,
|
||||
xml_element * const elemP,
|
||||
xmlrpc_value ** const valuePP) {
|
||||
|
||||
unsigned int const childCount = xml_element_children_size(elemP);
|
||||
|
||||
if (childCount > 0)
|
||||
setParseFault(envP, "The child of a <value> element "
|
||||
"is neither <array> nor <struct>, "
|
||||
"but has %u child elements of its own.",
|
||||
childCount);
|
||||
else {
|
||||
const char * const elemName = xml_element_name(elemP);
|
||||
const char * const cdata = xml_element_cdata(elemP);
|
||||
size_t const cdataSize = xml_element_cdata_size(elemP);
|
||||
|
||||
parseSimpleValueCdata(envP, elemName, cdata, cdataSize, valuePP);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
xmlrpc_parseValue(xmlrpc_env * const envP,
|
||||
unsigned int const maxRecursion,
|
||||
xml_element * const elemP,
|
||||
xmlrpc_value ** const valuePP) {
|
||||
/*----------------------------------------------------------------------------
|
||||
Compute the xmlrpc_value represented by the XML <value> element 'elem'.
|
||||
Return that xmlrpc_value.
|
||||
|
||||
We call convert_array() and convert_struct(), which may ultimately
|
||||
call us recursively. Don't recurse any more than 'maxRecursion'
|
||||
times.
|
||||
-----------------------------------------------------------------------------*/
|
||||
XMLRPC_ASSERT_ENV_OK(envP);
|
||||
XMLRPC_ASSERT(elemP != NULL);
|
||||
|
||||
/* Assume we'll need to recurse, make sure we're allowed */
|
||||
if (maxRecursion < 1)
|
||||
xmlrpc_env_set_fault(envP, XMLRPC_PARSE_ERROR,
|
||||
"Nested data structure too deep.");
|
||||
else {
|
||||
if (!xmlrpc_streq(xml_element_name(elemP), "value"))
|
||||
setParseFault(envP,
|
||||
"<%s> element where <value> expected",
|
||||
xml_element_name(elemP));
|
||||
else {
|
||||
unsigned int const childCount = xml_element_children_size(elemP);
|
||||
|
||||
if (childCount == 0) {
|
||||
/* We have no type element, so treat the value as a string. */
|
||||
char * const cdata = xml_element_cdata(elemP);
|
||||
size_t const cdata_size = xml_element_cdata_size(elemP);
|
||||
*valuePP = xmlrpc_string_new_lp(envP, cdata_size, cdata);
|
||||
} else if (childCount > 1)
|
||||
setParseFault(envP, "<value> has %u child elements. "
|
||||
"Only zero or one make sense.", childCount);
|
||||
else {
|
||||
/* We should have a type tag inside our value tag. */
|
||||
xml_element * const childP = xml_element_children(elemP)[0];
|
||||
const char * const childName = xml_element_name(childP);
|
||||
|
||||
if (xmlrpc_streq(childName, "struct"))
|
||||
parseStruct(envP, maxRecursion, childP, valuePP);
|
||||
else if (xmlrpc_streq(childName, "array"))
|
||||
parseArray(envP, maxRecursion, childP, valuePP);
|
||||
else
|
||||
parseSimpleValue(envP, childP, valuePP);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user