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

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:    +----------------------------------------------------------------------+
1.1.1.3 ! misho      40:    | Copyright (c) 1997-2013 The PHP Group                                |
1.1       misho      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: 
1.1.1.2   misho      54: /* $Id$ */
1.1       misho      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 */
1.1.1.2   misho    1046:                        ALLOC_ZVAL(method_name_save);
                   1047:                        MAKE_COPY_ZVAL(method_name, method_name_save);
1.1       misho    1048: 
                   1049:                        /* register our php method */
                   1050:                        add_zval(server->method_map, method_key, &method_name_save);
                   1051: 
                   1052:                        RETURN_BOOL(1);
                   1053:                }
                   1054:        }
                   1055:        RETURN_BOOL(0);
                   1056: }
                   1057: /* }}} */
                   1058: 
                   1059: /* {{{ proto bool xmlrpc_server_register_introspection_callback(resource server, string function)
                   1060:    Register a PHP function to generate documentation */
                   1061: PHP_FUNCTION(xmlrpc_server_register_introspection_callback)
                   1062: {
                   1063:        zval **method_name, *handle, *method_name_save;
                   1064:        int type;
                   1065:        xmlrpc_server_data* server;
                   1066: 
                   1067:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZ", &handle, &method_name) == FAILURE) {
                   1068:                return;
                   1069:        }
                   1070: 
                   1071:        server = zend_list_find(Z_LVAL_P(handle), &type);
                   1072: 
                   1073:        if (type == le_xmlrpc_server) {
                   1074:                /* save for later use */
1.1.1.2   misho    1075:                ALLOC_ZVAL(method_name_save);
                   1076:                MAKE_COPY_ZVAL(method_name, method_name_save);
1.1       misho    1077: 
                   1078:                /* register our php method */
                   1079:                add_zval(server->introspection_map, NULL, &method_name_save);
                   1080: 
                   1081:                RETURN_BOOL(1);
                   1082:        }
                   1083:        RETURN_BOOL(0);
                   1084: }
                   1085: /* }}} */
                   1086: 
                   1087: /* this function is itchin for a re-write */
                   1088: 
                   1089: /* {{{ proto mixed xmlrpc_server_call_method(resource server, string xml, mixed user_data [, array output_options])
                   1090:    Parses XML requests and call methods */
                   1091: PHP_FUNCTION(xmlrpc_server_call_method)
                   1092: {
                   1093:        xmlrpc_callback_data data = {0};
                   1094:        XMLRPC_REQUEST xRequest;
                   1095:        STRUCT_XMLRPC_REQUEST_INPUT_OPTIONS input_opts;
                   1096:        xmlrpc_server_data* server;
                   1097:        zval **caller_params, *handle, *output_opts = NULL;
                   1098:        char *rawxml;
                   1099:        int rawxml_len, type;
                   1100:        php_output_options out;
                   1101:        int argc =ZEND_NUM_ARGS();
                   1102:        
                   1103:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsZ|a", &handle, &rawxml, &rawxml_len, &caller_params, &output_opts) != SUCCESS) {
                   1104:                return;
                   1105:        }
                   1106:        /* user output options */
                   1107:        if (argc == 3) {
                   1108:                set_output_options(&out, NULL);
                   1109:        } else {
                   1110:                set_output_options(&out, output_opts);
                   1111:        }
                   1112: 
                   1113:        server = zend_list_find(Z_LVAL_P(handle), &type);
                   1114: 
                   1115:        if (type == le_xmlrpc_server) {
                   1116:                /* HACK: use output encoding for now */
                   1117:                input_opts.xml_elem_opts.encoding = utf8_get_encoding_id_from_string(out.xmlrpc_out.xml_elem_opts.encoding);
                   1118: 
                   1119:                /* generate an XMLRPC_REQUEST from the raw xml input */
                   1120:                xRequest = XMLRPC_REQUEST_FromXML(rawxml, rawxml_len, &input_opts);
                   1121: 
                   1122:                if (xRequest) {
                   1123:                        const char* methodname = XMLRPC_RequestGetMethodName(xRequest);
                   1124:                        XMLRPC_VALUE xAnswer = NULL;
                   1125:                        MAKE_STD_ZVAL(data.xmlrpc_method); /* init. very important.  spent a frustrating day finding this out. */
                   1126:                        MAKE_STD_ZVAL(data.return_data);
                   1127:                        Z_TYPE_P(data.return_data) = IS_NULL;  /* in case value is never init'd, we don't dtor to think it is a string or something */
                   1128:                        Z_TYPE_P(data.xmlrpc_method) = IS_NULL;
                   1129: 
                   1130:                        /* setup some data to pass to the callback function */
                   1131:                        data.caller_params = *caller_params;
                   1132:                        data.php_executed = 0;
                   1133:                        data.server = server;
                   1134: 
                   1135:                        /* We could just call the php method directly ourselves at this point, but we do this 
                   1136:                         * with a C callback in case the xmlrpc library ever implements some cool usage stats,
                   1137:                         * or somesuch.
                   1138:                         */
                   1139:                        xAnswer = XMLRPC_ServerCallMethod(server->server_ptr, xRequest, &data);
                   1140:                        if (xAnswer && out.b_php_out) {
                   1141:                                zval_dtor(data.return_data);
                   1142:                                FREE_ZVAL(data.return_data);
                   1143:                                data.return_data = XMLRPC_to_PHP(xAnswer);
                   1144:                        } else if (data.php_executed && !out.b_php_out && !xAnswer) {
                   1145:                                xAnswer = PHP_to_XMLRPC(data.return_data TSRMLS_CC);
                   1146:                        }
                   1147: 
                   1148:                        /* should we return data as xml? */
                   1149:                        if (!out.b_php_out) {
                   1150:                                XMLRPC_REQUEST xResponse = XMLRPC_RequestNew();
                   1151:                                if (xResponse) {
                   1152:                                        char *outBuf = 0;
                   1153:                                        int buf_len = 0;
                   1154: 
                   1155:                                        /* automagically determine output serialization type from request type */
                   1156:                                        if (out.b_auto_version) { 
                   1157:                                                XMLRPC_REQUEST_OUTPUT_OPTIONS opts = XMLRPC_RequestGetOutputOptions(xRequest);
                   1158:                                                if (opts) {
                   1159:                                                        out.xmlrpc_out.version = opts->version;
                   1160:                                                }
                   1161:                                        }
                   1162:                                        /* set some required request hoojum */
                   1163:                                        XMLRPC_RequestSetOutputOptions(xResponse, &out.xmlrpc_out);
                   1164:                                        XMLRPC_RequestSetRequestType(xResponse, xmlrpc_request_response);
                   1165:                                        XMLRPC_RequestSetData(xResponse, xAnswer);
                   1166:                                        XMLRPC_RequestSetMethodName(xResponse, methodname);
                   1167: 
                   1168:                                        /* generate xml */
                   1169:                                        outBuf = XMLRPC_REQUEST_ToXML(xResponse, &buf_len);
                   1170:                                        if (outBuf) {
                   1171:                                                RETVAL_STRINGL(outBuf, buf_len, 1);
                   1172:                                                free(outBuf);
                   1173:                                        }
                   1174:                                        /* cleanup after ourselves.  what a sty! */
                   1175:                                        XMLRPC_RequestFree(xResponse, 0);
                   1176:                                }
                   1177:                        } else { /* or as native php types? */
                   1178:                                *return_value = *data.return_data;
                   1179:                                zval_copy_ctor(return_value);
                   1180:                        }
                   1181: 
                   1182:                        /* cleanup after ourselves.  what a sty! */
                   1183:                        zval_ptr_dtor(&data.xmlrpc_method);
                   1184: 
                   1185:                        zval_dtor(data.return_data);
                   1186:                        FREE_ZVAL(data.return_data);
                   1187: 
                   1188:                        if (xAnswer) {
                   1189:                                XMLRPC_CleanupValue(xAnswer);
                   1190:                        }
                   1191: 
                   1192:                        XMLRPC_RequestFree(xRequest, 1);
                   1193:                }
                   1194:        }
                   1195: }
                   1196: /* }}} */
                   1197: 
                   1198: /* {{{ proto int xmlrpc_server_add_introspection_data(resource server, array desc)
                   1199:    Adds introspection documentation  */
                   1200: PHP_FUNCTION(xmlrpc_server_add_introspection_data)
                   1201: {
                   1202:        zval *handle, *desc;
                   1203:        int type;
                   1204:        xmlrpc_server_data* server;
                   1205: 
                   1206:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ra", &handle, &desc) == FAILURE) {
                   1207:                return;
                   1208:        }
                   1209: 
                   1210:        server = zend_list_find(Z_LVAL_P(handle), &type);
                   1211: 
                   1212:        if (type == le_xmlrpc_server) {
                   1213:                XMLRPC_VALUE xDesc = PHP_to_XMLRPC(desc TSRMLS_CC);
                   1214:                if (xDesc) {
                   1215:                        int retval = XMLRPC_ServerAddIntrospectionData(server->server_ptr, xDesc);
                   1216:                        XMLRPC_CleanupValue(xDesc);
                   1217:                        RETURN_LONG(retval);
                   1218:                }
                   1219:        }
                   1220:        RETURN_LONG(0);
                   1221: }
                   1222: /* }}} */
                   1223: 
                   1224: /* {{{ proto array xmlrpc_parse_method_descriptions(string xml)
                   1225:    Decodes XML into a list of method descriptions */
                   1226: PHP_FUNCTION(xmlrpc_parse_method_descriptions)
                   1227: {
                   1228:        zval *retval;
                   1229:        char *arg1;
                   1230:        int arg1_len;
                   1231: 
                   1232:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg1, &arg1_len) == FAILURE) {
                   1233:                return;
                   1234:        }
                   1235: 
                   1236:        if (return_value_used) {
                   1237:                STRUCT_XMLRPC_ERROR err = {0};
                   1238:                XMLRPC_VALUE xVal = XMLRPC_IntrospectionCreateDescription(arg1, &err);
                   1239:                if (xVal) {
                   1240:                        retval = XMLRPC_to_PHP(xVal);
                   1241: 
                   1242:                        if (retval) {
1.1.1.2   misho    1243:                                RETVAL_ZVAL(retval, 1, 1);
1.1       misho    1244:                        }
                   1245:                        /* dust, sweep, and mop */
                   1246:                        XMLRPC_CleanupValue(xVal);
                   1247:                } else {
                   1248:                        /* could not create description */
                   1249:                        if (err.xml_elem_error.parser_code) {
                   1250:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "xml parse error: [line %ld, column %ld, message: %s] Unable to create introspection data", 
                   1251:                                                err.xml_elem_error.column, err.xml_elem_error.line, err.xml_elem_error.parser_error);
                   1252:                        } else {
                   1253:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid xml structure. Unable to create introspection data");
                   1254:                        }
                   1255: 
                   1256:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "xml parse error. no method description created");
                   1257:                }
                   1258:        }
                   1259: }
                   1260: /* }}} */
                   1261: 
                   1262: /************
                   1263: * type data *
                   1264: ************/
                   1265: 
                   1266: #define XMLRPC_TYPE_COUNT 9
                   1267: #define XMLRPC_VECTOR_TYPE_COUNT 4
                   1268: #define TYPE_STR_MAP_SIZE (XMLRPC_TYPE_COUNT + XMLRPC_VECTOR_TYPE_COUNT)
                   1269: 
                   1270: /* return a string matching a given xmlrpc type */
                   1271: static const char** get_type_str_mapping(void) /* {{{ */
                   1272: {
                   1273:        static const char* str_mapping[TYPE_STR_MAP_SIZE];
                   1274:        static int first = 1;
                   1275:        if (first) {
                   1276:                /* warning. do not add/delete without changing size define */
                   1277:                str_mapping[xmlrpc_none]     = "none";
                   1278:                str_mapping[xmlrpc_empty]    = "empty";
                   1279:                str_mapping[xmlrpc_base64]   = "base64";
                   1280:                str_mapping[xmlrpc_boolean]  = "boolean";
                   1281:                str_mapping[xmlrpc_datetime] = "datetime";
                   1282:                str_mapping[xmlrpc_double]   = "double";
                   1283:                str_mapping[xmlrpc_int]      = "int";
                   1284:                str_mapping[xmlrpc_string]   = "string";
                   1285:                str_mapping[xmlrpc_vector]   = "vector";
                   1286:                str_mapping[XMLRPC_TYPE_COUNT + xmlrpc_vector_none]   = "none";
                   1287:                str_mapping[XMLRPC_TYPE_COUNT + xmlrpc_vector_array]  = "array";
                   1288:                str_mapping[XMLRPC_TYPE_COUNT + xmlrpc_vector_mixed]  = "mixed";
                   1289:                str_mapping[XMLRPC_TYPE_COUNT + xmlrpc_vector_struct] = "struct";
                   1290:                first = 0;
                   1291:        }
                   1292:        return (const char**)str_mapping;
                   1293: }
                   1294: /* }}} */
                   1295: 
                   1296: /* map an xmlrpc type to a string */
                   1297: const char* xmlrpc_type_as_str(XMLRPC_VALUE_TYPE type, XMLRPC_VECTOR_TYPE vtype) /* {{{ */
                   1298: {
                   1299:        const char** str_mapping = get_type_str_mapping();
                   1300: 
                   1301:        if (vtype == xmlrpc_vector_none) {
                   1302:                return str_mapping[type];
                   1303:        } else {
                   1304:                return str_mapping[XMLRPC_TYPE_COUNT + vtype];
                   1305:        }
                   1306: }
                   1307: /* }}} */
                   1308: 
                   1309: /* map a string to an xmlrpc type */
                   1310: XMLRPC_VALUE_TYPE xmlrpc_str_as_type(const char* str) /* {{{ */
                   1311: {
                   1312:        const char** str_mapping = get_type_str_mapping();
                   1313:        int i;
                   1314: 
                   1315:        if (str) {
                   1316:                for (i = 0; i < XMLRPC_TYPE_COUNT; i++) {
                   1317:                        if (!strcmp(str_mapping[i], str)) {
                   1318:                                return (XMLRPC_VALUE_TYPE) i;
                   1319:                        }
                   1320:                }
                   1321:        }
                   1322:        return xmlrpc_none;
                   1323: }
                   1324: /* }}} */
                   1325: 
                   1326: /* map a string to an xmlrpc vector type */
                   1327: XMLRPC_VECTOR_TYPE xmlrpc_str_as_vector_type(const char* str) /* {{{ */
                   1328: {
                   1329:        const char** str_mapping = get_type_str_mapping();
                   1330:        int i;
                   1331: 
                   1332:        if (str) {
                   1333:                for (i = XMLRPC_TYPE_COUNT; i < TYPE_STR_MAP_SIZE; i++) {
                   1334:                        if (!strcmp(str_mapping[i], str)) {
                   1335:                                return (XMLRPC_VECTOR_TYPE) (i - XMLRPC_TYPE_COUNT);
                   1336:                        }
                   1337:                }
                   1338:        }
                   1339:        return xmlrpc_none;
                   1340: }
                   1341: /* }}} */
                   1342: 
                   1343: /* set a given value to a particular type. 
                   1344:  * note: this only works on strings, and only for date and base64,
                   1345:  *       which do not have native php types. black magic lies herein.
                   1346:  */
                   1347: int set_zval_xmlrpc_type(zval* value, XMLRPC_VALUE_TYPE newtype) /* {{{ */
                   1348: {
                   1349:        int bSuccess = FAILURE;
                   1350:        TSRMLS_FETCH();
                   1351: 
                   1352:        /* we only really care about strings because they can represent
                   1353:         * base64 and datetime.  all other types have corresponding php types
                   1354:         */
                   1355:        if (Z_TYPE_P(value) == IS_STRING) {
                   1356:                if (newtype == xmlrpc_base64 || newtype == xmlrpc_datetime) {
                   1357:                        const char* typestr = xmlrpc_type_as_str(newtype, xmlrpc_vector_none);
                   1358:                        zval* type;
                   1359: 
                   1360:                        MAKE_STD_ZVAL(type);
                   1361: 
                   1362:                        Z_TYPE_P(type) = IS_STRING;
                   1363:                        Z_STRVAL_P(type) = estrdup(typestr);
                   1364:                        Z_STRLEN_P(type) = strlen(typestr);
                   1365: 
                   1366:                        if (newtype == xmlrpc_datetime) {
                   1367:                                XMLRPC_VALUE v = XMLRPC_CreateValueDateTime_ISO8601(NULL, value->value.str.val);
                   1368:                                if (v) {
                   1369:                                        time_t timestamp = (time_t) php_parse_date((char *)XMLRPC_GetValueDateTime_ISO8601(v), NULL);
                   1370:                                        if (timestamp != -1) {
                   1371:                                                zval* ztimestamp;
                   1372: 
                   1373:                                                MAKE_STD_ZVAL(ztimestamp);
                   1374: 
                   1375:                                                ztimestamp->type = IS_LONG;
                   1376:                                                ztimestamp->value.lval = timestamp;
                   1377: 
                   1378:                                                convert_to_object(value);
                   1379:                                                if (SUCCESS == zend_hash_update(Z_OBJPROP_P(value), OBJECT_TYPE_ATTR, sizeof(OBJECT_TYPE_ATTR), (void *) &type, sizeof(zval *), NULL)) {
                   1380:                                                        bSuccess = zend_hash_update(Z_OBJPROP_P(value), OBJECT_VALUE_TS_ATTR, sizeof(OBJECT_VALUE_TS_ATTR), (void *) &ztimestamp, sizeof(zval *), NULL);
                   1381:                                                }
                   1382:                                        } else {
                   1383:                                                zval_ptr_dtor(&type);
                   1384:                                        }
                   1385:                                        XMLRPC_CleanupValue(v);
                   1386:                                } else {
                   1387:                                        zval_ptr_dtor(&type);
                   1388:                                }
                   1389:                        } else {
                   1390:                                convert_to_object(value);
                   1391:                                bSuccess = zend_hash_update(Z_OBJPROP_P(value), OBJECT_TYPE_ATTR, sizeof(OBJECT_TYPE_ATTR), (void *) &type, sizeof(zval *), NULL);
                   1392:                        }
                   1393:                }
                   1394:        }
                   1395: 
                   1396:        return bSuccess;
                   1397: }
                   1398: /* }}} */
                   1399: 
                   1400: /* return xmlrpc type of a php value */
                   1401: XMLRPC_VALUE_TYPE get_zval_xmlrpc_type(zval* value, zval** newvalue) /* {{{ */
                   1402: {
                   1403:        XMLRPC_VALUE_TYPE type = xmlrpc_none;
                   1404:        TSRMLS_FETCH();
                   1405: 
                   1406:        if (value) {
                   1407:                switch (Z_TYPE_P(value)) {
                   1408:                        case IS_NULL:
                   1409:                                type = xmlrpc_base64;
                   1410:                                break;
                   1411: #ifndef BOOL_AS_LONG
                   1412: 
                   1413:                        /* Right thing to do, but it breaks some legacy code. */
                   1414:                        case IS_BOOL:
                   1415:                                type = xmlrpc_boolean;
                   1416:                                break;
                   1417: #else
                   1418:                        case IS_BOOL:
                   1419: #endif
                   1420:                        case IS_LONG:
                   1421:                        case IS_RESOURCE:
                   1422:                                type = xmlrpc_int;
                   1423:                                break;
                   1424:                        case IS_DOUBLE:
                   1425:                                type = xmlrpc_double;
                   1426:                                break;
                   1427:                        case IS_CONSTANT:
                   1428:                                type = xmlrpc_string;
                   1429:                                break;
                   1430:                        case IS_STRING:
                   1431:                                type = xmlrpc_string;
                   1432:                                break;
                   1433:                        case IS_ARRAY:
                   1434:                        case IS_CONSTANT_ARRAY:
                   1435:                                type = xmlrpc_vector;
                   1436:                                break;
                   1437:                        case IS_OBJECT:
                   1438:                                {
                   1439:                                        zval** attr;
                   1440:                                        type = xmlrpc_vector;
                   1441: 
                   1442:                                        if (zend_hash_find(Z_OBJPROP_P(value), OBJECT_TYPE_ATTR, sizeof(OBJECT_TYPE_ATTR), (void**) &attr) == SUCCESS) {
                   1443:                                                if (Z_TYPE_PP(attr) == IS_STRING) {
                   1444:                                                        type = xmlrpc_str_as_type(Z_STRVAL_PP(attr));
                   1445:                                                }
                   1446:                                        }
                   1447:                                        break;
                   1448:                                }
                   1449:                }
                   1450: 
                   1451:                /* if requested, return an unmolested (magic removed) copy of the value */
                   1452:                if (newvalue) {
                   1453:                        zval** val;
                   1454: 
                   1455:                        if ((type == xmlrpc_base64 && Z_TYPE_P(value) != IS_NULL) || type == xmlrpc_datetime) {
                   1456:                                if (zend_hash_find(Z_OBJPROP_P(value), OBJECT_VALUE_ATTR, sizeof(OBJECT_VALUE_ATTR), (void**) &val) == SUCCESS) {
                   1457:                                        *newvalue = *val;
                   1458:                                }
                   1459:                        } else {
                   1460:                                *newvalue = value;
                   1461:                        }
                   1462:                }
                   1463:        }
                   1464: 
                   1465:        return type;
                   1466: }
                   1467: /* }}} */
                   1468: 
                   1469: /* {{{ proto bool xmlrpc_set_type(string value, string type)
                   1470:    Sets xmlrpc type, base64 or datetime, for a PHP string value */
                   1471: PHP_FUNCTION(xmlrpc_set_type)
                   1472: {
                   1473:        zval **arg;
                   1474:        char *type;
                   1475:        int type_len;
                   1476:        XMLRPC_VALUE_TYPE vtype;
                   1477: 
                   1478:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zs", &arg, &type, &type_len) == FAILURE) {
                   1479:                return;
                   1480:        }
                   1481: 
                   1482:        vtype = xmlrpc_str_as_type(type);
                   1483:        if (vtype != xmlrpc_none) {
                   1484:                if (set_zval_xmlrpc_type(*arg, vtype) == SUCCESS) {
                   1485:                        RETURN_TRUE;
                   1486:                }
                   1487:        } else {
                   1488:                zend_error(E_WARNING,"invalid type '%s' passed to xmlrpc_set_type()", type);
                   1489:        }
                   1490:        RETURN_FALSE;
                   1491: }
                   1492: /* }}} */
                   1493: 
                   1494: /* {{{ proto string xmlrpc_get_type(mixed value)
                   1495:    Gets xmlrpc type for a PHP value. Especially useful for base64 and datetime strings */
                   1496: PHP_FUNCTION(xmlrpc_get_type)
                   1497: {
                   1498:        zval **arg;
                   1499:        XMLRPC_VALUE_TYPE type;
                   1500:        XMLRPC_VECTOR_TYPE vtype = xmlrpc_vector_none;
                   1501: 
                   1502:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg) == FAILURE) {
                   1503:                return;
                   1504:        }
                   1505: 
                   1506:        type = get_zval_xmlrpc_type(*arg, 0);
                   1507:        if (type == xmlrpc_vector) {
                   1508:                vtype = determine_vector_type((Z_TYPE_PP(arg) == IS_OBJECT) ? Z_OBJPROP_PP(arg) : Z_ARRVAL_PP(arg));
                   1509:        }
                   1510:    
                   1511:        RETURN_STRING((char*) xmlrpc_type_as_str(type, vtype), 1);
                   1512: }
                   1513: /* }}} */
                   1514: 
                   1515: /* {{{ proto bool xmlrpc_is_fault(array)
                   1516:    Determines if an array value represents an XMLRPC fault. */
                   1517: PHP_FUNCTION(xmlrpc_is_fault)
                   1518: {
                   1519:        zval *arg, **val;
                   1520: 
                   1521:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &arg) == FAILURE) {
                   1522:                return;
                   1523:        }
                   1524: 
                   1525:        /* The "correct" way to do this would be to call the xmlrpc
                   1526:         * library XMLRPC_ValueIsFault() func.  However, doing that
                   1527:         * would require us to create an xmlrpc value from the php
                   1528:         * array, which is rather expensive, especially if it was
                   1529:         * a big array.  Thus, we resort to this not so clever hackery.
                   1530:         */
                   1531:        if (zend_hash_find(Z_ARRVAL_P(arg), FAULT_CODE, FAULT_CODE_LEN + 1, (void**) &val) == SUCCESS && 
                   1532:                zend_hash_find(Z_ARRVAL_P(arg), FAULT_STRING, FAULT_STRING_LEN + 1, (void**) &val) == SUCCESS) {
                   1533:                RETURN_TRUE;
                   1534:        }
                   1535: 
                   1536:        RETURN_FALSE;
                   1537: }
                   1538: /* }}} */
                   1539: 
                   1540: /*
                   1541:  * Local variables:
                   1542:  * tab-width: 4
                   1543:  * c-basic-offset: 4
                   1544:  * End:
                   1545:  */
                   1546: 

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