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