Back to index

php5  5.3.10
xml_to_xmlrpc.c
Go to the documentation of this file.
00001 /*
00002   This file is part of libXMLRPC - a C library for xml-encoded function calls.
00003 
00004   Author: Dan Libby (dan@libby.com)
00005   Epinions.com may be contacted at feedback@epinions-inc.com
00006 */
00007 
00008 /*  
00009   Copyright 2000 Epinions, Inc. 
00010 
00011   Subject to the following 3 conditions, Epinions, Inc.  permits you, free 
00012   of charge, to (a) use, copy, distribute, modify, perform and display this 
00013   software and associated documentation files (the "Software"), and (b) 
00014   permit others to whom the Software is furnished to do so as well.  
00015 
00016   1) The above copyright notice and this permission notice shall be included 
00017   without modification in all copies or substantial portions of the 
00018   Software.  
00019 
00020   2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF 
00021   ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY 
00022   IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR 
00023   PURPOSE OR NONINFRINGEMENT.  
00024 
00025   3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, 
00026   SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT 
00027   OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING 
00028   NEGLIGENCE), EVEN IF EPINIONS, INC.  IS AWARE OF THE POSSIBILITY OF SUCH 
00029   DAMAGES.    
00030 
00031 */
00032 
00033 
00034 static const char rcsid[] = "#(@) $Id: xml_to_xmlrpc.c 242949 2007-09-26 15:44:16Z cvs2svn $";
00035 
00036 #include "php.h"
00037 #include "main/snprintf.h"
00038 #ifdef _WIN32
00039 #include "xmlrpc_win32.h"
00040 #endif
00041 #include <string.h>
00042 #include <stdlib.h>
00043 #include "xml_to_xmlrpc.h"
00044 #include "base64.h"
00045 
00046 /* list of tokens used in vocab */
00047 #define ELEM_ARRAY          "array"
00048 #define ELEM_BASE64         "base64"
00049 #define ELEM_BOOLEAN        "boolean"
00050 #define ELEM_DATA           "data"
00051 #define ELEM_DATETIME       "dateTime.iso8601"
00052 #define ELEM_DOUBLE         "double"
00053 #define ELEM_FAULT          "fault"
00054 #define ELEM_FAULTCODE      "faultCode"
00055 #define ELEM_FAULTSTRING    "faultString"
00056 #define ELEM_I4             "i4"
00057 #define ELEM_INT            "int"
00058 #define ELEM_MEMBER         "member"
00059 #define ELEM_METHODCALL     "methodCall"
00060 #define ELEM_METHODNAME     "methodName"
00061 #define ELEM_METHODRESPONSE "methodResponse"
00062 #define ELEM_NAME           "name"
00063 #define ELEM_PARAM          "param"
00064 #define ELEM_PARAMS         "params"
00065 #define ELEM_STRING         "string"
00066 #define ELEM_STRUCT         "struct"
00067 #define ELEM_VALUE          "value"
00068 
00069 
00070 XMLRPC_VALUE xml_element_to_XMLRPC_REQUEST_worker(XMLRPC_REQUEST request, XMLRPC_VALUE parent_vector, XMLRPC_VALUE current_val, xml_element* el) {
00071    if (!current_val) {
00072       /* This should only be the case for the first element */
00073       current_val = XMLRPC_CreateValueEmpty();
00074    }
00075 
00076        if (el->name) {
00077 
00078       /* first, deal with the crazy/stupid fault format */
00079       if (!strcmp(el->name, ELEM_FAULT)) {
00080                      xml_element* fault_value = (xml_element*)Q_Head(&el->children);
00081                      XMLRPC_SetIsVector(current_val, xmlrpc_vector_struct);
00082 
00083          if(fault_value) {
00084             xml_element* fault_struct = (xml_element*)Q_Head(&fault_value->children);
00085             if(fault_struct) {
00086                xml_element* iter = (xml_element*)Q_Head(&fault_struct->children);
00087 
00088                while (iter) {
00089                   XMLRPC_VALUE xNextVal = XMLRPC_CreateValueEmpty();
00090                   xml_element_to_XMLRPC_REQUEST_worker(request, current_val, xNextVal, iter);
00091                   XMLRPC_AddValueToVector(current_val, xNextVal);
00092                   iter = (xml_element*)Q_Next(&fault_struct->children);
00093                }
00094             }
00095          }
00096       }
00097               else if (!strcmp(el->name, ELEM_DATA)     /* should be ELEM_ARRAY, but there is an extra level. weird */
00098                       || (!strcmp(el->name, ELEM_PARAMS) && 
00099                               (XMLRPC_RequestGetRequestType(request) == xmlrpc_request_call)) ) {        /* this "PARAMS" concept is silly.  dave?! */
00100          xml_element* iter = (xml_element*)Q_Head(&el->children);
00101          XMLRPC_SetIsVector(current_val, xmlrpc_vector_array);
00102 
00103          while (iter) {
00104             XMLRPC_VALUE xNextVal = XMLRPC_CreateValueEmpty();
00105             xml_element_to_XMLRPC_REQUEST_worker(request, current_val, xNextVal, iter);
00106             XMLRPC_AddValueToVector(current_val, xNextVal);
00107             iter = (xml_element*)Q_Next(&el->children);
00108          }
00109               }
00110               else if (!strcmp(el->name, ELEM_STRUCT)) {
00111          xml_element* iter = (xml_element*)Q_Head(&el->children);
00112          XMLRPC_SetIsVector(current_val, xmlrpc_vector_struct);
00113 
00114          while ( iter ) {
00115             XMLRPC_VALUE xNextVal = XMLRPC_CreateValueEmpty();
00116             xml_element_to_XMLRPC_REQUEST_worker(request, current_val, xNextVal, iter);
00117             XMLRPC_AddValueToVector(current_val, xNextVal);
00118             iter = (xml_element*)Q_Next(&el->children);
00119          }
00120               }
00121               else if (!strcmp(el->name, ELEM_STRING) || 
00122                  (!strcmp(el->name, ELEM_VALUE) && Q_Size(&el->children) == 0)) {
00123          XMLRPC_SetValueString(current_val, el->text.str, el->text.len);
00124               }
00125               else if (!strcmp(el->name, ELEM_NAME)) {
00126          XMLRPC_SetValueID_Case(current_val, el->text.str, 0, xmlrpc_case_exact);
00127               }
00128               else if (!strcmp(el->name, ELEM_INT) || !strcmp(el->name, ELEM_I4)) {
00129          XMLRPC_SetValueInt(current_val, atoi(el->text.str));
00130               }
00131               else if (!strcmp(el->name, ELEM_BOOLEAN)) {
00132          XMLRPC_SetValueBoolean(current_val, atoi(el->text.str));
00133               }
00134               else if (!strcmp(el->name, ELEM_DOUBLE)) {
00135          XMLRPC_SetValueDouble(current_val, atof(el->text.str));
00136               }
00137               else if (!strcmp(el->name, ELEM_DATETIME)) {
00138          XMLRPC_SetValueDateTime_ISO8601(current_val, el->text.str);
00139               }
00140               else if (!strcmp(el->name, ELEM_BASE64)) {
00141          struct buffer_st buf;
00142          base64_decode_xmlrpc(&buf, el->text.str, el->text.len);
00143          XMLRPC_SetValueBase64(current_val, buf.data, buf.offset);
00144          buffer_delete(&buf);
00145               }
00146               else {
00147          xml_element* iter;
00148 
00149          if (!strcmp(el->name, ELEM_METHODCALL)) {
00150             if (request) {
00151                XMLRPC_RequestSetRequestType(request, xmlrpc_request_call);
00152             }
00153                      }
00154                      else if (!strcmp(el->name, ELEM_METHODRESPONSE)) {
00155             if (request) {
00156                XMLRPC_RequestSetRequestType(request, xmlrpc_request_response);
00157             }
00158                      }
00159                      else if (!strcmp(el->name, ELEM_METHODNAME)) {
00160             if (request) {
00161                XMLRPC_RequestSetMethodName(request, el->text.str);
00162             }
00163          }
00164 
00165          iter = (xml_element*)Q_Head(&el->children);
00166          while ( iter ) {
00167             xml_element_to_XMLRPC_REQUEST_worker(request, parent_vector, 
00168                                                  current_val, iter);
00169             iter = (xml_element*)Q_Next(&el->children);
00170          }
00171       }
00172    }
00173    return current_val;
00174 }
00175 
00176 XMLRPC_VALUE xml_element_to_XMLRPC_VALUE(xml_element* el)
00177 {
00178    return xml_element_to_XMLRPC_REQUEST_worker(NULL, NULL, NULL, el);
00179 }
00180 
00181 XMLRPC_VALUE xml_element_to_XMLRPC_REQUEST(XMLRPC_REQUEST request, xml_element* el)
00182 {
00183    if (request) {
00184       return XMLRPC_RequestSetData(request, xml_element_to_XMLRPC_REQUEST_worker(request, NULL, NULL, el));
00185    }
00186    return NULL;
00187 }
00188 
00189 xml_element* XMLRPC_to_xml_element_worker(XMLRPC_VALUE current_vector, XMLRPC_VALUE node, 
00190                                           XMLRPC_REQUEST_TYPE request_type, int depth) {
00191 #define BUF_SIZE 512
00192    xml_element* root = NULL;
00193    if (node) {
00194       char buf[BUF_SIZE];
00195       XMLRPC_VALUE_TYPE type = XMLRPC_GetValueType(node);
00196       XMLRPC_VECTOR_TYPE vtype = XMLRPC_GetVectorType(node);
00197       xml_element* elem_val = xml_elem_new();
00198 
00199       /* special case for when root element is not an array */
00200       if (depth == 0 && 
00201           !(type == xmlrpc_vector && 
00202             vtype == xmlrpc_vector_array && 
00203             request_type == xmlrpc_request_call) ) {
00204          int bIsFault = (vtype == xmlrpc_vector_struct && XMLRPC_VectorGetValueWithID(node, ELEM_FAULTCODE));
00205 
00206          xml_element* next_el = XMLRPC_to_xml_element_worker(NULL, node, request_type, depth + 1);
00207          if (next_el) {
00208             Q_PushTail(&elem_val->children, next_el);
00209          }
00210          elem_val->name = strdup(bIsFault ? ELEM_FAULT : ELEM_PARAMS);
00211               }
00212               else {
00213          switch (type) {
00214                      case xmlrpc_empty: /*  treat null value as empty string in xmlrpc. */
00215          case xmlrpc_string:
00216             elem_val->name = strdup(ELEM_STRING);
00217             simplestring_addn(&elem_val->text, XMLRPC_GetValueString(node), XMLRPC_GetValueStringLen(node));
00218             break;
00219          case xmlrpc_int:
00220             elem_val->name = strdup(ELEM_INT);
00221             snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueInt(node));
00222             simplestring_add(&elem_val->text, buf);
00223             break;
00224          case xmlrpc_boolean:
00225             elem_val->name = strdup(ELEM_BOOLEAN);
00226             snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueBoolean(node));
00227             simplestring_add(&elem_val->text, buf);
00228             break;
00229          case xmlrpc_double:
00230             {
00231                 TSRMLS_FETCH();
00232                 elem_val->name = strdup(ELEM_DOUBLE);
00233                 ap_php_snprintf(buf, BUF_SIZE, "%.*G", (int) EG(precision), XMLRPC_GetValueDouble(node));
00234                 simplestring_add(&elem_val->text, buf);
00235             }
00236             break;
00237          case xmlrpc_datetime:
00238             elem_val->name = strdup(ELEM_DATETIME);
00239             simplestring_add(&elem_val->text, XMLRPC_GetValueDateTime_ISO8601(node));
00240             break;
00241          case xmlrpc_base64:
00242             {
00243                struct buffer_st buf;
00244                elem_val->name = strdup(ELEM_BASE64);
00245                base64_encode_xmlrpc(&buf, XMLRPC_GetValueBase64(node), XMLRPC_GetValueStringLen(node));
00246                simplestring_addn(&elem_val->text, buf.data, buf.offset );
00247                buffer_delete(&buf);
00248             }
00249             break;
00250          case xmlrpc_vector:
00251             {
00252                XMLRPC_VECTOR_TYPE my_type = XMLRPC_GetVectorType(node);
00253                XMLRPC_VALUE xIter = XMLRPC_VectorRewind(node);
00254                xml_element* root_vector_elem = elem_val;
00255 
00256                switch (my_type) {
00257                case xmlrpc_vector_array:
00258                   {
00259                       if(depth == 0) {
00260                          elem_val->name = strdup(ELEM_PARAMS);
00261                       }
00262                       else {
00263                          /* Hi my name is Dave and I like to make things as confusing
00264                           * as possible, thus I will throw in this 'data' element
00265                           * where it absolutely does not belong just so that people
00266                           * cannot code arrays and structs in a similar and straight
00267                           * forward manner. Have a good day.
00268                           *
00269                           * GRRRRRRRRR!
00270                           */
00271                          xml_element* data = xml_elem_new();
00272                          data->name = strdup(ELEM_DATA);
00273     
00274                          elem_val->name = strdup(ELEM_ARRAY);
00275                          Q_PushTail(&elem_val->children, data);
00276                          root_vector_elem = data;
00277                       }
00278                   }
00279                   break;
00280                case xmlrpc_vector_mixed:       /* not officially supported */
00281                case xmlrpc_vector_struct:
00282                   elem_val->name = strdup(ELEM_STRUCT);
00283                   break;
00284                default:
00285                   break;
00286                }
00287 
00288                /* recurse through sub-elements */
00289                while ( xIter ) {
00290                   xml_element* next_el = XMLRPC_to_xml_element_worker(node, xIter, request_type, depth + 1);
00291                   if (next_el) {
00292                      Q_PushTail(&root_vector_elem->children, next_el);
00293                   }
00294                   xIter = XMLRPC_VectorNext(node);
00295                }
00296             }
00297             break;
00298          default:
00299             break;
00300          }
00301       }
00302 
00303       {
00304          XMLRPC_VECTOR_TYPE vtype = XMLRPC_GetVectorType(current_vector);
00305 
00306          if (depth == 1) {
00307             xml_element* value = xml_elem_new();
00308             value->name = strdup(ELEM_VALUE);
00309 
00310             /* yet another hack for the "fault" crap */
00311             if (XMLRPC_VectorGetValueWithID(node, ELEM_FAULTCODE)) {
00312                root = value;
00313                             }
00314                             else {
00315                xml_element* param = xml_elem_new();
00316                param->name = strdup(ELEM_PARAM);
00317 
00318                Q_PushTail(&param->children, value);
00319 
00320                root = param;
00321             }
00322             Q_PushTail(&value->children, elem_val);
00323                      }
00324                      else if (vtype == xmlrpc_vector_struct || vtype == xmlrpc_vector_mixed) {
00325             xml_element* member = xml_elem_new();
00326             xml_element* name = xml_elem_new();
00327             xml_element* value = xml_elem_new();
00328 
00329             member->name = strdup(ELEM_MEMBER);
00330             name->name = strdup(ELEM_NAME);
00331             value->name = strdup(ELEM_VALUE);
00332 
00333             simplestring_add(&name->text, XMLRPC_GetValueID(node));
00334 
00335             Q_PushTail(&member->children, name);
00336             Q_PushTail(&member->children, value);
00337             Q_PushTail(&value->children, elem_val);
00338 
00339             root = member;
00340                      }
00341                      else if (vtype == xmlrpc_vector_array) {
00342             xml_element* value = xml_elem_new();
00343 
00344             value->name = strdup(ELEM_VALUE);
00345 
00346             Q_PushTail(&value->children, elem_val);
00347 
00348             root = value;
00349                      }
00350                      else if (vtype == xmlrpc_vector_none) {
00351             /* no parent.  non-op */
00352             root = elem_val;
00353                      }
00354                      else {
00355             xml_element* value = xml_elem_new();
00356 
00357             value->name = strdup(ELEM_VALUE);
00358 
00359             Q_PushTail(&value->children, elem_val);
00360 
00361             root = value;
00362          }
00363       }
00364    }
00365    return root;
00366 }
00367 
00368 xml_element* XMLRPC_VALUE_to_xml_element(XMLRPC_VALUE node) {
00369    return XMLRPC_to_xml_element_worker(NULL, node, xmlrpc_request_none, 0);
00370 }
00371 
00372 xml_element* XMLRPC_REQUEST_to_xml_element(XMLRPC_REQUEST request) {
00373    xml_element* wrapper = NULL;
00374    if (request) {
00375       const char* pStr = NULL;
00376       XMLRPC_REQUEST_TYPE request_type = XMLRPC_RequestGetRequestType(request);
00377       XMLRPC_VALUE xParams = XMLRPC_RequestGetData(request);
00378 
00379       wrapper = xml_elem_new();
00380 
00381       if (request_type == xmlrpc_request_call) {
00382          pStr = ELEM_METHODCALL;
00383               }
00384               else if (request_type == xmlrpc_request_response) {
00385          pStr = ELEM_METHODRESPONSE;
00386       }
00387       if (pStr) {
00388          wrapper->name = strdup(pStr);
00389       }
00390 
00391               if(request_type == xmlrpc_request_call) {
00392       pStr = XMLRPC_RequestGetMethodName(request);
00393 
00394       if (pStr) {
00395          xml_element* method = xml_elem_new();
00396          method->name = strdup(ELEM_METHODNAME);
00397          simplestring_add(&method->text, pStr);
00398          Q_PushTail(&wrapper->children, method);
00399       }
00400               }
00401       if (xParams) {
00402          Q_PushTail(&wrapper->children, 
00403                     XMLRPC_to_xml_element_worker(NULL, XMLRPC_RequestGetData(request), XMLRPC_RequestGetRequestType(request), 0));
00404               }
00405               else {
00406          /* Despite the spec, the xml-rpc list folk want me to send an empty params element */
00407          xml_element* params = xml_elem_new();
00408          params->name = strdup(ELEM_PARAMS);
00409          Q_PushTail(&wrapper->children, params);
00410       }
00411    }
00412    return wrapper;
00413 }
00414