1/* 2 +----------------------------------------------------------------------+ 3 | PHP Version 5 | 4 +----------------------------------------------------------------------+ 5 | Copyright (c) 1997-2013 The PHP Group | 6 +----------------------------------------------------------------------+ 7 | This source file is subject to version 3.01 of the PHP license, | 8 | that is bundled with this package in the file LICENSE, and is | 9 | available through the world-wide-web at the following url: | 10 | http://www.php.net/license/3_01.txt | 11 | If you did not receive a copy of the PHP license and are unable to | 12 | obtain it through the world-wide-web, please send a note to | 13 | license@php.net so we can mail you a copy immediately. | 14 +----------------------------------------------------------------------+ 15 | Authors: Stig S�ther Bakken <ssb@php.net> | 16 | Thies C. Arntzen <thies@thieso.net> | 17 | Sterling Hughes <sterling@php.net> | 18 +----------------------------------------------------------------------+ 19 */ 20 21/* $Id$ */ 22 23#define IS_EXT_MODULE 24 25#ifdef HAVE_CONFIG_H 26#include "config.h" 27#endif 28 29#include "php.h" 30 31#define PHP_XML_INTERNAL 32#include "zend_variables.h" 33#include "ext/standard/php_string.h" 34#include "ext/standard/info.h" 35#include "ext/standard/html.h" 36 37#if HAVE_XML 38 39#include "php_xml.h" 40# include "ext/standard/head.h" 41#ifdef LIBXML_EXPAT_COMPAT 42#include "ext/libxml/php_libxml.h" 43#endif 44 45/* Short-term TODO list: 46 * - Implement XML_ExternalEntityParserCreate() 47 * - XML_SetCommentHandler 48 * - XML_SetCdataSectionHandler 49 * - XML_SetParamEntityParsing 50 */ 51 52/* Long-term TODO list: 53 * - Fix the expat library so you can install your own memory manager 54 * functions 55 */ 56 57/* Known bugs: 58 * - Weird things happen with <![CDATA[]]> sections. 59 */ 60 61ZEND_DECLARE_MODULE_GLOBALS(xml) 62 63/* {{{ dynamically loadable module stuff */ 64#ifdef COMPILE_DL_XML 65ZEND_GET_MODULE(xml) 66#endif /* COMPILE_DL_XML */ 67/* }}} */ 68 69/* {{{ function prototypes */ 70PHP_MINIT_FUNCTION(xml); 71PHP_MINFO_FUNCTION(xml); 72static PHP_GINIT_FUNCTION(xml); 73 74static void xml_parser_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC); 75static void xml_set_handler(zval **, zval **); 76inline static unsigned short xml_encode_iso_8859_1(unsigned char); 77inline static char xml_decode_iso_8859_1(unsigned short); 78inline static unsigned short xml_encode_us_ascii(unsigned char); 79inline static char xml_decode_us_ascii(unsigned short); 80static zval *xml_call_handler(xml_parser *, zval *, zend_function *, int, zval **); 81static zval *_xml_xmlchar_zval(const XML_Char *, int, const XML_Char *); 82static int _xml_xmlcharlen(const XML_Char *); 83static void _xml_add_to_info(xml_parser *parser,char *name); 84inline static char *_xml_decode_tag(xml_parser *parser, const char *tag); 85 86void _xml_startElementHandler(void *, const XML_Char *, const XML_Char **); 87void _xml_endElementHandler(void *, const XML_Char *); 88void _xml_characterDataHandler(void *, const XML_Char *, int); 89void _xml_processingInstructionHandler(void *, const XML_Char *, const XML_Char *); 90void _xml_defaultHandler(void *, const XML_Char *, int); 91void _xml_unparsedEntityDeclHandler(void *, const XML_Char *, const XML_Char *, const XML_Char *, const XML_Char *, const XML_Char *); 92void _xml_notationDeclHandler(void *, const XML_Char *, const XML_Char *, const XML_Char *, const XML_Char *); 93int _xml_externalEntityRefHandler(XML_Parser, const XML_Char *, const XML_Char *, const XML_Char *, const XML_Char *); 94 95void _xml_startNamespaceDeclHandler(void *, const XML_Char *, const XML_Char *); 96void _xml_endNamespaceDeclHandler(void *, const XML_Char *); 97/* }}} */ 98 99/* {{{ extension definition structures */ 100ZEND_BEGIN_ARG_INFO_EX(arginfo_xml_parser_create, 0, 0, 0) 101 ZEND_ARG_INFO(0, encoding) 102ZEND_END_ARG_INFO() 103 104ZEND_BEGIN_ARG_INFO_EX(arginfo_xml_parser_create_ns, 0, 0, 0) 105 ZEND_ARG_INFO(0, encoding) 106 ZEND_ARG_INFO(0, sep) 107ZEND_END_ARG_INFO() 108 109ZEND_BEGIN_ARG_INFO_EX(arginfo_xml_set_object, 0, 0, 2) 110 ZEND_ARG_INFO(0, parser) 111 ZEND_ARG_INFO(1, obj) 112ZEND_END_ARG_INFO() 113 114ZEND_BEGIN_ARG_INFO_EX(arginfo_xml_set_element_handler, 0, 0, 3) 115 ZEND_ARG_INFO(0, parser) 116 ZEND_ARG_INFO(0, shdl) 117 ZEND_ARG_INFO(0, ehdl) 118ZEND_END_ARG_INFO() 119 120ZEND_BEGIN_ARG_INFO_EX(arginfo_xml_set_character_data_handler, 0, 0, 2) 121 ZEND_ARG_INFO(0, parser) 122 ZEND_ARG_INFO(0, hdl) 123ZEND_END_ARG_INFO() 124 125ZEND_BEGIN_ARG_INFO_EX(arginfo_xml_set_processing_instruction_handler, 0, 0, 2) 126 ZEND_ARG_INFO(0, parser) 127 ZEND_ARG_INFO(0, hdl) 128ZEND_END_ARG_INFO() 129 130ZEND_BEGIN_ARG_INFO_EX(arginfo_xml_set_default_handler, 0, 0, 2) 131 ZEND_ARG_INFO(0, parser) 132 ZEND_ARG_INFO(0, hdl) 133ZEND_END_ARG_INFO() 134 135ZEND_BEGIN_ARG_INFO_EX(arginfo_xml_set_unparsed_entity_decl_handler, 0, 0, 2) 136 ZEND_ARG_INFO(0, parser) 137 ZEND_ARG_INFO(0, hdl) 138ZEND_END_ARG_INFO() 139 140ZEND_BEGIN_ARG_INFO_EX(arginfo_xml_set_notation_decl_handler, 0, 0, 2) 141 ZEND_ARG_INFO(0, parser) 142 ZEND_ARG_INFO(0, hdl) 143ZEND_END_ARG_INFO() 144 145ZEND_BEGIN_ARG_INFO_EX(arginfo_xml_set_external_entity_ref_handler, 0, 0, 2) 146 ZEND_ARG_INFO(0, parser) 147 ZEND_ARG_INFO(0, hdl) 148ZEND_END_ARG_INFO() 149 150ZEND_BEGIN_ARG_INFO_EX(arginfo_xml_set_start_namespace_decl_handler, 0, 0, 2) 151 ZEND_ARG_INFO(0, parser) 152 ZEND_ARG_INFO(0, hdl) 153ZEND_END_ARG_INFO() 154 155ZEND_BEGIN_ARG_INFO_EX(arginfo_xml_set_end_namespace_decl_handler, 0, 0, 2) 156 ZEND_ARG_INFO(0, parser) 157 ZEND_ARG_INFO(0, hdl) 158ZEND_END_ARG_INFO() 159 160ZEND_BEGIN_ARG_INFO_EX(arginfo_xml_parse, 0, 0, 2) 161 ZEND_ARG_INFO(0, parser) 162 ZEND_ARG_INFO(0, data) 163 ZEND_ARG_INFO(0, isfinal) 164ZEND_END_ARG_INFO() 165 166ZEND_BEGIN_ARG_INFO_EX(arginfo_xml_parse_into_struct, 0, 0, 3) 167 ZEND_ARG_INFO(0, parser) 168 ZEND_ARG_INFO(0, data) 169 ZEND_ARG_INFO(1, values) 170 ZEND_ARG_INFO(1, index) 171ZEND_END_ARG_INFO() 172 173ZEND_BEGIN_ARG_INFO_EX(arginfo_xml_get_error_code, 0, 0, 1) 174 ZEND_ARG_INFO(0, parser) 175ZEND_END_ARG_INFO() 176 177ZEND_BEGIN_ARG_INFO_EX(arginfo_xml_error_string, 0, 0, 1) 178 ZEND_ARG_INFO(0, code) 179ZEND_END_ARG_INFO() 180 181ZEND_BEGIN_ARG_INFO_EX(arginfo_xml_get_current_line_number, 0, 0, 1) 182 ZEND_ARG_INFO(0, parser) 183ZEND_END_ARG_INFO() 184 185ZEND_BEGIN_ARG_INFO_EX(arginfo_xml_get_current_column_number, 0, 0, 1) 186 ZEND_ARG_INFO(0, parser) 187ZEND_END_ARG_INFO() 188 189ZEND_BEGIN_ARG_INFO_EX(arginfo_xml_get_current_byte_index, 0, 0, 1) 190 ZEND_ARG_INFO(0, parser) 191ZEND_END_ARG_INFO() 192 193ZEND_BEGIN_ARG_INFO_EX(arginfo_xml_parser_free, 0, 0, 1) 194 ZEND_ARG_INFO(0, parser) 195ZEND_END_ARG_INFO() 196 197ZEND_BEGIN_ARG_INFO_EX(arginfo_xml_parser_set_option, 0, 0, 3) 198 ZEND_ARG_INFO(0, parser) 199 ZEND_ARG_INFO(0, option) 200 ZEND_ARG_INFO(0, value) 201ZEND_END_ARG_INFO() 202 203ZEND_BEGIN_ARG_INFO_EX(arginfo_xml_parser_get_option, 0, 0, 2) 204 ZEND_ARG_INFO(0, parser) 205 ZEND_ARG_INFO(0, option) 206ZEND_END_ARG_INFO() 207 208ZEND_BEGIN_ARG_INFO_EX(arginfo_utf8_encode, 0, 0, 1) 209 ZEND_ARG_INFO(0, data) 210ZEND_END_ARG_INFO() 211 212ZEND_BEGIN_ARG_INFO_EX(arginfo_utf8_decode, 0, 0, 1) 213 ZEND_ARG_INFO(0, data) 214ZEND_END_ARG_INFO() 215 216const zend_function_entry xml_functions[] = { 217 PHP_FE(xml_parser_create, arginfo_xml_parser_create) 218 PHP_FE(xml_parser_create_ns, arginfo_xml_parser_create_ns) 219 PHP_FE(xml_set_object, arginfo_xml_set_object) 220 PHP_FE(xml_set_element_handler, arginfo_xml_set_element_handler) 221 PHP_FE(xml_set_character_data_handler, arginfo_xml_set_character_data_handler) 222 PHP_FE(xml_set_processing_instruction_handler, arginfo_xml_set_processing_instruction_handler) 223 PHP_FE(xml_set_default_handler, arginfo_xml_set_default_handler) 224 PHP_FE(xml_set_unparsed_entity_decl_handler,arginfo_xml_set_unparsed_entity_decl_handler) 225 PHP_FE(xml_set_notation_decl_handler, arginfo_xml_set_notation_decl_handler) 226 PHP_FE(xml_set_external_entity_ref_handler, arginfo_xml_set_external_entity_ref_handler) 227 PHP_FE(xml_set_start_namespace_decl_handler,arginfo_xml_set_start_namespace_decl_handler) 228 PHP_FE(xml_set_end_namespace_decl_handler, arginfo_xml_set_end_namespace_decl_handler) 229 PHP_FE(xml_parse, arginfo_xml_parse) 230 PHP_FE(xml_parse_into_struct, arginfo_xml_parse_into_struct) 231 PHP_FE(xml_get_error_code, arginfo_xml_get_error_code) 232 PHP_FE(xml_error_string, arginfo_xml_error_string) 233 PHP_FE(xml_get_current_line_number, arginfo_xml_get_current_line_number) 234 PHP_FE(xml_get_current_column_number, arginfo_xml_get_current_column_number) 235 PHP_FE(xml_get_current_byte_index, arginfo_xml_get_current_byte_index) 236 PHP_FE(xml_parser_free, arginfo_xml_parser_free) 237 PHP_FE(xml_parser_set_option, arginfo_xml_parser_set_option) 238 PHP_FE(xml_parser_get_option, arginfo_xml_parser_get_option) 239 PHP_FE(utf8_encode, arginfo_utf8_encode) 240 PHP_FE(utf8_decode, arginfo_utf8_decode) 241 PHP_FE_END 242}; 243 244#ifdef LIBXML_EXPAT_COMPAT 245static const zend_module_dep xml_deps[] = { 246 ZEND_MOD_REQUIRED("libxml") 247 ZEND_MOD_END 248}; 249#endif 250 251zend_module_entry xml_module_entry = { 252#ifdef LIBXML_EXPAT_COMPAT 253 STANDARD_MODULE_HEADER_EX, NULL, 254 xml_deps, 255#else 256 STANDARD_MODULE_HEADER, 257#endif 258 "xml", /* extension name */ 259 xml_functions, /* extension function list */ 260 PHP_MINIT(xml), /* extension-wide startup function */ 261 NULL, /* extension-wide shutdown function */ 262 NULL, /* per-request startup function */ 263 NULL, /* per-request shutdown function */ 264 PHP_MINFO(xml), /* information function */ 265 NO_VERSION_YET, 266 PHP_MODULE_GLOBALS(xml), /* globals descriptor */ 267 PHP_GINIT(xml), /* globals ctor */ 268 NULL, /* globals dtor */ 269 NULL, /* post deactivate */ 270 STANDARD_MODULE_PROPERTIES_EX 271}; 272 273/* All the encoding functions are set to NULL right now, since all 274 * the encoding is currently done internally by expat/xmltok. 275 */ 276xml_encoding xml_encodings[] = { 277 { "ISO-8859-1", xml_decode_iso_8859_1, xml_encode_iso_8859_1 }, 278 { "US-ASCII", xml_decode_us_ascii, xml_encode_us_ascii }, 279 { "UTF-8", NULL, NULL }, 280 { NULL, NULL, NULL } 281}; 282 283static XML_Memory_Handling_Suite php_xml_mem_hdlrs; 284 285/* True globals, no need for thread safety */ 286static int le_xml_parser; 287 288/* }}} */ 289 290/* {{{ startup, shutdown and info functions */ 291static PHP_GINIT_FUNCTION(xml) 292{ 293 xml_globals->default_encoding = "UTF-8"; 294} 295 296static void *php_xml_malloc_wrapper(size_t sz) 297{ 298 return emalloc(sz); 299} 300 301static void *php_xml_realloc_wrapper(void *ptr, size_t sz) 302{ 303 return erealloc(ptr, sz); 304} 305 306static void php_xml_free_wrapper(void *ptr) 307{ 308 if (ptr != NULL) { 309 efree(ptr); 310 } 311} 312 313PHP_MINIT_FUNCTION(xml) 314{ 315 le_xml_parser = zend_register_list_destructors_ex(xml_parser_dtor, NULL, "xml", module_number); 316 317 REGISTER_LONG_CONSTANT("XML_ERROR_NONE", XML_ERROR_NONE, CONST_CS|CONST_PERSISTENT); 318 REGISTER_LONG_CONSTANT("XML_ERROR_NO_MEMORY", XML_ERROR_NO_MEMORY, CONST_CS|CONST_PERSISTENT); 319 REGISTER_LONG_CONSTANT("XML_ERROR_SYNTAX", XML_ERROR_SYNTAX, CONST_CS|CONST_PERSISTENT); 320 REGISTER_LONG_CONSTANT("XML_ERROR_NO_ELEMENTS", XML_ERROR_NO_ELEMENTS, CONST_CS|CONST_PERSISTENT); 321 REGISTER_LONG_CONSTANT("XML_ERROR_INVALID_TOKEN", XML_ERROR_INVALID_TOKEN, CONST_CS|CONST_PERSISTENT); 322 REGISTER_LONG_CONSTANT("XML_ERROR_UNCLOSED_TOKEN", XML_ERROR_UNCLOSED_TOKEN, CONST_CS|CONST_PERSISTENT); 323 REGISTER_LONG_CONSTANT("XML_ERROR_PARTIAL_CHAR", XML_ERROR_PARTIAL_CHAR, CONST_CS|CONST_PERSISTENT); 324 REGISTER_LONG_CONSTANT("XML_ERROR_TAG_MISMATCH", XML_ERROR_TAG_MISMATCH, CONST_CS|CONST_PERSISTENT); 325 REGISTER_LONG_CONSTANT("XML_ERROR_DUPLICATE_ATTRIBUTE", XML_ERROR_DUPLICATE_ATTRIBUTE, CONST_CS|CONST_PERSISTENT); 326 REGISTER_LONG_CONSTANT("XML_ERROR_JUNK_AFTER_DOC_ELEMENT", XML_ERROR_JUNK_AFTER_DOC_ELEMENT, CONST_CS|CONST_PERSISTENT); 327 REGISTER_LONG_CONSTANT("XML_ERROR_PARAM_ENTITY_REF", XML_ERROR_PARAM_ENTITY_REF, CONST_CS|CONST_PERSISTENT); 328 REGISTER_LONG_CONSTANT("XML_ERROR_UNDEFINED_ENTITY", XML_ERROR_UNDEFINED_ENTITY, CONST_CS|CONST_PERSISTENT); 329 REGISTER_LONG_CONSTANT("XML_ERROR_RECURSIVE_ENTITY_REF", XML_ERROR_RECURSIVE_ENTITY_REF, CONST_CS|CONST_PERSISTENT); 330 REGISTER_LONG_CONSTANT("XML_ERROR_ASYNC_ENTITY", XML_ERROR_ASYNC_ENTITY, CONST_CS|CONST_PERSISTENT); 331 REGISTER_LONG_CONSTANT("XML_ERROR_BAD_CHAR_REF", XML_ERROR_BAD_CHAR_REF, CONST_CS|CONST_PERSISTENT); 332 REGISTER_LONG_CONSTANT("XML_ERROR_BINARY_ENTITY_REF", XML_ERROR_BINARY_ENTITY_REF, CONST_CS|CONST_PERSISTENT); 333 REGISTER_LONG_CONSTANT("XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF", XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF, CONST_CS|CONST_PERSISTENT); 334 REGISTER_LONG_CONSTANT("XML_ERROR_MISPLACED_XML_PI", XML_ERROR_MISPLACED_XML_PI, CONST_CS|CONST_PERSISTENT); 335 REGISTER_LONG_CONSTANT("XML_ERROR_UNKNOWN_ENCODING", XML_ERROR_UNKNOWN_ENCODING, CONST_CS|CONST_PERSISTENT); 336 REGISTER_LONG_CONSTANT("XML_ERROR_INCORRECT_ENCODING", XML_ERROR_INCORRECT_ENCODING, CONST_CS|CONST_PERSISTENT); 337 REGISTER_LONG_CONSTANT("XML_ERROR_UNCLOSED_CDATA_SECTION", XML_ERROR_UNCLOSED_CDATA_SECTION, CONST_CS|CONST_PERSISTENT); 338 REGISTER_LONG_CONSTANT("XML_ERROR_EXTERNAL_ENTITY_HANDLING", XML_ERROR_EXTERNAL_ENTITY_HANDLING, CONST_CS|CONST_PERSISTENT); 339 340 REGISTER_LONG_CONSTANT("XML_OPTION_CASE_FOLDING", PHP_XML_OPTION_CASE_FOLDING, CONST_CS|CONST_PERSISTENT); 341 REGISTER_LONG_CONSTANT("XML_OPTION_TARGET_ENCODING", PHP_XML_OPTION_TARGET_ENCODING, CONST_CS|CONST_PERSISTENT); 342 REGISTER_LONG_CONSTANT("XML_OPTION_SKIP_TAGSTART", PHP_XML_OPTION_SKIP_TAGSTART, CONST_CS|CONST_PERSISTENT); 343 REGISTER_LONG_CONSTANT("XML_OPTION_SKIP_WHITE", PHP_XML_OPTION_SKIP_WHITE, CONST_CS|CONST_PERSISTENT); 344 345 /* this object should not be pre-initialised at compile time, 346 as the order of members may vary */ 347 348 php_xml_mem_hdlrs.malloc_fcn = php_xml_malloc_wrapper; 349 php_xml_mem_hdlrs.realloc_fcn = php_xml_realloc_wrapper; 350 php_xml_mem_hdlrs.free_fcn = php_xml_free_wrapper; 351 352#ifdef LIBXML_EXPAT_COMPAT 353 REGISTER_STRING_CONSTANT("XML_SAX_IMPL", "libxml", CONST_CS|CONST_PERSISTENT); 354#else 355 REGISTER_STRING_CONSTANT("XML_SAX_IMPL", "expat", CONST_CS|CONST_PERSISTENT); 356#endif 357 358 return SUCCESS; 359} 360 361PHP_MINFO_FUNCTION(xml) 362{ 363 php_info_print_table_start(); 364 php_info_print_table_row(2, "XML Support", "active"); 365 php_info_print_table_row(2, "XML Namespace Support", "active"); 366#if defined(LIBXML_DOTTED_VERSION) && defined(LIBXML_EXPAT_COMPAT) 367 php_info_print_table_row(2, "libxml2 Version", LIBXML_DOTTED_VERSION); 368#else 369 php_info_print_table_row(2, "EXPAT Version", XML_ExpatVersion()); 370#endif 371 php_info_print_table_end(); 372} 373/* }}} */ 374 375/* {{{ extension-internal functions */ 376static zval *_xml_resource_zval(long value) 377{ 378 zval *ret; 379 TSRMLS_FETCH(); 380 381 MAKE_STD_ZVAL(ret); 382 383 Z_TYPE_P(ret) = IS_RESOURCE; 384 Z_LVAL_P(ret) = value; 385 386 zend_list_addref(value); 387 388 return ret; 389} 390 391static zval *_xml_string_zval(const char *str) 392{ 393 zval *ret; 394 int len = strlen(str); 395 MAKE_STD_ZVAL(ret); 396 397 Z_TYPE_P(ret) = IS_STRING; 398 Z_STRLEN_P(ret) = len; 399 Z_STRVAL_P(ret) = estrndup(str, len); 400 return ret; 401} 402 403static zval *_xml_xmlchar_zval(const XML_Char *s, int len, const XML_Char *encoding) 404{ 405 zval *ret; 406 MAKE_STD_ZVAL(ret); 407 408 if (s == NULL) { 409 ZVAL_FALSE(ret); 410 return ret; 411 } 412 if (len == 0) { 413 len = _xml_xmlcharlen(s); 414 } 415 Z_TYPE_P(ret) = IS_STRING; 416 Z_STRVAL_P(ret) = xml_utf8_decode(s, len, &Z_STRLEN_P(ret), encoding); 417 return ret; 418} 419/* }}} */ 420 421/* {{{ xml_parser_dtor() */ 422static void xml_parser_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) 423{ 424 xml_parser *parser = (xml_parser *)rsrc->ptr; 425 426 if (parser->parser) { 427 XML_ParserFree(parser->parser); 428 } 429 if (parser->ltags) { 430 int inx; 431 for (inx = 0; inx < parser->level; inx++) 432 efree(parser->ltags[ inx ]); 433 efree(parser->ltags); 434 } 435 if (parser->startElementHandler) { 436 zval_ptr_dtor(&parser->startElementHandler); 437 } 438 if (parser->endElementHandler) { 439 zval_ptr_dtor(&parser->endElementHandler); 440 } 441 if (parser->characterDataHandler) { 442 zval_ptr_dtor(&parser->characterDataHandler); 443 } 444 if (parser->processingInstructionHandler) { 445 zval_ptr_dtor(&parser->processingInstructionHandler); 446 } 447 if (parser->defaultHandler) { 448 zval_ptr_dtor(&parser->defaultHandler); 449 } 450 if (parser->unparsedEntityDeclHandler) { 451 zval_ptr_dtor(&parser->unparsedEntityDeclHandler); 452 } 453 if (parser->notationDeclHandler) { 454 zval_ptr_dtor(&parser->notationDeclHandler); 455 } 456 if (parser->externalEntityRefHandler) { 457 zval_ptr_dtor(&parser->externalEntityRefHandler); 458 } 459 if (parser->unknownEncodingHandler) { 460 zval_ptr_dtor(&parser->unknownEncodingHandler); 461 } 462 if (parser->startNamespaceDeclHandler) { 463 zval_ptr_dtor(&parser->startNamespaceDeclHandler); 464 } 465 if (parser->endNamespaceDeclHandler) { 466 zval_ptr_dtor(&parser->endNamespaceDeclHandler); 467 } 468 if (parser->baseURI) { 469 efree(parser->baseURI); 470 } 471 if (parser->object) { 472 zval_ptr_dtor(&parser->object); 473 } 474 475 efree(parser); 476} 477/* }}} */ 478 479/* {{{ xml_set_handler() */ 480static void xml_set_handler(zval **handler, zval **data) 481{ 482 /* If we have already a handler, release it */ 483 if (*handler) { 484 zval_ptr_dtor(handler); 485 } 486 487 /* IS_ARRAY might indicate that we're using array($obj, 'method') syntax */ 488 if (Z_TYPE_PP(data) != IS_ARRAY && Z_TYPE_PP(data) != IS_OBJECT) { 489 490 convert_to_string_ex(data); 491 if (Z_STRLEN_PP(data) == 0) { 492 *handler = NULL; 493 return; 494 } 495 } 496 497 zval_add_ref(data); 498 499 *handler = *data; 500} 501/* }}} */ 502 503/* {{{ xml_call_handler() */ 504static zval *xml_call_handler(xml_parser *parser, zval *handler, zend_function *function_ptr, int argc, zval **argv) 505{ 506 int i; 507 TSRMLS_FETCH(); 508 509 if (parser && handler && !EG(exception)) { 510 zval ***args; 511 zval *retval; 512 int result; 513 zend_fcall_info fci; 514 515 args = safe_emalloc(sizeof(zval **), argc, 0); 516 for (i = 0; i < argc; i++) { 517 args[i] = &argv[i]; 518 } 519 520 fci.size = sizeof(fci); 521 fci.function_table = EG(function_table); 522 fci.function_name = handler; 523 fci.symbol_table = NULL; 524 fci.object_ptr = parser->object; 525 fci.retval_ptr_ptr = &retval; 526 fci.param_count = argc; 527 fci.params = args; 528 fci.no_separation = 0; 529 /*fci.function_handler_cache = &function_ptr;*/ 530 531 result = zend_call_function(&fci, NULL TSRMLS_CC); 532 if (result == FAILURE) { 533 zval **method; 534 zval **obj; 535 536 if (Z_TYPE_P(handler) == IS_STRING) { 537 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to call handler %s()", Z_STRVAL_P(handler)); 538 } else if (zend_hash_index_find(Z_ARRVAL_P(handler), 0, (void **) &obj) == SUCCESS && 539 zend_hash_index_find(Z_ARRVAL_P(handler), 1, (void **) &method) == SUCCESS && 540 Z_TYPE_PP(obj) == IS_OBJECT && 541 Z_TYPE_PP(method) == IS_STRING) { 542 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to call handler %s::%s()", Z_OBJCE_PP(obj)->name, Z_STRVAL_PP(method)); 543 } else 544 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to call handler"); 545 } 546 547 for (i = 0; i < argc; i++) { 548 zval_ptr_dtor(args[i]); 549 } 550 efree(args); 551 552 if (result == FAILURE) { 553 return NULL; 554 } else { 555 return EG(exception) ? NULL : retval; 556 } 557 } else { 558 for (i = 0; i < argc; i++) { 559 zval_ptr_dtor(&argv[i]); 560 } 561 return NULL; 562 } 563} 564/* }}} */ 565 566/* {{{ xml_encode_iso_8859_1() */ 567inline static unsigned short xml_encode_iso_8859_1(unsigned char c) 568{ 569 return (unsigned short)c; 570} 571/* }}} */ 572 573/* {{{ xml_decode_iso_8859_1() */ 574inline static char xml_decode_iso_8859_1(unsigned short c) 575{ 576 return (char)(c > 0xff ? '?' : c); 577} 578/* }}} */ 579 580/* {{{ xml_encode_us_ascii() */ 581inline static unsigned short xml_encode_us_ascii(unsigned char c) 582{ 583 return (unsigned short)c; 584} 585/* }}} */ 586 587/* {{{ xml_decode_us_ascii() */ 588inline static char xml_decode_us_ascii(unsigned short c) 589{ 590 return (char)(c > 0x7f ? '?' : c); 591} 592/* }}} */ 593 594/* {{{ xml_get_encoding() */ 595static xml_encoding *xml_get_encoding(const XML_Char *name) 596{ 597 xml_encoding *enc = &xml_encodings[0]; 598 599 while (enc && enc->name) { 600 if (strcasecmp(name, enc->name) == 0) { 601 return enc; 602 } 603 enc++; 604 } 605 return NULL; 606} 607/* }}} */ 608 609/* {{{ xml_utf8_encode */ 610PHPAPI char *xml_utf8_encode(const char *s, int len, int *newlen, const XML_Char *encoding) 611{ 612 int pos = len; 613 char *newbuf; 614 unsigned int c; 615 unsigned short (*encoder)(unsigned char) = NULL; 616 xml_encoding *enc = xml_get_encoding(encoding); 617 618 *newlen = 0; 619 if (enc) { 620 encoder = enc->encoding_function; 621 } else { 622 /* If the target encoding was unknown, fail */ 623 return NULL; 624 } 625 if (encoder == NULL) { 626 /* If no encoder function was specified, return the data as-is. 627 */ 628 newbuf = emalloc(len + 1); 629 memcpy(newbuf, s, len); 630 *newlen = len; 631 newbuf[*newlen] = '\0'; 632 return newbuf; 633 } 634 /* This is the theoretical max (will never get beyond len * 2 as long 635 * as we are converting from single-byte characters, though) */ 636 newbuf = safe_emalloc(len, 4, 1); 637 while (pos > 0) { 638 c = encoder ? encoder((unsigned char)(*s)) : (unsigned short)(*s); 639 if (c < 0x80) { 640 newbuf[(*newlen)++] = (char) c; 641 } else if (c < 0x800) { 642 newbuf[(*newlen)++] = (0xc0 | (c >> 6)); 643 newbuf[(*newlen)++] = (0x80 | (c & 0x3f)); 644 } else if (c < 0x10000) { 645 newbuf[(*newlen)++] = (0xe0 | (c >> 12)); 646 newbuf[(*newlen)++] = (0xc0 | ((c >> 6) & 0x3f)); 647 newbuf[(*newlen)++] = (0x80 | (c & 0x3f)); 648 } else if (c < 0x200000) { 649 newbuf[(*newlen)++] = (0xf0 | (c >> 18)); 650 newbuf[(*newlen)++] = (0xe0 | ((c >> 12) & 0x3f)); 651 newbuf[(*newlen)++] = (0xc0 | ((c >> 6) & 0x3f)); 652 newbuf[(*newlen)++] = (0x80 | (c & 0x3f)); 653 } 654 pos--; 655 s++; 656 } 657 newbuf[*newlen] = 0; 658 newbuf = erealloc(newbuf, (*newlen)+1); 659 return newbuf; 660} 661/* }}} */ 662 663/* {{{ xml_utf8_decode */ 664PHPAPI char *xml_utf8_decode(const XML_Char *s, int len, int *newlen, const XML_Char *encoding) 665{ 666 size_t pos = 0; 667 char *newbuf = emalloc(len + 1); 668 unsigned int c; 669 char (*decoder)(unsigned short) = NULL; 670 xml_encoding *enc = xml_get_encoding(encoding); 671 672 *newlen = 0; 673 if (enc) { 674 decoder = enc->decoding_function; 675 } 676 if (decoder == NULL) { 677 /* If the target encoding was unknown, or no decoder function 678 * was specified, return the UTF-8-encoded data as-is. 679 */ 680 memcpy(newbuf, s, len); 681 *newlen = len; 682 newbuf[*newlen] = '\0'; 683 return newbuf; 684 } 685 686 while (pos < (size_t)len) { 687 int status = FAILURE; 688 c = php_next_utf8_char((const unsigned char*)s, (size_t) len, &pos, &status); 689 690 if (status == FAILURE || c > 0xFFU) { 691 c = '?'; 692 } 693 694 newbuf[*newlen] = decoder ? decoder(c) : c; 695 ++*newlen; 696 } 697 if (*newlen < len) { 698 newbuf = erealloc(newbuf, *newlen + 1); 699 } 700 newbuf[*newlen] = '\0'; 701 return newbuf; 702} 703/* }}} */ 704 705/* {{{ _xml_xmlcharlen() */ 706static int _xml_xmlcharlen(const XML_Char *s) 707{ 708 int len = 0; 709 710 while (*s) { 711 len++; 712 s++; 713 } 714 return len; 715} 716/* }}} */ 717 718/* {{{ _xml_zval_strdup() */ 719PHPAPI char *_xml_zval_strdup(zval *val) 720{ 721 if (Z_TYPE_P(val) == IS_STRING) { 722 char *buf = emalloc(Z_STRLEN_P(val) + 1); 723 memcpy(buf, Z_STRVAL_P(val), Z_STRLEN_P(val)); 724 buf[Z_STRLEN_P(val)] = '\0'; 725 return buf; 726 } 727 return NULL; 728} 729/* }}} */ 730 731/* {{{ _xml_add_to_info */ 732static void _xml_add_to_info(xml_parser *parser,char *name) 733{ 734 zval **element, *values; 735 736 if (! parser->info) { 737 return; 738 } 739 740 if (zend_hash_find(Z_ARRVAL_P(parser->info),name,strlen(name) + 1,(void **) &element) == FAILURE) { 741 MAKE_STD_ZVAL(values); 742 743 array_init(values); 744 745 zend_hash_update(Z_ARRVAL_P(parser->info), name, strlen(name)+1, (void *) &values, sizeof(zval*), (void **) &element); 746 } 747 748 add_next_index_long(*element,parser->curtag); 749 750 parser->curtag++; 751} 752/* }}} */ 753 754/* {{{ _xml_decode_tag() */ 755static char *_xml_decode_tag(xml_parser *parser, const char *tag) 756{ 757 char *newstr; 758 int out_len; 759 760 newstr = xml_utf8_decode(tag, strlen(tag), &out_len, parser->target_encoding); 761 762 if (parser->case_folding) { 763 php_strtoupper(newstr, out_len); 764 } 765 766 return newstr; 767} 768/* }}} */ 769 770/* {{{ _xml_startElementHandler() */ 771void _xml_startElementHandler(void *userData, const XML_Char *name, const XML_Char **attributes) 772{ 773 xml_parser *parser = (xml_parser *)userData; 774 const char **attrs = (const char **) attributes; 775 char *tag_name; 776 char *att, *val; 777 int val_len; 778 zval *retval, *args[3]; 779 780 if (parser) { 781 parser->level++; 782 783 tag_name = _xml_decode_tag(parser, name); 784 785 if (parser->startElementHandler) { 786 args[0] = _xml_resource_zval(parser->index); 787 args[1] = _xml_string_zval(((char *) tag_name) + parser->toffset); 788 MAKE_STD_ZVAL(args[2]); 789 array_init(args[2]); 790 791 while (attributes && *attributes) { 792 att = _xml_decode_tag(parser, attributes[0]); 793 val = xml_utf8_decode(attributes[1], strlen(attributes[1]), &val_len, parser->target_encoding); 794 795 add_assoc_stringl(args[2], att, val, val_len, 0); 796 797 attributes += 2; 798 799 efree(att); 800 } 801 802 if ((retval = xml_call_handler(parser, parser->startElementHandler, parser->startElementPtr, 3, args))) { 803 zval_ptr_dtor(&retval); 804 } 805 } 806 807 if (parser->data) { 808 zval *tag, *atr; 809 int atcnt = 0; 810 811 MAKE_STD_ZVAL(tag); 812 MAKE_STD_ZVAL(atr); 813 814 array_init(tag); 815 array_init(atr); 816 817 _xml_add_to_info(parser,((char *) tag_name) + parser->toffset); 818 819 add_assoc_string(tag,"tag",((char *) tag_name) + parser->toffset,1); /* cast to avoid gcc-warning */ 820 add_assoc_string(tag,"type","open",1); 821 add_assoc_long(tag,"level",parser->level); 822 823 parser->ltags[parser->level-1] = estrdup(tag_name); 824 parser->lastwasopen = 1; 825 826 attributes = (const XML_Char **) attrs; 827 828 while (attributes && *attributes) { 829 att = _xml_decode_tag(parser, attributes[0]); 830 val = xml_utf8_decode(attributes[1], strlen(attributes[1]), &val_len, parser->target_encoding); 831 832 add_assoc_stringl(atr,att,val,val_len,0); 833 834 atcnt++; 835 attributes += 2; 836 837 efree(att); 838 } 839 840 if (atcnt) { 841 zend_hash_add(Z_ARRVAL_P(tag),"attributes",sizeof("attributes"),&atr,sizeof(zval*),NULL); 842 } else { 843 zval_ptr_dtor(&atr); 844 } 845 846 zend_hash_next_index_insert(Z_ARRVAL_P(parser->data),&tag,sizeof(zval*),(void *) &parser->ctag); 847 } 848 849 efree(tag_name); 850 } 851} 852/* }}} */ 853 854/* {{{ _xml_endElementHandler() */ 855void _xml_endElementHandler(void *userData, const XML_Char *name) 856{ 857 xml_parser *parser = (xml_parser *)userData; 858 char *tag_name; 859 860 if (parser) { 861 zval *retval, *args[2]; 862 863 tag_name = _xml_decode_tag(parser, name); 864 865 if (parser->endElementHandler) { 866 args[0] = _xml_resource_zval(parser->index); 867 args[1] = _xml_string_zval(((char *) tag_name) + parser->toffset); 868 869 if ((retval = xml_call_handler(parser, parser->endElementHandler, parser->endElementPtr, 2, args))) { 870 zval_ptr_dtor(&retval); 871 } 872 } 873 874 if (parser->data) { 875 zval *tag; 876 877 if (parser->lastwasopen) { 878 add_assoc_string(*(parser->ctag),"type","complete",1); 879 } else { 880 MAKE_STD_ZVAL(tag); 881 882 array_init(tag); 883 884 _xml_add_to_info(parser,((char *) tag_name) + parser->toffset); 885 886 add_assoc_string(tag,"tag",((char *) tag_name) + parser->toffset,1); /* cast to avoid gcc-warning */ 887 add_assoc_string(tag,"type","close",1); 888 add_assoc_long(tag,"level",parser->level); 889 890 zend_hash_next_index_insert(Z_ARRVAL_P(parser->data),&tag,sizeof(zval*),NULL); 891 } 892 893 parser->lastwasopen = 0; 894 } 895 896 efree(tag_name); 897 898 if (parser->ltags) { 899 efree(parser->ltags[parser->level-1]); 900 } 901 902 parser->level--; 903 } 904} 905/* }}} */ 906 907/* {{{ _xml_characterDataHandler() */ 908void _xml_characterDataHandler(void *userData, const XML_Char *s, int len) 909{ 910 xml_parser *parser = (xml_parser *)userData; 911 912 if (parser) { 913 zval *retval, *args[2]; 914 915 if (parser->characterDataHandler) { 916 args[0] = _xml_resource_zval(parser->index); 917 args[1] = _xml_xmlchar_zval(s, len, parser->target_encoding); 918 if ((retval = xml_call_handler(parser, parser->characterDataHandler, parser->characterDataPtr, 2, args))) { 919 zval_ptr_dtor(&retval); 920 } 921 } 922 923 if (parser->data) { 924 int i; 925 int doprint = 0; 926 927 char *decoded_value; 928 int decoded_len; 929 930 decoded_value = xml_utf8_decode(s,len,&decoded_len,parser->target_encoding); 931 for (i = 0; i < decoded_len; i++) { 932 switch (decoded_value[i]) { 933 case ' ': 934 case '\t': 935 case '\n': 936 continue; 937 default: 938 doprint = 1; 939 break; 940 } 941 if (doprint) { 942 break; 943 } 944 } 945 if (doprint || (! parser->skipwhite)) { 946 if (parser->lastwasopen) { 947 zval **myval; 948 949 /* check if the current tag already has a value - if yes append to that! */ 950 if (zend_hash_find(Z_ARRVAL_PP(parser->ctag),"value",sizeof("value"),(void **) &myval) == SUCCESS) { 951 int newlen = Z_STRLEN_PP(myval) + decoded_len; 952 Z_STRVAL_PP(myval) = erealloc(Z_STRVAL_PP(myval),newlen+1); 953 strncpy(Z_STRVAL_PP(myval) + Z_STRLEN_PP(myval), decoded_value, decoded_len + 1); 954 Z_STRLEN_PP(myval) += decoded_len; 955 efree(decoded_value); 956 } else { 957 add_assoc_string(*(parser->ctag),"value",decoded_value,0); 958 } 959 960 } else { 961 zval *tag; 962 zval **curtag, **mytype, **myval; 963 HashPosition hpos=NULL; 964 965 zend_hash_internal_pointer_end_ex(Z_ARRVAL_P(parser->data), &hpos); 966 967 if (hpos && (zend_hash_get_current_data_ex(Z_ARRVAL_P(parser->data), (void **) &curtag, &hpos) == SUCCESS)) { 968 if (zend_hash_find(Z_ARRVAL_PP(curtag),"type",sizeof("type"),(void **) &mytype) == SUCCESS) { 969 if (!strcmp(Z_STRVAL_PP(mytype), "cdata")) { 970 if (zend_hash_find(Z_ARRVAL_PP(curtag),"value",sizeof("value"),(void **) &myval) == SUCCESS) { 971 int newlen = Z_STRLEN_PP(myval) + decoded_len; 972 Z_STRVAL_PP(myval) = erealloc(Z_STRVAL_PP(myval),newlen+1); 973 strncpy(Z_STRVAL_PP(myval) + Z_STRLEN_PP(myval), decoded_value, decoded_len + 1); 974 Z_STRLEN_PP(myval) += decoded_len; 975 efree(decoded_value); 976 return; 977 } 978 } 979 } 980 } 981 982 MAKE_STD_ZVAL(tag); 983 984 array_init(tag); 985 986 _xml_add_to_info(parser,parser->ltags[parser->level-1] + parser->toffset); 987 988 add_assoc_string(tag,"tag",parser->ltags[parser->level-1] + parser->toffset,1); 989 add_assoc_string(tag,"value",decoded_value,0); 990 add_assoc_string(tag,"type","cdata",1); 991 add_assoc_long(tag,"level",parser->level); 992 993 zend_hash_next_index_insert(Z_ARRVAL_P(parser->data),&tag,sizeof(zval*),NULL); 994 } 995 } else { 996 efree(decoded_value); 997 } 998 } 999 } 1000} 1001/* }}} */ 1002 1003/* {{{ _xml_processingInstructionHandler() */ 1004void _xml_processingInstructionHandler(void *userData, const XML_Char *target, const XML_Char *data) 1005{ 1006 xml_parser *parser = (xml_parser *)userData; 1007 1008 if (parser && parser->processingInstructionHandler) { 1009 zval *retval, *args[3]; 1010 1011 args[0] = _xml_resource_zval(parser->index); 1012 args[1] = _xml_xmlchar_zval(target, 0, parser->target_encoding); 1013 args[2] = _xml_xmlchar_zval(data, 0, parser->target_encoding); 1014 if ((retval = xml_call_handler(parser, parser->processingInstructionHandler, parser->processingInstructionPtr, 3, args))) { 1015 zval_ptr_dtor(&retval); 1016 } 1017 } 1018} 1019/* }}} */ 1020 1021/* {{{ _xml_defaultHandler() */ 1022void _xml_defaultHandler(void *userData, const XML_Char *s, int len) 1023{ 1024 xml_parser *parser = (xml_parser *)userData; 1025 1026 if (parser && parser->defaultHandler) { 1027 zval *retval, *args[2]; 1028 1029 args[0] = _xml_resource_zval(parser->index); 1030 args[1] = _xml_xmlchar_zval(s, len, parser->target_encoding); 1031 if ((retval = xml_call_handler(parser, parser->defaultHandler, parser->defaultPtr, 2, args))) { 1032 zval_ptr_dtor(&retval); 1033 } 1034 } 1035} 1036/* }}} */ 1037 1038/* {{{ _xml_unparsedEntityDeclHandler() */ 1039void _xml_unparsedEntityDeclHandler(void *userData, 1040 const XML_Char *entityName, 1041 const XML_Char *base, 1042 const XML_Char *systemId, 1043 const XML_Char *publicId, 1044 const XML_Char *notationName) 1045{ 1046 xml_parser *parser = (xml_parser *)userData; 1047 1048 if (parser && parser->unparsedEntityDeclHandler) { 1049 zval *retval, *args[6]; 1050 1051 args[0] = _xml_resource_zval(parser->index); 1052 args[1] = _xml_xmlchar_zval(entityName, 0, parser->target_encoding); 1053 args[2] = _xml_xmlchar_zval(base, 0, parser->target_encoding); 1054 args[3] = _xml_xmlchar_zval(systemId, 0, parser->target_encoding); 1055 args[4] = _xml_xmlchar_zval(publicId, 0, parser->target_encoding); 1056 args[5] = _xml_xmlchar_zval(notationName, 0, parser->target_encoding); 1057 if ((retval = xml_call_handler(parser, parser->unparsedEntityDeclHandler, parser->unparsedEntityDeclPtr, 6, args))) { 1058 zval_ptr_dtor(&retval); 1059 } 1060 } 1061} 1062/* }}} */ 1063 1064/* {{{ _xml_notationDeclHandler() */ 1065void _xml_notationDeclHandler(void *userData, 1066 const XML_Char *notationName, 1067 const XML_Char *base, 1068 const XML_Char *systemId, 1069 const XML_Char *publicId) 1070{ 1071 xml_parser *parser = (xml_parser *)userData; 1072 1073 if (parser && parser->notationDeclHandler) { 1074 zval *retval, *args[5]; 1075 1076 args[0] = _xml_resource_zval(parser->index); 1077 args[1] = _xml_xmlchar_zval(notationName, 0, parser->target_encoding); 1078 args[2] = _xml_xmlchar_zval(base, 0, parser->target_encoding); 1079 args[3] = _xml_xmlchar_zval(systemId, 0, parser->target_encoding); 1080 args[4] = _xml_xmlchar_zval(publicId, 0, parser->target_encoding); 1081 if ((retval = xml_call_handler(parser, parser->notationDeclHandler, parser->notationDeclPtr, 5, args))) { 1082 zval_ptr_dtor(&retval); 1083 } 1084 } 1085} 1086/* }}} */ 1087 1088/* {{{ _xml_externalEntityRefHandler() */ 1089int _xml_externalEntityRefHandler(XML_Parser parserPtr, 1090 const XML_Char *openEntityNames, 1091 const XML_Char *base, 1092 const XML_Char *systemId, 1093 const XML_Char *publicId) 1094{ 1095 xml_parser *parser = XML_GetUserData(parserPtr); 1096 int ret = 0; /* abort if no handler is set (should be configurable?) */ 1097 1098 if (parser && parser->externalEntityRefHandler) { 1099 zval *retval, *args[5]; 1100 1101 args[0] = _xml_resource_zval(parser->index); 1102 args[1] = _xml_xmlchar_zval(openEntityNames, 0, parser->target_encoding); 1103 args[2] = _xml_xmlchar_zval(base, 0, parser->target_encoding); 1104 args[3] = _xml_xmlchar_zval(systemId, 0, parser->target_encoding); 1105 args[4] = _xml_xmlchar_zval(publicId, 0, parser->target_encoding); 1106 if ((retval = xml_call_handler(parser, parser->externalEntityRefHandler, parser->externalEntityRefPtr, 5, args))) { 1107 convert_to_long(retval); 1108 ret = Z_LVAL_P(retval); 1109 efree(retval); 1110 } else { 1111 ret = 0; 1112 } 1113 } 1114 return ret; 1115} 1116/* }}} */ 1117 1118/* {{{ _xml_startNamespaceDeclHandler() */ 1119void _xml_startNamespaceDeclHandler(void *userData,const XML_Char *prefix, const XML_Char *uri) 1120{ 1121 xml_parser *parser = (xml_parser *)userData; 1122 1123 if (parser && parser->startNamespaceDeclHandler) { 1124 zval *retval, *args[3]; 1125 1126 args[0] = _xml_resource_zval(parser->index); 1127 args[1] = _xml_xmlchar_zval(prefix, 0, parser->target_encoding); 1128 args[2] = _xml_xmlchar_zval(uri, 0, parser->target_encoding); 1129 if ((retval = xml_call_handler(parser, parser->startNamespaceDeclHandler, parser->startNamespaceDeclPtr, 3, args))) { 1130 zval_ptr_dtor(&retval); 1131 } 1132 } 1133} 1134/* }}} */ 1135 1136/* {{{ _xml_endNamespaceDeclHandler() */ 1137void _xml_endNamespaceDeclHandler(void *userData, const XML_Char *prefix) 1138{ 1139 xml_parser *parser = (xml_parser *)userData; 1140 1141 if (parser && parser->endNamespaceDeclHandler) { 1142 zval *retval, *args[2]; 1143 1144 args[0] = _xml_resource_zval(parser->index); 1145 args[1] = _xml_xmlchar_zval(prefix, 0, parser->target_encoding); 1146 if ((retval = xml_call_handler(parser, parser->endNamespaceDeclHandler, parser->endNamespaceDeclPtr, 2, args))) { 1147 zval_ptr_dtor(&retval); 1148 } 1149 } 1150} 1151/* }}} */ 1152 1153/************************* EXTENSION FUNCTIONS *************************/ 1154 1155static void php_xml_parser_create_impl(INTERNAL_FUNCTION_PARAMETERS, int ns_support) /* {{{ */ 1156{ 1157 xml_parser *parser; 1158 int auto_detect = 0; 1159 1160 char *encoding_param = NULL; 1161 int encoding_param_len = 0; 1162 1163 char *ns_param = NULL; 1164 int ns_param_len = 0; 1165 1166 XML_Char *encoding; 1167 1168 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, (ns_support ? "|ss": "|s"), &encoding_param, &encoding_param_len, &ns_param, &ns_param_len) == FAILURE) { 1169 RETURN_FALSE; 1170 } 1171 1172 if (encoding_param != NULL) { 1173 /* The supported encoding types are hardcoded here because 1174 * we are limited to the encodings supported by expat/xmltok. 1175 */ 1176 if (encoding_param_len == 0) { 1177 encoding = XML(default_encoding); 1178 auto_detect = 1; 1179 } else if (strcasecmp(encoding_param, "ISO-8859-1") == 0) { 1180 encoding = "ISO-8859-1"; 1181 } else if (strcasecmp(encoding_param, "UTF-8") == 0) { 1182 encoding = "UTF-8"; 1183 } else if (strcasecmp(encoding_param, "US-ASCII") == 0) { 1184 encoding = "US-ASCII"; 1185 } else { 1186 php_error_docref(NULL TSRMLS_CC, E_WARNING, "unsupported source encoding \"%s\"", encoding_param); 1187 RETURN_FALSE; 1188 } 1189 } else { 1190 encoding = XML(default_encoding); 1191 } 1192 1193 if (ns_support && ns_param == NULL){ 1194 ns_param = ":"; 1195 } 1196 1197 parser = ecalloc(1, sizeof(xml_parser)); 1198 parser->parser = XML_ParserCreate_MM((auto_detect ? NULL : encoding), 1199 &php_xml_mem_hdlrs, ns_param); 1200 1201 parser->target_encoding = encoding; 1202 parser->case_folding = 1; 1203 parser->object = NULL; 1204 parser->isparsing = 0; 1205 1206 XML_SetUserData(parser->parser, parser); 1207 1208 ZEND_REGISTER_RESOURCE(return_value, parser,le_xml_parser); 1209 parser->index = Z_LVAL_P(return_value); 1210} 1211/* }}} */ 1212 1213/* {{{ proto resource xml_parser_create([string encoding]) 1214 Create an XML parser */ 1215PHP_FUNCTION(xml_parser_create) 1216{ 1217 php_xml_parser_create_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); 1218} 1219/* }}} */ 1220 1221/* {{{ proto resource xml_parser_create_ns([string encoding [, string sep]]) 1222 Create an XML parser */ 1223PHP_FUNCTION(xml_parser_create_ns) 1224{ 1225 php_xml_parser_create_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); 1226} 1227/* }}} */ 1228 1229/* {{{ proto int xml_set_object(resource parser, object &obj) 1230 Set up object which should be used for callbacks */ 1231PHP_FUNCTION(xml_set_object) 1232{ 1233 xml_parser *parser; 1234 zval *pind, *mythis; 1235 1236 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ro", &pind, &mythis) == FAILURE) { 1237 return; 1238 } 1239 1240 ZEND_FETCH_RESOURCE(parser,xml_parser *, &pind, -1, "XML Parser", le_xml_parser); 1241 1242 /* please leave this commented - or ask thies@thieso.net before doing it (again) */ 1243 if (parser->object) { 1244 zval_ptr_dtor(&parser->object); 1245 } 1246 1247 /* please leave this commented - or ask thies@thieso.net before doing it (again) */ 1248/* #ifdef ZEND_ENGINE_2 1249 zval_add_ref(&parser->object); 1250#endif */ 1251 1252 ALLOC_ZVAL(parser->object); 1253 MAKE_COPY_ZVAL(&mythis, parser->object); 1254 1255 RETVAL_TRUE; 1256} 1257/* }}} */ 1258 1259/* {{{ proto int xml_set_element_handler(resource parser, string shdl, string ehdl) 1260 Set up start and end element handlers */ 1261PHP_FUNCTION(xml_set_element_handler) 1262{ 1263 xml_parser *parser; 1264 zval *pind, **shdl, **ehdl; 1265 1266 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZZ", &pind, &shdl, &ehdl) == FAILURE) { 1267 return; 1268 } 1269 1270 ZEND_FETCH_RESOURCE(parser,xml_parser *, &pind, -1, "XML Parser", le_xml_parser); 1271 1272 xml_set_handler(&parser->startElementHandler, shdl); 1273 xml_set_handler(&parser->endElementHandler, ehdl); 1274 XML_SetElementHandler(parser->parser, _xml_startElementHandler, _xml_endElementHandler); 1275 RETVAL_TRUE; 1276} 1277/* }}} */ 1278 1279/* {{{ proto int xml_set_character_data_handler(resource parser, string hdl) 1280 Set up character data handler */ 1281PHP_FUNCTION(xml_set_character_data_handler) 1282{ 1283 xml_parser *parser; 1284 zval *pind, **hdl; 1285 1286 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZ", &pind, &hdl) == FAILURE) { 1287 return; 1288 } 1289 1290 ZEND_FETCH_RESOURCE(parser,xml_parser *, &pind, -1, "XML Parser", le_xml_parser); 1291 1292 xml_set_handler(&parser->characterDataHandler, hdl); 1293 XML_SetCharacterDataHandler(parser->parser, _xml_characterDataHandler); 1294 RETVAL_TRUE; 1295} 1296/* }}} */ 1297 1298/* {{{ proto int xml_set_processing_instruction_handler(resource parser, string hdl) 1299 Set up processing instruction (PI) handler */ 1300PHP_FUNCTION(xml_set_processing_instruction_handler) 1301{ 1302 xml_parser *parser; 1303 zval *pind, **hdl; 1304 1305 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZ", &pind, &hdl) == FAILURE) { 1306 return; 1307 } 1308 1309 ZEND_FETCH_RESOURCE(parser,xml_parser *, &pind, -1, "XML Parser", le_xml_parser); 1310 1311 xml_set_handler(&parser->processingInstructionHandler, hdl); 1312 XML_SetProcessingInstructionHandler(parser->parser, _xml_processingInstructionHandler); 1313 RETVAL_TRUE; 1314} 1315/* }}} */ 1316 1317/* {{{ proto int xml_set_default_handler(resource parser, string hdl) 1318 Set up default handler */ 1319PHP_FUNCTION(xml_set_default_handler) 1320{ 1321 xml_parser *parser; 1322 zval *pind, **hdl; 1323 1324 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZ", &pind, &hdl) == FAILURE) { 1325 return; 1326 } 1327 ZEND_FETCH_RESOURCE(parser,xml_parser *, &pind, -1, "XML Parser", le_xml_parser); 1328 1329 xml_set_handler(&parser->defaultHandler, hdl); 1330 XML_SetDefaultHandler(parser->parser, _xml_defaultHandler); 1331 RETVAL_TRUE; 1332} 1333/* }}} */ 1334 1335/* {{{ proto int xml_set_unparsed_entity_decl_handler(resource parser, string hdl) 1336 Set up unparsed entity declaration handler */ 1337PHP_FUNCTION(xml_set_unparsed_entity_decl_handler) 1338{ 1339 xml_parser *parser; 1340 zval *pind, **hdl; 1341 1342 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZ", &pind, &hdl) == FAILURE) { 1343 return; 1344 } 1345 1346 ZEND_FETCH_RESOURCE(parser,xml_parser *, &pind, -1, "XML Parser", le_xml_parser); 1347 1348 xml_set_handler(&parser->unparsedEntityDeclHandler, hdl); 1349 XML_SetUnparsedEntityDeclHandler(parser->parser, _xml_unparsedEntityDeclHandler); 1350 RETVAL_TRUE; 1351} 1352/* }}} */ 1353 1354/* {{{ proto int xml_set_notation_decl_handler(resource parser, string hdl) 1355 Set up notation declaration handler */ 1356PHP_FUNCTION(xml_set_notation_decl_handler) 1357{ 1358 xml_parser *parser; 1359 zval *pind, **hdl; 1360 1361 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZ", &pind, &hdl) == FAILURE) { 1362 return; 1363 } 1364 ZEND_FETCH_RESOURCE(parser,xml_parser *, &pind, -1, "XML Parser", le_xml_parser); 1365 1366 xml_set_handler(&parser->notationDeclHandler, hdl); 1367 XML_SetNotationDeclHandler(parser->parser, _xml_notationDeclHandler); 1368 RETVAL_TRUE; 1369} 1370/* }}} */ 1371 1372/* {{{ proto int xml_set_external_entity_ref_handler(resource parser, string hdl) 1373 Set up external entity reference handler */ 1374PHP_FUNCTION(xml_set_external_entity_ref_handler) 1375{ 1376 xml_parser *parser; 1377 zval *pind, **hdl; 1378 1379 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZ", &pind, &hdl) == FAILURE) { 1380 return; 1381 } 1382 ZEND_FETCH_RESOURCE(parser,xml_parser *, &pind, -1, "XML Parser", le_xml_parser); 1383 1384 xml_set_handler(&parser->externalEntityRefHandler, hdl); 1385 XML_SetExternalEntityRefHandler(parser->parser, (void *) _xml_externalEntityRefHandler); 1386 RETVAL_TRUE; 1387} 1388/* }}} */ 1389 1390/* {{{ proto int xml_set_start_namespace_decl_handler(resource parser, string hdl) 1391 Set up character data handler */ 1392PHP_FUNCTION(xml_set_start_namespace_decl_handler) 1393{ 1394 xml_parser *parser; 1395 zval *pind, **hdl; 1396 1397 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZ", &pind, &hdl) == FAILURE) { 1398 return; 1399 } 1400 1401 ZEND_FETCH_RESOURCE(parser,xml_parser *, &pind, -1, "XML Parser", le_xml_parser); 1402 1403 xml_set_handler(&parser->startNamespaceDeclHandler, hdl); 1404 XML_SetStartNamespaceDeclHandler(parser->parser, _xml_startNamespaceDeclHandler); 1405 RETVAL_TRUE; 1406} 1407/* }}} */ 1408 1409/* {{{ proto int xml_set_end_namespace_decl_handler(resource parser, string hdl) 1410 Set up character data handler */ 1411PHP_FUNCTION(xml_set_end_namespace_decl_handler) 1412{ 1413 xml_parser *parser; 1414 zval *pind, **hdl; 1415 1416 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZ", &pind, &hdl) == FAILURE) { 1417 return; 1418 } 1419 1420 ZEND_FETCH_RESOURCE(parser,xml_parser *, &pind, -1, "XML Parser", le_xml_parser); 1421 1422 xml_set_handler(&parser->endNamespaceDeclHandler, hdl); 1423 XML_SetEndNamespaceDeclHandler(parser->parser, _xml_endNamespaceDeclHandler); 1424 RETVAL_TRUE; 1425} 1426/* }}} */ 1427 1428/* {{{ proto int xml_parse(resource parser, string data [, int isFinal]) 1429 Start parsing an XML document */ 1430PHP_FUNCTION(xml_parse) 1431{ 1432 xml_parser *parser; 1433 zval *pind; 1434 char *data; 1435 int data_len, ret; 1436 long isFinal = 0; 1437 1438 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|l", &pind, &data, &data_len, &isFinal) == FAILURE) { 1439 return; 1440 } 1441 ZEND_FETCH_RESOURCE(parser,xml_parser *, &pind, -1, "XML Parser", le_xml_parser); 1442 1443 parser->isparsing = 1; 1444 ret = XML_Parse(parser->parser, data, data_len, isFinal); 1445 parser->isparsing = 0; 1446 RETVAL_LONG(ret); 1447} 1448 1449/* }}} */ 1450 1451/* {{{ proto int xml_parse_into_struct(resource parser, string data, array &values [, array &index ]) 1452 Parsing a XML document */ 1453 1454PHP_FUNCTION(xml_parse_into_struct) 1455{ 1456 xml_parser *parser; 1457 zval *pind, **xdata, **info = NULL; 1458 char *data; 1459 int data_len, ret; 1460 1461 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsZ|Z", &pind, &data, &data_len, &xdata, &info) == FAILURE) { 1462 return; 1463 } 1464 1465 if (info) { 1466 zval_dtor(*info); 1467 array_init(*info); 1468 } 1469 1470 ZEND_FETCH_RESOURCE(parser,xml_parser *, &pind, -1, "XML Parser", le_xml_parser); 1471 1472 zval_dtor(*xdata); 1473 array_init(*xdata); 1474 1475 parser->data = *xdata; 1476 1477 if (info) { 1478 parser->info = *info; 1479 } 1480 1481 parser->level = 0; 1482 parser->ltags = safe_emalloc(XML_MAXLEVEL, sizeof(char *), 0); 1483 1484 XML_SetDefaultHandler(parser->parser, _xml_defaultHandler); 1485 XML_SetElementHandler(parser->parser, _xml_startElementHandler, _xml_endElementHandler); 1486 XML_SetCharacterDataHandler(parser->parser, _xml_characterDataHandler); 1487 1488 parser->isparsing = 1; 1489 ret = XML_Parse(parser->parser, data, data_len, 1); 1490 parser->isparsing = 0; 1491 1492 RETVAL_LONG(ret); 1493} 1494/* }}} */ 1495 1496/* {{{ proto int xml_get_error_code(resource parser) 1497 Get XML parser error code */ 1498PHP_FUNCTION(xml_get_error_code) 1499{ 1500 xml_parser *parser; 1501 zval *pind; 1502 1503 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pind) == FAILURE) { 1504 return; 1505 } 1506 ZEND_FETCH_RESOURCE(parser,xml_parser *, &pind, -1, "XML Parser", le_xml_parser); 1507 1508 RETVAL_LONG((long)XML_GetErrorCode(parser->parser)); 1509} 1510/* }}} */ 1511 1512/* {{{ proto string xml_error_string(int code) 1513 Get XML parser error string */ 1514PHP_FUNCTION(xml_error_string) 1515{ 1516 long code; 1517 char *str; 1518 1519 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &code) == FAILURE) { 1520 return; 1521 } 1522 1523 str = (char *)XML_ErrorString((int)code); 1524 if (str) { 1525 RETVAL_STRING(str, 1); 1526 } 1527} 1528/* }}} */ 1529 1530/* {{{ proto int xml_get_current_line_number(resource parser) 1531 Get current line number for an XML parser */ 1532PHP_FUNCTION(xml_get_current_line_number) 1533{ 1534 xml_parser *parser; 1535 zval *pind; 1536 1537 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pind) == FAILURE) { 1538 return; 1539 } 1540 ZEND_FETCH_RESOURCE(parser,xml_parser *, &pind, -1, "XML Parser", le_xml_parser); 1541 1542 RETVAL_LONG(XML_GetCurrentLineNumber(parser->parser)); 1543} 1544/* }}} */ 1545 1546/* {{{ proto int xml_get_current_column_number(resource parser) 1547 Get current column number for an XML parser */ 1548PHP_FUNCTION(xml_get_current_column_number) 1549{ 1550 xml_parser *parser; 1551 zval *pind; 1552 1553 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pind) == FAILURE) { 1554 return; 1555 } 1556 ZEND_FETCH_RESOURCE(parser,xml_parser *, &pind, -1, "XML Parser", le_xml_parser); 1557 1558 RETVAL_LONG(XML_GetCurrentColumnNumber(parser->parser)); 1559} 1560/* }}} */ 1561 1562/* {{{ proto int xml_get_current_byte_index(resource parser) 1563 Get current byte index for an XML parser */ 1564PHP_FUNCTION(xml_get_current_byte_index) 1565{ 1566 xml_parser *parser; 1567 zval *pind; 1568 1569 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pind) == FAILURE) { 1570 return; 1571 } 1572 ZEND_FETCH_RESOURCE(parser,xml_parser *, &pind, -1, "XML Parser", le_xml_parser); 1573 1574 RETVAL_LONG(XML_GetCurrentByteIndex(parser->parser)); 1575} 1576/* }}} */ 1577 1578/* {{{ proto int xml_parser_free(resource parser) 1579 Free an XML parser */ 1580PHP_FUNCTION(xml_parser_free) 1581{ 1582 zval *pind; 1583 xml_parser *parser; 1584 1585 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pind) == FAILURE) { 1586 return; 1587 } 1588 1589 ZEND_FETCH_RESOURCE(parser,xml_parser *, &pind, -1, "XML Parser", le_xml_parser); 1590 1591 if (parser->isparsing == 1) { 1592 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Parser cannot be freed while it is parsing."); 1593 RETURN_FALSE; 1594 } 1595 1596 if (zend_list_delete(parser->index) == FAILURE) { 1597 RETURN_FALSE; 1598 } 1599 1600 RETVAL_TRUE; 1601} 1602/* }}} */ 1603 1604/* {{{ proto int xml_parser_set_option(resource parser, int option, mixed value) 1605 Set options in an XML parser */ 1606PHP_FUNCTION(xml_parser_set_option) 1607{ 1608 xml_parser *parser; 1609 zval *pind, **val; 1610 long opt; 1611 1612 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlZ", &pind, &opt, &val) == FAILURE) { 1613 return; 1614 } 1615 ZEND_FETCH_RESOURCE(parser,xml_parser *, &pind, -1, "XML Parser", le_xml_parser); 1616 1617 switch (opt) { 1618 case PHP_XML_OPTION_CASE_FOLDING: 1619 convert_to_long_ex(val); 1620 parser->case_folding = Z_LVAL_PP(val); 1621 break; 1622 case PHP_XML_OPTION_SKIP_TAGSTART: 1623 convert_to_long_ex(val); 1624 parser->toffset = Z_LVAL_PP(val); 1625 break; 1626 case PHP_XML_OPTION_SKIP_WHITE: 1627 convert_to_long_ex(val); 1628 parser->skipwhite = Z_LVAL_PP(val); 1629 break; 1630 case PHP_XML_OPTION_TARGET_ENCODING: { 1631 xml_encoding *enc; 1632 convert_to_string_ex(val); 1633 enc = xml_get_encoding(Z_STRVAL_PP(val)); 1634 if (enc == NULL) { 1635 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported target encoding \"%s\"", Z_STRVAL_PP(val)); 1636 RETURN_FALSE; 1637 } 1638 parser->target_encoding = enc->name; 1639 break; 1640 } 1641 default: 1642 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown option"); 1643 RETURN_FALSE; 1644 break; 1645 } 1646 RETVAL_TRUE; 1647} 1648/* }}} */ 1649 1650/* {{{ proto int xml_parser_get_option(resource parser, int option) 1651 Get options from an XML parser */ 1652PHP_FUNCTION(xml_parser_get_option) 1653{ 1654 xml_parser *parser; 1655 zval *pind; 1656 long opt; 1657 1658 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &pind, &opt) == FAILURE) { 1659 return; 1660 } 1661 ZEND_FETCH_RESOURCE(parser,xml_parser *, &pind, -1, "XML Parser", le_xml_parser); 1662 1663 switch (opt) { 1664 case PHP_XML_OPTION_CASE_FOLDING: 1665 RETURN_LONG(parser->case_folding); 1666 break; 1667 case PHP_XML_OPTION_TARGET_ENCODING: 1668 RETURN_STRING(parser->target_encoding, 1); 1669 break; 1670 default: 1671 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown option"); 1672 RETURN_FALSE; 1673 break; 1674 } 1675 1676 RETVAL_FALSE; /* never reached */ 1677} 1678/* }}} */ 1679 1680/* {{{ proto string utf8_encode(string data) 1681 Encodes an ISO-8859-1 string to UTF-8 */ 1682PHP_FUNCTION(utf8_encode) 1683{ 1684 char *arg; 1685 XML_Char *encoded; 1686 int arg_len, len; 1687 1688 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) { 1689 return; 1690 } 1691 1692 encoded = xml_utf8_encode(arg, arg_len, &len, "ISO-8859-1"); 1693 if (encoded == NULL) { 1694 RETURN_FALSE; 1695 } 1696 RETVAL_STRINGL(encoded, len, 0); 1697} 1698/* }}} */ 1699 1700/* {{{ proto string utf8_decode(string data) 1701 Converts a UTF-8 encoded string to ISO-8859-1 */ 1702PHP_FUNCTION(utf8_decode) 1703{ 1704 char *arg; 1705 XML_Char *decoded; 1706 int arg_len, len; 1707 1708 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) { 1709 return; 1710 } 1711 1712 decoded = xml_utf8_decode(arg, arg_len, &len, "ISO-8859-1"); 1713 if (decoded == NULL) { 1714 RETURN_FALSE; 1715 } 1716 RETVAL_STRINGL(decoded, len, 0); 1717} 1718/* }}} */ 1719 1720#endif 1721 1722/* 1723 * Local variables: 1724 * tab-width: 4 1725 * c-basic-offset: 4 1726 * End: 1727 * vim600: sw=4 ts=4 fdm=marker 1728 * vim<600: sw=4 ts=4 1729 */ 1730