initial load of upstream version 1.06.32
[xmlrpc-c] / src / xmlrpc_serialize.c
1 /* Copyright information is at end of file */
2
3 #include "xmlrpc_config.h"
4
5 #include <assert.h>
6 #include <stddef.h>
7 #include <stdarg.h>
8 #include <stdio.h>
9 #include <string.h>
10
11 #include "xmlrpc-c/base.h"
12 #include "xmlrpc-c/base_int.h"
13
14 #define CRLF "\015\012"
15 #define SMALL_BUFFER_SZ (128)
16 #define XML_PROLOGUE "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"CRLF
17
18
19 /*=========================================================================
20 **  format_out
21 **=========================================================================
22 **  A lightweight print routine for use with various serialization
23 **  functions. Only use this routine for printing small objects--it uses
24 **  a fixed-size internal buffer and returns an error on overflow.
25 **  In particular, do NOT use this routine to print XML-RPC string values!
26 */
27
28 static void 
29 format_out(xmlrpc_env *env,
30            xmlrpc_mem_block *output,
31            char *format_string,
32            ...) {
33
34     va_list args;
35     char buffer[SMALL_BUFFER_SZ];
36     int count;
37
38     XMLRPC_ASSERT_ENV_OK(env);
39
40     va_start(args, format_string);
41
42     /* We assume that this function is present and works correctly. Right. */
43     count = vsnprintf(buffer, SMALL_BUFFER_SZ, format_string, args);
44
45     /* Old C libraries return -1 if vsnprintf overflows its buffer.
46     ** New C libraries return the number of characters which *would* have
47     ** been printed if the error did not occur. This is impressively vile.
48     ** Thank the C99 committee for this bright idea. But wait! We also
49     ** need to keep track of the trailing NULL. */
50     if (count < 0 || count >= (SMALL_BUFFER_SZ - 1))
51     XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR,
52                 "format_out overflowed internal buffer");
53
54     /* Append our new data to our output. */
55     XMLRPC_TYPED_MEM_BLOCK_APPEND(char, env, output, buffer, count);
56     XMLRPC_FAIL_IF_FAULT(env);
57
58 cleanup:
59     va_end(args);
60 }
61
62
63
64 static void 
65 assertValidUtf8(const char * const str ATTR_UNUSED,
66                 size_t       const len ATTR_UNUSED) {
67 /*----------------------------------------------------------------------------
68    Assert that the string 'str' of length 'len' is valid UTF-8.
69 -----------------------------------------------------------------------------*/
70 #if !defined NDEBUG
71     /* Check the assertion; if it's false, issue a message to
72        Standard Error, but otherwise ignore it.
73     */
74     xmlrpc_env env;
75
76     xmlrpc_env_init(&env);
77     xmlrpc_validate_utf8(&env, str, len);
78     if (env.fault_occurred)
79         fprintf(stderr, "*** xmlrpc-c WARNING ***: %s (%s)\n",
80                 "Xmlrpc-c sending corrupted UTF-8 data to network",
81                 env.fault_string);
82     xmlrpc_env_clean(&env);
83 #endif
84 }
85
86
87
88 static size_t
89 escapedSize(const char * const chars,
90             size_t       const len) {
91     
92     size_t size;
93     size_t i;
94
95     size = 0;
96     for (i = 0; i < len; ++i) {
97         if (chars[i] == '<')
98             size += 4; /* &lt; */
99         else if (chars[i] == '>')
100             size += 4; /* &gt; */
101         else if (chars[i] == '&')
102             size += 5; /* &amp; */
103         else
104             size += 1;
105     }
106     return size;
107 }
108
109
110
111 static void
112 escapeForXml(xmlrpc_env *        const envP, 
113              const char *        const chars,
114              size_t              const len,
115              xmlrpc_mem_block ** const outputPP) {
116 /*----------------------------------------------------------------------------
117    Escape & and < in a UTF-8 string so as to make it suitable for the
118    content of an XML element.  I.e. turn them into entity references
119    &amp; and &lt;.  Also change > to &gt;, even though not required
120    for XML, for symmetry.
121 -----------------------------------------------------------------------------*/
122     xmlrpc_mem_block * outputP;
123     size_t outputSize;
124
125     XMLRPC_ASSERT_ENV_OK(envP);
126     XMLRPC_ASSERT(chars != NULL);
127
128     assertValidUtf8(chars, len);
129
130     /* Note that in UTF-8, any byte that has high bit of zero is a
131        character all by itself (every byte of a multi-byte UTF-8 character
132        has the high bit set).  Also, the Unicode code points < 128 are
133        identical to the ASCII ones.
134     */
135
136     outputSize = escapedSize(chars, len);
137
138     outputP = XMLRPC_MEMBLOCK_NEW(char, envP, outputSize);
139     if (!envP->fault_occurred) {
140         char * p;
141         size_t i;
142         p = XMLRPC_MEMBLOCK_CONTENTS(char, outputP); /* Start at beginning */
143
144         for (i = 0; i < len; i++) {
145             if (chars[i] == '<') {
146                 memcpy(p, "&lt;", 4);
147                 p += 4;
148             } else if (chars[i] == '>') {
149                 memcpy(p, "&gt;", 4);
150                 p += 4;
151             } else if (chars[i] == '&') {
152                 memcpy(p, "&amp;", 5);
153                 p += 5;
154             } else {
155                 *p = chars[i];
156                 p += 1;
157             }
158         }
159         *outputPP = outputP;
160         assert(p == XMLRPC_MEMBLOCK_CONTENTS(char, outputP) + outputSize);
161
162         if (envP->fault_occurred)
163             XMLRPC_MEMBLOCK_FREE(char, outputP);
164     }
165 }
166
167
168
169 static void 
170 serializeUtf8MemBlock(xmlrpc_env *       const envP,
171                       xmlrpc_mem_block * const outputP,
172                       xmlrpc_mem_block * const inputP) {
173 /*----------------------------------------------------------------------------
174    Append the characters in *inputP to the XML stream in *outputP.
175
176    *inputP contains Unicode characters in UTF-8.
177
178    We assume *inputP ends with a NUL character that marks end of
179    string, and we ignore that.  (There might also be NUL characters
180    inside the string, though).
181 -----------------------------------------------------------------------------*/
182     xmlrpc_mem_block * escapedP;
183
184     XMLRPC_ASSERT_ENV_OK(envP);
185     XMLRPC_ASSERT(outputP != NULL);
186     XMLRPC_ASSERT(inputP != NULL);
187
188     escapeForXml(envP,
189                  XMLRPC_MEMBLOCK_CONTENTS(const char, inputP),
190                  XMLRPC_MEMBLOCK_SIZE(const char, inputP) - 1,
191                     /* -1 is for the terminating NUL */
192                  &escapedP);
193     if (!envP->fault_occurred) {
194         const char * const contents =
195             XMLRPC_MEMBLOCK_CONTENTS(const char, escapedP);
196         size_t const size = XMLRPC_MEMBLOCK_SIZE(char, escapedP);
197     
198         XMLRPC_MEMBLOCK_APPEND(char, envP, outputP, contents, size);
199
200         XMLRPC_MEMBLOCK_FREE(const char, escapedP);
201     }
202 }
203
204
205
206 static void 
207 xmlrpc_serialize_base64_data(xmlrpc_env *       const envP,
208                              xmlrpc_mem_block * const output,
209                              unsigned char *    const data, 
210                              size_t             const len) {
211 /*----------------------------------------------------------------------------
212    Encode the 'len' bytes at 'data' in base64 ASCII and append the result to
213    'output'.
214 -----------------------------------------------------------------------------*/
215     xmlrpc_mem_block * encoded;
216
217     encoded = xmlrpc_base64_encode(envP, data, len);
218     if (!envP->fault_occurred) {
219         unsigned char * const contents =
220             XMLRPC_MEMBLOCK_CONTENTS(unsigned char, encoded);
221         size_t const size = 
222             XMLRPC_MEMBLOCK_SIZE(unsigned char, encoded);
223         
224         XMLRPC_MEMBLOCK_APPEND(char, envP, output, contents, size);
225         
226         XMLRPC_MEMBLOCK_FREE(char, encoded);
227     }
228 }
229
230
231
232 /*=========================================================================
233 **  xmlrpc_serialize_struct
234 **=========================================================================
235 **  Dump the contents of a struct.
236 */                
237
238 static void 
239 xmlrpc_serialize_struct(xmlrpc_env *env,
240                         xmlrpc_mem_block *output,
241                         xmlrpc_value *strct) {
242
243     size_t size;
244     size_t i;
245     xmlrpc_value *key, *value;
246
247     format_out(env, output, "<struct>"CRLF);
248     XMLRPC_FAIL_IF_FAULT(env);
249
250     size = xmlrpc_struct_size(env, strct);
251     XMLRPC_FAIL_IF_FAULT(env);
252     for (i = 0; i < size; i++) {
253         xmlrpc_struct_get_key_and_value(env, strct, i, &key, &value);
254         XMLRPC_FAIL_IF_FAULT(env);
255         format_out(env, output, "<member><name>");
256         XMLRPC_FAIL_IF_FAULT(env);
257         serializeUtf8MemBlock(env, output, &key->_block);
258         XMLRPC_FAIL_IF_FAULT(env);
259         format_out(env, output, "</name>"CRLF);
260         XMLRPC_FAIL_IF_FAULT(env);
261         xmlrpc_serialize_value(env, output, value);
262         XMLRPC_FAIL_IF_FAULT(env);
263         format_out(env, output, "</member>"CRLF);
264         XMLRPC_FAIL_IF_FAULT(env);
265     }
266
267     format_out(env, output, "</struct>");
268     XMLRPC_FAIL_IF_FAULT(env);
269
270 cleanup:
271     return;
272 }
273
274
275
276 /*=========================================================================
277 **  xmlrpc_serialize_value
278 **=========================================================================
279 **  Dump a value in the appropriate fashion.
280 */                
281
282 void 
283 xmlrpc_serialize_value(xmlrpc_env *env,
284                        xmlrpc_mem_block *output,
285                        xmlrpc_value *value) {
286
287     xmlrpc_value *item;
288     size_t size;
289     unsigned char* contents;
290     size_t i;
291
292     XMLRPC_ASSERT_ENV_OK(env);
293     XMLRPC_ASSERT(output != NULL);
294     XMLRPC_ASSERT_VALUE_OK(value);
295
296     /* Print our ubiquitous header. */
297     format_out(env, output, "<value>");
298     XMLRPC_FAIL_IF_FAULT(env);
299
300     switch (value->_type) {
301
302     case XMLRPC_TYPE_INT:
303         /* XXX - We assume that '%i' is the appropriate format specifier
304         ** for an xmlrpc_int32 value. We should add some test cases to
305         ** make sure this works. */
306         format_out(env, output, "<i4>%i</i4>", value->_value.i);
307         break;
308
309     case XMLRPC_TYPE_BOOL:
310         /* XXX - We assume that '%i' is the appropriate format specifier
311         ** for an xmlrpc_bool value. */
312         format_out(env, output, "<boolean>%i</boolean>",
313                    (value->_value.b) ? 1 : 0);
314         break;
315
316     case XMLRPC_TYPE_DOUBLE:
317         /* We must output a number of the form [+-]?\d*.\d*. */
318         format_out(env, output, "<double>%f</double>", value->_value.d);
319         break;
320
321     case XMLRPC_TYPE_STRING:
322         format_out(env, output, "<string>");
323         XMLRPC_FAIL_IF_FAULT(env);
324         serializeUtf8MemBlock(env, output, &value->_block);
325         XMLRPC_FAIL_IF_FAULT(env);
326         format_out(env, output, "</string>");
327         break;
328
329     case XMLRPC_TYPE_ARRAY:
330         format_out(env, output, "<array><data>"CRLF);
331         XMLRPC_FAIL_IF_FAULT(env);
332
333         /* Serialize each item. */
334         size = xmlrpc_array_size(env, value);
335         XMLRPC_FAIL_IF_FAULT(env);
336         for (i = 0; i < size; i++) {
337             item = xmlrpc_array_get_item(env, value, i);
338             XMLRPC_FAIL_IF_FAULT(env);
339             xmlrpc_serialize_value(env, output, item);
340             XMLRPC_FAIL_IF_FAULT(env);
341             format_out(env, output, CRLF);
342             XMLRPC_FAIL_IF_FAULT(env);
343         }
344
345         format_out(env, output, "</data></array>");
346         break;
347
348     case XMLRPC_TYPE_STRUCT:
349         xmlrpc_serialize_struct(env, output, value);
350         break;
351
352     case XMLRPC_TYPE_BASE64:
353         format_out(env, output, "<base64>"CRLF);
354         XMLRPC_FAIL_IF_FAULT(env);
355         contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(unsigned char,
356                                                    &value->_block);
357         size = XMLRPC_TYPED_MEM_BLOCK_SIZE(unsigned char, &value->_block);
358         xmlrpc_serialize_base64_data(env, output, contents, size);
359         XMLRPC_FAIL_IF_FAULT(env);
360         format_out(env, output, "</base64>");
361         break;      
362
363     case XMLRPC_TYPE_DATETIME:
364         format_out(env, output, "<dateTime.iso8601>");
365         XMLRPC_FAIL_IF_FAULT(env);
366         serializeUtf8MemBlock(env, output, &value->_block);
367         XMLRPC_FAIL_IF_FAULT(env);
368         format_out(env, output, "</dateTime.iso8601>");
369         break;
370
371     case XMLRPC_TYPE_C_PTR:
372         xmlrpc_env_set_fault_formatted(
373             env, XMLRPC_INTERNAL_ERROR,
374             "Tried to serialize a C pointer value.");
375         break;
376
377     case XMLRPC_TYPE_NIL:
378         format_out(env, output, "<nil/>");
379         XMLRPC_FAIL_IF_FAULT(env);
380         break;
381
382     case XMLRPC_TYPE_DEAD:
383         xmlrpc_env_set_fault_formatted(
384             env, XMLRPC_INTERNAL_ERROR,
385             "Tried to serialize a deaad value.");
386         break;
387
388     default:
389         xmlrpc_env_set_fault_formatted(
390             env, XMLRPC_INTERNAL_ERROR,
391             "Invalid xmlrpc_value type: %d", value->_type);
392     }
393     XMLRPC_FAIL_IF_FAULT(env);
394
395     /* Print our ubiquitous footer. */
396     format_out(env, output, "</value>");
397     XMLRPC_FAIL_IF_FAULT(env);
398
399  cleanup:
400     return;
401 }
402
403
404
405 /*=========================================================================
406 **  xmlrpc_serialize_params
407 **=========================================================================
408 **  Serialize a list as a set of parameters.
409 */                
410
411 void 
412 xmlrpc_serialize_params(xmlrpc_env *env,
413                         xmlrpc_mem_block *output,
414                         xmlrpc_value *param_array) {
415
416     size_t size, i;
417     xmlrpc_value *item;
418
419     XMLRPC_ASSERT_ENV_OK(env);
420     XMLRPC_ASSERT(output != NULL);
421     XMLRPC_ASSERT_VALUE_OK(param_array);
422
423     format_out(env, output, "<params>"CRLF);
424     XMLRPC_FAIL_IF_FAULT(env);
425
426     /* Dump each parameter. */
427     size = xmlrpc_array_size(env, param_array);
428     XMLRPC_FAIL_IF_FAULT(env);
429     for (i = 0; i < size; i++) {
430         format_out(env, output, "<param>");
431         XMLRPC_FAIL_IF_FAULT(env);
432         item = xmlrpc_array_get_item(env, param_array, i);
433         XMLRPC_FAIL_IF_FAULT(env);
434         xmlrpc_serialize_value(env, output, item);
435         XMLRPC_FAIL_IF_FAULT(env);
436         format_out(env, output, "</param>"CRLF);
437         XMLRPC_FAIL_IF_FAULT(env);
438     }
439
440     format_out(env, output, "</params>"CRLF);
441     XMLRPC_FAIL_IF_FAULT(env);
442
443  cleanup:    
444     return;
445 }
446
447
448
449 /*=========================================================================
450 **  xmlrpc_serialize_call
451 **=========================================================================
452 **  Serialize an XML-RPC call.
453 */                
454
455 void 
456 xmlrpc_serialize_call(xmlrpc_env *       const env,
457                       xmlrpc_mem_block * const output,
458                       const char *       const method_name,
459                       xmlrpc_value *     const param_array) {
460
461     xmlrpc_mem_block * encodedP;
462     char *contents;
463     size_t size;
464
465     XMLRPC_ASSERT_ENV_OK(env);
466     XMLRPC_ASSERT(output != NULL);
467     XMLRPC_ASSERT(method_name != NULL);
468     XMLRPC_ASSERT_VALUE_OK(param_array);
469     
470     /* Set up our error-handling preconditions. */
471     encodedP = NULL;
472
473     /* Dump our header. */
474     format_out(env, output, XML_PROLOGUE);
475     XMLRPC_FAIL_IF_FAULT(env);
476     format_out(env, output, "<methodCall>"CRLF"<methodName>");
477     XMLRPC_FAIL_IF_FAULT(env);
478
479     /* Dump the method name. */
480     escapeForXml(env, method_name, strlen(method_name), &encodedP);
481     XMLRPC_FAIL_IF_FAULT(env);
482     contents = XMLRPC_MEMBLOCK_CONTENTS(char, encodedP);
483     size = XMLRPC_MEMBLOCK_SIZE(char, encodedP);
484     XMLRPC_MEMBLOCK_APPEND(char, env, output, contents, size);
485     XMLRPC_FAIL_IF_FAULT(env);    
486
487     /* Dump our parameters and footer. */
488     format_out(env, output, "</methodName>"CRLF);
489     XMLRPC_FAIL_IF_FAULT(env);
490     xmlrpc_serialize_params(env, output, param_array);
491     XMLRPC_FAIL_IF_FAULT(env);
492     format_out(env, output, "</methodCall>"CRLF);
493     XMLRPC_FAIL_IF_FAULT(env);
494
495  cleanup:
496     if (encodedP)
497         XMLRPC_MEMBLOCK_FREE(char, encodedP);
498 }
499
500
501
502 /*=========================================================================
503 **  xmlrpc_serialize_response
504 **=========================================================================
505 **  Serialize the (non-fault) response to an XML-RPC call.
506 */                
507
508 void 
509 xmlrpc_serialize_response (xmlrpc_env *env,
510                            xmlrpc_mem_block *output,
511                            xmlrpc_value *value) {
512
513     XMLRPC_ASSERT_ENV_OK(env);
514     XMLRPC_ASSERT(output != NULL);
515     XMLRPC_ASSERT_VALUE_OK(value);
516
517     format_out(env, output, XML_PROLOGUE);
518     XMLRPC_FAIL_IF_FAULT(env);
519     format_out(env, output, "<methodResponse>"CRLF"<params>"CRLF"<param>");
520     XMLRPC_FAIL_IF_FAULT(env);
521
522     xmlrpc_serialize_value(env, output, value);
523     XMLRPC_FAIL_IF_FAULT(env);
524
525     format_out(env, output,
526                "</param>"CRLF"</params>"CRLF"</methodResponse>"CRLF);
527     XMLRPC_FAIL_IF_FAULT(env);
528     
529  cleanup:
530     return;
531 }
532
533
534
535 /*=========================================================================
536 **  xmlrpc_serialize_fault
537 **=========================================================================
538 **  Serialize an XML-RPC fault.
539 **
540 **  If this function fails, it will set up the first env argument. You'll
541 **  need to take some other drastic action to produce a serialized fault
542 **  of your own. (This function should only fail in an out-of-memory
543 **  situation, AFAIK.)
544 */                
545
546 void 
547 xmlrpc_serialize_fault(xmlrpc_env *env,
548                        xmlrpc_mem_block *output,
549                        xmlrpc_env *fault) {
550
551     xmlrpc_value *strct;
552
553     XMLRPC_ASSERT_ENV_OK(env);
554     XMLRPC_ASSERT(output != NULL);
555     XMLRPC_ASSERT(fault != NULL && fault->fault_occurred);
556
557     /* Set up our error-handling preconditions. */
558     strct = NULL;
559
560     /* Build a fault structure. */
561     strct = xmlrpc_build_value(env, "{s:i,s:s}",
562                    "faultCode", (xmlrpc_int32) fault->fault_code,
563                    "faultString", fault->fault_string);
564     XMLRPC_FAIL_IF_FAULT(env);
565
566     /* Output our header. */
567     format_out(env, output, XML_PROLOGUE);
568     XMLRPC_FAIL_IF_FAULT(env);
569     format_out(env, output, "<methodResponse>"CRLF"<fault>"CRLF);
570     XMLRPC_FAIL_IF_FAULT(env);
571
572     /* Serialize our fault structure. */
573     xmlrpc_serialize_value(env, output, strct);
574     XMLRPC_FAIL_IF_FAULT(env);
575
576     /* Output our footer. */
577     format_out(env, output, CRLF"</fault>"CRLF"</methodResponse>"CRLF);
578     XMLRPC_FAIL_IF_FAULT(env);
579
580  cleanup:
581     if (strct)
582         xmlrpc_DECREF(strct);
583 }
584
585
586
587
588 /* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
589 **
590 ** Redistribution and use in source and binary forms, with or without
591 ** modification, are permitted provided that the following conditions
592 ** are met:
593 ** 1. Redistributions of source code must retain the above copyright
594 **    notice, this list of conditions and the following disclaimer.
595 ** 2. Redistributions in binary form must reproduce the above copyright
596 **    notice, this list of conditions and the following disclaimer in the
597 **    documentation and/or other materials provided with the distribution.
598 ** 3. The name of the author may not be used to endorse or promote products
599 **    derived from this software without specific prior written permission. 
600 **  
601 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
602 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
603 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
604 ** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
605 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
606 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
607 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
608 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
609 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
610 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
611 ** SUCH DAMAGE. */