| File: | src/mod/xml_int/mod_xml_rpc/../../../../libs/xmlrpc-c/src/parse_value.c | 
| Location: | line 529, column 10 | 
| Description: | Access to field 'fault_occurred' results in a dereference of a null pointer (loaded from variable 'envP') | 
| 1 | #include "xmlrpc_config.h" | |||||
| 2 | ||||||
| 3 | #include <stddef.h> | |||||
| 4 | #include <stdlib.h> | |||||
| 5 | #include <string.h> | |||||
| 6 | #include <errno(*__errno_location ()).h> | |||||
| 7 | #include <ctype.h> | |||||
| 8 | #include <limits.h> | |||||
| 9 | #include <float.h> | |||||
| 10 | ||||||
| 11 | #include "bool.h" | |||||
| 12 | ||||||
| 13 | #include "xmlrpc-c/base.h" | |||||
| 14 | #include "xmlrpc-c/base_int.h" | |||||
| 15 | #include "xmlrpc-c/string_int.h" | |||||
| 16 | #include "xmlrpc-c/string_number.h" | |||||
| 17 | #include "xmlrpc-c/util.h" | |||||
| 18 | #include "xmlrpc-c/xmlparser.h" | |||||
| 19 | #include "parse_datetime.h" | |||||
| 20 | ||||||
| 21 | #include "parse_value.h" | |||||
| 22 | ||||||
| 23 | ||||||
| 24 | ||||||
| 25 | static void | |||||
| 26 | setParseFault(xmlrpc_env * const envP, | |||||
| 27 | const char * const format, | |||||
| 28 | ...) { | |||||
| 29 | ||||||
| 30 | va_list args; | |||||
| 31 | va_start(args, format)__builtin_va_start(args, format); | |||||
| 32 | xmlrpc_set_fault_formatted_v(envP, XMLRPC_PARSE_ERROR(-503), format, args); | |||||
| 33 | va_end(args)__builtin_va_end(args); | |||||
| 34 | } | |||||
| 35 | ||||||
| 36 | ||||||
| 37 | ||||||
| 38 | static void | |||||
| 39 | parseArrayDataChild(xmlrpc_env * const envP, | |||||
| 40 | xml_element * const childP, | |||||
| 41 | unsigned int const maxRecursion, | |||||
| 42 | xmlrpc_value * const arrayP) { | |||||
| 43 | ||||||
| 44 | const char * const elemName = xml_element_name(childP); | |||||
| 45 | ||||||
| 46 | if (!xmlrpc_streq(elemName, "value")) | |||||
| 47 | setParseFault(envP, "<data> element has <%s> child. " | |||||
| 48 | "Only <value> makes sense.", elemName); | |||||
| 49 | else { | |||||
| 50 | xmlrpc_value * itemP; | |||||
| 51 | ||||||
| 52 | xmlrpc_parseValue(envP, maxRecursion-1, childP, &itemP); | |||||
| 53 | ||||||
| 54 | if (!envP->fault_occurred) { | |||||
| 55 | xmlrpc_array_append_item(envP, arrayP, itemP); | |||||
| 56 | ||||||
| 57 | xmlrpc_DECREF(itemP); | |||||
| 58 | } | |||||
| 59 | } | |||||
| 60 | } | |||||
| 61 | ||||||
| 62 | ||||||
| 63 | ||||||
| 64 | static void | |||||
| 65 | parseArray(xmlrpc_env * const envP, | |||||
| 66 | unsigned int const maxRecursion, | |||||
| 67 | xml_element * const arrayElemP, | |||||
| 68 | xmlrpc_value ** const arrayPP) { | |||||
| 69 | ||||||
| 70 | xmlrpc_value * arrayP; | |||||
| 71 | ||||||
| 72 | XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string == ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/parse_value.c", 72); while (0 ); | |||||
| 73 | XMLRPC_ASSERT(arrayElemP != NULL)do if (!(arrayElemP != ((void*)0))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/parse_value.c" , 73); while (0); | |||||
| 74 | ||||||
| 75 | arrayP = xmlrpc_array_new(envP); | |||||
| 76 | if (!envP->fault_occurred) { | |||||
| 77 | size_t const childCount = xml_element_children_size(arrayElemP); | |||||
| 78 | ||||||
| 79 | if (childCount != 1) | |||||
| 80 | setParseFault(envP, | |||||
| 81 | "<array> element has %u children. Only one <data> " | |||||
| 82 | "makes sense.", (unsigned int)childCount); | |||||
| 83 | else { | |||||
| 84 | xml_element * const dataElemP = | |||||
| 85 | xml_element_children(arrayElemP)[0]; | |||||
| 86 | const char * const elemName = xml_element_name(dataElemP); | |||||
| 87 | ||||||
| 88 | if (!xmlrpc_streq(elemName, "data")) | |||||
| 89 | setParseFault(envP, | |||||
| 90 | "<array> element has <%s> child. Only <data> " | |||||
| 91 | "makes sense.", elemName); | |||||
| 92 | else { | |||||
| 93 | xml_element ** const values = xml_element_children(dataElemP); | |||||
| 94 | unsigned int const size = xml_element_children_size(dataElemP); | |||||
| 95 | ||||||
| 96 | unsigned int i; | |||||
| 97 | ||||||
| 98 | for (i = 0; i < size && !envP->fault_occurred; ++i) | |||||
| 99 | parseArrayDataChild(envP, values[i], maxRecursion, arrayP); | |||||
| 100 | } | |||||
| 101 | } | |||||
| 102 | if (envP->fault_occurred) | |||||
| 103 | xmlrpc_DECREF(arrayP); | |||||
| 104 | else | |||||
| 105 | *arrayPP = arrayP; | |||||
| 106 | } | |||||
| 107 | } | |||||
| 108 | ||||||
| 109 | ||||||
| 110 | ||||||
| 111 | static void | |||||
| 112 | parseName(xmlrpc_env * const envP, | |||||
| 113 | xml_element * const nameElemP, | |||||
| 114 | xmlrpc_value ** const valuePP) { | |||||
| 115 | ||||||
| 116 | size_t const childCount = xml_element_children_size(nameElemP); | |||||
| 117 | ||||||
| 118 | if (childCount > 0) | |||||
| 119 | setParseFault(envP, "<name> element has %u children. " | |||||
| 120 | "Should have none.", (unsigned int)childCount); | |||||
| 121 | else { | |||||
| 122 | const char * const cdata = xml_element_cdata(nameElemP); | |||||
| 123 | size_t const cdataSize = xml_element_cdata_size(nameElemP); | |||||
| 124 | ||||||
| 125 | *valuePP = xmlrpc_string_new_lp(envP, cdataSize, cdata); | |||||
| 126 | } | |||||
| 127 | } | |||||
| 128 | ||||||
| 129 | ||||||
| 130 | ||||||
| 131 | static void | |||||
| 132 | getNameChild(xmlrpc_env * const envP, | |||||
| 133 | xml_element * const parentP, | |||||
| 134 | xml_element * * const childPP) { | |||||
| 135 | ||||||
| 136 | xml_element ** const children = xml_element_children(parentP); | |||||
| 137 | size_t const childCount = xml_element_children_size(parentP); | |||||
| 138 | ||||||
| 139 | xml_element * childP; | |||||
| 140 | unsigned int i; | |||||
| 141 | ||||||
| 142 | for (i = 0, childP = NULL((void*)0); i < childCount && !childP; ++i) { | |||||
| 143 | if (xmlrpc_streq(xml_element_name(children[i]), "name")) | |||||
| 144 | childP = children[i]; | |||||
| 145 | } | |||||
| 146 | if (!childP) | |||||
| 147 | xmlrpc_env_set_fault(envP, XMLRPC_PARSE_ERROR(-503), | |||||
| 148 | "<member> has no <name> child"); | |||||
| 149 | else | |||||
| 150 | *childPP = childP; | |||||
| 151 | } | |||||
| 152 | ||||||
| 153 | ||||||
| 154 | ||||||
| 155 | static void | |||||
| 156 | getValueChild(xmlrpc_env * const envP, | |||||
| 157 | xml_element * const parentP, | |||||
| 158 | xml_element * * const childPP) { | |||||
| 159 | ||||||
| 160 | xml_element ** const children = xml_element_children(parentP); | |||||
| 161 | size_t const childCount = xml_element_children_size(parentP); | |||||
| 162 | ||||||
| 163 | xml_element * childP; | |||||
| 164 | unsigned int i; | |||||
| 165 | ||||||
| 166 | for (i = 0, childP = NULL((void*)0); i < childCount && !childP; ++i) { | |||||
| 167 | if (xmlrpc_streq(xml_element_name(children[i]), "value")) | |||||
| 168 | childP = children[i]; | |||||
| 169 | } | |||||
| 170 | if (!childP) | |||||
| 171 | xmlrpc_env_set_fault(envP, XMLRPC_PARSE_ERROR(-503), | |||||
| 172 | "<member> has no <value> child"); | |||||
| 173 | else | |||||
| 174 | *childPP = childP; | |||||
| 175 | } | |||||
| 176 | ||||||
| 177 | ||||||
| 178 | ||||||
| 179 | static void | |||||
| 180 | parseMember(xmlrpc_env * const envP, | |||||
| 181 | xml_element * const memberP, | |||||
| 182 | unsigned int const maxRecursion, | |||||
| 183 | xmlrpc_value ** const keyPP, | |||||
| 184 | xmlrpc_value ** const valuePP) { | |||||
| 185 | ||||||
| 186 | size_t const childCount = xml_element_children_size(memberP); | |||||
| 187 | ||||||
| 188 | if (childCount != 2) | |||||
| 189 | setParseFault(envP, | |||||
| 190 | "<member> element has %u children. Only one <name> and " | |||||
| 191 | "one <value> make sense.", (unsigned int)childCount); | |||||
| 192 | else { | |||||
| 193 | xml_element * nameElemP = NULL((void*)0); | |||||
| 194 | ||||||
| 195 | getNameChild(envP, memberP, &nameElemP); | |||||
| 196 | ||||||
| 197 | if (!envP->fault_occurred) { | |||||
| 198 | parseName(envP, nameElemP, keyPP); | |||||
| 199 | ||||||
| 200 | if (!envP->fault_occurred) { | |||||
| 201 | xml_element * valueElemP = NULL((void*)0); | |||||
| 202 | ||||||
| 203 | getValueChild(envP, memberP, &valueElemP); | |||||
| 204 | ||||||
| 205 | if (!envP->fault_occurred) | |||||
| 206 | xmlrpc_parseValue(envP, maxRecursion-1, valueElemP, | |||||
| 207 | valuePP); | |||||
| 208 | ||||||
| 209 | if (envP->fault_occurred) | |||||
| 210 | xmlrpc_DECREF(*keyPP); | |||||
| 211 | } | |||||
| 212 | } | |||||
| 213 | } | |||||
| 214 | } | |||||
| 215 | ||||||
| 216 | ||||||
| 217 | ||||||
| 218 | static void | |||||
| 219 | parseStruct(xmlrpc_env * const envP, | |||||
| 220 | unsigned int const maxRecursion, | |||||
| 221 | xml_element * const elemP, | |||||
| 222 | xmlrpc_value ** const structPP) { | |||||
| 223 | /*---------------------------------------------------------------------------- | |||||
| 224 | Parse the <struct> element 'elemP'. | |||||
| 225 | -----------------------------------------------------------------------------*/ | |||||
| 226 | xmlrpc_value * structP; | |||||
| 227 | ||||||
| 228 | XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string == ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/parse_value.c", 228); while ( 0); | |||||
| 229 | XMLRPC_ASSERT(elemP != NULL)do if (!(elemP != ((void*)0))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/parse_value.c" , 229); while (0); | |||||
| 230 | ||||||
| 231 | structP = xmlrpc_struct_new(envP); | |||||
| 232 | if (!envP->fault_occurred) { | |||||
| 233 | /* Iterate over our children, extracting key/value pairs. */ | |||||
| 234 | ||||||
| 235 | xml_element ** const members = xml_element_children(elemP); | |||||
| 236 | unsigned int const size = xml_element_children_size(elemP); | |||||
| 237 | ||||||
| 238 | unsigned int i; | |||||
| 239 | ||||||
| 240 | for (i = 0; i < size && !envP->fault_occurred; ++i) { | |||||
| 241 | const char * const elemName = xml_element_name(members[i]); | |||||
| 242 | ||||||
| 243 | if (!xmlrpc_streq(elemName, "member")) | |||||
| 244 | setParseFault(envP, "<%s> element found where only <member> " | |||||
| 245 | "makes sense", elemName); | |||||
| 246 | else { | |||||
| 247 | xmlrpc_value * keyP = NULL((void*)0); | |||||
| 248 | xmlrpc_value * valueP; | |||||
| 249 | ||||||
| 250 | parseMember(envP, members[i], maxRecursion, &keyP, &valueP); | |||||
| 251 | ||||||
| 252 | if (!envP->fault_occurred) { | |||||
| 253 | xmlrpc_struct_set_value_v(envP, structP, keyP, valueP); | |||||
| 254 | ||||||
| 255 | xmlrpc_DECREF(keyP); | |||||
| 256 | xmlrpc_DECREF(valueP); | |||||
| 257 | } | |||||
| 258 | } | |||||
| 259 | } | |||||
| 260 | if (envP->fault_occurred) | |||||
| 261 | xmlrpc_DECREF(structP); | |||||
| 262 | else | |||||
| 263 | *structPP = structP; | |||||
| 264 | } | |||||
| 265 | } | |||||
| 266 | ||||||
| 267 | ||||||
| 268 | ||||||
| 269 | static void | |||||
| 270 | parseInt(xmlrpc_env * const envP, | |||||
| 271 | const char * const str, | |||||
| 272 | xmlrpc_value ** const valuePP) { | |||||
| 273 | /*---------------------------------------------------------------------------- | |||||
| 274 | Parse the content of a <int> XML-RPC XML element, e.g. "34". | |||||
| 275 | ||||||
| 276 | 'str' is that content. | |||||
| 277 | -----------------------------------------------------------------------------*/ | |||||
| 278 | XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string == ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/parse_value.c", 278); while ( 0); | |||||
| 279 | XMLRPC_ASSERT_PTR_OK(str)do if (!((str) != ((void*)0))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/parse_value.c" , 279); while (0); | |||||
| 280 | ||||||
| 281 | if (str[0] == '\0') | |||||
| 282 | setParseFault(envP, "<int> XML element content is empty"); | |||||
| 283 | else if (isspace(str[0])((*__ctype_b_loc ())[(int) ((str[0]))] & (unsigned short int ) _ISspace)) | |||||
| 284 | setParseFault(envP, "<int> content '%s' starts with white space", | |||||
| 285 | str); | |||||
| 286 | else { | |||||
| 287 | long i; | |||||
| 288 | char * tail; | |||||
| 289 | ||||||
| 290 | errno(*__errno_location ()) = 0; | |||||
| 291 | i = strtol(str, &tail, 10); | |||||
| 292 | ||||||
| 293 | /* Look for ERANGE. */ | |||||
| 294 | if (errno(*__errno_location ()) == ERANGE34) | |||||
| 295 | setParseFault(envP, "<int> XML element value '%s' represents a " | |||||
| 296 | "number beyond the range that " | |||||
| 297 | "XML-RPC allows (%d - %d)", str, | |||||
| 298 | XMLRPC_INT32_MIN(-0x7fffffff - 1), XMLRPC_INT32_MAX0x7fffffff); | |||||
| 299 | else if (errno(*__errno_location ()) != 0) | |||||
| 300 | setParseFault(envP, "unexpected error parsing <int> XML element " | |||||
| 301 | "value '%s'. strtol() failed with errno %d (%s)", | |||||
| 302 | str, errno(*__errno_location ()), strerror(errno(*__errno_location ()))); | |||||
| 303 | else { | |||||
| 304 | /* Look for out-of-range errors which didn't produce ERANGE. */ | |||||
| 305 | if (i < XMLRPC_INT32_MIN(-0x7fffffff - 1)) | |||||
| 306 | setParseFault(envP, | |||||
| 307 | "<int> value %ld is below the range allowed " | |||||
| 308 | "by XML-RPC (minimum is %d)", | |||||
| 309 | i, XMLRPC_INT32_MIN(-0x7fffffff - 1)); | |||||
| 310 | else if (i > XMLRPC_INT32_MAX0x7fffffff) | |||||
| 311 | setParseFault(envP, | |||||
| 312 | "<int> value %ld is above the range allowed " | |||||
| 313 | "by XML-RPC (maximum is %d)", | |||||
| 314 | i, XMLRPC_INT32_MAX0x7fffffff); | |||||
| 315 | else { | |||||
| 316 | if (tail[0] != '\0') | |||||
| 317 | setParseFault(envP, | |||||
| 318 | "<int> value '%s' contains non-numerical " | |||||
| 319 | "junk: '%s'", str, tail); | |||||
| 320 | else | |||||
| 321 | *valuePP = xmlrpc_int_new(envP, i); | |||||
| 322 | } | |||||
| 323 | } | |||||
| 324 | } | |||||
| 325 | } | |||||
| 326 | ||||||
| 327 | ||||||
| 328 | ||||||
| 329 | static void | |||||
| 330 | parseBoolean(xmlrpc_env * const envP, | |||||
| 331 | const char * const str, | |||||
| 332 | xmlrpc_value ** const valuePP) { | |||||
| 333 | /*---------------------------------------------------------------------------- | |||||
| 334 | Parse the content of a <boolean> XML-RPC XML element, e.g. "1". | |||||
| 335 | ||||||
| 336 | 'str' is that content. | |||||
| 337 | -----------------------------------------------------------------------------*/ | |||||
| 338 | XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string == ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/parse_value.c", 338); while ( 0); | |||||
| 339 | XMLRPC_ASSERT_PTR_OK(str)do if (!((str) != ((void*)0))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/parse_value.c" , 339); while (0); | |||||
| 340 | ||||||
| 341 | if (xmlrpc_streq(str, "0") || xmlrpc_streq(str, "1")) | |||||
| 342 | *valuePP = xmlrpc_bool_new(envP, xmlrpc_streq(str, "1") ? 1 : 0); | |||||
| 343 | else | |||||
| 344 | setParseFault(envP, "<boolean> XML element content must be either " | |||||
| 345 | "'0' or '1' according to XML-RPC. This one has '%s'", | |||||
| 346 | str); | |||||
| 347 | } | |||||
| 348 | ||||||
| 349 | ||||||
| 350 | ||||||
| 351 | static void | |||||
| 352 | scanAndValidateDoubleString(xmlrpc_env * const envP, | |||||
| 353 | const char * const string, | |||||
| 354 | const char ** const mantissaP, | |||||
| 355 | const char ** const mantissaEndP, | |||||
| 356 | const char ** const fractionP, | |||||
| 357 | const char ** const fractionEndP) { | |||||
| 358 | ||||||
| 359 | const char * mantissa; | |||||
| 360 | const char * dp; | |||||
| 361 | const char * p; | |||||
| 362 | ||||||
| 363 | if (string[0] == '-' || string[0] == '+') | |||||
| 364 | mantissa = &string[1]; | |||||
| 365 | else | |||||
| 366 | mantissa = &string[0]; | |||||
| 367 | ||||||
| 368 | for (p = mantissa, dp = NULL((void*)0); *p; ++p) { | |||||
| 369 | char const c = *p; | |||||
| 370 | if (c == '.') { | |||||
| 371 | if (dp) { | |||||
| 372 | setParseFault(envP, "Two decimal points"); | |||||
| 373 | return; | |||||
| 374 | } else | |||||
| 375 | dp = p; | |||||
| 376 | } else if (c < '0' || c > '9') { | |||||
| 377 | setParseFault(envP, "Garbage (not sign, digit, or period) " | |||||
| 378 | "starting at '%s'", p); | |||||
| 379 | return; | |||||
| 380 | } | |||||
| 381 | } | |||||
| 382 | *mantissaP = mantissa; | |||||
| 383 | if (dp) { | |||||
| 384 | *mantissaEndP = dp; | |||||
| 385 | *fractionP = dp+1; | |||||
| 386 | *fractionEndP = p; | |||||
| 387 | } else { | |||||
| 388 | *mantissaEndP = p; | |||||
| 389 | *fractionP = p; | |||||
| 390 | *fractionEndP = p; | |||||
| 391 | } | |||||
| 392 | } | |||||
| 393 | ||||||
| 394 | ||||||
| 395 | ||||||
| 396 | static bool | |||||
| 397 | isInfinite(double const value) { | |||||
| 398 | ||||||
| 399 | return value > DBL_MAX1.7976931348623157e+308; | |||||
| 400 | } | |||||
| 401 | ||||||
| 402 | ||||||
| 403 | ||||||
| 404 | static void | |||||
| 405 | parseDoubleString(xmlrpc_env * const envP, | |||||
| 406 | const char * const string, | |||||
| 407 | double * const valueP) { | |||||
| 408 | /*---------------------------------------------------------------------------- | |||||
| 409 | Turn e.g. "4.3" into 4.3 . | |||||
| 410 | -----------------------------------------------------------------------------*/ | |||||
| 411 | /* strtod() is no good for this because it is designed for human | |||||
| 412 | interfaces; it parses according to locale. As a practical | |||||
| 413 | matter that sometimes means that it does not recognize "." as a | |||||
| 414 | decimal point. In XML-RPC, "." is a decimal point. | |||||
| 415 | ||||||
| 416 | Design note: in my experiments, using strtod() was 10 times | |||||
| 417 | slower than using this function. | |||||
| 418 | */ | |||||
| 419 | const char * mantissa = NULL((void*)0); | |||||
| 420 | const char * mantissaEnd = NULL((void*)0); | |||||
| 421 | const char * fraction = NULL((void*)0); | |||||
| 422 | const char * fractionEnd = NULL((void*)0); | |||||
| 423 | ||||||
| 424 | scanAndValidateDoubleString(envP, string, &mantissa, &mantissaEnd, | |||||
| 425 | &fraction, &fractionEnd); | |||||
| 426 | ||||||
| 427 | if (!envP->fault_occurred) { | |||||
| 428 | double accum; | |||||
| 429 | ||||||
| 430 | accum = 0.0; | |||||
| 431 | ||||||
| 432 | if (mantissa == mantissaEnd && fraction == fractionEnd) { | |||||
| 433 | setParseFault(envP, "No digits"); | |||||
| 434 | return; | |||||
| 435 | } | |||||
| 436 | { | |||||
| 437 | /* Add in the whole part */ | |||||
| 438 | const char * p; | |||||
| 439 | ||||||
| 440 | for (p = mantissa; p < mantissaEnd; ++p) { | |||||
| 441 | accum *= 10; | |||||
| 442 | accum += (*p - '0'); | |||||
| 443 | } | |||||
| 444 | } | |||||
| 445 | { | |||||
| 446 | /* Add in the fractional part */ | |||||
| 447 | double significance; | |||||
| 448 | const char * p; | |||||
| 449 | for (significance = 0.1, p = fraction; | |||||
| 450 | p < fractionEnd; | |||||
| 451 | ++p, significance *= 0.1) { | |||||
| 452 | ||||||
| 453 | accum += (*p - '0') * significance; | |||||
| 454 | } | |||||
| 455 | } | |||||
| 456 | if (isInfinite(accum)) | |||||
| 457 | setParseFault(envP, "Value exceeds the size allowed by XML-RPC"); | |||||
| 458 | else | |||||
| 459 | *valueP = string[0] == '-' ? (- accum) : accum; | |||||
| 460 | } | |||||
| 461 | } | |||||
| 462 | ||||||
| 463 | ||||||
| 464 | ||||||
| 465 | static void | |||||
| 466 | parseDoubleStringStrtod(const char * const str, | |||||
| 467 | bool * const failedP, | |||||
| 468 | double * const valueP) { | |||||
| 469 | ||||||
| 470 | if (strlen(str) == 0) { | |||||
| 471 | /* strtod() happily interprets empty string as 0.0. We don't think | |||||
| 472 | the user will appreciate that XML-RPC extension. | |||||
| 473 | */ | |||||
| 474 | *failedP = true; | |||||
| 475 | } else { | |||||
| 476 | char * tail; | |||||
| 477 | ||||||
| 478 | errno(*__errno_location ()) = 0; | |||||
| 479 | ||||||
| 480 | *valueP = strtod(str, &tail); | |||||
| 481 | ||||||
| 482 | if (errno(*__errno_location ()) != 0) | |||||
| 483 | *failedP = true; | |||||
| 484 | else { | |||||
| 485 | if (tail[0] != '\0') | |||||
| 486 | *failedP = true; | |||||
| 487 | else | |||||
| 488 | *failedP = false; | |||||
| 489 | } | |||||
| 490 | } | |||||
| 491 | } | |||||
| 492 | ||||||
| 493 | ||||||
| 494 | ||||||
| 495 | static void | |||||
| 496 | parseDouble(xmlrpc_env * const envP, | |||||
| 497 | const char * const str, | |||||
| 498 | xmlrpc_value ** const valuePP) { | |||||
| 499 | /*---------------------------------------------------------------------------- | |||||
| 500 | Parse the content of a <double> XML-RPC XML element, e.g. "34.5". | |||||
| 501 | ||||||
| 502 | 'str' is that content. | |||||
| 503 | -----------------------------------------------------------------------------*/ | |||||
| 504 | xmlrpc_env parseEnv; | |||||
| 505 | double valueDouble = 0; | |||||
| 506 | ||||||
| 507 | XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string == ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/parse_value.c", 507); while ( 0); | |||||
| 508 | XMLRPC_ASSERT_PTR_OK(str)do if (!((str) != ((void*)0))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/parse_value.c" , 508); while (0); | |||||
| 509 | ||||||
| 510 | xmlrpc_env_init(&parseEnv); | |||||
| 511 | ||||||
| 512 | parseDoubleString(&parseEnv, str, &valueDouble); | |||||
| 513 | ||||||
| 514 | if (parseEnv.fault_occurred) { | |||||
| 515 | /* As an alternative, try a strtod() parsing. strtod() | |||||
| 516 | accepts other forms, e.g. "3.4E6"; "3,4"; " 3.4". These | |||||
| 517 | are not permitted by XML-RPC, but an almost-XML-RPC partner | |||||
| 518 | might use one. In fact, for many years, Xmlrpc-c generated | |||||
| 519 | such alternatives (by mistake). | |||||
| 520 | */ | |||||
| 521 | bool failed; | |||||
| 522 | parseDoubleStringStrtod(str, &failed, &valueDouble); | |||||
| 523 | if (failed) | |||||
| 524 | setParseFault(envP, "<double> element value '%s' is not a valid " | |||||
| 525 | "floating point number. %s", | |||||
| 526 | str, parseEnv.fault_string); | |||||
| 527 | } | |||||
| 528 | ||||||
| 529 | if (!envP->fault_occurred) | |||||
| 
 | ||||||
| 530 | *valuePP = xmlrpc_double_new(envP, valueDouble); | |||||
| 531 | ||||||
| 532 | xmlrpc_env_clean(&parseEnv); | |||||
| 533 | } | |||||
| 534 | ||||||
| 535 | ||||||
| 536 | ||||||
| 537 | static void | |||||
| 538 | parseBase64(xmlrpc_env * const envP, | |||||
| 539 | const char * const str, | |||||
| 540 | size_t const strLength, | |||||
| 541 | xmlrpc_value ** const valuePP) { | |||||
| 542 | /*---------------------------------------------------------------------------- | |||||
| 543 | Parse the content of a <base64> XML-RPC XML element, e.g. "FD32YY". | |||||
| 544 | ||||||
| 545 | 'str' is that content. | |||||
| 546 | -----------------------------------------------------------------------------*/ | |||||
| 547 | xmlrpc_mem_block * decoded; | |||||
| 548 | ||||||
| 549 | XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string == ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/parse_value.c", 549); while ( 0); | |||||
| 550 | XMLRPC_ASSERT_PTR_OK(str)do if (!((str) != ((void*)0))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/parse_value.c" , 550); while (0); | |||||
| 551 | ||||||
| 552 | decoded = xmlrpc_base64_decode(envP, str, strLength); | |||||
| 553 | if (!envP->fault_occurred) { | |||||
| 554 | unsigned char * const bytes = | |||||
| 555 | XMLRPC_MEMBLOCK_CONTENTS(unsigned char, decoded)((unsigned char*) xmlrpc_mem_block_contents(decoded)); | |||||
| 556 | size_t const byteCount = | |||||
| 557 | XMLRPC_MEMBLOCK_SIZE(unsigned char, decoded)(xmlrpc_mem_block_size(decoded) / sizeof(unsigned char)); | |||||
| 558 | ||||||
| 559 | *valuePP = xmlrpc_base64_new(envP, byteCount, bytes); | |||||
| 560 | ||||||
| 561 | XMLRPC_MEMBLOCK_FREE(unsigned char, decoded)xmlrpc_mem_block_free(decoded); | |||||
| 562 | } | |||||
| 563 | } | |||||
| 564 | ||||||
| 565 | ||||||
| 566 | ||||||
| 567 | static void | |||||
| 568 | parseI8(xmlrpc_env * const envP, | |||||
| 569 | const char * const str, | |||||
| 570 | xmlrpc_value ** const valuePP) { | |||||
| 571 | /*---------------------------------------------------------------------------- | |||||
| 572 | Parse the content of a <i8> XML-RPC XML element, e.g. "34". | |||||
| 573 | ||||||
| 574 | 'str' is that content. | |||||
| 575 | -----------------------------------------------------------------------------*/ | |||||
| 576 | XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string == ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/parse_value.c", 576); while ( 0); | |||||
| 577 | XMLRPC_ASSERT_PTR_OK(str)do if (!((str) != ((void*)0))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/parse_value.c" , 577); while (0); | |||||
| 578 | ||||||
| 579 | if (str[0] == '\0') | |||||
| 580 | setParseFault(envP, "<i8> XML element content is empty"); | |||||
| 581 | else if (isspace(str[0])((*__ctype_b_loc ())[(int) ((str[0]))] & (unsigned short int ) _ISspace)) | |||||
| 582 | setParseFault(envP, | |||||
| 583 | "<i8> content '%s' starts with white space", str); | |||||
| 584 | else { | |||||
| 585 | xmlrpc_int64 i; | |||||
| 586 | xmlrpc_env env; | |||||
| 587 | ||||||
| 588 | xmlrpc_env_init(&env); | |||||
| 589 | ||||||
| 590 | xmlrpc_parse_int64(&env, str, &i); | |||||
| 591 | ||||||
| 592 | if (env.fault_occurred) | |||||
| 593 | setParseFault(envP, "<i8> XML element value '%s' is invalid " | |||||
| 594 | "because it does not represent " | |||||
| 595 | "a 64 bit integer. %s", env.fault_string); | |||||
| 596 | else | |||||
| 597 | *valuePP = xmlrpc_i8_new(envP, i); | |||||
| 598 | ||||||
| 599 | xmlrpc_env_clean(&env); | |||||
| 600 | } | |||||
| 601 | } | |||||
| 602 | ||||||
| 603 | ||||||
| 604 | ||||||
| 605 | static void | |||||
| 606 | parseSimpleValueCdata(xmlrpc_env * const envP, | |||||
| 607 | const char * const elementName, | |||||
| 608 | const char * const cdata, | |||||
| 609 | size_t const cdataLength, | |||||
| 610 | xmlrpc_value ** const valuePP) { | |||||
| 611 | /*---------------------------------------------------------------------------- | |||||
| 612 | Parse an XML element is supposedly a data type element such as | |||||
| 613 | <string>. Its name is 'elementName', and it has no children, but | |||||
| 614 | contains cdata 'cdata', which is 'dataLength' characters long. | |||||
| 615 | -----------------------------------------------------------------------------*/ | |||||
| 616 | /* We need to straighten out the whole character set / encoding thing | |||||
| 617 | some day. What is 'cdata', and what should it be? Does it have | |||||
| 618 | embedded NUL? Some of the code here assumes it doesn't. Is it | |||||
| 619 | text? | |||||
| 620 | ||||||
| 621 | The <string> parser assumes it's UTF 8 with embedded NULs. | |||||
| 622 | But the <int> parser will get terribly confused if there are any | |||||
| 623 | UTF-8 multibyte sequences or NUL characters. So will most of the | |||||
| 624 | others. | |||||
| 625 | ||||||
| 626 | The "ex:XXX" element names are what the Apache XML-RPC facility | |||||
| 627 | uses: http://ws.apache.org/xmlrpc/types.html. (Technically, it | |||||
| 628 | isn't "ex" but an arbitrary prefix that identifies a namespace | |||||
| 629 | declared earlier in the XML document -- this is an XML thing. | |||||
| 630 | But we aren't nearly sophisticated enough to use real XML | |||||
| 631 | namespaces, so we exploit the fact that XML-RPC actually uses | |||||
| 632 | "ex"). | |||||
| 633 | ||||||
| 634 | "i1" and "i2" are just from my imagination. | |||||
| 635 | */ | |||||
| 636 | ||||||
| 637 | if (xmlrpc_streq(elementName, "int") || | |||||
| 638 | xmlrpc_streq(elementName, "i4") || | |||||
| 639 | xmlrpc_streq(elementName, "i1") || | |||||
| 640 | xmlrpc_streq(elementName, "i2") || | |||||
| 641 | xmlrpc_streq(elementName, "ex:i1") || | |||||
| 642 | xmlrpc_streq(elementName, "ex:i2")) | |||||
| 643 | parseInt(envP, cdata, valuePP); | |||||
| 644 | else if (xmlrpc_streq(elementName, "boolean")) | |||||
| 645 | parseBoolean(envP, cdata, valuePP); | |||||
| 646 | else if (xmlrpc_streq(elementName, "double")) | |||||
| 647 | parseDouble(envP, cdata, valuePP); | |||||
| 648 | else if (xmlrpc_streq(elementName, "dateTime.iso8601")) | |||||
| 649 | xmlrpc_parseDatetime(envP, cdata, valuePP); | |||||
| 650 | else if (xmlrpc_streq(elementName, "string")) | |||||
| 651 | *valuePP = xmlrpc_string_new_lp(envP, cdataLength, cdata); | |||||
| 652 | else if (xmlrpc_streq(elementName, "base64")) | |||||
| 653 | parseBase64(envP, cdata, cdataLength, valuePP); | |||||
| 654 | else if (xmlrpc_streq(elementName, "nil") || | |||||
| 655 | xmlrpc_streq(elementName, "ex:nil")) | |||||
| 656 | *valuePP = xmlrpc_nil_new(envP); | |||||
| 657 | else if (xmlrpc_streq(elementName, "i8") || | |||||
| 658 | xmlrpc_streq(elementName, "ex:i8")) | |||||
| 659 | parseI8(envP, cdata, valuePP); | |||||
| 660 | else | |||||
| 661 | setParseFault(envP, "Unknown value type -- XML element is named " | |||||
| 662 | "<%s>", elementName); | |||||
| 663 | } | |||||
| 664 | ||||||
| 665 | ||||||
| 666 | ||||||
| 667 | static void | |||||
| 668 | parseSimpleValue(xmlrpc_env * const envP, | |||||
| 669 | xml_element * const elemP, | |||||
| 670 | xmlrpc_value ** const valuePP) { | |||||
| 671 | ||||||
| 672 | size_t childCount = xml_element_children_size(elemP); | |||||
| 673 | ||||||
| 674 | if (childCount > 0) | |||||
| 675 | setParseFault(envP, "The child of a <value> element " | |||||
| 676 | "is neither <array> nor <struct>, " | |||||
| 677 | "but has %u child elements of its own.", | |||||
| 678 | (unsigned int)childCount); | |||||
| 679 | else { | |||||
| 680 | const char * const elemName = xml_element_name(elemP); | |||||
| 681 | const char * const cdata = xml_element_cdata(elemP); | |||||
| 682 | size_t const cdataSize = xml_element_cdata_size(elemP); | |||||
| 683 | ||||||
| 684 | parseSimpleValueCdata(envP, elemName, cdata, cdataSize, valuePP); | |||||
| 685 | } | |||||
| 686 | } | |||||
| 687 | ||||||
| 688 | ||||||
| 689 | ||||||
| 690 | void | |||||
| 691 | xmlrpc_parseValue(xmlrpc_env * const envP, | |||||
| 692 | unsigned int const maxRecursion, | |||||
| 693 | xml_element * const elemP, | |||||
| 694 | xmlrpc_value ** const valuePP) { | |||||
| 695 | /*---------------------------------------------------------------------------- | |||||
| 696 | Compute the xmlrpc_value represented by the XML <value> element 'elem'. | |||||
| 697 | Return that xmlrpc_value. | |||||
| 698 | ||||||
| 699 | We call convert_array() and convert_struct(), which may ultimately | |||||
| 700 | call us recursively. Don't recurse any more than 'maxRecursion' | |||||
| 701 | times. | |||||
| 702 | -----------------------------------------------------------------------------*/ | |||||
| 703 | XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string == ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/parse_value.c", 703); while ( 0); | |||||
| 
 
 | ||||||
| 704 | XMLRPC_ASSERT(elemP != NULL)do if (!(elemP != ((void*)0))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/parse_value.c" , 704); while (0); | |||||
| 705 | ||||||
| 706 | /* Assume we'll need to recurse, make sure we're allowed */ | |||||
| 707 | if (maxRecursion < 1) | |||||
| 708 | xmlrpc_env_set_fault(envP, XMLRPC_PARSE_ERROR(-503), | |||||
| 709 | "Nested data structure too deep."); | |||||
| 710 | else { | |||||
| 711 | if (!xmlrpc_streq(xml_element_name(elemP), "value")) | |||||
| 712 | setParseFault(envP, | |||||
| 713 | "<%s> element where <value> expected", | |||||
| 714 | xml_element_name(elemP)); | |||||
| 715 | else { | |||||
| 716 | size_t const childCount = xml_element_children_size(elemP); | |||||
| 717 | ||||||
| 718 | if (childCount == 0) { | |||||
| 719 | /* We have no type element, so treat the value as a string. */ | |||||
| 720 | char * const cdata = xml_element_cdata(elemP); | |||||
| 721 | size_t const cdata_size = xml_element_cdata_size(elemP); | |||||
| 722 | *valuePP = xmlrpc_string_new_lp(envP, cdata_size, cdata); | |||||
| 723 | } else if (childCount > 1) | |||||
| 724 | setParseFault(envP, "<value> has %u child elements. " | |||||
| 725 | "Only zero or one make sense.", | |||||
| 726 | (unsigned int)childCount); | |||||
| 727 | else { | |||||
| 728 | /* We should have a type tag inside our value tag. */ | |||||
| 729 | xml_element * const childP = xml_element_children(elemP)[0]; | |||||
| 730 | const char * const childName = xml_element_name(childP); | |||||
| 731 | ||||||
| 732 | if (xmlrpc_streq(childName, "struct")) | |||||
| 733 | parseStruct(envP, maxRecursion, childP, valuePP); | |||||
| 734 | else if (xmlrpc_streq(childName, "array")) | |||||
| 735 | parseArray(envP, maxRecursion, childP, valuePP); | |||||
| 736 | else | |||||
| 737 | parseSimpleValue(envP, childP, valuePP); | |||||
| 738 | } | |||||
| 739 | } | |||||
| 740 | } | |||||
| 741 | } | |||||
| 742 | ||||||
| 743 | ||||||
| 744 |