simplexml.c 72 KB

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