1 /* Copyright information is at end of file */
2 
3 /* Implementation note:
4 
5    The printf format specifiers we use appear to be entirely standard,
6    except for the "long long" one, which is %I64 on Windows and %lld
7    everywhere else.  We could use the C99 standard macro PRId64 for that,
8    but on at least one 64-bit-long GNU compiler, PRId64 is "ld", which is
9    considered to be incompatible with long long.  So we have XMLRPC_PRId64.
10 */
11 
12 #include "xmlrpc_config.h"
13 
14 #include <assert.h>
15 #include <stddef.h>
16 #include <stdarg.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <float.h>
21 
22 #include "int.h"
23 #include "xmlrpc-c/base.h"
24 #include "xmlrpc-c/base_int.h"
25 #include "xmlrpc-c/string_int.h"
26 #include "double.h"
27 
28 #define CRLF "\015\012"
29 #define XML_PROLOGUE "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"CRLF
30 #define APACHE_URL "http://ws.apache.org/xmlrpc/namespaces/extensions"
31 #define XMLNS_APACHE "xmlns:ex=\"" APACHE_URL "\""
32 
33 
34 static void
addString(xmlrpc_env * const envP,xmlrpc_mem_block * const outputP,const char * const string)35 addString(xmlrpc_env *       const envP,
36           xmlrpc_mem_block * const outputP,
37           const char *       const string) {
38 
39     XMLRPC_MEMBLOCK_APPEND(char, envP, outputP, string, strlen(string));
40 }
41 
42 
43 
44 static void
formatOut(xmlrpc_env * const envP,xmlrpc_mem_block * const outputP,const char * const formatString,...)45 formatOut(xmlrpc_env *       const envP,
46           xmlrpc_mem_block * const outputP,
47           const char *       const formatString,
48           ...) {
49 /*----------------------------------------------------------------------------
50   A lightweight print routine for use with various serialization
51   functions.
52 
53   Use this routine only for printing small objects -- it uses a
54   fixed-size internal buffer and returns an error on overflow.  In
55   particular, do NOT use this routine to print XML-RPC string values!
56 -----------------------------------------------------------------------------*/
57     va_list args;
58     char buffer[128];
59     int rc;
60 
61     XMLRPC_ASSERT_ENV_OK(envP);
62 
63     va_start(args, formatString);
64 
65     rc = XMLRPC_VSNPRINTF(buffer, sizeof(buffer), formatString, args);
66 
67     /* Old vsnprintf() (and Windows) fails with return value -1 if the full
68        string doesn't fit in the buffer.  New vsnprintf() puts whatever will
69        fit in the buffer, and returns the length of the full string
70        regardless.  For us, this truncation is a failure.
71     */
72 
73     if (rc < 0)
74         xmlrpc_faultf(envP, "formatOut() overflowed internal buffer");
75     else {
76         unsigned int const formattedLen = rc;
77 
78         if (formattedLen + 1 >= (sizeof(buffer)))
79             xmlrpc_faultf(envP, "formatOut() overflowed internal buffer");
80         else
81             XMLRPC_MEMBLOCK_APPEND(char, envP, outputP, buffer, formattedLen);
82     }
83     va_end(args);
84 }
85 
86 
87 
88 static void
assertValidUtf8(const char * const str ATTR_UNUSED,size_t const len ATTR_UNUSED)89 assertValidUtf8(const char * const str ATTR_UNUSED,
90                 size_t       const len ATTR_UNUSED) {
91 /*----------------------------------------------------------------------------
92    Assert that the string 'str' of length 'len' is valid UTF-8.
93 -----------------------------------------------------------------------------*/
94 #if !defined NDEBUG
95     /* Check the assertion; if it's false, issue a message to
96        Standard Error, but otherwise ignore it.
97     */
98     xmlrpc_env env;
99 
100     xmlrpc_env_init(&env);
101     xmlrpc_validate_utf8(&env, str, len);
102     if (env.fault_occurred)
103         fprintf(stderr, "*** xmlrpc-c WARNING ***: %s (%s)\n",
104                 "Xmlrpc-c sending corrupted UTF-8 data to network",
105                 env.fault_string);
106     xmlrpc_env_clean(&env);
107 #endif
108 }
109 
110 
111 
112 static size_t
escapedSize(const char * const chars,size_t const len)113 escapedSize(const char * const chars,
114             size_t       const len) {
115 
116     size_t size;
117     size_t i;
118 
119     size = 0;
120     for (i = 0; i < len; ++i) {
121         if (chars[i] == '<')
122             size += 4; /* &lt; */
123         else if (chars[i] == '>')
124             size += 4; /* &gt; */
125         else if (chars[i] == '&')
126             size += 5; /* &amp; */
127         else if (chars[i] == '\r')
128             size += 6; /* &#x0d; */
129         else
130             size += 1;
131     }
132     return size;
133 }
134 
135 
136 
137 static void
escapeForXml(xmlrpc_env * const envP,const char * const chars,size_t const len,xmlrpc_mem_block ** const outputPP)138 escapeForXml(xmlrpc_env *        const envP,
139              const char *        const chars,
140              size_t              const len,
141              xmlrpc_mem_block ** const outputPP) {
142 /*----------------------------------------------------------------------------
143    Escape & and < in a UTF-8 string so as to make it suitable for the
144    content of an XML element.  I.e. turn them into entity references
145    &amp; and &lt;.
146 
147    Also change > to &gt;, even though not required for XML, for
148    symmetry.
149 
150    &lt; etc. are known in XML as "entity references."
151 
152    Also Escape CR as &#x0d; .  While raw CR _is_ allowed in the content
153    of an XML element, it has a special meaning -- it means line ending.
154    Our input uses LF for for line endings.  Since it also means line ending
155    in XML, we just pass it through to our output like it were a regular
156    character.
157 
158    &#x0d; is known in XML as a "character reference."
159 
160    We assume chars[] is is ASCII.  That isn't right -- we should
161    handle all valid UTF-8.  Someday, we must do something more complex
162    and copy over multibyte characters verbatim.  (The code here could
163    erroneously find that e.g. the 2nd byte of a UTF-8 character is a
164    CR).
165 -----------------------------------------------------------------------------*/
166     xmlrpc_mem_block * outputP;
167     size_t outputSize;
168 
169     XMLRPC_ASSERT_ENV_OK(envP);
170     XMLRPC_ASSERT(chars != NULL);
171 
172     assertValidUtf8(chars, len);
173 
174     /* Note that in UTF-8, any byte that has high bit of zero is a
175        character all by itself (every byte of a multi-byte UTF-8 character
176        has the high bit set).  Also, the Unicode code points < 128 are
177        identical to the ASCII ones.
178     */
179 
180     outputSize = escapedSize(chars, len);
181 
182     outputP = XMLRPC_MEMBLOCK_NEW(char, envP, outputSize);
183     if (!envP->fault_occurred) {
184         char * p;
185         size_t i;
186         p = XMLRPC_MEMBLOCK_CONTENTS(char, outputP); /* Start at beginning */
187 
188         for (i = 0; i < len; i++) {
189             if (chars[i] == '<') {
190                 memcpy(p, "&lt;", 4);
191                 p += 4;
192             } else if (chars[i] == '>') {
193                 memcpy(p, "&gt;", 4);
194                 p += 4;
195             } else if (chars[i] == '&') {
196                 memcpy(p, "&amp;", 5);
197                 p += 5;
198             } else if (chars[i] == '\r') {
199                 memcpy(p, "&#x0d;", 6);
200                 p += 6;
201             } else {
202                 /* Either a plain character or a LF line delimiter */
203                 *p = chars[i];
204                 p += 1;
205             }
206         }
207         *outputPP = outputP;
208         assert(p == XMLRPC_MEMBLOCK_CONTENTS(char, outputP) + outputSize);
209 
210         if (envP->fault_occurred)
211             XMLRPC_MEMBLOCK_FREE(char, outputP);
212     }
213 }
214 
215 
216 
217 static void
serializeUtf8MemBlock(xmlrpc_env * const envP,xmlrpc_mem_block * const outputP,xmlrpc_mem_block * const inputP)218 serializeUtf8MemBlock(xmlrpc_env *       const envP,
219                       xmlrpc_mem_block * const outputP,
220                       xmlrpc_mem_block * const inputP) {
221 /*----------------------------------------------------------------------------
222    Append the characters in *inputP to the XML stream in *outputP.
223 
224    *inputP contains Unicode characters in UTF-8.
225 
226    We assume *inputP ends with a NUL character that marks end of
227    string, and we ignore that.  (There might also be NUL characters
228    inside the string, though).
229 -----------------------------------------------------------------------------*/
230     xmlrpc_mem_block * escapedP;
231 
232     XMLRPC_ASSERT_ENV_OK(envP);
233     XMLRPC_ASSERT(outputP != NULL);
234     XMLRPC_ASSERT(inputP != NULL);
235 
236     escapeForXml(envP,
237                  XMLRPC_MEMBLOCK_CONTENTS(const char, inputP),
238                  XMLRPC_MEMBLOCK_SIZE(const char, inputP) - 1,
239                     /* -1 is for the terminating NUL */
240                  &escapedP);
241     if (!envP->fault_occurred) {
242         const char * const contents =
243             XMLRPC_MEMBLOCK_CONTENTS(const char, escapedP);
244         size_t const size = XMLRPC_MEMBLOCK_SIZE(char, escapedP);
245 
246         XMLRPC_MEMBLOCK_APPEND(char, envP, outputP, contents, size);
247 
248         XMLRPC_MEMBLOCK_FREE(const char, escapedP);
249     }
250 }
251 
252 
253 
254 static void
xmlrpc_serialize_base64_data(xmlrpc_env * const envP,xmlrpc_mem_block * const output,unsigned char * const data,size_t const len)255 xmlrpc_serialize_base64_data(xmlrpc_env *       const envP,
256                              xmlrpc_mem_block * const output,
257                              unsigned char *    const data,
258                              size_t             const len) {
259 /*----------------------------------------------------------------------------
260    Encode the 'len' bytes at 'data' in base64 ASCII and append the result to
261    'output'.
262 -----------------------------------------------------------------------------*/
263     xmlrpc_mem_block * encoded;
264 
265     encoded = xmlrpc_base64_encode(envP, data, len);
266     if (!envP->fault_occurred) {
267         unsigned char * const contents =
268             XMLRPC_MEMBLOCK_CONTENTS(unsigned char, encoded);
269         size_t const size =
270             XMLRPC_MEMBLOCK_SIZE(unsigned char, encoded);
271 
272         XMLRPC_MEMBLOCK_APPEND(char, envP, output, contents, size);
273 
274         XMLRPC_MEMBLOCK_FREE(char, encoded);
275     }
276 }
277 
278 
279 
280 static void
serializeDatetime(xmlrpc_env * const envP,xmlrpc_mem_block * const outputP,xmlrpc_value * const valueP)281 serializeDatetime(xmlrpc_env *       const envP,
282                   xmlrpc_mem_block * const outputP,
283                   xmlrpc_value *     const valueP) {
284 /*----------------------------------------------------------------------------
285    Add to *outputP the content of a <value> element to represent
286    the datetime value *valueP.  I.e.
287    "<dateTime.iso8601> ... </dateTime.iso8601>".
288 -----------------------------------------------------------------------------*/
289 
290     addString(envP, outputP, "<dateTime.iso8601>");
291     if (!envP->fault_occurred) {
292         char dtString[64];
293 
294         snprintf(dtString, sizeof(dtString),
295                  "%u%02u%02uT%02u:%02u:%02u",
296                  valueP->_value.dt.Y,
297                  valueP->_value.dt.M,
298                  valueP->_value.dt.D,
299                  valueP->_value.dt.h,
300                  valueP->_value.dt.m,
301                  valueP->_value.dt.s);
302 
303         if (valueP->_value.dt.u != 0) {
304             char usecString[64];
305             assert(valueP->_value.dt.u < 1000000);
306             snprintf(usecString, sizeof(usecString), ".%06u",
307                      valueP->_value.dt.u);
308             STRSCAT(dtString, usecString);
309         }
310         addString(envP, outputP, dtString);
311 
312         if (!envP->fault_occurred) {
313             addString(envP, outputP, "</dateTime.iso8601>");
314         }
315     }
316 }
317 
318 
319 
320 static void
serializeStructMember(xmlrpc_env * const envP,xmlrpc_mem_block * const outputP,xmlrpc_value * const memberKeyP,xmlrpc_value * const memberValueP,xmlrpc_dialect const dialect)321 serializeStructMember(xmlrpc_env *       const envP,
322                       xmlrpc_mem_block * const outputP,
323                       xmlrpc_value *     const memberKeyP,
324                       xmlrpc_value *     const memberValueP,
325                       xmlrpc_dialect     const dialect) {
326 
327     addString(envP, outputP, "<member><name>");
328 
329     if (!envP->fault_occurred) {
330         serializeUtf8MemBlock(envP, outputP, &memberKeyP->_block);
331 
332         if (!envP->fault_occurred) {
333             addString(envP, outputP, "</name>"CRLF);
334 
335             if (!envP->fault_occurred) {
336                 xmlrpc_serialize_value2(envP, outputP, memberValueP, dialect);
337 
338                 if (!envP->fault_occurred) {
339                     addString(envP, outputP, "</member>"CRLF);
340                 }
341             }
342         }
343     }
344 }
345 
346 
347 
348 static void
serializeStruct(xmlrpc_env * const envP,xmlrpc_mem_block * const outputP,xmlrpc_value * const structP,xmlrpc_dialect const dialect)349 serializeStruct(xmlrpc_env *       const envP,
350                 xmlrpc_mem_block * const outputP,
351                 xmlrpc_value *     const structP,
352                 xmlrpc_dialect     const dialect) {
353 /*----------------------------------------------------------------------------
354    Add to *outputP the content of a <value> element to represent
355    the structure value *valueP.  I.e. "<struct> ... </struct>".
356 -----------------------------------------------------------------------------*/
357     addString(envP, outputP, "<struct>"CRLF);
358     if (!envP->fault_occurred) {
359         unsigned int const size = xmlrpc_struct_size(envP, structP);
360         if (!envP->fault_occurred) {
361             unsigned int i;
362             for (i = 0; i < size && !envP->fault_occurred; ++i) {
363                 xmlrpc_value * memberKeyP;
364                 xmlrpc_value * memberValueP;
365 
366                 xmlrpc_struct_get_key_and_value(envP, structP, i,
367                                                 &memberKeyP, &memberValueP);
368                 if (!envP->fault_occurred) {
369                     serializeStructMember(envP, outputP,
370                                           memberKeyP, memberValueP, dialect);
371                 }
372             }
373             addString(envP, outputP, "</struct>");
374         }
375     }
376 }
377 
378 
379 
380 static void
serializeArray(xmlrpc_env * const envP,xmlrpc_mem_block * const outputP,xmlrpc_value * const valueP,xmlrpc_dialect const dialect)381 serializeArray(xmlrpc_env *       const envP,
382                xmlrpc_mem_block * const outputP,
383                xmlrpc_value *     const valueP,
384                xmlrpc_dialect     const dialect) {
385 /*----------------------------------------------------------------------------
386    Add to *outputP the content of a <value> element to represent
387    the array value *valueP.  I.e. "<array> ... </array>".
388 -----------------------------------------------------------------------------*/
389     int const size = xmlrpc_array_size(envP, valueP);
390 
391     if (!envP->fault_occurred) {
392         addString(envP, outputP, "<array><data>"CRLF);
393         if (!envP->fault_occurred) {
394             int i;
395             /* Serialize each item. */
396             for (i = 0; i < size && !envP->fault_occurred; ++i) {
397                 xmlrpc_value * const itemP =
398                     xmlrpc_array_get_item(envP, valueP, i);
399                 if (!envP->fault_occurred) {
400                     xmlrpc_serialize_value2(envP, outputP, itemP, dialect);
401                     if (!envP->fault_occurred)
402                         addString(envP, outputP, CRLF);
403                 }
404             }
405         }
406     }
407     if (!envP->fault_occurred)
408         addString(envP, outputP, "</data></array>");
409 }
410 
411 
412 
413 static void
formatValueContent(xmlrpc_env * const envP,xmlrpc_mem_block * const outputP,xmlrpc_value * const valueP,xmlrpc_dialect const dialect)414 formatValueContent(xmlrpc_env *       const envP,
415                    xmlrpc_mem_block * const outputP,
416                    xmlrpc_value *     const valueP,
417                    xmlrpc_dialect     const dialect) {
418 /*----------------------------------------------------------------------------
419    Add to *outputP the content of a <value> element to represent
420    value *valueP.  E.g. "<int>42</int>"
421 -----------------------------------------------------------------------------*/
422     XMLRPC_ASSERT_ENV_OK(envP);
423 
424     switch (valueP->_type) {
425     case XMLRPC_TYPE_INT:
426         formatOut(envP, outputP, "<i4>%d</i4>", valueP->_value.i);
427         break;
428 
429     case XMLRPC_TYPE_I8: {
430         const char * const elemName =
431             dialect == xmlrpc_dialect_apache ? "ex:i8" : "i8";
432         formatOut(envP, outputP, "<%s>%" PRId64 "</%s>",
433                   elemName, valueP->_value.i8, elemName);
434     } break;
435 
436     case XMLRPC_TYPE_BOOL:
437         formatOut(envP, outputP, "<boolean>%s</boolean>",
438                   valueP->_value.b ? "1" : "0");
439         break;
440 
441     case XMLRPC_TYPE_DOUBLE: {
442         const char * serializedValue;
443         xmlrpc_formatFloat(envP, valueP->_value.d, &serializedValue);
444         if (!envP->fault_occurred) {
445             addString(envP, outputP, "<double>");
446             if (!envP->fault_occurred) {
447                 addString(envP, outputP, serializedValue);
448                 if (!envP->fault_occurred)
449                     addString(envP, outputP, "</double>");
450             }
451             xmlrpc_strfree(serializedValue);
452         }
453     } break;
454 
455     case XMLRPC_TYPE_DATETIME:
456         serializeDatetime(envP, outputP, valueP);
457         break;
458 
459     case XMLRPC_TYPE_STRING:
460         addString(envP, outputP, "<string>");
461         if (!envP->fault_occurred) {
462             serializeUtf8MemBlock(envP, outputP, &valueP->_block);
463             if (!envP->fault_occurred)
464                 addString(envP, outputP, "</string>");
465         }
466         break;
467 
468     case XMLRPC_TYPE_BASE64: {
469         unsigned char * const contents =
470             XMLRPC_MEMBLOCK_CONTENTS(unsigned char, &valueP->_block);
471         size_t const size =
472             XMLRPC_MEMBLOCK_SIZE(unsigned char, &valueP->_block);
473         addString(envP, outputP, "<base64>"CRLF);
474         if (!envP->fault_occurred) {
475             xmlrpc_serialize_base64_data(envP, outputP, contents, size);
476             if (!envP->fault_occurred)
477                 addString(envP, outputP, "</base64>");
478         }
479     } break;
480 
481     case XMLRPC_TYPE_ARRAY:
482         serializeArray(envP, outputP, valueP, dialect);
483         break;
484 
485     case XMLRPC_TYPE_STRUCT:
486         serializeStruct(envP, outputP, valueP, dialect);
487         break;
488 
489     case XMLRPC_TYPE_C_PTR:
490         xmlrpc_faultf(envP, "Tried to serialize a C pointer value.");
491         break;
492 
493     case XMLRPC_TYPE_NIL: {
494         const char * const elemName =
495             dialect == xmlrpc_dialect_apache ? "ex:nil" : "nil";
496         formatOut(envP, outputP, "<%s/>", elemName);
497     } break;
498 
499     case XMLRPC_TYPE_DEAD:
500         xmlrpc_faultf(envP, "Tried to serialize a dead value.");
501         break;
502 
503     default:
504         xmlrpc_faultf(envP, "Invalid xmlrpc_value type: %d", valueP->_type);
505     }
506 }
507 
508 
509 
510 void
xmlrpc_serialize_value2(xmlrpc_env * const envP,xmlrpc_mem_block * const outputP,xmlrpc_value * const valueP,xmlrpc_dialect const dialect)511 xmlrpc_serialize_value2(xmlrpc_env *       const envP,
512                         xmlrpc_mem_block * const outputP,
513                         xmlrpc_value *     const valueP,
514                         xmlrpc_dialect     const dialect) {
515 /*----------------------------------------------------------------------------
516    Generate the XML to represent XML-RPC value 'valueP' in XML-RPC.
517 
518    Add it to *outputP.
519 -----------------------------------------------------------------------------*/
520     XMLRPC_ASSERT_ENV_OK(envP);
521     XMLRPC_ASSERT(outputP != NULL);
522     XMLRPC_ASSERT_VALUE_OK(valueP);
523 
524     addString(envP, outputP, "<value>");
525 
526     if (!envP->fault_occurred) {
527         formatValueContent(envP, outputP, valueP, dialect);
528 
529         if (!envP->fault_occurred)
530             addString(envP, outputP, "</value>");
531     }
532 }
533 
534 
535 
536 void
xmlrpc_serialize_value(xmlrpc_env * const envP,xmlrpc_mem_block * const outputP,xmlrpc_value * const valueP)537 xmlrpc_serialize_value(xmlrpc_env *       const envP,
538                        xmlrpc_mem_block * const outputP,
539                        xmlrpc_value *     const valueP) {
540 
541     xmlrpc_serialize_value2(envP, outputP, valueP, xmlrpc_dialect_i8);
542 }
543 
544 
545 
546 void
xmlrpc_serialize_params2(xmlrpc_env * const envP,xmlrpc_mem_block * const outputP,xmlrpc_value * const paramArrayP,xmlrpc_dialect const dialect)547 xmlrpc_serialize_params2(xmlrpc_env *       const envP,
548                          xmlrpc_mem_block * const outputP,
549                          xmlrpc_value *     const paramArrayP,
550                          xmlrpc_dialect     const dialect) {
551 /*----------------------------------------------------------------------------
552    Serialize the parameter list of an XML-RPC call.
553 -----------------------------------------------------------------------------*/
554     XMLRPC_ASSERT_ENV_OK(envP);
555     XMLRPC_ASSERT(outputP != NULL);
556     XMLRPC_ASSERT_VALUE_OK(paramArrayP);
557 
558     addString(envP, outputP, "<params>"CRLF);
559     if (!envP->fault_occurred) {
560         /* Serialize each parameter. */
561         int const paramCount = xmlrpc_array_size(envP, paramArrayP);
562         if (!envP->fault_occurred) {
563             int paramSeq;
564             for (paramSeq = 0;
565                  paramSeq < paramCount && !envP->fault_occurred;
566                  ++paramSeq) {
567 
568                 addString(envP, outputP, "<param>");
569                 if (!envP->fault_occurred) {
570                     xmlrpc_value * const itemP =
571                         xmlrpc_array_get_item(envP, paramArrayP, paramSeq);
572                     if (!envP->fault_occurred) {
573                         xmlrpc_serialize_value2(envP, outputP, itemP, dialect);
574                         if (!envP->fault_occurred)
575                             addString(envP, outputP, "</param>"CRLF);
576                     }
577                 }
578             }
579         }
580     }
581 
582     if (!envP->fault_occurred)
583         addString(envP, outputP, "</params>"CRLF);
584 }
585 
586 
587 
588 void
xmlrpc_serialize_params(xmlrpc_env * const envP,xmlrpc_mem_block * const outputP,xmlrpc_value * const paramArrayP)589 xmlrpc_serialize_params(xmlrpc_env *       const envP,
590                         xmlrpc_mem_block * const outputP,
591                         xmlrpc_value *     const paramArrayP) {
592 /*----------------------------------------------------------------------------
593    Serialize the parameter list of an XML-RPC call in the original
594    "i8" dialect.
595 -----------------------------------------------------------------------------*/
596     xmlrpc_serialize_params2(envP, outputP, paramArrayP, xmlrpc_dialect_i8);
597 }
598 
599 
600 
601 /*=========================================================================
602 **  xmlrpc_serialize_call
603 **=========================================================================
604 **  Serialize an XML-RPC call.
605 */
606 
607 void
xmlrpc_serialize_call2(xmlrpc_env * const envP,xmlrpc_mem_block * const outputP,const char * const methodName,xmlrpc_value * const paramArrayP,xmlrpc_dialect const dialect)608 xmlrpc_serialize_call2(xmlrpc_env *       const envP,
609                        xmlrpc_mem_block * const outputP,
610                        const char *       const methodName,
611                        xmlrpc_value *     const paramArrayP,
612                        xmlrpc_dialect     const dialect) {
613 /*----------------------------------------------------------------------------
614    Serialize an XML-RPC call of method named 'methodName' with parameter
615    list *paramArrayP.  Use XML-RPC dialect 'dialect'.
616 
617    Append the call XML ot *outputP.
618 -----------------------------------------------------------------------------*/
619     XMLRPC_ASSERT_ENV_OK(envP);
620     XMLRPC_ASSERT(outputP != NULL);
621     XMLRPC_ASSERT(methodName != NULL);
622     XMLRPC_ASSERT_VALUE_OK(paramArrayP);
623 
624     addString(envP, outputP, XML_PROLOGUE);
625     if (!envP->fault_occurred) {
626         const char * const xmlns =
627             dialect == xmlrpc_dialect_apache ? " " XMLNS_APACHE : "";
628         formatOut(envP, outputP, "<methodCall%s>"CRLF"<methodName>", xmlns);
629         if (!envP->fault_occurred) {
630             xmlrpc_mem_block * encodedP;
631             escapeForXml(envP, methodName, strlen(methodName), &encodedP);
632             if (!envP->fault_occurred) {
633                 const char * const contents =
634                     XMLRPC_MEMBLOCK_CONTENTS(char, encodedP);
635                 size_t const size = XMLRPC_MEMBLOCK_SIZE(char, encodedP);
636                 XMLRPC_MEMBLOCK_APPEND(char, envP, outputP, contents, size);
637                 if (!envP->fault_occurred) {
638                     addString(envP, outputP, "</methodName>"CRLF);
639                     if (!envP->fault_occurred) {
640                         xmlrpc_serialize_params2(envP, outputP, paramArrayP,
641                                                  dialect);
642                         if (!envP->fault_occurred)
643                             addString(envP, outputP, "</methodCall>"CRLF);
644                     }
645                 }
646                 XMLRPC_MEMBLOCK_FREE(char, encodedP);
647             }
648         }
649     }
650 }
651 
652 
653 
654 void
xmlrpc_serialize_call(xmlrpc_env * const envP,xmlrpc_mem_block * const outputP,const char * const methodName,xmlrpc_value * const paramArrayP)655 xmlrpc_serialize_call(xmlrpc_env *       const envP,
656                       xmlrpc_mem_block * const outputP,
657                       const char *       const methodName,
658                       xmlrpc_value *     const paramArrayP) {
659 
660     xmlrpc_serialize_call2(envP, outputP, methodName, paramArrayP,
661                            xmlrpc_dialect_i8);
662 }
663 
664 
665 
666 void
xmlrpc_serialize_response2(xmlrpc_env * const envP,xmlrpc_mem_block * const outputP,xmlrpc_value * const valueP,xmlrpc_dialect const dialect)667 xmlrpc_serialize_response2(xmlrpc_env *       const envP,
668                            xmlrpc_mem_block * const outputP,
669                            xmlrpc_value *     const valueP,
670                            xmlrpc_dialect     const dialect) {
671 /*----------------------------------------------------------------------------
672   Serialize a result response to an XML-RPC call.
673 
674   The result is 'valueP'.
675 
676   Add the response XML to *outputP.
677 -----------------------------------------------------------------------------*/
678     XMLRPC_ASSERT_ENV_OK(envP);
679     XMLRPC_ASSERT(outputP != NULL);
680     XMLRPC_ASSERT_VALUE_OK(valueP);
681 
682     addString(envP, outputP, XML_PROLOGUE);
683     if (!envP->fault_occurred) {
684         const char * const xmlns =
685             dialect == xmlrpc_dialect_apache ? " " XMLNS_APACHE : "";
686         formatOut(envP, outputP,
687                   "<methodResponse%s>"CRLF"<params>"CRLF"<param>", xmlns);
688         if (!envP->fault_occurred) {
689             xmlrpc_serialize_value2(envP, outputP, valueP, dialect);
690             if (!envP->fault_occurred) {
691                 addString(envP, outputP,
692                           "</param>"CRLF"</params>"CRLF
693                           "</methodResponse>"CRLF);
694             }
695         }
696     }
697 }
698 
699 
700 
701 void
xmlrpc_serialize_response(xmlrpc_env * const envP,xmlrpc_mem_block * const outputP,xmlrpc_value * const valueP)702 xmlrpc_serialize_response(xmlrpc_env *       const envP,
703                           xmlrpc_mem_block * const outputP,
704                           xmlrpc_value *     const valueP) {
705 
706     xmlrpc_serialize_response2(envP, outputP, valueP, xmlrpc_dialect_i8);
707 }
708 
709 
710 
711 void
xmlrpc_serialize_fault(xmlrpc_env * const envP,xmlrpc_mem_block * const outputP,const xmlrpc_env * const faultP)712 xmlrpc_serialize_fault(xmlrpc_env *       const envP,
713                        xmlrpc_mem_block * const outputP,
714                        const xmlrpc_env * const faultP) {
715 /*----------------------------------------------------------------------------
716    Serialize a fault response to an XML-RPC call.
717 
718    'faultP' is the fault.
719 
720    Add the response XML to *outputP.
721 -----------------------------------------------------------------------------*/
722     xmlrpc_value * faultStructP;
723 
724     XMLRPC_ASSERT_ENV_OK(envP);
725     XMLRPC_ASSERT(outputP != NULL);
726     XMLRPC_ASSERT(faultP != NULL);
727     XMLRPC_ASSERT(faultP->fault_occurred);
728 
729     faultStructP = xmlrpc_build_value(envP, "{s:i,s:s}",
730                                       "faultCode",
731                                       (xmlrpc_int32) faultP->fault_code,
732                                       "faultString", faultP->fault_string);
733     if (!envP->fault_occurred) {
734         addString(envP, outputP, XML_PROLOGUE);
735         if (!envP->fault_occurred) {
736             addString(envP, outputP, "<methodResponse>"CRLF"<fault>"CRLF);
737             if (!envP->fault_occurred) {
738                 xmlrpc_serialize_value(envP, outputP, faultStructP);
739                 if (!envP->fault_occurred) {
740                     addString(envP, outputP,
741                               CRLF"</fault>"CRLF"</methodResponse>"CRLF);
742                 }
743             }
744         }
745         xmlrpc_DECREF(faultStructP);
746     }
747 }
748 
749 
750 
751 /* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
752 **
753 ** Redistribution and use in source and binary forms, with or without
754 ** modification, are permitted provided that the following conditions
755 ** are met:
756 ** 1. Redistributions of source code must retain the above copyright
757 **    notice, this list of conditions and the following disclaimer.
758 ** 2. Redistributions in binary form must reproduce the above copyright
759 **    notice, this list of conditions and the following disclaimer in the
760 **    documentation and/or other materials provided with the distribution.
761 ** 3. The name of the author may not be used to endorse or promote products
762 **    derived from this software without specific prior written permission.
763 **
764 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
765 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
766 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
767 ** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
768 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
769 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
770 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
771 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
772 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
773 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
774 ** SUCH DAMAGE. */
775