xpath.c 375 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834
  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. #include <math.h>
  26. #include <float.h>
  27. #include <ctype.h>
  28. #include <libxml/xmlmemory.h>
  29. #include <libxml/tree.h>
  30. #include <libxml/xpath.h>
  31. #include <libxml/xpathInternals.h>
  32. #include <libxml/parserInternals.h>
  33. #include <libxml/hash.h>
  34. #ifdef LIBXML_XPTR_LOCS_ENABLED
  35. #include <libxml/xpointer.h>
  36. #endif
  37. #ifdef LIBXML_DEBUG_ENABLED
  38. #include <libxml/debugXML.h>
  39. #endif
  40. #include <libxml/xmlerror.h>
  41. #include <libxml/threads.h>
  42. #ifdef LIBXML_PATTERN_ENABLED
  43. #include <libxml/pattern.h>
  44. #endif
  45. #include "private/buf.h"
  46. #include "private/error.h"
  47. #include "private/xpath.h"
  48. #ifdef LIBXML_PATTERN_ENABLED
  49. #define XPATH_STREAMING
  50. #endif
  51. #define TODO \
  52. xmlGenericError(xmlGenericErrorContext, \
  53. "Unimplemented block at %s:%d\n", \
  54. __FILE__, __LINE__);
  55. /**
  56. * WITH_TIM_SORT:
  57. *
  58. * Use the Timsort algorithm provided in timsort.h to sort
  59. * nodeset as this is a great improvement over the old Shell sort
  60. * used in xmlXPathNodeSetSort()
  61. */
  62. #define WITH_TIM_SORT
  63. /*
  64. * XP_OPTIMIZED_NON_ELEM_COMPARISON:
  65. * If defined, this will use xmlXPathCmpNodesExt() instead of
  66. * xmlXPathCmpNodes(). The new function is optimized comparison of
  67. * non-element nodes; actually it will speed up comparison only if
  68. * xmlXPathOrderDocElems() was called in order to index the elements of
  69. * a tree in document order; Libxslt does such an indexing, thus it will
  70. * benefit from this optimization.
  71. */
  72. #define XP_OPTIMIZED_NON_ELEM_COMPARISON
  73. /*
  74. * XP_OPTIMIZED_FILTER_FIRST:
  75. * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
  76. * in a way, that it stop evaluation at the first node.
  77. */
  78. #define XP_OPTIMIZED_FILTER_FIRST
  79. /*
  80. * XPATH_MAX_STEPS:
  81. * when compiling an XPath expression we arbitrary limit the maximum
  82. * number of step operation in the compiled expression. 1000000 is
  83. * an insanely large value which should never be reached under normal
  84. * circumstances
  85. */
  86. #define XPATH_MAX_STEPS 1000000
  87. /*
  88. * XPATH_MAX_STACK_DEPTH:
  89. * when evaluating an XPath expression we arbitrary limit the maximum
  90. * number of object allowed to be pushed on the stack. 1000000 is
  91. * an insanely large value which should never be reached under normal
  92. * circumstances
  93. */
  94. #define XPATH_MAX_STACK_DEPTH 1000000
  95. /*
  96. * XPATH_MAX_NODESET_LENGTH:
  97. * when evaluating an XPath expression nodesets are created and we
  98. * arbitrary limit the maximum length of those node set. 10000000 is
  99. * an insanely large value which should never be reached under normal
  100. * circumstances, one would first need to construct an in memory tree
  101. * with more than 10 millions nodes.
  102. */
  103. #define XPATH_MAX_NODESET_LENGTH 10000000
  104. /*
  105. * XPATH_MAX_RECRUSION_DEPTH:
  106. * Maximum amount of nested functions calls when parsing or evaluating
  107. * expressions
  108. */
  109. #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
  110. #define XPATH_MAX_RECURSION_DEPTH 500
  111. #elif defined(_WIN32)
  112. /* Windows typically limits stack size to 1MB. */
  113. #define XPATH_MAX_RECURSION_DEPTH 1000
  114. #else
  115. #define XPATH_MAX_RECURSION_DEPTH 5000
  116. #endif
  117. /*
  118. * TODO:
  119. * There are a few spots where some tests are done which depend upon ascii
  120. * data. These should be enhanced for full UTF8 support (see particularly
  121. * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
  122. */
  123. #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
  124. /************************************************************************
  125. * *
  126. * Floating point stuff *
  127. * *
  128. ************************************************************************/
  129. double xmlXPathNAN = 0.0;
  130. double xmlXPathPINF = 0.0;
  131. double xmlXPathNINF = 0.0;
  132. /**
  133. * xmlXPathInit:
  134. *
  135. * DEPRECATED: Alias for xmlInitParser.
  136. */
  137. void
  138. xmlXPathInit(void) {
  139. xmlInitParser();
  140. }
  141. /**
  142. * xmlInitXPathInternal:
  143. *
  144. * Initialize the XPath environment
  145. */
  146. ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
  147. void
  148. xmlInitXPathInternal(void) {
  149. #if defined(NAN) && defined(INFINITY)
  150. xmlXPathNAN = NAN;
  151. xmlXPathPINF = INFINITY;
  152. xmlXPathNINF = -INFINITY;
  153. #else
  154. /* MSVC doesn't allow division by zero in constant expressions. */
  155. double zero = 0.0;
  156. xmlXPathNAN = 0.0 / zero;
  157. xmlXPathPINF = 1.0 / zero;
  158. xmlXPathNINF = -xmlXPathPINF;
  159. #endif
  160. }
  161. /**
  162. * xmlXPathIsNaN:
  163. * @val: a double value
  164. *
  165. * Checks whether a double is a NaN.
  166. *
  167. * Returns 1 if the value is a NaN, 0 otherwise
  168. */
  169. int
  170. xmlXPathIsNaN(double val) {
  171. #ifdef isnan
  172. return isnan(val);
  173. #else
  174. return !(val == val);
  175. #endif
  176. }
  177. /**
  178. * xmlXPathIsInf:
  179. * @val: a double value
  180. *
  181. * Checks whether a double is an infinity.
  182. *
  183. * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
  184. */
  185. int
  186. xmlXPathIsInf(double val) {
  187. #ifdef isinf
  188. return isinf(val) ? (val > 0 ? 1 : -1) : 0;
  189. #else
  190. if (val >= xmlXPathPINF)
  191. return 1;
  192. if (val <= -xmlXPathPINF)
  193. return -1;
  194. return 0;
  195. #endif
  196. }
  197. #endif /* SCHEMAS or XPATH */
  198. #ifdef LIBXML_XPATH_ENABLED
  199. /*
  200. * TODO: when compatibility allows remove all "fake node libxslt" strings
  201. * the test should just be name[0] = ' '
  202. */
  203. static xmlNs xmlXPathXMLNamespaceStruct = {
  204. NULL,
  205. XML_NAMESPACE_DECL,
  206. XML_XML_NAMESPACE,
  207. BAD_CAST "xml",
  208. NULL,
  209. NULL
  210. };
  211. static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
  212. #ifndef LIBXML_THREAD_ENABLED
  213. /*
  214. * Optimizer is disabled only when threaded apps are detected while
  215. * the library ain't compiled for thread safety.
  216. */
  217. static int xmlXPathDisableOptimizer = 0;
  218. #endif
  219. static void
  220. xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes);
  221. #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
  222. /**
  223. * xmlXPathCmpNodesExt:
  224. * @node1: the first node
  225. * @node2: the second node
  226. *
  227. * Compare two nodes w.r.t document order.
  228. * This one is optimized for handling of non-element nodes.
  229. *
  230. * Returns -2 in case of error 1 if first point < second point, 0 if
  231. * it's the same node, -1 otherwise
  232. */
  233. static int
  234. xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
  235. int depth1, depth2;
  236. int misc = 0, precedence1 = 0, precedence2 = 0;
  237. xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
  238. xmlNodePtr cur, root;
  239. ptrdiff_t l1, l2;
  240. if ((node1 == NULL) || (node2 == NULL))
  241. return(-2);
  242. if (node1 == node2)
  243. return(0);
  244. /*
  245. * a couple of optimizations which will avoid computations in most cases
  246. */
  247. switch (node1->type) {
  248. case XML_ELEMENT_NODE:
  249. if (node2->type == XML_ELEMENT_NODE) {
  250. if ((0 > (ptrdiff_t) node1->content) &&
  251. (0 > (ptrdiff_t) node2->content) &&
  252. (node1->doc == node2->doc))
  253. {
  254. l1 = -((ptrdiff_t) node1->content);
  255. l2 = -((ptrdiff_t) node2->content);
  256. if (l1 < l2)
  257. return(1);
  258. if (l1 > l2)
  259. return(-1);
  260. } else
  261. goto turtle_comparison;
  262. }
  263. break;
  264. case XML_ATTRIBUTE_NODE:
  265. precedence1 = 1; /* element is owner */
  266. miscNode1 = node1;
  267. node1 = node1->parent;
  268. misc = 1;
  269. break;
  270. case XML_TEXT_NODE:
  271. case XML_CDATA_SECTION_NODE:
  272. case XML_COMMENT_NODE:
  273. case XML_PI_NODE: {
  274. miscNode1 = node1;
  275. /*
  276. * Find nearest element node.
  277. */
  278. if (node1->prev != NULL) {
  279. do {
  280. node1 = node1->prev;
  281. if (node1->type == XML_ELEMENT_NODE) {
  282. precedence1 = 3; /* element in prev-sibl axis */
  283. break;
  284. }
  285. if (node1->prev == NULL) {
  286. precedence1 = 2; /* element is parent */
  287. /*
  288. * URGENT TODO: Are there any cases, where the
  289. * parent of such a node is not an element node?
  290. */
  291. node1 = node1->parent;
  292. break;
  293. }
  294. } while (1);
  295. } else {
  296. precedence1 = 2; /* element is parent */
  297. node1 = node1->parent;
  298. }
  299. if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
  300. (0 <= (ptrdiff_t) node1->content)) {
  301. /*
  302. * Fallback for whatever case.
  303. */
  304. node1 = miscNode1;
  305. precedence1 = 0;
  306. } else
  307. misc = 1;
  308. }
  309. break;
  310. case XML_NAMESPACE_DECL:
  311. /*
  312. * TODO: why do we return 1 for namespace nodes?
  313. */
  314. return(1);
  315. default:
  316. break;
  317. }
  318. switch (node2->type) {
  319. case XML_ELEMENT_NODE:
  320. break;
  321. case XML_ATTRIBUTE_NODE:
  322. precedence2 = 1; /* element is owner */
  323. miscNode2 = node2;
  324. node2 = node2->parent;
  325. misc = 1;
  326. break;
  327. case XML_TEXT_NODE:
  328. case XML_CDATA_SECTION_NODE:
  329. case XML_COMMENT_NODE:
  330. case XML_PI_NODE: {
  331. miscNode2 = node2;
  332. if (node2->prev != NULL) {
  333. do {
  334. node2 = node2->prev;
  335. if (node2->type == XML_ELEMENT_NODE) {
  336. precedence2 = 3; /* element in prev-sibl axis */
  337. break;
  338. }
  339. if (node2->prev == NULL) {
  340. precedence2 = 2; /* element is parent */
  341. node2 = node2->parent;
  342. break;
  343. }
  344. } while (1);
  345. } else {
  346. precedence2 = 2; /* element is parent */
  347. node2 = node2->parent;
  348. }
  349. if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
  350. (0 <= (ptrdiff_t) node2->content))
  351. {
  352. node2 = miscNode2;
  353. precedence2 = 0;
  354. } else
  355. misc = 1;
  356. }
  357. break;
  358. case XML_NAMESPACE_DECL:
  359. return(1);
  360. default:
  361. break;
  362. }
  363. if (misc) {
  364. if (node1 == node2) {
  365. if (precedence1 == precedence2) {
  366. /*
  367. * The ugly case; but normally there aren't many
  368. * adjacent non-element nodes around.
  369. */
  370. cur = miscNode2->prev;
  371. while (cur != NULL) {
  372. if (cur == miscNode1)
  373. return(1);
  374. if (cur->type == XML_ELEMENT_NODE)
  375. return(-1);
  376. cur = cur->prev;
  377. }
  378. return (-1);
  379. } else {
  380. /*
  381. * Evaluate based on higher precedence wrt to the element.
  382. * TODO: This assumes attributes are sorted before content.
  383. * Is this 100% correct?
  384. */
  385. if (precedence1 < precedence2)
  386. return(1);
  387. else
  388. return(-1);
  389. }
  390. }
  391. /*
  392. * Special case: One of the helper-elements is contained by the other.
  393. * <foo>
  394. * <node2>
  395. * <node1>Text-1(precedence1 == 2)</node1>
  396. * </node2>
  397. * Text-6(precedence2 == 3)
  398. * </foo>
  399. */
  400. if ((precedence2 == 3) && (precedence1 > 1)) {
  401. cur = node1->parent;
  402. while (cur) {
  403. if (cur == node2)
  404. return(1);
  405. cur = cur->parent;
  406. }
  407. }
  408. if ((precedence1 == 3) && (precedence2 > 1)) {
  409. cur = node2->parent;
  410. while (cur) {
  411. if (cur == node1)
  412. return(-1);
  413. cur = cur->parent;
  414. }
  415. }
  416. }
  417. /*
  418. * Speedup using document order if available.
  419. */
  420. if ((node1->type == XML_ELEMENT_NODE) &&
  421. (node2->type == XML_ELEMENT_NODE) &&
  422. (0 > (ptrdiff_t) node1->content) &&
  423. (0 > (ptrdiff_t) node2->content) &&
  424. (node1->doc == node2->doc)) {
  425. l1 = -((ptrdiff_t) node1->content);
  426. l2 = -((ptrdiff_t) node2->content);
  427. if (l1 < l2)
  428. return(1);
  429. if (l1 > l2)
  430. return(-1);
  431. }
  432. turtle_comparison:
  433. if (node1 == node2->prev)
  434. return(1);
  435. if (node1 == node2->next)
  436. return(-1);
  437. /*
  438. * compute depth to root
  439. */
  440. for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
  441. if (cur->parent == node1)
  442. return(1);
  443. depth2++;
  444. }
  445. root = cur;
  446. for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
  447. if (cur->parent == node2)
  448. return(-1);
  449. depth1++;
  450. }
  451. /*
  452. * Distinct document (or distinct entities :-( ) case.
  453. */
  454. if (root != cur) {
  455. return(-2);
  456. }
  457. /*
  458. * get the nearest common ancestor.
  459. */
  460. while (depth1 > depth2) {
  461. depth1--;
  462. node1 = node1->parent;
  463. }
  464. while (depth2 > depth1) {
  465. depth2--;
  466. node2 = node2->parent;
  467. }
  468. while (node1->parent != node2->parent) {
  469. node1 = node1->parent;
  470. node2 = node2->parent;
  471. /* should not happen but just in case ... */
  472. if ((node1 == NULL) || (node2 == NULL))
  473. return(-2);
  474. }
  475. /*
  476. * Find who's first.
  477. */
  478. if (node1 == node2->prev)
  479. return(1);
  480. if (node1 == node2->next)
  481. return(-1);
  482. /*
  483. * Speedup using document order if available.
  484. */
  485. if ((node1->type == XML_ELEMENT_NODE) &&
  486. (node2->type == XML_ELEMENT_NODE) &&
  487. (0 > (ptrdiff_t) node1->content) &&
  488. (0 > (ptrdiff_t) node2->content) &&
  489. (node1->doc == node2->doc)) {
  490. l1 = -((ptrdiff_t) node1->content);
  491. l2 = -((ptrdiff_t) node2->content);
  492. if (l1 < l2)
  493. return(1);
  494. if (l1 > l2)
  495. return(-1);
  496. }
  497. for (cur = node1->next;cur != NULL;cur = cur->next)
  498. if (cur == node2)
  499. return(1);
  500. return(-1); /* assume there is no sibling list corruption */
  501. }
  502. #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
  503. /*
  504. * Wrapper for the Timsort algorithm from timsort.h
  505. */
  506. #ifdef WITH_TIM_SORT
  507. #define SORT_NAME libxml_domnode
  508. #define SORT_TYPE xmlNodePtr
  509. /**
  510. * wrap_cmp:
  511. * @x: a node
  512. * @y: another node
  513. *
  514. * Comparison function for the Timsort implementation
  515. *
  516. * Returns -2 in case of error -1 if first point < second point, 0 if
  517. * it's the same node, +1 otherwise
  518. */
  519. static
  520. int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
  521. #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
  522. static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
  523. {
  524. int res = xmlXPathCmpNodesExt(x, y);
  525. return res == -2 ? res : -res;
  526. }
  527. #else
  528. static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
  529. {
  530. int res = xmlXPathCmpNodes(x, y);
  531. return res == -2 ? res : -res;
  532. }
  533. #endif
  534. #define SORT_CMP(x, y) (wrap_cmp(x, y))
  535. #include "timsort.h"
  536. #endif /* WITH_TIM_SORT */
  537. /************************************************************************
  538. * *
  539. * Error handling routines *
  540. * *
  541. ************************************************************************/
  542. /**
  543. * XP_ERRORNULL:
  544. * @X: the error code
  545. *
  546. * Macro to raise an XPath error and return NULL.
  547. */
  548. #define XP_ERRORNULL(X) \
  549. { xmlXPathErr(ctxt, X); return(NULL); }
  550. /*
  551. * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
  552. */
  553. static const char* const xmlXPathErrorMessages[] = {
  554. "Ok\n",
  555. "Number encoding\n",
  556. "Unfinished literal\n",
  557. "Start of literal\n",
  558. "Expected $ for variable reference\n",
  559. "Undefined variable\n",
  560. "Invalid predicate\n",
  561. "Invalid expression\n",
  562. "Missing closing curly brace\n",
  563. "Unregistered function\n",
  564. "Invalid operand\n",
  565. "Invalid type\n",
  566. "Invalid number of arguments\n",
  567. "Invalid context size\n",
  568. "Invalid context position\n",
  569. "Memory allocation error\n",
  570. "Syntax error\n",
  571. "Resource error\n",
  572. "Sub resource error\n",
  573. "Undefined namespace prefix\n",
  574. "Encoding error\n",
  575. "Char out of XML range\n",
  576. "Invalid or incomplete context\n",
  577. "Stack usage error\n",
  578. "Forbidden variable\n",
  579. "Operation limit exceeded\n",
  580. "Recursion limit exceeded\n",
  581. "?? Unknown error ??\n" /* Must be last in the list! */
  582. };
  583. #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
  584. sizeof(xmlXPathErrorMessages[0])) - 1)
  585. /**
  586. * xmlXPathErrMemory:
  587. * @ctxt: an XPath context
  588. * @extra: extra information
  589. *
  590. * Handle a redefinition of attribute error
  591. */
  592. static void
  593. xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
  594. {
  595. if (ctxt != NULL) {
  596. xmlResetError(&ctxt->lastError);
  597. if (extra) {
  598. xmlChar buf[200];
  599. xmlStrPrintf(buf, 200,
  600. "Memory allocation failed : %s\n",
  601. extra);
  602. ctxt->lastError.message = (char *) xmlStrdup(buf);
  603. } else {
  604. ctxt->lastError.message = (char *)
  605. xmlStrdup(BAD_CAST "Memory allocation failed\n");
  606. }
  607. ctxt->lastError.domain = XML_FROM_XPATH;
  608. ctxt->lastError.code = XML_ERR_NO_MEMORY;
  609. if (ctxt->error != NULL)
  610. ctxt->error(ctxt->userData, &ctxt->lastError);
  611. } else {
  612. if (extra)
  613. __xmlRaiseError(NULL, NULL, NULL,
  614. NULL, NULL, XML_FROM_XPATH,
  615. XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
  616. extra, NULL, NULL, 0, 0,
  617. "Memory allocation failed : %s\n", extra);
  618. else
  619. __xmlRaiseError(NULL, NULL, NULL,
  620. NULL, NULL, XML_FROM_XPATH,
  621. XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
  622. NULL, NULL, NULL, 0, 0,
  623. "Memory allocation failed\n");
  624. }
  625. }
  626. /**
  627. * xmlXPathPErrMemory:
  628. * @ctxt: an XPath parser context
  629. * @extra: extra information
  630. *
  631. * Handle a redefinition of attribute error
  632. */
  633. static void
  634. xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
  635. {
  636. if (ctxt == NULL)
  637. xmlXPathErrMemory(NULL, extra);
  638. else {
  639. ctxt->error = XPATH_MEMORY_ERROR;
  640. xmlXPathErrMemory(ctxt->context, extra);
  641. }
  642. }
  643. /**
  644. * xmlXPathErr:
  645. * @ctxt: a XPath parser context
  646. * @error: the error code
  647. *
  648. * Handle an XPath error
  649. */
  650. void
  651. xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
  652. {
  653. if ((error < 0) || (error > MAXERRNO))
  654. error = MAXERRNO;
  655. if (ctxt == NULL) {
  656. __xmlRaiseError(NULL, NULL, NULL,
  657. NULL, NULL, XML_FROM_XPATH,
  658. error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
  659. XML_ERR_ERROR, NULL, 0,
  660. NULL, NULL, NULL, 0, 0,
  661. "%s", xmlXPathErrorMessages[error]);
  662. return;
  663. }
  664. /* Only report the first error */
  665. if (ctxt->error != 0)
  666. return;
  667. ctxt->error = error;
  668. if (ctxt->context == NULL) {
  669. __xmlRaiseError(NULL, NULL, NULL,
  670. NULL, NULL, XML_FROM_XPATH,
  671. error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
  672. XML_ERR_ERROR, NULL, 0,
  673. (const char *) ctxt->base, NULL, NULL,
  674. ctxt->cur - ctxt->base, 0,
  675. "%s", xmlXPathErrorMessages[error]);
  676. return;
  677. }
  678. /* cleanup current last error */
  679. xmlResetError(&ctxt->context->lastError);
  680. ctxt->context->lastError.domain = XML_FROM_XPATH;
  681. ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
  682. XPATH_EXPRESSION_OK;
  683. ctxt->context->lastError.level = XML_ERR_ERROR;
  684. ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
  685. ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
  686. ctxt->context->lastError.node = ctxt->context->debugNode;
  687. if (ctxt->context->error != NULL) {
  688. ctxt->context->error(ctxt->context->userData,
  689. &ctxt->context->lastError);
  690. } else {
  691. __xmlRaiseError(NULL, NULL, NULL,
  692. NULL, ctxt->context->debugNode, XML_FROM_XPATH,
  693. error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
  694. XML_ERR_ERROR, NULL, 0,
  695. (const char *) ctxt->base, NULL, NULL,
  696. ctxt->cur - ctxt->base, 0,
  697. "%s", xmlXPathErrorMessages[error]);
  698. }
  699. }
  700. /**
  701. * xmlXPatherror:
  702. * @ctxt: the XPath Parser context
  703. * @file: the file name
  704. * @line: the line number
  705. * @no: the error number
  706. *
  707. * Formats an error message.
  708. */
  709. void
  710. xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
  711. int line ATTRIBUTE_UNUSED, int no) {
  712. xmlXPathErr(ctxt, no);
  713. }
  714. /**
  715. * xmlXPathCheckOpLimit:
  716. * @ctxt: the XPath Parser context
  717. * @opCount: the number of operations to be added
  718. *
  719. * Adds opCount to the running total of operations and returns -1 if the
  720. * operation limit is exceeded. Returns 0 otherwise.
  721. */
  722. static int
  723. xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
  724. xmlXPathContextPtr xpctxt = ctxt->context;
  725. if ((opCount > xpctxt->opLimit) ||
  726. (xpctxt->opCount > xpctxt->opLimit - opCount)) {
  727. xpctxt->opCount = xpctxt->opLimit;
  728. xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
  729. return(-1);
  730. }
  731. xpctxt->opCount += opCount;
  732. return(0);
  733. }
  734. #define OP_LIMIT_EXCEEDED(ctxt, n) \
  735. ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
  736. /************************************************************************
  737. * *
  738. * Utilities *
  739. * *
  740. ************************************************************************/
  741. /**
  742. * xsltPointerList:
  743. *
  744. * Pointer-list for various purposes.
  745. */
  746. typedef struct _xmlPointerList xmlPointerList;
  747. typedef xmlPointerList *xmlPointerListPtr;
  748. struct _xmlPointerList {
  749. void **items;
  750. int number;
  751. int size;
  752. };
  753. /*
  754. * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
  755. * and here, we should make the functions public.
  756. */
  757. static int
  758. xmlPointerListAddSize(xmlPointerListPtr list,
  759. void *item,
  760. int initialSize)
  761. {
  762. if (list->size <= list->number) {
  763. void **tmp;
  764. size_t newSize;
  765. if (list->size == 0) {
  766. if (initialSize <= 0)
  767. initialSize = 1;
  768. newSize = initialSize;
  769. } else {
  770. if (list->size > 50000000) {
  771. xmlXPathErrMemory(NULL,
  772. "xmlPointerListAddSize: re-allocating item\n");
  773. return(-1);
  774. }
  775. newSize = list->size * 2;
  776. }
  777. tmp = (void **) xmlRealloc(list->items, newSize * sizeof(void *));
  778. if (tmp == NULL) {
  779. xmlXPathErrMemory(NULL,
  780. "xmlPointerListAddSize: re-allocating item\n");
  781. return(-1);
  782. }
  783. list->items = tmp;
  784. list->size = newSize;
  785. }
  786. list->items[list->number++] = item;
  787. return(0);
  788. }
  789. /**
  790. * xsltPointerListCreate:
  791. *
  792. * Creates an xsltPointerList structure.
  793. *
  794. * Returns a xsltPointerList structure or NULL in case of an error.
  795. */
  796. static xmlPointerListPtr
  797. xmlPointerListCreate(int initialSize)
  798. {
  799. xmlPointerListPtr ret;
  800. ret = xmlMalloc(sizeof(xmlPointerList));
  801. if (ret == NULL) {
  802. xmlXPathErrMemory(NULL,
  803. "xmlPointerListCreate: allocating item\n");
  804. return (NULL);
  805. }
  806. memset(ret, 0, sizeof(xmlPointerList));
  807. if (initialSize > 0) {
  808. xmlPointerListAddSize(ret, NULL, initialSize);
  809. ret->number = 0;
  810. }
  811. return (ret);
  812. }
  813. /**
  814. * xsltPointerListFree:
  815. *
  816. * Frees the xsltPointerList structure. This does not free
  817. * the content of the list.
  818. */
  819. static void
  820. xmlPointerListFree(xmlPointerListPtr list)
  821. {
  822. if (list == NULL)
  823. return;
  824. if (list->items != NULL)
  825. xmlFree(list->items);
  826. xmlFree(list);
  827. }
  828. /************************************************************************
  829. * *
  830. * Parser Types *
  831. * *
  832. ************************************************************************/
  833. /*
  834. * Types are private:
  835. */
  836. typedef enum {
  837. XPATH_OP_END=0,
  838. XPATH_OP_AND,
  839. XPATH_OP_OR,
  840. XPATH_OP_EQUAL,
  841. XPATH_OP_CMP,
  842. XPATH_OP_PLUS,
  843. XPATH_OP_MULT,
  844. XPATH_OP_UNION,
  845. XPATH_OP_ROOT,
  846. XPATH_OP_NODE,
  847. XPATH_OP_COLLECT,
  848. XPATH_OP_VALUE, /* 11 */
  849. XPATH_OP_VARIABLE,
  850. XPATH_OP_FUNCTION,
  851. XPATH_OP_ARG,
  852. XPATH_OP_PREDICATE,
  853. XPATH_OP_FILTER, /* 16 */
  854. XPATH_OP_SORT /* 17 */
  855. #ifdef LIBXML_XPTR_LOCS_ENABLED
  856. ,XPATH_OP_RANGETO
  857. #endif
  858. } xmlXPathOp;
  859. typedef enum {
  860. AXIS_ANCESTOR = 1,
  861. AXIS_ANCESTOR_OR_SELF,
  862. AXIS_ATTRIBUTE,
  863. AXIS_CHILD,
  864. AXIS_DESCENDANT,
  865. AXIS_DESCENDANT_OR_SELF,
  866. AXIS_FOLLOWING,
  867. AXIS_FOLLOWING_SIBLING,
  868. AXIS_NAMESPACE,
  869. AXIS_PARENT,
  870. AXIS_PRECEDING,
  871. AXIS_PRECEDING_SIBLING,
  872. AXIS_SELF
  873. } xmlXPathAxisVal;
  874. typedef enum {
  875. NODE_TEST_NONE = 0,
  876. NODE_TEST_TYPE = 1,
  877. NODE_TEST_PI = 2,
  878. NODE_TEST_ALL = 3,
  879. NODE_TEST_NS = 4,
  880. NODE_TEST_NAME = 5
  881. } xmlXPathTestVal;
  882. typedef enum {
  883. NODE_TYPE_NODE = 0,
  884. NODE_TYPE_COMMENT = XML_COMMENT_NODE,
  885. NODE_TYPE_TEXT = XML_TEXT_NODE,
  886. NODE_TYPE_PI = XML_PI_NODE
  887. } xmlXPathTypeVal;
  888. typedef struct _xmlXPathStepOp xmlXPathStepOp;
  889. typedef xmlXPathStepOp *xmlXPathStepOpPtr;
  890. struct _xmlXPathStepOp {
  891. xmlXPathOp op; /* The identifier of the operation */
  892. int ch1; /* First child */
  893. int ch2; /* Second child */
  894. int value;
  895. int value2;
  896. int value3;
  897. void *value4;
  898. void *value5;
  899. xmlXPathFunction cache;
  900. void *cacheURI;
  901. };
  902. struct _xmlXPathCompExpr {
  903. int nbStep; /* Number of steps in this expression */
  904. int maxStep; /* Maximum number of steps allocated */
  905. xmlXPathStepOp *steps; /* ops for computation of this expression */
  906. int last; /* index of last step in expression */
  907. xmlChar *expr; /* the expression being computed */
  908. xmlDictPtr dict; /* the dictionary to use if any */
  909. #ifdef XPATH_STREAMING
  910. xmlPatternPtr stream;
  911. #endif
  912. };
  913. /************************************************************************
  914. * *
  915. * Forward declarations *
  916. * *
  917. ************************************************************************/
  918. static void
  919. xmlXPathFreeValueTree(xmlNodeSetPtr obj);
  920. static void
  921. xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
  922. static int
  923. xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
  924. xmlXPathStepOpPtr op, xmlNodePtr *first);
  925. static int
  926. xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
  927. xmlXPathStepOpPtr op,
  928. int isPredicate);
  929. static void
  930. xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
  931. /************************************************************************
  932. * *
  933. * Parser Type functions *
  934. * *
  935. ************************************************************************/
  936. /**
  937. * xmlXPathNewCompExpr:
  938. *
  939. * Create a new Xpath component
  940. *
  941. * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
  942. */
  943. static xmlXPathCompExprPtr
  944. xmlXPathNewCompExpr(void) {
  945. xmlXPathCompExprPtr cur;
  946. cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
  947. if (cur == NULL) {
  948. xmlXPathErrMemory(NULL, "allocating component\n");
  949. return(NULL);
  950. }
  951. memset(cur, 0, sizeof(xmlXPathCompExpr));
  952. cur->maxStep = 10;
  953. cur->nbStep = 0;
  954. cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
  955. sizeof(xmlXPathStepOp));
  956. if (cur->steps == NULL) {
  957. xmlXPathErrMemory(NULL, "allocating steps\n");
  958. xmlFree(cur);
  959. return(NULL);
  960. }
  961. memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
  962. cur->last = -1;
  963. return(cur);
  964. }
  965. /**
  966. * xmlXPathFreeCompExpr:
  967. * @comp: an XPATH comp
  968. *
  969. * Free up the memory allocated by @comp
  970. */
  971. void
  972. xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
  973. {
  974. xmlXPathStepOpPtr op;
  975. int i;
  976. if (comp == NULL)
  977. return;
  978. if (comp->dict == NULL) {
  979. for (i = 0; i < comp->nbStep; i++) {
  980. op = &comp->steps[i];
  981. if (op->value4 != NULL) {
  982. if (op->op == XPATH_OP_VALUE)
  983. xmlXPathFreeObject(op->value4);
  984. else
  985. xmlFree(op->value4);
  986. }
  987. if (op->value5 != NULL)
  988. xmlFree(op->value5);
  989. }
  990. } else {
  991. for (i = 0; i < comp->nbStep; i++) {
  992. op = &comp->steps[i];
  993. if (op->value4 != NULL) {
  994. if (op->op == XPATH_OP_VALUE)
  995. xmlXPathFreeObject(op->value4);
  996. }
  997. }
  998. xmlDictFree(comp->dict);
  999. }
  1000. if (comp->steps != NULL) {
  1001. xmlFree(comp->steps);
  1002. }
  1003. #ifdef XPATH_STREAMING
  1004. if (comp->stream != NULL) {
  1005. xmlFreePatternList(comp->stream);
  1006. }
  1007. #endif
  1008. if (comp->expr != NULL) {
  1009. xmlFree(comp->expr);
  1010. }
  1011. xmlFree(comp);
  1012. }
  1013. /**
  1014. * xmlXPathCompExprAdd:
  1015. * @comp: the compiled expression
  1016. * @ch1: first child index
  1017. * @ch2: second child index
  1018. * @op: an op
  1019. * @value: the first int value
  1020. * @value2: the second int value
  1021. * @value3: the third int value
  1022. * @value4: the first string value
  1023. * @value5: the second string value
  1024. *
  1025. * Add a step to an XPath Compiled Expression
  1026. *
  1027. * Returns -1 in case of failure, the index otherwise
  1028. */
  1029. static int
  1030. xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
  1031. xmlXPathOp op, int value,
  1032. int value2, int value3, void *value4, void *value5) {
  1033. xmlXPathCompExprPtr comp = ctxt->comp;
  1034. if (comp->nbStep >= comp->maxStep) {
  1035. xmlXPathStepOp *real;
  1036. if (comp->maxStep >= XPATH_MAX_STEPS) {
  1037. xmlXPathPErrMemory(ctxt, "adding step\n");
  1038. return(-1);
  1039. }
  1040. comp->maxStep *= 2;
  1041. real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
  1042. comp->maxStep * sizeof(xmlXPathStepOp));
  1043. if (real == NULL) {
  1044. comp->maxStep /= 2;
  1045. xmlXPathPErrMemory(ctxt, "adding step\n");
  1046. return(-1);
  1047. }
  1048. comp->steps = real;
  1049. }
  1050. comp->last = comp->nbStep;
  1051. comp->steps[comp->nbStep].ch1 = ch1;
  1052. comp->steps[comp->nbStep].ch2 = ch2;
  1053. comp->steps[comp->nbStep].op = op;
  1054. comp->steps[comp->nbStep].value = value;
  1055. comp->steps[comp->nbStep].value2 = value2;
  1056. comp->steps[comp->nbStep].value3 = value3;
  1057. if ((comp->dict != NULL) &&
  1058. ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
  1059. (op == XPATH_OP_COLLECT))) {
  1060. if (value4 != NULL) {
  1061. comp->steps[comp->nbStep].value4 = (xmlChar *)
  1062. (void *)xmlDictLookup(comp->dict, value4, -1);
  1063. xmlFree(value4);
  1064. } else
  1065. comp->steps[comp->nbStep].value4 = NULL;
  1066. if (value5 != NULL) {
  1067. comp->steps[comp->nbStep].value5 = (xmlChar *)
  1068. (void *)xmlDictLookup(comp->dict, value5, -1);
  1069. xmlFree(value5);
  1070. } else
  1071. comp->steps[comp->nbStep].value5 = NULL;
  1072. } else {
  1073. comp->steps[comp->nbStep].value4 = value4;
  1074. comp->steps[comp->nbStep].value5 = value5;
  1075. }
  1076. comp->steps[comp->nbStep].cache = NULL;
  1077. return(comp->nbStep++);
  1078. }
  1079. /**
  1080. * xmlXPathCompSwap:
  1081. * @comp: the compiled expression
  1082. * @op: operation index
  1083. *
  1084. * Swaps 2 operations in the compiled expression
  1085. */
  1086. static void
  1087. xmlXPathCompSwap(xmlXPathStepOpPtr op) {
  1088. int tmp;
  1089. #ifndef LIBXML_THREAD_ENABLED
  1090. /*
  1091. * Since this manipulates possibly shared variables, this is
  1092. * disabled if one detects that the library is used in a multithreaded
  1093. * application
  1094. */
  1095. if (xmlXPathDisableOptimizer)
  1096. return;
  1097. #endif
  1098. tmp = op->ch1;
  1099. op->ch1 = op->ch2;
  1100. op->ch2 = tmp;
  1101. }
  1102. #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
  1103. xmlXPathCompExprAdd(ctxt, (op1), (op2), \
  1104. (op), (val), (val2), (val3), (val4), (val5))
  1105. #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
  1106. xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \
  1107. (op), (val), (val2), (val3), (val4), (val5))
  1108. #define PUSH_LEAVE_EXPR(op, val, val2) \
  1109. xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
  1110. #define PUSH_UNARY_EXPR(op, ch, val, val2) \
  1111. xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
  1112. #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
  1113. xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \
  1114. (val), (val2), 0 ,NULL ,NULL)
  1115. /************************************************************************
  1116. * *
  1117. * XPath object cache structures *
  1118. * *
  1119. ************************************************************************/
  1120. /* #define XP_DEFAULT_CACHE_ON */
  1121. #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
  1122. typedef struct _xmlXPathContextCache xmlXPathContextCache;
  1123. typedef xmlXPathContextCache *xmlXPathContextCachePtr;
  1124. struct _xmlXPathContextCache {
  1125. xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
  1126. xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
  1127. xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
  1128. xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
  1129. xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
  1130. int maxNodeset;
  1131. int maxString;
  1132. int maxBoolean;
  1133. int maxNumber;
  1134. int maxMisc;
  1135. };
  1136. /************************************************************************
  1137. * *
  1138. * Debugging related functions *
  1139. * *
  1140. ************************************************************************/
  1141. #define STRANGE \
  1142. xmlGenericError(xmlGenericErrorContext, \
  1143. "Internal error at %s:%d\n", \
  1144. __FILE__, __LINE__);
  1145. #ifdef LIBXML_DEBUG_ENABLED
  1146. static void
  1147. xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
  1148. int i;
  1149. char shift[100];
  1150. for (i = 0;((i < depth) && (i < 25));i++)
  1151. shift[2 * i] = shift[2 * i + 1] = ' ';
  1152. shift[2 * i] = shift[2 * i + 1] = 0;
  1153. if (cur == NULL) {
  1154. fprintf(output, "%s", shift);
  1155. fprintf(output, "Node is NULL !\n");
  1156. return;
  1157. }
  1158. if ((cur->type == XML_DOCUMENT_NODE) ||
  1159. (cur->type == XML_HTML_DOCUMENT_NODE)) {
  1160. fprintf(output, "%s", shift);
  1161. fprintf(output, " /\n");
  1162. } else if (cur->type == XML_ATTRIBUTE_NODE)
  1163. xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
  1164. else
  1165. xmlDebugDumpOneNode(output, cur, depth);
  1166. }
  1167. static void
  1168. xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
  1169. xmlNodePtr tmp;
  1170. int i;
  1171. char shift[100];
  1172. for (i = 0;((i < depth) && (i < 25));i++)
  1173. shift[2 * i] = shift[2 * i + 1] = ' ';
  1174. shift[2 * i] = shift[2 * i + 1] = 0;
  1175. if (cur == NULL) {
  1176. fprintf(output, "%s", shift);
  1177. fprintf(output, "Node is NULL !\n");
  1178. return;
  1179. }
  1180. while (cur != NULL) {
  1181. tmp = cur;
  1182. cur = cur->next;
  1183. xmlDebugDumpOneNode(output, tmp, depth);
  1184. }
  1185. }
  1186. static void
  1187. xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
  1188. int i;
  1189. char shift[100];
  1190. for (i = 0;((i < depth) && (i < 25));i++)
  1191. shift[2 * i] = shift[2 * i + 1] = ' ';
  1192. shift[2 * i] = shift[2 * i + 1] = 0;
  1193. if (cur == NULL) {
  1194. fprintf(output, "%s", shift);
  1195. fprintf(output, "NodeSet is NULL !\n");
  1196. return;
  1197. }
  1198. if (cur != NULL) {
  1199. fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
  1200. for (i = 0;i < cur->nodeNr;i++) {
  1201. fprintf(output, "%s", shift);
  1202. fprintf(output, "%d", i + 1);
  1203. xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
  1204. }
  1205. }
  1206. }
  1207. static void
  1208. xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
  1209. int i;
  1210. char shift[100];
  1211. for (i = 0;((i < depth) && (i < 25));i++)
  1212. shift[2 * i] = shift[2 * i + 1] = ' ';
  1213. shift[2 * i] = shift[2 * i + 1] = 0;
  1214. if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
  1215. fprintf(output, "%s", shift);
  1216. fprintf(output, "Value Tree is NULL !\n");
  1217. return;
  1218. }
  1219. fprintf(output, "%s", shift);
  1220. fprintf(output, "%d", i + 1);
  1221. xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
  1222. }
  1223. #if defined(LIBXML_XPTR_LOCS_ENABLED)
  1224. static void
  1225. xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
  1226. int i;
  1227. char shift[100];
  1228. for (i = 0;((i < depth) && (i < 25));i++)
  1229. shift[2 * i] = shift[2 * i + 1] = ' ';
  1230. shift[2 * i] = shift[2 * i + 1] = 0;
  1231. if (cur == NULL) {
  1232. fprintf(output, "%s", shift);
  1233. fprintf(output, "LocationSet is NULL !\n");
  1234. return;
  1235. }
  1236. for (i = 0;i < cur->locNr;i++) {
  1237. fprintf(output, "%s", shift);
  1238. fprintf(output, "%d : ", i + 1);
  1239. xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
  1240. }
  1241. }
  1242. #endif /* LIBXML_XPTR_LOCS_ENABLED */
  1243. /**
  1244. * xmlXPathDebugDumpObject:
  1245. * @output: the FILE * to dump the output
  1246. * @cur: the object to inspect
  1247. * @depth: indentation level
  1248. *
  1249. * Dump the content of the object for debugging purposes
  1250. */
  1251. void
  1252. xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
  1253. int i;
  1254. char shift[100];
  1255. if (output == NULL) return;
  1256. for (i = 0;((i < depth) && (i < 25));i++)
  1257. shift[2 * i] = shift[2 * i + 1] = ' ';
  1258. shift[2 * i] = shift[2 * i + 1] = 0;
  1259. fprintf(output, "%s", shift);
  1260. if (cur == NULL) {
  1261. fprintf(output, "Object is empty (NULL)\n");
  1262. return;
  1263. }
  1264. switch(cur->type) {
  1265. case XPATH_UNDEFINED:
  1266. fprintf(output, "Object is uninitialized\n");
  1267. break;
  1268. case XPATH_NODESET:
  1269. fprintf(output, "Object is a Node Set :\n");
  1270. xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
  1271. break;
  1272. case XPATH_XSLT_TREE:
  1273. fprintf(output, "Object is an XSLT value tree :\n");
  1274. xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
  1275. break;
  1276. case XPATH_BOOLEAN:
  1277. fprintf(output, "Object is a Boolean : ");
  1278. if (cur->boolval) fprintf(output, "true\n");
  1279. else fprintf(output, "false\n");
  1280. break;
  1281. case XPATH_NUMBER:
  1282. switch (xmlXPathIsInf(cur->floatval)) {
  1283. case 1:
  1284. fprintf(output, "Object is a number : Infinity\n");
  1285. break;
  1286. case -1:
  1287. fprintf(output, "Object is a number : -Infinity\n");
  1288. break;
  1289. default:
  1290. if (xmlXPathIsNaN(cur->floatval)) {
  1291. fprintf(output, "Object is a number : NaN\n");
  1292. } else if (cur->floatval == 0) {
  1293. /* Omit sign for negative zero. */
  1294. fprintf(output, "Object is a number : 0\n");
  1295. } else {
  1296. fprintf(output, "Object is a number : %0g\n", cur->floatval);
  1297. }
  1298. }
  1299. break;
  1300. case XPATH_STRING:
  1301. fprintf(output, "Object is a string : ");
  1302. xmlDebugDumpString(output, cur->stringval);
  1303. fprintf(output, "\n");
  1304. break;
  1305. #ifdef LIBXML_XPTR_LOCS_ENABLED
  1306. case XPATH_POINT:
  1307. fprintf(output, "Object is a point : index %d in node", cur->index);
  1308. xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
  1309. fprintf(output, "\n");
  1310. break;
  1311. case XPATH_RANGE:
  1312. if ((cur->user2 == NULL) ||
  1313. ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
  1314. fprintf(output, "Object is a collapsed range :\n");
  1315. fprintf(output, "%s", shift);
  1316. if (cur->index >= 0)
  1317. fprintf(output, "index %d in ", cur->index);
  1318. fprintf(output, "node\n");
  1319. xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
  1320. depth + 1);
  1321. } else {
  1322. fprintf(output, "Object is a range :\n");
  1323. fprintf(output, "%s", shift);
  1324. fprintf(output, "From ");
  1325. if (cur->index >= 0)
  1326. fprintf(output, "index %d in ", cur->index);
  1327. fprintf(output, "node\n");
  1328. xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
  1329. depth + 1);
  1330. fprintf(output, "%s", shift);
  1331. fprintf(output, "To ");
  1332. if (cur->index2 >= 0)
  1333. fprintf(output, "index %d in ", cur->index2);
  1334. fprintf(output, "node\n");
  1335. xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
  1336. depth + 1);
  1337. fprintf(output, "\n");
  1338. }
  1339. break;
  1340. case XPATH_LOCATIONSET:
  1341. fprintf(output, "Object is a Location Set:\n");
  1342. xmlXPathDebugDumpLocationSet(output,
  1343. (xmlLocationSetPtr) cur->user, depth);
  1344. break;
  1345. #endif /* LIBXML_XPTR_LOCS_ENABLED */
  1346. case XPATH_USERS:
  1347. fprintf(output, "Object is user defined\n");
  1348. break;
  1349. }
  1350. }
  1351. static void
  1352. xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
  1353. xmlXPathStepOpPtr op, int depth) {
  1354. int i;
  1355. char shift[100];
  1356. for (i = 0;((i < depth) && (i < 25));i++)
  1357. shift[2 * i] = shift[2 * i + 1] = ' ';
  1358. shift[2 * i] = shift[2 * i + 1] = 0;
  1359. fprintf(output, "%s", shift);
  1360. if (op == NULL) {
  1361. fprintf(output, "Step is NULL\n");
  1362. return;
  1363. }
  1364. switch (op->op) {
  1365. case XPATH_OP_END:
  1366. fprintf(output, "END"); break;
  1367. case XPATH_OP_AND:
  1368. fprintf(output, "AND"); break;
  1369. case XPATH_OP_OR:
  1370. fprintf(output, "OR"); break;
  1371. case XPATH_OP_EQUAL:
  1372. if (op->value)
  1373. fprintf(output, "EQUAL =");
  1374. else
  1375. fprintf(output, "EQUAL !=");
  1376. break;
  1377. case XPATH_OP_CMP:
  1378. if (op->value)
  1379. fprintf(output, "CMP <");
  1380. else
  1381. fprintf(output, "CMP >");
  1382. if (!op->value2)
  1383. fprintf(output, "=");
  1384. break;
  1385. case XPATH_OP_PLUS:
  1386. if (op->value == 0)
  1387. fprintf(output, "PLUS -");
  1388. else if (op->value == 1)
  1389. fprintf(output, "PLUS +");
  1390. else if (op->value == 2)
  1391. fprintf(output, "PLUS unary -");
  1392. else if (op->value == 3)
  1393. fprintf(output, "PLUS unary - -");
  1394. break;
  1395. case XPATH_OP_MULT:
  1396. if (op->value == 0)
  1397. fprintf(output, "MULT *");
  1398. else if (op->value == 1)
  1399. fprintf(output, "MULT div");
  1400. else
  1401. fprintf(output, "MULT mod");
  1402. break;
  1403. case XPATH_OP_UNION:
  1404. fprintf(output, "UNION"); break;
  1405. case XPATH_OP_ROOT:
  1406. fprintf(output, "ROOT"); break;
  1407. case XPATH_OP_NODE:
  1408. fprintf(output, "NODE"); break;
  1409. case XPATH_OP_SORT:
  1410. fprintf(output, "SORT"); break;
  1411. case XPATH_OP_COLLECT: {
  1412. xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
  1413. xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
  1414. xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
  1415. const xmlChar *prefix = op->value4;
  1416. const xmlChar *name = op->value5;
  1417. fprintf(output, "COLLECT ");
  1418. switch (axis) {
  1419. case AXIS_ANCESTOR:
  1420. fprintf(output, " 'ancestors' "); break;
  1421. case AXIS_ANCESTOR_OR_SELF:
  1422. fprintf(output, " 'ancestors-or-self' "); break;
  1423. case AXIS_ATTRIBUTE:
  1424. fprintf(output, " 'attributes' "); break;
  1425. case AXIS_CHILD:
  1426. fprintf(output, " 'child' "); break;
  1427. case AXIS_DESCENDANT:
  1428. fprintf(output, " 'descendant' "); break;
  1429. case AXIS_DESCENDANT_OR_SELF:
  1430. fprintf(output, " 'descendant-or-self' "); break;
  1431. case AXIS_FOLLOWING:
  1432. fprintf(output, " 'following' "); break;
  1433. case AXIS_FOLLOWING_SIBLING:
  1434. fprintf(output, " 'following-siblings' "); break;
  1435. case AXIS_NAMESPACE:
  1436. fprintf(output, " 'namespace' "); break;
  1437. case AXIS_PARENT:
  1438. fprintf(output, " 'parent' "); break;
  1439. case AXIS_PRECEDING:
  1440. fprintf(output, " 'preceding' "); break;
  1441. case AXIS_PRECEDING_SIBLING:
  1442. fprintf(output, " 'preceding-sibling' "); break;
  1443. case AXIS_SELF:
  1444. fprintf(output, " 'self' "); break;
  1445. }
  1446. switch (test) {
  1447. case NODE_TEST_NONE:
  1448. fprintf(output, "'none' "); break;
  1449. case NODE_TEST_TYPE:
  1450. fprintf(output, "'type' "); break;
  1451. case NODE_TEST_PI:
  1452. fprintf(output, "'PI' "); break;
  1453. case NODE_TEST_ALL:
  1454. fprintf(output, "'all' "); break;
  1455. case NODE_TEST_NS:
  1456. fprintf(output, "'namespace' "); break;
  1457. case NODE_TEST_NAME:
  1458. fprintf(output, "'name' "); break;
  1459. }
  1460. switch (type) {
  1461. case NODE_TYPE_NODE:
  1462. fprintf(output, "'node' "); break;
  1463. case NODE_TYPE_COMMENT:
  1464. fprintf(output, "'comment' "); break;
  1465. case NODE_TYPE_TEXT:
  1466. fprintf(output, "'text' "); break;
  1467. case NODE_TYPE_PI:
  1468. fprintf(output, "'PI' "); break;
  1469. }
  1470. if (prefix != NULL)
  1471. fprintf(output, "%s:", prefix);
  1472. if (name != NULL)
  1473. fprintf(output, "%s", (const char *) name);
  1474. break;
  1475. }
  1476. case XPATH_OP_VALUE: {
  1477. xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
  1478. fprintf(output, "ELEM ");
  1479. xmlXPathDebugDumpObject(output, object, 0);
  1480. goto finish;
  1481. }
  1482. case XPATH_OP_VARIABLE: {
  1483. const xmlChar *prefix = op->value5;
  1484. const xmlChar *name = op->value4;
  1485. if (prefix != NULL)
  1486. fprintf(output, "VARIABLE %s:%s", prefix, name);
  1487. else
  1488. fprintf(output, "VARIABLE %s", name);
  1489. break;
  1490. }
  1491. case XPATH_OP_FUNCTION: {
  1492. int nbargs = op->value;
  1493. const xmlChar *prefix = op->value5;
  1494. const xmlChar *name = op->value4;
  1495. if (prefix != NULL)
  1496. fprintf(output, "FUNCTION %s:%s(%d args)",
  1497. prefix, name, nbargs);
  1498. else
  1499. fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
  1500. break;
  1501. }
  1502. case XPATH_OP_ARG: fprintf(output, "ARG"); break;
  1503. case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
  1504. case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
  1505. #ifdef LIBXML_XPTR_LOCS_ENABLED
  1506. case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
  1507. #endif
  1508. default:
  1509. fprintf(output, "UNKNOWN %d\n", op->op); return;
  1510. }
  1511. fprintf(output, "\n");
  1512. finish:
  1513. if (op->ch1 >= 0)
  1514. xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
  1515. if (op->ch2 >= 0)
  1516. xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
  1517. }
  1518. /**
  1519. * xmlXPathDebugDumpCompExpr:
  1520. * @output: the FILE * for the output
  1521. * @comp: the precompiled XPath expression
  1522. * @depth: the indentation level.
  1523. *
  1524. * Dumps the tree of the compiled XPath expression.
  1525. */
  1526. void
  1527. xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
  1528. int depth) {
  1529. int i;
  1530. char shift[100];
  1531. if ((output == NULL) || (comp == NULL)) return;
  1532. for (i = 0;((i < depth) && (i < 25));i++)
  1533. shift[2 * i] = shift[2 * i + 1] = ' ';
  1534. shift[2 * i] = shift[2 * i + 1] = 0;
  1535. fprintf(output, "%s", shift);
  1536. #ifdef XPATH_STREAMING
  1537. if (comp->stream) {
  1538. fprintf(output, "Streaming Expression\n");
  1539. } else
  1540. #endif
  1541. {
  1542. fprintf(output, "Compiled Expression : %d elements\n",
  1543. comp->nbStep);
  1544. i = comp->last;
  1545. xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
  1546. }
  1547. }
  1548. #endif /* LIBXML_DEBUG_ENABLED */
  1549. /************************************************************************
  1550. * *
  1551. * XPath object caching *
  1552. * *
  1553. ************************************************************************/
  1554. /**
  1555. * xmlXPathNewCache:
  1556. *
  1557. * Create a new object cache
  1558. *
  1559. * Returns the xmlXPathCache just allocated.
  1560. */
  1561. static xmlXPathContextCachePtr
  1562. xmlXPathNewCache(void)
  1563. {
  1564. xmlXPathContextCachePtr ret;
  1565. ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
  1566. if (ret == NULL) {
  1567. xmlXPathErrMemory(NULL, "creating object cache\n");
  1568. return(NULL);
  1569. }
  1570. memset(ret, 0 , sizeof(xmlXPathContextCache));
  1571. ret->maxNodeset = 100;
  1572. ret->maxString = 100;
  1573. ret->maxBoolean = 100;
  1574. ret->maxNumber = 100;
  1575. ret->maxMisc = 100;
  1576. return(ret);
  1577. }
  1578. static void
  1579. xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
  1580. {
  1581. int i;
  1582. xmlXPathObjectPtr obj;
  1583. if (list == NULL)
  1584. return;
  1585. for (i = 0; i < list->number; i++) {
  1586. obj = list->items[i];
  1587. /*
  1588. * Note that it is already assured that we don't need to
  1589. * look out for namespace nodes in the node-set.
  1590. */
  1591. if (obj->nodesetval != NULL) {
  1592. if (obj->nodesetval->nodeTab != NULL)
  1593. xmlFree(obj->nodesetval->nodeTab);
  1594. xmlFree(obj->nodesetval);
  1595. }
  1596. xmlFree(obj);
  1597. }
  1598. xmlPointerListFree(list);
  1599. }
  1600. static void
  1601. xmlXPathFreeCache(xmlXPathContextCachePtr cache)
  1602. {
  1603. if (cache == NULL)
  1604. return;
  1605. if (cache->nodesetObjs)
  1606. xmlXPathCacheFreeObjectList(cache->nodesetObjs);
  1607. if (cache->stringObjs)
  1608. xmlXPathCacheFreeObjectList(cache->stringObjs);
  1609. if (cache->booleanObjs)
  1610. xmlXPathCacheFreeObjectList(cache->booleanObjs);
  1611. if (cache->numberObjs)
  1612. xmlXPathCacheFreeObjectList(cache->numberObjs);
  1613. if (cache->miscObjs)
  1614. xmlXPathCacheFreeObjectList(cache->miscObjs);
  1615. xmlFree(cache);
  1616. }
  1617. /**
  1618. * xmlXPathContextSetCache:
  1619. *
  1620. * @ctxt: the XPath context
  1621. * @active: enables/disables (creates/frees) the cache
  1622. * @value: a value with semantics dependent on @options
  1623. * @options: options (currently only the value 0 is used)
  1624. *
  1625. * Creates/frees an object cache on the XPath context.
  1626. * If activates XPath objects (xmlXPathObject) will be cached internally
  1627. * to be reused.
  1628. * @options:
  1629. * 0: This will set the XPath object caching:
  1630. * @value:
  1631. * This will set the maximum number of XPath objects
  1632. * to be cached per slot
  1633. * There are 5 slots for: node-set, string, number, boolean, and
  1634. * misc objects. Use <0 for the default number (100).
  1635. * Other values for @options have currently no effect.
  1636. *
  1637. * Returns 0 if the setting succeeded, and -1 on API or internal errors.
  1638. */
  1639. int
  1640. xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
  1641. int active,
  1642. int value,
  1643. int options)
  1644. {
  1645. if (ctxt == NULL)
  1646. return(-1);
  1647. if (active) {
  1648. xmlXPathContextCachePtr cache;
  1649. if (ctxt->cache == NULL) {
  1650. ctxt->cache = xmlXPathNewCache();
  1651. if (ctxt->cache == NULL)
  1652. return(-1);
  1653. }
  1654. cache = (xmlXPathContextCachePtr) ctxt->cache;
  1655. if (options == 0) {
  1656. if (value < 0)
  1657. value = 100;
  1658. cache->maxNodeset = value;
  1659. cache->maxString = value;
  1660. cache->maxNumber = value;
  1661. cache->maxBoolean = value;
  1662. cache->maxMisc = value;
  1663. }
  1664. } else if (ctxt->cache != NULL) {
  1665. xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
  1666. ctxt->cache = NULL;
  1667. }
  1668. return(0);
  1669. }
  1670. /**
  1671. * xmlXPathCacheWrapNodeSet:
  1672. * @ctxt: the XPath context
  1673. * @val: the NodePtr value
  1674. *
  1675. * This is the cached version of xmlXPathWrapNodeSet().
  1676. * Wrap the Nodeset @val in a new xmlXPathObjectPtr
  1677. *
  1678. * Returns the created or reused object.
  1679. *
  1680. * In case of error the node set is destroyed and NULL is returned.
  1681. */
  1682. static xmlXPathObjectPtr
  1683. xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
  1684. {
  1685. if ((ctxt != NULL) && (ctxt->cache != NULL)) {
  1686. xmlXPathContextCachePtr cache =
  1687. (xmlXPathContextCachePtr) ctxt->cache;
  1688. if ((cache->miscObjs != NULL) &&
  1689. (cache->miscObjs->number != 0))
  1690. {
  1691. xmlXPathObjectPtr ret;
  1692. ret = (xmlXPathObjectPtr)
  1693. cache->miscObjs->items[--cache->miscObjs->number];
  1694. ret->type = XPATH_NODESET;
  1695. ret->nodesetval = val;
  1696. return(ret);
  1697. }
  1698. }
  1699. return(xmlXPathWrapNodeSet(val));
  1700. }
  1701. /**
  1702. * xmlXPathCacheWrapString:
  1703. * @ctxt: the XPath context
  1704. * @val: the xmlChar * value
  1705. *
  1706. * This is the cached version of xmlXPathWrapString().
  1707. * Wraps the @val string into an XPath object.
  1708. *
  1709. * Returns the created or reused object.
  1710. */
  1711. static xmlXPathObjectPtr
  1712. xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
  1713. {
  1714. if ((ctxt != NULL) && (ctxt->cache != NULL)) {
  1715. xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
  1716. if ((cache->stringObjs != NULL) &&
  1717. (cache->stringObjs->number != 0))
  1718. {
  1719. xmlXPathObjectPtr ret;
  1720. ret = (xmlXPathObjectPtr)
  1721. cache->stringObjs->items[--cache->stringObjs->number];
  1722. ret->type = XPATH_STRING;
  1723. ret->stringval = val;
  1724. return(ret);
  1725. } else if ((cache->miscObjs != NULL) &&
  1726. (cache->miscObjs->number != 0))
  1727. {
  1728. xmlXPathObjectPtr ret;
  1729. /*
  1730. * Fallback to misc-cache.
  1731. */
  1732. ret = (xmlXPathObjectPtr)
  1733. cache->miscObjs->items[--cache->miscObjs->number];
  1734. ret->type = XPATH_STRING;
  1735. ret->stringval = val;
  1736. return(ret);
  1737. }
  1738. }
  1739. return(xmlXPathWrapString(val));
  1740. }
  1741. /**
  1742. * xmlXPathCacheNewNodeSet:
  1743. * @ctxt: the XPath context
  1744. * @val: the NodePtr value
  1745. *
  1746. * This is the cached version of xmlXPathNewNodeSet().
  1747. * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
  1748. * it with the single Node @val
  1749. *
  1750. * Returns the created or reused object.
  1751. */
  1752. static xmlXPathObjectPtr
  1753. xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
  1754. {
  1755. if ((ctxt != NULL) && (ctxt->cache)) {
  1756. xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
  1757. if ((cache->nodesetObjs != NULL) &&
  1758. (cache->nodesetObjs->number != 0))
  1759. {
  1760. xmlXPathObjectPtr ret;
  1761. /*
  1762. * Use the nodeset-cache.
  1763. */
  1764. ret = (xmlXPathObjectPtr)
  1765. cache->nodesetObjs->items[--cache->nodesetObjs->number];
  1766. ret->type = XPATH_NODESET;
  1767. ret->boolval = 0;
  1768. if (val) {
  1769. if ((ret->nodesetval->nodeMax == 0) ||
  1770. (val->type == XML_NAMESPACE_DECL))
  1771. {
  1772. /* TODO: Check memory error. */
  1773. xmlXPathNodeSetAddUnique(ret->nodesetval, val);
  1774. } else {
  1775. ret->nodesetval->nodeTab[0] = val;
  1776. ret->nodesetval->nodeNr = 1;
  1777. }
  1778. }
  1779. return(ret);
  1780. } else if ((cache->miscObjs != NULL) &&
  1781. (cache->miscObjs->number != 0))
  1782. {
  1783. xmlXPathObjectPtr ret;
  1784. xmlNodeSetPtr set;
  1785. /*
  1786. * Fallback to misc-cache.
  1787. */
  1788. set = xmlXPathNodeSetCreate(val);
  1789. if (set == NULL) {
  1790. ctxt->lastError.domain = XML_FROM_XPATH;
  1791. ctxt->lastError.code = XML_ERR_NO_MEMORY;
  1792. return(NULL);
  1793. }
  1794. ret = (xmlXPathObjectPtr)
  1795. cache->miscObjs->items[--cache->miscObjs->number];
  1796. ret->type = XPATH_NODESET;
  1797. ret->boolval = 0;
  1798. ret->nodesetval = set;
  1799. return(ret);
  1800. }
  1801. }
  1802. return(xmlXPathNewNodeSet(val));
  1803. }
  1804. /**
  1805. * xmlXPathCacheNewString:
  1806. * @ctxt: the XPath context
  1807. * @val: the xmlChar * value
  1808. *
  1809. * This is the cached version of xmlXPathNewString().
  1810. * Acquire an xmlXPathObjectPtr of type string and of value @val
  1811. *
  1812. * Returns the created or reused object.
  1813. */
  1814. static xmlXPathObjectPtr
  1815. xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
  1816. {
  1817. if ((ctxt != NULL) && (ctxt->cache)) {
  1818. xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
  1819. if ((cache->stringObjs != NULL) &&
  1820. (cache->stringObjs->number != 0))
  1821. {
  1822. xmlXPathObjectPtr ret;
  1823. xmlChar *copy;
  1824. if (val == NULL)
  1825. val = BAD_CAST "";
  1826. copy = xmlStrdup(val);
  1827. if (copy == NULL) {
  1828. xmlXPathErrMemory(ctxt, NULL);
  1829. return(NULL);
  1830. }
  1831. ret = (xmlXPathObjectPtr)
  1832. cache->stringObjs->items[--cache->stringObjs->number];
  1833. ret->type = XPATH_STRING;
  1834. ret->stringval = copy;
  1835. return(ret);
  1836. } else if ((cache->miscObjs != NULL) &&
  1837. (cache->miscObjs->number != 0))
  1838. {
  1839. xmlXPathObjectPtr ret;
  1840. xmlChar *copy;
  1841. if (val == NULL)
  1842. val = BAD_CAST "";
  1843. copy = xmlStrdup(val);
  1844. if (copy == NULL) {
  1845. xmlXPathErrMemory(ctxt, NULL);
  1846. return(NULL);
  1847. }
  1848. ret = (xmlXPathObjectPtr)
  1849. cache->miscObjs->items[--cache->miscObjs->number];
  1850. ret->type = XPATH_STRING;
  1851. ret->stringval = copy;
  1852. return(ret);
  1853. }
  1854. }
  1855. return(xmlXPathNewString(val));
  1856. }
  1857. /**
  1858. * xmlXPathCacheNewCString:
  1859. * @ctxt: the XPath context
  1860. * @val: the char * value
  1861. *
  1862. * This is the cached version of xmlXPathNewCString().
  1863. * Acquire an xmlXPathObjectPtr of type string and of value @val
  1864. *
  1865. * Returns the created or reused object.
  1866. */
  1867. static xmlXPathObjectPtr
  1868. xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
  1869. {
  1870. return xmlXPathCacheNewString(ctxt, BAD_CAST val);
  1871. }
  1872. /**
  1873. * xmlXPathCacheNewBoolean:
  1874. * @ctxt: the XPath context
  1875. * @val: the boolean value
  1876. *
  1877. * This is the cached version of xmlXPathNewBoolean().
  1878. * Acquires an xmlXPathObjectPtr of type boolean and of value @val
  1879. *
  1880. * Returns the created or reused object.
  1881. */
  1882. static xmlXPathObjectPtr
  1883. xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
  1884. {
  1885. if ((ctxt != NULL) && (ctxt->cache)) {
  1886. xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
  1887. if ((cache->booleanObjs != NULL) &&
  1888. (cache->booleanObjs->number != 0))
  1889. {
  1890. xmlXPathObjectPtr ret;
  1891. ret = (xmlXPathObjectPtr)
  1892. cache->booleanObjs->items[--cache->booleanObjs->number];
  1893. ret->type = XPATH_BOOLEAN;
  1894. ret->boolval = (val != 0);
  1895. return(ret);
  1896. } else if ((cache->miscObjs != NULL) &&
  1897. (cache->miscObjs->number != 0))
  1898. {
  1899. xmlXPathObjectPtr ret;
  1900. ret = (xmlXPathObjectPtr)
  1901. cache->miscObjs->items[--cache->miscObjs->number];
  1902. ret->type = XPATH_BOOLEAN;
  1903. ret->boolval = (val != 0);
  1904. return(ret);
  1905. }
  1906. }
  1907. return(xmlXPathNewBoolean(val));
  1908. }
  1909. /**
  1910. * xmlXPathCacheNewFloat:
  1911. * @ctxt: the XPath context
  1912. * @val: the double value
  1913. *
  1914. * This is the cached version of xmlXPathNewFloat().
  1915. * Acquires an xmlXPathObjectPtr of type double and of value @val
  1916. *
  1917. * Returns the created or reused object.
  1918. */
  1919. static xmlXPathObjectPtr
  1920. xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
  1921. {
  1922. if ((ctxt != NULL) && (ctxt->cache)) {
  1923. xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
  1924. if ((cache->numberObjs != NULL) &&
  1925. (cache->numberObjs->number != 0))
  1926. {
  1927. xmlXPathObjectPtr ret;
  1928. ret = (xmlXPathObjectPtr)
  1929. cache->numberObjs->items[--cache->numberObjs->number];
  1930. ret->type = XPATH_NUMBER;
  1931. ret->floatval = val;
  1932. return(ret);
  1933. } else if ((cache->miscObjs != NULL) &&
  1934. (cache->miscObjs->number != 0))
  1935. {
  1936. xmlXPathObjectPtr ret;
  1937. ret = (xmlXPathObjectPtr)
  1938. cache->miscObjs->items[--cache->miscObjs->number];
  1939. ret->type = XPATH_NUMBER;
  1940. ret->floatval = val;
  1941. return(ret);
  1942. }
  1943. }
  1944. return(xmlXPathNewFloat(val));
  1945. }
  1946. /**
  1947. * xmlXPathCacheConvertString:
  1948. * @ctxt: the XPath context
  1949. * @val: an XPath object
  1950. *
  1951. * This is the cached version of xmlXPathConvertString().
  1952. * Converts an existing object to its string() equivalent
  1953. *
  1954. * Returns a created or reused object, the old one is freed (cached)
  1955. * (or the operation is done directly on @val)
  1956. */
  1957. static xmlXPathObjectPtr
  1958. xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
  1959. xmlChar *res = NULL;
  1960. if (val == NULL)
  1961. return(xmlXPathCacheNewCString(ctxt, ""));
  1962. switch (val->type) {
  1963. case XPATH_UNDEFINED:
  1964. break;
  1965. case XPATH_NODESET:
  1966. case XPATH_XSLT_TREE:
  1967. res = xmlXPathCastNodeSetToString(val->nodesetval);
  1968. break;
  1969. case XPATH_STRING:
  1970. return(val);
  1971. case XPATH_BOOLEAN:
  1972. res = xmlXPathCastBooleanToString(val->boolval);
  1973. break;
  1974. case XPATH_NUMBER:
  1975. res = xmlXPathCastNumberToString(val->floatval);
  1976. break;
  1977. case XPATH_USERS:
  1978. #ifdef LIBXML_XPTR_LOCS_ENABLED
  1979. case XPATH_POINT:
  1980. case XPATH_RANGE:
  1981. case XPATH_LOCATIONSET:
  1982. #endif /* LIBXML_XPTR_LOCS_ENABLED */
  1983. TODO;
  1984. break;
  1985. }
  1986. xmlXPathReleaseObject(ctxt, val);
  1987. if (res == NULL)
  1988. return(xmlXPathCacheNewCString(ctxt, ""));
  1989. return(xmlXPathCacheWrapString(ctxt, res));
  1990. }
  1991. /**
  1992. * xmlXPathCacheObjectCopy:
  1993. * @ctxt: the XPath context
  1994. * @val: the original object
  1995. *
  1996. * This is the cached version of xmlXPathObjectCopy().
  1997. * Acquire a copy of a given object
  1998. *
  1999. * Returns a created or reused created object.
  2000. */
  2001. static xmlXPathObjectPtr
  2002. xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
  2003. {
  2004. if (val == NULL)
  2005. return(NULL);
  2006. if (XP_HAS_CACHE(ctxt)) {
  2007. switch (val->type) {
  2008. case XPATH_NODESET:
  2009. return(xmlXPathCacheWrapNodeSet(ctxt,
  2010. xmlXPathNodeSetMerge(NULL, val->nodesetval)));
  2011. case XPATH_STRING:
  2012. return(xmlXPathCacheNewString(ctxt, val->stringval));
  2013. case XPATH_BOOLEAN:
  2014. return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
  2015. case XPATH_NUMBER:
  2016. return(xmlXPathCacheNewFloat(ctxt, val->floatval));
  2017. default:
  2018. break;
  2019. }
  2020. }
  2021. return(xmlXPathObjectCopy(val));
  2022. }
  2023. /**
  2024. * xmlXPathCacheConvertBoolean:
  2025. * @ctxt: the XPath context
  2026. * @val: an XPath object
  2027. *
  2028. * This is the cached version of xmlXPathConvertBoolean().
  2029. * Converts an existing object to its boolean() equivalent
  2030. *
  2031. * Returns a created or reused object, the old one is freed (or the operation
  2032. * is done directly on @val)
  2033. */
  2034. static xmlXPathObjectPtr
  2035. xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
  2036. xmlXPathObjectPtr ret;
  2037. if (val == NULL)
  2038. return(xmlXPathCacheNewBoolean(ctxt, 0));
  2039. if (val->type == XPATH_BOOLEAN)
  2040. return(val);
  2041. ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
  2042. xmlXPathReleaseObject(ctxt, val);
  2043. return(ret);
  2044. }
  2045. /**
  2046. * xmlXPathCacheConvertNumber:
  2047. * @ctxt: the XPath context
  2048. * @val: an XPath object
  2049. *
  2050. * This is the cached version of xmlXPathConvertNumber().
  2051. * Converts an existing object to its number() equivalent
  2052. *
  2053. * Returns a created or reused object, the old one is freed (or the operation
  2054. * is done directly on @val)
  2055. */
  2056. static xmlXPathObjectPtr
  2057. xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
  2058. xmlXPathObjectPtr ret;
  2059. if (val == NULL)
  2060. return(xmlXPathCacheNewFloat(ctxt, 0.0));
  2061. if (val->type == XPATH_NUMBER)
  2062. return(val);
  2063. ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
  2064. xmlXPathReleaseObject(ctxt, val);
  2065. return(ret);
  2066. }
  2067. /************************************************************************
  2068. * *
  2069. * Parser stacks related functions and macros *
  2070. * *
  2071. ************************************************************************/
  2072. /**
  2073. * valuePop:
  2074. * @ctxt: an XPath evaluation context
  2075. *
  2076. * Pops the top XPath object from the value stack
  2077. *
  2078. * Returns the XPath object just removed
  2079. */
  2080. xmlXPathObjectPtr
  2081. valuePop(xmlXPathParserContextPtr ctxt)
  2082. {
  2083. xmlXPathObjectPtr ret;
  2084. if ((ctxt == NULL) || (ctxt->valueNr <= 0))
  2085. return (NULL);
  2086. ctxt->valueNr--;
  2087. if (ctxt->valueNr > 0)
  2088. ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
  2089. else
  2090. ctxt->value = NULL;
  2091. ret = ctxt->valueTab[ctxt->valueNr];
  2092. ctxt->valueTab[ctxt->valueNr] = NULL;
  2093. return (ret);
  2094. }
  2095. /**
  2096. * valuePush:
  2097. * @ctxt: an XPath evaluation context
  2098. * @value: the XPath object
  2099. *
  2100. * Pushes a new XPath object on top of the value stack. If value is NULL,
  2101. * a memory error is recorded in the parser context.
  2102. *
  2103. * Returns the number of items on the value stack, or -1 in case of error.
  2104. *
  2105. * The object is destroyed in case of error.
  2106. */
  2107. int
  2108. valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
  2109. {
  2110. if (ctxt == NULL) return(-1);
  2111. if (value == NULL) {
  2112. /*
  2113. * A NULL value typically indicates that a memory allocation failed,
  2114. * so we set ctxt->error here to propagate the error.
  2115. */
  2116. ctxt->error = XPATH_MEMORY_ERROR;
  2117. return(-1);
  2118. }
  2119. if (ctxt->valueNr >= ctxt->valueMax) {
  2120. xmlXPathObjectPtr *tmp;
  2121. if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
  2122. xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
  2123. xmlXPathFreeObject(value);
  2124. return (-1);
  2125. }
  2126. tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
  2127. 2 * ctxt->valueMax *
  2128. sizeof(ctxt->valueTab[0]));
  2129. if (tmp == NULL) {
  2130. xmlXPathPErrMemory(ctxt, "pushing value\n");
  2131. xmlXPathFreeObject(value);
  2132. return (-1);
  2133. }
  2134. ctxt->valueMax *= 2;
  2135. ctxt->valueTab = tmp;
  2136. }
  2137. ctxt->valueTab[ctxt->valueNr] = value;
  2138. ctxt->value = value;
  2139. return (ctxt->valueNr++);
  2140. }
  2141. /**
  2142. * xmlXPathPopBoolean:
  2143. * @ctxt: an XPath parser context
  2144. *
  2145. * Pops a boolean from the stack, handling conversion if needed.
  2146. * Check error with #xmlXPathCheckError.
  2147. *
  2148. * Returns the boolean
  2149. */
  2150. int
  2151. xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
  2152. xmlXPathObjectPtr obj;
  2153. int ret;
  2154. obj = valuePop(ctxt);
  2155. if (obj == NULL) {
  2156. xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
  2157. return(0);
  2158. }
  2159. if (obj->type != XPATH_BOOLEAN)
  2160. ret = xmlXPathCastToBoolean(obj);
  2161. else
  2162. ret = obj->boolval;
  2163. xmlXPathReleaseObject(ctxt->context, obj);
  2164. return(ret);
  2165. }
  2166. /**
  2167. * xmlXPathPopNumber:
  2168. * @ctxt: an XPath parser context
  2169. *
  2170. * Pops a number from the stack, handling conversion if needed.
  2171. * Check error with #xmlXPathCheckError.
  2172. *
  2173. * Returns the number
  2174. */
  2175. double
  2176. xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
  2177. xmlXPathObjectPtr obj;
  2178. double ret;
  2179. obj = valuePop(ctxt);
  2180. if (obj == NULL) {
  2181. xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
  2182. return(0);
  2183. }
  2184. if (obj->type != XPATH_NUMBER)
  2185. ret = xmlXPathCastToNumber(obj);
  2186. else
  2187. ret = obj->floatval;
  2188. xmlXPathReleaseObject(ctxt->context, obj);
  2189. return(ret);
  2190. }
  2191. /**
  2192. * xmlXPathPopString:
  2193. * @ctxt: an XPath parser context
  2194. *
  2195. * Pops a string from the stack, handling conversion if needed.
  2196. * Check error with #xmlXPathCheckError.
  2197. *
  2198. * Returns the string
  2199. */
  2200. xmlChar *
  2201. xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
  2202. xmlXPathObjectPtr obj;
  2203. xmlChar * ret;
  2204. obj = valuePop(ctxt);
  2205. if (obj == NULL) {
  2206. xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
  2207. return(NULL);
  2208. }
  2209. ret = xmlXPathCastToString(obj); /* this does required strdup */
  2210. /* TODO: needs refactoring somewhere else */
  2211. if (obj->stringval == ret)
  2212. obj->stringval = NULL;
  2213. xmlXPathReleaseObject(ctxt->context, obj);
  2214. return(ret);
  2215. }
  2216. /**
  2217. * xmlXPathPopNodeSet:
  2218. * @ctxt: an XPath parser context
  2219. *
  2220. * Pops a node-set from the stack, handling conversion if needed.
  2221. * Check error with #xmlXPathCheckError.
  2222. *
  2223. * Returns the node-set
  2224. */
  2225. xmlNodeSetPtr
  2226. xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
  2227. xmlXPathObjectPtr obj;
  2228. xmlNodeSetPtr ret;
  2229. if (ctxt == NULL) return(NULL);
  2230. if (ctxt->value == NULL) {
  2231. xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
  2232. return(NULL);
  2233. }
  2234. if (!xmlXPathStackIsNodeSet(ctxt)) {
  2235. xmlXPathSetTypeError(ctxt);
  2236. return(NULL);
  2237. }
  2238. obj = valuePop(ctxt);
  2239. ret = obj->nodesetval;
  2240. #if 0
  2241. /* to fix memory leak of not clearing obj->user */
  2242. if (obj->boolval && obj->user != NULL)
  2243. xmlFreeNodeList((xmlNodePtr) obj->user);
  2244. #endif
  2245. obj->nodesetval = NULL;
  2246. xmlXPathReleaseObject(ctxt->context, obj);
  2247. return(ret);
  2248. }
  2249. /**
  2250. * xmlXPathPopExternal:
  2251. * @ctxt: an XPath parser context
  2252. *
  2253. * Pops an external object from the stack, handling conversion if needed.
  2254. * Check error with #xmlXPathCheckError.
  2255. *
  2256. * Returns the object
  2257. */
  2258. void *
  2259. xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
  2260. xmlXPathObjectPtr obj;
  2261. void * ret;
  2262. if ((ctxt == NULL) || (ctxt->value == NULL)) {
  2263. xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
  2264. return(NULL);
  2265. }
  2266. if (ctxt->value->type != XPATH_USERS) {
  2267. xmlXPathSetTypeError(ctxt);
  2268. return(NULL);
  2269. }
  2270. obj = valuePop(ctxt);
  2271. ret = obj->user;
  2272. obj->user = NULL;
  2273. xmlXPathReleaseObject(ctxt->context, obj);
  2274. return(ret);
  2275. }
  2276. /*
  2277. * Macros for accessing the content. Those should be used only by the parser,
  2278. * and not exported.
  2279. *
  2280. * Dirty macros, i.e. one need to make assumption on the context to use them
  2281. *
  2282. * CUR_PTR return the current pointer to the xmlChar to be parsed.
  2283. * CUR returns the current xmlChar value, i.e. a 8 bit value
  2284. * in ISO-Latin or UTF-8.
  2285. * This should be used internally by the parser
  2286. * only to compare to ASCII values otherwise it would break when
  2287. * running with UTF-8 encoding.
  2288. * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
  2289. * to compare on ASCII based substring.
  2290. * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
  2291. * strings within the parser.
  2292. * CURRENT Returns the current char value, with the full decoding of
  2293. * UTF-8 if we are using this mode. It returns an int.
  2294. * NEXT Skip to the next character, this does the proper decoding
  2295. * in UTF-8 mode. It also pop-up unfinished entities on the fly.
  2296. * It returns the pointer to the current xmlChar.
  2297. */
  2298. #define CUR (*ctxt->cur)
  2299. #define SKIP(val) ctxt->cur += (val)
  2300. #define NXT(val) ctxt->cur[(val)]
  2301. #define CUR_PTR ctxt->cur
  2302. #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
  2303. #define COPY_BUF(l,b,i,v) \
  2304. if (l == 1) b[i++] = v; \
  2305. else i += xmlCopyChar(l,&b[i],v)
  2306. #define NEXTL(l) ctxt->cur += l
  2307. #define SKIP_BLANKS \
  2308. while (IS_BLANK_CH(*(ctxt->cur))) NEXT
  2309. #define CURRENT (*ctxt->cur)
  2310. #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
  2311. #ifndef DBL_DIG
  2312. #define DBL_DIG 16
  2313. #endif
  2314. #ifndef DBL_EPSILON
  2315. #define DBL_EPSILON 1E-9
  2316. #endif
  2317. #define UPPER_DOUBLE 1E9
  2318. #define LOWER_DOUBLE 1E-5
  2319. #define LOWER_DOUBLE_EXP 5
  2320. #define INTEGER_DIGITS DBL_DIG
  2321. #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
  2322. #define EXPONENT_DIGITS (3 + 2)
  2323. /**
  2324. * xmlXPathFormatNumber:
  2325. * @number: number to format
  2326. * @buffer: output buffer
  2327. * @buffersize: size of output buffer
  2328. *
  2329. * Convert the number into a string representation.
  2330. */
  2331. static void
  2332. xmlXPathFormatNumber(double number, char buffer[], int buffersize)
  2333. {
  2334. switch (xmlXPathIsInf(number)) {
  2335. case 1:
  2336. if (buffersize > (int)sizeof("Infinity"))
  2337. snprintf(buffer, buffersize, "Infinity");
  2338. break;
  2339. case -1:
  2340. if (buffersize > (int)sizeof("-Infinity"))
  2341. snprintf(buffer, buffersize, "-Infinity");
  2342. break;
  2343. default:
  2344. if (xmlXPathIsNaN(number)) {
  2345. if (buffersize > (int)sizeof("NaN"))
  2346. snprintf(buffer, buffersize, "NaN");
  2347. } else if (number == 0) {
  2348. /* Omit sign for negative zero. */
  2349. snprintf(buffer, buffersize, "0");
  2350. } else if ((number > INT_MIN) && (number < INT_MAX) &&
  2351. (number == (int) number)) {
  2352. char work[30];
  2353. char *ptr, *cur;
  2354. int value = (int) number;
  2355. ptr = &buffer[0];
  2356. if (value == 0) {
  2357. *ptr++ = '0';
  2358. } else {
  2359. snprintf(work, 29, "%d", value);
  2360. cur = &work[0];
  2361. while ((*cur) && (ptr - buffer < buffersize)) {
  2362. *ptr++ = *cur++;
  2363. }
  2364. }
  2365. if (ptr - buffer < buffersize) {
  2366. *ptr = 0;
  2367. } else if (buffersize > 0) {
  2368. ptr--;
  2369. *ptr = 0;
  2370. }
  2371. } else {
  2372. /*
  2373. For the dimension of work,
  2374. DBL_DIG is number of significant digits
  2375. EXPONENT is only needed for "scientific notation"
  2376. 3 is sign, decimal point, and terminating zero
  2377. LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
  2378. Note that this dimension is slightly (a few characters)
  2379. larger than actually necessary.
  2380. */
  2381. char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
  2382. int integer_place, fraction_place;
  2383. char *ptr;
  2384. char *after_fraction;
  2385. double absolute_value;
  2386. int size;
  2387. absolute_value = fabs(number);
  2388. /*
  2389. * First choose format - scientific or regular floating point.
  2390. * In either case, result is in work, and after_fraction points
  2391. * just past the fractional part.
  2392. */
  2393. if ( ((absolute_value > UPPER_DOUBLE) ||
  2394. (absolute_value < LOWER_DOUBLE)) &&
  2395. (absolute_value != 0.0) ) {
  2396. /* Use scientific notation */
  2397. integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
  2398. fraction_place = DBL_DIG - 1;
  2399. size = snprintf(work, sizeof(work),"%*.*e",
  2400. integer_place, fraction_place, number);
  2401. while ((size > 0) && (work[size] != 'e')) size--;
  2402. }
  2403. else {
  2404. /* Use regular notation */
  2405. if (absolute_value > 0.0) {
  2406. integer_place = (int)log10(absolute_value);
  2407. if (integer_place > 0)
  2408. fraction_place = DBL_DIG - integer_place - 1;
  2409. else
  2410. fraction_place = DBL_DIG - integer_place;
  2411. } else {
  2412. fraction_place = 1;
  2413. }
  2414. size = snprintf(work, sizeof(work), "%0.*f",
  2415. fraction_place, number);
  2416. }
  2417. /* Remove leading spaces sometimes inserted by snprintf */
  2418. while (work[0] == ' ') {
  2419. for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
  2420. size--;
  2421. }
  2422. /* Remove fractional trailing zeroes */
  2423. after_fraction = work + size;
  2424. ptr = after_fraction;
  2425. while (*(--ptr) == '0')
  2426. ;
  2427. if (*ptr != '.')
  2428. ptr++;
  2429. while ((*ptr++ = *after_fraction++) != 0);
  2430. /* Finally copy result back to caller */
  2431. size = strlen(work) + 1;
  2432. if (size > buffersize) {
  2433. work[buffersize - 1] = 0;
  2434. size = buffersize;
  2435. }
  2436. memmove(buffer, work, size);
  2437. }
  2438. break;
  2439. }
  2440. }
  2441. /************************************************************************
  2442. * *
  2443. * Routines to handle NodeSets *
  2444. * *
  2445. ************************************************************************/
  2446. /**
  2447. * xmlXPathOrderDocElems:
  2448. * @doc: an input document
  2449. *
  2450. * Call this routine to speed up XPath computation on static documents.
  2451. * This stamps all the element nodes with the document order
  2452. * Like for line information, the order is kept in the element->content
  2453. * field, the value stored is actually - the node number (starting at -1)
  2454. * to be able to differentiate from line numbers.
  2455. *
  2456. * Returns the number of elements found in the document or -1 in case
  2457. * of error.
  2458. */
  2459. long
  2460. xmlXPathOrderDocElems(xmlDocPtr doc) {
  2461. ptrdiff_t count = 0;
  2462. xmlNodePtr cur;
  2463. if (doc == NULL)
  2464. return(-1);
  2465. cur = doc->children;
  2466. while (cur != NULL) {
  2467. if (cur->type == XML_ELEMENT_NODE) {
  2468. cur->content = (void *) (-(++count));
  2469. if (cur->children != NULL) {
  2470. cur = cur->children;
  2471. continue;
  2472. }
  2473. }
  2474. if (cur->next != NULL) {
  2475. cur = cur->next;
  2476. continue;
  2477. }
  2478. do {
  2479. cur = cur->parent;
  2480. if (cur == NULL)
  2481. break;
  2482. if (cur == (xmlNodePtr) doc) {
  2483. cur = NULL;
  2484. break;
  2485. }
  2486. if (cur->next != NULL) {
  2487. cur = cur->next;
  2488. break;
  2489. }
  2490. } while (cur != NULL);
  2491. }
  2492. return(count);
  2493. }
  2494. /**
  2495. * xmlXPathCmpNodes:
  2496. * @node1: the first node
  2497. * @node2: the second node
  2498. *
  2499. * Compare two nodes w.r.t document order
  2500. *
  2501. * Returns -2 in case of error 1 if first point < second point, 0 if
  2502. * it's the same node, -1 otherwise
  2503. */
  2504. int
  2505. xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
  2506. int depth1, depth2;
  2507. int attr1 = 0, attr2 = 0;
  2508. xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
  2509. xmlNodePtr cur, root;
  2510. if ((node1 == NULL) || (node2 == NULL))
  2511. return(-2);
  2512. /*
  2513. * a couple of optimizations which will avoid computations in most cases
  2514. */
  2515. if (node1 == node2) /* trivial case */
  2516. return(0);
  2517. if (node1->type == XML_ATTRIBUTE_NODE) {
  2518. attr1 = 1;
  2519. attrNode1 = node1;
  2520. node1 = node1->parent;
  2521. }
  2522. if (node2->type == XML_ATTRIBUTE_NODE) {
  2523. attr2 = 1;
  2524. attrNode2 = node2;
  2525. node2 = node2->parent;
  2526. }
  2527. if (node1 == node2) {
  2528. if (attr1 == attr2) {
  2529. /* not required, but we keep attributes in order */
  2530. if (attr1 != 0) {
  2531. cur = attrNode2->prev;
  2532. while (cur != NULL) {
  2533. if (cur == attrNode1)
  2534. return (1);
  2535. cur = cur->prev;
  2536. }
  2537. return (-1);
  2538. }
  2539. return(0);
  2540. }
  2541. if (attr2 == 1)
  2542. return(1);
  2543. return(-1);
  2544. }
  2545. if ((node1->type == XML_NAMESPACE_DECL) ||
  2546. (node2->type == XML_NAMESPACE_DECL))
  2547. return(1);
  2548. if (node1 == node2->prev)
  2549. return(1);
  2550. if (node1 == node2->next)
  2551. return(-1);
  2552. /*
  2553. * Speedup using document order if available.
  2554. */
  2555. if ((node1->type == XML_ELEMENT_NODE) &&
  2556. (node2->type == XML_ELEMENT_NODE) &&
  2557. (0 > (ptrdiff_t) node1->content) &&
  2558. (0 > (ptrdiff_t) node2->content) &&
  2559. (node1->doc == node2->doc)) {
  2560. ptrdiff_t l1, l2;
  2561. l1 = -((ptrdiff_t) node1->content);
  2562. l2 = -((ptrdiff_t) node2->content);
  2563. if (l1 < l2)
  2564. return(1);
  2565. if (l1 > l2)
  2566. return(-1);
  2567. }
  2568. /*
  2569. * compute depth to root
  2570. */
  2571. for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
  2572. if (cur->parent == node1)
  2573. return(1);
  2574. depth2++;
  2575. }
  2576. root = cur;
  2577. for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
  2578. if (cur->parent == node2)
  2579. return(-1);
  2580. depth1++;
  2581. }
  2582. /*
  2583. * Distinct document (or distinct entities :-( ) case.
  2584. */
  2585. if (root != cur) {
  2586. return(-2);
  2587. }
  2588. /*
  2589. * get the nearest common ancestor.
  2590. */
  2591. while (depth1 > depth2) {
  2592. depth1--;
  2593. node1 = node1->parent;
  2594. }
  2595. while (depth2 > depth1) {
  2596. depth2--;
  2597. node2 = node2->parent;
  2598. }
  2599. while (node1->parent != node2->parent) {
  2600. node1 = node1->parent;
  2601. node2 = node2->parent;
  2602. /* should not happen but just in case ... */
  2603. if ((node1 == NULL) || (node2 == NULL))
  2604. return(-2);
  2605. }
  2606. /*
  2607. * Find who's first.
  2608. */
  2609. if (node1 == node2->prev)
  2610. return(1);
  2611. if (node1 == node2->next)
  2612. return(-1);
  2613. /*
  2614. * Speedup using document order if available.
  2615. */
  2616. if ((node1->type == XML_ELEMENT_NODE) &&
  2617. (node2->type == XML_ELEMENT_NODE) &&
  2618. (0 > (ptrdiff_t) node1->content) &&
  2619. (0 > (ptrdiff_t) node2->content) &&
  2620. (node1->doc == node2->doc)) {
  2621. ptrdiff_t l1, l2;
  2622. l1 = -((ptrdiff_t) node1->content);
  2623. l2 = -((ptrdiff_t) node2->content);
  2624. if (l1 < l2)
  2625. return(1);
  2626. if (l1 > l2)
  2627. return(-1);
  2628. }
  2629. for (cur = node1->next;cur != NULL;cur = cur->next)
  2630. if (cur == node2)
  2631. return(1);
  2632. return(-1); /* assume there is no sibling list corruption */
  2633. }
  2634. /**
  2635. * xmlXPathNodeSetSort:
  2636. * @set: the node set
  2637. *
  2638. * Sort the node set in document order
  2639. */
  2640. void
  2641. xmlXPathNodeSetSort(xmlNodeSetPtr set) {
  2642. #ifndef WITH_TIM_SORT
  2643. int i, j, incr, len;
  2644. xmlNodePtr tmp;
  2645. #endif
  2646. if (set == NULL)
  2647. return;
  2648. #ifndef WITH_TIM_SORT
  2649. /*
  2650. * Use the old Shell's sort implementation to sort the node-set
  2651. * Timsort ought to be quite faster
  2652. */
  2653. len = set->nodeNr;
  2654. for (incr = len / 2; incr > 0; incr /= 2) {
  2655. for (i = incr; i < len; i++) {
  2656. j = i - incr;
  2657. while (j >= 0) {
  2658. #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
  2659. if (xmlXPathCmpNodesExt(set->nodeTab[j],
  2660. set->nodeTab[j + incr]) == -1)
  2661. #else
  2662. if (xmlXPathCmpNodes(set->nodeTab[j],
  2663. set->nodeTab[j + incr]) == -1)
  2664. #endif
  2665. {
  2666. tmp = set->nodeTab[j];
  2667. set->nodeTab[j] = set->nodeTab[j + incr];
  2668. set->nodeTab[j + incr] = tmp;
  2669. j -= incr;
  2670. } else
  2671. break;
  2672. }
  2673. }
  2674. }
  2675. #else /* WITH_TIM_SORT */
  2676. libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
  2677. #endif /* WITH_TIM_SORT */
  2678. }
  2679. #define XML_NODESET_DEFAULT 10
  2680. /**
  2681. * xmlXPathNodeSetDupNs:
  2682. * @node: the parent node of the namespace XPath node
  2683. * @ns: the libxml namespace declaration node.
  2684. *
  2685. * Namespace node in libxml don't match the XPath semantic. In a node set
  2686. * the namespace nodes are duplicated and the next pointer is set to the
  2687. * parent node in the XPath semantic.
  2688. *
  2689. * Returns the newly created object.
  2690. */
  2691. static xmlNodePtr
  2692. xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
  2693. xmlNsPtr cur;
  2694. if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
  2695. return(NULL);
  2696. if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
  2697. return((xmlNodePtr) ns);
  2698. /*
  2699. * Allocate a new Namespace and fill the fields.
  2700. */
  2701. cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
  2702. if (cur == NULL) {
  2703. xmlXPathErrMemory(NULL, "duplicating namespace\n");
  2704. return(NULL);
  2705. }
  2706. memset(cur, 0, sizeof(xmlNs));
  2707. cur->type = XML_NAMESPACE_DECL;
  2708. if (ns->href != NULL)
  2709. cur->href = xmlStrdup(ns->href);
  2710. if (ns->prefix != NULL)
  2711. cur->prefix = xmlStrdup(ns->prefix);
  2712. cur->next = (xmlNsPtr) node;
  2713. return((xmlNodePtr) cur);
  2714. }
  2715. /**
  2716. * xmlXPathNodeSetFreeNs:
  2717. * @ns: the XPath namespace node found in a nodeset.
  2718. *
  2719. * Namespace nodes in libxml don't match the XPath semantic. In a node set
  2720. * the namespace nodes are duplicated and the next pointer is set to the
  2721. * parent node in the XPath semantic. Check if such a node needs to be freed
  2722. */
  2723. void
  2724. xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
  2725. if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
  2726. return;
  2727. if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
  2728. if (ns->href != NULL)
  2729. xmlFree((xmlChar *)ns->href);
  2730. if (ns->prefix != NULL)
  2731. xmlFree((xmlChar *)ns->prefix);
  2732. xmlFree(ns);
  2733. }
  2734. }
  2735. /**
  2736. * xmlXPathNodeSetCreate:
  2737. * @val: an initial xmlNodePtr, or NULL
  2738. *
  2739. * Create a new xmlNodeSetPtr of type double and of value @val
  2740. *
  2741. * Returns the newly created object.
  2742. */
  2743. xmlNodeSetPtr
  2744. xmlXPathNodeSetCreate(xmlNodePtr val) {
  2745. xmlNodeSetPtr ret;
  2746. ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
  2747. if (ret == NULL) {
  2748. xmlXPathErrMemory(NULL, "creating nodeset\n");
  2749. return(NULL);
  2750. }
  2751. memset(ret, 0 , sizeof(xmlNodeSet));
  2752. if (val != NULL) {
  2753. ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
  2754. sizeof(xmlNodePtr));
  2755. if (ret->nodeTab == NULL) {
  2756. xmlXPathErrMemory(NULL, "creating nodeset\n");
  2757. xmlFree(ret);
  2758. return(NULL);
  2759. }
  2760. memset(ret->nodeTab, 0 ,
  2761. XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
  2762. ret->nodeMax = XML_NODESET_DEFAULT;
  2763. if (val->type == XML_NAMESPACE_DECL) {
  2764. xmlNsPtr ns = (xmlNsPtr) val;
  2765. xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
  2766. if (nsNode == NULL) {
  2767. xmlXPathFreeNodeSet(ret);
  2768. return(NULL);
  2769. }
  2770. ret->nodeTab[ret->nodeNr++] = nsNode;
  2771. } else
  2772. ret->nodeTab[ret->nodeNr++] = val;
  2773. }
  2774. return(ret);
  2775. }
  2776. /**
  2777. * xmlXPathNodeSetContains:
  2778. * @cur: the node-set
  2779. * @val: the node
  2780. *
  2781. * checks whether @cur contains @val
  2782. *
  2783. * Returns true (1) if @cur contains @val, false (0) otherwise
  2784. */
  2785. int
  2786. xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
  2787. int i;
  2788. if ((cur == NULL) || (val == NULL)) return(0);
  2789. if (val->type == XML_NAMESPACE_DECL) {
  2790. for (i = 0; i < cur->nodeNr; i++) {
  2791. if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
  2792. xmlNsPtr ns1, ns2;
  2793. ns1 = (xmlNsPtr) val;
  2794. ns2 = (xmlNsPtr) cur->nodeTab[i];
  2795. if (ns1 == ns2)
  2796. return(1);
  2797. if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
  2798. (xmlStrEqual(ns1->prefix, ns2->prefix)))
  2799. return(1);
  2800. }
  2801. }
  2802. } else {
  2803. for (i = 0; i < cur->nodeNr; i++) {
  2804. if (cur->nodeTab[i] == val)
  2805. return(1);
  2806. }
  2807. }
  2808. return(0);
  2809. }
  2810. /**
  2811. * xmlXPathNodeSetAddNs:
  2812. * @cur: the initial node set
  2813. * @node: the hosting node
  2814. * @ns: a the namespace node
  2815. *
  2816. * add a new namespace node to an existing NodeSet
  2817. *
  2818. * Returns 0 in case of success and -1 in case of error
  2819. */
  2820. int
  2821. xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
  2822. int i;
  2823. xmlNodePtr nsNode;
  2824. if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
  2825. (ns->type != XML_NAMESPACE_DECL) ||
  2826. (node->type != XML_ELEMENT_NODE))
  2827. return(-1);
  2828. /* @@ with_ns to check whether namespace nodes should be looked at @@ */
  2829. /*
  2830. * prevent duplicates
  2831. */
  2832. for (i = 0;i < cur->nodeNr;i++) {
  2833. if ((cur->nodeTab[i] != NULL) &&
  2834. (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
  2835. (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
  2836. (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
  2837. return(0);
  2838. }
  2839. /*
  2840. * grow the nodeTab if needed
  2841. */
  2842. if (cur->nodeMax == 0) {
  2843. cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
  2844. sizeof(xmlNodePtr));
  2845. if (cur->nodeTab == NULL) {
  2846. xmlXPathErrMemory(NULL, "growing nodeset\n");
  2847. return(-1);
  2848. }
  2849. memset(cur->nodeTab, 0 ,
  2850. XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
  2851. cur->nodeMax = XML_NODESET_DEFAULT;
  2852. } else if (cur->nodeNr == cur->nodeMax) {
  2853. xmlNodePtr *temp;
  2854. if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
  2855. xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
  2856. return(-1);
  2857. }
  2858. temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
  2859. sizeof(xmlNodePtr));
  2860. if (temp == NULL) {
  2861. xmlXPathErrMemory(NULL, "growing nodeset\n");
  2862. return(-1);
  2863. }
  2864. cur->nodeMax *= 2;
  2865. cur->nodeTab = temp;
  2866. }
  2867. nsNode = xmlXPathNodeSetDupNs(node, ns);
  2868. if(nsNode == NULL)
  2869. return(-1);
  2870. cur->nodeTab[cur->nodeNr++] = nsNode;
  2871. return(0);
  2872. }
  2873. /**
  2874. * xmlXPathNodeSetAdd:
  2875. * @cur: the initial node set
  2876. * @val: a new xmlNodePtr
  2877. *
  2878. * add a new xmlNodePtr to an existing NodeSet
  2879. *
  2880. * Returns 0 in case of success, and -1 in case of error
  2881. */
  2882. int
  2883. xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
  2884. int i;
  2885. if ((cur == NULL) || (val == NULL)) return(-1);
  2886. /* @@ with_ns to check whether namespace nodes should be looked at @@ */
  2887. /*
  2888. * prevent duplicates
  2889. */
  2890. for (i = 0;i < cur->nodeNr;i++)
  2891. if (cur->nodeTab[i] == val) return(0);
  2892. /*
  2893. * grow the nodeTab if needed
  2894. */
  2895. if (cur->nodeMax == 0) {
  2896. cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
  2897. sizeof(xmlNodePtr));
  2898. if (cur->nodeTab == NULL) {
  2899. xmlXPathErrMemory(NULL, "growing nodeset\n");
  2900. return(-1);
  2901. }
  2902. memset(cur->nodeTab, 0 ,
  2903. XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
  2904. cur->nodeMax = XML_NODESET_DEFAULT;
  2905. } else if (cur->nodeNr == cur->nodeMax) {
  2906. xmlNodePtr *temp;
  2907. if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
  2908. xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
  2909. return(-1);
  2910. }
  2911. temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
  2912. sizeof(xmlNodePtr));
  2913. if (temp == NULL) {
  2914. xmlXPathErrMemory(NULL, "growing nodeset\n");
  2915. return(-1);
  2916. }
  2917. cur->nodeMax *= 2;
  2918. cur->nodeTab = temp;
  2919. }
  2920. if (val->type == XML_NAMESPACE_DECL) {
  2921. xmlNsPtr ns = (xmlNsPtr) val;
  2922. xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
  2923. if (nsNode == NULL)
  2924. return(-1);
  2925. cur->nodeTab[cur->nodeNr++] = nsNode;
  2926. } else
  2927. cur->nodeTab[cur->nodeNr++] = val;
  2928. return(0);
  2929. }
  2930. /**
  2931. * xmlXPathNodeSetAddUnique:
  2932. * @cur: the initial node set
  2933. * @val: a new xmlNodePtr
  2934. *
  2935. * add a new xmlNodePtr to an existing NodeSet, optimized version
  2936. * when we are sure the node is not already in the set.
  2937. *
  2938. * Returns 0 in case of success and -1 in case of failure
  2939. */
  2940. int
  2941. xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
  2942. if ((cur == NULL) || (val == NULL)) return(-1);
  2943. /* @@ with_ns to check whether namespace nodes should be looked at @@ */
  2944. /*
  2945. * grow the nodeTab if needed
  2946. */
  2947. if (cur->nodeMax == 0) {
  2948. cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
  2949. sizeof(xmlNodePtr));
  2950. if (cur->nodeTab == NULL) {
  2951. xmlXPathErrMemory(NULL, "growing nodeset\n");
  2952. return(-1);
  2953. }
  2954. memset(cur->nodeTab, 0 ,
  2955. XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
  2956. cur->nodeMax = XML_NODESET_DEFAULT;
  2957. } else if (cur->nodeNr == cur->nodeMax) {
  2958. xmlNodePtr *temp;
  2959. if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
  2960. xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
  2961. return(-1);
  2962. }
  2963. temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
  2964. sizeof(xmlNodePtr));
  2965. if (temp == NULL) {
  2966. xmlXPathErrMemory(NULL, "growing nodeset\n");
  2967. return(-1);
  2968. }
  2969. cur->nodeTab = temp;
  2970. cur->nodeMax *= 2;
  2971. }
  2972. if (val->type == XML_NAMESPACE_DECL) {
  2973. xmlNsPtr ns = (xmlNsPtr) val;
  2974. xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
  2975. if (nsNode == NULL)
  2976. return(-1);
  2977. cur->nodeTab[cur->nodeNr++] = nsNode;
  2978. } else
  2979. cur->nodeTab[cur->nodeNr++] = val;
  2980. return(0);
  2981. }
  2982. /**
  2983. * xmlXPathNodeSetMerge:
  2984. * @val1: the first NodeSet or NULL
  2985. * @val2: the second NodeSet
  2986. *
  2987. * Merges two nodesets, all nodes from @val2 are added to @val1
  2988. * if @val1 is NULL, a new set is created and copied from @val2
  2989. *
  2990. * Returns @val1 once extended or NULL in case of error.
  2991. *
  2992. * Frees @val1 in case of error.
  2993. */
  2994. xmlNodeSetPtr
  2995. xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
  2996. int i, j, initNr, skip;
  2997. xmlNodePtr n1, n2;
  2998. if (val2 == NULL) return(val1);
  2999. if (val1 == NULL) {
  3000. val1 = xmlXPathNodeSetCreate(NULL);
  3001. if (val1 == NULL)
  3002. return (NULL);
  3003. }
  3004. /* @@ with_ns to check whether namespace nodes should be looked at @@ */
  3005. initNr = val1->nodeNr;
  3006. for (i = 0;i < val2->nodeNr;i++) {
  3007. n2 = val2->nodeTab[i];
  3008. /*
  3009. * check against duplicates
  3010. */
  3011. skip = 0;
  3012. for (j = 0; j < initNr; j++) {
  3013. n1 = val1->nodeTab[j];
  3014. if (n1 == n2) {
  3015. skip = 1;
  3016. break;
  3017. } else if ((n1->type == XML_NAMESPACE_DECL) &&
  3018. (n2->type == XML_NAMESPACE_DECL)) {
  3019. if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
  3020. (xmlStrEqual(((xmlNsPtr) n1)->prefix,
  3021. ((xmlNsPtr) n2)->prefix)))
  3022. {
  3023. skip = 1;
  3024. break;
  3025. }
  3026. }
  3027. }
  3028. if (skip)
  3029. continue;
  3030. /*
  3031. * grow the nodeTab if needed
  3032. */
  3033. if (val1->nodeMax == 0) {
  3034. val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
  3035. sizeof(xmlNodePtr));
  3036. if (val1->nodeTab == NULL) {
  3037. xmlXPathErrMemory(NULL, "merging nodeset\n");
  3038. goto error;
  3039. }
  3040. memset(val1->nodeTab, 0 ,
  3041. XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
  3042. val1->nodeMax = XML_NODESET_DEFAULT;
  3043. } else if (val1->nodeNr == val1->nodeMax) {
  3044. xmlNodePtr *temp;
  3045. if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
  3046. xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
  3047. goto error;
  3048. }
  3049. temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
  3050. sizeof(xmlNodePtr));
  3051. if (temp == NULL) {
  3052. xmlXPathErrMemory(NULL, "merging nodeset\n");
  3053. goto error;
  3054. }
  3055. val1->nodeTab = temp;
  3056. val1->nodeMax *= 2;
  3057. }
  3058. if (n2->type == XML_NAMESPACE_DECL) {
  3059. xmlNsPtr ns = (xmlNsPtr) n2;
  3060. xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
  3061. if (nsNode == NULL)
  3062. goto error;
  3063. val1->nodeTab[val1->nodeNr++] = nsNode;
  3064. } else
  3065. val1->nodeTab[val1->nodeNr++] = n2;
  3066. }
  3067. return(val1);
  3068. error:
  3069. xmlXPathFreeNodeSet(val1);
  3070. return(NULL);
  3071. }
  3072. /**
  3073. * xmlXPathNodeSetMergeAndClear:
  3074. * @set1: the first NodeSet or NULL
  3075. * @set2: the second NodeSet
  3076. *
  3077. * Merges two nodesets, all nodes from @set2 are added to @set1.
  3078. * Checks for duplicate nodes. Clears set2.
  3079. *
  3080. * Returns @set1 once extended or NULL in case of error.
  3081. *
  3082. * Frees @set1 in case of error.
  3083. */
  3084. static xmlNodeSetPtr
  3085. xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
  3086. {
  3087. {
  3088. int i, j, initNbSet1;
  3089. xmlNodePtr n1, n2;
  3090. initNbSet1 = set1->nodeNr;
  3091. for (i = 0;i < set2->nodeNr;i++) {
  3092. n2 = set2->nodeTab[i];
  3093. /*
  3094. * Skip duplicates.
  3095. */
  3096. for (j = 0; j < initNbSet1; j++) {
  3097. n1 = set1->nodeTab[j];
  3098. if (n1 == n2) {
  3099. goto skip_node;
  3100. } else if ((n1->type == XML_NAMESPACE_DECL) &&
  3101. (n2->type == XML_NAMESPACE_DECL))
  3102. {
  3103. if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
  3104. (xmlStrEqual(((xmlNsPtr) n1)->prefix,
  3105. ((xmlNsPtr) n2)->prefix)))
  3106. {
  3107. /*
  3108. * Free the namespace node.
  3109. */
  3110. xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
  3111. goto skip_node;
  3112. }
  3113. }
  3114. }
  3115. /*
  3116. * grow the nodeTab if needed
  3117. */
  3118. if (set1->nodeMax == 0) {
  3119. set1->nodeTab = (xmlNodePtr *) xmlMalloc(
  3120. XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
  3121. if (set1->nodeTab == NULL) {
  3122. xmlXPathErrMemory(NULL, "merging nodeset\n");
  3123. goto error;
  3124. }
  3125. memset(set1->nodeTab, 0,
  3126. XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
  3127. set1->nodeMax = XML_NODESET_DEFAULT;
  3128. } else if (set1->nodeNr >= set1->nodeMax) {
  3129. xmlNodePtr *temp;
  3130. if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
  3131. xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
  3132. goto error;
  3133. }
  3134. temp = (xmlNodePtr *) xmlRealloc(
  3135. set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
  3136. if (temp == NULL) {
  3137. xmlXPathErrMemory(NULL, "merging nodeset\n");
  3138. goto error;
  3139. }
  3140. set1->nodeTab = temp;
  3141. set1->nodeMax *= 2;
  3142. }
  3143. set1->nodeTab[set1->nodeNr++] = n2;
  3144. skip_node:
  3145. set2->nodeTab[i] = NULL;
  3146. }
  3147. }
  3148. set2->nodeNr = 0;
  3149. return(set1);
  3150. error:
  3151. xmlXPathFreeNodeSet(set1);
  3152. xmlXPathNodeSetClear(set2, 1);
  3153. return(NULL);
  3154. }
  3155. /**
  3156. * xmlXPathNodeSetMergeAndClearNoDupls:
  3157. * @set1: the first NodeSet or NULL
  3158. * @set2: the second NodeSet
  3159. *
  3160. * Merges two nodesets, all nodes from @set2 are added to @set1.
  3161. * Doesn't check for duplicate nodes. Clears set2.
  3162. *
  3163. * Returns @set1 once extended or NULL in case of error.
  3164. *
  3165. * Frees @set1 in case of error.
  3166. */
  3167. static xmlNodeSetPtr
  3168. xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
  3169. {
  3170. {
  3171. int i;
  3172. xmlNodePtr n2;
  3173. for (i = 0;i < set2->nodeNr;i++) {
  3174. n2 = set2->nodeTab[i];
  3175. if (set1->nodeMax == 0) {
  3176. set1->nodeTab = (xmlNodePtr *) xmlMalloc(
  3177. XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
  3178. if (set1->nodeTab == NULL) {
  3179. xmlXPathErrMemory(NULL, "merging nodeset\n");
  3180. goto error;
  3181. }
  3182. memset(set1->nodeTab, 0,
  3183. XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
  3184. set1->nodeMax = XML_NODESET_DEFAULT;
  3185. } else if (set1->nodeNr >= set1->nodeMax) {
  3186. xmlNodePtr *temp;
  3187. if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
  3188. xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
  3189. goto error;
  3190. }
  3191. temp = (xmlNodePtr *) xmlRealloc(
  3192. set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
  3193. if (temp == NULL) {
  3194. xmlXPathErrMemory(NULL, "merging nodeset\n");
  3195. goto error;
  3196. }
  3197. set1->nodeTab = temp;
  3198. set1->nodeMax *= 2;
  3199. }
  3200. set1->nodeTab[set1->nodeNr++] = n2;
  3201. set2->nodeTab[i] = NULL;
  3202. }
  3203. }
  3204. set2->nodeNr = 0;
  3205. return(set1);
  3206. error:
  3207. xmlXPathFreeNodeSet(set1);
  3208. xmlXPathNodeSetClear(set2, 1);
  3209. return(NULL);
  3210. }
  3211. /**
  3212. * xmlXPathNodeSetDel:
  3213. * @cur: the initial node set
  3214. * @val: an xmlNodePtr
  3215. *
  3216. * Removes an xmlNodePtr from an existing NodeSet
  3217. */
  3218. void
  3219. xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
  3220. int i;
  3221. if (cur == NULL) return;
  3222. if (val == NULL) return;
  3223. /*
  3224. * find node in nodeTab
  3225. */
  3226. for (i = 0;i < cur->nodeNr;i++)
  3227. if (cur->nodeTab[i] == val) break;
  3228. if (i >= cur->nodeNr) { /* not found */
  3229. return;
  3230. }
  3231. if ((cur->nodeTab[i] != NULL) &&
  3232. (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
  3233. xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
  3234. cur->nodeNr--;
  3235. for (;i < cur->nodeNr;i++)
  3236. cur->nodeTab[i] = cur->nodeTab[i + 1];
  3237. cur->nodeTab[cur->nodeNr] = NULL;
  3238. }
  3239. /**
  3240. * xmlXPathNodeSetRemove:
  3241. * @cur: the initial node set
  3242. * @val: the index to remove
  3243. *
  3244. * Removes an entry from an existing NodeSet list.
  3245. */
  3246. void
  3247. xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
  3248. if (cur == NULL) return;
  3249. if (val >= cur->nodeNr) return;
  3250. if ((cur->nodeTab[val] != NULL) &&
  3251. (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
  3252. xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
  3253. cur->nodeNr--;
  3254. for (;val < cur->nodeNr;val++)
  3255. cur->nodeTab[val] = cur->nodeTab[val + 1];
  3256. cur->nodeTab[cur->nodeNr] = NULL;
  3257. }
  3258. /**
  3259. * xmlXPathFreeNodeSet:
  3260. * @obj: the xmlNodeSetPtr to free
  3261. *
  3262. * Free the NodeSet compound (not the actual nodes !).
  3263. */
  3264. void
  3265. xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
  3266. if (obj == NULL) return;
  3267. if (obj->nodeTab != NULL) {
  3268. int i;
  3269. /* @@ with_ns to check whether namespace nodes should be looked at @@ */
  3270. for (i = 0;i < obj->nodeNr;i++)
  3271. if ((obj->nodeTab[i] != NULL) &&
  3272. (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
  3273. xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
  3274. xmlFree(obj->nodeTab);
  3275. }
  3276. xmlFree(obj);
  3277. }
  3278. /**
  3279. * xmlXPathNodeSetClearFromPos:
  3280. * @set: the node set to be cleared
  3281. * @pos: the start position to clear from
  3282. *
  3283. * Clears the list from temporary XPath objects (e.g. namespace nodes
  3284. * are feed) starting with the entry at @pos, but does *not* free the list
  3285. * itself. Sets the length of the list to @pos.
  3286. */
  3287. static void
  3288. xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
  3289. {
  3290. if ((set == NULL) || (pos >= set->nodeNr))
  3291. return;
  3292. else if ((hasNsNodes)) {
  3293. int i;
  3294. xmlNodePtr node;
  3295. for (i = pos; i < set->nodeNr; i++) {
  3296. node = set->nodeTab[i];
  3297. if ((node != NULL) &&
  3298. (node->type == XML_NAMESPACE_DECL))
  3299. xmlXPathNodeSetFreeNs((xmlNsPtr) node);
  3300. }
  3301. }
  3302. set->nodeNr = pos;
  3303. }
  3304. /**
  3305. * xmlXPathNodeSetClear:
  3306. * @set: the node set to clear
  3307. *
  3308. * Clears the list from all temporary XPath objects (e.g. namespace nodes
  3309. * are feed), but does *not* free the list itself. Sets the length of the
  3310. * list to 0.
  3311. */
  3312. static void
  3313. xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
  3314. {
  3315. xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
  3316. }
  3317. /**
  3318. * xmlXPathNodeSetKeepLast:
  3319. * @set: the node set to be cleared
  3320. *
  3321. * Move the last node to the first position and clear temporary XPath objects
  3322. * (e.g. namespace nodes) from all other nodes. Sets the length of the list
  3323. * to 1.
  3324. */
  3325. static void
  3326. xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
  3327. {
  3328. int i;
  3329. xmlNodePtr node;
  3330. if ((set == NULL) || (set->nodeNr <= 1))
  3331. return;
  3332. for (i = 0; i < set->nodeNr - 1; i++) {
  3333. node = set->nodeTab[i];
  3334. if ((node != NULL) &&
  3335. (node->type == XML_NAMESPACE_DECL))
  3336. xmlXPathNodeSetFreeNs((xmlNsPtr) node);
  3337. }
  3338. set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
  3339. set->nodeNr = 1;
  3340. }
  3341. /**
  3342. * xmlXPathFreeValueTree:
  3343. * @obj: the xmlNodeSetPtr to free
  3344. *
  3345. * Free the NodeSet compound and the actual tree, this is different
  3346. * from xmlXPathFreeNodeSet()
  3347. */
  3348. static void
  3349. xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
  3350. int i;
  3351. if (obj == NULL) return;
  3352. if (obj->nodeTab != NULL) {
  3353. for (i = 0;i < obj->nodeNr;i++) {
  3354. if (obj->nodeTab[i] != NULL) {
  3355. if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
  3356. xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
  3357. } else {
  3358. xmlFreeNodeList(obj->nodeTab[i]);
  3359. }
  3360. }
  3361. }
  3362. xmlFree(obj->nodeTab);
  3363. }
  3364. xmlFree(obj);
  3365. }
  3366. /**
  3367. * xmlXPathNewNodeSet:
  3368. * @val: the NodePtr value
  3369. *
  3370. * Create a new xmlXPathObjectPtr of type NodeSet and initialize
  3371. * it with the single Node @val
  3372. *
  3373. * Returns the newly created object.
  3374. */
  3375. xmlXPathObjectPtr
  3376. xmlXPathNewNodeSet(xmlNodePtr val) {
  3377. xmlXPathObjectPtr ret;
  3378. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  3379. if (ret == NULL) {
  3380. xmlXPathErrMemory(NULL, "creating nodeset\n");
  3381. return(NULL);
  3382. }
  3383. memset(ret, 0 , sizeof(xmlXPathObject));
  3384. ret->type = XPATH_NODESET;
  3385. ret->boolval = 0;
  3386. /* TODO: Check memory error. */
  3387. ret->nodesetval = xmlXPathNodeSetCreate(val);
  3388. /* @@ with_ns to check whether namespace nodes should be looked at @@ */
  3389. return(ret);
  3390. }
  3391. /**
  3392. * xmlXPathNewValueTree:
  3393. * @val: the NodePtr value
  3394. *
  3395. * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
  3396. * it with the tree root @val
  3397. *
  3398. * Returns the newly created object.
  3399. */
  3400. xmlXPathObjectPtr
  3401. xmlXPathNewValueTree(xmlNodePtr val) {
  3402. xmlXPathObjectPtr ret;
  3403. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  3404. if (ret == NULL) {
  3405. xmlXPathErrMemory(NULL, "creating result value tree\n");
  3406. return(NULL);
  3407. }
  3408. memset(ret, 0 , sizeof(xmlXPathObject));
  3409. ret->type = XPATH_XSLT_TREE;
  3410. ret->boolval = 1;
  3411. ret->user = (void *) val;
  3412. ret->nodesetval = xmlXPathNodeSetCreate(val);
  3413. return(ret);
  3414. }
  3415. /**
  3416. * xmlXPathNewNodeSetList:
  3417. * @val: an existing NodeSet
  3418. *
  3419. * Create a new xmlXPathObjectPtr of type NodeSet and initialize
  3420. * it with the Nodeset @val
  3421. *
  3422. * Returns the newly created object.
  3423. */
  3424. xmlXPathObjectPtr
  3425. xmlXPathNewNodeSetList(xmlNodeSetPtr val)
  3426. {
  3427. xmlXPathObjectPtr ret;
  3428. int i;
  3429. if (val == NULL)
  3430. ret = NULL;
  3431. else if (val->nodeTab == NULL)
  3432. ret = xmlXPathNewNodeSet(NULL);
  3433. else {
  3434. ret = xmlXPathNewNodeSet(val->nodeTab[0]);
  3435. if (ret) {
  3436. for (i = 1; i < val->nodeNr; ++i) {
  3437. /* TODO: Propagate memory error. */
  3438. if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
  3439. < 0) break;
  3440. }
  3441. }
  3442. }
  3443. return (ret);
  3444. }
  3445. /**
  3446. * xmlXPathWrapNodeSet:
  3447. * @val: the NodePtr value
  3448. *
  3449. * Wrap the Nodeset @val in a new xmlXPathObjectPtr
  3450. *
  3451. * Returns the newly created object.
  3452. *
  3453. * In case of error the node set is destroyed and NULL is returned.
  3454. */
  3455. xmlXPathObjectPtr
  3456. xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
  3457. xmlXPathObjectPtr ret;
  3458. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  3459. if (ret == NULL) {
  3460. xmlXPathErrMemory(NULL, "creating node set object\n");
  3461. xmlXPathFreeNodeSet(val);
  3462. return(NULL);
  3463. }
  3464. memset(ret, 0 , sizeof(xmlXPathObject));
  3465. ret->type = XPATH_NODESET;
  3466. ret->nodesetval = val;
  3467. return(ret);
  3468. }
  3469. /**
  3470. * xmlXPathFreeNodeSetList:
  3471. * @obj: an existing NodeSetList object
  3472. *
  3473. * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
  3474. * the list contrary to xmlXPathFreeObject().
  3475. */
  3476. void
  3477. xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
  3478. if (obj == NULL) return;
  3479. xmlFree(obj);
  3480. }
  3481. /**
  3482. * xmlXPathDifference:
  3483. * @nodes1: a node-set
  3484. * @nodes2: a node-set
  3485. *
  3486. * Implements the EXSLT - Sets difference() function:
  3487. * node-set set:difference (node-set, node-set)
  3488. *
  3489. * Returns the difference between the two node sets, or nodes1 if
  3490. * nodes2 is empty
  3491. */
  3492. xmlNodeSetPtr
  3493. xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  3494. xmlNodeSetPtr ret;
  3495. int i, l1;
  3496. xmlNodePtr cur;
  3497. if (xmlXPathNodeSetIsEmpty(nodes2))
  3498. return(nodes1);
  3499. /* TODO: Check memory error. */
  3500. ret = xmlXPathNodeSetCreate(NULL);
  3501. if (xmlXPathNodeSetIsEmpty(nodes1))
  3502. return(ret);
  3503. l1 = xmlXPathNodeSetGetLength(nodes1);
  3504. for (i = 0; i < l1; i++) {
  3505. cur = xmlXPathNodeSetItem(nodes1, i);
  3506. if (!xmlXPathNodeSetContains(nodes2, cur)) {
  3507. /* TODO: Propagate memory error. */
  3508. if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
  3509. break;
  3510. }
  3511. }
  3512. return(ret);
  3513. }
  3514. /**
  3515. * xmlXPathIntersection:
  3516. * @nodes1: a node-set
  3517. * @nodes2: a node-set
  3518. *
  3519. * Implements the EXSLT - Sets intersection() function:
  3520. * node-set set:intersection (node-set, node-set)
  3521. *
  3522. * Returns a node set comprising the nodes that are within both the
  3523. * node sets passed as arguments
  3524. */
  3525. xmlNodeSetPtr
  3526. xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  3527. xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
  3528. int i, l1;
  3529. xmlNodePtr cur;
  3530. if (ret == NULL)
  3531. return(ret);
  3532. if (xmlXPathNodeSetIsEmpty(nodes1))
  3533. return(ret);
  3534. if (xmlXPathNodeSetIsEmpty(nodes2))
  3535. return(ret);
  3536. l1 = xmlXPathNodeSetGetLength(nodes1);
  3537. for (i = 0; i < l1; i++) {
  3538. cur = xmlXPathNodeSetItem(nodes1, i);
  3539. if (xmlXPathNodeSetContains(nodes2, cur)) {
  3540. /* TODO: Propagate memory error. */
  3541. if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
  3542. break;
  3543. }
  3544. }
  3545. return(ret);
  3546. }
  3547. /**
  3548. * xmlXPathDistinctSorted:
  3549. * @nodes: a node-set, sorted by document order
  3550. *
  3551. * Implements the EXSLT - Sets distinct() function:
  3552. * node-set set:distinct (node-set)
  3553. *
  3554. * Returns a subset of the nodes contained in @nodes, or @nodes if
  3555. * it is empty
  3556. */
  3557. xmlNodeSetPtr
  3558. xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
  3559. xmlNodeSetPtr ret;
  3560. xmlHashTablePtr hash;
  3561. int i, l;
  3562. xmlChar * strval;
  3563. xmlNodePtr cur;
  3564. if (xmlXPathNodeSetIsEmpty(nodes))
  3565. return(nodes);
  3566. ret = xmlXPathNodeSetCreate(NULL);
  3567. if (ret == NULL)
  3568. return(ret);
  3569. l = xmlXPathNodeSetGetLength(nodes);
  3570. hash = xmlHashCreate (l);
  3571. for (i = 0; i < l; i++) {
  3572. cur = xmlXPathNodeSetItem(nodes, i);
  3573. strval = xmlXPathCastNodeToString(cur);
  3574. if (xmlHashLookup(hash, strval) == NULL) {
  3575. if (xmlHashAddEntry(hash, strval, strval) < 0) {
  3576. xmlFree(strval);
  3577. goto error;
  3578. }
  3579. if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
  3580. goto error;
  3581. } else {
  3582. xmlFree(strval);
  3583. }
  3584. }
  3585. xmlHashFree(hash, xmlHashDefaultDeallocator);
  3586. return(ret);
  3587. error:
  3588. xmlHashFree(hash, xmlHashDefaultDeallocator);
  3589. xmlXPathFreeNodeSet(ret);
  3590. return(NULL);
  3591. }
  3592. /**
  3593. * xmlXPathDistinct:
  3594. * @nodes: a node-set
  3595. *
  3596. * Implements the EXSLT - Sets distinct() function:
  3597. * node-set set:distinct (node-set)
  3598. * @nodes is sorted by document order, then #exslSetsDistinctSorted
  3599. * is called with the sorted node-set
  3600. *
  3601. * Returns a subset of the nodes contained in @nodes, or @nodes if
  3602. * it is empty
  3603. */
  3604. xmlNodeSetPtr
  3605. xmlXPathDistinct (xmlNodeSetPtr nodes) {
  3606. if (xmlXPathNodeSetIsEmpty(nodes))
  3607. return(nodes);
  3608. xmlXPathNodeSetSort(nodes);
  3609. return(xmlXPathDistinctSorted(nodes));
  3610. }
  3611. /**
  3612. * xmlXPathHasSameNodes:
  3613. * @nodes1: a node-set
  3614. * @nodes2: a node-set
  3615. *
  3616. * Implements the EXSLT - Sets has-same-nodes function:
  3617. * boolean set:has-same-node(node-set, node-set)
  3618. *
  3619. * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
  3620. * otherwise
  3621. */
  3622. int
  3623. xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  3624. int i, l;
  3625. xmlNodePtr cur;
  3626. if (xmlXPathNodeSetIsEmpty(nodes1) ||
  3627. xmlXPathNodeSetIsEmpty(nodes2))
  3628. return(0);
  3629. l = xmlXPathNodeSetGetLength(nodes1);
  3630. for (i = 0; i < l; i++) {
  3631. cur = xmlXPathNodeSetItem(nodes1, i);
  3632. if (xmlXPathNodeSetContains(nodes2, cur))
  3633. return(1);
  3634. }
  3635. return(0);
  3636. }
  3637. /**
  3638. * xmlXPathNodeLeadingSorted:
  3639. * @nodes: a node-set, sorted by document order
  3640. * @node: a node
  3641. *
  3642. * Implements the EXSLT - Sets leading() function:
  3643. * node-set set:leading (node-set, node-set)
  3644. *
  3645. * Returns the nodes in @nodes that precede @node in document order,
  3646. * @nodes if @node is NULL or an empty node-set if @nodes
  3647. * doesn't contain @node
  3648. */
  3649. xmlNodeSetPtr
  3650. xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
  3651. int i, l;
  3652. xmlNodePtr cur;
  3653. xmlNodeSetPtr ret;
  3654. if (node == NULL)
  3655. return(nodes);
  3656. ret = xmlXPathNodeSetCreate(NULL);
  3657. if (ret == NULL)
  3658. return(ret);
  3659. if (xmlXPathNodeSetIsEmpty(nodes) ||
  3660. (!xmlXPathNodeSetContains(nodes, node)))
  3661. return(ret);
  3662. l = xmlXPathNodeSetGetLength(nodes);
  3663. for (i = 0; i < l; i++) {
  3664. cur = xmlXPathNodeSetItem(nodes, i);
  3665. if (cur == node)
  3666. break;
  3667. /* TODO: Propagate memory error. */
  3668. if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
  3669. break;
  3670. }
  3671. return(ret);
  3672. }
  3673. /**
  3674. * xmlXPathNodeLeading:
  3675. * @nodes: a node-set
  3676. * @node: a node
  3677. *
  3678. * Implements the EXSLT - Sets leading() function:
  3679. * node-set set:leading (node-set, node-set)
  3680. * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
  3681. * is called.
  3682. *
  3683. * Returns the nodes in @nodes that precede @node in document order,
  3684. * @nodes if @node is NULL or an empty node-set if @nodes
  3685. * doesn't contain @node
  3686. */
  3687. xmlNodeSetPtr
  3688. xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
  3689. xmlXPathNodeSetSort(nodes);
  3690. return(xmlXPathNodeLeadingSorted(nodes, node));
  3691. }
  3692. /**
  3693. * xmlXPathLeadingSorted:
  3694. * @nodes1: a node-set, sorted by document order
  3695. * @nodes2: a node-set, sorted by document order
  3696. *
  3697. * Implements the EXSLT - Sets leading() function:
  3698. * node-set set:leading (node-set, node-set)
  3699. *
  3700. * Returns the nodes in @nodes1 that precede the first node in @nodes2
  3701. * in document order, @nodes1 if @nodes2 is NULL or empty or
  3702. * an empty node-set if @nodes1 doesn't contain @nodes2
  3703. */
  3704. xmlNodeSetPtr
  3705. xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  3706. if (xmlXPathNodeSetIsEmpty(nodes2))
  3707. return(nodes1);
  3708. return(xmlXPathNodeLeadingSorted(nodes1,
  3709. xmlXPathNodeSetItem(nodes2, 1)));
  3710. }
  3711. /**
  3712. * xmlXPathLeading:
  3713. * @nodes1: a node-set
  3714. * @nodes2: a node-set
  3715. *
  3716. * Implements the EXSLT - Sets leading() function:
  3717. * node-set set:leading (node-set, node-set)
  3718. * @nodes1 and @nodes2 are sorted by document order, then
  3719. * #exslSetsLeadingSorted is called.
  3720. *
  3721. * Returns the nodes in @nodes1 that precede the first node in @nodes2
  3722. * in document order, @nodes1 if @nodes2 is NULL or empty or
  3723. * an empty node-set if @nodes1 doesn't contain @nodes2
  3724. */
  3725. xmlNodeSetPtr
  3726. xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  3727. if (xmlXPathNodeSetIsEmpty(nodes2))
  3728. return(nodes1);
  3729. if (xmlXPathNodeSetIsEmpty(nodes1))
  3730. return(xmlXPathNodeSetCreate(NULL));
  3731. xmlXPathNodeSetSort(nodes1);
  3732. xmlXPathNodeSetSort(nodes2);
  3733. return(xmlXPathNodeLeadingSorted(nodes1,
  3734. xmlXPathNodeSetItem(nodes2, 1)));
  3735. }
  3736. /**
  3737. * xmlXPathNodeTrailingSorted:
  3738. * @nodes: a node-set, sorted by document order
  3739. * @node: a node
  3740. *
  3741. * Implements the EXSLT - Sets trailing() function:
  3742. * node-set set:trailing (node-set, node-set)
  3743. *
  3744. * Returns the nodes in @nodes that follow @node in document order,
  3745. * @nodes if @node is NULL or an empty node-set if @nodes
  3746. * doesn't contain @node
  3747. */
  3748. xmlNodeSetPtr
  3749. xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
  3750. int i, l;
  3751. xmlNodePtr cur;
  3752. xmlNodeSetPtr ret;
  3753. if (node == NULL)
  3754. return(nodes);
  3755. ret = xmlXPathNodeSetCreate(NULL);
  3756. if (ret == NULL)
  3757. return(ret);
  3758. if (xmlXPathNodeSetIsEmpty(nodes) ||
  3759. (!xmlXPathNodeSetContains(nodes, node)))
  3760. return(ret);
  3761. l = xmlXPathNodeSetGetLength(nodes);
  3762. for (i = l - 1; i >= 0; i--) {
  3763. cur = xmlXPathNodeSetItem(nodes, i);
  3764. if (cur == node)
  3765. break;
  3766. /* TODO: Propagate memory error. */
  3767. if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
  3768. break;
  3769. }
  3770. xmlXPathNodeSetSort(ret); /* bug 413451 */
  3771. return(ret);
  3772. }
  3773. /**
  3774. * xmlXPathNodeTrailing:
  3775. * @nodes: a node-set
  3776. * @node: a node
  3777. *
  3778. * Implements the EXSLT - Sets trailing() function:
  3779. * node-set set:trailing (node-set, node-set)
  3780. * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
  3781. * is called.
  3782. *
  3783. * Returns the nodes in @nodes that follow @node in document order,
  3784. * @nodes if @node is NULL or an empty node-set if @nodes
  3785. * doesn't contain @node
  3786. */
  3787. xmlNodeSetPtr
  3788. xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
  3789. xmlXPathNodeSetSort(nodes);
  3790. return(xmlXPathNodeTrailingSorted(nodes, node));
  3791. }
  3792. /**
  3793. * xmlXPathTrailingSorted:
  3794. * @nodes1: a node-set, sorted by document order
  3795. * @nodes2: a node-set, sorted by document order
  3796. *
  3797. * Implements the EXSLT - Sets trailing() function:
  3798. * node-set set:trailing (node-set, node-set)
  3799. *
  3800. * Returns the nodes in @nodes1 that follow the first node in @nodes2
  3801. * in document order, @nodes1 if @nodes2 is NULL or empty or
  3802. * an empty node-set if @nodes1 doesn't contain @nodes2
  3803. */
  3804. xmlNodeSetPtr
  3805. xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  3806. if (xmlXPathNodeSetIsEmpty(nodes2))
  3807. return(nodes1);
  3808. return(xmlXPathNodeTrailingSorted(nodes1,
  3809. xmlXPathNodeSetItem(nodes2, 0)));
  3810. }
  3811. /**
  3812. * xmlXPathTrailing:
  3813. * @nodes1: a node-set
  3814. * @nodes2: a node-set
  3815. *
  3816. * Implements the EXSLT - Sets trailing() function:
  3817. * node-set set:trailing (node-set, node-set)
  3818. * @nodes1 and @nodes2 are sorted by document order, then
  3819. * #xmlXPathTrailingSorted is called.
  3820. *
  3821. * Returns the nodes in @nodes1 that follow the first node in @nodes2
  3822. * in document order, @nodes1 if @nodes2 is NULL or empty or
  3823. * an empty node-set if @nodes1 doesn't contain @nodes2
  3824. */
  3825. xmlNodeSetPtr
  3826. xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  3827. if (xmlXPathNodeSetIsEmpty(nodes2))
  3828. return(nodes1);
  3829. if (xmlXPathNodeSetIsEmpty(nodes1))
  3830. return(xmlXPathNodeSetCreate(NULL));
  3831. xmlXPathNodeSetSort(nodes1);
  3832. xmlXPathNodeSetSort(nodes2);
  3833. return(xmlXPathNodeTrailingSorted(nodes1,
  3834. xmlXPathNodeSetItem(nodes2, 0)));
  3835. }
  3836. /************************************************************************
  3837. * *
  3838. * Routines to handle extra functions *
  3839. * *
  3840. ************************************************************************/
  3841. /**
  3842. * xmlXPathRegisterFunc:
  3843. * @ctxt: the XPath context
  3844. * @name: the function name
  3845. * @f: the function implementation or NULL
  3846. *
  3847. * Register a new function. If @f is NULL it unregisters the function
  3848. *
  3849. * Returns 0 in case of success, -1 in case of error
  3850. */
  3851. int
  3852. xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
  3853. xmlXPathFunction f) {
  3854. return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
  3855. }
  3856. /**
  3857. * xmlXPathRegisterFuncNS:
  3858. * @ctxt: the XPath context
  3859. * @name: the function name
  3860. * @ns_uri: the function namespace URI
  3861. * @f: the function implementation or NULL
  3862. *
  3863. * Register a new function. If @f is NULL it unregisters the function
  3864. *
  3865. * Returns 0 in case of success, -1 in case of error
  3866. */
  3867. int
  3868. xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
  3869. const xmlChar *ns_uri, xmlXPathFunction f) {
  3870. if (ctxt == NULL)
  3871. return(-1);
  3872. if (name == NULL)
  3873. return(-1);
  3874. if (ctxt->funcHash == NULL)
  3875. ctxt->funcHash = xmlHashCreate(0);
  3876. if (ctxt->funcHash == NULL)
  3877. return(-1);
  3878. if (f == NULL)
  3879. return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
  3880. XML_IGNORE_FPTR_CAST_WARNINGS
  3881. return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
  3882. XML_POP_WARNINGS
  3883. }
  3884. /**
  3885. * xmlXPathRegisterFuncLookup:
  3886. * @ctxt: the XPath context
  3887. * @f: the lookup function
  3888. * @funcCtxt: the lookup data
  3889. *
  3890. * Registers an external mechanism to do function lookup.
  3891. */
  3892. void
  3893. xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
  3894. xmlXPathFuncLookupFunc f,
  3895. void *funcCtxt) {
  3896. if (ctxt == NULL)
  3897. return;
  3898. ctxt->funcLookupFunc = f;
  3899. ctxt->funcLookupData = funcCtxt;
  3900. }
  3901. /**
  3902. * xmlXPathFunctionLookup:
  3903. * @ctxt: the XPath context
  3904. * @name: the function name
  3905. *
  3906. * Search in the Function array of the context for the given
  3907. * function.
  3908. *
  3909. * Returns the xmlXPathFunction or NULL if not found
  3910. */
  3911. xmlXPathFunction
  3912. xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
  3913. if (ctxt == NULL)
  3914. return (NULL);
  3915. if (ctxt->funcLookupFunc != NULL) {
  3916. xmlXPathFunction ret;
  3917. xmlXPathFuncLookupFunc f;
  3918. f = ctxt->funcLookupFunc;
  3919. ret = f(ctxt->funcLookupData, name, NULL);
  3920. if (ret != NULL)
  3921. return(ret);
  3922. }
  3923. return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
  3924. }
  3925. /**
  3926. * xmlXPathFunctionLookupNS:
  3927. * @ctxt: the XPath context
  3928. * @name: the function name
  3929. * @ns_uri: the function namespace URI
  3930. *
  3931. * Search in the Function array of the context for the given
  3932. * function.
  3933. *
  3934. * Returns the xmlXPathFunction or NULL if not found
  3935. */
  3936. xmlXPathFunction
  3937. xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
  3938. const xmlChar *ns_uri) {
  3939. xmlXPathFunction ret;
  3940. if (ctxt == NULL)
  3941. return(NULL);
  3942. if (name == NULL)
  3943. return(NULL);
  3944. if (ctxt->funcLookupFunc != NULL) {
  3945. xmlXPathFuncLookupFunc f;
  3946. f = ctxt->funcLookupFunc;
  3947. ret = f(ctxt->funcLookupData, name, ns_uri);
  3948. if (ret != NULL)
  3949. return(ret);
  3950. }
  3951. if (ctxt->funcHash == NULL)
  3952. return(NULL);
  3953. XML_IGNORE_FPTR_CAST_WARNINGS
  3954. ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
  3955. XML_POP_WARNINGS
  3956. return(ret);
  3957. }
  3958. /**
  3959. * xmlXPathRegisteredFuncsCleanup:
  3960. * @ctxt: the XPath context
  3961. *
  3962. * Cleanup the XPath context data associated to registered functions
  3963. */
  3964. void
  3965. xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
  3966. if (ctxt == NULL)
  3967. return;
  3968. xmlHashFree(ctxt->funcHash, NULL);
  3969. ctxt->funcHash = NULL;
  3970. }
  3971. /************************************************************************
  3972. * *
  3973. * Routines to handle Variables *
  3974. * *
  3975. ************************************************************************/
  3976. /**
  3977. * xmlXPathRegisterVariable:
  3978. * @ctxt: the XPath context
  3979. * @name: the variable name
  3980. * @value: the variable value or NULL
  3981. *
  3982. * Register a new variable value. If @value is NULL it unregisters
  3983. * the variable
  3984. *
  3985. * Returns 0 in case of success, -1 in case of error
  3986. */
  3987. int
  3988. xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
  3989. xmlXPathObjectPtr value) {
  3990. return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
  3991. }
  3992. /**
  3993. * xmlXPathRegisterVariableNS:
  3994. * @ctxt: the XPath context
  3995. * @name: the variable name
  3996. * @ns_uri: the variable namespace URI
  3997. * @value: the variable value or NULL
  3998. *
  3999. * Register a new variable value. If @value is NULL it unregisters
  4000. * the variable
  4001. *
  4002. * Returns 0 in case of success, -1 in case of error
  4003. */
  4004. int
  4005. xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
  4006. const xmlChar *ns_uri,
  4007. xmlXPathObjectPtr value) {
  4008. if (ctxt == NULL)
  4009. return(-1);
  4010. if (name == NULL)
  4011. return(-1);
  4012. if (ctxt->varHash == NULL)
  4013. ctxt->varHash = xmlHashCreate(0);
  4014. if (ctxt->varHash == NULL)
  4015. return(-1);
  4016. if (value == NULL)
  4017. return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
  4018. xmlXPathFreeObjectEntry));
  4019. return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
  4020. (void *) value, xmlXPathFreeObjectEntry));
  4021. }
  4022. /**
  4023. * xmlXPathRegisterVariableLookup:
  4024. * @ctxt: the XPath context
  4025. * @f: the lookup function
  4026. * @data: the lookup data
  4027. *
  4028. * register an external mechanism to do variable lookup
  4029. */
  4030. void
  4031. xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
  4032. xmlXPathVariableLookupFunc f, void *data) {
  4033. if (ctxt == NULL)
  4034. return;
  4035. ctxt->varLookupFunc = f;
  4036. ctxt->varLookupData = data;
  4037. }
  4038. /**
  4039. * xmlXPathVariableLookup:
  4040. * @ctxt: the XPath context
  4041. * @name: the variable name
  4042. *
  4043. * Search in the Variable array of the context for the given
  4044. * variable value.
  4045. *
  4046. * Returns a copy of the value or NULL if not found
  4047. */
  4048. xmlXPathObjectPtr
  4049. xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
  4050. if (ctxt == NULL)
  4051. return(NULL);
  4052. if (ctxt->varLookupFunc != NULL) {
  4053. xmlXPathObjectPtr ret;
  4054. ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
  4055. (ctxt->varLookupData, name, NULL);
  4056. return(ret);
  4057. }
  4058. return(xmlXPathVariableLookupNS(ctxt, name, NULL));
  4059. }
  4060. /**
  4061. * xmlXPathVariableLookupNS:
  4062. * @ctxt: the XPath context
  4063. * @name: the variable name
  4064. * @ns_uri: the variable namespace URI
  4065. *
  4066. * Search in the Variable array of the context for the given
  4067. * variable value.
  4068. *
  4069. * Returns the a copy of the value or NULL if not found
  4070. */
  4071. xmlXPathObjectPtr
  4072. xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
  4073. const xmlChar *ns_uri) {
  4074. if (ctxt == NULL)
  4075. return(NULL);
  4076. if (ctxt->varLookupFunc != NULL) {
  4077. xmlXPathObjectPtr ret;
  4078. ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
  4079. (ctxt->varLookupData, name, ns_uri);
  4080. if (ret != NULL) return(ret);
  4081. }
  4082. if (ctxt->varHash == NULL)
  4083. return(NULL);
  4084. if (name == NULL)
  4085. return(NULL);
  4086. return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
  4087. xmlHashLookup2(ctxt->varHash, name, ns_uri)));
  4088. }
  4089. /**
  4090. * xmlXPathRegisteredVariablesCleanup:
  4091. * @ctxt: the XPath context
  4092. *
  4093. * Cleanup the XPath context data associated to registered variables
  4094. */
  4095. void
  4096. xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
  4097. if (ctxt == NULL)
  4098. return;
  4099. xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
  4100. ctxt->varHash = NULL;
  4101. }
  4102. /**
  4103. * xmlXPathRegisterNs:
  4104. * @ctxt: the XPath context
  4105. * @prefix: the namespace prefix cannot be NULL or empty string
  4106. * @ns_uri: the namespace name
  4107. *
  4108. * Register a new namespace. If @ns_uri is NULL it unregisters
  4109. * the namespace
  4110. *
  4111. * Returns 0 in case of success, -1 in case of error
  4112. */
  4113. int
  4114. xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
  4115. const xmlChar *ns_uri) {
  4116. xmlChar *copy;
  4117. if (ctxt == NULL)
  4118. return(-1);
  4119. if (prefix == NULL)
  4120. return(-1);
  4121. if (prefix[0] == 0)
  4122. return(-1);
  4123. if (ctxt->nsHash == NULL)
  4124. ctxt->nsHash = xmlHashCreate(10);
  4125. if (ctxt->nsHash == NULL)
  4126. return(-1);
  4127. if (ns_uri == NULL)
  4128. return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
  4129. xmlHashDefaultDeallocator));
  4130. copy = xmlStrdup(ns_uri);
  4131. if (copy == NULL)
  4132. return(-1);
  4133. if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
  4134. xmlHashDefaultDeallocator) < 0) {
  4135. xmlFree(copy);
  4136. return(-1);
  4137. }
  4138. return(0);
  4139. }
  4140. /**
  4141. * xmlXPathNsLookup:
  4142. * @ctxt: the XPath context
  4143. * @prefix: the namespace prefix value
  4144. *
  4145. * Search in the namespace declaration array of the context for the given
  4146. * namespace name associated to the given prefix
  4147. *
  4148. * Returns the value or NULL if not found
  4149. */
  4150. const xmlChar *
  4151. xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
  4152. if (ctxt == NULL)
  4153. return(NULL);
  4154. if (prefix == NULL)
  4155. return(NULL);
  4156. #ifdef XML_XML_NAMESPACE
  4157. if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
  4158. return(XML_XML_NAMESPACE);
  4159. #endif
  4160. if (ctxt->namespaces != NULL) {
  4161. int i;
  4162. for (i = 0;i < ctxt->nsNr;i++) {
  4163. if ((ctxt->namespaces[i] != NULL) &&
  4164. (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
  4165. return(ctxt->namespaces[i]->href);
  4166. }
  4167. }
  4168. return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
  4169. }
  4170. /**
  4171. * xmlXPathRegisteredNsCleanup:
  4172. * @ctxt: the XPath context
  4173. *
  4174. * Cleanup the XPath context data associated to registered variables
  4175. */
  4176. void
  4177. xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
  4178. if (ctxt == NULL)
  4179. return;
  4180. xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
  4181. ctxt->nsHash = NULL;
  4182. }
  4183. /************************************************************************
  4184. * *
  4185. * Routines to handle Values *
  4186. * *
  4187. ************************************************************************/
  4188. /* Allocations are terrible, one needs to optimize all this !!! */
  4189. /**
  4190. * xmlXPathNewFloat:
  4191. * @val: the double value
  4192. *
  4193. * Create a new xmlXPathObjectPtr of type double and of value @val
  4194. *
  4195. * Returns the newly created object.
  4196. */
  4197. xmlXPathObjectPtr
  4198. xmlXPathNewFloat(double val) {
  4199. xmlXPathObjectPtr ret;
  4200. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4201. if (ret == NULL) {
  4202. xmlXPathErrMemory(NULL, "creating float object\n");
  4203. return(NULL);
  4204. }
  4205. memset(ret, 0 , sizeof(xmlXPathObject));
  4206. ret->type = XPATH_NUMBER;
  4207. ret->floatval = val;
  4208. return(ret);
  4209. }
  4210. /**
  4211. * xmlXPathNewBoolean:
  4212. * @val: the boolean value
  4213. *
  4214. * Create a new xmlXPathObjectPtr of type boolean and of value @val
  4215. *
  4216. * Returns the newly created object.
  4217. */
  4218. xmlXPathObjectPtr
  4219. xmlXPathNewBoolean(int val) {
  4220. xmlXPathObjectPtr ret;
  4221. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4222. if (ret == NULL) {
  4223. xmlXPathErrMemory(NULL, "creating boolean object\n");
  4224. return(NULL);
  4225. }
  4226. memset(ret, 0 , sizeof(xmlXPathObject));
  4227. ret->type = XPATH_BOOLEAN;
  4228. ret->boolval = (val != 0);
  4229. return(ret);
  4230. }
  4231. /**
  4232. * xmlXPathNewString:
  4233. * @val: the xmlChar * value
  4234. *
  4235. * Create a new xmlXPathObjectPtr of type string and of value @val
  4236. *
  4237. * Returns the newly created object.
  4238. */
  4239. xmlXPathObjectPtr
  4240. xmlXPathNewString(const xmlChar *val) {
  4241. xmlXPathObjectPtr ret;
  4242. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4243. if (ret == NULL) {
  4244. xmlXPathErrMemory(NULL, "creating string object\n");
  4245. return(NULL);
  4246. }
  4247. memset(ret, 0 , sizeof(xmlXPathObject));
  4248. ret->type = XPATH_STRING;
  4249. if (val == NULL)
  4250. val = BAD_CAST "";
  4251. ret->stringval = xmlStrdup(val);
  4252. if (ret->stringval == NULL) {
  4253. xmlFree(ret);
  4254. return(NULL);
  4255. }
  4256. return(ret);
  4257. }
  4258. /**
  4259. * xmlXPathWrapString:
  4260. * @val: the xmlChar * value
  4261. *
  4262. * Wraps the @val string into an XPath object.
  4263. *
  4264. * Returns the newly created object.
  4265. *
  4266. * Frees @val in case of error.
  4267. */
  4268. xmlXPathObjectPtr
  4269. xmlXPathWrapString (xmlChar *val) {
  4270. xmlXPathObjectPtr ret;
  4271. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4272. if (ret == NULL) {
  4273. xmlXPathErrMemory(NULL, "creating string object\n");
  4274. xmlFree(val);
  4275. return(NULL);
  4276. }
  4277. memset(ret, 0 , sizeof(xmlXPathObject));
  4278. ret->type = XPATH_STRING;
  4279. ret->stringval = val;
  4280. return(ret);
  4281. }
  4282. /**
  4283. * xmlXPathNewCString:
  4284. * @val: the char * value
  4285. *
  4286. * Create a new xmlXPathObjectPtr of type string and of value @val
  4287. *
  4288. * Returns the newly created object.
  4289. */
  4290. xmlXPathObjectPtr
  4291. xmlXPathNewCString(const char *val) {
  4292. return(xmlXPathNewString(BAD_CAST val));
  4293. }
  4294. /**
  4295. * xmlXPathWrapCString:
  4296. * @val: the char * value
  4297. *
  4298. * Wraps a string into an XPath object.
  4299. *
  4300. * Returns the newly created object.
  4301. */
  4302. xmlXPathObjectPtr
  4303. xmlXPathWrapCString (char * val) {
  4304. return(xmlXPathWrapString((xmlChar *)(val)));
  4305. }
  4306. /**
  4307. * xmlXPathWrapExternal:
  4308. * @val: the user data
  4309. *
  4310. * Wraps the @val data into an XPath object.
  4311. *
  4312. * Returns the newly created object.
  4313. */
  4314. xmlXPathObjectPtr
  4315. xmlXPathWrapExternal (void *val) {
  4316. xmlXPathObjectPtr ret;
  4317. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4318. if (ret == NULL) {
  4319. xmlXPathErrMemory(NULL, "creating user object\n");
  4320. return(NULL);
  4321. }
  4322. memset(ret, 0 , sizeof(xmlXPathObject));
  4323. ret->type = XPATH_USERS;
  4324. ret->user = val;
  4325. return(ret);
  4326. }
  4327. /**
  4328. * xmlXPathObjectCopy:
  4329. * @val: the original object
  4330. *
  4331. * allocate a new copy of a given object
  4332. *
  4333. * Returns the newly created object.
  4334. */
  4335. xmlXPathObjectPtr
  4336. xmlXPathObjectCopy(xmlXPathObjectPtr val) {
  4337. xmlXPathObjectPtr ret;
  4338. if (val == NULL)
  4339. return(NULL);
  4340. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4341. if (ret == NULL) {
  4342. xmlXPathErrMemory(NULL, "copying object\n");
  4343. return(NULL);
  4344. }
  4345. memcpy(ret, val , sizeof(xmlXPathObject));
  4346. switch (val->type) {
  4347. case XPATH_BOOLEAN:
  4348. case XPATH_NUMBER:
  4349. #ifdef LIBXML_XPTR_LOCS_ENABLED
  4350. case XPATH_POINT:
  4351. case XPATH_RANGE:
  4352. #endif /* LIBXML_XPTR_LOCS_ENABLED */
  4353. break;
  4354. case XPATH_STRING:
  4355. ret->stringval = xmlStrdup(val->stringval);
  4356. if (ret->stringval == NULL) {
  4357. xmlFree(ret);
  4358. return(NULL);
  4359. }
  4360. break;
  4361. case XPATH_XSLT_TREE:
  4362. #if 0
  4363. /*
  4364. Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
  4365. this previous handling is no longer correct, and can cause some serious
  4366. problems (ref. bug 145547)
  4367. */
  4368. if ((val->nodesetval != NULL) &&
  4369. (val->nodesetval->nodeTab != NULL)) {
  4370. xmlNodePtr cur, tmp;
  4371. xmlDocPtr top;
  4372. ret->boolval = 1;
  4373. top = xmlNewDoc(NULL);
  4374. top->name = (char *)
  4375. xmlStrdup(val->nodesetval->nodeTab[0]->name);
  4376. ret->user = top;
  4377. if (top != NULL) {
  4378. top->doc = top;
  4379. cur = val->nodesetval->nodeTab[0]->children;
  4380. while (cur != NULL) {
  4381. tmp = xmlDocCopyNode(cur, top, 1);
  4382. xmlAddChild((xmlNodePtr) top, tmp);
  4383. cur = cur->next;
  4384. }
  4385. }
  4386. ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
  4387. } else
  4388. ret->nodesetval = xmlXPathNodeSetCreate(NULL);
  4389. /* Deallocate the copied tree value */
  4390. break;
  4391. #endif
  4392. case XPATH_NODESET:
  4393. /* TODO: Check memory error. */
  4394. ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
  4395. /* Do not deallocate the copied tree value */
  4396. ret->boolval = 0;
  4397. break;
  4398. #ifdef LIBXML_XPTR_LOCS_ENABLED
  4399. case XPATH_LOCATIONSET:
  4400. {
  4401. xmlLocationSetPtr loc = val->user;
  4402. ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
  4403. break;
  4404. }
  4405. #endif
  4406. case XPATH_USERS:
  4407. ret->user = val->user;
  4408. break;
  4409. case XPATH_UNDEFINED:
  4410. xmlGenericError(xmlGenericErrorContext,
  4411. "xmlXPathObjectCopy: unsupported type %d\n",
  4412. val->type);
  4413. break;
  4414. }
  4415. return(ret);
  4416. }
  4417. /**
  4418. * xmlXPathFreeObject:
  4419. * @obj: the object to free
  4420. *
  4421. * Free up an xmlXPathObjectPtr object.
  4422. */
  4423. void
  4424. xmlXPathFreeObject(xmlXPathObjectPtr obj) {
  4425. if (obj == NULL) return;
  4426. if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
  4427. if (obj->boolval) {
  4428. #if 0
  4429. if (obj->user != NULL) {
  4430. xmlXPathFreeNodeSet(obj->nodesetval);
  4431. xmlFreeNodeList((xmlNodePtr) obj->user);
  4432. } else
  4433. #endif
  4434. obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
  4435. if (obj->nodesetval != NULL)
  4436. xmlXPathFreeValueTree(obj->nodesetval);
  4437. } else {
  4438. if (obj->nodesetval != NULL)
  4439. xmlXPathFreeNodeSet(obj->nodesetval);
  4440. }
  4441. #ifdef LIBXML_XPTR_LOCS_ENABLED
  4442. } else if (obj->type == XPATH_LOCATIONSET) {
  4443. if (obj->user != NULL)
  4444. xmlXPtrFreeLocationSet(obj->user);
  4445. #endif
  4446. } else if (obj->type == XPATH_STRING) {
  4447. if (obj->stringval != NULL)
  4448. xmlFree(obj->stringval);
  4449. }
  4450. xmlFree(obj);
  4451. }
  4452. static void
  4453. xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
  4454. xmlXPathFreeObject((xmlXPathObjectPtr) obj);
  4455. }
  4456. /**
  4457. * xmlXPathReleaseObject:
  4458. * @obj: the xmlXPathObjectPtr to free or to cache
  4459. *
  4460. * Depending on the state of the cache this frees the given
  4461. * XPath object or stores it in the cache.
  4462. */
  4463. static void
  4464. xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
  4465. {
  4466. #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
  4467. sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
  4468. if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
  4469. #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
  4470. if (obj == NULL)
  4471. return;
  4472. if ((ctxt == NULL) || (ctxt->cache == NULL)) {
  4473. xmlXPathFreeObject(obj);
  4474. } else {
  4475. xmlXPathContextCachePtr cache =
  4476. (xmlXPathContextCachePtr) ctxt->cache;
  4477. switch (obj->type) {
  4478. case XPATH_NODESET:
  4479. case XPATH_XSLT_TREE:
  4480. if (obj->nodesetval != NULL) {
  4481. if (obj->boolval) {
  4482. /*
  4483. * It looks like the @boolval is used for
  4484. * evaluation if this an XSLT Result Tree Fragment.
  4485. * TODO: Check if this assumption is correct.
  4486. */
  4487. obj->type = XPATH_XSLT_TREE; /* just for debugging */
  4488. xmlXPathFreeValueTree(obj->nodesetval);
  4489. obj->nodesetval = NULL;
  4490. } else if ((obj->nodesetval->nodeMax <= 40) &&
  4491. (XP_CACHE_WANTS(cache->nodesetObjs,
  4492. cache->maxNodeset)))
  4493. {
  4494. XP_CACHE_ADD(cache->nodesetObjs, obj);
  4495. goto obj_cached;
  4496. } else {
  4497. xmlXPathFreeNodeSet(obj->nodesetval);
  4498. obj->nodesetval = NULL;
  4499. }
  4500. }
  4501. break;
  4502. case XPATH_STRING:
  4503. if (obj->stringval != NULL)
  4504. xmlFree(obj->stringval);
  4505. if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
  4506. XP_CACHE_ADD(cache->stringObjs, obj);
  4507. goto obj_cached;
  4508. }
  4509. break;
  4510. case XPATH_BOOLEAN:
  4511. if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
  4512. XP_CACHE_ADD(cache->booleanObjs, obj);
  4513. goto obj_cached;
  4514. }
  4515. break;
  4516. case XPATH_NUMBER:
  4517. if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
  4518. XP_CACHE_ADD(cache->numberObjs, obj);
  4519. goto obj_cached;
  4520. }
  4521. break;
  4522. #ifdef LIBXML_XPTR_LOCS_ENABLED
  4523. case XPATH_LOCATIONSET:
  4524. if (obj->user != NULL) {
  4525. xmlXPtrFreeLocationSet(obj->user);
  4526. }
  4527. goto free_obj;
  4528. #endif
  4529. default:
  4530. goto free_obj;
  4531. }
  4532. /*
  4533. * Fallback to adding to the misc-objects slot.
  4534. */
  4535. if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
  4536. XP_CACHE_ADD(cache->miscObjs, obj);
  4537. } else
  4538. goto free_obj;
  4539. obj_cached:
  4540. if (obj->nodesetval != NULL) {
  4541. xmlNodeSetPtr tmpset = obj->nodesetval;
  4542. /*
  4543. * TODO: Due to those nasty ns-nodes, we need to traverse
  4544. * the list and free the ns-nodes.
  4545. * URGENT TODO: Check if it's actually slowing things down.
  4546. * Maybe we shouldn't try to preserve the list.
  4547. */
  4548. if (tmpset->nodeNr > 1) {
  4549. int i;
  4550. xmlNodePtr node;
  4551. for (i = 0; i < tmpset->nodeNr; i++) {
  4552. node = tmpset->nodeTab[i];
  4553. if ((node != NULL) &&
  4554. (node->type == XML_NAMESPACE_DECL))
  4555. {
  4556. xmlXPathNodeSetFreeNs((xmlNsPtr) node);
  4557. }
  4558. }
  4559. } else if (tmpset->nodeNr == 1) {
  4560. if ((tmpset->nodeTab[0] != NULL) &&
  4561. (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
  4562. xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
  4563. }
  4564. tmpset->nodeNr = 0;
  4565. memset(obj, 0, sizeof(xmlXPathObject));
  4566. obj->nodesetval = tmpset;
  4567. } else
  4568. memset(obj, 0, sizeof(xmlXPathObject));
  4569. return;
  4570. free_obj:
  4571. /*
  4572. * Cache is full; free the object.
  4573. */
  4574. if (obj->nodesetval != NULL)
  4575. xmlXPathFreeNodeSet(obj->nodesetval);
  4576. xmlFree(obj);
  4577. }
  4578. return;
  4579. }
  4580. /************************************************************************
  4581. * *
  4582. * Type Casting Routines *
  4583. * *
  4584. ************************************************************************/
  4585. /**
  4586. * xmlXPathCastBooleanToString:
  4587. * @val: a boolean
  4588. *
  4589. * Converts a boolean to its string value.
  4590. *
  4591. * Returns a newly allocated string.
  4592. */
  4593. xmlChar *
  4594. xmlXPathCastBooleanToString (int val) {
  4595. xmlChar *ret;
  4596. if (val)
  4597. ret = xmlStrdup((const xmlChar *) "true");
  4598. else
  4599. ret = xmlStrdup((const xmlChar *) "false");
  4600. return(ret);
  4601. }
  4602. /**
  4603. * xmlXPathCastNumberToString:
  4604. * @val: a number
  4605. *
  4606. * Converts a number to its string value.
  4607. *
  4608. * Returns a newly allocated string.
  4609. */
  4610. xmlChar *
  4611. xmlXPathCastNumberToString (double val) {
  4612. xmlChar *ret;
  4613. switch (xmlXPathIsInf(val)) {
  4614. case 1:
  4615. ret = xmlStrdup((const xmlChar *) "Infinity");
  4616. break;
  4617. case -1:
  4618. ret = xmlStrdup((const xmlChar *) "-Infinity");
  4619. break;
  4620. default:
  4621. if (xmlXPathIsNaN(val)) {
  4622. ret = xmlStrdup((const xmlChar *) "NaN");
  4623. } else if (val == 0) {
  4624. /* Omit sign for negative zero. */
  4625. ret = xmlStrdup((const xmlChar *) "0");
  4626. } else {
  4627. /* could be improved */
  4628. char buf[100];
  4629. xmlXPathFormatNumber(val, buf, 99);
  4630. buf[99] = 0;
  4631. ret = xmlStrdup((const xmlChar *) buf);
  4632. }
  4633. }
  4634. return(ret);
  4635. }
  4636. /**
  4637. * xmlXPathCastNodeToString:
  4638. * @node: a node
  4639. *
  4640. * Converts a node to its string value.
  4641. *
  4642. * Returns a newly allocated string.
  4643. */
  4644. xmlChar *
  4645. xmlXPathCastNodeToString (xmlNodePtr node) {
  4646. xmlChar *ret;
  4647. if ((ret = xmlNodeGetContent(node)) == NULL)
  4648. ret = xmlStrdup((const xmlChar *) "");
  4649. return(ret);
  4650. }
  4651. /**
  4652. * xmlXPathCastNodeSetToString:
  4653. * @ns: a node-set
  4654. *
  4655. * Converts a node-set to its string value.
  4656. *
  4657. * Returns a newly allocated string.
  4658. */
  4659. xmlChar *
  4660. xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
  4661. if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
  4662. return(xmlStrdup((const xmlChar *) ""));
  4663. if (ns->nodeNr > 1)
  4664. xmlXPathNodeSetSort(ns);
  4665. return(xmlXPathCastNodeToString(ns->nodeTab[0]));
  4666. }
  4667. /**
  4668. * xmlXPathCastToString:
  4669. * @val: an XPath object
  4670. *
  4671. * Converts an existing object to its string() equivalent
  4672. *
  4673. * Returns the allocated string value of the object, NULL in case of error.
  4674. * It's up to the caller to free the string memory with xmlFree().
  4675. */
  4676. xmlChar *
  4677. xmlXPathCastToString(xmlXPathObjectPtr val) {
  4678. xmlChar *ret = NULL;
  4679. if (val == NULL)
  4680. return(xmlStrdup((const xmlChar *) ""));
  4681. switch (val->type) {
  4682. case XPATH_UNDEFINED:
  4683. ret = xmlStrdup((const xmlChar *) "");
  4684. break;
  4685. case XPATH_NODESET:
  4686. case XPATH_XSLT_TREE:
  4687. ret = xmlXPathCastNodeSetToString(val->nodesetval);
  4688. break;
  4689. case XPATH_STRING:
  4690. return(xmlStrdup(val->stringval));
  4691. case XPATH_BOOLEAN:
  4692. ret = xmlXPathCastBooleanToString(val->boolval);
  4693. break;
  4694. case XPATH_NUMBER: {
  4695. ret = xmlXPathCastNumberToString(val->floatval);
  4696. break;
  4697. }
  4698. case XPATH_USERS:
  4699. #ifdef LIBXML_XPTR_LOCS_ENABLED
  4700. case XPATH_POINT:
  4701. case XPATH_RANGE:
  4702. case XPATH_LOCATIONSET:
  4703. #endif /* LIBXML_XPTR_LOCS_ENABLED */
  4704. TODO
  4705. ret = xmlStrdup((const xmlChar *) "");
  4706. break;
  4707. }
  4708. return(ret);
  4709. }
  4710. /**
  4711. * xmlXPathConvertString:
  4712. * @val: an XPath object
  4713. *
  4714. * Converts an existing object to its string() equivalent
  4715. *
  4716. * Returns the new object, the old one is freed (or the operation
  4717. * is done directly on @val)
  4718. */
  4719. xmlXPathObjectPtr
  4720. xmlXPathConvertString(xmlXPathObjectPtr val) {
  4721. xmlChar *res = NULL;
  4722. if (val == NULL)
  4723. return(xmlXPathNewCString(""));
  4724. switch (val->type) {
  4725. case XPATH_UNDEFINED:
  4726. break;
  4727. case XPATH_NODESET:
  4728. case XPATH_XSLT_TREE:
  4729. res = xmlXPathCastNodeSetToString(val->nodesetval);
  4730. break;
  4731. case XPATH_STRING:
  4732. return(val);
  4733. case XPATH_BOOLEAN:
  4734. res = xmlXPathCastBooleanToString(val->boolval);
  4735. break;
  4736. case XPATH_NUMBER:
  4737. res = xmlXPathCastNumberToString(val->floatval);
  4738. break;
  4739. case XPATH_USERS:
  4740. #ifdef LIBXML_XPTR_LOCS_ENABLED
  4741. case XPATH_POINT:
  4742. case XPATH_RANGE:
  4743. case XPATH_LOCATIONSET:
  4744. #endif /* LIBXML_XPTR_LOCS_ENABLED */
  4745. TODO;
  4746. break;
  4747. }
  4748. xmlXPathFreeObject(val);
  4749. if (res == NULL)
  4750. return(xmlXPathNewCString(""));
  4751. return(xmlXPathWrapString(res));
  4752. }
  4753. /**
  4754. * xmlXPathCastBooleanToNumber:
  4755. * @val: a boolean
  4756. *
  4757. * Converts a boolean to its number value
  4758. *
  4759. * Returns the number value
  4760. */
  4761. double
  4762. xmlXPathCastBooleanToNumber(int val) {
  4763. if (val)
  4764. return(1.0);
  4765. return(0.0);
  4766. }
  4767. /**
  4768. * xmlXPathCastStringToNumber:
  4769. * @val: a string
  4770. *
  4771. * Converts a string to its number value
  4772. *
  4773. * Returns the number value
  4774. */
  4775. double
  4776. xmlXPathCastStringToNumber(const xmlChar * val) {
  4777. return(xmlXPathStringEvalNumber(val));
  4778. }
  4779. /**
  4780. * xmlXPathCastNodeToNumber:
  4781. * @node: a node
  4782. *
  4783. * Converts a node to its number value
  4784. *
  4785. * Returns the number value
  4786. */
  4787. double
  4788. xmlXPathCastNodeToNumber (xmlNodePtr node) {
  4789. xmlChar *strval;
  4790. double ret;
  4791. if (node == NULL)
  4792. return(xmlXPathNAN);
  4793. strval = xmlXPathCastNodeToString(node);
  4794. if (strval == NULL)
  4795. return(xmlXPathNAN);
  4796. ret = xmlXPathCastStringToNumber(strval);
  4797. xmlFree(strval);
  4798. return(ret);
  4799. }
  4800. /**
  4801. * xmlXPathCastNodeSetToNumber:
  4802. * @ns: a node-set
  4803. *
  4804. * Converts a node-set to its number value
  4805. *
  4806. * Returns the number value
  4807. */
  4808. double
  4809. xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
  4810. xmlChar *str;
  4811. double ret;
  4812. if (ns == NULL)
  4813. return(xmlXPathNAN);
  4814. str = xmlXPathCastNodeSetToString(ns);
  4815. ret = xmlXPathCastStringToNumber(str);
  4816. xmlFree(str);
  4817. return(ret);
  4818. }
  4819. /**
  4820. * xmlXPathCastToNumber:
  4821. * @val: an XPath object
  4822. *
  4823. * Converts an XPath object to its number value
  4824. *
  4825. * Returns the number value
  4826. */
  4827. double
  4828. xmlXPathCastToNumber(xmlXPathObjectPtr val) {
  4829. double ret = 0.0;
  4830. if (val == NULL)
  4831. return(xmlXPathNAN);
  4832. switch (val->type) {
  4833. case XPATH_UNDEFINED:
  4834. ret = xmlXPathNAN;
  4835. break;
  4836. case XPATH_NODESET:
  4837. case XPATH_XSLT_TREE:
  4838. ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
  4839. break;
  4840. case XPATH_STRING:
  4841. ret = xmlXPathCastStringToNumber(val->stringval);
  4842. break;
  4843. case XPATH_NUMBER:
  4844. ret = val->floatval;
  4845. break;
  4846. case XPATH_BOOLEAN:
  4847. ret = xmlXPathCastBooleanToNumber(val->boolval);
  4848. break;
  4849. case XPATH_USERS:
  4850. #ifdef LIBXML_XPTR_LOCS_ENABLED
  4851. case XPATH_POINT:
  4852. case XPATH_RANGE:
  4853. case XPATH_LOCATIONSET:
  4854. #endif /* LIBXML_XPTR_LOCS_ENABLED */
  4855. TODO;
  4856. ret = xmlXPathNAN;
  4857. break;
  4858. }
  4859. return(ret);
  4860. }
  4861. /**
  4862. * xmlXPathConvertNumber:
  4863. * @val: an XPath object
  4864. *
  4865. * Converts an existing object to its number() equivalent
  4866. *
  4867. * Returns the new object, the old one is freed (or the operation
  4868. * is done directly on @val)
  4869. */
  4870. xmlXPathObjectPtr
  4871. xmlXPathConvertNumber(xmlXPathObjectPtr val) {
  4872. xmlXPathObjectPtr ret;
  4873. if (val == NULL)
  4874. return(xmlXPathNewFloat(0.0));
  4875. if (val->type == XPATH_NUMBER)
  4876. return(val);
  4877. ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
  4878. xmlXPathFreeObject(val);
  4879. return(ret);
  4880. }
  4881. /**
  4882. * xmlXPathCastNumberToBoolean:
  4883. * @val: a number
  4884. *
  4885. * Converts a number to its boolean value
  4886. *
  4887. * Returns the boolean value
  4888. */
  4889. int
  4890. xmlXPathCastNumberToBoolean (double val) {
  4891. if (xmlXPathIsNaN(val) || (val == 0.0))
  4892. return(0);
  4893. return(1);
  4894. }
  4895. /**
  4896. * xmlXPathCastStringToBoolean:
  4897. * @val: a string
  4898. *
  4899. * Converts a string to its boolean value
  4900. *
  4901. * Returns the boolean value
  4902. */
  4903. int
  4904. xmlXPathCastStringToBoolean (const xmlChar *val) {
  4905. if ((val == NULL) || (xmlStrlen(val) == 0))
  4906. return(0);
  4907. return(1);
  4908. }
  4909. /**
  4910. * xmlXPathCastNodeSetToBoolean:
  4911. * @ns: a node-set
  4912. *
  4913. * Converts a node-set to its boolean value
  4914. *
  4915. * Returns the boolean value
  4916. */
  4917. int
  4918. xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
  4919. if ((ns == NULL) || (ns->nodeNr == 0))
  4920. return(0);
  4921. return(1);
  4922. }
  4923. /**
  4924. * xmlXPathCastToBoolean:
  4925. * @val: an XPath object
  4926. *
  4927. * Converts an XPath object to its boolean value
  4928. *
  4929. * Returns the boolean value
  4930. */
  4931. int
  4932. xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
  4933. int ret = 0;
  4934. if (val == NULL)
  4935. return(0);
  4936. switch (val->type) {
  4937. case XPATH_UNDEFINED:
  4938. ret = 0;
  4939. break;
  4940. case XPATH_NODESET:
  4941. case XPATH_XSLT_TREE:
  4942. ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
  4943. break;
  4944. case XPATH_STRING:
  4945. ret = xmlXPathCastStringToBoolean(val->stringval);
  4946. break;
  4947. case XPATH_NUMBER:
  4948. ret = xmlXPathCastNumberToBoolean(val->floatval);
  4949. break;
  4950. case XPATH_BOOLEAN:
  4951. ret = val->boolval;
  4952. break;
  4953. case XPATH_USERS:
  4954. #ifdef LIBXML_XPTR_LOCS_ENABLED
  4955. case XPATH_POINT:
  4956. case XPATH_RANGE:
  4957. case XPATH_LOCATIONSET:
  4958. #endif /* LIBXML_XPTR_LOCS_ENABLED */
  4959. TODO;
  4960. ret = 0;
  4961. break;
  4962. }
  4963. return(ret);
  4964. }
  4965. /**
  4966. * xmlXPathConvertBoolean:
  4967. * @val: an XPath object
  4968. *
  4969. * Converts an existing object to its boolean() equivalent
  4970. *
  4971. * Returns the new object, the old one is freed (or the operation
  4972. * is done directly on @val)
  4973. */
  4974. xmlXPathObjectPtr
  4975. xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
  4976. xmlXPathObjectPtr ret;
  4977. if (val == NULL)
  4978. return(xmlXPathNewBoolean(0));
  4979. if (val->type == XPATH_BOOLEAN)
  4980. return(val);
  4981. ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
  4982. xmlXPathFreeObject(val);
  4983. return(ret);
  4984. }
  4985. /************************************************************************
  4986. * *
  4987. * Routines to handle XPath contexts *
  4988. * *
  4989. ************************************************************************/
  4990. /**
  4991. * xmlXPathNewContext:
  4992. * @doc: the XML document
  4993. *
  4994. * Create a new xmlXPathContext
  4995. *
  4996. * Returns the xmlXPathContext just allocated. The caller will need to free it.
  4997. */
  4998. xmlXPathContextPtr
  4999. xmlXPathNewContext(xmlDocPtr doc) {
  5000. xmlXPathContextPtr ret;
  5001. ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
  5002. if (ret == NULL) {
  5003. xmlXPathErrMemory(NULL, "creating context\n");
  5004. return(NULL);
  5005. }
  5006. memset(ret, 0 , sizeof(xmlXPathContext));
  5007. ret->doc = doc;
  5008. ret->node = NULL;
  5009. ret->varHash = NULL;
  5010. ret->nb_types = 0;
  5011. ret->max_types = 0;
  5012. ret->types = NULL;
  5013. ret->funcHash = xmlHashCreate(0);
  5014. ret->nb_axis = 0;
  5015. ret->max_axis = 0;
  5016. ret->axis = NULL;
  5017. ret->nsHash = NULL;
  5018. ret->user = NULL;
  5019. ret->contextSize = -1;
  5020. ret->proximityPosition = -1;
  5021. #ifdef XP_DEFAULT_CACHE_ON
  5022. if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
  5023. xmlXPathFreeContext(ret);
  5024. return(NULL);
  5025. }
  5026. #endif
  5027. xmlXPathRegisterAllFunctions(ret);
  5028. return(ret);
  5029. }
  5030. /**
  5031. * xmlXPathFreeContext:
  5032. * @ctxt: the context to free
  5033. *
  5034. * Free up an xmlXPathContext
  5035. */
  5036. void
  5037. xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
  5038. if (ctxt == NULL) return;
  5039. if (ctxt->cache != NULL)
  5040. xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
  5041. xmlXPathRegisteredNsCleanup(ctxt);
  5042. xmlXPathRegisteredFuncsCleanup(ctxt);
  5043. xmlXPathRegisteredVariablesCleanup(ctxt);
  5044. xmlResetError(&ctxt->lastError);
  5045. xmlFree(ctxt);
  5046. }
  5047. /************************************************************************
  5048. * *
  5049. * Routines to handle XPath parser contexts *
  5050. * *
  5051. ************************************************************************/
  5052. #define CHECK_CTXT(ctxt) \
  5053. if (ctxt == NULL) { \
  5054. __xmlRaiseError(NULL, NULL, NULL, \
  5055. NULL, NULL, XML_FROM_XPATH, \
  5056. XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
  5057. __FILE__, __LINE__, \
  5058. NULL, NULL, NULL, 0, 0, \
  5059. "NULL context pointer\n"); \
  5060. return(NULL); \
  5061. } \
  5062. #define CHECK_CTXT_NEG(ctxt) \
  5063. if (ctxt == NULL) { \
  5064. __xmlRaiseError(NULL, NULL, NULL, \
  5065. NULL, NULL, XML_FROM_XPATH, \
  5066. XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
  5067. __FILE__, __LINE__, \
  5068. NULL, NULL, NULL, 0, 0, \
  5069. "NULL context pointer\n"); \
  5070. return(-1); \
  5071. } \
  5072. #define CHECK_CONTEXT(ctxt) \
  5073. if ((ctxt == NULL) || (ctxt->doc == NULL) || \
  5074. (ctxt->doc->children == NULL)) { \
  5075. xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
  5076. return(NULL); \
  5077. }
  5078. /**
  5079. * xmlXPathNewParserContext:
  5080. * @str: the XPath expression
  5081. * @ctxt: the XPath context
  5082. *
  5083. * Create a new xmlXPathParserContext
  5084. *
  5085. * Returns the xmlXPathParserContext just allocated.
  5086. */
  5087. xmlXPathParserContextPtr
  5088. xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
  5089. xmlXPathParserContextPtr ret;
  5090. ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
  5091. if (ret == NULL) {
  5092. xmlXPathErrMemory(ctxt, "creating parser context\n");
  5093. return(NULL);
  5094. }
  5095. memset(ret, 0 , sizeof(xmlXPathParserContext));
  5096. ret->cur = ret->base = str;
  5097. ret->context = ctxt;
  5098. ret->comp = xmlXPathNewCompExpr();
  5099. if (ret->comp == NULL) {
  5100. xmlFree(ret->valueTab);
  5101. xmlFree(ret);
  5102. return(NULL);
  5103. }
  5104. if ((ctxt != NULL) && (ctxt->dict != NULL)) {
  5105. ret->comp->dict = ctxt->dict;
  5106. xmlDictReference(ret->comp->dict);
  5107. }
  5108. return(ret);
  5109. }
  5110. /**
  5111. * xmlXPathCompParserContext:
  5112. * @comp: the XPath compiled expression
  5113. * @ctxt: the XPath context
  5114. *
  5115. * Create a new xmlXPathParserContext when processing a compiled expression
  5116. *
  5117. * Returns the xmlXPathParserContext just allocated.
  5118. */
  5119. static xmlXPathParserContextPtr
  5120. xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
  5121. xmlXPathParserContextPtr ret;
  5122. ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
  5123. if (ret == NULL) {
  5124. xmlXPathErrMemory(ctxt, "creating evaluation context\n");
  5125. return(NULL);
  5126. }
  5127. memset(ret, 0 , sizeof(xmlXPathParserContext));
  5128. /* Allocate the value stack */
  5129. ret->valueTab = (xmlXPathObjectPtr *)
  5130. xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
  5131. if (ret->valueTab == NULL) {
  5132. xmlFree(ret);
  5133. xmlXPathErrMemory(ctxt, "creating evaluation context\n");
  5134. return(NULL);
  5135. }
  5136. ret->valueNr = 0;
  5137. ret->valueMax = 10;
  5138. ret->value = NULL;
  5139. ret->context = ctxt;
  5140. ret->comp = comp;
  5141. return(ret);
  5142. }
  5143. /**
  5144. * xmlXPathFreeParserContext:
  5145. * @ctxt: the context to free
  5146. *
  5147. * Free up an xmlXPathParserContext
  5148. */
  5149. void
  5150. xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
  5151. int i;
  5152. if (ctxt->valueTab != NULL) {
  5153. for (i = 0; i < ctxt->valueNr; i++) {
  5154. if (ctxt->context)
  5155. xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
  5156. else
  5157. xmlXPathFreeObject(ctxt->valueTab[i]);
  5158. }
  5159. xmlFree(ctxt->valueTab);
  5160. }
  5161. if (ctxt->comp != NULL) {
  5162. #ifdef XPATH_STREAMING
  5163. if (ctxt->comp->stream != NULL) {
  5164. xmlFreePatternList(ctxt->comp->stream);
  5165. ctxt->comp->stream = NULL;
  5166. }
  5167. #endif
  5168. xmlXPathFreeCompExpr(ctxt->comp);
  5169. }
  5170. xmlFree(ctxt);
  5171. }
  5172. /************************************************************************
  5173. * *
  5174. * The implicit core function library *
  5175. * *
  5176. ************************************************************************/
  5177. /**
  5178. * xmlXPathNodeValHash:
  5179. * @node: a node pointer
  5180. *
  5181. * Function computing the beginning of the string value of the node,
  5182. * used to speed up comparisons
  5183. *
  5184. * Returns an int usable as a hash
  5185. */
  5186. static unsigned int
  5187. xmlXPathNodeValHash(xmlNodePtr node) {
  5188. int len = 2;
  5189. const xmlChar * string = NULL;
  5190. xmlNodePtr tmp = NULL;
  5191. unsigned int ret = 0;
  5192. if (node == NULL)
  5193. return(0);
  5194. if (node->type == XML_DOCUMENT_NODE) {
  5195. tmp = xmlDocGetRootElement((xmlDocPtr) node);
  5196. if (tmp == NULL)
  5197. node = node->children;
  5198. else
  5199. node = tmp;
  5200. if (node == NULL)
  5201. return(0);
  5202. }
  5203. switch (node->type) {
  5204. case XML_COMMENT_NODE:
  5205. case XML_PI_NODE:
  5206. case XML_CDATA_SECTION_NODE:
  5207. case XML_TEXT_NODE:
  5208. string = node->content;
  5209. if (string == NULL)
  5210. return(0);
  5211. if (string[0] == 0)
  5212. return(0);
  5213. return(string[0] + (string[1] << 8));
  5214. case XML_NAMESPACE_DECL:
  5215. string = ((xmlNsPtr)node)->href;
  5216. if (string == NULL)
  5217. return(0);
  5218. if (string[0] == 0)
  5219. return(0);
  5220. return(string[0] + (string[1] << 8));
  5221. case XML_ATTRIBUTE_NODE:
  5222. tmp = ((xmlAttrPtr) node)->children;
  5223. break;
  5224. case XML_ELEMENT_NODE:
  5225. tmp = node->children;
  5226. break;
  5227. default:
  5228. return(0);
  5229. }
  5230. while (tmp != NULL) {
  5231. switch (tmp->type) {
  5232. case XML_CDATA_SECTION_NODE:
  5233. case XML_TEXT_NODE:
  5234. string = tmp->content;
  5235. break;
  5236. default:
  5237. string = NULL;
  5238. break;
  5239. }
  5240. if ((string != NULL) && (string[0] != 0)) {
  5241. if (len == 1) {
  5242. return(ret + (string[0] << 8));
  5243. }
  5244. if (string[1] == 0) {
  5245. len = 1;
  5246. ret = string[0];
  5247. } else {
  5248. return(string[0] + (string[1] << 8));
  5249. }
  5250. }
  5251. /*
  5252. * Skip to next node
  5253. */
  5254. if ((tmp->children != NULL) &&
  5255. (tmp->type != XML_DTD_NODE) &&
  5256. (tmp->type != XML_ENTITY_REF_NODE) &&
  5257. (tmp->children->type != XML_ENTITY_DECL)) {
  5258. tmp = tmp->children;
  5259. continue;
  5260. }
  5261. if (tmp == node)
  5262. break;
  5263. if (tmp->next != NULL) {
  5264. tmp = tmp->next;
  5265. continue;
  5266. }
  5267. do {
  5268. tmp = tmp->parent;
  5269. if (tmp == NULL)
  5270. break;
  5271. if (tmp == node) {
  5272. tmp = NULL;
  5273. break;
  5274. }
  5275. if (tmp->next != NULL) {
  5276. tmp = tmp->next;
  5277. break;
  5278. }
  5279. } while (tmp != NULL);
  5280. }
  5281. return(ret);
  5282. }
  5283. /**
  5284. * xmlXPathStringHash:
  5285. * @string: a string
  5286. *
  5287. * Function computing the beginning of the string value of the node,
  5288. * used to speed up comparisons
  5289. *
  5290. * Returns an int usable as a hash
  5291. */
  5292. static unsigned int
  5293. xmlXPathStringHash(const xmlChar * string) {
  5294. if (string == NULL)
  5295. return(0);
  5296. if (string[0] == 0)
  5297. return(0);
  5298. return(string[0] + (string[1] << 8));
  5299. }
  5300. /**
  5301. * xmlXPathCompareNodeSetFloat:
  5302. * @ctxt: the XPath Parser context
  5303. * @inf: less than (1) or greater than (0)
  5304. * @strict: is the comparison strict
  5305. * @arg: the node set
  5306. * @f: the value
  5307. *
  5308. * Implement the compare operation between a nodeset and a number
  5309. * @ns < @val (1, 1, ...
  5310. * @ns <= @val (1, 0, ...
  5311. * @ns > @val (0, 1, ...
  5312. * @ns >= @val (0, 0, ...
  5313. *
  5314. * If one object to be compared is a node-set and the other is a number,
  5315. * then the comparison will be true if and only if there is a node in the
  5316. * node-set such that the result of performing the comparison on the number
  5317. * to be compared and on the result of converting the string-value of that
  5318. * node to a number using the number function is true.
  5319. *
  5320. * Returns 0 or 1 depending on the results of the test.
  5321. */
  5322. static int
  5323. xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
  5324. xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
  5325. int i, ret = 0;
  5326. xmlNodeSetPtr ns;
  5327. xmlChar *str2;
  5328. if ((f == NULL) || (arg == NULL) ||
  5329. ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
  5330. xmlXPathReleaseObject(ctxt->context, arg);
  5331. xmlXPathReleaseObject(ctxt->context, f);
  5332. return(0);
  5333. }
  5334. ns = arg->nodesetval;
  5335. if (ns != NULL) {
  5336. for (i = 0;i < ns->nodeNr;i++) {
  5337. str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
  5338. if (str2 != NULL) {
  5339. valuePush(ctxt,
  5340. xmlXPathCacheNewString(ctxt->context, str2));
  5341. xmlFree(str2);
  5342. xmlXPathNumberFunction(ctxt, 1);
  5343. valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
  5344. ret = xmlXPathCompareValues(ctxt, inf, strict);
  5345. if (ret)
  5346. break;
  5347. }
  5348. }
  5349. }
  5350. xmlXPathReleaseObject(ctxt->context, arg);
  5351. xmlXPathReleaseObject(ctxt->context, f);
  5352. return(ret);
  5353. }
  5354. /**
  5355. * xmlXPathCompareNodeSetString:
  5356. * @ctxt: the XPath Parser context
  5357. * @inf: less than (1) or greater than (0)
  5358. * @strict: is the comparison strict
  5359. * @arg: the node set
  5360. * @s: the value
  5361. *
  5362. * Implement the compare operation between a nodeset and a string
  5363. * @ns < @val (1, 1, ...
  5364. * @ns <= @val (1, 0, ...
  5365. * @ns > @val (0, 1, ...
  5366. * @ns >= @val (0, 0, ...
  5367. *
  5368. * If one object to be compared is a node-set and the other is a string,
  5369. * then the comparison will be true if and only if there is a node in
  5370. * the node-set such that the result of performing the comparison on the
  5371. * string-value of the node and the other string is true.
  5372. *
  5373. * Returns 0 or 1 depending on the results of the test.
  5374. */
  5375. static int
  5376. xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
  5377. xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
  5378. int i, ret = 0;
  5379. xmlNodeSetPtr ns;
  5380. xmlChar *str2;
  5381. if ((s == NULL) || (arg == NULL) ||
  5382. ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
  5383. xmlXPathReleaseObject(ctxt->context, arg);
  5384. xmlXPathReleaseObject(ctxt->context, s);
  5385. return(0);
  5386. }
  5387. ns = arg->nodesetval;
  5388. if (ns != NULL) {
  5389. for (i = 0;i < ns->nodeNr;i++) {
  5390. str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
  5391. if (str2 != NULL) {
  5392. valuePush(ctxt,
  5393. xmlXPathCacheNewString(ctxt->context, str2));
  5394. xmlFree(str2);
  5395. valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
  5396. ret = xmlXPathCompareValues(ctxt, inf, strict);
  5397. if (ret)
  5398. break;
  5399. }
  5400. }
  5401. }
  5402. xmlXPathReleaseObject(ctxt->context, arg);
  5403. xmlXPathReleaseObject(ctxt->context, s);
  5404. return(ret);
  5405. }
  5406. /**
  5407. * xmlXPathCompareNodeSets:
  5408. * @inf: less than (1) or greater than (0)
  5409. * @strict: is the comparison strict
  5410. * @arg1: the first node set object
  5411. * @arg2: the second node set object
  5412. *
  5413. * Implement the compare operation on nodesets:
  5414. *
  5415. * If both objects to be compared are node-sets, then the comparison
  5416. * will be true if and only if there is a node in the first node-set
  5417. * and a node in the second node-set such that the result of performing
  5418. * the comparison on the string-values of the two nodes is true.
  5419. * ....
  5420. * When neither object to be compared is a node-set and the operator
  5421. * is <=, <, >= or >, then the objects are compared by converting both
  5422. * objects to numbers and comparing the numbers according to IEEE 754.
  5423. * ....
  5424. * The number function converts its argument to a number as follows:
  5425. * - a string that consists of optional whitespace followed by an
  5426. * optional minus sign followed by a Number followed by whitespace
  5427. * is converted to the IEEE 754 number that is nearest (according
  5428. * to the IEEE 754 round-to-nearest rule) to the mathematical value
  5429. * represented by the string; any other string is converted to NaN
  5430. *
  5431. * Conclusion all nodes need to be converted first to their string value
  5432. * and then the comparison must be done when possible
  5433. */
  5434. static int
  5435. xmlXPathCompareNodeSets(int inf, int strict,
  5436. xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
  5437. int i, j, init = 0;
  5438. double val1;
  5439. double *values2;
  5440. int ret = 0;
  5441. xmlNodeSetPtr ns1;
  5442. xmlNodeSetPtr ns2;
  5443. if ((arg1 == NULL) ||
  5444. ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
  5445. xmlXPathFreeObject(arg2);
  5446. return(0);
  5447. }
  5448. if ((arg2 == NULL) ||
  5449. ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
  5450. xmlXPathFreeObject(arg1);
  5451. xmlXPathFreeObject(arg2);
  5452. return(0);
  5453. }
  5454. ns1 = arg1->nodesetval;
  5455. ns2 = arg2->nodesetval;
  5456. if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
  5457. xmlXPathFreeObject(arg1);
  5458. xmlXPathFreeObject(arg2);
  5459. return(0);
  5460. }
  5461. if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
  5462. xmlXPathFreeObject(arg1);
  5463. xmlXPathFreeObject(arg2);
  5464. return(0);
  5465. }
  5466. values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
  5467. if (values2 == NULL) {
  5468. /* TODO: Propagate memory error. */
  5469. xmlXPathErrMemory(NULL, "comparing nodesets\n");
  5470. xmlXPathFreeObject(arg1);
  5471. xmlXPathFreeObject(arg2);
  5472. return(0);
  5473. }
  5474. for (i = 0;i < ns1->nodeNr;i++) {
  5475. val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
  5476. if (xmlXPathIsNaN(val1))
  5477. continue;
  5478. for (j = 0;j < ns2->nodeNr;j++) {
  5479. if (init == 0) {
  5480. values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
  5481. }
  5482. if (xmlXPathIsNaN(values2[j]))
  5483. continue;
  5484. if (inf && strict)
  5485. ret = (val1 < values2[j]);
  5486. else if (inf && !strict)
  5487. ret = (val1 <= values2[j]);
  5488. else if (!inf && strict)
  5489. ret = (val1 > values2[j]);
  5490. else if (!inf && !strict)
  5491. ret = (val1 >= values2[j]);
  5492. if (ret)
  5493. break;
  5494. }
  5495. if (ret)
  5496. break;
  5497. init = 1;
  5498. }
  5499. xmlFree(values2);
  5500. xmlXPathFreeObject(arg1);
  5501. xmlXPathFreeObject(arg2);
  5502. return(ret);
  5503. }
  5504. /**
  5505. * xmlXPathCompareNodeSetValue:
  5506. * @ctxt: the XPath Parser context
  5507. * @inf: less than (1) or greater than (0)
  5508. * @strict: is the comparison strict
  5509. * @arg: the node set
  5510. * @val: the value
  5511. *
  5512. * Implement the compare operation between a nodeset and a value
  5513. * @ns < @val (1, 1, ...
  5514. * @ns <= @val (1, 0, ...
  5515. * @ns > @val (0, 1, ...
  5516. * @ns >= @val (0, 0, ...
  5517. *
  5518. * If one object to be compared is a node-set and the other is a boolean,
  5519. * then the comparison will be true if and only if the result of performing
  5520. * the comparison on the boolean and on the result of converting
  5521. * the node-set to a boolean using the boolean function is true.
  5522. *
  5523. * Returns 0 or 1 depending on the results of the test.
  5524. */
  5525. static int
  5526. xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
  5527. xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
  5528. if ((val == NULL) || (arg == NULL) ||
  5529. ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
  5530. return(0);
  5531. switch(val->type) {
  5532. case XPATH_NUMBER:
  5533. return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
  5534. case XPATH_NODESET:
  5535. case XPATH_XSLT_TREE:
  5536. return(xmlXPathCompareNodeSets(inf, strict, arg, val));
  5537. case XPATH_STRING:
  5538. return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
  5539. case XPATH_BOOLEAN:
  5540. valuePush(ctxt, arg);
  5541. xmlXPathBooleanFunction(ctxt, 1);
  5542. valuePush(ctxt, val);
  5543. return(xmlXPathCompareValues(ctxt, inf, strict));
  5544. default:
  5545. xmlGenericError(xmlGenericErrorContext,
  5546. "xmlXPathCompareNodeSetValue: Can't compare node set "
  5547. "and object of type %d\n",
  5548. val->type);
  5549. xmlXPathReleaseObject(ctxt->context, arg);
  5550. xmlXPathReleaseObject(ctxt->context, val);
  5551. XP_ERROR0(XPATH_INVALID_TYPE);
  5552. }
  5553. return(0);
  5554. }
  5555. /**
  5556. * xmlXPathEqualNodeSetString:
  5557. * @arg: the nodeset object argument
  5558. * @str: the string to compare to.
  5559. * @neq: flag to show whether for '=' (0) or '!=' (1)
  5560. *
  5561. * Implement the equal operation on XPath objects content: @arg1 == @arg2
  5562. * If one object to be compared is a node-set and the other is a string,
  5563. * then the comparison will be true if and only if there is a node in
  5564. * the node-set such that the result of performing the comparison on the
  5565. * string-value of the node and the other string is true.
  5566. *
  5567. * Returns 0 or 1 depending on the results of the test.
  5568. */
  5569. static int
  5570. xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
  5571. {
  5572. int i;
  5573. xmlNodeSetPtr ns;
  5574. xmlChar *str2;
  5575. unsigned int hash;
  5576. if ((str == NULL) || (arg == NULL) ||
  5577. ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
  5578. return (0);
  5579. ns = arg->nodesetval;
  5580. /*
  5581. * A NULL nodeset compared with a string is always false
  5582. * (since there is no node equal, and no node not equal)
  5583. */
  5584. if ((ns == NULL) || (ns->nodeNr <= 0) )
  5585. return (0);
  5586. hash = xmlXPathStringHash(str);
  5587. for (i = 0; i < ns->nodeNr; i++) {
  5588. if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
  5589. str2 = xmlNodeGetContent(ns->nodeTab[i]);
  5590. if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
  5591. xmlFree(str2);
  5592. if (neq)
  5593. continue;
  5594. return (1);
  5595. } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
  5596. if (neq)
  5597. continue;
  5598. return (1);
  5599. } else if (neq) {
  5600. if (str2 != NULL)
  5601. xmlFree(str2);
  5602. return (1);
  5603. }
  5604. if (str2 != NULL)
  5605. xmlFree(str2);
  5606. } else if (neq)
  5607. return (1);
  5608. }
  5609. return (0);
  5610. }
  5611. /**
  5612. * xmlXPathEqualNodeSetFloat:
  5613. * @arg: the nodeset object argument
  5614. * @f: the float to compare to
  5615. * @neq: flag to show whether to compare '=' (0) or '!=' (1)
  5616. *
  5617. * Implement the equal operation on XPath objects content: @arg1 == @arg2
  5618. * If one object to be compared is a node-set and the other is a number,
  5619. * then the comparison will be true if and only if there is a node in
  5620. * the node-set such that the result of performing the comparison on the
  5621. * number to be compared and on the result of converting the string-value
  5622. * of that node to a number using the number function is true.
  5623. *
  5624. * Returns 0 or 1 depending on the results of the test.
  5625. */
  5626. static int
  5627. xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
  5628. xmlXPathObjectPtr arg, double f, int neq) {
  5629. int i, ret=0;
  5630. xmlNodeSetPtr ns;
  5631. xmlChar *str2;
  5632. xmlXPathObjectPtr val;
  5633. double v;
  5634. if ((arg == NULL) ||
  5635. ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
  5636. return(0);
  5637. ns = arg->nodesetval;
  5638. if (ns != NULL) {
  5639. for (i=0;i<ns->nodeNr;i++) {
  5640. str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
  5641. if (str2 != NULL) {
  5642. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
  5643. xmlFree(str2);
  5644. xmlXPathNumberFunction(ctxt, 1);
  5645. CHECK_ERROR0;
  5646. val = valuePop(ctxt);
  5647. v = val->floatval;
  5648. xmlXPathReleaseObject(ctxt->context, val);
  5649. if (!xmlXPathIsNaN(v)) {
  5650. if ((!neq) && (v==f)) {
  5651. ret = 1;
  5652. break;
  5653. } else if ((neq) && (v!=f)) {
  5654. ret = 1;
  5655. break;
  5656. }
  5657. } else { /* NaN is unequal to any value */
  5658. if (neq)
  5659. ret = 1;
  5660. }
  5661. }
  5662. }
  5663. }
  5664. return(ret);
  5665. }
  5666. /**
  5667. * xmlXPathEqualNodeSets:
  5668. * @arg1: first nodeset object argument
  5669. * @arg2: second nodeset object argument
  5670. * @neq: flag to show whether to test '=' (0) or '!=' (1)
  5671. *
  5672. * Implement the equal / not equal operation on XPath nodesets:
  5673. * @arg1 == @arg2 or @arg1 != @arg2
  5674. * If both objects to be compared are node-sets, then the comparison
  5675. * will be true if and only if there is a node in the first node-set and
  5676. * a node in the second node-set such that the result of performing the
  5677. * comparison on the string-values of the two nodes is true.
  5678. *
  5679. * (needless to say, this is a costly operation)
  5680. *
  5681. * Returns 0 or 1 depending on the results of the test.
  5682. */
  5683. static int
  5684. xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
  5685. int i, j;
  5686. unsigned int *hashs1;
  5687. unsigned int *hashs2;
  5688. xmlChar **values1;
  5689. xmlChar **values2;
  5690. int ret = 0;
  5691. xmlNodeSetPtr ns1;
  5692. xmlNodeSetPtr ns2;
  5693. if ((arg1 == NULL) ||
  5694. ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
  5695. return(0);
  5696. if ((arg2 == NULL) ||
  5697. ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
  5698. return(0);
  5699. ns1 = arg1->nodesetval;
  5700. ns2 = arg2->nodesetval;
  5701. if ((ns1 == NULL) || (ns1->nodeNr <= 0))
  5702. return(0);
  5703. if ((ns2 == NULL) || (ns2->nodeNr <= 0))
  5704. return(0);
  5705. /*
  5706. * for equal, check if there is a node pertaining to both sets
  5707. */
  5708. if (neq == 0)
  5709. for (i = 0;i < ns1->nodeNr;i++)
  5710. for (j = 0;j < ns2->nodeNr;j++)
  5711. if (ns1->nodeTab[i] == ns2->nodeTab[j])
  5712. return(1);
  5713. values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
  5714. if (values1 == NULL) {
  5715. /* TODO: Propagate memory error. */
  5716. xmlXPathErrMemory(NULL, "comparing nodesets\n");
  5717. return(0);
  5718. }
  5719. hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
  5720. if (hashs1 == NULL) {
  5721. /* TODO: Propagate memory error. */
  5722. xmlXPathErrMemory(NULL, "comparing nodesets\n");
  5723. xmlFree(values1);
  5724. return(0);
  5725. }
  5726. memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
  5727. values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
  5728. if (values2 == NULL) {
  5729. /* TODO: Propagate memory error. */
  5730. xmlXPathErrMemory(NULL, "comparing nodesets\n");
  5731. xmlFree(hashs1);
  5732. xmlFree(values1);
  5733. return(0);
  5734. }
  5735. hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
  5736. if (hashs2 == NULL) {
  5737. /* TODO: Propagate memory error. */
  5738. xmlXPathErrMemory(NULL, "comparing nodesets\n");
  5739. xmlFree(hashs1);
  5740. xmlFree(values1);
  5741. xmlFree(values2);
  5742. return(0);
  5743. }
  5744. memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
  5745. for (i = 0;i < ns1->nodeNr;i++) {
  5746. hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
  5747. for (j = 0;j < ns2->nodeNr;j++) {
  5748. if (i == 0)
  5749. hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
  5750. if (hashs1[i] != hashs2[j]) {
  5751. if (neq) {
  5752. ret = 1;
  5753. break;
  5754. }
  5755. }
  5756. else {
  5757. if (values1[i] == NULL)
  5758. values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
  5759. if (values2[j] == NULL)
  5760. values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
  5761. ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
  5762. if (ret)
  5763. break;
  5764. }
  5765. }
  5766. if (ret)
  5767. break;
  5768. }
  5769. for (i = 0;i < ns1->nodeNr;i++)
  5770. if (values1[i] != NULL)
  5771. xmlFree(values1[i]);
  5772. for (j = 0;j < ns2->nodeNr;j++)
  5773. if (values2[j] != NULL)
  5774. xmlFree(values2[j]);
  5775. xmlFree(values1);
  5776. xmlFree(values2);
  5777. xmlFree(hashs1);
  5778. xmlFree(hashs2);
  5779. return(ret);
  5780. }
  5781. static int
  5782. xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
  5783. xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
  5784. int ret = 0;
  5785. /*
  5786. *At this point we are assured neither arg1 nor arg2
  5787. *is a nodeset, so we can just pick the appropriate routine.
  5788. */
  5789. switch (arg1->type) {
  5790. case XPATH_UNDEFINED:
  5791. break;
  5792. case XPATH_BOOLEAN:
  5793. switch (arg2->type) {
  5794. case XPATH_UNDEFINED:
  5795. break;
  5796. case XPATH_BOOLEAN:
  5797. ret = (arg1->boolval == arg2->boolval);
  5798. break;
  5799. case XPATH_NUMBER:
  5800. ret = (arg1->boolval ==
  5801. xmlXPathCastNumberToBoolean(arg2->floatval));
  5802. break;
  5803. case XPATH_STRING:
  5804. if ((arg2->stringval == NULL) ||
  5805. (arg2->stringval[0] == 0)) ret = 0;
  5806. else
  5807. ret = 1;
  5808. ret = (arg1->boolval == ret);
  5809. break;
  5810. case XPATH_USERS:
  5811. #ifdef LIBXML_XPTR_LOCS_ENABLED
  5812. case XPATH_POINT:
  5813. case XPATH_RANGE:
  5814. case XPATH_LOCATIONSET:
  5815. #endif /* LIBXML_XPTR_LOCS_ENABLED */
  5816. TODO
  5817. break;
  5818. case XPATH_NODESET:
  5819. case XPATH_XSLT_TREE:
  5820. break;
  5821. }
  5822. break;
  5823. case XPATH_NUMBER:
  5824. switch (arg2->type) {
  5825. case XPATH_UNDEFINED:
  5826. break;
  5827. case XPATH_BOOLEAN:
  5828. ret = (arg2->boolval==
  5829. xmlXPathCastNumberToBoolean(arg1->floatval));
  5830. break;
  5831. case XPATH_STRING:
  5832. valuePush(ctxt, arg2);
  5833. xmlXPathNumberFunction(ctxt, 1);
  5834. arg2 = valuePop(ctxt);
  5835. if (ctxt->error)
  5836. break;
  5837. /* Falls through. */
  5838. case XPATH_NUMBER:
  5839. /* Hand check NaN and Infinity equalities */
  5840. if (xmlXPathIsNaN(arg1->floatval) ||
  5841. xmlXPathIsNaN(arg2->floatval)) {
  5842. ret = 0;
  5843. } else if (xmlXPathIsInf(arg1->floatval) == 1) {
  5844. if (xmlXPathIsInf(arg2->floatval) == 1)
  5845. ret = 1;
  5846. else
  5847. ret = 0;
  5848. } else if (xmlXPathIsInf(arg1->floatval) == -1) {
  5849. if (xmlXPathIsInf(arg2->floatval) == -1)
  5850. ret = 1;
  5851. else
  5852. ret = 0;
  5853. } else if (xmlXPathIsInf(arg2->floatval) == 1) {
  5854. if (xmlXPathIsInf(arg1->floatval) == 1)
  5855. ret = 1;
  5856. else
  5857. ret = 0;
  5858. } else if (xmlXPathIsInf(arg2->floatval) == -1) {
  5859. if (xmlXPathIsInf(arg1->floatval) == -1)
  5860. ret = 1;
  5861. else
  5862. ret = 0;
  5863. } else {
  5864. ret = (arg1->floatval == arg2->floatval);
  5865. }
  5866. break;
  5867. case XPATH_USERS:
  5868. #ifdef LIBXML_XPTR_LOCS_ENABLED
  5869. case XPATH_POINT:
  5870. case XPATH_RANGE:
  5871. case XPATH_LOCATIONSET:
  5872. #endif /* LIBXML_XPTR_LOCS_ENABLED */
  5873. TODO
  5874. break;
  5875. case XPATH_NODESET:
  5876. case XPATH_XSLT_TREE:
  5877. break;
  5878. }
  5879. break;
  5880. case XPATH_STRING:
  5881. switch (arg2->type) {
  5882. case XPATH_UNDEFINED:
  5883. break;
  5884. case XPATH_BOOLEAN:
  5885. if ((arg1->stringval == NULL) ||
  5886. (arg1->stringval[0] == 0)) ret = 0;
  5887. else
  5888. ret = 1;
  5889. ret = (arg2->boolval == ret);
  5890. break;
  5891. case XPATH_STRING:
  5892. ret = xmlStrEqual(arg1->stringval, arg2->stringval);
  5893. break;
  5894. case XPATH_NUMBER:
  5895. valuePush(ctxt, arg1);
  5896. xmlXPathNumberFunction(ctxt, 1);
  5897. arg1 = valuePop(ctxt);
  5898. if (ctxt->error)
  5899. break;
  5900. /* Hand check NaN and Infinity equalities */
  5901. if (xmlXPathIsNaN(arg1->floatval) ||
  5902. xmlXPathIsNaN(arg2->floatval)) {
  5903. ret = 0;
  5904. } else if (xmlXPathIsInf(arg1->floatval) == 1) {
  5905. if (xmlXPathIsInf(arg2->floatval) == 1)
  5906. ret = 1;
  5907. else
  5908. ret = 0;
  5909. } else if (xmlXPathIsInf(arg1->floatval) == -1) {
  5910. if (xmlXPathIsInf(arg2->floatval) == -1)
  5911. ret = 1;
  5912. else
  5913. ret = 0;
  5914. } else if (xmlXPathIsInf(arg2->floatval) == 1) {
  5915. if (xmlXPathIsInf(arg1->floatval) == 1)
  5916. ret = 1;
  5917. else
  5918. ret = 0;
  5919. } else if (xmlXPathIsInf(arg2->floatval) == -1) {
  5920. if (xmlXPathIsInf(arg1->floatval) == -1)
  5921. ret = 1;
  5922. else
  5923. ret = 0;
  5924. } else {
  5925. ret = (arg1->floatval == arg2->floatval);
  5926. }
  5927. break;
  5928. case XPATH_USERS:
  5929. #ifdef LIBXML_XPTR_LOCS_ENABLED
  5930. case XPATH_POINT:
  5931. case XPATH_RANGE:
  5932. case XPATH_LOCATIONSET:
  5933. #endif /* LIBXML_XPTR_LOCS_ENABLED */
  5934. TODO
  5935. break;
  5936. case XPATH_NODESET:
  5937. case XPATH_XSLT_TREE:
  5938. break;
  5939. }
  5940. break;
  5941. case XPATH_USERS:
  5942. #ifdef LIBXML_XPTR_LOCS_ENABLED
  5943. case XPATH_POINT:
  5944. case XPATH_RANGE:
  5945. case XPATH_LOCATIONSET:
  5946. #endif /* LIBXML_XPTR_LOCS_ENABLED */
  5947. TODO
  5948. break;
  5949. case XPATH_NODESET:
  5950. case XPATH_XSLT_TREE:
  5951. break;
  5952. }
  5953. xmlXPathReleaseObject(ctxt->context, arg1);
  5954. xmlXPathReleaseObject(ctxt->context, arg2);
  5955. return(ret);
  5956. }
  5957. /**
  5958. * xmlXPathEqualValues:
  5959. * @ctxt: the XPath Parser context
  5960. *
  5961. * Implement the equal operation on XPath objects content: @arg1 == @arg2
  5962. *
  5963. * Returns 0 or 1 depending on the results of the test.
  5964. */
  5965. int
  5966. xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
  5967. xmlXPathObjectPtr arg1, arg2, argtmp;
  5968. int ret = 0;
  5969. if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
  5970. arg2 = valuePop(ctxt);
  5971. arg1 = valuePop(ctxt);
  5972. if ((arg1 == NULL) || (arg2 == NULL)) {
  5973. if (arg1 != NULL)
  5974. xmlXPathReleaseObject(ctxt->context, arg1);
  5975. else
  5976. xmlXPathReleaseObject(ctxt->context, arg2);
  5977. XP_ERROR0(XPATH_INVALID_OPERAND);
  5978. }
  5979. if (arg1 == arg2) {
  5980. xmlXPathFreeObject(arg1);
  5981. return(1);
  5982. }
  5983. /*
  5984. *If either argument is a nodeset, it's a 'special case'
  5985. */
  5986. if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
  5987. (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
  5988. /*
  5989. *Hack it to assure arg1 is the nodeset
  5990. */
  5991. if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
  5992. argtmp = arg2;
  5993. arg2 = arg1;
  5994. arg1 = argtmp;
  5995. }
  5996. switch (arg2->type) {
  5997. case XPATH_UNDEFINED:
  5998. break;
  5999. case XPATH_NODESET:
  6000. case XPATH_XSLT_TREE:
  6001. ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
  6002. break;
  6003. case XPATH_BOOLEAN:
  6004. if ((arg1->nodesetval == NULL) ||
  6005. (arg1->nodesetval->nodeNr == 0)) ret = 0;
  6006. else
  6007. ret = 1;
  6008. ret = (ret == arg2->boolval);
  6009. break;
  6010. case XPATH_NUMBER:
  6011. ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
  6012. break;
  6013. case XPATH_STRING:
  6014. ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
  6015. break;
  6016. case XPATH_USERS:
  6017. #ifdef LIBXML_XPTR_LOCS_ENABLED
  6018. case XPATH_POINT:
  6019. case XPATH_RANGE:
  6020. case XPATH_LOCATIONSET:
  6021. #endif /* LIBXML_XPTR_LOCS_ENABLED */
  6022. TODO
  6023. break;
  6024. }
  6025. xmlXPathReleaseObject(ctxt->context, arg1);
  6026. xmlXPathReleaseObject(ctxt->context, arg2);
  6027. return(ret);
  6028. }
  6029. return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
  6030. }
  6031. /**
  6032. * xmlXPathNotEqualValues:
  6033. * @ctxt: the XPath Parser context
  6034. *
  6035. * Implement the equal operation on XPath objects content: @arg1 == @arg2
  6036. *
  6037. * Returns 0 or 1 depending on the results of the test.
  6038. */
  6039. int
  6040. xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
  6041. xmlXPathObjectPtr arg1, arg2, argtmp;
  6042. int ret = 0;
  6043. if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
  6044. arg2 = valuePop(ctxt);
  6045. arg1 = valuePop(ctxt);
  6046. if ((arg1 == NULL) || (arg2 == NULL)) {
  6047. if (arg1 != NULL)
  6048. xmlXPathReleaseObject(ctxt->context, arg1);
  6049. else
  6050. xmlXPathReleaseObject(ctxt->context, arg2);
  6051. XP_ERROR0(XPATH_INVALID_OPERAND);
  6052. }
  6053. if (arg1 == arg2) {
  6054. xmlXPathReleaseObject(ctxt->context, arg1);
  6055. return(0);
  6056. }
  6057. /*
  6058. *If either argument is a nodeset, it's a 'special case'
  6059. */
  6060. if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
  6061. (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
  6062. /*
  6063. *Hack it to assure arg1 is the nodeset
  6064. */
  6065. if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
  6066. argtmp = arg2;
  6067. arg2 = arg1;
  6068. arg1 = argtmp;
  6069. }
  6070. switch (arg2->type) {
  6071. case XPATH_UNDEFINED:
  6072. break;
  6073. case XPATH_NODESET:
  6074. case XPATH_XSLT_TREE:
  6075. ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
  6076. break;
  6077. case XPATH_BOOLEAN:
  6078. if ((arg1->nodesetval == NULL) ||
  6079. (arg1->nodesetval->nodeNr == 0)) ret = 0;
  6080. else
  6081. ret = 1;
  6082. ret = (ret != arg2->boolval);
  6083. break;
  6084. case XPATH_NUMBER:
  6085. ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
  6086. break;
  6087. case XPATH_STRING:
  6088. ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
  6089. break;
  6090. case XPATH_USERS:
  6091. #ifdef LIBXML_XPTR_LOCS_ENABLED
  6092. case XPATH_POINT:
  6093. case XPATH_RANGE:
  6094. case XPATH_LOCATIONSET:
  6095. #endif /* LIBXML_XPTR_LOCS_ENABLED */
  6096. TODO
  6097. break;
  6098. }
  6099. xmlXPathReleaseObject(ctxt->context, arg1);
  6100. xmlXPathReleaseObject(ctxt->context, arg2);
  6101. return(ret);
  6102. }
  6103. return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
  6104. }
  6105. /**
  6106. * xmlXPathCompareValues:
  6107. * @ctxt: the XPath Parser context
  6108. * @inf: less than (1) or greater than (0)
  6109. * @strict: is the comparison strict
  6110. *
  6111. * Implement the compare operation on XPath objects:
  6112. * @arg1 < @arg2 (1, 1, ...
  6113. * @arg1 <= @arg2 (1, 0, ...
  6114. * @arg1 > @arg2 (0, 1, ...
  6115. * @arg1 >= @arg2 (0, 0, ...
  6116. *
  6117. * When neither object to be compared is a node-set and the operator is
  6118. * <=, <, >=, >, then the objects are compared by converted both objects
  6119. * to numbers and comparing the numbers according to IEEE 754. The <
  6120. * comparison will be true if and only if the first number is less than the
  6121. * second number. The <= comparison will be true if and only if the first
  6122. * number is less than or equal to the second number. The > comparison
  6123. * will be true if and only if the first number is greater than the second
  6124. * number. The >= comparison will be true if and only if the first number
  6125. * is greater than or equal to the second number.
  6126. *
  6127. * Returns 1 if the comparison succeeded, 0 if it failed
  6128. */
  6129. int
  6130. xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
  6131. int ret = 0, arg1i = 0, arg2i = 0;
  6132. xmlXPathObjectPtr arg1, arg2;
  6133. if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
  6134. arg2 = valuePop(ctxt);
  6135. arg1 = valuePop(ctxt);
  6136. if ((arg1 == NULL) || (arg2 == NULL)) {
  6137. if (arg1 != NULL)
  6138. xmlXPathReleaseObject(ctxt->context, arg1);
  6139. else
  6140. xmlXPathReleaseObject(ctxt->context, arg2);
  6141. XP_ERROR0(XPATH_INVALID_OPERAND);
  6142. }
  6143. if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
  6144. (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
  6145. /*
  6146. * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
  6147. * are not freed from within this routine; they will be freed from the
  6148. * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
  6149. */
  6150. if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
  6151. ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
  6152. ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
  6153. } else {
  6154. if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
  6155. ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
  6156. arg1, arg2);
  6157. } else {
  6158. ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
  6159. arg2, arg1);
  6160. }
  6161. }
  6162. return(ret);
  6163. }
  6164. if (arg1->type != XPATH_NUMBER) {
  6165. valuePush(ctxt, arg1);
  6166. xmlXPathNumberFunction(ctxt, 1);
  6167. arg1 = valuePop(ctxt);
  6168. }
  6169. if (arg2->type != XPATH_NUMBER) {
  6170. valuePush(ctxt, arg2);
  6171. xmlXPathNumberFunction(ctxt, 1);
  6172. arg2 = valuePop(ctxt);
  6173. }
  6174. if (ctxt->error)
  6175. goto error;
  6176. /*
  6177. * Add tests for infinity and nan
  6178. * => feedback on 3.4 for Inf and NaN
  6179. */
  6180. /* Hand check NaN and Infinity comparisons */
  6181. if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
  6182. ret=0;
  6183. } else {
  6184. arg1i=xmlXPathIsInf(arg1->floatval);
  6185. arg2i=xmlXPathIsInf(arg2->floatval);
  6186. if (inf && strict) {
  6187. if ((arg1i == -1 && arg2i != -1) ||
  6188. (arg2i == 1 && arg1i != 1)) {
  6189. ret = 1;
  6190. } else if (arg1i == 0 && arg2i == 0) {
  6191. ret = (arg1->floatval < arg2->floatval);
  6192. } else {
  6193. ret = 0;
  6194. }
  6195. }
  6196. else if (inf && !strict) {
  6197. if (arg1i == -1 || arg2i == 1) {
  6198. ret = 1;
  6199. } else if (arg1i == 0 && arg2i == 0) {
  6200. ret = (arg1->floatval <= arg2->floatval);
  6201. } else {
  6202. ret = 0;
  6203. }
  6204. }
  6205. else if (!inf && strict) {
  6206. if ((arg1i == 1 && arg2i != 1) ||
  6207. (arg2i == -1 && arg1i != -1)) {
  6208. ret = 1;
  6209. } else if (arg1i == 0 && arg2i == 0) {
  6210. ret = (arg1->floatval > arg2->floatval);
  6211. } else {
  6212. ret = 0;
  6213. }
  6214. }
  6215. else if (!inf && !strict) {
  6216. if (arg1i == 1 || arg2i == -1) {
  6217. ret = 1;
  6218. } else if (arg1i == 0 && arg2i == 0) {
  6219. ret = (arg1->floatval >= arg2->floatval);
  6220. } else {
  6221. ret = 0;
  6222. }
  6223. }
  6224. }
  6225. error:
  6226. xmlXPathReleaseObject(ctxt->context, arg1);
  6227. xmlXPathReleaseObject(ctxt->context, arg2);
  6228. return(ret);
  6229. }
  6230. /**
  6231. * xmlXPathValueFlipSign:
  6232. * @ctxt: the XPath Parser context
  6233. *
  6234. * Implement the unary - operation on an XPath object
  6235. * The numeric operators convert their operands to numbers as if
  6236. * by calling the number function.
  6237. */
  6238. void
  6239. xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
  6240. if ((ctxt == NULL) || (ctxt->context == NULL)) return;
  6241. CAST_TO_NUMBER;
  6242. CHECK_TYPE(XPATH_NUMBER);
  6243. ctxt->value->floatval = -ctxt->value->floatval;
  6244. }
  6245. /**
  6246. * xmlXPathAddValues:
  6247. * @ctxt: the XPath Parser context
  6248. *
  6249. * Implement the add operation on XPath objects:
  6250. * The numeric operators convert their operands to numbers as if
  6251. * by calling the number function.
  6252. */
  6253. void
  6254. xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
  6255. xmlXPathObjectPtr arg;
  6256. double val;
  6257. arg = valuePop(ctxt);
  6258. if (arg == NULL)
  6259. XP_ERROR(XPATH_INVALID_OPERAND);
  6260. val = xmlXPathCastToNumber(arg);
  6261. xmlXPathReleaseObject(ctxt->context, arg);
  6262. CAST_TO_NUMBER;
  6263. CHECK_TYPE(XPATH_NUMBER);
  6264. ctxt->value->floatval += val;
  6265. }
  6266. /**
  6267. * xmlXPathSubValues:
  6268. * @ctxt: the XPath Parser context
  6269. *
  6270. * Implement the subtraction operation on XPath objects:
  6271. * The numeric operators convert their operands to numbers as if
  6272. * by calling the number function.
  6273. */
  6274. void
  6275. xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
  6276. xmlXPathObjectPtr arg;
  6277. double val;
  6278. arg = valuePop(ctxt);
  6279. if (arg == NULL)
  6280. XP_ERROR(XPATH_INVALID_OPERAND);
  6281. val = xmlXPathCastToNumber(arg);
  6282. xmlXPathReleaseObject(ctxt->context, arg);
  6283. CAST_TO_NUMBER;
  6284. CHECK_TYPE(XPATH_NUMBER);
  6285. ctxt->value->floatval -= val;
  6286. }
  6287. /**
  6288. * xmlXPathMultValues:
  6289. * @ctxt: the XPath Parser context
  6290. *
  6291. * Implement the multiply operation on XPath objects:
  6292. * The numeric operators convert their operands to numbers as if
  6293. * by calling the number function.
  6294. */
  6295. void
  6296. xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
  6297. xmlXPathObjectPtr arg;
  6298. double val;
  6299. arg = valuePop(ctxt);
  6300. if (arg == NULL)
  6301. XP_ERROR(XPATH_INVALID_OPERAND);
  6302. val = xmlXPathCastToNumber(arg);
  6303. xmlXPathReleaseObject(ctxt->context, arg);
  6304. CAST_TO_NUMBER;
  6305. CHECK_TYPE(XPATH_NUMBER);
  6306. ctxt->value->floatval *= val;
  6307. }
  6308. /**
  6309. * xmlXPathDivValues:
  6310. * @ctxt: the XPath Parser context
  6311. *
  6312. * Implement the div operation on XPath objects @arg1 / @arg2:
  6313. * The numeric operators convert their operands to numbers as if
  6314. * by calling the number function.
  6315. */
  6316. ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
  6317. void
  6318. xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
  6319. xmlXPathObjectPtr arg;
  6320. double val;
  6321. arg = valuePop(ctxt);
  6322. if (arg == NULL)
  6323. XP_ERROR(XPATH_INVALID_OPERAND);
  6324. val = xmlXPathCastToNumber(arg);
  6325. xmlXPathReleaseObject(ctxt->context, arg);
  6326. CAST_TO_NUMBER;
  6327. CHECK_TYPE(XPATH_NUMBER);
  6328. ctxt->value->floatval /= val;
  6329. }
  6330. /**
  6331. * xmlXPathModValues:
  6332. * @ctxt: the XPath Parser context
  6333. *
  6334. * Implement the mod operation on XPath objects: @arg1 / @arg2
  6335. * The numeric operators convert their operands to numbers as if
  6336. * by calling the number function.
  6337. */
  6338. void
  6339. xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
  6340. xmlXPathObjectPtr arg;
  6341. double arg1, arg2;
  6342. arg = valuePop(ctxt);
  6343. if (arg == NULL)
  6344. XP_ERROR(XPATH_INVALID_OPERAND);
  6345. arg2 = xmlXPathCastToNumber(arg);
  6346. xmlXPathReleaseObject(ctxt->context, arg);
  6347. CAST_TO_NUMBER;
  6348. CHECK_TYPE(XPATH_NUMBER);
  6349. arg1 = ctxt->value->floatval;
  6350. if (arg2 == 0)
  6351. ctxt->value->floatval = xmlXPathNAN;
  6352. else {
  6353. ctxt->value->floatval = fmod(arg1, arg2);
  6354. }
  6355. }
  6356. /************************************************************************
  6357. * *
  6358. * The traversal functions *
  6359. * *
  6360. ************************************************************************/
  6361. /*
  6362. * A traversal function enumerates nodes along an axis.
  6363. * Initially it must be called with NULL, and it indicates
  6364. * termination on the axis by returning NULL.
  6365. */
  6366. typedef xmlNodePtr (*xmlXPathTraversalFunction)
  6367. (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
  6368. /*
  6369. * xmlXPathTraversalFunctionExt:
  6370. * A traversal function enumerates nodes along an axis.
  6371. * Initially it must be called with NULL, and it indicates
  6372. * termination on the axis by returning NULL.
  6373. * The context node of the traversal is specified via @contextNode.
  6374. */
  6375. typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
  6376. (xmlNodePtr cur, xmlNodePtr contextNode);
  6377. /*
  6378. * xmlXPathNodeSetMergeFunction:
  6379. * Used for merging node sets in xmlXPathCollectAndTest().
  6380. */
  6381. typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
  6382. (xmlNodeSetPtr, xmlNodeSetPtr);
  6383. /**
  6384. * xmlXPathNextSelf:
  6385. * @ctxt: the XPath Parser context
  6386. * @cur: the current node in the traversal
  6387. *
  6388. * Traversal function for the "self" direction
  6389. * The self axis contains just the context node itself
  6390. *
  6391. * Returns the next element following that axis
  6392. */
  6393. xmlNodePtr
  6394. xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  6395. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  6396. if (cur == NULL)
  6397. return(ctxt->context->node);
  6398. return(NULL);
  6399. }
  6400. /**
  6401. * xmlXPathNextChild:
  6402. * @ctxt: the XPath Parser context
  6403. * @cur: the current node in the traversal
  6404. *
  6405. * Traversal function for the "child" direction
  6406. * The child axis contains the children of the context node in document order.
  6407. *
  6408. * Returns the next element following that axis
  6409. */
  6410. xmlNodePtr
  6411. xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  6412. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  6413. if (cur == NULL) {
  6414. if (ctxt->context->node == NULL) return(NULL);
  6415. switch (ctxt->context->node->type) {
  6416. case XML_ELEMENT_NODE:
  6417. case XML_TEXT_NODE:
  6418. case XML_CDATA_SECTION_NODE:
  6419. case XML_ENTITY_REF_NODE:
  6420. case XML_ENTITY_NODE:
  6421. case XML_PI_NODE:
  6422. case XML_COMMENT_NODE:
  6423. case XML_NOTATION_NODE:
  6424. case XML_DTD_NODE:
  6425. return(ctxt->context->node->children);
  6426. case XML_DOCUMENT_NODE:
  6427. case XML_DOCUMENT_TYPE_NODE:
  6428. case XML_DOCUMENT_FRAG_NODE:
  6429. case XML_HTML_DOCUMENT_NODE:
  6430. return(((xmlDocPtr) ctxt->context->node)->children);
  6431. case XML_ELEMENT_DECL:
  6432. case XML_ATTRIBUTE_DECL:
  6433. case XML_ENTITY_DECL:
  6434. case XML_ATTRIBUTE_NODE:
  6435. case XML_NAMESPACE_DECL:
  6436. case XML_XINCLUDE_START:
  6437. case XML_XINCLUDE_END:
  6438. return(NULL);
  6439. }
  6440. return(NULL);
  6441. }
  6442. if ((cur->type == XML_DOCUMENT_NODE) ||
  6443. (cur->type == XML_HTML_DOCUMENT_NODE))
  6444. return(NULL);
  6445. return(cur->next);
  6446. }
  6447. /**
  6448. * xmlXPathNextChildElement:
  6449. * @ctxt: the XPath Parser context
  6450. * @cur: the current node in the traversal
  6451. *
  6452. * Traversal function for the "child" direction and nodes of type element.
  6453. * The child axis contains the children of the context node in document order.
  6454. *
  6455. * Returns the next element following that axis
  6456. */
  6457. static xmlNodePtr
  6458. xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  6459. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  6460. if (cur == NULL) {
  6461. cur = ctxt->context->node;
  6462. if (cur == NULL) return(NULL);
  6463. /*
  6464. * Get the first element child.
  6465. */
  6466. switch (cur->type) {
  6467. case XML_ELEMENT_NODE:
  6468. case XML_DOCUMENT_FRAG_NODE:
  6469. case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
  6470. case XML_ENTITY_NODE:
  6471. cur = cur->children;
  6472. if (cur != NULL) {
  6473. if (cur->type == XML_ELEMENT_NODE)
  6474. return(cur);
  6475. do {
  6476. cur = cur->next;
  6477. } while ((cur != NULL) &&
  6478. (cur->type != XML_ELEMENT_NODE));
  6479. return(cur);
  6480. }
  6481. return(NULL);
  6482. case XML_DOCUMENT_NODE:
  6483. case XML_HTML_DOCUMENT_NODE:
  6484. return(xmlDocGetRootElement((xmlDocPtr) cur));
  6485. default:
  6486. return(NULL);
  6487. }
  6488. return(NULL);
  6489. }
  6490. /*
  6491. * Get the next sibling element node.
  6492. */
  6493. switch (cur->type) {
  6494. case XML_ELEMENT_NODE:
  6495. case XML_TEXT_NODE:
  6496. case XML_ENTITY_REF_NODE:
  6497. case XML_ENTITY_NODE:
  6498. case XML_CDATA_SECTION_NODE:
  6499. case XML_PI_NODE:
  6500. case XML_COMMENT_NODE:
  6501. case XML_XINCLUDE_END:
  6502. break;
  6503. /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
  6504. default:
  6505. return(NULL);
  6506. }
  6507. if (cur->next != NULL) {
  6508. if (cur->next->type == XML_ELEMENT_NODE)
  6509. return(cur->next);
  6510. cur = cur->next;
  6511. do {
  6512. cur = cur->next;
  6513. } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
  6514. return(cur);
  6515. }
  6516. return(NULL);
  6517. }
  6518. #if 0
  6519. /**
  6520. * xmlXPathNextDescendantOrSelfElemParent:
  6521. * @ctxt: the XPath Parser context
  6522. * @cur: the current node in the traversal
  6523. *
  6524. * Traversal function for the "descendant-or-self" axis.
  6525. * Additionally it returns only nodes which can be parents of
  6526. * element nodes.
  6527. *
  6528. *
  6529. * Returns the next element following that axis
  6530. */
  6531. static xmlNodePtr
  6532. xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
  6533. xmlNodePtr contextNode)
  6534. {
  6535. if (cur == NULL) {
  6536. if (contextNode == NULL)
  6537. return(NULL);
  6538. switch (contextNode->type) {
  6539. case XML_ELEMENT_NODE:
  6540. case XML_XINCLUDE_START:
  6541. case XML_DOCUMENT_FRAG_NODE:
  6542. case XML_DOCUMENT_NODE:
  6543. case XML_HTML_DOCUMENT_NODE:
  6544. return(contextNode);
  6545. default:
  6546. return(NULL);
  6547. }
  6548. return(NULL);
  6549. } else {
  6550. xmlNodePtr start = cur;
  6551. while (cur != NULL) {
  6552. switch (cur->type) {
  6553. case XML_ELEMENT_NODE:
  6554. /* TODO: OK to have XInclude here? */
  6555. case XML_XINCLUDE_START:
  6556. case XML_DOCUMENT_FRAG_NODE:
  6557. if (cur != start)
  6558. return(cur);
  6559. if (cur->children != NULL) {
  6560. cur = cur->children;
  6561. continue;
  6562. }
  6563. break;
  6564. /* Not sure if we need those here. */
  6565. case XML_DOCUMENT_NODE:
  6566. case XML_HTML_DOCUMENT_NODE:
  6567. if (cur != start)
  6568. return(cur);
  6569. return(xmlDocGetRootElement((xmlDocPtr) cur));
  6570. default:
  6571. break;
  6572. }
  6573. next_sibling:
  6574. if ((cur == NULL) || (cur == contextNode))
  6575. return(NULL);
  6576. if (cur->next != NULL) {
  6577. cur = cur->next;
  6578. } else {
  6579. cur = cur->parent;
  6580. goto next_sibling;
  6581. }
  6582. }
  6583. }
  6584. return(NULL);
  6585. }
  6586. #endif
  6587. /**
  6588. * xmlXPathNextDescendant:
  6589. * @ctxt: the XPath Parser context
  6590. * @cur: the current node in the traversal
  6591. *
  6592. * Traversal function for the "descendant" direction
  6593. * the descendant axis contains the descendants of the context node in document
  6594. * order; a descendant is a child or a child of a child and so on.
  6595. *
  6596. * Returns the next element following that axis
  6597. */
  6598. xmlNodePtr
  6599. xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  6600. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  6601. if (cur == NULL) {
  6602. if (ctxt->context->node == NULL)
  6603. return(NULL);
  6604. if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
  6605. (ctxt->context->node->type == XML_NAMESPACE_DECL))
  6606. return(NULL);
  6607. if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
  6608. return(ctxt->context->doc->children);
  6609. return(ctxt->context->node->children);
  6610. }
  6611. if (cur->type == XML_NAMESPACE_DECL)
  6612. return(NULL);
  6613. if (cur->children != NULL) {
  6614. /*
  6615. * Do not descend on entities declarations
  6616. */
  6617. if (cur->children->type != XML_ENTITY_DECL) {
  6618. cur = cur->children;
  6619. /*
  6620. * Skip DTDs
  6621. */
  6622. if (cur->type != XML_DTD_NODE)
  6623. return(cur);
  6624. }
  6625. }
  6626. if (cur == ctxt->context->node) return(NULL);
  6627. while (cur->next != NULL) {
  6628. cur = cur->next;
  6629. if ((cur->type != XML_ENTITY_DECL) &&
  6630. (cur->type != XML_DTD_NODE))
  6631. return(cur);
  6632. }
  6633. do {
  6634. cur = cur->parent;
  6635. if (cur == NULL) break;
  6636. if (cur == ctxt->context->node) return(NULL);
  6637. if (cur->next != NULL) {
  6638. cur = cur->next;
  6639. return(cur);
  6640. }
  6641. } while (cur != NULL);
  6642. return(cur);
  6643. }
  6644. /**
  6645. * xmlXPathNextDescendantOrSelf:
  6646. * @ctxt: the XPath Parser context
  6647. * @cur: the current node in the traversal
  6648. *
  6649. * Traversal function for the "descendant-or-self" direction
  6650. * the descendant-or-self axis contains the context node and the descendants
  6651. * of the context node in document order; thus the context node is the first
  6652. * node on the axis, and the first child of the context node is the second node
  6653. * on the axis
  6654. *
  6655. * Returns the next element following that axis
  6656. */
  6657. xmlNodePtr
  6658. xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  6659. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  6660. if (cur == NULL)
  6661. return(ctxt->context->node);
  6662. if (ctxt->context->node == NULL)
  6663. return(NULL);
  6664. if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
  6665. (ctxt->context->node->type == XML_NAMESPACE_DECL))
  6666. return(NULL);
  6667. return(xmlXPathNextDescendant(ctxt, cur));
  6668. }
  6669. /**
  6670. * xmlXPathNextParent:
  6671. * @ctxt: the XPath Parser context
  6672. * @cur: the current node in the traversal
  6673. *
  6674. * Traversal function for the "parent" direction
  6675. * The parent axis contains the parent of the context node, if there is one.
  6676. *
  6677. * Returns the next element following that axis
  6678. */
  6679. xmlNodePtr
  6680. xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  6681. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  6682. /*
  6683. * the parent of an attribute or namespace node is the element
  6684. * to which the attribute or namespace node is attached
  6685. * Namespace handling !!!
  6686. */
  6687. if (cur == NULL) {
  6688. if (ctxt->context->node == NULL) return(NULL);
  6689. switch (ctxt->context->node->type) {
  6690. case XML_ELEMENT_NODE:
  6691. case XML_TEXT_NODE:
  6692. case XML_CDATA_SECTION_NODE:
  6693. case XML_ENTITY_REF_NODE:
  6694. case XML_ENTITY_NODE:
  6695. case XML_PI_NODE:
  6696. case XML_COMMENT_NODE:
  6697. case XML_NOTATION_NODE:
  6698. case XML_DTD_NODE:
  6699. case XML_ELEMENT_DECL:
  6700. case XML_ATTRIBUTE_DECL:
  6701. case XML_XINCLUDE_START:
  6702. case XML_XINCLUDE_END:
  6703. case XML_ENTITY_DECL:
  6704. if (ctxt->context->node->parent == NULL)
  6705. return((xmlNodePtr) ctxt->context->doc);
  6706. if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
  6707. ((ctxt->context->node->parent->name[0] == ' ') ||
  6708. (xmlStrEqual(ctxt->context->node->parent->name,
  6709. BAD_CAST "fake node libxslt"))))
  6710. return(NULL);
  6711. return(ctxt->context->node->parent);
  6712. case XML_ATTRIBUTE_NODE: {
  6713. xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
  6714. return(att->parent);
  6715. }
  6716. case XML_DOCUMENT_NODE:
  6717. case XML_DOCUMENT_TYPE_NODE:
  6718. case XML_DOCUMENT_FRAG_NODE:
  6719. case XML_HTML_DOCUMENT_NODE:
  6720. return(NULL);
  6721. case XML_NAMESPACE_DECL: {
  6722. xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
  6723. if ((ns->next != NULL) &&
  6724. (ns->next->type != XML_NAMESPACE_DECL))
  6725. return((xmlNodePtr) ns->next);
  6726. return(NULL);
  6727. }
  6728. }
  6729. }
  6730. return(NULL);
  6731. }
  6732. /**
  6733. * xmlXPathNextAncestor:
  6734. * @ctxt: the XPath Parser context
  6735. * @cur: the current node in the traversal
  6736. *
  6737. * Traversal function for the "ancestor" direction
  6738. * the ancestor axis contains the ancestors of the context node; the ancestors
  6739. * of the context node consist of the parent of context node and the parent's
  6740. * parent and so on; the nodes are ordered in reverse document order; thus the
  6741. * parent is the first node on the axis, and the parent's parent is the second
  6742. * node on the axis
  6743. *
  6744. * Returns the next element following that axis
  6745. */
  6746. xmlNodePtr
  6747. xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  6748. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  6749. /*
  6750. * the parent of an attribute or namespace node is the element
  6751. * to which the attribute or namespace node is attached
  6752. * !!!!!!!!!!!!!
  6753. */
  6754. if (cur == NULL) {
  6755. if (ctxt->context->node == NULL) return(NULL);
  6756. switch (ctxt->context->node->type) {
  6757. case XML_ELEMENT_NODE:
  6758. case XML_TEXT_NODE:
  6759. case XML_CDATA_SECTION_NODE:
  6760. case XML_ENTITY_REF_NODE:
  6761. case XML_ENTITY_NODE:
  6762. case XML_PI_NODE:
  6763. case XML_COMMENT_NODE:
  6764. case XML_DTD_NODE:
  6765. case XML_ELEMENT_DECL:
  6766. case XML_ATTRIBUTE_DECL:
  6767. case XML_ENTITY_DECL:
  6768. case XML_NOTATION_NODE:
  6769. case XML_XINCLUDE_START:
  6770. case XML_XINCLUDE_END:
  6771. if (ctxt->context->node->parent == NULL)
  6772. return((xmlNodePtr) ctxt->context->doc);
  6773. if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
  6774. ((ctxt->context->node->parent->name[0] == ' ') ||
  6775. (xmlStrEqual(ctxt->context->node->parent->name,
  6776. BAD_CAST "fake node libxslt"))))
  6777. return(NULL);
  6778. return(ctxt->context->node->parent);
  6779. case XML_ATTRIBUTE_NODE: {
  6780. xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
  6781. return(tmp->parent);
  6782. }
  6783. case XML_DOCUMENT_NODE:
  6784. case XML_DOCUMENT_TYPE_NODE:
  6785. case XML_DOCUMENT_FRAG_NODE:
  6786. case XML_HTML_DOCUMENT_NODE:
  6787. return(NULL);
  6788. case XML_NAMESPACE_DECL: {
  6789. xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
  6790. if ((ns->next != NULL) &&
  6791. (ns->next->type != XML_NAMESPACE_DECL))
  6792. return((xmlNodePtr) ns->next);
  6793. /* Bad, how did that namespace end up here ? */
  6794. return(NULL);
  6795. }
  6796. }
  6797. return(NULL);
  6798. }
  6799. if (cur == ctxt->context->doc->children)
  6800. return((xmlNodePtr) ctxt->context->doc);
  6801. if (cur == (xmlNodePtr) ctxt->context->doc)
  6802. return(NULL);
  6803. switch (cur->type) {
  6804. case XML_ELEMENT_NODE:
  6805. case XML_TEXT_NODE:
  6806. case XML_CDATA_SECTION_NODE:
  6807. case XML_ENTITY_REF_NODE:
  6808. case XML_ENTITY_NODE:
  6809. case XML_PI_NODE:
  6810. case XML_COMMENT_NODE:
  6811. case XML_NOTATION_NODE:
  6812. case XML_DTD_NODE:
  6813. case XML_ELEMENT_DECL:
  6814. case XML_ATTRIBUTE_DECL:
  6815. case XML_ENTITY_DECL:
  6816. case XML_XINCLUDE_START:
  6817. case XML_XINCLUDE_END:
  6818. if (cur->parent == NULL)
  6819. return(NULL);
  6820. if ((cur->parent->type == XML_ELEMENT_NODE) &&
  6821. ((cur->parent->name[0] == ' ') ||
  6822. (xmlStrEqual(cur->parent->name,
  6823. BAD_CAST "fake node libxslt"))))
  6824. return(NULL);
  6825. return(cur->parent);
  6826. case XML_ATTRIBUTE_NODE: {
  6827. xmlAttrPtr att = (xmlAttrPtr) cur;
  6828. return(att->parent);
  6829. }
  6830. case XML_NAMESPACE_DECL: {
  6831. xmlNsPtr ns = (xmlNsPtr) cur;
  6832. if ((ns->next != NULL) &&
  6833. (ns->next->type != XML_NAMESPACE_DECL))
  6834. return((xmlNodePtr) ns->next);
  6835. /* Bad, how did that namespace end up here ? */
  6836. return(NULL);
  6837. }
  6838. case XML_DOCUMENT_NODE:
  6839. case XML_DOCUMENT_TYPE_NODE:
  6840. case XML_DOCUMENT_FRAG_NODE:
  6841. case XML_HTML_DOCUMENT_NODE:
  6842. return(NULL);
  6843. }
  6844. return(NULL);
  6845. }
  6846. /**
  6847. * xmlXPathNextAncestorOrSelf:
  6848. * @ctxt: the XPath Parser context
  6849. * @cur: the current node in the traversal
  6850. *
  6851. * Traversal function for the "ancestor-or-self" direction
  6852. * he ancestor-or-self axis contains the context node and ancestors of
  6853. * the context node in reverse document order; thus the context node is
  6854. * the first node on the axis, and the context node's parent the second;
  6855. * parent here is defined the same as with the parent axis.
  6856. *
  6857. * Returns the next element following that axis
  6858. */
  6859. xmlNodePtr
  6860. xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  6861. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  6862. if (cur == NULL)
  6863. return(ctxt->context->node);
  6864. return(xmlXPathNextAncestor(ctxt, cur));
  6865. }
  6866. /**
  6867. * xmlXPathNextFollowingSibling:
  6868. * @ctxt: the XPath Parser context
  6869. * @cur: the current node in the traversal
  6870. *
  6871. * Traversal function for the "following-sibling" direction
  6872. * The following-sibling axis contains the following siblings of the context
  6873. * node in document order.
  6874. *
  6875. * Returns the next element following that axis
  6876. */
  6877. xmlNodePtr
  6878. xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  6879. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  6880. if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
  6881. (ctxt->context->node->type == XML_NAMESPACE_DECL))
  6882. return(NULL);
  6883. if (cur == (xmlNodePtr) ctxt->context->doc)
  6884. return(NULL);
  6885. if (cur == NULL)
  6886. return(ctxt->context->node->next);
  6887. return(cur->next);
  6888. }
  6889. /**
  6890. * xmlXPathNextPrecedingSibling:
  6891. * @ctxt: the XPath Parser context
  6892. * @cur: the current node in the traversal
  6893. *
  6894. * Traversal function for the "preceding-sibling" direction
  6895. * The preceding-sibling axis contains the preceding siblings of the context
  6896. * node in reverse document order; the first preceding sibling is first on the
  6897. * axis; the sibling preceding that node is the second on the axis and so on.
  6898. *
  6899. * Returns the next element following that axis
  6900. */
  6901. xmlNodePtr
  6902. xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  6903. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  6904. if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
  6905. (ctxt->context->node->type == XML_NAMESPACE_DECL))
  6906. return(NULL);
  6907. if (cur == (xmlNodePtr) ctxt->context->doc)
  6908. return(NULL);
  6909. if (cur == NULL)
  6910. return(ctxt->context->node->prev);
  6911. if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
  6912. cur = cur->prev;
  6913. if (cur == NULL)
  6914. return(ctxt->context->node->prev);
  6915. }
  6916. return(cur->prev);
  6917. }
  6918. /**
  6919. * xmlXPathNextFollowing:
  6920. * @ctxt: the XPath Parser context
  6921. * @cur: the current node in the traversal
  6922. *
  6923. * Traversal function for the "following" direction
  6924. * The following axis contains all nodes in the same document as the context
  6925. * node that are after the context node in document order, excluding any
  6926. * descendants and excluding attribute nodes and namespace nodes; the nodes
  6927. * are ordered in document order
  6928. *
  6929. * Returns the next element following that axis
  6930. */
  6931. xmlNodePtr
  6932. xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  6933. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  6934. if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
  6935. (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
  6936. return(cur->children);
  6937. if (cur == NULL) {
  6938. cur = ctxt->context->node;
  6939. if (cur->type == XML_ATTRIBUTE_NODE) {
  6940. cur = cur->parent;
  6941. } else if (cur->type == XML_NAMESPACE_DECL) {
  6942. xmlNsPtr ns = (xmlNsPtr) cur;
  6943. if ((ns->next == NULL) ||
  6944. (ns->next->type == XML_NAMESPACE_DECL))
  6945. return (NULL);
  6946. cur = (xmlNodePtr) ns->next;
  6947. }
  6948. }
  6949. if (cur == NULL) return(NULL) ; /* ERROR */
  6950. if (cur->next != NULL) return(cur->next) ;
  6951. do {
  6952. cur = cur->parent;
  6953. if (cur == NULL) break;
  6954. if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
  6955. if (cur->next != NULL) return(cur->next);
  6956. } while (cur != NULL);
  6957. return(cur);
  6958. }
  6959. /*
  6960. * xmlXPathIsAncestor:
  6961. * @ancestor: the ancestor node
  6962. * @node: the current node
  6963. *
  6964. * Check that @ancestor is a @node's ancestor
  6965. *
  6966. * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
  6967. */
  6968. static int
  6969. xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
  6970. if ((ancestor == NULL) || (node == NULL)) return(0);
  6971. if (node->type == XML_NAMESPACE_DECL)
  6972. return(0);
  6973. if (ancestor->type == XML_NAMESPACE_DECL)
  6974. return(0);
  6975. /* nodes need to be in the same document */
  6976. if (ancestor->doc != node->doc) return(0);
  6977. /* avoid searching if ancestor or node is the root node */
  6978. if (ancestor == (xmlNodePtr) node->doc) return(1);
  6979. if (node == (xmlNodePtr) ancestor->doc) return(0);
  6980. while (node->parent != NULL) {
  6981. if (node->parent == ancestor)
  6982. return(1);
  6983. node = node->parent;
  6984. }
  6985. return(0);
  6986. }
  6987. /**
  6988. * xmlXPathNextPreceding:
  6989. * @ctxt: the XPath Parser context
  6990. * @cur: the current node in the traversal
  6991. *
  6992. * Traversal function for the "preceding" direction
  6993. * the preceding axis contains all nodes in the same document as the context
  6994. * node that are before the context node in document order, excluding any
  6995. * ancestors and excluding attribute nodes and namespace nodes; the nodes are
  6996. * ordered in reverse document order
  6997. *
  6998. * Returns the next element following that axis
  6999. */
  7000. xmlNodePtr
  7001. xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
  7002. {
  7003. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7004. if (cur == NULL) {
  7005. cur = ctxt->context->node;
  7006. if (cur->type == XML_ATTRIBUTE_NODE) {
  7007. cur = cur->parent;
  7008. } else if (cur->type == XML_NAMESPACE_DECL) {
  7009. xmlNsPtr ns = (xmlNsPtr) cur;
  7010. if ((ns->next == NULL) ||
  7011. (ns->next->type == XML_NAMESPACE_DECL))
  7012. return (NULL);
  7013. cur = (xmlNodePtr) ns->next;
  7014. }
  7015. }
  7016. if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
  7017. return (NULL);
  7018. if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
  7019. cur = cur->prev;
  7020. do {
  7021. if (cur->prev != NULL) {
  7022. for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
  7023. return (cur);
  7024. }
  7025. cur = cur->parent;
  7026. if (cur == NULL)
  7027. return (NULL);
  7028. if (cur == ctxt->context->doc->children)
  7029. return (NULL);
  7030. } while (xmlXPathIsAncestor(cur, ctxt->context->node));
  7031. return (cur);
  7032. }
  7033. /**
  7034. * xmlXPathNextPrecedingInternal:
  7035. * @ctxt: the XPath Parser context
  7036. * @cur: the current node in the traversal
  7037. *
  7038. * Traversal function for the "preceding" direction
  7039. * the preceding axis contains all nodes in the same document as the context
  7040. * node that are before the context node in document order, excluding any
  7041. * ancestors and excluding attribute nodes and namespace nodes; the nodes are
  7042. * ordered in reverse document order
  7043. * This is a faster implementation but internal only since it requires a
  7044. * state kept in the parser context: ctxt->ancestor.
  7045. *
  7046. * Returns the next element following that axis
  7047. */
  7048. static xmlNodePtr
  7049. xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
  7050. xmlNodePtr cur)
  7051. {
  7052. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7053. if (cur == NULL) {
  7054. cur = ctxt->context->node;
  7055. if (cur == NULL)
  7056. return (NULL);
  7057. if (cur->type == XML_ATTRIBUTE_NODE) {
  7058. cur = cur->parent;
  7059. } else if (cur->type == XML_NAMESPACE_DECL) {
  7060. xmlNsPtr ns = (xmlNsPtr) cur;
  7061. if ((ns->next == NULL) ||
  7062. (ns->next->type == XML_NAMESPACE_DECL))
  7063. return (NULL);
  7064. cur = (xmlNodePtr) ns->next;
  7065. }
  7066. ctxt->ancestor = cur->parent;
  7067. }
  7068. if (cur->type == XML_NAMESPACE_DECL)
  7069. return(NULL);
  7070. if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
  7071. cur = cur->prev;
  7072. while (cur->prev == NULL) {
  7073. cur = cur->parent;
  7074. if (cur == NULL)
  7075. return (NULL);
  7076. if (cur == ctxt->context->doc->children)
  7077. return (NULL);
  7078. if (cur != ctxt->ancestor)
  7079. return (cur);
  7080. ctxt->ancestor = cur->parent;
  7081. }
  7082. cur = cur->prev;
  7083. while (cur->last != NULL)
  7084. cur = cur->last;
  7085. return (cur);
  7086. }
  7087. /**
  7088. * xmlXPathNextNamespace:
  7089. * @ctxt: the XPath Parser context
  7090. * @cur: the current attribute in the traversal
  7091. *
  7092. * Traversal function for the "namespace" direction
  7093. * the namespace axis contains the namespace nodes of the context node;
  7094. * the order of nodes on this axis is implementation-defined; the axis will
  7095. * be empty unless the context node is an element
  7096. *
  7097. * We keep the XML namespace node at the end of the list.
  7098. *
  7099. * Returns the next element following that axis
  7100. */
  7101. xmlNodePtr
  7102. xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7103. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7104. if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
  7105. if (cur == NULL) {
  7106. if (ctxt->context->tmpNsList != NULL)
  7107. xmlFree(ctxt->context->tmpNsList);
  7108. ctxt->context->tmpNsList =
  7109. xmlGetNsList(ctxt->context->doc, ctxt->context->node);
  7110. ctxt->context->tmpNsNr = 0;
  7111. if (ctxt->context->tmpNsList != NULL) {
  7112. while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
  7113. ctxt->context->tmpNsNr++;
  7114. }
  7115. }
  7116. return((xmlNodePtr) xmlXPathXMLNamespace);
  7117. }
  7118. if (ctxt->context->tmpNsNr > 0) {
  7119. return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
  7120. } else {
  7121. if (ctxt->context->tmpNsList != NULL)
  7122. xmlFree(ctxt->context->tmpNsList);
  7123. ctxt->context->tmpNsList = NULL;
  7124. return(NULL);
  7125. }
  7126. }
  7127. /**
  7128. * xmlXPathNextAttribute:
  7129. * @ctxt: the XPath Parser context
  7130. * @cur: the current attribute in the traversal
  7131. *
  7132. * Traversal function for the "attribute" direction
  7133. * TODO: support DTD inherited default attributes
  7134. *
  7135. * Returns the next element following that axis
  7136. */
  7137. xmlNodePtr
  7138. xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7139. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7140. if (ctxt->context->node == NULL)
  7141. return(NULL);
  7142. if (ctxt->context->node->type != XML_ELEMENT_NODE)
  7143. return(NULL);
  7144. if (cur == NULL) {
  7145. if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
  7146. return(NULL);
  7147. return((xmlNodePtr)ctxt->context->node->properties);
  7148. }
  7149. return((xmlNodePtr)cur->next);
  7150. }
  7151. /************************************************************************
  7152. * *
  7153. * NodeTest Functions *
  7154. * *
  7155. ************************************************************************/
  7156. #define IS_FUNCTION 200
  7157. /************************************************************************
  7158. * *
  7159. * Implicit tree core function library *
  7160. * *
  7161. ************************************************************************/
  7162. /**
  7163. * xmlXPathRoot:
  7164. * @ctxt: the XPath Parser context
  7165. *
  7166. * Initialize the context to the root of the document
  7167. */
  7168. void
  7169. xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
  7170. if ((ctxt == NULL) || (ctxt->context == NULL))
  7171. return;
  7172. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  7173. (xmlNodePtr) ctxt->context->doc));
  7174. }
  7175. /************************************************************************
  7176. * *
  7177. * The explicit core function library *
  7178. *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
  7179. * *
  7180. ************************************************************************/
  7181. /**
  7182. * xmlXPathLastFunction:
  7183. * @ctxt: the XPath Parser context
  7184. * @nargs: the number of arguments
  7185. *
  7186. * Implement the last() XPath function
  7187. * number last()
  7188. * The last function returns the number of nodes in the context node list.
  7189. */
  7190. void
  7191. xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7192. CHECK_ARITY(0);
  7193. if (ctxt->context->contextSize >= 0) {
  7194. valuePush(ctxt,
  7195. xmlXPathCacheNewFloat(ctxt->context,
  7196. (double) ctxt->context->contextSize));
  7197. } else {
  7198. XP_ERROR(XPATH_INVALID_CTXT_SIZE);
  7199. }
  7200. }
  7201. /**
  7202. * xmlXPathPositionFunction:
  7203. * @ctxt: the XPath Parser context
  7204. * @nargs: the number of arguments
  7205. *
  7206. * Implement the position() XPath function
  7207. * number position()
  7208. * The position function returns the position of the context node in the
  7209. * context node list. The first position is 1, and so the last position
  7210. * will be equal to last().
  7211. */
  7212. void
  7213. xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7214. CHECK_ARITY(0);
  7215. if (ctxt->context->proximityPosition >= 0) {
  7216. valuePush(ctxt,
  7217. xmlXPathCacheNewFloat(ctxt->context,
  7218. (double) ctxt->context->proximityPosition));
  7219. } else {
  7220. XP_ERROR(XPATH_INVALID_CTXT_POSITION);
  7221. }
  7222. }
  7223. /**
  7224. * xmlXPathCountFunction:
  7225. * @ctxt: the XPath Parser context
  7226. * @nargs: the number of arguments
  7227. *
  7228. * Implement the count() XPath function
  7229. * number count(node-set)
  7230. */
  7231. void
  7232. xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7233. xmlXPathObjectPtr cur;
  7234. CHECK_ARITY(1);
  7235. if ((ctxt->value == NULL) ||
  7236. ((ctxt->value->type != XPATH_NODESET) &&
  7237. (ctxt->value->type != XPATH_XSLT_TREE)))
  7238. XP_ERROR(XPATH_INVALID_TYPE);
  7239. cur = valuePop(ctxt);
  7240. if ((cur == NULL) || (cur->nodesetval == NULL))
  7241. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
  7242. else
  7243. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
  7244. (double) cur->nodesetval->nodeNr));
  7245. xmlXPathReleaseObject(ctxt->context, cur);
  7246. }
  7247. /**
  7248. * xmlXPathGetElementsByIds:
  7249. * @doc: the document
  7250. * @ids: a whitespace separated list of IDs
  7251. *
  7252. * Selects elements by their unique ID.
  7253. *
  7254. * Returns a node-set of selected elements.
  7255. */
  7256. static xmlNodeSetPtr
  7257. xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
  7258. xmlNodeSetPtr ret;
  7259. const xmlChar *cur = ids;
  7260. xmlChar *ID;
  7261. xmlAttrPtr attr;
  7262. xmlNodePtr elem = NULL;
  7263. if (ids == NULL) return(NULL);
  7264. ret = xmlXPathNodeSetCreate(NULL);
  7265. if (ret == NULL)
  7266. return(ret);
  7267. while (IS_BLANK_CH(*cur)) cur++;
  7268. while (*cur != 0) {
  7269. while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
  7270. cur++;
  7271. ID = xmlStrndup(ids, cur - ids);
  7272. if (ID != NULL) {
  7273. /*
  7274. * We used to check the fact that the value passed
  7275. * was an NCName, but this generated much troubles for
  7276. * me and Aleksey Sanin, people blatantly violated that
  7277. * constraint, like Visa3D spec.
  7278. * if (xmlValidateNCName(ID, 1) == 0)
  7279. */
  7280. attr = xmlGetID(doc, ID);
  7281. if (attr != NULL) {
  7282. if (attr->type == XML_ATTRIBUTE_NODE)
  7283. elem = attr->parent;
  7284. else if (attr->type == XML_ELEMENT_NODE)
  7285. elem = (xmlNodePtr) attr;
  7286. else
  7287. elem = NULL;
  7288. /* TODO: Check memory error. */
  7289. if (elem != NULL)
  7290. xmlXPathNodeSetAdd(ret, elem);
  7291. }
  7292. xmlFree(ID);
  7293. }
  7294. while (IS_BLANK_CH(*cur)) cur++;
  7295. ids = cur;
  7296. }
  7297. return(ret);
  7298. }
  7299. /**
  7300. * xmlXPathIdFunction:
  7301. * @ctxt: the XPath Parser context
  7302. * @nargs: the number of arguments
  7303. *
  7304. * Implement the id() XPath function
  7305. * node-set id(object)
  7306. * The id function selects elements by their unique ID
  7307. * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
  7308. * then the result is the union of the result of applying id to the
  7309. * string value of each of the nodes in the argument node-set. When the
  7310. * argument to id is of any other type, the argument is converted to a
  7311. * string as if by a call to the string function; the string is split
  7312. * into a whitespace-separated list of tokens (whitespace is any sequence
  7313. * of characters matching the production S); the result is a node-set
  7314. * containing the elements in the same document as the context node that
  7315. * have a unique ID equal to any of the tokens in the list.
  7316. */
  7317. void
  7318. xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7319. xmlChar *tokens;
  7320. xmlNodeSetPtr ret;
  7321. xmlXPathObjectPtr obj;
  7322. CHECK_ARITY(1);
  7323. obj = valuePop(ctxt);
  7324. if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
  7325. if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
  7326. xmlNodeSetPtr ns;
  7327. int i;
  7328. /* TODO: Check memory error. */
  7329. ret = xmlXPathNodeSetCreate(NULL);
  7330. if (obj->nodesetval != NULL) {
  7331. for (i = 0; i < obj->nodesetval->nodeNr; i++) {
  7332. tokens =
  7333. xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
  7334. ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
  7335. /* TODO: Check memory error. */
  7336. ret = xmlXPathNodeSetMerge(ret, ns);
  7337. xmlXPathFreeNodeSet(ns);
  7338. if (tokens != NULL)
  7339. xmlFree(tokens);
  7340. }
  7341. }
  7342. xmlXPathReleaseObject(ctxt->context, obj);
  7343. valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
  7344. return;
  7345. }
  7346. obj = xmlXPathCacheConvertString(ctxt->context, obj);
  7347. if (obj == NULL) return;
  7348. ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
  7349. valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
  7350. xmlXPathReleaseObject(ctxt->context, obj);
  7351. return;
  7352. }
  7353. /**
  7354. * xmlXPathLocalNameFunction:
  7355. * @ctxt: the XPath Parser context
  7356. * @nargs: the number of arguments
  7357. *
  7358. * Implement the local-name() XPath function
  7359. * string local-name(node-set?)
  7360. * The local-name function returns a string containing the local part
  7361. * of the name of the node in the argument node-set that is first in
  7362. * document order. If the node-set is empty or the first node has no
  7363. * name, an empty string is returned. If the argument is omitted it
  7364. * defaults to the context node.
  7365. */
  7366. void
  7367. xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7368. xmlXPathObjectPtr cur;
  7369. if (ctxt == NULL) return;
  7370. if (nargs == 0) {
  7371. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  7372. ctxt->context->node));
  7373. nargs = 1;
  7374. }
  7375. CHECK_ARITY(1);
  7376. if ((ctxt->value == NULL) ||
  7377. ((ctxt->value->type != XPATH_NODESET) &&
  7378. (ctxt->value->type != XPATH_XSLT_TREE)))
  7379. XP_ERROR(XPATH_INVALID_TYPE);
  7380. cur = valuePop(ctxt);
  7381. if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
  7382. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  7383. } else {
  7384. int i = 0; /* Should be first in document order !!!!! */
  7385. switch (cur->nodesetval->nodeTab[i]->type) {
  7386. case XML_ELEMENT_NODE:
  7387. case XML_ATTRIBUTE_NODE:
  7388. case XML_PI_NODE:
  7389. if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
  7390. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  7391. else
  7392. valuePush(ctxt,
  7393. xmlXPathCacheNewString(ctxt->context,
  7394. cur->nodesetval->nodeTab[i]->name));
  7395. break;
  7396. case XML_NAMESPACE_DECL:
  7397. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  7398. ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
  7399. break;
  7400. default:
  7401. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  7402. }
  7403. }
  7404. xmlXPathReleaseObject(ctxt->context, cur);
  7405. }
  7406. /**
  7407. * xmlXPathNamespaceURIFunction:
  7408. * @ctxt: the XPath Parser context
  7409. * @nargs: the number of arguments
  7410. *
  7411. * Implement the namespace-uri() XPath function
  7412. * string namespace-uri(node-set?)
  7413. * The namespace-uri function returns a string containing the
  7414. * namespace URI of the expanded name of the node in the argument
  7415. * node-set that is first in document order. If the node-set is empty,
  7416. * the first node has no name, or the expanded name has no namespace
  7417. * URI, an empty string is returned. If the argument is omitted it
  7418. * defaults to the context node.
  7419. */
  7420. void
  7421. xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7422. xmlXPathObjectPtr cur;
  7423. if (ctxt == NULL) return;
  7424. if (nargs == 0) {
  7425. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  7426. ctxt->context->node));
  7427. nargs = 1;
  7428. }
  7429. CHECK_ARITY(1);
  7430. if ((ctxt->value == NULL) ||
  7431. ((ctxt->value->type != XPATH_NODESET) &&
  7432. (ctxt->value->type != XPATH_XSLT_TREE)))
  7433. XP_ERROR(XPATH_INVALID_TYPE);
  7434. cur = valuePop(ctxt);
  7435. if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
  7436. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  7437. } else {
  7438. int i = 0; /* Should be first in document order !!!!! */
  7439. switch (cur->nodesetval->nodeTab[i]->type) {
  7440. case XML_ELEMENT_NODE:
  7441. case XML_ATTRIBUTE_NODE:
  7442. if (cur->nodesetval->nodeTab[i]->ns == NULL)
  7443. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  7444. else
  7445. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  7446. cur->nodesetval->nodeTab[i]->ns->href));
  7447. break;
  7448. default:
  7449. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  7450. }
  7451. }
  7452. xmlXPathReleaseObject(ctxt->context, cur);
  7453. }
  7454. /**
  7455. * xmlXPathNameFunction:
  7456. * @ctxt: the XPath Parser context
  7457. * @nargs: the number of arguments
  7458. *
  7459. * Implement the name() XPath function
  7460. * string name(node-set?)
  7461. * The name function returns a string containing a QName representing
  7462. * the name of the node in the argument node-set that is first in document
  7463. * order. The QName must represent the name with respect to the namespace
  7464. * declarations in effect on the node whose name is being represented.
  7465. * Typically, this will be the form in which the name occurred in the XML
  7466. * source. This need not be the case if there are namespace declarations
  7467. * in effect on the node that associate multiple prefixes with the same
  7468. * namespace. However, an implementation may include information about
  7469. * the original prefix in its representation of nodes; in this case, an
  7470. * implementation can ensure that the returned string is always the same
  7471. * as the QName used in the XML source. If the argument it omitted it
  7472. * defaults to the context node.
  7473. * Libxml keep the original prefix so the "real qualified name" used is
  7474. * returned.
  7475. */
  7476. static void
  7477. xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
  7478. {
  7479. xmlXPathObjectPtr cur;
  7480. if (nargs == 0) {
  7481. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  7482. ctxt->context->node));
  7483. nargs = 1;
  7484. }
  7485. CHECK_ARITY(1);
  7486. if ((ctxt->value == NULL) ||
  7487. ((ctxt->value->type != XPATH_NODESET) &&
  7488. (ctxt->value->type != XPATH_XSLT_TREE)))
  7489. XP_ERROR(XPATH_INVALID_TYPE);
  7490. cur = valuePop(ctxt);
  7491. if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
  7492. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  7493. } else {
  7494. int i = 0; /* Should be first in document order !!!!! */
  7495. switch (cur->nodesetval->nodeTab[i]->type) {
  7496. case XML_ELEMENT_NODE:
  7497. case XML_ATTRIBUTE_NODE:
  7498. if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
  7499. valuePush(ctxt,
  7500. xmlXPathCacheNewCString(ctxt->context, ""));
  7501. else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
  7502. (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
  7503. valuePush(ctxt,
  7504. xmlXPathCacheNewString(ctxt->context,
  7505. cur->nodesetval->nodeTab[i]->name));
  7506. } else {
  7507. xmlChar *fullname;
  7508. fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
  7509. cur->nodesetval->nodeTab[i]->ns->prefix,
  7510. NULL, 0);
  7511. if (fullname == cur->nodesetval->nodeTab[i]->name)
  7512. fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
  7513. if (fullname == NULL)
  7514. xmlXPathPErrMemory(ctxt, NULL);
  7515. valuePush(ctxt, xmlXPathCacheWrapString(
  7516. ctxt->context, fullname));
  7517. }
  7518. break;
  7519. default:
  7520. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  7521. cur->nodesetval->nodeTab[i]));
  7522. xmlXPathLocalNameFunction(ctxt, 1);
  7523. }
  7524. }
  7525. xmlXPathReleaseObject(ctxt->context, cur);
  7526. }
  7527. /**
  7528. * xmlXPathStringFunction:
  7529. * @ctxt: the XPath Parser context
  7530. * @nargs: the number of arguments
  7531. *
  7532. * Implement the string() XPath function
  7533. * string string(object?)
  7534. * The string function converts an object to a string as follows:
  7535. * - A node-set is converted to a string by returning the value of
  7536. * the node in the node-set that is first in document order.
  7537. * If the node-set is empty, an empty string is returned.
  7538. * - A number is converted to a string as follows
  7539. * + NaN is converted to the string NaN
  7540. * + positive zero is converted to the string 0
  7541. * + negative zero is converted to the string 0
  7542. * + positive infinity is converted to the string Infinity
  7543. * + negative infinity is converted to the string -Infinity
  7544. * + if the number is an integer, the number is represented in
  7545. * decimal form as a Number with no decimal point and no leading
  7546. * zeros, preceded by a minus sign (-) if the number is negative
  7547. * + otherwise, the number is represented in decimal form as a
  7548. * Number including a decimal point with at least one digit
  7549. * before the decimal point and at least one digit after the
  7550. * decimal point, preceded by a minus sign (-) if the number
  7551. * is negative; there must be no leading zeros before the decimal
  7552. * point apart possibly from the one required digit immediately
  7553. * before the decimal point; beyond the one required digit
  7554. * after the decimal point there must be as many, but only as
  7555. * many, more digits as are needed to uniquely distinguish the
  7556. * number from all other IEEE 754 numeric values.
  7557. * - The boolean false value is converted to the string false.
  7558. * The boolean true value is converted to the string true.
  7559. *
  7560. * If the argument is omitted, it defaults to a node-set with the
  7561. * context node as its only member.
  7562. */
  7563. void
  7564. xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7565. xmlXPathObjectPtr cur;
  7566. if (ctxt == NULL) return;
  7567. if (nargs == 0) {
  7568. valuePush(ctxt,
  7569. xmlXPathCacheWrapString(ctxt->context,
  7570. xmlXPathCastNodeToString(ctxt->context->node)));
  7571. return;
  7572. }
  7573. CHECK_ARITY(1);
  7574. cur = valuePop(ctxt);
  7575. if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
  7576. valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
  7577. }
  7578. /**
  7579. * xmlXPathStringLengthFunction:
  7580. * @ctxt: the XPath Parser context
  7581. * @nargs: the number of arguments
  7582. *
  7583. * Implement the string-length() XPath function
  7584. * number string-length(string?)
  7585. * The string-length returns the number of characters in the string
  7586. * (see [3.6 Strings]). If the argument is omitted, it defaults to
  7587. * the context node converted to a string, in other words the value
  7588. * of the context node.
  7589. */
  7590. void
  7591. xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7592. xmlXPathObjectPtr cur;
  7593. if (nargs == 0) {
  7594. if ((ctxt == NULL) || (ctxt->context == NULL))
  7595. return;
  7596. if (ctxt->context->node == NULL) {
  7597. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
  7598. } else {
  7599. xmlChar *content;
  7600. content = xmlXPathCastNodeToString(ctxt->context->node);
  7601. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
  7602. xmlUTF8Strlen(content)));
  7603. xmlFree(content);
  7604. }
  7605. return;
  7606. }
  7607. CHECK_ARITY(1);
  7608. CAST_TO_STRING;
  7609. CHECK_TYPE(XPATH_STRING);
  7610. cur = valuePop(ctxt);
  7611. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
  7612. xmlUTF8Strlen(cur->stringval)));
  7613. xmlXPathReleaseObject(ctxt->context, cur);
  7614. }
  7615. /**
  7616. * xmlXPathConcatFunction:
  7617. * @ctxt: the XPath Parser context
  7618. * @nargs: the number of arguments
  7619. *
  7620. * Implement the concat() XPath function
  7621. * string concat(string, string, string*)
  7622. * The concat function returns the concatenation of its arguments.
  7623. */
  7624. void
  7625. xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7626. xmlXPathObjectPtr cur, newobj;
  7627. xmlChar *tmp;
  7628. if (ctxt == NULL) return;
  7629. if (nargs < 2) {
  7630. CHECK_ARITY(2);
  7631. }
  7632. CAST_TO_STRING;
  7633. cur = valuePop(ctxt);
  7634. if ((cur == NULL) || (cur->type != XPATH_STRING)) {
  7635. xmlXPathReleaseObject(ctxt->context, cur);
  7636. return;
  7637. }
  7638. nargs--;
  7639. while (nargs > 0) {
  7640. CAST_TO_STRING;
  7641. newobj = valuePop(ctxt);
  7642. if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
  7643. xmlXPathReleaseObject(ctxt->context, newobj);
  7644. xmlXPathReleaseObject(ctxt->context, cur);
  7645. XP_ERROR(XPATH_INVALID_TYPE);
  7646. }
  7647. tmp = xmlStrcat(newobj->stringval, cur->stringval);
  7648. newobj->stringval = cur->stringval;
  7649. cur->stringval = tmp;
  7650. xmlXPathReleaseObject(ctxt->context, newobj);
  7651. nargs--;
  7652. }
  7653. valuePush(ctxt, cur);
  7654. }
  7655. /**
  7656. * xmlXPathContainsFunction:
  7657. * @ctxt: the XPath Parser context
  7658. * @nargs: the number of arguments
  7659. *
  7660. * Implement the contains() XPath function
  7661. * boolean contains(string, string)
  7662. * The contains function returns true if the first argument string
  7663. * contains the second argument string, and otherwise returns false.
  7664. */
  7665. void
  7666. xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7667. xmlXPathObjectPtr hay, needle;
  7668. CHECK_ARITY(2);
  7669. CAST_TO_STRING;
  7670. CHECK_TYPE(XPATH_STRING);
  7671. needle = valuePop(ctxt);
  7672. CAST_TO_STRING;
  7673. hay = valuePop(ctxt);
  7674. if ((hay == NULL) || (hay->type != XPATH_STRING)) {
  7675. xmlXPathReleaseObject(ctxt->context, hay);
  7676. xmlXPathReleaseObject(ctxt->context, needle);
  7677. XP_ERROR(XPATH_INVALID_TYPE);
  7678. }
  7679. if (xmlStrstr(hay->stringval, needle->stringval))
  7680. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
  7681. else
  7682. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
  7683. xmlXPathReleaseObject(ctxt->context, hay);
  7684. xmlXPathReleaseObject(ctxt->context, needle);
  7685. }
  7686. /**
  7687. * xmlXPathStartsWithFunction:
  7688. * @ctxt: the XPath Parser context
  7689. * @nargs: the number of arguments
  7690. *
  7691. * Implement the starts-with() XPath function
  7692. * boolean starts-with(string, string)
  7693. * The starts-with function returns true if the first argument string
  7694. * starts with the second argument string, and otherwise returns false.
  7695. */
  7696. void
  7697. xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7698. xmlXPathObjectPtr hay, needle;
  7699. int n;
  7700. CHECK_ARITY(2);
  7701. CAST_TO_STRING;
  7702. CHECK_TYPE(XPATH_STRING);
  7703. needle = valuePop(ctxt);
  7704. CAST_TO_STRING;
  7705. hay = valuePop(ctxt);
  7706. if ((hay == NULL) || (hay->type != XPATH_STRING)) {
  7707. xmlXPathReleaseObject(ctxt->context, hay);
  7708. xmlXPathReleaseObject(ctxt->context, needle);
  7709. XP_ERROR(XPATH_INVALID_TYPE);
  7710. }
  7711. n = xmlStrlen(needle->stringval);
  7712. if (xmlStrncmp(hay->stringval, needle->stringval, n))
  7713. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
  7714. else
  7715. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
  7716. xmlXPathReleaseObject(ctxt->context, hay);
  7717. xmlXPathReleaseObject(ctxt->context, needle);
  7718. }
  7719. /**
  7720. * xmlXPathSubstringFunction:
  7721. * @ctxt: the XPath Parser context
  7722. * @nargs: the number of arguments
  7723. *
  7724. * Implement the substring() XPath function
  7725. * string substring(string, number, number?)
  7726. * The substring function returns the substring of the first argument
  7727. * starting at the position specified in the second argument with
  7728. * length specified in the third argument. For example,
  7729. * substring("12345",2,3) returns "234". If the third argument is not
  7730. * specified, it returns the substring starting at the position specified
  7731. * in the second argument and continuing to the end of the string. For
  7732. * example, substring("12345",2) returns "2345". More precisely, each
  7733. * character in the string (see [3.6 Strings]) is considered to have a
  7734. * numeric position: the position of the first character is 1, the position
  7735. * of the second character is 2 and so on. The returned substring contains
  7736. * those characters for which the position of the character is greater than
  7737. * or equal to the second argument and, if the third argument is specified,
  7738. * less than the sum of the second and third arguments; the comparisons
  7739. * and addition used for the above follow the standard IEEE 754 rules. Thus:
  7740. * - substring("12345", 1.5, 2.6) returns "234"
  7741. * - substring("12345", 0, 3) returns "12"
  7742. * - substring("12345", 0 div 0, 3) returns ""
  7743. * - substring("12345", 1, 0 div 0) returns ""
  7744. * - substring("12345", -42, 1 div 0) returns "12345"
  7745. * - substring("12345", -1 div 0, 1 div 0) returns ""
  7746. */
  7747. void
  7748. xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7749. xmlXPathObjectPtr str, start, len;
  7750. double le=0, in;
  7751. int i = 1, j = INT_MAX;
  7752. if (nargs < 2) {
  7753. CHECK_ARITY(2);
  7754. }
  7755. if (nargs > 3) {
  7756. CHECK_ARITY(3);
  7757. }
  7758. /*
  7759. * take care of possible last (position) argument
  7760. */
  7761. if (nargs == 3) {
  7762. CAST_TO_NUMBER;
  7763. CHECK_TYPE(XPATH_NUMBER);
  7764. len = valuePop(ctxt);
  7765. le = len->floatval;
  7766. xmlXPathReleaseObject(ctxt->context, len);
  7767. }
  7768. CAST_TO_NUMBER;
  7769. CHECK_TYPE(XPATH_NUMBER);
  7770. start = valuePop(ctxt);
  7771. in = start->floatval;
  7772. xmlXPathReleaseObject(ctxt->context, start);
  7773. CAST_TO_STRING;
  7774. CHECK_TYPE(XPATH_STRING);
  7775. str = valuePop(ctxt);
  7776. if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
  7777. i = INT_MAX;
  7778. } else if (in >= 1.0) {
  7779. i = (int)in;
  7780. if (in - floor(in) >= 0.5)
  7781. i += 1;
  7782. }
  7783. if (nargs == 3) {
  7784. double rin, rle, end;
  7785. rin = floor(in);
  7786. if (in - rin >= 0.5)
  7787. rin += 1.0;
  7788. rle = floor(le);
  7789. if (le - rle >= 0.5)
  7790. rle += 1.0;
  7791. end = rin + rle;
  7792. if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
  7793. j = 1;
  7794. } else if (end < INT_MAX) {
  7795. j = (int)end;
  7796. }
  7797. }
  7798. if (i < j) {
  7799. xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
  7800. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
  7801. xmlFree(ret);
  7802. } else {
  7803. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  7804. }
  7805. xmlXPathReleaseObject(ctxt->context, str);
  7806. }
  7807. /**
  7808. * xmlXPathSubstringBeforeFunction:
  7809. * @ctxt: the XPath Parser context
  7810. * @nargs: the number of arguments
  7811. *
  7812. * Implement the substring-before() XPath function
  7813. * string substring-before(string, string)
  7814. * The substring-before function returns the substring of the first
  7815. * argument string that precedes the first occurrence of the second
  7816. * argument string in the first argument string, or the empty string
  7817. * if the first argument string does not contain the second argument
  7818. * string. For example, substring-before("1999/04/01","/") returns 1999.
  7819. */
  7820. void
  7821. xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7822. xmlXPathObjectPtr str;
  7823. xmlXPathObjectPtr find;
  7824. xmlBufPtr target;
  7825. const xmlChar *point;
  7826. int offset;
  7827. CHECK_ARITY(2);
  7828. CAST_TO_STRING;
  7829. find = valuePop(ctxt);
  7830. CAST_TO_STRING;
  7831. str = valuePop(ctxt);
  7832. target = xmlBufCreate();
  7833. if (target) {
  7834. point = xmlStrstr(str->stringval, find->stringval);
  7835. if (point) {
  7836. offset = point - str->stringval;
  7837. xmlBufAdd(target, str->stringval, offset);
  7838. }
  7839. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  7840. xmlBufContent(target)));
  7841. xmlBufFree(target);
  7842. }
  7843. xmlXPathReleaseObject(ctxt->context, str);
  7844. xmlXPathReleaseObject(ctxt->context, find);
  7845. }
  7846. /**
  7847. * xmlXPathSubstringAfterFunction:
  7848. * @ctxt: the XPath Parser context
  7849. * @nargs: the number of arguments
  7850. *
  7851. * Implement the substring-after() XPath function
  7852. * string substring-after(string, string)
  7853. * The substring-after function returns the substring of the first
  7854. * argument string that follows the first occurrence of the second
  7855. * argument string in the first argument string, or the empty stringi
  7856. * if the first argument string does not contain the second argument
  7857. * string. For example, substring-after("1999/04/01","/") returns 04/01,
  7858. * and substring-after("1999/04/01","19") returns 99/04/01.
  7859. */
  7860. void
  7861. xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7862. xmlXPathObjectPtr str;
  7863. xmlXPathObjectPtr find;
  7864. xmlBufPtr target;
  7865. const xmlChar *point;
  7866. int offset;
  7867. CHECK_ARITY(2);
  7868. CAST_TO_STRING;
  7869. find = valuePop(ctxt);
  7870. CAST_TO_STRING;
  7871. str = valuePop(ctxt);
  7872. target = xmlBufCreate();
  7873. if (target) {
  7874. point = xmlStrstr(str->stringval, find->stringval);
  7875. if (point) {
  7876. offset = point - str->stringval + xmlStrlen(find->stringval);
  7877. xmlBufAdd(target, &str->stringval[offset],
  7878. xmlStrlen(str->stringval) - offset);
  7879. }
  7880. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  7881. xmlBufContent(target)));
  7882. xmlBufFree(target);
  7883. }
  7884. xmlXPathReleaseObject(ctxt->context, str);
  7885. xmlXPathReleaseObject(ctxt->context, find);
  7886. }
  7887. /**
  7888. * xmlXPathNormalizeFunction:
  7889. * @ctxt: the XPath Parser context
  7890. * @nargs: the number of arguments
  7891. *
  7892. * Implement the normalize-space() XPath function
  7893. * string normalize-space(string?)
  7894. * The normalize-space function returns the argument string with white
  7895. * space normalized by stripping leading and trailing whitespace
  7896. * and replacing sequences of whitespace characters by a single
  7897. * space. Whitespace characters are the same allowed by the S production
  7898. * in XML. If the argument is omitted, it defaults to the context
  7899. * node converted to a string, in other words the value of the context node.
  7900. */
  7901. void
  7902. xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7903. xmlChar *source, *target;
  7904. int blank;
  7905. if (ctxt == NULL) return;
  7906. if (nargs == 0) {
  7907. /* Use current context node */
  7908. valuePush(ctxt,
  7909. xmlXPathCacheWrapString(ctxt->context,
  7910. xmlXPathCastNodeToString(ctxt->context->node)));
  7911. nargs = 1;
  7912. }
  7913. CHECK_ARITY(1);
  7914. CAST_TO_STRING;
  7915. CHECK_TYPE(XPATH_STRING);
  7916. source = ctxt->value->stringval;
  7917. if (source == NULL)
  7918. return;
  7919. target = source;
  7920. /* Skip leading whitespaces */
  7921. while (IS_BLANK_CH(*source))
  7922. source++;
  7923. /* Collapse intermediate whitespaces, and skip trailing whitespaces */
  7924. blank = 0;
  7925. while (*source) {
  7926. if (IS_BLANK_CH(*source)) {
  7927. blank = 1;
  7928. } else {
  7929. if (blank) {
  7930. *target++ = 0x20;
  7931. blank = 0;
  7932. }
  7933. *target++ = *source;
  7934. }
  7935. source++;
  7936. }
  7937. *target = 0;
  7938. }
  7939. /**
  7940. * xmlXPathTranslateFunction:
  7941. * @ctxt: the XPath Parser context
  7942. * @nargs: the number of arguments
  7943. *
  7944. * Implement the translate() XPath function
  7945. * string translate(string, string, string)
  7946. * The translate function returns the first argument string with
  7947. * occurrences of characters in the second argument string replaced
  7948. * by the character at the corresponding position in the third argument
  7949. * string. For example, translate("bar","abc","ABC") returns the string
  7950. * BAr. If there is a character in the second argument string with no
  7951. * character at a corresponding position in the third argument string
  7952. * (because the second argument string is longer than the third argument
  7953. * string), then occurrences of that character in the first argument
  7954. * string are removed. For example, translate("--aaa--","abc-","ABC")
  7955. * returns "AAA". If a character occurs more than once in second
  7956. * argument string, then the first occurrence determines the replacement
  7957. * character. If the third argument string is longer than the second
  7958. * argument string, then excess characters are ignored.
  7959. */
  7960. void
  7961. xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7962. xmlXPathObjectPtr str;
  7963. xmlXPathObjectPtr from;
  7964. xmlXPathObjectPtr to;
  7965. xmlBufPtr target;
  7966. int offset, max;
  7967. int ch;
  7968. const xmlChar *point;
  7969. xmlChar *cptr;
  7970. CHECK_ARITY(3);
  7971. CAST_TO_STRING;
  7972. to = valuePop(ctxt);
  7973. CAST_TO_STRING;
  7974. from = valuePop(ctxt);
  7975. CAST_TO_STRING;
  7976. str = valuePop(ctxt);
  7977. target = xmlBufCreate();
  7978. if (target) {
  7979. max = xmlUTF8Strlen(to->stringval);
  7980. for (cptr = str->stringval; (ch=*cptr); ) {
  7981. offset = xmlUTF8Strloc(from->stringval, cptr);
  7982. if (offset >= 0) {
  7983. if (offset < max) {
  7984. point = xmlUTF8Strpos(to->stringval, offset);
  7985. if (point)
  7986. xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
  7987. }
  7988. } else
  7989. xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
  7990. /* Step to next character in input */
  7991. cptr++;
  7992. if ( ch & 0x80 ) {
  7993. /* if not simple ascii, verify proper format */
  7994. if ( (ch & 0xc0) != 0xc0 ) {
  7995. xmlGenericError(xmlGenericErrorContext,
  7996. "xmlXPathTranslateFunction: Invalid UTF8 string\n");
  7997. /* not asserting an XPath error is probably better */
  7998. break;
  7999. }
  8000. /* then skip over remaining bytes for this char */
  8001. while ( (ch <<= 1) & 0x80 )
  8002. if ( (*cptr++ & 0xc0) != 0x80 ) {
  8003. xmlGenericError(xmlGenericErrorContext,
  8004. "xmlXPathTranslateFunction: Invalid UTF8 string\n");
  8005. /* not asserting an XPath error is probably better */
  8006. break;
  8007. }
  8008. if (ch & 0x80) /* must have had error encountered */
  8009. break;
  8010. }
  8011. }
  8012. }
  8013. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  8014. xmlBufContent(target)));
  8015. xmlBufFree(target);
  8016. xmlXPathReleaseObject(ctxt->context, str);
  8017. xmlXPathReleaseObject(ctxt->context, from);
  8018. xmlXPathReleaseObject(ctxt->context, to);
  8019. }
  8020. /**
  8021. * xmlXPathBooleanFunction:
  8022. * @ctxt: the XPath Parser context
  8023. * @nargs: the number of arguments
  8024. *
  8025. * Implement the boolean() XPath function
  8026. * boolean boolean(object)
  8027. * The boolean function converts its argument to a boolean as follows:
  8028. * - a number is true if and only if it is neither positive or
  8029. * negative zero nor NaN
  8030. * - a node-set is true if and only if it is non-empty
  8031. * - a string is true if and only if its length is non-zero
  8032. */
  8033. void
  8034. xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8035. xmlXPathObjectPtr cur;
  8036. CHECK_ARITY(1);
  8037. cur = valuePop(ctxt);
  8038. if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
  8039. cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
  8040. valuePush(ctxt, cur);
  8041. }
  8042. /**
  8043. * xmlXPathNotFunction:
  8044. * @ctxt: the XPath Parser context
  8045. * @nargs: the number of arguments
  8046. *
  8047. * Implement the not() XPath function
  8048. * boolean not(boolean)
  8049. * The not function returns true if its argument is false,
  8050. * and false otherwise.
  8051. */
  8052. void
  8053. xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8054. CHECK_ARITY(1);
  8055. CAST_TO_BOOLEAN;
  8056. CHECK_TYPE(XPATH_BOOLEAN);
  8057. ctxt->value->boolval = ! ctxt->value->boolval;
  8058. }
  8059. /**
  8060. * xmlXPathTrueFunction:
  8061. * @ctxt: the XPath Parser context
  8062. * @nargs: the number of arguments
  8063. *
  8064. * Implement the true() XPath function
  8065. * boolean true()
  8066. */
  8067. void
  8068. xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8069. CHECK_ARITY(0);
  8070. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
  8071. }
  8072. /**
  8073. * xmlXPathFalseFunction:
  8074. * @ctxt: the XPath Parser context
  8075. * @nargs: the number of arguments
  8076. *
  8077. * Implement the false() XPath function
  8078. * boolean false()
  8079. */
  8080. void
  8081. xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8082. CHECK_ARITY(0);
  8083. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
  8084. }
  8085. /**
  8086. * xmlXPathLangFunction:
  8087. * @ctxt: the XPath Parser context
  8088. * @nargs: the number of arguments
  8089. *
  8090. * Implement the lang() XPath function
  8091. * boolean lang(string)
  8092. * The lang function returns true or false depending on whether the
  8093. * language of the context node as specified by xml:lang attributes
  8094. * is the same as or is a sublanguage of the language specified by
  8095. * the argument string. The language of the context node is determined
  8096. * by the value of the xml:lang attribute on the context node, or, if
  8097. * the context node has no xml:lang attribute, by the value of the
  8098. * xml:lang attribute on the nearest ancestor of the context node that
  8099. * has an xml:lang attribute. If there is no such attribute, then lang
  8100. * returns false. If there is such an attribute, then lang returns
  8101. * true if the attribute value is equal to the argument ignoring case,
  8102. * or if there is some suffix starting with - such that the attribute
  8103. * value is equal to the argument ignoring that suffix of the attribute
  8104. * value and ignoring case.
  8105. */
  8106. void
  8107. xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8108. xmlXPathObjectPtr val = NULL;
  8109. const xmlChar *theLang = NULL;
  8110. const xmlChar *lang;
  8111. int ret = 0;
  8112. int i;
  8113. CHECK_ARITY(1);
  8114. CAST_TO_STRING;
  8115. CHECK_TYPE(XPATH_STRING);
  8116. val = valuePop(ctxt);
  8117. lang = val->stringval;
  8118. theLang = xmlNodeGetLang(ctxt->context->node);
  8119. if ((theLang != NULL) && (lang != NULL)) {
  8120. for (i = 0;lang[i] != 0;i++)
  8121. if (toupper(lang[i]) != toupper(theLang[i]))
  8122. goto not_equal;
  8123. if ((theLang[i] == 0) || (theLang[i] == '-'))
  8124. ret = 1;
  8125. }
  8126. not_equal:
  8127. if (theLang != NULL)
  8128. xmlFree((void *)theLang);
  8129. xmlXPathReleaseObject(ctxt->context, val);
  8130. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
  8131. }
  8132. /**
  8133. * xmlXPathNumberFunction:
  8134. * @ctxt: the XPath Parser context
  8135. * @nargs: the number of arguments
  8136. *
  8137. * Implement the number() XPath function
  8138. * number number(object?)
  8139. */
  8140. void
  8141. xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8142. xmlXPathObjectPtr cur;
  8143. double res;
  8144. if (ctxt == NULL) return;
  8145. if (nargs == 0) {
  8146. if (ctxt->context->node == NULL) {
  8147. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
  8148. } else {
  8149. xmlChar* content = xmlNodeGetContent(ctxt->context->node);
  8150. res = xmlXPathStringEvalNumber(content);
  8151. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
  8152. xmlFree(content);
  8153. }
  8154. return;
  8155. }
  8156. CHECK_ARITY(1);
  8157. cur = valuePop(ctxt);
  8158. valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
  8159. }
  8160. /**
  8161. * xmlXPathSumFunction:
  8162. * @ctxt: the XPath Parser context
  8163. * @nargs: the number of arguments
  8164. *
  8165. * Implement the sum() XPath function
  8166. * number sum(node-set)
  8167. * The sum function returns the sum of the values of the nodes in
  8168. * the argument node-set.
  8169. */
  8170. void
  8171. xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8172. xmlXPathObjectPtr cur;
  8173. int i;
  8174. double res = 0.0;
  8175. CHECK_ARITY(1);
  8176. if ((ctxt->value == NULL) ||
  8177. ((ctxt->value->type != XPATH_NODESET) &&
  8178. (ctxt->value->type != XPATH_XSLT_TREE)))
  8179. XP_ERROR(XPATH_INVALID_TYPE);
  8180. cur = valuePop(ctxt);
  8181. if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
  8182. for (i = 0; i < cur->nodesetval->nodeNr; i++) {
  8183. res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
  8184. }
  8185. }
  8186. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
  8187. xmlXPathReleaseObject(ctxt->context, cur);
  8188. }
  8189. /**
  8190. * xmlXPathFloorFunction:
  8191. * @ctxt: the XPath Parser context
  8192. * @nargs: the number of arguments
  8193. *
  8194. * Implement the floor() XPath function
  8195. * number floor(number)
  8196. * The floor function returns the largest (closest to positive infinity)
  8197. * number that is not greater than the argument and that is an integer.
  8198. */
  8199. void
  8200. xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8201. CHECK_ARITY(1);
  8202. CAST_TO_NUMBER;
  8203. CHECK_TYPE(XPATH_NUMBER);
  8204. ctxt->value->floatval = floor(ctxt->value->floatval);
  8205. }
  8206. /**
  8207. * xmlXPathCeilingFunction:
  8208. * @ctxt: the XPath Parser context
  8209. * @nargs: the number of arguments
  8210. *
  8211. * Implement the ceiling() XPath function
  8212. * number ceiling(number)
  8213. * The ceiling function returns the smallest (closest to negative infinity)
  8214. * number that is not less than the argument and that is an integer.
  8215. */
  8216. void
  8217. xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8218. CHECK_ARITY(1);
  8219. CAST_TO_NUMBER;
  8220. CHECK_TYPE(XPATH_NUMBER);
  8221. #ifdef _AIX
  8222. /* Work around buggy ceil() function on AIX */
  8223. ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
  8224. #else
  8225. ctxt->value->floatval = ceil(ctxt->value->floatval);
  8226. #endif
  8227. }
  8228. /**
  8229. * xmlXPathRoundFunction:
  8230. * @ctxt: the XPath Parser context
  8231. * @nargs: the number of arguments
  8232. *
  8233. * Implement the round() XPath function
  8234. * number round(number)
  8235. * The round function returns the number that is closest to the
  8236. * argument and that is an integer. If there are two such numbers,
  8237. * then the one that is closest to positive infinity is returned.
  8238. */
  8239. void
  8240. xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8241. double f;
  8242. CHECK_ARITY(1);
  8243. CAST_TO_NUMBER;
  8244. CHECK_TYPE(XPATH_NUMBER);
  8245. f = ctxt->value->floatval;
  8246. if ((f >= -0.5) && (f < 0.5)) {
  8247. /* Handles negative zero. */
  8248. ctxt->value->floatval *= 0.0;
  8249. }
  8250. else {
  8251. double rounded = floor(f);
  8252. if (f - rounded >= 0.5)
  8253. rounded += 1.0;
  8254. ctxt->value->floatval = rounded;
  8255. }
  8256. }
  8257. /************************************************************************
  8258. * *
  8259. * The Parser *
  8260. * *
  8261. ************************************************************************/
  8262. /*
  8263. * a few forward declarations since we use a recursive call based
  8264. * implementation.
  8265. */
  8266. static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
  8267. static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
  8268. static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
  8269. static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
  8270. static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
  8271. int qualified);
  8272. /**
  8273. * xmlXPathCurrentChar:
  8274. * @ctxt: the XPath parser context
  8275. * @cur: pointer to the beginning of the char
  8276. * @len: pointer to the length of the char read
  8277. *
  8278. * The current char value, if using UTF-8 this may actually span multiple
  8279. * bytes in the input buffer.
  8280. *
  8281. * Returns the current char value and its length
  8282. */
  8283. static int
  8284. xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
  8285. unsigned char c;
  8286. unsigned int val;
  8287. const xmlChar *cur;
  8288. if (ctxt == NULL)
  8289. return(0);
  8290. cur = ctxt->cur;
  8291. /*
  8292. * We are supposed to handle UTF8, check it's valid
  8293. * From rfc2044: encoding of the Unicode values on UTF-8:
  8294. *
  8295. * UCS-4 range (hex.) UTF-8 octet sequence (binary)
  8296. * 0000 0000-0000 007F 0xxxxxxx
  8297. * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
  8298. * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
  8299. *
  8300. * Check for the 0x110000 limit too
  8301. */
  8302. c = *cur;
  8303. if (c & 0x80) {
  8304. if ((cur[1] & 0xc0) != 0x80)
  8305. goto encoding_error;
  8306. if ((c & 0xe0) == 0xe0) {
  8307. if ((cur[2] & 0xc0) != 0x80)
  8308. goto encoding_error;
  8309. if ((c & 0xf0) == 0xf0) {
  8310. if (((c & 0xf8) != 0xf0) ||
  8311. ((cur[3] & 0xc0) != 0x80))
  8312. goto encoding_error;
  8313. /* 4-byte code */
  8314. *len = 4;
  8315. val = (cur[0] & 0x7) << 18;
  8316. val |= (cur[1] & 0x3f) << 12;
  8317. val |= (cur[2] & 0x3f) << 6;
  8318. val |= cur[3] & 0x3f;
  8319. } else {
  8320. /* 3-byte code */
  8321. *len = 3;
  8322. val = (cur[0] & 0xf) << 12;
  8323. val |= (cur[1] & 0x3f) << 6;
  8324. val |= cur[2] & 0x3f;
  8325. }
  8326. } else {
  8327. /* 2-byte code */
  8328. *len = 2;
  8329. val = (cur[0] & 0x1f) << 6;
  8330. val |= cur[1] & 0x3f;
  8331. }
  8332. if (!IS_CHAR(val)) {
  8333. XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
  8334. }
  8335. return(val);
  8336. } else {
  8337. /* 1-byte code */
  8338. *len = 1;
  8339. return(*cur);
  8340. }
  8341. encoding_error:
  8342. /*
  8343. * If we detect an UTF8 error that probably means that the
  8344. * input encoding didn't get properly advertised in the
  8345. * declaration header. Report the error and switch the encoding
  8346. * to ISO-Latin-1 (if you don't like this policy, just declare the
  8347. * encoding !)
  8348. */
  8349. *len = 0;
  8350. XP_ERROR0(XPATH_ENCODING_ERROR);
  8351. }
  8352. /**
  8353. * xmlXPathParseNCName:
  8354. * @ctxt: the XPath Parser context
  8355. *
  8356. * parse an XML namespace non qualified name.
  8357. *
  8358. * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
  8359. *
  8360. * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
  8361. * CombiningChar | Extender
  8362. *
  8363. * Returns the namespace name or NULL
  8364. */
  8365. xmlChar *
  8366. xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
  8367. const xmlChar *in;
  8368. xmlChar *ret;
  8369. int count = 0;
  8370. if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
  8371. /*
  8372. * Accelerator for simple ASCII names
  8373. */
  8374. in = ctxt->cur;
  8375. if (((*in >= 0x61) && (*in <= 0x7A)) ||
  8376. ((*in >= 0x41) && (*in <= 0x5A)) ||
  8377. (*in == '_')) {
  8378. in++;
  8379. while (((*in >= 0x61) && (*in <= 0x7A)) ||
  8380. ((*in >= 0x41) && (*in <= 0x5A)) ||
  8381. ((*in >= 0x30) && (*in <= 0x39)) ||
  8382. (*in == '_') || (*in == '.') ||
  8383. (*in == '-'))
  8384. in++;
  8385. if ((*in == ' ') || (*in == '>') || (*in == '/') ||
  8386. (*in == '[') || (*in == ']') || (*in == ':') ||
  8387. (*in == '@') || (*in == '*')) {
  8388. count = in - ctxt->cur;
  8389. if (count == 0)
  8390. return(NULL);
  8391. ret = xmlStrndup(ctxt->cur, count);
  8392. ctxt->cur = in;
  8393. return(ret);
  8394. }
  8395. }
  8396. return(xmlXPathParseNameComplex(ctxt, 0));
  8397. }
  8398. /**
  8399. * xmlXPathParseQName:
  8400. * @ctxt: the XPath Parser context
  8401. * @prefix: a xmlChar **
  8402. *
  8403. * parse an XML qualified name
  8404. *
  8405. * [NS 5] QName ::= (Prefix ':')? LocalPart
  8406. *
  8407. * [NS 6] Prefix ::= NCName
  8408. *
  8409. * [NS 7] LocalPart ::= NCName
  8410. *
  8411. * Returns the function returns the local part, and prefix is updated
  8412. * to get the Prefix if any.
  8413. */
  8414. static xmlChar *
  8415. xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
  8416. xmlChar *ret = NULL;
  8417. *prefix = NULL;
  8418. ret = xmlXPathParseNCName(ctxt);
  8419. if (ret && CUR == ':') {
  8420. *prefix = ret;
  8421. NEXT;
  8422. ret = xmlXPathParseNCName(ctxt);
  8423. }
  8424. return(ret);
  8425. }
  8426. /**
  8427. * xmlXPathParseName:
  8428. * @ctxt: the XPath Parser context
  8429. *
  8430. * parse an XML name
  8431. *
  8432. * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
  8433. * CombiningChar | Extender
  8434. *
  8435. * [5] Name ::= (Letter | '_' | ':') (NameChar)*
  8436. *
  8437. * Returns the namespace name or NULL
  8438. */
  8439. xmlChar *
  8440. xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
  8441. const xmlChar *in;
  8442. xmlChar *ret;
  8443. size_t count = 0;
  8444. if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
  8445. /*
  8446. * Accelerator for simple ASCII names
  8447. */
  8448. in = ctxt->cur;
  8449. if (((*in >= 0x61) && (*in <= 0x7A)) ||
  8450. ((*in >= 0x41) && (*in <= 0x5A)) ||
  8451. (*in == '_') || (*in == ':')) {
  8452. in++;
  8453. while (((*in >= 0x61) && (*in <= 0x7A)) ||
  8454. ((*in >= 0x41) && (*in <= 0x5A)) ||
  8455. ((*in >= 0x30) && (*in <= 0x39)) ||
  8456. (*in == '_') || (*in == '-') ||
  8457. (*in == ':') || (*in == '.'))
  8458. in++;
  8459. if ((*in > 0) && (*in < 0x80)) {
  8460. count = in - ctxt->cur;
  8461. if (count > XML_MAX_NAME_LENGTH) {
  8462. ctxt->cur = in;
  8463. XP_ERRORNULL(XPATH_EXPR_ERROR);
  8464. }
  8465. ret = xmlStrndup(ctxt->cur, count);
  8466. ctxt->cur = in;
  8467. return(ret);
  8468. }
  8469. }
  8470. return(xmlXPathParseNameComplex(ctxt, 1));
  8471. }
  8472. static xmlChar *
  8473. xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
  8474. xmlChar buf[XML_MAX_NAMELEN + 5];
  8475. int len = 0, l;
  8476. int c;
  8477. /*
  8478. * Handler for more complex cases
  8479. */
  8480. c = CUR_CHAR(l);
  8481. if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
  8482. (c == '[') || (c == ']') || (c == '@') || /* accelerators */
  8483. (c == '*') || /* accelerators */
  8484. (!IS_LETTER(c) && (c != '_') &&
  8485. ((!qualified) || (c != ':')))) {
  8486. return(NULL);
  8487. }
  8488. while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
  8489. ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
  8490. (c == '.') || (c == '-') ||
  8491. (c == '_') || ((qualified) && (c == ':')) ||
  8492. (IS_COMBINING(c)) ||
  8493. (IS_EXTENDER(c)))) {
  8494. COPY_BUF(l,buf,len,c);
  8495. NEXTL(l);
  8496. c = CUR_CHAR(l);
  8497. if (len >= XML_MAX_NAMELEN) {
  8498. /*
  8499. * Okay someone managed to make a huge name, so he's ready to pay
  8500. * for the processing speed.
  8501. */
  8502. xmlChar *buffer;
  8503. int max = len * 2;
  8504. if (len > XML_MAX_NAME_LENGTH) {
  8505. XP_ERRORNULL(XPATH_EXPR_ERROR);
  8506. }
  8507. buffer = (xmlChar *) xmlMallocAtomic(max);
  8508. if (buffer == NULL) {
  8509. XP_ERRORNULL(XPATH_MEMORY_ERROR);
  8510. }
  8511. memcpy(buffer, buf, len);
  8512. while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
  8513. (c == '.') || (c == '-') ||
  8514. (c == '_') || ((qualified) && (c == ':')) ||
  8515. (IS_COMBINING(c)) ||
  8516. (IS_EXTENDER(c))) {
  8517. if (len + 10 > max) {
  8518. xmlChar *tmp;
  8519. if (max > XML_MAX_NAME_LENGTH) {
  8520. xmlFree(buffer);
  8521. XP_ERRORNULL(XPATH_EXPR_ERROR);
  8522. }
  8523. max *= 2;
  8524. tmp = (xmlChar *) xmlRealloc(buffer, max);
  8525. if (tmp == NULL) {
  8526. xmlFree(buffer);
  8527. XP_ERRORNULL(XPATH_MEMORY_ERROR);
  8528. }
  8529. buffer = tmp;
  8530. }
  8531. COPY_BUF(l,buffer,len,c);
  8532. NEXTL(l);
  8533. c = CUR_CHAR(l);
  8534. }
  8535. buffer[len] = 0;
  8536. return(buffer);
  8537. }
  8538. }
  8539. if (len == 0)
  8540. return(NULL);
  8541. return(xmlStrndup(buf, len));
  8542. }
  8543. #define MAX_FRAC 20
  8544. /**
  8545. * xmlXPathStringEvalNumber:
  8546. * @str: A string to scan
  8547. *
  8548. * [30a] Float ::= Number ('e' Digits?)?
  8549. *
  8550. * [30] Number ::= Digits ('.' Digits?)?
  8551. * | '.' Digits
  8552. * [31] Digits ::= [0-9]+
  8553. *
  8554. * Compile a Number in the string
  8555. * In complement of the Number expression, this function also handles
  8556. * negative values : '-' Number.
  8557. *
  8558. * Returns the double value.
  8559. */
  8560. double
  8561. xmlXPathStringEvalNumber(const xmlChar *str) {
  8562. const xmlChar *cur = str;
  8563. double ret;
  8564. int ok = 0;
  8565. int isneg = 0;
  8566. int exponent = 0;
  8567. int is_exponent_negative = 0;
  8568. #ifdef __GNUC__
  8569. unsigned long tmp = 0;
  8570. double temp;
  8571. #endif
  8572. if (cur == NULL) return(0);
  8573. while (IS_BLANK_CH(*cur)) cur++;
  8574. if (*cur == '-') {
  8575. isneg = 1;
  8576. cur++;
  8577. }
  8578. if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
  8579. return(xmlXPathNAN);
  8580. }
  8581. #ifdef __GNUC__
  8582. /*
  8583. * tmp/temp is a workaround against a gcc compiler bug
  8584. * http://veillard.com/gcc.bug
  8585. */
  8586. ret = 0;
  8587. while ((*cur >= '0') && (*cur <= '9')) {
  8588. ret = ret * 10;
  8589. tmp = (*cur - '0');
  8590. ok = 1;
  8591. cur++;
  8592. temp = (double) tmp;
  8593. ret = ret + temp;
  8594. }
  8595. #else
  8596. ret = 0;
  8597. while ((*cur >= '0') && (*cur <= '9')) {
  8598. ret = ret * 10 + (*cur - '0');
  8599. ok = 1;
  8600. cur++;
  8601. }
  8602. #endif
  8603. if (*cur == '.') {
  8604. int v, frac = 0, max;
  8605. double fraction = 0;
  8606. cur++;
  8607. if (((*cur < '0') || (*cur > '9')) && (!ok)) {
  8608. return(xmlXPathNAN);
  8609. }
  8610. while (*cur == '0') {
  8611. frac = frac + 1;
  8612. cur++;
  8613. }
  8614. max = frac + MAX_FRAC;
  8615. while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
  8616. v = (*cur - '0');
  8617. fraction = fraction * 10 + v;
  8618. frac = frac + 1;
  8619. cur++;
  8620. }
  8621. fraction /= pow(10.0, frac);
  8622. ret = ret + fraction;
  8623. while ((*cur >= '0') && (*cur <= '9'))
  8624. cur++;
  8625. }
  8626. if ((*cur == 'e') || (*cur == 'E')) {
  8627. cur++;
  8628. if (*cur == '-') {
  8629. is_exponent_negative = 1;
  8630. cur++;
  8631. } else if (*cur == '+') {
  8632. cur++;
  8633. }
  8634. while ((*cur >= '0') && (*cur <= '9')) {
  8635. if (exponent < 1000000)
  8636. exponent = exponent * 10 + (*cur - '0');
  8637. cur++;
  8638. }
  8639. }
  8640. while (IS_BLANK_CH(*cur)) cur++;
  8641. if (*cur != 0) return(xmlXPathNAN);
  8642. if (isneg) ret = -ret;
  8643. if (is_exponent_negative) exponent = -exponent;
  8644. ret *= pow(10.0, (double)exponent);
  8645. return(ret);
  8646. }
  8647. /**
  8648. * xmlXPathCompNumber:
  8649. * @ctxt: the XPath Parser context
  8650. *
  8651. * [30] Number ::= Digits ('.' Digits?)?
  8652. * | '.' Digits
  8653. * [31] Digits ::= [0-9]+
  8654. *
  8655. * Compile a Number, then push it on the stack
  8656. *
  8657. */
  8658. static void
  8659. xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
  8660. {
  8661. double ret = 0.0;
  8662. int ok = 0;
  8663. int exponent = 0;
  8664. int is_exponent_negative = 0;
  8665. xmlXPathObjectPtr num;
  8666. #ifdef __GNUC__
  8667. unsigned long tmp = 0;
  8668. double temp;
  8669. #endif
  8670. CHECK_ERROR;
  8671. if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
  8672. XP_ERROR(XPATH_NUMBER_ERROR);
  8673. }
  8674. #ifdef __GNUC__
  8675. /*
  8676. * tmp/temp is a workaround against a gcc compiler bug
  8677. * http://veillard.com/gcc.bug
  8678. */
  8679. ret = 0;
  8680. while ((CUR >= '0') && (CUR <= '9')) {
  8681. ret = ret * 10;
  8682. tmp = (CUR - '0');
  8683. ok = 1;
  8684. NEXT;
  8685. temp = (double) tmp;
  8686. ret = ret + temp;
  8687. }
  8688. #else
  8689. ret = 0;
  8690. while ((CUR >= '0') && (CUR <= '9')) {
  8691. ret = ret * 10 + (CUR - '0');
  8692. ok = 1;
  8693. NEXT;
  8694. }
  8695. #endif
  8696. if (CUR == '.') {
  8697. int v, frac = 0, max;
  8698. double fraction = 0;
  8699. NEXT;
  8700. if (((CUR < '0') || (CUR > '9')) && (!ok)) {
  8701. XP_ERROR(XPATH_NUMBER_ERROR);
  8702. }
  8703. while (CUR == '0') {
  8704. frac = frac + 1;
  8705. NEXT;
  8706. }
  8707. max = frac + MAX_FRAC;
  8708. while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
  8709. v = (CUR - '0');
  8710. fraction = fraction * 10 + v;
  8711. frac = frac + 1;
  8712. NEXT;
  8713. }
  8714. fraction /= pow(10.0, frac);
  8715. ret = ret + fraction;
  8716. while ((CUR >= '0') && (CUR <= '9'))
  8717. NEXT;
  8718. }
  8719. if ((CUR == 'e') || (CUR == 'E')) {
  8720. NEXT;
  8721. if (CUR == '-') {
  8722. is_exponent_negative = 1;
  8723. NEXT;
  8724. } else if (CUR == '+') {
  8725. NEXT;
  8726. }
  8727. while ((CUR >= '0') && (CUR <= '9')) {
  8728. if (exponent < 1000000)
  8729. exponent = exponent * 10 + (CUR - '0');
  8730. NEXT;
  8731. }
  8732. if (is_exponent_negative)
  8733. exponent = -exponent;
  8734. ret *= pow(10.0, (double) exponent);
  8735. }
  8736. num = xmlXPathCacheNewFloat(ctxt->context, ret);
  8737. if (num == NULL) {
  8738. ctxt->error = XPATH_MEMORY_ERROR;
  8739. } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
  8740. NULL) == -1) {
  8741. xmlXPathReleaseObject(ctxt->context, num);
  8742. }
  8743. }
  8744. /**
  8745. * xmlXPathParseLiteral:
  8746. * @ctxt: the XPath Parser context
  8747. *
  8748. * Parse a Literal
  8749. *
  8750. * [29] Literal ::= '"' [^"]* '"'
  8751. * | "'" [^']* "'"
  8752. *
  8753. * Returns the value found or NULL in case of error
  8754. */
  8755. static xmlChar *
  8756. xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
  8757. const xmlChar *q;
  8758. xmlChar *ret = NULL;
  8759. if (CUR == '"') {
  8760. NEXT;
  8761. q = CUR_PTR;
  8762. while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
  8763. NEXT;
  8764. if (!IS_CHAR_CH(CUR)) {
  8765. XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
  8766. } else {
  8767. ret = xmlStrndup(q, CUR_PTR - q);
  8768. NEXT;
  8769. }
  8770. } else if (CUR == '\'') {
  8771. NEXT;
  8772. q = CUR_PTR;
  8773. while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
  8774. NEXT;
  8775. if (!IS_CHAR_CH(CUR)) {
  8776. XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
  8777. } else {
  8778. ret = xmlStrndup(q, CUR_PTR - q);
  8779. NEXT;
  8780. }
  8781. } else {
  8782. XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
  8783. }
  8784. return(ret);
  8785. }
  8786. /**
  8787. * xmlXPathCompLiteral:
  8788. * @ctxt: the XPath Parser context
  8789. *
  8790. * Parse a Literal and push it on the stack.
  8791. *
  8792. * [29] Literal ::= '"' [^"]* '"'
  8793. * | "'" [^']* "'"
  8794. *
  8795. * TODO: xmlXPathCompLiteral memory allocation could be improved.
  8796. */
  8797. static void
  8798. xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
  8799. const xmlChar *q;
  8800. xmlChar *ret = NULL;
  8801. xmlXPathObjectPtr lit;
  8802. if (CUR == '"') {
  8803. NEXT;
  8804. q = CUR_PTR;
  8805. while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
  8806. NEXT;
  8807. if (!IS_CHAR_CH(CUR)) {
  8808. XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
  8809. } else {
  8810. ret = xmlStrndup(q, CUR_PTR - q);
  8811. NEXT;
  8812. }
  8813. } else if (CUR == '\'') {
  8814. NEXT;
  8815. q = CUR_PTR;
  8816. while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
  8817. NEXT;
  8818. if (!IS_CHAR_CH(CUR)) {
  8819. XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
  8820. } else {
  8821. ret = xmlStrndup(q, CUR_PTR - q);
  8822. NEXT;
  8823. }
  8824. } else {
  8825. XP_ERROR(XPATH_START_LITERAL_ERROR);
  8826. }
  8827. if (ret == NULL) {
  8828. xmlXPathPErrMemory(ctxt, NULL);
  8829. return;
  8830. }
  8831. lit = xmlXPathCacheNewString(ctxt->context, ret);
  8832. if (lit == NULL) {
  8833. ctxt->error = XPATH_MEMORY_ERROR;
  8834. } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
  8835. NULL) == -1) {
  8836. xmlXPathReleaseObject(ctxt->context, lit);
  8837. }
  8838. xmlFree(ret);
  8839. }
  8840. /**
  8841. * xmlXPathCompVariableReference:
  8842. * @ctxt: the XPath Parser context
  8843. *
  8844. * Parse a VariableReference, evaluate it and push it on the stack.
  8845. *
  8846. * The variable bindings consist of a mapping from variable names
  8847. * to variable values. The value of a variable is an object, which can be
  8848. * of any of the types that are possible for the value of an expression,
  8849. * and may also be of additional types not specified here.
  8850. *
  8851. * Early evaluation is possible since:
  8852. * The variable bindings [...] used to evaluate a subexpression are
  8853. * always the same as those used to evaluate the containing expression.
  8854. *
  8855. * [36] VariableReference ::= '$' QName
  8856. */
  8857. static void
  8858. xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
  8859. xmlChar *name;
  8860. xmlChar *prefix;
  8861. SKIP_BLANKS;
  8862. if (CUR != '$') {
  8863. XP_ERROR(XPATH_VARIABLE_REF_ERROR);
  8864. }
  8865. NEXT;
  8866. name = xmlXPathParseQName(ctxt, &prefix);
  8867. if (name == NULL) {
  8868. xmlFree(prefix);
  8869. XP_ERROR(XPATH_VARIABLE_REF_ERROR);
  8870. }
  8871. ctxt->comp->last = -1;
  8872. if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
  8873. xmlFree(prefix);
  8874. xmlFree(name);
  8875. }
  8876. SKIP_BLANKS;
  8877. if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
  8878. XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
  8879. }
  8880. }
  8881. /**
  8882. * xmlXPathIsNodeType:
  8883. * @name: a name string
  8884. *
  8885. * Is the name given a NodeType one.
  8886. *
  8887. * [38] NodeType ::= 'comment'
  8888. * | 'text'
  8889. * | 'processing-instruction'
  8890. * | 'node'
  8891. *
  8892. * Returns 1 if true 0 otherwise
  8893. */
  8894. int
  8895. xmlXPathIsNodeType(const xmlChar *name) {
  8896. if (name == NULL)
  8897. return(0);
  8898. if (xmlStrEqual(name, BAD_CAST "node"))
  8899. return(1);
  8900. if (xmlStrEqual(name, BAD_CAST "text"))
  8901. return(1);
  8902. if (xmlStrEqual(name, BAD_CAST "comment"))
  8903. return(1);
  8904. if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
  8905. return(1);
  8906. return(0);
  8907. }
  8908. /**
  8909. * xmlXPathCompFunctionCall:
  8910. * @ctxt: the XPath Parser context
  8911. *
  8912. * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
  8913. * [17] Argument ::= Expr
  8914. *
  8915. * Compile a function call, the evaluation of all arguments are
  8916. * pushed on the stack
  8917. */
  8918. static void
  8919. xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
  8920. xmlChar *name;
  8921. xmlChar *prefix;
  8922. int nbargs = 0;
  8923. int sort = 1;
  8924. name = xmlXPathParseQName(ctxt, &prefix);
  8925. if (name == NULL) {
  8926. xmlFree(prefix);
  8927. XP_ERROR(XPATH_EXPR_ERROR);
  8928. }
  8929. SKIP_BLANKS;
  8930. if (CUR != '(') {
  8931. xmlFree(name);
  8932. xmlFree(prefix);
  8933. XP_ERROR(XPATH_EXPR_ERROR);
  8934. }
  8935. NEXT;
  8936. SKIP_BLANKS;
  8937. /*
  8938. * Optimization for count(): we don't need the node-set to be sorted.
  8939. */
  8940. if ((prefix == NULL) && (name[0] == 'c') &&
  8941. xmlStrEqual(name, BAD_CAST "count"))
  8942. {
  8943. sort = 0;
  8944. }
  8945. ctxt->comp->last = -1;
  8946. if (CUR != ')') {
  8947. while (CUR != 0) {
  8948. int op1 = ctxt->comp->last;
  8949. ctxt->comp->last = -1;
  8950. xmlXPathCompileExpr(ctxt, sort);
  8951. if (ctxt->error != XPATH_EXPRESSION_OK) {
  8952. xmlFree(name);
  8953. xmlFree(prefix);
  8954. return;
  8955. }
  8956. PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
  8957. nbargs++;
  8958. if (CUR == ')') break;
  8959. if (CUR != ',') {
  8960. xmlFree(name);
  8961. xmlFree(prefix);
  8962. XP_ERROR(XPATH_EXPR_ERROR);
  8963. }
  8964. NEXT;
  8965. SKIP_BLANKS;
  8966. }
  8967. }
  8968. if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
  8969. xmlFree(prefix);
  8970. xmlFree(name);
  8971. }
  8972. NEXT;
  8973. SKIP_BLANKS;
  8974. }
  8975. /**
  8976. * xmlXPathCompPrimaryExpr:
  8977. * @ctxt: the XPath Parser context
  8978. *
  8979. * [15] PrimaryExpr ::= VariableReference
  8980. * | '(' Expr ')'
  8981. * | Literal
  8982. * | Number
  8983. * | FunctionCall
  8984. *
  8985. * Compile a primary expression.
  8986. */
  8987. static void
  8988. xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
  8989. SKIP_BLANKS;
  8990. if (CUR == '$') xmlXPathCompVariableReference(ctxt);
  8991. else if (CUR == '(') {
  8992. NEXT;
  8993. SKIP_BLANKS;
  8994. xmlXPathCompileExpr(ctxt, 1);
  8995. CHECK_ERROR;
  8996. if (CUR != ')') {
  8997. XP_ERROR(XPATH_EXPR_ERROR);
  8998. }
  8999. NEXT;
  9000. SKIP_BLANKS;
  9001. } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
  9002. xmlXPathCompNumber(ctxt);
  9003. } else if ((CUR == '\'') || (CUR == '"')) {
  9004. xmlXPathCompLiteral(ctxt);
  9005. } else {
  9006. xmlXPathCompFunctionCall(ctxt);
  9007. }
  9008. SKIP_BLANKS;
  9009. }
  9010. /**
  9011. * xmlXPathCompFilterExpr:
  9012. * @ctxt: the XPath Parser context
  9013. *
  9014. * [20] FilterExpr ::= PrimaryExpr
  9015. * | FilterExpr Predicate
  9016. *
  9017. * Compile a filter expression.
  9018. * Square brackets are used to filter expressions in the same way that
  9019. * they are used in location paths. It is an error if the expression to
  9020. * be filtered does not evaluate to a node-set. The context node list
  9021. * used for evaluating the expression in square brackets is the node-set
  9022. * to be filtered listed in document order.
  9023. */
  9024. static void
  9025. xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
  9026. xmlXPathCompPrimaryExpr(ctxt);
  9027. CHECK_ERROR;
  9028. SKIP_BLANKS;
  9029. while (CUR == '[') {
  9030. xmlXPathCompPredicate(ctxt, 1);
  9031. SKIP_BLANKS;
  9032. }
  9033. }
  9034. /**
  9035. * xmlXPathScanName:
  9036. * @ctxt: the XPath Parser context
  9037. *
  9038. * Trickery: parse an XML name but without consuming the input flow
  9039. * Needed to avoid insanity in the parser state.
  9040. *
  9041. * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
  9042. * CombiningChar | Extender
  9043. *
  9044. * [5] Name ::= (Letter | '_' | ':') (NameChar)*
  9045. *
  9046. * [6] Names ::= Name (S Name)*
  9047. *
  9048. * Returns the Name parsed or NULL
  9049. */
  9050. static xmlChar *
  9051. xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
  9052. int l;
  9053. int c;
  9054. const xmlChar *cur;
  9055. xmlChar *ret;
  9056. cur = ctxt->cur;
  9057. c = CUR_CHAR(l);
  9058. if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
  9059. (!IS_LETTER(c) && (c != '_') &&
  9060. (c != ':'))) {
  9061. return(NULL);
  9062. }
  9063. while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
  9064. ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
  9065. (c == '.') || (c == '-') ||
  9066. (c == '_') || (c == ':') ||
  9067. (IS_COMBINING(c)) ||
  9068. (IS_EXTENDER(c)))) {
  9069. NEXTL(l);
  9070. c = CUR_CHAR(l);
  9071. }
  9072. ret = xmlStrndup(cur, ctxt->cur - cur);
  9073. ctxt->cur = cur;
  9074. return(ret);
  9075. }
  9076. /**
  9077. * xmlXPathCompPathExpr:
  9078. * @ctxt: the XPath Parser context
  9079. *
  9080. * [19] PathExpr ::= LocationPath
  9081. * | FilterExpr
  9082. * | FilterExpr '/' RelativeLocationPath
  9083. * | FilterExpr '//' RelativeLocationPath
  9084. *
  9085. * Compile a path expression.
  9086. * The / operator and // operators combine an arbitrary expression
  9087. * and a relative location path. It is an error if the expression
  9088. * does not evaluate to a node-set.
  9089. * The / operator does composition in the same way as when / is
  9090. * used in a location path. As in location paths, // is short for
  9091. * /descendant-or-self::node()/.
  9092. */
  9093. static void
  9094. xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
  9095. int lc = 1; /* Should we branch to LocationPath ? */
  9096. xmlChar *name = NULL; /* we may have to preparse a name to find out */
  9097. SKIP_BLANKS;
  9098. if ((CUR == '$') || (CUR == '(') ||
  9099. (IS_ASCII_DIGIT(CUR)) ||
  9100. (CUR == '\'') || (CUR == '"') ||
  9101. (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
  9102. lc = 0;
  9103. } else if (CUR == '*') {
  9104. /* relative or absolute location path */
  9105. lc = 1;
  9106. } else if (CUR == '/') {
  9107. /* relative or absolute location path */
  9108. lc = 1;
  9109. } else if (CUR == '@') {
  9110. /* relative abbreviated attribute location path */
  9111. lc = 1;
  9112. } else if (CUR == '.') {
  9113. /* relative abbreviated attribute location path */
  9114. lc = 1;
  9115. } else {
  9116. /*
  9117. * Problem is finding if we have a name here whether it's:
  9118. * - a nodetype
  9119. * - a function call in which case it's followed by '('
  9120. * - an axis in which case it's followed by ':'
  9121. * - a element name
  9122. * We do an a priori analysis here rather than having to
  9123. * maintain parsed token content through the recursive function
  9124. * calls. This looks uglier but makes the code easier to
  9125. * read/write/debug.
  9126. */
  9127. SKIP_BLANKS;
  9128. name = xmlXPathScanName(ctxt);
  9129. if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
  9130. lc = 1;
  9131. xmlFree(name);
  9132. } else if (name != NULL) {
  9133. int len =xmlStrlen(name);
  9134. while (NXT(len) != 0) {
  9135. if (NXT(len) == '/') {
  9136. /* element name */
  9137. lc = 1;
  9138. break;
  9139. } else if (IS_BLANK_CH(NXT(len))) {
  9140. /* ignore blanks */
  9141. ;
  9142. } else if (NXT(len) == ':') {
  9143. lc = 1;
  9144. break;
  9145. } else if ((NXT(len) == '(')) {
  9146. /* Node Type or Function */
  9147. if (xmlXPathIsNodeType(name)) {
  9148. lc = 1;
  9149. #ifdef LIBXML_XPTR_LOCS_ENABLED
  9150. } else if (ctxt->xptr &&
  9151. xmlStrEqual(name, BAD_CAST "range-to")) {
  9152. lc = 1;
  9153. #endif
  9154. } else {
  9155. lc = 0;
  9156. }
  9157. break;
  9158. } else if ((NXT(len) == '[')) {
  9159. /* element name */
  9160. lc = 1;
  9161. break;
  9162. } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
  9163. (NXT(len) == '=')) {
  9164. lc = 1;
  9165. break;
  9166. } else {
  9167. lc = 1;
  9168. break;
  9169. }
  9170. len++;
  9171. }
  9172. if (NXT(len) == 0) {
  9173. /* element name */
  9174. lc = 1;
  9175. }
  9176. xmlFree(name);
  9177. } else {
  9178. /* make sure all cases are covered explicitly */
  9179. XP_ERROR(XPATH_EXPR_ERROR);
  9180. }
  9181. }
  9182. if (lc) {
  9183. if (CUR == '/') {
  9184. PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
  9185. } else {
  9186. PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
  9187. }
  9188. xmlXPathCompLocationPath(ctxt);
  9189. } else {
  9190. xmlXPathCompFilterExpr(ctxt);
  9191. CHECK_ERROR;
  9192. if ((CUR == '/') && (NXT(1) == '/')) {
  9193. SKIP(2);
  9194. SKIP_BLANKS;
  9195. PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
  9196. NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
  9197. xmlXPathCompRelativeLocationPath(ctxt);
  9198. } else if (CUR == '/') {
  9199. xmlXPathCompRelativeLocationPath(ctxt);
  9200. }
  9201. }
  9202. SKIP_BLANKS;
  9203. }
  9204. /**
  9205. * xmlXPathCompUnionExpr:
  9206. * @ctxt: the XPath Parser context
  9207. *
  9208. * [18] UnionExpr ::= PathExpr
  9209. * | UnionExpr '|' PathExpr
  9210. *
  9211. * Compile an union expression.
  9212. */
  9213. static void
  9214. xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
  9215. xmlXPathCompPathExpr(ctxt);
  9216. CHECK_ERROR;
  9217. SKIP_BLANKS;
  9218. while (CUR == '|') {
  9219. int op1 = ctxt->comp->last;
  9220. PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
  9221. NEXT;
  9222. SKIP_BLANKS;
  9223. xmlXPathCompPathExpr(ctxt);
  9224. PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
  9225. SKIP_BLANKS;
  9226. }
  9227. }
  9228. /**
  9229. * xmlXPathCompUnaryExpr:
  9230. * @ctxt: the XPath Parser context
  9231. *
  9232. * [27] UnaryExpr ::= UnionExpr
  9233. * | '-' UnaryExpr
  9234. *
  9235. * Compile an unary expression.
  9236. */
  9237. static void
  9238. xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
  9239. int minus = 0;
  9240. int found = 0;
  9241. SKIP_BLANKS;
  9242. while (CUR == '-') {
  9243. minus = 1 - minus;
  9244. found = 1;
  9245. NEXT;
  9246. SKIP_BLANKS;
  9247. }
  9248. xmlXPathCompUnionExpr(ctxt);
  9249. CHECK_ERROR;
  9250. if (found) {
  9251. if (minus)
  9252. PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
  9253. else
  9254. PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
  9255. }
  9256. }
  9257. /**
  9258. * xmlXPathCompMultiplicativeExpr:
  9259. * @ctxt: the XPath Parser context
  9260. *
  9261. * [26] MultiplicativeExpr ::= UnaryExpr
  9262. * | MultiplicativeExpr MultiplyOperator UnaryExpr
  9263. * | MultiplicativeExpr 'div' UnaryExpr
  9264. * | MultiplicativeExpr 'mod' UnaryExpr
  9265. * [34] MultiplyOperator ::= '*'
  9266. *
  9267. * Compile an Additive expression.
  9268. */
  9269. static void
  9270. xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
  9271. xmlXPathCompUnaryExpr(ctxt);
  9272. CHECK_ERROR;
  9273. SKIP_BLANKS;
  9274. while ((CUR == '*') ||
  9275. ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
  9276. ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
  9277. int op = -1;
  9278. int op1 = ctxt->comp->last;
  9279. if (CUR == '*') {
  9280. op = 0;
  9281. NEXT;
  9282. } else if (CUR == 'd') {
  9283. op = 1;
  9284. SKIP(3);
  9285. } else if (CUR == 'm') {
  9286. op = 2;
  9287. SKIP(3);
  9288. }
  9289. SKIP_BLANKS;
  9290. xmlXPathCompUnaryExpr(ctxt);
  9291. CHECK_ERROR;
  9292. PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
  9293. SKIP_BLANKS;
  9294. }
  9295. }
  9296. /**
  9297. * xmlXPathCompAdditiveExpr:
  9298. * @ctxt: the XPath Parser context
  9299. *
  9300. * [25] AdditiveExpr ::= MultiplicativeExpr
  9301. * | AdditiveExpr '+' MultiplicativeExpr
  9302. * | AdditiveExpr '-' MultiplicativeExpr
  9303. *
  9304. * Compile an Additive expression.
  9305. */
  9306. static void
  9307. xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
  9308. xmlXPathCompMultiplicativeExpr(ctxt);
  9309. CHECK_ERROR;
  9310. SKIP_BLANKS;
  9311. while ((CUR == '+') || (CUR == '-')) {
  9312. int plus;
  9313. int op1 = ctxt->comp->last;
  9314. if (CUR == '+') plus = 1;
  9315. else plus = 0;
  9316. NEXT;
  9317. SKIP_BLANKS;
  9318. xmlXPathCompMultiplicativeExpr(ctxt);
  9319. CHECK_ERROR;
  9320. PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
  9321. SKIP_BLANKS;
  9322. }
  9323. }
  9324. /**
  9325. * xmlXPathCompRelationalExpr:
  9326. * @ctxt: the XPath Parser context
  9327. *
  9328. * [24] RelationalExpr ::= AdditiveExpr
  9329. * | RelationalExpr '<' AdditiveExpr
  9330. * | RelationalExpr '>' AdditiveExpr
  9331. * | RelationalExpr '<=' AdditiveExpr
  9332. * | RelationalExpr '>=' AdditiveExpr
  9333. *
  9334. * A <= B > C is allowed ? Answer from James, yes with
  9335. * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
  9336. * which is basically what got implemented.
  9337. *
  9338. * Compile a Relational expression, then push the result
  9339. * on the stack
  9340. */
  9341. static void
  9342. xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
  9343. xmlXPathCompAdditiveExpr(ctxt);
  9344. CHECK_ERROR;
  9345. SKIP_BLANKS;
  9346. while ((CUR == '<') || (CUR == '>')) {
  9347. int inf, strict;
  9348. int op1 = ctxt->comp->last;
  9349. if (CUR == '<') inf = 1;
  9350. else inf = 0;
  9351. if (NXT(1) == '=') strict = 0;
  9352. else strict = 1;
  9353. NEXT;
  9354. if (!strict) NEXT;
  9355. SKIP_BLANKS;
  9356. xmlXPathCompAdditiveExpr(ctxt);
  9357. CHECK_ERROR;
  9358. PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
  9359. SKIP_BLANKS;
  9360. }
  9361. }
  9362. /**
  9363. * xmlXPathCompEqualityExpr:
  9364. * @ctxt: the XPath Parser context
  9365. *
  9366. * [23] EqualityExpr ::= RelationalExpr
  9367. * | EqualityExpr '=' RelationalExpr
  9368. * | EqualityExpr '!=' RelationalExpr
  9369. *
  9370. * A != B != C is allowed ? Answer from James, yes with
  9371. * (RelationalExpr = RelationalExpr) = RelationalExpr
  9372. * (RelationalExpr != RelationalExpr) != RelationalExpr
  9373. * which is basically what got implemented.
  9374. *
  9375. * Compile an Equality expression.
  9376. *
  9377. */
  9378. static void
  9379. xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
  9380. xmlXPathCompRelationalExpr(ctxt);
  9381. CHECK_ERROR;
  9382. SKIP_BLANKS;
  9383. while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
  9384. int eq;
  9385. int op1 = ctxt->comp->last;
  9386. if (CUR == '=') eq = 1;
  9387. else eq = 0;
  9388. NEXT;
  9389. if (!eq) NEXT;
  9390. SKIP_BLANKS;
  9391. xmlXPathCompRelationalExpr(ctxt);
  9392. CHECK_ERROR;
  9393. PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
  9394. SKIP_BLANKS;
  9395. }
  9396. }
  9397. /**
  9398. * xmlXPathCompAndExpr:
  9399. * @ctxt: the XPath Parser context
  9400. *
  9401. * [22] AndExpr ::= EqualityExpr
  9402. * | AndExpr 'and' EqualityExpr
  9403. *
  9404. * Compile an AND expression.
  9405. *
  9406. */
  9407. static void
  9408. xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
  9409. xmlXPathCompEqualityExpr(ctxt);
  9410. CHECK_ERROR;
  9411. SKIP_BLANKS;
  9412. while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
  9413. int op1 = ctxt->comp->last;
  9414. SKIP(3);
  9415. SKIP_BLANKS;
  9416. xmlXPathCompEqualityExpr(ctxt);
  9417. CHECK_ERROR;
  9418. PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
  9419. SKIP_BLANKS;
  9420. }
  9421. }
  9422. /**
  9423. * xmlXPathCompileExpr:
  9424. * @ctxt: the XPath Parser context
  9425. *
  9426. * [14] Expr ::= OrExpr
  9427. * [21] OrExpr ::= AndExpr
  9428. * | OrExpr 'or' AndExpr
  9429. *
  9430. * Parse and compile an expression
  9431. */
  9432. static void
  9433. xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
  9434. xmlXPathContextPtr xpctxt = ctxt->context;
  9435. if (xpctxt != NULL) {
  9436. if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
  9437. XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
  9438. /*
  9439. * Parsing a single '(' pushes about 10 functions on the call stack
  9440. * before recursing!
  9441. */
  9442. xpctxt->depth += 10;
  9443. }
  9444. xmlXPathCompAndExpr(ctxt);
  9445. CHECK_ERROR;
  9446. SKIP_BLANKS;
  9447. while ((CUR == 'o') && (NXT(1) == 'r')) {
  9448. int op1 = ctxt->comp->last;
  9449. SKIP(2);
  9450. SKIP_BLANKS;
  9451. xmlXPathCompAndExpr(ctxt);
  9452. CHECK_ERROR;
  9453. PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
  9454. SKIP_BLANKS;
  9455. }
  9456. if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
  9457. /* more ops could be optimized too */
  9458. /*
  9459. * This is the main place to eliminate sorting for
  9460. * operations which don't require a sorted node-set.
  9461. * E.g. count().
  9462. */
  9463. PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
  9464. }
  9465. if (xpctxt != NULL)
  9466. xpctxt->depth -= 10;
  9467. }
  9468. /**
  9469. * xmlXPathCompPredicate:
  9470. * @ctxt: the XPath Parser context
  9471. * @filter: act as a filter
  9472. *
  9473. * [8] Predicate ::= '[' PredicateExpr ']'
  9474. * [9] PredicateExpr ::= Expr
  9475. *
  9476. * Compile a predicate expression
  9477. */
  9478. static void
  9479. xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
  9480. int op1 = ctxt->comp->last;
  9481. SKIP_BLANKS;
  9482. if (CUR != '[') {
  9483. XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
  9484. }
  9485. NEXT;
  9486. SKIP_BLANKS;
  9487. ctxt->comp->last = -1;
  9488. /*
  9489. * This call to xmlXPathCompileExpr() will deactivate sorting
  9490. * of the predicate result.
  9491. * TODO: Sorting is still activated for filters, since I'm not
  9492. * sure if needed. Normally sorting should not be needed, since
  9493. * a filter can only diminish the number of items in a sequence,
  9494. * but won't change its order; so if the initial sequence is sorted,
  9495. * subsequent sorting is not needed.
  9496. */
  9497. if (! filter)
  9498. xmlXPathCompileExpr(ctxt, 0);
  9499. else
  9500. xmlXPathCompileExpr(ctxt, 1);
  9501. CHECK_ERROR;
  9502. if (CUR != ']') {
  9503. XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
  9504. }
  9505. if (filter)
  9506. PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
  9507. else
  9508. PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
  9509. NEXT;
  9510. SKIP_BLANKS;
  9511. }
  9512. /**
  9513. * xmlXPathCompNodeTest:
  9514. * @ctxt: the XPath Parser context
  9515. * @test: pointer to a xmlXPathTestVal
  9516. * @type: pointer to a xmlXPathTypeVal
  9517. * @prefix: placeholder for a possible name prefix
  9518. *
  9519. * [7] NodeTest ::= NameTest
  9520. * | NodeType '(' ')'
  9521. * | 'processing-instruction' '(' Literal ')'
  9522. *
  9523. * [37] NameTest ::= '*'
  9524. * | NCName ':' '*'
  9525. * | QName
  9526. * [38] NodeType ::= 'comment'
  9527. * | 'text'
  9528. * | 'processing-instruction'
  9529. * | 'node'
  9530. *
  9531. * Returns the name found and updates @test, @type and @prefix appropriately
  9532. */
  9533. static xmlChar *
  9534. xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
  9535. xmlXPathTypeVal *type, xmlChar **prefix,
  9536. xmlChar *name) {
  9537. int blanks;
  9538. if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
  9539. STRANGE;
  9540. return(NULL);
  9541. }
  9542. *type = (xmlXPathTypeVal) 0;
  9543. *test = (xmlXPathTestVal) 0;
  9544. *prefix = NULL;
  9545. SKIP_BLANKS;
  9546. if ((name == NULL) && (CUR == '*')) {
  9547. /*
  9548. * All elements
  9549. */
  9550. NEXT;
  9551. *test = NODE_TEST_ALL;
  9552. return(NULL);
  9553. }
  9554. if (name == NULL)
  9555. name = xmlXPathParseNCName(ctxt);
  9556. if (name == NULL) {
  9557. XP_ERRORNULL(XPATH_EXPR_ERROR);
  9558. }
  9559. blanks = IS_BLANK_CH(CUR);
  9560. SKIP_BLANKS;
  9561. if (CUR == '(') {
  9562. NEXT;
  9563. /*
  9564. * NodeType or PI search
  9565. */
  9566. if (xmlStrEqual(name, BAD_CAST "comment"))
  9567. *type = NODE_TYPE_COMMENT;
  9568. else if (xmlStrEqual(name, BAD_CAST "node"))
  9569. *type = NODE_TYPE_NODE;
  9570. else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
  9571. *type = NODE_TYPE_PI;
  9572. else if (xmlStrEqual(name, BAD_CAST "text"))
  9573. *type = NODE_TYPE_TEXT;
  9574. else {
  9575. if (name != NULL)
  9576. xmlFree(name);
  9577. XP_ERRORNULL(XPATH_EXPR_ERROR);
  9578. }
  9579. *test = NODE_TEST_TYPE;
  9580. SKIP_BLANKS;
  9581. if (*type == NODE_TYPE_PI) {
  9582. /*
  9583. * Specific case: search a PI by name.
  9584. */
  9585. if (name != NULL)
  9586. xmlFree(name);
  9587. name = NULL;
  9588. if (CUR != ')') {
  9589. name = xmlXPathParseLiteral(ctxt);
  9590. if (name == NULL) {
  9591. XP_ERRORNULL(XPATH_EXPR_ERROR);
  9592. }
  9593. *test = NODE_TEST_PI;
  9594. SKIP_BLANKS;
  9595. }
  9596. }
  9597. if (CUR != ')') {
  9598. if (name != NULL)
  9599. xmlFree(name);
  9600. XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
  9601. }
  9602. NEXT;
  9603. return(name);
  9604. }
  9605. *test = NODE_TEST_NAME;
  9606. if ((!blanks) && (CUR == ':')) {
  9607. NEXT;
  9608. /*
  9609. * Since currently the parser context don't have a
  9610. * namespace list associated:
  9611. * The namespace name for this prefix can be computed
  9612. * only at evaluation time. The compilation is done
  9613. * outside of any context.
  9614. */
  9615. #if 0
  9616. *prefix = xmlXPathNsLookup(ctxt->context, name);
  9617. if (name != NULL)
  9618. xmlFree(name);
  9619. if (*prefix == NULL) {
  9620. XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
  9621. }
  9622. #else
  9623. *prefix = name;
  9624. #endif
  9625. if (CUR == '*') {
  9626. /*
  9627. * All elements
  9628. */
  9629. NEXT;
  9630. *test = NODE_TEST_ALL;
  9631. return(NULL);
  9632. }
  9633. name = xmlXPathParseNCName(ctxt);
  9634. if (name == NULL) {
  9635. XP_ERRORNULL(XPATH_EXPR_ERROR);
  9636. }
  9637. }
  9638. return(name);
  9639. }
  9640. /**
  9641. * xmlXPathIsAxisName:
  9642. * @name: a preparsed name token
  9643. *
  9644. * [6] AxisName ::= 'ancestor'
  9645. * | 'ancestor-or-self'
  9646. * | 'attribute'
  9647. * | 'child'
  9648. * | 'descendant'
  9649. * | 'descendant-or-self'
  9650. * | 'following'
  9651. * | 'following-sibling'
  9652. * | 'namespace'
  9653. * | 'parent'
  9654. * | 'preceding'
  9655. * | 'preceding-sibling'
  9656. * | 'self'
  9657. *
  9658. * Returns the axis or 0
  9659. */
  9660. static xmlXPathAxisVal
  9661. xmlXPathIsAxisName(const xmlChar *name) {
  9662. xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
  9663. switch (name[0]) {
  9664. case 'a':
  9665. if (xmlStrEqual(name, BAD_CAST "ancestor"))
  9666. ret = AXIS_ANCESTOR;
  9667. if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
  9668. ret = AXIS_ANCESTOR_OR_SELF;
  9669. if (xmlStrEqual(name, BAD_CAST "attribute"))
  9670. ret = AXIS_ATTRIBUTE;
  9671. break;
  9672. case 'c':
  9673. if (xmlStrEqual(name, BAD_CAST "child"))
  9674. ret = AXIS_CHILD;
  9675. break;
  9676. case 'd':
  9677. if (xmlStrEqual(name, BAD_CAST "descendant"))
  9678. ret = AXIS_DESCENDANT;
  9679. if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
  9680. ret = AXIS_DESCENDANT_OR_SELF;
  9681. break;
  9682. case 'f':
  9683. if (xmlStrEqual(name, BAD_CAST "following"))
  9684. ret = AXIS_FOLLOWING;
  9685. if (xmlStrEqual(name, BAD_CAST "following-sibling"))
  9686. ret = AXIS_FOLLOWING_SIBLING;
  9687. break;
  9688. case 'n':
  9689. if (xmlStrEqual(name, BAD_CAST "namespace"))
  9690. ret = AXIS_NAMESPACE;
  9691. break;
  9692. case 'p':
  9693. if (xmlStrEqual(name, BAD_CAST "parent"))
  9694. ret = AXIS_PARENT;
  9695. if (xmlStrEqual(name, BAD_CAST "preceding"))
  9696. ret = AXIS_PRECEDING;
  9697. if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
  9698. ret = AXIS_PRECEDING_SIBLING;
  9699. break;
  9700. case 's':
  9701. if (xmlStrEqual(name, BAD_CAST "self"))
  9702. ret = AXIS_SELF;
  9703. break;
  9704. }
  9705. return(ret);
  9706. }
  9707. /**
  9708. * xmlXPathCompStep:
  9709. * @ctxt: the XPath Parser context
  9710. *
  9711. * [4] Step ::= AxisSpecifier NodeTest Predicate*
  9712. * | AbbreviatedStep
  9713. *
  9714. * [12] AbbreviatedStep ::= '.' | '..'
  9715. *
  9716. * [5] AxisSpecifier ::= AxisName '::'
  9717. * | AbbreviatedAxisSpecifier
  9718. *
  9719. * [13] AbbreviatedAxisSpecifier ::= '@'?
  9720. *
  9721. * Modified for XPtr range support as:
  9722. *
  9723. * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
  9724. * | AbbreviatedStep
  9725. * | 'range-to' '(' Expr ')' Predicate*
  9726. *
  9727. * Compile one step in a Location Path
  9728. * A location step of . is short for self::node(). This is
  9729. * particularly useful in conjunction with //. For example, the
  9730. * location path .//para is short for
  9731. * self::node()/descendant-or-self::node()/child::para
  9732. * and so will select all para descendant elements of the context
  9733. * node.
  9734. * Similarly, a location step of .. is short for parent::node().
  9735. * For example, ../title is short for parent::node()/child::title
  9736. * and so will select the title children of the parent of the context
  9737. * node.
  9738. */
  9739. static void
  9740. xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
  9741. #ifdef LIBXML_XPTR_LOCS_ENABLED
  9742. int rangeto = 0;
  9743. int op2 = -1;
  9744. #endif
  9745. SKIP_BLANKS;
  9746. if ((CUR == '.') && (NXT(1) == '.')) {
  9747. SKIP(2);
  9748. SKIP_BLANKS;
  9749. PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
  9750. NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
  9751. } else if (CUR == '.') {
  9752. NEXT;
  9753. SKIP_BLANKS;
  9754. } else {
  9755. xmlChar *name = NULL;
  9756. xmlChar *prefix = NULL;
  9757. xmlXPathTestVal test = (xmlXPathTestVal) 0;
  9758. xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
  9759. xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
  9760. int op1;
  9761. /*
  9762. * The modification needed for XPointer change to the production
  9763. */
  9764. #ifdef LIBXML_XPTR_LOCS_ENABLED
  9765. if (ctxt->xptr) {
  9766. name = xmlXPathParseNCName(ctxt);
  9767. if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
  9768. op2 = ctxt->comp->last;
  9769. xmlFree(name);
  9770. SKIP_BLANKS;
  9771. if (CUR != '(') {
  9772. XP_ERROR(XPATH_EXPR_ERROR);
  9773. }
  9774. NEXT;
  9775. SKIP_BLANKS;
  9776. xmlXPathCompileExpr(ctxt, 1);
  9777. /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
  9778. CHECK_ERROR;
  9779. SKIP_BLANKS;
  9780. if (CUR != ')') {
  9781. XP_ERROR(XPATH_EXPR_ERROR);
  9782. }
  9783. NEXT;
  9784. rangeto = 1;
  9785. goto eval_predicates;
  9786. }
  9787. }
  9788. #endif
  9789. if (CUR == '*') {
  9790. axis = AXIS_CHILD;
  9791. } else {
  9792. if (name == NULL)
  9793. name = xmlXPathParseNCName(ctxt);
  9794. if (name != NULL) {
  9795. axis = xmlXPathIsAxisName(name);
  9796. if (axis != 0) {
  9797. SKIP_BLANKS;
  9798. if ((CUR == ':') && (NXT(1) == ':')) {
  9799. SKIP(2);
  9800. xmlFree(name);
  9801. name = NULL;
  9802. } else {
  9803. /* an element name can conflict with an axis one :-\ */
  9804. axis = AXIS_CHILD;
  9805. }
  9806. } else {
  9807. axis = AXIS_CHILD;
  9808. }
  9809. } else if (CUR == '@') {
  9810. NEXT;
  9811. axis = AXIS_ATTRIBUTE;
  9812. } else {
  9813. axis = AXIS_CHILD;
  9814. }
  9815. }
  9816. if (ctxt->error != XPATH_EXPRESSION_OK) {
  9817. xmlFree(name);
  9818. return;
  9819. }
  9820. name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
  9821. if (test == 0)
  9822. return;
  9823. if ((prefix != NULL) && (ctxt->context != NULL) &&
  9824. (ctxt->context->flags & XML_XPATH_CHECKNS)) {
  9825. if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
  9826. xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
  9827. }
  9828. }
  9829. #ifdef LIBXML_XPTR_LOCS_ENABLED
  9830. eval_predicates:
  9831. #endif
  9832. op1 = ctxt->comp->last;
  9833. ctxt->comp->last = -1;
  9834. SKIP_BLANKS;
  9835. while (CUR == '[') {
  9836. xmlXPathCompPredicate(ctxt, 0);
  9837. }
  9838. #ifdef LIBXML_XPTR_LOCS_ENABLED
  9839. if (rangeto) {
  9840. PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
  9841. } else
  9842. #endif
  9843. if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
  9844. test, type, (void *)prefix, (void *)name) == -1) {
  9845. xmlFree(prefix);
  9846. xmlFree(name);
  9847. }
  9848. }
  9849. }
  9850. /**
  9851. * xmlXPathCompRelativeLocationPath:
  9852. * @ctxt: the XPath Parser context
  9853. *
  9854. * [3] RelativeLocationPath ::= Step
  9855. * | RelativeLocationPath '/' Step
  9856. * | AbbreviatedRelativeLocationPath
  9857. * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
  9858. *
  9859. * Compile a relative location path.
  9860. */
  9861. static void
  9862. xmlXPathCompRelativeLocationPath
  9863. (xmlXPathParserContextPtr ctxt) {
  9864. SKIP_BLANKS;
  9865. if ((CUR == '/') && (NXT(1) == '/')) {
  9866. SKIP(2);
  9867. SKIP_BLANKS;
  9868. PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
  9869. NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
  9870. } else if (CUR == '/') {
  9871. NEXT;
  9872. SKIP_BLANKS;
  9873. }
  9874. xmlXPathCompStep(ctxt);
  9875. CHECK_ERROR;
  9876. SKIP_BLANKS;
  9877. while (CUR == '/') {
  9878. if ((CUR == '/') && (NXT(1) == '/')) {
  9879. SKIP(2);
  9880. SKIP_BLANKS;
  9881. PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
  9882. NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
  9883. xmlXPathCompStep(ctxt);
  9884. } else if (CUR == '/') {
  9885. NEXT;
  9886. SKIP_BLANKS;
  9887. xmlXPathCompStep(ctxt);
  9888. }
  9889. SKIP_BLANKS;
  9890. }
  9891. }
  9892. /**
  9893. * xmlXPathCompLocationPath:
  9894. * @ctxt: the XPath Parser context
  9895. *
  9896. * [1] LocationPath ::= RelativeLocationPath
  9897. * | AbsoluteLocationPath
  9898. * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
  9899. * | AbbreviatedAbsoluteLocationPath
  9900. * [10] AbbreviatedAbsoluteLocationPath ::=
  9901. * '//' RelativeLocationPath
  9902. *
  9903. * Compile a location path
  9904. *
  9905. * // is short for /descendant-or-self::node()/. For example,
  9906. * //para is short for /descendant-or-self::node()/child::para and
  9907. * so will select any para element in the document (even a para element
  9908. * that is a document element will be selected by //para since the
  9909. * document element node is a child of the root node); div//para is
  9910. * short for div/descendant-or-self::node()/child::para and so will
  9911. * select all para descendants of div children.
  9912. */
  9913. static void
  9914. xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
  9915. SKIP_BLANKS;
  9916. if (CUR != '/') {
  9917. xmlXPathCompRelativeLocationPath(ctxt);
  9918. } else {
  9919. while (CUR == '/') {
  9920. if ((CUR == '/') && (NXT(1) == '/')) {
  9921. SKIP(2);
  9922. SKIP_BLANKS;
  9923. PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
  9924. NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
  9925. xmlXPathCompRelativeLocationPath(ctxt);
  9926. } else if (CUR == '/') {
  9927. NEXT;
  9928. SKIP_BLANKS;
  9929. if ((CUR != 0 ) &&
  9930. ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
  9931. (CUR == '@') || (CUR == '*')))
  9932. xmlXPathCompRelativeLocationPath(ctxt);
  9933. }
  9934. CHECK_ERROR;
  9935. }
  9936. }
  9937. }
  9938. /************************************************************************
  9939. * *
  9940. * XPath precompiled expression evaluation *
  9941. * *
  9942. ************************************************************************/
  9943. static int
  9944. xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
  9945. /**
  9946. * xmlXPathNodeSetFilter:
  9947. * @ctxt: the XPath Parser context
  9948. * @set: the node set to filter
  9949. * @filterOpIndex: the index of the predicate/filter op
  9950. * @minPos: minimum position in the filtered set (1-based)
  9951. * @maxPos: maximum position in the filtered set (1-based)
  9952. * @hasNsNodes: true if the node set may contain namespace nodes
  9953. *
  9954. * Filter a node set, keeping only nodes for which the predicate expression
  9955. * matches. Afterwards, keep only nodes between minPos and maxPos in the
  9956. * filtered result.
  9957. */
  9958. static void
  9959. xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
  9960. xmlNodeSetPtr set,
  9961. int filterOpIndex,
  9962. int minPos, int maxPos,
  9963. int hasNsNodes)
  9964. {
  9965. xmlXPathContextPtr xpctxt;
  9966. xmlNodePtr oldnode;
  9967. xmlDocPtr olddoc;
  9968. xmlXPathStepOpPtr filterOp;
  9969. int oldcs, oldpp;
  9970. int i, j, pos;
  9971. if ((set == NULL) || (set->nodeNr == 0))
  9972. return;
  9973. /*
  9974. * Check if the node set contains a sufficient number of nodes for
  9975. * the requested range.
  9976. */
  9977. if (set->nodeNr < minPos) {
  9978. xmlXPathNodeSetClear(set, hasNsNodes);
  9979. return;
  9980. }
  9981. xpctxt = ctxt->context;
  9982. oldnode = xpctxt->node;
  9983. olddoc = xpctxt->doc;
  9984. oldcs = xpctxt->contextSize;
  9985. oldpp = xpctxt->proximityPosition;
  9986. filterOp = &ctxt->comp->steps[filterOpIndex];
  9987. xpctxt->contextSize = set->nodeNr;
  9988. for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
  9989. xmlNodePtr node = set->nodeTab[i];
  9990. int res;
  9991. xpctxt->node = node;
  9992. xpctxt->proximityPosition = i + 1;
  9993. /*
  9994. * Also set the xpath document in case things like
  9995. * key() are evaluated in the predicate.
  9996. *
  9997. * TODO: Get real doc for namespace nodes.
  9998. */
  9999. if ((node->type != XML_NAMESPACE_DECL) &&
  10000. (node->doc != NULL))
  10001. xpctxt->doc = node->doc;
  10002. res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
  10003. if (ctxt->error != XPATH_EXPRESSION_OK)
  10004. break;
  10005. if (res < 0) {
  10006. /* Shouldn't happen */
  10007. xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
  10008. break;
  10009. }
  10010. if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
  10011. if (i != j) {
  10012. set->nodeTab[j] = node;
  10013. set->nodeTab[i] = NULL;
  10014. }
  10015. j += 1;
  10016. } else {
  10017. /* Remove the entry from the initial node set. */
  10018. set->nodeTab[i] = NULL;
  10019. if (node->type == XML_NAMESPACE_DECL)
  10020. xmlXPathNodeSetFreeNs((xmlNsPtr) node);
  10021. }
  10022. if (res != 0) {
  10023. if (pos == maxPos) {
  10024. i += 1;
  10025. break;
  10026. }
  10027. pos += 1;
  10028. }
  10029. }
  10030. /* Free remaining nodes. */
  10031. if (hasNsNodes) {
  10032. for (; i < set->nodeNr; i++) {
  10033. xmlNodePtr node = set->nodeTab[i];
  10034. if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
  10035. xmlXPathNodeSetFreeNs((xmlNsPtr) node);
  10036. }
  10037. }
  10038. set->nodeNr = j;
  10039. /* If too many elements were removed, shrink table to preserve memory. */
  10040. if ((set->nodeMax > XML_NODESET_DEFAULT) &&
  10041. (set->nodeNr < set->nodeMax / 2)) {
  10042. xmlNodePtr *tmp;
  10043. int nodeMax = set->nodeNr;
  10044. if (nodeMax < XML_NODESET_DEFAULT)
  10045. nodeMax = XML_NODESET_DEFAULT;
  10046. tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
  10047. nodeMax * sizeof(xmlNodePtr));
  10048. if (tmp == NULL) {
  10049. xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
  10050. } else {
  10051. set->nodeTab = tmp;
  10052. set->nodeMax = nodeMax;
  10053. }
  10054. }
  10055. xpctxt->node = oldnode;
  10056. xpctxt->doc = olddoc;
  10057. xpctxt->contextSize = oldcs;
  10058. xpctxt->proximityPosition = oldpp;
  10059. }
  10060. #ifdef LIBXML_XPTR_LOCS_ENABLED
  10061. /**
  10062. * xmlXPathLocationSetFilter:
  10063. * @ctxt: the XPath Parser context
  10064. * @locset: the location set to filter
  10065. * @filterOpIndex: the index of the predicate/filter op
  10066. * @minPos: minimum position in the filtered set (1-based)
  10067. * @maxPos: maximum position in the filtered set (1-based)
  10068. *
  10069. * Filter a location set, keeping only nodes for which the predicate
  10070. * expression matches. Afterwards, keep only nodes between minPos and maxPos
  10071. * in the filtered result.
  10072. */
  10073. static void
  10074. xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
  10075. xmlLocationSetPtr locset,
  10076. int filterOpIndex,
  10077. int minPos, int maxPos)
  10078. {
  10079. xmlXPathContextPtr xpctxt;
  10080. xmlNodePtr oldnode;
  10081. xmlDocPtr olddoc;
  10082. xmlXPathStepOpPtr filterOp;
  10083. int oldcs, oldpp;
  10084. int i, j, pos;
  10085. if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
  10086. return;
  10087. xpctxt = ctxt->context;
  10088. oldnode = xpctxt->node;
  10089. olddoc = xpctxt->doc;
  10090. oldcs = xpctxt->contextSize;
  10091. oldpp = xpctxt->proximityPosition;
  10092. filterOp = &ctxt->comp->steps[filterOpIndex];
  10093. xpctxt->contextSize = locset->locNr;
  10094. for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
  10095. xmlNodePtr contextNode = locset->locTab[i]->user;
  10096. int res;
  10097. xpctxt->node = contextNode;
  10098. xpctxt->proximityPosition = i + 1;
  10099. /*
  10100. * Also set the xpath document in case things like
  10101. * key() are evaluated in the predicate.
  10102. *
  10103. * TODO: Get real doc for namespace nodes.
  10104. */
  10105. if ((contextNode->type != XML_NAMESPACE_DECL) &&
  10106. (contextNode->doc != NULL))
  10107. xpctxt->doc = contextNode->doc;
  10108. res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
  10109. if (ctxt->error != XPATH_EXPRESSION_OK)
  10110. break;
  10111. if (res < 0) {
  10112. /* Shouldn't happen */
  10113. xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
  10114. break;
  10115. }
  10116. if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
  10117. if (i != j) {
  10118. locset->locTab[j] = locset->locTab[i];
  10119. locset->locTab[i] = NULL;
  10120. }
  10121. j += 1;
  10122. } else {
  10123. /* Remove the entry from the initial location set. */
  10124. xmlXPathFreeObject(locset->locTab[i]);
  10125. locset->locTab[i] = NULL;
  10126. }
  10127. if (res != 0) {
  10128. if (pos == maxPos) {
  10129. i += 1;
  10130. break;
  10131. }
  10132. pos += 1;
  10133. }
  10134. }
  10135. /* Free remaining nodes. */
  10136. for (; i < locset->locNr; i++)
  10137. xmlXPathFreeObject(locset->locTab[i]);
  10138. locset->locNr = j;
  10139. /* If too many elements were removed, shrink table to preserve memory. */
  10140. if ((locset->locMax > XML_NODESET_DEFAULT) &&
  10141. (locset->locNr < locset->locMax / 2)) {
  10142. xmlXPathObjectPtr *tmp;
  10143. int locMax = locset->locNr;
  10144. if (locMax < XML_NODESET_DEFAULT)
  10145. locMax = XML_NODESET_DEFAULT;
  10146. tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
  10147. locMax * sizeof(xmlXPathObjectPtr));
  10148. if (tmp == NULL) {
  10149. xmlXPathPErrMemory(ctxt, "shrinking locset\n");
  10150. } else {
  10151. locset->locTab = tmp;
  10152. locset->locMax = locMax;
  10153. }
  10154. }
  10155. xpctxt->node = oldnode;
  10156. xpctxt->doc = olddoc;
  10157. xpctxt->contextSize = oldcs;
  10158. xpctxt->proximityPosition = oldpp;
  10159. }
  10160. #endif /* LIBXML_XPTR_LOCS_ENABLED */
  10161. /**
  10162. * xmlXPathCompOpEvalPredicate:
  10163. * @ctxt: the XPath Parser context
  10164. * @op: the predicate op
  10165. * @set: the node set to filter
  10166. * @minPos: minimum position in the filtered set (1-based)
  10167. * @maxPos: maximum position in the filtered set (1-based)
  10168. * @hasNsNodes: true if the node set may contain namespace nodes
  10169. *
  10170. * Filter a node set, keeping only nodes for which the sequence of predicate
  10171. * expressions matches. Afterwards, keep only nodes between minPos and maxPos
  10172. * in the filtered result.
  10173. */
  10174. static void
  10175. xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
  10176. xmlXPathStepOpPtr op,
  10177. xmlNodeSetPtr set,
  10178. int minPos, int maxPos,
  10179. int hasNsNodes)
  10180. {
  10181. if (op->ch1 != -1) {
  10182. xmlXPathCompExprPtr comp = ctxt->comp;
  10183. /*
  10184. * Process inner predicates first.
  10185. */
  10186. if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
  10187. xmlGenericError(xmlGenericErrorContext,
  10188. "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
  10189. XP_ERROR(XPATH_INVALID_OPERAND);
  10190. }
  10191. if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
  10192. XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
  10193. ctxt->context->depth += 1;
  10194. xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
  10195. 1, set->nodeNr, hasNsNodes);
  10196. ctxt->context->depth -= 1;
  10197. CHECK_ERROR;
  10198. }
  10199. if (op->ch2 != -1)
  10200. xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
  10201. }
  10202. static int
  10203. xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
  10204. xmlXPathStepOpPtr op,
  10205. int *maxPos)
  10206. {
  10207. xmlXPathStepOpPtr exprOp;
  10208. /*
  10209. * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
  10210. */
  10211. /*
  10212. * If not -1, then ch1 will point to:
  10213. * 1) For predicates (XPATH_OP_PREDICATE):
  10214. * - an inner predicate operator
  10215. * 2) For filters (XPATH_OP_FILTER):
  10216. * - an inner filter operator OR
  10217. * - an expression selecting the node set.
  10218. * E.g. "key('a', 'b')" or "(//foo | //bar)".
  10219. */
  10220. if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
  10221. return(0);
  10222. if (op->ch2 != -1) {
  10223. exprOp = &ctxt->comp->steps[op->ch2];
  10224. } else
  10225. return(0);
  10226. if ((exprOp != NULL) &&
  10227. (exprOp->op == XPATH_OP_VALUE) &&
  10228. (exprOp->value4 != NULL) &&
  10229. (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
  10230. {
  10231. double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
  10232. /*
  10233. * We have a "[n]" predicate here.
  10234. * TODO: Unfortunately this simplistic test here is not
  10235. * able to detect a position() predicate in compound
  10236. * expressions like "[@attr = 'a" and position() = 1],
  10237. * and even not the usage of position() in
  10238. * "[position() = 1]"; thus - obviously - a position-range,
  10239. * like it "[position() < 5]", is also not detected.
  10240. * Maybe we could rewrite the AST to ease the optimization.
  10241. */
  10242. if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
  10243. *maxPos = (int) floatval;
  10244. if (floatval == (double) *maxPos)
  10245. return(1);
  10246. }
  10247. }
  10248. return(0);
  10249. }
  10250. static int
  10251. xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
  10252. xmlXPathStepOpPtr op,
  10253. xmlNodePtr * first, xmlNodePtr * last,
  10254. int toBool)
  10255. {
  10256. #define XP_TEST_HIT \
  10257. if (hasAxisRange != 0) { \
  10258. if (++pos == maxPos) { \
  10259. if (addNode(seq, cur) < 0) \
  10260. ctxt->error = XPATH_MEMORY_ERROR; \
  10261. goto axis_range_end; } \
  10262. } else { \
  10263. if (addNode(seq, cur) < 0) \
  10264. ctxt->error = XPATH_MEMORY_ERROR; \
  10265. if (breakOnFirstHit) goto first_hit; }
  10266. #define XP_TEST_HIT_NS \
  10267. if (hasAxisRange != 0) { \
  10268. if (++pos == maxPos) { \
  10269. hasNsNodes = 1; \
  10270. if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
  10271. ctxt->error = XPATH_MEMORY_ERROR; \
  10272. goto axis_range_end; } \
  10273. } else { \
  10274. hasNsNodes = 1; \
  10275. if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
  10276. ctxt->error = XPATH_MEMORY_ERROR; \
  10277. if (breakOnFirstHit) goto first_hit; }
  10278. xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
  10279. xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
  10280. xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
  10281. const xmlChar *prefix = op->value4;
  10282. const xmlChar *name = op->value5;
  10283. const xmlChar *URI = NULL;
  10284. int total = 0, hasNsNodes = 0;
  10285. /* The popped object holding the context nodes */
  10286. xmlXPathObjectPtr obj;
  10287. /* The set of context nodes for the node tests */
  10288. xmlNodeSetPtr contextSeq;
  10289. int contextIdx;
  10290. xmlNodePtr contextNode;
  10291. /* The final resulting node set wrt to all context nodes */
  10292. xmlNodeSetPtr outSeq;
  10293. /*
  10294. * The temporary resulting node set wrt 1 context node.
  10295. * Used to feed predicate evaluation.
  10296. */
  10297. xmlNodeSetPtr seq;
  10298. xmlNodePtr cur;
  10299. /* First predicate operator */
  10300. xmlXPathStepOpPtr predOp;
  10301. int maxPos; /* The requested position() (when a "[n]" predicate) */
  10302. int hasPredicateRange, hasAxisRange, pos;
  10303. int breakOnFirstHit;
  10304. xmlXPathTraversalFunction next = NULL;
  10305. int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
  10306. xmlXPathNodeSetMergeFunction mergeAndClear;
  10307. xmlNodePtr oldContextNode;
  10308. xmlXPathContextPtr xpctxt = ctxt->context;
  10309. CHECK_TYPE0(XPATH_NODESET);
  10310. obj = valuePop(ctxt);
  10311. /*
  10312. * Setup namespaces.
  10313. */
  10314. if (prefix != NULL) {
  10315. URI = xmlXPathNsLookup(xpctxt, prefix);
  10316. if (URI == NULL) {
  10317. xmlXPathReleaseObject(xpctxt, obj);
  10318. XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
  10319. }
  10320. }
  10321. /*
  10322. * Setup axis.
  10323. *
  10324. * MAYBE FUTURE TODO: merging optimizations:
  10325. * - If the nodes to be traversed wrt to the initial nodes and
  10326. * the current axis cannot overlap, then we could avoid searching
  10327. * for duplicates during the merge.
  10328. * But the question is how/when to evaluate if they cannot overlap.
  10329. * Example: if we know that for two initial nodes, the one is
  10330. * not in the ancestor-or-self axis of the other, then we could safely
  10331. * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
  10332. * the descendant-or-self axis.
  10333. */
  10334. mergeAndClear = xmlXPathNodeSetMergeAndClear;
  10335. switch (axis) {
  10336. case AXIS_ANCESTOR:
  10337. first = NULL;
  10338. next = xmlXPathNextAncestor;
  10339. break;
  10340. case AXIS_ANCESTOR_OR_SELF:
  10341. first = NULL;
  10342. next = xmlXPathNextAncestorOrSelf;
  10343. break;
  10344. case AXIS_ATTRIBUTE:
  10345. first = NULL;
  10346. last = NULL;
  10347. next = xmlXPathNextAttribute;
  10348. mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
  10349. break;
  10350. case AXIS_CHILD:
  10351. last = NULL;
  10352. if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
  10353. (type == NODE_TYPE_NODE))
  10354. {
  10355. /*
  10356. * Optimization if an element node type is 'element'.
  10357. */
  10358. next = xmlXPathNextChildElement;
  10359. } else
  10360. next = xmlXPathNextChild;
  10361. mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
  10362. break;
  10363. case AXIS_DESCENDANT:
  10364. last = NULL;
  10365. next = xmlXPathNextDescendant;
  10366. break;
  10367. case AXIS_DESCENDANT_OR_SELF:
  10368. last = NULL;
  10369. next = xmlXPathNextDescendantOrSelf;
  10370. break;
  10371. case AXIS_FOLLOWING:
  10372. last = NULL;
  10373. next = xmlXPathNextFollowing;
  10374. break;
  10375. case AXIS_FOLLOWING_SIBLING:
  10376. last = NULL;
  10377. next = xmlXPathNextFollowingSibling;
  10378. break;
  10379. case AXIS_NAMESPACE:
  10380. first = NULL;
  10381. last = NULL;
  10382. next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
  10383. mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
  10384. break;
  10385. case AXIS_PARENT:
  10386. first = NULL;
  10387. next = xmlXPathNextParent;
  10388. break;
  10389. case AXIS_PRECEDING:
  10390. first = NULL;
  10391. next = xmlXPathNextPrecedingInternal;
  10392. break;
  10393. case AXIS_PRECEDING_SIBLING:
  10394. first = NULL;
  10395. next = xmlXPathNextPrecedingSibling;
  10396. break;
  10397. case AXIS_SELF:
  10398. first = NULL;
  10399. last = NULL;
  10400. next = xmlXPathNextSelf;
  10401. mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
  10402. break;
  10403. }
  10404. if (next == NULL) {
  10405. xmlXPathReleaseObject(xpctxt, obj);
  10406. return(0);
  10407. }
  10408. contextSeq = obj->nodesetval;
  10409. if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
  10410. xmlXPathReleaseObject(xpctxt, obj);
  10411. valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
  10412. return(0);
  10413. }
  10414. /*
  10415. * Predicate optimization ---------------------------------------------
  10416. * If this step has a last predicate, which contains a position(),
  10417. * then we'll optimize (although not exactly "position()", but only
  10418. * the short-hand form, i.e., "[n]".
  10419. *
  10420. * Example - expression "/foo[parent::bar][1]":
  10421. *
  10422. * COLLECT 'child' 'name' 'node' foo -- op (we are here)
  10423. * ROOT -- op->ch1
  10424. * PREDICATE -- op->ch2 (predOp)
  10425. * PREDICATE -- predOp->ch1 = [parent::bar]
  10426. * SORT
  10427. * COLLECT 'parent' 'name' 'node' bar
  10428. * NODE
  10429. * ELEM Object is a number : 1 -- predOp->ch2 = [1]
  10430. *
  10431. */
  10432. maxPos = 0;
  10433. predOp = NULL;
  10434. hasPredicateRange = 0;
  10435. hasAxisRange = 0;
  10436. if (op->ch2 != -1) {
  10437. /*
  10438. * There's at least one predicate. 16 == XPATH_OP_PREDICATE
  10439. */
  10440. predOp = &ctxt->comp->steps[op->ch2];
  10441. if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
  10442. if (predOp->ch1 != -1) {
  10443. /*
  10444. * Use the next inner predicate operator.
  10445. */
  10446. predOp = &ctxt->comp->steps[predOp->ch1];
  10447. hasPredicateRange = 1;
  10448. } else {
  10449. /*
  10450. * There's no other predicate than the [n] predicate.
  10451. */
  10452. predOp = NULL;
  10453. hasAxisRange = 1;
  10454. }
  10455. }
  10456. }
  10457. breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
  10458. /*
  10459. * Axis traversal -----------------------------------------------------
  10460. */
  10461. /*
  10462. * 2.3 Node Tests
  10463. * - For the attribute axis, the principal node type is attribute.
  10464. * - For the namespace axis, the principal node type is namespace.
  10465. * - For other axes, the principal node type is element.
  10466. *
  10467. * A node test * is true for any node of the
  10468. * principal node type. For example, child::* will
  10469. * select all element children of the context node
  10470. */
  10471. oldContextNode = xpctxt->node;
  10472. addNode = xmlXPathNodeSetAddUnique;
  10473. outSeq = NULL;
  10474. seq = NULL;
  10475. contextNode = NULL;
  10476. contextIdx = 0;
  10477. while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
  10478. (ctxt->error == XPATH_EXPRESSION_OK)) {
  10479. xpctxt->node = contextSeq->nodeTab[contextIdx++];
  10480. if (seq == NULL) {
  10481. seq = xmlXPathNodeSetCreate(NULL);
  10482. if (seq == NULL) {
  10483. /* TODO: Propagate memory error. */
  10484. total = 0;
  10485. goto error;
  10486. }
  10487. }
  10488. /*
  10489. * Traverse the axis and test the nodes.
  10490. */
  10491. pos = 0;
  10492. cur = NULL;
  10493. hasNsNodes = 0;
  10494. do {
  10495. if (OP_LIMIT_EXCEEDED(ctxt, 1))
  10496. goto error;
  10497. cur = next(ctxt, cur);
  10498. if (cur == NULL)
  10499. break;
  10500. /*
  10501. * QUESTION TODO: What does the "first" and "last" stuff do?
  10502. */
  10503. if ((first != NULL) && (*first != NULL)) {
  10504. if (*first == cur)
  10505. break;
  10506. if (((total % 256) == 0) &&
  10507. #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
  10508. (xmlXPathCmpNodesExt(*first, cur) >= 0))
  10509. #else
  10510. (xmlXPathCmpNodes(*first, cur) >= 0))
  10511. #endif
  10512. {
  10513. break;
  10514. }
  10515. }
  10516. if ((last != NULL) && (*last != NULL)) {
  10517. if (*last == cur)
  10518. break;
  10519. if (((total % 256) == 0) &&
  10520. #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
  10521. (xmlXPathCmpNodesExt(cur, *last) >= 0))
  10522. #else
  10523. (xmlXPathCmpNodes(cur, *last) >= 0))
  10524. #endif
  10525. {
  10526. break;
  10527. }
  10528. }
  10529. total++;
  10530. switch (test) {
  10531. case NODE_TEST_NONE:
  10532. total = 0;
  10533. STRANGE
  10534. goto error;
  10535. case NODE_TEST_TYPE:
  10536. if (type == NODE_TYPE_NODE) {
  10537. switch (cur->type) {
  10538. case XML_DOCUMENT_NODE:
  10539. case XML_HTML_DOCUMENT_NODE:
  10540. case XML_ELEMENT_NODE:
  10541. case XML_ATTRIBUTE_NODE:
  10542. case XML_PI_NODE:
  10543. case XML_COMMENT_NODE:
  10544. case XML_CDATA_SECTION_NODE:
  10545. case XML_TEXT_NODE:
  10546. XP_TEST_HIT
  10547. break;
  10548. case XML_NAMESPACE_DECL: {
  10549. if (axis == AXIS_NAMESPACE) {
  10550. XP_TEST_HIT_NS
  10551. } else {
  10552. hasNsNodes = 1;
  10553. XP_TEST_HIT
  10554. }
  10555. break;
  10556. }
  10557. default:
  10558. break;
  10559. }
  10560. } else if (cur->type == (xmlElementType) type) {
  10561. if (cur->type == XML_NAMESPACE_DECL)
  10562. XP_TEST_HIT_NS
  10563. else
  10564. XP_TEST_HIT
  10565. } else if ((type == NODE_TYPE_TEXT) &&
  10566. (cur->type == XML_CDATA_SECTION_NODE))
  10567. {
  10568. XP_TEST_HIT
  10569. }
  10570. break;
  10571. case NODE_TEST_PI:
  10572. if ((cur->type == XML_PI_NODE) &&
  10573. ((name == NULL) || xmlStrEqual(name, cur->name)))
  10574. {
  10575. XP_TEST_HIT
  10576. }
  10577. break;
  10578. case NODE_TEST_ALL:
  10579. if (axis == AXIS_ATTRIBUTE) {
  10580. if (cur->type == XML_ATTRIBUTE_NODE)
  10581. {
  10582. if (prefix == NULL)
  10583. {
  10584. XP_TEST_HIT
  10585. } else if ((cur->ns != NULL) &&
  10586. (xmlStrEqual(URI, cur->ns->href)))
  10587. {
  10588. XP_TEST_HIT
  10589. }
  10590. }
  10591. } else if (axis == AXIS_NAMESPACE) {
  10592. if (cur->type == XML_NAMESPACE_DECL)
  10593. {
  10594. XP_TEST_HIT_NS
  10595. }
  10596. } else {
  10597. if (cur->type == XML_ELEMENT_NODE) {
  10598. if (prefix == NULL)
  10599. {
  10600. XP_TEST_HIT
  10601. } else if ((cur->ns != NULL) &&
  10602. (xmlStrEqual(URI, cur->ns->href)))
  10603. {
  10604. XP_TEST_HIT
  10605. }
  10606. }
  10607. }
  10608. break;
  10609. case NODE_TEST_NS:{
  10610. TODO;
  10611. break;
  10612. }
  10613. case NODE_TEST_NAME:
  10614. if (axis == AXIS_ATTRIBUTE) {
  10615. if (cur->type != XML_ATTRIBUTE_NODE)
  10616. break;
  10617. } else if (axis == AXIS_NAMESPACE) {
  10618. if (cur->type != XML_NAMESPACE_DECL)
  10619. break;
  10620. } else {
  10621. if (cur->type != XML_ELEMENT_NODE)
  10622. break;
  10623. }
  10624. switch (cur->type) {
  10625. case XML_ELEMENT_NODE:
  10626. if (xmlStrEqual(name, cur->name)) {
  10627. if (prefix == NULL) {
  10628. if (cur->ns == NULL)
  10629. {
  10630. XP_TEST_HIT
  10631. }
  10632. } else {
  10633. if ((cur->ns != NULL) &&
  10634. (xmlStrEqual(URI, cur->ns->href)))
  10635. {
  10636. XP_TEST_HIT
  10637. }
  10638. }
  10639. }
  10640. break;
  10641. case XML_ATTRIBUTE_NODE:{
  10642. xmlAttrPtr attr = (xmlAttrPtr) cur;
  10643. if (xmlStrEqual(name, attr->name)) {
  10644. if (prefix == NULL) {
  10645. if ((attr->ns == NULL) ||
  10646. (attr->ns->prefix == NULL))
  10647. {
  10648. XP_TEST_HIT
  10649. }
  10650. } else {
  10651. if ((attr->ns != NULL) &&
  10652. (xmlStrEqual(URI,
  10653. attr->ns->href)))
  10654. {
  10655. XP_TEST_HIT
  10656. }
  10657. }
  10658. }
  10659. break;
  10660. }
  10661. case XML_NAMESPACE_DECL:
  10662. if (cur->type == XML_NAMESPACE_DECL) {
  10663. xmlNsPtr ns = (xmlNsPtr) cur;
  10664. if ((ns->prefix != NULL) && (name != NULL)
  10665. && (xmlStrEqual(ns->prefix, name)))
  10666. {
  10667. XP_TEST_HIT_NS
  10668. }
  10669. }
  10670. break;
  10671. default:
  10672. break;
  10673. }
  10674. break;
  10675. } /* switch(test) */
  10676. } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
  10677. goto apply_predicates;
  10678. axis_range_end: /* ----------------------------------------------------- */
  10679. /*
  10680. * We have a "/foo[n]", and position() = n was reached.
  10681. * Note that we can have as well "/foo/::parent::foo[1]", so
  10682. * a duplicate-aware merge is still needed.
  10683. * Merge with the result.
  10684. */
  10685. if (outSeq == NULL) {
  10686. outSeq = seq;
  10687. seq = NULL;
  10688. } else
  10689. /* TODO: Check memory error. */
  10690. outSeq = mergeAndClear(outSeq, seq);
  10691. /*
  10692. * Break if only a true/false result was requested.
  10693. */
  10694. if (toBool)
  10695. break;
  10696. continue;
  10697. first_hit: /* ---------------------------------------------------------- */
  10698. /*
  10699. * Break if only a true/false result was requested and
  10700. * no predicates existed and a node test succeeded.
  10701. */
  10702. if (outSeq == NULL) {
  10703. outSeq = seq;
  10704. seq = NULL;
  10705. } else
  10706. /* TODO: Check memory error. */
  10707. outSeq = mergeAndClear(outSeq, seq);
  10708. break;
  10709. apply_predicates: /* --------------------------------------------------- */
  10710. if (ctxt->error != XPATH_EXPRESSION_OK)
  10711. goto error;
  10712. /*
  10713. * Apply predicates.
  10714. */
  10715. if ((predOp != NULL) && (seq->nodeNr > 0)) {
  10716. /*
  10717. * E.g. when we have a "/foo[some expression][n]".
  10718. */
  10719. /*
  10720. * QUESTION TODO: The old predicate evaluation took into
  10721. * account location-sets.
  10722. * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
  10723. * Do we expect such a set here?
  10724. * All what I learned now from the evaluation semantics
  10725. * does not indicate that a location-set will be processed
  10726. * here, so this looks OK.
  10727. */
  10728. /*
  10729. * Iterate over all predicates, starting with the outermost
  10730. * predicate.
  10731. * TODO: Problem: we cannot execute the inner predicates first
  10732. * since we cannot go back *up* the operator tree!
  10733. * Options we have:
  10734. * 1) Use of recursive functions (like is it currently done
  10735. * via xmlXPathCompOpEval())
  10736. * 2) Add a predicate evaluation information stack to the
  10737. * context struct
  10738. * 3) Change the way the operators are linked; we need a
  10739. * "parent" field on xmlXPathStepOp
  10740. *
  10741. * For the moment, I'll try to solve this with a recursive
  10742. * function: xmlXPathCompOpEvalPredicate().
  10743. */
  10744. if (hasPredicateRange != 0)
  10745. xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
  10746. hasNsNodes);
  10747. else
  10748. xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
  10749. hasNsNodes);
  10750. if (ctxt->error != XPATH_EXPRESSION_OK) {
  10751. total = 0;
  10752. goto error;
  10753. }
  10754. }
  10755. if (seq->nodeNr > 0) {
  10756. /*
  10757. * Add to result set.
  10758. */
  10759. if (outSeq == NULL) {
  10760. outSeq = seq;
  10761. seq = NULL;
  10762. } else {
  10763. /* TODO: Check memory error. */
  10764. outSeq = mergeAndClear(outSeq, seq);
  10765. }
  10766. if (toBool)
  10767. break;
  10768. }
  10769. }
  10770. error:
  10771. if ((obj->boolval) && (obj->user != NULL)) {
  10772. /*
  10773. * QUESTION TODO: What does this do and why?
  10774. * TODO: Do we have to do this also for the "error"
  10775. * cleanup further down?
  10776. */
  10777. ctxt->value->boolval = 1;
  10778. ctxt->value->user = obj->user;
  10779. obj->user = NULL;
  10780. obj->boolval = 0;
  10781. }
  10782. xmlXPathReleaseObject(xpctxt, obj);
  10783. /*
  10784. * Ensure we return at least an empty set.
  10785. */
  10786. if (outSeq == NULL) {
  10787. if ((seq != NULL) && (seq->nodeNr == 0))
  10788. outSeq = seq;
  10789. else
  10790. /* TODO: Check memory error. */
  10791. outSeq = xmlXPathNodeSetCreate(NULL);
  10792. }
  10793. if ((seq != NULL) && (seq != outSeq)) {
  10794. xmlXPathFreeNodeSet(seq);
  10795. }
  10796. /*
  10797. * Hand over the result. Better to push the set also in
  10798. * case of errors.
  10799. */
  10800. valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
  10801. /*
  10802. * Reset the context node.
  10803. */
  10804. xpctxt->node = oldContextNode;
  10805. /*
  10806. * When traversing the namespace axis in "toBool" mode, it's
  10807. * possible that tmpNsList wasn't freed.
  10808. */
  10809. if (xpctxt->tmpNsList != NULL) {
  10810. xmlFree(xpctxt->tmpNsList);
  10811. xpctxt->tmpNsList = NULL;
  10812. }
  10813. return(total);
  10814. }
  10815. static int
  10816. xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
  10817. xmlXPathStepOpPtr op, xmlNodePtr * first);
  10818. /**
  10819. * xmlXPathCompOpEvalFirst:
  10820. * @ctxt: the XPath parser context with the compiled expression
  10821. * @op: an XPath compiled operation
  10822. * @first: the first elem found so far
  10823. *
  10824. * Evaluate the Precompiled XPath operation searching only the first
  10825. * element in document order
  10826. *
  10827. * Returns the number of examined objects.
  10828. */
  10829. static int
  10830. xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
  10831. xmlXPathStepOpPtr op, xmlNodePtr * first)
  10832. {
  10833. int total = 0, cur;
  10834. xmlXPathCompExprPtr comp;
  10835. xmlXPathObjectPtr arg1, arg2;
  10836. CHECK_ERROR0;
  10837. if (OP_LIMIT_EXCEEDED(ctxt, 1))
  10838. return(0);
  10839. if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
  10840. XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
  10841. ctxt->context->depth += 1;
  10842. comp = ctxt->comp;
  10843. switch (op->op) {
  10844. case XPATH_OP_END:
  10845. break;
  10846. case XPATH_OP_UNION:
  10847. total =
  10848. xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
  10849. first);
  10850. CHECK_ERROR0;
  10851. if ((ctxt->value != NULL)
  10852. && (ctxt->value->type == XPATH_NODESET)
  10853. && (ctxt->value->nodesetval != NULL)
  10854. && (ctxt->value->nodesetval->nodeNr >= 1)) {
  10855. /*
  10856. * limit tree traversing to first node in the result
  10857. */
  10858. /*
  10859. * OPTIMIZE TODO: This implicitly sorts
  10860. * the result, even if not needed. E.g. if the argument
  10861. * of the count() function, no sorting is needed.
  10862. * OPTIMIZE TODO: How do we know if the node-list wasn't
  10863. * already sorted?
  10864. */
  10865. if (ctxt->value->nodesetval->nodeNr > 1)
  10866. xmlXPathNodeSetSort(ctxt->value->nodesetval);
  10867. *first = ctxt->value->nodesetval->nodeTab[0];
  10868. }
  10869. cur =
  10870. xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
  10871. first);
  10872. CHECK_ERROR0;
  10873. arg2 = valuePop(ctxt);
  10874. arg1 = valuePop(ctxt);
  10875. if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
  10876. (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
  10877. xmlXPathReleaseObject(ctxt->context, arg1);
  10878. xmlXPathReleaseObject(ctxt->context, arg2);
  10879. XP_ERROR0(XPATH_INVALID_TYPE);
  10880. }
  10881. if ((ctxt->context->opLimit != 0) &&
  10882. (((arg1->nodesetval != NULL) &&
  10883. (xmlXPathCheckOpLimit(ctxt,
  10884. arg1->nodesetval->nodeNr) < 0)) ||
  10885. ((arg2->nodesetval != NULL) &&
  10886. (xmlXPathCheckOpLimit(ctxt,
  10887. arg2->nodesetval->nodeNr) < 0)))) {
  10888. xmlXPathReleaseObject(ctxt->context, arg1);
  10889. xmlXPathReleaseObject(ctxt->context, arg2);
  10890. break;
  10891. }
  10892. /* TODO: Check memory error. */
  10893. arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
  10894. arg2->nodesetval);
  10895. valuePush(ctxt, arg1);
  10896. xmlXPathReleaseObject(ctxt->context, arg2);
  10897. /* optimizer */
  10898. if (total > cur)
  10899. xmlXPathCompSwap(op);
  10900. total += cur;
  10901. break;
  10902. case XPATH_OP_ROOT:
  10903. xmlXPathRoot(ctxt);
  10904. break;
  10905. case XPATH_OP_NODE:
  10906. if (op->ch1 != -1)
  10907. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  10908. CHECK_ERROR0;
  10909. if (op->ch2 != -1)
  10910. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  10911. CHECK_ERROR0;
  10912. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  10913. ctxt->context->node));
  10914. break;
  10915. case XPATH_OP_COLLECT:{
  10916. if (op->ch1 == -1)
  10917. break;
  10918. total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  10919. CHECK_ERROR0;
  10920. total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
  10921. break;
  10922. }
  10923. case XPATH_OP_VALUE:
  10924. valuePush(ctxt,
  10925. xmlXPathCacheObjectCopy(ctxt->context,
  10926. (xmlXPathObjectPtr) op->value4));
  10927. break;
  10928. case XPATH_OP_SORT:
  10929. if (op->ch1 != -1)
  10930. total +=
  10931. xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
  10932. first);
  10933. CHECK_ERROR0;
  10934. if ((ctxt->value != NULL)
  10935. && (ctxt->value->type == XPATH_NODESET)
  10936. && (ctxt->value->nodesetval != NULL)
  10937. && (ctxt->value->nodesetval->nodeNr > 1))
  10938. xmlXPathNodeSetSort(ctxt->value->nodesetval);
  10939. break;
  10940. #ifdef XP_OPTIMIZED_FILTER_FIRST
  10941. case XPATH_OP_FILTER:
  10942. total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
  10943. break;
  10944. #endif
  10945. default:
  10946. total += xmlXPathCompOpEval(ctxt, op);
  10947. break;
  10948. }
  10949. ctxt->context->depth -= 1;
  10950. return(total);
  10951. }
  10952. /**
  10953. * xmlXPathCompOpEvalLast:
  10954. * @ctxt: the XPath parser context with the compiled expression
  10955. * @op: an XPath compiled operation
  10956. * @last: the last elem found so far
  10957. *
  10958. * Evaluate the Precompiled XPath operation searching only the last
  10959. * element in document order
  10960. *
  10961. * Returns the number of nodes traversed
  10962. */
  10963. static int
  10964. xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
  10965. xmlNodePtr * last)
  10966. {
  10967. int total = 0, cur;
  10968. xmlXPathCompExprPtr comp;
  10969. xmlXPathObjectPtr arg1, arg2;
  10970. CHECK_ERROR0;
  10971. if (OP_LIMIT_EXCEEDED(ctxt, 1))
  10972. return(0);
  10973. if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
  10974. XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
  10975. ctxt->context->depth += 1;
  10976. comp = ctxt->comp;
  10977. switch (op->op) {
  10978. case XPATH_OP_END:
  10979. break;
  10980. case XPATH_OP_UNION:
  10981. total =
  10982. xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
  10983. CHECK_ERROR0;
  10984. if ((ctxt->value != NULL)
  10985. && (ctxt->value->type == XPATH_NODESET)
  10986. && (ctxt->value->nodesetval != NULL)
  10987. && (ctxt->value->nodesetval->nodeNr >= 1)) {
  10988. /*
  10989. * limit tree traversing to first node in the result
  10990. */
  10991. if (ctxt->value->nodesetval->nodeNr > 1)
  10992. xmlXPathNodeSetSort(ctxt->value->nodesetval);
  10993. *last =
  10994. ctxt->value->nodesetval->nodeTab[ctxt->value->
  10995. nodesetval->nodeNr -
  10996. 1];
  10997. }
  10998. cur =
  10999. xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
  11000. CHECK_ERROR0;
  11001. if ((ctxt->value != NULL)
  11002. && (ctxt->value->type == XPATH_NODESET)
  11003. && (ctxt->value->nodesetval != NULL)
  11004. && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
  11005. }
  11006. arg2 = valuePop(ctxt);
  11007. arg1 = valuePop(ctxt);
  11008. if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
  11009. (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
  11010. xmlXPathReleaseObject(ctxt->context, arg1);
  11011. xmlXPathReleaseObject(ctxt->context, arg2);
  11012. XP_ERROR0(XPATH_INVALID_TYPE);
  11013. }
  11014. if ((ctxt->context->opLimit != 0) &&
  11015. (((arg1->nodesetval != NULL) &&
  11016. (xmlXPathCheckOpLimit(ctxt,
  11017. arg1->nodesetval->nodeNr) < 0)) ||
  11018. ((arg2->nodesetval != NULL) &&
  11019. (xmlXPathCheckOpLimit(ctxt,
  11020. arg2->nodesetval->nodeNr) < 0)))) {
  11021. xmlXPathReleaseObject(ctxt->context, arg1);
  11022. xmlXPathReleaseObject(ctxt->context, arg2);
  11023. break;
  11024. }
  11025. /* TODO: Check memory error. */
  11026. arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
  11027. arg2->nodesetval);
  11028. valuePush(ctxt, arg1);
  11029. xmlXPathReleaseObject(ctxt->context, arg2);
  11030. /* optimizer */
  11031. if (total > cur)
  11032. xmlXPathCompSwap(op);
  11033. total += cur;
  11034. break;
  11035. case XPATH_OP_ROOT:
  11036. xmlXPathRoot(ctxt);
  11037. break;
  11038. case XPATH_OP_NODE:
  11039. if (op->ch1 != -1)
  11040. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11041. CHECK_ERROR0;
  11042. if (op->ch2 != -1)
  11043. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  11044. CHECK_ERROR0;
  11045. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  11046. ctxt->context->node));
  11047. break;
  11048. case XPATH_OP_COLLECT:{
  11049. if (op->ch1 == -1)
  11050. break;
  11051. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11052. CHECK_ERROR0;
  11053. total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
  11054. break;
  11055. }
  11056. case XPATH_OP_VALUE:
  11057. valuePush(ctxt,
  11058. xmlXPathCacheObjectCopy(ctxt->context,
  11059. (xmlXPathObjectPtr) op->value4));
  11060. break;
  11061. case XPATH_OP_SORT:
  11062. if (op->ch1 != -1)
  11063. total +=
  11064. xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
  11065. last);
  11066. CHECK_ERROR0;
  11067. if ((ctxt->value != NULL)
  11068. && (ctxt->value->type == XPATH_NODESET)
  11069. && (ctxt->value->nodesetval != NULL)
  11070. && (ctxt->value->nodesetval->nodeNr > 1))
  11071. xmlXPathNodeSetSort(ctxt->value->nodesetval);
  11072. break;
  11073. default:
  11074. total += xmlXPathCompOpEval(ctxt, op);
  11075. break;
  11076. }
  11077. ctxt->context->depth -= 1;
  11078. return (total);
  11079. }
  11080. #ifdef XP_OPTIMIZED_FILTER_FIRST
  11081. static int
  11082. xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
  11083. xmlXPathStepOpPtr op, xmlNodePtr * first)
  11084. {
  11085. int total = 0;
  11086. xmlXPathCompExprPtr comp;
  11087. xmlXPathObjectPtr obj;
  11088. xmlNodeSetPtr set;
  11089. CHECK_ERROR0;
  11090. comp = ctxt->comp;
  11091. /*
  11092. * Optimization for ()[last()] selection i.e. the last elem
  11093. */
  11094. if ((op->ch1 != -1) && (op->ch2 != -1) &&
  11095. (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
  11096. (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
  11097. int f = comp->steps[op->ch2].ch1;
  11098. if ((f != -1) &&
  11099. (comp->steps[f].op == XPATH_OP_FUNCTION) &&
  11100. (comp->steps[f].value5 == NULL) &&
  11101. (comp->steps[f].value == 0) &&
  11102. (comp->steps[f].value4 != NULL) &&
  11103. (xmlStrEqual
  11104. (comp->steps[f].value4, BAD_CAST "last"))) {
  11105. xmlNodePtr last = NULL;
  11106. total +=
  11107. xmlXPathCompOpEvalLast(ctxt,
  11108. &comp->steps[op->ch1],
  11109. &last);
  11110. CHECK_ERROR0;
  11111. /*
  11112. * The nodeset should be in document order,
  11113. * Keep only the last value
  11114. */
  11115. if ((ctxt->value != NULL) &&
  11116. (ctxt->value->type == XPATH_NODESET) &&
  11117. (ctxt->value->nodesetval != NULL) &&
  11118. (ctxt->value->nodesetval->nodeTab != NULL) &&
  11119. (ctxt->value->nodesetval->nodeNr > 1)) {
  11120. xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
  11121. *first = *(ctxt->value->nodesetval->nodeTab);
  11122. }
  11123. return (total);
  11124. }
  11125. }
  11126. if (op->ch1 != -1)
  11127. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11128. CHECK_ERROR0;
  11129. if (op->ch2 == -1)
  11130. return (total);
  11131. if (ctxt->value == NULL)
  11132. return (total);
  11133. #ifdef LIBXML_XPTR_LOCS_ENABLED
  11134. /*
  11135. * Hum are we filtering the result of an XPointer expression
  11136. */
  11137. if (ctxt->value->type == XPATH_LOCATIONSET) {
  11138. xmlLocationSetPtr locset = ctxt->value->user;
  11139. if (locset != NULL) {
  11140. xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
  11141. if (locset->locNr > 0)
  11142. *first = (xmlNodePtr) locset->locTab[0]->user;
  11143. }
  11144. return (total);
  11145. }
  11146. #endif /* LIBXML_XPTR_LOCS_ENABLED */
  11147. /*
  11148. * In case of errors, xmlXPathNodeSetFilter can pop additional nodes from
  11149. * the stack. We have to temporarily remove the nodeset object from the
  11150. * stack to avoid freeing it prematurely.
  11151. */
  11152. CHECK_TYPE0(XPATH_NODESET);
  11153. obj = valuePop(ctxt);
  11154. set = obj->nodesetval;
  11155. if (set != NULL) {
  11156. xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
  11157. if (set->nodeNr > 0)
  11158. *first = set->nodeTab[0];
  11159. }
  11160. valuePush(ctxt, obj);
  11161. return (total);
  11162. }
  11163. #endif /* XP_OPTIMIZED_FILTER_FIRST */
  11164. /**
  11165. * xmlXPathCompOpEval:
  11166. * @ctxt: the XPath parser context with the compiled expression
  11167. * @op: an XPath compiled operation
  11168. *
  11169. * Evaluate the Precompiled XPath operation
  11170. * Returns the number of nodes traversed
  11171. */
  11172. static int
  11173. xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
  11174. {
  11175. int total = 0;
  11176. int equal, ret;
  11177. xmlXPathCompExprPtr comp;
  11178. xmlXPathObjectPtr arg1, arg2;
  11179. CHECK_ERROR0;
  11180. if (OP_LIMIT_EXCEEDED(ctxt, 1))
  11181. return(0);
  11182. if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
  11183. XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
  11184. ctxt->context->depth += 1;
  11185. comp = ctxt->comp;
  11186. switch (op->op) {
  11187. case XPATH_OP_END:
  11188. break;
  11189. case XPATH_OP_AND:
  11190. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11191. CHECK_ERROR0;
  11192. xmlXPathBooleanFunction(ctxt, 1);
  11193. if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
  11194. break;
  11195. arg2 = valuePop(ctxt);
  11196. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  11197. if (ctxt->error) {
  11198. xmlXPathFreeObject(arg2);
  11199. break;
  11200. }
  11201. xmlXPathBooleanFunction(ctxt, 1);
  11202. if (ctxt->value != NULL)
  11203. ctxt->value->boolval &= arg2->boolval;
  11204. xmlXPathReleaseObject(ctxt->context, arg2);
  11205. break;
  11206. case XPATH_OP_OR:
  11207. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11208. CHECK_ERROR0;
  11209. xmlXPathBooleanFunction(ctxt, 1);
  11210. if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
  11211. break;
  11212. arg2 = valuePop(ctxt);
  11213. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  11214. if (ctxt->error) {
  11215. xmlXPathFreeObject(arg2);
  11216. break;
  11217. }
  11218. xmlXPathBooleanFunction(ctxt, 1);
  11219. if (ctxt->value != NULL)
  11220. ctxt->value->boolval |= arg2->boolval;
  11221. xmlXPathReleaseObject(ctxt->context, arg2);
  11222. break;
  11223. case XPATH_OP_EQUAL:
  11224. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11225. CHECK_ERROR0;
  11226. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  11227. CHECK_ERROR0;
  11228. if (op->value)
  11229. equal = xmlXPathEqualValues(ctxt);
  11230. else
  11231. equal = xmlXPathNotEqualValues(ctxt);
  11232. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
  11233. break;
  11234. case XPATH_OP_CMP:
  11235. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11236. CHECK_ERROR0;
  11237. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  11238. CHECK_ERROR0;
  11239. ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
  11240. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
  11241. break;
  11242. case XPATH_OP_PLUS:
  11243. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11244. CHECK_ERROR0;
  11245. if (op->ch2 != -1) {
  11246. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  11247. }
  11248. CHECK_ERROR0;
  11249. if (op->value == 0)
  11250. xmlXPathSubValues(ctxt);
  11251. else if (op->value == 1)
  11252. xmlXPathAddValues(ctxt);
  11253. else if (op->value == 2)
  11254. xmlXPathValueFlipSign(ctxt);
  11255. else if (op->value == 3) {
  11256. CAST_TO_NUMBER;
  11257. CHECK_TYPE0(XPATH_NUMBER);
  11258. }
  11259. break;
  11260. case XPATH_OP_MULT:
  11261. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11262. CHECK_ERROR0;
  11263. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  11264. CHECK_ERROR0;
  11265. if (op->value == 0)
  11266. xmlXPathMultValues(ctxt);
  11267. else if (op->value == 1)
  11268. xmlXPathDivValues(ctxt);
  11269. else if (op->value == 2)
  11270. xmlXPathModValues(ctxt);
  11271. break;
  11272. case XPATH_OP_UNION:
  11273. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11274. CHECK_ERROR0;
  11275. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  11276. CHECK_ERROR0;
  11277. arg2 = valuePop(ctxt);
  11278. arg1 = valuePop(ctxt);
  11279. if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
  11280. (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
  11281. xmlXPathReleaseObject(ctxt->context, arg1);
  11282. xmlXPathReleaseObject(ctxt->context, arg2);
  11283. XP_ERROR0(XPATH_INVALID_TYPE);
  11284. }
  11285. if ((ctxt->context->opLimit != 0) &&
  11286. (((arg1->nodesetval != NULL) &&
  11287. (xmlXPathCheckOpLimit(ctxt,
  11288. arg1->nodesetval->nodeNr) < 0)) ||
  11289. ((arg2->nodesetval != NULL) &&
  11290. (xmlXPathCheckOpLimit(ctxt,
  11291. arg2->nodesetval->nodeNr) < 0)))) {
  11292. xmlXPathReleaseObject(ctxt->context, arg1);
  11293. xmlXPathReleaseObject(ctxt->context, arg2);
  11294. break;
  11295. }
  11296. if ((arg1->nodesetval == NULL) ||
  11297. ((arg2->nodesetval != NULL) &&
  11298. (arg2->nodesetval->nodeNr != 0)))
  11299. {
  11300. /* TODO: Check memory error. */
  11301. arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
  11302. arg2->nodesetval);
  11303. }
  11304. valuePush(ctxt, arg1);
  11305. xmlXPathReleaseObject(ctxt->context, arg2);
  11306. break;
  11307. case XPATH_OP_ROOT:
  11308. xmlXPathRoot(ctxt);
  11309. break;
  11310. case XPATH_OP_NODE:
  11311. if (op->ch1 != -1)
  11312. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11313. CHECK_ERROR0;
  11314. if (op->ch2 != -1)
  11315. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  11316. CHECK_ERROR0;
  11317. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  11318. ctxt->context->node));
  11319. break;
  11320. case XPATH_OP_COLLECT:{
  11321. if (op->ch1 == -1)
  11322. break;
  11323. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11324. CHECK_ERROR0;
  11325. total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
  11326. break;
  11327. }
  11328. case XPATH_OP_VALUE:
  11329. valuePush(ctxt,
  11330. xmlXPathCacheObjectCopy(ctxt->context,
  11331. (xmlXPathObjectPtr) op->value4));
  11332. break;
  11333. case XPATH_OP_VARIABLE:{
  11334. xmlXPathObjectPtr val;
  11335. if (op->ch1 != -1)
  11336. total +=
  11337. xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11338. if (op->value5 == NULL) {
  11339. val = xmlXPathVariableLookup(ctxt->context, op->value4);
  11340. if (val == NULL)
  11341. XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
  11342. valuePush(ctxt, val);
  11343. } else {
  11344. const xmlChar *URI;
  11345. URI = xmlXPathNsLookup(ctxt->context, op->value5);
  11346. if (URI == NULL) {
  11347. xmlGenericError(xmlGenericErrorContext,
  11348. "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
  11349. (char *) op->value4, (char *)op->value5);
  11350. ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
  11351. break;
  11352. }
  11353. val = xmlXPathVariableLookupNS(ctxt->context,
  11354. op->value4, URI);
  11355. if (val == NULL)
  11356. XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
  11357. valuePush(ctxt, val);
  11358. }
  11359. break;
  11360. }
  11361. case XPATH_OP_FUNCTION:{
  11362. xmlXPathFunction func;
  11363. const xmlChar *oldFunc, *oldFuncURI;
  11364. int i;
  11365. int frame;
  11366. frame = ctxt->valueNr;
  11367. if (op->ch1 != -1) {
  11368. total +=
  11369. xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11370. if (ctxt->error != XPATH_EXPRESSION_OK)
  11371. break;
  11372. }
  11373. if (ctxt->valueNr < frame + op->value) {
  11374. xmlGenericError(xmlGenericErrorContext,
  11375. "xmlXPathCompOpEval: parameter error\n");
  11376. ctxt->error = XPATH_INVALID_OPERAND;
  11377. break;
  11378. }
  11379. for (i = 0; i < op->value; i++) {
  11380. if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
  11381. xmlGenericError(xmlGenericErrorContext,
  11382. "xmlXPathCompOpEval: parameter error\n");
  11383. ctxt->error = XPATH_INVALID_OPERAND;
  11384. break;
  11385. }
  11386. }
  11387. if (op->cache != NULL)
  11388. func = op->cache;
  11389. else {
  11390. const xmlChar *URI = NULL;
  11391. if (op->value5 == NULL)
  11392. func =
  11393. xmlXPathFunctionLookup(ctxt->context,
  11394. op->value4);
  11395. else {
  11396. URI = xmlXPathNsLookup(ctxt->context, op->value5);
  11397. if (URI == NULL) {
  11398. xmlGenericError(xmlGenericErrorContext,
  11399. "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
  11400. (char *)op->value4, (char *)op->value5);
  11401. ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
  11402. break;
  11403. }
  11404. func = xmlXPathFunctionLookupNS(ctxt->context,
  11405. op->value4, URI);
  11406. }
  11407. if (func == NULL) {
  11408. xmlGenericError(xmlGenericErrorContext,
  11409. "xmlXPathCompOpEval: function %s not found\n",
  11410. (char *)op->value4);
  11411. XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
  11412. }
  11413. op->cache = func;
  11414. op->cacheURI = (void *) URI;
  11415. }
  11416. oldFunc = ctxt->context->function;
  11417. oldFuncURI = ctxt->context->functionURI;
  11418. ctxt->context->function = op->value4;
  11419. ctxt->context->functionURI = op->cacheURI;
  11420. func(ctxt, op->value);
  11421. ctxt->context->function = oldFunc;
  11422. ctxt->context->functionURI = oldFuncURI;
  11423. if ((ctxt->error == XPATH_EXPRESSION_OK) &&
  11424. (ctxt->valueNr != frame + 1))
  11425. XP_ERROR0(XPATH_STACK_ERROR);
  11426. break;
  11427. }
  11428. case XPATH_OP_ARG:
  11429. if (op->ch1 != -1) {
  11430. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11431. CHECK_ERROR0;
  11432. }
  11433. if (op->ch2 != -1) {
  11434. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  11435. CHECK_ERROR0;
  11436. }
  11437. break;
  11438. case XPATH_OP_PREDICATE:
  11439. case XPATH_OP_FILTER:{
  11440. xmlXPathObjectPtr obj;
  11441. xmlNodeSetPtr set;
  11442. /*
  11443. * Optimization for ()[1] selection i.e. the first elem
  11444. */
  11445. if ((op->ch1 != -1) && (op->ch2 != -1) &&
  11446. #ifdef XP_OPTIMIZED_FILTER_FIRST
  11447. /*
  11448. * FILTER TODO: Can we assume that the inner processing
  11449. * will result in an ordered list if we have an
  11450. * XPATH_OP_FILTER?
  11451. * What about an additional field or flag on
  11452. * xmlXPathObject like @sorted ? This way we wouldn't need
  11453. * to assume anything, so it would be more robust and
  11454. * easier to optimize.
  11455. */
  11456. ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
  11457. (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
  11458. #else
  11459. (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
  11460. #endif
  11461. (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
  11462. xmlXPathObjectPtr val;
  11463. val = comp->steps[op->ch2].value4;
  11464. if ((val != NULL) && (val->type == XPATH_NUMBER) &&
  11465. (val->floatval == 1.0)) {
  11466. xmlNodePtr first = NULL;
  11467. total +=
  11468. xmlXPathCompOpEvalFirst(ctxt,
  11469. &comp->steps[op->ch1],
  11470. &first);
  11471. CHECK_ERROR0;
  11472. /*
  11473. * The nodeset should be in document order,
  11474. * Keep only the first value
  11475. */
  11476. if ((ctxt->value != NULL) &&
  11477. (ctxt->value->type == XPATH_NODESET) &&
  11478. (ctxt->value->nodesetval != NULL) &&
  11479. (ctxt->value->nodesetval->nodeNr > 1))
  11480. xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
  11481. 1, 1);
  11482. break;
  11483. }
  11484. }
  11485. /*
  11486. * Optimization for ()[last()] selection i.e. the last elem
  11487. */
  11488. if ((op->ch1 != -1) && (op->ch2 != -1) &&
  11489. (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
  11490. (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
  11491. int f = comp->steps[op->ch2].ch1;
  11492. if ((f != -1) &&
  11493. (comp->steps[f].op == XPATH_OP_FUNCTION) &&
  11494. (comp->steps[f].value5 == NULL) &&
  11495. (comp->steps[f].value == 0) &&
  11496. (comp->steps[f].value4 != NULL) &&
  11497. (xmlStrEqual
  11498. (comp->steps[f].value4, BAD_CAST "last"))) {
  11499. xmlNodePtr last = NULL;
  11500. total +=
  11501. xmlXPathCompOpEvalLast(ctxt,
  11502. &comp->steps[op->ch1],
  11503. &last);
  11504. CHECK_ERROR0;
  11505. /*
  11506. * The nodeset should be in document order,
  11507. * Keep only the last value
  11508. */
  11509. if ((ctxt->value != NULL) &&
  11510. (ctxt->value->type == XPATH_NODESET) &&
  11511. (ctxt->value->nodesetval != NULL) &&
  11512. (ctxt->value->nodesetval->nodeTab != NULL) &&
  11513. (ctxt->value->nodesetval->nodeNr > 1))
  11514. xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
  11515. break;
  11516. }
  11517. }
  11518. /*
  11519. * Process inner predicates first.
  11520. * Example "index[parent::book][1]":
  11521. * ...
  11522. * PREDICATE <-- we are here "[1]"
  11523. * PREDICATE <-- process "[parent::book]" first
  11524. * SORT
  11525. * COLLECT 'parent' 'name' 'node' book
  11526. * NODE
  11527. * ELEM Object is a number : 1
  11528. */
  11529. if (op->ch1 != -1)
  11530. total +=
  11531. xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11532. CHECK_ERROR0;
  11533. if (op->ch2 == -1)
  11534. break;
  11535. if (ctxt->value == NULL)
  11536. break;
  11537. #ifdef LIBXML_XPTR_LOCS_ENABLED
  11538. /*
  11539. * Hum are we filtering the result of an XPointer expression
  11540. */
  11541. if (ctxt->value->type == XPATH_LOCATIONSET) {
  11542. xmlLocationSetPtr locset = ctxt->value->user;
  11543. xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
  11544. 1, locset->locNr);
  11545. break;
  11546. }
  11547. #endif /* LIBXML_XPTR_LOCS_ENABLED */
  11548. /*
  11549. * In case of errors, xmlXPathNodeSetFilter can pop additional
  11550. * nodes from the stack. We have to temporarily remove the
  11551. * nodeset object from the stack to avoid freeing it
  11552. * prematurely.
  11553. */
  11554. CHECK_TYPE0(XPATH_NODESET);
  11555. obj = valuePop(ctxt);
  11556. set = obj->nodesetval;
  11557. if (set != NULL)
  11558. xmlXPathNodeSetFilter(ctxt, set, op->ch2,
  11559. 1, set->nodeNr, 1);
  11560. valuePush(ctxt, obj);
  11561. break;
  11562. }
  11563. case XPATH_OP_SORT:
  11564. if (op->ch1 != -1)
  11565. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11566. CHECK_ERROR0;
  11567. if ((ctxt->value != NULL) &&
  11568. (ctxt->value->type == XPATH_NODESET) &&
  11569. (ctxt->value->nodesetval != NULL) &&
  11570. (ctxt->value->nodesetval->nodeNr > 1))
  11571. {
  11572. xmlXPathNodeSetSort(ctxt->value->nodesetval);
  11573. }
  11574. break;
  11575. #ifdef LIBXML_XPTR_LOCS_ENABLED
  11576. case XPATH_OP_RANGETO:{
  11577. xmlXPathObjectPtr range;
  11578. xmlXPathObjectPtr res, obj;
  11579. xmlXPathObjectPtr tmp;
  11580. xmlLocationSetPtr newlocset = NULL;
  11581. xmlLocationSetPtr oldlocset;
  11582. xmlNodeSetPtr oldset;
  11583. xmlNodePtr oldnode = ctxt->context->node;
  11584. int oldcs = ctxt->context->contextSize;
  11585. int oldpp = ctxt->context->proximityPosition;
  11586. int i, j;
  11587. if (op->ch1 != -1) {
  11588. total +=
  11589. xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11590. CHECK_ERROR0;
  11591. }
  11592. if (ctxt->value == NULL) {
  11593. XP_ERROR0(XPATH_INVALID_OPERAND);
  11594. }
  11595. if (op->ch2 == -1)
  11596. break;
  11597. if (ctxt->value->type == XPATH_LOCATIONSET) {
  11598. /*
  11599. * Extract the old locset, and then evaluate the result of the
  11600. * expression for all the element in the locset. use it to grow
  11601. * up a new locset.
  11602. */
  11603. CHECK_TYPE0(XPATH_LOCATIONSET);
  11604. if ((ctxt->value->user == NULL) ||
  11605. (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
  11606. break;
  11607. obj = valuePop(ctxt);
  11608. oldlocset = obj->user;
  11609. newlocset = xmlXPtrLocationSetCreate(NULL);
  11610. for (i = 0; i < oldlocset->locNr; i++) {
  11611. /*
  11612. * Run the evaluation with a node list made of a
  11613. * single item in the nodelocset.
  11614. */
  11615. ctxt->context->node = oldlocset->locTab[i]->user;
  11616. ctxt->context->contextSize = oldlocset->locNr;
  11617. ctxt->context->proximityPosition = i + 1;
  11618. tmp = xmlXPathCacheNewNodeSet(ctxt->context,
  11619. ctxt->context->node);
  11620. valuePush(ctxt, tmp);
  11621. if (op->ch2 != -1)
  11622. total +=
  11623. xmlXPathCompOpEval(ctxt,
  11624. &comp->steps[op->ch2]);
  11625. if (ctxt->error != XPATH_EXPRESSION_OK) {
  11626. xmlXPtrFreeLocationSet(newlocset);
  11627. goto rangeto_error;
  11628. }
  11629. res = valuePop(ctxt);
  11630. if (res->type == XPATH_LOCATIONSET) {
  11631. xmlLocationSetPtr rloc =
  11632. (xmlLocationSetPtr)res->user;
  11633. for (j=0; j<rloc->locNr; j++) {
  11634. range = xmlXPtrNewRange(
  11635. oldlocset->locTab[i]->user,
  11636. oldlocset->locTab[i]->index,
  11637. rloc->locTab[j]->user2,
  11638. rloc->locTab[j]->index2);
  11639. if (range != NULL) {
  11640. xmlXPtrLocationSetAdd(newlocset, range);
  11641. }
  11642. }
  11643. } else {
  11644. range = xmlXPtrNewRangeNodeObject(
  11645. (xmlNodePtr)oldlocset->locTab[i]->user, res);
  11646. if (range != NULL) {
  11647. xmlXPtrLocationSetAdd(newlocset,range);
  11648. }
  11649. }
  11650. /*
  11651. * Cleanup
  11652. */
  11653. if (res != NULL) {
  11654. xmlXPathReleaseObject(ctxt->context, res);
  11655. }
  11656. if (ctxt->value == tmp) {
  11657. res = valuePop(ctxt);
  11658. xmlXPathReleaseObject(ctxt->context, res);
  11659. }
  11660. }
  11661. } else { /* Not a location set */
  11662. CHECK_TYPE0(XPATH_NODESET);
  11663. obj = valuePop(ctxt);
  11664. oldset = obj->nodesetval;
  11665. newlocset = xmlXPtrLocationSetCreate(NULL);
  11666. if (oldset != NULL) {
  11667. for (i = 0; i < oldset->nodeNr; i++) {
  11668. /*
  11669. * Run the evaluation with a node list made of a single item
  11670. * in the nodeset.
  11671. */
  11672. ctxt->context->node = oldset->nodeTab[i];
  11673. /*
  11674. * OPTIMIZE TODO: Avoid recreation for every iteration.
  11675. */
  11676. tmp = xmlXPathCacheNewNodeSet(ctxt->context,
  11677. ctxt->context->node);
  11678. valuePush(ctxt, tmp);
  11679. if (op->ch2 != -1)
  11680. total +=
  11681. xmlXPathCompOpEval(ctxt,
  11682. &comp->steps[op->ch2]);
  11683. if (ctxt->error != XPATH_EXPRESSION_OK) {
  11684. xmlXPtrFreeLocationSet(newlocset);
  11685. goto rangeto_error;
  11686. }
  11687. res = valuePop(ctxt);
  11688. range =
  11689. xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
  11690. res);
  11691. if (range != NULL) {
  11692. xmlXPtrLocationSetAdd(newlocset, range);
  11693. }
  11694. /*
  11695. * Cleanup
  11696. */
  11697. if (res != NULL) {
  11698. xmlXPathReleaseObject(ctxt->context, res);
  11699. }
  11700. if (ctxt->value == tmp) {
  11701. res = valuePop(ctxt);
  11702. xmlXPathReleaseObject(ctxt->context, res);
  11703. }
  11704. }
  11705. }
  11706. }
  11707. /*
  11708. * The result is used as the new evaluation set.
  11709. */
  11710. valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
  11711. rangeto_error:
  11712. xmlXPathReleaseObject(ctxt->context, obj);
  11713. ctxt->context->node = oldnode;
  11714. ctxt->context->contextSize = oldcs;
  11715. ctxt->context->proximityPosition = oldpp;
  11716. break;
  11717. }
  11718. #endif /* LIBXML_XPTR_LOCS_ENABLED */
  11719. default:
  11720. xmlGenericError(xmlGenericErrorContext,
  11721. "XPath: unknown precompiled operation %d\n", op->op);
  11722. ctxt->error = XPATH_INVALID_OPERAND;
  11723. break;
  11724. }
  11725. ctxt->context->depth -= 1;
  11726. return (total);
  11727. }
  11728. /**
  11729. * xmlXPathCompOpEvalToBoolean:
  11730. * @ctxt: the XPath parser context
  11731. *
  11732. * Evaluates if the expression evaluates to true.
  11733. *
  11734. * Returns 1 if true, 0 if false and -1 on API or internal errors.
  11735. */
  11736. static int
  11737. xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
  11738. xmlXPathStepOpPtr op,
  11739. int isPredicate)
  11740. {
  11741. xmlXPathObjectPtr resObj = NULL;
  11742. start:
  11743. if (OP_LIMIT_EXCEEDED(ctxt, 1))
  11744. return(0);
  11745. /* comp = ctxt->comp; */
  11746. switch (op->op) {
  11747. case XPATH_OP_END:
  11748. return (0);
  11749. case XPATH_OP_VALUE:
  11750. resObj = (xmlXPathObjectPtr) op->value4;
  11751. if (isPredicate)
  11752. return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
  11753. return(xmlXPathCastToBoolean(resObj));
  11754. case XPATH_OP_SORT:
  11755. /*
  11756. * We don't need sorting for boolean results. Skip this one.
  11757. */
  11758. if (op->ch1 != -1) {
  11759. op = &ctxt->comp->steps[op->ch1];
  11760. goto start;
  11761. }
  11762. return(0);
  11763. case XPATH_OP_COLLECT:
  11764. if (op->ch1 == -1)
  11765. return(0);
  11766. xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
  11767. if (ctxt->error != XPATH_EXPRESSION_OK)
  11768. return(-1);
  11769. xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
  11770. if (ctxt->error != XPATH_EXPRESSION_OK)
  11771. return(-1);
  11772. resObj = valuePop(ctxt);
  11773. if (resObj == NULL)
  11774. return(-1);
  11775. break;
  11776. default:
  11777. /*
  11778. * Fallback to call xmlXPathCompOpEval().
  11779. */
  11780. xmlXPathCompOpEval(ctxt, op);
  11781. if (ctxt->error != XPATH_EXPRESSION_OK)
  11782. return(-1);
  11783. resObj = valuePop(ctxt);
  11784. if (resObj == NULL)
  11785. return(-1);
  11786. break;
  11787. }
  11788. if (resObj) {
  11789. int res;
  11790. if (resObj->type == XPATH_BOOLEAN) {
  11791. res = resObj->boolval;
  11792. } else if (isPredicate) {
  11793. /*
  11794. * For predicates a result of type "number" is handled
  11795. * differently:
  11796. * SPEC XPath 1.0:
  11797. * "If the result is a number, the result will be converted
  11798. * to true if the number is equal to the context position
  11799. * and will be converted to false otherwise;"
  11800. */
  11801. res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
  11802. } else {
  11803. res = xmlXPathCastToBoolean(resObj);
  11804. }
  11805. xmlXPathReleaseObject(ctxt->context, resObj);
  11806. return(res);
  11807. }
  11808. return(0);
  11809. }
  11810. #ifdef XPATH_STREAMING
  11811. /**
  11812. * xmlXPathRunStreamEval:
  11813. * @ctxt: the XPath parser context with the compiled expression
  11814. *
  11815. * Evaluate the Precompiled Streamable XPath expression in the given context.
  11816. */
  11817. static int
  11818. xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
  11819. xmlXPathObjectPtr *resultSeq, int toBool)
  11820. {
  11821. int max_depth, min_depth;
  11822. int from_root;
  11823. int ret, depth;
  11824. int eval_all_nodes;
  11825. xmlNodePtr cur = NULL, limit = NULL;
  11826. xmlStreamCtxtPtr patstream = NULL;
  11827. if ((ctxt == NULL) || (comp == NULL))
  11828. return(-1);
  11829. max_depth = xmlPatternMaxDepth(comp);
  11830. if (max_depth == -1)
  11831. return(-1);
  11832. if (max_depth == -2)
  11833. max_depth = 10000;
  11834. min_depth = xmlPatternMinDepth(comp);
  11835. if (min_depth == -1)
  11836. return(-1);
  11837. from_root = xmlPatternFromRoot(comp);
  11838. if (from_root < 0)
  11839. return(-1);
  11840. #if 0
  11841. printf("stream eval: depth %d from root %d\n", max_depth, from_root);
  11842. #endif
  11843. if (! toBool) {
  11844. if (resultSeq == NULL)
  11845. return(-1);
  11846. *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
  11847. if (*resultSeq == NULL)
  11848. return(-1);
  11849. }
  11850. /*
  11851. * handle the special cases of "/" amd "." being matched
  11852. */
  11853. if (min_depth == 0) {
  11854. if (from_root) {
  11855. /* Select "/" */
  11856. if (toBool)
  11857. return(1);
  11858. /* TODO: Check memory error. */
  11859. xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
  11860. (xmlNodePtr) ctxt->doc);
  11861. } else {
  11862. /* Select "self::node()" */
  11863. if (toBool)
  11864. return(1);
  11865. /* TODO: Check memory error. */
  11866. xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
  11867. }
  11868. }
  11869. if (max_depth == 0) {
  11870. return(0);
  11871. }
  11872. if (from_root) {
  11873. cur = (xmlNodePtr)ctxt->doc;
  11874. } else if (ctxt->node != NULL) {
  11875. switch (ctxt->node->type) {
  11876. case XML_ELEMENT_NODE:
  11877. case XML_DOCUMENT_NODE:
  11878. case XML_DOCUMENT_FRAG_NODE:
  11879. case XML_HTML_DOCUMENT_NODE:
  11880. cur = ctxt->node;
  11881. break;
  11882. case XML_ATTRIBUTE_NODE:
  11883. case XML_TEXT_NODE:
  11884. case XML_CDATA_SECTION_NODE:
  11885. case XML_ENTITY_REF_NODE:
  11886. case XML_ENTITY_NODE:
  11887. case XML_PI_NODE:
  11888. case XML_COMMENT_NODE:
  11889. case XML_NOTATION_NODE:
  11890. case XML_DTD_NODE:
  11891. case XML_DOCUMENT_TYPE_NODE:
  11892. case XML_ELEMENT_DECL:
  11893. case XML_ATTRIBUTE_DECL:
  11894. case XML_ENTITY_DECL:
  11895. case XML_NAMESPACE_DECL:
  11896. case XML_XINCLUDE_START:
  11897. case XML_XINCLUDE_END:
  11898. break;
  11899. }
  11900. limit = cur;
  11901. }
  11902. if (cur == NULL) {
  11903. return(0);
  11904. }
  11905. patstream = xmlPatternGetStreamCtxt(comp);
  11906. if (patstream == NULL) {
  11907. /*
  11908. * QUESTION TODO: Is this an error?
  11909. */
  11910. return(0);
  11911. }
  11912. eval_all_nodes = xmlStreamWantsAnyNode(patstream);
  11913. if (from_root) {
  11914. ret = xmlStreamPush(patstream, NULL, NULL);
  11915. if (ret < 0) {
  11916. } else if (ret == 1) {
  11917. if (toBool)
  11918. goto return_1;
  11919. /* TODO: Check memory error. */
  11920. xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
  11921. }
  11922. }
  11923. depth = 0;
  11924. goto scan_children;
  11925. next_node:
  11926. do {
  11927. if (ctxt->opLimit != 0) {
  11928. if (ctxt->opCount >= ctxt->opLimit) {
  11929. xmlGenericError(xmlGenericErrorContext,
  11930. "XPath operation limit exceeded\n");
  11931. xmlFreeStreamCtxt(patstream);
  11932. return(-1);
  11933. }
  11934. ctxt->opCount++;
  11935. }
  11936. switch (cur->type) {
  11937. case XML_ELEMENT_NODE:
  11938. case XML_TEXT_NODE:
  11939. case XML_CDATA_SECTION_NODE:
  11940. case XML_COMMENT_NODE:
  11941. case XML_PI_NODE:
  11942. if (cur->type == XML_ELEMENT_NODE) {
  11943. ret = xmlStreamPush(patstream, cur->name,
  11944. (cur->ns ? cur->ns->href : NULL));
  11945. } else if (eval_all_nodes)
  11946. ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
  11947. else
  11948. break;
  11949. if (ret < 0) {
  11950. /* NOP. */
  11951. } else if (ret == 1) {
  11952. if (toBool)
  11953. goto return_1;
  11954. if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
  11955. < 0) {
  11956. ctxt->lastError.domain = XML_FROM_XPATH;
  11957. ctxt->lastError.code = XML_ERR_NO_MEMORY;
  11958. }
  11959. }
  11960. if ((cur->children == NULL) || (depth >= max_depth)) {
  11961. ret = xmlStreamPop(patstream);
  11962. while (cur->next != NULL) {
  11963. cur = cur->next;
  11964. if ((cur->type != XML_ENTITY_DECL) &&
  11965. (cur->type != XML_DTD_NODE))
  11966. goto next_node;
  11967. }
  11968. }
  11969. default:
  11970. break;
  11971. }
  11972. scan_children:
  11973. if (cur->type == XML_NAMESPACE_DECL) break;
  11974. if ((cur->children != NULL) && (depth < max_depth)) {
  11975. /*
  11976. * Do not descend on entities declarations
  11977. */
  11978. if (cur->children->type != XML_ENTITY_DECL) {
  11979. cur = cur->children;
  11980. depth++;
  11981. /*
  11982. * Skip DTDs
  11983. */
  11984. if (cur->type != XML_DTD_NODE)
  11985. continue;
  11986. }
  11987. }
  11988. if (cur == limit)
  11989. break;
  11990. while (cur->next != NULL) {
  11991. cur = cur->next;
  11992. if ((cur->type != XML_ENTITY_DECL) &&
  11993. (cur->type != XML_DTD_NODE))
  11994. goto next_node;
  11995. }
  11996. do {
  11997. cur = cur->parent;
  11998. depth--;
  11999. if ((cur == NULL) || (cur == limit) ||
  12000. (cur->type == XML_DOCUMENT_NODE))
  12001. goto done;
  12002. if (cur->type == XML_ELEMENT_NODE) {
  12003. ret = xmlStreamPop(patstream);
  12004. } else if ((eval_all_nodes) &&
  12005. ((cur->type == XML_TEXT_NODE) ||
  12006. (cur->type == XML_CDATA_SECTION_NODE) ||
  12007. (cur->type == XML_COMMENT_NODE) ||
  12008. (cur->type == XML_PI_NODE)))
  12009. {
  12010. ret = xmlStreamPop(patstream);
  12011. }
  12012. if (cur->next != NULL) {
  12013. cur = cur->next;
  12014. break;
  12015. }
  12016. } while (cur != NULL);
  12017. } while ((cur != NULL) && (depth >= 0));
  12018. done:
  12019. if (patstream)
  12020. xmlFreeStreamCtxt(patstream);
  12021. return(0);
  12022. return_1:
  12023. if (patstream)
  12024. xmlFreeStreamCtxt(patstream);
  12025. return(1);
  12026. }
  12027. #endif /* XPATH_STREAMING */
  12028. /**
  12029. * xmlXPathRunEval:
  12030. * @ctxt: the XPath parser context with the compiled expression
  12031. * @toBool: evaluate to a boolean result
  12032. *
  12033. * Evaluate the Precompiled XPath expression in the given context.
  12034. */
  12035. static int
  12036. xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
  12037. {
  12038. xmlXPathCompExprPtr comp;
  12039. int oldDepth;
  12040. if ((ctxt == NULL) || (ctxt->comp == NULL))
  12041. return(-1);
  12042. if (ctxt->valueTab == NULL) {
  12043. /* Allocate the value stack */
  12044. ctxt->valueTab = (xmlXPathObjectPtr *)
  12045. xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
  12046. if (ctxt->valueTab == NULL) {
  12047. xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
  12048. return(-1);
  12049. }
  12050. ctxt->valueNr = 0;
  12051. ctxt->valueMax = 10;
  12052. ctxt->value = NULL;
  12053. }
  12054. #ifdef XPATH_STREAMING
  12055. if (ctxt->comp->stream) {
  12056. int res;
  12057. if (toBool) {
  12058. /*
  12059. * Evaluation to boolean result.
  12060. */
  12061. res = xmlXPathRunStreamEval(ctxt->context,
  12062. ctxt->comp->stream, NULL, 1);
  12063. if (res != -1)
  12064. return(res);
  12065. } else {
  12066. xmlXPathObjectPtr resObj = NULL;
  12067. /*
  12068. * Evaluation to a sequence.
  12069. */
  12070. res = xmlXPathRunStreamEval(ctxt->context,
  12071. ctxt->comp->stream, &resObj, 0);
  12072. if ((res != -1) && (resObj != NULL)) {
  12073. valuePush(ctxt, resObj);
  12074. return(0);
  12075. }
  12076. if (resObj != NULL)
  12077. xmlXPathReleaseObject(ctxt->context, resObj);
  12078. }
  12079. /*
  12080. * QUESTION TODO: This falls back to normal XPath evaluation
  12081. * if res == -1. Is this intended?
  12082. */
  12083. }
  12084. #endif
  12085. comp = ctxt->comp;
  12086. if (comp->last < 0) {
  12087. xmlGenericError(xmlGenericErrorContext,
  12088. "xmlXPathRunEval: last is less than zero\n");
  12089. return(-1);
  12090. }
  12091. oldDepth = ctxt->context->depth;
  12092. if (toBool)
  12093. return(xmlXPathCompOpEvalToBoolean(ctxt,
  12094. &comp->steps[comp->last], 0));
  12095. else
  12096. xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
  12097. ctxt->context->depth = oldDepth;
  12098. return(0);
  12099. }
  12100. /************************************************************************
  12101. * *
  12102. * Public interfaces *
  12103. * *
  12104. ************************************************************************/
  12105. /**
  12106. * xmlXPathEvalPredicate:
  12107. * @ctxt: the XPath context
  12108. * @res: the Predicate Expression evaluation result
  12109. *
  12110. * Evaluate a predicate result for the current node.
  12111. * A PredicateExpr is evaluated by evaluating the Expr and converting
  12112. * the result to a boolean. If the result is a number, the result will
  12113. * be converted to true if the number is equal to the position of the
  12114. * context node in the context node list (as returned by the position
  12115. * function) and will be converted to false otherwise; if the result
  12116. * is not a number, then the result will be converted as if by a call
  12117. * to the boolean function.
  12118. *
  12119. * Returns 1 if predicate is true, 0 otherwise
  12120. */
  12121. int
  12122. xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
  12123. if ((ctxt == NULL) || (res == NULL)) return(0);
  12124. switch (res->type) {
  12125. case XPATH_BOOLEAN:
  12126. return(res->boolval);
  12127. case XPATH_NUMBER:
  12128. return(res->floatval == ctxt->proximityPosition);
  12129. case XPATH_NODESET:
  12130. case XPATH_XSLT_TREE:
  12131. if (res->nodesetval == NULL)
  12132. return(0);
  12133. return(res->nodesetval->nodeNr != 0);
  12134. case XPATH_STRING:
  12135. return((res->stringval != NULL) &&
  12136. (xmlStrlen(res->stringval) != 0));
  12137. default:
  12138. STRANGE
  12139. }
  12140. return(0);
  12141. }
  12142. /**
  12143. * xmlXPathEvaluatePredicateResult:
  12144. * @ctxt: the XPath Parser context
  12145. * @res: the Predicate Expression evaluation result
  12146. *
  12147. * Evaluate a predicate result for the current node.
  12148. * A PredicateExpr is evaluated by evaluating the Expr and converting
  12149. * the result to a boolean. If the result is a number, the result will
  12150. * be converted to true if the number is equal to the position of the
  12151. * context node in the context node list (as returned by the position
  12152. * function) and will be converted to false otherwise; if the result
  12153. * is not a number, then the result will be converted as if by a call
  12154. * to the boolean function.
  12155. *
  12156. * Returns 1 if predicate is true, 0 otherwise
  12157. */
  12158. int
  12159. xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
  12160. xmlXPathObjectPtr res) {
  12161. if ((ctxt == NULL) || (res == NULL)) return(0);
  12162. switch (res->type) {
  12163. case XPATH_BOOLEAN:
  12164. return(res->boolval);
  12165. case XPATH_NUMBER:
  12166. #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
  12167. return((res->floatval == ctxt->context->proximityPosition) &&
  12168. (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
  12169. #else
  12170. return(res->floatval == ctxt->context->proximityPosition);
  12171. #endif
  12172. case XPATH_NODESET:
  12173. case XPATH_XSLT_TREE:
  12174. if (res->nodesetval == NULL)
  12175. return(0);
  12176. return(res->nodesetval->nodeNr != 0);
  12177. case XPATH_STRING:
  12178. return((res->stringval != NULL) && (res->stringval[0] != 0));
  12179. #ifdef LIBXML_XPTR_LOCS_ENABLED
  12180. case XPATH_LOCATIONSET:{
  12181. xmlLocationSetPtr ptr = res->user;
  12182. if (ptr == NULL)
  12183. return(0);
  12184. return (ptr->locNr != 0);
  12185. }
  12186. #endif
  12187. default:
  12188. STRANGE
  12189. }
  12190. return(0);
  12191. }
  12192. #ifdef XPATH_STREAMING
  12193. /**
  12194. * xmlXPathTryStreamCompile:
  12195. * @ctxt: an XPath context
  12196. * @str: the XPath expression
  12197. *
  12198. * Try to compile the XPath expression as a streamable subset.
  12199. *
  12200. * Returns the compiled expression or NULL if failed to compile.
  12201. */
  12202. static xmlXPathCompExprPtr
  12203. xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
  12204. /*
  12205. * Optimization: use streaming patterns when the XPath expression can
  12206. * be compiled to a stream lookup
  12207. */
  12208. xmlPatternPtr stream;
  12209. xmlXPathCompExprPtr comp;
  12210. xmlDictPtr dict = NULL;
  12211. const xmlChar **namespaces = NULL;
  12212. xmlNsPtr ns;
  12213. int i, j;
  12214. if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
  12215. (!xmlStrchr(str, '@'))) {
  12216. const xmlChar *tmp;
  12217. /*
  12218. * We don't try to handle expressions using the verbose axis
  12219. * specifiers ("::"), just the simplified form at this point.
  12220. * Additionally, if there is no list of namespaces available and
  12221. * there's a ":" in the expression, indicating a prefixed QName,
  12222. * then we won't try to compile either. xmlPatterncompile() needs
  12223. * to have a list of namespaces at compilation time in order to
  12224. * compile prefixed name tests.
  12225. */
  12226. tmp = xmlStrchr(str, ':');
  12227. if ((tmp != NULL) &&
  12228. ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
  12229. return(NULL);
  12230. if (ctxt != NULL) {
  12231. dict = ctxt->dict;
  12232. if (ctxt->nsNr > 0) {
  12233. namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
  12234. if (namespaces == NULL) {
  12235. xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
  12236. return(NULL);
  12237. }
  12238. for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
  12239. ns = ctxt->namespaces[j];
  12240. namespaces[i++] = ns->href;
  12241. namespaces[i++] = ns->prefix;
  12242. }
  12243. namespaces[i++] = NULL;
  12244. namespaces[i] = NULL;
  12245. }
  12246. }
  12247. stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
  12248. if (namespaces != NULL) {
  12249. xmlFree((xmlChar **)namespaces);
  12250. }
  12251. if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
  12252. comp = xmlXPathNewCompExpr();
  12253. if (comp == NULL) {
  12254. xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
  12255. xmlFreePattern(stream);
  12256. return(NULL);
  12257. }
  12258. comp->stream = stream;
  12259. comp->dict = dict;
  12260. if (comp->dict)
  12261. xmlDictReference(comp->dict);
  12262. return(comp);
  12263. }
  12264. xmlFreePattern(stream);
  12265. }
  12266. return(NULL);
  12267. }
  12268. #endif /* XPATH_STREAMING */
  12269. static void
  12270. xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
  12271. xmlXPathStepOpPtr op)
  12272. {
  12273. xmlXPathCompExprPtr comp = pctxt->comp;
  12274. xmlXPathContextPtr ctxt;
  12275. /*
  12276. * Try to rewrite "descendant-or-self::node()/foo" to an optimized
  12277. * internal representation.
  12278. */
  12279. if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
  12280. (op->ch1 != -1) &&
  12281. (op->ch2 == -1 /* no predicate */))
  12282. {
  12283. xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
  12284. if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
  12285. ((xmlXPathAxisVal) prevop->value ==
  12286. AXIS_DESCENDANT_OR_SELF) &&
  12287. (prevop->ch2 == -1) &&
  12288. ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
  12289. ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
  12290. {
  12291. /*
  12292. * This is a "descendant-or-self::node()" without predicates.
  12293. * Try to eliminate it.
  12294. */
  12295. switch ((xmlXPathAxisVal) op->value) {
  12296. case AXIS_CHILD:
  12297. case AXIS_DESCENDANT:
  12298. /*
  12299. * Convert "descendant-or-self::node()/child::" or
  12300. * "descendant-or-self::node()/descendant::" to
  12301. * "descendant::"
  12302. */
  12303. op->ch1 = prevop->ch1;
  12304. op->value = AXIS_DESCENDANT;
  12305. break;
  12306. case AXIS_SELF:
  12307. case AXIS_DESCENDANT_OR_SELF:
  12308. /*
  12309. * Convert "descendant-or-self::node()/self::" or
  12310. * "descendant-or-self::node()/descendant-or-self::" to
  12311. * to "descendant-or-self::"
  12312. */
  12313. op->ch1 = prevop->ch1;
  12314. op->value = AXIS_DESCENDANT_OR_SELF;
  12315. break;
  12316. default:
  12317. break;
  12318. }
  12319. }
  12320. }
  12321. /* OP_VALUE has invalid ch1. */
  12322. if (op->op == XPATH_OP_VALUE)
  12323. return;
  12324. /* Recurse */
  12325. ctxt = pctxt->context;
  12326. if (ctxt != NULL) {
  12327. if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
  12328. return;
  12329. ctxt->depth += 1;
  12330. }
  12331. if (op->ch1 != -1)
  12332. xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
  12333. if (op->ch2 != -1)
  12334. xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
  12335. if (ctxt != NULL)
  12336. ctxt->depth -= 1;
  12337. }
  12338. /**
  12339. * xmlXPathCtxtCompile:
  12340. * @ctxt: an XPath context
  12341. * @str: the XPath expression
  12342. *
  12343. * Compile an XPath expression
  12344. *
  12345. * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
  12346. * the caller has to free the object.
  12347. */
  12348. xmlXPathCompExprPtr
  12349. xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
  12350. xmlXPathParserContextPtr pctxt;
  12351. xmlXPathCompExprPtr comp;
  12352. int oldDepth = 0;
  12353. #ifdef XPATH_STREAMING
  12354. comp = xmlXPathTryStreamCompile(ctxt, str);
  12355. if (comp != NULL)
  12356. return(comp);
  12357. #endif
  12358. xmlInitParser();
  12359. pctxt = xmlXPathNewParserContext(str, ctxt);
  12360. if (pctxt == NULL)
  12361. return NULL;
  12362. if (ctxt != NULL)
  12363. oldDepth = ctxt->depth;
  12364. xmlXPathCompileExpr(pctxt, 1);
  12365. if (ctxt != NULL)
  12366. ctxt->depth = oldDepth;
  12367. if( pctxt->error != XPATH_EXPRESSION_OK )
  12368. {
  12369. xmlXPathFreeParserContext(pctxt);
  12370. return(NULL);
  12371. }
  12372. if (*pctxt->cur != 0) {
  12373. /*
  12374. * aleksey: in some cases this line prints *second* error message
  12375. * (see bug #78858) and probably this should be fixed.
  12376. * However, we are not sure that all error messages are printed
  12377. * out in other places. It's not critical so we leave it as-is for now
  12378. */
  12379. xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
  12380. comp = NULL;
  12381. } else {
  12382. comp = pctxt->comp;
  12383. if ((comp->nbStep > 1) && (comp->last >= 0)) {
  12384. if (ctxt != NULL)
  12385. oldDepth = ctxt->depth;
  12386. xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
  12387. if (ctxt != NULL)
  12388. ctxt->depth = oldDepth;
  12389. }
  12390. pctxt->comp = NULL;
  12391. }
  12392. xmlXPathFreeParserContext(pctxt);
  12393. if (comp != NULL) {
  12394. comp->expr = xmlStrdup(str);
  12395. }
  12396. return(comp);
  12397. }
  12398. /**
  12399. * xmlXPathCompile:
  12400. * @str: the XPath expression
  12401. *
  12402. * Compile an XPath expression
  12403. *
  12404. * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
  12405. * the caller has to free the object.
  12406. */
  12407. xmlXPathCompExprPtr
  12408. xmlXPathCompile(const xmlChar *str) {
  12409. return(xmlXPathCtxtCompile(NULL, str));
  12410. }
  12411. /**
  12412. * xmlXPathCompiledEvalInternal:
  12413. * @comp: the compiled XPath expression
  12414. * @ctxt: the XPath context
  12415. * @resObj: the resulting XPath object or NULL
  12416. * @toBool: 1 if only a boolean result is requested
  12417. *
  12418. * Evaluate the Precompiled XPath expression in the given context.
  12419. * The caller has to free @resObj.
  12420. *
  12421. * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
  12422. * the caller has to free the object.
  12423. */
  12424. static int
  12425. xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
  12426. xmlXPathContextPtr ctxt,
  12427. xmlXPathObjectPtr *resObjPtr,
  12428. int toBool)
  12429. {
  12430. xmlXPathParserContextPtr pctxt;
  12431. xmlXPathObjectPtr resObj;
  12432. #ifndef LIBXML_THREAD_ENABLED
  12433. static int reentance = 0;
  12434. #endif
  12435. int res;
  12436. CHECK_CTXT_NEG(ctxt)
  12437. if (comp == NULL)
  12438. return(-1);
  12439. xmlInitParser();
  12440. #ifndef LIBXML_THREAD_ENABLED
  12441. reentance++;
  12442. if (reentance > 1)
  12443. xmlXPathDisableOptimizer = 1;
  12444. #endif
  12445. pctxt = xmlXPathCompParserContext(comp, ctxt);
  12446. if (pctxt == NULL)
  12447. return(-1);
  12448. res = xmlXPathRunEval(pctxt, toBool);
  12449. if (pctxt->error != XPATH_EXPRESSION_OK) {
  12450. resObj = NULL;
  12451. } else {
  12452. resObj = valuePop(pctxt);
  12453. if (resObj == NULL) {
  12454. if (!toBool)
  12455. xmlGenericError(xmlGenericErrorContext,
  12456. "xmlXPathCompiledEval: No result on the stack.\n");
  12457. } else if (pctxt->valueNr > 0) {
  12458. xmlGenericError(xmlGenericErrorContext,
  12459. "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
  12460. pctxt->valueNr);
  12461. }
  12462. }
  12463. if (resObjPtr)
  12464. *resObjPtr = resObj;
  12465. else
  12466. xmlXPathReleaseObject(ctxt, resObj);
  12467. pctxt->comp = NULL;
  12468. xmlXPathFreeParserContext(pctxt);
  12469. #ifndef LIBXML_THREAD_ENABLED
  12470. reentance--;
  12471. #endif
  12472. return(res);
  12473. }
  12474. /**
  12475. * xmlXPathCompiledEval:
  12476. * @comp: the compiled XPath expression
  12477. * @ctx: the XPath context
  12478. *
  12479. * Evaluate the Precompiled XPath expression in the given context.
  12480. *
  12481. * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
  12482. * the caller has to free the object.
  12483. */
  12484. xmlXPathObjectPtr
  12485. xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
  12486. {
  12487. xmlXPathObjectPtr res = NULL;
  12488. xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
  12489. return(res);
  12490. }
  12491. /**
  12492. * xmlXPathCompiledEvalToBoolean:
  12493. * @comp: the compiled XPath expression
  12494. * @ctxt: the XPath context
  12495. *
  12496. * Applies the XPath boolean() function on the result of the given
  12497. * compiled expression.
  12498. *
  12499. * Returns 1 if the expression evaluated to true, 0 if to false and
  12500. * -1 in API and internal errors.
  12501. */
  12502. int
  12503. xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
  12504. xmlXPathContextPtr ctxt)
  12505. {
  12506. return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
  12507. }
  12508. /**
  12509. * xmlXPathEvalExpr:
  12510. * @ctxt: the XPath Parser context
  12511. *
  12512. * Parse and evaluate an XPath expression in the given context,
  12513. * then push the result on the context stack
  12514. */
  12515. void
  12516. xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
  12517. #ifdef XPATH_STREAMING
  12518. xmlXPathCompExprPtr comp;
  12519. #endif
  12520. int oldDepth = 0;
  12521. if (ctxt == NULL) return;
  12522. #ifdef XPATH_STREAMING
  12523. comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
  12524. if (comp != NULL) {
  12525. if (ctxt->comp != NULL)
  12526. xmlXPathFreeCompExpr(ctxt->comp);
  12527. ctxt->comp = comp;
  12528. } else
  12529. #endif
  12530. {
  12531. if (ctxt->context != NULL)
  12532. oldDepth = ctxt->context->depth;
  12533. xmlXPathCompileExpr(ctxt, 1);
  12534. if (ctxt->context != NULL)
  12535. ctxt->context->depth = oldDepth;
  12536. CHECK_ERROR;
  12537. /* Check for trailing characters. */
  12538. if (*ctxt->cur != 0)
  12539. XP_ERROR(XPATH_EXPR_ERROR);
  12540. if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
  12541. if (ctxt->context != NULL)
  12542. oldDepth = ctxt->context->depth;
  12543. xmlXPathOptimizeExpression(ctxt,
  12544. &ctxt->comp->steps[ctxt->comp->last]);
  12545. if (ctxt->context != NULL)
  12546. ctxt->context->depth = oldDepth;
  12547. }
  12548. }
  12549. xmlXPathRunEval(ctxt, 0);
  12550. }
  12551. /**
  12552. * xmlXPathEval:
  12553. * @str: the XPath expression
  12554. * @ctx: the XPath context
  12555. *
  12556. * Evaluate the XPath Location Path in the given context.
  12557. *
  12558. * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
  12559. * the caller has to free the object.
  12560. */
  12561. xmlXPathObjectPtr
  12562. xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
  12563. xmlXPathParserContextPtr ctxt;
  12564. xmlXPathObjectPtr res;
  12565. CHECK_CTXT(ctx)
  12566. xmlInitParser();
  12567. ctxt = xmlXPathNewParserContext(str, ctx);
  12568. if (ctxt == NULL)
  12569. return NULL;
  12570. xmlXPathEvalExpr(ctxt);
  12571. if (ctxt->error != XPATH_EXPRESSION_OK) {
  12572. res = NULL;
  12573. } else {
  12574. res = valuePop(ctxt);
  12575. if (res == NULL) {
  12576. xmlGenericError(xmlGenericErrorContext,
  12577. "xmlXPathCompiledEval: No result on the stack.\n");
  12578. } else if (ctxt->valueNr > 0) {
  12579. xmlGenericError(xmlGenericErrorContext,
  12580. "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
  12581. ctxt->valueNr);
  12582. }
  12583. }
  12584. xmlXPathFreeParserContext(ctxt);
  12585. return(res);
  12586. }
  12587. /**
  12588. * xmlXPathSetContextNode:
  12589. * @node: the node to to use as the context node
  12590. * @ctx: the XPath context
  12591. *
  12592. * Sets 'node' as the context node. The node must be in the same
  12593. * document as that associated with the context.
  12594. *
  12595. * Returns -1 in case of error or 0 if successful
  12596. */
  12597. int
  12598. xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
  12599. if ((node == NULL) || (ctx == NULL))
  12600. return(-1);
  12601. if (node->doc == ctx->doc) {
  12602. ctx->node = node;
  12603. return(0);
  12604. }
  12605. return(-1);
  12606. }
  12607. /**
  12608. * xmlXPathNodeEval:
  12609. * @node: the node to to use as the context node
  12610. * @str: the XPath expression
  12611. * @ctx: the XPath context
  12612. *
  12613. * Evaluate the XPath Location Path in the given context. The node 'node'
  12614. * is set as the context node. The context node is not restored.
  12615. *
  12616. * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
  12617. * the caller has to free the object.
  12618. */
  12619. xmlXPathObjectPtr
  12620. xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
  12621. if (str == NULL)
  12622. return(NULL);
  12623. if (xmlXPathSetContextNode(node, ctx) < 0)
  12624. return(NULL);
  12625. return(xmlXPathEval(str, ctx));
  12626. }
  12627. /**
  12628. * xmlXPathEvalExpression:
  12629. * @str: the XPath expression
  12630. * @ctxt: the XPath context
  12631. *
  12632. * Alias for xmlXPathEval().
  12633. *
  12634. * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
  12635. * the caller has to free the object.
  12636. */
  12637. xmlXPathObjectPtr
  12638. xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
  12639. return(xmlXPathEval(str, ctxt));
  12640. }
  12641. /************************************************************************
  12642. * *
  12643. * Extra functions not pertaining to the XPath spec *
  12644. * *
  12645. ************************************************************************/
  12646. /**
  12647. * xmlXPathEscapeUriFunction:
  12648. * @ctxt: the XPath Parser context
  12649. * @nargs: the number of arguments
  12650. *
  12651. * Implement the escape-uri() XPath function
  12652. * string escape-uri(string $str, bool $escape-reserved)
  12653. *
  12654. * This function applies the URI escaping rules defined in section 2 of [RFC
  12655. * 2396] to the string supplied as $uri-part, which typically represents all
  12656. * or part of a URI. The effect of the function is to replace any special
  12657. * character in the string by an escape sequence of the form %xx%yy...,
  12658. * where xxyy... is the hexadecimal representation of the octets used to
  12659. * represent the character in UTF-8.
  12660. *
  12661. * The set of characters that are escaped depends on the setting of the
  12662. * boolean argument $escape-reserved.
  12663. *
  12664. * If $escape-reserved is true, all characters are escaped other than lower
  12665. * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
  12666. * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
  12667. * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
  12668. * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
  12669. * A-F).
  12670. *
  12671. * If $escape-reserved is false, the behavior differs in that characters
  12672. * referred to in [RFC 2396] as reserved characters are not escaped. These
  12673. * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
  12674. *
  12675. * [RFC 2396] does not define whether escaped URIs should use lower case or
  12676. * upper case for hexadecimal digits. To ensure that escaped URIs can be
  12677. * compared using string comparison functions, this function must always use
  12678. * the upper-case letters A-F.
  12679. *
  12680. * Generally, $escape-reserved should be set to true when escaping a string
  12681. * that is to form a single part of a URI, and to false when escaping an
  12682. * entire URI or URI reference.
  12683. *
  12684. * In the case of non-ascii characters, the string is encoded according to
  12685. * utf-8 and then converted according to RFC 2396.
  12686. *
  12687. * Examples
  12688. * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
  12689. * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
  12690. * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
  12691. * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
  12692. *
  12693. */
  12694. static void
  12695. xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  12696. xmlXPathObjectPtr str;
  12697. int escape_reserved;
  12698. xmlBufPtr target;
  12699. xmlChar *cptr;
  12700. xmlChar escape[4];
  12701. CHECK_ARITY(2);
  12702. escape_reserved = xmlXPathPopBoolean(ctxt);
  12703. CAST_TO_STRING;
  12704. str = valuePop(ctxt);
  12705. target = xmlBufCreate();
  12706. escape[0] = '%';
  12707. escape[3] = 0;
  12708. if (target) {
  12709. for (cptr = str->stringval; *cptr; cptr++) {
  12710. if ((*cptr >= 'A' && *cptr <= 'Z') ||
  12711. (*cptr >= 'a' && *cptr <= 'z') ||
  12712. (*cptr >= '0' && *cptr <= '9') ||
  12713. *cptr == '-' || *cptr == '_' || *cptr == '.' ||
  12714. *cptr == '!' || *cptr == '~' || *cptr == '*' ||
  12715. *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
  12716. (*cptr == '%' &&
  12717. ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
  12718. (cptr[1] >= 'a' && cptr[1] <= 'f') ||
  12719. (cptr[1] >= '0' && cptr[1] <= '9')) &&
  12720. ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
  12721. (cptr[2] >= 'a' && cptr[2] <= 'f') ||
  12722. (cptr[2] >= '0' && cptr[2] <= '9'))) ||
  12723. (!escape_reserved &&
  12724. (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
  12725. *cptr == ':' || *cptr == '@' || *cptr == '&' ||
  12726. *cptr == '=' || *cptr == '+' || *cptr == '$' ||
  12727. *cptr == ','))) {
  12728. xmlBufAdd(target, cptr, 1);
  12729. } else {
  12730. if ((*cptr >> 4) < 10)
  12731. escape[1] = '0' + (*cptr >> 4);
  12732. else
  12733. escape[1] = 'A' - 10 + (*cptr >> 4);
  12734. if ((*cptr & 0xF) < 10)
  12735. escape[2] = '0' + (*cptr & 0xF);
  12736. else
  12737. escape[2] = 'A' - 10 + (*cptr & 0xF);
  12738. xmlBufAdd(target, &escape[0], 3);
  12739. }
  12740. }
  12741. }
  12742. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  12743. xmlBufContent(target)));
  12744. xmlBufFree(target);
  12745. xmlXPathReleaseObject(ctxt->context, str);
  12746. }
  12747. /**
  12748. * xmlXPathRegisterAllFunctions:
  12749. * @ctxt: the XPath context
  12750. *
  12751. * Registers all default XPath functions in this context
  12752. */
  12753. void
  12754. xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
  12755. {
  12756. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
  12757. xmlXPathBooleanFunction);
  12758. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
  12759. xmlXPathCeilingFunction);
  12760. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
  12761. xmlXPathCountFunction);
  12762. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
  12763. xmlXPathConcatFunction);
  12764. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
  12765. xmlXPathContainsFunction);
  12766. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
  12767. xmlXPathIdFunction);
  12768. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
  12769. xmlXPathFalseFunction);
  12770. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
  12771. xmlXPathFloorFunction);
  12772. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
  12773. xmlXPathLastFunction);
  12774. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
  12775. xmlXPathLangFunction);
  12776. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
  12777. xmlXPathLocalNameFunction);
  12778. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
  12779. xmlXPathNotFunction);
  12780. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
  12781. xmlXPathNameFunction);
  12782. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
  12783. xmlXPathNamespaceURIFunction);
  12784. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
  12785. xmlXPathNormalizeFunction);
  12786. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
  12787. xmlXPathNumberFunction);
  12788. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
  12789. xmlXPathPositionFunction);
  12790. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
  12791. xmlXPathRoundFunction);
  12792. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
  12793. xmlXPathStringFunction);
  12794. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
  12795. xmlXPathStringLengthFunction);
  12796. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
  12797. xmlXPathStartsWithFunction);
  12798. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
  12799. xmlXPathSubstringFunction);
  12800. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
  12801. xmlXPathSubstringBeforeFunction);
  12802. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
  12803. xmlXPathSubstringAfterFunction);
  12804. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
  12805. xmlXPathSumFunction);
  12806. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
  12807. xmlXPathTrueFunction);
  12808. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
  12809. xmlXPathTranslateFunction);
  12810. xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
  12811. (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
  12812. xmlXPathEscapeUriFunction);
  12813. }
  12814. #endif /* LIBXML_XPATH_ENABLED */