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: Christian Stocker <chregu@php.net>                          |
16   |          Rob Richards <rrichards@php.net>                            |
17   +----------------------------------------------------------------------+
18*/
19
20/* $Id$ */
21
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
25
26#include "php.h"
27#if HAVE_LIBXML && HAVE_DOM
28#include "php_dom.h"
29#include <libxml/SAX.h>
30#ifdef LIBXML_SCHEMAS_ENABLED
31#include <libxml/relaxng.h>
32#include <libxml/xmlschemas.h>
33#endif
34
35typedef struct _idsIterator idsIterator;
36struct _idsIterator {
37    xmlChar *elementId;
38    xmlNode *element;
39};
40
41#define DOM_LOAD_STRING 0
42#define DOM_LOAD_FILE 1
43
44/* {{{ arginfo */
45ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_create_element, 0, 0, 1)
46    ZEND_ARG_INFO(0, tagName)
47    ZEND_ARG_INFO(0, value)
48ZEND_END_ARG_INFO();
49
50ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_create_document_fragment, 0, 0, 0)
51ZEND_END_ARG_INFO();
52
53ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_create_text_node, 0, 0, 1)
54    ZEND_ARG_INFO(0, data)
55ZEND_END_ARG_INFO();
56
57ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_create_comment, 0, 0, 1)
58    ZEND_ARG_INFO(0, data)
59ZEND_END_ARG_INFO();
60
61ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_create_cdatasection, 0, 0, 1)
62    ZEND_ARG_INFO(0, data)
63ZEND_END_ARG_INFO();
64
65ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_create_processing_instruction, 0, 0, 2)
66    ZEND_ARG_INFO(0, target)
67    ZEND_ARG_INFO(0, data)
68ZEND_END_ARG_INFO();
69
70ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_create_attribute, 0, 0, 1)
71    ZEND_ARG_INFO(0, name)
72ZEND_END_ARG_INFO();
73
74ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_create_entity_reference, 0, 0, 1)
75    ZEND_ARG_INFO(0, name)
76ZEND_END_ARG_INFO();
77
78ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_get_elements_by_tag_name, 0, 0, 1)
79    ZEND_ARG_INFO(0, tagName)
80ZEND_END_ARG_INFO();
81
82ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_import_node, 0, 0, 2)
83    ZEND_ARG_OBJ_INFO(0, importedNode, DOMNode, 0)
84    ZEND_ARG_INFO(0, deep)
85ZEND_END_ARG_INFO();
86
87ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_create_element_ns, 0, 0, 2)
88    ZEND_ARG_INFO(0, namespaceURI)
89    ZEND_ARG_INFO(0, qualifiedName)
90    ZEND_ARG_INFO(0, value)
91ZEND_END_ARG_INFO();
92
93ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_create_attribute_ns, 0, 0, 2)
94    ZEND_ARG_INFO(0, namespaceURI)
95    ZEND_ARG_INFO(0, qualifiedName)
96ZEND_END_ARG_INFO();
97
98ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_get_elements_by_tag_name_ns, 0, 0, 2)
99    ZEND_ARG_INFO(0, namespaceURI)
100    ZEND_ARG_INFO(0, localName)
101ZEND_END_ARG_INFO();
102
103ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_get_element_by_id, 0, 0, 1)
104    ZEND_ARG_INFO(0, elementId)
105ZEND_END_ARG_INFO();
106
107ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_adopt_node, 0, 0, 1)
108    ZEND_ARG_OBJ_INFO(0, source, DOMNode, 0)
109ZEND_END_ARG_INFO();
110
111ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_normalize_document, 0, 0, 0)
112ZEND_END_ARG_INFO();
113
114ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_rename_node, 0, 0, 3)
115    ZEND_ARG_OBJ_INFO(0, node, DOMNode, 0)
116    ZEND_ARG_INFO(0, namespaceURI)
117    ZEND_ARG_INFO(0, qualifiedName)
118ZEND_END_ARG_INFO();
119
120ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_load, 0, 0, 1)
121    ZEND_ARG_INFO(0, source)
122    ZEND_ARG_INFO(0, options)
123ZEND_END_ARG_INFO();
124
125ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_save, 0, 0, 1)
126    ZEND_ARG_INFO(0, file)
127ZEND_END_ARG_INFO();
128
129ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_loadxml, 0, 0, 1)
130    ZEND_ARG_INFO(0, source)
131    ZEND_ARG_INFO(0, options)
132ZEND_END_ARG_INFO();
133
134ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_savexml, 0, 0, 0)
135    ZEND_ARG_OBJ_INFO(0, node, DOMNode, 1)
136ZEND_END_ARG_INFO();
137
138ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_construct, 0, 0, 0)
139    ZEND_ARG_INFO(0, version)
140    ZEND_ARG_INFO(0, encoding)
141ZEND_END_ARG_INFO();
142
143ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_validate, 0, 0, 0)
144ZEND_END_ARG_INFO();
145
146ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_xinclude, 0, 0, 0)
147    ZEND_ARG_INFO(0, options)
148ZEND_END_ARG_INFO();
149
150ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_loadhtml, 0, 0, 1)
151    ZEND_ARG_INFO(0, source)
152ZEND_END_ARG_INFO();
153
154ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_loadhtmlfile, 0, 0, 1)
155    ZEND_ARG_INFO(0, source)
156ZEND_END_ARG_INFO();
157
158ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_savehtml, 0, 0, 0)
159ZEND_END_ARG_INFO();
160
161ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_savehtmlfile, 0, 0, 1)
162    ZEND_ARG_INFO(0, file)
163ZEND_END_ARG_INFO();
164
165ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_schema_validate_file, 0, 0, 1)
166    ZEND_ARG_INFO(0, filename)
167ZEND_END_ARG_INFO();
168
169ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_schema_validate_xml, 0, 0, 1)
170    ZEND_ARG_INFO(0, source)
171ZEND_END_ARG_INFO();
172
173ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_relaxNG_validate_file, 0, 0, 1)
174    ZEND_ARG_INFO(0, filename)
175ZEND_END_ARG_INFO();
176
177ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_relaxNG_validate_xml, 0, 0, 1)
178    ZEND_ARG_INFO(0, source)
179ZEND_END_ARG_INFO();
180
181ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_document_registernodeclass, 0, 0, 2)
182    ZEND_ARG_INFO(0, baseClass)
183    ZEND_ARG_INFO(0, extendedClass)
184ZEND_END_ARG_INFO();
185/* }}} */
186
187/*
188* class DOMDocument extends DOMNode
189*
190* URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-i-Document
191* Since:
192*/
193
194const zend_function_entry php_dom_document_class_functions[] = { /* {{{ */
195    PHP_FALIAS(createElement, dom_document_create_element, arginfo_dom_document_create_element)
196    PHP_FALIAS(createDocumentFragment, dom_document_create_document_fragment, arginfo_dom_document_create_document_fragment)
197    PHP_FALIAS(createTextNode, dom_document_create_text_node, arginfo_dom_document_create_text_node)
198    PHP_FALIAS(createComment, dom_document_create_comment, arginfo_dom_document_create_comment)
199    PHP_FALIAS(createCDATASection, dom_document_create_cdatasection, arginfo_dom_document_create_cdatasection)
200    PHP_FALIAS(createProcessingInstruction, dom_document_create_processing_instruction, arginfo_dom_document_create_processing_instruction)
201    PHP_FALIAS(createAttribute, dom_document_create_attribute, arginfo_dom_document_create_attribute)
202    PHP_FALIAS(createEntityReference, dom_document_create_entity_reference, arginfo_dom_document_create_entity_reference)
203    PHP_FALIAS(getElementsByTagName, dom_document_get_elements_by_tag_name, arginfo_dom_document_get_elements_by_tag_name)
204    PHP_FALIAS(importNode, dom_document_import_node, arginfo_dom_document_import_node)
205    PHP_FALIAS(createElementNS, dom_document_create_element_ns, arginfo_dom_document_create_element_ns)
206    PHP_FALIAS(createAttributeNS, dom_document_create_attribute_ns, arginfo_dom_document_create_attribute_ns)
207    PHP_FALIAS(getElementsByTagNameNS, dom_document_get_elements_by_tag_name_ns, arginfo_dom_document_get_elements_by_tag_name_ns)
208    PHP_FALIAS(getElementById, dom_document_get_element_by_id, arginfo_dom_document_get_element_by_id)
209    PHP_FALIAS(adoptNode, dom_document_adopt_node, arginfo_dom_document_adopt_node)
210    PHP_FALIAS(normalizeDocument, dom_document_normalize_document, arginfo_dom_document_normalize_document)
211    PHP_FALIAS(renameNode, dom_document_rename_node, arginfo_dom_document_rename_node)
212    PHP_ME(domdocument, load, arginfo_dom_document_load, ZEND_ACC_PUBLIC|ZEND_ACC_ALLOW_STATIC)
213    PHP_FALIAS(save, dom_document_save, arginfo_dom_document_save)
214    PHP_ME(domdocument, loadXML, arginfo_dom_document_loadxml, ZEND_ACC_PUBLIC|ZEND_ACC_ALLOW_STATIC)
215    PHP_FALIAS(saveXML, dom_document_savexml, arginfo_dom_document_savexml)
216    PHP_ME(domdocument, __construct, arginfo_dom_document_construct, ZEND_ACC_PUBLIC)
217    PHP_FALIAS(validate, dom_document_validate, arginfo_dom_document_validate)
218    PHP_FALIAS(xinclude, dom_document_xinclude, arginfo_dom_document_xinclude)
219#if defined(LIBXML_HTML_ENABLED)
220    PHP_ME(domdocument, loadHTML, arginfo_dom_document_loadhtml, ZEND_ACC_PUBLIC|ZEND_ACC_ALLOW_STATIC)
221    PHP_ME(domdocument, loadHTMLFile, arginfo_dom_document_loadhtmlfile, ZEND_ACC_PUBLIC|ZEND_ACC_ALLOW_STATIC)
222    PHP_FALIAS(saveHTML, dom_document_save_html, arginfo_dom_document_savehtml)
223    PHP_FALIAS(saveHTMLFile, dom_document_save_html_file, arginfo_dom_document_savehtmlfile)
224#endif  /* defined(LIBXML_HTML_ENABLED) */
225#if defined(LIBXML_SCHEMAS_ENABLED)
226    PHP_FALIAS(schemaValidate, dom_document_schema_validate_file, arginfo_dom_document_schema_validate_file)
227    PHP_FALIAS(schemaValidateSource, dom_document_schema_validate_xml, arginfo_dom_document_schema_validate_xml)
228    PHP_FALIAS(relaxNGValidate, dom_document_relaxNG_validate_file, arginfo_dom_document_relaxNG_validate_file)
229    PHP_FALIAS(relaxNGValidateSource, dom_document_relaxNG_validate_xml, arginfo_dom_document_relaxNG_validate_xml)
230#endif
231    PHP_ME(domdocument, registerNodeClass, arginfo_dom_document_registernodeclass, ZEND_ACC_PUBLIC)
232    PHP_FE_END
233};
234/* }}} */
235
236/* {{{ docType  DOMDocumentType
237readonly=yes
238URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-B63ED1A31
239Since:
240*/
241int dom_document_doctype_read(dom_object *obj, zval **retval TSRMLS_DC)
242{
243    xmlDoc *docp;
244    xmlDtdPtr dtdptr;
245    int ret;
246
247    docp = (xmlDocPtr) dom_object_get_node(obj);
248
249    if (docp == NULL) {
250        php_dom_throw_error(INVALID_STATE_ERR, 0 TSRMLS_CC);
251        return FAILURE;
252    }
253
254    ALLOC_ZVAL(*retval);
255
256    dtdptr = xmlGetIntSubset(docp);
257    if (!dtdptr) {
258        ZVAL_NULL(*retval);
259        return SUCCESS;
260    }
261
262    if (NULL == (*retval = php_dom_create_object((xmlNodePtr) dtdptr, &ret, NULL, *retval, obj TSRMLS_CC))) {
263        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot create required DOM object");
264        return FAILURE;
265    }
266    return SUCCESS;
267
268}
269
270/* }}} */
271
272/* {{{ implementation   DOMImplementation
273readonly=yes
274URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1B793EBA
275Since:
276*/
277int dom_document_implementation_read(dom_object *obj, zval **retval TSRMLS_DC)
278{
279    ALLOC_ZVAL(*retval);
280    php_dom_create_implementation(retval TSRMLS_CC);
281    return SUCCESS;
282}
283
284/* }}} */
285
286/* {{{ documentElement  DOMElement
287readonly=yes
288URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-87CD092
289Since:
290*/
291int dom_document_document_element_read(dom_object *obj, zval **retval TSRMLS_DC)
292{
293    xmlDoc *docp;
294    xmlNode *root;
295    int ret;
296
297    docp = (xmlDocPtr) dom_object_get_node(obj);
298
299    if (docp == NULL) {
300        php_dom_throw_error(INVALID_STATE_ERR, 0 TSRMLS_CC);
301        return FAILURE;
302    }
303
304    ALLOC_ZVAL(*retval);
305
306    root = xmlDocGetRootElement(docp);
307    if (!root) {
308        ZVAL_NULL(*retval);
309        return SUCCESS;
310    }
311
312    if (NULL == (*retval = php_dom_create_object(root, &ret, NULL, *retval, obj TSRMLS_CC))) {
313        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot create required DOM object");
314        return FAILURE;
315    }
316    return SUCCESS;
317}
318
319/* }}} */
320
321/* {{{ encoding string
322URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-Document3-encoding
323Since: DOM Level 3
324*/
325int dom_document_encoding_read(dom_object *obj, zval **retval TSRMLS_DC)
326{
327    xmlDoc *docp;
328    char *encoding;
329
330    docp = (xmlDocPtr) dom_object_get_node(obj);
331
332    if (docp == NULL) {
333        php_dom_throw_error(INVALID_STATE_ERR, 0 TSRMLS_CC);
334        return FAILURE;
335    }
336
337    encoding = (char *) docp->encoding;
338    ALLOC_ZVAL(*retval);
339
340    if (encoding != NULL) {
341        ZVAL_STRING(*retval, encoding, 1);
342    } else {
343        ZVAL_NULL(*retval);
344    }
345
346    return SUCCESS;
347}
348
349int dom_document_encoding_write(dom_object *obj, zval *newval TSRMLS_DC)
350{
351    zval value_copy;
352    xmlDoc *docp;
353    xmlCharEncodingHandlerPtr handler;
354
355    docp = (xmlDocPtr) dom_object_get_node(obj);
356
357    if (docp == NULL) {
358        php_dom_throw_error(INVALID_STATE_ERR, 0 TSRMLS_CC);
359        return FAILURE;
360    }
361
362    if (newval->type != IS_STRING) {
363        if(Z_REFCOUNT_P(newval) > 1) {
364            value_copy = *newval;
365            zval_copy_ctor(&value_copy);
366            newval = &value_copy;
367        }
368        convert_to_string(newval);
369    }
370
371    handler = xmlFindCharEncodingHandler(Z_STRVAL_P(newval));
372
373    if (handler != NULL) {
374        xmlCharEncCloseFunc(handler);
375        if (docp->encoding != NULL) {
376            xmlFree((xmlChar *)docp->encoding);
377        }
378        docp->encoding = xmlStrdup((const xmlChar *) Z_STRVAL_P(newval));
379    } else {
380        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Document Encoding");
381    }
382
383    if (newval == &value_copy) {
384        zval_dtor(newval);
385    }
386
387    return SUCCESS;
388}
389
390/* }}} */
391
392/* {{{ standalone   boolean
393readonly=no
394URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-Document3-standalone
395Since: DOM Level 3
396*/
397int dom_document_standalone_read(dom_object *obj, zval **retval TSRMLS_DC)
398{
399    xmlDoc *docp;
400    int standalone;
401
402    docp = (xmlDocPtr) dom_object_get_node(obj);
403
404    if (docp == NULL) {
405        php_dom_throw_error(INVALID_STATE_ERR, 0 TSRMLS_CC);
406        return FAILURE;
407    }
408
409    ALLOC_ZVAL(*retval);
410    standalone = docp->standalone;
411    ZVAL_BOOL(*retval, standalone);
412
413    return SUCCESS;
414}
415
416int dom_document_standalone_write(dom_object *obj, zval *newval TSRMLS_DC)
417{
418    zval value_copy;
419    xmlDoc *docp;
420    int standalone;
421
422    docp = (xmlDocPtr) dom_object_get_node(obj);
423
424    if (docp == NULL) {
425        php_dom_throw_error(INVALID_STATE_ERR, 0 TSRMLS_CC);
426        return FAILURE;
427    }
428
429    if(Z_REFCOUNT_P(newval) > 1) {
430        value_copy = *newval;
431        zval_copy_ctor(&value_copy);
432        newval = &value_copy;
433    }
434    convert_to_long(newval);
435
436    standalone = Z_LVAL_P(newval);
437    if (standalone > 0) {
438        docp->standalone = 1;
439    }
440    else if (standalone < 0) {
441        docp->standalone = -1;
442    }
443    else {
444        docp->standalone = 0;
445    }
446
447    if (newval == &value_copy) {
448        zval_dtor(newval);
449    }
450
451    return SUCCESS;
452}
453
454/* }}} */
455
456/* {{{ version  string
457readonly=no
458URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-Document3-version
459Since: DOM Level 3
460*/
461int dom_document_version_read(dom_object *obj, zval **retval TSRMLS_DC)
462{
463    xmlDoc *docp;
464    char *version;
465
466    docp = (xmlDocPtr) dom_object_get_node(obj);
467
468    if (docp == NULL) {
469        php_dom_throw_error(INVALID_STATE_ERR, 0 TSRMLS_CC);
470        return FAILURE;
471    }
472
473    version = (char *) docp->version;
474    ALLOC_ZVAL(*retval);
475
476    if (version != NULL) {
477        ZVAL_STRING(*retval, version, 1);
478    } else {
479        ZVAL_NULL(*retval);
480    }
481
482    return SUCCESS;
483}
484
485int dom_document_version_write(dom_object *obj, zval *newval TSRMLS_DC)
486{
487    zval value_copy;
488    xmlDoc *docp;
489
490    docp = (xmlDocPtr) dom_object_get_node(obj);
491
492    if (docp == NULL) {
493        php_dom_throw_error(INVALID_STATE_ERR, 0 TSRMLS_CC);
494        return FAILURE;
495    }
496
497    if (docp->version != NULL) {
498        xmlFree((xmlChar *) docp->version );
499    }
500
501    if (newval->type != IS_STRING) {
502        if(Z_REFCOUNT_P(newval) > 1) {
503            value_copy = *newval;
504            zval_copy_ctor(&value_copy);
505            newval = &value_copy;
506        }
507        convert_to_string(newval);
508    }
509
510    docp->version = xmlStrdup((const xmlChar *) Z_STRVAL_P(newval));
511
512    if (newval == &value_copy) {
513        zval_dtor(newval);
514    }
515
516    return SUCCESS;
517}
518
519/* }}} */
520
521/* {{{ strictErrorChecking  boolean
522readonly=no
523URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-Document3-strictErrorChecking
524Since: DOM Level 3
525*/
526int dom_document_strict_error_checking_read(dom_object *obj, zval **retval TSRMLS_DC)
527{
528    dom_doc_propsptr doc_prop;
529
530    ALLOC_ZVAL(*retval);
531    if (obj->document) {
532        doc_prop = dom_get_doc_props(obj->document);
533        ZVAL_BOOL(*retval, doc_prop->stricterror);
534    } else {
535        ZVAL_FALSE(*retval);
536    }
537    return SUCCESS;
538}
539
540int dom_document_strict_error_checking_write(dom_object *obj, zval *newval TSRMLS_DC)
541{
542    zval value_copy;
543    dom_doc_propsptr doc_prop;
544
545    if(Z_REFCOUNT_P(newval) > 1) {
546        value_copy = *newval;
547        zval_copy_ctor(&value_copy);
548        newval = &value_copy;
549    }
550    convert_to_boolean(newval);
551
552    if (obj->document) {
553        doc_prop = dom_get_doc_props(obj->document);
554        doc_prop->stricterror = Z_LVAL_P(newval);
555    }
556
557    if (newval == &value_copy) {
558        zval_dtor(newval);
559    }
560
561    return SUCCESS;
562}
563
564/* }}} */
565
566/* {{{ formatOutput boolean
567readonly=no
568*/
569int dom_document_format_output_read(dom_object *obj, zval **retval TSRMLS_DC)
570{
571    dom_doc_propsptr doc_prop;
572
573    ALLOC_ZVAL(*retval);
574    if (obj->document) {
575        doc_prop = dom_get_doc_props(obj->document);
576        ZVAL_BOOL(*retval, doc_prop->formatoutput);
577    } else {
578        ZVAL_FALSE(*retval);
579    }
580    return SUCCESS;
581}
582
583int dom_document_format_output_write(dom_object *obj, zval *newval TSRMLS_DC)
584{
585    zval value_copy;
586    dom_doc_propsptr doc_prop;
587
588    if(Z_REFCOUNT_P(newval) > 1) {
589        value_copy = *newval;
590        zval_copy_ctor(&value_copy);
591        newval = &value_copy;
592    }
593    convert_to_boolean(newval);
594
595    if (obj->document) {
596        doc_prop = dom_get_doc_props(obj->document);
597        doc_prop->formatoutput = Z_LVAL_P(newval);
598    }
599
600    if (newval == &value_copy) {
601        zval_dtor(newval);
602    }
603
604    return SUCCESS;
605}
606/* }}} */
607
608/* {{{ validateOnParse  boolean
609readonly=no
610*/
611int dom_document_validate_on_parse_read(dom_object *obj, zval **retval TSRMLS_DC)
612{
613    dom_doc_propsptr doc_prop;
614
615    ALLOC_ZVAL(*retval);
616    if (obj->document) {
617        doc_prop = dom_get_doc_props(obj->document);
618        ZVAL_BOOL(*retval, doc_prop->validateonparse);
619    } else {
620        ZVAL_FALSE(*retval);
621    }
622    return SUCCESS;
623}
624
625int dom_document_validate_on_parse_write(dom_object *obj, zval *newval TSRMLS_DC)
626{
627    zval value_copy;
628    dom_doc_propsptr doc_prop;
629
630    if(Z_REFCOUNT_P(newval) > 1) {
631        value_copy = *newval;
632        zval_copy_ctor(&value_copy);
633        newval = &value_copy;
634    }
635    convert_to_boolean(newval);
636
637    if (obj->document) {
638        doc_prop = dom_get_doc_props(obj->document);
639        doc_prop->validateonparse = Z_LVAL_P(newval);
640    }
641
642    if (newval == &value_copy) {
643        zval_dtor(newval);
644    }
645
646    return SUCCESS;
647}
648/* }}} */
649
650/* {{{ resolveExternals boolean
651readonly=no
652*/
653int dom_document_resolve_externals_read(dom_object *obj, zval **retval TSRMLS_DC)
654{
655    dom_doc_propsptr doc_prop;
656
657    ALLOC_ZVAL(*retval);
658    if (obj->document) {
659        doc_prop = dom_get_doc_props(obj->document);
660        ZVAL_BOOL(*retval, doc_prop->resolveexternals);
661    } else {
662        ZVAL_FALSE(*retval);
663    }
664    return SUCCESS;
665}
666
667int dom_document_resolve_externals_write(dom_object *obj, zval *newval TSRMLS_DC)
668{
669    zval value_copy;
670    dom_doc_propsptr doc_prop;
671
672    if(Z_REFCOUNT_P(newval) > 1) {
673        value_copy = *newval;
674        zval_copy_ctor(&value_copy);
675        newval = &value_copy;
676    }
677    convert_to_boolean(newval);
678
679    if (obj->document) {
680        doc_prop = dom_get_doc_props(obj->document);
681        doc_prop->resolveexternals = Z_LVAL_P(newval);
682    }
683
684    if (newval == &value_copy) {
685        zval_dtor(newval);
686    }
687
688    return SUCCESS;
689}
690/* }}} */
691
692/* {{{ preserveWhiteSpace   boolean
693readonly=no
694*/
695int dom_document_preserve_whitespace_read(dom_object *obj, zval **retval TSRMLS_DC)
696{
697    dom_doc_propsptr doc_prop;
698
699    ALLOC_ZVAL(*retval);
700    if (obj->document) {
701        doc_prop = dom_get_doc_props(obj->document);
702        ZVAL_BOOL(*retval, doc_prop->preservewhitespace);
703    } else {
704        ZVAL_FALSE(*retval);
705    }
706    return SUCCESS;
707}
708
709int dom_document_preserve_whitespace_write(dom_object *obj, zval *newval TSRMLS_DC)
710{
711    zval value_copy;
712    dom_doc_propsptr doc_prop;
713
714    if(Z_REFCOUNT_P(newval) > 1) {
715        value_copy = *newval;
716        zval_copy_ctor(&value_copy);
717        newval = &value_copy;
718    }
719    convert_to_boolean(newval);
720
721    if (obj->document) {
722        doc_prop = dom_get_doc_props(obj->document);
723        doc_prop->preservewhitespace = Z_LVAL_P(newval);
724    }
725
726    if (newval == &value_copy) {
727        zval_dtor(newval);
728    }
729
730    return SUCCESS;
731}
732/* }}} */
733
734/* {{{ recover  boolean
735readonly=no
736*/
737int dom_document_recover_read(dom_object *obj, zval **retval TSRMLS_DC)
738{
739    dom_doc_propsptr doc_prop;
740
741    ALLOC_ZVAL(*retval);
742    if (obj->document) {
743        doc_prop = dom_get_doc_props(obj->document);
744        ZVAL_BOOL(*retval, doc_prop->recover);
745    } else {
746        ZVAL_FALSE(*retval);
747    }
748    return SUCCESS;
749}
750
751int dom_document_recover_write(dom_object *obj, zval *newval TSRMLS_DC)
752{
753    zval value_copy;
754    dom_doc_propsptr doc_prop;
755
756    if(Z_REFCOUNT_P(newval) > 1) {
757        value_copy = *newval;
758        zval_copy_ctor(&value_copy);
759        newval = &value_copy;
760    }
761    convert_to_boolean(newval);
762
763    if (obj->document) {
764        doc_prop = dom_get_doc_props(obj->document);
765        doc_prop->recover = Z_LVAL_P(newval);
766    }
767
768    if (newval == &value_copy) {
769        zval_dtor(newval);
770    }
771
772    return SUCCESS;
773}
774/* }}} */
775
776/* {{{ substituteEntities   boolean
777readonly=no
778*/
779int dom_document_substitue_entities_read(dom_object *obj, zval **retval TSRMLS_DC)
780{
781    dom_doc_propsptr doc_prop;
782
783    ALLOC_ZVAL(*retval);
784    if (obj->document) {
785        doc_prop = dom_get_doc_props(obj->document);
786        ZVAL_BOOL(*retval, doc_prop->substituteentities);
787    } else {
788        ZVAL_FALSE(*retval);
789    }
790    return SUCCESS;
791}
792
793int dom_document_substitue_entities_write(dom_object *obj, zval *newval TSRMLS_DC)
794{
795    zval value_copy;
796    dom_doc_propsptr doc_prop;
797
798    if(Z_REFCOUNT_P(newval) > 1) {
799        value_copy = *newval;
800        zval_copy_ctor(&value_copy);
801        newval = &value_copy;
802    }
803    convert_to_boolean(newval);
804
805    if (obj->document) {
806        doc_prop = dom_get_doc_props(obj->document);
807        doc_prop->substituteentities = Z_LVAL_P(newval);
808    }
809
810    if (newval == &value_copy) {
811        zval_dtor(newval);
812    }
813
814    return SUCCESS;
815}
816/* }}} */
817
818/* {{{ documentURI  string
819readonly=no
820URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-Document3-documentURI
821Since: DOM Level 3
822*/
823int dom_document_document_uri_read(dom_object *obj, zval **retval TSRMLS_DC)
824{
825    xmlDoc *docp;
826    char *url;
827
828    docp = (xmlDocPtr) dom_object_get_node(obj);
829
830    if (docp == NULL) {
831        php_dom_throw_error(INVALID_STATE_ERR, 0 TSRMLS_CC);
832        return FAILURE;
833    }
834
835    ALLOC_ZVAL(*retval);
836    url = (char *) docp->URL;
837    if (url != NULL) {
838        ZVAL_STRING(*retval, url, 1);
839    } else {
840        ZVAL_NULL(*retval);
841    }
842
843    return SUCCESS;
844}
845
846int dom_document_document_uri_write(dom_object *obj, zval *newval TSRMLS_DC)
847{
848    zval value_copy;
849    xmlDoc *docp;
850
851    docp = (xmlDocPtr) dom_object_get_node(obj);
852
853    if (docp == NULL) {
854        php_dom_throw_error(INVALID_STATE_ERR, 0 TSRMLS_CC);
855        return FAILURE;
856    }
857
858    if (docp->URL != NULL) {
859        xmlFree((xmlChar *) docp->URL);
860    }
861
862    if (newval->type != IS_STRING) {
863        if(Z_REFCOUNT_P(newval) > 1) {
864            value_copy = *newval;
865            zval_copy_ctor(&value_copy);
866            newval = &value_copy;
867        }
868        convert_to_string(newval);
869    }
870
871    docp->URL = xmlStrdup((const xmlChar *) Z_STRVAL_P(newval));
872
873    if (newval == &value_copy) {
874        zval_dtor(newval);
875    }
876
877    return SUCCESS;
878}
879
880/* }}} */
881
882/* {{{ config   DOMConfiguration
883readonly=yes
884URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-Document3-config
885Since: DOM Level 3
886*/
887int dom_document_config_read(dom_object *obj, zval **retval TSRMLS_DC)
888{
889    ALLOC_ZVAL(*retval);
890    ZVAL_NULL(*retval);
891    return SUCCESS;
892}
893
894/* }}} */
895
896/* {{{ proto DOMElement dom_document_create_element(string tagName [, string value]);
897URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-2141741547
898Since:
899*/
900PHP_FUNCTION(dom_document_create_element)
901{
902    zval *id, *rv = NULL;
903    xmlNode *node;
904    xmlDocPtr docp;
905    dom_object *intern;
906    int ret, name_len, value_len;
907    char *name, *value = NULL;
908
909    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os|s", &id, dom_document_class_entry, &name, &name_len, &value, &value_len) == FAILURE) {
910        return;
911    }
912
913    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
914
915    if (xmlValidateName((xmlChar *) name, 0) != 0) {
916        php_dom_throw_error(INVALID_CHARACTER_ERR, dom_get_strict_error(intern->document) TSRMLS_CC);
917        RETURN_FALSE;
918    }
919
920    node = xmlNewDocNode(docp, NULL, name, value);
921    if (!node) {
922        RETURN_FALSE;
923    }
924
925    DOM_RET_OBJ(rv, node, &ret, intern);
926}
927/* }}} end dom_document_create_element */
928
929/* {{{ proto DOMDocumentFragment dom_document_create_document_fragment();
930URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-35CB04B5
931Since:
932*/
933PHP_FUNCTION(dom_document_create_document_fragment)
934{
935    zval *id, *rv = NULL;
936    xmlNode *node;
937    xmlDocPtr docp;
938    dom_object *intern;
939    int ret;
940
941    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &id, dom_document_class_entry) == FAILURE) {
942        return;
943    }
944
945    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
946
947    node =  xmlNewDocFragment(docp);
948    if (!node) {
949        RETURN_FALSE;
950    }
951
952    DOM_RET_OBJ(rv, node, &ret, intern);
953}
954/* }}} end dom_document_create_document_fragment */
955
956/* {{{ proto DOMText dom_document_create_text_node(string data);
957URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1975348127
958Since:
959*/
960PHP_FUNCTION(dom_document_create_text_node)
961{
962    zval *id, *rv = NULL;
963    xmlNode *node;
964    xmlDocPtr docp;
965    int ret, value_len;
966    dom_object *intern;
967    char *value;
968
969    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &id, dom_document_class_entry, &value, &value_len) == FAILURE) {
970        return;
971    }
972
973    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
974
975    node = xmlNewDocText(docp, (xmlChar *) value);
976    if (!node) {
977        RETURN_FALSE;
978    }
979
980    DOM_RET_OBJ(rv, node, &ret, intern);
981}
982/* }}} end dom_document_create_text_node */
983
984/* {{{ proto DOMComment dom_document_create_comment(string data);
985URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1334481328
986Since:
987*/
988PHP_FUNCTION(dom_document_create_comment)
989{
990    zval *id, *rv = NULL;
991    xmlNode *node;
992    xmlDocPtr docp;
993    int ret, value_len;
994    dom_object *intern;
995    char *value;
996
997    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &id, dom_document_class_entry, &value, &value_len) == FAILURE) {
998        return;
999    }
1000
1001    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1002
1003    node = xmlNewDocComment(docp, (xmlChar *) value);
1004    if (!node) {
1005        RETURN_FALSE;
1006    }
1007
1008    DOM_RET_OBJ(rv, node, &ret, intern);
1009}
1010/* }}} end dom_document_create_comment */
1011
1012/* {{{ proto DOMCdataSection dom_document_create_cdatasection(string data);
1013URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-D26C0AF8
1014Since:
1015*/
1016PHP_FUNCTION(dom_document_create_cdatasection)
1017{
1018    zval *id, *rv = NULL;
1019    xmlNode *node;
1020    xmlDocPtr docp;
1021    int ret, value_len;
1022    dom_object *intern;
1023    char *value;
1024
1025    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &id, dom_document_class_entry, &value, &value_len) == FAILURE) {
1026        return;
1027    }
1028
1029    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1030
1031    node = xmlNewCDataBlock(docp, (xmlChar *) value, value_len);
1032    if (!node) {
1033        RETURN_FALSE;
1034    }
1035
1036    DOM_RET_OBJ(rv, node, &ret, intern);
1037}
1038/* }}} end dom_document_create_cdatasection */
1039
1040/* {{{ proto DOMProcessingInstruction dom_document_create_processing_instruction(string target, string data);
1041URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-135944439
1042Since:
1043*/
1044PHP_FUNCTION(dom_document_create_processing_instruction)
1045{
1046    zval *id, *rv = NULL;
1047    xmlNode *node;
1048    xmlDocPtr docp;
1049    int ret, value_len, name_len = 0;
1050    dom_object *intern;
1051    char *name, *value = NULL;
1052
1053    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os|s", &id, dom_document_class_entry, &name, &name_len, &value, &value_len) == FAILURE) {
1054        return;
1055    }
1056
1057    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1058
1059    if (xmlValidateName((xmlChar *) name, 0) != 0) {
1060        php_dom_throw_error(INVALID_CHARACTER_ERR, dom_get_strict_error(intern->document) TSRMLS_CC);
1061        RETURN_FALSE;
1062    }
1063
1064    node = xmlNewPI((xmlChar *) name, (xmlChar *) value);
1065    if (!node) {
1066        RETURN_FALSE;
1067    }
1068
1069    node->doc = docp;
1070
1071    DOM_RET_OBJ(rv, node, &ret, intern);
1072}
1073/* }}} end dom_document_create_processing_instruction */
1074
1075/* {{{ proto DOMAttr dom_document_create_attribute(string name);
1076URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1084891198
1077Since:
1078*/
1079PHP_FUNCTION(dom_document_create_attribute)
1080{
1081    zval *id, *rv = NULL;
1082    xmlAttrPtr node;
1083    xmlDocPtr docp;
1084    int ret, name_len;
1085    dom_object *intern;
1086    char *name;
1087
1088    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &id, dom_document_class_entry, &name, &name_len) == FAILURE) {
1089        return;
1090    }
1091
1092    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1093
1094    if (xmlValidateName((xmlChar *) name, 0) != 0) {
1095        php_dom_throw_error(INVALID_CHARACTER_ERR, dom_get_strict_error(intern->document) TSRMLS_CC);
1096        RETURN_FALSE;
1097    }
1098
1099    node = xmlNewDocProp(docp, (xmlChar *) name, NULL);
1100    if (!node) {
1101        RETURN_FALSE;
1102    }
1103
1104    DOM_RET_OBJ(rv, (xmlNodePtr) node, &ret, intern);
1105
1106}
1107/* }}} end dom_document_create_attribute */
1108
1109/* {{{ proto DOMEntityReference dom_document_create_entity_reference(string name);
1110URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-392B75AE
1111Since:
1112*/
1113PHP_FUNCTION(dom_document_create_entity_reference)
1114{
1115    zval *id, *rv = NULL;
1116    xmlNode *node;
1117    xmlDocPtr docp = NULL;
1118    dom_object *intern;
1119    int ret, name_len;
1120    char *name;
1121
1122    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &id, dom_document_class_entry, &name, &name_len) == FAILURE) {
1123        return;
1124    }
1125
1126    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1127
1128    if (xmlValidateName((xmlChar *) name, 0) != 0) {
1129        php_dom_throw_error(INVALID_CHARACTER_ERR, dom_get_strict_error(intern->document) TSRMLS_CC);
1130        RETURN_FALSE;
1131    }
1132
1133    node = xmlNewReference(docp, name);
1134    if (!node) {
1135        RETURN_FALSE;
1136    }
1137
1138    DOM_RET_OBJ(rv, (xmlNodePtr) node, &ret, intern);
1139}
1140/* }}} end dom_document_create_entity_reference */
1141
1142/* {{{ proto DOMNodeList dom_document_get_elements_by_tag_name(string tagname);
1143URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-A6C9094
1144Since:
1145*/
1146PHP_FUNCTION(dom_document_get_elements_by_tag_name)
1147{
1148    zval *id;
1149    xmlDocPtr docp;
1150    int name_len;
1151    dom_object *intern, *namednode;
1152    char *name;
1153    xmlChar *local;
1154
1155    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &id, dom_document_class_entry, &name, &name_len) == FAILURE) {
1156        return;
1157    }
1158
1159    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1160
1161    php_dom_create_interator(return_value, DOM_NODELIST TSRMLS_CC);
1162    namednode = (dom_object *)zend_objects_get_address(return_value TSRMLS_CC);
1163    local = xmlCharStrndup(name, name_len);
1164    dom_namednode_iter(intern, 0, namednode, NULL, local, NULL TSRMLS_CC);
1165}
1166/* }}} end dom_document_get_elements_by_tag_name */
1167
1168/* {{{ proto DOMNode dom_document_import_node(DOMNode importedNode, boolean deep);
1169URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Core-Document-importNode
1170Since: DOM Level 2
1171*/
1172PHP_FUNCTION(dom_document_import_node)
1173{
1174    zval *rv = NULL;
1175    zval *id, *node;
1176    xmlDocPtr docp;
1177    xmlNodePtr nodep, retnodep;
1178    dom_object *intern, *nodeobj;
1179    int ret;
1180    long recursive = 0;
1181
1182    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO|l", &id, dom_document_class_entry, &node, dom_node_class_entry, &recursive) == FAILURE) {
1183        return;
1184    }
1185
1186    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1187
1188    DOM_GET_OBJ(nodep, node, xmlNodePtr, nodeobj);
1189
1190    if (nodep->type == XML_HTML_DOCUMENT_NODE || nodep->type == XML_DOCUMENT_NODE
1191        || nodep->type == XML_DOCUMENT_TYPE_NODE) {
1192        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot import: Node Type Not Supported");
1193        RETURN_FALSE;
1194    }
1195
1196    if (nodep->doc == docp) {
1197        retnodep = nodep;
1198    } else {
1199        if ((recursive == 0) && (nodep->type == XML_ELEMENT_NODE)) {
1200            recursive = 2;
1201        }
1202        retnodep = xmlDocCopyNode(nodep, docp, recursive);
1203        if (!retnodep) {
1204            RETURN_FALSE;
1205        }
1206
1207        if ((retnodep->type == XML_ATTRIBUTE_NODE) && (nodep->ns != NULL)) {
1208            xmlNsPtr nsptr = NULL;
1209            xmlNodePtr root = xmlDocGetRootElement(docp);
1210
1211            nsptr = xmlSearchNsByHref (nodep->doc, root, nodep->ns->href);
1212            if (nsptr == NULL) {
1213                int errorcode;
1214                nsptr = dom_get_ns(root, nodep->ns->href, &errorcode, nodep->ns->prefix);
1215            }
1216            xmlSetNs(retnodep, nsptr);
1217        }
1218    }
1219
1220    DOM_RET_OBJ(rv, (xmlNodePtr) retnodep, &ret, intern);
1221}
1222/* }}} end dom_document_import_node */
1223
1224/* {{{ proto DOMElement dom_document_create_element_ns(string namespaceURI, string qualifiedName [,string value]);
1225URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-DocCrElNS
1226Since: DOM Level 2
1227*/
1228PHP_FUNCTION(dom_document_create_element_ns)
1229{
1230    zval *id, *rv = NULL;
1231    xmlDocPtr docp;
1232    xmlNodePtr nodep = NULL;
1233    xmlNsPtr nsptr = NULL;
1234    int ret, uri_len = 0, name_len = 0, value_len = 0;
1235    char *uri, *name, *value = NULL;
1236    char *localname = NULL, *prefix = NULL;
1237    int errorcode;
1238    dom_object *intern;
1239
1240    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os!s|s", &id, dom_document_class_entry, &uri, &uri_len, &name, &name_len, &value, &value_len) == FAILURE) {
1241        return;
1242    }
1243
1244    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1245
1246    errorcode = dom_check_qname(name, &localname, &prefix, uri_len, name_len);
1247
1248    if (errorcode == 0) {
1249        if (xmlValidateName((xmlChar *) localname, 0) == 0) {
1250            nodep = xmlNewDocNode (docp, NULL, localname, value);
1251            if (nodep != NULL && uri != NULL) {
1252                nsptr = xmlSearchNsByHref (nodep->doc, nodep, uri);
1253                if (nsptr == NULL) {
1254                    nsptr = dom_get_ns(nodep, uri, &errorcode, prefix);
1255                }
1256                xmlSetNs(nodep, nsptr);
1257            }
1258        } else {
1259            errorcode = INVALID_CHARACTER_ERR;
1260        }
1261    }
1262
1263    xmlFree(localname);
1264    if (prefix != NULL) {
1265        xmlFree(prefix);
1266    }
1267
1268    if (errorcode != 0) {
1269        if (nodep != NULL) {
1270            xmlFreeNode(nodep);
1271        }
1272        php_dom_throw_error(errorcode, dom_get_strict_error(intern->document) TSRMLS_CC);
1273        RETURN_FALSE;
1274    }
1275
1276    if (nodep == NULL) {
1277        RETURN_FALSE;
1278    }
1279
1280
1281    nodep->ns = nsptr;
1282
1283    DOM_RET_OBJ(rv, nodep, &ret, intern);
1284}
1285/* }}} end dom_document_create_element_ns */
1286
1287/* {{{ proto DOMAttr dom_document_create_attribute_ns(string namespaceURI, string qualifiedName);
1288URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-DocCrAttrNS
1289Since: DOM Level 2
1290*/
1291PHP_FUNCTION(dom_document_create_attribute_ns)
1292{
1293    zval *id, *rv = NULL;
1294    xmlDocPtr docp;
1295    xmlNodePtr nodep = NULL, root;
1296    xmlNsPtr nsptr;
1297    int ret, uri_len = 0, name_len = 0;
1298    char *uri, *name;
1299    char *localname = NULL, *prefix = NULL;
1300    dom_object *intern;
1301    int errorcode;
1302
1303    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os!s", &id, dom_document_class_entry, &uri, &uri_len, &name, &name_len) == FAILURE) {
1304        return;
1305    }
1306
1307    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1308
1309    root = xmlDocGetRootElement(docp);
1310    if (root != NULL) {
1311        errorcode = dom_check_qname(name, &localname, &prefix, uri_len, name_len);
1312        if (errorcode == 0) {
1313            if (xmlValidateName((xmlChar *) localname, 0) == 0) {
1314                nodep = (xmlNodePtr) xmlNewDocProp(docp, localname, NULL);
1315                if (nodep != NULL && uri_len > 0) {
1316                    nsptr = xmlSearchNsByHref (nodep->doc, root, uri);
1317                    if (nsptr == NULL) {
1318                        nsptr = dom_get_ns(root, uri, &errorcode, prefix);
1319                    }
1320                    xmlSetNs(nodep, nsptr);
1321                }
1322            } else {
1323                errorcode = INVALID_CHARACTER_ERR;
1324            }
1325        }
1326    } else {
1327        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Document Missing Root Element");
1328        RETURN_FALSE;
1329    }
1330
1331    xmlFree(localname);
1332    if (prefix != NULL) {
1333        xmlFree(prefix);
1334    }
1335
1336    if (errorcode != 0) {
1337        if (nodep != NULL) {
1338            xmlFreeProp((xmlAttrPtr) nodep);
1339        }
1340        php_dom_throw_error(errorcode, dom_get_strict_error(intern->document) TSRMLS_CC);
1341        RETURN_FALSE;
1342    }
1343
1344    if (nodep == NULL) {
1345        RETURN_FALSE;
1346    }
1347
1348    DOM_RET_OBJ(rv, nodep, &ret, intern);
1349}
1350/* }}} end dom_document_create_attribute_ns */
1351
1352/* {{{ proto DOMNodeList dom_document_get_elements_by_tag_name_ns(string namespaceURI, string localName);
1353URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-getElBTNNS
1354Since: DOM Level 2
1355*/
1356PHP_FUNCTION(dom_document_get_elements_by_tag_name_ns)
1357{
1358    zval *id;
1359    xmlDocPtr docp;
1360    int uri_len, name_len;
1361    dom_object *intern, *namednode;
1362    char *uri, *name;
1363    xmlChar *local, *nsuri;
1364
1365    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oss", &id, dom_document_class_entry, &uri, &uri_len, &name, &name_len) == FAILURE) {
1366        return;
1367    }
1368
1369    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1370
1371    php_dom_create_interator(return_value, DOM_NODELIST TSRMLS_CC);
1372    namednode = (dom_object *)zend_objects_get_address(return_value TSRMLS_CC);
1373    local = xmlCharStrndup(name, name_len);
1374    nsuri = xmlCharStrndup(uri, uri_len);
1375    dom_namednode_iter(intern, 0, namednode, NULL, local, nsuri TSRMLS_CC);
1376}
1377/* }}} end dom_document_get_elements_by_tag_name_ns */
1378
1379/* {{{ proto DOMElement dom_document_get_element_by_id(string elementId);
1380URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-getElBId
1381Since: DOM Level 2
1382*/
1383PHP_FUNCTION(dom_document_get_element_by_id)
1384{
1385    zval *id, *rv = NULL;
1386    xmlDocPtr docp;
1387    xmlAttrPtr  attrp;
1388    int ret, idname_len;
1389    dom_object *intern;
1390    char *idname;
1391
1392    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &id, dom_document_class_entry, &idname, &idname_len) == FAILURE) {
1393        return;
1394    }
1395
1396    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1397
1398    attrp = xmlGetID(docp, (xmlChar *) idname);
1399
1400    if (attrp && attrp->parent) {
1401        DOM_RET_OBJ(rv, (xmlNodePtr) attrp->parent, &ret, intern);
1402    } else {
1403        RETVAL_NULL();
1404    }
1405
1406}
1407/* }}} end dom_document_get_element_by_id */
1408
1409/* {{{ proto DOMNode dom_document_adopt_node(DOMNode source);
1410URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-Document3-adoptNode
1411Since: DOM Level 3
1412*/
1413PHP_FUNCTION(dom_document_adopt_node)
1414{
1415 DOM_NOT_IMPLEMENTED();
1416}
1417/* }}} end dom_document_adopt_node */
1418
1419/* {{{ proto void dom_document_normalize_document();
1420URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-Document3-normalizeDocument
1421Since: DOM Level 3
1422*/
1423PHP_FUNCTION(dom_document_normalize_document)
1424{
1425    zval *id;
1426    xmlDocPtr docp;
1427    dom_object *intern;
1428
1429    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &id, dom_document_class_entry) == FAILURE) {
1430        return;
1431    }
1432
1433    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1434
1435    dom_normalize((xmlNodePtr) docp TSRMLS_CC);
1436}
1437/* }}} end dom_document_normalize_document */
1438
1439/* {{{ proto DOMNode dom_document_rename_node(node n, string namespaceURI, string qualifiedName);
1440URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-Document3-renameNode
1441Since: DOM Level 3
1442*/
1443PHP_FUNCTION(dom_document_rename_node)
1444{
1445 DOM_NOT_IMPLEMENTED();
1446}
1447/* }}} end dom_document_rename_node */
1448
1449/* {{{ proto void DOMDocument::__construct([string version], [string encoding]); */
1450PHP_METHOD(domdocument, __construct)
1451{
1452
1453    zval *id;
1454    xmlDoc *docp = NULL, *olddoc;
1455    dom_object *intern;
1456    char *encoding, *version = NULL;
1457    int encoding_len = 0, version_len = 0, refcount;
1458    zend_error_handling error_handling;
1459
1460    zend_replace_error_handling(EH_THROW, dom_domexception_class_entry, &error_handling TSRMLS_CC);
1461    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O|ss", &id, dom_document_class_entry, &version, &version_len, &encoding, &encoding_len) == FAILURE) {
1462        zend_restore_error_handling(&error_handling TSRMLS_CC);
1463        return;
1464    }
1465
1466    zend_restore_error_handling(&error_handling TSRMLS_CC);
1467    docp = xmlNewDoc(version);
1468
1469    if (!docp) {
1470        php_dom_throw_error(INVALID_STATE_ERR, 1 TSRMLS_CC);
1471        RETURN_FALSE;
1472    }
1473
1474    if (encoding_len > 0) {
1475        docp->encoding = (const xmlChar*)xmlStrdup(encoding);
1476    }
1477
1478    intern = (dom_object *)zend_object_store_get_object(id TSRMLS_CC);
1479    if (intern != NULL) {
1480        olddoc = (xmlDocPtr) dom_object_get_node(intern);
1481        if (olddoc != NULL) {
1482            php_libxml_decrement_node_ptr((php_libxml_node_object *) intern TSRMLS_CC);
1483            refcount = php_libxml_decrement_doc_ref((php_libxml_node_object *)intern TSRMLS_CC);
1484            if (refcount != 0) {
1485                olddoc->_private = NULL;
1486            }
1487        }
1488        intern->document = NULL;
1489        if (php_libxml_increment_doc_ref((php_libxml_node_object *)intern, docp TSRMLS_CC) == -1) {
1490            RETURN_FALSE;
1491        }
1492        php_libxml_increment_node_ptr((php_libxml_node_object *)intern, (xmlNodePtr)docp, (void *)intern TSRMLS_CC);
1493    }
1494}
1495/* }}} end DOMDocument::__construct */
1496
1497char *_dom_get_valid_file_path(char *source, char *resolved_path, int resolved_path_len  TSRMLS_DC) /* {{{ */
1498{
1499    xmlURI *uri;
1500    xmlChar *escsource;
1501    char *file_dest;
1502    int isFileUri = 0;
1503
1504    uri = xmlCreateURI();
1505    escsource = xmlURIEscapeStr(source, ":");
1506    xmlParseURIReference(uri, escsource);
1507    xmlFree(escsource);
1508
1509    if (uri->scheme != NULL) {
1510        /* absolute file uris - libxml only supports localhost or empty host */
1511        if (strncasecmp(source, "file:///",8) == 0) {
1512            isFileUri = 1;
1513#ifdef PHP_WIN32
1514            source += 8;
1515#else
1516            source += 7;
1517#endif
1518        } else if (strncasecmp(source, "file://localhost/",17) == 0) {
1519            isFileUri = 1;
1520#ifdef PHP_WIN32
1521            source += 17;
1522#else
1523            source += 16;
1524#endif
1525        }
1526    }
1527
1528    file_dest = source;
1529
1530    if ((uri->scheme == NULL || isFileUri)) {
1531        /* XXX possible buffer overflow if VCWD_REALPATH does not know size of resolved_path */
1532        if (!VCWD_REALPATH(source, resolved_path) && !expand_filepath(source, resolved_path TSRMLS_CC)) {
1533            xmlFreeURI(uri);
1534            return NULL;
1535        }
1536        file_dest = resolved_path;
1537    }
1538
1539    xmlFreeURI(uri);
1540
1541    return file_dest;
1542}
1543/* }}} */
1544
1545static xmlDocPtr dom_document_parser(zval *id, int mode, char *source, int source_len, int options TSRMLS_DC) /* {{{ */
1546{
1547    xmlDocPtr ret;
1548    xmlParserCtxtPtr ctxt = NULL;
1549    dom_doc_propsptr doc_props;
1550    dom_object *intern;
1551    php_libxml_ref_obj *document = NULL;
1552    int validate, recover, resolve_externals, keep_blanks, substitute_ent;
1553    int resolved_path_len;
1554    int old_error_reporting = 0;
1555    char *directory=NULL, resolved_path[MAXPATHLEN];
1556
1557    if (id != NULL) {
1558        intern = (dom_object *)zend_object_store_get_object(id TSRMLS_CC);
1559        document = intern->document;
1560    }
1561
1562    doc_props = dom_get_doc_props(document);
1563    validate = doc_props->validateonparse;
1564    resolve_externals = doc_props->resolveexternals;
1565    keep_blanks = doc_props->preservewhitespace;
1566    substitute_ent = doc_props->substituteentities;
1567    recover = doc_props->recover;
1568
1569    if (document == NULL) {
1570        efree(doc_props);
1571    }
1572
1573    xmlInitParser();
1574
1575    if (mode == DOM_LOAD_FILE) {
1576        char *file_dest = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN  TSRMLS_CC);
1577        if (file_dest) {
1578            ctxt = xmlCreateFileParserCtxt(file_dest);
1579        }
1580
1581    } else {
1582        ctxt = xmlCreateMemoryParserCtxt(source, source_len);
1583    }
1584
1585    if (ctxt == NULL) {
1586        return(NULL);
1587    }
1588
1589    /* If loading from memory, we need to set the base directory for the document */
1590    if (mode != DOM_LOAD_FILE) {
1591#if HAVE_GETCWD
1592        directory = VCWD_GETCWD(resolved_path, MAXPATHLEN);
1593#elif HAVE_GETWD
1594        directory = VCWD_GETWD(resolved_path);
1595#endif
1596        if (directory) {
1597            if(ctxt->directory != NULL) {
1598                xmlFree((char *) ctxt->directory);
1599            }
1600            resolved_path_len = strlen(resolved_path);
1601            if (resolved_path[resolved_path_len - 1] != DEFAULT_SLASH) {
1602                resolved_path[resolved_path_len] = DEFAULT_SLASH;
1603                resolved_path[++resolved_path_len] = '\0';
1604            }
1605            ctxt->directory = (char *) xmlCanonicPath((const xmlChar *) resolved_path);
1606        }
1607    }
1608
1609    ctxt->vctxt.error = php_libxml_ctx_error;
1610    ctxt->vctxt.warning = php_libxml_ctx_warning;
1611
1612    if (ctxt->sax != NULL) {
1613        ctxt->sax->error = php_libxml_ctx_error;
1614        ctxt->sax->warning = php_libxml_ctx_warning;
1615    }
1616
1617    if (validate && ! (options & XML_PARSE_DTDVALID)) {
1618        options |= XML_PARSE_DTDVALID;
1619    }
1620    if (resolve_externals && ! (options & XML_PARSE_DTDATTR)) {
1621        options |= XML_PARSE_DTDATTR;
1622    }
1623    if (substitute_ent && ! (options & XML_PARSE_NOENT)) {
1624        options |= XML_PARSE_NOENT;
1625    }
1626    if (keep_blanks == 0 && ! (options & XML_PARSE_NOBLANKS)) {
1627        options |= XML_PARSE_NOBLANKS;
1628    }
1629
1630    xmlCtxtUseOptions(ctxt, options);
1631
1632    ctxt->recovery = recover;
1633    if (recover) {
1634        old_error_reporting = EG(error_reporting);
1635        EG(error_reporting) = old_error_reporting | E_WARNING;
1636    }
1637
1638    xmlParseDocument(ctxt);
1639
1640    if (ctxt->wellFormed || recover) {
1641        ret = ctxt->myDoc;
1642        if (ctxt->recovery) {
1643            EG(error_reporting) = old_error_reporting;
1644        }
1645        /* If loading from memory, set the base reference uri for the document */
1646        if (ret && ret->URL == NULL && ctxt->directory != NULL) {
1647            ret->URL = xmlStrdup(ctxt->directory);
1648        }
1649    } else {
1650        ret = NULL;
1651        xmlFreeDoc(ctxt->myDoc);
1652        ctxt->myDoc = NULL;
1653    }
1654
1655    xmlFreeParserCtxt(ctxt);
1656
1657    return(ret);
1658}
1659/* }}} */
1660
1661/* {{{ static void dom_parse_document(INTERNAL_FUNCTION_PARAMETERS, int mode) */
1662static void dom_parse_document(INTERNAL_FUNCTION_PARAMETERS, int mode) {
1663    zval *id, *rv = NULL;
1664    xmlDoc *docp = NULL, *newdoc;
1665    dom_doc_propsptr doc_prop;
1666    dom_object *intern;
1667    char *source;
1668    int source_len, refcount, ret;
1669    long options = 0;
1670
1671    id = getThis();
1672    if (id != NULL && ! instanceof_function(Z_OBJCE_P(id), dom_document_class_entry TSRMLS_CC)) {
1673        id = NULL;
1674    }
1675
1676    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &source, &source_len, &options) == FAILURE) {
1677        return;
1678    }
1679
1680    if (!source_len) {
1681        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty string supplied as input");
1682        RETURN_FALSE;
1683    }
1684
1685    newdoc = dom_document_parser(id, mode, source, source_len, options TSRMLS_CC);
1686
1687    if (!newdoc)
1688        RETURN_FALSE;
1689
1690    if (id != NULL) {
1691        intern = (dom_object *)zend_object_store_get_object(id TSRMLS_CC);
1692        if (intern != NULL) {
1693            docp = (xmlDocPtr) dom_object_get_node(intern);
1694            doc_prop = NULL;
1695            if (docp != NULL) {
1696                php_libxml_decrement_node_ptr((php_libxml_node_object *) intern TSRMLS_CC);
1697                doc_prop = intern->document->doc_props;
1698                intern->document->doc_props = NULL;
1699                refcount = php_libxml_decrement_doc_ref((php_libxml_node_object *)intern TSRMLS_CC);
1700                if (refcount != 0) {
1701                    docp->_private = NULL;
1702                }
1703            }
1704            intern->document = NULL;
1705            if (php_libxml_increment_doc_ref((php_libxml_node_object *)intern, newdoc TSRMLS_CC) == -1) {
1706                RETURN_FALSE;
1707            }
1708            intern->document->doc_props = doc_prop;
1709        }
1710
1711        php_libxml_increment_node_ptr((php_libxml_node_object *)intern, (xmlNodePtr)newdoc, (void *)intern TSRMLS_CC);
1712
1713        RETURN_TRUE;
1714    } else {
1715        DOM_RET_OBJ(rv, (xmlNodePtr) newdoc, &ret, NULL);
1716    }
1717}
1718/* }}} end dom_parser_document */
1719
1720/* {{{ proto DOMNode dom_document_load(string source [, int options]);
1721URL: http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-DocumentLS-load
1722Since: DOM Level 3
1723*/
1724PHP_METHOD(domdocument, load)
1725{
1726    dom_parse_document(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
1727}
1728/* }}} end dom_document_load */
1729
1730/* {{{ proto DOMNode dom_document_loadxml(string source [, int options]);
1731URL: http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-DocumentLS-loadXML
1732Since: DOM Level 3
1733*/
1734PHP_METHOD(domdocument, loadXML)
1735{
1736    dom_parse_document(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
1737}
1738/* }}} end dom_document_loadxml */
1739
1740/* {{{ proto int dom_document_save(string file);
1741Convenience method to save to file
1742*/
1743PHP_FUNCTION(dom_document_save)
1744{
1745    zval *id;
1746    xmlDoc *docp;
1747    int file_len = 0, bytes, format, saveempty = 0;
1748    dom_object *intern;
1749    dom_doc_propsptr doc_props;
1750    char *file;
1751    long options = 0;
1752
1753    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os|l", &id, dom_document_class_entry, &file, &file_len, &options) == FAILURE) {
1754        return;
1755    }
1756
1757    if (file_len == 0) {
1758        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Filename");
1759        RETURN_FALSE;
1760    }
1761
1762    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1763
1764    /* encoding handled by property on doc */
1765
1766    doc_props = dom_get_doc_props(intern->document);
1767    format = doc_props->formatoutput;
1768    if (options & LIBXML_SAVE_NOEMPTYTAG) {
1769        saveempty = xmlSaveNoEmptyTags;
1770        xmlSaveNoEmptyTags = 1;
1771    }
1772    bytes = xmlSaveFormatFileEnc(file, docp, NULL, format);
1773    if (options & LIBXML_SAVE_NOEMPTYTAG) {
1774        xmlSaveNoEmptyTags = saveempty;
1775    }
1776    if (bytes == -1) {
1777        RETURN_FALSE;
1778    }
1779    RETURN_LONG(bytes);
1780}
1781/* }}} end dom_document_save */
1782
1783/* {{{ proto string dom_document_savexml([node n]);
1784URL: http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-DocumentLS-saveXML
1785Since: DOM Level 3
1786*/
1787PHP_FUNCTION(dom_document_savexml)
1788{
1789    zval *id, *nodep = NULL;
1790    xmlDoc *docp;
1791    xmlNode *node;
1792    xmlBufferPtr buf;
1793    xmlChar *mem;
1794    dom_object *intern, *nodeobj;
1795    dom_doc_propsptr doc_props;
1796    int size, format, saveempty = 0;
1797    long options = 0;
1798
1799    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O|O!l", &id, dom_document_class_entry, &nodep, dom_node_class_entry, &options) == FAILURE) {
1800        return;
1801    }
1802
1803    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1804
1805    doc_props = dom_get_doc_props(intern->document);
1806    format = doc_props->formatoutput;
1807
1808    if (nodep != NULL) {
1809        /* Dump contents of Node */
1810        DOM_GET_OBJ(node, nodep, xmlNodePtr, nodeobj);
1811        if (node->doc != docp) {
1812            php_dom_throw_error(WRONG_DOCUMENT_ERR, dom_get_strict_error(intern->document) TSRMLS_CC);
1813            RETURN_FALSE;
1814        }
1815        buf = xmlBufferCreate();
1816        if (!buf) {
1817            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not fetch buffer");
1818            RETURN_FALSE;
1819        }
1820        if (options & LIBXML_SAVE_NOEMPTYTAG) {
1821            saveempty = xmlSaveNoEmptyTags;
1822            xmlSaveNoEmptyTags = 1;
1823        }
1824        xmlNodeDump(buf, docp, node, 0, format);
1825        if (options & LIBXML_SAVE_NOEMPTYTAG) {
1826            xmlSaveNoEmptyTags = saveempty;
1827        }
1828        mem = (xmlChar*) xmlBufferContent(buf);
1829        if (!mem) {
1830            xmlBufferFree(buf);
1831            RETURN_FALSE;
1832        }
1833        RETVAL_STRING(mem, 1);
1834        xmlBufferFree(buf);
1835    } else {
1836        if (options & LIBXML_SAVE_NOEMPTYTAG) {
1837            saveempty = xmlSaveNoEmptyTags;
1838            xmlSaveNoEmptyTags = 1;
1839        }
1840        /* Encoding is handled from the encoding property set on the document */
1841        xmlDocDumpFormatMemory(docp, &mem, &size, format);
1842        if (options & LIBXML_SAVE_NOEMPTYTAG) {
1843            xmlSaveNoEmptyTags = saveempty;
1844        }
1845        if (!size) {
1846            RETURN_FALSE;
1847        }
1848        RETVAL_STRINGL(mem, size, 1);
1849        xmlFree(mem);
1850    }
1851}
1852/* }}} end dom_document_savexml */
1853
1854static xmlNodePtr php_dom_free_xinclude_node(xmlNodePtr cur TSRMLS_DC) /* {{{ */
1855{
1856    xmlNodePtr xincnode;
1857
1858    xincnode = cur;
1859    cur = cur->next;
1860    xmlUnlinkNode(xincnode);
1861    php_libxml_node_free_resource(xincnode TSRMLS_CC);
1862
1863    return cur;
1864}
1865/* }}} */
1866
1867static void php_dom_remove_xinclude_nodes(xmlNodePtr cur TSRMLS_DC) /* {{{ */
1868{
1869    while(cur) {
1870        if (cur->type == XML_XINCLUDE_START) {
1871            cur = php_dom_free_xinclude_node(cur TSRMLS_CC);
1872
1873            /* XML_XINCLUDE_END node will be a sibling of XML_XINCLUDE_START */
1874            while(cur && cur->type != XML_XINCLUDE_END) {
1875                /* remove xinclude processing nodes from recursive xincludes */
1876                if (cur->type == XML_ELEMENT_NODE) {
1877                       php_dom_remove_xinclude_nodes(cur->children TSRMLS_CC);
1878                }
1879                cur = cur->next;
1880            }
1881
1882            if (cur && cur->type == XML_XINCLUDE_END) {
1883                cur = php_dom_free_xinclude_node(cur TSRMLS_CC);
1884            }
1885        } else {
1886            if (cur->type == XML_ELEMENT_NODE) {
1887                php_dom_remove_xinclude_nodes(cur->children TSRMLS_CC);
1888            }
1889            cur = cur->next;
1890        }
1891    }
1892}
1893/* }}} */
1894
1895/* {{{ proto int dom_document_xinclude([int options])
1896   Substitutues xincludes in a DomDocument */
1897PHP_FUNCTION(dom_document_xinclude)
1898{
1899    zval *id;
1900    xmlDoc *docp;
1901    xmlNodePtr root;
1902    long flags = 0;
1903    int err;
1904    dom_object *intern;
1905
1906    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O|l", &id, dom_document_class_entry, &flags) == FAILURE) {
1907        return;
1908    }
1909
1910    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1911
1912    err = xmlXIncludeProcessFlags(docp, flags);
1913
1914    /* XML_XINCLUDE_START and XML_XINCLUDE_END nodes need to be removed as these
1915    are added via xmlXIncludeProcess to mark beginning and ending of xincluded document
1916    but are not wanted in resulting document - must be done even if err as it could fail after
1917    having processed some xincludes */
1918    root = (xmlNodePtr) docp->children;
1919    while(root && root->type != XML_ELEMENT_NODE && root->type != XML_XINCLUDE_START) {
1920        root = root->next;
1921    }
1922    if (root) {
1923        php_dom_remove_xinclude_nodes(root TSRMLS_CC);
1924    }
1925
1926    if (err) {
1927        RETVAL_LONG(err);
1928    } else {
1929        RETVAL_FALSE;
1930    }
1931
1932}
1933/* }}} */
1934
1935/* {{{ proto boolean dom_document_validate();
1936Since: DOM extended
1937*/
1938PHP_FUNCTION(dom_document_validate)
1939{
1940    zval *id;
1941    xmlDoc *docp;
1942    dom_object *intern;
1943    xmlValidCtxt *cvp;
1944
1945    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &id, dom_document_class_entry) == FAILURE) {
1946        return;
1947    }
1948
1949    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1950
1951    cvp = xmlNewValidCtxt();
1952
1953    cvp->userData = NULL;
1954    cvp->error    = (xmlValidityErrorFunc) php_libxml_error_handler;
1955    cvp->warning  = (xmlValidityErrorFunc) php_libxml_error_handler;
1956
1957    if (xmlValidateDocument(cvp, docp)) {
1958        RETVAL_TRUE;
1959    } else {
1960        RETVAL_FALSE;
1961    }
1962
1963    xmlFreeValidCtxt(cvp);
1964
1965}
1966/* }}} */
1967
1968#if defined(LIBXML_SCHEMAS_ENABLED)
1969static void _dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ */
1970{
1971    zval *id;
1972    xmlDoc *docp;
1973    dom_object *intern;
1974    char *source = NULL, *valid_file = NULL;
1975    int source_len = 0;
1976    xmlSchemaParserCtxtPtr  parser;
1977    xmlSchemaPtr            sptr;
1978    xmlSchemaValidCtxtPtr   vptr;
1979    int                     is_valid;
1980    char resolved_path[MAXPATHLEN + 1];
1981
1982    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &id, dom_document_class_entry, &source, &source_len) == FAILURE) {
1983        return;
1984    }
1985
1986    if (source_len == 0) {
1987        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Schema source");
1988        RETURN_FALSE;
1989    }
1990
1991    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1992
1993    switch (type) {
1994    case DOM_LOAD_FILE:
1995        valid_file = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN  TSRMLS_CC);
1996        if (!valid_file) {
1997            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Schema file source");
1998            RETURN_FALSE;
1999        }
2000        parser = xmlSchemaNewParserCtxt(valid_file);
2001        break;
2002    case DOM_LOAD_STRING:
2003        parser = xmlSchemaNewMemParserCtxt(source, source_len);
2004        /* If loading from memory, we need to set the base directory for the document
2005           but it is not apparent how to do that for schema's */
2006        break;
2007    default:
2008        return;
2009    }
2010
2011    xmlSchemaSetParserErrors(parser,
2012        (xmlSchemaValidityErrorFunc) php_libxml_error_handler,
2013        (xmlSchemaValidityWarningFunc) php_libxml_error_handler,
2014        parser);
2015    sptr = xmlSchemaParse(parser);
2016    xmlSchemaFreeParserCtxt(parser);
2017    if (!sptr) {
2018        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Schema");
2019        RETURN_FALSE;
2020    }
2021
2022    docp = (xmlDocPtr) dom_object_get_node(intern);
2023
2024    vptr = xmlSchemaNewValidCtxt(sptr);
2025    if (!vptr) {
2026        xmlSchemaFree(sptr);
2027        php_error(E_ERROR, "Invalid Schema Validation Context");
2028        RETURN_FALSE;
2029    }
2030
2031    xmlSchemaSetValidErrors(vptr, php_libxml_error_handler, php_libxml_error_handler, vptr);
2032    is_valid = xmlSchemaValidateDoc(vptr, docp);
2033    xmlSchemaFree(sptr);
2034    xmlSchemaFreeValidCtxt(vptr);
2035
2036    if (is_valid == 0) {
2037        RETURN_TRUE;
2038    } else {
2039        RETURN_FALSE;
2040    }
2041}
2042/* }}} */
2043
2044/* {{{ proto boolean dom_document_schema_validate_file(string filename); */
2045PHP_FUNCTION(dom_document_schema_validate_file)
2046{
2047    _dom_document_schema_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
2048}
2049/* }}} end dom_document_schema_validate_file */
2050
2051/* {{{ proto boolean dom_document_schema_validate(string source); */
2052PHP_FUNCTION(dom_document_schema_validate_xml)
2053{
2054    _dom_document_schema_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
2055}
2056/* }}} end dom_document_schema_validate */
2057
2058static void _dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ */
2059{
2060    zval *id;
2061    xmlDoc *docp;
2062    dom_object *intern;
2063    char *source = NULL, *valid_file = NULL;
2064    int source_len = 0;
2065    xmlRelaxNGParserCtxtPtr parser;
2066    xmlRelaxNGPtr           sptr;
2067    xmlRelaxNGValidCtxtPtr  vptr;
2068    int                     is_valid;
2069    char resolved_path[MAXPATHLEN + 1];
2070
2071    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &id, dom_document_class_entry, &source, &source_len) == FAILURE) {
2072        return;
2073    }
2074
2075    if (source_len == 0) {
2076        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Schema source");
2077        RETURN_FALSE;
2078    }
2079
2080    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
2081
2082    switch (type) {
2083    case DOM_LOAD_FILE:
2084        valid_file = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN  TSRMLS_CC);
2085        if (!valid_file) {
2086            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid RelaxNG file source");
2087            RETURN_FALSE;
2088        }
2089        parser = xmlRelaxNGNewParserCtxt(valid_file);
2090        break;
2091    case DOM_LOAD_STRING:
2092        parser = xmlRelaxNGNewMemParserCtxt(source, source_len);
2093        /* If loading from memory, we need to set the base directory for the document
2094           but it is not apparent how to do that for schema's */
2095        break;
2096    default:
2097        return;
2098    }
2099
2100    xmlRelaxNGSetParserErrors(parser,
2101        (xmlRelaxNGValidityErrorFunc) php_libxml_error_handler,
2102        (xmlRelaxNGValidityWarningFunc) php_libxml_error_handler,
2103        parser);
2104    sptr = xmlRelaxNGParse(parser);
2105    xmlRelaxNGFreeParserCtxt(parser);
2106    if (!sptr) {
2107        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid RelaxNG");
2108        RETURN_FALSE;
2109    }
2110
2111    docp = (xmlDocPtr) dom_object_get_node(intern);
2112
2113    vptr = xmlRelaxNGNewValidCtxt(sptr);
2114    if (!vptr) {
2115        xmlRelaxNGFree(sptr);
2116        php_error(E_ERROR, "Invalid RelaxNG Validation Context");
2117        RETURN_FALSE;
2118    }
2119
2120    xmlRelaxNGSetValidErrors(vptr, php_libxml_error_handler, php_libxml_error_handler, vptr);
2121    is_valid = xmlRelaxNGValidateDoc(vptr, docp);
2122    xmlRelaxNGFree(sptr);
2123    xmlRelaxNGFreeValidCtxt(vptr);
2124
2125    if (is_valid == 0) {
2126        RETURN_TRUE;
2127    } else {
2128        RETURN_FALSE;
2129    }
2130}
2131/* }}} */
2132
2133/* {{{ proto boolean dom_document_relaxNG_validate_file(string filename); */
2134PHP_FUNCTION(dom_document_relaxNG_validate_file)
2135{
2136    _dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
2137}
2138/* }}} end dom_document_relaxNG_validate_file */
2139
2140/* {{{ proto boolean dom_document_relaxNG_validate_xml(string source); */
2141PHP_FUNCTION(dom_document_relaxNG_validate_xml)
2142{
2143    _dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
2144}
2145/* }}} end dom_document_relaxNG_validate_xml */
2146
2147#endif
2148
2149#if defined(LIBXML_HTML_ENABLED)
2150
2151static void dom_load_html(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ */
2152{
2153    zval *id, *rv = NULL;
2154    xmlDoc *docp = NULL, *newdoc;
2155    dom_object *intern;
2156    dom_doc_propsptr doc_prop;
2157    char *source;
2158    int source_len, refcount, ret;
2159    htmlParserCtxtPtr ctxt;
2160
2161    id = getThis();
2162
2163    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &source, &source_len) == FAILURE) {
2164        return;
2165    }
2166
2167    if (!source_len) {
2168        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty string supplied as input");
2169        RETURN_FALSE;
2170    }
2171
2172    if (mode == DOM_LOAD_FILE) {
2173        ctxt = htmlCreateFileParserCtxt(source, NULL);
2174    } else {
2175        source_len = xmlStrlen(source);
2176        ctxt = htmlCreateMemoryParserCtxt(source, source_len);
2177    }
2178
2179    if (!ctxt) {
2180        RETURN_FALSE;
2181    }
2182
2183    ctxt->vctxt.error = php_libxml_ctx_error;
2184    ctxt->vctxt.warning = php_libxml_ctx_warning;
2185    if (ctxt->sax != NULL) {
2186        ctxt->sax->error = php_libxml_ctx_error;
2187        ctxt->sax->warning = php_libxml_ctx_warning;
2188    }
2189    htmlParseDocument(ctxt);
2190    newdoc = ctxt->myDoc;
2191    htmlFreeParserCtxt(ctxt);
2192
2193    if (!newdoc)
2194        RETURN_FALSE;
2195
2196    if (id != NULL && instanceof_function(Z_OBJCE_P(id), dom_document_class_entry TSRMLS_CC)) {
2197        intern = (dom_object *)zend_object_store_get_object(id TSRMLS_CC);
2198        if (intern != NULL) {
2199            docp = (xmlDocPtr) dom_object_get_node(intern);
2200            doc_prop = NULL;
2201            if (docp != NULL) {
2202                php_libxml_decrement_node_ptr((php_libxml_node_object *) intern TSRMLS_CC);
2203                doc_prop = intern->document->doc_props;
2204                intern->document->doc_props = NULL;
2205                refcount = php_libxml_decrement_doc_ref((php_libxml_node_object *)intern TSRMLS_CC);
2206                if (refcount != 0) {
2207                    docp->_private = NULL;
2208                }
2209            }
2210            intern->document = NULL;
2211            if (php_libxml_increment_doc_ref((php_libxml_node_object *)intern, newdoc TSRMLS_CC) == -1) {
2212                RETURN_FALSE;
2213            }
2214            intern->document->doc_props = doc_prop;
2215        }
2216
2217        php_libxml_increment_node_ptr((php_libxml_node_object *)intern, (xmlNodePtr)newdoc, (void *)intern TSRMLS_CC);
2218
2219        RETURN_TRUE;
2220    } else {
2221        DOM_RET_OBJ(rv, (xmlNodePtr) newdoc, &ret, NULL);
2222    }
2223}
2224/* }}} */
2225
2226/* {{{ proto DOMNode dom_document_load_html_file(string source);
2227Since: DOM extended
2228*/
2229PHP_METHOD(domdocument, loadHTMLFile)
2230{
2231    dom_load_html(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
2232}
2233/* }}} end dom_document_load_html_file */
2234
2235/* {{{ proto DOMNode dom_document_load_html(string source);
2236Since: DOM extended
2237*/
2238PHP_METHOD(domdocument, loadHTML)
2239{
2240    dom_load_html(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
2241}
2242/* }}} end dom_document_load_html */
2243
2244/* {{{ proto int dom_document_save_html_file(string file);
2245Convenience method to save to file as html
2246*/
2247PHP_FUNCTION(dom_document_save_html_file)
2248{
2249    zval *id;
2250    xmlDoc *docp;
2251    int file_len, bytes, format;
2252    dom_object *intern;
2253    dom_doc_propsptr doc_props;
2254    char *file;
2255    const char *encoding;
2256
2257    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &id, dom_document_class_entry, &file, &file_len) == FAILURE) {
2258        return;
2259    }
2260
2261    if (file_len == 0) {
2262        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Filename");
2263        RETURN_FALSE;
2264    }
2265
2266    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
2267
2268
2269    encoding = (const char *) htmlGetMetaEncoding(docp);
2270
2271    doc_props = dom_get_doc_props(intern->document);
2272    format = doc_props->formatoutput;
2273    bytes = htmlSaveFileFormat(file, docp, encoding, format);
2274
2275    if (bytes == -1) {
2276        RETURN_FALSE;
2277    }
2278    RETURN_LONG(bytes);
2279}
2280/* }}} end dom_document_save_html_file */
2281
2282/* {{{ proto string dom_document_save_html();
2283Convenience method to output as html
2284*/
2285PHP_FUNCTION(dom_document_save_html)
2286{
2287    zval *id, *nodep = NULL;
2288    xmlDoc *docp;
2289    xmlNode *node;
2290    xmlBufferPtr buf;
2291    dom_object *intern, *nodeobj;
2292    xmlChar *mem = NULL;
2293    int size, format;
2294    dom_doc_propsptr doc_props;
2295
2296    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
2297        "O|O!", &id, dom_document_class_entry, &nodep, dom_node_class_entry)
2298        == FAILURE) {
2299        return;
2300    }
2301
2302    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
2303
2304    doc_props = dom_get_doc_props(intern->document);
2305    format = doc_props->formatoutput;
2306
2307    if (nodep != NULL) {
2308        /* Dump contents of Node */
2309        DOM_GET_OBJ(node, nodep, xmlNodePtr, nodeobj);
2310        if (node->doc != docp) {
2311            php_dom_throw_error(WRONG_DOCUMENT_ERR, dom_get_strict_error(intern->document) TSRMLS_CC);
2312            RETURN_FALSE;
2313        }
2314
2315        buf = xmlBufferCreate();
2316        if (!buf) {
2317            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not fetch buffer");
2318            RETURN_FALSE;
2319        }
2320
2321        size = htmlNodeDump(buf, docp, node);
2322        if (size >= 0) {
2323            mem = (xmlChar*) xmlBufferContent(buf);
2324            if (!mem) {
2325                RETVAL_FALSE;
2326            } else {
2327                RETVAL_STRINGL((const char*) mem, size, 1);
2328            }
2329        } else {
2330            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error dumping HTML node");
2331            RETVAL_FALSE;
2332        }
2333        xmlBufferFree(buf);
2334    } else {
2335#if LIBXML_VERSION >= 20623
2336        htmlDocDumpMemoryFormat(docp, &mem, &size, format);
2337#else
2338        htmlDocDumpMemory(docp, &mem, &size);
2339#endif
2340        if (!size) {
2341            RETVAL_FALSE;
2342        } else {
2343            RETVAL_STRINGL((const char*) mem, size, 1);
2344        }
2345        if (mem)
2346            xmlFree(mem);
2347    }
2348
2349}
2350/* }}} end dom_document_save_html */
2351
2352#endif  /* defined(LIBXML_HTML_ENABLED) */
2353
2354/* {{{ proto boolean DOMDocument::registerNodeClass(string baseclass, string extendedclass);
2355   Register extended class used to create base node type */
2356PHP_METHOD(domdocument, registerNodeClass)
2357{
2358    zval *id;
2359    xmlDoc *docp;
2360    char *baseclass = NULL, *extendedclass = NULL;
2361    int baseclass_len = 0, extendedclass_len = 0;
2362    zend_class_entry *basece = NULL, *ce = NULL;
2363    dom_object *intern;
2364
2365    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oss!", &id, dom_document_class_entry, &baseclass, &baseclass_len, &extendedclass, &extendedclass_len) == FAILURE) {
2366        return;
2367    }
2368
2369    if (baseclass_len) {
2370        zend_class_entry **pce;
2371        if (zend_lookup_class(baseclass, baseclass_len, &pce TSRMLS_CC) == FAILURE) {
2372            php_error_docref(NULL TSRMLS_CC, E_ERROR, "Class %s does not exist", baseclass);
2373            return;
2374        }
2375        basece = *pce;
2376    }
2377
2378    if (basece == NULL || ! instanceof_function(basece, dom_node_class_entry TSRMLS_CC)) {
2379        php_error_docref(NULL TSRMLS_CC, E_ERROR, "Class %s is not derived from DOMNode.", baseclass);
2380        return;
2381    }
2382
2383    if (extendedclass_len) {
2384        zend_class_entry **pce;
2385        if (zend_lookup_class(extendedclass, extendedclass_len, &pce TSRMLS_CC) == FAILURE) {
2386            php_error_docref(NULL TSRMLS_CC, E_ERROR, "Class %s does not exist", extendedclass);
2387        }
2388        ce = *pce;
2389    }
2390
2391    if (ce == NULL || instanceof_function(ce, basece TSRMLS_CC)) {
2392
2393        DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
2394
2395        if (dom_set_doc_classmap(intern->document, basece, ce TSRMLS_CC) == FAILURE) {
2396            php_error_docref(NULL TSRMLS_CC, E_ERROR, "Class %s could not be registered.", extendedclass);
2397        }
2398        RETURN_TRUE;
2399    } else {
2400        php_error_docref(NULL TSRMLS_CC, E_ERROR, "Class %s is not derived from %s.", extendedclass, baseclass);
2401    }
2402
2403    RETURN_FALSE;
2404}
2405/* }}} */
2406
2407#endif  /* HAVE_LIBXML && HAVE_DOM */
2408
2409/*
2410 * Local variables:
2411 * tab-width: 4
2412 * c-basic-offset: 4
2413 * End:
2414 * vim600: noet sw=4 ts=4 fdm=marker
2415 * vim<600: noet sw=4 ts=4
2416 */
2417