Annotation of embedaddon/php/ext/xmlrpc/xmlrpc-epi-php.c, revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>