|
|
#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/string_number.h" |
|
|
#include "xmlrpc-c/util.h" |
|
|
#include "xmlparser.h" |
|
|
#include "parse_datetime.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) { |
|
|
size_t const childCount = xml_element_children_size(arrayElemP); |
|
|
|
|
|
if (childCount != 1) |
|
|
setParseFault(envP, |
|
|
"<array> element has %u children. Only one <data> " |
|
|
"makes sense.", (unsigned int)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) { |
|
|
|
|
|
size_t const childCount = xml_element_children_size(nameElemP); |
|
|
|
|
|
if (childCount > 0) |
|
|
setParseFault(envP, "<name> element has %u children. " |
|
|
"Should have none.", (unsigned int)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) { |
|
|
|
|
|
size_t 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.", (unsigned int)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) { |
|
|
|
|
|
|
|
|
|
|
|
xmlrpc_value * structP; |
|
|
|
|
|
XMLRPC_ASSERT_ENV_OK(envP); |
|
|
XMLRPC_ASSERT(elemP != NULL); |
|
|
|
|
|
structP = xmlrpc_struct_new(envP); |
|
|
if (!envP->fault_occurred) { |
|
|
|
|
|
|
|
|
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) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
|
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 { |
|
|
|
|
|
if (i < XMLRPC_INT32_MIN) |
|
|
setParseFault(envP, |
|
|
"<int> value %ld 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 %ld 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) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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; |
|
|
} |
|
|
{ |
|
|
|
|
|
const char * p; |
|
|
|
|
|
for (p = mantissa; p < mantissaEnd; ++p) { |
|
|
accum *= 10; |
|
|
accum += (*p - '0'); |
|
|
} |
|
|
} |
|
|
{ |
|
|
|
|
|
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) { |
|
|
|
|
|
|
|
|
|
|
|
*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) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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; |
|
|
xmlrpc_env env; |
|
|
|
|
|
xmlrpc_env_init(&env); |
|
|
|
|
|
xmlrpc_parse_int64(&env, str, &i); |
|
|
|
|
|
if (env.fault_occurred) |
|
|
setParseFault(envP, "<i8> XML element value '%s' is invalid " |
|
|
"because it does not represent " |
|
|
"a 64 bit integer. %s", env.fault_string); |
|
|
else |
|
|
*valuePP = xmlrpc_i8_new(envP, i); |
|
|
|
|
|
xmlrpc_env_clean(&env); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void |
|
|
parseSimpleValueCdata(xmlrpc_env * const envP, |
|
|
const char * const elementName, |
|
|
const char * const cdata, |
|
|
size_t const cdataLength, |
|
|
xmlrpc_value ** const valuePP) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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")) |
|
|
xmlrpc_parseDatetime(envP, cdata, valuePP); |
|
|
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) { |
|
|
|
|
|
size_t 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.", |
|
|
(unsigned int)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) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
XMLRPC_ASSERT_ENV_OK(envP); |
|
|
XMLRPC_ASSERT(elemP != NULL); |
|
|
|
|
|
|
|
|
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 { |
|
|
size_t const childCount = xml_element_children_size(elemP); |
|
|
|
|
|
if (childCount == 0) { |
|
|
|
|
|
const 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.", |
|
|
(unsigned int)childCount); |
|
|
else { |
|
|
|
|
|
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); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|