PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/xmlrpc - xmlrpc-epi-php.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 443 579 76.5 %
Date: 2014-08-17 Functions: 29 33 87.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of, or distributed with, libXMLRPC - a C library for 
       3             :   xml-encoded function calls.
       4             : 
       5             :   Author: Dan Libby (dan@libby.com)
       6             :   Epinions.com may be contacted at feedback@epinions-inc.com
       7             : */
       8             : 
       9             : /*  
      10             :   Copyright 2001 Epinions, Inc. 
      11             : 
      12             :   Subject to the following 3 conditions, Epinions, Inc.  permits you, free 
      13             :   of charge, to (a) use, copy, distribute, modify, perform and display this 
      14             :   software and associated documentation files (the "Software"), and (b) 
      15             :   permit others to whom the Software is furnished to do so as well.  
      16             : 
      17             :   1) The above copyright notice and this permission notice shall be included 
      18             :   without modification in all copies or substantial portions of the 
      19             :   Software.  
      20             : 
      21             :   2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF 
      22             :   ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY 
      23             :   IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR 
      24             :   PURPOSE OR NONINFRINGEMENT.  
      25             : 
      26             :   3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, 
      27             :   SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT 
      28             :   OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING 
      29             :   NEGLIGENCE), EVEN IF EPINIONS, INC.  IS AWARE OF THE POSSIBILITY OF SUCH 
      30             :   DAMAGES.    
      31             : 
      32             : */
      33             : 
      34             : /* auto-generated portions of this file are also subject to the php license */
      35             : 
      36             : /*
      37             :    +----------------------------------------------------------------------+
      38             :    | PHP Version 5                                                        |
      39             :    +----------------------------------------------------------------------+
      40             :    | Copyright (c) 1997-2014 The PHP Group                                |
      41             :    +----------------------------------------------------------------------+
      42             :    | This source file is subject to version 3.01 of the PHP license,      |
      43             :    | that is bundled with this package in the file LICENSE, and is        |
      44             :    | available through the world-wide-web at the following url:           |
      45             :    | http://www.php.net/license/3_01.txt                                  |
      46             :    | If you did not receive a copy of the PHP license and are unable to   |
      47             :    | obtain it through the world-wide-web, please send a note to          |
      48             :    | license@php.net so we can mail you a copy immediately.               |
      49             :    +----------------------------------------------------------------------+
      50             :    | Author: Dan Libby                                                    |
      51             :    +----------------------------------------------------------------------+
      52             :  */
      53             : 
      54             : /* $Id$ */
      55             : 
      56             : /**********************************************************************
      57             : * BUGS:                                                               *
      58             : *  - when calling a php user function, there appears to be no way to  *
      59             : *    distinguish between a return value of null, and no return value  *
      60             : *    at all.  The xml serialization layer(s) will then return a value *
      61             : *    of null, when the right thing may be no value at all. (SOAP)     *
      62             : **********************************************************************/
      63             : 
      64             : #ifdef HAVE_CONFIG_H
      65             : #include "config.h"
      66             : #endif
      67             : 
      68             : #include "php.h"
      69             : #include "ext/standard/info.h"
      70             : #include "ext/standard/php_string.h"
      71             : #include "ext/date/php_date.h"
      72             : #include "php_ini.h"
      73             : #include "php_xmlrpc.h"
      74             : #include "xmlrpc.h"
      75             : 
      76             : #define PHP_EXT_VERSION "0.51"
      77             : 
      78             : static int le_xmlrpc_server;
      79             : 
      80             : /* {{{ arginfo */
      81             : ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_encode, 0, 0, 1)
      82             :         ZEND_ARG_INFO(0, value)
      83             : ZEND_END_ARG_INFO()
      84             : 
      85             : ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_decode, 0, 0, 1)
      86             :         ZEND_ARG_INFO(0, value)
      87             :         ZEND_ARG_INFO(0, encoding)
      88             : ZEND_END_ARG_INFO()
      89             : 
      90             : ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_decode_request, 0, 0, 2)
      91             :         ZEND_ARG_INFO(0, xml)
      92             :         ZEND_ARG_INFO(1, method)
      93             :         ZEND_ARG_INFO(0, encoding)
      94             : ZEND_END_ARG_INFO()
      95             : 
      96             : ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_encode_request, 0, 0, 2)
      97             :         ZEND_ARG_INFO(0, method)
      98             :         ZEND_ARG_INFO(0, params)
      99             :         ZEND_ARG_INFO(0, output_options)
     100             : ZEND_END_ARG_INFO()
     101             : 
     102             : ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_set_type, 0, 0, 2)
     103             :         ZEND_ARG_INFO(1, value)
     104             :         ZEND_ARG_INFO(0, type)
     105             : ZEND_END_ARG_INFO()
     106             : 
     107             : ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_is_fault, 0, 0, 1)
     108             :         ZEND_ARG_INFO(0, arg)
     109             : ZEND_END_ARG_INFO()
     110             : 
     111             : ZEND_BEGIN_ARG_INFO(arginfo_xmlrpc_server_create, 0)
     112             : ZEND_END_ARG_INFO()
     113             : 
     114             : ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_server_destroy, 0, 0, 1)
     115             :         ZEND_ARG_INFO(0, server)
     116             : ZEND_END_ARG_INFO()
     117             : 
     118             : ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_server_register_method, 0, 0, 3)
     119             :         ZEND_ARG_INFO(0, server)
     120             :         ZEND_ARG_INFO(0, method_name)
     121             :         ZEND_ARG_INFO(0, function)
     122             : ZEND_END_ARG_INFO()
     123             : 
     124             : ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_server_call_method, 0, 0, 3)
     125             :         ZEND_ARG_INFO(0, server)
     126             :         ZEND_ARG_INFO(0, xml)
     127             :         ZEND_ARG_INFO(0, user_data)
     128             :         ZEND_ARG_INFO(0, output_options)
     129             : ZEND_END_ARG_INFO()
     130             : 
     131             : ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_parse_method_descriptions, 0, 0, 1)
     132             :         ZEND_ARG_INFO(0, xml)
     133             : ZEND_END_ARG_INFO()
     134             : 
     135             : ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_server_add_introspection_data, 0, 0, 2)
     136             :         ZEND_ARG_INFO(0, server)
     137             :         ZEND_ARG_INFO(0, desc)
     138             : ZEND_END_ARG_INFO()
     139             : 
     140             : ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_server_register_introspection_callback, 0, 0, 2)
     141             :         ZEND_ARG_INFO(0, server)
     142             :         ZEND_ARG_INFO(0, function)
     143             : ZEND_END_ARG_INFO()
     144             : /* }}} */
     145             : 
     146             : const zend_function_entry xmlrpc_functions[] = {
     147             :         PHP_FE(xmlrpc_encode,                                                                   arginfo_xmlrpc_encode) 
     148             :         PHP_FE(xmlrpc_decode,                                                                   arginfo_xmlrpc_decode)
     149             :         PHP_FE(xmlrpc_decode_request,                                                   arginfo_xmlrpc_decode_request)
     150             :         PHP_FE(xmlrpc_encode_request,                                                   arginfo_xmlrpc_encode_request)
     151             :         PHP_FE(xmlrpc_get_type,                                                                 arginfo_xmlrpc_encode)
     152             :         PHP_FE(xmlrpc_set_type,                                                                 arginfo_xmlrpc_set_type)
     153             :         PHP_FE(xmlrpc_is_fault,                                                                 arginfo_xmlrpc_is_fault)
     154             :         PHP_FE(xmlrpc_server_create,                                                    arginfo_xmlrpc_server_create)
     155             :         PHP_FE(xmlrpc_server_destroy,                                                   arginfo_xmlrpc_server_destroy)
     156             :         PHP_FE(xmlrpc_server_register_method,                                   arginfo_xmlrpc_server_register_method)
     157             :         PHP_FE(xmlrpc_server_call_method,                                               arginfo_xmlrpc_server_call_method)
     158             :         PHP_FE(xmlrpc_parse_method_descriptions,                                arginfo_xmlrpc_parse_method_descriptions)
     159             :         PHP_FE(xmlrpc_server_add_introspection_data,                    arginfo_xmlrpc_server_add_introspection_data)
     160             :         PHP_FE(xmlrpc_server_register_introspection_callback,   arginfo_xmlrpc_server_register_introspection_callback)
     161             :         PHP_FE_END
     162             : };
     163             : 
     164             : zend_module_entry xmlrpc_module_entry = {
     165             :         STANDARD_MODULE_HEADER,
     166             :         "xmlrpc",
     167             :         xmlrpc_functions,
     168             :         PHP_MINIT(xmlrpc),
     169             :         NULL,
     170             :         NULL,
     171             :         NULL,
     172             :         PHP_MINFO(xmlrpc),
     173             :         PHP_EXT_VERSION,
     174             :         STANDARD_MODULE_PROPERTIES
     175             : };
     176             : 
     177             : #ifdef COMPILE_DL_XMLRPC
     178             : ZEND_GET_MODULE(xmlrpc)
     179             : #endif
     180             : 
     181             : /*******************************
     182             : * local structures and defines *
     183             : *******************************/
     184             : 
     185             : /* per server data */
     186             : typedef struct _xmlrpc_server_data {
     187             :         zval* method_map;
     188             :         zval* introspection_map;
     189             :         XMLRPC_SERVER server_ptr;
     190             : } xmlrpc_server_data;
     191             : 
     192             : 
     193             : /* how to format output */
     194             : typedef struct _php_output_options {
     195             :         int b_php_out;
     196             :         int b_auto_version;
     197             :         STRUCT_XMLRPC_REQUEST_OUTPUT_OPTIONS xmlrpc_out;
     198             : } php_output_options;
     199             : 
     200             : /* data passed to C callback */
     201             : typedef struct _xmlrpc_callback_data {
     202             :         zval* xmlrpc_method;
     203             :         zval* php_function;
     204             :         zval* caller_params;
     205             :         zval* return_data;
     206             :         xmlrpc_server_data* server;
     207             :         char php_executed;
     208             : } xmlrpc_callback_data;
     209             : 
     210             : /* output options */
     211             : #define OUTPUT_TYPE_KEY       "output_type"
     212             : #define OUTPUT_TYPE_KEY_LEN   (sizeof(OUTPUT_TYPE_KEY) - 1)
     213             : #define OUTPUT_TYPE_VALUE_PHP "php"
     214             : #define OUTPUT_TYPE_VALUE_XML "xml"
     215             : 
     216             : #define VERBOSITY_KEY                  "verbosity"
     217             : #define VERBOSITY_KEY_LEN              (sizeof(VERBOSITY_KEY) - 1)
     218             : #define VERBOSITY_VALUE_NO_WHITE_SPACE "no_white_space"
     219             : #define VERBOSITY_VALUE_NEWLINES_ONLY  "newlines_only"
     220             : #define VERBOSITY_VALUE_PRETTY         "pretty"
     221             : 
     222             : #define ESCAPING_KEY             "escaping"
     223             : #define ESCAPING_KEY_LEN         (sizeof(ESCAPING_KEY) - 1)
     224             : #define ESCAPING_VALUE_CDATA     "cdata"
     225             : #define ESCAPING_VALUE_NON_ASCII "non-ascii"
     226             : #define ESCAPING_VALUE_NON_PRINT "non-print"
     227             : #define ESCAPING_VALUE_MARKUP    "markup"
     228             : 
     229             : #define VERSION_KEY          "version"
     230             : #define VERSION_KEY_LEN      (sizeof(VERSION_KEY) - 1)
     231             : #define VERSION_VALUE_SIMPLE "simple"
     232             : #define VERSION_VALUE_XMLRPC "xmlrpc"
     233             : #define VERSION_VALUE_SOAP11 "soap 1.1"
     234             : #define VERSION_VALUE_AUTO   "auto"
     235             : 
     236             : #define ENCODING_KEY     "encoding"
     237             : #define ENCODING_KEY_LEN (sizeof(ENCODING_KEY) - 1)
     238             : #define ENCODING_DEFAULT "iso-8859-1"
     239             : 
     240             : /* value types */
     241             : #define OBJECT_TYPE_ATTR  "xmlrpc_type"
     242             : #define OBJECT_VALUE_ATTR "scalar"
     243             : #define OBJECT_VALUE_TS_ATTR "timestamp"
     244             : 
     245             : /* faults */
     246             : #define FAULT_CODE       "faultCode"
     247             : #define FAULT_CODE_LEN   (sizeof(FAULT_CODE) - 1)
     248             : #define FAULT_STRING     "faultString"
     249             : #define FAULT_STRING_LEN (sizeof(FAULT_STRING) - 1)
     250             : 
     251             : /***********************
     252             : * forward declarations *
     253             : ***********************/
     254             : XMLRPC_VALUE_TYPE get_zval_xmlrpc_type(zval* value, zval** newvalue);
     255             : static void php_xmlrpc_introspection_callback(XMLRPC_SERVER server, void* data);
     256             : int sset_zval_xmlrpc_type(zval* value, XMLRPC_VALUE_TYPE type);
     257             : zval* decode_request_worker(char *xml_in, int xml_in_len, char *encoding_in, zval* method_name_out);
     258             : const char* xmlrpc_type_as_str(XMLRPC_VALUE_TYPE type, XMLRPC_VECTOR_TYPE vtype);
     259             : XMLRPC_VALUE_TYPE xmlrpc_str_as_type(const char* str);
     260             : XMLRPC_VECTOR_TYPE xmlrpc_str_as_vector_type(const char* str);
     261             : int set_zval_xmlrpc_type(zval* value, XMLRPC_VALUE_TYPE type);
     262             : 
     263             : /*********************
     264             : * startup / shutdown *
     265             : *********************/
     266             : 
     267          10 : static void destroy_server_data(xmlrpc_server_data *server TSRMLS_DC)
     268             : {
     269          10 :         if (server) {
     270          10 :                 XMLRPC_ServerDestroy(server->server_ptr);
     271             : 
     272          10 :                 zval_dtor(server->method_map);
     273          10 :                 FREE_ZVAL(server->method_map);
     274             : 
     275          10 :                 zval_dtor(server->introspection_map);
     276          10 :                 FREE_ZVAL(server->introspection_map);
     277             : 
     278          10 :                 efree(server);
     279             :         }
     280          10 : }
     281             : 
     282             : /* called when server is being destructed. either when xmlrpc_server_destroy
     283             :  * is called, or when request ends.  */
     284          10 : static void xmlrpc_server_destructor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
     285             : {
     286          10 :         if (rsrc && rsrc->ptr) {
     287          10 :                 destroy_server_data((xmlrpc_server_data*) rsrc->ptr TSRMLS_CC);
     288             :         }
     289          10 : }
     290             : 
     291             : /* module init */
     292       20205 : PHP_MINIT_FUNCTION(xmlrpc)
     293             : {
     294       20205 :         le_xmlrpc_server = zend_register_list_destructors_ex(xmlrpc_server_destructor, NULL, "xmlrpc server", module_number);
     295             : 
     296       20205 :         return SUCCESS;
     297             : }
     298             : 
     299             : /* display info in phpinfo() */
     300         148 : PHP_MINFO_FUNCTION(xmlrpc)
     301             : {
     302         148 :         php_info_print_table_start();
     303         148 :         php_info_print_table_row(2, "core library version", XMLRPC_GetVersionString());
     304         148 :         php_info_print_table_row(2, "php extension version", PHP_EXT_VERSION);
     305         148 :         php_info_print_table_row(2, "author", "Dan Libby");
     306         148 :         php_info_print_table_row(2, "homepage", "http://xmlrpc-epi.sourceforge.net");
     307         148 :         php_info_print_table_row(2, "open sourced by", "Epinions.com");
     308         148 :         php_info_print_table_end();
     309         148 : }
     310             : 
     311             : /*******************
     312             : * random utilities *
     313             : *******************/
     314             : 
     315             : /* Utility functions for adding data types to arrays, with or without key (assoc, non-assoc).
     316             :  * Could easily be further generalized to work with objects.
     317             :  */
     318             : #if 0
     319             : static int add_long(zval* list, char* id, int num) {
     320             :         if(id) return add_assoc_long(list, id, num);
     321             :         else   return add_next_index_long(list, num);
     322             : }
     323             : 
     324             : static int add_double(zval* list, char* id, double num) {
     325             :         if(id) return add_assoc_double(list, id, num);
     326             :         else   return add_next_index_double(list, num);
     327             : }
     328             : 
     329             : static int add_string(zval* list, char* id, char* string, int duplicate) {
     330             :         if(id) return add_assoc_string(list, id, string, duplicate);
     331             :         else   return add_next_index_string(list, string, duplicate);
     332             : }
     333             : 
     334             : static int add_stringl(zval* list, char* id, char* string, uint length, int duplicate) {
     335             :         if(id) return add_assoc_stringl(list, id, string, length, duplicate);
     336             :         else   return add_next_index_stringl(list, string, length, duplicate);
     337             : }
     338             : 
     339             : #endif
     340             : 
     341          42 : static int add_zval(zval* list, const char* id, zval** val)
     342             : {
     343          42 :         if (list && val) {
     344          42 :                 if (id) {
     345          23 :                         int id_len = strlen(id);
     346          23 :                         if (!(id_len > 1 && id[0] == '0') && is_numeric_string((char *)id, id_len, NULL, NULL, 0) == IS_LONG) {
     347          11 :                                 long index = strtol(id, NULL, 0);
     348          11 :                                 return zend_hash_index_update(Z_ARRVAL_P(list), index, (void *) val, sizeof(zval **), NULL);
     349             :                         } else {
     350          12 :                                 return zend_hash_update(Z_ARRVAL_P(list), (char*) id, strlen(id) + 1, (void *) val, sizeof(zval **), NULL);
     351             :                         }
     352             :                 } else {
     353          19 :                         return zend_hash_next_index_insert(Z_ARRVAL_P(list), (void *) val, sizeof(zval **), NULL); 
     354             :                 }
     355             :         }
     356             :         /* what is the correct return on error? */
     357           0 :         return 0;
     358             : }
     359             : 
     360             : #define my_zend_hash_get_current_key(ht, my_key, num_index) zend_hash_get_current_key(ht, my_key, num_index, 0)
     361             : 
     362             : 
     363             : /*************************
     364             : * input / output options *
     365             : *************************/
     366             : 
     367             : /* parse an array (user input) into output options suitable for use by xmlrpc engine
     368             :  * and determine whether to return data as xml or php vars */
     369          22 : static void set_output_options(php_output_options* options, zval* output_opts)
     370             : {
     371          22 :         if (options) {
     372             : 
     373             :                 /* defaults */
     374          22 :                 options->b_php_out = 0;
     375          22 :                 options->b_auto_version = 1;
     376          22 :                 options->xmlrpc_out.version = xmlrpc_version_1_0;
     377          22 :                 options->xmlrpc_out.xml_elem_opts.encoding = ENCODING_DEFAULT;
     378          22 :                 options->xmlrpc_out.xml_elem_opts.verbosity = xml_elem_pretty;
     379          22 :                 options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_markup_escaping | xml_elem_non_ascii_escaping | xml_elem_non_print_escaping;
     380             : 
     381          22 :                 if (output_opts && Z_TYPE_P(output_opts) == IS_ARRAY) {
     382             :                         zval** val;
     383             : 
     384             :                         /* type of output (xml/php) */
     385           2 :                         if (zend_hash_find(Z_ARRVAL_P(output_opts), OUTPUT_TYPE_KEY, OUTPUT_TYPE_KEY_LEN + 1, (void**) &val) == SUCCESS) {
     386           2 :                                 if (Z_TYPE_PP(val) == IS_STRING) {
     387           2 :                                         if (!strcmp(Z_STRVAL_PP(val), OUTPUT_TYPE_VALUE_PHP)) {
     388           0 :                                                 options->b_php_out = 1;
     389           2 :                                         } else if (!strcmp(Z_STRVAL_PP(val), OUTPUT_TYPE_VALUE_XML)) {
     390           2 :                                                 options->b_php_out = 0;
     391             :                                         }
     392             :                                 }
     393             :                         }
     394             : 
     395             :                         /* verbosity of generated xml */
     396           2 :                         if (zend_hash_find(Z_ARRVAL_P(output_opts), VERBOSITY_KEY, VERBOSITY_KEY_LEN + 1, (void**) &val) == SUCCESS) {
     397           0 :                                 if (Z_TYPE_PP(val) == IS_STRING) {
     398           0 :                                         if (!strcmp(Z_STRVAL_PP(val), VERBOSITY_VALUE_NO_WHITE_SPACE)) {
     399           0 :                                                 options->xmlrpc_out.xml_elem_opts.verbosity = xml_elem_no_white_space;
     400           0 :                                         } else if (!strcmp(Z_STRVAL_PP(val), VERBOSITY_VALUE_NEWLINES_ONLY)) {
     401           0 :                                                 options->xmlrpc_out.xml_elem_opts.verbosity = xml_elem_newlines_only;
     402           0 :                                         } else if (!strcmp(Z_STRVAL_PP(val), VERBOSITY_VALUE_PRETTY)) {
     403           0 :                                                 options->xmlrpc_out.xml_elem_opts.verbosity = xml_elem_pretty;
     404             :                                         }
     405             :                                 }
     406             :                         }
     407             : 
     408             :                         /* version of xml to output */
     409           2 :                         if (zend_hash_find(Z_ARRVAL_P(output_opts), VERSION_KEY, VERSION_KEY_LEN + 1, (void**) &val) == SUCCESS) {
     410           2 :                                 if (Z_TYPE_PP(val) == IS_STRING) {
     411           2 :                                         options->b_auto_version = 0;
     412           2 :                                         if (!strcmp(Z_STRVAL_PP(val), VERSION_VALUE_XMLRPC)) {
     413           2 :                                                 options->xmlrpc_out.version = xmlrpc_version_1_0;
     414           0 :                                         } else if (!strcmp(Z_STRVAL_PP(val), VERSION_VALUE_SIMPLE)) {
     415           0 :                                                 options->xmlrpc_out.version = xmlrpc_version_simple;
     416           0 :                                         } else if (!strcmp((*val)->value.str.val, VERSION_VALUE_SOAP11)) {
     417           0 :                                                         options->xmlrpc_out.version = xmlrpc_version_soap_1_1;
     418             :                                         } else { /* if(!strcmp((*val)->value.str.val, VERSION_VALUE_AUTO)) { */
     419           0 :                                                         options->b_auto_version = 1;
     420             :                                         }
     421             :                                 }
     422             :                         }
     423             : 
     424             :                         /* encoding code set */
     425           2 :                         if (zend_hash_find(Z_ARRVAL_P(output_opts), ENCODING_KEY, ENCODING_KEY_LEN + 1, (void**)&val) == SUCCESS) {
     426           0 :                                 if (Z_TYPE_PP(val) == IS_STRING) {
     427           0 :                                         options->xmlrpc_out.xml_elem_opts.encoding = estrdup(Z_STRVAL_PP(val));
     428             :                                 }
     429             :                         }
     430             : 
     431             :                         /* escaping options */
     432           2 :                         if (zend_hash_find(Z_ARRVAL_P(output_opts), ESCAPING_KEY, ESCAPING_KEY_LEN + 1, (void**)&val) == SUCCESS) {
     433             :                                 /* multiple values allowed.  check if array */
     434           0 :                                 if (Z_TYPE_PP(val) == IS_ARRAY) {
     435             :                                         zval** iter_val;
     436             : 
     437           0 :                                         zend_hash_internal_pointer_reset(Z_ARRVAL_PP(val));
     438           0 :                                         options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_no_escaping;
     439             : 
     440             :                                         while (1) {
     441           0 :                                                 if (zend_hash_get_current_data(Z_ARRVAL_PP(val), (void**)&iter_val) == SUCCESS) {
     442           0 :                                                         if (Z_TYPE_PP(iter_val) == IS_STRING && Z_STRVAL_PP(iter_val)) {
     443           0 :                                                                 if (!strcmp(Z_STRVAL_PP(iter_val), ESCAPING_VALUE_CDATA)) {
     444           0 :                                                                         options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_cdata_escaping;
     445           0 :                                                                 } else if (!strcmp(Z_STRVAL_PP(iter_val), ESCAPING_VALUE_NON_ASCII)) {
     446           0 :                                                                         options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_non_ascii_escaping;
     447           0 :                                                                 } else if (!strcmp(Z_STRVAL_PP(iter_val), ESCAPING_VALUE_NON_PRINT)) {
     448           0 :                                                                         options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_non_print_escaping;
     449           0 :                                                                 } else if (!strcmp(Z_STRVAL_PP(iter_val), ESCAPING_VALUE_MARKUP)) {
     450           0 :                                                                         options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_markup_escaping;
     451             :                                                                 }
     452             :                                                         }
     453             :                                                 } else {
     454           0 :                                                         break;
     455             :                                                 }
     456           0 :                                                 zend_hash_move_forward(Z_ARRVAL_PP(val));
     457           0 :                                         }
     458             :                                 /* else, check for single value */
     459           0 :                                 } else if (Z_TYPE_PP(val) == IS_STRING) {
     460           0 :                                         if (!strcmp(Z_STRVAL_PP(val), ESCAPING_VALUE_CDATA)) {
     461           0 :                                                 options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_cdata_escaping;
     462           0 :                                         } else if (!strcmp(Z_STRVAL_PP(val), ESCAPING_VALUE_NON_ASCII)) {
     463           0 :                                                 options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_non_ascii_escaping;
     464           0 :                                         } else if (!strcmp(Z_STRVAL_PP(val), ESCAPING_VALUE_NON_PRINT)) {
     465           0 :                                                 options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_non_print_escaping;
     466           0 :                                         } else if (!strcmp(Z_STRVAL_PP(val), ESCAPING_VALUE_MARKUP)) {
     467           0 :                                                 options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_markup_escaping;
     468             :                                         }
     469             :                                 }
     470             :                         }
     471             :                 }
     472             :         }
     473          22 : }
     474             : 
     475             : 
     476             : /******************
     477             : * encode / decode *
     478             : ******************/
     479             : 
     480             : /* php arrays have no distinction between array and struct types.
     481             :  * they even allow mixed.  Thus, we determine the type by iterating
     482             :  * through the entire array and figuring out each element.
     483             :  * room for some optimation here if we stop after a specific # of elements.
     484             :  */
     485          21 : static XMLRPC_VECTOR_TYPE determine_vector_type (HashTable *ht)
     486             : {
     487          21 :         int bArray = 0, bStruct = 0, bMixed = 0;
     488          21 :         unsigned long num_index, last_num = 0;
     489             :         char* my_key;
     490             : 
     491          21 :         zend_hash_internal_pointer_reset(ht);
     492             :         while (1) {
     493          53 :                 int res = my_zend_hash_get_current_key(ht, &my_key, &num_index);
     494             :                 
     495          53 :                 if (res == HASH_KEY_IS_LONG) {
     496          25 :                         if (bStruct) {
     497           1 :                                 bMixed = 1;
     498           1 :                                 break;
     499          24 :                         } else if (last_num > 0 && last_num != num_index-1) {
     500           2 :                                 bStruct = 1;
     501           2 :                                 break;
     502             :                         }
     503          22 :                         bArray = 1;
     504          22 :                         last_num = num_index;
     505          28 :                 } else if (res == HASH_KEY_NON_EXISTANT) {
     506          16 :                         break;
     507          12 :                 } else if (res == HASH_KEY_IS_STRING) {
     508          12 :                         if (bArray) {
     509           2 :                                 bMixed = 1;
     510           2 :                                 break;
     511             :                         }
     512          10 :                         bStruct = 1;
     513             :                 }
     514          32 :                 zend_hash_move_forward(ht);
     515          32 :         }
     516          21 :         return bMixed ? xmlrpc_vector_mixed : (bStruct ? xmlrpc_vector_struct : xmlrpc_vector_array);
     517             : }
     518             : 
     519             : /* recursively convert php values into xmlrpc values */
     520          67 : static XMLRPC_VALUE PHP_to_XMLRPC_worker (const char* key, zval* in_val, int depth TSRMLS_DC)
     521             : {
     522          67 :         XMLRPC_VALUE xReturn = NULL;
     523             : 
     524          67 :         if (in_val) {
     525          67 :                 zval* val = NULL;
     526          67 :                 XMLRPC_VALUE_TYPE type = get_zval_xmlrpc_type(in_val, &val);
     527             :         
     528          67 :                 if (val) {
     529          67 :                         switch (type) {
     530             :                                 case xmlrpc_base64:
     531           0 :                                         if (Z_TYPE_P(val) == IS_NULL) {
     532           0 :                                                 xReturn = XMLRPC_CreateValueEmpty();
     533           0 :                                                 XMLRPC_SetValueID(xReturn, key, 0);
     534             :                                         } else {
     535           0 :                                                 xReturn = XMLRPC_CreateValueBase64(key, Z_STRVAL_P(val), Z_STRLEN_P(val));
     536             :                                         }
     537           0 :                                         break;
     538             :                                 case xmlrpc_datetime:
     539           4 :                                         convert_to_string(val);
     540           4 :                                         xReturn = XMLRPC_CreateValueDateTime_ISO8601(key, Z_STRVAL_P(val));
     541           4 :                                         break;
     542             :                                 case xmlrpc_boolean:
     543           0 :                                         convert_to_boolean(val);
     544           0 :                                         xReturn = XMLRPC_CreateValueBoolean(key, Z_LVAL_P(val));
     545           0 :                                         break;
     546             :                                 case xmlrpc_int:
     547          15 :                                         convert_to_long(val);
     548          15 :                                         xReturn = XMLRPC_CreateValueInt(key, Z_LVAL_P(val));
     549          15 :                                         break;
     550             :                                 case xmlrpc_double:
     551           3 :                                         convert_to_double(val);
     552           3 :                                         xReturn = XMLRPC_CreateValueDouble(key, Z_DVAL_P(val));
     553           3 :                                         break;
     554             :                                 case xmlrpc_string:
     555          29 :                                         convert_to_string(val);
     556          29 :                                         xReturn = XMLRPC_CreateValueString(key, Z_STRVAL_P(val), Z_STRLEN_P(val));
     557          29 :                                         break;
     558             :                                 case xmlrpc_vector:
     559             :                                         {
     560             :                                                 unsigned long num_index;
     561             :                                                 zval** pIter;
     562             :                                                 char* my_key;
     563          16 :                                                 HashTable *ht = NULL;
     564             :                                                 zval *val_arr;
     565             :                                                 XMLRPC_VECTOR_TYPE vtype;
     566             : 
     567          16 :                                                 ht = HASH_OF(val);
     568          16 :                                                 if (ht && ht->nApplyCount > 1) {
     569           0 :                                                         php_error_docref(NULL TSRMLS_CC, E_ERROR, "XML-RPC doesn't support circular references");
     570           0 :                                                         return NULL;
     571             :                                                 }
     572             : 
     573          16 :                                                 MAKE_STD_ZVAL(val_arr);
     574          48 :                                                 MAKE_COPY_ZVAL(&val, val_arr);
     575          16 :                                                 convert_to_array(val_arr);
     576             :                                                 
     577          16 :                                                 vtype = determine_vector_type(Z_ARRVAL_P(val_arr));
     578          16 :                                                 xReturn = XMLRPC_CreateVector(key, vtype);
     579             : 
     580          16 :                                                 zend_hash_internal_pointer_reset(Z_ARRVAL_P(val_arr));
     581          64 :                                                 while(zend_hash_get_current_data(Z_ARRVAL_P(val_arr), (void**)&pIter) == SUCCESS) {
     582          32 :                                                         int res = my_zend_hash_get_current_key(Z_ARRVAL_P(val_arr), &my_key, &num_index);
     583             : 
     584          32 :                                                         switch (res) {
     585             :                                                                 case HASH_KEY_NON_EXISTANT:
     586           0 :                                                                         break;
     587             :                                                                 case HASH_KEY_IS_STRING:
     588             :                                                                 case HASH_KEY_IS_LONG:
     589          32 :                                                                         ht = HASH_OF(*pIter);
     590          32 :                                                                         if (ht) {
     591           4 :                                                                                 ht->nApplyCount++;
     592             :                                                                         }
     593          32 :                                                                         if (res == HASH_KEY_IS_LONG) {
     594          23 :                                                                                 char *num_str = NULL;
     595             :                                                                                 
     596          23 :                                                                                 if (vtype != xmlrpc_vector_array) {
     597          12 :                                                                                         spprintf(&num_str, 0, "%ld", num_index);
     598             :                                                                                 }
     599          23 :                                                                                 XMLRPC_AddValueToVector(xReturn, PHP_to_XMLRPC_worker(num_str, *pIter, depth++ TSRMLS_CC));
     600          23 :                                                                                 if (num_str) {
     601          12 :                                                                                         efree(num_str);
     602             :                                                                                 }
     603             :                                                                         } else {
     604           9 :                                                                                 XMLRPC_AddValueToVector(xReturn, PHP_to_XMLRPC_worker(my_key, *pIter, depth++ TSRMLS_CC));
     605             :                                                                         }
     606          32 :                                                                         if (ht) {
     607           4 :                                                                                 ht->nApplyCount--;
     608             :                                                                         }
     609             :                                                                         break;
     610             :                                                         }
     611          32 :                                                         zend_hash_move_forward(Z_ARRVAL_P(val_arr));
     612             :                                                 }       
     613          16 :                                                 zval_ptr_dtor(&val_arr);
     614             :                                         }
     615             :                                         break;
     616             :                                 default:
     617             :                                         break;
     618             :                         }
     619             :                 }
     620             :         }
     621          67 :         return xReturn;
     622             : }
     623             : 
     624          35 : static XMLRPC_VALUE PHP_to_XMLRPC(zval* root_val TSRMLS_DC)
     625             : {
     626          35 :         return PHP_to_XMLRPC_worker(NULL, root_val, 0 TSRMLS_CC);
     627             : }
     628             : 
     629             : /* recursively convert xmlrpc values into php values */
     630          54 : static zval* XMLRPC_to_PHP(XMLRPC_VALUE el)
     631             : {
     632          54 :         zval* elem = NULL;
     633             :         const char* pStr;
     634             : 
     635          54 :         if (el) {
     636          53 :                 XMLRPC_VALUE_TYPE type = XMLRPC_GetValueType(el);
     637             : 
     638          53 :                 MAKE_STD_ZVAL(elem); /* init. very important.  spent a frustrating day finding this out. */
     639             : 
     640          53 :                 switch(type) {
     641             :                         case xmlrpc_empty:
     642           1 :                                 Z_TYPE_P(elem) = IS_NULL;
     643           1 :                                 break;
     644             :                         case xmlrpc_string:
     645          20 :                                 pStr = XMLRPC_GetValueString(el);
     646          20 :                                 if (pStr) {
     647          20 :                                         Z_STRLEN_P(elem) = XMLRPC_GetValueStringLen(el);
     648          20 :                                         Z_STRVAL_P(elem) = estrndup(pStr, Z_STRLEN_P(elem));
     649          20 :                                         Z_TYPE_P(elem) = IS_STRING;
     650             :                                 }
     651          20 :                                 break;
     652             :                         case xmlrpc_int:
     653           8 :                                 Z_LVAL_P(elem) = XMLRPC_GetValueInt(el);
     654           8 :                                 Z_TYPE_P(elem) = IS_LONG;
     655           8 :                                 break;
     656             :                         case xmlrpc_boolean:
     657           0 :                                 Z_LVAL_P(elem) = XMLRPC_GetValueBoolean(el);
     658           0 :                                 Z_TYPE_P(elem) = IS_BOOL;
     659           0 :                                 break;
     660             :                         case xmlrpc_double:
     661           0 :                                 Z_DVAL_P(elem) = XMLRPC_GetValueDouble(el);
     662           0 :                                 Z_TYPE_P(elem) = IS_DOUBLE;
     663           0 :                                 break;
     664             :                         case xmlrpc_datetime:
     665           5 :                                 Z_STRLEN_P(elem) = XMLRPC_GetValueStringLen(el);
     666           5 :                                 Z_STRVAL_P(elem) = estrndup(XMLRPC_GetValueDateTime_ISO8601(el), Z_STRLEN_P(elem));
     667           5 :                                 Z_TYPE_P(elem) = IS_STRING;
     668           5 :                                 break;
     669             :                         case xmlrpc_base64:
     670           0 :                                 pStr = XMLRPC_GetValueBase64(el);
     671           0 :                                 if (pStr) {
     672           0 :                                         Z_STRLEN_P(elem) = XMLRPC_GetValueStringLen(el);
     673           0 :                                         Z_STRVAL_P(elem) = estrndup(pStr, Z_STRLEN_P(elem));
     674           0 :                                         Z_TYPE_P(elem) = IS_STRING;
     675             :                                 }
     676           0 :                                 break;
     677             :                         case xmlrpc_vector:
     678          19 :                                 array_init(elem);
     679             :                                 {
     680          19 :                                         XMLRPC_VALUE xIter = XMLRPC_VectorRewind(el);
     681             : 
     682          65 :                                         while( xIter ) {
     683          27 :                                                 zval *val = XMLRPC_to_PHP(xIter);
     684          27 :                                                 if (val) {
     685          27 :                                                         add_zval(elem, XMLRPC_GetValueID(xIter), &val);
     686             :                                                 }
     687          27 :                                                 xIter = XMLRPC_VectorNext(el);
     688             :                                         }
     689             :                                 }
     690             :                                 break;
     691             :                         default:
     692             :                                 break;
     693             :                 }
     694          53 :                 set_zval_xmlrpc_type(elem, type);
     695             :         }
     696          54 :         return elem;
     697             : }
     698             : 
     699             : /* {{{ proto string xmlrpc_encode_request(string method, mixed params [, array output_options])
     700             :    Generates XML for a method request */
     701          15 : PHP_FUNCTION(xmlrpc_encode_request)
     702             : {
     703          15 :         XMLRPC_REQUEST xRequest = NULL;
     704             :         char *outBuf;
     705          15 :         zval *vals, *out_opts = NULL;
     706          15 :         char *method = NULL;
     707             :         int method_len;
     708             :         php_output_options out;
     709             : 
     710          15 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s!z|a", &method, &method_len, &vals, &out_opts) == FAILURE) {
     711           2 :                 return;
     712             :         }
     713             : 
     714          13 :         set_output_options(&out, out_opts ? out_opts : 0);
     715             : 
     716          13 :         if (return_value_used) {
     717          13 :                 xRequest = XMLRPC_RequestNew();
     718             : 
     719          13 :                 if (xRequest) {
     720          13 :                         XMLRPC_RequestSetOutputOptions(xRequest, &out.xmlrpc_out);
     721          13 :                         if (method == NULL) {
     722           0 :                                 XMLRPC_RequestSetRequestType(xRequest, xmlrpc_request_response);
     723             :                         } else {
     724          13 :                                 XMLRPC_RequestSetMethodName(xRequest, method);
     725          13 :                                 XMLRPC_RequestSetRequestType(xRequest, xmlrpc_request_call);
     726             :                         }
     727          13 :                         if (Z_TYPE_P(vals) != IS_NULL) {
     728          13 :                                 XMLRPC_RequestSetData(xRequest, PHP_to_XMLRPC(vals TSRMLS_CC));
     729             :                         }
     730             : 
     731          13 :                         outBuf = XMLRPC_REQUEST_ToXML(xRequest, 0);
     732          13 :                         if (outBuf) {
     733          13 :                                 RETVAL_STRING(outBuf, 1);
     734          13 :                                 free(outBuf);
     735             :                         }
     736          13 :                         XMLRPC_RequestFree(xRequest, 1);
     737             :                 }
     738             :         }
     739             :         
     740          13 :         if (strcmp(out.xmlrpc_out.xml_elem_opts.encoding, ENCODING_DEFAULT) != 0) {
     741           0 :                 efree((char *)out.xmlrpc_out.xml_elem_opts.encoding);
     742             :         }
     743             : }
     744             : /* }}} */
     745             : 
     746             : /* {{{ proto string xmlrpc_encode(mixed value)
     747             :    Generates XML for a PHP value */
     748          14 : PHP_FUNCTION(xmlrpc_encode)
     749             : {
     750          14 :         XMLRPC_VALUE xOut = NULL;
     751             :         zval **arg1;
     752             :         char *outBuf;
     753             : 
     754          14 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg1) == FAILURE) {
     755           0 :                 return;
     756             :         }
     757             : 
     758          14 :         if (return_value_used) {
     759             :                 /* convert native php type to xmlrpc type */
     760          14 :                 xOut = PHP_to_XMLRPC(*arg1 TSRMLS_CC);
     761             : 
     762             :                 /* generate raw xml from xmlrpc data */
     763          14 :                 outBuf = XMLRPC_VALUE_ToXML(xOut, 0);
     764             : 
     765          14 :                 if (xOut) {
     766          14 :                         if (outBuf) {
     767          14 :                                 RETVAL_STRING(outBuf, 1);
     768          14 :                                 free(outBuf);
     769             :                         }
     770             :                         /* cleanup */
     771          14 :                         XMLRPC_CleanupValue(xOut);
     772             :                 }
     773             :         }
     774             : }
     775             : /* }}} */
     776             : 
     777          18 : zval* decode_request_worker(char *xml_in, int xml_in_len, char *encoding_in, zval* method_name_out) /* {{{ */
     778             : {
     779          18 :         zval* retval = NULL;
     780             :         XMLRPC_REQUEST response;
     781          18 :         STRUCT_XMLRPC_REQUEST_INPUT_OPTIONS opts = {{0}};
     782             :         const char *method_name;
     783          18 :         opts.xml_elem_opts.encoding = encoding_in ? utf8_get_encoding_id_from_string(encoding_in) : ENCODING_DEFAULT;
     784             : 
     785             :         /* generate XMLRPC_REQUEST from raw xml */
     786          18 :         response = XMLRPC_REQUEST_FromXML(xml_in, xml_in_len, &opts);
     787          18 :         if (response) {
     788             :                 /* convert xmlrpc data to native php types */
     789          18 :                 retval = XMLRPC_to_PHP(XMLRPC_RequestGetData(response));
     790             : 
     791          18 :                 if (XMLRPC_RequestGetRequestType(response) == xmlrpc_request_call) {
     792           5 :                         if (method_name_out) {
     793           5 :                                 method_name = XMLRPC_RequestGetMethodName(response);
     794           5 :                                 if (method_name) {
     795             :                                         zval_dtor(method_name_out);
     796           4 :                                         Z_TYPE_P(method_name_out) = IS_STRING;
     797           4 :                                         Z_STRVAL_P(method_name_out) = estrdup(method_name);
     798           4 :                                         Z_STRLEN_P(method_name_out) = strlen(Z_STRVAL_P(method_name_out));
     799           1 :                                 } else if (retval) {
     800           1 :                                         zval_ptr_dtor(&retval);
     801           1 :                                         retval = NULL;
     802             :                                 }
     803             :                         }
     804             :                 }
     805             : 
     806             :                 /* dust, sweep, and mop */
     807          18 :                 XMLRPC_RequestFree(response, 1);
     808             :         }
     809          18 :         return retval;
     810             : }
     811             : /* }}} */
     812             : 
     813             : /* {{{ proto array xmlrpc_decode_request(string xml, string& method [, string encoding])
     814             :    Decodes XML into native PHP types */
     815           6 : PHP_FUNCTION(xmlrpc_decode_request)
     816             : {
     817           6 :         char *xml, *encoding = NULL;
     818             :         zval **method;
     819           6 :         int xml_len, encoding_len = 0;
     820             : 
     821           6 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sZ|s", &xml, &xml_len, &method, &encoding, &encoding_len) == FAILURE) {
     822           0 :                 return;
     823             :         }
     824             : 
     825             : 
     826           6 :         if (return_value_used) {
     827           6 :                 zval* retval = decode_request_worker(xml, xml_len, encoding_len ? encoding : NULL, *method);
     828           6 :                 if (retval) {
     829           4 :                         *return_value = *retval;
     830           4 :                         FREE_ZVAL(retval);
     831             :                 }
     832             :         }
     833             : }
     834             : /* }}} */
     835             : 
     836             : /* {{{ proto array xmlrpc_decode(string xml [, string encoding])
     837             :    Decodes XML into native PHP types */
     838          12 : PHP_FUNCTION(xmlrpc_decode)
     839             : {
     840          12 :         char *arg1, *arg2 = NULL;
     841          12 :         int arg1_len, arg2_len = 0;
     842             : 
     843          12 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &arg1, &arg1_len, &arg2, &arg2_len) == FAILURE) {
     844           0 :                 return;
     845             :         }
     846             : 
     847          12 :         if (return_value_used) {
     848          12 :                 zval* retval = decode_request_worker(arg1, arg1_len, arg2_len ? arg2 : NULL, NULL);
     849          12 :                 if (retval) {
     850          12 :                         *return_value = *retval;
     851          12 :                         FREE_ZVAL(retval);
     852             :                 }
     853             :         }
     854             : }
     855             : /* }}} */
     856             : 
     857             : /*************************
     858             : * server related methods *
     859             : *************************/
     860             : 
     861             : /* {{{ proto resource xmlrpc_server_create(void)
     862             :    Creates an xmlrpc server */
     863          10 : PHP_FUNCTION(xmlrpc_server_create)
     864             : {
     865          10 :         if (zend_parse_parameters_none() == FAILURE) {
     866           0 :                 return;
     867             :         }
     868             : 
     869          10 :         if (return_value_used) {
     870             :                 zval *method_map, *introspection_map;
     871          10 :                 xmlrpc_server_data *server = emalloc(sizeof(xmlrpc_server_data));
     872          10 :                 MAKE_STD_ZVAL(method_map);
     873          10 :                 MAKE_STD_ZVAL(introspection_map);
     874             :                 
     875          10 :                 array_init(method_map);
     876          10 :                 array_init(introspection_map);
     877             :                 
     878             :                 /* allocate server data.  free'd in destroy_server_data() */
     879          10 :                 server->method_map = method_map;
     880          10 :                 server->introspection_map = introspection_map;
     881          10 :                 server->server_ptr = XMLRPC_ServerCreate();
     882             : 
     883          10 :                 XMLRPC_ServerRegisterIntrospectionCallback(server->server_ptr, php_xmlrpc_introspection_callback);
     884             : 
     885             :                 /* store for later use */
     886          10 :                 ZEND_REGISTER_RESOURCE(return_value,server, le_xmlrpc_server);
     887             :         }
     888             : }
     889             : /* }}} */
     890             : 
     891             : /* {{{ proto int xmlrpc_server_destroy(resource server)
     892             :    Destroys server resources */
     893           0 : PHP_FUNCTION(xmlrpc_server_destroy)
     894             : {
     895             :         zval *arg1;
     896           0 :         int bSuccess = FAILURE, type;
     897             :         xmlrpc_server_data *server;
     898             : 
     899           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) {
     900           0 :                 return;
     901             :         }
     902             : 
     903           0 :         server = zend_list_find(Z_LVAL_P(arg1), &type);
     904             : 
     905           0 :         if (server && type == le_xmlrpc_server) {
     906           0 :                 bSuccess = zend_list_delete(Z_LVAL_P(arg1));
     907             : 
     908             :                 /* called by hashtable destructor
     909             :                  * destroy_server_data(server);
     910             :                  */
     911             :         }
     912           0 :         RETVAL_LONG(bSuccess == SUCCESS);
     913             : }
     914             : /* }}} */
     915             :            
     916             : /* called by xmlrpc C engine as method handler for all registered methods.
     917             :  * it then calls the corresponding PHP function to handle the method.
     918             :  */
     919           8 : static XMLRPC_VALUE php_xmlrpc_callback(XMLRPC_SERVER server, XMLRPC_REQUEST xRequest, void* data) /* {{{ */
     920             : {
     921           8 :         xmlrpc_callback_data* pData = (xmlrpc_callback_data*)data;
     922             :         zval** php_function;
     923             :         zval* xmlrpc_params;
     924             :         zval* callback_params[3];
     925             :         TSRMLS_FETCH();
     926             : 
     927           8 :         zval_dtor(pData->xmlrpc_method);
     928           8 :         zval_dtor(pData->return_data);
     929             : 
     930             :         /* convert xmlrpc to native php types */
     931           8 :         ZVAL_STRING(pData->xmlrpc_method, XMLRPC_RequestGetMethodName(xRequest), 1);
     932           8 :         xmlrpc_params = XMLRPC_to_PHP(XMLRPC_RequestGetData(xRequest));
     933             :         
     934             :         /* check if the called method has been previous registered */
     935          24 :         if(zend_hash_find(Z_ARRVAL_P(pData->server->method_map),
     936           8 :                       Z_STRVAL_P(pData->xmlrpc_method), 
     937           8 :                       Z_STRLEN_P(pData->xmlrpc_method) + 1, 
     938             :                       (void**)&php_function) == SUCCESS) {
     939             : 
     940           8 :                 pData->php_function = *php_function;
     941             :         }
     942             : 
     943             :         /* setup data hoojum */
     944           8 :         callback_params[0] = pData->xmlrpc_method;
     945           8 :         callback_params[1] = xmlrpc_params;
     946           8 :         callback_params[2] = pData->caller_params;
     947             : 
     948             :         /* Use same C function for all methods */
     949             : 
     950             :         /* php func prototype: function user_func($method_name, $xmlrpc_params, $user_params) */
     951           8 :         call_user_function(CG(function_table), NULL, pData->php_function, pData->return_data, 3, callback_params TSRMLS_CC);
     952             : 
     953           8 :         pData->php_executed = 1;
     954             : 
     955           8 :         zval_ptr_dtor(&xmlrpc_params);
     956             : 
     957           8 :         return PHP_to_XMLRPC(pData->return_data TSRMLS_CC);
     958             : }
     959             : /* }}} */
     960             : 
     961             : /* called by the C server when it first receives an introspection request.  We pass this on to
     962             :  * our PHP listeners, if any
     963             :  */
     964           2 : static void php_xmlrpc_introspection_callback(XMLRPC_SERVER server, void* data) /* {{{ */
     965             : {
     966             :         zval retval, **php_function;
     967             :         zval *callback_params[1];
     968             :         char *php_function_name;
     969           2 :         xmlrpc_callback_data* pData = (xmlrpc_callback_data*)data;
     970             :         TSRMLS_FETCH();
     971             : 
     972             :         /* setup data hoojum */
     973           2 :         callback_params[0] = pData->caller_params;
     974             : 
     975             :         /* loop through and call all registered callbacks */
     976           2 :         zend_hash_internal_pointer_reset(Z_ARRVAL_P(pData->server->introspection_map));
     977             :         while (1) {
     978           7 :                 if (zend_hash_get_current_data(Z_ARRVAL_P(pData->server->introspection_map), (void**)&php_function) == SUCCESS) {
     979           5 :                         if (zend_is_callable(*php_function, 0, &php_function_name TSRMLS_CC)) {
     980             :                                 /* php func prototype: function string user_func($user_params) */
     981           1 :                                 if (call_user_function(CG(function_table), NULL, *php_function, &retval, 1, callback_params TSRMLS_CC) == SUCCESS) {
     982             :                                         XMLRPC_VALUE xData;
     983           1 :                                         STRUCT_XMLRPC_ERROR err = {0};
     984             : 
     985             :                                         /* return value should be a string */
     986           1 :                                         convert_to_string(&retval);
     987             : 
     988           1 :                                         xData = XMLRPC_IntrospectionCreateDescription(Z_STRVAL(retval), &err);
     989             : 
     990           1 :                                         if (xData) {
     991           0 :                                                 if (!XMLRPC_ServerAddIntrospectionData(server, xData)) {
     992           0 :                                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to add introspection data returned from %s(), improper element structure", php_function_name);
     993             :                                                 }
     994           0 :                                                 XMLRPC_CleanupValue(xData);
     995             :                                         } else {
     996             :                                                 /* could not create description */
     997           1 :                                                 if (err.xml_elem_error.parser_code) {
     998           1 :                                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "xml parse error: [line %ld, column %ld, message: %s] Unable to add introspection data returned from %s()", 
     999             :                                                                 err.xml_elem_error.column, err.xml_elem_error.line, err.xml_elem_error.parser_error, php_function_name);
    1000             :                                                 } else {
    1001           0 :                                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to add introspection data returned from %s()", php_function_name);
    1002             :                                                 }
    1003             :                                         }
    1004             :                                         zval_dtor(&retval);
    1005             :                                 } else {
    1006             :                                         /* user func failed */
    1007           0 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error calling user introspection callback: %s()", php_function_name);
    1008             :                                 }
    1009             :                         } else {
    1010           4 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid callback '%s' passed", php_function_name);
    1011             :                         }
    1012           5 :                         efree(php_function_name);
    1013             :                 } else {
    1014           2 :                         break;
    1015             :                 }
    1016           5 :                 zend_hash_move_forward(Z_ARRVAL_P(pData->server->introspection_map));
    1017           5 :         }
    1018             :         
    1019             :         /* so we don't call the same callbacks ever again */
    1020           2 :         zend_hash_clean(Z_ARRVAL_P(pData->server->introspection_map));
    1021           2 : }
    1022             : /* }}} */
    1023             : 
    1024             : /* {{{ proto bool xmlrpc_server_register_method(resource server, string method_name, string function)
    1025             :    Register a PHP function to handle method matching method_name */
    1026           9 : PHP_FUNCTION(xmlrpc_server_register_method)
    1027             : {
    1028             :         char *method_key;
    1029             :         int method_key_len;
    1030             :         zval *handle, *method_name_save, **method_name;
    1031             :         int type;
    1032             :         xmlrpc_server_data* server;
    1033             : 
    1034           9 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsZ", &handle, &method_key, &method_key_len, &method_name) == FAILURE) {
    1035           0 :                 return;
    1036             :         }
    1037             : 
    1038           9 :         server = zend_list_find(Z_LVAL_P(handle), &type);
    1039             : 
    1040           9 :         if (type == le_xmlrpc_server) {
    1041             :                 /* register with C engine. every method just calls our standard callback, 
    1042             :                  * and it then dispatches to php as necessary
    1043             :                  */
    1044           9 :                 if (XMLRPC_ServerRegisterMethod(server->server_ptr, method_key, php_xmlrpc_callback)) {
    1045             :                         /* save for later use */
    1046           9 :                         ALLOC_ZVAL(method_name_save);
    1047          27 :                         MAKE_COPY_ZVAL(method_name, method_name_save);
    1048             : 
    1049             :                         /* register our php method */
    1050           9 :                         add_zval(server->method_map, method_key, &method_name_save);
    1051             : 
    1052           9 :                         RETURN_BOOL(1);
    1053             :                 }
    1054             :         }
    1055           0 :         RETURN_BOOL(0);
    1056             : }
    1057             : /* }}} */
    1058             : 
    1059             : /* {{{ proto bool xmlrpc_server_register_introspection_callback(resource server, string function)
    1060             :    Register a PHP function to generate documentation */
    1061           6 : PHP_FUNCTION(xmlrpc_server_register_introspection_callback)
    1062             : {
    1063             :         zval **method_name, *handle, *method_name_save;
    1064             :         int type;
    1065             :         xmlrpc_server_data* server;
    1066             : 
    1067           6 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZ", &handle, &method_name) == FAILURE) {
    1068           0 :                 return;
    1069             :         }
    1070             : 
    1071           6 :         server = zend_list_find(Z_LVAL_P(handle), &type);
    1072             : 
    1073           6 :         if (type == le_xmlrpc_server) {
    1074             :                 /* save for later use */
    1075           6 :                 ALLOC_ZVAL(method_name_save);
    1076          18 :                 MAKE_COPY_ZVAL(method_name, method_name_save);
    1077             : 
    1078             :                 /* register our php method */
    1079           6 :                 add_zval(server->introspection_map, NULL, &method_name_save);
    1080             : 
    1081           6 :                 RETURN_BOOL(1);
    1082             :         }
    1083           0 :         RETURN_BOOL(0);
    1084             : }
    1085             : /* }}} */
    1086             : 
    1087             : /* this function is itchin for a re-write */
    1088             : 
    1089             : /* {{{ proto mixed xmlrpc_server_call_method(resource server, string xml, mixed user_data [, array output_options])
    1090             :    Parses XML requests and call methods */
    1091           9 : PHP_FUNCTION(xmlrpc_server_call_method)
    1092             : {
    1093           9 :         xmlrpc_callback_data data = {0};
    1094             :         XMLRPC_REQUEST xRequest;
    1095             :         STRUCT_XMLRPC_REQUEST_INPUT_OPTIONS input_opts;
    1096             :         xmlrpc_server_data* server;
    1097           9 :         zval **caller_params, *handle, *output_opts = NULL;
    1098             :         char *rawxml;
    1099             :         int rawxml_len, type;
    1100             :         php_output_options out;
    1101           9 :         int argc =ZEND_NUM_ARGS();
    1102             :         
    1103           9 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsZ|a", &handle, &rawxml, &rawxml_len, &caller_params, &output_opts) != SUCCESS) {
    1104           0 :                 return;
    1105             :         }
    1106             :         /* user output options */
    1107           9 :         if (argc == 3) {
    1108           7 :                 set_output_options(&out, NULL);
    1109             :         } else {
    1110           2 :                 set_output_options(&out, output_opts);
    1111             :         }
    1112             : 
    1113           9 :         server = zend_list_find(Z_LVAL_P(handle), &type);
    1114             : 
    1115           9 :         if (type == le_xmlrpc_server) {
    1116             :                 /* HACK: use output encoding for now */
    1117           9 :                 input_opts.xml_elem_opts.encoding = utf8_get_encoding_id_from_string(out.xmlrpc_out.xml_elem_opts.encoding);
    1118             : 
    1119             :                 /* generate an XMLRPC_REQUEST from the raw xml input */
    1120           9 :                 xRequest = XMLRPC_REQUEST_FromXML(rawxml, rawxml_len, &input_opts);
    1121             : 
    1122           9 :                 if (xRequest) {
    1123           9 :                         const char* methodname = XMLRPC_RequestGetMethodName(xRequest);
    1124           9 :                         XMLRPC_VALUE xAnswer = NULL;
    1125           9 :                         MAKE_STD_ZVAL(data.xmlrpc_method); /* init. very important.  spent a frustrating day finding this out. */
    1126           9 :                         MAKE_STD_ZVAL(data.return_data);
    1127           9 :                         Z_TYPE_P(data.return_data) = IS_NULL;  /* in case value is never init'd, we don't dtor to think it is a string or something */
    1128           9 :                         Z_TYPE_P(data.xmlrpc_method) = IS_NULL;
    1129             : 
    1130             :                         /* setup some data to pass to the callback function */
    1131           9 :                         data.caller_params = *caller_params;
    1132           9 :                         data.php_executed = 0;
    1133           9 :                         data.server = server;
    1134             : 
    1135             :                         /* We could just call the php method directly ourselves at this point, but we do this 
    1136             :                          * with a C callback in case the xmlrpc library ever implements some cool usage stats,
    1137             :                          * or somesuch.
    1138             :                          */
    1139           9 :                         xAnswer = XMLRPC_ServerCallMethod(server->server_ptr, xRequest, &data);
    1140           9 :                         if (xAnswer && out.b_php_out) {
    1141           0 :                                 zval_dtor(data.return_data);
    1142           0 :                                 FREE_ZVAL(data.return_data);
    1143           0 :                                 data.return_data = XMLRPC_to_PHP(xAnswer);
    1144           9 :                         } else if (data.php_executed && !out.b_php_out && !xAnswer) {
    1145           0 :                                 xAnswer = PHP_to_XMLRPC(data.return_data TSRMLS_CC);
    1146             :                         }
    1147             : 
    1148             :                         /* should we return data as xml? */
    1149           9 :                         if (!out.b_php_out) {
    1150           9 :                                 XMLRPC_REQUEST xResponse = XMLRPC_RequestNew();
    1151           9 :                                 if (xResponse) {
    1152           9 :                                         char *outBuf = 0;
    1153           9 :                                         int buf_len = 0;
    1154             : 
    1155             :                                         /* automagically determine output serialization type from request type */
    1156           9 :                                         if (out.b_auto_version) { 
    1157           7 :                                                 XMLRPC_REQUEST_OUTPUT_OPTIONS opts = XMLRPC_RequestGetOutputOptions(xRequest);
    1158           7 :                                                 if (opts) {
    1159           7 :                                                         out.xmlrpc_out.version = opts->version;
    1160             :                                                 }
    1161             :                                         }
    1162             :                                         /* set some required request hoojum */
    1163           9 :                                         XMLRPC_RequestSetOutputOptions(xResponse, &out.xmlrpc_out);
    1164           9 :                                         XMLRPC_RequestSetRequestType(xResponse, xmlrpc_request_response);
    1165           9 :                                         XMLRPC_RequestSetData(xResponse, xAnswer);
    1166           9 :                                         XMLRPC_RequestSetMethodName(xResponse, methodname);
    1167             : 
    1168             :                                         /* generate xml */
    1169           9 :                                         outBuf = XMLRPC_REQUEST_ToXML(xResponse, &buf_len);
    1170           9 :                                         if (outBuf) {
    1171           9 :                                                 RETVAL_STRINGL(outBuf, buf_len, 1);
    1172           9 :                                                 free(outBuf);
    1173             :                                         }
    1174             :                                         /* cleanup after ourselves.  what a sty! */
    1175           9 :                                         XMLRPC_RequestFree(xResponse, 0);
    1176             :                                 }
    1177             :                         } else { /* or as native php types? */
    1178           0 :                                 *return_value = *data.return_data;
    1179             :                                 zval_copy_ctor(return_value);
    1180             :                         }
    1181             : 
    1182             :                         /* cleanup after ourselves.  what a sty! */
    1183           9 :                         zval_ptr_dtor(&data.xmlrpc_method);
    1184             : 
    1185           9 :                         zval_dtor(data.return_data);
    1186           9 :                         FREE_ZVAL(data.return_data);
    1187             : 
    1188           9 :                         if (xAnswer) {
    1189           9 :                                 XMLRPC_CleanupValue(xAnswer);
    1190             :                         }
    1191             : 
    1192           9 :                         XMLRPC_RequestFree(xRequest, 1);
    1193             :                 }
    1194             :         }
    1195             : }
    1196             : /* }}} */
    1197             : 
    1198             : /* {{{ proto int xmlrpc_server_add_introspection_data(resource server, array desc)
    1199             :    Adds introspection documentation  */
    1200           0 : PHP_FUNCTION(xmlrpc_server_add_introspection_data)
    1201             : {
    1202             :         zval *handle, *desc;
    1203             :         int type;
    1204             :         xmlrpc_server_data* server;
    1205             : 
    1206           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ra", &handle, &desc) == FAILURE) {
    1207           0 :                 return;
    1208             :         }
    1209             : 
    1210           0 :         server = zend_list_find(Z_LVAL_P(handle), &type);
    1211             : 
    1212           0 :         if (type == le_xmlrpc_server) {
    1213           0 :                 XMLRPC_VALUE xDesc = PHP_to_XMLRPC(desc TSRMLS_CC);
    1214           0 :                 if (xDesc) {
    1215           0 :                         int retval = XMLRPC_ServerAddIntrospectionData(server->server_ptr, xDesc);
    1216           0 :                         XMLRPC_CleanupValue(xDesc);
    1217           0 :                         RETURN_LONG(retval);
    1218             :                 }
    1219             :         }
    1220           0 :         RETURN_LONG(0);
    1221             : }
    1222             : /* }}} */
    1223             : 
    1224             : /* {{{ proto array xmlrpc_parse_method_descriptions(string xml)
    1225             :    Decodes XML into a list of method descriptions */
    1226           1 : PHP_FUNCTION(xmlrpc_parse_method_descriptions)
    1227             : {
    1228             :         zval *retval;
    1229             :         char *arg1;
    1230             :         int arg1_len;
    1231             : 
    1232           1 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg1, &arg1_len) == FAILURE) {
    1233           0 :                 return;
    1234             :         }
    1235             : 
    1236           1 :         if (return_value_used) {
    1237           1 :                 STRUCT_XMLRPC_ERROR err = {0};
    1238           1 :                 XMLRPC_VALUE xVal = XMLRPC_IntrospectionCreateDescription(arg1, &err);
    1239           1 :                 if (xVal) {
    1240           1 :                         retval = XMLRPC_to_PHP(xVal);
    1241             : 
    1242           1 :                         if (retval) {
    1243           3 :                                 RETVAL_ZVAL(retval, 1, 1);
    1244             :                         }
    1245             :                         /* dust, sweep, and mop */
    1246           1 :                         XMLRPC_CleanupValue(xVal);
    1247             :                 } else {
    1248             :                         /* could not create description */
    1249           0 :                         if (err.xml_elem_error.parser_code) {
    1250           0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "xml parse error: [line %ld, column %ld, message: %s] Unable to create introspection data", 
    1251             :                                                 err.xml_elem_error.column, err.xml_elem_error.line, err.xml_elem_error.parser_error);
    1252             :                         } else {
    1253           0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid xml structure. Unable to create introspection data");
    1254             :                         }
    1255             : 
    1256           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "xml parse error. no method description created");
    1257             :                 }
    1258             :         }
    1259             : }
    1260             : /* }}} */
    1261             : 
    1262             : /************
    1263             : * type data *
    1264             : ************/
    1265             : 
    1266             : #define XMLRPC_TYPE_COUNT 9
    1267             : #define XMLRPC_VECTOR_TYPE_COUNT 4
    1268             : #define TYPE_STR_MAP_SIZE (XMLRPC_TYPE_COUNT + XMLRPC_VECTOR_TYPE_COUNT)
    1269             : 
    1270             : /* return a string matching a given xmlrpc type */
    1271          22 : static const char** get_type_str_mapping(void) /* {{{ */
    1272             : {
    1273             :         static const char* str_mapping[TYPE_STR_MAP_SIZE];
    1274             :         static int first = 1;
    1275          22 :         if (first) {
    1276             :                 /* warning. do not add/delete without changing size define */
    1277           6 :                 str_mapping[xmlrpc_none]     = "none";
    1278           6 :                 str_mapping[xmlrpc_empty]    = "empty";
    1279           6 :                 str_mapping[xmlrpc_base64]   = "base64";
    1280           6 :                 str_mapping[xmlrpc_boolean]  = "boolean";
    1281           6 :                 str_mapping[xmlrpc_datetime] = "datetime";
    1282           6 :                 str_mapping[xmlrpc_double]   = "double";
    1283           6 :                 str_mapping[xmlrpc_int]      = "int";
    1284           6 :                 str_mapping[xmlrpc_string]   = "string";
    1285           6 :                 str_mapping[xmlrpc_vector]   = "vector";
    1286           6 :                 str_mapping[XMLRPC_TYPE_COUNT + xmlrpc_vector_none]   = "none";
    1287           6 :                 str_mapping[XMLRPC_TYPE_COUNT + xmlrpc_vector_array]  = "array";
    1288           6 :                 str_mapping[XMLRPC_TYPE_COUNT + xmlrpc_vector_mixed]  = "mixed";
    1289           6 :                 str_mapping[XMLRPC_TYPE_COUNT + xmlrpc_vector_struct] = "struct";
    1290           6 :                 first = 0;
    1291             :         }
    1292          22 :         return (const char**)str_mapping;
    1293             : }
    1294             : /* }}} */
    1295             : 
    1296             : /* map an xmlrpc type to a string */
    1297          14 : const char* xmlrpc_type_as_str(XMLRPC_VALUE_TYPE type, XMLRPC_VECTOR_TYPE vtype) /* {{{ */
    1298             : {
    1299          14 :         const char** str_mapping = get_type_str_mapping();
    1300             : 
    1301          14 :         if (vtype == xmlrpc_vector_none) {
    1302           9 :                 return str_mapping[type];
    1303             :         } else {
    1304           5 :                 return str_mapping[XMLRPC_TYPE_COUNT + vtype];
    1305             :         }
    1306             : }
    1307             : /* }}} */
    1308             : 
    1309             : /* map a string to an xmlrpc type */
    1310           8 : XMLRPC_VALUE_TYPE xmlrpc_str_as_type(const char* str) /* {{{ */
    1311             : {
    1312           8 :         const char** str_mapping = get_type_str_mapping();
    1313             :         int i;
    1314             : 
    1315           8 :         if (str) {
    1316          40 :                 for (i = 0; i < XMLRPC_TYPE_COUNT; i++) {
    1317          40 :                         if (!strcmp(str_mapping[i], str)) {
    1318           8 :                                 return (XMLRPC_VALUE_TYPE) i;
    1319             :                         }
    1320             :                 }
    1321             :         }
    1322           0 :         return xmlrpc_none;
    1323             : }
    1324             : /* }}} */
    1325             : 
    1326             : /* map a string to an xmlrpc vector type */
    1327           0 : XMLRPC_VECTOR_TYPE xmlrpc_str_as_vector_type(const char* str) /* {{{ */
    1328             : {
    1329           0 :         const char** str_mapping = get_type_str_mapping();
    1330             :         int i;
    1331             : 
    1332           0 :         if (str) {
    1333           0 :                 for (i = XMLRPC_TYPE_COUNT; i < TYPE_STR_MAP_SIZE; i++) {
    1334           0 :                         if (!strcmp(str_mapping[i], str)) {
    1335           0 :                                 return (XMLRPC_VECTOR_TYPE) (i - XMLRPC_TYPE_COUNT);
    1336             :                         }
    1337             :                 }
    1338             :         }
    1339           0 :         return xmlrpc_none;
    1340             : }
    1341             : /* }}} */
    1342             : 
    1343             : /* set a given value to a particular type. 
    1344             :  * note: this only works on strings, and only for date and base64,
    1345             :  *       which do not have native php types. black magic lies herein.
    1346             :  */
    1347          57 : int set_zval_xmlrpc_type(zval* value, XMLRPC_VALUE_TYPE newtype) /* {{{ */
    1348             : {
    1349          57 :         int bSuccess = FAILURE;
    1350             :         TSRMLS_FETCH();
    1351             : 
    1352             :         /* we only really care about strings because they can represent
    1353             :          * base64 and datetime.  all other types have corresponding php types
    1354             :          */
    1355          57 :         if (Z_TYPE_P(value) == IS_STRING) {
    1356          29 :                 if (newtype == xmlrpc_base64 || newtype == xmlrpc_datetime) {
    1357           9 :                         const char* typestr = xmlrpc_type_as_str(newtype, xmlrpc_vector_none);
    1358             :                         zval* type;
    1359             : 
    1360           9 :                         MAKE_STD_ZVAL(type);
    1361             : 
    1362           9 :                         Z_TYPE_P(type) = IS_STRING;
    1363           9 :                         Z_STRVAL_P(type) = estrdup(typestr);
    1364           9 :                         Z_STRLEN_P(type) = strlen(typestr);
    1365             : 
    1366           9 :                         if (newtype == xmlrpc_datetime) {
    1367           9 :                                 XMLRPC_VALUE v = XMLRPC_CreateValueDateTime_ISO8601(NULL, value->value.str.val);
    1368           9 :                                 if (v) {
    1369           9 :                                         time_t timestamp = (time_t) php_parse_date((char *)XMLRPC_GetValueDateTime_ISO8601(v), NULL);
    1370           9 :                                         if (timestamp != -1) {
    1371             :                                                 zval* ztimestamp;
    1372             : 
    1373           8 :                                                 MAKE_STD_ZVAL(ztimestamp);
    1374             : 
    1375           8 :                                                 ztimestamp->type = IS_LONG;
    1376           8 :                                                 ztimestamp->value.lval = timestamp;
    1377             : 
    1378           8 :                                                 convert_to_object(value);
    1379           8 :                                                 if (SUCCESS == zend_hash_update(Z_OBJPROP_P(value), OBJECT_TYPE_ATTR, sizeof(OBJECT_TYPE_ATTR), (void *) &type, sizeof(zval *), NULL)) {
    1380           8 :                                                         bSuccess = zend_hash_update(Z_OBJPROP_P(value), OBJECT_VALUE_TS_ATTR, sizeof(OBJECT_VALUE_TS_ATTR), (void *) &ztimestamp, sizeof(zval *), NULL);
    1381             :                                                 }
    1382             :                                         } else {
    1383           1 :                                                 zval_ptr_dtor(&type);
    1384             :                                         }
    1385           9 :                                         XMLRPC_CleanupValue(v);
    1386             :                                 } else {
    1387           0 :                                         zval_ptr_dtor(&type);
    1388             :                                 }
    1389             :                         } else {
    1390           0 :                                 convert_to_object(value);
    1391           0 :                                 bSuccess = zend_hash_update(Z_OBJPROP_P(value), OBJECT_TYPE_ATTR, sizeof(OBJECT_TYPE_ATTR), (void *) &type, sizeof(zval *), NULL);
    1392             :                         }
    1393             :                 }
    1394             :         }
    1395             : 
    1396          57 :         return bSuccess;
    1397             : }
    1398             : /* }}} */
    1399             : 
    1400             : /* return xmlrpc type of a php value */
    1401          72 : XMLRPC_VALUE_TYPE get_zval_xmlrpc_type(zval* value, zval** newvalue) /* {{{ */
    1402             : {
    1403          72 :         XMLRPC_VALUE_TYPE type = xmlrpc_none;
    1404             :         TSRMLS_FETCH();
    1405             : 
    1406          72 :         if (value) {
    1407          72 :                 switch (Z_TYPE_P(value)) {
    1408             :                         case IS_NULL:
    1409           0 :                                 type = xmlrpc_base64;
    1410           0 :                                 break;
    1411             : #ifndef BOOL_AS_LONG
    1412             : 
    1413             :                         /* Right thing to do, but it breaks some legacy code. */
    1414             :                         case IS_BOOL:
    1415           0 :                                 type = xmlrpc_boolean;
    1416           0 :                                 break;
    1417             : #else
    1418             :                         case IS_BOOL:
    1419             : #endif
    1420             :                         case IS_LONG:
    1421             :                         case IS_RESOURCE:
    1422          15 :                                 type = xmlrpc_int;
    1423          15 :                                 break;
    1424             :                         case IS_DOUBLE:
    1425           3 :                                 type = xmlrpc_double;
    1426           3 :                                 break;
    1427             :                         case IS_CONSTANT:
    1428           0 :                                 type = xmlrpc_string;
    1429           0 :                                 break;
    1430             :                         case IS_STRING:
    1431          29 :                                 type = xmlrpc_string;
    1432          29 :                                 break;
    1433             :                         case IS_ARRAY:
    1434             :                         case IS_CONSTANT_ARRAY:
    1435          19 :                                 type = xmlrpc_vector;
    1436          19 :                                 break;
    1437             :                         case IS_OBJECT:
    1438             :                                 {
    1439             :                                         zval** attr;
    1440           6 :                                         type = xmlrpc_vector;
    1441             : 
    1442           6 :                                         if (zend_hash_find(Z_OBJPROP_P(value), OBJECT_TYPE_ATTR, sizeof(OBJECT_TYPE_ATTR), (void**) &attr) == SUCCESS) {
    1443           4 :                                                 if (Z_TYPE_PP(attr) == IS_STRING) {
    1444           4 :                                                         type = xmlrpc_str_as_type(Z_STRVAL_PP(attr));
    1445             :                                                 }
    1446             :                                         }
    1447             :                                         break;
    1448             :                                 }
    1449             :                 }
    1450             : 
    1451             :                 /* if requested, return an unmolested (magic removed) copy of the value */
    1452          72 :                 if (newvalue) {
    1453             :                         zval** val;
    1454             : 
    1455          71 :                         if ((type == xmlrpc_base64 && Z_TYPE_P(value) != IS_NULL) || type == xmlrpc_datetime) {
    1456           4 :                                 if (zend_hash_find(Z_OBJPROP_P(value), OBJECT_VALUE_ATTR, sizeof(OBJECT_VALUE_ATTR), (void**) &val) == SUCCESS) {
    1457           4 :                                         *newvalue = *val;
    1458             :                                 }
    1459             :                         } else {
    1460          63 :                                 *newvalue = value;
    1461             :                         }
    1462             :                 }
    1463             :         }
    1464             : 
    1465          72 :         return type;
    1466             : }
    1467             : /* }}} */
    1468             : 
    1469             : /* {{{ proto bool xmlrpc_set_type(string value, string type)
    1470             :    Sets xmlrpc type, base64 or datetime, for a PHP string value */
    1471           4 : PHP_FUNCTION(xmlrpc_set_type)
    1472             : {
    1473             :         zval **arg;
    1474             :         char *type;
    1475             :         int type_len;
    1476             :         XMLRPC_VALUE_TYPE vtype;
    1477             : 
    1478           4 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zs", &arg, &type, &type_len) == FAILURE) {
    1479           0 :                 return;
    1480             :         }
    1481             : 
    1482           4 :         vtype = xmlrpc_str_as_type(type);
    1483           4 :         if (vtype != xmlrpc_none) {
    1484           4 :                 if (set_zval_xmlrpc_type(*arg, vtype) == SUCCESS) {
    1485           3 :                         RETURN_TRUE;
    1486             :                 }
    1487             :         } else {
    1488           0 :                 zend_error(E_WARNING,"invalid type '%s' passed to xmlrpc_set_type()", type);
    1489             :         }
    1490           1 :         RETURN_FALSE;
    1491             : }
    1492             : /* }}} */
    1493             : 
    1494             : /* {{{ proto string xmlrpc_get_type(mixed value)
    1495             :    Gets xmlrpc type for a PHP value. Especially useful for base64 and datetime strings */
    1496           5 : PHP_FUNCTION(xmlrpc_get_type)
    1497             : {
    1498             :         zval **arg;
    1499             :         XMLRPC_VALUE_TYPE type;
    1500           5 :         XMLRPC_VECTOR_TYPE vtype = xmlrpc_vector_none;
    1501             : 
    1502           5 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg) == FAILURE) {
    1503           0 :                 return;
    1504             :         }
    1505             : 
    1506           5 :         type = get_zval_xmlrpc_type(*arg, 0);
    1507           5 :         if (type == xmlrpc_vector) {
    1508           5 :                 vtype = determine_vector_type((Z_TYPE_PP(arg) == IS_OBJECT) ? Z_OBJPROP_PP(arg) : Z_ARRVAL_PP(arg));
    1509             :         }
    1510             :    
    1511           5 :         RETURN_STRING((char*) xmlrpc_type_as_str(type, vtype), 1);
    1512             : }
    1513             : /* }}} */
    1514             : 
    1515             : /* {{{ proto bool xmlrpc_is_fault(array)
    1516             :    Determines if an array value represents an XMLRPC fault. */
    1517           0 : PHP_FUNCTION(xmlrpc_is_fault)
    1518             : {
    1519             :         zval *arg, **val;
    1520             : 
    1521           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &arg) == FAILURE) {
    1522           0 :                 return;
    1523             :         }
    1524             : 
    1525             :         /* The "correct" way to do this would be to call the xmlrpc
    1526             :          * library XMLRPC_ValueIsFault() func.  However, doing that
    1527             :          * would require us to create an xmlrpc value from the php
    1528             :          * array, which is rather expensive, especially if it was
    1529             :          * a big array.  Thus, we resort to this not so clever hackery.
    1530             :          */
    1531           0 :         if (zend_hash_find(Z_ARRVAL_P(arg), FAULT_CODE, FAULT_CODE_LEN + 1, (void**) &val) == SUCCESS && 
    1532           0 :                 zend_hash_find(Z_ARRVAL_P(arg), FAULT_STRING, FAULT_STRING_LEN + 1, (void**) &val) == SUCCESS) {
    1533           0 :                 RETURN_TRUE;
    1534             :         }
    1535             : 
    1536           0 :         RETURN_FALSE;
    1537             : }
    1538             : /* }}} */
    1539             : 
    1540             : /*
    1541             :  * Local variables:
    1542             :  * tab-width: 4
    1543             :  * c-basic-offset: 4
    1544             :  * End:
    1545             :  */
    1546             : 

Generated by: LCOV version 1.10

Generated at Sun, 17 Aug 2014 15:22:03 +0000 (2 days ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.