Bug Summary

File:src/mod/xml_int/mod_xml_rpc/../../../../libs/xmlrpc-c/src/xmlrpc_decompose.c
Location:line 1063, column 19
Description:Assigned value is garbage or undefined

Annotated Source Code

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
55struct integerDecomp {
56 xmlrpc_int32 * valueP;
57};
58
59struct boolDecomp {
60 xmlrpc_bool * valueP;
61};
62
63struct doubleDecomp {
64 double * valueP;
65};
66
67struct datetimeTDecomp {
68 time_t * valueP;
69};
70
71struct datetime8Decomp {
72 const char ** valueP;
73};
74
75struct stringDecomp {
76 const char ** valueP;
77 size_t * sizeP;
78 /* NULL means don't store a size */
79};
80
81struct 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
89struct bitStringDecomp {
90 const unsigned char ** valueP;
91 size_t * sizeP;
92};
93
94struct cptrDecomp {
95 void ** valueP;
96};
97
98struct i8Decomp {
99 xmlrpc_int64 * valueP;
100};
101
102struct valueDecomp {
103 xmlrpc_value ** valueP;
104};
105
106struct arrayValDecomp {
107 xmlrpc_value ** valueP;
108};
109
110struct structValDecomp {
111 xmlrpc_value ** valueP;
112};
113
114struct 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
125struct 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
132struct structDecomp {
133 unsigned int mbrCnt;
134 struct mbrDecomp mbrArray[16];
135};
136
137
138struct 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 */
167static void
168releaseDecomposition(const struct decompTreeNode * const decompRootP,
169 bool const oldstyleMemMgmt);
170
171
172static void
173releaseDecompArray(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
183static void
184releaseDecompStruct(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
196static void
197releaseDecomposition(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
251static void
252decomposeValueWithTree(xmlrpc_env * const envP,
253 xmlrpc_value * const valueP,
254 bool const oldstyleMemMgmt,
255 const struct decompTreeNode * const decompRootP);
256
257
258
259static void
260validateArraySize(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
284static void
285parsearray(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
324static void
325parsestruct(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
363static void
364readString(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
377static void
378readStringLp(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
393static void
394readStringW(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
407static void
408readStringWLp(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
422static void
423readDatetime8Str(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
436static void
437readBase64(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
450static void
451decomposeValueWithTree(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
598static void
599createDecompTreeNext(xmlrpc_env * const envP,
600 const char ** const formatP,
601 va_listx * const argsP,
602 struct decompTreeNode ** const decompNodePP);
603
604
605
606static void
607buildWideStringNode(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
630static void
631destroyDecompTree(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
652static void
653processArraySpecTail(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
681static void
682buildArrayDecompBranch(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
741static void
742doStructValue(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
759static void
760skipAsterisk(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
785static void
786skipColon(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
803static void
804skipComma(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
819static void
820buildStructDecompBranch(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
899static void
900createDecompTreeNext(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))
6
Assuming 'decompNodeP' is equal to null
7
Taking true branch
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
1040static void
1041createDecompTree(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;
4
'decompRootP' declared without an initial value
1048 va_listx currentArgs;
1049
1050 currentArgs = args;
1051 formatCursor = &format[0];
1052 createDecompTreeNext(envP, &formatCursor, &currentArgs, &decompRootP);
5
Calling 'createDecompTreeNext'
8
Returning from 'createDecompTreeNext'
1053 if (!envP->fault_occurred) {
9
Taking false branch
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;
10
Assigned value is garbage or undefined
1064}
1065
1066
1067
1068static void
1069decomposeValue(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);
3
Calling 'createDecompTree'
1082
1083 if (!envP->fault_occurred) {
1084 decomposeValueWithTree(envP, valueP, oldstyleMemMgmt, decompRootP);
1085
1086 destroyDecompTree(decompRootP);
1087 }
1088}
1089
1090
1091
1092void
1093xmlrpc_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
1108void
1109xmlrpc_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
1123void
1124xmlrpc_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);
2
Calling 'decomposeValue'
1135}
1136
1137
1138
1139void
1140xmlrpc_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);
1
Calling 'xmlrpc_parse_value_va'
1149 va_end(args)__builtin_va_end(args);
1150}