/* +----------------------------------------------------------------------+ | PHP version 4.0 | +----------------------------------------------------------------------+ | Copyright (c) 1997, 1998, 1999, 2000 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 2.02 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available at through the world-wide-web at | | http://www.php.net/license/2_02.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Sterling Hughes | +----------------------------------------------------------------------+ */ #include "php.h" #if HAVE_SABLOT /* Sablotron Includes */ #include /* Standard Includes */ #include /* PHP Includes */ #include "ext/standard/info.h" #include "ext/standard/php_output.h" #include "php_sablot.h" static int le_sablot; /* Functions related to PHP's list handling */ static void _php_sablot_free_processor(zend_rsrc_list_entry *rsrc); /* SAX Handlers */ static void _php_sablot_handler_pair(php_sablot *, zval **, zval **, zval **); static void _php_sablot_call_handler_function(zval *, int, zval **, char *); static SAX_RETURN _php_sablot_sax_startDoc(void *); static SAX_RETURN _php_sablot_sax_startElement(void *, const char *, const char **); static SAX_RETURN _php_sablot_sax_endElement(void *, const char *); static SAX_RETURN _php_sablot_sax_startNamespace(void *, const char *, const char *); static SAX_RETURN _php_sablot_sax_endNamespace(void *, const char *); static SAX_RETURN _php_sablot_sax_comment(void *, const char *); static SAX_RETURN _php_sablot_sax_PI(void *, const char *, const char *); static SAX_RETURN _php_sablot_sax_characters(void *, const char *, int); static SAX_RETURN _php_sablot_sax_endDoc(void *); /* Error Handling Functions */ static MH_ERROR _php_sablot_make_code(void *, SablotHandle, int, unsigned short, unsigned short); static MH_ERROR _php_sablot_error(void *, SablotHandle, MH_ERROR, MH_LEVEL, char **); static void _php_sablot_standard_error(php_sablot_error *, php_sablot_error, int, int); /* Scheme Handling Functions */ static int _php_sablot_sh_getAll(void *userData, SablotHandle p, const char *scheme, const char *rest, char **buffer, int *byteCount); static int _php_sablot_sh_freeMemory(void *userData, SablotHandle p, char *buffer); static int _php_sablot_sh_open(void *userData, SablotHandle p, const char *scheme, const char *rest, int *handle); static int _php_sablot_sh_get(void *userData, SablotHandle p, int handle, char *buffer, int *byteCount); static int _php_sablot_sh_put(void *userData, SablotHandle p, int handle, const char *buffer, int *byteCount); static int _php_sablot_sh_close(void *userData, SablotHandle p, int handle); /* PHP Utility Functions */ static void _php_sablot_ht_char(HashTable *, char **); static zval *_php_sablot_string_zval(const char *); static zval *_php_sablot_resource_zval(long); /* Macro's */ /* Free macros */ #define S_FREE(__var) if (__var) efree(__var); #define FUNCH_FREE(__var) if (__var) zval_del_ref(&(__var)); /* ERROR Macros */ #define SABLOT_FREE_ERROR_HANDLE(__handle) \ if ((__handle).errors) { \ (__handle).errors = (__handle).errors_start.next; \ while ((__handle).errors) { \ S_FREE((__handle).errors->key); \ S_FREE((__handle).errors->value); \ (__handle).errors = (__handle).errors->next; \ } \ S_FREE((__handle).errors); \ } /* Sablotron Basic Api macro's */ #define SABLOT_BASIC_CREATE_PROCESSOR() \ if (SABLOTG(processor) == NULL) { \ int ret = 0; \ \ ret = SablotCreateProcessor(&SABLOTG(processor)); \ if (ret) { \ SABLOTG(last_errno) = (int) ret; \ return; \ } \ \ ret = SablotRegHandler(SABLOTG(processor), HLR_MESSAGE, (void *)&mh, (void *)NULL); \ if (ret) { \ SABLOTG(last_errno) = (int) ret; \ return; \ } \ } #define SABLOT_BASIC_HANDLE SABLOTG(processor) #define SABLOT_SET_ERROR(handle, error) \ if (error != 0) { \ if (handle) { \ handle->last_errno = error; \ } \ \ SABLOTG(last_errno) = error; \ } /** * SAX Handler structure, this defines the different functions to be * called when Sablotron's internal expat parser reaches the * different callbacks. These are the same as the functions which are * defined for expat. */ static SAXHandler sax = { _php_sablot_sax_startDoc, _php_sablot_sax_startElement, _php_sablot_sax_endElement, _php_sablot_sax_startNamespace, _php_sablot_sax_endNamespace, _php_sablot_sax_comment, _php_sablot_sax_PI, _php_sablot_sax_characters, _php_sablot_sax_endDoc }; /** * Message Handler structure for use when Sablotron * reports that something has gone wrong. */ static MessageHandler mh = { _php_sablot_make_code, _php_sablot_error, _php_sablot_error }; /** * Scheme Handler structure for use when Sablotron * call rhe document Xpath function. */ static SchemeHandler sh = { _php_sablot_sh_getAll, _php_sablot_sh_freeMemory, _php_sablot_sh_open, _php_sablot_sh_get, _php_sablot_sh_put, _php_sablot_sh_close }; #ifdef ZTS int sablot_globals_id; #else php_sablot_globals sablot_globals; #endif static unsigned char sixth_arg_force_ref[] = { 6, BYREF_NONE, BYREF_NONE, BYREF_NONE, BYREF_NONE, BYREF_NONE, BYREF_FORCE }; static unsigned char third_arg_force_ref[] = { 4, BYREF_NONE, BYREF_NONE, BYREF_FORCE, BYREF_NONE }; function_entry sablot_functions[] = { PHP_FE(xslt_output_begintransform, NULL) PHP_FE(xslt_output_endtransform, NULL) PHP_FE(xslt_transform, sixth_arg_force_ref) PHP_FE(xslt_process, third_arg_force_ref) PHP_FE(xslt_create, NULL) PHP_FE(xslt_run, NULL) PHP_FE(xslt_fetch_result, NULL) PHP_FE(xslt_openlog, NULL) PHP_FE(xslt_closelog, NULL) PHP_FE(xslt_set_sax_handler, NULL) PHP_FE(xslt_set_scheme_handler, NULL) PHP_FE(xslt_set_error_handler, NULL) PHP_FE(xslt_set_base, NULL) #ifdef HAVE_SABLOT_SET_ENCODING PHP_FE(xslt_set_encoding, NULL) #endif PHP_FE(xslt_free, NULL) PHP_FE(xslt_error, NULL) PHP_FE(xslt_errno, NULL) {NULL, NULL, NULL} }; zend_module_entry sablot_module_entry = { "sablot", sablot_functions, PHP_MINIT(sablot), PHP_MSHUTDOWN(sablot), NULL, PHP_RSHUTDOWN(sablot), PHP_MINFO(sablot), STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_SABLOT ZEND_GET_MODULE(sablot) #endif static void php_sablot_init_globals(SABLOTLS_D) { SABLOTG(processor) = NULL; SABLOTG(errors) = NULL; SABLOTG(errorHandler) = NULL; } /* MINIT and MINFO Functions */ PHP_MINIT_FUNCTION(sablot) { #ifdef ZTS sablot_globals_id = ts_allocate_id(sizeof(php_sablot_globals), (ts_allocate_ctor)php_sablot_init_globals, NULL); #else php_sablot_init_globals(SABLOTLS_C); #endif le_sablot = zend_register_list_destructors_ex(_php_sablot_free_processor, NULL, "Sablotron XSLT", module_number); return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(sablot) { SABLOTLS_FETCH(); if (SABLOTG(processor)) { SablotUnregHandler(SABLOTG(processor), HLR_MESSAGE, NULL, NULL); SablotDestroyProcessor(SABLOTG(processor)); } return SUCCESS; } PHP_RSHUTDOWN_FUNCTION(sablot) { SABLOTLS_FETCH(); SABLOT_FREE_ERROR_HANDLE(SABLOTG_HANDLE); return SUCCESS; } PHP_MINFO_FUNCTION(sablot) { php_info_print_table_start(); php_info_print_table_row(2, "Sablotron XSLT support", "enabled"); php_info_print_table_end(); } /* {{{ proto void xslt_output_begintransform(string file) Begin filtering of all data that is being printed out through the XSL file given by the file parameter. */ PHP_FUNCTION(xslt_output_begintransform) { /* The name of the file to pass the output through */ zval **file; /* needed for the output transformation file name */ SABLOTLS_FETCH(); if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &file) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string_ex(file); /* If the buffer exists, free it */ S_FREE(SABLOTG(output_transform_file)); SABLOTG(output_transform_file) = estrndup(Z_STRVAL_PP(file), Z_STRLEN_PP(file)); /** * Start output buffering, NULL signifies that no "user-space" output function * will be used. The 0 disables chunking */ php_start_ob_buffer(NULL, 0); } /* }}} */ /* {{{ proto void xslt_output_endtranform(void) End filtering that data through the XSL file set by xslt_output_transform() and output the data */ PHP_FUNCTION(xslt_output_endtransform) { char *tRes = NULL, *buffer = NULL; int ret = 0; /* Fetch both the output globals and the sablotron globals */ OLS_FETCH(); SABLOTLS_FETCH(); /** * Make sure that we don't have more than one output buffer going on * at the same time. */ if (OG(nesting_level) == 0) { RETURN_NULL(); } buffer = estrndup(OG(active_ob_buffer).buffer, OG(active_ob_buffer).text_length); /* Nake sure there is data to send */ if (OG(active_ob_buffer).text_length) { char *args[] = {"/_xmlinput", buffer, "/_output", NULL}; SABLOT_BASIC_CREATE_PROCESSOR(); ret = SablotRunProcessor(SABLOT_BASIC_HANDLE, SABLOTG(output_transform_file), "arg:/_xmlinput", "arg:/_output", NULL, args); if (ret) { SABLOTG(last_errno) = ret; S_FREE(SABLOTG(output_transform_file)); RETURN_NULL(); } ret = SablotGetResultArg(SABLOT_BASIC_HANDLE, "arg:/_output", &tRes); if (ret) { SABLOTG(last_errno) = ret; S_FREE(SABLOTG(output_transform_file)); RETURN_NULL(); } } /** * A non-zero return means error, save this error in the global * errno (for xslt_errno() and xslt_error()) free the output * transformation file and null. */ if (ret) { SABLOTG(last_errno) = ret; S_FREE(SABLOTG(output_transform_file)); RETURN_NULL(); } /** * If there is a buffer, end output buffering and clear the * current output buffer (so we don't send data twice) */ if (tRes) php_end_ob_buffer(0); PUTS(tRes); S_FREE(SABLOTG(output_transform_file)); S_FREE(buffer); /** * If there exists a result, free that result * otherwise just end output buffering and send the * data. */ if (tRes) SablotFree(tRes); else php_end_ob_buffer(1); } /* }}} */ /* {{{ proto bool xslt_transform(string xslt_uri, string transform_uri, string result_uri[, array xslt_params[, array xslt_args[, string &result]]]) Transform an XML document, transform_uri, with an XSL stylesheet, xslt_uri with parameters, xslt_params, into the Result buffer, result_uri, xslt_args defines the variables in xslt_uri, transform_uri and result_uri. */ PHP_FUNCTION(xslt_transform) { zval **xslt_uri, **transform_uri, **result_uri, **xslt_params, **xslt_args, **result; char **args = NULL, **params = NULL, *tResult = NULL; int argc = ZEND_NUM_ARGS(), ret = 0; SABLOTLS_FETCH(); if (argc < 3 || argc > 6 || zend_get_parameters_ex(argc, &xslt_uri, &transform_uri, &result_uri, &xslt_params, &xslt_args, &result) == FAILURE) { WRONG_PARAM_COUNT; } multi_convert_to_string_ex(3, xslt_uri, transform_uri, result_uri); /** * if there are more than 3 function arguments, inspect the value of * the third argument and decide whether or not there are Sablotron * parameters. */ if (argc > 3) { HashTable *ar = HASH_OF(*xslt_params); if (ar) { int numelems, size; /** * Allocate 2 times the number of elements in * the array, since with associative arrays in PHP * keys are not counted. */ numelems = zend_hash_num_elements(ar); size = (numelems * 2 + 1) * sizeof(char *); params = (char **)emalloc(size+1); memset((char *)params, 0, size); /** * Translate a PHP array (HashTable *) into a * Sablotron array (char **). */ _php_sablot_ht_char(ar, params); } } /** * If there are more than 4 function arguments, inspect the value * of the 4 argument and decide whether or not there are Sablotron * arguments. */ if (argc > 4) { HashTable *ar = HASH_OF(*xslt_args); if (ar) { int numelems, size; numelems = zend_hash_num_elements(ar); size = (numelems * 2 + 1) * sizeof(char *); args = (char **)emalloc(size+1); memset((char *)args, 0, size); _php_sablot_ht_char(ar, args); } } SABLOT_BASIC_CREATE_PROCESSOR(); ret = SablotRunProcessor(SABLOT_BASIC_HANDLE, Z_STRVAL_PP(xslt_uri), Z_STRVAL_PP(transform_uri), Z_STRVAL_PP(result_uri), params, args); if (ret) { SABLOTG(last_errno) = ret; S_FREE(params); S_FREE(args); RETURN_FALSE; } ret = SablotGetResultArg(SABLOT_BASIC_HANDLE, Z_STRVAL_PP(result_uri), &tResult); if (ret) { SABLOTG(last_errno) = ret; S_FREE(params); S_FREE(args); if (tResult) SablotFree(tResult); RETURN_FALSE; } else { RETVAL_TRUE; } if (tResult && argc == 6) { ZVAL_STRING(*result, tResult, 1); } S_FREE(params); S_FREE(args); if (tResult) SablotFree(tResult); } /* }}} */ /* {{{ proto bool xslt_process(string xslt, string input_str, string &result[, string base]) Process data given by input_str through xslt and place the results in the string result. If base is supplied, it will be used as the base URI. */ PHP_FUNCTION(xslt_process) { zval **xslt, **input, **result, **base; char *tRes = NULL; int ret = 0, argc = ZEND_NUM_ARGS(); SABLOTLS_FETCH(); if (argc < 3 || argc > 4 || zend_get_parameters_ex(argc, &xslt, &input, &result, &base) == FAILURE) { WRONG_PARAM_COUNT; } multi_convert_to_string_ex(2, xslt, input); SABLOT_BASIC_CREATE_PROCESSOR(); /** * If we have more than three arguments that means we have * a base! */ if (argc > 3) { convert_to_string_ex(base); SablotSetBase(SABLOT_BASIC_HANDLE, Z_STRVAL_PP(base)); } /** * Need to declare args here (to lazy to actually allocate * it with emalloc() ;) */ { char *args[] = {"/_stylesheet", Z_STRVAL_PP(xslt), "/_xmlinput", Z_STRVAL_PP(input), "/_output", NULL, NULL}; ret = SablotRunProcessor(SABLOT_BASIC_HANDLE, "arg:/_stylesheet", "arg:/_xmlinput", "arg:/_output", NULL, args); } if (ret) { SABLOTG(last_errno) = ret; RETURN_FALSE; } SablotGetResultArg(SABLOT_BASIC_HANDLE, "arg:/_output", &tRes); if (ret) { SABLOTG(last_errno) = ret; RETURN_FALSE; if (tRes) SablotFree(tRes); } if (tRes) { ZVAL_STRING(*result, tRes, 1); SablotFree(tRes); } RETURN_TRUE; } /* }}} */ /* {{{ proto resource xslt_create(void) Create a new XSL processor and return a resource identifier. */ PHP_FUNCTION(xslt_create) { php_sablot *handle; SablotHandle p; int ret; SABLOTLS_FETCH(); ret = SablotCreateProcessor(&p); if (ret) { SABLOTG(last_errno) = ret; RETURN_FALSE; } handle = (php_sablot *)emalloc(sizeof(php_sablot)); if (!handle) { php_error(E_WARNING, "Couldn't allocate PHP-Sablotron Handle"); RETURN_FALSE; } memset(handle, 0, sizeof(php_sablot)); handle->p = p; ret = SablotRegHandler(handle->p, HLR_SAX, (void *)&sax, (void *)handle); if (ret) { SABLOTG(last_errno) = ret; RETURN_FALSE; } ret = SablotRegHandler(handle->p, HLR_MESSAGE, (void *)&mh, (void *)handle); if (ret) { SABLOTG(last_errno) = ret; RETURN_FALSE; } ret = SablotRegHandler(handle->p, HLR_SCHEME, (void *)&sh, (void *)handle); if (ret) { SABLOTG(last_errno) = ret; RETURN_FALSE; } ZEND_REGISTER_RESOURCE(return_value, handle, le_sablot); handle->index = Z_LVAL_P(return_value); } /* }}} */ /* {{{ proto bool xslt_run(resource xh, string xslt_file, string data_file[, string result[, array xslt_params[, array xslt_args]]]) Process the file data_file with the XSL stylesheet xslt_file and parameters xslt_parameters place the results in the buffer pointed to by the result parameter (defaults to "/_result"), args contains the values of the variables in the other parameters. */ PHP_FUNCTION(xslt_run) { zval **xh, **xslt_file, **data_file, **xslt_result, **xslt_params, **xslt_args; php_sablot *handle; char **args = NULL, **params = NULL, *result = NULL; int argc = ZEND_NUM_ARGS(), ret = 0; SABLOTLS_FETCH(); if (argc < 3 || argc > 6 || zend_get_parameters_ex(argc, &xh, &xslt_file, &data_file, &xslt_result, &xslt_params, &xslt_args) == FAILURE) { WRONG_PARAM_COUNT; } ZEND_FETCH_RESOURCE(handle, php_sablot *, xh, -1, "PHP-Sablotron handle", le_sablot); multi_convert_to_string_ex(2, xslt_file, data_file); if (argc == 3) { result = estrdup("arg:/_result"); } if (argc > 3) { convert_to_string_ex(xslt_result); result = estrndup(Z_STRVAL_PP(xslt_result), Z_STRLEN_PP(xslt_result)); } if (argc > 4) { HashTable *ar = HASH_OF(*xslt_params); if (ar) { int numelems, size; numelems = zend_hash_num_elements(ar); size = (numelems * 2 + 1) * sizeof(char *); params = (char **)emalloc(size+1); memset((char *)params, 0, size); _php_sablot_ht_char(ar, params); } } if (argc > 5) { HashTable *ar = HASH_OF(*xslt_args); if (ar) { int numelems, size; numelems = zend_hash_num_elements(ar); size = (numelems * 2 + 1) * sizeof(char *); args = (char **)emalloc(size+1); memset((char *)args, 0, size); _php_sablot_ht_char(ar, args); } } ret = SablotRunProcessor(handle->p, Z_STRVAL_PP(xslt_file), Z_STRVAL_PP(data_file), result, params, args); if (ret) { handle->last_errno = ret; SABLOTG(last_errno) = ret; S_FREE(params); S_FREE(args); S_FREE(result); RETURN_FALSE; } S_FREE(params); S_FREE(args); S_FREE(result); RETURN_TRUE; } /* }}} */ /* {{{ proto bool xslt_openlog(resource xh, string logfile[, int loglevel]) Sets a logfile for Sablotron to place all of its error messages */ PHP_FUNCTION(xslt_openlog) { zval **xh, **logfile, **opt_loglevel; php_sablot *handle; int ret = 0, loglevel = 0, argc = ZEND_NUM_ARGS(); SABLOTLS_FETCH(); if (argc < 2 || argc > 3 || zend_get_parameters_ex(argc, &xh, &logfile, &opt_loglevel) == FAILURE) { WRONG_PARAM_COUNT; } ZEND_FETCH_RESOURCE(handle, php_sablot *, xh, -1, "PHP-Sablotron", le_sablot); convert_to_string_ex(logfile); if (argc > 2) { convert_to_long_ex(opt_loglevel); loglevel = Z_LVAL_PP(opt_loglevel); } ret = SablotSetLog(handle->p, (const char *)Z_STRVAL_PP(logfile), loglevel); if (ret) { handle->last_errno = ret; SABLOTG(last_errno) = ret; RETURN_FALSE; } else { RETURN_TRUE; } } /* }}} */ /* {{{ proto bool xslt_closelog(resource xh) Clear the logfile for a given instance Sablotron */ PHP_FUNCTION(xslt_closelog) { zval **xh; php_sablot *handle; int ret; SABLOTLS_FETCH(); if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &xh) == FAILURE) { WRONG_PARAM_COUNT; } ZEND_FETCH_RESOURCE(handle, php_sablot *, xh, -1, "PHP-Sablotron", le_sablot); ret = SablotSetLog(handle->p, (const char *)NULL, 1); if (ret) { RETURN_FALSE; } RETURN_TRUE; } /* }}} */ /* {{{ proto string xslt_fetch_result(resource xh[, string result_name]) Fetch a result buffer on process handle, xh, with name, result_name, if name is not given than the "/_result" buffer is fetched. */ PHP_FUNCTION(xslt_fetch_result) { zval **xh, **result_name; php_sablot *handle; char *value = NULL, *rname = NULL; int argc = ZEND_NUM_ARGS(), ret = 0; SABLOTLS_FETCH(); if (argc < 1 || argc > 2 || zend_get_parameters_ex(argc, &xh, &result_name) == FAILURE) { WRONG_PARAM_COUNT; } ZEND_FETCH_RESOURCE(handle, php_sablot *, xh, -1, "PHP-Sablotron Handle", le_sablot); if (argc > 1) { convert_to_string_ex(result_name); rname = estrndup(Z_STRVAL_PP(result_name), Z_STRLEN_PP(result_name)); } else { rname = estrdup("/_result"); } ret = SablotGetResultArg(handle->p, rname, &value); S_FREE(rname); if (ret) { handle->last_errno = ret; SABLOTG(last_errno) = ret; if (value) { SablotFree(value); } RETURN_FALSE; } if (value) { RETVAL_STRING(value, 1); SablotFree(value); } } /* }}} */ /* {{{ proto void xslt_free(resource xh) Free resources associated with a xslt handle. */ PHP_FUNCTION(xslt_free) { zval **xh; php_sablot *handle; SABLOTLS_FETCH(); if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &xh) == FAILURE) { WRONG_PARAM_COUNT; } ZEND_FETCH_RESOURCE(handle, php_sablot *, xh, -1, "PHP-Sablotron Handle", le_sablot); zend_list_delete(Z_LVAL_PP(xh)); } /* }}} */ /* {{{ proto void xslt_set_sax_handler(resource xh, array handlers) Set SAX Handlers on the resource handle given by xh. */ PHP_FUNCTION(xslt_set_sax_handler) { zval **xh, **handlers, **indiv_handlers; php_sablot *handle; HashTable *handlers_list; char *string_key = NULL; ulong num_key; SABLOTLS_FETCH(); if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &xh, &handlers) == FAILURE) { WRONG_PARAM_COUNT; } if ((*handlers)->type != IS_ARRAY) { php_error(E_ERROR, "The second parameter must be an array"); } ZEND_FETCH_RESOURCE(handle, php_sablot *, xh, -1, "PHP-Sablotron Handle", le_sablot); handlers_list = HASH_OF(*handlers); for (zend_hash_internal_pointer_reset(handlers_list); zend_hash_get_current_data(handlers_list, (void **)&indiv_handlers) == SUCCESS; zend_hash_move_forward(handlers_list)) { SEPARATE_ZVAL(indiv_handlers); if (zend_hash_get_current_key(handlers_list, &string_key, &num_key, 0) == HASH_KEY_IS_LONG) { php_error(E_WARNING, "The Keys of the first dimension of your array must be strings"); RETURN_FALSE; } if (!strcasecmp("document", string_key)) { _php_sablot_handler_pair(handle, &handle->startDocHandler, &handle->endDocHandler, indiv_handlers); } else if (!strcasecmp("element", string_key)) { _php_sablot_handler_pair(handle, &handle->startElementHandler, &handle->endElementHandler, indiv_handlers); } else if (!strcasecmp("namespace", string_key)) { _php_sablot_handler_pair(handle, &handle->startNamespaceHandler, &handle->endNamespaceHandler, indiv_handlers); } else if (!strcasecmp("comment", string_key)) { zval_add_ref(indiv_handlers); handle->commentHandler = *indiv_handlers; } else if (!strcasecmp("pi", string_key)) { zval_add_ref(indiv_handlers); handle->PIHandler = *indiv_handlers; } else if (!strcasecmp("characters", string_key)) { zval_add_ref(indiv_handlers); handle->charactersHandler = *indiv_handlers; } else { php_error(E_WARNING, "Invalid option: %s", string_key); } } } /* }}} */ /* {{{ proto void xslt_set_scheme_handler(resource xh, array handlers) Set SAX Handlers on the resource handle given by xh. */ PHP_FUNCTION(xslt_set_scheme_handler) { zval **xh, **handlers, **indiv_handlers; php_sablot *handle; HashTable *handlers_list; char *string_key = NULL; ulong num_key; SABLOTLS_FETCH(); if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &xh, &handlers) == FAILURE) { WRONG_PARAM_COUNT; } if ((*handlers)->type != IS_ARRAY) { php_error(E_ERROR, "The second parameter must be an array"); } ZEND_FETCH_RESOURCE(handle, php_sablot *, xh, -1, "PHP-Sablotron Handle", le_sablot); handlers_list = HASH_OF(*handlers); for (zend_hash_internal_pointer_reset(handlers_list); zend_hash_get_current_data(handlers_list, (void **)&indiv_handlers) == SUCCESS; zend_hash_move_forward(handlers_list)) { SEPARATE_ZVAL(indiv_handlers); if (zend_hash_get_current_key(handlers_list, &string_key, &num_key, 0) == HASH_KEY_IS_LONG) { php_error(E_WARNING, "The Keys of the first dimension of your array must be strings"); RETURN_FALSE; } if (!strcasecmp("getall", string_key)) { zval_add_ref(indiv_handlers); handle->getAllHandler = *indiv_handlers; } else { php_error(E_WARNING, "Invalid option: %s", string_key); } } } /* }}} */ #ifdef HAVE_SABLOT_SET_ENCODING /* {{{ proto void xslt_set_encoding(resource xh, string encoding) Sets output encoding to be used for Sablotron regardless of the encoding specified by the stylesheet. To unset, call with encoding_ NULL. */ PHP_FUNCTION(xslt_set_encoding) { zval **xh, **encoding; php_sablot *handle; int ret = 0, loglevel = 0, argc = ZEND_NUM_ARGS(); SABLOTLS_FETCH(); if (argc != 2 || zend_get_parameters_ex(argc, &xh, &encoding) == FAILURE) { WRONG_PARAM_COUNT; } ZEND_FETCH_RESOURCE(handle, php_sablot *, xh, -1, "PHP-Sablotron", le_sablot); convert_to_string_ex(encoding); SablotSetEncoding(handle->p, (char *) Z_STRVAL_PP(encoding)); } /* }}} */ #endif /* {{{ proto bool xslt_set_base(resource xh, string scheme, string base) Overrides the default base for a resource. If scheme is non-null, it only affects the uri given by scheme */ PHP_FUNCTION(xslt_set_base) { zval **xh, **scheme, **base; php_sablot *handle; int argc = ZEND_NUM_ARGS(), ret = 0; SABLOTLS_FETCH(); if (argc < 2 || argc > 3 || zend_get_parameters_ex(argc, &xh, &scheme, &base) == FAILURE) { WRONG_PARAM_COUNT; } if (argc > 2) { ZEND_FETCH_RESOURCE(handle, php_sablot *, xh, -1, "PHP-Sablotron handle", le_sablot); if (Z_TYPE_PP(scheme) != IS_STRING) { ret = SablotSetBase(handle->p, Z_STRVAL_PP(base)); } else { ret = SablotSetBaseForScheme((void *) handle->p, Z_STRVAL_PP(scheme), Z_STRVAL_PP(base)); } } else { if (Z_TYPE_PP(scheme) != IS_STRING) { ret = SablotSetBase(SABLOTG(processor), Z_STRVAL_PP(base)); } else { ret = SablotSetBaseForScheme((void *) SABLOTG(processor), Z_STRVAL_PP(scheme), Z_STRVAL_PP(base)); } } SABLOT_SET_ERROR(handle, ret); if (ret != 0) { RETURN_FALSE; } else { RETURN_TRUE; } } /* }}} */ /* }}} */ /* {{{ Begin Error Handling functions */ /* {{{ proto mixed xslt_error([int xh]) Return the error string related to a given error handle. If no handle is given the last error that occurred anywhere is returned. */ PHP_FUNCTION(xslt_error) { zval **xh; php_sablot *handle; int serrno = 0, argc = ZEND_NUM_ARGS(); SABLOTLS_FETCH(); if (argc < 0 || argc > 1 || zend_get_parameters_ex(argc, &xh) == FAILURE) { WRONG_PARAM_COUNT; } if (argc) { ZEND_FETCH_RESOURCE(handle, php_sablot *, xh, -1, "PHP-Sablotron Handle", le_sablot); if (handle->errors) { if (array_init(return_value) == FAILURE) { php_error(E_WARNING, "Cannot initialize return array from xslt_error()"); RETURN_FALSE; } handle->errors = handle->errors_start.next; while (handle->errors) { add_assoc_string(return_value, handle->errors->key, handle->errors->value, 0); handle->errors = handle->errors->next; } add_assoc_string(return_value, "errstr", (char *)SablotGetMsgText(handle->last_errno), 1); add_assoc_long(return_value, "errno", handle->last_errno); return; } serrno = handle->last_errno; } else { serrno = SABLOTG(last_errno); } RETURN_STRING((char *)SablotGetMsgText(serrno), 1); } /* }}} */ /* {{{ proto int xslt_errno([int xh]) Return the error number related to a given error handle. If no handle is given the last error number that occurred anywhere is returned. */ PHP_FUNCTION(xslt_errno) { zval **xh; php_sablot *handle; int argc = ZEND_NUM_ARGS(); SABLOTLS_FETCH(); if (argc < 0 || argc > 1 || zend_get_parameters_ex(argc, &xh) == FAILURE) { WRONG_PARAM_COUNT; } if (argc) { ZEND_FETCH_RESOURCE(handle, php_sablot *, xh, -1, "PHP-Sablotron Handle", le_sablot); RETURN_LONG(handle->last_errno); } else { RETURN_LONG(SABLOTG(last_errno)); } } /* }}} */ /* {{{ proto void xslt_set_error_handler([int xh, ] string error_handler_name) Set a error handler (either per handle or global) */ PHP_FUNCTION(xslt_set_error_handler) { zval **arg1, **arg2; php_sablot *handle; int argc = ZEND_NUM_ARGS(); SABLOTLS_FETCH(); if (argc > 2 || argc < 1 || zend_get_parameters_ex(argc, &arg1, &arg2) == FAILURE) { WRONG_PARAM_COUNT; } if (argc > 1) { convert_to_string_ex(arg2); ZEND_FETCH_RESOURCE(handle, php_sablot *, arg1, -1, "PHP-Sablotron Handle", le_sablot); if (!handle->errorHandler) MAKE_STD_ZVAL(handle->errorHandler); *handle->errorHandler = **arg2; zval_copy_ctor(handle->errorHandler); } else { convert_to_string_ex(arg1); if (!SABLOTG(errorHandler)) MAKE_STD_ZVAL(SABLOTG(errorHandler)); *SABLOTG(errorHandler) = **arg1; zval_copy_ctor(SABLOTG(errorHandler)); } } /* }}} */ /* {{{ _php_sablot_handler_pair() Set the handler functions from a two item array */ static void _php_sablot_handler_pair(php_sablot *handle, zval **first_func, zval **second_func, zval **indiv_handlers) { HashTable *second_level = HASH_OF(*indiv_handlers); zval **handler; int item = 0; for (zend_hash_internal_pointer_reset(second_level); zend_hash_get_current_data(second_level, (void **)&handler) == SUCCESS; zend_hash_move_forward(second_level)) { SEPARATE_ZVAL(handler); zval_add_ref(handler); switch (item) { case 0: *first_func = *handler; break; case 1: *second_func = *handler; break; default: convert_to_string_ex(handler); php_error(E_WARNING, "Sorry, too many elements, %s discarded", Z_STRVAL_PP(handler)); zval_del_ref(handler); break; } item++; } } /* }}} */ /* {{{ _php_sablot_call_handler_function() Call a sablot call handler function, wrapper for call_user_function() */ static void _php_sablot_call_handler_function(zval *handlerName, int argc, zval **args, char *function_name) { zval *retval; int i; ELS_FETCH(); MAKE_STD_ZVAL(retval); if (call_user_function(EG(function_table), NULL, handlerName, retval, argc, args) == FAILURE) { php_error(E_WARNING, "Sorry, couldn't call %s handler", function_name); } zval_dtor(retval); efree(retval); for (i=0; istartDocHandler) { zval *args[1]; args[0] = _php_sablot_resource_zval(handle->index); _php_sablot_call_handler_function(handle->startDocHandler, 1, args, "start document"); } } /* }}} */ /* {{{ _php_sablot_sax_startElement() Start Element handler */ static SAX_RETURN _php_sablot_sax_startElement(void *userData, const char *name, const char **attributes) { php_sablot *handle = (php_sablot *)userData; if (handle->startElementHandler) { zval *args[3]; args[0] = _php_sablot_resource_zval(handle->index); args[1] = _php_sablot_string_zval(name); MAKE_STD_ZVAL(args[2]); if (array_init(args[2]) == FAILURE) { php_error(E_WARNING, "Couldn't initialize array to be passed to start element handler"); return; } while (attributes && *attributes) { char *key = (char *)attributes[0]; zval *value = _php_sablot_string_zval(attributes[1]); add_assoc_string(args[2], key, Z_STRVAL_P(value), 0); attributes += 2; } _php_sablot_call_handler_function(handle->startElementHandler, 3, args, "start element"); } } /* }}} */ /* {{{ _php_sablot_sax_endElement() End element handler */ static SAX_RETURN _php_sablot_sax_endElement(void *userData, const char *name) { php_sablot *handle = (php_sablot *)userData; if (handle->endElementHandler) { zval *args[2]; args[0] = _php_sablot_resource_zval(handle->index); args[1] = _php_sablot_string_zval(name); _php_sablot_call_handler_function(handle->endElementHandler, 2, args, "end element"); } } /* }}} */ /* {{{ _php_sablot_sax_startNamespace() Start Namespace handler */ static SAX_RETURN _php_sablot_sax_startNamespace(void *userData, const char *prefix, const char *uri) { php_sablot *handle = (php_sablot *)userData; if (handle->startNamespaceHandler) { zval *args[3]; args[0] = _php_sablot_resource_zval(handle->index); args[1] = _php_sablot_string_zval(prefix); args[2] = _php_sablot_string_zval(uri); _php_sablot_call_handler_function(handle->startNamespaceHandler, 3, args, "start namespace"); } } /* }}} */ /* {{{ _php_sablot_sax_endNamespace() End Namespace Handler */ static SAX_RETURN _php_sablot_sax_endNamespace(void *userData, const char *prefix) { php_sablot *handle = (php_sablot *)userData; if (handle->endNamespaceHandler) { zval *args[2]; args[0] = _php_sablot_resource_zval(handle->index); args[1] = _php_sablot_string_zval(prefix); _php_sablot_call_handler_function(handle->endNamespaceHandler, 2, args, "end namespace"); } } /* }}} */ /* {{{ _php_sablot_sax_comment() Comment Handler */ static SAX_RETURN _php_sablot_sax_comment(void *userData, const char *contents) { php_sablot *handle = (php_sablot *)userData; if (handle->commentHandler) { zval *args[2]; args[0] = _php_sablot_resource_zval(handle->index); args[1] = _php_sablot_string_zval(contents); _php_sablot_call_handler_function(handle->commentHandler, 2, args, "comment"); } } /* }}} */ /* {{{ _php_sablot_sax_PI() Processing Instruction Handler */ static SAX_RETURN _php_sablot_sax_PI(void *userData, const char *target, const char *contents) { php_sablot *handle = (php_sablot *)userData; if (handle->PIHandler) { zval *args[3]; args[0] = _php_sablot_resource_zval(handle->index); args[1] = _php_sablot_string_zval(target); args[2] = _php_sablot_string_zval(contents); _php_sablot_call_handler_function(handle->PIHandler, 3, args, "PI Handler"); } } /* }}} */ /* {{{ _php_sablot_sax_characters() Character handler */ static SAX_RETURN _php_sablot_sax_characters(void *userData, const char *contents, int length) { php_sablot *handle = (php_sablot *)userData; if (handle->charactersHandler) { zval *args[2]; args[0] = _php_sablot_resource_zval(handle->index); args[1] = _php_sablot_string_zval(contents); _php_sablot_call_handler_function(handle->charactersHandler, 2, args, "characters"); } } /* }}} */ /* {{{ _php_sablot_sax_endDoc() End document handler */ static SAX_RETURN _php_sablot_sax_endDoc(void *userData) { php_sablot *handle = (php_sablot *)userData; if (handle->endDocHandler) { zval *args[1]; args[0] = _php_sablot_resource_zval(handle->index); _php_sablot_call_handler_function(handle->endDocHandler, 1, args, "end document"); } } /* }}} */ /* }}} */ /* {{{ Sablotron Error Handling */ /* {{{ _php_sablot_make_code() Makes an error code, currently does nothing */ static MH_ERROR _php_sablot_make_code(void *userData, SablotHandle p, int severity, unsigned short facility, unsigned short code) { return(code); } /* }}} */ /* {{{ _php_sablot_error() Handle Sablotron errors */ static MH_ERROR _php_sablot_error(void *userData, SablotHandle p, MH_ERROR code, MH_LEVEL level, char **fields) { zval **argv = NULL, *errorHandler; php_sablot_error *errors; php_sablot *handle = NULL; char *sep = NULL; int isAdvanced = 0, argc = 0, i, idx, len; SABLOTLS_FETCH(); if (userData == NULL) { SABLOT_FREE_ERROR_HANDLE(SABLOTG_HANDLE); SABLOTG(errors_start).next = NULL; SABLOTG(errors) = &SABLOTG(errors_start); errors = SABLOTG(errors); errorHandler = SABLOTG(errorHandler); } else { handle = (php_sablot *)userData; SABLOT_FREE_ERROR_HANDLE(*handle); handle->errors_start.next = NULL; handle->errors = &handle->errors_start; errors = handle->errors; errorHandler = handle->errorHandler; isAdvanced = 1; } while (fields && *fields) { errors->next = (php_sablot_error *)emalloc(sizeof(php_sablot_error)); errors = errors->next; sep = strchr(fields[0], ':'); idx = sep - fields[0]; len = strlen(fields[0]); errors->key = emalloc(idx+1); errors->value = emalloc((len - idx) + 1); memcpy(errors->key, fields[0], idx); memcpy(errors->value, fields[0] + idx + 1, len - idx - 1); errors->key[idx] = '\0'; errors->value[len - idx - 1] = '\0'; errors->next = NULL; fields++; } if (isAdvanced) handle->last_errno = (int) code; else SABLOTG(last_errno) = (int) code; if (errorHandler) { zval *retval; ELS_FETCH(); MAKE_STD_ZVAL(retval); argc = isAdvanced ? 4 : 3; argv = emalloc(argc * sizeof(zval *)); MAKE_STD_ZVAL(argv[0]); MAKE_STD_ZVAL(argv[1]); MAKE_STD_ZVAL(argv[2]); if (isAdvanced) { MAKE_STD_ZVAL(argv[3]); ZVAL_RESOURCE(argv[0], handle->index); ZVAL_LONG(argv[1], code); ZVAL_LONG(argv[2], level); array_init(argv[3]); errors = handle->errors_start.next; while (errors) { add_assoc_string(argv[3], errors->key, errors->value, 1); errors = errors->next; } } else { ZVAL_LONG(argv[0], code); ZVAL_LONG(argv[1], level); array_init(argv[2]); errors = SABLOTG(errors_start).next; while (errors) { add_assoc_string(argv[2], errors->key, errors->value, 1); errors = errors->next; } } if (call_user_function(EG(function_table), NULL, errorHandler, retval, argc, argv) == FAILURE) { php_error(E_WARNING, "Sorry, couldn't call %s error handler", Z_STRVAL_P(errorHandler)); } zval_dtor(retval); efree(retval); for (i = 1; i < argc; i++) { zval_del_ref(&argv[i]); } } else { if (level == MH_LEVEL_CRITICAL || level == MH_LEVEL_ERROR || level == MH_LEVEL_WARN) { _php_sablot_standard_error(errors, isAdvanced ? handle->errors_start : SABLOTG(errors_start), code, level); } } return(0); } /* }}} */ static void _php_sablot_standard_error(php_sablot_error *errors, php_sablot_error errors_start, int code, int level) { char *errstr = NULL; SABLOTLS_FETCH(); errors = errors_start.next; while (errors) { if (strcmp(errors->key, "msg") == 0) { errstr = estrdup(errors->value); break; } errors = errors->next; } switch (level) { case MH_LEVEL_CRITICAL: case MH_LEVEL_ERROR: php_error(E_ERROR, errstr); break; case MH_LEVEL_WARN: php_error(E_WARNING, errstr); break; } efree(errstr); } /* }}} */ /* {{{ Sablotron Scheme Handler functions */ static int _php_sablot_sh_getAll(void *userData, SablotHandle p, const char *scheme, const char *rest, char **buffer, int *byteCount) { php_sablot *handle = (php_sablot *) userData; ELS_FETCH(); if (handle->getAllHandler) { zval *retval, *argv[4]; int idx, argc = 4; MAKE_STD_ZVAL(retval); argv[0] = _php_sablot_resource_zval(handle->index); argv[1] = _php_sablot_string_zval(scheme); argv[2] = _php_sablot_string_zval(rest); argv[3] = _php_sablot_string_zval(""); if (call_user_function(EG(function_table), NULL, handle->getAllHandler, retval, argc, argv) == FAILURE) { php_error(E_WARNING, "Sorry couldn't call function, %s, with handler of type %s", handle->getAllHandler->value.str.val, "Scheme GetALL"); } zval_dtor(retval); efree(retval); *buffer = Z_STRVAL_P(argv[3]); *byteCount = Z_STRLEN_P(argv[3]); for (idx = 1; idx < 3; idx++) { zval_del_ref(&(argv[idx])); } } return(0); } static int _php_sablot_sh_freeMemory(void *userData, SablotHandle p, char *buffer) { /** Not implemented **/ } static int _php_sablot_sh_open(void *userData, SablotHandle p, const char *scheme, const char *rest, int *handle) { /** * Not implemented */ } static int _php_sablot_sh_get(void *userData, SablotHandle p, int handle, char *buffer, int *byteCount) { /** * Not implemented */ } static int _php_sablot_sh_put(void *userData, SablotHandle p, int handle, const char *buffer, int *byteCount) { /** * Not implemented */ } static int _php_sablot_sh_close(void *userData, SablotHandle p, int handle) { /** * Not implemented */ } /* }}} */ /* {{{ List Handling functions */ /* {{{ _php_sablot_free_processor() Free a Sablot handle */ static void _php_sablot_free_processor(zend_rsrc_list_entry *rsrc) { php_sablot *handle = (php_sablot *)rsrc->ptr; if (handle->p) { SablotUnregHandler(handle->p, HLR_MESSAGE, NULL, NULL); SablotUnregHandler(handle->p, HLR_SAX, NULL, NULL); SablotUnregHandler(handle->p, HLR_SCHEME, NULL, NULL); SablotDestroyProcessor(handle->p); } FUNCH_FREE(handle->startDocHandler); FUNCH_FREE(handle->startElementHandler); FUNCH_FREE(handle->endElementHandler); FUNCH_FREE(handle->startNamespaceHandler); FUNCH_FREE(handle->endNamespaceHandler); FUNCH_FREE(handle->commentHandler); FUNCH_FREE(handle->PIHandler); FUNCH_FREE(handle->charactersHandler); FUNCH_FREE(handle->endDocHandler); FUNCH_FREE(handle->getAllHandler); SABLOT_FREE_ERROR_HANDLE(*handle); efree(handle); } /* }}} */ /* }}} */ /* {{{ Conversion Helper functions */ /* {{{ _php_sablot_zval_char() Translates a PHP array to a Sablotron character array */ static void _php_sablot_ht_char(HashTable *php, char **sablot) { zval **value; char *string_key = NULL; ulong num_key; int i = 0; for (zend_hash_internal_pointer_reset(php); zend_hash_get_current_data(php, (void **)&value) == SUCCESS; zend_hash_move_forward(php)) { SEPARATE_ZVAL(value); convert_to_string_ex(value); switch (zend_hash_get_current_key(php, &string_key, &num_key, 1)) { case HASH_KEY_IS_LONG: sablot[i++] = Z_STRVAL_PP(value); break; case HASH_KEY_IS_STRING: sablot[i++] = string_key; sablot[i++] = Z_STRVAL_PP(value); break; } } sablot[i++] = NULL; } /* {{{ _php_sablot_string_zval() Converts a Sablotron string to a zval */ static zval *_php_sablot_string_zval(const char *str) { zval *ret; int len = strlen(str); MAKE_STD_ZVAL(ret); Z_TYPE_P(ret) = IS_STRING; Z_STRLEN_P(ret) = len; Z_STRVAL_P(ret) = estrndup(str, len); return(ret); } /* }}} */ /* {{{ _php_sablot_resource_zval() Converts a long identifier to a resource id */ static zval *_php_sablot_resource_zval(long value) { zval *ret; MAKE_STD_ZVAL(ret); Z_TYPE_P(ret) = IS_RESOURCE; Z_LVAL_P(ret) = value; zend_list_addref(value); return(ret); } /* }}} */ /* }}} */ /* }}} */ #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: */