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