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
1497    newdoc = dom_document_parser(id, mode, source, source_len, options);
1498
1499    if (!newdoc)
1500        RETURN_FALSE;
1501
1502    if (id != NULL) {
1503        intern = Z_DOMOBJ_P(id);
1504        if (intern != NULL) {
1505            docp = (xmlDocPtr) dom_object_get_node(intern);
1506            doc_prop = NULL;
1507            if (docp != NULL) {
1508                php_libxml_decrement_node_ptr((php_libxml_node_object *) intern);
1509                doc_prop = intern->document->doc_props;
1510                intern->document->doc_props = NULL;
1511                refcount = php_libxml_decrement_doc_ref((php_libxml_node_object *)intern);
1512                if (refcount != 0) {
1513                    docp->_private = NULL;
1514                }
1515            }
1516            intern->document = NULL;
1517            if (php_libxml_increment_doc_ref((php_libxml_node_object *)intern, newdoc) == -1) {
1518                RETURN_FALSE;
1519            }
1520            intern->document->doc_props = doc_prop;
1521        }
1522
1523        php_libxml_increment_node_ptr((php_libxml_node_object *)intern, (xmlNodePtr)newdoc, (void *)intern);
1524
1525        RETURN_TRUE;
1526    } else {
1527        DOM_RET_OBJ((xmlNodePtr) newdoc, &ret, NULL);
1528    }
1529}
1530/* }}} end dom_parser_document */
1531
1532/* {{{ proto DOMNode dom_document_load(string source [, int options])
1533URL: http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-DocumentLS-load
1534Since: DOM Level 3
1535*/
1536PHP_METHOD(domdocument, load)
1537{
1538    dom_parse_document(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
1539}
1540/* }}} end dom_document_load */
1541
1542/* {{{ proto DOMNode dom_document_loadxml(string source [, int options])
1543URL: http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-DocumentLS-loadXML
1544Since: DOM Level 3
1545*/
1546PHP_METHOD(domdocument, loadXML)
1547{
1548    dom_parse_document(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
1549}
1550/* }}} end dom_document_loadxml */
1551
1552/* {{{ proto int dom_document_save(string file)
1553Convenience method to save to file
1554*/
1555PHP_FUNCTION(dom_document_save)
1556{
1557    zval *id;
1558    xmlDoc *docp;
1559    size_t file_len = 0;
1560    int bytes, format, saveempty = 0;
1561    dom_object *intern;
1562    dom_doc_propsptr doc_props;
1563    char *file;
1564    zend_long options = 0;
1565
1566    if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Op|l", &id, dom_document_class_entry, &file, &file_len, &options) == FAILURE) {
1567        return;
1568    }
1569
1570    if (file_len == 0) {
1571        php_error_docref(NULL, E_WARNING, "Invalid Filename");
1572        RETURN_FALSE;
1573    }
1574
1575    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1576
1577    /* encoding handled by property on doc */
1578
1579    doc_props = dom_get_doc_props(intern->document);
1580    format = doc_props->formatoutput;
1581    if (options & LIBXML_SAVE_NOEMPTYTAG) {
1582        saveempty = xmlSaveNoEmptyTags;
1583        xmlSaveNoEmptyTags = 1;
1584    }
1585    bytes = xmlSaveFormatFileEnc(file, docp, NULL, format);
1586    if (options & LIBXML_SAVE_NOEMPTYTAG) {
1587        xmlSaveNoEmptyTags = saveempty;
1588    }
1589    if (bytes == -1) {
1590        RETURN_FALSE;
1591    }
1592    RETURN_LONG(bytes);
1593}
1594/* }}} end dom_document_save */
1595
1596/* {{{ proto string dom_document_savexml([node n])
1597URL: http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-DocumentLS-saveXML
1598Since: DOM Level 3
1599*/
1600PHP_FUNCTION(dom_document_savexml)
1601{
1602    zval *id, *nodep = NULL;
1603    xmlDoc *docp;
1604    xmlNode *node;
1605    xmlBufferPtr buf;
1606    xmlChar *mem;
1607    dom_object *intern, *nodeobj;
1608    dom_doc_propsptr doc_props;
1609    int size, format, saveempty = 0;
1610    zend_long options = 0;
1611
1612    if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|O!l", &id, dom_document_class_entry, &nodep, dom_node_class_entry, &options) == FAILURE) {
1613        return;
1614    }
1615
1616    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1617
1618    doc_props = dom_get_doc_props(intern->document);
1619    format = doc_props->formatoutput;
1620
1621    if (nodep != NULL) {
1622        /* Dump contents of Node */
1623        DOM_GET_OBJ(node, nodep, xmlNodePtr, nodeobj);
1624        if (node->doc != docp) {
1625            php_dom_throw_error(WRONG_DOCUMENT_ERR, dom_get_strict_error(intern->document));
1626            RETURN_FALSE;
1627        }
1628        buf = xmlBufferCreate();
1629        if (!buf) {
1630            php_error_docref(NULL, E_WARNING, "Could not fetch buffer");
1631            RETURN_FALSE;
1632        }
1633        if (options & LIBXML_SAVE_NOEMPTYTAG) {
1634            saveempty = xmlSaveNoEmptyTags;
1635            xmlSaveNoEmptyTags = 1;
1636        }
1637        xmlNodeDump(buf, docp, node, 0, format);
1638        if (options & LIBXML_SAVE_NOEMPTYTAG) {
1639            xmlSaveNoEmptyTags = saveempty;
1640        }
1641        mem = (xmlChar*) xmlBufferContent(buf);
1642        if (!mem) {
1643            xmlBufferFree(buf);
1644            RETURN_FALSE;
1645        }
1646        RETVAL_STRING((char *) mem);
1647        xmlBufferFree(buf);
1648    } else {
1649        if (options & LIBXML_SAVE_NOEMPTYTAG) {
1650            saveempty = xmlSaveNoEmptyTags;
1651            xmlSaveNoEmptyTags = 1;
1652        }
1653        /* Encoding is handled from the encoding property set on the document */
1654        xmlDocDumpFormatMemory(docp, &mem, &size, format);
1655        if (options & LIBXML_SAVE_NOEMPTYTAG) {
1656            xmlSaveNoEmptyTags = saveempty;
1657        }
1658        if (!size) {
1659            RETURN_FALSE;
1660        }
1661        RETVAL_STRINGL((char *) mem, size);
1662        xmlFree(mem);
1663    }
1664}
1665/* }}} end dom_document_savexml */
1666
1667static xmlNodePtr php_dom_free_xinclude_node(xmlNodePtr cur) /* {{{ */
1668{
1669    xmlNodePtr xincnode;
1670
1671    xincnode = cur;
1672    cur = cur->next;
1673    xmlUnlinkNode(xincnode);
1674    php_libxml_node_free_resource(xincnode);
1675
1676    return cur;
1677}
1678/* }}} */
1679
1680static void php_dom_remove_xinclude_nodes(xmlNodePtr cur) /* {{{ */
1681{
1682    while(cur) {
1683        if (cur->type == XML_XINCLUDE_START) {
1684            cur = php_dom_free_xinclude_node(cur);
1685
1686            /* XML_XINCLUDE_END node will be a sibling of XML_XINCLUDE_START */
1687            while(cur && cur->type != XML_XINCLUDE_END) {
1688                /* remove xinclude processing nodes from recursive xincludes */
1689                if (cur->type == XML_ELEMENT_NODE) {
1690                       php_dom_remove_xinclude_nodes(cur->children);
1691                }
1692                cur = cur->next;
1693            }
1694
1695            if (cur && cur->type == XML_XINCLUDE_END) {
1696                cur = php_dom_free_xinclude_node(cur);
1697            }
1698        } else {
1699            if (cur->type == XML_ELEMENT_NODE) {
1700                php_dom_remove_xinclude_nodes(cur->children);
1701            }
1702            cur = cur->next;
1703        }
1704    }
1705}
1706/* }}} */
1707
1708/* {{{ proto int dom_document_xinclude([int options])
1709   Substitutues xincludes in a DomDocument */
1710PHP_FUNCTION(dom_document_xinclude)
1711{
1712    zval *id;
1713    xmlDoc *docp;
1714    xmlNodePtr root;
1715    zend_long flags = 0;
1716    int err;
1717    dom_object *intern;
1718
1719    if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|l", &id, dom_document_class_entry, &flags) == FAILURE) {
1720        return;
1721    }
1722
1723    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1724
1725    err = xmlXIncludeProcessFlags(docp, flags);
1726
1727    /* XML_XINCLUDE_START and XML_XINCLUDE_END nodes need to be removed as these
1728    are added via xmlXIncludeProcess to mark beginning and ending of xincluded document
1729    but are not wanted in resulting document - must be done even if err as it could fail after
1730    having processed some xincludes */
1731    root = (xmlNodePtr) docp->children;
1732    while(root && root->type != XML_ELEMENT_NODE && root->type != XML_XINCLUDE_START) {
1733        root = root->next;
1734    }
1735    if (root) {
1736        php_dom_remove_xinclude_nodes(root);
1737    }
1738
1739    if (err) {
1740        RETVAL_LONG(err);
1741    } else {
1742        RETVAL_FALSE;
1743    }
1744
1745}
1746/* }}} */
1747
1748/* {{{ proto boolean dom_document_validate()
1749Since: DOM extended
1750*/
1751PHP_FUNCTION(dom_document_validate)
1752{
1753    zval *id;
1754    xmlDoc *docp;
1755    dom_object *intern;
1756    xmlValidCtxt *cvp;
1757
1758    if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &id, dom_document_class_entry) == FAILURE) {
1759        return;
1760    }
1761
1762    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1763
1764    cvp = xmlNewValidCtxt();
1765
1766    cvp->userData = NULL;
1767    cvp->error    = (xmlValidityErrorFunc) php_libxml_error_handler;
1768    cvp->warning  = (xmlValidityErrorFunc) php_libxml_error_handler;
1769
1770    if (xmlValidateDocument(cvp, docp)) {
1771        RETVAL_TRUE;
1772    } else {
1773        RETVAL_FALSE;
1774    }
1775
1776    xmlFreeValidCtxt(cvp);
1777
1778}
1779/* }}} */
1780
1781#if defined(LIBXML_SCHEMAS_ENABLED)
1782static void _dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ */
1783{
1784    zval *id;
1785    xmlDoc *docp;
1786    dom_object *intern;
1787    char *source = NULL, *valid_file = NULL;
1788    size_t source_len = 0;
1789    int valid_opts = 0;
1790    zend_long flags = 0;
1791    xmlSchemaParserCtxtPtr  parser;
1792    xmlSchemaPtr            sptr;
1793    xmlSchemaValidCtxtPtr   vptr;
1794    int                     is_valid;
1795    char resolved_path[MAXPATHLEN + 1];
1796
1797    if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os|l", &id, dom_document_class_entry, &source, &source_len, &flags) == FAILURE) {
1798        return;
1799    }
1800
1801    if (source_len == 0) {
1802        php_error_docref(NULL, E_WARNING, "Invalid Schema source");
1803        RETURN_FALSE;
1804    }
1805
1806    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1807
1808    switch (type) {
1809    case DOM_LOAD_FILE:
1810        if (CHECK_NULL_PATH(source, source_len)) {
1811            php_error_docref(NULL, E_WARNING, "Invalid Schema file source");
1812            RETURN_FALSE;
1813        }
1814        valid_file = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN  TSRMLS_CC);
1815        if (!valid_file) {
1816            php_error_docref(NULL, E_WARNING, "Invalid Schema file source");
1817            RETURN_FALSE;
1818        }
1819        parser = xmlSchemaNewParserCtxt(valid_file);
1820        break;
1821    case DOM_LOAD_STRING:
1822        parser = xmlSchemaNewMemParserCtxt(source, source_len);
1823        /* If loading from memory, we need to set the base directory for the document
1824           but it is not apparent how to do that for schema's */
1825        break;
1826    default:
1827        return;
1828    }
1829
1830    xmlSchemaSetParserErrors(parser,
1831        (xmlSchemaValidityErrorFunc) php_libxml_error_handler,
1832        (xmlSchemaValidityWarningFunc) php_libxml_error_handler,
1833        parser);
1834    sptr = xmlSchemaParse(parser);
1835    xmlSchemaFreeParserCtxt(parser);
1836    if (!sptr) {
1837        php_error_docref(NULL, E_WARNING, "Invalid Schema");
1838        RETURN_FALSE;
1839    }
1840
1841    docp = (xmlDocPtr) dom_object_get_node(intern);
1842
1843    vptr = xmlSchemaNewValidCtxt(sptr);
1844    if (!vptr) {
1845        xmlSchemaFree(sptr);
1846        php_error(E_ERROR, "Invalid Schema Validation Context");
1847        RETURN_FALSE;
1848    }
1849
1850#if LIBXML_VERSION >= 20614
1851    if (flags & XML_SCHEMA_VAL_VC_I_CREATE) {
1852        valid_opts |= XML_SCHEMA_VAL_VC_I_CREATE;
1853    }
1854#endif
1855
1856    xmlSchemaSetValidOptions(vptr, valid_opts);
1857    xmlSchemaSetValidErrors(vptr, php_libxml_error_handler, php_libxml_error_handler, vptr);
1858    is_valid = xmlSchemaValidateDoc(vptr, docp);
1859    xmlSchemaFree(sptr);
1860    xmlSchemaFreeValidCtxt(vptr);
1861
1862    if (is_valid == 0) {
1863        RETURN_TRUE;
1864    } else {
1865        RETURN_FALSE;
1866    }
1867}
1868/* }}} */
1869
1870/* {{{ proto boolean dom_document_schema_validate_file(string filename, int flags); */
1871PHP_FUNCTION(dom_document_schema_validate_file)
1872{
1873    _dom_document_schema_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
1874}
1875/* }}} end dom_document_schema_validate_file */
1876
1877/* {{{ proto boolean dom_document_schema_validate(string source, int flags); */
1878PHP_FUNCTION(dom_document_schema_validate_xml)
1879{
1880    _dom_document_schema_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
1881}
1882/* }}} end dom_document_schema_validate */
1883
1884static void _dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ */
1885{
1886    zval *id;
1887    xmlDoc *docp;
1888    dom_object *intern;
1889    char *source = NULL, *valid_file = NULL;
1890    size_t source_len = 0;
1891    xmlRelaxNGParserCtxtPtr parser;
1892    xmlRelaxNGPtr           sptr;
1893    xmlRelaxNGValidCtxtPtr  vptr;
1894    int                     is_valid;
1895    char resolved_path[MAXPATHLEN + 1];
1896
1897    if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &id, dom_document_class_entry, &source, &source_len) == FAILURE) {
1898        return;
1899    }
1900
1901    if (source_len == 0) {
1902        php_error_docref(NULL, E_WARNING, "Invalid Schema source");
1903        RETURN_FALSE;
1904    }
1905
1906    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1907
1908    switch (type) {
1909    case DOM_LOAD_FILE:
1910        if (CHECK_NULL_PATH(source, source_len)) {
1911            php_error_docref(NULL, E_WARNING, "Invalid RelaxNG file source");
1912            RETURN_FALSE;
1913        }
1914        valid_file = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN  TSRMLS_CC);
1915        if (!valid_file) {
1916            php_error_docref(NULL, E_WARNING, "Invalid RelaxNG file source");
1917            RETURN_FALSE;
1918        }
1919        parser = xmlRelaxNGNewParserCtxt(valid_file);
1920        break;
1921    case DOM_LOAD_STRING:
1922        parser = xmlRelaxNGNewMemParserCtxt(source, source_len);
1923        /* If loading from memory, we need to set the base directory for the document
1924           but it is not apparent how to do that for schema's */
1925        break;
1926    default:
1927        return;
1928    }
1929
1930    xmlRelaxNGSetParserErrors(parser,
1931        (xmlRelaxNGValidityErrorFunc) php_libxml_error_handler,
1932        (xmlRelaxNGValidityWarningFunc) php_libxml_error_handler,
1933        parser);
1934    sptr = xmlRelaxNGParse(parser);
1935    xmlRelaxNGFreeParserCtxt(parser);
1936    if (!sptr) {
1937        php_error_docref(NULL, E_WARNING, "Invalid RelaxNG");
1938        RETURN_FALSE;
1939    }
1940
1941    docp = (xmlDocPtr) dom_object_get_node(intern);
1942
1943    vptr = xmlRelaxNGNewValidCtxt(sptr);
1944    if (!vptr) {
1945        xmlRelaxNGFree(sptr);
1946        php_error(E_ERROR, "Invalid RelaxNG Validation Context");
1947        RETURN_FALSE;
1948    }
1949
1950    xmlRelaxNGSetValidErrors(vptr, php_libxml_error_handler, php_libxml_error_handler, vptr);
1951    is_valid = xmlRelaxNGValidateDoc(vptr, docp);
1952    xmlRelaxNGFree(sptr);
1953    xmlRelaxNGFreeValidCtxt(vptr);
1954
1955    if (is_valid == 0) {
1956        RETURN_TRUE;
1957    } else {
1958        RETURN_FALSE;
1959    }
1960}
1961/* }}} */
1962
1963/* {{{ proto boolean dom_document_relaxNG_validate_file(string filename); */
1964PHP_FUNCTION(dom_document_relaxNG_validate_file)
1965{
1966    _dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
1967}
1968/* }}} end dom_document_relaxNG_validate_file */
1969
1970/* {{{ proto boolean dom_document_relaxNG_validate_xml(string source); */
1971PHP_FUNCTION(dom_document_relaxNG_validate_xml)
1972{
1973    _dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
1974}
1975/* }}} end dom_document_relaxNG_validate_xml */
1976
1977#endif
1978
1979#if defined(LIBXML_HTML_ENABLED)
1980
1981static void dom_load_html(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ */
1982{
1983    zval *id;
1984    xmlDoc *docp = NULL, *newdoc;
1985    dom_object *intern;
1986    dom_doc_propsptr doc_prop;
1987    char *source;
1988    size_t source_len;
1989    int refcount, ret;
1990    zend_long options = 0;
1991    htmlParserCtxtPtr ctxt;
1992
1993    id = getThis();
1994
1995    if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &source, &source_len, &options) == FAILURE) {
1996        return;
1997    }
1998
1999    if (!source_len) {
2000        php_error_docref(NULL, E_WARNING, "Empty string supplied as input");
2001        RETURN_FALSE;
2002    }
2003
2004    if (mode == DOM_LOAD_FILE) {
2005        if (CHECK_NULL_PATH(source, source_len)) {
2006            php_error_docref(NULL, E_WARNING, "Invalid file source");
2007            RETURN_FALSE;
2008        }
2009        ctxt = htmlCreateFileParserCtxt(source, NULL);
2010    } else {
2011        source_len = xmlStrlen((xmlChar *) source);
2012        ctxt = htmlCreateMemoryParserCtxt(source, source_len);
2013    }
2014
2015    if (!ctxt) {
2016        RETURN_FALSE;
2017    }
2018
2019    if (options) {
2020        htmlCtxtUseOptions(ctxt, options);
2021    }
2022
2023    ctxt->vctxt.error = php_libxml_ctx_error;
2024    ctxt->vctxt.warning = php_libxml_ctx_warning;
2025    if (ctxt->sax != NULL) {
2026        ctxt->sax->error = php_libxml_ctx_error;
2027        ctxt->sax->warning = php_libxml_ctx_warning;
2028    }
2029    htmlParseDocument(ctxt);
2030    newdoc = ctxt->myDoc;
2031    htmlFreeParserCtxt(ctxt);
2032
2033    if (!newdoc)
2034        RETURN_FALSE;
2035
2036    if (id != NULL && instanceof_function(Z_OBJCE_P(id), dom_document_class_entry)) {
2037        intern = Z_DOMOBJ_P(id);
2038        if (intern != NULL) {
2039            docp = (xmlDocPtr) dom_object_get_node(intern);
2040            doc_prop = NULL;
2041            if (docp != NULL) {
2042                php_libxml_decrement_node_ptr((php_libxml_node_object *) intern);
2043                doc_prop = intern->document->doc_props;
2044                intern->document->doc_props = NULL;
2045                refcount = php_libxml_decrement_doc_ref((php_libxml_node_object *)intern);
2046                if (refcount != 0) {
2047                    docp->_private = NULL;
2048                }
2049            }
2050            intern->document = NULL;
2051            if (php_libxml_increment_doc_ref((php_libxml_node_object *)intern, newdoc) == -1) {
2052                RETURN_FALSE;
2053            }
2054            intern->document->doc_props = doc_prop;
2055        }
2056
2057        php_libxml_increment_node_ptr((php_libxml_node_object *)intern, (xmlNodePtr)newdoc, (void *)intern);
2058
2059        RETURN_TRUE;
2060    } else {
2061        DOM_RET_OBJ((xmlNodePtr) newdoc, &ret, NULL);
2062    }
2063}
2064/* }}} */
2065
2066/* {{{ proto DOMNode dom_document_load_html_file(string source)
2067Since: DOM extended
2068*/
2069PHP_METHOD(domdocument, loadHTMLFile)
2070{
2071    dom_load_html(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
2072}
2073/* }}} end dom_document_load_html_file */
2074
2075/* {{{ proto DOMNode dom_document_load_html(string source)
2076Since: DOM extended
2077*/
2078PHP_METHOD(domdocument, loadHTML)
2079{
2080    dom_load_html(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
2081}
2082/* }}} end dom_document_load_html */
2083
2084/* {{{ proto int dom_document_save_html_file(string file)
2085Convenience method to save to file as html
2086*/
2087PHP_FUNCTION(dom_document_save_html_file)
2088{
2089    zval *id;
2090    xmlDoc *docp;
2091    size_t file_len;
2092    int bytes, format;
2093    dom_object *intern;
2094    dom_doc_propsptr doc_props;
2095    char *file;
2096    const char *encoding;
2097
2098    if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Op", &id, dom_document_class_entry, &file, &file_len) == FAILURE) {
2099        return;
2100    }
2101
2102    if (file_len == 0) {
2103        php_error_docref(NULL, E_WARNING, "Invalid Filename");
2104        RETURN_FALSE;
2105    }
2106
2107    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
2108
2109
2110    encoding = (const char *) htmlGetMetaEncoding(docp);
2111
2112    doc_props = dom_get_doc_props(intern->document);
2113    format = doc_props->formatoutput;
2114    bytes = htmlSaveFileFormat(file, docp, encoding, format);
2115
2116    if (bytes == -1) {
2117        RETURN_FALSE;
2118    }
2119    RETURN_LONG(bytes);
2120}
2121/* }}} end dom_document_save_html_file */
2122
2123/* {{{ proto string dom_document_save_html()
2124Convenience method to output as html
2125*/
2126PHP_FUNCTION(dom_document_save_html)
2127{
2128    zval *id, *nodep = NULL;
2129    xmlDoc *docp;
2130    xmlNode *node;
2131    xmlBufferPtr buf;
2132    dom_object *intern, *nodeobj;
2133    xmlChar *mem = NULL;
2134    int size = 0, format;
2135    dom_doc_propsptr doc_props;
2136
2137    if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
2138        "O|O!", &id, dom_document_class_entry, &nodep, dom_node_class_entry)
2139        == FAILURE) {
2140        return;
2141    }
2142
2143    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
2144
2145    doc_props = dom_get_doc_props(intern->document);
2146    format = doc_props->formatoutput;
2147
2148    if (nodep != NULL) {
2149        /* Dump contents of Node */
2150        DOM_GET_OBJ(node, nodep, xmlNodePtr, nodeobj);
2151        if (node->doc != docp) {
2152            php_dom_throw_error(WRONG_DOCUMENT_ERR, dom_get_strict_error(intern->document));
2153            RETURN_FALSE;
2154        }
2155
2156        buf = xmlBufferCreate();
2157        if (!buf) {
2158            php_error_docref(NULL, E_WARNING, "Could not fetch buffer");
2159            RETURN_FALSE;
2160        }
2161
2162        if (node->type == XML_DOCUMENT_FRAG_NODE) {
2163            int one_size;
2164
2165            for (node = node->children; node; node = node->next) {
2166                one_size = htmlNodeDump(buf, docp, node);
2167
2168                if (one_size >= 0) {
2169                    size += one_size;
2170                } else {
2171                    size = -1;
2172                    break;
2173                }
2174            }
2175        } else {
2176            size = htmlNodeDump(buf, docp, node);
2177        }
2178        if (size >= 0) {
2179            mem = (xmlChar*) xmlBufferContent(buf);
2180            if (!mem) {
2181                RETVAL_FALSE;
2182            } else {
2183                RETVAL_STRINGL((const char*) mem, size);
2184            }
2185        } else {
2186            php_error_docref(NULL, E_WARNING, "Error dumping HTML node");
2187            RETVAL_FALSE;
2188        }
2189        xmlBufferFree(buf);
2190    } else {
2191#if LIBXML_VERSION >= 20623
2192        htmlDocDumpMemoryFormat(docp, &mem, &size, format);
2193#else
2194        htmlDocDumpMemory(docp, &mem, &size);
2195#endif
2196        if (!size) {
2197            RETVAL_FALSE;
2198        } else {
2199            RETVAL_STRINGL((const char*) mem, size);
2200        }
2201        if (mem)
2202            xmlFree(mem);
2203    }
2204
2205}
2206/* }}} end dom_document_save_html */
2207
2208#endif  /* defined(LIBXML_HTML_ENABLED) */
2209
2210/* {{{ proto boolean DOMDocument::registerNodeClass(string baseclass, string extendedclass)
2211   Register extended class used to create base node type */
2212PHP_METHOD(domdocument, registerNodeClass)
2213{
2214    zval *id;
2215    xmlDoc *docp;
2216    zend_class_entry *basece = dom_node_class_entry, *ce = NULL;
2217    dom_object *intern;
2218
2219    if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "OCC!", &id, dom_document_class_entry, &basece, &ce) == FAILURE) {
2220        return;
2221    }
2222
2223    if (ce == NULL || instanceof_function(ce, basece)) {
2224        DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
2225
2226        if (dom_set_doc_classmap(intern->document, basece, ce) == FAILURE) {
2227            php_error_docref(NULL, E_ERROR, "Class %s could not be registered.", ZSTR_VAL(ce->name));
2228        }
2229        RETURN_TRUE;
2230    } else {
2231        php_error_docref(NULL, E_ERROR, "Class %s is not derived from %s.", ZSTR_VAL(ce->name), ZSTR_VAL(basece->name));
2232    }
2233
2234    RETURN_FALSE;
2235}
2236/* }}} */
2237
2238#endif  /* HAVE_LIBXML && HAVE_DOM */
2239
2240/*
2241 * Local variables:
2242 * tab-width: 4
2243 * c-basic-offset: 4
2244 * End:
2245 * vim600: noet sw=4 ts=4 fdm=marker
2246 * vim<600: noet sw=4 ts=4
2247 */
2248