1/*
2   +----------------------------------------------------------------------+
3   | PHP Version 5                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2014 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#ifdef PHP_WIN32
1513        if (strncasecmp(source, "file://",7) == 0 && ':' == source[8]) {
1514            isFileUri = 1;
1515            source += 7;
1516        } else
1517#endif
1518        if (strncasecmp(source, "file:///",8) == 0) {
1519            isFileUri = 1;
1520#ifdef PHP_WIN32
1521            source += 8;
1522#else
1523            source += 7;
1524#endif
1525        } else if (strncasecmp(source, "file://localhost/",17) == 0) {
1526            isFileUri = 1;
1527#ifdef PHP_WIN32
1528            source += 17;
1529#else
1530            source += 16;
1531#endif
1532        }
1533    }
1534
1535    file_dest = source;
1536
1537    if ((uri->scheme == NULL || isFileUri)) {
1538        /* XXX possible buffer overflow if VCWD_REALPATH does not know size of resolved_path */
1539        if (!VCWD_REALPATH(source, resolved_path) && !expand_filepath(source, resolved_path TSRMLS_CC)) {
1540            xmlFreeURI(uri);
1541            return NULL;
1542        }
1543        file_dest = resolved_path;
1544    }
1545
1546    xmlFreeURI(uri);
1547
1548    return file_dest;
1549}
1550/* }}} */
1551
1552static xmlDocPtr dom_document_parser(zval *id, int mode, char *source, int source_len, int options TSRMLS_DC) /* {{{ */
1553{
1554    xmlDocPtr ret;
1555    xmlParserCtxtPtr ctxt = NULL;
1556    dom_doc_propsptr doc_props;
1557    dom_object *intern;
1558    php_libxml_ref_obj *document = NULL;
1559    int validate, recover, resolve_externals, keep_blanks, substitute_ent;
1560    int resolved_path_len;
1561    int old_error_reporting = 0;
1562    char *directory=NULL, resolved_path[MAXPATHLEN];
1563
1564    if (id != NULL) {
1565        intern = (dom_object *)zend_object_store_get_object(id TSRMLS_CC);
1566        document = intern->document;
1567    }
1568
1569    doc_props = dom_get_doc_props(document);
1570    validate = doc_props->validateonparse;
1571    resolve_externals = doc_props->resolveexternals;
1572    keep_blanks = doc_props->preservewhitespace;
1573    substitute_ent = doc_props->substituteentities;
1574    recover = doc_props->recover;
1575
1576    if (document == NULL) {
1577        efree(doc_props);
1578    }
1579
1580    xmlInitParser();
1581
1582    if (mode == DOM_LOAD_FILE) {
1583        char *file_dest = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN  TSRMLS_CC);
1584        if (file_dest) {
1585            ctxt = xmlCreateFileParserCtxt(file_dest);
1586        }
1587
1588    } else {
1589        ctxt = xmlCreateMemoryParserCtxt(source, source_len);
1590    }
1591
1592    if (ctxt == NULL) {
1593        return(NULL);
1594    }
1595
1596    /* If loading from memory, we need to set the base directory for the document */
1597    if (mode != DOM_LOAD_FILE) {
1598#if HAVE_GETCWD
1599        directory = VCWD_GETCWD(resolved_path, MAXPATHLEN);
1600#elif HAVE_GETWD
1601        directory = VCWD_GETWD(resolved_path);
1602#endif
1603        if (directory) {
1604            if(ctxt->directory != NULL) {
1605                xmlFree((char *) ctxt->directory);
1606            }
1607            resolved_path_len = strlen(resolved_path);
1608            if (resolved_path[resolved_path_len - 1] != DEFAULT_SLASH) {
1609                resolved_path[resolved_path_len] = DEFAULT_SLASH;
1610                resolved_path[++resolved_path_len] = '\0';
1611            }
1612            ctxt->directory = (char *) xmlCanonicPath((const xmlChar *) resolved_path);
1613        }
1614    }
1615
1616    ctxt->vctxt.error = php_libxml_ctx_error;
1617    ctxt->vctxt.warning = php_libxml_ctx_warning;
1618
1619    if (ctxt->sax != NULL) {
1620        ctxt->sax->error = php_libxml_ctx_error;
1621        ctxt->sax->warning = php_libxml_ctx_warning;
1622    }
1623
1624    if (validate && ! (options & XML_PARSE_DTDVALID)) {
1625        options |= XML_PARSE_DTDVALID;
1626    }
1627    if (resolve_externals && ! (options & XML_PARSE_DTDATTR)) {
1628        options |= XML_PARSE_DTDATTR;
1629    }
1630    if (substitute_ent && ! (options & XML_PARSE_NOENT)) {
1631        options |= XML_PARSE_NOENT;
1632    }
1633    if (keep_blanks == 0 && ! (options & XML_PARSE_NOBLANKS)) {
1634        options |= XML_PARSE_NOBLANKS;
1635    }
1636
1637    xmlCtxtUseOptions(ctxt, options);
1638
1639    ctxt->recovery = recover;
1640    if (recover) {
1641        old_error_reporting = EG(error_reporting);
1642        EG(error_reporting) = old_error_reporting | E_WARNING;
1643    }
1644
1645    xmlParseDocument(ctxt);
1646
1647    if (ctxt->wellFormed || recover) {
1648        ret = ctxt->myDoc;
1649        if (ctxt->recovery) {
1650            EG(error_reporting) = old_error_reporting;
1651        }
1652        /* If loading from memory, set the base reference uri for the document */
1653        if (ret && ret->URL == NULL && ctxt->directory != NULL) {
1654            ret->URL = xmlStrdup(ctxt->directory);
1655        }
1656    } else {
1657        ret = NULL;
1658        xmlFreeDoc(ctxt->myDoc);
1659        ctxt->myDoc = NULL;
1660    }
1661
1662    xmlFreeParserCtxt(ctxt);
1663
1664    return(ret);
1665}
1666/* }}} */
1667
1668/* {{{ static void dom_parse_document(INTERNAL_FUNCTION_PARAMETERS, int mode) */
1669static void dom_parse_document(INTERNAL_FUNCTION_PARAMETERS, int mode) {
1670    zval *id;
1671    xmlDoc *docp = NULL, *newdoc;
1672    dom_doc_propsptr doc_prop;
1673    dom_object *intern;
1674    char *source;
1675    int source_len, refcount, ret;
1676    long options = 0;
1677
1678    id = getThis();
1679    if (id != NULL && ! instanceof_function(Z_OBJCE_P(id), dom_document_class_entry TSRMLS_CC)) {
1680        id = NULL;
1681    }
1682
1683    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &source, &source_len, &options) == FAILURE) {
1684        return;
1685    }
1686
1687    if (!source_len) {
1688        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty string supplied as input");
1689        RETURN_FALSE;
1690    }
1691
1692    newdoc = dom_document_parser(id, mode, source, source_len, options TSRMLS_CC);
1693
1694    if (!newdoc)
1695        RETURN_FALSE;
1696
1697    if (id != NULL) {
1698        intern = (dom_object *)zend_object_store_get_object(id TSRMLS_CC);
1699        if (intern != NULL) {
1700            docp = (xmlDocPtr) dom_object_get_node(intern);
1701            doc_prop = NULL;
1702            if (docp != NULL) {
1703                php_libxml_decrement_node_ptr((php_libxml_node_object *) intern TSRMLS_CC);
1704                doc_prop = intern->document->doc_props;
1705                intern->document->doc_props = NULL;
1706                refcount = php_libxml_decrement_doc_ref((php_libxml_node_object *)intern TSRMLS_CC);
1707                if (refcount != 0) {
1708                    docp->_private = NULL;
1709                }
1710            }
1711            intern->document = NULL;
1712            if (php_libxml_increment_doc_ref((php_libxml_node_object *)intern, newdoc TSRMLS_CC) == -1) {
1713                RETURN_FALSE;
1714            }
1715            intern->document->doc_props = doc_prop;
1716        }
1717
1718        php_libxml_increment_node_ptr((php_libxml_node_object *)intern, (xmlNodePtr)newdoc, (void *)intern TSRMLS_CC);
1719
1720        RETURN_TRUE;
1721    } else {
1722        DOM_RET_OBJ((xmlNodePtr) newdoc, &ret, NULL);
1723    }
1724}
1725/* }}} end dom_parser_document */
1726
1727/* {{{ proto DOMNode dom_document_load(string source [, int options]);
1728URL: http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-DocumentLS-load
1729Since: DOM Level 3
1730*/
1731PHP_METHOD(domdocument, load)
1732{
1733    dom_parse_document(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
1734}
1735/* }}} end dom_document_load */
1736
1737/* {{{ proto DOMNode dom_document_loadxml(string source [, int options]);
1738URL: http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-DocumentLS-loadXML
1739Since: DOM Level 3
1740*/
1741PHP_METHOD(domdocument, loadXML)
1742{
1743    dom_parse_document(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
1744}
1745/* }}} end dom_document_loadxml */
1746
1747/* {{{ proto int dom_document_save(string file);
1748Convenience method to save to file
1749*/
1750PHP_FUNCTION(dom_document_save)
1751{
1752    zval *id;
1753    xmlDoc *docp;
1754    int file_len = 0, bytes, format, saveempty = 0;
1755    dom_object *intern;
1756    dom_doc_propsptr doc_props;
1757    char *file;
1758    long options = 0;
1759
1760    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os|l", &id, dom_document_class_entry, &file, &file_len, &options) == FAILURE) {
1761        return;
1762    }
1763
1764    if (file_len == 0) {
1765        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Filename");
1766        RETURN_FALSE;
1767    }
1768
1769    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1770
1771    /* encoding handled by property on doc */
1772
1773    doc_props = dom_get_doc_props(intern->document);
1774    format = doc_props->formatoutput;
1775    if (options & LIBXML_SAVE_NOEMPTYTAG) {
1776        saveempty = xmlSaveNoEmptyTags;
1777        xmlSaveNoEmptyTags = 1;
1778    }
1779    bytes = xmlSaveFormatFileEnc(file, docp, NULL, format);
1780    if (options & LIBXML_SAVE_NOEMPTYTAG) {
1781        xmlSaveNoEmptyTags = saveempty;
1782    }
1783    if (bytes == -1) {
1784        RETURN_FALSE;
1785    }
1786    RETURN_LONG(bytes);
1787}
1788/* }}} end dom_document_save */
1789
1790/* {{{ proto string dom_document_savexml([node n]);
1791URL: http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-DocumentLS-saveXML
1792Since: DOM Level 3
1793*/
1794PHP_FUNCTION(dom_document_savexml)
1795{
1796    zval *id, *nodep = NULL;
1797    xmlDoc *docp;
1798    xmlNode *node;
1799    xmlBufferPtr buf;
1800    xmlChar *mem;
1801    dom_object *intern, *nodeobj;
1802    dom_doc_propsptr doc_props;
1803    int size, format, saveempty = 0;
1804    long options = 0;
1805
1806    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) {
1807        return;
1808    }
1809
1810    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1811
1812    doc_props = dom_get_doc_props(intern->document);
1813    format = doc_props->formatoutput;
1814
1815    if (nodep != NULL) {
1816        /* Dump contents of Node */
1817        DOM_GET_OBJ(node, nodep, xmlNodePtr, nodeobj);
1818        if (node->doc != docp) {
1819            php_dom_throw_error(WRONG_DOCUMENT_ERR, dom_get_strict_error(intern->document) TSRMLS_CC);
1820            RETURN_FALSE;
1821        }
1822        buf = xmlBufferCreate();
1823        if (!buf) {
1824            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not fetch buffer");
1825            RETURN_FALSE;
1826        }
1827        if (options & LIBXML_SAVE_NOEMPTYTAG) {
1828            saveempty = xmlSaveNoEmptyTags;
1829            xmlSaveNoEmptyTags = 1;
1830        }
1831        xmlNodeDump(buf, docp, node, 0, format);
1832        if (options & LIBXML_SAVE_NOEMPTYTAG) {
1833            xmlSaveNoEmptyTags = saveempty;
1834        }
1835        mem = (xmlChar*) xmlBufferContent(buf);
1836        if (!mem) {
1837            xmlBufferFree(buf);
1838            RETURN_FALSE;
1839        }
1840        RETVAL_STRING(mem, 1);
1841        xmlBufferFree(buf);
1842    } else {
1843        if (options & LIBXML_SAVE_NOEMPTYTAG) {
1844            saveempty = xmlSaveNoEmptyTags;
1845            xmlSaveNoEmptyTags = 1;
1846        }
1847        /* Encoding is handled from the encoding property set on the document */
1848        xmlDocDumpFormatMemory(docp, &mem, &size, format);
1849        if (options & LIBXML_SAVE_NOEMPTYTAG) {
1850            xmlSaveNoEmptyTags = saveempty;
1851        }
1852        if (!size) {
1853            RETURN_FALSE;
1854        }
1855        RETVAL_STRINGL(mem, size, 1);
1856        xmlFree(mem);
1857    }
1858}
1859/* }}} end dom_document_savexml */
1860
1861static xmlNodePtr php_dom_free_xinclude_node(xmlNodePtr cur TSRMLS_DC) /* {{{ */
1862{
1863    xmlNodePtr xincnode;
1864
1865    xincnode = cur;
1866    cur = cur->next;
1867    xmlUnlinkNode(xincnode);
1868    php_libxml_node_free_resource(xincnode TSRMLS_CC);
1869
1870    return cur;
1871}
1872/* }}} */
1873
1874static void php_dom_remove_xinclude_nodes(xmlNodePtr cur TSRMLS_DC) /* {{{ */
1875{
1876    while(cur) {
1877        if (cur->type == XML_XINCLUDE_START) {
1878            cur = php_dom_free_xinclude_node(cur TSRMLS_CC);
1879
1880            /* XML_XINCLUDE_END node will be a sibling of XML_XINCLUDE_START */
1881            while(cur && cur->type != XML_XINCLUDE_END) {
1882                /* remove xinclude processing nodes from recursive xincludes */
1883                if (cur->type == XML_ELEMENT_NODE) {
1884                       php_dom_remove_xinclude_nodes(cur->children TSRMLS_CC);
1885                }
1886                cur = cur->next;
1887            }
1888
1889            if (cur && cur->type == XML_XINCLUDE_END) {
1890                cur = php_dom_free_xinclude_node(cur TSRMLS_CC);
1891            }
1892        } else {
1893            if (cur->type == XML_ELEMENT_NODE) {
1894                php_dom_remove_xinclude_nodes(cur->children TSRMLS_CC);
1895            }
1896            cur = cur->next;
1897        }
1898    }
1899}
1900/* }}} */
1901
1902/* {{{ proto int dom_document_xinclude([int options])
1903   Substitutues xincludes in a DomDocument */
1904PHP_FUNCTION(dom_document_xinclude)
1905{
1906    zval *id;
1907    xmlDoc *docp;
1908    xmlNodePtr root;
1909    long flags = 0;
1910    int err;
1911    dom_object *intern;
1912
1913    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O|l", &id, dom_document_class_entry, &flags) == FAILURE) {
1914        return;
1915    }
1916
1917    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1918
1919    err = xmlXIncludeProcessFlags(docp, flags);
1920
1921    /* XML_XINCLUDE_START and XML_XINCLUDE_END nodes need to be removed as these
1922    are added via xmlXIncludeProcess to mark beginning and ending of xincluded document
1923    but are not wanted in resulting document - must be done even if err as it could fail after
1924    having processed some xincludes */
1925    root = (xmlNodePtr) docp->children;
1926    while(root && root->type != XML_ELEMENT_NODE && root->type != XML_XINCLUDE_START) {
1927        root = root->next;
1928    }
1929    if (root) {
1930        php_dom_remove_xinclude_nodes(root TSRMLS_CC);
1931    }
1932
1933    if (err) {
1934        RETVAL_LONG(err);
1935    } else {
1936        RETVAL_FALSE;
1937    }
1938
1939}
1940/* }}} */
1941
1942/* {{{ proto boolean dom_document_validate();
1943Since: DOM extended
1944*/
1945PHP_FUNCTION(dom_document_validate)
1946{
1947    zval *id;
1948    xmlDoc *docp;
1949    dom_object *intern;
1950    xmlValidCtxt *cvp;
1951
1952    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &id, dom_document_class_entry) == FAILURE) {
1953        return;
1954    }
1955
1956    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1957
1958    cvp = xmlNewValidCtxt();
1959
1960    cvp->userData = NULL;
1961    cvp->error    = (xmlValidityErrorFunc) php_libxml_error_handler;
1962    cvp->warning  = (xmlValidityErrorFunc) php_libxml_error_handler;
1963
1964    if (xmlValidateDocument(cvp, docp)) {
1965        RETVAL_TRUE;
1966    } else {
1967        RETVAL_FALSE;
1968    }
1969
1970    xmlFreeValidCtxt(cvp);
1971
1972}
1973/* }}} */
1974
1975#if defined(LIBXML_SCHEMAS_ENABLED)
1976static void _dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ */
1977{
1978    zval *id;
1979    xmlDoc *docp;
1980    dom_object *intern;
1981    char *source = NULL, *valid_file = NULL;
1982    int source_len = 0, valid_opts = 0;
1983    long flags = 0;
1984    xmlSchemaParserCtxtPtr  parser;
1985    xmlSchemaPtr            sptr;
1986    xmlSchemaValidCtxtPtr   vptr;
1987    int                     is_valid;
1988    char resolved_path[MAXPATHLEN + 1];
1989
1990    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Op|l", &id, dom_document_class_entry, &source, &source_len, &flags) == FAILURE) {
1991        return;
1992    }
1993
1994    if (source_len == 0) {
1995        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Schema source");
1996        RETURN_FALSE;
1997    }
1998
1999    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
2000
2001    switch (type) {
2002    case DOM_LOAD_FILE:
2003        valid_file = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN  TSRMLS_CC);
2004        if (!valid_file) {
2005            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Schema file source");
2006            RETURN_FALSE;
2007        }
2008        parser = xmlSchemaNewParserCtxt(valid_file);
2009        break;
2010    case DOM_LOAD_STRING:
2011        parser = xmlSchemaNewMemParserCtxt(source, source_len);
2012        /* If loading from memory, we need to set the base directory for the document
2013           but it is not apparent how to do that for schema's */
2014        break;
2015    default:
2016        return;
2017    }
2018
2019    xmlSchemaSetParserErrors(parser,
2020        (xmlSchemaValidityErrorFunc) php_libxml_error_handler,
2021        (xmlSchemaValidityWarningFunc) php_libxml_error_handler,
2022        parser);
2023    sptr = xmlSchemaParse(parser);
2024    xmlSchemaFreeParserCtxt(parser);
2025    if (!sptr) {
2026        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Schema");
2027        RETURN_FALSE;
2028    }
2029
2030    docp = (xmlDocPtr) dom_object_get_node(intern);
2031
2032    vptr = xmlSchemaNewValidCtxt(sptr);
2033    if (!vptr) {
2034        xmlSchemaFree(sptr);
2035        php_error(E_ERROR, "Invalid Schema Validation Context");
2036        RETURN_FALSE;
2037    }
2038
2039#if LIBXML_VERSION >= 20614
2040    if (flags & XML_SCHEMA_VAL_VC_I_CREATE) {
2041        valid_opts |= XML_SCHEMA_VAL_VC_I_CREATE;
2042    }
2043#endif
2044
2045    xmlSchemaSetValidOptions(vptr, valid_opts);
2046    xmlSchemaSetValidErrors(vptr, php_libxml_error_handler, php_libxml_error_handler, vptr);
2047    is_valid = xmlSchemaValidateDoc(vptr, docp);
2048    xmlSchemaFree(sptr);
2049    xmlSchemaFreeValidCtxt(vptr);
2050
2051    if (is_valid == 0) {
2052        RETURN_TRUE;
2053    } else {
2054        RETURN_FALSE;
2055    }
2056}
2057/* }}} */
2058
2059/* {{{ proto boolean dom_document_schema_validate_file(string filename, int flags); */
2060PHP_FUNCTION(dom_document_schema_validate_file)
2061{
2062    _dom_document_schema_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
2063}
2064/* }}} end dom_document_schema_validate_file */
2065
2066/* {{{ proto boolean dom_document_schema_validate(string source, int flags); */
2067PHP_FUNCTION(dom_document_schema_validate_xml)
2068{
2069    _dom_document_schema_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
2070}
2071/* }}} end dom_document_schema_validate */
2072
2073static void _dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ */
2074{
2075    zval *id;
2076    xmlDoc *docp;
2077    dom_object *intern;
2078    char *source = NULL, *valid_file = NULL;
2079    int source_len = 0;
2080    xmlRelaxNGParserCtxtPtr parser;
2081    xmlRelaxNGPtr           sptr;
2082    xmlRelaxNGValidCtxtPtr  vptr;
2083    int                     is_valid;
2084    char resolved_path[MAXPATHLEN + 1];
2085
2086    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Op", &id, dom_document_class_entry, &source, &source_len) == FAILURE) {
2087        return;
2088    }
2089
2090    if (source_len == 0) {
2091        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Schema source");
2092        RETURN_FALSE;
2093    }
2094
2095    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
2096
2097    switch (type) {
2098    case DOM_LOAD_FILE:
2099        valid_file = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN  TSRMLS_CC);
2100        if (!valid_file) {
2101            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid RelaxNG file source");
2102            RETURN_FALSE;
2103        }
2104        parser = xmlRelaxNGNewParserCtxt(valid_file);
2105        break;
2106    case DOM_LOAD_STRING:
2107        parser = xmlRelaxNGNewMemParserCtxt(source, source_len);
2108        /* If loading from memory, we need to set the base directory for the document
2109           but it is not apparent how to do that for schema's */
2110        break;
2111    default:
2112        return;
2113    }
2114
2115    xmlRelaxNGSetParserErrors(parser,
2116        (xmlRelaxNGValidityErrorFunc) php_libxml_error_handler,
2117        (xmlRelaxNGValidityWarningFunc) php_libxml_error_handler,
2118        parser);
2119    sptr = xmlRelaxNGParse(parser);
2120    xmlRelaxNGFreeParserCtxt(parser);
2121    if (!sptr) {
2122        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid RelaxNG");
2123        RETURN_FALSE;
2124    }
2125
2126    docp = (xmlDocPtr) dom_object_get_node(intern);
2127
2128    vptr = xmlRelaxNGNewValidCtxt(sptr);
2129    if (!vptr) {
2130        xmlRelaxNGFree(sptr);
2131        php_error(E_ERROR, "Invalid RelaxNG Validation Context");
2132        RETURN_FALSE;
2133    }
2134
2135    xmlRelaxNGSetValidErrors(vptr, php_libxml_error_handler, php_libxml_error_handler, vptr);
2136    is_valid = xmlRelaxNGValidateDoc(vptr, docp);
2137    xmlRelaxNGFree(sptr);
2138    xmlRelaxNGFreeValidCtxt(vptr);
2139
2140    if (is_valid == 0) {
2141        RETURN_TRUE;
2142    } else {
2143        RETURN_FALSE;
2144    }
2145}
2146/* }}} */
2147
2148/* {{{ proto boolean dom_document_relaxNG_validate_file(string filename); */
2149PHP_FUNCTION(dom_document_relaxNG_validate_file)
2150{
2151    _dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
2152}
2153/* }}} end dom_document_relaxNG_validate_file */
2154
2155/* {{{ proto boolean dom_document_relaxNG_validate_xml(string source); */
2156PHP_FUNCTION(dom_document_relaxNG_validate_xml)
2157{
2158    _dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
2159}
2160/* }}} end dom_document_relaxNG_validate_xml */
2161
2162#endif
2163
2164#if defined(LIBXML_HTML_ENABLED)
2165
2166static void dom_load_html(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ */
2167{
2168    zval *id;
2169    xmlDoc *docp = NULL, *newdoc;
2170    dom_object *intern;
2171    dom_doc_propsptr doc_prop;
2172    char *source;
2173    int source_len, refcount, ret;
2174    long options = 0;
2175    htmlParserCtxtPtr ctxt;
2176
2177    id = getThis();
2178
2179    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &source, &source_len, &options) == FAILURE) {
2180        return;
2181    }
2182
2183    if (!source_len) {
2184        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty string supplied as input");
2185        RETURN_FALSE;
2186    }
2187
2188    if (mode == DOM_LOAD_FILE) {
2189        ctxt = htmlCreateFileParserCtxt(source, NULL);
2190    } else {
2191        source_len = xmlStrlen(source);
2192        ctxt = htmlCreateMemoryParserCtxt(source, source_len);
2193    }
2194
2195    if (!ctxt) {
2196        RETURN_FALSE;
2197    }
2198
2199    if (options) {
2200        htmlCtxtUseOptions(ctxt, options);
2201    }
2202
2203    ctxt->vctxt.error = php_libxml_ctx_error;
2204    ctxt->vctxt.warning = php_libxml_ctx_warning;
2205    if (ctxt->sax != NULL) {
2206        ctxt->sax->error = php_libxml_ctx_error;
2207        ctxt->sax->warning = php_libxml_ctx_warning;
2208    }
2209    htmlParseDocument(ctxt);
2210    newdoc = ctxt->myDoc;
2211    htmlFreeParserCtxt(ctxt);
2212
2213    if (!newdoc)
2214        RETURN_FALSE;
2215
2216    if (id != NULL && instanceof_function(Z_OBJCE_P(id), dom_document_class_entry TSRMLS_CC)) {
2217        intern = (dom_object *)zend_object_store_get_object(id TSRMLS_CC);
2218        if (intern != NULL) {
2219            docp = (xmlDocPtr) dom_object_get_node(intern);
2220            doc_prop = NULL;
2221            if (docp != NULL) {
2222                php_libxml_decrement_node_ptr((php_libxml_node_object *) intern TSRMLS_CC);
2223                doc_prop = intern->document->doc_props;
2224                intern->document->doc_props = NULL;
2225                refcount = php_libxml_decrement_doc_ref((php_libxml_node_object *)intern TSRMLS_CC);
2226                if (refcount != 0) {
2227                    docp->_private = NULL;
2228                }
2229            }
2230            intern->document = NULL;
2231            if (php_libxml_increment_doc_ref((php_libxml_node_object *)intern, newdoc TSRMLS_CC) == -1) {
2232                RETURN_FALSE;
2233            }
2234            intern->document->doc_props = doc_prop;
2235        }
2236
2237        php_libxml_increment_node_ptr((php_libxml_node_object *)intern, (xmlNodePtr)newdoc, (void *)intern TSRMLS_CC);
2238
2239        RETURN_TRUE;
2240    } else {
2241        DOM_RET_OBJ((xmlNodePtr) newdoc, &ret, NULL);
2242    }
2243}
2244/* }}} */
2245
2246/* {{{ proto DOMNode dom_document_load_html_file(string source);
2247Since: DOM extended
2248*/
2249PHP_METHOD(domdocument, loadHTMLFile)
2250{
2251    dom_load_html(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
2252}
2253/* }}} end dom_document_load_html_file */
2254
2255/* {{{ proto DOMNode dom_document_load_html(string source);
2256Since: DOM extended
2257*/
2258PHP_METHOD(domdocument, loadHTML)
2259{
2260    dom_load_html(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
2261}
2262/* }}} end dom_document_load_html */
2263
2264/* {{{ proto int dom_document_save_html_file(string file);
2265Convenience method to save to file as html
2266*/
2267PHP_FUNCTION(dom_document_save_html_file)
2268{
2269    zval *id;
2270    xmlDoc *docp;
2271    int file_len, bytes, format;
2272    dom_object *intern;
2273    dom_doc_propsptr doc_props;
2274    char *file;
2275    const char *encoding;
2276
2277    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &id, dom_document_class_entry, &file, &file_len) == FAILURE) {
2278        return;
2279    }
2280
2281    if (file_len == 0) {
2282        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Filename");
2283        RETURN_FALSE;
2284    }
2285
2286    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
2287
2288
2289    encoding = (const char *) htmlGetMetaEncoding(docp);
2290
2291    doc_props = dom_get_doc_props(intern->document);
2292    format = doc_props->formatoutput;
2293    bytes = htmlSaveFileFormat(file, docp, encoding, format);
2294
2295    if (bytes == -1) {
2296        RETURN_FALSE;
2297    }
2298    RETURN_LONG(bytes);
2299}
2300/* }}} end dom_document_save_html_file */
2301
2302/* {{{ proto string dom_document_save_html();
2303Convenience method to output as html
2304*/
2305PHP_FUNCTION(dom_document_save_html)
2306{
2307    zval *id, *nodep = NULL;
2308    xmlDoc *docp;
2309    xmlNode *node;
2310    xmlBufferPtr buf;
2311    dom_object *intern, *nodeobj;
2312    xmlChar *mem = NULL;
2313    int size = 0, format;
2314    dom_doc_propsptr doc_props;
2315
2316    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
2317        "O|O!", &id, dom_document_class_entry, &nodep, dom_node_class_entry)
2318        == FAILURE) {
2319        return;
2320    }
2321
2322    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
2323
2324    doc_props = dom_get_doc_props(intern->document);
2325    format = doc_props->formatoutput;
2326
2327    if (nodep != NULL) {
2328        /* Dump contents of Node */
2329        DOM_GET_OBJ(node, nodep, xmlNodePtr, nodeobj);
2330        if (node->doc != docp) {
2331            php_dom_throw_error(WRONG_DOCUMENT_ERR, dom_get_strict_error(intern->document) TSRMLS_CC);
2332            RETURN_FALSE;
2333        }
2334
2335        buf = xmlBufferCreate();
2336        if (!buf) {
2337            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not fetch buffer");
2338            RETURN_FALSE;
2339        }
2340
2341        if (node->type == XML_DOCUMENT_FRAG_NODE) {
2342            int one_size;
2343
2344            for (node = node->children; node; node = node->next) {
2345                one_size = htmlNodeDump(buf, docp, node);
2346
2347                if (one_size >= 0) {
2348                    size += one_size;
2349                } else {
2350                    size = -1;
2351                    break;
2352                }
2353            }
2354        } else {
2355            size = htmlNodeDump(buf, docp, node);
2356        }
2357        if (size >= 0) {
2358            mem = (xmlChar*) xmlBufferContent(buf);
2359            if (!mem) {
2360                RETVAL_FALSE;
2361            } else {
2362                RETVAL_STRINGL((const char*) mem, size, 1);
2363            }
2364        } else {
2365            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error dumping HTML node");
2366            RETVAL_FALSE;
2367        }
2368        xmlBufferFree(buf);
2369    } else {
2370#if LIBXML_VERSION >= 20623
2371        htmlDocDumpMemoryFormat(docp, &mem, &size, format);
2372#else
2373        htmlDocDumpMemory(docp, &mem, &size);
2374#endif
2375        if (!size) {
2376            RETVAL_FALSE;
2377        } else {
2378            RETVAL_STRINGL((const char*) mem, size, 1);
2379        }
2380        if (mem)
2381            xmlFree(mem);
2382    }
2383
2384}
2385/* }}} end dom_document_save_html */
2386
2387#endif  /* defined(LIBXML_HTML_ENABLED) */
2388
2389/* {{{ proto boolean DOMDocument::registerNodeClass(string baseclass, string extendedclass);
2390   Register extended class used to create base node type */
2391PHP_METHOD(domdocument, registerNodeClass)
2392{
2393    zval *id;
2394    xmlDoc *docp;
2395    char *baseclass = NULL, *extendedclass = NULL;
2396    int baseclass_len = 0, extendedclass_len = 0;
2397    zend_class_entry *basece = NULL, *ce = NULL;
2398    dom_object *intern;
2399
2400    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oss!", &id, dom_document_class_entry, &baseclass, &baseclass_len, &extendedclass, &extendedclass_len) == FAILURE) {
2401        return;
2402    }
2403
2404    if (baseclass_len) {
2405        zend_class_entry **pce;
2406        if (zend_lookup_class(baseclass, baseclass_len, &pce TSRMLS_CC) == FAILURE) {
2407            php_error_docref(NULL TSRMLS_CC, E_ERROR, "Class %s does not exist", baseclass);
2408            return;
2409        }
2410        basece = *pce;
2411    }
2412
2413    if (basece == NULL || ! instanceof_function(basece, dom_node_class_entry TSRMLS_CC)) {
2414        php_error_docref(NULL TSRMLS_CC, E_ERROR, "Class %s is not derived from DOMNode.", baseclass);
2415        return;
2416    }
2417
2418    if (extendedclass_len) {
2419        zend_class_entry **pce;
2420        if (zend_lookup_class(extendedclass, extendedclass_len, &pce TSRMLS_CC) == FAILURE) {
2421            php_error_docref(NULL TSRMLS_CC, E_ERROR, "Class %s does not exist", extendedclass);
2422        }
2423        ce = *pce;
2424    }
2425
2426    if (ce == NULL || instanceof_function(ce, basece TSRMLS_CC)) {
2427
2428        DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
2429
2430        if (dom_set_doc_classmap(intern->document, basece, ce TSRMLS_CC) == FAILURE) {
2431            php_error_docref(NULL TSRMLS_CC, E_ERROR, "Class %s could not be registered.", extendedclass);
2432        }
2433        RETURN_TRUE;
2434    } else {
2435        php_error_docref(NULL TSRMLS_CC, E_ERROR, "Class %s is not derived from %s.", extendedclass, baseclass);
2436    }
2437
2438    RETURN_FALSE;
2439}
2440/* }}} */
2441
2442#endif  /* HAVE_LIBXML && HAVE_DOM */
2443
2444/*
2445 * Local variables:
2446 * tab-width: 4
2447 * c-basic-offset: 4
2448 * End:
2449 * vim600: noet sw=4 ts=4 fdm=marker
2450 * vim<600: noet sw=4 ts=4
2451 */
2452