1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2016 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: d7077fc935154236afb4fe70814ba358efdbdca4 $ */
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 void php_sxe_iterator_current_key(zend_object_iterator *iter, zval *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,int fetch_type,const zend_literal * key TSRMLS_DC)697 static zval** sxe_property_get_adr(zval *object, zval *member, int fetch_type, 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 ( sxe->iter.type == SXE_ITER_NONE || !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 if (!strval) {
1416 RETVAL_FALSE;
1417 } else {
1418 RETVAL_STRINGL((char *)strval, strval_len, 1);
1419 }
1420 xmlFree(strval);
1421 } else {
1422 char *return_content;
1423 size_t return_len;
1424 /* Should we be passing encoding information instead of NULL? */
1425 outbuf = xmlAllocOutputBuffer(NULL);
1426
1427 if (outbuf == NULL) {
1428 RETURN_FALSE;
1429 }
1430
1431 xmlNodeDumpOutput(outbuf, (xmlDocPtr) sxe->document->ptr, node, 0, 0, ((xmlDocPtr) sxe->document->ptr)->encoding);
1432 xmlOutputBufferFlush(outbuf);
1433 #ifdef LIBXML2_NEW_BUFFER
1434 return_content = (char *)xmlOutputBufferGetContent(outbuf);
1435 return_len = xmlOutputBufferGetSize(outbuf);
1436 #else
1437 return_content = (char *)outbuf->buffer->content;
1438 return_len = outbuf->buffer->use;
1439 #endif
1440 if (!return_content) {
1441 RETVAL_FALSE;
1442 } else {
1443 RETVAL_STRINGL_CHECK(return_content, return_len, 1);
1444 }
1445 xmlOutputBufferClose(outbuf);
1446 }
1447 } else {
1448 RETVAL_FALSE;
1449 }
1450 }
1451 /* }}} */
1452
1453 #define SXE_NS_PREFIX(ns) (ns->prefix ? (char*)ns->prefix : "")
1454
sxe_add_namespace_name(zval * return_value,xmlNsPtr ns)1455 static inline void sxe_add_namespace_name(zval *return_value, xmlNsPtr ns) /* {{{ */
1456 {
1457 char *prefix = SXE_NS_PREFIX(ns);
1458 if (zend_hash_exists(Z_ARRVAL_P(return_value), prefix, strlen(prefix) + 1) == 0) {
1459 add_assoc_string(return_value, prefix, (char*)ns->href, 1);
1460 }
1461 }
1462 /* }}} */
1463
sxe_add_namespaces(php_sxe_object * sxe,xmlNodePtr node,zend_bool recursive,zval * return_value TSRMLS_DC)1464 static void sxe_add_namespaces(php_sxe_object *sxe, xmlNodePtr node, zend_bool recursive, zval *return_value TSRMLS_DC) /* {{{ */
1465 {
1466 xmlAttrPtr attr;
1467
1468 if (node->ns) {
1469 sxe_add_namespace_name(return_value, node->ns);
1470 }
1471
1472 attr = node->properties;
1473 while (attr) {
1474 if (attr->ns) {
1475 sxe_add_namespace_name(return_value, attr->ns);
1476 }
1477 attr = attr->next;
1478 }
1479
1480 if (recursive) {
1481 node = node->children;
1482 while (node) {
1483 if (node->type == XML_ELEMENT_NODE) {
1484 sxe_add_namespaces(sxe, node, recursive, return_value TSRMLS_CC);
1485 }
1486 node = node->next;
1487 }
1488 }
1489 } /* }}} */
1490
1491 /* {{{ proto string SimpleXMLElement::getNamespaces([bool recursve])
1492 Return all namespaces in use */
SXE_METHOD(getNamespaces)1493 SXE_METHOD(getNamespaces)
1494 {
1495 zend_bool recursive = 0;
1496 php_sxe_object *sxe;
1497 xmlNodePtr node;
1498
1499 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &recursive) == FAILURE) {
1500 return;
1501 }
1502
1503 array_init(return_value);
1504
1505 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1506 GET_NODE(sxe, node);
1507 node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1508
1509 if (node) {
1510 if (node->type == XML_ELEMENT_NODE) {
1511 sxe_add_namespaces(sxe, node, recursive, return_value TSRMLS_CC);
1512 } else if (node->type == XML_ATTRIBUTE_NODE && node->ns) {
1513 sxe_add_namespace_name(return_value, node->ns);
1514 }
1515 }
1516 }
1517 /* }}} */
1518
sxe_add_registered_namespaces(php_sxe_object * sxe,xmlNodePtr node,zend_bool recursive,zval * return_value TSRMLS_DC)1519 static void sxe_add_registered_namespaces(php_sxe_object *sxe, xmlNodePtr node, zend_bool recursive, zval *return_value TSRMLS_DC) /* {{{ */
1520 {
1521 xmlNsPtr ns;
1522
1523 if (node->type == XML_ELEMENT_NODE) {
1524 ns = node->nsDef;
1525 while (ns != NULL) {
1526 sxe_add_namespace_name(return_value, ns);
1527 ns = ns->next;
1528 }
1529 if (recursive) {
1530 node = node->children;
1531 while (node) {
1532 sxe_add_registered_namespaces(sxe, node, recursive, return_value TSRMLS_CC);
1533 node = node->next;
1534 }
1535 }
1536 }
1537 }
1538 /* }}} */
1539
1540 /* {{{ proto string SimpleXMLElement::getDocNamespaces([bool recursive [, bool from_root])
1541 Return all namespaces registered with document */
SXE_METHOD(getDocNamespaces)1542 SXE_METHOD(getDocNamespaces)
1543 {
1544 zend_bool recursive = 0, from_root = 1;
1545 php_sxe_object *sxe;
1546 xmlNodePtr node;
1547
1548 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|bb", &recursive, &from_root) == FAILURE) {
1549 return;
1550 }
1551
1552 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1553 if(from_root){
1554 node = xmlDocGetRootElement((xmlDocPtr)sxe->document->ptr);
1555 }else{
1556 GET_NODE(sxe, node);
1557 }
1558
1559 if (node == NULL) {
1560 RETURN_FALSE;
1561 }
1562
1563 array_init(return_value);
1564 sxe_add_registered_namespaces(sxe, node, recursive, return_value TSRMLS_CC);
1565 }
1566 /* }}} */
1567
1568 /* {{{ proto object SimpleXMLElement::children([string ns [, bool is_prefix]])
1569 Finds children of given node */
SXE_METHOD(children)1570 SXE_METHOD(children)
1571 {
1572 php_sxe_object *sxe;
1573 char *nsprefix = NULL;
1574 int nsprefix_len = 0;
1575 xmlNodePtr node;
1576 zend_bool isprefix = 0;
1577
1578 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!b", &nsprefix, &nsprefix_len, &isprefix) == FAILURE) {
1579 return;
1580 }
1581
1582 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1583
1584 if (sxe->iter.type == SXE_ITER_ATTRLIST) {
1585 return; /* attributes don't have attributes */
1586 }
1587
1588 GET_NODE(sxe, node);
1589 node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1590
1591 _node_as_zval(sxe, node, return_value, SXE_ITER_CHILD, NULL, (xmlChar *)nsprefix, isprefix TSRMLS_CC);
1592
1593 }
1594 /* }}} */
1595
1596 /* {{{ proto object SimpleXMLElement::getName()
1597 Finds children of given node */
SXE_METHOD(getName)1598 SXE_METHOD(getName)
1599 {
1600 php_sxe_object *sxe;
1601 xmlNodePtr node;
1602 int namelen;
1603
1604 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1605
1606 GET_NODE(sxe, node);
1607 node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1608 if (node) {
1609 namelen = xmlStrlen(node->name);
1610 RETURN_STRINGL((char*)node->name, namelen, 1);
1611 } else {
1612 RETURN_EMPTY_STRING();
1613 }
1614 }
1615 /* }}} */
1616
1617 /* {{{ proto array SimpleXMLElement::attributes([string ns [, bool is_prefix]])
1618 Identifies an element's attributes */
SXE_METHOD(attributes)1619 SXE_METHOD(attributes)
1620 {
1621 php_sxe_object *sxe;
1622 char *nsprefix = NULL;
1623 int nsprefix_len = 0;
1624 xmlNodePtr node;
1625 zend_bool isprefix = 0;
1626
1627 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!b", &nsprefix, &nsprefix_len, &isprefix) == FAILURE) {
1628 return;
1629 }
1630
1631 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1632 GET_NODE(sxe, node);
1633
1634 if (sxe->iter.type == SXE_ITER_ATTRLIST) {
1635 return; /* attributes don't have attributes */
1636 }
1637
1638 node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1639
1640 _node_as_zval(sxe, node, return_value, SXE_ITER_ATTRLIST, NULL, (xmlChar *)nsprefix, isprefix TSRMLS_CC);
1641 }
1642 /* }}} */
1643
1644 /* {{{ proto void SimpleXMLElement::addChild(string qName [, string value [, string ns]])
1645 Add Element with optional namespace information */
SXE_METHOD(addChild)1646 SXE_METHOD(addChild)
1647 {
1648 php_sxe_object *sxe;
1649 char *qname, *value = NULL, *nsuri = NULL;
1650 int qname_len, value_len = 0, nsuri_len = 0;
1651 xmlNodePtr node, newnode;
1652 xmlNsPtr nsptr = NULL;
1653 xmlChar *localname, *prefix = NULL;
1654
1655 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!s!",
1656 &qname, &qname_len, &value, &value_len, &nsuri, &nsuri_len) == FAILURE) {
1657 return;
1658 }
1659
1660 if (qname_len == 0) {
1661 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Element name is required");
1662 return;
1663 }
1664
1665 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1666 GET_NODE(sxe, node);
1667
1668 if (sxe->iter.type == SXE_ITER_ATTRLIST) {
1669 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element to attributes");
1670 return;
1671 }
1672
1673 node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1674
1675 if (node == NULL) {
1676 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add child. Parent is not a permanent member of the XML tree");
1677 return;
1678 }
1679
1680 localname = xmlSplitQName2((xmlChar *)qname, &prefix);
1681 if (localname == NULL) {
1682 localname = xmlStrdup((xmlChar *)qname);
1683 }
1684
1685 newnode = xmlNewChild(node, NULL, localname, (xmlChar *)value);
1686
1687 if (nsuri != NULL) {
1688 if (nsuri_len == 0) {
1689 newnode->ns = NULL;
1690 nsptr = xmlNewNs(newnode, (xmlChar *)nsuri, prefix);
1691 } else {
1692 nsptr = xmlSearchNsByHref(node->doc, node, (xmlChar *)nsuri);
1693 if (nsptr == NULL) {
1694 nsptr = xmlNewNs(newnode, (xmlChar *)nsuri, prefix);
1695 }
1696 newnode->ns = nsptr;
1697 }
1698 }
1699
1700 _node_as_zval(sxe, newnode, return_value, SXE_ITER_NONE, (char *)localname, prefix, 0 TSRMLS_CC);
1701
1702 xmlFree(localname);
1703 if (prefix != NULL) {
1704 xmlFree(prefix);
1705 }
1706 }
1707 /* }}} */
1708
1709 /* {{{ proto void SimpleXMLElement::addAttribute(string qName, string value [,string ns])
1710 Add Attribute with optional namespace information */
SXE_METHOD(addAttribute)1711 SXE_METHOD(addAttribute)
1712 {
1713 php_sxe_object *sxe;
1714 char *qname, *value = NULL, *nsuri = NULL;
1715 int qname_len, value_len = 0, nsuri_len = 0;
1716 xmlNodePtr node;
1717 xmlAttrPtr attrp = NULL;
1718 xmlNsPtr nsptr = NULL;
1719 xmlChar *localname, *prefix = NULL;
1720
1721 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s!",
1722 &qname, &qname_len, &value, &value_len, &nsuri, &nsuri_len) == FAILURE) {
1723 return;
1724 }
1725
1726 if (qname_len == 0) {
1727 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attribute name is required");
1728 return;
1729 }
1730
1731 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1732 GET_NODE(sxe, node);
1733
1734 node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1735
1736 if (node && node->type != XML_ELEMENT_NODE) {
1737 node = node->parent;
1738 }
1739
1740 if (node == NULL) {
1741 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to locate parent Element");
1742 return;
1743 }
1744
1745 localname = xmlSplitQName2((xmlChar *)qname, &prefix);
1746 if (localname == NULL) {
1747 if (nsuri_len > 0) {
1748 if (prefix != NULL) {
1749 xmlFree(prefix);
1750 }
1751 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attribute requires prefix for namespace");
1752 return;
1753 }
1754 localname = xmlStrdup((xmlChar *)qname);
1755 }
1756
1757 attrp = xmlHasNsProp(node, localname, (xmlChar *)nsuri);
1758 if (attrp != NULL && attrp->type != XML_ATTRIBUTE_DECL) {
1759 xmlFree(localname);
1760 if (prefix != NULL) {
1761 xmlFree(prefix);
1762 }
1763 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attribute already exists");
1764 return;
1765 }
1766
1767 if (nsuri != NULL) {
1768 nsptr = xmlSearchNsByHref(node->doc, node, (xmlChar *)nsuri);
1769 if (nsptr == NULL) {
1770 nsptr = xmlNewNs(node, (xmlChar *)nsuri, prefix);
1771 }
1772 }
1773
1774 attrp = xmlNewNsProp(node, nsptr, localname, (xmlChar *)value);
1775
1776 xmlFree(localname);
1777 if (prefix != NULL) {
1778 xmlFree(prefix);
1779 }
1780 }
1781 /* }}} */
1782
1783 /* {{{ cast_object()
1784 */
cast_object(zval * object,int type,char * contents TSRMLS_DC)1785 static int cast_object(zval *object, int type, char *contents TSRMLS_DC)
1786 {
1787 if (contents) {
1788 ZVAL_STRINGL(object, contents, strlen(contents), 1);
1789 } else {
1790 ZVAL_NULL(object);
1791 }
1792 Z_SET_REFCOUNT_P(object, 1);
1793 Z_UNSET_ISREF_P(object);
1794
1795 switch (type) {
1796 case IS_STRING:
1797 convert_to_string(object);
1798 break;
1799 case IS_BOOL:
1800 convert_to_boolean(object);
1801 break;
1802 case IS_LONG:
1803 convert_to_long(object);
1804 break;
1805 case IS_DOUBLE:
1806 convert_to_double(object);
1807 break;
1808 default:
1809 return FAILURE;
1810 }
1811 return SUCCESS;
1812 }
1813 /* }}} */
1814
1815 /* {{{ sxe_object_cast()
1816 */
sxe_object_cast(zval * readobj,zval * writeobj,int type TSRMLS_DC)1817 static int sxe_object_cast(zval *readobj, zval *writeobj, int type TSRMLS_DC)
1818 {
1819 php_sxe_object *sxe;
1820 xmlChar *contents = NULL;
1821 xmlNodePtr node;
1822 int rv;
1823 HashTable *prop_hash;
1824
1825 sxe = php_sxe_fetch_object(readobj TSRMLS_CC);
1826
1827 if (type == IS_BOOL) {
1828 node = php_sxe_get_first_node(sxe, NULL TSRMLS_CC);
1829 prop_hash = sxe_get_prop_hash(readobj, 1 TSRMLS_CC);
1830 INIT_PZVAL(writeobj);
1831 ZVAL_BOOL(writeobj, node != NULL || zend_hash_num_elements(prop_hash) > 0);
1832 zend_hash_destroy(prop_hash);
1833 efree(prop_hash);
1834 return SUCCESS;
1835 }
1836
1837 if (sxe->iter.type != SXE_ITER_NONE) {
1838 node = php_sxe_get_first_node(sxe, NULL TSRMLS_CC);
1839 if (node) {
1840 contents = xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, node->children, 1);
1841 }
1842 } else {
1843 if (!sxe->node) {
1844 if (sxe->document) {
1845 php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement((xmlDocPtr) sxe->document->ptr), NULL TSRMLS_CC);
1846 }
1847 }
1848
1849 if (sxe->node && sxe->node->node) {
1850 if (sxe->node->node->children) {
1851 contents = xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, sxe->node->node->children, 1);
1852 }
1853 }
1854 }
1855
1856 if (readobj == writeobj) {
1857 INIT_PZVAL(writeobj);
1858 zval_dtor(readobj);
1859 }
1860
1861 rv = cast_object(writeobj, type, (char *)contents TSRMLS_CC);
1862
1863 if (contents) {
1864 xmlFree(contents);
1865 }
1866 return rv;
1867 }
1868 /* }}} */
1869
1870 /* {{{ proto object SimpleXMLElement::__toString() U
1871 Returns the string content */
SXE_METHOD(__toString)1872 SXE_METHOD(__toString)
1873 {
1874 zval *result;
1875
1876 ALLOC_INIT_ZVAL(result);
1877
1878 if (sxe_object_cast(getThis(), result, IS_STRING TSRMLS_CC) == SUCCESS) {
1879 RETURN_ZVAL(result, 1, 1);
1880 } else {
1881 zval_ptr_dtor(&result);
1882 RETURN_EMPTY_STRING();
1883 }
1884 }
1885 /* }}} */
1886
php_sxe_count_elements_helper(php_sxe_object * sxe,long * count TSRMLS_DC)1887 static int php_sxe_count_elements_helper(php_sxe_object *sxe, long *count TSRMLS_DC) /* {{{ */
1888 {
1889 xmlNodePtr node;
1890 zval *data;
1891
1892 *count = 0;
1893
1894 data = sxe->iter.data;
1895 sxe->iter.data = NULL;
1896
1897 node = php_sxe_reset_iterator(sxe, 0 TSRMLS_CC);
1898
1899 while (node)
1900 {
1901 (*count)++;
1902 node = php_sxe_iterator_fetch(sxe, node->next, 0 TSRMLS_CC);
1903 }
1904
1905 if (sxe->iter.data) {
1906 zval_ptr_dtor(&sxe->iter.data);
1907 }
1908 sxe->iter.data = data;
1909
1910 return SUCCESS;
1911 }
1912 /* }}} */
1913
sxe_count_elements(zval * object,long * count TSRMLS_DC)1914 static int sxe_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */
1915 {
1916 php_sxe_object *intern;
1917 intern = php_sxe_fetch_object(object TSRMLS_CC);
1918 if (intern->fptr_count) {
1919 zval *rv;
1920 zend_call_method_with_0_params(&object, intern->zo.ce, &intern->fptr_count, "count", &rv);
1921 if (rv) {
1922 if (intern->tmp) {
1923 zval_ptr_dtor(&intern->tmp);
1924 }
1925 MAKE_STD_ZVAL(intern->tmp);
1926 ZVAL_ZVAL(intern->tmp, rv, 1, 1);
1927 convert_to_long(intern->tmp);
1928 *count = (long) Z_LVAL_P(intern->tmp);
1929 return SUCCESS;
1930 }
1931 return FAILURE;
1932 }
1933 return php_sxe_count_elements_helper(intern, count TSRMLS_CC);
1934 }
1935 /* }}} */
1936
1937 /* {{{ proto int SimpleXMLElement::count()
1938 Get number of child elements */
SXE_METHOD(count)1939 SXE_METHOD(count)
1940 {
1941 long count = 0;
1942 php_sxe_object *sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1943
1944 if (zend_parse_parameters_none() == FAILURE) {
1945 return;
1946 }
1947
1948 php_sxe_count_elements_helper(sxe, &count TSRMLS_CC);
1949
1950 RETURN_LONG(count);
1951 }
1952 /* }}} */
1953
sxe_get_value(zval * z TSRMLS_DC)1954 static zval *sxe_get_value(zval *z TSRMLS_DC) /* {{{ */
1955 {
1956 zval *retval;
1957
1958 MAKE_STD_ZVAL(retval);
1959
1960 if (sxe_object_cast(z, retval, IS_STRING TSRMLS_CC)==FAILURE) {
1961 zend_error(E_ERROR, "Unable to cast node to string");
1962 /* FIXME: Should not be fatal */
1963 }
1964
1965 Z_SET_REFCOUNT_P(retval, 0);
1966 return retval;
1967 }
1968 /* }}} */
1969
1970 static zend_object_handlers sxe_object_handlers = { /* {{{ */
1971 ZEND_OBJECTS_STORE_HANDLERS,
1972 sxe_property_read,
1973 sxe_property_write,
1974 sxe_dimension_read,
1975 sxe_dimension_write,
1976 sxe_property_get_adr,
1977 sxe_get_value, /* get */
1978 NULL,
1979 sxe_property_exists,
1980 sxe_property_delete,
1981 sxe_dimension_exists,
1982 sxe_dimension_delete,
1983 sxe_get_properties,
1984 NULL, /* zend_get_std_object_handlers()->get_method,*/
1985 NULL, /* zend_get_std_object_handlers()->call_method,*/
1986 NULL, /* zend_get_std_object_handlers()->get_constructor, */
1987 NULL, /* zend_get_std_object_handlers()->get_class_entry,*/
1988 NULL, /* zend_get_std_object_handlers()->get_class_name,*/
1989 sxe_objects_compare,
1990 sxe_object_cast,
1991 sxe_count_elements,
1992 sxe_get_debug_info,
1993 NULL,
1994 sxe_get_gc
1995 };
1996 /* }}} */
1997
1998 /* {{{ sxe_object_clone()
1999 */
2000 static void
sxe_object_clone(void * object,void ** clone_ptr TSRMLS_DC)2001 sxe_object_clone(void *object, void **clone_ptr TSRMLS_DC)
2002 {
2003 php_sxe_object *sxe = (php_sxe_object *) object;
2004 php_sxe_object *clone;
2005 xmlNodePtr nodep = NULL;
2006 xmlDocPtr docp = NULL;
2007
2008 clone = php_sxe_object_new(sxe->zo.ce TSRMLS_CC);
2009 clone->document = sxe->document;
2010 if (clone->document) {
2011 clone->document->refcount++;
2012 docp = clone->document->ptr;
2013 }
2014
2015 clone->iter.isprefix = sxe->iter.isprefix;
2016 if (sxe->iter.name != NULL) {
2017 clone->iter.name = xmlStrdup((xmlChar *)sxe->iter.name);
2018 }
2019 if (sxe->iter.nsprefix != NULL) {
2020 clone->iter.nsprefix = xmlStrdup((xmlChar *)sxe->iter.nsprefix);
2021 }
2022 clone->iter.type = sxe->iter.type;
2023
2024 if (sxe->node) {
2025 nodep = xmlDocCopyNode(sxe->node->node, docp, 1);
2026 }
2027
2028 php_libxml_increment_node_ptr((php_libxml_node_object *)clone, nodep, NULL TSRMLS_CC);
2029
2030 *clone_ptr = (void *) clone;
2031 }
2032 /* }}} */
2033
2034 /* {{{ sxe_object_dtor()
2035 */
sxe_object_dtor(void * object,zend_object_handle handle TSRMLS_DC)2036 static void sxe_object_dtor(void *object, zend_object_handle handle TSRMLS_DC)
2037 {
2038 /* dtor required to cleanup iterator related data properly */
2039
2040 php_sxe_object *sxe;
2041
2042 sxe = (php_sxe_object *) object;
2043
2044 if (sxe->iter.data) {
2045 zval_ptr_dtor(&sxe->iter.data);
2046 sxe->iter.data = NULL;
2047 }
2048
2049 if (sxe->iter.name) {
2050 xmlFree(sxe->iter.name);
2051 sxe->iter.name = NULL;
2052 }
2053 if (sxe->iter.nsprefix) {
2054 xmlFree(sxe->iter.nsprefix);
2055 sxe->iter.nsprefix = NULL;
2056 }
2057 if (sxe->tmp) {
2058 zval_ptr_dtor(&sxe->tmp);
2059 sxe->tmp = NULL;
2060 }
2061 }
2062 /* }}} */
2063
2064 /* {{{ sxe_object_free_storage()
2065 */
sxe_object_free_storage(void * object TSRMLS_DC)2066 static void sxe_object_free_storage(void *object TSRMLS_DC)
2067 {
2068 php_sxe_object *sxe;
2069
2070 sxe = (php_sxe_object *) object;
2071
2072 #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)
2073 zend_object_std_dtor(&sxe->zo TSRMLS_CC);
2074 #else
2075 if (sxe->zo.guards) {
2076 zend_hash_destroy(sxe->zo.guards);
2077 FREE_HASHTABLE(sxe->zo.guards);
2078 }
2079
2080 if (sxe->zo.properties) {
2081 zend_hash_destroy(sxe->zo.properties);
2082 FREE_HASHTABLE(sxe->zo.properties);
2083 }
2084 #endif
2085
2086 php_libxml_node_decrement_resource((php_libxml_node_object *)sxe TSRMLS_CC);
2087
2088 if (sxe->xpath) {
2089 xmlXPathFreeContext(sxe->xpath);
2090 }
2091
2092 if (sxe->properties) {
2093 zend_hash_destroy(sxe->properties);
2094 FREE_HASHTABLE(sxe->properties);
2095 }
2096
2097 efree(object);
2098 }
2099 /* }}} */
2100
2101 /* {{{ php_sxe_object_new()
2102 */
php_sxe_object_new(zend_class_entry * ce TSRMLS_DC)2103 static php_sxe_object* php_sxe_object_new(zend_class_entry *ce TSRMLS_DC)
2104 {
2105 php_sxe_object *intern;
2106 zend_class_entry *parent = ce;
2107 int inherited = 0;
2108
2109 intern = ecalloc(1, sizeof(php_sxe_object));
2110
2111 intern->iter.type = SXE_ITER_NONE;
2112 intern->iter.nsprefix = NULL;
2113 intern->iter.name = NULL;
2114 intern->fptr_count = NULL;
2115
2116 #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)
2117 zend_object_std_init(&intern->zo, ce TSRMLS_CC);
2118 #else
2119 ALLOC_HASHTABLE(intern->zo.properties);
2120 zend_hash_init(intern->zo.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
2121
2122 intern->zo.ce = ce;
2123 intern->zo.guards = NULL;
2124 #endif
2125
2126 while (parent) {
2127 if (parent == sxe_class_entry) {
2128 break;
2129 }
2130
2131 parent = parent->parent;
2132 inherited = 1;
2133 }
2134
2135 if (inherited) {
2136 zend_hash_find(&ce->function_table, "count", sizeof("count"),(void **) &intern->fptr_count);
2137 if (intern->fptr_count->common.scope == parent) {
2138 intern->fptr_count = NULL;
2139 }
2140 }
2141
2142 return intern;
2143 }
2144 /* }}} */
2145
2146 /* {{{ php_sxe_register_object
2147 */
2148 static zend_object_value
php_sxe_register_object(php_sxe_object * intern TSRMLS_DC)2149 php_sxe_register_object(php_sxe_object *intern TSRMLS_DC)
2150 {
2151 zend_object_value rv;
2152
2153 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);
2154 rv.handlers = (zend_object_handlers *) &sxe_object_handlers;
2155
2156 return rv;
2157 }
2158 /* }}} */
2159
2160 /* {{{ sxe_object_new()
2161 */
2162 PHP_SXE_API zend_object_value
sxe_object_new(zend_class_entry * ce TSRMLS_DC)2163 sxe_object_new(zend_class_entry *ce TSRMLS_DC)
2164 {
2165 php_sxe_object *intern;
2166
2167 intern = php_sxe_object_new(ce TSRMLS_CC);
2168 return php_sxe_register_object(intern TSRMLS_CC);
2169 }
2170 /* }}} */
2171
2172 /* {{{ proto simplemxml_element simplexml_load_file(string filename [, string class_name [, int options [, string ns [, bool is_prefix]]]])
2173 Load a filename and return a simplexml_element object to allow for processing */
PHP_FUNCTION(simplexml_load_file)2174 PHP_FUNCTION(simplexml_load_file)
2175 {
2176 php_sxe_object *sxe;
2177 char *filename;
2178 int filename_len;
2179 xmlDocPtr docp;
2180 char *ns = NULL;
2181 int ns_len = 0;
2182 long options = 0;
2183 zend_class_entry *ce= sxe_class_entry;
2184 zend_bool isprefix = 0;
2185
2186 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p|C!lsb", &filename, &filename_len, &ce, &options, &ns, &ns_len, &isprefix) == FAILURE) {
2187 return;
2188 }
2189
2190 docp = xmlReadFile(filename, NULL, options);
2191
2192 if (! docp) {
2193 RETURN_FALSE;
2194 }
2195
2196 if (!ce) {
2197 ce = sxe_class_entry;
2198 }
2199 sxe = php_sxe_object_new(ce TSRMLS_CC);
2200 sxe->iter.nsprefix = ns_len ? xmlStrdup((xmlChar *)ns) : NULL;
2201 sxe->iter.isprefix = isprefix;
2202 php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp TSRMLS_CC);
2203 php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL TSRMLS_CC);
2204
2205 return_value->type = IS_OBJECT;
2206 return_value->value.obj = php_sxe_register_object(sxe TSRMLS_CC);
2207 }
2208 /* }}} */
2209
2210 /* {{{ proto simplemxml_element simplexml_load_string(string data [, string class_name [, int options [, string ns [, bool is_prefix]]]])
2211 Load a string and return a simplexml_element object to allow for processing */
PHP_FUNCTION(simplexml_load_string)2212 PHP_FUNCTION(simplexml_load_string)
2213 {
2214 php_sxe_object *sxe;
2215 char *data;
2216 int data_len;
2217 xmlDocPtr docp;
2218 char *ns = NULL;
2219 int ns_len = 0;
2220 long options = 0;
2221 zend_class_entry *ce= sxe_class_entry;
2222 zend_bool isprefix = 0;
2223
2224 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|C!lsb", &data, &data_len, &ce, &options, &ns, &ns_len, &isprefix) == FAILURE) {
2225 return;
2226 }
2227
2228 docp = xmlReadMemory(data, data_len, NULL, NULL, options);
2229
2230 if (! docp) {
2231 RETURN_FALSE;
2232 }
2233
2234 if (!ce) {
2235 ce = sxe_class_entry;
2236 }
2237 sxe = php_sxe_object_new(ce TSRMLS_CC);
2238 sxe->iter.nsprefix = ns_len ? xmlStrdup((xmlChar *)ns) : NULL;
2239 sxe->iter.isprefix = isprefix;
2240 php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp TSRMLS_CC);
2241 php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL TSRMLS_CC);
2242
2243 return_value->type = IS_OBJECT;
2244 return_value->value.obj = php_sxe_register_object(sxe TSRMLS_CC);
2245 }
2246 /* }}} */
2247
2248 /* {{{ proto SimpleXMLElement::__construct(string data [, int options [, bool data_is_url [, string ns [, bool is_prefix]]]])
2249 SimpleXMLElement constructor */
SXE_METHOD(__construct)2250 SXE_METHOD(__construct)
2251 {
2252 php_sxe_object *sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
2253 char *data, *ns = NULL;
2254 int data_len, ns_len = 0;
2255 xmlDocPtr docp;
2256 long options = 0;
2257 zend_bool is_url = 0, isprefix = 0;
2258 zend_error_handling error_handling;
2259
2260 zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
2261 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lbsb", &data, &data_len, &options, &is_url, &ns, &ns_len, &isprefix) == FAILURE) {
2262 zend_restore_error_handling(&error_handling TSRMLS_CC);
2263 return;
2264 }
2265
2266 zend_restore_error_handling(&error_handling TSRMLS_CC);
2267
2268 docp = is_url ? xmlReadFile(data, NULL, options) : xmlReadMemory(data, data_len, NULL, NULL, options);
2269
2270 if (!docp) {
2271 ((php_libxml_node_object *)sxe)->document = NULL;
2272 zend_throw_exception(zend_exception_get_default(TSRMLS_C), "String could not be parsed as XML", 0 TSRMLS_CC);
2273 return;
2274 }
2275
2276 sxe->iter.nsprefix = ns_len ? xmlStrdup((xmlChar *)ns) : NULL;
2277 sxe->iter.isprefix = isprefix;
2278 php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp TSRMLS_CC);
2279 php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL TSRMLS_CC);
2280 }
2281 /* }}} */
2282
2283 zend_object_iterator_funcs php_sxe_iterator_funcs = { /* {{{ */
2284 php_sxe_iterator_dtor,
2285 php_sxe_iterator_valid,
2286 php_sxe_iterator_current_data,
2287 php_sxe_iterator_current_key,
2288 php_sxe_iterator_move_forward,
2289 php_sxe_iterator_rewind,
2290 };
2291 /* }}} */
2292
php_sxe_iterator_fetch(php_sxe_object * sxe,xmlNodePtr node,int use_data TSRMLS_DC)2293 static xmlNodePtr php_sxe_iterator_fetch(php_sxe_object *sxe, xmlNodePtr node, int use_data TSRMLS_DC) /* {{{ */
2294 {
2295 xmlChar *prefix = sxe->iter.nsprefix;
2296 int isprefix = sxe->iter.isprefix;
2297 int test_elem = sxe->iter.type == SXE_ITER_ELEMENT && sxe->iter.name;
2298 int test_attr = sxe->iter.type == SXE_ITER_ATTRLIST && sxe->iter.name;
2299
2300 while (node) {
2301 SKIP_TEXT(node);
2302 if (sxe->iter.type != SXE_ITER_ATTRLIST && node->type == XML_ELEMENT_NODE) {
2303 if ((!test_elem || !xmlStrcmp(node->name, sxe->iter.name)) && match_ns(sxe, node, prefix, isprefix)) {
2304 break;
2305 }
2306 } else if (node->type == XML_ATTRIBUTE_NODE) {
2307 if ((!test_attr || !xmlStrcmp(node->name, sxe->iter.name)) && match_ns(sxe, node, prefix, isprefix)) {
2308 break;
2309 }
2310 }
2311 next_iter:
2312 node = node->next;
2313 }
2314
2315 if (node && use_data) {
2316 ALLOC_INIT_ZVAL(sxe->iter.data);
2317 _node_as_zval(sxe, node, sxe->iter.data, SXE_ITER_NONE, NULL, prefix, isprefix TSRMLS_CC);
2318 }
2319
2320 return node;
2321 }
2322 /* }}} */
2323
php_sxe_reset_iterator(php_sxe_object * sxe,int use_data TSRMLS_DC)2324 static xmlNodePtr php_sxe_reset_iterator(php_sxe_object *sxe, int use_data TSRMLS_DC) /* {{{ */
2325 {
2326 xmlNodePtr node;
2327
2328 if (sxe->iter.data) {
2329 zval_ptr_dtor(&sxe->iter.data);
2330 sxe->iter.data = NULL;
2331 }
2332
2333 GET_NODE(sxe, node)
2334
2335 if (node) {
2336 switch (sxe->iter.type) {
2337 case SXE_ITER_ELEMENT:
2338 case SXE_ITER_CHILD:
2339 case SXE_ITER_NONE:
2340 node = node->children;
2341 break;
2342 case SXE_ITER_ATTRLIST:
2343 node = (xmlNodePtr) node->properties;
2344 }
2345 return php_sxe_iterator_fetch(sxe, node, use_data TSRMLS_CC);
2346 }
2347 return NULL;
2348 }
2349 /* }}} */
2350
php_sxe_get_iterator(zend_class_entry * ce,zval * object,int by_ref TSRMLS_DC)2351 zend_object_iterator *php_sxe_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
2352 {
2353 php_sxe_iterator *iterator;
2354
2355 if (by_ref) {
2356 zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
2357 }
2358 iterator = emalloc(sizeof(php_sxe_iterator));
2359
2360 Z_ADDREF_P(object);
2361 iterator->intern.data = (void*)object;
2362 iterator->intern.funcs = &php_sxe_iterator_funcs;
2363 iterator->sxe = php_sxe_fetch_object(object TSRMLS_CC);
2364
2365 return (zend_object_iterator*)iterator;
2366 }
2367 /* }}} */
2368
php_sxe_iterator_dtor(zend_object_iterator * iter TSRMLS_DC)2369 static void php_sxe_iterator_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
2370 {
2371 php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2372
2373 /* cleanup handled in sxe_object_dtor as we dont always have an iterator wrapper */
2374 if (iterator->intern.data) {
2375 zval_ptr_dtor((zval**)&iterator->intern.data);
2376 }
2377
2378 efree(iterator);
2379 }
2380 /* }}} */
2381
php_sxe_iterator_valid(zend_object_iterator * iter TSRMLS_DC)2382 static int php_sxe_iterator_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
2383 {
2384 php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2385
2386 return iterator->sxe->iter.data ? SUCCESS : FAILURE;
2387 }
2388 /* }}} */
2389
php_sxe_iterator_current_data(zend_object_iterator * iter,zval *** data TSRMLS_DC)2390 static void php_sxe_iterator_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */
2391 {
2392 php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2393
2394 *data = &iterator->sxe->iter.data;
2395 }
2396 /* }}} */
2397
php_sxe_iterator_current_key(zend_object_iterator * iter,zval * key TSRMLS_DC)2398 static void php_sxe_iterator_current_key(zend_object_iterator *iter, zval *key TSRMLS_DC) /* {{{ */
2399 {
2400 php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2401 zval *curobj = iterator->sxe->iter.data;
2402 php_sxe_object *intern = (php_sxe_object *)zend_object_store_get_object(curobj TSRMLS_CC);
2403
2404 xmlNodePtr curnode = NULL;
2405 if (intern != NULL && intern->node != NULL) {
2406 curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->node)->node;
2407 }
2408
2409 if (curnode) {
2410 ZVAL_STRINGL(key, (char *) curnode->name, xmlStrlen(curnode->name), 1);
2411 } else {
2412 ZVAL_NULL(key);
2413 }
2414 }
2415 /* }}} */
2416
php_sxe_move_forward_iterator(php_sxe_object * sxe TSRMLS_DC)2417 PHP_SXE_API void php_sxe_move_forward_iterator(php_sxe_object *sxe TSRMLS_DC) /* {{{ */
2418 {
2419 xmlNodePtr node = NULL;
2420 php_sxe_object *intern;
2421
2422 if (sxe->iter.data) {
2423 intern = (php_sxe_object *)zend_object_store_get_object(sxe->iter.data TSRMLS_CC);
2424 GET_NODE(intern, node)
2425 zval_ptr_dtor(&sxe->iter.data);
2426 sxe->iter.data = NULL;
2427 }
2428
2429 if (node) {
2430 php_sxe_iterator_fetch(sxe, node->next, 1 TSRMLS_CC);
2431 }
2432 }
2433 /* }}} */
2434
php_sxe_iterator_move_forward(zend_object_iterator * iter TSRMLS_DC)2435 static void php_sxe_iterator_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
2436 {
2437 php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2438 php_sxe_move_forward_iterator(iterator->sxe TSRMLS_CC);
2439 }
2440 /* }}} */
2441
php_sxe_iterator_rewind(zend_object_iterator * iter TSRMLS_DC)2442 static void php_sxe_iterator_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
2443 {
2444 php_sxe_object *sxe;
2445
2446 php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2447 sxe = iterator->sxe;
2448
2449 php_sxe_reset_iterator(sxe, 1 TSRMLS_CC);
2450 }
2451 /* }}} */
2452
simplexml_export_node(zval * object TSRMLS_DC)2453 void *simplexml_export_node(zval *object TSRMLS_DC) /* {{{ */
2454 {
2455 php_sxe_object *sxe;
2456 xmlNodePtr node;
2457
2458 sxe = php_sxe_fetch_object(object TSRMLS_CC);
2459 GET_NODE(sxe, node);
2460 return php_sxe_get_first_node(sxe, node TSRMLS_CC);
2461 }
2462 /* }}} */
2463
2464 /* {{{ proto simplemxml_element simplexml_import_dom(domNode node [, string class_name])
2465 Get a simplexml_element object from dom to allow for processing */
PHP_FUNCTION(simplexml_import_dom)2466 PHP_FUNCTION(simplexml_import_dom)
2467 {
2468 php_sxe_object *sxe;
2469 zval *node;
2470 php_libxml_node_object *object;
2471 xmlNodePtr nodep = NULL;
2472 zend_class_entry *ce= sxe_class_entry;
2473
2474 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o|C!", &node, &ce) == FAILURE) {
2475 return;
2476 }
2477
2478 object = (php_libxml_node_object *)zend_object_store_get_object(node TSRMLS_CC);
2479
2480 nodep = php_libxml_import_node(node TSRMLS_CC);
2481
2482 if (nodep) {
2483 if (nodep->doc == NULL) {
2484 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Imported Node must have associated Document");
2485 RETURN_NULL();
2486 }
2487 if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
2488 nodep = xmlDocGetRootElement((xmlDocPtr) nodep);
2489 }
2490 }
2491
2492 if (nodep && nodep->type == XML_ELEMENT_NODE) {
2493 if (!ce) {
2494 ce = sxe_class_entry;
2495 }
2496 sxe = php_sxe_object_new(ce TSRMLS_CC);
2497 sxe->document = object->document;
2498 php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, nodep->doc TSRMLS_CC);
2499 php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, nodep, NULL TSRMLS_CC);
2500
2501 return_value->type = IS_OBJECT;
2502 return_value->value.obj = php_sxe_register_object(sxe TSRMLS_CC);
2503 } else {
2504 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Nodetype to import");
2505 RETVAL_NULL();
2506 }
2507 }
2508 /* }}} */
2509
2510 /* {{{ arginfo */
2511 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexml_load_file, 0, 0, 1)
2512 ZEND_ARG_INFO(0, filename)
2513 ZEND_ARG_INFO(0, class_name)
2514 ZEND_ARG_INFO(0, options)
2515 ZEND_ARG_INFO(0, ns)
2516 ZEND_ARG_INFO(0, is_prefix)
2517 ZEND_END_ARG_INFO()
2518
2519 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexml_load_string, 0, 0, 1)
2520 ZEND_ARG_INFO(0, data)
2521 ZEND_ARG_INFO(0, class_name)
2522 ZEND_ARG_INFO(0, options)
2523 ZEND_ARG_INFO(0, ns)
2524 ZEND_ARG_INFO(0, is_prefix)
2525 ZEND_END_ARG_INFO()
2526
2527 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexml_import_dom, 0, 0, 1)
2528 ZEND_ARG_INFO(0, node)
2529 ZEND_ARG_INFO(0, class_name)
2530 ZEND_END_ARG_INFO()
2531
2532 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_xpath, 0, 0, 1)
2533 ZEND_ARG_INFO(0, path)
2534 ZEND_END_ARG_INFO()
2535
2536 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_registerxpathnamespace, 0, 0, 2)
2537 ZEND_ARG_INFO(0, prefix)
2538 ZEND_ARG_INFO(0, ns)
2539 ZEND_END_ARG_INFO()
2540
2541 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_asxml, 0, 0, 0)
2542 ZEND_ARG_INFO(0, filename)
2543 ZEND_END_ARG_INFO()
2544
2545 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_getnamespaces, 0, 0, 0)
2546 ZEND_ARG_INFO(0, recursve)
2547 ZEND_END_ARG_INFO()
2548
2549 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_getdocnamespaces, 0, 0, 0)
2550 ZEND_ARG_INFO(0, recursve)
2551 ZEND_ARG_INFO(0, from_root)
2552 ZEND_END_ARG_INFO()
2553
2554 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_children, 0, 0, 0)
2555 ZEND_ARG_INFO(0, ns)
2556 ZEND_ARG_INFO(0, is_prefix)
2557 ZEND_END_ARG_INFO()
2558
2559 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement__construct, 0, 0, 1)
2560 ZEND_ARG_INFO(0, data)
2561 ZEND_ARG_INFO(0, options)
2562 ZEND_ARG_INFO(0, data_is_url)
2563 ZEND_ARG_INFO(0, ns)
2564 ZEND_ARG_INFO(0, is_prefix)
2565 ZEND_END_ARG_INFO()
2566
2567 ZEND_BEGIN_ARG_INFO(arginfo_simplexmlelement__void, 0)
2568 ZEND_END_ARG_INFO()
2569
2570 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_addchild, 0, 0, 1)
2571 ZEND_ARG_INFO(0, name)
2572 ZEND_ARG_INFO(0, value)
2573 ZEND_ARG_INFO(0, ns)
2574 ZEND_END_ARG_INFO()
2575 /* }}} */
2576
2577 const zend_function_entry simplexml_functions[] = { /* {{{ */
2578 PHP_FE(simplexml_load_file, arginfo_simplexml_load_file)
2579 PHP_FE(simplexml_load_string, arginfo_simplexml_load_string)
2580 PHP_FE(simplexml_import_dom, arginfo_simplexml_import_dom)
2581 PHP_FE_END
2582 };
2583 /* }}} */
2584
2585 static const zend_module_dep simplexml_deps[] = { /* {{{ */
2586 ZEND_MOD_REQUIRED("libxml")
2587 ZEND_MOD_REQUIRED("spl")
2588 ZEND_MOD_END
2589 };
2590 /* }}} */
2591
2592 zend_module_entry simplexml_module_entry = { /* {{{ */
2593 STANDARD_MODULE_HEADER_EX, NULL,
2594 simplexml_deps,
2595 "SimpleXML",
2596 simplexml_functions,
2597 PHP_MINIT(simplexml),
2598 PHP_MSHUTDOWN(simplexml),
2599 NULL,
2600 NULL,
2601 PHP_MINFO(simplexml),
2602 "0.1",
2603 STANDARD_MODULE_PROPERTIES
2604 };
2605 /* }}} */
2606
2607 #ifdef COMPILE_DL_SIMPLEXML
2608 ZEND_GET_MODULE(simplexml)
2609 #endif
2610
2611 /* the method table */
2612 /* each method can have its own parameters and visibility */
2613 static const zend_function_entry sxe_functions[] = { /* {{{ */
2614 SXE_ME(__construct, arginfo_simplexmlelement__construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) /* must be called */
2615 SXE_ME(asXML, arginfo_simplexmlelement_asxml, ZEND_ACC_PUBLIC)
2616 SXE_MALIAS(saveXML, asXML, arginfo_simplexmlelement_asxml, ZEND_ACC_PUBLIC)
2617 SXE_ME(xpath, arginfo_simplexmlelement_xpath, ZEND_ACC_PUBLIC)
2618 SXE_ME(registerXPathNamespace, arginfo_simplexmlelement_registerxpathnamespace, ZEND_ACC_PUBLIC)
2619 SXE_ME(attributes, arginfo_simplexmlelement_children, ZEND_ACC_PUBLIC)
2620 SXE_ME(children, arginfo_simplexmlelement_children, ZEND_ACC_PUBLIC)
2621 SXE_ME(getNamespaces, arginfo_simplexmlelement_getnamespaces, ZEND_ACC_PUBLIC)
2622 SXE_ME(getDocNamespaces, arginfo_simplexmlelement_getdocnamespaces, ZEND_ACC_PUBLIC)
2623 SXE_ME(getName, arginfo_simplexmlelement__void, ZEND_ACC_PUBLIC)
2624 SXE_ME(addChild, arginfo_simplexmlelement_addchild, ZEND_ACC_PUBLIC)
2625 SXE_ME(addAttribute, arginfo_simplexmlelement_addchild, ZEND_ACC_PUBLIC)
2626 SXE_ME(__toString, arginfo_simplexmlelement__void, ZEND_ACC_PUBLIC)
2627 SXE_ME(count, arginfo_simplexmlelement__void, ZEND_ACC_PUBLIC)
2628 PHP_FE_END
2629 };
2630 /* }}} */
2631
2632 /* {{{ PHP_MINIT_FUNCTION(simplexml)
2633 */
PHP_MINIT_FUNCTION(simplexml)2634 PHP_MINIT_FUNCTION(simplexml)
2635 {
2636 zend_class_entry sxe;
2637
2638 INIT_CLASS_ENTRY(sxe, "SimpleXMLElement", sxe_functions);
2639 sxe.create_object = sxe_object_new;
2640 sxe_class_entry = zend_register_internal_class(&sxe TSRMLS_CC);
2641 sxe_class_entry->get_iterator = php_sxe_get_iterator;
2642 sxe_class_entry->iterator_funcs.funcs = &php_sxe_iterator_funcs;
2643 zend_class_implements(sxe_class_entry TSRMLS_CC, 1, zend_ce_traversable);
2644 sxe_object_handlers.get_method = zend_get_std_object_handlers()->get_method;
2645 sxe_object_handlers.get_constructor = zend_get_std_object_handlers()->get_constructor;
2646 sxe_object_handlers.get_class_entry = zend_get_std_object_handlers()->get_class_entry;
2647 sxe_object_handlers.get_class_name = zend_get_std_object_handlers()->get_class_name;
2648 sxe_class_entry->serialize = zend_class_serialize_deny;
2649 sxe_class_entry->unserialize = zend_class_unserialize_deny;
2650
2651 php_libxml_register_export(sxe_class_entry, simplexml_export_node);
2652
2653 PHP_MINIT(sxe)(INIT_FUNC_ARGS_PASSTHRU);
2654
2655 return SUCCESS;
2656 }
2657 /* }}} */
2658
2659 /* {{{ PHP_MSHUTDOWN_FUNCTION(simplexml)
2660 */
PHP_MSHUTDOWN_FUNCTION(simplexml)2661 PHP_MSHUTDOWN_FUNCTION(simplexml)
2662 {
2663 sxe_class_entry = NULL;
2664 return SUCCESS;
2665 }
2666 /* }}} */
2667
2668 /* {{{ PHP_MINFO_FUNCTION(simplexml)
2669 */
PHP_MINFO_FUNCTION(simplexml)2670 PHP_MINFO_FUNCTION(simplexml)
2671 {
2672 php_info_print_table_start();
2673 php_info_print_table_header(2, "Simplexml support", "enabled");
2674 php_info_print_table_row(2, "Revision", "$Id: d7077fc935154236afb4fe70814ba358efdbdca4 $");
2675 php_info_print_table_row(2, "Schema support",
2676 #ifdef LIBXML_SCHEMAS_ENABLED
2677 "enabled");
2678 #else
2679 "not available");
2680 #endif
2681 php_info_print_table_end();
2682 }
2683 /* }}} */
2684
2685 #endif
2686
2687 /**
2688 * Local Variables:
2689 * c-basic-offset: 4
2690 * tab-width: 4
2691 * indent-tabs-mode: t
2692 * End:
2693 * vim600: fdm=marker
2694 * vim: noet sw=4 ts=4
2695 */
2696