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