Annotation of embedaddon/php/ext/xmlrpc/libxmlrpc/xml_to_xmlrpc.c, revision 1.1.1.2
1.1 misho 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:
1.1.1.2 ! misho 34: static const char rcsid[] = "#(@) $Id$";
1.1 misho 35:
36: #include "php.h"
37: #include "main/snprintf.h"
38: #ifdef _WIN32
39: #include "xmlrpc_win32.h"
40: #endif
41: #include <string.h>
42: #include <stdlib.h>
43: #include "xml_to_xmlrpc.h"
44: #include "base64.h"
45:
46: /* list of tokens used in vocab */
47: #define ELEM_ARRAY "array"
48: #define ELEM_BASE64 "base64"
49: #define ELEM_BOOLEAN "boolean"
50: #define ELEM_DATA "data"
51: #define ELEM_DATETIME "dateTime.iso8601"
52: #define ELEM_DOUBLE "double"
53: #define ELEM_FAULT "fault"
54: #define ELEM_FAULTCODE "faultCode"
55: #define ELEM_FAULTSTRING "faultString"
56: #define ELEM_I4 "i4"
57: #define ELEM_INT "int"
58: #define ELEM_MEMBER "member"
59: #define ELEM_METHODCALL "methodCall"
60: #define ELEM_METHODNAME "methodName"
61: #define ELEM_METHODRESPONSE "methodResponse"
62: #define ELEM_NAME "name"
63: #define ELEM_PARAM "param"
64: #define ELEM_PARAMS "params"
65: #define ELEM_STRING "string"
66: #define ELEM_STRUCT "struct"
67: #define ELEM_VALUE "value"
68:
69:
70: XMLRPC_VALUE xml_element_to_XMLRPC_REQUEST_worker(XMLRPC_REQUEST request, XMLRPC_VALUE parent_vector, XMLRPC_VALUE current_val, xml_element* el) {
71: if (!current_val) {
72: /* This should only be the case for the first element */
73: current_val = XMLRPC_CreateValueEmpty();
74: }
75:
76: if (el->name) {
77:
78: /* first, deal with the crazy/stupid fault format */
79: if (!strcmp(el->name, ELEM_FAULT)) {
80: xml_element* fault_value = (xml_element*)Q_Head(&el->children);
81: XMLRPC_SetIsVector(current_val, xmlrpc_vector_struct);
82:
83: if(fault_value) {
84: xml_element* fault_struct = (xml_element*)Q_Head(&fault_value->children);
85: if(fault_struct) {
86: xml_element* iter = (xml_element*)Q_Head(&fault_struct->children);
87:
88: while (iter) {
89: XMLRPC_VALUE xNextVal = XMLRPC_CreateValueEmpty();
90: xml_element_to_XMLRPC_REQUEST_worker(request, current_val, xNextVal, iter);
91: XMLRPC_AddValueToVector(current_val, xNextVal);
92: iter = (xml_element*)Q_Next(&fault_struct->children);
93: }
94: }
95: }
96: }
97: else if (!strcmp(el->name, ELEM_DATA) /* should be ELEM_ARRAY, but there is an extra level. weird */
98: || (!strcmp(el->name, ELEM_PARAMS) &&
99: (XMLRPC_RequestGetRequestType(request) == xmlrpc_request_call)) ) { /* this "PARAMS" concept is silly. dave?! */
100: xml_element* iter = (xml_element*)Q_Head(&el->children);
101: XMLRPC_SetIsVector(current_val, xmlrpc_vector_array);
102:
103: while (iter) {
104: XMLRPC_VALUE xNextVal = XMLRPC_CreateValueEmpty();
105: xml_element_to_XMLRPC_REQUEST_worker(request, current_val, xNextVal, iter);
106: XMLRPC_AddValueToVector(current_val, xNextVal);
107: iter = (xml_element*)Q_Next(&el->children);
108: }
109: }
110: else if (!strcmp(el->name, ELEM_STRUCT)) {
111: xml_element* iter = (xml_element*)Q_Head(&el->children);
112: XMLRPC_SetIsVector(current_val, xmlrpc_vector_struct);
113:
114: while ( iter ) {
115: XMLRPC_VALUE xNextVal = XMLRPC_CreateValueEmpty();
116: xml_element_to_XMLRPC_REQUEST_worker(request, current_val, xNextVal, iter);
117: XMLRPC_AddValueToVector(current_val, xNextVal);
118: iter = (xml_element*)Q_Next(&el->children);
119: }
120: }
121: else if (!strcmp(el->name, ELEM_STRING) ||
122: (!strcmp(el->name, ELEM_VALUE) && Q_Size(&el->children) == 0)) {
123: XMLRPC_SetValueString(current_val, el->text.str, el->text.len);
124: }
125: else if (!strcmp(el->name, ELEM_NAME)) {
126: XMLRPC_SetValueID_Case(current_val, el->text.str, 0, xmlrpc_case_exact);
127: }
128: else if (!strcmp(el->name, ELEM_INT) || !strcmp(el->name, ELEM_I4)) {
129: XMLRPC_SetValueInt(current_val, atoi(el->text.str));
130: }
131: else if (!strcmp(el->name, ELEM_BOOLEAN)) {
132: XMLRPC_SetValueBoolean(current_val, atoi(el->text.str));
133: }
134: else if (!strcmp(el->name, ELEM_DOUBLE)) {
135: XMLRPC_SetValueDouble(current_val, atof(el->text.str));
136: }
137: else if (!strcmp(el->name, ELEM_DATETIME)) {
138: XMLRPC_SetValueDateTime_ISO8601(current_val, el->text.str);
139: }
140: else if (!strcmp(el->name, ELEM_BASE64)) {
141: struct buffer_st buf;
142: base64_decode_xmlrpc(&buf, el->text.str, el->text.len);
143: XMLRPC_SetValueBase64(current_val, buf.data, buf.offset);
144: buffer_delete(&buf);
145: }
146: else {
147: xml_element* iter;
148:
149: if (!strcmp(el->name, ELEM_METHODCALL)) {
150: if (request) {
151: XMLRPC_RequestSetRequestType(request, xmlrpc_request_call);
152: }
153: }
154: else if (!strcmp(el->name, ELEM_METHODRESPONSE)) {
155: if (request) {
156: XMLRPC_RequestSetRequestType(request, xmlrpc_request_response);
157: }
158: }
159: else if (!strcmp(el->name, ELEM_METHODNAME)) {
160: if (request) {
161: XMLRPC_RequestSetMethodName(request, el->text.str);
162: }
163: }
164:
165: iter = (xml_element*)Q_Head(&el->children);
166: while ( iter ) {
167: xml_element_to_XMLRPC_REQUEST_worker(request, parent_vector,
168: current_val, iter);
169: iter = (xml_element*)Q_Next(&el->children);
170: }
171: }
172: }
173: return current_val;
174: }
175:
176: XMLRPC_VALUE xml_element_to_XMLRPC_VALUE(xml_element* el)
177: {
178: return xml_element_to_XMLRPC_REQUEST_worker(NULL, NULL, NULL, el);
179: }
180:
181: XMLRPC_VALUE xml_element_to_XMLRPC_REQUEST(XMLRPC_REQUEST request, xml_element* el)
182: {
183: if (request) {
184: return XMLRPC_RequestSetData(request, xml_element_to_XMLRPC_REQUEST_worker(request, NULL, NULL, el));
185: }
186: return NULL;
187: }
188:
189: xml_element* XMLRPC_to_xml_element_worker(XMLRPC_VALUE current_vector, XMLRPC_VALUE node,
190: XMLRPC_REQUEST_TYPE request_type, int depth) {
191: #define BUF_SIZE 512
192: xml_element* root = NULL;
193: if (node) {
194: char buf[BUF_SIZE];
195: XMLRPC_VALUE_TYPE type = XMLRPC_GetValueType(node);
196: XMLRPC_VECTOR_TYPE vtype = XMLRPC_GetVectorType(node);
197: xml_element* elem_val = xml_elem_new();
198:
199: /* special case for when root element is not an array */
200: if (depth == 0 &&
201: !(type == xmlrpc_vector &&
202: vtype == xmlrpc_vector_array &&
203: request_type == xmlrpc_request_call) ) {
204: int bIsFault = (vtype == xmlrpc_vector_struct && XMLRPC_VectorGetValueWithID(node, ELEM_FAULTCODE));
205:
206: xml_element* next_el = XMLRPC_to_xml_element_worker(NULL, node, request_type, depth + 1);
207: if (next_el) {
208: Q_PushTail(&elem_val->children, next_el);
209: }
210: elem_val->name = strdup(bIsFault ? ELEM_FAULT : ELEM_PARAMS);
211: }
212: else {
213: switch (type) {
214: case xmlrpc_empty: /* treat null value as empty string in xmlrpc. */
215: case xmlrpc_string:
216: elem_val->name = strdup(ELEM_STRING);
217: simplestring_addn(&elem_val->text, XMLRPC_GetValueString(node), XMLRPC_GetValueStringLen(node));
218: break;
219: case xmlrpc_int:
220: elem_val->name = strdup(ELEM_INT);
221: snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueInt(node));
222: simplestring_add(&elem_val->text, buf);
223: break;
224: case xmlrpc_boolean:
225: elem_val->name = strdup(ELEM_BOOLEAN);
226: snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueBoolean(node));
227: simplestring_add(&elem_val->text, buf);
228: break;
229: case xmlrpc_double:
230: {
231: TSRMLS_FETCH();
232: elem_val->name = strdup(ELEM_DOUBLE);
233: ap_php_snprintf(buf, BUF_SIZE, "%.*G", (int) EG(precision), XMLRPC_GetValueDouble(node));
234: simplestring_add(&elem_val->text, buf);
235: }
236: break;
237: case xmlrpc_datetime:
238: elem_val->name = strdup(ELEM_DATETIME);
239: simplestring_add(&elem_val->text, XMLRPC_GetValueDateTime_ISO8601(node));
240: break;
241: case xmlrpc_base64:
242: {
243: struct buffer_st buf;
244: elem_val->name = strdup(ELEM_BASE64);
245: base64_encode_xmlrpc(&buf, XMLRPC_GetValueBase64(node), XMLRPC_GetValueStringLen(node));
246: simplestring_addn(&elem_val->text, buf.data, buf.offset );
247: buffer_delete(&buf);
248: }
249: break;
250: case xmlrpc_vector:
251: {
252: XMLRPC_VECTOR_TYPE my_type = XMLRPC_GetVectorType(node);
253: XMLRPC_VALUE xIter = XMLRPC_VectorRewind(node);
254: xml_element* root_vector_elem = elem_val;
255:
256: switch (my_type) {
257: case xmlrpc_vector_array:
258: {
259: if(depth == 0) {
260: elem_val->name = strdup(ELEM_PARAMS);
261: }
262: else {
263: /* Hi my name is Dave and I like to make things as confusing
264: * as possible, thus I will throw in this 'data' element
265: * where it absolutely does not belong just so that people
266: * cannot code arrays and structs in a similar and straight
267: * forward manner. Have a good day.
268: *
269: * GRRRRRRRRR!
270: */
271: xml_element* data = xml_elem_new();
272: data->name = strdup(ELEM_DATA);
273:
274: elem_val->name = strdup(ELEM_ARRAY);
275: Q_PushTail(&elem_val->children, data);
276: root_vector_elem = data;
277: }
278: }
279: break;
280: case xmlrpc_vector_mixed: /* not officially supported */
281: case xmlrpc_vector_struct:
282: elem_val->name = strdup(ELEM_STRUCT);
283: break;
284: default:
285: break;
286: }
287:
288: /* recurse through sub-elements */
289: while ( xIter ) {
290: xml_element* next_el = XMLRPC_to_xml_element_worker(node, xIter, request_type, depth + 1);
291: if (next_el) {
292: Q_PushTail(&root_vector_elem->children, next_el);
293: }
294: xIter = XMLRPC_VectorNext(node);
295: }
296: }
297: break;
298: default:
299: break;
300: }
301: }
302:
303: {
304: XMLRPC_VECTOR_TYPE vtype = XMLRPC_GetVectorType(current_vector);
305:
306: if (depth == 1) {
307: xml_element* value = xml_elem_new();
308: value->name = strdup(ELEM_VALUE);
309:
310: /* yet another hack for the "fault" crap */
311: if (XMLRPC_VectorGetValueWithID(node, ELEM_FAULTCODE)) {
312: root = value;
313: }
314: else {
315: xml_element* param = xml_elem_new();
316: param->name = strdup(ELEM_PARAM);
317:
318: Q_PushTail(¶m->children, value);
319:
320: root = param;
321: }
322: Q_PushTail(&value->children, elem_val);
323: }
324: else if (vtype == xmlrpc_vector_struct || vtype == xmlrpc_vector_mixed) {
325: xml_element* member = xml_elem_new();
326: xml_element* name = xml_elem_new();
327: xml_element* value = xml_elem_new();
328:
329: member->name = strdup(ELEM_MEMBER);
330: name->name = strdup(ELEM_NAME);
331: value->name = strdup(ELEM_VALUE);
332:
333: simplestring_add(&name->text, XMLRPC_GetValueID(node));
334:
335: Q_PushTail(&member->children, name);
336: Q_PushTail(&member->children, value);
337: Q_PushTail(&value->children, elem_val);
338:
339: root = member;
340: }
341: else if (vtype == xmlrpc_vector_array) {
342: xml_element* value = xml_elem_new();
343:
344: value->name = strdup(ELEM_VALUE);
345:
346: Q_PushTail(&value->children, elem_val);
347:
348: root = value;
349: }
350: else if (vtype == xmlrpc_vector_none) {
351: /* no parent. non-op */
352: root = elem_val;
353: }
354: else {
355: xml_element* value = xml_elem_new();
356:
357: value->name = strdup(ELEM_VALUE);
358:
359: Q_PushTail(&value->children, elem_val);
360:
361: root = value;
362: }
363: }
364: }
365: return root;
366: }
367:
368: xml_element* XMLRPC_VALUE_to_xml_element(XMLRPC_VALUE node) {
369: return XMLRPC_to_xml_element_worker(NULL, node, xmlrpc_request_none, 0);
370: }
371:
372: xml_element* XMLRPC_REQUEST_to_xml_element(XMLRPC_REQUEST request) {
373: xml_element* wrapper = NULL;
374: if (request) {
375: const char* pStr = NULL;
376: XMLRPC_REQUEST_TYPE request_type = XMLRPC_RequestGetRequestType(request);
377: XMLRPC_VALUE xParams = XMLRPC_RequestGetData(request);
378:
379: wrapper = xml_elem_new();
380:
381: if (request_type == xmlrpc_request_call) {
382: pStr = ELEM_METHODCALL;
383: }
384: else if (request_type == xmlrpc_request_response) {
385: pStr = ELEM_METHODRESPONSE;
386: }
387: if (pStr) {
388: wrapper->name = strdup(pStr);
389: }
390:
391: if(request_type == xmlrpc_request_call) {
392: pStr = XMLRPC_RequestGetMethodName(request);
393:
394: if (pStr) {
395: xml_element* method = xml_elem_new();
396: method->name = strdup(ELEM_METHODNAME);
397: simplestring_add(&method->text, pStr);
398: Q_PushTail(&wrapper->children, method);
399: }
400: }
401: if (xParams) {
402: Q_PushTail(&wrapper->children,
403: XMLRPC_to_xml_element_worker(NULL, XMLRPC_RequestGetData(request), XMLRPC_RequestGetRequestType(request), 0));
404: }
405: else {
406: /* Despite the spec, the xml-rpc list folk want me to send an empty params element */
407: xml_element* params = xml_elem_new();
408: params->name = strdup(ELEM_PARAMS);
409: Q_PushTail(&wrapper->children, params);
410: }
411: }
412: return wrapper;
413: }
414:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>