1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2013 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: 02ab7893b36d51e9c59da77d7e287eb3b35e1e32 $ */
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 TSRMLS_DC)392 static zval * sxe_property_read(zval *object, zval *member, int type 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 TSRMLS_DC)683 static void sxe_property_write(zval *object, zval *member, zval *value 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 TSRMLS_DC)697 static zval** sxe_property_get_adr(zval *object, zval *member 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 TSRMLS_DC)849 static int sxe_property_exists(zval *object, zval *member, int check_empty 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 TSRMLS_DC)974 static void sxe_property_delete(zval *object, zval *member 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
1073 sxe = php_sxe_fetch_object(object TSRMLS_CC);
1074
1075 if (is_debug) {
1076 ALLOC_HASHTABLE(rv);
1077 zend_hash_init(rv, 0, NULL, ZVAL_PTR_DTOR, 0);
1078 }
1079 else if (sxe->properties) {
1080 if (GC_G(gc_active)) {
1081 return sxe->properties;
1082 }
1083 zend_hash_clean(sxe->properties);
1084 rv = sxe->properties;
1085 } else {
1086 if (GC_G(gc_active)) {
1087 return NULL;
1088 }
1089 ALLOC_HASHTABLE(rv);
1090 zend_hash_init(rv, 0, NULL, ZVAL_PTR_DTOR, 0);
1091 sxe->properties = rv;
1092 }
1093
1094 GET_NODE(sxe, node);
1095 if (!node) {
1096 return rv;
1097 }
1098 if (is_debug || sxe->iter.type != SXE_ITER_CHILD) {
1099 if (sxe->iter.type == SXE_ITER_ELEMENT) {
1100 node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1101 }
1102 if (!node || node->type != XML_ENTITY_DECL) {
1103 attr = node ? (xmlAttrPtr)node->properties : NULL;
1104 zattr = NULL;
1105 test = sxe->iter.name && sxe->iter.type == SXE_ITER_ATTRLIST;
1106 while (attr) {
1107 if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr)attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
1108 MAKE_STD_ZVAL(value);
1109 ZVAL_STRING(value, sxe_xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, attr->children, 1), 0);
1110 namelen = xmlStrlen(attr->name) + 1;
1111 if (!zattr) {
1112 MAKE_STD_ZVAL(zattr);
1113 array_init(zattr);
1114 sxe_properties_add(rv, "@attributes", sizeof("@attributes"), zattr TSRMLS_CC);
1115 }
1116 add_assoc_zval_ex(zattr, (char*)attr->name, namelen, value);
1117 }
1118 attr = attr->next;
1119 }
1120 }
1121 }
1122
1123 GET_NODE(sxe, node);
1124 node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1125 if (node && sxe->iter.type != SXE_ITER_ATTRLIST) {
1126 if (node->type == XML_ATTRIBUTE_NODE) {
1127 MAKE_STD_ZVAL(value);
1128 ZVAL_STRING(value, sxe_xmlNodeListGetString(node->doc, node->children, 1), 0);
1129 zend_hash_next_index_insert(rv, &value, sizeof(zval *), NULL);
1130 node = NULL;
1131 } else if (sxe->iter.type != SXE_ITER_CHILD) {
1132 node = node->children;
1133 }
1134
1135 while (node) {
1136 if (node->children != NULL || node->prev != NULL || node->next != NULL) {
1137 SKIP_TEXT(node);
1138 } else {
1139 if (node->type == XML_TEXT_NODE) {
1140 const xmlChar *cur = node->content;
1141
1142 if (*cur != 0) {
1143 MAKE_STD_ZVAL(value);
1144 ZVAL_STRING(value, sxe_xmlNodeListGetString(node->doc, node, 1), 0);
1145 zend_hash_next_index_insert(rv, &value, sizeof(zval *), NULL);
1146 }
1147 goto next_iter;
1148 }
1149 }
1150
1151 if (node->type == XML_ELEMENT_NODE && (! match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix))) {
1152 goto next_iter;
1153 }
1154
1155 name = (char *) node->name;
1156 if (!name) {
1157 goto next_iter;
1158 } else {
1159 namelen = xmlStrlen(node->name) + 1;
1160 }
1161
1162 _get_base_node_value(sxe, node, &value, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
1163
1164 sxe_properties_add(rv, name, namelen, value TSRMLS_CC);
1165 next_iter:
1166 node = node->next;
1167 }
1168 }
1169
1170 return rv;
1171 }
1172 /* }}} */
1173
sxe_get_properties(zval * object TSRMLS_DC)1174 static HashTable * sxe_get_properties(zval *object TSRMLS_DC) /* {{{ */
1175 {
1176 return sxe_get_prop_hash(object, 0 TSRMLS_CC);
1177 }
1178 /* }}} */
1179
sxe_get_debug_info(zval * object,int * is_temp TSRMLS_DC)1180 static HashTable * sxe_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */
1181 {
1182 *is_temp = 1;
1183 return sxe_get_prop_hash(object, 1 TSRMLS_CC);
1184 }
1185 /* }}} */
1186
sxe_objects_compare(zval * object1,zval * object2 TSRMLS_DC)1187 static int sxe_objects_compare(zval *object1, zval *object2 TSRMLS_DC) /* {{{ */
1188 {
1189 php_sxe_object *sxe1;
1190 php_sxe_object *sxe2;
1191
1192 sxe1 = php_sxe_fetch_object(object1 TSRMLS_CC);
1193 sxe2 = php_sxe_fetch_object(object2 TSRMLS_CC);
1194
1195 if (sxe1->node == NULL) {
1196 if (sxe2->node) {
1197 return 1;
1198 } else if (sxe1->document->ptr == sxe2->document->ptr) {
1199 return 0;
1200 }
1201 } else {
1202 return !(sxe1->node == sxe2->node);
1203 }
1204 return 1;
1205 }
1206 /* }}} */
1207
1208 /* {{{ proto array SimpleXMLElement::xpath(string path)
1209 Runs XPath query on the XML data */
SXE_METHOD(xpath)1210 SXE_METHOD(xpath)
1211 {
1212 php_sxe_object *sxe;
1213 zval *value;
1214 char *query;
1215 int query_len;
1216 int i;
1217 int nsnbr = 0;
1218 xmlNsPtr *ns = NULL;
1219 xmlXPathObjectPtr retval;
1220 xmlNodeSetPtr result;
1221 xmlNodePtr nodeptr;
1222
1223 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &query, &query_len) == FAILURE) {
1224 return;
1225 }
1226
1227 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1228
1229 if (sxe->iter.type == SXE_ITER_ATTRLIST) {
1230 return; /* attributes don't have attributes */
1231 }
1232
1233 if (!sxe->xpath) {
1234 sxe->xpath = xmlXPathNewContext((xmlDocPtr) sxe->document->ptr);
1235 }
1236 if (!sxe->node) {
1237 php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement((xmlDocPtr) sxe->document->ptr), NULL TSRMLS_CC);
1238 }
1239
1240 nodeptr = php_sxe_get_first_node(sxe, sxe->node->node TSRMLS_CC);
1241
1242 sxe->xpath->node = nodeptr;
1243
1244 ns = xmlGetNsList((xmlDocPtr) sxe->document->ptr, nodeptr);
1245 if (ns != NULL) {
1246 while (ns[nsnbr] != NULL) {
1247 nsnbr++;
1248 }
1249 }
1250
1251 sxe->xpath->namespaces = ns;
1252 sxe->xpath->nsNr = nsnbr;
1253
1254 retval = xmlXPathEval((xmlChar *)query, sxe->xpath);
1255 if (ns != NULL) {
1256 xmlFree(ns);
1257 sxe->xpath->namespaces = NULL;
1258 sxe->xpath->nsNr = 0;
1259 }
1260
1261 if (!retval) {
1262 RETURN_FALSE;
1263 }
1264
1265 result = retval->nodesetval;
1266
1267 array_init(return_value);
1268
1269 if (result != NULL) {
1270 for (i = 0; i < result->nodeNr; ++i) {
1271 nodeptr = result->nodeTab[i];
1272 if (nodeptr->type == XML_TEXT_NODE || nodeptr->type == XML_ELEMENT_NODE || nodeptr->type == XML_ATTRIBUTE_NODE) {
1273 MAKE_STD_ZVAL(value);
1274 /**
1275 * Detect the case where the last selector is text(), simplexml
1276 * always accesses the text() child by default, therefore we assign
1277 * to the parent node.
1278 */
1279 if (nodeptr->type == XML_TEXT_NODE) {
1280 _node_as_zval(sxe, nodeptr->parent, value, SXE_ITER_NONE, NULL, NULL, 0 TSRMLS_CC);
1281 } else if (nodeptr->type == XML_ATTRIBUTE_NODE) {
1282 _node_as_zval(sxe, nodeptr->parent, value, SXE_ITER_ATTRLIST, (char*)nodeptr->name, nodeptr->ns ? (xmlChar *)nodeptr->ns->href : NULL, 0 TSRMLS_CC);
1283 } else {
1284 _node_as_zval(sxe, nodeptr, value, SXE_ITER_NONE, NULL, NULL, 0 TSRMLS_CC);
1285 }
1286
1287 add_next_index_zval(return_value, value);
1288 }
1289 }
1290 }
1291
1292 xmlXPathFreeObject(retval);
1293 }
1294 /* }}} */
1295
1296 /* {{{ proto bool SimpleXMLElement::registerXPathNamespace(string prefix, string ns)
1297 Creates a prefix/ns context for the next XPath query */
SXE_METHOD(registerXPathNamespace)1298 SXE_METHOD(registerXPathNamespace)
1299 {
1300 php_sxe_object *sxe;
1301 int prefix_len, ns_uri_len;
1302 char *prefix, *ns_uri;
1303
1304 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &prefix, &prefix_len, &ns_uri, &ns_uri_len) == FAILURE) {
1305 return;
1306 }
1307
1308 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1309 if (!sxe->xpath) {
1310 sxe->xpath = xmlXPathNewContext((xmlDocPtr) sxe->document->ptr);
1311 }
1312
1313 if (xmlXPathRegisterNs(sxe->xpath, (xmlChar *)prefix, (xmlChar *)ns_uri) != 0) {
1314 RETURN_FALSE
1315 }
1316 RETURN_TRUE;
1317 }
1318
1319 /* }}} */
1320
1321 /* {{{ proto string SimpleXMLElement::asXML([string filename])
1322 Return a well-formed XML string based on SimpleXML element */
SXE_METHOD(asXML)1323 SXE_METHOD(asXML)
1324 {
1325 php_sxe_object *sxe;
1326 xmlNodePtr node;
1327 xmlOutputBufferPtr outbuf;
1328 xmlChar *strval;
1329 int strval_len;
1330 char *filename;
1331 int filename_len;
1332
1333 if (ZEND_NUM_ARGS() > 1) {
1334 RETURN_FALSE;
1335 }
1336
1337 if (ZEND_NUM_ARGS() == 1) {
1338 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
1339 RETURN_FALSE;
1340 }
1341
1342 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1343 GET_NODE(sxe, node);
1344 node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1345
1346 if (node) {
1347 if (node->parent && (XML_DOCUMENT_NODE == node->parent->type)) {
1348 int bytes;
1349 bytes = xmlSaveFile(filename, (xmlDocPtr) sxe->document->ptr);
1350 if (bytes == -1) {
1351 RETURN_FALSE;
1352 } else {
1353 RETURN_TRUE;
1354 }
1355 } else {
1356 outbuf = xmlOutputBufferCreateFilename(filename, NULL, 0);
1357
1358 if (outbuf == NULL) {
1359 RETURN_FALSE;
1360 }
1361
1362 xmlNodeDumpOutput(outbuf, (xmlDocPtr) sxe->document->ptr, node, 0, 0, NULL);
1363 xmlOutputBufferClose(outbuf);
1364 RETURN_TRUE;
1365 }
1366 } else {
1367 RETURN_FALSE;
1368 }
1369 }
1370
1371 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1372 GET_NODE(sxe, node);
1373 node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1374
1375 if (node) {
1376 if (node->parent && (XML_DOCUMENT_NODE == node->parent->type)) {
1377 xmlDocDumpMemoryEnc((xmlDocPtr) sxe->document->ptr, &strval, &strval_len, ((xmlDocPtr) sxe->document->ptr)->encoding);
1378 RETVAL_STRINGL((char *)strval, strval_len, 1);
1379 xmlFree(strval);
1380 } else {
1381 /* Should we be passing encoding information instead of NULL? */
1382 outbuf = xmlAllocOutputBuffer(NULL);
1383
1384 if (outbuf == NULL) {
1385 RETURN_FALSE;
1386 }
1387
1388 xmlNodeDumpOutput(outbuf, (xmlDocPtr) sxe->document->ptr, node, 0, 0, ((xmlDocPtr) sxe->document->ptr)->encoding);
1389 xmlOutputBufferFlush(outbuf);
1390 #ifdef LIBXML2_NEW_BUFFER
1391 RETVAL_STRINGL((char *)xmlOutputBufferGetContent(outbuf), xmlOutputBufferGetSize(outbuf), 1);
1392 #else
1393 RETVAL_STRINGL((char *)outbuf->buffer->content, outbuf->buffer->use, 1);
1394 #endif
1395 xmlOutputBufferClose(outbuf);
1396 }
1397 } else {
1398 RETVAL_FALSE;
1399 }
1400 }
1401 /* }}} */
1402
1403 #define SXE_NS_PREFIX(ns) (ns->prefix ? (char*)ns->prefix : "")
1404
sxe_add_namespace_name(zval * return_value,xmlNsPtr ns)1405 static inline void sxe_add_namespace_name(zval *return_value, xmlNsPtr ns) /* {{{ */
1406 {
1407 char *prefix = SXE_NS_PREFIX(ns);
1408 if (zend_hash_exists(Z_ARRVAL_P(return_value), prefix, strlen(prefix) + 1) == 0) {
1409 add_assoc_string(return_value, prefix, (char*)ns->href, 1);
1410 }
1411 }
1412 /* }}} */
1413
sxe_add_namespaces(php_sxe_object * sxe,xmlNodePtr node,zend_bool recursive,zval * return_value TSRMLS_DC)1414 static void sxe_add_namespaces(php_sxe_object *sxe, xmlNodePtr node, zend_bool recursive, zval *return_value TSRMLS_DC) /* {{{ */
1415 {
1416 xmlAttrPtr attr;
1417
1418 if (node->ns) {
1419 sxe_add_namespace_name(return_value, node->ns);
1420 }
1421
1422 attr = node->properties;
1423 while (attr) {
1424 if (attr->ns) {
1425 sxe_add_namespace_name(return_value, attr->ns);
1426 }
1427 attr = attr->next;
1428 }
1429
1430 if (recursive) {
1431 node = node->children;
1432 while (node) {
1433 if (node->type == XML_ELEMENT_NODE) {
1434 sxe_add_namespaces(sxe, node, recursive, return_value TSRMLS_CC);
1435 }
1436 node = node->next;
1437 }
1438 }
1439 } /* }}} */
1440
1441 /* {{{ proto string SimpleXMLElement::getNamespaces([bool recursve])
1442 Return all namespaces in use */
SXE_METHOD(getNamespaces)1443 SXE_METHOD(getNamespaces)
1444 {
1445 zend_bool recursive = 0;
1446 php_sxe_object *sxe;
1447 xmlNodePtr node;
1448
1449 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &recursive) == FAILURE) {
1450 return;
1451 }
1452
1453 array_init(return_value);
1454
1455 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1456 GET_NODE(sxe, node);
1457 node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1458
1459 if (node) {
1460 if (node->type == XML_ELEMENT_NODE) {
1461 sxe_add_namespaces(sxe, node, recursive, return_value TSRMLS_CC);
1462 } else if (node->type == XML_ATTRIBUTE_NODE && node->ns) {
1463 sxe_add_namespace_name(return_value, node->ns);
1464 }
1465 }
1466 }
1467 /* }}} */
1468
sxe_add_registered_namespaces(php_sxe_object * sxe,xmlNodePtr node,zend_bool recursive,zval * return_value TSRMLS_DC)1469 static void sxe_add_registered_namespaces(php_sxe_object *sxe, xmlNodePtr node, zend_bool recursive, zval *return_value TSRMLS_DC) /* {{{ */
1470 {
1471 xmlNsPtr ns;
1472
1473 if (node->type == XML_ELEMENT_NODE) {
1474 ns = node->nsDef;
1475 while (ns != NULL) {
1476 sxe_add_namespace_name(return_value, ns);
1477 ns = ns->next;
1478 }
1479 if (recursive) {
1480 node = node->children;
1481 while (node) {
1482 sxe_add_registered_namespaces(sxe, node, recursive, return_value TSRMLS_CC);
1483 node = node->next;
1484 }
1485 }
1486 }
1487 }
1488 /* }}} */
1489
1490 /* {{{ proto string SimpleXMLElement::getDocNamespaces([bool recursive])
1491 Return all namespaces registered with document */
SXE_METHOD(getDocNamespaces)1492 SXE_METHOD(getDocNamespaces)
1493 {
1494 zend_bool recursive = 0;
1495 php_sxe_object *sxe;
1496
1497 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &recursive) == FAILURE) {
1498 return;
1499 }
1500
1501 array_init(return_value);
1502
1503 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1504
1505 sxe_add_registered_namespaces(sxe, xmlDocGetRootElement((xmlDocPtr)sxe->document->ptr), recursive, return_value TSRMLS_CC);
1506 }
1507 /* }}} */
1508
1509 /* {{{ proto object SimpleXMLElement::children([string ns [, bool is_prefix]])
1510 Finds children of given node */
SXE_METHOD(children)1511 SXE_METHOD(children)
1512 {
1513 php_sxe_object *sxe;
1514 char *nsprefix = NULL;
1515 int nsprefix_len = 0;
1516 xmlNodePtr node;
1517 zend_bool isprefix = 0;
1518
1519 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!b", &nsprefix, &nsprefix_len, &isprefix) == FAILURE) {
1520 return;
1521 }
1522
1523 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1524
1525 if (sxe->iter.type == SXE_ITER_ATTRLIST) {
1526 return; /* attributes don't have attributes */
1527 }
1528
1529 GET_NODE(sxe, node);
1530 node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1531
1532 _node_as_zval(sxe, node, return_value, SXE_ITER_CHILD, NULL, (xmlChar *)nsprefix, isprefix TSRMLS_CC);
1533
1534 }
1535 /* }}} */
1536
1537 /* {{{ proto object SimpleXMLElement::getName()
1538 Finds children of given node */
SXE_METHOD(getName)1539 SXE_METHOD(getName)
1540 {
1541 php_sxe_object *sxe;
1542 xmlNodePtr node;
1543 int namelen;
1544
1545 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1546
1547 GET_NODE(sxe, node);
1548 node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1549 if (node) {
1550 namelen = xmlStrlen(node->name);
1551 RETURN_STRINGL((char*)node->name, namelen, 1);
1552 } else {
1553 RETURN_EMPTY_STRING();
1554 }
1555 }
1556 /* }}} */
1557
1558 /* {{{ proto array SimpleXMLElement::attributes([string ns [, bool is_prefix]])
1559 Identifies an element's attributes */
SXE_METHOD(attributes)1560 SXE_METHOD(attributes)
1561 {
1562 php_sxe_object *sxe;
1563 char *nsprefix = NULL;
1564 int nsprefix_len = 0;
1565 xmlNodePtr node;
1566 zend_bool isprefix = 0;
1567
1568 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!b", &nsprefix, &nsprefix_len, &isprefix) == FAILURE) {
1569 return;
1570 }
1571
1572 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1573 GET_NODE(sxe, node);
1574
1575 if (sxe->iter.type == SXE_ITER_ATTRLIST) {
1576 return; /* attributes don't have attributes */
1577 }
1578
1579 node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1580
1581 _node_as_zval(sxe, node, return_value, SXE_ITER_ATTRLIST, NULL, (xmlChar *)nsprefix, isprefix TSRMLS_CC);
1582 }
1583 /* }}} */
1584
1585 /* {{{ proto void SimpleXMLElement::addChild(string qName [, string value [, string ns]])
1586 Add Element with optional namespace information */
SXE_METHOD(addChild)1587 SXE_METHOD(addChild)
1588 {
1589 php_sxe_object *sxe;
1590 char *qname, *value = NULL, *nsuri = NULL;
1591 int qname_len, value_len = 0, nsuri_len = 0;
1592 xmlNodePtr node, newnode;
1593 xmlNsPtr nsptr = NULL;
1594 xmlChar *localname, *prefix = NULL;
1595
1596 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!s!",
1597 &qname, &qname_len, &value, &value_len, &nsuri, &nsuri_len) == FAILURE) {
1598 return;
1599 }
1600
1601 if (qname_len == 0) {
1602 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Element name is required");
1603 return;
1604 }
1605
1606 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1607 GET_NODE(sxe, node);
1608
1609 if (sxe->iter.type == SXE_ITER_ATTRLIST) {
1610 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element to attributes");
1611 return;
1612 }
1613
1614 node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1615
1616 if (node == NULL) {
1617 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add child. Parent is not a permanent member of the XML tree");
1618 return;
1619 }
1620
1621 localname = xmlSplitQName2((xmlChar *)qname, &prefix);
1622 if (localname == NULL) {
1623 localname = xmlStrdup((xmlChar *)qname);
1624 }
1625
1626 newnode = xmlNewChild(node, NULL, localname, (xmlChar *)value);
1627
1628 if (nsuri != NULL) {
1629 if (nsuri_len == 0) {
1630 newnode->ns = NULL;
1631 nsptr = xmlNewNs(newnode, (xmlChar *)nsuri, prefix);
1632 } else {
1633 nsptr = xmlSearchNsByHref(node->doc, node, (xmlChar *)nsuri);
1634 if (nsptr == NULL) {
1635 nsptr = xmlNewNs(newnode, (xmlChar *)nsuri, prefix);
1636 }
1637 newnode->ns = nsptr;
1638 }
1639 }
1640
1641 _node_as_zval(sxe, newnode, return_value, SXE_ITER_NONE, (char *)localname, prefix, 0 TSRMLS_CC);
1642
1643 xmlFree(localname);
1644 if (prefix != NULL) {
1645 xmlFree(prefix);
1646 }
1647 }
1648 /* }}} */
1649
1650 /* {{{ proto void SimpleXMLElement::addAttribute(string qName, string value [,string ns])
1651 Add Attribute with optional namespace information */
SXE_METHOD(addAttribute)1652 SXE_METHOD(addAttribute)
1653 {
1654 php_sxe_object *sxe;
1655 char *qname, *value = NULL, *nsuri = NULL;
1656 int qname_len, value_len = 0, nsuri_len = 0;
1657 xmlNodePtr node;
1658 xmlAttrPtr attrp = NULL;
1659 xmlNsPtr nsptr = NULL;
1660 xmlChar *localname, *prefix = NULL;
1661
1662 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s!",
1663 &qname, &qname_len, &value, &value_len, &nsuri, &nsuri_len) == FAILURE) {
1664 return;
1665 }
1666
1667 if (qname_len == 0) {
1668 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attribute name is required");
1669 return;
1670 }
1671
1672 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1673 GET_NODE(sxe, node);
1674
1675 node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1676
1677 if (node && node->type != XML_ELEMENT_NODE) {
1678 node = node->parent;
1679 }
1680
1681 if (node == NULL) {
1682 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to locate parent Element");
1683 return;
1684 }
1685
1686 localname = xmlSplitQName2((xmlChar *)qname, &prefix);
1687 if (localname == NULL) {
1688 if (nsuri_len > 0) {
1689 if (prefix != NULL) {
1690 xmlFree(prefix);
1691 }
1692 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attribute requires prefix for namespace");
1693 return;
1694 }
1695 localname = xmlStrdup((xmlChar *)qname);
1696 }
1697
1698 attrp = xmlHasNsProp(node, localname, (xmlChar *)nsuri);
1699 if (attrp != NULL && attrp->type != XML_ATTRIBUTE_DECL) {
1700 xmlFree(localname);
1701 if (prefix != NULL) {
1702 xmlFree(prefix);
1703 }
1704 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attribute already exists");
1705 return;
1706 }
1707
1708 if (nsuri != NULL) {
1709 nsptr = xmlSearchNsByHref(node->doc, node, (xmlChar *)nsuri);
1710 if (nsptr == NULL) {
1711 nsptr = xmlNewNs(node, (xmlChar *)nsuri, prefix);
1712 }
1713 }
1714
1715 attrp = xmlNewNsProp(node, nsptr, localname, (xmlChar *)value);
1716
1717 xmlFree(localname);
1718 if (prefix != NULL) {
1719 xmlFree(prefix);
1720 }
1721 }
1722 /* }}} */
1723
1724 /* {{{ cast_object()
1725 */
cast_object(zval * object,int type,char * contents TSRMLS_DC)1726 static int cast_object(zval *object, int type, char *contents TSRMLS_DC)
1727 {
1728 if (contents) {
1729 ZVAL_STRINGL(object, contents, strlen(contents), 1);
1730 } else {
1731 ZVAL_NULL(object);
1732 }
1733 Z_SET_REFCOUNT_P(object, 1);
1734 Z_UNSET_ISREF_P(object);
1735
1736 switch (type) {
1737 case IS_STRING:
1738 convert_to_string(object);
1739 break;
1740 case IS_BOOL:
1741 convert_to_boolean(object);
1742 break;
1743 case IS_LONG:
1744 convert_to_long(object);
1745 break;
1746 case IS_DOUBLE:
1747 convert_to_double(object);
1748 break;
1749 default:
1750 return FAILURE;
1751 }
1752 return SUCCESS;
1753 }
1754 /* }}} */
1755
1756 /* {{{ sxe_object_cast()
1757 */
sxe_object_cast(zval * readobj,zval * writeobj,int type TSRMLS_DC)1758 static int sxe_object_cast(zval *readobj, zval *writeobj, int type TSRMLS_DC)
1759 {
1760 php_sxe_object *sxe;
1761 xmlChar *contents = NULL;
1762 xmlNodePtr node;
1763 int rv;
1764 HashTable *prop_hash;
1765
1766 sxe = php_sxe_fetch_object(readobj TSRMLS_CC);
1767
1768 if (type == IS_BOOL) {
1769 node = php_sxe_get_first_node(sxe, NULL TSRMLS_CC);
1770 prop_hash = sxe_get_prop_hash(readobj, 1 TSRMLS_CC);
1771 INIT_PZVAL(writeobj);
1772 ZVAL_BOOL(writeobj, node != NULL || zend_hash_num_elements(prop_hash) > 0);
1773 zend_hash_destroy(prop_hash);
1774 efree(prop_hash);
1775 return SUCCESS;
1776 }
1777
1778 if (sxe->iter.type != SXE_ITER_NONE) {
1779 node = php_sxe_get_first_node(sxe, NULL TSRMLS_CC);
1780 if (node) {
1781 contents = xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, node->children, 1);
1782 }
1783 } else {
1784 if (!sxe->node) {
1785 if (sxe->document) {
1786 php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement((xmlDocPtr) sxe->document->ptr), NULL TSRMLS_CC);
1787 }
1788 }
1789
1790 if (sxe->node && sxe->node->node) {
1791 if (sxe->node->node->children) {
1792 contents = xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, sxe->node->node->children, 1);
1793 }
1794 }
1795 }
1796
1797 if (readobj == writeobj) {
1798 INIT_PZVAL(writeobj);
1799 zval_dtor(readobj);
1800 }
1801
1802 rv = cast_object(writeobj, type, (char *)contents TSRMLS_CC);
1803
1804 if (contents) {
1805 xmlFree(contents);
1806 }
1807 return rv;
1808 }
1809 /* }}} */
1810
1811 /* {{{ proto object SimpleXMLElement::__toString() U
1812 Returns the string content */
SXE_METHOD(__toString)1813 SXE_METHOD(__toString)
1814 {
1815 zval *result;
1816
1817 ALLOC_INIT_ZVAL(result);
1818
1819 if (sxe_object_cast(getThis(), result, IS_STRING TSRMLS_CC) == SUCCESS) {
1820 RETURN_ZVAL(result, 1, 1);
1821 } else {
1822 zval_ptr_dtor(&result);
1823 RETURN_EMPTY_STRING();
1824 }
1825 }
1826 /* }}} */
1827
php_sxe_count_elements_helper(php_sxe_object * sxe,long * count TSRMLS_DC)1828 static int php_sxe_count_elements_helper(php_sxe_object *sxe, long *count TSRMLS_DC) /* {{{ */
1829 {
1830 xmlNodePtr node;
1831 zval *data;
1832
1833 *count = 0;
1834
1835 data = sxe->iter.data;
1836 sxe->iter.data = NULL;
1837
1838 node = php_sxe_reset_iterator(sxe, 0 TSRMLS_CC);
1839
1840 while (node)
1841 {
1842 (*count)++;
1843 node = php_sxe_iterator_fetch(sxe, node->next, 0 TSRMLS_CC);
1844 }
1845
1846 if (sxe->iter.data) {
1847 zval_ptr_dtor(&sxe->iter.data);
1848 }
1849 sxe->iter.data = data;
1850
1851 return SUCCESS;
1852 }
1853 /* }}} */
1854
sxe_count_elements(zval * object,long * count TSRMLS_DC)1855 static int sxe_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */
1856 {
1857 php_sxe_object *intern;
1858 intern = php_sxe_fetch_object(object TSRMLS_CC);
1859 if (intern->fptr_count) {
1860 zval *rv;
1861 zend_call_method_with_0_params(&object, intern->zo.ce, &intern->fptr_count, "count", &rv);
1862 if (rv) {
1863 if (intern->tmp) {
1864 zval_ptr_dtor(&intern->tmp);
1865 }
1866 MAKE_STD_ZVAL(intern->tmp);
1867 ZVAL_ZVAL(intern->tmp, rv, 1, 1);
1868 convert_to_long(intern->tmp);
1869 *count = (long) Z_LVAL_P(intern->tmp);
1870 return SUCCESS;
1871 }
1872 return FAILURE;
1873 }
1874 return php_sxe_count_elements_helper(intern, count TSRMLS_CC);
1875 }
1876 /* }}} */
1877
1878 /* {{{ proto int SimpleXMLElement::count()
1879 Get number of child elements */
SXE_METHOD(count)1880 SXE_METHOD(count)
1881 {
1882 long count = 0;
1883 php_sxe_object *sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1884
1885 if (zend_parse_parameters_none() == FAILURE) {
1886 return;
1887 }
1888
1889 php_sxe_count_elements_helper(sxe, &count TSRMLS_CC);
1890
1891 RETURN_LONG(count);
1892 }
1893 /* }}} */
1894
sxe_get_value(zval * z TSRMLS_DC)1895 static zval *sxe_get_value(zval *z TSRMLS_DC) /* {{{ */
1896 {
1897 zval *retval;
1898
1899 MAKE_STD_ZVAL(retval);
1900
1901 if (sxe_object_cast(z, retval, IS_STRING TSRMLS_CC)==FAILURE) {
1902 zend_error(E_ERROR, "Unable to cast node to string");
1903 /* FIXME: Should not be fatal */
1904 }
1905
1906 Z_SET_REFCOUNT_P(retval, 0);
1907 return retval;
1908 }
1909 /* }}} */
1910
1911 static zend_object_handlers sxe_object_handlers = { /* {{{ */
1912 ZEND_OBJECTS_STORE_HANDLERS,
1913 sxe_property_read,
1914 sxe_property_write,
1915 sxe_dimension_read,
1916 sxe_dimension_write,
1917 sxe_property_get_adr,
1918 sxe_get_value, /* get */
1919 NULL,
1920 sxe_property_exists,
1921 sxe_property_delete,
1922 sxe_dimension_exists,
1923 sxe_dimension_delete,
1924 sxe_get_properties,
1925 NULL, /* zend_get_std_object_handlers()->get_method,*/
1926 NULL, /* zend_get_std_object_handlers()->call_method,*/
1927 NULL, /* zend_get_std_object_handlers()->get_constructor, */
1928 NULL, /* zend_get_std_object_handlers()->get_class_entry,*/
1929 NULL, /* zend_get_std_object_handlers()->get_class_name,*/
1930 sxe_objects_compare,
1931 sxe_object_cast,
1932 sxe_count_elements,
1933 sxe_get_debug_info
1934 };
1935 /* }}} */
1936
1937 /* {{{ sxe_object_clone()
1938 */
1939 static void
sxe_object_clone(void * object,void ** clone_ptr TSRMLS_DC)1940 sxe_object_clone(void *object, void **clone_ptr TSRMLS_DC)
1941 {
1942 php_sxe_object *sxe = (php_sxe_object *) object;
1943 php_sxe_object *clone;
1944 xmlNodePtr nodep = NULL;
1945 xmlDocPtr docp = NULL;
1946
1947 clone = php_sxe_object_new(sxe->zo.ce TSRMLS_CC);
1948 clone->document = sxe->document;
1949 if (clone->document) {
1950 clone->document->refcount++;
1951 docp = clone->document->ptr;
1952 }
1953
1954 clone->iter.isprefix = sxe->iter.isprefix;
1955 if (sxe->iter.name != NULL) {
1956 clone->iter.name = xmlStrdup((xmlChar *)sxe->iter.name);
1957 }
1958 if (sxe->iter.nsprefix != NULL) {
1959 clone->iter.nsprefix = xmlStrdup((xmlChar *)sxe->iter.nsprefix);
1960 }
1961 clone->iter.type = sxe->iter.type;
1962
1963 if (sxe->node) {
1964 nodep = xmlDocCopyNode(sxe->node->node, docp, 1);
1965 }
1966
1967 php_libxml_increment_node_ptr((php_libxml_node_object *)clone, nodep, NULL TSRMLS_CC);
1968
1969 *clone_ptr = (void *) clone;
1970 }
1971 /* }}} */
1972
1973 /* {{{ sxe_object_dtor()
1974 */
sxe_object_dtor(void * object,zend_object_handle handle TSRMLS_DC)1975 static void sxe_object_dtor(void *object, zend_object_handle handle TSRMLS_DC)
1976 {
1977 /* dtor required to cleanup iterator related data properly */
1978
1979 php_sxe_object *sxe;
1980
1981 sxe = (php_sxe_object *) object;
1982
1983 if (sxe->iter.data) {
1984 zval_ptr_dtor(&sxe->iter.data);
1985 sxe->iter.data = NULL;
1986 }
1987
1988 if (sxe->iter.name) {
1989 xmlFree(sxe->iter.name);
1990 sxe->iter.name = NULL;
1991 }
1992 if (sxe->iter.nsprefix) {
1993 xmlFree(sxe->iter.nsprefix);
1994 sxe->iter.nsprefix = NULL;
1995 }
1996 if (sxe->tmp) {
1997 zval_ptr_dtor(&sxe->tmp);
1998 sxe->tmp = NULL;
1999 }
2000 }
2001 /* }}} */
2002
2003 /* {{{ sxe_object_free_storage()
2004 */
sxe_object_free_storage(void * object TSRMLS_DC)2005 static void sxe_object_free_storage(void *object TSRMLS_DC)
2006 {
2007 php_sxe_object *sxe;
2008
2009 sxe = (php_sxe_object *) object;
2010
2011 #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)
2012 zend_object_std_dtor(&sxe->zo TSRMLS_CC);
2013 #else
2014 if (sxe->zo.guards) {
2015 zend_hash_destroy(sxe->zo.guards);
2016 FREE_HASHTABLE(sxe->zo.guards);
2017 }
2018
2019 if (sxe->zo.properties) {
2020 zend_hash_destroy(sxe->zo.properties);
2021 FREE_HASHTABLE(sxe->zo.properties);
2022 }
2023 #endif
2024
2025 php_libxml_node_decrement_resource((php_libxml_node_object *)sxe TSRMLS_CC);
2026
2027 if (sxe->xpath) {
2028 xmlXPathFreeContext(sxe->xpath);
2029 }
2030
2031 if (sxe->properties) {
2032 zend_hash_destroy(sxe->properties);
2033 FREE_HASHTABLE(sxe->properties);
2034 }
2035
2036 efree(object);
2037 }
2038 /* }}} */
2039
2040 /* {{{ php_sxe_object_new()
2041 */
php_sxe_object_new(zend_class_entry * ce TSRMLS_DC)2042 static php_sxe_object* php_sxe_object_new(zend_class_entry *ce TSRMLS_DC)
2043 {
2044 php_sxe_object *intern;
2045 zend_class_entry *parent = ce;
2046 int inherited = 0;
2047
2048 intern = ecalloc(1, sizeof(php_sxe_object));
2049
2050 intern->iter.type = SXE_ITER_NONE;
2051 intern->iter.nsprefix = NULL;
2052 intern->iter.name = NULL;
2053 intern->fptr_count = NULL;
2054
2055 #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)
2056 zend_object_std_init(&intern->zo, ce TSRMLS_CC);
2057 #else
2058 ALLOC_HASHTABLE(intern->zo.properties);
2059 zend_hash_init(intern->zo.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
2060
2061 intern->zo.ce = ce;
2062 intern->zo.guards = NULL;
2063 #endif
2064
2065 while (parent) {
2066 if (parent == sxe_class_entry) {
2067 break;
2068 }
2069
2070 parent = parent->parent;
2071 inherited = 1;
2072 }
2073
2074 if (inherited) {
2075 zend_hash_find(&ce->function_table, "count", sizeof("count"),(void **) &intern->fptr_count);
2076 if (intern->fptr_count->common.scope == parent) {
2077 intern->fptr_count = NULL;
2078 }
2079 }
2080
2081 return intern;
2082 }
2083 /* }}} */
2084
2085 /* {{{ php_sxe_register_object
2086 */
2087 static zend_object_value
php_sxe_register_object(php_sxe_object * intern TSRMLS_DC)2088 php_sxe_register_object(php_sxe_object *intern TSRMLS_DC)
2089 {
2090 zend_object_value rv;
2091
2092 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);
2093 rv.handlers = (zend_object_handlers *) &sxe_object_handlers;
2094
2095 return rv;
2096 }
2097 /* }}} */
2098
2099 /* {{{ sxe_object_new()
2100 */
2101 PHP_SXE_API zend_object_value
sxe_object_new(zend_class_entry * ce TSRMLS_DC)2102 sxe_object_new(zend_class_entry *ce TSRMLS_DC)
2103 {
2104 php_sxe_object *intern;
2105
2106 intern = php_sxe_object_new(ce TSRMLS_CC);
2107 return php_sxe_register_object(intern TSRMLS_CC);
2108 }
2109 /* }}} */
2110
2111 /* {{{ proto simplemxml_element simplexml_load_file(string filename [, string class_name [, int options [, string ns [, bool is_prefix]]]])
2112 Load a filename and return a simplexml_element object to allow for processing */
PHP_FUNCTION(simplexml_load_file)2113 PHP_FUNCTION(simplexml_load_file)
2114 {
2115 php_sxe_object *sxe;
2116 char *filename;
2117 int filename_len;
2118 xmlDocPtr docp;
2119 char *ns = NULL;
2120 int ns_len = 0;
2121 long options = 0;
2122 zend_class_entry *ce= sxe_class_entry;
2123 zend_bool isprefix = 0;
2124
2125 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|C!lsb", &filename, &filename_len, &ce, &options, &ns, &ns_len, &isprefix) == FAILURE) {
2126 return;
2127 }
2128
2129 docp = xmlReadFile(filename, NULL, options);
2130
2131 if (! docp) {
2132 RETURN_FALSE;
2133 }
2134
2135 if (!ce) {
2136 ce = sxe_class_entry;
2137 }
2138 sxe = php_sxe_object_new(ce TSRMLS_CC);
2139 sxe->iter.nsprefix = ns_len ? xmlStrdup((xmlChar *)ns) : NULL;
2140 sxe->iter.isprefix = isprefix;
2141 php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp TSRMLS_CC);
2142 php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL TSRMLS_CC);
2143
2144 return_value->type = IS_OBJECT;
2145 return_value->value.obj = php_sxe_register_object(sxe TSRMLS_CC);
2146 }
2147 /* }}} */
2148
2149 /* {{{ proto simplemxml_element simplexml_load_string(string data [, string class_name [, int options [, string ns [, bool is_prefix]]]])
2150 Load a string and return a simplexml_element object to allow for processing */
PHP_FUNCTION(simplexml_load_string)2151 PHP_FUNCTION(simplexml_load_string)
2152 {
2153 php_sxe_object *sxe;
2154 char *data;
2155 int data_len;
2156 xmlDocPtr docp;
2157 char *ns = NULL;
2158 int ns_len = 0;
2159 long options = 0;
2160 zend_class_entry *ce= sxe_class_entry;
2161 zend_bool isprefix = 0;
2162
2163 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|C!lsb", &data, &data_len, &ce, &options, &ns, &ns_len, &isprefix) == FAILURE) {
2164 return;
2165 }
2166
2167 docp = xmlReadMemory(data, data_len, NULL, NULL, options);
2168
2169 if (! docp) {
2170 RETURN_FALSE;
2171 }
2172
2173 if (!ce) {
2174 ce = sxe_class_entry;
2175 }
2176 sxe = php_sxe_object_new(ce TSRMLS_CC);
2177 sxe->iter.nsprefix = ns_len ? xmlStrdup((xmlChar *)ns) : NULL;
2178 sxe->iter.isprefix = isprefix;
2179 php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp TSRMLS_CC);
2180 php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL TSRMLS_CC);
2181
2182 return_value->type = IS_OBJECT;
2183 return_value->value.obj = php_sxe_register_object(sxe TSRMLS_CC);
2184 }
2185 /* }}} */
2186
2187 /* {{{ proto SimpleXMLElement::__construct(string data [, int options [, bool data_is_url [, string ns [, bool is_prefix]]]])
2188 SimpleXMLElement constructor */
SXE_METHOD(__construct)2189 SXE_METHOD(__construct)
2190 {
2191 php_sxe_object *sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
2192 char *data, *ns = NULL;
2193 int data_len, ns_len = 0;
2194 xmlDocPtr docp;
2195 long options = 0;
2196 zend_bool is_url = 0, isprefix = 0;
2197 zend_error_handling error_handling;
2198
2199 zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
2200 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lbsb", &data, &data_len, &options, &is_url, &ns, &ns_len, &isprefix) == FAILURE) {
2201 zend_restore_error_handling(&error_handling TSRMLS_CC);
2202 return;
2203 }
2204
2205 zend_restore_error_handling(&error_handling TSRMLS_CC);
2206
2207 docp = is_url ? xmlReadFile(data, NULL, options) : xmlReadMemory(data, data_len, NULL, NULL, options);
2208
2209 if (!docp) {
2210 ((php_libxml_node_object *)sxe)->document = NULL;
2211 zend_throw_exception(zend_exception_get_default(TSRMLS_C), "String could not be parsed as XML", 0 TSRMLS_CC);
2212 return;
2213 }
2214
2215 sxe->iter.nsprefix = ns_len ? xmlStrdup((xmlChar *)ns) : NULL;
2216 sxe->iter.isprefix = isprefix;
2217 php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp TSRMLS_CC);
2218 php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL TSRMLS_CC);
2219 }
2220 /* }}} */
2221
2222 zend_object_iterator_funcs php_sxe_iterator_funcs = { /* {{{ */
2223 php_sxe_iterator_dtor,
2224 php_sxe_iterator_valid,
2225 php_sxe_iterator_current_data,
2226 php_sxe_iterator_current_key,
2227 php_sxe_iterator_move_forward,
2228 php_sxe_iterator_rewind,
2229 };
2230 /* }}} */
2231
php_sxe_iterator_fetch(php_sxe_object * sxe,xmlNodePtr node,int use_data TSRMLS_DC)2232 static xmlNodePtr php_sxe_iterator_fetch(php_sxe_object *sxe, xmlNodePtr node, int use_data TSRMLS_DC) /* {{{ */
2233 {
2234 xmlChar *prefix = sxe->iter.nsprefix;
2235 int isprefix = sxe->iter.isprefix;
2236 int test_elem = sxe->iter.type == SXE_ITER_ELEMENT && sxe->iter.name;
2237 int test_attr = sxe->iter.type == SXE_ITER_ATTRLIST && sxe->iter.name;
2238
2239 while (node) {
2240 SKIP_TEXT(node);
2241 if (sxe->iter.type != SXE_ITER_ATTRLIST && node->type == XML_ELEMENT_NODE) {
2242 if ((!test_elem || !xmlStrcmp(node->name, sxe->iter.name)) && match_ns(sxe, node, prefix, isprefix)) {
2243 break;
2244 }
2245 } else if (node->type == XML_ATTRIBUTE_NODE) {
2246 if ((!test_attr || !xmlStrcmp(node->name, sxe->iter.name)) && match_ns(sxe, node, prefix, isprefix)) {
2247 break;
2248 }
2249 }
2250 next_iter:
2251 node = node->next;
2252 }
2253
2254 if (node && use_data) {
2255 ALLOC_INIT_ZVAL(sxe->iter.data);
2256 _node_as_zval(sxe, node, sxe->iter.data, SXE_ITER_NONE, NULL, prefix, isprefix TSRMLS_CC);
2257 }
2258
2259 return node;
2260 }
2261 /* }}} */
2262
php_sxe_reset_iterator(php_sxe_object * sxe,int use_data TSRMLS_DC)2263 static xmlNodePtr php_sxe_reset_iterator(php_sxe_object *sxe, int use_data TSRMLS_DC) /* {{{ */
2264 {
2265 xmlNodePtr node;
2266
2267 if (sxe->iter.data) {
2268 zval_ptr_dtor(&sxe->iter.data);
2269 sxe->iter.data = NULL;
2270 }
2271
2272 GET_NODE(sxe, node)
2273
2274 if (node) {
2275 switch (sxe->iter.type) {
2276 case SXE_ITER_ELEMENT:
2277 case SXE_ITER_CHILD:
2278 case SXE_ITER_NONE:
2279 node = node->children;
2280 break;
2281 case SXE_ITER_ATTRLIST:
2282 node = (xmlNodePtr) node->properties;
2283 }
2284 return php_sxe_iterator_fetch(sxe, node, use_data TSRMLS_CC);
2285 }
2286 return NULL;
2287 }
2288 /* }}} */
2289
php_sxe_get_iterator(zend_class_entry * ce,zval * object,int by_ref TSRMLS_DC)2290 zend_object_iterator *php_sxe_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
2291 {
2292 php_sxe_iterator *iterator;
2293
2294 if (by_ref) {
2295 zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
2296 }
2297 iterator = emalloc(sizeof(php_sxe_iterator));
2298
2299 Z_ADDREF_P(object);
2300 iterator->intern.data = (void*)object;
2301 iterator->intern.funcs = &php_sxe_iterator_funcs;
2302 iterator->sxe = php_sxe_fetch_object(object TSRMLS_CC);
2303
2304 return (zend_object_iterator*)iterator;
2305 }
2306 /* }}} */
2307
php_sxe_iterator_dtor(zend_object_iterator * iter TSRMLS_DC)2308 static void php_sxe_iterator_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
2309 {
2310 php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2311
2312 /* cleanup handled in sxe_object_dtor as we dont always have an iterator wrapper */
2313 if (iterator->intern.data) {
2314 zval_ptr_dtor((zval**)&iterator->intern.data);
2315 }
2316
2317 efree(iterator);
2318 }
2319 /* }}} */
2320
php_sxe_iterator_valid(zend_object_iterator * iter TSRMLS_DC)2321 static int php_sxe_iterator_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
2322 {
2323 php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2324
2325 return iterator->sxe->iter.data ? SUCCESS : FAILURE;
2326 }
2327 /* }}} */
2328
php_sxe_iterator_current_data(zend_object_iterator * iter,zval *** data TSRMLS_DC)2329 static void php_sxe_iterator_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */
2330 {
2331 php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2332
2333 *data = &iterator->sxe->iter.data;
2334 }
2335 /* }}} */
2336
php_sxe_iterator_current_key(zend_object_iterator * iter,char ** str_key,uint * str_key_len,ulong * int_key TSRMLS_DC)2337 static int php_sxe_iterator_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
2338 {
2339 zval *curobj;
2340 xmlNodePtr curnode = NULL;
2341 php_sxe_object *intern;
2342 int namelen;
2343
2344 php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2345 curobj = iterator->sxe->iter.data;
2346
2347 intern = (php_sxe_object *)zend_object_store_get_object(curobj TSRMLS_CC);
2348 if (intern != NULL && intern->node != NULL) {
2349 curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->node)->node;
2350 }
2351 if (!curnode) {
2352 return HASH_KEY_NON_EXISTANT;
2353 }
2354
2355 namelen = xmlStrlen(curnode->name);
2356 *str_key = estrndup((char *)curnode->name, namelen);
2357 *str_key_len = namelen + 1;
2358 return HASH_KEY_IS_STRING;
2359
2360 }
2361 /* }}} */
2362
php_sxe_move_forward_iterator(php_sxe_object * sxe TSRMLS_DC)2363 PHP_SXE_API void php_sxe_move_forward_iterator(php_sxe_object *sxe TSRMLS_DC) /* {{{ */
2364 {
2365 xmlNodePtr node = NULL;
2366 php_sxe_object *intern;
2367
2368 if (sxe->iter.data) {
2369 intern = (php_sxe_object *)zend_object_store_get_object(sxe->iter.data TSRMLS_CC);
2370 GET_NODE(intern, node)
2371 zval_ptr_dtor(&sxe->iter.data);
2372 sxe->iter.data = NULL;
2373 }
2374
2375 if (node) {
2376 php_sxe_iterator_fetch(sxe, node->next, 1 TSRMLS_CC);
2377 }
2378 }
2379 /* }}} */
2380
php_sxe_iterator_move_forward(zend_object_iterator * iter TSRMLS_DC)2381 static void php_sxe_iterator_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
2382 {
2383 php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2384 php_sxe_move_forward_iterator(iterator->sxe TSRMLS_CC);
2385 }
2386 /* }}} */
2387
php_sxe_iterator_rewind(zend_object_iterator * iter TSRMLS_DC)2388 static void php_sxe_iterator_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
2389 {
2390 php_sxe_object *sxe;
2391
2392 php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
2393 sxe = iterator->sxe;
2394
2395 php_sxe_reset_iterator(sxe, 1 TSRMLS_CC);
2396 }
2397 /* }}} */
2398
simplexml_export_node(zval * object TSRMLS_DC)2399 void *simplexml_export_node(zval *object TSRMLS_DC) /* {{{ */
2400 {
2401 php_sxe_object *sxe;
2402 xmlNodePtr node;
2403
2404 sxe = php_sxe_fetch_object(object TSRMLS_CC);
2405 GET_NODE(sxe, node);
2406 return php_sxe_get_first_node(sxe, node TSRMLS_CC);
2407 }
2408 /* }}} */
2409
2410 /* {{{ proto simplemxml_element simplexml_import_dom(domNode node [, string class_name])
2411 Get a simplexml_element object from dom to allow for processing */
PHP_FUNCTION(simplexml_import_dom)2412 PHP_FUNCTION(simplexml_import_dom)
2413 {
2414 php_sxe_object *sxe;
2415 zval *node;
2416 php_libxml_node_object *object;
2417 xmlNodePtr nodep = NULL;
2418 zend_class_entry *ce= sxe_class_entry;
2419
2420 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o|C!", &node, &ce) == FAILURE) {
2421 return;
2422 }
2423
2424 object = (php_libxml_node_object *)zend_object_store_get_object(node TSRMLS_CC);
2425
2426 nodep = php_libxml_import_node(node TSRMLS_CC);
2427
2428 if (nodep) {
2429 if (nodep->doc == NULL) {
2430 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Imported Node must have associated Document");
2431 RETURN_NULL();
2432 }
2433 if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
2434 nodep = xmlDocGetRootElement((xmlDocPtr) nodep);
2435 }
2436 }
2437
2438 if (nodep && nodep->type == XML_ELEMENT_NODE) {
2439 if (!ce) {
2440 ce = sxe_class_entry;
2441 }
2442 sxe = php_sxe_object_new(ce TSRMLS_CC);
2443 sxe->document = object->document;
2444 php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, nodep->doc TSRMLS_CC);
2445 php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, nodep, NULL TSRMLS_CC);
2446
2447 return_value->type = IS_OBJECT;
2448 return_value->value.obj = php_sxe_register_object(sxe TSRMLS_CC);
2449 } else {
2450 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Nodetype to import");
2451 RETVAL_NULL();
2452 }
2453 }
2454 /* }}} */
2455
2456 /* {{{ arginfo */
2457 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexml_load_file, 0, 0, 1)
2458 ZEND_ARG_INFO(0, filename)
2459 ZEND_ARG_INFO(0, class_name)
2460 ZEND_ARG_INFO(0, options)
2461 ZEND_ARG_INFO(0, ns)
2462 ZEND_ARG_INFO(0, is_prefix)
2463 ZEND_END_ARG_INFO()
2464
2465 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexml_load_string, 0, 0, 1)
2466 ZEND_ARG_INFO(0, data)
2467 ZEND_ARG_INFO(0, class_name)
2468 ZEND_ARG_INFO(0, options)
2469 ZEND_ARG_INFO(0, ns)
2470 ZEND_ARG_INFO(0, is_prefix)
2471 ZEND_END_ARG_INFO()
2472
2473 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexml_import_dom, 0, 0, 1)
2474 ZEND_ARG_INFO(0, node)
2475 ZEND_ARG_INFO(0, class_name)
2476 ZEND_END_ARG_INFO()
2477
2478 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_xpath, 0, 0, 1)
2479 ZEND_ARG_INFO(0, path)
2480 ZEND_END_ARG_INFO()
2481
2482 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_registerxpathnamespace, 0, 0, 2)
2483 ZEND_ARG_INFO(0, prefix)
2484 ZEND_ARG_INFO(0, ns)
2485 ZEND_END_ARG_INFO()
2486
2487 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_asxml, 0, 0, 0)
2488 ZEND_ARG_INFO(0, filename)
2489 ZEND_END_ARG_INFO()
2490
2491 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_getnamespaces, 0, 0, 0)
2492 ZEND_ARG_INFO(0, recursve)
2493 ZEND_END_ARG_INFO()
2494
2495 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_children, 0, 0, 0)
2496 ZEND_ARG_INFO(0, ns)
2497 ZEND_ARG_INFO(0, is_prefix)
2498 ZEND_END_ARG_INFO()
2499
2500 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement__construct, 0, 0, 1)
2501 ZEND_ARG_INFO(0, data)
2502 ZEND_ARG_INFO(0, options)
2503 ZEND_ARG_INFO(0, data_is_url)
2504 ZEND_ARG_INFO(0, ns)
2505 ZEND_ARG_INFO(0, is_prefix)
2506 ZEND_END_ARG_INFO()
2507
2508 ZEND_BEGIN_ARG_INFO(arginfo_simplexmlelement__void, 0)
2509 ZEND_END_ARG_INFO()
2510
2511 ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_addchild, 0, 0, 1)
2512 ZEND_ARG_INFO(0, name)
2513 ZEND_ARG_INFO(0, value)
2514 ZEND_ARG_INFO(0, ns)
2515 ZEND_END_ARG_INFO()
2516 /* }}} */
2517
2518 const zend_function_entry simplexml_functions[] = { /* {{{ */
2519 PHP_FE(simplexml_load_file, arginfo_simplexml_load_file)
2520 PHP_FE(simplexml_load_string, arginfo_simplexml_load_string)
2521 PHP_FE(simplexml_import_dom, arginfo_simplexml_import_dom)
2522 PHP_FE_END
2523 };
2524 /* }}} */
2525
2526 static const zend_module_dep simplexml_deps[] = { /* {{{ */
2527 ZEND_MOD_REQUIRED("libxml")
2528 ZEND_MOD_REQUIRED("spl")
2529 ZEND_MOD_END
2530 };
2531 /* }}} */
2532
2533 zend_module_entry simplexml_module_entry = { /* {{{ */
2534 STANDARD_MODULE_HEADER_EX, NULL,
2535 simplexml_deps,
2536 "SimpleXML",
2537 simplexml_functions,
2538 PHP_MINIT(simplexml),
2539 PHP_MSHUTDOWN(simplexml),
2540 NULL,
2541 NULL,
2542 PHP_MINFO(simplexml),
2543 "0.1",
2544 STANDARD_MODULE_PROPERTIES
2545 };
2546 /* }}} */
2547
2548 #ifdef COMPILE_DL_SIMPLEXML
2549 ZEND_GET_MODULE(simplexml)
2550 #endif
2551
2552 /* the method table */
2553 /* each method can have its own parameters and visibility */
2554 static const zend_function_entry sxe_functions[] = { /* {{{ */
2555 SXE_ME(__construct, arginfo_simplexmlelement__construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) /* must be called */
2556 SXE_ME(asXML, arginfo_simplexmlelement_asxml, ZEND_ACC_PUBLIC)
2557 SXE_MALIAS(saveXML, asXML, arginfo_simplexmlelement_asxml, ZEND_ACC_PUBLIC)
2558 SXE_ME(xpath, arginfo_simplexmlelement_xpath, ZEND_ACC_PUBLIC)
2559 SXE_ME(registerXPathNamespace, arginfo_simplexmlelement_registerxpathnamespace, ZEND_ACC_PUBLIC)
2560 SXE_ME(attributes, arginfo_simplexmlelement_children, ZEND_ACC_PUBLIC)
2561 SXE_ME(children, arginfo_simplexmlelement_children, ZEND_ACC_PUBLIC)
2562 SXE_ME(getNamespaces, arginfo_simplexmlelement_getnamespaces, ZEND_ACC_PUBLIC)
2563 SXE_ME(getDocNamespaces, arginfo_simplexmlelement_getnamespaces, ZEND_ACC_PUBLIC)
2564 SXE_ME(getName, arginfo_simplexmlelement__void, ZEND_ACC_PUBLIC)
2565 SXE_ME(addChild, arginfo_simplexmlelement_addchild, ZEND_ACC_PUBLIC)
2566 SXE_ME(addAttribute, arginfo_simplexmlelement_addchild, ZEND_ACC_PUBLIC)
2567 SXE_ME(__toString, arginfo_simplexmlelement__void, ZEND_ACC_PUBLIC)
2568 SXE_ME(count, arginfo_simplexmlelement__void, ZEND_ACC_PUBLIC)
2569 PHP_FE_END
2570 };
2571 /* }}} */
2572
2573 /* {{{ PHP_MINIT_FUNCTION(simplexml)
2574 */
PHP_MINIT_FUNCTION(simplexml)2575 PHP_MINIT_FUNCTION(simplexml)
2576 {
2577 zend_class_entry sxe;
2578
2579 INIT_CLASS_ENTRY(sxe, "SimpleXMLElement", sxe_functions);
2580 sxe.create_object = sxe_object_new;
2581 sxe_class_entry = zend_register_internal_class(&sxe TSRMLS_CC);
2582 sxe_class_entry->get_iterator = php_sxe_get_iterator;
2583 sxe_class_entry->iterator_funcs.funcs = &php_sxe_iterator_funcs;
2584 zend_class_implements(sxe_class_entry TSRMLS_CC, 1, zend_ce_traversable);
2585 sxe_object_handlers.get_method = zend_get_std_object_handlers()->get_method;
2586 sxe_object_handlers.get_constructor = zend_get_std_object_handlers()->get_constructor;
2587 sxe_object_handlers.get_class_entry = zend_get_std_object_handlers()->get_class_entry;
2588 sxe_object_handlers.get_class_name = zend_get_std_object_handlers()->get_class_name;
2589 sxe_class_entry->serialize = zend_class_serialize_deny;
2590 sxe_class_entry->unserialize = zend_class_unserialize_deny;
2591
2592 php_libxml_register_export(sxe_class_entry, simplexml_export_node);
2593
2594 PHP_MINIT(sxe)(INIT_FUNC_ARGS_PASSTHRU);
2595
2596 return SUCCESS;
2597 }
2598 /* }}} */
2599
2600 /* {{{ PHP_MSHUTDOWN_FUNCTION(simplexml)
2601 */
PHP_MSHUTDOWN_FUNCTION(simplexml)2602 PHP_MSHUTDOWN_FUNCTION(simplexml)
2603 {
2604 sxe_class_entry = NULL;
2605 return SUCCESS;
2606 }
2607 /* }}} */
2608
2609 /* {{{ PHP_MINFO_FUNCTION(simplexml)
2610 */
PHP_MINFO_FUNCTION(simplexml)2611 PHP_MINFO_FUNCTION(simplexml)
2612 {
2613 php_info_print_table_start();
2614 php_info_print_table_header(2, "Simplexml support", "enabled");
2615 php_info_print_table_row(2, "Revision", "$Id: 02ab7893b36d51e9c59da77d7e287eb3b35e1e32 $");
2616 php_info_print_table_row(2, "Schema support",
2617 #ifdef LIBXML_SCHEMAS_ENABLED
2618 "enabled");
2619 #else
2620 "not available");
2621 #endif
2622 php_info_print_table_end();
2623 }
2624 /* }}} */
2625
2626 #endif
2627
2628 /**
2629 * Local Variables:
2630 * c-basic-offset: 4
2631 * tab-width: 4
2632 * indent-tabs-mode: t
2633 * End:
2634 * vim600: fdm=marker
2635 * vim: noet sw=4 ts=4
2636 */
2637