Annotation of embedaddon/php/ext/xmlrpc/libxmlrpc/xml_to_xmlrpc.c, revision 1.1.1.1

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: 
                     34: static const char rcsid[] = "#(@) $Id: xml_to_xmlrpc.c 242949 2007-09-26 15:44:16Z cvs2svn $";
                     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(&param->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>