PageRenderTime 73ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/ext/xml/xml.c

http://github.com/php/php-src
C | 1519 lines | 1097 code | 253 blank | 169 comment | 194 complexity | 77f06e89dd7fd0c2f8d74429fdffbe8b MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-2.1
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | http://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Authors: Stig Sæther Bakken <ssb@php.net> |
  14. | Thies C. Arntzen <thies@thieso.net> |
  15. | Sterling Hughes <sterling@php.net> |
  16. +----------------------------------------------------------------------+
  17. */
  18. #ifdef HAVE_CONFIG_H
  19. #include "config.h"
  20. #endif
  21. #include "php.h"
  22. #include "zend_variables.h"
  23. #include "ext/standard/php_string.h"
  24. #include "ext/standard/info.h"
  25. #include "ext/standard/html.h"
  26. #include "zend_interfaces.h"
  27. #if HAVE_XML
  28. #include "php_xml.h"
  29. # include "ext/standard/head.h"
  30. #ifdef LIBXML_EXPAT_COMPAT
  31. #include "ext/libxml/php_libxml.h"
  32. #endif
  33. #include "xml_arginfo.h"
  34. /* Short-term TODO list:
  35. * - Implement XML_ExternalEntityParserCreate()
  36. * - XML_SetCommentHandler
  37. * - XML_SetCdataSectionHandler
  38. * - XML_SetParamEntityParsing
  39. */
  40. /* Long-term TODO list:
  41. * - Fix the expat library so you can install your own memory manager
  42. * functions
  43. */
  44. /* Known bugs:
  45. * - Weird things happen with <![CDATA[]]> sections.
  46. */
  47. ZEND_BEGIN_MODULE_GLOBALS(xml)
  48. XML_Char *default_encoding;
  49. ZEND_END_MODULE_GLOBALS(xml)
  50. ZEND_DECLARE_MODULE_GLOBALS(xml)
  51. #define XML(v) ZEND_MODULE_GLOBALS_ACCESSOR(xml, v)
  52. typedef struct {
  53. int case_folding;
  54. XML_Parser parser;
  55. XML_Char *target_encoding;
  56. /* Reference to the object itself, for convenience.
  57. * It is not owned, do not release it. */
  58. zval index;
  59. /* We return a pointer to these zvals in get_gc(), so it's
  60. * important that a) they are adjacent b) object is the first
  61. * and c) the number of zvals is kept up to date. */
  62. #define XML_PARSER_NUM_ZVALS 12
  63. zval object;
  64. zval startElementHandler;
  65. zval endElementHandler;
  66. zval characterDataHandler;
  67. zval processingInstructionHandler;
  68. zval defaultHandler;
  69. zval unparsedEntityDeclHandler;
  70. zval notationDeclHandler;
  71. zval externalEntityRefHandler;
  72. zval unknownEncodingHandler;
  73. zval startNamespaceDeclHandler;
  74. zval endNamespaceDeclHandler;
  75. zend_function *startElementPtr;
  76. zend_function *endElementPtr;
  77. zend_function *characterDataPtr;
  78. zend_function *processingInstructionPtr;
  79. zend_function *defaultPtr;
  80. zend_function *unparsedEntityDeclPtr;
  81. zend_function *notationDeclPtr;
  82. zend_function *externalEntityRefPtr;
  83. zend_function *unknownEncodingPtr;
  84. zend_function *startNamespaceDeclPtr;
  85. zend_function *endNamespaceDeclPtr;
  86. zval data;
  87. zval info;
  88. int level;
  89. int toffset;
  90. int curtag;
  91. zval *ctag;
  92. char **ltags;
  93. int lastwasopen;
  94. int skipwhite;
  95. int isparsing;
  96. XML_Char *baseURI;
  97. zend_object std;
  98. } xml_parser;
  99. typedef struct {
  100. XML_Char *name;
  101. char (*decoding_function)(unsigned short);
  102. unsigned short (*encoding_function)(unsigned char);
  103. } xml_encoding;
  104. enum php_xml_option {
  105. PHP_XML_OPTION_CASE_FOLDING = 1,
  106. PHP_XML_OPTION_TARGET_ENCODING,
  107. PHP_XML_OPTION_SKIP_TAGSTART,
  108. PHP_XML_OPTION_SKIP_WHITE
  109. };
  110. /* {{{ dynamically loadable module stuff */
  111. #ifdef COMPILE_DL_XML
  112. #ifdef ZTS
  113. ZEND_TSRMLS_CACHE_DEFINE()
  114. #endif
  115. ZEND_GET_MODULE(xml)
  116. #endif /* COMPILE_DL_XML */
  117. /* }}} */
  118. #define XML_MAXLEVEL 255 /* XXX this should be dynamic */
  119. #define SKIP_TAGSTART(str) ((str) + (parser->toffset > (int)strlen(str) ? strlen(str) : parser->toffset))
  120. static zend_class_entry *xml_parser_ce;
  121. static zend_object_handlers xml_parser_object_handlers;
  122. /* {{{ function prototypes */
  123. PHP_MINIT_FUNCTION(xml);
  124. PHP_MINFO_FUNCTION(xml);
  125. static PHP_GINIT_FUNCTION(xml);
  126. static zend_object *xml_parser_create_object(zend_class_entry *class_type);
  127. static void xml_parser_free_obj(zend_object *object);
  128. static HashTable *xml_parser_get_gc(zend_object *object, zval **table, int *n);
  129. static zend_function *xml_parser_get_constructor(zend_object *object);
  130. static zend_string *xml_utf8_decode(const XML_Char *, size_t, const XML_Char *);
  131. static void xml_set_handler(zval *, zval *);
  132. inline static unsigned short xml_encode_iso_8859_1(unsigned char);
  133. inline static char xml_decode_iso_8859_1(unsigned short);
  134. inline static unsigned short xml_encode_us_ascii(unsigned char);
  135. inline static char xml_decode_us_ascii(unsigned short);
  136. static void xml_call_handler(xml_parser *, zval *, zend_function *, int, zval *, zval *);
  137. static void _xml_xmlchar_zval(const XML_Char *, int, const XML_Char *, zval *);
  138. static int _xml_xmlcharlen(const XML_Char *);
  139. static void _xml_add_to_info(xml_parser *parser,char *name);
  140. inline static zend_string *_xml_decode_tag(xml_parser *parser, const char *tag);
  141. void _xml_startElementHandler(void *, const XML_Char *, const XML_Char **);
  142. void _xml_endElementHandler(void *, const XML_Char *);
  143. void _xml_characterDataHandler(void *, const XML_Char *, int);
  144. void _xml_processingInstructionHandler(void *, const XML_Char *, const XML_Char *);
  145. void _xml_defaultHandler(void *, const XML_Char *, int);
  146. void _xml_unparsedEntityDeclHandler(void *, const XML_Char *, const XML_Char *, const XML_Char *, const XML_Char *, const XML_Char *);
  147. void _xml_notationDeclHandler(void *, const XML_Char *, const XML_Char *, const XML_Char *, const XML_Char *);
  148. int _xml_externalEntityRefHandler(XML_Parser, const XML_Char *, const XML_Char *, const XML_Char *, const XML_Char *);
  149. void _xml_startNamespaceDeclHandler(void *, const XML_Char *, const XML_Char *);
  150. void _xml_endNamespaceDeclHandler(void *, const XML_Char *);
  151. /* }}} */
  152. #ifdef LIBXML_EXPAT_COMPAT
  153. static const zend_module_dep xml_deps[] = {
  154. ZEND_MOD_REQUIRED("libxml")
  155. ZEND_MOD_END
  156. };
  157. #endif
  158. zend_module_entry xml_module_entry = {
  159. #ifdef LIBXML_EXPAT_COMPAT
  160. STANDARD_MODULE_HEADER_EX, NULL,
  161. xml_deps,
  162. #else
  163. STANDARD_MODULE_HEADER,
  164. #endif
  165. "xml", /* extension name */
  166. ext_functions, /* extension function list */
  167. PHP_MINIT(xml), /* extension-wide startup function */
  168. NULL, /* extension-wide shutdown function */
  169. NULL, /* per-request startup function */
  170. NULL, /* per-request shutdown function */
  171. PHP_MINFO(xml), /* information function */
  172. PHP_XML_VERSION,
  173. PHP_MODULE_GLOBALS(xml), /* globals descriptor */
  174. PHP_GINIT(xml), /* globals ctor */
  175. NULL, /* globals dtor */
  176. NULL, /* post deactivate */
  177. STANDARD_MODULE_PROPERTIES_EX
  178. };
  179. /* All the encoding functions are set to NULL right now, since all
  180. * the encoding is currently done internally by expat/xmltok.
  181. */
  182. const xml_encoding xml_encodings[] = {
  183. { (XML_Char *)"ISO-8859-1", xml_decode_iso_8859_1, xml_encode_iso_8859_1 },
  184. { (XML_Char *)"US-ASCII", xml_decode_us_ascii, xml_encode_us_ascii },
  185. { (XML_Char *)"UTF-8", NULL, NULL },
  186. { (XML_Char *)NULL, NULL, NULL }
  187. };
  188. static XML_Memory_Handling_Suite php_xml_mem_hdlrs;
  189. /* }}} */
  190. /* {{{ startup, shutdown and info functions */
  191. static PHP_GINIT_FUNCTION(xml)
  192. {
  193. #if defined(COMPILE_DL_XML) && defined(ZTS)
  194. ZEND_TSRMLS_CACHE_UPDATE();
  195. #endif
  196. xml_globals->default_encoding = (XML_Char*)"UTF-8";
  197. }
  198. static void *php_xml_malloc_wrapper(size_t sz)
  199. {
  200. return emalloc(sz);
  201. }
  202. static void *php_xml_realloc_wrapper(void *ptr, size_t sz)
  203. {
  204. return erealloc(ptr, sz);
  205. }
  206. static void php_xml_free_wrapper(void *ptr)
  207. {
  208. if (ptr != NULL) {
  209. efree(ptr);
  210. }
  211. }
  212. PHP_MINIT_FUNCTION(xml)
  213. {
  214. zend_class_entry ce;
  215. INIT_CLASS_ENTRY(ce, "XmlParser", class_XMLParser_methods);
  216. xml_parser_ce = zend_register_internal_class(&ce);
  217. xml_parser_ce->create_object = xml_parser_create_object;
  218. xml_parser_ce->ce_flags |= ZEND_ACC_FINAL;
  219. xml_parser_ce->serialize = zend_class_serialize_deny;
  220. xml_parser_ce->unserialize = zend_class_unserialize_deny;
  221. memcpy(&xml_parser_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
  222. xml_parser_object_handlers.offset = XtOffsetOf(xml_parser, std);
  223. xml_parser_object_handlers.free_obj = xml_parser_free_obj;
  224. xml_parser_object_handlers.get_gc = xml_parser_get_gc;
  225. xml_parser_object_handlers.get_constructor = xml_parser_get_constructor;
  226. xml_parser_object_handlers.clone_obj = NULL;
  227. REGISTER_LONG_CONSTANT("XML_ERROR_NONE", XML_ERROR_NONE, CONST_CS|CONST_PERSISTENT);
  228. REGISTER_LONG_CONSTANT("XML_ERROR_NO_MEMORY", XML_ERROR_NO_MEMORY, CONST_CS|CONST_PERSISTENT);
  229. REGISTER_LONG_CONSTANT("XML_ERROR_SYNTAX", XML_ERROR_SYNTAX, CONST_CS|CONST_PERSISTENT);
  230. REGISTER_LONG_CONSTANT("XML_ERROR_NO_ELEMENTS", XML_ERROR_NO_ELEMENTS, CONST_CS|CONST_PERSISTENT);
  231. REGISTER_LONG_CONSTANT("XML_ERROR_INVALID_TOKEN", XML_ERROR_INVALID_TOKEN, CONST_CS|CONST_PERSISTENT);
  232. REGISTER_LONG_CONSTANT("XML_ERROR_UNCLOSED_TOKEN", XML_ERROR_UNCLOSED_TOKEN, CONST_CS|CONST_PERSISTENT);
  233. REGISTER_LONG_CONSTANT("XML_ERROR_PARTIAL_CHAR", XML_ERROR_PARTIAL_CHAR, CONST_CS|CONST_PERSISTENT);
  234. REGISTER_LONG_CONSTANT("XML_ERROR_TAG_MISMATCH", XML_ERROR_TAG_MISMATCH, CONST_CS|CONST_PERSISTENT);
  235. REGISTER_LONG_CONSTANT("XML_ERROR_DUPLICATE_ATTRIBUTE", XML_ERROR_DUPLICATE_ATTRIBUTE, CONST_CS|CONST_PERSISTENT);
  236. REGISTER_LONG_CONSTANT("XML_ERROR_JUNK_AFTER_DOC_ELEMENT", XML_ERROR_JUNK_AFTER_DOC_ELEMENT, CONST_CS|CONST_PERSISTENT);
  237. REGISTER_LONG_CONSTANT("XML_ERROR_PARAM_ENTITY_REF", XML_ERROR_PARAM_ENTITY_REF, CONST_CS|CONST_PERSISTENT);
  238. REGISTER_LONG_CONSTANT("XML_ERROR_UNDEFINED_ENTITY", XML_ERROR_UNDEFINED_ENTITY, CONST_CS|CONST_PERSISTENT);
  239. REGISTER_LONG_CONSTANT("XML_ERROR_RECURSIVE_ENTITY_REF", XML_ERROR_RECURSIVE_ENTITY_REF, CONST_CS|CONST_PERSISTENT);
  240. REGISTER_LONG_CONSTANT("XML_ERROR_ASYNC_ENTITY", XML_ERROR_ASYNC_ENTITY, CONST_CS|CONST_PERSISTENT);
  241. REGISTER_LONG_CONSTANT("XML_ERROR_BAD_CHAR_REF", XML_ERROR_BAD_CHAR_REF, CONST_CS|CONST_PERSISTENT);
  242. REGISTER_LONG_CONSTANT("XML_ERROR_BINARY_ENTITY_REF", XML_ERROR_BINARY_ENTITY_REF, CONST_CS|CONST_PERSISTENT);
  243. REGISTER_LONG_CONSTANT("XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF", XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF, CONST_CS|CONST_PERSISTENT);
  244. REGISTER_LONG_CONSTANT("XML_ERROR_MISPLACED_XML_PI", XML_ERROR_MISPLACED_XML_PI, CONST_CS|CONST_PERSISTENT);
  245. REGISTER_LONG_CONSTANT("XML_ERROR_UNKNOWN_ENCODING", XML_ERROR_UNKNOWN_ENCODING, CONST_CS|CONST_PERSISTENT);
  246. REGISTER_LONG_CONSTANT("XML_ERROR_INCORRECT_ENCODING", XML_ERROR_INCORRECT_ENCODING, CONST_CS|CONST_PERSISTENT);
  247. REGISTER_LONG_CONSTANT("XML_ERROR_UNCLOSED_CDATA_SECTION", XML_ERROR_UNCLOSED_CDATA_SECTION, CONST_CS|CONST_PERSISTENT);
  248. REGISTER_LONG_CONSTANT("XML_ERROR_EXTERNAL_ENTITY_HANDLING", XML_ERROR_EXTERNAL_ENTITY_HANDLING, CONST_CS|CONST_PERSISTENT);
  249. REGISTER_LONG_CONSTANT("XML_OPTION_CASE_FOLDING", PHP_XML_OPTION_CASE_FOLDING, CONST_CS|CONST_PERSISTENT);
  250. REGISTER_LONG_CONSTANT("XML_OPTION_TARGET_ENCODING", PHP_XML_OPTION_TARGET_ENCODING, CONST_CS|CONST_PERSISTENT);
  251. REGISTER_LONG_CONSTANT("XML_OPTION_SKIP_TAGSTART", PHP_XML_OPTION_SKIP_TAGSTART, CONST_CS|CONST_PERSISTENT);
  252. REGISTER_LONG_CONSTANT("XML_OPTION_SKIP_WHITE", PHP_XML_OPTION_SKIP_WHITE, CONST_CS|CONST_PERSISTENT);
  253. /* this object should not be pre-initialised at compile time,
  254. as the order of members may vary */
  255. php_xml_mem_hdlrs.malloc_fcn = php_xml_malloc_wrapper;
  256. php_xml_mem_hdlrs.realloc_fcn = php_xml_realloc_wrapper;
  257. php_xml_mem_hdlrs.free_fcn = php_xml_free_wrapper;
  258. #ifdef LIBXML_EXPAT_COMPAT
  259. REGISTER_STRING_CONSTANT("XML_SAX_IMPL", "libxml", CONST_CS|CONST_PERSISTENT);
  260. #else
  261. REGISTER_STRING_CONSTANT("XML_SAX_IMPL", "expat", CONST_CS|CONST_PERSISTENT);
  262. #endif
  263. return SUCCESS;
  264. }
  265. PHP_MINFO_FUNCTION(xml)
  266. {
  267. php_info_print_table_start();
  268. php_info_print_table_row(2, "XML Support", "active");
  269. php_info_print_table_row(2, "XML Namespace Support", "active");
  270. #if defined(LIBXML_DOTTED_VERSION) && defined(LIBXML_EXPAT_COMPAT)
  271. php_info_print_table_row(2, "libxml2 Version", LIBXML_DOTTED_VERSION);
  272. #else
  273. php_info_print_table_row(2, "EXPAT Version", XML_ExpatVersion());
  274. #endif
  275. php_info_print_table_end();
  276. }
  277. /* }}} */
  278. /* {{{ extension-internal functions */
  279. static void _xml_xmlchar_zval(const XML_Char *s, int len, const XML_Char *encoding, zval *ret)
  280. {
  281. if (s == NULL) {
  282. ZVAL_FALSE(ret);
  283. return;
  284. }
  285. if (len == 0) {
  286. len = _xml_xmlcharlen(s);
  287. }
  288. ZVAL_STR(ret, xml_utf8_decode(s, len, encoding));
  289. }
  290. /* }}} */
  291. static inline xml_parser *xml_parser_from_obj(zend_object *obj) {
  292. return (xml_parser *)((char *)(obj) - XtOffsetOf(xml_parser, std));
  293. }
  294. #define Z_XMLPARSER_P(zv) xml_parser_from_obj(Z_OBJ_P(zv))
  295. static zend_object *xml_parser_create_object(zend_class_entry *class_type) {
  296. xml_parser *intern = zend_object_alloc(sizeof(xml_parser), class_type);
  297. memset(intern, 0, sizeof(xml_parser) - sizeof(zend_object));
  298. zend_object_std_init(&intern->std, class_type);
  299. object_properties_init(&intern->std, class_type);
  300. intern->std.handlers = &xml_parser_object_handlers;
  301. return &intern->std;
  302. }
  303. static void xml_parser_free_obj(zend_object *object)
  304. {
  305. xml_parser *parser = xml_parser_from_obj(object);
  306. if (parser->parser) {
  307. XML_ParserFree(parser->parser);
  308. }
  309. if (parser->ltags) {
  310. int inx;
  311. for (inx = 0; ((inx < parser->level) && (inx < XML_MAXLEVEL)); inx++)
  312. efree(parser->ltags[ inx ]);
  313. efree(parser->ltags);
  314. }
  315. if (!Z_ISUNDEF(parser->startElementHandler)) {
  316. zval_ptr_dtor(&parser->startElementHandler);
  317. }
  318. if (!Z_ISUNDEF(parser->endElementHandler)) {
  319. zval_ptr_dtor(&parser->endElementHandler);
  320. }
  321. if (!Z_ISUNDEF(parser->characterDataHandler)) {
  322. zval_ptr_dtor(&parser->characterDataHandler);
  323. }
  324. if (!Z_ISUNDEF(parser->processingInstructionHandler)) {
  325. zval_ptr_dtor(&parser->processingInstructionHandler);
  326. }
  327. if (!Z_ISUNDEF(parser->defaultHandler)) {
  328. zval_ptr_dtor(&parser->defaultHandler);
  329. }
  330. if (!Z_ISUNDEF(parser->unparsedEntityDeclHandler)) {
  331. zval_ptr_dtor(&parser->unparsedEntityDeclHandler);
  332. }
  333. if (!Z_ISUNDEF(parser->notationDeclHandler)) {
  334. zval_ptr_dtor(&parser->notationDeclHandler);
  335. }
  336. if (!Z_ISUNDEF(parser->externalEntityRefHandler)) {
  337. zval_ptr_dtor(&parser->externalEntityRefHandler);
  338. }
  339. if (!Z_ISUNDEF(parser->unknownEncodingHandler)) {
  340. zval_ptr_dtor(&parser->unknownEncodingHandler);
  341. }
  342. if (!Z_ISUNDEF(parser->startNamespaceDeclHandler)) {
  343. zval_ptr_dtor(&parser->startNamespaceDeclHandler);
  344. }
  345. if (!Z_ISUNDEF(parser->endNamespaceDeclHandler)) {
  346. zval_ptr_dtor(&parser->endNamespaceDeclHandler);
  347. }
  348. if (parser->baseURI) {
  349. efree(parser->baseURI);
  350. }
  351. if (!Z_ISUNDEF(parser->object)) {
  352. zval_ptr_dtor(&parser->object);
  353. }
  354. zend_object_std_dtor(&parser->std);
  355. }
  356. static HashTable *xml_parser_get_gc(zend_object *object, zval **table, int *n)
  357. {
  358. xml_parser *parser = xml_parser_from_obj(object);
  359. *table = &parser->object;
  360. *n = XML_PARSER_NUM_ZVALS;
  361. return zend_std_get_properties(object);
  362. }
  363. static zend_function *xml_parser_get_constructor(zend_object *object) {
  364. zend_throw_error(NULL, "Cannot directly construct XmlParser, use xml_parser_create() or xml_parser_create_ns() instead");
  365. return NULL;
  366. }
  367. /* {{{ xml_set_handler() */
  368. static void xml_set_handler(zval *handler, zval *data)
  369. {
  370. /* If we have already a handler, release it */
  371. if (handler) {
  372. zval_ptr_dtor(handler);
  373. }
  374. /* IS_ARRAY might indicate that we're using array($obj, 'method') syntax */
  375. if (Z_TYPE_P(data) != IS_ARRAY && Z_TYPE_P(data) != IS_OBJECT) {
  376. convert_to_string_ex(data);
  377. if (Z_STRLEN_P(data) == 0) {
  378. ZVAL_UNDEF(handler);
  379. return;
  380. }
  381. }
  382. ZVAL_COPY(handler, data);
  383. }
  384. /* }}} */
  385. /* {{{ xml_call_handler() */
  386. static void xml_call_handler(xml_parser *parser, zval *handler, zend_function *function_ptr, int argc, zval *argv, zval *retval)
  387. {
  388. int i;
  389. ZVAL_UNDEF(retval);
  390. if (parser && handler && !EG(exception)) {
  391. int result;
  392. zend_fcall_info fci;
  393. fci.size = sizeof(fci);
  394. ZVAL_COPY_VALUE(&fci.function_name, handler);
  395. fci.object = Z_OBJ(parser->object);
  396. fci.retval = retval;
  397. fci.param_count = argc;
  398. fci.params = argv;
  399. fci.no_separation = 0;
  400. /*fci.function_handler_cache = &function_ptr;*/
  401. result = zend_call_function(&fci, NULL);
  402. if (result == FAILURE) {
  403. zval *method;
  404. zval *obj;
  405. if (Z_TYPE_P(handler) == IS_STRING) {
  406. php_error_docref(NULL, E_WARNING, "Unable to call handler %s()", Z_STRVAL_P(handler));
  407. } else if (Z_TYPE_P(handler) == IS_ARRAY &&
  408. (obj = zend_hash_index_find(Z_ARRVAL_P(handler), 0)) != NULL &&
  409. (method = zend_hash_index_find(Z_ARRVAL_P(handler), 1)) != NULL &&
  410. Z_TYPE_P(obj) == IS_OBJECT &&
  411. Z_TYPE_P(method) == IS_STRING) {
  412. php_error_docref(NULL, E_WARNING, "Unable to call handler %s::%s()", ZSTR_VAL(Z_OBJCE_P(obj)->name), Z_STRVAL_P(method));
  413. } else
  414. php_error_docref(NULL, E_WARNING, "Unable to call handler");
  415. }
  416. }
  417. for (i = 0; i < argc; i++) {
  418. zval_ptr_dtor(&argv[i]);
  419. }
  420. }
  421. /* }}} */
  422. /* {{{ xml_encode_iso_8859_1() */
  423. inline static unsigned short xml_encode_iso_8859_1(unsigned char c)
  424. {
  425. return (unsigned short)c;
  426. }
  427. /* }}} */
  428. /* {{{ xml_decode_iso_8859_1() */
  429. inline static char xml_decode_iso_8859_1(unsigned short c)
  430. {
  431. return (char)(c > 0xff ? '?' : c);
  432. }
  433. /* }}} */
  434. /* {{{ xml_encode_us_ascii() */
  435. inline static unsigned short xml_encode_us_ascii(unsigned char c)
  436. {
  437. return (unsigned short)c;
  438. }
  439. /* }}} */
  440. /* {{{ xml_decode_us_ascii() */
  441. inline static char xml_decode_us_ascii(unsigned short c)
  442. {
  443. return (char)(c > 0x7f ? '?' : c);
  444. }
  445. /* }}} */
  446. /* {{{ xml_get_encoding() */
  447. static const xml_encoding *xml_get_encoding(const XML_Char *name)
  448. {
  449. const xml_encoding *enc = &xml_encodings[0];
  450. while (enc && enc->name) {
  451. if (strcasecmp((char *)name, (char *)enc->name) == 0) {
  452. return enc;
  453. }
  454. enc++;
  455. }
  456. return NULL;
  457. }
  458. /* }}} */
  459. /* {{{ xml_utf8_decode() */
  460. static zend_string *xml_utf8_decode(const XML_Char *s, size_t len, const XML_Char *encoding)
  461. {
  462. size_t pos = 0;
  463. unsigned int c;
  464. char (*decoder)(unsigned short) = NULL;
  465. const xml_encoding *enc = xml_get_encoding(encoding);
  466. zend_string *str;
  467. if (enc) {
  468. decoder = enc->decoding_function;
  469. }
  470. if (decoder == NULL) {
  471. /* If the target encoding was unknown, or no decoder function
  472. * was specified, return the UTF-8-encoded data as-is.
  473. */
  474. str = zend_string_init((char *)s, len, 0);
  475. return str;
  476. }
  477. str = zend_string_alloc(len, 0);
  478. ZSTR_LEN(str) = 0;
  479. while (pos < len) {
  480. int status = FAILURE;
  481. c = php_next_utf8_char((const unsigned char*)s, (size_t) len, &pos, &status);
  482. if (status == FAILURE || c > 0xFFU) {
  483. c = '?';
  484. }
  485. ZSTR_VAL(str)[ZSTR_LEN(str)++] = decoder ? (unsigned int)decoder(c) : c;
  486. }
  487. ZSTR_VAL(str)[ZSTR_LEN(str)] = '\0';
  488. if (ZSTR_LEN(str) < len) {
  489. str = zend_string_truncate(str, ZSTR_LEN(str), 0);
  490. }
  491. return str;
  492. }
  493. /* }}} */
  494. /* {{{ _xml_xmlcharlen() */
  495. static int _xml_xmlcharlen(const XML_Char *s)
  496. {
  497. int len = 0;
  498. while (*s) {
  499. len++;
  500. s++;
  501. }
  502. return len;
  503. }
  504. /* }}} */
  505. /* {{{ _xml_add_to_info() */
  506. static void _xml_add_to_info(xml_parser *parser,char *name)
  507. {
  508. zval *element;
  509. if (Z_ISUNDEF(parser->info)) {
  510. return;
  511. }
  512. if ((element = zend_hash_str_find(Z_ARRVAL(parser->info), name, strlen(name))) == NULL) {
  513. zval values;
  514. array_init(&values);
  515. element = zend_hash_str_update(Z_ARRVAL(parser->info), name, strlen(name), &values);
  516. }
  517. add_next_index_long(element, parser->curtag);
  518. parser->curtag++;
  519. }
  520. /* }}} */
  521. /* {{{ _xml_decode_tag() */
  522. static zend_string *_xml_decode_tag(xml_parser *parser, const char *tag)
  523. {
  524. zend_string *str;
  525. str = xml_utf8_decode((const XML_Char *)tag, strlen(tag), parser->target_encoding);
  526. if (parser->case_folding) {
  527. php_strtoupper(ZSTR_VAL(str), ZSTR_LEN(str));
  528. }
  529. return str;
  530. }
  531. /* }}} */
  532. /* {{{ _xml_startElementHandler() */
  533. void _xml_startElementHandler(void *userData, const XML_Char *name, const XML_Char **attributes)
  534. {
  535. xml_parser *parser = (xml_parser *)userData;
  536. const char **attrs = (const char **) attributes;
  537. zend_string *att, *tag_name, *val;
  538. zval retval, args[3];
  539. if (parser) {
  540. parser->level++;
  541. tag_name = _xml_decode_tag(parser, (const char *)name);
  542. if (!Z_ISUNDEF(parser->startElementHandler)) {
  543. ZVAL_COPY(&args[0], &parser->index);
  544. ZVAL_STRING(&args[1], SKIP_TAGSTART(ZSTR_VAL(tag_name)));
  545. array_init(&args[2]);
  546. while (attributes && *attributes) {
  547. zval tmp;
  548. att = _xml_decode_tag(parser, (const char *)attributes[0]);
  549. val = xml_utf8_decode(attributes[1], strlen((char *)attributes[1]), parser->target_encoding);
  550. ZVAL_STR(&tmp, val);
  551. zend_symtable_update(Z_ARRVAL(args[2]), att, &tmp);
  552. attributes += 2;
  553. zend_string_release_ex(att, 0);
  554. }
  555. xml_call_handler(parser, &parser->startElementHandler, parser->startElementPtr, 3, args, &retval);
  556. zval_ptr_dtor(&retval);
  557. }
  558. if (!Z_ISUNDEF(parser->data)) {
  559. if (parser->level <= XML_MAXLEVEL) {
  560. zval tag, atr;
  561. int atcnt = 0;
  562. array_init(&tag);
  563. array_init(&atr);
  564. _xml_add_to_info(parser, ZSTR_VAL(tag_name) + parser->toffset);
  565. add_assoc_string(&tag, "tag", SKIP_TAGSTART(ZSTR_VAL(tag_name))); /* cast to avoid gcc-warning */
  566. add_assoc_string(&tag, "type", "open");
  567. add_assoc_long(&tag, "level", parser->level);
  568. parser->ltags[parser->level-1] = estrdup(ZSTR_VAL(tag_name));
  569. parser->lastwasopen = 1;
  570. attributes = (const XML_Char **) attrs;
  571. while (attributes && *attributes) {
  572. zval tmp;
  573. att = _xml_decode_tag(parser, (const char *)attributes[0]);
  574. val = xml_utf8_decode(attributes[1], strlen((char *)attributes[1]), parser->target_encoding);
  575. ZVAL_STR(&tmp, val);
  576. zend_symtable_update(Z_ARRVAL(atr), att, &tmp);
  577. atcnt++;
  578. attributes += 2;
  579. zend_string_release_ex(att, 0);
  580. }
  581. if (atcnt) {
  582. zend_hash_str_add(Z_ARRVAL(tag), "attributes", sizeof("attributes") - 1, &atr);
  583. } else {
  584. zval_ptr_dtor(&atr);
  585. }
  586. parser->ctag = zend_hash_next_index_insert(Z_ARRVAL(parser->data), &tag);
  587. } else if (parser->level == (XML_MAXLEVEL + 1)) {
  588. php_error_docref(NULL, E_WARNING, "Maximum depth exceeded - Results truncated");
  589. }
  590. }
  591. zend_string_release_ex(tag_name, 0);
  592. }
  593. }
  594. /* }}} */
  595. /* {{{ _xml_endElementHandler() */
  596. void _xml_endElementHandler(void *userData, const XML_Char *name)
  597. {
  598. xml_parser *parser = (xml_parser *)userData;
  599. if (parser) {
  600. zval retval, args[2];
  601. zend_string *tag_name = _xml_decode_tag(parser, (const char *)name);
  602. if (!Z_ISUNDEF(parser->endElementHandler)) {
  603. ZVAL_COPY(&args[0], &parser->index);
  604. ZVAL_STRING(&args[1], SKIP_TAGSTART(ZSTR_VAL(tag_name)));
  605. xml_call_handler(parser, &parser->endElementHandler, parser->endElementPtr, 2, args, &retval);
  606. zval_ptr_dtor(&retval);
  607. }
  608. if (!Z_ISUNDEF(parser->data)) {
  609. zval tag;
  610. if (parser->lastwasopen) {
  611. add_assoc_string(parser->ctag, "type", "complete");
  612. } else {
  613. array_init(&tag);
  614. _xml_add_to_info(parser, ZSTR_VAL(tag_name) + parser->toffset);
  615. add_assoc_string(&tag, "tag", SKIP_TAGSTART(ZSTR_VAL(tag_name))); /* cast to avoid gcc-warning */
  616. add_assoc_string(&tag, "type", "close");
  617. add_assoc_long(&tag, "level", parser->level);
  618. zend_hash_next_index_insert(Z_ARRVAL(parser->data), &tag);
  619. }
  620. parser->lastwasopen = 0;
  621. }
  622. zend_string_release_ex(tag_name, 0);
  623. if ((parser->ltags) && (parser->level <= XML_MAXLEVEL)) {
  624. efree(parser->ltags[parser->level-1]);
  625. }
  626. parser->level--;
  627. }
  628. }
  629. /* }}} */
  630. /* {{{ _xml_characterDataHandler() */
  631. void _xml_characterDataHandler(void *userData, const XML_Char *s, int len)
  632. {
  633. xml_parser *parser = (xml_parser *)userData;
  634. if (parser) {
  635. zval retval, args[2];
  636. if (!Z_ISUNDEF(parser->characterDataHandler)) {
  637. ZVAL_COPY(&args[0], &parser->index);
  638. _xml_xmlchar_zval(s, len, parser->target_encoding, &args[1]);
  639. xml_call_handler(parser, &parser->characterDataHandler, parser->characterDataPtr, 2, args, &retval);
  640. zval_ptr_dtor(&retval);
  641. }
  642. if (!Z_ISUNDEF(parser->data)) {
  643. size_t i;
  644. int doprint = 0;
  645. zend_string *decoded_value;
  646. decoded_value = xml_utf8_decode(s, len, parser->target_encoding);
  647. for (i = 0; i < ZSTR_LEN(decoded_value); i++) {
  648. switch (ZSTR_VAL(decoded_value)[i]) {
  649. case ' ':
  650. case '\t':
  651. case '\n':
  652. continue;
  653. default:
  654. doprint = 1;
  655. break;
  656. }
  657. if (doprint) {
  658. break;
  659. }
  660. }
  661. if (doprint || (! parser->skipwhite)) {
  662. if (parser->lastwasopen) {
  663. zval *myval;
  664. /* check if the current tag already has a value - if yes append to that! */
  665. if ((myval = zend_hash_str_find(Z_ARRVAL_P(parser->ctag), "value", sizeof("value") - 1))) {
  666. int newlen = Z_STRLEN_P(myval) + ZSTR_LEN(decoded_value);
  667. Z_STR_P(myval) = zend_string_extend(Z_STR_P(myval), newlen, 0);
  668. strncpy(Z_STRVAL_P(myval) + Z_STRLEN_P(myval) - ZSTR_LEN(decoded_value),
  669. ZSTR_VAL(decoded_value), ZSTR_LEN(decoded_value) + 1);
  670. zend_string_release_ex(decoded_value, 0);
  671. } else {
  672. add_assoc_str(parser->ctag, "value", decoded_value);
  673. }
  674. } else {
  675. zval tag;
  676. zval *curtag, *mytype, *myval;
  677. ZEND_HASH_REVERSE_FOREACH_VAL(Z_ARRVAL(parser->data), curtag) {
  678. if ((mytype = zend_hash_str_find(Z_ARRVAL_P(curtag),"type", sizeof("type") - 1))) {
  679. if (!strcmp(Z_STRVAL_P(mytype), "cdata")) {
  680. if ((myval = zend_hash_str_find(Z_ARRVAL_P(curtag), "value", sizeof("value") - 1))) {
  681. int newlen = Z_STRLEN_P(myval) + ZSTR_LEN(decoded_value);
  682. Z_STR_P(myval) = zend_string_extend(Z_STR_P(myval), newlen, 0);
  683. strncpy(Z_STRVAL_P(myval) + Z_STRLEN_P(myval) - ZSTR_LEN(decoded_value),
  684. ZSTR_VAL(decoded_value), ZSTR_LEN(decoded_value) + 1);
  685. zend_string_release_ex(decoded_value, 0);
  686. return;
  687. }
  688. }
  689. }
  690. break;
  691. } ZEND_HASH_FOREACH_END();
  692. if (parser->level <= XML_MAXLEVEL && parser->level > 0) {
  693. array_init(&tag);
  694. _xml_add_to_info(parser,SKIP_TAGSTART(parser->ltags[parser->level-1]));
  695. add_assoc_string(&tag, "tag", SKIP_TAGSTART(parser->ltags[parser->level-1]));
  696. add_assoc_str(&tag, "value", decoded_value);
  697. add_assoc_string(&tag, "type", "cdata");
  698. add_assoc_long(&tag, "level", parser->level);
  699. zend_hash_next_index_insert(Z_ARRVAL(parser->data), &tag);
  700. } else if (parser->level == (XML_MAXLEVEL + 1)) {
  701. php_error_docref(NULL, E_WARNING, "Maximum depth exceeded - Results truncated");
  702. }
  703. }
  704. } else {
  705. zend_string_release_ex(decoded_value, 0);
  706. }
  707. }
  708. }
  709. }
  710. /* }}} */
  711. /* {{{ _xml_processingInstructionHandler() */
  712. void _xml_processingInstructionHandler(void *userData, const XML_Char *target, const XML_Char *data)
  713. {
  714. xml_parser *parser = (xml_parser *)userData;
  715. if (parser && !Z_ISUNDEF(parser->processingInstructionHandler)) {
  716. zval retval, args[3];
  717. ZVAL_COPY(&args[0], &parser->index);
  718. _xml_xmlchar_zval(target, 0, parser->target_encoding, &args[1]);
  719. _xml_xmlchar_zval(data, 0, parser->target_encoding, &args[2]);
  720. xml_call_handler(parser, &parser->processingInstructionHandler, parser->processingInstructionPtr, 3, args, &retval);
  721. zval_ptr_dtor(&retval);
  722. }
  723. }
  724. /* }}} */
  725. /* {{{ _xml_defaultHandler() */
  726. void _xml_defaultHandler(void *userData, const XML_Char *s, int len)
  727. {
  728. xml_parser *parser = (xml_parser *)userData;
  729. if (parser && !Z_ISUNDEF(parser->defaultHandler)) {
  730. zval retval, args[2];
  731. ZVAL_COPY(&args[0], &parser->index);
  732. _xml_xmlchar_zval(s, len, parser->target_encoding, &args[1]);
  733. xml_call_handler(parser, &parser->defaultHandler, parser->defaultPtr, 2, args, &retval);
  734. zval_ptr_dtor(&retval);
  735. }
  736. }
  737. /* }}} */
  738. /* {{{ _xml_unparsedEntityDeclHandler() */
  739. void _xml_unparsedEntityDeclHandler(void *userData,
  740. const XML_Char *entityName,
  741. const XML_Char *base,
  742. const XML_Char *systemId,
  743. const XML_Char *publicId,
  744. const XML_Char *notationName)
  745. {
  746. xml_parser *parser = (xml_parser *)userData;
  747. if (parser && !Z_ISUNDEF(parser->unparsedEntityDeclHandler)) {
  748. zval retval, args[6];
  749. ZVAL_COPY(&args[0], &parser->index);
  750. _xml_xmlchar_zval(entityName, 0, parser->target_encoding, &args[1]);
  751. _xml_xmlchar_zval(base, 0, parser->target_encoding, &args[2]);
  752. _xml_xmlchar_zval(systemId, 0, parser->target_encoding, &args[3]);
  753. _xml_xmlchar_zval(publicId, 0, parser->target_encoding, &args[4]);
  754. _xml_xmlchar_zval(notationName, 0, parser->target_encoding, &args[5]);
  755. xml_call_handler(parser, &parser->unparsedEntityDeclHandler, parser->unparsedEntityDeclPtr, 6, args, &retval);
  756. zval_ptr_dtor(&retval);
  757. }
  758. }
  759. /* }}} */
  760. /* {{{ _xml_notationDeclHandler() */
  761. void _xml_notationDeclHandler(void *userData,
  762. const XML_Char *notationName,
  763. const XML_Char *base,
  764. const XML_Char *systemId,
  765. const XML_Char *publicId)
  766. {
  767. xml_parser *parser = (xml_parser *)userData;
  768. if (parser && !Z_ISUNDEF(parser->notationDeclHandler)) {
  769. zval retval, args[5];
  770. ZVAL_COPY(&args[0], &parser->index);
  771. _xml_xmlchar_zval(notationName, 0, parser->target_encoding, &args[1]);
  772. _xml_xmlchar_zval(base, 0, parser->target_encoding, &args[2]);
  773. _xml_xmlchar_zval(systemId, 0, parser->target_encoding, &args[3]);
  774. _xml_xmlchar_zval(publicId, 0, parser->target_encoding, &args[4]);
  775. xml_call_handler(parser, &parser->notationDeclHandler, parser->notationDeclPtr, 5, args, &retval);
  776. zval_ptr_dtor(&retval);
  777. }
  778. }
  779. /* }}} */
  780. /* {{{ _xml_externalEntityRefHandler() */
  781. int _xml_externalEntityRefHandler(XML_Parser parserPtr,
  782. const XML_Char *openEntityNames,
  783. const XML_Char *base,
  784. const XML_Char *systemId,
  785. const XML_Char *publicId)
  786. {
  787. xml_parser *parser = XML_GetUserData(parserPtr);
  788. int ret = 0; /* abort if no handler is set (should be configurable?) */
  789. if (parser && !Z_ISUNDEF(parser->externalEntityRefHandler)) {
  790. zval retval, args[5];
  791. ZVAL_COPY(&args[0], &parser->index);
  792. _xml_xmlchar_zval(openEntityNames, 0, parser->target_encoding, &args[1]);
  793. _xml_xmlchar_zval(base, 0, parser->target_encoding, &args[2]);
  794. _xml_xmlchar_zval(systemId, 0, parser->target_encoding, &args[3]);
  795. _xml_xmlchar_zval(publicId, 0, parser->target_encoding, &args[4]);
  796. xml_call_handler(parser, &parser->externalEntityRefHandler, parser->externalEntityRefPtr, 5, args, &retval);
  797. if (!Z_ISUNDEF(retval)) {
  798. convert_to_long(&retval);
  799. ret = Z_LVAL(retval);
  800. } else {
  801. ret = 0;
  802. }
  803. }
  804. return ret;
  805. }
  806. /* }}} */
  807. /* {{{ _xml_startNamespaceDeclHandler() */
  808. void _xml_startNamespaceDeclHandler(void *userData,const XML_Char *prefix, const XML_Char *uri)
  809. {
  810. xml_parser *parser = (xml_parser *)userData;
  811. if (parser && !Z_ISUNDEF(parser->startNamespaceDeclHandler)) {
  812. zval retval, args[3];
  813. ZVAL_COPY(&args[0], &parser->index);
  814. _xml_xmlchar_zval(prefix, 0, parser->target_encoding, &args[1]);
  815. _xml_xmlchar_zval(uri, 0, parser->target_encoding, &args[2]);
  816. xml_call_handler(parser, &parser->startNamespaceDeclHandler, parser->startNamespaceDeclPtr, 3, args, &retval);
  817. zval_ptr_dtor(&retval);
  818. }
  819. }
  820. /* }}} */
  821. /* {{{ _xml_endNamespaceDeclHandler() */
  822. void _xml_endNamespaceDeclHandler(void *userData, const XML_Char *prefix)
  823. {
  824. xml_parser *parser = (xml_parser *)userData;
  825. if (parser && !Z_ISUNDEF(parser->endNamespaceDeclHandler)) {
  826. zval retval, args[2];
  827. ZVAL_COPY(&args[0], &parser->index);
  828. _xml_xmlchar_zval(prefix, 0, parser->target_encoding, &args[1]);
  829. xml_call_handler(parser, &parser->endNamespaceDeclHandler, parser->endNamespaceDeclPtr, 2, args, &retval);
  830. zval_ptr_dtor(&retval);
  831. }
  832. }
  833. /* }}} */
  834. /************************* EXTENSION FUNCTIONS *************************/
  835. static void php_xml_parser_create_impl(INTERNAL_FUNCTION_PARAMETERS, int ns_support) /* {{{ */
  836. {
  837. xml_parser *parser;
  838. int auto_detect = 0;
  839. char *encoding_param = NULL;
  840. size_t encoding_param_len = 0;
  841. char *ns_param = NULL;
  842. size_t ns_param_len = 0;
  843. XML_Char *encoding;
  844. if (zend_parse_parameters(ZEND_NUM_ARGS(), (ns_support ? "|s!s": "|s!"), &encoding_param, &encoding_param_len, &ns_param, &ns_param_len) == FAILURE) {
  845. RETURN_THROWS();
  846. }
  847. if (encoding_param != NULL) {
  848. /* The supported encoding types are hardcoded here because
  849. * we are limited to the encodings supported by expat/xmltok.
  850. */
  851. if (encoding_param_len == 0) {
  852. encoding = XML(default_encoding);
  853. auto_detect = 1;
  854. } else if (strcasecmp(encoding_param, "ISO-8859-1") == 0) {
  855. encoding = (XML_Char*)"ISO-8859-1";
  856. } else if (strcasecmp(encoding_param, "UTF-8") == 0) {
  857. encoding = (XML_Char*)"UTF-8";
  858. } else if (strcasecmp(encoding_param, "US-ASCII") == 0) {
  859. encoding = (XML_Char*)"US-ASCII";
  860. } else {
  861. php_error_docref(NULL, E_WARNING, "Unsupported source encoding \"%s\"", encoding_param);
  862. RETURN_FALSE;
  863. }
  864. } else {
  865. encoding = XML(default_encoding);
  866. }
  867. if (ns_support && ns_param == NULL){
  868. ns_param = ":";
  869. }
  870. object_init_ex(return_value, xml_parser_ce);
  871. parser = Z_XMLPARSER_P(return_value);
  872. parser->parser = XML_ParserCreate_MM((auto_detect ? NULL : encoding),
  873. &php_xml_mem_hdlrs, (XML_Char*)ns_param);
  874. parser->target_encoding = encoding;
  875. parser->case_folding = 1;
  876. parser->isparsing = 0;
  877. XML_SetUserData(parser->parser, parser);
  878. ZVAL_COPY_VALUE(&parser->index, return_value);
  879. }
  880. /* }}} */
  881. /* {{{ proto resource xml_parser_create([string encoding])
  882. Create an XML parser */
  883. PHP_FUNCTION(xml_parser_create)
  884. {
  885. php_xml_parser_create_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
  886. }
  887. /* }}} */
  888. /* {{{ proto resource xml_parser_create_ns([string encoding [, string sep]])
  889. Create an XML parser */
  890. PHP_FUNCTION(xml_parser_create_ns)
  891. {
  892. php_xml_parser_create_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
  893. }
  894. /* }}} */
  895. /* {{{ proto int xml_set_object(resource parser, object &obj)
  896. Set up object which should be used for callbacks */
  897. PHP_FUNCTION(xml_set_object)
  898. {
  899. xml_parser *parser;
  900. zval *pind, *mythis;
  901. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oo", &pind, xml_parser_ce, &mythis) == FAILURE) {
  902. RETURN_THROWS();
  903. }
  904. parser = Z_XMLPARSER_P(pind);
  905. zval_ptr_dtor(&parser->object);
  906. Z_ADDREF_P(mythis);
  907. ZVAL_OBJ(&parser->object, Z_OBJ_P(mythis));
  908. RETVAL_TRUE;
  909. }
  910. /* }}} */
  911. /* {{{ proto int xml_set_element_handler(resource parser, string shdl, string ehdl)
  912. Set up start and end element handlers */
  913. PHP_FUNCTION(xml_set_element_handler)
  914. {
  915. xml_parser *parser;
  916. zval *pind, *shdl, *ehdl;
  917. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ozz", &pind, xml_parser_ce, &shdl, &ehdl) == FAILURE) {
  918. RETURN_THROWS();
  919. }
  920. parser = Z_XMLPARSER_P(pind);
  921. xml_set_handler(&parser->startElementHandler, shdl);
  922. xml_set_handler(&parser->endElementHandler, ehdl);
  923. XML_SetElementHandler(parser->parser, _xml_startElementHandler, _xml_endElementHandler);
  924. RETVAL_TRUE;
  925. }
  926. /* }}} */
  927. /* {{{ proto int xml_set_character_data_handler(resource parser, string hdl)
  928. Set up character data handler */
  929. PHP_FUNCTION(xml_set_character_data_handler)
  930. {
  931. xml_parser *parser;
  932. zval *pind, *hdl;
  933. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oz", &pind, xml_parser_ce, &hdl) == FAILURE) {
  934. RETURN_THROWS();
  935. }
  936. parser = Z_XMLPARSER_P(pind);
  937. xml_set_handler(&parser->characterDataHandler, hdl);
  938. XML_SetCharacterDataHandler(parser->parser, _xml_characterDataHandler);
  939. RETVAL_TRUE;
  940. }
  941. /* }}} */
  942. /* {{{ proto int xml_set_processing_instruction_handler(resource parser, string hdl)
  943. Set up processing instruction (PI) handler */
  944. PHP_FUNCTION(xml_set_processing_instruction_handler)
  945. {
  946. xml_parser *parser;
  947. zval *pind, *hdl;
  948. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oz", &pind, xml_parser_ce, &hdl) == FAILURE) {
  949. RETURN_THROWS();
  950. }
  951. parser = Z_XMLPARSER_P(pind);
  952. xml_set_handler(&parser->processingInstructionHandler, hdl);
  953. XML_SetProcessingInstructionHandler(parser->parser, _xml_processingInstructionHandler);
  954. RETVAL_TRUE;
  955. }
  956. /* }}} */
  957. /* {{{ proto int xml_set_default_handler(resource parser, string hdl)
  958. Set up default handler */
  959. PHP_FUNCTION(xml_set_default_handler)
  960. {
  961. xml_parser *parser;
  962. zval *pind, *hdl;
  963. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oz", &pind, xml_parser_ce, &hdl) == FAILURE) {
  964. RETURN_THROWS();
  965. }
  966. parser = Z_XMLPARSER_P(pind);
  967. xml_set_handler(&parser->defaultHandler, hdl);
  968. XML_SetDefaultHandler(parser->parser, _xml_defaultHandler);
  969. RETVAL_TRUE;
  970. }
  971. /* }}} */
  972. /* {{{ proto int xml_set_unparsed_entity_decl_handler(resource parser, string hdl)
  973. Set up unparsed entity declaration handler */
  974. PHP_FUNCTION(xml_set_unparsed_entity_decl_handler)
  975. {
  976. xml_parser *parser;
  977. zval *pind, *hdl;
  978. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oz", &pind, xml_parser_ce, &hdl) == FAILURE) {
  979. RETURN_THROWS();
  980. }
  981. parser = Z_XMLPARSER_P(pind);
  982. xml_set_handler(&parser->unparsedEntityDeclHandler, hdl);
  983. XML_SetUnparsedEntityDeclHandler(parser->parser, _xml_unparsedEntityDeclHandler);
  984. RETVAL_TRUE;
  985. }
  986. /* }}} */
  987. /* {{{ proto int xml_set_notation_decl_handler(resource parser, string hdl)
  988. Set up notation declaration handler */
  989. PHP_FUNCTION(xml_set_notation_decl_handler)
  990. {
  991. xml_parser *parser;
  992. zval *pind, *hdl;
  993. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oz", &pind, xml_parser_ce, &hdl) == FAILURE) {
  994. RETURN_THROWS();
  995. }
  996. parser = Z_XMLPARSER_P(pind);
  997. xml_set_handler(&parser->notationDeclHandler, hdl);
  998. XML_SetNotationDeclHandler(parser->parser, _xml_notationDeclHandler);
  999. RETVAL_TRUE;
  1000. }
  1001. /* }}} */
  1002. /* {{{ proto int xml_set_external_entity_ref_handler(resource parser, string hdl)
  1003. Set up external entity reference handler */
  1004. PHP_FUNCTION(xml_set_external_entity_ref_handler)
  1005. {
  1006. xml_parser *parser;
  1007. zval *pind, *hdl;
  1008. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oz", &pind, xml_parser_ce, &hdl) == FAILURE) {
  1009. RETURN_THROWS();
  1010. }
  1011. parser = Z_XMLPARSER_P(pind);
  1012. xml_set_handler(&parser->externalEntityRefHandler, hdl);
  1013. XML_SetExternalEntityRefHandler(parser->parser, (void *) _xml_externalEntityRefHandler);
  1014. RETVAL_TRUE;
  1015. }
  1016. /* }}} */
  1017. /* {{{ proto int xml_set_start_namespace_decl_handler(resource parser, string hdl)
  1018. Set up character data handler */
  1019. PHP_FUNCTION(xml_set_start_namespace_decl_handler)
  1020. {
  1021. xml_parser *parser;
  1022. zval *pind, *hdl;
  1023. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oz", &pind, xml_parser_ce, &hdl) == FAILURE) {
  1024. RETURN_THROWS();
  1025. }
  1026. parser = Z_XMLPARSER_P(pind);
  1027. xml_set_handler(&parser->startNamespaceDeclHandler, hdl);
  1028. XML_SetStartNamespaceDeclHandler(parser->parser, _xml_startNamespaceDeclHandler);
  1029. RETVAL_TRUE;
  1030. }
  1031. /* }}} */
  1032. /* {{{ proto int xml_set_end_namespace_decl_handler(resource parser, string hdl)
  1033. Set up character data handler */
  1034. PHP_FUNCTION(xml_set_end_namespace_decl_handler)
  1035. {
  1036. xml_parser *parser;
  1037. zval *pind, *hdl;
  1038. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oz", &pind, xml_parser_ce, &hdl) == FAILURE) {
  1039. RETURN_THROWS();
  1040. }
  1041. parser = Z_XMLPARSER_P(pind);
  1042. xml_set_handler(&parser->endNamespaceDeclHandler, hdl);
  1043. XML_SetEndNamespaceDeclHandler(parser->parser, _xml_endNamespaceDeclHandler);
  1044. RETVAL_TRUE;
  1045. }
  1046. /* }}} */
  1047. /* {{{ proto int xml_parse(resource parser, string data [, bool isFinal])
  1048. Start parsing an XML document */
  1049. PHP_FUNCTION(xml_parse)
  1050. {
  1051. xml_parser *parser;
  1052. zval *pind;
  1053. char *data;
  1054. size_t data_len;
  1055. int ret;
  1056. zend_bool isFinal = 0;
  1057. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os|b", &pind, xml_parser_ce, &data, &data_len, &isFinal) == FAILURE) {
  1058. RETURN_THROWS();
  1059. }
  1060. parser = Z_XMLPARSER_P(pind);
  1061. parser->isparsing = 1;
  1062. ret = XML_Parse(parser->parser, (XML_Char*)data, data_len, isFinal);
  1063. parser->isparsing = 0;
  1064. RETVAL_LONG(ret);
  1065. }
  1066. /* }}} */
  1067. /* {{{ proto int xml_parse_into_struct(resource parser, string data, array &values [, array &index ])
  1068. Parsing a XML document */
  1069. PHP_FUNCTION(xml_parse_into_struct)
  1070. {
  1071. xml_parser *parser;
  1072. zval *pind, *xdata, *info = NULL;
  1073. char *data;
  1074. size_t data_len;
  1075. int ret;
  1076. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Osz|z", &pind, xml_parser_ce, &data, &data_len, &xdata, &info) == FAILURE) {
  1077. RETURN_THROWS();
  1078. }
  1079. parser = Z_XMLPARSER_P(pind);
  1080. if (info) {
  1081. info = zend_try_array_init(info);
  1082. if (!info) {
  1083. RETURN_THROWS();
  1084. }
  1085. }
  1086. xdata = zend_try_array_init(xdata);
  1087. if (!xdata) {
  1088. RETURN_THROWS();
  1089. }
  1090. ZVAL_COPY_VALUE(&parser->data, xdata);
  1091. if (info) {
  1092. ZVAL_COPY_VALUE(&parser->info, info);
  1093. }
  1094. parser->level = 0;
  1095. parser->ltags = safe_emalloc(XML_MAXLEVEL, sizeof(char *), 0);
  1096. XML_SetElementHandler(parser->parser, _xml_startElementHandler, _xml_endElementHandler);
  1097. XML_SetCharacterDataHandler(parser->parser, _xml_characterDataHandler);
  1098. parser->isparsing = 1;
  1099. ret = XML_Parse(parser->parser, (XML_Char*)data, data_len, 1);
  1100. parser->isparsing = 0;
  1101. RETVAL_LONG(ret);
  1102. }
  1103. /* }}} */
  1104. /* {{{ proto int xml_get_error_code(resource parser)
  1105. Get XML parser error code */
  1106. PHP_FUNCTION(xml_get_error_code)
  1107. {
  1108. xml_parser *parser;
  1109. zval *pind;
  1110. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pind, xml_parser_ce) == FAILURE) {
  1111. RETURN_THROWS();
  1112. }
  1113. parser = Z_XMLPARSER_P(pind);
  1114. RETURN_LONG((zend_long)XML_GetErrorCode(parser->parser));
  1115. }
  1116. /* }}} */
  1117. /* {{{ proto string xml_error_string(int code)
  1118. Get XML parser error string */
  1119. PHP_FUNCTION(xml_error_string)
  1120. {
  1121. zend_long code;
  1122. char *str;
  1123. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &code) == FAILURE) {
  1124. RETURN_THROWS();
  1125. }
  1126. str = (char *)XML_ErrorString((int)code);
  1127. if (str) {
  1128. RETVAL_STRING(str);
  1129. }
  1130. }
  1131. /* }}} */
  1132. /* {{{ proto int xml_get_current_line_number(resource parser)
  1133. Get current line number for an XML parser */
  1134. PHP_FUNCTION(xml_get_current_line_number)
  1135. {
  1136. xml_parser *parser;
  1137. zval *pind;
  1138. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pind, xml_parser_ce) == FAILURE) {
  1139. RETURN_THROWS();
  1140. }
  1141. parser = Z_XMLPARSER_P(pind);
  1142. RETVAL_LONG(XML_GetCurrentLineNumber(parser->parser));
  1143. }
  1144. /* }}} */
  1145. /* {{{ proto int xml_get_current_column_number(resource parser)
  1146. Get current column number for an XML parser */
  1147. PHP_FUNCTION(xml_get_current_column_number)
  1148. {
  1149. xml_parser *parser;
  1150. zval *pind;
  1151. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pind, xml_parser_ce) == FAILURE) {
  1152. RETURN_THROWS();
  1153. }
  1154. parser = Z_XMLPARSER_P(pind);
  1155. RETVAL_LONG(XML_GetCurrentColumnNumber(parser->parser));
  1156. }
  1157. /* }}} */
  1158. /* {{{ proto int xml_get_current_byte_index(resource parser)
  1159. Get current byte index for an XML parser */
  1160. PHP_FUNCTION(xml_get_current_byte_index)
  1161. {
  1162. xml_parser *parser;
  1163. zval *pind;
  1164. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pind, xml_parser_ce) == FAILURE) {
  1165. RETURN_THROWS();
  1166. }
  1167. parser = Z_XMLPARSER_P(pind);
  1168. RETVAL_LONG(XML_GetCurrentByteIndex(parser->parser));
  1169. }
  1170. /* }}} */
  1171. /* {{{ proto int xml_parser_free(resource parser)
  1172. Free an XML parser */
  1173. PHP_FUNCTION(xml_parser_free)
  1174. {
  1175. zval *pind;
  1176. xml_parser *parser;
  1177. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pind, xml_parser_ce) == FAILURE) {
  1178. RETURN_THROWS();
  1179. }
  1180. parser = Z_XMLPARSER_P(pind);
  1181. if (parser->isparsing == 1) {
  1182. php_error_docref(NULL, E_WARNING, "Parser cannot be freed while it is parsing.");
  1183. RETURN_FALSE;
  1184. }
  1185. RETURN_TRUE;
  1186. }
  1187. /* }}} */
  1188. /* {{{ proto int xml_parser_set_option(resource parser, int option, mixed value)
  1189. Set options in an XML parser */
  1190. PHP_FUNCTION(xml_parser_set_option)
  1191. {
  1192. xml_parser *parser;
  1193. zval *pind, *val;
  1194. zend_long opt;
  1195. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olz", &pind, xml_parser_ce, &opt, &val) == FAILURE) {
  1196. RETURN_THROWS();
  1197. }
  1198. parser = Z_XMLPARSER_P(pind);
  1199. switch (opt) {
  1200. case PHP_XML_OPTION_CASE_FOLDING:
  1201. parser->case_folding = zval_get_long(val);
  1202. break;
  1203. case PHP_XML_OPTION_SKIP_TAGSTART:
  1204. parser->toffset = zval_get_long(val);
  1205. if (parser->toffset < 0) {
  1206. php_error_docref(NULL, E_NOTICE, "tagstart ignored, because it is out of range");
  1207. parser->toffset = 0;
  1208. }
  1209. break;
  1210. case PHP_XML_OPTION_SKIP_WHITE:
  1211. parser->skipwhite = zval_get_long(val);
  1212. break;
  1213. case PHP_XML_OPTION_TARGET_ENCODING: {
  1214. const xml_encoding *enc;
  1215. if (!try_convert_to_string(val)) {
  1216. RETURN_THROWS();
  1217. }
  1218. enc = xml_get_encoding((XML_Char*)Z_STRVAL_P(val));
  1219. if (enc == NULL) {
  1220. php_error_docref(NULL, E_WARNING, "Unsupported target encoding \"%s\"", Z_STRVAL_P(val));
  1221. RETURN_FALSE;
  1222. }
  1223. parser->target_encoding = enc->name;
  1224. break;
  1225. }
  1226. default:
  1227. php_error_docref(NULL, E_WARNING, "Unknown option");
  1228. RETURN_FALSE;
  1229. break;
  1230. }
  1231. RETVAL_TRUE;
  1232. }
  1233. /* }}} */
  1234. /* {{{ proto int xml_parser_get_option(resource parser, int option)
  1235. Get options from an XML parser */
  1236. PHP_FUNCTION(xml_parser_get_option)
  1237. {
  1238. xml_parser *parser;
  1239. zval *pind;
  1240. zend_long opt;
  1241. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &pind, xml_parser_ce, &opt) == FAILURE) {
  1242. RETURN_THROWS();
  1243. }
  1244. parser = Z_XMLPARSER_P(pind);
  1245. switch (opt) {
  1246. case PHP_XML_OPTION_CASE_FOLDING:
  1247. RETURN_LONG(parser->case_folding);
  1248. break;
  1249. case PHP_XML_OPTION_SKIP_TAGSTART:
  1250. RETURN_LONG(parser->toffset);
  1251. break;
  1252. case PHP_XML_OPTION_SKIP_WHITE:
  1253. RETURN_LONG(parser->skipwhite);
  1254. break;
  1255. case PHP_XML_OPTION_TARGET_ENCODING:
  1256. RETURN_STRING((char *)parser->target_encoding);
  1257. break;
  1258. default:
  1259. php_error_docref(NULL, E_WARNING, "Unknown option");
  1260. RETURN_FALSE;
  1261. break;
  1262. }
  1263. RETVAL_FALSE; /* never reached */
  1264. }
  1265. /* }}} */
  1266. #endif