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