1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2018 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Sterling Hughes <sterling@php.net> |
16 | Marcus Boerger <helly@php.net> |
17 | Rob Richards <rrichards@php.net> |
18 +----------------------------------------------------------------------+
19 */
20
21 /* $Id: 341daed0ee94ea8f728bfd0ba4626e6ed365c0d1 $ */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "php.h"
28 #if HAVE_LIBXML && HAVE_SIMPLEXML
29
30 #include "php_ini.h"
31 #include "ext/standard/info.h"
32 #include "ext/standard/php_string.h"
33 #include "php_simplexml.h"
34 #include "php_simplexml_exports.h"
35 #include "zend_exceptions.h"
36 #include "zend_interfaces.h"
37 #include "sxe.h"
38
39 zend_class_entry *sxe_class_entry = NULL;
40
sxe_get_element_class_entry()41 PHP_SXE_API zend_class_entry *sxe_get_element_class_entry() /* {{{ */
42 {
43 return sxe_class_entry;
44 }
45 /* }}} */
46
47 #define SXE_ME(func, arg_info, flags) PHP_ME(simplexml_element, func, arg_info, flags)
48 #define SXE_MALIAS(func, alias, arg_info, flags) PHP_MALIAS(simplexml_element, func, alias, arg_info, flags)
49
50 #define SXE_METHOD(func) PHP_METHOD(simplexml_element, func)
51
52 static php_sxe_object* php_sxe_object_new(zend_class_entry *ce, zend_function *fptr_count);
53 static xmlNodePtr php_sxe_reset_iterator(php_sxe_object *sxe, int use_data);
54 static xmlNodePtr php_sxe_iterator_fetch(php_sxe_object *sxe, xmlNodePtr node, int use_data);
55 static zval *sxe_get_value(zval *z, zval *rv);
56 static void php_sxe_iterator_dtor(zend_object_iterator *iter);
57 static int php_sxe_iterator_valid(zend_object_iterator *iter);
58 static zval *php_sxe_iterator_current_data(zend_object_iterator *iter);
59 static void php_sxe_iterator_current_key(zend_object_iterator *iter, zval *key);
60 static void php_sxe_iterator_move_forward(zend_object_iterator *iter);
61 static void php_sxe_iterator_rewind(zend_object_iterator *iter);
62
63 /* {{{ _node_as_zval()
64 */
_node_as_zval(php_sxe_object * sxe,xmlNodePtr node,zval * value,SXE_ITER itertype,char * name,const xmlChar * nsprefix,int isprefix)65 static void _node_as_zval(php_sxe_object *sxe, xmlNodePtr node, zval *value, SXE_ITER itertype, char *name, const xmlChar *nsprefix, int isprefix)
66 {
67 php_sxe_object *subnode;
68
69 subnode = php_sxe_object_new(sxe->zo.ce, sxe->fptr_count);
70 subnode->document = sxe->document;
71 subnode->document->refcount++;
72 subnode->iter.type = itertype;
73 if (name) {
74 subnode->iter.name = (xmlChar*)estrdup(name);
75 }
76 if (nsprefix && *nsprefix) {
77 subnode->iter.nsprefix = (xmlChar*)estrdup((char*)nsprefix);
78 subnode->iter.isprefix = isprefix;
79 }
80
81 php_libxml_increment_node_ptr((php_libxml_node_object *)subnode, node, NULL);
82
83 ZVAL_OBJ(value, &subnode->zo);
84 }
85 /* }}} */
86
87 #define GET_NODE(__s, __n) { \
88 if ((__s)->node && (__s)->node->node) { \
89 __n = (__s)->node->node; \
90 } else { \
91 __n = NULL; \
92 php_error_docref(NULL, E_WARNING, "Node no longer exists"); \
93 } \
94 }
95
php_sxe_get_first_node(php_sxe_object * sxe,xmlNodePtr node)96 static xmlNodePtr php_sxe_get_first_node(php_sxe_object *sxe, xmlNodePtr node) /* {{{ */
97 {
98 php_sxe_object *intern;
99 xmlNodePtr retnode = NULL;
100
101 if (sxe && sxe->iter.type != SXE_ITER_NONE) {
102 php_sxe_reset_iterator(sxe, 1);
103 if (!Z_ISUNDEF(sxe->iter.data)) {
104 intern = Z_SXEOBJ_P(&sxe->iter.data);
105 GET_NODE(intern, retnode)
106 }
107 return retnode;
108 } else {
109 return node;
110 }
111 }
112 /* }}} */
113
match_ns(php_sxe_object * sxe,xmlNodePtr node,xmlChar * name,int prefix)114 static inline int match_ns(php_sxe_object *sxe, xmlNodePtr node, xmlChar *name, int prefix) /* {{{ */
115 {
116 if (name == NULL && (node->ns == NULL || node->ns->prefix == NULL)) {
117 return 1;
118 }
119
120 if (node->ns && !xmlStrcmp(prefix ? node->ns->prefix : node->ns->href, name)) {
121 return 1;
122 }
123
124 return 0;
125 }
126 /* }}} */
127
sxe_get_element_by_offset(php_sxe_object * sxe,zend_long offset,xmlNodePtr node,zend_long * cnt)128 static xmlNodePtr sxe_get_element_by_offset(php_sxe_object *sxe, zend_long offset, xmlNodePtr node, zend_long *cnt) /* {{{ */
129 {
130 zend_long nodendx = 0;
131
132 if (sxe->iter.type == SXE_ITER_NONE) {
133 if (offset == 0) {
134 if (cnt) {
135 *cnt = 0;
136 }
137 return node;
138 } else {
139 return NULL;
140 }
141 }
142 while (node && nodendx <= offset) {
143 SKIP_TEXT(node)
144 if (node->type == XML_ELEMENT_NODE && match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix)) {
145 if (sxe->iter.type == SXE_ITER_CHILD || (
146 sxe->iter.type == SXE_ITER_ELEMENT && !xmlStrcmp(node->name, sxe->iter.name))) {
147 if (nodendx == offset) {
148 break;
149 }
150 nodendx++;
151 }
152 }
153 next_iter:
154 node = node->next;
155 }
156
157 if (cnt) {
158 *cnt = nodendx;
159 }
160
161 return node;
162 }
163 /* }}} */
164
sxe_find_element_by_name(php_sxe_object * sxe,xmlNodePtr node,xmlChar * name)165 static xmlNodePtr sxe_find_element_by_name(php_sxe_object *sxe, xmlNodePtr node, xmlChar *name) /* {{{ */
166 {
167 while (node) {
168 SKIP_TEXT(node)
169 if (node->type == XML_ELEMENT_NODE && match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix)) {
170 if (!xmlStrcmp(node->name, name)) {
171 return node;
172 }
173 }
174 next_iter:
175 node = node->next;
176 }
177 return NULL;
178 } /* }}} */
179
sxe_get_element_by_name(php_sxe_object * sxe,xmlNodePtr node,char ** name,SXE_ITER * type)180 static xmlNodePtr sxe_get_element_by_name(php_sxe_object *sxe, xmlNodePtr node, char **name, SXE_ITER *type) /* {{{ */
181 {
182 int orgtype;
183 xmlNodePtr orgnode = node;
184 xmlNodePtr retnode = NULL;
185
186 if (sxe->iter.type != SXE_ITER_ATTRLIST)
187 {
188 orgtype = sxe->iter.type;
189 if (sxe->iter.type == SXE_ITER_NONE) {
190 sxe->iter.type = SXE_ITER_CHILD;
191 }
192 node = php_sxe_get_first_node(sxe, node);
193 sxe->iter.type = orgtype;
194 }
195
196 if (sxe->iter.type == SXE_ITER_ELEMENT) {
197 orgnode = sxe_find_element_by_name(sxe, node, sxe->iter.name);
198 if (!orgnode) {
199 return NULL;
200 }
201 node = orgnode->children;
202 }
203
204 while (node) {
205 SKIP_TEXT(node)
206 if (node->type == XML_ELEMENT_NODE && match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix)) {
207 if (!xmlStrcmp(node->name, (xmlChar *)*name)) {
208 if (1||retnode)
209 {
210 *type = SXE_ITER_ELEMENT;
211 return orgnode;
212 }
213 retnode = node;
214 }
215 }
216 next_iter:
217 node = node->next;
218 }
219
220 if (retnode)
221 {
222 *type = SXE_ITER_NONE;
223 *name = NULL;
224 return retnode;
225 }
226
227 return NULL;
228 }
229 /* }}} */
230
231 /* {{{ sxe_prop_dim_read()
232 */
sxe_prop_dim_read(zval * object,zval * member,zend_bool elements,zend_bool attribs,int type,zval * rv)233 static zval *sxe_prop_dim_read(zval *object, zval *member, zend_bool elements, zend_bool attribs, int type, zval *rv)
234 {
235 php_sxe_object *sxe;
236 char *name;
237 xmlNodePtr node;
238 xmlAttrPtr attr = NULL;
239 zval tmp_zv;
240 int nodendx = 0;
241 int test = 0;
242
243 sxe = Z_SXEOBJ_P(object);
244
245 if (!member) {
246 if (sxe->iter.type == SXE_ITER_ATTRLIST) {
247 /* This happens when the user did: $sxe[]->foo = $value */
248 zend_throw_error(NULL, "Cannot create unnamed attribute");
249 return &EG(uninitialized_zval);
250 }
251 goto long_dim;
252 } else {
253 ZVAL_DEREF(member);
254 if (Z_TYPE_P(member) == IS_LONG) {
255 if (sxe->iter.type != SXE_ITER_ATTRLIST) {
256 long_dim:
257 attribs = 0;
258 elements = 1;
259 }
260 name = NULL;
261 } else {
262 if (Z_TYPE_P(member) != IS_STRING) {
263 ZVAL_STR(&tmp_zv, zval_get_string(member));
264 member = &tmp_zv;
265 }
266 name = Z_STRVAL_P(member);
267 }
268 }
269
270 GET_NODE(sxe, node);
271
272 if (sxe->iter.type == SXE_ITER_ATTRLIST) {
273 attribs = 1;
274 elements = 0;
275 node = php_sxe_get_first_node(sxe, node);
276 attr = (xmlAttrPtr)node;
277 test = sxe->iter.name != NULL;
278 } else if (sxe->iter.type != SXE_ITER_CHILD) {
279 node = php_sxe_get_first_node(sxe, node);
280 attr = node ? node->properties : NULL;
281 test = 0;
282 if (!member && node && node->parent &&
283 node->parent->type == XML_DOCUMENT_NODE) {
284 /* This happens when the user did: $sxe[]->foo = $value */
285 zend_throw_error(NULL, "Cannot create unnamed attribute");
286 return &EG(uninitialized_zval);
287 }
288 }
289
290 ZVAL_UNDEF(rv);
291
292 if (node) {
293 if (attribs) {
294 if (Z_TYPE_P(member) != IS_LONG || sxe->iter.type == SXE_ITER_ATTRLIST) {
295 if (Z_TYPE_P(member) == IS_LONG) {
296 while (attr && nodendx <= Z_LVAL_P(member)) {
297 if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
298 if (nodendx == Z_LVAL_P(member)) {
299 _node_as_zval(sxe, (xmlNodePtr) attr, rv, SXE_ITER_NONE, NULL, sxe->iter.nsprefix, sxe->iter.isprefix);
300 break;
301 }
302 nodendx++;
303 }
304 attr = attr->next;
305 }
306 } else {
307 while (attr) {
308 if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && !xmlStrcmp(attr->name, (xmlChar *)name) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
309 _node_as_zval(sxe, (xmlNodePtr) attr, rv, SXE_ITER_NONE, NULL, sxe->iter.nsprefix, sxe->iter.isprefix);
310 break;
311 }
312 attr = attr->next;
313 }
314 }
315 }
316 }
317
318 if (elements) {
319 if (!sxe->node) {
320 php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, node, NULL);
321 }
322 if (!member || Z_TYPE_P(member) == IS_LONG) {
323 zend_long cnt = 0;
324 xmlNodePtr mynode = node;
325
326 if (sxe->iter.type == SXE_ITER_CHILD) {
327 node = php_sxe_get_first_node(sxe, node);
328 }
329 if (sxe->iter.type == SXE_ITER_NONE) {
330 if (member && Z_LVAL_P(member) > 0) {
331 php_error_docref(NULL, E_WARNING, "Cannot add element %s number " ZEND_LONG_FMT " when only 0 such elements exist", mynode->name, Z_LVAL_P(member));
332 }
333 } else if (member) {
334 node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, &cnt);
335 } else {
336 node = NULL;
337 }
338 if (node) {
339 _node_as_zval(sxe, node, rv, SXE_ITER_NONE, NULL, sxe->iter.nsprefix, sxe->iter.isprefix);
340 } else if (type == BP_VAR_W || type == BP_VAR_RW) {
341 if (member && cnt < Z_LVAL_P(member)) {
342 php_error_docref(NULL, E_WARNING, "Cannot add element %s number " ZEND_LONG_FMT " when only " ZEND_LONG_FMT " such elements exist", mynode->name, Z_LVAL_P(member), cnt);
343 }
344 node = xmlNewTextChild(mynode->parent, mynode->ns, mynode->name, NULL);
345 _node_as_zval(sxe, node, rv, SXE_ITER_NONE, NULL, sxe->iter.nsprefix, sxe->iter.isprefix);
346 }
347 } else {
348 /* In BP_VAR_IS mode only return a proper node if it actually exists. */
349 if (type != BP_VAR_IS || sxe_find_element_by_name(sxe, node->children, (xmlChar *) name)) {
350 _node_as_zval(sxe, node, rv, SXE_ITER_ELEMENT, name, sxe->iter.nsprefix, sxe->iter.isprefix);
351 }
352 }
353 }
354 }
355
356 if (member == &tmp_zv) {
357 zval_dtor(&tmp_zv);
358 }
359
360 if (Z_ISUNDEF_P(rv)) {
361 ZVAL_COPY_VALUE(rv, &EG(uninitialized_zval));
362 }
363
364 return rv;
365 }
366 /* }}} */
367
368 /* {{{ sxe_property_read()
369 */
sxe_property_read(zval * object,zval * member,int type,void ** cache_slot,zval * rv)370 static zval *sxe_property_read(zval *object, zval *member, int type, void **cache_slot, zval *rv)
371 {
372 return sxe_prop_dim_read(object, member, 1, 0, type, rv);
373 }
374 /* }}} */
375
376 /* {{{ sxe_dimension_read()
377 */
sxe_dimension_read(zval * object,zval * offset,int type,zval * rv)378 static zval *sxe_dimension_read(zval *object, zval *offset, int type, zval *rv)
379 {
380 return sxe_prop_dim_read(object, offset, 0, 1, type, rv);
381 }
382 /* }}} */
383
384 /* {{{ change_node_zval()
385 */
change_node_zval(xmlNodePtr node,zval * value)386 static void change_node_zval(xmlNodePtr node, zval *value)
387 {
388 zval value_copy;
389 xmlChar *buffer;
390 int buffer_len;
391
392 if (!value)
393 {
394 xmlNodeSetContentLen(node, (xmlChar *)"", 0);
395 return;
396 }
397 switch (Z_TYPE_P(value)) {
398 case IS_LONG:
399 case IS_FALSE:
400 case IS_TRUE:
401 case IS_DOUBLE:
402 case IS_NULL:
403 if (Z_REFCOUNT_P(value) > 1) {
404 value_copy = *value;
405 zval_copy_ctor(&value_copy);
406 value = &value_copy;
407 }
408 convert_to_string(value);
409 /* break missing intentionally */
410 case IS_STRING:
411 buffer = xmlEncodeEntitiesReentrant(node->doc, (xmlChar *)Z_STRVAL_P(value));
412 buffer_len = xmlStrlen(buffer);
413 /* check for NULL buffer in case of memory error in xmlEncodeEntitiesReentrant */
414 if (buffer) {
415 xmlNodeSetContentLen(node, buffer, buffer_len);
416 xmlFree(buffer);
417 }
418 if (value == &value_copy) {
419 zval_dtor(value);
420 }
421 break;
422 default:
423 php_error_docref(NULL, E_WARNING, "It is not possible to assign complex types to nodes");
424 break;
425 }
426 }
427 /* }}} */
428
429 /* {{{ sxe_property_write()
430 */
sxe_prop_dim_write(zval * object,zval * member,zval * value,zend_bool elements,zend_bool attribs,xmlNodePtr * pnewnode)431 static int sxe_prop_dim_write(zval *object, zval *member, zval *value, zend_bool elements, zend_bool attribs, xmlNodePtr *pnewnode)
432 {
433 php_sxe_object *sxe;
434 xmlNodePtr node;
435 xmlNodePtr newnode = NULL;
436 xmlNodePtr mynode;
437 xmlNodePtr tempnode;
438 xmlAttrPtr attr = NULL;
439 int counter = 0;
440 int is_attr = 0;
441 int nodendx = 0;
442 int test = 0;
443 int new_value = 0;
444 zend_long cnt = 0;
445 int retval = SUCCESS;
446 zval tmp_zv, zval_copy;
447 zend_string *trim_str;
448
449 sxe = Z_SXEOBJ_P(object);
450
451 if (!member) {
452 if (sxe->iter.type == SXE_ITER_ATTRLIST) {
453 /* This happens when the user did: $sxe[] = $value
454 * and could also be E_PARSE, but we use this only during parsing
455 * and this is during runtime.
456 */
457 zend_throw_error(NULL, "Cannot create unnamed attribute");
458 return FAILURE;
459 }
460 goto long_dim;
461 } else {
462 ZVAL_DEREF(member);
463 if (Z_TYPE_P(member) == IS_LONG) {
464 if (sxe->iter.type != SXE_ITER_ATTRLIST) {
465 long_dim:
466 attribs = 0;
467 elements = 1;
468 }
469 } else {
470 if (Z_TYPE_P(member) != IS_STRING) {
471 trim_str = zval_get_string(member);
472 ZVAL_STR(&tmp_zv, php_trim(trim_str, NULL, 0, 3));
473 zend_string_release(trim_str);
474 member = &tmp_zv;
475 }
476
477 if (!Z_STRLEN_P(member)) {
478 php_error_docref(NULL, E_WARNING, "Cannot write or create unnamed %s", attribs ? "attribute" : "element");
479 if (member == &tmp_zv) {
480 zval_dtor(&tmp_zv);
481 }
482 return FAILURE;
483 }
484 }
485 }
486
487 GET_NODE(sxe, node);
488
489 if (sxe->iter.type == SXE_ITER_ATTRLIST) {
490 attribs = 1;
491 elements = 0;
492 node = php_sxe_get_first_node(sxe, node);
493 attr = (xmlAttrPtr)node;
494 test = sxe->iter.name != NULL;
495 } else if (sxe->iter.type != SXE_ITER_CHILD) {
496 mynode = node;
497 node = php_sxe_get_first_node(sxe, node);
498 attr = node ? node->properties : NULL;
499 test = 0;
500 if (!member && node && node->parent &&
501 node->parent->type == XML_DOCUMENT_NODE) {
502 /* This happens when the user did: $sxe[] = $value
503 * and could also be E_PARSE, but we use this only during parsing
504 * and this is during runtime.
505 */
506 zend_throw_error(NULL, "Cannot create unnamed attribute");
507 return FAILURE;
508 }
509 if (attribs && !node && sxe->iter.type == SXE_ITER_ELEMENT) {
510 node = xmlNewChild(mynode, mynode->ns, sxe->iter.name, NULL);
511 attr = node->properties;
512 }
513 }
514
515 mynode = node;
516
517 if (value) {
518 switch (Z_TYPE_P(value)) {
519 case IS_LONG:
520 case IS_FALSE:
521 case IS_TRUE:
522 case IS_DOUBLE:
523 case IS_NULL:
524 if (Z_TYPE_P(value) != IS_STRING) {
525 ZVAL_COPY(&zval_copy, value);
526 value = &zval_copy;
527 convert_to_string(value);
528 new_value = 1;
529 }
530 break;
531 case IS_STRING:
532 break;
533 case IS_OBJECT:
534 if (Z_OBJCE_P(value) == sxe_class_entry) {
535 value = sxe_get_value(value, &zval_copy);
536 new_value = 1;
537 break;
538 }
539 /* break is missing intentionally */
540 default:
541 if (member == &tmp_zv) {
542 zval_dtor(&tmp_zv);
543 }
544 zend_error(E_WARNING, "It is not yet possible to assign complex types to %s", attribs ? "attributes" : "properties");
545 return FAILURE;
546 }
547 }
548
549 if (node) {
550 if (attribs) {
551 if (Z_TYPE_P(member) == IS_LONG) {
552 while (attr && nodendx <= Z_LVAL_P(member)) {
553 if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
554 if (nodendx == Z_LVAL_P(member)) {
555 is_attr = 1;
556 ++counter;
557 break;
558 }
559 nodendx++;
560 }
561 attr = attr->next;
562 }
563 } else {
564 while (attr) {
565 if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && !xmlStrcmp(attr->name, (xmlChar *)Z_STRVAL_P(member)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
566 is_attr = 1;
567 ++counter;
568 break;
569 }
570 attr = attr->next;
571 }
572 }
573
574 }
575
576 if (elements) {
577 if (!member || Z_TYPE_P(member) == IS_LONG) {
578 if (node->type == XML_ATTRIBUTE_NODE) {
579 zend_throw_error(NULL, "Cannot create duplicate attribute");
580 if (new_value) {
581 zval_ptr_dtor(value);
582 }
583 return FAILURE;
584 }
585
586 if (sxe->iter.type == SXE_ITER_NONE) {
587 newnode = node;
588 ++counter;
589 if (member && Z_LVAL_P(member) > 0) {
590 php_error_docref(NULL, E_WARNING, "Cannot add element %s number " ZEND_LONG_FMT " when only 0 such elements exist", mynode->name, Z_LVAL_P(member));
591 retval = FAILURE;
592 }
593 } else if (member) {
594 newnode = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, &cnt);
595 if (newnode) {
596 ++counter;
597 }
598 }
599 } else {
600 node = node->children;
601 while (node) {
602 SKIP_TEXT(node);
603
604 if (!xmlStrcmp(node->name, (xmlChar *)Z_STRVAL_P(member)) && match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix)) {
605 newnode = node;
606 ++counter;
607 }
608
609 next_iter:
610 node = node->next;
611 }
612 }
613 }
614
615 if (counter == 1) {
616 if (is_attr) {
617 newnode = (xmlNodePtr) attr;
618 }
619 if (value) {
620 while ((tempnode = (xmlNodePtr) newnode->children)) {
621 xmlUnlinkNode(tempnode);
622 php_libxml_node_free_resource((xmlNodePtr) tempnode);
623 }
624 change_node_zval(newnode, value);
625 }
626 } else if (counter > 1) {
627 php_error_docref(NULL, E_WARNING, "Cannot assign to an array of nodes (duplicate subnodes or attr detected)");
628 retval = FAILURE;
629 } else if (elements) {
630 if (!node) {
631 if (!member || Z_TYPE_P(member) == IS_LONG) {
632 newnode = xmlNewTextChild(mynode->parent, mynode->ns, mynode->name, value ? (xmlChar *)Z_STRVAL_P(value) : NULL);
633 } else {
634 newnode = xmlNewTextChild(mynode, mynode->ns, (xmlChar *)Z_STRVAL_P(member), value ? (xmlChar *)Z_STRVAL_P(value) : NULL);
635 }
636 } else if (!member || Z_TYPE_P(member) == IS_LONG) {
637 if (member && cnt < Z_LVAL_P(member)) {
638 php_error_docref(NULL, E_WARNING, "Cannot add element %s number " ZEND_LONG_FMT " when only " ZEND_LONG_FMT " such elements exist", mynode->name, Z_LVAL_P(member), cnt);
639 retval = FAILURE;
640 }
641 newnode = xmlNewTextChild(mynode->parent, mynode->ns, mynode->name, value ? (xmlChar *)Z_STRVAL_P(value) : NULL);
642 }
643 } else if (attribs) {
644 if (Z_TYPE_P(member) == IS_LONG) {
645 php_error_docref(NULL, E_WARNING, "Cannot change attribute number " ZEND_LONG_FMT " when only %d attributes exist", Z_LVAL_P(member), nodendx);
646 retval = FAILURE;
647 } else {
648 newnode = (xmlNodePtr)xmlNewProp(node, (xmlChar *)Z_STRVAL_P(member), value ? (xmlChar *)Z_STRVAL_P(value) : NULL);
649 }
650 }
651 }
652
653 if (member == &tmp_zv) {
654 zval_dtor(&tmp_zv);
655 }
656 if (pnewnode) {
657 *pnewnode = newnode;
658 }
659 if (new_value) {
660 zval_ptr_dtor(value);
661 }
662 return retval;
663 }
664 /* }}} */
665
666 /* {{{ sxe_property_write()
667 */
sxe_property_write(zval * object,zval * member,zval * value,void ** cache_slot)668 static void sxe_property_write(zval *object, zval *member, zval *value, void **cache_slot)
669 {
670 sxe_prop_dim_write(object, member, value, 1, 0, NULL);
671 }
672 /* }}} */
673
674 /* {{{ sxe_dimension_write()
675 */
sxe_dimension_write(zval * object,zval * offset,zval * value)676 static void sxe_dimension_write(zval *object, zval *offset, zval *value)
677 {
678 sxe_prop_dim_write(object, offset, value, 0, 1, NULL);
679 }
680 /* }}} */
681
sxe_property_get_adr(zval * object,zval * member,int fetch_type,void ** cache_slot)682 static zval *sxe_property_get_adr(zval *object, zval *member, int fetch_type, void **cache_slot) /* {{{ */
683 {
684 php_sxe_object *sxe;
685 xmlNodePtr node;
686 zval ret;
687 char *name;
688 SXE_ITER type;
689
690 sxe = Z_SXEOBJ_P(object);
691
692 GET_NODE(sxe, node);
693 convert_to_string(member);
694 name = Z_STRVAL_P(member);
695 node = sxe_get_element_by_name(sxe, node, &name, &type);
696 if (node) {
697 return NULL;
698 }
699 if (sxe_prop_dim_write(object, member, NULL, 1, 0, &node) != SUCCESS) {
700 return NULL;
701 }
702 type = SXE_ITER_NONE;
703 name = NULL;
704
705 _node_as_zval(sxe, node, &ret, type, name, sxe->iter.nsprefix, sxe->iter.isprefix);
706
707 if (!Z_ISUNDEF(sxe->tmp)) {
708 zval_ptr_dtor(&sxe->tmp);
709 }
710
711 ZVAL_COPY_VALUE(&sxe->tmp, &ret);
712
713 return &sxe->tmp;
714 }
715 /* }}} */
716
717 /* {{{ sxe_prop_dim_exists()
718 */
sxe_prop_dim_exists(zval * object,zval * member,int check_empty,zend_bool elements,zend_bool attribs)719 static int sxe_prop_dim_exists(zval *object, zval *member, int check_empty, zend_bool elements, zend_bool attribs)
720 {
721 php_sxe_object *sxe;
722 xmlNodePtr node;
723 xmlAttrPtr attr = NULL;
724 int exists = 0;
725 int test = 0;
726 zval tmp_zv;
727
728 if (Z_TYPE_P(member) != IS_STRING && Z_TYPE_P(member) != IS_LONG) {
729 ZVAL_STR(&tmp_zv, zval_get_string(member));
730 member = &tmp_zv;
731 }
732
733 sxe = Z_SXEOBJ_P(object);
734
735 GET_NODE(sxe, node);
736
737 if (Z_TYPE_P(member) == IS_LONG) {
738 if (sxe->iter.type != SXE_ITER_ATTRLIST) {
739 attribs = 0;
740 elements = 1;
741 if (sxe->iter.type == SXE_ITER_CHILD) {
742 node = php_sxe_get_first_node(sxe, node);
743 }
744 }
745 }
746
747 if (sxe->iter.type == SXE_ITER_ATTRLIST) {
748 attribs = 1;
749 elements = 0;
750 node = php_sxe_get_first_node(sxe, node);
751 attr = (xmlAttrPtr)node;
752 test = sxe->iter.name != NULL;
753 } else if (sxe->iter.type != SXE_ITER_CHILD) {
754 node = php_sxe_get_first_node(sxe, node);
755 attr = node ? node->properties : NULL;
756 test = 0;
757 }
758
759 if (node) {
760 if (attribs) {
761 if (Z_TYPE_P(member) == IS_LONG) {
762 int nodendx = 0;
763
764 while (attr && nodendx <= Z_LVAL_P(member)) {
765 if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
766 if (nodendx == Z_LVAL_P(member)) {
767 exists = 1;
768 break;
769 }
770 nodendx++;
771 }
772 attr = attr->next;
773 }
774 } else {
775 while (attr) {
776 if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && !xmlStrcmp(attr->name, (xmlChar *)Z_STRVAL_P(member)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
777 exists = 1;
778 break;
779 }
780
781 attr = attr->next;
782 }
783 }
784 if (exists && check_empty == 1 &&
785 (!attr->children || !attr->children->content || !attr->children->content[0] || !xmlStrcmp(attr->children->content, (const xmlChar *) "0")) ) {
786 /* Attribute with no content in it's text node */
787 exists = 0;
788 }
789 }
790
791 if (elements) {
792 if (Z_TYPE_P(member) == IS_LONG) {
793 if (sxe->iter.type == SXE_ITER_CHILD) {
794 node = php_sxe_get_first_node(sxe, node);
795 }
796 node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, NULL);
797 } else {
798 node = sxe_find_element_by_name(sxe, node->children, (xmlChar *)Z_STRVAL_P(member));
799 }
800 if (node) {
801 exists = 1;
802 if (check_empty == 1 &&
803 (!node->children || (node->children->type == XML_TEXT_NODE && !node->children->next &&
804 (!node->children->content || !node->children->content[0] || !xmlStrcmp(node->children->content, (const xmlChar *) "0")))) ) {
805 exists = 0;
806 }
807 }
808 }
809 }
810
811 if (member == &tmp_zv) {
812 zval_dtor(&tmp_zv);
813 }
814
815 return exists;
816 }
817 /* }}} */
818
819 /* {{{ sxe_property_exists()
820 */
sxe_property_exists(zval * object,zval * member,int check_empty,void ** cache_slot)821 static int sxe_property_exists(zval *object, zval *member, int check_empty, void **cache_slot)
822 {
823 return sxe_prop_dim_exists(object, member, check_empty, 1, 0);
824 }
825 /* }}} */
826
827 /* {{{ sxe_dimension_exists()
828 */
sxe_dimension_exists(zval * object,zval * member,int check_empty)829 static int sxe_dimension_exists(zval *object, zval *member, int check_empty)
830 {
831 return sxe_prop_dim_exists(object, member, check_empty, 0, 1);
832 }
833 /* }}} */
834
835 /* {{{ sxe_prop_dim_delete()
836 */
sxe_prop_dim_delete(zval * object,zval * member,zend_bool elements,zend_bool attribs)837 static void sxe_prop_dim_delete(zval *object, zval *member, zend_bool elements, zend_bool attribs)
838 {
839 php_sxe_object *sxe;
840 xmlNodePtr node;
841 xmlNodePtr nnext;
842 xmlAttrPtr attr = NULL;
843 xmlAttrPtr anext;
844 zval tmp_zv;
845 int test = 0;
846
847 if (Z_TYPE_P(member) != IS_STRING && Z_TYPE_P(member) != IS_LONG) {
848 ZVAL_STR(&tmp_zv, zval_get_string(member));
849 member = &tmp_zv;
850 }
851
852 sxe = Z_SXEOBJ_P(object);
853
854 GET_NODE(sxe, node);
855
856 if (Z_TYPE_P(member) == IS_LONG) {
857 if (sxe->iter.type != SXE_ITER_ATTRLIST) {
858 attribs = 0;
859 elements = 1;
860 if (sxe->iter.type == SXE_ITER_CHILD) {
861 node = php_sxe_get_first_node(sxe, node);
862 }
863 }
864 }
865
866 if (sxe->iter.type == SXE_ITER_ATTRLIST) {
867 attribs = 1;
868 elements = 0;
869 node = php_sxe_get_first_node(sxe, node);
870 attr = (xmlAttrPtr)node;
871 test = sxe->iter.name != NULL;
872 } else if (sxe->iter.type != SXE_ITER_CHILD) {
873 node = php_sxe_get_first_node(sxe, node);
874 attr = node ? node->properties : NULL;
875 test = 0;
876 }
877
878 if (node) {
879 if (attribs) {
880 if (Z_TYPE_P(member) == IS_LONG) {
881 int nodendx = 0;
882
883 while (attr && nodendx <= Z_LVAL_P(member)) {
884 if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
885 if (nodendx == Z_LVAL_P(member)) {
886 xmlUnlinkNode((xmlNodePtr) attr);
887 php_libxml_node_free_resource((xmlNodePtr) attr);
888 break;
889 }
890 nodendx++;
891 }
892 attr = attr->next;
893 }
894 } else {
895 while (attr) {
896 anext = attr->next;
897 if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && !xmlStrcmp(attr->name, (xmlChar *)Z_STRVAL_P(member)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
898 xmlUnlinkNode((xmlNodePtr) attr);
899 php_libxml_node_free_resource((xmlNodePtr) attr);
900 break;
901 }
902 attr = anext;
903 }
904 }
905 }
906
907 if (elements) {
908 if (Z_TYPE_P(member) == IS_LONG) {
909 if (sxe->iter.type == SXE_ITER_CHILD) {
910 node = php_sxe_get_first_node(sxe, node);
911 }
912 node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, NULL);
913 if (node) {
914 xmlUnlinkNode(node);
915 php_libxml_node_free_resource(node);
916 }
917 } else {
918 node = node->children;
919 while (node) {
920 nnext = node->next;
921
922 SKIP_TEXT(node);
923
924 if (!xmlStrcmp(node->name, (xmlChar *)Z_STRVAL_P(member)) && match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix)) {
925 xmlUnlinkNode(node);
926 php_libxml_node_free_resource(node);
927 }
928
929 next_iter:
930 node = nnext;
931 }
932 }
933 }
934 }
935
936 if (member == &tmp_zv) {
937 zval_dtor(&tmp_zv);
938 }
939 }
940 /* }}} */
941
942 /* {{{ sxe_property_delete()
943 */
sxe_property_delete(zval * object,zval * member,void ** cache_slot)944 static void sxe_property_delete(zval *object, zval *member, void **cache_slot)
945 {
946 sxe_prop_dim_delete(object, member, 1, 0);
947 }
948 /* }}} */
949
950 /* {{{ sxe_dimension_unset()
951 */
sxe_dimension_delete(zval * object,zval * offset)952 static void sxe_dimension_delete(zval *object, zval *offset)
953 {
954 sxe_prop_dim_delete(object, offset, 0, 1);
955 }
956 /* }}} */
957
sxe_xmlNodeListGetString(xmlDocPtr doc,xmlNodePtr list,int inLine)958 static inline zend_string *sxe_xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) /* {{{ */
959 {
960 xmlChar *tmp = xmlNodeListGetString(doc, list, inLine);
961 zend_string *res;
962
963 if (tmp) {
964 res = zend_string_init((char*)tmp, strlen((char *)tmp), 0);
965 xmlFree(tmp);
966 } else {
967 res = ZSTR_EMPTY_ALLOC();
968 }
969
970 return res;
971 }
972 /* }}} */
973
974 /* {{{ _get_base_node_value()
975 */
_get_base_node_value(php_sxe_object * sxe_ref,xmlNodePtr node,zval * value,xmlChar * nsprefix,int isprefix)976 static void _get_base_node_value(php_sxe_object *sxe_ref, xmlNodePtr node, zval *value, xmlChar *nsprefix, int isprefix)
977 {
978 php_sxe_object *subnode;
979 xmlChar *contents;
980
981 if (node->children && node->children->type == XML_TEXT_NODE && !xmlIsBlankNode(node->children)) {
982 contents = xmlNodeListGetString(node->doc, node->children, 1);
983 if (contents) {
984 ZVAL_STRING(value, (char *)contents);
985 xmlFree(contents);
986 }
987 } else {
988 subnode = php_sxe_object_new(sxe_ref->zo.ce, sxe_ref->fptr_count);
989 subnode->document = sxe_ref->document;
990 subnode->document->refcount++;
991 if (nsprefix && *nsprefix) {
992 subnode->iter.nsprefix = (xmlChar*)estrdup((char *)nsprefix);
993 subnode->iter.isprefix = isprefix;
994 }
995 php_libxml_increment_node_ptr((php_libxml_node_object *)subnode, node, NULL);
996
997 ZVAL_OBJ(value, &subnode->zo);
998 /*zval_add_ref(value);*/
999 }
1000 }
1001 /* }}} */
1002
sxe_properties_add(HashTable * rv,char * name,int namelen,zval * value)1003 static void sxe_properties_add(HashTable *rv, char *name, int namelen, zval *value) /* {{{ */
1004 {
1005 zend_string *key;
1006 zval *data_ptr;
1007 zval newptr;
1008
1009 key = zend_string_init(name, namelen, 0);
1010 if ((data_ptr = zend_hash_find(rv, key)) != NULL) {
1011 if (Z_TYPE_P(data_ptr) == IS_ARRAY) {
1012 zend_hash_next_index_insert_new(Z_ARRVAL_P(data_ptr), value);
1013 } else {
1014 array_init(&newptr);
1015 zend_hash_next_index_insert_new(Z_ARRVAL(newptr), data_ptr);
1016 zend_hash_next_index_insert_new(Z_ARRVAL(newptr), value);
1017 ZVAL_ARR(data_ptr, Z_ARR(newptr));
1018 }
1019 } else {
1020 zend_hash_add_new(rv, key, value);
1021 }
1022 zend_string_release(key);
1023 }
1024 /* }}} */
1025
sxe_prop_is_empty(zval * object)1026 static int sxe_prop_is_empty(zval *object) /* {{{ */
1027 {
1028 php_sxe_object *sxe;
1029 xmlNodePtr node;
1030 xmlAttrPtr attr;
1031 zval iter_data;
1032 int test;
1033 int is_empty;
1034
1035 sxe = Z_SXEOBJ_P(object);
1036
1037 GET_NODE(sxe, node);
1038 if (!node) {
1039 return 1;
1040 }
1041
1042 if (sxe->iter.type == SXE_ITER_ELEMENT) {
1043 node = php_sxe_get_first_node(sxe, node);
1044 }
1045 if (!node || node->type != XML_ENTITY_DECL) {
1046 attr = node ? (xmlAttrPtr)node->properties : NULL;
1047 test = sxe->iter.name && sxe->iter.type == SXE_ITER_ATTRLIST;
1048 while (attr) {
1049 if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr)attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
1050 return 0;
1051 }
1052 attr = attr->next;
1053 }
1054 }
1055
1056 GET_NODE(sxe, node);
1057 node = php_sxe_get_first_node(sxe, node);
1058 is_empty = 1;
1059 ZVAL_UNDEF(&iter_data);
1060 if (node && sxe->iter.type != SXE_ITER_ATTRLIST) {
1061 if (node->type == XML_ATTRIBUTE_NODE) {
1062 return 0;
1063 } else if (sxe->iter.type != SXE_ITER_CHILD) {
1064 if (sxe->iter.type == SXE_ITER_NONE || !node->children || !node->parent || node->children->next || node->children->children || node->parent->children == node->parent->last) {
1065 node = node->children;
1066 } else {
1067 ZVAL_COPY_VALUE(&iter_data, &sxe->iter.data);
1068 ZVAL_UNDEF(&sxe->iter.data);
1069 node = php_sxe_reset_iterator(sxe, 0);
1070 }
1071 }
1072
1073 while (node) {
1074 if (node->children != NULL || node->prev != NULL || node->next != NULL) {
1075 SKIP_TEXT(node);
1076 } else {
1077 if (node->type == XML_TEXT_NODE) {
1078 const xmlChar *cur = node->content;
1079 if (*cur != 0) {
1080 is_empty = 0;
1081 break;
1082 }
1083 goto next_iter;
1084 }
1085 }
1086
1087 if (node->type == XML_ELEMENT_NODE && (! match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix))) {
1088 goto next_iter;
1089 }
1090
1091 if (!node->name) {
1092 goto next_iter;
1093 }
1094
1095 is_empty = 0;
1096 break;
1097 next_iter:
1098 if (!Z_ISUNDEF(iter_data)) {
1099 node = php_sxe_iterator_fetch(sxe, node->next, 0);
1100 } else {
1101 node = node->next;
1102 }
1103 }
1104 }
1105
1106 if (!Z_ISUNDEF(iter_data)) {
1107 if (!Z_ISUNDEF(sxe->iter.data)) {
1108 zval_ptr_dtor(&sxe->iter.data);
1109 }
1110 ZVAL_COPY_VALUE(&sxe->iter.data, &iter_data);
1111 }
1112
1113 return is_empty;
1114 }
1115 /* }}} */
1116
sxe_get_prop_hash(zval * object,int is_debug)1117 static HashTable *sxe_get_prop_hash(zval *object, int is_debug) /* {{{ */
1118 {
1119 zval value;
1120 zval zattr;
1121 HashTable *rv;
1122 php_sxe_object *sxe;
1123 char *name;
1124 xmlNodePtr node;
1125 xmlAttrPtr attr;
1126 int namelen;
1127 int test;
1128 char use_iter;
1129 zval iter_data;
1130
1131 use_iter = 0;
1132
1133 sxe = Z_SXEOBJ_P(object);
1134
1135 if (is_debug) {
1136 ALLOC_HASHTABLE(rv);
1137 zend_hash_init(rv, 0, NULL, ZVAL_PTR_DTOR, 0);
1138 } else if (sxe->properties) {
1139 zend_hash_clean(sxe->properties);
1140 rv = sxe->properties;
1141 } else {
1142 ALLOC_HASHTABLE(rv);
1143 zend_hash_init(rv, 0, NULL, ZVAL_PTR_DTOR, 0);
1144 sxe->properties = rv;
1145 }
1146
1147 GET_NODE(sxe, node);
1148 if (!node) {
1149 return rv;
1150 }
1151 if (is_debug || sxe->iter.type != SXE_ITER_CHILD) {
1152 if (sxe->iter.type == SXE_ITER_ELEMENT) {
1153 node = php_sxe_get_first_node(sxe, node);
1154 }
1155 if (!node || node->type != XML_ENTITY_DECL) {
1156 attr = node ? (xmlAttrPtr)node->properties : NULL;
1157 ZVAL_UNDEF(&zattr);
1158 test = sxe->iter.name && sxe->iter.type == SXE_ITER_ATTRLIST;
1159 while (attr) {
1160 if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr)attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
1161 ZVAL_STR(&value, sxe_xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, attr->children, 1));
1162 namelen = xmlStrlen(attr->name);
1163 if (Z_ISUNDEF(zattr)) {
1164 array_init(&zattr);
1165 sxe_properties_add(rv, "@attributes", sizeof("@attributes") - 1, &zattr);
1166 }
1167 add_assoc_zval_ex(&zattr, (char*)attr->name, namelen, &value);
1168 }
1169 attr = attr->next;
1170 }
1171 }
1172 }
1173
1174 GET_NODE(sxe, node);
1175 node = php_sxe_get_first_node(sxe, node);
1176
1177 if (node && sxe->iter.type != SXE_ITER_ATTRLIST) {
1178 if (node->type == XML_ATTRIBUTE_NODE) {
1179 ZVAL_STR(&value, sxe_xmlNodeListGetString(node->doc, node->children, 1));
1180 zend_hash_next_index_insert(rv, &value);
1181 node = NULL;
1182 } else if (sxe->iter.type != SXE_ITER_CHILD) {
1183
1184 if ( sxe->iter.type == SXE_ITER_NONE || !node->children || !node->parent || !node->next || node->children->next || node->children->children || node->parent->children == node->parent->last ) {
1185 node = node->children;
1186 } else {
1187 ZVAL_COPY_VALUE(&iter_data, &sxe->iter.data);
1188 ZVAL_UNDEF(&sxe->iter.data);
1189
1190 node = php_sxe_reset_iterator(sxe, 0);
1191
1192 use_iter = 1;
1193 }
1194 }
1195
1196 while (node) {
1197 if (node->children != NULL || node->prev != NULL || node->next != NULL) {
1198 SKIP_TEXT(node);
1199 } else {
1200 if (node->type == XML_TEXT_NODE) {
1201 const xmlChar *cur = node->content;
1202
1203 if (*cur != 0) {
1204 ZVAL_STR(&value, sxe_xmlNodeListGetString(node->doc, node, 1));
1205 zend_hash_next_index_insert(rv, &value);
1206 }
1207 goto next_iter;
1208 }
1209 }
1210
1211 if (node->type == XML_ELEMENT_NODE && (! match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix))) {
1212 goto next_iter;
1213 }
1214
1215 name = (char *) node->name;
1216 if (!name) {
1217 goto next_iter;
1218 } else {
1219 namelen = xmlStrlen(node->name);
1220 }
1221
1222 _get_base_node_value(sxe, node, &value, sxe->iter.nsprefix, sxe->iter.isprefix);
1223
1224 if ( use_iter ) {
1225 zend_hash_next_index_insert(rv, &value);
1226 } else {
1227 sxe_properties_add(rv, name, namelen, &value);
1228 }
1229 next_iter:
1230 if (use_iter) {
1231 node = php_sxe_iterator_fetch(sxe, node->next, 0);
1232 } else {
1233 node = node->next;
1234 }
1235 }
1236 }
1237
1238 if (use_iter) {
1239 if (!Z_ISUNDEF(sxe->iter.data)) {
1240 zval_ptr_dtor(&sxe->iter.data);
1241 }
1242 ZVAL_COPY_VALUE(&sxe->iter.data, &iter_data);
1243 }
1244
1245 return rv;
1246 }
1247 /* }}} */
1248
sxe_get_gc(zval * object,zval ** table,int * n)1249 static HashTable *sxe_get_gc(zval *object, zval **table, int *n) /* {{{ */ {
1250 php_sxe_object *sxe;
1251 sxe = Z_SXEOBJ_P(object);
1252
1253 *table = NULL;
1254 *n = 0;
1255 return sxe->properties;
1256 }
1257 /* }}} */
1258
sxe_get_properties(zval * object)1259 static HashTable *sxe_get_properties(zval *object) /* {{{ */
1260 {
1261 return sxe_get_prop_hash(object, 0);
1262 }
1263 /* }}} */
1264
sxe_get_debug_info(zval * object,int * is_temp)1265 static HashTable * sxe_get_debug_info(zval *object, int *is_temp) /* {{{ */
1266 {
1267 *is_temp = 1;
1268 return sxe_get_prop_hash(object, 1);
1269 }
1270 /* }}} */
1271
sxe_objects_compare(zval * object1,zval * object2)1272 static int sxe_objects_compare(zval *object1, zval *object2) /* {{{ */
1273 {
1274 php_sxe_object *sxe1;
1275 php_sxe_object *sxe2;
1276
1277 sxe1 = Z_SXEOBJ_P(object1);
1278 sxe2 = Z_SXEOBJ_P(object2);
1279
1280 if (sxe1->node == NULL) {
1281 if (sxe2->node) {
1282 return 1;
1283 } else if (sxe1->document->ptr == sxe2->document->ptr) {
1284 return 0;
1285 }
1286 } else {
1287 return !(sxe1->node == sxe2->node);
1288 }
1289 return 1;
1290 }
1291 /* }}} */
1292
1293 /* {{{ proto array SimpleXMLElement::xpath(string path)
1294 Runs XPath query on the XML data */
SXE_METHOD(xpath)1295 SXE_METHOD(xpath)
1296 {
1297 php_sxe_object *sxe;
1298 zval value;
1299 char *query;
1300 size_t query_len;
1301 int i;
1302 int nsnbr = 0;
1303 xmlNsPtr *ns = NULL;
1304 xmlXPathObjectPtr retval;
1305 xmlNodeSetPtr result;
1306 xmlNodePtr nodeptr;
1307
1308 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &query, &query_len) == FAILURE) {
1309 return;
1310 }
1311
1312 sxe = Z_SXEOBJ_P(getThis());
1313
1314 if (sxe->iter.type == SXE_ITER_ATTRLIST) {
1315 return; /* attributes don't have attributes */
1316 }
1317
1318 if (!sxe->xpath) {
1319 sxe->xpath = xmlXPathNewContext((xmlDocPtr) sxe->document->ptr);
1320 }
1321 if (!sxe->node) {
1322 php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement((xmlDocPtr) sxe->document->ptr), NULL);
1323 if (!sxe->node) {
1324 RETURN_FALSE;
1325 }
1326 }
1327
1328 nodeptr = php_sxe_get_first_node(sxe, sxe->node->node);
1329
1330 sxe->xpath->node = nodeptr;
1331
1332 ns = xmlGetNsList((xmlDocPtr) sxe->document->ptr, nodeptr);
1333 if (ns != NULL) {
1334 while (ns[nsnbr] != NULL) {
1335 nsnbr++;
1336 }
1337 }
1338
1339 sxe->xpath->namespaces = ns;
1340 sxe->xpath->nsNr = nsnbr;
1341
1342 retval = xmlXPathEval((xmlChar *)query, sxe->xpath);
1343 if (ns != NULL) {
1344 xmlFree(ns);
1345 sxe->xpath->namespaces = NULL;
1346 sxe->xpath->nsNr = 0;
1347 }
1348
1349 if (!retval) {
1350 RETURN_FALSE;
1351 }
1352
1353 result = retval->nodesetval;
1354
1355 array_init(return_value);
1356
1357 if (result != NULL) {
1358 for (i = 0; i < result->nodeNr; ++i) {
1359 nodeptr = result->nodeTab[i];
1360 if (nodeptr->type == XML_TEXT_NODE || nodeptr->type == XML_ELEMENT_NODE || nodeptr->type == XML_ATTRIBUTE_NODE) {
1361 /**
1362 * Detect the case where the last selector is text(), simplexml
1363 * always accesses the text() child by default, therefore we assign
1364 * to the parent node.
1365 */
1366 if (nodeptr->type == XML_TEXT_NODE) {
1367 _node_as_zval(sxe, nodeptr->parent, &value, SXE_ITER_NONE, NULL, NULL, 0);
1368 } else if (nodeptr->type == XML_ATTRIBUTE_NODE) {
1369 _node_as_zval(sxe, nodeptr->parent, &value, SXE_ITER_ATTRLIST, (char*)nodeptr->name, nodeptr->ns ? (xmlChar *)nodeptr->ns->href : NULL, 0);
1370 } else {
1371 _node_as_zval(sxe, nodeptr, &value, SXE_ITER_NONE, NULL, NULL, 0);
1372 }
1373
1374 add_next_index_zval(return_value, &value);
1375 }
1376 }
1377 }
1378
1379 xmlXPathFreeObject(retval);
1380 }
1381 /* }}} */
1382
1383 /* {{{ proto bool SimpleXMLElement::registerXPathNamespace(string prefix, string ns)
1384 Creates a prefix/ns context for the next XPath query */
SXE_METHOD(registerXPathNamespace)1385 SXE_METHOD(registerXPathNamespace)
1386 {
1387 php_sxe_object *sxe;
1388 size_t prefix_len, ns_uri_len;
1389 char *prefix, *ns_uri;
1390
1391 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &prefix, &prefix_len, &ns_uri, &ns_uri_len) == FAILURE) {
1392 return;
1393 }
1394
1395 sxe = Z_SXEOBJ_P(getThis());
1396 if (!sxe->xpath) {
1397 sxe->xpath = xmlXPathNewContext((xmlDocPtr) sxe->document->ptr);
1398 }
1399
1400 if (xmlXPathRegisterNs(sxe->xpath, (xmlChar *)prefix, (xmlChar *)ns_uri) != 0) {
1401 RETURN_FALSE
1402 }
1403 RETURN_TRUE;
1404 }
1405
1406 /* }}} */
1407
1408 /* {{{ proto string SimpleXMLElement::asXML([string filename])
1409 Return a well-formed XML string based on SimpleXML element */
SXE_METHOD(asXML)1410 SXE_METHOD(asXML)
1411 {
1412 php_sxe_object *sxe;
1413 xmlNodePtr node;
1414 xmlOutputBufferPtr outbuf;
1415 xmlChar *strval;
1416 int strval_len;
1417 char *filename;
1418 size_t filename_len;
1419
1420 if (ZEND_NUM_ARGS() > 1) {
1421 RETURN_FALSE;
1422 }
1423
1424 if (ZEND_NUM_ARGS() == 1) {
1425 if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &filename, &filename_len) == FAILURE) {
1426 RETURN_FALSE;
1427 }
1428
1429 sxe = Z_SXEOBJ_P(getThis());
1430 GET_NODE(sxe, node);
1431 node = php_sxe_get_first_node(sxe, node);
1432
1433 if (node) {
1434 if (node->parent && (XML_DOCUMENT_NODE == node->parent->type)) {
1435 int bytes;
1436 bytes = xmlSaveFile(filename, (xmlDocPtr) sxe->document->ptr);
1437 if (bytes == -1) {
1438 RETURN_FALSE;
1439 } else {
1440 RETURN_TRUE;
1441 }
1442 } else {
1443 outbuf = xmlOutputBufferCreateFilename(filename, NULL, 0);
1444
1445 if (outbuf == NULL) {
1446 RETURN_FALSE;
1447 }
1448
1449 xmlNodeDumpOutput(outbuf, (xmlDocPtr) sxe->document->ptr, node, 0, 0, NULL);
1450 xmlOutputBufferClose(outbuf);
1451 RETURN_TRUE;
1452 }
1453 } else {
1454 RETURN_FALSE;
1455 }
1456 }
1457
1458 sxe = Z_SXEOBJ_P(getThis());
1459 GET_NODE(sxe, node);
1460 node = php_sxe_get_first_node(sxe, node);
1461
1462 if (node) {
1463 if (node->parent && (XML_DOCUMENT_NODE == node->parent->type)) {
1464 xmlDocDumpMemoryEnc((xmlDocPtr) sxe->document->ptr, &strval, &strval_len, (const char *) ((xmlDocPtr) sxe->document->ptr)->encoding);
1465 if (!strval) {
1466 RETVAL_FALSE;
1467 } else {
1468 RETVAL_STRINGL((char *)strval, strval_len);
1469 }
1470 xmlFree(strval);
1471 } else {
1472 char *return_content;
1473 size_t return_len;
1474 /* Should we be passing encoding information instead of NULL? */
1475 outbuf = xmlAllocOutputBuffer(NULL);
1476
1477 if (outbuf == NULL) {
1478 RETURN_FALSE;
1479 }
1480
1481 xmlNodeDumpOutput(outbuf, (xmlDocPtr) sxe->document->ptr, node, 0, 0, (const char *) ((xmlDocPtr) sxe->document->ptr)->encoding);
1482 xmlOutputBufferFlush(outbuf);
1483 #ifdef LIBXML2_NEW_BUFFER
1484 return_content = (char *)xmlOutputBufferGetContent(outbuf);
1485 return_len = xmlOutputBufferGetSize(outbuf);
1486 #else
1487 return_content = (char *)outbuf->buffer->content;
1488 return_len = outbuf->buffer->use;
1489 #endif
1490 if (!return_content) {
1491 RETVAL_FALSE;
1492 } else {
1493 RETVAL_STRINGL(return_content, return_len);
1494 }
1495 xmlOutputBufferClose(outbuf);
1496 }
1497 } else {
1498 RETVAL_FALSE;
1499 }
1500 }
1501 /* }}} */
1502
1503 #define SXE_NS_PREFIX(ns) (ns->prefix ? (char*)ns->prefix : "")
1504
sxe_add_namespace_name(zval * return_value,xmlNsPtr ns)1505 static inline void sxe_add_namespace_name(zval *return_value, xmlNsPtr ns) /* {{{ */
1506 {
1507 char *prefix = SXE_NS_PREFIX(ns);
1508 zend_string *key = zend_string_init(prefix, strlen(prefix), 0);
1509 zval zv;
1510
1511 if (!zend_hash_exists(Z_ARRVAL_P(return_value), key)) {
1512 ZVAL_STRING(&zv, (char*)ns->href);
1513 zend_hash_add_new(Z_ARRVAL_P(return_value), key, &zv);
1514 }
1515 zend_string_release(key);
1516 }
1517 /* }}} */
1518
sxe_add_namespaces(php_sxe_object * sxe,xmlNodePtr node,zend_bool recursive,zval * return_value)1519 static void sxe_add_namespaces(php_sxe_object *sxe, xmlNodePtr node, zend_bool recursive, zval *return_value) /* {{{ */
1520 {
1521 xmlAttrPtr attr;
1522
1523 if (node->ns) {
1524 sxe_add_namespace_name(return_value, node->ns);
1525 }
1526
1527 attr = node->properties;
1528 while (attr) {
1529 if (attr->ns) {
1530 sxe_add_namespace_name(return_value, attr->ns);
1531 }
1532 attr = attr->next;
1533 }
1534
1535 if (recursive) {
1536 node = node->children;
1537 while (node) {
1538 if (node->type == XML_ELEMENT_NODE) {
1539 sxe_add_namespaces(sxe, node, recursive, return_value);
1540 }
1541 node = node->next;
1542 }
1543 }
1544 } /* }}} */
1545
1546 /* {{{ proto string SimpleXMLElement::getNamespaces([bool recursve])
1547 Return all namespaces in use */
SXE_METHOD(getNamespaces)1548 SXE_METHOD(getNamespaces)
1549 {
1550 zend_bool recursive = 0;
1551 php_sxe_object *sxe;
1552 xmlNodePtr node;
1553
1554 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &recursive) == FAILURE) {
1555 return;
1556 }
1557
1558 array_init(return_value);
1559
1560 sxe = Z_SXEOBJ_P(getThis());
1561 GET_NODE(sxe, node);
1562 node = php_sxe_get_first_node(sxe, node);
1563
1564 if (node) {
1565 if (node->type == XML_ELEMENT_NODE) {
1566 sxe_add_namespaces(sxe, node, recursive, return_value);
1567 } else if (node->type == XML_ATTRIBUTE_NODE && node->ns) {
1568 sxe_add_namespace_name(return_value, node->ns);
1569 }
1570 }
1571 }
1572 /* }}} */
1573
sxe_add_registered_namespaces(php_sxe_object * sxe,xmlNodePtr node,zend_bool recursive,zval * return_value)1574 static void sxe_add_registered_namespaces(php_sxe_object *sxe, xmlNodePtr node, zend_bool recursive, zval *return_value) /* {{{ */
1575 {
1576 xmlNsPtr ns;
1577
1578 if (node->type == XML_ELEMENT_NODE) {
1579 ns = node->nsDef;
1580 while (ns != NULL) {
1581 sxe_add_namespace_name(return_value, ns);
1582 ns = ns->next;
1583 }
1584 if (recursive) {
1585 node = node->children;
1586 while (node) {
1587 sxe_add_registered_namespaces(sxe, node, recursive, return_value);
1588 node = node->next;
1589 }
1590 }
1591 }
1592 }
1593 /* }}} */
1594
1595 /* {{{ proto string SimpleXMLElement::getDocNamespaces([bool recursive [, bool from_root])
1596 Return all namespaces registered with document */
SXE_METHOD(getDocNamespaces)1597 SXE_METHOD(getDocNamespaces)
1598 {
1599 zend_bool recursive = 0, from_root = 1;
1600 php_sxe_object *sxe;
1601 xmlNodePtr node;
1602
1603 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|bb", &recursive, &from_root) == FAILURE) {
1604 return;
1605 }
1606
1607 sxe = Z_SXEOBJ_P(getThis());
1608 if(from_root){
1609 node = xmlDocGetRootElement((xmlDocPtr)sxe->document->ptr);
1610 }else{
1611 GET_NODE(sxe, node);
1612 }
1613
1614 if (node == NULL) {
1615 RETURN_FALSE;
1616 }
1617
1618 array_init(return_value);
1619 sxe_add_registered_namespaces(sxe, node, recursive, return_value);
1620 }
1621 /* }}} */
1622
1623 /* {{{ proto object SimpleXMLElement::children([string ns [, bool is_prefix]])
1624 Finds children of given node */
SXE_METHOD(children)1625 SXE_METHOD(children)
1626 {
1627 php_sxe_object *sxe;
1628 char *nsprefix = NULL;
1629 size_t nsprefix_len = 0;
1630 xmlNodePtr node;
1631 zend_bool isprefix = 0;
1632
1633 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s!b", &nsprefix, &nsprefix_len, &isprefix) == FAILURE) {
1634 return;
1635 }
1636
1637 sxe = Z_SXEOBJ_P(getThis());
1638
1639 if (sxe->iter.type == SXE_ITER_ATTRLIST) {
1640 return; /* attributes don't have attributes */
1641 }
1642
1643 GET_NODE(sxe, node);
1644 node = php_sxe_get_first_node(sxe, node);
1645
1646 _node_as_zval(sxe, node, return_value, SXE_ITER_CHILD, NULL, (xmlChar *)nsprefix, isprefix);
1647
1648 }
1649 /* }}} */
1650
1651 /* {{{ proto object SimpleXMLElement::getName()
1652 Finds children of given node */
SXE_METHOD(getName)1653 SXE_METHOD(getName)
1654 {
1655 php_sxe_object *sxe;
1656 xmlNodePtr node;
1657 int namelen;
1658
1659 sxe = Z_SXEOBJ_P(getThis());
1660
1661 GET_NODE(sxe, node);
1662 node = php_sxe_get_first_node(sxe, node);
1663 if (node) {
1664 namelen = xmlStrlen(node->name);
1665 RETURN_STRINGL((char*)node->name, namelen);
1666 } else {
1667 RETURN_EMPTY_STRING();
1668 }
1669 }
1670 /* }}} */
1671
1672 /* {{{ proto array SimpleXMLElement::attributes([string ns [, bool is_prefix]])
1673 Identifies an element's attributes */
SXE_METHOD(attributes)1674 SXE_METHOD(attributes)
1675 {
1676 php_sxe_object *sxe;
1677 char *nsprefix = NULL;
1678 size_t nsprefix_len = 0;
1679 xmlNodePtr node;
1680 zend_bool isprefix = 0;
1681
1682 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s!b", &nsprefix, &nsprefix_len, &isprefix) == FAILURE) {
1683 return;
1684 }
1685
1686 sxe = Z_SXEOBJ_P(getThis());
1687 GET_NODE(sxe, node);
1688
1689 if (sxe->iter.type == SXE_ITER_ATTRLIST) {
1690 return; /* attributes don't have attributes */
1691 }
1692
1693 node = php_sxe_get_first_node(sxe, node);
1694
1695 _node_as_zval(sxe, node, return_value, SXE_ITER_ATTRLIST, NULL, (xmlChar *)nsprefix, isprefix);
1696 }
1697 /* }}} */
1698
1699 /* {{{ proto void SimpleXMLElement::addChild(string qName [, string value [, string ns]])
1700 Add Element with optional namespace information */
SXE_METHOD(addChild)1701 SXE_METHOD(addChild)
1702 {
1703 php_sxe_object *sxe;
1704 char *qname, *value = NULL, *nsuri = NULL;
1705 size_t qname_len, value_len = 0, nsuri_len = 0;
1706 xmlNodePtr node, newnode;
1707 xmlNsPtr nsptr = NULL;
1708 xmlChar *localname, *prefix = NULL;
1709
1710 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s!s!",
1711 &qname, &qname_len, &value, &value_len, &nsuri, &nsuri_len) == FAILURE) {
1712 return;
1713 }
1714
1715 if (qname_len == 0) {
1716 php_error_docref(NULL, E_WARNING, "Element name is required");
1717 return;
1718 }
1719
1720 sxe = Z_SXEOBJ_P(getThis());
1721 GET_NODE(sxe, node);
1722
1723 if (sxe->iter.type == SXE_ITER_ATTRLIST) {
1724 php_error_docref(NULL, E_WARNING, "Cannot add element to attributes");
1725 return;
1726 }
1727
1728 node = php_sxe_get_first_node(sxe, node);
1729
1730 if (node == NULL) {
1731 php_error_docref(NULL, E_WARNING, "Cannot add child. Parent is not a permanent member of the XML tree");
1732 return;
1733 }
1734
1735 localname = xmlSplitQName2((xmlChar *)qname, &prefix);
1736 if (localname == NULL) {
1737 localname = xmlStrdup((xmlChar *)qname);
1738 }
1739
1740 newnode = xmlNewChild(node, NULL, localname, (xmlChar *)value);
1741
1742 if (nsuri != NULL) {
1743 if (nsuri_len == 0) {
1744 newnode->ns = NULL;
1745 nsptr = xmlNewNs(newnode, (xmlChar *)nsuri, prefix);
1746 } else {
1747 nsptr = xmlSearchNsByHref(node->doc, node, (xmlChar *)nsuri);
1748 if (nsptr == NULL) {
1749 nsptr = xmlNewNs(newnode, (xmlChar *)nsuri, prefix);
1750 }
1751 newnode->ns = nsptr;
1752 }
1753 }
1754
1755 _node_as_zval(sxe, newnode, return_value, SXE_ITER_NONE, (char *)localname, prefix, 0);
1756
1757 xmlFree(localname);
1758 if (prefix != NULL) {
1759 xmlFree(prefix);
1760 }
1761 }
1762 /* }}} */
1763
1764 /* {{{ proto void SimpleXMLElement::addAttribute(string qName, string value [,string ns])
1765 Add Attribute with optional namespace information */
SXE_METHOD(addAttribute)1766 SXE_METHOD(addAttribute)
1767 {
1768 php_sxe_object *sxe;
1769 char *qname, *value = NULL, *nsuri = NULL;
1770 size_t qname_len, value_len = 0, nsuri_len = 0;
1771 xmlNodePtr node;
1772 xmlAttrPtr attrp = NULL;
1773 xmlNsPtr nsptr = NULL;
1774 xmlChar *localname, *prefix = NULL;
1775
1776 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|s!",
1777 &qname, &qname_len, &value, &value_len, &nsuri, &nsuri_len) == FAILURE) {
1778 return;
1779 }
1780
1781 if (qname_len == 0) {
1782 php_error_docref(NULL, E_WARNING, "Attribute name is required");
1783 return;
1784 }
1785
1786 sxe = Z_SXEOBJ_P(getThis());
1787 GET_NODE(sxe, node);
1788
1789 node = php_sxe_get_first_node(sxe, node);
1790
1791 if (node && node->type != XML_ELEMENT_NODE) {
1792 node = node->parent;
1793 }
1794
1795 if (node == NULL) {
1796 php_error_docref(NULL, E_WARNING, "Unable to locate parent Element");
1797 return;
1798 }
1799
1800 localname = xmlSplitQName2((xmlChar *)qname, &prefix);
1801 if (localname == NULL) {
1802 if (nsuri_len > 0) {
1803 if (prefix != NULL) {
1804 xmlFree(prefix);
1805 }
1806 php_error_docref(NULL, E_WARNING, "Attribute requires prefix for namespace");
1807 return;
1808 }
1809 localname = xmlStrdup((xmlChar *)qname);
1810 }
1811
1812 attrp = xmlHasNsProp(node, localname, (xmlChar *)nsuri);
1813 if (attrp != NULL && attrp->type != XML_ATTRIBUTE_DECL) {
1814 xmlFree(localname);
1815 if (prefix != NULL) {
1816 xmlFree(prefix);
1817 }
1818 php_error_docref(NULL, E_WARNING, "Attribute already exists");
1819 return;
1820 }
1821
1822 if (nsuri != NULL) {
1823 nsptr = xmlSearchNsByHref(node->doc, node, (xmlChar *)nsuri);
1824 if (nsptr == NULL) {
1825 nsptr = xmlNewNs(node, (xmlChar *)nsuri, prefix);
1826 }
1827 }
1828
1829 attrp = xmlNewNsProp(node, nsptr, localname, (xmlChar *)value);
1830
1831 xmlFree(localname);
1832 if (prefix != NULL) {
1833 xmlFree(prefix);
1834 }
1835 }
1836 /* }}} */
1837
1838 /* {{{ cast_object()
1839 */
cast_object(zval * object,int type,char * contents)1840 static int cast_object(zval *object, int type, char *contents)
1841 {
1842 if (contents) {
1843 ZVAL_STRINGL(object, contents, strlen(contents));
1844 } else {
1845 ZVAL_NULL(object);
1846 }
1847
1848 switch (type) {
1849 case IS_STRING:
1850 convert_to_string(object);
1851 break;
1852 case _IS_BOOL:
1853 convert_to_boolean(object);
1854 break;
1855 case IS_LONG:
1856 convert_to_long(object);
1857 break;
1858 case IS_DOUBLE:
1859 convert_to_double(object);
1860 break;
1861 default:
1862 return FAILURE;
1863 }
1864 return SUCCESS;
1865 }
1866 /* }}} */
1867
1868 /* {{{ sxe_object_cast()
1869 */
sxe_object_cast_ex(zval * readobj,zval * writeobj,int type)1870 static int sxe_object_cast_ex(zval *readobj, zval *writeobj, int type)
1871 {
1872 php_sxe_object *sxe;
1873 xmlChar *contents = NULL;
1874 xmlNodePtr node;
1875 int rv;
1876
1877 sxe = Z_SXEOBJ_P(readobj);
1878
1879 if (type == _IS_BOOL) {
1880 node = php_sxe_get_first_node(sxe, NULL);
1881 if (node) {
1882 ZVAL_TRUE(writeobj);
1883 } else {
1884 ZVAL_BOOL(writeobj, !sxe_prop_is_empty(readobj));
1885 }
1886 return SUCCESS;
1887 }
1888
1889 if (sxe->iter.type != SXE_ITER_NONE) {
1890 node = php_sxe_get_first_node(sxe, NULL);
1891 if (node) {
1892 contents = xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, node->children, 1);
1893 }
1894 } else {
1895 if (!sxe->node) {
1896 if (sxe->document) {
1897 php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement((xmlDocPtr) sxe->document->ptr), NULL);
1898 }
1899 }
1900
1901 if (sxe->node && sxe->node->node) {
1902 if (sxe->node->node->children) {
1903 contents = xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, sxe->node->node->children, 1);
1904 }
1905 }
1906 }
1907
1908 if (readobj == writeobj) {
1909 zval_ptr_dtor(readobj);
1910 }
1911
1912 rv = cast_object(writeobj, type, (char *)contents);
1913
1914 if (contents) {
1915 xmlFree(contents);
1916 }
1917
1918 return rv;
1919 }
1920 /* }}} */
1921
1922 /* {{{ Variant of sxe_object_cast_ex that handles overwritten __toString() method */
sxe_object_cast(zval * readobj,zval * writeobj,int type)1923 static int sxe_object_cast(zval *readobj, zval *writeobj, int type)
1924 {
1925 if (type == IS_STRING
1926 && zend_std_cast_object_tostring(readobj, writeobj, IS_STRING) == SUCCESS
1927 ) {
1928 return SUCCESS;
1929 }
1930
1931 return sxe_object_cast_ex(readobj, writeobj, type);
1932 }
1933 /* }}} */
1934
1935 /* {{{ proto object SimpleXMLElement::__toString()
1936 Returns the string content */
SXE_METHOD(__toString)1937 SXE_METHOD(__toString)
1938 {
1939 if (sxe_object_cast_ex(getThis(), return_value, IS_STRING) != SUCCESS) {
1940 zval_ptr_dtor(return_value);
1941 RETURN_EMPTY_STRING();
1942 }
1943 }
1944 /* }}} */
1945
php_sxe_count_elements_helper(php_sxe_object * sxe,zend_long * count)1946 static int php_sxe_count_elements_helper(php_sxe_object *sxe, zend_long *count) /* {{{ */
1947 {
1948 xmlNodePtr node;
1949 zval data;
1950
1951 *count = 0;
1952
1953 ZVAL_COPY_VALUE(&data, &sxe->iter.data);
1954 ZVAL_UNDEF(&sxe->iter.data);
1955
1956 node = php_sxe_reset_iterator(sxe, 0);
1957
1958 while (node)
1959 {
1960 (*count)++;
1961 node = php_sxe_iterator_fetch(sxe, node->next, 0);
1962 }
1963
1964 if (!Z_ISUNDEF(sxe->iter.data)) {
1965 zval_ptr_dtor(&sxe->iter.data);
1966 }
1967 ZVAL_COPY_VALUE(&sxe->iter.data, &data);
1968
1969 return SUCCESS;
1970 }
1971 /* }}} */
1972
sxe_count_elements(zval * object,zend_long * count)1973 static int sxe_count_elements(zval *object, zend_long *count) /* {{{ */
1974 {
1975 php_sxe_object *intern;
1976 intern = Z_SXEOBJ_P(object);
1977 if (intern->fptr_count) {
1978 zval rv;
1979 zend_call_method_with_0_params(object, intern->zo.ce, &intern->fptr_count, "count", &rv);
1980 if (!Z_ISUNDEF(rv)) {
1981 *count = zval_get_long(&rv);
1982 zval_ptr_dtor(&rv);
1983 return SUCCESS;
1984 }
1985 return FAILURE;
1986 }
1987 return php_sxe_count_elements_helper(intern, count);
1988 }
1989 /* }}} */
1990
1991 /* {{{ proto int SimpleXMLElement::count()
1992 Get number of child elements */
SXE_METHOD(count)1993 SXE_METHOD(count)
1994 {
1995 zend_long count = 0;
1996 php_sxe_object *sxe = Z_SXEOBJ_P(getThis());
1997
1998 if (zend_parse_parameters_none() == FAILURE) {
1999 return;
2000 }
2001
2002 php_sxe_count_elements_helper(sxe, &count);
2003
2004 RETURN_LONG(count);
2005 }
2006 /* }}} */
2007
sxe_get_value(zval * z,zval * rv)2008 static zval *sxe_get_value(zval *z, zval *rv) /* {{{ */
2009 {
2010 if (sxe_object_cast_ex(z, rv, IS_STRING) == FAILURE) {
2011 zend_error(E_ERROR, "Unable to cast node to string");
2012 /* FIXME: Should not be fatal */
2013 }
2014
2015 return rv;
2016 }
2017 /* }}} */
2018
2019 static zend_object_handlers sxe_object_handlers = { /* {{{ */
2020 ZEND_OBJECTS_STORE_HANDLERS,
2021 sxe_property_read,
2022 sxe_property_write,
2023 sxe_dimension_read,
2024 sxe_dimension_write,
2025 sxe_property_get_adr,
2026 sxe_get_value, /* get */
2027 NULL,
2028 sxe_property_exists,
2029 sxe_property_delete,
2030 sxe_dimension_exists,
2031 sxe_dimension_delete,
2032 sxe_get_properties,
2033 NULL, /* zend_get_std_object_handlers()->get_method,*/
2034 NULL, /* zend_get_std_object_handlers()->call_method,*/
2035 NULL, /* zend_get_std_object_handlers()->get_constructor, */
2036 NULL, /* zend_get_std_object_handlers()->get_class_name,*/
2037 sxe_objects_compare,
2038 sxe_object_cast,
2039 sxe_count_elements,
2040 sxe_get_debug_info,
2041 NULL,
2042 sxe_get_gc,
2043 NULL,
2044 NULL
2045 };
2046 /* }}} */
2047
2048 /* {{{ sxe_object_clone()
2049 */
2050 static zend_object *
sxe_object_clone(zval * object)2051 sxe_object_clone(zval *object)
2052 {
2053 php_sxe_object *sxe = Z_SXEOBJ_P(object);
2054 php_sxe_object *clone;
2055 xmlNodePtr nodep = NULL;
2056 xmlDocPtr docp = NULL;
2057
2058 clone = php_sxe_object_new(sxe->zo.ce, sxe->fptr_count);
2059 clone->document = sxe->document;
2060 if (clone->document) {
2061 clone->document->refcount++;
2062 docp = clone->document->ptr;
2063 }
2064
2065 clone->iter.isprefix = sxe->iter.isprefix;
2066 if (sxe->iter.name != NULL) {
2067 clone->iter.name = (xmlChar*)estrdup((char*)sxe->iter.name);
2068 }
2069 if (sxe->iter.nsprefix != NULL) {
2070 clone->iter.nsprefix = (xmlChar*)estrdup((char*)sxe->iter.nsprefix);
2071 }
2072 clone->iter.type = sxe->iter.type;
2073
2074 if (sxe->node) {
2075 nodep = xmlDocCopyNode(sxe->node->node, docp, 1);
2076 }
2077
2078 php_libxml_increment_node_ptr((php_libxml_node_object *)clone, nodep, NULL);
2079
2080 return &clone->zo;
2081 }
2082 /* }}} */
2083
2084 /* {{{ sxe_object_dtor()
2085 */
sxe_object_dtor(zend_object * object)2086 static void sxe_object_dtor(zend_object *object)
2087 {
2088 /* dtor required to cleanup iterator related data properly */
2089 php_sxe_object *sxe;
2090
2091 sxe = php_sxe_fetch_object(object);
2092
2093 if (!Z_ISUNDEF(sxe->iter.data)) {
2094 zval_ptr_dtor(&sxe->iter.data);
2095 ZVAL_UNDEF(&sxe->iter.data);
2096 }
2097
2098 if (sxe->iter.name) {
2099 efree(sxe->iter.name);
2100 sxe->iter.name = NULL;
2101 }
2102 if (sxe->iter.nsprefix) {
2103 efree(sxe->iter.nsprefix);
2104 sxe->iter.nsprefix = NULL;
2105 }
2106 if (!Z_ISUNDEF(sxe->tmp)) {
2107 zval_ptr_dtor(&sxe->tmp);
2108 ZVAL_UNDEF(&sxe->tmp);
2109 }
2110 }
2111 /* }}} */
2112
2113 /* {{{ sxe_object_free_storage()
2114 */
sxe_object_free_storage(zend_object * object)2115 static void sxe_object_free_storage(zend_object *object)
2116 {
2117 php_sxe_object *sxe;
2118
2119 sxe = php_sxe_fetch_object(object);
2120
2121 zend_object_std_dtor(&sxe->zo);
2122
2123 php_libxml_node_decrement_resource((php_libxml_node_object *)sxe);
2124
2125 if (sxe->xpath) {
2126 xmlXPathFreeContext(sxe->xpath);
2127 }
2128
2129 if (sxe->properties) {
2130 zend_hash_destroy(sxe->properties);
2131 FREE_HASHTABLE(sxe->properties);
2132 }
2133 }
2134 /* }}} */
2135
2136 /* {{{ php_sxe_find_fptr_count()
2137 */
php_sxe_find_fptr_count(zend_class_entry * ce)2138 static zend_function* php_sxe_find_fptr_count(zend_class_entry *ce)
2139 {
2140 zend_function *fptr_count = NULL;
2141 zend_class_entry *parent = ce;
2142 int inherited = 0;
2143
2144 while (parent) {
2145 if (parent == sxe_class_entry) {
2146 break;
2147 }
2148 parent = parent->parent;
2149 inherited = 1;
2150 }
2151
2152 if (inherited) {
2153 fptr_count = zend_hash_str_find_ptr(&ce->function_table, "count", sizeof("count") - 1);
2154 if (fptr_count->common.scope == parent) {
2155 fptr_count = NULL;
2156 }
2157 }
2158
2159 return fptr_count;
2160 }
2161 /* }}} */
2162
2163 /* {{{ php_sxe_object_new()
2164 */
php_sxe_object_new(zend_class_entry * ce,zend_function * fptr_count)2165 static php_sxe_object* php_sxe_object_new(zend_class_entry *ce, zend_function *fptr_count)
2166 {
2167 php_sxe_object *intern;
2168
2169 intern = ecalloc(1, sizeof(php_sxe_object) + zend_object_properties_size(ce));
2170
2171 intern->iter.type = SXE_ITER_NONE;
2172 intern->iter.nsprefix = NULL;
2173 intern->iter.name = NULL;
2174 intern->fptr_count = fptr_count;
2175
2176 zend_object_std_init(&intern->zo, ce);
2177 object_properties_init(&intern->zo, ce);
2178 intern->zo.handlers = &sxe_object_handlers;
2179
2180 return intern;
2181 }
2182 /* }}} */
2183
2184 /* {{{ sxe_object_new()
2185 */
2186 PHP_SXE_API zend_object *
sxe_object_new(zend_class_entry * ce)2187 sxe_object_new(zend_class_entry *ce)
2188 {
2189 php_sxe_object *intern;
2190
2191 intern = php_sxe_object_new(ce, php_sxe_find_fptr_count(ce));
2192 return &intern->zo;
2193 }
2194 /* }}} */
2195
2196 /* {{{ proto simplemxml_element simplexml_load_file(string filename [, string class_name [, int options [, string ns [, bool is_prefix]]]])
2197 Load a filename and return a simplexml_element object to allow for processing */
PHP_FUNCTION(simplexml_load_file)2198 PHP_FUNCTION(simplexml_load_file)
2199 {
2200 php_sxe_object *sxe;
2201 char *filename;
2202 size_t filename_len;
2203 xmlDocPtr docp;
2204 char *ns = NULL;
2205 size_t ns_len = 0;
2206 zend_long options = 0;
2207 zend_class_entry *ce= sxe_class_entry;
2208 zend_function *fptr_count;
2209 zend_bool isprefix = 0;
2210
2211 if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|C!lsb", &filename, &filename_len, &ce, &options, &ns, &ns_len, &isprefix) == FAILURE) {
2212 return;
2213 }
2214
2215 if (ZEND_LONG_EXCEEDS_INT(options)) {
2216 php_error_docref(NULL, E_WARNING, "Invalid options");
2217 RETURN_FALSE;
2218 }
2219
2220 docp = xmlReadFile(filename, NULL, (int)options);
2221
2222 if (!docp) {
2223 RETURN_FALSE;
2224 }
2225
2226 if (!ce) {
2227 ce = sxe_class_entry;
2228 fptr_count = NULL;
2229 } else {
2230 fptr_count = php_sxe_find_fptr_count(ce);
2231 }
2232 sxe = php_sxe_object_new(ce, fptr_count);
2233 sxe->iter.nsprefix = ns_len ? (xmlChar*)estrdup(ns) : NULL;
2234 sxe->iter.isprefix = isprefix;
2235 php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp);
2236 php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL);
2237
2238 ZVAL_OBJ(return_value, &sxe->zo);
2239 }
2240 /* }}} */
2241
2242 /* {{{ proto simplemxml_element simplexml_load_string(string data [, string class_name [, int options [, string ns [, bool is_prefix]]]])
2243 Load a string and return a simplexml_element object to allow for processing */
PHP_FUNCTION(simplexml_load_string)2244 PHP_FUNCTION(simplexml_load_string)
2245 {
2246 php_sxe_object *sxe;
2247 char *data;
2248 size_t data_len;
2249 xmlDocPtr docp;
2250 char *ns = NULL;
2251 size_t ns_len = 0;
2252 zend_long options = 0;
2253 zend_class_entry *ce= sxe_class_entry;
2254 zend_function *fptr_count;
2255 zend_bool isprefix = 0;
2256
2257 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|C!lsb", &data, &data_len, &ce, &options, &ns, &ns_len, &isprefix) == FAILURE) {
2258 return;
2259 }
2260
2261 if (ZEND_SIZE_T_INT_OVFL(data_len)) {
2262 php_error_docref(NULL, E_WARNING, "Data is too long");
2263 RETURN_FALSE;
2264 }
2265 if (ZEND_SIZE_T_INT_OVFL(ns_len)) {
2266 php_error_docref(NULL, E_WARNING, "Namespace is too long");
2267 RETURN_FALSE;
2268 }
2269 if (ZEND_LONG_EXCEEDS_INT(options)) {
2270 php_error_docref(NULL, E_WARNING, "Invalid options");
2271 RETURN_FALSE;
2272 }
2273
2274 docp = xmlReadMemory(data, (int)data_len, NULL, NULL, (int)options);
2275
2276 if (!docp) {
2277 RETURN_FALSE;
2278 }
2279
2280 if (!ce) {
2281 ce = sxe_class_entry;
2282 fptr_count = NULL;
2283 } else {
2284 fptr_count = php_sxe_find_fptr_count(ce);
2285 }
2286 sxe = php_sxe_object_new(ce, fptr_count);
2287 sxe->iter.nsprefix = ns_len ? (xmlChar*)estrdup(ns) : NULL;
2288 sxe->iter.isprefix = isprefix;
2289 php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp);
2290 php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL);
2291
2292 ZVAL_OBJ(return_value, &sxe->zo);
2293 }
2294 /* }}} */
2295
2296 /* {{{ proto SimpleXMLElement::__construct(string data [, int options [, bool data_is_url [, string ns [, bool is_prefix]]]])
2297 SimpleXMLElement constructor */
SXE_METHOD(__construct)2298 SXE_METHOD(__construct)
2299 {
2300 php_sxe_object *sxe = Z_SXEOBJ_P(getThis());
2301 char *data, *ns = NULL;
2302 size_t data_len, ns_len = 0;
2303 xmlDocPtr docp;
2304 zend_long options = 0;
2305 zend_bool is_url = 0, isprefix = 0;
2306
2307 if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "s|lbsb", &data, &data_len, &options, &is_url, &ns, &ns_len, &isprefix) == FAILURE) {
2308 return;
2309 }
2310
2311 if (ZEND_SIZE_T_INT_OVFL(data_len)) {
2312 zend_throw_exception(zend_ce_exception, "Data is too long", 0);
2313 return;
2314 }
2315 if (ZEND_SIZE_T_INT_OVFL(ns_len)) {
2316 zend_throw_exception(zend_ce_exception, "Namespace is too long", 0);
2317 return;
2318 }
2319 if (ZEND_LONG_EXCEEDS_INT(options)) {
2320 zend_throw_exception(zend_ce_exception, "Invalid options", 0);
2321 return;
2322 }
2323
2324 docp = is_url ? xmlReadFile(data, NULL, (int)options) : xmlReadMemory(data, (int)data_len, NULL, NULL, (int)options);
2325
2326 if (!docp) {
2327 ((php_libxml_node_object *)sxe)->document = NULL;
2328 zend_throw_exception(zend_ce_exception, "String could not be parsed as XML", 0);
2329 return;
2330 }
2331
2332 sxe->iter.nsprefix = ns_len ? (xmlChar*)estrdup(ns) : NULL;
2333 sxe->iter.isprefix = isprefix;
2334 php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp);
2335 php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL);
2336 }
2337 /* }}} */
2338
2339 zend_object_iterator_funcs php_sxe_iterator_funcs = { /* {{{ */
2340 php_sxe_iterator_dtor,
2341 php_sxe_iterator_valid,
2342 php_sxe_iterator_current_data,
2343 php_sxe_iterator_current_key,
2344 php_sxe_iterator_move_forward,
2345 php_sxe_iterator_rewind,
2346 NULL
2347 };
2348 /* }}} */
2349
php_sxe_iterator_fetch(php_sxe_object * sxe,xmlNodePtr node,int use_data)2350 static xmlNodePtr php_sxe_iterator_fetch(php_sxe_object *sxe, xmlNodePtr node, int use_data) /* {{{ */
2351 {
2352 xmlChar *prefix = sxe->iter.nsprefix;
2353 int isprefix = sxe->iter.isprefix;
2354
2355 if (sxe->iter.type == SXE_ITER_ATTRLIST) {
2356 if (sxe->iter.name) {
2357 while (node) {
2358 if (node->type == XML_ATTRIBUTE_NODE) {
2359 if (!xmlStrcmp(node->name, sxe->iter.name) && match_ns(sxe, node, prefix, isprefix)) {
2360 break;
2361 }
2362 }
2363 node = node->next;
2364 }
2365 } else {
2366 while (node) {
2367 if (node->type == XML_ATTRIBUTE_NODE) {
2368 if (match_ns(sxe, node, prefix, isprefix)) {
2369 break;
2370 }
2371 }
2372 node = node->next;
2373 }
2374 }
2375 } else if (sxe->iter.type == SXE_ITER_ELEMENT && sxe->iter.name) {
2376 while (node) {
2377 if (node->type == XML_ELEMENT_NODE) {
2378 if (!xmlStrcmp(node->name, sxe->iter.name) && match_ns(sxe, node, prefix, isprefix)) {
2379 break;
2380 }
2381 }
2382 node = node->next;
2383 }
2384 } else {
2385 while (node) {
2386 if (node->type == XML_ELEMENT_NODE) {
2387 if (match_ns(sxe, node, prefix, isprefix)) {
2388 break;
2389 }
2390 }
2391 node = node->next;
2392 }
2393 }
2394
2395 if (node && use_data) {
2396 _node_as_zval(sxe, node, &sxe->iter.data, SXE_ITER_NONE, NULL, prefix, isprefix);
2397 }
2398
2399 return node;
2400 }
2401 /* }}} */
2402
php_sxe_reset_iterator(php_sxe_object * sxe,int use_data)2403 static xmlNodePtr php_sxe_reset_iterator(php_sxe_object *sxe, int use_data) /* {{{ */
2404 {
2405 xmlNodePtr node;
2406
2407 if (!Z_ISUNDEF(sxe->iter.data)) {
2408 zval_ptr_dtor(&sxe->iter.data);
2409 ZVAL_UNDEF(&sxe->iter.data);
2410 }
2411
2412 GET_NODE(sxe, node)
2413
2414 if (node) {
2415 switch (sxe->iter.type) {
2416 case SXE_ITER_ELEMENT:
2417 case SXE_ITER_CHILD:
2418 case SXE_ITER_NONE:
2419 node = node->children;
2420 break;
2421 case SXE_ITER_ATTRLIST:
2422 node = (xmlNodePtr) node->properties;
2423 }
2424 return php_sxe_iterator_fetch(sxe, node, use_data);
2425 }
2426 return NULL;
2427 }
2428 /* }}} */
2429
php_sxe_get_iterator(zend_class_entry * ce,zval * object,int by_ref)2430 zend_object_iterator *php_sxe_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */
2431 {
2432 php_sxe_iterator *iterator;
2433
2434 if (by_ref) {
2435 zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
2436 }
2437 iterator = emalloc(sizeof(php_sxe_iterator));
2438 zend_iterator_init(&iterator->intern);
2439
2440 ZVAL_COPY(&iterator->intern.data, object);
2441 iterator->intern.funcs = &php_sxe_iterator_funcs;
2442 iterator->sxe = Z_SXEOBJ_P(object);
2443
2444 return (zend_object_iterator*)iterator;
2445 }
2446 /* }}} */
2447
php_sxe_iterator_dtor(zend_object_iterator * iter)2448 static void php_sxe_iterator_dtor(zend_object_iterator *iter) /* {{{ */
2449 {
2450 php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2451
2452 /* cleanup handled in sxe_object_dtor as we dont always have an iterator wrapper */
2453 if (!Z_ISUNDEF(iterator->intern.data)) {
2454 zval_ptr_dtor(&iterator->intern.data);
2455 }
2456 }
2457 /* }}} */
2458
php_sxe_iterator_valid(zend_object_iterator * iter)2459 static int php_sxe_iterator_valid(zend_object_iterator *iter) /* {{{ */
2460 {
2461 php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2462
2463 return Z_ISUNDEF(iterator->sxe->iter.data) ? FAILURE : SUCCESS;
2464 }
2465 /* }}} */
2466
php_sxe_iterator_current_data(zend_object_iterator * iter)2467 static zval *php_sxe_iterator_current_data(zend_object_iterator *iter) /* {{{ */
2468 {
2469 php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2470
2471 return &iterator->sxe->iter.data;
2472 }
2473 /* }}} */
2474
php_sxe_iterator_current_key(zend_object_iterator * iter,zval * key)2475 static void php_sxe_iterator_current_key(zend_object_iterator *iter, zval *key) /* {{{ */
2476 {
2477 php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2478 zval *curobj = &iterator->sxe->iter.data;
2479 php_sxe_object *intern = Z_SXEOBJ_P(curobj);
2480
2481 xmlNodePtr curnode = NULL;
2482 if (intern != NULL && intern->node != NULL) {
2483 curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->node)->node;
2484 }
2485
2486 if (curnode) {
2487 ZVAL_STRINGL(key, (char *) curnode->name, xmlStrlen(curnode->name));
2488 } else {
2489 ZVAL_NULL(key);
2490 }
2491 }
2492 /* }}} */
2493
php_sxe_move_forward_iterator(php_sxe_object * sxe)2494 PHP_SXE_API void php_sxe_move_forward_iterator(php_sxe_object *sxe) /* {{{ */
2495 {
2496 xmlNodePtr node = NULL;
2497 php_sxe_object *intern;
2498
2499 if (!Z_ISUNDEF(sxe->iter.data)) {
2500 intern = Z_SXEOBJ_P(&sxe->iter.data);
2501 GET_NODE(intern, node)
2502 zval_ptr_dtor(&sxe->iter.data);
2503 ZVAL_UNDEF(&sxe->iter.data);
2504 }
2505
2506 if (node) {
2507 php_sxe_iterator_fetch(sxe, node->next, 1);
2508 }
2509 }
2510 /* }}} */
2511
php_sxe_iterator_move_forward(zend_object_iterator * iter)2512 static void php_sxe_iterator_move_forward(zend_object_iterator *iter) /* {{{ */
2513 {
2514 php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2515 php_sxe_move_forward_iterator(iterator->sxe);
2516 }
2517 /* }}} */
2518
php_sxe_iterator_rewind(zend_object_iterator * iter)2519 static void php_sxe_iterator_rewind(zend_object_iterator *iter) /* {{{ */
2520 {
2521 php_sxe_object *sxe;
2522
2523 php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2524 sxe = iterator->sxe;
2525
2526 php_sxe_reset_iterator(sxe, 1);
2527 }
2528 /* }}} */
2529
simplexml_export_node(zval * object)2530 void *simplexml_export_node(zval *object) /* {{{ */
2531 {
2532 php_sxe_object *sxe;
2533 xmlNodePtr node;
2534
2535 sxe = Z_SXEOBJ_P(object);
2536 GET_NODE(sxe, node);
2537 return php_sxe_get_first_node(sxe, node);
2538 }
2539 /* }}} */
2540
2541 /* {{{ proto simplemxml_element simplexml_import_dom(domNode node [, string class_name])
2542 Get a simplexml_element object from dom to allow for processing */
PHP_FUNCTION(simplexml_import_dom)2543 PHP_FUNCTION(simplexml_import_dom)
2544 {
2545 php_sxe_object *sxe;
2546 zval *node;
2547 php_libxml_node_object *object;
2548 xmlNodePtr nodep = NULL;
2549 zend_class_entry *ce = sxe_class_entry;
2550 zend_function *fptr_count;
2551
2552 if (zend_parse_parameters(ZEND_NUM_ARGS(), "o|C!", &node, &ce) == FAILURE) {
2553 return;
2554 }
2555
2556 object = Z_LIBXML_NODE_P(node);
2557
2558 nodep = php_libxml_import_node(node);
2559
2560 if (nodep) {
2561 if (nodep->doc == NULL) {
2562 php_error_docref(NULL, E_WARNING, "Imported Node must have associated Document");
2563 RETURN_NULL();
2564 }
2565 if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
2566 nodep = xmlDocGetRootElement((xmlDocPtr) nodep);
2567 }
2568 }
2569
2570 if (nodep && nodep->type == XML_ELEMENT_NODE) {
2571 if (!ce) {
2572 ce = sxe_class_entry;
2573 fptr_count = NULL;
2574 } else {
2575 fptr_count = php_sxe_find_fptr_count(ce);
2576 }
2577 sxe = php_sxe_object_new(ce, fptr_count);
2578 sxe->document = object->document;
2579 php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, nodep->doc);
2580 php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, nodep, NULL);
2581
2582 ZVAL_OBJ(return_value, &sxe->zo);
2583 } else {
2584 php_error_docref(NULL, E_WARNING, "Invalid Nodetype to import");
2585 RETVAL_NULL();
2586 }
2587 }
2588 /* }}} */
2589
2590 /* {{{ arginfo */
2591 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexml_load_file, 0, 0, 1)
2592 ZEND_ARG_INFO(0, filename)
2593 ZEND_ARG_INFO(0, class_name)
2594 ZEND_ARG_INFO(0, options)
2595 ZEND_ARG_INFO(0, ns)
2596 ZEND_ARG_INFO(0, is_prefix)
2597 ZEND_END_ARG_INFO()
2598
2599 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexml_load_string, 0, 0, 1)
2600 ZEND_ARG_INFO(0, data)
2601 ZEND_ARG_INFO(0, class_name)
2602 ZEND_ARG_INFO(0, options)
2603 ZEND_ARG_INFO(0, ns)
2604 ZEND_ARG_INFO(0, is_prefix)
2605 ZEND_END_ARG_INFO()
2606
2607 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexml_import_dom, 0, 0, 1)
2608 ZEND_ARG_INFO(0, node)
2609 ZEND_ARG_INFO(0, class_name)
2610 ZEND_END_ARG_INFO()
2611
2612 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_xpath, 0, 0, 1)
2613 ZEND_ARG_INFO(0, path)
2614 ZEND_END_ARG_INFO()
2615
2616 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_registerxpathnamespace, 0, 0, 2)
2617 ZEND_ARG_INFO(0, prefix)
2618 ZEND_ARG_INFO(0, ns)
2619 ZEND_END_ARG_INFO()
2620
2621 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_asxml, 0, 0, 0)
2622 ZEND_ARG_INFO(0, filename)
2623 ZEND_END_ARG_INFO()
2624
2625 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_getnamespaces, 0, 0, 0)
2626 ZEND_ARG_INFO(0, recursve)
2627 ZEND_END_ARG_INFO()
2628
2629 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_getdocnamespaces, 0, 0, 0)
2630 ZEND_ARG_INFO(0, recursve)
2631 ZEND_ARG_INFO(0, from_root)
2632 ZEND_END_ARG_INFO()
2633
2634 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_children, 0, 0, 0)
2635 ZEND_ARG_INFO(0, ns)
2636 ZEND_ARG_INFO(0, is_prefix)
2637 ZEND_END_ARG_INFO()
2638
2639 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement__construct, 0, 0, 1)
2640 ZEND_ARG_INFO(0, data)
2641 ZEND_ARG_INFO(0, options)
2642 ZEND_ARG_INFO(0, data_is_url)
2643 ZEND_ARG_INFO(0, ns)
2644 ZEND_ARG_INFO(0, is_prefix)
2645 ZEND_END_ARG_INFO()
2646
2647 ZEND_BEGIN_ARG_INFO(arginfo_simplexmlelement__void, 0)
2648 ZEND_END_ARG_INFO()
2649
2650 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_addchild, 0, 0, 1)
2651 ZEND_ARG_INFO(0, name)
2652 ZEND_ARG_INFO(0, value)
2653 ZEND_ARG_INFO(0, ns)
2654 ZEND_END_ARG_INFO()
2655 /* }}} */
2656
2657 const zend_function_entry simplexml_functions[] = { /* {{{ */
2658 PHP_FE(simplexml_load_file, arginfo_simplexml_load_file)
2659 PHP_FE(simplexml_load_string, arginfo_simplexml_load_string)
2660 PHP_FE(simplexml_import_dom, arginfo_simplexml_import_dom)
2661 PHP_FE_END
2662 };
2663 /* }}} */
2664
2665 static const zend_module_dep simplexml_deps[] = { /* {{{ */
2666 ZEND_MOD_REQUIRED("libxml")
2667 ZEND_MOD_REQUIRED("spl")
2668 ZEND_MOD_END
2669 };
2670 /* }}} */
2671
2672 zend_module_entry simplexml_module_entry = { /* {{{ */
2673 STANDARD_MODULE_HEADER_EX, NULL,
2674 simplexml_deps,
2675 "SimpleXML",
2676 simplexml_functions,
2677 PHP_MINIT(simplexml),
2678 PHP_MSHUTDOWN(simplexml),
2679 NULL,
2680 NULL,
2681 PHP_MINFO(simplexml),
2682 PHP_SIMPLEXML_VERSION,
2683 STANDARD_MODULE_PROPERTIES
2684 };
2685 /* }}} */
2686
2687 #ifdef COMPILE_DL_SIMPLEXML
2688 ZEND_GET_MODULE(simplexml)
2689 #endif
2690
2691 /* the method table */
2692 /* each method can have its own parameters and visibility */
2693 static const zend_function_entry sxe_functions[] = { /* {{{ */
2694 SXE_ME(__construct, arginfo_simplexmlelement__construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) /* must be called */
2695 SXE_ME(asXML, arginfo_simplexmlelement_asxml, ZEND_ACC_PUBLIC)
2696 SXE_MALIAS(saveXML, asXML, arginfo_simplexmlelement_asxml, ZEND_ACC_PUBLIC)
2697 SXE_ME(xpath, arginfo_simplexmlelement_xpath, ZEND_ACC_PUBLIC)
2698 SXE_ME(registerXPathNamespace, arginfo_simplexmlelement_registerxpathnamespace, ZEND_ACC_PUBLIC)
2699 SXE_ME(attributes, arginfo_simplexmlelement_children, ZEND_ACC_PUBLIC)
2700 SXE_ME(children, arginfo_simplexmlelement_children, ZEND_ACC_PUBLIC)
2701 SXE_ME(getNamespaces, arginfo_simplexmlelement_getnamespaces, ZEND_ACC_PUBLIC)
2702 SXE_ME(getDocNamespaces, arginfo_simplexmlelement_getdocnamespaces, ZEND_ACC_PUBLIC)
2703 SXE_ME(getName, arginfo_simplexmlelement__void, ZEND_ACC_PUBLIC)
2704 SXE_ME(addChild, arginfo_simplexmlelement_addchild, ZEND_ACC_PUBLIC)
2705 SXE_ME(addAttribute, arginfo_simplexmlelement_addchild, ZEND_ACC_PUBLIC)
2706 SXE_ME(__toString, arginfo_simplexmlelement__void, ZEND_ACC_PUBLIC)
2707 SXE_ME(count, arginfo_simplexmlelement__void, ZEND_ACC_PUBLIC)
2708 PHP_FE_END
2709 };
2710 /* }}} */
2711
2712 /* {{{ PHP_MINIT_FUNCTION(simplexml)
2713 */
PHP_MINIT_FUNCTION(simplexml)2714 PHP_MINIT_FUNCTION(simplexml)
2715 {
2716 zend_class_entry sxe;
2717
2718 INIT_CLASS_ENTRY(sxe, "SimpleXMLElement", sxe_functions);
2719 sxe.create_object = sxe_object_new;
2720 sxe_class_entry = zend_register_internal_class(&sxe);
2721 sxe_class_entry->get_iterator = php_sxe_get_iterator;
2722 sxe_class_entry->iterator_funcs.funcs = &php_sxe_iterator_funcs;
2723 zend_class_implements(sxe_class_entry, 1, zend_ce_traversable);
2724 sxe_object_handlers.offset = XtOffsetOf(php_sxe_object, zo);
2725 sxe_object_handlers.dtor_obj = sxe_object_dtor;
2726 sxe_object_handlers.free_obj = sxe_object_free_storage;
2727 sxe_object_handlers.clone_obj = sxe_object_clone;
2728 sxe_object_handlers.get_method = zend_get_std_object_handlers()->get_method;
2729 sxe_object_handlers.get_constructor = zend_get_std_object_handlers()->get_constructor;
2730 sxe_object_handlers.get_class_name = zend_get_std_object_handlers()->get_class_name;
2731 sxe_class_entry->serialize = zend_class_serialize_deny;
2732 sxe_class_entry->unserialize = zend_class_unserialize_deny;
2733
2734 php_libxml_register_export(sxe_class_entry, simplexml_export_node);
2735
2736 PHP_MINIT(sxe)(INIT_FUNC_ARGS_PASSTHRU);
2737
2738 return SUCCESS;
2739 }
2740 /* }}} */
2741
2742 /* {{{ PHP_MSHUTDOWN_FUNCTION(simplexml)
2743 */
PHP_MSHUTDOWN_FUNCTION(simplexml)2744 PHP_MSHUTDOWN_FUNCTION(simplexml)
2745 {
2746 sxe_class_entry = NULL;
2747 return SUCCESS;
2748 }
2749 /* }}} */
2750
2751 /* {{{ PHP_MINFO_FUNCTION(simplexml)
2752 */
PHP_MINFO_FUNCTION(simplexml)2753 PHP_MINFO_FUNCTION(simplexml)
2754 {
2755 php_info_print_table_start();
2756 php_info_print_table_header(2, "Simplexml support", "enabled");
2757 php_info_print_table_row(2, "Revision", "$Id: 341daed0ee94ea8f728bfd0ba4626e6ed365c0d1 $");
2758 php_info_print_table_row(2, "Schema support",
2759 #ifdef LIBXML_SCHEMAS_ENABLED
2760 "enabled");
2761 #else
2762 "not available");
2763 #endif
2764 php_info_print_table_end();
2765 }
2766 /* }}} */
2767
2768 #endif
2769
2770 /**
2771 * Local Variables:
2772 * c-basic-offset: 4
2773 * tab-width: 4
2774 * indent-tabs-mode: t
2775 * End:
2776 * vim600: fdm=marker
2777 * vim: noet sw=4 ts=4
2778 */
2779