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