File: | src/mod/xml_int/mod_xml_rpc/../../../../libs/xmlrpc-c/src/parse_value.c |
Location: | line 553, 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 |