1/*
2   +----------------------------------------------------------------------+
3   | PHP Version 7                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2016 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	zend_long 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_bool recursive = 0;
982
983	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "OO|b", &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	if (ZEND_LONG_EXCEEDS_INT(flags)) {
1732		php_error_docref(NULL, E_WARNING, "Invalid flags");
1733		RETURN_FALSE;
1734	}
1735
1736	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1737
1738	err = xmlXIncludeProcessFlags(docp, (int)flags);
1739
1740	/* XML_XINCLUDE_START and XML_XINCLUDE_END nodes need to be removed as these
1741	are added via xmlXIncludeProcess to mark beginning and ending of xincluded document
1742	but are not wanted in resulting document - must be done even if err as it could fail after
1743	having processed some xincludes */
1744	root = (xmlNodePtr) docp->children;
1745	while(root && root->type != XML_ELEMENT_NODE && root->type != XML_XINCLUDE_START) {
1746		root = root->next;
1747	}
1748	if (root) {
1749		php_dom_remove_xinclude_nodes(root);
1750	}
1751
1752	if (err) {
1753		RETVAL_LONG(err);
1754	} else {
1755		RETVAL_FALSE;
1756	}
1757
1758}
1759/* }}} */
1760
1761/* {{{ proto boolean dom_document_validate()
1762Since: DOM extended
1763*/
1764PHP_FUNCTION(dom_document_validate)
1765{
1766	zval *id;
1767	xmlDoc *docp;
1768	dom_object *intern;
1769	xmlValidCtxt *cvp;
1770
1771	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &id, dom_document_class_entry) == FAILURE) {
1772		return;
1773	}
1774
1775	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1776
1777	cvp = xmlNewValidCtxt();
1778
1779	cvp->userData = NULL;
1780	cvp->error    = (xmlValidityErrorFunc) php_libxml_error_handler;
1781	cvp->warning  = (xmlValidityErrorFunc) php_libxml_error_handler;
1782
1783	if (xmlValidateDocument(cvp, docp)) {
1784		RETVAL_TRUE;
1785	} else {
1786		RETVAL_FALSE;
1787	}
1788
1789	xmlFreeValidCtxt(cvp);
1790
1791}
1792/* }}} */
1793
1794#if defined(LIBXML_SCHEMAS_ENABLED)
1795static void _dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ */
1796{
1797	zval *id;
1798	xmlDoc *docp;
1799	dom_object *intern;
1800	char *source = NULL, *valid_file = NULL;
1801	size_t source_len = 0;
1802	int valid_opts = 0;
1803	zend_long flags = 0;
1804	xmlSchemaParserCtxtPtr  parser;
1805	xmlSchemaPtr            sptr;
1806	xmlSchemaValidCtxtPtr   vptr;
1807	int                     is_valid;
1808	char resolved_path[MAXPATHLEN + 1];
1809
1810	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os|l", &id, dom_document_class_entry, &source, &source_len, &flags) == FAILURE) {
1811		return;
1812	}
1813
1814	if (source_len == 0) {
1815		php_error_docref(NULL, E_WARNING, "Invalid Schema source");
1816		RETURN_FALSE;
1817	}
1818
1819	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1820
1821	switch (type) {
1822	case DOM_LOAD_FILE:
1823		if (CHECK_NULL_PATH(source, source_len)) {
1824			php_error_docref(NULL, E_WARNING, "Invalid Schema file source");
1825			RETURN_FALSE;
1826		}
1827		valid_file = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN);
1828		if (!valid_file) {
1829			php_error_docref(NULL, E_WARNING, "Invalid Schema file source");
1830			RETURN_FALSE;
1831		}
1832		parser = xmlSchemaNewParserCtxt(valid_file);
1833		break;
1834	case DOM_LOAD_STRING:
1835		parser = xmlSchemaNewMemParserCtxt(source, source_len);
1836		/* If loading from memory, we need to set the base directory for the document
1837		   but it is not apparent how to do that for schema's */
1838		break;
1839	default:
1840		return;
1841	}
1842
1843	xmlSchemaSetParserErrors(parser,
1844		(xmlSchemaValidityErrorFunc) php_libxml_error_handler,
1845		(xmlSchemaValidityWarningFunc) php_libxml_error_handler,
1846		parser);
1847	sptr = xmlSchemaParse(parser);
1848	xmlSchemaFreeParserCtxt(parser);
1849	if (!sptr) {
1850		php_error_docref(NULL, E_WARNING, "Invalid Schema");
1851		RETURN_FALSE;
1852	}
1853
1854	docp = (xmlDocPtr) dom_object_get_node(intern);
1855
1856	vptr = xmlSchemaNewValidCtxt(sptr);
1857	if (!vptr) {
1858		xmlSchemaFree(sptr);
1859		php_error(E_ERROR, "Invalid Schema Validation Context");
1860		RETURN_FALSE;
1861	}
1862
1863#if LIBXML_VERSION >= 20614
1864	if (flags & XML_SCHEMA_VAL_VC_I_CREATE) {
1865		valid_opts |= XML_SCHEMA_VAL_VC_I_CREATE;
1866	}
1867#endif
1868
1869	xmlSchemaSetValidOptions(vptr, valid_opts);
1870	xmlSchemaSetValidErrors(vptr, php_libxml_error_handler, php_libxml_error_handler, vptr);
1871	is_valid = xmlSchemaValidateDoc(vptr, docp);
1872	xmlSchemaFree(sptr);
1873	xmlSchemaFreeValidCtxt(vptr);
1874
1875	if (is_valid == 0) {
1876		RETURN_TRUE;
1877	} else {
1878		RETURN_FALSE;
1879	}
1880}
1881/* }}} */
1882
1883/* {{{ proto boolean dom_document_schema_validate_file(string filename, int flags); */
1884PHP_FUNCTION(dom_document_schema_validate_file)
1885{
1886	_dom_document_schema_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
1887}
1888/* }}} end dom_document_schema_validate_file */
1889
1890/* {{{ proto boolean dom_document_schema_validate(string source, int flags); */
1891PHP_FUNCTION(dom_document_schema_validate_xml)
1892{
1893	_dom_document_schema_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
1894}
1895/* }}} end dom_document_schema_validate */
1896
1897static void _dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ */
1898{
1899	zval *id;
1900	xmlDoc *docp;
1901	dom_object *intern;
1902	char *source = NULL, *valid_file = NULL;
1903	size_t source_len = 0;
1904	xmlRelaxNGParserCtxtPtr parser;
1905	xmlRelaxNGPtr           sptr;
1906	xmlRelaxNGValidCtxtPtr  vptr;
1907	int                     is_valid;
1908	char resolved_path[MAXPATHLEN + 1];
1909
1910	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &id, dom_document_class_entry, &source, &source_len) == FAILURE) {
1911		return;
1912	}
1913
1914	if (source_len == 0) {
1915		php_error_docref(NULL, E_WARNING, "Invalid Schema source");
1916		RETURN_FALSE;
1917	}
1918
1919	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1920
1921	switch (type) {
1922	case DOM_LOAD_FILE:
1923		if (CHECK_NULL_PATH(source, source_len)) {
1924			php_error_docref(NULL, E_WARNING, "Invalid RelaxNG file source");
1925			RETURN_FALSE;
1926		}
1927		valid_file = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN);
1928		if (!valid_file) {
1929			php_error_docref(NULL, E_WARNING, "Invalid RelaxNG file source");
1930			RETURN_FALSE;
1931		}
1932		parser = xmlRelaxNGNewParserCtxt(valid_file);
1933		break;
1934	case DOM_LOAD_STRING:
1935		parser = xmlRelaxNGNewMemParserCtxt(source, source_len);
1936		/* If loading from memory, we need to set the base directory for the document
1937		   but it is not apparent how to do that for schema's */
1938		break;
1939	default:
1940		return;
1941	}
1942
1943	xmlRelaxNGSetParserErrors(parser,
1944		(xmlRelaxNGValidityErrorFunc) php_libxml_error_handler,
1945		(xmlRelaxNGValidityWarningFunc) php_libxml_error_handler,
1946		parser);
1947	sptr = xmlRelaxNGParse(parser);
1948	xmlRelaxNGFreeParserCtxt(parser);
1949	if (!sptr) {
1950		php_error_docref(NULL, E_WARNING, "Invalid RelaxNG");
1951		RETURN_FALSE;
1952	}
1953
1954	docp = (xmlDocPtr) dom_object_get_node(intern);
1955
1956	vptr = xmlRelaxNGNewValidCtxt(sptr);
1957	if (!vptr) {
1958		xmlRelaxNGFree(sptr);
1959		php_error(E_ERROR, "Invalid RelaxNG Validation Context");
1960		RETURN_FALSE;
1961	}
1962
1963	xmlRelaxNGSetValidErrors(vptr, php_libxml_error_handler, php_libxml_error_handler, vptr);
1964	is_valid = xmlRelaxNGValidateDoc(vptr, docp);
1965	xmlRelaxNGFree(sptr);
1966	xmlRelaxNGFreeValidCtxt(vptr);
1967
1968	if (is_valid == 0) {
1969		RETURN_TRUE;
1970	} else {
1971		RETURN_FALSE;
1972	}
1973}
1974/* }}} */
1975
1976/* {{{ proto boolean dom_document_relaxNG_validate_file(string filename); */
1977PHP_FUNCTION(dom_document_relaxNG_validate_file)
1978{
1979	_dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
1980}
1981/* }}} end dom_document_relaxNG_validate_file */
1982
1983/* {{{ proto boolean dom_document_relaxNG_validate_xml(string source); */
1984PHP_FUNCTION(dom_document_relaxNG_validate_xml)
1985{
1986	_dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
1987}
1988/* }}} end dom_document_relaxNG_validate_xml */
1989
1990#endif
1991
1992#if defined(LIBXML_HTML_ENABLED)
1993
1994static void dom_load_html(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ */
1995{
1996	zval *id;
1997	xmlDoc *docp = NULL, *newdoc;
1998	dom_object *intern;
1999	dom_doc_propsptr doc_prop;
2000	char *source;
2001	size_t source_len;
2002	int refcount, ret;
2003	zend_long options = 0;
2004	htmlParserCtxtPtr ctxt;
2005
2006	id = getThis();
2007
2008	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &source, &source_len, &options) == FAILURE) {
2009		return;
2010	}
2011
2012	if (!source_len) {
2013		php_error_docref(NULL, E_WARNING, "Empty string supplied as input");
2014		RETURN_FALSE;
2015	}
2016
2017	if (ZEND_LONG_EXCEEDS_INT(options)) {
2018		php_error_docref(NULL, E_WARNING, "Invalid options");
2019		RETURN_FALSE;
2020	}
2021
2022	if (mode == DOM_LOAD_FILE) {
2023		if (CHECK_NULL_PATH(source, source_len)) {
2024			php_error_docref(NULL, E_WARNING, "Invalid file source");
2025			RETURN_FALSE;
2026		}
2027		ctxt = htmlCreateFileParserCtxt(source, NULL);
2028	} else {
2029		source_len = xmlStrlen((xmlChar *) source);
2030		if (ZEND_SIZE_T_INT_OVFL(source_len)) {
2031			php_error_docref(NULL, E_WARNING, "Input string is too long");
2032			RETURN_FALSE;
2033		}
2034		ctxt = htmlCreateMemoryParserCtxt(source, (int)source_len);
2035	}
2036
2037	if (!ctxt) {
2038		RETURN_FALSE;
2039	}
2040
2041	if (options) {
2042		htmlCtxtUseOptions(ctxt, (int)options);
2043	}
2044
2045	ctxt->vctxt.error = php_libxml_ctx_error;
2046	ctxt->vctxt.warning = php_libxml_ctx_warning;
2047	if (ctxt->sax != NULL) {
2048		ctxt->sax->error = php_libxml_ctx_error;
2049		ctxt->sax->warning = php_libxml_ctx_warning;
2050	}
2051	htmlParseDocument(ctxt);
2052	newdoc = ctxt->myDoc;
2053	htmlFreeParserCtxt(ctxt);
2054
2055	if (!newdoc)
2056		RETURN_FALSE;
2057
2058	if (id != NULL && instanceof_function(Z_OBJCE_P(id), dom_document_class_entry)) {
2059		intern = Z_DOMOBJ_P(id);
2060		if (intern != NULL) {
2061			docp = (xmlDocPtr) dom_object_get_node(intern);
2062			doc_prop = NULL;
2063			if (docp != NULL) {
2064				php_libxml_decrement_node_ptr((php_libxml_node_object *) intern);
2065				doc_prop = intern->document->doc_props;
2066				intern->document->doc_props = NULL;
2067				refcount = php_libxml_decrement_doc_ref((php_libxml_node_object *)intern);
2068				if (refcount != 0) {
2069					docp->_private = NULL;
2070				}
2071			}
2072			intern->document = NULL;
2073			if (php_libxml_increment_doc_ref((php_libxml_node_object *)intern, newdoc) == -1) {
2074				RETURN_FALSE;
2075			}
2076			intern->document->doc_props = doc_prop;
2077		}
2078
2079		php_libxml_increment_node_ptr((php_libxml_node_object *)intern, (xmlNodePtr)newdoc, (void *)intern);
2080
2081		RETURN_TRUE;
2082	} else {
2083		DOM_RET_OBJ((xmlNodePtr) newdoc, &ret, NULL);
2084	}
2085}
2086/* }}} */
2087
2088/* {{{ proto DOMNode dom_document_load_html_file(string source)
2089Since: DOM extended
2090*/
2091PHP_METHOD(domdocument, loadHTMLFile)
2092{
2093	dom_load_html(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
2094}
2095/* }}} end dom_document_load_html_file */
2096
2097/* {{{ proto DOMNode dom_document_load_html(string source)
2098Since: DOM extended
2099*/
2100PHP_METHOD(domdocument, loadHTML)
2101{
2102	dom_load_html(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
2103}
2104/* }}} end dom_document_load_html */
2105
2106/* {{{ proto int dom_document_save_html_file(string file)
2107Convenience method to save to file as html
2108*/
2109PHP_FUNCTION(dom_document_save_html_file)
2110{
2111	zval *id;
2112	xmlDoc *docp;
2113	size_t file_len;
2114	int bytes, format;
2115	dom_object *intern;
2116	dom_doc_propsptr doc_props;
2117	char *file;
2118	const char *encoding;
2119
2120	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Op", &id, dom_document_class_entry, &file, &file_len) == FAILURE) {
2121		return;
2122	}
2123
2124	if (file_len == 0) {
2125		php_error_docref(NULL, E_WARNING, "Invalid Filename");
2126		RETURN_FALSE;
2127	}
2128
2129	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
2130
2131
2132	encoding = (const char *) htmlGetMetaEncoding(docp);
2133
2134	doc_props = dom_get_doc_props(intern->document);
2135	format = doc_props->formatoutput;
2136	bytes = htmlSaveFileFormat(file, docp, encoding, format);
2137
2138	if (bytes == -1) {
2139		RETURN_FALSE;
2140	}
2141	RETURN_LONG(bytes);
2142}
2143/* }}} end dom_document_save_html_file */
2144
2145/* {{{ proto string dom_document_save_html()
2146Convenience method to output as html
2147*/
2148PHP_FUNCTION(dom_document_save_html)
2149{
2150	zval *id, *nodep = NULL;
2151	xmlDoc *docp;
2152	xmlNode *node;
2153	xmlBufferPtr buf;
2154	dom_object *intern, *nodeobj;
2155	xmlChar *mem = NULL;
2156	int size = 0, format;
2157	dom_doc_propsptr doc_props;
2158
2159	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
2160		"O|O!", &id, dom_document_class_entry, &nodep, dom_node_class_entry)
2161		== FAILURE) {
2162		return;
2163	}
2164
2165	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
2166
2167	doc_props = dom_get_doc_props(intern->document);
2168	format = doc_props->formatoutput;
2169
2170	if (nodep != NULL) {
2171		/* Dump contents of Node */
2172		DOM_GET_OBJ(node, nodep, xmlNodePtr, nodeobj);
2173		if (node->doc != docp) {
2174			php_dom_throw_error(WRONG_DOCUMENT_ERR, dom_get_strict_error(intern->document));
2175			RETURN_FALSE;
2176		}
2177
2178		buf = xmlBufferCreate();
2179		if (!buf) {
2180			php_error_docref(NULL, E_WARNING, "Could not fetch buffer");
2181			RETURN_FALSE;
2182		}
2183
2184		if (node->type == XML_DOCUMENT_FRAG_NODE) {
2185			int one_size;
2186
2187			for (node = node->children; node; node = node->next) {
2188				one_size = htmlNodeDump(buf, docp, node);
2189
2190				if (one_size >= 0) {
2191					size += one_size;
2192				} else {
2193					size = -1;
2194					break;
2195				}
2196			}
2197		} else {
2198			size = htmlNodeDump(buf, docp, node);
2199		}
2200		if (size >= 0) {
2201			mem = (xmlChar*) xmlBufferContent(buf);
2202			if (!mem) {
2203				RETVAL_FALSE;
2204			} else {
2205				RETVAL_STRINGL((const char*) mem, size);
2206			}
2207		} else {
2208			php_error_docref(NULL, E_WARNING, "Error dumping HTML node");
2209			RETVAL_FALSE;
2210		}
2211		xmlBufferFree(buf);
2212	} else {
2213#if LIBXML_VERSION >= 20623
2214		htmlDocDumpMemoryFormat(docp, &mem, &size, format);
2215#else
2216		htmlDocDumpMemory(docp, &mem, &size);
2217#endif
2218		if (!size) {
2219			RETVAL_FALSE;
2220		} else {
2221			RETVAL_STRINGL((const char*) mem, size);
2222		}
2223		if (mem)
2224			xmlFree(mem);
2225	}
2226
2227}
2228/* }}} end dom_document_save_html */
2229
2230#endif  /* defined(LIBXML_HTML_ENABLED) */
2231
2232/* {{{ proto boolean DOMDocument::registerNodeClass(string baseclass, string extendedclass)
2233   Register extended class used to create base node type */
2234PHP_METHOD(domdocument, registerNodeClass)
2235{
2236	zval *id;
2237	xmlDoc *docp;
2238	zend_class_entry *basece = dom_node_class_entry, *ce = NULL;
2239	dom_object *intern;
2240
2241	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "OCC!", &id, dom_document_class_entry, &basece, &ce) == FAILURE) {
2242		return;
2243	}
2244
2245	if (ce == NULL || instanceof_function(ce, basece)) {
2246		DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
2247
2248		if (dom_set_doc_classmap(intern->document, basece, ce) == FAILURE) {
2249			php_error_docref(NULL, E_ERROR, "Class %s could not be registered.", ZSTR_VAL(ce->name));
2250		}
2251		RETURN_TRUE;
2252	} else {
2253		php_error_docref(NULL, E_ERROR, "Class %s is not derived from %s.", ZSTR_VAL(ce->name), ZSTR_VAL(basece->name));
2254	}
2255
2256	RETURN_FALSE;
2257}
2258/* }}} */
2259
2260#endif  /* HAVE_LIBXML && HAVE_DOM */
2261
2262/*
2263 * Local variables:
2264 * tab-width: 4
2265 * c-basic-offset: 4
2266 * End:
2267 * vim600: noet sw=4 ts=4 fdm=marker
2268 * vim<600: noet sw=4 ts=4
2269 */
2270