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

Generated by: LTP GCOV extension version 1.5

Generated at Thu, 22 Oct 2009 13:56:11 +0000 (16 days ago)

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