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