xpath.c 400 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736
  1. /*
  2. * xpath.c: XML Path Language implementation
  3. * XPath is a language for addressing parts of an XML document,
  4. * designed to be used by both XSLT and XPointer
  5. *
  6. * Reference: W3C Recommendation 16 November 1999
  7. * http://www.w3.org/TR/1999/REC-xpath-19991116
  8. * Public reference:
  9. * http://www.w3.org/TR/xpath
  10. *
  11. * See Copyright for the status of this software
  12. *
  13. * Author: daniel@veillard.com
  14. *
  15. */
  16. /* To avoid EBCDIC trouble when parsing on zOS */
  17. #if defined(__MVS__)
  18. #pragma convert("ISO8859-1")
  19. #endif
  20. #define IN_LIBXML
  21. #include "libxml.h"
  22. #include <limits.h>
  23. #include <string.h>
  24. #include <stddef.h>
  25. #ifdef HAVE_SYS_TYPES_H
  26. #include <sys/types.h>
  27. #endif
  28. #ifdef HAVE_MATH_H
  29. #include <math.h>
  30. #endif
  31. #ifdef HAVE_FLOAT_H
  32. #include <float.h>
  33. #endif
  34. #ifdef HAVE_CTYPE_H
  35. #include <ctype.h>
  36. #endif
  37. #ifdef HAVE_SIGNAL_H
  38. #include <signal.h>
  39. #endif
  40. #include <libxml/xmlmemory.h>
  41. #include <libxml/tree.h>
  42. #include <libxml/valid.h>
  43. #include <libxml/xpath.h>
  44. #include <libxml/xpathInternals.h>
  45. #include <libxml/parserInternals.h>
  46. #include <libxml/hash.h>
  47. #ifdef LIBXML_XPTR_ENABLED
  48. #include <libxml/xpointer.h>
  49. #endif
  50. #ifdef LIBXML_DEBUG_ENABLED
  51. #include <libxml/debugXML.h>
  52. #endif
  53. #include <libxml/xmlerror.h>
  54. #include <libxml/threads.h>
  55. #include <libxml/globals.h>
  56. #ifdef LIBXML_PATTERN_ENABLED
  57. #include <libxml/pattern.h>
  58. #endif
  59. #include "buf.h"
  60. #ifdef LIBXML_PATTERN_ENABLED
  61. #define XPATH_STREAMING
  62. #endif
  63. #define TODO \
  64. xmlGenericError(xmlGenericErrorContext, \
  65. "Unimplemented block at %s:%d\n", \
  66. __FILE__, __LINE__);
  67. /**
  68. * WITH_TIM_SORT:
  69. *
  70. * Use the Timsort algorithm provided in timsort.h to sort
  71. * nodeset as this is a great improvement over the old Shell sort
  72. * used in xmlXPathNodeSetSort()
  73. */
  74. #define WITH_TIM_SORT
  75. /*
  76. * XP_OPTIMIZED_NON_ELEM_COMPARISON:
  77. * If defined, this will use xmlXPathCmpNodesExt() instead of
  78. * xmlXPathCmpNodes(). The new function is optimized comparison of
  79. * non-element nodes; actually it will speed up comparison only if
  80. * xmlXPathOrderDocElems() was called in order to index the elements of
  81. * a tree in document order; Libxslt does such an indexing, thus it will
  82. * benefit from this optimization.
  83. */
  84. #define XP_OPTIMIZED_NON_ELEM_COMPARISON
  85. /*
  86. * XP_OPTIMIZED_FILTER_FIRST:
  87. * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
  88. * in a way, that it stop evaluation at the first node.
  89. */
  90. #define XP_OPTIMIZED_FILTER_FIRST
  91. /*
  92. * XP_DEBUG_OBJ_USAGE:
  93. * Internal flag to enable tracking of how much XPath objects have been
  94. * created.
  95. */
  96. /* #define XP_DEBUG_OBJ_USAGE */
  97. /*
  98. * XPATH_MAX_STEPS:
  99. * when compiling an XPath expression we arbitrary limit the maximum
  100. * number of step operation in the compiled expression. 1000000 is
  101. * an insanely large value which should never be reached under normal
  102. * circumstances
  103. */
  104. #define XPATH_MAX_STEPS 1000000
  105. /*
  106. * XPATH_MAX_STACK_DEPTH:
  107. * when evaluating an XPath expression we arbitrary limit the maximum
  108. * number of object allowed to be pushed on the stack. 1000000 is
  109. * an insanely large value which should never be reached under normal
  110. * circumstances
  111. */
  112. #define XPATH_MAX_STACK_DEPTH 1000000
  113. /*
  114. * XPATH_MAX_NODESET_LENGTH:
  115. * when evaluating an XPath expression nodesets are created and we
  116. * arbitrary limit the maximum length of those node set. 10000000 is
  117. * an insanely large value which should never be reached under normal
  118. * circumstances, one would first need to construct an in memory tree
  119. * with more than 10 millions nodes.
  120. */
  121. #define XPATH_MAX_NODESET_LENGTH 10000000
  122. /*
  123. * XPATH_MAX_RECRUSION_DEPTH:
  124. * Maximum amount of nested functions calls when parsing or evaluating
  125. * expressions
  126. */
  127. #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
  128. #define XPATH_MAX_RECURSION_DEPTH 500
  129. #else
  130. #define XPATH_MAX_RECURSION_DEPTH 5000
  131. #endif
  132. /*
  133. * TODO:
  134. * There are a few spots where some tests are done which depend upon ascii
  135. * data. These should be enhanced for full UTF8 support (see particularly
  136. * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
  137. */
  138. #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
  139. /**
  140. * xmlXPathCmpNodesExt:
  141. * @node1: the first node
  142. * @node2: the second node
  143. *
  144. * Compare two nodes w.r.t document order.
  145. * This one is optimized for handling of non-element nodes.
  146. *
  147. * Returns -2 in case of error 1 if first point < second point, 0 if
  148. * it's the same node, -1 otherwise
  149. */
  150. static int
  151. xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
  152. int depth1, depth2;
  153. int misc = 0, precedence1 = 0, precedence2 = 0;
  154. xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
  155. xmlNodePtr cur, root;
  156. ptrdiff_t l1, l2;
  157. if ((node1 == NULL) || (node2 == NULL))
  158. return(-2);
  159. if (node1 == node2)
  160. return(0);
  161. /*
  162. * a couple of optimizations which will avoid computations in most cases
  163. */
  164. switch (node1->type) {
  165. case XML_ELEMENT_NODE:
  166. if (node2->type == XML_ELEMENT_NODE) {
  167. if ((0 > (ptrdiff_t) node1->content) &&
  168. (0 > (ptrdiff_t) node2->content) &&
  169. (node1->doc == node2->doc))
  170. {
  171. l1 = -((ptrdiff_t) node1->content);
  172. l2 = -((ptrdiff_t) node2->content);
  173. if (l1 < l2)
  174. return(1);
  175. if (l1 > l2)
  176. return(-1);
  177. } else
  178. goto turtle_comparison;
  179. }
  180. break;
  181. case XML_ATTRIBUTE_NODE:
  182. precedence1 = 1; /* element is owner */
  183. miscNode1 = node1;
  184. node1 = node1->parent;
  185. misc = 1;
  186. break;
  187. case XML_TEXT_NODE:
  188. case XML_CDATA_SECTION_NODE:
  189. case XML_COMMENT_NODE:
  190. case XML_PI_NODE: {
  191. miscNode1 = node1;
  192. /*
  193. * Find nearest element node.
  194. */
  195. if (node1->prev != NULL) {
  196. do {
  197. node1 = node1->prev;
  198. if (node1->type == XML_ELEMENT_NODE) {
  199. precedence1 = 3; /* element in prev-sibl axis */
  200. break;
  201. }
  202. if (node1->prev == NULL) {
  203. precedence1 = 2; /* element is parent */
  204. /*
  205. * URGENT TODO: Are there any cases, where the
  206. * parent of such a node is not an element node?
  207. */
  208. node1 = node1->parent;
  209. break;
  210. }
  211. } while (1);
  212. } else {
  213. precedence1 = 2; /* element is parent */
  214. node1 = node1->parent;
  215. }
  216. if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
  217. (0 <= (ptrdiff_t) node1->content)) {
  218. /*
  219. * Fallback for whatever case.
  220. */
  221. node1 = miscNode1;
  222. precedence1 = 0;
  223. } else
  224. misc = 1;
  225. }
  226. break;
  227. case XML_NAMESPACE_DECL:
  228. /*
  229. * TODO: why do we return 1 for namespace nodes?
  230. */
  231. return(1);
  232. default:
  233. break;
  234. }
  235. switch (node2->type) {
  236. case XML_ELEMENT_NODE:
  237. break;
  238. case XML_ATTRIBUTE_NODE:
  239. precedence2 = 1; /* element is owner */
  240. miscNode2 = node2;
  241. node2 = node2->parent;
  242. misc = 1;
  243. break;
  244. case XML_TEXT_NODE:
  245. case XML_CDATA_SECTION_NODE:
  246. case XML_COMMENT_NODE:
  247. case XML_PI_NODE: {
  248. miscNode2 = node2;
  249. if (node2->prev != NULL) {
  250. do {
  251. node2 = node2->prev;
  252. if (node2->type == XML_ELEMENT_NODE) {
  253. precedence2 = 3; /* element in prev-sibl axis */
  254. break;
  255. }
  256. if (node2->prev == NULL) {
  257. precedence2 = 2; /* element is parent */
  258. node2 = node2->parent;
  259. break;
  260. }
  261. } while (1);
  262. } else {
  263. precedence2 = 2; /* element is parent */
  264. node2 = node2->parent;
  265. }
  266. if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
  267. (0 <= (ptrdiff_t) node2->content))
  268. {
  269. node2 = miscNode2;
  270. precedence2 = 0;
  271. } else
  272. misc = 1;
  273. }
  274. break;
  275. case XML_NAMESPACE_DECL:
  276. return(1);
  277. default:
  278. break;
  279. }
  280. if (misc) {
  281. if (node1 == node2) {
  282. if (precedence1 == precedence2) {
  283. /*
  284. * The ugly case; but normally there aren't many
  285. * adjacent non-element nodes around.
  286. */
  287. cur = miscNode2->prev;
  288. while (cur != NULL) {
  289. if (cur == miscNode1)
  290. return(1);
  291. if (cur->type == XML_ELEMENT_NODE)
  292. return(-1);
  293. cur = cur->prev;
  294. }
  295. return (-1);
  296. } else {
  297. /*
  298. * Evaluate based on higher precedence wrt to the element.
  299. * TODO: This assumes attributes are sorted before content.
  300. * Is this 100% correct?
  301. */
  302. if (precedence1 < precedence2)
  303. return(1);
  304. else
  305. return(-1);
  306. }
  307. }
  308. /*
  309. * Special case: One of the helper-elements is contained by the other.
  310. * <foo>
  311. * <node2>
  312. * <node1>Text-1(precedence1 == 2)</node1>
  313. * </node2>
  314. * Text-6(precedence2 == 3)
  315. * </foo>
  316. */
  317. if ((precedence2 == 3) && (precedence1 > 1)) {
  318. cur = node1->parent;
  319. while (cur) {
  320. if (cur == node2)
  321. return(1);
  322. cur = cur->parent;
  323. }
  324. }
  325. if ((precedence1 == 3) && (precedence2 > 1)) {
  326. cur = node2->parent;
  327. while (cur) {
  328. if (cur == node1)
  329. return(-1);
  330. cur = cur->parent;
  331. }
  332. }
  333. }
  334. /*
  335. * Speedup using document order if available.
  336. */
  337. if ((node1->type == XML_ELEMENT_NODE) &&
  338. (node2->type == XML_ELEMENT_NODE) &&
  339. (0 > (ptrdiff_t) node1->content) &&
  340. (0 > (ptrdiff_t) node2->content) &&
  341. (node1->doc == node2->doc)) {
  342. l1 = -((ptrdiff_t) node1->content);
  343. l2 = -((ptrdiff_t) node2->content);
  344. if (l1 < l2)
  345. return(1);
  346. if (l1 > l2)
  347. return(-1);
  348. }
  349. turtle_comparison:
  350. if (node1 == node2->prev)
  351. return(1);
  352. if (node1 == node2->next)
  353. return(-1);
  354. /*
  355. * compute depth to root
  356. */
  357. for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
  358. if (cur->parent == node1)
  359. return(1);
  360. depth2++;
  361. }
  362. root = cur;
  363. for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
  364. if (cur->parent == node2)
  365. return(-1);
  366. depth1++;
  367. }
  368. /*
  369. * Distinct document (or distinct entities :-( ) case.
  370. */
  371. if (root != cur) {
  372. return(-2);
  373. }
  374. /*
  375. * get the nearest common ancestor.
  376. */
  377. while (depth1 > depth2) {
  378. depth1--;
  379. node1 = node1->parent;
  380. }
  381. while (depth2 > depth1) {
  382. depth2--;
  383. node2 = node2->parent;
  384. }
  385. while (node1->parent != node2->parent) {
  386. node1 = node1->parent;
  387. node2 = node2->parent;
  388. /* should not happen but just in case ... */
  389. if ((node1 == NULL) || (node2 == NULL))
  390. return(-2);
  391. }
  392. /*
  393. * Find who's first.
  394. */
  395. if (node1 == node2->prev)
  396. return(1);
  397. if (node1 == node2->next)
  398. return(-1);
  399. /*
  400. * Speedup using document order if available.
  401. */
  402. if ((node1->type == XML_ELEMENT_NODE) &&
  403. (node2->type == XML_ELEMENT_NODE) &&
  404. (0 > (ptrdiff_t) node1->content) &&
  405. (0 > (ptrdiff_t) node2->content) &&
  406. (node1->doc == node2->doc)) {
  407. l1 = -((ptrdiff_t) node1->content);
  408. l2 = -((ptrdiff_t) node2->content);
  409. if (l1 < l2)
  410. return(1);
  411. if (l1 > l2)
  412. return(-1);
  413. }
  414. for (cur = node1->next;cur != NULL;cur = cur->next)
  415. if (cur == node2)
  416. return(1);
  417. return(-1); /* assume there is no sibling list corruption */
  418. }
  419. #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
  420. /*
  421. * Wrapper for the Timsort algorithm from timsort.h
  422. */
  423. #ifdef WITH_TIM_SORT
  424. #define SORT_NAME libxml_domnode
  425. #define SORT_TYPE xmlNodePtr
  426. /**
  427. * wrap_cmp:
  428. * @x: a node
  429. * @y: another node
  430. *
  431. * Comparison function for the Timsort implementation
  432. *
  433. * Returns -2 in case of error -1 if first point < second point, 0 if
  434. * it's the same node, +1 otherwise
  435. */
  436. static
  437. int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
  438. #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
  439. static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
  440. {
  441. int res = xmlXPathCmpNodesExt(x, y);
  442. return res == -2 ? res : -res;
  443. }
  444. #else
  445. static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
  446. {
  447. int res = xmlXPathCmpNodes(x, y);
  448. return res == -2 ? res : -res;
  449. }
  450. #endif
  451. #define SORT_CMP(x, y) (wrap_cmp(x, y))
  452. #include "timsort.h"
  453. #endif /* WITH_TIM_SORT */
  454. #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
  455. /************************************************************************
  456. * *
  457. * Floating point stuff *
  458. * *
  459. ************************************************************************/
  460. double xmlXPathNAN;
  461. double xmlXPathPINF;
  462. double xmlXPathNINF;
  463. /**
  464. * xmlXPathInit:
  465. *
  466. * Initialize the XPath environment
  467. */
  468. ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
  469. void
  470. xmlXPathInit(void) {
  471. /* MSVC doesn't allow division by zero in constant expressions. */
  472. double zero = 0.0;
  473. xmlXPathNAN = 0.0 / zero;
  474. xmlXPathPINF = 1.0 / zero;
  475. xmlXPathNINF = -xmlXPathPINF;
  476. }
  477. /**
  478. * xmlXPathIsNaN:
  479. * @val: a double value
  480. *
  481. * Returns 1 if the value is a NaN, 0 otherwise
  482. */
  483. int
  484. xmlXPathIsNaN(double val) {
  485. #ifdef isnan
  486. return isnan(val);
  487. #else
  488. return !(val == val);
  489. #endif
  490. }
  491. /**
  492. * xmlXPathIsInf:
  493. * @val: a double value
  494. *
  495. * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
  496. */
  497. int
  498. xmlXPathIsInf(double val) {
  499. #ifdef isinf
  500. return isinf(val) ? (val > 0 ? 1 : -1) : 0;
  501. #else
  502. if (val >= xmlXPathPINF)
  503. return 1;
  504. if (val <= -xmlXPathPINF)
  505. return -1;
  506. return 0;
  507. #endif
  508. }
  509. #endif /* SCHEMAS or XPATH */
  510. #ifdef LIBXML_XPATH_ENABLED
  511. /*
  512. * TODO: when compatibility allows remove all "fake node libxslt" strings
  513. * the test should just be name[0] = ' '
  514. */
  515. #ifdef DEBUG_XPATH_EXPRESSION
  516. #define DEBUG_STEP
  517. #define DEBUG_EXPR
  518. #define DEBUG_EVAL_COUNTS
  519. #endif
  520. static xmlNs xmlXPathXMLNamespaceStruct = {
  521. NULL,
  522. XML_NAMESPACE_DECL,
  523. XML_XML_NAMESPACE,
  524. BAD_CAST "xml",
  525. NULL,
  526. NULL
  527. };
  528. static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
  529. #ifndef LIBXML_THREAD_ENABLED
  530. /*
  531. * Optimizer is disabled only when threaded apps are detected while
  532. * the library ain't compiled for thread safety.
  533. */
  534. static int xmlXPathDisableOptimizer = 0;
  535. #endif
  536. /************************************************************************
  537. * *
  538. * Error handling routines *
  539. * *
  540. ************************************************************************/
  541. /**
  542. * XP_ERRORNULL:
  543. * @X: the error code
  544. *
  545. * Macro to raise an XPath error and return NULL.
  546. */
  547. #define XP_ERRORNULL(X) \
  548. { xmlXPathErr(ctxt, X); return(NULL); }
  549. /*
  550. * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
  551. */
  552. static const char *xmlXPathErrorMessages[] = {
  553. "Ok\n",
  554. "Number encoding\n",
  555. "Unfinished literal\n",
  556. "Start of literal\n",
  557. "Expected $ for variable reference\n",
  558. "Undefined variable\n",
  559. "Invalid predicate\n",
  560. "Invalid expression\n",
  561. "Missing closing curly brace\n",
  562. "Unregistered function\n",
  563. "Invalid operand\n",
  564. "Invalid type\n",
  565. "Invalid number of arguments\n",
  566. "Invalid context size\n",
  567. "Invalid context position\n",
  568. "Memory allocation error\n",
  569. "Syntax error\n",
  570. "Resource error\n",
  571. "Sub resource error\n",
  572. "Undefined namespace prefix\n",
  573. "Encoding error\n",
  574. "Char out of XML range\n",
  575. "Invalid or incomplete context\n",
  576. "Stack usage error\n",
  577. "Forbidden variable\n",
  578. "Operation limit exceeded\n",
  579. "Recursion limit exceeded\n",
  580. "?? Unknown error ??\n" /* Must be last in the list! */
  581. };
  582. #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
  583. sizeof(xmlXPathErrorMessages[0])) - 1)
  584. /**
  585. * xmlXPathErrMemory:
  586. * @ctxt: an XPath context
  587. * @extra: extra information
  588. *
  589. * Handle a redefinition of attribute error
  590. */
  591. static void
  592. xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
  593. {
  594. if (ctxt != NULL) {
  595. xmlResetError(&ctxt->lastError);
  596. if (extra) {
  597. xmlChar buf[200];
  598. xmlStrPrintf(buf, 200,
  599. "Memory allocation failed : %s\n",
  600. extra);
  601. ctxt->lastError.message = (char *) xmlStrdup(buf);
  602. } else {
  603. ctxt->lastError.message = (char *)
  604. xmlStrdup(BAD_CAST "Memory allocation failed\n");
  605. }
  606. ctxt->lastError.domain = XML_FROM_XPATH;
  607. ctxt->lastError.code = XML_ERR_NO_MEMORY;
  608. if (ctxt->error != NULL)
  609. ctxt->error(ctxt->userData, &ctxt->lastError);
  610. } else {
  611. if (extra)
  612. __xmlRaiseError(NULL, NULL, NULL,
  613. NULL, NULL, XML_FROM_XPATH,
  614. XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
  615. extra, NULL, NULL, 0, 0,
  616. "Memory allocation failed : %s\n", extra);
  617. else
  618. __xmlRaiseError(NULL, NULL, NULL,
  619. NULL, NULL, XML_FROM_XPATH,
  620. XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
  621. NULL, NULL, NULL, 0, 0,
  622. "Memory allocation failed\n");
  623. }
  624. }
  625. /**
  626. * xmlXPathPErrMemory:
  627. * @ctxt: an XPath parser context
  628. * @extra: extra information
  629. *
  630. * Handle a redefinition of attribute error
  631. */
  632. static void
  633. xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
  634. {
  635. if (ctxt == NULL)
  636. xmlXPathErrMemory(NULL, extra);
  637. else {
  638. ctxt->error = XPATH_MEMORY_ERROR;
  639. xmlXPathErrMemory(ctxt->context, extra);
  640. }
  641. }
  642. /**
  643. * xmlXPathErr:
  644. * @ctxt: a XPath parser context
  645. * @error: the error code
  646. *
  647. * Handle an XPath error
  648. */
  649. void
  650. xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
  651. {
  652. if ((error < 0) || (error > MAXERRNO))
  653. error = MAXERRNO;
  654. if (ctxt == NULL) {
  655. __xmlRaiseError(NULL, NULL, NULL,
  656. NULL, NULL, XML_FROM_XPATH,
  657. error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
  658. XML_ERR_ERROR, NULL, 0,
  659. NULL, NULL, NULL, 0, 0,
  660. "%s", xmlXPathErrorMessages[error]);
  661. return;
  662. }
  663. ctxt->error = error;
  664. if (ctxt->context == NULL) {
  665. __xmlRaiseError(NULL, NULL, NULL,
  666. NULL, NULL, XML_FROM_XPATH,
  667. error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
  668. XML_ERR_ERROR, NULL, 0,
  669. (const char *) ctxt->base, NULL, NULL,
  670. ctxt->cur - ctxt->base, 0,
  671. "%s", xmlXPathErrorMessages[error]);
  672. return;
  673. }
  674. /* cleanup current last error */
  675. xmlResetError(&ctxt->context->lastError);
  676. ctxt->context->lastError.domain = XML_FROM_XPATH;
  677. ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
  678. XPATH_EXPRESSION_OK;
  679. ctxt->context->lastError.level = XML_ERR_ERROR;
  680. ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
  681. ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
  682. ctxt->context->lastError.node = ctxt->context->debugNode;
  683. if (ctxt->context->error != NULL) {
  684. ctxt->context->error(ctxt->context->userData,
  685. &ctxt->context->lastError);
  686. } else {
  687. __xmlRaiseError(NULL, NULL, NULL,
  688. NULL, ctxt->context->debugNode, XML_FROM_XPATH,
  689. error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
  690. XML_ERR_ERROR, NULL, 0,
  691. (const char *) ctxt->base, NULL, NULL,
  692. ctxt->cur - ctxt->base, 0,
  693. "%s", xmlXPathErrorMessages[error]);
  694. }
  695. }
  696. /**
  697. * xmlXPatherror:
  698. * @ctxt: the XPath Parser context
  699. * @file: the file name
  700. * @line: the line number
  701. * @no: the error number
  702. *
  703. * Formats an error message.
  704. */
  705. void
  706. xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
  707. int line ATTRIBUTE_UNUSED, int no) {
  708. xmlXPathErr(ctxt, no);
  709. }
  710. /**
  711. * xmlXPathCheckOpLimit:
  712. * @ctxt: the XPath Parser context
  713. * @opCount: the number of operations to be added
  714. *
  715. * Adds opCount to the running total of operations and returns -1 if the
  716. * operation limit is exceeded. Returns 0 otherwise.
  717. */
  718. static int
  719. xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
  720. xmlXPathContextPtr xpctxt = ctxt->context;
  721. if ((opCount > xpctxt->opLimit) ||
  722. (xpctxt->opCount > xpctxt->opLimit - opCount)) {
  723. xpctxt->opCount = xpctxt->opLimit;
  724. xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
  725. return(-1);
  726. }
  727. xpctxt->opCount += opCount;
  728. return(0);
  729. }
  730. #define OP_LIMIT_EXCEEDED(ctxt, n) \
  731. ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
  732. /************************************************************************
  733. * *
  734. * Utilities *
  735. * *
  736. ************************************************************************/
  737. /**
  738. * xsltPointerList:
  739. *
  740. * Pointer-list for various purposes.
  741. */
  742. typedef struct _xmlPointerList xmlPointerList;
  743. typedef xmlPointerList *xmlPointerListPtr;
  744. struct _xmlPointerList {
  745. void **items;
  746. int number;
  747. int size;
  748. };
  749. /*
  750. * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
  751. * and here, we should make the functions public.
  752. */
  753. static int
  754. xmlPointerListAddSize(xmlPointerListPtr list,
  755. void *item,
  756. int initialSize)
  757. {
  758. if (list->items == NULL) {
  759. if (initialSize <= 0)
  760. initialSize = 1;
  761. list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
  762. if (list->items == NULL) {
  763. xmlXPathErrMemory(NULL,
  764. "xmlPointerListCreate: allocating item\n");
  765. return(-1);
  766. }
  767. list->number = 0;
  768. list->size = initialSize;
  769. } else if (list->size <= list->number) {
  770. if (list->size > 50000000) {
  771. xmlXPathErrMemory(NULL,
  772. "xmlPointerListAddSize: re-allocating item\n");
  773. return(-1);
  774. }
  775. list->size *= 2;
  776. list->items = (void **) xmlRealloc(list->items,
  777. list->size * sizeof(void *));
  778. if (list->items == NULL) {
  779. xmlXPathErrMemory(NULL,
  780. "xmlPointerListAddSize: re-allocating item\n");
  781. list->size = 0;
  782. return(-1);
  783. }
  784. }
  785. list->items[list->number++] = item;
  786. return(0);
  787. }
  788. /**
  789. * xsltPointerListCreate:
  790. *
  791. * Creates an xsltPointerList structure.
  792. *
  793. * Returns a xsltPointerList structure or NULL in case of an error.
  794. */
  795. static xmlPointerListPtr
  796. xmlPointerListCreate(int initialSize)
  797. {
  798. xmlPointerListPtr ret;
  799. ret = xmlMalloc(sizeof(xmlPointerList));
  800. if (ret == NULL) {
  801. xmlXPathErrMemory(NULL,
  802. "xmlPointerListCreate: allocating item\n");
  803. return (NULL);
  804. }
  805. memset(ret, 0, sizeof(xmlPointerList));
  806. if (initialSize > 0) {
  807. xmlPointerListAddSize(ret, NULL, initialSize);
  808. ret->number = 0;
  809. }
  810. return (ret);
  811. }
  812. /**
  813. * xsltPointerListFree:
  814. *
  815. * Frees the xsltPointerList structure. This does not free
  816. * the content of the list.
  817. */
  818. static void
  819. xmlPointerListFree(xmlPointerListPtr list)
  820. {
  821. if (list == NULL)
  822. return;
  823. if (list->items != NULL)
  824. xmlFree(list->items);
  825. xmlFree(list);
  826. }
  827. /************************************************************************
  828. * *
  829. * Parser Types *
  830. * *
  831. ************************************************************************/
  832. /*
  833. * Types are private:
  834. */
  835. typedef enum {
  836. XPATH_OP_END=0,
  837. XPATH_OP_AND,
  838. XPATH_OP_OR,
  839. XPATH_OP_EQUAL,
  840. XPATH_OP_CMP,
  841. XPATH_OP_PLUS,
  842. XPATH_OP_MULT,
  843. XPATH_OP_UNION,
  844. XPATH_OP_ROOT,
  845. XPATH_OP_NODE,
  846. XPATH_OP_COLLECT,
  847. XPATH_OP_VALUE, /* 11 */
  848. XPATH_OP_VARIABLE,
  849. XPATH_OP_FUNCTION,
  850. XPATH_OP_ARG,
  851. XPATH_OP_PREDICATE,
  852. XPATH_OP_FILTER, /* 16 */
  853. XPATH_OP_SORT /* 17 */
  854. #ifdef LIBXML_XPTR_ENABLED
  855. ,XPATH_OP_RANGETO
  856. #endif
  857. } xmlXPathOp;
  858. typedef enum {
  859. AXIS_ANCESTOR = 1,
  860. AXIS_ANCESTOR_OR_SELF,
  861. AXIS_ATTRIBUTE,
  862. AXIS_CHILD,
  863. AXIS_DESCENDANT,
  864. AXIS_DESCENDANT_OR_SELF,
  865. AXIS_FOLLOWING,
  866. AXIS_FOLLOWING_SIBLING,
  867. AXIS_NAMESPACE,
  868. AXIS_PARENT,
  869. AXIS_PRECEDING,
  870. AXIS_PRECEDING_SIBLING,
  871. AXIS_SELF
  872. } xmlXPathAxisVal;
  873. typedef enum {
  874. NODE_TEST_NONE = 0,
  875. NODE_TEST_TYPE = 1,
  876. NODE_TEST_PI = 2,
  877. NODE_TEST_ALL = 3,
  878. NODE_TEST_NS = 4,
  879. NODE_TEST_NAME = 5
  880. } xmlXPathTestVal;
  881. typedef enum {
  882. NODE_TYPE_NODE = 0,
  883. NODE_TYPE_COMMENT = XML_COMMENT_NODE,
  884. NODE_TYPE_TEXT = XML_TEXT_NODE,
  885. NODE_TYPE_PI = XML_PI_NODE
  886. } xmlXPathTypeVal;
  887. typedef struct _xmlXPathStepOp xmlXPathStepOp;
  888. typedef xmlXPathStepOp *xmlXPathStepOpPtr;
  889. struct _xmlXPathStepOp {
  890. xmlXPathOp op; /* The identifier of the operation */
  891. int ch1; /* First child */
  892. int ch2; /* Second child */
  893. int value;
  894. int value2;
  895. int value3;
  896. void *value4;
  897. void *value5;
  898. xmlXPathFunction cache;
  899. void *cacheURI;
  900. };
  901. struct _xmlXPathCompExpr {
  902. int nbStep; /* Number of steps in this expression */
  903. int maxStep; /* Maximum number of steps allocated */
  904. xmlXPathStepOp *steps; /* ops for computation of this expression */
  905. int last; /* index of last step in expression */
  906. xmlChar *expr; /* the expression being computed */
  907. xmlDictPtr dict; /* the dictionary to use if any */
  908. #ifdef DEBUG_EVAL_COUNTS
  909. int nb;
  910. xmlChar *string;
  911. #endif
  912. #ifdef XPATH_STREAMING
  913. xmlPatternPtr stream;
  914. #endif
  915. };
  916. /************************************************************************
  917. * *
  918. * Forward declarations *
  919. * *
  920. ************************************************************************/
  921. static void
  922. xmlXPathFreeValueTree(xmlNodeSetPtr obj);
  923. static void
  924. xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
  925. static int
  926. xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
  927. xmlXPathStepOpPtr op, xmlNodePtr *first);
  928. static int
  929. xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
  930. xmlXPathStepOpPtr op,
  931. int isPredicate);
  932. static void
  933. xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
  934. /************************************************************************
  935. * *
  936. * Parser Type functions *
  937. * *
  938. ************************************************************************/
  939. /**
  940. * xmlXPathNewCompExpr:
  941. *
  942. * Create a new Xpath component
  943. *
  944. * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
  945. */
  946. static xmlXPathCompExprPtr
  947. xmlXPathNewCompExpr(void) {
  948. xmlXPathCompExprPtr cur;
  949. cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
  950. if (cur == NULL) {
  951. xmlXPathErrMemory(NULL, "allocating component\n");
  952. return(NULL);
  953. }
  954. memset(cur, 0, sizeof(xmlXPathCompExpr));
  955. cur->maxStep = 10;
  956. cur->nbStep = 0;
  957. cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
  958. sizeof(xmlXPathStepOp));
  959. if (cur->steps == NULL) {
  960. xmlXPathErrMemory(NULL, "allocating steps\n");
  961. xmlFree(cur);
  962. return(NULL);
  963. }
  964. memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
  965. cur->last = -1;
  966. #ifdef DEBUG_EVAL_COUNTS
  967. cur->nb = 0;
  968. #endif
  969. return(cur);
  970. }
  971. /**
  972. * xmlXPathFreeCompExpr:
  973. * @comp: an XPATH comp
  974. *
  975. * Free up the memory allocated by @comp
  976. */
  977. void
  978. xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
  979. {
  980. xmlXPathStepOpPtr op;
  981. int i;
  982. if (comp == NULL)
  983. return;
  984. if (comp->dict == NULL) {
  985. for (i = 0; i < comp->nbStep; i++) {
  986. op = &comp->steps[i];
  987. if (op->value4 != NULL) {
  988. if (op->op == XPATH_OP_VALUE)
  989. xmlXPathFreeObject(op->value4);
  990. else
  991. xmlFree(op->value4);
  992. }
  993. if (op->value5 != NULL)
  994. xmlFree(op->value5);
  995. }
  996. } else {
  997. for (i = 0; i < comp->nbStep; i++) {
  998. op = &comp->steps[i];
  999. if (op->value4 != NULL) {
  1000. if (op->op == XPATH_OP_VALUE)
  1001. xmlXPathFreeObject(op->value4);
  1002. }
  1003. }
  1004. xmlDictFree(comp->dict);
  1005. }
  1006. if (comp->steps != NULL) {
  1007. xmlFree(comp->steps);
  1008. }
  1009. #ifdef DEBUG_EVAL_COUNTS
  1010. if (comp->string != NULL) {
  1011. xmlFree(comp->string);
  1012. }
  1013. #endif
  1014. #ifdef XPATH_STREAMING
  1015. if (comp->stream != NULL) {
  1016. xmlFreePatternList(comp->stream);
  1017. }
  1018. #endif
  1019. if (comp->expr != NULL) {
  1020. xmlFree(comp->expr);
  1021. }
  1022. xmlFree(comp);
  1023. }
  1024. /**
  1025. * xmlXPathCompExprAdd:
  1026. * @comp: the compiled expression
  1027. * @ch1: first child index
  1028. * @ch2: second child index
  1029. * @op: an op
  1030. * @value: the first int value
  1031. * @value2: the second int value
  1032. * @value3: the third int value
  1033. * @value4: the first string value
  1034. * @value5: the second string value
  1035. *
  1036. * Add a step to an XPath Compiled Expression
  1037. *
  1038. * Returns -1 in case of failure, the index otherwise
  1039. */
  1040. static int
  1041. xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
  1042. xmlXPathOp op, int value,
  1043. int value2, int value3, void *value4, void *value5) {
  1044. xmlXPathCompExprPtr comp = ctxt->comp;
  1045. if (comp->nbStep >= comp->maxStep) {
  1046. xmlXPathStepOp *real;
  1047. if (comp->maxStep >= XPATH_MAX_STEPS) {
  1048. xmlXPathPErrMemory(ctxt, "adding step\n");
  1049. return(-1);
  1050. }
  1051. comp->maxStep *= 2;
  1052. real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
  1053. comp->maxStep * sizeof(xmlXPathStepOp));
  1054. if (real == NULL) {
  1055. comp->maxStep /= 2;
  1056. xmlXPathPErrMemory(ctxt, "adding step\n");
  1057. return(-1);
  1058. }
  1059. comp->steps = real;
  1060. }
  1061. comp->last = comp->nbStep;
  1062. comp->steps[comp->nbStep].ch1 = ch1;
  1063. comp->steps[comp->nbStep].ch2 = ch2;
  1064. comp->steps[comp->nbStep].op = op;
  1065. comp->steps[comp->nbStep].value = value;
  1066. comp->steps[comp->nbStep].value2 = value2;
  1067. comp->steps[comp->nbStep].value3 = value3;
  1068. if ((comp->dict != NULL) &&
  1069. ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
  1070. (op == XPATH_OP_COLLECT))) {
  1071. if (value4 != NULL) {
  1072. comp->steps[comp->nbStep].value4 = (xmlChar *)
  1073. (void *)xmlDictLookup(comp->dict, value4, -1);
  1074. xmlFree(value4);
  1075. } else
  1076. comp->steps[comp->nbStep].value4 = NULL;
  1077. if (value5 != NULL) {
  1078. comp->steps[comp->nbStep].value5 = (xmlChar *)
  1079. (void *)xmlDictLookup(comp->dict, value5, -1);
  1080. xmlFree(value5);
  1081. } else
  1082. comp->steps[comp->nbStep].value5 = NULL;
  1083. } else {
  1084. comp->steps[comp->nbStep].value4 = value4;
  1085. comp->steps[comp->nbStep].value5 = value5;
  1086. }
  1087. comp->steps[comp->nbStep].cache = NULL;
  1088. return(comp->nbStep++);
  1089. }
  1090. /**
  1091. * xmlXPathCompSwap:
  1092. * @comp: the compiled expression
  1093. * @op: operation index
  1094. *
  1095. * Swaps 2 operations in the compiled expression
  1096. */
  1097. static void
  1098. xmlXPathCompSwap(xmlXPathStepOpPtr op) {
  1099. int tmp;
  1100. #ifndef LIBXML_THREAD_ENABLED
  1101. /*
  1102. * Since this manipulates possibly shared variables, this is
  1103. * disabled if one detects that the library is used in a multithreaded
  1104. * application
  1105. */
  1106. if (xmlXPathDisableOptimizer)
  1107. return;
  1108. #endif
  1109. tmp = op->ch1;
  1110. op->ch1 = op->ch2;
  1111. op->ch2 = tmp;
  1112. }
  1113. #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
  1114. xmlXPathCompExprAdd(ctxt, (op1), (op2), \
  1115. (op), (val), (val2), (val3), (val4), (val5))
  1116. #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
  1117. xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \
  1118. (op), (val), (val2), (val3), (val4), (val5))
  1119. #define PUSH_LEAVE_EXPR(op, val, val2) \
  1120. xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
  1121. #define PUSH_UNARY_EXPR(op, ch, val, val2) \
  1122. xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
  1123. #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
  1124. xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \
  1125. (val), (val2), 0 ,NULL ,NULL)
  1126. /************************************************************************
  1127. * *
  1128. * XPath object cache structures *
  1129. * *
  1130. ************************************************************************/
  1131. /* #define XP_DEFAULT_CACHE_ON */
  1132. #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
  1133. typedef struct _xmlXPathContextCache xmlXPathContextCache;
  1134. typedef xmlXPathContextCache *xmlXPathContextCachePtr;
  1135. struct _xmlXPathContextCache {
  1136. xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
  1137. xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
  1138. xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
  1139. xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
  1140. xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
  1141. int maxNodeset;
  1142. int maxString;
  1143. int maxBoolean;
  1144. int maxNumber;
  1145. int maxMisc;
  1146. #ifdef XP_DEBUG_OBJ_USAGE
  1147. int dbgCachedAll;
  1148. int dbgCachedNodeset;
  1149. int dbgCachedString;
  1150. int dbgCachedBool;
  1151. int dbgCachedNumber;
  1152. int dbgCachedPoint;
  1153. int dbgCachedRange;
  1154. int dbgCachedLocset;
  1155. int dbgCachedUsers;
  1156. int dbgCachedXSLTTree;
  1157. int dbgCachedUndefined;
  1158. int dbgReusedAll;
  1159. int dbgReusedNodeset;
  1160. int dbgReusedString;
  1161. int dbgReusedBool;
  1162. int dbgReusedNumber;
  1163. int dbgReusedPoint;
  1164. int dbgReusedRange;
  1165. int dbgReusedLocset;
  1166. int dbgReusedUsers;
  1167. int dbgReusedXSLTTree;
  1168. int dbgReusedUndefined;
  1169. #endif
  1170. };
  1171. /************************************************************************
  1172. * *
  1173. * Debugging related functions *
  1174. * *
  1175. ************************************************************************/
  1176. #define STRANGE \
  1177. xmlGenericError(xmlGenericErrorContext, \
  1178. "Internal error at %s:%d\n", \
  1179. __FILE__, __LINE__);
  1180. #ifdef LIBXML_DEBUG_ENABLED
  1181. static void
  1182. xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
  1183. int i;
  1184. char shift[100];
  1185. for (i = 0;((i < depth) && (i < 25));i++)
  1186. shift[2 * i] = shift[2 * i + 1] = ' ';
  1187. shift[2 * i] = shift[2 * i + 1] = 0;
  1188. if (cur == NULL) {
  1189. fprintf(output, "%s", shift);
  1190. fprintf(output, "Node is NULL !\n");
  1191. return;
  1192. }
  1193. if ((cur->type == XML_DOCUMENT_NODE) ||
  1194. (cur->type == XML_HTML_DOCUMENT_NODE)) {
  1195. fprintf(output, "%s", shift);
  1196. fprintf(output, " /\n");
  1197. } else if (cur->type == XML_ATTRIBUTE_NODE)
  1198. xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
  1199. else
  1200. xmlDebugDumpOneNode(output, cur, depth);
  1201. }
  1202. static void
  1203. xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
  1204. xmlNodePtr tmp;
  1205. int i;
  1206. char shift[100];
  1207. for (i = 0;((i < depth) && (i < 25));i++)
  1208. shift[2 * i] = shift[2 * i + 1] = ' ';
  1209. shift[2 * i] = shift[2 * i + 1] = 0;
  1210. if (cur == NULL) {
  1211. fprintf(output, "%s", shift);
  1212. fprintf(output, "Node is NULL !\n");
  1213. return;
  1214. }
  1215. while (cur != NULL) {
  1216. tmp = cur;
  1217. cur = cur->next;
  1218. xmlDebugDumpOneNode(output, tmp, depth);
  1219. }
  1220. }
  1221. static void
  1222. xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
  1223. int i;
  1224. char shift[100];
  1225. for (i = 0;((i < depth) && (i < 25));i++)
  1226. shift[2 * i] = shift[2 * i + 1] = ' ';
  1227. shift[2 * i] = shift[2 * i + 1] = 0;
  1228. if (cur == NULL) {
  1229. fprintf(output, "%s", shift);
  1230. fprintf(output, "NodeSet is NULL !\n");
  1231. return;
  1232. }
  1233. if (cur != NULL) {
  1234. fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
  1235. for (i = 0;i < cur->nodeNr;i++) {
  1236. fprintf(output, "%s", shift);
  1237. fprintf(output, "%d", i + 1);
  1238. xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
  1239. }
  1240. }
  1241. }
  1242. static void
  1243. xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
  1244. int i;
  1245. char shift[100];
  1246. for (i = 0;((i < depth) && (i < 25));i++)
  1247. shift[2 * i] = shift[2 * i + 1] = ' ';
  1248. shift[2 * i] = shift[2 * i + 1] = 0;
  1249. if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
  1250. fprintf(output, "%s", shift);
  1251. fprintf(output, "Value Tree is NULL !\n");
  1252. return;
  1253. }
  1254. fprintf(output, "%s", shift);
  1255. fprintf(output, "%d", i + 1);
  1256. xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
  1257. }
  1258. #if defined(LIBXML_XPTR_ENABLED)
  1259. static void
  1260. xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
  1261. int i;
  1262. char shift[100];
  1263. for (i = 0;((i < depth) && (i < 25));i++)
  1264. shift[2 * i] = shift[2 * i + 1] = ' ';
  1265. shift[2 * i] = shift[2 * i + 1] = 0;
  1266. if (cur == NULL) {
  1267. fprintf(output, "%s", shift);
  1268. fprintf(output, "LocationSet is NULL !\n");
  1269. return;
  1270. }
  1271. for (i = 0;i < cur->locNr;i++) {
  1272. fprintf(output, "%s", shift);
  1273. fprintf(output, "%d : ", i + 1);
  1274. xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
  1275. }
  1276. }
  1277. #endif /* LIBXML_XPTR_ENABLED */
  1278. /**
  1279. * xmlXPathDebugDumpObject:
  1280. * @output: the FILE * to dump the output
  1281. * @cur: the object to inspect
  1282. * @depth: indentation level
  1283. *
  1284. * Dump the content of the object for debugging purposes
  1285. */
  1286. void
  1287. xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
  1288. int i;
  1289. char shift[100];
  1290. if (output == NULL) return;
  1291. for (i = 0;((i < depth) && (i < 25));i++)
  1292. shift[2 * i] = shift[2 * i + 1] = ' ';
  1293. shift[2 * i] = shift[2 * i + 1] = 0;
  1294. fprintf(output, "%s", shift);
  1295. if (cur == NULL) {
  1296. fprintf(output, "Object is empty (NULL)\n");
  1297. return;
  1298. }
  1299. switch(cur->type) {
  1300. case XPATH_UNDEFINED:
  1301. fprintf(output, "Object is uninitialized\n");
  1302. break;
  1303. case XPATH_NODESET:
  1304. fprintf(output, "Object is a Node Set :\n");
  1305. xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
  1306. break;
  1307. case XPATH_XSLT_TREE:
  1308. fprintf(output, "Object is an XSLT value tree :\n");
  1309. xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
  1310. break;
  1311. case XPATH_BOOLEAN:
  1312. fprintf(output, "Object is a Boolean : ");
  1313. if (cur->boolval) fprintf(output, "true\n");
  1314. else fprintf(output, "false\n");
  1315. break;
  1316. case XPATH_NUMBER:
  1317. switch (xmlXPathIsInf(cur->floatval)) {
  1318. case 1:
  1319. fprintf(output, "Object is a number : Infinity\n");
  1320. break;
  1321. case -1:
  1322. fprintf(output, "Object is a number : -Infinity\n");
  1323. break;
  1324. default:
  1325. if (xmlXPathIsNaN(cur->floatval)) {
  1326. fprintf(output, "Object is a number : NaN\n");
  1327. } else if (cur->floatval == 0) {
  1328. /* Omit sign for negative zero. */
  1329. fprintf(output, "Object is a number : 0\n");
  1330. } else {
  1331. fprintf(output, "Object is a number : %0g\n", cur->floatval);
  1332. }
  1333. }
  1334. break;
  1335. case XPATH_STRING:
  1336. fprintf(output, "Object is a string : ");
  1337. xmlDebugDumpString(output, cur->stringval);
  1338. fprintf(output, "\n");
  1339. break;
  1340. case XPATH_POINT:
  1341. fprintf(output, "Object is a point : index %d in node", cur->index);
  1342. xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
  1343. fprintf(output, "\n");
  1344. break;
  1345. case XPATH_RANGE:
  1346. if ((cur->user2 == NULL) ||
  1347. ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
  1348. fprintf(output, "Object is a collapsed range :\n");
  1349. fprintf(output, "%s", shift);
  1350. if (cur->index >= 0)
  1351. fprintf(output, "index %d in ", cur->index);
  1352. fprintf(output, "node\n");
  1353. xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
  1354. depth + 1);
  1355. } else {
  1356. fprintf(output, "Object is a range :\n");
  1357. fprintf(output, "%s", shift);
  1358. fprintf(output, "From ");
  1359. if (cur->index >= 0)
  1360. fprintf(output, "index %d in ", cur->index);
  1361. fprintf(output, "node\n");
  1362. xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
  1363. depth + 1);
  1364. fprintf(output, "%s", shift);
  1365. fprintf(output, "To ");
  1366. if (cur->index2 >= 0)
  1367. fprintf(output, "index %d in ", cur->index2);
  1368. fprintf(output, "node\n");
  1369. xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
  1370. depth + 1);
  1371. fprintf(output, "\n");
  1372. }
  1373. break;
  1374. case XPATH_LOCATIONSET:
  1375. #if defined(LIBXML_XPTR_ENABLED)
  1376. fprintf(output, "Object is a Location Set:\n");
  1377. xmlXPathDebugDumpLocationSet(output,
  1378. (xmlLocationSetPtr) cur->user, depth);
  1379. #endif
  1380. break;
  1381. case XPATH_USERS:
  1382. fprintf(output, "Object is user defined\n");
  1383. break;
  1384. }
  1385. }
  1386. static void
  1387. xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
  1388. xmlXPathStepOpPtr op, int depth) {
  1389. int i;
  1390. char shift[100];
  1391. for (i = 0;((i < depth) && (i < 25));i++)
  1392. shift[2 * i] = shift[2 * i + 1] = ' ';
  1393. shift[2 * i] = shift[2 * i + 1] = 0;
  1394. fprintf(output, "%s", shift);
  1395. if (op == NULL) {
  1396. fprintf(output, "Step is NULL\n");
  1397. return;
  1398. }
  1399. switch (op->op) {
  1400. case XPATH_OP_END:
  1401. fprintf(output, "END"); break;
  1402. case XPATH_OP_AND:
  1403. fprintf(output, "AND"); break;
  1404. case XPATH_OP_OR:
  1405. fprintf(output, "OR"); break;
  1406. case XPATH_OP_EQUAL:
  1407. if (op->value)
  1408. fprintf(output, "EQUAL =");
  1409. else
  1410. fprintf(output, "EQUAL !=");
  1411. break;
  1412. case XPATH_OP_CMP:
  1413. if (op->value)
  1414. fprintf(output, "CMP <");
  1415. else
  1416. fprintf(output, "CMP >");
  1417. if (!op->value2)
  1418. fprintf(output, "=");
  1419. break;
  1420. case XPATH_OP_PLUS:
  1421. if (op->value == 0)
  1422. fprintf(output, "PLUS -");
  1423. else if (op->value == 1)
  1424. fprintf(output, "PLUS +");
  1425. else if (op->value == 2)
  1426. fprintf(output, "PLUS unary -");
  1427. else if (op->value == 3)
  1428. fprintf(output, "PLUS unary - -");
  1429. break;
  1430. case XPATH_OP_MULT:
  1431. if (op->value == 0)
  1432. fprintf(output, "MULT *");
  1433. else if (op->value == 1)
  1434. fprintf(output, "MULT div");
  1435. else
  1436. fprintf(output, "MULT mod");
  1437. break;
  1438. case XPATH_OP_UNION:
  1439. fprintf(output, "UNION"); break;
  1440. case XPATH_OP_ROOT:
  1441. fprintf(output, "ROOT"); break;
  1442. case XPATH_OP_NODE:
  1443. fprintf(output, "NODE"); break;
  1444. case XPATH_OP_SORT:
  1445. fprintf(output, "SORT"); break;
  1446. case XPATH_OP_COLLECT: {
  1447. xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
  1448. xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
  1449. xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
  1450. const xmlChar *prefix = op->value4;
  1451. const xmlChar *name = op->value5;
  1452. fprintf(output, "COLLECT ");
  1453. switch (axis) {
  1454. case AXIS_ANCESTOR:
  1455. fprintf(output, " 'ancestors' "); break;
  1456. case AXIS_ANCESTOR_OR_SELF:
  1457. fprintf(output, " 'ancestors-or-self' "); break;
  1458. case AXIS_ATTRIBUTE:
  1459. fprintf(output, " 'attributes' "); break;
  1460. case AXIS_CHILD:
  1461. fprintf(output, " 'child' "); break;
  1462. case AXIS_DESCENDANT:
  1463. fprintf(output, " 'descendant' "); break;
  1464. case AXIS_DESCENDANT_OR_SELF:
  1465. fprintf(output, " 'descendant-or-self' "); break;
  1466. case AXIS_FOLLOWING:
  1467. fprintf(output, " 'following' "); break;
  1468. case AXIS_FOLLOWING_SIBLING:
  1469. fprintf(output, " 'following-siblings' "); break;
  1470. case AXIS_NAMESPACE:
  1471. fprintf(output, " 'namespace' "); break;
  1472. case AXIS_PARENT:
  1473. fprintf(output, " 'parent' "); break;
  1474. case AXIS_PRECEDING:
  1475. fprintf(output, " 'preceding' "); break;
  1476. case AXIS_PRECEDING_SIBLING:
  1477. fprintf(output, " 'preceding-sibling' "); break;
  1478. case AXIS_SELF:
  1479. fprintf(output, " 'self' "); break;
  1480. }
  1481. switch (test) {
  1482. case NODE_TEST_NONE:
  1483. fprintf(output, "'none' "); break;
  1484. case NODE_TEST_TYPE:
  1485. fprintf(output, "'type' "); break;
  1486. case NODE_TEST_PI:
  1487. fprintf(output, "'PI' "); break;
  1488. case NODE_TEST_ALL:
  1489. fprintf(output, "'all' "); break;
  1490. case NODE_TEST_NS:
  1491. fprintf(output, "'namespace' "); break;
  1492. case NODE_TEST_NAME:
  1493. fprintf(output, "'name' "); break;
  1494. }
  1495. switch (type) {
  1496. case NODE_TYPE_NODE:
  1497. fprintf(output, "'node' "); break;
  1498. case NODE_TYPE_COMMENT:
  1499. fprintf(output, "'comment' "); break;
  1500. case NODE_TYPE_TEXT:
  1501. fprintf(output, "'text' "); break;
  1502. case NODE_TYPE_PI:
  1503. fprintf(output, "'PI' "); break;
  1504. }
  1505. if (prefix != NULL)
  1506. fprintf(output, "%s:", prefix);
  1507. if (name != NULL)
  1508. fprintf(output, "%s", (const char *) name);
  1509. break;
  1510. }
  1511. case XPATH_OP_VALUE: {
  1512. xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
  1513. fprintf(output, "ELEM ");
  1514. xmlXPathDebugDumpObject(output, object, 0);
  1515. goto finish;
  1516. }
  1517. case XPATH_OP_VARIABLE: {
  1518. const xmlChar *prefix = op->value5;
  1519. const xmlChar *name = op->value4;
  1520. if (prefix != NULL)
  1521. fprintf(output, "VARIABLE %s:%s", prefix, name);
  1522. else
  1523. fprintf(output, "VARIABLE %s", name);
  1524. break;
  1525. }
  1526. case XPATH_OP_FUNCTION: {
  1527. int nbargs = op->value;
  1528. const xmlChar *prefix = op->value5;
  1529. const xmlChar *name = op->value4;
  1530. if (prefix != NULL)
  1531. fprintf(output, "FUNCTION %s:%s(%d args)",
  1532. prefix, name, nbargs);
  1533. else
  1534. fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
  1535. break;
  1536. }
  1537. case XPATH_OP_ARG: fprintf(output, "ARG"); break;
  1538. case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
  1539. case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
  1540. #ifdef LIBXML_XPTR_ENABLED
  1541. case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
  1542. #endif
  1543. default:
  1544. fprintf(output, "UNKNOWN %d\n", op->op); return;
  1545. }
  1546. fprintf(output, "\n");
  1547. finish:
  1548. if (op->ch1 >= 0)
  1549. xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
  1550. if (op->ch2 >= 0)
  1551. xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
  1552. }
  1553. /**
  1554. * xmlXPathDebugDumpCompExpr:
  1555. * @output: the FILE * for the output
  1556. * @comp: the precompiled XPath expression
  1557. * @depth: the indentation level.
  1558. *
  1559. * Dumps the tree of the compiled XPath expression.
  1560. */
  1561. void
  1562. xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
  1563. int depth) {
  1564. int i;
  1565. char shift[100];
  1566. if ((output == NULL) || (comp == NULL)) return;
  1567. for (i = 0;((i < depth) && (i < 25));i++)
  1568. shift[2 * i] = shift[2 * i + 1] = ' ';
  1569. shift[2 * i] = shift[2 * i + 1] = 0;
  1570. fprintf(output, "%s", shift);
  1571. #ifdef XPATH_STREAMING
  1572. if (comp->stream) {
  1573. fprintf(output, "Streaming Expression\n");
  1574. } else
  1575. #endif
  1576. {
  1577. fprintf(output, "Compiled Expression : %d elements\n",
  1578. comp->nbStep);
  1579. i = comp->last;
  1580. xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
  1581. }
  1582. }
  1583. #ifdef XP_DEBUG_OBJ_USAGE
  1584. /*
  1585. * XPath object usage related debugging variables.
  1586. */
  1587. static int xmlXPathDebugObjCounterUndefined = 0;
  1588. static int xmlXPathDebugObjCounterNodeset = 0;
  1589. static int xmlXPathDebugObjCounterBool = 0;
  1590. static int xmlXPathDebugObjCounterNumber = 0;
  1591. static int xmlXPathDebugObjCounterString = 0;
  1592. static int xmlXPathDebugObjCounterPoint = 0;
  1593. static int xmlXPathDebugObjCounterRange = 0;
  1594. static int xmlXPathDebugObjCounterLocset = 0;
  1595. static int xmlXPathDebugObjCounterUsers = 0;
  1596. static int xmlXPathDebugObjCounterXSLTTree = 0;
  1597. static int xmlXPathDebugObjCounterAll = 0;
  1598. static int xmlXPathDebugObjTotalUndefined = 0;
  1599. static int xmlXPathDebugObjTotalNodeset = 0;
  1600. static int xmlXPathDebugObjTotalBool = 0;
  1601. static int xmlXPathDebugObjTotalNumber = 0;
  1602. static int xmlXPathDebugObjTotalString = 0;
  1603. static int xmlXPathDebugObjTotalPoint = 0;
  1604. static int xmlXPathDebugObjTotalRange = 0;
  1605. static int xmlXPathDebugObjTotalLocset = 0;
  1606. static int xmlXPathDebugObjTotalUsers = 0;
  1607. static int xmlXPathDebugObjTotalXSLTTree = 0;
  1608. static int xmlXPathDebugObjTotalAll = 0;
  1609. static int xmlXPathDebugObjMaxUndefined = 0;
  1610. static int xmlXPathDebugObjMaxNodeset = 0;
  1611. static int xmlXPathDebugObjMaxBool = 0;
  1612. static int xmlXPathDebugObjMaxNumber = 0;
  1613. static int xmlXPathDebugObjMaxString = 0;
  1614. static int xmlXPathDebugObjMaxPoint = 0;
  1615. static int xmlXPathDebugObjMaxRange = 0;
  1616. static int xmlXPathDebugObjMaxLocset = 0;
  1617. static int xmlXPathDebugObjMaxUsers = 0;
  1618. static int xmlXPathDebugObjMaxXSLTTree = 0;
  1619. static int xmlXPathDebugObjMaxAll = 0;
  1620. static void
  1621. xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
  1622. {
  1623. if (ctxt != NULL) {
  1624. if (ctxt->cache != NULL) {
  1625. xmlXPathContextCachePtr cache =
  1626. (xmlXPathContextCachePtr) ctxt->cache;
  1627. cache->dbgCachedAll = 0;
  1628. cache->dbgCachedNodeset = 0;
  1629. cache->dbgCachedString = 0;
  1630. cache->dbgCachedBool = 0;
  1631. cache->dbgCachedNumber = 0;
  1632. cache->dbgCachedPoint = 0;
  1633. cache->dbgCachedRange = 0;
  1634. cache->dbgCachedLocset = 0;
  1635. cache->dbgCachedUsers = 0;
  1636. cache->dbgCachedXSLTTree = 0;
  1637. cache->dbgCachedUndefined = 0;
  1638. cache->dbgReusedAll = 0;
  1639. cache->dbgReusedNodeset = 0;
  1640. cache->dbgReusedString = 0;
  1641. cache->dbgReusedBool = 0;
  1642. cache->dbgReusedNumber = 0;
  1643. cache->dbgReusedPoint = 0;
  1644. cache->dbgReusedRange = 0;
  1645. cache->dbgReusedLocset = 0;
  1646. cache->dbgReusedUsers = 0;
  1647. cache->dbgReusedXSLTTree = 0;
  1648. cache->dbgReusedUndefined = 0;
  1649. }
  1650. }
  1651. xmlXPathDebugObjCounterUndefined = 0;
  1652. xmlXPathDebugObjCounterNodeset = 0;
  1653. xmlXPathDebugObjCounterBool = 0;
  1654. xmlXPathDebugObjCounterNumber = 0;
  1655. xmlXPathDebugObjCounterString = 0;
  1656. xmlXPathDebugObjCounterPoint = 0;
  1657. xmlXPathDebugObjCounterRange = 0;
  1658. xmlXPathDebugObjCounterLocset = 0;
  1659. xmlXPathDebugObjCounterUsers = 0;
  1660. xmlXPathDebugObjCounterXSLTTree = 0;
  1661. xmlXPathDebugObjCounterAll = 0;
  1662. xmlXPathDebugObjTotalUndefined = 0;
  1663. xmlXPathDebugObjTotalNodeset = 0;
  1664. xmlXPathDebugObjTotalBool = 0;
  1665. xmlXPathDebugObjTotalNumber = 0;
  1666. xmlXPathDebugObjTotalString = 0;
  1667. xmlXPathDebugObjTotalPoint = 0;
  1668. xmlXPathDebugObjTotalRange = 0;
  1669. xmlXPathDebugObjTotalLocset = 0;
  1670. xmlXPathDebugObjTotalUsers = 0;
  1671. xmlXPathDebugObjTotalXSLTTree = 0;
  1672. xmlXPathDebugObjTotalAll = 0;
  1673. xmlXPathDebugObjMaxUndefined = 0;
  1674. xmlXPathDebugObjMaxNodeset = 0;
  1675. xmlXPathDebugObjMaxBool = 0;
  1676. xmlXPathDebugObjMaxNumber = 0;
  1677. xmlXPathDebugObjMaxString = 0;
  1678. xmlXPathDebugObjMaxPoint = 0;
  1679. xmlXPathDebugObjMaxRange = 0;
  1680. xmlXPathDebugObjMaxLocset = 0;
  1681. xmlXPathDebugObjMaxUsers = 0;
  1682. xmlXPathDebugObjMaxXSLTTree = 0;
  1683. xmlXPathDebugObjMaxAll = 0;
  1684. }
  1685. static void
  1686. xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
  1687. xmlXPathObjectType objType)
  1688. {
  1689. int isCached = 0;
  1690. if (ctxt != NULL) {
  1691. if (ctxt->cache != NULL) {
  1692. xmlXPathContextCachePtr cache =
  1693. (xmlXPathContextCachePtr) ctxt->cache;
  1694. isCached = 1;
  1695. cache->dbgReusedAll++;
  1696. switch (objType) {
  1697. case XPATH_UNDEFINED:
  1698. cache->dbgReusedUndefined++;
  1699. break;
  1700. case XPATH_NODESET:
  1701. cache->dbgReusedNodeset++;
  1702. break;
  1703. case XPATH_BOOLEAN:
  1704. cache->dbgReusedBool++;
  1705. break;
  1706. case XPATH_NUMBER:
  1707. cache->dbgReusedNumber++;
  1708. break;
  1709. case XPATH_STRING:
  1710. cache->dbgReusedString++;
  1711. break;
  1712. case XPATH_POINT:
  1713. cache->dbgReusedPoint++;
  1714. break;
  1715. case XPATH_RANGE:
  1716. cache->dbgReusedRange++;
  1717. break;
  1718. case XPATH_LOCATIONSET:
  1719. cache->dbgReusedLocset++;
  1720. break;
  1721. case XPATH_USERS:
  1722. cache->dbgReusedUsers++;
  1723. break;
  1724. case XPATH_XSLT_TREE:
  1725. cache->dbgReusedXSLTTree++;
  1726. break;
  1727. default:
  1728. break;
  1729. }
  1730. }
  1731. }
  1732. switch (objType) {
  1733. case XPATH_UNDEFINED:
  1734. if (! isCached)
  1735. xmlXPathDebugObjTotalUndefined++;
  1736. xmlXPathDebugObjCounterUndefined++;
  1737. if (xmlXPathDebugObjCounterUndefined >
  1738. xmlXPathDebugObjMaxUndefined)
  1739. xmlXPathDebugObjMaxUndefined =
  1740. xmlXPathDebugObjCounterUndefined;
  1741. break;
  1742. case XPATH_NODESET:
  1743. if (! isCached)
  1744. xmlXPathDebugObjTotalNodeset++;
  1745. xmlXPathDebugObjCounterNodeset++;
  1746. if (xmlXPathDebugObjCounterNodeset >
  1747. xmlXPathDebugObjMaxNodeset)
  1748. xmlXPathDebugObjMaxNodeset =
  1749. xmlXPathDebugObjCounterNodeset;
  1750. break;
  1751. case XPATH_BOOLEAN:
  1752. if (! isCached)
  1753. xmlXPathDebugObjTotalBool++;
  1754. xmlXPathDebugObjCounterBool++;
  1755. if (xmlXPathDebugObjCounterBool >
  1756. xmlXPathDebugObjMaxBool)
  1757. xmlXPathDebugObjMaxBool =
  1758. xmlXPathDebugObjCounterBool;
  1759. break;
  1760. case XPATH_NUMBER:
  1761. if (! isCached)
  1762. xmlXPathDebugObjTotalNumber++;
  1763. xmlXPathDebugObjCounterNumber++;
  1764. if (xmlXPathDebugObjCounterNumber >
  1765. xmlXPathDebugObjMaxNumber)
  1766. xmlXPathDebugObjMaxNumber =
  1767. xmlXPathDebugObjCounterNumber;
  1768. break;
  1769. case XPATH_STRING:
  1770. if (! isCached)
  1771. xmlXPathDebugObjTotalString++;
  1772. xmlXPathDebugObjCounterString++;
  1773. if (xmlXPathDebugObjCounterString >
  1774. xmlXPathDebugObjMaxString)
  1775. xmlXPathDebugObjMaxString =
  1776. xmlXPathDebugObjCounterString;
  1777. break;
  1778. case XPATH_POINT:
  1779. if (! isCached)
  1780. xmlXPathDebugObjTotalPoint++;
  1781. xmlXPathDebugObjCounterPoint++;
  1782. if (xmlXPathDebugObjCounterPoint >
  1783. xmlXPathDebugObjMaxPoint)
  1784. xmlXPathDebugObjMaxPoint =
  1785. xmlXPathDebugObjCounterPoint;
  1786. break;
  1787. case XPATH_RANGE:
  1788. if (! isCached)
  1789. xmlXPathDebugObjTotalRange++;
  1790. xmlXPathDebugObjCounterRange++;
  1791. if (xmlXPathDebugObjCounterRange >
  1792. xmlXPathDebugObjMaxRange)
  1793. xmlXPathDebugObjMaxRange =
  1794. xmlXPathDebugObjCounterRange;
  1795. break;
  1796. case XPATH_LOCATIONSET:
  1797. if (! isCached)
  1798. xmlXPathDebugObjTotalLocset++;
  1799. xmlXPathDebugObjCounterLocset++;
  1800. if (xmlXPathDebugObjCounterLocset >
  1801. xmlXPathDebugObjMaxLocset)
  1802. xmlXPathDebugObjMaxLocset =
  1803. xmlXPathDebugObjCounterLocset;
  1804. break;
  1805. case XPATH_USERS:
  1806. if (! isCached)
  1807. xmlXPathDebugObjTotalUsers++;
  1808. xmlXPathDebugObjCounterUsers++;
  1809. if (xmlXPathDebugObjCounterUsers >
  1810. xmlXPathDebugObjMaxUsers)
  1811. xmlXPathDebugObjMaxUsers =
  1812. xmlXPathDebugObjCounterUsers;
  1813. break;
  1814. case XPATH_XSLT_TREE:
  1815. if (! isCached)
  1816. xmlXPathDebugObjTotalXSLTTree++;
  1817. xmlXPathDebugObjCounterXSLTTree++;
  1818. if (xmlXPathDebugObjCounterXSLTTree >
  1819. xmlXPathDebugObjMaxXSLTTree)
  1820. xmlXPathDebugObjMaxXSLTTree =
  1821. xmlXPathDebugObjCounterXSLTTree;
  1822. break;
  1823. default:
  1824. break;
  1825. }
  1826. if (! isCached)
  1827. xmlXPathDebugObjTotalAll++;
  1828. xmlXPathDebugObjCounterAll++;
  1829. if (xmlXPathDebugObjCounterAll >
  1830. xmlXPathDebugObjMaxAll)
  1831. xmlXPathDebugObjMaxAll =
  1832. xmlXPathDebugObjCounterAll;
  1833. }
  1834. static void
  1835. xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
  1836. xmlXPathObjectType objType)
  1837. {
  1838. int isCached = 0;
  1839. if (ctxt != NULL) {
  1840. if (ctxt->cache != NULL) {
  1841. xmlXPathContextCachePtr cache =
  1842. (xmlXPathContextCachePtr) ctxt->cache;
  1843. isCached = 1;
  1844. cache->dbgCachedAll++;
  1845. switch (objType) {
  1846. case XPATH_UNDEFINED:
  1847. cache->dbgCachedUndefined++;
  1848. break;
  1849. case XPATH_NODESET:
  1850. cache->dbgCachedNodeset++;
  1851. break;
  1852. case XPATH_BOOLEAN:
  1853. cache->dbgCachedBool++;
  1854. break;
  1855. case XPATH_NUMBER:
  1856. cache->dbgCachedNumber++;
  1857. break;
  1858. case XPATH_STRING:
  1859. cache->dbgCachedString++;
  1860. break;
  1861. case XPATH_POINT:
  1862. cache->dbgCachedPoint++;
  1863. break;
  1864. case XPATH_RANGE:
  1865. cache->dbgCachedRange++;
  1866. break;
  1867. case XPATH_LOCATIONSET:
  1868. cache->dbgCachedLocset++;
  1869. break;
  1870. case XPATH_USERS:
  1871. cache->dbgCachedUsers++;
  1872. break;
  1873. case XPATH_XSLT_TREE:
  1874. cache->dbgCachedXSLTTree++;
  1875. break;
  1876. default:
  1877. break;
  1878. }
  1879. }
  1880. }
  1881. switch (objType) {
  1882. case XPATH_UNDEFINED:
  1883. xmlXPathDebugObjCounterUndefined--;
  1884. break;
  1885. case XPATH_NODESET:
  1886. xmlXPathDebugObjCounterNodeset--;
  1887. break;
  1888. case XPATH_BOOLEAN:
  1889. xmlXPathDebugObjCounterBool--;
  1890. break;
  1891. case XPATH_NUMBER:
  1892. xmlXPathDebugObjCounterNumber--;
  1893. break;
  1894. case XPATH_STRING:
  1895. xmlXPathDebugObjCounterString--;
  1896. break;
  1897. case XPATH_POINT:
  1898. xmlXPathDebugObjCounterPoint--;
  1899. break;
  1900. case XPATH_RANGE:
  1901. xmlXPathDebugObjCounterRange--;
  1902. break;
  1903. case XPATH_LOCATIONSET:
  1904. xmlXPathDebugObjCounterLocset--;
  1905. break;
  1906. case XPATH_USERS:
  1907. xmlXPathDebugObjCounterUsers--;
  1908. break;
  1909. case XPATH_XSLT_TREE:
  1910. xmlXPathDebugObjCounterXSLTTree--;
  1911. break;
  1912. default:
  1913. break;
  1914. }
  1915. xmlXPathDebugObjCounterAll--;
  1916. }
  1917. static void
  1918. xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
  1919. {
  1920. int reqAll, reqNodeset, reqString, reqBool, reqNumber,
  1921. reqXSLTTree, reqUndefined;
  1922. int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
  1923. caNumber = 0, caXSLTTree = 0, caUndefined = 0;
  1924. int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
  1925. reNumber = 0, reXSLTTree = 0, reUndefined = 0;
  1926. int leftObjs = xmlXPathDebugObjCounterAll;
  1927. reqAll = xmlXPathDebugObjTotalAll;
  1928. reqNodeset = xmlXPathDebugObjTotalNodeset;
  1929. reqString = xmlXPathDebugObjTotalString;
  1930. reqBool = xmlXPathDebugObjTotalBool;
  1931. reqNumber = xmlXPathDebugObjTotalNumber;
  1932. reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
  1933. reqUndefined = xmlXPathDebugObjTotalUndefined;
  1934. printf("# XPath object usage:\n");
  1935. if (ctxt != NULL) {
  1936. if (ctxt->cache != NULL) {
  1937. xmlXPathContextCachePtr cache =
  1938. (xmlXPathContextCachePtr) ctxt->cache;
  1939. reAll = cache->dbgReusedAll;
  1940. reqAll += reAll;
  1941. reNodeset = cache->dbgReusedNodeset;
  1942. reqNodeset += reNodeset;
  1943. reString = cache->dbgReusedString;
  1944. reqString += reString;
  1945. reBool = cache->dbgReusedBool;
  1946. reqBool += reBool;
  1947. reNumber = cache->dbgReusedNumber;
  1948. reqNumber += reNumber;
  1949. reXSLTTree = cache->dbgReusedXSLTTree;
  1950. reqXSLTTree += reXSLTTree;
  1951. reUndefined = cache->dbgReusedUndefined;
  1952. reqUndefined += reUndefined;
  1953. caAll = cache->dbgCachedAll;
  1954. caBool = cache->dbgCachedBool;
  1955. caNodeset = cache->dbgCachedNodeset;
  1956. caString = cache->dbgCachedString;
  1957. caNumber = cache->dbgCachedNumber;
  1958. caXSLTTree = cache->dbgCachedXSLTTree;
  1959. caUndefined = cache->dbgCachedUndefined;
  1960. if (cache->nodesetObjs)
  1961. leftObjs -= cache->nodesetObjs->number;
  1962. if (cache->stringObjs)
  1963. leftObjs -= cache->stringObjs->number;
  1964. if (cache->booleanObjs)
  1965. leftObjs -= cache->booleanObjs->number;
  1966. if (cache->numberObjs)
  1967. leftObjs -= cache->numberObjs->number;
  1968. if (cache->miscObjs)
  1969. leftObjs -= cache->miscObjs->number;
  1970. }
  1971. }
  1972. printf("# all\n");
  1973. printf("# total : %d\n", reqAll);
  1974. printf("# left : %d\n", leftObjs);
  1975. printf("# created: %d\n", xmlXPathDebugObjTotalAll);
  1976. printf("# reused : %d\n", reAll);
  1977. printf("# max : %d\n", xmlXPathDebugObjMaxAll);
  1978. printf("# node-sets\n");
  1979. printf("# total : %d\n", reqNodeset);
  1980. printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
  1981. printf("# reused : %d\n", reNodeset);
  1982. printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
  1983. printf("# strings\n");
  1984. printf("# total : %d\n", reqString);
  1985. printf("# created: %d\n", xmlXPathDebugObjTotalString);
  1986. printf("# reused : %d\n", reString);
  1987. printf("# max : %d\n", xmlXPathDebugObjMaxString);
  1988. printf("# booleans\n");
  1989. printf("# total : %d\n", reqBool);
  1990. printf("# created: %d\n", xmlXPathDebugObjTotalBool);
  1991. printf("# reused : %d\n", reBool);
  1992. printf("# max : %d\n", xmlXPathDebugObjMaxBool);
  1993. printf("# numbers\n");
  1994. printf("# total : %d\n", reqNumber);
  1995. printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
  1996. printf("# reused : %d\n", reNumber);
  1997. printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
  1998. printf("# XSLT result tree fragments\n");
  1999. printf("# total : %d\n", reqXSLTTree);
  2000. printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
  2001. printf("# reused : %d\n", reXSLTTree);
  2002. printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
  2003. printf("# undefined\n");
  2004. printf("# total : %d\n", reqUndefined);
  2005. printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
  2006. printf("# reused : %d\n", reUndefined);
  2007. printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
  2008. }
  2009. #endif /* XP_DEBUG_OBJ_USAGE */
  2010. #endif /* LIBXML_DEBUG_ENABLED */
  2011. /************************************************************************
  2012. * *
  2013. * XPath object caching *
  2014. * *
  2015. ************************************************************************/
  2016. /**
  2017. * xmlXPathNewCache:
  2018. *
  2019. * Create a new object cache
  2020. *
  2021. * Returns the xmlXPathCache just allocated.
  2022. */
  2023. static xmlXPathContextCachePtr
  2024. xmlXPathNewCache(void)
  2025. {
  2026. xmlXPathContextCachePtr ret;
  2027. ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
  2028. if (ret == NULL) {
  2029. xmlXPathErrMemory(NULL, "creating object cache\n");
  2030. return(NULL);
  2031. }
  2032. memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
  2033. ret->maxNodeset = 100;
  2034. ret->maxString = 100;
  2035. ret->maxBoolean = 100;
  2036. ret->maxNumber = 100;
  2037. ret->maxMisc = 100;
  2038. return(ret);
  2039. }
  2040. static void
  2041. xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
  2042. {
  2043. int i;
  2044. xmlXPathObjectPtr obj;
  2045. if (list == NULL)
  2046. return;
  2047. for (i = 0; i < list->number; i++) {
  2048. obj = list->items[i];
  2049. /*
  2050. * Note that it is already assured that we don't need to
  2051. * look out for namespace nodes in the node-set.
  2052. */
  2053. if (obj->nodesetval != NULL) {
  2054. if (obj->nodesetval->nodeTab != NULL)
  2055. xmlFree(obj->nodesetval->nodeTab);
  2056. xmlFree(obj->nodesetval);
  2057. }
  2058. xmlFree(obj);
  2059. #ifdef XP_DEBUG_OBJ_USAGE
  2060. xmlXPathDebugObjCounterAll--;
  2061. #endif
  2062. }
  2063. xmlPointerListFree(list);
  2064. }
  2065. static void
  2066. xmlXPathFreeCache(xmlXPathContextCachePtr cache)
  2067. {
  2068. if (cache == NULL)
  2069. return;
  2070. if (cache->nodesetObjs)
  2071. xmlXPathCacheFreeObjectList(cache->nodesetObjs);
  2072. if (cache->stringObjs)
  2073. xmlXPathCacheFreeObjectList(cache->stringObjs);
  2074. if (cache->booleanObjs)
  2075. xmlXPathCacheFreeObjectList(cache->booleanObjs);
  2076. if (cache->numberObjs)
  2077. xmlXPathCacheFreeObjectList(cache->numberObjs);
  2078. if (cache->miscObjs)
  2079. xmlXPathCacheFreeObjectList(cache->miscObjs);
  2080. xmlFree(cache);
  2081. }
  2082. /**
  2083. * xmlXPathContextSetCache:
  2084. *
  2085. * @ctxt: the XPath context
  2086. * @active: enables/disables (creates/frees) the cache
  2087. * @value: a value with semantics dependent on @options
  2088. * @options: options (currently only the value 0 is used)
  2089. *
  2090. * Creates/frees an object cache on the XPath context.
  2091. * If activates XPath objects (xmlXPathObject) will be cached internally
  2092. * to be reused.
  2093. * @options:
  2094. * 0: This will set the XPath object caching:
  2095. * @value:
  2096. * This will set the maximum number of XPath objects
  2097. * to be cached per slot
  2098. * There are 5 slots for: node-set, string, number, boolean, and
  2099. * misc objects. Use <0 for the default number (100).
  2100. * Other values for @options have currently no effect.
  2101. *
  2102. * Returns 0 if the setting succeeded, and -1 on API or internal errors.
  2103. */
  2104. int
  2105. xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
  2106. int active,
  2107. int value,
  2108. int options)
  2109. {
  2110. if (ctxt == NULL)
  2111. return(-1);
  2112. if (active) {
  2113. xmlXPathContextCachePtr cache;
  2114. if (ctxt->cache == NULL) {
  2115. ctxt->cache = xmlXPathNewCache();
  2116. if (ctxt->cache == NULL)
  2117. return(-1);
  2118. }
  2119. cache = (xmlXPathContextCachePtr) ctxt->cache;
  2120. if (options == 0) {
  2121. if (value < 0)
  2122. value = 100;
  2123. cache->maxNodeset = value;
  2124. cache->maxString = value;
  2125. cache->maxNumber = value;
  2126. cache->maxBoolean = value;
  2127. cache->maxMisc = value;
  2128. }
  2129. } else if (ctxt->cache != NULL) {
  2130. xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
  2131. ctxt->cache = NULL;
  2132. }
  2133. return(0);
  2134. }
  2135. /**
  2136. * xmlXPathCacheWrapNodeSet:
  2137. * @ctxt: the XPath context
  2138. * @val: the NodePtr value
  2139. *
  2140. * This is the cached version of xmlXPathWrapNodeSet().
  2141. * Wrap the Nodeset @val in a new xmlXPathObjectPtr
  2142. *
  2143. * Returns the created or reused object.
  2144. */
  2145. static xmlXPathObjectPtr
  2146. xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
  2147. {
  2148. if ((ctxt != NULL) && (ctxt->cache != NULL)) {
  2149. xmlXPathContextCachePtr cache =
  2150. (xmlXPathContextCachePtr) ctxt->cache;
  2151. if ((cache->miscObjs != NULL) &&
  2152. (cache->miscObjs->number != 0))
  2153. {
  2154. xmlXPathObjectPtr ret;
  2155. ret = (xmlXPathObjectPtr)
  2156. cache->miscObjs->items[--cache->miscObjs->number];
  2157. ret->type = XPATH_NODESET;
  2158. ret->nodesetval = val;
  2159. #ifdef XP_DEBUG_OBJ_USAGE
  2160. xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
  2161. #endif
  2162. return(ret);
  2163. }
  2164. }
  2165. return(xmlXPathWrapNodeSet(val));
  2166. }
  2167. /**
  2168. * xmlXPathCacheWrapString:
  2169. * @ctxt: the XPath context
  2170. * @val: the xmlChar * value
  2171. *
  2172. * This is the cached version of xmlXPathWrapString().
  2173. * Wraps the @val string into an XPath object.
  2174. *
  2175. * Returns the created or reused object.
  2176. */
  2177. static xmlXPathObjectPtr
  2178. xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
  2179. {
  2180. if ((ctxt != NULL) && (ctxt->cache != NULL)) {
  2181. xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
  2182. if ((cache->stringObjs != NULL) &&
  2183. (cache->stringObjs->number != 0))
  2184. {
  2185. xmlXPathObjectPtr ret;
  2186. ret = (xmlXPathObjectPtr)
  2187. cache->stringObjs->items[--cache->stringObjs->number];
  2188. ret->type = XPATH_STRING;
  2189. ret->stringval = val;
  2190. #ifdef XP_DEBUG_OBJ_USAGE
  2191. xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
  2192. #endif
  2193. return(ret);
  2194. } else if ((cache->miscObjs != NULL) &&
  2195. (cache->miscObjs->number != 0))
  2196. {
  2197. xmlXPathObjectPtr ret;
  2198. /*
  2199. * Fallback to misc-cache.
  2200. */
  2201. ret = (xmlXPathObjectPtr)
  2202. cache->miscObjs->items[--cache->miscObjs->number];
  2203. ret->type = XPATH_STRING;
  2204. ret->stringval = val;
  2205. #ifdef XP_DEBUG_OBJ_USAGE
  2206. xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
  2207. #endif
  2208. return(ret);
  2209. }
  2210. }
  2211. return(xmlXPathWrapString(val));
  2212. }
  2213. /**
  2214. * xmlXPathCacheNewNodeSet:
  2215. * @ctxt: the XPath context
  2216. * @val: the NodePtr value
  2217. *
  2218. * This is the cached version of xmlXPathNewNodeSet().
  2219. * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
  2220. * it with the single Node @val
  2221. *
  2222. * Returns the created or reused object.
  2223. */
  2224. static xmlXPathObjectPtr
  2225. xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
  2226. {
  2227. if ((ctxt != NULL) && (ctxt->cache)) {
  2228. xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
  2229. if ((cache->nodesetObjs != NULL) &&
  2230. (cache->nodesetObjs->number != 0))
  2231. {
  2232. xmlXPathObjectPtr ret;
  2233. /*
  2234. * Use the nodeset-cache.
  2235. */
  2236. ret = (xmlXPathObjectPtr)
  2237. cache->nodesetObjs->items[--cache->nodesetObjs->number];
  2238. ret->type = XPATH_NODESET;
  2239. ret->boolval = 0;
  2240. if (val) {
  2241. if ((ret->nodesetval->nodeMax == 0) ||
  2242. (val->type == XML_NAMESPACE_DECL))
  2243. {
  2244. /* TODO: Check memory error. */
  2245. xmlXPathNodeSetAddUnique(ret->nodesetval, val);
  2246. } else {
  2247. ret->nodesetval->nodeTab[0] = val;
  2248. ret->nodesetval->nodeNr = 1;
  2249. }
  2250. }
  2251. #ifdef XP_DEBUG_OBJ_USAGE
  2252. xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
  2253. #endif
  2254. return(ret);
  2255. } else if ((cache->miscObjs != NULL) &&
  2256. (cache->miscObjs->number != 0))
  2257. {
  2258. xmlXPathObjectPtr ret;
  2259. /*
  2260. * Fallback to misc-cache.
  2261. */
  2262. ret = (xmlXPathObjectPtr)
  2263. cache->miscObjs->items[--cache->miscObjs->number];
  2264. ret->type = XPATH_NODESET;
  2265. ret->boolval = 0;
  2266. ret->nodesetval = xmlXPathNodeSetCreate(val);
  2267. if (ret->nodesetval == NULL) {
  2268. ctxt->lastError.domain = XML_FROM_XPATH;
  2269. ctxt->lastError.code = XML_ERR_NO_MEMORY;
  2270. return(NULL);
  2271. }
  2272. #ifdef XP_DEBUG_OBJ_USAGE
  2273. xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
  2274. #endif
  2275. return(ret);
  2276. }
  2277. }
  2278. return(xmlXPathNewNodeSet(val));
  2279. }
  2280. /**
  2281. * xmlXPathCacheNewCString:
  2282. * @ctxt: the XPath context
  2283. * @val: the char * value
  2284. *
  2285. * This is the cached version of xmlXPathNewCString().
  2286. * Acquire an xmlXPathObjectPtr of type string and of value @val
  2287. *
  2288. * Returns the created or reused object.
  2289. */
  2290. static xmlXPathObjectPtr
  2291. xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
  2292. {
  2293. if ((ctxt != NULL) && (ctxt->cache)) {
  2294. xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
  2295. if ((cache->stringObjs != NULL) &&
  2296. (cache->stringObjs->number != 0))
  2297. {
  2298. xmlXPathObjectPtr ret;
  2299. ret = (xmlXPathObjectPtr)
  2300. cache->stringObjs->items[--cache->stringObjs->number];
  2301. ret->type = XPATH_STRING;
  2302. ret->stringval = xmlStrdup(BAD_CAST val);
  2303. #ifdef XP_DEBUG_OBJ_USAGE
  2304. xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
  2305. #endif
  2306. return(ret);
  2307. } else if ((cache->miscObjs != NULL) &&
  2308. (cache->miscObjs->number != 0))
  2309. {
  2310. xmlXPathObjectPtr ret;
  2311. ret = (xmlXPathObjectPtr)
  2312. cache->miscObjs->items[--cache->miscObjs->number];
  2313. ret->type = XPATH_STRING;
  2314. ret->stringval = xmlStrdup(BAD_CAST val);
  2315. #ifdef XP_DEBUG_OBJ_USAGE
  2316. xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
  2317. #endif
  2318. return(ret);
  2319. }
  2320. }
  2321. return(xmlXPathNewCString(val));
  2322. }
  2323. /**
  2324. * xmlXPathCacheNewString:
  2325. * @ctxt: the XPath context
  2326. * @val: the xmlChar * value
  2327. *
  2328. * This is the cached version of xmlXPathNewString().
  2329. * Acquire an xmlXPathObjectPtr of type string and of value @val
  2330. *
  2331. * Returns the created or reused object.
  2332. */
  2333. static xmlXPathObjectPtr
  2334. xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
  2335. {
  2336. if ((ctxt != NULL) && (ctxt->cache)) {
  2337. xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
  2338. if ((cache->stringObjs != NULL) &&
  2339. (cache->stringObjs->number != 0))
  2340. {
  2341. xmlXPathObjectPtr ret;
  2342. ret = (xmlXPathObjectPtr)
  2343. cache->stringObjs->items[--cache->stringObjs->number];
  2344. ret->type = XPATH_STRING;
  2345. if (val != NULL)
  2346. ret->stringval = xmlStrdup(val);
  2347. else
  2348. ret->stringval = xmlStrdup((const xmlChar *)"");
  2349. #ifdef XP_DEBUG_OBJ_USAGE
  2350. xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
  2351. #endif
  2352. return(ret);
  2353. } else if ((cache->miscObjs != NULL) &&
  2354. (cache->miscObjs->number != 0))
  2355. {
  2356. xmlXPathObjectPtr ret;
  2357. ret = (xmlXPathObjectPtr)
  2358. cache->miscObjs->items[--cache->miscObjs->number];
  2359. ret->type = XPATH_STRING;
  2360. if (val != NULL)
  2361. ret->stringval = xmlStrdup(val);
  2362. else
  2363. ret->stringval = xmlStrdup((const xmlChar *)"");
  2364. #ifdef XP_DEBUG_OBJ_USAGE
  2365. xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
  2366. #endif
  2367. return(ret);
  2368. }
  2369. }
  2370. return(xmlXPathNewString(val));
  2371. }
  2372. /**
  2373. * xmlXPathCacheNewBoolean:
  2374. * @ctxt: the XPath context
  2375. * @val: the boolean value
  2376. *
  2377. * This is the cached version of xmlXPathNewBoolean().
  2378. * Acquires an xmlXPathObjectPtr of type boolean and of value @val
  2379. *
  2380. * Returns the created or reused object.
  2381. */
  2382. static xmlXPathObjectPtr
  2383. xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
  2384. {
  2385. if ((ctxt != NULL) && (ctxt->cache)) {
  2386. xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
  2387. if ((cache->booleanObjs != NULL) &&
  2388. (cache->booleanObjs->number != 0))
  2389. {
  2390. xmlXPathObjectPtr ret;
  2391. ret = (xmlXPathObjectPtr)
  2392. cache->booleanObjs->items[--cache->booleanObjs->number];
  2393. ret->type = XPATH_BOOLEAN;
  2394. ret->boolval = (val != 0);
  2395. #ifdef XP_DEBUG_OBJ_USAGE
  2396. xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
  2397. #endif
  2398. return(ret);
  2399. } else if ((cache->miscObjs != NULL) &&
  2400. (cache->miscObjs->number != 0))
  2401. {
  2402. xmlXPathObjectPtr ret;
  2403. ret = (xmlXPathObjectPtr)
  2404. cache->miscObjs->items[--cache->miscObjs->number];
  2405. ret->type = XPATH_BOOLEAN;
  2406. ret->boolval = (val != 0);
  2407. #ifdef XP_DEBUG_OBJ_USAGE
  2408. xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
  2409. #endif
  2410. return(ret);
  2411. }
  2412. }
  2413. return(xmlXPathNewBoolean(val));
  2414. }
  2415. /**
  2416. * xmlXPathCacheNewFloat:
  2417. * @ctxt: the XPath context
  2418. * @val: the double value
  2419. *
  2420. * This is the cached version of xmlXPathNewFloat().
  2421. * Acquires an xmlXPathObjectPtr of type double and of value @val
  2422. *
  2423. * Returns the created or reused object.
  2424. */
  2425. static xmlXPathObjectPtr
  2426. xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
  2427. {
  2428. if ((ctxt != NULL) && (ctxt->cache)) {
  2429. xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
  2430. if ((cache->numberObjs != NULL) &&
  2431. (cache->numberObjs->number != 0))
  2432. {
  2433. xmlXPathObjectPtr ret;
  2434. ret = (xmlXPathObjectPtr)
  2435. cache->numberObjs->items[--cache->numberObjs->number];
  2436. ret->type = XPATH_NUMBER;
  2437. ret->floatval = val;
  2438. #ifdef XP_DEBUG_OBJ_USAGE
  2439. xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
  2440. #endif
  2441. return(ret);
  2442. } else if ((cache->miscObjs != NULL) &&
  2443. (cache->miscObjs->number != 0))
  2444. {
  2445. xmlXPathObjectPtr ret;
  2446. ret = (xmlXPathObjectPtr)
  2447. cache->miscObjs->items[--cache->miscObjs->number];
  2448. ret->type = XPATH_NUMBER;
  2449. ret->floatval = val;
  2450. #ifdef XP_DEBUG_OBJ_USAGE
  2451. xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
  2452. #endif
  2453. return(ret);
  2454. }
  2455. }
  2456. return(xmlXPathNewFloat(val));
  2457. }
  2458. /**
  2459. * xmlXPathCacheConvertString:
  2460. * @ctxt: the XPath context
  2461. * @val: an XPath object
  2462. *
  2463. * This is the cached version of xmlXPathConvertString().
  2464. * Converts an existing object to its string() equivalent
  2465. *
  2466. * Returns a created or reused object, the old one is freed (cached)
  2467. * (or the operation is done directly on @val)
  2468. */
  2469. static xmlXPathObjectPtr
  2470. xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
  2471. xmlChar *res = NULL;
  2472. if (val == NULL)
  2473. return(xmlXPathCacheNewCString(ctxt, ""));
  2474. switch (val->type) {
  2475. case XPATH_UNDEFINED:
  2476. #ifdef DEBUG_EXPR
  2477. xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
  2478. #endif
  2479. break;
  2480. case XPATH_NODESET:
  2481. case XPATH_XSLT_TREE:
  2482. res = xmlXPathCastNodeSetToString(val->nodesetval);
  2483. break;
  2484. case XPATH_STRING:
  2485. return(val);
  2486. case XPATH_BOOLEAN:
  2487. res = xmlXPathCastBooleanToString(val->boolval);
  2488. break;
  2489. case XPATH_NUMBER:
  2490. res = xmlXPathCastNumberToString(val->floatval);
  2491. break;
  2492. case XPATH_USERS:
  2493. case XPATH_POINT:
  2494. case XPATH_RANGE:
  2495. case XPATH_LOCATIONSET:
  2496. TODO;
  2497. break;
  2498. }
  2499. xmlXPathReleaseObject(ctxt, val);
  2500. if (res == NULL)
  2501. return(xmlXPathCacheNewCString(ctxt, ""));
  2502. return(xmlXPathCacheWrapString(ctxt, res));
  2503. }
  2504. /**
  2505. * xmlXPathCacheObjectCopy:
  2506. * @ctxt: the XPath context
  2507. * @val: the original object
  2508. *
  2509. * This is the cached version of xmlXPathObjectCopy().
  2510. * Acquire a copy of a given object
  2511. *
  2512. * Returns a created or reused created object.
  2513. */
  2514. static xmlXPathObjectPtr
  2515. xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
  2516. {
  2517. if (val == NULL)
  2518. return(NULL);
  2519. if (XP_HAS_CACHE(ctxt)) {
  2520. switch (val->type) {
  2521. case XPATH_NODESET:
  2522. return(xmlXPathCacheWrapNodeSet(ctxt,
  2523. xmlXPathNodeSetMerge(NULL, val->nodesetval)));
  2524. case XPATH_STRING:
  2525. return(xmlXPathCacheNewString(ctxt, val->stringval));
  2526. case XPATH_BOOLEAN:
  2527. return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
  2528. case XPATH_NUMBER:
  2529. return(xmlXPathCacheNewFloat(ctxt, val->floatval));
  2530. default:
  2531. break;
  2532. }
  2533. }
  2534. return(xmlXPathObjectCopy(val));
  2535. }
  2536. /**
  2537. * xmlXPathCacheConvertBoolean:
  2538. * @ctxt: the XPath context
  2539. * @val: an XPath object
  2540. *
  2541. * This is the cached version of xmlXPathConvertBoolean().
  2542. * Converts an existing object to its boolean() equivalent
  2543. *
  2544. * Returns a created or reused object, the old one is freed (or the operation
  2545. * is done directly on @val)
  2546. */
  2547. static xmlXPathObjectPtr
  2548. xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
  2549. xmlXPathObjectPtr ret;
  2550. if (val == NULL)
  2551. return(xmlXPathCacheNewBoolean(ctxt, 0));
  2552. if (val->type == XPATH_BOOLEAN)
  2553. return(val);
  2554. ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
  2555. xmlXPathReleaseObject(ctxt, val);
  2556. return(ret);
  2557. }
  2558. /**
  2559. * xmlXPathCacheConvertNumber:
  2560. * @ctxt: the XPath context
  2561. * @val: an XPath object
  2562. *
  2563. * This is the cached version of xmlXPathConvertNumber().
  2564. * Converts an existing object to its number() equivalent
  2565. *
  2566. * Returns a created or reused object, the old one is freed (or the operation
  2567. * is done directly on @val)
  2568. */
  2569. static xmlXPathObjectPtr
  2570. xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
  2571. xmlXPathObjectPtr ret;
  2572. if (val == NULL)
  2573. return(xmlXPathCacheNewFloat(ctxt, 0.0));
  2574. if (val->type == XPATH_NUMBER)
  2575. return(val);
  2576. ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
  2577. xmlXPathReleaseObject(ctxt, val);
  2578. return(ret);
  2579. }
  2580. /************************************************************************
  2581. * *
  2582. * Parser stacks related functions and macros *
  2583. * *
  2584. ************************************************************************/
  2585. /**
  2586. * xmlXPathSetFrame:
  2587. * @ctxt: an XPath parser context
  2588. *
  2589. * Set the callee evaluation frame
  2590. *
  2591. * Returns the previous frame value to be restored once done
  2592. */
  2593. static int
  2594. xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
  2595. int ret;
  2596. if (ctxt == NULL)
  2597. return(0);
  2598. ret = ctxt->valueFrame;
  2599. ctxt->valueFrame = ctxt->valueNr;
  2600. return(ret);
  2601. }
  2602. /**
  2603. * xmlXPathPopFrame:
  2604. * @ctxt: an XPath parser context
  2605. * @frame: the previous frame value
  2606. *
  2607. * Remove the callee evaluation frame
  2608. */
  2609. static void
  2610. xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
  2611. if (ctxt == NULL)
  2612. return;
  2613. if (ctxt->valueNr < ctxt->valueFrame) {
  2614. xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
  2615. }
  2616. ctxt->valueFrame = frame;
  2617. }
  2618. /**
  2619. * valuePop:
  2620. * @ctxt: an XPath evaluation context
  2621. *
  2622. * Pops the top XPath object from the value stack
  2623. *
  2624. * Returns the XPath object just removed
  2625. */
  2626. xmlXPathObjectPtr
  2627. valuePop(xmlXPathParserContextPtr ctxt)
  2628. {
  2629. xmlXPathObjectPtr ret;
  2630. if ((ctxt == NULL) || (ctxt->valueNr <= 0))
  2631. return (NULL);
  2632. if (ctxt->valueNr <= ctxt->valueFrame) {
  2633. xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
  2634. return (NULL);
  2635. }
  2636. ctxt->valueNr--;
  2637. if (ctxt->valueNr > 0)
  2638. ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
  2639. else
  2640. ctxt->value = NULL;
  2641. ret = ctxt->valueTab[ctxt->valueNr];
  2642. ctxt->valueTab[ctxt->valueNr] = NULL;
  2643. return (ret);
  2644. }
  2645. /**
  2646. * valuePush:
  2647. * @ctxt: an XPath evaluation context
  2648. * @value: the XPath object
  2649. *
  2650. * Pushes a new XPath object on top of the value stack. If value is NULL,
  2651. * a memory error is recorded in the parser context.
  2652. *
  2653. * Returns the number of items on the value stack, or -1 in case of error.
  2654. */
  2655. int
  2656. valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
  2657. {
  2658. if (ctxt == NULL) return(-1);
  2659. if (value == NULL) {
  2660. /*
  2661. * A NULL value typically indicates that a memory allocation failed,
  2662. * so we set ctxt->error here to propagate the error.
  2663. */
  2664. ctxt->error = XPATH_MEMORY_ERROR;
  2665. return(-1);
  2666. }
  2667. if (ctxt->valueNr >= ctxt->valueMax) {
  2668. xmlXPathObjectPtr *tmp;
  2669. if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
  2670. xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
  2671. return (-1);
  2672. }
  2673. tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
  2674. 2 * ctxt->valueMax *
  2675. sizeof(ctxt->valueTab[0]));
  2676. if (tmp == NULL) {
  2677. xmlXPathPErrMemory(ctxt, "pushing value\n");
  2678. return (-1);
  2679. }
  2680. ctxt->valueMax *= 2;
  2681. ctxt->valueTab = tmp;
  2682. }
  2683. ctxt->valueTab[ctxt->valueNr] = value;
  2684. ctxt->value = value;
  2685. return (ctxt->valueNr++);
  2686. }
  2687. /**
  2688. * xmlXPathPopBoolean:
  2689. * @ctxt: an XPath parser context
  2690. *
  2691. * Pops a boolean from the stack, handling conversion if needed.
  2692. * Check error with #xmlXPathCheckError.
  2693. *
  2694. * Returns the boolean
  2695. */
  2696. int
  2697. xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
  2698. xmlXPathObjectPtr obj;
  2699. int ret;
  2700. obj = valuePop(ctxt);
  2701. if (obj == NULL) {
  2702. xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
  2703. return(0);
  2704. }
  2705. if (obj->type != XPATH_BOOLEAN)
  2706. ret = xmlXPathCastToBoolean(obj);
  2707. else
  2708. ret = obj->boolval;
  2709. xmlXPathReleaseObject(ctxt->context, obj);
  2710. return(ret);
  2711. }
  2712. /**
  2713. * xmlXPathPopNumber:
  2714. * @ctxt: an XPath parser context
  2715. *
  2716. * Pops a number from the stack, handling conversion if needed.
  2717. * Check error with #xmlXPathCheckError.
  2718. *
  2719. * Returns the number
  2720. */
  2721. double
  2722. xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
  2723. xmlXPathObjectPtr obj;
  2724. double ret;
  2725. obj = valuePop(ctxt);
  2726. if (obj == NULL) {
  2727. xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
  2728. return(0);
  2729. }
  2730. if (obj->type != XPATH_NUMBER)
  2731. ret = xmlXPathCastToNumber(obj);
  2732. else
  2733. ret = obj->floatval;
  2734. xmlXPathReleaseObject(ctxt->context, obj);
  2735. return(ret);
  2736. }
  2737. /**
  2738. * xmlXPathPopString:
  2739. * @ctxt: an XPath parser context
  2740. *
  2741. * Pops a string from the stack, handling conversion if needed.
  2742. * Check error with #xmlXPathCheckError.
  2743. *
  2744. * Returns the string
  2745. */
  2746. xmlChar *
  2747. xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
  2748. xmlXPathObjectPtr obj;
  2749. xmlChar * ret;
  2750. obj = valuePop(ctxt);
  2751. if (obj == NULL) {
  2752. xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
  2753. return(NULL);
  2754. }
  2755. ret = xmlXPathCastToString(obj); /* this does required strdup */
  2756. /* TODO: needs refactoring somewhere else */
  2757. if (obj->stringval == ret)
  2758. obj->stringval = NULL;
  2759. xmlXPathReleaseObject(ctxt->context, obj);
  2760. return(ret);
  2761. }
  2762. /**
  2763. * xmlXPathPopNodeSet:
  2764. * @ctxt: an XPath parser context
  2765. *
  2766. * Pops a node-set from the stack, handling conversion if needed.
  2767. * Check error with #xmlXPathCheckError.
  2768. *
  2769. * Returns the node-set
  2770. */
  2771. xmlNodeSetPtr
  2772. xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
  2773. xmlXPathObjectPtr obj;
  2774. xmlNodeSetPtr ret;
  2775. if (ctxt == NULL) return(NULL);
  2776. if (ctxt->value == NULL) {
  2777. xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
  2778. return(NULL);
  2779. }
  2780. if (!xmlXPathStackIsNodeSet(ctxt)) {
  2781. xmlXPathSetTypeError(ctxt);
  2782. return(NULL);
  2783. }
  2784. obj = valuePop(ctxt);
  2785. ret = obj->nodesetval;
  2786. #if 0
  2787. /* to fix memory leak of not clearing obj->user */
  2788. if (obj->boolval && obj->user != NULL)
  2789. xmlFreeNodeList((xmlNodePtr) obj->user);
  2790. #endif
  2791. obj->nodesetval = NULL;
  2792. xmlXPathReleaseObject(ctxt->context, obj);
  2793. return(ret);
  2794. }
  2795. /**
  2796. * xmlXPathPopExternal:
  2797. * @ctxt: an XPath parser context
  2798. *
  2799. * Pops an external object from the stack, handling conversion if needed.
  2800. * Check error with #xmlXPathCheckError.
  2801. *
  2802. * Returns the object
  2803. */
  2804. void *
  2805. xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
  2806. xmlXPathObjectPtr obj;
  2807. void * ret;
  2808. if ((ctxt == NULL) || (ctxt->value == NULL)) {
  2809. xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
  2810. return(NULL);
  2811. }
  2812. if (ctxt->value->type != XPATH_USERS) {
  2813. xmlXPathSetTypeError(ctxt);
  2814. return(NULL);
  2815. }
  2816. obj = valuePop(ctxt);
  2817. ret = obj->user;
  2818. obj->user = NULL;
  2819. xmlXPathReleaseObject(ctxt->context, obj);
  2820. return(ret);
  2821. }
  2822. /*
  2823. * Macros for accessing the content. Those should be used only by the parser,
  2824. * and not exported.
  2825. *
  2826. * Dirty macros, i.e. one need to make assumption on the context to use them
  2827. *
  2828. * CUR_PTR return the current pointer to the xmlChar to be parsed.
  2829. * CUR returns the current xmlChar value, i.e. a 8 bit value
  2830. * in ISO-Latin or UTF-8.
  2831. * This should be used internally by the parser
  2832. * only to compare to ASCII values otherwise it would break when
  2833. * running with UTF-8 encoding.
  2834. * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
  2835. * to compare on ASCII based substring.
  2836. * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
  2837. * strings within the parser.
  2838. * CURRENT Returns the current char value, with the full decoding of
  2839. * UTF-8 if we are using this mode. It returns an int.
  2840. * NEXT Skip to the next character, this does the proper decoding
  2841. * in UTF-8 mode. It also pop-up unfinished entities on the fly.
  2842. * It returns the pointer to the current xmlChar.
  2843. */
  2844. #define CUR (*ctxt->cur)
  2845. #define SKIP(val) ctxt->cur += (val)
  2846. #define NXT(val) ctxt->cur[(val)]
  2847. #define CUR_PTR ctxt->cur
  2848. #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
  2849. #define COPY_BUF(l,b,i,v) \
  2850. if (l == 1) b[i++] = (xmlChar) v; \
  2851. else i += xmlCopyChar(l,&b[i],v)
  2852. #define NEXTL(l) ctxt->cur += l
  2853. #define SKIP_BLANKS \
  2854. while (IS_BLANK_CH(*(ctxt->cur))) NEXT
  2855. #define CURRENT (*ctxt->cur)
  2856. #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
  2857. #ifndef DBL_DIG
  2858. #define DBL_DIG 16
  2859. #endif
  2860. #ifndef DBL_EPSILON
  2861. #define DBL_EPSILON 1E-9
  2862. #endif
  2863. #define UPPER_DOUBLE 1E9
  2864. #define LOWER_DOUBLE 1E-5
  2865. #define LOWER_DOUBLE_EXP 5
  2866. #define INTEGER_DIGITS DBL_DIG
  2867. #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
  2868. #define EXPONENT_DIGITS (3 + 2)
  2869. /**
  2870. * xmlXPathFormatNumber:
  2871. * @number: number to format
  2872. * @buffer: output buffer
  2873. * @buffersize: size of output buffer
  2874. *
  2875. * Convert the number into a string representation.
  2876. */
  2877. static void
  2878. xmlXPathFormatNumber(double number, char buffer[], int buffersize)
  2879. {
  2880. switch (xmlXPathIsInf(number)) {
  2881. case 1:
  2882. if (buffersize > (int)sizeof("Infinity"))
  2883. snprintf(buffer, buffersize, "Infinity");
  2884. break;
  2885. case -1:
  2886. if (buffersize > (int)sizeof("-Infinity"))
  2887. snprintf(buffer, buffersize, "-Infinity");
  2888. break;
  2889. default:
  2890. if (xmlXPathIsNaN(number)) {
  2891. if (buffersize > (int)sizeof("NaN"))
  2892. snprintf(buffer, buffersize, "NaN");
  2893. } else if (number == 0) {
  2894. /* Omit sign for negative zero. */
  2895. snprintf(buffer, buffersize, "0");
  2896. } else if ((number > INT_MIN) && (number < INT_MAX) &&
  2897. (number == (int) number)) {
  2898. char work[30];
  2899. char *ptr, *cur;
  2900. int value = (int) number;
  2901. ptr = &buffer[0];
  2902. if (value == 0) {
  2903. *ptr++ = '0';
  2904. } else {
  2905. snprintf(work, 29, "%d", value);
  2906. cur = &work[0];
  2907. while ((*cur) && (ptr - buffer < buffersize)) {
  2908. *ptr++ = *cur++;
  2909. }
  2910. }
  2911. if (ptr - buffer < buffersize) {
  2912. *ptr = 0;
  2913. } else if (buffersize > 0) {
  2914. ptr--;
  2915. *ptr = 0;
  2916. }
  2917. } else {
  2918. /*
  2919. For the dimension of work,
  2920. DBL_DIG is number of significant digits
  2921. EXPONENT is only needed for "scientific notation"
  2922. 3 is sign, decimal point, and terminating zero
  2923. LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
  2924. Note that this dimension is slightly (a few characters)
  2925. larger than actually necessary.
  2926. */
  2927. char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
  2928. int integer_place, fraction_place;
  2929. char *ptr;
  2930. char *after_fraction;
  2931. double absolute_value;
  2932. int size;
  2933. absolute_value = fabs(number);
  2934. /*
  2935. * First choose format - scientific or regular floating point.
  2936. * In either case, result is in work, and after_fraction points
  2937. * just past the fractional part.
  2938. */
  2939. if ( ((absolute_value > UPPER_DOUBLE) ||
  2940. (absolute_value < LOWER_DOUBLE)) &&
  2941. (absolute_value != 0.0) ) {
  2942. /* Use scientific notation */
  2943. integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
  2944. fraction_place = DBL_DIG - 1;
  2945. size = snprintf(work, sizeof(work),"%*.*e",
  2946. integer_place, fraction_place, number);
  2947. while ((size > 0) && (work[size] != 'e')) size--;
  2948. }
  2949. else {
  2950. /* Use regular notation */
  2951. if (absolute_value > 0.0) {
  2952. integer_place = (int)log10(absolute_value);
  2953. if (integer_place > 0)
  2954. fraction_place = DBL_DIG - integer_place - 1;
  2955. else
  2956. fraction_place = DBL_DIG - integer_place;
  2957. } else {
  2958. fraction_place = 1;
  2959. }
  2960. size = snprintf(work, sizeof(work), "%0.*f",
  2961. fraction_place, number);
  2962. }
  2963. /* Remove leading spaces sometimes inserted by snprintf */
  2964. while (work[0] == ' ') {
  2965. for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
  2966. size--;
  2967. }
  2968. /* Remove fractional trailing zeroes */
  2969. after_fraction = work + size;
  2970. ptr = after_fraction;
  2971. while (*(--ptr) == '0')
  2972. ;
  2973. if (*ptr != '.')
  2974. ptr++;
  2975. while ((*ptr++ = *after_fraction++) != 0);
  2976. /* Finally copy result back to caller */
  2977. size = strlen(work) + 1;
  2978. if (size > buffersize) {
  2979. work[buffersize - 1] = 0;
  2980. size = buffersize;
  2981. }
  2982. memmove(buffer, work, size);
  2983. }
  2984. break;
  2985. }
  2986. }
  2987. /************************************************************************
  2988. * *
  2989. * Routines to handle NodeSets *
  2990. * *
  2991. ************************************************************************/
  2992. /**
  2993. * xmlXPathOrderDocElems:
  2994. * @doc: an input document
  2995. *
  2996. * Call this routine to speed up XPath computation on static documents.
  2997. * This stamps all the element nodes with the document order
  2998. * Like for line information, the order is kept in the element->content
  2999. * field, the value stored is actually - the node number (starting at -1)
  3000. * to be able to differentiate from line numbers.
  3001. *
  3002. * Returns the number of elements found in the document or -1 in case
  3003. * of error.
  3004. */
  3005. long
  3006. xmlXPathOrderDocElems(xmlDocPtr doc) {
  3007. ptrdiff_t count = 0;
  3008. xmlNodePtr cur;
  3009. if (doc == NULL)
  3010. return(-1);
  3011. cur = doc->children;
  3012. while (cur != NULL) {
  3013. if (cur->type == XML_ELEMENT_NODE) {
  3014. cur->content = (void *) (-(++count));
  3015. if (cur->children != NULL) {
  3016. cur = cur->children;
  3017. continue;
  3018. }
  3019. }
  3020. if (cur->next != NULL) {
  3021. cur = cur->next;
  3022. continue;
  3023. }
  3024. do {
  3025. cur = cur->parent;
  3026. if (cur == NULL)
  3027. break;
  3028. if (cur == (xmlNodePtr) doc) {
  3029. cur = NULL;
  3030. break;
  3031. }
  3032. if (cur->next != NULL) {
  3033. cur = cur->next;
  3034. break;
  3035. }
  3036. } while (cur != NULL);
  3037. }
  3038. return((long) count);
  3039. }
  3040. /**
  3041. * xmlXPathCmpNodes:
  3042. * @node1: the first node
  3043. * @node2: the second node
  3044. *
  3045. * Compare two nodes w.r.t document order
  3046. *
  3047. * Returns -2 in case of error 1 if first point < second point, 0 if
  3048. * it's the same node, -1 otherwise
  3049. */
  3050. int
  3051. xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
  3052. int depth1, depth2;
  3053. int attr1 = 0, attr2 = 0;
  3054. xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
  3055. xmlNodePtr cur, root;
  3056. if ((node1 == NULL) || (node2 == NULL))
  3057. return(-2);
  3058. /*
  3059. * a couple of optimizations which will avoid computations in most cases
  3060. */
  3061. if (node1 == node2) /* trivial case */
  3062. return(0);
  3063. if (node1->type == XML_ATTRIBUTE_NODE) {
  3064. attr1 = 1;
  3065. attrNode1 = node1;
  3066. node1 = node1->parent;
  3067. }
  3068. if (node2->type == XML_ATTRIBUTE_NODE) {
  3069. attr2 = 1;
  3070. attrNode2 = node2;
  3071. node2 = node2->parent;
  3072. }
  3073. if (node1 == node2) {
  3074. if (attr1 == attr2) {
  3075. /* not required, but we keep attributes in order */
  3076. if (attr1 != 0) {
  3077. cur = attrNode2->prev;
  3078. while (cur != NULL) {
  3079. if (cur == attrNode1)
  3080. return (1);
  3081. cur = cur->prev;
  3082. }
  3083. return (-1);
  3084. }
  3085. return(0);
  3086. }
  3087. if (attr2 == 1)
  3088. return(1);
  3089. return(-1);
  3090. }
  3091. if ((node1->type == XML_NAMESPACE_DECL) ||
  3092. (node2->type == XML_NAMESPACE_DECL))
  3093. return(1);
  3094. if (node1 == node2->prev)
  3095. return(1);
  3096. if (node1 == node2->next)
  3097. return(-1);
  3098. /*
  3099. * Speedup using document order if available.
  3100. */
  3101. if ((node1->type == XML_ELEMENT_NODE) &&
  3102. (node2->type == XML_ELEMENT_NODE) &&
  3103. (0 > (ptrdiff_t) node1->content) &&
  3104. (0 > (ptrdiff_t) node2->content) &&
  3105. (node1->doc == node2->doc)) {
  3106. ptrdiff_t l1, l2;
  3107. l1 = -((ptrdiff_t) node1->content);
  3108. l2 = -((ptrdiff_t) node2->content);
  3109. if (l1 < l2)
  3110. return(1);
  3111. if (l1 > l2)
  3112. return(-1);
  3113. }
  3114. /*
  3115. * compute depth to root
  3116. */
  3117. for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
  3118. if (cur->parent == node1)
  3119. return(1);
  3120. depth2++;
  3121. }
  3122. root = cur;
  3123. for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
  3124. if (cur->parent == node2)
  3125. return(-1);
  3126. depth1++;
  3127. }
  3128. /*
  3129. * Distinct document (or distinct entities :-( ) case.
  3130. */
  3131. if (root != cur) {
  3132. return(-2);
  3133. }
  3134. /*
  3135. * get the nearest common ancestor.
  3136. */
  3137. while (depth1 > depth2) {
  3138. depth1--;
  3139. node1 = node1->parent;
  3140. }
  3141. while (depth2 > depth1) {
  3142. depth2--;
  3143. node2 = node2->parent;
  3144. }
  3145. while (node1->parent != node2->parent) {
  3146. node1 = node1->parent;
  3147. node2 = node2->parent;
  3148. /* should not happen but just in case ... */
  3149. if ((node1 == NULL) || (node2 == NULL))
  3150. return(-2);
  3151. }
  3152. /*
  3153. * Find who's first.
  3154. */
  3155. if (node1 == node2->prev)
  3156. return(1);
  3157. if (node1 == node2->next)
  3158. return(-1);
  3159. /*
  3160. * Speedup using document order if available.
  3161. */
  3162. if ((node1->type == XML_ELEMENT_NODE) &&
  3163. (node2->type == XML_ELEMENT_NODE) &&
  3164. (0 > (ptrdiff_t) node1->content) &&
  3165. (0 > (ptrdiff_t) node2->content) &&
  3166. (node1->doc == node2->doc)) {
  3167. ptrdiff_t l1, l2;
  3168. l1 = -((ptrdiff_t) node1->content);
  3169. l2 = -((ptrdiff_t) node2->content);
  3170. if (l1 < l2)
  3171. return(1);
  3172. if (l1 > l2)
  3173. return(-1);
  3174. }
  3175. for (cur = node1->next;cur != NULL;cur = cur->next)
  3176. if (cur == node2)
  3177. return(1);
  3178. return(-1); /* assume there is no sibling list corruption */
  3179. }
  3180. /**
  3181. * xmlXPathNodeSetSort:
  3182. * @set: the node set
  3183. *
  3184. * Sort the node set in document order
  3185. */
  3186. void
  3187. xmlXPathNodeSetSort(xmlNodeSetPtr set) {
  3188. #ifndef WITH_TIM_SORT
  3189. int i, j, incr, len;
  3190. xmlNodePtr tmp;
  3191. #endif
  3192. if (set == NULL)
  3193. return;
  3194. #ifndef WITH_TIM_SORT
  3195. /*
  3196. * Use the old Shell's sort implementation to sort the node-set
  3197. * Timsort ought to be quite faster
  3198. */
  3199. len = set->nodeNr;
  3200. for (incr = len / 2; incr > 0; incr /= 2) {
  3201. for (i = incr; i < len; i++) {
  3202. j = i - incr;
  3203. while (j >= 0) {
  3204. #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
  3205. if (xmlXPathCmpNodesExt(set->nodeTab[j],
  3206. set->nodeTab[j + incr]) == -1)
  3207. #else
  3208. if (xmlXPathCmpNodes(set->nodeTab[j],
  3209. set->nodeTab[j + incr]) == -1)
  3210. #endif
  3211. {
  3212. tmp = set->nodeTab[j];
  3213. set->nodeTab[j] = set->nodeTab[j + incr];
  3214. set->nodeTab[j + incr] = tmp;
  3215. j -= incr;
  3216. } else
  3217. break;
  3218. }
  3219. }
  3220. }
  3221. #else /* WITH_TIM_SORT */
  3222. libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
  3223. #endif /* WITH_TIM_SORT */
  3224. }
  3225. #define XML_NODESET_DEFAULT 10
  3226. /**
  3227. * xmlXPathNodeSetDupNs:
  3228. * @node: the parent node of the namespace XPath node
  3229. * @ns: the libxml namespace declaration node.
  3230. *
  3231. * Namespace node in libxml don't match the XPath semantic. In a node set
  3232. * the namespace nodes are duplicated and the next pointer is set to the
  3233. * parent node in the XPath semantic.
  3234. *
  3235. * Returns the newly created object.
  3236. */
  3237. static xmlNodePtr
  3238. xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
  3239. xmlNsPtr cur;
  3240. if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
  3241. return(NULL);
  3242. if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
  3243. return((xmlNodePtr) ns);
  3244. /*
  3245. * Allocate a new Namespace and fill the fields.
  3246. */
  3247. cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
  3248. if (cur == NULL) {
  3249. xmlXPathErrMemory(NULL, "duplicating namespace\n");
  3250. return(NULL);
  3251. }
  3252. memset(cur, 0, sizeof(xmlNs));
  3253. cur->type = XML_NAMESPACE_DECL;
  3254. if (ns->href != NULL)
  3255. cur->href = xmlStrdup(ns->href);
  3256. if (ns->prefix != NULL)
  3257. cur->prefix = xmlStrdup(ns->prefix);
  3258. cur->next = (xmlNsPtr) node;
  3259. return((xmlNodePtr) cur);
  3260. }
  3261. /**
  3262. * xmlXPathNodeSetFreeNs:
  3263. * @ns: the XPath namespace node found in a nodeset.
  3264. *
  3265. * Namespace nodes in libxml don't match the XPath semantic. In a node set
  3266. * the namespace nodes are duplicated and the next pointer is set to the
  3267. * parent node in the XPath semantic. Check if such a node needs to be freed
  3268. */
  3269. void
  3270. xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
  3271. if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
  3272. return;
  3273. if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
  3274. if (ns->href != NULL)
  3275. xmlFree((xmlChar *)ns->href);
  3276. if (ns->prefix != NULL)
  3277. xmlFree((xmlChar *)ns->prefix);
  3278. xmlFree(ns);
  3279. }
  3280. }
  3281. /**
  3282. * xmlXPathNodeSetCreate:
  3283. * @val: an initial xmlNodePtr, or NULL
  3284. *
  3285. * Create a new xmlNodeSetPtr of type double and of value @val
  3286. *
  3287. * Returns the newly created object.
  3288. */
  3289. xmlNodeSetPtr
  3290. xmlXPathNodeSetCreate(xmlNodePtr val) {
  3291. xmlNodeSetPtr ret;
  3292. ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
  3293. if (ret == NULL) {
  3294. xmlXPathErrMemory(NULL, "creating nodeset\n");
  3295. return(NULL);
  3296. }
  3297. memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
  3298. if (val != NULL) {
  3299. ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
  3300. sizeof(xmlNodePtr));
  3301. if (ret->nodeTab == NULL) {
  3302. xmlXPathErrMemory(NULL, "creating nodeset\n");
  3303. xmlFree(ret);
  3304. return(NULL);
  3305. }
  3306. memset(ret->nodeTab, 0 ,
  3307. XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
  3308. ret->nodeMax = XML_NODESET_DEFAULT;
  3309. if (val->type == XML_NAMESPACE_DECL) {
  3310. xmlNsPtr ns = (xmlNsPtr) val;
  3311. /* TODO: Check memory error. */
  3312. ret->nodeTab[ret->nodeNr++] =
  3313. xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
  3314. } else
  3315. ret->nodeTab[ret->nodeNr++] = val;
  3316. }
  3317. return(ret);
  3318. }
  3319. /**
  3320. * xmlXPathNodeSetContains:
  3321. * @cur: the node-set
  3322. * @val: the node
  3323. *
  3324. * checks whether @cur contains @val
  3325. *
  3326. * Returns true (1) if @cur contains @val, false (0) otherwise
  3327. */
  3328. int
  3329. xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
  3330. int i;
  3331. if ((cur == NULL) || (val == NULL)) return(0);
  3332. if (val->type == XML_NAMESPACE_DECL) {
  3333. for (i = 0; i < cur->nodeNr; i++) {
  3334. if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
  3335. xmlNsPtr ns1, ns2;
  3336. ns1 = (xmlNsPtr) val;
  3337. ns2 = (xmlNsPtr) cur->nodeTab[i];
  3338. if (ns1 == ns2)
  3339. return(1);
  3340. if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
  3341. (xmlStrEqual(ns1->prefix, ns2->prefix)))
  3342. return(1);
  3343. }
  3344. }
  3345. } else {
  3346. for (i = 0; i < cur->nodeNr; i++) {
  3347. if (cur->nodeTab[i] == val)
  3348. return(1);
  3349. }
  3350. }
  3351. return(0);
  3352. }
  3353. /**
  3354. * xmlXPathNodeSetAddNs:
  3355. * @cur: the initial node set
  3356. * @node: the hosting node
  3357. * @ns: a the namespace node
  3358. *
  3359. * add a new namespace node to an existing NodeSet
  3360. *
  3361. * Returns 0 in case of success and -1 in case of error
  3362. */
  3363. int
  3364. xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
  3365. int i;
  3366. if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
  3367. (ns->type != XML_NAMESPACE_DECL) ||
  3368. (node->type != XML_ELEMENT_NODE))
  3369. return(-1);
  3370. /* @@ with_ns to check whether namespace nodes should be looked at @@ */
  3371. /*
  3372. * prevent duplicates
  3373. */
  3374. for (i = 0;i < cur->nodeNr;i++) {
  3375. if ((cur->nodeTab[i] != NULL) &&
  3376. (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
  3377. (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
  3378. (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
  3379. return(0);
  3380. }
  3381. /*
  3382. * grow the nodeTab if needed
  3383. */
  3384. if (cur->nodeMax == 0) {
  3385. cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
  3386. sizeof(xmlNodePtr));
  3387. if (cur->nodeTab == NULL) {
  3388. xmlXPathErrMemory(NULL, "growing nodeset\n");
  3389. return(-1);
  3390. }
  3391. memset(cur->nodeTab, 0 ,
  3392. XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
  3393. cur->nodeMax = XML_NODESET_DEFAULT;
  3394. } else if (cur->nodeNr == cur->nodeMax) {
  3395. xmlNodePtr *temp;
  3396. if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
  3397. xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
  3398. return(-1);
  3399. }
  3400. temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
  3401. sizeof(xmlNodePtr));
  3402. if (temp == NULL) {
  3403. xmlXPathErrMemory(NULL, "growing nodeset\n");
  3404. return(-1);
  3405. }
  3406. cur->nodeMax *= 2;
  3407. cur->nodeTab = temp;
  3408. }
  3409. /* TODO: Check memory error. */
  3410. cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
  3411. return(0);
  3412. }
  3413. /**
  3414. * xmlXPathNodeSetAdd:
  3415. * @cur: the initial node set
  3416. * @val: a new xmlNodePtr
  3417. *
  3418. * add a new xmlNodePtr to an existing NodeSet
  3419. *
  3420. * Returns 0 in case of success, and -1 in case of error
  3421. */
  3422. int
  3423. xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
  3424. int i;
  3425. if ((cur == NULL) || (val == NULL)) return(-1);
  3426. /* @@ with_ns to check whether namespace nodes should be looked at @@ */
  3427. /*
  3428. * prevent duplicates
  3429. */
  3430. for (i = 0;i < cur->nodeNr;i++)
  3431. if (cur->nodeTab[i] == val) return(0);
  3432. /*
  3433. * grow the nodeTab if needed
  3434. */
  3435. if (cur->nodeMax == 0) {
  3436. cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
  3437. sizeof(xmlNodePtr));
  3438. if (cur->nodeTab == NULL) {
  3439. xmlXPathErrMemory(NULL, "growing nodeset\n");
  3440. return(-1);
  3441. }
  3442. memset(cur->nodeTab, 0 ,
  3443. XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
  3444. cur->nodeMax = XML_NODESET_DEFAULT;
  3445. } else if (cur->nodeNr == cur->nodeMax) {
  3446. xmlNodePtr *temp;
  3447. if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
  3448. xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
  3449. return(-1);
  3450. }
  3451. temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
  3452. sizeof(xmlNodePtr));
  3453. if (temp == NULL) {
  3454. xmlXPathErrMemory(NULL, "growing nodeset\n");
  3455. return(-1);
  3456. }
  3457. cur->nodeMax *= 2;
  3458. cur->nodeTab = temp;
  3459. }
  3460. if (val->type == XML_NAMESPACE_DECL) {
  3461. xmlNsPtr ns = (xmlNsPtr) val;
  3462. /* TODO: Check memory error. */
  3463. cur->nodeTab[cur->nodeNr++] =
  3464. xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
  3465. } else
  3466. cur->nodeTab[cur->nodeNr++] = val;
  3467. return(0);
  3468. }
  3469. /**
  3470. * xmlXPathNodeSetAddUnique:
  3471. * @cur: the initial node set
  3472. * @val: a new xmlNodePtr
  3473. *
  3474. * add a new xmlNodePtr to an existing NodeSet, optimized version
  3475. * when we are sure the node is not already in the set.
  3476. *
  3477. * Returns 0 in case of success and -1 in case of failure
  3478. */
  3479. int
  3480. xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
  3481. if ((cur == NULL) || (val == NULL)) return(-1);
  3482. /* @@ with_ns to check whether namespace nodes should be looked at @@ */
  3483. /*
  3484. * grow the nodeTab if needed
  3485. */
  3486. if (cur->nodeMax == 0) {
  3487. cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
  3488. sizeof(xmlNodePtr));
  3489. if (cur->nodeTab == NULL) {
  3490. xmlXPathErrMemory(NULL, "growing nodeset\n");
  3491. return(-1);
  3492. }
  3493. memset(cur->nodeTab, 0 ,
  3494. XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
  3495. cur->nodeMax = XML_NODESET_DEFAULT;
  3496. } else if (cur->nodeNr == cur->nodeMax) {
  3497. xmlNodePtr *temp;
  3498. if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
  3499. xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
  3500. return(-1);
  3501. }
  3502. temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
  3503. sizeof(xmlNodePtr));
  3504. if (temp == NULL) {
  3505. xmlXPathErrMemory(NULL, "growing nodeset\n");
  3506. return(-1);
  3507. }
  3508. cur->nodeTab = temp;
  3509. cur->nodeMax *= 2;
  3510. }
  3511. if (val->type == XML_NAMESPACE_DECL) {
  3512. xmlNsPtr ns = (xmlNsPtr) val;
  3513. /* TODO: Check memory error. */
  3514. cur->nodeTab[cur->nodeNr++] =
  3515. xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
  3516. } else
  3517. cur->nodeTab[cur->nodeNr++] = val;
  3518. return(0);
  3519. }
  3520. /**
  3521. * xmlXPathNodeSetMerge:
  3522. * @val1: the first NodeSet or NULL
  3523. * @val2: the second NodeSet
  3524. *
  3525. * Merges two nodesets, all nodes from @val2 are added to @val1
  3526. * if @val1 is NULL, a new set is created and copied from @val2
  3527. *
  3528. * Returns @val1 once extended or NULL in case of error.
  3529. */
  3530. xmlNodeSetPtr
  3531. xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
  3532. int i, j, initNr, skip;
  3533. xmlNodePtr n1, n2;
  3534. if (val2 == NULL) return(val1);
  3535. if (val1 == NULL) {
  3536. val1 = xmlXPathNodeSetCreate(NULL);
  3537. if (val1 == NULL)
  3538. return (NULL);
  3539. #if 0
  3540. /*
  3541. * TODO: The optimization won't work in every case, since
  3542. * those nasty namespace nodes need to be added with
  3543. * xmlXPathNodeSetDupNs() to the set; thus a pure
  3544. * memcpy is not possible.
  3545. * If there was a flag on the nodesetval, indicating that
  3546. * some temporary nodes are in, that would be helpful.
  3547. */
  3548. /*
  3549. * Optimization: Create an equally sized node-set
  3550. * and memcpy the content.
  3551. */
  3552. val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
  3553. if (val1 == NULL)
  3554. return(NULL);
  3555. if (val2->nodeNr != 0) {
  3556. if (val2->nodeNr == 1)
  3557. *(val1->nodeTab) = *(val2->nodeTab);
  3558. else {
  3559. memcpy(val1->nodeTab, val2->nodeTab,
  3560. val2->nodeNr * sizeof(xmlNodePtr));
  3561. }
  3562. val1->nodeNr = val2->nodeNr;
  3563. }
  3564. return(val1);
  3565. #endif
  3566. }
  3567. /* @@ with_ns to check whether namespace nodes should be looked at @@ */
  3568. initNr = val1->nodeNr;
  3569. for (i = 0;i < val2->nodeNr;i++) {
  3570. n2 = val2->nodeTab[i];
  3571. /*
  3572. * check against duplicates
  3573. */
  3574. skip = 0;
  3575. for (j = 0; j < initNr; j++) {
  3576. n1 = val1->nodeTab[j];
  3577. if (n1 == n2) {
  3578. skip = 1;
  3579. break;
  3580. } else if ((n1->type == XML_NAMESPACE_DECL) &&
  3581. (n2->type == XML_NAMESPACE_DECL)) {
  3582. if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
  3583. (xmlStrEqual(((xmlNsPtr) n1)->prefix,
  3584. ((xmlNsPtr) n2)->prefix)))
  3585. {
  3586. skip = 1;
  3587. break;
  3588. }
  3589. }
  3590. }
  3591. if (skip)
  3592. continue;
  3593. /*
  3594. * grow the nodeTab if needed
  3595. */
  3596. if (val1->nodeMax == 0) {
  3597. val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
  3598. sizeof(xmlNodePtr));
  3599. if (val1->nodeTab == NULL) {
  3600. xmlXPathErrMemory(NULL, "merging nodeset\n");
  3601. return(NULL);
  3602. }
  3603. memset(val1->nodeTab, 0 ,
  3604. XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
  3605. val1->nodeMax = XML_NODESET_DEFAULT;
  3606. } else if (val1->nodeNr == val1->nodeMax) {
  3607. xmlNodePtr *temp;
  3608. if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
  3609. xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
  3610. return(NULL);
  3611. }
  3612. temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
  3613. sizeof(xmlNodePtr));
  3614. if (temp == NULL) {
  3615. xmlXPathErrMemory(NULL, "merging nodeset\n");
  3616. return(NULL);
  3617. }
  3618. val1->nodeTab = temp;
  3619. val1->nodeMax *= 2;
  3620. }
  3621. if (n2->type == XML_NAMESPACE_DECL) {
  3622. xmlNsPtr ns = (xmlNsPtr) n2;
  3623. /* TODO: Check memory error. */
  3624. val1->nodeTab[val1->nodeNr++] =
  3625. xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
  3626. } else
  3627. val1->nodeTab[val1->nodeNr++] = n2;
  3628. }
  3629. return(val1);
  3630. }
  3631. /**
  3632. * xmlXPathNodeSetMergeAndClear:
  3633. * @set1: the first NodeSet or NULL
  3634. * @set2: the second NodeSet
  3635. *
  3636. * Merges two nodesets, all nodes from @set2 are added to @set1.
  3637. * Checks for duplicate nodes. Clears set2.
  3638. *
  3639. * Returns @set1 once extended or NULL in case of error.
  3640. */
  3641. static xmlNodeSetPtr
  3642. xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
  3643. {
  3644. {
  3645. int i, j, initNbSet1;
  3646. xmlNodePtr n1, n2;
  3647. initNbSet1 = set1->nodeNr;
  3648. for (i = 0;i < set2->nodeNr;i++) {
  3649. n2 = set2->nodeTab[i];
  3650. /*
  3651. * Skip duplicates.
  3652. */
  3653. for (j = 0; j < initNbSet1; j++) {
  3654. n1 = set1->nodeTab[j];
  3655. if (n1 == n2) {
  3656. goto skip_node;
  3657. } else if ((n1->type == XML_NAMESPACE_DECL) &&
  3658. (n2->type == XML_NAMESPACE_DECL))
  3659. {
  3660. if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
  3661. (xmlStrEqual(((xmlNsPtr) n1)->prefix,
  3662. ((xmlNsPtr) n2)->prefix)))
  3663. {
  3664. /*
  3665. * Free the namespace node.
  3666. */
  3667. set2->nodeTab[i] = NULL;
  3668. xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
  3669. goto skip_node;
  3670. }
  3671. }
  3672. }
  3673. /*
  3674. * grow the nodeTab if needed
  3675. */
  3676. if (set1->nodeMax == 0) {
  3677. set1->nodeTab = (xmlNodePtr *) xmlMalloc(
  3678. XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
  3679. if (set1->nodeTab == NULL) {
  3680. xmlXPathErrMemory(NULL, "merging nodeset\n");
  3681. return(NULL);
  3682. }
  3683. memset(set1->nodeTab, 0,
  3684. XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
  3685. set1->nodeMax = XML_NODESET_DEFAULT;
  3686. } else if (set1->nodeNr >= set1->nodeMax) {
  3687. xmlNodePtr *temp;
  3688. if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
  3689. xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
  3690. return(NULL);
  3691. }
  3692. temp = (xmlNodePtr *) xmlRealloc(
  3693. set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
  3694. if (temp == NULL) {
  3695. xmlXPathErrMemory(NULL, "merging nodeset\n");
  3696. return(NULL);
  3697. }
  3698. set1->nodeTab = temp;
  3699. set1->nodeMax *= 2;
  3700. }
  3701. set1->nodeTab[set1->nodeNr++] = n2;
  3702. skip_node:
  3703. {}
  3704. }
  3705. }
  3706. set2->nodeNr = 0;
  3707. return(set1);
  3708. }
  3709. /**
  3710. * xmlXPathNodeSetMergeAndClearNoDupls:
  3711. * @set1: the first NodeSet or NULL
  3712. * @set2: the second NodeSet
  3713. *
  3714. * Merges two nodesets, all nodes from @set2 are added to @set1.
  3715. * Doesn't check for duplicate nodes. Clears set2.
  3716. *
  3717. * Returns @set1 once extended or NULL in case of error.
  3718. */
  3719. static xmlNodeSetPtr
  3720. xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
  3721. {
  3722. {
  3723. int i;
  3724. xmlNodePtr n2;
  3725. for (i = 0;i < set2->nodeNr;i++) {
  3726. n2 = set2->nodeTab[i];
  3727. if (set1->nodeMax == 0) {
  3728. set1->nodeTab = (xmlNodePtr *) xmlMalloc(
  3729. XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
  3730. if (set1->nodeTab == NULL) {
  3731. xmlXPathErrMemory(NULL, "merging nodeset\n");
  3732. return(NULL);
  3733. }
  3734. memset(set1->nodeTab, 0,
  3735. XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
  3736. set1->nodeMax = XML_NODESET_DEFAULT;
  3737. } else if (set1->nodeNr >= set1->nodeMax) {
  3738. xmlNodePtr *temp;
  3739. if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
  3740. xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
  3741. return(NULL);
  3742. }
  3743. temp = (xmlNodePtr *) xmlRealloc(
  3744. set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
  3745. if (temp == NULL) {
  3746. xmlXPathErrMemory(NULL, "merging nodeset\n");
  3747. return(NULL);
  3748. }
  3749. set1->nodeTab = temp;
  3750. set1->nodeMax *= 2;
  3751. }
  3752. set1->nodeTab[set1->nodeNr++] = n2;
  3753. }
  3754. }
  3755. set2->nodeNr = 0;
  3756. return(set1);
  3757. }
  3758. /**
  3759. * xmlXPathNodeSetDel:
  3760. * @cur: the initial node set
  3761. * @val: an xmlNodePtr
  3762. *
  3763. * Removes an xmlNodePtr from an existing NodeSet
  3764. */
  3765. void
  3766. xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
  3767. int i;
  3768. if (cur == NULL) return;
  3769. if (val == NULL) return;
  3770. /*
  3771. * find node in nodeTab
  3772. */
  3773. for (i = 0;i < cur->nodeNr;i++)
  3774. if (cur->nodeTab[i] == val) break;
  3775. if (i >= cur->nodeNr) { /* not found */
  3776. #ifdef DEBUG
  3777. xmlGenericError(xmlGenericErrorContext,
  3778. "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
  3779. val->name);
  3780. #endif
  3781. return;
  3782. }
  3783. if ((cur->nodeTab[i] != NULL) &&
  3784. (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
  3785. xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
  3786. cur->nodeNr--;
  3787. for (;i < cur->nodeNr;i++)
  3788. cur->nodeTab[i] = cur->nodeTab[i + 1];
  3789. cur->nodeTab[cur->nodeNr] = NULL;
  3790. }
  3791. /**
  3792. * xmlXPathNodeSetRemove:
  3793. * @cur: the initial node set
  3794. * @val: the index to remove
  3795. *
  3796. * Removes an entry from an existing NodeSet list.
  3797. */
  3798. void
  3799. xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
  3800. if (cur == NULL) return;
  3801. if (val >= cur->nodeNr) return;
  3802. if ((cur->nodeTab[val] != NULL) &&
  3803. (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
  3804. xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
  3805. cur->nodeNr--;
  3806. for (;val < cur->nodeNr;val++)
  3807. cur->nodeTab[val] = cur->nodeTab[val + 1];
  3808. cur->nodeTab[cur->nodeNr] = NULL;
  3809. }
  3810. /**
  3811. * xmlXPathFreeNodeSet:
  3812. * @obj: the xmlNodeSetPtr to free
  3813. *
  3814. * Free the NodeSet compound (not the actual nodes !).
  3815. */
  3816. void
  3817. xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
  3818. if (obj == NULL) return;
  3819. if (obj->nodeTab != NULL) {
  3820. int i;
  3821. /* @@ with_ns to check whether namespace nodes should be looked at @@ */
  3822. for (i = 0;i < obj->nodeNr;i++)
  3823. if ((obj->nodeTab[i] != NULL) &&
  3824. (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
  3825. xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
  3826. xmlFree(obj->nodeTab);
  3827. }
  3828. xmlFree(obj);
  3829. }
  3830. /**
  3831. * xmlXPathNodeSetClearFromPos:
  3832. * @set: the node set to be cleared
  3833. * @pos: the start position to clear from
  3834. *
  3835. * Clears the list from temporary XPath objects (e.g. namespace nodes
  3836. * are feed) starting with the entry at @pos, but does *not* free the list
  3837. * itself. Sets the length of the list to @pos.
  3838. */
  3839. static void
  3840. xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
  3841. {
  3842. if ((set == NULL) || (pos >= set->nodeNr))
  3843. return;
  3844. else if ((hasNsNodes)) {
  3845. int i;
  3846. xmlNodePtr node;
  3847. for (i = pos; i < set->nodeNr; i++) {
  3848. node = set->nodeTab[i];
  3849. if ((node != NULL) &&
  3850. (node->type == XML_NAMESPACE_DECL))
  3851. xmlXPathNodeSetFreeNs((xmlNsPtr) node);
  3852. }
  3853. }
  3854. set->nodeNr = pos;
  3855. }
  3856. /**
  3857. * xmlXPathNodeSetClear:
  3858. * @set: the node set to clear
  3859. *
  3860. * Clears the list from all temporary XPath objects (e.g. namespace nodes
  3861. * are feed), but does *not* free the list itself. Sets the length of the
  3862. * list to 0.
  3863. */
  3864. static void
  3865. xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
  3866. {
  3867. xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
  3868. }
  3869. /**
  3870. * xmlXPathNodeSetKeepLast:
  3871. * @set: the node set to be cleared
  3872. *
  3873. * Move the last node to the first position and clear temporary XPath objects
  3874. * (e.g. namespace nodes) from all other nodes. Sets the length of the list
  3875. * to 1.
  3876. */
  3877. static void
  3878. xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
  3879. {
  3880. int i;
  3881. xmlNodePtr node;
  3882. if ((set == NULL) || (set->nodeNr <= 1))
  3883. return;
  3884. for (i = 0; i < set->nodeNr - 1; i++) {
  3885. node = set->nodeTab[i];
  3886. if ((node != NULL) &&
  3887. (node->type == XML_NAMESPACE_DECL))
  3888. xmlXPathNodeSetFreeNs((xmlNsPtr) node);
  3889. }
  3890. set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
  3891. set->nodeNr = 1;
  3892. }
  3893. /**
  3894. * xmlXPathFreeValueTree:
  3895. * @obj: the xmlNodeSetPtr to free
  3896. *
  3897. * Free the NodeSet compound and the actual tree, this is different
  3898. * from xmlXPathFreeNodeSet()
  3899. */
  3900. static void
  3901. xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
  3902. int i;
  3903. if (obj == NULL) return;
  3904. if (obj->nodeTab != NULL) {
  3905. for (i = 0;i < obj->nodeNr;i++) {
  3906. if (obj->nodeTab[i] != NULL) {
  3907. if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
  3908. xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
  3909. } else {
  3910. xmlFreeNodeList(obj->nodeTab[i]);
  3911. }
  3912. }
  3913. }
  3914. xmlFree(obj->nodeTab);
  3915. }
  3916. xmlFree(obj);
  3917. }
  3918. #if defined(DEBUG) || defined(DEBUG_STEP)
  3919. /**
  3920. * xmlGenericErrorContextNodeSet:
  3921. * @output: a FILE * for the output
  3922. * @obj: the xmlNodeSetPtr to display
  3923. *
  3924. * Quick display of a NodeSet
  3925. */
  3926. void
  3927. xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
  3928. int i;
  3929. if (output == NULL) output = xmlGenericErrorContext;
  3930. if (obj == NULL) {
  3931. fprintf(output, "NodeSet == NULL !\n");
  3932. return;
  3933. }
  3934. if (obj->nodeNr == 0) {
  3935. fprintf(output, "NodeSet is empty\n");
  3936. return;
  3937. }
  3938. if (obj->nodeTab == NULL) {
  3939. fprintf(output, " nodeTab == NULL !\n");
  3940. return;
  3941. }
  3942. for (i = 0; i < obj->nodeNr; i++) {
  3943. if (obj->nodeTab[i] == NULL) {
  3944. fprintf(output, " NULL !\n");
  3945. return;
  3946. }
  3947. if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
  3948. (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
  3949. fprintf(output, " /");
  3950. else if (obj->nodeTab[i]->name == NULL)
  3951. fprintf(output, " noname!");
  3952. else fprintf(output, " %s", obj->nodeTab[i]->name);
  3953. }
  3954. fprintf(output, "\n");
  3955. }
  3956. #endif
  3957. /**
  3958. * xmlXPathNewNodeSet:
  3959. * @val: the NodePtr value
  3960. *
  3961. * Create a new xmlXPathObjectPtr of type NodeSet and initialize
  3962. * it with the single Node @val
  3963. *
  3964. * Returns the newly created object.
  3965. */
  3966. xmlXPathObjectPtr
  3967. xmlXPathNewNodeSet(xmlNodePtr val) {
  3968. xmlXPathObjectPtr ret;
  3969. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  3970. if (ret == NULL) {
  3971. xmlXPathErrMemory(NULL, "creating nodeset\n");
  3972. return(NULL);
  3973. }
  3974. memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  3975. ret->type = XPATH_NODESET;
  3976. ret->boolval = 0;
  3977. /* TODO: Check memory error. */
  3978. ret->nodesetval = xmlXPathNodeSetCreate(val);
  3979. /* @@ with_ns to check whether namespace nodes should be looked at @@ */
  3980. #ifdef XP_DEBUG_OBJ_USAGE
  3981. xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
  3982. #endif
  3983. return(ret);
  3984. }
  3985. /**
  3986. * xmlXPathNewValueTree:
  3987. * @val: the NodePtr value
  3988. *
  3989. * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
  3990. * it with the tree root @val
  3991. *
  3992. * Returns the newly created object.
  3993. */
  3994. xmlXPathObjectPtr
  3995. xmlXPathNewValueTree(xmlNodePtr val) {
  3996. xmlXPathObjectPtr ret;
  3997. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  3998. if (ret == NULL) {
  3999. xmlXPathErrMemory(NULL, "creating result value tree\n");
  4000. return(NULL);
  4001. }
  4002. memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  4003. ret->type = XPATH_XSLT_TREE;
  4004. ret->boolval = 1;
  4005. ret->user = (void *) val;
  4006. ret->nodesetval = xmlXPathNodeSetCreate(val);
  4007. #ifdef XP_DEBUG_OBJ_USAGE
  4008. xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
  4009. #endif
  4010. return(ret);
  4011. }
  4012. /**
  4013. * xmlXPathNewNodeSetList:
  4014. * @val: an existing NodeSet
  4015. *
  4016. * Create a new xmlXPathObjectPtr of type NodeSet and initialize
  4017. * it with the Nodeset @val
  4018. *
  4019. * Returns the newly created object.
  4020. */
  4021. xmlXPathObjectPtr
  4022. xmlXPathNewNodeSetList(xmlNodeSetPtr val)
  4023. {
  4024. xmlXPathObjectPtr ret;
  4025. int i;
  4026. if (val == NULL)
  4027. ret = NULL;
  4028. else if (val->nodeTab == NULL)
  4029. ret = xmlXPathNewNodeSet(NULL);
  4030. else {
  4031. ret = xmlXPathNewNodeSet(val->nodeTab[0]);
  4032. if (ret) {
  4033. for (i = 1; i < val->nodeNr; ++i) {
  4034. /* TODO: Propagate memory error. */
  4035. if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
  4036. < 0) break;
  4037. }
  4038. }
  4039. }
  4040. return (ret);
  4041. }
  4042. /**
  4043. * xmlXPathWrapNodeSet:
  4044. * @val: the NodePtr value
  4045. *
  4046. * Wrap the Nodeset @val in a new xmlXPathObjectPtr
  4047. *
  4048. * Returns the newly created object.
  4049. */
  4050. xmlXPathObjectPtr
  4051. xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
  4052. xmlXPathObjectPtr ret;
  4053. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4054. if (ret == NULL) {
  4055. xmlXPathErrMemory(NULL, "creating node set object\n");
  4056. return(NULL);
  4057. }
  4058. memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  4059. ret->type = XPATH_NODESET;
  4060. ret->nodesetval = val;
  4061. #ifdef XP_DEBUG_OBJ_USAGE
  4062. xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
  4063. #endif
  4064. return(ret);
  4065. }
  4066. /**
  4067. * xmlXPathFreeNodeSetList:
  4068. * @obj: an existing NodeSetList object
  4069. *
  4070. * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
  4071. * the list contrary to xmlXPathFreeObject().
  4072. */
  4073. void
  4074. xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
  4075. if (obj == NULL) return;
  4076. #ifdef XP_DEBUG_OBJ_USAGE
  4077. xmlXPathDebugObjUsageReleased(NULL, obj->type);
  4078. #endif
  4079. xmlFree(obj);
  4080. }
  4081. /**
  4082. * xmlXPathDifference:
  4083. * @nodes1: a node-set
  4084. * @nodes2: a node-set
  4085. *
  4086. * Implements the EXSLT - Sets difference() function:
  4087. * node-set set:difference (node-set, node-set)
  4088. *
  4089. * Returns the difference between the two node sets, or nodes1 if
  4090. * nodes2 is empty
  4091. */
  4092. xmlNodeSetPtr
  4093. xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  4094. xmlNodeSetPtr ret;
  4095. int i, l1;
  4096. xmlNodePtr cur;
  4097. if (xmlXPathNodeSetIsEmpty(nodes2))
  4098. return(nodes1);
  4099. /* TODO: Check memory error. */
  4100. ret = xmlXPathNodeSetCreate(NULL);
  4101. if (xmlXPathNodeSetIsEmpty(nodes1))
  4102. return(ret);
  4103. l1 = xmlXPathNodeSetGetLength(nodes1);
  4104. for (i = 0; i < l1; i++) {
  4105. cur = xmlXPathNodeSetItem(nodes1, i);
  4106. if (!xmlXPathNodeSetContains(nodes2, cur)) {
  4107. /* TODO: Propagate memory error. */
  4108. if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
  4109. break;
  4110. }
  4111. }
  4112. return(ret);
  4113. }
  4114. /**
  4115. * xmlXPathIntersection:
  4116. * @nodes1: a node-set
  4117. * @nodes2: a node-set
  4118. *
  4119. * Implements the EXSLT - Sets intersection() function:
  4120. * node-set set:intersection (node-set, node-set)
  4121. *
  4122. * Returns a node set comprising the nodes that are within both the
  4123. * node sets passed as arguments
  4124. */
  4125. xmlNodeSetPtr
  4126. xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  4127. xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
  4128. int i, l1;
  4129. xmlNodePtr cur;
  4130. if (ret == NULL)
  4131. return(ret);
  4132. if (xmlXPathNodeSetIsEmpty(nodes1))
  4133. return(ret);
  4134. if (xmlXPathNodeSetIsEmpty(nodes2))
  4135. return(ret);
  4136. l1 = xmlXPathNodeSetGetLength(nodes1);
  4137. for (i = 0; i < l1; i++) {
  4138. cur = xmlXPathNodeSetItem(nodes1, i);
  4139. if (xmlXPathNodeSetContains(nodes2, cur)) {
  4140. /* TODO: Propagate memory error. */
  4141. if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
  4142. break;
  4143. }
  4144. }
  4145. return(ret);
  4146. }
  4147. /**
  4148. * xmlXPathDistinctSorted:
  4149. * @nodes: a node-set, sorted by document order
  4150. *
  4151. * Implements the EXSLT - Sets distinct() function:
  4152. * node-set set:distinct (node-set)
  4153. *
  4154. * Returns a subset of the nodes contained in @nodes, or @nodes if
  4155. * it is empty
  4156. */
  4157. xmlNodeSetPtr
  4158. xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
  4159. xmlNodeSetPtr ret;
  4160. xmlHashTablePtr hash;
  4161. int i, l;
  4162. xmlChar * strval;
  4163. xmlNodePtr cur;
  4164. if (xmlXPathNodeSetIsEmpty(nodes))
  4165. return(nodes);
  4166. ret = xmlXPathNodeSetCreate(NULL);
  4167. if (ret == NULL)
  4168. return(ret);
  4169. l = xmlXPathNodeSetGetLength(nodes);
  4170. hash = xmlHashCreate (l);
  4171. for (i = 0; i < l; i++) {
  4172. cur = xmlXPathNodeSetItem(nodes, i);
  4173. strval = xmlXPathCastNodeToString(cur);
  4174. if (xmlHashLookup(hash, strval) == NULL) {
  4175. xmlHashAddEntry(hash, strval, strval);
  4176. /* TODO: Propagate memory error. */
  4177. if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
  4178. break;
  4179. } else {
  4180. xmlFree(strval);
  4181. }
  4182. }
  4183. xmlHashFree(hash, xmlHashDefaultDeallocator);
  4184. return(ret);
  4185. }
  4186. /**
  4187. * xmlXPathDistinct:
  4188. * @nodes: a node-set
  4189. *
  4190. * Implements the EXSLT - Sets distinct() function:
  4191. * node-set set:distinct (node-set)
  4192. * @nodes is sorted by document order, then #exslSetsDistinctSorted
  4193. * is called with the sorted node-set
  4194. *
  4195. * Returns a subset of the nodes contained in @nodes, or @nodes if
  4196. * it is empty
  4197. */
  4198. xmlNodeSetPtr
  4199. xmlXPathDistinct (xmlNodeSetPtr nodes) {
  4200. if (xmlXPathNodeSetIsEmpty(nodes))
  4201. return(nodes);
  4202. xmlXPathNodeSetSort(nodes);
  4203. return(xmlXPathDistinctSorted(nodes));
  4204. }
  4205. /**
  4206. * xmlXPathHasSameNodes:
  4207. * @nodes1: a node-set
  4208. * @nodes2: a node-set
  4209. *
  4210. * Implements the EXSLT - Sets has-same-nodes function:
  4211. * boolean set:has-same-node(node-set, node-set)
  4212. *
  4213. * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
  4214. * otherwise
  4215. */
  4216. int
  4217. xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  4218. int i, l;
  4219. xmlNodePtr cur;
  4220. if (xmlXPathNodeSetIsEmpty(nodes1) ||
  4221. xmlXPathNodeSetIsEmpty(nodes2))
  4222. return(0);
  4223. l = xmlXPathNodeSetGetLength(nodes1);
  4224. for (i = 0; i < l; i++) {
  4225. cur = xmlXPathNodeSetItem(nodes1, i);
  4226. if (xmlXPathNodeSetContains(nodes2, cur))
  4227. return(1);
  4228. }
  4229. return(0);
  4230. }
  4231. /**
  4232. * xmlXPathNodeLeadingSorted:
  4233. * @nodes: a node-set, sorted by document order
  4234. * @node: a node
  4235. *
  4236. * Implements the EXSLT - Sets leading() function:
  4237. * node-set set:leading (node-set, node-set)
  4238. *
  4239. * Returns the nodes in @nodes that precede @node in document order,
  4240. * @nodes if @node is NULL or an empty node-set if @nodes
  4241. * doesn't contain @node
  4242. */
  4243. xmlNodeSetPtr
  4244. xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
  4245. int i, l;
  4246. xmlNodePtr cur;
  4247. xmlNodeSetPtr ret;
  4248. if (node == NULL)
  4249. return(nodes);
  4250. ret = xmlXPathNodeSetCreate(NULL);
  4251. if (ret == NULL)
  4252. return(ret);
  4253. if (xmlXPathNodeSetIsEmpty(nodes) ||
  4254. (!xmlXPathNodeSetContains(nodes, node)))
  4255. return(ret);
  4256. l = xmlXPathNodeSetGetLength(nodes);
  4257. for (i = 0; i < l; i++) {
  4258. cur = xmlXPathNodeSetItem(nodes, i);
  4259. if (cur == node)
  4260. break;
  4261. /* TODO: Propagate memory error. */
  4262. if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
  4263. break;
  4264. }
  4265. return(ret);
  4266. }
  4267. /**
  4268. * xmlXPathNodeLeading:
  4269. * @nodes: a node-set
  4270. * @node: a node
  4271. *
  4272. * Implements the EXSLT - Sets leading() function:
  4273. * node-set set:leading (node-set, node-set)
  4274. * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
  4275. * is called.
  4276. *
  4277. * Returns the nodes in @nodes that precede @node in document order,
  4278. * @nodes if @node is NULL or an empty node-set if @nodes
  4279. * doesn't contain @node
  4280. */
  4281. xmlNodeSetPtr
  4282. xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
  4283. xmlXPathNodeSetSort(nodes);
  4284. return(xmlXPathNodeLeadingSorted(nodes, node));
  4285. }
  4286. /**
  4287. * xmlXPathLeadingSorted:
  4288. * @nodes1: a node-set, sorted by document order
  4289. * @nodes2: a node-set, sorted by document order
  4290. *
  4291. * Implements the EXSLT - Sets leading() function:
  4292. * node-set set:leading (node-set, node-set)
  4293. *
  4294. * Returns the nodes in @nodes1 that precede the first node in @nodes2
  4295. * in document order, @nodes1 if @nodes2 is NULL or empty or
  4296. * an empty node-set if @nodes1 doesn't contain @nodes2
  4297. */
  4298. xmlNodeSetPtr
  4299. xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  4300. if (xmlXPathNodeSetIsEmpty(nodes2))
  4301. return(nodes1);
  4302. return(xmlXPathNodeLeadingSorted(nodes1,
  4303. xmlXPathNodeSetItem(nodes2, 1)));
  4304. }
  4305. /**
  4306. * xmlXPathLeading:
  4307. * @nodes1: a node-set
  4308. * @nodes2: a node-set
  4309. *
  4310. * Implements the EXSLT - Sets leading() function:
  4311. * node-set set:leading (node-set, node-set)
  4312. * @nodes1 and @nodes2 are sorted by document order, then
  4313. * #exslSetsLeadingSorted is called.
  4314. *
  4315. * Returns the nodes in @nodes1 that precede the first node in @nodes2
  4316. * in document order, @nodes1 if @nodes2 is NULL or empty or
  4317. * an empty node-set if @nodes1 doesn't contain @nodes2
  4318. */
  4319. xmlNodeSetPtr
  4320. xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  4321. if (xmlXPathNodeSetIsEmpty(nodes2))
  4322. return(nodes1);
  4323. if (xmlXPathNodeSetIsEmpty(nodes1))
  4324. return(xmlXPathNodeSetCreate(NULL));
  4325. xmlXPathNodeSetSort(nodes1);
  4326. xmlXPathNodeSetSort(nodes2);
  4327. return(xmlXPathNodeLeadingSorted(nodes1,
  4328. xmlXPathNodeSetItem(nodes2, 1)));
  4329. }
  4330. /**
  4331. * xmlXPathNodeTrailingSorted:
  4332. * @nodes: a node-set, sorted by document order
  4333. * @node: a node
  4334. *
  4335. * Implements the EXSLT - Sets trailing() function:
  4336. * node-set set:trailing (node-set, node-set)
  4337. *
  4338. * Returns the nodes in @nodes that follow @node in document order,
  4339. * @nodes if @node is NULL or an empty node-set if @nodes
  4340. * doesn't contain @node
  4341. */
  4342. xmlNodeSetPtr
  4343. xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
  4344. int i, l;
  4345. xmlNodePtr cur;
  4346. xmlNodeSetPtr ret;
  4347. if (node == NULL)
  4348. return(nodes);
  4349. ret = xmlXPathNodeSetCreate(NULL);
  4350. if (ret == NULL)
  4351. return(ret);
  4352. if (xmlXPathNodeSetIsEmpty(nodes) ||
  4353. (!xmlXPathNodeSetContains(nodes, node)))
  4354. return(ret);
  4355. l = xmlXPathNodeSetGetLength(nodes);
  4356. for (i = l - 1; i >= 0; i--) {
  4357. cur = xmlXPathNodeSetItem(nodes, i);
  4358. if (cur == node)
  4359. break;
  4360. /* TODO: Propagate memory error. */
  4361. if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
  4362. break;
  4363. }
  4364. xmlXPathNodeSetSort(ret); /* bug 413451 */
  4365. return(ret);
  4366. }
  4367. /**
  4368. * xmlXPathNodeTrailing:
  4369. * @nodes: a node-set
  4370. * @node: a node
  4371. *
  4372. * Implements the EXSLT - Sets trailing() function:
  4373. * node-set set:trailing (node-set, node-set)
  4374. * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
  4375. * is called.
  4376. *
  4377. * Returns the nodes in @nodes that follow @node in document order,
  4378. * @nodes if @node is NULL or an empty node-set if @nodes
  4379. * doesn't contain @node
  4380. */
  4381. xmlNodeSetPtr
  4382. xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
  4383. xmlXPathNodeSetSort(nodes);
  4384. return(xmlXPathNodeTrailingSorted(nodes, node));
  4385. }
  4386. /**
  4387. * xmlXPathTrailingSorted:
  4388. * @nodes1: a node-set, sorted by document order
  4389. * @nodes2: a node-set, sorted by document order
  4390. *
  4391. * Implements the EXSLT - Sets trailing() function:
  4392. * node-set set:trailing (node-set, node-set)
  4393. *
  4394. * Returns the nodes in @nodes1 that follow the first node in @nodes2
  4395. * in document order, @nodes1 if @nodes2 is NULL or empty or
  4396. * an empty node-set if @nodes1 doesn't contain @nodes2
  4397. */
  4398. xmlNodeSetPtr
  4399. xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  4400. if (xmlXPathNodeSetIsEmpty(nodes2))
  4401. return(nodes1);
  4402. return(xmlXPathNodeTrailingSorted(nodes1,
  4403. xmlXPathNodeSetItem(nodes2, 0)));
  4404. }
  4405. /**
  4406. * xmlXPathTrailing:
  4407. * @nodes1: a node-set
  4408. * @nodes2: a node-set
  4409. *
  4410. * Implements the EXSLT - Sets trailing() function:
  4411. * node-set set:trailing (node-set, node-set)
  4412. * @nodes1 and @nodes2 are sorted by document order, then
  4413. * #xmlXPathTrailingSorted is called.
  4414. *
  4415. * Returns the nodes in @nodes1 that follow the first node in @nodes2
  4416. * in document order, @nodes1 if @nodes2 is NULL or empty or
  4417. * an empty node-set if @nodes1 doesn't contain @nodes2
  4418. */
  4419. xmlNodeSetPtr
  4420. xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  4421. if (xmlXPathNodeSetIsEmpty(nodes2))
  4422. return(nodes1);
  4423. if (xmlXPathNodeSetIsEmpty(nodes1))
  4424. return(xmlXPathNodeSetCreate(NULL));
  4425. xmlXPathNodeSetSort(nodes1);
  4426. xmlXPathNodeSetSort(nodes2);
  4427. return(xmlXPathNodeTrailingSorted(nodes1,
  4428. xmlXPathNodeSetItem(nodes2, 0)));
  4429. }
  4430. /************************************************************************
  4431. * *
  4432. * Routines to handle extra functions *
  4433. * *
  4434. ************************************************************************/
  4435. /**
  4436. * xmlXPathRegisterFunc:
  4437. * @ctxt: the XPath context
  4438. * @name: the function name
  4439. * @f: the function implementation or NULL
  4440. *
  4441. * Register a new function. If @f is NULL it unregisters the function
  4442. *
  4443. * Returns 0 in case of success, -1 in case of error
  4444. */
  4445. int
  4446. xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
  4447. xmlXPathFunction f) {
  4448. return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
  4449. }
  4450. /**
  4451. * xmlXPathRegisterFuncNS:
  4452. * @ctxt: the XPath context
  4453. * @name: the function name
  4454. * @ns_uri: the function namespace URI
  4455. * @f: the function implementation or NULL
  4456. *
  4457. * Register a new function. If @f is NULL it unregisters the function
  4458. *
  4459. * Returns 0 in case of success, -1 in case of error
  4460. */
  4461. int
  4462. xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
  4463. const xmlChar *ns_uri, xmlXPathFunction f) {
  4464. if (ctxt == NULL)
  4465. return(-1);
  4466. if (name == NULL)
  4467. return(-1);
  4468. if (ctxt->funcHash == NULL)
  4469. ctxt->funcHash = xmlHashCreate(0);
  4470. if (ctxt->funcHash == NULL)
  4471. return(-1);
  4472. if (f == NULL)
  4473. return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
  4474. XML_IGNORE_PEDANTIC_WARNINGS
  4475. return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
  4476. XML_POP_WARNINGS
  4477. }
  4478. /**
  4479. * xmlXPathRegisterFuncLookup:
  4480. * @ctxt: the XPath context
  4481. * @f: the lookup function
  4482. * @funcCtxt: the lookup data
  4483. *
  4484. * Registers an external mechanism to do function lookup.
  4485. */
  4486. void
  4487. xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
  4488. xmlXPathFuncLookupFunc f,
  4489. void *funcCtxt) {
  4490. if (ctxt == NULL)
  4491. return;
  4492. ctxt->funcLookupFunc = f;
  4493. ctxt->funcLookupData = funcCtxt;
  4494. }
  4495. /**
  4496. * xmlXPathFunctionLookup:
  4497. * @ctxt: the XPath context
  4498. * @name: the function name
  4499. *
  4500. * Search in the Function array of the context for the given
  4501. * function.
  4502. *
  4503. * Returns the xmlXPathFunction or NULL if not found
  4504. */
  4505. xmlXPathFunction
  4506. xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
  4507. if (ctxt == NULL)
  4508. return (NULL);
  4509. if (ctxt->funcLookupFunc != NULL) {
  4510. xmlXPathFunction ret;
  4511. xmlXPathFuncLookupFunc f;
  4512. f = ctxt->funcLookupFunc;
  4513. ret = f(ctxt->funcLookupData, name, NULL);
  4514. if (ret != NULL)
  4515. return(ret);
  4516. }
  4517. return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
  4518. }
  4519. /**
  4520. * xmlXPathFunctionLookupNS:
  4521. * @ctxt: the XPath context
  4522. * @name: the function name
  4523. * @ns_uri: the function namespace URI
  4524. *
  4525. * Search in the Function array of the context for the given
  4526. * function.
  4527. *
  4528. * Returns the xmlXPathFunction or NULL if not found
  4529. */
  4530. xmlXPathFunction
  4531. xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
  4532. const xmlChar *ns_uri) {
  4533. xmlXPathFunction ret;
  4534. if (ctxt == NULL)
  4535. return(NULL);
  4536. if (name == NULL)
  4537. return(NULL);
  4538. if (ctxt->funcLookupFunc != NULL) {
  4539. xmlXPathFuncLookupFunc f;
  4540. f = ctxt->funcLookupFunc;
  4541. ret = f(ctxt->funcLookupData, name, ns_uri);
  4542. if (ret != NULL)
  4543. return(ret);
  4544. }
  4545. if (ctxt->funcHash == NULL)
  4546. return(NULL);
  4547. XML_IGNORE_PEDANTIC_WARNINGS
  4548. ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
  4549. XML_POP_WARNINGS
  4550. return(ret);
  4551. }
  4552. /**
  4553. * xmlXPathRegisteredFuncsCleanup:
  4554. * @ctxt: the XPath context
  4555. *
  4556. * Cleanup the XPath context data associated to registered functions
  4557. */
  4558. void
  4559. xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
  4560. if (ctxt == NULL)
  4561. return;
  4562. xmlHashFree(ctxt->funcHash, NULL);
  4563. ctxt->funcHash = NULL;
  4564. }
  4565. /************************************************************************
  4566. * *
  4567. * Routines to handle Variables *
  4568. * *
  4569. ************************************************************************/
  4570. /**
  4571. * xmlXPathRegisterVariable:
  4572. * @ctxt: the XPath context
  4573. * @name: the variable name
  4574. * @value: the variable value or NULL
  4575. *
  4576. * Register a new variable value. If @value is NULL it unregisters
  4577. * the variable
  4578. *
  4579. * Returns 0 in case of success, -1 in case of error
  4580. */
  4581. int
  4582. xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
  4583. xmlXPathObjectPtr value) {
  4584. return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
  4585. }
  4586. /**
  4587. * xmlXPathRegisterVariableNS:
  4588. * @ctxt: the XPath context
  4589. * @name: the variable name
  4590. * @ns_uri: the variable namespace URI
  4591. * @value: the variable value or NULL
  4592. *
  4593. * Register a new variable value. If @value is NULL it unregisters
  4594. * the variable
  4595. *
  4596. * Returns 0 in case of success, -1 in case of error
  4597. */
  4598. int
  4599. xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
  4600. const xmlChar *ns_uri,
  4601. xmlXPathObjectPtr value) {
  4602. if (ctxt == NULL)
  4603. return(-1);
  4604. if (name == NULL)
  4605. return(-1);
  4606. if (ctxt->varHash == NULL)
  4607. ctxt->varHash = xmlHashCreate(0);
  4608. if (ctxt->varHash == NULL)
  4609. return(-1);
  4610. if (value == NULL)
  4611. return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
  4612. xmlXPathFreeObjectEntry));
  4613. return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
  4614. (void *) value, xmlXPathFreeObjectEntry));
  4615. }
  4616. /**
  4617. * xmlXPathRegisterVariableLookup:
  4618. * @ctxt: the XPath context
  4619. * @f: the lookup function
  4620. * @data: the lookup data
  4621. *
  4622. * register an external mechanism to do variable lookup
  4623. */
  4624. void
  4625. xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
  4626. xmlXPathVariableLookupFunc f, void *data) {
  4627. if (ctxt == NULL)
  4628. return;
  4629. ctxt->varLookupFunc = f;
  4630. ctxt->varLookupData = data;
  4631. }
  4632. /**
  4633. * xmlXPathVariableLookup:
  4634. * @ctxt: the XPath context
  4635. * @name: the variable name
  4636. *
  4637. * Search in the Variable array of the context for the given
  4638. * variable value.
  4639. *
  4640. * Returns a copy of the value or NULL if not found
  4641. */
  4642. xmlXPathObjectPtr
  4643. xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
  4644. if (ctxt == NULL)
  4645. return(NULL);
  4646. if (ctxt->varLookupFunc != NULL) {
  4647. xmlXPathObjectPtr ret;
  4648. ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
  4649. (ctxt->varLookupData, name, NULL);
  4650. return(ret);
  4651. }
  4652. return(xmlXPathVariableLookupNS(ctxt, name, NULL));
  4653. }
  4654. /**
  4655. * xmlXPathVariableLookupNS:
  4656. * @ctxt: the XPath context
  4657. * @name: the variable name
  4658. * @ns_uri: the variable namespace URI
  4659. *
  4660. * Search in the Variable array of the context for the given
  4661. * variable value.
  4662. *
  4663. * Returns the a copy of the value or NULL if not found
  4664. */
  4665. xmlXPathObjectPtr
  4666. xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
  4667. const xmlChar *ns_uri) {
  4668. if (ctxt == NULL)
  4669. return(NULL);
  4670. if (ctxt->varLookupFunc != NULL) {
  4671. xmlXPathObjectPtr ret;
  4672. ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
  4673. (ctxt->varLookupData, name, ns_uri);
  4674. if (ret != NULL) return(ret);
  4675. }
  4676. if (ctxt->varHash == NULL)
  4677. return(NULL);
  4678. if (name == NULL)
  4679. return(NULL);
  4680. return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
  4681. xmlHashLookup2(ctxt->varHash, name, ns_uri)));
  4682. }
  4683. /**
  4684. * xmlXPathRegisteredVariablesCleanup:
  4685. * @ctxt: the XPath context
  4686. *
  4687. * Cleanup the XPath context data associated to registered variables
  4688. */
  4689. void
  4690. xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
  4691. if (ctxt == NULL)
  4692. return;
  4693. xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
  4694. ctxt->varHash = NULL;
  4695. }
  4696. /**
  4697. * xmlXPathRegisterNs:
  4698. * @ctxt: the XPath context
  4699. * @prefix: the namespace prefix cannot be NULL or empty string
  4700. * @ns_uri: the namespace name
  4701. *
  4702. * Register a new namespace. If @ns_uri is NULL it unregisters
  4703. * the namespace
  4704. *
  4705. * Returns 0 in case of success, -1 in case of error
  4706. */
  4707. int
  4708. xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
  4709. const xmlChar *ns_uri) {
  4710. if (ctxt == NULL)
  4711. return(-1);
  4712. if (prefix == NULL)
  4713. return(-1);
  4714. if (prefix[0] == 0)
  4715. return(-1);
  4716. if (ctxt->nsHash == NULL)
  4717. ctxt->nsHash = xmlHashCreate(10);
  4718. if (ctxt->nsHash == NULL)
  4719. return(-1);
  4720. if (ns_uri == NULL)
  4721. return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
  4722. xmlHashDefaultDeallocator));
  4723. return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
  4724. xmlHashDefaultDeallocator));
  4725. }
  4726. /**
  4727. * xmlXPathNsLookup:
  4728. * @ctxt: the XPath context
  4729. * @prefix: the namespace prefix value
  4730. *
  4731. * Search in the namespace declaration array of the context for the given
  4732. * namespace name associated to the given prefix
  4733. *
  4734. * Returns the value or NULL if not found
  4735. */
  4736. const xmlChar *
  4737. xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
  4738. if (ctxt == NULL)
  4739. return(NULL);
  4740. if (prefix == NULL)
  4741. return(NULL);
  4742. #ifdef XML_XML_NAMESPACE
  4743. if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
  4744. return(XML_XML_NAMESPACE);
  4745. #endif
  4746. if (ctxt->namespaces != NULL) {
  4747. int i;
  4748. for (i = 0;i < ctxt->nsNr;i++) {
  4749. if ((ctxt->namespaces[i] != NULL) &&
  4750. (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
  4751. return(ctxt->namespaces[i]->href);
  4752. }
  4753. }
  4754. return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
  4755. }
  4756. /**
  4757. * xmlXPathRegisteredNsCleanup:
  4758. * @ctxt: the XPath context
  4759. *
  4760. * Cleanup the XPath context data associated to registered variables
  4761. */
  4762. void
  4763. xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
  4764. if (ctxt == NULL)
  4765. return;
  4766. xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
  4767. ctxt->nsHash = NULL;
  4768. }
  4769. /************************************************************************
  4770. * *
  4771. * Routines to handle Values *
  4772. * *
  4773. ************************************************************************/
  4774. /* Allocations are terrible, one needs to optimize all this !!! */
  4775. /**
  4776. * xmlXPathNewFloat:
  4777. * @val: the double value
  4778. *
  4779. * Create a new xmlXPathObjectPtr of type double and of value @val
  4780. *
  4781. * Returns the newly created object.
  4782. */
  4783. xmlXPathObjectPtr
  4784. xmlXPathNewFloat(double val) {
  4785. xmlXPathObjectPtr ret;
  4786. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4787. if (ret == NULL) {
  4788. xmlXPathErrMemory(NULL, "creating float object\n");
  4789. return(NULL);
  4790. }
  4791. memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  4792. ret->type = XPATH_NUMBER;
  4793. ret->floatval = val;
  4794. #ifdef XP_DEBUG_OBJ_USAGE
  4795. xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
  4796. #endif
  4797. return(ret);
  4798. }
  4799. /**
  4800. * xmlXPathNewBoolean:
  4801. * @val: the boolean value
  4802. *
  4803. * Create a new xmlXPathObjectPtr of type boolean and of value @val
  4804. *
  4805. * Returns the newly created object.
  4806. */
  4807. xmlXPathObjectPtr
  4808. xmlXPathNewBoolean(int val) {
  4809. xmlXPathObjectPtr ret;
  4810. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4811. if (ret == NULL) {
  4812. xmlXPathErrMemory(NULL, "creating boolean object\n");
  4813. return(NULL);
  4814. }
  4815. memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  4816. ret->type = XPATH_BOOLEAN;
  4817. ret->boolval = (val != 0);
  4818. #ifdef XP_DEBUG_OBJ_USAGE
  4819. xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
  4820. #endif
  4821. return(ret);
  4822. }
  4823. /**
  4824. * xmlXPathNewString:
  4825. * @val: the xmlChar * value
  4826. *
  4827. * Create a new xmlXPathObjectPtr of type string and of value @val
  4828. *
  4829. * Returns the newly created object.
  4830. */
  4831. xmlXPathObjectPtr
  4832. xmlXPathNewString(const xmlChar *val) {
  4833. xmlXPathObjectPtr ret;
  4834. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4835. if (ret == NULL) {
  4836. xmlXPathErrMemory(NULL, "creating string object\n");
  4837. return(NULL);
  4838. }
  4839. memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  4840. ret->type = XPATH_STRING;
  4841. if (val != NULL)
  4842. ret->stringval = xmlStrdup(val);
  4843. else
  4844. ret->stringval = xmlStrdup((const xmlChar *)"");
  4845. #ifdef XP_DEBUG_OBJ_USAGE
  4846. xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
  4847. #endif
  4848. return(ret);
  4849. }
  4850. /**
  4851. * xmlXPathWrapString:
  4852. * @val: the xmlChar * value
  4853. *
  4854. * Wraps the @val string into an XPath object.
  4855. *
  4856. * Returns the newly created object.
  4857. */
  4858. xmlXPathObjectPtr
  4859. xmlXPathWrapString (xmlChar *val) {
  4860. xmlXPathObjectPtr ret;
  4861. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4862. if (ret == NULL) {
  4863. xmlXPathErrMemory(NULL, "creating string object\n");
  4864. return(NULL);
  4865. }
  4866. memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  4867. ret->type = XPATH_STRING;
  4868. ret->stringval = val;
  4869. #ifdef XP_DEBUG_OBJ_USAGE
  4870. xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
  4871. #endif
  4872. return(ret);
  4873. }
  4874. /**
  4875. * xmlXPathNewCString:
  4876. * @val: the char * value
  4877. *
  4878. * Create a new xmlXPathObjectPtr of type string and of value @val
  4879. *
  4880. * Returns the newly created object.
  4881. */
  4882. xmlXPathObjectPtr
  4883. xmlXPathNewCString(const char *val) {
  4884. xmlXPathObjectPtr ret;
  4885. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4886. if (ret == NULL) {
  4887. xmlXPathErrMemory(NULL, "creating string object\n");
  4888. return(NULL);
  4889. }
  4890. memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  4891. ret->type = XPATH_STRING;
  4892. ret->stringval = xmlStrdup(BAD_CAST val);
  4893. #ifdef XP_DEBUG_OBJ_USAGE
  4894. xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
  4895. #endif
  4896. return(ret);
  4897. }
  4898. /**
  4899. * xmlXPathWrapCString:
  4900. * @val: the char * value
  4901. *
  4902. * Wraps a string into an XPath object.
  4903. *
  4904. * Returns the newly created object.
  4905. */
  4906. xmlXPathObjectPtr
  4907. xmlXPathWrapCString (char * val) {
  4908. return(xmlXPathWrapString((xmlChar *)(val)));
  4909. }
  4910. /**
  4911. * xmlXPathWrapExternal:
  4912. * @val: the user data
  4913. *
  4914. * Wraps the @val data into an XPath object.
  4915. *
  4916. * Returns the newly created object.
  4917. */
  4918. xmlXPathObjectPtr
  4919. xmlXPathWrapExternal (void *val) {
  4920. xmlXPathObjectPtr ret;
  4921. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4922. if (ret == NULL) {
  4923. xmlXPathErrMemory(NULL, "creating user object\n");
  4924. return(NULL);
  4925. }
  4926. memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  4927. ret->type = XPATH_USERS;
  4928. ret->user = val;
  4929. #ifdef XP_DEBUG_OBJ_USAGE
  4930. xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
  4931. #endif
  4932. return(ret);
  4933. }
  4934. /**
  4935. * xmlXPathObjectCopy:
  4936. * @val: the original object
  4937. *
  4938. * allocate a new copy of a given object
  4939. *
  4940. * Returns the newly created object.
  4941. */
  4942. xmlXPathObjectPtr
  4943. xmlXPathObjectCopy(xmlXPathObjectPtr val) {
  4944. xmlXPathObjectPtr ret;
  4945. if (val == NULL)
  4946. return(NULL);
  4947. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4948. if (ret == NULL) {
  4949. xmlXPathErrMemory(NULL, "copying object\n");
  4950. return(NULL);
  4951. }
  4952. memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
  4953. #ifdef XP_DEBUG_OBJ_USAGE
  4954. xmlXPathDebugObjUsageRequested(NULL, val->type);
  4955. #endif
  4956. switch (val->type) {
  4957. case XPATH_BOOLEAN:
  4958. case XPATH_NUMBER:
  4959. case XPATH_POINT:
  4960. case XPATH_RANGE:
  4961. break;
  4962. case XPATH_STRING:
  4963. ret->stringval = xmlStrdup(val->stringval);
  4964. break;
  4965. case XPATH_XSLT_TREE:
  4966. #if 0
  4967. /*
  4968. Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
  4969. this previous handling is no longer correct, and can cause some serious
  4970. problems (ref. bug 145547)
  4971. */
  4972. if ((val->nodesetval != NULL) &&
  4973. (val->nodesetval->nodeTab != NULL)) {
  4974. xmlNodePtr cur, tmp;
  4975. xmlDocPtr top;
  4976. ret->boolval = 1;
  4977. top = xmlNewDoc(NULL);
  4978. top->name = (char *)
  4979. xmlStrdup(val->nodesetval->nodeTab[0]->name);
  4980. ret->user = top;
  4981. if (top != NULL) {
  4982. top->doc = top;
  4983. cur = val->nodesetval->nodeTab[0]->children;
  4984. while (cur != NULL) {
  4985. tmp = xmlDocCopyNode(cur, top, 1);
  4986. xmlAddChild((xmlNodePtr) top, tmp);
  4987. cur = cur->next;
  4988. }
  4989. }
  4990. ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
  4991. } else
  4992. ret->nodesetval = xmlXPathNodeSetCreate(NULL);
  4993. /* Deallocate the copied tree value */
  4994. break;
  4995. #endif
  4996. case XPATH_NODESET:
  4997. /* TODO: Check memory error. */
  4998. ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
  4999. /* Do not deallocate the copied tree value */
  5000. ret->boolval = 0;
  5001. break;
  5002. case XPATH_LOCATIONSET:
  5003. #ifdef LIBXML_XPTR_ENABLED
  5004. {
  5005. xmlLocationSetPtr loc = val->user;
  5006. ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
  5007. break;
  5008. }
  5009. #endif
  5010. case XPATH_USERS:
  5011. ret->user = val->user;
  5012. break;
  5013. case XPATH_UNDEFINED:
  5014. xmlGenericError(xmlGenericErrorContext,
  5015. "xmlXPathObjectCopy: unsupported type %d\n",
  5016. val->type);
  5017. break;
  5018. }
  5019. return(ret);
  5020. }
  5021. /**
  5022. * xmlXPathFreeObject:
  5023. * @obj: the object to free
  5024. *
  5025. * Free up an xmlXPathObjectPtr object.
  5026. */
  5027. void
  5028. xmlXPathFreeObject(xmlXPathObjectPtr obj) {
  5029. if (obj == NULL) return;
  5030. if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
  5031. if (obj->boolval) {
  5032. #if 0
  5033. if (obj->user != NULL) {
  5034. xmlXPathFreeNodeSet(obj->nodesetval);
  5035. xmlFreeNodeList((xmlNodePtr) obj->user);
  5036. } else
  5037. #endif
  5038. obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
  5039. if (obj->nodesetval != NULL)
  5040. xmlXPathFreeValueTree(obj->nodesetval);
  5041. } else {
  5042. if (obj->nodesetval != NULL)
  5043. xmlXPathFreeNodeSet(obj->nodesetval);
  5044. }
  5045. #ifdef LIBXML_XPTR_ENABLED
  5046. } else if (obj->type == XPATH_LOCATIONSET) {
  5047. if (obj->user != NULL)
  5048. xmlXPtrFreeLocationSet(obj->user);
  5049. #endif
  5050. } else if (obj->type == XPATH_STRING) {
  5051. if (obj->stringval != NULL)
  5052. xmlFree(obj->stringval);
  5053. }
  5054. #ifdef XP_DEBUG_OBJ_USAGE
  5055. xmlXPathDebugObjUsageReleased(NULL, obj->type);
  5056. #endif
  5057. xmlFree(obj);
  5058. }
  5059. static void
  5060. xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
  5061. xmlXPathFreeObject((xmlXPathObjectPtr) obj);
  5062. }
  5063. /**
  5064. * xmlXPathReleaseObject:
  5065. * @obj: the xmlXPathObjectPtr to free or to cache
  5066. *
  5067. * Depending on the state of the cache this frees the given
  5068. * XPath object or stores it in the cache.
  5069. */
  5070. static void
  5071. xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
  5072. {
  5073. #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
  5074. sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
  5075. if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
  5076. #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
  5077. if (obj == NULL)
  5078. return;
  5079. if ((ctxt == NULL) || (ctxt->cache == NULL)) {
  5080. xmlXPathFreeObject(obj);
  5081. } else {
  5082. xmlXPathContextCachePtr cache =
  5083. (xmlXPathContextCachePtr) ctxt->cache;
  5084. switch (obj->type) {
  5085. case XPATH_NODESET:
  5086. case XPATH_XSLT_TREE:
  5087. if (obj->nodesetval != NULL) {
  5088. if (obj->boolval) {
  5089. /*
  5090. * It looks like the @boolval is used for
  5091. * evaluation if this an XSLT Result Tree Fragment.
  5092. * TODO: Check if this assumption is correct.
  5093. */
  5094. obj->type = XPATH_XSLT_TREE; /* just for debugging */
  5095. xmlXPathFreeValueTree(obj->nodesetval);
  5096. obj->nodesetval = NULL;
  5097. } else if ((obj->nodesetval->nodeMax <= 40) &&
  5098. (XP_CACHE_WANTS(cache->nodesetObjs,
  5099. cache->maxNodeset)))
  5100. {
  5101. XP_CACHE_ADD(cache->nodesetObjs, obj);
  5102. goto obj_cached;
  5103. } else {
  5104. xmlXPathFreeNodeSet(obj->nodesetval);
  5105. obj->nodesetval = NULL;
  5106. }
  5107. }
  5108. break;
  5109. case XPATH_STRING:
  5110. if (obj->stringval != NULL)
  5111. xmlFree(obj->stringval);
  5112. if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
  5113. XP_CACHE_ADD(cache->stringObjs, obj);
  5114. goto obj_cached;
  5115. }
  5116. break;
  5117. case XPATH_BOOLEAN:
  5118. if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
  5119. XP_CACHE_ADD(cache->booleanObjs, obj);
  5120. goto obj_cached;
  5121. }
  5122. break;
  5123. case XPATH_NUMBER:
  5124. if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
  5125. XP_CACHE_ADD(cache->numberObjs, obj);
  5126. goto obj_cached;
  5127. }
  5128. break;
  5129. #ifdef LIBXML_XPTR_ENABLED
  5130. case XPATH_LOCATIONSET:
  5131. if (obj->user != NULL) {
  5132. xmlXPtrFreeLocationSet(obj->user);
  5133. }
  5134. goto free_obj;
  5135. #endif
  5136. default:
  5137. goto free_obj;
  5138. }
  5139. /*
  5140. * Fallback to adding to the misc-objects slot.
  5141. */
  5142. if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
  5143. XP_CACHE_ADD(cache->miscObjs, obj);
  5144. } else
  5145. goto free_obj;
  5146. obj_cached:
  5147. #ifdef XP_DEBUG_OBJ_USAGE
  5148. xmlXPathDebugObjUsageReleased(ctxt, obj->type);
  5149. #endif
  5150. if (obj->nodesetval != NULL) {
  5151. xmlNodeSetPtr tmpset = obj->nodesetval;
  5152. /*
  5153. * TODO: Due to those nasty ns-nodes, we need to traverse
  5154. * the list and free the ns-nodes.
  5155. * URGENT TODO: Check if it's actually slowing things down.
  5156. * Maybe we shouldn't try to preserve the list.
  5157. */
  5158. if (tmpset->nodeNr > 1) {
  5159. int i;
  5160. xmlNodePtr node;
  5161. for (i = 0; i < tmpset->nodeNr; i++) {
  5162. node = tmpset->nodeTab[i];
  5163. if ((node != NULL) &&
  5164. (node->type == XML_NAMESPACE_DECL))
  5165. {
  5166. xmlXPathNodeSetFreeNs((xmlNsPtr) node);
  5167. }
  5168. }
  5169. } else if (tmpset->nodeNr == 1) {
  5170. if ((tmpset->nodeTab[0] != NULL) &&
  5171. (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
  5172. xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
  5173. }
  5174. tmpset->nodeNr = 0;
  5175. memset(obj, 0, sizeof(xmlXPathObject));
  5176. obj->nodesetval = tmpset;
  5177. } else
  5178. memset(obj, 0, sizeof(xmlXPathObject));
  5179. return;
  5180. free_obj:
  5181. /*
  5182. * Cache is full; free the object.
  5183. */
  5184. if (obj->nodesetval != NULL)
  5185. xmlXPathFreeNodeSet(obj->nodesetval);
  5186. #ifdef XP_DEBUG_OBJ_USAGE
  5187. xmlXPathDebugObjUsageReleased(NULL, obj->type);
  5188. #endif
  5189. xmlFree(obj);
  5190. }
  5191. return;
  5192. }
  5193. /************************************************************************
  5194. * *
  5195. * Type Casting Routines *
  5196. * *
  5197. ************************************************************************/
  5198. /**
  5199. * xmlXPathCastBooleanToString:
  5200. * @val: a boolean
  5201. *
  5202. * Converts a boolean to its string value.
  5203. *
  5204. * Returns a newly allocated string.
  5205. */
  5206. xmlChar *
  5207. xmlXPathCastBooleanToString (int val) {
  5208. xmlChar *ret;
  5209. if (val)
  5210. ret = xmlStrdup((const xmlChar *) "true");
  5211. else
  5212. ret = xmlStrdup((const xmlChar *) "false");
  5213. return(ret);
  5214. }
  5215. /**
  5216. * xmlXPathCastNumberToString:
  5217. * @val: a number
  5218. *
  5219. * Converts a number to its string value.
  5220. *
  5221. * Returns a newly allocated string.
  5222. */
  5223. xmlChar *
  5224. xmlXPathCastNumberToString (double val) {
  5225. xmlChar *ret;
  5226. switch (xmlXPathIsInf(val)) {
  5227. case 1:
  5228. ret = xmlStrdup((const xmlChar *) "Infinity");
  5229. break;
  5230. case -1:
  5231. ret = xmlStrdup((const xmlChar *) "-Infinity");
  5232. break;
  5233. default:
  5234. if (xmlXPathIsNaN(val)) {
  5235. ret = xmlStrdup((const xmlChar *) "NaN");
  5236. } else if (val == 0) {
  5237. /* Omit sign for negative zero. */
  5238. ret = xmlStrdup((const xmlChar *) "0");
  5239. } else {
  5240. /* could be improved */
  5241. char buf[100];
  5242. xmlXPathFormatNumber(val, buf, 99);
  5243. buf[99] = 0;
  5244. ret = xmlStrdup((const xmlChar *) buf);
  5245. }
  5246. }
  5247. return(ret);
  5248. }
  5249. /**
  5250. * xmlXPathCastNodeToString:
  5251. * @node: a node
  5252. *
  5253. * Converts a node to its string value.
  5254. *
  5255. * Returns a newly allocated string.
  5256. */
  5257. xmlChar *
  5258. xmlXPathCastNodeToString (xmlNodePtr node) {
  5259. xmlChar *ret;
  5260. if ((ret = xmlNodeGetContent(node)) == NULL)
  5261. ret = xmlStrdup((const xmlChar *) "");
  5262. return(ret);
  5263. }
  5264. /**
  5265. * xmlXPathCastNodeSetToString:
  5266. * @ns: a node-set
  5267. *
  5268. * Converts a node-set to its string value.
  5269. *
  5270. * Returns a newly allocated string.
  5271. */
  5272. xmlChar *
  5273. xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
  5274. if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
  5275. return(xmlStrdup((const xmlChar *) ""));
  5276. if (ns->nodeNr > 1)
  5277. xmlXPathNodeSetSort(ns);
  5278. return(xmlXPathCastNodeToString(ns->nodeTab[0]));
  5279. }
  5280. /**
  5281. * xmlXPathCastToString:
  5282. * @val: an XPath object
  5283. *
  5284. * Converts an existing object to its string() equivalent
  5285. *
  5286. * Returns the allocated string value of the object, NULL in case of error.
  5287. * It's up to the caller to free the string memory with xmlFree().
  5288. */
  5289. xmlChar *
  5290. xmlXPathCastToString(xmlXPathObjectPtr val) {
  5291. xmlChar *ret = NULL;
  5292. if (val == NULL)
  5293. return(xmlStrdup((const xmlChar *) ""));
  5294. switch (val->type) {
  5295. case XPATH_UNDEFINED:
  5296. #ifdef DEBUG_EXPR
  5297. xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
  5298. #endif
  5299. ret = xmlStrdup((const xmlChar *) "");
  5300. break;
  5301. case XPATH_NODESET:
  5302. case XPATH_XSLT_TREE:
  5303. ret = xmlXPathCastNodeSetToString(val->nodesetval);
  5304. break;
  5305. case XPATH_STRING:
  5306. return(xmlStrdup(val->stringval));
  5307. case XPATH_BOOLEAN:
  5308. ret = xmlXPathCastBooleanToString(val->boolval);
  5309. break;
  5310. case XPATH_NUMBER: {
  5311. ret = xmlXPathCastNumberToString(val->floatval);
  5312. break;
  5313. }
  5314. case XPATH_USERS:
  5315. case XPATH_POINT:
  5316. case XPATH_RANGE:
  5317. case XPATH_LOCATIONSET:
  5318. TODO
  5319. ret = xmlStrdup((const xmlChar *) "");
  5320. break;
  5321. }
  5322. return(ret);
  5323. }
  5324. /**
  5325. * xmlXPathConvertString:
  5326. * @val: an XPath object
  5327. *
  5328. * Converts an existing object to its string() equivalent
  5329. *
  5330. * Returns the new object, the old one is freed (or the operation
  5331. * is done directly on @val)
  5332. */
  5333. xmlXPathObjectPtr
  5334. xmlXPathConvertString(xmlXPathObjectPtr val) {
  5335. xmlChar *res = NULL;
  5336. if (val == NULL)
  5337. return(xmlXPathNewCString(""));
  5338. switch (val->type) {
  5339. case XPATH_UNDEFINED:
  5340. #ifdef DEBUG_EXPR
  5341. xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
  5342. #endif
  5343. break;
  5344. case XPATH_NODESET:
  5345. case XPATH_XSLT_TREE:
  5346. res = xmlXPathCastNodeSetToString(val->nodesetval);
  5347. break;
  5348. case XPATH_STRING:
  5349. return(val);
  5350. case XPATH_BOOLEAN:
  5351. res = xmlXPathCastBooleanToString(val->boolval);
  5352. break;
  5353. case XPATH_NUMBER:
  5354. res = xmlXPathCastNumberToString(val->floatval);
  5355. break;
  5356. case XPATH_USERS:
  5357. case XPATH_POINT:
  5358. case XPATH_RANGE:
  5359. case XPATH_LOCATIONSET:
  5360. TODO;
  5361. break;
  5362. }
  5363. xmlXPathFreeObject(val);
  5364. if (res == NULL)
  5365. return(xmlXPathNewCString(""));
  5366. return(xmlXPathWrapString(res));
  5367. }
  5368. /**
  5369. * xmlXPathCastBooleanToNumber:
  5370. * @val: a boolean
  5371. *
  5372. * Converts a boolean to its number value
  5373. *
  5374. * Returns the number value
  5375. */
  5376. double
  5377. xmlXPathCastBooleanToNumber(int val) {
  5378. if (val)
  5379. return(1.0);
  5380. return(0.0);
  5381. }
  5382. /**
  5383. * xmlXPathCastStringToNumber:
  5384. * @val: a string
  5385. *
  5386. * Converts a string to its number value
  5387. *
  5388. * Returns the number value
  5389. */
  5390. double
  5391. xmlXPathCastStringToNumber(const xmlChar * val) {
  5392. return(xmlXPathStringEvalNumber(val));
  5393. }
  5394. /**
  5395. * xmlXPathCastNodeToNumber:
  5396. * @node: a node
  5397. *
  5398. * Converts a node to its number value
  5399. *
  5400. * Returns the number value
  5401. */
  5402. double
  5403. xmlXPathCastNodeToNumber (xmlNodePtr node) {
  5404. xmlChar *strval;
  5405. double ret;
  5406. if (node == NULL)
  5407. return(xmlXPathNAN);
  5408. strval = xmlXPathCastNodeToString(node);
  5409. if (strval == NULL)
  5410. return(xmlXPathNAN);
  5411. ret = xmlXPathCastStringToNumber(strval);
  5412. xmlFree(strval);
  5413. return(ret);
  5414. }
  5415. /**
  5416. * xmlXPathCastNodeSetToNumber:
  5417. * @ns: a node-set
  5418. *
  5419. * Converts a node-set to its number value
  5420. *
  5421. * Returns the number value
  5422. */
  5423. double
  5424. xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
  5425. xmlChar *str;
  5426. double ret;
  5427. if (ns == NULL)
  5428. return(xmlXPathNAN);
  5429. str = xmlXPathCastNodeSetToString(ns);
  5430. ret = xmlXPathCastStringToNumber(str);
  5431. xmlFree(str);
  5432. return(ret);
  5433. }
  5434. /**
  5435. * xmlXPathCastToNumber:
  5436. * @val: an XPath object
  5437. *
  5438. * Converts an XPath object to its number value
  5439. *
  5440. * Returns the number value
  5441. */
  5442. double
  5443. xmlXPathCastToNumber(xmlXPathObjectPtr val) {
  5444. double ret = 0.0;
  5445. if (val == NULL)
  5446. return(xmlXPathNAN);
  5447. switch (val->type) {
  5448. case XPATH_UNDEFINED:
  5449. #ifdef DEBUG_EXPR
  5450. xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
  5451. #endif
  5452. ret = xmlXPathNAN;
  5453. break;
  5454. case XPATH_NODESET:
  5455. case XPATH_XSLT_TREE:
  5456. ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
  5457. break;
  5458. case XPATH_STRING:
  5459. ret = xmlXPathCastStringToNumber(val->stringval);
  5460. break;
  5461. case XPATH_NUMBER:
  5462. ret = val->floatval;
  5463. break;
  5464. case XPATH_BOOLEAN:
  5465. ret = xmlXPathCastBooleanToNumber(val->boolval);
  5466. break;
  5467. case XPATH_USERS:
  5468. case XPATH_POINT:
  5469. case XPATH_RANGE:
  5470. case XPATH_LOCATIONSET:
  5471. TODO;
  5472. ret = xmlXPathNAN;
  5473. break;
  5474. }
  5475. return(ret);
  5476. }
  5477. /**
  5478. * xmlXPathConvertNumber:
  5479. * @val: an XPath object
  5480. *
  5481. * Converts an existing object to its number() equivalent
  5482. *
  5483. * Returns the new object, the old one is freed (or the operation
  5484. * is done directly on @val)
  5485. */
  5486. xmlXPathObjectPtr
  5487. xmlXPathConvertNumber(xmlXPathObjectPtr val) {
  5488. xmlXPathObjectPtr ret;
  5489. if (val == NULL)
  5490. return(xmlXPathNewFloat(0.0));
  5491. if (val->type == XPATH_NUMBER)
  5492. return(val);
  5493. ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
  5494. xmlXPathFreeObject(val);
  5495. return(ret);
  5496. }
  5497. /**
  5498. * xmlXPathCastNumberToBoolean:
  5499. * @val: a number
  5500. *
  5501. * Converts a number to its boolean value
  5502. *
  5503. * Returns the boolean value
  5504. */
  5505. int
  5506. xmlXPathCastNumberToBoolean (double val) {
  5507. if (xmlXPathIsNaN(val) || (val == 0.0))
  5508. return(0);
  5509. return(1);
  5510. }
  5511. /**
  5512. * xmlXPathCastStringToBoolean:
  5513. * @val: a string
  5514. *
  5515. * Converts a string to its boolean value
  5516. *
  5517. * Returns the boolean value
  5518. */
  5519. int
  5520. xmlXPathCastStringToBoolean (const xmlChar *val) {
  5521. if ((val == NULL) || (xmlStrlen(val) == 0))
  5522. return(0);
  5523. return(1);
  5524. }
  5525. /**
  5526. * xmlXPathCastNodeSetToBoolean:
  5527. * @ns: a node-set
  5528. *
  5529. * Converts a node-set to its boolean value
  5530. *
  5531. * Returns the boolean value
  5532. */
  5533. int
  5534. xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
  5535. if ((ns == NULL) || (ns->nodeNr == 0))
  5536. return(0);
  5537. return(1);
  5538. }
  5539. /**
  5540. * xmlXPathCastToBoolean:
  5541. * @val: an XPath object
  5542. *
  5543. * Converts an XPath object to its boolean value
  5544. *
  5545. * Returns the boolean value
  5546. */
  5547. int
  5548. xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
  5549. int ret = 0;
  5550. if (val == NULL)
  5551. return(0);
  5552. switch (val->type) {
  5553. case XPATH_UNDEFINED:
  5554. #ifdef DEBUG_EXPR
  5555. xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
  5556. #endif
  5557. ret = 0;
  5558. break;
  5559. case XPATH_NODESET:
  5560. case XPATH_XSLT_TREE:
  5561. ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
  5562. break;
  5563. case XPATH_STRING:
  5564. ret = xmlXPathCastStringToBoolean(val->stringval);
  5565. break;
  5566. case XPATH_NUMBER:
  5567. ret = xmlXPathCastNumberToBoolean(val->floatval);
  5568. break;
  5569. case XPATH_BOOLEAN:
  5570. ret = val->boolval;
  5571. break;
  5572. case XPATH_USERS:
  5573. case XPATH_POINT:
  5574. case XPATH_RANGE:
  5575. case XPATH_LOCATIONSET:
  5576. TODO;
  5577. ret = 0;
  5578. break;
  5579. }
  5580. return(ret);
  5581. }
  5582. /**
  5583. * xmlXPathConvertBoolean:
  5584. * @val: an XPath object
  5585. *
  5586. * Converts an existing object to its boolean() equivalent
  5587. *
  5588. * Returns the new object, the old one is freed (or the operation
  5589. * is done directly on @val)
  5590. */
  5591. xmlXPathObjectPtr
  5592. xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
  5593. xmlXPathObjectPtr ret;
  5594. if (val == NULL)
  5595. return(xmlXPathNewBoolean(0));
  5596. if (val->type == XPATH_BOOLEAN)
  5597. return(val);
  5598. ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
  5599. xmlXPathFreeObject(val);
  5600. return(ret);
  5601. }
  5602. /************************************************************************
  5603. * *
  5604. * Routines to handle XPath contexts *
  5605. * *
  5606. ************************************************************************/
  5607. /**
  5608. * xmlXPathNewContext:
  5609. * @doc: the XML document
  5610. *
  5611. * Create a new xmlXPathContext
  5612. *
  5613. * Returns the xmlXPathContext just allocated. The caller will need to free it.
  5614. */
  5615. xmlXPathContextPtr
  5616. xmlXPathNewContext(xmlDocPtr doc) {
  5617. xmlXPathContextPtr ret;
  5618. ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
  5619. if (ret == NULL) {
  5620. xmlXPathErrMemory(NULL, "creating context\n");
  5621. return(NULL);
  5622. }
  5623. memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
  5624. ret->doc = doc;
  5625. ret->node = NULL;
  5626. ret->varHash = NULL;
  5627. ret->nb_types = 0;
  5628. ret->max_types = 0;
  5629. ret->types = NULL;
  5630. ret->funcHash = xmlHashCreate(0);
  5631. ret->nb_axis = 0;
  5632. ret->max_axis = 0;
  5633. ret->axis = NULL;
  5634. ret->nsHash = NULL;
  5635. ret->user = NULL;
  5636. ret->contextSize = -1;
  5637. ret->proximityPosition = -1;
  5638. #ifdef XP_DEFAULT_CACHE_ON
  5639. if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
  5640. xmlXPathFreeContext(ret);
  5641. return(NULL);
  5642. }
  5643. #endif
  5644. xmlXPathRegisterAllFunctions(ret);
  5645. return(ret);
  5646. }
  5647. /**
  5648. * xmlXPathFreeContext:
  5649. * @ctxt: the context to free
  5650. *
  5651. * Free up an xmlXPathContext
  5652. */
  5653. void
  5654. xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
  5655. if (ctxt == NULL) return;
  5656. if (ctxt->cache != NULL)
  5657. xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
  5658. xmlXPathRegisteredNsCleanup(ctxt);
  5659. xmlXPathRegisteredFuncsCleanup(ctxt);
  5660. xmlXPathRegisteredVariablesCleanup(ctxt);
  5661. xmlResetError(&ctxt->lastError);
  5662. xmlFree(ctxt);
  5663. }
  5664. /************************************************************************
  5665. * *
  5666. * Routines to handle XPath parser contexts *
  5667. * *
  5668. ************************************************************************/
  5669. #define CHECK_CTXT(ctxt) \
  5670. if (ctxt == NULL) { \
  5671. __xmlRaiseError(NULL, NULL, NULL, \
  5672. NULL, NULL, XML_FROM_XPATH, \
  5673. XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
  5674. __FILE__, __LINE__, \
  5675. NULL, NULL, NULL, 0, 0, \
  5676. "NULL context pointer\n"); \
  5677. return(NULL); \
  5678. } \
  5679. #define CHECK_CTXT_NEG(ctxt) \
  5680. if (ctxt == NULL) { \
  5681. __xmlRaiseError(NULL, NULL, NULL, \
  5682. NULL, NULL, XML_FROM_XPATH, \
  5683. XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
  5684. __FILE__, __LINE__, \
  5685. NULL, NULL, NULL, 0, 0, \
  5686. "NULL context pointer\n"); \
  5687. return(-1); \
  5688. } \
  5689. #define CHECK_CONTEXT(ctxt) \
  5690. if ((ctxt == NULL) || (ctxt->doc == NULL) || \
  5691. (ctxt->doc->children == NULL)) { \
  5692. xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
  5693. return(NULL); \
  5694. }
  5695. /**
  5696. * xmlXPathNewParserContext:
  5697. * @str: the XPath expression
  5698. * @ctxt: the XPath context
  5699. *
  5700. * Create a new xmlXPathParserContext
  5701. *
  5702. * Returns the xmlXPathParserContext just allocated.
  5703. */
  5704. xmlXPathParserContextPtr
  5705. xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
  5706. xmlXPathParserContextPtr ret;
  5707. ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
  5708. if (ret == NULL) {
  5709. xmlXPathErrMemory(ctxt, "creating parser context\n");
  5710. return(NULL);
  5711. }
  5712. memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
  5713. ret->cur = ret->base = str;
  5714. ret->context = ctxt;
  5715. ret->comp = xmlXPathNewCompExpr();
  5716. if (ret->comp == NULL) {
  5717. xmlFree(ret->valueTab);
  5718. xmlFree(ret);
  5719. return(NULL);
  5720. }
  5721. if ((ctxt != NULL) && (ctxt->dict != NULL)) {
  5722. ret->comp->dict = ctxt->dict;
  5723. xmlDictReference(ret->comp->dict);
  5724. }
  5725. return(ret);
  5726. }
  5727. /**
  5728. * xmlXPathCompParserContext:
  5729. * @comp: the XPath compiled expression
  5730. * @ctxt: the XPath context
  5731. *
  5732. * Create a new xmlXPathParserContext when processing a compiled expression
  5733. *
  5734. * Returns the xmlXPathParserContext just allocated.
  5735. */
  5736. static xmlXPathParserContextPtr
  5737. xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
  5738. xmlXPathParserContextPtr ret;
  5739. ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
  5740. if (ret == NULL) {
  5741. xmlXPathErrMemory(ctxt, "creating evaluation context\n");
  5742. return(NULL);
  5743. }
  5744. memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
  5745. /* Allocate the value stack */
  5746. ret->valueTab = (xmlXPathObjectPtr *)
  5747. xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
  5748. if (ret->valueTab == NULL) {
  5749. xmlFree(ret);
  5750. xmlXPathErrMemory(ctxt, "creating evaluation context\n");
  5751. return(NULL);
  5752. }
  5753. ret->valueNr = 0;
  5754. ret->valueMax = 10;
  5755. ret->value = NULL;
  5756. ret->valueFrame = 0;
  5757. ret->context = ctxt;
  5758. ret->comp = comp;
  5759. return(ret);
  5760. }
  5761. /**
  5762. * xmlXPathFreeParserContext:
  5763. * @ctxt: the context to free
  5764. *
  5765. * Free up an xmlXPathParserContext
  5766. */
  5767. void
  5768. xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
  5769. int i;
  5770. if (ctxt->valueTab != NULL) {
  5771. for (i = 0; i < ctxt->valueNr; i++) {
  5772. if (ctxt->context)
  5773. xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
  5774. else
  5775. xmlXPathFreeObject(ctxt->valueTab[i]);
  5776. }
  5777. xmlFree(ctxt->valueTab);
  5778. }
  5779. if (ctxt->comp != NULL) {
  5780. #ifdef XPATH_STREAMING
  5781. if (ctxt->comp->stream != NULL) {
  5782. xmlFreePatternList(ctxt->comp->stream);
  5783. ctxt->comp->stream = NULL;
  5784. }
  5785. #endif
  5786. xmlXPathFreeCompExpr(ctxt->comp);
  5787. }
  5788. xmlFree(ctxt);
  5789. }
  5790. /************************************************************************
  5791. * *
  5792. * The implicit core function library *
  5793. * *
  5794. ************************************************************************/
  5795. /**
  5796. * xmlXPathNodeValHash:
  5797. * @node: a node pointer
  5798. *
  5799. * Function computing the beginning of the string value of the node,
  5800. * used to speed up comparisons
  5801. *
  5802. * Returns an int usable as a hash
  5803. */
  5804. static unsigned int
  5805. xmlXPathNodeValHash(xmlNodePtr node) {
  5806. int len = 2;
  5807. const xmlChar * string = NULL;
  5808. xmlNodePtr tmp = NULL;
  5809. unsigned int ret = 0;
  5810. if (node == NULL)
  5811. return(0);
  5812. if (node->type == XML_DOCUMENT_NODE) {
  5813. tmp = xmlDocGetRootElement((xmlDocPtr) node);
  5814. if (tmp == NULL)
  5815. node = node->children;
  5816. else
  5817. node = tmp;
  5818. if (node == NULL)
  5819. return(0);
  5820. }
  5821. switch (node->type) {
  5822. case XML_COMMENT_NODE:
  5823. case XML_PI_NODE:
  5824. case XML_CDATA_SECTION_NODE:
  5825. case XML_TEXT_NODE:
  5826. string = node->content;
  5827. if (string == NULL)
  5828. return(0);
  5829. if (string[0] == 0)
  5830. return(0);
  5831. return(((unsigned int) string[0]) +
  5832. (((unsigned int) string[1]) << 8));
  5833. case XML_NAMESPACE_DECL:
  5834. string = ((xmlNsPtr)node)->href;
  5835. if (string == NULL)
  5836. return(0);
  5837. if (string[0] == 0)
  5838. return(0);
  5839. return(((unsigned int) string[0]) +
  5840. (((unsigned int) string[1]) << 8));
  5841. case XML_ATTRIBUTE_NODE:
  5842. tmp = ((xmlAttrPtr) node)->children;
  5843. break;
  5844. case XML_ELEMENT_NODE:
  5845. tmp = node->children;
  5846. break;
  5847. default:
  5848. return(0);
  5849. }
  5850. while (tmp != NULL) {
  5851. switch (tmp->type) {
  5852. case XML_CDATA_SECTION_NODE:
  5853. case XML_TEXT_NODE:
  5854. string = tmp->content;
  5855. break;
  5856. default:
  5857. string = NULL;
  5858. break;
  5859. }
  5860. if ((string != NULL) && (string[0] != 0)) {
  5861. if (len == 1) {
  5862. return(ret + (((unsigned int) string[0]) << 8));
  5863. }
  5864. if (string[1] == 0) {
  5865. len = 1;
  5866. ret = (unsigned int) string[0];
  5867. } else {
  5868. return(((unsigned int) string[0]) +
  5869. (((unsigned int) string[1]) << 8));
  5870. }
  5871. }
  5872. /*
  5873. * Skip to next node
  5874. */
  5875. if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
  5876. if (tmp->children->type != XML_ENTITY_DECL) {
  5877. tmp = tmp->children;
  5878. continue;
  5879. }
  5880. }
  5881. if (tmp == node)
  5882. break;
  5883. if (tmp->next != NULL) {
  5884. tmp = tmp->next;
  5885. continue;
  5886. }
  5887. do {
  5888. tmp = tmp->parent;
  5889. if (tmp == NULL)
  5890. break;
  5891. if (tmp == node) {
  5892. tmp = NULL;
  5893. break;
  5894. }
  5895. if (tmp->next != NULL) {
  5896. tmp = tmp->next;
  5897. break;
  5898. }
  5899. } while (tmp != NULL);
  5900. }
  5901. return(ret);
  5902. }
  5903. /**
  5904. * xmlXPathStringHash:
  5905. * @string: a string
  5906. *
  5907. * Function computing the beginning of the string value of the node,
  5908. * used to speed up comparisons
  5909. *
  5910. * Returns an int usable as a hash
  5911. */
  5912. static unsigned int
  5913. xmlXPathStringHash(const xmlChar * string) {
  5914. if (string == NULL)
  5915. return((unsigned int) 0);
  5916. if (string[0] == 0)
  5917. return(0);
  5918. return(((unsigned int) string[0]) +
  5919. (((unsigned int) string[1]) << 8));
  5920. }
  5921. /**
  5922. * xmlXPathCompareNodeSetFloat:
  5923. * @ctxt: the XPath Parser context
  5924. * @inf: less than (1) or greater than (0)
  5925. * @strict: is the comparison strict
  5926. * @arg: the node set
  5927. * @f: the value
  5928. *
  5929. * Implement the compare operation between a nodeset and a number
  5930. * @ns < @val (1, 1, ...
  5931. * @ns <= @val (1, 0, ...
  5932. * @ns > @val (0, 1, ...
  5933. * @ns >= @val (0, 0, ...
  5934. *
  5935. * If one object to be compared is a node-set and the other is a number,
  5936. * then the comparison will be true if and only if there is a node in the
  5937. * node-set such that the result of performing the comparison on the number
  5938. * to be compared and on the result of converting the string-value of that
  5939. * node to a number using the number function is true.
  5940. *
  5941. * Returns 0 or 1 depending on the results of the test.
  5942. */
  5943. static int
  5944. xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
  5945. xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
  5946. int i, ret = 0;
  5947. xmlNodeSetPtr ns;
  5948. xmlChar *str2;
  5949. if ((f == NULL) || (arg == NULL) ||
  5950. ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
  5951. xmlXPathReleaseObject(ctxt->context, arg);
  5952. xmlXPathReleaseObject(ctxt->context, f);
  5953. return(0);
  5954. }
  5955. ns = arg->nodesetval;
  5956. if (ns != NULL) {
  5957. for (i = 0;i < ns->nodeNr;i++) {
  5958. str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
  5959. if (str2 != NULL) {
  5960. valuePush(ctxt,
  5961. xmlXPathCacheNewString(ctxt->context, str2));
  5962. xmlFree(str2);
  5963. xmlXPathNumberFunction(ctxt, 1);
  5964. valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
  5965. ret = xmlXPathCompareValues(ctxt, inf, strict);
  5966. if (ret)
  5967. break;
  5968. }
  5969. }
  5970. }
  5971. xmlXPathReleaseObject(ctxt->context, arg);
  5972. xmlXPathReleaseObject(ctxt->context, f);
  5973. return(ret);
  5974. }
  5975. /**
  5976. * xmlXPathCompareNodeSetString:
  5977. * @ctxt: the XPath Parser context
  5978. * @inf: less than (1) or greater than (0)
  5979. * @strict: is the comparison strict
  5980. * @arg: the node set
  5981. * @s: the value
  5982. *
  5983. * Implement the compare operation between a nodeset and a string
  5984. * @ns < @val (1, 1, ...
  5985. * @ns <= @val (1, 0, ...
  5986. * @ns > @val (0, 1, ...
  5987. * @ns >= @val (0, 0, ...
  5988. *
  5989. * If one object to be compared is a node-set and the other is a string,
  5990. * then the comparison will be true if and only if there is a node in
  5991. * the node-set such that the result of performing the comparison on the
  5992. * string-value of the node and the other string is true.
  5993. *
  5994. * Returns 0 or 1 depending on the results of the test.
  5995. */
  5996. static int
  5997. xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
  5998. xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
  5999. int i, ret = 0;
  6000. xmlNodeSetPtr ns;
  6001. xmlChar *str2;
  6002. if ((s == NULL) || (arg == NULL) ||
  6003. ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
  6004. xmlXPathReleaseObject(ctxt->context, arg);
  6005. xmlXPathReleaseObject(ctxt->context, s);
  6006. return(0);
  6007. }
  6008. ns = arg->nodesetval;
  6009. if (ns != NULL) {
  6010. for (i = 0;i < ns->nodeNr;i++) {
  6011. str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
  6012. if (str2 != NULL) {
  6013. valuePush(ctxt,
  6014. xmlXPathCacheNewString(ctxt->context, str2));
  6015. xmlFree(str2);
  6016. valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
  6017. ret = xmlXPathCompareValues(ctxt, inf, strict);
  6018. if (ret)
  6019. break;
  6020. }
  6021. }
  6022. }
  6023. xmlXPathReleaseObject(ctxt->context, arg);
  6024. xmlXPathReleaseObject(ctxt->context, s);
  6025. return(ret);
  6026. }
  6027. /**
  6028. * xmlXPathCompareNodeSets:
  6029. * @inf: less than (1) or greater than (0)
  6030. * @strict: is the comparison strict
  6031. * @arg1: the first node set object
  6032. * @arg2: the second node set object
  6033. *
  6034. * Implement the compare operation on nodesets:
  6035. *
  6036. * If both objects to be compared are node-sets, then the comparison
  6037. * will be true if and only if there is a node in the first node-set
  6038. * and a node in the second node-set such that the result of performing
  6039. * the comparison on the string-values of the two nodes is true.
  6040. * ....
  6041. * When neither object to be compared is a node-set and the operator
  6042. * is <=, <, >= or >, then the objects are compared by converting both
  6043. * objects to numbers and comparing the numbers according to IEEE 754.
  6044. * ....
  6045. * The number function converts its argument to a number as follows:
  6046. * - a string that consists of optional whitespace followed by an
  6047. * optional minus sign followed by a Number followed by whitespace
  6048. * is converted to the IEEE 754 number that is nearest (according
  6049. * to the IEEE 754 round-to-nearest rule) to the mathematical value
  6050. * represented by the string; any other string is converted to NaN
  6051. *
  6052. * Conclusion all nodes need to be converted first to their string value
  6053. * and then the comparison must be done when possible
  6054. */
  6055. static int
  6056. xmlXPathCompareNodeSets(int inf, int strict,
  6057. xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
  6058. int i, j, init = 0;
  6059. double val1;
  6060. double *values2;
  6061. int ret = 0;
  6062. xmlNodeSetPtr ns1;
  6063. xmlNodeSetPtr ns2;
  6064. if ((arg1 == NULL) ||
  6065. ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
  6066. xmlXPathFreeObject(arg2);
  6067. return(0);
  6068. }
  6069. if ((arg2 == NULL) ||
  6070. ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
  6071. xmlXPathFreeObject(arg1);
  6072. xmlXPathFreeObject(arg2);
  6073. return(0);
  6074. }
  6075. ns1 = arg1->nodesetval;
  6076. ns2 = arg2->nodesetval;
  6077. if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
  6078. xmlXPathFreeObject(arg1);
  6079. xmlXPathFreeObject(arg2);
  6080. return(0);
  6081. }
  6082. if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
  6083. xmlXPathFreeObject(arg1);
  6084. xmlXPathFreeObject(arg2);
  6085. return(0);
  6086. }
  6087. values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
  6088. if (values2 == NULL) {
  6089. /* TODO: Propagate memory error. */
  6090. xmlXPathErrMemory(NULL, "comparing nodesets\n");
  6091. xmlXPathFreeObject(arg1);
  6092. xmlXPathFreeObject(arg2);
  6093. return(0);
  6094. }
  6095. for (i = 0;i < ns1->nodeNr;i++) {
  6096. val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
  6097. if (xmlXPathIsNaN(val1))
  6098. continue;
  6099. for (j = 0;j < ns2->nodeNr;j++) {
  6100. if (init == 0) {
  6101. values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
  6102. }
  6103. if (xmlXPathIsNaN(values2[j]))
  6104. continue;
  6105. if (inf && strict)
  6106. ret = (val1 < values2[j]);
  6107. else if (inf && !strict)
  6108. ret = (val1 <= values2[j]);
  6109. else if (!inf && strict)
  6110. ret = (val1 > values2[j]);
  6111. else if (!inf && !strict)
  6112. ret = (val1 >= values2[j]);
  6113. if (ret)
  6114. break;
  6115. }
  6116. if (ret)
  6117. break;
  6118. init = 1;
  6119. }
  6120. xmlFree(values2);
  6121. xmlXPathFreeObject(arg1);
  6122. xmlXPathFreeObject(arg2);
  6123. return(ret);
  6124. }
  6125. /**
  6126. * xmlXPathCompareNodeSetValue:
  6127. * @ctxt: the XPath Parser context
  6128. * @inf: less than (1) or greater than (0)
  6129. * @strict: is the comparison strict
  6130. * @arg: the node set
  6131. * @val: the value
  6132. *
  6133. * Implement the compare operation between a nodeset and a value
  6134. * @ns < @val (1, 1, ...
  6135. * @ns <= @val (1, 0, ...
  6136. * @ns > @val (0, 1, ...
  6137. * @ns >= @val (0, 0, ...
  6138. *
  6139. * If one object to be compared is a node-set and the other is a boolean,
  6140. * then the comparison will be true if and only if the result of performing
  6141. * the comparison on the boolean and on the result of converting
  6142. * the node-set to a boolean using the boolean function is true.
  6143. *
  6144. * Returns 0 or 1 depending on the results of the test.
  6145. */
  6146. static int
  6147. xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
  6148. xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
  6149. if ((val == NULL) || (arg == NULL) ||
  6150. ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
  6151. return(0);
  6152. switch(val->type) {
  6153. case XPATH_NUMBER:
  6154. return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
  6155. case XPATH_NODESET:
  6156. case XPATH_XSLT_TREE:
  6157. return(xmlXPathCompareNodeSets(inf, strict, arg, val));
  6158. case XPATH_STRING:
  6159. return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
  6160. case XPATH_BOOLEAN:
  6161. valuePush(ctxt, arg);
  6162. xmlXPathBooleanFunction(ctxt, 1);
  6163. valuePush(ctxt, val);
  6164. return(xmlXPathCompareValues(ctxt, inf, strict));
  6165. default:
  6166. xmlGenericError(xmlGenericErrorContext,
  6167. "xmlXPathCompareNodeSetValue: Can't compare node set "
  6168. "and object of type %d\n",
  6169. val->type);
  6170. xmlXPathReleaseObject(ctxt->context, arg);
  6171. xmlXPathReleaseObject(ctxt->context, val);
  6172. XP_ERROR0(XPATH_INVALID_TYPE);
  6173. }
  6174. return(0);
  6175. }
  6176. /**
  6177. * xmlXPathEqualNodeSetString:
  6178. * @arg: the nodeset object argument
  6179. * @str: the string to compare to.
  6180. * @neq: flag to show whether for '=' (0) or '!=' (1)
  6181. *
  6182. * Implement the equal operation on XPath objects content: @arg1 == @arg2
  6183. * If one object to be compared is a node-set and the other is a string,
  6184. * then the comparison will be true if and only if there is a node in
  6185. * the node-set such that the result of performing the comparison on the
  6186. * string-value of the node and the other string is true.
  6187. *
  6188. * Returns 0 or 1 depending on the results of the test.
  6189. */
  6190. static int
  6191. xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
  6192. {
  6193. int i;
  6194. xmlNodeSetPtr ns;
  6195. xmlChar *str2;
  6196. unsigned int hash;
  6197. if ((str == NULL) || (arg == NULL) ||
  6198. ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
  6199. return (0);
  6200. ns = arg->nodesetval;
  6201. /*
  6202. * A NULL nodeset compared with a string is always false
  6203. * (since there is no node equal, and no node not equal)
  6204. */
  6205. if ((ns == NULL) || (ns->nodeNr <= 0) )
  6206. return (0);
  6207. hash = xmlXPathStringHash(str);
  6208. for (i = 0; i < ns->nodeNr; i++) {
  6209. if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
  6210. str2 = xmlNodeGetContent(ns->nodeTab[i]);
  6211. if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
  6212. xmlFree(str2);
  6213. if (neq)
  6214. continue;
  6215. return (1);
  6216. } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
  6217. if (neq)
  6218. continue;
  6219. return (1);
  6220. } else if (neq) {
  6221. if (str2 != NULL)
  6222. xmlFree(str2);
  6223. return (1);
  6224. }
  6225. if (str2 != NULL)
  6226. xmlFree(str2);
  6227. } else if (neq)
  6228. return (1);
  6229. }
  6230. return (0);
  6231. }
  6232. /**
  6233. * xmlXPathEqualNodeSetFloat:
  6234. * @arg: the nodeset object argument
  6235. * @f: the float to compare to
  6236. * @neq: flag to show whether to compare '=' (0) or '!=' (1)
  6237. *
  6238. * Implement the equal operation on XPath objects content: @arg1 == @arg2
  6239. * If one object to be compared is a node-set and the other is a number,
  6240. * then the comparison will be true if and only if there is a node in
  6241. * the node-set such that the result of performing the comparison on the
  6242. * number to be compared and on the result of converting the string-value
  6243. * of that node to a number using the number function is true.
  6244. *
  6245. * Returns 0 or 1 depending on the results of the test.
  6246. */
  6247. static int
  6248. xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
  6249. xmlXPathObjectPtr arg, double f, int neq) {
  6250. int i, ret=0;
  6251. xmlNodeSetPtr ns;
  6252. xmlChar *str2;
  6253. xmlXPathObjectPtr val;
  6254. double v;
  6255. if ((arg == NULL) ||
  6256. ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
  6257. return(0);
  6258. ns = arg->nodesetval;
  6259. if (ns != NULL) {
  6260. for (i=0;i<ns->nodeNr;i++) {
  6261. str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
  6262. if (str2 != NULL) {
  6263. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
  6264. xmlFree(str2);
  6265. xmlXPathNumberFunction(ctxt, 1);
  6266. val = valuePop(ctxt);
  6267. v = val->floatval;
  6268. xmlXPathReleaseObject(ctxt->context, val);
  6269. if (!xmlXPathIsNaN(v)) {
  6270. if ((!neq) && (v==f)) {
  6271. ret = 1;
  6272. break;
  6273. } else if ((neq) && (v!=f)) {
  6274. ret = 1;
  6275. break;
  6276. }
  6277. } else { /* NaN is unequal to any value */
  6278. if (neq)
  6279. ret = 1;
  6280. }
  6281. }
  6282. }
  6283. }
  6284. return(ret);
  6285. }
  6286. /**
  6287. * xmlXPathEqualNodeSets:
  6288. * @arg1: first nodeset object argument
  6289. * @arg2: second nodeset object argument
  6290. * @neq: flag to show whether to test '=' (0) or '!=' (1)
  6291. *
  6292. * Implement the equal / not equal operation on XPath nodesets:
  6293. * @arg1 == @arg2 or @arg1 != @arg2
  6294. * If both objects to be compared are node-sets, then the comparison
  6295. * will be true if and only if there is a node in the first node-set and
  6296. * a node in the second node-set such that the result of performing the
  6297. * comparison on the string-values of the two nodes is true.
  6298. *
  6299. * (needless to say, this is a costly operation)
  6300. *
  6301. * Returns 0 or 1 depending on the results of the test.
  6302. */
  6303. static int
  6304. xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
  6305. int i, j;
  6306. unsigned int *hashs1;
  6307. unsigned int *hashs2;
  6308. xmlChar **values1;
  6309. xmlChar **values2;
  6310. int ret = 0;
  6311. xmlNodeSetPtr ns1;
  6312. xmlNodeSetPtr ns2;
  6313. if ((arg1 == NULL) ||
  6314. ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
  6315. return(0);
  6316. if ((arg2 == NULL) ||
  6317. ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
  6318. return(0);
  6319. ns1 = arg1->nodesetval;
  6320. ns2 = arg2->nodesetval;
  6321. if ((ns1 == NULL) || (ns1->nodeNr <= 0))
  6322. return(0);
  6323. if ((ns2 == NULL) || (ns2->nodeNr <= 0))
  6324. return(0);
  6325. /*
  6326. * for equal, check if there is a node pertaining to both sets
  6327. */
  6328. if (neq == 0)
  6329. for (i = 0;i < ns1->nodeNr;i++)
  6330. for (j = 0;j < ns2->nodeNr;j++)
  6331. if (ns1->nodeTab[i] == ns2->nodeTab[j])
  6332. return(1);
  6333. values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
  6334. if (values1 == NULL) {
  6335. /* TODO: Propagate memory error. */
  6336. xmlXPathErrMemory(NULL, "comparing nodesets\n");
  6337. return(0);
  6338. }
  6339. hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
  6340. if (hashs1 == NULL) {
  6341. /* TODO: Propagate memory error. */
  6342. xmlXPathErrMemory(NULL, "comparing nodesets\n");
  6343. xmlFree(values1);
  6344. return(0);
  6345. }
  6346. memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
  6347. values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
  6348. if (values2 == NULL) {
  6349. /* TODO: Propagate memory error. */
  6350. xmlXPathErrMemory(NULL, "comparing nodesets\n");
  6351. xmlFree(hashs1);
  6352. xmlFree(values1);
  6353. return(0);
  6354. }
  6355. hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
  6356. if (hashs2 == NULL) {
  6357. /* TODO: Propagate memory error. */
  6358. xmlXPathErrMemory(NULL, "comparing nodesets\n");
  6359. xmlFree(hashs1);
  6360. xmlFree(values1);
  6361. xmlFree(values2);
  6362. return(0);
  6363. }
  6364. memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
  6365. for (i = 0;i < ns1->nodeNr;i++) {
  6366. hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
  6367. for (j = 0;j < ns2->nodeNr;j++) {
  6368. if (i == 0)
  6369. hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
  6370. if (hashs1[i] != hashs2[j]) {
  6371. if (neq) {
  6372. ret = 1;
  6373. break;
  6374. }
  6375. }
  6376. else {
  6377. if (values1[i] == NULL)
  6378. values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
  6379. if (values2[j] == NULL)
  6380. values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
  6381. ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
  6382. if (ret)
  6383. break;
  6384. }
  6385. }
  6386. if (ret)
  6387. break;
  6388. }
  6389. for (i = 0;i < ns1->nodeNr;i++)
  6390. if (values1[i] != NULL)
  6391. xmlFree(values1[i]);
  6392. for (j = 0;j < ns2->nodeNr;j++)
  6393. if (values2[j] != NULL)
  6394. xmlFree(values2[j]);
  6395. xmlFree(values1);
  6396. xmlFree(values2);
  6397. xmlFree(hashs1);
  6398. xmlFree(hashs2);
  6399. return(ret);
  6400. }
  6401. static int
  6402. xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
  6403. xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
  6404. int ret = 0;
  6405. /*
  6406. *At this point we are assured neither arg1 nor arg2
  6407. *is a nodeset, so we can just pick the appropriate routine.
  6408. */
  6409. switch (arg1->type) {
  6410. case XPATH_UNDEFINED:
  6411. #ifdef DEBUG_EXPR
  6412. xmlGenericError(xmlGenericErrorContext,
  6413. "Equal: undefined\n");
  6414. #endif
  6415. break;
  6416. case XPATH_BOOLEAN:
  6417. switch (arg2->type) {
  6418. case XPATH_UNDEFINED:
  6419. #ifdef DEBUG_EXPR
  6420. xmlGenericError(xmlGenericErrorContext,
  6421. "Equal: undefined\n");
  6422. #endif
  6423. break;
  6424. case XPATH_BOOLEAN:
  6425. #ifdef DEBUG_EXPR
  6426. xmlGenericError(xmlGenericErrorContext,
  6427. "Equal: %d boolean %d \n",
  6428. arg1->boolval, arg2->boolval);
  6429. #endif
  6430. ret = (arg1->boolval == arg2->boolval);
  6431. break;
  6432. case XPATH_NUMBER:
  6433. ret = (arg1->boolval ==
  6434. xmlXPathCastNumberToBoolean(arg2->floatval));
  6435. break;
  6436. case XPATH_STRING:
  6437. if ((arg2->stringval == NULL) ||
  6438. (arg2->stringval[0] == 0)) ret = 0;
  6439. else
  6440. ret = 1;
  6441. ret = (arg1->boolval == ret);
  6442. break;
  6443. case XPATH_USERS:
  6444. case XPATH_POINT:
  6445. case XPATH_RANGE:
  6446. case XPATH_LOCATIONSET:
  6447. TODO
  6448. break;
  6449. case XPATH_NODESET:
  6450. case XPATH_XSLT_TREE:
  6451. break;
  6452. }
  6453. break;
  6454. case XPATH_NUMBER:
  6455. switch (arg2->type) {
  6456. case XPATH_UNDEFINED:
  6457. #ifdef DEBUG_EXPR
  6458. xmlGenericError(xmlGenericErrorContext,
  6459. "Equal: undefined\n");
  6460. #endif
  6461. break;
  6462. case XPATH_BOOLEAN:
  6463. ret = (arg2->boolval==
  6464. xmlXPathCastNumberToBoolean(arg1->floatval));
  6465. break;
  6466. case XPATH_STRING:
  6467. valuePush(ctxt, arg2);
  6468. xmlXPathNumberFunction(ctxt, 1);
  6469. arg2 = valuePop(ctxt);
  6470. /* Falls through. */
  6471. case XPATH_NUMBER:
  6472. /* Hand check NaN and Infinity equalities */
  6473. if (xmlXPathIsNaN(arg1->floatval) ||
  6474. xmlXPathIsNaN(arg2->floatval)) {
  6475. ret = 0;
  6476. } else if (xmlXPathIsInf(arg1->floatval) == 1) {
  6477. if (xmlXPathIsInf(arg2->floatval) == 1)
  6478. ret = 1;
  6479. else
  6480. ret = 0;
  6481. } else if (xmlXPathIsInf(arg1->floatval) == -1) {
  6482. if (xmlXPathIsInf(arg2->floatval) == -1)
  6483. ret = 1;
  6484. else
  6485. ret = 0;
  6486. } else if (xmlXPathIsInf(arg2->floatval) == 1) {
  6487. if (xmlXPathIsInf(arg1->floatval) == 1)
  6488. ret = 1;
  6489. else
  6490. ret = 0;
  6491. } else if (xmlXPathIsInf(arg2->floatval) == -1) {
  6492. if (xmlXPathIsInf(arg1->floatval) == -1)
  6493. ret = 1;
  6494. else
  6495. ret = 0;
  6496. } else {
  6497. ret = (arg1->floatval == arg2->floatval);
  6498. }
  6499. break;
  6500. case XPATH_USERS:
  6501. case XPATH_POINT:
  6502. case XPATH_RANGE:
  6503. case XPATH_LOCATIONSET:
  6504. TODO
  6505. break;
  6506. case XPATH_NODESET:
  6507. case XPATH_XSLT_TREE:
  6508. break;
  6509. }
  6510. break;
  6511. case XPATH_STRING:
  6512. switch (arg2->type) {
  6513. case XPATH_UNDEFINED:
  6514. #ifdef DEBUG_EXPR
  6515. xmlGenericError(xmlGenericErrorContext,
  6516. "Equal: undefined\n");
  6517. #endif
  6518. break;
  6519. case XPATH_BOOLEAN:
  6520. if ((arg1->stringval == NULL) ||
  6521. (arg1->stringval[0] == 0)) ret = 0;
  6522. else
  6523. ret = 1;
  6524. ret = (arg2->boolval == ret);
  6525. break;
  6526. case XPATH_STRING:
  6527. ret = xmlStrEqual(arg1->stringval, arg2->stringval);
  6528. break;
  6529. case XPATH_NUMBER:
  6530. valuePush(ctxt, arg1);
  6531. xmlXPathNumberFunction(ctxt, 1);
  6532. arg1 = valuePop(ctxt);
  6533. /* Hand check NaN and Infinity equalities */
  6534. if (xmlXPathIsNaN(arg1->floatval) ||
  6535. xmlXPathIsNaN(arg2->floatval)) {
  6536. ret = 0;
  6537. } else if (xmlXPathIsInf(arg1->floatval) == 1) {
  6538. if (xmlXPathIsInf(arg2->floatval) == 1)
  6539. ret = 1;
  6540. else
  6541. ret = 0;
  6542. } else if (xmlXPathIsInf(arg1->floatval) == -1) {
  6543. if (xmlXPathIsInf(arg2->floatval) == -1)
  6544. ret = 1;
  6545. else
  6546. ret = 0;
  6547. } else if (xmlXPathIsInf(arg2->floatval) == 1) {
  6548. if (xmlXPathIsInf(arg1->floatval) == 1)
  6549. ret = 1;
  6550. else
  6551. ret = 0;
  6552. } else if (xmlXPathIsInf(arg2->floatval) == -1) {
  6553. if (xmlXPathIsInf(arg1->floatval) == -1)
  6554. ret = 1;
  6555. else
  6556. ret = 0;
  6557. } else {
  6558. ret = (arg1->floatval == arg2->floatval);
  6559. }
  6560. break;
  6561. case XPATH_USERS:
  6562. case XPATH_POINT:
  6563. case XPATH_RANGE:
  6564. case XPATH_LOCATIONSET:
  6565. TODO
  6566. break;
  6567. case XPATH_NODESET:
  6568. case XPATH_XSLT_TREE:
  6569. break;
  6570. }
  6571. break;
  6572. case XPATH_USERS:
  6573. case XPATH_POINT:
  6574. case XPATH_RANGE:
  6575. case XPATH_LOCATIONSET:
  6576. TODO
  6577. break;
  6578. case XPATH_NODESET:
  6579. case XPATH_XSLT_TREE:
  6580. break;
  6581. }
  6582. xmlXPathReleaseObject(ctxt->context, arg1);
  6583. xmlXPathReleaseObject(ctxt->context, arg2);
  6584. return(ret);
  6585. }
  6586. /**
  6587. * xmlXPathEqualValues:
  6588. * @ctxt: the XPath Parser context
  6589. *
  6590. * Implement the equal operation on XPath objects content: @arg1 == @arg2
  6591. *
  6592. * Returns 0 or 1 depending on the results of the test.
  6593. */
  6594. int
  6595. xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
  6596. xmlXPathObjectPtr arg1, arg2, argtmp;
  6597. int ret = 0;
  6598. if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
  6599. arg2 = valuePop(ctxt);
  6600. arg1 = valuePop(ctxt);
  6601. if ((arg1 == NULL) || (arg2 == NULL)) {
  6602. if (arg1 != NULL)
  6603. xmlXPathReleaseObject(ctxt->context, arg1);
  6604. else
  6605. xmlXPathReleaseObject(ctxt->context, arg2);
  6606. XP_ERROR0(XPATH_INVALID_OPERAND);
  6607. }
  6608. if (arg1 == arg2) {
  6609. #ifdef DEBUG_EXPR
  6610. xmlGenericError(xmlGenericErrorContext,
  6611. "Equal: by pointer\n");
  6612. #endif
  6613. xmlXPathFreeObject(arg1);
  6614. return(1);
  6615. }
  6616. /*
  6617. *If either argument is a nodeset, it's a 'special case'
  6618. */
  6619. if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
  6620. (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
  6621. /*
  6622. *Hack it to assure arg1 is the nodeset
  6623. */
  6624. if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
  6625. argtmp = arg2;
  6626. arg2 = arg1;
  6627. arg1 = argtmp;
  6628. }
  6629. switch (arg2->type) {
  6630. case XPATH_UNDEFINED:
  6631. #ifdef DEBUG_EXPR
  6632. xmlGenericError(xmlGenericErrorContext,
  6633. "Equal: undefined\n");
  6634. #endif
  6635. break;
  6636. case XPATH_NODESET:
  6637. case XPATH_XSLT_TREE:
  6638. ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
  6639. break;
  6640. case XPATH_BOOLEAN:
  6641. if ((arg1->nodesetval == NULL) ||
  6642. (arg1->nodesetval->nodeNr == 0)) ret = 0;
  6643. else
  6644. ret = 1;
  6645. ret = (ret == arg2->boolval);
  6646. break;
  6647. case XPATH_NUMBER:
  6648. ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
  6649. break;
  6650. case XPATH_STRING:
  6651. ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
  6652. break;
  6653. case XPATH_USERS:
  6654. case XPATH_POINT:
  6655. case XPATH_RANGE:
  6656. case XPATH_LOCATIONSET:
  6657. TODO
  6658. break;
  6659. }
  6660. xmlXPathReleaseObject(ctxt->context, arg1);
  6661. xmlXPathReleaseObject(ctxt->context, arg2);
  6662. return(ret);
  6663. }
  6664. return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
  6665. }
  6666. /**
  6667. * xmlXPathNotEqualValues:
  6668. * @ctxt: the XPath Parser context
  6669. *
  6670. * Implement the equal operation on XPath objects content: @arg1 == @arg2
  6671. *
  6672. * Returns 0 or 1 depending on the results of the test.
  6673. */
  6674. int
  6675. xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
  6676. xmlXPathObjectPtr arg1, arg2, argtmp;
  6677. int ret = 0;
  6678. if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
  6679. arg2 = valuePop(ctxt);
  6680. arg1 = valuePop(ctxt);
  6681. if ((arg1 == NULL) || (arg2 == NULL)) {
  6682. if (arg1 != NULL)
  6683. xmlXPathReleaseObject(ctxt->context, arg1);
  6684. else
  6685. xmlXPathReleaseObject(ctxt->context, arg2);
  6686. XP_ERROR0(XPATH_INVALID_OPERAND);
  6687. }
  6688. if (arg1 == arg2) {
  6689. #ifdef DEBUG_EXPR
  6690. xmlGenericError(xmlGenericErrorContext,
  6691. "NotEqual: by pointer\n");
  6692. #endif
  6693. xmlXPathReleaseObject(ctxt->context, arg1);
  6694. return(0);
  6695. }
  6696. /*
  6697. *If either argument is a nodeset, it's a 'special case'
  6698. */
  6699. if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
  6700. (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
  6701. /*
  6702. *Hack it to assure arg1 is the nodeset
  6703. */
  6704. if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
  6705. argtmp = arg2;
  6706. arg2 = arg1;
  6707. arg1 = argtmp;
  6708. }
  6709. switch (arg2->type) {
  6710. case XPATH_UNDEFINED:
  6711. #ifdef DEBUG_EXPR
  6712. xmlGenericError(xmlGenericErrorContext,
  6713. "NotEqual: undefined\n");
  6714. #endif
  6715. break;
  6716. case XPATH_NODESET:
  6717. case XPATH_XSLT_TREE:
  6718. ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
  6719. break;
  6720. case XPATH_BOOLEAN:
  6721. if ((arg1->nodesetval == NULL) ||
  6722. (arg1->nodesetval->nodeNr == 0)) ret = 0;
  6723. else
  6724. ret = 1;
  6725. ret = (ret != arg2->boolval);
  6726. break;
  6727. case XPATH_NUMBER:
  6728. ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
  6729. break;
  6730. case XPATH_STRING:
  6731. ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
  6732. break;
  6733. case XPATH_USERS:
  6734. case XPATH_POINT:
  6735. case XPATH_RANGE:
  6736. case XPATH_LOCATIONSET:
  6737. TODO
  6738. break;
  6739. }
  6740. xmlXPathReleaseObject(ctxt->context, arg1);
  6741. xmlXPathReleaseObject(ctxt->context, arg2);
  6742. return(ret);
  6743. }
  6744. return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
  6745. }
  6746. /**
  6747. * xmlXPathCompareValues:
  6748. * @ctxt: the XPath Parser context
  6749. * @inf: less than (1) or greater than (0)
  6750. * @strict: is the comparison strict
  6751. *
  6752. * Implement the compare operation on XPath objects:
  6753. * @arg1 < @arg2 (1, 1, ...
  6754. * @arg1 <= @arg2 (1, 0, ...
  6755. * @arg1 > @arg2 (0, 1, ...
  6756. * @arg1 >= @arg2 (0, 0, ...
  6757. *
  6758. * When neither object to be compared is a node-set and the operator is
  6759. * <=, <, >=, >, then the objects are compared by converted both objects
  6760. * to numbers and comparing the numbers according to IEEE 754. The <
  6761. * comparison will be true if and only if the first number is less than the
  6762. * second number. The <= comparison will be true if and only if the first
  6763. * number is less than or equal to the second number. The > comparison
  6764. * will be true if and only if the first number is greater than the second
  6765. * number. The >= comparison will be true if and only if the first number
  6766. * is greater than or equal to the second number.
  6767. *
  6768. * Returns 1 if the comparison succeeded, 0 if it failed
  6769. */
  6770. int
  6771. xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
  6772. int ret = 0, arg1i = 0, arg2i = 0;
  6773. xmlXPathObjectPtr arg1, arg2;
  6774. if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
  6775. arg2 = valuePop(ctxt);
  6776. arg1 = valuePop(ctxt);
  6777. if ((arg1 == NULL) || (arg2 == NULL)) {
  6778. if (arg1 != NULL)
  6779. xmlXPathReleaseObject(ctxt->context, arg1);
  6780. else
  6781. xmlXPathReleaseObject(ctxt->context, arg2);
  6782. XP_ERROR0(XPATH_INVALID_OPERAND);
  6783. }
  6784. if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
  6785. (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
  6786. /*
  6787. * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
  6788. * are not freed from within this routine; they will be freed from the
  6789. * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
  6790. */
  6791. if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
  6792. ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
  6793. ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
  6794. } else {
  6795. if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
  6796. ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
  6797. arg1, arg2);
  6798. } else {
  6799. ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
  6800. arg2, arg1);
  6801. }
  6802. }
  6803. return(ret);
  6804. }
  6805. if (arg1->type != XPATH_NUMBER) {
  6806. valuePush(ctxt, arg1);
  6807. xmlXPathNumberFunction(ctxt, 1);
  6808. arg1 = valuePop(ctxt);
  6809. }
  6810. if (arg1->type != XPATH_NUMBER) {
  6811. xmlXPathFreeObject(arg1);
  6812. xmlXPathFreeObject(arg2);
  6813. XP_ERROR0(XPATH_INVALID_OPERAND);
  6814. }
  6815. if (arg2->type != XPATH_NUMBER) {
  6816. valuePush(ctxt, arg2);
  6817. xmlXPathNumberFunction(ctxt, 1);
  6818. arg2 = valuePop(ctxt);
  6819. }
  6820. if (arg2->type != XPATH_NUMBER) {
  6821. xmlXPathReleaseObject(ctxt->context, arg1);
  6822. xmlXPathReleaseObject(ctxt->context, arg2);
  6823. XP_ERROR0(XPATH_INVALID_OPERAND);
  6824. }
  6825. /*
  6826. * Add tests for infinity and nan
  6827. * => feedback on 3.4 for Inf and NaN
  6828. */
  6829. /* Hand check NaN and Infinity comparisons */
  6830. if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
  6831. ret=0;
  6832. } else {
  6833. arg1i=xmlXPathIsInf(arg1->floatval);
  6834. arg2i=xmlXPathIsInf(arg2->floatval);
  6835. if (inf && strict) {
  6836. if ((arg1i == -1 && arg2i != -1) ||
  6837. (arg2i == 1 && arg1i != 1)) {
  6838. ret = 1;
  6839. } else if (arg1i == 0 && arg2i == 0) {
  6840. ret = (arg1->floatval < arg2->floatval);
  6841. } else {
  6842. ret = 0;
  6843. }
  6844. }
  6845. else if (inf && !strict) {
  6846. if (arg1i == -1 || arg2i == 1) {
  6847. ret = 1;
  6848. } else if (arg1i == 0 && arg2i == 0) {
  6849. ret = (arg1->floatval <= arg2->floatval);
  6850. } else {
  6851. ret = 0;
  6852. }
  6853. }
  6854. else if (!inf && strict) {
  6855. if ((arg1i == 1 && arg2i != 1) ||
  6856. (arg2i == -1 && arg1i != -1)) {
  6857. ret = 1;
  6858. } else if (arg1i == 0 && arg2i == 0) {
  6859. ret = (arg1->floatval > arg2->floatval);
  6860. } else {
  6861. ret = 0;
  6862. }
  6863. }
  6864. else if (!inf && !strict) {
  6865. if (arg1i == 1 || arg2i == -1) {
  6866. ret = 1;
  6867. } else if (arg1i == 0 && arg2i == 0) {
  6868. ret = (arg1->floatval >= arg2->floatval);
  6869. } else {
  6870. ret = 0;
  6871. }
  6872. }
  6873. }
  6874. xmlXPathReleaseObject(ctxt->context, arg1);
  6875. xmlXPathReleaseObject(ctxt->context, arg2);
  6876. return(ret);
  6877. }
  6878. /**
  6879. * xmlXPathValueFlipSign:
  6880. * @ctxt: the XPath Parser context
  6881. *
  6882. * Implement the unary - operation on an XPath object
  6883. * The numeric operators convert their operands to numbers as if
  6884. * by calling the number function.
  6885. */
  6886. void
  6887. xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
  6888. if ((ctxt == NULL) || (ctxt->context == NULL)) return;
  6889. CAST_TO_NUMBER;
  6890. CHECK_TYPE(XPATH_NUMBER);
  6891. ctxt->value->floatval = -ctxt->value->floatval;
  6892. }
  6893. /**
  6894. * xmlXPathAddValues:
  6895. * @ctxt: the XPath Parser context
  6896. *
  6897. * Implement the add operation on XPath objects:
  6898. * The numeric operators convert their operands to numbers as if
  6899. * by calling the number function.
  6900. */
  6901. void
  6902. xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
  6903. xmlXPathObjectPtr arg;
  6904. double val;
  6905. arg = valuePop(ctxt);
  6906. if (arg == NULL)
  6907. XP_ERROR(XPATH_INVALID_OPERAND);
  6908. val = xmlXPathCastToNumber(arg);
  6909. xmlXPathReleaseObject(ctxt->context, arg);
  6910. CAST_TO_NUMBER;
  6911. CHECK_TYPE(XPATH_NUMBER);
  6912. ctxt->value->floatval += val;
  6913. }
  6914. /**
  6915. * xmlXPathSubValues:
  6916. * @ctxt: the XPath Parser context
  6917. *
  6918. * Implement the subtraction operation on XPath objects:
  6919. * The numeric operators convert their operands to numbers as if
  6920. * by calling the number function.
  6921. */
  6922. void
  6923. xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
  6924. xmlXPathObjectPtr arg;
  6925. double val;
  6926. arg = valuePop(ctxt);
  6927. if (arg == NULL)
  6928. XP_ERROR(XPATH_INVALID_OPERAND);
  6929. val = xmlXPathCastToNumber(arg);
  6930. xmlXPathReleaseObject(ctxt->context, arg);
  6931. CAST_TO_NUMBER;
  6932. CHECK_TYPE(XPATH_NUMBER);
  6933. ctxt->value->floatval -= val;
  6934. }
  6935. /**
  6936. * xmlXPathMultValues:
  6937. * @ctxt: the XPath Parser context
  6938. *
  6939. * Implement the multiply operation on XPath objects:
  6940. * The numeric operators convert their operands to numbers as if
  6941. * by calling the number function.
  6942. */
  6943. void
  6944. xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
  6945. xmlXPathObjectPtr arg;
  6946. double val;
  6947. arg = valuePop(ctxt);
  6948. if (arg == NULL)
  6949. XP_ERROR(XPATH_INVALID_OPERAND);
  6950. val = xmlXPathCastToNumber(arg);
  6951. xmlXPathReleaseObject(ctxt->context, arg);
  6952. CAST_TO_NUMBER;
  6953. CHECK_TYPE(XPATH_NUMBER);
  6954. ctxt->value->floatval *= val;
  6955. }
  6956. /**
  6957. * xmlXPathDivValues:
  6958. * @ctxt: the XPath Parser context
  6959. *
  6960. * Implement the div operation on XPath objects @arg1 / @arg2:
  6961. * The numeric operators convert their operands to numbers as if
  6962. * by calling the number function.
  6963. */
  6964. ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
  6965. void
  6966. xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
  6967. xmlXPathObjectPtr arg;
  6968. double val;
  6969. arg = valuePop(ctxt);
  6970. if (arg == NULL)
  6971. XP_ERROR(XPATH_INVALID_OPERAND);
  6972. val = xmlXPathCastToNumber(arg);
  6973. xmlXPathReleaseObject(ctxt->context, arg);
  6974. CAST_TO_NUMBER;
  6975. CHECK_TYPE(XPATH_NUMBER);
  6976. ctxt->value->floatval /= val;
  6977. }
  6978. /**
  6979. * xmlXPathModValues:
  6980. * @ctxt: the XPath Parser context
  6981. *
  6982. * Implement the mod operation on XPath objects: @arg1 / @arg2
  6983. * The numeric operators convert their operands to numbers as if
  6984. * by calling the number function.
  6985. */
  6986. void
  6987. xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
  6988. xmlXPathObjectPtr arg;
  6989. double arg1, arg2;
  6990. arg = valuePop(ctxt);
  6991. if (arg == NULL)
  6992. XP_ERROR(XPATH_INVALID_OPERAND);
  6993. arg2 = xmlXPathCastToNumber(arg);
  6994. xmlXPathReleaseObject(ctxt->context, arg);
  6995. CAST_TO_NUMBER;
  6996. CHECK_TYPE(XPATH_NUMBER);
  6997. arg1 = ctxt->value->floatval;
  6998. if (arg2 == 0)
  6999. ctxt->value->floatval = xmlXPathNAN;
  7000. else {
  7001. ctxt->value->floatval = fmod(arg1, arg2);
  7002. }
  7003. }
  7004. /************************************************************************
  7005. * *
  7006. * The traversal functions *
  7007. * *
  7008. ************************************************************************/
  7009. /*
  7010. * A traversal function enumerates nodes along an axis.
  7011. * Initially it must be called with NULL, and it indicates
  7012. * termination on the axis by returning NULL.
  7013. */
  7014. typedef xmlNodePtr (*xmlXPathTraversalFunction)
  7015. (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
  7016. /*
  7017. * xmlXPathTraversalFunctionExt:
  7018. * A traversal function enumerates nodes along an axis.
  7019. * Initially it must be called with NULL, and it indicates
  7020. * termination on the axis by returning NULL.
  7021. * The context node of the traversal is specified via @contextNode.
  7022. */
  7023. typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
  7024. (xmlNodePtr cur, xmlNodePtr contextNode);
  7025. /*
  7026. * xmlXPathNodeSetMergeFunction:
  7027. * Used for merging node sets in xmlXPathCollectAndTest().
  7028. */
  7029. typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
  7030. (xmlNodeSetPtr, xmlNodeSetPtr);
  7031. /**
  7032. * xmlXPathNextSelf:
  7033. * @ctxt: the XPath Parser context
  7034. * @cur: the current node in the traversal
  7035. *
  7036. * Traversal function for the "self" direction
  7037. * The self axis contains just the context node itself
  7038. *
  7039. * Returns the next element following that axis
  7040. */
  7041. xmlNodePtr
  7042. xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7043. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7044. if (cur == NULL)
  7045. return(ctxt->context->node);
  7046. return(NULL);
  7047. }
  7048. /**
  7049. * xmlXPathNextChild:
  7050. * @ctxt: the XPath Parser context
  7051. * @cur: the current node in the traversal
  7052. *
  7053. * Traversal function for the "child" direction
  7054. * The child axis contains the children of the context node in document order.
  7055. *
  7056. * Returns the next element following that axis
  7057. */
  7058. xmlNodePtr
  7059. xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7060. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7061. if (cur == NULL) {
  7062. if (ctxt->context->node == NULL) return(NULL);
  7063. switch (ctxt->context->node->type) {
  7064. case XML_ELEMENT_NODE:
  7065. case XML_TEXT_NODE:
  7066. case XML_CDATA_SECTION_NODE:
  7067. case XML_ENTITY_REF_NODE:
  7068. case XML_ENTITY_NODE:
  7069. case XML_PI_NODE:
  7070. case XML_COMMENT_NODE:
  7071. case XML_NOTATION_NODE:
  7072. case XML_DTD_NODE:
  7073. return(ctxt->context->node->children);
  7074. case XML_DOCUMENT_NODE:
  7075. case XML_DOCUMENT_TYPE_NODE:
  7076. case XML_DOCUMENT_FRAG_NODE:
  7077. case XML_HTML_DOCUMENT_NODE:
  7078. #ifdef LIBXML_DOCB_ENABLED
  7079. case XML_DOCB_DOCUMENT_NODE:
  7080. #endif
  7081. return(((xmlDocPtr) ctxt->context->node)->children);
  7082. case XML_ELEMENT_DECL:
  7083. case XML_ATTRIBUTE_DECL:
  7084. case XML_ENTITY_DECL:
  7085. case XML_ATTRIBUTE_NODE:
  7086. case XML_NAMESPACE_DECL:
  7087. case XML_XINCLUDE_START:
  7088. case XML_XINCLUDE_END:
  7089. return(NULL);
  7090. }
  7091. return(NULL);
  7092. }
  7093. if ((cur->type == XML_DOCUMENT_NODE) ||
  7094. (cur->type == XML_HTML_DOCUMENT_NODE))
  7095. return(NULL);
  7096. return(cur->next);
  7097. }
  7098. /**
  7099. * xmlXPathNextChildElement:
  7100. * @ctxt: the XPath Parser context
  7101. * @cur: the current node in the traversal
  7102. *
  7103. * Traversal function for the "child" direction and nodes of type element.
  7104. * The child axis contains the children of the context node in document order.
  7105. *
  7106. * Returns the next element following that axis
  7107. */
  7108. static xmlNodePtr
  7109. xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7110. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7111. if (cur == NULL) {
  7112. cur = ctxt->context->node;
  7113. if (cur == NULL) return(NULL);
  7114. /*
  7115. * Get the first element child.
  7116. */
  7117. switch (cur->type) {
  7118. case XML_ELEMENT_NODE:
  7119. case XML_DOCUMENT_FRAG_NODE:
  7120. case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
  7121. case XML_ENTITY_NODE:
  7122. cur = cur->children;
  7123. if (cur != NULL) {
  7124. if (cur->type == XML_ELEMENT_NODE)
  7125. return(cur);
  7126. do {
  7127. cur = cur->next;
  7128. } while ((cur != NULL) &&
  7129. (cur->type != XML_ELEMENT_NODE));
  7130. return(cur);
  7131. }
  7132. return(NULL);
  7133. case XML_DOCUMENT_NODE:
  7134. case XML_HTML_DOCUMENT_NODE:
  7135. #ifdef LIBXML_DOCB_ENABLED
  7136. case XML_DOCB_DOCUMENT_NODE:
  7137. #endif
  7138. return(xmlDocGetRootElement((xmlDocPtr) cur));
  7139. default:
  7140. return(NULL);
  7141. }
  7142. return(NULL);
  7143. }
  7144. /*
  7145. * Get the next sibling element node.
  7146. */
  7147. switch (cur->type) {
  7148. case XML_ELEMENT_NODE:
  7149. case XML_TEXT_NODE:
  7150. case XML_ENTITY_REF_NODE:
  7151. case XML_ENTITY_NODE:
  7152. case XML_CDATA_SECTION_NODE:
  7153. case XML_PI_NODE:
  7154. case XML_COMMENT_NODE:
  7155. case XML_XINCLUDE_END:
  7156. break;
  7157. /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
  7158. default:
  7159. return(NULL);
  7160. }
  7161. if (cur->next != NULL) {
  7162. if (cur->next->type == XML_ELEMENT_NODE)
  7163. return(cur->next);
  7164. cur = cur->next;
  7165. do {
  7166. cur = cur->next;
  7167. } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
  7168. return(cur);
  7169. }
  7170. return(NULL);
  7171. }
  7172. #if 0
  7173. /**
  7174. * xmlXPathNextDescendantOrSelfElemParent:
  7175. * @ctxt: the XPath Parser context
  7176. * @cur: the current node in the traversal
  7177. *
  7178. * Traversal function for the "descendant-or-self" axis.
  7179. * Additionally it returns only nodes which can be parents of
  7180. * element nodes.
  7181. *
  7182. *
  7183. * Returns the next element following that axis
  7184. */
  7185. static xmlNodePtr
  7186. xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
  7187. xmlNodePtr contextNode)
  7188. {
  7189. if (cur == NULL) {
  7190. if (contextNode == NULL)
  7191. return(NULL);
  7192. switch (contextNode->type) {
  7193. case XML_ELEMENT_NODE:
  7194. case XML_XINCLUDE_START:
  7195. case XML_DOCUMENT_FRAG_NODE:
  7196. case XML_DOCUMENT_NODE:
  7197. #ifdef LIBXML_DOCB_ENABLED
  7198. case XML_DOCB_DOCUMENT_NODE:
  7199. #endif
  7200. case XML_HTML_DOCUMENT_NODE:
  7201. return(contextNode);
  7202. default:
  7203. return(NULL);
  7204. }
  7205. return(NULL);
  7206. } else {
  7207. xmlNodePtr start = cur;
  7208. while (cur != NULL) {
  7209. switch (cur->type) {
  7210. case XML_ELEMENT_NODE:
  7211. /* TODO: OK to have XInclude here? */
  7212. case XML_XINCLUDE_START:
  7213. case XML_DOCUMENT_FRAG_NODE:
  7214. if (cur != start)
  7215. return(cur);
  7216. if (cur->children != NULL) {
  7217. cur = cur->children;
  7218. continue;
  7219. }
  7220. break;
  7221. /* Not sure if we need those here. */
  7222. case XML_DOCUMENT_NODE:
  7223. #ifdef LIBXML_DOCB_ENABLED
  7224. case XML_DOCB_DOCUMENT_NODE:
  7225. #endif
  7226. case XML_HTML_DOCUMENT_NODE:
  7227. if (cur != start)
  7228. return(cur);
  7229. return(xmlDocGetRootElement((xmlDocPtr) cur));
  7230. default:
  7231. break;
  7232. }
  7233. next_sibling:
  7234. if ((cur == NULL) || (cur == contextNode))
  7235. return(NULL);
  7236. if (cur->next != NULL) {
  7237. cur = cur->next;
  7238. } else {
  7239. cur = cur->parent;
  7240. goto next_sibling;
  7241. }
  7242. }
  7243. }
  7244. return(NULL);
  7245. }
  7246. #endif
  7247. /**
  7248. * xmlXPathNextDescendant:
  7249. * @ctxt: the XPath Parser context
  7250. * @cur: the current node in the traversal
  7251. *
  7252. * Traversal function for the "descendant" direction
  7253. * the descendant axis contains the descendants of the context node in document
  7254. * order; a descendant is a child or a child of a child and so on.
  7255. *
  7256. * Returns the next element following that axis
  7257. */
  7258. xmlNodePtr
  7259. xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7260. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7261. if (cur == NULL) {
  7262. if (ctxt->context->node == NULL)
  7263. return(NULL);
  7264. if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
  7265. (ctxt->context->node->type == XML_NAMESPACE_DECL))
  7266. return(NULL);
  7267. if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
  7268. return(ctxt->context->doc->children);
  7269. return(ctxt->context->node->children);
  7270. }
  7271. if (cur->type == XML_NAMESPACE_DECL)
  7272. return(NULL);
  7273. if (cur->children != NULL) {
  7274. /*
  7275. * Do not descend on entities declarations
  7276. */
  7277. if (cur->children->type != XML_ENTITY_DECL) {
  7278. cur = cur->children;
  7279. /*
  7280. * Skip DTDs
  7281. */
  7282. if (cur->type != XML_DTD_NODE)
  7283. return(cur);
  7284. }
  7285. }
  7286. if (cur == ctxt->context->node) return(NULL);
  7287. while (cur->next != NULL) {
  7288. cur = cur->next;
  7289. if ((cur->type != XML_ENTITY_DECL) &&
  7290. (cur->type != XML_DTD_NODE))
  7291. return(cur);
  7292. }
  7293. do {
  7294. cur = cur->parent;
  7295. if (cur == NULL) break;
  7296. if (cur == ctxt->context->node) return(NULL);
  7297. if (cur->next != NULL) {
  7298. cur = cur->next;
  7299. return(cur);
  7300. }
  7301. } while (cur != NULL);
  7302. return(cur);
  7303. }
  7304. /**
  7305. * xmlXPathNextDescendantOrSelf:
  7306. * @ctxt: the XPath Parser context
  7307. * @cur: the current node in the traversal
  7308. *
  7309. * Traversal function for the "descendant-or-self" direction
  7310. * the descendant-or-self axis contains the context node and the descendants
  7311. * of the context node in document order; thus the context node is the first
  7312. * node on the axis, and the first child of the context node is the second node
  7313. * on the axis
  7314. *
  7315. * Returns the next element following that axis
  7316. */
  7317. xmlNodePtr
  7318. xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7319. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7320. if (cur == NULL)
  7321. return(ctxt->context->node);
  7322. if (ctxt->context->node == NULL)
  7323. return(NULL);
  7324. if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
  7325. (ctxt->context->node->type == XML_NAMESPACE_DECL))
  7326. return(NULL);
  7327. return(xmlXPathNextDescendant(ctxt, cur));
  7328. }
  7329. /**
  7330. * xmlXPathNextParent:
  7331. * @ctxt: the XPath Parser context
  7332. * @cur: the current node in the traversal
  7333. *
  7334. * Traversal function for the "parent" direction
  7335. * The parent axis contains the parent of the context node, if there is one.
  7336. *
  7337. * Returns the next element following that axis
  7338. */
  7339. xmlNodePtr
  7340. xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7341. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7342. /*
  7343. * the parent of an attribute or namespace node is the element
  7344. * to which the attribute or namespace node is attached
  7345. * Namespace handling !!!
  7346. */
  7347. if (cur == NULL) {
  7348. if (ctxt->context->node == NULL) return(NULL);
  7349. switch (ctxt->context->node->type) {
  7350. case XML_ELEMENT_NODE:
  7351. case XML_TEXT_NODE:
  7352. case XML_CDATA_SECTION_NODE:
  7353. case XML_ENTITY_REF_NODE:
  7354. case XML_ENTITY_NODE:
  7355. case XML_PI_NODE:
  7356. case XML_COMMENT_NODE:
  7357. case XML_NOTATION_NODE:
  7358. case XML_DTD_NODE:
  7359. case XML_ELEMENT_DECL:
  7360. case XML_ATTRIBUTE_DECL:
  7361. case XML_XINCLUDE_START:
  7362. case XML_XINCLUDE_END:
  7363. case XML_ENTITY_DECL:
  7364. if (ctxt->context->node->parent == NULL)
  7365. return((xmlNodePtr) ctxt->context->doc);
  7366. if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
  7367. ((ctxt->context->node->parent->name[0] == ' ') ||
  7368. (xmlStrEqual(ctxt->context->node->parent->name,
  7369. BAD_CAST "fake node libxslt"))))
  7370. return(NULL);
  7371. return(ctxt->context->node->parent);
  7372. case XML_ATTRIBUTE_NODE: {
  7373. xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
  7374. return(att->parent);
  7375. }
  7376. case XML_DOCUMENT_NODE:
  7377. case XML_DOCUMENT_TYPE_NODE:
  7378. case XML_DOCUMENT_FRAG_NODE:
  7379. case XML_HTML_DOCUMENT_NODE:
  7380. #ifdef LIBXML_DOCB_ENABLED
  7381. case XML_DOCB_DOCUMENT_NODE:
  7382. #endif
  7383. return(NULL);
  7384. case XML_NAMESPACE_DECL: {
  7385. xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
  7386. if ((ns->next != NULL) &&
  7387. (ns->next->type != XML_NAMESPACE_DECL))
  7388. return((xmlNodePtr) ns->next);
  7389. return(NULL);
  7390. }
  7391. }
  7392. }
  7393. return(NULL);
  7394. }
  7395. /**
  7396. * xmlXPathNextAncestor:
  7397. * @ctxt: the XPath Parser context
  7398. * @cur: the current node in the traversal
  7399. *
  7400. * Traversal function for the "ancestor" direction
  7401. * the ancestor axis contains the ancestors of the context node; the ancestors
  7402. * of the context node consist of the parent of context node and the parent's
  7403. * parent and so on; the nodes are ordered in reverse document order; thus the
  7404. * parent is the first node on the axis, and the parent's parent is the second
  7405. * node on the axis
  7406. *
  7407. * Returns the next element following that axis
  7408. */
  7409. xmlNodePtr
  7410. xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7411. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7412. /*
  7413. * the parent of an attribute or namespace node is the element
  7414. * to which the attribute or namespace node is attached
  7415. * !!!!!!!!!!!!!
  7416. */
  7417. if (cur == NULL) {
  7418. if (ctxt->context->node == NULL) return(NULL);
  7419. switch (ctxt->context->node->type) {
  7420. case XML_ELEMENT_NODE:
  7421. case XML_TEXT_NODE:
  7422. case XML_CDATA_SECTION_NODE:
  7423. case XML_ENTITY_REF_NODE:
  7424. case XML_ENTITY_NODE:
  7425. case XML_PI_NODE:
  7426. case XML_COMMENT_NODE:
  7427. case XML_DTD_NODE:
  7428. case XML_ELEMENT_DECL:
  7429. case XML_ATTRIBUTE_DECL:
  7430. case XML_ENTITY_DECL:
  7431. case XML_NOTATION_NODE:
  7432. case XML_XINCLUDE_START:
  7433. case XML_XINCLUDE_END:
  7434. if (ctxt->context->node->parent == NULL)
  7435. return((xmlNodePtr) ctxt->context->doc);
  7436. if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
  7437. ((ctxt->context->node->parent->name[0] == ' ') ||
  7438. (xmlStrEqual(ctxt->context->node->parent->name,
  7439. BAD_CAST "fake node libxslt"))))
  7440. return(NULL);
  7441. return(ctxt->context->node->parent);
  7442. case XML_ATTRIBUTE_NODE: {
  7443. xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
  7444. return(tmp->parent);
  7445. }
  7446. case XML_DOCUMENT_NODE:
  7447. case XML_DOCUMENT_TYPE_NODE:
  7448. case XML_DOCUMENT_FRAG_NODE:
  7449. case XML_HTML_DOCUMENT_NODE:
  7450. #ifdef LIBXML_DOCB_ENABLED
  7451. case XML_DOCB_DOCUMENT_NODE:
  7452. #endif
  7453. return(NULL);
  7454. case XML_NAMESPACE_DECL: {
  7455. xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
  7456. if ((ns->next != NULL) &&
  7457. (ns->next->type != XML_NAMESPACE_DECL))
  7458. return((xmlNodePtr) ns->next);
  7459. /* Bad, how did that namespace end up here ? */
  7460. return(NULL);
  7461. }
  7462. }
  7463. return(NULL);
  7464. }
  7465. if (cur == ctxt->context->doc->children)
  7466. return((xmlNodePtr) ctxt->context->doc);
  7467. if (cur == (xmlNodePtr) ctxt->context->doc)
  7468. return(NULL);
  7469. switch (cur->type) {
  7470. case XML_ELEMENT_NODE:
  7471. case XML_TEXT_NODE:
  7472. case XML_CDATA_SECTION_NODE:
  7473. case XML_ENTITY_REF_NODE:
  7474. case XML_ENTITY_NODE:
  7475. case XML_PI_NODE:
  7476. case XML_COMMENT_NODE:
  7477. case XML_NOTATION_NODE:
  7478. case XML_DTD_NODE:
  7479. case XML_ELEMENT_DECL:
  7480. case XML_ATTRIBUTE_DECL:
  7481. case XML_ENTITY_DECL:
  7482. case XML_XINCLUDE_START:
  7483. case XML_XINCLUDE_END:
  7484. if (cur->parent == NULL)
  7485. return(NULL);
  7486. if ((cur->parent->type == XML_ELEMENT_NODE) &&
  7487. ((cur->parent->name[0] == ' ') ||
  7488. (xmlStrEqual(cur->parent->name,
  7489. BAD_CAST "fake node libxslt"))))
  7490. return(NULL);
  7491. return(cur->parent);
  7492. case XML_ATTRIBUTE_NODE: {
  7493. xmlAttrPtr att = (xmlAttrPtr) cur;
  7494. return(att->parent);
  7495. }
  7496. case XML_NAMESPACE_DECL: {
  7497. xmlNsPtr ns = (xmlNsPtr) cur;
  7498. if ((ns->next != NULL) &&
  7499. (ns->next->type != XML_NAMESPACE_DECL))
  7500. return((xmlNodePtr) ns->next);
  7501. /* Bad, how did that namespace end up here ? */
  7502. return(NULL);
  7503. }
  7504. case XML_DOCUMENT_NODE:
  7505. case XML_DOCUMENT_TYPE_NODE:
  7506. case XML_DOCUMENT_FRAG_NODE:
  7507. case XML_HTML_DOCUMENT_NODE:
  7508. #ifdef LIBXML_DOCB_ENABLED
  7509. case XML_DOCB_DOCUMENT_NODE:
  7510. #endif
  7511. return(NULL);
  7512. }
  7513. return(NULL);
  7514. }
  7515. /**
  7516. * xmlXPathNextAncestorOrSelf:
  7517. * @ctxt: the XPath Parser context
  7518. * @cur: the current node in the traversal
  7519. *
  7520. * Traversal function for the "ancestor-or-self" direction
  7521. * he ancestor-or-self axis contains the context node and ancestors of
  7522. * the context node in reverse document order; thus the context node is
  7523. * the first node on the axis, and the context node's parent the second;
  7524. * parent here is defined the same as with the parent axis.
  7525. *
  7526. * Returns the next element following that axis
  7527. */
  7528. xmlNodePtr
  7529. xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7530. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7531. if (cur == NULL)
  7532. return(ctxt->context->node);
  7533. return(xmlXPathNextAncestor(ctxt, cur));
  7534. }
  7535. /**
  7536. * xmlXPathNextFollowingSibling:
  7537. * @ctxt: the XPath Parser context
  7538. * @cur: the current node in the traversal
  7539. *
  7540. * Traversal function for the "following-sibling" direction
  7541. * The following-sibling axis contains the following siblings of the context
  7542. * node in document order.
  7543. *
  7544. * Returns the next element following that axis
  7545. */
  7546. xmlNodePtr
  7547. xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7548. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7549. if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
  7550. (ctxt->context->node->type == XML_NAMESPACE_DECL))
  7551. return(NULL);
  7552. if (cur == (xmlNodePtr) ctxt->context->doc)
  7553. return(NULL);
  7554. if (cur == NULL)
  7555. return(ctxt->context->node->next);
  7556. return(cur->next);
  7557. }
  7558. /**
  7559. * xmlXPathNextPrecedingSibling:
  7560. * @ctxt: the XPath Parser context
  7561. * @cur: the current node in the traversal
  7562. *
  7563. * Traversal function for the "preceding-sibling" direction
  7564. * The preceding-sibling axis contains the preceding siblings of the context
  7565. * node in reverse document order; the first preceding sibling is first on the
  7566. * axis; the sibling preceding that node is the second on the axis and so on.
  7567. *
  7568. * Returns the next element following that axis
  7569. */
  7570. xmlNodePtr
  7571. xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7572. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7573. if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
  7574. (ctxt->context->node->type == XML_NAMESPACE_DECL))
  7575. return(NULL);
  7576. if (cur == (xmlNodePtr) ctxt->context->doc)
  7577. return(NULL);
  7578. if (cur == NULL)
  7579. return(ctxt->context->node->prev);
  7580. if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
  7581. cur = cur->prev;
  7582. if (cur == NULL)
  7583. return(ctxt->context->node->prev);
  7584. }
  7585. return(cur->prev);
  7586. }
  7587. /**
  7588. * xmlXPathNextFollowing:
  7589. * @ctxt: the XPath Parser context
  7590. * @cur: the current node in the traversal
  7591. *
  7592. * Traversal function for the "following" direction
  7593. * The following axis contains all nodes in the same document as the context
  7594. * node that are after the context node in document order, excluding any
  7595. * descendants and excluding attribute nodes and namespace nodes; the nodes
  7596. * are ordered in document order
  7597. *
  7598. * Returns the next element following that axis
  7599. */
  7600. xmlNodePtr
  7601. xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7602. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7603. if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
  7604. (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
  7605. return(cur->children);
  7606. if (cur == NULL) {
  7607. cur = ctxt->context->node;
  7608. if (cur->type == XML_ATTRIBUTE_NODE) {
  7609. cur = cur->parent;
  7610. } else if (cur->type == XML_NAMESPACE_DECL) {
  7611. xmlNsPtr ns = (xmlNsPtr) cur;
  7612. if ((ns->next == NULL) ||
  7613. (ns->next->type == XML_NAMESPACE_DECL))
  7614. return (NULL);
  7615. cur = (xmlNodePtr) ns->next;
  7616. }
  7617. }
  7618. if (cur == NULL) return(NULL) ; /* ERROR */
  7619. if (cur->next != NULL) return(cur->next) ;
  7620. do {
  7621. cur = cur->parent;
  7622. if (cur == NULL) break;
  7623. if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
  7624. if (cur->next != NULL) return(cur->next);
  7625. } while (cur != NULL);
  7626. return(cur);
  7627. }
  7628. /*
  7629. * xmlXPathIsAncestor:
  7630. * @ancestor: the ancestor node
  7631. * @node: the current node
  7632. *
  7633. * Check that @ancestor is a @node's ancestor
  7634. *
  7635. * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
  7636. */
  7637. static int
  7638. xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
  7639. if ((ancestor == NULL) || (node == NULL)) return(0);
  7640. if (node->type == XML_NAMESPACE_DECL)
  7641. return(0);
  7642. if (ancestor->type == XML_NAMESPACE_DECL)
  7643. return(0);
  7644. /* nodes need to be in the same document */
  7645. if (ancestor->doc != node->doc) return(0);
  7646. /* avoid searching if ancestor or node is the root node */
  7647. if (ancestor == (xmlNodePtr) node->doc) return(1);
  7648. if (node == (xmlNodePtr) ancestor->doc) return(0);
  7649. while (node->parent != NULL) {
  7650. if (node->parent == ancestor)
  7651. return(1);
  7652. node = node->parent;
  7653. }
  7654. return(0);
  7655. }
  7656. /**
  7657. * xmlXPathNextPreceding:
  7658. * @ctxt: the XPath Parser context
  7659. * @cur: the current node in the traversal
  7660. *
  7661. * Traversal function for the "preceding" direction
  7662. * the preceding axis contains all nodes in the same document as the context
  7663. * node that are before the context node in document order, excluding any
  7664. * ancestors and excluding attribute nodes and namespace nodes; the nodes are
  7665. * ordered in reverse document order
  7666. *
  7667. * Returns the next element following that axis
  7668. */
  7669. xmlNodePtr
  7670. xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
  7671. {
  7672. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7673. if (cur == NULL) {
  7674. cur = ctxt->context->node;
  7675. if (cur->type == XML_ATTRIBUTE_NODE) {
  7676. cur = cur->parent;
  7677. } else if (cur->type == XML_NAMESPACE_DECL) {
  7678. xmlNsPtr ns = (xmlNsPtr) cur;
  7679. if ((ns->next == NULL) ||
  7680. (ns->next->type == XML_NAMESPACE_DECL))
  7681. return (NULL);
  7682. cur = (xmlNodePtr) ns->next;
  7683. }
  7684. }
  7685. if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
  7686. return (NULL);
  7687. if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
  7688. cur = cur->prev;
  7689. do {
  7690. if (cur->prev != NULL) {
  7691. for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
  7692. return (cur);
  7693. }
  7694. cur = cur->parent;
  7695. if (cur == NULL)
  7696. return (NULL);
  7697. if (cur == ctxt->context->doc->children)
  7698. return (NULL);
  7699. } while (xmlXPathIsAncestor(cur, ctxt->context->node));
  7700. return (cur);
  7701. }
  7702. /**
  7703. * xmlXPathNextPrecedingInternal:
  7704. * @ctxt: the XPath Parser context
  7705. * @cur: the current node in the traversal
  7706. *
  7707. * Traversal function for the "preceding" direction
  7708. * the preceding axis contains all nodes in the same document as the context
  7709. * node that are before the context node in document order, excluding any
  7710. * ancestors and excluding attribute nodes and namespace nodes; the nodes are
  7711. * ordered in reverse document order
  7712. * This is a faster implementation but internal only since it requires a
  7713. * state kept in the parser context: ctxt->ancestor.
  7714. *
  7715. * Returns the next element following that axis
  7716. */
  7717. static xmlNodePtr
  7718. xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
  7719. xmlNodePtr cur)
  7720. {
  7721. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7722. if (cur == NULL) {
  7723. cur = ctxt->context->node;
  7724. if (cur == NULL)
  7725. return (NULL);
  7726. if (cur->type == XML_ATTRIBUTE_NODE) {
  7727. cur = cur->parent;
  7728. } else if (cur->type == XML_NAMESPACE_DECL) {
  7729. xmlNsPtr ns = (xmlNsPtr) cur;
  7730. if ((ns->next == NULL) ||
  7731. (ns->next->type == XML_NAMESPACE_DECL))
  7732. return (NULL);
  7733. cur = (xmlNodePtr) ns->next;
  7734. }
  7735. ctxt->ancestor = cur->parent;
  7736. }
  7737. if (cur->type == XML_NAMESPACE_DECL)
  7738. return(NULL);
  7739. if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
  7740. cur = cur->prev;
  7741. while (cur->prev == NULL) {
  7742. cur = cur->parent;
  7743. if (cur == NULL)
  7744. return (NULL);
  7745. if (cur == ctxt->context->doc->children)
  7746. return (NULL);
  7747. if (cur != ctxt->ancestor)
  7748. return (cur);
  7749. ctxt->ancestor = cur->parent;
  7750. }
  7751. cur = cur->prev;
  7752. while (cur->last != NULL)
  7753. cur = cur->last;
  7754. return (cur);
  7755. }
  7756. /**
  7757. * xmlXPathNextNamespace:
  7758. * @ctxt: the XPath Parser context
  7759. * @cur: the current attribute in the traversal
  7760. *
  7761. * Traversal function for the "namespace" direction
  7762. * the namespace axis contains the namespace nodes of the context node;
  7763. * the order of nodes on this axis is implementation-defined; the axis will
  7764. * be empty unless the context node is an element
  7765. *
  7766. * We keep the XML namespace node at the end of the list.
  7767. *
  7768. * Returns the next element following that axis
  7769. */
  7770. xmlNodePtr
  7771. xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7772. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7773. if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
  7774. if (cur == NULL) {
  7775. if (ctxt->context->tmpNsList != NULL)
  7776. xmlFree(ctxt->context->tmpNsList);
  7777. ctxt->context->tmpNsList =
  7778. xmlGetNsList(ctxt->context->doc, ctxt->context->node);
  7779. ctxt->context->tmpNsNr = 0;
  7780. if (ctxt->context->tmpNsList != NULL) {
  7781. while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
  7782. ctxt->context->tmpNsNr++;
  7783. }
  7784. }
  7785. return((xmlNodePtr) xmlXPathXMLNamespace);
  7786. }
  7787. if (ctxt->context->tmpNsNr > 0) {
  7788. return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
  7789. } else {
  7790. if (ctxt->context->tmpNsList != NULL)
  7791. xmlFree(ctxt->context->tmpNsList);
  7792. ctxt->context->tmpNsList = NULL;
  7793. return(NULL);
  7794. }
  7795. }
  7796. /**
  7797. * xmlXPathNextAttribute:
  7798. * @ctxt: the XPath Parser context
  7799. * @cur: the current attribute in the traversal
  7800. *
  7801. * Traversal function for the "attribute" direction
  7802. * TODO: support DTD inherited default attributes
  7803. *
  7804. * Returns the next element following that axis
  7805. */
  7806. xmlNodePtr
  7807. xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7808. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7809. if (ctxt->context->node == NULL)
  7810. return(NULL);
  7811. if (ctxt->context->node->type != XML_ELEMENT_NODE)
  7812. return(NULL);
  7813. if (cur == NULL) {
  7814. if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
  7815. return(NULL);
  7816. return((xmlNodePtr)ctxt->context->node->properties);
  7817. }
  7818. return((xmlNodePtr)cur->next);
  7819. }
  7820. /************************************************************************
  7821. * *
  7822. * NodeTest Functions *
  7823. * *
  7824. ************************************************************************/
  7825. #define IS_FUNCTION 200
  7826. /************************************************************************
  7827. * *
  7828. * Implicit tree core function library *
  7829. * *
  7830. ************************************************************************/
  7831. /**
  7832. * xmlXPathRoot:
  7833. * @ctxt: the XPath Parser context
  7834. *
  7835. * Initialize the context to the root of the document
  7836. */
  7837. void
  7838. xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
  7839. if ((ctxt == NULL) || (ctxt->context == NULL))
  7840. return;
  7841. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  7842. (xmlNodePtr) ctxt->context->doc));
  7843. }
  7844. /************************************************************************
  7845. * *
  7846. * The explicit core function library *
  7847. *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
  7848. * *
  7849. ************************************************************************/
  7850. /**
  7851. * xmlXPathLastFunction:
  7852. * @ctxt: the XPath Parser context
  7853. * @nargs: the number of arguments
  7854. *
  7855. * Implement the last() XPath function
  7856. * number last()
  7857. * The last function returns the number of nodes in the context node list.
  7858. */
  7859. void
  7860. xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7861. CHECK_ARITY(0);
  7862. if (ctxt->context->contextSize >= 0) {
  7863. valuePush(ctxt,
  7864. xmlXPathCacheNewFloat(ctxt->context,
  7865. (double) ctxt->context->contextSize));
  7866. #ifdef DEBUG_EXPR
  7867. xmlGenericError(xmlGenericErrorContext,
  7868. "last() : %d\n", ctxt->context->contextSize);
  7869. #endif
  7870. } else {
  7871. XP_ERROR(XPATH_INVALID_CTXT_SIZE);
  7872. }
  7873. }
  7874. /**
  7875. * xmlXPathPositionFunction:
  7876. * @ctxt: the XPath Parser context
  7877. * @nargs: the number of arguments
  7878. *
  7879. * Implement the position() XPath function
  7880. * number position()
  7881. * The position function returns the position of the context node in the
  7882. * context node list. The first position is 1, and so the last position
  7883. * will be equal to last().
  7884. */
  7885. void
  7886. xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7887. CHECK_ARITY(0);
  7888. if (ctxt->context->proximityPosition >= 0) {
  7889. valuePush(ctxt,
  7890. xmlXPathCacheNewFloat(ctxt->context,
  7891. (double) ctxt->context->proximityPosition));
  7892. #ifdef DEBUG_EXPR
  7893. xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
  7894. ctxt->context->proximityPosition);
  7895. #endif
  7896. } else {
  7897. XP_ERROR(XPATH_INVALID_CTXT_POSITION);
  7898. }
  7899. }
  7900. /**
  7901. * xmlXPathCountFunction:
  7902. * @ctxt: the XPath Parser context
  7903. * @nargs: the number of arguments
  7904. *
  7905. * Implement the count() XPath function
  7906. * number count(node-set)
  7907. */
  7908. void
  7909. xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7910. xmlXPathObjectPtr cur;
  7911. CHECK_ARITY(1);
  7912. if ((ctxt->value == NULL) ||
  7913. ((ctxt->value->type != XPATH_NODESET) &&
  7914. (ctxt->value->type != XPATH_XSLT_TREE)))
  7915. XP_ERROR(XPATH_INVALID_TYPE);
  7916. cur = valuePop(ctxt);
  7917. if ((cur == NULL) || (cur->nodesetval == NULL))
  7918. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
  7919. else
  7920. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
  7921. (double) cur->nodesetval->nodeNr));
  7922. xmlXPathReleaseObject(ctxt->context, cur);
  7923. }
  7924. /**
  7925. * xmlXPathGetElementsByIds:
  7926. * @doc: the document
  7927. * @ids: a whitespace separated list of IDs
  7928. *
  7929. * Selects elements by their unique ID.
  7930. *
  7931. * Returns a node-set of selected elements.
  7932. */
  7933. static xmlNodeSetPtr
  7934. xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
  7935. xmlNodeSetPtr ret;
  7936. const xmlChar *cur = ids;
  7937. xmlChar *ID;
  7938. xmlAttrPtr attr;
  7939. xmlNodePtr elem = NULL;
  7940. if (ids == NULL) return(NULL);
  7941. ret = xmlXPathNodeSetCreate(NULL);
  7942. if (ret == NULL)
  7943. return(ret);
  7944. while (IS_BLANK_CH(*cur)) cur++;
  7945. while (*cur != 0) {
  7946. while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
  7947. cur++;
  7948. ID = xmlStrndup(ids, cur - ids);
  7949. if (ID != NULL) {
  7950. /*
  7951. * We used to check the fact that the value passed
  7952. * was an NCName, but this generated much troubles for
  7953. * me and Aleksey Sanin, people blatantly violated that
  7954. * constraint, like Visa3D spec.
  7955. * if (xmlValidateNCName(ID, 1) == 0)
  7956. */
  7957. attr = xmlGetID(doc, ID);
  7958. if (attr != NULL) {
  7959. if (attr->type == XML_ATTRIBUTE_NODE)
  7960. elem = attr->parent;
  7961. else if (attr->type == XML_ELEMENT_NODE)
  7962. elem = (xmlNodePtr) attr;
  7963. else
  7964. elem = NULL;
  7965. /* TODO: Check memory error. */
  7966. if (elem != NULL)
  7967. xmlXPathNodeSetAdd(ret, elem);
  7968. }
  7969. xmlFree(ID);
  7970. }
  7971. while (IS_BLANK_CH(*cur)) cur++;
  7972. ids = cur;
  7973. }
  7974. return(ret);
  7975. }
  7976. /**
  7977. * xmlXPathIdFunction:
  7978. * @ctxt: the XPath Parser context
  7979. * @nargs: the number of arguments
  7980. *
  7981. * Implement the id() XPath function
  7982. * node-set id(object)
  7983. * The id function selects elements by their unique ID
  7984. * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
  7985. * then the result is the union of the result of applying id to the
  7986. * string value of each of the nodes in the argument node-set. When the
  7987. * argument to id is of any other type, the argument is converted to a
  7988. * string as if by a call to the string function; the string is split
  7989. * into a whitespace-separated list of tokens (whitespace is any sequence
  7990. * of characters matching the production S); the result is a node-set
  7991. * containing the elements in the same document as the context node that
  7992. * have a unique ID equal to any of the tokens in the list.
  7993. */
  7994. void
  7995. xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7996. xmlChar *tokens;
  7997. xmlNodeSetPtr ret;
  7998. xmlXPathObjectPtr obj;
  7999. CHECK_ARITY(1);
  8000. obj = valuePop(ctxt);
  8001. if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
  8002. if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
  8003. xmlNodeSetPtr ns;
  8004. int i;
  8005. /* TODO: Check memory error. */
  8006. ret = xmlXPathNodeSetCreate(NULL);
  8007. if (obj->nodesetval != NULL) {
  8008. for (i = 0; i < obj->nodesetval->nodeNr; i++) {
  8009. tokens =
  8010. xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
  8011. ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
  8012. /* TODO: Check memory error. */
  8013. ret = xmlXPathNodeSetMerge(ret, ns);
  8014. xmlXPathFreeNodeSet(ns);
  8015. if (tokens != NULL)
  8016. xmlFree(tokens);
  8017. }
  8018. }
  8019. xmlXPathReleaseObject(ctxt->context, obj);
  8020. valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
  8021. return;
  8022. }
  8023. obj = xmlXPathCacheConvertString(ctxt->context, obj);
  8024. if (obj == NULL) return;
  8025. ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
  8026. valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
  8027. xmlXPathReleaseObject(ctxt->context, obj);
  8028. return;
  8029. }
  8030. /**
  8031. * xmlXPathLocalNameFunction:
  8032. * @ctxt: the XPath Parser context
  8033. * @nargs: the number of arguments
  8034. *
  8035. * Implement the local-name() XPath function
  8036. * string local-name(node-set?)
  8037. * The local-name function returns a string containing the local part
  8038. * of the name of the node in the argument node-set that is first in
  8039. * document order. If the node-set is empty or the first node has no
  8040. * name, an empty string is returned. If the argument is omitted it
  8041. * defaults to the context node.
  8042. */
  8043. void
  8044. xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8045. xmlXPathObjectPtr cur;
  8046. if (ctxt == NULL) return;
  8047. if (nargs == 0) {
  8048. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  8049. ctxt->context->node));
  8050. nargs = 1;
  8051. }
  8052. CHECK_ARITY(1);
  8053. if ((ctxt->value == NULL) ||
  8054. ((ctxt->value->type != XPATH_NODESET) &&
  8055. (ctxt->value->type != XPATH_XSLT_TREE)))
  8056. XP_ERROR(XPATH_INVALID_TYPE);
  8057. cur = valuePop(ctxt);
  8058. if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
  8059. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  8060. } else {
  8061. int i = 0; /* Should be first in document order !!!!! */
  8062. switch (cur->nodesetval->nodeTab[i]->type) {
  8063. case XML_ELEMENT_NODE:
  8064. case XML_ATTRIBUTE_NODE:
  8065. case XML_PI_NODE:
  8066. if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
  8067. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  8068. else
  8069. valuePush(ctxt,
  8070. xmlXPathCacheNewString(ctxt->context,
  8071. cur->nodesetval->nodeTab[i]->name));
  8072. break;
  8073. case XML_NAMESPACE_DECL:
  8074. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  8075. ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
  8076. break;
  8077. default:
  8078. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  8079. }
  8080. }
  8081. xmlXPathReleaseObject(ctxt->context, cur);
  8082. }
  8083. /**
  8084. * xmlXPathNamespaceURIFunction:
  8085. * @ctxt: the XPath Parser context
  8086. * @nargs: the number of arguments
  8087. *
  8088. * Implement the namespace-uri() XPath function
  8089. * string namespace-uri(node-set?)
  8090. * The namespace-uri function returns a string containing the
  8091. * namespace URI of the expanded name of the node in the argument
  8092. * node-set that is first in document order. If the node-set is empty,
  8093. * the first node has no name, or the expanded name has no namespace
  8094. * URI, an empty string is returned. If the argument is omitted it
  8095. * defaults to the context node.
  8096. */
  8097. void
  8098. xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8099. xmlXPathObjectPtr cur;
  8100. if (ctxt == NULL) return;
  8101. if (nargs == 0) {
  8102. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  8103. ctxt->context->node));
  8104. nargs = 1;
  8105. }
  8106. CHECK_ARITY(1);
  8107. if ((ctxt->value == NULL) ||
  8108. ((ctxt->value->type != XPATH_NODESET) &&
  8109. (ctxt->value->type != XPATH_XSLT_TREE)))
  8110. XP_ERROR(XPATH_INVALID_TYPE);
  8111. cur = valuePop(ctxt);
  8112. if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
  8113. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  8114. } else {
  8115. int i = 0; /* Should be first in document order !!!!! */
  8116. switch (cur->nodesetval->nodeTab[i]->type) {
  8117. case XML_ELEMENT_NODE:
  8118. case XML_ATTRIBUTE_NODE:
  8119. if (cur->nodesetval->nodeTab[i]->ns == NULL)
  8120. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  8121. else
  8122. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  8123. cur->nodesetval->nodeTab[i]->ns->href));
  8124. break;
  8125. default:
  8126. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  8127. }
  8128. }
  8129. xmlXPathReleaseObject(ctxt->context, cur);
  8130. }
  8131. /**
  8132. * xmlXPathNameFunction:
  8133. * @ctxt: the XPath Parser context
  8134. * @nargs: the number of arguments
  8135. *
  8136. * Implement the name() XPath function
  8137. * string name(node-set?)
  8138. * The name function returns a string containing a QName representing
  8139. * the name of the node in the argument node-set that is first in document
  8140. * order. The QName must represent the name with respect to the namespace
  8141. * declarations in effect on the node whose name is being represented.
  8142. * Typically, this will be the form in which the name occurred in the XML
  8143. * source. This need not be the case if there are namespace declarations
  8144. * in effect on the node that associate multiple prefixes with the same
  8145. * namespace. However, an implementation may include information about
  8146. * the original prefix in its representation of nodes; in this case, an
  8147. * implementation can ensure that the returned string is always the same
  8148. * as the QName used in the XML source. If the argument it omitted it
  8149. * defaults to the context node.
  8150. * Libxml keep the original prefix so the "real qualified name" used is
  8151. * returned.
  8152. */
  8153. static void
  8154. xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
  8155. {
  8156. xmlXPathObjectPtr cur;
  8157. if (nargs == 0) {
  8158. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  8159. ctxt->context->node));
  8160. nargs = 1;
  8161. }
  8162. CHECK_ARITY(1);
  8163. if ((ctxt->value == NULL) ||
  8164. ((ctxt->value->type != XPATH_NODESET) &&
  8165. (ctxt->value->type != XPATH_XSLT_TREE)))
  8166. XP_ERROR(XPATH_INVALID_TYPE);
  8167. cur = valuePop(ctxt);
  8168. if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
  8169. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  8170. } else {
  8171. int i = 0; /* Should be first in document order !!!!! */
  8172. switch (cur->nodesetval->nodeTab[i]->type) {
  8173. case XML_ELEMENT_NODE:
  8174. case XML_ATTRIBUTE_NODE:
  8175. if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
  8176. valuePush(ctxt,
  8177. xmlXPathCacheNewCString(ctxt->context, ""));
  8178. else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
  8179. (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
  8180. valuePush(ctxt,
  8181. xmlXPathCacheNewString(ctxt->context,
  8182. cur->nodesetval->nodeTab[i]->name));
  8183. } else {
  8184. xmlChar *fullname;
  8185. fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
  8186. cur->nodesetval->nodeTab[i]->ns->prefix,
  8187. NULL, 0);
  8188. if (fullname == cur->nodesetval->nodeTab[i]->name)
  8189. fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
  8190. if (fullname == NULL) {
  8191. XP_ERROR(XPATH_MEMORY_ERROR);
  8192. }
  8193. valuePush(ctxt, xmlXPathCacheWrapString(
  8194. ctxt->context, fullname));
  8195. }
  8196. break;
  8197. default:
  8198. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  8199. cur->nodesetval->nodeTab[i]));
  8200. xmlXPathLocalNameFunction(ctxt, 1);
  8201. }
  8202. }
  8203. xmlXPathReleaseObject(ctxt->context, cur);
  8204. }
  8205. /**
  8206. * xmlXPathStringFunction:
  8207. * @ctxt: the XPath Parser context
  8208. * @nargs: the number of arguments
  8209. *
  8210. * Implement the string() XPath function
  8211. * string string(object?)
  8212. * The string function converts an object to a string as follows:
  8213. * - A node-set is converted to a string by returning the value of
  8214. * the node in the node-set that is first in document order.
  8215. * If the node-set is empty, an empty string is returned.
  8216. * - A number is converted to a string as follows
  8217. * + NaN is converted to the string NaN
  8218. * + positive zero is converted to the string 0
  8219. * + negative zero is converted to the string 0
  8220. * + positive infinity is converted to the string Infinity
  8221. * + negative infinity is converted to the string -Infinity
  8222. * + if the number is an integer, the number is represented in
  8223. * decimal form as a Number with no decimal point and no leading
  8224. * zeros, preceded by a minus sign (-) if the number is negative
  8225. * + otherwise, the number is represented in decimal form as a
  8226. * Number including a decimal point with at least one digit
  8227. * before the decimal point and at least one digit after the
  8228. * decimal point, preceded by a minus sign (-) if the number
  8229. * is negative; there must be no leading zeros before the decimal
  8230. * point apart possibly from the one required digit immediately
  8231. * before the decimal point; beyond the one required digit
  8232. * after the decimal point there must be as many, but only as
  8233. * many, more digits as are needed to uniquely distinguish the
  8234. * number from all other IEEE 754 numeric values.
  8235. * - The boolean false value is converted to the string false.
  8236. * The boolean true value is converted to the string true.
  8237. *
  8238. * If the argument is omitted, it defaults to a node-set with the
  8239. * context node as its only member.
  8240. */
  8241. void
  8242. xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8243. xmlXPathObjectPtr cur;
  8244. if (ctxt == NULL) return;
  8245. if (nargs == 0) {
  8246. valuePush(ctxt,
  8247. xmlXPathCacheWrapString(ctxt->context,
  8248. xmlXPathCastNodeToString(ctxt->context->node)));
  8249. return;
  8250. }
  8251. CHECK_ARITY(1);
  8252. cur = valuePop(ctxt);
  8253. if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
  8254. valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
  8255. }
  8256. /**
  8257. * xmlXPathStringLengthFunction:
  8258. * @ctxt: the XPath Parser context
  8259. * @nargs: the number of arguments
  8260. *
  8261. * Implement the string-length() XPath function
  8262. * number string-length(string?)
  8263. * The string-length returns the number of characters in the string
  8264. * (see [3.6 Strings]). If the argument is omitted, it defaults to
  8265. * the context node converted to a string, in other words the value
  8266. * of the context node.
  8267. */
  8268. void
  8269. xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8270. xmlXPathObjectPtr cur;
  8271. if (nargs == 0) {
  8272. if ((ctxt == NULL) || (ctxt->context == NULL))
  8273. return;
  8274. if (ctxt->context->node == NULL) {
  8275. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
  8276. } else {
  8277. xmlChar *content;
  8278. content = xmlXPathCastNodeToString(ctxt->context->node);
  8279. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
  8280. xmlUTF8Strlen(content)));
  8281. xmlFree(content);
  8282. }
  8283. return;
  8284. }
  8285. CHECK_ARITY(1);
  8286. CAST_TO_STRING;
  8287. CHECK_TYPE(XPATH_STRING);
  8288. cur = valuePop(ctxt);
  8289. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
  8290. xmlUTF8Strlen(cur->stringval)));
  8291. xmlXPathReleaseObject(ctxt->context, cur);
  8292. }
  8293. /**
  8294. * xmlXPathConcatFunction:
  8295. * @ctxt: the XPath Parser context
  8296. * @nargs: the number of arguments
  8297. *
  8298. * Implement the concat() XPath function
  8299. * string concat(string, string, string*)
  8300. * The concat function returns the concatenation of its arguments.
  8301. */
  8302. void
  8303. xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8304. xmlXPathObjectPtr cur, newobj;
  8305. xmlChar *tmp;
  8306. if (ctxt == NULL) return;
  8307. if (nargs < 2) {
  8308. CHECK_ARITY(2);
  8309. }
  8310. CAST_TO_STRING;
  8311. cur = valuePop(ctxt);
  8312. if ((cur == NULL) || (cur->type != XPATH_STRING)) {
  8313. xmlXPathReleaseObject(ctxt->context, cur);
  8314. return;
  8315. }
  8316. nargs--;
  8317. while (nargs > 0) {
  8318. CAST_TO_STRING;
  8319. newobj = valuePop(ctxt);
  8320. if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
  8321. xmlXPathReleaseObject(ctxt->context, newobj);
  8322. xmlXPathReleaseObject(ctxt->context, cur);
  8323. XP_ERROR(XPATH_INVALID_TYPE);
  8324. }
  8325. tmp = xmlStrcat(newobj->stringval, cur->stringval);
  8326. newobj->stringval = cur->stringval;
  8327. cur->stringval = tmp;
  8328. xmlXPathReleaseObject(ctxt->context, newobj);
  8329. nargs--;
  8330. }
  8331. valuePush(ctxt, cur);
  8332. }
  8333. /**
  8334. * xmlXPathContainsFunction:
  8335. * @ctxt: the XPath Parser context
  8336. * @nargs: the number of arguments
  8337. *
  8338. * Implement the contains() XPath function
  8339. * boolean contains(string, string)
  8340. * The contains function returns true if the first argument string
  8341. * contains the second argument string, and otherwise returns false.
  8342. */
  8343. void
  8344. xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8345. xmlXPathObjectPtr hay, needle;
  8346. CHECK_ARITY(2);
  8347. CAST_TO_STRING;
  8348. CHECK_TYPE(XPATH_STRING);
  8349. needle = valuePop(ctxt);
  8350. CAST_TO_STRING;
  8351. hay = valuePop(ctxt);
  8352. if ((hay == NULL) || (hay->type != XPATH_STRING)) {
  8353. xmlXPathReleaseObject(ctxt->context, hay);
  8354. xmlXPathReleaseObject(ctxt->context, needle);
  8355. XP_ERROR(XPATH_INVALID_TYPE);
  8356. }
  8357. if (xmlStrstr(hay->stringval, needle->stringval))
  8358. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
  8359. else
  8360. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
  8361. xmlXPathReleaseObject(ctxt->context, hay);
  8362. xmlXPathReleaseObject(ctxt->context, needle);
  8363. }
  8364. /**
  8365. * xmlXPathStartsWithFunction:
  8366. * @ctxt: the XPath Parser context
  8367. * @nargs: the number of arguments
  8368. *
  8369. * Implement the starts-with() XPath function
  8370. * boolean starts-with(string, string)
  8371. * The starts-with function returns true if the first argument string
  8372. * starts with the second argument string, and otherwise returns false.
  8373. */
  8374. void
  8375. xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8376. xmlXPathObjectPtr hay, needle;
  8377. int n;
  8378. CHECK_ARITY(2);
  8379. CAST_TO_STRING;
  8380. CHECK_TYPE(XPATH_STRING);
  8381. needle = valuePop(ctxt);
  8382. CAST_TO_STRING;
  8383. hay = valuePop(ctxt);
  8384. if ((hay == NULL) || (hay->type != XPATH_STRING)) {
  8385. xmlXPathReleaseObject(ctxt->context, hay);
  8386. xmlXPathReleaseObject(ctxt->context, needle);
  8387. XP_ERROR(XPATH_INVALID_TYPE);
  8388. }
  8389. n = xmlStrlen(needle->stringval);
  8390. if (xmlStrncmp(hay->stringval, needle->stringval, n))
  8391. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
  8392. else
  8393. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
  8394. xmlXPathReleaseObject(ctxt->context, hay);
  8395. xmlXPathReleaseObject(ctxt->context, needle);
  8396. }
  8397. /**
  8398. * xmlXPathSubstringFunction:
  8399. * @ctxt: the XPath Parser context
  8400. * @nargs: the number of arguments
  8401. *
  8402. * Implement the substring() XPath function
  8403. * string substring(string, number, number?)
  8404. * The substring function returns the substring of the first argument
  8405. * starting at the position specified in the second argument with
  8406. * length specified in the third argument. For example,
  8407. * substring("12345",2,3) returns "234". If the third argument is not
  8408. * specified, it returns the substring starting at the position specified
  8409. * in the second argument and continuing to the end of the string. For
  8410. * example, substring("12345",2) returns "2345". More precisely, each
  8411. * character in the string (see [3.6 Strings]) is considered to have a
  8412. * numeric position: the position of the first character is 1, the position
  8413. * of the second character is 2 and so on. The returned substring contains
  8414. * those characters for which the position of the character is greater than
  8415. * or equal to the second argument and, if the third argument is specified,
  8416. * less than the sum of the second and third arguments; the comparisons
  8417. * and addition used for the above follow the standard IEEE 754 rules. Thus:
  8418. * - substring("12345", 1.5, 2.6) returns "234"
  8419. * - substring("12345", 0, 3) returns "12"
  8420. * - substring("12345", 0 div 0, 3) returns ""
  8421. * - substring("12345", 1, 0 div 0) returns ""
  8422. * - substring("12345", -42, 1 div 0) returns "12345"
  8423. * - substring("12345", -1 div 0, 1 div 0) returns ""
  8424. */
  8425. void
  8426. xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8427. xmlXPathObjectPtr str, start, len;
  8428. double le=0, in;
  8429. int i = 1, j = INT_MAX;
  8430. if (nargs < 2) {
  8431. CHECK_ARITY(2);
  8432. }
  8433. if (nargs > 3) {
  8434. CHECK_ARITY(3);
  8435. }
  8436. /*
  8437. * take care of possible last (position) argument
  8438. */
  8439. if (nargs == 3) {
  8440. CAST_TO_NUMBER;
  8441. CHECK_TYPE(XPATH_NUMBER);
  8442. len = valuePop(ctxt);
  8443. le = len->floatval;
  8444. xmlXPathReleaseObject(ctxt->context, len);
  8445. }
  8446. CAST_TO_NUMBER;
  8447. CHECK_TYPE(XPATH_NUMBER);
  8448. start = valuePop(ctxt);
  8449. in = start->floatval;
  8450. xmlXPathReleaseObject(ctxt->context, start);
  8451. CAST_TO_STRING;
  8452. CHECK_TYPE(XPATH_STRING);
  8453. str = valuePop(ctxt);
  8454. if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
  8455. i = INT_MAX;
  8456. } else if (in >= 1.0) {
  8457. i = (int)in;
  8458. if (in - floor(in) >= 0.5)
  8459. i += 1;
  8460. }
  8461. if (nargs == 3) {
  8462. double rin, rle, end;
  8463. rin = floor(in);
  8464. if (in - rin >= 0.5)
  8465. rin += 1.0;
  8466. rle = floor(le);
  8467. if (le - rle >= 0.5)
  8468. rle += 1.0;
  8469. end = rin + rle;
  8470. if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
  8471. j = 1;
  8472. } else if (end < INT_MAX) {
  8473. j = (int)end;
  8474. }
  8475. }
  8476. if (i < j) {
  8477. xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
  8478. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
  8479. xmlFree(ret);
  8480. } else {
  8481. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  8482. }
  8483. xmlXPathReleaseObject(ctxt->context, str);
  8484. }
  8485. /**
  8486. * xmlXPathSubstringBeforeFunction:
  8487. * @ctxt: the XPath Parser context
  8488. * @nargs: the number of arguments
  8489. *
  8490. * Implement the substring-before() XPath function
  8491. * string substring-before(string, string)
  8492. * The substring-before function returns the substring of the first
  8493. * argument string that precedes the first occurrence of the second
  8494. * argument string in the first argument string, or the empty string
  8495. * if the first argument string does not contain the second argument
  8496. * string. For example, substring-before("1999/04/01","/") returns 1999.
  8497. */
  8498. void
  8499. xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8500. xmlXPathObjectPtr str;
  8501. xmlXPathObjectPtr find;
  8502. xmlBufPtr target;
  8503. const xmlChar *point;
  8504. int offset;
  8505. CHECK_ARITY(2);
  8506. CAST_TO_STRING;
  8507. find = valuePop(ctxt);
  8508. CAST_TO_STRING;
  8509. str = valuePop(ctxt);
  8510. target = xmlBufCreate();
  8511. if (target) {
  8512. point = xmlStrstr(str->stringval, find->stringval);
  8513. if (point) {
  8514. offset = (int)(point - str->stringval);
  8515. xmlBufAdd(target, str->stringval, offset);
  8516. }
  8517. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  8518. xmlBufContent(target)));
  8519. xmlBufFree(target);
  8520. }
  8521. xmlXPathReleaseObject(ctxt->context, str);
  8522. xmlXPathReleaseObject(ctxt->context, find);
  8523. }
  8524. /**
  8525. * xmlXPathSubstringAfterFunction:
  8526. * @ctxt: the XPath Parser context
  8527. * @nargs: the number of arguments
  8528. *
  8529. * Implement the substring-after() XPath function
  8530. * string substring-after(string, string)
  8531. * The substring-after function returns the substring of the first
  8532. * argument string that follows the first occurrence of the second
  8533. * argument string in the first argument string, or the empty stringi
  8534. * if the first argument string does not contain the second argument
  8535. * string. For example, substring-after("1999/04/01","/") returns 04/01,
  8536. * and substring-after("1999/04/01","19") returns 99/04/01.
  8537. */
  8538. void
  8539. xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8540. xmlXPathObjectPtr str;
  8541. xmlXPathObjectPtr find;
  8542. xmlBufPtr target;
  8543. const xmlChar *point;
  8544. int offset;
  8545. CHECK_ARITY(2);
  8546. CAST_TO_STRING;
  8547. find = valuePop(ctxt);
  8548. CAST_TO_STRING;
  8549. str = valuePop(ctxt);
  8550. target = xmlBufCreate();
  8551. if (target) {
  8552. point = xmlStrstr(str->stringval, find->stringval);
  8553. if (point) {
  8554. offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
  8555. xmlBufAdd(target, &str->stringval[offset],
  8556. xmlStrlen(str->stringval) - offset);
  8557. }
  8558. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  8559. xmlBufContent(target)));
  8560. xmlBufFree(target);
  8561. }
  8562. xmlXPathReleaseObject(ctxt->context, str);
  8563. xmlXPathReleaseObject(ctxt->context, find);
  8564. }
  8565. /**
  8566. * xmlXPathNormalizeFunction:
  8567. * @ctxt: the XPath Parser context
  8568. * @nargs: the number of arguments
  8569. *
  8570. * Implement the normalize-space() XPath function
  8571. * string normalize-space(string?)
  8572. * The normalize-space function returns the argument string with white
  8573. * space normalized by stripping leading and trailing whitespace
  8574. * and replacing sequences of whitespace characters by a single
  8575. * space. Whitespace characters are the same allowed by the S production
  8576. * in XML. If the argument is omitted, it defaults to the context
  8577. * node converted to a string, in other words the value of the context node.
  8578. */
  8579. void
  8580. xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8581. xmlXPathObjectPtr obj = NULL;
  8582. xmlChar *source = NULL;
  8583. xmlBufPtr target;
  8584. xmlChar blank;
  8585. if (ctxt == NULL) return;
  8586. if (nargs == 0) {
  8587. /* Use current context node */
  8588. valuePush(ctxt,
  8589. xmlXPathCacheWrapString(ctxt->context,
  8590. xmlXPathCastNodeToString(ctxt->context->node)));
  8591. nargs = 1;
  8592. }
  8593. CHECK_ARITY(1);
  8594. CAST_TO_STRING;
  8595. CHECK_TYPE(XPATH_STRING);
  8596. obj = valuePop(ctxt);
  8597. source = obj->stringval;
  8598. target = xmlBufCreate();
  8599. if (target && source) {
  8600. /* Skip leading whitespaces */
  8601. while (IS_BLANK_CH(*source))
  8602. source++;
  8603. /* Collapse intermediate whitespaces, and skip trailing whitespaces */
  8604. blank = 0;
  8605. while (*source) {
  8606. if (IS_BLANK_CH(*source)) {
  8607. blank = 0x20;
  8608. } else {
  8609. if (blank) {
  8610. xmlBufAdd(target, &blank, 1);
  8611. blank = 0;
  8612. }
  8613. xmlBufAdd(target, source, 1);
  8614. }
  8615. source++;
  8616. }
  8617. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  8618. xmlBufContent(target)));
  8619. xmlBufFree(target);
  8620. }
  8621. xmlXPathReleaseObject(ctxt->context, obj);
  8622. }
  8623. /**
  8624. * xmlXPathTranslateFunction:
  8625. * @ctxt: the XPath Parser context
  8626. * @nargs: the number of arguments
  8627. *
  8628. * Implement the translate() XPath function
  8629. * string translate(string, string, string)
  8630. * The translate function returns the first argument string with
  8631. * occurrences of characters in the second argument string replaced
  8632. * by the character at the corresponding position in the third argument
  8633. * string. For example, translate("bar","abc","ABC") returns the string
  8634. * BAr. If there is a character in the second argument string with no
  8635. * character at a corresponding position in the third argument string
  8636. * (because the second argument string is longer than the third argument
  8637. * string), then occurrences of that character in the first argument
  8638. * string are removed. For example, translate("--aaa--","abc-","ABC")
  8639. * returns "AAA". If a character occurs more than once in second
  8640. * argument string, then the first occurrence determines the replacement
  8641. * character. If the third argument string is longer than the second
  8642. * argument string, then excess characters are ignored.
  8643. */
  8644. void
  8645. xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8646. xmlXPathObjectPtr str;
  8647. xmlXPathObjectPtr from;
  8648. xmlXPathObjectPtr to;
  8649. xmlBufPtr target;
  8650. int offset, max;
  8651. xmlChar ch;
  8652. const xmlChar *point;
  8653. xmlChar *cptr;
  8654. CHECK_ARITY(3);
  8655. CAST_TO_STRING;
  8656. to = valuePop(ctxt);
  8657. CAST_TO_STRING;
  8658. from = valuePop(ctxt);
  8659. CAST_TO_STRING;
  8660. str = valuePop(ctxt);
  8661. target = xmlBufCreate();
  8662. if (target) {
  8663. max = xmlUTF8Strlen(to->stringval);
  8664. for (cptr = str->stringval; (ch=*cptr); ) {
  8665. offset = xmlUTF8Strloc(from->stringval, cptr);
  8666. if (offset >= 0) {
  8667. if (offset < max) {
  8668. point = xmlUTF8Strpos(to->stringval, offset);
  8669. if (point)
  8670. xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
  8671. }
  8672. } else
  8673. xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
  8674. /* Step to next character in input */
  8675. cptr++;
  8676. if ( ch & 0x80 ) {
  8677. /* if not simple ascii, verify proper format */
  8678. if ( (ch & 0xc0) != 0xc0 ) {
  8679. xmlGenericError(xmlGenericErrorContext,
  8680. "xmlXPathTranslateFunction: Invalid UTF8 string\n");
  8681. /* not asserting an XPath error is probably better */
  8682. break;
  8683. }
  8684. /* then skip over remaining bytes for this char */
  8685. while ( (ch <<= 1) & 0x80 )
  8686. if ( (*cptr++ & 0xc0) != 0x80 ) {
  8687. xmlGenericError(xmlGenericErrorContext,
  8688. "xmlXPathTranslateFunction: Invalid UTF8 string\n");
  8689. /* not asserting an XPath error is probably better */
  8690. break;
  8691. }
  8692. if (ch & 0x80) /* must have had error encountered */
  8693. break;
  8694. }
  8695. }
  8696. }
  8697. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  8698. xmlBufContent(target)));
  8699. xmlBufFree(target);
  8700. xmlXPathReleaseObject(ctxt->context, str);
  8701. xmlXPathReleaseObject(ctxt->context, from);
  8702. xmlXPathReleaseObject(ctxt->context, to);
  8703. }
  8704. /**
  8705. * xmlXPathBooleanFunction:
  8706. * @ctxt: the XPath Parser context
  8707. * @nargs: the number of arguments
  8708. *
  8709. * Implement the boolean() XPath function
  8710. * boolean boolean(object)
  8711. * The boolean function converts its argument to a boolean as follows:
  8712. * - a number is true if and only if it is neither positive or
  8713. * negative zero nor NaN
  8714. * - a node-set is true if and only if it is non-empty
  8715. * - a string is true if and only if its length is non-zero
  8716. */
  8717. void
  8718. xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8719. xmlXPathObjectPtr cur;
  8720. CHECK_ARITY(1);
  8721. cur = valuePop(ctxt);
  8722. if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
  8723. cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
  8724. valuePush(ctxt, cur);
  8725. }
  8726. /**
  8727. * xmlXPathNotFunction:
  8728. * @ctxt: the XPath Parser context
  8729. * @nargs: the number of arguments
  8730. *
  8731. * Implement the not() XPath function
  8732. * boolean not(boolean)
  8733. * The not function returns true if its argument is false,
  8734. * and false otherwise.
  8735. */
  8736. void
  8737. xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8738. CHECK_ARITY(1);
  8739. CAST_TO_BOOLEAN;
  8740. CHECK_TYPE(XPATH_BOOLEAN);
  8741. ctxt->value->boolval = ! ctxt->value->boolval;
  8742. }
  8743. /**
  8744. * xmlXPathTrueFunction:
  8745. * @ctxt: the XPath Parser context
  8746. * @nargs: the number of arguments
  8747. *
  8748. * Implement the true() XPath function
  8749. * boolean true()
  8750. */
  8751. void
  8752. xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8753. CHECK_ARITY(0);
  8754. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
  8755. }
  8756. /**
  8757. * xmlXPathFalseFunction:
  8758. * @ctxt: the XPath Parser context
  8759. * @nargs: the number of arguments
  8760. *
  8761. * Implement the false() XPath function
  8762. * boolean false()
  8763. */
  8764. void
  8765. xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8766. CHECK_ARITY(0);
  8767. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
  8768. }
  8769. /**
  8770. * xmlXPathLangFunction:
  8771. * @ctxt: the XPath Parser context
  8772. * @nargs: the number of arguments
  8773. *
  8774. * Implement the lang() XPath function
  8775. * boolean lang(string)
  8776. * The lang function returns true or false depending on whether the
  8777. * language of the context node as specified by xml:lang attributes
  8778. * is the same as or is a sublanguage of the language specified by
  8779. * the argument string. The language of the context node is determined
  8780. * by the value of the xml:lang attribute on the context node, or, if
  8781. * the context node has no xml:lang attribute, by the value of the
  8782. * xml:lang attribute on the nearest ancestor of the context node that
  8783. * has an xml:lang attribute. If there is no such attribute, then lang
  8784. * returns false. If there is such an attribute, then lang returns
  8785. * true if the attribute value is equal to the argument ignoring case,
  8786. * or if there is some suffix starting with - such that the attribute
  8787. * value is equal to the argument ignoring that suffix of the attribute
  8788. * value and ignoring case.
  8789. */
  8790. void
  8791. xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8792. xmlXPathObjectPtr val = NULL;
  8793. const xmlChar *theLang = NULL;
  8794. const xmlChar *lang;
  8795. int ret = 0;
  8796. int i;
  8797. CHECK_ARITY(1);
  8798. CAST_TO_STRING;
  8799. CHECK_TYPE(XPATH_STRING);
  8800. val = valuePop(ctxt);
  8801. lang = val->stringval;
  8802. theLang = xmlNodeGetLang(ctxt->context->node);
  8803. if ((theLang != NULL) && (lang != NULL)) {
  8804. for (i = 0;lang[i] != 0;i++)
  8805. if (toupper(lang[i]) != toupper(theLang[i]))
  8806. goto not_equal;
  8807. if ((theLang[i] == 0) || (theLang[i] == '-'))
  8808. ret = 1;
  8809. }
  8810. not_equal:
  8811. if (theLang != NULL)
  8812. xmlFree((void *)theLang);
  8813. xmlXPathReleaseObject(ctxt->context, val);
  8814. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
  8815. }
  8816. /**
  8817. * xmlXPathNumberFunction:
  8818. * @ctxt: the XPath Parser context
  8819. * @nargs: the number of arguments
  8820. *
  8821. * Implement the number() XPath function
  8822. * number number(object?)
  8823. */
  8824. void
  8825. xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8826. xmlXPathObjectPtr cur;
  8827. double res;
  8828. if (ctxt == NULL) return;
  8829. if (nargs == 0) {
  8830. if (ctxt->context->node == NULL) {
  8831. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
  8832. } else {
  8833. xmlChar* content = xmlNodeGetContent(ctxt->context->node);
  8834. res = xmlXPathStringEvalNumber(content);
  8835. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
  8836. xmlFree(content);
  8837. }
  8838. return;
  8839. }
  8840. CHECK_ARITY(1);
  8841. cur = valuePop(ctxt);
  8842. valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
  8843. }
  8844. /**
  8845. * xmlXPathSumFunction:
  8846. * @ctxt: the XPath Parser context
  8847. * @nargs: the number of arguments
  8848. *
  8849. * Implement the sum() XPath function
  8850. * number sum(node-set)
  8851. * The sum function returns the sum of the values of the nodes in
  8852. * the argument node-set.
  8853. */
  8854. void
  8855. xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8856. xmlXPathObjectPtr cur;
  8857. int i;
  8858. double res = 0.0;
  8859. CHECK_ARITY(1);
  8860. if ((ctxt->value == NULL) ||
  8861. ((ctxt->value->type != XPATH_NODESET) &&
  8862. (ctxt->value->type != XPATH_XSLT_TREE)))
  8863. XP_ERROR(XPATH_INVALID_TYPE);
  8864. cur = valuePop(ctxt);
  8865. if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
  8866. for (i = 0; i < cur->nodesetval->nodeNr; i++) {
  8867. res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
  8868. }
  8869. }
  8870. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
  8871. xmlXPathReleaseObject(ctxt->context, cur);
  8872. }
  8873. /**
  8874. * xmlXPathFloorFunction:
  8875. * @ctxt: the XPath Parser context
  8876. * @nargs: the number of arguments
  8877. *
  8878. * Implement the floor() XPath function
  8879. * number floor(number)
  8880. * The floor function returns the largest (closest to positive infinity)
  8881. * number that is not greater than the argument and that is an integer.
  8882. */
  8883. void
  8884. xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8885. CHECK_ARITY(1);
  8886. CAST_TO_NUMBER;
  8887. CHECK_TYPE(XPATH_NUMBER);
  8888. ctxt->value->floatval = floor(ctxt->value->floatval);
  8889. }
  8890. /**
  8891. * xmlXPathCeilingFunction:
  8892. * @ctxt: the XPath Parser context
  8893. * @nargs: the number of arguments
  8894. *
  8895. * Implement the ceiling() XPath function
  8896. * number ceiling(number)
  8897. * The ceiling function returns the smallest (closest to negative infinity)
  8898. * number that is not less than the argument and that is an integer.
  8899. */
  8900. void
  8901. xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8902. CHECK_ARITY(1);
  8903. CAST_TO_NUMBER;
  8904. CHECK_TYPE(XPATH_NUMBER);
  8905. #ifdef _AIX
  8906. /* Work around buggy ceil() function on AIX */
  8907. ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
  8908. #else
  8909. ctxt->value->floatval = ceil(ctxt->value->floatval);
  8910. #endif
  8911. }
  8912. /**
  8913. * xmlXPathRoundFunction:
  8914. * @ctxt: the XPath Parser context
  8915. * @nargs: the number of arguments
  8916. *
  8917. * Implement the round() XPath function
  8918. * number round(number)
  8919. * The round function returns the number that is closest to the
  8920. * argument and that is an integer. If there are two such numbers,
  8921. * then the one that is closest to positive infinity is returned.
  8922. */
  8923. void
  8924. xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8925. double f;
  8926. CHECK_ARITY(1);
  8927. CAST_TO_NUMBER;
  8928. CHECK_TYPE(XPATH_NUMBER);
  8929. f = ctxt->value->floatval;
  8930. if ((f >= -0.5) && (f < 0.5)) {
  8931. /* Handles negative zero. */
  8932. ctxt->value->floatval *= 0.0;
  8933. }
  8934. else {
  8935. double rounded = floor(f);
  8936. if (f - rounded >= 0.5)
  8937. rounded += 1.0;
  8938. ctxt->value->floatval = rounded;
  8939. }
  8940. }
  8941. /************************************************************************
  8942. * *
  8943. * The Parser *
  8944. * *
  8945. ************************************************************************/
  8946. /*
  8947. * a few forward declarations since we use a recursive call based
  8948. * implementation.
  8949. */
  8950. static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
  8951. static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
  8952. static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
  8953. static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
  8954. static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
  8955. int qualified);
  8956. /**
  8957. * xmlXPathCurrentChar:
  8958. * @ctxt: the XPath parser context
  8959. * @cur: pointer to the beginning of the char
  8960. * @len: pointer to the length of the char read
  8961. *
  8962. * The current char value, if using UTF-8 this may actually span multiple
  8963. * bytes in the input buffer.
  8964. *
  8965. * Returns the current char value and its length
  8966. */
  8967. static int
  8968. xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
  8969. unsigned char c;
  8970. unsigned int val;
  8971. const xmlChar *cur;
  8972. if (ctxt == NULL)
  8973. return(0);
  8974. cur = ctxt->cur;
  8975. /*
  8976. * We are supposed to handle UTF8, check it's valid
  8977. * From rfc2044: encoding of the Unicode values on UTF-8:
  8978. *
  8979. * UCS-4 range (hex.) UTF-8 octet sequence (binary)
  8980. * 0000 0000-0000 007F 0xxxxxxx
  8981. * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
  8982. * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
  8983. *
  8984. * Check for the 0x110000 limit too
  8985. */
  8986. c = *cur;
  8987. if (c & 0x80) {
  8988. if ((cur[1] & 0xc0) != 0x80)
  8989. goto encoding_error;
  8990. if ((c & 0xe0) == 0xe0) {
  8991. if ((cur[2] & 0xc0) != 0x80)
  8992. goto encoding_error;
  8993. if ((c & 0xf0) == 0xf0) {
  8994. if (((c & 0xf8) != 0xf0) ||
  8995. ((cur[3] & 0xc0) != 0x80))
  8996. goto encoding_error;
  8997. /* 4-byte code */
  8998. *len = 4;
  8999. val = (cur[0] & 0x7) << 18;
  9000. val |= (cur[1] & 0x3f) << 12;
  9001. val |= (cur[2] & 0x3f) << 6;
  9002. val |= cur[3] & 0x3f;
  9003. } else {
  9004. /* 3-byte code */
  9005. *len = 3;
  9006. val = (cur[0] & 0xf) << 12;
  9007. val |= (cur[1] & 0x3f) << 6;
  9008. val |= cur[2] & 0x3f;
  9009. }
  9010. } else {
  9011. /* 2-byte code */
  9012. *len = 2;
  9013. val = (cur[0] & 0x1f) << 6;
  9014. val |= cur[1] & 0x3f;
  9015. }
  9016. if (!IS_CHAR(val)) {
  9017. XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
  9018. }
  9019. return(val);
  9020. } else {
  9021. /* 1-byte code */
  9022. *len = 1;
  9023. return((int) *cur);
  9024. }
  9025. encoding_error:
  9026. /*
  9027. * If we detect an UTF8 error that probably means that the
  9028. * input encoding didn't get properly advertised in the
  9029. * declaration header. Report the error and switch the encoding
  9030. * to ISO-Latin-1 (if you don't like this policy, just declare the
  9031. * encoding !)
  9032. */
  9033. *len = 0;
  9034. XP_ERROR0(XPATH_ENCODING_ERROR);
  9035. }
  9036. /**
  9037. * xmlXPathParseNCName:
  9038. * @ctxt: the XPath Parser context
  9039. *
  9040. * parse an XML namespace non qualified name.
  9041. *
  9042. * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
  9043. *
  9044. * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
  9045. * CombiningChar | Extender
  9046. *
  9047. * Returns the namespace name or NULL
  9048. */
  9049. xmlChar *
  9050. xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
  9051. const xmlChar *in;
  9052. xmlChar *ret;
  9053. int count = 0;
  9054. if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
  9055. /*
  9056. * Accelerator for simple ASCII names
  9057. */
  9058. in = ctxt->cur;
  9059. if (((*in >= 0x61) && (*in <= 0x7A)) ||
  9060. ((*in >= 0x41) && (*in <= 0x5A)) ||
  9061. (*in == '_')) {
  9062. in++;
  9063. while (((*in >= 0x61) && (*in <= 0x7A)) ||
  9064. ((*in >= 0x41) && (*in <= 0x5A)) ||
  9065. ((*in >= 0x30) && (*in <= 0x39)) ||
  9066. (*in == '_') || (*in == '.') ||
  9067. (*in == '-'))
  9068. in++;
  9069. if ((*in == ' ') || (*in == '>') || (*in == '/') ||
  9070. (*in == '[') || (*in == ']') || (*in == ':') ||
  9071. (*in == '@') || (*in == '*')) {
  9072. count = in - ctxt->cur;
  9073. if (count == 0)
  9074. return(NULL);
  9075. ret = xmlStrndup(ctxt->cur, count);
  9076. ctxt->cur = in;
  9077. return(ret);
  9078. }
  9079. }
  9080. return(xmlXPathParseNameComplex(ctxt, 0));
  9081. }
  9082. /**
  9083. * xmlXPathParseQName:
  9084. * @ctxt: the XPath Parser context
  9085. * @prefix: a xmlChar **
  9086. *
  9087. * parse an XML qualified name
  9088. *
  9089. * [NS 5] QName ::= (Prefix ':')? LocalPart
  9090. *
  9091. * [NS 6] Prefix ::= NCName
  9092. *
  9093. * [NS 7] LocalPart ::= NCName
  9094. *
  9095. * Returns the function returns the local part, and prefix is updated
  9096. * to get the Prefix if any.
  9097. */
  9098. static xmlChar *
  9099. xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
  9100. xmlChar *ret = NULL;
  9101. *prefix = NULL;
  9102. ret = xmlXPathParseNCName(ctxt);
  9103. if (ret && CUR == ':') {
  9104. *prefix = ret;
  9105. NEXT;
  9106. ret = xmlXPathParseNCName(ctxt);
  9107. }
  9108. return(ret);
  9109. }
  9110. /**
  9111. * xmlXPathParseName:
  9112. * @ctxt: the XPath Parser context
  9113. *
  9114. * parse an XML name
  9115. *
  9116. * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
  9117. * CombiningChar | Extender
  9118. *
  9119. * [5] Name ::= (Letter | '_' | ':') (NameChar)*
  9120. *
  9121. * Returns the namespace name or NULL
  9122. */
  9123. xmlChar *
  9124. xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
  9125. const xmlChar *in;
  9126. xmlChar *ret;
  9127. size_t count = 0;
  9128. if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
  9129. /*
  9130. * Accelerator for simple ASCII names
  9131. */
  9132. in = ctxt->cur;
  9133. if (((*in >= 0x61) && (*in <= 0x7A)) ||
  9134. ((*in >= 0x41) && (*in <= 0x5A)) ||
  9135. (*in == '_') || (*in == ':')) {
  9136. in++;
  9137. while (((*in >= 0x61) && (*in <= 0x7A)) ||
  9138. ((*in >= 0x41) && (*in <= 0x5A)) ||
  9139. ((*in >= 0x30) && (*in <= 0x39)) ||
  9140. (*in == '_') || (*in == '-') ||
  9141. (*in == ':') || (*in == '.'))
  9142. in++;
  9143. if ((*in > 0) && (*in < 0x80)) {
  9144. count = in - ctxt->cur;
  9145. if (count > XML_MAX_NAME_LENGTH) {
  9146. ctxt->cur = in;
  9147. XP_ERRORNULL(XPATH_EXPR_ERROR);
  9148. }
  9149. ret = xmlStrndup(ctxt->cur, count);
  9150. ctxt->cur = in;
  9151. return(ret);
  9152. }
  9153. }
  9154. return(xmlXPathParseNameComplex(ctxt, 1));
  9155. }
  9156. static xmlChar *
  9157. xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
  9158. xmlChar buf[XML_MAX_NAMELEN + 5];
  9159. int len = 0, l;
  9160. int c;
  9161. /*
  9162. * Handler for more complex cases
  9163. */
  9164. c = CUR_CHAR(l);
  9165. if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
  9166. (c == '[') || (c == ']') || (c == '@') || /* accelerators */
  9167. (c == '*') || /* accelerators */
  9168. (!IS_LETTER(c) && (c != '_') &&
  9169. ((!qualified) || (c != ':')))) {
  9170. return(NULL);
  9171. }
  9172. while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
  9173. ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
  9174. (c == '.') || (c == '-') ||
  9175. (c == '_') || ((qualified) && (c == ':')) ||
  9176. (IS_COMBINING(c)) ||
  9177. (IS_EXTENDER(c)))) {
  9178. COPY_BUF(l,buf,len,c);
  9179. NEXTL(l);
  9180. c = CUR_CHAR(l);
  9181. if (len >= XML_MAX_NAMELEN) {
  9182. /*
  9183. * Okay someone managed to make a huge name, so he's ready to pay
  9184. * for the processing speed.
  9185. */
  9186. xmlChar *buffer;
  9187. int max = len * 2;
  9188. if (len > XML_MAX_NAME_LENGTH) {
  9189. XP_ERRORNULL(XPATH_EXPR_ERROR);
  9190. }
  9191. buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
  9192. if (buffer == NULL) {
  9193. XP_ERRORNULL(XPATH_MEMORY_ERROR);
  9194. }
  9195. memcpy(buffer, buf, len);
  9196. while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
  9197. (c == '.') || (c == '-') ||
  9198. (c == '_') || ((qualified) && (c == ':')) ||
  9199. (IS_COMBINING(c)) ||
  9200. (IS_EXTENDER(c))) {
  9201. if (len + 10 > max) {
  9202. xmlChar *tmp;
  9203. if (max > XML_MAX_NAME_LENGTH) {
  9204. xmlFree(buffer);
  9205. XP_ERRORNULL(XPATH_EXPR_ERROR);
  9206. }
  9207. max *= 2;
  9208. tmp = (xmlChar *) xmlRealloc(buffer,
  9209. max * sizeof(xmlChar));
  9210. if (tmp == NULL) {
  9211. xmlFree(buffer);
  9212. XP_ERRORNULL(XPATH_MEMORY_ERROR);
  9213. }
  9214. buffer = tmp;
  9215. }
  9216. COPY_BUF(l,buffer,len,c);
  9217. NEXTL(l);
  9218. c = CUR_CHAR(l);
  9219. }
  9220. buffer[len] = 0;
  9221. return(buffer);
  9222. }
  9223. }
  9224. if (len == 0)
  9225. return(NULL);
  9226. return(xmlStrndup(buf, len));
  9227. }
  9228. #define MAX_FRAC 20
  9229. /**
  9230. * xmlXPathStringEvalNumber:
  9231. * @str: A string to scan
  9232. *
  9233. * [30a] Float ::= Number ('e' Digits?)?
  9234. *
  9235. * [30] Number ::= Digits ('.' Digits?)?
  9236. * | '.' Digits
  9237. * [31] Digits ::= [0-9]+
  9238. *
  9239. * Compile a Number in the string
  9240. * In complement of the Number expression, this function also handles
  9241. * negative values : '-' Number.
  9242. *
  9243. * Returns the double value.
  9244. */
  9245. double
  9246. xmlXPathStringEvalNumber(const xmlChar *str) {
  9247. const xmlChar *cur = str;
  9248. double ret;
  9249. int ok = 0;
  9250. int isneg = 0;
  9251. int exponent = 0;
  9252. int is_exponent_negative = 0;
  9253. #ifdef __GNUC__
  9254. unsigned long tmp = 0;
  9255. double temp;
  9256. #endif
  9257. if (cur == NULL) return(0);
  9258. while (IS_BLANK_CH(*cur)) cur++;
  9259. if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
  9260. return(xmlXPathNAN);
  9261. }
  9262. if (*cur == '-') {
  9263. isneg = 1;
  9264. cur++;
  9265. }
  9266. #ifdef __GNUC__
  9267. /*
  9268. * tmp/temp is a workaround against a gcc compiler bug
  9269. * http://veillard.com/gcc.bug
  9270. */
  9271. ret = 0;
  9272. while ((*cur >= '0') && (*cur <= '9')) {
  9273. ret = ret * 10;
  9274. tmp = (*cur - '0');
  9275. ok = 1;
  9276. cur++;
  9277. temp = (double) tmp;
  9278. ret = ret + temp;
  9279. }
  9280. #else
  9281. ret = 0;
  9282. while ((*cur >= '0') && (*cur <= '9')) {
  9283. ret = ret * 10 + (*cur - '0');
  9284. ok = 1;
  9285. cur++;
  9286. }
  9287. #endif
  9288. if (*cur == '.') {
  9289. int v, frac = 0, max;
  9290. double fraction = 0;
  9291. cur++;
  9292. if (((*cur < '0') || (*cur > '9')) && (!ok)) {
  9293. return(xmlXPathNAN);
  9294. }
  9295. while (*cur == '0') {
  9296. frac = frac + 1;
  9297. cur++;
  9298. }
  9299. max = frac + MAX_FRAC;
  9300. while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
  9301. v = (*cur - '0');
  9302. fraction = fraction * 10 + v;
  9303. frac = frac + 1;
  9304. cur++;
  9305. }
  9306. fraction /= pow(10.0, frac);
  9307. ret = ret + fraction;
  9308. while ((*cur >= '0') && (*cur <= '9'))
  9309. cur++;
  9310. }
  9311. if ((*cur == 'e') || (*cur == 'E')) {
  9312. cur++;
  9313. if (*cur == '-') {
  9314. is_exponent_negative = 1;
  9315. cur++;
  9316. } else if (*cur == '+') {
  9317. cur++;
  9318. }
  9319. while ((*cur >= '0') && (*cur <= '9')) {
  9320. if (exponent < 1000000)
  9321. exponent = exponent * 10 + (*cur - '0');
  9322. cur++;
  9323. }
  9324. }
  9325. while (IS_BLANK_CH(*cur)) cur++;
  9326. if (*cur != 0) return(xmlXPathNAN);
  9327. if (isneg) ret = -ret;
  9328. if (is_exponent_negative) exponent = -exponent;
  9329. ret *= pow(10.0, (double)exponent);
  9330. return(ret);
  9331. }
  9332. /**
  9333. * xmlXPathCompNumber:
  9334. * @ctxt: the XPath Parser context
  9335. *
  9336. * [30] Number ::= Digits ('.' Digits?)?
  9337. * | '.' Digits
  9338. * [31] Digits ::= [0-9]+
  9339. *
  9340. * Compile a Number, then push it on the stack
  9341. *
  9342. */
  9343. static void
  9344. xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
  9345. {
  9346. double ret = 0.0;
  9347. int ok = 0;
  9348. int exponent = 0;
  9349. int is_exponent_negative = 0;
  9350. xmlXPathObjectPtr num;
  9351. #ifdef __GNUC__
  9352. unsigned long tmp = 0;
  9353. double temp;
  9354. #endif
  9355. CHECK_ERROR;
  9356. if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
  9357. XP_ERROR(XPATH_NUMBER_ERROR);
  9358. }
  9359. #ifdef __GNUC__
  9360. /*
  9361. * tmp/temp is a workaround against a gcc compiler bug
  9362. * http://veillard.com/gcc.bug
  9363. */
  9364. ret = 0;
  9365. while ((CUR >= '0') && (CUR <= '9')) {
  9366. ret = ret * 10;
  9367. tmp = (CUR - '0');
  9368. ok = 1;
  9369. NEXT;
  9370. temp = (double) tmp;
  9371. ret = ret + temp;
  9372. }
  9373. #else
  9374. ret = 0;
  9375. while ((CUR >= '0') && (CUR <= '9')) {
  9376. ret = ret * 10 + (CUR - '0');
  9377. ok = 1;
  9378. NEXT;
  9379. }
  9380. #endif
  9381. if (CUR == '.') {
  9382. int v, frac = 0, max;
  9383. double fraction = 0;
  9384. NEXT;
  9385. if (((CUR < '0') || (CUR > '9')) && (!ok)) {
  9386. XP_ERROR(XPATH_NUMBER_ERROR);
  9387. }
  9388. while (CUR == '0') {
  9389. frac = frac + 1;
  9390. NEXT;
  9391. }
  9392. max = frac + MAX_FRAC;
  9393. while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
  9394. v = (CUR - '0');
  9395. fraction = fraction * 10 + v;
  9396. frac = frac + 1;
  9397. NEXT;
  9398. }
  9399. fraction /= pow(10.0, frac);
  9400. ret = ret + fraction;
  9401. while ((CUR >= '0') && (CUR <= '9'))
  9402. NEXT;
  9403. }
  9404. if ((CUR == 'e') || (CUR == 'E')) {
  9405. NEXT;
  9406. if (CUR == '-') {
  9407. is_exponent_negative = 1;
  9408. NEXT;
  9409. } else if (CUR == '+') {
  9410. NEXT;
  9411. }
  9412. while ((CUR >= '0') && (CUR <= '9')) {
  9413. if (exponent < 1000000)
  9414. exponent = exponent * 10 + (CUR - '0');
  9415. NEXT;
  9416. }
  9417. if (is_exponent_negative)
  9418. exponent = -exponent;
  9419. ret *= pow(10.0, (double) exponent);
  9420. }
  9421. num = xmlXPathCacheNewFloat(ctxt->context, ret);
  9422. if (num == NULL) {
  9423. ctxt->error = XPATH_MEMORY_ERROR;
  9424. } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
  9425. NULL) == -1) {
  9426. xmlXPathReleaseObject(ctxt->context, num);
  9427. }
  9428. }
  9429. /**
  9430. * xmlXPathParseLiteral:
  9431. * @ctxt: the XPath Parser context
  9432. *
  9433. * Parse a Literal
  9434. *
  9435. * [29] Literal ::= '"' [^"]* '"'
  9436. * | "'" [^']* "'"
  9437. *
  9438. * Returns the value found or NULL in case of error
  9439. */
  9440. static xmlChar *
  9441. xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
  9442. const xmlChar *q;
  9443. xmlChar *ret = NULL;
  9444. if (CUR == '"') {
  9445. NEXT;
  9446. q = CUR_PTR;
  9447. while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
  9448. NEXT;
  9449. if (!IS_CHAR_CH(CUR)) {
  9450. XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
  9451. } else {
  9452. ret = xmlStrndup(q, CUR_PTR - q);
  9453. NEXT;
  9454. }
  9455. } else if (CUR == '\'') {
  9456. NEXT;
  9457. q = CUR_PTR;
  9458. while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
  9459. NEXT;
  9460. if (!IS_CHAR_CH(CUR)) {
  9461. XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
  9462. } else {
  9463. ret = xmlStrndup(q, CUR_PTR - q);
  9464. NEXT;
  9465. }
  9466. } else {
  9467. XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
  9468. }
  9469. return(ret);
  9470. }
  9471. /**
  9472. * xmlXPathCompLiteral:
  9473. * @ctxt: the XPath Parser context
  9474. *
  9475. * Parse a Literal and push it on the stack.
  9476. *
  9477. * [29] Literal ::= '"' [^"]* '"'
  9478. * | "'" [^']* "'"
  9479. *
  9480. * TODO: xmlXPathCompLiteral memory allocation could be improved.
  9481. */
  9482. static void
  9483. xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
  9484. const xmlChar *q;
  9485. xmlChar *ret = NULL;
  9486. xmlXPathObjectPtr lit;
  9487. if (CUR == '"') {
  9488. NEXT;
  9489. q = CUR_PTR;
  9490. while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
  9491. NEXT;
  9492. if (!IS_CHAR_CH(CUR)) {
  9493. XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
  9494. } else {
  9495. ret = xmlStrndup(q, CUR_PTR - q);
  9496. NEXT;
  9497. }
  9498. } else if (CUR == '\'') {
  9499. NEXT;
  9500. q = CUR_PTR;
  9501. while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
  9502. NEXT;
  9503. if (!IS_CHAR_CH(CUR)) {
  9504. XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
  9505. } else {
  9506. ret = xmlStrndup(q, CUR_PTR - q);
  9507. NEXT;
  9508. }
  9509. } else {
  9510. XP_ERROR(XPATH_START_LITERAL_ERROR);
  9511. }
  9512. if (ret == NULL) return;
  9513. lit = xmlXPathCacheNewString(ctxt->context, ret);
  9514. if (lit == NULL) {
  9515. ctxt->error = XPATH_MEMORY_ERROR;
  9516. } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
  9517. NULL) == -1) {
  9518. xmlXPathReleaseObject(ctxt->context, lit);
  9519. }
  9520. xmlFree(ret);
  9521. }
  9522. /**
  9523. * xmlXPathCompVariableReference:
  9524. * @ctxt: the XPath Parser context
  9525. *
  9526. * Parse a VariableReference, evaluate it and push it on the stack.
  9527. *
  9528. * The variable bindings consist of a mapping from variable names
  9529. * to variable values. The value of a variable is an object, which can be
  9530. * of any of the types that are possible for the value of an expression,
  9531. * and may also be of additional types not specified here.
  9532. *
  9533. * Early evaluation is possible since:
  9534. * The variable bindings [...] used to evaluate a subexpression are
  9535. * always the same as those used to evaluate the containing expression.
  9536. *
  9537. * [36] VariableReference ::= '$' QName
  9538. */
  9539. static void
  9540. xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
  9541. xmlChar *name;
  9542. xmlChar *prefix;
  9543. SKIP_BLANKS;
  9544. if (CUR != '$') {
  9545. XP_ERROR(XPATH_VARIABLE_REF_ERROR);
  9546. }
  9547. NEXT;
  9548. name = xmlXPathParseQName(ctxt, &prefix);
  9549. if (name == NULL) {
  9550. xmlFree(prefix);
  9551. XP_ERROR(XPATH_VARIABLE_REF_ERROR);
  9552. }
  9553. ctxt->comp->last = -1;
  9554. if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
  9555. xmlFree(prefix);
  9556. xmlFree(name);
  9557. }
  9558. SKIP_BLANKS;
  9559. if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
  9560. XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
  9561. }
  9562. }
  9563. /**
  9564. * xmlXPathIsNodeType:
  9565. * @name: a name string
  9566. *
  9567. * Is the name given a NodeType one.
  9568. *
  9569. * [38] NodeType ::= 'comment'
  9570. * | 'text'
  9571. * | 'processing-instruction'
  9572. * | 'node'
  9573. *
  9574. * Returns 1 if true 0 otherwise
  9575. */
  9576. int
  9577. xmlXPathIsNodeType(const xmlChar *name) {
  9578. if (name == NULL)
  9579. return(0);
  9580. if (xmlStrEqual(name, BAD_CAST "node"))
  9581. return(1);
  9582. if (xmlStrEqual(name, BAD_CAST "text"))
  9583. return(1);
  9584. if (xmlStrEqual(name, BAD_CAST "comment"))
  9585. return(1);
  9586. if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
  9587. return(1);
  9588. return(0);
  9589. }
  9590. /**
  9591. * xmlXPathCompFunctionCall:
  9592. * @ctxt: the XPath Parser context
  9593. *
  9594. * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
  9595. * [17] Argument ::= Expr
  9596. *
  9597. * Compile a function call, the evaluation of all arguments are
  9598. * pushed on the stack
  9599. */
  9600. static void
  9601. xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
  9602. xmlChar *name;
  9603. xmlChar *prefix;
  9604. int nbargs = 0;
  9605. int sort = 1;
  9606. name = xmlXPathParseQName(ctxt, &prefix);
  9607. if (name == NULL) {
  9608. xmlFree(prefix);
  9609. XP_ERROR(XPATH_EXPR_ERROR);
  9610. }
  9611. SKIP_BLANKS;
  9612. #ifdef DEBUG_EXPR
  9613. if (prefix == NULL)
  9614. xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
  9615. name);
  9616. else
  9617. xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
  9618. prefix, name);
  9619. #endif
  9620. if (CUR != '(') {
  9621. xmlFree(name);
  9622. xmlFree(prefix);
  9623. XP_ERROR(XPATH_EXPR_ERROR);
  9624. }
  9625. NEXT;
  9626. SKIP_BLANKS;
  9627. /*
  9628. * Optimization for count(): we don't need the node-set to be sorted.
  9629. */
  9630. if ((prefix == NULL) && (name[0] == 'c') &&
  9631. xmlStrEqual(name, BAD_CAST "count"))
  9632. {
  9633. sort = 0;
  9634. }
  9635. ctxt->comp->last = -1;
  9636. if (CUR != ')') {
  9637. while (CUR != 0) {
  9638. int op1 = ctxt->comp->last;
  9639. ctxt->comp->last = -1;
  9640. xmlXPathCompileExpr(ctxt, sort);
  9641. if (ctxt->error != XPATH_EXPRESSION_OK) {
  9642. xmlFree(name);
  9643. xmlFree(prefix);
  9644. return;
  9645. }
  9646. PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
  9647. nbargs++;
  9648. if (CUR == ')') break;
  9649. if (CUR != ',') {
  9650. xmlFree(name);
  9651. xmlFree(prefix);
  9652. XP_ERROR(XPATH_EXPR_ERROR);
  9653. }
  9654. NEXT;
  9655. SKIP_BLANKS;
  9656. }
  9657. }
  9658. if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
  9659. xmlFree(prefix);
  9660. xmlFree(name);
  9661. }
  9662. NEXT;
  9663. SKIP_BLANKS;
  9664. }
  9665. /**
  9666. * xmlXPathCompPrimaryExpr:
  9667. * @ctxt: the XPath Parser context
  9668. *
  9669. * [15] PrimaryExpr ::= VariableReference
  9670. * | '(' Expr ')'
  9671. * | Literal
  9672. * | Number
  9673. * | FunctionCall
  9674. *
  9675. * Compile a primary expression.
  9676. */
  9677. static void
  9678. xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
  9679. SKIP_BLANKS;
  9680. if (CUR == '$') xmlXPathCompVariableReference(ctxt);
  9681. else if (CUR == '(') {
  9682. NEXT;
  9683. SKIP_BLANKS;
  9684. xmlXPathCompileExpr(ctxt, 1);
  9685. CHECK_ERROR;
  9686. if (CUR != ')') {
  9687. XP_ERROR(XPATH_EXPR_ERROR);
  9688. }
  9689. NEXT;
  9690. SKIP_BLANKS;
  9691. } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
  9692. xmlXPathCompNumber(ctxt);
  9693. } else if ((CUR == '\'') || (CUR == '"')) {
  9694. xmlXPathCompLiteral(ctxt);
  9695. } else {
  9696. xmlXPathCompFunctionCall(ctxt);
  9697. }
  9698. SKIP_BLANKS;
  9699. }
  9700. /**
  9701. * xmlXPathCompFilterExpr:
  9702. * @ctxt: the XPath Parser context
  9703. *
  9704. * [20] FilterExpr ::= PrimaryExpr
  9705. * | FilterExpr Predicate
  9706. *
  9707. * Compile a filter expression.
  9708. * Square brackets are used to filter expressions in the same way that
  9709. * they are used in location paths. It is an error if the expression to
  9710. * be filtered does not evaluate to a node-set. The context node list
  9711. * used for evaluating the expression in square brackets is the node-set
  9712. * to be filtered listed in document order.
  9713. */
  9714. static void
  9715. xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
  9716. xmlXPathCompPrimaryExpr(ctxt);
  9717. CHECK_ERROR;
  9718. SKIP_BLANKS;
  9719. while (CUR == '[') {
  9720. xmlXPathCompPredicate(ctxt, 1);
  9721. SKIP_BLANKS;
  9722. }
  9723. }
  9724. /**
  9725. * xmlXPathScanName:
  9726. * @ctxt: the XPath Parser context
  9727. *
  9728. * Trickery: parse an XML name but without consuming the input flow
  9729. * Needed to avoid insanity in the parser state.
  9730. *
  9731. * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
  9732. * CombiningChar | Extender
  9733. *
  9734. * [5] Name ::= (Letter | '_' | ':') (NameChar)*
  9735. *
  9736. * [6] Names ::= Name (S Name)*
  9737. *
  9738. * Returns the Name parsed or NULL
  9739. */
  9740. static xmlChar *
  9741. xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
  9742. int len = 0, l;
  9743. int c;
  9744. const xmlChar *cur;
  9745. xmlChar *ret;
  9746. cur = ctxt->cur;
  9747. c = CUR_CHAR(l);
  9748. if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
  9749. (!IS_LETTER(c) && (c != '_') &&
  9750. (c != ':'))) {
  9751. return(NULL);
  9752. }
  9753. while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
  9754. ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
  9755. (c == '.') || (c == '-') ||
  9756. (c == '_') || (c == ':') ||
  9757. (IS_COMBINING(c)) ||
  9758. (IS_EXTENDER(c)))) {
  9759. len += l;
  9760. NEXTL(l);
  9761. c = CUR_CHAR(l);
  9762. }
  9763. ret = xmlStrndup(cur, ctxt->cur - cur);
  9764. ctxt->cur = cur;
  9765. return(ret);
  9766. }
  9767. /**
  9768. * xmlXPathCompPathExpr:
  9769. * @ctxt: the XPath Parser context
  9770. *
  9771. * [19] PathExpr ::= LocationPath
  9772. * | FilterExpr
  9773. * | FilterExpr '/' RelativeLocationPath
  9774. * | FilterExpr '//' RelativeLocationPath
  9775. *
  9776. * Compile a path expression.
  9777. * The / operator and // operators combine an arbitrary expression
  9778. * and a relative location path. It is an error if the expression
  9779. * does not evaluate to a node-set.
  9780. * The / operator does composition in the same way as when / is
  9781. * used in a location path. As in location paths, // is short for
  9782. * /descendant-or-self::node()/.
  9783. */
  9784. static void
  9785. xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
  9786. int lc = 1; /* Should we branch to LocationPath ? */
  9787. xmlChar *name = NULL; /* we may have to preparse a name to find out */
  9788. SKIP_BLANKS;
  9789. if ((CUR == '$') || (CUR == '(') ||
  9790. (IS_ASCII_DIGIT(CUR)) ||
  9791. (CUR == '\'') || (CUR == '"') ||
  9792. (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
  9793. lc = 0;
  9794. } else if (CUR == '*') {
  9795. /* relative or absolute location path */
  9796. lc = 1;
  9797. } else if (CUR == '/') {
  9798. /* relative or absolute location path */
  9799. lc = 1;
  9800. } else if (CUR == '@') {
  9801. /* relative abbreviated attribute location path */
  9802. lc = 1;
  9803. } else if (CUR == '.') {
  9804. /* relative abbreviated attribute location path */
  9805. lc = 1;
  9806. } else {
  9807. /*
  9808. * Problem is finding if we have a name here whether it's:
  9809. * - a nodetype
  9810. * - a function call in which case it's followed by '('
  9811. * - an axis in which case it's followed by ':'
  9812. * - a element name
  9813. * We do an a priori analysis here rather than having to
  9814. * maintain parsed token content through the recursive function
  9815. * calls. This looks uglier but makes the code easier to
  9816. * read/write/debug.
  9817. */
  9818. SKIP_BLANKS;
  9819. name = xmlXPathScanName(ctxt);
  9820. if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
  9821. #ifdef DEBUG_STEP
  9822. xmlGenericError(xmlGenericErrorContext,
  9823. "PathExpr: Axis\n");
  9824. #endif
  9825. lc = 1;
  9826. xmlFree(name);
  9827. } else if (name != NULL) {
  9828. int len =xmlStrlen(name);
  9829. while (NXT(len) != 0) {
  9830. if (NXT(len) == '/') {
  9831. /* element name */
  9832. #ifdef DEBUG_STEP
  9833. xmlGenericError(xmlGenericErrorContext,
  9834. "PathExpr: AbbrRelLocation\n");
  9835. #endif
  9836. lc = 1;
  9837. break;
  9838. } else if (IS_BLANK_CH(NXT(len))) {
  9839. /* ignore blanks */
  9840. ;
  9841. } else if (NXT(len) == ':') {
  9842. #ifdef DEBUG_STEP
  9843. xmlGenericError(xmlGenericErrorContext,
  9844. "PathExpr: AbbrRelLocation\n");
  9845. #endif
  9846. lc = 1;
  9847. break;
  9848. } else if ((NXT(len) == '(')) {
  9849. /* Node Type or Function */
  9850. if (xmlXPathIsNodeType(name)) {
  9851. #ifdef DEBUG_STEP
  9852. xmlGenericError(xmlGenericErrorContext,
  9853. "PathExpr: Type search\n");
  9854. #endif
  9855. lc = 1;
  9856. #ifdef LIBXML_XPTR_ENABLED
  9857. } else if (ctxt->xptr &&
  9858. xmlStrEqual(name, BAD_CAST "range-to")) {
  9859. lc = 1;
  9860. #endif
  9861. } else {
  9862. #ifdef DEBUG_STEP
  9863. xmlGenericError(xmlGenericErrorContext,
  9864. "PathExpr: function call\n");
  9865. #endif
  9866. lc = 0;
  9867. }
  9868. break;
  9869. } else if ((NXT(len) == '[')) {
  9870. /* element name */
  9871. #ifdef DEBUG_STEP
  9872. xmlGenericError(xmlGenericErrorContext,
  9873. "PathExpr: AbbrRelLocation\n");
  9874. #endif
  9875. lc = 1;
  9876. break;
  9877. } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
  9878. (NXT(len) == '=')) {
  9879. lc = 1;
  9880. break;
  9881. } else {
  9882. lc = 1;
  9883. break;
  9884. }
  9885. len++;
  9886. }
  9887. if (NXT(len) == 0) {
  9888. #ifdef DEBUG_STEP
  9889. xmlGenericError(xmlGenericErrorContext,
  9890. "PathExpr: AbbrRelLocation\n");
  9891. #endif
  9892. /* element name */
  9893. lc = 1;
  9894. }
  9895. xmlFree(name);
  9896. } else {
  9897. /* make sure all cases are covered explicitly */
  9898. XP_ERROR(XPATH_EXPR_ERROR);
  9899. }
  9900. }
  9901. if (lc) {
  9902. if (CUR == '/') {
  9903. PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
  9904. } else {
  9905. PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
  9906. }
  9907. xmlXPathCompLocationPath(ctxt);
  9908. } else {
  9909. xmlXPathCompFilterExpr(ctxt);
  9910. CHECK_ERROR;
  9911. if ((CUR == '/') && (NXT(1) == '/')) {
  9912. SKIP(2);
  9913. SKIP_BLANKS;
  9914. PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
  9915. NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
  9916. xmlXPathCompRelativeLocationPath(ctxt);
  9917. } else if (CUR == '/') {
  9918. xmlXPathCompRelativeLocationPath(ctxt);
  9919. }
  9920. }
  9921. SKIP_BLANKS;
  9922. }
  9923. /**
  9924. * xmlXPathCompUnionExpr:
  9925. * @ctxt: the XPath Parser context
  9926. *
  9927. * [18] UnionExpr ::= PathExpr
  9928. * | UnionExpr '|' PathExpr
  9929. *
  9930. * Compile an union expression.
  9931. */
  9932. static void
  9933. xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
  9934. xmlXPathCompPathExpr(ctxt);
  9935. CHECK_ERROR;
  9936. SKIP_BLANKS;
  9937. while (CUR == '|') {
  9938. int op1 = ctxt->comp->last;
  9939. PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
  9940. NEXT;
  9941. SKIP_BLANKS;
  9942. xmlXPathCompPathExpr(ctxt);
  9943. PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
  9944. SKIP_BLANKS;
  9945. }
  9946. }
  9947. /**
  9948. * xmlXPathCompUnaryExpr:
  9949. * @ctxt: the XPath Parser context
  9950. *
  9951. * [27] UnaryExpr ::= UnionExpr
  9952. * | '-' UnaryExpr
  9953. *
  9954. * Compile an unary expression.
  9955. */
  9956. static void
  9957. xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
  9958. int minus = 0;
  9959. int found = 0;
  9960. SKIP_BLANKS;
  9961. while (CUR == '-') {
  9962. minus = 1 - minus;
  9963. found = 1;
  9964. NEXT;
  9965. SKIP_BLANKS;
  9966. }
  9967. xmlXPathCompUnionExpr(ctxt);
  9968. CHECK_ERROR;
  9969. if (found) {
  9970. if (minus)
  9971. PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
  9972. else
  9973. PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
  9974. }
  9975. }
  9976. /**
  9977. * xmlXPathCompMultiplicativeExpr:
  9978. * @ctxt: the XPath Parser context
  9979. *
  9980. * [26] MultiplicativeExpr ::= UnaryExpr
  9981. * | MultiplicativeExpr MultiplyOperator UnaryExpr
  9982. * | MultiplicativeExpr 'div' UnaryExpr
  9983. * | MultiplicativeExpr 'mod' UnaryExpr
  9984. * [34] MultiplyOperator ::= '*'
  9985. *
  9986. * Compile an Additive expression.
  9987. */
  9988. static void
  9989. xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
  9990. xmlXPathCompUnaryExpr(ctxt);
  9991. CHECK_ERROR;
  9992. SKIP_BLANKS;
  9993. while ((CUR == '*') ||
  9994. ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
  9995. ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
  9996. int op = -1;
  9997. int op1 = ctxt->comp->last;
  9998. if (CUR == '*') {
  9999. op = 0;
  10000. NEXT;
  10001. } else if (CUR == 'd') {
  10002. op = 1;
  10003. SKIP(3);
  10004. } else if (CUR == 'm') {
  10005. op = 2;
  10006. SKIP(3);
  10007. }
  10008. SKIP_BLANKS;
  10009. xmlXPathCompUnaryExpr(ctxt);
  10010. CHECK_ERROR;
  10011. PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
  10012. SKIP_BLANKS;
  10013. }
  10014. }
  10015. /**
  10016. * xmlXPathCompAdditiveExpr:
  10017. * @ctxt: the XPath Parser context
  10018. *
  10019. * [25] AdditiveExpr ::= MultiplicativeExpr
  10020. * | AdditiveExpr '+' MultiplicativeExpr
  10021. * | AdditiveExpr '-' MultiplicativeExpr
  10022. *
  10023. * Compile an Additive expression.
  10024. */
  10025. static void
  10026. xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
  10027. xmlXPathCompMultiplicativeExpr(ctxt);
  10028. CHECK_ERROR;
  10029. SKIP_BLANKS;
  10030. while ((CUR == '+') || (CUR == '-')) {
  10031. int plus;
  10032. int op1 = ctxt->comp->last;
  10033. if (CUR == '+') plus = 1;
  10034. else plus = 0;
  10035. NEXT;
  10036. SKIP_BLANKS;
  10037. xmlXPathCompMultiplicativeExpr(ctxt);
  10038. CHECK_ERROR;
  10039. PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
  10040. SKIP_BLANKS;
  10041. }
  10042. }
  10043. /**
  10044. * xmlXPathCompRelationalExpr:
  10045. * @ctxt: the XPath Parser context
  10046. *
  10047. * [24] RelationalExpr ::= AdditiveExpr
  10048. * | RelationalExpr '<' AdditiveExpr
  10049. * | RelationalExpr '>' AdditiveExpr
  10050. * | RelationalExpr '<=' AdditiveExpr
  10051. * | RelationalExpr '>=' AdditiveExpr
  10052. *
  10053. * A <= B > C is allowed ? Answer from James, yes with
  10054. * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
  10055. * which is basically what got implemented.
  10056. *
  10057. * Compile a Relational expression, then push the result
  10058. * on the stack
  10059. */
  10060. static void
  10061. xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
  10062. xmlXPathCompAdditiveExpr(ctxt);
  10063. CHECK_ERROR;
  10064. SKIP_BLANKS;
  10065. while ((CUR == '<') || (CUR == '>')) {
  10066. int inf, strict;
  10067. int op1 = ctxt->comp->last;
  10068. if (CUR == '<') inf = 1;
  10069. else inf = 0;
  10070. if (NXT(1) == '=') strict = 0;
  10071. else strict = 1;
  10072. NEXT;
  10073. if (!strict) NEXT;
  10074. SKIP_BLANKS;
  10075. xmlXPathCompAdditiveExpr(ctxt);
  10076. CHECK_ERROR;
  10077. PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
  10078. SKIP_BLANKS;
  10079. }
  10080. }
  10081. /**
  10082. * xmlXPathCompEqualityExpr:
  10083. * @ctxt: the XPath Parser context
  10084. *
  10085. * [23] EqualityExpr ::= RelationalExpr
  10086. * | EqualityExpr '=' RelationalExpr
  10087. * | EqualityExpr '!=' RelationalExpr
  10088. *
  10089. * A != B != C is allowed ? Answer from James, yes with
  10090. * (RelationalExpr = RelationalExpr) = RelationalExpr
  10091. * (RelationalExpr != RelationalExpr) != RelationalExpr
  10092. * which is basically what got implemented.
  10093. *
  10094. * Compile an Equality expression.
  10095. *
  10096. */
  10097. static void
  10098. xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
  10099. xmlXPathCompRelationalExpr(ctxt);
  10100. CHECK_ERROR;
  10101. SKIP_BLANKS;
  10102. while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
  10103. int eq;
  10104. int op1 = ctxt->comp->last;
  10105. if (CUR == '=') eq = 1;
  10106. else eq = 0;
  10107. NEXT;
  10108. if (!eq) NEXT;
  10109. SKIP_BLANKS;
  10110. xmlXPathCompRelationalExpr(ctxt);
  10111. CHECK_ERROR;
  10112. PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
  10113. SKIP_BLANKS;
  10114. }
  10115. }
  10116. /**
  10117. * xmlXPathCompAndExpr:
  10118. * @ctxt: the XPath Parser context
  10119. *
  10120. * [22] AndExpr ::= EqualityExpr
  10121. * | AndExpr 'and' EqualityExpr
  10122. *
  10123. * Compile an AND expression.
  10124. *
  10125. */
  10126. static void
  10127. xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
  10128. xmlXPathCompEqualityExpr(ctxt);
  10129. CHECK_ERROR;
  10130. SKIP_BLANKS;
  10131. while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
  10132. int op1 = ctxt->comp->last;
  10133. SKIP(3);
  10134. SKIP_BLANKS;
  10135. xmlXPathCompEqualityExpr(ctxt);
  10136. CHECK_ERROR;
  10137. PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
  10138. SKIP_BLANKS;
  10139. }
  10140. }
  10141. /**
  10142. * xmlXPathCompileExpr:
  10143. * @ctxt: the XPath Parser context
  10144. *
  10145. * [14] Expr ::= OrExpr
  10146. * [21] OrExpr ::= AndExpr
  10147. * | OrExpr 'or' AndExpr
  10148. *
  10149. * Parse and compile an expression
  10150. */
  10151. static void
  10152. xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
  10153. xmlXPathContextPtr xpctxt = ctxt->context;
  10154. if (xpctxt != NULL) {
  10155. if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
  10156. XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
  10157. /*
  10158. * Parsing a single '(' pushes about 10 functions on the call stack
  10159. * before recursing!
  10160. */
  10161. xpctxt->depth += 10;
  10162. }
  10163. xmlXPathCompAndExpr(ctxt);
  10164. CHECK_ERROR;
  10165. SKIP_BLANKS;
  10166. while ((CUR == 'o') && (NXT(1) == 'r')) {
  10167. int op1 = ctxt->comp->last;
  10168. SKIP(2);
  10169. SKIP_BLANKS;
  10170. xmlXPathCompAndExpr(ctxt);
  10171. CHECK_ERROR;
  10172. PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
  10173. SKIP_BLANKS;
  10174. }
  10175. if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
  10176. /* more ops could be optimized too */
  10177. /*
  10178. * This is the main place to eliminate sorting for
  10179. * operations which don't require a sorted node-set.
  10180. * E.g. count().
  10181. */
  10182. PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
  10183. }
  10184. if (xpctxt != NULL)
  10185. xpctxt->depth -= 10;
  10186. }
  10187. /**
  10188. * xmlXPathCompPredicate:
  10189. * @ctxt: the XPath Parser context
  10190. * @filter: act as a filter
  10191. *
  10192. * [8] Predicate ::= '[' PredicateExpr ']'
  10193. * [9] PredicateExpr ::= Expr
  10194. *
  10195. * Compile a predicate expression
  10196. */
  10197. static void
  10198. xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
  10199. int op1 = ctxt->comp->last;
  10200. SKIP_BLANKS;
  10201. if (CUR != '[') {
  10202. XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
  10203. }
  10204. NEXT;
  10205. SKIP_BLANKS;
  10206. ctxt->comp->last = -1;
  10207. /*
  10208. * This call to xmlXPathCompileExpr() will deactivate sorting
  10209. * of the predicate result.
  10210. * TODO: Sorting is still activated for filters, since I'm not
  10211. * sure if needed. Normally sorting should not be needed, since
  10212. * a filter can only diminish the number of items in a sequence,
  10213. * but won't change its order; so if the initial sequence is sorted,
  10214. * subsequent sorting is not needed.
  10215. */
  10216. if (! filter)
  10217. xmlXPathCompileExpr(ctxt, 0);
  10218. else
  10219. xmlXPathCompileExpr(ctxt, 1);
  10220. CHECK_ERROR;
  10221. if (CUR != ']') {
  10222. XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
  10223. }
  10224. if (filter)
  10225. PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
  10226. else
  10227. PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
  10228. NEXT;
  10229. SKIP_BLANKS;
  10230. }
  10231. /**
  10232. * xmlXPathCompNodeTest:
  10233. * @ctxt: the XPath Parser context
  10234. * @test: pointer to a xmlXPathTestVal
  10235. * @type: pointer to a xmlXPathTypeVal
  10236. * @prefix: placeholder for a possible name prefix
  10237. *
  10238. * [7] NodeTest ::= NameTest
  10239. * | NodeType '(' ')'
  10240. * | 'processing-instruction' '(' Literal ')'
  10241. *
  10242. * [37] NameTest ::= '*'
  10243. * | NCName ':' '*'
  10244. * | QName
  10245. * [38] NodeType ::= 'comment'
  10246. * | 'text'
  10247. * | 'processing-instruction'
  10248. * | 'node'
  10249. *
  10250. * Returns the name found and updates @test, @type and @prefix appropriately
  10251. */
  10252. static xmlChar *
  10253. xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
  10254. xmlXPathTypeVal *type, xmlChar **prefix,
  10255. xmlChar *name) {
  10256. int blanks;
  10257. if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
  10258. STRANGE;
  10259. return(NULL);
  10260. }
  10261. *type = (xmlXPathTypeVal) 0;
  10262. *test = (xmlXPathTestVal) 0;
  10263. *prefix = NULL;
  10264. SKIP_BLANKS;
  10265. if ((name == NULL) && (CUR == '*')) {
  10266. /*
  10267. * All elements
  10268. */
  10269. NEXT;
  10270. *test = NODE_TEST_ALL;
  10271. return(NULL);
  10272. }
  10273. if (name == NULL)
  10274. name = xmlXPathParseNCName(ctxt);
  10275. if (name == NULL) {
  10276. XP_ERRORNULL(XPATH_EXPR_ERROR);
  10277. }
  10278. blanks = IS_BLANK_CH(CUR);
  10279. SKIP_BLANKS;
  10280. if (CUR == '(') {
  10281. NEXT;
  10282. /*
  10283. * NodeType or PI search
  10284. */
  10285. if (xmlStrEqual(name, BAD_CAST "comment"))
  10286. *type = NODE_TYPE_COMMENT;
  10287. else if (xmlStrEqual(name, BAD_CAST "node"))
  10288. *type = NODE_TYPE_NODE;
  10289. else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
  10290. *type = NODE_TYPE_PI;
  10291. else if (xmlStrEqual(name, BAD_CAST "text"))
  10292. *type = NODE_TYPE_TEXT;
  10293. else {
  10294. if (name != NULL)
  10295. xmlFree(name);
  10296. XP_ERRORNULL(XPATH_EXPR_ERROR);
  10297. }
  10298. *test = NODE_TEST_TYPE;
  10299. SKIP_BLANKS;
  10300. if (*type == NODE_TYPE_PI) {
  10301. /*
  10302. * Specific case: search a PI by name.
  10303. */
  10304. if (name != NULL)
  10305. xmlFree(name);
  10306. name = NULL;
  10307. if (CUR != ')') {
  10308. name = xmlXPathParseLiteral(ctxt);
  10309. if (name == NULL) {
  10310. XP_ERRORNULL(XPATH_EXPR_ERROR);
  10311. }
  10312. *test = NODE_TEST_PI;
  10313. SKIP_BLANKS;
  10314. }
  10315. }
  10316. if (CUR != ')') {
  10317. if (name != NULL)
  10318. xmlFree(name);
  10319. XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
  10320. }
  10321. NEXT;
  10322. return(name);
  10323. }
  10324. *test = NODE_TEST_NAME;
  10325. if ((!blanks) && (CUR == ':')) {
  10326. NEXT;
  10327. /*
  10328. * Since currently the parser context don't have a
  10329. * namespace list associated:
  10330. * The namespace name for this prefix can be computed
  10331. * only at evaluation time. The compilation is done
  10332. * outside of any context.
  10333. */
  10334. #if 0
  10335. *prefix = xmlXPathNsLookup(ctxt->context, name);
  10336. if (name != NULL)
  10337. xmlFree(name);
  10338. if (*prefix == NULL) {
  10339. XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
  10340. }
  10341. #else
  10342. *prefix = name;
  10343. #endif
  10344. if (CUR == '*') {
  10345. /*
  10346. * All elements
  10347. */
  10348. NEXT;
  10349. *test = NODE_TEST_ALL;
  10350. return(NULL);
  10351. }
  10352. name = xmlXPathParseNCName(ctxt);
  10353. if (name == NULL) {
  10354. XP_ERRORNULL(XPATH_EXPR_ERROR);
  10355. }
  10356. }
  10357. return(name);
  10358. }
  10359. /**
  10360. * xmlXPathIsAxisName:
  10361. * @name: a preparsed name token
  10362. *
  10363. * [6] AxisName ::= 'ancestor'
  10364. * | 'ancestor-or-self'
  10365. * | 'attribute'
  10366. * | 'child'
  10367. * | 'descendant'
  10368. * | 'descendant-or-self'
  10369. * | 'following'
  10370. * | 'following-sibling'
  10371. * | 'namespace'
  10372. * | 'parent'
  10373. * | 'preceding'
  10374. * | 'preceding-sibling'
  10375. * | 'self'
  10376. *
  10377. * Returns the axis or 0
  10378. */
  10379. static xmlXPathAxisVal
  10380. xmlXPathIsAxisName(const xmlChar *name) {
  10381. xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
  10382. switch (name[0]) {
  10383. case 'a':
  10384. if (xmlStrEqual(name, BAD_CAST "ancestor"))
  10385. ret = AXIS_ANCESTOR;
  10386. if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
  10387. ret = AXIS_ANCESTOR_OR_SELF;
  10388. if (xmlStrEqual(name, BAD_CAST "attribute"))
  10389. ret = AXIS_ATTRIBUTE;
  10390. break;
  10391. case 'c':
  10392. if (xmlStrEqual(name, BAD_CAST "child"))
  10393. ret = AXIS_CHILD;
  10394. break;
  10395. case 'd':
  10396. if (xmlStrEqual(name, BAD_CAST "descendant"))
  10397. ret = AXIS_DESCENDANT;
  10398. if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
  10399. ret = AXIS_DESCENDANT_OR_SELF;
  10400. break;
  10401. case 'f':
  10402. if (xmlStrEqual(name, BAD_CAST "following"))
  10403. ret = AXIS_FOLLOWING;
  10404. if (xmlStrEqual(name, BAD_CAST "following-sibling"))
  10405. ret = AXIS_FOLLOWING_SIBLING;
  10406. break;
  10407. case 'n':
  10408. if (xmlStrEqual(name, BAD_CAST "namespace"))
  10409. ret = AXIS_NAMESPACE;
  10410. break;
  10411. case 'p':
  10412. if (xmlStrEqual(name, BAD_CAST "parent"))
  10413. ret = AXIS_PARENT;
  10414. if (xmlStrEqual(name, BAD_CAST "preceding"))
  10415. ret = AXIS_PRECEDING;
  10416. if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
  10417. ret = AXIS_PRECEDING_SIBLING;
  10418. break;
  10419. case 's':
  10420. if (xmlStrEqual(name, BAD_CAST "self"))
  10421. ret = AXIS_SELF;
  10422. break;
  10423. }
  10424. return(ret);
  10425. }
  10426. /**
  10427. * xmlXPathCompStep:
  10428. * @ctxt: the XPath Parser context
  10429. *
  10430. * [4] Step ::= AxisSpecifier NodeTest Predicate*
  10431. * | AbbreviatedStep
  10432. *
  10433. * [12] AbbreviatedStep ::= '.' | '..'
  10434. *
  10435. * [5] AxisSpecifier ::= AxisName '::'
  10436. * | AbbreviatedAxisSpecifier
  10437. *
  10438. * [13] AbbreviatedAxisSpecifier ::= '@'?
  10439. *
  10440. * Modified for XPtr range support as:
  10441. *
  10442. * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
  10443. * | AbbreviatedStep
  10444. * | 'range-to' '(' Expr ')' Predicate*
  10445. *
  10446. * Compile one step in a Location Path
  10447. * A location step of . is short for self::node(). This is
  10448. * particularly useful in conjunction with //. For example, the
  10449. * location path .//para is short for
  10450. * self::node()/descendant-or-self::node()/child::para
  10451. * and so will select all para descendant elements of the context
  10452. * node.
  10453. * Similarly, a location step of .. is short for parent::node().
  10454. * For example, ../title is short for parent::node()/child::title
  10455. * and so will select the title children of the parent of the context
  10456. * node.
  10457. */
  10458. static void
  10459. xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
  10460. #ifdef LIBXML_XPTR_ENABLED
  10461. int rangeto = 0;
  10462. int op2 = -1;
  10463. #endif
  10464. SKIP_BLANKS;
  10465. if ((CUR == '.') && (NXT(1) == '.')) {
  10466. SKIP(2);
  10467. SKIP_BLANKS;
  10468. PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
  10469. NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
  10470. } else if (CUR == '.') {
  10471. NEXT;
  10472. SKIP_BLANKS;
  10473. } else {
  10474. xmlChar *name = NULL;
  10475. xmlChar *prefix = NULL;
  10476. xmlXPathTestVal test = (xmlXPathTestVal) 0;
  10477. xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
  10478. xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
  10479. int op1;
  10480. /*
  10481. * The modification needed for XPointer change to the production
  10482. */
  10483. #ifdef LIBXML_XPTR_ENABLED
  10484. if (ctxt->xptr) {
  10485. name = xmlXPathParseNCName(ctxt);
  10486. if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
  10487. op2 = ctxt->comp->last;
  10488. xmlFree(name);
  10489. SKIP_BLANKS;
  10490. if (CUR != '(') {
  10491. XP_ERROR(XPATH_EXPR_ERROR);
  10492. }
  10493. NEXT;
  10494. SKIP_BLANKS;
  10495. xmlXPathCompileExpr(ctxt, 1);
  10496. /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
  10497. CHECK_ERROR;
  10498. SKIP_BLANKS;
  10499. if (CUR != ')') {
  10500. XP_ERROR(XPATH_EXPR_ERROR);
  10501. }
  10502. NEXT;
  10503. rangeto = 1;
  10504. goto eval_predicates;
  10505. }
  10506. }
  10507. #endif
  10508. if (CUR == '*') {
  10509. axis = AXIS_CHILD;
  10510. } else {
  10511. if (name == NULL)
  10512. name = xmlXPathParseNCName(ctxt);
  10513. if (name != NULL) {
  10514. axis = xmlXPathIsAxisName(name);
  10515. if (axis != 0) {
  10516. SKIP_BLANKS;
  10517. if ((CUR == ':') && (NXT(1) == ':')) {
  10518. SKIP(2);
  10519. xmlFree(name);
  10520. name = NULL;
  10521. } else {
  10522. /* an element name can conflict with an axis one :-\ */
  10523. axis = AXIS_CHILD;
  10524. }
  10525. } else {
  10526. axis = AXIS_CHILD;
  10527. }
  10528. } else if (CUR == '@') {
  10529. NEXT;
  10530. axis = AXIS_ATTRIBUTE;
  10531. } else {
  10532. axis = AXIS_CHILD;
  10533. }
  10534. }
  10535. if (ctxt->error != XPATH_EXPRESSION_OK) {
  10536. xmlFree(name);
  10537. return;
  10538. }
  10539. name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
  10540. if (test == 0)
  10541. return;
  10542. if ((prefix != NULL) && (ctxt->context != NULL) &&
  10543. (ctxt->context->flags & XML_XPATH_CHECKNS)) {
  10544. if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
  10545. xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
  10546. }
  10547. }
  10548. #ifdef DEBUG_STEP
  10549. xmlGenericError(xmlGenericErrorContext,
  10550. "Basis : computing new set\n");
  10551. #endif
  10552. #ifdef DEBUG_STEP
  10553. xmlGenericError(xmlGenericErrorContext, "Basis : ");
  10554. if (ctxt->value == NULL)
  10555. xmlGenericError(xmlGenericErrorContext, "no value\n");
  10556. else if (ctxt->value->nodesetval == NULL)
  10557. xmlGenericError(xmlGenericErrorContext, "Empty\n");
  10558. else
  10559. xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
  10560. #endif
  10561. #ifdef LIBXML_XPTR_ENABLED
  10562. eval_predicates:
  10563. #endif
  10564. op1 = ctxt->comp->last;
  10565. ctxt->comp->last = -1;
  10566. SKIP_BLANKS;
  10567. while (CUR == '[') {
  10568. xmlXPathCompPredicate(ctxt, 0);
  10569. }
  10570. #ifdef LIBXML_XPTR_ENABLED
  10571. if (rangeto) {
  10572. PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
  10573. } else
  10574. #endif
  10575. if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
  10576. test, type, (void *)prefix, (void *)name) == -1) {
  10577. xmlFree(prefix);
  10578. xmlFree(name);
  10579. }
  10580. }
  10581. #ifdef DEBUG_STEP
  10582. xmlGenericError(xmlGenericErrorContext, "Step : ");
  10583. if (ctxt->value == NULL)
  10584. xmlGenericError(xmlGenericErrorContext, "no value\n");
  10585. else if (ctxt->value->nodesetval == NULL)
  10586. xmlGenericError(xmlGenericErrorContext, "Empty\n");
  10587. else
  10588. xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
  10589. ctxt->value->nodesetval);
  10590. #endif
  10591. }
  10592. /**
  10593. * xmlXPathCompRelativeLocationPath:
  10594. * @ctxt: the XPath Parser context
  10595. *
  10596. * [3] RelativeLocationPath ::= Step
  10597. * | RelativeLocationPath '/' Step
  10598. * | AbbreviatedRelativeLocationPath
  10599. * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
  10600. *
  10601. * Compile a relative location path.
  10602. */
  10603. static void
  10604. xmlXPathCompRelativeLocationPath
  10605. (xmlXPathParserContextPtr ctxt) {
  10606. SKIP_BLANKS;
  10607. if ((CUR == '/') && (NXT(1) == '/')) {
  10608. SKIP(2);
  10609. SKIP_BLANKS;
  10610. PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
  10611. NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
  10612. } else if (CUR == '/') {
  10613. NEXT;
  10614. SKIP_BLANKS;
  10615. }
  10616. xmlXPathCompStep(ctxt);
  10617. CHECK_ERROR;
  10618. SKIP_BLANKS;
  10619. while (CUR == '/') {
  10620. if ((CUR == '/') && (NXT(1) == '/')) {
  10621. SKIP(2);
  10622. SKIP_BLANKS;
  10623. PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
  10624. NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
  10625. xmlXPathCompStep(ctxt);
  10626. } else if (CUR == '/') {
  10627. NEXT;
  10628. SKIP_BLANKS;
  10629. xmlXPathCompStep(ctxt);
  10630. }
  10631. SKIP_BLANKS;
  10632. }
  10633. }
  10634. /**
  10635. * xmlXPathCompLocationPath:
  10636. * @ctxt: the XPath Parser context
  10637. *
  10638. * [1] LocationPath ::= RelativeLocationPath
  10639. * | AbsoluteLocationPath
  10640. * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
  10641. * | AbbreviatedAbsoluteLocationPath
  10642. * [10] AbbreviatedAbsoluteLocationPath ::=
  10643. * '//' RelativeLocationPath
  10644. *
  10645. * Compile a location path
  10646. *
  10647. * // is short for /descendant-or-self::node()/. For example,
  10648. * //para is short for /descendant-or-self::node()/child::para and
  10649. * so will select any para element in the document (even a para element
  10650. * that is a document element will be selected by //para since the
  10651. * document element node is a child of the root node); div//para is
  10652. * short for div/descendant-or-self::node()/child::para and so will
  10653. * select all para descendants of div children.
  10654. */
  10655. static void
  10656. xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
  10657. SKIP_BLANKS;
  10658. if (CUR != '/') {
  10659. xmlXPathCompRelativeLocationPath(ctxt);
  10660. } else {
  10661. while (CUR == '/') {
  10662. if ((CUR == '/') && (NXT(1) == '/')) {
  10663. SKIP(2);
  10664. SKIP_BLANKS;
  10665. PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
  10666. NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
  10667. xmlXPathCompRelativeLocationPath(ctxt);
  10668. } else if (CUR == '/') {
  10669. NEXT;
  10670. SKIP_BLANKS;
  10671. if ((CUR != 0 ) &&
  10672. ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
  10673. (CUR == '@') || (CUR == '*')))
  10674. xmlXPathCompRelativeLocationPath(ctxt);
  10675. }
  10676. CHECK_ERROR;
  10677. }
  10678. }
  10679. }
  10680. /************************************************************************
  10681. * *
  10682. * XPath precompiled expression evaluation *
  10683. * *
  10684. ************************************************************************/
  10685. static int
  10686. xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
  10687. #ifdef DEBUG_STEP
  10688. static void
  10689. xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
  10690. int nbNodes)
  10691. {
  10692. xmlGenericError(xmlGenericErrorContext, "new step : ");
  10693. switch (op->value) {
  10694. case AXIS_ANCESTOR:
  10695. xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
  10696. break;
  10697. case AXIS_ANCESTOR_OR_SELF:
  10698. xmlGenericError(xmlGenericErrorContext,
  10699. "axis 'ancestors-or-self' ");
  10700. break;
  10701. case AXIS_ATTRIBUTE:
  10702. xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
  10703. break;
  10704. case AXIS_CHILD:
  10705. xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
  10706. break;
  10707. case AXIS_DESCENDANT:
  10708. xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
  10709. break;
  10710. case AXIS_DESCENDANT_OR_SELF:
  10711. xmlGenericError(xmlGenericErrorContext,
  10712. "axis 'descendant-or-self' ");
  10713. break;
  10714. case AXIS_FOLLOWING:
  10715. xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
  10716. break;
  10717. case AXIS_FOLLOWING_SIBLING:
  10718. xmlGenericError(xmlGenericErrorContext,
  10719. "axis 'following-siblings' ");
  10720. break;
  10721. case AXIS_NAMESPACE:
  10722. xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
  10723. break;
  10724. case AXIS_PARENT:
  10725. xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
  10726. break;
  10727. case AXIS_PRECEDING:
  10728. xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
  10729. break;
  10730. case AXIS_PRECEDING_SIBLING:
  10731. xmlGenericError(xmlGenericErrorContext,
  10732. "axis 'preceding-sibling' ");
  10733. break;
  10734. case AXIS_SELF:
  10735. xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
  10736. break;
  10737. }
  10738. xmlGenericError(xmlGenericErrorContext,
  10739. " context contains %d nodes\n", nbNodes);
  10740. switch (op->value2) {
  10741. case NODE_TEST_NONE:
  10742. xmlGenericError(xmlGenericErrorContext,
  10743. " searching for none !!!\n");
  10744. break;
  10745. case NODE_TEST_TYPE:
  10746. xmlGenericError(xmlGenericErrorContext,
  10747. " searching for type %d\n", op->value3);
  10748. break;
  10749. case NODE_TEST_PI:
  10750. xmlGenericError(xmlGenericErrorContext,
  10751. " searching for PI !!!\n");
  10752. break;
  10753. case NODE_TEST_ALL:
  10754. xmlGenericError(xmlGenericErrorContext,
  10755. " searching for *\n");
  10756. break;
  10757. case NODE_TEST_NS:
  10758. xmlGenericError(xmlGenericErrorContext,
  10759. " searching for namespace %s\n",
  10760. op->value5);
  10761. break;
  10762. case NODE_TEST_NAME:
  10763. xmlGenericError(xmlGenericErrorContext,
  10764. " searching for name %s\n", op->value5);
  10765. if (op->value4)
  10766. xmlGenericError(xmlGenericErrorContext,
  10767. " with namespace %s\n", op->value4);
  10768. break;
  10769. }
  10770. xmlGenericError(xmlGenericErrorContext, "Testing : ");
  10771. }
  10772. #endif /* DEBUG_STEP */
  10773. /**
  10774. * xmlXPathNodeSetFilter:
  10775. * @ctxt: the XPath Parser context
  10776. * @set: the node set to filter
  10777. * @filterOpIndex: the index of the predicate/filter op
  10778. * @minPos: minimum position in the filtered set (1-based)
  10779. * @maxPos: maximum position in the filtered set (1-based)
  10780. * @hasNsNodes: true if the node set may contain namespace nodes
  10781. *
  10782. * Filter a node set, keeping only nodes for which the predicate expression
  10783. * matches. Afterwards, keep only nodes between minPos and maxPos in the
  10784. * filtered result.
  10785. */
  10786. static void
  10787. xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
  10788. xmlNodeSetPtr set,
  10789. int filterOpIndex,
  10790. int minPos, int maxPos,
  10791. int hasNsNodes)
  10792. {
  10793. xmlXPathContextPtr xpctxt;
  10794. xmlNodePtr oldnode;
  10795. xmlDocPtr olddoc;
  10796. xmlXPathStepOpPtr filterOp;
  10797. int oldcs, oldpp;
  10798. int i, j, pos;
  10799. if ((set == NULL) || (set->nodeNr == 0))
  10800. return;
  10801. /*
  10802. * Check if the node set contains a sufficient number of nodes for
  10803. * the requested range.
  10804. */
  10805. if (set->nodeNr < minPos) {
  10806. xmlXPathNodeSetClear(set, hasNsNodes);
  10807. return;
  10808. }
  10809. xpctxt = ctxt->context;
  10810. oldnode = xpctxt->node;
  10811. olddoc = xpctxt->doc;
  10812. oldcs = xpctxt->contextSize;
  10813. oldpp = xpctxt->proximityPosition;
  10814. filterOp = &ctxt->comp->steps[filterOpIndex];
  10815. xpctxt->contextSize = set->nodeNr;
  10816. for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
  10817. xmlNodePtr node = set->nodeTab[i];
  10818. int res;
  10819. xpctxt->node = node;
  10820. xpctxt->proximityPosition = i + 1;
  10821. /*
  10822. * Also set the xpath document in case things like
  10823. * key() are evaluated in the predicate.
  10824. *
  10825. * TODO: Get real doc for namespace nodes.
  10826. */
  10827. if ((node->type != XML_NAMESPACE_DECL) &&
  10828. (node->doc != NULL))
  10829. xpctxt->doc = node->doc;
  10830. res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
  10831. if (ctxt->error != XPATH_EXPRESSION_OK)
  10832. break;
  10833. if (res < 0) {
  10834. /* Shouldn't happen */
  10835. xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
  10836. break;
  10837. }
  10838. if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
  10839. if (i != j) {
  10840. set->nodeTab[j] = node;
  10841. set->nodeTab[i] = NULL;
  10842. }
  10843. j += 1;
  10844. } else {
  10845. /* Remove the entry from the initial node set. */
  10846. set->nodeTab[i] = NULL;
  10847. if (node->type == XML_NAMESPACE_DECL)
  10848. xmlXPathNodeSetFreeNs((xmlNsPtr) node);
  10849. }
  10850. if (res != 0) {
  10851. if (pos == maxPos) {
  10852. i += 1;
  10853. break;
  10854. }
  10855. pos += 1;
  10856. }
  10857. }
  10858. /* Free remaining nodes. */
  10859. if (hasNsNodes) {
  10860. for (; i < set->nodeNr; i++) {
  10861. xmlNodePtr node = set->nodeTab[i];
  10862. if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
  10863. xmlXPathNodeSetFreeNs((xmlNsPtr) node);
  10864. }
  10865. }
  10866. set->nodeNr = j;
  10867. /* If too many elements were removed, shrink table to preserve memory. */
  10868. if ((set->nodeMax > XML_NODESET_DEFAULT) &&
  10869. (set->nodeNr < set->nodeMax / 2)) {
  10870. xmlNodePtr *tmp;
  10871. int nodeMax = set->nodeNr;
  10872. if (nodeMax < XML_NODESET_DEFAULT)
  10873. nodeMax = XML_NODESET_DEFAULT;
  10874. tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
  10875. nodeMax * sizeof(xmlNodePtr));
  10876. if (tmp == NULL) {
  10877. xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
  10878. } else {
  10879. set->nodeTab = tmp;
  10880. set->nodeMax = nodeMax;
  10881. }
  10882. }
  10883. xpctxt->node = oldnode;
  10884. xpctxt->doc = olddoc;
  10885. xpctxt->contextSize = oldcs;
  10886. xpctxt->proximityPosition = oldpp;
  10887. }
  10888. #ifdef LIBXML_XPTR_ENABLED
  10889. /**
  10890. * xmlXPathLocationSetFilter:
  10891. * @ctxt: the XPath Parser context
  10892. * @locset: the location set to filter
  10893. * @filterOpIndex: the index of the predicate/filter op
  10894. * @minPos: minimum position in the filtered set (1-based)
  10895. * @maxPos: maximum position in the filtered set (1-based)
  10896. *
  10897. * Filter a location set, keeping only nodes for which the predicate
  10898. * expression matches. Afterwards, keep only nodes between minPos and maxPos
  10899. * in the filtered result.
  10900. */
  10901. static void
  10902. xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
  10903. xmlLocationSetPtr locset,
  10904. int filterOpIndex,
  10905. int minPos, int maxPos)
  10906. {
  10907. xmlXPathContextPtr xpctxt;
  10908. xmlNodePtr oldnode;
  10909. xmlDocPtr olddoc;
  10910. xmlXPathStepOpPtr filterOp;
  10911. int oldcs, oldpp;
  10912. int i, j, pos;
  10913. if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
  10914. return;
  10915. xpctxt = ctxt->context;
  10916. oldnode = xpctxt->node;
  10917. olddoc = xpctxt->doc;
  10918. oldcs = xpctxt->contextSize;
  10919. oldpp = xpctxt->proximityPosition;
  10920. filterOp = &ctxt->comp->steps[filterOpIndex];
  10921. xpctxt->contextSize = locset->locNr;
  10922. for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
  10923. xmlNodePtr contextNode = locset->locTab[i]->user;
  10924. int res;
  10925. xpctxt->node = contextNode;
  10926. xpctxt->proximityPosition = i + 1;
  10927. /*
  10928. * Also set the xpath document in case things like
  10929. * key() are evaluated in the predicate.
  10930. *
  10931. * TODO: Get real doc for namespace nodes.
  10932. */
  10933. if ((contextNode->type != XML_NAMESPACE_DECL) &&
  10934. (contextNode->doc != NULL))
  10935. xpctxt->doc = contextNode->doc;
  10936. res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
  10937. if (ctxt->error != XPATH_EXPRESSION_OK)
  10938. break;
  10939. if (res < 0) {
  10940. /* Shouldn't happen */
  10941. xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
  10942. break;
  10943. }
  10944. if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
  10945. if (i != j) {
  10946. locset->locTab[j] = locset->locTab[i];
  10947. locset->locTab[i] = NULL;
  10948. }
  10949. j += 1;
  10950. } else {
  10951. /* Remove the entry from the initial location set. */
  10952. xmlXPathFreeObject(locset->locTab[i]);
  10953. locset->locTab[i] = NULL;
  10954. }
  10955. if (res != 0) {
  10956. if (pos == maxPos) {
  10957. i += 1;
  10958. break;
  10959. }
  10960. pos += 1;
  10961. }
  10962. }
  10963. /* Free remaining nodes. */
  10964. for (; i < locset->locNr; i++)
  10965. xmlXPathFreeObject(locset->locTab[i]);
  10966. locset->locNr = j;
  10967. /* If too many elements were removed, shrink table to preserve memory. */
  10968. if ((locset->locMax > XML_NODESET_DEFAULT) &&
  10969. (locset->locNr < locset->locMax / 2)) {
  10970. xmlXPathObjectPtr *tmp;
  10971. int locMax = locset->locNr;
  10972. if (locMax < XML_NODESET_DEFAULT)
  10973. locMax = XML_NODESET_DEFAULT;
  10974. tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
  10975. locMax * sizeof(xmlXPathObjectPtr));
  10976. if (tmp == NULL) {
  10977. xmlXPathPErrMemory(ctxt, "shrinking locset\n");
  10978. } else {
  10979. locset->locTab = tmp;
  10980. locset->locMax = locMax;
  10981. }
  10982. }
  10983. xpctxt->node = oldnode;
  10984. xpctxt->doc = olddoc;
  10985. xpctxt->contextSize = oldcs;
  10986. xpctxt->proximityPosition = oldpp;
  10987. }
  10988. #endif /* LIBXML_XPTR_ENABLED */
  10989. /**
  10990. * xmlXPathCompOpEvalPredicate:
  10991. * @ctxt: the XPath Parser context
  10992. * @op: the predicate op
  10993. * @set: the node set to filter
  10994. * @minPos: minimum position in the filtered set (1-based)
  10995. * @maxPos: maximum position in the filtered set (1-based)
  10996. * @hasNsNodes: true if the node set may contain namespace nodes
  10997. *
  10998. * Filter a node set, keeping only nodes for which the sequence of predicate
  10999. * expressions matches. Afterwards, keep only nodes between minPos and maxPos
  11000. * in the filtered result.
  11001. */
  11002. static void
  11003. xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
  11004. xmlXPathStepOpPtr op,
  11005. xmlNodeSetPtr set,
  11006. int minPos, int maxPos,
  11007. int hasNsNodes)
  11008. {
  11009. if (op->ch1 != -1) {
  11010. xmlXPathCompExprPtr comp = ctxt->comp;
  11011. /*
  11012. * Process inner predicates first.
  11013. */
  11014. if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
  11015. xmlGenericError(xmlGenericErrorContext,
  11016. "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
  11017. XP_ERROR(XPATH_INVALID_OPERAND);
  11018. }
  11019. if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
  11020. XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
  11021. ctxt->context->depth += 1;
  11022. xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
  11023. 1, set->nodeNr, hasNsNodes);
  11024. ctxt->context->depth -= 1;
  11025. CHECK_ERROR;
  11026. }
  11027. if (op->ch2 != -1)
  11028. xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
  11029. }
  11030. static int
  11031. xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
  11032. xmlXPathStepOpPtr op,
  11033. int *maxPos)
  11034. {
  11035. xmlXPathStepOpPtr exprOp;
  11036. /*
  11037. * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
  11038. */
  11039. /*
  11040. * If not -1, then ch1 will point to:
  11041. * 1) For predicates (XPATH_OP_PREDICATE):
  11042. * - an inner predicate operator
  11043. * 2) For filters (XPATH_OP_FILTER):
  11044. * - an inner filter operator OR
  11045. * - an expression selecting the node set.
  11046. * E.g. "key('a', 'b')" or "(//foo | //bar)".
  11047. */
  11048. if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
  11049. return(0);
  11050. if (op->ch2 != -1) {
  11051. exprOp = &ctxt->comp->steps[op->ch2];
  11052. } else
  11053. return(0);
  11054. if ((exprOp != NULL) &&
  11055. (exprOp->op == XPATH_OP_VALUE) &&
  11056. (exprOp->value4 != NULL) &&
  11057. (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
  11058. {
  11059. double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
  11060. /*
  11061. * We have a "[n]" predicate here.
  11062. * TODO: Unfortunately this simplistic test here is not
  11063. * able to detect a position() predicate in compound
  11064. * expressions like "[@attr = 'a" and position() = 1],
  11065. * and even not the usage of position() in
  11066. * "[position() = 1]"; thus - obviously - a position-range,
  11067. * like it "[position() < 5]", is also not detected.
  11068. * Maybe we could rewrite the AST to ease the optimization.
  11069. */
  11070. if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
  11071. *maxPos = (int) floatval;
  11072. if (floatval == (double) *maxPos)
  11073. return(1);
  11074. }
  11075. }
  11076. return(0);
  11077. }
  11078. static int
  11079. xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
  11080. xmlXPathStepOpPtr op,
  11081. xmlNodePtr * first, xmlNodePtr * last,
  11082. int toBool)
  11083. {
  11084. #define XP_TEST_HIT \
  11085. if (hasAxisRange != 0) { \
  11086. if (++pos == maxPos) { \
  11087. if (addNode(seq, cur) < 0) \
  11088. ctxt->error = XPATH_MEMORY_ERROR; \
  11089. goto axis_range_end; } \
  11090. } else { \
  11091. if (addNode(seq, cur) < 0) \
  11092. ctxt->error = XPATH_MEMORY_ERROR; \
  11093. if (breakOnFirstHit) goto first_hit; }
  11094. #define XP_TEST_HIT_NS \
  11095. if (hasAxisRange != 0) { \
  11096. if (++pos == maxPos) { \
  11097. hasNsNodes = 1; \
  11098. if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
  11099. ctxt->error = XPATH_MEMORY_ERROR; \
  11100. goto axis_range_end; } \
  11101. } else { \
  11102. hasNsNodes = 1; \
  11103. if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
  11104. ctxt->error = XPATH_MEMORY_ERROR; \
  11105. if (breakOnFirstHit) goto first_hit; }
  11106. xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
  11107. xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
  11108. xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
  11109. const xmlChar *prefix = op->value4;
  11110. const xmlChar *name = op->value5;
  11111. const xmlChar *URI = NULL;
  11112. #ifdef DEBUG_STEP
  11113. int nbMatches = 0, prevMatches = 0;
  11114. #endif
  11115. int total = 0, hasNsNodes = 0;
  11116. /* The popped object holding the context nodes */
  11117. xmlXPathObjectPtr obj;
  11118. /* The set of context nodes for the node tests */
  11119. xmlNodeSetPtr contextSeq;
  11120. int contextIdx;
  11121. xmlNodePtr contextNode;
  11122. /* The final resulting node set wrt to all context nodes */
  11123. xmlNodeSetPtr outSeq;
  11124. /*
  11125. * The temporary resulting node set wrt 1 context node.
  11126. * Used to feed predicate evaluation.
  11127. */
  11128. xmlNodeSetPtr seq;
  11129. xmlNodePtr cur;
  11130. /* First predicate operator */
  11131. xmlXPathStepOpPtr predOp;
  11132. int maxPos; /* The requested position() (when a "[n]" predicate) */
  11133. int hasPredicateRange, hasAxisRange, pos;
  11134. int breakOnFirstHit;
  11135. xmlXPathTraversalFunction next = NULL;
  11136. int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
  11137. xmlXPathNodeSetMergeFunction mergeAndClear;
  11138. xmlNodePtr oldContextNode;
  11139. xmlXPathContextPtr xpctxt = ctxt->context;
  11140. CHECK_TYPE0(XPATH_NODESET);
  11141. obj = valuePop(ctxt);
  11142. /*
  11143. * Setup namespaces.
  11144. */
  11145. if (prefix != NULL) {
  11146. URI = xmlXPathNsLookup(xpctxt, prefix);
  11147. if (URI == NULL) {
  11148. xmlXPathReleaseObject(xpctxt, obj);
  11149. XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
  11150. }
  11151. }
  11152. /*
  11153. * Setup axis.
  11154. *
  11155. * MAYBE FUTURE TODO: merging optimizations:
  11156. * - If the nodes to be traversed wrt to the initial nodes and
  11157. * the current axis cannot overlap, then we could avoid searching
  11158. * for duplicates during the merge.
  11159. * But the question is how/when to evaluate if they cannot overlap.
  11160. * Example: if we know that for two initial nodes, the one is
  11161. * not in the ancestor-or-self axis of the other, then we could safely
  11162. * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
  11163. * the descendant-or-self axis.
  11164. */
  11165. mergeAndClear = xmlXPathNodeSetMergeAndClear;
  11166. switch (axis) {
  11167. case AXIS_ANCESTOR:
  11168. first = NULL;
  11169. next = xmlXPathNextAncestor;
  11170. break;
  11171. case AXIS_ANCESTOR_OR_SELF:
  11172. first = NULL;
  11173. next = xmlXPathNextAncestorOrSelf;
  11174. break;
  11175. case AXIS_ATTRIBUTE:
  11176. first = NULL;
  11177. last = NULL;
  11178. next = xmlXPathNextAttribute;
  11179. mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
  11180. break;
  11181. case AXIS_CHILD:
  11182. last = NULL;
  11183. if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
  11184. (type == NODE_TYPE_NODE))
  11185. {
  11186. /*
  11187. * Optimization if an element node type is 'element'.
  11188. */
  11189. next = xmlXPathNextChildElement;
  11190. } else
  11191. next = xmlXPathNextChild;
  11192. mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
  11193. break;
  11194. case AXIS_DESCENDANT:
  11195. last = NULL;
  11196. next = xmlXPathNextDescendant;
  11197. break;
  11198. case AXIS_DESCENDANT_OR_SELF:
  11199. last = NULL;
  11200. next = xmlXPathNextDescendantOrSelf;
  11201. break;
  11202. case AXIS_FOLLOWING:
  11203. last = NULL;
  11204. next = xmlXPathNextFollowing;
  11205. break;
  11206. case AXIS_FOLLOWING_SIBLING:
  11207. last = NULL;
  11208. next = xmlXPathNextFollowingSibling;
  11209. break;
  11210. case AXIS_NAMESPACE:
  11211. first = NULL;
  11212. last = NULL;
  11213. next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
  11214. mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
  11215. break;
  11216. case AXIS_PARENT:
  11217. first = NULL;
  11218. next = xmlXPathNextParent;
  11219. break;
  11220. case AXIS_PRECEDING:
  11221. first = NULL;
  11222. next = xmlXPathNextPrecedingInternal;
  11223. break;
  11224. case AXIS_PRECEDING_SIBLING:
  11225. first = NULL;
  11226. next = xmlXPathNextPrecedingSibling;
  11227. break;
  11228. case AXIS_SELF:
  11229. first = NULL;
  11230. last = NULL;
  11231. next = xmlXPathNextSelf;
  11232. mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
  11233. break;
  11234. }
  11235. #ifdef DEBUG_STEP
  11236. xmlXPathDebugDumpStepAxis(op,
  11237. (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
  11238. #endif
  11239. if (next == NULL) {
  11240. xmlXPathReleaseObject(xpctxt, obj);
  11241. return(0);
  11242. }
  11243. contextSeq = obj->nodesetval;
  11244. if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
  11245. xmlXPathReleaseObject(xpctxt, obj);
  11246. valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
  11247. return(0);
  11248. }
  11249. /*
  11250. * Predicate optimization ---------------------------------------------
  11251. * If this step has a last predicate, which contains a position(),
  11252. * then we'll optimize (although not exactly "position()", but only
  11253. * the short-hand form, i.e., "[n]".
  11254. *
  11255. * Example - expression "/foo[parent::bar][1]":
  11256. *
  11257. * COLLECT 'child' 'name' 'node' foo -- op (we are here)
  11258. * ROOT -- op->ch1
  11259. * PREDICATE -- op->ch2 (predOp)
  11260. * PREDICATE -- predOp->ch1 = [parent::bar]
  11261. * SORT
  11262. * COLLECT 'parent' 'name' 'node' bar
  11263. * NODE
  11264. * ELEM Object is a number : 1 -- predOp->ch2 = [1]
  11265. *
  11266. */
  11267. maxPos = 0;
  11268. predOp = NULL;
  11269. hasPredicateRange = 0;
  11270. hasAxisRange = 0;
  11271. if (op->ch2 != -1) {
  11272. /*
  11273. * There's at least one predicate. 16 == XPATH_OP_PREDICATE
  11274. */
  11275. predOp = &ctxt->comp->steps[op->ch2];
  11276. if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
  11277. if (predOp->ch1 != -1) {
  11278. /*
  11279. * Use the next inner predicate operator.
  11280. */
  11281. predOp = &ctxt->comp->steps[predOp->ch1];
  11282. hasPredicateRange = 1;
  11283. } else {
  11284. /*
  11285. * There's no other predicate than the [n] predicate.
  11286. */
  11287. predOp = NULL;
  11288. hasAxisRange = 1;
  11289. }
  11290. }
  11291. }
  11292. breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
  11293. /*
  11294. * Axis traversal -----------------------------------------------------
  11295. */
  11296. /*
  11297. * 2.3 Node Tests
  11298. * - For the attribute axis, the principal node type is attribute.
  11299. * - For the namespace axis, the principal node type is namespace.
  11300. * - For other axes, the principal node type is element.
  11301. *
  11302. * A node test * is true for any node of the
  11303. * principal node type. For example, child::* will
  11304. * select all element children of the context node
  11305. */
  11306. oldContextNode = xpctxt->node;
  11307. addNode = xmlXPathNodeSetAddUnique;
  11308. outSeq = NULL;
  11309. seq = NULL;
  11310. contextNode = NULL;
  11311. contextIdx = 0;
  11312. while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
  11313. (ctxt->error == XPATH_EXPRESSION_OK)) {
  11314. xpctxt->node = contextSeq->nodeTab[contextIdx++];
  11315. if (seq == NULL) {
  11316. seq = xmlXPathNodeSetCreate(NULL);
  11317. if (seq == NULL) {
  11318. /* TODO: Propagate memory error. */
  11319. total = 0;
  11320. goto error;
  11321. }
  11322. }
  11323. /*
  11324. * Traverse the axis and test the nodes.
  11325. */
  11326. pos = 0;
  11327. cur = NULL;
  11328. hasNsNodes = 0;
  11329. do {
  11330. if (OP_LIMIT_EXCEEDED(ctxt, 1))
  11331. goto error;
  11332. cur = next(ctxt, cur);
  11333. if (cur == NULL)
  11334. break;
  11335. /*
  11336. * QUESTION TODO: What does the "first" and "last" stuff do?
  11337. */
  11338. if ((first != NULL) && (*first != NULL)) {
  11339. if (*first == cur)
  11340. break;
  11341. if (((total % 256) == 0) &&
  11342. #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
  11343. (xmlXPathCmpNodesExt(*first, cur) >= 0))
  11344. #else
  11345. (xmlXPathCmpNodes(*first, cur) >= 0))
  11346. #endif
  11347. {
  11348. break;
  11349. }
  11350. }
  11351. if ((last != NULL) && (*last != NULL)) {
  11352. if (*last == cur)
  11353. break;
  11354. if (((total % 256) == 0) &&
  11355. #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
  11356. (xmlXPathCmpNodesExt(cur, *last) >= 0))
  11357. #else
  11358. (xmlXPathCmpNodes(cur, *last) >= 0))
  11359. #endif
  11360. {
  11361. break;
  11362. }
  11363. }
  11364. total++;
  11365. #ifdef DEBUG_STEP
  11366. xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
  11367. #endif
  11368. switch (test) {
  11369. case NODE_TEST_NONE:
  11370. total = 0;
  11371. STRANGE
  11372. goto error;
  11373. case NODE_TEST_TYPE:
  11374. if (type == NODE_TYPE_NODE) {
  11375. switch (cur->type) {
  11376. case XML_DOCUMENT_NODE:
  11377. case XML_HTML_DOCUMENT_NODE:
  11378. #ifdef LIBXML_DOCB_ENABLED
  11379. case XML_DOCB_DOCUMENT_NODE:
  11380. #endif
  11381. case XML_ELEMENT_NODE:
  11382. case XML_ATTRIBUTE_NODE:
  11383. case XML_PI_NODE:
  11384. case XML_COMMENT_NODE:
  11385. case XML_CDATA_SECTION_NODE:
  11386. case XML_TEXT_NODE:
  11387. XP_TEST_HIT
  11388. break;
  11389. case XML_NAMESPACE_DECL: {
  11390. if (axis == AXIS_NAMESPACE) {
  11391. XP_TEST_HIT_NS
  11392. } else {
  11393. hasNsNodes = 1;
  11394. XP_TEST_HIT
  11395. }
  11396. break;
  11397. }
  11398. default:
  11399. break;
  11400. }
  11401. } else if (cur->type == (xmlElementType) type) {
  11402. if (cur->type == XML_NAMESPACE_DECL)
  11403. XP_TEST_HIT_NS
  11404. else
  11405. XP_TEST_HIT
  11406. } else if ((type == NODE_TYPE_TEXT) &&
  11407. (cur->type == XML_CDATA_SECTION_NODE))
  11408. {
  11409. XP_TEST_HIT
  11410. }
  11411. break;
  11412. case NODE_TEST_PI:
  11413. if ((cur->type == XML_PI_NODE) &&
  11414. ((name == NULL) || xmlStrEqual(name, cur->name)))
  11415. {
  11416. XP_TEST_HIT
  11417. }
  11418. break;
  11419. case NODE_TEST_ALL:
  11420. if (axis == AXIS_ATTRIBUTE) {
  11421. if (cur->type == XML_ATTRIBUTE_NODE)
  11422. {
  11423. if (prefix == NULL)
  11424. {
  11425. XP_TEST_HIT
  11426. } else if ((cur->ns != NULL) &&
  11427. (xmlStrEqual(URI, cur->ns->href)))
  11428. {
  11429. XP_TEST_HIT
  11430. }
  11431. }
  11432. } else if (axis == AXIS_NAMESPACE) {
  11433. if (cur->type == XML_NAMESPACE_DECL)
  11434. {
  11435. XP_TEST_HIT_NS
  11436. }
  11437. } else {
  11438. if (cur->type == XML_ELEMENT_NODE) {
  11439. if (prefix == NULL)
  11440. {
  11441. XP_TEST_HIT
  11442. } else if ((cur->ns != NULL) &&
  11443. (xmlStrEqual(URI, cur->ns->href)))
  11444. {
  11445. XP_TEST_HIT
  11446. }
  11447. }
  11448. }
  11449. break;
  11450. case NODE_TEST_NS:{
  11451. TODO;
  11452. break;
  11453. }
  11454. case NODE_TEST_NAME:
  11455. if (axis == AXIS_ATTRIBUTE) {
  11456. if (cur->type != XML_ATTRIBUTE_NODE)
  11457. break;
  11458. } else if (axis == AXIS_NAMESPACE) {
  11459. if (cur->type != XML_NAMESPACE_DECL)
  11460. break;
  11461. } else {
  11462. if (cur->type != XML_ELEMENT_NODE)
  11463. break;
  11464. }
  11465. switch (cur->type) {
  11466. case XML_ELEMENT_NODE:
  11467. if (xmlStrEqual(name, cur->name)) {
  11468. if (prefix == NULL) {
  11469. if (cur->ns == NULL)
  11470. {
  11471. XP_TEST_HIT
  11472. }
  11473. } else {
  11474. if ((cur->ns != NULL) &&
  11475. (xmlStrEqual(URI, cur->ns->href)))
  11476. {
  11477. XP_TEST_HIT
  11478. }
  11479. }
  11480. }
  11481. break;
  11482. case XML_ATTRIBUTE_NODE:{
  11483. xmlAttrPtr attr = (xmlAttrPtr) cur;
  11484. if (xmlStrEqual(name, attr->name)) {
  11485. if (prefix == NULL) {
  11486. if ((attr->ns == NULL) ||
  11487. (attr->ns->prefix == NULL))
  11488. {
  11489. XP_TEST_HIT
  11490. }
  11491. } else {
  11492. if ((attr->ns != NULL) &&
  11493. (xmlStrEqual(URI,
  11494. attr->ns->href)))
  11495. {
  11496. XP_TEST_HIT
  11497. }
  11498. }
  11499. }
  11500. break;
  11501. }
  11502. case XML_NAMESPACE_DECL:
  11503. if (cur->type == XML_NAMESPACE_DECL) {
  11504. xmlNsPtr ns = (xmlNsPtr) cur;
  11505. if ((ns->prefix != NULL) && (name != NULL)
  11506. && (xmlStrEqual(ns->prefix, name)))
  11507. {
  11508. XP_TEST_HIT_NS
  11509. }
  11510. }
  11511. break;
  11512. default:
  11513. break;
  11514. }
  11515. break;
  11516. } /* switch(test) */
  11517. } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
  11518. goto apply_predicates;
  11519. axis_range_end: /* ----------------------------------------------------- */
  11520. /*
  11521. * We have a "/foo[n]", and position() = n was reached.
  11522. * Note that we can have as well "/foo/::parent::foo[1]", so
  11523. * a duplicate-aware merge is still needed.
  11524. * Merge with the result.
  11525. */
  11526. if (outSeq == NULL) {
  11527. outSeq = seq;
  11528. seq = NULL;
  11529. } else
  11530. /* TODO: Check memory error. */
  11531. outSeq = mergeAndClear(outSeq, seq);
  11532. /*
  11533. * Break if only a true/false result was requested.
  11534. */
  11535. if (toBool)
  11536. break;
  11537. continue;
  11538. first_hit: /* ---------------------------------------------------------- */
  11539. /*
  11540. * Break if only a true/false result was requested and
  11541. * no predicates existed and a node test succeeded.
  11542. */
  11543. if (outSeq == NULL) {
  11544. outSeq = seq;
  11545. seq = NULL;
  11546. } else
  11547. /* TODO: Check memory error. */
  11548. outSeq = mergeAndClear(outSeq, seq);
  11549. break;
  11550. #ifdef DEBUG_STEP
  11551. if (seq != NULL)
  11552. nbMatches += seq->nodeNr;
  11553. #endif
  11554. apply_predicates: /* --------------------------------------------------- */
  11555. if (ctxt->error != XPATH_EXPRESSION_OK)
  11556. goto error;
  11557. /*
  11558. * Apply predicates.
  11559. */
  11560. if ((predOp != NULL) && (seq->nodeNr > 0)) {
  11561. /*
  11562. * E.g. when we have a "/foo[some expression][n]".
  11563. */
  11564. /*
  11565. * QUESTION TODO: The old predicate evaluation took into
  11566. * account location-sets.
  11567. * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
  11568. * Do we expect such a set here?
  11569. * All what I learned now from the evaluation semantics
  11570. * does not indicate that a location-set will be processed
  11571. * here, so this looks OK.
  11572. */
  11573. /*
  11574. * Iterate over all predicates, starting with the outermost
  11575. * predicate.
  11576. * TODO: Problem: we cannot execute the inner predicates first
  11577. * since we cannot go back *up* the operator tree!
  11578. * Options we have:
  11579. * 1) Use of recursive functions (like is it currently done
  11580. * via xmlXPathCompOpEval())
  11581. * 2) Add a predicate evaluation information stack to the
  11582. * context struct
  11583. * 3) Change the way the operators are linked; we need a
  11584. * "parent" field on xmlXPathStepOp
  11585. *
  11586. * For the moment, I'll try to solve this with a recursive
  11587. * function: xmlXPathCompOpEvalPredicate().
  11588. */
  11589. if (hasPredicateRange != 0)
  11590. xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
  11591. hasNsNodes);
  11592. else
  11593. xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
  11594. hasNsNodes);
  11595. if (ctxt->error != XPATH_EXPRESSION_OK) {
  11596. total = 0;
  11597. goto error;
  11598. }
  11599. }
  11600. if (seq->nodeNr > 0) {
  11601. /*
  11602. * Add to result set.
  11603. */
  11604. if (outSeq == NULL) {
  11605. outSeq = seq;
  11606. seq = NULL;
  11607. } else {
  11608. /* TODO: Check memory error. */
  11609. outSeq = mergeAndClear(outSeq, seq);
  11610. }
  11611. if (toBool)
  11612. break;
  11613. }
  11614. }
  11615. error:
  11616. if ((obj->boolval) && (obj->user != NULL)) {
  11617. /*
  11618. * QUESTION TODO: What does this do and why?
  11619. * TODO: Do we have to do this also for the "error"
  11620. * cleanup further down?
  11621. */
  11622. ctxt->value->boolval = 1;
  11623. ctxt->value->user = obj->user;
  11624. obj->user = NULL;
  11625. obj->boolval = 0;
  11626. }
  11627. xmlXPathReleaseObject(xpctxt, obj);
  11628. /*
  11629. * Ensure we return at least an empty set.
  11630. */
  11631. if (outSeq == NULL) {
  11632. if ((seq != NULL) && (seq->nodeNr == 0))
  11633. outSeq = seq;
  11634. else
  11635. /* TODO: Check memory error. */
  11636. outSeq = xmlXPathNodeSetCreate(NULL);
  11637. }
  11638. if ((seq != NULL) && (seq != outSeq)) {
  11639. xmlXPathFreeNodeSet(seq);
  11640. }
  11641. /*
  11642. * Hand over the result. Better to push the set also in
  11643. * case of errors.
  11644. */
  11645. valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
  11646. /*
  11647. * Reset the context node.
  11648. */
  11649. xpctxt->node = oldContextNode;
  11650. /*
  11651. * When traversing the namespace axis in "toBool" mode, it's
  11652. * possible that tmpNsList wasn't freed.
  11653. */
  11654. if (xpctxt->tmpNsList != NULL) {
  11655. xmlFree(xpctxt->tmpNsList);
  11656. xpctxt->tmpNsList = NULL;
  11657. }
  11658. #ifdef DEBUG_STEP
  11659. xmlGenericError(xmlGenericErrorContext,
  11660. "\nExamined %d nodes, found %d nodes at that step\n",
  11661. total, nbMatches);
  11662. #endif
  11663. return(total);
  11664. }
  11665. static int
  11666. xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
  11667. xmlXPathStepOpPtr op, xmlNodePtr * first);
  11668. /**
  11669. * xmlXPathCompOpEvalFirst:
  11670. * @ctxt: the XPath parser context with the compiled expression
  11671. * @op: an XPath compiled operation
  11672. * @first: the first elem found so far
  11673. *
  11674. * Evaluate the Precompiled XPath operation searching only the first
  11675. * element in document order
  11676. *
  11677. * Returns the number of examined objects.
  11678. */
  11679. static int
  11680. xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
  11681. xmlXPathStepOpPtr op, xmlNodePtr * first)
  11682. {
  11683. int total = 0, cur;
  11684. xmlXPathCompExprPtr comp;
  11685. xmlXPathObjectPtr arg1, arg2;
  11686. CHECK_ERROR0;
  11687. if (OP_LIMIT_EXCEEDED(ctxt, 1))
  11688. return(0);
  11689. if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
  11690. XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
  11691. ctxt->context->depth += 1;
  11692. comp = ctxt->comp;
  11693. switch (op->op) {
  11694. case XPATH_OP_END:
  11695. break;
  11696. case XPATH_OP_UNION:
  11697. total =
  11698. xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
  11699. first);
  11700. CHECK_ERROR0;
  11701. if ((ctxt->value != NULL)
  11702. && (ctxt->value->type == XPATH_NODESET)
  11703. && (ctxt->value->nodesetval != NULL)
  11704. && (ctxt->value->nodesetval->nodeNr >= 1)) {
  11705. /*
  11706. * limit tree traversing to first node in the result
  11707. */
  11708. /*
  11709. * OPTIMIZE TODO: This implicitly sorts
  11710. * the result, even if not needed. E.g. if the argument
  11711. * of the count() function, no sorting is needed.
  11712. * OPTIMIZE TODO: How do we know if the node-list wasn't
  11713. * already sorted?
  11714. */
  11715. if (ctxt->value->nodesetval->nodeNr > 1)
  11716. xmlXPathNodeSetSort(ctxt->value->nodesetval);
  11717. *first = ctxt->value->nodesetval->nodeTab[0];
  11718. }
  11719. cur =
  11720. xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
  11721. first);
  11722. CHECK_ERROR0;
  11723. arg2 = valuePop(ctxt);
  11724. arg1 = valuePop(ctxt);
  11725. if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
  11726. (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
  11727. xmlXPathReleaseObject(ctxt->context, arg1);
  11728. xmlXPathReleaseObject(ctxt->context, arg2);
  11729. XP_ERROR0(XPATH_INVALID_TYPE);
  11730. }
  11731. if ((ctxt->context->opLimit != 0) &&
  11732. (((arg1->nodesetval != NULL) &&
  11733. (xmlXPathCheckOpLimit(ctxt,
  11734. arg1->nodesetval->nodeNr) < 0)) ||
  11735. ((arg2->nodesetval != NULL) &&
  11736. (xmlXPathCheckOpLimit(ctxt,
  11737. arg2->nodesetval->nodeNr) < 0)))) {
  11738. xmlXPathReleaseObject(ctxt->context, arg1);
  11739. xmlXPathReleaseObject(ctxt->context, arg2);
  11740. break;
  11741. }
  11742. /* TODO: Check memory error. */
  11743. arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
  11744. arg2->nodesetval);
  11745. valuePush(ctxt, arg1);
  11746. xmlXPathReleaseObject(ctxt->context, arg2);
  11747. /* optimizer */
  11748. if (total > cur)
  11749. xmlXPathCompSwap(op);
  11750. total += cur;
  11751. break;
  11752. case XPATH_OP_ROOT:
  11753. xmlXPathRoot(ctxt);
  11754. break;
  11755. case XPATH_OP_NODE:
  11756. if (op->ch1 != -1)
  11757. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11758. CHECK_ERROR0;
  11759. if (op->ch2 != -1)
  11760. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  11761. CHECK_ERROR0;
  11762. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  11763. ctxt->context->node));
  11764. break;
  11765. case XPATH_OP_COLLECT:{
  11766. if (op->ch1 == -1)
  11767. break;
  11768. total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11769. CHECK_ERROR0;
  11770. total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
  11771. break;
  11772. }
  11773. case XPATH_OP_VALUE:
  11774. valuePush(ctxt,
  11775. xmlXPathCacheObjectCopy(ctxt->context,
  11776. (xmlXPathObjectPtr) op->value4));
  11777. break;
  11778. case XPATH_OP_SORT:
  11779. if (op->ch1 != -1)
  11780. total +=
  11781. xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
  11782. first);
  11783. CHECK_ERROR0;
  11784. if ((ctxt->value != NULL)
  11785. && (ctxt->value->type == XPATH_NODESET)
  11786. && (ctxt->value->nodesetval != NULL)
  11787. && (ctxt->value->nodesetval->nodeNr > 1))
  11788. xmlXPathNodeSetSort(ctxt->value->nodesetval);
  11789. break;
  11790. #ifdef XP_OPTIMIZED_FILTER_FIRST
  11791. case XPATH_OP_FILTER:
  11792. total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
  11793. break;
  11794. #endif
  11795. default:
  11796. total += xmlXPathCompOpEval(ctxt, op);
  11797. break;
  11798. }
  11799. ctxt->context->depth -= 1;
  11800. return(total);
  11801. }
  11802. /**
  11803. * xmlXPathCompOpEvalLast:
  11804. * @ctxt: the XPath parser context with the compiled expression
  11805. * @op: an XPath compiled operation
  11806. * @last: the last elem found so far
  11807. *
  11808. * Evaluate the Precompiled XPath operation searching only the last
  11809. * element in document order
  11810. *
  11811. * Returns the number of nodes traversed
  11812. */
  11813. static int
  11814. xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
  11815. xmlNodePtr * last)
  11816. {
  11817. int total = 0, cur;
  11818. xmlXPathCompExprPtr comp;
  11819. xmlXPathObjectPtr arg1, arg2;
  11820. CHECK_ERROR0;
  11821. if (OP_LIMIT_EXCEEDED(ctxt, 1))
  11822. return(0);
  11823. if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
  11824. XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
  11825. ctxt->context->depth += 1;
  11826. comp = ctxt->comp;
  11827. switch (op->op) {
  11828. case XPATH_OP_END:
  11829. break;
  11830. case XPATH_OP_UNION:
  11831. total =
  11832. xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
  11833. CHECK_ERROR0;
  11834. if ((ctxt->value != NULL)
  11835. && (ctxt->value->type == XPATH_NODESET)
  11836. && (ctxt->value->nodesetval != NULL)
  11837. && (ctxt->value->nodesetval->nodeNr >= 1)) {
  11838. /*
  11839. * limit tree traversing to first node in the result
  11840. */
  11841. if (ctxt->value->nodesetval->nodeNr > 1)
  11842. xmlXPathNodeSetSort(ctxt->value->nodesetval);
  11843. *last =
  11844. ctxt->value->nodesetval->nodeTab[ctxt->value->
  11845. nodesetval->nodeNr -
  11846. 1];
  11847. }
  11848. cur =
  11849. xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
  11850. CHECK_ERROR0;
  11851. if ((ctxt->value != NULL)
  11852. && (ctxt->value->type == XPATH_NODESET)
  11853. && (ctxt->value->nodesetval != NULL)
  11854. && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
  11855. }
  11856. arg2 = valuePop(ctxt);
  11857. arg1 = valuePop(ctxt);
  11858. if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
  11859. (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
  11860. xmlXPathReleaseObject(ctxt->context, arg1);
  11861. xmlXPathReleaseObject(ctxt->context, arg2);
  11862. XP_ERROR0(XPATH_INVALID_TYPE);
  11863. }
  11864. if ((ctxt->context->opLimit != 0) &&
  11865. (((arg1->nodesetval != NULL) &&
  11866. (xmlXPathCheckOpLimit(ctxt,
  11867. arg1->nodesetval->nodeNr) < 0)) ||
  11868. ((arg2->nodesetval != NULL) &&
  11869. (xmlXPathCheckOpLimit(ctxt,
  11870. arg2->nodesetval->nodeNr) < 0)))) {
  11871. xmlXPathReleaseObject(ctxt->context, arg1);
  11872. xmlXPathReleaseObject(ctxt->context, arg2);
  11873. break;
  11874. }
  11875. /* TODO: Check memory error. */
  11876. arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
  11877. arg2->nodesetval);
  11878. valuePush(ctxt, arg1);
  11879. xmlXPathReleaseObject(ctxt->context, arg2);
  11880. /* optimizer */
  11881. if (total > cur)
  11882. xmlXPathCompSwap(op);
  11883. total += cur;
  11884. break;
  11885. case XPATH_OP_ROOT:
  11886. xmlXPathRoot(ctxt);
  11887. break;
  11888. case XPATH_OP_NODE:
  11889. if (op->ch1 != -1)
  11890. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11891. CHECK_ERROR0;
  11892. if (op->ch2 != -1)
  11893. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  11894. CHECK_ERROR0;
  11895. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  11896. ctxt->context->node));
  11897. break;
  11898. case XPATH_OP_COLLECT:{
  11899. if (op->ch1 == -1)
  11900. break;
  11901. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11902. CHECK_ERROR0;
  11903. total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
  11904. break;
  11905. }
  11906. case XPATH_OP_VALUE:
  11907. valuePush(ctxt,
  11908. xmlXPathCacheObjectCopy(ctxt->context,
  11909. (xmlXPathObjectPtr) op->value4));
  11910. break;
  11911. case XPATH_OP_SORT:
  11912. if (op->ch1 != -1)
  11913. total +=
  11914. xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
  11915. last);
  11916. CHECK_ERROR0;
  11917. if ((ctxt->value != NULL)
  11918. && (ctxt->value->type == XPATH_NODESET)
  11919. && (ctxt->value->nodesetval != NULL)
  11920. && (ctxt->value->nodesetval->nodeNr > 1))
  11921. xmlXPathNodeSetSort(ctxt->value->nodesetval);
  11922. break;
  11923. default:
  11924. total += xmlXPathCompOpEval(ctxt, op);
  11925. break;
  11926. }
  11927. ctxt->context->depth -= 1;
  11928. return (total);
  11929. }
  11930. #ifdef XP_OPTIMIZED_FILTER_FIRST
  11931. static int
  11932. xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
  11933. xmlXPathStepOpPtr op, xmlNodePtr * first)
  11934. {
  11935. int total = 0;
  11936. xmlXPathCompExprPtr comp;
  11937. xmlNodeSetPtr set;
  11938. CHECK_ERROR0;
  11939. comp = ctxt->comp;
  11940. /*
  11941. * Optimization for ()[last()] selection i.e. the last elem
  11942. */
  11943. if ((op->ch1 != -1) && (op->ch2 != -1) &&
  11944. (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
  11945. (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
  11946. int f = comp->steps[op->ch2].ch1;
  11947. if ((f != -1) &&
  11948. (comp->steps[f].op == XPATH_OP_FUNCTION) &&
  11949. (comp->steps[f].value5 == NULL) &&
  11950. (comp->steps[f].value == 0) &&
  11951. (comp->steps[f].value4 != NULL) &&
  11952. (xmlStrEqual
  11953. (comp->steps[f].value4, BAD_CAST "last"))) {
  11954. xmlNodePtr last = NULL;
  11955. total +=
  11956. xmlXPathCompOpEvalLast(ctxt,
  11957. &comp->steps[op->ch1],
  11958. &last);
  11959. CHECK_ERROR0;
  11960. /*
  11961. * The nodeset should be in document order,
  11962. * Keep only the last value
  11963. */
  11964. if ((ctxt->value != NULL) &&
  11965. (ctxt->value->type == XPATH_NODESET) &&
  11966. (ctxt->value->nodesetval != NULL) &&
  11967. (ctxt->value->nodesetval->nodeTab != NULL) &&
  11968. (ctxt->value->nodesetval->nodeNr > 1)) {
  11969. xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
  11970. *first = *(ctxt->value->nodesetval->nodeTab);
  11971. }
  11972. return (total);
  11973. }
  11974. }
  11975. if (op->ch1 != -1)
  11976. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11977. CHECK_ERROR0;
  11978. if (op->ch2 == -1)
  11979. return (total);
  11980. if (ctxt->value == NULL)
  11981. return (total);
  11982. #ifdef LIBXML_XPTR_ENABLED
  11983. /*
  11984. * Hum are we filtering the result of an XPointer expression
  11985. */
  11986. if (ctxt->value->type == XPATH_LOCATIONSET) {
  11987. xmlLocationSetPtr locset = ctxt->value->user;
  11988. if (locset != NULL) {
  11989. xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
  11990. if (locset->locNr > 0)
  11991. *first = (xmlNodePtr) locset->locTab[0]->user;
  11992. }
  11993. return (total);
  11994. }
  11995. #endif /* LIBXML_XPTR_ENABLED */
  11996. CHECK_TYPE0(XPATH_NODESET);
  11997. set = ctxt->value->nodesetval;
  11998. if (set != NULL) {
  11999. xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
  12000. if (set->nodeNr > 0)
  12001. *first = set->nodeTab[0];
  12002. }
  12003. return (total);
  12004. }
  12005. #endif /* XP_OPTIMIZED_FILTER_FIRST */
  12006. /**
  12007. * xmlXPathCompOpEval:
  12008. * @ctxt: the XPath parser context with the compiled expression
  12009. * @op: an XPath compiled operation
  12010. *
  12011. * Evaluate the Precompiled XPath operation
  12012. * Returns the number of nodes traversed
  12013. */
  12014. static int
  12015. xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
  12016. {
  12017. int total = 0;
  12018. int equal, ret;
  12019. xmlXPathCompExprPtr comp;
  12020. xmlXPathObjectPtr arg1, arg2;
  12021. CHECK_ERROR0;
  12022. if (OP_LIMIT_EXCEEDED(ctxt, 1))
  12023. return(0);
  12024. if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
  12025. XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
  12026. ctxt->context->depth += 1;
  12027. comp = ctxt->comp;
  12028. switch (op->op) {
  12029. case XPATH_OP_END:
  12030. break;
  12031. case XPATH_OP_AND:
  12032. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12033. CHECK_ERROR0;
  12034. xmlXPathBooleanFunction(ctxt, 1);
  12035. if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
  12036. break;
  12037. arg2 = valuePop(ctxt);
  12038. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12039. if (ctxt->error) {
  12040. xmlXPathFreeObject(arg2);
  12041. break;
  12042. }
  12043. xmlXPathBooleanFunction(ctxt, 1);
  12044. if (ctxt->value != NULL)
  12045. ctxt->value->boolval &= arg2->boolval;
  12046. xmlXPathReleaseObject(ctxt->context, arg2);
  12047. break;
  12048. case XPATH_OP_OR:
  12049. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12050. CHECK_ERROR0;
  12051. xmlXPathBooleanFunction(ctxt, 1);
  12052. if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
  12053. break;
  12054. arg2 = valuePop(ctxt);
  12055. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12056. if (ctxt->error) {
  12057. xmlXPathFreeObject(arg2);
  12058. break;
  12059. }
  12060. xmlXPathBooleanFunction(ctxt, 1);
  12061. if (ctxt->value != NULL)
  12062. ctxt->value->boolval |= arg2->boolval;
  12063. xmlXPathReleaseObject(ctxt->context, arg2);
  12064. break;
  12065. case XPATH_OP_EQUAL:
  12066. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12067. CHECK_ERROR0;
  12068. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12069. CHECK_ERROR0;
  12070. if (op->value)
  12071. equal = xmlXPathEqualValues(ctxt);
  12072. else
  12073. equal = xmlXPathNotEqualValues(ctxt);
  12074. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
  12075. break;
  12076. case XPATH_OP_CMP:
  12077. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12078. CHECK_ERROR0;
  12079. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12080. CHECK_ERROR0;
  12081. ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
  12082. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
  12083. break;
  12084. case XPATH_OP_PLUS:
  12085. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12086. CHECK_ERROR0;
  12087. if (op->ch2 != -1) {
  12088. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12089. }
  12090. CHECK_ERROR0;
  12091. if (op->value == 0)
  12092. xmlXPathSubValues(ctxt);
  12093. else if (op->value == 1)
  12094. xmlXPathAddValues(ctxt);
  12095. else if (op->value == 2)
  12096. xmlXPathValueFlipSign(ctxt);
  12097. else if (op->value == 3) {
  12098. CAST_TO_NUMBER;
  12099. CHECK_TYPE0(XPATH_NUMBER);
  12100. }
  12101. break;
  12102. case XPATH_OP_MULT:
  12103. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12104. CHECK_ERROR0;
  12105. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12106. CHECK_ERROR0;
  12107. if (op->value == 0)
  12108. xmlXPathMultValues(ctxt);
  12109. else if (op->value == 1)
  12110. xmlXPathDivValues(ctxt);
  12111. else if (op->value == 2)
  12112. xmlXPathModValues(ctxt);
  12113. break;
  12114. case XPATH_OP_UNION:
  12115. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12116. CHECK_ERROR0;
  12117. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12118. CHECK_ERROR0;
  12119. arg2 = valuePop(ctxt);
  12120. arg1 = valuePop(ctxt);
  12121. if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
  12122. (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
  12123. xmlXPathReleaseObject(ctxt->context, arg1);
  12124. xmlXPathReleaseObject(ctxt->context, arg2);
  12125. XP_ERROR0(XPATH_INVALID_TYPE);
  12126. }
  12127. if ((ctxt->context->opLimit != 0) &&
  12128. (((arg1->nodesetval != NULL) &&
  12129. (xmlXPathCheckOpLimit(ctxt,
  12130. arg1->nodesetval->nodeNr) < 0)) ||
  12131. ((arg2->nodesetval != NULL) &&
  12132. (xmlXPathCheckOpLimit(ctxt,
  12133. arg2->nodesetval->nodeNr) < 0)))) {
  12134. xmlXPathReleaseObject(ctxt->context, arg1);
  12135. xmlXPathReleaseObject(ctxt->context, arg2);
  12136. break;
  12137. }
  12138. if ((arg1->nodesetval == NULL) ||
  12139. ((arg2->nodesetval != NULL) &&
  12140. (arg2->nodesetval->nodeNr != 0)))
  12141. {
  12142. /* TODO: Check memory error. */
  12143. arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
  12144. arg2->nodesetval);
  12145. }
  12146. valuePush(ctxt, arg1);
  12147. xmlXPathReleaseObject(ctxt->context, arg2);
  12148. break;
  12149. case XPATH_OP_ROOT:
  12150. xmlXPathRoot(ctxt);
  12151. break;
  12152. case XPATH_OP_NODE:
  12153. if (op->ch1 != -1)
  12154. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12155. CHECK_ERROR0;
  12156. if (op->ch2 != -1)
  12157. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12158. CHECK_ERROR0;
  12159. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  12160. ctxt->context->node));
  12161. break;
  12162. case XPATH_OP_COLLECT:{
  12163. if (op->ch1 == -1)
  12164. break;
  12165. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12166. CHECK_ERROR0;
  12167. total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
  12168. break;
  12169. }
  12170. case XPATH_OP_VALUE:
  12171. valuePush(ctxt,
  12172. xmlXPathCacheObjectCopy(ctxt->context,
  12173. (xmlXPathObjectPtr) op->value4));
  12174. break;
  12175. case XPATH_OP_VARIABLE:{
  12176. xmlXPathObjectPtr val;
  12177. if (op->ch1 != -1)
  12178. total +=
  12179. xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12180. if (op->value5 == NULL) {
  12181. val = xmlXPathVariableLookup(ctxt->context, op->value4);
  12182. if (val == NULL)
  12183. XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
  12184. valuePush(ctxt, val);
  12185. } else {
  12186. const xmlChar *URI;
  12187. URI = xmlXPathNsLookup(ctxt->context, op->value5);
  12188. if (URI == NULL) {
  12189. xmlGenericError(xmlGenericErrorContext,
  12190. "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
  12191. (char *) op->value4, (char *)op->value5);
  12192. ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
  12193. break;
  12194. }
  12195. val = xmlXPathVariableLookupNS(ctxt->context,
  12196. op->value4, URI);
  12197. if (val == NULL)
  12198. XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
  12199. valuePush(ctxt, val);
  12200. }
  12201. break;
  12202. }
  12203. case XPATH_OP_FUNCTION:{
  12204. xmlXPathFunction func;
  12205. const xmlChar *oldFunc, *oldFuncURI;
  12206. int i;
  12207. int frame;
  12208. frame = xmlXPathSetFrame(ctxt);
  12209. if (op->ch1 != -1) {
  12210. total +=
  12211. xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12212. if (ctxt->error != XPATH_EXPRESSION_OK) {
  12213. xmlXPathPopFrame(ctxt, frame);
  12214. break;
  12215. }
  12216. }
  12217. if (ctxt->valueNr < ctxt->valueFrame + op->value) {
  12218. xmlGenericError(xmlGenericErrorContext,
  12219. "xmlXPathCompOpEval: parameter error\n");
  12220. ctxt->error = XPATH_INVALID_OPERAND;
  12221. xmlXPathPopFrame(ctxt, frame);
  12222. break;
  12223. }
  12224. for (i = 0; i < op->value; i++) {
  12225. if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
  12226. xmlGenericError(xmlGenericErrorContext,
  12227. "xmlXPathCompOpEval: parameter error\n");
  12228. ctxt->error = XPATH_INVALID_OPERAND;
  12229. xmlXPathPopFrame(ctxt, frame);
  12230. break;
  12231. }
  12232. }
  12233. if (op->cache != NULL)
  12234. func = op->cache;
  12235. else {
  12236. const xmlChar *URI = NULL;
  12237. if (op->value5 == NULL)
  12238. func =
  12239. xmlXPathFunctionLookup(ctxt->context,
  12240. op->value4);
  12241. else {
  12242. URI = xmlXPathNsLookup(ctxt->context, op->value5);
  12243. if (URI == NULL) {
  12244. xmlGenericError(xmlGenericErrorContext,
  12245. "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
  12246. (char *)op->value4, (char *)op->value5);
  12247. xmlXPathPopFrame(ctxt, frame);
  12248. ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
  12249. break;
  12250. }
  12251. func = xmlXPathFunctionLookupNS(ctxt->context,
  12252. op->value4, URI);
  12253. }
  12254. if (func == NULL) {
  12255. xmlGenericError(xmlGenericErrorContext,
  12256. "xmlXPathCompOpEval: function %s not found\n",
  12257. (char *)op->value4);
  12258. XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
  12259. }
  12260. op->cache = func;
  12261. op->cacheURI = (void *) URI;
  12262. }
  12263. oldFunc = ctxt->context->function;
  12264. oldFuncURI = ctxt->context->functionURI;
  12265. ctxt->context->function = op->value4;
  12266. ctxt->context->functionURI = op->cacheURI;
  12267. func(ctxt, op->value);
  12268. ctxt->context->function = oldFunc;
  12269. ctxt->context->functionURI = oldFuncURI;
  12270. if ((ctxt->error == XPATH_EXPRESSION_OK) &&
  12271. (ctxt->valueNr != ctxt->valueFrame + 1))
  12272. XP_ERROR0(XPATH_STACK_ERROR);
  12273. xmlXPathPopFrame(ctxt, frame);
  12274. break;
  12275. }
  12276. case XPATH_OP_ARG:
  12277. if (op->ch1 != -1) {
  12278. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12279. CHECK_ERROR0;
  12280. }
  12281. if (op->ch2 != -1) {
  12282. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12283. CHECK_ERROR0;
  12284. }
  12285. break;
  12286. case XPATH_OP_PREDICATE:
  12287. case XPATH_OP_FILTER:{
  12288. xmlNodeSetPtr set;
  12289. /*
  12290. * Optimization for ()[1] selection i.e. the first elem
  12291. */
  12292. if ((op->ch1 != -1) && (op->ch2 != -1) &&
  12293. #ifdef XP_OPTIMIZED_FILTER_FIRST
  12294. /*
  12295. * FILTER TODO: Can we assume that the inner processing
  12296. * will result in an ordered list if we have an
  12297. * XPATH_OP_FILTER?
  12298. * What about an additional field or flag on
  12299. * xmlXPathObject like @sorted ? This way we wouldn't need
  12300. * to assume anything, so it would be more robust and
  12301. * easier to optimize.
  12302. */
  12303. ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
  12304. (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
  12305. #else
  12306. (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
  12307. #endif
  12308. (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
  12309. xmlXPathObjectPtr val;
  12310. val = comp->steps[op->ch2].value4;
  12311. if ((val != NULL) && (val->type == XPATH_NUMBER) &&
  12312. (val->floatval == 1.0)) {
  12313. xmlNodePtr first = NULL;
  12314. total +=
  12315. xmlXPathCompOpEvalFirst(ctxt,
  12316. &comp->steps[op->ch1],
  12317. &first);
  12318. CHECK_ERROR0;
  12319. /*
  12320. * The nodeset should be in document order,
  12321. * Keep only the first value
  12322. */
  12323. if ((ctxt->value != NULL) &&
  12324. (ctxt->value->type == XPATH_NODESET) &&
  12325. (ctxt->value->nodesetval != NULL) &&
  12326. (ctxt->value->nodesetval->nodeNr > 1))
  12327. xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
  12328. 1, 1);
  12329. break;
  12330. }
  12331. }
  12332. /*
  12333. * Optimization for ()[last()] selection i.e. the last elem
  12334. */
  12335. if ((op->ch1 != -1) && (op->ch2 != -1) &&
  12336. (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
  12337. (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
  12338. int f = comp->steps[op->ch2].ch1;
  12339. if ((f != -1) &&
  12340. (comp->steps[f].op == XPATH_OP_FUNCTION) &&
  12341. (comp->steps[f].value5 == NULL) &&
  12342. (comp->steps[f].value == 0) &&
  12343. (comp->steps[f].value4 != NULL) &&
  12344. (xmlStrEqual
  12345. (comp->steps[f].value4, BAD_CAST "last"))) {
  12346. xmlNodePtr last = NULL;
  12347. total +=
  12348. xmlXPathCompOpEvalLast(ctxt,
  12349. &comp->steps[op->ch1],
  12350. &last);
  12351. CHECK_ERROR0;
  12352. /*
  12353. * The nodeset should be in document order,
  12354. * Keep only the last value
  12355. */
  12356. if ((ctxt->value != NULL) &&
  12357. (ctxt->value->type == XPATH_NODESET) &&
  12358. (ctxt->value->nodesetval != NULL) &&
  12359. (ctxt->value->nodesetval->nodeTab != NULL) &&
  12360. (ctxt->value->nodesetval->nodeNr > 1))
  12361. xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
  12362. break;
  12363. }
  12364. }
  12365. /*
  12366. * Process inner predicates first.
  12367. * Example "index[parent::book][1]":
  12368. * ...
  12369. * PREDICATE <-- we are here "[1]"
  12370. * PREDICATE <-- process "[parent::book]" first
  12371. * SORT
  12372. * COLLECT 'parent' 'name' 'node' book
  12373. * NODE
  12374. * ELEM Object is a number : 1
  12375. */
  12376. if (op->ch1 != -1)
  12377. total +=
  12378. xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12379. CHECK_ERROR0;
  12380. if (op->ch2 == -1)
  12381. break;
  12382. if (ctxt->value == NULL)
  12383. break;
  12384. #ifdef LIBXML_XPTR_ENABLED
  12385. /*
  12386. * Hum are we filtering the result of an XPointer expression
  12387. */
  12388. if (ctxt->value->type == XPATH_LOCATIONSET) {
  12389. xmlLocationSetPtr locset = ctxt->value->user;
  12390. xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
  12391. 1, locset->locNr);
  12392. break;
  12393. }
  12394. #endif /* LIBXML_XPTR_ENABLED */
  12395. CHECK_TYPE0(XPATH_NODESET);
  12396. set = ctxt->value->nodesetval;
  12397. if (set != NULL)
  12398. xmlXPathNodeSetFilter(ctxt, set, op->ch2,
  12399. 1, set->nodeNr, 1);
  12400. break;
  12401. }
  12402. case XPATH_OP_SORT:
  12403. if (op->ch1 != -1)
  12404. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12405. CHECK_ERROR0;
  12406. if ((ctxt->value != NULL) &&
  12407. (ctxt->value->type == XPATH_NODESET) &&
  12408. (ctxt->value->nodesetval != NULL) &&
  12409. (ctxt->value->nodesetval->nodeNr > 1))
  12410. {
  12411. xmlXPathNodeSetSort(ctxt->value->nodesetval);
  12412. }
  12413. break;
  12414. #ifdef LIBXML_XPTR_ENABLED
  12415. case XPATH_OP_RANGETO:{
  12416. xmlXPathObjectPtr range;
  12417. xmlXPathObjectPtr res, obj;
  12418. xmlXPathObjectPtr tmp;
  12419. xmlLocationSetPtr newlocset = NULL;
  12420. xmlLocationSetPtr oldlocset;
  12421. xmlNodeSetPtr oldset;
  12422. xmlNodePtr oldnode = ctxt->context->node;
  12423. int oldcs = ctxt->context->contextSize;
  12424. int oldpp = ctxt->context->proximityPosition;
  12425. int i, j;
  12426. if (op->ch1 != -1) {
  12427. total +=
  12428. xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12429. CHECK_ERROR0;
  12430. }
  12431. if (ctxt->value == NULL) {
  12432. XP_ERROR0(XPATH_INVALID_OPERAND);
  12433. }
  12434. if (op->ch2 == -1)
  12435. break;
  12436. if (ctxt->value->type == XPATH_LOCATIONSET) {
  12437. /*
  12438. * Extract the old locset, and then evaluate the result of the
  12439. * expression for all the element in the locset. use it to grow
  12440. * up a new locset.
  12441. */
  12442. CHECK_TYPE0(XPATH_LOCATIONSET);
  12443. if ((ctxt->value->user == NULL) ||
  12444. (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
  12445. break;
  12446. obj = valuePop(ctxt);
  12447. oldlocset = obj->user;
  12448. newlocset = xmlXPtrLocationSetCreate(NULL);
  12449. for (i = 0; i < oldlocset->locNr; i++) {
  12450. /*
  12451. * Run the evaluation with a node list made of a
  12452. * single item in the nodelocset.
  12453. */
  12454. ctxt->context->node = oldlocset->locTab[i]->user;
  12455. ctxt->context->contextSize = oldlocset->locNr;
  12456. ctxt->context->proximityPosition = i + 1;
  12457. tmp = xmlXPathCacheNewNodeSet(ctxt->context,
  12458. ctxt->context->node);
  12459. valuePush(ctxt, tmp);
  12460. if (op->ch2 != -1)
  12461. total +=
  12462. xmlXPathCompOpEval(ctxt,
  12463. &comp->steps[op->ch2]);
  12464. if (ctxt->error != XPATH_EXPRESSION_OK) {
  12465. xmlXPtrFreeLocationSet(newlocset);
  12466. goto rangeto_error;
  12467. }
  12468. res = valuePop(ctxt);
  12469. if (res->type == XPATH_LOCATIONSET) {
  12470. xmlLocationSetPtr rloc =
  12471. (xmlLocationSetPtr)res->user;
  12472. for (j=0; j<rloc->locNr; j++) {
  12473. range = xmlXPtrNewRange(
  12474. oldlocset->locTab[i]->user,
  12475. oldlocset->locTab[i]->index,
  12476. rloc->locTab[j]->user2,
  12477. rloc->locTab[j]->index2);
  12478. if (range != NULL) {
  12479. xmlXPtrLocationSetAdd(newlocset, range);
  12480. }
  12481. }
  12482. } else {
  12483. range = xmlXPtrNewRangeNodeObject(
  12484. (xmlNodePtr)oldlocset->locTab[i]->user, res);
  12485. if (range != NULL) {
  12486. xmlXPtrLocationSetAdd(newlocset,range);
  12487. }
  12488. }
  12489. /*
  12490. * Cleanup
  12491. */
  12492. if (res != NULL) {
  12493. xmlXPathReleaseObject(ctxt->context, res);
  12494. }
  12495. if (ctxt->value == tmp) {
  12496. res = valuePop(ctxt);
  12497. xmlXPathReleaseObject(ctxt->context, res);
  12498. }
  12499. }
  12500. } else { /* Not a location set */
  12501. CHECK_TYPE0(XPATH_NODESET);
  12502. obj = valuePop(ctxt);
  12503. oldset = obj->nodesetval;
  12504. newlocset = xmlXPtrLocationSetCreate(NULL);
  12505. if (oldset != NULL) {
  12506. for (i = 0; i < oldset->nodeNr; i++) {
  12507. /*
  12508. * Run the evaluation with a node list made of a single item
  12509. * in the nodeset.
  12510. */
  12511. ctxt->context->node = oldset->nodeTab[i];
  12512. /*
  12513. * OPTIMIZE TODO: Avoid recreation for every iteration.
  12514. */
  12515. tmp = xmlXPathCacheNewNodeSet(ctxt->context,
  12516. ctxt->context->node);
  12517. valuePush(ctxt, tmp);
  12518. if (op->ch2 != -1)
  12519. total +=
  12520. xmlXPathCompOpEval(ctxt,
  12521. &comp->steps[op->ch2]);
  12522. if (ctxt->error != XPATH_EXPRESSION_OK) {
  12523. xmlXPtrFreeLocationSet(newlocset);
  12524. goto rangeto_error;
  12525. }
  12526. res = valuePop(ctxt);
  12527. range =
  12528. xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
  12529. res);
  12530. if (range != NULL) {
  12531. xmlXPtrLocationSetAdd(newlocset, range);
  12532. }
  12533. /*
  12534. * Cleanup
  12535. */
  12536. if (res != NULL) {
  12537. xmlXPathReleaseObject(ctxt->context, res);
  12538. }
  12539. if (ctxt->value == tmp) {
  12540. res = valuePop(ctxt);
  12541. xmlXPathReleaseObject(ctxt->context, res);
  12542. }
  12543. }
  12544. }
  12545. }
  12546. /*
  12547. * The result is used as the new evaluation set.
  12548. */
  12549. valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
  12550. rangeto_error:
  12551. xmlXPathReleaseObject(ctxt->context, obj);
  12552. ctxt->context->node = oldnode;
  12553. ctxt->context->contextSize = oldcs;
  12554. ctxt->context->proximityPosition = oldpp;
  12555. break;
  12556. }
  12557. #endif /* LIBXML_XPTR_ENABLED */
  12558. default:
  12559. xmlGenericError(xmlGenericErrorContext,
  12560. "XPath: unknown precompiled operation %d\n", op->op);
  12561. ctxt->error = XPATH_INVALID_OPERAND;
  12562. break;
  12563. }
  12564. ctxt->context->depth -= 1;
  12565. return (total);
  12566. }
  12567. /**
  12568. * xmlXPathCompOpEvalToBoolean:
  12569. * @ctxt: the XPath parser context
  12570. *
  12571. * Evaluates if the expression evaluates to true.
  12572. *
  12573. * Returns 1 if true, 0 if false and -1 on API or internal errors.
  12574. */
  12575. static int
  12576. xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
  12577. xmlXPathStepOpPtr op,
  12578. int isPredicate)
  12579. {
  12580. xmlXPathObjectPtr resObj = NULL;
  12581. start:
  12582. if (OP_LIMIT_EXCEEDED(ctxt, 1))
  12583. return(0);
  12584. /* comp = ctxt->comp; */
  12585. switch (op->op) {
  12586. case XPATH_OP_END:
  12587. return (0);
  12588. case XPATH_OP_VALUE:
  12589. resObj = (xmlXPathObjectPtr) op->value4;
  12590. if (isPredicate)
  12591. return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
  12592. return(xmlXPathCastToBoolean(resObj));
  12593. case XPATH_OP_SORT:
  12594. /*
  12595. * We don't need sorting for boolean results. Skip this one.
  12596. */
  12597. if (op->ch1 != -1) {
  12598. op = &ctxt->comp->steps[op->ch1];
  12599. goto start;
  12600. }
  12601. return(0);
  12602. case XPATH_OP_COLLECT:
  12603. if (op->ch1 == -1)
  12604. return(0);
  12605. xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
  12606. if (ctxt->error != XPATH_EXPRESSION_OK)
  12607. return(-1);
  12608. xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
  12609. if (ctxt->error != XPATH_EXPRESSION_OK)
  12610. return(-1);
  12611. resObj = valuePop(ctxt);
  12612. if (resObj == NULL)
  12613. return(-1);
  12614. break;
  12615. default:
  12616. /*
  12617. * Fallback to call xmlXPathCompOpEval().
  12618. */
  12619. xmlXPathCompOpEval(ctxt, op);
  12620. if (ctxt->error != XPATH_EXPRESSION_OK)
  12621. return(-1);
  12622. resObj = valuePop(ctxt);
  12623. if (resObj == NULL)
  12624. return(-1);
  12625. break;
  12626. }
  12627. if (resObj) {
  12628. int res;
  12629. if (resObj->type == XPATH_BOOLEAN) {
  12630. res = resObj->boolval;
  12631. } else if (isPredicate) {
  12632. /*
  12633. * For predicates a result of type "number" is handled
  12634. * differently:
  12635. * SPEC XPath 1.0:
  12636. * "If the result is a number, the result will be converted
  12637. * to true if the number is equal to the context position
  12638. * and will be converted to false otherwise;"
  12639. */
  12640. res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
  12641. } else {
  12642. res = xmlXPathCastToBoolean(resObj);
  12643. }
  12644. xmlXPathReleaseObject(ctxt->context, resObj);
  12645. return(res);
  12646. }
  12647. return(0);
  12648. }
  12649. #ifdef XPATH_STREAMING
  12650. /**
  12651. * xmlXPathRunStreamEval:
  12652. * @ctxt: the XPath parser context with the compiled expression
  12653. *
  12654. * Evaluate the Precompiled Streamable XPath expression in the given context.
  12655. */
  12656. static int
  12657. xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
  12658. xmlXPathObjectPtr *resultSeq, int toBool)
  12659. {
  12660. int max_depth, min_depth;
  12661. int from_root;
  12662. int ret, depth;
  12663. int eval_all_nodes;
  12664. xmlNodePtr cur = NULL, limit = NULL;
  12665. xmlStreamCtxtPtr patstream = NULL;
  12666. int nb_nodes = 0;
  12667. if ((ctxt == NULL) || (comp == NULL))
  12668. return(-1);
  12669. max_depth = xmlPatternMaxDepth(comp);
  12670. if (max_depth == -1)
  12671. return(-1);
  12672. if (max_depth == -2)
  12673. max_depth = 10000;
  12674. min_depth = xmlPatternMinDepth(comp);
  12675. if (min_depth == -1)
  12676. return(-1);
  12677. from_root = xmlPatternFromRoot(comp);
  12678. if (from_root < 0)
  12679. return(-1);
  12680. #if 0
  12681. printf("stream eval: depth %d from root %d\n", max_depth, from_root);
  12682. #endif
  12683. if (! toBool) {
  12684. if (resultSeq == NULL)
  12685. return(-1);
  12686. *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
  12687. if (*resultSeq == NULL)
  12688. return(-1);
  12689. }
  12690. /*
  12691. * handle the special cases of "/" amd "." being matched
  12692. */
  12693. if (min_depth == 0) {
  12694. if (from_root) {
  12695. /* Select "/" */
  12696. if (toBool)
  12697. return(1);
  12698. /* TODO: Check memory error. */
  12699. xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
  12700. (xmlNodePtr) ctxt->doc);
  12701. } else {
  12702. /* Select "self::node()" */
  12703. if (toBool)
  12704. return(1);
  12705. /* TODO: Check memory error. */
  12706. xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
  12707. }
  12708. }
  12709. if (max_depth == 0) {
  12710. return(0);
  12711. }
  12712. if (from_root) {
  12713. cur = (xmlNodePtr)ctxt->doc;
  12714. } else if (ctxt->node != NULL) {
  12715. switch (ctxt->node->type) {
  12716. case XML_ELEMENT_NODE:
  12717. case XML_DOCUMENT_NODE:
  12718. case XML_DOCUMENT_FRAG_NODE:
  12719. case XML_HTML_DOCUMENT_NODE:
  12720. #ifdef LIBXML_DOCB_ENABLED
  12721. case XML_DOCB_DOCUMENT_NODE:
  12722. #endif
  12723. cur = ctxt->node;
  12724. break;
  12725. case XML_ATTRIBUTE_NODE:
  12726. case XML_TEXT_NODE:
  12727. case XML_CDATA_SECTION_NODE:
  12728. case XML_ENTITY_REF_NODE:
  12729. case XML_ENTITY_NODE:
  12730. case XML_PI_NODE:
  12731. case XML_COMMENT_NODE:
  12732. case XML_NOTATION_NODE:
  12733. case XML_DTD_NODE:
  12734. case XML_DOCUMENT_TYPE_NODE:
  12735. case XML_ELEMENT_DECL:
  12736. case XML_ATTRIBUTE_DECL:
  12737. case XML_ENTITY_DECL:
  12738. case XML_NAMESPACE_DECL:
  12739. case XML_XINCLUDE_START:
  12740. case XML_XINCLUDE_END:
  12741. break;
  12742. }
  12743. limit = cur;
  12744. }
  12745. if (cur == NULL) {
  12746. return(0);
  12747. }
  12748. patstream = xmlPatternGetStreamCtxt(comp);
  12749. if (patstream == NULL) {
  12750. /*
  12751. * QUESTION TODO: Is this an error?
  12752. */
  12753. return(0);
  12754. }
  12755. eval_all_nodes = xmlStreamWantsAnyNode(patstream);
  12756. if (from_root) {
  12757. ret = xmlStreamPush(patstream, NULL, NULL);
  12758. if (ret < 0) {
  12759. } else if (ret == 1) {
  12760. if (toBool)
  12761. goto return_1;
  12762. /* TODO: Check memory error. */
  12763. xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
  12764. }
  12765. }
  12766. depth = 0;
  12767. goto scan_children;
  12768. next_node:
  12769. do {
  12770. if (ctxt->opLimit != 0) {
  12771. if (ctxt->opCount >= ctxt->opLimit) {
  12772. xmlGenericError(xmlGenericErrorContext,
  12773. "XPath operation limit exceeded\n");
  12774. xmlFreeStreamCtxt(patstream);
  12775. return(-1);
  12776. }
  12777. ctxt->opCount++;
  12778. }
  12779. nb_nodes++;
  12780. switch (cur->type) {
  12781. case XML_ELEMENT_NODE:
  12782. case XML_TEXT_NODE:
  12783. case XML_CDATA_SECTION_NODE:
  12784. case XML_COMMENT_NODE:
  12785. case XML_PI_NODE:
  12786. if (cur->type == XML_ELEMENT_NODE) {
  12787. ret = xmlStreamPush(patstream, cur->name,
  12788. (cur->ns ? cur->ns->href : NULL));
  12789. } else if (eval_all_nodes)
  12790. ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
  12791. else
  12792. break;
  12793. if (ret < 0) {
  12794. /* NOP. */
  12795. } else if (ret == 1) {
  12796. if (toBool)
  12797. goto return_1;
  12798. if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
  12799. < 0) {
  12800. ctxt->lastError.domain = XML_FROM_XPATH;
  12801. ctxt->lastError.code = XML_ERR_NO_MEMORY;
  12802. }
  12803. }
  12804. if ((cur->children == NULL) || (depth >= max_depth)) {
  12805. ret = xmlStreamPop(patstream);
  12806. while (cur->next != NULL) {
  12807. cur = cur->next;
  12808. if ((cur->type != XML_ENTITY_DECL) &&
  12809. (cur->type != XML_DTD_NODE))
  12810. goto next_node;
  12811. }
  12812. }
  12813. default:
  12814. break;
  12815. }
  12816. scan_children:
  12817. if (cur->type == XML_NAMESPACE_DECL) break;
  12818. if ((cur->children != NULL) && (depth < max_depth)) {
  12819. /*
  12820. * Do not descend on entities declarations
  12821. */
  12822. if (cur->children->type != XML_ENTITY_DECL) {
  12823. cur = cur->children;
  12824. depth++;
  12825. /*
  12826. * Skip DTDs
  12827. */
  12828. if (cur->type != XML_DTD_NODE)
  12829. continue;
  12830. }
  12831. }
  12832. if (cur == limit)
  12833. break;
  12834. while (cur->next != NULL) {
  12835. cur = cur->next;
  12836. if ((cur->type != XML_ENTITY_DECL) &&
  12837. (cur->type != XML_DTD_NODE))
  12838. goto next_node;
  12839. }
  12840. do {
  12841. cur = cur->parent;
  12842. depth--;
  12843. if ((cur == NULL) || (cur == limit) ||
  12844. (cur->type == XML_DOCUMENT_NODE))
  12845. goto done;
  12846. if (cur->type == XML_ELEMENT_NODE) {
  12847. ret = xmlStreamPop(patstream);
  12848. } else if ((eval_all_nodes) &&
  12849. ((cur->type == XML_TEXT_NODE) ||
  12850. (cur->type == XML_CDATA_SECTION_NODE) ||
  12851. (cur->type == XML_COMMENT_NODE) ||
  12852. (cur->type == XML_PI_NODE)))
  12853. {
  12854. ret = xmlStreamPop(patstream);
  12855. }
  12856. if (cur->next != NULL) {
  12857. cur = cur->next;
  12858. break;
  12859. }
  12860. } while (cur != NULL);
  12861. } while ((cur != NULL) && (depth >= 0));
  12862. done:
  12863. #if 0
  12864. printf("stream eval: checked %d nodes selected %d\n",
  12865. nb_nodes, retObj->nodesetval->nodeNr);
  12866. #endif
  12867. if (patstream)
  12868. xmlFreeStreamCtxt(patstream);
  12869. return(0);
  12870. return_1:
  12871. if (patstream)
  12872. xmlFreeStreamCtxt(patstream);
  12873. return(1);
  12874. }
  12875. #endif /* XPATH_STREAMING */
  12876. /**
  12877. * xmlXPathRunEval:
  12878. * @ctxt: the XPath parser context with the compiled expression
  12879. * @toBool: evaluate to a boolean result
  12880. *
  12881. * Evaluate the Precompiled XPath expression in the given context.
  12882. */
  12883. static int
  12884. xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
  12885. {
  12886. xmlXPathCompExprPtr comp;
  12887. if ((ctxt == NULL) || (ctxt->comp == NULL))
  12888. return(-1);
  12889. ctxt->context->depth = 0;
  12890. if (ctxt->valueTab == NULL) {
  12891. /* Allocate the value stack */
  12892. ctxt->valueTab = (xmlXPathObjectPtr *)
  12893. xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
  12894. if (ctxt->valueTab == NULL) {
  12895. xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
  12896. xmlFree(ctxt);
  12897. }
  12898. ctxt->valueNr = 0;
  12899. ctxt->valueMax = 10;
  12900. ctxt->value = NULL;
  12901. ctxt->valueFrame = 0;
  12902. }
  12903. #ifdef XPATH_STREAMING
  12904. if (ctxt->comp->stream) {
  12905. int res;
  12906. if (toBool) {
  12907. /*
  12908. * Evaluation to boolean result.
  12909. */
  12910. res = xmlXPathRunStreamEval(ctxt->context,
  12911. ctxt->comp->stream, NULL, 1);
  12912. if (res != -1)
  12913. return(res);
  12914. } else {
  12915. xmlXPathObjectPtr resObj = NULL;
  12916. /*
  12917. * Evaluation to a sequence.
  12918. */
  12919. res = xmlXPathRunStreamEval(ctxt->context,
  12920. ctxt->comp->stream, &resObj, 0);
  12921. if ((res != -1) && (resObj != NULL)) {
  12922. valuePush(ctxt, resObj);
  12923. return(0);
  12924. }
  12925. if (resObj != NULL)
  12926. xmlXPathReleaseObject(ctxt->context, resObj);
  12927. }
  12928. /*
  12929. * QUESTION TODO: This falls back to normal XPath evaluation
  12930. * if res == -1. Is this intended?
  12931. */
  12932. }
  12933. #endif
  12934. comp = ctxt->comp;
  12935. if (comp->last < 0) {
  12936. xmlGenericError(xmlGenericErrorContext,
  12937. "xmlXPathRunEval: last is less than zero\n");
  12938. return(-1);
  12939. }
  12940. if (toBool)
  12941. return(xmlXPathCompOpEvalToBoolean(ctxt,
  12942. &comp->steps[comp->last], 0));
  12943. else
  12944. xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
  12945. return(0);
  12946. }
  12947. /************************************************************************
  12948. * *
  12949. * Public interfaces *
  12950. * *
  12951. ************************************************************************/
  12952. /**
  12953. * xmlXPathEvalPredicate:
  12954. * @ctxt: the XPath context
  12955. * @res: the Predicate Expression evaluation result
  12956. *
  12957. * Evaluate a predicate result for the current node.
  12958. * A PredicateExpr is evaluated by evaluating the Expr and converting
  12959. * the result to a boolean. If the result is a number, the result will
  12960. * be converted to true if the number is equal to the position of the
  12961. * context node in the context node list (as returned by the position
  12962. * function) and will be converted to false otherwise; if the result
  12963. * is not a number, then the result will be converted as if by a call
  12964. * to the boolean function.
  12965. *
  12966. * Returns 1 if predicate is true, 0 otherwise
  12967. */
  12968. int
  12969. xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
  12970. if ((ctxt == NULL) || (res == NULL)) return(0);
  12971. switch (res->type) {
  12972. case XPATH_BOOLEAN:
  12973. return(res->boolval);
  12974. case XPATH_NUMBER:
  12975. return(res->floatval == ctxt->proximityPosition);
  12976. case XPATH_NODESET:
  12977. case XPATH_XSLT_TREE:
  12978. if (res->nodesetval == NULL)
  12979. return(0);
  12980. return(res->nodesetval->nodeNr != 0);
  12981. case XPATH_STRING:
  12982. return((res->stringval != NULL) &&
  12983. (xmlStrlen(res->stringval) != 0));
  12984. default:
  12985. STRANGE
  12986. }
  12987. return(0);
  12988. }
  12989. /**
  12990. * xmlXPathEvaluatePredicateResult:
  12991. * @ctxt: the XPath Parser context
  12992. * @res: the Predicate Expression evaluation result
  12993. *
  12994. * Evaluate a predicate result for the current node.
  12995. * A PredicateExpr is evaluated by evaluating the Expr and converting
  12996. * the result to a boolean. If the result is a number, the result will
  12997. * be converted to true if the number is equal to the position of the
  12998. * context node in the context node list (as returned by the position
  12999. * function) and will be converted to false otherwise; if the result
  13000. * is not a number, then the result will be converted as if by a call
  13001. * to the boolean function.
  13002. *
  13003. * Returns 1 if predicate is true, 0 otherwise
  13004. */
  13005. int
  13006. xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
  13007. xmlXPathObjectPtr res) {
  13008. if ((ctxt == NULL) || (res == NULL)) return(0);
  13009. switch (res->type) {
  13010. case XPATH_BOOLEAN:
  13011. return(res->boolval);
  13012. case XPATH_NUMBER:
  13013. #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
  13014. return((res->floatval == ctxt->context->proximityPosition) &&
  13015. (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
  13016. #else
  13017. return(res->floatval == ctxt->context->proximityPosition);
  13018. #endif
  13019. case XPATH_NODESET:
  13020. case XPATH_XSLT_TREE:
  13021. if (res->nodesetval == NULL)
  13022. return(0);
  13023. return(res->nodesetval->nodeNr != 0);
  13024. case XPATH_STRING:
  13025. return((res->stringval != NULL) && (res->stringval[0] != 0));
  13026. #ifdef LIBXML_XPTR_ENABLED
  13027. case XPATH_LOCATIONSET:{
  13028. xmlLocationSetPtr ptr = res->user;
  13029. if (ptr == NULL)
  13030. return(0);
  13031. return (ptr->locNr != 0);
  13032. }
  13033. #endif
  13034. default:
  13035. STRANGE
  13036. }
  13037. return(0);
  13038. }
  13039. #ifdef XPATH_STREAMING
  13040. /**
  13041. * xmlXPathTryStreamCompile:
  13042. * @ctxt: an XPath context
  13043. * @str: the XPath expression
  13044. *
  13045. * Try to compile the XPath expression as a streamable subset.
  13046. *
  13047. * Returns the compiled expression or NULL if failed to compile.
  13048. */
  13049. static xmlXPathCompExprPtr
  13050. xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
  13051. /*
  13052. * Optimization: use streaming patterns when the XPath expression can
  13053. * be compiled to a stream lookup
  13054. */
  13055. xmlPatternPtr stream;
  13056. xmlXPathCompExprPtr comp;
  13057. xmlDictPtr dict = NULL;
  13058. const xmlChar **namespaces = NULL;
  13059. xmlNsPtr ns;
  13060. int i, j;
  13061. if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
  13062. (!xmlStrchr(str, '@'))) {
  13063. const xmlChar *tmp;
  13064. /*
  13065. * We don't try to handle expressions using the verbose axis
  13066. * specifiers ("::"), just the simplified form at this point.
  13067. * Additionally, if there is no list of namespaces available and
  13068. * there's a ":" in the expression, indicating a prefixed QName,
  13069. * then we won't try to compile either. xmlPatterncompile() needs
  13070. * to have a list of namespaces at compilation time in order to
  13071. * compile prefixed name tests.
  13072. */
  13073. tmp = xmlStrchr(str, ':');
  13074. if ((tmp != NULL) &&
  13075. ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
  13076. return(NULL);
  13077. if (ctxt != NULL) {
  13078. dict = ctxt->dict;
  13079. if (ctxt->nsNr > 0) {
  13080. namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
  13081. if (namespaces == NULL) {
  13082. xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
  13083. return(NULL);
  13084. }
  13085. for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
  13086. ns = ctxt->namespaces[j];
  13087. namespaces[i++] = ns->href;
  13088. namespaces[i++] = ns->prefix;
  13089. }
  13090. namespaces[i++] = NULL;
  13091. namespaces[i] = NULL;
  13092. }
  13093. }
  13094. stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
  13095. if (namespaces != NULL) {
  13096. xmlFree((xmlChar **)namespaces);
  13097. }
  13098. if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
  13099. comp = xmlXPathNewCompExpr();
  13100. if (comp == NULL) {
  13101. xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
  13102. return(NULL);
  13103. }
  13104. comp->stream = stream;
  13105. comp->dict = dict;
  13106. if (comp->dict)
  13107. xmlDictReference(comp->dict);
  13108. return(comp);
  13109. }
  13110. xmlFreePattern(stream);
  13111. }
  13112. return(NULL);
  13113. }
  13114. #endif /* XPATH_STREAMING */
  13115. static void
  13116. xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
  13117. xmlXPathStepOpPtr op)
  13118. {
  13119. xmlXPathCompExprPtr comp = pctxt->comp;
  13120. xmlXPathContextPtr ctxt;
  13121. /*
  13122. * Try to rewrite "descendant-or-self::node()/foo" to an optimized
  13123. * internal representation.
  13124. */
  13125. if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
  13126. (op->ch1 != -1) &&
  13127. (op->ch2 == -1 /* no predicate */))
  13128. {
  13129. xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
  13130. if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
  13131. ((xmlXPathAxisVal) prevop->value ==
  13132. AXIS_DESCENDANT_OR_SELF) &&
  13133. (prevop->ch2 == -1) &&
  13134. ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
  13135. ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
  13136. {
  13137. /*
  13138. * This is a "descendant-or-self::node()" without predicates.
  13139. * Try to eliminate it.
  13140. */
  13141. switch ((xmlXPathAxisVal) op->value) {
  13142. case AXIS_CHILD:
  13143. case AXIS_DESCENDANT:
  13144. /*
  13145. * Convert "descendant-or-self::node()/child::" or
  13146. * "descendant-or-self::node()/descendant::" to
  13147. * "descendant::"
  13148. */
  13149. op->ch1 = prevop->ch1;
  13150. op->value = AXIS_DESCENDANT;
  13151. break;
  13152. case AXIS_SELF:
  13153. case AXIS_DESCENDANT_OR_SELF:
  13154. /*
  13155. * Convert "descendant-or-self::node()/self::" or
  13156. * "descendant-or-self::node()/descendant-or-self::" to
  13157. * to "descendant-or-self::"
  13158. */
  13159. op->ch1 = prevop->ch1;
  13160. op->value = AXIS_DESCENDANT_OR_SELF;
  13161. break;
  13162. default:
  13163. break;
  13164. }
  13165. }
  13166. }
  13167. /* OP_VALUE has invalid ch1. */
  13168. if (op->op == XPATH_OP_VALUE)
  13169. return;
  13170. /* Recurse */
  13171. ctxt = pctxt->context;
  13172. if (ctxt != NULL) {
  13173. if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
  13174. return;
  13175. ctxt->depth += 1;
  13176. }
  13177. if (op->ch1 != -1)
  13178. xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
  13179. if (op->ch2 != -1)
  13180. xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
  13181. if (ctxt != NULL)
  13182. ctxt->depth -= 1;
  13183. }
  13184. /**
  13185. * xmlXPathCtxtCompile:
  13186. * @ctxt: an XPath context
  13187. * @str: the XPath expression
  13188. *
  13189. * Compile an XPath expression
  13190. *
  13191. * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
  13192. * the caller has to free the object.
  13193. */
  13194. xmlXPathCompExprPtr
  13195. xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
  13196. xmlXPathParserContextPtr pctxt;
  13197. xmlXPathCompExprPtr comp;
  13198. #ifdef XPATH_STREAMING
  13199. comp = xmlXPathTryStreamCompile(ctxt, str);
  13200. if (comp != NULL)
  13201. return(comp);
  13202. #endif
  13203. xmlInitParser();
  13204. pctxt = xmlXPathNewParserContext(str, ctxt);
  13205. if (pctxt == NULL)
  13206. return NULL;
  13207. if (ctxt != NULL)
  13208. ctxt->depth = 0;
  13209. xmlXPathCompileExpr(pctxt, 1);
  13210. if( pctxt->error != XPATH_EXPRESSION_OK )
  13211. {
  13212. xmlXPathFreeParserContext(pctxt);
  13213. return(NULL);
  13214. }
  13215. if (*pctxt->cur != 0) {
  13216. /*
  13217. * aleksey: in some cases this line prints *second* error message
  13218. * (see bug #78858) and probably this should be fixed.
  13219. * However, we are not sure that all error messages are printed
  13220. * out in other places. It's not critical so we leave it as-is for now
  13221. */
  13222. xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
  13223. comp = NULL;
  13224. } else {
  13225. comp = pctxt->comp;
  13226. if ((comp->nbStep > 1) && (comp->last >= 0)) {
  13227. if (ctxt != NULL)
  13228. ctxt->depth = 0;
  13229. xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
  13230. }
  13231. pctxt->comp = NULL;
  13232. }
  13233. xmlXPathFreeParserContext(pctxt);
  13234. if (comp != NULL) {
  13235. comp->expr = xmlStrdup(str);
  13236. #ifdef DEBUG_EVAL_COUNTS
  13237. comp->string = xmlStrdup(str);
  13238. comp->nb = 0;
  13239. #endif
  13240. }
  13241. return(comp);
  13242. }
  13243. /**
  13244. * xmlXPathCompile:
  13245. * @str: the XPath expression
  13246. *
  13247. * Compile an XPath expression
  13248. *
  13249. * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
  13250. * the caller has to free the object.
  13251. */
  13252. xmlXPathCompExprPtr
  13253. xmlXPathCompile(const xmlChar *str) {
  13254. return(xmlXPathCtxtCompile(NULL, str));
  13255. }
  13256. /**
  13257. * xmlXPathCompiledEvalInternal:
  13258. * @comp: the compiled XPath expression
  13259. * @ctxt: the XPath context
  13260. * @resObj: the resulting XPath object or NULL
  13261. * @toBool: 1 if only a boolean result is requested
  13262. *
  13263. * Evaluate the Precompiled XPath expression in the given context.
  13264. * The caller has to free @resObj.
  13265. *
  13266. * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
  13267. * the caller has to free the object.
  13268. */
  13269. static int
  13270. xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
  13271. xmlXPathContextPtr ctxt,
  13272. xmlXPathObjectPtr *resObjPtr,
  13273. int toBool)
  13274. {
  13275. xmlXPathParserContextPtr pctxt;
  13276. xmlXPathObjectPtr resObj;
  13277. #ifndef LIBXML_THREAD_ENABLED
  13278. static int reentance = 0;
  13279. #endif
  13280. int res;
  13281. CHECK_CTXT_NEG(ctxt)
  13282. if (comp == NULL)
  13283. return(-1);
  13284. xmlInitParser();
  13285. #ifndef LIBXML_THREAD_ENABLED
  13286. reentance++;
  13287. if (reentance > 1)
  13288. xmlXPathDisableOptimizer = 1;
  13289. #endif
  13290. #ifdef DEBUG_EVAL_COUNTS
  13291. comp->nb++;
  13292. if ((comp->string != NULL) && (comp->nb > 100)) {
  13293. fprintf(stderr, "100 x %s\n", comp->string);
  13294. comp->nb = 0;
  13295. }
  13296. #endif
  13297. pctxt = xmlXPathCompParserContext(comp, ctxt);
  13298. res = xmlXPathRunEval(pctxt, toBool);
  13299. if (pctxt->error != XPATH_EXPRESSION_OK) {
  13300. resObj = NULL;
  13301. } else {
  13302. resObj = valuePop(pctxt);
  13303. if (resObj == NULL) {
  13304. if (!toBool)
  13305. xmlGenericError(xmlGenericErrorContext,
  13306. "xmlXPathCompiledEval: No result on the stack.\n");
  13307. } else if (pctxt->valueNr > 0) {
  13308. xmlGenericError(xmlGenericErrorContext,
  13309. "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
  13310. pctxt->valueNr);
  13311. }
  13312. }
  13313. if (resObjPtr)
  13314. *resObjPtr = resObj;
  13315. else
  13316. xmlXPathReleaseObject(ctxt, resObj);
  13317. pctxt->comp = NULL;
  13318. xmlXPathFreeParserContext(pctxt);
  13319. #ifndef LIBXML_THREAD_ENABLED
  13320. reentance--;
  13321. #endif
  13322. return(res);
  13323. }
  13324. /**
  13325. * xmlXPathCompiledEval:
  13326. * @comp: the compiled XPath expression
  13327. * @ctx: the XPath context
  13328. *
  13329. * Evaluate the Precompiled XPath expression in the given context.
  13330. *
  13331. * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
  13332. * the caller has to free the object.
  13333. */
  13334. xmlXPathObjectPtr
  13335. xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
  13336. {
  13337. xmlXPathObjectPtr res = NULL;
  13338. xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
  13339. return(res);
  13340. }
  13341. /**
  13342. * xmlXPathCompiledEvalToBoolean:
  13343. * @comp: the compiled XPath expression
  13344. * @ctxt: the XPath context
  13345. *
  13346. * Applies the XPath boolean() function on the result of the given
  13347. * compiled expression.
  13348. *
  13349. * Returns 1 if the expression evaluated to true, 0 if to false and
  13350. * -1 in API and internal errors.
  13351. */
  13352. int
  13353. xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
  13354. xmlXPathContextPtr ctxt)
  13355. {
  13356. return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
  13357. }
  13358. /**
  13359. * xmlXPathEvalExpr:
  13360. * @ctxt: the XPath Parser context
  13361. *
  13362. * Parse and evaluate an XPath expression in the given context,
  13363. * then push the result on the context stack
  13364. */
  13365. void
  13366. xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
  13367. #ifdef XPATH_STREAMING
  13368. xmlXPathCompExprPtr comp;
  13369. #endif
  13370. if (ctxt == NULL) return;
  13371. #ifdef XPATH_STREAMING
  13372. comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
  13373. if (comp != NULL) {
  13374. if (ctxt->comp != NULL)
  13375. xmlXPathFreeCompExpr(ctxt->comp);
  13376. ctxt->comp = comp;
  13377. } else
  13378. #endif
  13379. {
  13380. if (ctxt->context != NULL)
  13381. ctxt->context->depth = 0;
  13382. xmlXPathCompileExpr(ctxt, 1);
  13383. CHECK_ERROR;
  13384. /* Check for trailing characters. */
  13385. if (*ctxt->cur != 0)
  13386. XP_ERROR(XPATH_EXPR_ERROR);
  13387. if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
  13388. if (ctxt->context != NULL)
  13389. ctxt->context->depth = 0;
  13390. xmlXPathOptimizeExpression(ctxt,
  13391. &ctxt->comp->steps[ctxt->comp->last]);
  13392. }
  13393. }
  13394. xmlXPathRunEval(ctxt, 0);
  13395. }
  13396. /**
  13397. * xmlXPathEval:
  13398. * @str: the XPath expression
  13399. * @ctx: the XPath context
  13400. *
  13401. * Evaluate the XPath Location Path in the given context.
  13402. *
  13403. * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
  13404. * the caller has to free the object.
  13405. */
  13406. xmlXPathObjectPtr
  13407. xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
  13408. xmlXPathParserContextPtr ctxt;
  13409. xmlXPathObjectPtr res;
  13410. CHECK_CTXT(ctx)
  13411. xmlInitParser();
  13412. ctxt = xmlXPathNewParserContext(str, ctx);
  13413. if (ctxt == NULL)
  13414. return NULL;
  13415. xmlXPathEvalExpr(ctxt);
  13416. if (ctxt->error != XPATH_EXPRESSION_OK) {
  13417. res = NULL;
  13418. } else {
  13419. res = valuePop(ctxt);
  13420. if (res == NULL) {
  13421. xmlGenericError(xmlGenericErrorContext,
  13422. "xmlXPathCompiledEval: No result on the stack.\n");
  13423. } else if (ctxt->valueNr > 0) {
  13424. xmlGenericError(xmlGenericErrorContext,
  13425. "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
  13426. ctxt->valueNr);
  13427. }
  13428. }
  13429. xmlXPathFreeParserContext(ctxt);
  13430. return(res);
  13431. }
  13432. /**
  13433. * xmlXPathSetContextNode:
  13434. * @node: the node to to use as the context node
  13435. * @ctx: the XPath context
  13436. *
  13437. * Sets 'node' as the context node. The node must be in the same
  13438. * document as that associated with the context.
  13439. *
  13440. * Returns -1 in case of error or 0 if successful
  13441. */
  13442. int
  13443. xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
  13444. if ((node == NULL) || (ctx == NULL))
  13445. return(-1);
  13446. if (node->doc == ctx->doc) {
  13447. ctx->node = node;
  13448. return(0);
  13449. }
  13450. return(-1);
  13451. }
  13452. /**
  13453. * xmlXPathNodeEval:
  13454. * @node: the node to to use as the context node
  13455. * @str: the XPath expression
  13456. * @ctx: the XPath context
  13457. *
  13458. * Evaluate the XPath Location Path in the given context. The node 'node'
  13459. * is set as the context node. The context node is not restored.
  13460. *
  13461. * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
  13462. * the caller has to free the object.
  13463. */
  13464. xmlXPathObjectPtr
  13465. xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
  13466. if (str == NULL)
  13467. return(NULL);
  13468. if (xmlXPathSetContextNode(node, ctx) < 0)
  13469. return(NULL);
  13470. return(xmlXPathEval(str, ctx));
  13471. }
  13472. /**
  13473. * xmlXPathEvalExpression:
  13474. * @str: the XPath expression
  13475. * @ctxt: the XPath context
  13476. *
  13477. * Alias for xmlXPathEval().
  13478. *
  13479. * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
  13480. * the caller has to free the object.
  13481. */
  13482. xmlXPathObjectPtr
  13483. xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
  13484. return(xmlXPathEval(str, ctxt));
  13485. }
  13486. /************************************************************************
  13487. * *
  13488. * Extra functions not pertaining to the XPath spec *
  13489. * *
  13490. ************************************************************************/
  13491. /**
  13492. * xmlXPathEscapeUriFunction:
  13493. * @ctxt: the XPath Parser context
  13494. * @nargs: the number of arguments
  13495. *
  13496. * Implement the escape-uri() XPath function
  13497. * string escape-uri(string $str, bool $escape-reserved)
  13498. *
  13499. * This function applies the URI escaping rules defined in section 2 of [RFC
  13500. * 2396] to the string supplied as $uri-part, which typically represents all
  13501. * or part of a URI. The effect of the function is to replace any special
  13502. * character in the string by an escape sequence of the form %xx%yy...,
  13503. * where xxyy... is the hexadecimal representation of the octets used to
  13504. * represent the character in UTF-8.
  13505. *
  13506. * The set of characters that are escaped depends on the setting of the
  13507. * boolean argument $escape-reserved.
  13508. *
  13509. * If $escape-reserved is true, all characters are escaped other than lower
  13510. * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
  13511. * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
  13512. * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
  13513. * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
  13514. * A-F).
  13515. *
  13516. * If $escape-reserved is false, the behavior differs in that characters
  13517. * referred to in [RFC 2396] as reserved characters are not escaped. These
  13518. * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
  13519. *
  13520. * [RFC 2396] does not define whether escaped URIs should use lower case or
  13521. * upper case for hexadecimal digits. To ensure that escaped URIs can be
  13522. * compared using string comparison functions, this function must always use
  13523. * the upper-case letters A-F.
  13524. *
  13525. * Generally, $escape-reserved should be set to true when escaping a string
  13526. * that is to form a single part of a URI, and to false when escaping an
  13527. * entire URI or URI reference.
  13528. *
  13529. * In the case of non-ascii characters, the string is encoded according to
  13530. * utf-8 and then converted according to RFC 2396.
  13531. *
  13532. * Examples
  13533. * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
  13534. * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
  13535. * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
  13536. * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
  13537. *
  13538. */
  13539. static void
  13540. xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  13541. xmlXPathObjectPtr str;
  13542. int escape_reserved;
  13543. xmlBufPtr target;
  13544. xmlChar *cptr;
  13545. xmlChar escape[4];
  13546. CHECK_ARITY(2);
  13547. escape_reserved = xmlXPathPopBoolean(ctxt);
  13548. CAST_TO_STRING;
  13549. str = valuePop(ctxt);
  13550. target = xmlBufCreate();
  13551. escape[0] = '%';
  13552. escape[3] = 0;
  13553. if (target) {
  13554. for (cptr = str->stringval; *cptr; cptr++) {
  13555. if ((*cptr >= 'A' && *cptr <= 'Z') ||
  13556. (*cptr >= 'a' && *cptr <= 'z') ||
  13557. (*cptr >= '0' && *cptr <= '9') ||
  13558. *cptr == '-' || *cptr == '_' || *cptr == '.' ||
  13559. *cptr == '!' || *cptr == '~' || *cptr == '*' ||
  13560. *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
  13561. (*cptr == '%' &&
  13562. ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
  13563. (cptr[1] >= 'a' && cptr[1] <= 'f') ||
  13564. (cptr[1] >= '0' && cptr[1] <= '9')) &&
  13565. ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
  13566. (cptr[2] >= 'a' && cptr[2] <= 'f') ||
  13567. (cptr[2] >= '0' && cptr[2] <= '9'))) ||
  13568. (!escape_reserved &&
  13569. (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
  13570. *cptr == ':' || *cptr == '@' || *cptr == '&' ||
  13571. *cptr == '=' || *cptr == '+' || *cptr == '$' ||
  13572. *cptr == ','))) {
  13573. xmlBufAdd(target, cptr, 1);
  13574. } else {
  13575. if ((*cptr >> 4) < 10)
  13576. escape[1] = '0' + (*cptr >> 4);
  13577. else
  13578. escape[1] = 'A' - 10 + (*cptr >> 4);
  13579. if ((*cptr & 0xF) < 10)
  13580. escape[2] = '0' + (*cptr & 0xF);
  13581. else
  13582. escape[2] = 'A' - 10 + (*cptr & 0xF);
  13583. xmlBufAdd(target, &escape[0], 3);
  13584. }
  13585. }
  13586. }
  13587. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  13588. xmlBufContent(target)));
  13589. xmlBufFree(target);
  13590. xmlXPathReleaseObject(ctxt->context, str);
  13591. }
  13592. /**
  13593. * xmlXPathRegisterAllFunctions:
  13594. * @ctxt: the XPath context
  13595. *
  13596. * Registers all default XPath functions in this context
  13597. */
  13598. void
  13599. xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
  13600. {
  13601. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
  13602. xmlXPathBooleanFunction);
  13603. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
  13604. xmlXPathCeilingFunction);
  13605. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
  13606. xmlXPathCountFunction);
  13607. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
  13608. xmlXPathConcatFunction);
  13609. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
  13610. xmlXPathContainsFunction);
  13611. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
  13612. xmlXPathIdFunction);
  13613. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
  13614. xmlXPathFalseFunction);
  13615. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
  13616. xmlXPathFloorFunction);
  13617. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
  13618. xmlXPathLastFunction);
  13619. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
  13620. xmlXPathLangFunction);
  13621. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
  13622. xmlXPathLocalNameFunction);
  13623. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
  13624. xmlXPathNotFunction);
  13625. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
  13626. xmlXPathNameFunction);
  13627. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
  13628. xmlXPathNamespaceURIFunction);
  13629. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
  13630. xmlXPathNormalizeFunction);
  13631. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
  13632. xmlXPathNumberFunction);
  13633. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
  13634. xmlXPathPositionFunction);
  13635. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
  13636. xmlXPathRoundFunction);
  13637. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
  13638. xmlXPathStringFunction);
  13639. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
  13640. xmlXPathStringLengthFunction);
  13641. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
  13642. xmlXPathStartsWithFunction);
  13643. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
  13644. xmlXPathSubstringFunction);
  13645. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
  13646. xmlXPathSubstringBeforeFunction);
  13647. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
  13648. xmlXPathSubstringAfterFunction);
  13649. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
  13650. xmlXPathSumFunction);
  13651. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
  13652. xmlXPathTrueFunction);
  13653. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
  13654. xmlXPathTranslateFunction);
  13655. xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
  13656. (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
  13657. xmlXPathEscapeUriFunction);
  13658. }
  13659. #endif /* LIBXML_XPATH_ENABLED */
  13660. #define bottom_xpath
  13661. #include "elfgcchack.h"