root/ext/xmlrpc/libxmlrpc/xml_to_xmlrpc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. xml_element_to_XMLRPC_REQUEST_worker
  2. xml_element_to_XMLRPC_VALUE
  3. xml_element_to_XMLRPC_REQUEST
  4. XMLRPC_to_xml_element_worker
  5. XMLRPC_VALUE_to_xml_element
  6. XMLRPC_REQUEST_to_xml_element

   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 
  34 static const char rcsid[] = "#(@) $Id$";
  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                                 elem_val->name = strdup(ELEM_DOUBLE);
 232                 ap_php_snprintf(buf, BUF_SIZE, "%.*G", (int) EG(precision), XMLRPC_GetValueDouble(node));
 233                 simplestring_add(&elem_val->text, buf);
 234             }
 235             break;
 236          case xmlrpc_datetime:
 237             elem_val->name = strdup(ELEM_DATETIME);
 238             simplestring_add(&elem_val->text, XMLRPC_GetValueDateTime_ISO8601(node));
 239             break;
 240          case xmlrpc_base64:
 241             {
 242                struct buffer_st buf;
 243                elem_val->name = strdup(ELEM_BASE64);
 244                base64_encode_xmlrpc(&buf, XMLRPC_GetValueBase64(node), XMLRPC_GetValueStringLen(node));
 245                simplestring_addn(&elem_val->text, buf.data, buf.offset );
 246                buffer_delete(&buf);
 247             }
 248             break;
 249          case xmlrpc_vector:
 250             {
 251                XMLRPC_VECTOR_TYPE my_type = XMLRPC_GetVectorType(node);
 252                XMLRPC_VALUE xIter = XMLRPC_VectorRewind(node);
 253                xml_element* root_vector_elem = elem_val;
 254 
 255                switch (my_type) {
 256                case xmlrpc_vector_array:
 257                   {
 258                       if(depth == 0) {
 259                          elem_val->name = strdup(ELEM_PARAMS);
 260                       }
 261                       else {
 262                          /* Hi my name is Dave and I like to make things as confusing
 263                           * as possible, thus I will throw in this 'data' element
 264                           * where it absolutely does not belong just so that people
 265                           * cannot code arrays and structs in a similar and straight
 266                           * forward manner. Have a good day.
 267                           *
 268                           * GRRRRRRRRR!
 269                           */
 270                          xml_element* data = xml_elem_new();
 271                          data->name = strdup(ELEM_DATA);
 272 
 273                          elem_val->name = strdup(ELEM_ARRAY);
 274                          Q_PushTail(&elem_val->children, data);
 275                          root_vector_elem = data;
 276                       }
 277                   }
 278                   break;
 279                case xmlrpc_vector_mixed:       /* not officially supported */
 280                case xmlrpc_vector_struct:
 281                   elem_val->name = strdup(ELEM_STRUCT);
 282                   break;
 283                default:
 284                   break;
 285                }
 286 
 287                /* recurse through sub-elements */
 288                while ( xIter ) {
 289                   xml_element* next_el = XMLRPC_to_xml_element_worker(node, xIter, request_type, depth + 1);
 290                   if (next_el) {
 291                      Q_PushTail(&root_vector_elem->children, next_el);
 292                   }
 293                   xIter = XMLRPC_VectorNext(node);
 294                }
 295             }
 296             break;
 297          default:
 298             break;
 299          }
 300       }
 301 
 302       {
 303          XMLRPC_VECTOR_TYPE vtype = XMLRPC_GetVectorType(current_vector);
 304 
 305          if (depth == 1) {
 306             xml_element* value = xml_elem_new();
 307             value->name = strdup(ELEM_VALUE);
 308 
 309             /* yet another hack for the "fault" crap */
 310             if (XMLRPC_VectorGetValueWithID(node, ELEM_FAULTCODE)) {
 311                root = value;
 312                                 }
 313                                 else {
 314                xml_element* param = xml_elem_new();
 315                param->name = strdup(ELEM_PARAM);
 316 
 317                Q_PushTail(&param->children, value);
 318 
 319                root = param;
 320             }
 321             Q_PushTail(&value->children, elem_val);
 322                         }
 323                         else if (vtype == xmlrpc_vector_struct || vtype == xmlrpc_vector_mixed) {
 324             xml_element* member = xml_elem_new();
 325             xml_element* name = xml_elem_new();
 326             xml_element* value = xml_elem_new();
 327 
 328             member->name = strdup(ELEM_MEMBER);
 329             name->name = strdup(ELEM_NAME);
 330             value->name = strdup(ELEM_VALUE);
 331 
 332             simplestring_add(&name->text, XMLRPC_GetValueID(node));
 333 
 334             Q_PushTail(&member->children, name);
 335             Q_PushTail(&member->children, value);
 336             Q_PushTail(&value->children, elem_val);
 337 
 338             root = member;
 339                         }
 340                         else if (vtype == xmlrpc_vector_array) {
 341             xml_element* value = xml_elem_new();
 342 
 343             value->name = strdup(ELEM_VALUE);
 344 
 345             Q_PushTail(&value->children, elem_val);
 346 
 347             root = value;
 348                         }
 349                         else if (vtype == xmlrpc_vector_none) {
 350             /* no parent.  non-op */
 351             root = elem_val;
 352                         }
 353                         else {
 354             xml_element* value = xml_elem_new();
 355 
 356             value->name = strdup(ELEM_VALUE);
 357 
 358             Q_PushTail(&value->children, elem_val);
 359 
 360             root = value;
 361          }
 362       }
 363    }
 364    return root;
 365 }
 366 
 367 xml_element* XMLRPC_VALUE_to_xml_element(XMLRPC_VALUE node) {
 368    return XMLRPC_to_xml_element_worker(NULL, node, xmlrpc_request_none, 0);
 369 }
 370 
 371 xml_element* XMLRPC_REQUEST_to_xml_element(XMLRPC_REQUEST request) {
 372    xml_element* wrapper = NULL;
 373    if (request) {
 374       const char* pStr = NULL;
 375       XMLRPC_REQUEST_TYPE request_type = XMLRPC_RequestGetRequestType(request);
 376       XMLRPC_VALUE xParams = XMLRPC_RequestGetData(request);
 377 
 378       wrapper = xml_elem_new();
 379 
 380       if (request_type == xmlrpc_request_call) {
 381          pStr = ELEM_METHODCALL;
 382                 }
 383                 else if (request_type == xmlrpc_request_response) {
 384          pStr = ELEM_METHODRESPONSE;
 385       }
 386       if (pStr) {
 387          wrapper->name = strdup(pStr);
 388       }
 389 
 390                 if(request_type == xmlrpc_request_call) {
 391       pStr = XMLRPC_RequestGetMethodName(request);
 392 
 393       if (pStr) {
 394          xml_element* method = xml_elem_new();
 395          method->name = strdup(ELEM_METHODNAME);
 396          simplestring_add(&method->text, pStr);
 397          Q_PushTail(&wrapper->children, method);
 398       }
 399                 }
 400       if (xParams) {
 401          Q_PushTail(&wrapper->children,
 402                     XMLRPC_to_xml_element_worker(NULL, XMLRPC_RequestGetData(request), XMLRPC_RequestGetRequestType(request), 0));
 403                 }
 404                 else {
 405          /* Despite the spec, the xml-rpc list folk want me to send an empty params element */
 406          xml_element* params = xml_elem_new();
 407          params->name = strdup(ELEM_PARAMS);
 408          Q_PushTail(&wrapper->children, params);
 409       }
 410    }
 411    return wrapper;
 412 }
 413 

/* [<][>][^][v][top][bottom][index][help] */