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