Resync
[CMakeLuaTailorHgBridge.git] / CMakeLua / Utilities / cmxmlrpc / xmlrpc_data.c
blob456d8e487977cd39024bac7a3eeed42716f3a643
1 /* Copyright information is at end of file */
3 #include "xmlrpc_config.h"
5 #include <stddef.h>
6 #include <stdlib.h>
7 #include <stdarg.h>
8 #include <string.h>
10 #include "bool.h"
11 #include "xmlrpc.h"
12 #include "xmlrpc_int.h"
14 /* Borrowed from Python 1.5.2.
15 ** MPW pushes 'extended' for float and double types with varargs */
16 #ifdef MPW
17 typedef extended va_double;
18 #else
19 typedef double va_double;
20 #endif
22 /* Borrowed from Python 1.5.2.
23 ** Python copies its va_list objects before using them in certain
24 ** tricky fashions. We don't why Python does this, but since we're
25 ** abusing our va_list objects in a similar fashion, we'll copy them
26 ** too. */
27 #ifdef HAS_VA_COPY
28 # define VA_LIST_COPY(dest,src) va_copy((dest), (src))
29 #else
30 # if VA_LIST_IS_ARRAY
31 # define VA_LIST_COPY(dest,src) memcpy((dest), (src), sizeof(va_list))
32 # else
33 # define VA_LIST_COPY(dest,src) ((dest) = (src))
34 # endif
35 #endif
38 static void
39 destroyValue(xmlrpc_value * const valueP) {
41 /* First, we need to destroy this value's contents, if any. */
42 switch (valueP->_type) {
43 case XMLRPC_TYPE_INT:
44 case XMLRPC_TYPE_BOOL:
45 case XMLRPC_TYPE_DOUBLE:
46 break;
48 case XMLRPC_TYPE_ARRAY:
49 xmlrpc_destroyArrayContents(valueP);
50 break;
52 case XMLRPC_TYPE_STRING:
53 #ifdef HAVE_UNICODE_WCHAR
54 if (valueP->_wcs_block)
55 xmlrpc_mem_block_free(valueP->_wcs_block);
56 #endif /* HAVE_UNICODE_WCHAR */
57 /* Fall through. */
59 case XMLRPC_TYPE_DATETIME:
60 case XMLRPC_TYPE_BASE64:
61 xmlrpc_mem_block_clean(&valueP->_block);
62 break;
64 case XMLRPC_TYPE_STRUCT:
65 xmlrpc_destroyStruct(valueP);
66 break;
68 case XMLRPC_TYPE_C_PTR:
69 break;
71 case XMLRPC_TYPE_DEAD:
72 XMLRPC_ASSERT(FALSE); /* Can't happen, per entry conditions */
74 default:
75 XMLRPC_ASSERT(FALSE); /* There are no other possible values */
78 /* Next, we mark this value as invalid, to help catch refcount
79 ** errors. */
80 valueP->_type = XMLRPC_TYPE_DEAD;
82 /* Finally, we destroy the value itself. */
83 free(valueP);
88 /*=========================================================================
89 ** Reference Counting
90 **=========================================================================
91 ** Some simple reference-counting code. The xmlrpc_DECREF routine is in
92 ** charge of destroying values when their reference count equals zero.
95 void
96 xmlrpc_INCREF (xmlrpc_value * const valueP) {
98 XMLRPC_ASSERT_VALUE_OK(valueP);
99 XMLRPC_ASSERT(valueP->_refcount > 0);
101 valueP->_refcount++;
106 void
107 xmlrpc_DECREF (xmlrpc_value * const valueP) {
109 XMLRPC_ASSERT_VALUE_OK(valueP);
110 XMLRPC_ASSERT(valueP->_refcount > 0);
111 XMLRPC_ASSERT(valueP->_type != XMLRPC_TYPE_DEAD);
113 valueP->_refcount--;
115 /* If we have no more refs, we need to deallocate this value. */
116 if (valueP->_refcount == 0)
117 destroyValue(valueP);
122 /*=========================================================================
123 Utiltiies
124 =========================================================================*/
126 static const char *
127 typeName(xmlrpc_type const type) {
129 switch(type) {
131 case XMLRPC_TYPE_INT: return "INT";
132 case XMLRPC_TYPE_BOOL: return "BOOL";
133 case XMLRPC_TYPE_DOUBLE: return "DOUBLE";
134 case XMLRPC_TYPE_DATETIME: return "DATETIME";
135 case XMLRPC_TYPE_STRING: return "STRING";
136 case XMLRPC_TYPE_BASE64: return "BASE64";
137 case XMLRPC_TYPE_ARRAY: return "ARRAY";
138 case XMLRPC_TYPE_STRUCT: return "STRUCT";
139 case XMLRPC_TYPE_C_PTR: return "C_PTR";
140 case XMLRPC_TYPE_DEAD: return "DEAD";
141 default: return "???";
147 static void
148 verifyNoNulls(xmlrpc_env * const envP,
149 const char * const contents,
150 unsigned int const len) {
151 /*----------------------------------------------------------------------------
152 Verify that the character array 'contents', which is 'len' bytes long,
153 does not contain any NUL characters, which means it can be made into
154 a passable ASCIIZ string just by adding a terminating NUL.
156 Fail if the array contains a NUL.
157 -----------------------------------------------------------------------------*/
158 unsigned int i;
160 for (i = 0; i < len && !envP->fault_occurred; i++)
161 if (contents[i] == '\0')
162 xmlrpc_env_set_fault_formatted(
163 envP, XMLRPC_TYPE_ERROR,
164 "String must not contain NUL characters");
169 static void
170 verifyNoNullsW(xmlrpc_env * const envP,
171 const wchar_t * const contents,
172 unsigned int const len) {
173 /*----------------------------------------------------------------------------
174 Same as verifyNoNulls(), but for wide characters.
175 -----------------------------------------------------------------------------*/
176 unsigned int i;
178 for (i = 0; i < len && !envP->fault_occurred; i++)
179 if (contents[i] == '\0')
180 xmlrpc_env_set_fault_formatted(
181 envP, XMLRPC_TYPE_ERROR,
182 "String must not contain NUL characters");
187 static void
188 validateType(xmlrpc_env * const envP,
189 const xmlrpc_value * const valueP,
190 xmlrpc_type const expectedType) {
192 if (valueP->_type != expectedType) {
193 xmlrpc_env_set_fault_formatted(
194 envP, XMLRPC_TYPE_ERROR, "Value of type %s supplied where "
195 "type %s was expected.",
196 typeName(valueP->_type), typeName(expectedType));
202 /*=========================================================================
203 Extracting XML-RPC value
204 ===========================================================================
205 These routines extract XML-RPC values into ordinary C data types.
207 For array and struct values, see the separates files xmlrpc_array.c
208 and xmlrpc_struct.c.
209 =========================================================================*/
211 void
212 xmlrpc_read_int(xmlrpc_env * const envP,
213 const xmlrpc_value * const valueP,
214 xmlrpc_int32 * const intValueP) {
216 validateType(envP, valueP, XMLRPC_TYPE_INT);
217 if (!envP->fault_occurred)
218 *intValueP = valueP->_value.i;
223 void
224 xmlrpc_read_double(xmlrpc_env * const envP,
225 const xmlrpc_value * const valueP,
226 xmlrpc_double * const doubleValueP) {
228 validateType(envP, valueP, XMLRPC_TYPE_DOUBLE);
229 if (!envP->fault_occurred)
230 *doubleValueP = valueP->_value.d;
236 void
237 xmlrpc_read_bool(xmlrpc_env * const envP,
238 const xmlrpc_value * const valueP,
239 xmlrpc_bool * const boolValueP) {
241 validateType(envP, valueP, XMLRPC_TYPE_BOOL);
242 if (!envP->fault_occurred)
243 *boolValueP = valueP->_value.b;
248 void
249 xmlrpc_read_string(xmlrpc_env * const envP,
250 const xmlrpc_value * const valueP,
251 const char ** const stringValueP) {
252 /*----------------------------------------------------------------------------
253 Read the value of an XML-RPC string an ASCIIZ string.
255 Fail if the string contains null characters (which means it wasn't
256 really a string, but XML-RPC doesn't seem to understand what a string
257 is, and such values are possible).
258 -----------------------------------------------------------------------------*/
259 validateType(envP, valueP, XMLRPC_TYPE_STRING);
260 if (!envP->fault_occurred) {
261 size_t const size =
262 XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block);
263 const char * const contents =
264 XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block);
266 verifyNoNulls(envP, contents, (unsigned int)size);
267 if (!envP->fault_occurred) {
268 char * stringValue;
270 stringValue = malloc(size+1);
271 if (stringValue == NULL)
272 xmlrpc_env_set_fault_formatted(
273 envP, XMLRPC_INTERNAL_ERROR, "Unable to allocate space "
274 "for %u-character string", size);
275 else {
276 memcpy(stringValue,
277 XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block), size);
278 stringValue[size] = '\0';
280 *stringValueP = stringValue;
288 void
289 xmlrpc_read_string_lp(xmlrpc_env * const envP,
290 const xmlrpc_value * const valueP,
291 unsigned int * const lengthP,
292 const char ** const stringValueP) {
294 validateType(envP, valueP, XMLRPC_TYPE_STRING);
295 if (!envP->fault_occurred) {
296 size_t const size =
297 XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block);
298 const char * const contents =
299 XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block);
301 char * stringValue;
303 stringValue = malloc(size);
304 if (stringValue == NULL)
305 xmlrpc_env_set_fault_formatted(
306 envP, XMLRPC_INTERNAL_ERROR, "Unable to allocate %u bytes "
307 "for string.", size);
308 else {
309 memcpy(stringValue, contents, size);
310 *stringValueP = stringValue;
311 *lengthP = (unsigned int)size;
318 /*=========================================================================
319 ** Building XML-RPC values.
320 **=========================================================================
321 ** Build new XML-RPC values from a format string. This code is heavily
322 ** inspired by Py_BuildValue from Python 1.5.2. In particular, our
323 ** particular abuse of the va_list data type is copied from the equivalent
324 ** Python code in modsupport.c. Since Python is portable, our code should
325 ** (in theory) also be portable.
329 xmlrpc_type xmlrpc_value_type (xmlrpc_value* value)
331 XMLRPC_ASSERT_VALUE_OK(value);
332 return value->_type;
337 static void
338 createXmlrpcValue(xmlrpc_env * const envP,
339 xmlrpc_value ** const valPP) {
340 /*----------------------------------------------------------------------------
341 Create a blank xmlrpc_value to be filled in.
343 Set the reference count to 1.
344 -----------------------------------------------------------------------------*/
345 xmlrpc_value * valP;
347 valP = (xmlrpc_value*) malloc(sizeof(xmlrpc_value));
348 if (!valP)
349 xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR,
350 "Could not allocate memory for xmlrpc_value");
351 else
352 valP->_refcount = 1;
354 *valPP = valP;
359 static void
360 mkInt(xmlrpc_env * const envP,
361 xmlrpc_int32 const value,
362 xmlrpc_value ** const valPP) {
364 xmlrpc_value * valP;
366 createXmlrpcValue(envP, &valP);
368 if (!envP->fault_occurred) {
369 valP->_type = XMLRPC_TYPE_INT;
370 valP->_value.i = value;
372 *valPP = valP;
377 static void
378 mkBool(xmlrpc_env * const envP,
379 xmlrpc_bool const value,
380 xmlrpc_value ** const valPP) {
382 xmlrpc_value * valP;
384 createXmlrpcValue(envP, &valP);
386 if (!envP->fault_occurred) {
387 valP->_type = XMLRPC_TYPE_BOOL;
388 valP->_value.b = value;
390 *valPP = valP;
395 static void
396 mkDouble(xmlrpc_env * const envP,
397 double const value,
398 xmlrpc_value ** const valPP) {
400 xmlrpc_value * valP;
402 createXmlrpcValue(envP, &valP);
404 if (!envP->fault_occurred) {
405 valP->_type = XMLRPC_TYPE_DOUBLE;
406 valP->_value.d = value;
408 *valPP = valP;
413 #ifdef HAVE_UNICODE_WCHAR
414 #define MAKE_WCS_BLOCK_NULL(val) ((val)->_wcs_block = NULL)
415 #else
416 #define MAKE_WCS_BLOCK_NULL(val) do {} while(0)
417 #endif
421 static void
422 mkString(xmlrpc_env * const envP,
423 const char * const value,
424 unsigned int const length,
425 xmlrpc_value ** const valPP) {
427 xmlrpc_value * valP;
429 createXmlrpcValue(envP, &valP);
431 if (!envP->fault_occurred) {
432 valP->_type = XMLRPC_TYPE_STRING;
433 MAKE_WCS_BLOCK_NULL(valP);
434 XMLRPC_MEMBLOCK_INIT(char, envP, &valP->_block, length + 1);
435 if (!envP->fault_occurred) {
436 char * const contents =
437 XMLRPC_MEMBLOCK_CONTENTS(char, &valP->_block);
438 memcpy(contents, value, length);
439 contents[length] = '\0';
441 if (envP->fault_occurred)
442 free(valP);
444 *valPP = valP;
449 static void
450 getString(xmlrpc_env * const envP,
451 const char ** const formatP,
452 va_list * const args,
453 xmlrpc_value ** const valPP) {
455 const char * str;
456 size_t len;
458 str = (const char*) va_arg(*args, char*);
459 if (**formatP == '#') {
460 (*formatP)++;
461 len = (size_t) va_arg(*args, size_t);
462 } else
463 len = strlen(str);
465 mkString(envP, str, (unsigned int)len, valPP);
470 #ifdef HAVE_UNICODE_WCHAR
471 static void
472 mkWideString(xmlrpc_env * const envP,
473 wchar_t * const wcs,
474 size_t const wcs_len,
475 xmlrpc_value ** const valPP) {
477 xmlrpc_value * valP;
478 char *contents;
479 wchar_t *wcs_contents;
480 int block_is_inited;
481 xmlrpc_mem_block *utf8_block;
482 char *utf8_contents;
483 size_t utf8_len;
485 /* Error-handling preconditions. */
486 utf8_block = NULL;
487 block_is_inited = 0;
489 /* Initialize our XML-RPC value. */
490 valP = (xmlrpc_value*) malloc(sizeof(xmlrpc_value));
491 XMLRPC_FAIL_IF_NULL(valP, envP, XMLRPC_INTERNAL_ERROR,
492 "Could not allocate memory for wide string");
493 valP->_refcount = 1;
494 valP->_type = XMLRPC_TYPE_STRING;
496 /* More error-handling preconditions. */
497 valP->_wcs_block = NULL;
499 /* Build our wchar_t block first. */
500 valP->_wcs_block =
501 XMLRPC_TYPED_MEM_BLOCK_NEW(wchar_t, envP, wcs_len + 1);
502 XMLRPC_FAIL_IF_FAULT(envP);
503 wcs_contents =
504 XMLRPC_TYPED_MEM_BLOCK_CONTENTS(wchar_t, valP->_wcs_block);
505 memcpy(wcs_contents, wcs, wcs_len * sizeof(wchar_t));
506 wcs_contents[wcs_len] = '\0';
508 /* Convert the wcs block to UTF-8. */
509 utf8_block = xmlrpc_wcs_to_utf8(envP, wcs_contents, wcs_len + 1);
510 XMLRPC_FAIL_IF_FAULT(envP);
511 utf8_contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, utf8_block);
512 utf8_len = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, utf8_block);
514 /* XXX - We need an extra memcopy to initialize _block. */
515 XMLRPC_TYPED_MEM_BLOCK_INIT(char, envP, &valP->_block, utf8_len);
516 XMLRPC_FAIL_IF_FAULT(envP);
517 block_is_inited = 1;
518 contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, &valP->_block);
519 memcpy(contents, utf8_contents, utf8_len);
521 cleanup:
522 if (utf8_block)
523 xmlrpc_mem_block_free(utf8_block);
524 if (envP->fault_occurred) {
525 if (valP) {
526 if (valP->_wcs_block)
527 xmlrpc_mem_block_free(valP->_wcs_block);
528 if (block_is_inited)
529 xmlrpc_mem_block_clean(&valP->_block);
530 free(valP);
533 *valPP = valP;
535 #endif /* HAVE_UNICODE_WCHAR */
539 static void
540 getWideString(xmlrpc_env * const envP,
541 const char ** const formatP,
542 va_list * const args,
543 xmlrpc_value ** const valPP) {
544 #ifdef HAVE_UNICODE_WCHAR
546 wchar_t *wcs;
547 size_t len;
549 wcs = (wchar_t*) va_arg(*args, wchar_t*);
550 if (**formatP == '#') {
551 (*formatP)++;
552 len = (size_t) va_arg(*args, size_t);
553 } else
554 len = wcslen(wcs);
556 mkWideString(envP, wcs, len, valPP);
558 #endif /* HAVE_UNICODE_WCHAR */
563 static void
564 mkDatetime(xmlrpc_env * const envP,
565 const char * const value,
566 xmlrpc_value ** const valPP) {
568 xmlrpc_value * valP;
570 createXmlrpcValue(envP, &valP);
572 if (!envP->fault_occurred) {
573 valP->_type = XMLRPC_TYPE_DATETIME;
575 XMLRPC_TYPED_MEM_BLOCK_INIT(
576 char, envP, &valP->_block, strlen(value) + 1);
577 if (!envP->fault_occurred) {
578 char * const contents =
579 XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, &valP->_block);
580 strcpy(contents, value);
582 if (envP->fault_occurred)
583 free(valP);
585 *valPP = valP;
590 static void
591 mkBase64(xmlrpc_env * const envP,
592 const unsigned char * const value,
593 size_t const length,
594 xmlrpc_value ** const valPP) {
596 xmlrpc_value * valP;
598 createXmlrpcValue(envP, &valP);
600 if (!envP->fault_occurred) {
601 valP->_type = XMLRPC_TYPE_BASE64;
603 xmlrpc_mem_block_init(envP, &valP->_block, length);
604 if (!envP->fault_occurred) {
605 char * const contents =
606 xmlrpc_mem_block_contents(&valP->_block);
607 memcpy(contents, value, length);
609 if (envP->fault_occurred)
610 free(valP);
612 *valPP = valP;
617 static void
618 getBase64(xmlrpc_env * const envP,
619 va_list * const args,
620 xmlrpc_value ** const valPP) {
622 unsigned char * value;
623 size_t length;
625 value = (unsigned char*) va_arg(*args, unsigned char*);
626 length = (size_t) va_arg(*args, size_t);
628 mkBase64(envP, value, length, valPP);
633 static void
634 mkCPtr(xmlrpc_env * const envP,
635 void * const value,
636 xmlrpc_value ** const valPP) {
638 xmlrpc_value * valP;
640 createXmlrpcValue(envP, &valP);
642 if (!envP->fault_occurred) {
643 valP->_type = XMLRPC_TYPE_C_PTR;
644 valP->_value.c_ptr = value;
646 *valPP = valP;
651 static void
652 mkArrayFromVal(xmlrpc_env * const envP,
653 xmlrpc_value * const value,
654 xmlrpc_value ** const valPP) {
656 if (xmlrpc_value_type(value) != XMLRPC_TYPE_ARRAY)
657 xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR,
658 "Array format ('A'), non-array xmlrpc_value");
659 else
660 xmlrpc_INCREF(value);
662 *valPP = value;
667 static void
668 mkStructFromVal(xmlrpc_env * const envP,
669 xmlrpc_value * const value,
670 xmlrpc_value ** const valPP) {
672 if (xmlrpc_value_type(value) != XMLRPC_TYPE_STRUCT)
673 xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR,
674 "Struct format ('S'), non-struct xmlrpc_value");
675 else
676 xmlrpc_INCREF(value);
678 *valPP = value;
683 static void
684 getValue(xmlrpc_env * const envP,
685 const char** const format,
686 va_list * const args,
687 xmlrpc_value ** const valPP);
691 static void
692 createXmlrpcArray(xmlrpc_env * const envP,
693 xmlrpc_value ** const arrayPP) {
694 /*----------------------------------------------------------------------------
695 Create an empty array xmlrpc_value.
696 -----------------------------------------------------------------------------*/
697 xmlrpc_value * arrayP;
699 createXmlrpcValue(envP, &arrayP);
700 if (!envP->fault_occurred) {
701 arrayP->_type = XMLRPC_TYPE_ARRAY;
702 XMLRPC_TYPED_MEM_BLOCK_INIT(xmlrpc_value*, envP, &arrayP->_block, 0);
703 if (envP->fault_occurred)
704 free(arrayP);
706 *arrayPP = arrayP;
711 static void
712 getArray(xmlrpc_env * const envP,
713 const char ** const formatP,
714 char const delimiter,
715 va_list * const args,
716 xmlrpc_value ** const arrayPP) {
718 xmlrpc_value * arrayP;
720 createXmlrpcArray(envP, &arrayP);
722 /* Add items to the array until we hit our delimiter. */
724 while (**formatP != delimiter && !envP->fault_occurred) {
726 xmlrpc_value * itemP;
728 if (**formatP == '\0')
729 xmlrpc_env_set_fault(
730 envP, XMLRPC_INTERNAL_ERROR,
731 "format string ended before closing ')'.");
732 else {
733 getValue(envP, formatP, args, &itemP);
734 if (!envP->fault_occurred) {
735 xmlrpc_array_append_item(envP, arrayP, itemP);
736 xmlrpc_DECREF(itemP);
740 if (envP->fault_occurred)
741 xmlrpc_DECREF(arrayP);
743 *arrayPP = arrayP;
748 static void
749 getStructMember(xmlrpc_env * const envP,
750 const char ** const formatP,
751 va_list * const args,
752 xmlrpc_value ** const keyPP,
753 xmlrpc_value ** const valuePP) {
756 /* Get the key */
757 getValue(envP, formatP, args, keyPP);
758 if (!envP->fault_occurred) {
759 if (**formatP != ':')
760 xmlrpc_env_set_fault(
761 envP, XMLRPC_INTERNAL_ERROR,
762 "format string does not have ':' after a "
763 "structure member key.");
764 else {
765 /* Skip over colon that separates key from value */
766 (*formatP)++;
768 /* Get the value */
769 getValue(envP, formatP, args, valuePP);
771 if (envP->fault_occurred)
772 xmlrpc_DECREF(*keyPP);
778 static void
779 getStruct(xmlrpc_env * const envP,
780 const char ** const formatP,
781 char const delimiter,
782 va_list * const args,
783 xmlrpc_value ** const structPP) {
785 xmlrpc_value * structP;
787 structP = xmlrpc_struct_new(envP);
788 if (!envP->fault_occurred) {
789 while (**formatP != delimiter && !envP->fault_occurred) {
790 xmlrpc_value * keyP;
791 xmlrpc_value * valueP;
793 getStructMember(envP, formatP, args, &keyP, &valueP);
795 if (!envP->fault_occurred) {
796 if (**formatP == ',')
797 (*formatP)++; /* Skip over the comma */
798 else if (**formatP == delimiter) {
799 /* End of the line */
800 } else
801 xmlrpc_env_set_fault(
802 envP, XMLRPC_INTERNAL_ERROR,
803 "format string does not have ',' or ')' after "
804 "a structure member");
806 if (!envP->fault_occurred)
807 /* Add the new member to the struct. */
808 xmlrpc_struct_set_value_v(envP, structP, keyP, valueP);
810 xmlrpc_DECREF(valueP);
811 xmlrpc_DECREF(keyP);
814 if (envP->fault_occurred)
815 xmlrpc_DECREF(structP);
817 *structPP = structP;
822 static void
823 getValue(xmlrpc_env * const envP,
824 const char** const formatP,
825 va_list * const args,
826 xmlrpc_value ** const valPP) {
827 /*----------------------------------------------------------------------------
828 Get the next value from the list. *formatP points to the specifier
829 for the next value in the format string (i.e. to the type code
830 character) and we move *formatP past the whole specifier for the
831 next value. We read the required arguments from 'args'. We return
832 the value as *valPP with a reference to it.
834 For example, if *formatP points to the "i" in the string "sis",
835 we read one argument from 'args' and return as *valP an integer whose
836 value is the argument we read. We advance *formatP to point to the
837 last 's' and advance 'args' to point to the argument that belongs to
838 that 's'.
839 -----------------------------------------------------------------------------*/
840 char const formatChar = *(*formatP)++;
842 switch (formatChar) {
843 case 'i':
844 mkInt(envP, (xmlrpc_int32) va_arg(*args, xmlrpc_int32), valPP);
845 break;
847 case 'b':
848 mkBool(envP, (xmlrpc_bool) va_arg(*args, xmlrpc_bool), valPP);
849 break;
851 case 'd':
852 mkDouble(envP, (double) va_arg(*args, va_double), valPP);
853 break;
855 case 's':
856 getString(envP, formatP, args, valPP);
857 break;
859 case 'w':
860 getWideString(envP, formatP, args, valPP);
861 break;
863 /* The code 't' is reserved for a better, time_t based
864 implementation of dateTime conversion.
866 case '8':
867 mkDatetime(envP, (char*) va_arg(*args, char*), valPP);
868 break;
870 case '6':
871 getBase64(envP, args, valPP);
872 break;
874 case 'p':
875 /* We might someday want to use the code 'p!' to read in a
876 cleanup function for this pointer.
878 mkCPtr(envP, (void*) va_arg(*args, void*), valPP);
879 break;
881 case 'A':
882 mkArrayFromVal(envP, (xmlrpc_value*) va_arg(*args, xmlrpc_value*),
883 valPP);
884 break;
886 case 'S':
887 mkStructFromVal(envP, (xmlrpc_value*) va_arg(*args, xmlrpc_value*),
888 valPP);
889 break;
891 case 'V':
892 *valPP = (xmlrpc_value*) va_arg(*args, xmlrpc_value*);
893 xmlrpc_INCREF(*valPP);
894 break;
896 case '(':
897 getArray(envP, formatP, ')', args, valPP);
898 if (!envP->fault_occurred) {
899 XMLRPC_ASSERT(**formatP == ')');
900 (*formatP)++; /* Skip over closing parenthesis */
902 break;
904 case '{':
905 getStruct(envP, formatP, '}', args, valPP);
906 if (!envP->fault_occurred) {
907 XMLRPC_ASSERT(**formatP == '}');
908 (*formatP)++; /* Skip over closing brace */
910 break;
912 default: {
913 const char * const badCharacter = xmlrpc_makePrintableChar(formatChar);
914 xmlrpc_env_set_fault_formatted(
915 envP, XMLRPC_INTERNAL_ERROR,
916 "Unexpected character '%s' in format string", badCharacter);
917 xmlrpc_strfree(badCharacter);
924 void
925 xmlrpc_build_value_va(xmlrpc_env * const envP,
926 const char * const format,
927 va_list args,
928 xmlrpc_value ** const valPP,
929 const char ** const tailP) {
931 const char * formatCursor;
932 va_list args_copy;
934 XMLRPC_ASSERT_ENV_OK(envP);
935 XMLRPC_ASSERT(format != NULL);
937 if (strlen(format) == 0)
938 xmlrpc_env_set_fault_formatted(
939 envP, XMLRPC_INTERNAL_ERROR, "Format string is empty.");
940 else {
941 formatCursor = &format[0];
942 VA_LIST_COPY(args_copy, args);
943 getValue(envP, &formatCursor, &args_copy, valPP);
945 if (!envP->fault_occurred)
946 XMLRPC_ASSERT_VALUE_OK(*valPP);
948 *tailP = formatCursor;
954 xmlrpc_value *
955 xmlrpc_build_value(xmlrpc_env * const envP,
956 const char * const format,
957 ...) {
959 va_list args;
960 xmlrpc_value* retval;
961 const char * suffix;
963 va_start(args, format);
964 xmlrpc_build_value_va(envP, format, args, &retval, &suffix);
965 va_end(args);
967 if (!envP->fault_occurred) {
968 if (*suffix != '\0')
969 xmlrpc_env_set_fault_formatted(
970 envP, XMLRPC_INTERNAL_ERROR, "Junk after the argument "
971 "specifier: '%s'. There must be exactly one arument.",
972 suffix);
974 if (envP->fault_occurred)
975 xmlrpc_DECREF(retval);
977 return retval;
981 /*=========================================================================
982 ** Parsing XML-RPC values.
983 **=========================================================================
984 ** Parse an XML-RPC value based on a format string. This code is heavily
985 ** inspired by Py_BuildValue from Python 1.5.2.
988 /* Prototype for recursive invocation: */
990 static void
991 parsevalue(xmlrpc_env * const env,
992 xmlrpc_value * const val,
993 const char ** const format,
994 va_list * args);
996 static void
997 parsearray(xmlrpc_env * const env,
998 const xmlrpc_value * const array,
999 const char ** const format,
1000 char const delimiter,
1001 va_list * args) {
1003 int size, i;
1004 xmlrpc_value *item;
1006 /* Fetch the array size. */
1007 size = xmlrpc_array_size(env, array);
1008 XMLRPC_FAIL_IF_FAULT(env);
1010 /* Loop over the items in the array. */
1011 for (i = 0; i < size; i++) {
1012 /* Bail out if the caller didn't care about the rest of the items. */
1013 if (**format == '*')
1014 break;
1016 item = xmlrpc_array_get_item(env, array, i);
1017 XMLRPC_FAIL_IF_FAULT(env);
1019 XMLRPC_ASSERT(**format != '\0');
1020 if (**format == delimiter)
1021 XMLRPC_FAIL(env, XMLRPC_INDEX_ERROR, "Too many items in array");
1022 parsevalue(env, item, format, args);
1023 XMLRPC_FAIL_IF_FAULT(env);
1025 if (**format == '*')
1026 (*format)++;
1027 if (**format != delimiter)
1028 XMLRPC_FAIL(env, XMLRPC_INDEX_ERROR, "Not enough items in array");
1030 cleanup:
1031 return;
1036 static void
1037 parsestruct(xmlrpc_env * const env,
1038 xmlrpc_value * const strct,
1039 const char ** const format,
1040 char const delimiter,
1041 va_list * args) {
1043 xmlrpc_value *key, *value;
1044 char *keystr;
1045 size_t keylen;
1047 /* Set up error handling preconditions. */
1048 key = NULL;
1050 /* Build the members of our struct. */
1051 while (**format != '*' && **format != delimiter && **format != '\0') {
1053 /* Get our key, and skip over the ':' character. Notice the
1054 ** sudden call to getValue--we're going in the opposite direction. */
1055 getValue(env, format, args, &key);
1056 XMLRPC_FAIL_IF_FAULT(env);
1057 XMLRPC_ASSERT(**format == ':');
1058 (*format)++;
1060 /* Look up the value for our key. */
1061 xmlrpc_parse_value(env, key, "s#", &keystr, &keylen);
1062 XMLRPC_FAIL_IF_FAULT(env);
1063 value = xmlrpc_struct_get_value_n(env, strct, keystr, keylen);
1064 XMLRPC_FAIL_IF_FAULT(env);
1066 /* Get our value, and skip over the ',' character (if present). */
1067 parsevalue(env, value, format, args);
1068 XMLRPC_FAIL_IF_FAULT(env);
1069 XMLRPC_ASSERT(**format == ',' || **format == delimiter);
1070 if (**format == ',')
1071 (*format)++;
1073 /* Release our reference, and restore our invariant. */
1074 xmlrpc_DECREF(key);
1075 key = NULL;
1077 if (**format == '*') {
1078 (*format)++;
1079 if (**format != delimiter && **format != '\0')
1080 XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR,
1081 "* can appear only at the end "
1082 "of a structure format specifier");
1083 } else {
1084 /* Here we're supposed to fail if he didn't extract all the
1085 members. But we don't know how to determine whether he
1086 specified all the members, so we always fail.
1088 XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "You must specify '*' as the "
1089 "last member of a structure in a format specifier "
1090 "used for parsing an xmlrpc_value");
1092 XMLRPC_ASSERT(**format == delimiter || **format == '\0');
1094 cleanup:
1095 if (key)
1096 xmlrpc_DECREF(key);
1100 static void
1101 parsevalue(xmlrpc_env * const envP,
1102 xmlrpc_value * const valueP,
1103 const char ** const format,
1104 va_list * args) {
1106 char formatSpecChar;
1108 formatSpecChar = *(*format)++;
1110 switch (formatSpecChar) {
1111 case 'i':
1112 validateType(envP, valueP, XMLRPC_TYPE_INT);
1113 if (!envP->fault_occurred) {
1114 xmlrpc_int32 * const int32ptr =
1115 (xmlrpc_int32*) va_arg(*args, xmlrpc_int32*);
1116 *int32ptr = valueP->_value.i;
1118 break;
1120 case 'b':
1121 validateType(envP, valueP, XMLRPC_TYPE_BOOL);
1122 if (!envP->fault_occurred) {
1123 xmlrpc_bool * const boolptr =
1124 (xmlrpc_bool*) va_arg(*args, xmlrpc_bool*);
1125 *boolptr = valueP->_value.b;
1127 break;
1129 case 'd':
1130 validateType(envP, valueP, XMLRPC_TYPE_DOUBLE);
1131 if (!envP->fault_occurred) {
1132 double * const doubleptr = (double*) va_arg(*args, double*);
1133 *doubleptr = valueP->_value.d;
1135 break;
1137 case 's':
1138 validateType(envP, valueP, XMLRPC_TYPE_STRING);
1139 if (!envP->fault_occurred) {
1140 char * const contents =
1141 XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block);
1142 size_t const len = XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block) - 1;
1144 char ** const strptr = (char**) va_arg(*args, char**);
1145 if (**format == '#') {
1146 size_t * const sizeptr = (size_t*) va_arg(*args, size_t**);
1147 (*format)++;
1148 *sizeptr = len;
1149 } else
1150 verifyNoNulls(envP, contents, (unsigned int)len);
1151 *strptr = contents;
1153 break;
1155 #ifdef HAVE_UNICODE_WCHAR
1156 case 'w':
1157 validateType(envP, valueP, XMLRPC_TYPE_STRING);
1158 if (!envP->fault_occurred) {
1159 if (!valueP->_wcs_block) {
1160 /* Allocate a wchar_t string if we don't have one. */
1161 char * const contents =
1162 XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block);
1163 size_t const len =
1164 XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block) - 1;
1165 valueP->_wcs_block =
1166 xmlrpc_utf8_to_wcs(envP, contents, len + 1);
1168 if (!envP->fault_occurred) {
1169 wchar_t * const wcontents =
1170 XMLRPC_MEMBLOCK_CONTENTS(wchar_t, valueP->_wcs_block);
1171 size_t const len =
1172 XMLRPC_MEMBLOCK_SIZE(wchar_t, valueP->_wcs_block) - 1;
1174 wchar_t ** const wcsptr = (wchar_t**) va_arg(*args, wchar_t**);
1175 if (**format == '#') {
1176 size_t * const sizeptr = (size_t*) va_arg(*args, size_t**);
1177 (*format)++;
1178 *sizeptr = len;
1179 } else
1180 verifyNoNullsW(envP, wcontents, (unsigned int)len);
1181 *wcsptr = wcontents;
1184 break;
1185 #endif /* HAVE_UNICODE_WCHAR */
1187 case '8':
1188 /* The code 't' is reserved for a better, time_t based
1189 ** implementation of dateTime conversion. */
1190 validateType(envP, valueP, XMLRPC_TYPE_DATETIME);
1191 if (!envP->fault_occurred) {
1192 char * const contents =
1193 XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block);
1194 char ** const strptr = (char**) va_arg(*args, char**);
1195 *strptr = contents;
1197 break;
1199 case '6':
1200 validateType(envP, valueP, XMLRPC_TYPE_BASE64);
1201 if (!envP->fault_occurred) {
1202 unsigned char * const bin_data =
1203 XMLRPC_MEMBLOCK_CONTENTS(unsigned char,
1204 &valueP->_block);
1205 size_t const len = XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block);
1206 unsigned char ** const binptr =
1207 (unsigned char**) va_arg(*args, unsigned char**);
1208 size_t * const sizeptr = (size_t*) va_arg(*args, size_t**);
1209 *binptr = bin_data;
1210 *sizeptr = len;
1212 break;
1214 case 'p':
1215 validateType(envP, valueP, XMLRPC_TYPE_C_PTR);
1216 if (!envP->fault_occurred) {
1217 void ** const voidptrptr = (void**) va_arg(*args, void**);
1218 *voidptrptr = valueP->_value.c_ptr;
1220 break;
1222 case 'V': {
1223 xmlrpc_value ** const valptr =
1224 (xmlrpc_value**) va_arg(*args, xmlrpc_value**);
1225 *valptr = valueP;
1227 break;
1229 case 'A':
1230 validateType(envP, valueP, XMLRPC_TYPE_ARRAY);
1231 if (!envP->fault_occurred) {
1232 xmlrpc_value ** const valptr =
1233 (xmlrpc_value**) va_arg(*args, xmlrpc_value**);
1234 *valptr = valueP;
1236 break;
1238 case 'S':
1239 validateType(envP, valueP, XMLRPC_TYPE_STRUCT);
1240 if (!envP->fault_occurred) {
1241 xmlrpc_value ** const valptr =
1242 (xmlrpc_value**) va_arg(*args, xmlrpc_value**);
1243 *valptr = valueP;
1245 break;
1247 case '(':
1248 validateType(envP, valueP, XMLRPC_TYPE_ARRAY);
1249 if (!envP->fault_occurred) {
1250 parsearray(envP, valueP, format, ')', args);
1251 (*format)++;
1253 break;
1255 case '{':
1256 validateType(envP, valueP, XMLRPC_TYPE_STRUCT);
1257 if (!envP->fault_occurred) {
1258 parsestruct(envP, valueP, format, '}', args);
1259 (*format)++;
1261 break;
1263 default:
1264 xmlrpc_env_set_fault_formatted(
1265 envP, XMLRPC_INTERNAL_ERROR, "Invalid format character '%c'",
1266 formatSpecChar);
1272 void
1273 xmlrpc_parse_value_va(xmlrpc_env * const envP,
1274 xmlrpc_value * const value,
1275 const char * const format,
1276 va_list args) {
1278 const char *format_copy;
1279 va_list args_copy;
1281 XMLRPC_ASSERT_ENV_OK(envP);
1282 XMLRPC_ASSERT_VALUE_OK(value);
1283 XMLRPC_ASSERT(format != NULL);
1285 format_copy = format;
1286 VA_LIST_COPY(args_copy, args);
1287 parsevalue(envP, value, &format_copy, &args_copy);
1288 if (!envP->fault_occurred) {
1289 XMLRPC_ASSERT(*format_copy == '\0');
1295 void
1296 xmlrpc_parse_value(xmlrpc_env * const envP,
1297 xmlrpc_value * const value,
1298 const char * const format,
1299 ...) {
1301 va_list args;
1303 va_start(args, format);
1304 xmlrpc_parse_value_va(envP, value, format, args);
1305 va_end(args);
1310 /* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
1311 ** Copyright (C) 2001 by Eric Kidd. All rights reserved.
1313 ** Redistribution and use in source and binary forms, with or without
1314 ** modification, are permitted provided that the following conditions
1315 ** are met:
1316 ** 1. Redistributions of source code must retain the above copyright
1317 ** notice, this list of conditions and the following disclaimer.
1318 ** 2. Redistributions in binary form must reproduce the above copyright
1319 ** notice, this list of conditions and the following disclaimer in the
1320 ** documentation and/or other materials provided with the distribution.
1321 ** 3. The name of the author may not be used to endorse or promote products
1322 ** derived from this software without specific prior written permission.
1324 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1325 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1326 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1327 ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1328 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1329 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1330 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1331 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1332 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1333 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1334 ** SUCH DAMAGE. */