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