X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=trunk%2Fphp%2Fxmlrpc%2Flibxmlrpc%2Fxml_to_xmlrpc.c;fp=trunk%2Fphp%2Fxmlrpc%2Flibxmlrpc%2Fxml_to_xmlrpc.c;h=c76b00f2214f38de404ca70f809ee6ff7275adec;hb=5a4c1b1278ffa01e630fde47f7c54888ed20a576;hp=0000000000000000000000000000000000000000;hpb=cee5ab52df1c9f38b6eaff2dd354cb22f59028c7;p=plcapi.git diff --git a/trunk/php/xmlrpc/libxmlrpc/xml_to_xmlrpc.c b/trunk/php/xmlrpc/libxmlrpc/xml_to_xmlrpc.c new file mode 100644 index 0000000..c76b00f --- /dev/null +++ b/trunk/php/xmlrpc/libxmlrpc/xml_to_xmlrpc.c @@ -0,0 +1,413 @@ +/* + This file is part of libXMLRPC - a C library for xml-encoded function calls. + + Author: Dan Libby (dan@libby.com) + Epinions.com may be contacted at feedback@epinions-inc.com +*/ + +/* + Copyright 2000 Epinions, Inc. + + Subject to the following 3 conditions, Epinions, Inc. permits you, free + of charge, to (a) use, copy, distribute, modify, perform and display this + software and associated documentation files (the "Software"), and (b) + permit others to whom the Software is furnished to do so as well. + + 1) The above copyright notice and this permission notice shall be included + without modification in all copies or substantial portions of the + Software. + + 2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF + ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY + IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE OR NONINFRINGEMENT. + + 3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT + OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING + NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH + DAMAGES. + +*/ + + +static const char rcsid[] = "#(@) $Id$"; + +#ifdef _WIN32 +#include "xmlrpc_win32.h" +#endif +#include +#include +#include "xml_to_xmlrpc.h" +#include "base64.h" + +/* list of tokens used in vocab */ +#define ELEM_ARRAY "array" +#define ELEM_BASE64 "base64" +#define ELEM_BOOLEAN "boolean" +#define ELEM_DATA "data" +#define ELEM_DATETIME "dateTime.iso8601" +#define ELEM_DOUBLE "double" +#define ELEM_FAULT "fault" +#define ELEM_FAULTCODE "faultCode" +#define ELEM_FAULTSTRING "faultString" +#define ELEM_I4 "i4" +#define ELEM_INT "int" +#define ELEM_MEMBER "member" +#define ELEM_METHODCALL "methodCall" +#define ELEM_METHODNAME "methodName" +#define ELEM_METHODRESPONSE "methodResponse" +#define ELEM_NAME "name" +#define ELEM_NIL "nil" +#define ELEM_PARAM "param" +#define ELEM_PARAMS "params" +#define ELEM_STRING "string" +#define ELEM_STRUCT "struct" +#define ELEM_VALUE "value" + + +XMLRPC_VALUE xml_element_to_XMLRPC_REQUEST_worker(XMLRPC_REQUEST request, XMLRPC_VALUE parent_vector, XMLRPC_VALUE current_val, xml_element* el) { + if (!current_val) { + /* This should only be the case for the first element */ + current_val = XMLRPC_CreateValueEmpty(); + } + + if (el->name) { + + /* first, deal with the crazy/stupid fault format */ + if (!strcmp(el->name, ELEM_FAULT)) { + xml_element* fault_value = (xml_element*)Q_Head(&el->children); + XMLRPC_SetIsVector(current_val, xmlrpc_vector_struct); + + if(fault_value) { + xml_element* fault_struct = (xml_element*)Q_Head(&fault_value->children); + if(fault_struct) { + xml_element* iter = (xml_element*)Q_Head(&fault_struct->children); + + while (iter) { + XMLRPC_VALUE xNextVal = XMLRPC_CreateValueEmpty(); + xml_element_to_XMLRPC_REQUEST_worker(request, current_val, xNextVal, iter); + XMLRPC_AddValueToVector(current_val, xNextVal); + iter = (xml_element*)Q_Next(&fault_struct->children); + } + } + } + } + else if (!strcmp(el->name, ELEM_DATA) /* should be ELEM_ARRAY, but there is an extra level. weird */ + || (!strcmp(el->name, ELEM_PARAMS) && + (XMLRPC_RequestGetRequestType(request) == xmlrpc_request_call)) ) { /* this "PARAMS" concept is silly. dave?! */ + xml_element* iter = (xml_element*)Q_Head(&el->children); + XMLRPC_SetIsVector(current_val, xmlrpc_vector_array); + + while (iter) { + XMLRPC_VALUE xNextVal = XMLRPC_CreateValueEmpty(); + xml_element_to_XMLRPC_REQUEST_worker(request, current_val, xNextVal, iter); + XMLRPC_AddValueToVector(current_val, xNextVal); + iter = (xml_element*)Q_Next(&el->children); + } + } + else if (!strcmp(el->name, ELEM_STRUCT)) { + xml_element* iter = (xml_element*)Q_Head(&el->children); + XMLRPC_SetIsVector(current_val, xmlrpc_vector_struct); + + while ( iter ) { + XMLRPC_VALUE xNextVal = XMLRPC_CreateValueEmpty(); + xml_element_to_XMLRPC_REQUEST_worker(request, current_val, xNextVal, iter); + XMLRPC_AddValueToVector(current_val, xNextVal); + iter = (xml_element*)Q_Next(&el->children); + } + } + else if (!strcmp(el->name, ELEM_STRING) || + (!strcmp(el->name, ELEM_VALUE) && Q_Size(&el->children) == 0)) { + XMLRPC_SetValueString(current_val, el->text.str, el->text.len); + } + else if (!strcmp(el->name, ELEM_NAME)) { + XMLRPC_SetValueID_Case(current_val, el->text.str, 0, xmlrpc_case_exact); + } + else if (!strcmp(el->name, ELEM_INT) || !strcmp(el->name, ELEM_I4)) { + XMLRPC_SetValueInt(current_val, atoi(el->text.str)); + } + else if (!strcmp(el->name, ELEM_BOOLEAN)) { + XMLRPC_SetValueBoolean(current_val, atoi(el->text.str)); + } + else if (!strcmp(el->name, ELEM_DOUBLE)) { + XMLRPC_SetValueDouble(current_val, atof(el->text.str)); + } + else if (!strcmp(el->name, ELEM_DATETIME)) { + XMLRPC_SetValueDateTime_ISO8601(current_val, el->text.str); + } + else if (!strcmp(el->name, ELEM_BASE64)) { + struct buffer_st buf; + base64_decode(&buf, el->text.str, el->text.len); + XMLRPC_SetValueBase64(current_val, buf.data, buf.offset); + buffer_delete(&buf); + } + else { + xml_element* iter; + + if (!strcmp(el->name, ELEM_METHODCALL)) { + if (request) { + XMLRPC_RequestSetRequestType(request, xmlrpc_request_call); + } + } + else if (!strcmp(el->name, ELEM_METHODRESPONSE)) { + if (request) { + XMLRPC_RequestSetRequestType(request, xmlrpc_request_response); + } + } + else if (!strcmp(el->name, ELEM_METHODNAME)) { + if (request) { + XMLRPC_RequestSetMethodName(request, el->text.str); + } + } + + iter = (xml_element*)Q_Head(&el->children); + while ( iter ) { + xml_element_to_XMLRPC_REQUEST_worker(request, parent_vector, + current_val, iter); + iter = (xml_element*)Q_Next(&el->children); + } + } + } + return current_val; +} + +XMLRPC_VALUE xml_element_to_XMLRPC_VALUE(xml_element* el) +{ + return xml_element_to_XMLRPC_REQUEST_worker(NULL, NULL, NULL, el); +} + +XMLRPC_VALUE xml_element_to_XMLRPC_REQUEST(XMLRPC_REQUEST request, xml_element* el) +{ + if (request) { + return XMLRPC_RequestSetData(request, xml_element_to_XMLRPC_REQUEST_worker(request, NULL, NULL, el)); + } + return NULL; +} + +xml_element* XMLRPC_to_xml_element_worker(XMLRPC_VALUE current_vector, XMLRPC_VALUE node, + XMLRPC_REQUEST_TYPE request_type, int depth) { +#define BUF_SIZE 512 + xml_element* root = NULL; + if (node) { + char buf[BUF_SIZE]; + XMLRPC_VALUE_TYPE type = XMLRPC_GetValueType(node); + XMLRPC_VECTOR_TYPE vtype = XMLRPC_GetVectorType(node); + xml_element* elem_val = xml_elem_new(); + + /* special case for when root element is not an array */ + if (depth == 0 && + !(type == xmlrpc_vector && + vtype == xmlrpc_vector_array && + request_type == xmlrpc_request_call) ) { + int bIsFault = (vtype == xmlrpc_vector_struct && XMLRPC_VectorGetValueWithID(node, ELEM_FAULTCODE)); + + xml_element* next_el = XMLRPC_to_xml_element_worker(NULL, node, request_type, depth + 1); + if (next_el) { + Q_PushTail(&elem_val->children, next_el); + } + elem_val->name = strdup(bIsFault ? ELEM_FAULT : ELEM_PARAMS); + } + else { + switch (type) { + case xmlrpc_empty: /* treat null value as empty string in xmlrpc. */ + case xmlrpc_nil: + elem_val->name = strdup(ELEM_NIL); + break; + case xmlrpc_string: + elem_val->name = strdup(ELEM_STRING); + simplestring_addn(&elem_val->text, XMLRPC_GetValueString(node), XMLRPC_GetValueStringLen(node)); + break; + case xmlrpc_int: + elem_val->name = strdup(ELEM_INT); + snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueInt(node)); + simplestring_add(&elem_val->text, buf); + break; + case xmlrpc_boolean: + elem_val->name = strdup(ELEM_BOOLEAN); + snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueBoolean(node)); + simplestring_add(&elem_val->text, buf); + break; + case xmlrpc_double: + elem_val->name = strdup(ELEM_DOUBLE); + snprintf(buf, BUF_SIZE, "%f", XMLRPC_GetValueDouble(node)); + simplestring_add(&elem_val->text, buf); + break; + case xmlrpc_datetime: + elem_val->name = strdup(ELEM_DATETIME); + simplestring_add(&elem_val->text, XMLRPC_GetValueDateTime_ISO8601(node)); + break; + case xmlrpc_base64: + { + struct buffer_st buf; + elem_val->name = strdup(ELEM_BASE64); + base64_encode(&buf, XMLRPC_GetValueBase64(node), XMLRPC_GetValueStringLen(node)); + simplestring_addn(&elem_val->text, buf.data, buf.offset ); + buffer_delete(&buf); + } + break; + case xmlrpc_vector: + { + XMLRPC_VECTOR_TYPE my_type = XMLRPC_GetVectorType(node); + XMLRPC_VALUE xIter = XMLRPC_VectorRewind(node); + xml_element* root_vector_elem = elem_val; + + switch (my_type) { + case xmlrpc_vector_array: + { + if(depth == 0) { + elem_val->name = strdup(ELEM_PARAMS); + } + else { + /* Hi my name is Dave and I like to make things as confusing + * as possible, thus I will throw in this 'data' element + * where it absolutely does not belong just so that people + * cannot code arrays and structs in a similar and straight + * forward manner. Have a good day. + * + * GRRRRRRRRR! + */ + xml_element* data = xml_elem_new(); + data->name = strdup(ELEM_DATA); + + elem_val->name = strdup(ELEM_ARRAY); + Q_PushTail(&elem_val->children, data); + root_vector_elem = data; + } + } + break; + case xmlrpc_vector_mixed: /* not officially supported */ + case xmlrpc_vector_struct: + elem_val->name = strdup(ELEM_STRUCT); + break; + default: + break; + } + + /* recurse through sub-elements */ + while ( xIter ) { + xml_element* next_el = XMLRPC_to_xml_element_worker(node, xIter, request_type, depth + 1); + if (next_el) { + Q_PushTail(&root_vector_elem->children, next_el); + } + xIter = XMLRPC_VectorNext(node); + } + } + break; + default: + break; + } + } + + { + XMLRPC_VECTOR_TYPE vtype = XMLRPC_GetVectorType(current_vector); + + if (depth == 1) { + xml_element* value = xml_elem_new(); + value->name = strdup(ELEM_VALUE); + + /* yet another hack for the "fault" crap */ + if (XMLRPC_VectorGetValueWithID(node, ELEM_FAULTCODE)) { + root = value; + } + else { + xml_element* param = xml_elem_new(); + param->name = strdup(ELEM_PARAM); + + Q_PushTail(¶m->children, value); + + root = param; + } + Q_PushTail(&value->children, elem_val); + } + else if (vtype == xmlrpc_vector_struct || vtype == xmlrpc_vector_mixed) { + xml_element* member = xml_elem_new(); + xml_element* name = xml_elem_new(); + xml_element* value = xml_elem_new(); + + member->name = strdup(ELEM_MEMBER); + name->name = strdup(ELEM_NAME); + value->name = strdup(ELEM_VALUE); + + simplestring_add(&name->text, XMLRPC_GetValueID(node)); + + Q_PushTail(&member->children, name); + Q_PushTail(&member->children, value); + Q_PushTail(&value->children, elem_val); + + root = member; + } + else if (vtype == xmlrpc_vector_array) { + xml_element* value = xml_elem_new(); + + value->name = strdup(ELEM_VALUE); + + Q_PushTail(&value->children, elem_val); + + root = value; + } + else if (vtype == xmlrpc_vector_none) { + /* no parent. non-op */ + root = elem_val; + } + else { + xml_element* value = xml_elem_new(); + + value->name = strdup(ELEM_VALUE); + + Q_PushTail(&value->children, elem_val); + + root = value; + } + } + } + return root; +} + +xml_element* XMLRPC_VALUE_to_xml_element(XMLRPC_VALUE node) { + return XMLRPC_to_xml_element_worker(NULL, node, xmlrpc_request_none, 0); +} + +xml_element* XMLRPC_REQUEST_to_xml_element(XMLRPC_REQUEST request) { + xml_element* wrapper = NULL; + if (request) { + const char* pStr = NULL; + XMLRPC_REQUEST_TYPE request_type = XMLRPC_RequestGetRequestType(request); + XMLRPC_VALUE xParams = XMLRPC_RequestGetData(request); + + wrapper = xml_elem_new(); + + if (request_type == xmlrpc_request_call) { + pStr = ELEM_METHODCALL; + } + else if (request_type == xmlrpc_request_response) { + pStr = ELEM_METHODRESPONSE; + } + if (pStr) { + wrapper->name = strdup(pStr); + } + + if(request_type == xmlrpc_request_call) { + pStr = XMLRPC_RequestGetMethodName(request); + + if (pStr) { + xml_element* method = xml_elem_new(); + method->name = strdup(ELEM_METHODNAME); + simplestring_add(&method->text, pStr); + Q_PushTail(&wrapper->children, method); + } + } + if (xParams) { + Q_PushTail(&wrapper->children, + XMLRPC_to_xml_element_worker(NULL, XMLRPC_RequestGetData(request), XMLRPC_RequestGetRequestType(request), 0)); + } + else { + /* Despite the spec, the xml-rpc list folk want me to send an empty params element */ + xml_element* params = xml_elem_new(); + params->name = strdup(ELEM_PARAMS); + Q_PushTail(&wrapper->children, params); + } + } + return wrapper; +} +