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