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