1 /*
2   This file is part of libXMLRPC - a C library for xml-encoded function calls.
3 
4   Author: Dan Libby (dan@libby.com)
5   Epinions.com may be contacted at feedback@epinions-inc.com
6 */
7 
8 /*
9   Copyright 2000 Epinions, Inc.
10 
11   Subject to the following 3 conditions, Epinions, Inc.  permits you, free
12   of charge, to (a) use, copy, distribute, modify, perform and display this
13   software and associated documentation files (the "Software"), and (b)
14   permit others to whom the Software is furnished to do so as well.
15 
16   1) The above copyright notice and this permission notice shall be included
17   without modification in all copies or substantial portions of the
18   Software.
19 
20   2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF
21   ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY
22   IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR
23   PURPOSE OR NONINFRINGEMENT.
24 
25   3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
26   SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
27   OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING
28   NEGLIGENCE), EVEN IF EPINIONS, INC.  IS AWARE OF THE POSSIBILITY OF SUCH
29   DAMAGES.
30 
31 */
32 
33 #ifdef _WIN32
34 #include "xmlrpc_win32.h"
35 #endif
36 #include <string.h>
37 #include <stdlib.h>
38 #include "xml_to_dandarpc.h"
39 #include "base64.h"
40 
41 /* list of tokens used in vocab */
42 #define ELEM_METHODCALL     "methodCall"
43 #define ELEM_METHODNAME     "methodName"
44 #define ELEM_METHODRESPONSE "methodResponse"
45 #define ELEM_ROOT           "simpleRPC"
46 
47 #define ATTR_ARRAY          "array"
48 #define ATTR_BASE64         "base64"
49 #define ATTR_BOOLEAN        "boolean"
50 #define ATTR_DATETIME       "dateTime.iso8601"
51 #define ATTR_DOUBLE         "double"
52 #define ATTR_ID             "id"
53 #define ATTR_INT            "int"
54 #define ATTR_MIXED          "mixed"
55 #define ATTR_SCALAR         "scalar"
56 #define ATTR_STRING         "string"
57 #define ATTR_STRUCT         "struct"
58 #define ATTR_TYPE           "type"
59 #define ATTR_VECTOR         "vector"
60 #define ATTR_VERSION        "version"
61 
62 #define VAL_VERSION_0_9     "0.9"
63 
64 
xml_element_to_DANDARPC_REQUEST_worker(XMLRPC_REQUEST request,XMLRPC_VALUE xCurrent,xml_element * el)65 XMLRPC_VALUE xml_element_to_DANDARPC_REQUEST_worker(XMLRPC_REQUEST request, XMLRPC_VALUE xCurrent, xml_element* el) {
66    if(!xCurrent) {
67       xCurrent = XMLRPC_CreateValueEmpty();
68    }
69 
70    if(el->name) {
71       const char* id = NULL;
72       const char* type = NULL;
73       xml_element_attr* attr_iter = Q_Head(&el->attrs);
74 
75       while(attr_iter) {
76          if(!strcmp(attr_iter->key, ATTR_ID)) {
77             id = attr_iter->val;
78          }
79          if(!strcmp(attr_iter->key, ATTR_TYPE)) {
80             type = attr_iter->val;
81          }
82          attr_iter = Q_Next(&el->attrs);
83       }
84 
85       if(id) {
86          XMLRPC_SetValueID_Case(xCurrent, id, 0, xmlrpc_case_exact);
87       }
88 
89       if(!strcmp(el->name, ATTR_SCALAR)) {
90          if(!type || !strcmp(type, ATTR_STRING)) {
91             XMLRPC_SetValueString(xCurrent, el->text.str, el->text.len);
92          }
93          else if(!strcmp(type, ATTR_INT)) {
94             XMLRPC_SetValueInt(xCurrent, atoi(el->text.str));
95          }
96          else if(!strcmp(type, ATTR_BOOLEAN)) {
97             XMLRPC_SetValueBoolean(xCurrent, atoi(el->text.str));
98          }
99          else if(!strcmp(type, ATTR_DOUBLE)) {
100             XMLRPC_SetValueDouble(xCurrent, atof(el->text.str));
101          }
102          else if(!strcmp(type, ATTR_DATETIME)) {
103             XMLRPC_SetValueDateTime_ISO8601(xCurrent, el->text.str);
104          }
105          else if(!strcmp(type, ATTR_BASE64)) {
106             struct buffer_st buf;
107             base64_decode_xmlrpc(&buf, el->text.str, el->text.len);
108             XMLRPC_SetValueBase64(xCurrent, buf.data, buf.offset);
109             buffer_delete(&buf);
110          }
111       }
112       else if(!strcmp(el->name, ATTR_VECTOR)) {
113          xml_element* iter = (xml_element*)Q_Head(&el->children);
114 
115          if(!type || !strcmp(type, ATTR_MIXED)) {
116             XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_mixed);
117          }
118          else if(!strcmp(type, ATTR_ARRAY)) {
119 				XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_array);
120          }
121          else if(!strcmp(type, ATTR_STRUCT)) {
122             XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_struct);
123          }
124          while( iter ) {
125             XMLRPC_VALUE xNext = XMLRPC_CreateValueEmpty();
126             xml_element_to_DANDARPC_REQUEST_worker(request, xNext, iter);
127             XMLRPC_AddValueToVector(xCurrent, xNext);
128             iter = (xml_element*)Q_Next(&el->children);
129          }
130       }
131       else {
132          xml_element* iter = (xml_element*)Q_Head(&el->children);
133          while( iter ) {
134             xml_element_to_DANDARPC_REQUEST_worker(request, xCurrent, iter);
135             iter = (xml_element*)Q_Next(&el->children);
136          }
137 
138          if(!strcmp(el->name, ELEM_METHODCALL)) {
139             if(request) {
140                XMLRPC_RequestSetRequestType(request, xmlrpc_request_call);
141             }
142          }
143          else if(!strcmp(el->name, ELEM_METHODRESPONSE)) {
144             if(request) {
145                XMLRPC_RequestSetRequestType(request, xmlrpc_request_response);
146             }
147          }
148          else if(!strcmp(el->name, ELEM_METHODNAME)) {
149             if(request) {
150                XMLRPC_RequestSetMethodName(request, el->text.str);
151             }
152          }
153       }
154    }
155    return xCurrent;
156 }
157 
xml_element_to_DANDARPC_VALUE(xml_element * el)158 XMLRPC_VALUE xml_element_to_DANDARPC_VALUE(xml_element* el)
159 {
160    return xml_element_to_DANDARPC_REQUEST_worker(NULL, NULL, el);
161 }
162 
xml_element_to_DANDARPC_REQUEST(XMLRPC_REQUEST request,xml_element * el)163 XMLRPC_VALUE xml_element_to_DANDARPC_REQUEST(XMLRPC_REQUEST request, xml_element* el)
164 {
165    if(request) {
166       return XMLRPC_RequestSetData(request, xml_element_to_DANDARPC_REQUEST_worker(request, NULL, el));
167    }
168    return NULL;
169 }
170 
DANDARPC_to_xml_element_worker(XMLRPC_REQUEST request,XMLRPC_VALUE node)171 xml_element* DANDARPC_to_xml_element_worker(XMLRPC_REQUEST request, XMLRPC_VALUE node) {
172 #define BUF_SIZE 512
173    xml_element* root = NULL;
174    if(node) {
175       char buf[BUF_SIZE];
176       const char* id = XMLRPC_GetValueID(node);
177       XMLRPC_VALUE_TYPE type = XMLRPC_GetValueType(node);
178       XMLRPC_REQUEST_OUTPUT_OPTIONS output = XMLRPC_RequestGetOutputOptions(request);
179       int bNoAddType = (type == xmlrpc_string && request && output && output->xml_elem_opts.verbosity == xml_elem_no_white_space);
180       xml_element* elem_val = xml_elem_new();
181       const char* pAttrType = NULL;
182 
183       xml_element_attr* attr_type = bNoAddType ? NULL : malloc(sizeof(xml_element_attr));
184 
185       if(attr_type) {
186          attr_type->key = strdup(ATTR_TYPE);
187          attr_type->val = 0;
188          Q_PushTail(&elem_val->attrs, attr_type);
189       }
190 
191       elem_val->name = (type == xmlrpc_vector) ? strdup(ATTR_VECTOR) : strdup(ATTR_SCALAR);
192 
193       if(id && *id) {
194          xml_element_attr* attr_id = malloc(sizeof(xml_element_attr));
195          if(attr_id) {
196             attr_id->key = strdup(ATTR_ID);
197             attr_id->val = strdup(id);
198             Q_PushTail(&elem_val->attrs, attr_id);
199          }
200       }
201 
202       switch(type) {
203          case xmlrpc_string:
204             pAttrType = ATTR_STRING;
205             simplestring_addn(&elem_val->text, XMLRPC_GetValueString(node), XMLRPC_GetValueStringLen(node));
206             break;
207          case xmlrpc_int:
208             pAttrType = ATTR_INT;
209             snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueInt(node));
210             simplestring_add(&elem_val->text, buf);
211             break;
212          case xmlrpc_boolean:
213             pAttrType = ATTR_BOOLEAN;
214             snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueBoolean(node));
215             simplestring_add(&elem_val->text, buf);
216             break;
217          case xmlrpc_double:
218             pAttrType = ATTR_DOUBLE;
219             snprintf(buf, BUF_SIZE, "%f", XMLRPC_GetValueDouble(node));
220             simplestring_add(&elem_val->text, buf);
221             break;
222          case xmlrpc_datetime:
223             pAttrType = ATTR_DATETIME;
224             simplestring_add(&elem_val->text, XMLRPC_GetValueDateTime_ISO8601(node));
225             break;
226          case xmlrpc_base64:
227             {
228                struct buffer_st buf;
229                pAttrType = ATTR_BASE64;
230                base64_encode_xmlrpc(&buf, XMLRPC_GetValueBase64(node), XMLRPC_GetValueStringLen(node));
231                simplestring_addn(&elem_val->text, buf.data, buf.offset );
232                buffer_delete(&buf);
233             }
234             break;
235          case xmlrpc_vector:
236             {
237                XMLRPC_VECTOR_TYPE my_type = XMLRPC_GetVectorType(node);
238                XMLRPC_VALUE xIter = XMLRPC_VectorRewind(node);
239 
240                switch(my_type) {
241                   case xmlrpc_vector_array:
242                      pAttrType = ATTR_ARRAY;
243                      break;
244                   case xmlrpc_vector_mixed:
245                      pAttrType = ATTR_MIXED;
246                      break;
247                   case xmlrpc_vector_struct:
248                      pAttrType = ATTR_STRUCT;
249                      break;
250                   default:
251                      break;
252                }
253 
254                /* recurse through sub-elements */
255                while( xIter ) {
256                   xml_element* next_el = DANDARPC_to_xml_element_worker(request, xIter);
257                   if(next_el) {
258                      Q_PushTail(&elem_val->children, next_el);
259                   }
260                   xIter = XMLRPC_VectorNext(node);
261                }
262             }
263             break;
264          default:
265             break;
266       }
267       if(pAttrType && attr_type && !bNoAddType) {
268          attr_type->val = strdup(pAttrType);
269       }
270       root = elem_val;
271    }
272    return root;
273 }
274 
DANDARPC_VALUE_to_xml_element(XMLRPC_VALUE node)275 xml_element* DANDARPC_VALUE_to_xml_element(XMLRPC_VALUE node) {
276    return DANDARPC_to_xml_element_worker(NULL, node);
277 }
278 
DANDARPC_REQUEST_to_xml_element(XMLRPC_REQUEST request)279 xml_element* DANDARPC_REQUEST_to_xml_element(XMLRPC_REQUEST request) {
280    xml_element* wrapper = NULL;
281    xml_element* root = NULL;
282    if(request) {
283       XMLRPC_REQUEST_TYPE request_type = XMLRPC_RequestGetRequestType(request);
284       const char* pStr = NULL;
285       xml_element_attr* version = malloc(sizeof(xml_element_attr));
286       version->key = strdup(ATTR_VERSION);
287       version->val = strdup(VAL_VERSION_0_9);
288 
289       wrapper = xml_elem_new();
290 
291       if(request_type == xmlrpc_request_response) {
292          pStr = ELEM_METHODRESPONSE;
293       }
294       else if(request_type == xmlrpc_request_call) {
295          pStr = ELEM_METHODCALL;
296       }
297       if(pStr) {
298          wrapper->name = strdup(pStr);
299       }
300 
301       root = xml_elem_new();
302       root->name = strdup(ELEM_ROOT);
303       Q_PushTail(&root->attrs, version);
304       Q_PushTail(&root->children, wrapper);
305 
306       pStr = XMLRPC_RequestGetMethodName(request);
307 
308       if(pStr) {
309          xml_element* method = xml_elem_new();
310          method->name = strdup(ELEM_METHODNAME);
311          simplestring_add(&method->text, pStr);
312          Q_PushTail(&wrapper->children, method);
313       }
314       Q_PushTail(&wrapper->children,
315                  DANDARPC_to_xml_element_worker(request, XMLRPC_RequestGetData(request)));
316    }
317    return root;
318 }
319 
320