simplexml.c 71 KB

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