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;
701    size_t name_len, value_len;
702    char *name, *value = NULL;
703
704    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) {
705        return;
706    }
707
708    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
709
710    if (xmlValidateName((xmlChar *) name, 0) != 0) {
711        php_dom_throw_error(INVALID_CHARACTER_ERR, dom_get_strict_error(intern->document) TSRMLS_CC);
712        RETURN_FALSE;
713    }
714
715    node = xmlNewDocNode(docp, NULL, name, value);
716    if (!node) {
717        RETURN_FALSE;
718    }
719
720    DOM_RET_OBJ(node, &ret, intern);
721}
722/* }}} end dom_document_create_element */
723
724/* {{{ proto DOMDocumentFragment dom_document_create_document_fragment();
725URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-35CB04B5
726Since:
727*/
728PHP_FUNCTION(dom_document_create_document_fragment)
729{
730    zval *id;
731    xmlNode *node;
732    xmlDocPtr docp;
733    dom_object *intern;
734    int ret;
735
736    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &id, dom_document_class_entry) == FAILURE) {
737        return;
738    }
739
740    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
741
742    node =  xmlNewDocFragment(docp);
743    if (!node) {
744        RETURN_FALSE;
745    }
746
747    DOM_RET_OBJ(node, &ret, intern);
748}
749/* }}} end dom_document_create_document_fragment */
750
751/* {{{ proto DOMText dom_document_create_text_node(string data);
752URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1975348127
753Since:
754*/
755PHP_FUNCTION(dom_document_create_text_node)
756{
757    zval *id;
758    xmlNode *node;
759    xmlDocPtr docp;
760    int ret;
761    size_t value_len;
762    dom_object *intern;
763    char *value;
764
765    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &id, dom_document_class_entry, &value, &value_len) == FAILURE) {
766        return;
767    }
768
769    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
770
771    node = xmlNewDocText(docp, (xmlChar *) value);
772    if (!node) {
773        RETURN_FALSE;
774    }
775
776    DOM_RET_OBJ(node, &ret, intern);
777}
778/* }}} end dom_document_create_text_node */
779
780/* {{{ proto DOMComment dom_document_create_comment(string data);
781URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1334481328
782Since:
783*/
784PHP_FUNCTION(dom_document_create_comment)
785{
786    zval *id;
787    xmlNode *node;
788    xmlDocPtr docp;
789    int ret;
790    size_t value_len;
791    dom_object *intern;
792    char *value;
793
794    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &id, dom_document_class_entry, &value, &value_len) == FAILURE) {
795        return;
796    }
797
798    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
799
800    node = xmlNewDocComment(docp, (xmlChar *) value);
801    if (!node) {
802        RETURN_FALSE;
803    }
804
805    DOM_RET_OBJ(node, &ret, intern);
806}
807/* }}} end dom_document_create_comment */
808
809/* {{{ proto DOMCdataSection dom_document_create_cdatasection(string data);
810URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-D26C0AF8
811Since:
812*/
813PHP_FUNCTION(dom_document_create_cdatasection)
814{
815    zval *id;
816    xmlNode *node;
817    xmlDocPtr docp;
818    int ret;
819    size_t value_len;
820    dom_object *intern;
821    char *value;
822
823    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &id, dom_document_class_entry, &value, &value_len) == FAILURE) {
824        return;
825    }
826
827    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
828
829    node = xmlNewCDataBlock(docp, (xmlChar *) value, value_len);
830    if (!node) {
831        RETURN_FALSE;
832    }
833
834    DOM_RET_OBJ(node, &ret, intern);
835}
836/* }}} end dom_document_create_cdatasection */
837
838/* {{{ proto DOMProcessingInstruction dom_document_create_processing_instruction(string target, string data);
839URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-135944439
840Since:
841*/
842PHP_FUNCTION(dom_document_create_processing_instruction)
843{
844    zval *id;
845    xmlNode *node;
846    xmlDocPtr docp;
847    int ret;
848    size_t value_len, name_len = 0;
849    dom_object *intern;
850    char *name, *value = NULL;
851
852    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) {
853        return;
854    }
855
856    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
857
858    if (xmlValidateName((xmlChar *) name, 0) != 0) {
859        php_dom_throw_error(INVALID_CHARACTER_ERR, dom_get_strict_error(intern->document) TSRMLS_CC);
860        RETURN_FALSE;
861    }
862
863    node = xmlNewPI((xmlChar *) name, (xmlChar *) value);
864    if (!node) {
865        RETURN_FALSE;
866    }
867
868    node->doc = docp;
869
870    DOM_RET_OBJ(node, &ret, intern);
871}
872/* }}} end dom_document_create_processing_instruction */
873
874/* {{{ proto DOMAttr dom_document_create_attribute(string name);
875URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1084891198
876Since:
877*/
878PHP_FUNCTION(dom_document_create_attribute)
879{
880    zval *id;
881    xmlAttrPtr node;
882    xmlDocPtr docp;
883    int ret;
884    size_t name_len;
885    dom_object *intern;
886    char *name;
887
888    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &id, dom_document_class_entry, &name, &name_len) == FAILURE) {
889        return;
890    }
891
892    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
893
894    if (xmlValidateName((xmlChar *) name, 0) != 0) {
895        php_dom_throw_error(INVALID_CHARACTER_ERR, dom_get_strict_error(intern->document) TSRMLS_CC);
896        RETURN_FALSE;
897    }
898
899    node = xmlNewDocProp(docp, (xmlChar *) name, NULL);
900    if (!node) {
901        RETURN_FALSE;
902    }
903
904    DOM_RET_OBJ((xmlNodePtr) node, &ret, intern);
905
906}
907/* }}} end dom_document_create_attribute */
908
909/* {{{ proto DOMEntityReference dom_document_create_entity_reference(string name);
910URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-392B75AE
911Since:
912*/
913PHP_FUNCTION(dom_document_create_entity_reference)
914{
915    zval *id;
916    xmlNode *node;
917    xmlDocPtr docp = NULL;
918    dom_object *intern;
919    int ret;
920    size_t name_len;
921    char *name;
922
923    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &id, dom_document_class_entry, &name, &name_len) == FAILURE) {
924        return;
925    }
926
927    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
928
929    if (xmlValidateName((xmlChar *) name, 0) != 0) {
930        php_dom_throw_error(INVALID_CHARACTER_ERR, dom_get_strict_error(intern->document) TSRMLS_CC);
931        RETURN_FALSE;
932    }
933
934    node = xmlNewReference(docp, name);
935    if (!node) {
936        RETURN_FALSE;
937    }
938
939    DOM_RET_OBJ((xmlNodePtr) node, &ret, intern);
940}
941/* }}} end dom_document_create_entity_reference */
942
943/* {{{ proto DOMNodeList dom_document_get_elements_by_tag_name(string tagname);
944URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-A6C9094
945Since:
946*/
947PHP_FUNCTION(dom_document_get_elements_by_tag_name)
948{
949    zval *id;
950    xmlDocPtr docp;
951    size_t name_len;
952    dom_object *intern, *namednode;
953    char *name;
954    xmlChar *local;
955
956    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &id, dom_document_class_entry, &name, &name_len) == FAILURE) {
957        return;
958    }
959
960    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
961
962    php_dom_create_interator(return_value, DOM_NODELIST TSRMLS_CC);
963    namednode = Z_DOMOBJ_P(return_value);
964    local = xmlCharStrndup(name, name_len);
965    dom_namednode_iter(intern, 0, namednode, NULL, local, NULL TSRMLS_CC);
966}
967/* }}} end dom_document_get_elements_by_tag_name */
968
969/* {{{ proto DOMNode dom_document_import_node(DOMNode importedNode, boolean deep);
970URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Core-Document-importNode
971Since: DOM Level 2
972*/
973PHP_FUNCTION(dom_document_import_node)
974{
975    zval *id, *node;
976    xmlDocPtr docp;
977    xmlNodePtr nodep, retnodep;
978    dom_object *intern, *nodeobj;
979    int ret;
980    zend_long recursive = 0;
981
982    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) {
983        return;
984    }
985
986    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
987
988    DOM_GET_OBJ(nodep, node, xmlNodePtr, nodeobj);
989
990    if (nodep->type == XML_HTML_DOCUMENT_NODE || nodep->type == XML_DOCUMENT_NODE
991        || nodep->type == XML_DOCUMENT_TYPE_NODE) {
992        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot import: Node Type Not Supported");
993        RETURN_FALSE;
994    }
995
996    if (nodep->doc == docp) {
997        retnodep = nodep;
998    } else {
999        if ((recursive == 0) && (nodep->type == XML_ELEMENT_NODE)) {
1000            recursive = 2;
1001        }
1002        retnodep = xmlDocCopyNode(nodep, docp, recursive);
1003        if (!retnodep) {
1004            RETURN_FALSE;
1005        }
1006
1007        if ((retnodep->type == XML_ATTRIBUTE_NODE) && (nodep->ns != NULL)) {
1008            xmlNsPtr nsptr = NULL;
1009            xmlNodePtr root = xmlDocGetRootElement(docp);
1010
1011            nsptr = xmlSearchNsByHref (nodep->doc, root, nodep->ns->href);
1012            if (nsptr == NULL) {
1013                int errorcode;
1014                nsptr = dom_get_ns(root, (char *) nodep->ns->href, &errorcode, (char *) nodep->ns->prefix);
1015            }
1016            xmlSetNs(retnodep, nsptr);
1017        }
1018    }
1019
1020    DOM_RET_OBJ((xmlNodePtr) retnodep, &ret, intern);
1021}
1022/* }}} end dom_document_import_node */
1023
1024/* {{{ proto DOMElement dom_document_create_element_ns(string namespaceURI, string qualifiedName [,string value]);
1025URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-DocCrElNS
1026Since: DOM Level 2
1027*/
1028PHP_FUNCTION(dom_document_create_element_ns)
1029{
1030    zval *id;
1031    xmlDocPtr docp;
1032    xmlNodePtr nodep = NULL;
1033    xmlNsPtr nsptr = NULL;
1034    int ret;
1035    size_t uri_len = 0, name_len = 0, value_len = 0;
1036    char *uri, *name, *value = NULL;
1037    char *localname = NULL, *prefix = NULL;
1038    int errorcode;
1039    dom_object *intern;
1040
1041    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) {
1042        return;
1043    }
1044
1045    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1046
1047    errorcode = dom_check_qname(name, &localname, &prefix, uri_len, name_len);
1048
1049    if (errorcode == 0) {
1050        if (xmlValidateName((xmlChar *) localname, 0) == 0) {
1051            nodep = xmlNewDocNode (docp, NULL, localname, value);
1052            if (nodep != NULL && uri != NULL) {
1053                nsptr = xmlSearchNsByHref (nodep->doc, nodep, uri);
1054                if (nsptr == NULL) {
1055                    nsptr = dom_get_ns(nodep, uri, &errorcode, prefix);
1056                }
1057                xmlSetNs(nodep, nsptr);
1058            }
1059        } else {
1060            errorcode = INVALID_CHARACTER_ERR;
1061        }
1062    }
1063
1064    xmlFree(localname);
1065    if (prefix != NULL) {
1066        xmlFree(prefix);
1067    }
1068
1069    if (errorcode != 0) {
1070        if (nodep != NULL) {
1071            xmlFreeNode(nodep);
1072        }
1073        php_dom_throw_error(errorcode, dom_get_strict_error(intern->document) TSRMLS_CC);
1074        RETURN_FALSE;
1075    }
1076
1077    if (nodep == NULL) {
1078        RETURN_FALSE;
1079    }
1080
1081
1082    nodep->ns = nsptr;
1083
1084    DOM_RET_OBJ(nodep, &ret, intern);
1085}
1086/* }}} end dom_document_create_element_ns */
1087
1088/* {{{ proto DOMAttr dom_document_create_attribute_ns(string namespaceURI, string qualifiedName);
1089URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-DocCrAttrNS
1090Since: DOM Level 2
1091*/
1092PHP_FUNCTION(dom_document_create_attribute_ns)
1093{
1094    zval *id;
1095    xmlDocPtr docp;
1096    xmlNodePtr nodep = NULL, root;
1097    xmlNsPtr nsptr;
1098    int ret;
1099    size_t uri_len = 0, name_len = 0;
1100    char *uri, *name;
1101    char *localname = NULL, *prefix = NULL;
1102    dom_object *intern;
1103    int errorcode;
1104
1105    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) {
1106        return;
1107    }
1108
1109    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1110
1111    root = xmlDocGetRootElement(docp);
1112    if (root != NULL) {
1113        errorcode = dom_check_qname(name, &localname, &prefix, uri_len, name_len);
1114        if (errorcode == 0) {
1115            if (xmlValidateName((xmlChar *) localname, 0) == 0) {
1116                nodep = (xmlNodePtr) xmlNewDocProp(docp, localname, NULL);
1117                if (nodep != NULL && uri_len > 0) {
1118                    nsptr = xmlSearchNsByHref (nodep->doc, root, uri);
1119                    if (nsptr == NULL) {
1120                        nsptr = dom_get_ns(root, uri, &errorcode, prefix);
1121                    }
1122                    xmlSetNs(nodep, nsptr);
1123                }
1124            } else {
1125                errorcode = INVALID_CHARACTER_ERR;
1126            }
1127        }
1128    } else {
1129        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Document Missing Root Element");
1130        RETURN_FALSE;
1131    }
1132
1133    xmlFree(localname);
1134    if (prefix != NULL) {
1135        xmlFree(prefix);
1136    }
1137
1138    if (errorcode != 0) {
1139        if (nodep != NULL) {
1140            xmlFreeProp((xmlAttrPtr) nodep);
1141        }
1142        php_dom_throw_error(errorcode, dom_get_strict_error(intern->document) TSRMLS_CC);
1143        RETURN_FALSE;
1144    }
1145
1146    if (nodep == NULL) {
1147        RETURN_FALSE;
1148    }
1149
1150    DOM_RET_OBJ(nodep, &ret, intern);
1151}
1152/* }}} end dom_document_create_attribute_ns */
1153
1154/* {{{ proto DOMNodeList dom_document_get_elements_by_tag_name_ns(string namespaceURI, string localName);
1155URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-getElBTNNS
1156Since: DOM Level 2
1157*/
1158PHP_FUNCTION(dom_document_get_elements_by_tag_name_ns)
1159{
1160    zval *id;
1161    xmlDocPtr docp;
1162    size_t uri_len, name_len;
1163    dom_object *intern, *namednode;
1164    char *uri, *name;
1165    xmlChar *local, *nsuri;
1166
1167    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oss", &id, dom_document_class_entry, &uri, &uri_len, &name, &name_len) == FAILURE) {
1168        return;
1169    }
1170
1171    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1172
1173    php_dom_create_interator(return_value, DOM_NODELIST TSRMLS_CC);
1174    namednode = Z_DOMOBJ_P(return_value);
1175    local = xmlCharStrndup(name, name_len);
1176    nsuri = xmlCharStrndup(uri, uri_len);
1177    dom_namednode_iter(intern, 0, namednode, NULL, local, nsuri TSRMLS_CC);
1178}
1179/* }}} end dom_document_get_elements_by_tag_name_ns */
1180
1181/* {{{ proto DOMElement dom_document_get_element_by_id(string elementId);
1182URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-getElBId
1183Since: DOM Level 2
1184*/
1185PHP_FUNCTION(dom_document_get_element_by_id)
1186{
1187    zval *id;
1188    xmlDocPtr docp;
1189    xmlAttrPtr  attrp;
1190    int ret;
1191    size_t idname_len;
1192    dom_object *intern;
1193    char *idname;
1194
1195    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &id, dom_document_class_entry, &idname, &idname_len) == FAILURE) {
1196        return;
1197    }
1198
1199    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1200
1201    attrp = xmlGetID(docp, (xmlChar *) idname);
1202
1203    if (attrp && attrp->parent) {
1204        DOM_RET_OBJ((xmlNodePtr) attrp->parent, &ret, intern);
1205    } else {
1206        RETVAL_NULL();
1207    }
1208
1209}
1210/* }}} end dom_document_get_element_by_id */
1211
1212/* {{{ proto DOMNode dom_document_adopt_node(DOMNode source);
1213URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-Document3-adoptNode
1214Since: DOM Level 3
1215*/
1216PHP_FUNCTION(dom_document_adopt_node)
1217{
1218 DOM_NOT_IMPLEMENTED();
1219}
1220/* }}} end dom_document_adopt_node */
1221
1222/* {{{ proto void dom_document_normalize_document();
1223URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-Document3-normalizeDocument
1224Since: DOM Level 3
1225*/
1226PHP_FUNCTION(dom_document_normalize_document)
1227{
1228    zval *id;
1229    xmlDocPtr docp;
1230    dom_object *intern;
1231
1232    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &id, dom_document_class_entry) == FAILURE) {
1233        return;
1234    }
1235
1236    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1237
1238    dom_normalize((xmlNodePtr) docp TSRMLS_CC);
1239}
1240/* }}} end dom_document_normalize_document */
1241
1242/* {{{ proto DOMNode dom_document_rename_node(node n, string namespaceURI, string qualifiedName);
1243URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-Document3-renameNode
1244Since: DOM Level 3
1245*/
1246PHP_FUNCTION(dom_document_rename_node)
1247{
1248 DOM_NOT_IMPLEMENTED();
1249}
1250/* }}} end dom_document_rename_node */
1251
1252/* {{{ proto void DOMDocument::__construct([string version], [string encoding]); */
1253PHP_METHOD(domdocument, __construct)
1254{
1255
1256    zval *id;
1257    xmlDoc *docp = NULL, *olddoc;
1258    dom_object *intern;
1259    char *encoding, *version = NULL;
1260    size_t encoding_len = 0, version_len = 0;
1261    int refcount;
1262    zend_error_handling error_handling;
1263
1264    zend_replace_error_handling(EH_THROW, dom_domexception_class_entry, &error_handling TSRMLS_CC);
1265    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) {
1266        zend_restore_error_handling(&error_handling TSRMLS_CC);
1267        return;
1268    }
1269
1270    zend_restore_error_handling(&error_handling TSRMLS_CC);
1271    docp = xmlNewDoc(version);
1272
1273    if (!docp) {
1274        php_dom_throw_error(INVALID_STATE_ERR, 1 TSRMLS_CC);
1275        RETURN_FALSE;
1276    }
1277
1278    if (encoding_len > 0) {
1279        docp->encoding = (const xmlChar*)xmlStrdup(encoding);
1280    }
1281
1282    intern = Z_DOMOBJ_P(id);
1283    if (intern != NULL) {
1284        olddoc = (xmlDocPtr) dom_object_get_node(intern);
1285        if (olddoc != NULL) {
1286            php_libxml_decrement_node_ptr((php_libxml_node_object *) intern TSRMLS_CC);
1287            refcount = php_libxml_decrement_doc_ref((php_libxml_node_object *)intern TSRMLS_CC);
1288            if (refcount != 0) {
1289                olddoc->_private = NULL;
1290            }
1291        }
1292        intern->document = NULL;
1293        if (php_libxml_increment_doc_ref((php_libxml_node_object *)intern, docp TSRMLS_CC) == -1) {
1294            RETURN_FALSE;
1295        }
1296        php_libxml_increment_node_ptr((php_libxml_node_object *)intern, (xmlNodePtr)docp, (void *)intern TSRMLS_CC);
1297    }
1298}
1299/* }}} end DOMDocument::__construct */
1300
1301char *_dom_get_valid_file_path(char *source, char *resolved_path, int resolved_path_len  TSRMLS_DC) /* {{{ */
1302{
1303    xmlURI *uri;
1304    xmlChar *escsource;
1305    char *file_dest;
1306    int isFileUri = 0;
1307
1308    uri = xmlCreateURI();
1309    escsource = xmlURIEscapeStr(source, ":");
1310    xmlParseURIReference(uri, escsource);
1311    xmlFree(escsource);
1312
1313    if (uri->scheme != NULL) {
1314        /* absolute file uris - libxml only supports localhost or empty host */
1315#ifdef PHP_WIN32
1316        if (strncasecmp(source, "file://",7) == 0 && ':' == source[8]) {
1317            isFileUri = 1;
1318            source += 7;
1319        } else
1320#endif
1321        if (strncasecmp(source, "file:///",8) == 0) {
1322            isFileUri = 1;
1323#ifdef PHP_WIN32
1324            source += 8;
1325#else
1326            source += 7;
1327#endif
1328        } else if (strncasecmp(source, "file://localhost/",17) == 0) {
1329            isFileUri = 1;
1330#ifdef PHP_WIN32
1331            source += 17;
1332#else
1333            source += 16;
1334#endif
1335        }
1336    }
1337
1338    file_dest = source;
1339
1340    if ((uri->scheme == NULL || isFileUri)) {
1341        /* XXX possible buffer overflow if VCWD_REALPATH does not know size of resolved_path */
1342        if (!VCWD_REALPATH(source, resolved_path) && !expand_filepath(source, resolved_path TSRMLS_CC)) {
1343            xmlFreeURI(uri);
1344            return NULL;
1345        }
1346        file_dest = resolved_path;
1347    }
1348
1349    xmlFreeURI(uri);
1350
1351    return file_dest;
1352}
1353/* }}} */
1354
1355static xmlDocPtr dom_document_parser(zval *id, int mode, char *source, size_t source_len, size_t options TSRMLS_DC) /* {{{ */
1356{
1357    xmlDocPtr ret;
1358    xmlParserCtxtPtr ctxt = NULL;
1359    dom_doc_propsptr doc_props;
1360    dom_object *intern;
1361    php_libxml_ref_obj *document = NULL;
1362    int validate, recover, resolve_externals, keep_blanks, substitute_ent;
1363    int resolved_path_len;
1364    int old_error_reporting = 0;
1365    char *directory=NULL, resolved_path[MAXPATHLEN];
1366
1367    if (id != NULL) {
1368        intern = Z_DOMOBJ_P(id);
1369        document = intern->document;
1370    }
1371
1372    doc_props = dom_get_doc_props(document);
1373    validate = doc_props->validateonparse;
1374    resolve_externals = doc_props->resolveexternals;
1375    keep_blanks = doc_props->preservewhitespace;
1376    substitute_ent = doc_props->substituteentities;
1377    recover = doc_props->recover;
1378
1379    if (document == NULL) {
1380        efree(doc_props);
1381    }
1382
1383    xmlInitParser();
1384
1385    if (mode == DOM_LOAD_FILE) {
1386        char *file_dest = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN  TSRMLS_CC);
1387        if (file_dest) {
1388            ctxt = xmlCreateFileParserCtxt(file_dest);
1389        }
1390
1391    } else {
1392        ctxt = xmlCreateMemoryParserCtxt(source, source_len);
1393    }
1394
1395    if (ctxt == NULL) {
1396        return(NULL);
1397    }
1398
1399    /* If loading from memory, we need to set the base directory for the document */
1400    if (mode != DOM_LOAD_FILE) {
1401#if HAVE_GETCWD
1402        directory = VCWD_GETCWD(resolved_path, MAXPATHLEN);
1403#elif HAVE_GETWD
1404        directory = VCWD_GETWD(resolved_path);
1405#endif
1406        if (directory) {
1407            if(ctxt->directory != NULL) {
1408                xmlFree((char *) ctxt->directory);
1409            }
1410            resolved_path_len = strlen(resolved_path);
1411            if (resolved_path[resolved_path_len - 1] != DEFAULT_SLASH) {
1412                resolved_path[resolved_path_len] = DEFAULT_SLASH;
1413                resolved_path[++resolved_path_len] = '\0';
1414            }
1415            ctxt->directory = (char *) xmlCanonicPath((const xmlChar *) resolved_path);
1416        }
1417    }
1418
1419    ctxt->vctxt.error = php_libxml_ctx_error;
1420    ctxt->vctxt.warning = php_libxml_ctx_warning;
1421
1422    if (ctxt->sax != NULL) {
1423        ctxt->sax->error = php_libxml_ctx_error;
1424        ctxt->sax->warning = php_libxml_ctx_warning;
1425    }
1426
1427    if (validate && ! (options & XML_PARSE_DTDVALID)) {
1428        options |= XML_PARSE_DTDVALID;
1429    }
1430    if (resolve_externals && ! (options & XML_PARSE_DTDATTR)) {
1431        options |= XML_PARSE_DTDATTR;
1432    }
1433    if (substitute_ent && ! (options & XML_PARSE_NOENT)) {
1434        options |= XML_PARSE_NOENT;
1435    }
1436    if (keep_blanks == 0 && ! (options & XML_PARSE_NOBLANKS)) {
1437        options |= XML_PARSE_NOBLANKS;
1438    }
1439
1440    xmlCtxtUseOptions(ctxt, options);
1441
1442    ctxt->recovery = recover;
1443    if (recover) {
1444        old_error_reporting = EG(error_reporting);
1445        EG(error_reporting) = old_error_reporting | E_WARNING;
1446    }
1447
1448    xmlParseDocument(ctxt);
1449
1450    if (ctxt->wellFormed || recover) {
1451        ret = ctxt->myDoc;
1452        if (ctxt->recovery) {
1453            EG(error_reporting) = old_error_reporting;
1454        }
1455        /* If loading from memory, set the base reference uri for the document */
1456        if (ret && ret->URL == NULL && ctxt->directory != NULL) {
1457            ret->URL = xmlStrdup(ctxt->directory);
1458        }
1459    } else {
1460        ret = NULL;
1461        xmlFreeDoc(ctxt->myDoc);
1462        ctxt->myDoc = NULL;
1463    }
1464
1465    xmlFreeParserCtxt(ctxt);
1466
1467    return(ret);
1468}
1469/* }}} */
1470
1471/* {{{ static void dom_parse_document(INTERNAL_FUNCTION_PARAMETERS, int mode) */
1472static void dom_parse_document(INTERNAL_FUNCTION_PARAMETERS, int mode) {
1473    zval *id;
1474    xmlDoc *docp = NULL, *newdoc;
1475    dom_doc_propsptr doc_prop;
1476    dom_object *intern;
1477    char *source;
1478    size_t source_len;
1479    int refcount, ret;
1480    zend_long options = 0;
1481
1482    id = getThis();
1483    if (id != NULL && ! instanceof_function(Z_OBJCE_P(id), dom_document_class_entry TSRMLS_CC)) {
1484        id = NULL;
1485    }
1486
1487    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &source, &source_len, &options) == FAILURE) {
1488        return;
1489    }
1490
1491    if (!source_len) {
1492        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty string supplied as input");
1493        RETURN_FALSE;
1494    }
1495
1496    newdoc = dom_document_parser(id, mode, source, source_len, options TSRMLS_CC);
1497
1498    if (!newdoc)
1499        RETURN_FALSE;
1500
1501    if (id != NULL) {
1502        intern = Z_DOMOBJ_P(id);
1503        if (intern != NULL) {
1504            docp = (xmlDocPtr) dom_object_get_node(intern);
1505            doc_prop = NULL;
1506            if (docp != NULL) {
1507                php_libxml_decrement_node_ptr((php_libxml_node_object *) intern TSRMLS_CC);
1508                doc_prop = intern->document->doc_props;
1509                intern->document->doc_props = NULL;
1510                refcount = php_libxml_decrement_doc_ref((php_libxml_node_object *)intern TSRMLS_CC);
1511                if (refcount != 0) {
1512                    docp->_private = NULL;
1513                }
1514            }
1515            intern->document = NULL;
1516            if (php_libxml_increment_doc_ref((php_libxml_node_object *)intern, newdoc TSRMLS_CC) == -1) {
1517                RETURN_FALSE;
1518            }
1519            intern->document->doc_props = doc_prop;
1520        }
1521
1522        php_libxml_increment_node_ptr((php_libxml_node_object *)intern, (xmlNodePtr)newdoc, (void *)intern TSRMLS_CC);
1523
1524        RETURN_TRUE;
1525    } else {
1526        DOM_RET_OBJ((xmlNodePtr) newdoc, &ret, NULL);
1527    }
1528}
1529/* }}} end dom_parser_document */
1530
1531/* {{{ proto DOMNode dom_document_load(string source [, int options]);
1532URL: http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-DocumentLS-load
1533Since: DOM Level 3
1534*/
1535PHP_METHOD(domdocument, load)
1536{
1537    dom_parse_document(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
1538}
1539/* }}} end dom_document_load */
1540
1541/* {{{ proto DOMNode dom_document_loadxml(string source [, int options]);
1542URL: http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-DocumentLS-loadXML
1543Since: DOM Level 3
1544*/
1545PHP_METHOD(domdocument, loadXML)
1546{
1547    dom_parse_document(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
1548}
1549/* }}} end dom_document_loadxml */
1550
1551/* {{{ proto int dom_document_save(string file);
1552Convenience method to save to file
1553*/
1554PHP_FUNCTION(dom_document_save)
1555{
1556    zval *id;
1557    xmlDoc *docp;
1558    size_t file_len = 0;
1559    int bytes, format, saveempty = 0;
1560    dom_object *intern;
1561    dom_doc_propsptr doc_props;
1562    char *file;
1563    zend_long options = 0;
1564
1565    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os|l", &id, dom_document_class_entry, &file, &file_len, &options) == FAILURE) {
1566        return;
1567    }
1568
1569    if (file_len == 0) {
1570        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Filename");
1571        RETURN_FALSE;
1572    }
1573
1574    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1575
1576    /* encoding handled by property on doc */
1577
1578    doc_props = dom_get_doc_props(intern->document);
1579    format = doc_props->formatoutput;
1580    if (options & LIBXML_SAVE_NOEMPTYTAG) {
1581        saveempty = xmlSaveNoEmptyTags;
1582        xmlSaveNoEmptyTags = 1;
1583    }
1584    bytes = xmlSaveFormatFileEnc(file, docp, NULL, format);
1585    if (options & LIBXML_SAVE_NOEMPTYTAG) {
1586        xmlSaveNoEmptyTags = saveempty;
1587    }
1588    if (bytes == -1) {
1589        RETURN_FALSE;
1590    }
1591    RETURN_LONG(bytes);
1592}
1593/* }}} end dom_document_save */
1594
1595/* {{{ proto string dom_document_savexml([node n]);
1596URL: http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-DocumentLS-saveXML
1597Since: DOM Level 3
1598*/
1599PHP_FUNCTION(dom_document_savexml)
1600{
1601    zval *id, *nodep = NULL;
1602    xmlDoc *docp;
1603    xmlNode *node;
1604    xmlBufferPtr buf;
1605    xmlChar *mem;
1606    dom_object *intern, *nodeobj;
1607    dom_doc_propsptr doc_props;
1608    int size, format, saveempty = 0;
1609    zend_long options = 0;
1610
1611    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) {
1612        return;
1613    }
1614
1615    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1616
1617    doc_props = dom_get_doc_props(intern->document);
1618    format = doc_props->formatoutput;
1619
1620    if (nodep != NULL) {
1621        /* Dump contents of Node */
1622        DOM_GET_OBJ(node, nodep, xmlNodePtr, nodeobj);
1623        if (node->doc != docp) {
1624            php_dom_throw_error(WRONG_DOCUMENT_ERR, dom_get_strict_error(intern->document) TSRMLS_CC);
1625            RETURN_FALSE;
1626        }
1627        buf = xmlBufferCreate();
1628        if (!buf) {
1629            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not fetch buffer");
1630            RETURN_FALSE;
1631        }
1632        if (options & LIBXML_SAVE_NOEMPTYTAG) {
1633            saveempty = xmlSaveNoEmptyTags;
1634            xmlSaveNoEmptyTags = 1;
1635        }
1636        xmlNodeDump(buf, docp, node, 0, format);
1637        if (options & LIBXML_SAVE_NOEMPTYTAG) {
1638            xmlSaveNoEmptyTags = saveempty;
1639        }
1640        mem = (xmlChar*) xmlBufferContent(buf);
1641        if (!mem) {
1642            xmlBufferFree(buf);
1643            RETURN_FALSE;
1644        }
1645        RETVAL_STRING(mem);
1646        xmlBufferFree(buf);
1647    } else {
1648        if (options & LIBXML_SAVE_NOEMPTYTAG) {
1649            saveempty = xmlSaveNoEmptyTags;
1650            xmlSaveNoEmptyTags = 1;
1651        }
1652        /* Encoding is handled from the encoding property set on the document */
1653        xmlDocDumpFormatMemory(docp, &mem, &size, format);
1654        if (options & LIBXML_SAVE_NOEMPTYTAG) {
1655            xmlSaveNoEmptyTags = saveempty;
1656        }
1657        if (!size) {
1658            RETURN_FALSE;
1659        }
1660        RETVAL_STRINGL(mem, size);
1661        xmlFree(mem);
1662    }
1663}
1664/* }}} end dom_document_savexml */
1665
1666static xmlNodePtr php_dom_free_xinclude_node(xmlNodePtr cur TSRMLS_DC) /* {{{ */
1667{
1668    xmlNodePtr xincnode;
1669
1670    xincnode = cur;
1671    cur = cur->next;
1672    xmlUnlinkNode(xincnode);
1673    php_libxml_node_free_resource(xincnode TSRMLS_CC);
1674
1675    return cur;
1676}
1677/* }}} */
1678
1679static void php_dom_remove_xinclude_nodes(xmlNodePtr cur TSRMLS_DC) /* {{{ */
1680{
1681    while(cur) {
1682        if (cur->type == XML_XINCLUDE_START) {
1683            cur = php_dom_free_xinclude_node(cur TSRMLS_CC);
1684
1685            /* XML_XINCLUDE_END node will be a sibling of XML_XINCLUDE_START */
1686            while(cur && cur->type != XML_XINCLUDE_END) {
1687                /* remove xinclude processing nodes from recursive xincludes */
1688                if (cur->type == XML_ELEMENT_NODE) {
1689                       php_dom_remove_xinclude_nodes(cur->children TSRMLS_CC);
1690                }
1691                cur = cur->next;
1692            }
1693
1694            if (cur && cur->type == XML_XINCLUDE_END) {
1695                cur = php_dom_free_xinclude_node(cur TSRMLS_CC);
1696            }
1697        } else {
1698            if (cur->type == XML_ELEMENT_NODE) {
1699                php_dom_remove_xinclude_nodes(cur->children TSRMLS_CC);
1700            }
1701            cur = cur->next;
1702        }
1703    }
1704}
1705/* }}} */
1706
1707/* {{{ proto int dom_document_xinclude([int options])
1708   Substitutues xincludes in a DomDocument */
1709PHP_FUNCTION(dom_document_xinclude)
1710{
1711    zval *id;
1712    xmlDoc *docp;
1713    xmlNodePtr root;
1714    zend_long flags = 0;
1715    int err;
1716    dom_object *intern;
1717
1718    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O|l", &id, dom_document_class_entry, &flags) == FAILURE) {
1719        return;
1720    }
1721
1722    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1723
1724    err = xmlXIncludeProcessFlags(docp, flags);
1725
1726    /* XML_XINCLUDE_START and XML_XINCLUDE_END nodes need to be removed as these
1727    are added via xmlXIncludeProcess to mark beginning and ending of xincluded document
1728    but are not wanted in resulting document - must be done even if err as it could fail after
1729    having processed some xincludes */
1730    root = (xmlNodePtr) docp->children;
1731    while(root && root->type != XML_ELEMENT_NODE && root->type != XML_XINCLUDE_START) {
1732        root = root->next;
1733    }
1734    if (root) {
1735        php_dom_remove_xinclude_nodes(root TSRMLS_CC);
1736    }
1737
1738    if (err) {
1739        RETVAL_LONG(err);
1740    } else {
1741        RETVAL_FALSE;
1742    }
1743
1744}
1745/* }}} */
1746
1747/* {{{ proto boolean dom_document_validate();
1748Since: DOM extended
1749*/
1750PHP_FUNCTION(dom_document_validate)
1751{
1752    zval *id;
1753    xmlDoc *docp;
1754    dom_object *intern;
1755    xmlValidCtxt *cvp;
1756
1757    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &id, dom_document_class_entry) == FAILURE) {
1758        return;
1759    }
1760
1761    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1762
1763    cvp = xmlNewValidCtxt();
1764
1765    cvp->userData = NULL;
1766    cvp->error    = (xmlValidityErrorFunc) php_libxml_error_handler;
1767    cvp->warning  = (xmlValidityErrorFunc) php_libxml_error_handler;
1768
1769    if (xmlValidateDocument(cvp, docp)) {
1770        RETVAL_TRUE;
1771    } else {
1772        RETVAL_FALSE;
1773    }
1774
1775    xmlFreeValidCtxt(cvp);
1776
1777}
1778/* }}} */
1779
1780#if defined(LIBXML_SCHEMAS_ENABLED)
1781static void _dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ */
1782{
1783    zval *id;
1784    xmlDoc *docp;
1785    dom_object *intern;
1786    char *source = NULL, *valid_file = NULL;
1787    size_t source_len = 0;
1788    int valid_opts = 0;
1789    zend_long flags = 0;
1790    xmlSchemaParserCtxtPtr  parser;
1791    xmlSchemaPtr            sptr;
1792    xmlSchemaValidCtxtPtr   vptr;
1793    int                     is_valid;
1794    char resolved_path[MAXPATHLEN + 1];
1795
1796    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Op|l", &id, dom_document_class_entry, &source, &source_len, &flags) == FAILURE) {
1797        return;
1798    }
1799
1800    if (source_len == 0) {
1801        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Schema source");
1802        RETURN_FALSE;
1803    }
1804
1805    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1806
1807    switch (type) {
1808    case DOM_LOAD_FILE:
1809        valid_file = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN  TSRMLS_CC);
1810        if (!valid_file) {
1811            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Schema file source");
1812            RETURN_FALSE;
1813        }
1814        parser = xmlSchemaNewParserCtxt(valid_file);
1815        break;
1816    case DOM_LOAD_STRING:
1817        parser = xmlSchemaNewMemParserCtxt(source, source_len);
1818        /* If loading from memory, we need to set the base directory for the document
1819           but it is not apparent how to do that for schema's */
1820        break;
1821    default:
1822        return;
1823    }
1824
1825    xmlSchemaSetParserErrors(parser,
1826        (xmlSchemaValidityErrorFunc) php_libxml_error_handler,
1827        (xmlSchemaValidityWarningFunc) php_libxml_error_handler,
1828        parser);
1829    sptr = xmlSchemaParse(parser);
1830    xmlSchemaFreeParserCtxt(parser);
1831    if (!sptr) {
1832        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Schema");
1833        RETURN_FALSE;
1834    }
1835
1836    docp = (xmlDocPtr) dom_object_get_node(intern);
1837
1838    vptr = xmlSchemaNewValidCtxt(sptr);
1839    if (!vptr) {
1840        xmlSchemaFree(sptr);
1841        php_error(E_ERROR, "Invalid Schema Validation Context");
1842        RETURN_FALSE;
1843    }
1844
1845#if LIBXML_VERSION >= 20614
1846    if (flags & XML_SCHEMA_VAL_VC_I_CREATE) {
1847        valid_opts |= XML_SCHEMA_VAL_VC_I_CREATE;
1848    }
1849#endif
1850
1851    xmlSchemaSetValidOptions(vptr, valid_opts);
1852    xmlSchemaSetValidErrors(vptr, php_libxml_error_handler, php_libxml_error_handler, vptr);
1853    is_valid = xmlSchemaValidateDoc(vptr, docp);
1854    xmlSchemaFree(sptr);
1855    xmlSchemaFreeValidCtxt(vptr);
1856
1857    if (is_valid == 0) {
1858        RETURN_TRUE;
1859    } else {
1860        RETURN_FALSE;
1861    }
1862}
1863/* }}} */
1864
1865/* {{{ proto boolean dom_document_schema_validate_file(string filename, int flags); */
1866PHP_FUNCTION(dom_document_schema_validate_file)
1867{
1868    _dom_document_schema_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
1869}
1870/* }}} end dom_document_schema_validate_file */
1871
1872/* {{{ proto boolean dom_document_schema_validate(string source, int flags); */
1873PHP_FUNCTION(dom_document_schema_validate_xml)
1874{
1875    _dom_document_schema_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
1876}
1877/* }}} end dom_document_schema_validate */
1878
1879static void _dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ */
1880{
1881    zval *id;
1882    xmlDoc *docp;
1883    dom_object *intern;
1884    char *source = NULL, *valid_file = NULL;
1885    size_t source_len = 0;
1886    xmlRelaxNGParserCtxtPtr parser;
1887    xmlRelaxNGPtr           sptr;
1888    xmlRelaxNGValidCtxtPtr  vptr;
1889    int                     is_valid;
1890    char resolved_path[MAXPATHLEN + 1];
1891
1892    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Op", &id, dom_document_class_entry, &source, &source_len) == FAILURE) {
1893        return;
1894    }
1895
1896    if (source_len == 0) {
1897        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Schema source");
1898        RETURN_FALSE;
1899    }
1900
1901    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1902
1903    switch (type) {
1904    case DOM_LOAD_FILE:
1905        valid_file = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN  TSRMLS_CC);
1906        if (!valid_file) {
1907            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid RelaxNG file source");
1908            RETURN_FALSE;
1909        }
1910        parser = xmlRelaxNGNewParserCtxt(valid_file);
1911        break;
1912    case DOM_LOAD_STRING:
1913        parser = xmlRelaxNGNewMemParserCtxt(source, source_len);
1914        /* If loading from memory, we need to set the base directory for the document
1915           but it is not apparent how to do that for schema's */
1916        break;
1917    default:
1918        return;
1919    }
1920
1921    xmlRelaxNGSetParserErrors(parser,
1922        (xmlRelaxNGValidityErrorFunc) php_libxml_error_handler,
1923        (xmlRelaxNGValidityWarningFunc) php_libxml_error_handler,
1924        parser);
1925    sptr = xmlRelaxNGParse(parser);
1926    xmlRelaxNGFreeParserCtxt(parser);
1927    if (!sptr) {
1928        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid RelaxNG");
1929        RETURN_FALSE;
1930    }
1931
1932    docp = (xmlDocPtr) dom_object_get_node(intern);
1933
1934    vptr = xmlRelaxNGNewValidCtxt(sptr);
1935    if (!vptr) {
1936        xmlRelaxNGFree(sptr);
1937        php_error(E_ERROR, "Invalid RelaxNG Validation Context");
1938        RETURN_FALSE;
1939    }
1940
1941    xmlRelaxNGSetValidErrors(vptr, php_libxml_error_handler, php_libxml_error_handler, vptr);
1942    is_valid = xmlRelaxNGValidateDoc(vptr, docp);
1943    xmlRelaxNGFree(sptr);
1944    xmlRelaxNGFreeValidCtxt(vptr);
1945
1946    if (is_valid == 0) {
1947        RETURN_TRUE;
1948    } else {
1949        RETURN_FALSE;
1950    }
1951}
1952/* }}} */
1953
1954/* {{{ proto boolean dom_document_relaxNG_validate_file(string filename); */
1955PHP_FUNCTION(dom_document_relaxNG_validate_file)
1956{
1957    _dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
1958}
1959/* }}} end dom_document_relaxNG_validate_file */
1960
1961/* {{{ proto boolean dom_document_relaxNG_validate_xml(string source); */
1962PHP_FUNCTION(dom_document_relaxNG_validate_xml)
1963{
1964    _dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
1965}
1966/* }}} end dom_document_relaxNG_validate_xml */
1967
1968#endif
1969
1970#if defined(LIBXML_HTML_ENABLED)
1971
1972static void dom_load_html(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ */
1973{
1974    zval *id;
1975    xmlDoc *docp = NULL, *newdoc;
1976    dom_object *intern;
1977    dom_doc_propsptr doc_prop;
1978    char *source;
1979    size_t source_len;
1980    int refcount, ret;
1981    zend_long options = 0;
1982    htmlParserCtxtPtr ctxt;
1983
1984    id = getThis();
1985
1986    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &source, &source_len, &options) == FAILURE) {
1987        return;
1988    }
1989
1990    if (!source_len) {
1991        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty string supplied as input");
1992        RETURN_FALSE;
1993    }
1994
1995    if (mode == DOM_LOAD_FILE) {
1996        ctxt = htmlCreateFileParserCtxt(source, NULL);
1997    } else {
1998        source_len = xmlStrlen(source);
1999        ctxt = htmlCreateMemoryParserCtxt(source, source_len);
2000    }
2001
2002    if (!ctxt) {
2003        RETURN_FALSE;
2004    }
2005
2006    if (options) {
2007        htmlCtxtUseOptions(ctxt, options);
2008    }
2009
2010    ctxt->vctxt.error = php_libxml_ctx_error;
2011    ctxt->vctxt.warning = php_libxml_ctx_warning;
2012    if (ctxt->sax != NULL) {
2013        ctxt->sax->error = php_libxml_ctx_error;
2014        ctxt->sax->warning = php_libxml_ctx_warning;
2015    }
2016    htmlParseDocument(ctxt);
2017    newdoc = ctxt->myDoc;
2018    htmlFreeParserCtxt(ctxt);
2019
2020    if (!newdoc)
2021        RETURN_FALSE;
2022
2023    if (id != NULL && instanceof_function(Z_OBJCE_P(id), dom_document_class_entry TSRMLS_CC)) {
2024        intern = Z_DOMOBJ_P(id);
2025        if (intern != NULL) {
2026            docp = (xmlDocPtr) dom_object_get_node(intern);
2027            doc_prop = NULL;
2028            if (docp != NULL) {
2029                php_libxml_decrement_node_ptr((php_libxml_node_object *) intern TSRMLS_CC);
2030                doc_prop = intern->document->doc_props;
2031                intern->document->doc_props = NULL;
2032                refcount = php_libxml_decrement_doc_ref((php_libxml_node_object *)intern TSRMLS_CC);
2033                if (refcount != 0) {
2034                    docp->_private = NULL;
2035                }
2036            }
2037            intern->document = NULL;
2038            if (php_libxml_increment_doc_ref((php_libxml_node_object *)intern, newdoc TSRMLS_CC) == -1) {
2039                RETURN_FALSE;
2040            }
2041            intern->document->doc_props = doc_prop;
2042        }
2043
2044        php_libxml_increment_node_ptr((php_libxml_node_object *)intern, (xmlNodePtr)newdoc, (void *)intern TSRMLS_CC);
2045
2046        RETURN_TRUE;
2047    } else {
2048        DOM_RET_OBJ((xmlNodePtr) newdoc, &ret, NULL);
2049    }
2050}
2051/* }}} */
2052
2053/* {{{ proto DOMNode dom_document_load_html_file(string source);
2054Since: DOM extended
2055*/
2056PHP_METHOD(domdocument, loadHTMLFile)
2057{
2058    dom_load_html(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
2059}
2060/* }}} end dom_document_load_html_file */
2061
2062/* {{{ proto DOMNode dom_document_load_html(string source);
2063Since: DOM extended
2064*/
2065PHP_METHOD(domdocument, loadHTML)
2066{
2067    dom_load_html(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
2068}
2069/* }}} end dom_document_load_html */
2070
2071/* {{{ proto int dom_document_save_html_file(string file);
2072Convenience method to save to file as html
2073*/
2074PHP_FUNCTION(dom_document_save_html_file)
2075{
2076    zval *id;
2077    xmlDoc *docp;
2078    size_t file_len;
2079    int bytes, format;
2080    dom_object *intern;
2081    dom_doc_propsptr doc_props;
2082    char *file;
2083    const char *encoding;
2084
2085    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &id, dom_document_class_entry, &file, &file_len) == FAILURE) {
2086        return;
2087    }
2088
2089    if (file_len == 0) {
2090        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Filename");
2091        RETURN_FALSE;
2092    }
2093
2094    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
2095
2096
2097    encoding = (const char *) htmlGetMetaEncoding(docp);
2098
2099    doc_props = dom_get_doc_props(intern->document);
2100    format = doc_props->formatoutput;
2101    bytes = htmlSaveFileFormat(file, docp, encoding, format);
2102
2103    if (bytes == -1) {
2104        RETURN_FALSE;
2105    }
2106    RETURN_LONG(bytes);
2107}
2108/* }}} end dom_document_save_html_file */
2109
2110/* {{{ proto string dom_document_save_html();
2111Convenience method to output as html
2112*/
2113PHP_FUNCTION(dom_document_save_html)
2114{
2115    zval *id, *nodep = NULL;
2116    xmlDoc *docp;
2117    xmlNode *node;
2118    xmlBufferPtr buf;
2119    dom_object *intern, *nodeobj;
2120    xmlChar *mem = NULL;
2121    int size = 0, format;
2122    dom_doc_propsptr doc_props;
2123
2124    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
2125        "O|O!", &id, dom_document_class_entry, &nodep, dom_node_class_entry)
2126        == FAILURE) {
2127        return;
2128    }
2129
2130    DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
2131
2132    doc_props = dom_get_doc_props(intern->document);
2133    format = doc_props->formatoutput;
2134
2135    if (nodep != NULL) {
2136        /* Dump contents of Node */
2137        DOM_GET_OBJ(node, nodep, xmlNodePtr, nodeobj);
2138        if (node->doc != docp) {
2139            php_dom_throw_error(WRONG_DOCUMENT_ERR, dom_get_strict_error(intern->document) TSRMLS_CC);
2140            RETURN_FALSE;
2141        }
2142
2143        buf = xmlBufferCreate();
2144        if (!buf) {
2145            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not fetch buffer");
2146            RETURN_FALSE;
2147        }
2148
2149        if (node->type == XML_DOCUMENT_FRAG_NODE) {
2150            int one_size;
2151
2152            for (node = node->children; node; node = node->next) {
2153                one_size = htmlNodeDump(buf, docp, node);
2154
2155                if (one_size >= 0) {
2156                    size += one_size;
2157                } else {
2158                    size = -1;
2159                    break;
2160                }
2161            }
2162        } else {
2163            size = htmlNodeDump(buf, docp, node);
2164        }
2165        if (size >= 0) {
2166            mem = (xmlChar*) xmlBufferContent(buf);
2167            if (!mem) {
2168                RETVAL_FALSE;
2169            } else {
2170                RETVAL_STRINGL((const char*) mem, size);
2171            }
2172        } else {
2173            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error dumping HTML node");
2174            RETVAL_FALSE;
2175        }
2176        xmlBufferFree(buf);
2177    } else {
2178#if LIBXML_VERSION >= 20623
2179        htmlDocDumpMemoryFormat(docp, &mem, &size, format);
2180#else
2181        htmlDocDumpMemory(docp, &mem, &size);
2182#endif
2183        if (!size) {
2184            RETVAL_FALSE;
2185        } else {
2186            RETVAL_STRINGL((const char*) mem, size);
2187        }
2188        if (mem)
2189            xmlFree(mem);
2190    }
2191
2192}
2193/* }}} end dom_document_save_html */
2194
2195#endif  /* defined(LIBXML_HTML_ENABLED) */
2196
2197/* {{{ proto boolean DOMDocument::registerNodeClass(string baseclass, string extendedclass);
2198   Register extended class used to create base node type */
2199PHP_METHOD(domdocument, registerNodeClass)
2200{
2201    zval *id;
2202    xmlDoc *docp;
2203    zend_class_entry *basece = dom_node_class_entry, *ce = NULL;
2204    dom_object *intern;
2205
2206    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OCC!", &id, dom_document_class_entry, &basece, &ce) == FAILURE) {
2207        return;
2208    }
2209
2210    if (ce == NULL || instanceof_function(ce, basece TSRMLS_CC)) {
2211        DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
2212
2213        if (dom_set_doc_classmap(intern->document, basece, ce TSRMLS_CC) == FAILURE) {
2214            php_error_docref(NULL TSRMLS_CC, E_ERROR, "Class %s could not be registered.", ce->name->val);
2215        }
2216        RETURN_TRUE;
2217    } else {
2218        php_error_docref(NULL TSRMLS_CC, E_ERROR, "Class %s is not derived from %s.", ce->name->val, basece->name->val);
2219    }
2220
2221    RETURN_FALSE;
2222}
2223/* }}} */
2224
2225#endif  /* HAVE_LIBXML && HAVE_DOM */
2226
2227/*
2228 * Local variables:
2229 * tab-width: 4
2230 * c-basic-offset: 4
2231 * End:
2232 * vim600: noet sw=4 ts=4 fdm=marker
2233 * vim<600: noet sw=4 ts=4
2234 */
2235