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