spl_iterators.c 97 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | https://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Authors: Marcus Boerger <helly@php.net> |
  14. +----------------------------------------------------------------------+
  15. */
  16. #ifdef HAVE_CONFIG_H
  17. # include "config.h"
  18. #endif
  19. #include "php.h"
  20. #include "php_ini.h"
  21. #include "ext/standard/info.h"
  22. #include "zend_exceptions.h"
  23. #include "zend_interfaces.h"
  24. #include "php_spl.h"
  25. #include "spl_functions.h"
  26. #include "spl_engine.h"
  27. #include "spl_iterators.h"
  28. #include "spl_iterators_arginfo.h"
  29. #include "spl_directory.h"
  30. #include "spl_array.h"
  31. #include "spl_exceptions.h"
  32. #include "zend_smart_str.h"
  33. #ifdef accept
  34. #undef accept
  35. #endif
  36. PHPAPI zend_class_entry *spl_ce_RecursiveIterator;
  37. PHPAPI zend_class_entry *spl_ce_RecursiveIteratorIterator;
  38. PHPAPI zend_class_entry *spl_ce_FilterIterator;
  39. PHPAPI zend_class_entry *spl_ce_CallbackFilterIterator;
  40. PHPAPI zend_class_entry *spl_ce_RecursiveFilterIterator;
  41. PHPAPI zend_class_entry *spl_ce_RecursiveCallbackFilterIterator;
  42. PHPAPI zend_class_entry *spl_ce_ParentIterator;
  43. PHPAPI zend_class_entry *spl_ce_SeekableIterator;
  44. PHPAPI zend_class_entry *spl_ce_LimitIterator;
  45. PHPAPI zend_class_entry *spl_ce_CachingIterator;
  46. PHPAPI zend_class_entry *spl_ce_RecursiveCachingIterator;
  47. PHPAPI zend_class_entry *spl_ce_OuterIterator;
  48. PHPAPI zend_class_entry *spl_ce_IteratorIterator;
  49. PHPAPI zend_class_entry *spl_ce_NoRewindIterator;
  50. PHPAPI zend_class_entry *spl_ce_InfiniteIterator;
  51. PHPAPI zend_class_entry *spl_ce_EmptyIterator;
  52. PHPAPI zend_class_entry *spl_ce_AppendIterator;
  53. PHPAPI zend_class_entry *spl_ce_RegexIterator;
  54. PHPAPI zend_class_entry *spl_ce_RecursiveRegexIterator;
  55. PHPAPI zend_class_entry *spl_ce_RecursiveTreeIterator;
  56. typedef enum {
  57. RIT_LEAVES_ONLY = 0,
  58. RIT_SELF_FIRST = 1,
  59. RIT_CHILD_FIRST = 2
  60. } RecursiveIteratorMode;
  61. #define RIT_CATCH_GET_CHILD CIT_CATCH_GET_CHILD
  62. typedef enum {
  63. RTIT_BYPASS_CURRENT = 4,
  64. RTIT_BYPASS_KEY = 8
  65. } RecursiveTreeIteratorFlags;
  66. typedef enum {
  67. RS_NEXT = 0,
  68. RS_TEST = 1,
  69. RS_SELF = 2,
  70. RS_CHILD = 3,
  71. RS_START = 4
  72. } RecursiveIteratorState;
  73. typedef struct _spl_sub_iterator {
  74. zend_object_iterator *iterator;
  75. zval zobject;
  76. zend_class_entry *ce;
  77. RecursiveIteratorState state;
  78. zend_function *haschildren;
  79. zend_function *getchildren;
  80. } spl_sub_iterator;
  81. typedef struct _spl_recursive_it_object {
  82. spl_sub_iterator *iterators;
  83. int level;
  84. RecursiveIteratorMode mode;
  85. int flags;
  86. int max_depth;
  87. bool in_iteration;
  88. zend_function *beginIteration;
  89. zend_function *endIteration;
  90. zend_function *callHasChildren;
  91. zend_function *callGetChildren;
  92. zend_function *beginChildren;
  93. zend_function *endChildren;
  94. zend_function *nextElement;
  95. zend_class_entry *ce;
  96. zend_string *prefix[6];
  97. zend_string *postfix[1];
  98. zend_object std;
  99. } spl_recursive_it_object;
  100. typedef struct _spl_recursive_it_iterator {
  101. zend_object_iterator intern;
  102. } spl_recursive_it_iterator;
  103. static zend_object_handlers spl_handlers_rec_it_it;
  104. static zend_object_handlers spl_handlers_dual_it;
  105. static inline spl_recursive_it_object *spl_recursive_it_from_obj(zend_object *obj) /* {{{ */ {
  106. return (spl_recursive_it_object*)((char*)(obj) - XtOffsetOf(spl_recursive_it_object, std));
  107. }
  108. /* }}} */
  109. #define Z_SPLRECURSIVE_IT_P(zv) spl_recursive_it_from_obj(Z_OBJ_P((zv)))
  110. #define SPL_FETCH_AND_CHECK_DUAL_IT(var, objzval) \
  111. do { \
  112. spl_dual_it_object *it = Z_SPLDUAL_IT_P(objzval); \
  113. if (it->dit_type == DIT_Unknown) { \
  114. zend_throw_error(NULL, "The object is in an invalid state as the parent constructor was not called"); \
  115. RETURN_THROWS(); \
  116. } \
  117. (var) = it; \
  118. } while (0)
  119. #define SPL_FETCH_SUB_ELEMENT(var, object, element) \
  120. do { \
  121. if(!(object)->iterators) { \
  122. zend_throw_error(NULL, "The object is in an invalid state as the parent constructor was not called"); \
  123. return; \
  124. } \
  125. (var) = (object)->iterators[(object)->level].element; \
  126. } while (0)
  127. #define SPL_FETCH_SUB_ELEMENT_ADDR(var, object, element) \
  128. do { \
  129. if(!(object)->iterators) { \
  130. zend_throw_error(NULL, "The object is in an invalid state as the parent constructor was not called"); \
  131. RETURN_THROWS(); \
  132. } \
  133. (var) = &(object)->iterators[(object)->level].element; \
  134. } while (0)
  135. #define SPL_FETCH_SUB_ITERATOR(var, object) SPL_FETCH_SUB_ELEMENT(var, object, iterator)
  136. static void spl_recursive_it_dtor(zend_object_iterator *_iter)
  137. {
  138. spl_recursive_it_iterator *iter = (spl_recursive_it_iterator*)_iter;
  139. spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(&iter->intern.data);
  140. zend_object_iterator *sub_iter;
  141. if (object->iterators) {
  142. while (object->level > 0) {
  143. if (!Z_ISUNDEF(object->iterators[object->level].zobject)) {
  144. sub_iter = object->iterators[object->level].iterator;
  145. zend_iterator_dtor(sub_iter);
  146. zval_ptr_dtor(&object->iterators[object->level].zobject);
  147. }
  148. object->level--;
  149. }
  150. object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator));
  151. object->level = 0;
  152. }
  153. zval_ptr_dtor(&iter->intern.data);
  154. }
  155. static int spl_recursive_it_valid_ex(spl_recursive_it_object *object, zval *zthis)
  156. {
  157. zend_object_iterator *sub_iter;
  158. int level = object->level;
  159. if(!object->iterators) {
  160. return FAILURE;
  161. }
  162. while (level >=0) {
  163. sub_iter = object->iterators[level].iterator;
  164. if (sub_iter->funcs->valid(sub_iter) == SUCCESS) {
  165. return SUCCESS;
  166. }
  167. level--;
  168. }
  169. if (object->endIteration && object->in_iteration) {
  170. zend_call_method_with_0_params(Z_OBJ_P(zthis), object->ce, &object->endIteration, "endIteration", NULL);
  171. }
  172. object->in_iteration = 0;
  173. return FAILURE;
  174. }
  175. static int spl_recursive_it_valid(zend_object_iterator *iter)
  176. {
  177. return spl_recursive_it_valid_ex(Z_SPLRECURSIVE_IT_P(&iter->data), &iter->data);
  178. }
  179. static zval *spl_recursive_it_get_current_data(zend_object_iterator *iter)
  180. {
  181. spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(&iter->data);
  182. zend_object_iterator *sub_iter = object->iterators[object->level].iterator;
  183. return sub_iter->funcs->get_current_data(sub_iter);
  184. }
  185. static void spl_recursive_it_get_current_key(zend_object_iterator *iter, zval *key)
  186. {
  187. spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(&iter->data);
  188. zend_object_iterator *sub_iter = object->iterators[object->level].iterator;
  189. if (sub_iter->funcs->get_current_key) {
  190. sub_iter->funcs->get_current_key(sub_iter, key);
  191. } else {
  192. ZVAL_LONG(key, iter->index);
  193. }
  194. }
  195. static void spl_recursive_it_move_forward_ex(spl_recursive_it_object *object, zval *zthis)
  196. {
  197. zend_object_iterator *iterator;
  198. zend_class_entry *ce;
  199. zval retval, child;
  200. zend_object_iterator *sub_iter;
  201. int has_children;
  202. SPL_FETCH_SUB_ITERATOR(iterator, object);
  203. while (!EG(exception)) {
  204. next_step:
  205. iterator = object->iterators[object->level].iterator;
  206. switch (object->iterators[object->level].state) {
  207. case RS_NEXT:
  208. iterator->funcs->move_forward(iterator);
  209. if (EG(exception)) {
  210. if (!(object->flags & RIT_CATCH_GET_CHILD)) {
  211. return;
  212. } else {
  213. zend_clear_exception();
  214. }
  215. }
  216. ZEND_FALLTHROUGH;
  217. case RS_START:
  218. if (iterator->funcs->valid(iterator) == FAILURE) {
  219. break;
  220. }
  221. object->iterators[object->level].state = RS_TEST;
  222. /* break; */
  223. /* TODO: Check this is correct */
  224. ZEND_FALLTHROUGH;
  225. case RS_TEST:
  226. if (object->callHasChildren) {
  227. zend_call_method_with_0_params(Z_OBJ_P(zthis), object->ce, &object->callHasChildren, "callHasChildren", &retval);
  228. } else {
  229. zend_class_entry *ce = object->iterators[object->level].ce;
  230. zend_object *obj = Z_OBJ(object->iterators[object->level].zobject);
  231. zend_function **cache = &object->iterators[object->level].haschildren;
  232. zend_call_method_with_0_params(obj, ce, cache, "haschildren", &retval);
  233. }
  234. if (EG(exception)) {
  235. if (!(object->flags & RIT_CATCH_GET_CHILD)) {
  236. object->iterators[object->level].state = RS_NEXT;
  237. return;
  238. } else {
  239. zend_clear_exception();
  240. }
  241. }
  242. if (Z_TYPE(retval) != IS_UNDEF) {
  243. has_children = zend_is_true(&retval);
  244. zval_ptr_dtor(&retval);
  245. if (has_children) {
  246. if (object->max_depth == -1 || object->max_depth > object->level) {
  247. switch (object->mode) {
  248. case RIT_LEAVES_ONLY:
  249. case RIT_CHILD_FIRST:
  250. object->iterators[object->level].state = RS_CHILD;
  251. goto next_step;
  252. case RIT_SELF_FIRST:
  253. object->iterators[object->level].state = RS_SELF;
  254. goto next_step;
  255. }
  256. } else {
  257. /* do not recurse into */
  258. if (object->mode == RIT_LEAVES_ONLY) {
  259. /* this is not a leave, so skip it */
  260. object->iterators[object->level].state = RS_NEXT;
  261. goto next_step;
  262. }
  263. }
  264. }
  265. }
  266. if (object->nextElement) {
  267. zend_call_method_with_0_params(Z_OBJ_P(zthis), object->ce, &object->nextElement, "nextelement", NULL);
  268. }
  269. object->iterators[object->level].state = RS_NEXT;
  270. if (EG(exception)) {
  271. if (!(object->flags & RIT_CATCH_GET_CHILD)) {
  272. return;
  273. } else {
  274. zend_clear_exception();
  275. }
  276. }
  277. return /* self */;
  278. case RS_SELF:
  279. if (object->nextElement && (object->mode == RIT_SELF_FIRST || object->mode == RIT_CHILD_FIRST)) {
  280. zend_call_method_with_0_params(Z_OBJ_P(zthis), object->ce, &object->nextElement, "nextelement", NULL);
  281. }
  282. if (object->mode == RIT_SELF_FIRST) {
  283. object->iterators[object->level].state = RS_CHILD;
  284. } else {
  285. object->iterators[object->level].state = RS_NEXT;
  286. }
  287. return /* self */;
  288. case RS_CHILD:
  289. if (object->callGetChildren) {
  290. zend_call_method_with_0_params(Z_OBJ_P(zthis), object->ce, &object->callGetChildren, "callGetChildren", &child);
  291. } else {
  292. zend_class_entry *ce = object->iterators[object->level].ce;
  293. zend_object *obj = Z_OBJ(object->iterators[object->level].zobject);
  294. zend_function **cache = &object->iterators[object->level].getchildren;
  295. zend_call_method_with_0_params(obj, ce, cache, "getchildren", &child);
  296. }
  297. if (EG(exception)) {
  298. if (!(object->flags & RIT_CATCH_GET_CHILD)) {
  299. return;
  300. } else {
  301. zend_clear_exception();
  302. zval_ptr_dtor(&child);
  303. object->iterators[object->level].state = RS_NEXT;
  304. goto next_step;
  305. }
  306. }
  307. if (Z_TYPE(child) == IS_UNDEF || Z_TYPE(child) != IS_OBJECT ||
  308. !((ce = Z_OBJCE(child)) && instanceof_function(ce, spl_ce_RecursiveIterator))) {
  309. zval_ptr_dtor(&child);
  310. zend_throw_exception(spl_ce_UnexpectedValueException, "Objects returned by RecursiveIterator::getChildren() must implement RecursiveIterator", 0);
  311. return;
  312. }
  313. if (object->mode == RIT_CHILD_FIRST) {
  314. object->iterators[object->level].state = RS_SELF;
  315. } else {
  316. object->iterators[object->level].state = RS_NEXT;
  317. }
  318. object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator) * (++object->level+1));
  319. sub_iter = ce->get_iterator(ce, &child, 0);
  320. ZVAL_COPY_VALUE(&object->iterators[object->level].zobject, &child);
  321. object->iterators[object->level].iterator = sub_iter;
  322. object->iterators[object->level].ce = ce;
  323. object->iterators[object->level].state = RS_START;
  324. if (object->level > 0
  325. && object->iterators[object->level - 1].ce == 0) {
  326. object->iterators[object->level].haschildren =
  327. object->iterators[object->level - 1].haschildren;
  328. object->iterators[object->level].getchildren =
  329. object->iterators[object->level - 1].getchildren;
  330. } else {
  331. object->iterators[object->level].haschildren = NULL;
  332. object->iterators[object->level].getchildren = NULL;
  333. }
  334. if (sub_iter->funcs->rewind) {
  335. sub_iter->funcs->rewind(sub_iter);
  336. }
  337. if (object->beginChildren) {
  338. zend_call_method_with_0_params(Z_OBJ_P(zthis), object->ce, &object->beginChildren, "beginchildren", NULL);
  339. if (EG(exception)) {
  340. if (!(object->flags & RIT_CATCH_GET_CHILD)) {
  341. return;
  342. } else {
  343. zend_clear_exception();
  344. }
  345. }
  346. }
  347. goto next_step;
  348. }
  349. /* no more elements */
  350. if (object->level > 0) {
  351. if (object->endChildren) {
  352. zend_call_method_with_0_params(Z_OBJ_P(zthis), object->ce, &object->endChildren, "endchildren", NULL);
  353. if (EG(exception)) {
  354. if (!(object->flags & RIT_CATCH_GET_CHILD)) {
  355. return;
  356. } else {
  357. zend_clear_exception();
  358. }
  359. }
  360. }
  361. if (object->level > 0) {
  362. zval garbage;
  363. ZVAL_COPY_VALUE(&garbage, &object->iterators[object->level].zobject);
  364. ZVAL_UNDEF(&object->iterators[object->level].zobject);
  365. zval_ptr_dtor(&garbage);
  366. zend_iterator_dtor(iterator);
  367. object->level--;
  368. }
  369. } else {
  370. return; /* done completeley */
  371. }
  372. }
  373. }
  374. static void spl_recursive_it_rewind_ex(spl_recursive_it_object *object, zval *zthis)
  375. {
  376. zend_object_iterator *sub_iter;
  377. SPL_FETCH_SUB_ITERATOR(sub_iter, object);
  378. while (object->level) {
  379. sub_iter = object->iterators[object->level].iterator;
  380. zend_iterator_dtor(sub_iter);
  381. zval_ptr_dtor(&object->iterators[object->level--].zobject);
  382. if (!EG(exception) && (!object->endChildren || object->endChildren->common.scope != spl_ce_RecursiveIteratorIterator)) {
  383. zend_call_method_with_0_params(Z_OBJ_P(zthis), object->ce, &object->endChildren, "endchildren", NULL);
  384. }
  385. }
  386. object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator));
  387. object->iterators[0].state = RS_START;
  388. sub_iter = object->iterators[0].iterator;
  389. if (sub_iter->funcs->rewind) {
  390. sub_iter->funcs->rewind(sub_iter);
  391. }
  392. if (!EG(exception) && object->beginIteration && !object->in_iteration) {
  393. zend_call_method_with_0_params(Z_OBJ_P(zthis), object->ce, &object->beginIteration, "beginIteration", NULL);
  394. }
  395. object->in_iteration = 1;
  396. spl_recursive_it_move_forward_ex(object, zthis);
  397. }
  398. static void spl_recursive_it_move_forward(zend_object_iterator *iter)
  399. {
  400. spl_recursive_it_move_forward_ex(Z_SPLRECURSIVE_IT_P(&iter->data), &iter->data);
  401. }
  402. static void spl_recursive_it_rewind(zend_object_iterator *iter)
  403. {
  404. spl_recursive_it_rewind_ex(Z_SPLRECURSIVE_IT_P(&iter->data), &iter->data);
  405. }
  406. static const zend_object_iterator_funcs spl_recursive_it_iterator_funcs = {
  407. spl_recursive_it_dtor,
  408. spl_recursive_it_valid,
  409. spl_recursive_it_get_current_data,
  410. spl_recursive_it_get_current_key,
  411. spl_recursive_it_move_forward,
  412. spl_recursive_it_rewind,
  413. NULL,
  414. NULL, /* get_gc */
  415. };
  416. static zend_object_iterator *spl_recursive_it_get_iterator(zend_class_entry *ce, zval *zobject, int by_ref)
  417. {
  418. if (by_ref) {
  419. zend_throw_error(NULL, "An iterator cannot be used with foreach by reference");
  420. return NULL;
  421. }
  422. spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(zobject);
  423. if (object->iterators == NULL) {
  424. zend_throw_error(NULL, "Object is not initialized");
  425. return NULL;
  426. }
  427. spl_recursive_it_iterator *iterator = emalloc(sizeof(spl_recursive_it_iterator));
  428. zend_iterator_init((zend_object_iterator*)iterator);
  429. ZVAL_OBJ_COPY(&iterator->intern.data, Z_OBJ_P(zobject));
  430. iterator->intern.funcs = &spl_recursive_it_iterator_funcs;
  431. return (zend_object_iterator*)iterator;
  432. }
  433. static int spl_get_iterator_from_aggregate(zval *retval, zend_class_entry *ce, zend_object *obj) {
  434. zend_function **getiterator_cache =
  435. ce->iterator_funcs_ptr ? &ce->iterator_funcs_ptr->zf_new_iterator : NULL;
  436. zend_call_method_with_0_params(obj, ce, getiterator_cache, "getiterator", retval);
  437. if (EG(exception)) {
  438. return FAILURE;
  439. }
  440. if (Z_TYPE_P(retval) != IS_OBJECT
  441. || !instanceof_function(Z_OBJCE_P(retval), zend_ce_traversable)) {
  442. zend_throw_exception_ex(spl_ce_LogicException, 0,
  443. "%s::getIterator() must return an object that implements Traversable",
  444. ZSTR_VAL(ce->name));
  445. zval_ptr_dtor(retval);
  446. return FAILURE;
  447. }
  448. return SUCCESS;
  449. }
  450. static void spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce_base, zend_class_entry *ce_inner, recursive_it_it_type rit_type)
  451. {
  452. zval *object = ZEND_THIS;
  453. spl_recursive_it_object *intern;
  454. zval *iterator;
  455. zend_class_entry *ce_iterator;
  456. zend_long mode, flags;
  457. zval caching_it, aggregate_retval;
  458. switch (rit_type) {
  459. case RIT_RecursiveTreeIterator: {
  460. zval caching_it_flags;
  461. zend_long user_caching_it_flags = CIT_CATCH_GET_CHILD;
  462. mode = RIT_SELF_FIRST;
  463. flags = RTIT_BYPASS_KEY;
  464. if (zend_parse_parameters(ZEND_NUM_ARGS(), "o|lll", &iterator, &flags, &user_caching_it_flags, &mode) == FAILURE) {
  465. RETURN_THROWS();
  466. }
  467. if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate)) {
  468. if (spl_get_iterator_from_aggregate(
  469. &aggregate_retval, Z_OBJCE_P(iterator), Z_OBJ_P(iterator)) == FAILURE) {
  470. RETURN_THROWS();
  471. }
  472. iterator = &aggregate_retval;
  473. } else {
  474. Z_ADDREF_P(iterator);
  475. }
  476. ZVAL_LONG(&caching_it_flags, user_caching_it_flags);
  477. spl_instantiate_arg_ex2(spl_ce_RecursiveCachingIterator, &caching_it, iterator, &caching_it_flags);
  478. zval_ptr_dtor(&caching_it_flags);
  479. zval_ptr_dtor(iterator);
  480. iterator = &caching_it;
  481. break;
  482. }
  483. case RIT_RecursiveIteratorIterator:
  484. default: {
  485. mode = RIT_LEAVES_ONLY;
  486. flags = 0;
  487. if (zend_parse_parameters(ZEND_NUM_ARGS(), "o|ll", &iterator, &mode, &flags) == FAILURE) {
  488. RETURN_THROWS();
  489. }
  490. if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate)) {
  491. if (spl_get_iterator_from_aggregate(
  492. &aggregate_retval, Z_OBJCE_P(iterator), Z_OBJ_P(iterator)) == FAILURE) {
  493. RETURN_THROWS();
  494. }
  495. iterator = &aggregate_retval;
  496. } else {
  497. Z_ADDREF_P(iterator);
  498. }
  499. break;
  500. }
  501. }
  502. if (!instanceof_function(Z_OBJCE_P(iterator), spl_ce_RecursiveIterator)) {
  503. if (iterator) {
  504. zval_ptr_dtor(iterator);
  505. }
  506. zend_throw_exception(spl_ce_InvalidArgumentException, "An instance of RecursiveIterator or IteratorAggregate creating it is required", 0);
  507. return;
  508. }
  509. intern = Z_SPLRECURSIVE_IT_P(object);
  510. intern->iterators = emalloc(sizeof(spl_sub_iterator));
  511. intern->level = 0;
  512. intern->mode = mode;
  513. intern->flags = (int)flags;
  514. intern->max_depth = -1;
  515. intern->in_iteration = 0;
  516. intern->ce = Z_OBJCE_P(object);
  517. intern->beginIteration = zend_hash_str_find_ptr(&intern->ce->function_table, "beginiteration", sizeof("beginiteration") - 1);
  518. if (intern->beginIteration->common.scope == ce_base) {
  519. intern->beginIteration = NULL;
  520. }
  521. intern->endIteration = zend_hash_str_find_ptr(&intern->ce->function_table, "enditeration", sizeof("enditeration") - 1);
  522. if (intern->endIteration->common.scope == ce_base) {
  523. intern->endIteration = NULL;
  524. }
  525. intern->callHasChildren = zend_hash_str_find_ptr(&intern->ce->function_table, "callhaschildren", sizeof("callHasChildren") - 1);
  526. if (intern->callHasChildren->common.scope == ce_base) {
  527. intern->callHasChildren = NULL;
  528. }
  529. intern->callGetChildren = zend_hash_str_find_ptr(&intern->ce->function_table, "callgetchildren", sizeof("callGetChildren") - 1);
  530. if (intern->callGetChildren->common.scope == ce_base) {
  531. intern->callGetChildren = NULL;
  532. }
  533. intern->beginChildren = zend_hash_str_find_ptr(&intern->ce->function_table, "beginchildren", sizeof("beginchildren") - 1);
  534. if (intern->beginChildren->common.scope == ce_base) {
  535. intern->beginChildren = NULL;
  536. }
  537. intern->endChildren = zend_hash_str_find_ptr(&intern->ce->function_table, "endchildren", sizeof("endchildren") - 1);
  538. if (intern->endChildren->common.scope == ce_base) {
  539. intern->endChildren = NULL;
  540. }
  541. intern->nextElement = zend_hash_str_find_ptr(&intern->ce->function_table, "nextelement", sizeof("nextElement") - 1);
  542. if (intern->nextElement->common.scope == ce_base) {
  543. intern->nextElement = NULL;
  544. }
  545. ce_iterator = Z_OBJCE_P(iterator); /* respect inheritance, don't use spl_ce_RecursiveIterator */
  546. intern->iterators[0].iterator = ce_iterator->get_iterator(ce_iterator, iterator, 0);
  547. ZVAL_OBJ(&intern->iterators[0].zobject, Z_OBJ_P(iterator));
  548. intern->iterators[0].ce = ce_iterator;
  549. intern->iterators[0].state = RS_START;
  550. intern->iterators[0].haschildren = NULL;
  551. intern->iterators[0].getchildren = NULL;
  552. if (EG(exception)) {
  553. zend_object_iterator *sub_iter;
  554. while (intern->level >= 0) {
  555. sub_iter = intern->iterators[intern->level].iterator;
  556. zend_iterator_dtor(sub_iter);
  557. zval_ptr_dtor(&intern->iterators[intern->level--].zobject);
  558. }
  559. efree(intern->iterators);
  560. intern->iterators = NULL;
  561. }
  562. }
  563. /* {{{ Creates a RecursiveIteratorIterator from a RecursiveIterator. */
  564. PHP_METHOD(RecursiveIteratorIterator, __construct)
  565. {
  566. spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveIteratorIterator, zend_ce_iterator, RIT_RecursiveIteratorIterator);
  567. } /* }}} */
  568. /* {{{ Rewind the iterator to the first element of the top level inner iterator. */
  569. PHP_METHOD(RecursiveIteratorIterator, rewind)
  570. {
  571. spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS);
  572. if (zend_parse_parameters_none() == FAILURE) {
  573. RETURN_THROWS();
  574. }
  575. spl_recursive_it_rewind_ex(object, ZEND_THIS);
  576. } /* }}} */
  577. /* {{{ Check whether the current position is valid */
  578. PHP_METHOD(RecursiveIteratorIterator, valid)
  579. {
  580. spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS);
  581. if (zend_parse_parameters_none() == FAILURE) {
  582. RETURN_THROWS();
  583. }
  584. RETURN_BOOL(spl_recursive_it_valid_ex(object, ZEND_THIS) == SUCCESS);
  585. } /* }}} */
  586. /* {{{ Access the current key */
  587. PHP_METHOD(RecursiveIteratorIterator, key)
  588. {
  589. spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS);
  590. zend_object_iterator *iterator;
  591. if (zend_parse_parameters_none() == FAILURE) {
  592. RETURN_THROWS();
  593. }
  594. SPL_FETCH_SUB_ITERATOR(iterator, object);
  595. if (iterator->funcs->get_current_key) {
  596. iterator->funcs->get_current_key(iterator, return_value);
  597. } else {
  598. RETURN_NULL();
  599. }
  600. } /* }}} */
  601. /* {{{ Access the current element value */
  602. PHP_METHOD(RecursiveIteratorIterator, current)
  603. {
  604. spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS);
  605. zend_object_iterator *iterator;
  606. zval *data;
  607. if (zend_parse_parameters_none() == FAILURE) {
  608. RETURN_THROWS();
  609. }
  610. SPL_FETCH_SUB_ITERATOR(iterator, object);
  611. data = iterator->funcs->get_current_data(iterator);
  612. if (data) {
  613. RETURN_COPY_DEREF(data);
  614. }
  615. } /* }}} */
  616. /* {{{ Move forward to the next element */
  617. PHP_METHOD(RecursiveIteratorIterator, next)
  618. {
  619. spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS);
  620. if (zend_parse_parameters_none() == FAILURE) {
  621. RETURN_THROWS();
  622. }
  623. spl_recursive_it_move_forward_ex(object, ZEND_THIS);
  624. } /* }}} */
  625. /* {{{ Get the current depth of the recursive iteration */
  626. PHP_METHOD(RecursiveIteratorIterator, getDepth)
  627. {
  628. spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS);
  629. if (zend_parse_parameters_none() == FAILURE) {
  630. RETURN_THROWS();
  631. }
  632. RETURN_LONG(object->level);
  633. } /* }}} */
  634. /* {{{ The current active sub iterator or the iterator at specified level */
  635. PHP_METHOD(RecursiveIteratorIterator, getSubIterator)
  636. {
  637. spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS);
  638. zend_long level;
  639. bool level_is_null = 1;
  640. zval *value;
  641. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l!", &level, &level_is_null) == FAILURE) {
  642. RETURN_THROWS();
  643. }
  644. if (level_is_null) {
  645. level = object->level;
  646. } else if (level < 0 || level > object->level) {
  647. RETURN_NULL();
  648. }
  649. if(!object->iterators) {
  650. zend_throw_error(NULL, "The object is in an invalid state as the parent constructor was not called");
  651. RETURN_THROWS();
  652. }
  653. value = &object->iterators[level].zobject;
  654. RETURN_COPY_DEREF(value);
  655. } /* }}} */
  656. /* {{{ The current active sub iterator */
  657. PHP_METHOD(RecursiveIteratorIterator, getInnerIterator)
  658. {
  659. spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS);
  660. zval *zobject;
  661. if (zend_parse_parameters_none() == FAILURE) {
  662. RETURN_THROWS();
  663. }
  664. SPL_FETCH_SUB_ELEMENT_ADDR(zobject, object, zobject);
  665. RETURN_COPY_DEREF(zobject);
  666. } /* }}} */
  667. /* {{{ Called when iteration begins (after first rewind() call) */
  668. PHP_METHOD(RecursiveIteratorIterator, beginIteration)
  669. {
  670. if (zend_parse_parameters_none() == FAILURE) {
  671. RETURN_THROWS();
  672. }
  673. /* nothing to do */
  674. } /* }}} */
  675. /* {{{ Called when iteration ends (when valid() first returns false */
  676. PHP_METHOD(RecursiveIteratorIterator, endIteration)
  677. {
  678. if (zend_parse_parameters_none() == FAILURE) {
  679. RETURN_THROWS();
  680. }
  681. /* nothing to do */
  682. } /* }}} */
  683. /* {{{ Called for each element to test whether it has children */
  684. PHP_METHOD(RecursiveIteratorIterator, callHasChildren)
  685. {
  686. spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS);
  687. zend_class_entry *ce;
  688. zval *zobject;
  689. if (zend_parse_parameters_none() == FAILURE) {
  690. RETURN_THROWS();
  691. }
  692. if (!object->iterators) {
  693. RETURN_FALSE;
  694. }
  695. SPL_FETCH_SUB_ELEMENT(ce, object, ce);
  696. zobject = &object->iterators[object->level].zobject;
  697. if (Z_TYPE_P(zobject) == IS_UNDEF) {
  698. RETURN_FALSE;
  699. } else {
  700. zend_call_method_with_0_params(Z_OBJ_P(zobject), ce, &object->iterators[object->level].haschildren, "haschildren", return_value);
  701. if (Z_TYPE_P(return_value) == IS_UNDEF) {
  702. RETURN_FALSE;
  703. }
  704. }
  705. } /* }}} */
  706. /* {{{ Return children of current element */
  707. PHP_METHOD(RecursiveIteratorIterator, callGetChildren)
  708. {
  709. spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS);
  710. zend_class_entry *ce;
  711. zval *zobject;
  712. if (zend_parse_parameters_none() == FAILURE) {
  713. RETURN_THROWS();
  714. }
  715. SPL_FETCH_SUB_ELEMENT(ce, object, ce);
  716. zobject = &object->iterators[object->level].zobject;
  717. if (Z_TYPE_P(zobject) == IS_UNDEF) {
  718. return;
  719. } else {
  720. zend_call_method_with_0_params(Z_OBJ_P(zobject), ce, &object->iterators[object->level].getchildren, "getchildren", return_value);
  721. if (Z_TYPE_P(return_value) == IS_UNDEF) {
  722. RETURN_NULL();
  723. }
  724. }
  725. } /* }}} */
  726. /* {{{ Called when recursing one level down */
  727. PHP_METHOD(RecursiveIteratorIterator, beginChildren)
  728. {
  729. if (zend_parse_parameters_none() == FAILURE) {
  730. RETURN_THROWS();
  731. }
  732. /* nothing to do */
  733. } /* }}} */
  734. /* {{{ Called when end recursing one level */
  735. PHP_METHOD(RecursiveIteratorIterator, endChildren)
  736. {
  737. if (zend_parse_parameters_none() == FAILURE) {
  738. RETURN_THROWS();
  739. }
  740. /* nothing to do */
  741. } /* }}} */
  742. /* {{{ Called when the next element is available */
  743. PHP_METHOD(RecursiveIteratorIterator, nextElement)
  744. {
  745. if (zend_parse_parameters_none() == FAILURE) {
  746. RETURN_THROWS();
  747. }
  748. /* nothing to do */
  749. } /* }}} */
  750. /* {{{ Set the maximum allowed depth (or any depth if pmax_depth = -1] */
  751. PHP_METHOD(RecursiveIteratorIterator, setMaxDepth)
  752. {
  753. spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS);
  754. zend_long max_depth = -1;
  755. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &max_depth) == FAILURE) {
  756. RETURN_THROWS();
  757. }
  758. if (max_depth < -1) {
  759. zend_argument_value_error(1, "must be greater than or equal to -1");
  760. RETURN_THROWS();
  761. } else if (max_depth > INT_MAX) {
  762. max_depth = INT_MAX;
  763. }
  764. object->max_depth = (int)max_depth;
  765. } /* }}} */
  766. /* {{{ Return the maximum accepted depth or false if any depth is allowed */
  767. PHP_METHOD(RecursiveIteratorIterator, getMaxDepth)
  768. {
  769. spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS);
  770. if (zend_parse_parameters_none() == FAILURE) {
  771. RETURN_THROWS();
  772. }
  773. if (object->max_depth == -1) {
  774. RETURN_FALSE;
  775. } else {
  776. RETURN_LONG(object->max_depth);
  777. }
  778. } /* }}} */
  779. static zend_function *spl_recursive_it_get_method(zend_object **zobject, zend_string *method, const zval *key)
  780. {
  781. zend_function *function_handler;
  782. spl_recursive_it_object *object = spl_recursive_it_from_obj(*zobject);
  783. zend_long level = object->level;
  784. zval *zobj;
  785. if (!object->iterators) {
  786. zend_throw_error(NULL, "The %s instance wasn't initialized properly", ZSTR_VAL((*zobject)->ce->name));
  787. return NULL;
  788. }
  789. zobj = &object->iterators[level].zobject;
  790. function_handler = zend_std_get_method(zobject, method, key);
  791. if (!function_handler) {
  792. if ((function_handler = zend_hash_find_ptr(&Z_OBJCE_P(zobj)->function_table, method)) == NULL) {
  793. *zobject = Z_OBJ_P(zobj);
  794. function_handler = (*zobject)->handlers->get_method(zobject, method, key);
  795. } else {
  796. *zobject = Z_OBJ_P(zobj);
  797. }
  798. }
  799. return function_handler;
  800. }
  801. /* {{{ spl_RecursiveIteratorIterator_free_storage */
  802. static void spl_RecursiveIteratorIterator_free_storage(zend_object *_object)
  803. {
  804. spl_recursive_it_object *object = spl_recursive_it_from_obj(_object);
  805. if (object->iterators) {
  806. while (object->level >= 0) {
  807. zend_object_iterator *sub_iter = object->iterators[object->level].iterator;
  808. zend_iterator_dtor(sub_iter);
  809. zval_ptr_dtor(&object->iterators[object->level].zobject);
  810. object->level--;
  811. }
  812. efree(object->iterators);
  813. object->iterators = NULL;
  814. }
  815. zend_object_std_dtor(&object->std);
  816. for (size_t i = 0; i < 6; i++) {
  817. if (object->prefix[i]) {
  818. zend_string_release(object->prefix[i]);
  819. }
  820. }
  821. if (object->postfix[0]) {
  822. zend_string_release(object->postfix[0]);
  823. }
  824. }
  825. /* }}} */
  826. static HashTable *spl_RecursiveIteratorIterator_get_gc(zend_object *obj, zval **table, int *n)
  827. {
  828. spl_recursive_it_object *object = spl_recursive_it_from_obj(obj);
  829. zend_get_gc_buffer *gc_buffer = zend_get_gc_buffer_create();
  830. if (object->iterators) {
  831. for (int level = 0; level <= object->level; level++) {
  832. zend_get_gc_buffer_add_zval(gc_buffer, &object->iterators[level].zobject);
  833. zend_get_gc_buffer_add_obj(gc_buffer, &object->iterators[level].iterator->std);
  834. }
  835. }
  836. zend_get_gc_buffer_use(gc_buffer, table, n);
  837. return zend_std_get_properties(obj);
  838. }
  839. /* {{{ spl_RecursiveIteratorIterator_new_ex */
  840. static zend_object *spl_RecursiveIteratorIterator_new_ex(zend_class_entry *class_type, int init_prefix)
  841. {
  842. spl_recursive_it_object *intern;
  843. intern = zend_object_alloc(sizeof(spl_recursive_it_object), class_type);
  844. if (init_prefix) {
  845. intern->prefix[0] = ZSTR_EMPTY_ALLOC();
  846. intern->prefix[1] = zend_string_init("| ", 2, 0);
  847. intern->prefix[2] = zend_string_init(" ", 2, 0);
  848. intern->prefix[3] = zend_string_init("|-", 2, 0);
  849. intern->prefix[4] = zend_string_init("\\-", 2, 0);
  850. intern->prefix[5] = ZSTR_EMPTY_ALLOC();
  851. intern->postfix[0] = ZSTR_EMPTY_ALLOC();
  852. }
  853. zend_object_std_init(&intern->std, class_type);
  854. object_properties_init(&intern->std, class_type);
  855. intern->std.handlers = &spl_handlers_rec_it_it;
  856. return &intern->std;
  857. }
  858. /* }}} */
  859. /* {{{ spl_RecursiveIteratorIterator_new */
  860. static zend_object *spl_RecursiveIteratorIterator_new(zend_class_entry *class_type)
  861. {
  862. return spl_RecursiveIteratorIterator_new_ex(class_type, 0);
  863. }
  864. /* }}} */
  865. /* {{{ spl_RecursiveTreeIterator_new */
  866. static zend_object *spl_RecursiveTreeIterator_new(zend_class_entry *class_type)
  867. {
  868. return spl_RecursiveIteratorIterator_new_ex(class_type, 1);
  869. }
  870. /* }}} */
  871. static zend_string *spl_recursive_tree_iterator_get_prefix(spl_recursive_it_object *object)
  872. {
  873. smart_str str = {0};
  874. zval has_next;
  875. int level;
  876. smart_str_append(&str, object->prefix[0]);
  877. for (level = 0; level < object->level; ++level) {
  878. zend_call_method_with_0_params(Z_OBJ(object->iterators[level].zobject), object->iterators[level].ce, NULL, "hasnext", &has_next);
  879. if (Z_TYPE(has_next) != IS_UNDEF) {
  880. if (Z_TYPE(has_next) == IS_TRUE) {
  881. smart_str_append(&str, object->prefix[1]);
  882. } else {
  883. smart_str_append(&str, object->prefix[2]);
  884. }
  885. zval_ptr_dtor(&has_next);
  886. }
  887. }
  888. zend_call_method_with_0_params(Z_OBJ(object->iterators[level].zobject), object->iterators[level].ce, NULL, "hasnext", &has_next);
  889. if (Z_TYPE(has_next) != IS_UNDEF) {
  890. if (Z_TYPE(has_next) == IS_TRUE) {
  891. smart_str_append(&str, object->prefix[3]);
  892. } else {
  893. smart_str_append(&str, object->prefix[4]);
  894. }
  895. zval_ptr_dtor(&has_next);
  896. }
  897. smart_str_append(&str, object->prefix[5]);
  898. smart_str_0(&str);
  899. return str.s;
  900. }
  901. static zend_string *spl_recursive_tree_iterator_get_entry(spl_recursive_it_object *object)
  902. {
  903. zend_object_iterator *iterator = object->iterators[object->level].iterator;
  904. zval *data = iterator->funcs->get_current_data(iterator);
  905. if (!data) {
  906. return NULL;
  907. }
  908. ZVAL_DEREF(data);
  909. if (Z_TYPE_P(data) == IS_ARRAY) {
  910. /* TODO: Remove this special case? */
  911. return ZSTR_KNOWN(ZEND_STR_ARRAY_CAPITALIZED);
  912. }
  913. return zval_get_string(data);
  914. }
  915. static zend_string *spl_recursive_tree_iterator_get_postfix(spl_recursive_it_object *object)
  916. {
  917. return zend_string_copy(object->postfix[0]);
  918. }
  919. /* {{{ RecursiveIteratorIterator to generate ASCII graphic trees for the entries in a RecursiveIterator */
  920. PHP_METHOD(RecursiveTreeIterator, __construct)
  921. {
  922. spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveTreeIterator, zend_ce_iterator, RIT_RecursiveTreeIterator);
  923. } /* }}} */
  924. /* {{{ Sets prefix parts as used in getPrefix() */
  925. PHP_METHOD(RecursiveTreeIterator, setPrefixPart)
  926. {
  927. zend_long part;
  928. zend_string *prefix;
  929. spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS);
  930. if (zend_parse_parameters(ZEND_NUM_ARGS(), "lS", &part, &prefix) == FAILURE) {
  931. RETURN_THROWS();
  932. }
  933. if (0 > part || part > 5) {
  934. zend_argument_value_error(1, "must be a RecursiveTreeIterator::PREFIX_* constant");
  935. RETURN_THROWS();
  936. }
  937. zend_string_release(object->prefix[part]);
  938. object->prefix[part] = zend_string_copy(prefix);
  939. } /* }}} */
  940. /* {{{ Returns the string to place in front of current element */
  941. PHP_METHOD(RecursiveTreeIterator, getPrefix)
  942. {
  943. spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS);
  944. if (zend_parse_parameters_none() == FAILURE) {
  945. RETURN_THROWS();
  946. }
  947. if(!object->iterators) {
  948. zend_throw_error(NULL, "The object is in an invalid state as the parent constructor was not called");
  949. RETURN_THROWS();
  950. }
  951. RETURN_STR(spl_recursive_tree_iterator_get_prefix(object));
  952. } /* }}} */
  953. /* {{{ Sets postfix as used in getPostfix() */
  954. PHP_METHOD(RecursiveTreeIterator, setPostfix)
  955. {
  956. spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS);
  957. zend_string *postfix;
  958. if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &postfix) == FAILURE) {
  959. RETURN_THROWS();
  960. }
  961. zend_string_release(object->postfix[0]);
  962. object->postfix[0] = zend_string_copy(postfix);
  963. } /* }}} */
  964. /* {{{ Returns the string presentation built for current element */
  965. PHP_METHOD(RecursiveTreeIterator, getEntry)
  966. {
  967. spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS);
  968. if (zend_parse_parameters_none() == FAILURE) {
  969. RETURN_THROWS();
  970. }
  971. if(!object->iterators) {
  972. zend_throw_error(NULL, "The object is in an invalid state as the parent constructor was not called");
  973. RETURN_THROWS();
  974. }
  975. zend_string *entry = spl_recursive_tree_iterator_get_entry(object);
  976. if (!entry) {
  977. // TODO: Can this happen? It's not in the stubs.
  978. RETURN_NULL();
  979. }
  980. RETURN_STR(entry);
  981. } /* }}} */
  982. /* {{{ Returns the string to place after the current element */
  983. PHP_METHOD(RecursiveTreeIterator, getPostfix)
  984. {
  985. spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS);
  986. if (zend_parse_parameters_none() == FAILURE) {
  987. RETURN_THROWS();
  988. }
  989. if(!object->iterators) {
  990. zend_throw_error(NULL, "The object is in an invalid state as the parent constructor was not called");
  991. RETURN_THROWS();
  992. }
  993. RETURN_STR(spl_recursive_tree_iterator_get_postfix(object));
  994. } /* }}} */
  995. /* {{{ Returns the current element prefixed and postfixed */
  996. PHP_METHOD(RecursiveTreeIterator, current)
  997. {
  998. spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS);
  999. if (zend_parse_parameters_none() == FAILURE) {
  1000. RETURN_THROWS();
  1001. }
  1002. if(!object->iterators) {
  1003. zend_throw_error(NULL, "The object is in an invalid state as the parent constructor was not called");
  1004. RETURN_THROWS();
  1005. }
  1006. if (object->flags & RTIT_BYPASS_CURRENT) {
  1007. zend_object_iterator *iterator = object->iterators[object->level].iterator;
  1008. zval *data;
  1009. SPL_FETCH_SUB_ITERATOR(iterator, object);
  1010. data = iterator->funcs->get_current_data(iterator);
  1011. if (data) {
  1012. RETURN_COPY_DEREF(data);
  1013. } else {
  1014. RETURN_NULL();
  1015. }
  1016. }
  1017. zend_string *entry = spl_recursive_tree_iterator_get_entry(object);
  1018. if (!entry) {
  1019. RETURN_NULL();
  1020. }
  1021. zend_string *prefix = spl_recursive_tree_iterator_get_prefix(object);
  1022. zend_string *postfix = spl_recursive_tree_iterator_get_postfix(object);
  1023. zend_string *result = zend_string_concat3(
  1024. ZSTR_VAL(prefix), ZSTR_LEN(prefix),
  1025. ZSTR_VAL(entry), ZSTR_LEN(entry),
  1026. ZSTR_VAL(postfix), ZSTR_LEN(postfix));
  1027. zend_string_release(entry);
  1028. zend_string_release(prefix);
  1029. zend_string_release(postfix);
  1030. RETURN_NEW_STR(result);
  1031. } /* }}} */
  1032. /* {{{ Returns the current key prefixed and postfixed */
  1033. PHP_METHOD(RecursiveTreeIterator, key)
  1034. {
  1035. spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS);
  1036. zend_object_iterator *iterator;
  1037. zval key;
  1038. if (zend_parse_parameters_none() == FAILURE) {
  1039. RETURN_THROWS();
  1040. }
  1041. SPL_FETCH_SUB_ITERATOR(iterator, object);
  1042. if (iterator->funcs->get_current_key) {
  1043. iterator->funcs->get_current_key(iterator, &key);
  1044. } else {
  1045. ZVAL_NULL(&key);
  1046. }
  1047. if (object->flags & RTIT_BYPASS_KEY) {
  1048. RETURN_COPY_VALUE(&key);
  1049. }
  1050. zend_string *key_str = zval_get_string(&key);
  1051. zend_string *prefix = spl_recursive_tree_iterator_get_prefix(object);
  1052. zend_string *postfix = spl_recursive_tree_iterator_get_postfix(object);
  1053. zend_string *result = zend_string_concat3(
  1054. ZSTR_VAL(prefix), ZSTR_LEN(prefix),
  1055. ZSTR_VAL(key_str), ZSTR_LEN(key_str),
  1056. ZSTR_VAL(postfix), ZSTR_LEN(postfix));
  1057. zend_string_release(key_str);
  1058. zend_string_release(prefix);
  1059. zend_string_release(postfix);
  1060. zval_ptr_dtor(&key);
  1061. RETURN_NEW_STR(result);
  1062. } /* }}} */
  1063. static zend_function *spl_dual_it_get_method(zend_object **object, zend_string *method, const zval *key)
  1064. {
  1065. zend_function *function_handler;
  1066. spl_dual_it_object *intern;
  1067. intern = spl_dual_it_from_obj(*object);
  1068. function_handler = zend_std_get_method(object, method, key);
  1069. if (!function_handler && intern->inner.ce) {
  1070. if ((function_handler = zend_hash_find_ptr(&intern->inner.ce->function_table, method)) == NULL) {
  1071. if (Z_OBJ_HT(intern->inner.zobject)->get_method) {
  1072. *object = Z_OBJ(intern->inner.zobject);
  1073. function_handler = (*object)->handlers->get_method(object, method, key);
  1074. }
  1075. } else {
  1076. *object = Z_OBJ(intern->inner.zobject);
  1077. }
  1078. }
  1079. return function_handler;
  1080. }
  1081. #define SPL_CHECK_CTOR(intern, classname) \
  1082. if (intern->dit_type == DIT_Unknown) { \
  1083. /* TODO Normal Error? */ \
  1084. zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Classes derived from %s must call %s::__construct()", \
  1085. ZSTR_VAL((spl_ce_##classname)->name), ZSTR_VAL((spl_ce_##classname)->name)); \
  1086. RETURN_THROWS(); \
  1087. }
  1088. #define APPENDIT_CHECK_CTOR(intern) SPL_CHECK_CTOR(intern, AppendIterator)
  1089. static inline int spl_dual_it_fetch(spl_dual_it_object *intern, int check_more);
  1090. static inline int spl_cit_check_flags(zend_long flags)
  1091. {
  1092. zend_long cnt = 0;
  1093. cnt += (flags & CIT_CALL_TOSTRING) ? 1 : 0;
  1094. cnt += (flags & CIT_TOSTRING_USE_KEY) ? 1 : 0;
  1095. cnt += (flags & CIT_TOSTRING_USE_CURRENT) ? 1 : 0;
  1096. cnt += (flags & CIT_TOSTRING_USE_INNER) ? 1 : 0;
  1097. return cnt <= 1 ? SUCCESS : FAILURE;
  1098. }
  1099. static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce_base, zend_class_entry *ce_inner, dual_it_type dit_type)
  1100. {
  1101. zval *zobject, retval;
  1102. spl_dual_it_object *intern;
  1103. zend_class_entry *ce = NULL;
  1104. int inc_refcount = 1;
  1105. zend_error_handling error_handling;
  1106. intern = Z_SPLDUAL_IT_P(ZEND_THIS);
  1107. if (intern->dit_type != DIT_Unknown) {
  1108. zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s::getIterator() must be called exactly once per instance", ZSTR_VAL(ce_base->name));
  1109. return NULL;
  1110. }
  1111. switch (dit_type) {
  1112. case DIT_LimitIterator: {
  1113. intern->u.limit.offset = 0; /* start at beginning */
  1114. intern->u.limit.count = -1; /* get all */
  1115. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|ll", &zobject, ce_inner, &intern->u.limit.offset, &intern->u.limit.count) == FAILURE) {
  1116. return NULL;
  1117. }
  1118. if (intern->u.limit.offset < 0) {
  1119. zend_argument_value_error(2, "must be greater than or equal to 0");
  1120. return NULL;
  1121. }
  1122. if (intern->u.limit.count < -1) {
  1123. zend_argument_value_error(3, "must be greater than or equal to -1");
  1124. return NULL;
  1125. }
  1126. break;
  1127. }
  1128. case DIT_CachingIterator:
  1129. case DIT_RecursiveCachingIterator: {
  1130. zend_long flags = CIT_CALL_TOSTRING;
  1131. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|l", &zobject, ce_inner, &flags) == FAILURE) {
  1132. return NULL;
  1133. }
  1134. if (spl_cit_check_flags(flags) != SUCCESS) {
  1135. zend_argument_value_error(2, "must contain only one of CachingIterator::CALL_TOSTRING, "
  1136. "CachingIterator::TOSTRING_USE_KEY, CachingIterator::TOSTRING_USE_CURRENT, "
  1137. "or CachingIterator::TOSTRING_USE_INNER");
  1138. return NULL;
  1139. }
  1140. intern->u.caching.flags |= flags & CIT_PUBLIC;
  1141. array_init(&intern->u.caching.zcache);
  1142. break;
  1143. }
  1144. case DIT_IteratorIterator: {
  1145. zend_class_entry *ce_cast;
  1146. zend_string *class_name = NULL;
  1147. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|S!", &zobject, ce_inner, &class_name) == FAILURE) {
  1148. return NULL;
  1149. }
  1150. ce = Z_OBJCE_P(zobject);
  1151. if (!instanceof_function(ce, zend_ce_iterator)) {
  1152. if (class_name) {
  1153. if (!(ce_cast = zend_lookup_class(class_name))
  1154. || !instanceof_function(ce, ce_cast)
  1155. || !ce_cast->get_iterator
  1156. ) {
  1157. zend_throw_exception(spl_ce_LogicException, "Class to downcast to not found or not base class or does not implement Traversable", 0);
  1158. return NULL;
  1159. }
  1160. ce = ce_cast;
  1161. }
  1162. if (instanceof_function(ce, zend_ce_aggregate)) {
  1163. if (spl_get_iterator_from_aggregate(&retval, ce, Z_OBJ_P(zobject)) == FAILURE) {
  1164. return NULL;
  1165. }
  1166. zobject = &retval;
  1167. ce = Z_OBJCE_P(zobject);
  1168. inc_refcount = 0;
  1169. }
  1170. }
  1171. break;
  1172. }
  1173. case DIT_AppendIterator:
  1174. if (zend_parse_parameters_none() == FAILURE) {
  1175. return NULL;
  1176. }
  1177. intern->dit_type = DIT_AppendIterator;
  1178. object_init_ex(&intern->u.append.zarrayit, spl_ce_ArrayIterator);
  1179. zend_call_method_with_0_params(Z_OBJ(intern->u.append.zarrayit), spl_ce_ArrayIterator, &spl_ce_ArrayIterator->constructor, "__construct", NULL);
  1180. intern->u.append.iterator = spl_ce_ArrayIterator->get_iterator(spl_ce_ArrayIterator, &intern->u.append.zarrayit, 0);
  1181. return intern;
  1182. case DIT_RegexIterator:
  1183. case DIT_RecursiveRegexIterator: {
  1184. zend_string *regex;
  1185. zend_long mode = REGIT_MODE_MATCH;
  1186. intern->u.regex.use_flags = ZEND_NUM_ARGS() >= 5;
  1187. intern->u.regex.flags = 0;
  1188. intern->u.regex.preg_flags = 0;
  1189. if (zend_parse_parameters(ZEND_NUM_ARGS(), "OS|lll", &zobject, ce_inner, &regex, &mode, &intern->u.regex.flags, &intern->u.regex.preg_flags) == FAILURE) {
  1190. return NULL;
  1191. }
  1192. if (mode < 0 || mode >= REGIT_MODE_MAX) {
  1193. zend_argument_value_error(3, "must be RegexIterator::MATCH, RegexIterator::GET_MATCH, "
  1194. "RegexIterator::ALL_MATCHES, RegexIterator::SPLIT, or RegexIterator::REPLACE");
  1195. return NULL;
  1196. }
  1197. /* pcre_get_compiled_regex_cache() might emit E_WARNINGs that we want to promote to exception */
  1198. zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling);
  1199. intern->u.regex.pce = pcre_get_compiled_regex_cache(regex);
  1200. zend_restore_error_handling(&error_handling);
  1201. if (intern->u.regex.pce == NULL) {
  1202. /* pcre_get_compiled_regex_cache has already sent error */
  1203. return NULL;
  1204. }
  1205. intern->u.regex.mode = mode;
  1206. intern->u.regex.regex = zend_string_copy(regex);
  1207. php_pcre_pce_incref(intern->u.regex.pce);
  1208. break;
  1209. }
  1210. case DIT_CallbackFilterIterator:
  1211. case DIT_RecursiveCallbackFilterIterator: {
  1212. _spl_cbfilter_it_intern *cfi = emalloc(sizeof(*cfi));
  1213. cfi->fci.object = NULL;
  1214. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Of", &zobject, ce_inner, &cfi->fci, &cfi->fcc) == FAILURE) {
  1215. efree(cfi);
  1216. return NULL;
  1217. }
  1218. Z_TRY_ADDREF(cfi->fci.function_name);
  1219. cfi->object = cfi->fcc.object;
  1220. if (cfi->object) GC_ADDREF(cfi->object);
  1221. intern->u.cbfilter = cfi;
  1222. break;
  1223. }
  1224. default:
  1225. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &zobject, ce_inner) == FAILURE) {
  1226. return NULL;
  1227. }
  1228. break;
  1229. }
  1230. intern->dit_type = dit_type;
  1231. if (inc_refcount) {
  1232. Z_ADDREF_P(zobject);
  1233. }
  1234. ZVAL_OBJ(&intern->inner.zobject, Z_OBJ_P(zobject));
  1235. intern->inner.ce = dit_type == DIT_IteratorIterator ? ce : Z_OBJCE_P(zobject);
  1236. intern->inner.object = Z_OBJ_P(zobject);
  1237. intern->inner.iterator = intern->inner.ce->get_iterator(intern->inner.ce, zobject, 0);
  1238. return intern;
  1239. }
  1240. /* {{{ Create an Iterator from another iterator */
  1241. PHP_METHOD(FilterIterator, __construct)
  1242. {
  1243. spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_FilterIterator, zend_ce_iterator, DIT_FilterIterator);
  1244. } /* }}} */
  1245. /* {{{ Create an Iterator from another iterator */
  1246. PHP_METHOD(CallbackFilterIterator, __construct)
  1247. {
  1248. spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_CallbackFilterIterator, zend_ce_iterator, DIT_CallbackFilterIterator);
  1249. } /* }}} */
  1250. /* {{{ Get the inner iterator */
  1251. PHP_METHOD(IteratorIterator, getInnerIterator)
  1252. {
  1253. spl_dual_it_object *intern;
  1254. if (zend_parse_parameters_none() == FAILURE) {
  1255. RETURN_THROWS();
  1256. }
  1257. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  1258. if (!Z_ISUNDEF(intern->inner.zobject)) {
  1259. zval *value = &intern->inner.zobject;
  1260. RETURN_COPY_DEREF(value);
  1261. } else {
  1262. RETURN_NULL();
  1263. }
  1264. } /* }}} */
  1265. static inline void spl_dual_it_free(spl_dual_it_object *intern)
  1266. {
  1267. if (intern->inner.iterator && intern->inner.iterator->funcs->invalidate_current) {
  1268. intern->inner.iterator->funcs->invalidate_current(intern->inner.iterator);
  1269. }
  1270. if (Z_TYPE(intern->current.data) != IS_UNDEF) {
  1271. zval_ptr_dtor(&intern->current.data);
  1272. ZVAL_UNDEF(&intern->current.data);
  1273. }
  1274. if (Z_TYPE(intern->current.key) != IS_UNDEF) {
  1275. zval_ptr_dtor(&intern->current.key);
  1276. ZVAL_UNDEF(&intern->current.key);
  1277. }
  1278. if (intern->dit_type == DIT_CachingIterator || intern->dit_type == DIT_RecursiveCachingIterator) {
  1279. if (intern->u.caching.zstr) {
  1280. zend_string_release(intern->u.caching.zstr);
  1281. intern->u.caching.zstr = NULL;
  1282. }
  1283. if (Z_TYPE(intern->u.caching.zchildren) != IS_UNDEF) {
  1284. zval_ptr_dtor(&intern->u.caching.zchildren);
  1285. ZVAL_UNDEF(&intern->u.caching.zchildren);
  1286. }
  1287. }
  1288. }
  1289. static inline void spl_dual_it_rewind(spl_dual_it_object *intern)
  1290. {
  1291. spl_dual_it_free(intern);
  1292. intern->current.pos = 0;
  1293. if (intern->inner.iterator && intern->inner.iterator->funcs->rewind) {
  1294. intern->inner.iterator->funcs->rewind(intern->inner.iterator);
  1295. }
  1296. }
  1297. static inline int spl_dual_it_valid(spl_dual_it_object *intern)
  1298. {
  1299. if (!intern->inner.iterator) {
  1300. return FAILURE;
  1301. }
  1302. /* FAILURE / SUCCESS */
  1303. return intern->inner.iterator->funcs->valid(intern->inner.iterator);
  1304. }
  1305. static inline int spl_dual_it_fetch(spl_dual_it_object *intern, int check_more)
  1306. {
  1307. zval *data;
  1308. spl_dual_it_free(intern);
  1309. if (!check_more || spl_dual_it_valid(intern) == SUCCESS) {
  1310. data = intern->inner.iterator->funcs->get_current_data(intern->inner.iterator);
  1311. if (data) {
  1312. ZVAL_COPY(&intern->current.data, data);
  1313. }
  1314. if (intern->inner.iterator->funcs->get_current_key) {
  1315. intern->inner.iterator->funcs->get_current_key(intern->inner.iterator, &intern->current.key);
  1316. if (EG(exception)) {
  1317. zval_ptr_dtor(&intern->current.key);
  1318. ZVAL_UNDEF(&intern->current.key);
  1319. }
  1320. } else {
  1321. ZVAL_LONG(&intern->current.key, intern->current.pos);
  1322. }
  1323. return EG(exception) ? FAILURE : SUCCESS;
  1324. }
  1325. return FAILURE;
  1326. }
  1327. static inline void spl_dual_it_next(spl_dual_it_object *intern, int do_free)
  1328. {
  1329. if (do_free) {
  1330. spl_dual_it_free(intern);
  1331. } else if (!intern->inner.iterator) {
  1332. zend_throw_error(NULL, "The inner constructor wasn't initialized with an iterator instance");
  1333. return;
  1334. }
  1335. intern->inner.iterator->funcs->move_forward(intern->inner.iterator);
  1336. intern->current.pos++;
  1337. }
  1338. /* {{{ Rewind the iterator */
  1339. PHP_METHOD(IteratorIterator, rewind)
  1340. {
  1341. spl_dual_it_object *intern;
  1342. if (zend_parse_parameters_none() == FAILURE) {
  1343. RETURN_THROWS();
  1344. }
  1345. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  1346. spl_dual_it_rewind(intern);
  1347. spl_dual_it_fetch(intern, 1);
  1348. } /* }}} */
  1349. /* {{{ Check whether the current element is valid */
  1350. PHP_METHOD(IteratorIterator, valid)
  1351. {
  1352. spl_dual_it_object *intern;
  1353. if (zend_parse_parameters_none() == FAILURE) {
  1354. RETURN_THROWS();
  1355. }
  1356. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  1357. RETURN_BOOL(Z_TYPE(intern->current.data) != IS_UNDEF);
  1358. } /* }}} */
  1359. /* {{{ Get the current key */
  1360. PHP_METHOD(IteratorIterator, key)
  1361. {
  1362. spl_dual_it_object *intern;
  1363. if (zend_parse_parameters_none() == FAILURE) {
  1364. RETURN_THROWS();
  1365. }
  1366. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  1367. if (Z_TYPE(intern->current.key) != IS_UNDEF) {
  1368. RETURN_COPY_DEREF(&intern->current.key);
  1369. } else {
  1370. RETURN_NULL();
  1371. }
  1372. } /* }}} */
  1373. /* {{{ Get the current element value */
  1374. PHP_METHOD(IteratorIterator, current)
  1375. {
  1376. spl_dual_it_object *intern;
  1377. if (zend_parse_parameters_none() == FAILURE) {
  1378. RETURN_THROWS();
  1379. }
  1380. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  1381. if (Z_TYPE(intern->current.data) != IS_UNDEF) {
  1382. RETURN_COPY_DEREF(&intern->current.data);
  1383. } else {
  1384. RETURN_NULL();
  1385. }
  1386. } /* }}} */
  1387. /* {{{ Move the iterator forward */
  1388. PHP_METHOD(IteratorIterator, next)
  1389. {
  1390. spl_dual_it_object *intern;
  1391. if (zend_parse_parameters_none() == FAILURE) {
  1392. RETURN_THROWS();
  1393. }
  1394. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  1395. spl_dual_it_next(intern, 1);
  1396. spl_dual_it_fetch(intern, 1);
  1397. } /* }}} */
  1398. static inline void spl_filter_it_fetch(zval *zthis, spl_dual_it_object *intern)
  1399. {
  1400. zval retval;
  1401. while (spl_dual_it_fetch(intern, 1) == SUCCESS) {
  1402. zend_call_method_with_0_params(Z_OBJ_P(zthis), intern->std.ce, NULL, "accept", &retval);
  1403. if (Z_TYPE(retval) != IS_UNDEF) {
  1404. if (zend_is_true(&retval)) {
  1405. zval_ptr_dtor(&retval);
  1406. return;
  1407. }
  1408. zval_ptr_dtor(&retval);
  1409. }
  1410. if (EG(exception)) {
  1411. return;
  1412. }
  1413. intern->inner.iterator->funcs->move_forward(intern->inner.iterator);
  1414. }
  1415. spl_dual_it_free(intern);
  1416. }
  1417. static inline void spl_filter_it_rewind(zval *zthis, spl_dual_it_object *intern)
  1418. {
  1419. spl_dual_it_rewind(intern);
  1420. spl_filter_it_fetch(zthis, intern);
  1421. }
  1422. static inline void spl_filter_it_next(zval *zthis, spl_dual_it_object *intern)
  1423. {
  1424. spl_dual_it_next(intern, 1);
  1425. spl_filter_it_fetch(zthis, intern);
  1426. }
  1427. /* {{{ Rewind the iterator */
  1428. PHP_METHOD(FilterIterator, rewind)
  1429. {
  1430. spl_dual_it_object *intern;
  1431. if (zend_parse_parameters_none() == FAILURE) {
  1432. RETURN_THROWS();
  1433. }
  1434. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  1435. spl_filter_it_rewind(ZEND_THIS, intern);
  1436. } /* }}} */
  1437. /* {{{ Move the iterator forward */
  1438. PHP_METHOD(FilterIterator, next)
  1439. {
  1440. spl_dual_it_object *intern;
  1441. if (zend_parse_parameters_none() == FAILURE) {
  1442. RETURN_THROWS();
  1443. }
  1444. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  1445. spl_filter_it_next(ZEND_THIS, intern);
  1446. } /* }}} */
  1447. /* {{{ Create a RecursiveCallbackFilterIterator from a RecursiveIterator */
  1448. PHP_METHOD(RecursiveCallbackFilterIterator, __construct)
  1449. {
  1450. spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveCallbackFilterIterator, spl_ce_RecursiveIterator, DIT_RecursiveCallbackFilterIterator);
  1451. } /* }}} */
  1452. /* {{{ Create a RecursiveFilterIterator from a RecursiveIterator */
  1453. PHP_METHOD(RecursiveFilterIterator, __construct)
  1454. {
  1455. spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveFilterIterator, spl_ce_RecursiveIterator, DIT_RecursiveFilterIterator);
  1456. } /* }}} */
  1457. /* {{{ Check whether the inner iterator's current element has children */
  1458. PHP_METHOD(RecursiveFilterIterator, hasChildren)
  1459. {
  1460. spl_dual_it_object *intern;
  1461. if (zend_parse_parameters_none() == FAILURE) {
  1462. RETURN_THROWS();
  1463. }
  1464. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  1465. zend_call_method_with_0_params(Z_OBJ(intern->inner.zobject), intern->inner.ce, NULL, "haschildren", return_value);
  1466. } /* }}} */
  1467. /* {{{ Return the inner iterator's children contained in a RecursiveFilterIterator */
  1468. PHP_METHOD(RecursiveFilterIterator, getChildren)
  1469. {
  1470. spl_dual_it_object *intern;
  1471. zval retval;
  1472. if (zend_parse_parameters_none() == FAILURE) {
  1473. RETURN_THROWS();
  1474. }
  1475. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  1476. zend_call_method_with_0_params(Z_OBJ(intern->inner.zobject), intern->inner.ce, NULL, "getchildren", &retval);
  1477. if (!EG(exception) && Z_TYPE(retval) != IS_UNDEF) {
  1478. spl_instantiate_arg_ex1(Z_OBJCE_P(ZEND_THIS), return_value, &retval);
  1479. }
  1480. zval_ptr_dtor(&retval);
  1481. } /* }}} */
  1482. /* {{{ Return the inner iterator's children contained in a RecursiveCallbackFilterIterator */
  1483. PHP_METHOD(RecursiveCallbackFilterIterator, getChildren)
  1484. {
  1485. spl_dual_it_object *intern;
  1486. zval retval;
  1487. if (zend_parse_parameters_none() == FAILURE) {
  1488. RETURN_THROWS();
  1489. }
  1490. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  1491. zend_call_method_with_0_params(Z_OBJ(intern->inner.zobject), intern->inner.ce, NULL, "getchildren", &retval);
  1492. if (!EG(exception) && Z_TYPE(retval) != IS_UNDEF) {
  1493. spl_instantiate_arg_ex2(Z_OBJCE_P(ZEND_THIS), return_value, &retval, &intern->u.cbfilter->fci.function_name);
  1494. }
  1495. zval_ptr_dtor(&retval);
  1496. } /* }}} */
  1497. /* {{{ Create a ParentIterator from a RecursiveIterator */
  1498. PHP_METHOD(ParentIterator, __construct)
  1499. {
  1500. spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_ParentIterator, spl_ce_RecursiveIterator, DIT_ParentIterator);
  1501. } /* }}} */
  1502. /* {{{ Create an RegexIterator from another iterator and a regular expression */
  1503. PHP_METHOD(RegexIterator, __construct)
  1504. {
  1505. spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RegexIterator, zend_ce_iterator, DIT_RegexIterator);
  1506. } /* }}} */
  1507. /* {{{ Calls the callback with the current value, the current key and the inner iterator as arguments */
  1508. PHP_METHOD(CallbackFilterIterator, accept)
  1509. {
  1510. spl_dual_it_object *intern;
  1511. if (zend_parse_parameters_none() == FAILURE) {
  1512. RETURN_THROWS();
  1513. }
  1514. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  1515. if (Z_TYPE(intern->current.data) == IS_UNDEF || Z_TYPE(intern->current.key) == IS_UNDEF) {
  1516. RETURN_FALSE;
  1517. }
  1518. zval params[3];
  1519. ZVAL_COPY_VALUE(&params[0], &intern->current.data);
  1520. ZVAL_COPY_VALUE(&params[1], &intern->current.key);
  1521. ZVAL_COPY_VALUE(&params[2], &intern->inner.zobject);
  1522. zend_fcall_info *fci = &intern->u.cbfilter->fci;
  1523. zend_fcall_info_cache *fcc = &intern->u.cbfilter->fcc;
  1524. fci->retval = return_value;
  1525. fci->param_count = 3;
  1526. fci->params = params;
  1527. if (zend_call_function(fci, fcc) != SUCCESS || Z_ISUNDEF_P(return_value)) {
  1528. RETURN_FALSE;
  1529. }
  1530. }
  1531. /* }}} */
  1532. /* {{{ Match (string)current() against regular expression */
  1533. PHP_METHOD(RegexIterator, accept)
  1534. {
  1535. spl_dual_it_object *intern;
  1536. zend_string *result, *subject;
  1537. size_t count = 0;
  1538. zval zcount, rv;
  1539. pcre2_match_data *match_data;
  1540. pcre2_code *re;
  1541. int rc;
  1542. if (zend_parse_parameters_none() == FAILURE) {
  1543. RETURN_THROWS();
  1544. }
  1545. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  1546. if (Z_TYPE(intern->current.data) == IS_UNDEF) {
  1547. RETURN_FALSE;
  1548. }
  1549. if (intern->u.regex.flags & REGIT_USE_KEY) {
  1550. subject = zval_get_string(&intern->current.key);
  1551. } else {
  1552. if (Z_TYPE(intern->current.data) == IS_ARRAY) {
  1553. RETURN_FALSE;
  1554. }
  1555. subject = zval_get_string(&intern->current.data);
  1556. }
  1557. /* Exception during string conversion. */
  1558. if (EG(exception)) {
  1559. RETURN_THROWS();
  1560. }
  1561. switch (intern->u.regex.mode)
  1562. {
  1563. case REGIT_MODE_MAX: /* won't happen but makes compiler happy */
  1564. case REGIT_MODE_MATCH:
  1565. re = php_pcre_pce_re(intern->u.regex.pce);
  1566. match_data = php_pcre_create_match_data(0, re);
  1567. if (!match_data) {
  1568. RETURN_FALSE;
  1569. }
  1570. rc = pcre2_match(re, (PCRE2_SPTR)ZSTR_VAL(subject), ZSTR_LEN(subject), 0, 0, match_data, php_pcre_mctx());
  1571. RETVAL_BOOL(rc >= 0);
  1572. php_pcre_free_match_data(match_data);
  1573. break;
  1574. case REGIT_MODE_ALL_MATCHES:
  1575. case REGIT_MODE_GET_MATCH:
  1576. zval_ptr_dtor(&intern->current.data);
  1577. ZVAL_UNDEF(&intern->current.data);
  1578. php_pcre_match_impl(intern->u.regex.pce, subject, &zcount,
  1579. &intern->current.data, intern->u.regex.mode == REGIT_MODE_ALL_MATCHES, intern->u.regex.use_flags, intern->u.regex.preg_flags, 0);
  1580. RETVAL_BOOL(Z_LVAL(zcount) > 0);
  1581. break;
  1582. case REGIT_MODE_SPLIT:
  1583. zval_ptr_dtor(&intern->current.data);
  1584. ZVAL_UNDEF(&intern->current.data);
  1585. php_pcre_split_impl(intern->u.regex.pce, subject, &intern->current.data, -1, intern->u.regex.preg_flags);
  1586. count = zend_hash_num_elements(Z_ARRVAL(intern->current.data));
  1587. RETVAL_BOOL(count > 1);
  1588. break;
  1589. case REGIT_MODE_REPLACE: {
  1590. zval *replacement = zend_read_property(intern->std.ce, Z_OBJ_P(ZEND_THIS), "replacement", sizeof("replacement")-1, 1, &rv);
  1591. zend_string *replacement_str = zval_try_get_string(replacement);
  1592. if (UNEXPECTED(!replacement_str)) {
  1593. RETURN_THROWS();
  1594. }
  1595. result = php_pcre_replace_impl(intern->u.regex.pce, subject, ZSTR_VAL(subject), ZSTR_LEN(subject), replacement_str, -1, &count);
  1596. if (intern->u.regex.flags & REGIT_USE_KEY) {
  1597. zval_ptr_dtor(&intern->current.key);
  1598. ZVAL_STR(&intern->current.key, result);
  1599. } else {
  1600. zval_ptr_dtor(&intern->current.data);
  1601. ZVAL_STR(&intern->current.data, result);
  1602. }
  1603. zend_string_release(replacement_str);
  1604. RETVAL_BOOL(count > 0);
  1605. }
  1606. }
  1607. if (intern->u.regex.flags & REGIT_INVERTED) {
  1608. RETVAL_BOOL(Z_TYPE_P(return_value) != IS_TRUE);
  1609. }
  1610. zend_string_release_ex(subject, 0);
  1611. } /* }}} */
  1612. /* {{{ Returns current regular expression */
  1613. PHP_METHOD(RegexIterator, getRegex)
  1614. {
  1615. spl_dual_it_object *intern = Z_SPLDUAL_IT_P(ZEND_THIS);
  1616. if (zend_parse_parameters_none() == FAILURE) {
  1617. RETURN_THROWS();
  1618. }
  1619. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  1620. RETURN_STR_COPY(intern->u.regex.regex);
  1621. } /* }}} */
  1622. /* {{{ Returns current operation mode */
  1623. PHP_METHOD(RegexIterator, getMode)
  1624. {
  1625. spl_dual_it_object *intern;
  1626. if (zend_parse_parameters_none() == FAILURE) {
  1627. RETURN_THROWS();
  1628. }
  1629. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  1630. RETURN_LONG(intern->u.regex.mode);
  1631. } /* }}} */
  1632. /* {{{ Set new operation mode */
  1633. PHP_METHOD(RegexIterator, setMode)
  1634. {
  1635. spl_dual_it_object *intern;
  1636. zend_long mode;
  1637. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &mode) == FAILURE) {
  1638. RETURN_THROWS();
  1639. }
  1640. if (mode < 0 || mode >= REGIT_MODE_MAX) {
  1641. zend_argument_value_error(1, "must be RegexIterator::MATCH, RegexIterator::GET_MATCH, "
  1642. "RegexIterator::ALL_MATCHES, RegexIterator::SPLIT, or RegexIterator::REPLACE");
  1643. RETURN_THROWS();
  1644. }
  1645. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  1646. intern->u.regex.mode = mode;
  1647. } /* }}} */
  1648. /* {{{ Returns current operation flags */
  1649. PHP_METHOD(RegexIterator, getFlags)
  1650. {
  1651. spl_dual_it_object *intern;
  1652. if (zend_parse_parameters_none() == FAILURE) {
  1653. RETURN_THROWS();
  1654. }
  1655. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  1656. RETURN_LONG(intern->u.regex.flags);
  1657. } /* }}} */
  1658. /* {{{ Set operation flags */
  1659. PHP_METHOD(RegexIterator, setFlags)
  1660. {
  1661. spl_dual_it_object *intern;
  1662. zend_long flags;
  1663. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &flags) == FAILURE) {
  1664. RETURN_THROWS();
  1665. }
  1666. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  1667. intern->u.regex.flags = flags;
  1668. } /* }}} */
  1669. /* {{{ Returns current PREG flags (if in use or NULL) */
  1670. PHP_METHOD(RegexIterator, getPregFlags)
  1671. {
  1672. spl_dual_it_object *intern;
  1673. if (zend_parse_parameters_none() == FAILURE) {
  1674. RETURN_THROWS();
  1675. }
  1676. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  1677. if (intern->u.regex.use_flags) {
  1678. RETURN_LONG(intern->u.regex.preg_flags);
  1679. } else {
  1680. RETURN_LONG(0);
  1681. }
  1682. } /* }}} */
  1683. /* {{{ Set PREG flags */
  1684. PHP_METHOD(RegexIterator, setPregFlags)
  1685. {
  1686. spl_dual_it_object *intern;
  1687. zend_long preg_flags;
  1688. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &preg_flags) == FAILURE) {
  1689. RETURN_THROWS();
  1690. }
  1691. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  1692. intern->u.regex.preg_flags = preg_flags;
  1693. intern->u.regex.use_flags = 1;
  1694. } /* }}} */
  1695. /* {{{ Create an RecursiveRegexIterator from another recursive iterator and a regular expression */
  1696. PHP_METHOD(RecursiveRegexIterator, __construct)
  1697. {
  1698. spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveRegexIterator, spl_ce_RecursiveIterator, DIT_RecursiveRegexIterator);
  1699. } /* }}} */
  1700. /* {{{ Return the inner iterator's children contained in a RecursiveRegexIterator */
  1701. PHP_METHOD(RecursiveRegexIterator, getChildren)
  1702. {
  1703. spl_dual_it_object *intern;
  1704. zval retval;
  1705. if (zend_parse_parameters_none() == FAILURE) {
  1706. RETURN_THROWS();
  1707. }
  1708. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  1709. zend_call_method_with_0_params(Z_OBJ(intern->inner.zobject), intern->inner.ce, NULL, "getchildren", &retval);
  1710. if (!EG(exception)) {
  1711. zval args[5];
  1712. ZVAL_COPY(&args[0], &retval);
  1713. ZVAL_STR_COPY(&args[1], intern->u.regex.regex);
  1714. ZVAL_LONG(&args[2], intern->u.regex.mode);
  1715. ZVAL_LONG(&args[3], intern->u.regex.flags);
  1716. ZVAL_LONG(&args[4], intern->u.regex.preg_flags);
  1717. spl_instantiate_arg_n(Z_OBJCE_P(ZEND_THIS), return_value, 5, args);
  1718. zval_ptr_dtor(&args[0]);
  1719. zval_ptr_dtor(&args[1]);
  1720. }
  1721. zval_ptr_dtor(&retval);
  1722. } /* }}} */
  1723. PHP_METHOD(RecursiveRegexIterator, accept)
  1724. {
  1725. spl_dual_it_object *intern;
  1726. if (zend_parse_parameters_none() == FAILURE) {
  1727. RETURN_THROWS();
  1728. }
  1729. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  1730. if (Z_TYPE(intern->current.data) == IS_UNDEF) {
  1731. RETURN_FALSE;
  1732. } else if (Z_TYPE(intern->current.data) == IS_ARRAY) {
  1733. RETURN_BOOL(zend_hash_num_elements(Z_ARRVAL(intern->current.data)) > 0);
  1734. }
  1735. zend_call_method_with_0_params(Z_OBJ_P(ZEND_THIS), spl_ce_RegexIterator, NULL, "accept", return_value);
  1736. }
  1737. /* {{{ spl_dual_it_free_storage */
  1738. static void spl_dual_it_free_storage(zend_object *_object)
  1739. {
  1740. spl_dual_it_object *object = spl_dual_it_from_obj(_object);
  1741. spl_dual_it_free(object);
  1742. if (object->inner.iterator) {
  1743. zend_iterator_dtor(object->inner.iterator);
  1744. }
  1745. if (!Z_ISUNDEF(object->inner.zobject)) {
  1746. zval_ptr_dtor(&object->inner.zobject);
  1747. }
  1748. if (object->dit_type == DIT_AppendIterator) {
  1749. zend_iterator_dtor(object->u.append.iterator);
  1750. if (Z_TYPE(object->u.append.zarrayit) != IS_UNDEF) {
  1751. zval_ptr_dtor(&object->u.append.zarrayit);
  1752. }
  1753. }
  1754. if (object->dit_type == DIT_CachingIterator || object->dit_type == DIT_RecursiveCachingIterator) {
  1755. zval_ptr_dtor(&object->u.caching.zcache);
  1756. }
  1757. if (object->dit_type == DIT_RegexIterator || object->dit_type == DIT_RecursiveRegexIterator) {
  1758. if (object->u.regex.pce) {
  1759. php_pcre_pce_decref(object->u.regex.pce);
  1760. }
  1761. if (object->u.regex.regex) {
  1762. zend_string_release_ex(object->u.regex.regex, 0);
  1763. }
  1764. }
  1765. if (object->dit_type == DIT_CallbackFilterIterator || object->dit_type == DIT_RecursiveCallbackFilterIterator) {
  1766. if (object->u.cbfilter) {
  1767. _spl_cbfilter_it_intern *cbfilter = object->u.cbfilter;
  1768. object->u.cbfilter = NULL;
  1769. zval_ptr_dtor(&cbfilter->fci.function_name);
  1770. if (cbfilter->fci.object) {
  1771. OBJ_RELEASE(cbfilter->fci.object);
  1772. }
  1773. efree(cbfilter);
  1774. }
  1775. }
  1776. zend_object_std_dtor(&object->std);
  1777. }
  1778. /* }}} */
  1779. static HashTable *spl_dual_it_get_gc(zend_object *obj, zval **table, int *n)
  1780. {
  1781. spl_dual_it_object *object = spl_dual_it_from_obj(obj);
  1782. zend_get_gc_buffer *gc_buffer = zend_get_gc_buffer_create();
  1783. if (object->inner.iterator) {
  1784. zend_get_gc_buffer_add_obj(gc_buffer, &object->inner.iterator->std);
  1785. }
  1786. zend_get_gc_buffer_add_zval(gc_buffer, &object->current.data);
  1787. zend_get_gc_buffer_add_zval(gc_buffer, &object->current.key);
  1788. zend_get_gc_buffer_add_zval(gc_buffer, &object->inner.zobject);
  1789. switch (object->dit_type) {
  1790. case DIT_Unknown:
  1791. case DIT_Default:
  1792. case DIT_IteratorIterator:
  1793. case DIT_NoRewindIterator:
  1794. case DIT_InfiniteIterator:
  1795. case DIT_LimitIterator:
  1796. case DIT_RegexIterator:
  1797. case DIT_RecursiveRegexIterator:
  1798. /* Nothing to do */
  1799. break;
  1800. case DIT_AppendIterator:
  1801. zend_get_gc_buffer_add_obj(gc_buffer, &object->u.append.iterator->std);
  1802. if (Z_TYPE(object->u.append.zarrayit) != IS_UNDEF) {
  1803. zend_get_gc_buffer_add_zval(gc_buffer, &object->u.append.zarrayit);
  1804. }
  1805. break;
  1806. case DIT_CachingIterator:
  1807. case DIT_RecursiveCachingIterator:
  1808. zend_get_gc_buffer_add_zval(gc_buffer, &object->u.caching.zcache);
  1809. zend_get_gc_buffer_add_zval(gc_buffer, &object->u.caching.zchildren);
  1810. break;
  1811. case DIT_CallbackFilterIterator:
  1812. case DIT_RecursiveCallbackFilterIterator:
  1813. if (object->u.cbfilter) {
  1814. zend_get_gc_buffer_add_zval(gc_buffer, &object->u.cbfilter->fci.function_name);
  1815. if (object->u.cbfilter->fci.object) {
  1816. zend_get_gc_buffer_add_obj(gc_buffer, object->u.cbfilter->fci.object);
  1817. }
  1818. }
  1819. break;
  1820. }
  1821. zend_get_gc_buffer_use(gc_buffer, table, n);
  1822. return zend_std_get_properties(obj);
  1823. }
  1824. /* {{{ spl_dual_it_new */
  1825. static zend_object *spl_dual_it_new(zend_class_entry *class_type)
  1826. {
  1827. spl_dual_it_object *intern;
  1828. intern = zend_object_alloc(sizeof(spl_dual_it_object), class_type);
  1829. intern->dit_type = DIT_Unknown;
  1830. zend_object_std_init(&intern->std, class_type);
  1831. object_properties_init(&intern->std, class_type);
  1832. intern->std.handlers = &spl_handlers_dual_it;
  1833. return &intern->std;
  1834. }
  1835. /* }}} */
  1836. static inline int spl_limit_it_valid(spl_dual_it_object *intern)
  1837. {
  1838. /* FAILURE / SUCCESS */
  1839. if (intern->u.limit.count != -1 && intern->current.pos >= intern->u.limit.offset + intern->u.limit.count) {
  1840. return FAILURE;
  1841. } else {
  1842. return spl_dual_it_valid(intern);
  1843. }
  1844. }
  1845. static inline void spl_limit_it_seek(spl_dual_it_object *intern, zend_long pos)
  1846. {
  1847. zval zpos;
  1848. spl_dual_it_free(intern);
  1849. if (pos < intern->u.limit.offset) {
  1850. zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0, "Cannot seek to " ZEND_LONG_FMT " which is below the offset " ZEND_LONG_FMT, pos, intern->u.limit.offset);
  1851. return;
  1852. }
  1853. if (pos >= intern->u.limit.offset + intern->u.limit.count && intern->u.limit.count != -1) {
  1854. zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0, "Cannot seek to " ZEND_LONG_FMT " which is behind offset " ZEND_LONG_FMT " plus count " ZEND_LONG_FMT, pos, intern->u.limit.offset, intern->u.limit.count);
  1855. return;
  1856. }
  1857. if (pos != intern->current.pos && instanceof_function(intern->inner.ce, spl_ce_SeekableIterator)) {
  1858. ZVAL_LONG(&zpos, pos);
  1859. spl_dual_it_free(intern);
  1860. zend_call_method_with_1_params(Z_OBJ(intern->inner.zobject), intern->inner.ce, NULL, "seek", NULL, &zpos);
  1861. if (!EG(exception)) {
  1862. intern->current.pos = pos;
  1863. if (spl_limit_it_valid(intern) == SUCCESS) {
  1864. spl_dual_it_fetch(intern, 0);
  1865. }
  1866. }
  1867. } else {
  1868. /* emulate the forward seek, by next() calls */
  1869. /* a back ward seek is done by a previous rewind() */
  1870. if (pos < intern->current.pos) {
  1871. spl_dual_it_rewind(intern);
  1872. }
  1873. while (pos > intern->current.pos && spl_dual_it_valid(intern) == SUCCESS) {
  1874. spl_dual_it_next(intern, 1);
  1875. }
  1876. if (spl_dual_it_valid(intern) == SUCCESS) {
  1877. spl_dual_it_fetch(intern, 1);
  1878. }
  1879. }
  1880. }
  1881. /* {{{ Construct a LimitIterator from an Iterator with a given starting offset and optionally a maximum count */
  1882. PHP_METHOD(LimitIterator, __construct)
  1883. {
  1884. spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_LimitIterator, zend_ce_iterator, DIT_LimitIterator);
  1885. } /* }}} */
  1886. /* {{{ Rewind the iterator to the specified starting offset */
  1887. PHP_METHOD(LimitIterator, rewind)
  1888. {
  1889. spl_dual_it_object *intern;
  1890. if (zend_parse_parameters_none() == FAILURE) {
  1891. RETURN_THROWS();
  1892. }
  1893. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  1894. spl_dual_it_rewind(intern);
  1895. spl_limit_it_seek(intern, intern->u.limit.offset);
  1896. } /* }}} */
  1897. /* {{{ Check whether the current element is valid */
  1898. PHP_METHOD(LimitIterator, valid)
  1899. {
  1900. spl_dual_it_object *intern;
  1901. if (zend_parse_parameters_none() == FAILURE) {
  1902. RETURN_THROWS();
  1903. }
  1904. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  1905. /* RETURN_BOOL(spl_limit_it_valid(intern) == SUCCESS);*/
  1906. RETURN_BOOL((intern->u.limit.count == -1 || intern->current.pos < intern->u.limit.offset + intern->u.limit.count) && Z_TYPE(intern->current.data) != IS_UNDEF);
  1907. } /* }}} */
  1908. /* {{{ Move the iterator forward */
  1909. PHP_METHOD(LimitIterator, next)
  1910. {
  1911. spl_dual_it_object *intern;
  1912. if (zend_parse_parameters_none() == FAILURE) {
  1913. RETURN_THROWS();
  1914. }
  1915. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  1916. spl_dual_it_next(intern, 1);
  1917. if (intern->u.limit.count == -1 || intern->current.pos < intern->u.limit.offset + intern->u.limit.count) {
  1918. spl_dual_it_fetch(intern, 1);
  1919. }
  1920. } /* }}} */
  1921. /* {{{ Seek to the given position */
  1922. PHP_METHOD(LimitIterator, seek)
  1923. {
  1924. spl_dual_it_object *intern;
  1925. zend_long pos;
  1926. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &pos) == FAILURE) {
  1927. RETURN_THROWS();
  1928. }
  1929. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  1930. spl_limit_it_seek(intern, pos);
  1931. RETURN_LONG(intern->current.pos);
  1932. } /* }}} */
  1933. /* {{{ Return the current position */
  1934. PHP_METHOD(LimitIterator, getPosition)
  1935. {
  1936. spl_dual_it_object *intern;
  1937. if (zend_parse_parameters_none() == FAILURE) {
  1938. RETURN_THROWS();
  1939. }
  1940. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  1941. RETURN_LONG(intern->current.pos);
  1942. } /* }}} */
  1943. static inline int spl_caching_it_valid(spl_dual_it_object *intern)
  1944. {
  1945. return intern->u.caching.flags & CIT_VALID ? SUCCESS : FAILURE;
  1946. }
  1947. static inline int spl_caching_it_has_next(spl_dual_it_object *intern)
  1948. {
  1949. return spl_dual_it_valid(intern);
  1950. }
  1951. static inline void spl_caching_it_next(spl_dual_it_object *intern)
  1952. {
  1953. if (spl_dual_it_fetch(intern, 1) == SUCCESS) {
  1954. intern->u.caching.flags |= CIT_VALID;
  1955. /* Full cache ? */
  1956. if (intern->u.caching.flags & CIT_FULL_CACHE) {
  1957. zval *key = &intern->current.key;
  1958. zval *data = &intern->current.data;
  1959. ZVAL_DEREF(data);
  1960. array_set_zval_key(Z_ARRVAL(intern->u.caching.zcache), key, data);
  1961. }
  1962. /* Recursion ? */
  1963. if (intern->dit_type == DIT_RecursiveCachingIterator) {
  1964. zval retval, zchildren, zflags;
  1965. zend_call_method_with_0_params(Z_OBJ(intern->inner.zobject), intern->inner.ce, NULL, "haschildren", &retval);
  1966. if (EG(exception)) {
  1967. zval_ptr_dtor(&retval);
  1968. if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) {
  1969. zend_clear_exception();
  1970. } else {
  1971. return;
  1972. }
  1973. } else {
  1974. if (zend_is_true(&retval)) {
  1975. zend_call_method_with_0_params(Z_OBJ(intern->inner.zobject), intern->inner.ce, NULL, "getchildren", &zchildren);
  1976. if (EG(exception)) {
  1977. zval_ptr_dtor(&zchildren);
  1978. if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) {
  1979. zend_clear_exception();
  1980. } else {
  1981. zval_ptr_dtor(&retval);
  1982. return;
  1983. }
  1984. } else {
  1985. ZVAL_LONG(&zflags, intern->u.caching.flags & CIT_PUBLIC);
  1986. spl_instantiate_arg_ex2(spl_ce_RecursiveCachingIterator, &intern->u.caching.zchildren, &zchildren, &zflags);
  1987. zval_ptr_dtor(&zchildren);
  1988. }
  1989. }
  1990. zval_ptr_dtor(&retval);
  1991. if (EG(exception)) {
  1992. if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) {
  1993. zend_clear_exception();
  1994. } else {
  1995. return;
  1996. }
  1997. }
  1998. }
  1999. }
  2000. if (intern->u.caching.flags & (CIT_TOSTRING_USE_INNER|CIT_CALL_TOSTRING)) {
  2001. if (intern->u.caching.flags & CIT_TOSTRING_USE_INNER) {
  2002. intern->u.caching.zstr = zval_get_string(&intern->inner.zobject);
  2003. } else {
  2004. intern->u.caching.zstr = zval_get_string(&intern->current.data);
  2005. }
  2006. }
  2007. spl_dual_it_next(intern, 0);
  2008. } else {
  2009. intern->u.caching.flags &= ~CIT_VALID;
  2010. }
  2011. }
  2012. static inline void spl_caching_it_rewind(spl_dual_it_object *intern)
  2013. {
  2014. spl_dual_it_rewind(intern);
  2015. zend_hash_clean(Z_ARRVAL(intern->u.caching.zcache));
  2016. spl_caching_it_next(intern);
  2017. }
  2018. /* {{{ Construct a CachingIterator from an Iterator */
  2019. PHP_METHOD(CachingIterator, __construct)
  2020. {
  2021. spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_CachingIterator, zend_ce_iterator, DIT_CachingIterator);
  2022. } /* }}} */
  2023. /* {{{ Rewind the iterator */
  2024. PHP_METHOD(CachingIterator, rewind)
  2025. {
  2026. spl_dual_it_object *intern;
  2027. if (zend_parse_parameters_none() == FAILURE) {
  2028. RETURN_THROWS();
  2029. }
  2030. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  2031. spl_caching_it_rewind(intern);
  2032. } /* }}} */
  2033. /* {{{ Check whether the current element is valid */
  2034. PHP_METHOD(CachingIterator, valid)
  2035. {
  2036. spl_dual_it_object *intern;
  2037. if (zend_parse_parameters_none() == FAILURE) {
  2038. RETURN_THROWS();
  2039. }
  2040. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  2041. RETURN_BOOL(spl_caching_it_valid(intern) == SUCCESS);
  2042. } /* }}} */
  2043. /* {{{ Move the iterator forward */
  2044. PHP_METHOD(CachingIterator, next)
  2045. {
  2046. spl_dual_it_object *intern;
  2047. if (zend_parse_parameters_none() == FAILURE) {
  2048. RETURN_THROWS();
  2049. }
  2050. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  2051. spl_caching_it_next(intern);
  2052. } /* }}} */
  2053. /* {{{ Check whether the inner iterator has a valid next element */
  2054. PHP_METHOD(CachingIterator, hasNext)
  2055. {
  2056. spl_dual_it_object *intern;
  2057. if (zend_parse_parameters_none() == FAILURE) {
  2058. RETURN_THROWS();
  2059. }
  2060. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  2061. RETURN_BOOL(spl_caching_it_has_next(intern) == SUCCESS);
  2062. } /* }}} */
  2063. /* {{{ Return the string representation of the current element */
  2064. PHP_METHOD(CachingIterator, __toString)
  2065. {
  2066. spl_dual_it_object *intern;
  2067. if (zend_parse_parameters_none() == FAILURE) {
  2068. RETURN_THROWS();
  2069. }
  2070. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  2071. if (!(intern->u.caching.flags & (CIT_CALL_TOSTRING|CIT_TOSTRING_USE_KEY|CIT_TOSTRING_USE_CURRENT|CIT_TOSTRING_USE_INNER))) {
  2072. zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s does not fetch string value (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name));
  2073. RETURN_THROWS();
  2074. }
  2075. if (intern->u.caching.flags & CIT_TOSTRING_USE_KEY) {
  2076. ZVAL_COPY(return_value, &intern->current.key);
  2077. convert_to_string(return_value);
  2078. return;
  2079. } else if (intern->u.caching.flags & CIT_TOSTRING_USE_CURRENT) {
  2080. ZVAL_COPY(return_value, &intern->current.data);
  2081. convert_to_string(return_value);
  2082. return;
  2083. }
  2084. if (intern->u.caching.zstr) {
  2085. RETURN_STR_COPY(intern->u.caching.zstr);
  2086. } else {
  2087. RETURN_EMPTY_STRING();
  2088. }
  2089. } /* }}} */
  2090. /* {{{ Set given index in cache */
  2091. PHP_METHOD(CachingIterator, offsetSet)
  2092. {
  2093. spl_dual_it_object *intern;
  2094. zend_string *key;
  2095. zval *value;
  2096. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz", &key, &value) == FAILURE) {
  2097. RETURN_THROWS();
  2098. }
  2099. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  2100. if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
  2101. zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s does not use a full cache (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name));
  2102. RETURN_THROWS();
  2103. }
  2104. Z_TRY_ADDREF_P(value);
  2105. zend_symtable_update(Z_ARRVAL(intern->u.caching.zcache), key, value);
  2106. }
  2107. /* }}} */
  2108. /* {{{ Return the internal cache if used */
  2109. PHP_METHOD(CachingIterator, offsetGet)
  2110. {
  2111. spl_dual_it_object *intern;
  2112. zend_string *key;
  2113. zval *value;
  2114. if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &key) == FAILURE) {
  2115. RETURN_THROWS();
  2116. }
  2117. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  2118. if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
  2119. zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s does not use a full cache (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name));
  2120. RETURN_THROWS();
  2121. }
  2122. if ((value = zend_symtable_find(Z_ARRVAL(intern->u.caching.zcache), key)) == NULL) {
  2123. zend_error(E_WARNING, "Undefined array key \"%s\"", ZSTR_VAL(key));
  2124. return;
  2125. }
  2126. RETURN_COPY_DEREF(value);
  2127. }
  2128. /* }}} */
  2129. /* {{{ Unset given index in cache */
  2130. PHP_METHOD(CachingIterator, offsetUnset)
  2131. {
  2132. spl_dual_it_object *intern;
  2133. zend_string *key;
  2134. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  2135. if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &key) == FAILURE) {
  2136. RETURN_THROWS();
  2137. }
  2138. if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
  2139. zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s does not use a full cache (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name));
  2140. RETURN_THROWS();
  2141. }
  2142. zend_symtable_del(Z_ARRVAL(intern->u.caching.zcache), key);
  2143. }
  2144. /* }}} */
  2145. /* {{{ Return whether the requested index exists */
  2146. PHP_METHOD(CachingIterator, offsetExists)
  2147. {
  2148. spl_dual_it_object *intern;
  2149. zend_string *key;
  2150. if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &key) == FAILURE) {
  2151. RETURN_THROWS();
  2152. }
  2153. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  2154. if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
  2155. zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s does not use a full cache (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name));
  2156. RETURN_THROWS();
  2157. }
  2158. RETURN_BOOL(zend_symtable_exists(Z_ARRVAL(intern->u.caching.zcache), key));
  2159. }
  2160. /* }}} */
  2161. /* {{{ Return the cache */
  2162. PHP_METHOD(CachingIterator, getCache)
  2163. {
  2164. spl_dual_it_object *intern;
  2165. if (zend_parse_parameters_none() == FAILURE) {
  2166. RETURN_THROWS();
  2167. }
  2168. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  2169. if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
  2170. zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s does not use a full cache (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name));
  2171. RETURN_THROWS();
  2172. }
  2173. ZVAL_COPY(return_value, &intern->u.caching.zcache);
  2174. }
  2175. /* }}} */
  2176. /* {{{ Return the internal flags */
  2177. PHP_METHOD(CachingIterator, getFlags)
  2178. {
  2179. spl_dual_it_object *intern;
  2180. if (zend_parse_parameters_none() == FAILURE) {
  2181. RETURN_THROWS();
  2182. }
  2183. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  2184. RETURN_LONG(intern->u.caching.flags);
  2185. }
  2186. /* }}} */
  2187. /* {{{ Set the internal flags */
  2188. PHP_METHOD(CachingIterator, setFlags)
  2189. {
  2190. spl_dual_it_object *intern;
  2191. zend_long flags;
  2192. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &flags) == FAILURE) {
  2193. RETURN_THROWS();
  2194. }
  2195. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  2196. if (spl_cit_check_flags(flags) != SUCCESS) {
  2197. zend_argument_value_error(1, "must contain only one of CachingIterator::CALL_TOSTRING, "
  2198. "CachingIterator::TOSTRING_USE_KEY, CachingIterator::TOSTRING_USE_CURRENT, "
  2199. "or CachingIterator::TOSTRING_USE_INNER");
  2200. RETURN_THROWS();
  2201. }
  2202. if ((intern->u.caching.flags & CIT_CALL_TOSTRING) != 0 && (flags & CIT_CALL_TOSTRING) == 0) {
  2203. zend_throw_exception(spl_ce_InvalidArgumentException, "Unsetting flag CALL_TO_STRING is not possible", 0);
  2204. RETURN_THROWS();
  2205. }
  2206. if ((intern->u.caching.flags & CIT_TOSTRING_USE_INNER) != 0 && (flags & CIT_TOSTRING_USE_INNER) == 0) {
  2207. zend_throw_exception(spl_ce_InvalidArgumentException, "Unsetting flag TOSTRING_USE_INNER is not possible", 0);
  2208. RETURN_THROWS();
  2209. }
  2210. if ((flags & CIT_FULL_CACHE) != 0 && (intern->u.caching.flags & CIT_FULL_CACHE) == 0) {
  2211. /* clear on (re)enable */
  2212. zend_hash_clean(Z_ARRVAL(intern->u.caching.zcache));
  2213. }
  2214. intern->u.caching.flags = (intern->u.caching.flags & ~CIT_PUBLIC) | (flags & CIT_PUBLIC);
  2215. }
  2216. /* }}} */
  2217. /* {{{ Number of cached elements */
  2218. PHP_METHOD(CachingIterator, count)
  2219. {
  2220. spl_dual_it_object *intern;
  2221. if (zend_parse_parameters_none() == FAILURE) {
  2222. RETURN_THROWS();
  2223. }
  2224. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  2225. if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
  2226. zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s does not use a full cache (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name));
  2227. RETURN_THROWS();
  2228. }
  2229. RETURN_LONG(zend_hash_num_elements(Z_ARRVAL(intern->u.caching.zcache)));
  2230. }
  2231. /* }}} */
  2232. /* {{{ Create an iterator from a RecursiveIterator */
  2233. PHP_METHOD(RecursiveCachingIterator, __construct)
  2234. {
  2235. spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveCachingIterator, spl_ce_RecursiveIterator, DIT_RecursiveCachingIterator);
  2236. } /* }}} */
  2237. /* {{{ Check whether the current element of the inner iterator has children */
  2238. PHP_METHOD(RecursiveCachingIterator, hasChildren)
  2239. {
  2240. spl_dual_it_object *intern;
  2241. if (zend_parse_parameters_none() == FAILURE) {
  2242. RETURN_THROWS();
  2243. }
  2244. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  2245. RETURN_BOOL(Z_TYPE(intern->u.caching.zchildren) != IS_UNDEF);
  2246. } /* }}} */
  2247. /* {{{ Return the inner iterator's children as a RecursiveCachingIterator */
  2248. PHP_METHOD(RecursiveCachingIterator, getChildren)
  2249. {
  2250. spl_dual_it_object *intern;
  2251. if (zend_parse_parameters_none() == FAILURE) {
  2252. RETURN_THROWS();
  2253. }
  2254. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  2255. if (Z_TYPE(intern->u.caching.zchildren) != IS_UNDEF) {
  2256. zval *value = &intern->u.caching.zchildren;
  2257. RETURN_COPY_DEREF(value);
  2258. } else {
  2259. RETURN_NULL();
  2260. }
  2261. } /* }}} */
  2262. /* {{{ Create an iterator from anything that is traversable */
  2263. PHP_METHOD(IteratorIterator, __construct)
  2264. {
  2265. spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_IteratorIterator, zend_ce_traversable, DIT_IteratorIterator);
  2266. } /* }}} */
  2267. /* {{{ Create an iterator from another iterator */
  2268. PHP_METHOD(NoRewindIterator, __construct)
  2269. {
  2270. spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_NoRewindIterator, zend_ce_iterator, DIT_NoRewindIterator);
  2271. } /* }}} */
  2272. /* {{{ Prevent a call to inner iterators rewind() */
  2273. PHP_METHOD(NoRewindIterator, rewind)
  2274. {
  2275. if (zend_parse_parameters_none() == FAILURE) {
  2276. RETURN_THROWS();
  2277. }
  2278. /* nothing to do */
  2279. } /* }}} */
  2280. /* {{{ Return inner iterators valid() */
  2281. PHP_METHOD(NoRewindIterator, valid)
  2282. {
  2283. spl_dual_it_object *intern;
  2284. if (zend_parse_parameters_none() == FAILURE) {
  2285. RETURN_THROWS();
  2286. }
  2287. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  2288. RETURN_BOOL(intern->inner.iterator->funcs->valid(intern->inner.iterator) == SUCCESS);
  2289. } /* }}} */
  2290. /* {{{ Return inner iterators key() */
  2291. PHP_METHOD(NoRewindIterator, key)
  2292. {
  2293. spl_dual_it_object *intern;
  2294. if (zend_parse_parameters_none() == FAILURE) {
  2295. RETURN_THROWS();
  2296. }
  2297. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  2298. if (intern->inner.iterator->funcs->get_current_key) {
  2299. intern->inner.iterator->funcs->get_current_key(intern->inner.iterator, return_value);
  2300. } else {
  2301. RETURN_NULL();
  2302. }
  2303. } /* }}} */
  2304. /* {{{ Return inner iterators current() */
  2305. PHP_METHOD(NoRewindIterator, current)
  2306. {
  2307. spl_dual_it_object *intern;
  2308. zval *data;
  2309. if (zend_parse_parameters_none() == FAILURE) {
  2310. RETURN_THROWS();
  2311. }
  2312. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  2313. data = intern->inner.iterator->funcs->get_current_data(intern->inner.iterator);
  2314. if (data) {
  2315. RETURN_COPY_DEREF(data);
  2316. }
  2317. } /* }}} */
  2318. /* {{{ Return inner iterators next() */
  2319. PHP_METHOD(NoRewindIterator, next)
  2320. {
  2321. spl_dual_it_object *intern;
  2322. if (zend_parse_parameters_none() == FAILURE) {
  2323. RETURN_THROWS();
  2324. }
  2325. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  2326. intern->inner.iterator->funcs->move_forward(intern->inner.iterator);
  2327. } /* }}} */
  2328. /* {{{ Create an iterator from another iterator */
  2329. PHP_METHOD(InfiniteIterator, __construct)
  2330. {
  2331. spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_InfiniteIterator, zend_ce_iterator, DIT_InfiniteIterator);
  2332. } /* }}} */
  2333. /* {{{ Prevent a call to inner iterators rewind() (internally the current data will be fetched if valid()) */
  2334. PHP_METHOD(InfiniteIterator, next)
  2335. {
  2336. spl_dual_it_object *intern;
  2337. if (zend_parse_parameters_none() == FAILURE) {
  2338. RETURN_THROWS();
  2339. }
  2340. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  2341. spl_dual_it_next(intern, 1);
  2342. if (spl_dual_it_valid(intern) == SUCCESS) {
  2343. spl_dual_it_fetch(intern, 0);
  2344. } else {
  2345. spl_dual_it_rewind(intern);
  2346. if (spl_dual_it_valid(intern) == SUCCESS) {
  2347. spl_dual_it_fetch(intern, 0);
  2348. }
  2349. }
  2350. } /* }}} */
  2351. /* {{{ Does nothing */
  2352. PHP_METHOD(EmptyIterator, rewind)
  2353. {
  2354. if (zend_parse_parameters_none() == FAILURE) {
  2355. RETURN_THROWS();
  2356. }
  2357. } /* }}} */
  2358. /* {{{ Return false */
  2359. PHP_METHOD(EmptyIterator, valid)
  2360. {
  2361. if (zend_parse_parameters_none() == FAILURE) {
  2362. RETURN_THROWS();
  2363. }
  2364. RETURN_FALSE;
  2365. } /* }}} */
  2366. /* {{{ Throws exception BadMethodCallException */
  2367. PHP_METHOD(EmptyIterator, key)
  2368. {
  2369. if (zend_parse_parameters_none() == FAILURE) {
  2370. RETURN_THROWS();
  2371. }
  2372. zend_throw_exception(spl_ce_BadMethodCallException, "Accessing the key of an EmptyIterator", 0);
  2373. } /* }}} */
  2374. /* {{{ Throws exception BadMethodCallException */
  2375. PHP_METHOD(EmptyIterator, current)
  2376. {
  2377. if (zend_parse_parameters_none() == FAILURE) {
  2378. RETURN_THROWS();
  2379. }
  2380. zend_throw_exception(spl_ce_BadMethodCallException, "Accessing the value of an EmptyIterator", 0);
  2381. } /* }}} */
  2382. /* {{{ Does nothing */
  2383. PHP_METHOD(EmptyIterator, next)
  2384. {
  2385. if (zend_parse_parameters_none() == FAILURE) {
  2386. RETURN_THROWS();
  2387. }
  2388. } /* }}} */
  2389. int spl_append_it_next_iterator(spl_dual_it_object *intern) /* {{{*/
  2390. {
  2391. spl_dual_it_free(intern);
  2392. if (!Z_ISUNDEF(intern->inner.zobject)) {
  2393. zval_ptr_dtor(&intern->inner.zobject);
  2394. ZVAL_UNDEF(&intern->inner.zobject);
  2395. intern->inner.ce = NULL;
  2396. if (intern->inner.iterator) {
  2397. zend_iterator_dtor(intern->inner.iterator);
  2398. intern->inner.iterator = NULL;
  2399. }
  2400. }
  2401. if (intern->u.append.iterator->funcs->valid(intern->u.append.iterator) == SUCCESS) {
  2402. zval *it;
  2403. it = intern->u.append.iterator->funcs->get_current_data(intern->u.append.iterator);
  2404. ZVAL_COPY(&intern->inner.zobject, it);
  2405. intern->inner.ce = Z_OBJCE_P(it);
  2406. intern->inner.iterator = intern->inner.ce->get_iterator(intern->inner.ce, it, 0);
  2407. spl_dual_it_rewind(intern);
  2408. return SUCCESS;
  2409. } else {
  2410. return FAILURE;
  2411. }
  2412. } /* }}} */
  2413. void spl_append_it_fetch(spl_dual_it_object *intern) /* {{{*/
  2414. {
  2415. while (spl_dual_it_valid(intern) != SUCCESS) {
  2416. intern->u.append.iterator->funcs->move_forward(intern->u.append.iterator);
  2417. if (spl_append_it_next_iterator(intern) != SUCCESS) {
  2418. return;
  2419. }
  2420. }
  2421. spl_dual_it_fetch(intern, 0);
  2422. } /* }}} */
  2423. void spl_append_it_next(spl_dual_it_object *intern) /* {{{ */
  2424. {
  2425. if (spl_dual_it_valid(intern) == SUCCESS) {
  2426. spl_dual_it_next(intern, 1);
  2427. }
  2428. spl_append_it_fetch(intern);
  2429. } /* }}} */
  2430. /* {{{ Create an AppendIterator */
  2431. PHP_METHOD(AppendIterator, __construct)
  2432. {
  2433. spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_AppendIterator, zend_ce_iterator, DIT_AppendIterator);
  2434. } /* }}} */
  2435. /* {{{ Append an iterator */
  2436. PHP_METHOD(AppendIterator, append)
  2437. {
  2438. spl_dual_it_object *intern;
  2439. zval *it;
  2440. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &it, zend_ce_iterator) == FAILURE) {
  2441. RETURN_THROWS();
  2442. }
  2443. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  2444. if (intern->u.append.iterator->funcs->valid(intern->u.append.iterator) == SUCCESS && spl_dual_it_valid(intern) != SUCCESS) {
  2445. spl_array_iterator_append(&intern->u.append.zarrayit, it);
  2446. intern->u.append.iterator->funcs->move_forward(intern->u.append.iterator);
  2447. }else{
  2448. spl_array_iterator_append(&intern->u.append.zarrayit, it);
  2449. }
  2450. if (!intern->inner.iterator || spl_dual_it_valid(intern) != SUCCESS) {
  2451. if (intern->u.append.iterator->funcs->valid(intern->u.append.iterator) != SUCCESS) {
  2452. intern->u.append.iterator->funcs->rewind(intern->u.append.iterator);
  2453. }
  2454. do {
  2455. spl_append_it_next_iterator(intern);
  2456. } while (Z_OBJ(intern->inner.zobject) != Z_OBJ_P(it));
  2457. spl_append_it_fetch(intern);
  2458. }
  2459. } /* }}} */
  2460. /* {{{ Get the current element value */
  2461. PHP_METHOD(AppendIterator, current)
  2462. {
  2463. spl_dual_it_object *intern;
  2464. if (zend_parse_parameters_none() == FAILURE) {
  2465. RETURN_THROWS();
  2466. }
  2467. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  2468. spl_dual_it_fetch(intern, 1);
  2469. if (Z_TYPE(intern->current.data) != IS_UNDEF) {
  2470. RETURN_COPY_DEREF(&intern->current.data);
  2471. } else {
  2472. RETURN_NULL();
  2473. }
  2474. } /* }}} */
  2475. /* {{{ Rewind to the first iterator and rewind the first iterator, too */
  2476. PHP_METHOD(AppendIterator, rewind)
  2477. {
  2478. spl_dual_it_object *intern;
  2479. if (zend_parse_parameters_none() == FAILURE) {
  2480. RETURN_THROWS();
  2481. }
  2482. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  2483. intern->u.append.iterator->funcs->rewind(intern->u.append.iterator);
  2484. if (spl_append_it_next_iterator(intern) == SUCCESS) {
  2485. spl_append_it_fetch(intern);
  2486. }
  2487. } /* }}} */
  2488. /* {{{ Check if the current state is valid */
  2489. PHP_METHOD(AppendIterator, valid)
  2490. {
  2491. spl_dual_it_object *intern;
  2492. if (zend_parse_parameters_none() == FAILURE) {
  2493. RETURN_THROWS();
  2494. }
  2495. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  2496. RETURN_BOOL(Z_TYPE(intern->current.data) != IS_UNDEF);
  2497. } /* }}} */
  2498. /* {{{ Forward to next element */
  2499. PHP_METHOD(AppendIterator, next)
  2500. {
  2501. spl_dual_it_object *intern;
  2502. if (zend_parse_parameters_none() == FAILURE) {
  2503. RETURN_THROWS();
  2504. }
  2505. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  2506. spl_append_it_next(intern);
  2507. } /* }}} */
  2508. /* {{{ Get index of iterator */
  2509. PHP_METHOD(AppendIterator, getIteratorIndex)
  2510. {
  2511. spl_dual_it_object *intern;
  2512. if (zend_parse_parameters_none() == FAILURE) {
  2513. RETURN_THROWS();
  2514. }
  2515. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  2516. APPENDIT_CHECK_CTOR(intern);
  2517. spl_array_iterator_key(&intern->u.append.zarrayit, return_value);
  2518. } /* }}} */
  2519. /* {{{ Get access to inner ArrayIterator */
  2520. PHP_METHOD(AppendIterator, getArrayIterator)
  2521. {
  2522. spl_dual_it_object *intern;
  2523. zval *value;
  2524. if (zend_parse_parameters_none() == FAILURE) {
  2525. RETURN_THROWS();
  2526. }
  2527. SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
  2528. value = &intern->u.append.zarrayit;
  2529. RETURN_COPY_DEREF(value);
  2530. } /* }}} */
  2531. PHPAPI int spl_iterator_apply(zval *obj, spl_iterator_apply_func_t apply_func, void *puser)
  2532. {
  2533. zend_object_iterator *iter;
  2534. zend_class_entry *ce = Z_OBJCE_P(obj);
  2535. iter = ce->get_iterator(ce, obj, 0);
  2536. if (EG(exception)) {
  2537. goto done;
  2538. }
  2539. iter->index = 0;
  2540. if (iter->funcs->rewind) {
  2541. iter->funcs->rewind(iter);
  2542. if (EG(exception)) {
  2543. goto done;
  2544. }
  2545. }
  2546. while (iter->funcs->valid(iter) == SUCCESS) {
  2547. if (EG(exception)) {
  2548. goto done;
  2549. }
  2550. if (apply_func(iter, puser) == ZEND_HASH_APPLY_STOP || EG(exception)) {
  2551. goto done;
  2552. }
  2553. iter->index++;
  2554. iter->funcs->move_forward(iter);
  2555. if (EG(exception)) {
  2556. goto done;
  2557. }
  2558. }
  2559. done:
  2560. if (iter) {
  2561. zend_iterator_dtor(iter);
  2562. }
  2563. return EG(exception) ? FAILURE : SUCCESS;
  2564. }
  2565. /* }}} */
  2566. static int spl_iterator_to_array_apply(zend_object_iterator *iter, void *puser) /* {{{ */
  2567. {
  2568. zval *data, *return_value = (zval*)puser;
  2569. data = iter->funcs->get_current_data(iter);
  2570. if (EG(exception)) {
  2571. return ZEND_HASH_APPLY_STOP;
  2572. }
  2573. if (data == NULL) {
  2574. return ZEND_HASH_APPLY_STOP;
  2575. }
  2576. if (iter->funcs->get_current_key) {
  2577. zval key;
  2578. iter->funcs->get_current_key(iter, &key);
  2579. if (EG(exception)) {
  2580. return ZEND_HASH_APPLY_STOP;
  2581. }
  2582. array_set_zval_key(Z_ARRVAL_P(return_value), &key, data);
  2583. zval_ptr_dtor(&key);
  2584. } else {
  2585. Z_TRY_ADDREF_P(data);
  2586. add_next_index_zval(return_value, data);
  2587. }
  2588. return ZEND_HASH_APPLY_KEEP;
  2589. }
  2590. /* }}} */
  2591. static int spl_iterator_to_values_apply(zend_object_iterator *iter, void *puser) /* {{{ */
  2592. {
  2593. zval *data, *return_value = (zval*)puser;
  2594. data = iter->funcs->get_current_data(iter);
  2595. if (EG(exception)) {
  2596. return ZEND_HASH_APPLY_STOP;
  2597. }
  2598. if (data == NULL) {
  2599. return ZEND_HASH_APPLY_STOP;
  2600. }
  2601. Z_TRY_ADDREF_P(data);
  2602. add_next_index_zval(return_value, data);
  2603. return ZEND_HASH_APPLY_KEEP;
  2604. }
  2605. /* }}} */
  2606. /* {{{ Copy the iterator into an array */
  2607. PHP_FUNCTION(iterator_to_array)
  2608. {
  2609. zval *obj;
  2610. bool use_keys = 1;
  2611. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|b", &obj, zend_ce_traversable, &use_keys) == FAILURE) {
  2612. RETURN_THROWS();
  2613. }
  2614. array_init(return_value);
  2615. spl_iterator_apply(obj, use_keys ? spl_iterator_to_array_apply : spl_iterator_to_values_apply, (void*)return_value);
  2616. } /* }}} */
  2617. static int spl_iterator_count_apply(zend_object_iterator *iter, void *puser) /* {{{ */
  2618. {
  2619. if (UNEXPECTED(*(zend_long*)puser == ZEND_LONG_MAX)) {
  2620. return ZEND_HASH_APPLY_STOP;
  2621. }
  2622. (*(zend_long*)puser)++;
  2623. return ZEND_HASH_APPLY_KEEP;
  2624. }
  2625. /* }}} */
  2626. /* {{{ Count the elements in an iterator */
  2627. PHP_FUNCTION(iterator_count)
  2628. {
  2629. zval *obj;
  2630. zend_long count = 0;
  2631. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &obj, zend_ce_traversable) == FAILURE) {
  2632. RETURN_THROWS();
  2633. }
  2634. if (spl_iterator_apply(obj, spl_iterator_count_apply, (void*)&count) == FAILURE) {
  2635. return;
  2636. }
  2637. RETURN_LONG(count);
  2638. }
  2639. /* }}} */
  2640. typedef struct {
  2641. zval *obj;
  2642. zval *args;
  2643. zend_long count;
  2644. zend_fcall_info fci;
  2645. zend_fcall_info_cache fcc;
  2646. } spl_iterator_apply_info;
  2647. static int spl_iterator_func_apply(zend_object_iterator *iter, void *puser) /* {{{ */
  2648. {
  2649. zval retval;
  2650. spl_iterator_apply_info *apply_info = (spl_iterator_apply_info*)puser;
  2651. int result;
  2652. apply_info->count++;
  2653. zend_fcall_info_call(&apply_info->fci, &apply_info->fcc, &retval, NULL);
  2654. result = zend_is_true(&retval) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_STOP;
  2655. zval_ptr_dtor(&retval);
  2656. return result;
  2657. }
  2658. /* }}} */
  2659. /* {{{ Calls a function for every element in an iterator */
  2660. PHP_FUNCTION(iterator_apply)
  2661. {
  2662. spl_iterator_apply_info apply_info;
  2663. apply_info.args = NULL;
  2664. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Of|a!", &apply_info.obj, zend_ce_traversable, &apply_info.fci, &apply_info.fcc, &apply_info.args) == FAILURE) {
  2665. RETURN_THROWS();
  2666. }
  2667. apply_info.count = 0;
  2668. zend_fcall_info_args(&apply_info.fci, apply_info.args);
  2669. if (spl_iterator_apply(apply_info.obj, spl_iterator_func_apply, (void*)&apply_info) == FAILURE) {
  2670. zend_fcall_info_args(&apply_info.fci, NULL);
  2671. return;
  2672. }
  2673. zend_fcall_info_args(&apply_info.fci, NULL);
  2674. RETURN_LONG(apply_info.count);
  2675. }
  2676. /* }}} */
  2677. /* {{{ PHP_MINIT_FUNCTION(spl_iterators) */
  2678. PHP_MINIT_FUNCTION(spl_iterators)
  2679. {
  2680. spl_ce_RecursiveIterator = register_class_RecursiveIterator(zend_ce_iterator);
  2681. spl_ce_OuterIterator = register_class_OuterIterator(zend_ce_iterator);
  2682. spl_ce_RecursiveIteratorIterator = register_class_RecursiveIteratorIterator(spl_ce_OuterIterator);
  2683. spl_ce_RecursiveIteratorIterator->create_object = spl_RecursiveIteratorIterator_new;
  2684. spl_ce_RecursiveIteratorIterator->get_iterator = spl_recursive_it_get_iterator;
  2685. memcpy(&spl_handlers_rec_it_it, &std_object_handlers, sizeof(zend_object_handlers));
  2686. spl_handlers_rec_it_it.offset = XtOffsetOf(spl_recursive_it_object, std);
  2687. spl_handlers_rec_it_it.get_method = spl_recursive_it_get_method;
  2688. spl_handlers_rec_it_it.clone_obj = NULL;
  2689. spl_handlers_rec_it_it.free_obj = spl_RecursiveIteratorIterator_free_storage;
  2690. spl_handlers_rec_it_it.get_gc = spl_RecursiveIteratorIterator_get_gc;
  2691. memcpy(&spl_handlers_dual_it, &std_object_handlers, sizeof(zend_object_handlers));
  2692. spl_handlers_dual_it.offset = XtOffsetOf(spl_dual_it_object, std);
  2693. spl_handlers_dual_it.get_method = spl_dual_it_get_method;
  2694. spl_handlers_dual_it.clone_obj = NULL;
  2695. spl_handlers_dual_it.free_obj = spl_dual_it_free_storage;
  2696. spl_handlers_dual_it.get_gc = spl_dual_it_get_gc;
  2697. REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "LEAVES_ONLY", RIT_LEAVES_ONLY);
  2698. REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "SELF_FIRST", RIT_SELF_FIRST);
  2699. REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "CHILD_FIRST", RIT_CHILD_FIRST);
  2700. REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "CATCH_GET_CHILD", RIT_CATCH_GET_CHILD);
  2701. spl_ce_IteratorIterator = register_class_IteratorIterator(spl_ce_OuterIterator);
  2702. spl_ce_IteratorIterator->create_object = spl_dual_it_new;
  2703. spl_ce_FilterIterator = register_class_FilterIterator(spl_ce_IteratorIterator);
  2704. spl_ce_FilterIterator->create_object = spl_dual_it_new;
  2705. spl_ce_RecursiveFilterIterator = register_class_RecursiveFilterIterator(spl_ce_FilterIterator, spl_ce_RecursiveIterator);
  2706. spl_ce_RecursiveFilterIterator->create_object = spl_dual_it_new;
  2707. spl_ce_CallbackFilterIterator = register_class_CallbackFilterIterator(spl_ce_FilterIterator);
  2708. spl_ce_CallbackFilterIterator->create_object = spl_dual_it_new;
  2709. spl_ce_RecursiveCallbackFilterIterator = register_class_RecursiveCallbackFilterIterator(spl_ce_CallbackFilterIterator, spl_ce_RecursiveIterator);
  2710. spl_ce_RecursiveCallbackFilterIterator->create_object = spl_dual_it_new;
  2711. spl_ce_ParentIterator = register_class_ParentIterator(spl_ce_RecursiveFilterIterator);
  2712. spl_ce_ParentIterator->create_object = spl_dual_it_new;
  2713. spl_ce_SeekableIterator = register_class_SeekableIterator(zend_ce_iterator);
  2714. spl_ce_LimitIterator = register_class_LimitIterator(spl_ce_IteratorIterator);
  2715. spl_ce_LimitIterator->create_object = spl_dual_it_new;
  2716. spl_ce_CachingIterator = register_class_CachingIterator(spl_ce_IteratorIterator, zend_ce_arrayaccess, zend_ce_countable, zend_ce_stringable);
  2717. spl_ce_CachingIterator->create_object = spl_dual_it_new;
  2718. REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "CALL_TOSTRING", CIT_CALL_TOSTRING);
  2719. REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "CATCH_GET_CHILD", CIT_CATCH_GET_CHILD);
  2720. REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_KEY", CIT_TOSTRING_USE_KEY);
  2721. REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_CURRENT", CIT_TOSTRING_USE_CURRENT);
  2722. REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_INNER", CIT_TOSTRING_USE_INNER);
  2723. REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "FULL_CACHE", CIT_FULL_CACHE);
  2724. spl_ce_RecursiveCachingIterator = register_class_RecursiveCachingIterator(spl_ce_CachingIterator, spl_ce_RecursiveIterator);
  2725. spl_ce_RecursiveCachingIterator->create_object = spl_dual_it_new;
  2726. spl_ce_NoRewindIterator = register_class_NoRewindIterator(spl_ce_IteratorIterator);
  2727. spl_ce_NoRewindIterator->create_object = spl_dual_it_new;
  2728. spl_ce_AppendIterator = register_class_AppendIterator(spl_ce_IteratorIterator);
  2729. spl_ce_AppendIterator->create_object = spl_dual_it_new;
  2730. spl_ce_InfiniteIterator = register_class_InfiniteIterator(spl_ce_IteratorIterator);
  2731. spl_ce_InfiniteIterator->create_object = spl_dual_it_new;
  2732. spl_ce_RegexIterator = register_class_RegexIterator(spl_ce_FilterIterator);
  2733. spl_ce_RegexIterator->create_object = spl_dual_it_new;
  2734. REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "USE_KEY", REGIT_USE_KEY);
  2735. REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "INVERT_MATCH",REGIT_INVERTED);
  2736. REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "MATCH", REGIT_MODE_MATCH);
  2737. REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "GET_MATCH", REGIT_MODE_GET_MATCH);
  2738. REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "ALL_MATCHES", REGIT_MODE_ALL_MATCHES);
  2739. REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "SPLIT", REGIT_MODE_SPLIT);
  2740. REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "REPLACE", REGIT_MODE_REPLACE);
  2741. spl_ce_RecursiveRegexIterator = register_class_RecursiveRegexIterator(spl_ce_RegexIterator, spl_ce_RecursiveIterator);
  2742. spl_ce_RecursiveRegexIterator->create_object = spl_dual_it_new;
  2743. spl_ce_EmptyIterator = register_class_EmptyIterator(zend_ce_iterator);
  2744. spl_ce_RecursiveTreeIterator = register_class_RecursiveTreeIterator(spl_ce_RecursiveIteratorIterator);
  2745. spl_ce_RecursiveTreeIterator->create_object = spl_RecursiveTreeIterator_new;
  2746. REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "BYPASS_CURRENT", RTIT_BYPASS_CURRENT);
  2747. REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "BYPASS_KEY", RTIT_BYPASS_KEY);
  2748. REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_LEFT", 0);
  2749. REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_MID_HAS_NEXT", 1);
  2750. REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_MID_LAST", 2);
  2751. REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_END_HAS_NEXT", 3);
  2752. REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_END_LAST", 4);
  2753. REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_RIGHT", 5);
  2754. return SUCCESS;
  2755. }
  2756. /* }}} */