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