File: | src/mod/xml_int/mod_xml_rpc/../../../../libs/xmlrpc-c/src/xmlrpc_decompose.c |
Location: | line 883, column 10 |
Description: | Access to field 'fault_occurred' results in a dereference of a null pointer (loaded from variable 'envP') |
1 | /* By Bryan Henderson July 2006. | |||
2 | ||||
3 | Contributed to the public domain. | |||
4 | */ | |||
5 | ||||
6 | #include "xmlrpc_config.h" | |||
7 | ||||
8 | #include <stddef.h> | |||
9 | #include <stdlib.h> | |||
10 | #include <stdarg.h> | |||
11 | #include <string.h> | |||
12 | ||||
13 | #include "bool.h" | |||
14 | #include "c_util.h" | |||
15 | #include "mallocvar.h" | |||
16 | #include "stdargx.h" | |||
17 | ||||
18 | #include "xmlrpc-c/base.h" | |||
19 | #include "xmlrpc-c/base_int.h" | |||
20 | #include "xmlrpc-c/string_int.h" | |||
21 | ||||
22 | ||||
23 | /* THE DECOMPOSITION TREE | |||
24 | ||||
25 | We execute xmlrpc_decompose_value() in two steps: | |||
26 | ||||
27 | 1) Create a "decomposition tree" that tells how Caller wants the XML-RPC | |||
28 | value decomposed. | |||
29 | ||||
30 | 2) Using that tree, decompose the value. I.e. store stuff in the variables | |||
31 | in which Caller wants it stored. | |||
32 | ||||
33 | The decomposition tree is composed of information from the format | |||
34 | string and the variable arguments that the format string describes. | |||
35 | Nothing in the tree is derived from the actual XML-RPC value being | |||
36 | decomposed, and the tree may in fact be invalid for the particular | |||
37 | XML-RPC value it's meant for. | |||
38 | ||||
39 | If the XML-RPC value is a simple value such as an integer, the | |||
40 | decomposition tree is trivial -- it's a single node that says | |||
41 | "store the value of an integer via pointer P". | |||
42 | ||||
43 | Where it gets interesting is where the XML-RPC value to be decomposed | |||
44 | is a complex value (array or struct). Then, the root node of the tree | |||
45 | says, e.g., "decompose a 5-item array according to the following | |||
46 | 5 decomposition trees" and it points to 5 additional nodes. Each of | |||
47 | those nodes is the root of another decomposition tree (which can also | |||
48 | be called a branch in this context). Each of those branches tells | |||
49 | how to decompose one of the items of the array. | |||
50 | ||||
51 | Roots, interior nodes, and leaves are all essentially the same data | |||
52 | type. | |||
53 | */ | |||
54 | ||||
55 | struct integerDecomp { | |||
56 | xmlrpc_int32 * valueP; | |||
57 | }; | |||
58 | ||||
59 | struct boolDecomp { | |||
60 | xmlrpc_bool * valueP; | |||
61 | }; | |||
62 | ||||
63 | struct doubleDecomp { | |||
64 | double * valueP; | |||
65 | }; | |||
66 | ||||
67 | struct datetimeTDecomp { | |||
68 | time_t * valueP; | |||
69 | }; | |||
70 | ||||
71 | struct datetime8Decomp { | |||
72 | const char ** valueP; | |||
73 | }; | |||
74 | ||||
75 | struct stringDecomp { | |||
76 | const char ** valueP; | |||
77 | size_t * sizeP; | |||
78 | /* NULL means don't store a size */ | |||
79 | }; | |||
80 | ||||
81 | struct wideStringDecomp { | |||
82 | #if HAVE_UNICODE_WCHAR1 | |||
83 | const wchar_t ** valueP; | |||
84 | #endif | |||
85 | size_t * sizeP; | |||
86 | /* NULL means don't store a size */ | |||
87 | }; | |||
88 | ||||
89 | struct bitStringDecomp { | |||
90 | const unsigned char ** valueP; | |||
91 | size_t * sizeP; | |||
92 | }; | |||
93 | ||||
94 | struct cptrDecomp { | |||
95 | void ** valueP; | |||
96 | }; | |||
97 | ||||
98 | struct i8Decomp { | |||
99 | xmlrpc_int64 * valueP; | |||
100 | }; | |||
101 | ||||
102 | struct valueDecomp { | |||
103 | xmlrpc_value ** valueP; | |||
104 | }; | |||
105 | ||||
106 | struct arrayValDecomp { | |||
107 | xmlrpc_value ** valueP; | |||
108 | }; | |||
109 | ||||
110 | struct structValDecomp { | |||
111 | xmlrpc_value ** valueP; | |||
112 | }; | |||
113 | ||||
114 | struct arrayDecomp { | |||
115 | unsigned int itemCnt; | |||
116 | bool ignoreExcess; | |||
117 | /* If there are more that 'itemCnt' items in the array, just | |||
118 | extract the first 'itemCnt' and ignore the rest, rather than | |||
119 | fail the decomposition. | |||
120 | */ | |||
121 | struct decompTreeNode * itemArray[16]; | |||
122 | /* Only first 'itemCnt' elements of this array are defined */ | |||
123 | }; | |||
124 | ||||
125 | struct mbrDecomp { | |||
126 | const char * key; | |||
127 | /* The key for the member whose value client wants to extract */ | |||
128 | struct decompTreeNode * decompTreeP; | |||
129 | /* Instructions on how to decompose (extract) member's value */ | |||
130 | }; | |||
131 | ||||
132 | struct structDecomp { | |||
133 | unsigned int mbrCnt; | |||
134 | struct mbrDecomp mbrArray[16]; | |||
135 | }; | |||
136 | ||||
137 | ||||
138 | struct decompTreeNode { | |||
139 | char formatSpecChar; | |||
140 | /* e.g. 'i', 'b', '8', 'A'. '(' means array; '{' means struct */ | |||
141 | union { | |||
142 | /*------------------------------------------------------------------------ | |||
143 | 'formatSpecChar' selects among these members. | |||
144 | -------------------------------------------------------------------------*/ | |||
145 | struct integerDecomp Tinteger; | |||
146 | struct boolDecomp Tbool; | |||
147 | struct doubleDecomp Tdouble; | |||
148 | struct datetimeTDecomp TdatetimeT; | |||
149 | struct datetime8Decomp Tdatetime8; | |||
150 | struct stringDecomp Tstring; | |||
151 | struct wideStringDecomp TwideString; | |||
152 | struct bitStringDecomp TbitString; | |||
153 | struct cptrDecomp Tcptr; | |||
154 | struct i8Decomp Ti8; | |||
155 | struct valueDecomp Tvalue; | |||
156 | struct arrayValDecomp TarrayVal; | |||
157 | struct structValDecomp TstructVal; | |||
158 | struct arrayDecomp Tarray; | |||
159 | struct structDecomp Tstruct; | |||
160 | } store; | |||
161 | ||||
162 | }; | |||
163 | ||||
164 | ||||
165 | ||||
166 | /* prototype for recursive calls */ | |||
167 | static void | |||
168 | releaseDecomposition(const struct decompTreeNode * const decompRootP, | |||
169 | bool const oldstyleMemMgmt); | |||
170 | ||||
171 | ||||
172 | static void | |||
173 | releaseDecompArray(struct arrayDecomp const arrayDecomp, | |||
174 | bool const oldstyleMemMgmt) { | |||
175 | ||||
176 | unsigned int i; | |||
177 | for (i = 0; i < arrayDecomp.itemCnt; ++i) { | |||
178 | releaseDecomposition(arrayDecomp.itemArray[i], oldstyleMemMgmt); | |||
179 | } | |||
180 | } | |||
181 | ||||
182 | ||||
183 | static void | |||
184 | releaseDecompStruct(struct structDecomp const structDecomp, | |||
185 | bool const oldstyleMemMgmt) { | |||
186 | ||||
187 | unsigned int i; | |||
188 | for (i = 0; i < structDecomp.mbrCnt; ++i) { | |||
189 | releaseDecomposition(structDecomp.mbrArray[i].decompTreeP, | |||
190 | oldstyleMemMgmt); | |||
191 | } | |||
192 | } | |||
193 | ||||
194 | ||||
195 | ||||
196 | static void | |||
197 | releaseDecomposition(const struct decompTreeNode * const decompRootP, | |||
198 | bool const oldstyleMemMgmt) { | |||
199 | /*---------------------------------------------------------------------------- | |||
200 | Assuming that Caller has decomposed something according to 'decompRootP', | |||
201 | release whatever resources the decomposed information occupies. | |||
202 | ||||
203 | E.g. if it's an XML-RPC string, Caller would have allocated memory | |||
204 | for the C string that represents the decomposed value of XML-RPC string, | |||
205 | and we release that memory. | |||
206 | -----------------------------------------------------------------------------*/ | |||
207 | switch (decompRootP->formatSpecChar) { | |||
208 | case 'i': | |||
209 | case 'b': | |||
210 | case 'd': | |||
211 | case 'n': | |||
212 | case 'I': | |||
213 | case 't': | |||
214 | case 'p': | |||
215 | /* Nothing was allocated; nothing to release */ | |||
216 | break; | |||
217 | case '8': | |||
218 | xmlrpc_strfree(*decompRootP->store.Tdatetime8.valueP); | |||
219 | break; | |||
220 | case 's': | |||
221 | xmlrpc_strfree(*decompRootP->store.Tstring.valueP); | |||
222 | break; | |||
223 | case 'w': | |||
224 | free((void*)*decompRootP->store.TwideString.valueP); | |||
225 | break; | |||
226 | case '6': | |||
227 | free((void*)*decompRootP->store.TbitString.valueP); | |||
228 | break; | |||
229 | case 'V': | |||
230 | xmlrpc_DECREF(*decompRootP->store.Tvalue.valueP); | |||
231 | break; | |||
232 | case 'A': | |||
233 | xmlrpc_DECREF(*decompRootP->store.TarrayVal.valueP); | |||
234 | break; | |||
235 | case 'S': | |||
236 | xmlrpc_DECREF(*decompRootP->store.TstructVal.valueP); | |||
237 | break; | |||
238 | case '(': | |||
239 | releaseDecompArray(decompRootP->store.Tarray, oldstyleMemMgmt); | |||
240 | break; | |||
241 | case '{': | |||
242 | releaseDecompStruct(decompRootP->store.Tstruct, oldstyleMemMgmt); | |||
243 | break; | |||
244 | } | |||
245 | } | |||
246 | ||||
247 | ||||
248 | ||||
249 | /* Prototype for recursive invocation: */ | |||
250 | ||||
251 | static void | |||
252 | decomposeValueWithTree(xmlrpc_env * const envP, | |||
253 | xmlrpc_value * const valueP, | |||
254 | bool const oldstyleMemMgmt, | |||
255 | const struct decompTreeNode * const decompRootP); | |||
256 | ||||
257 | ||||
258 | ||||
259 | static void | |||
260 | validateArraySize(xmlrpc_env * const envP, | |||
261 | const xmlrpc_value * const arrayP, | |||
262 | struct arrayDecomp const arrayDecomp) { | |||
263 | ||||
264 | unsigned int size; | |||
265 | ||||
266 | size = xmlrpc_array_size(envP, arrayP); | |||
267 | if (!envP->fault_occurred) { | |||
268 | if (arrayDecomp.itemCnt > size) | |||
269 | xmlrpc_env_set_fault_formatted( | |||
270 | envP, XMLRPC_INDEX_ERROR(-502), | |||
271 | "Format string requests %u items from array, but array " | |||
272 | "has only %u items.", arrayDecomp.itemCnt, size); | |||
273 | else if (arrayDecomp.itemCnt < size && !arrayDecomp.ignoreExcess) | |||
274 | xmlrpc_env_set_fault_formatted( | |||
275 | envP, XMLRPC_INDEX_ERROR(-502), | |||
276 | "Format string requests exactly %u items from array, " | |||
277 | "but array has %u items. (A '*' at the end would avoid " | |||
278 | "this failure)", arrayDecomp.itemCnt, size); | |||
279 | } | |||
280 | } | |||
281 | ||||
282 | ||||
283 | ||||
284 | static void | |||
285 | parsearray(xmlrpc_env * const envP, | |||
286 | const xmlrpc_value * const arrayP, | |||
287 | struct arrayDecomp const arrayDecomp, | |||
288 | bool const oldstyleMemMgmt) { | |||
289 | ||||
290 | validateArraySize(envP, arrayP, arrayDecomp); | |||
291 | ||||
292 | if (!envP->fault_occurred) { | |||
293 | unsigned int doneCnt; | |||
294 | ||||
295 | doneCnt = 0; | |||
296 | while(doneCnt < arrayDecomp.itemCnt && !envP->fault_occurred) { | |||
297 | xmlrpc_value * itemP; | |||
298 | ||||
299 | xmlrpc_array_read_item(envP, arrayP, doneCnt, &itemP); | |||
300 | ||||
301 | if (!envP->fault_occurred) { | |||
302 | XMLRPC_ASSERT(doneCnt < ARRAY_SIZE(arrayDecomp.itemArray))do if (!(doneCnt < (sizeof(arrayDecomp.itemArray)/sizeof(arrayDecomp .itemArray[0])))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_decompose.c" , 302); while (0); | |||
303 | decomposeValueWithTree(envP, itemP, oldstyleMemMgmt, | |||
304 | arrayDecomp.itemArray[doneCnt]); | |||
305 | ||||
306 | if (!envP->fault_occurred) | |||
307 | ++doneCnt; | |||
308 | ||||
309 | xmlrpc_DECREF(itemP); | |||
310 | } | |||
311 | } | |||
312 | if (envP->fault_occurred) { | |||
313 | /* Release the items we completed before we failed. */ | |||
314 | unsigned int i; | |||
315 | for (i = 0; i < doneCnt; ++i) | |||
316 | releaseDecomposition(arrayDecomp.itemArray[i], | |||
317 | oldstyleMemMgmt); | |||
318 | } | |||
319 | } | |||
320 | } | |||
321 | ||||
322 | ||||
323 | ||||
324 | static void | |||
325 | parsestruct(xmlrpc_env * const envP, | |||
326 | xmlrpc_value * const structP, | |||
327 | struct structDecomp const structDecomp, | |||
328 | bool const oldstyleMemMgmt) { | |||
329 | ||||
330 | unsigned int doneCount; | |||
331 | ||||
332 | doneCount = 0; /* No members done yet */ | |||
333 | ||||
334 | while (doneCount < structDecomp.mbrCnt && !envP->fault_occurred) { | |||
335 | const char * const key = structDecomp.mbrArray[doneCount].key; | |||
336 | ||||
337 | xmlrpc_value * valueP; | |||
338 | ||||
339 | xmlrpc_struct_read_value(envP, structP, key, &valueP); | |||
340 | ||||
341 | if (!envP->fault_occurred) { | |||
342 | decomposeValueWithTree( | |||
343 | envP, valueP, oldstyleMemMgmt, | |||
344 | structDecomp.mbrArray[doneCount].decompTreeP); | |||
345 | ||||
346 | if (!envP->fault_occurred) | |||
347 | ++doneCount; | |||
348 | ||||
349 | xmlrpc_DECREF(valueP); | |||
350 | } | |||
351 | } | |||
352 | ||||
353 | if (envP->fault_occurred) { | |||
354 | unsigned int i; | |||
355 | for (i = 0; i < doneCount; ++i) | |||
356 | releaseDecomposition(structDecomp.mbrArray[i].decompTreeP, | |||
357 | oldstyleMemMgmt); | |||
358 | } | |||
359 | } | |||
360 | ||||
361 | ||||
362 | ||||
363 | static void | |||
364 | readString(xmlrpc_env * const envP, | |||
365 | const xmlrpc_value * const valueP, | |||
366 | const char ** const stringValueP, | |||
367 | bool const oldstyleMemMgmt) { | |||
368 | ||||
369 | if (oldstyleMemMgmt) { | |||
370 | xmlrpc_read_string_old(envP, valueP, stringValueP); | |||
371 | } else | |||
372 | xmlrpc_read_string(envP, valueP, stringValueP); | |||
373 | } | |||
374 | ||||
375 | ||||
376 | ||||
377 | static void | |||
378 | readStringLp(xmlrpc_env * const envP, | |||
379 | const xmlrpc_value * const valueP, | |||
380 | size_t * const lengthP, | |||
381 | const char ** const stringValueP, | |||
382 | bool const oldstyleMemMgmt) { | |||
383 | ||||
384 | if (oldstyleMemMgmt) { | |||
385 | xmlrpc_read_string_lp_old(envP, valueP, lengthP, stringValueP); | |||
386 | } else | |||
387 | xmlrpc_read_string_lp(envP, valueP, lengthP, stringValueP); | |||
388 | } | |||
389 | ||||
390 | ||||
391 | ||||
392 | #if HAVE_UNICODE_WCHAR1 | |||
393 | static void | |||
394 | readStringW(xmlrpc_env * const envP, | |||
395 | xmlrpc_value * const valueP, | |||
396 | const wchar_t ** const stringValueP, | |||
397 | bool const oldstyleMemMgmt) { | |||
398 | ||||
399 | if (oldstyleMemMgmt) { | |||
400 | xmlrpc_read_string_w_old(envP, valueP, stringValueP); | |||
401 | } else | |||
402 | xmlrpc_read_string_w(envP, valueP, stringValueP); | |||
403 | } | |||
404 | ||||
405 | ||||
406 | ||||
407 | static void | |||
408 | readStringWLp(xmlrpc_env * const envP, | |||
409 | xmlrpc_value * const valueP, | |||
410 | size_t * const lengthP, | |||
411 | const wchar_t ** const stringValueP, | |||
412 | bool const oldstyleMemMgmt) { | |||
413 | ||||
414 | if (oldstyleMemMgmt) { | |||
415 | xmlrpc_read_string_w_lp_old(envP, valueP, lengthP, stringValueP); | |||
416 | } else | |||
417 | xmlrpc_read_string_w_lp(envP, valueP, lengthP, stringValueP); | |||
418 | } | |||
419 | #endif | |||
420 | ||||
421 | ||||
422 | static void | |||
423 | readDatetime8Str(xmlrpc_env * const envP, | |||
424 | const xmlrpc_value * const valueP, | |||
425 | const char ** const stringValueP, | |||
426 | bool const oldstyleMemMgmt) { | |||
427 | ||||
428 | if (oldstyleMemMgmt) | |||
429 | xmlrpc_read_datetime_str_old(envP, valueP, stringValueP); | |||
430 | else | |||
431 | xmlrpc_read_datetime_str(envP, valueP, stringValueP); | |||
432 | } | |||
433 | ||||
434 | ||||
435 | ||||
436 | static void | |||
437 | readBase64(xmlrpc_env * const envP, | |||
438 | const xmlrpc_value * const valueP, | |||
439 | size_t * const lengthP, | |||
440 | const unsigned char ** const byteStringValueP, | |||
441 | bool const oldstyleMemMgmt) { | |||
442 | ||||
443 | if (oldstyleMemMgmt) | |||
444 | xmlrpc_read_base64_old(envP, valueP, lengthP, byteStringValueP); | |||
445 | else | |||
446 | xmlrpc_read_base64(envP, valueP, lengthP, byteStringValueP); | |||
447 | } | |||
448 | ||||
449 | ||||
450 | static void | |||
451 | decomposeValueWithTree(xmlrpc_env * const envP, | |||
452 | xmlrpc_value * const valueP, | |||
453 | bool const oldstyleMemMgmt, | |||
454 | const struct decompTreeNode * const decompRootP) { | |||
455 | /*---------------------------------------------------------------------------- | |||
456 | Decompose XML-RPC value *valueP, given the decomposition tree | |||
457 | *decompRootP. The decomposition tree tells what structure *valueP | |||
458 | is expected to have and where to put the various components of it | |||
459 | (e.g. it says "it's an array of 3 integers. Put their values at | |||
460 | locations x, y, and z") | |||
461 | -----------------------------------------------------------------------------*/ | |||
462 | switch (decompRootP->formatSpecChar) { | |||
463 | case '-': | |||
464 | /* There's nothing to validate or return */ | |||
465 | break; | |||
466 | case 'i': | |||
467 | xmlrpc_read_int(envP, valueP, decompRootP->store.Tinteger.valueP); | |||
468 | break; | |||
469 | ||||
470 | case 'b': | |||
471 | xmlrpc_read_bool(envP, valueP, decompRootP->store.Tbool.valueP); | |||
472 | break; | |||
473 | ||||
474 | case 'd': | |||
475 | xmlrpc_read_double(envP, valueP, decompRootP->store.Tdouble.valueP); | |||
476 | break; | |||
477 | ||||
478 | case 't': | |||
479 | xmlrpc_read_datetime_sec(envP, valueP, | |||
480 | decompRootP->store.TdatetimeT.valueP); | |||
481 | break; | |||
482 | ||||
483 | case '8': | |||
484 | readDatetime8Str(envP, valueP, decompRootP->store.Tdatetime8.valueP, | |||
485 | oldstyleMemMgmt); | |||
486 | break; | |||
487 | ||||
488 | case 's': | |||
489 | if (decompRootP->store.Tstring.sizeP) | |||
490 | readStringLp(envP, valueP, | |||
491 | decompRootP->store.Tstring.sizeP, | |||
492 | decompRootP->store.Tstring.valueP, | |||
493 | oldstyleMemMgmt); | |||
494 | else | |||
495 | readString(envP, valueP, decompRootP->store.Tstring.valueP, | |||
496 | oldstyleMemMgmt); | |||
497 | break; | |||
498 | ||||
499 | case 'w': | |||
500 | #if HAVE_UNICODE_WCHAR1 | |||
501 | if (decompRootP->store.Tstring.sizeP) | |||
502 | readStringWLp(envP, valueP, | |||
503 | decompRootP->store.TwideString.sizeP, | |||
504 | decompRootP->store.TwideString.valueP, | |||
505 | oldstyleMemMgmt); | |||
506 | else | |||
507 | readStringW(envP, valueP, decompRootP->store.TwideString.valueP, | |||
508 | oldstyleMemMgmt); | |||
509 | #else | |||
510 | XMLRPC_ASSERT(false)do if (!(false)) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_decompose.c" , 510); while (0); | |||
511 | #endif /* HAVE_UNICODE_WCHAR */ | |||
512 | break; | |||
513 | ||||
514 | case '6': | |||
515 | readBase64(envP, valueP, | |||
516 | decompRootP->store.TbitString.sizeP, | |||
517 | decompRootP->store.TbitString.valueP, | |||
518 | oldstyleMemMgmt); | |||
519 | break; | |||
520 | ||||
521 | case 'n': | |||
522 | xmlrpc_read_nil(envP, valueP); | |||
523 | break; | |||
524 | ||||
525 | case 'I': | |||
526 | xmlrpc_read_i8(envP, valueP, decompRootP->store.Ti8.valueP); | |||
527 | break; | |||
528 | ||||
529 | case 'p': | |||
530 | xmlrpc_read_cptr(envP, valueP, decompRootP->store.Tcptr.valueP); | |||
531 | break; | |||
532 | ||||
533 | case 'V': | |||
534 | *decompRootP->store.Tvalue.valueP = valueP; | |||
535 | if (!oldstyleMemMgmt) | |||
536 | xmlrpc_INCREF(valueP); | |||
537 | break; | |||
538 | ||||
539 | case 'A': | |||
540 | if (xmlrpc_value_type(valueP) != XMLRPC_TYPE_ARRAY) | |||
541 | xmlrpc_env_set_fault_formatted( | |||
542 | envP, XMLRPC_TYPE_ERROR(-501), "Value to be decomposed is of type " | |||
543 | "%s, but the 'A' specifier requires type ARRAY", | |||
544 | xmlrpc_type_name(xmlrpc_value_type(valueP))); | |||
545 | else { | |||
546 | *decompRootP->store.TarrayVal.valueP = valueP; | |||
547 | if (!oldstyleMemMgmt) | |||
548 | xmlrpc_INCREF(valueP); | |||
549 | } | |||
550 | break; | |||
551 | ||||
552 | case 'S': | |||
553 | if (xmlrpc_value_type(valueP) != XMLRPC_TYPE_STRUCT) | |||
554 | xmlrpc_env_set_fault_formatted( | |||
555 | envP, XMLRPC_TYPE_ERROR(-501), "Value to be decomposed is of type " | |||
556 | "%s, but the 'S' specifier requires type STRUCT.", | |||
557 | xmlrpc_type_name(xmlrpc_value_type(valueP))); | |||
558 | else { | |||
559 | *decompRootP->store.TstructVal.valueP = valueP; | |||
560 | if (!oldstyleMemMgmt) | |||
561 | xmlrpc_INCREF(valueP); | |||
562 | } | |||
563 | break; | |||
564 | ||||
565 | case '(': | |||
566 | if (xmlrpc_value_type(valueP) != XMLRPC_TYPE_ARRAY) | |||
567 | xmlrpc_env_set_fault_formatted( | |||
568 | envP, XMLRPC_TYPE_ERROR(-501), "Value to be decomposed is of type " | |||
569 | "%s, but the '(...)' specifier requires type ARRAY", | |||
570 | xmlrpc_type_name(xmlrpc_value_type(valueP))); | |||
571 | else | |||
572 | parsearray(envP, valueP, decompRootP->store.Tarray, | |||
573 | oldstyleMemMgmt); | |||
574 | break; | |||
575 | ||||
576 | case '{': | |||
577 | if (xmlrpc_value_type(valueP) != XMLRPC_TYPE_STRUCT) | |||
578 | xmlrpc_env_set_fault_formatted( | |||
579 | envP, XMLRPC_TYPE_ERROR(-501), "Value to be decomposed is of type " | |||
580 | "%s, but the '{...}' specifier requires type STRUCT", | |||
581 | xmlrpc_type_name(xmlrpc_value_type(valueP))); | |||
582 | else | |||
583 | parsestruct(envP, valueP, decompRootP->store.Tstruct, | |||
584 | oldstyleMemMgmt); | |||
585 | break; | |||
586 | ||||
587 | default: | |||
588 | /* Every format character that is allowed in a decomposition tree | |||
589 | node is handled above. | |||
590 | */ | |||
591 | XMLRPC_ASSERT(false)do if (!(false)) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_decompose.c" , 591); while (0); | |||
592 | } | |||
593 | } | |||
594 | ||||
595 | ||||
596 | /* Forward declaration for recursive calls */ | |||
597 | ||||
598 | static void | |||
599 | createDecompTreeNext(xmlrpc_env * const envP, | |||
600 | const char ** const formatP, | |||
601 | va_listx * const argsP, | |||
602 | struct decompTreeNode ** const decompNodePP); | |||
603 | ||||
604 | ||||
605 | ||||
606 | static void | |||
607 | buildWideStringNode(xmlrpc_env * const envP ATTR_UNUSED__attribute__((__unused__)), | |||
608 | const char ** const formatP, | |||
609 | va_listx * const argsP, | |||
610 | struct decompTreeNode * const decompNodeP) { | |||
611 | ||||
612 | #if HAVE_UNICODE_WCHAR1 | |||
613 | decompNodeP->store.TwideString.valueP = | |||
614 | (const wchar_t**) va_arg(argsP->v, wchar_t**)__builtin_va_arg(argsP->v, wchar_t**); | |||
615 | if (**formatP == '#') { | |||
616 | decompNodeP->store.TwideString.sizeP = | |||
617 | (size_t*) va_arg(argsP->v, size_t**)__builtin_va_arg(argsP->v, size_t**); | |||
618 | (*formatP)++; | |||
619 | } else | |||
620 | decompNodeP->store.TwideString.sizeP = NULL((void*)0); | |||
621 | #else | |||
622 | xmlrpc_faultf(envP, | |||
623 | "This XML-RPC For C/C++ library was built without Unicode " | |||
624 | "wide character capability. 'w' isn't available."); | |||
625 | #endif /* HAVE_UNICODE_WCHAR */ | |||
626 | } | |||
627 | ||||
628 | ||||
629 | ||||
630 | static void | |||
631 | destroyDecompTree(struct decompTreeNode * const decompRootP) { | |||
632 | ||||
633 | switch (decompRootP->formatSpecChar) { | |||
634 | case '(': { | |||
635 | unsigned int i; | |||
636 | for (i = 0; i < decompRootP->store.Tarray.itemCnt; ++i) | |||
637 | destroyDecompTree(decompRootP->store.Tarray.itemArray[i]); | |||
638 | } break; | |||
639 | case '{': { | |||
640 | unsigned int i; | |||
641 | for (i = 0; i < decompRootP->store.Tstruct.mbrCnt; ++i) | |||
642 | destroyDecompTree( | |||
643 | decompRootP->store.Tstruct.mbrArray[i].decompTreeP); | |||
644 | } break; | |||
645 | } | |||
646 | ||||
647 | free(decompRootP); | |||
648 | } | |||
649 | ||||
650 | ||||
651 | ||||
652 | static void | |||
653 | processArraySpecTail(xmlrpc_env * const envP, | |||
654 | const char ** const formatP, | |||
655 | bool * const hasTrailingAsteriskP, | |||
656 | char const delim) { | |||
657 | ||||
658 | if (**formatP == '*') { | |||
659 | *hasTrailingAsteriskP = true; | |||
660 | ||||
661 | ++*formatP; | |||
662 | ||||
663 | if (!**formatP) | |||
664 | xmlrpc_faultf(envP, "missing closing delimiter ('%c')", delim); | |||
665 | else if (**formatP != delim) | |||
666 | xmlrpc_faultf(envP, "character following '*' in array " | |||
667 | "specification should be the closing delimiter " | |||
668 | "'%c', but is '%c'", delim, **formatP); | |||
669 | } else { | |||
670 | *hasTrailingAsteriskP = false; | |||
671 | ||||
672 | if (!**formatP) | |||
673 | xmlrpc_faultf(envP, "missing closing delimiter ('%c')", delim); | |||
674 | } | |||
675 | if (!envP->fault_occurred) | |||
676 | XMLRPC_ASSERT(**formatP == delim)do if (!(**formatP == delim)) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_decompose.c" , 676); while (0); | |||
677 | } | |||
678 | ||||
679 | ||||
680 | ||||
681 | static void | |||
682 | buildArrayDecompBranch(xmlrpc_env * const envP, | |||
683 | const char ** const formatP, | |||
684 | char const delim, | |||
685 | va_listx * const argsP, | |||
686 | struct decompTreeNode * const decompNodeP) { | |||
687 | /*---------------------------------------------------------------------------- | |||
688 | Fill in the decomposition tree node *decompNodeP to cover an array | |||
689 | whose items are described by *formatP. To wit, they are the values | |||
690 | described by successive format specifiers in *formatP up to but not | |||
691 | including the next 'delim' character. | |||
692 | ||||
693 | Plus, the last character before the delimiter might be a '*', which | |||
694 | means "ignore any additional items in the array." | |||
695 | ||||
696 | We create a node (and whole branch if required) to describe each array | |||
697 | item. | |||
698 | ||||
699 | The pointers to where those items are to be stored are given by | |||
700 | 'argsP'. | |||
701 | ||||
702 | We advance *formatP to the delimiter character, and advance 'argsP' | |||
703 | past whatever arguments we use. | |||
704 | -----------------------------------------------------------------------------*/ | |||
705 | unsigned int itemCnt; | |||
706 | /* Number of array items in the branch so far */ | |||
707 | ||||
708 | itemCnt = 0; /* Branch is empty so far */ | |||
709 | ||||
710 | while (**formatP && **formatP != delim && **formatP != '*' && | |||
711 | !envP->fault_occurred) { | |||
712 | if (itemCnt >= ARRAY_SIZE(decompNodeP->store.Tarray.itemArray)(sizeof(decompNodeP->store.Tarray.itemArray)/sizeof(decompNodeP ->store.Tarray.itemArray[0]))) | |||
713 | xmlrpc_faultf(envP, "Too many array items in format string. " | |||
714 | "The most items you can have for an array in " | |||
715 | "a format string is %u.", (unsigned) | |||
716 | ARRAY_SIZE(decompNodeP->store.Tarray.itemArray)(sizeof(decompNodeP->store.Tarray.itemArray)/sizeof(decompNodeP ->store.Tarray.itemArray[0]))); | |||
717 | else { | |||
718 | struct decompTreeNode * itemNodeP; | |||
719 | ||||
720 | createDecompTreeNext(envP, formatP, argsP, &itemNodeP); | |||
721 | ||||
722 | if (!envP->fault_occurred) | |||
723 | decompNodeP->store.Tarray.itemArray[itemCnt++] = itemNodeP; | |||
724 | } | |||
725 | } | |||
726 | if (!envP->fault_occurred) { | |||
727 | decompNodeP->store.Tarray.itemCnt = itemCnt; | |||
728 | processArraySpecTail(envP, formatP, | |||
729 | &decompNodeP->store.Tarray.ignoreExcess, | |||
730 | delim); | |||
731 | } | |||
732 | if (envP->fault_occurred) { | |||
733 | unsigned int i; | |||
734 | for (i = 0; i < itemCnt; ++i) | |||
735 | destroyDecompTree(decompNodeP->store.Tarray.itemArray[i]); | |||
736 | } | |||
737 | } | |||
738 | ||||
739 | ||||
740 | ||||
741 | static void | |||
742 | doStructValue(xmlrpc_env * const envP, | |||
743 | const char ** const formatP, | |||
744 | va_listx * const argsP, | |||
745 | struct mbrDecomp * const mbrP) { | |||
746 | ||||
747 | struct decompTreeNode * valueNodeP; | |||
748 | ||||
749 | mbrP->key = (const char*) va_arg(argsP->v, char*)__builtin_va_arg(argsP->v, char*); | |||
750 | ||||
751 | createDecompTreeNext(envP, formatP, argsP, &valueNodeP); | |||
752 | ||||
753 | if (!envP->fault_occurred) | |||
754 | mbrP->decompTreeP = valueNodeP; | |||
755 | } | |||
756 | ||||
757 | ||||
758 | ||||
759 | static void | |||
760 | skipAsterisk(xmlrpc_env * const envP, | |||
761 | const char ** const formatP, | |||
762 | char const delim) { | |||
763 | ||||
764 | if (**formatP == '*') { | |||
765 | ++*formatP; | |||
766 | ||||
767 | if (!**formatP) | |||
768 | xmlrpc_faultf(envP, "missing closing delimiter ('%c')", delim); | |||
769 | else if (**formatP != delim) | |||
770 | xmlrpc_faultf(envP, "junk after '*' in the specifier of an " | |||
771 | "array. First character='%c'", **formatP); | |||
772 | } else | |||
773 | /* Conceptually, one can make it an error to leave some struct | |||
774 | members behind, but we have never had code that knows how to | |||
775 | recognize that case. | |||
776 | */ | |||
777 | xmlrpc_faultf(envP, | |||
778 | "You must put a trailing '*' in the specifiers for " | |||
779 | "struct members to signify it's OK if there are " | |||
780 | "additional members you didn't get."); | |||
781 | } | |||
782 | ||||
783 | ||||
784 | ||||
785 | static void | |||
786 | skipColon(xmlrpc_env * const envP, | |||
787 | const char ** const formatP, | |||
788 | char const delim) { | |||
789 | ||||
790 | if (**formatP == '\0') | |||
791 | xmlrpc_faultf(envP, "format string ends in the middle of a struct " | |||
792 | "member specifier"); | |||
793 | else if (**formatP == delim) | |||
794 | xmlrpc_faultf(envP, "member list ends in the middle of a member"); | |||
795 | else if (**formatP != ':') | |||
796 | xmlrpc_faultf(envP, "In a struct specifier, '%c' found " | |||
797 | "where a colon (':') separating key and " | |||
798 | "value was expected.", **formatP); | |||
799 | } | |||
800 | ||||
801 | ||||
802 | ||||
803 | static void | |||
804 | skipComma(xmlrpc_env * const envP, | |||
805 | const char ** const formatP, | |||
806 | char const delim) { | |||
807 | ||||
808 | if (**formatP && **formatP != delim) { | |||
809 | if (**formatP == ',') | |||
810 | ++*formatP; /* skip over comma */ | |||
811 | else | |||
812 | xmlrpc_faultf(envP, "'%c' where we expected a ',' " | |||
813 | "to separate struct members", **formatP); | |||
814 | } | |||
815 | } | |||
816 | ||||
817 | ||||
818 | ||||
819 | static void | |||
820 | buildStructDecompBranch(xmlrpc_env * const envP, | |||
821 | const char ** const formatP, | |||
822 | char const delim, | |||
823 | va_listx * const argsP, | |||
824 | struct decompTreeNode * const decompNodeP) { | |||
825 | /*---------------------------------------------------------------------------- | |||
826 | Fill in the decomposition tree node *decompNodeP to cover a struct | |||
827 | whose members are described by *formatP. To wit, they are the values | |||
828 | described by successive format specifiers in *formatP up to but not | |||
829 | including the next 'delim' character. | |||
830 | ||||
831 | We create a node (and whole branch if required) to describe each | |||
832 | struct member value. | |||
833 | ||||
834 | The pointers to where those values are to be stored are given by | |||
835 | 'argsP'. | |||
836 | ||||
837 | The names of the members to be extracted are also given by 'argsP'. | |||
838 | ||||
839 | We advance *formatP to the delimiter character, and advance 'argsP' | |||
840 | past whatever arguments we use. | |||
841 | -----------------------------------------------------------------------------*/ | |||
842 | unsigned int memberCnt; | |||
843 | /* Number of struct members in the branch so far */ | |||
844 | ||||
845 | memberCnt = 0; /* Branch is empty so far */ | |||
846 | ||||
847 | while (**formatP && **formatP != delim && **formatP != '*' && | |||
848 | !envP->fault_occurred) { | |||
849 | if (memberCnt >= ARRAY_SIZE(decompNodeP->store.Tstruct.mbrArray)(sizeof(decompNodeP->store.Tstruct.mbrArray)/sizeof(decompNodeP ->store.Tstruct.mbrArray[0]))) | |||
850 | xmlrpc_faultf(envP, | |||
851 | "Too many structure members in format string. " | |||
852 | "The most members you can specify in " | |||
853 | "a format string is %u.", (unsigned) | |||
854 | ARRAY_SIZE(decompNodeP->store.Tstruct.mbrArray)(sizeof(decompNodeP->store.Tstruct.mbrArray)/sizeof(decompNodeP ->store.Tstruct.mbrArray[0]))); | |||
855 | else { | |||
856 | struct mbrDecomp * const mbrP = | |||
857 | &decompNodeP->store.Tstruct.mbrArray[memberCnt]; | |||
858 | ||||
859 | if (**formatP != 's') | |||
860 | xmlrpc_faultf(envP, "In a struct specifier, the specifier " | |||
861 | "for the key is '%c', but it must be 's'.", | |||
862 | **formatP); | |||
863 | else { | |||
864 | ++*formatP; | |||
865 | ||||
866 | skipColon(envP, formatP, delim); | |||
867 | ||||
868 | if (!envP->fault_occurred) { | |||
869 | ++*formatP; | |||
870 | ||||
871 | doStructValue(envP, formatP, argsP, mbrP); | |||
872 | ||||
873 | if (!envP->fault_occurred) | |||
874 | ++memberCnt; | |||
875 | ||||
876 | skipComma(envP, formatP, delim); | |||
877 | } | |||
878 | } | |||
879 | } | |||
880 | } | |||
881 | decompNodeP->store.Tstruct.mbrCnt = memberCnt; | |||
882 | ||||
883 | if (!envP->fault_occurred) { | |||
| ||||
884 | skipAsterisk(envP, formatP, delim); | |||
885 | if (!envP->fault_occurred) | |||
886 | XMLRPC_ASSERT(**formatP == delim)do if (!(**formatP == delim)) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_decompose.c" , 886); while (0); | |||
887 | } | |||
888 | ||||
889 | if (envP->fault_occurred) { | |||
890 | unsigned int i; | |||
891 | for (i = 0; i < memberCnt; ++i) | |||
892 | destroyDecompTree( | |||
893 | decompNodeP->store.Tstruct.mbrArray[i].decompTreeP); | |||
894 | } | |||
895 | } | |||
896 | ||||
897 | ||||
898 | ||||
899 | static void | |||
900 | createDecompTreeNext(xmlrpc_env * const envP, | |||
901 | const char ** const formatP, | |||
902 | va_listx * const argsP, | |||
903 | struct decompTreeNode ** const decompNodePP) { | |||
904 | /*---------------------------------------------------------------------------- | |||
905 | Create a branch of a decomposition tree that applies to the first | |||
906 | value described by '*formatP', and advance *formatP past the description | |||
907 | of that first value. E.g.: | |||
908 | ||||
909 | - If *formatP is "isb", we create a branch consisting of one | |||
910 | node -- for an integer. We advance *formatP by one character, so | |||
911 | it points to the "s". | |||
912 | ||||
913 | - If *formatP is "(isb)s", we create a branch that represents the | |||
914 | array (isb) and advance *formatP past the closing parenthesis to | |||
915 | point to the final "s". We return as *decompNodePP a pointer to | |||
916 | a node for the array, and that array in turn points to nodes for | |||
917 | each of the 3 array items: one for an integer, one for a string, | |||
918 | and one for a boolean. | |||
919 | ||||
920 | The locations at which the components of that value are to be | |||
921 | stored (which is the main contents of the branch we create) are | |||
922 | given by 'argsP'. | |||
923 | ||||
924 | Return as *decompNodeP a pointer to the root node of the branch we | |||
925 | generate. | |||
926 | -----------------------------------------------------------------------------*/ | |||
927 | struct decompTreeNode * decompNodeP; | |||
928 | ||||
929 | MALLOCVAR(decompNodeP)decompNodeP = malloc(sizeof(*decompNodeP)); | |||
930 | ||||
931 | if (decompNodeP == NULL((void*)0)) | |||
932 | xmlrpc_faultf(envP, "Could not allocate space for a decomposition " | |||
933 | "tree node"); | |||
934 | else { | |||
935 | decompNodeP->formatSpecChar = *(*formatP)++; | |||
936 | ||||
937 | switch (decompNodeP->formatSpecChar) { | |||
938 | case '-': | |||
939 | /* There's nothing to store */ | |||
940 | break; | |||
941 | case 'i': | |||
942 | decompNodeP->store.Tinteger.valueP = | |||
943 | (xmlrpc_int32*) va_arg(argsP->v, xmlrpc_int32*)__builtin_va_arg(argsP->v, xmlrpc_int32*); | |||
944 | break; | |||
945 | ||||
946 | case 'b': | |||
947 | decompNodeP->store.Tbool.valueP = | |||
948 | (xmlrpc_bool*) va_arg(argsP->v, xmlrpc_bool*)__builtin_va_arg(argsP->v, xmlrpc_bool*); | |||
949 | break; | |||
950 | ||||
951 | case 'd': | |||
952 | decompNodeP->store.Tdouble.valueP = | |||
953 | (double*) va_arg(argsP->v, double*)__builtin_va_arg(argsP->v, double*); | |||
954 | break; | |||
955 | ||||
956 | case 't': | |||
957 | decompNodeP->store.TdatetimeT.valueP = | |||
958 | va_arg(argsP->v, time_t*)__builtin_va_arg(argsP->v, time_t*); | |||
959 | break; | |||
960 | ||||
961 | case '8': | |||
962 | decompNodeP->store.Tdatetime8.valueP = | |||
963 | (const char**) va_arg(argsP->v, char**)__builtin_va_arg(argsP->v, char**); | |||
964 | break; | |||
965 | ||||
966 | case 's': | |||
967 | decompNodeP->store.Tstring.valueP = | |||
968 | (const char**) va_arg(argsP->v, char**)__builtin_va_arg(argsP->v, char**); | |||
969 | if (**formatP == '#') { | |||
970 | decompNodeP->store.Tstring.sizeP = | |||
971 | (size_t*) va_arg(argsP->v, size_t**)__builtin_va_arg(argsP->v, size_t**); | |||
972 | ++*formatP; | |||
973 | } else | |||
974 | decompNodeP->store.Tstring.sizeP = NULL((void*)0); | |||
975 | break; | |||
976 | ||||
977 | case 'w': | |||
978 | buildWideStringNode(envP, formatP, argsP, decompNodeP); | |||
979 | break; | |||
980 | ||||
981 | case '6': | |||
982 | decompNodeP->store.TbitString.valueP = | |||
983 | (const unsigned char**) va_arg(argsP->v, unsigned char**)__builtin_va_arg(argsP->v, unsigned char**); | |||
984 | decompNodeP->store.TbitString.sizeP = | |||
985 | (size_t*) va_arg(argsP->v, size_t**)__builtin_va_arg(argsP->v, size_t**); | |||
986 | break; | |||
987 | ||||
988 | case 'n': | |||
989 | /* There's no value to store */ | |||
990 | break; | |||
991 | ||||
992 | case 'I': | |||
993 | decompNodeP->store.Ti8.valueP = | |||
994 | (xmlrpc_int64 *) va_arg(argsP->v, xmlrpc_int64 *)__builtin_va_arg(argsP->v, xmlrpc_int64 *); | |||
995 | break; | |||
996 | ||||
997 | case 'p': | |||
998 | decompNodeP->store.Tcptr.valueP = | |||
999 | (void**) va_arg(argsP->v, void**)__builtin_va_arg(argsP->v, void**); | |||
1000 | break; | |||
1001 | ||||
1002 | case 'V': | |||
1003 | decompNodeP->store.Tvalue.valueP = | |||
1004 | (xmlrpc_value**) va_arg(argsP->v, xmlrpc_value**)__builtin_va_arg(argsP->v, xmlrpc_value**); | |||
1005 | break; | |||
1006 | ||||
1007 | case 'A': | |||
1008 | decompNodeP->store.TarrayVal.valueP = | |||
1009 | (xmlrpc_value**) va_arg(argsP->v, xmlrpc_value**)__builtin_va_arg(argsP->v, xmlrpc_value**); | |||
1010 | break; | |||
1011 | ||||
1012 | case 'S': | |||
1013 | decompNodeP->store.TstructVal.valueP = | |||
1014 | (xmlrpc_value**) va_arg(argsP->v, xmlrpc_value**)__builtin_va_arg(argsP->v, xmlrpc_value**); | |||
1015 | break; | |||
1016 | ||||
1017 | case '(': | |||
1018 | buildArrayDecompBranch(envP, formatP, ')', argsP, decompNodeP); | |||
1019 | ++(*formatP); /* skip past closing ')' */ | |||
1020 | break; | |||
1021 | ||||
1022 | case '{': | |||
1023 | buildStructDecompBranch(envP, formatP, '}', argsP, decompNodeP); | |||
1024 | ++(*formatP); /* skip past closing '}' */ | |||
1025 | break; | |||
1026 | ||||
1027 | default: | |||
1028 | xmlrpc_faultf(envP, "Invalid format character '%c'", | |||
1029 | decompNodeP->formatSpecChar); | |||
1030 | } | |||
1031 | if (envP->fault_occurred) | |||
1032 | free(decompNodeP); | |||
1033 | else | |||
1034 | *decompNodePP = decompNodeP; | |||
1035 | } | |||
1036 | } | |||
1037 | ||||
1038 | ||||
1039 | ||||
1040 | static void | |||
1041 | createDecompTree(xmlrpc_env * const envP, | |||
1042 | const char * const format, | |||
1043 | va_listx const args, | |||
1044 | struct decompTreeNode ** const decompRootPP) { | |||
1045 | ||||
1046 | const char * formatCursor; | |||
1047 | struct decompTreeNode * decompRootP; | |||
1048 | va_listx currentArgs; | |||
1049 | ||||
1050 | currentArgs = args; | |||
1051 | formatCursor = &format[0]; | |||
1052 | createDecompTreeNext(envP, &formatCursor, ¤tArgs, &decompRootP); | |||
1053 | if (!envP->fault_occurred) { | |||
1054 | if (*formatCursor != '\0') | |||
1055 | xmlrpc_faultf(envP, "format string '%s' has garbage at the end: " | |||
1056 | "'%s'. It should be a specifier of a single value " | |||
1057 | "(but that might be a complex value, such as an " | |||
1058 | "array)", format, formatCursor); | |||
1059 | ||||
1060 | if (envP->fault_occurred) | |||
1061 | destroyDecompTree(decompRootP); | |||
1062 | } | |||
1063 | *decompRootPP = decompRootP; | |||
1064 | } | |||
1065 | ||||
1066 | ||||
1067 | ||||
1068 | static void | |||
1069 | decomposeValue(xmlrpc_env * const envP, | |||
1070 | xmlrpc_value * const valueP, | |||
1071 | bool const oldstyleMemMgmt, | |||
1072 | const char * const format, | |||
1073 | va_listx const args) { | |||
1074 | ||||
1075 | struct decompTreeNode * decompRootP; | |||
1076 | ||||
1077 | 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/xmlrpc_decompose.c", 1077); while (0); | |||
1078 | XMLRPC_ASSERT_VALUE_OK(valueP)do if (!((valueP) != ((void*)0) && (valueP)->_type != XMLRPC_TYPE_DEAD)) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_decompose.c" , 1078); while (0); | |||
1079 | XMLRPC_ASSERT(format != NULL)do if (!(format != ((void*)0))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_decompose.c" , 1079); while (0); | |||
1080 | ||||
1081 | createDecompTree(envP, format, args, &decompRootP); | |||
1082 | ||||
1083 | if (!envP->fault_occurred) { | |||
1084 | decomposeValueWithTree(envP, valueP, oldstyleMemMgmt, decompRootP); | |||
1085 | ||||
1086 | destroyDecompTree(decompRootP); | |||
1087 | } | |||
1088 | } | |||
1089 | ||||
1090 | ||||
1091 | ||||
1092 | void | |||
1093 | xmlrpc_decompose_value_va(xmlrpc_env * const envP, | |||
1094 | xmlrpc_value * const valueP, | |||
1095 | const char * const format, | |||
1096 | va_list const args) { | |||
1097 | ||||
1098 | bool const oldstyleMemMgtFalse = false; | |||
1099 | va_listx argsx; | |||
1100 | ||||
1101 | init_va_listx(&argsx, args); | |||
1102 | ||||
1103 | decomposeValue(envP, valueP, oldstyleMemMgtFalse, format, argsx); | |||
1104 | } | |||
1105 | ||||
1106 | ||||
1107 | ||||
1108 | void | |||
1109 | xmlrpc_decompose_value(xmlrpc_env * const envP, | |||
1110 | xmlrpc_value * const value, | |||
1111 | const char * const format, | |||
1112 | ...) { | |||
1113 | ||||
1114 | va_list args; | |||
1115 | ||||
1116 | va_start(args, format)__builtin_va_start(args, format); | |||
1117 | xmlrpc_decompose_value_va(envP, value, format, args); | |||
1118 | va_end(args)__builtin_va_end(args); | |||
1119 | } | |||
1120 | ||||
1121 | ||||
1122 | ||||
1123 | void | |||
1124 | xmlrpc_parse_value_va(xmlrpc_env * const envP, | |||
1125 | xmlrpc_value * const valueP, | |||
1126 | const char * const format, | |||
1127 | va_list const args) { | |||
1128 | ||||
1129 | bool const oldstyleMemMgmtTrue = true; | |||
1130 | va_listx argsx; | |||
1131 | ||||
1132 | init_va_listx(&argsx, args); | |||
1133 | ||||
1134 | decomposeValue(envP, valueP, oldstyleMemMgmtTrue, format, argsx); | |||
1135 | } | |||
1136 | ||||
1137 | ||||
1138 | ||||
1139 | void | |||
1140 | xmlrpc_parse_value(xmlrpc_env * const envP, | |||
1141 | xmlrpc_value * const value, | |||
1142 | const char * const format, | |||
1143 | ...) { | |||
1144 | ||||
1145 | va_list args; | |||
1146 | ||||
1147 | va_start(args, format)__builtin_va_start(args, format); | |||
1148 | xmlrpc_parse_value_va(envP, value, format, args); | |||
| ||||
1149 | va_end(args)__builtin_va_end(args); | |||
1150 | } |