1 /*
2    +----------------------------------------------------------------------+
3    | Copyright (c) The PHP Group                                          |
4    +----------------------------------------------------------------------+
5    | This source file is subject to version 3.01 of the PHP license,      |
6    | that is bundled with this package in the file LICENSE, and is        |
7    | available through the world-wide-web at the following url:           |
8    | https://www.php.net/license/3_01.txt                                 |
9    | If you did not receive a copy of the PHP license and are unable to   |
10    | obtain it through the world-wide-web, please send a note to          |
11    | license@php.net so we can mail you a copy immediately.               |
12    +----------------------------------------------------------------------+
13    | Authors: Christian Stocker <chregu@php.net>                          |
14    |          Rob Richards <rrichards@php.net>                            |
15    |          Marcus Borger <helly@php.net>                               |
16    +----------------------------------------------------------------------+
17 */
18 
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22 
23 #include "php.h"
24 #if defined(HAVE_LIBXML) && defined(HAVE_DOM)
25 #include "ext/standard/php_rand.h"
26 #include "php_dom.h"
27 #include "php_dom_arginfo.h"
28 #include "dom_properties.h"
29 #include "zend_interfaces.h"
30 
31 #include "ext/standard/info.h"
32 #define PHP_XPATH 1
33 #define PHP_XPTR 2
34 
35 /* {{{ class entries */
36 PHP_DOM_EXPORT zend_class_entry *dom_node_class_entry;
37 PHP_DOM_EXPORT zend_class_entry *dom_domexception_class_entry;
38 PHP_DOM_EXPORT zend_class_entry *dom_parentnode_class_entry;
39 PHP_DOM_EXPORT zend_class_entry *dom_childnode_class_entry;
40 PHP_DOM_EXPORT zend_class_entry *dom_domimplementation_class_entry;
41 PHP_DOM_EXPORT zend_class_entry *dom_documentfragment_class_entry;
42 PHP_DOM_EXPORT zend_class_entry *dom_document_class_entry;
43 PHP_DOM_EXPORT zend_class_entry *dom_nodelist_class_entry;
44 PHP_DOM_EXPORT zend_class_entry *dom_namednodemap_class_entry;
45 PHP_DOM_EXPORT zend_class_entry *dom_characterdata_class_entry;
46 PHP_DOM_EXPORT zend_class_entry *dom_attr_class_entry;
47 PHP_DOM_EXPORT zend_class_entry *dom_element_class_entry;
48 PHP_DOM_EXPORT zend_class_entry *dom_text_class_entry;
49 PHP_DOM_EXPORT zend_class_entry *dom_comment_class_entry;
50 PHP_DOM_EXPORT zend_class_entry *dom_cdatasection_class_entry;
51 PHP_DOM_EXPORT zend_class_entry *dom_documenttype_class_entry;
52 PHP_DOM_EXPORT zend_class_entry *dom_notation_class_entry;
53 PHP_DOM_EXPORT zend_class_entry *dom_entity_class_entry;
54 PHP_DOM_EXPORT zend_class_entry *dom_entityreference_class_entry;
55 PHP_DOM_EXPORT zend_class_entry *dom_processinginstruction_class_entry;
56 #ifdef LIBXML_XPATH_ENABLED
57 PHP_DOM_EXPORT zend_class_entry *dom_xpath_class_entry;
58 #endif
59 PHP_DOM_EXPORT zend_class_entry *dom_namespace_node_class_entry;
60 /* }}} */
61 
62 zend_object_handlers dom_object_handlers;
63 zend_object_handlers dom_nnodemap_object_handlers;
64 #ifdef LIBXML_XPATH_ENABLED
65 zend_object_handlers dom_xpath_object_handlers;
66 #endif
67 
68 static HashTable classes;
69 /* {{{ prop handler tables */
70 static HashTable dom_document_prop_handlers;
71 static HashTable dom_documentfragment_prop_handlers;
72 static HashTable dom_node_prop_handlers;
73 static HashTable dom_nodelist_prop_handlers;
74 static HashTable dom_namednodemap_prop_handlers;
75 static HashTable dom_characterdata_prop_handlers;
76 static HashTable dom_attr_prop_handlers;
77 static HashTable dom_element_prop_handlers;
78 static HashTable dom_text_prop_handlers;
79 static HashTable dom_documenttype_prop_handlers;
80 static HashTable dom_notation_prop_handlers;
81 static HashTable dom_entity_prop_handlers;
82 static HashTable dom_processinginstruction_prop_handlers;
83 static HashTable dom_namespace_node_prop_handlers;
84 #ifdef LIBXML_XPATH_ENABLED
85 static HashTable dom_xpath_prop_handlers;
86 #endif
87 /* }}} */
88 
89 typedef int (*dom_read_t)(dom_object *obj, zval *retval);
90 typedef int (*dom_write_t)(dom_object *obj, zval *newval);
91 
92 typedef struct _dom_prop_handler {
93 	dom_read_t read_func;
94 	dom_write_t write_func;
95 } dom_prop_handler;
96 
dom_get_obj_handlers(void)97 static zend_object_handlers* dom_get_obj_handlers(void) {
98 	return &dom_object_handlers;
99 }
100 
101 /* {{{ int dom_node_is_read_only(xmlNodePtr node) */
dom_node_is_read_only(xmlNodePtr node)102 int dom_node_is_read_only(xmlNodePtr node) {
103 	switch (node->type) {
104 		case XML_ENTITY_REF_NODE:
105 		case XML_ENTITY_NODE:
106 		case XML_DOCUMENT_TYPE_NODE:
107 		case XML_NOTATION_NODE:
108 		case XML_DTD_NODE:
109 		case XML_ELEMENT_DECL:
110 		case XML_ATTRIBUTE_DECL:
111 		case XML_ENTITY_DECL:
112 		case XML_NAMESPACE_DECL:
113 			return SUCCESS;
114 			break;
115 		default:
116 			if (node->doc == NULL) {
117 				return SUCCESS;
118 			} else {
119 				return FAILURE;
120 			}
121 	}
122 }
123 /* }}} end dom_node_is_read_only */
124 
125 /* {{{ int dom_node_children_valid(xmlNodePtr node) */
dom_node_children_valid(xmlNodePtr node)126 int dom_node_children_valid(xmlNodePtr node) {
127 	switch (node->type) {
128 		case XML_DOCUMENT_TYPE_NODE:
129 		case XML_DTD_NODE:
130 		case XML_PI_NODE:
131 		case XML_COMMENT_NODE:
132 		case XML_TEXT_NODE:
133 		case XML_CDATA_SECTION_NODE:
134 		case XML_NOTATION_NODE:
135 			return FAILURE;
136 			break;
137 		default:
138 			return SUCCESS;
139 	}
140 }
141 /* }}} end dom_node_children_valid */
142 
143 /* {{{ dom_get_doc_props() */
dom_get_doc_props(php_libxml_ref_obj * document)144 dom_doc_propsptr dom_get_doc_props(php_libxml_ref_obj *document)
145 {
146 	dom_doc_propsptr doc_props;
147 
148 	if (document && document->doc_props) {
149 		return document->doc_props;
150 	} else {
151 		doc_props = emalloc(sizeof(libxml_doc_props));
152 		doc_props->formatoutput = 0;
153 		doc_props->validateonparse = 0;
154 		doc_props->resolveexternals = 0;
155 		doc_props->preservewhitespace = 1;
156 		doc_props->substituteentities = 0;
157 		doc_props->stricterror = 1;
158 		doc_props->recover = 0;
159 		doc_props->classmap = NULL;
160 		if (document) {
161 			document->doc_props = doc_props;
162 		}
163 		return doc_props;
164 	}
165 }
166 
dom_copy_doc_props(php_libxml_ref_obj * source_doc,php_libxml_ref_obj * dest_doc)167 static void dom_copy_doc_props(php_libxml_ref_obj *source_doc, php_libxml_ref_obj *dest_doc)
168 {
169 	dom_doc_propsptr source, dest;
170 
171 	if (source_doc && dest_doc) {
172 
173 		source = dom_get_doc_props(source_doc);
174 		dest = dom_get_doc_props(dest_doc);
175 
176 		dest->formatoutput = source->formatoutput;
177 		dest->validateonparse = source->validateonparse;
178 		dest->resolveexternals = source->resolveexternals;
179 		dest->preservewhitespace = source->preservewhitespace;
180 		dest->substituteentities = source->substituteentities;
181 		dest->stricterror = source->stricterror;
182 		dest->recover = source->recover;
183 		if (source->classmap) {
184 			ALLOC_HASHTABLE(dest->classmap);
185 			zend_hash_init(dest->classmap, 0, NULL, NULL, 0);
186 			zend_hash_copy(dest->classmap, source->classmap, NULL);
187 		}
188 
189 	}
190 }
191 
dom_set_doc_classmap(php_libxml_ref_obj * document,zend_class_entry * basece,zend_class_entry * ce)192 void dom_set_doc_classmap(php_libxml_ref_obj *document, zend_class_entry *basece, zend_class_entry *ce)
193 {
194 	dom_doc_propsptr doc_props;
195 
196 	if (document) {
197 		doc_props = dom_get_doc_props(document);
198 		if (doc_props->classmap == NULL) {
199 			if (ce == NULL) {
200 				return;
201 			}
202 			ALLOC_HASHTABLE(doc_props->classmap);
203 			zend_hash_init(doc_props->classmap, 0, NULL, NULL, 0);
204 		}
205 		if (ce) {
206 			zend_hash_update_ptr(doc_props->classmap, basece->name, ce);
207 		} else {
208 			zend_hash_del(doc_props->classmap, basece->name);
209 		}
210 	}
211 }
212 
dom_get_doc_classmap(php_libxml_ref_obj * document,zend_class_entry * basece)213 zend_class_entry *dom_get_doc_classmap(php_libxml_ref_obj *document, zend_class_entry *basece)
214 {
215 	dom_doc_propsptr doc_props;
216 
217 	if (document) {
218 		doc_props = dom_get_doc_props(document);
219 		if (doc_props->classmap) {
220 			zend_class_entry *ce = zend_hash_find_ptr(doc_props->classmap, basece->name);
221 			if (ce) {
222 				return ce;
223 			}
224 		}
225 	}
226 
227 	return basece;
228 }
229 /* }}} */
230 
231 /* {{{ dom_get_strict_error() */
dom_get_strict_error(php_libxml_ref_obj * document)232 int dom_get_strict_error(php_libxml_ref_obj *document) {
233 	int stricterror;
234 	dom_doc_propsptr doc_props;
235 
236 	doc_props = dom_get_doc_props(document);
237 	stricterror = doc_props->stricterror;
238 	if (document == NULL) {
239 		efree(doc_props);
240 	}
241 
242 	return stricterror;
243 }
244 /* }}} */
245 
246 /* {{{ xmlNodePtr dom_object_get_node(dom_object *obj) */
dom_object_get_node(dom_object * obj)247 PHP_DOM_EXPORT xmlNodePtr dom_object_get_node(dom_object *obj)
248 {
249 	if (obj && obj->ptr != NULL) {
250 		return ((php_libxml_node_ptr *)obj->ptr)->node;
251 	} else {
252 		return NULL;
253 	}
254 }
255 /* }}} end dom_object_get_node */
256 
257 /* {{{ dom_object *php_dom_object_get_data(xmlNodePtr obj) */
php_dom_object_get_data(xmlNodePtr obj)258 PHP_DOM_EXPORT dom_object *php_dom_object_get_data(xmlNodePtr obj)
259 {
260 	if (obj && obj->_private != NULL) {
261 		return (dom_object *) ((php_libxml_node_ptr *) obj->_private)->_private;
262 	} else {
263 		return NULL;
264 	}
265 }
266 /* }}} end php_dom_object_get_data */
267 
dom_register_prop_handler(HashTable * prop_handler,char * name,size_t name_len,dom_read_t read_func,dom_write_t write_func)268 static void dom_register_prop_handler(HashTable *prop_handler, char *name, size_t name_len, dom_read_t read_func, dom_write_t write_func)
269 {
270 	dom_prop_handler hnd;
271 	zend_string *str;
272 
273 	hnd.read_func = read_func;
274 	hnd.write_func = write_func;
275 	str = zend_string_init_interned(name, name_len, 1);
276 	zend_hash_add_mem(prop_handler, str, &hnd, sizeof(dom_prop_handler));
277 	zend_string_release_ex(str, 1);
278 }
279 
dom_get_property_ptr_ptr(zend_object * object,zend_string * name,int type,void ** cache_slot)280 static zval *dom_get_property_ptr_ptr(zend_object *object, zend_string *name, int type, void **cache_slot)
281 {
282 	dom_object *obj = php_dom_obj_from_obj(object);
283 
284 	if (!obj->prop_handler || !zend_hash_exists(obj->prop_handler, name)) {
285 		return zend_std_get_property_ptr_ptr(object, name, type, cache_slot);
286 	}
287 
288 	return NULL;
289 }
290 
291 /* {{{ dom_read_property */
dom_read_property(zend_object * object,zend_string * name,int type,void ** cache_slot,zval * rv)292 zval *dom_read_property(zend_object *object, zend_string *name, int type, void **cache_slot, zval *rv)
293 {
294 	dom_object *obj = php_dom_obj_from_obj(object);
295 	zval *retval;
296 	dom_prop_handler *hnd = NULL;
297 
298 	if (obj->prop_handler != NULL) {
299 		hnd = zend_hash_find_ptr(obj->prop_handler, name);
300 	} else if (instanceof_function(obj->std.ce, dom_node_class_entry)) {
301 		zend_throw_error(NULL, "Couldn't fetch %s. Node no longer exists", ZSTR_VAL(obj->std.ce->name));
302 		retval = &EG(uninitialized_zval);
303 		return retval;
304 	}
305 
306 	if (hnd) {
307 		int ret = hnd->read_func(obj, rv);
308 		if (ret == SUCCESS) {
309 			retval = rv;
310 		} else {
311 			retval = &EG(uninitialized_zval);
312 		}
313 	} else {
314 		retval = zend_std_read_property(object, name, type, cache_slot, rv);
315 	}
316 
317 	return retval;
318 }
319 /* }}} */
320 
dom_write_property(zend_object * object,zend_string * name,zval * value,void ** cache_slot)321 zval *dom_write_property(zend_object *object, zend_string *name, zval *value, void **cache_slot)
322 {
323 	dom_object *obj = php_dom_obj_from_obj(object);
324 	dom_prop_handler *hnd = NULL;
325 
326 	if (obj->prop_handler != NULL) {
327 		hnd = zend_hash_find_ptr(obj->prop_handler, name);
328 	}
329 
330 	if (hnd) {
331 		if (!hnd->write_func) {
332 			zend_throw_error(NULL, "Cannot write read-only property %s::$%s", ZSTR_VAL(object->ce->name), ZSTR_VAL(name));
333 			return &EG(error_zval);
334 		}
335 
336 		zend_property_info *prop = zend_get_property_info(object->ce, name, /* silent */ true);
337 		if (prop && ZEND_TYPE_IS_SET(prop->type)) {
338 			zval tmp;
339 			ZVAL_COPY(&tmp, value);
340 			if (!zend_verify_property_type(prop, &tmp, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data)))) {
341 				zval_ptr_dtor(&tmp);
342 				return &EG(error_zval);
343 			}
344 			hnd->write_func(obj, &tmp);
345 			zval_ptr_dtor(&tmp);
346 		} else {
347 			hnd->write_func(obj, value);
348 		}
349 
350 		return value;
351 	}
352 
353 	return zend_std_write_property(object, name, value, cache_slot);
354 }
355 
356 /* {{{ dom_property_exists */
dom_property_exists(zend_object * object,zend_string * name,int check_empty,void ** cache_slot)357 static int dom_property_exists(zend_object *object, zend_string *name, int check_empty, void **cache_slot)
358 {
359 	dom_object *obj = php_dom_obj_from_obj(object);
360 	dom_prop_handler *hnd = NULL;
361 	int retval = 0;
362 
363 	if (obj->prop_handler != NULL) {
364 		hnd = zend_hash_find_ptr(obj->prop_handler, name);
365 	}
366 	if (hnd) {
367 		zval tmp;
368 
369 		if (check_empty == 2) {
370 			retval = 1;
371 		} else if (hnd->read_func(obj, &tmp) == SUCCESS) {
372 			if (check_empty == 1) {
373 				retval = zend_is_true(&tmp);
374 			} else if (check_empty == 0) {
375 				retval = (Z_TYPE(tmp) != IS_NULL);
376 			}
377 			zval_ptr_dtor(&tmp);
378 		}
379 	} else {
380 		retval = zend_std_has_property(object, name, check_empty, cache_slot);
381 	}
382 
383 	return retval;
384 }
385 /* }}} */
386 
dom_get_debug_info_helper(zend_object * object,int * is_temp)387 static HashTable* dom_get_debug_info_helper(zend_object *object, int *is_temp) /* {{{ */
388 {
389 	dom_object			*obj = php_dom_obj_from_obj(object);
390 	HashTable			*debug_info,
391 						*prop_handlers = obj->prop_handler,
392 						*std_props;
393 	zend_string			*string_key;
394 	dom_prop_handler	*entry;
395 	zend_string         *object_str;
396 
397 	*is_temp = 1;
398 
399 	std_props = zend_std_get_properties(object);
400 	debug_info = zend_array_dup(std_props);
401 
402 	if (!prop_handlers) {
403 		return debug_info;
404 	}
405 
406 	object_str = zend_string_init("(object value omitted)", sizeof("(object value omitted)")-1, 0);
407 
408 	ZEND_HASH_FOREACH_STR_KEY_PTR(prop_handlers, string_key, entry) {
409 		zval value;
410 
411 		if (entry->read_func(obj, &value) == FAILURE || !string_key) {
412 			continue;
413 		}
414 
415 		if (Z_TYPE(value) == IS_OBJECT) {
416 			zval_ptr_dtor(&value);
417 			ZVAL_NEW_STR(&value, object_str);
418 			zend_string_addref(object_str);
419 		}
420 
421 		zend_hash_update(debug_info, string_key, &value);
422 	} ZEND_HASH_FOREACH_END();
423 
424 	zend_string_release_ex(object_str, 0);
425 
426 	return debug_info;
427 }
428 /* }}} */
429 
dom_get_debug_info(zend_object * object,int * is_temp)430 static HashTable* dom_get_debug_info(zend_object *object, int *is_temp) /* {{{ */
431 {
432 	return dom_get_debug_info_helper(object, is_temp);
433 }
434 /* }}} */
435 
php_dom_export_node(zval * object)436 void *php_dom_export_node(zval *object) /* {{{ */
437 {
438 	php_libxml_node_object *intern;
439 	xmlNodePtr nodep = NULL;
440 
441 	intern = (php_libxml_node_object *) Z_DOMOBJ_P(object);
442 	if (intern->node) {
443 		nodep = intern->node->node;
444 	}
445 
446 	return nodep;
447 }
448 /* }}} */
449 
450 /* {{{ Get a simplexml_element object from dom to allow for processing */
PHP_FUNCTION(dom_import_simplexml)451 PHP_FUNCTION(dom_import_simplexml)
452 {
453 	zval *node;
454 	xmlNodePtr nodep = NULL;
455 	php_libxml_node_object *nodeobj;
456 	int ret;
457 
458 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &node) == FAILURE) {
459 		RETURN_THROWS();
460 	}
461 
462 	nodeobj = (php_libxml_node_object *) ((char *) Z_OBJ_P(node) - Z_OBJ_HT_P(node)->offset);
463 	nodep = php_libxml_import_node(node);
464 
465 	if (nodep && nodeobj && (nodep->type == XML_ELEMENT_NODE || nodep->type == XML_ATTRIBUTE_NODE)) {
466 		DOM_RET_OBJ((xmlNodePtr) nodep, &ret, (dom_object *)nodeobj);
467 	} else {
468 		zend_argument_value_error(1, "is not a valid node type");
469 		RETURN_THROWS();
470 	}
471 }
472 /* }}} */
473 
474 static dom_object* dom_objects_set_class(zend_class_entry *class_type);
475 
dom_objects_store_clone_obj(zend_object * zobject)476 static zend_object *dom_objects_store_clone_obj(zend_object *zobject) /* {{{ */
477 {
478 	dom_object *intern = php_dom_obj_from_obj(zobject);
479 	dom_object *clone = dom_objects_set_class(intern->std.ce);
480 
481 	clone->std.handlers = dom_get_obj_handlers();
482 
483 	if (instanceof_function(intern->std.ce, dom_node_class_entry)) {
484 		xmlNodePtr node = (xmlNodePtr)dom_object_get_node(intern);
485 		if (node != NULL) {
486 			xmlNodePtr cloned_node = xmlDocCopyNode(node, node->doc, 1);
487 			if (cloned_node != NULL) {
488 				/* If we cloned a document then we must create new doc proxy */
489 				if (cloned_node->doc == node->doc) {
490 					clone->document = intern->document;
491 				}
492 				php_libxml_increment_doc_ref((php_libxml_node_object *)clone, cloned_node->doc);
493 				php_libxml_increment_node_ptr((php_libxml_node_object *)clone, cloned_node, (void *)clone);
494 				if (intern->document != clone->document) {
495 					dom_copy_doc_props(intern->document, clone->document);
496 				}
497 			}
498 
499 		}
500 	}
501 
502 	zend_objects_clone_members(&clone->std, &intern->std);
503 
504 	return &clone->std;
505 }
506 /* }}} */
507 
dom_copy_prop_handler(zval * zv)508 static void dom_copy_prop_handler(zval *zv) /* {{{ */
509 {
510 	dom_prop_handler *hnd = Z_PTR_P(zv);
511 	Z_PTR_P(zv) = malloc(sizeof(dom_prop_handler));
512 	memcpy(Z_PTR_P(zv), hnd, sizeof(dom_prop_handler));
513 }
514 /* }}} */
515 
dom_dtor_prop_handler(zval * zv)516 static void dom_dtor_prop_handler(zval *zv) /* {{{ */
517 {
518 	free(Z_PTR_P(zv));
519 }
520 
521 static const zend_module_dep dom_deps[] = {
522 	ZEND_MOD_REQUIRED("libxml")
523 	ZEND_MOD_CONFLICTS("domxml")
524 	ZEND_MOD_END
525 };
526 
527 zend_module_entry dom_module_entry = { /* {{{ */
528 	STANDARD_MODULE_HEADER_EX, NULL,
529 	dom_deps,
530 	"dom",
531 	ext_functions,
532 	PHP_MINIT(dom),
533 	PHP_MSHUTDOWN(dom),
534 	NULL,
535 	NULL,
536 	PHP_MINFO(dom),
537 	DOM_API_VERSION, /* Extension versionnumber */
538 	STANDARD_MODULE_PROPERTIES
539 };
540 /* }}} */
541 
542 #ifdef COMPILE_DL_DOM
543 ZEND_GET_MODULE(dom)
544 #endif
545 
546 void dom_objects_free_storage(zend_object *object);
547 void dom_nnodemap_objects_free_storage(zend_object *object);
548 static zval *dom_nodelist_read_dimension(zend_object *object, zval *offset, int type, zval *rv);
549 static int dom_nodelist_has_dimension(zend_object *object, zval *member, int check_empty);
550 static zend_object *dom_objects_store_clone_obj(zend_object *zobject);
551 #ifdef LIBXML_XPATH_ENABLED
552 void dom_xpath_objects_free_storage(zend_object *object);
553 #endif
554 
555 /* {{{ PHP_MINIT_FUNCTION(dom) */
PHP_MINIT_FUNCTION(dom)556 PHP_MINIT_FUNCTION(dom)
557 {
558 	memcpy(&dom_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
559 	dom_object_handlers.offset = XtOffsetOf(dom_object, std);
560 	dom_object_handlers.free_obj = dom_objects_free_storage;
561 	dom_object_handlers.read_property = dom_read_property;
562 	dom_object_handlers.write_property = dom_write_property;
563 	dom_object_handlers.get_property_ptr_ptr = dom_get_property_ptr_ptr;
564 	dom_object_handlers.clone_obj = dom_objects_store_clone_obj;
565 	dom_object_handlers.has_property = dom_property_exists;
566 	dom_object_handlers.get_debug_info = dom_get_debug_info;
567 
568 	memcpy(&dom_nnodemap_object_handlers, &dom_object_handlers, sizeof(zend_object_handlers));
569 	dom_nnodemap_object_handlers.free_obj = dom_nnodemap_objects_free_storage;
570 	dom_nnodemap_object_handlers.read_dimension = dom_nodelist_read_dimension;
571 	dom_nnodemap_object_handlers.has_dimension = dom_nodelist_has_dimension;
572 
573 	zend_hash_init(&classes, 0, NULL, NULL, 1);
574 
575 	dom_domexception_class_entry = register_class_DOMException(zend_ce_exception);
576 
577 	dom_parentnode_class_entry = register_class_DOMParentNode();
578 
579 	dom_childnode_class_entry = register_class_DOMChildNode();
580 
581 	dom_domimplementation_class_entry = register_class_DOMImplementation();
582 	dom_domimplementation_class_entry->create_object = dom_objects_new;
583 
584 	dom_node_class_entry = register_class_DOMNode();
585 	dom_node_class_entry->create_object = dom_objects_new;
586 
587 	zend_hash_init(&dom_node_prop_handlers, 0, NULL, dom_dtor_prop_handler, 1);
588 	dom_register_prop_handler(&dom_node_prop_handlers, "nodeName", sizeof("nodeName")-1, dom_node_node_name_read, NULL);
589 	dom_register_prop_handler(&dom_node_prop_handlers, "nodeValue", sizeof("nodeValue")-1, dom_node_node_value_read, dom_node_node_value_write);
590 	dom_register_prop_handler(&dom_node_prop_handlers, "nodeType", sizeof("nodeType")-1, dom_node_node_type_read, NULL);
591 	dom_register_prop_handler(&dom_node_prop_handlers, "parentNode", sizeof("parentNode")-1, dom_node_parent_node_read, NULL);
592 	dom_register_prop_handler(&dom_node_prop_handlers, "childNodes", sizeof("childNodes")-1, dom_node_child_nodes_read, NULL);
593 	dom_register_prop_handler(&dom_node_prop_handlers, "firstChild", sizeof("firstChild")-1, dom_node_first_child_read, NULL);
594 	dom_register_prop_handler(&dom_node_prop_handlers, "lastChild", sizeof("lastChild")-1, dom_node_last_child_read, NULL);
595 	dom_register_prop_handler(&dom_node_prop_handlers, "previousSibling", sizeof("previousSibling")-1, dom_node_previous_sibling_read, NULL);
596 	dom_register_prop_handler(&dom_node_prop_handlers, "nextSibling", sizeof("nextSibling")-1, dom_node_next_sibling_read, NULL);
597 	dom_register_prop_handler(&dom_node_prop_handlers, "attributes", sizeof("attributes")-1, dom_node_attributes_read, NULL);
598 	dom_register_prop_handler(&dom_node_prop_handlers, "ownerDocument", sizeof("ownerDocument")-1, dom_node_owner_document_read, NULL);
599 	dom_register_prop_handler(&dom_node_prop_handlers, "namespaceURI", sizeof("namespaceURI")-1, dom_node_namespace_uri_read, NULL);
600 	dom_register_prop_handler(&dom_node_prop_handlers, "prefix", sizeof("prefix")-1, dom_node_prefix_read, dom_node_prefix_write);
601 	dom_register_prop_handler(&dom_node_prop_handlers, "localName", sizeof("localName")-1, dom_node_local_name_read, NULL);
602 	dom_register_prop_handler(&dom_node_prop_handlers, "baseURI", sizeof("baseURI")-1, dom_node_base_uri_read, NULL);
603 	dom_register_prop_handler(&dom_node_prop_handlers, "textContent", sizeof("textContent")-1, dom_node_text_content_read, dom_node_text_content_write);
604 	zend_hash_add_ptr(&classes, dom_node_class_entry->name, &dom_node_prop_handlers);
605 
606 	dom_namespace_node_class_entry = register_class_DOMNameSpaceNode();
607 	dom_namespace_node_class_entry->create_object = dom_objects_new;
608 
609 	zend_hash_init(&dom_namespace_node_prop_handlers, 0, NULL, dom_dtor_prop_handler, 1);
610 	dom_register_prop_handler(&dom_namespace_node_prop_handlers, "nodeName", sizeof("nodeName")-1, dom_node_node_name_read, NULL);
611 	dom_register_prop_handler(&dom_namespace_node_prop_handlers, "nodeValue", sizeof("nodeValue")-1, dom_node_node_value_read, NULL);
612 	dom_register_prop_handler(&dom_namespace_node_prop_handlers, "nodeType", sizeof("nodeType")-1, dom_node_node_type_read, NULL);
613 	dom_register_prop_handler(&dom_namespace_node_prop_handlers, "prefix", sizeof("prefix")-1, dom_node_prefix_read, NULL);
614 	dom_register_prop_handler(&dom_namespace_node_prop_handlers, "localName", sizeof("localName")-1, dom_node_local_name_read, NULL);
615 	dom_register_prop_handler(&dom_namespace_node_prop_handlers, "namespaceURI", sizeof("namespaceURI")-1, dom_node_namespace_uri_read, NULL);
616 	dom_register_prop_handler(&dom_namespace_node_prop_handlers, "ownerDocument", sizeof("ownerDocument")-1, dom_node_owner_document_read, NULL);
617 	dom_register_prop_handler(&dom_namespace_node_prop_handlers, "parentNode", sizeof("parentNode")-1, dom_node_parent_node_read, NULL);
618 	zend_hash_add_ptr(&classes, dom_namespace_node_class_entry->name, &dom_namespace_node_prop_handlers);
619 
620 	dom_documentfragment_class_entry = register_class_DOMDocumentFragment(dom_node_class_entry, dom_parentnode_class_entry);
621 	dom_documentfragment_class_entry->create_object = dom_objects_new;
622 	zend_hash_init(&dom_documentfragment_prop_handlers, 0, NULL, dom_dtor_prop_handler, 1);
623 
624 	dom_register_prop_handler(&dom_documentfragment_prop_handlers, "firstElementChild", sizeof("firstElementChild")-1, dom_parent_node_first_element_child_read, NULL);
625 	dom_register_prop_handler(&dom_documentfragment_prop_handlers, "lastElementChild", sizeof("lastElementChild")-1, dom_parent_node_last_element_child_read, NULL);
626 	dom_register_prop_handler(&dom_documentfragment_prop_handlers, "childElementCount", sizeof("childElementCount")-1, dom_parent_node_child_element_count, NULL);
627 
628 	zend_hash_merge(&dom_documentfragment_prop_handlers, &dom_node_prop_handlers, dom_copy_prop_handler, 0);
629 	zend_hash_add_ptr(&classes, dom_documentfragment_class_entry->name, &dom_documentfragment_prop_handlers);
630 
631 	dom_document_class_entry = register_class_DOMDocument(dom_node_class_entry, dom_parentnode_class_entry);
632 	dom_document_class_entry->create_object = dom_objects_new;
633 	zend_hash_init(&dom_document_prop_handlers, 0, NULL, dom_dtor_prop_handler, 1);
634 	dom_register_prop_handler(&dom_document_prop_handlers, "doctype", sizeof("doctype")-1, dom_document_doctype_read, NULL);
635 	dom_register_prop_handler(&dom_document_prop_handlers, "implementation", sizeof("implementation")-1, dom_document_implementation_read, NULL);
636 	dom_register_prop_handler(&dom_document_prop_handlers, "documentElement", sizeof("documentElement")-1, dom_document_document_element_read, NULL);
637 	dom_register_prop_handler(&dom_document_prop_handlers, "actualEncoding", sizeof("actualEncoding")-1, dom_document_encoding_read, NULL);
638 	dom_register_prop_handler(&dom_document_prop_handlers, "encoding", sizeof("encoding")-1, dom_document_encoding_read, dom_document_encoding_write);
639 	dom_register_prop_handler(&dom_document_prop_handlers, "xmlEncoding", sizeof("xmlEncoding")-1, dom_document_encoding_read, NULL);
640 	dom_register_prop_handler(&dom_document_prop_handlers, "standalone", sizeof("standalone")-1, dom_document_standalone_read, dom_document_standalone_write);
641 	dom_register_prop_handler(&dom_document_prop_handlers, "xmlStandalone", sizeof("xmlStandalone")-1, dom_document_standalone_read, dom_document_standalone_write);
642 	dom_register_prop_handler(&dom_document_prop_handlers, "version", sizeof("version")-1, dom_document_version_read, dom_document_version_write);
643 	dom_register_prop_handler(&dom_document_prop_handlers, "xmlVersion", sizeof("xmlVersion")-1, dom_document_version_read, dom_document_version_write);
644 	dom_register_prop_handler(&dom_document_prop_handlers, "strictErrorChecking", sizeof("strictErrorChecking")-1, dom_document_strict_error_checking_read, dom_document_strict_error_checking_write);
645 	dom_register_prop_handler(&dom_document_prop_handlers, "documentURI", sizeof("documentURI")-1, dom_document_document_uri_read, dom_document_document_uri_write);
646 	dom_register_prop_handler(&dom_document_prop_handlers, "config", sizeof("config")-1, dom_document_config_read, NULL);
647 	dom_register_prop_handler(&dom_document_prop_handlers, "formatOutput", sizeof("formatOutput")-1, dom_document_format_output_read, dom_document_format_output_write);
648 	dom_register_prop_handler(&dom_document_prop_handlers, "validateOnParse", sizeof("validateOnParse")-1, dom_document_validate_on_parse_read, dom_document_validate_on_parse_write);
649 	dom_register_prop_handler(&dom_document_prop_handlers, "resolveExternals", sizeof("resolveExternals")-1, dom_document_resolve_externals_read, dom_document_resolve_externals_write);
650 	dom_register_prop_handler(&dom_document_prop_handlers, "preserveWhiteSpace", sizeof("preserveWhitespace")-1, dom_document_preserve_whitespace_read, dom_document_preserve_whitespace_write);
651 	dom_register_prop_handler(&dom_document_prop_handlers, "recover", sizeof("recover")-1, dom_document_recover_read, dom_document_recover_write);
652 	dom_register_prop_handler(&dom_document_prop_handlers, "substituteEntities", sizeof("substituteEntities")-1, dom_document_substitue_entities_read, dom_document_substitue_entities_write);
653 
654 	dom_register_prop_handler(&dom_document_prop_handlers, "firstElementChild", sizeof("firstElementChild")-1, dom_parent_node_first_element_child_read, NULL);
655 	dom_register_prop_handler(&dom_document_prop_handlers, "lastElementChild", sizeof("lastElementChild")-1, dom_parent_node_last_element_child_read, NULL);
656 	dom_register_prop_handler(&dom_document_prop_handlers, "childElementCount", sizeof("childElementCount")-1, dom_parent_node_child_element_count, NULL);
657 
658 	zend_hash_merge(&dom_document_prop_handlers, &dom_node_prop_handlers, dom_copy_prop_handler, 0);
659 	zend_hash_add_ptr(&classes, dom_document_class_entry->name, &dom_document_prop_handlers);
660 
661 	dom_nodelist_class_entry = register_class_DOMNodeList(zend_ce_aggregate, zend_ce_countable);
662 	dom_nodelist_class_entry->create_object = dom_nnodemap_objects_new;
663 	dom_nodelist_class_entry->get_iterator = php_dom_get_iterator;
664 
665 	zend_hash_init(&dom_nodelist_prop_handlers, 0, NULL, dom_dtor_prop_handler, 1);
666 	dom_register_prop_handler(&dom_nodelist_prop_handlers, "length", sizeof("length")-1, dom_nodelist_length_read, NULL);
667 	zend_hash_add_ptr(&classes, dom_nodelist_class_entry->name, &dom_nodelist_prop_handlers);
668 
669 	dom_namednodemap_class_entry = register_class_DOMNamedNodeMap(zend_ce_aggregate, zend_ce_countable);
670 	dom_namednodemap_class_entry->create_object = dom_nnodemap_objects_new;
671 	dom_namednodemap_class_entry->get_iterator = php_dom_get_iterator;
672 
673 	zend_hash_init(&dom_namednodemap_prop_handlers, 0, NULL, dom_dtor_prop_handler, 1);
674 	dom_register_prop_handler(&dom_namednodemap_prop_handlers, "length", sizeof("length")-1, dom_namednodemap_length_read, NULL);
675 	zend_hash_add_ptr(&classes, dom_namednodemap_class_entry->name, &dom_namednodemap_prop_handlers);
676 
677 	dom_characterdata_class_entry = register_class_DOMCharacterData(dom_node_class_entry, dom_childnode_class_entry);
678 	dom_characterdata_class_entry->create_object = dom_objects_new;
679 
680 	zend_hash_init(&dom_characterdata_prop_handlers, 0, NULL, dom_dtor_prop_handler, 1);
681 	dom_register_prop_handler(&dom_characterdata_prop_handlers, "data", sizeof("data")-1, dom_characterdata_data_read, dom_characterdata_data_write);
682 	dom_register_prop_handler(&dom_characterdata_prop_handlers, "length", sizeof("length")-1, dom_characterdata_length_read, NULL);
683 	dom_register_prop_handler(&dom_characterdata_prop_handlers, "previousElementSibling", sizeof("previousElementSibling")-1, dom_node_previous_element_sibling_read, NULL);
684 	dom_register_prop_handler(&dom_characterdata_prop_handlers, "nextElementSibling", sizeof("nextElementSibling")-1, dom_node_next_element_sibling_read, NULL);
685 	zend_hash_merge(&dom_characterdata_prop_handlers, &dom_node_prop_handlers, dom_copy_prop_handler, 0);
686 	zend_hash_add_ptr(&classes, dom_characterdata_class_entry->name, &dom_characterdata_prop_handlers);
687 
688 	dom_attr_class_entry = register_class_DOMAttr(dom_node_class_entry);
689 	dom_attr_class_entry->create_object = dom_objects_new;
690 
691 	zend_hash_init(&dom_attr_prop_handlers, 0, NULL, dom_dtor_prop_handler, 1);
692 	dom_register_prop_handler(&dom_attr_prop_handlers, "name", sizeof("name")-1, dom_attr_name_read, NULL);
693 	dom_register_prop_handler(&dom_attr_prop_handlers, "specified", sizeof("specified")-1, dom_attr_specified_read, NULL);
694 	dom_register_prop_handler(&dom_attr_prop_handlers, "value", sizeof("value")-1, dom_attr_value_read, dom_attr_value_write);
695 	dom_register_prop_handler(&dom_attr_prop_handlers, "ownerElement", sizeof("ownerElement")-1, dom_attr_owner_element_read, NULL);
696 	dom_register_prop_handler(&dom_attr_prop_handlers, "schemaTypeInfo", sizeof("schemaTypeInfo")-1, dom_attr_schema_type_info_read, NULL);
697 	zend_hash_merge(&dom_attr_prop_handlers, &dom_node_prop_handlers, dom_copy_prop_handler, 0);
698 	zend_hash_add_ptr(&classes, dom_attr_class_entry->name, &dom_attr_prop_handlers);
699 
700 	dom_element_class_entry = register_class_DOMElement(dom_node_class_entry, dom_parentnode_class_entry, dom_childnode_class_entry);
701 	dom_element_class_entry->create_object = dom_objects_new;
702 
703 	zend_hash_init(&dom_element_prop_handlers, 0, NULL, dom_dtor_prop_handler, 1);
704 	dom_register_prop_handler(&dom_element_prop_handlers, "tagName", sizeof("tagName")-1, dom_element_tag_name_read, NULL);
705 	dom_register_prop_handler(&dom_element_prop_handlers, "schemaTypeInfo", sizeof("schemaTypeInfo")-1, dom_element_schema_type_info_read, NULL);
706 	dom_register_prop_handler(&dom_element_prop_handlers, "firstElementChild", sizeof("firstElementChild")-1, dom_parent_node_first_element_child_read, NULL);
707 	dom_register_prop_handler(&dom_element_prop_handlers, "lastElementChild", sizeof("lastElementChild")-1, dom_parent_node_last_element_child_read, NULL);
708 	dom_register_prop_handler(&dom_element_prop_handlers, "childElementCount", sizeof("childElementCount")-1, dom_parent_node_child_element_count, NULL);
709 	dom_register_prop_handler(&dom_element_prop_handlers, "previousElementSibling", sizeof("previousElementSibling")-1, dom_node_previous_element_sibling_read, NULL);
710 	dom_register_prop_handler(&dom_element_prop_handlers, "nextElementSibling", sizeof("nextElementSibling")-1, dom_node_next_element_sibling_read, NULL);
711 	zend_hash_merge(&dom_element_prop_handlers, &dom_node_prop_handlers, dom_copy_prop_handler, 0);
712 	zend_hash_add_ptr(&classes, dom_element_class_entry->name, &dom_element_prop_handlers);
713 
714 	dom_text_class_entry = register_class_DOMText(dom_characterdata_class_entry);
715 	dom_text_class_entry->create_object = dom_objects_new;
716 
717 	zend_hash_init(&dom_text_prop_handlers, 0, NULL, dom_dtor_prop_handler, 1);
718 	dom_register_prop_handler(&dom_text_prop_handlers, "wholeText", sizeof("wholeText")-1, dom_text_whole_text_read, NULL);
719 	zend_hash_merge(&dom_text_prop_handlers, &dom_characterdata_prop_handlers, dom_copy_prop_handler, 0);
720 	zend_hash_add_ptr(&classes, dom_text_class_entry->name, &dom_text_prop_handlers);
721 
722 	dom_comment_class_entry = register_class_DOMComment(dom_characterdata_class_entry);
723 	dom_comment_class_entry->create_object = dom_objects_new;
724 	zend_hash_add_ptr(&classes, dom_comment_class_entry->name, &dom_characterdata_prop_handlers);
725 
726 	dom_cdatasection_class_entry = register_class_DOMCdataSection(dom_text_class_entry);
727 	dom_cdatasection_class_entry->create_object = dom_objects_new;
728 	zend_hash_add_ptr(&classes, dom_cdatasection_class_entry->name, &dom_text_prop_handlers);
729 
730 	dom_documenttype_class_entry = register_class_DOMDocumentType(dom_node_class_entry);
731 	dom_documenttype_class_entry->create_object = dom_objects_new;
732 
733 	zend_hash_init(&dom_documenttype_prop_handlers, 0, NULL, dom_dtor_prop_handler, 1);
734 	dom_register_prop_handler(&dom_documenttype_prop_handlers, "name", sizeof("name")-1, dom_documenttype_name_read, NULL);
735 	dom_register_prop_handler(&dom_documenttype_prop_handlers, "entities", sizeof("entities")-1, dom_documenttype_entities_read, NULL);
736 	dom_register_prop_handler(&dom_documenttype_prop_handlers, "notations", sizeof("notations")-1, dom_documenttype_notations_read, NULL);
737 	dom_register_prop_handler(&dom_documenttype_prop_handlers, "publicId", sizeof("publicId")-1, dom_documenttype_public_id_read, NULL);
738 	dom_register_prop_handler(&dom_documenttype_prop_handlers, "systemId", sizeof("systemId")-1, dom_documenttype_system_id_read, NULL);
739 	dom_register_prop_handler(&dom_documenttype_prop_handlers, "internalSubset", sizeof("internalSubset")-1, dom_documenttype_internal_subset_read, NULL);
740 	zend_hash_merge(&dom_documenttype_prop_handlers, &dom_node_prop_handlers, dom_copy_prop_handler, 0);
741 	zend_hash_add_ptr(&classes, dom_documenttype_class_entry->name, &dom_documenttype_prop_handlers);
742 
743 	dom_notation_class_entry = register_class_DOMNotation(dom_node_class_entry);
744 	dom_notation_class_entry->create_object = dom_objects_new;
745 
746 	zend_hash_init(&dom_notation_prop_handlers, 0, NULL, dom_dtor_prop_handler, 1);
747 	dom_register_prop_handler(&dom_notation_prop_handlers, "publicId", sizeof("publicId")-1, dom_notation_public_id_read, NULL);
748 	dom_register_prop_handler(&dom_notation_prop_handlers, "systemId", sizeof("systemId")-1, dom_notation_system_id_read, NULL);
749 	zend_hash_merge(&dom_notation_prop_handlers, &dom_node_prop_handlers, dom_copy_prop_handler, 0);
750 	zend_hash_add_ptr(&classes, dom_notation_class_entry->name, &dom_notation_prop_handlers);
751 
752 	dom_entity_class_entry = register_class_DOMEntity(dom_node_class_entry);
753 	dom_entity_class_entry->create_object = dom_objects_new;
754 
755 	zend_hash_init(&dom_entity_prop_handlers, 0, NULL, dom_dtor_prop_handler, 1);
756 	dom_register_prop_handler(&dom_entity_prop_handlers, "publicId", sizeof("publicId")-1, dom_entity_public_id_read, NULL);
757 	dom_register_prop_handler(&dom_entity_prop_handlers, "systemId", sizeof("systemId")-1, dom_entity_system_id_read, NULL);
758 	dom_register_prop_handler(&dom_entity_prop_handlers, "notationName", sizeof("notationName")-1, dom_entity_notation_name_read, NULL);
759 	dom_register_prop_handler(&dom_entity_prop_handlers, "actualEncoding", sizeof("actualEncoding")-1, dom_entity_actual_encoding_read, NULL);
760 	dom_register_prop_handler(&dom_entity_prop_handlers, "encoding", sizeof("encoding")-1, dom_entity_encoding_read, NULL);
761 	dom_register_prop_handler(&dom_entity_prop_handlers, "version", sizeof("version")-1, dom_entity_version_read, NULL);
762 	zend_hash_merge(&dom_entity_prop_handlers, &dom_node_prop_handlers, dom_copy_prop_handler, 0);
763 	zend_hash_add_ptr(&classes, dom_entity_class_entry->name, &dom_entity_prop_handlers);
764 
765 	dom_entityreference_class_entry = register_class_DOMEntityReference(dom_node_class_entry);
766 	dom_entityreference_class_entry->create_object = dom_objects_new;
767 	zend_hash_add_ptr(&classes, dom_entityreference_class_entry->name, &dom_node_prop_handlers);
768 
769 	dom_processinginstruction_class_entry = register_class_DOMProcessingInstruction(dom_node_class_entry);
770 	dom_processinginstruction_class_entry->create_object = dom_objects_new;
771 
772 	zend_hash_init(&dom_processinginstruction_prop_handlers, 0, NULL, dom_dtor_prop_handler, 1);
773 	dom_register_prop_handler(&dom_processinginstruction_prop_handlers, "target", sizeof("target")-1, dom_processinginstruction_target_read, NULL);
774 	dom_register_prop_handler(&dom_processinginstruction_prop_handlers, "data", sizeof("data")-1, dom_processinginstruction_data_read, dom_processinginstruction_data_write);
775 	zend_hash_merge(&dom_processinginstruction_prop_handlers, &dom_node_prop_handlers, dom_copy_prop_handler, 0);
776 	zend_hash_add_ptr(&classes, dom_processinginstruction_class_entry->name, &dom_processinginstruction_prop_handlers);
777 
778 #ifdef LIBXML_XPATH_ENABLED
779 	memcpy(&dom_xpath_object_handlers, &dom_object_handlers, sizeof(zend_object_handlers));
780 	dom_xpath_object_handlers.offset = XtOffsetOf(dom_xpath_object, dom) + XtOffsetOf(dom_object, std);
781 	dom_xpath_object_handlers.free_obj = dom_xpath_objects_free_storage;
782 
783 	dom_xpath_class_entry = register_class_DOMXPath();
784 	dom_xpath_class_entry->create_object = dom_xpath_objects_new;
785 
786 	zend_hash_init(&dom_xpath_prop_handlers, 0, NULL, dom_dtor_prop_handler, 1);
787 	dom_register_prop_handler(&dom_xpath_prop_handlers, "document", sizeof("document")-1, dom_xpath_document_read, NULL);
788 	dom_register_prop_handler(&dom_xpath_prop_handlers, "registerNodeNamespaces", sizeof("registerNodeNamespaces")-1, dom_xpath_register_node_ns_read, dom_xpath_register_node_ns_write);
789 	zend_hash_add_ptr(&classes, dom_xpath_class_entry->name, &dom_xpath_prop_handlers);
790 #endif
791 
792 	REGISTER_LONG_CONSTANT("XML_ELEMENT_NODE",			XML_ELEMENT_NODE,			CONST_CS | CONST_PERSISTENT);
793 	REGISTER_LONG_CONSTANT("XML_ATTRIBUTE_NODE",		XML_ATTRIBUTE_NODE,			CONST_CS | CONST_PERSISTENT);
794 	REGISTER_LONG_CONSTANT("XML_TEXT_NODE",				XML_TEXT_NODE,				CONST_CS | CONST_PERSISTENT);
795 	REGISTER_LONG_CONSTANT("XML_CDATA_SECTION_NODE",	XML_CDATA_SECTION_NODE,		CONST_CS | CONST_PERSISTENT);
796 	REGISTER_LONG_CONSTANT("XML_ENTITY_REF_NODE",		XML_ENTITY_REF_NODE,		CONST_CS | CONST_PERSISTENT);
797 	REGISTER_LONG_CONSTANT("XML_ENTITY_NODE",			XML_ENTITY_NODE,			CONST_CS | CONST_PERSISTENT);
798 	REGISTER_LONG_CONSTANT("XML_PI_NODE",				XML_PI_NODE,				CONST_CS | CONST_PERSISTENT);
799 	REGISTER_LONG_CONSTANT("XML_COMMENT_NODE",			XML_COMMENT_NODE,			CONST_CS | CONST_PERSISTENT);
800 	REGISTER_LONG_CONSTANT("XML_DOCUMENT_NODE",			XML_DOCUMENT_NODE,			CONST_CS | CONST_PERSISTENT);
801 	REGISTER_LONG_CONSTANT("XML_DOCUMENT_TYPE_NODE",	XML_DOCUMENT_TYPE_NODE,		CONST_CS | CONST_PERSISTENT);
802 	REGISTER_LONG_CONSTANT("XML_DOCUMENT_FRAG_NODE",	XML_DOCUMENT_FRAG_NODE,		CONST_CS | CONST_PERSISTENT);
803 	REGISTER_LONG_CONSTANT("XML_NOTATION_NODE",			XML_NOTATION_NODE,			CONST_CS | CONST_PERSISTENT);
804 	REGISTER_LONG_CONSTANT("XML_HTML_DOCUMENT_NODE",	XML_HTML_DOCUMENT_NODE,		CONST_CS | CONST_PERSISTENT);
805 	REGISTER_LONG_CONSTANT("XML_DTD_NODE",				XML_DTD_NODE,				CONST_CS | CONST_PERSISTENT);
806 	REGISTER_LONG_CONSTANT("XML_ELEMENT_DECL_NODE", 	XML_ELEMENT_DECL,			CONST_CS | CONST_PERSISTENT);
807 	REGISTER_LONG_CONSTANT("XML_ATTRIBUTE_DECL_NODE",	XML_ATTRIBUTE_DECL,			CONST_CS | CONST_PERSISTENT);
808 	REGISTER_LONG_CONSTANT("XML_ENTITY_DECL_NODE",		XML_ENTITY_DECL,			CONST_CS | CONST_PERSISTENT);
809 	REGISTER_LONG_CONSTANT("XML_NAMESPACE_DECL_NODE",	XML_NAMESPACE_DECL,			CONST_CS | CONST_PERSISTENT);
810 #ifdef XML_GLOBAL_NAMESPACE
811 	REGISTER_LONG_CONSTANT("XML_GLOBAL_NAMESPACE",		XML_GLOBAL_NAMESPACE,		CONST_CS | CONST_PERSISTENT);
812 #endif
813 	REGISTER_LONG_CONSTANT("XML_LOCAL_NAMESPACE",		XML_LOCAL_NAMESPACE,		CONST_CS | CONST_PERSISTENT);
814 	REGISTER_LONG_CONSTANT("XML_ATTRIBUTE_CDATA",		XML_ATTRIBUTE_CDATA,		CONST_CS | CONST_PERSISTENT);
815 	REGISTER_LONG_CONSTANT("XML_ATTRIBUTE_ID",			XML_ATTRIBUTE_ID,			CONST_CS | CONST_PERSISTENT);
816 	REGISTER_LONG_CONSTANT("XML_ATTRIBUTE_IDREF",		XML_ATTRIBUTE_IDREF,		CONST_CS | CONST_PERSISTENT);
817 	REGISTER_LONG_CONSTANT("XML_ATTRIBUTE_IDREFS",		XML_ATTRIBUTE_IDREFS,		CONST_CS | CONST_PERSISTENT);
818 	REGISTER_LONG_CONSTANT("XML_ATTRIBUTE_ENTITY",		XML_ATTRIBUTE_ENTITIES,		CONST_CS | CONST_PERSISTENT);
819 	REGISTER_LONG_CONSTANT("XML_ATTRIBUTE_NMTOKEN",		XML_ATTRIBUTE_NMTOKEN,		CONST_CS | CONST_PERSISTENT);
820 	REGISTER_LONG_CONSTANT("XML_ATTRIBUTE_NMTOKENS",	XML_ATTRIBUTE_NMTOKENS,		CONST_CS | CONST_PERSISTENT);
821 	REGISTER_LONG_CONSTANT("XML_ATTRIBUTE_ENUMERATION",	XML_ATTRIBUTE_ENUMERATION,	CONST_CS | CONST_PERSISTENT);
822 	REGISTER_LONG_CONSTANT("XML_ATTRIBUTE_NOTATION",	XML_ATTRIBUTE_NOTATION,		CONST_CS | CONST_PERSISTENT);
823 
824 	/* DOMException Codes */
825 	REGISTER_LONG_CONSTANT("DOM_PHP_ERR",				PHP_ERR,				CONST_CS | CONST_PERSISTENT);
826 	REGISTER_LONG_CONSTANT("DOM_INDEX_SIZE_ERR",		INDEX_SIZE_ERR,			CONST_CS | CONST_PERSISTENT);
827 	REGISTER_LONG_CONSTANT("DOMSTRING_SIZE_ERR",		DOMSTRING_SIZE_ERR,		CONST_CS | CONST_PERSISTENT);
828 	REGISTER_LONG_CONSTANT("DOM_HIERARCHY_REQUEST_ERR",	HIERARCHY_REQUEST_ERR,	CONST_CS | CONST_PERSISTENT);
829 	REGISTER_LONG_CONSTANT("DOM_WRONG_DOCUMENT_ERR",	WRONG_DOCUMENT_ERR,		CONST_CS | CONST_PERSISTENT);
830 	REGISTER_LONG_CONSTANT("DOM_INVALID_CHARACTER_ERR",	INVALID_CHARACTER_ERR,	CONST_CS | CONST_PERSISTENT);
831 	REGISTER_LONG_CONSTANT("DOM_NO_DATA_ALLOWED_ERR",	NO_DATA_ALLOWED_ERR,	CONST_CS | CONST_PERSISTENT);
832 	REGISTER_LONG_CONSTANT("DOM_NO_MODIFICATION_ALLOWED_ERR", NO_MODIFICATION_ALLOWED_ERR, CONST_CS | CONST_PERSISTENT);
833 	REGISTER_LONG_CONSTANT("DOM_NOT_FOUND_ERR",			NOT_FOUND_ERR,			CONST_CS | CONST_PERSISTENT);
834 	REGISTER_LONG_CONSTANT("DOM_NOT_SUPPORTED_ERR",		NOT_SUPPORTED_ERR,		CONST_CS | CONST_PERSISTENT);
835 	REGISTER_LONG_CONSTANT("DOM_INUSE_ATTRIBUTE_ERR",	INUSE_ATTRIBUTE_ERR,	CONST_CS | CONST_PERSISTENT);
836 	REGISTER_LONG_CONSTANT("DOM_INVALID_STATE_ERR",		INVALID_STATE_ERR,		CONST_CS | CONST_PERSISTENT);
837 	REGISTER_LONG_CONSTANT("DOM_SYNTAX_ERR",			SYNTAX_ERR,				CONST_CS | CONST_PERSISTENT);
838 	REGISTER_LONG_CONSTANT("DOM_INVALID_MODIFICATION_ERR",	INVALID_MODIFICATION_ERR, CONST_CS | CONST_PERSISTENT);
839 	REGISTER_LONG_CONSTANT("DOM_NAMESPACE_ERR",			NAMESPACE_ERR,			CONST_CS | CONST_PERSISTENT);
840 	REGISTER_LONG_CONSTANT("DOM_INVALID_ACCESS_ERR",	INVALID_ACCESS_ERR,		CONST_CS | CONST_PERSISTENT);
841 	REGISTER_LONG_CONSTANT("DOM_VALIDATION_ERR",		VALIDATION_ERR,			CONST_CS | CONST_PERSISTENT);
842 
843 	php_libxml_register_export(dom_node_class_entry, php_dom_export_node);
844 
845 	return SUCCESS;
846 }
847 /* }}} */
848 
849 /* {{{ */
PHP_MINFO_FUNCTION(dom)850 PHP_MINFO_FUNCTION(dom)
851 {
852 	php_info_print_table_start();
853 	php_info_print_table_row(2, "DOM/XML", "enabled");
854 	php_info_print_table_row(2, "DOM/XML API Version", DOM_API_VERSION);
855 	php_info_print_table_row(2, "libxml Version", LIBXML_DOTTED_VERSION);
856 #ifdef LIBXML_HTML_ENABLED
857 	php_info_print_table_row(2, "HTML Support", "enabled");
858 #endif
859 #ifdef LIBXML_XPATH_ENABLED
860 	php_info_print_table_row(2, "XPath Support", "enabled");
861 #endif
862 #ifdef LIBXML_XPTR_ENABLED
863 	php_info_print_table_row(2, "XPointer Support", "enabled");
864 #endif
865 #ifdef LIBXML_SCHEMAS_ENABLED
866 	php_info_print_table_row(2, "Schema Support", "enabled");
867 	php_info_print_table_row(2, "RelaxNG Support", "enabled");
868 #endif
869 	php_info_print_table_end();
870 }
871 /* }}} */
872 
PHP_MSHUTDOWN_FUNCTION(dom)873 PHP_MSHUTDOWN_FUNCTION(dom) /* {{{ */
874 {
875 	zend_hash_destroy(&dom_document_prop_handlers);
876 	zend_hash_destroy(&dom_documentfragment_prop_handlers);
877 	zend_hash_destroy(&dom_node_prop_handlers);
878 	zend_hash_destroy(&dom_namespace_node_prop_handlers);
879 	zend_hash_destroy(&dom_nodelist_prop_handlers);
880 	zend_hash_destroy(&dom_namednodemap_prop_handlers);
881 	zend_hash_destroy(&dom_characterdata_prop_handlers);
882 	zend_hash_destroy(&dom_attr_prop_handlers);
883 	zend_hash_destroy(&dom_element_prop_handlers);
884 	zend_hash_destroy(&dom_text_prop_handlers);
885 	zend_hash_destroy(&dom_documenttype_prop_handlers);
886 	zend_hash_destroy(&dom_notation_prop_handlers);
887 	zend_hash_destroy(&dom_entity_prop_handlers);
888 	zend_hash_destroy(&dom_processinginstruction_prop_handlers);
889 #ifdef LIBXML_XPATH_ENABLED
890 	zend_hash_destroy(&dom_xpath_prop_handlers);
891 #endif
892 	zend_hash_destroy(&classes);
893 
894 /*	If you want do find memleaks in this module, compile libxml2 with --with-mem-debug and
895 	uncomment the following line, this will tell you the amount of not freed memory
896 	and the total used memory into apaches error_log  */
897 /*  xmlMemoryDump();*/
898 
899 	return SUCCESS;
900 }
901 /* }}} */
902 
903 /* {{{ node_list_unlink */
node_list_unlink(xmlNodePtr node)904 void node_list_unlink(xmlNodePtr node)
905 {
906 	dom_object *wrapper;
907 
908 	while (node != NULL) {
909 
910 		wrapper = php_dom_object_get_data(node);
911 
912 		if (wrapper != NULL ) {
913 			xmlUnlinkNode(node);
914 		} else {
915 			if (node->type == XML_ENTITY_REF_NODE)
916 				break;
917 			node_list_unlink(node->children);
918 
919 			switch (node->type) {
920 				case XML_ATTRIBUTE_DECL:
921 				case XML_DTD_NODE:
922 				case XML_DOCUMENT_TYPE_NODE:
923 				case XML_ENTITY_DECL:
924 				case XML_ATTRIBUTE_NODE:
925 				case XML_TEXT_NODE:
926 					break;
927 				default:
928 					node_list_unlink((xmlNodePtr) node->properties);
929 			}
930 
931 		}
932 
933 		node = node->next;
934 	}
935 }
936 /* }}} end node_list_unlink */
937 
938 #ifdef LIBXML_XPATH_ENABLED
939 /* {{{ dom_xpath_objects_free_storage */
dom_xpath_objects_free_storage(zend_object * object)940 void dom_xpath_objects_free_storage(zend_object *object)
941 {
942 	dom_xpath_object *intern = php_xpath_obj_from_obj(object);
943 
944 	zend_object_std_dtor(&intern->dom.std);
945 
946 	if (intern->dom.ptr != NULL) {
947 		xmlXPathFreeContext((xmlXPathContextPtr) intern->dom.ptr);
948 		php_libxml_decrement_doc_ref((php_libxml_node_object *) &intern->dom);
949 	}
950 
951 	if (intern->registered_phpfunctions) {
952 		zend_hash_destroy(intern->registered_phpfunctions);
953 		FREE_HASHTABLE(intern->registered_phpfunctions);
954 	}
955 
956 	if (intern->node_list) {
957 		zend_hash_destroy(intern->node_list);
958 		FREE_HASHTABLE(intern->node_list);
959 	}
960 }
961 /* }}} */
962 #endif
963 
964 /* {{{ dom_objects_free_storage */
dom_objects_free_storage(zend_object * object)965 void dom_objects_free_storage(zend_object *object)
966 {
967 	dom_object *intern = php_dom_obj_from_obj(object);
968 #if defined(__GNUC__) && __GNUC__ >= 3
969 	int retcount __attribute__((unused)); /* keep compiler quiet */
970 #else
971 	int retcount;
972 #endif
973 
974 	zend_object_std_dtor(&intern->std);
975 
976 	if (intern->ptr != NULL && ((php_libxml_node_ptr *)intern->ptr)->node != NULL) {
977 		if (((xmlNodePtr) ((php_libxml_node_ptr *)intern->ptr)->node)->type != XML_DOCUMENT_NODE && ((xmlNodePtr) ((php_libxml_node_ptr *)intern->ptr)->node)->type != XML_HTML_DOCUMENT_NODE) {
978 			php_libxml_node_decrement_resource((php_libxml_node_object *) intern);
979 		} else {
980 			php_libxml_decrement_node_ptr((php_libxml_node_object *) intern);
981 			retcount = php_libxml_decrement_doc_ref((php_libxml_node_object *)intern);
982 		}
983 		intern->ptr = NULL;
984 	}
985 }
986 /* }}} */
987 
dom_namednode_iter(dom_object * basenode,int ntype,dom_object * intern,xmlHashTablePtr ht,xmlChar * local,xmlChar * ns)988 void dom_namednode_iter(dom_object *basenode, int ntype, dom_object *intern, xmlHashTablePtr ht, xmlChar *local, xmlChar *ns) /* {{{ */
989 {
990 	dom_nnodemap_object *mapptr = (dom_nnodemap_object *) intern->ptr;
991 
992 	ZEND_ASSERT(basenode != NULL);
993 
994 	ZVAL_OBJ_COPY(&mapptr->baseobj_zv, &basenode->std);
995 
996 	mapptr->baseobj = basenode;
997 	mapptr->nodetype = ntype;
998 	mapptr->ht = ht;
999 	mapptr->local = local;
1000 	mapptr->ns = ns;
1001 }
1002 /* }}} */
1003 
dom_objects_set_class(zend_class_entry * class_type)1004 static dom_object* dom_objects_set_class(zend_class_entry *class_type) /* {{{ */
1005 {
1006 	dom_object *intern = zend_object_alloc(sizeof(dom_object), class_type);
1007 
1008 	zend_class_entry *base_class = class_type;
1009 	while ((base_class->type != ZEND_INTERNAL_CLASS || base_class->info.internal.module->module_number != dom_module_entry.module_number) && base_class->parent != NULL) {
1010 		base_class = base_class->parent;
1011 	}
1012 
1013 	intern->prop_handler = zend_hash_find_ptr(&classes, base_class->name);
1014 
1015 	zend_object_std_init(&intern->std, class_type);
1016 	object_properties_init(&intern->std, class_type);
1017 
1018 	return intern;
1019 }
1020 /* }}} */
1021 
1022 /* {{{ dom_objects_new */
dom_objects_new(zend_class_entry * class_type)1023 zend_object *dom_objects_new(zend_class_entry *class_type)
1024 {
1025 	dom_object *intern = dom_objects_set_class(class_type);
1026 	intern->std.handlers = dom_get_obj_handlers();
1027 	return &intern->std;
1028 }
1029 /* }}} */
1030 
1031 #ifdef LIBXML_XPATH_ENABLED
1032 /* {{{ zend_object dom_xpath_objects_new(zend_class_entry *class_type) */
dom_xpath_objects_new(zend_class_entry * class_type)1033 zend_object *dom_xpath_objects_new(zend_class_entry *class_type)
1034 {
1035 	dom_xpath_object *intern = zend_object_alloc(sizeof(dom_xpath_object), class_type);
1036 
1037 	intern->registered_phpfunctions = zend_new_array(0);
1038 	intern->register_node_ns = 1;
1039 
1040 	intern->dom.prop_handler = &dom_xpath_prop_handlers;
1041 	intern->dom.std.handlers = &dom_xpath_object_handlers;
1042 
1043 	zend_object_std_init(&intern->dom.std, class_type);
1044 	object_properties_init(&intern->dom.std, class_type);
1045 
1046 	return &intern->dom.std;
1047 }
1048 /* }}} */
1049 #endif
1050 
dom_nnodemap_objects_free_storage(zend_object * object)1051 void dom_nnodemap_objects_free_storage(zend_object *object) /* {{{ */
1052 {
1053 	dom_object *intern = php_dom_obj_from_obj(object);
1054 	dom_nnodemap_object *objmap = (dom_nnodemap_object *)intern->ptr;
1055 
1056 	if (objmap) {
1057 		if (objmap->local) {
1058 			xmlFree(objmap->local);
1059 		}
1060 		if (objmap->ns) {
1061 			xmlFree(objmap->ns);
1062 		}
1063 		if (!Z_ISUNDEF(objmap->baseobj_zv)) {
1064 			zval_ptr_dtor(&objmap->baseobj_zv);
1065 		}
1066 		efree(objmap);
1067 		intern->ptr = NULL;
1068 	}
1069 
1070 	php_libxml_decrement_doc_ref((php_libxml_node_object *)intern);
1071 
1072 	zend_object_std_dtor(&intern->std);
1073 }
1074 /* }}} */
1075 
dom_nnodemap_objects_new(zend_class_entry * class_type)1076 zend_object *dom_nnodemap_objects_new(zend_class_entry *class_type) /* {{{ */
1077 {
1078 	dom_object *intern;
1079 	dom_nnodemap_object *objmap;
1080 
1081 	intern = dom_objects_set_class(class_type);
1082 	intern->ptr = emalloc(sizeof(dom_nnodemap_object));
1083 	objmap = (dom_nnodemap_object *)intern->ptr;
1084 	ZVAL_UNDEF(&objmap->baseobj_zv);
1085 	objmap->baseobj = NULL;
1086 	objmap->nodetype = 0;
1087 	objmap->ht = NULL;
1088 	objmap->local = NULL;
1089 	objmap->ns = NULL;
1090 
1091 	intern->std.handlers = &dom_nnodemap_object_handlers;
1092 
1093 	return &intern->std;
1094 }
1095 /* }}} */
1096 
php_dom_create_iterator(zval * return_value,int ce_type)1097 void php_dom_create_iterator(zval *return_value, int ce_type) /* {{{ */
1098 {
1099 	zend_class_entry *ce;
1100 
1101 	if (ce_type == DOM_NAMEDNODEMAP) {
1102 		ce = dom_namednodemap_class_entry;
1103 	} else {
1104 		ce = dom_nodelist_class_entry;
1105 	}
1106 
1107 	object_init_ex(return_value, ce);
1108 }
1109 /* }}} */
1110 
1111 /* {{{ php_dom_create_object */
php_dom_create_object(xmlNodePtr obj,zval * return_value,dom_object * domobj)1112 PHP_DOM_EXPORT bool php_dom_create_object(xmlNodePtr obj, zval *return_value, dom_object *domobj)
1113 {
1114 	zend_class_entry *ce;
1115 	dom_object *intern;
1116 
1117 	if (!obj) {
1118 		ZVAL_NULL(return_value);
1119 		return 0;
1120 	}
1121 
1122 	if ((intern = (dom_object *) php_dom_object_get_data((void *) obj))) {
1123 		ZVAL_OBJ_COPY(return_value, &intern->std);
1124 		return 1;
1125 	}
1126 
1127 	switch (obj->type) {
1128 		case XML_DOCUMENT_NODE:
1129 		case XML_HTML_DOCUMENT_NODE:
1130 		{
1131 			ce = dom_document_class_entry;
1132 			break;
1133 		}
1134 		case XML_DTD_NODE:
1135 		case XML_DOCUMENT_TYPE_NODE:
1136 		{
1137 			ce = dom_documenttype_class_entry;
1138 			break;
1139 		}
1140 		case XML_ELEMENT_NODE:
1141 		{
1142 			ce = dom_element_class_entry;
1143 			break;
1144 		}
1145 		case XML_ATTRIBUTE_NODE:
1146 		{
1147 			ce = dom_attr_class_entry;
1148 			break;
1149 		}
1150 		case XML_TEXT_NODE:
1151 		{
1152 			ce = dom_text_class_entry;
1153 			break;
1154 		}
1155 		case XML_COMMENT_NODE:
1156 		{
1157 			ce = dom_comment_class_entry;
1158 			break;
1159 		}
1160 		case XML_PI_NODE:
1161 		{
1162 			ce = dom_processinginstruction_class_entry;
1163 			break;
1164 		}
1165 		case XML_ENTITY_REF_NODE:
1166 		{
1167 			ce = dom_entityreference_class_entry;
1168 			break;
1169 		}
1170 		case XML_ENTITY_DECL:
1171 		case XML_ELEMENT_DECL:
1172 		{
1173 			ce = dom_entity_class_entry;
1174 			break;
1175 		}
1176 		case XML_CDATA_SECTION_NODE:
1177 		{
1178 			ce = dom_cdatasection_class_entry;
1179 			break;
1180 		}
1181 		case XML_DOCUMENT_FRAG_NODE:
1182 		{
1183 			ce = dom_documentfragment_class_entry;
1184 			break;
1185 		}
1186 		case XML_NOTATION_NODE:
1187 		{
1188 			ce = dom_notation_class_entry;
1189 			break;
1190 		}
1191 		case XML_NAMESPACE_DECL:
1192 		{
1193 			ce = dom_namespace_node_class_entry;
1194 			break;
1195 		}
1196 		default:
1197 			/* TODO Convert to a ZEND assertion? */
1198 			zend_throw_error(NULL, "Unsupported node type: %d", obj->type);
1199 			ZVAL_NULL(return_value);
1200 			return 0;
1201 	}
1202 
1203 	if (domobj && domobj->document) {
1204 		ce = dom_get_doc_classmap(domobj->document, ce);
1205 	}
1206 	object_init_ex(return_value, ce);
1207 
1208 	intern = Z_DOMOBJ_P(return_value);
1209 	if (obj->doc != NULL) {
1210 		if (domobj != NULL) {
1211 			intern->document = domobj->document;
1212 		}
1213 		php_libxml_increment_doc_ref((php_libxml_node_object *)intern, obj->doc);
1214 	}
1215 
1216 	php_libxml_increment_node_ptr((php_libxml_node_object *)intern, obj, (void *)intern);
1217 	return 0;
1218 }
1219 /* }}} end php_domobject_new */
1220 
php_dom_create_implementation(zval * retval)1221 void php_dom_create_implementation(zval *retval) {
1222 	object_init_ex(retval, dom_domimplementation_class_entry);
1223 }
1224 
1225 /* {{{ int dom_hierarchy(xmlNodePtr parent, xmlNodePtr child) */
dom_hierarchy(xmlNodePtr parent,xmlNodePtr child)1226 int dom_hierarchy(xmlNodePtr parent, xmlNodePtr child)
1227 {
1228 	xmlNodePtr nodep;
1229 
1230 	if (parent == NULL || child == NULL || child->doc != parent->doc) {
1231 		return SUCCESS;
1232 	}
1233 
1234 	if (child->type == XML_DOCUMENT_NODE) {
1235 		return FAILURE;
1236 	}
1237 
1238 	nodep = parent;
1239 
1240 	while (nodep) {
1241 		if (nodep == child) {
1242 			return FAILURE;
1243 		}
1244 		nodep = nodep->parent;
1245 	}
1246 
1247 	return SUCCESS;
1248 }
1249 /* }}} end dom_hierarchy */
1250 
1251 /* {{{ */
dom_has_feature(zend_string * feature,zend_string * version)1252 bool dom_has_feature(zend_string *feature, zend_string *version)
1253 {
1254 	if (zend_string_equals_literal(version, "1.0")
1255 		|| zend_string_equals_literal(version, "2.0")
1256 		|| zend_string_equals_literal(version, "")
1257 	) {
1258 		if (zend_string_equals_literal_ci(feature, "XML")
1259 			|| (zend_string_equals_literal_ci(feature, "Core") && zend_string_equals_literal(version, "1.0"))
1260 		) {
1261 			return true;
1262 		}
1263 	}
1264 
1265 	return false;
1266 }
1267 /* }}} end dom_has_feature */
1268 
dom_get_elements_by_tag_name_ns_raw(xmlNodePtr nodep,char * ns,char * local,int * cur,int index)1269 xmlNode *dom_get_elements_by_tag_name_ns_raw(xmlNodePtr nodep, char *ns, char *local, int *cur, int index) /* {{{ */
1270 {
1271 	xmlNodePtr ret = NULL;
1272 
1273 	while (nodep != NULL && (*cur <= index || index == -1)) {
1274 		if (nodep->type == XML_ELEMENT_NODE) {
1275 			if (xmlStrEqual(nodep->name, (xmlChar *)local) || xmlStrEqual((xmlChar *)"*", (xmlChar *)local)) {
1276 				if (ns == NULL || (!strcmp(ns, "") && nodep->ns == NULL) || (nodep->ns != NULL && (xmlStrEqual(nodep->ns->href, (xmlChar *)ns) || xmlStrEqual((xmlChar *)"*", (xmlChar *)ns)))) {
1277 					if (*cur == index) {
1278 						ret = nodep;
1279 						break;
1280 					}
1281 					(*cur)++;
1282 				}
1283 			}
1284 			ret = dom_get_elements_by_tag_name_ns_raw(nodep->children, ns, local, cur, index);
1285 			if (ret != NULL) {
1286 				break;
1287 			}
1288 		}
1289 		nodep = nodep->next;
1290 	}
1291 	return ret;
1292 }
1293 /* }}} */
1294 /* }}} end dom_element_get_elements_by_tag_name_ns_raw */
1295 
is_empty_node(xmlNodePtr nodep)1296 static inline bool is_empty_node(xmlNodePtr nodep)
1297 {
1298 	xmlChar	*strContent = xmlNodeGetContent(nodep);
1299 	bool ret = strContent == NULL || *strContent == '\0';
1300 	xmlFree(strContent);
1301 	return ret;
1302 }
1303 
1304 /* {{{ void dom_normalize (xmlNodePtr nodep) */
dom_normalize(xmlNodePtr nodep)1305 void dom_normalize (xmlNodePtr nodep)
1306 {
1307 	xmlNodePtr child, nextp, newnextp;
1308 	xmlAttrPtr attr;
1309 	xmlChar	*strContent;
1310 
1311 	child = nodep->children;
1312 	while(child != NULL) {
1313 		switch (child->type) {
1314 			case XML_TEXT_NODE:
1315 				nextp = child->next;
1316 				while (nextp != NULL) {
1317 					if (nextp->type == XML_TEXT_NODE) {
1318 						newnextp = nextp->next;
1319 						strContent = xmlNodeGetContent(nextp);
1320 						xmlNodeAddContent(child, strContent);
1321 						xmlFree(strContent);
1322 						xmlUnlinkNode(nextp);
1323 						php_libxml_node_free_resource(nextp);
1324 						nextp = newnextp;
1325 					} else {
1326 						break;
1327 					}
1328 				}
1329 				if (is_empty_node(child)) {
1330 					nextp = child->next;
1331 					xmlUnlinkNode(child);
1332 					php_libxml_node_free_resource(child);
1333 					child = nextp;
1334 					continue;
1335 				}
1336 				break;
1337 			case XML_ELEMENT_NODE:
1338 				dom_normalize (child);
1339 				attr = child->properties;
1340 				while (attr != NULL) {
1341 					dom_normalize((xmlNodePtr) attr);
1342 					attr = attr->next;
1343 				}
1344 				break;
1345 			case XML_ATTRIBUTE_NODE:
1346 				dom_normalize (child);
1347 				break;
1348 			default:
1349 				break;
1350 		}
1351 		child = child->next;
1352 	}
1353 }
1354 /* }}} end dom_normalize */
1355 
1356 
1357 /* {{{ void dom_set_old_ns(xmlDoc *doc, xmlNs *ns) */
dom_set_old_ns(xmlDoc * doc,xmlNs * ns)1358 void dom_set_old_ns(xmlDoc *doc, xmlNs *ns) {
1359 	xmlNs *cur;
1360 
1361 	if (doc == NULL)
1362 		return;
1363 
1364 	if (doc->oldNs == NULL) {
1365 		doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1366 		if (doc->oldNs == NULL) {
1367 			return;
1368 		}
1369 		memset(doc->oldNs, 0, sizeof(xmlNs));
1370 		doc->oldNs->type = XML_LOCAL_NAMESPACE;
1371 		doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
1372 		doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
1373 	}
1374 
1375 	cur = doc->oldNs;
1376 	while (cur->next != NULL) {
1377 		cur = cur->next;
1378 	}
1379 	cur->next = ns;
1380 }
1381 /* }}} end dom_set_old_ns */
1382 
dom_reconcile_ns(xmlDocPtr doc,xmlNodePtr nodep)1383 void dom_reconcile_ns(xmlDocPtr doc, xmlNodePtr nodep) /* {{{ */
1384 {
1385 	xmlNsPtr nsptr, nsdftptr, curns, prevns = NULL;
1386 
1387 	if (nodep->type == XML_ELEMENT_NODE) {
1388 		/* Following if block primarily used for inserting nodes created via createElementNS */
1389 		if (nodep->nsDef != NULL) {
1390 			curns = nodep->nsDef;
1391 			while (curns) {
1392 				nsdftptr = curns->next;
1393 				if (curns->href != NULL) {
1394 					if((nsptr = xmlSearchNsByHref(doc, nodep->parent, curns->href)) &&
1395 						(curns->prefix == NULL || xmlStrEqual(nsptr->prefix, curns->prefix))) {
1396 						curns->next = NULL;
1397 						if (prevns == NULL) {
1398 							nodep->nsDef = nsdftptr;
1399 						} else {
1400 							prevns->next = nsdftptr;
1401 						}
1402 						dom_set_old_ns(doc, curns);
1403 						curns = prevns;
1404 					}
1405 				}
1406 				prevns = curns;
1407 				curns = nsdftptr;
1408 			}
1409 		}
1410 		xmlReconciliateNs(doc, nodep);
1411 	}
1412 }
1413 /* }}} */
1414 
1415 /*
1416 http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#ID-DocCrElNS
1417 
1418 NAMESPACE_ERR: Raised if
1419 
1420 1. the qualifiedName is a malformed qualified name
1421 2. the qualifiedName has a prefix and the  namespaceURI is null
1422 */
1423 
1424 /* {{{ int dom_check_qname(char *qname, char **localname, char **prefix, int uri_len, int name_len) */
dom_check_qname(char * qname,char ** localname,char ** prefix,int uri_len,int name_len)1425 int dom_check_qname(char *qname, char **localname, char **prefix, int uri_len, int name_len) {
1426 	if (name_len == 0) {
1427 		return NAMESPACE_ERR;
1428 	}
1429 
1430 	*localname = (char *)xmlSplitQName2((xmlChar *)qname, (xmlChar **) prefix);
1431 	if (*localname == NULL) {
1432 		*localname = (char *)xmlStrdup((xmlChar *)qname);
1433 		if (*prefix == NULL && uri_len == 0) {
1434 			return 0;
1435 		}
1436 	}
1437 
1438 	/* 1 */
1439 	if (xmlValidateQName((xmlChar *) qname, 0) != 0) {
1440 		return NAMESPACE_ERR;
1441 	}
1442 
1443 	/* 2 */
1444 	if (*prefix != NULL && uri_len == 0) {
1445 		return NAMESPACE_ERR;
1446 	}
1447 
1448 	return 0;
1449 }
1450 /* }}} */
1451 
1452 /*
1453 http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#ID-DocCrElNS
1454 
1455 NAMESPACE_ERR: Raised if
1456 
1457 3. the qualifiedName has a prefix that is "xml" and the namespaceURI is different from "http://www.w3.org/XML/1998/namespace" [XML Namespaces]
1458 4. the qualifiedName or its prefix is "xmlns" and the namespaceURI is different from  "http://www.w3.org/2000/xmlns/"
1459 5. the namespaceURI is "http://www.w3.org/2000/xmlns/" and neither the	qualifiedName nor its prefix is "xmlns".
1460 */
1461 
1462 /* {{{ xmlNsPtr dom_get_ns(xmlNodePtr nodep, char *uri, int *errorcode, char *prefix) */
dom_get_ns(xmlNodePtr nodep,char * uri,int * errorcode,char * prefix)1463 xmlNsPtr dom_get_ns(xmlNodePtr nodep, char *uri, int *errorcode, char *prefix) {
1464 	xmlNsPtr nsptr = NULL;
1465 
1466 	*errorcode = 0;
1467 
1468 	if (! ((prefix && !strcmp (prefix, "xml") && strcmp(uri, (char *)XML_XML_NAMESPACE)) ||
1469 		   (prefix && !strcmp (prefix, "xmlns") && strcmp(uri, (char *)DOM_XMLNS_NAMESPACE)) ||
1470 		   (prefix && !strcmp(uri, (char *)DOM_XMLNS_NAMESPACE) && strcmp (prefix, "xmlns")))) {
1471 		nsptr = xmlNewNs(nodep, (xmlChar *)uri, (xmlChar *)prefix);
1472 	}
1473 
1474 	if (nsptr == NULL) {
1475 		*errorcode = NAMESPACE_ERR;
1476 	}
1477 
1478 	return nsptr;
1479 
1480 }
1481 /* }}} end dom_get_ns */
1482 
1483 /* {{{ xmlNsPtr dom_get_nsdecl(xmlNode *node, xmlChar *localName) */
dom_get_nsdecl(xmlNode * node,xmlChar * localName)1484 xmlNsPtr dom_get_nsdecl(xmlNode *node, xmlChar *localName) {
1485 	xmlNsPtr cur;
1486 	xmlNs *ret = NULL;
1487 	if (node == NULL)
1488 		return NULL;
1489 
1490 	if (localName == NULL || xmlStrEqual(localName, (xmlChar *)"")) {
1491 		cur = node->nsDef;
1492 		while (cur != NULL) {
1493 			if (cur->prefix == NULL  && cur->href != NULL) {
1494 				ret = cur;
1495 				break;
1496 			}
1497 			cur = cur->next;
1498 		}
1499 	} else {
1500 		cur = node->nsDef;
1501 		while (cur != NULL) {
1502 			if (cur->prefix != NULL && xmlStrEqual(localName, cur->prefix)) {
1503 				ret = cur;
1504 				break;
1505 			}
1506 			cur = cur->next;
1507 		}
1508 	}
1509 	return ret;
1510 }
1511 /* }}} end dom_get_nsdecl */
1512 
dom_nodelist_read_dimension(zend_object * object,zval * offset,int type,zval * rv)1513 static zval *dom_nodelist_read_dimension(zend_object *object, zval *offset, int type, zval *rv) /* {{{ */
1514 {
1515 	zval offset_copy;
1516 
1517 	if (!offset) {
1518 		zend_throw_error(NULL, "Cannot access node list without offset");
1519 		return NULL;
1520 	}
1521 
1522 	ZVAL_LONG(&offset_copy, zval_get_long(offset));
1523 
1524 	zend_call_method_with_1_params(object, object->ce, NULL, "item", rv, &offset_copy);
1525 
1526 	return rv;
1527 } /* }}} end dom_nodelist_read_dimension */
1528 
dom_nodelist_has_dimension(zend_object * object,zval * member,int check_empty)1529 static int dom_nodelist_has_dimension(zend_object *object, zval *member, int check_empty)
1530 {
1531 	zend_long offset = zval_get_long(member);
1532 	zval rv;
1533 
1534 	if (offset < 0) {
1535 		return 0;
1536 	} else {
1537 		zval *length = zend_read_property(
1538 			object->ce, object, "length", sizeof("length") - 1, 0, &rv);
1539 		return length && offset < Z_LVAL_P(length);
1540 	}
1541 } /* }}} end dom_nodelist_has_dimension */
1542 
1543 #endif /* HAVE_DOM */
1544