File: | src/mod/xml_int/mod_xml_rpc/../../../../libs/xmlrpc-c/src/parse_value.c |
Location: | line 459, column 23 |
Description: | Array access (from variable 'string') results in a null pointer dereference |
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 |