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