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