initial load of upstream version 1.06.32
[xmlrpc-c] / src / xmlrpc_builddecomp.c
1 /* Copyright information is at end of file */
2
3 #include "xmlrpc_config.h"
4
5 #include <stddef.h>
6 #include <stdlib.h>
7 #include <stdarg.h>
8 #include <string.h>
9
10 #include "bool.h"
11
12 #include "xmlrpc-c/base.h"
13 #include "xmlrpc-c/base_int.h"
14 #include "xmlrpc-c/string_int.h"
15
16 /* Borrowed from Python 1.5.2.
17 ** MPW pushes 'extended' for float and double types with varargs */
18 #ifdef MPW
19 typedef extended va_double;
20 #else
21 typedef double va_double;
22 #endif
23
24 /* Borrowed from Python 1.5.2.
25 ** Python copies its va_list objects before using them in certain
26 ** tricky fashions. We don't why Python does this, but since we're
27 ** abusing our va_list objects in a similar fashion, we'll copy them
28 ** too. */
29 #if VA_LIST_IS_ARRAY
30 #define VA_LIST_COPY(dest,src) memcpy((dest), (src), sizeof(va_list))
31 #else
32 #define VA_LIST_COPY(dest,src) ((dest) = (src))
33 #endif
34
35 /*=========================================================================
36 **  Creating XML-RPC values.
37 **=========================================================================
38 **  Build new XML-RPC values from a format string. This code is heavily
39 **  inspired by Py_BuildValue from Python 1.5.2. In particular, our
40 **  particular abuse of the va_list data type is copied from the equivalent
41 **  Python code in modsupport.c. Since Python is portable, our code should
42 **  (in theory) also be portable.
43 */
44
45
46 static void
47 getString(xmlrpc_env *    const envP,
48           const char **   const formatP,
49           va_list *       const args,
50           xmlrpc_value ** const valPP) {
51
52     const char * str;
53     unsigned int len;
54     
55     str = (const char*) va_arg(*args, char*);
56     if (**formatP == '#') {
57         (*formatP)++;
58         len = (size_t) va_arg(*args, size_t);
59     } else
60         len = strlen(str);
61
62     *valPP = xmlrpc_string_new_lp(envP, len, str);
63 }
64
65
66
67 #if HAVE_UNICODE_WCHAR
68 static void
69 mkWideString(xmlrpc_env *    const envP,
70              wchar_t *       const wcs,
71              size_t          const wcs_len,
72              xmlrpc_value ** const valPP) {
73
74     xmlrpc_value * valP;
75     char *contents;
76     wchar_t *wcs_contents;
77     int block_is_inited;
78     xmlrpc_mem_block *utf8_block;
79     char *utf8_contents;
80     size_t utf8_len;
81
82     /* Error-handling preconditions. */
83     valP = NULL;
84     utf8_block = NULL;
85     block_is_inited = 0;
86
87     /* Initialize our XML-RPC value. */
88     valP = (xmlrpc_value*) malloc(sizeof(xmlrpc_value));
89     XMLRPC_FAIL_IF_NULL(valP, envP, XMLRPC_INTERNAL_ERROR,
90                         "Could not allocate memory for wide string");
91     valP->_refcount = 1;
92     valP->_type = XMLRPC_TYPE_STRING;
93
94     /* More error-handling preconditions. */
95     valP->_wcs_block = NULL;
96
97     /* Build our wchar_t block first. */
98     valP->_wcs_block =
99         XMLRPC_TYPED_MEM_BLOCK_NEW(wchar_t, envP, wcs_len + 1);
100     XMLRPC_FAIL_IF_FAULT(envP);
101     wcs_contents =
102         XMLRPC_TYPED_MEM_BLOCK_CONTENTS(wchar_t, valP->_wcs_block);
103     memcpy(wcs_contents, wcs, wcs_len * sizeof(wchar_t));
104     wcs_contents[wcs_len] = '\0';
105     
106     /* Convert the wcs block to UTF-8. */
107     utf8_block = xmlrpc_wcs_to_utf8(envP, wcs_contents, wcs_len + 1);
108     XMLRPC_FAIL_IF_FAULT(envP);
109     utf8_contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, utf8_block);
110     utf8_len = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, utf8_block);
111
112     /* XXX - We need an extra memcopy to initialize _block. */
113     XMLRPC_TYPED_MEM_BLOCK_INIT(char, envP, &valP->_block, utf8_len);
114     XMLRPC_FAIL_IF_FAULT(envP);
115     block_is_inited = 1;
116     contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, &valP->_block);
117     memcpy(contents, utf8_contents, utf8_len);
118
119  cleanup:
120     if (utf8_block)
121         xmlrpc_mem_block_free(utf8_block);
122     if (envP->fault_occurred) {
123         if (valP) {
124             if (valP->_wcs_block)
125                 xmlrpc_mem_block_free(valP->_wcs_block);
126             if (block_is_inited)
127                 xmlrpc_mem_block_clean(&valP->_block);
128             free(valP);
129         }
130     }
131     *valPP = valP;
132 }
133 #endif /* HAVE_UNICODE_WCHAR */
134
135
136
137 static void
138 getWideString(xmlrpc_env *    const envP ATTR_UNUSED,
139               const char **   const formatP ATTR_UNUSED,
140               va_list *       const args ATTR_UNUSED,
141               xmlrpc_value ** const valPP ATTR_UNUSED) {
142
143 #if HAVE_UNICODE_WCHAR
144     wchar_t *wcs;
145     size_t len;
146     
147     wcs = (wchar_t*) va_arg(*args, wchar_t*);
148     if (**formatP == '#') {
149         (*formatP)++;
150         len = (size_t) va_arg(*args, size_t);
151     } else
152         len = wcslen(wcs);
153
154     mkWideString(envP, wcs, len, valPP);
155
156 #endif /* HAVE_UNICODE_WCHAR */
157 }
158
159
160
161 static void
162 getBase64(xmlrpc_env *    const envP,
163           va_list *       const args,
164           xmlrpc_value ** const valPP) {
165
166     unsigned char * value;
167     size_t          length;
168     
169     value  = (unsigned char*) va_arg(*args, unsigned char*);
170     length = (size_t)         va_arg(*args, size_t);
171
172     *valPP = xmlrpc_base64_new(envP, length, value);
173 }
174
175
176
177 static void
178 getValue(xmlrpc_env *    const envP, 
179          const char**    const format, 
180          va_list *             args,
181          xmlrpc_value ** const valPP);
182
183
184
185 static void
186 getArray(xmlrpc_env *    const envP,
187          const char **   const formatP,
188          char            const delimiter,
189          va_list *       const args,
190          xmlrpc_value ** const arrayPP) {
191
192     xmlrpc_value * arrayP;
193
194     arrayP = xmlrpc_array_new(envP);
195
196     /* Add items to the array until we hit our delimiter. */
197     
198     while (**formatP != delimiter && !envP->fault_occurred) {
199         
200         xmlrpc_value * itemP;
201         
202         if (**formatP == '\0')
203             xmlrpc_env_set_fault(
204                 envP, XMLRPC_INTERNAL_ERROR,
205                 "format string ended before closing ')'.");
206         else {
207             getValue(envP, formatP, args, &itemP);
208             if (!envP->fault_occurred) {
209                 xmlrpc_array_append_item(envP, arrayP, itemP);
210                 xmlrpc_DECREF(itemP);
211             }
212         }
213     }
214     if (envP->fault_occurred)
215         xmlrpc_DECREF(arrayP);
216
217     *arrayPP = arrayP;
218 }
219
220
221
222 static void
223 getStructMember(xmlrpc_env *    const envP,
224                 const char **   const formatP,
225                 va_list *       const args,
226                 xmlrpc_value ** const keyPP,
227                 xmlrpc_value ** const valuePP) {
228
229
230     /* Get the key */
231     getValue(envP, formatP, args, keyPP);
232     if (!envP->fault_occurred) {
233         if (**formatP != ':')
234             xmlrpc_env_set_fault(
235                 envP, XMLRPC_INTERNAL_ERROR,
236                 "format string does not have ':' after a "
237                 "structure member key.");
238         else {
239             /* Skip over colon that separates key from value */
240             (*formatP)++;
241             
242             /* Get the value */
243             getValue(envP, formatP, args, valuePP);
244         }
245         if (envP->fault_occurred)
246             xmlrpc_DECREF(*keyPP);
247     }
248 }
249             
250             
251
252 static void
253 getStruct(xmlrpc_env *    const envP,
254           const char **   const formatP,
255           char            const delimiter,
256           va_list *       const args,
257           xmlrpc_value ** const structPP) {
258
259     xmlrpc_value * structP;
260
261     structP = xmlrpc_struct_new(envP);
262     if (!envP->fault_occurred) {
263         while (**formatP != delimiter && !envP->fault_occurred) {
264             xmlrpc_value * keyP;
265             xmlrpc_value * valueP;
266             
267             getStructMember(envP, formatP, args, &keyP, &valueP);
268             
269             if (!envP->fault_occurred) {
270                 if (**formatP == ',')
271                     (*formatP)++;  /* Skip over the comma */
272                 else if (**formatP == delimiter) {
273                     /* End of the line */
274                 } else 
275                     xmlrpc_env_set_fault(
276                         envP, XMLRPC_INTERNAL_ERROR,
277                         "format string does not have ',' or ')' after "
278                         "a structure member");
279                 
280                 if (!envP->fault_occurred)
281                     /* Add the new member to the struct. */
282                     xmlrpc_struct_set_value_v(envP, structP, keyP, valueP);
283                 
284                 xmlrpc_DECREF(valueP);
285                 xmlrpc_DECREF(keyP);
286             }
287         }
288         if (envP->fault_occurred)
289             xmlrpc_DECREF(structP);
290     }
291     *structPP = structP;
292 }
293
294
295
296 static void
297 mkArrayFromVal(xmlrpc_env *    const envP, 
298                xmlrpc_value *  const value,
299                xmlrpc_value ** const valPP) {
300
301     if (xmlrpc_value_type(value) != XMLRPC_TYPE_ARRAY)
302         xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR,
303                              "Array format ('A'), non-array xmlrpc_value");
304     else
305         xmlrpc_INCREF(value);
306
307     *valPP = value;
308 }
309
310
311
312 static void
313 mkStructFromVal(xmlrpc_env *    const envP, 
314                 xmlrpc_value *  const value,
315                 xmlrpc_value ** const valPP) {
316
317     if (xmlrpc_value_type(value) != XMLRPC_TYPE_STRUCT)
318         xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR,
319                              "Struct format ('S'), non-struct xmlrpc_value");
320     else
321         xmlrpc_INCREF(value);
322
323     *valPP = value;
324 }
325
326
327
328 static void
329 getValue(xmlrpc_env *    const envP, 
330          const char**    const formatP,
331          va_list *       const args,
332          xmlrpc_value ** const valPP) {
333 /*----------------------------------------------------------------------------
334    Get the next value from the list.  *formatP points to the specifier
335    for the next value in the format string (i.e. to the type code
336    character) and we move *formatP past the whole specifier for the
337    next value.  We read the required arguments from 'args'.  We return
338    the value as *valPP with a reference to it.
339
340    For example, if *formatP points to the "i" in the string "sis",
341    we read one argument from 'args' and return as *valP an integer whose
342    value is the argument we read.  We advance *formatP to point to the
343    last 's' and advance 'args' to point to the argument that belongs to
344    that 's'.
345 -----------------------------------------------------------------------------*/
346     char const formatChar = *(*formatP)++;
347
348     switch (formatChar) {
349     case 'i':
350         *valPP = 
351             xmlrpc_int_new(envP, (xmlrpc_int32) va_arg(*args, xmlrpc_int32));
352         break;
353
354     case 'b':
355         *valPP = 
356             xmlrpc_bool_new(envP, (xmlrpc_bool) va_arg(*args, xmlrpc_bool));
357         break;
358
359     case 'd':
360         *valPP =
361             xmlrpc_double_new(envP, (double) va_arg(*args, va_double));
362         break;
363
364     case 's':
365         getString(envP, formatP, args, valPP);
366         break;
367
368     case 'w':
369         getWideString(envP, formatP, args, valPP);
370         break;
371
372     /* The code 't' is reserved for a better, time_t based
373        implementation of dateTime conversion.  
374     */
375     case '8':
376         *valPP = 
377             xmlrpc_datetime_new_str(envP, (char*) va_arg(*args, char*));
378         break;
379
380     case '6':
381         getBase64(envP, args, valPP);
382         break;
383
384     case 'n':
385         *valPP =
386             xmlrpc_nil_new(envP);
387         break;      
388
389     case 'p':
390         /* We might someday want to use the code 'p!' to read in a
391            cleanup function for this pointer. 
392         */
393         *valPP = 
394             xmlrpc_cptr_new(envP, (void*) va_arg(*args, void*));
395         break;      
396
397     case 'A':
398         mkArrayFromVal(envP, (xmlrpc_value*) va_arg(*args, xmlrpc_value*),
399                        valPP);
400         break;
401
402     case 'S':
403         mkStructFromVal(envP, (xmlrpc_value*) va_arg(*args, xmlrpc_value*),
404                         valPP);
405         break;
406
407     case 'V':
408         *valPP = (xmlrpc_value*) va_arg(*args, xmlrpc_value*);
409         xmlrpc_INCREF(*valPP);
410         break;
411
412     case '(':
413         getArray(envP, formatP, ')', args, valPP);
414         if (!envP->fault_occurred) {
415             XMLRPC_ASSERT(**formatP == ')');
416             (*formatP)++;  /* Skip over closing parenthesis */
417         }
418         break;
419
420     case '{': 
421         getStruct(envP, formatP, '}', args, valPP);
422         if (!envP->fault_occurred) {
423             XMLRPC_ASSERT(**formatP == '}');
424             (*formatP)++;  /* Skip over closing brace */
425         }
426         break;
427
428     default: {
429         const char * const badCharacter = xmlrpc_makePrintableChar(formatChar);
430         xmlrpc_env_set_fault_formatted(
431             envP, XMLRPC_INTERNAL_ERROR,
432             "Unexpected character '%s' in format string", badCharacter);
433         xmlrpc_strfree(badCharacter);
434         }
435     }
436 }
437
438
439
440 void
441 xmlrpc_build_value_va(xmlrpc_env *    const envP,
442                       const char *    const format,
443                       va_list               args,
444                       xmlrpc_value ** const valPP,
445                       const char **   const tailP) {
446
447     const char * formatCursor;
448     va_list args_copy;
449
450     XMLRPC_ASSERT_ENV_OK(envP);
451     XMLRPC_ASSERT(format != NULL);
452
453     if (strlen(format) == 0)
454         xmlrpc_env_set_fault_formatted(
455             envP, XMLRPC_INTERNAL_ERROR, "Format string is empty.");
456     else {
457         formatCursor = &format[0];
458         VA_LIST_COPY(args_copy, args);
459         getValue(envP, &formatCursor, &args_copy, valPP);
460         
461         if (!envP->fault_occurred)
462             XMLRPC_ASSERT_VALUE_OK(*valPP);
463         
464         *tailP = formatCursor;
465     }
466 }
467
468
469
470 xmlrpc_value * 
471 xmlrpc_build_value(xmlrpc_env * const envP,
472                    const char * const format, 
473                    ...) {
474
475     va_list args;
476     xmlrpc_value* retval;
477     const char * suffix;
478
479     va_start(args, format);
480     xmlrpc_build_value_va(envP, format, args, &retval, &suffix);
481     va_end(args);
482
483     if (!envP->fault_occurred) {
484         if (*suffix != '\0')
485             xmlrpc_env_set_fault_formatted(
486                 envP, XMLRPC_INTERNAL_ERROR, "Junk after the argument "
487                 "specifier: '%s'.  There must be exactly one arument.",
488                 suffix);
489     
490         if (envP->fault_occurred)
491             xmlrpc_DECREF(retval);
492     }
493     return retval;
494 }
495
496
497
498
499
500 /*=========================================================================
501 **  Parsing XML-RPC values.
502 **=========================================================================
503 **  Parse an XML-RPC value based on a format string. This code is heavily
504 **  inspired by Py_BuildValue from Python 1.5.2.
505 */
506
507 /* Prototype for recursive invocation: */
508
509 static void 
510 decomposeValue(xmlrpc_env *   const env,
511                xmlrpc_value * const val,
512                const char **  const format,
513                va_list *            args,
514                xmlrpc_bool    const oldstyleMemMgmt);
515
516
517
518 static void 
519 parsearray(xmlrpc_env *         const env,
520            const xmlrpc_value * const array,
521            const char **        const format,
522            char                 const delimiter,
523            va_list *                  args,
524            xmlrpc_bool          const oldstyleMemMgmt) {
525
526     int size, i;
527     xmlrpc_value *item;
528
529     /* Fetch the array size. */
530     size = xmlrpc_array_size(env, array);
531     XMLRPC_FAIL_IF_FAULT(env);
532
533     /* Loop over the items in the array. */
534     for (i = 0; i < size; i++) {
535         /* Bail out if the caller didn't care about the rest of the items. */
536         if (**format == '*')
537             break;
538
539         item = xmlrpc_array_get_item(env, array, i);
540         XMLRPC_FAIL_IF_FAULT(env);
541
542         XMLRPC_ASSERT(**format != '\0');
543         if (**format == delimiter)
544             XMLRPC_FAIL(env, XMLRPC_INDEX_ERROR, "Too many items in array");
545         decomposeValue(env, item, format, args, oldstyleMemMgmt);
546         XMLRPC_FAIL_IF_FAULT(env);
547     }
548     if (**format == '*')
549         (*format)++;
550     if (**format != delimiter)
551         XMLRPC_FAIL(env, XMLRPC_INDEX_ERROR, "Not enough items in array");
552
553            cleanup:
554     return;
555 }
556
557
558
559 static void 
560 parsestruct(xmlrpc_env *   const env,
561             xmlrpc_value * const strct,
562             const char **  const format,
563             char           const delimiter,
564             va_list *            args,
565             xmlrpc_bool    const oldstyleMemMgmt) {
566
567     xmlrpc_value *key, *value;
568     char *keystr;
569     size_t keylen;
570
571     /* Set up error handling preconditions. */
572     key = NULL;
573
574     /* Build the members of our struct. */
575     while (**format != '*' && **format != delimiter && **format != '\0') {
576
577         /* Get our key, and skip over the ':' character. Notice the
578         ** sudden call to getValue--we're going in the opposite direction. */
579         getValue(env, format, args, &key);
580         XMLRPC_FAIL_IF_FAULT(env);
581         XMLRPC_ASSERT(**format == ':');
582         (*format)++;
583
584         /* Look up the value for our key. */
585         xmlrpc_parse_value(env, key, "s#", &keystr, &keylen);
586         XMLRPC_FAIL_IF_FAULT(env);
587         value = xmlrpc_struct_get_value_n(env, strct, keystr, keylen);
588         XMLRPC_FAIL_IF_FAULT(env);
589
590         /* Get our value, and skip over the ',' character (if present). */
591         decomposeValue(env, value, format, args, oldstyleMemMgmt);
592         XMLRPC_FAIL_IF_FAULT(env);
593         XMLRPC_ASSERT(**format == ',' || **format == delimiter);
594         if (**format == ',')
595             (*format)++;
596
597         /* Release our reference, and restore our invariant. */
598         xmlrpc_DECREF(key);
599         key = NULL;
600     }
601     if (**format == '*') {
602         (*format)++;
603         if (**format != delimiter && **format != '\0')
604             XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, 
605                         "* can appear only at the end "
606                         "of a structure format specifier");
607     } else {
608         /* Here we're supposed to fail if he didn't extract all the
609            members.  But we don't know how to determine whether he
610            specified all the members, so we always fail.
611         */
612         XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "You must specify '*' as the "
613                     "last member of a structure in a format specifier "
614                     "used for parsing an xmlrpc_value"); 
615     }
616     XMLRPC_ASSERT(**format == delimiter || **format == '\0');
617
618 cleanup:
619     if (key)
620         xmlrpc_DECREF(key);
621 }
622
623
624 static void
625 readString(xmlrpc_env *         const envP,
626            const xmlrpc_value * const valueP,
627            const char **        const stringValueP,
628            xmlrpc_bool          const oldstyleMemMgmt) {
629
630     if (oldstyleMemMgmt) {
631         xmlrpc_read_string_old(envP, valueP, stringValueP);
632     } else
633         xmlrpc_read_string(envP, valueP, stringValueP);
634 }
635
636
637
638 static void
639 readStringLp(xmlrpc_env *         const envP,
640              const xmlrpc_value * const valueP,
641              size_t *             const lengthP,
642              const char **        const stringValueP,
643              xmlrpc_bool          const oldstyleMemMgmt) {
644
645     if (oldstyleMemMgmt) {
646         xmlrpc_read_string_lp_old(envP, valueP, lengthP, stringValueP);
647     } else
648         xmlrpc_read_string_lp(envP, valueP, lengthP, stringValueP);
649 }
650
651
652
653 #if HAVE_UNICODE_WCHAR
654 static void
655 readStringW(xmlrpc_env *     const envP,
656             xmlrpc_value *   const valueP,
657             const wchar_t ** const stringValueP,
658             xmlrpc_bool      const oldstyleMemMgmt) {
659
660     if (oldstyleMemMgmt) {
661         xmlrpc_read_string_w_old(envP, valueP, stringValueP);
662     } else
663         xmlrpc_read_string_w(envP, valueP, stringValueP);
664 }
665
666
667
668 static void
669 readStringWLp(xmlrpc_env *     const envP,
670               xmlrpc_value *   const valueP,
671               size_t *         const lengthP,
672               const wchar_t ** const stringValueP,
673               xmlrpc_bool      const oldstyleMemMgmt) {
674
675     if (oldstyleMemMgmt) {
676         xmlrpc_read_string_w_lp_old(envP, valueP, lengthP, stringValueP);
677     } else
678         xmlrpc_read_string_w_lp(envP, valueP, lengthP, stringValueP);
679 }
680 #endif
681
682
683 static void
684 readDatetimeStr(xmlrpc_env *         const envP,
685                 const xmlrpc_value * const valueP,
686                 const char **        const stringValueP,
687                 xmlrpc_bool          const oldstyleMemMgmt) {
688
689     if (oldstyleMemMgmt)
690         xmlrpc_read_datetime_str_old(envP, valueP, stringValueP);
691     else
692         xmlrpc_read_datetime_str(envP, valueP, stringValueP);
693 }
694
695
696
697 static void
698 readBase64(xmlrpc_env *           const envP,
699            const xmlrpc_value *   const valueP,
700            size_t *               const lengthP,
701            const unsigned char ** const byteStringValueP,
702            xmlrpc_bool            const oldstyleMemMgmt) {
703
704     if (oldstyleMemMgmt)
705         xmlrpc_read_base64_old(envP, valueP, lengthP, byteStringValueP);
706     else
707         xmlrpc_read_base64(envP, valueP, lengthP, byteStringValueP);
708 }
709
710
711
712 static void 
713 decomposeValue(xmlrpc_env *   const envP,
714                xmlrpc_value * const valueP,
715                const char **  const format,
716                va_list *            args,
717                xmlrpc_bool    const oldstyleMemMgmt) {
718
719     char formatSpecChar;
720
721     formatSpecChar = *(*format)++;
722
723     switch (formatSpecChar) {
724     case 'i': {
725         xmlrpc_int32 * const int32ptr = 
726             (xmlrpc_int32*) va_arg(*args, xmlrpc_int32*);
727         xmlrpc_read_int(envP, valueP, int32ptr);
728         }
729     break;
730
731     case 'b': {
732         xmlrpc_bool * const boolptr =
733             (xmlrpc_bool*) va_arg(*args, xmlrpc_bool*);
734         xmlrpc_read_bool(envP, valueP, boolptr);
735     }
736     break;
737
738     case 'd': {
739         double * const doubleptr = (double*) va_arg(*args, double*);
740         xmlrpc_read_double(envP, valueP, doubleptr);
741     }
742     break;
743
744     case '8': {
745         /* The code 't' is reserved for a better, time_t based
746            implementation of dateTime conversion. 
747         */
748         const char ** const strptr = (const char**) va_arg(*args, char**);
749         readDatetimeStr(envP, valueP, strptr, oldstyleMemMgmt);
750     }
751     break;
752
753     case 's': {
754         const char ** const strptr = (const char**) va_arg(*args, char**);
755         if (**format == '#') {
756             size_t * const sizeptr = (size_t*) va_arg(*args, size_t**);
757             (*format)++;
758
759             readStringLp(envP, valueP, sizeptr, strptr, oldstyleMemMgmt);
760         } else
761             readString(envP, valueP, strptr, oldstyleMemMgmt);
762     }
763     break;
764
765     case 'w': {
766 #if HAVE_UNICODE_WCHAR
767         const wchar_t ** const wcsptr = 
768             (const wchar_t**) va_arg(*args, wchar_t**);
769         if (**format == '#') {
770             size_t * const sizeptr = (size_t*) va_arg(*args, size_t**);
771             (*format)++;
772             readStringWLp(envP, valueP, sizeptr, wcsptr, oldstyleMemMgmt);
773         } else
774             readStringW(envP, valueP, wcsptr, oldstyleMemMgmt);
775 #else
776         xmlrpc_env_set_fault_formatted(
777             envP, XMLRPC_INTERNAL_ERROR,
778             "This XML-RPC For C/C++ library was built without Unicode "
779             "wide character capability.  'w' isn't available.");
780 #endif /* HAVE_UNICODE_WCHAR */
781     }
782     break;
783         
784     case '6': {
785         const unsigned char ** const binptr =
786             (const unsigned char**) va_arg(*args, unsigned char**);
787         size_t * const sizeptr = (size_t*) va_arg(*args, size_t**);        
788         readBase64(envP, valueP, sizeptr, binptr, oldstyleMemMgmt);
789     }
790     break;
791
792     case 'n': {
793         xmlrpc_read_nil(envP, valueP);
794     }
795     break;
796
797     case 'p': {
798         void ** const voidptrptr = (void**) va_arg(*args, void**);
799         xmlrpc_read_cptr(envP, valueP, voidptrptr);
800     }
801     break;
802
803     case 'V': {
804         xmlrpc_value ** const valptr =
805             (xmlrpc_value**) va_arg(*args, xmlrpc_value**);
806         *valptr = valueP;
807         if (!oldstyleMemMgmt)
808             xmlrpc_INCREF(valueP);
809     }
810     break;
811
812     case 'A':
813         if (xmlrpc_value_type(valueP) != XMLRPC_TYPE_ARRAY)
814             xmlrpc_env_set_fault_formatted(
815                 envP, XMLRPC_TYPE_ERROR, "Non-array type supplied for "
816                 "'A' specifier");
817         else {
818             xmlrpc_value ** const valptr =
819                 (xmlrpc_value**) va_arg(*args, xmlrpc_value**);
820             *valptr = valueP;
821             if (!oldstyleMemMgmt)
822                 xmlrpc_INCREF(valueP);
823         }
824         break;
825
826     case 'S':
827         if (xmlrpc_value_type(valueP) != XMLRPC_TYPE_STRUCT)
828             xmlrpc_env_set_fault_formatted(
829                 envP, XMLRPC_TYPE_ERROR, "Non-struct type supplied for "
830                 "'S' specifier");
831         else {
832             xmlrpc_value ** const valptr =
833                 (xmlrpc_value**) va_arg(*args, xmlrpc_value**);
834             *valptr = valueP;
835             if (!oldstyleMemMgmt)
836                 xmlrpc_INCREF(valueP);
837         }
838         break;
839
840     case '(':
841         if (xmlrpc_value_type(valueP) != XMLRPC_TYPE_ARRAY)
842             xmlrpc_env_set_fault_formatted(
843                 envP, XMLRPC_TYPE_ERROR, "Non-array type supplied for "
844                 "'()' specifier");
845         else {
846             parsearray(envP, valueP, format, ')', args, oldstyleMemMgmt);
847             (*format)++;
848         }
849         break;
850
851     case '{':
852         if (xmlrpc_value_type(valueP) != XMLRPC_TYPE_STRUCT)
853             xmlrpc_env_set_fault_formatted(
854                 envP, XMLRPC_TYPE_ERROR, "Non-struct type supplied for "
855                 "'{}' specifier");
856         else {
857             parsestruct(envP, valueP, format, '}', args, oldstyleMemMgmt);
858             (*format)++;
859         }
860         break;
861
862     default:
863         xmlrpc_env_set_fault_formatted(
864             envP, XMLRPC_INTERNAL_ERROR, "Invalid format character '%c'",
865             formatSpecChar);
866     }
867 }
868
869
870
871 void 
872 xmlrpc_decompose_value_va(xmlrpc_env *   const envP,
873                           xmlrpc_value * const value,
874                           const char *   const format,
875                           va_list              args) {
876
877     const char *format_copy;
878     va_list args_copy;
879
880     XMLRPC_ASSERT_ENV_OK(envP);
881     XMLRPC_ASSERT_VALUE_OK(value);
882     XMLRPC_ASSERT(format != NULL);
883
884     format_copy = format;
885     VA_LIST_COPY(args_copy, args);
886     decomposeValue(envP, value, &format_copy, &args_copy, false);
887     if (!envP->fault_occurred) {
888         XMLRPC_ASSERT(*format_copy == '\0');
889     }
890 }
891
892
893
894 void 
895 xmlrpc_decompose_value(xmlrpc_env *   const envP,
896                        xmlrpc_value * const value,
897                        const char *   const format, 
898                        ...) {
899
900     va_list args;
901
902     va_start(args, format);
903     xmlrpc_decompose_value_va(envP, value, format, args);
904     va_end(args);
905 }
906
907
908
909 void 
910 xmlrpc_parse_value_va(xmlrpc_env *   const envP,
911                       xmlrpc_value * const value,
912                       const char *   const format,
913                       va_list              args) {
914
915     const char *format_copy;
916     va_list args_copy;
917
918     XMLRPC_ASSERT_ENV_OK(envP);
919     XMLRPC_ASSERT_VALUE_OK(value);
920     XMLRPC_ASSERT(format != NULL);
921
922     format_copy = format;
923     VA_LIST_COPY(args_copy, args);
924     decomposeValue(envP, value, &format_copy, &args_copy, true);
925     if (!envP->fault_occurred) {
926         XMLRPC_ASSERT(*format_copy == '\0');
927     }
928 }
929
930
931
932 void 
933 xmlrpc_parse_value(xmlrpc_env *   const envP,
934                    xmlrpc_value * const value,
935                    const char *   const format, 
936                    ...) {
937
938     va_list args;
939
940     va_start(args, format);
941     xmlrpc_parse_value_va(envP, value, format, args);
942     va_end(args);
943 }
944
945
946
947 /* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
948 ** Copyright (C) 2001 by Eric Kidd. All rights reserved.
949 **
950 ** Redistribution and use in source and binary forms, with or without
951 ** modification, are permitted provided that the following conditions
952 ** are met:
953 ** 1. Redistributions of source code must retain the above copyright
954 **    notice, this list of conditions and the following disclaimer.
955 ** 2. Redistributions in binary form must reproduce the above copyright
956 **    notice, this list of conditions and the following disclaimer in the
957 **    documentation and/or other materials provided with the distribution.
958 ** 3. The name of the author may not be used to endorse or promote products
959 **    derived from this software without specific prior written permission. 
960 **  
961 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
962 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
963 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
964 ** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
965 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
966 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
967 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
968 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
969 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
970 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
971 ** SUCH DAMAGE. */