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

LTP GCOV extension - code coverage report
Current view: directory - xmlrpc - xmlrpc-epi-php.c
Test: PHP Code Coverage
Date: 2008-09-03 Instrumented lines: 566
Code covered: 71.4 % Executed lines: 404
Legend: not executed executed

       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-2008 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: xmlrpc-epi-php.c,v 1.61 2008/08/24 00:45:20 felipe Exp $ */
      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 "php_ini.h"
      71                 : #include "php_xmlrpc.h"
      72                 : #include "xmlrpc.h"
      73                 : 
      74                 : #define PHP_EXT_VERSION "0.51"
      75                 : 
      76                 : static int le_xmlrpc_server;
      77                 : 
      78                 : /* {{{ arginfo */
      79                 : static
      80                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_encode, 0, 0, 1)
      81                 :         ZEND_ARG_INFO(0, value)
      82                 : ZEND_END_ARG_INFO()
      83                 : 
      84                 : static
      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                 : static
      91                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_decode_request, 0, 0, 2)
      92                 :         ZEND_ARG_INFO(0, xml)
      93                 :         ZEND_ARG_INFO(1, method)
      94                 :         ZEND_ARG_INFO(0, encoding)
      95                 : ZEND_END_ARG_INFO()
      96                 : 
      97                 : static
      98                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_encode_request, 0, 0, 2)
      99                 :         ZEND_ARG_INFO(0, method)
     100                 :         ZEND_ARG_INFO(0, params)
     101                 :         ZEND_ARG_INFO(0, output_options)
     102                 : ZEND_END_ARG_INFO()
     103                 : 
     104                 : static
     105                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_set_type, 0, 0, 2)
     106                 :         ZEND_ARG_INFO(1, value)
     107                 :         ZEND_ARG_INFO(0, type)
     108                 : ZEND_END_ARG_INFO()
     109                 : 
     110                 : static
     111                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_is_fault, 0, 0, 1)
     112                 :         ZEND_ARG_INFO(0, arg)
     113                 : ZEND_END_ARG_INFO()
     114                 : 
     115                 : static
     116                 : ZEND_BEGIN_ARG_INFO(arginfo_xmlrpc_server_create, 0)
     117                 : ZEND_END_ARG_INFO()
     118                 : 
     119                 : static
     120                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_server_destroy, 0, 0, 1)
     121                 :         ZEND_ARG_INFO(0, server)
     122                 : ZEND_END_ARG_INFO()
     123                 : 
     124                 : static
     125                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_server_register_method, 0, 0, 3)
     126                 :         ZEND_ARG_INFO(0, server)
     127                 :         ZEND_ARG_INFO(0, method_name)
     128                 :         ZEND_ARG_INFO(0, function)
     129                 : ZEND_END_ARG_INFO()
     130                 : 
     131                 : static
     132                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_server_call_method, 0, 0, 3)
     133                 :         ZEND_ARG_INFO(0, server)
     134                 :         ZEND_ARG_INFO(0, xml)
     135                 :         ZEND_ARG_INFO(0, user_data)
     136                 :         ZEND_ARG_INFO(0, output_options)
     137                 : ZEND_END_ARG_INFO()
     138                 : 
     139                 : static
     140                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_parse_method_descriptions, 0, 0, 1)
     141                 :         ZEND_ARG_INFO(0, xml)
     142                 : ZEND_END_ARG_INFO()
     143                 : 
     144                 : static
     145                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_server_add_introspection_data, 0, 0, 2)
     146                 :         ZEND_ARG_INFO(0, server)
     147                 :         ZEND_ARG_INFO(0, desc)
     148                 : ZEND_END_ARG_INFO()
     149                 : 
     150                 : static
     151                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_server_register_introspection_callback, 0, 0, 2)
     152                 :         ZEND_ARG_INFO(0, server)
     153                 :         ZEND_ARG_INFO(0, function)
     154                 : ZEND_END_ARG_INFO()
     155                 : /* }}} */
     156                 : 
     157                 : const zend_function_entry xmlrpc_functions[] = {
     158                 :         PHP_FE(xmlrpc_encode,                                                                   arginfo_xmlrpc_encode) 
     159                 :         PHP_FE(xmlrpc_decode,                                                                   arginfo_xmlrpc_decode)
     160                 :         PHP_FE(xmlrpc_decode_request,                                                   arginfo_xmlrpc_decode_request)
     161                 :         PHP_FE(xmlrpc_encode_request,                                                   arginfo_xmlrpc_encode_request)
     162                 :         PHP_FE(xmlrpc_get_type,                                                                 arginfo_xmlrpc_encode)
     163                 :         PHP_FE(xmlrpc_set_type,                                                                 arginfo_xmlrpc_set_type)
     164                 :         PHP_FE(xmlrpc_is_fault,                                                                 arginfo_xmlrpc_is_fault)
     165                 :         PHP_FE(xmlrpc_server_create,                                                    arginfo_xmlrpc_server_create)
     166                 :         PHP_FE(xmlrpc_server_destroy,                                                   arginfo_xmlrpc_server_destroy)
     167                 :         PHP_FE(xmlrpc_server_register_method,                                   arginfo_xmlrpc_server_register_method)
     168                 :         PHP_FE(xmlrpc_server_call_method,                                               arginfo_xmlrpc_server_call_method)
     169                 :         PHP_FE(xmlrpc_parse_method_descriptions,                                arginfo_xmlrpc_parse_method_descriptions)
     170                 :         PHP_FE(xmlrpc_server_add_introspection_data,                    arginfo_xmlrpc_server_add_introspection_data)
     171                 :         PHP_FE(xmlrpc_server_register_introspection_callback,   arginfo_xmlrpc_server_register_introspection_callback)
     172                 :         {NULL, NULL, NULL}
     173                 : };
     174                 : 
     175                 : zend_module_entry xmlrpc_module_entry = {
     176                 :         STANDARD_MODULE_HEADER,
     177                 :         "xmlrpc",
     178                 :         xmlrpc_functions,
     179                 :         PHP_MINIT(xmlrpc),
     180                 :         NULL,
     181                 :         NULL,
     182                 :         NULL,
     183                 :         PHP_MINFO(xmlrpc),
     184                 :         PHP_EXT_VERSION,
     185                 :         STANDARD_MODULE_PROPERTIES
     186                 : };
     187                 : 
     188                 : #ifdef COMPILE_DL_XMLRPC
     189                 : ZEND_GET_MODULE(xmlrpc)
     190                 : #endif
     191                 : 
     192                 : /*******************************
     193                 : * local structures and defines *
     194                 : *******************************/
     195                 : 
     196                 : /* per server data */
     197                 : typedef struct _xmlrpc_server_data {
     198                 :         zval* method_map;
     199                 :         zval* introspection_map;
     200                 :         XMLRPC_SERVER server_ptr;
     201                 : } xmlrpc_server_data;
     202                 : 
     203                 : 
     204                 : /* how to format output */
     205                 : typedef struct _php_output_options {
     206                 :         int b_php_out;
     207                 :         int b_auto_version;
     208                 :         STRUCT_XMLRPC_REQUEST_OUTPUT_OPTIONS xmlrpc_out;
     209                 : } php_output_options;
     210                 : 
     211                 : /* data passed to C callback */
     212                 : typedef struct _xmlrpc_callback_data {
     213                 :         zval* xmlrpc_method;
     214                 :         zval* php_function;
     215                 :         zval* caller_params;
     216                 :         zval* return_data;
     217                 :         xmlrpc_server_data* server;
     218                 :         char php_executed;
     219                 : } xmlrpc_callback_data;
     220                 : 
     221                 : /* output options */
     222                 : #define OUTPUT_TYPE_KEY       "output_type"
     223                 : #define OUTPUT_TYPE_KEY_LEN   (sizeof(OUTPUT_TYPE_KEY) - 1)
     224                 : #define OUTPUT_TYPE_VALUE_PHP "php"
     225                 : #define OUTPUT_TYPE_VALUE_XML "xml"
     226                 : 
     227                 : #define VERBOSITY_KEY                  "verbosity"
     228                 : #define VERBOSITY_KEY_LEN              (sizeof(VERBOSITY_KEY) - 1)
     229                 : #define VERBOSITY_VALUE_NO_WHITE_SPACE "no_white_space"
     230                 : #define VERBOSITY_VALUE_NEWLINES_ONLY  "newlines_only"
     231                 : #define VERBOSITY_VALUE_PRETTY         "pretty"
     232                 : 
     233                 : #define ESCAPING_KEY             "escaping"
     234                 : #define ESCAPING_KEY_LEN         (sizeof(ESCAPING_KEY) - 1)
     235                 : #define ESCAPING_VALUE_CDATA     "cdata"
     236                 : #define ESCAPING_VALUE_NON_ASCII "non-ascii"
     237                 : #define ESCAPING_VALUE_NON_PRINT "non-print"
     238                 : #define ESCAPING_VALUE_MARKUP    "markup"
     239                 : 
     240                 : #define VERSION_KEY          "version"
     241                 : #define VERSION_KEY_LEN      (sizeof(VERSION_KEY) - 1)
     242                 : #define VERSION_VALUE_SIMPLE "simple"
     243                 : #define VERSION_VALUE_XMLRPC "xmlrpc"
     244                 : #define VERSION_VALUE_SOAP11 "soap 1.1"
     245                 : #define VERSION_VALUE_AUTO   "auto"
     246                 : 
     247                 : #define ENCODING_KEY     "encoding"
     248                 : #define ENCODING_KEY_LEN (sizeof(ENCODING_KEY) - 1)
     249                 : #define ENCODING_DEFAULT "iso-8859-1"
     250                 : 
     251                 : /* value types */
     252                 : #define OBJECT_TYPE_ATTR  "xmlrpc_type"
     253                 : #define OBJECT_VALUE_ATTR "scalar"
     254                 : #define OBJECT_VALUE_TS_ATTR "timestamp"
     255                 : 
     256                 : /* faults */
     257                 : #define FAULT_CODE       "faultCode"
     258                 : #define FAULT_CODE_LEN   (sizeof(FAULT_CODE) - 1)
     259                 : #define FAULT_STRING     "faultString"
     260                 : #define FAULT_STRING_LEN (sizeof(FAULT_STRING) - 1)
     261                 : 
     262                 : /***********************
     263                 : * forward declarations *
     264                 : ***********************/
     265                 : XMLRPC_VALUE_TYPE get_zval_xmlrpc_type(zval* value, zval** newvalue);
     266                 : static void php_xmlrpc_introspection_callback(XMLRPC_SERVER server, void* data);
     267                 : int sset_zval_xmlrpc_type(zval* value, XMLRPC_VALUE_TYPE type);
     268                 : zval* decode_request_worker(char *xml_in, int xml_in_len, char *encoding_in, zval* method_name_out);
     269                 : const char* xmlrpc_type_as_str(XMLRPC_VALUE_TYPE type, XMLRPC_VECTOR_TYPE vtype);
     270                 : XMLRPC_VALUE_TYPE xmlrpc_str_as_type(const char* str);
     271                 : XMLRPC_VECTOR_TYPE xmlrpc_str_as_vector_type(const char* str);
     272                 : int set_zval_xmlrpc_type(zval* value, XMLRPC_VALUE_TYPE type);
     273                 : 
     274                 : /*********************
     275                 : * startup / shutdown *
     276                 : *********************/
     277                 : 
     278                 : static void destroy_server_data(xmlrpc_server_data *server TSRMLS_DC) /* {{{ */
     279               3 : {
     280               3 :         if (server) {
     281               3 :                 XMLRPC_ServerDestroy(server->server_ptr);
     282                 : 
     283               3 :                 zval_dtor(server->method_map);
     284               3 :                 FREE_ZVAL(server->method_map);
     285                 : 
     286               3 :                 zval_dtor(server->introspection_map);
     287               3 :                 FREE_ZVAL(server->introspection_map);
     288                 : 
     289               3 :                 efree(server);
     290                 :         }
     291               3 : }
     292                 : /* }}} */
     293                 : 
     294                 : /* called when server is being destructed. either when xmlrpc_server_destroy
     295                 :  * is called, or when request ends.  */
     296                 : static void xmlrpc_server_destructor(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
     297               3 : {
     298               3 :         if (rsrc && rsrc->ptr) {
     299               3 :                 destroy_server_data((xmlrpc_server_data*) rsrc->ptr TSRMLS_CC);
     300                 :         }
     301               3 : }
     302                 : /* }}} */
     303                 : 
     304                 : /* module init */
     305                 : PHP_MINIT_FUNCTION(xmlrpc) /* {{{ */
     306           10678 : {
     307           10678 :         le_xmlrpc_server = zend_register_list_destructors_ex(xmlrpc_server_destructor, NULL, "xmlrpc server", module_number);
     308           10678 :         return SUCCESS;
     309                 : }
     310                 : /* }}} */
     311                 : 
     312                 : /* display info in phpinfo() */
     313                 : PHP_MINFO_FUNCTION(xmlrpc) /* {{{ */
     314              30 : {
     315              30 :         php_info_print_table_start();
     316              30 :         php_info_print_table_row(2, "core library version", XMLRPC_GetVersionString());
     317              30 :         php_info_print_table_row(2, "php extension version", PHP_EXT_VERSION);
     318              30 :         php_info_print_table_row(2, "author", "Dan Libby");
     319              30 :         php_info_print_table_row(2, "homepage", "http://xmlrpc-epi.sourceforge.net");
     320              30 :         php_info_print_table_row(2, "open sourced by", "Epinions.com");
     321              30 :         php_info_print_table_end();
     322              30 : }
     323                 : /* }}} */
     324                 : 
     325                 : /*******************
     326                 :  * random utilities *
     327                 :  *******************/
     328                 : 
     329                 : /* Utility functions for adding data types to arrays, with or without key (assoc, non-assoc).
     330                 :  * Could easily be further generalized to work with objects.
     331                 :  */
     332                 : #if 0
     333                 : static int add_long(zval* list, char* id, int num) {
     334                 :         if(id) return add_assoc_long(list, id, num);
     335                 :         else   return add_next_index_long(list, num);
     336                 : }
     337                 : 
     338                 : static int add_double(zval* list, char* id, double num) {
     339                 :         if(id) return add_assoc_double(list, id, num);
     340                 :         else   return add_next_index_double(list, num);
     341                 : }
     342                 : 
     343                 : static int add_string(zval* list, char* id, char* string, int duplicate) {
     344                 :         if(id) return add_assoc_string(list, id, string, duplicate);
     345                 :         else   return add_next_index_string(list, string, duplicate);
     346                 : }
     347                 : 
     348                 : static int add_stringl(zval* list, char* id, char* string, uint length, int duplicate) {
     349                 :         if(id) return add_assoc_stringl(list, id, string, length, duplicate);
     350                 :         else   return add_next_index_stringl(list, string, length, duplicate);
     351                 : }
     352                 : 
     353                 : #endif
     354                 : 
     355                 : static int add_zval(zval* list, const char* id, zval** val) /* {{{ */
     356              13 : {
     357              13 :         if (list && val) {
     358              13 :                 if (id) {
     359               3 :                         int id_len = strlen(id);
     360               3 :                         if (!(id_len > 1 && id[0] == '0') && is_numeric_string((char *)id, id_len, NULL, NULL, 0) == IS_LONG) {
     361               2 :                                 long index = strtol(id, NULL, 0);
     362               2 :                                 return zend_hash_index_update(Z_ARRVAL_P(list), index, (void *) val, sizeof(zval **), NULL);
     363                 :                         } else {
     364               1 :                                 return zend_hash_update(Z_ARRVAL_P(list), (char*) id, strlen(id) + 1, (void *) val, sizeof(zval **), NULL);
     365                 :                         }
     366                 :                 } else {
     367              10 :                         return zend_hash_next_index_insert(Z_ARRVAL_P(list), (void *) val, sizeof(zval **), NULL); 
     368                 :                 }
     369                 :         }
     370                 :         /* what is the correct return on error? */
     371               0 :         return 0;
     372                 : }
     373                 : /* }}} */
     374                 : 
     375                 : #define my_zend_hash_get_current_key(ht, my_key, num_index) zend_hash_get_current_key(ht, my_key, num_index, 0)
     376                 : 
     377                 : 
     378                 : /*************************
     379                 :  * input / output options *
     380                 :  *************************/
     381                 : 
     382                 : /* parse an array (user input) into output options suitable for use by xmlrpc engine
     383                 :  * and determine whether to return data as xml or php vars */
     384                 : static void set_output_options(php_output_options* options, zval* output_opts) /* {{{ */
     385              14 : {
     386              14 :         if (options) {
     387                 : 
     388                 :                 /* defaults */
     389              14 :                 options->b_php_out = 0;
     390              14 :                 options->b_auto_version = 1;
     391              14 :                 options->xmlrpc_out.version = xmlrpc_version_1_0;
     392              14 :                 options->xmlrpc_out.xml_elem_opts.encoding = ENCODING_DEFAULT;
     393              14 :                 options->xmlrpc_out.xml_elem_opts.verbosity = xml_elem_pretty;
     394              14 :                 options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_markup_escaping | xml_elem_non_ascii_escaping | xml_elem_non_print_escaping;
     395                 : 
     396              14 :                 if (output_opts && Z_TYPE_P(output_opts) == IS_ARRAY) {
     397                 :                         zval** val;
     398                 : 
     399                 :                         /* type of output (xml/php) */
     400               2 :                         if (zend_hash_find(Z_ARRVAL_P(output_opts), OUTPUT_TYPE_KEY, OUTPUT_TYPE_KEY_LEN + 1, (void**) &val) == SUCCESS) {
     401               0 :                                 if (Z_TYPE_PP(val) == IS_STRING) {
     402               0 :                                         if (!strcmp(Z_STRVAL_PP(val), OUTPUT_TYPE_VALUE_PHP)) {
     403               0 :                                                 options->b_php_out = 1;
     404               0 :                                         } else if (!strcmp(Z_STRVAL_PP(val), OUTPUT_TYPE_VALUE_XML)) {
     405               0 :                                                 options->b_php_out = 0;
     406                 :                                         }
     407                 :                                 }
     408                 :                         }
     409                 : 
     410                 :                         /* verbosity of generated xml */
     411               2 :                         if (zend_hash_find(Z_ARRVAL_P(output_opts), VERBOSITY_KEY, VERBOSITY_KEY_LEN + 1, (void**) &val) == SUCCESS) {
     412               0 :                                 if (Z_TYPE_PP(val) == IS_STRING) {
     413               0 :                                         if (!strcmp(Z_STRVAL_PP(val), VERBOSITY_VALUE_NO_WHITE_SPACE)) {
     414               0 :                                                 options->xmlrpc_out.xml_elem_opts.verbosity = xml_elem_no_white_space;
     415               0 :                                         } else if (!strcmp(Z_STRVAL_PP(val), VERBOSITY_VALUE_NEWLINES_ONLY)) {
     416               0 :                                                 options->xmlrpc_out.xml_elem_opts.verbosity = xml_elem_newlines_only;
     417               0 :                                         } else if (!strcmp(Z_STRVAL_PP(val), VERBOSITY_VALUE_PRETTY)) {
     418               0 :                                                 options->xmlrpc_out.xml_elem_opts.verbosity = xml_elem_pretty;
     419                 :                                         }
     420                 :                                 }
     421                 :                         }
     422                 : 
     423                 :                         /* version of xml to output */
     424               2 :                         if (zend_hash_find(Z_ARRVAL_P(output_opts), VERSION_KEY, VERSION_KEY_LEN + 1, (void**) &val) == SUCCESS) {
     425               0 :                                 if (Z_TYPE_PP(val) == IS_STRING) {
     426               0 :                                         options->b_auto_version = 0;
     427               0 :                                         if (!strcmp(Z_STRVAL_PP(val), VERSION_VALUE_XMLRPC)) {
     428               0 :                                                 options->xmlrpc_out.version = xmlrpc_version_1_0;
     429               0 :                                         } else if (!strcmp(Z_STRVAL_PP(val), VERSION_VALUE_SIMPLE)) {
     430               0 :                                                 options->xmlrpc_out.version = xmlrpc_version_simple;
     431               0 :                                         } else if (!strcmp((*val)->value.str.val, VERSION_VALUE_SOAP11)) {
     432               0 :                                                 options->xmlrpc_out.version = xmlrpc_version_soap_1_1;
     433                 :                                         } else { /* if(!strcmp((*val)->value.str.val, VERSION_VALUE_AUTO)) */
     434               0 :                                                 options->b_auto_version = 1;
     435                 :                                         }
     436                 :                                 }
     437                 :                         }
     438                 : 
     439                 :                         /* encoding code set */
     440               2 :                         if (zend_hash_find(Z_ARRVAL_P(output_opts), ENCODING_KEY, ENCODING_KEY_LEN + 1, (void**)&val) == SUCCESS) {
     441               0 :                                 if (Z_TYPE_PP(val) == IS_STRING) {
     442               0 :                                         options->xmlrpc_out.xml_elem_opts.encoding = estrdup(Z_STRVAL_PP(val));
     443                 :                                 }
     444                 :                         }
     445                 : 
     446                 :                         /* escaping options */
     447               2 :                         if (zend_hash_find(Z_ARRVAL_P(output_opts), ESCAPING_KEY, ESCAPING_KEY_LEN + 1, (void**)&val) == SUCCESS) {
     448                 :                                 /* multiple values allowed.  check if array */
     449               0 :                                 if (Z_TYPE_PP(val) == IS_ARRAY) {
     450                 :                                         zval** iter_val;
     451               0 :                                         zend_hash_internal_pointer_reset(Z_ARRVAL_PP(val));
     452               0 :                                         options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_no_escaping;
     453                 :                                         while (1) {
     454               0 :                                                 if (zend_hash_get_current_data(Z_ARRVAL_PP(val), (void**)&iter_val) == SUCCESS) {
     455               0 :                                                         if (Z_TYPE_PP(iter_val) == IS_STRING && Z_STRVAL_PP(iter_val)) {
     456               0 :                                                                 if (!strcmp(Z_STRVAL_PP(iter_val), ESCAPING_VALUE_CDATA)) {
     457               0 :                                                                         options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_cdata_escaping;
     458               0 :                                                                 } else if (!strcmp(Z_STRVAL_PP(iter_val), ESCAPING_VALUE_NON_ASCII)) {
     459               0 :                                                                         options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_non_ascii_escaping;
     460               0 :                                                                 } else if (!strcmp(Z_STRVAL_PP(iter_val), ESCAPING_VALUE_NON_PRINT)) {
     461               0 :                                                                         options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_non_print_escaping;
     462               0 :                                                                 } else if (!strcmp(Z_STRVAL_PP(iter_val), ESCAPING_VALUE_MARKUP)) {
     463               0 :                                                                         options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_markup_escaping;
     464                 :                                                                 }
     465                 :                                                         }
     466                 :                                                 } else {
     467               0 :                                                         break;
     468                 :                                                 }
     469                 : 
     470               0 :                                                 zend_hash_move_forward(Z_ARRVAL_PP(val));
     471               0 :                                         }
     472                 :                                 }
     473                 :                                 /* else, check for single value */
     474               0 :                                 else if (Z_TYPE_PP(val) == IS_STRING) {
     475               0 :                                         if (!strcmp(Z_STRVAL_PP(val), ESCAPING_VALUE_CDATA)) {
     476               0 :                                                 options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_cdata_escaping;
     477               0 :                                         } else if (!strcmp(Z_STRVAL_PP(val), ESCAPING_VALUE_NON_ASCII)) {
     478               0 :                                                 options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_non_ascii_escaping;
     479               0 :                                         } else if (!strcmp(Z_STRVAL_PP(val), ESCAPING_VALUE_NON_PRINT)) {
     480               0 :                                                 options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_non_print_escaping;
     481               0 :                                         } else if (!strcmp(Z_STRVAL_PP(val), ESCAPING_VALUE_MARKUP)) {
     482               0 :                                                 options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_markup_escaping;
     483                 :                                         }
     484                 :                                 }
     485                 :                         }
     486                 :                 }
     487                 :         }
     488              14 : }
     489                 : /* }}} */
     490                 : 
     491                 : 
     492                 : /******************
     493                 :  * encode / decode *
     494                 :  ******************/
     495                 : 
     496                 : /* php arrays have no distinction between array and struct types.
     497                 :  * they even allow mixed.  Thus, we determine the type by iterating
     498                 :  * through the entire array and figuring out each element.
     499                 :  * room for some optimation here if we stop after a specific # of elements.
     500                 :  */
     501                 : static XMLRPC_VECTOR_TYPE determine_vector_type (HashTable *ht) /* {{{ */
     502              10 : {
     503              10 :         int bArray = 0, bStruct = 0, bMixed = 0;
     504                 :         unsigned long num_index;
     505                 :         char* my_key;
     506                 : 
     507              10 :         zend_hash_internal_pointer_reset(ht);
     508                 :         while (1) {
     509              18 :                 int res = my_zend_hash_get_current_key(ht, &my_key, &num_index);
     510              18 :                 if (res == HASH_KEY_IS_LONG) {
     511               5 :                         if (bStruct) {
     512               1 :                                 bMixed = 1;
     513               1 :                                 break;
     514                 :                         }
     515               4 :                         bArray = 1;
     516              13 :                 } else if (res == HASH_KEY_NON_EXISTANT) {
     517               9 :                         break;
     518               4 :                 } else if (res == HASH_KEY_IS_STRING || res == HASH_KEY_IS_UNICODE) {
     519               4 :                         if (bArray) {
     520               0 :                                 bMixed = 1;
     521               0 :                                 break;
     522                 :                         }
     523               4 :                         bStruct = 1;
     524                 :                 }
     525                 : 
     526               8 :                 zend_hash_move_forward(ht);
     527               8 :         }
     528              10 :         return bMixed ? xmlrpc_vector_mixed : (bStruct ? xmlrpc_vector_struct : xmlrpc_vector_array);
     529                 : }
     530                 : /* }}} */
     531                 : 
     532                 : /* recursively convert php values into xmlrpc values */
     533                 : static XMLRPC_VALUE PHP_to_XMLRPC_worker (const char* key, zval* in_val, int depth TSRMLS_DC) /* {{{ */
     534              20 : {
     535              20 :         XMLRPC_VALUE xReturn = NULL;
     536              20 :         if (in_val) {
     537              20 :                 zval* val = NULL;
     538              20 :                 XMLRPC_VALUE_TYPE type = get_zval_xmlrpc_type(in_val, &val);
     539              20 :                 if (val) {
     540              20 :                         switch (type) {
     541                 :                                 case xmlrpc_base64:
     542               0 :                                         if (Z_TYPE_P(val) == IS_NULL) {
     543               0 :                                                 xReturn = XMLRPC_CreateValueEmpty();
     544               0 :                                                 XMLRPC_SetValueID(xReturn, key, 0);
     545                 :                                         } else {
     546               0 :                                                 xReturn = XMLRPC_CreateValueBase64(key, Z_STRVAL_P(val), Z_STRLEN_P(val));
     547                 :                                         }
     548               0 :                                         break;
     549                 :                                 case xmlrpc_datetime:
     550               1 :                                         convert_to_string(val);
     551               1 :                                         xReturn = XMLRPC_CreateValueDateTime_ISO8601(key, Z_STRVAL_P(val));
     552               1 :                                         break;
     553                 :                                 case xmlrpc_boolean:
     554               0 :                                         convert_to_boolean(val);
     555               0 :                                         xReturn = XMLRPC_CreateValueBoolean(key, Z_LVAL_P(val));
     556               0 :                                         break;
     557                 :                                 case xmlrpc_int:
     558               7 :                                         convert_to_long(val);
     559               7 :                                         xReturn = XMLRPC_CreateValueInt(key, Z_LVAL_P(val));
     560               7 :                                         break;
     561                 :                                 case xmlrpc_double:
     562               2 :                                         convert_to_double(val);
     563               2 :                                         xReturn = XMLRPC_CreateValueDouble(key, Z_DVAL_P(val));
     564               2 :                                         break;
     565                 :                                 case xmlrpc_string:
     566               5 :                                         convert_to_string(val);
     567               5 :                                         xReturn = XMLRPC_CreateValueString(key, Z_STRVAL_P(val), Z_STRLEN_P(val));
     568               5 :                                         break;
     569                 :                                 case xmlrpc_vector:
     570                 :                                         {
     571                 :                                                 unsigned long num_index;
     572                 :                                                 zval** pIter;
     573                 :                                                 char* my_key;
     574               5 :                                                 HashTable *ht = NULL;
     575                 : 
     576               5 :                                                 ht = HASH_OF(val);
     577               5 :                                                 if (ht && ht->nApplyCount > 1) {
     578               0 :                                                         php_error_docref(NULL TSRMLS_CC, E_ERROR, "XML-RPC doesn't support circular references");
     579               0 :                                                         return NULL;
     580                 :                                                 }
     581                 : 
     582               5 :                                                 convert_to_array(val);
     583               5 :                                                 xReturn = XMLRPC_CreateVector(key, determine_vector_type(Z_ARRVAL_P(val)));
     584                 : 
     585               5 :                                                 zend_hash_internal_pointer_reset(Z_ARRVAL_P(val));
     586              12 :                                                 while (zend_hash_get_current_data(Z_ARRVAL_P(val), (void**)&pIter) == SUCCESS) {
     587               2 :                                                         int res = my_zend_hash_get_current_key(Z_ARRVAL_P(val), &my_key, &num_index);
     588                 : 
     589               2 :                                                         switch (res) {
     590                 :                                                                 case HASH_KEY_NON_EXISTANT:
     591               0 :                                                                         break;
     592                 :                                                                 default:
     593               2 :                                                                         ht = HASH_OF(*pIter);
     594               2 :                                                                         if (ht) {
     595               2 :                                                                                 ht->nApplyCount++;
     596                 :                                                                         }
     597               2 :                                                                         if (res == HASH_KEY_IS_LONG) {
     598               1 :                                                                                 XMLRPC_AddValueToVector(xReturn, PHP_to_XMLRPC_worker(0, *pIter, depth++ TSRMLS_CC));
     599                 :                                                                         } else {
     600               1 :                                                                                 XMLRPC_AddValueToVector(xReturn, PHP_to_XMLRPC_worker(my_key, *pIter, depth++ TSRMLS_CC));
     601                 :                                                                         }
     602               2 :                                                                         if (ht) {
     603               2 :                                                                                 ht->nApplyCount--;
     604                 :                                                                         }
     605                 :                                                                         break;
     606                 :                                                         }
     607               2 :                                                         zend_hash_move_forward(Z_ARRVAL_P(val));
     608                 :                                                 }
     609                 :                                         }
     610                 :                                         break;
     611                 :                                 default:
     612                 :                                         break;
     613                 :                         }
     614                 :                 }
     615                 :         }
     616              20 :         return xReturn;
     617                 : }
     618                 : /* }}} */
     619                 : 
     620                 : static XMLRPC_VALUE PHP_to_XMLRPC(zval* root_val TSRMLS_DC) /* {{{ */
     621              18 : {
     622              18 :         return PHP_to_XMLRPC_worker(NULL, root_val, 0 TSRMLS_CC);
     623                 : }
     624                 : /* }}} */
     625                 : 
     626                 : /* recursively convert xmlrpc values into php values */
     627                 : static zval* XMLRPC_to_PHP(XMLRPC_VALUE el) /* {{{ */
     628              15 : {
     629              15 :         zval* elem = NULL;
     630                 :         const char* pStr;
     631                 : 
     632              15 :         if (el) {
     633              15 :                 XMLRPC_VALUE_TYPE type = XMLRPC_GetValueType(el);
     634                 : 
     635              15 :                 MAKE_STD_ZVAL(elem); /* init. very important.  spent a frustrating day finding this out. */
     636                 : 
     637              15 :                 switch(type) {
     638                 :                         case xmlrpc_empty:
     639               0 :                                 Z_TYPE_P(elem) = IS_NULL;
     640               0 :                                 break;
     641                 :                         case xmlrpc_string:
     642               4 :                                 pStr = XMLRPC_GetValueString(el);
     643               4 :                                 if (pStr) {
     644               4 :                                         Z_STRLEN_P(elem) = XMLRPC_GetValueStringLen(el);
     645               4 :                                         Z_STRVAL_P(elem) = estrndup(pStr, Z_STRLEN_P(elem));
     646               4 :                                         Z_TYPE_P(elem) = IS_STRING;
     647                 :                                 }
     648               4 :                                 break;
     649                 :                         case xmlrpc_int:
     650               2 :                                 Z_LVAL_P(elem) = XMLRPC_GetValueInt(el);
     651               2 :                                 Z_TYPE_P(elem) = IS_LONG;
     652               2 :                                 break;
     653                 :                         case xmlrpc_boolean:
     654               0 :                                 Z_LVAL_P(elem) = XMLRPC_GetValueBoolean(el);
     655               0 :                                 Z_TYPE_P(elem) = IS_BOOL;
     656               0 :                                 break;
     657                 :                         case xmlrpc_double:
     658               0 :                                 Z_DVAL_P(elem) = XMLRPC_GetValueDouble(el);
     659               0 :                                 Z_TYPE_P(elem) = IS_DOUBLE;
     660               0 :                                 break;
     661                 :                         case xmlrpc_datetime:
     662               1 :                                 Z_STRLEN_P(elem) = XMLRPC_GetValueStringLen(el);
     663               1 :                                 Z_STRVAL_P(elem) = estrndup(XMLRPC_GetValueDateTime_ISO8601(el), Z_STRLEN_P(elem));
     664               1 :                                 Z_TYPE_P(elem) = IS_STRING;
     665               1 :                                 break;
     666                 :                         case xmlrpc_base64:
     667               0 :                                 pStr = XMLRPC_GetValueBase64(el);
     668               0 :                                 if (pStr) {
     669               0 :                                         Z_STRLEN_P(elem) = XMLRPC_GetValueStringLen(el);
     670               0 :                                         Z_STRVAL_P(elem) = estrndup(pStr, Z_STRLEN_P(elem));
     671               0 :                                         Z_TYPE_P(elem) = IS_STRING;
     672                 :                                 }
     673               0 :                                 break;
     674                 :                         case xmlrpc_vector:
     675               8 :                                 array_init(elem);
     676                 :                                 {
     677               8 :                                         XMLRPC_VALUE xIter = XMLRPC_VectorRewind(el);
     678                 : 
     679              23 :                                         while (xIter) {
     680               7 :                                                 zval *val = XMLRPC_to_PHP(xIter);
     681               7 :                                                 if (val) {
     682               7 :                                                         add_zval(elem, XMLRPC_GetValueID(xIter), &val);
     683                 :                                                 }
     684               7 :                                                 xIter = XMLRPC_VectorNext(el);
     685                 :                                         }
     686                 :                                 }
     687                 :                                 break;
     688                 :                         default:
     689                 :                                 break;
     690                 :                 }
     691              15 :                 set_zval_xmlrpc_type(elem, type);
     692                 :         }
     693              15 :         return elem;
     694                 : }
     695                 : /* }}} */
     696                 : 
     697                 : /* {{{ proto string xmlrpc_encode_request(string method, mixed params)
     698                 :    Generates XML for a method request */
     699                 : PHP_FUNCTION(xmlrpc_encode_request)
     700              11 : {
     701              11 :         XMLRPC_REQUEST xRequest = NULL;
     702                 :         char *outBuf;
     703                 :         zval **method, **vals, *out_opts;
     704                 :         php_output_options out;
     705                 : 
     706              11 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|a", &method, &vals, &out_opts) == FAILURE) {
     707               0 :                 return;
     708                 :         }
     709                 : 
     710              11 :         set_output_options(&out, (ZEND_NUM_ARGS() == 3) ? out_opts : 0);
     711                 : 
     712              11 :         if (return_value_used) {
     713              11 :                 xRequest = XMLRPC_RequestNew();
     714                 : 
     715              11 :                 if (xRequest) {
     716              11 :                         XMLRPC_RequestSetOutputOptions(xRequest, &out.xmlrpc_out);
     717              11 :                         if (Z_TYPE_PP(method) == IS_NULL) {
     718               0 :                                 XMLRPC_RequestSetRequestType(xRequest, xmlrpc_request_response);
     719                 :                         } else {
     720              11 :                                 convert_to_string_ex(method);
     721              11 :                                 XMLRPC_RequestSetMethodName(xRequest, Z_STRVAL_PP(method));
     722              11 :                                 XMLRPC_RequestSetRequestType(xRequest, xmlrpc_request_call);
     723                 :                         }
     724              11 :                         if (Z_TYPE_PP(vals) != IS_NULL) {
     725              11 :                                 XMLRPC_RequestSetData(xRequest, PHP_to_XMLRPC(*vals TSRMLS_CC));
     726                 :                         }
     727                 : 
     728              11 :                         outBuf = XMLRPC_REQUEST_ToXML(xRequest, 0);
     729              11 :                         if (outBuf) {
     730              11 :                                 RETVAL_STRING(outBuf, 1);
     731              11 :                                 free(outBuf);
     732                 :                         }
     733              11 :                         XMLRPC_RequestFree(xRequest, 1);
     734                 :                 }
     735                 :         }
     736                 : 
     737              11 :         if (out.xmlrpc_out.xml_elem_opts.encoding != ENCODING_DEFAULT) {
     738               0 :                 efree((char *)out.xmlrpc_out.xml_elem_opts.encoding);
     739                 :         }
     740                 : }
     741                 : /* }}} */
     742                 : 
     743                 : /* {{{ proto string xmlrpc_encode(mixed value)
     744                 :    Generates XML for a PHP value */
     745                 : PHP_FUNCTION(xmlrpc_encode)
     746               6 : {
     747               6 :         XMLRPC_VALUE xOut = NULL;
     748                 :         zval **arg1;
     749                 :         char *outBuf;
     750                 : 
     751               6 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg1) == FAILURE) {
     752               0 :                 return;
     753                 :         }
     754                 : 
     755               6 :         if (return_value_used) {
     756                 :                 /* convert native php type to xmlrpc type */
     757               6 :                 xOut = PHP_to_XMLRPC(*arg1 TSRMLS_CC);
     758                 : 
     759                 :                 /* generate raw xml from xmlrpc data */
     760               6 :                 outBuf = XMLRPC_VALUE_ToXML(xOut, 0);
     761                 : 
     762               6 :                 if (xOut) {
     763               6 :                         if (outBuf) {
     764               6 :                                 RETVAL_STRING(outBuf, 1);
     765               6 :                                 free(outBuf);
     766                 :                         }
     767                 :                         /* cleanup */
     768               6 :                         XMLRPC_CleanupValue(xOut);
     769                 :                 }
     770                 :         }
     771                 : }
     772                 : /* }}} */
     773                 : 
     774                 : zval* decode_request_worker(char *xml_in, int xml_in_len, char *encoding_in, zval* method_name_out) /* {{{ */
     775               7 : {
     776               7 :         zval* retval = NULL;
     777                 :         XMLRPC_REQUEST response;
     778               7 :         STRUCT_XMLRPC_REQUEST_INPUT_OPTIONS opts = {{0}};
     779               7 :         opts.xml_elem_opts.encoding = encoding_in ? utf8_get_encoding_id_from_string(encoding_in) : ENCODING_DEFAULT;
     780                 : 
     781                 :         /* generate XMLRPC_REQUEST from raw xml */
     782               7 :         response = XMLRPC_REQUEST_FromXML(xml_in, xml_in_len, &opts);
     783               7 :         if (response) {
     784                 :                 /* convert xmlrpc data to native php types */
     785               7 :                 retval = XMLRPC_to_PHP(XMLRPC_RequestGetData(response));
     786                 : 
     787               7 :                 if (XMLRPC_RequestGetRequestType(response) == xmlrpc_request_call) {
     788               5 :                         if (method_name_out) {
     789               5 :                                 zval_dtor(method_name_out);
     790               5 :                                 Z_TYPE_P(method_name_out) = IS_STRING;
     791               5 :                                 Z_STRVAL_P(method_name_out) = estrdup(XMLRPC_RequestGetMethodName(response));
     792               5 :                                 Z_STRLEN_P(method_name_out) = strlen(Z_STRVAL_P(method_name_out));
     793                 :                         }
     794                 :                 }
     795                 : 
     796                 :                 /* dust, sweep, and mop */
     797               7 :                 XMLRPC_RequestFree(response, 1);
     798                 :         }
     799               7 :         return retval;
     800                 : }
     801                 : /* }}} */
     802                 : 
     803                 : /* {{{ proto array xmlrpc_decode_request(string xml, string& method [, string encoding])
     804                 :    Decodes XML into native PHP types */
     805                 : PHP_FUNCTION(xmlrpc_decode_request)
     806               5 : {
     807               5 :         char *xml, *encoding = NULL;
     808                 :         zval **method;
     809               5 :         int xml_len, encoding_len = 0;
     810                 : 
     811               5 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sZ|s", &xml, &xml_len, &method, &encoding, &encoding_len) == FAILURE) {
     812               0 :                 return;
     813                 :         }
     814                 : 
     815               5 :         convert_to_string_ex(method);
     816                 : 
     817               5 :         if (return_value_used) {
     818               5 :                 zval* retval = decode_request_worker(xml, xml_len, encoding_len ? encoding : NULL, *method);
     819               5 :                 if (retval) {
     820               5 :                         *return_value = *retval;
     821               5 :                         FREE_ZVAL(retval);
     822                 :                 }
     823                 :         }
     824                 : }
     825                 : /* }}} */
     826                 : 
     827                 : /* {{{ proto array xmlrpc_decode(string xml [, string encoding])
     828                 :    Decodes XML into native PHP types */
     829                 : PHP_FUNCTION(xmlrpc_decode)
     830               2 : {
     831               2 :         char *arg1, *arg2 = NULL;
     832               2 :         int arg1_len, arg2_len = 0;
     833                 : 
     834               2 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &arg1, &arg1_len, &arg2, &arg2_len) == FAILURE) {
     835               0 :                 return;
     836                 :         }
     837                 : 
     838               2 :         if (return_value_used) {
     839               2 :                 zval* retval = decode_request_worker(arg1, arg1_len, arg2_len ? arg2 : NULL, NULL);
     840               2 :                 if (retval) {
     841               2 :                         *return_value = *retval;
     842               2 :                         FREE_ZVAL(retval);
     843                 :                 }
     844                 :         }
     845                 : }
     846                 : /* }}} */
     847                 : 
     848                 : /*************************
     849                 : * server related methods *
     850                 : *************************/
     851                 : 
     852                 : /* {{{ proto resource xmlrpc_server_create(void)
     853                 :    Creates an xmlrpc server */
     854                 : PHP_FUNCTION(xmlrpc_server_create)
     855               3 : {
     856               3 :         if (zend_parse_parameters_none() == FAILURE) {
     857               0 :                 return;
     858                 :         }
     859                 : 
     860               3 :         if (return_value_used) {
     861                 :                 zval *method_map, *introspection_map;
     862               3 :                 xmlrpc_server_data *server = emalloc(sizeof(xmlrpc_server_data));
     863               3 :                 MAKE_STD_ZVAL(method_map);
     864               3 :                 MAKE_STD_ZVAL(introspection_map);
     865                 : 
     866               3 :                 array_init(method_map);
     867               3 :                 array_init(introspection_map);
     868                 : 
     869                 :                 /* allocate server data.  free'd in destroy_server_data() */
     870               3 :                 server->method_map = method_map;
     871               3 :                 server->introspection_map = introspection_map;
     872               3 :                 server->server_ptr = XMLRPC_ServerCreate();
     873                 : 
     874               3 :                 XMLRPC_ServerRegisterIntrospectionCallback(server->server_ptr, php_xmlrpc_introspection_callback);
     875                 : 
     876                 :                 /* store for later use */
     877               3 :                 ZEND_REGISTER_RESOURCE(return_value,server, le_xmlrpc_server);
     878                 :         }
     879                 : }
     880                 : /* }}} */
     881                 : 
     882                 : /* {{{ proto int xmlrpc_server_destroy(resource server)
     883                 :    Destroys server resources */
     884                 : PHP_FUNCTION(xmlrpc_server_destroy)
     885               0 : {
     886                 :         zval *arg1;
     887               0 :         int bSuccess = FAILURE, type;
     888                 :         xmlrpc_server_data *server;
     889                 : 
     890               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) {
     891               0 :                 return;
     892                 :         }
     893                 : 
     894               0 :         server = zend_list_find(Z_LVAL_P(arg1), &type);
     895                 : 
     896               0 :         if (server && type == le_xmlrpc_server) {
     897               0 :                 bSuccess = zend_list_delete(Z_LVAL_P(arg1));
     898                 : 
     899                 :                 /* called by hashtable destructor
     900                 :                  * destroy_server_data(server);
     901                 :                  */
     902                 :         }
     903               0 :         RETVAL_LONG(bSuccess == SUCCESS);
     904                 : }
     905                 : /* }}} */
     906                 : 
     907                 : /* called by xmlrpc C engine as method handler for all registered methods.
     908                 :  * it then calls the corresponding PHP function to handle the method.
     909                 :  */
     910                 : static XMLRPC_VALUE php_xmlrpc_callback(XMLRPC_SERVER server, XMLRPC_REQUEST xRequest, void* data) /* {{{ */
     911               1 : {
     912               1 :         xmlrpc_callback_data* pData = (xmlrpc_callback_data*)data;
     913                 :         zval* xmlrpc_params;
     914                 :         zval* callback_params[3];
     915                 :         TSRMLS_FETCH();
     916                 : 
     917                 :         /* convert xmlrpc to native php types */
     918               1 :         xmlrpc_params = XMLRPC_to_PHP(XMLRPC_RequestGetData(xRequest));
     919                 : 
     920                 :         /* setup data hoojum */
     921               1 :         callback_params[0] = pData->xmlrpc_method;
     922               1 :         callback_params[1] = xmlrpc_params;
     923               1 :         callback_params[2] = pData->caller_params;
     924                 : 
     925                 :         /* Use same C function for all methods */
     926                 : 
     927                 :         /* php func prototype: function user_func($method_name, $xmlrpc_params, $user_params) */
     928               1 :         call_user_function(CG(function_table), NULL, pData->php_function, pData->return_data, 3, callback_params TSRMLS_CC);
     929                 : 
     930               1 :         pData->php_executed = 1;
     931                 : 
     932               1 :         zval_ptr_dtor(&xmlrpc_params);
     933                 : 
     934               1 :         return NULL;
     935                 : }
     936                 : /* }}} */
     937                 : 
     938                 : /* called by the C server when it first receives an introspection request.  We pass this on to
     939                 :  * our PHP listeners, if any
     940                 :  */
     941                 : static void php_xmlrpc_introspection_callback(XMLRPC_SERVER server, void* data) /* {{{ */
     942               2 : {
     943                 :         zval retval, **php_function;
     944                 :         zval *callback_params[1];
     945                 :         zval php_function_name;
     946               2 :         xmlrpc_callback_data* pData = (xmlrpc_callback_data*)data;
     947                 :         TSRMLS_FETCH();
     948                 : 
     949                 :         /* setup data hoojum */
     950               2 :         callback_params[0] = pData->caller_params;
     951                 : 
     952                 :         /* loop through and call all registered callbacks */
     953               2 :         zend_hash_internal_pointer_reset(Z_ARRVAL_P(pData->server->introspection_map));
     954                 :         while (1) {
     955               7 :                 if (zend_hash_get_current_data(Z_ARRVAL_P(pData->server->introspection_map), (void**)&php_function) == SUCCESS) {
     956               5 :                         if (zend_is_callable(*php_function, 0, &php_function_name TSRMLS_CC)) {
     957                 :                                 /* php func prototype: function string user_func($user_params) */
     958               1 :                                 if (call_user_function(CG(function_table), NULL, *php_function, &retval, 1, callback_params TSRMLS_CC) == SUCCESS) {
     959                 :                                         XMLRPC_VALUE xData;
     960               1 :                                         STRUCT_XMLRPC_ERROR err = {0};
     961                 : 
     962                 :                                         /* return value should be a string */
     963               1 :                                         convert_to_string(&retval);
     964                 : 
     965               1 :                                         xData = XMLRPC_IntrospectionCreateDescription(Z_STRVAL(retval), &err);
     966                 : 
     967               1 :                                         if (xData) {
     968               0 :                                                 if (!XMLRPC_ServerAddIntrospectionData(server, xData)) {
     969               0 :                                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to add introspection data returned from %v(), improper element structure", Z_UNIVAL(php_function_name));
     970                 :                                                 }
     971               0 :                                                 XMLRPC_CleanupValue(xData);
     972                 :                                         } else {
     973                 :                                                 /* could not create description */
     974               1 :                                                 if (err.xml_elem_error.parser_code) {
     975               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 %v()", 
     976                 :                                                                 err.xml_elem_error.column, err.xml_elem_error.line, err.xml_elem_error.parser_error, Z_UNIVAL(php_function_name));
     977                 :                                                 } else {
     978               0 :                                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to add introspection data returned from %v()", Z_UNIVAL(php_function_name));
     979                 :                                                 }
     980                 :                                         }
     981               1 :                                         zval_dtor(&retval);
     982                 :                                 } else {
     983                 :                                         /* user func failed */
     984               0 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error calling user introspection callback: %v()", Z_UNIVAL(php_function_name));
     985                 :                                 }
     986                 :                         } else {
     987               4 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid callback '%v' passed", Z_UNIVAL(php_function_name));
     988                 :                         }
     989               5 :                         zval_dtor(&php_function_name);
     990                 :                 } else {
     991               2 :                         break;
     992                 :                 }
     993               5 :                 zend_hash_move_forward(Z_ARRVAL_P(pData->server->introspection_map));
     994               5 :         }
     995                 : 
     996                 :         /* so we don't call the same callbacks ever again */
     997               2 :         zend_hash_clean(Z_ARRVAL_P(pData->server->introspection_map));
     998               2 : }
     999                 : /* }}} */
    1000                 : 
    1001                 : /* {{{ proto bool xmlrpc_server_register_method(resource server, string method_name, string function)
    1002                 :    Register a PHP function to handle method matching method_name */
    1003                 : PHP_FUNCTION(xmlrpc_server_register_method)
    1004               1 : {
    1005                 :         char *method_key;
    1006                 :         int method_key_len;
    1007                 :         zval *handle, *method_name_save, **method_name;
    1008                 :         int type;
    1009                 :         xmlrpc_server_data* server;
    1010                 : 
    1011               1 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsZ", &handle, &method_key, &method_key_len, &method_name) == FAILURE) {
    1012               0 :                 return;
    1013                 :         }
    1014                 : 
    1015               1 :         server = zend_list_find(Z_LVAL_P(handle), &type);
    1016                 : 
    1017               1 :         if (type == le_xmlrpc_server) {
    1018                 :                 /* register with C engine. every method just calls our standard callback, 
    1019                 :                  * and it then dispatches to php as necessary
    1020                 :                  */
    1021               1 :                 if (XMLRPC_ServerRegisterMethod(server->server_ptr, method_key, php_xmlrpc_callback)) {
    1022                 :                         /* save for later use */
    1023               1 :                         MAKE_STD_ZVAL(method_name_save);
    1024               1 :                         *method_name_save = **method_name;
    1025               1 :                         zval_copy_ctor(method_name_save);
    1026                 : 
    1027                 :                         /* register our php method */
    1028               1 :                         add_zval(server->method_map, method_key, &method_name_save);
    1029                 : 
    1030               1 :                         RETURN_BOOL(1);
    1031                 :                 }
    1032                 :         }
    1033               0 :         RETURN_BOOL(0);
    1034                 : }
    1035                 : /* }}} */
    1036                 : 
    1037                 : /* {{{ proto bool xmlrpc_server_register_introspection_callback(resource server, string function)
    1038                 :    Register a PHP function to generate documentation */
    1039                 : PHP_FUNCTION(xmlrpc_server_register_introspection_callback)
    1040               5 : {
    1041                 :         zval **method_name, *handle, *method_name_save;
    1042                 :         int type;
    1043                 :         xmlrpc_server_data* server;
    1044                 : 
    1045               5 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZ", &handle, &method_name) == FAILURE) {
    1046               0 :                 return;
    1047                 :         }
    1048                 : 
    1049               5 :         server = zend_list_find(Z_LVAL_P(handle), &type);
    1050                 : 
    1051               5 :         if (type == le_xmlrpc_server) {
    1052                 :                 /* save for later use */
    1053               5 :                 MAKE_STD_ZVAL(method_name_save);
    1054               5 :                 *method_name_save = **method_name;
    1055               5 :                 zval_copy_ctor(method_name_save);
    1056                 : 
    1057                 :                 /* register our php method */
    1058               5 :                 add_zval(server->introspection_map, NULL, &method_name_save);
    1059                 : 
    1060               5 :                 RETURN_BOOL(1);
    1061                 :         }
    1062               0 :         RETURN_BOOL(0);
    1063                 : }
    1064                 : /* }}} */
    1065                 : 
    1066                 : /* this function is itchin for a re-write */
    1067                 : 
    1068                 : /* {{{ proto mixed xmlrpc_server_call_method(resource server, string xml, mixed user_data [, array output_options])
    1069                 :    Parses XML requests and call methods */
    1070                 : PHP_FUNCTION(xmlrpc_server_call_method)
    1071               3 : {
    1072               3 :         xmlrpc_callback_data data = {0};
    1073                 :         XMLRPC_REQUEST xRequest;
    1074                 :         STRUCT_XMLRPC_REQUEST_INPUT_OPTIONS input_opts;
    1075                 :         xmlrpc_server_data* server;
    1076               3 :         zval **caller_params, *handle, **output_opts = NULL;
    1077                 :         char *rawxml;
    1078                 :         int rawxml_len, type;
    1079                 :         php_output_options out;
    1080               3 :         int argc =ZEND_NUM_ARGS();
    1081                 : 
    1082               3 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsZ|Z", &handle, &rawxml, &rawxml_len, &caller_params, &output_opts) != SUCCESS) {
    1083               0 :                 return;
    1084                 :         }
    1085                 :         /* user output options */
    1086               3 :         if (argc == 3) {
    1087               1 :                 set_output_options(&out, NULL);
    1088                 :         } else {
    1089               2 :                 set_output_options(&out, *output_opts);
    1090                 :         }
    1091                 : 
    1092               3 :         server = zend_list_find(Z_LVAL_P(handle), &type);
    1093                 : 
    1094               3 :         if (type == le_xmlrpc_server) {
    1095                 :                 /* HACK: use output encoding for now */
    1096               3 :                 input_opts.xml_elem_opts.encoding = utf8_get_encoding_id_from_string(out.xmlrpc_out.xml_elem_opts.encoding);
    1097                 : 
    1098                 :                 /* generate an XMLRPC_REQUEST from the raw xml input */
    1099               3 :                 xRequest = XMLRPC_REQUEST_FromXML(rawxml, rawxml_len, &input_opts);
    1100                 : 
    1101               3 :                 if (xRequest) {
    1102               3 :                         const char* methodname = XMLRPC_RequestGetMethodName(xRequest);
    1103                 :                         zval **php_function;
    1104               3 :                         XMLRPC_VALUE xAnswer = NULL;
    1105               3 :                         MAKE_STD_ZVAL(data.xmlrpc_method); /* init. very important.  spent a frustrating day finding this out. */
    1106               3 :                         MAKE_STD_ZVAL(data.return_data);
    1107               3 :                         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 */
    1108               3 :                         Z_TYPE_P(data.xmlrpc_method) = IS_NULL;
    1109                 : 
    1110               3 :                         if (!methodname) {
    1111               0 :                                 methodname = "";
    1112                 :                         }
    1113                 : 
    1114                 :                         /* setup some data to pass to the callback function */
    1115               3 :                         Z_STRVAL_P(data.xmlrpc_method) = estrdup(methodname);
    1116               3 :                         Z_STRLEN_P(data.xmlrpc_method) = strlen(methodname);
    1117               3 :                         Z_TYPE_P(data.xmlrpc_method) = IS_STRING;
    1118               3 :                         data.caller_params = *caller_params;