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