jptree.cpp 209 KB

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