jptree.cpp 175 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963
  1. /*##############################################################################
  2. Copyright (C) 2011 HPCC Systems.
  3. All rights reserved. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ############################################################################## */
  14. #include <stdio.h>
  15. #include "jarray.hpp"
  16. #include "jdebug.hpp"
  17. #include "jhash.hpp"
  18. #include "jmutex.hpp"
  19. #include "jexcept.hpp"
  20. #include "jlzw.hpp"
  21. #include "jregexp.hpp"
  22. #include "jstring.hpp"
  23. #include <algorithm>
  24. #if defined(_DEBUG) && defined(_WIN32) && !defined(USING_MPATROL)
  25. #undef new
  26. #define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
  27. #endif
  28. #define MAKE_LSTRING(name,src,length) \
  29. const char *name = (const char *) alloca((length)+1); \
  30. memcpy((char *) name, (src), (length)); \
  31. *(char *) (name+(length)) = '\0';
  32. #include "jfile.hpp"
  33. #include "jlog.hpp"
  34. #include "jptree.ipp"
  35. #define WARNLEGACYCOMPARE
  36. #define XMLTAG_CONTENT "<>"
  37. #undef UNIMPLEMENTED
  38. #define UNIMPLEMENTED throw MakeIPTException(-1, "UNIMPLEMENTED")
  39. #define CHECK_ATTRIBUTE(X) if (X && isAttribute(X)) throw MakeIPTException(PTreeExcpt_XPath_Unsupported, "Attribute usage invalid here");
  40. #define AMBIGUOUS_PATH(X,P) { StringBuffer buf; buf.append(X": ambiguous xpath \"").append(P).append("\""); throw MakeIPTException(PTreeExcpt_XPath_Ambiguity,buf.str()); }
  41. #define PTREE_COMPRESS_THRESHOLD (4*1024) // i.e. only use compress if > threshold
  42. #define PTREE_COMPRESS_BOTHER_PECENTAGE (80) // i.e. if it doesn't compress to <80 % of original size don't bother
  43. class NullPTreeIterator : public CInterface, implements IPropertyTreeIterator
  44. {
  45. public:
  46. IMPLEMENT_IINTERFACE;
  47. // IPropertyTreeIterator
  48. virtual bool first() { return false; }
  49. virtual bool next() { return false; }
  50. virtual bool isValid() { return false; }
  51. virtual IPropertyTree & query() { assertex(false); return *(IPropertyTree *)NULL; }
  52. } *nullPTreeIterator;
  53. IPropertyTreeIterator *createNullPTreeIterator() { return LINK(nullPTreeIterator); } // initialize in init mod below.
  54. //===================================================================
  55. struct AttrStrC: public AttrStr
  56. {
  57. static inline unsigned getHash(const char *k)
  58. {
  59. return hashc((const byte *)k,strlen(k),17);
  60. }
  61. inline bool eq(const char *k)
  62. {
  63. return strcmp(k,str)==0;
  64. }
  65. static AttrStrC *create(const char *k)
  66. {
  67. size32_t kl = (k?strlen(k):0);
  68. AttrStrC *ret = (AttrStrC *)malloc(sizeof(AttrStrC)+kl);
  69. memcpy(ret->str,k,kl);
  70. ret->str[kl] = 0;
  71. ret->hash = hashc((const byte *)k,kl,17);
  72. ret->linkcount = 0;
  73. return ret;
  74. }
  75. static void destroy(AttrStrC *a)
  76. {
  77. free(a);
  78. }
  79. };
  80. struct AttrStrNC: public AttrStr
  81. {
  82. static inline unsigned getHash(const char *k)
  83. {
  84. return hashnc((const byte *)k,strlen(k),17);
  85. }
  86. inline bool eq(const char *k)
  87. {
  88. return stricmp(k,str)==0;
  89. }
  90. static AttrStrNC *create(const char *k)
  91. {
  92. size32_t kl = (k?strlen(k):0);
  93. AttrStrNC *ret = (AttrStrNC *)malloc(sizeof(AttrStrNC)+kl);
  94. memcpy(ret->str,k,kl);
  95. ret->str[kl] = 0;
  96. ret->hash = hashnc((const byte *)k,kl,17);
  97. ret->linkcount = 0;
  98. return ret;
  99. }
  100. static void destroy(AttrStrNC *a)
  101. {
  102. free(a);
  103. }
  104. };
  105. class CAttrValHashTable
  106. {
  107. CMinHashTable<AttrStrC> htc;
  108. CMinHashTable<AttrStrNC> htnc;
  109. CMinHashTable<AttrStrC> htv;
  110. public:
  111. inline AttrStr *addkey(const char *v,bool nc)
  112. {
  113. AttrStr * ret;
  114. if (nc)
  115. ret = htnc.find(v,true);
  116. else
  117. ret = htc.find(v,true);
  118. if (ret->linkcount!=(unsigned short)-1)
  119. ret->linkcount++;
  120. return ret;
  121. }
  122. inline AttrStr *addval(const char *v)
  123. {
  124. AttrStr * ret = htv.find(v,true);
  125. if (ret->linkcount!=(unsigned short)-1)
  126. ret->linkcount++;
  127. return ret;
  128. }
  129. inline void removekey(AttrStr *a,bool nc)
  130. {
  131. if (a->linkcount!=(unsigned short)-1)
  132. if (--(a->linkcount)==0)
  133. if (nc)
  134. htnc.remove((AttrStrNC *)a);
  135. else
  136. htc.remove((AttrStrC *)a);
  137. }
  138. inline void removeval(AttrStr *a)
  139. {
  140. if (a->linkcount!=(unsigned short)-1)
  141. if (--(a->linkcount)==0)
  142. htv.remove((AttrStrC *)a);
  143. }
  144. };
  145. //===================================================================
  146. static CriticalSection hashcrit;
  147. static AtomRefTable *keyTable, *keyTableNC;
  148. static CAttrValHashTable *attrHT=NULL;
  149. AttrValue **AttrMap::freelist=NULL;
  150. unsigned AttrMap::freelistmax=0;
  151. CLargeMemoryAllocator AttrMap::freeallocator((size32_t)-1,0x1000*sizeof(AttrValue),true);
  152. MODULE_INIT(INIT_PRIORITY_JPTREE)
  153. {
  154. nullPTreeIterator = new NullPTreeIterator;
  155. keyTable = new AtomRefTable;
  156. keyTableNC = new AtomRefTable(true);
  157. attrHT = new CAttrValHashTable;
  158. return true;
  159. }
  160. MODULE_EXIT()
  161. {
  162. nullPTreeIterator->Release();
  163. keyTable->Release();
  164. keyTableNC->Release();
  165. delete attrHT;
  166. AttrMap::killfreelist();
  167. }
  168. static int comparePropTrees(IInterface **ll, IInterface **rr)
  169. {
  170. IPropertyTree *l = (IPropertyTree *) *ll;
  171. IPropertyTree *r = (IPropertyTree *) *rr;
  172. return stricmp(l->queryName(), r->queryName());
  173. };
  174. //////////////////
  175. unsigned ChildMap::getHashFromElement(const void *e) const
  176. {
  177. PTree &elem= (PTree &) (*(IPropertyTree *)e);
  178. return elem.queryKey()->queryHash();
  179. }
  180. unsigned ChildMap::numChildren()
  181. {
  182. SuperHashIteratorOf<IPropertyTree> iter(*this);
  183. if (!iter.first()) return 0;
  184. unsigned count = 0;
  185. do
  186. {
  187. PTree *element = (PTree *) &iter.query();
  188. if (element->value && element->value->isArray())
  189. count += element->value->elements();
  190. else
  191. ++count;
  192. }
  193. while (iter.next());
  194. return count;
  195. }
  196. IPropertyTreeIterator *ChildMap::getIterator(bool sort)
  197. {
  198. class CPTHashIterator : public CInterface, implements IPropertyTreeIterator
  199. {
  200. SuperHashIteratorOf<IPropertyTree> *hiter;
  201. public:
  202. IMPLEMENT_IINTERFACE;
  203. CPTHashIterator(SuperHashTable &table) { hiter = new SuperHashIteratorOf<IPropertyTree>(table); }
  204. ~CPTHashIterator() { hiter->Release(); }
  205. // IPropertyTreeIterator
  206. virtual bool first() { return hiter->first(); }
  207. virtual bool next() { return hiter->next(); }
  208. virtual bool isValid() { return hiter->isValid(); }
  209. virtual IPropertyTree & query() { return hiter->query(); }
  210. };
  211. class CPTArrayIterator : public ArrayIIteratorOf<IArrayOf<IPropertyTree>, IPropertyTree, IPropertyTreeIterator>
  212. {
  213. IArrayOf<IPropertyTree> elems;
  214. public:
  215. CPTArrayIterator(IPropertyTreeIterator &iter) : ArrayIIteratorOf<IArrayOf<IPropertyTree>, IPropertyTree, IPropertyTreeIterator>(elems)
  216. {
  217. ForEach(iter)
  218. elems.append(iter.get());
  219. elems.sort(comparePropTrees);
  220. }
  221. };
  222. IPropertyTreeIterator *baseIter = new CPTHashIterator(*this);
  223. if (!sort)
  224. return baseIter;
  225. IPropertyTreeIterator *it = new CPTArrayIterator(*baseIter);
  226. baseIter->Release();
  227. return it;
  228. }
  229. ///////////
  230. AttrValue *AttrMap::newArray(unsigned n)
  231. {
  232. // NB crit must be locked
  233. if (!n)
  234. return NULL;
  235. if (freelistmax<=n) {
  236. freelist = (AttrValue **)realloc(freelist,sizeof(AttrValue *)*(n+1));
  237. while (freelistmax<=n)
  238. freelist[freelistmax++] = NULL;
  239. }
  240. AttrValue *&p = freelist[n];
  241. AttrValue *ret = p;
  242. if (ret)
  243. p = *(AttrValue **)ret;
  244. else
  245. ret = (AttrValue *)freeallocator.alloc(sizeof(AttrValue)*n);
  246. return ret;
  247. }
  248. void AttrMap::freeArray(AttrValue *a,unsigned n)
  249. {
  250. // NB crit must be locked
  251. if (a) {
  252. AttrValue *&p = freelist[n];
  253. *(AttrValue **)a = p;
  254. p = a;
  255. }
  256. }
  257. void AttrMap::set(const char *key, const char *val)
  258. {
  259. if (!key)
  260. return;
  261. if (!val)
  262. val = ""; // cannot have NULL value
  263. AttrValue *a = attrs+count();
  264. AttrValue *v = NULL;
  265. bool nc = isNoCase();
  266. if (nc) {
  267. while (a--!=attrs)
  268. if (stricmp(a->key->str,key)==0) {
  269. v = a;
  270. break;
  271. }
  272. }
  273. else {
  274. while (a--!=attrs)
  275. if (strcmp(a->key->str,key)==0) {
  276. v = a;
  277. break;
  278. }
  279. }
  280. if (v) {
  281. if (strcmp(v->value->str,val)==0)
  282. return;
  283. CriticalBlock block(hashcrit);
  284. attrHT->removeval(v->value);
  285. v->value = attrHT->addval(val);
  286. }
  287. else {
  288. CriticalBlock block(hashcrit);
  289. unsigned n = count();
  290. AttrValue *newattrs = newArray(n+1);
  291. memcpy(newattrs,attrs,n*sizeof(AttrValue));
  292. newattrs[n].key = attrHT->addkey(key,nc);
  293. newattrs[n].value = attrHT->addval(val);
  294. numattrs++;
  295. freeArray(attrs,n);
  296. attrs = newattrs;
  297. }
  298. }
  299. void AttrMap::kill()
  300. {
  301. if (!attrs)
  302. return;
  303. CriticalBlock block(hashcrit);
  304. AttrValue *a = attrs+count();
  305. bool nc = isNoCase();
  306. while (a--!=attrs) {
  307. attrHT->removekey(a->key,nc);
  308. attrHT->removeval(a->value);
  309. }
  310. freeArray(attrs,count());
  311. attrs = NULL;
  312. numattrs &= AM_NOCASE_FLAG; // clear num attrs
  313. }
  314. const char *AttrMap::find(const char *key) const
  315. {
  316. AttrValue *a = attrs+count();
  317. if (isNoCase()) {
  318. while (a--!=attrs)
  319. if (stricmp(a->key->str,key)==0)
  320. return a->value->str;
  321. }
  322. else {
  323. while (a--!=attrs)
  324. if (strcmp(a->key->str,key)==0)
  325. return a->value->str;
  326. }
  327. return NULL;
  328. }
  329. bool AttrMap::remove(const char *key)
  330. {
  331. unsigned n = count();
  332. AttrValue *a = attrs+n;
  333. AttrValue *del = NULL;
  334. if (isNoCase()) {
  335. while (a--!=attrs)
  336. if (stricmp(a->key->str,key)==0) {
  337. del = a;
  338. break;
  339. }
  340. }
  341. else {
  342. while (a--!=attrs)
  343. if (strcmp(a->key->str,key)==0) {
  344. del = a;
  345. break;
  346. }
  347. }
  348. if (!del)
  349. return false;
  350. CriticalBlock block(hashcrit);
  351. numattrs--;
  352. n--;
  353. AttrValue *newattrs = newArray(n);
  354. if (newattrs) {
  355. size32_t ls = (byte *)a-(byte *)attrs;
  356. memcpy(newattrs,attrs,ls);
  357. memcpy(((byte *)newattrs)+ls,((byte *)attrs)+ls+sizeof(AttrValue),n*sizeof(AttrValue)-ls);
  358. }
  359. freeArray(attrs,n+1);
  360. attrs = newattrs;
  361. return true;
  362. }
  363. void AttrMap::swap(AttrMap &other)
  364. {
  365. AttrValue *ta = attrs;
  366. attrs = other.attrs;
  367. other.attrs = ta;
  368. unsigned short tn = numattrs;
  369. numattrs = other.numattrs;
  370. other.numattrs = tn;
  371. }
  372. ///////////
  373. bool validateXMLTag(const char *name)
  374. {
  375. if (!isValidXPathStartChr(*name)) return false;
  376. ++name;
  377. while (*name != '\0')
  378. {
  379. if (!isValidXPathChr(*name)) return false;
  380. ++name;
  381. }
  382. return true;
  383. }
  384. class jlib_thrown_decl CPTreeException : public CInterface, implements IPTreeException
  385. {
  386. int errCode;
  387. StringBuffer errMsg;
  388. public:
  389. IMPLEMENT_IINTERFACE;
  390. CPTreeException(int _errCode, const char *_errMsg, va_list &args) : errCode(_errCode)
  391. {
  392. if (_errMsg)
  393. errMsg.valist_appendf(_errMsg, args);
  394. }
  395. StringBuffer &translateCode(StringBuffer &out) const
  396. {
  397. out.append("IPropertyTree: ");
  398. switch (errCode)
  399. {
  400. case PTreeExcpt_XPath_Ambiguity:
  401. return out.append("Ambiguous xpath used");
  402. case PTreeExcpt_XPath_ParseError:
  403. return out.append("xpath parse error");
  404. case PTreeExcpt_XPath_Unsupported:
  405. return out.append("unsupported xpath syntax used");
  406. case PTreeExcpt_InvalidTagName:
  407. return out.append("Invalid tag name");
  408. default:
  409. return out.append("UNKNOWN ERROR CODE: ").append(errCode);
  410. }
  411. }
  412. // IException
  413. int errorCode() const { return errCode; }
  414. StringBuffer &errorMessage(StringBuffer &out) const
  415. {
  416. return translateCode(out).append("\n").append(errMsg.str());
  417. }
  418. MessageAudience errorAudience() const { return MSGAUD_user; }
  419. };
  420. IPTreeException *MakeIPTException(int code, const char *format, ...)
  421. {
  422. va_list args;
  423. va_start(args, format);
  424. IPTreeException *e = new CPTreeException(code, format, args);
  425. va_end(args);
  426. return e;
  427. }
  428. IPTreeException *MakeXPathException(const char *xpath, int code, unsigned pos, const char *format, ...)
  429. {
  430. va_list args;
  431. va_start(args, format);
  432. StringBuffer s("XPath Exception: ");
  433. s.valist_appendf(format, args);
  434. va_end(args);
  435. #ifdef _DEBUG
  436. PrintStackReport();
  437. #endif
  438. const char *msg = "in xpath = ";
  439. s.append("\n").append(msg).append(xpath);
  440. s.append("\n").appendN((size32_t)strlen(msg)+pos, ' ').append("^");
  441. return MakeIPTException(code, s.str());
  442. }
  443. inline static void readID(const char *&xxpath, bool started)
  444. {
  445. const char *xpath = xxpath;
  446. if (isValidXPathStartChr(*xpath) || (started && isValidXPathChr(*xpath)))
  447. {
  448. do
  449. {
  450. xpath++;
  451. } while (isValidXPathChr(*xpath));
  452. xxpath = xpath;
  453. }
  454. }
  455. inline static void readWildId(const char *&xpath, bool &wild)
  456. {
  457. const char *start = xpath;
  458. wild = false;
  459. loop
  460. {
  461. readID(xpath, wild);
  462. if ('*' != *xpath)
  463. break;
  464. wild = true;
  465. ++xpath;
  466. }
  467. }
  468. inline const char * readIndex(const char *xpath, StringAttr &index)
  469. {
  470. const char *start = xpath;
  471. do { xpath++; } while (isdigit(*xpath));
  472. index.set(start, (xpath - start));
  473. return xpath;
  474. }
  475. inline static void readWildIdIndex(const char *&xpath, bool &wild)
  476. {
  477. const char *_xpath = xpath;
  478. readWildId(xpath, wild);
  479. if ('[' == *xpath) // check for local index not iterative qualifier.
  480. {
  481. const char *end = xpath+1;
  482. if (isdigit(*end)) {
  483. StringAttr index;
  484. end = readIndex(end, index);
  485. if (']' != *end)
  486. throw MakeXPathException(_xpath, PTreeExcpt_XPath_ParseError, xpath-_xpath, "Qualifier brace unclosed");
  487. xpath = end+1;
  488. }
  489. }
  490. }
  491. inline static unsigned getTailIdLength(const char *xxpath, unsigned xxpathlength)
  492. {
  493. const char *xpath = xxpath+xxpathlength;
  494. const char *end = xpath;
  495. while (xpath != xxpath)
  496. {
  497. --xpath;
  498. if (!isValidXPathChr(*xpath)) break;
  499. }
  500. if (!isAttribute(xpath) && xpath != xxpath) ++xpath;
  501. return end-xpath;
  502. }
  503. const char *splitXPathUQ(const char *xpath, StringBuffer &path)
  504. {
  505. size32_t xpathSize = (size32_t) strlen(xpath);
  506. size32_t idSize = getTailIdLength(xpath, xpathSize);
  507. path.append(xpathSize-idSize, xpath);
  508. return xpath + (xpathSize-idSize);
  509. }
  510. const char *splitXPathX(const char *xpath)
  511. {
  512. size32_t xpathSize = (size32_t) strlen(xpath);
  513. size32_t idSize = getTailIdLength(xpath, xpathSize);
  514. return xpath + (xpathSize-idSize);
  515. }
  516. // similar to above, splitXPathUQ doesn't split if qualified
  517. const char *splitXPath(const char *xpath, StringBuffer &headPath)
  518. {
  519. StringBuffer path;
  520. const char *end = xpath+strlen(xpath);
  521. const char *prop = end;
  522. bool quote = false;
  523. bool braced = false;
  524. while (xpath != prop)
  525. {
  526. --prop;
  527. if (*prop == '"')
  528. {
  529. if (quote) quote = false;
  530. else quote = true;
  531. }
  532. else if (*prop == ']' && !quote)
  533. {
  534. assertex(!braced);
  535. braced = true;
  536. }
  537. else if (*prop == '[' && !quote)
  538. {
  539. assertex(braced);
  540. braced = false;
  541. }
  542. else if (*prop == '/' && !quote && !braced)
  543. {
  544. ++prop;
  545. break;
  546. }
  547. }
  548. if (prop == end)
  549. return NULL;
  550. else if (xpath != prop)
  551. {
  552. size32_t ps = prop-xpath-1;
  553. headPath.append(ps, xpath);
  554. }
  555. return prop;
  556. }
  557. const char *queryNextUnquoted(const char *str, char c)
  558. {
  559. const char *end = str+strlen(str);
  560. bool quote = false;
  561. while (end != str)
  562. {
  563. ++str;
  564. if ('"' == *str)
  565. {
  566. if (quote) quote = false;
  567. else quote = true;
  568. }
  569. else if (c == *str && !quote)
  570. break;
  571. }
  572. return str==end?NULL:str;
  573. }
  574. const char *queryHead(const char *xpath, StringBuffer &head)
  575. {
  576. if (!xpath) return NULL;
  577. StringBuffer path;
  578. const char *start = xpath;
  579. const char *end = xpath+strlen(xpath);
  580. bool quote = false;
  581. bool braced = false;
  582. while (end != xpath)
  583. {
  584. ++xpath;
  585. if (*xpath == '"')
  586. {
  587. if (quote) quote = false;
  588. else quote = true;
  589. }
  590. else if (*xpath == ']' && !quote)
  591. {
  592. assertex(braced);
  593. braced = false;
  594. }
  595. else if (*xpath == '[' && !quote)
  596. {
  597. assertex(!braced);
  598. braced = true;
  599. }
  600. else if (*xpath == '/' && !quote && !braced)
  601. {
  602. if ('/' == *start) // so leading '//'
  603. return start;
  604. else if ('/' == *(xpath+1)) // in middle of path
  605. {
  606. head.append(xpath-start, start);
  607. return xpath;
  608. }
  609. break;
  610. }
  611. }
  612. if (xpath == end)
  613. return NULL;
  614. head.append(xpath-start, start);
  615. return xpath+1;
  616. }
  617. ///////////////////
  618. class SeriesPTIterator : public CInterface, implements IPropertyTreeIterator
  619. {
  620. public:
  621. IMPLEMENT_IINTERFACE;
  622. SeriesPTIterator() : current(NULL), cp(0)
  623. {
  624. }
  625. void addIterator(IPropertyTreeIterator *iter) { iters.append(*iter); }
  626. // IPropertyTreeIterator impl.
  627. virtual bool first()
  628. {
  629. cp = 0;
  630. iterCount = iters.ordinality();
  631. if (nextIterator())
  632. return true;
  633. else
  634. return false;
  635. }
  636. virtual bool next()
  637. {
  638. while (currentIter)
  639. {
  640. if (currentIter->next())
  641. {
  642. current = &currentIter->query();
  643. return true;
  644. }
  645. if (nextIterator())
  646. return true;
  647. }
  648. current = NULL;
  649. return false;
  650. }
  651. virtual bool isValid() { return (NULL != current); }
  652. virtual IPropertyTree & query() { assertex(current); return *current; }
  653. private:
  654. bool nextIterator()
  655. {
  656. while (cp<iterCount)
  657. {
  658. currentIter = (IPropertyTreeIterator *) &iters.item(cp++);
  659. if (currentIter->first())
  660. {
  661. current = &currentIter->query();
  662. return true;
  663. }
  664. }
  665. current = NULL;
  666. currentIter = NULL;
  667. return false;
  668. }
  669. Array iters;
  670. IPropertyTreeIterator *currentIter;
  671. IPropertyTree *current;
  672. unsigned cp, iterCount;
  673. };
  674. ///////////////////
  675. CPTValue::CPTValue(size32_t size, const void *data, bool binary, bool raw, bool _compressed)
  676. {
  677. compressed = _compressed;
  678. if (!raw && binary && size > PTREE_COMPRESS_THRESHOLD)
  679. {
  680. unsigned newSize = size * PTREE_COMPRESS_BOTHER_PECENTAGE / 100;
  681. void *newData = NULL;
  682. ICompressor *compressor = NULL;
  683. try
  684. {
  685. newData = malloc(sizeof(size32_t) + newSize);
  686. compressor = createLZWCompressor();
  687. compressor->open(((char *)newData) + sizeof(size32_t), newSize);
  688. if (compressor->write(data, size)==size)
  689. {
  690. compressor->close();
  691. memcpy(newData, &size, sizeof(size32_t));
  692. newSize = sizeof(size32_t) + compressor->buflen();
  693. compressed = true;
  694. set(newSize, newData);
  695. }
  696. free(newData);
  697. compressor->Release();
  698. }
  699. catch (...)
  700. {
  701. if (newData)
  702. free(newData);
  703. if (compressor) compressor->Release();
  704. throw;
  705. }
  706. }
  707. if (raw || !compressed)
  708. set(size, data);
  709. }
  710. static void *uncompress(const void *src, size32_t &sz)
  711. {
  712. IExpander *expander = NULL;
  713. void *uncompressedValue = NULL;
  714. try
  715. {
  716. memcpy(&sz, src, sizeof(size32_t));
  717. assertex(sz);
  718. expander = createLZWExpander();
  719. src = ((const char *)src) + sizeof(size32_t);
  720. void *uncompressedValue = malloc(sz); assertex(uncompressedValue);
  721. expander->init(src);
  722. expander->expand(uncompressedValue);
  723. expander->Release();
  724. return uncompressedValue;
  725. }
  726. catch (...)
  727. {
  728. if (expander) expander->Release();
  729. if (uncompressedValue) free(uncompressedValue);
  730. throw;
  731. }
  732. }
  733. const void *CPTValue::queryValue() const
  734. {
  735. if (compressed)
  736. {
  737. size32_t sz;
  738. void *uncompressedValue = uncompress(get(), sz);
  739. ((MemoryAttr *)this)->setOwn(sz, uncompressedValue);
  740. compressed = false;
  741. }
  742. return get();
  743. }
  744. void CPTValue::serialize(MemoryBuffer &tgt)
  745. {
  746. tgt.append(length());
  747. if (length())
  748. {
  749. tgt.append(compressed);
  750. tgt.append(length(), get());
  751. }
  752. }
  753. void CPTValue::deserialize(MemoryBuffer &src)
  754. {
  755. size32_t sz;
  756. src.read(sz);
  757. if (sz)
  758. {
  759. src.read(compressed);
  760. set(sz, src.readDirect(sz));
  761. }
  762. else
  763. {
  764. compressed = false;
  765. clear();
  766. }
  767. }
  768. MemoryBuffer &CPTValue::getValue(MemoryBuffer &tgt, bool binary) const
  769. {
  770. if (compressed)
  771. {
  772. size32_t sz;
  773. void *uncompressedValue = uncompress(get(), sz);
  774. if (!binary) sz -= 1;
  775. tgt.append(sz, uncompressedValue);
  776. if (uncompressedValue)
  777. free(uncompressedValue);
  778. }
  779. else
  780. {
  781. if (binary)
  782. tgt.append(length(), get());
  783. else
  784. tgt.append(length()-1, get());
  785. }
  786. return tgt;
  787. }
  788. StringBuffer &CPTValue::getValue(StringBuffer &tgt, bool binary) const
  789. {
  790. if (compressed)
  791. {
  792. size32_t sz;
  793. void *uncompressedValue = NULL;
  794. try
  795. {
  796. uncompressedValue = uncompress(get(), sz);
  797. if (!binary) sz -= 1;
  798. tgt.append(sz, (const char *)uncompressedValue);
  799. free(uncompressedValue);
  800. }
  801. catch (IException *)
  802. {
  803. if (uncompressedValue) free(uncompressedValue);
  804. throw;
  805. }
  806. }
  807. else
  808. {
  809. if (binary) // this should probably be an assert?
  810. tgt.append(length(), (const char *)get());
  811. else if (length())
  812. tgt.append(length()-1, (const char *)get());
  813. }
  814. return tgt;
  815. }
  816. size32_t CPTValue::queryValueSize() const
  817. {
  818. if (compressed)
  819. {
  820. size32_t sz;
  821. memcpy(&sz, get(), sizeof(size32_t));
  822. return sz;
  823. }
  824. else
  825. return length();
  826. }
  827. ///////////////////
  828. PTree::PTree(MemoryBuffer &src)
  829. {
  830. init();
  831. deserialize(src);
  832. }
  833. PTree::PTree(const char *_name, byte _flags, IPTArrayValue *_value, ChildMap *_children)
  834. {
  835. init();
  836. flags = _flags;
  837. if (isnocase())
  838. attributes.setNoCase(true);
  839. if (_name) setName(_name);
  840. children = LINK(_children);
  841. value = _value;
  842. }
  843. PTree::~PTree()
  844. {
  845. if (value) delete value;
  846. ::Release(children);
  847. if (name)
  848. {
  849. AtomRefTable *kT = isnocase()?keyTableNC:keyTable;
  850. kT->releaseKey(name);
  851. }
  852. }
  853. IPropertyTree *PTree::queryChild(unsigned index)
  854. {
  855. if (!value) return NULL;
  856. if (!value->isArray()) return this;
  857. IPropertyTree *v = value->queryElement(index);
  858. return v;
  859. }
  860. aindex_t PTree::findChild(IPropertyTree *child, bool remove)
  861. {
  862. if (value && value->isArray())
  863. {
  864. unsigned i;
  865. for (i=0; i<value->elements(); i++)
  866. {
  867. IPropertyTree *_child = value->queryElement(i);
  868. if (_child == child)
  869. {
  870. if (remove)
  871. {
  872. assertex(value);
  873. value->removeElement(i);
  874. }
  875. return i;
  876. }
  877. }
  878. }
  879. else if (children)
  880. {
  881. IPropertyTree *_child = children->query(child->queryName());
  882. if (_child == child)
  883. {
  884. if (remove)
  885. children->removeExact(_child);
  886. return 0;
  887. }
  888. else if (_child)
  889. {
  890. PTree *__child = (PTree *) _child;
  891. return __child->findChild(child, remove);
  892. }
  893. }
  894. return NotFound;
  895. }
  896. ChildMap *PTree::checkChildren() const
  897. {
  898. return children;
  899. }
  900. void PTree::setLocal(size32_t l, const void *data, bool _binary)
  901. {
  902. if (value) delete value;
  903. if (l)
  904. value = new CPTValue(l, data, _binary);
  905. else
  906. value = NULL;
  907. if (_binary)
  908. IptFlagSet(flags, ipt_binary);
  909. else
  910. IptFlagClr(flags, ipt_binary);
  911. }
  912. void PTree::appendLocal(size32_t l, const void *data, bool binary)
  913. {
  914. if (0 == l) return;
  915. MemoryBuffer mb;
  916. if (value)
  917. {
  918. assertex(!value->isArray());
  919. assertex(binary == IptFlagTst(flags, ipt_binary));
  920. value->getValue(mb, binary);
  921. mb.append(l, data);
  922. delete value;
  923. l = mb.length();
  924. data = mb.toByteArray();
  925. }
  926. if (l)
  927. value = new CPTValue(l, data, binary);
  928. else
  929. value = NULL;
  930. if (binary)
  931. IptFlagSet(flags, ipt_binary);
  932. else
  933. IptFlagClr(flags, ipt_binary);
  934. }
  935. void PTree::setName(const char *_name)
  936. {
  937. AtomRefTable *kT = isnocase()?keyTableNC:keyTable;
  938. HashKeyElement *oname = name;
  939. if (!_name)
  940. name = NULL;
  941. else
  942. {
  943. if (!validateXMLTag(_name))
  944. throw MakeIPTException(PTreeExcpt_InvalidTagName, ": %s", _name);
  945. name = kT->queryCreate(_name);
  946. }
  947. if (oname)
  948. kT->releaseKey(oname);
  949. }
  950. // IPropertyTree impl.
  951. bool PTree::hasProp(const char * xpath) const
  952. {
  953. const char *prop = splitXPathX(xpath);
  954. if (isAttribute(prop)) // JCS - note no wildcards on attributes
  955. {
  956. if (prop != xpath)
  957. {
  958. MAKE_LSTRING(path, xpath, prop-xpath);
  959. Owned<IPropertyTreeIterator> iter = getElements(path);
  960. if (iter->first())
  961. {
  962. do
  963. {
  964. IPropertyTree &branch = iter->query();
  965. if (branch.hasProp(prop))
  966. return true;
  967. }
  968. while (iter->next());
  969. }
  970. return false;
  971. }
  972. else
  973. return (NULL != attributes.find(xpath));
  974. }
  975. else
  976. {
  977. IPropertyTreeIterator *iter = getElements(xpath);
  978. bool res = iter->first();
  979. iter->Release();
  980. return res;
  981. }
  982. }
  983. const char *PTree::queryProp(const char *xpath) const
  984. {
  985. if (!xpath)
  986. {
  987. if (!value) return NULL;
  988. return (const char *) value->queryValue();
  989. }
  990. else if (isAttribute(xpath))
  991. {
  992. return attributes.find(xpath);
  993. }
  994. else
  995. {
  996. const char *prop = splitXPathX(xpath);
  997. if (isAttribute(prop))
  998. {
  999. MAKE_LSTRING(path, xpath, prop-xpath);
  1000. IPropertyTree *branch = queryPropTree(path);
  1001. if (!branch) return NULL;
  1002. return branch->queryProp(prop);
  1003. }
  1004. else
  1005. {
  1006. IPropertyTree *branch = queryPropTree(xpath);
  1007. if (!branch) return NULL;
  1008. return branch->queryProp(NULL);
  1009. }
  1010. }
  1011. }
  1012. bool PTree::getProp(const char *xpath, StringBuffer &ret) const
  1013. {
  1014. if (!xpath)
  1015. {
  1016. if (!value) return false;
  1017. value->getValue(ret, IptFlagTst(flags, ipt_binary));
  1018. return true;
  1019. }
  1020. else if (isAttribute(xpath))
  1021. {
  1022. const char *value = attributes.find(xpath);
  1023. if (!value) return false;
  1024. ret.append(value);
  1025. return true;
  1026. }
  1027. else
  1028. {
  1029. const char *prop = splitXPathX(xpath);
  1030. if (isAttribute(prop))
  1031. {
  1032. MAKE_LSTRING(path, xpath, prop-xpath)
  1033. IPropertyTree *branch = queryPropTree(path);
  1034. if (!branch) return false;
  1035. return branch->getProp(prop, ret);
  1036. }
  1037. else
  1038. {
  1039. IPropertyTree *branch = queryPropTree(xpath);
  1040. if (!branch) return false;
  1041. return branch->getProp(NULL, ret);
  1042. }
  1043. }
  1044. }
  1045. bool PTree::removeAttr(const char *attr)
  1046. {
  1047. return attributes.remove(attr);
  1048. }
  1049. void PTree::setAttr(const char *attr, const char *val)
  1050. {
  1051. if (!validateXMLTag(attr+1))
  1052. throw MakeIPTException(-1, "Invalid xml attribute: %s", attr);
  1053. attributes.set(attr, val);
  1054. }
  1055. void PTree::setProp(const char *xpath, const char *val)
  1056. {
  1057. if (!xpath || '\0' == *xpath)
  1058. {
  1059. if (!val)
  1060. {
  1061. if (value) delete value;
  1062. value = NULL;
  1063. }
  1064. else
  1065. {
  1066. size32_t l=(size32_t)strlen(val);
  1067. if (!l)
  1068. {
  1069. if (value) delete value;
  1070. value = NULL;
  1071. }
  1072. else
  1073. setLocal(l+1, val);
  1074. }
  1075. }
  1076. else if (isAttribute(xpath))
  1077. {
  1078. if (!val)
  1079. removeAttr(xpath);
  1080. else
  1081. setAttr(xpath, val);
  1082. }
  1083. else
  1084. {
  1085. const char *prop;
  1086. IPropertyTree *branch = splitBranchProp(xpath, prop, true);
  1087. if (isAttribute(prop))
  1088. branch->setProp(prop, val);
  1089. else
  1090. {
  1091. if (val)
  1092. {
  1093. IPropertyTree *propBranch = queryCreateBranch(branch, prop);
  1094. propBranch->setProp(NULL, val);
  1095. }
  1096. else
  1097. branch->removeProp(prop);
  1098. }
  1099. }
  1100. }
  1101. aindex_t PTree::getChildMatchPos(const char *xpath)
  1102. {
  1103. Owned<IPropertyTreeIterator> childIter = getElements(xpath);
  1104. if (!childIter->first())
  1105. return (aindex_t)-1;
  1106. IPropertyTree &childMatch = childIter->query();
  1107. if (childIter->next())
  1108. AMBIGUOUS_PATH("addPropX", xpath);
  1109. if (value)
  1110. if (value->isArray())
  1111. return findChild(&childMatch);
  1112. else
  1113. return 0;
  1114. else
  1115. return 0;
  1116. }
  1117. void PTree::resolveParentChild(const char *xpath, IPropertyTree *&parent, IPropertyTree *&child, StringAttr &path, StringAttr &qualifier)
  1118. {
  1119. parent = child = NULL;
  1120. if (!xpath)
  1121. throw MakeIPTException(-1, "No path to resolve parent from");
  1122. const char *end = xpath+strlen(xpath);
  1123. const char *prop = end;
  1124. while (prop != xpath && *(prop-1) != '/')
  1125. --prop;
  1126. size32_t ps = prop-xpath;
  1127. if (ps)
  1128. {
  1129. path.set(xpath, ps);
  1130. Owned<IPropertyTreeIterator> pathIter = getElements(path);
  1131. if (!pathIter->first())
  1132. throw MakeIPTException(-1, "resolveParentChild: path not found %s", xpath);
  1133. IPropertyTree *currentPath = NULL;
  1134. bool multiplePaths = false;
  1135. bool multipleChildMatches = false;
  1136. loop
  1137. {
  1138. // JCSMORE - a bit annoying has to be done again once path has been established
  1139. currentPath = &pathIter->query();
  1140. Owned<IPropertyTreeIterator> childIter = currentPath->getElements(prop);
  1141. if (childIter->first())
  1142. {
  1143. child = &childIter->query();
  1144. if (parent)
  1145. AMBIGUOUS_PATH("resolveParentChild", xpath);
  1146. if (!multipleChildMatches && childIter->next())
  1147. multipleChildMatches = true;
  1148. parent = currentPath;
  1149. }
  1150. if (pathIter->next())
  1151. multiplePaths = true;
  1152. else break;
  1153. }
  1154. if (!parent)
  1155. {
  1156. if (multiplePaths) // i.e. no unique path to child found and multiple parent paths
  1157. AMBIGUOUS_PATH("resolveParentChild", xpath);
  1158. parent = currentPath;
  1159. }
  1160. if (multipleChildMatches)
  1161. child = NULL; // single parent, but no single child.
  1162. path.set(prop);
  1163. const char *pstart = prop;
  1164. bool wild;
  1165. readWildId(prop, wild);
  1166. size32_t s = prop-pstart;
  1167. if (wild)
  1168. throw MakeXPathException(pstart, PTreeExcpt_XPath_ParseError, s-1, "Wildcards not permitted on add");
  1169. assertex(s);
  1170. path.set(pstart, s);
  1171. qualifier.set(prop);
  1172. }
  1173. else
  1174. {
  1175. assertex(prop && *prop);
  1176. parent = this;
  1177. const char *pstart = prop;
  1178. bool wild;
  1179. readWildId(prop, wild);
  1180. assertex(!wild);
  1181. size32_t s = prop-pstart;
  1182. if (*prop && *prop != '[')
  1183. throw MakeXPathException(pstart, PTreeExcpt_XPath_ParseError, s, "Qualifier expected e.g. [..]");
  1184. path.set(pstart, s);
  1185. if (checkChildren())
  1186. child = children->query(path);
  1187. if (child)
  1188. qualifier.set(prop);
  1189. else
  1190. qualifier.clear();
  1191. }
  1192. }
  1193. void PTree::addProp(const char *xpath, const char *val)
  1194. {
  1195. if (!xpath || '\0' == *xpath)
  1196. addLocal((size32_t)strlen(val)+1, val);
  1197. else if (isAttribute(xpath))
  1198. setAttr(xpath, val);
  1199. else if ('[' == *xpath)
  1200. {
  1201. aindex_t pos = getChildMatchPos(xpath);
  1202. if (-1 == pos)
  1203. throw MakeIPTException(-1, "addProp: qualifier unmatched %s", xpath);
  1204. addLocal((size32_t)strlen(val)+1, val, false, pos);
  1205. }
  1206. else
  1207. {
  1208. IPropertyTree *parent, *child;
  1209. StringAttr path, qualifier;
  1210. resolveParentChild(xpath, parent, child, path, qualifier);
  1211. if (parent != this)
  1212. parent->addProp(path, val);
  1213. else if (child)
  1214. child->addProp(qualifier, val);
  1215. else
  1216. setProp(path, val);
  1217. }
  1218. }
  1219. void PTree::appendProp(const char *xpath, const char *val)
  1220. {
  1221. if (!xpath || '\0' == *xpath)
  1222. appendLocal((size_t)strlen(val)+1, val, false);
  1223. else if (isAttribute(xpath))
  1224. {
  1225. StringBuffer newVal;
  1226. getProp(xpath, newVal);
  1227. newVal.append(val);
  1228. setAttr(xpath, newVal.str());
  1229. }
  1230. else if ('[' == *xpath)
  1231. {
  1232. aindex_t pos = getChildMatchPos(xpath);
  1233. if (-1 == pos)
  1234. throw MakeIPTException(-1, "appendProp: qualifier unmatched %s", xpath);
  1235. appendLocal((size_t)strlen(val)+1, val, false);
  1236. }
  1237. else
  1238. {
  1239. IPropertyTree *parent, *child;
  1240. StringAttr path, qualifier;
  1241. resolveParentChild(xpath, parent, child, path, qualifier);
  1242. if (parent != this)
  1243. parent->appendProp(path, val);
  1244. else if (child)
  1245. child->appendProp(qualifier, val);
  1246. else
  1247. setProp(path, val);
  1248. }
  1249. }
  1250. bool PTree::getPropBool(const char *xpath, bool dft) const
  1251. {
  1252. const char *val = queryProp(xpath);
  1253. if (val && *val)
  1254. return strToBool(val);
  1255. else
  1256. return dft;
  1257. }
  1258. __int64 PTree::getPropInt64(const char *xpath, __int64 dft) const
  1259. {
  1260. if (!xpath)
  1261. {
  1262. if (!value) return dft;
  1263. else
  1264. {
  1265. const char *v = (const char *)value->queryValue();
  1266. if (!v || !*v) return dft;
  1267. else return _atoi64(v);
  1268. }
  1269. }
  1270. else if (isAttribute(xpath))
  1271. {
  1272. const char *a = attributes.find(xpath);
  1273. if (!a || !*a)
  1274. return dft;
  1275. return _atoi64(a);
  1276. }
  1277. else
  1278. {
  1279. const char *prop = splitXPathX(xpath);
  1280. if (isAttribute(prop))
  1281. {
  1282. MAKE_LSTRING(path, xpath, prop-xpath);
  1283. IPropertyTree *branch = queryPropTree(path);
  1284. if (!branch) return dft;
  1285. return branch->getPropInt64(prop, dft);
  1286. }
  1287. else
  1288. {
  1289. IPropertyTree *branch = queryPropTree(xpath);
  1290. if (!branch) return dft;
  1291. return branch->getPropInt64(NULL, dft);
  1292. }
  1293. }
  1294. }
  1295. void PTree::setPropInt64(const char * xpath, __int64 val)
  1296. {
  1297. if (!xpath || '\0' == *xpath)
  1298. {
  1299. char buf[23];
  1300. numtostr(buf, val);
  1301. setLocal((size32_t)strlen(buf)+1, buf);
  1302. }
  1303. else if (isAttribute(xpath))
  1304. {
  1305. char buf[23];
  1306. numtostr(buf, val);
  1307. setAttr(xpath, buf);
  1308. }
  1309. else
  1310. {
  1311. const char *prop;
  1312. IPropertyTree *branch = splitBranchProp(xpath, prop, true);
  1313. if (isAttribute(prop))
  1314. branch->setPropInt64(prop, val);
  1315. else
  1316. {
  1317. IPropertyTree *propBranch = queryCreateBranch(branch, prop);
  1318. propBranch->setPropInt64(NULL, val);
  1319. }
  1320. }
  1321. }
  1322. void PTree::addPropInt64(const char *xpath, __int64 val)
  1323. {
  1324. if (!xpath || '\0' == *xpath)
  1325. {
  1326. char buf[23];
  1327. numtostr(buf,val);
  1328. addLocal((size32_t)strlen(buf)+1, buf);
  1329. }
  1330. else if (isAttribute(xpath))
  1331. {
  1332. char buf[23];
  1333. numtostr(buf, val);
  1334. setAttr(xpath, buf);
  1335. }
  1336. else if ('[' == *xpath)
  1337. {
  1338. char buf[23];
  1339. numtostr(buf, val);
  1340. aindex_t pos = getChildMatchPos(xpath);
  1341. if (-1 == pos)
  1342. throw MakeIPTException(-1, "addPropInt64: qualifier unmatched %s", xpath);
  1343. addLocal((size32_t)strlen(buf)+1, buf, false, pos);
  1344. }
  1345. else
  1346. {
  1347. IPropertyTree *parent, *child;
  1348. StringAttr path, qualifier;
  1349. resolveParentChild(xpath, parent, child, path, qualifier);
  1350. if (parent != this)
  1351. parent->addPropInt64(path, val);
  1352. else if (child)
  1353. child->addPropInt64(qualifier, val);
  1354. else
  1355. setPropInt64(path, val);
  1356. }
  1357. }
  1358. int PTree::getPropInt(const char *xpath, int dft) const
  1359. {
  1360. return (int) getPropInt64(xpath, dft); // underlying type always __int64 (now)
  1361. }
  1362. void PTree::setPropInt(const char *xpath, int val)
  1363. {
  1364. setPropInt64(xpath, val); // underlying type always __int64 (now)
  1365. }
  1366. void PTree::addPropInt(const char *xpath, int val)
  1367. {
  1368. addPropInt64(xpath, val); // underlying type always __int64 (now)
  1369. }
  1370. bool PTree::isCompressed(const char *xpath) const
  1371. {
  1372. if (!xpath)
  1373. return (value && value->isCompressed());
  1374. else if (isAttribute(xpath))
  1375. return false;
  1376. else
  1377. {
  1378. const char *prop = splitXPathX(xpath);
  1379. if (prop && '\0' != *prop && !isAttribute(prop))
  1380. {
  1381. IPropertyTree *branch = queryPropTree(xpath);
  1382. if (branch)
  1383. return branch->isCompressed(prop);
  1384. }
  1385. }
  1386. return false;
  1387. }
  1388. bool PTree::isBinary(const char *xpath) const
  1389. {
  1390. if (!xpath)
  1391. return IptFlagTst(flags, ipt_binary);
  1392. else if (isAttribute(xpath)) // still positing that attr cannot be binary for now.
  1393. return false;
  1394. else
  1395. {
  1396. const char *prop = splitXPathX(xpath);
  1397. if (prop && '\0' != *prop && !isAttribute(prop))
  1398. {
  1399. IPropertyTree *branch = queryPropTree(xpath);
  1400. if (branch)
  1401. return branch->isBinary(NULL);
  1402. }
  1403. }
  1404. return false;
  1405. }
  1406. bool PTree::renameTree(IPropertyTree *child, const char *newName) // really here for hook for SDS (can substationally optimize remote action)
  1407. {
  1408. if (0==strcmp(newName, child->queryName()) && NotFound!=findChild(child)) return false;
  1409. Linked<IPropertyTree> tmp = child;
  1410. if (removeTree(child))
  1411. {
  1412. addPropTree(newName, child);
  1413. tmp.getClear(); // addPropTree has taken ownership.
  1414. return true;
  1415. }
  1416. return false;
  1417. }
  1418. bool PTree::renameProp(const char *xpath, const char *newName)
  1419. {
  1420. if (!xpath || '\0' == *xpath)
  1421. throw MakeIPTException(-1, "renameProp: cannot rename self, renameProp has to rename in context of a parent");
  1422. if (strcmp(xpath,"/")==0) // rename of self allowed assuming no parent
  1423. setName(newName);
  1424. else if ('[' == *xpath)
  1425. UNIMPLEMENTED;
  1426. else if (isAttribute(xpath))
  1427. {
  1428. StringBuffer val;
  1429. if (!getProp(xpath, val))
  1430. return false;
  1431. removeProp(xpath);
  1432. addProp(newName, val.str());
  1433. }
  1434. else
  1435. {
  1436. StringBuffer path;
  1437. const char *prop = splitXPath(xpath, path);
  1438. assertex(prop);
  1439. if (path.length())
  1440. {
  1441. Owned<IPropertyTreeIterator> iter = getElements(path.str());
  1442. if (!iter->first())
  1443. return false;
  1444. IPropertyTree &branch = iter->query();
  1445. if (iter->next())
  1446. AMBIGUOUS_PATH("renameProp", xpath);
  1447. return branch.renameProp(prop, newName);
  1448. }
  1449. else
  1450. {
  1451. IPropertyTree *old = queryPropTree(xpath);
  1452. if (!old)
  1453. return false;
  1454. return renameTree(old, newName);
  1455. }
  1456. }
  1457. return true;
  1458. }
  1459. bool PTree::getPropBin(const char *xpath, MemoryBuffer &ret) const
  1460. {
  1461. CHECK_ATTRIBUTE(xpath);
  1462. if (!xpath)
  1463. {
  1464. if (!value) return true; // exists, but no value
  1465. value->getValue(ret, IptFlagTst(flags, ipt_binary));
  1466. return true;
  1467. }
  1468. else
  1469. {
  1470. const char *prop = splitXPathX(xpath);
  1471. if (isAttribute(prop))
  1472. {
  1473. MAKE_LSTRING(path, xpath, prop-xpath);
  1474. IPropertyTree *branch = queryPropTree(path);
  1475. if (!branch) return false;
  1476. return branch->getPropBin(prop, ret);
  1477. }
  1478. else
  1479. {
  1480. IPropertyTree *branch = queryPropTree(xpath);
  1481. if (!branch) return false;
  1482. return branch->getPropBin(NULL, ret);
  1483. }
  1484. }
  1485. }
  1486. void PTree::setPropBin(const char * xpath, size32_t size, const void *data)
  1487. {
  1488. CHECK_ATTRIBUTE(xpath);
  1489. if (!xpath || '\0' == *xpath)
  1490. setLocal(size, data, true);
  1491. else
  1492. {
  1493. const char *prop;
  1494. IPropertyTree *branch = splitBranchProp(xpath, prop, true);
  1495. if (isAttribute(prop))
  1496. branch->setPropBin(prop, size, data);
  1497. else
  1498. {
  1499. IPropertyTree *propBranch = queryCreateBranch(branch, prop);
  1500. propBranch->setPropBin(NULL, size, data);
  1501. }
  1502. }
  1503. }
  1504. void PTree::addPropBin(const char *xpath, size32_t size, const void *data)
  1505. {
  1506. CHECK_ATTRIBUTE(xpath);
  1507. if (!xpath || '\0' == *xpath)
  1508. addLocal(size, data, true);
  1509. else if ('[' == *xpath)
  1510. {
  1511. aindex_t pos = getChildMatchPos(xpath);
  1512. if (-1 == pos)
  1513. throw MakeIPTException(-1, "addPropBin: qualifier unmatched %s", xpath);
  1514. addLocal(size, data, true, pos);
  1515. }
  1516. else
  1517. {
  1518. IPropertyTree *parent, *child;
  1519. StringAttr path, qualifier;
  1520. resolveParentChild(xpath, parent, child, path, qualifier);
  1521. if (parent != this)
  1522. parent->addPropBin(path, size, data);
  1523. else if (child)
  1524. child->addPropBin(qualifier, size, data);
  1525. else
  1526. setPropBin(path, size, data);
  1527. }
  1528. }
  1529. void PTree::appendPropBin(const char *xpath, size32_t size, const void *data)
  1530. {
  1531. CHECK_ATTRIBUTE(xpath);
  1532. if (!xpath || '\0' == *xpath)
  1533. appendLocal(size, data, true);
  1534. else if ('[' == *xpath)
  1535. {
  1536. aindex_t pos = getChildMatchPos(xpath);
  1537. if (-1 == pos)
  1538. throw MakeIPTException(-1, "appendPropBin: qualifier unmatched %s", xpath);
  1539. appendLocal(size, data, true);
  1540. }
  1541. else
  1542. {
  1543. IPropertyTree *parent, *child;
  1544. StringAttr path, qualifier;
  1545. resolveParentChild(xpath, parent, child, path, qualifier);
  1546. if (parent != this)
  1547. parent->appendPropBin(path, size, data);
  1548. else if (child)
  1549. child->appendPropBin(qualifier, size, data);
  1550. else
  1551. setPropBin(path, size, data);
  1552. }
  1553. }
  1554. IPropertyTree *PTree::getPropTree(const char *xpath) const
  1555. {
  1556. IPropertyTree *tree = queryPropTree(xpath);
  1557. return LINK(tree);
  1558. }
  1559. IPropertyTree *PTree::queryPropTree(const char *xpath) const
  1560. {
  1561. Owned<IPropertyTreeIterator> iter = getElements(xpath);
  1562. IPropertyTree *element = NULL;
  1563. if (iter->first())
  1564. {
  1565. element = &iter->query();
  1566. if (iter->next())
  1567. {
  1568. #ifdef _DEBUG
  1569. AMBIGUOUS_PATH("getProp",xpath);
  1570. #else
  1571. LOG(MCoperatorWarning, unknownJob, "getProp: ambiguous xpath '%s', in parent node '%s'", xpath, queryName());
  1572. #endif
  1573. }
  1574. }
  1575. return element;
  1576. }
  1577. void PTree::replaceSelf(IPropertyTree *val)
  1578. {
  1579. Owned<IAttributeIterator> aiter = getAttributes();
  1580. StringArray attrs;
  1581. ForEach (*aiter)
  1582. attrs.append(aiter->queryName());
  1583. ForEachItemIn(a, attrs)
  1584. removeProp(attrs.item(a));
  1585. ICopyArrayOf<IPropertyTree> elems;
  1586. Owned<IPropertyTreeIterator> iter = getElements("*");
  1587. ForEach(*iter)
  1588. elems.append(iter->query());
  1589. ForEachItemIn(e, elems)
  1590. removeTree(&elems.item(e));
  1591. aiter.setown(val->getAttributes());
  1592. ForEach(*aiter)
  1593. setProp(aiter->queryName(), aiter->queryValue());
  1594. iter.setown(val->getElements("*"));
  1595. ForEach(*iter)
  1596. {
  1597. IPropertyTree &node = iter->query();
  1598. node.Link();
  1599. addPropTree(node.queryName(), &node);
  1600. }
  1601. val->Release();
  1602. }
  1603. IPropertyTree *PTree::setPropTree(const char *xpath, IPropertyTree *val)
  1604. {
  1605. CHECK_ATTRIBUTE(xpath);
  1606. if (NULL == xpath)
  1607. {
  1608. replaceSelf(val);
  1609. return this;
  1610. }
  1611. else
  1612. {
  1613. StringAttr prop, qualifier;
  1614. IPropertyTree *branch, *child;
  1615. resolveParentChild(xpath, branch, child, prop, qualifier);
  1616. if (branch == this)
  1617. {
  1618. IPropertyTree *_val = ownPTree(val);
  1619. PTree *__val = QUERYINTERFACE(_val, PTree); assertex(__val);
  1620. __val->setName(prop);
  1621. addingNewElement(*_val, ANE_SET);
  1622. if (!checkChildren()) createChildMap();
  1623. children->set(prop, _val);
  1624. return _val;
  1625. }
  1626. else
  1627. return branch->setPropTree(prop, val);
  1628. }
  1629. }
  1630. IPropertyTree *PTree::addPropTree(const char *xpath, IPropertyTree *val)
  1631. {
  1632. if (!xpath || '\0' == *xpath)
  1633. throw MakeIPTException(PTreeExcpt_InvalidTagName, "Invalid xpath for property tree insertion specified");
  1634. else
  1635. {
  1636. CHECK_ATTRIBUTE(xpath);
  1637. const char *x = xpath;
  1638. loop
  1639. {
  1640. if (!*x++)
  1641. {
  1642. IPropertyTree *_val = ownPTree(val);
  1643. PTree *__val = QUERYINTERFACE(_val, PTree); assertex(__val);
  1644. __val->setName(xpath);
  1645. addingNewElement(*_val, -1);
  1646. if (checkChildren())
  1647. {
  1648. IPropertyTree *child = children->query(xpath);
  1649. if (child)
  1650. {
  1651. __val->setParent(this);
  1652. PTree *tree = QUERYINTERFACE(child, PTree); assertex(tree);
  1653. if (tree->value && tree->value->isArray())
  1654. tree->value->addElement(_val);
  1655. else
  1656. {
  1657. IPTArrayValue *array = new CPTArray();
  1658. array->addElement(LINK(child));
  1659. array->addElement(_val);
  1660. IPropertyTree *container = create(xpath, array);
  1661. PTree *_tree = QUERYINTERFACE(child, PTree); assertex(_tree); _tree->setParent(this);
  1662. children->replace(xpath, container);
  1663. }
  1664. return _val;
  1665. }
  1666. }
  1667. else
  1668. createChildMap();
  1669. children->set(xpath, _val);
  1670. return _val;
  1671. }
  1672. if ('/' == *x || '[' == *x)
  1673. break;
  1674. }
  1675. IPropertyTree *parent, *child;
  1676. StringAttr path, qualifier;
  1677. resolveParentChild(xpath, parent, child, path, qualifier);
  1678. if (parent != this)
  1679. return parent->addPropTree(path, val);
  1680. else
  1681. {
  1682. aindex_t pos = (aindex_t)-1;
  1683. if (qualifier.length())
  1684. {
  1685. pos = ((PTree *)child)->getChildMatchPos(qualifier);
  1686. if (-1 == pos)
  1687. throw MakeIPTException(-1, "addPropTree: qualifier unmatched %s", xpath);
  1688. }
  1689. IPropertyTree *_val = ownPTree(val);
  1690. PTree *__val = QUERYINTERFACE(_val, PTree); assertex(__val);
  1691. __val->setName(path);
  1692. addingNewElement(*_val, pos);
  1693. if (child)
  1694. {
  1695. __val->setParent(this);
  1696. PTree *tree = QUERYINTERFACE(child, PTree); assertex(tree);
  1697. if (tree->value && tree->value->isArray())
  1698. {
  1699. if (-1 == pos)
  1700. tree->value->addElement(_val);
  1701. else
  1702. tree->value->setElement(pos, _val);
  1703. }
  1704. else
  1705. {
  1706. IPTArrayValue *array = new CPTArray();
  1707. array->addElement(LINK(child));
  1708. assertex(-1 == pos || 0 == pos);
  1709. if (-1 == pos)
  1710. array->addElement(_val);
  1711. else
  1712. array->setElement(0, _val);
  1713. IPropertyTree *container = create(path, array);
  1714. tree->setParent(this);
  1715. children->replace(path, container);
  1716. }
  1717. }
  1718. else
  1719. {
  1720. if (!checkChildren()) createChildMap();
  1721. children->set(path, _val);
  1722. }
  1723. return _val;
  1724. }
  1725. }
  1726. }
  1727. bool PTree::removeTree(IPropertyTree *child)
  1728. {
  1729. if (children)
  1730. {
  1731. Owned<IPropertyTreeIterator> iter = children->getIterator(false);
  1732. if (iter->first())
  1733. {
  1734. do
  1735. {
  1736. PTree *element = (PTree *) &iter->query();
  1737. if (element == child)
  1738. return children->removeExact(element);
  1739. if (element->value && element->value->isArray())
  1740. {
  1741. Linked<PTree> tmp = (PTree*) child;
  1742. aindex_t i = element->findChild(child, true);
  1743. if (NotFound != i)
  1744. {
  1745. removingElement(child, i);
  1746. if (0 == element->value->elements())
  1747. children->removeExact(element);
  1748. return true;
  1749. }
  1750. }
  1751. }
  1752. while (iter->next());
  1753. }
  1754. }
  1755. return false;
  1756. }
  1757. bool PTree::removeProp(const char *xpath)
  1758. {
  1759. if (xpath && isAttribute(xpath))
  1760. return removeAttr(xpath);
  1761. StringBuffer path;
  1762. const char *prop = splitXPath(xpath, path);
  1763. if (!prop)
  1764. throw MakeXPathException(xpath, PTreeExcpt_XPath_ParseError, 0, "Invalid xpath for property deletion");
  1765. if (path.length())
  1766. {
  1767. Owned<IPropertyTreeIterator> iter = getElements(path.str());
  1768. if (!iter)
  1769. return false;
  1770. bool res = false;
  1771. if (iter->first())
  1772. {
  1773. do
  1774. {
  1775. IPropertyTree *branch = &iter->query();
  1776. if (branch) {
  1777. res = branch->removeProp(prop);
  1778. if (res)
  1779. break; // deleted first may be another
  1780. }
  1781. }
  1782. while (iter->next());
  1783. }
  1784. return res;
  1785. }
  1786. else
  1787. {
  1788. if (!queryNextUnquoted(xpath, '[') && !strchr(prop, '*')) // have to work hard to locate qualified prop tree from parent.
  1789. {
  1790. if (!checkChildren()) return false;
  1791. return children->remove(prop); // NB: might be multivalued.
  1792. }
  1793. const char *xxpath = prop;
  1794. readID(xxpath, false);
  1795. const char *idEnd = xxpath;
  1796. if ('[' == *xxpath)
  1797. {
  1798. ++xxpath;
  1799. const char *digitStart = xxpath;
  1800. while (*xxpath && ']' != *xxpath && isdigit(*xxpath)) xxpath++;
  1801. assertex(*xxpath != '\0');
  1802. if (']' == *xxpath) // so it's a digit index!
  1803. {
  1804. StringAttr id(prop, idEnd-prop);
  1805. PTree *child = children?(PTree *)children->query(id):NULL;
  1806. if (child)
  1807. {
  1808. if (child->value && child->value->isArray() && child->value->elements()>1)
  1809. {
  1810. StringAttr digit(digitStart, xxpath-digitStart);
  1811. unsigned i = atoi(digit);
  1812. if (i <= child->value->elements())
  1813. {
  1814. removingElement(child->value->queryElement(i-1), i-1);
  1815. child->value->removeElement(i-1);
  1816. return true;
  1817. }
  1818. }
  1819. else
  1820. return children->removeExact(child);
  1821. }
  1822. return false;
  1823. }
  1824. }
  1825. // JCSMORE - This is ridiculous for qualifier have to iterate to find match ok, but then finding where that *was* gees!
  1826. Owned <IPropertyTreeIterator> iter = getElements(prop);
  1827. if (!iter->first())
  1828. return false;
  1829. IPropertyTree *match = &iter->query();
  1830. #if 0 // intentionally removes first encountered
  1831. if (iter->next())
  1832. {
  1833. AMBIGUOUS_PATH("removeProp",xpath);
  1834. }
  1835. #endif
  1836. return removeTree(match);
  1837. }
  1838. return false;
  1839. }
  1840. aindex_t PTree::queryChildIndex(IPropertyTree *child)
  1841. {
  1842. return findChild(child);
  1843. }
  1844. const char *PTree::queryName() const
  1845. {
  1846. return name?name->get():NULL;
  1847. }
  1848. StringBuffer &PTree::getName(StringBuffer &ret) const
  1849. {
  1850. ret.append(queryName());
  1851. return ret;
  1852. }
  1853. MAKEPointerArray(AttrValue, AttrArray);
  1854. IAttributeIterator *PTree::getAttributes(bool sorted) const
  1855. {
  1856. class CAttributeIterator : public CInterface, implements IAttributeIterator
  1857. {
  1858. public:
  1859. IMPLEMENT_IINTERFACE;
  1860. CAttributeIterator(const PTree *_parent) : parent(_parent), cur(NULL)
  1861. {
  1862. index = 0;
  1863. cur = NULL;
  1864. }
  1865. ~CAttributeIterator()
  1866. {
  1867. }
  1868. // IAttributeIterator impl.
  1869. virtual bool first()
  1870. {
  1871. index = 0;
  1872. if (!parent->queryAttributes().count()) {
  1873. cur = NULL;
  1874. return false;
  1875. }
  1876. cur = parent->queryAttributes().item(0);
  1877. return true;
  1878. }
  1879. virtual bool next()
  1880. {
  1881. index++;
  1882. if (index>=parent->queryAttributes().count()) {
  1883. cur = NULL;
  1884. return false;
  1885. }
  1886. cur = parent->queryAttributes().item(index);
  1887. return true;
  1888. }
  1889. virtual bool isValid() { return cur!=NULL; }
  1890. virtual const char *queryName() const
  1891. {
  1892. assertex(cur);
  1893. return cur->key->get();
  1894. }
  1895. virtual const char *queryValue() const
  1896. {
  1897. assertex(cur);
  1898. return cur->value->get();
  1899. }
  1900. virtual StringBuffer &getValue(StringBuffer &out)
  1901. {
  1902. assertex(cur);
  1903. out.append(cur->value->get());
  1904. return out;
  1905. }
  1906. virtual unsigned count() { return parent->queryAttributes().count(); }
  1907. private:
  1908. AttrValue *cur;
  1909. unsigned index;
  1910. Linked<const PTree> parent;
  1911. };
  1912. class CSortedAttributeIterator : public CInterface, implements IAttributeIterator
  1913. {
  1914. typedef ArrayIteratorOf<AttrArray, AttrValue &> AttrIterator;
  1915. public:
  1916. IMPLEMENT_IINTERFACE;
  1917. static int compareAttrs(AttrValue **ll, AttrValue **rr)
  1918. {
  1919. return stricmp((*ll)->key->get(), (*rr)->key->get());
  1920. };
  1921. CSortedAttributeIterator(const PTree *_parent) : parent(_parent), iter(NULL), cur(NULL)
  1922. {
  1923. unsigned i = parent->queryAttributes().count();
  1924. if (i)
  1925. {
  1926. attrs.ensure(i);
  1927. while (i--)
  1928. attrs.append(*parent->queryAttributes().item(i));
  1929. attrs.sort(compareAttrs);
  1930. iter = new AttrIterator(attrs);
  1931. }
  1932. }
  1933. ~CSortedAttributeIterator()
  1934. {
  1935. if (iter)
  1936. delete iter;
  1937. }
  1938. // IAttributeIterator impl.
  1939. virtual bool first()
  1940. {
  1941. if (!iter) return false;
  1942. if (!iter->first()) { cur = NULL; return false; }
  1943. cur = &iter->query();
  1944. return true;
  1945. }
  1946. virtual bool next()
  1947. {
  1948. if (!iter) return false;
  1949. if (!iter->next()) { cur = NULL; return false; }
  1950. cur = &iter->query();
  1951. return true;
  1952. }
  1953. virtual bool isValid() { return cur!=NULL; }
  1954. virtual const char *queryName() const
  1955. {
  1956. assertex(cur);
  1957. return cur->key->get();
  1958. }
  1959. virtual const char *queryValue() const
  1960. {
  1961. assertex(cur);
  1962. return cur->value->get();
  1963. }
  1964. virtual StringBuffer &getValue(StringBuffer &out)
  1965. {
  1966. assertex(cur);
  1967. out.append(cur->value->get());
  1968. return out;
  1969. }
  1970. virtual unsigned count() { return attrs.ordinality(); }
  1971. private:
  1972. AttrArray attrs;
  1973. AttrValue *cur;
  1974. AttrIterator *iter;
  1975. Linked<const PTree> parent;
  1976. };
  1977. if (sorted)
  1978. return new CSortedAttributeIterator(this);
  1979. else
  1980. return new CAttributeIterator(this);
  1981. }
  1982. ///////////////////
  1983. class CIndexIterator : public CInterface, implements IPropertyTreeIterator
  1984. {
  1985. Owned<IPropertyTreeIterator> subIter;
  1986. IPropertyTree *celem;
  1987. unsigned index, current;
  1988. public:
  1989. IMPLEMENT_IINTERFACE;
  1990. CIndexIterator(IPropertyTreeIterator *_subIter, unsigned _index) : subIter(_subIter), index(_index)
  1991. {
  1992. }
  1993. // IPropertyTreeIterator
  1994. virtual bool first()
  1995. {
  1996. if (!index)
  1997. return false;
  1998. if (!subIter->first())
  1999. return false;
  2000. current = 1;
  2001. celem = NULL;
  2002. do
  2003. {
  2004. if (current == index)
  2005. {
  2006. celem = &subIter->query();
  2007. return true;
  2008. }
  2009. if (!subIter->next())
  2010. return false;
  2011. } while (++current <= index);
  2012. return false;
  2013. }
  2014. virtual bool isValid()
  2015. {
  2016. return celem && (index >= current);
  2017. }
  2018. virtual bool next()
  2019. {
  2020. celem = NULL;
  2021. return false;
  2022. }
  2023. virtual IPropertyTree & query()
  2024. {
  2025. return *celem;
  2026. }
  2027. };
  2028. IPropertyTreeIterator *PTree::getElements(const char *xpath, IPTIteratorCodes flags) const
  2029. {
  2030. // NULL iterator for local value (i.e. maybe be single value or array)
  2031. if (NULL == xpath || '\0' == *xpath)
  2032. return new SingleIdIterator(*this);
  2033. Owned<IPropertyTreeIterator> iter;
  2034. const char *_xpath = xpath;
  2035. bool root=true;
  2036. restart:
  2037. switch (*xpath)
  2038. {
  2039. case '.':
  2040. root=false;
  2041. ++xpath;
  2042. if ('\0' == *xpath)
  2043. return new SingleIdIterator(*this);
  2044. else if ('/' != *xpath)
  2045. throw MakeXPathException(xpath-1, PTreeExcpt_XPath_Unsupported, 0, "");
  2046. goto restart;
  2047. case '/':
  2048. ++xpath;
  2049. if ('/' == *xpath)
  2050. {
  2051. iter.setown(getElements(xpath+1));
  2052. if (checkChildren())
  2053. {
  2054. IPropertyTreeIterator *iter2 = new PTIdMatchIterator(this, "*", isnocase(), flags & iptiter_sort);
  2055. iter2 = new PTStackIterator(iter2, xpath-1);
  2056. SeriesPTIterator *series = new SeriesPTIterator();
  2057. series->addIterator(iter.getClear());
  2058. series->addIterator(iter2);
  2059. return series;
  2060. }
  2061. else
  2062. return iter.getClear();
  2063. }
  2064. else if (root)
  2065. throw MakeXPathException(xpath, PTreeExcpt_XPath_Unsupported, 0, "Root specifier \"/\" specifier is not supported");
  2066. else if ('\0' == *xpath)
  2067. return new SingleIdIterator(*this);
  2068. goto restart;
  2069. case '[':
  2070. {
  2071. ++xpath;
  2072. if (isdigit(*xpath)) {
  2073. StringAttr index;
  2074. xpath = readIndex(xpath, index);
  2075. unsigned i = atoi(index.get());
  2076. if (i)
  2077. {
  2078. if (value && value->isArray())
  2079. {
  2080. IPropertyTree *element = value->queryElement(--i);
  2081. if (element)
  2082. {
  2083. iter.setown(element->getElements(NULL));
  2084. }
  2085. }
  2086. else if (i == 1)
  2087. iter.setown(new SingleIdIterator(*this));
  2088. }
  2089. }
  2090. else
  2091. {
  2092. if (checkPattern(xpath))
  2093. iter.setown(new SingleIdIterator(*this));
  2094. }
  2095. if (']' != *xpath)
  2096. throw MakeXPathException(_xpath, PTreeExcpt_XPath_ParseError, xpath-_xpath, "Qualifier brace unclosed");
  2097. ++xpath;
  2098. break;
  2099. }
  2100. default:
  2101. {
  2102. bool wild;
  2103. const char *start = xpath;
  2104. readWildId(xpath, wild);
  2105. size32_t s = xpath-start;
  2106. if (s)
  2107. {
  2108. MAKE_LSTRING(id, start, s);
  2109. if (checkChildren())
  2110. {
  2111. IPropertyTree *child = NULL;
  2112. if (!wild)
  2113. child = children->query(id);
  2114. if ((wild || child) && '[' == *xpath) // check for local index not iterative qualifier.
  2115. {
  2116. const char *xxpath = xpath+1;
  2117. if (isdigit(*xxpath)) {
  2118. StringAttr idxstr;
  2119. xxpath = readIndex(xxpath, idxstr);
  2120. if (']' != *xxpath)
  2121. throw MakeXPathException(_xpath, PTreeExcpt_XPath_ParseError, xpath-_xpath, "Qualifier brace unclosed");
  2122. ++xxpath;
  2123. unsigned index = atoi(idxstr.get());
  2124. if (index)
  2125. {
  2126. Owned<IPropertyTreeIterator> _iter = getElements(id);
  2127. if (_iter->first())
  2128. {
  2129. do
  2130. {
  2131. if (0 == --index)
  2132. {
  2133. iter.setown(new SingleIdIterator((PTree &)_iter->query()));
  2134. break;
  2135. }
  2136. }
  2137. while (_iter->next());
  2138. }
  2139. }
  2140. xpath = xxpath;
  2141. }
  2142. else
  2143. {
  2144. if (wild)
  2145. iter.setown(new PTIdMatchIterator(this, id, isnocase(), flags & iptiter_sort));
  2146. else
  2147. iter.setown(child->getElements(NULL));
  2148. const char *start = xxpath-1;
  2149. loop
  2150. {
  2151. char quote = 0;
  2152. while (']' != *(++xxpath) || quote)
  2153. {
  2154. switch (*xxpath) {
  2155. case '\"':
  2156. case '\'':
  2157. {
  2158. if (quote)
  2159. {
  2160. if (*xxpath == quote)
  2161. quote = 0;
  2162. }
  2163. else
  2164. quote = *xxpath;
  2165. break;
  2166. }
  2167. case '\0':
  2168. throw MakeXPathException(start, PTreeExcpt_XPath_ParseError, xxpath-start, "Qualifier brace unclosed");
  2169. }
  2170. }
  2171. ++xxpath;
  2172. if ('[' == *xxpath)
  2173. {
  2174. ++xxpath;
  2175. if (isdigit(*xxpath))
  2176. {
  2177. StringAttr qualifier(start, (xxpath-1)-start);
  2178. Owned<PTStackIterator> siter = new PTStackIterator(iter.getClear(), qualifier.get());
  2179. StringAttr index;
  2180. xxpath = readIndex(xxpath, index);
  2181. unsigned i = atoi(index.get());
  2182. iter.setown(new CIndexIterator(siter.getClear(), i));
  2183. ++xxpath;
  2184. break;
  2185. }
  2186. }
  2187. else
  2188. {
  2189. StringAttr qualifier(start, xxpath-start);
  2190. iter.setown(new PTStackIterator(iter.getClear(), qualifier.get()));
  2191. break;
  2192. }
  2193. }
  2194. xpath = xxpath;
  2195. }
  2196. }
  2197. else
  2198. {
  2199. if (wild)
  2200. iter.setown(new PTIdMatchIterator(this, id, isnocase(), flags & iptiter_sort));
  2201. else if (child)
  2202. iter.setown(child->getElements(NULL));
  2203. }
  2204. }
  2205. }
  2206. break;
  2207. }
  2208. }
  2209. if (!iter)
  2210. iter.setown(LINK(nullPTreeIterator));
  2211. if (*xpath == '\0' || (*xpath == '/' && '\0' == *(xpath+1)))
  2212. return iter.getClear();
  2213. else
  2214. return new PTStackIterator(iter.getClear(), xpath);
  2215. }
  2216. void PTree::localizeElements(const char *xpath, bool allTail)
  2217. {
  2218. // null action for local ptree
  2219. }
  2220. unsigned PTree::numChildren()
  2221. {
  2222. if (!checkChildren()) return 0;
  2223. return children->numChildren();
  2224. }
  2225. void getXPathMatchTree(IPropertyTree &parentContext, const char *xpath, IPropertyTree *&matchContainer)
  2226. {
  2227. if (!xpath || !*xpath)
  2228. {
  2229. matchContainer = createPTree(parentContext.queryName());
  2230. return;
  2231. }
  2232. StringBuffer head;
  2233. const char *str = xpath;
  2234. const char *end = str+strlen(xpath);
  2235. bool quote = false;
  2236. bool inQualifier = false;
  2237. bool done = false;
  2238. bool recurse = false;
  2239. while (end != str)
  2240. {
  2241. switch (*str) {
  2242. case '"':
  2243. if (quote) quote = false;
  2244. else quote = true;
  2245. break;
  2246. case '[':
  2247. if (inQualifier)
  2248. {
  2249. if (!quote)
  2250. throw MakeXPathException(xpath, PTreeExcpt_XPath_ParseError, str-xpath, "Unclosed qualifier detected");
  2251. }
  2252. else
  2253. inQualifier = true;
  2254. break;
  2255. case ']':
  2256. if (inQualifier)
  2257. {
  2258. if (!quote)
  2259. inQualifier = false;
  2260. }
  2261. else if (!quote)
  2262. throw MakeXPathException(xpath, PTreeExcpt_XPath_ParseError, str-xpath, "Unopened qualifier detected");
  2263. break;
  2264. case '/':
  2265. if (!quote && !inQualifier)
  2266. {
  2267. if ('/' == *(str+1))
  2268. recurse = true;
  2269. done = true;
  2270. }
  2271. break;
  2272. }
  2273. if (done) break;
  2274. ++str;
  2275. }
  2276. const char *tail;
  2277. if (str==end) // top-level matches
  2278. {
  2279. head.append(xpath);
  2280. if (0 == head.length())
  2281. {
  2282. matchContainer = createPTree(xpath);
  2283. return;
  2284. }
  2285. tail = NULL;
  2286. }
  2287. else
  2288. {
  2289. head.append(str-xpath, xpath);
  2290. if (recurse)
  2291. tail = str+2;
  2292. else
  2293. tail = str+1;
  2294. }
  2295. Owned<IPropertyTreeIterator> parentIter = parentContext.getElements(head.str());
  2296. Owned<IPropertyTree> matchParent;
  2297. ForEach (*parentIter)
  2298. {
  2299. IPropertyTree &parent = parentIter->query();
  2300. if (!matchParent)
  2301. matchParent.setown(createPTree(parentContext.queryName()));
  2302. if (tail && *tail)
  2303. {
  2304. IPropertyTree *childContainer = NULL;
  2305. getXPathMatchTree(parent, tail, childContainer);
  2306. if (childContainer)
  2307. {
  2308. if (!head.length())
  2309. matchParent.setown(childContainer);
  2310. else
  2311. {
  2312. unsigned pos = ((PTree &)parentContext).findChild(&parent);
  2313. matchParent->addPropTree(childContainer->queryName(), childContainer);
  2314. childContainer->setPropInt("@pos", pos+1);
  2315. }
  2316. if (!matchContainer)
  2317. matchContainer = LINK(matchParent);
  2318. }
  2319. if (recurse)
  2320. {
  2321. Owned<IPropertyTreeIterator> iter = parent.getElements("*");
  2322. ForEach (*iter)
  2323. {
  2324. IPropertyTree *childContainer = NULL;
  2325. IPropertyTree &child = iter->query();
  2326. getXPathMatchTree(child, xpath, childContainer);
  2327. if (childContainer)
  2328. {
  2329. unsigned pos = ((PTree &)parent).findChild(&child);
  2330. matchParent->addPropTree(childContainer->queryName(), childContainer);
  2331. childContainer->setPropInt("@pos", pos+1);
  2332. if (!matchContainer)
  2333. matchContainer = LINK(matchParent);
  2334. }
  2335. }
  2336. }
  2337. }
  2338. else
  2339. {
  2340. if (&parent != &parentContext)
  2341. {
  2342. IPropertyTree *childContainer = matchParent->addPropTree(parent.queryName(), createPTree());
  2343. unsigned pos = ((PTree &)parentContext).findChild(&parent);
  2344. childContainer->setPropInt("@pos", pos+1);
  2345. }
  2346. if (!matchContainer)
  2347. matchContainer = LINK(matchParent);
  2348. }
  2349. }
  2350. }
  2351. IPropertyTree *getXPathMatchTree(IPropertyTree &parent, const char *xpath)
  2352. {
  2353. IPropertyTree *matchTree = NULL;
  2354. getXPathMatchTree(parent, xpath, matchTree);
  2355. return matchTree;
  2356. }
  2357. void PTree::serializeAttributes(MemoryBuffer &tgt)
  2358. {
  2359. IAttributeIterator *aIter = getAttributes();
  2360. if (aIter->first())
  2361. {
  2362. do
  2363. {
  2364. tgt.append(aIter->queryName());
  2365. tgt.append(aIter->queryValue());
  2366. }
  2367. while (aIter->next());
  2368. }
  2369. tgt.append(""); // attribute terminator. i.e. blank attr name.
  2370. aIter->Release();
  2371. }
  2372. void PTree::serializeSelf(MemoryBuffer &tgt)
  2373. {
  2374. tgt.append(name ? name->get() : "");
  2375. tgt.append(flags);
  2376. serializeAttributes(tgt);
  2377. if (value)
  2378. value->serialize(tgt);
  2379. else
  2380. tgt.append((size32_t)0);
  2381. }
  2382. void PTree::serializeCutOff(MemoryBuffer &tgt, int cutoff, int depth)
  2383. {
  2384. serializeSelf(tgt);
  2385. if (-1 == cutoff || depth<cutoff)
  2386. {
  2387. Owned<IPropertyTreeIterator> iter = getElements("*");
  2388. if (iter->first())
  2389. {
  2390. do
  2391. {
  2392. IPropertyTree *_child = &iter->query();
  2393. PTree *child = QUERYINTERFACE(_child, PTree); assertex(child);
  2394. child->serializeCutOff(tgt, cutoff, depth+1);
  2395. }
  2396. while (iter->next());
  2397. }
  2398. }
  2399. tgt.append(""); // element terminator. i.e. blank child name.
  2400. }
  2401. // serializable impl.
  2402. void PTree::serialize(MemoryBuffer &tgt)
  2403. {
  2404. serializeCutOff(tgt, -1, 0);
  2405. }
  2406. void PTree::deserialize(MemoryBuffer &src)
  2407. {
  2408. deserializeSelf(src);
  2409. StringAttr eName;
  2410. loop
  2411. {
  2412. size32_t pos = src.getPos();
  2413. src.read(eName);
  2414. if (!eName.length())
  2415. break;
  2416. src.reset(pos); // reset to re-read tree name
  2417. IPropertyTree *child = create(src);
  2418. addPropTree(eName, child);
  2419. }
  2420. }
  2421. void PTree::deserializeSelf(MemoryBuffer &src)
  2422. {
  2423. setName(NULL); // needs to be cleared before flags changed
  2424. StringAttr _name;
  2425. src.read(_name);
  2426. src.read(flags);
  2427. if (_name[0]==0)
  2428. setName(NULL);
  2429. else
  2430. setName(_name);
  2431. attributes.setNoCase(isnocase());
  2432. StringAttr attrName, attrValue;
  2433. loop
  2434. {
  2435. src.read(attrName);
  2436. if (!attrName.length())
  2437. break;
  2438. src.read(attrValue);
  2439. setProp(attrName, attrValue);
  2440. }
  2441. size32_t size;
  2442. unsigned pos = src.getPos();
  2443. src.read(size);
  2444. if (value) delete value;
  2445. if (size)
  2446. {
  2447. src.reset(pos);
  2448. value = new CPTValue(src);
  2449. }
  2450. else value = NULL;
  2451. }
  2452. void PTree::init()
  2453. {
  2454. flags = 0;
  2455. name = NULL;
  2456. value = NULL;
  2457. children = NULL;
  2458. parent = NULL;
  2459. }
  2460. void PTree::clear()
  2461. {
  2462. attributes.kill();
  2463. if (children) { children->Release(); children = NULL; }
  2464. if (value) { delete value; value = NULL; }
  2465. }
  2466. IPropertyTree *PTree::clone(IPropertyTree &srcTree, bool self, bool sub)
  2467. {
  2468. IPropertyTree *_dstTree = self ? this : create(srcTree.queryName());
  2469. PTree *dstTree = QUERYINTERFACE(_dstTree, PTree);
  2470. assertex(dstTree);
  2471. dstTree->setName(srcTree.queryName());
  2472. clone(srcTree, *dstTree, sub);
  2473. return _dstTree;
  2474. }
  2475. void PTree::clone(IPropertyTree &srcTree, IPropertyTree &dstTree, bool sub)
  2476. {
  2477. PTree *_dstTree = QUERYINTERFACE((&dstTree), PTree); assertex(_dstTree); //JCSMORE
  2478. flags = _dstTree->flags;
  2479. if (srcTree.isBinary(NULL))
  2480. {
  2481. MemoryBuffer mb;
  2482. verifyex(srcTree.getPropBin(NULL, mb));
  2483. dstTree.setPropBin(NULL, mb.length(), mb.toByteArray());
  2484. }
  2485. else if (srcTree.isCompressed(NULL))
  2486. {
  2487. StringBuffer s;
  2488. verifyex(srcTree.getProp(NULL, s));
  2489. dstTree.setProp(NULL, s.toCharArray());
  2490. }
  2491. else
  2492. dstTree.setProp(NULL, srcTree.queryProp(NULL));
  2493. IAttributeIterator *attrs = srcTree.getAttributes();
  2494. if (attrs->first())
  2495. {
  2496. do
  2497. {
  2498. dstTree.setProp(attrs->queryName(), attrs->queryValue());
  2499. }
  2500. while (attrs->next());
  2501. }
  2502. attrs->Release();
  2503. if (sub)
  2504. {
  2505. Owned<IPropertyTreeIterator> iter = srcTree.getElements("*");
  2506. if (iter->first())
  2507. {
  2508. do
  2509. {
  2510. IPropertyTree &child = iter->query();
  2511. IPropertyTree *newChild = clone(child, false, sub);
  2512. StringAttr name(newChild->queryName());
  2513. dstTree.addPropTree(name, newChild);
  2514. }
  2515. while (iter->next());
  2516. }
  2517. }
  2518. }
  2519. IPropertyTree *PTree::ownPTree(IPropertyTree *tree)
  2520. {
  2521. if (!isEquivalent(tree) || tree->IsShared() || isCaseInsensitive() != tree->isCaseInsensitive())
  2522. {
  2523. IPropertyTree *newTree = clone(*tree);
  2524. tree->Release();
  2525. return newTree;
  2526. }
  2527. else
  2528. return tree;
  2529. }
  2530. IPropertyTree *PTree::queryCreateBranch(IPropertyTree *branch, const char *prop, bool *newBranch)
  2531. {
  2532. IPropertyTree *childBranch = branch->queryPropTree(prop);
  2533. if (!childBranch)
  2534. {
  2535. if (newBranch) *newBranch = true;
  2536. childBranch = create(prop);
  2537. branch->setPropTree(prop, childBranch);
  2538. }
  2539. else if (newBranch) *newBranch = false;
  2540. return childBranch;
  2541. }
  2542. IPropertyTree *PTree::splitBranchProp(const char *xpath, const char *&prop, bool error)
  2543. {
  2544. prop = splitXPathX(xpath);
  2545. MAKE_LSTRING(path, xpath, prop-xpath);
  2546. IPropertyTree *branch = queryPropTree(path);
  2547. if (!branch && error)
  2548. throw MakeIPTException(-1, "path %s not found, when setting prop %s", path, xpath);
  2549. return branch;
  2550. }
  2551. IPropertyTree *_createPropBranch(IPropertyTree *tree, const char *xpath, bool createIntermediates, IPropertyTree *&created, IPropertyTree *&createdParent)
  2552. {
  2553. const char *prop;
  2554. StringBuffer path;
  2555. prop = splitXPathUQ(xpath, path);
  2556. IPropertyTree *branch = tree->queryPropTree(path.str());
  2557. if (!branch)
  2558. {
  2559. if (path.length() == strlen(xpath))
  2560. throw MakeIPTException(-1, "createPropBranch: cannot create path : %s", xpath);
  2561. if (!createIntermediates)
  2562. throw MakeIPTException(-1, "createPropBranch: no path found for : %s", path.str());
  2563. if ('/' == path.charAt(path.length()-1))
  2564. path.remove(path.length()-1, 1);
  2565. branch = _createPropBranch(tree, path.str(), createIntermediates, created, createdParent);
  2566. assertex(branch);
  2567. }
  2568. if (prop && '\0' != *prop && '@' != *prop)
  2569. {
  2570. IPropertyTree *_branch = branch->queryPropTree(prop);
  2571. if (_branch)
  2572. branch = _branch;
  2573. else
  2574. {
  2575. IPropertyTree *p = branch;
  2576. branch = branch->addPropTree(prop, createPTree());
  2577. if (!created) { created = branch; createdParent = p; }
  2578. }
  2579. }
  2580. return branch;
  2581. }
  2582. IPropertyTree *createPropBranch(IPropertyTree *tree, const char *xpath, bool createIntermediates, IPropertyTree **created, IPropertyTree **createdParent)
  2583. {
  2584. IPropertyTree *_created = NULL, *_createdParent = NULL;
  2585. try
  2586. {
  2587. IPropertyTree *ret = _createPropBranch(tree, xpath, createIntermediates, _created, _createdParent);
  2588. if (created) *created = _created;
  2589. if (createdParent) *createdParent = _createdParent;
  2590. return ret;
  2591. }
  2592. catch (...)
  2593. {
  2594. if (_created) (_createdParent)->removeTree(_created);
  2595. throw;
  2596. }
  2597. }
  2598. void PTree::addLocal(size32_t l, const void *data, bool _binary, int pos)
  2599. {
  2600. if (!l) return; // right thing to do on addProp("x", NULL) ?
  2601. IPTArrayValue *newValue = new CPTValue(l, data, _binary);
  2602. Owned<IPropertyTree> tree = create(queryName(), newValue);
  2603. PTree *_tree = QUERYINTERFACE(tree.get(), PTree); assertex(_tree); _tree->setParent(this);
  2604. addingNewElement(*tree, pos);
  2605. IPTArrayValue *array;
  2606. if (value && value->isArray())
  2607. {
  2608. array = value;
  2609. if (pos != -1 && ((unsigned)pos > array->elements()))
  2610. throw MakeIPTException(-1, "Error trying to insert element at %d of %d", pos, array->elements());
  2611. }
  2612. else
  2613. {
  2614. if (pos > 0)
  2615. throw MakeIPTException(-1, "Error trying to insert element at %d of 0", pos);
  2616. array = new CPTArray();
  2617. // detach children and attributes of this branch now owned by element of newly created array.
  2618. IPropertyTree *tree = create(queryName(), value, children, true);
  2619. PTree *_tree = QUERYINTERFACE(tree, PTree); assertex(_tree); _tree->setParent(this);
  2620. ::Release(children);
  2621. attributes.swap(_tree->attributes);
  2622. children = NULL;
  2623. addingNewElement(*tree, ANE_APPEND);
  2624. array->addElement(tree);
  2625. value = array;
  2626. }
  2627. tree->Link();
  2628. if (-1 == pos)
  2629. array->addElement(tree);
  2630. else
  2631. array->setElement(pos, tree);
  2632. if (_binary)
  2633. IptFlagSet(flags, ipt_binary);
  2634. else
  2635. IptFlagClr(flags, ipt_binary);
  2636. }
  2637. enum exprType { t_none, t_equality, t_inequality, t_lteq, t_lt, t_gt, t_gteq } tType;
  2638. inline bool match(bool wild, bool numeric, const char *xpath, exprType t, const char *value, unsigned len, const char *pat, unsigned patLen, bool nocase)
  2639. {
  2640. int m;
  2641. if (numeric)
  2642. {
  2643. __int64 lhsN = atoi64_l(value, len);
  2644. __int64 rhsN = atoi64_l(pat, patLen);
  2645. m = lhsN<rhsN?-1:lhsN>rhsN?1:0;
  2646. }
  2647. else if (wild)
  2648. m = false==WildMatch(value, len, pat, patLen, nocase);
  2649. else
  2650. {
  2651. if (len == patLen)
  2652. m = nocase ? memicmp(value, pat, len) : memcmp(value, pat, len);
  2653. else if (len < patLen)
  2654. m = -1;
  2655. else
  2656. m = 1;
  2657. }
  2658. switch (t)
  2659. {
  2660. case t_inequality:
  2661. return m!=0;
  2662. case t_lt:
  2663. return m<0;
  2664. case t_lteq:
  2665. return m<=0;
  2666. case t_equality:
  2667. return m==0;
  2668. case t_gteq:
  2669. return m>=0;
  2670. case t_gt:
  2671. return m>0;
  2672. }
  2673. throw MakeXPathException(xpath, PTreeExcpt_XPath_ParseError, 0, "Invalid xpath qualifier expression in xpath: %s", xpath);
  2674. }
  2675. bool PTree::checkPattern(const char *&xxpath) const
  2676. {
  2677. // Pattern is an additional filter at the current node level
  2678. // It can be [condition], or it can be empty (we don't support anything else)
  2679. // supported conditions are:
  2680. // tag - must have child called tag
  2681. // @attr - must have attribute called attr
  2682. // tag="value" - must have child called tag with given value
  2683. // @attr="value" - must have attribute called attr with given value
  2684. const char *xpath = xxpath;
  2685. while (*xpath == ' ' || *xpath == '\t') xpath++;
  2686. const char *start = xpath;
  2687. bool wild = false, nocase = isnocase();
  2688. if (*xpath=='@')
  2689. xpath++;
  2690. char quote = 0;
  2691. const char *lhsEnd, *quoteBegin, *quoteEnd, *rhsBegin, *rhsEnd;
  2692. lhsEnd = quoteBegin = quoteEnd = rhsBegin = rhsEnd = NULL;
  2693. exprType tType = t_none;
  2694. bool numeric=false;
  2695. #ifdef WARNLEGACYCOMPARE
  2696. bool legacynumeric=false;
  2697. #endif
  2698. loop
  2699. {
  2700. switch (*xpath) {
  2701. case '"':
  2702. case '\'':
  2703. if (quote)
  2704. {
  2705. if (*xpath == quote)
  2706. {
  2707. quote = 0;
  2708. quoteEnd = xpath;
  2709. }
  2710. }
  2711. else
  2712. {
  2713. if (quoteBegin)
  2714. throw MakeXPathException(start, PTreeExcpt_XPath_ParseError, xpath-start, "Quoted left hand side already seen");
  2715. quote = *xpath;
  2716. quoteBegin = xpath+1;
  2717. }
  2718. break;
  2719. case '[':
  2720. if (!quote)
  2721. throw MakeXPathException(start, PTreeExcpt_XPath_ParseError, xpath-start, "Unclosed qualifier detected");
  2722. break;
  2723. case ']':
  2724. if (!quote)
  2725. {
  2726. if (!lhsEnd)
  2727. lhsEnd = xpath;
  2728. rhsEnd = xpath;
  2729. }
  2730. break;
  2731. case ' ':
  2732. case '\t':
  2733. if (!lhsEnd)
  2734. lhsEnd = xpath;
  2735. break;
  2736. case '!':
  2737. if (!quote)
  2738. {
  2739. if (tType)
  2740. throw MakeXPathException(start, PTreeExcpt_XPath_ParseError, xpath-start, "Unexpected expression operator xpath");
  2741. if ('=' != *(xpath+1))
  2742. throw MakeXPathException(start, PTreeExcpt_XPath_ParseError, xpath-start, "Invalid xpath qualifier expression in xpath");
  2743. if (!lhsEnd)
  2744. lhsEnd = xpath;
  2745. ++xpath;
  2746. tType = t_inequality;
  2747. wild = true; // true by default now, introduced ~ syntax, to denote wild string
  2748. }
  2749. break;
  2750. case '=':
  2751. if (!quote)
  2752. {
  2753. if (wild)
  2754. throw MakeXPathException(start, PTreeExcpt_XPath_ParseError, xpath-start, "Wildcard match '~' makes no sense in this context");
  2755. if (tType)
  2756. throw MakeXPathException(start, PTreeExcpt_XPath_ParseError, xpath-start, "Unexpected expression operator xpath");
  2757. tType = t_equality;
  2758. wild = true; // true by default now, introduced ~ syntax, to denote wild string
  2759. if (!lhsEnd)
  2760. lhsEnd = xpath;
  2761. }
  2762. break;
  2763. case '>':
  2764. if (!quote)
  2765. {
  2766. if (wild)
  2767. throw MakeXPathException(start, PTreeExcpt_XPath_ParseError, xpath-start, "Wildcard match '~' makes no sense in this context");
  2768. if (tType)
  2769. throw MakeXPathException(start, PTreeExcpt_XPath_ParseError, xpath-start, "Unexpected expression operator in xpath");
  2770. if (!lhsEnd)
  2771. lhsEnd = xpath;
  2772. #ifdef WARNLEGACYCOMPARE
  2773. legacynumeric = true;
  2774. #endif
  2775. if ('=' == *(xpath+1))
  2776. {
  2777. ++xpath;
  2778. tType = t_gteq;
  2779. }
  2780. else
  2781. tType = t_gt;
  2782. }
  2783. break;
  2784. case '<':
  2785. if (!quote)
  2786. {
  2787. if (tType)
  2788. throw MakeXPathException(start, PTreeExcpt_XPath_ParseError, xpath-start, "Unexpected expression operator in xpath");
  2789. if (!lhsEnd)
  2790. lhsEnd = xpath;
  2791. #ifdef WARNLEGACYCOMPARE
  2792. legacynumeric = true;
  2793. #endif
  2794. if ('=' == *(xpath+1))
  2795. {
  2796. ++xpath;
  2797. tType = t_lteq;
  2798. }
  2799. else
  2800. tType = t_lt;
  2801. }
  2802. break;
  2803. case '~':
  2804. if (!quote)
  2805. {
  2806. if (!tType)
  2807. throw MakeXPathException(start, PTreeExcpt_XPath_ParseError, xpath-start, "Unexpected wild operator in xpath");
  2808. wild = true;
  2809. }
  2810. break;
  2811. case '?':
  2812. if (!quote)
  2813. {
  2814. if (!tType)
  2815. throw MakeXPathException(start, PTreeExcpt_XPath_ParseError, xpath-start, "Unexpected case-insensitive operator in xpath");
  2816. nocase = true;
  2817. }
  2818. break;
  2819. case '\0':
  2820. rhsEnd = xpath;
  2821. break;
  2822. }
  2823. if (rhsEnd)
  2824. break;
  2825. xpath++;
  2826. if (!rhsBegin && tType && !isspace(*xpath))
  2827. rhsBegin = xpath;
  2828. }
  2829. if (quote)
  2830. throw MakeXPathException(start, PTreeExcpt_XPath_ParseError, xpath-start, "Parse error, unclosed quoted content");
  2831. if (tType)
  2832. {
  2833. if (quoteBegin && !quoteEnd)
  2834. throw MakeXPathException(start, PTreeExcpt_XPath_ParseError, xpath-start, "Parse error, RHS missing closing quote");
  2835. if (rhsBegin && !rhsEnd)
  2836. throw MakeXPathException(start, PTreeExcpt_XPath_ParseError, xpath-start, "Parse error, RHS missing closing quote");
  2837. if (!quoteBegin && rhsEnd) // validate it's a numeric
  2838. {
  2839. const char *c = rhsBegin;
  2840. loop
  2841. {
  2842. if (!isdigit(*c++))
  2843. throw MakeXPathException(start, PTreeExcpt_XPath_ParseError, xpath-start, "Parse error, RHS is an unquoted string");
  2844. if (c==rhsEnd) break;
  2845. }
  2846. }
  2847. }
  2848. MAKE_LSTRING(lhs, start, lhsEnd-start);
  2849. bool ret = false;
  2850. const char *tProp = splitXPathX(lhs);
  2851. MAKE_LSTRING(head, lhs, tProp-lhs);
  2852. Owned<IPropertyTreeIterator> iter = getElements(head);
  2853. ForEach (*iter)
  2854. {
  2855. IPropertyTree &found = iter->query();
  2856. if (t_none == tType)
  2857. {
  2858. if (found.hasProp(tProp))
  2859. {
  2860. ret = true;
  2861. break;
  2862. }
  2863. }
  2864. else
  2865. {
  2866. Owned<IPropertyTreeIterator> _iter2;
  2867. IPropertyTreeIterator *iter2;
  2868. IPropertyTree *matchElem;
  2869. if (isAttribute(tProp))
  2870. {
  2871. matchElem = &found;
  2872. iter2 = NULL;
  2873. }
  2874. else
  2875. {
  2876. _iter2.setown(found.getElements(tProp));
  2877. iter2 = _iter2;
  2878. if (iter2->first())
  2879. matchElem = &iter2->query();
  2880. else
  2881. continue;
  2882. tProp = NULL;
  2883. }
  2884. loop
  2885. {
  2886. if (matchElem->isBinary(tProp))
  2887. UNIMPLEMENTED;
  2888. const char *rhs;
  2889. unsigned rhslength;
  2890. if (quoteEnd)
  2891. {
  2892. rhs = quoteBegin;
  2893. rhslength = quoteEnd-quoteBegin;
  2894. #ifdef WARNLEGACYCOMPARE
  2895. if (legacynumeric)
  2896. {
  2897. if (isdigit(*rhs))
  2898. WARNLOG("Possible deprecated use of quoted numeric comparison operation: %s", xxpath);
  2899. }
  2900. #endif
  2901. }
  2902. else if (rhsEnd)
  2903. {
  2904. rhs = rhsBegin;
  2905. rhslength = rhsEnd-rhsBegin;
  2906. numeric = true;
  2907. }
  2908. else
  2909. {
  2910. rhs = NULL;
  2911. rhslength = 0;
  2912. }
  2913. if (matchElem->isCompressed(tProp))
  2914. {
  2915. StringBuffer s;
  2916. matchElem->getProp(tProp, s);
  2917. ret = match(wild, numeric, xxpath, tType, s.toCharArray(), s.length(), rhs, rhslength, nocase);
  2918. }
  2919. else
  2920. {
  2921. const char *value = matchElem->queryProp(tProp);
  2922. if (value)
  2923. ret = match(wild, numeric, xxpath, tType, value, value?(size32_t)strlen(value):0, rhs, rhslength, nocase);
  2924. else if (tType == t_equality)
  2925. ret = (NULL == rhs || '\0' == *rhs);
  2926. else if (tType == t_inequality)
  2927. ret = (NULL != rhs && '\0' != *rhs);
  2928. }
  2929. if (ret)
  2930. break;
  2931. if (!iter2 || !iter2->next())
  2932. break;
  2933. matchElem = &iter2->query();
  2934. }
  2935. if (ret)
  2936. break;
  2937. }
  2938. }
  2939. xxpath = xpath;
  2940. return ret;
  2941. }
  2942. bool isEmptyPTree(IPropertyTree *t)
  2943. {
  2944. if (!t)
  2945. return true;
  2946. if (t->numUniq())
  2947. return false;
  2948. Owned<IAttributeIterator> ai = t->getAttributes();
  2949. if (ai->first())
  2950. return false;
  2951. const char *s = t->queryProp(NULL);
  2952. if (s&&*s)
  2953. return false;
  2954. return true;
  2955. }
  2956. ///////////////////
  2957. PTLocalIteratorBase::PTLocalIteratorBase(const PTree *_tree, const char *_id, bool _nocase, bool _sort) : tree(_tree), id(_id), nocase(_nocase), sort(_sort)
  2958. {
  2959. class CPTArrayIterator : public ArrayIIteratorOf<IArrayOf<IPropertyTree>, IPropertyTree, IPropertyTreeIterator>
  2960. {
  2961. public:
  2962. CPTArrayIterator(IPropertyTreeIterator &src) : ArrayIIteratorOf<IArrayOf<IPropertyTree>, IPropertyTree, IPropertyTreeIterator>(elems)
  2963. {
  2964. ForEach(src)
  2965. elems.append(src.get());
  2966. elems.sort(comparePropTrees);
  2967. }
  2968. IArrayOf<IPropertyTree> elems;
  2969. };
  2970. tree->Link();
  2971. baseIter = tree->checkChildren()->getIterator(sort);
  2972. iter = NULL;
  2973. current = NULL;
  2974. }
  2975. PTLocalIteratorBase::~PTLocalIteratorBase()
  2976. {
  2977. baseIter->Release();
  2978. ::Release(iter);
  2979. tree->Release();
  2980. }
  2981. // IPropertyTreeIterator
  2982. bool PTLocalIteratorBase::first()
  2983. {
  2984. ::Release(iter); iter=NULL;
  2985. if (!baseIter || !baseIter->first()) return false;
  2986. return _next();
  2987. }
  2988. bool PTLocalIteratorBase::_next()
  2989. {
  2990. if (iter && iter->isValid() && iter->next())
  2991. return true;
  2992. loop
  2993. {
  2994. loop
  2995. {
  2996. if (!baseIter->isValid())
  2997. {
  2998. current = NULL;
  2999. return false;
  3000. }
  3001. else if (match())
  3002. break;
  3003. baseIter->next();
  3004. }
  3005. IPropertyTree *element = &baseIter->query();
  3006. baseIter->next();
  3007. if (iter)
  3008. iter->Release();
  3009. iter = element->getElements(NULL);
  3010. if (iter->first())
  3011. {
  3012. current = &iter->query();
  3013. return true;
  3014. }
  3015. }
  3016. }
  3017. bool PTLocalIteratorBase::next()
  3018. {
  3019. return _next();
  3020. }
  3021. bool PTLocalIteratorBase::isValid()
  3022. {
  3023. return (current != NULL);
  3024. }
  3025. /////////////////////////////
  3026. bool PTIdMatchIterator::match()
  3027. {
  3028. IPropertyTree &tree = baseIter->query();
  3029. const char *key = tree.queryName();
  3030. return (0 != WildMatch(key, id, nocase));
  3031. }
  3032. ////////////////////////////
  3033. SingleIdIterator::SingleIdIterator(const PTree &_tree, unsigned pos, unsigned _many) : tree(_tree), many(_many), start(pos-1), whichNext(start), count(0), current(NULL)
  3034. {
  3035. tree.Link();
  3036. }
  3037. SingleIdIterator::~SingleIdIterator()
  3038. {
  3039. tree.Release();
  3040. }
  3041. void SingleIdIterator::setCurrent(unsigned pos)
  3042. {
  3043. current = tree.value->queryElement(pos);
  3044. }
  3045. // IInterface impl.
  3046. bool SingleIdIterator::first()
  3047. {
  3048. whichNext = start;
  3049. if (!tree.value || !tree.value->isArray())
  3050. {
  3051. if (0 == whichNext)
  3052. {
  3053. current = const_cast<PTree*>(&tree);
  3054. count = 1;
  3055. }
  3056. }
  3057. else
  3058. {
  3059. count = tree.value->elements();
  3060. if (whichNext < count)
  3061. setCurrent(whichNext);
  3062. else
  3063. return false;
  3064. }
  3065. ++whichNext;
  3066. return true;
  3067. }
  3068. bool SingleIdIterator::next()
  3069. {
  3070. if ((whichNext>=count) || (-1 != many && whichNext>start+many))
  3071. {
  3072. current = NULL;
  3073. return false;
  3074. }
  3075. setCurrent(whichNext++);
  3076. return true;
  3077. }
  3078. bool SingleIdIterator::isValid()
  3079. {
  3080. return (NULL != current);
  3081. }
  3082. //////////////
  3083. class StackElement
  3084. {
  3085. public:
  3086. void init(IPropertyTreeIterator *_iter, const char *_xpath)
  3087. {
  3088. xpath = (char *)strdup(_xpath);
  3089. iter=LINK(_iter);
  3090. }
  3091. void clear()
  3092. {
  3093. ::Release(iter);
  3094. if (xpath)
  3095. free(xpath);
  3096. }
  3097. IPropertyTreeIterator *get(StringAttr &str)
  3098. {
  3099. str.setown(xpath); return iter; // NB used in place of pop, as element invalid after call
  3100. }
  3101. IPropertyTreeIterator *iter;
  3102. char * xpath;
  3103. };
  3104. ///////////////////
  3105. PTStackIterator::PTStackIterator(IPropertyTreeIterator *_iter, const char *_xpath) : rootIter(_iter), xpath(_xpath)
  3106. {
  3107. iter = NULL;
  3108. xxpath = "";
  3109. current = NULL;
  3110. stacklen = 0;
  3111. stackmax = 4;
  3112. stack = (StackElement *)malloc(sizeof(StackElement)*stackmax);
  3113. }
  3114. PTStackIterator::~PTStackIterator()
  3115. {
  3116. while (stacklen)
  3117. stack[--stacklen].clear();
  3118. ::Release(iter);
  3119. ::Release(rootIter);
  3120. free(stack);
  3121. }
  3122. void PTStackIterator::setIterator(IPropertyTreeIterator *_iter)
  3123. {
  3124. assertex(_iter);
  3125. if (iter)
  3126. iter->Release();
  3127. iter = _iter;
  3128. iter->first();
  3129. }
  3130. // IIterator impl.
  3131. bool PTStackIterator::first()
  3132. {
  3133. while (stacklen)
  3134. stack[--stacklen].clear();
  3135. current = NULL;
  3136. xxpath = xpath;
  3137. rootIter->Link();
  3138. setIterator(rootIter);
  3139. return next();
  3140. }
  3141. bool PTStackIterator::isValid()
  3142. {
  3143. return (current != NULL);
  3144. }
  3145. IPropertyTree &PTStackIterator::query()
  3146. {
  3147. assertex(current);
  3148. return *current;
  3149. }
  3150. bool PTStackIterator::next()
  3151. {
  3152. bool separator = false;
  3153. if (iter)
  3154. {
  3155. IPropertyTree *element = NULL;
  3156. StringBuffer qualifierText;
  3157. loop
  3158. {
  3159. while (!iter->isValid())
  3160. {
  3161. if (iter) iter->Release();
  3162. iter = popFromStack(stackPath); // leaves linked
  3163. if (!iter)
  3164. {
  3165. current = NULL;
  3166. return false;
  3167. }
  3168. xxpath = stackPath;
  3169. element = NULL;
  3170. }
  3171. if (!element)
  3172. {
  3173. element = &iter->query();
  3174. iter->next();
  3175. }
  3176. while (element)
  3177. {
  3178. switch (*xxpath)
  3179. {
  3180. case '\0':
  3181. current = element;
  3182. return true;
  3183. case '.':
  3184. if (separator) throw MakeXPathException(xpath, PTreeExcpt_XPath_ParseError, 0, "Syntax error");
  3185. separator=false;
  3186. ++xxpath;
  3187. if (*xpath && '/' != *xpath)
  3188. throw MakeXPathException(xpath-1, PTreeExcpt_XPath_Unsupported, 0, "");
  3189. break;
  3190. case '/':
  3191. ++xxpath;
  3192. if ('/' == *xxpath)
  3193. {
  3194. --xxpath;
  3195. if (iter->isValid())
  3196. pushToStack(iter, xxpath);
  3197. setIterator(element->getElements(xxpath));
  3198. xxpath = "";
  3199. element = NULL;
  3200. }
  3201. separator=true;
  3202. break;
  3203. default:
  3204. separator=false;
  3205. if (iter->isValid())
  3206. pushToStack(iter, xxpath);
  3207. bool wild;
  3208. const char *start = xxpath;
  3209. readWildIdIndex(xxpath, wild);
  3210. size32_t s = xxpath-start;
  3211. if (s)
  3212. {
  3213. qualifierText.clear().append(s, start);
  3214. setIterator(element->getElements(qualifierText));
  3215. }
  3216. else // must be qualifier.
  3217. {
  3218. if ('[' != *xxpath)
  3219. throw MakeXPathException(xxpath, PTreeExcpt_XPath_ParseError, 0, "Qualifier expected e.g. [..]");
  3220. const char *start = xxpath;
  3221. char quote = 0;
  3222. while (']' != *(++xxpath) || quote)
  3223. {
  3224. switch (*xxpath) {
  3225. case '\"':
  3226. case '\'':
  3227. {
  3228. if (quote)
  3229. {
  3230. if (*xxpath == quote)
  3231. quote = 0;
  3232. }
  3233. else
  3234. quote = *xxpath;
  3235. break;
  3236. }
  3237. case '\0':
  3238. throw MakeXPathException(start, PTreeExcpt_XPath_ParseError, xxpath-start, "Qualifier brace unclosed");
  3239. }
  3240. }
  3241. ++xxpath;
  3242. qualifierText.clear().append(xxpath-start, start);
  3243. setIterator(element->getElements(qualifierText.str()));
  3244. }
  3245. element = NULL;
  3246. break;
  3247. }
  3248. }
  3249. }
  3250. }
  3251. return false;
  3252. }
  3253. void PTStackIterator::pushToStack(IPropertyTreeIterator *iter, const char *xpath)
  3254. {
  3255. if (stacklen==stackmax) {
  3256. stackmax *= 2;
  3257. stack = (StackElement *)realloc(stack, sizeof(StackElement)*stackmax);
  3258. }
  3259. stack[stacklen++].init(iter, xpath);
  3260. }
  3261. IPropertyTreeIterator *PTStackIterator::popFromStack(StringAttr &path)
  3262. {
  3263. if (!stacklen)
  3264. return NULL;
  3265. return stack[--stacklen].get(path);
  3266. }
  3267. // factory methods
  3268. IPropertyTree *createPTree(MemoryBuffer &src)
  3269. {
  3270. IPropertyTree *tree = new LocalPTree();
  3271. tree->deserialize(src);
  3272. return tree;
  3273. }
  3274. IPropertyTree *createPTreeFromIPT(const IPropertyTree *srcTree, ipt_flags flags)
  3275. {
  3276. Owned<PTree> tree = (PTree *)createPTree(NULL, flags);
  3277. return tree->clone(*srcTree->queryBranch(NULL));
  3278. }
  3279. void mergePTree(IPropertyTree *target, IPropertyTree *toMerge)
  3280. {
  3281. Owned<IAttributeIterator> aiter = toMerge->getAttributes();
  3282. ForEach (*aiter)
  3283. target->addProp(aiter->queryName(), aiter->queryValue());
  3284. Owned<IPropertyTreeIterator> iter = toMerge->getElements("*");
  3285. ForEach (*iter)
  3286. {
  3287. IPropertyTree &e = iter->query();
  3288. target->addPropTree(e.queryName(), LINK(&e));
  3289. }
  3290. }
  3291. void _synchronizePTree(IPropertyTree *target, IPropertyTree *source)
  3292. {
  3293. Owned<IAttributeIterator> aiter = target->getAttributes();
  3294. StringArray targetAttrs;
  3295. ForEach (*aiter)
  3296. targetAttrs.append(aiter->queryName());
  3297. aiter.setown(source->getAttributes());
  3298. ForEach (*aiter)
  3299. {
  3300. const char *attr = aiter->queryName();
  3301. if (!target->hasProp(attr))
  3302. target->setProp(attr, aiter->queryValue());
  3303. else
  3304. {
  3305. const char *sValue = aiter->queryValue();
  3306. const char *tValue = target->queryProp(attr);
  3307. if (NULL == sValue)
  3308. {
  3309. if (NULL != tValue)
  3310. target->setProp(attr, sValue);
  3311. }
  3312. else if (NULL == tValue ||0 != strcmp(sValue, tValue))
  3313. target->setProp(attr, sValue);
  3314. targetAttrs.zap(attr);
  3315. }
  3316. }
  3317. // remaining
  3318. ForEachItemIn (a, targetAttrs)
  3319. target->removeProp(targetAttrs.item(a));
  3320. bool equal = true;
  3321. MemoryBuffer srcMb;
  3322. const char *src = NULL;
  3323. if (target->isBinary())
  3324. {
  3325. MemoryBuffer tgtMb;
  3326. target->getPropBin(NULL, tgtMb);
  3327. source->getPropBin(NULL, srcMb);
  3328. if (tgtMb.length() != srcMb.length())
  3329. equal = false;
  3330. else if (0 != memcmp(tgtMb.toByteArray(), srcMb.toByteArray(), tgtMb.length()))
  3331. equal = false;
  3332. }
  3333. else
  3334. {
  3335. const char *tgt = target->queryProp(NULL);
  3336. src = source->queryProp(NULL);
  3337. unsigned lTgt = tgt?(size32_t)strlen(tgt):0;
  3338. unsigned lSrc = src?(size32_t)strlen(src):0;
  3339. if (lTgt != lSrc)
  3340. equal = false;
  3341. else if (0 != lTgt && (0 != strcmp(tgt, src)))
  3342. equal = false;
  3343. }
  3344. if (!equal)
  3345. {
  3346. if (target->isBinary())
  3347. target->setPropBin(NULL, srcMb.length(), srcMb.toByteArray());
  3348. else
  3349. target->setProp(NULL, src);
  3350. }
  3351. ICopyArrayOf<IPropertyTree> toProcess;
  3352. Owned<IPropertyTreeIterator> iter = source->getElements("*");
  3353. ForEach (*iter)
  3354. toProcess.append(iter->query());
  3355. iter.setown(target->getElements("*"));
  3356. ICopyArrayOf<IPropertyTree> removeTreeList;
  3357. Owned<IPropertyTreeIterator> srcTypeIter;
  3358. StringAttr firstOfType;
  3359. ForEach (*iter)
  3360. {
  3361. IPropertyTree &e = iter->query();
  3362. const char *name = e.queryName();
  3363. IPropertyTree *sourceCompare;
  3364. if (!source->hasProp(name))
  3365. {
  3366. removeTreeList.append(e);
  3367. firstOfType.clear();
  3368. srcTypeIter.clear();
  3369. }
  3370. else
  3371. {
  3372. if (!firstOfType.length() || 0 != strcmp(firstOfType, e.queryName()))
  3373. {
  3374. if (firstOfType.length() && srcTypeIter)
  3375. {
  3376. // add remaining
  3377. while (srcTypeIter->next())
  3378. {
  3379. sourceCompare = &srcTypeIter->query();
  3380. target->addPropTree(sourceCompare->queryName(), LINK(sourceCompare));
  3381. toProcess.zap(*sourceCompare);
  3382. }
  3383. }
  3384. srcTypeIter.setown(source->getElements(e.queryName()));
  3385. firstOfType.set(e.queryName());
  3386. assertex(srcTypeIter->first());
  3387. sourceCompare = &srcTypeIter->query();
  3388. }
  3389. else // 2nd of type etc..
  3390. sourceCompare = srcTypeIter->next() ? &srcTypeIter->query() : NULL;
  3391. if (sourceCompare)
  3392. {
  3393. toProcess.zap(*sourceCompare);
  3394. _synchronizePTree(&e, sourceCompare);
  3395. }
  3396. else
  3397. removeTreeList.append(e);
  3398. }
  3399. }
  3400. ForEachItemIn (rt, removeTreeList)
  3401. target->removeTree(&removeTreeList.item(rt));
  3402. // add unprocessed source elements, not reference by name in target
  3403. ForEachItemIn (s, toProcess)
  3404. {
  3405. IPropertyTree &e = toProcess.item(s);
  3406. target->addPropTree(e.queryName(), LINK(&e));
  3407. }
  3408. }
  3409. // ensure target is equivalent to source whilst retaining elements already present in target.
  3410. // presevers ordering of matching elements.
  3411. void synchronizePTree(IPropertyTree *target, IPropertyTree *source)
  3412. {
  3413. const char *srcName = source->queryName();
  3414. const char *tgtName = target->queryName();
  3415. if (0 != strcmp(srcName, tgtName))
  3416. throw MakeIPTException(PTreeExcpt_Unsupported, "Cannot synchronize if root nodes mismatch");
  3417. _synchronizePTree(target, source);
  3418. }
  3419. IPropertyTree *ensurePTree(IPropertyTree *root, const char *xpath)
  3420. {
  3421. return createPropBranch(root, xpath, true);
  3422. }
  3423. IXMLReadException *createXmlReadException(int code, const char *msg, const char *context, unsigned line, offset_t offset)
  3424. {
  3425. class jlib_thrown_decl CXMLReadException : public CInterface, implements IXMLReadException
  3426. {
  3427. int code;
  3428. StringAttr msg;
  3429. StringAttr context;
  3430. unsigned line;
  3431. offset_t offset;
  3432. StringBuffer &getErrorMessage(StringBuffer &out) const
  3433. {
  3434. switch (code)
  3435. {
  3436. case XmlRead_EOS:
  3437. return out.append("Error - end of stream");
  3438. case XmlRead_syntax:
  3439. return out.append("Error - syntax error");
  3440. }
  3441. return out;
  3442. }
  3443. public:
  3444. IMPLEMENT_IINTERFACE;
  3445. CXMLReadException(int _code, const char *_msg, const char *_context, unsigned _line, offset_t _offset) : code(_code), msg(_msg), context(_context), line(_line), offset(_offset) { }
  3446. // IException
  3447. int errorCode() const { return code; }
  3448. StringBuffer &errorMessage(StringBuffer &str) const
  3449. {
  3450. getErrorMessage(str);
  3451. if (msg.length())
  3452. str.append(" \"").append(msg).append("\"");
  3453. str.append(" [");
  3454. if (line>1) // don't bother with line 1, there may be no line breaks.
  3455. str.append("line ").append(line).append(", ");
  3456. str.append("file offset ").append(offset).append("]");
  3457. if (context.length())
  3458. str.newline().append(context);
  3459. return str;
  3460. }
  3461. MessageAudience errorAudience() const { return MSGAUD_user; }
  3462. const char *queryDescription() { return msg; }
  3463. unsigned queryLine() { return line; }
  3464. offset_t queryOffset() { return offset; }
  3465. const char *queryContext() { return context.get(); }
  3466. };
  3467. return new CXMLReadException(code, msg, context, line, offset);
  3468. }
  3469. template <typename X>
  3470. class CXMLReaderBase : public CInterface, implements IEntityHelper
  3471. {
  3472. Linked<ISimpleReadStream> lstream;
  3473. ISimpleReadStream *stream;
  3474. bool bufOwned, nullTerm;
  3475. byte *buf, *bufPtr;
  3476. size32_t bufSize, bufRemaining;
  3477. StringAttrMapping entityTable;
  3478. protected:
  3479. XmlReaderOptions xmlReaderOptions;
  3480. bool ignoreWhiteSpace, noRoot, ignoreNameSpaces;
  3481. Linked<IPTreeNotifyEvent> iEvent;
  3482. offset_t curOffset;
  3483. unsigned line;
  3484. char nextChar;
  3485. bool hadXMLDecl;
  3486. public:
  3487. CXMLReaderBase(ISimpleReadStream &_stream, IPTreeNotifyEvent &_iEvent, XmlReaderOptions _xmlReaderOptions, size32_t _bufSize=0) : xmlReaderOptions(_xmlReaderOptions), iEvent(&_iEvent), bufSize(_bufSize)
  3488. {
  3489. if (!bufSize) bufSize = 0x8000;
  3490. buf = new byte[bufSize];
  3491. bufRemaining = 0;
  3492. curOffset = 0;
  3493. bufOwned = true;
  3494. nullTerm = false;
  3495. lstream.set(&_stream);
  3496. stream = &_stream; // for efficiency
  3497. init();
  3498. }
  3499. CXMLReaderBase(const void *_buf, size32_t bufLength, IPTreeNotifyEvent &_iEvent, XmlReaderOptions _xmlReaderOptions) : xmlReaderOptions(_xmlReaderOptions), iEvent(&_iEvent)
  3500. {
  3501. bufSize = 0; // not used for direct reads
  3502. stream = NULL; // not used for direct reads
  3503. bufRemaining = bufLength;
  3504. nullTerm = false;
  3505. buf = (byte *)_buf;
  3506. bufOwned = false;
  3507. init();
  3508. }
  3509. CXMLReaderBase(const void *_buf, IPTreeNotifyEvent &_iEvent, XmlReaderOptions _xmlReaderOptions) : xmlReaderOptions(_xmlReaderOptions), iEvent(&_iEvent)
  3510. {
  3511. bufSize = 0; // not used for direct reads
  3512. stream = NULL; // not used for direct reads
  3513. curOffset = 0;
  3514. bufRemaining = 0;
  3515. nullTerm = true;
  3516. buf = (byte *)_buf;
  3517. bufOwned = false;
  3518. init();
  3519. }
  3520. ~CXMLReaderBase()
  3521. {
  3522. if (bufOwned)
  3523. delete [] buf;
  3524. }
  3525. protected:
  3526. void init()
  3527. {
  3528. ignoreWhiteSpace = 0 != ((unsigned)xmlReaderOptions & (unsigned)xr_ignoreWhiteSpace);
  3529. ignoreNameSpaces = 0 != ((unsigned)xmlReaderOptions & (unsigned)xr_ignoreNameSpaces);
  3530. noRoot = 0 != ((unsigned)xmlReaderOptions & (unsigned)xr_noRoot);
  3531. reset();
  3532. }
  3533. void reset()
  3534. {
  3535. bufPtr = buf;
  3536. nextChar = 0;
  3537. if (nullTerm || stream)
  3538. bufRemaining = 0;
  3539. curOffset = 0;
  3540. hadXMLDecl = false;
  3541. line = 0;
  3542. }
  3543. void rewind(size32_t n)
  3544. {
  3545. assertex(curOffset >= n);
  3546. if (!n) return;
  3547. curOffset -= n;
  3548. size32_t d = (size32_t)(bufPtr-buf);
  3549. if (n > d) n = d;
  3550. if (!nullTerm)
  3551. bufRemaining += n;
  3552. loop
  3553. {
  3554. --bufPtr;
  3555. if (!--n) break;
  3556. if (10 == *bufPtr) --line;
  3557. }
  3558. }
  3559. bool checkBOM()
  3560. {
  3561. bool unsupportedUnicode = false;
  3562. bool utf8 = false;
  3563. switch ((unsigned char)nextChar)
  3564. {
  3565. case 0xff:
  3566. readNext();
  3567. if (0xfe == (unsigned char)nextChar)
  3568. unsupportedUnicode = true;
  3569. break;
  3570. case 0xfe:
  3571. readNext();
  3572. if (0xff == (unsigned char)nextChar)
  3573. unsupportedUnicode = true;
  3574. break;
  3575. case 0xef:
  3576. readNext();
  3577. if (0xbb == (unsigned char)nextChar)
  3578. {
  3579. readNext();
  3580. if (0xbf == (unsigned char)nextChar)
  3581. utf8 = true;
  3582. }
  3583. break;
  3584. default:
  3585. break;
  3586. }
  3587. if (utf8)
  3588. return true;
  3589. else if (unsupportedUnicode)
  3590. error("Unsupported unicode detected in BOM header", false);
  3591. return false;
  3592. }
  3593. void error(const char *msg=NULL, bool giveContext=true, XmlReadExcptCode code=XmlRead_syntax)
  3594. {
  3595. // NB: there is little validation in parse, error can be late.
  3596. StringBuffer context;
  3597. if (giveContext)
  3598. {
  3599. size32_t bufPos = (size32_t)(bufPtr-buf);
  3600. unsigned preLen = std::min(40U, bufPos);
  3601. size32_t bR = bufRemaining;
  3602. if (nullTerm)
  3603. {
  3604. byte *tPtr = bufPtr;
  3605. while (bR<40)
  3606. {
  3607. if ('\0' == *tPtr++) break;
  3608. bR++;
  3609. }
  3610. }
  3611. unsigned postLen = std::min(80-preLen, bR);
  3612. const char *xmlContext = (const char *)(bufPtr - preLen);
  3613. context.append(preLen, xmlContext);
  3614. context.append("*ERROR*");
  3615. context.append(postLen, xmlContext+preLen);
  3616. }
  3617. throw createXmlReadException(code, msg, context.str(), line+1, curOffset);
  3618. }
  3619. inline void expecting(const char *str)
  3620. {
  3621. StringBuffer errorMsg("Expecting \"");
  3622. error(errorMsg.append(str).append("\"").str());
  3623. }
  3624. inline void eos()
  3625. {
  3626. error("String terminator hit");
  3627. }
  3628. void match(const char *txt)
  3629. {
  3630. const char *c = txt;
  3631. loop
  3632. {
  3633. if (*c == '\0') break;
  3634. readNext();
  3635. if (toupper(nextChar) != toupper(*c))
  3636. throw c;
  3637. c++;
  3638. }
  3639. }
  3640. void readID(StringBuffer &id)
  3641. {
  3642. if (isValidXPathStartChr(nextChar))
  3643. {
  3644. loop
  3645. {
  3646. id.append(nextChar);
  3647. readNext();
  3648. if (!isValidXPathChr(nextChar)) break;
  3649. }
  3650. }
  3651. }
  3652. void skipString()
  3653. {
  3654. if ('"' == nextChar)
  3655. {
  3656. do { readNext(); } while ('"' != nextChar);
  3657. }
  3658. else if ('\'' == nextChar)
  3659. {
  3660. do { readNext(); } while ('\'' != nextChar);
  3661. }
  3662. else expecting("\" or '");
  3663. }
  3664. bool lookupRefValue(const char *name, StringBuffer &value)
  3665. {
  3666. StringAttr *val = entityTable.getValue(name);
  3667. if (!val) return false;
  3668. value.append(*val);
  3669. return true;
  3670. }
  3671. void storeEntity(const char *name, const char *value)
  3672. {
  3673. entityTable.setValue(name, value);
  3674. }
  3675. void parseEntity()
  3676. {
  3677. try { match("NTITY"); }
  3678. catch (const char *) { error("Bad syntax"); }
  3679. readNext();
  3680. skipWS();
  3681. StringBuffer entityName;
  3682. if ('%' != nextChar)
  3683. {
  3684. readID(entityName);
  3685. skipWS();
  3686. if ('"' == nextChar)
  3687. {
  3688. StringBuffer refValue;
  3689. loop
  3690. {
  3691. readNext();
  3692. if (!nextChar || '"' == nextChar)
  3693. break;
  3694. if ('&' == nextChar)
  3695. {
  3696. readNext();
  3697. StringBuffer ref;
  3698. if ('#' == nextChar)
  3699. {
  3700. ref.append("&#");
  3701. loop
  3702. {
  3703. readNext();
  3704. if (!nextChar)
  3705. expecting(";");
  3706. if (';' == nextChar) break;
  3707. ref.append(nextChar);
  3708. }
  3709. ref.append(";");
  3710. decodeXML(ref, refValue, ref.length());
  3711. }
  3712. else
  3713. {
  3714. readID(ref);
  3715. if (';' != nextChar)
  3716. expecting(";");
  3717. if (!lookupRefValue(ref, refValue))
  3718. {
  3719. StringBuffer _ref("&");
  3720. _ref.append(ref).append(';');
  3721. decodeXML(ref, refValue, ref.length()); // try inbuilts
  3722. }
  3723. }
  3724. }
  3725. else
  3726. refValue.append(nextChar);
  3727. }
  3728. storeEntity(entityName, refValue);
  3729. }
  3730. }
  3731. do { readNext(); }
  3732. while (nextChar && nextChar != '>');
  3733. }
  3734. void parseIntSubset()
  3735. {
  3736. loop
  3737. {
  3738. readNext();
  3739. skipWS();
  3740. if (']'== nextChar) break;
  3741. if ('<' == nextChar)
  3742. {
  3743. readNext();
  3744. switch (nextChar)
  3745. {
  3746. case '!':
  3747. {
  3748. readNext();
  3749. switch (nextChar)
  3750. {
  3751. case '-':
  3752. parseComment();
  3753. break;
  3754. case 'E':
  3755. parseEntity();
  3756. break;
  3757. default: // ignore anything else
  3758. do { readNext(); }
  3759. while (nextChar && nextChar != '>');
  3760. break;
  3761. }
  3762. break;
  3763. }
  3764. case '?':
  3765. {
  3766. StringBuffer pi;
  3767. parsePI(pi);
  3768. break;
  3769. }
  3770. }
  3771. }
  3772. }
  3773. }
  3774. void parseOther()
  3775. {
  3776. switch (nextChar)
  3777. {
  3778. case '-':
  3779. parseComment2();
  3780. break;
  3781. case 'D':
  3782. {
  3783. try { match("OCTYPE"); }
  3784. catch (const char *) { error("Bad syntax"); }
  3785. readNext();
  3786. skipWS();
  3787. StringBuffer doctypeid;
  3788. readID(doctypeid);
  3789. loop
  3790. {
  3791. skipWS();
  3792. if ('>' == nextChar) break;
  3793. if ('[' == nextChar)
  3794. {
  3795. parseIntSubset();
  3796. if (']' != nextChar)
  3797. expecting("]");
  3798. }
  3799. else if ('S' == nextChar)
  3800. {
  3801. match("YSTEM");
  3802. readNext();
  3803. skipWS();
  3804. skipString();
  3805. }
  3806. else if ('P' == nextChar)
  3807. {
  3808. match("UBLIC");
  3809. readNext();
  3810. skipWS();
  3811. skipString();
  3812. readNext();
  3813. skipWS();
  3814. skipString();
  3815. }
  3816. readNext();
  3817. }
  3818. break;
  3819. }
  3820. default:
  3821. error("Invalid information tag");
  3822. }
  3823. }
  3824. void parsePIOrDecl()
  3825. {
  3826. StringBuffer target;
  3827. parsePI(target);
  3828. if (0 == strcmp("xml", target.str()))
  3829. {
  3830. if (hadXMLDecl)
  3831. error("Only one XML declartion permitted");
  3832. hadXMLDecl = true;
  3833. }
  3834. }
  3835. void parseCData(StringBuffer &text)
  3836. {
  3837. try { match("CDATA["); }
  3838. catch (const char *) { error("Bad CDATA syntax"); }
  3839. loop
  3840. {
  3841. readNext();
  3842. while (']' == nextChar)
  3843. {
  3844. char c1 = nextChar;
  3845. readNext();
  3846. if (']' == nextChar)
  3847. {
  3848. char c2 = nextChar;
  3849. readNext();
  3850. if ('>' == nextChar)
  3851. return;
  3852. else
  3853. text.append(c1).append(c2);
  3854. }
  3855. else
  3856. text.append(c1);
  3857. }
  3858. text.append(nextChar);
  3859. }
  3860. }
  3861. void parsePI(StringBuffer &target)
  3862. {
  3863. readNext();
  3864. if (!isValidXPathStartChr(nextChar))
  3865. error("Invalid PI target");
  3866. loop
  3867. {
  3868. target.append(nextChar);
  3869. readNext();
  3870. if (!isValidXPathChr(nextChar))
  3871. break;
  3872. }
  3873. skipWS();
  3874. unsigned closeTag=0;
  3875. loop
  3876. {
  3877. if (!nextChar)
  3878. error("Missing closing PI tag ?>");
  3879. if (1 == closeTag)
  3880. {
  3881. if ('>' == nextChar)
  3882. break;
  3883. closeTag = 0;
  3884. }
  3885. else if ('?' == nextChar)
  3886. closeTag = 1;
  3887. readNext();
  3888. }
  3889. }
  3890. void parseDirective(StringBuffer &res)
  3891. {
  3892. readNext();
  3893. switch (nextChar) {
  3894. case '-':
  3895. parseComment2();
  3896. break;
  3897. case '[':
  3898. parseCData(res);
  3899. break;
  3900. default:
  3901. error("Unrecognised syntax");
  3902. }
  3903. }
  3904. void parseComment()
  3905. {
  3906. readNext();
  3907. if (nextChar != '-') error("Bad comment syntax");
  3908. parseComment2();
  3909. }
  3910. void parseComment2()
  3911. {
  3912. readNext();
  3913. if (nextChar != '-') error("Bad comment syntax");
  3914. readNext();
  3915. unsigned seen = 0;
  3916. while (nextChar)
  3917. {
  3918. if (seen==2)
  3919. {
  3920. if (nextChar=='>')
  3921. return;
  3922. else if (nextChar != '-') // should be syntax error really.
  3923. seen = 0;
  3924. }
  3925. else if (nextChar=='-')
  3926. seen++;
  3927. else
  3928. seen = 0;
  3929. readNext();
  3930. }
  3931. error("Bad comment syntax");
  3932. }
  3933. inline void readNext()
  3934. {
  3935. if (!readNextToken())
  3936. error("End of stream encountered whilst parsing", true, XmlRead_EOS);
  3937. curOffset++;
  3938. }
  3939. inline bool checkReadNext()
  3940. {
  3941. if (!readNextToken())
  3942. return false;
  3943. curOffset++;
  3944. return true;
  3945. }
  3946. inline bool readNextToken();
  3947. inline bool checkSkipWS()
  3948. {
  3949. while (isspace(nextChar)) if (!checkReadNext()) return false;
  3950. return true;
  3951. }
  3952. inline void skipWS()
  3953. {
  3954. while (isspace(nextChar)) readNext();
  3955. }
  3956. const char *_decodeXML(unsigned read, const char *startMark, StringBuffer &ret, unsigned len)
  3957. {
  3958. const char *errMark = NULL;
  3959. try { return decodeXML(startMark, ret, len, &errMark, this); }
  3960. catch (IException *e)
  3961. {
  3962. if (errMark)
  3963. rewind((unsigned)(errMark-startMark));
  3964. StringBuffer errMsg;
  3965. e->errorMessage(errMsg);
  3966. e->Release();
  3967. error(errMsg.str());
  3968. }
  3969. return NULL; // will never get here.
  3970. }
  3971. // IEntityHelper impl.
  3972. virtual bool find(const char *entity, StringBuffer &value)
  3973. {
  3974. return lookupRefValue(entity, value);
  3975. }
  3976. };
  3977. class CXMLStream { public: }; // only used to ensure different template definitions.
  3978. class CXMLBuffer { public: };
  3979. class CXMLString { public: };
  3980. template <> inline bool CXMLReaderBase<CXMLStream>::readNextToken()
  3981. {
  3982. // do own buffering, to have reasonable error context.
  3983. if (0 == bufRemaining)
  3984. {
  3985. size32_t _bufRemaining = stream->read(bufSize, buf);
  3986. if (!_bufRemaining)
  3987. return false;
  3988. bufRemaining = _bufRemaining;
  3989. bufPtr = buf;
  3990. }
  3991. --bufRemaining;
  3992. nextChar = *bufPtr++;
  3993. if (10 == nextChar)
  3994. line++;
  3995. return true;
  3996. }
  3997. template <> inline bool CXMLReaderBase<CXMLBuffer>::readNextToken()
  3998. {
  3999. if (0 == bufRemaining)
  4000. return false;
  4001. --bufRemaining;
  4002. nextChar = *bufPtr++;
  4003. if (10 == nextChar)
  4004. line++;
  4005. return true;
  4006. }
  4007. template <> inline bool CXMLReaderBase<CXMLString>::readNextToken()
  4008. {
  4009. nextChar = *bufPtr++;
  4010. if ('\0' == nextChar)
  4011. {
  4012. --bufPtr;
  4013. return false;
  4014. }
  4015. if (10 == nextChar)
  4016. line++;
  4017. return true;
  4018. }
  4019. template <class X>
  4020. class CXMLReader : public CXMLReaderBase<X>, implements IXMLReader
  4021. {
  4022. typedef CXMLReaderBase<X> PARENT;
  4023. using PARENT::checkBOM;
  4024. using PARENT::readNext;
  4025. using PARENT::checkReadNext;
  4026. using PARENT::checkSkipWS;
  4027. using PARENT::expecting;
  4028. using PARENT::error;
  4029. using PARENT::eos;
  4030. using PARENT::parseDirective;
  4031. using PARENT::parseOther;
  4032. using PARENT::parsePI;
  4033. using PARENT::parsePIOrDecl;
  4034. using PARENT::parseComment;
  4035. using PARENT::_decodeXML;
  4036. using PARENT::skipWS;
  4037. using PARENT::nextChar;
  4038. using PARENT::curOffset;
  4039. using PARENT::noRoot;
  4040. using PARENT::ignoreWhiteSpace;
  4041. using PARENT::ignoreNameSpaces;
  4042. using PARENT::iEvent;
  4043. using PARENT::hadXMLDecl;
  4044. bool rootTerminated;
  4045. StringBuffer attrName, attrval;
  4046. StringBuffer tmpStr;
  4047. public:
  4048. IMPLEMENT_IINTERFACE;
  4049. CXMLReader(ISimpleReadStream &stream, IPTreeNotifyEvent &iEvent, XmlReaderOptions xmlReaderOptions, size32_t bufSize=0)
  4050. : PARENT(stream, iEvent, xmlReaderOptions, bufSize)
  4051. {
  4052. init();
  4053. }
  4054. CXMLReader(const void *buf, size32_t bufLength, IPTreeNotifyEvent &iEvent, XmlReaderOptions xmlReaderOptions)
  4055. : PARENT(buf, bufLength, iEvent, xmlReaderOptions)
  4056. {
  4057. init();
  4058. }
  4059. CXMLReader(const void *buf, IPTreeNotifyEvent &iEvent, XmlReaderOptions xmlReaderOptions)
  4060. : PARENT(buf, iEvent, xmlReaderOptions)
  4061. {
  4062. init();
  4063. }
  4064. void init()
  4065. {
  4066. attrName.append('@');
  4067. reset();
  4068. }
  4069. void reset()
  4070. {
  4071. PARENT::reset();
  4072. rootTerminated = false;
  4073. }
  4074. // IXMLReader
  4075. virtual void load() { loadXML(); }
  4076. virtual offset_t queryOffset() { return curOffset; }
  4077. void loadXML()
  4078. {
  4079. bool head=true;
  4080. restart:
  4081. if (!checkReadNext()) return;
  4082. if (head)
  4083. {
  4084. head = false;
  4085. if (checkBOM())
  4086. if (!checkReadNext()) return;
  4087. }
  4088. if (!checkSkipWS()) return;
  4089. if ('<' != nextChar)
  4090. expecting("<");
  4091. readNext();
  4092. if ('!' == nextChar)
  4093. {
  4094. readNext();
  4095. parseOther();
  4096. goto restart;
  4097. }
  4098. else if ('?' == nextChar)
  4099. {
  4100. parsePIOrDecl();
  4101. goto restart;
  4102. }
  4103. if (!noRoot && rootTerminated)
  4104. {
  4105. if (ignoreWhiteSpace)
  4106. if (!checkSkipWS()) return;
  4107. error("Trailing xml after close of root tag");
  4108. }
  4109. _loadXML();
  4110. if (noRoot)
  4111. {
  4112. head = true;
  4113. hadXMLDecl = false;
  4114. }
  4115. else
  4116. rootTerminated = true;
  4117. goto restart;
  4118. }
  4119. void _loadXML()
  4120. {
  4121. restart:
  4122. offset_t startOffset = curOffset-2;
  4123. if ('!' == nextChar) // not sure this branch can ever be hit.
  4124. {
  4125. parseComment();
  4126. readNext();
  4127. if ('<' != nextChar)
  4128. expecting("<");
  4129. goto restart;
  4130. }
  4131. StringBuffer tagName;
  4132. if (ignoreWhiteSpace)
  4133. skipWS();
  4134. while (!isspace(nextChar) && nextChar != '>' && nextChar != '/')
  4135. {
  4136. tagName.append(nextChar);
  4137. readNext();
  4138. if ('<' == nextChar)
  4139. error("Unmatched close tag encountered");
  4140. }
  4141. StringBuffer completeTagname = tagName;
  4142. if (ignoreNameSpaces)
  4143. {
  4144. const char *colon;
  4145. if (colon = strchr(tagName.str(), ':'))
  4146. tagName.remove(0, (size32_t)(colon - tagName.str() + 1));
  4147. }
  4148. iEvent->beginNode(tagName.toCharArray(), startOffset);
  4149. skipWS();
  4150. bool endTag = false;
  4151. bool base64 = false;
  4152. while(nextChar != '>')
  4153. {
  4154. skipWS();
  4155. if (nextChar=='/')
  4156. {
  4157. readNext();
  4158. if (nextChar != '>')
  4159. expecting(">");
  4160. endTag = true;
  4161. break;
  4162. }
  4163. attrName.setLength(1);
  4164. attrval.clear();
  4165. while (nextChar && !isspace(nextChar) && nextChar != '=' && nextChar != '>' && nextChar != '/')
  4166. {
  4167. attrName.append(nextChar);
  4168. readNext();
  4169. }
  4170. skipWS();
  4171. if (nextChar == '=') readNext(); else expecting("=");
  4172. skipWS();
  4173. if (nextChar == '"')
  4174. {
  4175. readNext();
  4176. while (nextChar != '"')
  4177. {
  4178. if (!nextChar)
  4179. eos();
  4180. attrval.append(nextChar);
  4181. readNext();
  4182. }
  4183. }
  4184. else if (nextChar == '\'')
  4185. {
  4186. readNext();
  4187. while (nextChar != '\'')
  4188. {
  4189. attrval.append(nextChar);
  4190. readNext();
  4191. }
  4192. }
  4193. else
  4194. error();
  4195. _decodeXML(0, attrval.str(), tmpStr.clear(), attrval.length());
  4196. if (0 == strcmp(attrName.str(), "@xsi:type") &&
  4197. (0 == stricmp(tmpStr.str(),"SOAP-ENC:base64")))
  4198. base64 = true;
  4199. else
  4200. iEvent->newAttribute(attrName.str(), tmpStr.str());
  4201. readNext();
  4202. skipWS();
  4203. }
  4204. iEvent->beginNodeContent(tagName.toCharArray());
  4205. StringBuffer tagText;
  4206. bool binary = base64;
  4207. if (!endTag)
  4208. {
  4209. if (nextChar == '>')
  4210. {
  4211. loop
  4212. {
  4213. loop
  4214. {
  4215. readNext();
  4216. if (ignoreWhiteSpace)
  4217. skipWS();
  4218. if ('\0' == nextChar)
  4219. eos();
  4220. StringBuffer mark;
  4221. while (nextChar && nextChar !='<') { mark.append(nextChar); readNext(); }
  4222. size32_t l = mark.length();
  4223. size32_t r = l+1;
  4224. if (l)
  4225. {
  4226. if (ignoreWhiteSpace)
  4227. {
  4228. while (l-- && isspace(mark.charAt(l)));
  4229. mark.setLength(l+1);
  4230. }
  4231. tagText.ensureCapacity(mark.length());
  4232. _decodeXML(r, mark.toCharArray(), tagText, mark.length());
  4233. }
  4234. readNext();
  4235. if ('!' == nextChar)
  4236. parseDirective(tagText);
  4237. else if ('?' == nextChar)
  4238. {
  4239. parsePI(tmpStr.clear());
  4240. #ifdef STRICT_PI
  4241. if (0 == stricmp(tmpStr.str(), "xml"))
  4242. error("Reserved PI target used");
  4243. #endif
  4244. }
  4245. else
  4246. break;
  4247. }
  4248. if (nextChar=='/')
  4249. {
  4250. if (base64)
  4251. {
  4252. JBASE64_Decode(tagText.str(), tmpStr.clear());
  4253. tagText.swapWith(tmpStr);
  4254. }
  4255. else
  4256. {
  4257. if (strlen(tagText.str()) != tagText.length())
  4258. binary = true;
  4259. }
  4260. break; // exit
  4261. }
  4262. else
  4263. _loadXML();
  4264. }
  4265. readNext();
  4266. unsigned i = 0;
  4267. while (!isspace(nextChar) && nextChar != '>')
  4268. {
  4269. if ((i >= completeTagname.length()) ||
  4270. (nextChar != completeTagname.charAt(i++)))
  4271. error("Mismatched opening and closing tags");
  4272. readNext();
  4273. }
  4274. if (i != completeTagname.length())
  4275. error("Mismatched opening and closing tags");
  4276. skipWS();
  4277. if (nextChar != '>')
  4278. expecting(">");
  4279. }
  4280. }
  4281. iEvent->endNode(tagName.toCharArray(), tagText.length(), tagText.toCharArray(), binary, curOffset);
  4282. }
  4283. };
  4284. template <class X>
  4285. class CPullXMLReader : public CXMLReaderBase<X>, implements IPullXMLReader
  4286. {
  4287. typedef CXMLReaderBase<X> PARENT;
  4288. using PARENT::checkBOM;
  4289. using PARENT::readNext;
  4290. using PARENT::checkReadNext;
  4291. using PARENT::checkSkipWS;
  4292. using PARENT::expecting;
  4293. using PARENT::error;
  4294. using PARENT::eos;
  4295. using PARENT::parseDirective;
  4296. using PARENT::parseOther;
  4297. using PARENT::parsePI;
  4298. using PARENT::parsePIOrDecl;
  4299. using PARENT::parseComment;
  4300. using PARENT::_decodeXML;
  4301. using PARENT::skipWS;
  4302. using PARENT::nextChar;
  4303. using PARENT::curOffset;
  4304. using PARENT::noRoot;
  4305. using PARENT::ignoreWhiteSpace;
  4306. using PARENT::ignoreNameSpaces;
  4307. using PARENT::iEvent;
  4308. using PARENT::hadXMLDecl;
  4309. class CStateInfo : public CInterface
  4310. {
  4311. public:
  4312. CStateInfo()
  4313. {
  4314. tag.ensureCapacity(15);
  4315. binary = base64 = false;
  4316. }
  4317. inline void reset()
  4318. {
  4319. binary = base64 = false;
  4320. tag.clear();
  4321. tagText.clear();
  4322. }
  4323. const char *wnsTag;
  4324. StringBuffer tag;
  4325. StringBuffer tagText;
  4326. bool binary, base64;
  4327. };
  4328. CopyCIArrayOf<CStateInfo> stack, freeStateInfo;
  4329. CStateInfo *stateInfo;
  4330. enum ParseStates { headerStart, tagStart, tagAttributes, tagContent, tagContent2, tagClose, tagEnd, tagMarker } state;
  4331. bool endOfRoot;
  4332. StringBuffer attrName, attrval, mark, tmpStr;
  4333. public:
  4334. IMPLEMENT_IINTERFACE;
  4335. CPullXMLReader(ISimpleReadStream &stream, IPTreeNotifyEvent &iEvent, XmlReaderOptions xmlReaderOptions, size32_t bufSize=0)
  4336. : CXMLReaderBase<X>(stream, iEvent, xmlReaderOptions, bufSize)
  4337. {
  4338. init();
  4339. }
  4340. CPullXMLReader(const void *buf, size32_t bufLength, IPTreeNotifyEvent &iEvent, XmlReaderOptions xmlReaderOptions)
  4341. : CXMLReaderBase<X>(buf, bufLength, iEvent, xmlReaderOptions)
  4342. {
  4343. init();
  4344. }
  4345. CPullXMLReader(const void *buf, IPTreeNotifyEvent &iEvent, XmlReaderOptions xmlReaderOptions)
  4346. : CXMLReaderBase<X>(buf, iEvent, xmlReaderOptions)
  4347. {
  4348. init();
  4349. }
  4350. ~CPullXMLReader()
  4351. {
  4352. ForEachItemIn(i, stack)
  4353. delete &stack.item(i);
  4354. ForEachItemIn(i2, freeStateInfo)
  4355. delete &freeStateInfo.item(i2);
  4356. }
  4357. void init()
  4358. {
  4359. state = headerStart;
  4360. stateInfo = NULL;
  4361. endOfRoot = false;
  4362. attrName.append('@');
  4363. }
  4364. // IPullXMLReader
  4365. virtual void load()
  4366. {
  4367. while (next()) {}
  4368. }
  4369. virtual offset_t queryOffset() { return curOffset; }
  4370. virtual bool next()
  4371. {
  4372. switch (state)
  4373. {
  4374. case headerStart:
  4375. {
  4376. if (!checkReadNext()) return false;
  4377. if (checkBOM())
  4378. if (!checkReadNext()) return false;
  4379. loop
  4380. {
  4381. if (!checkSkipWS()) return false;
  4382. if ('<' != nextChar)
  4383. expecting("<");
  4384. readNext();
  4385. if ('!' == nextChar)
  4386. {
  4387. readNext();
  4388. parseOther();
  4389. }
  4390. else if ('?' == nextChar)
  4391. parsePIOrDecl();
  4392. else
  4393. break;
  4394. if (!checkReadNext()) return false;
  4395. }
  4396. state = tagStart;
  4397. break;
  4398. }
  4399. case tagStart:
  4400. {
  4401. offset_t startOffset;
  4402. loop
  4403. {
  4404. if ('!' != nextChar)
  4405. break;
  4406. parseComment();
  4407. readNext();
  4408. if ('<' != nextChar)
  4409. expecting("<");
  4410. }
  4411. startOffset = curOffset-2;
  4412. if (freeStateInfo.ordinality())
  4413. {
  4414. stateInfo = &freeStateInfo.pop();
  4415. stateInfo->reset();
  4416. }
  4417. else
  4418. stateInfo = new CStateInfo;
  4419. stack.append(*stateInfo);
  4420. if ('/' == nextChar)
  4421. error("Unmatched close tag encountered");
  4422. while (!isspace(nextChar) && nextChar != '>')
  4423. {
  4424. stateInfo->tag.append(nextChar);
  4425. readNext();
  4426. if ('/' == nextChar) break;
  4427. if ('<' == nextChar)
  4428. error("Unmatched close tag encountered");
  4429. }
  4430. stateInfo->wnsTag = stateInfo->tag.str();
  4431. if (ignoreNameSpaces)
  4432. {
  4433. const char *colon;
  4434. if (colon = strchr(stateInfo->wnsTag, ':'))
  4435. stateInfo->wnsTag = colon+1;
  4436. }
  4437. endOfRoot = false;
  4438. try
  4439. {
  4440. iEvent->beginNode(stateInfo->wnsTag, startOffset);
  4441. }
  4442. catch (IPTreeException *pe)
  4443. {
  4444. if (PTreeExcpt_InvalidTagName == pe->errorCode())
  4445. {
  4446. pe->Release();
  4447. StringBuffer msg("Expecting valid start tag, but got \"");
  4448. error(msg.append(stateInfo->wnsTag).append("\"").str());
  4449. }
  4450. throw;
  4451. }
  4452. state = tagAttributes;
  4453. break;
  4454. }
  4455. case tagAttributes:
  4456. {
  4457. skipWS();
  4458. bool base64 = false;
  4459. if (nextChar == '>')
  4460. state = tagContent;
  4461. else
  4462. {
  4463. skipWS();
  4464. if (nextChar=='/')
  4465. {
  4466. readNext();
  4467. if (nextChar != '>')
  4468. expecting(">");
  4469. // no actual content
  4470. iEvent->beginNodeContent(stateInfo->wnsTag);
  4471. state = tagEnd;
  4472. break;
  4473. }
  4474. attrName.setLength(1);
  4475. attrval.clear();
  4476. while (nextChar && !isspace(nextChar) && nextChar != '=' && nextChar != '>' && nextChar != '/')
  4477. {
  4478. attrName.append(nextChar);
  4479. readNext();
  4480. }
  4481. skipWS();
  4482. if (nextChar == '=') readNext(); else expecting("=");
  4483. skipWS();
  4484. if (nextChar == '"')
  4485. {
  4486. readNext();
  4487. while (nextChar != '"')
  4488. {
  4489. if (!nextChar)
  4490. eos();
  4491. attrval.append(nextChar);
  4492. readNext();
  4493. }
  4494. }
  4495. else if (nextChar == '\'')
  4496. {
  4497. readNext();
  4498. while (nextChar != '\'')
  4499. {
  4500. attrval.append(nextChar);
  4501. readNext();
  4502. }
  4503. }
  4504. else
  4505. error();
  4506. _decodeXML(0, attrval.str(), tmpStr.clear(), attrval.length());
  4507. if (0 == strcmp(attrName.str(), "@xsi:type") &&
  4508. (0 == stricmp(tmpStr.str(),"SOAP-ENC:base64")))
  4509. stateInfo->base64 = true;
  4510. else
  4511. iEvent->newAttribute(attrName.str(), tmpStr.str());
  4512. readNext();
  4513. skipWS();
  4514. }
  4515. break;
  4516. }
  4517. case tagContent:
  4518. {
  4519. iEvent->beginNodeContent(stateInfo->wnsTag);
  4520. if ('>' != nextChar)
  4521. state = tagEnd;
  4522. else
  4523. state = tagContent2;
  4524. break;
  4525. }
  4526. case tagContent2:
  4527. {
  4528. try
  4529. {
  4530. loop
  4531. {
  4532. if (endOfRoot)
  4533. {
  4534. if (!checkReadNext()) return false;
  4535. if (!checkSkipWS()) return false;
  4536. }
  4537. else
  4538. {
  4539. readNext();
  4540. if (ignoreWhiteSpace)
  4541. skipWS();
  4542. }
  4543. if ('\0' == nextChar)
  4544. eos();
  4545. mark.clear();
  4546. state = tagMarker;
  4547. while (nextChar && nextChar !='<') { mark.append(nextChar); readNext(); }
  4548. if (!nextChar)
  4549. break;
  4550. size32_t l = mark.length();
  4551. size32_t r = l+1;
  4552. if (l && stateInfo)
  4553. {
  4554. if (ignoreWhiteSpace)
  4555. {
  4556. const char *tb = mark.toCharArray();
  4557. const char *t = tb+l-1;
  4558. if (isspace(*t))
  4559. {
  4560. while (t != tb && isspace(*(--t)));
  4561. mark.setLength((size32_t)(t-tb+1));
  4562. }
  4563. }
  4564. stateInfo->tagText.ensureCapacity(mark.length());
  4565. _decodeXML(r, mark.toCharArray(), stateInfo->tagText, mark.length());
  4566. }
  4567. if (endOfRoot && mark.length())
  4568. {
  4569. const char *m = mark.toCharArray();
  4570. const char *e = m+mark.length();
  4571. do { if (!isspace(*m++)) error("Trailing content after close of root tag"); }
  4572. while (m!=e);
  4573. }
  4574. readNext();
  4575. if ('!' == nextChar)
  4576. {
  4577. parseDirective(stateInfo->tagText);
  4578. state = tagContent2;
  4579. }
  4580. else if ('?' == nextChar)
  4581. {
  4582. parsePI(tmpStr.clear());
  4583. #ifdef STRICT_PI
  4584. if (0 == stricmp(tmpStr.str(), "xml"))
  4585. error("Reserved PI target used");
  4586. #endif
  4587. state = tagContent2;
  4588. }
  4589. else
  4590. break;
  4591. }
  4592. }
  4593. catch (IXMLReadException *e)
  4594. {
  4595. if (endOfRoot && XmlRead_EOS == e->errorCode() && (state != tagContent2 && mark.length())) // only to provide more meaningful error
  4596. {
  4597. const char *m = mark.toCharArray();
  4598. const char *es = m+mark.length();
  4599. do
  4600. {
  4601. if (!isspace(*m++))
  4602. {
  4603. e->Release();
  4604. error("Trailing content after close of root tag");
  4605. }
  4606. }
  4607. while (m!=es);
  4608. }
  4609. throw;
  4610. }
  4611. if ('/' == nextChar)
  4612. {
  4613. if (endOfRoot && !noRoot)
  4614. error("Trailing tag close after close of root tag");
  4615. if (stateInfo->base64)
  4616. {
  4617. JBASE64_Decode(stateInfo->tagText.str(), tmpStr.clear());
  4618. stateInfo->tagText.swapWith(tmpStr);
  4619. stateInfo->binary = true;
  4620. // next state tagContent2 still
  4621. }
  4622. else
  4623. {
  4624. if (strlen(stateInfo->tagText.str()) != stateInfo->tagText.length())
  4625. stateInfo->binary = true;
  4626. }
  4627. state = tagClose;
  4628. break; // exit
  4629. }
  4630. else
  4631. {
  4632. if (endOfRoot && !noRoot)
  4633. error("Trailing tag open after close of root tag");
  4634. state = tagStart;
  4635. }
  4636. break;
  4637. }
  4638. case tagClose:
  4639. {
  4640. readNext();
  4641. const char *t = stateInfo->tag.toCharArray();
  4642. const char *te = t+stateInfo->tag.length();
  4643. loop
  4644. {
  4645. if (nextChar == '>' || isspace(nextChar))
  4646. {
  4647. if (t != te)
  4648. error("Mismatched opening and closing tags");
  4649. break;
  4650. }
  4651. else if (nextChar != *t++)
  4652. error("Mismatched opening and closing tags");
  4653. readNext();
  4654. }
  4655. skipWS();
  4656. if (nextChar != '>')
  4657. expecting(">");
  4658. state = tagEnd;
  4659. break;
  4660. }
  4661. case tagEnd:
  4662. {
  4663. iEvent->endNode(stateInfo->wnsTag, stateInfo->tagText.length(), stateInfo->tagText.toCharArray(), stateInfo->binary, curOffset);
  4664. freeStateInfo.append(*stateInfo);
  4665. stack.pop();
  4666. endOfRoot = 0==stack.ordinality();
  4667. stateInfo = stack.ordinality()?&stack.tos():NULL;
  4668. if (endOfRoot && noRoot)
  4669. {
  4670. state = headerStart;
  4671. hadXMLDecl = false;
  4672. endOfRoot = false;
  4673. }
  4674. else
  4675. state = tagContent2;
  4676. break;
  4677. }
  4678. }
  4679. return true;
  4680. }
  4681. virtual void reset()
  4682. {
  4683. CXMLReaderBase<X>::reset();
  4684. stack.kill();
  4685. init();
  4686. }
  4687. };
  4688. IXMLReader *createXMLStreamReader(ISimpleReadStream &stream, IPTreeNotifyEvent &iEvent, XmlReaderOptions xmlReaderOptions, size32_t bufSize)
  4689. {
  4690. class CXMLStreamReader : public CXMLReader<CXMLStream>
  4691. {
  4692. public:
  4693. CXMLStreamReader(ISimpleReadStream &stream, IPTreeNotifyEvent &iEvent, XmlReaderOptions xmlReaderOptions, size32_t bufSize=0) : CXMLReader<CXMLStream>(stream, iEvent, xmlReaderOptions, bufSize) { }
  4694. };
  4695. return new CXMLStreamReader(stream, iEvent, xmlReaderOptions, bufSize);
  4696. }
  4697. IXMLReader *createXMLStringReader(const char *xml, IPTreeNotifyEvent &iEvent, XmlReaderOptions xmlReaderOptions)
  4698. {
  4699. class CXMLStringReader : public CXMLReader<CXMLString>
  4700. {
  4701. public:
  4702. CXMLStringReader(const void *xml, IPTreeNotifyEvent &iEvent, XmlReaderOptions xmlReaderOptions) : CXMLReader<CXMLString>(xml, iEvent, xmlReaderOptions) { }
  4703. };
  4704. if (NULL == xml)
  4705. throw createXmlReadException(XmlRead_syntax, "Null string passed to createXMLStringReader", NULL, 0, 0);
  4706. return new CXMLStringReader(xml, iEvent, xmlReaderOptions);
  4707. }
  4708. IXMLReader *createXMLBufferReader(const void *buf, size32_t bufLength, IPTreeNotifyEvent &iEvent, XmlReaderOptions xmlReaderOptions)
  4709. {
  4710. class CXMLBufferReader : public CXMLReader<CXMLBuffer>
  4711. {
  4712. public:
  4713. CXMLBufferReader(const void *buf, size32_t bufLength, IPTreeNotifyEvent &iEvent, XmlReaderOptions xmlReaderOptions) : CXMLReader<CXMLBuffer>(buf, bufLength, iEvent, xmlReaderOptions) { }
  4714. };
  4715. return new CXMLBufferReader(buf, bufLength, iEvent, xmlReaderOptions);
  4716. }
  4717. IPullXMLReader *createPullXMLStreamReader(ISimpleReadStream &stream, IPTreeNotifyEvent &iEvent, XmlReaderOptions xmlReaderOptions, size32_t bufSize)
  4718. {
  4719. class CXMLStreamReader : public CPullXMLReader<CXMLStream>
  4720. {
  4721. public:
  4722. CXMLStreamReader(ISimpleReadStream &stream, IPTreeNotifyEvent &iEvent, XmlReaderOptions xmlReaderOptions, size32_t bufSize=0) : CPullXMLReader<CXMLStream>(stream, iEvent, xmlReaderOptions, bufSize) { }
  4723. };
  4724. return new CXMLStreamReader(stream, iEvent, xmlReaderOptions, bufSize);
  4725. }
  4726. IPullXMLReader *createPullXMLStringReader(const char *xml, IPTreeNotifyEvent &iEvent, XmlReaderOptions xmlReaderOptions)
  4727. {
  4728. class CXMLStringReader : public CPullXMLReader<CXMLString>
  4729. {
  4730. public:
  4731. CXMLStringReader(const void *xml, IPTreeNotifyEvent &iEvent, XmlReaderOptions xmlReaderOptions) : CPullXMLReader<CXMLString>(xml, iEvent, xmlReaderOptions) { }
  4732. };
  4733. return new CXMLStringReader(xml, iEvent, xmlReaderOptions);
  4734. }
  4735. IPullXMLReader *createPullXMLBufferReader(const void *buf, size32_t bufLength, IPTreeNotifyEvent &iEvent, XmlReaderOptions xmlReaderOptions)
  4736. {
  4737. class CXMLBufferReader : public CPullXMLReader<CXMLBuffer>
  4738. {
  4739. public:
  4740. CXMLBufferReader(const void *buf, size32_t bufLength, IPTreeNotifyEvent &iEvent, XmlReaderOptions xmlReaderOptions) : CPullXMLReader<CXMLBuffer>(buf, bufLength, iEvent, xmlReaderOptions) { }
  4741. };
  4742. return new CXMLBufferReader(buf, bufLength, iEvent, xmlReaderOptions);
  4743. }
  4744. IPTreeMaker *createPTreeMaker(byte flags, IPropertyTree *root, IPTreeNodeCreator *nodeCreator)
  4745. {
  4746. return new CPTreeMaker(flags, nodeCreator, root);
  4747. }
  4748. IPTreeMaker *createRootLessPTreeMaker(byte flags, IPropertyTree *root, IPTreeNodeCreator *nodeCreator)
  4749. {
  4750. return new CPTreeMaker(flags, nodeCreator, root, true);
  4751. }
  4752. ////////////////////////////
  4753. ///////////////////////////
  4754. IPropertyTree *createPTree(ISimpleReadStream &stream, byte flags, XmlReaderOptions readFlags, IPTreeMaker *iMaker)
  4755. {
  4756. Owned<IPTreeMaker> _iMaker;
  4757. if (!iMaker)
  4758. {
  4759. iMaker = new CPTreeMaker(flags);
  4760. _iMaker.setown(iMaker);
  4761. }
  4762. Owned<IXMLReader> reader = createXMLStreamReader(stream, *iMaker, readFlags);
  4763. reader->load();
  4764. if (iMaker->queryRoot())
  4765. return LINK(iMaker->queryRoot());
  4766. else
  4767. return createPTree(flags);
  4768. }
  4769. IPropertyTree *createPTree(IFileIO &ifileio, byte flags, XmlReaderOptions readFlags, IPTreeMaker *iMaker)
  4770. {
  4771. OwnedIFileIOStream stream = createIOStream(&ifileio);
  4772. return createPTree(*stream, flags, readFlags, iMaker);
  4773. }
  4774. IPropertyTree *createPTree(IFile &ifile, byte flags, XmlReaderOptions readFlags, IPTreeMaker *iMaker)
  4775. {
  4776. OwnedIFileIO ifileio = ifile.open(IFOread);
  4777. if (!ifileio)
  4778. throw MakeStringException(0, "Could not locate filename: %s", ifile.queryFilename());
  4779. return createPTree(*ifileio, flags, readFlags, iMaker);
  4780. }
  4781. IPropertyTree *createPTreeFromXMLFile(const char *filename, byte flags, XmlReaderOptions readFlags, IPTreeMaker *iMaker)
  4782. {
  4783. OwnedIFile ifile = createIFile(filename);
  4784. return createPTree(*ifile, flags, readFlags, iMaker);
  4785. }
  4786. IPropertyTree *createPTreeFromXMLString(const char *xml, byte flags, XmlReaderOptions readFlags, IPTreeMaker *iMaker)
  4787. {
  4788. Owned<IPTreeMaker> _iMaker;
  4789. if (!iMaker)
  4790. {
  4791. iMaker = new CPTreeMaker(flags);
  4792. _iMaker.setown(iMaker);
  4793. }
  4794. Owned<IXMLReader> reader = createXMLStringReader(xml, *iMaker, readFlags);
  4795. reader->load();
  4796. return LINK(iMaker->queryRoot());
  4797. }
  4798. IPropertyTree *createPTreeFromXMLString(unsigned len, const char *xml, byte flags, XmlReaderOptions readFlags, IPTreeMaker *iMaker)
  4799. {
  4800. Owned<IPTreeMaker> _iMaker;
  4801. if (!iMaker)
  4802. {
  4803. iMaker = new CPTreeMaker(flags);
  4804. _iMaker.setown(iMaker);
  4805. }
  4806. Owned<IXMLReader> reader = createXMLBufferReader(xml, len, *iMaker, readFlags);
  4807. reader->load();
  4808. return LINK(iMaker->queryRoot());
  4809. }
  4810. //////////////////////////
  4811. /////////////////////////
  4812. static void _toXML(const IPropertyTree *tree, IIOStream &out, unsigned indent, byte flags)
  4813. {
  4814. const char *name = tree->queryName();
  4815. if (!name) name = "__unnamed__";
  4816. bool isBinary = tree->isBinary(NULL);
  4817. bool inlinebody = true;
  4818. if (flags & XML_Format) writeCharsNToStream(out, ' ', indent);
  4819. writeCharToStream(out, '<');
  4820. writeStringToStream(out, name);
  4821. Owned<IAttributeIterator> it = tree->getAttributes(true);
  4822. if (it->first())
  4823. {
  4824. unsigned attributeindent = indent+2+(size32_t)strlen(name);
  4825. bool first = true;
  4826. do
  4827. {
  4828. const char *key = it->queryName();
  4829. if (!isBinary || stricmp(key, "@xsi:type")!=0)
  4830. {
  4831. if (first)
  4832. {
  4833. if (flags & XML_Format) inlinebody = false;
  4834. first = false;
  4835. writeCharToStream(out, ' ');
  4836. }
  4837. else if ((flags & XML_Format) && it->count() > 3)
  4838. {
  4839. writeStringToStream(out, "\n");
  4840. writeCharsNToStream(out, ' ', attributeindent);
  4841. }
  4842. else
  4843. writeCharToStream(out, ' ');
  4844. writeStringToStream(out, key+1);
  4845. if (flags & XML_SingleQuoteAttributeValues)
  4846. writeStringToStream(out, "='");
  4847. else
  4848. writeStringToStream(out, "=\"");
  4849. const char *val = it->queryValue();
  4850. if (val)
  4851. {
  4852. if (flags & XML_SanitizeAttributeValues)
  4853. {
  4854. if (strcmp(val, "0")==0 || strcmp(val, "1")==0 || stricmp(val, "true")==0 || stricmp(val, "false")==0 || stricmp(val, "yes")==0 || stricmp(val, "no")==0)
  4855. encodeXML(val, out, ENCODE_NEWLINES, (unsigned)-1, true);
  4856. else
  4857. {
  4858. writeCharsNToStream(out, '*', strlen(val));
  4859. }
  4860. }
  4861. else
  4862. encodeXML(val, out, ENCODE_NEWLINES, (unsigned)-1, true);
  4863. }
  4864. if (flags & XML_SingleQuoteAttributeValues)
  4865. writeCharToStream(out, '\'');
  4866. else
  4867. writeCharToStream(out, '"');
  4868. }
  4869. }
  4870. while (it->next());
  4871. }
  4872. Owned<IPropertyTreeIterator> sub = tree->getElements("*", 0 != (flags & XML_SortTags) ? iptiter_sort : iptiter_null);
  4873. MemoryBuffer thislevelbin;
  4874. StringBuffer _thislevel;
  4875. const char *thislevel = NULL; // to avoid uninitialized warning
  4876. bool empty;
  4877. if (isBinary)
  4878. {
  4879. if (flags & XML_Format) inlinebody = false;
  4880. writeStringToStream(out, " xsi:type=\"SOAP-ENC:base64\"");
  4881. empty = (!tree->getPropBin(NULL, thislevelbin))||(thislevelbin.length()==0);
  4882. }
  4883. else
  4884. {
  4885. if (tree->isCompressed(NULL))
  4886. {
  4887. empty = false; // can't be empty if compressed;
  4888. verifyex(tree->getProp(NULL, _thislevel));
  4889. thislevel = _thislevel.toCharArray();
  4890. }
  4891. else
  4892. empty = (NULL == (thislevel = tree->queryProp(NULL)));
  4893. }
  4894. if (sub->first())
  4895. {
  4896. if (flags & XML_Format) inlinebody = false;
  4897. }
  4898. else if (empty && !(flags & XML_Sanitize))
  4899. {
  4900. if (flags & XML_Format)
  4901. writeStringToStream(out, "/>\n");
  4902. else
  4903. writeStringToStream(out, "/>");
  4904. return;
  4905. }
  4906. writeCharToStream(out, '>');
  4907. if (!inlinebody)
  4908. writeStringToStream(out, "\n");
  4909. for(; sub->isValid(); sub->next())
  4910. _toXML(&sub->query(), out, indent+1, flags);
  4911. if (!empty)
  4912. {
  4913. if (!inlinebody)
  4914. writeCharsNToStream(out, ' ', indent+1);
  4915. if (flags & XML_Sanitize)
  4916. {
  4917. // NOTE - we don't output anything for binary.... is that ok?
  4918. if (thislevel)
  4919. {
  4920. if (strcmp(thislevel, "0")==0 || strcmp(thislevel, "1")==0 || stricmp(thislevel, "true")==0 || stricmp(thislevel, "false")==0 || stricmp(thislevel, "yes")==0 || stricmp(thislevel, "no")==0)
  4921. writeStringToStream(out, thislevel);
  4922. else
  4923. writeCharsNToStream(out, '*', strlen(thislevel));
  4924. }
  4925. }
  4926. else if (isBinary)
  4927. {
  4928. if (flags & XML_NoBinaryEncode64)
  4929. {
  4930. if (flags & XML_NoEncode)
  4931. {
  4932. out.write(thislevelbin.length(), thislevelbin.toByteArray());
  4933. }
  4934. else
  4935. {
  4936. const char * buff = static_cast<const char *>(thislevelbin.toByteArray());
  4937. const unsigned len = thislevelbin.length();
  4938. unsigned prefix = 0;
  4939. while ((prefix < len) && isspace(buff[prefix]))
  4940. prefix++;
  4941. encodeXML(buff, out, ENCODE_WHITESPACE, prefix, true);
  4942. if (prefix != len) { // check not all spaces
  4943. unsigned suffix = len;
  4944. while (isspace(buff[suffix-1]))
  4945. suffix--;
  4946. encodeXML(buff+prefix, out, 0, suffix-prefix, true);
  4947. encodeXML(buff+suffix, out, ENCODE_WHITESPACE, len-suffix, true);
  4948. }
  4949. }
  4950. }
  4951. else
  4952. JBASE64_Encode(thislevelbin.toByteArray(), thislevelbin.length(), out);
  4953. }
  4954. else {
  4955. if (flags & XML_NoEncode)
  4956. {
  4957. writeStringToStream(out, thislevel);
  4958. }
  4959. else
  4960. {
  4961. const char *m = thislevel;
  4962. const char *p = m;
  4963. while (isspace(*p))
  4964. p++;
  4965. encodeXML(m, out, ENCODE_WHITESPACE, p-m, true);
  4966. if (*p) { // check not all spaces
  4967. const char *s = p+strlen(p);
  4968. while (isspace(*(s-1)))
  4969. s--;
  4970. assertex(s>p);
  4971. encodeXML(p, out, 0, s-p, true);
  4972. encodeXML(s, out, ENCODE_WHITESPACE, (unsigned)-1, true);
  4973. }
  4974. }
  4975. if (!inlinebody)
  4976. writeStringToStream(out, "\n");
  4977. }
  4978. }
  4979. if (!inlinebody)
  4980. writeCharsNToStream(out, ' ', indent);
  4981. writeStringToStream(out, "</");
  4982. writeStringToStream(out, name);
  4983. if (flags & XML_Format)
  4984. writeStringToStream(out, ">\n");
  4985. else
  4986. writeCharToStream(out, '>');
  4987. }
  4988. jlib_decl StringBuffer &toXML(const IPropertyTree *tree, StringBuffer &ret, unsigned indent, byte flags)
  4989. {
  4990. class CAdapter : public CInterface, implements IIOStream
  4991. {
  4992. StringBuffer &out;
  4993. public:
  4994. IMPLEMENT_IINTERFACE;
  4995. CAdapter(StringBuffer &_out) : out(_out) { }
  4996. virtual void flush() { }
  4997. virtual size32_t read(size32_t len, void * data) { UNIMPLEMENTED; return 0; }
  4998. virtual size32_t write(size32_t len, const void * data) { out.append(len, (const char *)data); return len; }
  4999. } adapter(ret);
  5000. _toXML(tree->queryBranch(NULL), adapter, indent, flags);
  5001. return ret;
  5002. }
  5003. void toXML(const IPropertyTree *tree, IIOStream &out, unsigned indent, byte flags)
  5004. {
  5005. _toXML(tree, out, indent, flags);
  5006. }
  5007. void saveXML(const char *filename, const IPropertyTree *tree, unsigned indent, byte flags)
  5008. {
  5009. OwnedIFile ifile = createIFile(filename);
  5010. saveXML(*ifile, tree, indent, flags);
  5011. }
  5012. void saveXML(IFile &ifile, const IPropertyTree *tree, unsigned indent, byte flags)
  5013. {
  5014. OwnedIFileIO ifileio = ifile.open(IFOcreate);
  5015. if (!ifileio)
  5016. throw MakeStringException(0, "saveXML: could not find %s to open", ifile.queryFilename());
  5017. saveXML(*ifileio, tree, indent, flags);
  5018. }
  5019. void saveXML(IFileIO &ifileio, const IPropertyTree *tree, unsigned indent, byte flags)
  5020. {
  5021. Owned<IIOStream> stream = createIOStream(&ifileio);
  5022. stream.setown(createBufferedIOStream(stream));
  5023. saveXML(*stream, tree, indent, flags);
  5024. }
  5025. void saveXML(IIOStream &stream, const IPropertyTree *tree, unsigned indent, byte flags)
  5026. {
  5027. toXML(tree, stream, indent, flags);
  5028. }
  5029. static inline void skipWS(const char *&xpath)
  5030. {
  5031. while (isspace(*xpath)) xpath++;
  5032. }
  5033. static void _validateXPathSyntax(const char *xpath);
  5034. static void validateQualifier(const char *&xxpath)
  5035. {
  5036. const char *xpath = xxpath;
  5037. bool wild = true; // true by default now, introduced ~ syntax, to denote wild string
  5038. const char *start = xpath;
  5039. skipWS(xpath);
  5040. const char *lhsStart = xpath;
  5041. loop
  5042. {
  5043. switch (*xpath) {
  5044. case ']':
  5045. case '!':
  5046. case '=':
  5047. case '\0':
  5048. break;
  5049. default:
  5050. if (!isspace(*xpath))
  5051. {
  5052. xpath++;
  5053. continue;
  5054. }
  5055. }
  5056. break;
  5057. }
  5058. StringAttr lhs(lhsStart, xpath-lhsStart);
  5059. _validateXPathSyntax(lhs);
  5060. skipWS(xpath);
  5061. exprType tType = t_none;
  5062. if ('=' == *xpath)
  5063. {
  5064. ++xpath;
  5065. tType = t_equality;
  5066. }
  5067. else if ('!' == *xpath)
  5068. {
  5069. ++xpath;
  5070. if (*xpath && '=' == *xpath)
  5071. {
  5072. tType = t_inequality;
  5073. ++xpath;
  5074. }
  5075. else
  5076. throw MakeXPathException(start, PTreeExcpt_XPath_ParseError, 0, "Invalid qualifier expression");
  5077. }
  5078. if (t_none != tType)
  5079. {
  5080. skipWS(xpath);
  5081. if ('~' == *xpath)
  5082. {
  5083. wild = true;
  5084. ++xpath;
  5085. }
  5086. skipWS(xpath);
  5087. char qu = *xpath;
  5088. if (qu != '\'' && qu != '\"')
  5089. throw MakeXPathException(xpath, PTreeExcpt_XPath_ParseError, 0, "Syntax error - no opening \" or \'");
  5090. const char *textStart = ++xpath;
  5091. while (*xpath && *xpath != qu)
  5092. xpath++;
  5093. if (!*xpath)
  5094. throw MakeXPathException(xpath, PTreeExcpt_XPath_ParseError, 0, "Syntax error - no closing \" or \'");
  5095. xpath++;
  5096. }
  5097. skipWS(xpath);
  5098. if (']' != *xpath)
  5099. throw MakeXPathException(start, PTreeExcpt_XPath_ParseError, 0, "No closing brace to qualifier");
  5100. xxpath = xpath;
  5101. }
  5102. static void _validateXPathSyntax(const char *xpath)
  5103. {
  5104. if (NULL == xpath || '\0' == *xpath)
  5105. return;
  5106. else
  5107. {
  5108. const char *_xpath = xpath;
  5109. restart:
  5110. if (NULL == xpath || '\0' == *xpath)
  5111. return;
  5112. switch (*xpath)
  5113. {
  5114. case '.':
  5115. ++xpath;
  5116. goto restart;
  5117. case '/':
  5118. ++xpath;
  5119. if ('/' == *xpath)
  5120. {
  5121. _validateXPathSyntax(xpath+1);
  5122. return;
  5123. }
  5124. goto restart;
  5125. case '[':
  5126. {
  5127. ++xpath;
  5128. if (isdigit(*xpath))
  5129. {
  5130. StringAttr index;
  5131. xpath = readIndex(xpath, index);
  5132. unsigned i = atoi(index.get());
  5133. if (i)
  5134. {
  5135. }
  5136. else
  5137. {
  5138. // should be syntax error
  5139. }
  5140. if (']' != *xpath)
  5141. throw MakeXPathException(_xpath, PTreeExcpt_XPath_ParseError, xpath-_xpath, "Qualifier brace unclosed");
  5142. }
  5143. else
  5144. validateQualifier(xpath);
  5145. ++xpath;
  5146. break;
  5147. }
  5148. default:
  5149. {
  5150. bool wild;
  5151. const char *start = xpath;
  5152. readWildId(xpath, wild); // validates also
  5153. size32_t s = xpath-start;
  5154. if (s)
  5155. {
  5156. StringAttr id(start, s);
  5157. if ('[' == *xpath) // check for local index not iterative qualifier.
  5158. {
  5159. const char *xxpath = xpath+1;
  5160. if (isdigit(*xxpath))
  5161. {
  5162. StringAttr idxstr;
  5163. xxpath = readIndex(xxpath, idxstr);
  5164. if (']' != *xxpath)
  5165. throw MakeXPathException(_xpath, PTreeExcpt_XPath_ParseError, xpath-_xpath, "Qualifier brace unclosed");
  5166. ++xxpath;
  5167. unsigned index = atoi(idxstr.get());
  5168. if (index)
  5169. {
  5170. }
  5171. xpath = xxpath;
  5172. }
  5173. }
  5174. }
  5175. else if ('@' == *xpath)
  5176. {
  5177. ++xpath;
  5178. const char *start = xpath;
  5179. readID(xpath, false);
  5180. size32_t s = xpath-start;
  5181. if (!s)
  5182. throw MakeXPathException(start, PTreeExcpt_XPath_ParseError, xpath-start, "Missing attribute?");
  5183. StringAttr id(start, s);
  5184. if (!validateXMLTag(id))
  5185. throw MakeXPathException(start, PTreeExcpt_XPath_ParseError, xpath-start, "Invalid xml tag: %s", id.get());
  5186. while (isspace(*xpath)) xpath++;
  5187. if ('\0' != *xpath)
  5188. throw MakeXPathException(start, PTreeExcpt_XPath_ParseError, xpath-start, "Cannot have embedded attribute within path (must be tail component)");
  5189. }
  5190. else
  5191. {
  5192. if ('[' != *xpath)
  5193. throw MakeXPathException(xpath, PTreeExcpt_XPath_ParseError, 0, "Qualifier expected e.g. [..]");
  5194. validateQualifier(xpath);
  5195. }
  5196. break;
  5197. }
  5198. }
  5199. }
  5200. if (*xpath == '\0' || (*xpath == '/' && '\0' == *(xpath+1)))
  5201. return;
  5202. else
  5203. _validateXPathSyntax(xpath);
  5204. }
  5205. bool validateXPathSyntax(const char *xpath, StringBuffer *error)
  5206. {
  5207. try
  5208. {
  5209. if (xpath && '/' == *xpath && *(xpath+1) != '/')
  5210. throw MakeXPathException(xpath, PTreeExcpt_XPath_Unsupported, 0, "Root specifier \"/\" specifier is not supported");
  5211. _validateXPathSyntax(xpath);
  5212. return true;
  5213. }
  5214. catch (IException *e)
  5215. {
  5216. if (error)
  5217. e->errorMessage(*error);
  5218. e->Release();
  5219. return false;
  5220. }
  5221. }
  5222. static bool isContentXPath(const char *xpath, StringBuffer &head)
  5223. {
  5224. unsigned l = xpath?strlen(xpath):0;
  5225. const char *x = xpath+l-2;
  5226. if (l>=2 && 0==strcmp(XMLTAG_CONTENT, x))
  5227. {
  5228. if (x != xpath)
  5229. head.append(x-xpath, xpath);
  5230. return true;
  5231. }
  5232. return false;
  5233. }
  5234. bool validateXMLParseXPath(const char *xpath, StringBuffer *error)
  5235. {
  5236. if (!xpath || !*xpath)
  5237. return true;
  5238. StringBuffer head;
  5239. if (isContentXPath(xpath, head))
  5240. {
  5241. if (head.length())
  5242. {
  5243. if ('/' == *xpath && '/' != *(xpath+1))
  5244. {
  5245. if (error)
  5246. {
  5247. Owned<IException> e = MakeStringException(0, "Invalid extract xml text '<>' usage, xpath cannot from be absolute: %s", xpath);
  5248. e->errorMessage(*error);
  5249. }
  5250. return false;
  5251. }
  5252. return validateXPathSyntax(head.toCharArray(), error);
  5253. }
  5254. return true;
  5255. }
  5256. else
  5257. return validateXPathSyntax('/' == *xpath && '/' != *(xpath+1) ? xpath+1 : xpath, error);
  5258. return true;
  5259. }
  5260. bool areMatchingPTrees(IPropertyTree * left, IPropertyTree * right)
  5261. {
  5262. if (left == right)
  5263. return true;
  5264. if (!left || !right)
  5265. return false;
  5266. bool isCaseInsensitive = left->isCaseInsensitive();
  5267. const char * lname = left->queryName();
  5268. const char * rname = right->queryName();
  5269. if (!lname || !rname)
  5270. {
  5271. if (lname || rname)
  5272. return false;
  5273. }
  5274. else if ((isCaseInsensitive ? stricmp(lname, rname) : strcmp(lname, rname)) != 0)
  5275. return false;
  5276. Owned<IAttributeIterator> leftAttrIter = left->getAttributes(true);
  5277. Owned<IAttributeIterator> rightAttrIter = right->getAttributes(true);
  5278. rightAttrIter->first();
  5279. ForEach(*leftAttrIter)
  5280. {
  5281. if (!rightAttrIter->isValid()) return false;
  5282. const char * lname = leftAttrIter->queryName();
  5283. const char * rname = rightAttrIter->queryName();
  5284. if ((isCaseInsensitive ? stricmp(lname, rname) : strcmp(lname, rname)) != 0)
  5285. return false;
  5286. if (strcmp(leftAttrIter->queryValue(), rightAttrIter->queryValue()) != 0)
  5287. return false;
  5288. rightAttrIter->next();
  5289. }
  5290. if (rightAttrIter->isValid()) return false;
  5291. Owned<IPropertyTreeIterator> leftElemIter = left->getElements("*", iptiter_sort);
  5292. Owned<IPropertyTreeIterator> rightElemIter = right->getElements("*", iptiter_sort);
  5293. rightElemIter->first();
  5294. ForEach(*leftElemIter)
  5295. {
  5296. if (!rightElemIter->isValid()) return false;
  5297. if (!areMatchingPTrees(&leftElemIter->query(), &rightElemIter->query()))
  5298. return false;
  5299. rightElemIter->next();
  5300. }
  5301. if (rightElemIter->isValid()) return false;
  5302. return true;
  5303. }
  5304. /////////////////////
  5305. static const char * skipWhitespace(const char * text)
  5306. {
  5307. while ((*text==' ') || (*text=='\t'))
  5308. text++;
  5309. return text;
  5310. }
  5311. static const char * skipAsterisk(const char * text)
  5312. {
  5313. if (*text=='*')
  5314. return skipWhitespace(text+1);
  5315. return text;
  5316. }
  5317. static const char * skipToNewline(const char * text)
  5318. {
  5319. while (*text && (*text != '\r') && (*text != '\n'))
  5320. text++;
  5321. return text;
  5322. }
  5323. static const char * skipNewline(const char * text)
  5324. {
  5325. if (*text == '\r')
  5326. text++;
  5327. if (*text == '\n')
  5328. text++;
  5329. return text;
  5330. }
  5331. void extractJavadoc(IPropertyTree * result, const char * text)
  5332. {
  5333. //Skip a leading blank line
  5334. text = skipWhitespace(text);
  5335. text = skipNewline(text);
  5336. //Now process each of the parameters...
  5337. StringBuffer tagname;
  5338. StringBuffer tagtext;
  5339. loop
  5340. {
  5341. text = skipWhitespace(text);
  5342. text = skipAsterisk(text);
  5343. if ((*text == 0) || (*text == '@'))
  5344. {
  5345. if (tagtext.length())
  5346. {
  5347. if (tagname.length())
  5348. result->addProp(tagname.str(), tagtext.str());
  5349. else
  5350. result->setProp("", tagtext.str());
  5351. tagtext.clear();
  5352. }
  5353. if (*text == 0)
  5354. return;
  5355. text++;
  5356. const char * start = text;
  5357. while (isalnum(*text))
  5358. text++;
  5359. if (start != text)
  5360. tagname.clear().append(text-start, start);
  5361. text = skipWhitespace(text);
  5362. }
  5363. const char * start = text;
  5364. text = skipToNewline(text);
  5365. if (start != text)
  5366. {
  5367. if (tagtext.length())
  5368. tagtext.append(" ");
  5369. tagtext.append(text-start, start);
  5370. }
  5371. text = skipNewline(text);
  5372. }
  5373. }
  5374. /////////////////////
  5375. #ifdef _DEBUG
  5376. jlib_decl void validatePTree()
  5377. {
  5378. Owned<IPropertyTree> testTree = createPTreeFromXMLString(
  5379. "<ROOT>" \
  5380. " <E a=\"av1\" b=\"bv1\" c=\"cv1\"></E>" \
  5381. " <E a=\"av1\" b=\"bv1\" c=\"cv2\"></E>" \
  5382. " <E a=\"av2\" b=\"bv1\"></E>" \
  5383. " <SE c=\"cv1\"></SE>" \
  5384. " <E a=\"av1\" b=\"bv2\"></E>" \
  5385. " <E a=\"av2\" b=\"bv2\" c=\"cv3\">ev1</E>" \
  5386. "</ROOT>"
  5387. );
  5388. Owned<IPropertyTreeIterator> iter = testTree->getElements("E[@a=\"av1\"][@b=\"bv2\"]");
  5389. unsigned c = 0;
  5390. ForEach (*iter)
  5391. ++c;
  5392. assertex(1 == c);
  5393. int v = strcmp("bv1", testTree->queryProp("E[@a=\"av1\"][2]/@b"));
  5394. assertex(0 == v);
  5395. v = strcmp("cv2", testTree->queryProp("E[@a=\"av1\"][@b=\"bv1\"][2]/@c"));
  5396. assertex(0 == v);
  5397. v = strcmp("cv2", testTree->queryProp("E[@a=\"av1\"][2]/@c"));
  5398. assertex(0 == v);
  5399. v = strcmp("ev1", testTree->queryProp("E[@a=\"av2\"][@c]"));
  5400. assertex(0 == v);
  5401. }
  5402. jlib_decl void testValidateXPathSyntax()
  5403. {
  5404. verifyex(validateXPathSyntax("@abc"));
  5405. verifyex(validateXPathSyntax("prop"));
  5406. verifyex(validateXPathSyntax("a/b"));
  5407. verifyex(validateXPathSyntax("a/@b"));
  5408. const char *s = "a[@a=\"blah\"]/b";
  5409. verifyex(validateXPathSyntax(s));
  5410. s = "a/b[@b=\"blah\"]";
  5411. verifyex(validateXPathSyntax(s));
  5412. verifyex(validateXPathSyntax(s));
  5413. s = "a/b[b=\"blah\"]";
  5414. verifyex(validateXPathSyntax(s));
  5415. s = "a/b[a/b=\"blah\"]";
  5416. verifyex(validateXPathSyntax(s));
  5417. verifyex(validateXPathSyntax("a[1]/b[2]"));
  5418. s = "a[b]/b[c=\"a\"]/c";
  5419. verifyex(validateXPathSyntax(s));
  5420. verifyex(validateXPathSyntax("//a/b/c"));
  5421. verifyex(!validateXPathSyntax("a[b"));
  5422. verifyex(!validateXPathSyntax("a["));
  5423. verifyex(!validateXPathSyntax("a]"));
  5424. verifyex(!validateXPathSyntax("a[b=blah]"));
  5425. verifyex(!validateXPathSyntax("@a/b"));
  5426. verifyex(!validateXPathSyntax("a[b[c]]"));
  5427. verifyex(validateXMLParseXPath("<>"));
  5428. verifyex(validateXMLParseXPath("a/b/c<>"));
  5429. verifyex(validateXMLParseXPath("a/b/<>"));
  5430. verifyex(validateXMLParseXPath("/a/b"));
  5431. verifyex(!validateXMLParseXPath("a/b[\"]/<>"));
  5432. verifyex(!validateXMLParseXPath("/<>"));
  5433. }
  5434. jlib_decl void testJdocCompare()
  5435. {
  5436. Owned<IPropertyTree> t1 = createPTree();
  5437. Owned<IPropertyTree> t2 = createPTree();
  5438. Owned<IPropertyTree> t3 = createPTree();
  5439. Owned<IPropertyTree> t4 = createPTree();
  5440. Owned<IPropertyTree> t5 = createPTree();
  5441. extractJavadoc(t1, "Defines a record that contains information about a person");
  5442. extractJavadoc(t2, "Allows the name table to be filtered.\n\n@param ages\tThe ages that are allowed to be processed.\n\t\tbadForename Forname to avoid.\n\n@return\tthe filtered dataset.");
  5443. extractJavadoc(t3, "Allows the name table to be filtered.\n\n@param ages\tThe ages that are allowed to be processed.\n\t\tbadForename Forname to avoid.\n\n@return\tthe filtered dataset.");
  5444. extractJavadoc(t4, "Allows the name table to be filtered.\n\n@param ages\tThe ages that are allowed to be processed.\n\t\tbadForename Forname to avoid.\n\n@return\tthe filtered dataset.");
  5445. extractJavadoc(t5, "Allows the name table to be filtered.\n\n@param ages\tThe ages that are allowed to be processed.\n\t\tbadForename Forname to avoid.\n\n@return\tthe filtered dataset.");
  5446. IPropertyTree * t2c = t2->addPropTree("Child1", createPTree());
  5447. extractJavadoc(t2c, "This is some child data\n\n@param ages\tThe ages that are allowed to be processed.");
  5448. IPropertyTree * t3c = t3->addPropTree("Child1", createPTree());
  5449. extractJavadoc(t3c, "This is some child data\n\n@param ages\tThe ages that are allowed to be processed.");
  5450. IPropertyTree * t4c = t4->addPropTree("Child1", createPTree());
  5451. extractJavadoc(t4c, "This is some child data\n\n@param ages\tThe ages that are allowed to be processed, but differs.");
  5452. IPropertyTree * t5c = t5->addPropTree("Child1", createPTree());
  5453. extractJavadoc(t5c, "This is some child data\n\n@param ages\tThe ages that are allowed to be processed.");
  5454. t2->setProp("@childAttr", "1");
  5455. t3->setProp("@childAttr", "1");
  5456. t4->setProp("@childAttr", "1");
  5457. t5->setProp("@childAttr", "2");
  5458. verifyex(areMatchingPTrees(NULL, NULL));
  5459. verifyex(!areMatchingPTrees(NULL, t1));
  5460. verifyex(!areMatchingPTrees(t1, NULL));
  5461. verifyex(areMatchingPTrees(t1, t1));
  5462. verifyex(areMatchingPTrees(t2, t3));
  5463. verifyex(!areMatchingPTrees(t2, t4));
  5464. verifyex(!areMatchingPTrees(t2, t5));
  5465. }
  5466. #endif
  5467. class COrderedPTree : public PTree
  5468. {
  5469. template <class BASECHILDMAP>
  5470. class jlib_decl COrderedChildMap : public BASECHILDMAP
  5471. {
  5472. typedef COrderedChildMap<BASECHILDMAP> SELF;
  5473. ICopyArrayOf<IPropertyTree> order;
  5474. public:
  5475. IMPLEMENT_SUPERHASHTABLEOF_REF_FIND(IPropertyTree, constcharptr);
  5476. COrderedChildMap<BASECHILDMAP>() : BASECHILDMAP() { }
  5477. ~COrderedChildMap<BASECHILDMAP>() { SELF::kill(); }
  5478. virtual unsigned numChildren() { return order.ordinality(); }
  5479. virtual IPropertyTreeIterator *getIterator(bool sort)
  5480. {
  5481. class CPTArrayIterator : public ArrayIIteratorOf<IArrayOf<IPropertyTree>, IPropertyTree, IPropertyTreeIterator>
  5482. {
  5483. IArrayOf<IPropertyTree> elems;
  5484. public:
  5485. CPTArrayIterator(ICopyArrayOf<IPropertyTree> &order, bool sort) : ArrayIIteratorOf<IArrayOf<IPropertyTree>, IPropertyTree, IPropertyTreeIterator>(elems)
  5486. {
  5487. ForEachItemIn(e, order)
  5488. elems.append(*LINK(&order.item(e)));
  5489. if (sort)
  5490. elems.sort(comparePropTrees);
  5491. }
  5492. };
  5493. return new CPTArrayIterator(order, sort);
  5494. }
  5495. virtual bool set(const char *key, IPropertyTree *tree)
  5496. {
  5497. IPropertyTree *existing = find(*key);
  5498. if (existing)
  5499. {
  5500. unsigned pos = order.find(*existing);
  5501. BASECHILDMAP::set(key, tree);
  5502. order.replace(*tree, pos);
  5503. }
  5504. else
  5505. {
  5506. BASECHILDMAP::set(key, tree);
  5507. order.append(*tree);
  5508. }
  5509. return true;
  5510. }
  5511. virtual bool replace(const char *key, IPropertyTree *tree) // provides different semantics, used if element being replaced is not to be treated as deleted.
  5512. {
  5513. return set(key, tree);
  5514. }
  5515. virtual bool remove(const char *key)
  5516. {
  5517. IPropertyTree *child = BASECHILDMAP::find(*key);
  5518. if (!child)
  5519. return false;
  5520. order.zap(*child);
  5521. return BASECHILDMAP::removeExact(child);
  5522. }
  5523. virtual bool removeExact(IPropertyTree *child)
  5524. {
  5525. order.zap(*child);
  5526. return BASECHILDMAP::removeExact(child);
  5527. }
  5528. };
  5529. public:
  5530. COrderedPTree(const char *name=NULL, byte flags=ipt_none, IPTArrayValue *value=NULL, ChildMap *children=NULL)
  5531. : PTree(name, flags|ipt_ordered, value, children) { }
  5532. virtual bool isEquivalent(IPropertyTree *tree) { return (NULL != QUERYINTERFACE(tree, COrderedPTree)); }
  5533. virtual IPropertyTree *create(const char *name=NULL, IPTArrayValue *value=NULL, ChildMap *children=NULL, bool existing=false)
  5534. {
  5535. return new COrderedPTree(name, flags, value, children);
  5536. }
  5537. virtual IPropertyTree *create(MemoryBuffer &mb)
  5538. {
  5539. IPropertyTree *tree = new COrderedPTree();
  5540. tree->deserialize(mb);
  5541. return tree;
  5542. }
  5543. virtual void createChildMap()
  5544. {
  5545. if (isnocase())
  5546. children = new COrderedChildMap<ChildMapNC>();
  5547. else
  5548. children = new COrderedChildMap<ChildMap>();
  5549. }
  5550. };
  5551. IPropertyTree *createPTree(byte flags)
  5552. {
  5553. if (flags & ipt_ordered)
  5554. return new COrderedPTree(NULL, flags);
  5555. else
  5556. return new LocalPTree(NULL, flags);
  5557. }
  5558. IPropertyTree *createPTree(const char *name, byte flags)
  5559. {
  5560. if (flags & ipt_ordered)
  5561. return new COrderedPTree(name, flags);
  5562. else
  5563. return new LocalPTree(name, flags);
  5564. }