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