You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2755 lines
70 KiB

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