Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089/* * tree.c : implementation of access function for an XML tree. * * References: * XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/ * * See Copyright for the status of this software. * * daniel@veillard.com * */
/* To avoid EBCDIC trouble when parsing on zOS */#if defined(__MVS__)#pragma convert("ISO8859-1")#endif
#define IN_LIBXML#include "libxml.h"
#include <string.h> /* for memset() only ! */#include <stddef.h>#include <limits.h>#include <ctype.h>#include <stdlib.h>
#ifdef LIBXML_ZLIB_ENABLED#include <zlib.h>#endif
#include <libxml/tree.h>#include <libxml/xmlmemory.h>#include <libxml/parser.h>#include <libxml/uri.h>#include <libxml/entities.h>#include <libxml/xmlerror.h>#include <libxml/parserInternals.h>#ifdef LIBXML_HTML_ENABLED#include <libxml/HTMLtree.h>#endif#ifdef LIBXML_DEBUG_ENABLED#include <libxml/debugXML.h>#endif
#include "private/buf.h"#include "private/entities.h"#include "private/error.h"#include "private/tree.h"
int __xmlRegisterCallbacks = 0;
/************************************************************************ * * * Forward declarations * * * ************************************************************************/
static xmlNsPtrxmlNewReconciledNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
static xmlChar* xmlGetPropNodeValueInternal(const xmlAttr *prop);
/************************************************************************ * * * Tree memory error handler * * * ************************************************************************//** * xmlTreeErrMemory: * @extra: extra information * * Handle an out of memory condition */static voidxmlTreeErrMemory(const char *extra){ __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);}
/** * xmlTreeErr: * @code: the error number * @extra: extra information * * Handle an out of memory condition */static voidxmlTreeErr(int code, xmlNodePtr node, const char *extra){ const char *msg = NULL;
switch(code) { case XML_TREE_INVALID_HEX: msg = "invalid hexadecimal character value\n"; break; case XML_TREE_INVALID_DEC: msg = "invalid decimal character value\n"; break; case XML_TREE_UNTERMINATED_ENTITY: msg = "unterminated entity reference %15s\n"; break; case XML_TREE_NOT_UTF8: msg = "string is not in UTF-8\n"; break; default: msg = "unexpected error number\n"; } __xmlSimpleError(XML_FROM_TREE, code, node, msg, extra);}
/************************************************************************ * * * A few static variables and macros * * * ************************************************************************//* #undef xmlStringText */const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };/* #undef xmlStringTextNoenc */const xmlChar xmlStringTextNoenc[] = { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };/* #undef xmlStringComment */const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
static int xmlCompressMode = 0;static int xmlCheckDTD = 1;
#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \ xmlNodePtr ulccur = (n)->children; \ if (ulccur == NULL) { \ (n)->last = NULL; \ } else { \ while (ulccur->next != NULL) { \ ulccur->parent = (n); \ ulccur = ulccur->next; \ } \ ulccur->parent = (n); \ (n)->last = ulccur; \}}
#define IS_STR_XML(str) ((str != NULL) && (str[0] == 'x') && \ (str[1] == 'm') && (str[2] == 'l') && (str[3] == 0))
/************************************************************************ * * * Functions to move to entities.c once the * * API freeze is smoothen and they can be made public. * * * ************************************************************************/#include <libxml/hash.h>
#ifdef LIBXML_TREE_ENABLED/** * xmlGetEntityFromDtd: * @dtd: A pointer to the DTD to search * @name: The entity name * * Do an entity lookup in the DTD entity hash table and * return the corresponding entity, if found. * * Returns A pointer to the entity structure or NULL if not found. */static xmlEntityPtrxmlGetEntityFromDtd(const xmlDtd *dtd, const xmlChar *name) { xmlEntitiesTablePtr table;
if((dtd != NULL) && (dtd->entities != NULL)) { table = (xmlEntitiesTablePtr) dtd->entities; return((xmlEntityPtr) xmlHashLookup(table, name)); /* return(xmlGetEntityFromTable(table, name)); */ } return(NULL);}/** * xmlGetParameterEntityFromDtd: * @dtd: A pointer to the DTD to search * @name: The entity name * * Do an entity lookup in the DTD parameter entity hash table and * return the corresponding entity, if found. * * Returns A pointer to the entity structure or NULL if not found. */static xmlEntityPtrxmlGetParameterEntityFromDtd(const xmlDtd *dtd, const xmlChar *name) { xmlEntitiesTablePtr table;
if ((dtd != NULL) && (dtd->pentities != NULL)) { table = (xmlEntitiesTablePtr) dtd->pentities; return((xmlEntityPtr) xmlHashLookup(table, name)); /* return(xmlGetEntityFromTable(table, name)); */ } return(NULL);}#endif /* LIBXML_TREE_ENABLED */
/************************************************************************ * * * QName handling helper * * * ************************************************************************/
/** * xmlBuildQName: * @ncname: the Name * @prefix: the prefix * @memory: preallocated memory * @len: preallocated memory length * * Builds the QName @prefix:@ncname in @memory if there is enough space * and prefix is not NULL nor empty, otherwise allocate a new string. * If prefix is NULL or empty it returns ncname. * * Returns the new string which must be freed by the caller if different from * @memory and @ncname or NULL in case of error */xmlChar *xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix, xmlChar *memory, int len) { int lenn, lenp; xmlChar *ret;
if (ncname == NULL) return(NULL); if (prefix == NULL) return((xmlChar *) ncname);
lenn = strlen((char *) ncname); lenp = strlen((char *) prefix);
if ((memory == NULL) || (len < lenn + lenp + 2)) { ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2); if (ret == NULL) { xmlTreeErrMemory("building QName"); return(NULL); } } else { ret = memory; } memcpy(&ret[0], prefix, lenp); ret[lenp] = ':'; memcpy(&ret[lenp + 1], ncname, lenn); ret[lenn + lenp + 1] = 0; return(ret);}
/** * xmlSplitQName2: * @name: the full QName * @prefix: a xmlChar ** * * parse an XML qualified name string * * [NS 5] QName ::= (Prefix ':')? LocalPart * * [NS 6] Prefix ::= NCName * * [NS 7] LocalPart ::= NCName * * Returns NULL if the name doesn't have a prefix. Otherwise, returns the * local part, and prefix is updated to get the Prefix. Both the return value * and the prefix must be freed by the caller. */xmlChar *xmlSplitQName2(const xmlChar *name, xmlChar **prefix) { int len = 0; xmlChar *ret = NULL;
if (prefix == NULL) return(NULL); *prefix = NULL; if (name == NULL) return(NULL);
#ifndef XML_XML_NAMESPACE /* xml: prefix is not really a namespace */ if ((name[0] == 'x') && (name[1] == 'm') && (name[2] == 'l') && (name[3] == ':')) return(NULL);#endif
/* nasty but valid */ if (name[0] == ':') return(NULL);
/* * we are not trying to validate but just to cut, and yes it will * work even if this is as set of UTF-8 encoded chars */ while ((name[len] != 0) && (name[len] != ':')) len++;
if (name[len] == 0) return(NULL);
*prefix = xmlStrndup(name, len); if (*prefix == NULL) { xmlTreeErrMemory("QName split"); return(NULL); } ret = xmlStrdup(&name[len + 1]); if (ret == NULL) { xmlTreeErrMemory("QName split"); if (*prefix != NULL) { xmlFree(*prefix); *prefix = NULL; } return(NULL); }
return(ret);}
/** * xmlSplitQName3: * @name: the full QName * @len: an int * * * parse an XML qualified name string,i * * returns NULL if it is not a Qualified Name, otherwise, update len * with the length in byte of the prefix and return a pointer * to the start of the name without the prefix */
const xmlChar *xmlSplitQName3(const xmlChar *name, int *len) { int l = 0;
if (name == NULL) return(NULL); if (len == NULL) return(NULL);
/* nasty but valid */ if (name[0] == ':') return(NULL);
/* * we are not trying to validate but just to cut, and yes it will * work even if this is as set of UTF-8 encoded chars */ while ((name[l] != 0) && (name[l] != ':')) l++;
if (name[l] == 0) return(NULL);
*len = l;
return(&name[l+1]);}
/************************************************************************ * * * Check Name, NCName and QName strings * * * ************************************************************************/
#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
/** * xmlValidateNCName: * @value: the value to check * @space: allow spaces in front and end of the string * * Check that a value conforms to the lexical space of NCName * * Returns 0 if this validates, a positive error code number otherwise * and -1 in case of internal or API error. */intxmlValidateNCName(const xmlChar *value, int space) { const xmlChar *cur = value; int c,l;
if (value == NULL) return(-1);
/* * First quick algorithm for ASCII range */ if (space) while (IS_BLANK_CH(*cur)) cur++; if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) || (*cur == '_')) cur++; else goto try_complex; while (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) || ((*cur >= '0') && (*cur <= '9')) || (*cur == '_') || (*cur == '-') || (*cur == '.')) cur++; if (space) while (IS_BLANK_CH(*cur)) cur++; if (*cur == 0) return(0);
try_complex: /* * Second check for chars outside the ASCII range */ cur = value; c = CUR_SCHAR(cur, l); if (space) { while (IS_BLANK(c)) { cur += l; c = CUR_SCHAR(cur, l); } } if ((!IS_LETTER(c)) && (c != '_')) return(1); cur += l; c = CUR_SCHAR(cur, l); while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) { cur += l; c = CUR_SCHAR(cur, l); } if (space) { while (IS_BLANK(c)) { cur += l; c = CUR_SCHAR(cur, l); } } if (c != 0) return(1);
return(0);}
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)/** * xmlValidateQName: * @value: the value to check * @space: allow spaces in front and end of the string * * Check that a value conforms to the lexical space of QName * * Returns 0 if this validates, a positive error code number otherwise * and -1 in case of internal or API error. */intxmlValidateQName(const xmlChar *value, int space) { const xmlChar *cur = value; int c,l;
if (value == NULL) return(-1); /* * First quick algorithm for ASCII range */ if (space) while (IS_BLANK_CH(*cur)) cur++; if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) || (*cur == '_')) cur++; else goto try_complex; while (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) || ((*cur >= '0') && (*cur <= '9')) || (*cur == '_') || (*cur == '-') || (*cur == '.')) cur++; if (*cur == ':') { cur++; if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) || (*cur == '_')) cur++; else goto try_complex; while (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) || ((*cur >= '0') && (*cur <= '9')) || (*cur == '_') || (*cur == '-') || (*cur == '.')) cur++; } if (space) while (IS_BLANK_CH(*cur)) cur++; if (*cur == 0) return(0);
try_complex: /* * Second check for chars outside the ASCII range */ cur = value; c = CUR_SCHAR(cur, l); if (space) { while (IS_BLANK(c)) { cur += l; c = CUR_SCHAR(cur, l); } } if ((!IS_LETTER(c)) && (c != '_')) return(1); cur += l; c = CUR_SCHAR(cur, l); while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) { cur += l; c = CUR_SCHAR(cur, l); } if (c == ':') { cur += l; c = CUR_SCHAR(cur, l); if ((!IS_LETTER(c)) && (c != '_')) return(1); cur += l; c = CUR_SCHAR(cur, l); while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) { cur += l; c = CUR_SCHAR(cur, l); } } if (space) { while (IS_BLANK(c)) { cur += l; c = CUR_SCHAR(cur, l); } } if (c != 0) return(1); return(0);}
/** * xmlValidateName: * @value: the value to check * @space: allow spaces in front and end of the string * * Check that a value conforms to the lexical space of Name * * Returns 0 if this validates, a positive error code number otherwise * and -1 in case of internal or API error. */intxmlValidateName(const xmlChar *value, int space) { const xmlChar *cur = value; int c,l;
if (value == NULL) return(-1); /* * First quick algorithm for ASCII range */ if (space) while (IS_BLANK_CH(*cur)) cur++; if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) || (*cur == '_') || (*cur == ':')) cur++; else goto try_complex; while (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) || ((*cur >= '0') && (*cur <= '9')) || (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':')) cur++; if (space) while (IS_BLANK_CH(*cur)) cur++; if (*cur == 0) return(0);
try_complex: /* * Second check for chars outside the ASCII range */ cur = value; c = CUR_SCHAR(cur, l); if (space) { while (IS_BLANK(c)) { cur += l; c = CUR_SCHAR(cur, l); } } if ((!IS_LETTER(c)) && (c != '_') && (c != ':')) return(1); cur += l; c = CUR_SCHAR(cur, l); while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') || (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) { cur += l; c = CUR_SCHAR(cur, l); } if (space) { while (IS_BLANK(c)) { cur += l; c = CUR_SCHAR(cur, l); } } if (c != 0) return(1); return(0);}
/** * xmlValidateNMToken: * @value: the value to check * @space: allow spaces in front and end of the string * * Check that a value conforms to the lexical space of NMToken * * Returns 0 if this validates, a positive error code number otherwise * and -1 in case of internal or API error. */intxmlValidateNMToken(const xmlChar *value, int space) { const xmlChar *cur = value; int c,l;
if (value == NULL) return(-1); /* * First quick algorithm for ASCII range */ if (space) while (IS_BLANK_CH(*cur)) cur++; if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) || ((*cur >= '0') && (*cur <= '9')) || (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':')) cur++; else goto try_complex; while (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) || ((*cur >= '0') && (*cur <= '9')) || (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':')) cur++; if (space) while (IS_BLANK_CH(*cur)) cur++; if (*cur == 0) return(0);
try_complex: /* * Second check for chars outside the ASCII range */ cur = value; c = CUR_SCHAR(cur, l); if (space) { while (IS_BLANK(c)) { cur += l; c = CUR_SCHAR(cur, l); } } if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') || (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c))) return(1); cur += l; c = CUR_SCHAR(cur, l); while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') || (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) { cur += l; c = CUR_SCHAR(cur, l); } if (space) { while (IS_BLANK(c)) { cur += l; c = CUR_SCHAR(cur, l); } } if (c != 0) return(1); return(0);}#endif /* LIBXML_TREE_ENABLED */
/************************************************************************ * * * Allocation and deallocation of basic structures * * * ************************************************************************/
/** * xmlSetBufferAllocationScheme: * @scheme: allocation method to use * * Set the buffer allocation method. Types are * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed, * improves performance */voidxmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) { if ((scheme == XML_BUFFER_ALLOC_EXACT) || (scheme == XML_BUFFER_ALLOC_DOUBLEIT) || (scheme == XML_BUFFER_ALLOC_HYBRID)) xmlBufferAllocScheme = scheme;}
/** * xmlGetBufferAllocationScheme: * * Types are * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed, * improves performance * XML_BUFFER_ALLOC_HYBRID - use exact sizes on small strings to keep memory usage tight * in normal usage, and doubleit on large strings to avoid * pathological performance. * * Returns the current allocation scheme */xmlBufferAllocationSchemexmlGetBufferAllocationScheme(void) { return(xmlBufferAllocScheme);}
/** * xmlNewNs: * @node: the element carrying the namespace * @href: the URI associated * @prefix: the prefix for the namespace * * Creation of a new Namespace. This function will refuse to create * a namespace with a similar prefix than an existing one present on this * node. * Note that for a default namespace, @prefix should be NULL. * * We use href==NULL in the case of an element creation where the namespace * was not defined. * * Returns a new namespace pointer or NULL */xmlNsPtrxmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) { xmlNsPtr cur;
if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) return(NULL);
if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml"))) { /* xml namespace is predefined, no need to add it */ if (xmlStrEqual(href, XML_XML_NAMESPACE)) return(NULL);
/* * Problem, this is an attempt to bind xml prefix to a wrong * namespace, which breaks * Namespace constraint: Reserved Prefixes and Namespace Names * from XML namespace. But documents authors may not care in * their context so let's proceed. */ }
/* * Allocate a new Namespace and fill the fields. */ cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); if (cur == NULL) { xmlTreeErrMemory("building namespace"); return(NULL); } memset(cur, 0, sizeof(xmlNs)); cur->type = XML_LOCAL_NAMESPACE;
if (href != NULL) cur->href = xmlStrdup(href); if (prefix != NULL) cur->prefix = xmlStrdup(prefix);
/* * Add it at the end to preserve parsing order ... * and checks for existing use of the prefix */ if (node != NULL) { if (node->nsDef == NULL) { node->nsDef = cur; } else { xmlNsPtr prev = node->nsDef;
if (((prev->prefix == NULL) && (cur->prefix == NULL)) || (xmlStrEqual(prev->prefix, cur->prefix))) { xmlFreeNs(cur); return(NULL); } while (prev->next != NULL) { prev = prev->next; if (((prev->prefix == NULL) && (cur->prefix == NULL)) || (xmlStrEqual(prev->prefix, cur->prefix))) { xmlFreeNs(cur); return(NULL); } } prev->next = cur; } } return(cur);}
/** * xmlSetNs: * @node: a node in the document * @ns: a namespace pointer * * Associate a namespace to a node, a posteriori. */voidxmlSetNs(xmlNodePtr node, xmlNsPtr ns) { if (node == NULL) { return; } if ((node->type == XML_ELEMENT_NODE) || (node->type == XML_ATTRIBUTE_NODE)) node->ns = ns;}
/** * xmlFreeNs: * @cur: the namespace pointer * * Free up the structures associated to a namespace */voidxmlFreeNs(xmlNsPtr cur) { if (cur == NULL) { return; } if (cur->href != NULL) xmlFree((char *) cur->href); if (cur->prefix != NULL) xmlFree((char *) cur->prefix); xmlFree(cur);}
/** * xmlFreeNsList: * @cur: the first namespace pointer * * Free up all the structures associated to the chained namespaces. */voidxmlFreeNsList(xmlNsPtr cur) { xmlNsPtr next; if (cur == NULL) { return; } while (cur != NULL) { next = cur->next; xmlFreeNs(cur); cur = next; }}
/** * xmlNewDtd: * @doc: the document pointer * @name: the DTD name * @ExternalID: the external ID * @SystemID: the system ID * * Creation of a new DTD for the external subset. To create an * internal subset, use xmlCreateIntSubset(). * * Returns a pointer to the new DTD structure */xmlDtdPtrxmlNewDtd(xmlDocPtr doc, const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID) { xmlDtdPtr cur;
if ((doc != NULL) && (doc->extSubset != NULL)) { return(NULL); }
/* * Allocate a new DTD and fill the fields. */ cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd)); if (cur == NULL) { xmlTreeErrMemory("building DTD"); return(NULL); } memset(cur, 0 , sizeof(xmlDtd)); cur->type = XML_DTD_NODE;
if (name != NULL) cur->name = xmlStrdup(name); if (ExternalID != NULL) cur->ExternalID = xmlStrdup(ExternalID); if (SystemID != NULL) cur->SystemID = xmlStrdup(SystemID); if (doc != NULL) doc->extSubset = cur; cur->doc = doc;
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue((xmlNodePtr)cur); return(cur);}
/** * xmlGetIntSubset: * @doc: the document pointer * * Get the internal subset of a document * Returns a pointer to the DTD structure or NULL if not found */
xmlDtdPtrxmlGetIntSubset(const xmlDoc *doc) { xmlNodePtr cur;
if (doc == NULL) return(NULL); cur = doc->children; while (cur != NULL) { if (cur->type == XML_DTD_NODE) return((xmlDtdPtr) cur); cur = cur->next; } return((xmlDtdPtr) doc->intSubset);}
/** * xmlCreateIntSubset: * @doc: the document pointer * @name: the DTD name * @ExternalID: the external (PUBLIC) ID * @SystemID: the system ID * * Create the internal subset of a document * Returns a pointer to the new DTD structure */xmlDtdPtrxmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID) { xmlDtdPtr cur;
if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) { return(NULL); }
/* * Allocate a new DTD and fill the fields. */ cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd)); if (cur == NULL) { xmlTreeErrMemory("building internal subset"); return(NULL); } memset(cur, 0, sizeof(xmlDtd)); cur->type = XML_DTD_NODE;
if (name != NULL) { cur->name = xmlStrdup(name); if (cur->name == NULL) { xmlTreeErrMemory("building internal subset"); xmlFree(cur); return(NULL); } } if (ExternalID != NULL) { cur->ExternalID = xmlStrdup(ExternalID); if (cur->ExternalID == NULL) { xmlTreeErrMemory("building internal subset"); if (cur->name != NULL) xmlFree((char *)cur->name); xmlFree(cur); return(NULL); } } if (SystemID != NULL) { cur->SystemID = xmlStrdup(SystemID); if (cur->SystemID == NULL) { xmlTreeErrMemory("building internal subset"); if (cur->name != NULL) xmlFree((char *)cur->name); if (cur->ExternalID != NULL) xmlFree((char *)cur->ExternalID); xmlFree(cur); return(NULL); } } if (doc != NULL) { doc->intSubset = cur; cur->parent = doc; cur->doc = doc; if (doc->children == NULL) { doc->children = (xmlNodePtr) cur; doc->last = (xmlNodePtr) cur; } else { if (doc->type == XML_HTML_DOCUMENT_NODE) { xmlNodePtr prev;
prev = doc->children; prev->prev = (xmlNodePtr) cur; cur->next = prev; doc->children = (xmlNodePtr) cur; } else { xmlNodePtr next;
next = doc->children; while ((next != NULL) && (next->type != XML_ELEMENT_NODE)) next = next->next; if (next == NULL) { cur->prev = doc->last; cur->prev->next = (xmlNodePtr) cur; cur->next = NULL; doc->last = (xmlNodePtr) cur; } else { cur->next = next; cur->prev = next->prev; if (cur->prev == NULL) doc->children = (xmlNodePtr) cur; else cur->prev->next = (xmlNodePtr) cur; next->prev = (xmlNodePtr) cur; } } } }
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue((xmlNodePtr)cur); return(cur);}
/** * DICT_FREE: * @str: a string * * Free a string if it is not owned by the "dict" dictionary in the * current scope */#define DICT_FREE(str) \ if ((str) && ((!dict) || \ (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \ xmlFree((char *)(str));
/** * DICT_COPY: * @str: a string * * Copy a string using a "dict" dictionary in the current scope, * if available. */#define DICT_COPY(str, cpy) \ if (str) { \ if (dict) { \ if (xmlDictOwns(dict, (const xmlChar *)(str))) \ cpy = (xmlChar *) (str); \ else \ cpy = (xmlChar *) xmlDictLookup((dict), (const xmlChar *)(str), -1); \ } else \ cpy = xmlStrdup((const xmlChar *)(str)); }
/** * DICT_CONST_COPY: * @str: a string * * Copy a string using a "dict" dictionary in the current scope, * if available. */#define DICT_CONST_COPY(str, cpy) \ if (str) { \ if (dict) { \ if (xmlDictOwns(dict, (const xmlChar *)(str))) \ cpy = (const xmlChar *) (str); \ else \ cpy = xmlDictLookup((dict), (const xmlChar *)(str), -1); \ } else \ cpy = (const xmlChar *) xmlStrdup((const xmlChar *)(str)); }
/** * xmlFreeDtd: * @cur: the DTD structure to free up * * Free a DTD structure. */voidxmlFreeDtd(xmlDtdPtr cur) { xmlDictPtr dict = NULL;
if (cur == NULL) { return; } if (cur->doc != NULL) dict = cur->doc->dict;
if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
if (cur->children != NULL) { xmlNodePtr next, c = cur->children;
/* * Cleanup all nodes which are not part of the specific lists * of notations, elements, attributes and entities. */ while (c != NULL) { next = c->next; if ((c->type != XML_NOTATION_NODE) && (c->type != XML_ELEMENT_DECL) && (c->type != XML_ATTRIBUTE_DECL) && (c->type != XML_ENTITY_DECL)) { xmlUnlinkNode(c); xmlFreeNode(c); } c = next; } } DICT_FREE(cur->name) DICT_FREE(cur->SystemID) DICT_FREE(cur->ExternalID) /* TODO !!! */ if (cur->notations != NULL) xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
if (cur->elements != NULL) xmlFreeElementTable((xmlElementTablePtr) cur->elements); if (cur->attributes != NULL) xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes); if (cur->entities != NULL) xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities); if (cur->pentities != NULL) xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
xmlFree(cur);}
/** * xmlNewDoc: * @version: xmlChar string giving the version of XML "1.0" * * Creates a new XML document * * Returns a new document */xmlDocPtrxmlNewDoc(const xmlChar *version) { xmlDocPtr cur;
if (version == NULL) version = (const xmlChar *) "1.0";
/* * Allocate a new document and fill the fields. */ cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc)); if (cur == NULL) { xmlTreeErrMemory("building doc"); return(NULL); } memset(cur, 0, sizeof(xmlDoc)); cur->type = XML_DOCUMENT_NODE;
cur->version = xmlStrdup(version); if (cur->version == NULL) { xmlTreeErrMemory("building doc"); xmlFree(cur); return(NULL); } cur->standalone = -1; cur->compression = -1; /* not initialized */ cur->doc = cur; cur->parseFlags = 0; cur->properties = XML_DOC_USERBUILT; /* * The in memory encoding is always UTF8 * This field will never change and would * be obsolete if not for binary compatibility. */ cur->charset = XML_CHAR_ENCODING_UTF8;
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue((xmlNodePtr)cur); return(cur);}
/** * xmlFreeDoc: * @cur: pointer to the document * * Free up all the structures used by a document, tree included. */voidxmlFreeDoc(xmlDocPtr cur) { xmlDtdPtr extSubset, intSubset; xmlDictPtr dict = NULL;
if (cur == NULL) { return; }
if (cur != NULL) dict = cur->dict;
if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
/* * Do this before freeing the children list to avoid ID lookups */ if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids); cur->ids = NULL; if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs); cur->refs = NULL; extSubset = cur->extSubset; intSubset = cur->intSubset; if (intSubset == extSubset) extSubset = NULL; if (extSubset != NULL) { xmlUnlinkNode((xmlNodePtr) cur->extSubset); cur->extSubset = NULL; xmlFreeDtd(extSubset); } if (intSubset != NULL) { xmlUnlinkNode((xmlNodePtr) cur->intSubset); cur->intSubset = NULL; xmlFreeDtd(intSubset); }
if (cur->children != NULL) xmlFreeNodeList(cur->children); if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
DICT_FREE(cur->version) DICT_FREE(cur->name) DICT_FREE(cur->encoding) DICT_FREE(cur->URL) xmlFree(cur); if (dict) xmlDictFree(dict);}
/** * xmlStringLenGetNodeList: * @doc: the document * @value: the value of the text * @len: the length of the string value * * Parse the value string and build the node list associated. Should * produce a flat tree with only TEXTs and ENTITY_REFs. * Returns a pointer to the first child */xmlNodePtrxmlStringLenGetNodeList(const xmlDoc *doc, const xmlChar *value, int len) { xmlNodePtr ret = NULL, last = NULL; xmlNodePtr node; xmlChar *val; const xmlChar *cur, *end; const xmlChar *q; xmlEntityPtr ent; xmlBufPtr buf;
if (value == NULL) return(NULL); cur = value; end = cur + len;
buf = xmlBufCreateSize(0); if (buf == NULL) return(NULL); xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
q = cur; while ((cur < end) && (*cur != 0)) { if (cur[0] == '&') { int charval = 0; xmlChar tmp;
/* * Save the current text. */ if (cur != q) { if (xmlBufAdd(buf, q, cur - q)) goto out; } q = cur; if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) { cur += 3; if (cur < end) tmp = *cur; else tmp = 0; while (tmp != ';') { /* Non input consuming loop */ /* * If you find an integer overflow here when fuzzing, * the bug is probably elsewhere. This function should * only receive entities that were already validated by * the parser, typically by xmlParseAttValueComplex * calling xmlStringDecodeEntities. * * So it's better *not* to check for overflow to * potentially discover new bugs. */ if ((tmp >= '0') && (tmp <= '9')) charval = charval * 16 + (tmp - '0'); else if ((tmp >= 'a') && (tmp <= 'f')) charval = charval * 16 + (tmp - 'a') + 10; else if ((tmp >= 'A') && (tmp <= 'F')) charval = charval * 16 + (tmp - 'A') + 10; else { xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc, NULL); charval = 0; break; } cur++; if (cur < end) tmp = *cur; else tmp = 0; } if (tmp == ';') cur++; q = cur; } else if ((cur + 1 < end) && (cur[1] == '#')) { cur += 2; if (cur < end) tmp = *cur; else tmp = 0; while (tmp != ';') { /* Non input consuming loops */ /* Don't check for integer overflow, see above. */ if ((tmp >= '0') && (tmp <= '9')) charval = charval * 10 + (tmp - '0'); else { xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc, NULL); charval = 0; break; } cur++; if (cur < end) tmp = *cur; else tmp = 0; } if (tmp == ';') cur++; q = cur; } else { /* * Read the entity string */ cur++; q = cur; while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++; if ((cur >= end) || (*cur == 0)) { xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc, (const char *) q); goto out; } if (cur != q) { /* * Predefined entities don't generate nodes */ val = xmlStrndup(q, cur - q); ent = xmlGetDocEntity(doc, val); if ((ent != NULL) && (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
if (xmlBufCat(buf, ent->content)) goto out;
} else { /* * Flush buffer so far */ if (!xmlBufIsEmpty(buf)) { node = xmlNewDocText(doc, NULL); if (node == NULL) { if (val != NULL) xmlFree(val); goto out; } node->content = xmlBufDetach(buf);
if (last == NULL) { last = ret = node; } else { last = xmlAddNextSibling(last, node); } }
/* * Create a new REFERENCE_REF node */ node = xmlNewReference(doc, val); if (node == NULL) { if (val != NULL) xmlFree(val); goto out; } else if ((ent != NULL) && ((ent->flags & XML_ENT_PARSED) == 0) && ((ent->flags & XML_ENT_EXPANDING) == 0)) { xmlNodePtr temp;
/* * The entity should have been checked already, * but set the flag anyway to avoid recursion. */ ent->flags |= XML_ENT_EXPANDING; ent->children = xmlStringGetNodeList(doc, (const xmlChar*)node->content); ent->owner = 1; ent->flags &= ~XML_ENT_EXPANDING; ent->flags |= XML_ENT_PARSED; temp = ent->children; while (temp) { temp->parent = (xmlNodePtr)ent; ent->last = temp; temp = temp->next; } } if (last == NULL) { last = ret = node; } else { last = xmlAddNextSibling(last, node); } } xmlFree(val); } cur++; q = cur; } if (charval != 0) { xmlChar buffer[10]; int l;
l = xmlCopyCharMultiByte(buffer, charval); buffer[l] = 0;
if (xmlBufCat(buf, buffer)) goto out; charval = 0; } } else cur++; }
if (cur != q) { /* * Handle the last piece of text. */ if (xmlBufAdd(buf, q, cur - q)) goto out; }
if (!xmlBufIsEmpty(buf)) { node = xmlNewDocText(doc, NULL); if (node == NULL) goto out; node->content = xmlBufDetach(buf);
if (last == NULL) { ret = node; } else { xmlAddNextSibling(last, node); } } else if (ret == NULL) { ret = xmlNewDocText(doc, BAD_CAST ""); }
out: xmlBufFree(buf); return(ret);}
/** * xmlStringGetNodeList: * @doc: the document * @value: the value of the attribute * * Parse the value string and build the node list associated. Should * produce a flat tree with only TEXTs and ENTITY_REFs. * Returns a pointer to the first child */xmlNodePtrxmlStringGetNodeList(const xmlDoc *doc, const xmlChar *value) { xmlNodePtr ret = NULL, head = NULL, last = NULL; xmlNodePtr node; xmlChar *val = NULL; const xmlChar *cur = value; const xmlChar *q; xmlEntityPtr ent; xmlBufPtr buf;
if (value == NULL) return(NULL);
buf = xmlBufCreateSize(0); if (buf == NULL) return(NULL); xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
q = cur; while (*cur != 0) { if (cur[0] == '&') { int charval = 0; xmlChar tmp;
/* * Save the current text. */ if (cur != q) { if (xmlBufAdd(buf, q, cur - q)) goto out; } q = cur; if ((cur[1] == '#') && (cur[2] == 'x')) { cur += 3; tmp = *cur; while (tmp != ';') { /* Non input consuming loop */ /* Don't check for integer overflow, see above. */ if ((tmp >= '0') && (tmp <= '9')) charval = charval * 16 + (tmp - '0'); else if ((tmp >= 'a') && (tmp <= 'f')) charval = charval * 16 + (tmp - 'a') + 10; else if ((tmp >= 'A') && (tmp <= 'F')) charval = charval * 16 + (tmp - 'A') + 10; else { xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc, NULL); charval = 0; break; } cur++; tmp = *cur; } if (tmp == ';') cur++; q = cur; } else if (cur[1] == '#') { cur += 2; tmp = *cur; while (tmp != ';') { /* Non input consuming loops */ /* Don't check for integer overflow, see above. */ if ((tmp >= '0') && (tmp <= '9')) charval = charval * 10 + (tmp - '0'); else { xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc, NULL); charval = 0; break; } cur++; tmp = *cur; } if (tmp == ';') cur++; q = cur; } else { /* * Read the entity string */ cur++; q = cur; while ((*cur != 0) && (*cur != ';')) cur++; if (*cur == 0) { xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc, (const char *) q); goto out; } if (cur != q) { /* * Predefined entities don't generate nodes */ val = xmlStrndup(q, cur - q); ent = xmlGetDocEntity(doc, val); if ((ent != NULL) && (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
if (xmlBufCat(buf, ent->content)) goto out;
} else { /* * Flush buffer so far */ if (!xmlBufIsEmpty(buf)) { node = xmlNewDocText(doc, NULL); if (node == NULL) goto out; node->content = xmlBufDetach(buf);
if (last == NULL) { last = head = node; } else { last = xmlAddNextSibling(last, node); } }
/* * Create a new REFERENCE_REF node */ node = xmlNewReference(doc, val); if (node == NULL) goto out; if ((ent != NULL) && ((ent->flags & XML_ENT_PARSED) == 0) && ((ent->flags & XML_ENT_EXPANDING) == 0)) { xmlNodePtr temp;
/* * The entity should have been checked already, * but set the flag anyway to avoid recursion. */ ent->flags |= XML_ENT_EXPANDING; ent->children = xmlStringGetNodeList(doc, (const xmlChar*)node->content); ent->owner = 1; ent->flags &= ~XML_ENT_EXPANDING; ent->flags |= XML_ENT_PARSED; temp = ent->children; while (temp) { temp->parent = (xmlNodePtr)ent; ent->last = temp; temp = temp->next; } } if (last == NULL) { last = head = node; } else { last = xmlAddNextSibling(last, node); } } xmlFree(val); val = NULL; } cur++; q = cur; } if (charval != 0) { xmlChar buffer[10]; int len;
len = xmlCopyCharMultiByte(buffer, charval); buffer[len] = 0;
if (xmlBufCat(buf, buffer)) goto out; charval = 0; } } else cur++; } if ((cur != q) || (head == NULL)) { /* * Handle the last piece of text. */ xmlBufAdd(buf, q, cur - q); }
if (!xmlBufIsEmpty(buf)) { node = xmlNewDocText(doc, NULL); if (node == NULL) goto out; node->content = xmlBufDetach(buf);
if (last == NULL) { head = node; } else { xmlAddNextSibling(last, node); } }
ret = head; head = NULL;
out: xmlBufFree(buf); if (val != NULL) xmlFree(val); if (head != NULL) xmlFreeNodeList(head); return(ret);}
/** * xmlNodeListGetString: * @doc: the document * @list: a Node list * @inLine: should we replace entity contents or show their external form * * Build the string equivalent to the text contained in the Node list * made of TEXTs and ENTITY_REFs * * Returns a pointer to the string copy, the caller must free it with xmlFree(). */xmlChar *xmlNodeListGetString(xmlDocPtr doc, const xmlNode *list, int inLine){ const xmlNode *node = list; xmlChar *ret = NULL; xmlEntityPtr ent; int attr;
if (list == NULL) return (NULL); if ((list->parent != NULL) && (list->parent->type == XML_ATTRIBUTE_NODE)) attr = 1; else attr = 0;
while (node != NULL) { if ((node->type == XML_TEXT_NODE) || (node->type == XML_CDATA_SECTION_NODE)) { if (inLine) { ret = xmlStrcat(ret, node->content); } else { xmlChar *buffer;
if (attr) buffer = xmlEncodeAttributeEntities(doc, node->content); else buffer = xmlEncodeEntitiesReentrant(doc, node->content); if (buffer != NULL) { ret = xmlStrcat(ret, buffer); xmlFree(buffer); } } } else if (node->type == XML_ENTITY_REF_NODE) { if (inLine) { ent = xmlGetDocEntity(doc, node->name); if (ent != NULL) { xmlChar *buffer;
/* an entity content can be any "well balanced chunk", * i.e. the result of the content [43] production: * http://www.w3.org/TR/REC-xml#NT-content. * So it can contain text, CDATA section or nested * entity reference nodes (among others). * -> we recursive call xmlNodeListGetString() * which handles these types */ buffer = xmlNodeListGetString(doc, ent->children, 1); if (buffer != NULL) { ret = xmlStrcat(ret, buffer); xmlFree(buffer); } } else { ret = xmlStrcat(ret, node->content); } } else { xmlChar buf[2];
buf[0] = '&'; buf[1] = 0; ret = xmlStrncat(ret, buf, 1); ret = xmlStrcat(ret, node->name); buf[0] = ';'; buf[1] = 0; ret = xmlStrncat(ret, buf, 1); } }#if 0 else { xmlGenericError(xmlGenericErrorContext, "xmlGetNodeListString : invalid node type %d\n", node->type); }#endif node = node->next; } return (ret);}
#ifdef LIBXML_TREE_ENABLED/** * xmlNodeListGetRawString: * @doc: the document * @list: a Node list * @inLine: should we replace entity contents or show their external form * * Builds the string equivalent to the text contained in the Node list * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString() * this function doesn't do any character encoding handling. * * Returns a pointer to the string copy, the caller must free it with xmlFree(). */xmlChar *xmlNodeListGetRawString(const xmlDoc *doc, const xmlNode *list, int inLine){ const xmlNode *node = list; xmlChar *ret = NULL; xmlEntityPtr ent;
if (list == NULL) return (NULL);
while (node != NULL) { if ((node->type == XML_TEXT_NODE) || (node->type == XML_CDATA_SECTION_NODE)) { if (inLine) { ret = xmlStrcat(ret, node->content); } else { xmlChar *buffer;
buffer = xmlEncodeSpecialChars(doc, node->content); if (buffer != NULL) { ret = xmlStrcat(ret, buffer); xmlFree(buffer); } } } else if (node->type == XML_ENTITY_REF_NODE) { if (inLine) { ent = xmlGetDocEntity(doc, node->name); if (ent != NULL) { xmlChar *buffer;
/* an entity content can be any "well balanced chunk", * i.e. the result of the content [43] production: * http://www.w3.org/TR/REC-xml#NT-content. * So it can contain text, CDATA section or nested * entity reference nodes (among others). * -> we recursive call xmlNodeListGetRawString() * which handles these types */ buffer = xmlNodeListGetRawString(doc, ent->children, 1); if (buffer != NULL) { ret = xmlStrcat(ret, buffer); xmlFree(buffer); } } else { ret = xmlStrcat(ret, node->content); } } else { xmlChar buf[2];
buf[0] = '&'; buf[1] = 0; ret = xmlStrncat(ret, buf, 1); ret = xmlStrcat(ret, node->name); buf[0] = ';'; buf[1] = 0; ret = xmlStrncat(ret, buf, 1); } }#if 0 else { xmlGenericError(xmlGenericErrorContext, "xmlGetNodeListString : invalid node type %d\n", node->type); }#endif node = node->next; } return (ret);}#endif /* LIBXML_TREE_ENABLED */
static xmlAttrPtrxmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns, const xmlChar * name, const xmlChar * value, int eatname){ xmlAttrPtr cur; xmlDocPtr doc = NULL;
if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) { if ((eatname == 1) && ((node->doc == NULL) || (node->doc->dict == NULL) || (!(xmlDictOwns(node->doc->dict, name))))) xmlFree((xmlChar *) name); return (NULL); }
/* * Allocate a new property and fill the fields. */ cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr)); if (cur == NULL) { if ((eatname == 1) && ((node == NULL) || (node->doc == NULL) || (node->doc->dict == NULL) || (!(xmlDictOwns(node->doc->dict, name))))) xmlFree((xmlChar *) name); xmlTreeErrMemory("building attribute"); return (NULL); } memset(cur, 0, sizeof(xmlAttr)); cur->type = XML_ATTRIBUTE_NODE;
cur->parent = node; if (node != NULL) { doc = node->doc; cur->doc = doc; } cur->ns = ns;
if (eatname == 0) { if ((doc != NULL) && (doc->dict != NULL)) cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1); else cur->name = xmlStrdup(name); } else cur->name = name;
if (value != NULL) { xmlNodePtr tmp;
cur->children = xmlNewDocText(doc, value); cur->last = NULL; tmp = cur->children; while (tmp != NULL) { tmp->parent = (xmlNodePtr) cur; if (tmp->next == NULL) cur->last = tmp; tmp = tmp->next; } }
/* * Add it at the end to preserve parsing order ... */ if (node != NULL) { if (node->properties == NULL) { node->properties = cur; } else { xmlAttrPtr prev = node->properties;
while (prev->next != NULL) prev = prev->next; prev->next = cur; cur->prev = prev; } }
if ((value != NULL) && (node != NULL) && (xmlIsID(node->doc, node, cur) == 1)) xmlAddID(NULL, node->doc, value, cur);
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue((xmlNodePtr) cur); return (cur);}
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \ defined(LIBXML_SCHEMAS_ENABLED)/** * xmlNewProp: * @node: the holding node * @name: the name of the attribute * @value: the value of the attribute * * Create a new property carried by a node. * Returns a pointer to the attribute */xmlAttrPtrxmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
if (name == NULL) { return(NULL); }
return xmlNewPropInternal(node, NULL, name, value, 0);}#endif /* LIBXML_TREE_ENABLED */
/** * xmlNewNsProp: * @node: the holding node * @ns: the namespace * @name: the name of the attribute * @value: the value of the attribute * * Create a new property tagged with a namespace and carried by a node. * Returns a pointer to the attribute */xmlAttrPtrxmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name, const xmlChar *value) {
if (name == NULL) { return(NULL); }
return xmlNewPropInternal(node, ns, name, value, 0);}
/** * xmlNewNsPropEatName: * @node: the holding node * @ns: the namespace * @name: the name of the attribute * @value: the value of the attribute * * Create a new property tagged with a namespace and carried by a node. * Returns a pointer to the attribute */xmlAttrPtrxmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name, const xmlChar *value) {
if (name == NULL) { return(NULL); }
return xmlNewPropInternal(node, ns, name, value, 1);}
/** * xmlNewDocProp: * @doc: the document * @name: the name of the attribute * @value: the value of the attribute * * Create a new property carried by a document. * NOTE: @value is supposed to be a piece of XML CDATA, so it allows entity * references, but XML special chars need to be escaped first by using * xmlEncodeEntitiesReentrant(). Use xmlNewProp() if you don't need * entities support. * * Returns a pointer to the attribute */xmlAttrPtrxmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) { xmlAttrPtr cur;
if (name == NULL) { return(NULL); }
/* * Allocate a new property and fill the fields. */ cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr)); if (cur == NULL) { xmlTreeErrMemory("building attribute"); return(NULL); } memset(cur, 0, sizeof(xmlAttr)); cur->type = XML_ATTRIBUTE_NODE;
if ((doc != NULL) && (doc->dict != NULL)) cur->name = xmlDictLookup(doc->dict, name, -1); else cur->name = xmlStrdup(name); cur->doc = doc; if (value != NULL) { xmlNodePtr tmp;
cur->children = xmlStringGetNodeList(doc, value); cur->last = NULL;
tmp = cur->children; while (tmp != NULL) { tmp->parent = (xmlNodePtr) cur; if (tmp->next == NULL) cur->last = tmp; tmp = tmp->next; } }
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue((xmlNodePtr)cur); return(cur);}
/** * xmlFreePropList: * @cur: the first property in the list * * Free a property and all its siblings, all the children are freed too. */voidxmlFreePropList(xmlAttrPtr cur) { xmlAttrPtr next; if (cur == NULL) return; while (cur != NULL) { next = cur->next; xmlFreeProp(cur); cur = next; }}
/** * xmlFreeProp: * @cur: an attribute * * Free one attribute, all the content is freed too */voidxmlFreeProp(xmlAttrPtr cur) { xmlDictPtr dict = NULL; if (cur == NULL) return;
if (cur->doc != NULL) dict = cur->doc->dict;
if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
/* Check for ID removal -> leading to invalid references ! */ if ((cur->doc != NULL) && (cur->atype == XML_ATTRIBUTE_ID)) { xmlRemoveID(cur->doc, cur); } if (cur->children != NULL) xmlFreeNodeList(cur->children); DICT_FREE(cur->name) xmlFree(cur);}
/** * xmlRemoveProp: * @cur: an attribute * * Unlink and free one attribute, all the content is freed too * Note this doesn't work for namespace definition attributes * * Returns 0 if success and -1 in case of error. */intxmlRemoveProp(xmlAttrPtr cur) { xmlAttrPtr tmp; if (cur == NULL) { return(-1); } if (cur->parent == NULL) { return(-1); } tmp = cur->parent->properties; if (tmp == cur) { cur->parent->properties = cur->next; if (cur->next != NULL) cur->next->prev = NULL; xmlFreeProp(cur); return(0); } while (tmp != NULL) { if (tmp->next == cur) { tmp->next = cur->next; if (tmp->next != NULL) tmp->next->prev = tmp; xmlFreeProp(cur); return(0); } tmp = tmp->next; } return(-1);}
/** * xmlNewDocPI: * @doc: the target document * @name: the processing instruction name * @content: the PI content * * Creation of a processing instruction element. * Returns a pointer to the new node object. */xmlNodePtrxmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) { xmlNodePtr cur;
if (name == NULL) { return(NULL); }
/* * Allocate a new node and fill the fields. */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); if (cur == NULL) { xmlTreeErrMemory("building PI"); return(NULL); } memset(cur, 0, sizeof(xmlNode)); cur->type = XML_PI_NODE;
if ((doc != NULL) && (doc->dict != NULL)) cur->name = xmlDictLookup(doc->dict, name, -1); else cur->name = xmlStrdup(name); if (content != NULL) { cur->content = xmlStrdup(content); } cur->doc = doc;
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue((xmlNodePtr)cur); return(cur);}
/** * xmlNewPI: * @name: the processing instruction name * @content: the PI content * * Creation of a processing instruction element. * * Use of this function is DISCOURAGED in favor of xmlNewDocPI. * * Returns a pointer to the new node object. */xmlNodePtrxmlNewPI(const xmlChar *name, const xmlChar *content) { return(xmlNewDocPI(NULL, name, content));}
/** * xmlNewNode: * @ns: namespace if any * @name: the node name * * Creation of a new node element. @ns is optional (NULL). * * Use of this function is DISCOURAGED in favor of xmlNewDocNode. * * Returns a pointer to the new node object. Uses xmlStrdup() to make * copy of @name. */xmlNodePtrxmlNewNode(xmlNsPtr ns, const xmlChar *name) { xmlNodePtr cur;
if (name == NULL) { return(NULL); }
/* * Allocate a new node and fill the fields. */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); if (cur == NULL) { xmlTreeErrMemory("building node"); return(NULL); } memset(cur, 0, sizeof(xmlNode)); cur->type = XML_ELEMENT_NODE;
cur->name = xmlStrdup(name); cur->ns = ns;
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue(cur); return(cur);}
/** * xmlNewNodeEatName: * @ns: namespace if any * @name: the node name * * Creation of a new node element. @ns is optional (NULL). * * Use of this function is DISCOURAGED in favor of xmlNewDocNodeEatName. * * Returns a pointer to the new node object, with pointer @name as * new node's name. Use xmlNewNode() if a copy of @name string is * is needed as new node's name. */xmlNodePtrxmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) { xmlNodePtr cur;
if (name == NULL) { return(NULL); }
/* * Allocate a new node and fill the fields. */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); if (cur == NULL) { xmlTreeErrMemory("building node"); /* we can't check here that name comes from the doc dictionary */ return(NULL); } memset(cur, 0, sizeof(xmlNode)); cur->type = XML_ELEMENT_NODE;
cur->name = name; cur->ns = ns;
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue((xmlNodePtr)cur); return(cur);}
/** * xmlNewDocNode: * @doc: the document * @ns: namespace if any * @name: the node name * @content: the XML text content if any * * Creation of a new node element within a document. @ns and @content * are optional (NULL). * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities * references, but XML special chars need to be escaped first by using * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't * need entities support. * * Returns a pointer to the new node object. */xmlNodePtrxmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns, const xmlChar *name, const xmlChar *content) { xmlNodePtr cur;
if ((doc != NULL) && (doc->dict != NULL)) cur = xmlNewNodeEatName(ns, (xmlChar *) xmlDictLookup(doc->dict, name, -1)); else cur = xmlNewNode(ns, name); if (cur != NULL) { cur->doc = doc; if (content != NULL) { cur->children = xmlStringGetNodeList(doc, content); UPDATE_LAST_CHILD_AND_PARENT(cur) } }
return(cur);}
/** * xmlNewDocNodeEatName: * @doc: the document * @ns: namespace if any * @name: the node name * @content: the XML text content if any * * Creation of a new node element within a document. @ns and @content * are optional (NULL). * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities * references, but XML special chars need to be escaped first by using * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't * need entities support. * * Returns a pointer to the new node object. */xmlNodePtrxmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns, xmlChar *name, const xmlChar *content) { xmlNodePtr cur;
cur = xmlNewNodeEatName(ns, name); if (cur != NULL) { cur->doc = doc; if (content != NULL) { cur->children = xmlStringGetNodeList(doc, content); UPDATE_LAST_CHILD_AND_PARENT(cur) } } else { /* if name don't come from the doc dictionary free it here */ if ((name != NULL) && ((doc == NULL) || (doc->dict == NULL) || (!(xmlDictOwns(doc->dict, name))))) xmlFree(name); } return(cur);}
#ifdef LIBXML_TREE_ENABLED/** * xmlNewDocRawNode: * @doc: the document * @ns: namespace if any * @name: the node name * @content: the text content if any * * Creation of a new node element within a document. @ns and @content * are optional (NULL). * * Returns a pointer to the new node object. */xmlNodePtrxmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns, const xmlChar *name, const xmlChar *content) { xmlNodePtr cur;
cur = xmlNewDocNode(doc, ns, name, NULL); if (cur != NULL) { cur->doc = doc; if (content != NULL) { cur->children = xmlNewDocText(doc, content); UPDATE_LAST_CHILD_AND_PARENT(cur) } } return(cur);}
/** * xmlNewDocFragment: * @doc: the document owning the fragment * * Creation of a new Fragment node. * Returns a pointer to the new node object. */xmlNodePtrxmlNewDocFragment(xmlDocPtr doc) { xmlNodePtr cur;
/* * Allocate a new DocumentFragment node and fill the fields. */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); if (cur == NULL) { xmlTreeErrMemory("building fragment"); return(NULL); } memset(cur, 0, sizeof(xmlNode)); cur->type = XML_DOCUMENT_FRAG_NODE;
cur->doc = doc;
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue(cur); return(cur);}#endif /* LIBXML_TREE_ENABLED */
/** * xmlNewText: * @content: the text content * * Creation of a new text node. * * Use of this function is DISCOURAGED in favor of xmlNewDocText. * * Returns a pointer to the new node object. */xmlNodePtrxmlNewText(const xmlChar *content) { xmlNodePtr cur;
/* * Allocate a new node and fill the fields. */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); if (cur == NULL) { xmlTreeErrMemory("building text"); return(NULL); } memset(cur, 0, sizeof(xmlNode)); cur->type = XML_TEXT_NODE;
cur->name = xmlStringText; if (content != NULL) { cur->content = xmlStrdup(content); }
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue(cur); return(cur);}
#ifdef LIBXML_TREE_ENABLED/** * xmlNewTextChild: * @parent: the parent node * @ns: a namespace if any * @name: the name of the child * @content: the text content of the child if any. * * Creation of a new child element, added at the end of @parent children list. * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly * created element inherits the namespace of @parent. If @content is non NULL, * a child TEXT node will be created containing the string @content. * NOTE: Use xmlNewChild() if @content will contain entities that need to be * preserved. Use this function, xmlNewTextChild(), if you need to ensure that * reserved XML chars that might appear in @content, such as the ampersand, * greater-than or less-than signs, are automatically replaced by their XML * escaped entity representations. * * Returns a pointer to the new node object. */xmlNodePtrxmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns, const xmlChar *name, const xmlChar *content) { xmlNodePtr cur, prev;
if (parent == NULL) { return(NULL); }
if (name == NULL) { return(NULL); }
/* * Allocate a new node */ if (parent->type == XML_ELEMENT_NODE) { if (ns == NULL) cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content); else cur = xmlNewDocRawNode(parent->doc, ns, name, content); } else if ((parent->type == XML_DOCUMENT_NODE) || (parent->type == XML_HTML_DOCUMENT_NODE)) { if (ns == NULL) cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content); else cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content); } else if (parent->type == XML_DOCUMENT_FRAG_NODE) { cur = xmlNewDocRawNode( parent->doc, ns, name, content); } else { return(NULL); } if (cur == NULL) return(NULL);
/* * add the new element at the end of the children list. */ cur->type = XML_ELEMENT_NODE; cur->parent = parent; cur->doc = parent->doc; if (parent->children == NULL) { parent->children = cur; parent->last = cur; } else { prev = parent->last; prev->next = cur; cur->prev = prev; parent->last = cur; }
return(cur);}#endif /* LIBXML_TREE_ENABLED */
/** * xmlNewCharRef: * @doc: the document * @name: the char ref string, starting with # or "&# ... ;" * * Creation of a new character reference node. * Returns a pointer to the new node object. */xmlNodePtrxmlNewCharRef(xmlDocPtr doc, const xmlChar *name) { xmlNodePtr cur;
if (name == NULL) return(NULL);
/* * Allocate a new node and fill the fields. */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); if (cur == NULL) { xmlTreeErrMemory("building character reference"); return(NULL); } memset(cur, 0, sizeof(xmlNode)); cur->type = XML_ENTITY_REF_NODE;
cur->doc = doc; if (name[0] == '&') { int len; name++; len = xmlStrlen(name); if (name[len - 1] == ';') cur->name = xmlStrndup(name, len - 1); else cur->name = xmlStrndup(name, len); } else cur->name = xmlStrdup(name);
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue(cur); return(cur);}
/** * xmlNewReference: * @doc: the document * @name: the reference name, or the reference string with & and ; * * Creation of a new reference node. * Returns a pointer to the new node object. */xmlNodePtrxmlNewReference(const xmlDoc *doc, const xmlChar *name) { xmlNodePtr cur; xmlEntityPtr ent;
if (name == NULL) return(NULL);
/* * Allocate a new node and fill the fields. */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); if (cur == NULL) { xmlTreeErrMemory("building reference"); return(NULL); } memset(cur, 0, sizeof(xmlNode)); cur->type = XML_ENTITY_REF_NODE;
cur->doc = (xmlDoc *)doc; if (name[0] == '&') { int len; name++; len = xmlStrlen(name); if (name[len - 1] == ';') cur->name = xmlStrndup(name, len - 1); else cur->name = xmlStrndup(name, len); } else cur->name = xmlStrdup(name);
ent = xmlGetDocEntity(doc, cur->name); if (ent != NULL) { cur->content = ent->content; /* * The parent pointer in entity is a DTD pointer and thus is NOT * updated. Not sure if this is 100% correct. * -George */ cur->children = (xmlNodePtr) ent; cur->last = (xmlNodePtr) ent; }
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue(cur); return(cur);}
/** * xmlNewDocText: * @doc: the document * @content: the text content * * Creation of a new text node within a document. * Returns a pointer to the new node object. */xmlNodePtrxmlNewDocText(const xmlDoc *doc, const xmlChar *content) { xmlNodePtr cur;
cur = xmlNewText(content); if (cur != NULL) cur->doc = (xmlDoc *)doc; return(cur);}
/** * xmlNewTextLen: * @content: the text content * @len: the text len. * * Use of this function is DISCOURAGED in favor of xmlNewDocTextLen. * * Creation of a new text node with an extra parameter for the content's length * Returns a pointer to the new node object. */xmlNodePtrxmlNewTextLen(const xmlChar *content, int len) { xmlNodePtr cur;
/* * Allocate a new node and fill the fields. */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); if (cur == NULL) { xmlTreeErrMemory("building text"); return(NULL); } memset(cur, 0, sizeof(xmlNode)); cur->type = XML_TEXT_NODE;
cur->name = xmlStringText; if (content != NULL) { cur->content = xmlStrndup(content, len); }
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue(cur); return(cur);}
/** * xmlNewDocTextLen: * @doc: the document * @content: the text content * @len: the text len. * * Creation of a new text node with an extra content length parameter. The * text node pertain to a given document. * Returns a pointer to the new node object. */xmlNodePtrxmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) { xmlNodePtr cur;
cur = xmlNewTextLen(content, len); if (cur != NULL) cur->doc = doc; return(cur);}
/** * xmlNewComment: * @content: the comment content * * Use of this function is DISCOURAGED in favor of xmlNewDocComment. * * Creation of a new node containing a comment. * Returns a pointer to the new node object. */xmlNodePtrxmlNewComment(const xmlChar *content) { xmlNodePtr cur;
/* * Allocate a new node and fill the fields. */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); if (cur == NULL) { xmlTreeErrMemory("building comment"); return(NULL); } memset(cur, 0, sizeof(xmlNode)); cur->type = XML_COMMENT_NODE;
cur->name = xmlStringComment; if (content != NULL) { cur->content = xmlStrdup(content); }
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue(cur); return(cur);}
/** * xmlNewCDataBlock: * @doc: the document * @content: the CDATA block content content * @len: the length of the block * * Creation of a new node containing a CDATA block. * Returns a pointer to the new node object. */xmlNodePtrxmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) { xmlNodePtr cur;
/* * Allocate a new node and fill the fields. */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); if (cur == NULL) { xmlTreeErrMemory("building CDATA"); return(NULL); } memset(cur, 0, sizeof(xmlNode)); cur->type = XML_CDATA_SECTION_NODE; cur->doc = doc;
if (content != NULL) { cur->content = xmlStrndup(content, len); }
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue(cur); return(cur);}
/** * xmlNewDocComment: * @doc: the document * @content: the comment content * * Creation of a new node containing a comment within a document. * Returns a pointer to the new node object. */xmlNodePtrxmlNewDocComment(xmlDocPtr doc, const xmlChar *content) { xmlNodePtr cur;
cur = xmlNewComment(content); if (cur != NULL) cur->doc = doc; return(cur);}
static const xmlChar *_copyStringForNewDictIfNeeded(xmlDictPtr oldDict, xmlDictPtr newDict, const xmlChar *oldValue) { const xmlChar *newValue = oldValue; if (oldValue) { int oldDictOwnsOldValue = oldDict && (xmlDictOwns(oldDict, oldValue) == 1); if (oldDictOwnsOldValue) { if (newDict) newValue = xmlDictLookup(newDict, oldValue, -1); else newValue = xmlStrdup(oldValue); } } return newValue;}
/** * xmlSetTreeDoc: * @tree: the top element * @doc: the document * * update all nodes under the tree to point to the right document */voidxmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) { xmlAttrPtr prop;
if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL)) return; if (tree->doc != doc) { xmlDictPtr oldTreeDict = tree->doc ? tree->doc->dict : NULL; xmlDictPtr newDict = doc ? doc->dict : NULL;
if(tree->type == XML_ELEMENT_NODE) { prop = tree->properties; while (prop != NULL) { if (prop->atype == XML_ATTRIBUTE_ID) { xmlRemoveID(tree->doc, prop); }
if (prop->doc != doc) { xmlDictPtr oldPropDict = prop->doc ? prop->doc->dict : NULL; prop->name = _copyStringForNewDictIfNeeded(oldPropDict, newDict, prop->name); prop->doc = doc; } xmlSetListDoc(prop->children, doc);
/* * TODO: ID attributes should be also added to the new * document, but this breaks things like xmlReplaceNode. * The underlying problem is that xmlRemoveID is only called * if a node is destroyed, not if it's unlinked. */#if 0 if (xmlIsID(doc, tree, prop)) { xmlChar *idVal = xmlNodeListGetString(doc, prop->children, 1); xmlAddID(NULL, doc, idVal, prop); }#endif
prop = prop->next; } } if (tree->type == XML_ENTITY_REF_NODE) { /* * Clear 'children' which points to the entity declaration * from the original document. */ tree->children = NULL; } else if (tree->children != NULL) { xmlSetListDoc(tree->children, doc); }
tree->name = _copyStringForNewDictIfNeeded(oldTreeDict, newDict, tree->name); tree->content = (xmlChar *)_copyStringForNewDictIfNeeded(oldTreeDict, NULL, tree->content); /* FIXME: tree->ns should be updated as in xmlStaticCopyNode(). */ tree->doc = doc; }}
/** * xmlSetListDoc: * @list: the first element * @doc: the document * * update all nodes in the list to point to the right document */voidxmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) { xmlNodePtr cur;
if ((list == NULL) || (list->type == XML_NAMESPACE_DECL)) return; cur = list; while (cur != NULL) { if (cur->doc != doc) xmlSetTreeDoc(cur, doc); cur = cur->next; }}
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)/** * xmlNewChild: * @parent: the parent node * @ns: a namespace if any * @name: the name of the child * @content: the XML content of the child if any. * * Creation of a new child element, added at the end of @parent children list. * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly * created element inherits the namespace of @parent. If @content is non NULL, * a child list containing the TEXTs and ENTITY_REFs node will be created. * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity * references. XML special chars must be escaped first by using * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used. * * Returns a pointer to the new node object. */xmlNodePtrxmlNewChild(xmlNodePtr parent, xmlNsPtr ns, const xmlChar *name, const xmlChar *content) { xmlNodePtr cur, prev;
if (parent == NULL) { return(NULL); }
if (name == NULL) { return(NULL); }
/* * Allocate a new node */ if (parent->type == XML_ELEMENT_NODE) { if (ns == NULL) cur = xmlNewDocNode(parent->doc, parent->ns, name, content); else cur = xmlNewDocNode(parent->doc, ns, name, content); } else if ((parent->type == XML_DOCUMENT_NODE) || (parent->type == XML_HTML_DOCUMENT_NODE)) { if (ns == NULL) cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content); else cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content); } else if (parent->type == XML_DOCUMENT_FRAG_NODE) { cur = xmlNewDocNode( parent->doc, ns, name, content); } else { return(NULL); } if (cur == NULL) return(NULL);
/* * add the new element at the end of the children list. */ cur->type = XML_ELEMENT_NODE; cur->parent = parent; cur->doc = parent->doc; if (parent->children == NULL) { parent->children = cur; parent->last = cur; } else { prev = parent->last; prev->next = cur; cur->prev = prev; parent->last = cur; }
return(cur);}#endif /* LIBXML_TREE_ENABLED */
/** * xmlAddPropSibling: * @prev: the attribute to which @prop is added after * @cur: the base attribute passed to calling function * @prop: the new attribute * * Add a new attribute after @prev using @cur as base attribute. * When inserting before @cur, @prev is passed as @cur->prev. * When inserting after @cur, @prev is passed as @cur. * If an existing attribute is found it is destroyed prior to adding @prop. * * See the note regarding namespaces in xmlAddChild. * * Returns the attribute being inserted or NULL in case of error. */static xmlNodePtrxmlAddPropSibling(xmlNodePtr prev, xmlNodePtr cur, xmlNodePtr prop) { xmlAttrPtr attr;
if ((cur == NULL) || (cur->type != XML_ATTRIBUTE_NODE) || (prop == NULL) || (prop->type != XML_ATTRIBUTE_NODE) || ((prev != NULL) && (prev->type != XML_ATTRIBUTE_NODE))) return(NULL);
/* check if an attribute with the same name exists */ if (prop->ns == NULL) attr = xmlHasNsProp(cur->parent, prop->name, NULL); else attr = xmlHasNsProp(cur->parent, prop->name, prop->ns->href);
if (prop->doc != cur->doc) { xmlSetTreeDoc(prop, cur->doc); } prop->parent = cur->parent; prop->prev = prev; if (prev != NULL) { prop->next = prev->next; prev->next = prop; if (prop->next) prop->next->prev = prop; } else { prop->next = cur; cur->prev = prop; } if (prop->prev == NULL && prop->parent != NULL) prop->parent->properties = (xmlAttrPtr) prop; if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) { /* different instance, destroy it (attributes must be unique) */ xmlRemoveProp((xmlAttrPtr) attr); } return prop;}
/** * xmlAddNextSibling: * @cur: the child node * @elem: the new node * * Add a new node @elem as the next sibling of @cur * If the new node was already inserted in a document it is * first unlinked from its existing context. * As a result of text merging @elem may be freed. * If the new node is ATTRIBUTE, it is added into properties instead of children. * If there is an attribute with equal name, it is first destroyed. * * See the note regarding namespaces in xmlAddChild. * * Returns the new node or NULL in case of error. */xmlNodePtrxmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) { if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) { return(NULL); } if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) { return(NULL); }
if (cur == elem) { return(NULL); }
xmlUnlinkNode(elem);
if (elem->type == XML_TEXT_NODE) { if (cur->type == XML_TEXT_NODE) { xmlNodeAddContent(cur, elem->content); xmlFreeNode(elem); return(cur); } if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) && (cur->name == cur->next->name)) { xmlChar *tmp;
tmp = xmlStrdup(elem->content); tmp = xmlStrcat(tmp, cur->next->content); xmlNodeSetContent(cur->next, tmp); xmlFree(tmp); xmlFreeNode(elem); return(cur->next); } } else if (elem->type == XML_ATTRIBUTE_NODE) { return xmlAddPropSibling(cur, cur, elem); }
if (elem->doc != cur->doc) { xmlSetTreeDoc(elem, cur->doc); } elem->parent = cur->parent; elem->prev = cur; elem->next = cur->next; cur->next = elem; if (elem->next != NULL) elem->next->prev = elem; if ((elem->parent != NULL) && (elem->parent->last == cur)) elem->parent->last = elem; return(elem);}
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \ defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)/** * xmlAddPrevSibling: * @cur: the child node * @elem: the new node * * Add a new node @elem as the previous sibling of @cur * merging adjacent TEXT nodes (@elem may be freed) * If the new node was already inserted in a document it is * first unlinked from its existing context. * If the new node is ATTRIBUTE, it is added into properties instead of children. * If there is an attribute with equal name, it is first destroyed. * * See the note regarding namespaces in xmlAddChild. * * Returns the new node or NULL in case of error. */xmlNodePtrxmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) { if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) { return(NULL); } if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) { return(NULL); }
if (cur == elem) { return(NULL); }
xmlUnlinkNode(elem);
if (elem->type == XML_TEXT_NODE) { if (cur->type == XML_TEXT_NODE) { xmlChar *tmp;
tmp = xmlStrdup(elem->content); tmp = xmlStrcat(tmp, cur->content); xmlNodeSetContent(cur, tmp); xmlFree(tmp); xmlFreeNode(elem); return(cur); } if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) && (cur->name == cur->prev->name)) { xmlNodeAddContent(cur->prev, elem->content); xmlFreeNode(elem); return(cur->prev); } } else if (elem->type == XML_ATTRIBUTE_NODE) { return xmlAddPropSibling(cur->prev, cur, elem); }
if (elem->doc != cur->doc) { xmlSetTreeDoc(elem, cur->doc); } elem->parent = cur->parent; elem->next = cur; elem->prev = cur->prev; cur->prev = elem; if (elem->prev != NULL) elem->prev->next = elem; if ((elem->parent != NULL) && (elem->parent->children == cur)) { elem->parent->children = elem; } return(elem);}#endif /* LIBXML_TREE_ENABLED */
/** * xmlAddSibling: * @cur: the child node * @elem: the new node * * Add a new element @elem to the list of siblings of @cur * merging adjacent TEXT nodes (@elem may be freed) * If the new element was already inserted in a document it is * first unlinked from its existing context. * * See the note regarding namespaces in xmlAddChild. * * Returns the new element or NULL in case of error. */xmlNodePtrxmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) { xmlNodePtr parent;
if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) { return(NULL); }
if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) { return(NULL); }
if (cur == elem) { return(NULL); }
/* * Constant time is we can rely on the ->parent->last to find * the last sibling. */ if ((cur->type != XML_ATTRIBUTE_NODE) && (cur->parent != NULL) && (cur->parent->children != NULL) && (cur->parent->last != NULL) && (cur->parent->last->next == NULL)) { cur = cur->parent->last; } else { while (cur->next != NULL) cur = cur->next; }
xmlUnlinkNode(elem);
if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) && (cur->name == elem->name)) { xmlNodeAddContent(cur, elem->content); xmlFreeNode(elem); return(cur); } else if (elem->type == XML_ATTRIBUTE_NODE) { return xmlAddPropSibling(cur, cur, elem); }
if (elem->doc != cur->doc) { xmlSetTreeDoc(elem, cur->doc); } parent = cur->parent; elem->prev = cur; elem->next = NULL; elem->parent = parent; cur->next = elem; if (parent != NULL) parent->last = elem;
return(elem);}
/** * xmlAddChildList: * @parent: the parent node * @cur: the first node in the list * * Add a list of node at the end of the child list of the parent * merging adjacent TEXT nodes (@cur may be freed) * * See the note regarding namespaces in xmlAddChild. * * Returns the last child or NULL in case of error. */xmlNodePtrxmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) { xmlNodePtr prev;
if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) { return(NULL); }
if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) { return(NULL); }
if ((cur->doc != NULL) && (parent->doc != NULL) && (cur->doc != parent->doc)) { }
/* * add the first element at the end of the children list. */
if (parent->children == NULL) { parent->children = cur; } else { /* * If cur and parent->last both are TEXT nodes, then merge them. */ if ((cur->type == XML_TEXT_NODE) && (parent->last->type == XML_TEXT_NODE) && (cur->name == parent->last->name)) { xmlNodeAddContent(parent->last, cur->content); /* * if it's the only child, nothing more to be done. */ if (cur->next == NULL) { xmlFreeNode(cur); return(parent->last); } prev = cur; cur = cur->next; xmlFreeNode(prev); } prev = parent->last; prev->next = cur; cur->prev = prev; } while (cur->next != NULL) { cur->parent = parent; if (cur->doc != parent->doc) { xmlSetTreeDoc(cur, parent->doc); } cur = cur->next; } cur->parent = parent; /* the parent may not be linked to a doc ! */ if (cur->doc != parent->doc) { xmlSetTreeDoc(cur, parent->doc); } parent->last = cur;
return(cur);}
/** * xmlAddChild: * @parent: the parent node * @cur: the child node * * Add a new node to @parent, at the end of the child (or property) list * merging adjacent TEXT nodes (in which case @cur is freed) * If the new node is ATTRIBUTE, it is added into properties instead of children. * If there is an attribute with equal name, it is first destroyed. * * All tree manipulation functions can safely move nodes within a document. * But when moving nodes from one document to another, references to * namespaces in element or attribute nodes are NOT fixed. In this case, * you MUST call xmlReconciliateNs after the move operation to avoid * memory errors. * * Returns the child or NULL in case of error. */xmlNodePtrxmlAddChild(xmlNodePtr parent, xmlNodePtr cur) { xmlNodePtr prev;
if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) { return(NULL); }
if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) { return(NULL); }
if (parent == cur) { return(NULL); } /* * If cur is a TEXT node, merge its content with adjacent TEXT nodes * cur is then freed. */ if (cur->type == XML_TEXT_NODE) { if ((parent->type == XML_TEXT_NODE) && (parent->content != NULL) && (parent->name == cur->name)) { xmlNodeAddContent(parent, cur->content); xmlFreeNode(cur); return(parent); } if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) && (parent->last->name == cur->name) && (parent->last != cur)) { xmlNodeAddContent(parent->last, cur->content); xmlFreeNode(cur); return(parent->last); } }
/* * add the new element at the end of the children list. */ prev = cur->parent; cur->parent = parent; if (cur->doc != parent->doc) { xmlSetTreeDoc(cur, parent->doc); } /* this check prevents a loop on tree-traversions if a developer * tries to add a node to its parent multiple times */ if (prev == parent) return(cur);
/* * Coalescing */ if ((parent->type == XML_TEXT_NODE) && (parent->content != NULL) && (parent != cur)) { xmlNodeAddContent(parent, cur->content); xmlFreeNode(cur); return(parent); } if (cur->type == XML_ATTRIBUTE_NODE) { if (parent->type != XML_ELEMENT_NODE) return(NULL); if (parent->properties != NULL) { /* check if an attribute with the same name exists */ xmlAttrPtr lastattr;
if (cur->ns == NULL) lastattr = xmlHasNsProp(parent, cur->name, NULL); else lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href); if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur) && (lastattr->type != XML_ATTRIBUTE_DECL)) { /* different instance, destroy it (attributes must be unique) */ xmlUnlinkNode((xmlNodePtr) lastattr); xmlFreeProp(lastattr); } if (lastattr == (xmlAttrPtr) cur) return(cur);
} if (parent->properties == NULL) { parent->properties = (xmlAttrPtr) cur; } else { /* find the end */ xmlAttrPtr lastattr = parent->properties; while (lastattr->next != NULL) { lastattr = lastattr->next; } lastattr->next = (xmlAttrPtr) cur; ((xmlAttrPtr) cur)->prev = lastattr; } } else { if (parent->children == NULL) { parent->children = cur; parent->last = cur; } else { prev = parent->last; prev->next = cur; cur->prev = prev; parent->last = cur; } } return(cur);}
/** * xmlGetLastChild: * @parent: the parent node * * Search the last child of a node. * Returns the last child or NULL if none. */xmlNodePtrxmlGetLastChild(const xmlNode *parent) { if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) { return(NULL); } return(parent->last);}
#ifdef LIBXML_TREE_ENABLED/* * 5 interfaces from DOM ElementTraversal */
/** * xmlChildElementCount: * @parent: the parent node * * Finds the current number of child nodes of that element which are * element nodes. * Note the handling of entities references is different than in * the W3C DOM element traversal spec since we don't have back reference * from entities content to entities references. * * Returns the count of element child or 0 if not available */unsigned longxmlChildElementCount(xmlNodePtr parent) { unsigned long ret = 0; xmlNodePtr cur = NULL;
if (parent == NULL) return(0); switch (parent->type) { case XML_ELEMENT_NODE: case XML_ENTITY_NODE: case XML_DOCUMENT_NODE: case XML_DOCUMENT_FRAG_NODE: case XML_HTML_DOCUMENT_NODE: cur = parent->children; break; default: return(0); } while (cur != NULL) { if (cur->type == XML_ELEMENT_NODE) ret++; cur = cur->next; } return(ret);}
/** * xmlFirstElementChild: * @parent: the parent node * * Finds the first child node of that element which is a Element node * Note the handling of entities references is different than in * the W3C DOM element traversal spec since we don't have back reference * from entities content to entities references. * * Returns the first element child or NULL if not available */xmlNodePtrxmlFirstElementChild(xmlNodePtr parent) { xmlNodePtr cur = NULL;
if (parent == NULL) return(NULL); switch (parent->type) { case XML_ELEMENT_NODE: case XML_ENTITY_NODE: case XML_DOCUMENT_NODE: case XML_DOCUMENT_FRAG_NODE: case XML_HTML_DOCUMENT_NODE: cur = parent->children; break; default: return(NULL); } while (cur != NULL) { if (cur->type == XML_ELEMENT_NODE) return(cur); cur = cur->next; } return(NULL);}
/** * xmlLastElementChild: * @parent: the parent node * * Finds the last child node of that element which is a Element node * Note the handling of entities references is different than in * the W3C DOM element traversal spec since we don't have back reference * from entities content to entities references. * * Returns the last element child or NULL if not available */xmlNodePtrxmlLastElementChild(xmlNodePtr parent) { xmlNodePtr cur = NULL;
if (parent == NULL) return(NULL); switch (parent->type) { case XML_ELEMENT_NODE: case XML_ENTITY_NODE: case XML_DOCUMENT_NODE: case XML_DOCUMENT_FRAG_NODE: case XML_HTML_DOCUMENT_NODE: cur = parent->last; break; default: return(NULL); } while (cur != NULL) { if (cur->type == XML_ELEMENT_NODE) return(cur); cur = cur->prev; } return(NULL);}
/** * xmlPreviousElementSibling: * @node: the current node * * Finds the first closest previous sibling of the node which is an * element node. * Note the handling of entities references is different than in * the W3C DOM element traversal spec since we don't have back reference * from entities content to entities references. * * Returns the previous element sibling or NULL if not available */xmlNodePtrxmlPreviousElementSibling(xmlNodePtr node) { if (node == NULL) return(NULL); switch (node->type) { case XML_ELEMENT_NODE: case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_ENTITY_REF_NODE: case XML_ENTITY_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: case XML_XINCLUDE_START: case XML_XINCLUDE_END: node = node->prev; break; default: return(NULL); } while (node != NULL) { if (node->type == XML_ELEMENT_NODE) return(node); node = node->prev; } return(NULL);}
/** * xmlNextElementSibling: * @node: the current node * * Finds the first closest next sibling of the node which is an * element node. * Note the handling of entities references is different than in * the W3C DOM element traversal spec since we don't have back reference * from entities content to entities references. * * Returns the next element sibling or NULL if not available */xmlNodePtrxmlNextElementSibling(xmlNodePtr node) { if (node == NULL) return(NULL); switch (node->type) { case XML_ELEMENT_NODE: case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_ENTITY_REF_NODE: case XML_ENTITY_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: case XML_DTD_NODE: case XML_XINCLUDE_START: case XML_XINCLUDE_END: node = node->next; break; default: return(NULL); } while (node != NULL) { if (node->type == XML_ELEMENT_NODE) return(node); node = node->next; } return(NULL);}
#endif /* LIBXML_TREE_ENABLED */
/** * xmlFreeNodeList: * @cur: the first node in the list * * Free a node and all its siblings, this is a recursive behaviour, all * the children are freed too. */voidxmlFreeNodeList(xmlNodePtr cur) { xmlNodePtr next; xmlNodePtr parent; xmlDictPtr dict = NULL; size_t depth = 0;
if (cur == NULL) return; if (cur->type == XML_NAMESPACE_DECL) { xmlFreeNsList((xmlNsPtr) cur); return; } if (cur->doc != NULL) dict = cur->doc->dict; while (1) { while ((cur->children != NULL) && (cur->type != XML_DOCUMENT_NODE) && (cur->type != XML_HTML_DOCUMENT_NODE) && (cur->type != XML_DTD_NODE) && (cur->type != XML_ENTITY_REF_NODE)) { cur = cur->children; depth += 1; }
next = cur->next; parent = cur->parent; if ((cur->type == XML_DOCUMENT_NODE) || (cur->type == XML_HTML_DOCUMENT_NODE)) { xmlFreeDoc((xmlDocPtr) cur); } else if (cur->type != XML_DTD_NODE) {
if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) xmlDeregisterNodeDefaultValue(cur);
if (((cur->type == XML_ELEMENT_NODE) || (cur->type == XML_XINCLUDE_START) || (cur->type == XML_XINCLUDE_END)) && (cur->properties != NULL)) xmlFreePropList(cur->properties); if ((cur->type != XML_ELEMENT_NODE) && (cur->type != XML_XINCLUDE_START) && (cur->type != XML_XINCLUDE_END) && (cur->type != XML_ENTITY_REF_NODE) && (cur->content != (xmlChar *) &(cur->properties))) { DICT_FREE(cur->content) } if (((cur->type == XML_ELEMENT_NODE) || (cur->type == XML_XINCLUDE_START) || (cur->type == XML_XINCLUDE_END)) && (cur->nsDef != NULL)) xmlFreeNsList(cur->nsDef);
/* * When a node is a text node or a comment, it uses a global static * variable for the name of the node. * Otherwise the node name might come from the document's * dictionary */ if ((cur->name != NULL) && (cur->type != XML_TEXT_NODE) && (cur->type != XML_COMMENT_NODE)) DICT_FREE(cur->name) xmlFree(cur); }
if (next != NULL) { cur = next; } else { if ((depth == 0) || (parent == NULL)) break; depth -= 1; cur = parent; cur->children = NULL; } }}
/** * xmlFreeNode: * @cur: the node * * Free a node, this is a recursive behaviour, all the children are freed too. * This doesn't unlink the child from the list, use xmlUnlinkNode() first. */voidxmlFreeNode(xmlNodePtr cur) { xmlDictPtr dict = NULL;
if (cur == NULL) return;
/* use xmlFreeDtd for DTD nodes */ if (cur->type == XML_DTD_NODE) { xmlFreeDtd((xmlDtdPtr) cur); return; } if (cur->type == XML_NAMESPACE_DECL) { xmlFreeNs((xmlNsPtr) cur); return; } if (cur->type == XML_ATTRIBUTE_NODE) { xmlFreeProp((xmlAttrPtr) cur); return; }
if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) xmlDeregisterNodeDefaultValue(cur);
if (cur->doc != NULL) dict = cur->doc->dict;
if (cur->type == XML_ENTITY_DECL) { xmlEntityPtr ent = (xmlEntityPtr) cur; DICT_FREE(ent->SystemID); DICT_FREE(ent->ExternalID); } if ((cur->children != NULL) && (cur->type != XML_ENTITY_REF_NODE)) xmlFreeNodeList(cur->children);
if ((cur->type == XML_ELEMENT_NODE) || (cur->type == XML_XINCLUDE_START) || (cur->type == XML_XINCLUDE_END)) { if (cur->properties != NULL) xmlFreePropList(cur->properties); if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef); } else if ((cur->content != NULL) && (cur->type != XML_ENTITY_REF_NODE) && (cur->content != (xmlChar *) &(cur->properties))) { DICT_FREE(cur->content) }
/* * When a node is a text node or a comment, it uses a global static * variable for the name of the node. * Otherwise the node name might come from the document's dictionary */ if ((cur->name != NULL) && (cur->type != XML_TEXT_NODE) && (cur->type != XML_COMMENT_NODE)) DICT_FREE(cur->name)
xmlFree(cur);}
/** * xmlUnlinkNode: * @cur: the node * * Unlink a node from it's current context, the node is not freed * If one need to free the node, use xmlFreeNode() routine after the * unlink to discard it. * Note that namespace nodes can't be unlinked as they do not have * pointer to their parent. */voidxmlUnlinkNode(xmlNodePtr cur) { if (cur == NULL) { return; } if (cur->type == XML_NAMESPACE_DECL) return; if (cur->type == XML_DTD_NODE) { xmlDocPtr doc; doc = cur->doc; if (doc != NULL) { if (doc->intSubset == (xmlDtdPtr) cur) doc->intSubset = NULL; if (doc->extSubset == (xmlDtdPtr) cur) doc->extSubset = NULL; } } if (cur->type == XML_ENTITY_DECL) { xmlDocPtr doc; doc = cur->doc; if (doc != NULL) { if (doc->intSubset != NULL) { if (xmlHashLookup(doc->intSubset->entities, cur->name) == cur) xmlHashRemoveEntry(doc->intSubset->entities, cur->name, NULL); if (xmlHashLookup(doc->intSubset->pentities, cur->name) == cur) xmlHashRemoveEntry(doc->intSubset->pentities, cur->name, NULL); } if (doc->extSubset != NULL) { if (xmlHashLookup(doc->extSubset->entities, cur->name) == cur) xmlHashRemoveEntry(doc->extSubset->entities, cur->name, NULL); if (xmlHashLookup(doc->extSubset->pentities, cur->name) == cur) xmlHashRemoveEntry(doc->extSubset->pentities, cur->name, NULL); } } } if (cur->parent != NULL) { xmlNodePtr parent; parent = cur->parent; if (cur->type == XML_ATTRIBUTE_NODE) { if (parent->properties == (xmlAttrPtr) cur) parent->properties = ((xmlAttrPtr) cur)->next; } else { if (parent->children == cur) parent->children = cur->next; if (parent->last == cur) parent->last = cur->prev; } cur->parent = NULL; } if (cur->next != NULL) cur->next->prev = cur->prev; if (cur->prev != NULL) cur->prev->next = cur->next; cur->next = cur->prev = NULL;}
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)/** * xmlReplaceNode: * @old: the old node * @cur: the node * * Unlink the old node from its current context, prune the new one * at the same place. If @cur was already inserted in a document it is * first unlinked from its existing context. * * See the note regarding namespaces in xmlAddChild. * * Returns the @old node */xmlNodePtrxmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) { if (old == cur) return(NULL); if ((old == NULL) || (old->type == XML_NAMESPACE_DECL) || (old->parent == NULL)) { return(NULL); } if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) { xmlUnlinkNode(old); return(old); } if (cur == old) { return(old); } if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) { return(old); } if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) { return(old); } xmlUnlinkNode(cur); xmlSetTreeDoc(cur, old->doc); cur->parent = old->parent; cur->next = old->next; if (cur->next != NULL) cur->next->prev = cur; cur->prev = old->prev; if (cur->prev != NULL) cur->prev->next = cur; if (cur->parent != NULL) { if (cur->type == XML_ATTRIBUTE_NODE) { if (cur->parent->properties == (xmlAttrPtr)old) cur->parent->properties = ((xmlAttrPtr) cur); } else { if (cur->parent->children == old) cur->parent->children = cur; if (cur->parent->last == old) cur->parent->last = cur; } } old->next = old->prev = NULL; old->parent = NULL; return(old);}#endif /* LIBXML_TREE_ENABLED */
/************************************************************************ * * * Copy operations * * * ************************************************************************/
/** * xmlCopyNamespace: * @cur: the namespace * * Do a copy of the namespace. * * Returns: a new #xmlNsPtr, or NULL in case of error. */xmlNsPtrxmlCopyNamespace(xmlNsPtr cur) { xmlNsPtr ret;
if (cur == NULL) return(NULL); switch (cur->type) { case XML_LOCAL_NAMESPACE: ret = xmlNewNs(NULL, cur->href, cur->prefix); break; default: return(NULL); } return(ret);}
/** * xmlCopyNamespaceList: * @cur: the first namespace * * Do a copy of an namespace list. * * Returns: a new #xmlNsPtr, or NULL in case of error. */xmlNsPtrxmlCopyNamespaceList(xmlNsPtr cur) { xmlNsPtr ret = NULL; xmlNsPtr p = NULL,q;
while (cur != NULL) { q = xmlCopyNamespace(cur); if (q == NULL) { xmlFreeNsList(ret); return(NULL); } if (p == NULL) { ret = p = q; } else { p->next = q; p = q; } cur = cur->next; } return(ret);}
static xmlAttrPtrxmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) { xmlAttrPtr ret;
if (cur == NULL) return(NULL); if ((target != NULL) && (target->type != XML_ELEMENT_NODE)) return(NULL); if (target != NULL) ret = xmlNewDocProp(target->doc, cur->name, NULL); else if (doc != NULL) ret = xmlNewDocProp(doc, cur->name, NULL); else if (cur->parent != NULL) ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL); else if (cur->children != NULL) ret = xmlNewDocProp(cur->children->doc, cur->name, NULL); else ret = xmlNewDocProp(NULL, cur->name, NULL); if (ret == NULL) return(NULL); ret->parent = target;
if ((cur->ns != NULL) && (target != NULL)) { xmlNsPtr ns;
ns = xmlSearchNs(target->doc, target, cur->ns->prefix); if (ns == NULL) { /* * Humm, we are copying an element whose namespace is defined * out of the new tree scope. Search it in the original tree * and add it at the top of the new tree */ ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix); if (ns != NULL) { xmlNodePtr root = target; xmlNodePtr pred = NULL;
while (root->parent != NULL) { pred = root; root = root->parent; } if (root == (xmlNodePtr) target->doc) { /* correct possibly cycling above the document elt */ root = pred; } ret->ns = xmlNewNs(root, ns->href, ns->prefix); } } else { /* * we have to find something appropriate here since * we can't be sure, that the namespace we found is identified * by the prefix */ if (xmlStrEqual(ns->href, cur->ns->href)) { /* this is the nice case */ ret->ns = ns; } else { /* * we are in trouble: we need a new reconciled namespace. * This is expensive */ ret->ns = xmlNewReconciledNs(target->doc, target, cur->ns); } }
} else ret->ns = NULL;
if (cur->children != NULL) { xmlNodePtr tmp;
ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret); ret->last = NULL; tmp = ret->children; while (tmp != NULL) { /* tmp->parent = (xmlNodePtr)ret; */ if (tmp->next == NULL) ret->last = tmp; tmp = tmp->next; } } /* * Try to handle IDs */ if ((target!= NULL) && (cur!= NULL) && (target->doc != NULL) && (cur->doc != NULL) && (cur->doc->ids != NULL) && (cur->parent != NULL)) { if (xmlIsID(cur->doc, cur->parent, cur)) { xmlChar *id;
id = xmlNodeListGetString(cur->doc, cur->children, 1); if (id != NULL) { xmlAddID(NULL, target->doc, id, ret); xmlFree(id); } } } return(ret);}
/** * xmlCopyProp: * @target: the element where the attribute will be grafted * @cur: the attribute * * Do a copy of the attribute. * * Returns: a new #xmlAttrPtr, or NULL in case of error. */xmlAttrPtrxmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) { return xmlCopyPropInternal(NULL, target, cur);}
/** * xmlCopyPropList: * @target: the element where the attributes will be grafted * @cur: the first attribute * * Do a copy of an attribute list. * * Returns: a new #xmlAttrPtr, or NULL in case of error. */xmlAttrPtrxmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) { xmlAttrPtr ret = NULL; xmlAttrPtr p = NULL,q;
if ((target != NULL) && (target->type != XML_ELEMENT_NODE)) return(NULL); while (cur != NULL) { q = xmlCopyProp(target, cur); if (q == NULL) { xmlFreePropList(ret); return(NULL); } if (p == NULL) { ret = p = q; } else { p->next = q; q->prev = p; p = q; } cur = cur->next; } return(ret);}
/* * NOTE about the CopyNode operations ! * * They are split into external and internal parts for one * tricky reason: namespaces. Doing a direct copy of a node * say RPM:Copyright without changing the namespace pointer to * something else can produce stale links. One way to do it is * to keep a reference counter but this doesn't work as soon * as one moves the element or the subtree out of the scope of * the existing namespace. The actual solution seems to be to add * a copy of the namespace at the top of the copied tree if * not available in the subtree. * Hence two functions, the public front-end call the inner ones * The argument "recursive" normally indicates a recursive copy * of the node with values 0 (no) and 1 (yes). For XInclude, * however, we allow a value of 2 to indicate copy properties and * namespace info, but don't recurse on children. */
xmlNodePtrxmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, int extended) { xmlNodePtr ret;
if (node == NULL) return(NULL); switch (node->type) { case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_ELEMENT_NODE: case XML_DOCUMENT_FRAG_NODE: case XML_ENTITY_REF_NODE: case XML_ENTITY_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: case XML_XINCLUDE_START: case XML_XINCLUDE_END: break; case XML_ATTRIBUTE_NODE: return((xmlNodePtr) xmlCopyPropInternal(doc, parent, (xmlAttrPtr) node)); case XML_NAMESPACE_DECL: return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
case XML_DOCUMENT_NODE: case XML_HTML_DOCUMENT_NODE:#ifdef LIBXML_TREE_ENABLED return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));#endif /* LIBXML_TREE_ENABLED */ case XML_DOCUMENT_TYPE_NODE: case XML_NOTATION_NODE: case XML_DTD_NODE: case XML_ELEMENT_DECL: case XML_ATTRIBUTE_DECL: case XML_ENTITY_DECL: return(NULL); }
/* * Allocate a new node and fill the fields. */ ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); if (ret == NULL) { xmlTreeErrMemory("copying node"); return(NULL); } memset(ret, 0, sizeof(xmlNode)); ret->type = node->type;
ret->doc = doc; ret->parent = parent; if (node->name == xmlStringText) ret->name = xmlStringText; else if (node->name == xmlStringTextNoenc) ret->name = xmlStringTextNoenc; else if (node->name == xmlStringComment) ret->name = xmlStringComment; else if (node->name != NULL) { if ((doc != NULL) && (doc->dict != NULL)) ret->name = xmlDictLookup(doc->dict, node->name, -1); else ret->name = xmlStrdup(node->name); } if ((node->type != XML_ELEMENT_NODE) && (node->content != NULL) && (node->type != XML_ENTITY_REF_NODE) && (node->type != XML_XINCLUDE_END) && (node->type != XML_XINCLUDE_START)) { ret->content = xmlStrdup(node->content); }else{ if (node->type == XML_ELEMENT_NODE) ret->line = node->line; } if (parent != NULL) { xmlNodePtr tmp;
/* * this is a tricky part for the node register thing: * in case ret does get coalesced in xmlAddChild * the deregister-node callback is called; so we register ret now already */ if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
/* * Note that since ret->parent is already set, xmlAddChild will * return early and not actually insert the node. It will only * coalesce text nodes and unnecessarily call xmlSetTreeDoc. * Assuming that the subtree to be copied always has its text * nodes coalesced, the somewhat confusing call to xmlAddChild * could be removed. */ tmp = xmlAddChild(parent, ret); /* node could have coalesced */ if (tmp != ret) return(tmp); }
if (!extended) goto out; if (((node->type == XML_ELEMENT_NODE) || (node->type == XML_XINCLUDE_START)) && (node->nsDef != NULL)) ret->nsDef = xmlCopyNamespaceList(node->nsDef);
if (node->ns != NULL) { xmlNsPtr ns;
ns = xmlSearchNs(doc, ret, node->ns->prefix); if (ns == NULL) { /* * Humm, we are copying an element whose namespace is defined * out of the new tree scope. Search it in the original tree * and add it at the top of the new tree. * * TODO: Searching the original tree seems unnecessary. We * already have a namespace URI. */ ns = xmlSearchNs(node->doc, node, node->ns->prefix); if (ns != NULL) { xmlNodePtr root = ret;
while (root->parent != NULL) root = root->parent; ret->ns = xmlNewNs(root, ns->href, ns->prefix); } else { ret->ns = xmlNewReconciledNs(doc, ret, node->ns); } } else { /* * reference the existing namespace definition in our own tree. */ ret->ns = ns; } } if (((node->type == XML_ELEMENT_NODE) || (node->type == XML_XINCLUDE_START)) && (node->properties != NULL)) ret->properties = xmlCopyPropList(ret, node->properties); if (node->type == XML_ENTITY_REF_NODE) { if ((doc == NULL) || (node->doc != doc)) { /* * The copied node will go into a separate document, so * to avoid dangling references to the ENTITY_DECL node * we cannot keep the reference. Try to find it in the * target document. */ ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name); } else { ret->children = node->children; } ret->last = ret->children; } else if ((node->children != NULL) && (extended != 2)) { xmlNodePtr cur, insert;
cur = node->children; insert = ret; while (cur != NULL) { xmlNodePtr copy = xmlStaticCopyNode(cur, doc, insert, 2); if (copy == NULL) { xmlFreeNode(ret); return(NULL); }
/* Check for coalesced text nodes */ if (insert->last != copy) { if (insert->last == NULL) { insert->children = copy; } else { copy->prev = insert->last; insert->last->next = copy; } insert->last = copy; }
if ((cur->type != XML_ENTITY_REF_NODE) && (cur->children != NULL)) { cur = cur->children; insert = copy; continue; }
while (1) { if (cur->next != NULL) { cur = cur->next; break; }
cur = cur->parent; insert = insert->parent; if (cur == node) { cur = NULL; break; } } } }
out: /* if parent != NULL we already registered the node above */ if ((parent == NULL) && ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))) xmlRegisterNodeDefaultValue((xmlNodePtr)ret); return(ret);}
xmlNodePtrxmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) { xmlNodePtr ret = NULL; xmlNodePtr p = NULL,q; xmlDtdPtr newSubset = NULL; int linkedSubset = 0;
while (node != NULL) {#ifdef LIBXML_TREE_ENABLED if (node->type == XML_DTD_NODE ) { if (doc == NULL) { node = node->next; continue; } if ((doc->intSubset == NULL) && (newSubset == NULL)) { q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node ); if (q == NULL) goto error; q->doc = doc; q->parent = parent; newSubset = (xmlDtdPtr) q; xmlAddChild(parent, q); } else { linkedSubset = 1; q = (xmlNodePtr) doc->intSubset; xmlAddChild(parent, q); } } else#endif /* LIBXML_TREE_ENABLED */ q = xmlStaticCopyNode(node, doc, parent, 1); if (q == NULL) goto error; if (ret == NULL) { q->prev = NULL; ret = p = q; } else if (p != q) { /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */ p->next = q; q->prev = p; p = q; } node = node->next; } if ((doc != NULL) && (newSubset != NULL)) doc->intSubset = newSubset; return(ret);error: if (linkedSubset != 0) xmlUnlinkNode((xmlNodePtr) doc->intSubset); xmlFreeNodeList(ret); return(NULL);}
/** * xmlCopyNode: * @node: the node * @extended: if 1 do a recursive copy (properties, namespaces and children * when applicable) * if 2 copy properties and namespaces (when applicable) * * Do a copy of the node. * * Returns: a new #xmlNodePtr, or NULL in case of error. */xmlNodePtrxmlCopyNode(xmlNodePtr node, int extended) { xmlNodePtr ret;
ret = xmlStaticCopyNode(node, NULL, NULL, extended); return(ret);}
/** * xmlDocCopyNode: * @node: the node * @doc: the document * @extended: if 1 do a recursive copy (properties, namespaces and children * when applicable) * if 2 copy properties and namespaces (when applicable) * * Do a copy of the node to a given document. * * Returns: a new #xmlNodePtr, or NULL in case of error. */xmlNodePtrxmlDocCopyNode(xmlNodePtr node, xmlDocPtr doc, int extended) { xmlNodePtr ret;
ret = xmlStaticCopyNode(node, doc, NULL, extended); return(ret);}
/** * xmlDocCopyNodeList: * @doc: the target document * @node: the first node in the list. * * Do a recursive copy of the node list. * * Returns: a new #xmlNodePtr, or NULL in case of error. */xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, xmlNodePtr node) { xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL); return(ret);}
/** * xmlCopyNodeList: * @node: the first node in the list. * * Do a recursive copy of the node list. * Use xmlDocCopyNodeList() if possible to ensure string interning. * * Returns: a new #xmlNodePtr, or NULL in case of error. */xmlNodePtr xmlCopyNodeList(xmlNodePtr node) { xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL); return(ret);}
#if defined(LIBXML_TREE_ENABLED)/** * xmlCopyDtd: * @dtd: the dtd * * Do a copy of the dtd. * * Returns: a new #xmlDtdPtr, or NULL in case of error. */xmlDtdPtrxmlCopyDtd(xmlDtdPtr dtd) { xmlDtdPtr ret; xmlNodePtr cur, p = NULL, q;
if (dtd == NULL) return(NULL); ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID); if (ret == NULL) return(NULL); if (dtd->entities != NULL) ret->entities = (void *) xmlCopyEntitiesTable( (xmlEntitiesTablePtr) dtd->entities); if (dtd->notations != NULL) ret->notations = (void *) xmlCopyNotationTable( (xmlNotationTablePtr) dtd->notations); if (dtd->elements != NULL) ret->elements = (void *) xmlCopyElementTable( (xmlElementTablePtr) dtd->elements); if (dtd->attributes != NULL) ret->attributes = (void *) xmlCopyAttributeTable( (xmlAttributeTablePtr) dtd->attributes); if (dtd->pentities != NULL) ret->pentities = (void *) xmlCopyEntitiesTable( (xmlEntitiesTablePtr) dtd->pentities);
cur = dtd->children; while (cur != NULL) { q = NULL;
if (cur->type == XML_ENTITY_DECL) { xmlEntityPtr tmp = (xmlEntityPtr) cur; switch (tmp->etype) { case XML_INTERNAL_GENERAL_ENTITY: case XML_EXTERNAL_GENERAL_PARSED_ENTITY: case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name); break; case XML_INTERNAL_PARAMETER_ENTITY: case XML_EXTERNAL_PARAMETER_ENTITY: q = (xmlNodePtr) xmlGetParameterEntityFromDtd(ret, tmp->name); break; case XML_INTERNAL_PREDEFINED_ENTITY: break; } } else if (cur->type == XML_ELEMENT_DECL) { xmlElementPtr tmp = (xmlElementPtr) cur; q = (xmlNodePtr) xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix); } else if (cur->type == XML_ATTRIBUTE_DECL) { xmlAttributePtr tmp = (xmlAttributePtr) cur; q = (xmlNodePtr) xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix); } else if (cur->type == XML_COMMENT_NODE) { q = xmlCopyNode(cur, 0); }
if (q == NULL) { cur = cur->next; continue; }
if (p == NULL) ret->children = q; else p->next = q;
q->prev = p; q->parent = (xmlNodePtr) ret; q->next = NULL; ret->last = q; p = q; cur = cur->next; }
return(ret);}#endif
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)/** * xmlCopyDoc: * @doc: the document * @recursive: if not zero do a recursive copy. * * Do a copy of the document info. If recursive, the content tree will * be copied too as well as DTD, namespaces and entities. * * Returns: a new #xmlDocPtr, or NULL in case of error. */xmlDocPtrxmlCopyDoc(xmlDocPtr doc, int recursive) { xmlDocPtr ret;
if (doc == NULL) return(NULL); ret = xmlNewDoc(doc->version); if (ret == NULL) return(NULL); ret->type = doc->type; if (doc->name != NULL) ret->name = xmlMemStrdup(doc->name); if (doc->encoding != NULL) ret->encoding = xmlStrdup(doc->encoding); if (doc->URL != NULL) ret->URL = xmlStrdup(doc->URL); ret->charset = doc->charset; ret->compression = doc->compression; ret->standalone = doc->standalone; if (!recursive) return(ret);
ret->last = NULL; ret->children = NULL;#ifdef LIBXML_TREE_ENABLED if (doc->intSubset != NULL) { ret->intSubset = xmlCopyDtd(doc->intSubset); if (ret->intSubset == NULL) { xmlFreeDoc(ret); return(NULL); } xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret); ret->intSubset->parent = ret; }#endif if (doc->oldNs != NULL) ret->oldNs = xmlCopyNamespaceList(doc->oldNs); if (doc->children != NULL) { xmlNodePtr tmp;
ret->children = xmlStaticCopyNodeList(doc->children, ret, (xmlNodePtr)ret); ret->last = NULL; tmp = ret->children; while (tmp != NULL) { if (tmp->next == NULL) ret->last = tmp; tmp = tmp->next; } } return(ret);}#endif /* LIBXML_TREE_ENABLED */
/************************************************************************ * * * Content access functions * * * ************************************************************************/
/** * xmlGetLineNoInternal: * @node: valid node * @depth: used to limit any risk of recursion * * Get line number of @node. * Try to override the limitation of lines being store in 16 bits ints * * Returns the line number if successful, -1 otherwise */static longxmlGetLineNoInternal(const xmlNode *node, int depth){ long result = -1;
if (depth >= 5) return(-1);
if (!node) return result; if ((node->type == XML_ELEMENT_NODE) || (node->type == XML_TEXT_NODE) || (node->type == XML_COMMENT_NODE) || (node->type == XML_PI_NODE)) { if (node->line == 65535) { if ((node->type == XML_TEXT_NODE) && (node->psvi != NULL)) result = (long) (ptrdiff_t) node->psvi; else if ((node->type == XML_ELEMENT_NODE) && (node->children != NULL)) result = xmlGetLineNoInternal(node->children, depth + 1); else if (node->next != NULL) result = xmlGetLineNoInternal(node->next, depth + 1); else if (node->prev != NULL) result = xmlGetLineNoInternal(node->prev, depth + 1); } if ((result == -1) || (result == 65535)) result = (long) node->line; } else if ((node->prev != NULL) && ((node->prev->type == XML_ELEMENT_NODE) || (node->prev->type == XML_TEXT_NODE) || (node->prev->type == XML_COMMENT_NODE) || (node->prev->type == XML_PI_NODE))) result = xmlGetLineNoInternal(node->prev, depth + 1); else if ((node->parent != NULL) && (node->parent->type == XML_ELEMENT_NODE)) result = xmlGetLineNoInternal(node->parent, depth + 1);
return result;}
/** * xmlGetLineNo: * @node: valid node * * Get line number of @node. * Try to override the limitation of lines being store in 16 bits ints * if XML_PARSE_BIG_LINES parser option was used * * Returns the line number if successful, -1 otherwise */longxmlGetLineNo(const xmlNode *node){ return(xmlGetLineNoInternal(node, 0));}
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)/** * xmlGetNodePath: * @node: a node * * Build a structure based Path for the given node * * Returns the new path or NULL in case of error. The caller must free * the returned string */xmlChar *xmlGetNodePath(const xmlNode *node){ const xmlNode *cur, *tmp, *next; xmlChar *buffer = NULL, *temp; size_t buf_len; xmlChar *buf; const char *sep; const char *name; char nametemp[100]; int occur = 0, generic;
if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) return (NULL);
buf_len = 500; buffer = (xmlChar *) xmlMallocAtomic(buf_len); if (buffer == NULL) { xmlTreeErrMemory("getting node path"); return (NULL); } buf = (xmlChar *) xmlMallocAtomic(buf_len); if (buf == NULL) { xmlTreeErrMemory("getting node path"); xmlFree(buffer); return (NULL); }
buffer[0] = 0; cur = node; do { name = ""; sep = "?"; occur = 0; if ((cur->type == XML_DOCUMENT_NODE) || (cur->type == XML_HTML_DOCUMENT_NODE)) { if (buffer[0] == '/') break; sep = "/"; next = NULL; } else if (cur->type == XML_ELEMENT_NODE) { generic = 0; sep = "/"; name = (const char *) cur->name; if (cur->ns) { if (cur->ns->prefix != NULL) { snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s", (char *)cur->ns->prefix, (char *)cur->name); nametemp[sizeof(nametemp) - 1] = 0; name = nametemp; } else { /* * We cannot express named elements in the default * namespace, so use "*". */ generic = 1; name = "*"; } } next = cur->parent;
/* * Thumbler index computation * TODO: the occurrence test seems bogus for namespaced names */ tmp = cur->prev; while (tmp != NULL) { if ((tmp->type == XML_ELEMENT_NODE) && (generic || (xmlStrEqual(cur->name, tmp->name) && ((tmp->ns == cur->ns) || ((tmp->ns != NULL) && (cur->ns != NULL) && (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix))))))) occur++; tmp = tmp->prev; } if (occur == 0) { tmp = cur->next; while (tmp != NULL && occur == 0) { if ((tmp->type == XML_ELEMENT_NODE) && (generic || (xmlStrEqual(cur->name, tmp->name) && ((tmp->ns == cur->ns) || ((tmp->ns != NULL) && (cur->ns != NULL) && (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix))))))) occur++; tmp = tmp->next; } if (occur != 0) occur = 1; } else occur++; } else if (cur->type == XML_COMMENT_NODE) { sep = "/"; name = "comment()"; next = cur->parent;
/* * Thumbler index computation */ tmp = cur->prev; while (tmp != NULL) { if (tmp->type == XML_COMMENT_NODE) occur++; tmp = tmp->prev; } if (occur == 0) { tmp = cur->next; while (tmp != NULL && occur == 0) { if (tmp->type == XML_COMMENT_NODE) occur++; tmp = tmp->next; } if (occur != 0) occur = 1; } else occur++; } else if ((cur->type == XML_TEXT_NODE) || (cur->type == XML_CDATA_SECTION_NODE)) { sep = "/"; name = "text()"; next = cur->parent;
/* * Thumbler index computation */ tmp = cur->prev; while (tmp != NULL) { if ((tmp->type == XML_TEXT_NODE) || (tmp->type == XML_CDATA_SECTION_NODE)) occur++; tmp = tmp->prev; } /* * Evaluate if this is the only text- or CDATA-section-node; * if yes, then we'll get "text()", otherwise "text()[1]". */ if (occur == 0) { tmp = cur->next; while (tmp != NULL) { if ((tmp->type == XML_TEXT_NODE) || (tmp->type == XML_CDATA_SECTION_NODE)) { occur = 1; break; } tmp = tmp->next; } } else occur++; } else if (cur->type == XML_PI_NODE) { sep = "/"; snprintf(nametemp, sizeof(nametemp) - 1, "processing-instruction('%s')", (char *)cur->name); nametemp[sizeof(nametemp) - 1] = 0; name = nametemp;
next = cur->parent;
/* * Thumbler index computation */ tmp = cur->prev; while (tmp != NULL) { if ((tmp->type == XML_PI_NODE) && (xmlStrEqual(cur->name, tmp->name))) occur++; tmp = tmp->prev; } if (occur == 0) { tmp = cur->next; while (tmp != NULL && occur == 0) { if ((tmp->type == XML_PI_NODE) && (xmlStrEqual(cur->name, tmp->name))) occur++; tmp = tmp->next; } if (occur != 0) occur = 1; } else occur++;
} else if (cur->type == XML_ATTRIBUTE_NODE) { sep = "/@"; name = (const char *) (((xmlAttrPtr) cur)->name); if (cur->ns) { if (cur->ns->prefix != NULL) snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s", (char *)cur->ns->prefix, (char *)cur->name); else snprintf(nametemp, sizeof(nametemp) - 1, "%s", (char *)cur->name); nametemp[sizeof(nametemp) - 1] = 0; name = nametemp; } next = ((xmlAttrPtr) cur)->parent; } else { xmlFree(buf); xmlFree(buffer); return (NULL); }
/* * Make sure there is enough room */ if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) { buf_len = 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20; temp = (xmlChar *) xmlRealloc(buffer, buf_len); if (temp == NULL) { xmlTreeErrMemory("getting node path"); xmlFree(buf); xmlFree(buffer); return (NULL); } buffer = temp; temp = (xmlChar *) xmlRealloc(buf, buf_len); if (temp == NULL) { xmlTreeErrMemory("getting node path"); xmlFree(buf); xmlFree(buffer); return (NULL); } buf = temp; } if (occur == 0) snprintf((char *) buf, buf_len, "%s%s%s", sep, name, (char *) buffer); else snprintf((char *) buf, buf_len, "%s%s[%d]%s", sep, name, occur, (char *) buffer); snprintf((char *) buffer, buf_len, "%s", (char *)buf); cur = next; } while (cur != NULL); xmlFree(buf); return (buffer);}#endif /* LIBXML_TREE_ENABLED */
/** * xmlDocGetRootElement: * @doc: the document * * Get the root element of the document (doc->children is a list * containing possibly comments, PIs, etc ...). * * Returns the #xmlNodePtr for the root or NULL */xmlNodePtrxmlDocGetRootElement(const xmlDoc *doc) { xmlNodePtr ret;
if (doc == NULL) return(NULL); ret = doc->children; while (ret != NULL) { if (ret->type == XML_ELEMENT_NODE) return(ret); ret = ret->next; } return(ret);}
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)/** * xmlDocSetRootElement: * @doc: the document * @root: the new document root element, if root is NULL no action is taken, * to remove a node from a document use xmlUnlinkNode(root) instead. * * Set the root element of the document (doc->children is a list * containing possibly comments, PIs, etc ...). * * Returns the old root element if any was found, NULL if root was NULL */xmlNodePtrxmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) { xmlNodePtr old = NULL;
if (doc == NULL) return(NULL); if ((root == NULL) || (root->type == XML_NAMESPACE_DECL)) return(NULL); xmlUnlinkNode(root); xmlSetTreeDoc(root, doc); root->parent = (xmlNodePtr) doc; old = doc->children; while (old != NULL) { if (old->type == XML_ELEMENT_NODE) break; old = old->next; } if (old == NULL) { if (doc->children == NULL) { doc->children = root; doc->last = root; } else { xmlAddSibling(doc->children, root); } } else { xmlReplaceNode(old, root); } return(old);}#endif
#if defined(LIBXML_TREE_ENABLED)/** * xmlNodeSetLang: * @cur: the node being changed * @lang: the language description * * Set the language of a node, i.e. the values of the xml:lang * attribute. */voidxmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) { xmlNsPtr ns;
if (cur == NULL) return; switch(cur->type) { case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_COMMENT_NODE: case XML_DOCUMENT_NODE: case XML_DOCUMENT_TYPE_NODE: case XML_DOCUMENT_FRAG_NODE: case XML_NOTATION_NODE: case XML_HTML_DOCUMENT_NODE: case XML_DTD_NODE: case XML_ELEMENT_DECL: case XML_ATTRIBUTE_DECL: case XML_ENTITY_DECL: case XML_PI_NODE: case XML_ENTITY_REF_NODE: case XML_ENTITY_NODE: case XML_NAMESPACE_DECL: case XML_XINCLUDE_START: case XML_XINCLUDE_END: return; case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: break; } ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE); if (ns == NULL) return; xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);}#endif /* LIBXML_TREE_ENABLED */
/** * xmlNodeGetLang: * @cur: the node being checked * * Searches the language of a node, i.e. the values of the xml:lang * attribute or the one carried by the nearest ancestor. * * Returns a pointer to the lang value, or NULL if not found * It's up to the caller to free the memory with xmlFree(). */xmlChar *xmlNodeGetLang(const xmlNode *cur) { xmlChar *lang;
if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) return(NULL); while (cur != NULL) { lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE); if (lang != NULL) return(lang); cur = cur->parent; } return(NULL);}
#ifdef LIBXML_TREE_ENABLED/** * xmlNodeSetSpacePreserve: * @cur: the node being changed * @val: the xml:space value ("0": default, 1: "preserve") * * Set (or reset) the space preserving behaviour of a node, i.e. the * value of the xml:space attribute. */voidxmlNodeSetSpacePreserve(xmlNodePtr cur, int val) { xmlNsPtr ns;
if (cur == NULL) return; switch(cur->type) { case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_COMMENT_NODE: case XML_DOCUMENT_NODE: case XML_DOCUMENT_TYPE_NODE: case XML_DOCUMENT_FRAG_NODE: case XML_NOTATION_NODE: case XML_HTML_DOCUMENT_NODE: case XML_DTD_NODE: case XML_ELEMENT_DECL: case XML_ATTRIBUTE_DECL: case XML_ENTITY_DECL: case XML_PI_NODE: case XML_ENTITY_REF_NODE: case XML_ENTITY_NODE: case XML_NAMESPACE_DECL: case XML_XINCLUDE_START: case XML_XINCLUDE_END: return; case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: break; } ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE); if (ns == NULL) return; switch (val) { case 0: xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default"); break; case 1: xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve"); break; }}#endif /* LIBXML_TREE_ENABLED */
/** * xmlNodeGetSpacePreserve: * @cur: the node being checked * * Searches the space preserving behaviour of a node, i.e. the values * of the xml:space attribute or the one carried by the nearest * ancestor. * * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve" */intxmlNodeGetSpacePreserve(const xmlNode *cur) { xmlChar *space;
if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE)) return(-1); while (cur != NULL) { space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE); if (space != NULL) { if (xmlStrEqual(space, BAD_CAST "preserve")) { xmlFree(space); return(1); } if (xmlStrEqual(space, BAD_CAST "default")) { xmlFree(space); return(0); } xmlFree(space); } cur = cur->parent; } return(-1);}
#ifdef LIBXML_TREE_ENABLED/** * xmlNodeSetName: * @cur: the node being changed * @name: the new tag name * * Set (or reset) the name of a node. */voidxmlNodeSetName(xmlNodePtr cur, const xmlChar *name) { xmlDocPtr doc; xmlDictPtr dict; const xmlChar *freeme = NULL;
if (cur == NULL) return; if (name == NULL) return; switch(cur->type) { case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_COMMENT_NODE: case XML_DOCUMENT_TYPE_NODE: case XML_DOCUMENT_FRAG_NODE: case XML_NOTATION_NODE: case XML_HTML_DOCUMENT_NODE: case XML_NAMESPACE_DECL: case XML_XINCLUDE_START: case XML_XINCLUDE_END: return; case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: case XML_PI_NODE: case XML_ENTITY_REF_NODE: case XML_ENTITY_NODE: case XML_DTD_NODE: case XML_DOCUMENT_NODE: case XML_ELEMENT_DECL: case XML_ATTRIBUTE_DECL: case XML_ENTITY_DECL: break; } doc = cur->doc; if (doc != NULL) dict = doc->dict; else dict = NULL; if (dict != NULL) { if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name))) freeme = cur->name; cur->name = xmlDictLookup(dict, name, -1); } else { if (cur->name != NULL) freeme = cur->name; cur->name = xmlStrdup(name); }
if (freeme) xmlFree((xmlChar *) freeme);}#endif
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)/** * xmlNodeSetBase: * @cur: the node being changed * @uri: the new base URI * * Set (or reset) the base URI of a node, i.e. the value of the * xml:base attribute. */voidxmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) { xmlNsPtr ns; xmlChar* fixed;
if (cur == NULL) return; switch(cur->type) { case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_COMMENT_NODE: case XML_DOCUMENT_TYPE_NODE: case XML_DOCUMENT_FRAG_NODE: case XML_NOTATION_NODE: case XML_DTD_NODE: case XML_ELEMENT_DECL: case XML_ATTRIBUTE_DECL: case XML_ENTITY_DECL: case XML_PI_NODE: case XML_ENTITY_REF_NODE: case XML_ENTITY_NODE: case XML_NAMESPACE_DECL: case XML_XINCLUDE_START: case XML_XINCLUDE_END: return; case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: break; case XML_DOCUMENT_NODE: case XML_HTML_DOCUMENT_NODE: { xmlDocPtr doc = (xmlDocPtr) cur;
if (doc->URL != NULL) xmlFree((xmlChar *) doc->URL); if (uri == NULL) doc->URL = NULL; else doc->URL = xmlPathToURI(uri); return; } }
ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE); if (ns == NULL) return; fixed = xmlPathToURI(uri); if (fixed != NULL) { xmlSetNsProp(cur, ns, BAD_CAST "base", fixed); xmlFree(fixed); } else { xmlSetNsProp(cur, ns, BAD_CAST "base", uri); }}#endif /* LIBXML_TREE_ENABLED */
/** * xmlNodeGetBase: * @doc: the document the node pertains to * @cur: the node being checked * * Searches for the BASE URL. The code should work on both XML * and HTML document even if base mechanisms are completely different. * It returns the base as defined in RFC 2396 sections * 5.1.1. Base URI within Document Content * and * 5.1.2. Base URI from the Encapsulating Entity * However it does not return the document base (5.1.3), use * doc->URL in this case * * Returns a pointer to the base URL, or NULL if not found * It's up to the caller to free the memory with xmlFree(). */xmlChar *xmlNodeGetBase(const xmlDoc *doc, const xmlNode *cur) { xmlChar *oldbase = NULL; xmlChar *base, *newbase;
if ((cur == NULL) && (doc == NULL)) return(NULL); if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL)) return(NULL); if (doc == NULL) doc = cur->doc; if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) { cur = doc->children; while ((cur != NULL) && (cur->name != NULL)) { if (cur->type != XML_ELEMENT_NODE) { cur = cur->next; continue; } if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) { cur = cur->children; continue; } if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) { cur = cur->children; continue; } if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) { return(xmlGetProp(cur, BAD_CAST "href")); } cur = cur->next; } return(NULL); } while (cur != NULL) { if (cur->type == XML_ENTITY_DECL) { xmlEntityPtr ent = (xmlEntityPtr) cur; return(xmlStrdup(ent->URI)); } if (cur->type == XML_ELEMENT_NODE) { base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE); if (base != NULL) { if (oldbase != NULL) { newbase = xmlBuildURI(oldbase, base); if (newbase != NULL) { xmlFree(oldbase); xmlFree(base); oldbase = newbase; } else { xmlFree(oldbase); xmlFree(base); return(NULL); } } else { oldbase = base; } if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) || (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) || (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4))) return(oldbase); } } cur = cur->parent; } if ((doc != NULL) && (doc->URL != NULL)) { if (oldbase == NULL) return(xmlStrdup(doc->URL)); newbase = xmlBuildURI(oldbase, doc->URL); xmlFree(oldbase); return(newbase); } return(oldbase);}
/** * xmlNodeBufGetContent: * @buffer: a buffer * @cur: the node being read * * Read the value of a node @cur, this can be either the text carried * directly by this node if it's a TEXT node or the aggregate string * of the values carried by this node child's (TEXT and ENTITY_REF). * Entity references are substituted. * Fills up the buffer @buffer with this value * * Returns 0 in case of success and -1 in case of error. */intxmlNodeBufGetContent(xmlBufferPtr buffer, const xmlNode *cur){ xmlBufPtr buf; int ret;
if ((cur == NULL) || (buffer == NULL)) return(-1); buf = xmlBufFromBuffer(buffer); ret = xmlBufGetNodeContent(buf, cur); buffer = xmlBufBackToBuffer(buf); if ((ret < 0) || (buffer == NULL)) return(-1); return(0);}
/** * xmlBufGetNodeContent: * @buf: a buffer xmlBufPtr * @cur: the node being read * * Read the value of a node @cur, this can be either the text carried * directly by this node if it's a TEXT node or the aggregate string * of the values carried by this node child's (TEXT and ENTITY_REF). * Entity references are substituted. * Fills up the buffer @buf with this value * * Returns 0 in case of success and -1 in case of error. */intxmlBufGetNodeContent(xmlBufPtr buf, const xmlNode *cur){ if ((cur == NULL) || (buf == NULL)) return(-1); switch (cur->type) { case XML_CDATA_SECTION_NODE: case XML_TEXT_NODE: xmlBufCat(buf, cur->content); break; case XML_DOCUMENT_FRAG_NODE: case XML_ELEMENT_NODE:{ const xmlNode *tmp = cur;
while (tmp != NULL) { switch (tmp->type) { case XML_CDATA_SECTION_NODE: case XML_TEXT_NODE: if (tmp->content != NULL) xmlBufCat(buf, tmp->content); break; case XML_ENTITY_REF_NODE: xmlBufGetNodeContent(buf, tmp); break; default: break; } /* * Skip to next node */ if (tmp->children != NULL) { if (tmp->children->type != XML_ENTITY_DECL) { tmp = tmp->children; continue; } } if (tmp == cur) break;
if (tmp->next != NULL) { tmp = tmp->next; continue; }
do { tmp = tmp->parent; if (tmp == NULL) break; if (tmp == cur) { tmp = NULL; break; } if (tmp->next != NULL) { tmp = tmp->next; break; } } while (tmp != NULL); } break; } case XML_ATTRIBUTE_NODE:{ xmlAttrPtr attr = (xmlAttrPtr) cur; xmlNodePtr tmp = attr->children;
while (tmp != NULL) { if (tmp->type == XML_TEXT_NODE) xmlBufCat(buf, tmp->content); else xmlBufGetNodeContent(buf, tmp); tmp = tmp->next; } break; } case XML_COMMENT_NODE: case XML_PI_NODE: xmlBufCat(buf, cur->content); break; case XML_ENTITY_REF_NODE:{ xmlEntityPtr ent; xmlNodePtr tmp;
/* lookup entity declaration */ ent = xmlGetDocEntity(cur->doc, cur->name); if (ent == NULL) return(-1);
/* an entity content can be any "well balanced chunk", * i.e. the result of the content [43] production: * http://www.w3.org/TR/REC-xml#NT-content * -> we iterate through child nodes and recursive call * xmlNodeGetContent() which handles all possible node types */ tmp = ent->children; while (tmp) { xmlBufGetNodeContent(buf, tmp); tmp = tmp->next; } break; } case XML_ENTITY_NODE: case XML_DOCUMENT_TYPE_NODE: case XML_NOTATION_NODE: case XML_DTD_NODE: case XML_XINCLUDE_START: case XML_XINCLUDE_END: break; case XML_DOCUMENT_NODE: case XML_HTML_DOCUMENT_NODE: cur = cur->children; while (cur!= NULL) { if ((cur->type == XML_ELEMENT_NODE) || (cur->type == XML_TEXT_NODE) || (cur->type == XML_CDATA_SECTION_NODE)) { xmlBufGetNodeContent(buf, cur); } cur = cur->next; } break; case XML_NAMESPACE_DECL: xmlBufCat(buf, ((xmlNsPtr) cur)->href); break; case XML_ELEMENT_DECL: case XML_ATTRIBUTE_DECL: case XML_ENTITY_DECL: break; } return(0);}
/** * xmlNodeGetContent: * @cur: the node being read * * Read the value of a node, this can be either the text carried * directly by this node if it's a TEXT node or the aggregate string * of the values carried by this node child's (TEXT and ENTITY_REF). * Entity references are substituted. * Returns a new #xmlChar * or NULL if no content is available. * It's up to the caller to free the memory with xmlFree(). */xmlChar *xmlNodeGetContent(const xmlNode *cur){ if (cur == NULL) return (NULL); switch (cur->type) { case XML_DOCUMENT_FRAG_NODE: case XML_ELEMENT_NODE:{ xmlBufPtr buf; xmlChar *ret;
buf = xmlBufCreateSize(64); if (buf == NULL) return (NULL); xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT); xmlBufGetNodeContent(buf, cur); ret = xmlBufDetach(buf); xmlBufFree(buf); return (ret); } case XML_ATTRIBUTE_NODE: return(xmlGetPropNodeValueInternal((xmlAttrPtr) cur)); case XML_COMMENT_NODE: case XML_PI_NODE: if (cur->content != NULL) return (xmlStrdup(cur->content)); return (NULL); case XML_ENTITY_REF_NODE:{ xmlEntityPtr ent; xmlBufPtr buf; xmlChar *ret;
/* lookup entity declaration */ ent = xmlGetDocEntity(cur->doc, cur->name); if (ent == NULL) return (NULL);
buf = xmlBufCreate(); if (buf == NULL) return (NULL); xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
xmlBufGetNodeContent(buf, cur);
ret = xmlBufDetach(buf); xmlBufFree(buf); return (ret); } case XML_ENTITY_NODE: case XML_DOCUMENT_TYPE_NODE: case XML_NOTATION_NODE: case XML_DTD_NODE: case XML_XINCLUDE_START: case XML_XINCLUDE_END: return (NULL); case XML_DOCUMENT_NODE: case XML_HTML_DOCUMENT_NODE: { xmlBufPtr buf; xmlChar *ret;
buf = xmlBufCreate(); if (buf == NULL) return (NULL); xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
xmlBufGetNodeContent(buf, (xmlNodePtr) cur);
ret = xmlBufDetach(buf); xmlBufFree(buf); return (ret); } case XML_NAMESPACE_DECL: { xmlChar *tmp;
tmp = xmlStrdup(((xmlNsPtr) cur)->href); return (tmp); } case XML_ELEMENT_DECL: /* TODO !!! */ return (NULL); case XML_ATTRIBUTE_DECL: /* TODO !!! */ return (NULL); case XML_ENTITY_DECL: /* TODO !!! */ return (NULL); case XML_CDATA_SECTION_NODE: case XML_TEXT_NODE: if (cur->content != NULL) return (xmlStrdup(cur->content)); return (NULL); } return (NULL);}
/** * xmlNodeSetContent: * @cur: the node being modified * @content: the new value of the content * * Replace the content of a node. * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity * references, but XML special chars need to be escaped first by using * xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars(). */voidxmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) { if (cur == NULL) { return; } switch (cur->type) { case XML_DOCUMENT_FRAG_NODE: case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: if (cur->children != NULL) xmlFreeNodeList(cur->children); cur->children = xmlStringGetNodeList(cur->doc, content); UPDATE_LAST_CHILD_AND_PARENT(cur) break; case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_ENTITY_REF_NODE: case XML_ENTITY_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: if ((cur->content != NULL) && (cur->content != (xmlChar *) &(cur->properties))) { if (!((cur->doc != NULL) && (cur->doc->dict != NULL) && (xmlDictOwns(cur->doc->dict, cur->content)))) xmlFree(cur->content); } if (cur->children != NULL) xmlFreeNodeList(cur->children); cur->last = cur->children = NULL; if (content != NULL) { cur->content = xmlStrdup(content); } else cur->content = NULL; cur->properties = NULL; break; case XML_DOCUMENT_NODE: case XML_HTML_DOCUMENT_NODE: case XML_DOCUMENT_TYPE_NODE: case XML_XINCLUDE_START: case XML_XINCLUDE_END: break; case XML_NOTATION_NODE: break; case XML_DTD_NODE: break; case XML_NAMESPACE_DECL: break; case XML_ELEMENT_DECL: /* TODO !!! */ break; case XML_ATTRIBUTE_DECL: /* TODO !!! */ break; case XML_ENTITY_DECL: /* TODO !!! */ break; }}
#ifdef LIBXML_TREE_ENABLED/** * xmlNodeSetContentLen: * @cur: the node being modified * @content: the new value of the content * @len: the size of @content * * Replace the content of a node. * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity * references, but XML special chars need to be escaped first by using * xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars(). */voidxmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) { if (cur == NULL) { return; } switch (cur->type) { case XML_DOCUMENT_FRAG_NODE: case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: if (cur->children != NULL) xmlFreeNodeList(cur->children); cur->children = xmlStringLenGetNodeList(cur->doc, content, len); UPDATE_LAST_CHILD_AND_PARENT(cur) break; case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_ENTITY_REF_NODE: case XML_ENTITY_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: case XML_NOTATION_NODE: if ((cur->content != NULL) && (cur->content != (xmlChar *) &(cur->properties))) { if (!((cur->doc != NULL) && (cur->doc->dict != NULL) && (xmlDictOwns(cur->doc->dict, cur->content)))) xmlFree(cur->content); } if (cur->children != NULL) xmlFreeNodeList(cur->children); cur->children = cur->last = NULL; if (content != NULL) { cur->content = xmlStrndup(content, len); } else cur->content = NULL; cur->properties = NULL; break; case XML_DOCUMENT_NODE: case XML_DTD_NODE: case XML_HTML_DOCUMENT_NODE: case XML_DOCUMENT_TYPE_NODE: case XML_NAMESPACE_DECL: case XML_XINCLUDE_START: case XML_XINCLUDE_END: break; case XML_ELEMENT_DECL: /* TODO !!! */ break; case XML_ATTRIBUTE_DECL: /* TODO !!! */ break; case XML_ENTITY_DECL: /* TODO !!! */ break; }}#endif /* LIBXML_TREE_ENABLED */
/** * xmlNodeAddContentLen: * @cur: the node being modified * @content: extra content * @len: the size of @content * * Append the extra substring to the node content. * NOTE: In contrast to xmlNodeSetContentLen(), @content is supposed to be * raw text, so unescaped XML special chars are allowed, entity * references are not supported. */voidxmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) { if (cur == NULL) { return; } if (len <= 0) return; switch (cur->type) { case XML_DOCUMENT_FRAG_NODE: case XML_ELEMENT_NODE: { xmlNodePtr last, newNode, tmp;
last = cur->last; newNode = xmlNewDocTextLen(cur->doc, content, len); if (newNode != NULL) { tmp = xmlAddChild(cur, newNode); if (tmp != newNode) return; if ((last != NULL) && (last->next == newNode)) { xmlTextMerge(last, newNode); } } break; } case XML_ATTRIBUTE_NODE: break; case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_ENTITY_REF_NODE: case XML_ENTITY_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: case XML_NOTATION_NODE: if (content != NULL) { if ((cur->content == (xmlChar *) &(cur->properties)) || ((cur->doc != NULL) && (cur->doc->dict != NULL) && xmlDictOwns(cur->doc->dict, cur->content))) { cur->content = xmlStrncatNew(cur->content, content, len); cur->properties = NULL; } else { cur->content = xmlStrncat(cur->content, content, len); } } break; case XML_DOCUMENT_NODE: case XML_DTD_NODE: case XML_HTML_DOCUMENT_NODE: case XML_DOCUMENT_TYPE_NODE: case XML_NAMESPACE_DECL: case XML_XINCLUDE_START: case XML_XINCLUDE_END: break; case XML_ELEMENT_DECL: case XML_ATTRIBUTE_DECL: case XML_ENTITY_DECL: break; }}
/** * xmlNodeAddContent: * @cur: the node being modified * @content: extra content * * Append the extra substring to the node content. * NOTE: In contrast to xmlNodeSetContent(), @content is supposed to be * raw text, so unescaped XML special chars are allowed, entity * references are not supported. */voidxmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) { int len;
if (cur == NULL) { return; } if (content == NULL) return; len = xmlStrlen(content); xmlNodeAddContentLen(cur, content, len);}
/** * xmlTextMerge: * @first: the first text node * @second: the second text node being merged * * Merge two text nodes into one * Returns the first text node augmented */xmlNodePtrxmlTextMerge(xmlNodePtr first, xmlNodePtr second) { if (first == NULL) return(second); if (second == NULL) return(first); if (first->type != XML_TEXT_NODE) return(first); if (second->type != XML_TEXT_NODE) return(first); if (second->name != first->name) return(first); xmlNodeAddContent(first, second->content); xmlUnlinkNode(second); xmlFreeNode(second); return(first);}
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)/** * xmlGetNsList: * @doc: the document * @node: the current node * * Search all the namespace applying to a given element. * Returns an NULL terminated array of all the #xmlNsPtr found * that need to be freed by the caller or NULL if no * namespace if defined */xmlNsPtr *xmlGetNsList(const xmlDoc *doc ATTRIBUTE_UNUSED, const xmlNode *node){ xmlNsPtr cur; xmlNsPtr *ret = NULL; int nbns = 0; int maxns = 0; int i;
if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) return(NULL);
while (node != NULL) { if (node->type == XML_ELEMENT_NODE) { cur = node->nsDef; while (cur != NULL) { for (i = 0; i < nbns; i++) { if ((cur->prefix == ret[i]->prefix) || (xmlStrEqual(cur->prefix, ret[i]->prefix))) break; } if (i >= nbns) { if (nbns >= maxns) { xmlNsPtr *tmp;
maxns = maxns ? maxns * 2 : 10; tmp = (xmlNsPtr *) xmlRealloc(ret, (maxns + 1) * sizeof(xmlNsPtr)); if (tmp == NULL) { xmlTreeErrMemory("getting namespace list"); xmlFree(ret); return (NULL); } ret = tmp; } ret[nbns++] = cur; ret[nbns] = NULL; }
cur = cur->next; } } node = node->parent; } return (ret);}#endif /* LIBXML_TREE_ENABLED */
/** xmlTreeEnsureXMLDecl:* @doc: the doc** Ensures that there is an XML namespace declaration on the doc.** Returns the XML ns-struct or NULL on API and internal errors.*/static xmlNsPtrxmlTreeEnsureXMLDecl(xmlDocPtr doc){ if (doc == NULL) return (NULL); if (doc->oldNs != NULL) return (doc->oldNs); { xmlNsPtr ns; ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); if (ns == NULL) { xmlTreeErrMemory( "allocating the XML namespace"); return (NULL); } memset(ns, 0, sizeof(xmlNs)); ns->type = XML_LOCAL_NAMESPACE; ns->href = xmlStrdup(XML_XML_NAMESPACE); ns->prefix = xmlStrdup((const xmlChar *)"xml"); doc->oldNs = ns; return (ns); }}
/** * xmlSearchNs: * @doc: the document * @node: the current node * @nameSpace: the namespace prefix * * Search a Ns registered under a given name space for a document. * recurse on the parents until it finds the defined namespace * or return NULL otherwise. * @nameSpace can be NULL, this is a search for the default namespace. * We don't allow to cross entities boundaries. If you don't declare * the namespace within those you will be in troubles !!! A warning * is generated to cover this case. * * Returns the namespace pointer or NULL. */xmlNsPtrxmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
xmlNsPtr cur; const xmlNode *orig = node;
if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) return(NULL); if ((nameSpace != NULL) && (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) { if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) { /* * The XML-1.0 namespace is normally held on the root * element. In this case exceptionally create it on the * node element. */ cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); if (cur == NULL) { xmlTreeErrMemory("searching namespace"); return(NULL); } memset(cur, 0, sizeof(xmlNs)); cur->type = XML_LOCAL_NAMESPACE; cur->href = xmlStrdup(XML_XML_NAMESPACE); cur->prefix = xmlStrdup((const xmlChar *)"xml"); cur->next = node->nsDef; node->nsDef = cur; return(cur); } if (doc == NULL) { doc = node->doc; if (doc == NULL) return(NULL); } /* * Return the XML namespace declaration held by the doc. */ if (doc->oldNs == NULL) return(xmlTreeEnsureXMLDecl(doc)); else return(doc->oldNs); } while (node != NULL) { if ((node->type == XML_ENTITY_REF_NODE) || (node->type == XML_ENTITY_NODE) || (node->type == XML_ENTITY_DECL)) return(NULL); if (node->type == XML_ELEMENT_NODE) { cur = node->nsDef; while (cur != NULL) { if ((cur->prefix == NULL) && (nameSpace == NULL) && (cur->href != NULL)) return(cur); if ((cur->prefix != NULL) && (nameSpace != NULL) && (cur->href != NULL) && (xmlStrEqual(cur->prefix, nameSpace))) return(cur); cur = cur->next; } if (orig != node) { cur = node->ns; if (cur != NULL) { if ((cur->prefix == NULL) && (nameSpace == NULL) && (cur->href != NULL)) return(cur); if ((cur->prefix != NULL) && (nameSpace != NULL) && (cur->href != NULL) && (xmlStrEqual(cur->prefix, nameSpace))) return(cur); } } } node = node->parent; } return(NULL);}
/** * xmlNsInScope: * @doc: the document * @node: the current node * @ancestor: the ancestor carrying the namespace * @prefix: the namespace prefix * * Verify that the given namespace held on @ancestor is still in scope * on node. * * Returns 1 if true, 0 if false and -1 in case of error. */static intxmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node, xmlNodePtr ancestor, const xmlChar * prefix){ xmlNsPtr tst;
while ((node != NULL) && (node != ancestor)) { if ((node->type == XML_ENTITY_REF_NODE) || (node->type == XML_ENTITY_NODE) || (node->type == XML_ENTITY_DECL)) return (-1); if (node->type == XML_ELEMENT_NODE) { tst = node->nsDef; while (tst != NULL) { if ((tst->prefix == NULL) && (prefix == NULL)) return (0); if ((tst->prefix != NULL) && (prefix != NULL) && (xmlStrEqual(tst->prefix, prefix))) return (0); tst = tst->next; } } node = node->parent; } if (node != ancestor) return (-1); return (1);}
/** * xmlSearchNsByHref: * @doc: the document * @node: the current node * @href: the namespace value * * Search a Ns aliasing a given URI. Recurse on the parents until it finds * the defined namespace or return NULL otherwise. * Returns the namespace pointer or NULL. */xmlNsPtrxmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href){ xmlNsPtr cur; xmlNodePtr orig = node; int is_attr;
if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) || (href == NULL)) return (NULL); if (xmlStrEqual(href, XML_XML_NAMESPACE)) { /* * Only the document can hold the XML spec namespace. */ if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) { /* * The XML-1.0 namespace is normally held on the root * element. In this case exceptionally create it on the * node element. */ cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); if (cur == NULL) { xmlTreeErrMemory("searching namespace"); return (NULL); } memset(cur, 0, sizeof(xmlNs)); cur->type = XML_LOCAL_NAMESPACE; cur->href = xmlStrdup(XML_XML_NAMESPACE); cur->prefix = xmlStrdup((const xmlChar *) "xml"); cur->next = node->nsDef; node->nsDef = cur; return (cur); } if (doc == NULL) { doc = node->doc; if (doc == NULL) return(NULL); } /* * Return the XML namespace declaration held by the doc. */ if (doc->oldNs == NULL) return(xmlTreeEnsureXMLDecl(doc)); else return(doc->oldNs); } is_attr = (node->type == XML_ATTRIBUTE_NODE); while (node != NULL) { if ((node->type == XML_ENTITY_REF_NODE) || (node->type == XML_ENTITY_NODE) || (node->type == XML_ENTITY_DECL)) return (NULL); if (node->type == XML_ELEMENT_NODE) { cur = node->nsDef; while (cur != NULL) { if ((cur->href != NULL) && (href != NULL) && (xmlStrEqual(cur->href, href))) { if (((!is_attr) || (cur->prefix != NULL)) && (xmlNsInScope(doc, orig, node, cur->prefix) == 1)) return (cur); } cur = cur->next; } if (orig != node) { cur = node->ns; if (cur != NULL) { if ((cur->href != NULL) && (href != NULL) && (xmlStrEqual(cur->href, href))) { if (((!is_attr) || (cur->prefix != NULL)) && (xmlNsInScope(doc, orig, node, cur->prefix) == 1)) return (cur); } } } } node = node->parent; } return (NULL);}
/** * xmlNewReconciledNs: * @doc: the document * @tree: a node expected to hold the new namespace * @ns: the original namespace * * This function tries to locate a namespace definition in a tree * ancestors, or create a new namespace definition node similar to * @ns trying to reuse the same prefix. However if the given prefix is * null (default namespace) or reused within the subtree defined by * @tree or on one of its ancestors then a new prefix is generated. * Returns the (new) namespace definition or NULL in case of error */static xmlNsPtrxmlNewReconciledNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) { xmlNsPtr def; xmlChar prefix[50]; int counter = 1;
if ((tree == NULL) || (tree->type != XML_ELEMENT_NODE)) { return(NULL); } if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) { return(NULL); } /* * Search an existing namespace definition inherited. */ def = xmlSearchNsByHref(doc, tree, ns->href); if (def != NULL) return(def);
/* * Find a close prefix which is not already in use. * Let's strip namespace prefixes longer than 20 chars ! */ if (ns->prefix == NULL) snprintf((char *) prefix, sizeof(prefix), "default"); else snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
def = xmlSearchNs(doc, tree, prefix); while (def != NULL) { if (counter > 1000) return(NULL); if (ns->prefix == NULL) snprintf((char *) prefix, sizeof(prefix), "default%d", counter++); else snprintf((char *) prefix, sizeof(prefix), "%.20s%d", (char *)ns->prefix, counter++); def = xmlSearchNs(doc, tree, prefix); }
/* * OK, now we are ready to create a new one. */ def = xmlNewNs(tree, ns->href, prefix); return(def);}
#ifdef LIBXML_TREE_ENABLED/** * xmlReconciliateNs: * @doc: the document * @tree: a node defining the subtree to reconciliate * * This function checks that all the namespaces declared within the given * tree are properly declared. This is needed for example after Copy or Cut * and then paste operations. The subtree may still hold pointers to * namespace declarations outside the subtree or invalid/masked. As much * as possible the function try to reuse the existing namespaces found in * the new environment. If not possible the new namespaces are redeclared * on @tree at the top of the given subtree. * Returns the number of namespace declarations created or -1 in case of error. */intxmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) { xmlNsPtr *oldNs = NULL; xmlNsPtr *newNs = NULL; int sizeCache = 0; int nbCache = 0;
xmlNsPtr n; xmlNodePtr node = tree; xmlAttrPtr attr; int ret = 0, i;
if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1); if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1); if (node->doc != doc) return(-1); while (node != NULL) { /* * Reconciliate the node namespace */ if (node->ns != NULL) { /* * initialize the cache if needed */ if (sizeCache == 0) { sizeCache = 10; oldNs = (xmlNsPtr *) xmlMalloc(sizeCache * sizeof(xmlNsPtr)); if (oldNs == NULL) { xmlTreeErrMemory("fixing namespaces"); return(-1); } newNs = (xmlNsPtr *) xmlMalloc(sizeCache * sizeof(xmlNsPtr)); if (newNs == NULL) { xmlTreeErrMemory("fixing namespaces"); xmlFree(oldNs); return(-1); } } for (i = 0;i < nbCache;i++) { if (oldNs[i] == node->ns) { node->ns = newNs[i]; break; } } if (i == nbCache) { /* * OK we need to recreate a new namespace definition */ n = xmlNewReconciledNs(doc, tree, node->ns); if (n != NULL) { /* :-( what if else ??? */ /* * check if we need to grow the cache buffers. */ if (sizeCache <= nbCache) { sizeCache *= 2; oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache * sizeof(xmlNsPtr)); if (oldNs == NULL) { xmlTreeErrMemory("fixing namespaces"); xmlFree(newNs); return(-1); } newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache * sizeof(xmlNsPtr)); if (newNs == NULL) { xmlTreeErrMemory("fixing namespaces"); xmlFree(oldNs); return(-1); } } newNs[nbCache] = n; oldNs[nbCache++] = node->ns; node->ns = n; } } } /* * now check for namespace held by attributes on the node. */ if (node->type == XML_ELEMENT_NODE) { attr = node->properties; while (attr != NULL) { if (attr->ns != NULL) { /* * initialize the cache if needed */ if (sizeCache == 0) { sizeCache = 10; oldNs = (xmlNsPtr *) xmlMalloc(sizeCache * sizeof(xmlNsPtr)); if (oldNs == NULL) { xmlTreeErrMemory("fixing namespaces"); return(-1); } newNs = (xmlNsPtr *) xmlMalloc(sizeCache * sizeof(xmlNsPtr)); if (newNs == NULL) { xmlTreeErrMemory("fixing namespaces"); xmlFree(oldNs); return(-1); } } for (i = 0;i < nbCache;i++) { if (oldNs[i] == attr->ns) { attr->ns = newNs[i]; break; } } if (i == nbCache) { /* * OK we need to recreate a new namespace definition */ n = xmlNewReconciledNs(doc, tree, attr->ns); if (n != NULL) { /* :-( what if else ??? */ /* * check if we need to grow the cache buffers. */ if (sizeCache <= nbCache) { sizeCache *= 2; oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache * sizeof(xmlNsPtr)); if (oldNs == NULL) { xmlTreeErrMemory("fixing namespaces"); xmlFree(newNs); return(-1); } newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache * sizeof(xmlNsPtr)); if (newNs == NULL) { xmlTreeErrMemory("fixing namespaces"); xmlFree(oldNs); return(-1); } } newNs[nbCache] = n; oldNs[nbCache++] = attr->ns; attr->ns = n; } } } attr = attr->next; } }
/* * Browse the full subtree, deep first */ if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) { /* deep first */ node = node->children; } else if ((node != tree) && (node->next != NULL)) { /* then siblings */ node = node->next; } else if (node != tree) { /* go up to parents->next if needed */ while (node != tree) { if (node->parent != NULL) node = node->parent; if ((node != tree) && (node->next != NULL)) { node = node->next; break; } if (node->parent == NULL) { node = NULL; break; } } /* exit condition */ if (node == tree) node = NULL; } else break; } if (oldNs != NULL) xmlFree(oldNs); if (newNs != NULL) xmlFree(newNs); return(ret);}#endif /* LIBXML_TREE_ENABLED */
static xmlAttrPtrxmlGetPropNodeInternal(const xmlNode *node, const xmlChar *name, const xmlChar *nsName, int useDTD){ xmlAttrPtr prop;
/* Avoid unused variable warning if features are disabled. */ (void) useDTD;
if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL)) return(NULL);
if (node->properties != NULL) { prop = node->properties; if (nsName == NULL) { /* * We want the attr to be in no namespace. */ do { if ((prop->ns == NULL) && xmlStrEqual(prop->name, name)) { return(prop); } prop = prop->next; } while (prop != NULL); } else { /* * We want the attr to be in the specified namespace. */ do { if ((prop->ns != NULL) && xmlStrEqual(prop->name, name) && ((prop->ns->href == nsName) || xmlStrEqual(prop->ns->href, nsName))) { return(prop); } prop = prop->next; } while (prop != NULL); } }
#ifdef LIBXML_TREE_ENABLED if (! useDTD) return(NULL); /* * Check if there is a default/fixed attribute declaration in * the internal or external subset. */ if ((node->doc != NULL) && (node->doc->intSubset != NULL)) { xmlDocPtr doc = node->doc; xmlAttributePtr attrDecl = NULL; xmlChar *elemQName, *tmpstr = NULL;
/* * We need the QName of the element for the DTD-lookup. */ if ((node->ns != NULL) && (node->ns->prefix != NULL)) { tmpstr = xmlStrdup(node->ns->prefix); tmpstr = xmlStrcat(tmpstr, BAD_CAST ":"); tmpstr = xmlStrcat(tmpstr, node->name); if (tmpstr == NULL) return(NULL); elemQName = tmpstr; } else elemQName = (xmlChar *) node->name; if (nsName == NULL) { /* * The common and nice case: Attr in no namespace. */ attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elemQName, name, NULL); if ((attrDecl == NULL) && (doc->extSubset != NULL)) { attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elemQName, name, NULL); } } else if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) { /* * The XML namespace must be bound to prefix 'xml'. */ attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elemQName, name, BAD_CAST "xml"); if ((attrDecl == NULL) && (doc->extSubset != NULL)) { attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elemQName, name, BAD_CAST "xml"); } } else { xmlNsPtr *nsList, *cur;
/* * The ugly case: Search using the prefixes of in-scope * ns-decls corresponding to @nsName. */ nsList = xmlGetNsList(node->doc, node); if (nsList == NULL) { if (tmpstr != NULL) xmlFree(tmpstr); return(NULL); } cur = nsList; while (*cur != NULL) { if (xmlStrEqual((*cur)->href, nsName)) { attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elemQName, name, (*cur)->prefix); if (attrDecl) break; if (doc->extSubset != NULL) { attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elemQName, name, (*cur)->prefix); if (attrDecl) break; } } cur++; } xmlFree(nsList); } if (tmpstr != NULL) xmlFree(tmpstr); /* * Only default/fixed attrs are relevant. */ if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL)) return((xmlAttrPtr) attrDecl); }#endif /* LIBXML_TREE_ENABLED */ return(NULL);}
static xmlChar*xmlGetPropNodeValueInternal(const xmlAttr *prop){ if (prop == NULL) return(NULL); if (prop->type == XML_ATTRIBUTE_NODE) { /* * Note that we return at least the empty string. * TODO: Do we really always want that? */ if (prop->children != NULL) { if ((prop->children->next == NULL) && ((prop->children->type == XML_TEXT_NODE) || (prop->children->type == XML_CDATA_SECTION_NODE))) { /* * Optimization for the common case: only 1 text node. */ return(xmlStrdup(prop->children->content)); } else { xmlChar *ret;
ret = xmlNodeListGetString(prop->doc, prop->children, 1); if (ret != NULL) return(ret); } } return(xmlStrdup((xmlChar *)"")); } else if (prop->type == XML_ATTRIBUTE_DECL) { return(xmlStrdup(((xmlAttributePtr)prop)->defaultValue)); } return(NULL);}
/** * xmlHasProp: * @node: the node * @name: the attribute name * * Search an attribute associated to a node * This function also looks in DTD attribute declaration for #FIXED or * default declaration values unless DTD use has been turned off. * * Returns the attribute or the attribute declaration or NULL if * neither was found. */xmlAttrPtrxmlHasProp(const xmlNode *node, const xmlChar *name) { xmlAttrPtr prop; xmlDocPtr doc;
if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL)) return(NULL); /* * Check on the properties attached to the node */ prop = node->properties; while (prop != NULL) { if (xmlStrEqual(prop->name, name)) { return(prop); } prop = prop->next; } if (!xmlCheckDTD) return(NULL);
/* * Check if there is a default declaration in the internal * or external subsets */ doc = node->doc; if (doc != NULL) { xmlAttributePtr attrDecl; if (doc->intSubset != NULL) { attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name); if ((attrDecl == NULL) && (doc->extSubset != NULL)) attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name); if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL)) /* return attribute declaration only if a default value is given (that includes #FIXED declarations) */ return((xmlAttrPtr) attrDecl); } } return(NULL);}
/** * xmlHasNsProp: * @node: the node * @name: the attribute name * @nameSpace: the URI of the namespace * * Search for an attribute associated to a node * This attribute has to be anchored in the namespace specified. * This does the entity substitution. * This function looks in DTD attribute declaration for #FIXED or * default declaration values unless DTD use has been turned off. * Note that a namespace of NULL indicates to use the default namespace. * * Returns the attribute or the attribute declaration or NULL * if neither was found. */xmlAttrPtrxmlHasNsProp(const xmlNode *node, const xmlChar *name, const xmlChar *nameSpace) {
return(xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD));}
/** * xmlGetProp: * @node: the node * @name: the attribute name * * Search and get the value of an attribute associated to a node * This does the entity substitution. * This function looks in DTD attribute declaration for #FIXED or * default declaration values unless DTD use has been turned off. * NOTE: this function acts independently of namespaces associated * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp() * for namespace aware processing. * * Returns the attribute value or NULL if not found. * It's up to the caller to free the memory with xmlFree(). */xmlChar *xmlGetProp(const xmlNode *node, const xmlChar *name) { xmlAttrPtr prop;
prop = xmlHasProp(node, name); if (prop == NULL) return(NULL); return(xmlGetPropNodeValueInternal(prop));}
/** * xmlGetNoNsProp: * @node: the node * @name: the attribute name * * Search and get the value of an attribute associated to a node * This does the entity substitution. * This function looks in DTD attribute declaration for #FIXED or * default declaration values unless DTD use has been turned off. * This function is similar to xmlGetProp except it will accept only * an attribute in no namespace. * * Returns the attribute value or NULL if not found. * It's up to the caller to free the memory with xmlFree(). */xmlChar *xmlGetNoNsProp(const xmlNode *node, const xmlChar *name) { xmlAttrPtr prop;
prop = xmlGetPropNodeInternal(node, name, NULL, xmlCheckDTD); if (prop == NULL) return(NULL); return(xmlGetPropNodeValueInternal(prop));}
/** * xmlGetNsProp: * @node: the node * @name: the attribute name * @nameSpace: the URI of the namespace * * Search and get the value of an attribute associated to a node * This attribute has to be anchored in the namespace specified. * This does the entity substitution. * This function looks in DTD attribute declaration for #FIXED or * default declaration values unless DTD use has been turned off. * * Returns the attribute value or NULL if not found. * It's up to the caller to free the memory with xmlFree(). */xmlChar *xmlGetNsProp(const xmlNode *node, const xmlChar *name, const xmlChar *nameSpace) { xmlAttrPtr prop;
prop = xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD); if (prop == NULL) return(NULL); return(xmlGetPropNodeValueInternal(prop));}
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)/** * xmlUnsetProp: * @node: the node * @name: the attribute name * * Remove an attribute carried by a node. * This handles only attributes in no namespace. * Returns 0 if successful, -1 if not found */intxmlUnsetProp(xmlNodePtr node, const xmlChar *name) { xmlAttrPtr prop;
prop = xmlGetPropNodeInternal(node, name, NULL, 0); if (prop == NULL) return(-1); xmlUnlinkNode((xmlNodePtr) prop); xmlFreeProp(prop); return(0);}
/** * xmlUnsetNsProp: * @node: the node * @ns: the namespace definition * @name: the attribute name * * Remove an attribute carried by a node. * Returns 0 if successful, -1 if not found */intxmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) { xmlAttrPtr prop;
prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0); if (prop == NULL) return(-1); xmlUnlinkNode((xmlNodePtr) prop); xmlFreeProp(prop); return(0);}#endif
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)/** * xmlSetProp: * @node: the node * @name: the attribute name (a QName) * @value: the attribute value * * Set (or reset) an attribute carried by a node. * If @name has a prefix, then the corresponding * namespace-binding will be used, if in scope; it is an * error it there's no such ns-binding for the prefix in * scope. * Returns the attribute pointer. * */xmlAttrPtrxmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) { int len; const xmlChar *nqname;
if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE)) return(NULL);
/* * handle QNames */ nqname = xmlSplitQName3(name, &len); if (nqname != NULL) { xmlNsPtr ns; xmlChar *prefix = xmlStrndup(name, len); ns = xmlSearchNs(node->doc, node, prefix); if (prefix != NULL) xmlFree(prefix); if (ns != NULL) return(xmlSetNsProp(node, ns, nqname, value)); } return(xmlSetNsProp(node, NULL, name, value));}
/** * xmlSetNsProp: * @node: the node * @ns: the namespace definition * @name: the attribute name * @value: the attribute value * * Set (or reset) an attribute carried by a node. * The ns structure must be in scope, this is not checked * * Returns the attribute pointer. */xmlAttrPtrxmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name, const xmlChar *value){ xmlAttrPtr prop;
if (ns && (ns->href == NULL)) return(NULL); prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0); if (prop != NULL) { /* * Modify the attribute's value. */ if (prop->atype == XML_ATTRIBUTE_ID) { xmlRemoveID(node->doc, prop); prop->atype = XML_ATTRIBUTE_ID; } if (prop->children != NULL) xmlFreeNodeList(prop->children); prop->children = NULL; prop->last = NULL; prop->ns = ns; if (value != NULL) { xmlNodePtr tmp;
prop->children = xmlNewDocText(node->doc, value); prop->last = NULL; tmp = prop->children; while (tmp != NULL) { tmp->parent = (xmlNodePtr) prop; if (tmp->next == NULL) prop->last = tmp; tmp = tmp->next; } } if (prop->atype == XML_ATTRIBUTE_ID) xmlAddID(NULL, node->doc, value, prop); return(prop); } /* * No equal attr found; create a new one. */ return(xmlNewPropInternal(node, ns, name, value, 0));}
#endif /* LIBXML_TREE_ENABLED */
/** * xmlNodeIsText: * @node: the node * * Is this node a Text node ? * Returns 1 yes, 0 no */intxmlNodeIsText(const xmlNode *node) { if (node == NULL) return(0);
if (node->type == XML_TEXT_NODE) return(1); return(0);}
/** * xmlIsBlankNode: * @node: the node * * Checks whether this node is an empty or whitespace only * (and possibly ignorable) text-node. * * Returns 1 yes, 0 no */intxmlIsBlankNode(const xmlNode *node) { const xmlChar *cur; if (node == NULL) return(0);
if ((node->type != XML_TEXT_NODE) && (node->type != XML_CDATA_SECTION_NODE)) return(0); if (node->content == NULL) return(1); cur = node->content; while (*cur != 0) { if (!IS_BLANK_CH(*cur)) return(0); cur++; }
return(1);}
/** * xmlTextConcat: * @node: the node * @content: the content * @len: @content length * * Concat the given string at the end of the existing node content * * Returns -1 in case of error, 0 otherwise */
intxmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) { if (node == NULL) return(-1);
if ((node->type != XML_TEXT_NODE) && (node->type != XML_CDATA_SECTION_NODE) && (node->type != XML_COMMENT_NODE) && (node->type != XML_PI_NODE)) { return(-1); } /* need to check if content is currently in the dictionary */ if ((node->content == (xmlChar *) &(node->properties)) || ((node->doc != NULL) && (node->doc->dict != NULL) && xmlDictOwns(node->doc->dict, node->content))) { node->content = xmlStrncatNew(node->content, content, len); } else { node->content = xmlStrncat(node->content, content, len); } node->properties = NULL; if (node->content == NULL) return(-1); return(0);}
/************************************************************************ * * * Output : to a FILE or in memory * * * ************************************************************************/
/** * xmlBufferCreate: * * routine to create an XML buffer. * returns the new structure. */xmlBufferPtrxmlBufferCreate(void) { xmlBufferPtr ret;
ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer)); if (ret == NULL) { xmlTreeErrMemory("creating buffer"); return(NULL); } ret->use = 0; ret->size = xmlDefaultBufferSize; ret->alloc = xmlBufferAllocScheme; ret->content = (xmlChar *) xmlMallocAtomic(ret->size); if (ret->content == NULL) { xmlTreeErrMemory("creating buffer"); xmlFree(ret); return(NULL); } ret->content[0] = 0; ret->contentIO = NULL; return(ret);}
/** * xmlBufferCreateSize: * @size: initial size of buffer * * routine to create an XML buffer. * returns the new structure. */xmlBufferPtrxmlBufferCreateSize(size_t size) { xmlBufferPtr ret;
if (size >= UINT_MAX) return(NULL); ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer)); if (ret == NULL) { xmlTreeErrMemory("creating buffer"); return(NULL); } ret->use = 0; ret->alloc = xmlBufferAllocScheme; ret->size = (size ? size + 1 : 0); /* +1 for ending null */ if (ret->size){ ret->content = (xmlChar *) xmlMallocAtomic(ret->size); if (ret->content == NULL) { xmlTreeErrMemory("creating buffer"); xmlFree(ret); return(NULL); } ret->content[0] = 0; } else ret->content = NULL; ret->contentIO = NULL; return(ret);}
/** * xmlBufferDetach: * @buf: the buffer * * Remove the string contained in a buffer and gie it back to the * caller. The buffer is reset to an empty content. * This doesn't work with immutable buffers as they can't be reset. * * Returns the previous string contained by the buffer. */xmlChar *xmlBufferDetach(xmlBufferPtr buf) { xmlChar *ret;
if (buf == NULL) return(NULL);
ret = buf->content; buf->content = NULL; buf->size = 0; buf->use = 0;
return ret;}
/** * xmlBufferCreateStatic: * @mem: the memory area * @size: the size in byte * * Returns an XML buffer initialized with bytes. */xmlBufferPtrxmlBufferCreateStatic(void *mem, size_t size) { xmlBufferPtr buf = xmlBufferCreateSize(size);
xmlBufferAdd(buf, mem, size); return(buf);}
/** * xmlBufferSetAllocationScheme: * @buf: the buffer to tune * @scheme: allocation scheme to use * * Sets the allocation scheme for this buffer */voidxmlBufferSetAllocationScheme(xmlBufferPtr buf, xmlBufferAllocationScheme scheme) { if (buf == NULL) { return; } if (buf->alloc == XML_BUFFER_ALLOC_IO) return; if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) || (scheme == XML_BUFFER_ALLOC_EXACT) || (scheme == XML_BUFFER_ALLOC_HYBRID)) buf->alloc = scheme;}
/** * xmlBufferFree: * @buf: the buffer to free * * Frees an XML buffer. It frees both the content and the structure which * encapsulate it. */voidxmlBufferFree(xmlBufferPtr buf) { if (buf == NULL) { return; }
if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) { xmlFree(buf->contentIO); } else if (buf->content != NULL) { xmlFree(buf->content); } xmlFree(buf);}
/** * xmlBufferEmpty: * @buf: the buffer * * empty a buffer. */voidxmlBufferEmpty(xmlBufferPtr buf) { if (buf == NULL) return; if (buf->content == NULL) return; buf->use = 0; if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) { size_t start_buf = buf->content - buf->contentIO;
buf->size += start_buf; buf->content = buf->contentIO; buf->content[0] = 0; } else { buf->content[0] = 0; }}
/** * xmlBufferShrink: * @buf: the buffer to dump * @len: the number of xmlChar to remove * * Remove the beginning of an XML buffer. * * Returns the number of #xmlChar removed, or -1 in case of failure. */intxmlBufferShrink(xmlBufferPtr buf, unsigned int len) { if (buf == NULL) return(-1); if (len == 0) return(0); if (len > buf->use) return(-1);
buf->use -= len; if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) { /* * we just move the content pointer, but also make sure * the perceived buffer size has shrunk accordingly */ buf->content += len; buf->size -= len;
/* * sometimes though it maybe be better to really shrink * on IO buffers */ if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) { size_t start_buf = buf->content - buf->contentIO; if (start_buf >= buf->size) { memmove(buf->contentIO, &buf->content[0], buf->use); buf->content = buf->contentIO; buf->content[buf->use] = 0; buf->size += start_buf; } } } else { memmove(buf->content, &buf->content[len], buf->use); buf->content[buf->use] = 0; } return(len);}
/** * xmlBufferGrow: * @buf: the buffer * @len: the minimum free size to allocate * * Grow the available space of an XML buffer. * * Returns the new available space or -1 in case of error */intxmlBufferGrow(xmlBufferPtr buf, unsigned int len) { unsigned int size; xmlChar *newbuf;
if (buf == NULL) return(-1);
if (len < buf->size - buf->use) return(0); if (len >= UINT_MAX - buf->use) { xmlTreeErrMemory("growing buffer past UINT_MAX"); return(-1); }
if (buf->size > (size_t) len) { size = buf->size > UINT_MAX / 2 ? UINT_MAX : buf->size * 2; } else { size = buf->use + len; size = size > UINT_MAX - 100 ? UINT_MAX : size + 100; }
if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) { size_t start_buf = buf->content - buf->contentIO;
newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size); if (newbuf == NULL) { xmlTreeErrMemory("growing buffer"); return(-1); } buf->contentIO = newbuf; buf->content = newbuf + start_buf; } else { newbuf = (xmlChar *) xmlRealloc(buf->content, size); if (newbuf == NULL) { xmlTreeErrMemory("growing buffer"); return(-1); } buf->content = newbuf; } buf->size = size; return(buf->size - buf->use - 1);}
/** * xmlBufferDump: * @file: the file output * @buf: the buffer to dump * * Dumps an XML buffer to a FILE *. * Returns the number of #xmlChar written */intxmlBufferDump(FILE *file, xmlBufferPtr buf) { size_t ret;
if (buf == NULL) { return(0); } if (buf->content == NULL) { return(0); } if (file == NULL) file = stdout; ret = fwrite(buf->content, 1, buf->use, file); return(ret > INT_MAX ? INT_MAX : ret);}
/** * xmlBufferContent: * @buf: the buffer * * Function to extract the content of a buffer * * Returns the internal content */
const xmlChar *xmlBufferContent(const xmlBuffer *buf){ if(!buf) return NULL;
return buf->content;}
/** * xmlBufferLength: * @buf: the buffer * * Function to get the length of a buffer * * Returns the length of data in the internal content */
intxmlBufferLength(const xmlBuffer *buf){ if(!buf) return 0;
return buf->use;}
/** * xmlBufferResize: * @buf: the buffer to resize * @size: the desired size * * Resize a buffer to accommodate minimum size of @size. * * Returns 0 in case of problems, 1 otherwise */intxmlBufferResize(xmlBufferPtr buf, unsigned int size){ unsigned int newSize; xmlChar* rebuf = NULL; size_t start_buf;
if (buf == NULL) return(0);
/* Don't resize if we don't have to */ if (size < buf->size) return 1;
if (size > UINT_MAX - 10) { xmlTreeErrMemory("growing buffer past UINT_MAX"); return 0; }
/* figure out new size */ switch (buf->alloc){ case XML_BUFFER_ALLOC_IO: case XML_BUFFER_ALLOC_DOUBLEIT: /*take care of empty case*/ if (buf->size == 0) newSize = (size > UINT_MAX - 10 ? UINT_MAX : size + 10); else newSize = buf->size; while (size > newSize) { if (newSize > UINT_MAX / 2) { xmlTreeErrMemory("growing buffer"); return 0; } newSize *= 2; } break; case XML_BUFFER_ALLOC_EXACT: newSize = (size > UINT_MAX - 10 ? UINT_MAX : size + 10); break; case XML_BUFFER_ALLOC_HYBRID: if (buf->use < BASE_BUFFER_SIZE) newSize = size; else { newSize = buf->size; while (size > newSize) { if (newSize > UINT_MAX / 2) { xmlTreeErrMemory("growing buffer"); return 0; } newSize *= 2; } } break;
default: newSize = (size > UINT_MAX - 10 ? UINT_MAX : size + 10); break; }
if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) { start_buf = buf->content - buf->contentIO;
if (start_buf > newSize) { /* move data back to start */ memmove(buf->contentIO, buf->content, buf->use); buf->content = buf->contentIO; buf->content[buf->use] = 0; buf->size += start_buf; } else { rebuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + newSize); if (rebuf == NULL) { xmlTreeErrMemory("growing buffer"); return 0; } buf->contentIO = rebuf; buf->content = rebuf + start_buf; } } else { if (buf->content == NULL) { rebuf = (xmlChar *) xmlMallocAtomic(newSize); buf->use = 0; rebuf[buf->use] = 0; } else if (buf->size - buf->use < 100) { rebuf = (xmlChar *) xmlRealloc(buf->content, newSize); } else { /* * if we are reallocating a buffer far from being full, it's * better to make a new allocation and copy only the used range * and free the old one. */ rebuf = (xmlChar *) xmlMallocAtomic(newSize); if (rebuf != NULL) { memcpy(rebuf, buf->content, buf->use); xmlFree(buf->content); rebuf[buf->use] = 0; } } if (rebuf == NULL) { xmlTreeErrMemory("growing buffer"); return 0; } buf->content = rebuf; } buf->size = newSize;
return 1;}
/** * xmlBufferAdd: * @buf: the buffer to dump * @str: the #xmlChar string * @len: the number of #xmlChar to add * * Add a string range to an XML buffer. if len == -1, the length of * str is recomputed. * * Returns 0 successful, a positive error code number otherwise * and -1 in case of internal or API error. */intxmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) { unsigned int needSize;
if ((str == NULL) || (buf == NULL)) { return -1; } if (len < -1) { return -1; } if (len == 0) return 0;
if (len < 0) len = xmlStrlen(str);
if (len < 0) return -1; if (len == 0) return 0;
/* Note that both buf->size and buf->use can be zero here. */ if ((unsigned) len >= buf->size - buf->use) { if ((unsigned) len >= UINT_MAX - buf->use) { xmlTreeErrMemory("growing buffer past UINT_MAX"); return XML_ERR_NO_MEMORY; } needSize = buf->use + len + 1; if (!xmlBufferResize(buf, needSize)){ xmlTreeErrMemory("growing buffer"); return XML_ERR_NO_MEMORY; } }
memmove(&buf->content[buf->use], str, len); buf->use += len; buf->content[buf->use] = 0; return 0;}
/** * xmlBufferAddHead: * @buf: the buffer * @str: the #xmlChar string * @len: the number of #xmlChar to add * * Add a string range to the beginning of an XML buffer. * if len == -1, the length of @str is recomputed. * * Returns 0 successful, a positive error code number otherwise * and -1 in case of internal or API error. */intxmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) { unsigned int needSize;
if (buf == NULL) return(-1); if (str == NULL) { return -1; } if (len < -1) { return -1; } if (len == 0) return 0;
if (len < 0) len = xmlStrlen(str);
if (len <= 0) return -1;
if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) { size_t start_buf = buf->content - buf->contentIO;
if (start_buf > (unsigned int) len) { /* * We can add it in the space previously shrunk */ buf->content -= len; memmove(&buf->content[0], str, len); buf->use += len; buf->size += len; buf->content[buf->use] = 0; return(0); } } /* Note that both buf->size and buf->use can be zero here. */ if ((unsigned) len >= buf->size - buf->use) { if ((unsigned) len >= UINT_MAX - buf->use) { xmlTreeErrMemory("growing buffer past UINT_MAX"); return(-1); } needSize = buf->use + len + 1; if (!xmlBufferResize(buf, needSize)){ xmlTreeErrMemory("growing buffer"); return XML_ERR_NO_MEMORY; } }
memmove(&buf->content[len], &buf->content[0], buf->use); memmove(&buf->content[0], str, len); buf->use += len; buf->content[buf->use] = 0; return 0;}
/** * xmlBufferCat: * @buf: the buffer to add to * @str: the #xmlChar string * * Append a zero terminated string to an XML buffer. * * Returns 0 successful, a positive error code number otherwise * and -1 in case of internal or API error. */intxmlBufferCat(xmlBufferPtr buf, const xmlChar *str) { if (buf == NULL) return(-1); if (str == NULL) return -1; return xmlBufferAdd(buf, str, -1);}
/** * xmlBufferCCat: * @buf: the buffer to dump * @str: the C char string * * Append a zero terminated C string to an XML buffer. * * Returns 0 successful, a positive error code number otherwise * and -1 in case of internal or API error. */intxmlBufferCCat(xmlBufferPtr buf, const char *str) { return xmlBufferCat(buf, (const xmlChar *) str);}
/** * xmlBufferWriteCHAR: * @buf: the XML buffer * @string: the string to add * * routine which manages and grows an output buffer. This one adds * xmlChars at the end of the buffer. */voidxmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) { if (buf == NULL) return; xmlBufferCat(buf, string);}
/** * xmlBufferWriteChar: * @buf: the XML buffer output * @string: the string to add * * routine which manage and grows an output buffer. This one add * C chars at the end of the array. */voidxmlBufferWriteChar(xmlBufferPtr buf, const char *string) { if (buf == NULL) return; xmlBufferCCat(buf, string);}
/** * xmlBufferWriteQuotedString: * @buf: the XML buffer output * @string: the string to add * * routine which manage and grows an output buffer. This one writes * a quoted or double quoted #xmlChar string, checking first if it holds * quote or double-quotes internally */voidxmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) { const xmlChar *cur, *base; if (buf == NULL) return; if (xmlStrchr(string, '\"')) { if (xmlStrchr(string, '\'')) { xmlBufferCCat(buf, "\""); base = cur = string; while(*cur != 0){ if(*cur == '"'){ if (base != cur) xmlBufferAdd(buf, base, cur - base); xmlBufferAdd(buf, BAD_CAST """, 6); cur++; base = cur; } else { cur++; } } if (base != cur) xmlBufferAdd(buf, base, cur - base); xmlBufferCCat(buf, "\""); } else{ xmlBufferCCat(buf, "\'"); xmlBufferCat(buf, string); xmlBufferCCat(buf, "\'"); } } else { xmlBufferCCat(buf, "\""); xmlBufferCat(buf, string); xmlBufferCCat(buf, "\""); }}
/** * xmlGetDocCompressMode: * @doc: the document * * get the compression ratio for a document, ZLIB based * Returns 0 (uncompressed) to 9 (max compression) */intxmlGetDocCompressMode (const xmlDoc *doc) { if (doc == NULL) return(-1); return(doc->compression);}
/** * xmlSetDocCompressMode: * @doc: the document * @mode: the compression ratio * * set the compression ratio for a document, ZLIB based * Correct values: 0 (uncompressed) to 9 (max compression) */voidxmlSetDocCompressMode (xmlDocPtr doc, int mode) { if (doc == NULL) return; if (mode < 0) doc->compression = 0; else if (mode > 9) doc->compression = 9; else doc->compression = mode;}
/** * xmlGetCompressMode: * * get the default compression mode used, ZLIB based. * Returns 0 (uncompressed) to 9 (max compression) */intxmlGetCompressMode(void){ return (xmlCompressMode);}
/** * xmlSetCompressMode: * @mode: the compression ratio * * set the default compression mode used, ZLIB based * Correct values: 0 (uncompressed) to 9 (max compression) */voidxmlSetCompressMode(int mode) { if (mode < 0) xmlCompressMode = 0; else if (mode > 9) xmlCompressMode = 9; else xmlCompressMode = mode;}
#define XML_TREE_NSMAP_PARENT -1#define XML_TREE_NSMAP_XML -2#define XML_TREE_NSMAP_DOC -3#define XML_TREE_NSMAP_CUSTOM -4
typedef struct xmlNsMapItem *xmlNsMapItemPtr;struct xmlNsMapItem { xmlNsMapItemPtr next; xmlNsMapItemPtr prev; xmlNsPtr oldNs; /* old ns decl reference */ xmlNsPtr newNs; /* new ns decl reference */ int shadowDepth; /* Shadowed at this depth */ /* * depth: * >= 0 == @node's ns-decls * -1 == @parent's ns-decls * -2 == the doc->oldNs XML ns-decl * -3 == the doc->oldNs storage ns-decls * -4 == ns-decls provided via custom ns-handling */ int depth;};
typedef struct xmlNsMap *xmlNsMapPtr;struct xmlNsMap { xmlNsMapItemPtr first; xmlNsMapItemPtr last; xmlNsMapItemPtr pool;};
#define XML_NSMAP_NOTEMPTY(m) (((m) != NULL) && ((m)->first != NULL))#define XML_NSMAP_FOREACH(m, i) for (i = (m)->first; i != NULL; i = (i)->next)#define XML_NSMAP_POP(m, i) \ i = (m)->last; \ (m)->last = (i)->prev; \ if ((m)->last == NULL) \ (m)->first = NULL; \ else \ (m)->last->next = NULL; \ (i)->next = (m)->pool; \ (m)->pool = i;
/** xmlDOMWrapNsMapFree:* @map: the ns-map** Frees the ns-map*/static voidxmlDOMWrapNsMapFree(xmlNsMapPtr nsmap){ xmlNsMapItemPtr cur, tmp;
if (nsmap == NULL) return; cur = nsmap->pool; while (cur != NULL) { tmp = cur; cur = cur->next; xmlFree(tmp); } cur = nsmap->first; while (cur != NULL) { tmp = cur; cur = cur->next; xmlFree(tmp); } xmlFree(nsmap);}
/** xmlDOMWrapNsMapAddItem:* @map: the ns-map* @oldNs: the old ns-struct* @newNs: the new ns-struct* @depth: depth and ns-kind information** Adds an ns-mapping item.*/static xmlNsMapItemPtrxmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position, xmlNsPtr oldNs, xmlNsPtr newNs, int depth){ xmlNsMapItemPtr ret; xmlNsMapPtr map;
if (nsmap == NULL) return(NULL); if ((position != -1) && (position != 0)) return(NULL); map = *nsmap;
if (map == NULL) { /* * Create the ns-map. */ map = (xmlNsMapPtr) xmlMalloc(sizeof(struct xmlNsMap)); if (map == NULL) { xmlTreeErrMemory("allocating namespace map"); return (NULL); } memset(map, 0, sizeof(struct xmlNsMap)); *nsmap = map; }
if (map->pool != NULL) { /* * Reuse an item from the pool. */ ret = map->pool; map->pool = ret->next; memset(ret, 0, sizeof(struct xmlNsMapItem)); } else { /* * Create a new item. */ ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem)); if (ret == NULL) { xmlTreeErrMemory("allocating namespace map item"); return (NULL); } memset(ret, 0, sizeof(struct xmlNsMapItem)); }
if (map->first == NULL) { /* * First ever. */ map->first = ret; map->last = ret; } else if (position == -1) { /* * Append. */ ret->prev = map->last; map->last->next = ret; map->last = ret; } else if (position == 0) { /* * Set on first position. */ map->first->prev = ret; ret->next = map->first; map->first = ret; }
ret->oldNs = oldNs; ret->newNs = newNs; ret->shadowDepth = -1; ret->depth = depth; return (ret);}
/** xmlDOMWrapStoreNs:* @doc: the doc* @nsName: the namespace name* @prefix: the prefix** Creates or reuses an xmlNs struct on doc->oldNs with* the given prefix and namespace name.** Returns the acquired ns struct or NULL in case of an API* or internal error.*/static xmlNsPtrxmlDOMWrapStoreNs(xmlDocPtr doc, const xmlChar *nsName, const xmlChar *prefix){ xmlNsPtr ns;
if (doc == NULL) return (NULL); ns = xmlTreeEnsureXMLDecl(doc); if (ns == NULL) return (NULL); if (ns->next != NULL) { /* Reuse. */ ns = ns->next; while (ns != NULL) { if (((ns->prefix == prefix) || xmlStrEqual(ns->prefix, prefix)) && xmlStrEqual(ns->href, nsName)) { return (ns); } if (ns->next == NULL) break; ns = ns->next; } } /* Create. */ if (ns != NULL) { ns->next = xmlNewNs(NULL, nsName, prefix); return (ns->next); } return(NULL);}
/** xmlDOMWrapNewCtxt:** Allocates and initializes a new DOM-wrapper context.** Returns the xmlDOMWrapCtxtPtr or NULL in case of an internal error.*/xmlDOMWrapCtxtPtrxmlDOMWrapNewCtxt(void){ xmlDOMWrapCtxtPtr ret;
ret = xmlMalloc(sizeof(xmlDOMWrapCtxt)); if (ret == NULL) { xmlTreeErrMemory("allocating DOM-wrapper context"); return (NULL); } memset(ret, 0, sizeof(xmlDOMWrapCtxt)); return (ret);}
/** xmlDOMWrapFreeCtxt:* @ctxt: the DOM-wrapper context** Frees the DOM-wrapper context.*/voidxmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt){ if (ctxt == NULL) return; if (ctxt->namespaceMap != NULL) xmlDOMWrapNsMapFree((xmlNsMapPtr) ctxt->namespaceMap); /* * TODO: Store the namespace map in the context. */ xmlFree(ctxt);}
/** xmlTreeLookupNsListByPrefix:* @nsList: a list of ns-structs* @prefix: the searched prefix** Searches for a ns-decl with the given prefix in @nsList.** Returns the ns-decl if found, NULL if not found and on* API errors.*/static xmlNsPtrxmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix){ if (nsList == NULL) return (NULL); { xmlNsPtr ns; ns = nsList; do { if ((prefix == ns->prefix) || xmlStrEqual(prefix, ns->prefix)) { return (ns); } ns = ns->next; } while (ns != NULL); } return (NULL);}
/*** xmlDOMWrapNSNormGatherInScopeNs:* @map: the namespace map* @node: the node to start with** Puts in-scope namespaces into the ns-map.** Returns 0 on success, -1 on API or internal errors.*/static intxmlDOMWrapNSNormGatherInScopeNs(xmlNsMapPtr *map, xmlNodePtr node){ xmlNodePtr cur; xmlNsPtr ns; xmlNsMapItemPtr mi; int shadowed;
if ((map == NULL) || (*map != NULL)) return (-1); if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) return (-1); /* * Get in-scope ns-decls of @parent. */ cur = node; while ((cur != NULL) && (cur != (xmlNodePtr) cur->doc)) { if (cur->type == XML_ELEMENT_NODE) { if (cur->nsDef != NULL) { ns = cur->nsDef; do { shadowed = 0; if (XML_NSMAP_NOTEMPTY(*map)) { /* * Skip shadowed prefixes. */ XML_NSMAP_FOREACH(*map, mi) { if ((ns->prefix == mi->newNs->prefix) || xmlStrEqual(ns->prefix, mi->newNs->prefix)) { shadowed = 1; break; } } } /* * Insert mapping. */ mi = xmlDOMWrapNsMapAddItem(map, 0, NULL, ns, XML_TREE_NSMAP_PARENT); if (mi == NULL) return (-1); if (shadowed) mi->shadowDepth = 0; ns = ns->next; } while (ns != NULL); } } cur = cur->parent; } return (0);}
/** XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict;* otherwise copy it, when it was in the source-dict.*/#define XML_TREE_ADOPT_STR(str) \ if (adoptStr && (str != NULL)) { \ if (destDoc->dict) { \ const xmlChar *old = str; \ str = xmlDictLookup(destDoc->dict, str, -1); \ if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \ (!xmlDictOwns(sourceDoc->dict, old))) \ xmlFree((char *)old); \ } else if ((sourceDoc) && (sourceDoc->dict) && \ xmlDictOwns(sourceDoc->dict, str)) { \ str = BAD_CAST xmlStrdup(str); \ } \ }
/** XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then* put it in dest-dict or copy it.*/#define XML_TREE_ADOPT_STR_2(str) \ if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \ (sourceDoc->dict != NULL) && \ xmlDictOwns(sourceDoc->dict, cur->content)) { \ if (destDoc->dict) \ cur->content = (xmlChar *) \ xmlDictLookup(destDoc->dict, cur->content, -1); \ else \ cur->content = xmlStrdup(BAD_CAST cur->content); \ }
/** xmlDOMWrapNSNormAddNsMapItem2:** For internal use. Adds a ns-decl mapping.** Returns 0 on success, -1 on internal errors.*/static intxmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number, xmlNsPtr oldNs, xmlNsPtr newNs){ if (*list == NULL) { *list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr)); if (*list == NULL) { xmlTreeErrMemory("alloc ns map item"); return(-1); } *size = 3; *number = 0; } else if ((*number) >= (*size)) { *size *= 2; *list = (xmlNsPtr *) xmlRealloc(*list, (*size) * 2 * sizeof(xmlNsPtr)); if (*list == NULL) { xmlTreeErrMemory("realloc ns map item"); return(-1); } } (*list)[2 * (*number)] = oldNs; (*list)[2 * (*number) +1] = newNs; (*number)++; return (0);}
/** xmlDOMWrapRemoveNode:* @ctxt: a DOM wrapper context* @doc: the doc* @node: the node to be removed.* @options: set of options, unused at the moment** Unlinks the given node from its owner.* This will substitute ns-references to node->nsDef for* ns-references to doc->oldNs, thus ensuring the removed* branch to be autark wrt ns-references.** NOTE: This function was not intensively tested.** Returns 0 on success, 1 if the node is not supported,* -1 on API and internal errors.*/intxmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr node, int options ATTRIBUTE_UNUSED){ xmlNsPtr *list = NULL; int sizeList, nbList, i, j; xmlNsPtr ns;
if ((node == NULL) || (doc == NULL) || (node->doc != doc)) return (-1);
/* TODO: 0 or -1 ? */ if (node->parent == NULL) return (0);
switch (node->type) { case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_ENTITY_REF_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: xmlUnlinkNode(node); return (0); case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: break; default: return (1); } xmlUnlinkNode(node); /* * Save out-of-scope ns-references in doc->oldNs. */ do { switch (node->type) { case XML_ELEMENT_NODE: if ((ctxt == NULL) && (node->nsDef != NULL)) { ns = node->nsDef; do { if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList, &nbList, ns, ns) == -1) goto internal_error; ns = ns->next; } while (ns != NULL); } /* Falls through. */ case XML_ATTRIBUTE_NODE: if (node->ns != NULL) { /* * Find a mapping. */ if (list != NULL) { for (i = 0, j = 0; i < nbList; i++, j += 2) { if (node->ns == list[j]) { node->ns = list[++j]; goto next_node; } } } ns = NULL; if (ctxt != NULL) { /* * User defined. */ } else { /* * Add to doc's oldNs. */ ns = xmlDOMWrapStoreNs(doc, node->ns->href, node->ns->prefix); if (ns == NULL) goto internal_error; } if (ns != NULL) { /* * Add mapping. */ if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList, &nbList, node->ns, ns) == -1) goto internal_error; } node->ns = ns; } if ((node->type == XML_ELEMENT_NODE) && (node->properties != NULL)) { node = (xmlNodePtr) node->properties; continue; } break; default: goto next_sibling; }next_node: if ((node->type == XML_ELEMENT_NODE) && (node->children != NULL)) { node = node->children; continue; }next_sibling: if (node == NULL) break; if (node->next != NULL) node = node->next; else { node = node->parent; goto next_sibling; } } while (node != NULL);
if (list != NULL) xmlFree(list); return (0);
internal_error: if (list != NULL) xmlFree(list); return (-1);}
/** xmlSearchNsByNamespaceStrict:* @doc: the document* @node: the start node* @nsName: the searched namespace name* @retNs: the resulting ns-decl* @prefixed: if the found ns-decl must have a prefix (for attributes)** Dynamically searches for a ns-declaration which matches* the given @nsName in the ancestor-or-self axis of @node.** Returns 1 if a ns-decl was found, 0 if not and -1 on API* and internal errors.*/static intxmlSearchNsByNamespaceStrict(xmlDocPtr doc, xmlNodePtr node, const xmlChar* nsName, xmlNsPtr *retNs, int prefixed){ xmlNodePtr cur, prev = NULL, out = NULL; xmlNsPtr ns, prevns;
if ((doc == NULL) || (nsName == NULL) || (retNs == NULL)) return (-1); if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) return(-1);
*retNs = NULL; if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) { *retNs = xmlTreeEnsureXMLDecl(doc); if (*retNs == NULL) return (-1); return (1); } cur = node; do { if (cur->type == XML_ELEMENT_NODE) { if (cur->nsDef != NULL) { for (ns = cur->nsDef; ns != NULL; ns = ns->next) { if (prefixed && (ns->prefix == NULL)) continue; if (prev != NULL) { /* * Check the last level of ns-decls for a * shadowing prefix. */ prevns = prev->nsDef; do { if ((prevns->prefix == ns->prefix) || ((prevns->prefix != NULL) && (ns->prefix != NULL) && xmlStrEqual(prevns->prefix, ns->prefix))) { /* * Shadowed. */ break; } prevns = prevns->next; } while (prevns != NULL); if (prevns != NULL) continue; } /* * Ns-name comparison. */ if ((nsName == ns->href) || xmlStrEqual(nsName, ns->href)) { /* * At this point the prefix can only be shadowed, * if we are the the (at least) 3rd level of * ns-decls. */ if (out) { int ret;
ret = xmlNsInScope(doc, node, prev, ns->prefix); if (ret < 0) return (-1); /* * TODO: Should we try to find a matching ns-name * only once? This here keeps on searching. * I think we should try further since, there might * be an other matching ns-decl with an unshadowed * prefix. */ if (! ret) continue; } *retNs = ns; return (1); } } out = prev; prev = cur; } } else if ((cur->type == XML_ENTITY_NODE) || (cur->type == XML_ENTITY_DECL)) return (0); cur = cur->parent; } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur)); return (0);}
/** xmlSearchNsByPrefixStrict:* @doc: the document* @node: the start node* @prefix: the searched namespace prefix* @retNs: the resulting ns-decl** Dynamically searches for a ns-declaration which matches* the given @nsName in the ancestor-or-self axis of @node.** Returns 1 if a ns-decl was found, 0 if not and -1 on API* and internal errors.*/static intxmlSearchNsByPrefixStrict(xmlDocPtr doc, xmlNodePtr node, const xmlChar* prefix, xmlNsPtr *retNs){ xmlNodePtr cur; xmlNsPtr ns;
if ((doc == NULL) || (node == NULL) || (node->type == XML_NAMESPACE_DECL)) return(-1);
if (retNs) *retNs = NULL; if (IS_STR_XML(prefix)) { if (retNs) { *retNs = xmlTreeEnsureXMLDecl(doc); if (*retNs == NULL) return (-1); } return (1); } cur = node; do { if (cur->type == XML_ELEMENT_NODE) { if (cur->nsDef != NULL) { ns = cur->nsDef; do { if ((prefix == ns->prefix) || xmlStrEqual(prefix, ns->prefix)) { /* * Disabled namespaces, e.g. xmlns:abc="". */ if (ns->href == NULL) return(0); if (retNs) *retNs = ns; return (1); } ns = ns->next; } while (ns != NULL); } } else if ((cur->type == XML_ENTITY_NODE) || (cur->type == XML_ENTITY_DECL)) return (0); cur = cur->parent; } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur)); return (0);}
/** xmlDOMWrapNSNormDeclareNsForced:* @doc: the doc* @elem: the element-node to declare on* @nsName: the namespace-name of the ns-decl* @prefix: the preferred prefix of the ns-decl* @checkShadow: ensure that the new ns-decl doesn't shadow ancestor ns-decls** Declares a new namespace on @elem. It tries to use the* given @prefix; if a ns-decl with the given prefix is already existent* on @elem, it will generate an other prefix.** Returns 1 if a ns-decl was found, 0 if not and -1 on API* and internal errors.*/static xmlNsPtrxmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc, xmlNodePtr elem, const xmlChar *nsName, const xmlChar *prefix, int checkShadow){
xmlNsPtr ret; char buf[50]; const xmlChar *pref; int counter = 0;
if ((doc == NULL) || (elem == NULL) || (elem->type != XML_ELEMENT_NODE)) return(NULL); /* * Create a ns-decl on @anchor. */ pref = prefix; while (1) { /* * Lookup whether the prefix is unused in elem's ns-decls. */ if ((elem->nsDef != NULL) && (xmlTreeNSListLookupByPrefix(elem->nsDef, pref) != NULL)) goto ns_next_prefix; if (checkShadow && elem->parent && ((xmlNodePtr) elem->parent->doc != elem->parent)) { /* * Does it shadow ancestor ns-decls? */ if (xmlSearchNsByPrefixStrict(doc, elem->parent, pref, NULL) == 1) goto ns_next_prefix; } ret = xmlNewNs(NULL, nsName, pref); if (ret == NULL) return (NULL); if (elem->nsDef == NULL) elem->nsDef = ret; else { xmlNsPtr ns2 = elem->nsDef; while (ns2->next != NULL) ns2 = ns2->next; ns2->next = ret; } return (ret);ns_next_prefix: counter++; if (counter > 1000) return (NULL); if (prefix == NULL) { snprintf((char *) buf, sizeof(buf), "ns_%d", counter); } else snprintf((char *) buf, sizeof(buf), "%.30s_%d", (char *)prefix, counter); pref = BAD_CAST buf; }}
/** xmlDOMWrapNSNormAcquireNormalizedNs:* @doc: the doc* @elem: the element-node to declare namespaces on* @ns: the ns-struct to use for the search* @retNs: the found/created ns-struct* @nsMap: the ns-map* @depth: the current tree depth* @ancestorsOnly: search in ancestor ns-decls only* @prefixed: if the searched ns-decl must have a prefix (for attributes)** Searches for a matching ns-name in the ns-decls of @nsMap, if not* found it will either declare it on @elem, or store it in doc->oldNs.* If a new ns-decl needs to be declared on @elem, it tries to use the* @ns->prefix for it, if this prefix is already in use on @elem, it will* change the prefix or the new ns-decl.** Returns 0 if succeeded, -1 otherwise and on API/internal errors.*/static intxmlDOMWrapNSNormAcquireNormalizedNs(xmlDocPtr doc, xmlNodePtr elem, xmlNsPtr ns, xmlNsPtr *retNs, xmlNsMapPtr *nsMap,
int depth, int ancestorsOnly, int prefixed){ xmlNsMapItemPtr mi;
if ((doc == NULL) || (ns == NULL) || (retNs == NULL) || (nsMap == NULL)) return (-1);
*retNs = NULL; /* * Handle XML namespace. */ if (IS_STR_XML(ns->prefix)) { /* * Insert XML namespace mapping. */ *retNs = xmlTreeEnsureXMLDecl(doc); if (*retNs == NULL) return (-1); return (0); } /* * If the search should be done in ancestors only and no * @elem (the first ancestor) was specified, then skip the search. */ if ((XML_NSMAP_NOTEMPTY(*nsMap)) && (! (ancestorsOnly && (elem == NULL)))) { /* * Try to find an equal ns-name in in-scope ns-decls. */ XML_NSMAP_FOREACH(*nsMap, mi) { if ((mi->depth >= XML_TREE_NSMAP_PARENT) && /* * ancestorsOnly: This should be turned on to gain speed, * if one knows that the branch itself was already * ns-wellformed and no stale references existed. * I.e. it searches in the ancestor axis only. */ ((! ancestorsOnly) || (mi->depth == XML_TREE_NSMAP_PARENT)) && /* Skip shadowed prefixes. */ (mi->shadowDepth == -1) && /* Skip xmlns="" or xmlns:foo="". */ ((mi->newNs->href != NULL) && (mi->newNs->href[0] != 0)) && /* Ensure a prefix if wanted. */ ((! prefixed) || (mi->newNs->prefix != NULL)) && /* Equal ns name */ ((mi->newNs->href == ns->href) || xmlStrEqual(mi->newNs->href, ns->href))) { /* Set the mapping. */ mi->oldNs = ns; *retNs = mi->newNs; return (0); } } } /* * No luck, the namespace is out of scope or shadowed. */ if (elem == NULL) { xmlNsPtr tmpns;
/* * Store ns-decls in "oldNs" of the document-node. */ tmpns = xmlDOMWrapStoreNs(doc, ns->href, ns->prefix); if (tmpns == NULL) return (-1); /* * Insert mapping. */ if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, tmpns, XML_TREE_NSMAP_DOC) == NULL) { xmlFreeNs(tmpns); return (-1); } *retNs = tmpns; } else { xmlNsPtr tmpns;
tmpns = xmlDOMWrapNSNormDeclareNsForced(doc, elem, ns->href, ns->prefix, 0); if (tmpns == NULL) return (-1);
if (*nsMap != NULL) { /* * Does it shadow ancestor ns-decls? */ XML_NSMAP_FOREACH(*nsMap, mi) { if ((mi->depth < depth) && (mi->shadowDepth == -1) && ((ns->prefix == mi->newNs->prefix) || xmlStrEqual(ns->prefix, mi->newNs->prefix))) { /* * Shadows. */ mi->shadowDepth = depth; break; } } } if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, tmpns, depth) == NULL) { xmlFreeNs(tmpns); return (-1); } *retNs = tmpns; } return (0);}
typedef enum { XML_DOM_RECONNS_REMOVEREDUND = 1<<0} xmlDOMReconcileNSOptions;
/** xmlDOMWrapReconcileNamespaces:* @ctxt: DOM wrapper context, unused at the moment* @elem: the element-node* @options: option flags** Ensures that ns-references point to ns-decls hold on element-nodes.* Ensures that the tree is namespace wellformed by creating additional* ns-decls where needed. Note that, since prefixes of already existent* ns-decls can be shadowed by this process, it could break QNames in* attribute values or element content.** NOTE: This function was not intensively tested.** Returns 0 if succeeded, -1 otherwise and on API/internal errors.*/
intxmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlNodePtr elem, int options){ int depth = -1, adoptns = 0, parnsdone = 0; xmlNsPtr ns, prevns; xmlDocPtr doc; xmlNodePtr cur, curElem = NULL; xmlNsMapPtr nsMap = NULL; xmlNsMapItemPtr /* topmi = NULL, */ mi; /* @ancestorsOnly should be set by an option flag. */ int ancestorsOnly = 0; int optRemoveRedundantNS = ((xmlDOMReconcileNSOptions) options & XML_DOM_RECONNS_REMOVEREDUND) ? 1 : 0; xmlNsPtr *listRedund = NULL; int sizeRedund = 0, nbRedund = 0, ret, i, j;
if ((elem == NULL) || (elem->doc == NULL) || (elem->type != XML_ELEMENT_NODE)) return (-1);
doc = elem->doc; cur = elem; do { switch (cur->type) { case XML_ELEMENT_NODE: adoptns = 1; curElem = cur; depth++; /* * Namespace declarations. */ if (cur->nsDef != NULL) { prevns = NULL; ns = cur->nsDef; while (ns != NULL) { if (! parnsdone) { if ((elem->parent) && ((xmlNodePtr) elem->parent->doc != elem->parent)) { /* * Gather ancestor in-scope ns-decls. */ if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, elem->parent) == -1) goto internal_error; } parnsdone = 1; }
/* * Lookup the ns ancestor-axis for equal ns-decls in scope. */ if (optRemoveRedundantNS && XML_NSMAP_NOTEMPTY(nsMap)) { XML_NSMAP_FOREACH(nsMap, mi) { if ((mi->depth >= XML_TREE_NSMAP_PARENT) && (mi->shadowDepth == -1) && ((ns->prefix == mi->newNs->prefix) || xmlStrEqual(ns->prefix, mi->newNs->prefix)) && ((ns->href == mi->newNs->href) || xmlStrEqual(ns->href, mi->newNs->href))) { /* * A redundant ns-decl was found. * Add it to the list of redundant ns-decls. */ if (xmlDOMWrapNSNormAddNsMapItem2(&listRedund, &sizeRedund, &nbRedund, ns, mi->newNs) == -1) goto internal_error; /* * Remove the ns-decl from the element-node. */ if (prevns) prevns->next = ns->next; else cur->nsDef = ns->next; goto next_ns_decl; } } }
/* * Skip ns-references handling if the referenced * ns-decl is declared on the same element. */ if ((cur->ns != NULL) && adoptns && (cur->ns == ns)) adoptns = 0; /* * Does it shadow any ns-decl? */ if (XML_NSMAP_NOTEMPTY(nsMap)) { XML_NSMAP_FOREACH(nsMap, mi) { if ((mi->depth >= XML_TREE_NSMAP_PARENT) && (mi->shadowDepth == -1) && ((ns->prefix == mi->newNs->prefix) || xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
mi->shadowDepth = depth; } } } /* * Push mapping. */ if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, ns, depth) == NULL) goto internal_error;
prevns = ns;next_ns_decl: ns = ns->next; } } if (! adoptns) goto ns_end; /* Falls through. */ case XML_ATTRIBUTE_NODE: /* No ns, no fun. */ if (cur->ns == NULL) goto ns_end;
if (! parnsdone) { if ((elem->parent) && ((xmlNodePtr) elem->parent->doc != elem->parent)) { if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, elem->parent) == -1) goto internal_error; } parnsdone = 1; } /* * Adjust the reference if this was a redundant ns-decl. */ if (listRedund) { for (i = 0, j = 0; i < nbRedund; i++, j += 2) { if (cur->ns == listRedund[j]) { cur->ns = listRedund[++j]; break; } } } /* * Adopt ns-references. */ if (XML_NSMAP_NOTEMPTY(nsMap)) { /* * Search for a mapping. */ XML_NSMAP_FOREACH(nsMap, mi) { if ((mi->shadowDepth == -1) && (cur->ns == mi->oldNs)) {
cur->ns = mi->newNs; goto ns_end; } } } /* * Acquire a normalized ns-decl and add it to the map. */ if (xmlDOMWrapNSNormAcquireNormalizedNs(doc, curElem, cur->ns, &ns, &nsMap, depth, ancestorsOnly, (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1) goto internal_error; cur->ns = ns;
ns_end: if ((cur->type == XML_ELEMENT_NODE) && (cur->properties != NULL)) { /* * Process attributes. */ cur = (xmlNodePtr) cur->properties; continue; } break; default: goto next_sibling; }into_content: if ((cur->type == XML_ELEMENT_NODE) && (cur->children != NULL)) { /* * Process content of element-nodes only. */ cur = cur->children; continue; }next_sibling: if (cur == elem) break; if (cur->type == XML_ELEMENT_NODE) { if (XML_NSMAP_NOTEMPTY(nsMap)) { /* * Pop mappings. */ while ((nsMap->last != NULL) && (nsMap->last->depth >= depth)) { XML_NSMAP_POP(nsMap, mi) } /* * Unshadow. */ XML_NSMAP_FOREACH(nsMap, mi) { if (mi->shadowDepth >= depth) mi->shadowDepth = -1; } } depth--; } if (cur->next != NULL) cur = cur->next; else { if (cur->type == XML_ATTRIBUTE_NODE) { cur = cur->parent; goto into_content; } cur = cur->parent; goto next_sibling; } } while (cur != NULL);
ret = 0; goto exit;internal_error: ret = -1;exit: if (listRedund) { for (i = 0, j = 0; i < nbRedund; i++, j += 2) { xmlFreeNs(listRedund[j]); } xmlFree(listRedund); } if (nsMap != NULL) xmlDOMWrapNsMapFree(nsMap); return (ret);}
/** xmlDOMWrapAdoptBranch:* @ctxt: the optional context for custom processing* @sourceDoc: the optional sourceDoc* @node: the element-node to start with* @destDoc: the destination doc for adoption* @destParent: the optional new parent of @node in @destDoc* @options: option flags** Ensures that ns-references point to @destDoc: either to* elements->nsDef entries if @destParent is given, or to* @destDoc->oldNs otherwise.* If @destParent is given, it ensures that the tree is namespace* wellformed by creating additional ns-decls where needed.* Note that, since prefixes of already existent ns-decls can be* shadowed by this process, it could break QNames in attribute* values or element content.** NOTE: This function was not intensively tested.** Returns 0 if succeeded, -1 otherwise and on API/internal errors.*/static intxmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr sourceDoc, xmlNodePtr node, xmlDocPtr destDoc, xmlNodePtr destParent, int options ATTRIBUTE_UNUSED){ int ret = 0; xmlNodePtr cur, curElem = NULL; xmlNsMapPtr nsMap = NULL; xmlNsMapItemPtr mi; xmlNsPtr ns = NULL; int depth = -1, adoptStr = 1; /* gather @parent's ns-decls. */ int parnsdone; /* @ancestorsOnly should be set per option. */ int ancestorsOnly = 0;
/* * Optimize string adoption for equal or none dicts. */ if ((sourceDoc != NULL) && (sourceDoc->dict == destDoc->dict)) adoptStr = 0; else adoptStr = 1;
/* * Get the ns-map from the context if available. */ if (ctxt) nsMap = (xmlNsMapPtr) ctxt->namespaceMap; /* * Disable search for ns-decls in the parent-axis of the * destination element, if: * 1) there's no destination parent * 2) custom ns-reference handling is used */ if ((destParent == NULL) || (ctxt && ctxt->getNsForNodeFunc)) { parnsdone = 1; } else parnsdone = 0;
cur = node; if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL)) goto internal_error;
while (cur != NULL) { /* * Paranoid source-doc sanity check. */ if (cur->doc != sourceDoc) { /* * We'll assume XIncluded nodes if the doc differs. * TODO: Do we need to reconciliate XIncluded nodes? * This here skips XIncluded nodes and tries to handle * broken sequences. */ if (cur->next == NULL) goto leave_node; do { cur = cur->next; if ((cur->type == XML_XINCLUDE_END) || (cur->doc == node->doc)) break; } while (cur->next != NULL);
if (cur->doc != node->doc) goto leave_node; } cur->doc = destDoc; switch (cur->type) { case XML_XINCLUDE_START: case XML_XINCLUDE_END: /* * TODO */ return (-1); case XML_ELEMENT_NODE: curElem = cur; depth++; /* * Namespace declarations. * - ns->href and ns->prefix are never in the dict, so * we need not move the values over to the destination dict. * - Note that for custom handling of ns-references, * the ns-decls need not be stored in the ns-map, * since they won't be referenced by node->ns. */ if ((cur->nsDef) && ((ctxt == NULL) || (ctxt->getNsForNodeFunc == NULL))) { if (! parnsdone) { /* * Gather @parent's in-scope ns-decls. */ if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, destParent) == -1) goto internal_error; parnsdone = 1; } for (ns = cur->nsDef; ns != NULL; ns = ns->next) { /* * NOTE: ns->prefix and ns->href are never in the dict. * XML_TREE_ADOPT_STR(ns->prefix) * XML_TREE_ADOPT_STR(ns->href) */ /* * Does it shadow any ns-decl? */ if (XML_NSMAP_NOTEMPTY(nsMap)) { XML_NSMAP_FOREACH(nsMap, mi) { if ((mi->depth >= XML_TREE_NSMAP_PARENT) && (mi->shadowDepth == -1) && ((ns->prefix == mi->newNs->prefix) || xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
mi->shadowDepth = depth; } } } /* * Push mapping. */ if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, ns, depth) == NULL) goto internal_error; } } /* Falls through. */ case XML_ATTRIBUTE_NODE: /* No namespace, no fun. */ if (cur->ns == NULL) goto ns_end;
if (! parnsdone) { if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, destParent) == -1) goto internal_error; parnsdone = 1; } /* * Adopt ns-references. */ if (XML_NSMAP_NOTEMPTY(nsMap)) { /* * Search for a mapping. */ XML_NSMAP_FOREACH(nsMap, mi) { if ((mi->shadowDepth == -1) && (cur->ns == mi->oldNs)) {
cur->ns = mi->newNs; goto ns_end; } } } /* * No matching namespace in scope. We need a new one. */ if ((ctxt) && (ctxt->getNsForNodeFunc)) { /* * User-defined behaviour. */ ns = ctxt->getNsForNodeFunc(ctxt, cur, cur->ns->href, cur->ns->prefix); /* * Insert mapping if ns is available; it's the users fault * if not. */ if (xmlDOMWrapNsMapAddItem(&nsMap, -1, cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL) goto internal_error; cur->ns = ns; } else { /* * Acquire a normalized ns-decl and add it to the map. */ if (xmlDOMWrapNSNormAcquireNormalizedNs(destDoc, /* ns-decls on curElem or on destDoc->oldNs */ destParent ? curElem : NULL, cur->ns, &ns, &nsMap, depth, ancestorsOnly, /* ns-decls must be prefixed for attributes. */ (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1) goto internal_error; cur->ns = ns; }ns_end: /* * Further node properties. * TODO: Is this all? */ XML_TREE_ADOPT_STR(cur->name) if (cur->type == XML_ELEMENT_NODE) { cur->psvi = NULL; cur->line = 0; cur->extra = 0; /* * Walk attributes. */ if (cur->properties != NULL) { /* * Process first attribute node. */ cur = (xmlNodePtr) cur->properties; continue; } } else { /* * Attributes. */ if ((sourceDoc != NULL) && (((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID)) { xmlRemoveID(sourceDoc, (xmlAttrPtr) cur); } ((xmlAttrPtr) cur)->atype = 0; ((xmlAttrPtr) cur)->psvi = NULL; } break; case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: /* * This puts the content in the dest dict, only if * it was previously in the source dict. */ XML_TREE_ADOPT_STR_2(cur->content) goto leave_node; case XML_ENTITY_REF_NODE: /* * Remove reference to the entity-node. */ cur->content = NULL; cur->children = NULL; cur->last = NULL; if ((destDoc->intSubset) || (destDoc->extSubset)) { xmlEntityPtr ent; /* * Assign new entity-node if available. */ ent = xmlGetDocEntity(destDoc, cur->name); if (ent != NULL) { cur->content = ent->content; cur->children = (xmlNodePtr) ent; cur->last = (xmlNodePtr) ent; } } goto leave_node; case XML_PI_NODE: XML_TREE_ADOPT_STR(cur->name) XML_TREE_ADOPT_STR_2(cur->content) break; case XML_COMMENT_NODE: break; default: goto internal_error; } /* * Walk the tree. */ if (cur->children != NULL) { cur = cur->children; continue; }
leave_node: if (cur == node) break; if ((cur->type == XML_ELEMENT_NODE) || (cur->type == XML_XINCLUDE_START) || (cur->type == XML_XINCLUDE_END)) { /* * TODO: Do we expect nsDefs on XML_XINCLUDE_START? */ if (XML_NSMAP_NOTEMPTY(nsMap)) { /* * Pop mappings. */ while ((nsMap->last != NULL) && (nsMap->last->depth >= depth)) { XML_NSMAP_POP(nsMap, mi) } /* * Unshadow. */ XML_NSMAP_FOREACH(nsMap, mi) { if (mi->shadowDepth >= depth) mi->shadowDepth = -1; } } depth--; } if (cur->next != NULL) cur = cur->next; else if ((cur->type == XML_ATTRIBUTE_NODE) && (cur->parent->children != NULL)) { cur = cur->parent->children; } else { cur = cur->parent; goto leave_node; } }
goto exit;
internal_error: ret = -1;
exit: /* * Cleanup. */ if (nsMap != NULL) { if ((ctxt) && (ctxt->namespaceMap == nsMap)) { /* * Just cleanup the map but don't free. */ if (nsMap->first) { if (nsMap->pool) nsMap->last->next = nsMap->pool; nsMap->pool = nsMap->first; nsMap->first = NULL; } } else xmlDOMWrapNsMapFree(nsMap); } return(ret);}
/** xmlDOMWrapCloneNode:* @ctxt: the optional context for custom processing* @sourceDoc: the optional sourceDoc* @node: the node to start with* @resNode: the clone of the given @node* @destDoc: the destination doc* @destParent: the optional new parent of @node in @destDoc* @deep: descend into child if set* @options: option flags** References of out-of scope ns-decls are remapped to point to @destDoc:* 1) If @destParent is given, then nsDef entries on element-nodes are used* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used.* This is the case when you don't know already where the cloned branch* will be added to.** If @destParent is given, it ensures that the tree is namespace* wellformed by creating additional ns-decls where needed.* Note that, since prefixes of already existent ns-decls can be* shadowed by this process, it could break QNames in attribute* values or element content.* TODO:* 1) What to do with XInclude? Currently this returns an error for XInclude.** Returns 0 if the operation succeeded,* 1 if a node of unsupported (or not yet supported) type was given,* -1 on API/internal errors.*/
intxmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr sourceDoc, xmlNodePtr node, xmlNodePtr *resNode, xmlDocPtr destDoc, xmlNodePtr destParent, int deep, int options ATTRIBUTE_UNUSED){ int ret = 0; xmlNodePtr cur, curElem = NULL; xmlNsMapPtr nsMap = NULL; xmlNsMapItemPtr mi; xmlNsPtr ns; int depth = -1; /* int adoptStr = 1; */ /* gather @parent's ns-decls. */ int parnsdone = 0; /* * @ancestorsOnly: * TODO: @ancestorsOnly should be set per option. * */ int ancestorsOnly = 0; xmlNodePtr resultClone = NULL, clone = NULL, parentClone = NULL, prevClone = NULL; xmlNsPtr cloneNs = NULL, *cloneNsDefSlot = NULL; xmlDictPtr dict; /* The destination dict */
if ((node == NULL) || (resNode == NULL) || (destDoc == NULL)) return(-1); /* * TODO: Initially we support only element-nodes. */ if (node->type != XML_ELEMENT_NODE) return(1); /* * Check node->doc sanity. */ if ((node->doc != NULL) && (sourceDoc != NULL) && (node->doc != sourceDoc)) { /* * Might be an XIncluded node. */ return (-1); } if (sourceDoc == NULL) sourceDoc = node->doc; if (sourceDoc == NULL) return (-1);
dict = destDoc->dict; /* * Reuse the namespace map of the context. */ if (ctxt) nsMap = (xmlNsMapPtr) ctxt->namespaceMap;
*resNode = NULL;
cur = node; if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL)) return(-1);
while (cur != NULL) { if (cur->doc != sourceDoc) { /* * We'll assume XIncluded nodes if the doc differs. * TODO: Do we need to reconciliate XIncluded nodes? * TODO: This here returns -1 in this case. */ goto internal_error; } /* * Create a new node. */ switch (cur->type) { case XML_XINCLUDE_START: case XML_XINCLUDE_END: /* * TODO: What to do with XInclude? */ goto internal_error; break; case XML_ELEMENT_NODE: case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_COMMENT_NODE: case XML_PI_NODE: case XML_DOCUMENT_FRAG_NODE: case XML_ENTITY_REF_NODE: case XML_ENTITY_NODE: /* * Nodes of xmlNode structure. */ clone = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); if (clone == NULL) { xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating a node"); goto internal_error; } memset(clone, 0, sizeof(xmlNode)); /* * Set hierarchical links. */ if (resultClone != NULL) { clone->parent = parentClone; if (prevClone) { prevClone->next = clone; clone->prev = prevClone; } else parentClone->children = clone; } else resultClone = clone;
break; case XML_ATTRIBUTE_NODE: /* * Attributes (xmlAttr). */ /* Use xmlRealloc to avoid -Warray-bounds warning */ clone = (xmlNodePtr) xmlRealloc(NULL, sizeof(xmlAttr)); if (clone == NULL) { xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating an attr-node"); goto internal_error; } memset(clone, 0, sizeof(xmlAttr)); /* * Set hierarchical links. * TODO: Change this to add to the end of attributes. */ if (resultClone != NULL) { clone->parent = parentClone; if (prevClone) { prevClone->next = clone; clone->prev = prevClone; } else parentClone->properties = (xmlAttrPtr) clone; } else resultClone = clone; break; default: /* * TODO QUESTION: Any other nodes expected? */ goto internal_error; }
clone->type = cur->type; clone->doc = destDoc;
/* * Clone the name of the node if any. */ if (cur->name == xmlStringText) clone->name = xmlStringText; else if (cur->name == xmlStringTextNoenc) /* * NOTE: Although xmlStringTextNoenc is never assigned to a node * in tree.c, it might be set in Libxslt via * "xsl:disable-output-escaping". */ clone->name = xmlStringTextNoenc; else if (cur->name == xmlStringComment) clone->name = xmlStringComment; else if (cur->name != NULL) { DICT_CONST_COPY(cur->name, clone->name); }
switch (cur->type) { case XML_XINCLUDE_START: case XML_XINCLUDE_END: /* * TODO */ return (-1); case XML_ELEMENT_NODE: curElem = cur; depth++; /* * Namespace declarations. */ if (cur->nsDef != NULL) { if (! parnsdone) { if (destParent && (ctxt == NULL)) { /* * Gather @parent's in-scope ns-decls. */ if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, destParent) == -1) goto internal_error; } parnsdone = 1; } /* * Clone namespace declarations. */ cloneNsDefSlot = &(clone->nsDef); for (ns = cur->nsDef; ns != NULL; ns = ns->next) { /* * Create a new xmlNs. */ cloneNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); if (cloneNs == NULL) { xmlTreeErrMemory("xmlDOMWrapCloneNode(): " "allocating namespace"); return(-1); } memset(cloneNs, 0, sizeof(xmlNs)); cloneNs->type = XML_LOCAL_NAMESPACE;
if (ns->href != NULL) cloneNs->href = xmlStrdup(ns->href); if (ns->prefix != NULL) cloneNs->prefix = xmlStrdup(ns->prefix);
*cloneNsDefSlot = cloneNs; cloneNsDefSlot = &(cloneNs->next);
/* * Note that for custom handling of ns-references, * the ns-decls need not be stored in the ns-map, * since they won't be referenced by node->ns. */ if ((ctxt == NULL) || (ctxt->getNsForNodeFunc == NULL)) { /* * Does it shadow any ns-decl? */ if (XML_NSMAP_NOTEMPTY(nsMap)) { XML_NSMAP_FOREACH(nsMap, mi) { if ((mi->depth >= XML_TREE_NSMAP_PARENT) && (mi->shadowDepth == -1) && ((ns->prefix == mi->newNs->prefix) || xmlStrEqual(ns->prefix, mi->newNs->prefix))) { /* * Mark as shadowed at the current * depth. */ mi->shadowDepth = depth; } } } /* * Push mapping. */ if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, cloneNs, depth) == NULL) goto internal_error; } } } /* cur->ns will be processed further down. */ break; case XML_ATTRIBUTE_NODE: /* IDs will be processed further down. */ /* cur->ns will be processed further down. */ break; case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: /* * Note that this will also cover the values of attributes. */ DICT_COPY(cur->content, clone->content); goto leave_node; case XML_ENTITY_NODE: /* TODO: What to do here? */ goto leave_node; case XML_ENTITY_REF_NODE: if (sourceDoc != destDoc) { if ((destDoc->intSubset) || (destDoc->extSubset)) { xmlEntityPtr ent; /* * Different doc: Assign new entity-node if available. */ ent = xmlGetDocEntity(destDoc, cur->name); if (ent != NULL) { clone->content = ent->content; clone->children = (xmlNodePtr) ent; clone->last = (xmlNodePtr) ent; } } } else { /* * Same doc: Use the current node's entity declaration * and value. */ clone->content = cur->content; clone->children = cur->children; clone->last = cur->last; } goto leave_node; case XML_PI_NODE: DICT_COPY(cur->content, clone->content); goto leave_node; case XML_COMMENT_NODE: DICT_COPY(cur->content, clone->content); goto leave_node; default: goto internal_error; }
if (cur->ns == NULL) goto end_ns_reference;
/* handle_ns_reference: */ /* ** The following will take care of references to ns-decls ******** ** and is intended only for element- and attribute-nodes. ** */ if (! parnsdone) { if (destParent && (ctxt == NULL)) { if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, destParent) == -1) goto internal_error; } parnsdone = 1; } /* * Adopt ns-references. */ if (XML_NSMAP_NOTEMPTY(nsMap)) { /* * Search for a mapping. */ XML_NSMAP_FOREACH(nsMap, mi) { if ((mi->shadowDepth == -1) && (cur->ns == mi->oldNs)) { /* * This is the nice case: a mapping was found. */ clone->ns = mi->newNs; goto end_ns_reference; } } } /* * No matching namespace in scope. We need a new one. */ if ((ctxt != NULL) && (ctxt->getNsForNodeFunc != NULL)) { /* * User-defined behaviour. */ ns = ctxt->getNsForNodeFunc(ctxt, cur, cur->ns->href, cur->ns->prefix); /* * Add user's mapping. */ if (xmlDOMWrapNsMapAddItem(&nsMap, -1, cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL) goto internal_error; clone->ns = ns; } else { /* * Acquire a normalized ns-decl and add it to the map. */ if (xmlDOMWrapNSNormAcquireNormalizedNs(destDoc, /* ns-decls on curElem or on destDoc->oldNs */ destParent ? curElem : NULL, cur->ns, &ns, &nsMap, depth, /* if we need to search only in the ancestor-axis */ ancestorsOnly, /* ns-decls must be prefixed for attributes. */ (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1) goto internal_error; clone->ns = ns; }
end_ns_reference:
/* * Some post-processing. * * Handle ID attributes. */ if ((clone->type == XML_ATTRIBUTE_NODE) && (clone->parent != NULL)) { if (xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone)) {
xmlChar *idVal;
idVal = xmlNodeListGetString(cur->doc, cur->children, 1); if (idVal != NULL) { if (xmlAddID(NULL, destDoc, idVal, (xmlAttrPtr) cur) == NULL) { /* TODO: error message. */ xmlFree(idVal); goto internal_error; } xmlFree(idVal); } } } /* ** ** The following will traverse the tree ************************** ** * * Walk the element's attributes before descending into child-nodes. */ if ((cur->type == XML_ELEMENT_NODE) && (cur->properties != NULL)) { prevClone = NULL; parentClone = clone; cur = (xmlNodePtr) cur->properties; continue; }into_content: /* * Descend into child-nodes. */ if (cur->children != NULL) { if (deep || (cur->type == XML_ATTRIBUTE_NODE)) { prevClone = NULL; parentClone = clone; cur = cur->children; continue; } }
leave_node: /* * At this point we are done with the node, its content * and an element-nodes's attribute-nodes. */ if (cur == node) break; if ((cur->type == XML_ELEMENT_NODE) || (cur->type == XML_XINCLUDE_START) || (cur->type == XML_XINCLUDE_END)) { /* * TODO: Do we expect nsDefs on XML_XINCLUDE_START? */ if (XML_NSMAP_NOTEMPTY(nsMap)) { /* * Pop mappings. */ while ((nsMap->last != NULL) && (nsMap->last->depth >= depth)) { XML_NSMAP_POP(nsMap, mi) } /* * Unshadow. */ XML_NSMAP_FOREACH(nsMap, mi) { if (mi->shadowDepth >= depth) mi->shadowDepth = -1; } } depth--; } if (cur->next != NULL) { prevClone = clone; cur = cur->next; } else if (cur->type != XML_ATTRIBUTE_NODE) { /* * Set clone->last. */ if (clone->parent != NULL) clone->parent->last = clone; clone = clone->parent; if (clone != NULL) parentClone = clone->parent; /* * Process parent --> next; */ cur = cur->parent; goto leave_node; } else { /* This is for attributes only. */ clone = clone->parent; parentClone = clone->parent; /* * Process parent-element --> children. */ cur = cur->parent; goto into_content; } } goto exit;
internal_error: ret = -1;
exit: /* * Cleanup. */ if (nsMap != NULL) { if ((ctxt) && (ctxt->namespaceMap == nsMap)) { /* * Just cleanup the map but don't free. */ if (nsMap->first) { if (nsMap->pool) nsMap->last->next = nsMap->pool; nsMap->pool = nsMap->first; nsMap->first = NULL; } } else xmlDOMWrapNsMapFree(nsMap); } /* * TODO: Should we try a cleanup of the cloned node in case of a * fatal error? */ *resNode = resultClone; return (ret);}
/** xmlDOMWrapAdoptAttr:* @ctxt: the optional context for custom processing* @sourceDoc: the optional source document of attr* @attr: the attribute-node to be adopted* @destDoc: the destination doc for adoption* @destParent: the optional new parent of @attr in @destDoc* @options: option flags** @attr is adopted by @destDoc.* Ensures that ns-references point to @destDoc: either to* elements->nsDef entries if @destParent is given, or to* @destDoc->oldNs otherwise.** Returns 0 if succeeded, -1 otherwise and on API/internal errors.*/static intxmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr sourceDoc, xmlAttrPtr attr, xmlDocPtr destDoc, xmlNodePtr destParent, int options ATTRIBUTE_UNUSED){ xmlNodePtr cur; int adoptStr = 1;
if ((attr == NULL) || (destDoc == NULL)) return (-1);
attr->doc = destDoc; if (attr->ns != NULL) { xmlNsPtr ns = NULL;
if (ctxt != NULL) { /* TODO: User defined. */ } /* XML Namespace. */ if (IS_STR_XML(attr->ns->prefix)) { ns = xmlTreeEnsureXMLDecl(destDoc); } else if (destParent == NULL) { /* * Store in @destDoc->oldNs. */ ns = xmlDOMWrapStoreNs(destDoc, attr->ns->href, attr->ns->prefix); } else { /* * Declare on @destParent. */ if (xmlSearchNsByNamespaceStrict(destDoc, destParent, attr->ns->href, &ns, 1) == -1) goto internal_error; if (ns == NULL) { ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent, attr->ns->href, attr->ns->prefix, 1); } } if (ns == NULL) goto internal_error; attr->ns = ns; }
XML_TREE_ADOPT_STR(attr->name); attr->atype = 0; attr->psvi = NULL; /* * Walk content. */ if (attr->children == NULL) return (0); cur = attr->children; if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL)) goto internal_error; while (cur != NULL) { cur->doc = destDoc; switch (cur->type) { case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: XML_TREE_ADOPT_STR_2(cur->content) break; case XML_ENTITY_REF_NODE: /* * Remove reference to the entity-node. */ cur->content = NULL; cur->children = NULL; cur->last = NULL; if ((destDoc->intSubset) || (destDoc->extSubset)) { xmlEntityPtr ent; /* * Assign new entity-node if available. */ ent = xmlGetDocEntity(destDoc, cur->name); if (ent != NULL) { cur->content = ent->content; cur->children = (xmlNodePtr) ent; cur->last = (xmlNodePtr) ent; } } break; default: break; } if (cur->children != NULL) { cur = cur->children; continue; }next_sibling: if (cur == (xmlNodePtr) attr) break; if (cur->next != NULL) cur = cur->next; else { cur = cur->parent; goto next_sibling; } } return (0);internal_error: return (-1);}
/** xmlDOMWrapAdoptNode:* @ctxt: the optional context for custom processing* @sourceDoc: the optional sourceDoc* @node: the node to start with* @destDoc: the destination doc* @destParent: the optional new parent of @node in @destDoc* @options: option flags** References of out-of scope ns-decls are remapped to point to @destDoc:* 1) If @destParent is given, then nsDef entries on element-nodes are used* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used* This is the case when you have an unlinked node and just want to move it* to the context of** If @destParent is given, it ensures that the tree is namespace* wellformed by creating additional ns-decls where needed.* Note that, since prefixes of already existent ns-decls can be* shadowed by this process, it could break QNames in attribute* values or element content.* NOTE: This function was not intensively tested.** Returns 0 if the operation succeeded,* 1 if a node of unsupported type was given,* 2 if a node of not yet supported type was given and* -1 on API/internal errors.*/intxmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr sourceDoc, xmlNodePtr node, xmlDocPtr destDoc, xmlNodePtr destParent, int options){ if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) || (destDoc == NULL) || ((destParent != NULL) && (destParent->doc != destDoc))) return(-1); /* * Check node->doc sanity. */ if ((node->doc != NULL) && (sourceDoc != NULL) && (node->doc != sourceDoc)) { /* * Might be an XIncluded node. */ return (-1); } if (sourceDoc == NULL) sourceDoc = node->doc; if (sourceDoc == destDoc) return (-1); switch (node->type) { case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_ENTITY_REF_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: break; case XML_DOCUMENT_FRAG_NODE: /* TODO: Support document-fragment-nodes. */ return (2); default: return (1); } /* * Unlink only if @node was not already added to @destParent. */ if ((node->parent != NULL) && (destParent != node->parent)) xmlUnlinkNode(node);
if (node->type == XML_ELEMENT_NODE) { return (xmlDOMWrapAdoptBranch(ctxt, sourceDoc, node, destDoc, destParent, options)); } else if (node->type == XML_ATTRIBUTE_NODE) { return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc, (xmlAttrPtr) node, destDoc, destParent, options)); } else { xmlNodePtr cur = node; int adoptStr = 1;
cur->doc = destDoc; /* * Optimize string adoption. */ if ((sourceDoc != NULL) && (sourceDoc->dict == destDoc->dict)) adoptStr = 0; switch (node->type) { case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: XML_TREE_ADOPT_STR_2(node->content) break; case XML_ENTITY_REF_NODE: /* * Remove reference to the entity-node. */ node->content = NULL; node->children = NULL; node->last = NULL; if ((destDoc->intSubset) || (destDoc->extSubset)) { xmlEntityPtr ent; /* * Assign new entity-node if available. */ ent = xmlGetDocEntity(destDoc, node->name); if (ent != NULL) { node->content = ent->content; node->children = (xmlNodePtr) ent; node->last = (xmlNodePtr) ent; } } XML_TREE_ADOPT_STR(node->name) break; case XML_PI_NODE: { XML_TREE_ADOPT_STR(node->name) XML_TREE_ADOPT_STR_2(node->content) break; } default: break; } } return (0);}
/************************************************************************ * * * XHTML detection * * * ************************************************************************/
#define XHTML_STRICT_PUBLIC_ID BAD_CAST \ "-//W3C//DTD XHTML 1.0 Strict//EN"#define XHTML_STRICT_SYSTEM_ID BAD_CAST \ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"#define XHTML_FRAME_PUBLIC_ID BAD_CAST \ "-//W3C//DTD XHTML 1.0 Frameset//EN"#define XHTML_FRAME_SYSTEM_ID BAD_CAST \ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"#define XHTML_TRANS_PUBLIC_ID BAD_CAST \ "-//W3C//DTD XHTML 1.0 Transitional//EN"#define XHTML_TRANS_SYSTEM_ID BAD_CAST \ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
/** * xmlIsXHTML: * @systemID: the system identifier * @publicID: the public identifier * * Try to find if the document correspond to an XHTML DTD * * Returns 1 if true, 0 if not and -1 in case of error */intxmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) { if ((systemID == NULL) && (publicID == NULL)) return(-1); if (publicID != NULL) { if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1); if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1); if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1); } if (systemID != NULL) { if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1); if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1); if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1); } return(0);}
/************************************************************************ * * * Node callbacks * * * ************************************************************************/
/** * xmlRegisterNodeDefault: * @func: function pointer to the new RegisterNodeFunc * * Registers a callback for node creation * * Returns the old value of the registration function */xmlRegisterNodeFuncxmlRegisterNodeDefault(xmlRegisterNodeFunc func){ xmlRegisterNodeFunc old = xmlRegisterNodeDefaultValue;
__xmlRegisterCallbacks = 1; xmlRegisterNodeDefaultValue = func; return(old);}
/** * xmlDeregisterNodeDefault: * @func: function pointer to the new DeregisterNodeFunc * * Registers a callback for node destruction * * Returns the previous value of the deregistration function */xmlDeregisterNodeFuncxmlDeregisterNodeDefault(xmlDeregisterNodeFunc func){ xmlDeregisterNodeFunc old = xmlDeregisterNodeDefaultValue;
__xmlRegisterCallbacks = 1; xmlDeregisterNodeDefaultValue = func; return(old);}