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