Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960/* * valid.c : part of the code use to do the DTD handling and the validity * checking * * See Copyright for the status of this software. * * daniel@veillard.com */
#define IN_LIBXML#include "libxml.h"
#include <string.h>#include <stdlib.h>
#include <libxml/xmlmemory.h>#include <libxml/hash.h>#include <libxml/uri.h>#include <libxml/valid.h>#include <libxml/parser.h>#include <libxml/parserInternals.h>#include <libxml/xmlerror.h>#include <libxml/list.h>
#include "private/error.h"#include "private/parser.h"
static xmlElementPtrxmlGetDtdElementDesc2(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name, int create);
#define TODO \ xmlGenericError(xmlGenericErrorContext, \ "Unimplemented block at %s:%d\n", \ __FILE__, __LINE__);
#ifdef LIBXML_VALID_ENABLEDstatic intxmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type, const xmlChar *value);#endif/************************************************************************ * * * Error handling routines * * * ************************************************************************/
/** * xmlVErrMemory: * @ctxt: an XML validation parser context * @extra: extra information * * Handle an out of memory error */static voidxmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra){ xmlGenericErrorFunc channel = NULL; xmlParserCtxtPtr pctxt = NULL; void *data = NULL;
if (ctxt != NULL) { channel = ctxt->error; data = ctxt->userData; /* Look up flag to detect if it is part of a parsing context */ if (ctxt->flags & XML_VCTXT_USE_PCTXT) { pctxt = ctxt->userData; } } if (extra) __xmlRaiseError(NULL, channel, data, pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0, "Memory allocation failed : %s\n", extra); else __xmlRaiseError(NULL, channel, data, pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0, "Memory allocation failed\n");}
/** * xmlErrValid: * @ctxt: an XML validation parser context * @error: the error number * @extra: extra information * * Handle a validation error */static void LIBXML_ATTR_FORMAT(3,0)xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error, const char *msg, const char *extra){ xmlGenericErrorFunc channel = NULL; xmlParserCtxtPtr pctxt = NULL; void *data = NULL;
if (ctxt != NULL) { channel = ctxt->error; data = ctxt->userData; /* Look up flag to detect if it is part of a parsing context */ if (ctxt->flags & XML_VCTXT_USE_PCTXT) { pctxt = ctxt->userData; } } if (extra) __xmlRaiseError(NULL, channel, data, pctxt, NULL, XML_FROM_VALID, error, XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0, msg, extra); else __xmlRaiseError(NULL, channel, data, pctxt, NULL, XML_FROM_VALID, error, XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0, "%s", msg);}
#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)/** * xmlErrValidNode: * @ctxt: an XML validation parser context * @node: the node raising the error * @error: the error number * @str1: extra information * @str2: extra information * @str3: extra information * * Handle a validation error, provide contextual information */static void LIBXML_ATTR_FORMAT(4,0)xmlErrValidNode(xmlValidCtxtPtr ctxt, xmlNodePtr node, xmlParserErrors error, const char *msg, const xmlChar * str1, const xmlChar * str2, const xmlChar * str3){ xmlStructuredErrorFunc schannel = NULL; xmlGenericErrorFunc channel = NULL; xmlParserCtxtPtr pctxt = NULL; void *data = NULL;
if (ctxt != NULL) { channel = ctxt->error; data = ctxt->userData; /* Look up flag to detect if it is part of a parsing context */ if (ctxt->flags & XML_VCTXT_USE_PCTXT) { pctxt = ctxt->userData; } } __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error, XML_ERR_ERROR, NULL, 0, (const char *) str1, (const char *) str2, (const char *) str3, 0, 0, msg, str1, str2, str3);}#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
#ifdef LIBXML_VALID_ENABLED/** * xmlErrValidNodeNr: * @ctxt: an XML validation parser context * @node: the node raising the error * @error: the error number * @str1: extra information * @int2: extra information * @str3: extra information * * Handle a validation error, provide contextual information */static void LIBXML_ATTR_FORMAT(4,0)xmlErrValidNodeNr(xmlValidCtxtPtr ctxt, xmlNodePtr node, xmlParserErrors error, const char *msg, const xmlChar * str1, int int2, const xmlChar * str3){ xmlStructuredErrorFunc schannel = NULL; xmlGenericErrorFunc channel = NULL; xmlParserCtxtPtr pctxt = NULL; void *data = NULL;
if (ctxt != NULL) { channel = ctxt->error; data = ctxt->userData; /* Look up flag to detect if it is part of a parsing context */ if (ctxt->flags & XML_VCTXT_USE_PCTXT) { pctxt = ctxt->userData; } } __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error, XML_ERR_ERROR, NULL, 0, (const char *) str1, (const char *) str3, NULL, int2, 0, msg, str1, int2, str3);}
/** * xmlErrValidWarning: * @ctxt: an XML validation parser context * @node: the node raising the error * @error: the error number * @str1: extra information * @str2: extra information * @str3: extra information * * Handle a validation error, provide contextual information */static void LIBXML_ATTR_FORMAT(4,0)xmlErrValidWarning(xmlValidCtxtPtr ctxt, xmlNodePtr node, xmlParserErrors error, const char *msg, const xmlChar * str1, const xmlChar * str2, const xmlChar * str3){ xmlStructuredErrorFunc schannel = NULL; xmlGenericErrorFunc channel = NULL; xmlParserCtxtPtr pctxt = NULL; void *data = NULL;
if (ctxt != NULL) { channel = ctxt->warning; data = ctxt->userData; /* Look up flag to detect if it is part of a parsing context */ if (ctxt->flags & XML_VCTXT_USE_PCTXT) { pctxt = ctxt->userData; } } __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error, XML_ERR_WARNING, NULL, 0, (const char *) str1, (const char *) str2, (const char *) str3, 0, 0, msg, str1, str2, str3);}
#ifdef LIBXML_REGEXP_ENABLED/* * If regexp are enabled we can do continuous validation without the * need of a tree to validate the content model. this is done in each * callbacks. * Each xmlValidState represent the validation state associated to the * set of nodes currently open from the document root to the current element. */
typedef struct _xmlValidState { xmlElementPtr elemDecl; /* pointer to the content model */ xmlNodePtr node; /* pointer to the current node */ xmlRegExecCtxtPtr exec; /* regexp runtime */} _xmlValidState;
static intvstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) { if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) { ctxt->vstateMax = 10; ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); if (ctxt->vstateTab == NULL) { xmlVErrMemory(ctxt, "malloc failed"); return(-1); } }
if (ctxt->vstateNr >= ctxt->vstateMax) { xmlValidState *tmp;
tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab, 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); if (tmp == NULL) { xmlVErrMemory(ctxt, "realloc failed"); return(-1); } ctxt->vstateMax *= 2; ctxt->vstateTab = tmp; } ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr]; ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl; ctxt->vstateTab[ctxt->vstateNr].node = node; if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) { if (elemDecl->contModel == NULL) xmlValidBuildContentModel(ctxt, elemDecl); if (elemDecl->contModel != NULL) { ctxt->vstateTab[ctxt->vstateNr].exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL); } else { ctxt->vstateTab[ctxt->vstateNr].exec = NULL; xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl, XML_ERR_INTERNAL_ERROR, "Failed to build content model regexp for %s\n", node->name, NULL, NULL); } } return(ctxt->vstateNr++);}
static intvstateVPop(xmlValidCtxtPtr ctxt) { xmlElementPtr elemDecl;
if (ctxt->vstateNr < 1) return(-1); ctxt->vstateNr--; elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl; ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL; ctxt->vstateTab[ctxt->vstateNr].node = NULL; if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) { xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec); } ctxt->vstateTab[ctxt->vstateNr].exec = NULL; if (ctxt->vstateNr >= 1) ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1]; else ctxt->vstate = NULL; return(ctxt->vstateNr);}
#else /* not LIBXML_REGEXP_ENABLED *//* * If regexp are not enabled, it uses a home made algorithm less * complex and easier to * debug/maintain than a generic NFA -> DFA state based algo. The * only restriction is on the deepness of the tree limited by the * size of the occurs bitfield * * this is the content of a saved state for rollbacks */
#define ROLLBACK_OR 0#define ROLLBACK_PARENT 1
typedef struct _xmlValidState { xmlElementContentPtr cont; /* pointer to the content model subtree */ xmlNodePtr node; /* pointer to the current node in the list */ long occurs;/* bitfield for multiple occurrences */ unsigned char depth; /* current depth in the overall tree */ unsigned char state; /* ROLLBACK_XXX */} _xmlValidState;
#define MAX_RECURSE 25000#define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)#define CONT ctxt->vstate->cont#define NODE ctxt->vstate->node#define DEPTH ctxt->vstate->depth#define OCCURS ctxt->vstate->occurs#define STATE ctxt->vstate->state
#define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))#define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
#define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)#define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
static intvstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont, xmlNodePtr node, unsigned char depth, long occurs, unsigned char state) { int i = ctxt->vstateNr - 1;
if (ctxt->vstateNr > MAX_RECURSE) { return(-1); } if (ctxt->vstateTab == NULL) { ctxt->vstateMax = 8; ctxt->vstateTab = (xmlValidState *) xmlMalloc( ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); if (ctxt->vstateTab == NULL) { xmlVErrMemory(ctxt, "malloc failed"); return(-1); } } if (ctxt->vstateNr >= ctxt->vstateMax) { xmlValidState *tmp;
tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab, 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); if (tmp == NULL) { xmlVErrMemory(ctxt, "malloc failed"); return(-1); } ctxt->vstateMax *= 2; ctxt->vstateTab = tmp; ctxt->vstate = &ctxt->vstateTab[0]; } /* * Don't push on the stack a state already here */ if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) && (ctxt->vstateTab[i].node == node) && (ctxt->vstateTab[i].depth == depth) && (ctxt->vstateTab[i].occurs == occurs) && (ctxt->vstateTab[i].state == state)) return(ctxt->vstateNr); ctxt->vstateTab[ctxt->vstateNr].cont = cont; ctxt->vstateTab[ctxt->vstateNr].node = node; ctxt->vstateTab[ctxt->vstateNr].depth = depth; ctxt->vstateTab[ctxt->vstateNr].occurs = occurs; ctxt->vstateTab[ctxt->vstateNr].state = state; return(ctxt->vstateNr++);}
static intvstateVPop(xmlValidCtxtPtr ctxt) { if (ctxt->vstateNr <= 1) return(-1); ctxt->vstateNr--; ctxt->vstate = &ctxt->vstateTab[0]; ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont; ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node; ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth; ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs; ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state; return(ctxt->vstateNr);}
#endif /* LIBXML_REGEXP_ENABLED */
static intnodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value){ if (ctxt->nodeMax <= 0) { ctxt->nodeMax = 4; ctxt->nodeTab = (xmlNodePtr *) xmlMalloc(ctxt->nodeMax * sizeof(ctxt->nodeTab[0])); if (ctxt->nodeTab == NULL) { xmlVErrMemory(ctxt, "malloc failed"); ctxt->nodeMax = 0; return (0); } } if (ctxt->nodeNr >= ctxt->nodeMax) { xmlNodePtr *tmp; tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab, ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0])); if (tmp == NULL) { xmlVErrMemory(ctxt, "realloc failed"); return (0); } ctxt->nodeMax *= 2; ctxt->nodeTab = tmp; } ctxt->nodeTab[ctxt->nodeNr] = value; ctxt->node = value; return (ctxt->nodeNr++);}static xmlNodePtrnodeVPop(xmlValidCtxtPtr ctxt){ xmlNodePtr ret;
if (ctxt->nodeNr <= 0) return (NULL); ctxt->nodeNr--; if (ctxt->nodeNr > 0) ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1]; else ctxt->node = NULL; ret = ctxt->nodeTab[ctxt->nodeNr]; ctxt->nodeTab[ctxt->nodeNr] = NULL; return (ret);}
/* TODO: use hash table for accesses to elem and attribute definitions */
#define CHECK_DTD \ if (doc == NULL) return(0); \ else if ((doc->intSubset == NULL) && \ (doc->extSubset == NULL)) return(0)
#ifdef LIBXML_REGEXP_ENABLED
/************************************************************************ * * * Content model validation based on the regexps * * * ************************************************************************/
/** * xmlValidBuildAContentModel: * @content: the content model * @ctxt: the schema parser context * @name: the element name whose content is being built * * Generate the automata sequence needed for that type * * Returns 1 if successful or 0 in case of error. */static intxmlValidBuildAContentModel(xmlElementContentPtr content, xmlValidCtxtPtr ctxt, const xmlChar *name) { if (content == NULL) { xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR, "Found NULL content in content model of %s\n", name, NULL, NULL); return(0); } switch (content->type) { case XML_ELEMENT_CONTENT_PCDATA: xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR, "Found PCDATA in content model of %s\n", name, NULL, NULL); return(0); break; case XML_ELEMENT_CONTENT_ELEMENT: { xmlAutomataStatePtr oldstate = ctxt->state; xmlChar fn[50]; xmlChar *fullname;
fullname = xmlBuildQName(content->name, content->prefix, fn, 50); if (fullname == NULL) { xmlVErrMemory(ctxt, "Building content model"); return(0); }
switch (content->ocur) { case XML_ELEMENT_CONTENT_ONCE: ctxt->state = xmlAutomataNewTransition(ctxt->am, ctxt->state, NULL, fullname, NULL); break; case XML_ELEMENT_CONTENT_OPT: ctxt->state = xmlAutomataNewTransition(ctxt->am, ctxt->state, NULL, fullname, NULL); xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state); break; case XML_ELEMENT_CONTENT_PLUS: ctxt->state = xmlAutomataNewTransition(ctxt->am, ctxt->state, NULL, fullname, NULL); xmlAutomataNewTransition(ctxt->am, ctxt->state, ctxt->state, fullname, NULL); break; case XML_ELEMENT_CONTENT_MULT: ctxt->state = xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL); xmlAutomataNewTransition(ctxt->am, ctxt->state, ctxt->state, fullname, NULL); break; } if ((fullname != fn) && (fullname != content->name)) xmlFree(fullname); break; } case XML_ELEMENT_CONTENT_SEQ: { xmlAutomataStatePtr oldstate, oldend; xmlElementContentOccur ocur;
/* * Simply iterate over the content */ oldstate = ctxt->state; ocur = content->ocur; if (ocur != XML_ELEMENT_CONTENT_ONCE) { ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL); oldstate = ctxt->state; } do { xmlValidBuildAContentModel(content->c1, ctxt, name); content = content->c2; } while ((content->type == XML_ELEMENT_CONTENT_SEQ) && (content->ocur == XML_ELEMENT_CONTENT_ONCE)); xmlValidBuildAContentModel(content, ctxt, name); oldend = ctxt->state; ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL); switch (ocur) { case XML_ELEMENT_CONTENT_ONCE: break; case XML_ELEMENT_CONTENT_OPT: xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state); break; case XML_ELEMENT_CONTENT_MULT: xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state); xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate); break; case XML_ELEMENT_CONTENT_PLUS: xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate); break; } break; } case XML_ELEMENT_CONTENT_OR: { xmlAutomataStatePtr oldstate, oldend; xmlElementContentOccur ocur;
ocur = content->ocur; if ((ocur == XML_ELEMENT_CONTENT_PLUS) || (ocur == XML_ELEMENT_CONTENT_MULT)) { ctxt->state = xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL); } oldstate = ctxt->state; oldend = xmlAutomataNewState(ctxt->am);
/* * iterate over the subtypes and remerge the end with an * epsilon transition */ do { ctxt->state = oldstate; xmlValidBuildAContentModel(content->c1, ctxt, name); xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend); content = content->c2; } while ((content->type == XML_ELEMENT_CONTENT_OR) && (content->ocur == XML_ELEMENT_CONTENT_ONCE)); ctxt->state = oldstate; xmlValidBuildAContentModel(content, ctxt, name); xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend); ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL); switch (ocur) { case XML_ELEMENT_CONTENT_ONCE: break; case XML_ELEMENT_CONTENT_OPT: xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state); break; case XML_ELEMENT_CONTENT_MULT: xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state); xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate); break; case XML_ELEMENT_CONTENT_PLUS: xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate); break; } break; } default: xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, "ContentModel broken for element %s\n", (const char *) name); return(0); } return(1);}/** * xmlValidBuildContentModel: * @ctxt: a validation context * @elem: an element declaration node * * (Re)Build the automata associated to the content model of this * element * * Returns 1 in case of success, 0 in case of error */intxmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
if ((ctxt == NULL) || (elem == NULL)) return(0); if (elem->type != XML_ELEMENT_DECL) return(0); if (elem->etype != XML_ELEMENT_TYPE_ELEMENT) return(1); /* TODO: should we rebuild in this case ? */ if (elem->contModel != NULL) { if (!xmlRegexpIsDeterminist(elem->contModel)) { ctxt->valid = 0; return(0); } return(1); }
ctxt->am = xmlNewAutomata(); if (ctxt->am == NULL) { xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_ERR_INTERNAL_ERROR, "Cannot create automata for element %s\n", elem->name, NULL, NULL); return(0); } ctxt->state = xmlAutomataGetInitState(ctxt->am); xmlValidBuildAContentModel(elem->content, ctxt, elem->name); xmlAutomataSetFinalState(ctxt->am, ctxt->state); elem->contModel = xmlAutomataCompile(ctxt->am); if (xmlRegexpIsDeterminist(elem->contModel) != 1) { char expr[5000]; expr[0] = 0; xmlSnprintfElementContent(expr, 5000, elem->content, 1); xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_NOT_DETERMINIST, "Content model of %s is not deterministic: %s\n", elem->name, BAD_CAST expr, NULL); ctxt->valid = 0; ctxt->state = NULL; xmlFreeAutomata(ctxt->am); ctxt->am = NULL; return(0); } ctxt->state = NULL; xmlFreeAutomata(ctxt->am); ctxt->am = NULL; return(1);}
#endif /* LIBXML_REGEXP_ENABLED */
/**************************************************************** * * * Util functions for data allocation/deallocation * * * ****************************************************************/
/** * xmlNewValidCtxt: * * Allocate a validation context structure. * * Returns NULL if not, otherwise the new validation context structure */xmlValidCtxtPtr xmlNewValidCtxt(void) { xmlValidCtxtPtr ret;
if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) { xmlVErrMemory(NULL, "malloc failed"); return (NULL); }
(void) memset(ret, 0, sizeof (xmlValidCtxt));
return (ret);}
/** * xmlFreeValidCtxt: * @cur: the validation context to free * * Free a validation context structure. */voidxmlFreeValidCtxt(xmlValidCtxtPtr cur) { if (cur == NULL) return; if (cur->vstateTab != NULL) xmlFree(cur->vstateTab); if (cur->nodeTab != NULL) xmlFree(cur->nodeTab); xmlFree(cur);}
#endif /* LIBXML_VALID_ENABLED */
/** * xmlNewDocElementContent: * @doc: the document * @name: the subelement name or NULL * @type: the type of element content decl * * Allocate an element content structure for the document. * * Returns NULL if not, otherwise the new element content structure */xmlElementContentPtrxmlNewDocElementContent(xmlDocPtr doc, const xmlChar *name, xmlElementContentType type) { xmlElementContentPtr ret; xmlDictPtr dict = NULL;
if (doc != NULL) dict = doc->dict;
switch(type) { case XML_ELEMENT_CONTENT_ELEMENT: if (name == NULL) { xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, "xmlNewElementContent : name == NULL !\n", NULL); } break; case XML_ELEMENT_CONTENT_PCDATA: case XML_ELEMENT_CONTENT_SEQ: case XML_ELEMENT_CONTENT_OR: if (name != NULL) { xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, "xmlNewElementContent : name != NULL !\n", NULL); } break; default: xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, "Internal: ELEMENT content corrupted invalid type\n", NULL); return(NULL); } ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent)); if (ret == NULL) { xmlVErrMemory(NULL, "malloc failed"); return(NULL); } memset(ret, 0, sizeof(xmlElementContent)); ret->type = type; ret->ocur = XML_ELEMENT_CONTENT_ONCE; if (name != NULL) { int l; const xmlChar *tmp;
tmp = xmlSplitQName3(name, &l); if (tmp == NULL) { if (dict == NULL) ret->name = xmlStrdup(name); else ret->name = xmlDictLookup(dict, name, -1); } else { if (dict == NULL) { ret->prefix = xmlStrndup(name, l); ret->name = xmlStrdup(tmp); } else { ret->prefix = xmlDictLookup(dict, name, l); ret->name = xmlDictLookup(dict, tmp, -1); } } } return(ret);}
/** * xmlNewElementContent: * @name: the subelement name or NULL * @type: the type of element content decl * * Allocate an element content structure. * Deprecated in favor of xmlNewDocElementContent * * Returns NULL if not, otherwise the new element content structure */xmlElementContentPtrxmlNewElementContent(const xmlChar *name, xmlElementContentType type) { return(xmlNewDocElementContent(NULL, name, type));}
/** * xmlCopyDocElementContent: * @doc: the document owning the element declaration * @cur: An element content pointer. * * Build a copy of an element content description. * * Returns the new xmlElementContentPtr or NULL in case of error. */xmlElementContentPtrxmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) { xmlElementContentPtr ret = NULL, prev = NULL, tmp; xmlDictPtr dict = NULL;
if (cur == NULL) return(NULL);
if (doc != NULL) dict = doc->dict;
ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent)); if (ret == NULL) { xmlVErrMemory(NULL, "malloc failed"); return(NULL); } memset(ret, 0, sizeof(xmlElementContent)); ret->type = cur->type; ret->ocur = cur->ocur; if (cur->name != NULL) { if (dict) ret->name = xmlDictLookup(dict, cur->name, -1); else ret->name = xmlStrdup(cur->name); }
if (cur->prefix != NULL) { if (dict) ret->prefix = xmlDictLookup(dict, cur->prefix, -1); else ret->prefix = xmlStrdup(cur->prefix); } if (cur->c1 != NULL) ret->c1 = xmlCopyDocElementContent(doc, cur->c1); if (ret->c1 != NULL) ret->c1->parent = ret; if (cur->c2 != NULL) { prev = ret; cur = cur->c2; while (cur != NULL) { tmp = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent)); if (tmp == NULL) { xmlVErrMemory(NULL, "malloc failed"); return(ret); } memset(tmp, 0, sizeof(xmlElementContent)); tmp->type = cur->type; tmp->ocur = cur->ocur; prev->c2 = tmp; tmp->parent = prev; if (cur->name != NULL) { if (dict) tmp->name = xmlDictLookup(dict, cur->name, -1); else tmp->name = xmlStrdup(cur->name); }
if (cur->prefix != NULL) { if (dict) tmp->prefix = xmlDictLookup(dict, cur->prefix, -1); else tmp->prefix = xmlStrdup(cur->prefix); } if (cur->c1 != NULL) tmp->c1 = xmlCopyDocElementContent(doc,cur->c1); if (tmp->c1 != NULL) tmp->c1->parent = tmp; prev = tmp; cur = cur->c2; } } return(ret);}
/** * xmlCopyElementContent: * @cur: An element content pointer. * * Build a copy of an element content description. * Deprecated, use xmlCopyDocElementContent instead * * Returns the new xmlElementContentPtr or NULL in case of error. */xmlElementContentPtrxmlCopyElementContent(xmlElementContentPtr cur) { return(xmlCopyDocElementContent(NULL, cur));}
/** * xmlFreeDocElementContent: * @doc: the document owning the element declaration * @cur: the element content tree to free * * Free an element content structure. The whole subtree is removed. */voidxmlFreeDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) { xmlDictPtr dict = NULL; size_t depth = 0;
if (cur == NULL) return; if (doc != NULL) dict = doc->dict;
while (1) { xmlElementContentPtr parent;
while ((cur->c1 != NULL) || (cur->c2 != NULL)) { cur = (cur->c1 != NULL) ? cur->c1 : cur->c2; depth += 1; }
switch (cur->type) { case XML_ELEMENT_CONTENT_PCDATA: case XML_ELEMENT_CONTENT_ELEMENT: case XML_ELEMENT_CONTENT_SEQ: case XML_ELEMENT_CONTENT_OR: break; default: xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, "Internal: ELEMENT content corrupted invalid type\n", NULL); return; } if (dict) { if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name))) xmlFree((xmlChar *) cur->name); if ((cur->prefix != NULL) && (!xmlDictOwns(dict, cur->prefix))) xmlFree((xmlChar *) cur->prefix); } else { if (cur->name != NULL) xmlFree((xmlChar *) cur->name); if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix); } parent = cur->parent; if ((depth == 0) || (parent == NULL)) { xmlFree(cur); break; } if (cur == parent->c1) parent->c1 = NULL; else parent->c2 = NULL; xmlFree(cur);
if (parent->c2 != NULL) { cur = parent->c2; } else { depth -= 1; cur = parent; } }}
/** * xmlFreeElementContent: * @cur: the element content tree to free * * Free an element content structure. The whole subtree is removed. * Deprecated, use xmlFreeDocElementContent instead */voidxmlFreeElementContent(xmlElementContentPtr cur) { xmlFreeDocElementContent(NULL, cur);}
#ifdef LIBXML_OUTPUT_ENABLED/** * xmlDumpElementOccur: * @buf: An XML buffer * @cur: An element table * * Dump the occurrence operator of an element. */static voidxmlDumpElementOccur(xmlBufferPtr buf, xmlElementContentPtr cur) { switch (cur->ocur) { case XML_ELEMENT_CONTENT_ONCE: break; case XML_ELEMENT_CONTENT_OPT: xmlBufferWriteChar(buf, "?"); break; case XML_ELEMENT_CONTENT_MULT: xmlBufferWriteChar(buf, "*"); break; case XML_ELEMENT_CONTENT_PLUS: xmlBufferWriteChar(buf, "+"); break; }}
/** * xmlDumpElementContent: * @buf: An XML buffer * @content: An element table * * This will dump the content of the element table as an XML DTD definition */static voidxmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content) { xmlElementContentPtr cur;
if (content == NULL) return;
xmlBufferWriteChar(buf, "("); cur = content;
do { if (cur == NULL) return;
switch (cur->type) { case XML_ELEMENT_CONTENT_PCDATA: xmlBufferWriteChar(buf, "#PCDATA"); break; case XML_ELEMENT_CONTENT_ELEMENT: if (cur->prefix != NULL) { xmlBufferWriteCHAR(buf, cur->prefix); xmlBufferWriteChar(buf, ":"); } xmlBufferWriteCHAR(buf, cur->name); break; case XML_ELEMENT_CONTENT_SEQ: case XML_ELEMENT_CONTENT_OR: if ((cur != content) && (cur->parent != NULL) && ((cur->type != cur->parent->type) || (cur->ocur != XML_ELEMENT_CONTENT_ONCE))) xmlBufferWriteChar(buf, "("); cur = cur->c1; continue; default: xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, "Internal: ELEMENT cur corrupted invalid type\n", NULL); }
while (cur != content) { xmlElementContentPtr parent = cur->parent;
if (parent == NULL) return;
if (((cur->type == XML_ELEMENT_CONTENT_OR) || (cur->type == XML_ELEMENT_CONTENT_SEQ)) && ((cur->type != parent->type) || (cur->ocur != XML_ELEMENT_CONTENT_ONCE))) xmlBufferWriteChar(buf, ")"); xmlDumpElementOccur(buf, cur);
if (cur == parent->c1) { if (parent->type == XML_ELEMENT_CONTENT_SEQ) xmlBufferWriteChar(buf, " , "); else if (parent->type == XML_ELEMENT_CONTENT_OR) xmlBufferWriteChar(buf, " | ");
cur = parent->c2; break; }
cur = parent; } } while (cur != content);
xmlBufferWriteChar(buf, ")"); xmlDumpElementOccur(buf, content);}
/** * xmlSprintfElementContent: * @buf: an output buffer * @content: An element table * @englob: 1 if one must print the englobing parenthesis, 0 otherwise * * Deprecated, unsafe, use xmlSnprintfElementContent */voidxmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED, xmlElementContentPtr content ATTRIBUTE_UNUSED, int englob ATTRIBUTE_UNUSED) {}#endif /* LIBXML_OUTPUT_ENABLED */
/** * xmlSnprintfElementContent: * @buf: an output buffer * @size: the buffer size * @content: An element table * @englob: 1 if one must print the englobing parenthesis, 0 otherwise * * This will dump the content of the element content definition * Intended just for the debug routine */voidxmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int englob) { int len;
if (content == NULL) return; len = strlen(buf); if (size - len < 50) { if ((size - len > 4) && (buf[len - 1] != '.')) strcat(buf, " ..."); return; } if (englob) strcat(buf, "("); switch (content->type) { case XML_ELEMENT_CONTENT_PCDATA: strcat(buf, "#PCDATA"); break; case XML_ELEMENT_CONTENT_ELEMENT: { int qnameLen = xmlStrlen(content->name);
if (content->prefix != NULL) qnameLen += xmlStrlen(content->prefix) + 1; if (size - len < qnameLen + 10) { strcat(buf, " ..."); return; } if (content->prefix != NULL) { strcat(buf, (char *) content->prefix); strcat(buf, ":"); } if (content->name != NULL) strcat(buf, (char *) content->name); break; } case XML_ELEMENT_CONTENT_SEQ: if ((content->c1->type == XML_ELEMENT_CONTENT_OR) || (content->c1->type == XML_ELEMENT_CONTENT_SEQ)) xmlSnprintfElementContent(buf, size, content->c1, 1); else xmlSnprintfElementContent(buf, size, content->c1, 0); len = strlen(buf); if (size - len < 50) { if ((size - len > 4) && (buf[len - 1] != '.')) strcat(buf, " ..."); return; } strcat(buf, " , "); if (((content->c2->type == XML_ELEMENT_CONTENT_OR) || (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) && (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT)) xmlSnprintfElementContent(buf, size, content->c2, 1); else xmlSnprintfElementContent(buf, size, content->c2, 0); break; case XML_ELEMENT_CONTENT_OR: if ((content->c1->type == XML_ELEMENT_CONTENT_OR) || (content->c1->type == XML_ELEMENT_CONTENT_SEQ)) xmlSnprintfElementContent(buf, size, content->c1, 1); else xmlSnprintfElementContent(buf, size, content->c1, 0); len = strlen(buf); if (size - len < 50) { if ((size - len > 4) && (buf[len - 1] != '.')) strcat(buf, " ..."); return; } strcat(buf, " | "); if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) || (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) && (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT)) xmlSnprintfElementContent(buf, size, content->c2, 1); else xmlSnprintfElementContent(buf, size, content->c2, 0); break; } if (size - strlen(buf) <= 2) return; if (englob) strcat(buf, ")"); switch (content->ocur) { case XML_ELEMENT_CONTENT_ONCE: break; case XML_ELEMENT_CONTENT_OPT: strcat(buf, "?"); break; case XML_ELEMENT_CONTENT_MULT: strcat(buf, "*"); break; case XML_ELEMENT_CONTENT_PLUS: strcat(buf, "+"); break; }}
/**************************************************************** * * * Registration of DTD declarations * * * ****************************************************************/
/** * xmlFreeElement: * @elem: An element * * Deallocate the memory used by an element definition */static voidxmlFreeElement(xmlElementPtr elem) { if (elem == NULL) return; xmlUnlinkNode((xmlNodePtr) elem); xmlFreeDocElementContent(elem->doc, elem->content); if (elem->name != NULL) xmlFree((xmlChar *) elem->name); if (elem->prefix != NULL) xmlFree((xmlChar *) elem->prefix);#ifdef LIBXML_REGEXP_ENABLED if (elem->contModel != NULL) xmlRegFreeRegexp(elem->contModel);#endif xmlFree(elem);}
/** * xmlAddElementDecl: * @ctxt: the validation context * @dtd: pointer to the DTD * @name: the entity name * @type: the element type * @content: the element content tree or NULL * * Register a new element declaration * * Returns NULL if not, otherwise the entity */xmlElementPtrxmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name, xmlElementTypeVal type, xmlElementContentPtr content) { xmlElementPtr ret; xmlElementTablePtr table; xmlAttributePtr oldAttributes = NULL; xmlChar *ns, *uqname;
if (dtd == NULL) { return(NULL); } if (name == NULL) { return(NULL); }
switch (type) { case XML_ELEMENT_TYPE_EMPTY: if (content != NULL) { xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, "xmlAddElementDecl: content != NULL for EMPTY\n", NULL); return(NULL); } break; case XML_ELEMENT_TYPE_ANY: if (content != NULL) { xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, "xmlAddElementDecl: content != NULL for ANY\n", NULL); return(NULL); } break; case XML_ELEMENT_TYPE_MIXED: if (content == NULL) { xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, "xmlAddElementDecl: content == NULL for MIXED\n", NULL); return(NULL); } break; case XML_ELEMENT_TYPE_ELEMENT: if (content == NULL) { xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, "xmlAddElementDecl: content == NULL for ELEMENT\n", NULL); return(NULL); } break; default: xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, "Internal: ELEMENT decl corrupted invalid type\n", NULL); return(NULL); }
/* * check if name is a QName */ uqname = xmlSplitQName2(name, &ns); if (uqname != NULL) name = uqname;
/* * Create the Element table if needed. */ table = (xmlElementTablePtr) dtd->elements; if (table == NULL) { xmlDictPtr dict = NULL;
if (dtd->doc != NULL) dict = dtd->doc->dict; table = xmlHashCreateDict(0, dict); dtd->elements = (void *) table; } if (table == NULL) { xmlVErrMemory(ctxt, "xmlAddElementDecl: Table creation failed!\n"); if (uqname != NULL) xmlFree(uqname); if (ns != NULL) xmlFree(ns); return(NULL); }
/* * lookup old attributes inserted on an undefined element in the * internal subset. */ if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) { ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns); if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) { oldAttributes = ret->attributes; ret->attributes = NULL; xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL); xmlFreeElement(ret); } }
/* * The element may already be present if one of its attribute * was registered first */ ret = xmlHashLookup2(table, name, ns); if (ret != NULL) { if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {#ifdef LIBXML_VALID_ENABLED /* * The element is already defined in this DTD. */ xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED, "Redefinition of element %s\n", name, NULL, NULL);#endif /* LIBXML_VALID_ENABLED */ if (uqname != NULL) xmlFree(uqname); if (ns != NULL) xmlFree(ns); return(NULL); } if (ns != NULL) { xmlFree(ns); ns = NULL; } } else { ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement)); if (ret == NULL) { xmlVErrMemory(ctxt, "malloc failed"); if (uqname != NULL) xmlFree(uqname); if (ns != NULL) xmlFree(ns); return(NULL); } memset(ret, 0, sizeof(xmlElement)); ret->type = XML_ELEMENT_DECL;
/* * fill the structure. */ ret->name = xmlStrdup(name); if (ret->name == NULL) { xmlVErrMemory(ctxt, "malloc failed"); if (uqname != NULL) xmlFree(uqname); if (ns != NULL) xmlFree(ns); xmlFree(ret); return(NULL); } ret->prefix = ns;
/* * Validity Check: * Insertion must not fail */ if (xmlHashAddEntry2(table, name, ns, ret)) {#ifdef LIBXML_VALID_ENABLED /* * The element is already defined in this DTD. */ xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED, "Redefinition of element %s\n", name, NULL, NULL);#endif /* LIBXML_VALID_ENABLED */ xmlFreeElement(ret); if (uqname != NULL) xmlFree(uqname); return(NULL); } /* * For new element, may have attributes from earlier * definition in internal subset */ ret->attributes = oldAttributes; }
/* * Finish to fill the structure. */ ret->etype = type; /* * Avoid a stupid copy when called by the parser * and flag it by setting a special parent value * so the parser doesn't unallocate it. */ if ((ctxt != NULL) && (ctxt->flags & XML_VCTXT_USE_PCTXT)) { ret->content = content; if (content != NULL) content->parent = (xmlElementContentPtr) 1; } else { ret->content = xmlCopyDocElementContent(dtd->doc, content); }
/* * Link it to the DTD */ ret->parent = dtd; ret->doc = dtd->doc; if (dtd->last == NULL) { dtd->children = dtd->last = (xmlNodePtr) ret; } else { dtd->last->next = (xmlNodePtr) ret; ret->prev = dtd->last; dtd->last = (xmlNodePtr) ret; } if (uqname != NULL) xmlFree(uqname); return(ret);}
static voidxmlFreeElementTableEntry(void *elem, const xmlChar *name ATTRIBUTE_UNUSED) { xmlFreeElement((xmlElementPtr) elem);}
/** * xmlFreeElementTable: * @table: An element table * * Deallocate the memory used by an element hash table. */voidxmlFreeElementTable(xmlElementTablePtr table) { xmlHashFree(table, xmlFreeElementTableEntry);}
#ifdef LIBXML_TREE_ENABLED/** * xmlCopyElement: * @elem: An element * * Build a copy of an element. * * Returns the new xmlElementPtr or NULL in case of error. */static void *xmlCopyElement(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { xmlElementPtr elem = (xmlElementPtr) payload; xmlElementPtr cur;
cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement)); if (cur == NULL) { xmlVErrMemory(NULL, "malloc failed"); return(NULL); } memset(cur, 0, sizeof(xmlElement)); cur->type = XML_ELEMENT_DECL; cur->etype = elem->etype; if (elem->name != NULL) cur->name = xmlStrdup(elem->name); else cur->name = NULL; if (elem->prefix != NULL) cur->prefix = xmlStrdup(elem->prefix); else cur->prefix = NULL; cur->content = xmlCopyElementContent(elem->content); /* TODO : rebuild the attribute list on the copy */ cur->attributes = NULL; return(cur);}
/** * xmlCopyElementTable: * @table: An element table * * Build a copy of an element table. * * Returns the new xmlElementTablePtr or NULL in case of error. */xmlElementTablePtrxmlCopyElementTable(xmlElementTablePtr table) { return((xmlElementTablePtr) xmlHashCopy(table, xmlCopyElement));}#endif /* LIBXML_TREE_ENABLED */
#ifdef LIBXML_OUTPUT_ENABLED/** * xmlDumpElementDecl: * @buf: the XML buffer output * @elem: An element table * * This will dump the content of the element declaration as an XML * DTD definition */voidxmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) { if ((buf == NULL) || (elem == NULL)) return; switch (elem->etype) { case XML_ELEMENT_TYPE_EMPTY: xmlBufferWriteChar(buf, "<!ELEMENT "); if (elem->prefix != NULL) { xmlBufferWriteCHAR(buf, elem->prefix); xmlBufferWriteChar(buf, ":"); } xmlBufferWriteCHAR(buf, elem->name); xmlBufferWriteChar(buf, " EMPTY>\n"); break; case XML_ELEMENT_TYPE_ANY: xmlBufferWriteChar(buf, "<!ELEMENT "); if (elem->prefix != NULL) { xmlBufferWriteCHAR(buf, elem->prefix); xmlBufferWriteChar(buf, ":"); } xmlBufferWriteCHAR(buf, elem->name); xmlBufferWriteChar(buf, " ANY>\n"); break; case XML_ELEMENT_TYPE_MIXED: xmlBufferWriteChar(buf, "<!ELEMENT "); if (elem->prefix != NULL) { xmlBufferWriteCHAR(buf, elem->prefix); xmlBufferWriteChar(buf, ":"); } xmlBufferWriteCHAR(buf, elem->name); xmlBufferWriteChar(buf, " "); xmlDumpElementContent(buf, elem->content); xmlBufferWriteChar(buf, ">\n"); break; case XML_ELEMENT_TYPE_ELEMENT: xmlBufferWriteChar(buf, "<!ELEMENT "); if (elem->prefix != NULL) { xmlBufferWriteCHAR(buf, elem->prefix); xmlBufferWriteChar(buf, ":"); } xmlBufferWriteCHAR(buf, elem->name); xmlBufferWriteChar(buf, " "); xmlDumpElementContent(buf, elem->content); xmlBufferWriteChar(buf, ">\n"); break; default: xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, "Internal: ELEMENT struct corrupted invalid type\n", NULL); }}
/** * xmlDumpElementDeclScan: * @elem: An element table * @buf: the XML buffer output * * This routine is used by the hash scan function. It just reverses * the arguments. */static voidxmlDumpElementDeclScan(void *elem, void *buf, const xmlChar *name ATTRIBUTE_UNUSED) { xmlDumpElementDecl((xmlBufferPtr) buf, (xmlElementPtr) elem);}
/** * xmlDumpElementTable: * @buf: the XML buffer output * @table: An element table * * This will dump the content of the element table as an XML DTD definition */voidxmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) { if ((buf == NULL) || (table == NULL)) return; xmlHashScan(table, xmlDumpElementDeclScan, buf);}#endif /* LIBXML_OUTPUT_ENABLED */
/** * xmlCreateEnumeration: * @name: the enumeration name or NULL * * create and initialize an enumeration attribute node. * * Returns the xmlEnumerationPtr just created or NULL in case * of error. */xmlEnumerationPtrxmlCreateEnumeration(const xmlChar *name) { xmlEnumerationPtr ret;
ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration)); if (ret == NULL) { xmlVErrMemory(NULL, "malloc failed"); return(NULL); } memset(ret, 0, sizeof(xmlEnumeration));
if (name != NULL) ret->name = xmlStrdup(name); return(ret);}
/** * xmlFreeEnumeration: * @cur: the tree to free. * * free an enumeration attribute node (recursive). */voidxmlFreeEnumeration(xmlEnumerationPtr cur) { if (cur == NULL) return;
if (cur->next != NULL) xmlFreeEnumeration(cur->next);
if (cur->name != NULL) xmlFree((xmlChar *) cur->name); xmlFree(cur);}
#ifdef LIBXML_TREE_ENABLED/** * xmlCopyEnumeration: * @cur: the tree to copy. * * Copy an enumeration attribute node (recursive). * * Returns the xmlEnumerationPtr just created or NULL in case * of error. */xmlEnumerationPtrxmlCopyEnumeration(xmlEnumerationPtr cur) { xmlEnumerationPtr ret;
if (cur == NULL) return(NULL); ret = xmlCreateEnumeration((xmlChar *) cur->name); if (ret == NULL) return(NULL);
if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next); else ret->next = NULL;
return(ret);}#endif /* LIBXML_TREE_ENABLED */
#ifdef LIBXML_OUTPUT_ENABLED/** * xmlDumpEnumeration: * @buf: the XML buffer output * @enum: An enumeration * * This will dump the content of the enumeration */static voidxmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) { if ((buf == NULL) || (cur == NULL)) return;
xmlBufferWriteCHAR(buf, cur->name); if (cur->next == NULL) xmlBufferWriteChar(buf, ")"); else { xmlBufferWriteChar(buf, " | "); xmlDumpEnumeration(buf, cur->next); }}#endif /* LIBXML_OUTPUT_ENABLED */
#ifdef LIBXML_VALID_ENABLED/** * xmlScanIDAttributeDecl: * @ctxt: the validation context * @elem: the element name * @err: whether to raise errors here * * Verify that the element don't have too many ID attributes * declared. * * Returns the number of ID attributes found. */static intxmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem, int err) { xmlAttributePtr cur; int ret = 0;
if (elem == NULL) return(0); cur = elem->attributes; while (cur != NULL) { if (cur->atype == XML_ATTRIBUTE_ID) { ret ++; if ((ret > 1) && (err)) xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID, "Element %s has too many ID attributes defined : %s\n", elem->name, cur->name, NULL); } cur = cur->nexth; } return(ret);}#endif /* LIBXML_VALID_ENABLED */
/** * xmlFreeAttribute: * @elem: An attribute * * Deallocate the memory used by an attribute definition */static voidxmlFreeAttribute(xmlAttributePtr attr) { xmlDictPtr dict;
if (attr == NULL) return; if (attr->doc != NULL) dict = attr->doc->dict; else dict = NULL; xmlUnlinkNode((xmlNodePtr) attr); if (attr->tree != NULL) xmlFreeEnumeration(attr->tree); if (dict) { if ((attr->elem != NULL) && (!xmlDictOwns(dict, attr->elem))) xmlFree((xmlChar *) attr->elem); if ((attr->name != NULL) && (!xmlDictOwns(dict, attr->name))) xmlFree((xmlChar *) attr->name); if ((attr->prefix != NULL) && (!xmlDictOwns(dict, attr->prefix))) xmlFree((xmlChar *) attr->prefix); if ((attr->defaultValue != NULL) && (!xmlDictOwns(dict, attr->defaultValue))) xmlFree((xmlChar *) attr->defaultValue); } else { if (attr->elem != NULL) xmlFree((xmlChar *) attr->elem); if (attr->name != NULL) xmlFree((xmlChar *) attr->name); if (attr->defaultValue != NULL) xmlFree((xmlChar *) attr->defaultValue); if (attr->prefix != NULL) xmlFree((xmlChar *) attr->prefix); } xmlFree(attr);}
/** * xmlAddAttributeDecl: * @ctxt: the validation context * @dtd: pointer to the DTD * @elem: the element name * @name: the attribute name * @ns: the attribute namespace prefix * @type: the attribute type * @def: the attribute default type * @defaultValue: the attribute default value * @tree: if it's an enumeration, the associated list * * Register a new attribute declaration * Note that @tree becomes the ownership of the DTD * * Returns NULL if not new, otherwise the attribute decl */xmlAttributePtrxmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name, const xmlChar *ns, xmlAttributeType type, xmlAttributeDefault def, const xmlChar *defaultValue, xmlEnumerationPtr tree) { xmlAttributePtr ret; xmlAttributeTablePtr table; xmlElementPtr elemDef; xmlDictPtr dict = NULL;
if (dtd == NULL) { xmlFreeEnumeration(tree); return(NULL); } if (name == NULL) { xmlFreeEnumeration(tree); return(NULL); } if (elem == NULL) { xmlFreeEnumeration(tree); return(NULL); } if (dtd->doc != NULL) dict = dtd->doc->dict;
#ifdef LIBXML_VALID_ENABLED /* * Check the type and possibly the default value. */ switch (type) { case XML_ATTRIBUTE_CDATA: break; case XML_ATTRIBUTE_ID: break; case XML_ATTRIBUTE_IDREF: break; case XML_ATTRIBUTE_IDREFS: break; case XML_ATTRIBUTE_ENTITY: break; case XML_ATTRIBUTE_ENTITIES: break; case XML_ATTRIBUTE_NMTOKEN: break; case XML_ATTRIBUTE_NMTOKENS: break; case XML_ATTRIBUTE_ENUMERATION: break; case XML_ATTRIBUTE_NOTATION: break; default: xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, "Internal: ATTRIBUTE struct corrupted invalid type\n", NULL); xmlFreeEnumeration(tree); return(NULL); } if ((defaultValue != NULL) && (!xmlValidateAttributeValueInternal(dtd->doc, type, defaultValue))) { xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT, "Attribute %s of %s: invalid default value\n", elem, name, defaultValue); defaultValue = NULL; if (ctxt != NULL) ctxt->valid = 0; }#endif /* LIBXML_VALID_ENABLED */
/* * Check first that an attribute defined in the external subset wasn't * already defined in the internal subset */ if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) && (dtd->doc->intSubset != NULL) && (dtd->doc->intSubset->attributes != NULL)) { ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem); if (ret != NULL) { xmlFreeEnumeration(tree); return(NULL); } }
/* * Create the Attribute table if needed. */ table = (xmlAttributeTablePtr) dtd->attributes; if (table == NULL) { table = xmlHashCreateDict(0, dict); dtd->attributes = (void *) table; } if (table == NULL) { xmlVErrMemory(ctxt, "xmlAddAttributeDecl: Table creation failed!\n"); xmlFreeEnumeration(tree); return(NULL); }
ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute)); if (ret == NULL) { xmlVErrMemory(ctxt, "malloc failed"); xmlFreeEnumeration(tree); return(NULL); } memset(ret, 0, sizeof(xmlAttribute)); ret->type = XML_ATTRIBUTE_DECL;
/* * fill the structure. */ ret->atype = type; /* * doc must be set before possible error causes call * to xmlFreeAttribute (because it's used to check on * dict use) */ ret->doc = dtd->doc; if (dict) { ret->name = xmlDictLookup(dict, name, -1); ret->prefix = xmlDictLookup(dict, ns, -1); ret->elem = xmlDictLookup(dict, elem, -1); } else { ret->name = xmlStrdup(name); ret->prefix = xmlStrdup(ns); ret->elem = xmlStrdup(elem); } ret->def = def; ret->tree = tree; if (defaultValue != NULL) { if (dict) ret->defaultValue = xmlDictLookup(dict, defaultValue, -1); else ret->defaultValue = xmlStrdup(defaultValue); }
/* * Validity Check: * Search the DTD for previous declarations of the ATTLIST */ if (xmlHashAddEntry3(table, ret->name, ret->prefix, ret->elem, ret) < 0) {#ifdef LIBXML_VALID_ENABLED /* * The attribute is already defined in this DTD. */ xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED, "Attribute %s of element %s: already defined\n", name, elem, NULL);#endif /* LIBXML_VALID_ENABLED */ xmlFreeAttribute(ret); return(NULL); }
/* * Validity Check: * Multiple ID per element */ elemDef = xmlGetDtdElementDesc2(ctxt, dtd, elem, 1); if (elemDef != NULL) {
#ifdef LIBXML_VALID_ENABLED if ((type == XML_ATTRIBUTE_ID) && (xmlScanIDAttributeDecl(NULL, elemDef, 1) != 0)) { xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID, "Element %s has too may ID attributes defined : %s\n", elem, name, NULL); if (ctxt != NULL) ctxt->valid = 0; }#endif /* LIBXML_VALID_ENABLED */
/* * Insert namespace default def first they need to be * processed first. */ if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) || ((ret->prefix != NULL && (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) { ret->nexth = elemDef->attributes; elemDef->attributes = ret; } else { xmlAttributePtr tmp = elemDef->attributes;
while ((tmp != NULL) && ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) || ((ret->prefix != NULL && (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) { if (tmp->nexth == NULL) break; tmp = tmp->nexth; } if (tmp != NULL) { ret->nexth = tmp->nexth; tmp->nexth = ret; } else { ret->nexth = elemDef->attributes; elemDef->attributes = ret; } } }
/* * Link it to the DTD */ ret->parent = dtd; if (dtd->last == NULL) { dtd->children = dtd->last = (xmlNodePtr) ret; } else { dtd->last->next = (xmlNodePtr) ret; ret->prev = dtd->last; dtd->last = (xmlNodePtr) ret; } return(ret);}
static voidxmlFreeAttributeTableEntry(void *attr, const xmlChar *name ATTRIBUTE_UNUSED) { xmlFreeAttribute((xmlAttributePtr) attr);}
/** * xmlFreeAttributeTable: * @table: An attribute table * * Deallocate the memory used by an entities hash table. */voidxmlFreeAttributeTable(xmlAttributeTablePtr table) { xmlHashFree(table, xmlFreeAttributeTableEntry);}
#ifdef LIBXML_TREE_ENABLED/** * xmlCopyAttribute: * @attr: An attribute * * Build a copy of an attribute. * * Returns the new xmlAttributePtr or NULL in case of error. */static void *xmlCopyAttribute(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { xmlAttributePtr attr = (xmlAttributePtr) payload; xmlAttributePtr cur;
cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute)); if (cur == NULL) { xmlVErrMemory(NULL, "malloc failed"); return(NULL); } memset(cur, 0, sizeof(xmlAttribute)); cur->type = XML_ATTRIBUTE_DECL; cur->atype = attr->atype; cur->def = attr->def; cur->tree = xmlCopyEnumeration(attr->tree); if (attr->elem != NULL) cur->elem = xmlStrdup(attr->elem); if (attr->name != NULL) cur->name = xmlStrdup(attr->name); if (attr->prefix != NULL) cur->prefix = xmlStrdup(attr->prefix); if (attr->defaultValue != NULL) cur->defaultValue = xmlStrdup(attr->defaultValue); return(cur);}
/** * xmlCopyAttributeTable: * @table: An attribute table * * Build a copy of an attribute table. * * Returns the new xmlAttributeTablePtr or NULL in case of error. */xmlAttributeTablePtrxmlCopyAttributeTable(xmlAttributeTablePtr table) { return((xmlAttributeTablePtr) xmlHashCopy(table, xmlCopyAttribute));}#endif /* LIBXML_TREE_ENABLED */
#ifdef LIBXML_OUTPUT_ENABLED/** * xmlDumpAttributeDecl: * @buf: the XML buffer output * @attr: An attribute declaration * * This will dump the content of the attribute declaration as an XML * DTD definition */voidxmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) { if ((buf == NULL) || (attr == NULL)) return; xmlBufferWriteChar(buf, "<!ATTLIST "); xmlBufferWriteCHAR(buf, attr->elem); xmlBufferWriteChar(buf, " "); if (attr->prefix != NULL) { xmlBufferWriteCHAR(buf, attr->prefix); xmlBufferWriteChar(buf, ":"); } xmlBufferWriteCHAR(buf, attr->name); switch (attr->atype) { case XML_ATTRIBUTE_CDATA: xmlBufferWriteChar(buf, " CDATA"); break; case XML_ATTRIBUTE_ID: xmlBufferWriteChar(buf, " ID"); break; case XML_ATTRIBUTE_IDREF: xmlBufferWriteChar(buf, " IDREF"); break; case XML_ATTRIBUTE_IDREFS: xmlBufferWriteChar(buf, " IDREFS"); break; case XML_ATTRIBUTE_ENTITY: xmlBufferWriteChar(buf, " ENTITY"); break; case XML_ATTRIBUTE_ENTITIES: xmlBufferWriteChar(buf, " ENTITIES"); break; case XML_ATTRIBUTE_NMTOKEN: xmlBufferWriteChar(buf, " NMTOKEN"); break; case XML_ATTRIBUTE_NMTOKENS: xmlBufferWriteChar(buf, " NMTOKENS"); break; case XML_ATTRIBUTE_ENUMERATION: xmlBufferWriteChar(buf, " ("); xmlDumpEnumeration(buf, attr->tree); break; case XML_ATTRIBUTE_NOTATION: xmlBufferWriteChar(buf, " NOTATION ("); xmlDumpEnumeration(buf, attr->tree); break; default: xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, "Internal: ATTRIBUTE struct corrupted invalid type\n", NULL); } switch (attr->def) { case XML_ATTRIBUTE_NONE: break; case XML_ATTRIBUTE_REQUIRED: xmlBufferWriteChar(buf, " #REQUIRED"); break; case XML_ATTRIBUTE_IMPLIED: xmlBufferWriteChar(buf, " #IMPLIED"); break; case XML_ATTRIBUTE_FIXED: xmlBufferWriteChar(buf, " #FIXED"); break; default: xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, "Internal: ATTRIBUTE struct corrupted invalid def\n", NULL); } if (attr->defaultValue != NULL) { xmlBufferWriteChar(buf, " "); xmlBufferWriteQuotedString(buf, attr->defaultValue); } xmlBufferWriteChar(buf, ">\n");}
/** * xmlDumpAttributeDeclScan: * @attr: An attribute declaration * @buf: the XML buffer output * * This is used with the hash scan function - just reverses arguments */static voidxmlDumpAttributeDeclScan(void *attr, void *buf, const xmlChar *name ATTRIBUTE_UNUSED) { xmlDumpAttributeDecl((xmlBufferPtr) buf, (xmlAttributePtr) attr);}
/** * xmlDumpAttributeTable: * @buf: the XML buffer output * @table: An attribute table * * This will dump the content of the attribute table as an XML DTD definition */voidxmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) { if ((buf == NULL) || (table == NULL)) return; xmlHashScan(table, xmlDumpAttributeDeclScan, buf);}#endif /* LIBXML_OUTPUT_ENABLED */
/************************************************************************ * * * NOTATIONs * * * ************************************************************************//** * xmlFreeNotation: * @not: A notation * * Deallocate the memory used by an notation definition */static voidxmlFreeNotation(xmlNotationPtr nota) { if (nota == NULL) return; if (nota->name != NULL) xmlFree((xmlChar *) nota->name); if (nota->PublicID != NULL) xmlFree((xmlChar *) nota->PublicID); if (nota->SystemID != NULL) xmlFree((xmlChar *) nota->SystemID); xmlFree(nota);}
/** * xmlAddNotationDecl: * @dtd: pointer to the DTD * @ctxt: the validation context * @name: the entity name * @PublicID: the public identifier or NULL * @SystemID: the system identifier or NULL * * Register a new notation declaration * * Returns NULL if not, otherwise the entity */xmlNotationPtrxmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name, const xmlChar *PublicID, const xmlChar *SystemID) { xmlNotationPtr ret; xmlNotationTablePtr table;
if (dtd == NULL) { return(NULL); } if (name == NULL) { return(NULL); } if ((PublicID == NULL) && (SystemID == NULL)) { return(NULL); }
/* * Create the Notation table if needed. */ table = (xmlNotationTablePtr) dtd->notations; if (table == NULL) { xmlDictPtr dict = NULL; if (dtd->doc != NULL) dict = dtd->doc->dict;
dtd->notations = table = xmlHashCreateDict(0, dict); } if (table == NULL) { xmlVErrMemory(ctxt, "xmlAddNotationDecl: Table creation failed!\n"); return(NULL); }
ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation)); if (ret == NULL) { xmlVErrMemory(ctxt, "malloc failed"); return(NULL); } memset(ret, 0, sizeof(xmlNotation));
/* * fill the structure. */ ret->name = xmlStrdup(name); if (SystemID != NULL) ret->SystemID = xmlStrdup(SystemID); if (PublicID != NULL) ret->PublicID = xmlStrdup(PublicID);
/* * Validity Check: * Check the DTD for previous declarations of the ATTLIST */ if (xmlHashAddEntry(table, name, ret)) {#ifdef LIBXML_VALID_ENABLED xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED, "xmlAddNotationDecl: %s already defined\n", (const char *) name);#endif /* LIBXML_VALID_ENABLED */ xmlFreeNotation(ret); return(NULL); } return(ret);}
static voidxmlFreeNotationTableEntry(void *nota, const xmlChar *name ATTRIBUTE_UNUSED) { xmlFreeNotation((xmlNotationPtr) nota);}
/** * xmlFreeNotationTable: * @table: An notation table * * Deallocate the memory used by an entities hash table. */voidxmlFreeNotationTable(xmlNotationTablePtr table) { xmlHashFree(table, xmlFreeNotationTableEntry);}
#ifdef LIBXML_TREE_ENABLED/** * xmlCopyNotation: * @nota: A notation * * Build a copy of a notation. * * Returns the new xmlNotationPtr or NULL in case of error. */static void *xmlCopyNotation(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { xmlNotationPtr nota = (xmlNotationPtr) payload; xmlNotationPtr cur;
cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation)); if (cur == NULL) { xmlVErrMemory(NULL, "malloc failed"); return(NULL); } if (nota->name != NULL) cur->name = xmlStrdup(nota->name); else cur->name = NULL; if (nota->PublicID != NULL) cur->PublicID = xmlStrdup(nota->PublicID); else cur->PublicID = NULL; if (nota->SystemID != NULL) cur->SystemID = xmlStrdup(nota->SystemID); else cur->SystemID = NULL; return(cur);}
/** * xmlCopyNotationTable: * @table: A notation table * * Build a copy of a notation table. * * Returns the new xmlNotationTablePtr or NULL in case of error. */xmlNotationTablePtrxmlCopyNotationTable(xmlNotationTablePtr table) { return((xmlNotationTablePtr) xmlHashCopy(table, xmlCopyNotation));}#endif /* LIBXML_TREE_ENABLED */
#ifdef LIBXML_OUTPUT_ENABLED/** * xmlDumpNotationDecl: * @buf: the XML buffer output * @nota: A notation declaration * * This will dump the content the notation declaration as an XML DTD definition */voidxmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) { if ((buf == NULL) || (nota == NULL)) return; xmlBufferWriteChar(buf, "<!NOTATION "); xmlBufferWriteCHAR(buf, nota->name); if (nota->PublicID != NULL) { xmlBufferWriteChar(buf, " PUBLIC "); xmlBufferWriteQuotedString(buf, nota->PublicID); if (nota->SystemID != NULL) { xmlBufferWriteChar(buf, " "); xmlBufferWriteQuotedString(buf, nota->SystemID); } } else { xmlBufferWriteChar(buf, " SYSTEM "); xmlBufferWriteQuotedString(buf, nota->SystemID); } xmlBufferWriteChar(buf, " >\n");}
/** * xmlDumpNotationDeclScan: * @nota: A notation declaration * @buf: the XML buffer output * * This is called with the hash scan function, and just reverses args */static voidxmlDumpNotationDeclScan(void *nota, void *buf, const xmlChar *name ATTRIBUTE_UNUSED) { xmlDumpNotationDecl((xmlBufferPtr) buf, (xmlNotationPtr) nota);}
/** * xmlDumpNotationTable: * @buf: the XML buffer output * @table: A notation table * * This will dump the content of the notation table as an XML DTD definition */voidxmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) { if ((buf == NULL) || (table == NULL)) return; xmlHashScan(table, xmlDumpNotationDeclScan, buf);}#endif /* LIBXML_OUTPUT_ENABLED */
/************************************************************************ * * * IDs * * * ************************************************************************//** * 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));
/** * xmlValidNormalizeString: * @str: a string * * Normalize a string in-place. */static voidxmlValidNormalizeString(xmlChar *str) { xmlChar *dst; const xmlChar *src;
if (str == NULL) return; src = str; dst = str;
while (*src == 0x20) src++; while (*src != 0) { if (*src == 0x20) { while (*src == 0x20) src++; if (*src != 0) *dst++ = 0x20; } else { *dst++ = *src++; } } *dst = 0;}
static intxmlIsStreaming(xmlValidCtxtPtr ctxt) { xmlParserCtxtPtr pctxt;
if (ctxt == NULL) return(0); if ((ctxt->flags & XML_VCTXT_USE_PCTXT) == 0) return(0); pctxt = ctxt->userData; return(pctxt->parseMode == XML_PARSE_READER);}
/** * xmlFreeID: * @not: A id * * Deallocate the memory used by an id definition */static voidxmlFreeID(xmlIDPtr id) { xmlDictPtr dict = NULL;
if (id == NULL) return;
if (id->doc != NULL) dict = id->doc->dict;
if (id->value != NULL) DICT_FREE(id->value) if (id->name != NULL) DICT_FREE(id->name) xmlFree(id);}
/** * xmlAddID: * @ctxt: the validation context * @doc: pointer to the document * @value: the value name * @attr: the attribute holding the ID * * Register a new id declaration * * Returns NULL if not, otherwise the new xmlIDPtr */xmlIDPtrxmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value, xmlAttrPtr attr) { xmlIDPtr ret; xmlIDTablePtr table;
if (doc == NULL) { return(NULL); } if ((value == NULL) || (value[0] == 0)) { return(NULL); } if (attr == NULL) { return(NULL); }
/* * Create the ID table if needed. */ table = (xmlIDTablePtr) doc->ids; if (table == NULL) { doc->ids = table = xmlHashCreateDict(0, doc->dict); } if (table == NULL) { xmlVErrMemory(ctxt, "xmlAddID: Table creation failed!\n"); return(NULL); }
ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID)); if (ret == NULL) { xmlVErrMemory(ctxt, "malloc failed"); return(NULL); }
/* * fill the structure. */ ret->value = xmlStrdup(value); ret->doc = doc; if (xmlIsStreaming(ctxt)) { /* * Operating in streaming mode, attr is gonna disappear */ if (doc->dict != NULL) ret->name = xmlDictLookup(doc->dict, attr->name, -1); else ret->name = xmlStrdup(attr->name); ret->attr = NULL; } else { ret->attr = attr; ret->name = NULL; } ret->lineno = xmlGetLineNo(attr->parent);
if (xmlHashAddEntry(table, value, ret) < 0) {#ifdef LIBXML_VALID_ENABLED /* * The id is already defined in this DTD. */ if (ctxt != NULL) { xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED, "ID %s already defined\n", value, NULL, NULL); }#endif /* LIBXML_VALID_ENABLED */ xmlFreeID(ret); return(NULL); } if (attr != NULL) attr->atype = XML_ATTRIBUTE_ID; return(ret);}
static voidxmlFreeIDTableEntry(void *id, const xmlChar *name ATTRIBUTE_UNUSED) { xmlFreeID((xmlIDPtr) id);}
/** * xmlFreeIDTable: * @table: An id table * * Deallocate the memory used by an ID hash table. */voidxmlFreeIDTable(xmlIDTablePtr table) { xmlHashFree(table, xmlFreeIDTableEntry);}
/** * xmlIsID: * @doc: the document * @elem: the element carrying the attribute * @attr: the attribute * * Determine whether an attribute is of type ID. In case we have DTD(s) * then this is done if DTD loading has been requested. In the case * of HTML documents parsed with the HTML parser, then ID detection is * done systematically. * * Returns 0 or 1 depending on the lookup result */intxmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) { if ((attr == NULL) || (attr->name == NULL)) return(0); if ((attr->ns != NULL) && (attr->ns->prefix != NULL) && (!strcmp((char *) attr->name, "id")) && (!strcmp((char *) attr->ns->prefix, "xml"))) return(1); if (doc == NULL) return(0); if ((doc->intSubset == NULL) && (doc->extSubset == NULL) && (doc->type != XML_HTML_DOCUMENT_NODE)) { return(0); } else if (doc->type == XML_HTML_DOCUMENT_NODE) { if ((xmlStrEqual(BAD_CAST "id", attr->name)) || ((xmlStrEqual(BAD_CAST "name", attr->name)) && ((elem == NULL) || (xmlStrEqual(elem->name, BAD_CAST "a"))))) return(1); return(0); } else if (elem == NULL) { return(0); } else { xmlAttributePtr attrDecl = NULL;
xmlChar felem[50], fattr[50]; xmlChar *fullelemname, *fullattrname;
fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ? xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) : (xmlChar *)elem->name;
fullattrname = (attr->ns != NULL && attr->ns->prefix != NULL) ? xmlBuildQName(attr->name, attr->ns->prefix, fattr, 50) : (xmlChar *)attr->name;
if (fullelemname != NULL && fullattrname != NULL) { attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullelemname, fullattrname); if ((attrDecl == NULL) && (doc->extSubset != NULL)) attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullelemname, fullattrname); }
if ((fullattrname != fattr) && (fullattrname != attr->name)) xmlFree(fullattrname); if ((fullelemname != felem) && (fullelemname != elem->name)) xmlFree(fullelemname);
if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID)) return(1); } return(0);}
/** * xmlRemoveID: * @doc: the document * @attr: the attribute * * Remove the given attribute from the ID table maintained internally. * * Returns -1 if the lookup failed and 0 otherwise */intxmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) { xmlIDTablePtr table; xmlIDPtr id; xmlChar *ID;
if (doc == NULL) return(-1); if (attr == NULL) return(-1);
table = (xmlIDTablePtr) doc->ids; if (table == NULL) return(-1);
ID = xmlNodeListGetString(doc, attr->children, 1); if (ID == NULL) return(-1); xmlValidNormalizeString(ID);
id = xmlHashLookup(table, ID); if (id == NULL || id->attr != attr) { xmlFree(ID); return(-1); }
xmlHashRemoveEntry(table, ID, xmlFreeIDTableEntry); xmlFree(ID); attr->atype = 0; return(0);}
/** * xmlGetID: * @doc: pointer to the document * @ID: the ID value * * Search the attribute declaring the given ID * * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID */xmlAttrPtrxmlGetID(xmlDocPtr doc, const xmlChar *ID) { xmlIDTablePtr table; xmlIDPtr id;
if (doc == NULL) { return(NULL); }
if (ID == NULL) { return(NULL); }
table = (xmlIDTablePtr) doc->ids; if (table == NULL) return(NULL);
id = xmlHashLookup(table, ID); if (id == NULL) return(NULL); if (id->attr == NULL) { /* * We are operating on a stream, return a well known reference * since the attribute node doesn't exist anymore */ return((xmlAttrPtr) doc); } return(id->attr);}
/************************************************************************ * * * Refs * * * ************************************************************************/typedef struct xmlRemoveMemo_t{ xmlListPtr l; xmlAttrPtr ap;} xmlRemoveMemo;
typedef xmlRemoveMemo *xmlRemoveMemoPtr;
typedef struct xmlValidateMemo_t{ xmlValidCtxtPtr ctxt; const xmlChar *name;} xmlValidateMemo;
typedef xmlValidateMemo *xmlValidateMemoPtr;
/** * xmlFreeRef: * @lk: A list link * * Deallocate the memory used by a ref definition */static voidxmlFreeRef(xmlLinkPtr lk) { xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk); if (ref == NULL) return; if (ref->value != NULL) xmlFree((xmlChar *)ref->value); if (ref->name != NULL) xmlFree((xmlChar *)ref->name); xmlFree(ref);}
/** * xmlFreeRefTableEntry: * @list_ref: A list of references. * * Deallocate the memory used by a list of references */static voidxmlFreeRefTableEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { xmlListPtr list_ref = (xmlListPtr) payload; if (list_ref == NULL) return; xmlListDelete(list_ref);}
/** * xmlWalkRemoveRef: * @data: Contents of current link * @user: Value supplied by the user * * Returns 0 to abort the walk or 1 to continue */static intxmlWalkRemoveRef(const void *data, void *user){ xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr; xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap; xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
if (attr0 == attr1) { /* Matched: remove and terminate walk */ xmlListRemoveFirst(ref_list, (void *)data); return 0; } return 1;}
/** * xmlDummyCompare * @data0: Value supplied by the user * @data1: Value supplied by the user * * Do nothing, return 0. Used to create unordered lists. */static intxmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED, const void *data1 ATTRIBUTE_UNUSED){ return (0);}
/** * xmlAddRef: * @ctxt: the validation context * @doc: pointer to the document * @value: the value name * @attr: the attribute holding the Ref * * DEPRECATED, do not use. This function will be removed from the public API. * * Register a new ref declaration * * Returns NULL if not, otherwise the new xmlRefPtr */xmlRefPtrxmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value, xmlAttrPtr attr) { xmlRefPtr ret; xmlRefTablePtr table; xmlListPtr ref_list;
if (doc == NULL) { return(NULL); } if (value == NULL) { return(NULL); } if (attr == NULL) { return(NULL); }
/* * Create the Ref table if needed. */ table = (xmlRefTablePtr) doc->refs; if (table == NULL) { doc->refs = table = xmlHashCreateDict(0, doc->dict); } if (table == NULL) { xmlVErrMemory(ctxt, "xmlAddRef: Table creation failed!\n"); return(NULL); }
ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef)); if (ret == NULL) { xmlVErrMemory(ctxt, "malloc failed"); return(NULL); }
/* * fill the structure. */ ret->value = xmlStrdup(value); if (xmlIsStreaming(ctxt)) { /* * Operating in streaming mode, attr is gonna disappear */ ret->name = xmlStrdup(attr->name); ret->attr = NULL; } else { ret->name = NULL; ret->attr = attr; } ret->lineno = xmlGetLineNo(attr->parent);
/* To add a reference :- * References are maintained as a list of references, * Lookup the entry, if no entry create new nodelist * Add the owning node to the NodeList * Return the ref */
if (NULL == (ref_list = xmlHashLookup(table, value))) { if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) { xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, "xmlAddRef: Reference list creation failed!\n", NULL); goto failed; } if (xmlHashAddEntry(table, value, ref_list) < 0) { xmlListDelete(ref_list); xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, "xmlAddRef: Reference list insertion failed!\n", NULL); goto failed; } } if (xmlListAppend(ref_list, ret) != 0) { xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, "xmlAddRef: Reference list insertion failed!\n", NULL); goto failed; } return(ret);failed: if (ret != NULL) { if (ret->value != NULL) xmlFree((char *)ret->value); if (ret->name != NULL) xmlFree((char *)ret->name); xmlFree(ret); } return(NULL);}
/** * xmlFreeRefTable: * @table: An ref table * * DEPRECATED, do not use. This function will be removed from the public API. * * Deallocate the memory used by an Ref hash table. */voidxmlFreeRefTable(xmlRefTablePtr table) { xmlHashFree(table, xmlFreeRefTableEntry);}
/** * xmlIsRef: * @doc: the document * @elem: the element carrying the attribute * @attr: the attribute * * DEPRECATED, do not use. This function will be removed from the public API. * * Determine whether an attribute is of type Ref. In case we have DTD(s) * then this is simple, otherwise we use an heuristic: name Ref (upper * or lowercase). * * Returns 0 or 1 depending on the lookup result */intxmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) { if (attr == NULL) return(0); if (doc == NULL) { doc = attr->doc; if (doc == NULL) return(0); }
if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) { return(0); } else if (doc->type == XML_HTML_DOCUMENT_NODE) { /* TODO @@@ */ return(0); } else { xmlAttributePtr attrDecl;
if (elem == NULL) return(0); attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name); if ((attrDecl == NULL) && (doc->extSubset != NULL)) attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, attr->name);
if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_IDREF || attrDecl->atype == XML_ATTRIBUTE_IDREFS)) return(1); } return(0);}
/** * xmlRemoveRef: * @doc: the document * @attr: the attribute * * DEPRECATED, do not use. This function will be removed from the public API. * * Remove the given attribute from the Ref table maintained internally. * * Returns -1 if the lookup failed and 0 otherwise */intxmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) { xmlListPtr ref_list; xmlRefTablePtr table; xmlChar *ID; xmlRemoveMemo target;
if (doc == NULL) return(-1); if (attr == NULL) return(-1);
table = (xmlRefTablePtr) doc->refs; if (table == NULL) return(-1);
ID = xmlNodeListGetString(doc, attr->children, 1); if (ID == NULL) return(-1);
ref_list = xmlHashLookup(table, ID); if(ref_list == NULL) { xmlFree(ID); return (-1); }
/* At this point, ref_list refers to a list of references which * have the same key as the supplied attr. Our list of references * is ordered by reference address and we don't have that information * here to use when removing. We'll have to walk the list and * check for a matching attribute, when we find one stop the walk * and remove the entry. * The list is ordered by reference, so that means we don't have the * key. Passing the list and the reference to the walker means we * will have enough data to be able to remove the entry. */ target.l = ref_list; target.ap = attr;
/* Remove the supplied attr from our list */ xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
/*If the list is empty then remove the list entry in the hash */ if (xmlListEmpty(ref_list)) xmlHashUpdateEntry(table, ID, NULL, xmlFreeRefTableEntry); xmlFree(ID); return(0);}
/** * xmlGetRefs: * @doc: pointer to the document * @ID: the ID value * * DEPRECATED, do not use. This function will be removed from the public API. * * Find the set of references for the supplied ID. * * Returns NULL if not found, otherwise node set for the ID. */xmlListPtrxmlGetRefs(xmlDocPtr doc, const xmlChar *ID) { xmlRefTablePtr table;
if (doc == NULL) { return(NULL); }
if (ID == NULL) { return(NULL); }
table = (xmlRefTablePtr) doc->refs; if (table == NULL) return(NULL);
return (xmlHashLookup(table, ID));}
/************************************************************************ * * * Routines for validity checking * * * ************************************************************************/
/** * xmlGetDtdElementDesc: * @dtd: a pointer to the DtD to search * @name: the element name * * Search the DTD for the description of this element * * returns the xmlElementPtr if found or NULL */
xmlElementPtrxmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) { xmlElementTablePtr table; xmlElementPtr cur; xmlChar *uqname = NULL, *prefix = NULL;
if ((dtd == NULL) || (name == NULL)) return(NULL); if (dtd->elements == NULL) return(NULL); table = (xmlElementTablePtr) dtd->elements;
uqname = xmlSplitQName2(name, &prefix); if (uqname != NULL) name = uqname; cur = xmlHashLookup2(table, name, prefix); if (prefix != NULL) xmlFree(prefix); if (uqname != NULL) xmlFree(uqname); return(cur);}/** * xmlGetDtdElementDesc2: * @dtd: a pointer to the DtD to search * @name: the element name * @create: create an empty description if not found * * Search the DTD for the description of this element * * returns the xmlElementPtr if found or NULL */
static xmlElementPtrxmlGetDtdElementDesc2(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name, int create) { xmlElementTablePtr table; xmlElementPtr cur; xmlChar *uqname = NULL, *prefix = NULL;
if (dtd == NULL) return(NULL); if (dtd->elements == NULL) { xmlDictPtr dict = NULL;
if (dtd->doc != NULL) dict = dtd->doc->dict;
if (!create) return(NULL); /* * Create the Element table if needed. */ table = (xmlElementTablePtr) dtd->elements; if (table == NULL) { table = xmlHashCreateDict(0, dict); dtd->elements = (void *) table; } if (table == NULL) { xmlVErrMemory(ctxt, "element table allocation failed"); return(NULL); } } table = (xmlElementTablePtr) dtd->elements;
uqname = xmlSplitQName2(name, &prefix); if (uqname != NULL) name = uqname; cur = xmlHashLookup2(table, name, prefix); if ((cur == NULL) && (create)) { cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement)); if (cur == NULL) { xmlVErrMemory(ctxt, "malloc failed"); goto error; } memset(cur, 0, sizeof(xmlElement)); cur->type = XML_ELEMENT_DECL;
/* * fill the structure. */ cur->name = xmlStrdup(name); cur->prefix = xmlStrdup(prefix); cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
if (xmlHashAddEntry2(table, name, prefix, cur) < 0) { xmlVErrMemory(ctxt, "adding entry failed"); xmlFreeElement(cur); cur = NULL; } }error: if (prefix != NULL) xmlFree(prefix); if (uqname != NULL) xmlFree(uqname); return(cur);}
/** * xmlGetDtdQElementDesc: * @dtd: a pointer to the DtD to search * @name: the element name * @prefix: the element namespace prefix * * Search the DTD for the description of this element * * returns the xmlElementPtr if found or NULL */
xmlElementPtrxmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name, const xmlChar *prefix) { xmlElementTablePtr table;
if (dtd == NULL) return(NULL); if (dtd->elements == NULL) return(NULL); table = (xmlElementTablePtr) dtd->elements;
return(xmlHashLookup2(table, name, prefix));}
/** * xmlGetDtdAttrDesc: * @dtd: a pointer to the DtD to search * @elem: the element name * @name: the attribute name * * Search the DTD for the description of this attribute on * this element. * * returns the xmlAttributePtr if found or NULL */
xmlAttributePtrxmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) { xmlAttributeTablePtr table; xmlAttributePtr cur; xmlChar *uqname = NULL, *prefix = NULL;
if (dtd == NULL) return(NULL); if (dtd->attributes == NULL) return(NULL);
table = (xmlAttributeTablePtr) dtd->attributes; if (table == NULL) return(NULL);
uqname = xmlSplitQName2(name, &prefix);
if (uqname != NULL) { cur = xmlHashLookup3(table, uqname, prefix, elem); if (prefix != NULL) xmlFree(prefix); if (uqname != NULL) xmlFree(uqname); } else cur = xmlHashLookup3(table, name, NULL, elem); return(cur);}
/** * xmlGetDtdQAttrDesc: * @dtd: a pointer to the DtD to search * @elem: the element name * @name: the attribute name * @prefix: the attribute namespace prefix * * Search the DTD for the description of this qualified attribute on * this element. * * returns the xmlAttributePtr if found or NULL */
xmlAttributePtrxmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name, const xmlChar *prefix) { xmlAttributeTablePtr table;
if (dtd == NULL) return(NULL); if (dtd->attributes == NULL) return(NULL); table = (xmlAttributeTablePtr) dtd->attributes;
return(xmlHashLookup3(table, name, prefix, elem));}
/** * xmlGetDtdNotationDesc: * @dtd: a pointer to the DtD to search * @name: the notation name * * Search the DTD for the description of this notation * * returns the xmlNotationPtr if found or NULL */
xmlNotationPtrxmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) { xmlNotationTablePtr table;
if (dtd == NULL) return(NULL); if (dtd->notations == NULL) return(NULL); table = (xmlNotationTablePtr) dtd->notations;
return(xmlHashLookup(table, name));}
#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)/** * xmlValidateNotationUse: * @ctxt: the validation context * @doc: the document * @notationName: the notation name to check * * Validate that the given name match a notation declaration. * - [ VC: Notation Declared ] * * returns 1 if valid or 0 otherwise */
intxmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *notationName) { xmlNotationPtr notaDecl; if ((doc == NULL) || (doc->intSubset == NULL) || (notationName == NULL)) return(-1);
notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName); if ((notaDecl == NULL) && (doc->extSubset != NULL)) notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
if ((notaDecl == NULL) && (ctxt != NULL)) { xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION, "NOTATION %s is not declared\n", notationName, NULL, NULL); return(0); } return(1);}#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
/** * xmlIsMixedElement: * @doc: the document * @name: the element name * * Search in the DtDs whether an element accept Mixed content (or ANY) * basically if it is supposed to accept text childs * * returns 0 if no, 1 if yes, and -1 if no element description is available */
intxmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) { xmlElementPtr elemDecl;
if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
elemDecl = xmlGetDtdElementDesc(doc->intSubset, name); if ((elemDecl == NULL) && (doc->extSubset != NULL)) elemDecl = xmlGetDtdElementDesc(doc->extSubset, name); if (elemDecl == NULL) return(-1); switch (elemDecl->etype) { case XML_ELEMENT_TYPE_UNDEFINED: return(-1); case XML_ELEMENT_TYPE_ELEMENT: return(0); case XML_ELEMENT_TYPE_EMPTY: /* * return 1 for EMPTY since we want VC error to pop up * on <empty> </empty> for example */ case XML_ELEMENT_TYPE_ANY: case XML_ELEMENT_TYPE_MIXED: return(1); } return(1);}
#ifdef LIBXML_VALID_ENABLED
static intxmlIsDocNameStartChar(xmlDocPtr doc, int c) { if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) { /* * Use the new checks of production [4] [4a] amd [5] of the * Update 5 of XML-1.0 */ if (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) || (c == '_') || (c == ':') || ((c >= 0xC0) && (c <= 0xD6)) || ((c >= 0xD8) && (c <= 0xF6)) || ((c >= 0xF8) && (c <= 0x2FF)) || ((c >= 0x370) && (c <= 0x37D)) || ((c >= 0x37F) && (c <= 0x1FFF)) || ((c >= 0x200C) && (c <= 0x200D)) || ((c >= 0x2070) && (c <= 0x218F)) || ((c >= 0x2C00) && (c <= 0x2FEF)) || ((c >= 0x3001) && (c <= 0xD7FF)) || ((c >= 0xF900) && (c <= 0xFDCF)) || ((c >= 0xFDF0) && (c <= 0xFFFD)) || ((c >= 0x10000) && (c <= 0xEFFFF))) return(1); } else { if (IS_LETTER(c) || (c == '_') || (c == ':')) return(1); } return(0);}
static intxmlIsDocNameChar(xmlDocPtr doc, int c) { if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) { /* * Use the new checks of production [4] [4a] amd [5] of the * Update 5 of XML-1.0 */ if (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) || ((c >= '0') && (c <= '9')) || /* !start */ (c == '_') || (c == ':') || (c == '-') || (c == '.') || (c == 0xB7) || /* !start */ ((c >= 0xC0) && (c <= 0xD6)) || ((c >= 0xD8) && (c <= 0xF6)) || ((c >= 0xF8) && (c <= 0x2FF)) || ((c >= 0x300) && (c <= 0x36F)) || /* !start */ ((c >= 0x370) && (c <= 0x37D)) || ((c >= 0x37F) && (c <= 0x1FFF)) || ((c >= 0x200C) && (c <= 0x200D)) || ((c >= 0x203F) && (c <= 0x2040)) || /* !start */ ((c >= 0x2070) && (c <= 0x218F)) || ((c >= 0x2C00) && (c <= 0x2FEF)) || ((c >= 0x3001) && (c <= 0xD7FF)) || ((c >= 0xF900) && (c <= 0xFDCF)) || ((c >= 0xFDF0) && (c <= 0xFFFD)) || ((c >= 0x10000) && (c <= 0xEFFFF))) return(1); } else { if ((IS_LETTER(c)) || (IS_DIGIT(c)) || (c == '.') || (c == '-') || (c == '_') || (c == ':') || (IS_COMBINING(c)) || (IS_EXTENDER(c))) return(1); } return(0);}
/** * xmlValidateNameValue: * @doc: pointer to the document or NULL * @value: an Name value * * Validate that the given value match Name production * * returns 1 if valid or 0 otherwise */
static intxmlValidateNameValueInternal(xmlDocPtr doc, const xmlChar *value) { const xmlChar *cur; int val, len;
if (value == NULL) return(0); cur = value; val = xmlStringCurrentChar(NULL, cur, &len); cur += len; if (!xmlIsDocNameStartChar(doc, val)) return(0);
val = xmlStringCurrentChar(NULL, cur, &len); cur += len; while (xmlIsDocNameChar(doc, val)) { val = xmlStringCurrentChar(NULL, cur, &len); cur += len; }
if (val != 0) return(0);
return(1);}
/** * xmlValidateNameValue: * @value: an Name value * * Validate that the given value match Name production * * returns 1 if valid or 0 otherwise */
intxmlValidateNameValue(const xmlChar *value) { return(xmlValidateNameValueInternal(NULL, value));}
/** * xmlValidateNamesValueInternal: * @doc: pointer to the document or NULL * @value: an Names value * * Validate that the given value match Names production * * returns 1 if valid or 0 otherwise */
static intxmlValidateNamesValueInternal(xmlDocPtr doc, const xmlChar *value) { const xmlChar *cur; int val, len;
if (value == NULL) return(0); cur = value; val = xmlStringCurrentChar(NULL, cur, &len); cur += len;
if (!xmlIsDocNameStartChar(doc, val)) return(0);
val = xmlStringCurrentChar(NULL, cur, &len); cur += len; while (xmlIsDocNameChar(doc, val)) { val = xmlStringCurrentChar(NULL, cur, &len); cur += len; }
/* Should not test IS_BLANK(val) here -- see erratum E20*/ while (val == 0x20) { while (val == 0x20) { val = xmlStringCurrentChar(NULL, cur, &len); cur += len; }
if (!xmlIsDocNameStartChar(doc, val)) return(0);
val = xmlStringCurrentChar(NULL, cur, &len); cur += len;
while (xmlIsDocNameChar(doc, val)) { val = xmlStringCurrentChar(NULL, cur, &len); cur += len; } }
if (val != 0) return(0);
return(1);}
/** * xmlValidateNamesValue: * @value: an Names value * * Validate that the given value match Names production * * returns 1 if valid or 0 otherwise */
intxmlValidateNamesValue(const xmlChar *value) { return(xmlValidateNamesValueInternal(NULL, value));}
/** * xmlValidateNmtokenValueInternal: * @doc: pointer to the document or NULL * @value: an Nmtoken value * * Validate that the given value match Nmtoken production * * [ VC: Name Token ] * * returns 1 if valid or 0 otherwise */
static intxmlValidateNmtokenValueInternal(xmlDocPtr doc, const xmlChar *value) { const xmlChar *cur; int val, len;
if (value == NULL) return(0); cur = value; val = xmlStringCurrentChar(NULL, cur, &len); cur += len;
if (!xmlIsDocNameChar(doc, val)) return(0);
val = xmlStringCurrentChar(NULL, cur, &len); cur += len; while (xmlIsDocNameChar(doc, val)) { val = xmlStringCurrentChar(NULL, cur, &len); cur += len; }
if (val != 0) return(0);
return(1);}
/** * xmlValidateNmtokenValue: * @value: an Nmtoken value * * Validate that the given value match Nmtoken production * * [ VC: Name Token ] * * returns 1 if valid or 0 otherwise */
intxmlValidateNmtokenValue(const xmlChar *value) { return(xmlValidateNmtokenValueInternal(NULL, value));}
/** * xmlValidateNmtokensValueInternal: * @doc: pointer to the document or NULL * @value: an Nmtokens value * * Validate that the given value match Nmtokens production * * [ VC: Name Token ] * * returns 1 if valid or 0 otherwise */
static intxmlValidateNmtokensValueInternal(xmlDocPtr doc, const xmlChar *value) { const xmlChar *cur; int val, len;
if (value == NULL) return(0); cur = value; val = xmlStringCurrentChar(NULL, cur, &len); cur += len;
while (IS_BLANK(val)) { val = xmlStringCurrentChar(NULL, cur, &len); cur += len; }
if (!xmlIsDocNameChar(doc, val)) return(0);
while (xmlIsDocNameChar(doc, val)) { val = xmlStringCurrentChar(NULL, cur, &len); cur += len; }
/* Should not test IS_BLANK(val) here -- see erratum E20*/ while (val == 0x20) { while (val == 0x20) { val = xmlStringCurrentChar(NULL, cur, &len); cur += len; } if (val == 0) return(1);
if (!xmlIsDocNameChar(doc, val)) return(0);
val = xmlStringCurrentChar(NULL, cur, &len); cur += len;
while (xmlIsDocNameChar(doc, val)) { val = xmlStringCurrentChar(NULL, cur, &len); cur += len; } }
if (val != 0) return(0);
return(1);}
/** * xmlValidateNmtokensValue: * @value: an Nmtokens value * * Validate that the given value match Nmtokens production * * [ VC: Name Token ] * * returns 1 if valid or 0 otherwise */
intxmlValidateNmtokensValue(const xmlChar *value) { return(xmlValidateNmtokensValueInternal(NULL, value));}
/** * xmlValidateNotationDecl: * @ctxt: the validation context * @doc: a document instance * @nota: a notation definition * * Try to validate a single notation definition * basically it does the following checks as described by the * XML-1.0 recommendation: * - it seems that no validity constraint exists on notation declarations * But this function get called anyway ... * * returns 1 if valid or 0 otherwise */
intxmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNotationPtr nota ATTRIBUTE_UNUSED) { int ret = 1;
return(ret);}
/** * xmlValidateAttributeValueInternal: * @doc: the document * @type: an attribute type * @value: an attribute value * * Validate that the given attribute value match the proper production * * returns 1 if valid or 0 otherwise */
static intxmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type, const xmlChar *value) { switch (type) { case XML_ATTRIBUTE_ENTITIES: case XML_ATTRIBUTE_IDREFS: return(xmlValidateNamesValueInternal(doc, value)); case XML_ATTRIBUTE_ENTITY: case XML_ATTRIBUTE_IDREF: case XML_ATTRIBUTE_ID: case XML_ATTRIBUTE_NOTATION: return(xmlValidateNameValueInternal(doc, value)); case XML_ATTRIBUTE_NMTOKENS: case XML_ATTRIBUTE_ENUMERATION: return(xmlValidateNmtokensValueInternal(doc, value)); case XML_ATTRIBUTE_NMTOKEN: return(xmlValidateNmtokenValueInternal(doc, value)); case XML_ATTRIBUTE_CDATA: break; } return(1);}
/** * xmlValidateAttributeValue: * @type: an attribute type * @value: an attribute value * * Validate that the given attribute value match the proper production * * [ VC: ID ] * Values of type ID must match the Name production.... * * [ VC: IDREF ] * Values of type IDREF must match the Name production, and values * of type IDREFS must match Names ... * * [ VC: Entity Name ] * Values of type ENTITY must match the Name production, values * of type ENTITIES must match Names ... * * [ VC: Name Token ] * Values of type NMTOKEN must match the Nmtoken production; values * of type NMTOKENS must match Nmtokens. * * returns 1 if valid or 0 otherwise */intxmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) { return(xmlValidateAttributeValueInternal(NULL, type, value));}
/** * xmlValidateAttributeValue2: * @ctxt: the validation context * @doc: the document * @name: the attribute name (used for error reporting only) * @type: the attribute type * @value: the attribute value * * Validate that the given attribute value match a given type. * This typically cannot be done before having finished parsing * the subsets. * * [ VC: IDREF ] * Values of type IDREF must match one of the declared IDs * Values of type IDREFS must match a sequence of the declared IDs * each Name must match the value of an ID attribute on some element * in the XML document; i.e. IDREF values must match the value of * some ID attribute * * [ VC: Entity Name ] * Values of type ENTITY must match one declared entity * Values of type ENTITIES must match a sequence of declared entities * * [ VC: Notation Attributes ] * all notation names in the declaration must be declared. * * returns 1 if valid or 0 otherwise */
static intxmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *name, xmlAttributeType type, const xmlChar *value) { int ret = 1; switch (type) { case XML_ATTRIBUTE_IDREFS: case XML_ATTRIBUTE_IDREF: case XML_ATTRIBUTE_ID: case XML_ATTRIBUTE_NMTOKENS: case XML_ATTRIBUTE_ENUMERATION: case XML_ATTRIBUTE_NMTOKEN: case XML_ATTRIBUTE_CDATA: break; case XML_ATTRIBUTE_ENTITY: { xmlEntityPtr ent;
ent = xmlGetDocEntity(doc, value); /* yeah it's a bit messy... */ if ((ent == NULL) && (doc->standalone == 1)) { doc->standalone = 0; ent = xmlGetDocEntity(doc, value); } if (ent == NULL) { xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_ENTITY, "ENTITY attribute %s reference an unknown entity \"%s\"\n", name, value, NULL); ret = 0; } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) { xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_ENTITY_TYPE, "ENTITY attribute %s reference an entity \"%s\" of wrong type\n", name, value, NULL); ret = 0; } break; } case XML_ATTRIBUTE_ENTITIES: { xmlChar *dup, *nam = NULL, *cur, save; xmlEntityPtr ent;
dup = xmlStrdup(value); if (dup == NULL) return(0); cur = dup; while (*cur != 0) { nam = cur; while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++; save = *cur; *cur = 0; ent = xmlGetDocEntity(doc, nam); if (ent == NULL) { xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_ENTITY, "ENTITIES attribute %s reference an unknown entity \"%s\"\n", name, nam, NULL); ret = 0; } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) { xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_ENTITY_TYPE, "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n", name, nam, NULL); ret = 0; } if (save == 0) break; *cur = save; while (IS_BLANK_CH(*cur)) cur++; } xmlFree(dup); break; } case XML_ATTRIBUTE_NOTATION: { xmlNotationPtr nota;
nota = xmlGetDtdNotationDesc(doc->intSubset, value); if ((nota == NULL) && (doc->extSubset != NULL)) nota = xmlGetDtdNotationDesc(doc->extSubset, value);
if (nota == NULL) { xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION, "NOTATION attribute %s reference an unknown notation \"%s\"\n", name, value, NULL); ret = 0; } break; } } return(ret);}
/** * xmlValidCtxtNormalizeAttributeValue: * @ctxt: the validation context * @doc: the document * @elem: the parent * @name: the attribute name * @value: the attribute value * @ctxt: the validation context or NULL * * Does the validation related extra step of the normalization of attribute * values: * * If the declared value is not CDATA, then the XML processor must further * process the normalized attribute value by discarding any leading and * trailing space (#x20) characters, and by replacing sequences of space * (#x20) characters by single space (#x20) character. * * Also check VC: Standalone Document Declaration in P32, and update * ctxt->valid accordingly * * returns a new normalized string if normalization is needed, NULL otherwise * the caller must free the returned value. */
xmlChar *xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem, const xmlChar *name, const xmlChar *value) { xmlChar *ret; xmlAttributePtr attrDecl = NULL; int extsubset = 0;
if (doc == NULL) return(NULL); if (elem == NULL) return(NULL); if (name == NULL) return(NULL); if (value == NULL) return(NULL);
if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) { xmlChar fn[50]; xmlChar *fullname;
fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50); if (fullname == NULL) return(NULL); attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name); if ((attrDecl == NULL) && (doc->extSubset != NULL)) { attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name); if (attrDecl != NULL) extsubset = 1; } if ((fullname != fn) && (fullname != elem->name)) xmlFree(fullname); } if ((attrDecl == NULL) && (doc->intSubset != NULL)) attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name); if ((attrDecl == NULL) && (doc->extSubset != NULL)) { attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name); if (attrDecl != NULL) extsubset = 1; }
if (attrDecl == NULL) return(NULL); if (attrDecl->atype == XML_ATTRIBUTE_CDATA) return(NULL);
ret = xmlStrdup(value); if (ret == NULL) return(NULL); xmlValidNormalizeString(ret); if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) { xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,"standalone: %s on %s value had to be normalized based on external subset declaration\n", name, elem->name, NULL); ctxt->valid = 0; } return(ret);}
/** * xmlValidNormalizeAttributeValue: * @doc: the document * @elem: the parent * @name: the attribute name * @value: the attribute value * * Does the validation related extra step of the normalization of attribute * values: * * If the declared value is not CDATA, then the XML processor must further * process the normalized attribute value by discarding any leading and * trailing space (#x20) characters, and by replacing sequences of space * (#x20) characters by single space (#x20) character. * * Returns a new normalized string if normalization is needed, NULL otherwise * the caller must free the returned value. */
xmlChar *xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem, const xmlChar *name, const xmlChar *value) { xmlChar *ret; xmlAttributePtr attrDecl = NULL;
if (doc == NULL) return(NULL); if (elem == NULL) return(NULL); if (name == NULL) return(NULL); if (value == NULL) return(NULL);
if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) { xmlChar fn[50]; xmlChar *fullname;
fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50); if (fullname == NULL) return(NULL); if ((fullname != fn) && (fullname != elem->name)) xmlFree(fullname); } attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name); if ((attrDecl == NULL) && (doc->extSubset != NULL)) attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
if (attrDecl == NULL) return(NULL); if (attrDecl->atype == XML_ATTRIBUTE_CDATA) return(NULL);
ret = xmlStrdup(value); if (ret == NULL) return(NULL); xmlValidNormalizeString(ret); return(ret);}
static voidxmlValidateAttributeIdCallback(void *payload, void *data, const xmlChar *name ATTRIBUTE_UNUSED) { xmlAttributePtr attr = (xmlAttributePtr) payload; int *count = (int *) data; if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;}
/** * xmlValidateAttributeDecl: * @ctxt: the validation context * @doc: a document instance * @attr: an attribute definition * * Try to validate a single attribute definition * basically it does the following checks as described by the * XML-1.0 recommendation: * - [ VC: Attribute Default Legal ] * - [ VC: Enumeration ] * - [ VC: ID Attribute Default ] * * The ID/IDREF uniqueness and matching are done separately * * returns 1 if valid or 0 otherwise */
intxmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlAttributePtr attr) { int ret = 1; int val; CHECK_DTD; if(attr == NULL) return(1);
/* Attribute Default Legal */ /* Enumeration */ if (attr->defaultValue != NULL) { val = xmlValidateAttributeValueInternal(doc, attr->atype, attr->defaultValue); if (val == 0) { xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT, "Syntax of default value for attribute %s of %s is not valid\n", attr->name, attr->elem, NULL); } ret &= val; }
/* ID Attribute Default */ if ((attr->atype == XML_ATTRIBUTE_ID)&& (attr->def != XML_ATTRIBUTE_IMPLIED) && (attr->def != XML_ATTRIBUTE_REQUIRED)) { xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED, "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n", attr->name, attr->elem, NULL); ret = 0; }
/* One ID per Element Type */ if (attr->atype == XML_ATTRIBUTE_ID) { int nbId;
/* the trick is that we parse DtD as their own internal subset */ xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset, attr->elem); if (elem != NULL) { nbId = xmlScanIDAttributeDecl(NULL, elem, 0); } else { xmlAttributeTablePtr table;
/* * The attribute may be declared in the internal subset and the * element in the external subset. */ nbId = 0; if (doc->intSubset != NULL) { table = (xmlAttributeTablePtr) doc->intSubset->attributes; xmlHashScan3(table, NULL, NULL, attr->elem, xmlValidateAttributeIdCallback, &nbId); } } if (nbId > 1) {
xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET, "Element %s has %d ID attribute defined in the internal subset : %s\n", attr->elem, nbId, attr->name); } else if (doc->extSubset != NULL) { int extId = 0; elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem); if (elem != NULL) { extId = xmlScanIDAttributeDecl(NULL, elem, 0); } if (extId > 1) { xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET, "Element %s has %d ID attribute defined in the external subset : %s\n", attr->elem, extId, attr->name); } else if (extId + nbId > 1) { xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,"Element %s has ID attributes defined in the internal and external subset : %s\n", attr->elem, attr->name, NULL); } } }
/* Validity Constraint: Enumeration */ if ((attr->defaultValue != NULL) && (attr->tree != NULL)) { xmlEnumerationPtr tree = attr->tree; while (tree != NULL) { if (xmlStrEqual(tree->name, attr->defaultValue)) break; tree = tree->next; } if (tree == NULL) { xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n", attr->defaultValue, attr->name, attr->elem); ret = 0; } }
return(ret);}
/** * xmlValidateElementDecl: * @ctxt: the validation context * @doc: a document instance * @elem: an element definition * * Try to validate a single element definition * basically it does the following checks as described by the * XML-1.0 recommendation: * - [ VC: One ID per Element Type ] * - [ VC: No Duplicate Types ] * - [ VC: Unique Element Type Declaration ] * * returns 1 if valid or 0 otherwise */
intxmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlElementPtr elem) { int ret = 1; xmlElementPtr tst;
CHECK_DTD;
if (elem == NULL) return(1);
#if 0#ifdef LIBXML_REGEXP_ENABLED /* Build the regexp associated to the content model */ ret = xmlValidBuildContentModel(ctxt, elem);#endif#endif
/* No Duplicate Types */ if (elem->etype == XML_ELEMENT_TYPE_MIXED) { xmlElementContentPtr cur, next; const xmlChar *name;
cur = elem->content; while (cur != NULL) { if (cur->type != XML_ELEMENT_CONTENT_OR) break; if (cur->c1 == NULL) break; if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) { name = cur->c1->name; next = cur->c2; while (next != NULL) { if (next->type == XML_ELEMENT_CONTENT_ELEMENT) { if ((xmlStrEqual(next->name, name)) && (xmlStrEqual(next->prefix, cur->c1->prefix))) { if (cur->c1->prefix == NULL) { xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR, "Definition of %s has duplicate references of %s\n", elem->name, name, NULL); } else { xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR, "Definition of %s has duplicate references of %s:%s\n", elem->name, cur->c1->prefix, name); } ret = 0; } break; } if (next->c1 == NULL) break; if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break; if ((xmlStrEqual(next->c1->name, name)) && (xmlStrEqual(next->c1->prefix, cur->c1->prefix))) { if (cur->c1->prefix == NULL) { xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR, "Definition of %s has duplicate references to %s\n", elem->name, name, NULL); } else { xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR, "Definition of %s has duplicate references to %s:%s\n", elem->name, cur->c1->prefix, name); } ret = 0; } next = next->c2; } } cur = cur->c2; } }
/* VC: Unique Element Type Declaration */ tst = xmlGetDtdElementDesc(doc->intSubset, elem->name); if ((tst != NULL ) && (tst != elem) && ((tst->prefix == elem->prefix) || (xmlStrEqual(tst->prefix, elem->prefix))) && (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) { xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED, "Redefinition of element %s\n", elem->name, NULL, NULL); ret = 0; } tst = xmlGetDtdElementDesc(doc->extSubset, elem->name); if ((tst != NULL ) && (tst != elem) && ((tst->prefix == elem->prefix) || (xmlStrEqual(tst->prefix, elem->prefix))) && (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) { xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED, "Redefinition of element %s\n", elem->name, NULL, NULL); ret = 0; } /* One ID per Element Type * already done when registering the attribute if (xmlScanIDAttributeDecl(ctxt, elem) > 1) { ret = 0; } */ return(ret);}
/** * xmlValidateOneAttribute: * @ctxt: the validation context * @doc: a document instance * @elem: an element instance * @attr: an attribute instance * @value: the attribute value (without entities processing) * * Try to validate a single attribute for an element * basically it does the following checks as described by the * XML-1.0 recommendation: * - [ VC: Attribute Value Type ] * - [ VC: Fixed Attribute Default ] * - [ VC: Entity Name ] * - [ VC: Name Token ] * - [ VC: ID ] * - [ VC: IDREF ] * - [ VC: Entity Name ] * - [ VC: Notation Attributes ] * * The ID/IDREF uniqueness and matching are done separately * * returns 1 if valid or 0 otherwise */
intxmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value){ xmlAttributePtr attrDecl = NULL; int val; int ret = 1;
CHECK_DTD; if ((elem == NULL) || (elem->name == NULL)) return(0); if ((attr == NULL) || (attr->name == NULL)) return(0);
if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) { xmlChar fn[50]; xmlChar *fullname;
fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50); if (fullname == NULL) return(0); if (attr->ns != NULL) { attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname, attr->name, attr->ns->prefix); if ((attrDecl == NULL) && (doc->extSubset != NULL)) attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname, attr->name, attr->ns->prefix); } else { attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name); if ((attrDecl == NULL) && (doc->extSubset != NULL)) attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, attr->name); } if ((fullname != fn) && (fullname != elem->name)) xmlFree(fullname); } if (attrDecl == NULL) { if (attr->ns != NULL) { attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name, attr->name, attr->ns->prefix); if ((attrDecl == NULL) && (doc->extSubset != NULL)) attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name, attr->name, attr->ns->prefix); } else { attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name); if ((attrDecl == NULL) && (doc->extSubset != NULL)) attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, attr->name); } }
/* Validity Constraint: Attribute Value Type */ if (attrDecl == NULL) { xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE, "No declaration for attribute %s of element %s\n", attr->name, elem->name, NULL); return(0); } attr->atype = attrDecl->atype;
val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value); if (val == 0) { xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE, "Syntax of value for attribute %s of %s is not valid\n", attr->name, elem->name, NULL); ret = 0; }
/* Validity constraint: Fixed Attribute Default */ if (attrDecl->def == XML_ATTRIBUTE_FIXED) { if (!xmlStrEqual(value, attrDecl->defaultValue)) { xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT, "Value for attribute %s of %s is different from default \"%s\"\n", attr->name, elem->name, attrDecl->defaultValue); ret = 0; } }
/* Validity Constraint: ID uniqueness */ if (attrDecl->atype == XML_ATTRIBUTE_ID) { if (xmlAddID(ctxt, doc, value, attr) == NULL) ret = 0; }
if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) || (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) { if (xmlAddRef(ctxt, doc, value, attr) == NULL) ret = 0; }
/* Validity Constraint: Notation Attributes */ if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) { xmlEnumerationPtr tree = attrDecl->tree; xmlNotationPtr nota;
/* First check that the given NOTATION was declared */ nota = xmlGetDtdNotationDesc(doc->intSubset, value); if (nota == NULL) nota = xmlGetDtdNotationDesc(doc->extSubset, value);
if (nota == NULL) { xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION, "Value \"%s\" for attribute %s of %s is not a declared Notation\n", value, attr->name, elem->name); ret = 0; }
/* Second, verify that it's among the list */ while (tree != NULL) { if (xmlStrEqual(tree->name, value)) break; tree = tree->next; } if (tree == NULL) { xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n", value, attr->name, elem->name); ret = 0; } }
/* Validity Constraint: Enumeration */ if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) { xmlEnumerationPtr tree = attrDecl->tree; while (tree != NULL) { if (xmlStrEqual(tree->name, value)) break; tree = tree->next; } if (tree == NULL) { xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE, "Value \"%s\" for attribute %s of %s is not among the enumerated set\n", value, attr->name, elem->name); ret = 0; } }
/* Fixed Attribute Default */ if ((attrDecl->def == XML_ATTRIBUTE_FIXED) && (!xmlStrEqual(attrDecl->defaultValue, value))) { xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE, "Value for attribute %s of %s must be \"%s\"\n", attr->name, elem->name, attrDecl->defaultValue); ret = 0; }
/* Extra check for the attribute value */ ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name, attrDecl->atype, value);
return(ret);}
/** * xmlValidateOneNamespace: * @ctxt: the validation context * @doc: a document instance * @elem: an element instance * @prefix: the namespace prefix * @ns: an namespace declaration instance * @value: the attribute value (without entities processing) * * Try to validate a single namespace declaration for an element * basically it does the following checks as described by the * XML-1.0 recommendation: * - [ VC: Attribute Value Type ] * - [ VC: Fixed Attribute Default ] * - [ VC: Entity Name ] * - [ VC: Name Token ] * - [ VC: ID ] * - [ VC: IDREF ] * - [ VC: Entity Name ] * - [ VC: Notation Attributes ] * * The ID/IDREF uniqueness and matching are done separately * * returns 1 if valid or 0 otherwise */
intxmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) { /* xmlElementPtr elemDecl; */ xmlAttributePtr attrDecl = NULL; int val; int ret = 1;
CHECK_DTD; if ((elem == NULL) || (elem->name == NULL)) return(0); if ((ns == NULL) || (ns->href == NULL)) return(0);
if (prefix != NULL) { xmlChar fn[50]; xmlChar *fullname;
fullname = xmlBuildQName(elem->name, prefix, fn, 50); if (fullname == NULL) { xmlVErrMemory(ctxt, "Validating namespace"); return(0); } if (ns->prefix != NULL) { attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname, ns->prefix, BAD_CAST "xmlns"); if ((attrDecl == NULL) && (doc->extSubset != NULL)) attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname, ns->prefix, BAD_CAST "xmlns"); } else { attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, BAD_CAST "xmlns"); if ((attrDecl == NULL) && (doc->extSubset != NULL)) attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, BAD_CAST "xmlns"); } if ((fullname != fn) && (fullname != elem->name)) xmlFree(fullname); } if (attrDecl == NULL) { if (ns->prefix != NULL) { attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name, ns->prefix, BAD_CAST "xmlns"); if ((attrDecl == NULL) && (doc->extSubset != NULL)) attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name, ns->prefix, BAD_CAST "xmlns"); } else { attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, BAD_CAST "xmlns"); if ((attrDecl == NULL) && (doc->extSubset != NULL)) attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, BAD_CAST "xmlns"); } }
/* Validity Constraint: Attribute Value Type */ if (attrDecl == NULL) { if (ns->prefix != NULL) { xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE, "No declaration for attribute xmlns:%s of element %s\n", ns->prefix, elem->name, NULL); } else { xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE, "No declaration for attribute xmlns of element %s\n", elem->name, NULL, NULL); } return(0); }
val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value); if (val == 0) { if (ns->prefix != NULL) { xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT, "Syntax of value for attribute xmlns:%s of %s is not valid\n", ns->prefix, elem->name, NULL); } else { xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT, "Syntax of value for attribute xmlns of %s is not valid\n", elem->name, NULL, NULL); } ret = 0; }
/* Validity constraint: Fixed Attribute Default */ if (attrDecl->def == XML_ATTRIBUTE_FIXED) { if (!xmlStrEqual(value, attrDecl->defaultValue)) { if (ns->prefix != NULL) { xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT, "Value for attribute xmlns:%s of %s is different from default \"%s\"\n", ns->prefix, elem->name, attrDecl->defaultValue); } else { xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT, "Value for attribute xmlns of %s is different from default \"%s\"\n", elem->name, attrDecl->defaultValue, NULL); } ret = 0; } }
/* * Casting ns to xmlAttrPtr is wrong. We'd need separate functions * xmlAddID and xmlAddRef for namespace declarations, but it makes * no practical sense to use ID types anyway. */#if 0 /* Validity Constraint: ID uniqueness */ if (attrDecl->atype == XML_ATTRIBUTE_ID) { if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL) ret = 0; }
if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) || (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) { if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL) ret = 0; }#endif
/* Validity Constraint: Notation Attributes */ if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) { xmlEnumerationPtr tree = attrDecl->tree; xmlNotationPtr nota;
/* First check that the given NOTATION was declared */ nota = xmlGetDtdNotationDesc(doc->intSubset, value); if (nota == NULL) nota = xmlGetDtdNotationDesc(doc->extSubset, value);
if (nota == NULL) { if (ns->prefix != NULL) { xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION, "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n", value, ns->prefix, elem->name); } else { xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION, "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n", value, elem->name, NULL); } ret = 0; }
/* Second, verify that it's among the list */ while (tree != NULL) { if (xmlStrEqual(tree->name, value)) break; tree = tree->next; } if (tree == NULL) { if (ns->prefix != NULL) { xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n", value, ns->prefix, elem->name); } else { xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n", value, elem->name, NULL); } ret = 0; } }
/* Validity Constraint: Enumeration */ if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) { xmlEnumerationPtr tree = attrDecl->tree; while (tree != NULL) { if (xmlStrEqual(tree->name, value)) break; tree = tree->next; } if (tree == NULL) { if (ns->prefix != NULL) { xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n", value, ns->prefix, elem->name); } else { xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n", value, elem->name, NULL); } ret = 0; } }
/* Fixed Attribute Default */ if ((attrDecl->def == XML_ATTRIBUTE_FIXED) && (!xmlStrEqual(attrDecl->defaultValue, value))) { if (ns->prefix != NULL) { xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE, "Value for attribute xmlns:%s of %s must be \"%s\"\n", ns->prefix, elem->name, attrDecl->defaultValue); } else { xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE, "Value for attribute xmlns of %s must be \"%s\"\n", elem->name, attrDecl->defaultValue, NULL); } ret = 0; }
/* Extra check for the attribute value */ if (ns->prefix != NULL) { ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix, attrDecl->atype, value); } else { ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns", attrDecl->atype, value); }
return(ret);}
#ifndef LIBXML_REGEXP_ENABLED/** * xmlValidateSkipIgnorable: * @ctxt: the validation context * @child: the child list * * Skip ignorable elements w.r.t. the validation process * * returns the first element to consider for validation of the content model */
static xmlNodePtrxmlValidateSkipIgnorable(xmlNodePtr child) { while (child != NULL) { switch (child->type) { /* These things are ignored (skipped) during validation. */ case XML_PI_NODE: case XML_COMMENT_NODE: case XML_XINCLUDE_START: case XML_XINCLUDE_END: child = child->next; break; case XML_TEXT_NODE: if (xmlIsBlankNode(child)) child = child->next; else return(child); break; /* keep current node */ default: return(child); } } return(child);}
/** * xmlValidateElementType: * @ctxt: the validation context * * Try to validate the content model of an element internal function * * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity * reference is found and -3 if the validation succeeded but * the content model is not determinist. */
static intxmlValidateElementType(xmlValidCtxtPtr ctxt) { int ret = -1; int determinist = 1;
NODE = xmlValidateSkipIgnorable(NODE); if ((NODE == NULL) && (CONT == NULL)) return(1); if ((NODE == NULL) && ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) || (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) { return(1); } if (CONT == NULL) return(-1); if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE)) return(-2);
/* * We arrive here when more states need to be examined */cont:
/* * We just recovered from a rollback generated by a possible * epsilon transition, go directly to the analysis phase */ if (STATE == ROLLBACK_PARENT) { ret = 1; goto analyze; }
/* * we may have to save a backup state here. This is the equivalent * of handling epsilon transition in NFAs. */ if ((CONT != NULL) && ((CONT->parent == NULL) || (CONT->parent == (xmlElementContentPtr) 1) || (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) && ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) || (CONT->ocur == XML_ELEMENT_CONTENT_OPT) || ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) { if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0) return(0); }
/* * Check first if the content matches */ switch (CONT->type) { case XML_ELEMENT_CONTENT_PCDATA: if (NODE == NULL) { ret = 0; break; } if (NODE->type == XML_TEXT_NODE) { /* * go to next element in the content model * skipping ignorable elems */ do { NODE = NODE->next; NODE = xmlValidateSkipIgnorable(NODE); if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE)) return(-2); } while ((NODE != NULL) && ((NODE->type != XML_ELEMENT_NODE) && (NODE->type != XML_TEXT_NODE) && (NODE->type != XML_CDATA_SECTION_NODE))); ret = 1; break; } else { ret = 0; break; } break; case XML_ELEMENT_CONTENT_ELEMENT: if (NODE == NULL) { ret = 0; break; } ret = ((NODE->type == XML_ELEMENT_NODE) && (xmlStrEqual(NODE->name, CONT->name))); if (ret == 1) { if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) { ret = (CONT->prefix == NULL); } else if (CONT->prefix == NULL) { ret = 0; } else { ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix); } } if (ret == 1) { /* * go to next element in the content model * skipping ignorable elems */ do { NODE = NODE->next; NODE = xmlValidateSkipIgnorable(NODE); if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE)) return(-2); } while ((NODE != NULL) && ((NODE->type != XML_ELEMENT_NODE) && (NODE->type != XML_TEXT_NODE) && (NODE->type != XML_CDATA_SECTION_NODE))); } else { ret = 0; break; } break; case XML_ELEMENT_CONTENT_OR: /* * Small optimization. */ if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) { if ((NODE == NULL) || (!xmlStrEqual(NODE->name, CONT->c1->name))) { DEPTH++; CONT = CONT->c2; goto cont; } if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) { ret = (CONT->c1->prefix == NULL); } else if (CONT->c1->prefix == NULL) { ret = 0; } else { ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix); } if (ret == 0) { DEPTH++; CONT = CONT->c2; goto cont; } }
/* * save the second branch 'or' branch */ if (vstateVPush(ctxt, CONT->c2, NODE, DEPTH + 1, OCCURS, ROLLBACK_OR) < 0) return(-1); DEPTH++; CONT = CONT->c1; goto cont; case XML_ELEMENT_CONTENT_SEQ: /* * Small optimization. */ if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) && ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) || (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) { if ((NODE == NULL) || (!xmlStrEqual(NODE->name, CONT->c1->name))) { DEPTH++; CONT = CONT->c2; goto cont; } if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) { ret = (CONT->c1->prefix == NULL); } else if (CONT->c1->prefix == NULL) { ret = 0; } else { ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix); } if (ret == 0) { DEPTH++; CONT = CONT->c2; goto cont; } } DEPTH++; CONT = CONT->c1; goto cont; }
/* * At this point handle going up in the tree */ if (ret == -1) { return(ret); }analyze: while (CONT != NULL) { /* * First do the analysis depending on the occurrence model at * this level. */ if (ret == 0) { switch (CONT->ocur) { xmlNodePtr cur;
case XML_ELEMENT_CONTENT_ONCE: cur = ctxt->vstate->node; if (vstateVPop(ctxt) < 0 ) { return(0); } if (cur != ctxt->vstate->node) determinist = -3; goto cont; case XML_ELEMENT_CONTENT_PLUS: if (OCCURRENCE == 0) { cur = ctxt->vstate->node; if (vstateVPop(ctxt) < 0 ) { return(0); } if (cur != ctxt->vstate->node) determinist = -3; goto cont; } ret = 1; break; case XML_ELEMENT_CONTENT_MULT: ret = 1; break; case XML_ELEMENT_CONTENT_OPT: ret = 1; break; } } else { switch (CONT->ocur) { case XML_ELEMENT_CONTENT_OPT: ret = 1; break; case XML_ELEMENT_CONTENT_ONCE: ret = 1; break; case XML_ELEMENT_CONTENT_PLUS: if (STATE == ROLLBACK_PARENT) { ret = 1; break; } if (NODE == NULL) { ret = 1; break; } SET_OCCURRENCE; goto cont; case XML_ELEMENT_CONTENT_MULT: if (STATE == ROLLBACK_PARENT) { ret = 1; break; } if (NODE == NULL) { ret = 1; break; } /* SET_OCCURRENCE; */ goto cont; } } STATE = 0;
/* * Then act accordingly at the parent level */ RESET_OCCURRENCE; if ((CONT->parent == NULL) || (CONT->parent == (xmlElementContentPtr) 1)) break;
switch (CONT->parent->type) { case XML_ELEMENT_CONTENT_PCDATA: return(-1); case XML_ELEMENT_CONTENT_ELEMENT: return(-1); case XML_ELEMENT_CONTENT_OR: if (ret == 1) { CONT = CONT->parent; DEPTH--; } else { CONT = CONT->parent; DEPTH--; } break; case XML_ELEMENT_CONTENT_SEQ: if (ret == 0) { CONT = CONT->parent; DEPTH--; } else if (CONT == CONT->parent->c1) { CONT = CONT->parent->c2; goto cont; } else { CONT = CONT->parent; DEPTH--; } } } if (NODE != NULL) { xmlNodePtr cur;
cur = ctxt->vstate->node; if (vstateVPop(ctxt) < 0 ) { return(0); } if (cur != ctxt->vstate->node) determinist = -3; goto cont; } if (ret == 0) { xmlNodePtr cur;
cur = ctxt->vstate->node; if (vstateVPop(ctxt) < 0 ) { return(0); } if (cur != ctxt->vstate->node) determinist = -3; goto cont; } return(determinist);}#endif
/** * xmlSnprintfElements: * @buf: an output buffer * @size: the size of the buffer * @content: An element * @glob: 1 if one must print the englobing parenthesis, 0 otherwise * * This will dump the list of elements to the buffer * Intended just for the debug routine */static voidxmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) { xmlNodePtr cur; int len;
if (node == NULL) return; if (glob) strcat(buf, "("); cur = node; while (cur != NULL) { len = strlen(buf); if (size - len < 50) { if ((size - len > 4) && (buf[len - 1] != '.')) strcat(buf, " ..."); return; } switch (cur->type) { case XML_ELEMENT_NODE: if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { if (size - len < xmlStrlen(cur->ns->prefix) + 10) { if ((size - len > 4) && (buf[len - 1] != '.')) strcat(buf, " ..."); return; } strcat(buf, (char *) cur->ns->prefix); strcat(buf, ":"); } if (size - len < xmlStrlen(cur->name) + 10) { if ((size - len > 4) && (buf[len - 1] != '.')) strcat(buf, " ..."); return; } strcat(buf, (char *) cur->name); if (cur->next != NULL) strcat(buf, " "); break; case XML_TEXT_NODE: if (xmlIsBlankNode(cur)) break; /* Falls through. */ case XML_CDATA_SECTION_NODE: case XML_ENTITY_REF_NODE: strcat(buf, "CDATA"); if (cur->next != NULL) strcat(buf, " "); break; case XML_ATTRIBUTE_NODE: case XML_DOCUMENT_NODE: case XML_HTML_DOCUMENT_NODE: case XML_DOCUMENT_TYPE_NODE: case XML_DOCUMENT_FRAG_NODE: case XML_NOTATION_NODE: case XML_NAMESPACE_DECL: strcat(buf, "???"); if (cur->next != NULL) strcat(buf, " "); break; case XML_ENTITY_NODE: case XML_PI_NODE: case XML_DTD_NODE: case XML_COMMENT_NODE: case XML_ELEMENT_DECL: case XML_ATTRIBUTE_DECL: case XML_ENTITY_DECL: case XML_XINCLUDE_START: case XML_XINCLUDE_END: break; } cur = cur->next; } if (glob) strcat(buf, ")");}
/** * xmlValidateElementContent: * @ctxt: the validation context * @child: the child list * @elemDecl: pointer to the element declaration * @warn: emit the error message * @parent: the parent element (for error reporting) * * Try to validate the content model of an element * * returns 1 if valid or 0 if not and -1 in case of error */
static intxmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child, xmlElementPtr elemDecl, int warn, xmlNodePtr parent) { int ret = 1;#ifndef LIBXML_REGEXP_ENABLED xmlNodePtr repl = NULL, last = NULL, tmp;#endif xmlNodePtr cur; xmlElementContentPtr cont; const xmlChar *name;
if ((elemDecl == NULL) || (parent == NULL) || (ctxt == NULL)) return(-1); cont = elemDecl->content; name = elemDecl->name;
#ifdef LIBXML_REGEXP_ENABLED /* Build the regexp associated to the content model */ if (elemDecl->contModel == NULL) ret = xmlValidBuildContentModel(ctxt, elemDecl); if (elemDecl->contModel == NULL) { return(-1); } else { xmlRegExecCtxtPtr exec;
if (!xmlRegexpIsDeterminist(elemDecl->contModel)) { return(-1); } ctxt->nodeMax = 0; ctxt->nodeNr = 0; ctxt->nodeTab = NULL; exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL); if (exec != NULL) { cur = child; while (cur != NULL) { switch (cur->type) { case XML_ENTITY_REF_NODE: /* * Push the current node to be able to roll back * and process within the entity */ if ((cur->children != NULL) && (cur->children->children != NULL)) { nodeVPush(ctxt, cur); cur = cur->children->children; continue; } break; case XML_TEXT_NODE: if (xmlIsBlankNode(cur)) break; ret = 0; goto fail; case XML_CDATA_SECTION_NODE: /* TODO */ ret = 0; goto fail; case XML_ELEMENT_NODE: if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { xmlChar fn[50]; xmlChar *fullname;
fullname = xmlBuildQName(cur->name, cur->ns->prefix, fn, 50); if (fullname == NULL) { ret = -1; goto fail; } ret = xmlRegExecPushString(exec, fullname, NULL); if ((fullname != fn) && (fullname != cur->name)) xmlFree(fullname); } else { ret = xmlRegExecPushString(exec, cur->name, NULL); } break; default: break; } /* * Switch to next element */ cur = cur->next; while (cur == NULL) { cur = nodeVPop(ctxt); if (cur == NULL) break; cur = cur->next; } } ret = xmlRegExecPushString(exec, NULL, NULL);fail: xmlRegFreeExecCtxt(exec); } }#else /* LIBXML_REGEXP_ENABLED */ /* * Allocate the stack */ ctxt->vstateMax = 8; ctxt->vstateTab = (xmlValidState *) xmlMalloc( ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); if (ctxt->vstateTab == NULL) { xmlVErrMemory(ctxt, "malloc failed"); return(-1); } /* * The first entry in the stack is reserved to the current state */ ctxt->nodeMax = 0; ctxt->nodeNr = 0; ctxt->nodeTab = NULL; ctxt->vstate = &ctxt->vstateTab[0]; ctxt->vstateNr = 1; CONT = cont; NODE = child; DEPTH = 0; OCCURS = 0; STATE = 0; ret = xmlValidateElementType(ctxt); if ((ret == -3) && (warn)) { char expr[5000]; expr[0] = 0; xmlSnprintfElementContent(expr, 5000, elemDecl->content, 1); xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl, XML_DTD_CONTENT_NOT_DETERMINIST, "Content model of %s is not deterministic: %s\n", name, BAD_CAST expr, NULL); } else if (ret == -2) { /* * An entities reference appeared at this level. * Build a minimal representation of this node content * sufficient to run the validation process on it */ cur = child; while (cur != NULL) { switch (cur->type) { case XML_ENTITY_REF_NODE: /* * Push the current node to be able to roll back * and process within the entity */ if ((cur->children != NULL) && (cur->children->children != NULL)) { nodeVPush(ctxt, cur); cur = cur->children->children; continue; } break; case XML_TEXT_NODE: if (xmlIsBlankNode(cur)) break; /* no break on purpose */ case XML_CDATA_SECTION_NODE: /* no break on purpose */ case XML_ELEMENT_NODE: /* * Allocate a new node and minimally fills in * what's required */ tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); if (tmp == NULL) { xmlVErrMemory(ctxt, "malloc failed"); xmlFreeNodeList(repl); ret = -1; goto done; } tmp->type = cur->type; tmp->name = cur->name; tmp->ns = cur->ns; tmp->next = NULL; tmp->content = NULL; if (repl == NULL) repl = last = tmp; else { last->next = tmp; last = tmp; } if (cur->type == XML_CDATA_SECTION_NODE) { /* * E59 spaces in CDATA does not match the * nonterminal S */ tmp->content = xmlStrdup(BAD_CAST "CDATA"); } break; default: break; } /* * Switch to next element */ cur = cur->next; while (cur == NULL) { cur = nodeVPop(ctxt); if (cur == NULL) break; cur = cur->next; } }
/* * Relaunch the validation */ ctxt->vstate = &ctxt->vstateTab[0]; ctxt->vstateNr = 1; CONT = cont; NODE = repl; DEPTH = 0; OCCURS = 0; STATE = 0; ret = xmlValidateElementType(ctxt); }#endif /* LIBXML_REGEXP_ENABLED */ if ((warn) && ((ret != 1) && (ret != -3))) { if (ctxt != NULL) { char expr[5000]; char list[5000];
expr[0] = 0; xmlSnprintfElementContent(&expr[0], 5000, cont, 1); list[0] = 0;#ifndef LIBXML_REGEXP_ENABLED if (repl != NULL) xmlSnprintfElements(&list[0], 5000, repl, 1); else#endif /* LIBXML_REGEXP_ENABLED */ xmlSnprintfElements(&list[0], 5000, child, 1);
if (name != NULL) { xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL, "Element %s content does not follow the DTD, expecting %s, got %s\n", name, BAD_CAST expr, BAD_CAST list); } else { xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL, "Element content does not follow the DTD, expecting %s, got %s\n", BAD_CAST expr, BAD_CAST list, NULL); } } else { if (name != NULL) { xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL, "Element %s content does not follow the DTD\n", name, NULL, NULL); } else { xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL, "Element content does not follow the DTD\n", NULL, NULL, NULL); } } ret = 0; } if (ret == -3) ret = 1;
#ifndef LIBXML_REGEXP_ENABLEDdone: /* * Deallocate the copy if done, and free up the validation stack */ while (repl != NULL) { tmp = repl->next; xmlFree(repl); repl = tmp; } ctxt->vstateMax = 0; if (ctxt->vstateTab != NULL) { xmlFree(ctxt->vstateTab); ctxt->vstateTab = NULL; }#endif ctxt->nodeMax = 0; ctxt->nodeNr = 0; if (ctxt->nodeTab != NULL) { xmlFree(ctxt->nodeTab); ctxt->nodeTab = NULL; } return(ret);
}
/** * xmlValidateCdataElement: * @ctxt: the validation context * @doc: a document instance * @elem: an element instance * * Check that an element follows #CDATA * * returns 1 if valid or 0 otherwise */static intxmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) { int ret = 1; xmlNodePtr cur, child;
if ((ctxt == NULL) || (doc == NULL) || (elem == NULL) || (elem->type != XML_ELEMENT_NODE)) return(0);
child = elem->children;
cur = child; while (cur != NULL) { switch (cur->type) { case XML_ENTITY_REF_NODE: /* * Push the current node to be able to roll back * and process within the entity */ if ((cur->children != NULL) && (cur->children->children != NULL)) { nodeVPush(ctxt, cur); cur = cur->children->children; continue; } break; case XML_COMMENT_NODE: case XML_PI_NODE: case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: break; default: ret = 0; goto done; } /* * Switch to next element */ cur = cur->next; while (cur == NULL) { cur = nodeVPop(ctxt); if (cur == NULL) break; cur = cur->next; } }done: ctxt->nodeMax = 0; ctxt->nodeNr = 0; if (ctxt->nodeTab != NULL) { xmlFree(ctxt->nodeTab); ctxt->nodeTab = NULL; } return(ret);}
#ifdef LIBXML_REGEXP_ENABLED/** * xmlValidateCheckMixed: * @ctxt: the validation context * @cont: the mixed content model * @qname: the qualified name as appearing in the serialization * * Check if the given node is part of the content model. * * Returns 1 if yes, 0 if no, -1 in case of error */static intxmlValidateCheckMixed(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont, const xmlChar *qname) { const xmlChar *name; int plen; name = xmlSplitQName3(qname, &plen);
if (name == NULL) { while (cont != NULL) { if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) { if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname))) return(1); } else if ((cont->type == XML_ELEMENT_CONTENT_OR) && (cont->c1 != NULL) && (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){ if ((cont->c1->prefix == NULL) && (xmlStrEqual(cont->c1->name, qname))) return(1); } else if ((cont->type != XML_ELEMENT_CONTENT_OR) || (cont->c1 == NULL) || (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){ xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT, "Internal: MIXED struct corrupted\n", NULL); break; } cont = cont->c2; } } else { while (cont != NULL) { if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) { if ((cont->prefix != NULL) && (xmlStrncmp(cont->prefix, qname, plen) == 0) && (xmlStrEqual(cont->name, name))) return(1); } else if ((cont->type == XML_ELEMENT_CONTENT_OR) && (cont->c1 != NULL) && (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){ if ((cont->c1->prefix != NULL) && (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) && (xmlStrEqual(cont->c1->name, name))) return(1); } else if ((cont->type != XML_ELEMENT_CONTENT_OR) || (cont->c1 == NULL) || (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){ xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT, "Internal: MIXED struct corrupted\n", NULL); break; } cont = cont->c2; } } return(0);}#endif /* LIBXML_REGEXP_ENABLED */
/** * xmlValidGetElemDecl: * @ctxt: the validation context * @doc: a document instance * @elem: an element instance * @extsubset: pointer, (out) indicate if the declaration was found * in the external subset. * * Finds a declaration associated to an element in the document. * * returns the pointer to the declaration or NULL if not found. */static xmlElementPtrxmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem, int *extsubset) { xmlElementPtr elemDecl = NULL; const xmlChar *prefix = NULL;
if ((ctxt == NULL) || (doc == NULL) || (elem == NULL) || (elem->name == NULL)) return(NULL); if (extsubset != NULL) *extsubset = 0;
/* * Fetch the declaration for the qualified name */ if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) prefix = elem->ns->prefix;
if (prefix != NULL) { elemDecl = xmlGetDtdQElementDesc(doc->intSubset, elem->name, prefix); if ((elemDecl == NULL) && (doc->extSubset != NULL)) { elemDecl = xmlGetDtdQElementDesc(doc->extSubset, elem->name, prefix); if ((elemDecl != NULL) && (extsubset != NULL)) *extsubset = 1; } }
/* * Fetch the declaration for the non qualified name * This is "non-strict" validation should be done on the * full QName but in that case being flexible makes sense. */ if (elemDecl == NULL) { elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name); if ((elemDecl == NULL) && (doc->extSubset != NULL)) { elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name); if ((elemDecl != NULL) && (extsubset != NULL)) *extsubset = 1; } } if (elemDecl == NULL) { xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM, "No declaration for element %s\n", elem->name, NULL, NULL); } return(elemDecl);}
#ifdef LIBXML_REGEXP_ENABLED/** * xmlValidatePushElement: * @ctxt: the validation context * @doc: a document instance * @elem: an element instance * @qname: the qualified name as appearing in the serialization * * Push a new element start on the validation stack. * * returns 1 if no validation problem was found or 0 otherwise */intxmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem, const xmlChar *qname) { int ret = 1; xmlElementPtr eDecl; int extsubset = 0;
if (ctxt == NULL) return(0);/* printf("PushElem %s\n", qname); */ if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) { xmlValidStatePtr state = ctxt->vstate; xmlElementPtr elemDecl;
/* * Check the new element against the content model of the new elem. */ if (state->elemDecl != NULL) { elemDecl = state->elemDecl;
switch(elemDecl->etype) { case XML_ELEMENT_TYPE_UNDEFINED: ret = 0; break; case XML_ELEMENT_TYPE_EMPTY: xmlErrValidNode(ctxt, state->node, XML_DTD_NOT_EMPTY, "Element %s was declared EMPTY this one has content\n", state->node->name, NULL, NULL); ret = 0; break; case XML_ELEMENT_TYPE_ANY: /* I don't think anything is required then */ break; case XML_ELEMENT_TYPE_MIXED: /* simple case of declared as #PCDATA */ if ((elemDecl->content != NULL) && (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) { xmlErrValidNode(ctxt, state->node, XML_DTD_NOT_PCDATA, "Element %s was declared #PCDATA but contains non text nodes\n", state->node->name, NULL, NULL); ret = 0; } else { ret = xmlValidateCheckMixed(ctxt, elemDecl->content, qname); if (ret != 1) { xmlErrValidNode(ctxt, state->node, XML_DTD_INVALID_CHILD, "Element %s is not declared in %s list of possible children\n", qname, state->node->name, NULL); } } break; case XML_ELEMENT_TYPE_ELEMENT: /* * TODO: * VC: Standalone Document Declaration * - element types with element content, if white space * occurs directly within any instance of those types. */ if (state->exec != NULL) { ret = xmlRegExecPushString(state->exec, qname, NULL); if (ret < 0) { xmlErrValidNode(ctxt, state->node, XML_DTD_CONTENT_MODEL, "Element %s content does not follow the DTD, Misplaced %s\n", state->node->name, qname, NULL); ret = 0; } else { ret = 1; } } break; } } } eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset); vstateVPush(ctxt, eDecl, elem); return(ret);}
/** * xmlValidatePushCData: * @ctxt: the validation context * @data: some character data read * @len: the length of the data * * check the CData parsed for validation in the current stack * * returns 1 if no validation problem was found or 0 otherwise */intxmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) { int ret = 1;
/* printf("CDATA %s %d\n", data, len); */ if (ctxt == NULL) return(0); if (len <= 0) return(ret); if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) { xmlValidStatePtr state = ctxt->vstate; xmlElementPtr elemDecl;
/* * Check the new element against the content model of the new elem. */ if (state->elemDecl != NULL) { elemDecl = state->elemDecl;
switch(elemDecl->etype) { case XML_ELEMENT_TYPE_UNDEFINED: ret = 0; break; case XML_ELEMENT_TYPE_EMPTY: xmlErrValidNode(ctxt, state->node, XML_DTD_NOT_EMPTY, "Element %s was declared EMPTY this one has content\n", state->node->name, NULL, NULL); ret = 0; break; case XML_ELEMENT_TYPE_ANY: break; case XML_ELEMENT_TYPE_MIXED: break; case XML_ELEMENT_TYPE_ELEMENT: { int i;
for (i = 0;i < len;i++) { if (!IS_BLANK_CH(data[i])) { xmlErrValidNode(ctxt, state->node, XML_DTD_CONTENT_MODEL, "Element %s content does not follow the DTD, Text not allowed\n", state->node->name, NULL, NULL); ret = 0; goto done; } } /* * TODO: * VC: Standalone Document Declaration * element types with element content, if white space * occurs directly within any instance of those types. */ break; } } } }done: return(ret);}
/** * xmlValidatePopElement: * @ctxt: the validation context * @doc: a document instance * @elem: an element instance * @qname: the qualified name as appearing in the serialization * * Pop the element end from the validation stack. * * returns 1 if no validation problem was found or 0 otherwise */intxmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr elem ATTRIBUTE_UNUSED, const xmlChar *qname ATTRIBUTE_UNUSED) { int ret = 1;
if (ctxt == NULL) return(0);/* printf("PopElem %s\n", qname); */ if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) { xmlValidStatePtr state = ctxt->vstate; xmlElementPtr elemDecl;
/* * Check the new element against the content model of the new elem. */ if (state->elemDecl != NULL) { elemDecl = state->elemDecl;
if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) { if (state->exec != NULL) { ret = xmlRegExecPushString(state->exec, NULL, NULL); if (ret <= 0) { xmlErrValidNode(ctxt, state->node, XML_DTD_CONTENT_MODEL, "Element %s content does not follow the DTD, Expecting more children\n", state->node->name, NULL,NULL); ret = 0; } else { /* * previous validation errors should not generate * a new one here */ ret = 1; } } } } vstateVPop(ctxt); } return(ret);}#endif /* LIBXML_REGEXP_ENABLED */
/** * xmlValidateOneElement: * @ctxt: the validation context * @doc: a document instance * @elem: an element instance * * Try to validate a single element and it's attributes, * basically it does the following checks as described by the * XML-1.0 recommendation: * - [ VC: Element Valid ] * - [ VC: Required Attribute ] * Then call xmlValidateOneAttribute() for each attribute present. * * The ID/IDREF checkings are done separately * * returns 1 if valid or 0 otherwise */
intxmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) { xmlElementPtr elemDecl = NULL; xmlElementContentPtr cont; xmlAttributePtr attr; xmlNodePtr child; int ret = 1, tmp; const xmlChar *name; int extsubset = 0;
CHECK_DTD;
if (elem == NULL) return(0); switch (elem->type) { case XML_ATTRIBUTE_NODE: xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, "Attribute element not expected\n", NULL, NULL ,NULL); return(0); case XML_TEXT_NODE: if (elem->children != NULL) { xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, "Text element has children !\n", NULL,NULL,NULL); return(0); } if (elem->ns != NULL) { xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, "Text element has namespace !\n", NULL,NULL,NULL); return(0); } if (elem->content == NULL) { xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, "Text element has no content !\n", NULL,NULL,NULL); return(0); } return(1); case XML_XINCLUDE_START: case XML_XINCLUDE_END: return(1); case XML_CDATA_SECTION_NODE: case XML_ENTITY_REF_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: return(1); case XML_ENTITY_NODE: xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, "Entity element not expected\n", NULL, NULL ,NULL); return(0); case XML_NOTATION_NODE: xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, "Notation element not expected\n", NULL, NULL ,NULL); return(0); case XML_DOCUMENT_NODE: case XML_DOCUMENT_TYPE_NODE: case XML_DOCUMENT_FRAG_NODE: xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, "Document element not expected\n", NULL, NULL ,NULL); return(0); case XML_HTML_DOCUMENT_NODE: xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, "HTML Document not expected\n", NULL, NULL ,NULL); return(0); case XML_ELEMENT_NODE: break; default: xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, "unknown element type\n", NULL, NULL ,NULL); return(0); }
/* * Fetch the declaration */ elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset); if (elemDecl == NULL) return(0);
/* * If vstateNr is not zero that means continuous validation is * activated, do not try to check the content model at that level. */ if (ctxt->vstateNr == 0) { /* Check that the element content matches the definition */ switch (elemDecl->etype) { case XML_ELEMENT_TYPE_UNDEFINED: xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM, "No declaration for element %s\n", elem->name, NULL, NULL); return(0); case XML_ELEMENT_TYPE_EMPTY: if (elem->children != NULL) { xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY, "Element %s was declared EMPTY this one has content\n", elem->name, NULL, NULL); ret = 0; } break; case XML_ELEMENT_TYPE_ANY: /* I don't think anything is required then */ break; case XML_ELEMENT_TYPE_MIXED:
/* simple case of declared as #PCDATA */ if ((elemDecl->content != NULL) && (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) { ret = xmlValidateOneCdataElement(ctxt, doc, elem); if (!ret) { xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA, "Element %s was declared #PCDATA but contains non text nodes\n", elem->name, NULL, NULL); } break; } child = elem->children; /* Hum, this start to get messy */ while (child != NULL) { if (child->type == XML_ELEMENT_NODE) { name = child->name; if ((child->ns != NULL) && (child->ns->prefix != NULL)) { xmlChar fn[50]; xmlChar *fullname;
fullname = xmlBuildQName(child->name, child->ns->prefix, fn, 50); if (fullname == NULL) return(0); cont = elemDecl->content; while (cont != NULL) { if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) { if (xmlStrEqual(cont->name, fullname)) break; } else if ((cont->type == XML_ELEMENT_CONTENT_OR) && (cont->c1 != NULL) && (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){ if (xmlStrEqual(cont->c1->name, fullname)) break; } else if ((cont->type != XML_ELEMENT_CONTENT_OR) || (cont->c1 == NULL) || (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){ xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT, "Internal: MIXED struct corrupted\n", NULL); break; } cont = cont->c2; } if ((fullname != fn) && (fullname != child->name)) xmlFree(fullname); if (cont != NULL) goto child_ok; } cont = elemDecl->content; while (cont != NULL) { if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) { if (xmlStrEqual(cont->name, name)) break; } else if ((cont->type == XML_ELEMENT_CONTENT_OR) && (cont->c1 != NULL) && (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) { if (xmlStrEqual(cont->c1->name, name)) break; } else if ((cont->type != XML_ELEMENT_CONTENT_OR) || (cont->c1 == NULL) || (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) { xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT, "Internal: MIXED struct corrupted\n", NULL); break; } cont = cont->c2; } if (cont == NULL) { xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD, "Element %s is not declared in %s list of possible children\n", name, elem->name, NULL); ret = 0; } }child_ok: child = child->next; } break; case XML_ELEMENT_TYPE_ELEMENT: if ((doc->standalone == 1) && (extsubset == 1)) { /* * VC: Standalone Document Declaration * - element types with element content, if white space * occurs directly within any instance of those types. */ child = elem->children; while (child != NULL) { if (child->type == XML_TEXT_NODE) { const xmlChar *content = child->content;
while (IS_BLANK_CH(*content)) content++; if (*content == 0) { xmlErrValidNode(ctxt, elem, XML_DTD_STANDALONE_WHITE_SPACE,"standalone: %s declared in the external subset contains white spaces nodes\n", elem->name, NULL, NULL); ret = 0; break; } } child =child->next; } } child = elem->children; cont = elemDecl->content; tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem); if (tmp <= 0) ret = tmp; break; } } /* not continuous */
/* [ VC: Required Attribute ] */ attr = elemDecl->attributes; while (attr != NULL) { if (attr->def == XML_ATTRIBUTE_REQUIRED) { int qualified = -1;
if ((attr->prefix == NULL) && (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) { xmlNsPtr ns;
ns = elem->nsDef; while (ns != NULL) { if (ns->prefix == NULL) goto found; ns = ns->next; } } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) { xmlNsPtr ns;
ns = elem->nsDef; while (ns != NULL) { if (xmlStrEqual(attr->name, ns->prefix)) goto found; ns = ns->next; } } else { xmlAttrPtr attrib;
attrib = elem->properties; while (attrib != NULL) { if (xmlStrEqual(attrib->name, attr->name)) { if (attr->prefix != NULL) { xmlNsPtr nameSpace = attrib->ns;
if (nameSpace == NULL) nameSpace = elem->ns; /* * qualified names handling is problematic, having a * different prefix should be possible but DTDs don't * allow to define the URI instead of the prefix :-( */ if (nameSpace == NULL) { if (qualified < 0) qualified = 0; } else if (!xmlStrEqual(nameSpace->prefix, attr->prefix)) { if (qualified < 1) qualified = 1; } else goto found; } else { /* * We should allow applications to define namespaces * for their application even if the DTD doesn't * carry one, otherwise, basically we would always * break. */ goto found; } } attrib = attrib->next; } } if (qualified == -1) { if (attr->prefix == NULL) { xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE, "Element %s does not carry attribute %s\n", elem->name, attr->name, NULL); ret = 0; } else { xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE, "Element %s does not carry attribute %s:%s\n", elem->name, attr->prefix,attr->name); ret = 0; } } else if (qualified == 0) { xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX, "Element %s required attribute %s:%s has no prefix\n", elem->name, attr->prefix, attr->name); } else if (qualified == 1) { xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX, "Element %s required attribute %s:%s has different prefix\n", elem->name, attr->prefix, attr->name); } } else if (attr->def == XML_ATTRIBUTE_FIXED) { /* * Special tests checking #FIXED namespace declarations * have the right value since this is not done as an * attribute checking */ if ((attr->prefix == NULL) && (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) { xmlNsPtr ns;
ns = elem->nsDef; while (ns != NULL) { if (ns->prefix == NULL) { if (!xmlStrEqual(attr->defaultValue, ns->href)) { xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_DEFAULT_NAMESPACE, "Element %s namespace name for default namespace does not match the DTD\n", elem->name, NULL, NULL); ret = 0; } goto found; } ns = ns->next; } } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) { xmlNsPtr ns;
ns = elem->nsDef; while (ns != NULL) { if (xmlStrEqual(attr->name, ns->prefix)) { if (!xmlStrEqual(attr->defaultValue, ns->href)) { xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE, "Element %s namespace name for %s does not match the DTD\n", elem->name, ns->prefix, NULL); ret = 0; } goto found; } ns = ns->next; } } }found: attr = attr->nexth; } return(ret);}
/** * xmlValidateRoot: * @ctxt: the validation context * @doc: a document instance * * Try to validate a the root element * basically it does the following check as described by the * XML-1.0 recommendation: * - [ VC: Root Element Type ] * it doesn't try to recurse or apply other check to the element * * returns 1 if valid or 0 otherwise */
intxmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { xmlNodePtr root; int ret;
if (doc == NULL) return(0);
root = xmlDocGetRootElement(doc); if ((root == NULL) || (root->name == NULL)) { xmlErrValid(ctxt, XML_DTD_NO_ROOT, "no root element\n", NULL); return(0); }
/* * When doing post validation against a separate DTD, those may * no internal subset has been generated */ if ((doc->intSubset != NULL) && (doc->intSubset->name != NULL)) { /* * Check first the document root against the NQName */ if (!xmlStrEqual(doc->intSubset->name, root->name)) { if ((root->ns != NULL) && (root->ns->prefix != NULL)) { xmlChar fn[50]; xmlChar *fullname;
fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50); if (fullname == NULL) { xmlVErrMemory(ctxt, NULL); return(0); } ret = xmlStrEqual(doc->intSubset->name, fullname); if ((fullname != fn) && (fullname != root->name)) xmlFree(fullname); if (ret == 1) goto name_ok; } if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) && (xmlStrEqual(root->name, BAD_CAST "html"))) goto name_ok; xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME, "root and DTD name do not match '%s' and '%s'\n", root->name, doc->intSubset->name, NULL); return(0); } }name_ok: return(1);}
/** * xmlValidateElement: * @ctxt: the validation context * @doc: a document instance * @root: an element instance * * Try to validate the subtree under an element * * returns 1 if valid or 0 otherwise */
intxmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr root) { xmlNodePtr elem; xmlAttrPtr attr; xmlNsPtr ns; const xmlChar *value; int ret = 1;
if (root == NULL) return(0);
CHECK_DTD;
elem = root; while (1) { ret &= xmlValidateOneElement(ctxt, doc, elem);
if (elem->type == XML_ELEMENT_NODE) { attr = elem->properties; while (attr != NULL) { value = xmlNodeListGetString(doc, attr->children, 0); ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value); if (value != NULL) xmlFree((char *)value); attr= attr->next; }
ns = elem->nsDef; while (ns != NULL) { if (elem->ns == NULL) ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL, ns, ns->href); else ret &= xmlValidateOneNamespace(ctxt, doc, elem, elem->ns->prefix, ns, ns->href); ns = ns->next; }
if (elem->children != NULL) { elem = elem->children; continue; } }
while (1) { if (elem == root) goto done; if (elem->next != NULL) break; elem = elem->parent; } elem = elem->next; }
done: return(ret);}
/** * xmlValidateRef: * @ref: A reference to be validated * @ctxt: Validation context * @name: Name of ID we are searching for * */static voidxmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt, const xmlChar *name) { xmlAttrPtr id; xmlAttrPtr attr;
if (ref == NULL) return; if ((ref->attr == NULL) && (ref->name == NULL)) return; attr = ref->attr; if (attr == NULL) { xmlChar *dup, *str = NULL, *cur, save;
dup = xmlStrdup(name); if (dup == NULL) { ctxt->valid = 0; return; } cur = dup; while (*cur != 0) { str = cur; while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++; save = *cur; *cur = 0; id = xmlGetID(ctxt->doc, str); if (id == NULL) { xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID, "attribute %s line %d references an unknown ID \"%s\"\n", ref->name, ref->lineno, str); ctxt->valid = 0; } if (save == 0) break; *cur = save; while (IS_BLANK_CH(*cur)) cur++; } xmlFree(dup); } else if (attr->atype == XML_ATTRIBUTE_IDREF) { id = xmlGetID(ctxt->doc, name); if (id == NULL) { xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID, "IDREF attribute %s references an unknown ID \"%s\"\n", attr->name, name, NULL); ctxt->valid = 0; } } else if (attr->atype == XML_ATTRIBUTE_IDREFS) { xmlChar *dup, *str = NULL, *cur, save;
dup = xmlStrdup(name); if (dup == NULL) { xmlVErrMemory(ctxt, "IDREFS split"); ctxt->valid = 0; return; } cur = dup; while (*cur != 0) { str = cur; while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++; save = *cur; *cur = 0; id = xmlGetID(ctxt->doc, str); if (id == NULL) { xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID, "IDREFS attribute %s references an unknown ID \"%s\"\n", attr->name, str, NULL); ctxt->valid = 0; } if (save == 0) break; *cur = save; while (IS_BLANK_CH(*cur)) cur++; } xmlFree(dup); }}
/** * xmlWalkValidateList: * @data: Contents of current link * @user: Value supplied by the user * * Returns 0 to abort the walk or 1 to continue */static intxmlWalkValidateList(const void *data, void *user){ xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user; xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name); return 1;}
/** * xmlValidateCheckRefCallback: * @ref_list: List of references * @ctxt: Validation context * @name: Name of ID we are searching for * */static voidxmlValidateCheckRefCallback(void *payload, void *data, const xmlChar *name) { xmlListPtr ref_list = (xmlListPtr) payload; xmlValidCtxtPtr ctxt = (xmlValidCtxtPtr) data; xmlValidateMemo memo;
if (ref_list == NULL) return; memo.ctxt = ctxt; memo.name = name;
xmlListWalk(ref_list, xmlWalkValidateList, &memo);
}
/** * xmlValidateDocumentFinal: * @ctxt: the validation context * @doc: a document instance * * Does the final step for the document validation once all the * incremental validation steps have been completed * * basically it does the following checks described by the XML Rec * * Check all the IDREF/IDREFS attributes definition for validity * * returns 1 if valid or 0 otherwise */
intxmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { xmlRefTablePtr table; unsigned int save;
if (ctxt == NULL) return(0); if (doc == NULL) { xmlErrValid(ctxt, XML_DTD_NO_DOC, "xmlValidateDocumentFinal: doc == NULL\n", NULL); return(0); }
/* trick to get correct line id report */ save = ctxt->flags; ctxt->flags &= ~XML_VCTXT_USE_PCTXT;
/* * Check all the NOTATION/NOTATIONS attributes */ /* * Check all the ENTITY/ENTITIES attributes definition for validity */ /* * Check all the IDREF/IDREFS attributes definition for validity */ table = (xmlRefTablePtr) doc->refs; ctxt->doc = doc; ctxt->valid = 1; xmlHashScan(table, xmlValidateCheckRefCallback, ctxt);
ctxt->flags = save; return(ctxt->valid);}
/** * xmlValidateDtd: * @ctxt: the validation context * @doc: a document instance * @dtd: a dtd instance * * Try to validate the document against the dtd instance * * Basically it does check all the definitions in the DtD. * Note the the internal subset (if present) is de-coupled * (i.e. not used), which could give problems if ID or IDREF * is present. * * returns 1 if valid or 0 otherwise */
intxmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) { int ret; xmlDtdPtr oldExt, oldInt; xmlNodePtr root;
if (dtd == NULL) return(0); if (doc == NULL) return(0); oldExt = doc->extSubset; oldInt = doc->intSubset; doc->extSubset = dtd; doc->intSubset = NULL; ret = xmlValidateRoot(ctxt, doc); if (ret == 0) { doc->extSubset = oldExt; doc->intSubset = oldInt; return(ret); } if (doc->ids != NULL) { xmlFreeIDTable(doc->ids); doc->ids = NULL; } if (doc->refs != NULL) { xmlFreeRefTable(doc->refs); doc->refs = NULL; } root = xmlDocGetRootElement(doc); ret = xmlValidateElement(ctxt, doc, root); ret &= xmlValidateDocumentFinal(ctxt, doc); doc->extSubset = oldExt; doc->intSubset = oldInt; return(ret);}
static voidxmlValidateNotationCallback(void *payload, void *data, const xmlChar *name ATTRIBUTE_UNUSED) { xmlEntityPtr cur = (xmlEntityPtr) payload; xmlValidCtxtPtr ctxt = (xmlValidCtxtPtr) data; if (cur == NULL) return; if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) { xmlChar *notation = cur->content;
if (notation != NULL) { int ret;
ret = xmlValidateNotationUse(ctxt, cur->doc, notation); if (ret != 1) { ctxt->valid = 0; } } }}
static voidxmlValidateAttributeCallback(void *payload, void *data, const xmlChar *name ATTRIBUTE_UNUSED) { xmlAttributePtr cur = (xmlAttributePtr) payload; xmlValidCtxtPtr ctxt = (xmlValidCtxtPtr) data; int ret; xmlDocPtr doc; xmlElementPtr elem = NULL;
if (cur == NULL) return; switch (cur->atype) { case XML_ATTRIBUTE_CDATA: case XML_ATTRIBUTE_ID: case XML_ATTRIBUTE_IDREF : case XML_ATTRIBUTE_IDREFS: case XML_ATTRIBUTE_NMTOKEN: case XML_ATTRIBUTE_NMTOKENS: case XML_ATTRIBUTE_ENUMERATION: break; case XML_ATTRIBUTE_ENTITY: case XML_ATTRIBUTE_ENTITIES: case XML_ATTRIBUTE_NOTATION: if (cur->defaultValue != NULL) {
ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name, cur->atype, cur->defaultValue); if ((ret == 0) && (ctxt->valid == 1)) ctxt->valid = 0; } if (cur->tree != NULL) { xmlEnumerationPtr tree = cur->tree; while (tree != NULL) { ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name, cur->atype, tree->name); if ((ret == 0) && (ctxt->valid == 1)) ctxt->valid = 0; tree = tree->next; } } } if (cur->atype == XML_ATTRIBUTE_NOTATION) { doc = cur->doc; if (cur->elem == NULL) { xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, "xmlValidateAttributeCallback(%s): internal error\n", (const char *) cur->name); return; }
if (doc != NULL) elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem); if ((elem == NULL) && (doc != NULL)) elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem); if ((elem == NULL) && (cur->parent != NULL) && (cur->parent->type == XML_DTD_NODE)) elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem); if (elem == NULL) { xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM, "attribute %s: could not find decl for element %s\n", cur->name, cur->elem, NULL); return; } if (elem->etype == XML_ELEMENT_TYPE_EMPTY) { xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION, "NOTATION attribute %s declared for EMPTY element %s\n", cur->name, cur->elem, NULL); ctxt->valid = 0; } }}
/** * xmlValidateDtdFinal: * @ctxt: the validation context * @doc: a document instance * * Does the final step for the dtds validation once all the * subsets have been parsed * * basically it does the following checks described by the XML Rec * - check that ENTITY and ENTITIES type attributes default or * possible values matches one of the defined entities. * - check that NOTATION type attributes default or * possible values matches one of the defined notations. * * returns 1 if valid or 0 if invalid and -1 if not well-formed */
intxmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { xmlDtdPtr dtd; xmlAttributeTablePtr table; xmlEntitiesTablePtr entities;
if ((doc == NULL) || (ctxt == NULL)) return(0); if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) return(0); ctxt->doc = doc; ctxt->valid = 1; dtd = doc->intSubset; if ((dtd != NULL) && (dtd->attributes != NULL)) { table = (xmlAttributeTablePtr) dtd->attributes; xmlHashScan(table, xmlValidateAttributeCallback, ctxt); } if ((dtd != NULL) && (dtd->entities != NULL)) { entities = (xmlEntitiesTablePtr) dtd->entities; xmlHashScan(entities, xmlValidateNotationCallback, ctxt); } dtd = doc->extSubset; if ((dtd != NULL) && (dtd->attributes != NULL)) { table = (xmlAttributeTablePtr) dtd->attributes; xmlHashScan(table, xmlValidateAttributeCallback, ctxt); } if ((dtd != NULL) && (dtd->entities != NULL)) { entities = (xmlEntitiesTablePtr) dtd->entities; xmlHashScan(entities, xmlValidateNotationCallback, ctxt); } return(ctxt->valid);}
/** * xmlValidateDocument: * @ctxt: the validation context * @doc: a document instance * * Try to validate the document instance * * basically it does the all the checks described by the XML Rec * i.e. validates the internal and external subset (if present) * and validate the document tree. * * returns 1 if valid or 0 otherwise */
intxmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { int ret; xmlNodePtr root;
if (doc == NULL) return(0); if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) { xmlErrValid(ctxt, XML_DTD_NO_DTD, "no DTD found!\n", NULL); return(0); } if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) || (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) { xmlChar *sysID; if (doc->intSubset->SystemID != NULL) { sysID = xmlBuildURI(doc->intSubset->SystemID, doc->URL); if (sysID == NULL) { xmlErrValid(ctxt, XML_DTD_LOAD_ERROR, "Could not build URI for external subset \"%s\"\n", (const char *) doc->intSubset->SystemID); return 0; } } else sysID = NULL; doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID, (const xmlChar *)sysID); if (sysID != NULL) xmlFree(sysID); if (doc->extSubset == NULL) { if (doc->intSubset->SystemID != NULL) { xmlErrValid(ctxt, XML_DTD_LOAD_ERROR, "Could not load the external subset \"%s\"\n", (const char *) doc->intSubset->SystemID); } else { xmlErrValid(ctxt, XML_DTD_LOAD_ERROR, "Could not load the external subset \"%s\"\n", (const char *) doc->intSubset->ExternalID); } return(0); } }
if (doc->ids != NULL) { xmlFreeIDTable(doc->ids); doc->ids = NULL; } if (doc->refs != NULL) { xmlFreeRefTable(doc->refs); doc->refs = NULL; } ret = xmlValidateDtdFinal(ctxt, doc); if (!xmlValidateRoot(ctxt, doc)) return(0);
root = xmlDocGetRootElement(doc); ret &= xmlValidateElement(ctxt, doc, root); ret &= xmlValidateDocumentFinal(ctxt, doc); return(ret);}
/************************************************************************ * * * Routines for dynamic validation editing * * * ************************************************************************/
/** * xmlValidGetPotentialChildren: * @ctree: an element content tree * @names: an array to store the list of child names * @len: a pointer to the number of element in the list * @max: the size of the array * * Build/extend a list of potential children allowed by the content tree * * returns the number of element in the list, or -1 in case of error. */
intxmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **names, int *len, int max) { int i;
if ((ctree == NULL) || (names == NULL) || (len == NULL)) return(-1); if (*len >= max) return(*len);
switch (ctree->type) { case XML_ELEMENT_CONTENT_PCDATA: for (i = 0; i < *len;i++) if (xmlStrEqual(BAD_CAST "#PCDATA", names[i])) return(*len); names[(*len)++] = BAD_CAST "#PCDATA"; break; case XML_ELEMENT_CONTENT_ELEMENT: for (i = 0; i < *len;i++) if (xmlStrEqual(ctree->name, names[i])) return(*len); names[(*len)++] = ctree->name; break; case XML_ELEMENT_CONTENT_SEQ: xmlValidGetPotentialChildren(ctree->c1, names, len, max); xmlValidGetPotentialChildren(ctree->c2, names, len, max); break; case XML_ELEMENT_CONTENT_OR: xmlValidGetPotentialChildren(ctree->c1, names, len, max); xmlValidGetPotentialChildren(ctree->c2, names, len, max); break; }
return(*len);}
/* * Dummy function to suppress messages while we try out valid elements */static void xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED, const char *msg ATTRIBUTE_UNUSED, ...) { return;}
/** * xmlValidGetValidElements: * @prev: an element to insert after * @next: an element to insert next * @names: an array to store the list of child names * @max: the size of the array * * This function returns the list of authorized children to insert * within an existing tree while respecting the validity constraints * forced by the Dtd. The insertion point is defined using @prev and * @next in the following ways: * to insert before 'node': xmlValidGetValidElements(node->prev, node, ... * to insert next 'node': xmlValidGetValidElements(node, node->next, ... * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ... * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs, * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ... * * pointers to the element names are inserted at the beginning of the array * and do not need to be freed. * * returns the number of element in the list, or -1 in case of error. If * the function returns the value @max the caller is invited to grow the * receiving array and retry. */
intxmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names, int max) { xmlValidCtxt vctxt; int nb_valid_elements = 0; const xmlChar *elements[256]={0}; int nb_elements = 0, i; const xmlChar *name;
xmlNode *ref_node; xmlNode *parent; xmlNode *test_node;
xmlNode *prev_next; xmlNode *next_prev; xmlNode *parent_childs; xmlNode *parent_last;
xmlElement *element_desc;
if (prev == NULL && next == NULL) return(-1);
if (names == NULL) return(-1); if (max <= 0) return(-1);
memset(&vctxt, 0, sizeof (xmlValidCtxt)); vctxt.error = xmlNoValidityErr; /* this suppresses err/warn output */
nb_valid_elements = 0; ref_node = prev ? prev : next; parent = ref_node->parent;
/* * Retrieves the parent element declaration */ element_desc = xmlGetDtdElementDesc(parent->doc->intSubset, parent->name); if ((element_desc == NULL) && (parent->doc->extSubset != NULL)) element_desc = xmlGetDtdElementDesc(parent->doc->extSubset, parent->name); if (element_desc == NULL) return(-1);
/* * Do a backup of the current tree structure */ prev_next = prev ? prev->next : NULL; next_prev = next ? next->prev : NULL; parent_childs = parent->children; parent_last = parent->last;
/* * Creates a dummy node and insert it into the tree */ test_node = xmlNewDocNode (ref_node->doc, NULL, BAD_CAST "<!dummy?>", NULL); if (test_node == NULL) return(-1);
test_node->parent = parent; test_node->prev = prev; test_node->next = next; name = test_node->name;
if (prev) prev->next = test_node; else parent->children = test_node;
if (next) next->prev = test_node; else parent->last = test_node;
/* * Insert each potential child node and check if the parent is * still valid */ nb_elements = xmlValidGetPotentialChildren(element_desc->content, elements, &nb_elements, 256);
for (i = 0;i < nb_elements;i++) { test_node->name = elements[i]; if (xmlValidateOneElement(&vctxt, parent->doc, parent)) { int j;
for (j = 0; j < nb_valid_elements;j++) if (xmlStrEqual(elements[i], names[j])) break; names[nb_valid_elements++] = elements[i]; if (nb_valid_elements >= max) break; } }
/* * Restore the tree structure */ if (prev) prev->next = prev_next; if (next) next->prev = next_prev; parent->children = parent_childs; parent->last = parent_last;
/* * Free up the dummy node */ test_node->name = name; xmlFreeNode(test_node);
return(nb_valid_elements);}#endif /* LIBXML_VALID_ENABLED */