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 #include <string.h>
34 #include <stdlib.h>
35 #include "xml_to_dandarpc.h"
36 #include "base64.h"
37
38 /* list of tokens used in vocab */
39 #define ELEM_METHODCALL "methodCall"
40 #define ELEM_METHODNAME "methodName"
41 #define ELEM_METHODRESPONSE "methodResponse"
42 #define ELEM_ROOT "simpleRPC"
43
44 #define ATTR_ARRAY "array"
45 #define ATTR_BASE64 "base64"
46 #define ATTR_BOOLEAN "boolean"
47 #define ATTR_DATETIME "dateTime.iso8601"
48 #define ATTR_DOUBLE "double"
49 #define ATTR_ID "id"
50 #define ATTR_INT "int"
51 #define ATTR_MIXED "mixed"
52 #define ATTR_SCALAR "scalar"
53 #define ATTR_STRING "string"
54 #define ATTR_STRUCT "struct"
55 #define ATTR_TYPE "type"
56 #define ATTR_VECTOR "vector"
57 #define ATTR_VERSION "version"
58
59 #define VAL_VERSION_0_9 "0.9"
60
61
xml_element_to_DANDARPC_REQUEST_worker(XMLRPC_REQUEST request,XMLRPC_VALUE xCurrent,xml_element * el)62 XMLRPC_VALUE xml_element_to_DANDARPC_REQUEST_worker(XMLRPC_REQUEST request, XMLRPC_VALUE xCurrent, xml_element* el) {
63 if(!xCurrent) {
64 xCurrent = XMLRPC_CreateValueEmpty();
65 }
66
67 if(el->name) {
68 const char* id = NULL;
69 const char* type = NULL;
70 xml_element_attr* attr_iter = Q_Head(&el->attrs);
71
72 while(attr_iter) {
73 if(!strcmp(attr_iter->key, ATTR_ID)) {
74 id = attr_iter->val;
75 }
76 if(!strcmp(attr_iter->key, ATTR_TYPE)) {
77 type = attr_iter->val;
78 }
79 attr_iter = Q_Next(&el->attrs);
80 }
81
82 if(id) {
83 XMLRPC_SetValueID_Case(xCurrent, id, 0, xmlrpc_case_exact);
84 }
85
86 if(!strcmp(el->name, ATTR_SCALAR)) {
87 if(!type || !strcmp(type, ATTR_STRING)) {
88 XMLRPC_SetValueString(xCurrent, el->text.str, el->text.len);
89 }
90 else if(!strcmp(type, ATTR_INT)) {
91 XMLRPC_SetValueInt(xCurrent, atoi(el->text.str));
92 }
93 else if(!strcmp(type, ATTR_BOOLEAN)) {
94 XMLRPC_SetValueBoolean(xCurrent, atoi(el->text.str));
95 }
96 else if(!strcmp(type, ATTR_DOUBLE)) {
97 XMLRPC_SetValueDouble(xCurrent, atof(el->text.str));
98 }
99 else if(!strcmp(type, ATTR_DATETIME)) {
100 XMLRPC_SetValueDateTime_ISO8601(xCurrent, el->text.str);
101 }
102 else if(!strcmp(type, ATTR_BASE64)) {
103 struct buffer_st buf;
104 base64_decode_xmlrpc(&buf, el->text.str, el->text.len);
105 XMLRPC_SetValueBase64(xCurrent, buf.data, buf.offset);
106 buffer_delete(&buf);
107 }
108 }
109 else if(!strcmp(el->name, ATTR_VECTOR)) {
110 xml_element* iter = (xml_element*)Q_Head(&el->children);
111
112 if(!type || !strcmp(type, ATTR_MIXED)) {
113 XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_mixed);
114 }
115 else if(!strcmp(type, ATTR_ARRAY)) {
116 XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_array);
117 }
118 else if(!strcmp(type, ATTR_STRUCT)) {
119 XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_struct);
120 }
121 while( iter ) {
122 XMLRPC_VALUE xNext = XMLRPC_CreateValueEmpty();
123 xml_element_to_DANDARPC_REQUEST_worker(request, xNext, iter);
124 XMLRPC_AddValueToVector(xCurrent, xNext);
125 iter = (xml_element*)Q_Next(&el->children);
126 }
127 }
128 else {
129 xml_element* iter = (xml_element*)Q_Head(&el->children);
130 while( iter ) {
131 xml_element_to_DANDARPC_REQUEST_worker(request, xCurrent, iter);
132 iter = (xml_element*)Q_Next(&el->children);
133 }
134
135 if(!strcmp(el->name, ELEM_METHODCALL)) {
136 if(request) {
137 XMLRPC_RequestSetRequestType(request, xmlrpc_request_call);
138 }
139 }
140 else if(!strcmp(el->name, ELEM_METHODRESPONSE)) {
141 if(request) {
142 XMLRPC_RequestSetRequestType(request, xmlrpc_request_response);
143 }
144 }
145 else if(!strcmp(el->name, ELEM_METHODNAME)) {
146 if(request) {
147 XMLRPC_RequestSetMethodName(request, el->text.str);
148 }
149 }
150 }
151 }
152 return xCurrent;
153 }
154
xml_element_to_DANDARPC_VALUE(xml_element * el)155 XMLRPC_VALUE xml_element_to_DANDARPC_VALUE(xml_element* el)
156 {
157 return xml_element_to_DANDARPC_REQUEST_worker(NULL, NULL, el);
158 }
159
xml_element_to_DANDARPC_REQUEST(XMLRPC_REQUEST request,xml_element * el)160 XMLRPC_VALUE xml_element_to_DANDARPC_REQUEST(XMLRPC_REQUEST request, xml_element* el)
161 {
162 if(request) {
163 return XMLRPC_RequestSetData(request, xml_element_to_DANDARPC_REQUEST_worker(request, NULL, el));
164 }
165 return NULL;
166 }
167
DANDARPC_to_xml_element_worker(XMLRPC_REQUEST request,XMLRPC_VALUE node)168 xml_element* DANDARPC_to_xml_element_worker(XMLRPC_REQUEST request, XMLRPC_VALUE node) {
169 #define BUF_SIZE 512
170 xml_element* root = NULL;
171 if(node) {
172 char buf[BUF_SIZE];
173 const char* id = XMLRPC_GetValueID(node);
174 XMLRPC_VALUE_TYPE type = XMLRPC_GetValueType(node);
175 XMLRPC_REQUEST_OUTPUT_OPTIONS output = XMLRPC_RequestGetOutputOptions(request);
176 int bNoAddType = (type == xmlrpc_string && request && output && output->xml_elem_opts.verbosity == xml_elem_no_white_space);
177 xml_element* elem_val = xml_elem_new();
178 const char* pAttrType = NULL;
179
180 xml_element_attr* attr_type = bNoAddType ? NULL : emalloc(sizeof(xml_element_attr));
181
182 if(attr_type) {
183 attr_type->key = estrdup(ATTR_TYPE);
184 attr_type->val = 0;
185 Q_PushTail(&elem_val->attrs, attr_type);
186 }
187
188 elem_val->name = (type == xmlrpc_vector) ? estrdup(ATTR_VECTOR) : estrdup(ATTR_SCALAR);
189
190 if(id && *id) {
191 xml_element_attr* attr_id = emalloc(sizeof(xml_element_attr));
192 if(attr_id) {
193 attr_id->key = estrdup(ATTR_ID);
194 attr_id->val = estrdup(id);
195 Q_PushTail(&elem_val->attrs, attr_id);
196 }
197 }
198
199 switch(type) {
200 case xmlrpc_string:
201 pAttrType = ATTR_STRING;
202 simplestring_addn(&elem_val->text, XMLRPC_GetValueString(node), XMLRPC_GetValueStringLen(node));
203 break;
204 case xmlrpc_int:
205 pAttrType = ATTR_INT;
206 snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueInt(node));
207 simplestring_add(&elem_val->text, buf);
208 break;
209 case xmlrpc_boolean:
210 pAttrType = ATTR_BOOLEAN;
211 snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueBoolean(node));
212 simplestring_add(&elem_val->text, buf);
213 break;
214 case xmlrpc_double:
215 pAttrType = ATTR_DOUBLE;
216 snprintf(buf, BUF_SIZE, "%f", XMLRPC_GetValueDouble(node));
217 simplestring_add(&elem_val->text, buf);
218 break;
219 case xmlrpc_datetime:
220 pAttrType = ATTR_DATETIME;
221 simplestring_add(&elem_val->text, XMLRPC_GetValueDateTime_ISO8601(node));
222 break;
223 case xmlrpc_base64:
224 {
225 struct buffer_st buf;
226 pAttrType = ATTR_BASE64;
227 base64_encode_xmlrpc(&buf, XMLRPC_GetValueBase64(node), XMLRPC_GetValueStringLen(node));
228 simplestring_addn(&elem_val->text, buf.data, buf.offset );
229 buffer_delete(&buf);
230 }
231 break;
232 case xmlrpc_vector:
233 {
234 XMLRPC_VECTOR_TYPE my_type = XMLRPC_GetVectorType(node);
235 XMLRPC_VALUE xIter = XMLRPC_VectorRewind(node);
236
237 switch(my_type) {
238 case xmlrpc_vector_array:
239 pAttrType = ATTR_ARRAY;
240 break;
241 case xmlrpc_vector_mixed:
242 pAttrType = ATTR_MIXED;
243 break;
244 case xmlrpc_vector_struct:
245 pAttrType = ATTR_STRUCT;
246 break;
247 default:
248 break;
249 }
250
251 /* recurse through sub-elements */
252 while( xIter ) {
253 xml_element* next_el = DANDARPC_to_xml_element_worker(request, xIter);
254 if(next_el) {
255 Q_PushTail(&elem_val->children, next_el);
256 }
257 xIter = XMLRPC_VectorNext(node);
258 }
259 }
260 break;
261 default:
262 break;
263 }
264 if(pAttrType && attr_type && !bNoAddType) {
265 attr_type->val = estrdup(pAttrType);
266 }
267 root = elem_val;
268 }
269 return root;
270 }
271
DANDARPC_VALUE_to_xml_element(XMLRPC_VALUE node)272 xml_element* DANDARPC_VALUE_to_xml_element(XMLRPC_VALUE node) {
273 return DANDARPC_to_xml_element_worker(NULL, node);
274 }
275
DANDARPC_REQUEST_to_xml_element(XMLRPC_REQUEST request)276 xml_element* DANDARPC_REQUEST_to_xml_element(XMLRPC_REQUEST request) {
277 xml_element* wrapper = NULL;
278 xml_element* root = NULL;
279 if(request) {
280 XMLRPC_REQUEST_TYPE request_type = XMLRPC_RequestGetRequestType(request);
281 const char* pStr = NULL;
282 xml_element_attr* version = emalloc(sizeof(xml_element_attr));
283 version->key = estrdup(ATTR_VERSION);
284 version->val = estrdup(VAL_VERSION_0_9);
285
286 wrapper = xml_elem_new();
287
288 if(request_type == xmlrpc_request_response) {
289 pStr = ELEM_METHODRESPONSE;
290 }
291 else if(request_type == xmlrpc_request_call) {
292 pStr = ELEM_METHODCALL;
293 }
294 if(pStr) {
295 wrapper->name = estrdup(pStr);
296 }
297
298 root = xml_elem_new();
299 root->name = estrdup(ELEM_ROOT);
300 Q_PushTail(&root->attrs, version);
301 Q_PushTail(&root->children, wrapper);
302
303 pStr = XMLRPC_RequestGetMethodName(request);
304
305 if(pStr) {
306 xml_element* method = xml_elem_new();
307 method->name = estrdup(ELEM_METHODNAME);
308 simplestring_add(&method->text, pStr);
309 Q_PushTail(&wrapper->children, method);
310 }
311 Q_PushTail(&wrapper->children,
312 DANDARPC_to_xml_element_worker(request, XMLRPC_RequestGetData(request)));
313 }
314 return root;
315 }
316