Something went wrong. Try again.
Reactos
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732147331473414735147361473714738147391474014741147421474314744147451474614747147481474914750147511475214753147541475514756147571475814759147601476114762147631476414765147661476714768147691477014771147721477314774147751477614777147781477914780147811478214783147841478514786147871478814789147901479114792147931479414795147961479714798147991480014801148021480314804148051480614807148081480914810148111481214813148141481514816148171481814819148201482114822148231482414825148261482714828148291483014831148321483314834148351483614837148381483914840148411484214843148441484514846148471484814849148501485114852148531485414855148561485714858148591486014861148621486314864148651486614867148681486914870148711487214873148741487514876148771487814879148801488114882148831488414885148861488714888148891489014891148921489314894148951489614897148981489914900149011490214903149041490514906149071490814909149101491114912149131491414915149161491714918149191492014921149221492314924149251492614927149281492914930149311493214933149341493514936149371493814939149401494114942149431494414945149461494714948149491495014951149521495314954149551495614957149581495914960149611496214963149641496514966149671496814969149701497114972149731497414975149761497714978149791498014981149821498314984149851498614987149881498914990149911499214993149941499514996149971499814999150001500115002150031500415005150061500715008150091501015011150121501315014150151501615017150181501915020150211502215023150241502515026150271502815029150301503115032150331503415035150361503715038150391504015041150421504315044150451504615047150481504915050150511505215053150541505515056150571505815059150601506115062150631506415065150661506715068150691507015071150721507315074150751507615077150781507915080150811508215083150841508515086150871508815089150901509115092150931509415095150961509715098150991510015101151021510315104151051510615107151081510915110151111511215113151141511515116151171511815119151201512115122151231512415125151261512715128151291513015131151321513315134151351513615137151381513915140151411514215143151441514515146151471514815149/* * parser.c : an XML 1.0 parser, namespaces and validity support are mostly * implemented on top of the SAX interfaces * * References: * The XML specification: * http://www.w3.org/TR/REC-xml * Original 1.0 version: * http://www.w3.org/TR/1998/REC-xml-19980210 * XML second edition working draft * http://www.w3.org/TR/2000/WD-xml-2e-20000814 * * Okay this is a big file, the parser core is around 7000 lines, then it * is followed by the progressive parser top routines, then the various * high level APIs to call the parser and a few miscellaneous functions. * A number of helper functions and deprecated ones have been moved to * parserInternals.c to reduce this file size. * As much as possible the functions are associated with their relative * production in the XML specification. A few productions defining the * different ranges of character are actually implanted either in * parserInternals.h or parserInternals.c * The DOM tree build is realized from the default SAX callbacks in * the module SAX.c. * The routines doing the validation checks are in valid.c and called either * from the SAX callbacks or as standalone functions using a preparsed * document. * * See Copyright for the status of this software. * * daniel@veillard.com */
/* To avoid EBCDIC trouble when parsing on zOS */#if defined(__MVS__)#pragma convert("ISO8859-1")#endif
#define IN_LIBXML#include "libxml.h"
#if defined(_WIN32)#define XML_DIR_SEP '\\'#else#define XML_DIR_SEP '/'#endif
#include <stdlib.h>#include <limits.h>#include <string.h>#include <stdarg.h>#include <stddef.h>#include <ctype.h>#include <stdlib.h>#include <libxml/parser.h>#include <libxml/xmlmemory.h>#include <libxml/tree.h>#include <libxml/parserInternals.h>#include <libxml/valid.h>#include <libxml/entities.h>#include <libxml/xmlerror.h>#include <libxml/encoding.h>#include <libxml/xmlIO.h>#include <libxml/uri.h>#include <libxml/SAX2.h>#ifdef LIBXML_CATALOG_ENABLED#include <libxml/catalog.h>#endif
#include "private/buf.h"#include "private/dict.h"#include "private/entities.h"#include "private/error.h"#include "private/html.h"#include "private/io.h"#include "private/parser.h"
#define NS_INDEX_EMPTY INT_MAX#define NS_INDEX_XML (INT_MAX - 1)#define URI_HASH_EMPTY 0xD943A04E#define URI_HASH_XML 0xF0451F02
struct _xmlStartTag { const xmlChar *prefix; const xmlChar *URI; int line; int nsNr;};
typedef struct { void *saxData; unsigned prefixHashValue; unsigned uriHashValue; unsigned elementId; int oldIndex;} xmlParserNsExtra;
typedef struct { unsigned hashValue; int index;} xmlParserNsBucket;
struct _xmlParserNsData { xmlParserNsExtra *extra;
unsigned hashSize; unsigned hashElems; xmlParserNsBucket *hash;
unsigned elementId; int defaultNsIndex;};
struct _xmlAttrHashBucket { int index;};
static xmlParserCtxtPtrxmlCreateEntityParserCtxtInternal(xmlSAXHandlerPtr sax, void *userData, const xmlChar *URL, const xmlChar *ID, const xmlChar *base, xmlParserCtxtPtr pctx);
static intxmlParseElementStart(xmlParserCtxtPtr ctxt);
static voidxmlParseElementEnd(xmlParserCtxtPtr ctxt);
/************************************************************************ * * * Arbitrary limits set in the parser. See XML_PARSE_HUGE * * * ************************************************************************/
#define XML_PARSER_BIG_ENTITY 1000#define XML_PARSER_LOT_ENTITY 5000
/* * Constants for protection against abusive entity expansion * ("billion laughs"). */
/* * A certain amount of entity expansion which is always allowed. */#define XML_PARSER_ALLOWED_EXPANSION 1000000
/* * Fixed cost for each entity reference. This crudely models processing time * as well to protect, for example, against exponential expansion of empty * or very short entities. */#define XML_ENT_FIXED_COST 20
/** * xmlParserMaxDepth: * * arbitrary depth limit for the XML documents that we allow to * process. This is not a limitation of the parser but a safety * boundary feature. It can be disabled with the XML_PARSE_HUGE * parser option. */unsigned int xmlParserMaxDepth = 256;
#define XML_PARSER_BIG_BUFFER_SIZE 300#define XML_PARSER_BUFFER_SIZE 100#define SAX_COMPAT_MODE BAD_CAST "SAX compatibility mode document"
/** * XML_PARSER_CHUNK_SIZE * * When calling GROW that's the minimal amount of data * the parser expected to have received. It is not a hard * limit but an optimization when reading strings like Names * It is not strictly needed as long as inputs available characters * are followed by 0, which should be provided by the I/O level */#define XML_PARSER_CHUNK_SIZE 100
/** * xmlParserVersion: * * Constant string describing the internal version of the library */const char *constxmlParserVersion = LIBXML_VERSION_STRING LIBXML_VERSION_EXTRA;
/* * List of XML prefixed PI allowed by W3C specs */
static const char* const xmlW3CPIs[] = { "xml-stylesheet", "xml-model", NULL};
/* DEPR void xmlParserHandleReference(xmlParserCtxtPtr ctxt); */static xmlEntityPtr xmlParseStringPEReference(xmlParserCtxtPtr ctxt, const xmlChar **str);
static xmlParserErrorsxmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt, xmlSAXHandlerPtr sax, void *user_data, int depth, const xmlChar *URL, const xmlChar *ID, xmlNodePtr *list);
static intxmlCtxtUseOptionsInternal(xmlParserCtxtPtr ctxt, int options);#ifdef LIBXML_LEGACY_ENABLEDstatic voidxmlAddEntityReference(xmlEntityPtr ent, xmlNodePtr firstNode, xmlNodePtr lastNode);#endif /* LIBXML_LEGACY_ENABLED */
static xmlParserErrorsxmlParseBalancedChunkMemoryInternal(xmlParserCtxtPtr oldctxt, const xmlChar *string, void *user_data, xmlNodePtr *lst);
static intxmlLoadEntityContent(xmlParserCtxtPtr ctxt, xmlEntityPtr entity);
/************************************************************************ * * * Some factorized error routines * * * ************************************************************************/
/** * xmlErrAttributeDup: * @ctxt: an XML parser context * @prefix: the attribute prefix * @localname: the attribute localname * * Handle a redefinition of attribute error */static voidxmlErrAttributeDup(xmlParserCtxtPtr ctxt, const xmlChar * prefix, const xmlChar * localname){ if ((ctxt != NULL) && (ctxt->disableSAX != 0) && (ctxt->instate == XML_PARSER_EOF)) return; if (ctxt != NULL) ctxt->errNo = XML_ERR_ATTRIBUTE_REDEFINED;
if (prefix == NULL) __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, XML_ERR_ATTRIBUTE_REDEFINED, XML_ERR_FATAL, NULL, 0, (const char *) localname, NULL, NULL, 0, 0, "Attribute %s redefined\n", localname); else __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, XML_ERR_ATTRIBUTE_REDEFINED, XML_ERR_FATAL, NULL, 0, (const char *) prefix, (const char *) localname, NULL, 0, 0, "Attribute %s:%s redefined\n", prefix, localname); if (ctxt != NULL) { ctxt->wellFormed = 0; if (ctxt->recovery == 0) ctxt->disableSAX = 1; }}
/** * xmlFatalErrMsg: * @ctxt: an XML parser context * @error: the error number * @msg: the error message * * Handle a fatal parser error, i.e. violating Well-Formedness constraints */static void LIBXML_ATTR_FORMAT(3,0)xmlFatalErrMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg){ if ((ctxt != NULL) && (ctxt->disableSAX != 0) && (ctxt->instate == XML_PARSER_EOF)) return; if (ctxt != NULL) ctxt->errNo = error; __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0, "%s", msg); if (ctxt != NULL) { ctxt->wellFormed = 0; if (ctxt->recovery == 0) ctxt->disableSAX = 1; }}
/** * xmlWarningMsg: * @ctxt: an XML parser context * @error: the error number * @msg: the error message * @str1: extra data * @str2: extra data * * Handle a warning. */void LIBXML_ATTR_FORMAT(3,0)xmlWarningMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, const xmlChar *str1, const xmlChar *str2){ xmlStructuredErrorFunc schannel = NULL;
if ((ctxt != NULL) && (ctxt->disableSAX != 0) && (ctxt->instate == XML_PARSER_EOF)) return; if ((ctxt != NULL) && (ctxt->sax != NULL) && (ctxt->sax->initialized == XML_SAX2_MAGIC)) schannel = ctxt->sax->serror; if (ctxt != NULL) { __xmlRaiseError(schannel, (ctxt->sax) ? ctxt->sax->warning : NULL, ctxt->userData, ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_WARNING, NULL, 0, (const char *) str1, (const char *) str2, NULL, 0, 0, msg, (const char *) str1, (const char *) str2); } else { __xmlRaiseError(schannel, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_WARNING, NULL, 0, (const char *) str1, (const char *) str2, NULL, 0, 0, msg, (const char *) str1, (const char *) str2); }}
/** * xmlValidityError: * @ctxt: an XML parser context * @error: the error number * @msg: the error message * @str1: extra data * * Handle a validity error. */static void LIBXML_ATTR_FORMAT(3,0)xmlValidityError(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, const xmlChar *str1, const xmlChar *str2){ xmlStructuredErrorFunc schannel = NULL;
if ((ctxt != NULL) && (ctxt->disableSAX != 0) && (ctxt->instate == XML_PARSER_EOF)) return; if (ctxt != NULL) { ctxt->errNo = error; if ((ctxt->sax != NULL) && (ctxt->sax->initialized == XML_SAX2_MAGIC)) schannel = ctxt->sax->serror; } if (ctxt != NULL) { __xmlRaiseError(schannel, ctxt->vctxt.error, ctxt->vctxt.userData, ctxt, NULL, XML_FROM_DTD, error, XML_ERR_ERROR, NULL, 0, (const char *) str1, (const char *) str2, NULL, 0, 0, msg, (const char *) str1, (const char *) str2); ctxt->valid = 0; } else { __xmlRaiseError(schannel, NULL, NULL, ctxt, NULL, XML_FROM_DTD, error, XML_ERR_ERROR, NULL, 0, (const char *) str1, (const char *) str2, NULL, 0, 0, msg, (const char *) str1, (const char *) str2); }}
/** * xmlFatalErrMsgInt: * @ctxt: an XML parser context * @error: the error number * @msg: the error message * @val: an integer value * * Handle a fatal parser error, i.e. violating Well-Formedness constraints */static void LIBXML_ATTR_FORMAT(3,0)xmlFatalErrMsgInt(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, int val){ if ((ctxt != NULL) && (ctxt->disableSAX != 0) && (ctxt->instate == XML_PARSER_EOF)) return; if (ctxt != NULL) ctxt->errNo = error; __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, val, 0, msg, val); if (ctxt != NULL) { ctxt->wellFormed = 0; if (ctxt->recovery == 0) ctxt->disableSAX = 1; }}
/** * xmlFatalErrMsgStrIntStr: * @ctxt: an XML parser context * @error: the error number * @msg: the error message * @str1: an string info * @val: an integer value * @str2: an string info * * Handle a fatal parser error, i.e. violating Well-Formedness constraints */static void LIBXML_ATTR_FORMAT(3,0)xmlFatalErrMsgStrIntStr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, const xmlChar *str1, int val, const xmlChar *str2){ if ((ctxt != NULL) && (ctxt->disableSAX != 0) && (ctxt->instate == XML_PARSER_EOF)) return; if (ctxt != NULL) ctxt->errNo = error; __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL, NULL, 0, (const char *) str1, (const char *) str2, NULL, val, 0, msg, str1, val, str2); if (ctxt != NULL) { ctxt->wellFormed = 0; if (ctxt->recovery == 0) ctxt->disableSAX = 1; }}
/** * xmlFatalErrMsgStr: * @ctxt: an XML parser context * @error: the error number * @msg: the error message * @val: a string value * * Handle a fatal parser error, i.e. violating Well-Formedness constraints */static void LIBXML_ATTR_FORMAT(3,0)xmlFatalErrMsgStr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, const xmlChar * val){ if ((ctxt != NULL) && (ctxt->disableSAX != 0) && (ctxt->instate == XML_PARSER_EOF)) return; if (ctxt != NULL) ctxt->errNo = error; __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL, NULL, 0, (const char *) val, NULL, NULL, 0, 0, msg, val); if (ctxt != NULL) { ctxt->wellFormed = 0; if (ctxt->recovery == 0) ctxt->disableSAX = 1; }}
/** * xmlErrMsgStr: * @ctxt: an XML parser context * @error: the error number * @msg: the error message * @val: a string value * * Handle a non fatal parser error */static void LIBXML_ATTR_FORMAT(3,0)xmlErrMsgStr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, const xmlChar * val){ if ((ctxt != NULL) && (ctxt->disableSAX != 0) && (ctxt->instate == XML_PARSER_EOF)) return; if (ctxt != NULL) ctxt->errNo = error; __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_ERROR, NULL, 0, (const char *) val, NULL, NULL, 0, 0, msg, val);}
/** * xmlNsErr: * @ctxt: an XML parser context * @error: the error number * @msg: the message * @info1: extra information string * @info2: extra information string * * Handle a fatal parser error, i.e. violating Well-Formedness constraints */static void LIBXML_ATTR_FORMAT(3,0)xmlNsErr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, const xmlChar * info1, const xmlChar * info2, const xmlChar * info3){ if ((ctxt != NULL) && (ctxt->disableSAX != 0) && (ctxt->instate == XML_PARSER_EOF)) return; if (ctxt != NULL) ctxt->errNo = error; __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_NAMESPACE, error, XML_ERR_ERROR, NULL, 0, (const char *) info1, (const char *) info2, (const char *) info3, 0, 0, msg, info1, info2, info3); if (ctxt != NULL) ctxt->nsWellFormed = 0;}
/** * xmlNsWarn * @ctxt: an XML parser context * @error: the error number * @msg: the message * @info1: extra information string * @info2: extra information string * * Handle a namespace warning error */static void LIBXML_ATTR_FORMAT(3,0)xmlNsWarn(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, const xmlChar * info1, const xmlChar * info2, const xmlChar * info3){ if ((ctxt != NULL) && (ctxt->disableSAX != 0) && (ctxt->instate == XML_PARSER_EOF)) return; __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_NAMESPACE, error, XML_ERR_WARNING, NULL, 0, (const char *) info1, (const char *) info2, (const char *) info3, 0, 0, msg, info1, info2, info3);}
static voidxmlSaturatedAdd(unsigned long *dst, unsigned long val) { if (val > ULONG_MAX - *dst) *dst = ULONG_MAX; else *dst += val;}
static voidxmlSaturatedAddSizeT(unsigned long *dst, unsigned long val) { if (val > ULONG_MAX - *dst) *dst = ULONG_MAX; else *dst += val;}
/** * xmlParserEntityCheck: * @ctxt: parser context * @extra: sum of unexpanded entity sizes * * Check for non-linear entity expansion behaviour. * * In some cases like xmlStringDecodeEntities, this function is called * for each, possibly nested entity and its unexpanded content length. * * In other cases like xmlParseReference, it's only called for each * top-level entity with its unexpanded content length plus the sum of * the unexpanded content lengths (plus fixed cost) of all nested * entities. * * Summing the unexpanded lengths also adds the length of the reference. * This is by design. Taking the length of the entity name into account * discourages attacks that try to waste CPU time with abusively long * entity names. See test/recurse/lol6.xml for example. Each call also * adds some fixed cost XML_ENT_FIXED_COST to discourage attacks with * short entities. * * Returns 1 on error, 0 on success. */static intxmlParserEntityCheck(xmlParserCtxtPtr ctxt, unsigned long extra){ unsigned long consumed; xmlParserInputPtr input = ctxt->input; xmlEntityPtr entity = input->entity;
/* * Compute total consumed bytes so far, including input streams of * external entities. */ consumed = input->parentConsumed; if ((entity == NULL) || ((entity->etype == XML_EXTERNAL_PARAMETER_ENTITY) && ((entity->flags & XML_ENT_PARSED) == 0))) { xmlSaturatedAdd(&consumed, input->consumed); xmlSaturatedAddSizeT(&consumed, input->cur - input->base); } xmlSaturatedAdd(&consumed, ctxt->sizeentities);
/* * Add extra cost and some fixed cost. */ xmlSaturatedAdd(&ctxt->sizeentcopy, extra); xmlSaturatedAdd(&ctxt->sizeentcopy, XML_ENT_FIXED_COST);
/* * It's important to always use saturation arithmetic when tracking * entity sizes to make the size checks reliable. If "sizeentcopy" * overflows, we have to abort. */ if ((ctxt->sizeentcopy > XML_PARSER_ALLOWED_EXPANSION) && ((ctxt->sizeentcopy >= ULONG_MAX) || (ctxt->sizeentcopy / ctxt->maxAmpl > consumed))) { xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_LOOP, "Maximum entity amplification factor exceeded, see " "xmlCtxtSetMaxAmplification.\n"); xmlHaltParser(ctxt); return(1); }
return(0);}
/************************************************************************ * * * Library wide options * * * ************************************************************************/
/** * xmlHasFeature: * @feature: the feature to be examined * * Examines if the library has been compiled with a given feature. * * Returns a non-zero value if the feature exist, otherwise zero. * Returns zero (0) if the feature does not exist or an unknown * unknown feature is requested, non-zero otherwise. */intxmlHasFeature(xmlFeature feature){ switch (feature) { case XML_WITH_THREAD:#ifdef LIBXML_THREAD_ENABLED return(1);#else return(0);#endif case XML_WITH_TREE:#ifdef LIBXML_TREE_ENABLED return(1);#else return(0);#endif case XML_WITH_OUTPUT:#ifdef LIBXML_OUTPUT_ENABLED return(1);#else return(0);#endif case XML_WITH_PUSH:#ifdef LIBXML_PUSH_ENABLED return(1);#else return(0);#endif case XML_WITH_READER:#ifdef LIBXML_READER_ENABLED return(1);#else return(0);#endif case XML_WITH_PATTERN:#ifdef LIBXML_PATTERN_ENABLED return(1);#else return(0);#endif case XML_WITH_WRITER:#ifdef LIBXML_WRITER_ENABLED return(1);#else return(0);#endif case XML_WITH_SAX1:#ifdef LIBXML_SAX1_ENABLED return(1);#else return(0);#endif case XML_WITH_FTP:#ifdef LIBXML_FTP_ENABLED return(1);#else return(0);#endif case XML_WITH_HTTP:#ifdef LIBXML_HTTP_ENABLED return(1);#else return(0);#endif case XML_WITH_VALID:#ifdef LIBXML_VALID_ENABLED return(1);#else return(0);#endif case XML_WITH_HTML:#ifdef LIBXML_HTML_ENABLED return(1);#else return(0);#endif case XML_WITH_LEGACY:#ifdef LIBXML_LEGACY_ENABLED return(1);#else return(0);#endif case XML_WITH_C14N:#ifdef LIBXML_C14N_ENABLED return(1);#else return(0);#endif case XML_WITH_CATALOG:#ifdef LIBXML_CATALOG_ENABLED return(1);#else return(0);#endif case XML_WITH_XPATH:#ifdef LIBXML_XPATH_ENABLED return(1);#else return(0);#endif case XML_WITH_XPTR:#ifdef LIBXML_XPTR_ENABLED return(1);#else return(0);#endif case XML_WITH_XINCLUDE:#ifdef LIBXML_XINCLUDE_ENABLED return(1);#else return(0);#endif case XML_WITH_ICONV:#ifdef LIBXML_ICONV_ENABLED return(1);#else return(0);#endif case XML_WITH_ISO8859X:#ifdef LIBXML_ISO8859X_ENABLED return(1);#else return(0);#endif case XML_WITH_UNICODE:#ifdef LIBXML_UNICODE_ENABLED return(1);#else return(0);#endif case XML_WITH_REGEXP:#ifdef LIBXML_REGEXP_ENABLED return(1);#else return(0);#endif case XML_WITH_AUTOMATA:#ifdef LIBXML_AUTOMATA_ENABLED return(1);#else return(0);#endif case XML_WITH_EXPR:#ifdef LIBXML_EXPR_ENABLED return(1);#else return(0);#endif case XML_WITH_SCHEMAS:#ifdef LIBXML_SCHEMAS_ENABLED return(1);#else return(0);#endif case XML_WITH_SCHEMATRON:#ifdef LIBXML_SCHEMATRON_ENABLED return(1);#else return(0);#endif case XML_WITH_MODULES:#ifdef LIBXML_MODULES_ENABLED return(1);#else return(0);#endif case XML_WITH_DEBUG:#ifdef LIBXML_DEBUG_ENABLED return(1);#else return(0);#endif case XML_WITH_DEBUG_MEM:#ifdef DEBUG_MEMORY_LOCATION return(1);#else return(0);#endif case XML_WITH_DEBUG_RUN: return(0); case XML_WITH_ZLIB:#ifdef LIBXML_ZLIB_ENABLED return(1);#else return(0);#endif case XML_WITH_LZMA:#ifdef LIBXML_LZMA_ENABLED return(1);#else return(0);#endif case XML_WITH_ICU:#ifdef LIBXML_ICU_ENABLED return(1);#else return(0);#endif default: break; } return(0);}
/************************************************************************ * * * SAX2 defaulted attributes handling * * * ************************************************************************/
/** * xmlDetectSAX2: * @ctxt: an XML parser context * * Do the SAX2 detection and specific initialization */static voidxmlDetectSAX2(xmlParserCtxtPtr ctxt) { xmlSAXHandlerPtr sax;
/* Avoid unused variable warning if features are disabled. */ (void) sax;
if (ctxt == NULL) return; sax = ctxt->sax;#ifdef LIBXML_SAX1_ENABLED /* * Only enable SAX2 if there SAX2 element handlers, except when there * are no element handlers at all. */ if ((sax) && (sax->initialized == XML_SAX2_MAGIC) && ((sax->startElementNs != NULL) || (sax->endElementNs != NULL) || ((sax->startElement == NULL) && (sax->endElement == NULL)))) ctxt->sax2 = 1;#else ctxt->sax2 = 1;#endif /* LIBXML_SAX1_ENABLED */
ctxt->str_xml = xmlDictLookup(ctxt->dict, BAD_CAST "xml", 3); ctxt->str_xmlns = xmlDictLookup(ctxt->dict, BAD_CAST "xmlns", 5); ctxt->str_xml_ns = xmlDictLookup(ctxt->dict, XML_XML_NAMESPACE, 36); if ((ctxt->str_xml==NULL) || (ctxt->str_xmlns==NULL) || (ctxt->str_xml_ns == NULL)) { xmlErrMemory(ctxt, NULL); }}
typedef struct { xmlHashedString prefix; xmlHashedString name; xmlHashedString value; const xmlChar *valueEnd; int external; int expandedSize;} xmlDefAttr;
typedef struct _xmlDefAttrs xmlDefAttrs;typedef xmlDefAttrs *xmlDefAttrsPtr;struct _xmlDefAttrs { int nbAttrs; /* number of defaulted attributes on that element */ int maxAttrs; /* the size of the array */#if __STDC_VERSION__ >= 199901L /* Using a C99 flexible array member avoids UBSan errors. */ xmlDefAttr attrs[]; /* array of localname/prefix/values/external */#else xmlDefAttr attrs[1];#endif};
/** * xmlAttrNormalizeSpace: * @src: the source string * @dst: the target string * * Normalize the space in non CDATA attribute values: * If the attribute type 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 a single space (#x20) character. * Note that the size of dst need to be at least src, and if one doesn't need * to preserve dst (and it doesn't come from a dictionary or read-only) then * passing src as dst is just fine. * * Returns a pointer to the normalized value (dst) or NULL if no conversion * is needed. */static xmlChar *xmlAttrNormalizeSpace(const xmlChar *src, xmlChar *dst){ if ((src == NULL) || (dst == NULL)) return(NULL);
while (*src == 0x20) src++; while (*src != 0) { if (*src == 0x20) { while (*src == 0x20) src++; if (*src != 0) *dst++ = 0x20; } else { *dst++ = *src++; } } *dst = 0; if (dst == src) return(NULL); return(dst);}
/** * xmlAttrNormalizeSpace2: * @src: the source string * * Normalize the space in non CDATA attribute values, a slightly more complex * front end to avoid allocation problems when running on attribute values * coming from the input. * * Returns a pointer to the normalized value (dst) or NULL if no conversion * is needed. */static const xmlChar *xmlAttrNormalizeSpace2(xmlParserCtxtPtr ctxt, xmlChar *src, int *len){ int i; int remove_head = 0; int need_realloc = 0; const xmlChar *cur;
if ((ctxt == NULL) || (src == NULL) || (len == NULL)) return(NULL); i = *len; if (i <= 0) return(NULL);
cur = src; while (*cur == 0x20) { cur++; remove_head++; } while (*cur != 0) { if (*cur == 0x20) { cur++; if ((*cur == 0x20) || (*cur == 0)) { need_realloc = 1; break; } } else cur++; } if (need_realloc) { xmlChar *ret;
ret = xmlStrndup(src + remove_head, i - remove_head + 1); if (ret == NULL) { xmlErrMemory(ctxt, NULL); return(NULL); } xmlAttrNormalizeSpace(ret, ret); *len = strlen((const char *)ret); return(ret); } else if (remove_head) { *len -= remove_head; memmove(src, src + remove_head, 1 + *len); return(src); } return(NULL);}
/** * xmlAddDefAttrs: * @ctxt: an XML parser context * @fullname: the element fullname * @fullattr: the attribute fullname * @value: the attribute value * * Add a defaulted attribute for an element */static voidxmlAddDefAttrs(xmlParserCtxtPtr ctxt, const xmlChar *fullname, const xmlChar *fullattr, const xmlChar *value) { xmlDefAttrsPtr defaults; xmlDefAttr *attr; int len, expandedSize; xmlHashedString name; xmlHashedString prefix; xmlHashedString hvalue; const xmlChar *localname;
/* * Allows to detect attribute redefinitions */ if (ctxt->attsSpecial != NULL) { if (xmlHashLookup2(ctxt->attsSpecial, fullname, fullattr) != NULL) return; }
if (ctxt->attsDefault == NULL) { ctxt->attsDefault = xmlHashCreateDict(10, ctxt->dict); if (ctxt->attsDefault == NULL) goto mem_error; }
/* * split the element name into prefix:localname , the string found * are within the DTD and then not associated to namespace names. */ localname = xmlSplitQName3(fullname, &len); if (localname == NULL) { name = xmlDictLookupHashed(ctxt->dict, fullname, -1); prefix.name = NULL; } else { name = xmlDictLookupHashed(ctxt->dict, localname, -1); prefix = xmlDictLookupHashed(ctxt->dict, fullname, len); if (prefix.name == NULL) goto mem_error; } if (name.name == NULL) goto mem_error;
/* * make sure there is some storage */ defaults = xmlHashLookup2(ctxt->attsDefault, name.name, prefix.name); if ((defaults == NULL) || (defaults->nbAttrs >= defaults->maxAttrs)) { xmlDefAttrsPtr temp; int newSize;
newSize = (defaults != NULL) ? 2 * defaults->maxAttrs : 4; temp = xmlRealloc(defaults, sizeof(*defaults) + newSize * sizeof(xmlDefAttr)); if (temp == NULL) goto mem_error; if (defaults == NULL) temp->nbAttrs = 0; temp->maxAttrs = newSize; defaults = temp; if (xmlHashUpdateEntry2(ctxt->attsDefault, name.name, prefix.name, defaults, NULL) < 0) { xmlFree(defaults); goto mem_error; } }
/* * Split the attribute name into prefix:localname , the string found * are within the DTD and hen not associated to namespace names. */ localname = xmlSplitQName3(fullattr, &len); if (localname == NULL) { name = xmlDictLookupHashed(ctxt->dict, fullattr, -1); prefix.name = NULL; } else { name = xmlDictLookupHashed(ctxt->dict, localname, -1); prefix = xmlDictLookupHashed(ctxt->dict, fullattr, len); if (prefix.name == NULL) goto mem_error; } if (name.name == NULL) goto mem_error;
/* intern the string and precompute the end */ len = strlen((const char *) value); hvalue = xmlDictLookupHashed(ctxt->dict, value, len); if (hvalue.name == NULL) goto mem_error;
expandedSize = strlen((const char *) name.name); if (prefix.name != NULL) expandedSize += strlen((const char *) prefix.name); expandedSize += len;
attr = &defaults->attrs[defaults->nbAttrs++]; attr->name = name; attr->prefix = prefix; attr->value = hvalue; attr->valueEnd = hvalue.name + len; attr->external = ctxt->external; attr->expandedSize = expandedSize;
return;
mem_error: xmlErrMemory(ctxt, NULL); return;}
/** * xmlAddSpecialAttr: * @ctxt: an XML parser context * @fullname: the element fullname * @fullattr: the attribute fullname * @type: the attribute type * * Register this attribute type */static voidxmlAddSpecialAttr(xmlParserCtxtPtr ctxt, const xmlChar *fullname, const xmlChar *fullattr, int type){ if (ctxt->attsSpecial == NULL) { ctxt->attsSpecial = xmlHashCreateDict(10, ctxt->dict); if (ctxt->attsSpecial == NULL) goto mem_error; }
if (xmlHashLookup2(ctxt->attsSpecial, fullname, fullattr) != NULL) return;
xmlHashAddEntry2(ctxt->attsSpecial, fullname, fullattr, (void *) (ptrdiff_t) type); return;
mem_error: xmlErrMemory(ctxt, NULL); return;}
/** * xmlCleanSpecialAttrCallback: * * Removes CDATA attributes from the special attribute table */static voidxmlCleanSpecialAttrCallback(void *payload, void *data, const xmlChar *fullname, const xmlChar *fullattr, const xmlChar *unused ATTRIBUTE_UNUSED) { xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) data;
if (((ptrdiff_t) payload) == XML_ATTRIBUTE_CDATA) { xmlHashRemoveEntry2(ctxt->attsSpecial, fullname, fullattr, NULL); }}
/** * xmlCleanSpecialAttr: * @ctxt: an XML parser context * * Trim the list of attributes defined to remove all those of type * CDATA as they are not special. This call should be done when finishing * to parse the DTD and before starting to parse the document root. */static voidxmlCleanSpecialAttr(xmlParserCtxtPtr ctxt){ if (ctxt->attsSpecial == NULL) return;
xmlHashScanFull(ctxt->attsSpecial, xmlCleanSpecialAttrCallback, ctxt);
if (xmlHashSize(ctxt->attsSpecial) == 0) { xmlHashFree(ctxt->attsSpecial, NULL); ctxt->attsSpecial = NULL; } return;}
/** * xmlCheckLanguageID: * @lang: pointer to the string value * * DEPRECATED: Internal function, do not use. * * Checks that the value conforms to the LanguageID production: * * NOTE: this is somewhat deprecated, those productions were removed from * the XML Second edition. * * [33] LanguageID ::= Langcode ('-' Subcode)* * [34] Langcode ::= ISO639Code | IanaCode | UserCode * [35] ISO639Code ::= ([a-z] | [A-Z]) ([a-z] | [A-Z]) * [36] IanaCode ::= ('i' | 'I') '-' ([a-z] | [A-Z])+ * [37] UserCode ::= ('x' | 'X') '-' ([a-z] | [A-Z])+ * [38] Subcode ::= ([a-z] | [A-Z])+ * * The current REC reference the successors of RFC 1766, currently 5646 * * http://www.rfc-editor.org/rfc/rfc5646.txt * langtag = language * ["-" script] * ["-" region] * *("-" variant) * *("-" extension) * ["-" privateuse] * language = 2*3ALPHA ; shortest ISO 639 code * ["-" extlang] ; sometimes followed by * ; extended language subtags * / 4ALPHA ; or reserved for future use * / 5*8ALPHA ; or registered language subtag * * extlang = 3ALPHA ; selected ISO 639 codes * *2("-" 3ALPHA) ; permanently reserved * * script = 4ALPHA ; ISO 15924 code * * region = 2ALPHA ; ISO 3166-1 code * / 3DIGIT ; UN M.49 code * * variant = 5*8alphanum ; registered variants * / (DIGIT 3alphanum) * * extension = singleton 1*("-" (2*8alphanum)) * * ; Single alphanumerics * ; "x" reserved for private use * singleton = DIGIT ; 0 - 9 * / %x41-57 ; A - W * / %x59-5A ; Y - Z * / %x61-77 ; a - w * / %x79-7A ; y - z * * it sounds right to still allow Irregular i-xxx IANA and user codes too * The parser below doesn't try to cope with extension or privateuse * that could be added but that's not interoperable anyway * * Returns 1 if correct 0 otherwise **/intxmlCheckLanguageID(const xmlChar * lang){ const xmlChar *cur = lang, *nxt;
if (cur == NULL) return (0); if (((cur[0] == 'i') && (cur[1] == '-')) || ((cur[0] == 'I') && (cur[1] == '-')) || ((cur[0] == 'x') && (cur[1] == '-')) || ((cur[0] == 'X') && (cur[1] == '-'))) { /* * Still allow IANA code and user code which were coming * from the previous version of the XML-1.0 specification * it's deprecated but we should not fail */ cur += 2; while (((cur[0] >= 'A') && (cur[0] <= 'Z')) || ((cur[0] >= 'a') && (cur[0] <= 'z'))) cur++; return(cur[0] == 0); } nxt = cur; while (((nxt[0] >= 'A') && (nxt[0] <= 'Z')) || ((nxt[0] >= 'a') && (nxt[0] <= 'z'))) nxt++; if (nxt - cur >= 4) { /* * Reserved */ if ((nxt - cur > 8) || (nxt[0] != 0)) return(0); return(1); } if (nxt - cur < 2) return(0); /* we got an ISO 639 code */ if (nxt[0] == 0) return(1); if (nxt[0] != '-') return(0);
nxt++; cur = nxt; /* now we can have extlang or script or region or variant */ if ((nxt[0] >= '0') && (nxt[0] <= '9')) goto region_m49;
while (((nxt[0] >= 'A') && (nxt[0] <= 'Z')) || ((nxt[0] >= 'a') && (nxt[0] <= 'z'))) nxt++; if (nxt - cur == 4) goto script; if (nxt - cur == 2) goto region; if ((nxt - cur >= 5) && (nxt - cur <= 8)) goto variant; if (nxt - cur != 3) return(0); /* we parsed an extlang */ if (nxt[0] == 0) return(1); if (nxt[0] != '-') return(0);
nxt++; cur = nxt; /* now we can have script or region or variant */ if ((nxt[0] >= '0') && (nxt[0] <= '9')) goto region_m49;
while (((nxt[0] >= 'A') && (nxt[0] <= 'Z')) || ((nxt[0] >= 'a') && (nxt[0] <= 'z'))) nxt++; if (nxt - cur == 2) goto region; if ((nxt - cur >= 5) && (nxt - cur <= 8)) goto variant; if (nxt - cur != 4) return(0); /* we parsed a script */script: if (nxt[0] == 0) return(1); if (nxt[0] != '-') return(0);
nxt++; cur = nxt; /* now we can have region or variant */ if ((nxt[0] >= '0') && (nxt[0] <= '9')) goto region_m49;
while (((nxt[0] >= 'A') && (nxt[0] <= 'Z')) || ((nxt[0] >= 'a') && (nxt[0] <= 'z'))) nxt++;
if ((nxt - cur >= 5) && (nxt - cur <= 8)) goto variant; if (nxt - cur != 2) return(0); /* we parsed a region */region: if (nxt[0] == 0) return(1); if (nxt[0] != '-') return(0);
nxt++; cur = nxt; /* now we can just have a variant */ while (((nxt[0] >= 'A') && (nxt[0] <= 'Z')) || ((nxt[0] >= 'a') && (nxt[0] <= 'z'))) nxt++;
if ((nxt - cur < 5) || (nxt - cur > 8)) return(0);
/* we parsed a variant */variant: if (nxt[0] == 0) return(1); if (nxt[0] != '-') return(0); /* extensions and private use subtags not checked */ return (1);
region_m49: if (((nxt[1] >= '0') && (nxt[1] <= '9')) && ((nxt[2] >= '0') && (nxt[2] <= '9'))) { nxt += 3; goto region; } return(0);}
/************************************************************************ * * * Parser stacks related functions and macros * * * ************************************************************************/
static xmlEntityPtr xmlParseStringEntityRef(xmlParserCtxtPtr ctxt, const xmlChar ** str);
/** * xmlParserNsCreate: * * Create a new namespace database. * * Returns the new obejct. */xmlParserNsData *xmlParserNsCreate(void) { xmlParserNsData *nsdb = xmlMalloc(sizeof(*nsdb));
if (nsdb == NULL) return(NULL); memset(nsdb, 0, sizeof(*nsdb)); nsdb->defaultNsIndex = INT_MAX;
return(nsdb);}
/** * xmlParserNsFree: * @nsdb: namespace database * * Free a namespace database. */voidxmlParserNsFree(xmlParserNsData *nsdb) { if (nsdb == NULL) return;
xmlFree(nsdb->extra); xmlFree(nsdb->hash); xmlFree(nsdb);}
/** * xmlParserNsReset: * @nsdb: namespace database * * Reset a namespace database. */static voidxmlParserNsReset(xmlParserNsData *nsdb) { if (nsdb == NULL) return;
nsdb->hashElems = 0; nsdb->elementId = 0; nsdb->defaultNsIndex = INT_MAX;
if (nsdb->hash) memset(nsdb->hash, 0, nsdb->hashSize * sizeof(nsdb->hash[0]));}
/** * xmlParserStartElement: * @nsdb: namespace database * * Signal that a new element has started. * * Returns 0 on success, -1 if the element counter overflowed. */static intxmlParserNsStartElement(xmlParserNsData *nsdb) { if (nsdb->elementId == UINT_MAX) return(-1); nsdb->elementId++;
return(0);}
/** * xmlParserNsLookup: * @ctxt: parser context * @prefix: namespace prefix * @bucketPtr: optional bucket (return value) * * Lookup namespace with given prefix. If @bucketPtr is non-NULL, it will * be set to the matching bucket, or the first empty bucket if no match * was found. * * Returns the namespace index on success, INT_MAX if no namespace was * found. */static intxmlParserNsLookup(xmlParserCtxtPtr ctxt, const xmlHashedString *prefix, xmlParserNsBucket **bucketPtr) { xmlParserNsBucket *bucket, *tombstone; unsigned index, hashValue;
if (prefix->name == NULL) return(ctxt->nsdb->defaultNsIndex);
if (ctxt->nsdb->hashSize == 0) return(INT_MAX);
hashValue = prefix->hashValue; index = hashValue & (ctxt->nsdb->hashSize - 1); bucket = &ctxt->nsdb->hash[index]; tombstone = NULL;
while (bucket->hashValue) { if (bucket->index == INT_MAX) { if (tombstone == NULL) tombstone = bucket; } else if (bucket->hashValue == hashValue) { if (ctxt->nsTab[bucket->index * 2] == prefix->name) { if (bucketPtr != NULL) *bucketPtr = bucket; return(bucket->index); } }
index++; bucket++; if (index == ctxt->nsdb->hashSize) { index = 0; bucket = ctxt->nsdb->hash; } }
if (bucketPtr != NULL) *bucketPtr = tombstone ? tombstone : bucket; return(INT_MAX);}
/** * xmlParserNsLookupUri: * @ctxt: parser context * @prefix: namespace prefix * * Lookup namespace URI with given prefix. * * Returns the namespace URI on success, NULL if no namespace was found. */static const xmlChar *xmlParserNsLookupUri(xmlParserCtxtPtr ctxt, const xmlHashedString *prefix) { const xmlChar *ret; int nsIndex;
if (prefix->name == ctxt->str_xml) return(ctxt->str_xml_ns);
nsIndex = xmlParserNsLookup(ctxt, prefix, NULL); if (nsIndex == INT_MAX) return(NULL);
ret = ctxt->nsTab[nsIndex * 2 + 1]; if (ret[0] == 0) ret = NULL; return(ret);}
/** * xmlParserNsLookupSax: * @ctxt: parser context * @prefix: namespace prefix * * Lookup extra data for the given prefix. This returns data stored * with xmlParserNsUdpateSax. * * Returns the data on success, NULL if no namespace was found. */void *xmlParserNsLookupSax(xmlParserCtxtPtr ctxt, const xmlChar *prefix) { xmlHashedString hprefix; int nsIndex;
if (prefix == ctxt->str_xml) return(NULL);
hprefix.name = prefix; if (prefix != NULL) hprefix.hashValue = xmlDictComputeHash(ctxt->dict, prefix); else hprefix.hashValue = 0; nsIndex = xmlParserNsLookup(ctxt, &hprefix, NULL); if (nsIndex == INT_MAX) return(NULL);
return(ctxt->nsdb->extra[nsIndex].saxData);}
/** * xmlParserNsUpdateSax: * @ctxt: parser context * @prefix: namespace prefix * @saxData: extra data for SAX handler * * Sets or updates extra data for the given prefix. This value will be * returned by xmlParserNsLookupSax as long as the namespace with the * given prefix is in scope. * * Returns the data on success, NULL if no namespace was found. */intxmlParserNsUpdateSax(xmlParserCtxtPtr ctxt, const xmlChar *prefix, void *saxData) { xmlHashedString hprefix; int nsIndex;
if (prefix == ctxt->str_xml) return(-1);
hprefix.name = prefix; if (prefix != NULL) hprefix.hashValue = xmlDictComputeHash(ctxt->dict, prefix); else hprefix.hashValue = 0; nsIndex = xmlParserNsLookup(ctxt, &hprefix, NULL); if (nsIndex == INT_MAX) return(-1);
ctxt->nsdb->extra[nsIndex].saxData = saxData; return(0);}
/** * xmlParserNsGrow: * @ctxt: parser context * * Grows the namespace tables. * * Returns 0 on success, -1 if a memory allocation failed. */static intxmlParserNsGrow(xmlParserCtxtPtr ctxt) { const xmlChar **table; xmlParserNsExtra *extra; int newSize;
if (ctxt->nsMax > INT_MAX / 2) goto error; newSize = ctxt->nsMax ? ctxt->nsMax * 2 : 16;
table = xmlRealloc(ctxt->nsTab, 2 * newSize * sizeof(table[0])); if (table == NULL) goto error; ctxt->nsTab = table;
extra = xmlRealloc(ctxt->nsdb->extra, newSize * sizeof(extra[0])); if (extra == NULL) goto error; ctxt->nsdb->extra = extra;
ctxt->nsMax = newSize; return(0);
error: xmlErrMemory(ctxt, NULL); return(-1);}
/** * xmlParserNsPush: * @ctxt: parser context * @prefix: prefix with hash value * @uri: uri with hash value * @saxData: extra data for SAX handler * @defAttr: whether the namespace comes from a default attribute * * Push a new namespace on the table. * * Returns 1 if the namespace was pushed, 0 if the namespace was ignored, * -1 if a memory allocation failed. */static intxmlParserNsPush(xmlParserCtxtPtr ctxt, const xmlHashedString *prefix, const xmlHashedString *uri, void *saxData, int defAttr) { xmlParserNsBucket *bucket = NULL; xmlParserNsExtra *extra; const xmlChar **ns; unsigned hashValue, nsIndex, oldIndex;
if ((prefix != NULL) && (prefix->name == ctxt->str_xml)) return(0);
if ((ctxt->nsNr >= ctxt->nsMax) && (xmlParserNsGrow(ctxt) < 0)) { xmlErrMemory(ctxt, NULL); return(-1); }
/* * Default namespace and 'xml' namespace */ if ((prefix == NULL) || (prefix->name == NULL)) { oldIndex = ctxt->nsdb->defaultNsIndex;
if (oldIndex != INT_MAX) { extra = &ctxt->nsdb->extra[oldIndex];
if (extra->elementId == ctxt->nsdb->elementId) { if (defAttr == 0) xmlErrAttributeDup(ctxt, NULL, BAD_CAST "xmlns"); return(0); }
if ((ctxt->options & XML_PARSE_NSCLEAN) && (uri->name == ctxt->nsTab[oldIndex * 2 + 1])) return(0); }
ctxt->nsdb->defaultNsIndex = ctxt->nsNr; goto populate_entry; }
/* * Hash table lookup */ oldIndex = xmlParserNsLookup(ctxt, prefix, &bucket); if (oldIndex != INT_MAX) { extra = &ctxt->nsdb->extra[oldIndex];
/* * Check for duplicate definitions on the same element. */ if (extra->elementId == ctxt->nsdb->elementId) { if (defAttr == 0) xmlErrAttributeDup(ctxt, BAD_CAST "xmlns", prefix->name); return(0); }
if ((ctxt->options & XML_PARSE_NSCLEAN) && (uri->name == ctxt->nsTab[bucket->index * 2 + 1])) return(0);
bucket->index = ctxt->nsNr; goto populate_entry; }
/* * Insert new bucket */
hashValue = prefix->hashValue;
/* * Grow hash table, 50% fill factor */ if (ctxt->nsdb->hashElems + 1 > ctxt->nsdb->hashSize / 2) { xmlParserNsBucket *newHash; unsigned newSize, i, index;
if (ctxt->nsdb->hashSize > UINT_MAX / 2) { xmlErrMemory(ctxt, NULL); return(-1); } newSize = ctxt->nsdb->hashSize ? ctxt->nsdb->hashSize * 2 : 16; newHash = xmlMalloc(newSize * sizeof(newHash[0])); if (newHash == NULL) { xmlErrMemory(ctxt, NULL); return(-1); } memset(newHash, 0, newSize * sizeof(newHash[0]));
for (i = 0; i < ctxt->nsdb->hashSize; i++) { unsigned hv = ctxt->nsdb->hash[i].hashValue; unsigned newIndex;
if ((hv == 0) || (ctxt->nsdb->hash[i].index == INT_MAX)) continue; newIndex = hv & (newSize - 1);
while (newHash[newIndex].hashValue != 0) { newIndex++; if (newIndex == newSize) newIndex = 0; }
newHash[newIndex] = ctxt->nsdb->hash[i]; }
xmlFree(ctxt->nsdb->hash); ctxt->nsdb->hash = newHash; ctxt->nsdb->hashSize = newSize;
/* * Relookup */ index = hashValue & (newSize - 1);
while (newHash[index].hashValue != 0) { index++; if (index == newSize) index = 0; }
bucket = &newHash[index]; }
bucket->hashValue = hashValue; bucket->index = ctxt->nsNr; ctxt->nsdb->hashElems++; oldIndex = INT_MAX;
populate_entry: nsIndex = ctxt->nsNr;
ns = &ctxt->nsTab[nsIndex * 2]; ns[0] = prefix ? prefix->name : NULL; ns[1] = uri->name;
extra = &ctxt->nsdb->extra[nsIndex]; extra->saxData = saxData; extra->prefixHashValue = prefix ? prefix->hashValue : 0; extra->uriHashValue = uri->hashValue; extra->elementId = ctxt->nsdb->elementId; extra->oldIndex = oldIndex;
ctxt->nsNr++;
return(1);}
/** * xmlParserNsPop: * @ctxt: an XML parser context * @nr: the number to pop * * Pops the top @nr namespaces and restores the hash table. * * Returns the number of namespaces popped. */static intxmlParserNsPop(xmlParserCtxtPtr ctxt, int nr){ int i;
/* assert(nr <= ctxt->nsNr); */
for (i = ctxt->nsNr - 1; i >= ctxt->nsNr - nr; i--) { const xmlChar *prefix = ctxt->nsTab[i * 2]; xmlParserNsExtra *extra = &ctxt->nsdb->extra[i];
if (prefix == NULL) { ctxt->nsdb->defaultNsIndex = extra->oldIndex; } else { xmlHashedString hprefix; xmlParserNsBucket *bucket = NULL;
hprefix.name = prefix; hprefix.hashValue = extra->prefixHashValue; xmlParserNsLookup(ctxt, &hprefix, &bucket); /* assert(bucket && bucket->hashValue); */ bucket->index = extra->oldIndex; } }
ctxt->nsNr -= nr; return(nr);}
static intxmlCtxtGrowAttrs(xmlParserCtxtPtr ctxt, int nr) { const xmlChar **atts; unsigned *attallocs; int maxatts;
if (nr + 5 > ctxt->maxatts) { maxatts = ctxt->maxatts == 0 ? 55 : (nr + 5) * 2; atts = (const xmlChar **) xmlMalloc( maxatts * sizeof(const xmlChar *)); if (atts == NULL) goto mem_error; attallocs = xmlRealloc(ctxt->attallocs, (maxatts / 5) * sizeof(attallocs[0])); if (attallocs == NULL) { xmlFree(atts); goto mem_error; } if (ctxt->maxatts > 0) memcpy(atts, ctxt->atts, ctxt->maxatts * sizeof(const xmlChar *)); xmlFree(ctxt->atts); ctxt->atts = atts; ctxt->attallocs = attallocs; ctxt->maxatts = maxatts; } return(ctxt->maxatts);mem_error: xmlErrMemory(ctxt, NULL); return(-1);}
/** * inputPush: * @ctxt: an XML parser context * @value: the parser input * * Pushes a new parser input on top of the input stack * * Returns -1 in case of error, the index in the stack otherwise */intinputPush(xmlParserCtxtPtr ctxt, xmlParserInputPtr value){ if ((ctxt == NULL) || (value == NULL)) return(-1); if (ctxt->inputNr >= ctxt->inputMax) { size_t newSize = ctxt->inputMax * 2; xmlParserInputPtr *tmp;
tmp = (xmlParserInputPtr *) xmlRealloc(ctxt->inputTab, newSize * sizeof(*tmp)); if (tmp == NULL) { xmlErrMemory(ctxt, NULL); return (-1); } ctxt->inputTab = tmp; ctxt->inputMax = newSize; } ctxt->inputTab[ctxt->inputNr] = value; ctxt->input = value; return (ctxt->inputNr++);}/** * inputPop: * @ctxt: an XML parser context * * Pops the top parser input from the input stack * * Returns the input just removed */xmlParserInputPtrinputPop(xmlParserCtxtPtr ctxt){ xmlParserInputPtr ret;
if (ctxt == NULL) return(NULL); if (ctxt->inputNr <= 0) return (NULL); ctxt->inputNr--; if (ctxt->inputNr > 0) ctxt->input = ctxt->inputTab[ctxt->inputNr - 1]; else ctxt->input = NULL; ret = ctxt->inputTab[ctxt->inputNr]; ctxt->inputTab[ctxt->inputNr] = NULL; return (ret);}/** * nodePush: * @ctxt: an XML parser context * @value: the element node * * DEPRECATED: Internal function, do not use. * * Pushes a new element node on top of the node stack * * Returns -1 in case of error, the index in the stack otherwise */intnodePush(xmlParserCtxtPtr ctxt, xmlNodePtr value){ if (ctxt == NULL) return(0); if (ctxt->nodeNr >= ctxt->nodeMax) { xmlNodePtr *tmp;
tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab, ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0])); if (tmp == NULL) { xmlErrMemory(ctxt, NULL); return (-1); } ctxt->nodeTab = tmp; ctxt->nodeMax *= 2; } if ((((unsigned int) ctxt->nodeNr) > xmlParserMaxDepth) && ((ctxt->options & XML_PARSE_HUGE) == 0)) { xmlFatalErrMsgInt(ctxt, XML_ERR_INTERNAL_ERROR, "Excessive depth in document: %d use XML_PARSE_HUGE option\n", xmlParserMaxDepth); xmlHaltParser(ctxt); return(-1); } ctxt->nodeTab[ctxt->nodeNr] = value; ctxt->node = value; return (ctxt->nodeNr++);}
/** * nodePop: * @ctxt: an XML parser context * * DEPRECATED: Internal function, do not use. * * Pops the top element node from the node stack * * Returns the node just removed */xmlNodePtrnodePop(xmlParserCtxtPtr ctxt){ xmlNodePtr ret;
if (ctxt == NULL) return(NULL); 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);}
/** * nameNsPush: * @ctxt: an XML parser context * @value: the element name * @prefix: the element prefix * @URI: the element namespace name * @line: the current line number for error messages * @nsNr: the number of namespaces pushed on the namespace table * * Pushes a new element name/prefix/URL on top of the name stack * * Returns -1 in case of error, the index in the stack otherwise */static intnameNsPush(xmlParserCtxtPtr ctxt, const xmlChar * value, const xmlChar *prefix, const xmlChar *URI, int line, int nsNr){ xmlStartTag *tag;
if (ctxt->nameNr >= ctxt->nameMax) { const xmlChar * *tmp; xmlStartTag *tmp2; ctxt->nameMax *= 2; tmp = (const xmlChar * *) xmlRealloc((xmlChar * *)ctxt->nameTab, ctxt->nameMax * sizeof(ctxt->nameTab[0])); if (tmp == NULL) { ctxt->nameMax /= 2; goto mem_error; } ctxt->nameTab = tmp; tmp2 = (xmlStartTag *) xmlRealloc((void * *)ctxt->pushTab, ctxt->nameMax * sizeof(ctxt->pushTab[0])); if (tmp2 == NULL) { ctxt->nameMax /= 2; goto mem_error; } ctxt->pushTab = tmp2; } else if (ctxt->pushTab == NULL) { ctxt->pushTab = (xmlStartTag *) xmlMalloc(ctxt->nameMax * sizeof(ctxt->pushTab[0])); if (ctxt->pushTab == NULL) goto mem_error; } ctxt->nameTab[ctxt->nameNr] = value; ctxt->name = value; tag = &ctxt->pushTab[ctxt->nameNr]; tag->prefix = prefix; tag->URI = URI; tag->line = line; tag->nsNr = nsNr; return (ctxt->nameNr++);mem_error: xmlErrMemory(ctxt, NULL); return (-1);}#ifdef LIBXML_PUSH_ENABLED/** * nameNsPop: * @ctxt: an XML parser context * * Pops the top element/prefix/URI name from the name stack * * Returns the name just removed */static const xmlChar *nameNsPop(xmlParserCtxtPtr ctxt){ const xmlChar *ret;
if (ctxt->nameNr <= 0) return (NULL); ctxt->nameNr--; if (ctxt->nameNr > 0) ctxt->name = ctxt->nameTab[ctxt->nameNr - 1]; else ctxt->name = NULL; ret = ctxt->nameTab[ctxt->nameNr]; ctxt->nameTab[ctxt->nameNr] = NULL; return (ret);}#endif /* LIBXML_PUSH_ENABLED */
/** * namePush: * @ctxt: an XML parser context * @value: the element name * * DEPRECATED: Internal function, do not use. * * Pushes a new element name on top of the name stack * * Returns -1 in case of error, the index in the stack otherwise */intnamePush(xmlParserCtxtPtr ctxt, const xmlChar * value){ if (ctxt == NULL) return (-1);
if (ctxt->nameNr >= ctxt->nameMax) { const xmlChar * *tmp; tmp = (const xmlChar * *) xmlRealloc((xmlChar * *)ctxt->nameTab, ctxt->nameMax * 2 * sizeof(ctxt->nameTab[0])); if (tmp == NULL) { goto mem_error; } ctxt->nameTab = tmp; ctxt->nameMax *= 2; } ctxt->nameTab[ctxt->nameNr] = value; ctxt->name = value; return (ctxt->nameNr++);mem_error: xmlErrMemory(ctxt, NULL); return (-1);}
/** * namePop: * @ctxt: an XML parser context * * DEPRECATED: Internal function, do not use. * * Pops the top element name from the name stack * * Returns the name just removed */const xmlChar *namePop(xmlParserCtxtPtr ctxt){ const xmlChar *ret;
if ((ctxt == NULL) || (ctxt->nameNr <= 0)) return (NULL); ctxt->nameNr--; if (ctxt->nameNr > 0) ctxt->name = ctxt->nameTab[ctxt->nameNr - 1]; else ctxt->name = NULL; ret = ctxt->nameTab[ctxt->nameNr]; ctxt->nameTab[ctxt->nameNr] = NULL; return (ret);}
static int spacePush(xmlParserCtxtPtr ctxt, int val) { if (ctxt->spaceNr >= ctxt->spaceMax) { int *tmp;
ctxt->spaceMax *= 2; tmp = (int *) xmlRealloc(ctxt->spaceTab, ctxt->spaceMax * sizeof(ctxt->spaceTab[0])); if (tmp == NULL) { xmlErrMemory(ctxt, NULL); ctxt->spaceMax /=2; return(-1); } ctxt->spaceTab = tmp; } ctxt->spaceTab[ctxt->spaceNr] = val; ctxt->space = &ctxt->spaceTab[ctxt->spaceNr]; return(ctxt->spaceNr++);}
static int spacePop(xmlParserCtxtPtr ctxt) { int ret; if (ctxt->spaceNr <= 0) return(0); ctxt->spaceNr--; if (ctxt->spaceNr > 0) ctxt->space = &ctxt->spaceTab[ctxt->spaceNr - 1]; else ctxt->space = &ctxt->spaceTab[0]; ret = ctxt->spaceTab[ctxt->spaceNr]; ctxt->spaceTab[ctxt->spaceNr] = -1; return(ret);}
/* * Macros for accessing the content. Those should be used only by the parser, * and not exported. * * Dirty macros, i.e. one often need to make assumption on the context to * use them * * CUR_PTR return the current pointer to the xmlChar to be parsed. * To be used with extreme caution since operations consuming * characters may move the input buffer to a different location ! * CUR returns the current xmlChar value, i.e. a 8 bit value if compiled * This should be used internally by the parser * only to compare to ASCII values otherwise it would break when * running with UTF-8 encoding. * RAW same as CUR but in the input buffer, bypass any token * extraction that may have been done * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only * to compare on ASCII based substring. * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined * strings without newlines within the parser. * NEXT1(l) Skip 1 xmlChar, and must also be used only to skip 1 non-newline ASCII * defined char within the parser. * Clean macros, not dependent of an ASCII context, expect UTF-8 encoding * * NEXT Skip to the next character, this does the proper decoding * in UTF-8 mode. It also pop-up unfinished entities on the fly. * NEXTL(l) Skip the current unicode character of l xmlChars long. * CUR_CHAR(l) returns the current unicode character (int), set l * to the number of xmlChars used for the encoding [0-5]. * CUR_SCHAR same but operate on a string instead of the context * COPY_BUF copy the current unicode char to the target buffer, increment * the index * GROW, SHRINK handling of input buffers */
#define RAW (*ctxt->input->cur)#define CUR (*ctxt->input->cur)#define NXT(val) ctxt->input->cur[(val)]#define CUR_PTR ctxt->input->cur#define BASE_PTR ctxt->input->base
#define CMP4( s, c1, c2, c3, c4 ) \ ( ((unsigned char *) s)[ 0 ] == c1 && ((unsigned char *) s)[ 1 ] == c2 && \ ((unsigned char *) s)[ 2 ] == c3 && ((unsigned char *) s)[ 3 ] == c4 )#define CMP5( s, c1, c2, c3, c4, c5 ) \ ( CMP4( s, c1, c2, c3, c4 ) && ((unsigned char *) s)[ 4 ] == c5 )#define CMP6( s, c1, c2, c3, c4, c5, c6 ) \ ( CMP5( s, c1, c2, c3, c4, c5 ) && ((unsigned char *) s)[ 5 ] == c6 )#define CMP7( s, c1, c2, c3, c4, c5, c6, c7 ) \ ( CMP6( s, c1, c2, c3, c4, c5, c6 ) && ((unsigned char *) s)[ 6 ] == c7 )#define CMP8( s, c1, c2, c3, c4, c5, c6, c7, c8 ) \ ( CMP7( s, c1, c2, c3, c4, c5, c6, c7 ) && ((unsigned char *) s)[ 7 ] == c8 )#define CMP9( s, c1, c2, c3, c4, c5, c6, c7, c8, c9 ) \ ( CMP8( s, c1, c2, c3, c4, c5, c6, c7, c8 ) && \ ((unsigned char *) s)[ 8 ] == c9 )#define CMP10( s, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10 ) \ ( CMP9( s, c1, c2, c3, c4, c5, c6, c7, c8, c9 ) && \ ((unsigned char *) s)[ 9 ] == c10 )
#define SKIP(val) do { \ ctxt->input->cur += (val),ctxt->input->col+=(val); \ if (*ctxt->input->cur == 0) \ xmlParserGrow(ctxt); \ } while (0)
#define SKIPL(val) do { \ int skipl; \ for(skipl=0; skipl<val; skipl++) { \ if (*(ctxt->input->cur) == '\n') { \ ctxt->input->line++; ctxt->input->col = 1; \ } else ctxt->input->col++; \ ctxt->input->cur++; \ } \ if (*ctxt->input->cur == 0) \ xmlParserGrow(ctxt); \ } while (0)
/* Don't shrink push parser buffer. */#define SHRINK \ if (((ctxt->progressive == 0) || (ctxt->inputNr > 1)) && \ (ctxt->input->cur - ctxt->input->base > 2 * INPUT_CHUNK) && \ (ctxt->input->end - ctxt->input->cur < 2 * INPUT_CHUNK)) \ xmlParserShrink(ctxt);
#define GROW if (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK) \ xmlParserGrow(ctxt);
#define SKIP_BLANKS xmlSkipBlankChars(ctxt)
#define NEXT xmlNextChar(ctxt)
#define NEXT1 { \ ctxt->input->col++; \ ctxt->input->cur++; \ if (*ctxt->input->cur == 0) \ xmlParserGrow(ctxt); \ }
#define NEXTL(l) do { \ if (*(ctxt->input->cur) == '\n') { \ ctxt->input->line++; ctxt->input->col = 1; \ } else ctxt->input->col++; \ ctxt->input->cur += l; \ } while (0)
#define CUR_CHAR(l) xmlCurrentChar(ctxt, &l)#define CUR_SCHAR(s, l) xmlStringCurrentChar(ctxt, s, &l)
#define COPY_BUF(b, i, v) \ if (v < 0x80) b[i++] = v; \ else i += xmlCopyCharMultiByte(&b[i],v)
/** * xmlSkipBlankChars: * @ctxt: the XML parser context * * DEPRECATED: Internal function, do not use. * * skip all blanks character found at that point in the input streams. * It pops up finished entities in the process if allowable at that point. * * Returns the number of space chars skipped */
intxmlSkipBlankChars(xmlParserCtxtPtr ctxt) { int res = 0;
/* * It's Okay to use CUR/NEXT here since all the blanks are on * the ASCII range. */ if (((ctxt->inputNr == 1) && (ctxt->instate != XML_PARSER_DTD)) || (ctxt->instate == XML_PARSER_START)) { const xmlChar *cur; /* * if we are in the document content, go really fast */ cur = ctxt->input->cur; while (IS_BLANK_CH(*cur)) { if (*cur == '\n') { ctxt->input->line++; ctxt->input->col = 1; } else { ctxt->input->col++; } cur++; if (res < INT_MAX) res++; if (*cur == 0) { ctxt->input->cur = cur; xmlParserGrow(ctxt); cur = ctxt->input->cur; } } ctxt->input->cur = cur; } else { int expandPE = ((ctxt->external != 0) || (ctxt->inputNr != 1));
while (ctxt->instate != XML_PARSER_EOF) { if (IS_BLANK_CH(CUR)) { /* CHECKED tstblanks.xml */ NEXT; } else if (CUR == '%') { /* * Need to handle support of entities branching here */ if ((expandPE == 0) || (IS_BLANK_CH(NXT(1))) || (NXT(1) == 0)) break; xmlParsePEReference(ctxt); } else if (CUR == 0) { unsigned long consumed; xmlEntityPtr ent;
if (ctxt->inputNr <= 1) break;
consumed = ctxt->input->consumed; xmlSaturatedAddSizeT(&consumed, ctxt->input->cur - ctxt->input->base);
/* * Add to sizeentities when parsing an external entity * for the first time. */ ent = ctxt->input->entity; if ((ent->etype == XML_EXTERNAL_PARAMETER_ENTITY) && ((ent->flags & XML_ENT_PARSED) == 0)) { ent->flags |= XML_ENT_PARSED;
xmlSaturatedAdd(&ctxt->sizeentities, consumed); }
xmlParserEntityCheck(ctxt, consumed);
xmlPopInput(ctxt); } else { break; }
/* * Also increase the counter when entering or exiting a PERef. * The spec says: "When a parameter-entity reference is recognized * in the DTD and included, its replacement text MUST be enlarged * by the attachment of one leading and one following space (#x20) * character." */ if (res < INT_MAX) res++; } } return(res);}
/************************************************************************ * * * Commodity functions to handle entities * * * ************************************************************************/
/** * xmlPopInput: * @ctxt: an XML parser context * * xmlPopInput: the current input pointed by ctxt->input came to an end * pop it and return the next char. * * Returns the current xmlChar in the parser context */xmlCharxmlPopInput(xmlParserCtxtPtr ctxt) { xmlParserInputPtr input;
if ((ctxt == NULL) || (ctxt->inputNr <= 1)) return(0); if (xmlParserDebugEntities) xmlGenericError(xmlGenericErrorContext, "Popping input %d\n", ctxt->inputNr); if ((ctxt->inputNr > 1) && (ctxt->inSubset == 0) && (ctxt->instate != XML_PARSER_EOF)) xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, "Unfinished entity outside the DTD"); input = inputPop(ctxt); if (input->entity != NULL) input->entity->flags &= ~XML_ENT_EXPANDING; xmlFreeInputStream(input); if (*ctxt->input->cur == 0) xmlParserGrow(ctxt); return(CUR);}
/** * xmlPushInput: * @ctxt: an XML parser context * @input: an XML parser input fragment (entity, XML fragment ...). * * xmlPushInput: switch to a new input stream which is stacked on top * of the previous one(s). * Returns -1 in case of error or the index in the input stack */intxmlPushInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr input) { int ret; if (input == NULL) return(-1);
if (xmlParserDebugEntities) { if ((ctxt->input != NULL) && (ctxt->input->filename)) xmlGenericError(xmlGenericErrorContext, "%s(%d): ", ctxt->input->filename, ctxt->input->line); xmlGenericError(xmlGenericErrorContext, "Pushing input %d : %.30s\n", ctxt->inputNr+1, input->cur); } if (((ctxt->inputNr > 40) && ((ctxt->options & XML_PARSE_HUGE) == 0)) || (ctxt->inputNr > 100)) { xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); while (ctxt->inputNr > 1) xmlFreeInputStream(inputPop(ctxt)); return(-1); } ret = inputPush(ctxt, input); if (ctxt->instate == XML_PARSER_EOF) return(-1); GROW; return(ret);}
/** * xmlParseCharRef: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * Parse a numeric character reference. Always consumes '&'. * * [66] CharRef ::= '&#' [0-9]+ ';' | * '&#x' [0-9a-fA-F]+ ';' * * [ WFC: Legal Character ] * Characters referred to using character references must match the * production for Char. * * Returns the value parsed (as an int), 0 in case of error */intxmlParseCharRef(xmlParserCtxtPtr ctxt) { int val = 0; int count = 0;
/* * Using RAW/CUR/NEXT is okay since we are working on ASCII range here */ if ((RAW == '&') && (NXT(1) == '#') && (NXT(2) == 'x')) { SKIP(3); GROW; while (RAW != ';') { /* loop blocked by count */ if (count++ > 20) { count = 0; GROW; if (ctxt->instate == XML_PARSER_EOF) return(0); } if ((RAW >= '0') && (RAW <= '9')) val = val * 16 + (CUR - '0'); else if ((RAW >= 'a') && (RAW <= 'f') && (count < 20)) val = val * 16 + (CUR - 'a') + 10; else if ((RAW >= 'A') && (RAW <= 'F') && (count < 20)) val = val * 16 + (CUR - 'A') + 10; else { xmlFatalErr(ctxt, XML_ERR_INVALID_HEX_CHARREF, NULL); val = 0; break; } if (val > 0x110000) val = 0x110000;
NEXT; count++; } if (RAW == ';') { /* on purpose to avoid reentrancy problems with NEXT and SKIP */ ctxt->input->col++; ctxt->input->cur++; } } else if ((RAW == '&') && (NXT(1) == '#')) { SKIP(2); GROW; while (RAW != ';') { /* loop blocked by count */ if (count++ > 20) { count = 0; GROW; if (ctxt->instate == XML_PARSER_EOF) return(0); } if ((RAW >= '0') && (RAW <= '9')) val = val * 10 + (CUR - '0'); else { xmlFatalErr(ctxt, XML_ERR_INVALID_DEC_CHARREF, NULL); val = 0; break; } if (val > 0x110000) val = 0x110000;
NEXT; count++; } if (RAW == ';') { /* on purpose to avoid reentrancy problems with NEXT and SKIP */ ctxt->input->col++; ctxt->input->cur++; } } else { if (RAW == '&') SKIP(1); xmlFatalErr(ctxt, XML_ERR_INVALID_CHARREF, NULL); }
/* * [ WFC: Legal Character ] * Characters referred to using character references must match the * production for Char. */ if (val >= 0x110000) { xmlFatalErrMsgInt(ctxt, XML_ERR_INVALID_CHAR, "xmlParseCharRef: character reference out of bounds\n", val); } else if (IS_CHAR(val)) { return(val); } else { xmlFatalErrMsgInt(ctxt, XML_ERR_INVALID_CHAR, "xmlParseCharRef: invalid xmlChar value %d\n", val); } return(0);}
/** * xmlParseStringCharRef: * @ctxt: an XML parser context * @str: a pointer to an index in the string * * parse Reference declarations, variant parsing from a string rather * than an an input flow. * * [66] CharRef ::= '&#' [0-9]+ ';' | * '&#x' [0-9a-fA-F]+ ';' * * [ WFC: Legal Character ] * Characters referred to using character references must match the * production for Char. * * Returns the value parsed (as an int), 0 in case of error, str will be * updated to the current value of the index */static intxmlParseStringCharRef(xmlParserCtxtPtr ctxt, const xmlChar **str) { const xmlChar *ptr; xmlChar cur; int val = 0;
if ((str == NULL) || (*str == NULL)) return(0); ptr = *str; cur = *ptr; if ((cur == '&') && (ptr[1] == '#') && (ptr[2] == 'x')) { ptr += 3; cur = *ptr; while (cur != ';') { /* Non input consuming loop */ if ((cur >= '0') && (cur <= '9')) val = val * 16 + (cur - '0'); else if ((cur >= 'a') && (cur <= 'f')) val = val * 16 + (cur - 'a') + 10; else if ((cur >= 'A') && (cur <= 'F')) val = val * 16 + (cur - 'A') + 10; else { xmlFatalErr(ctxt, XML_ERR_INVALID_HEX_CHARREF, NULL); val = 0; break; } if (val > 0x110000) val = 0x110000;
ptr++; cur = *ptr; } if (cur == ';') ptr++; } else if ((cur == '&') && (ptr[1] == '#')){ ptr += 2; cur = *ptr; while (cur != ';') { /* Non input consuming loops */ if ((cur >= '0') && (cur <= '9')) val = val * 10 + (cur - '0'); else { xmlFatalErr(ctxt, XML_ERR_INVALID_DEC_CHARREF, NULL); val = 0; break; } if (val > 0x110000) val = 0x110000;
ptr++; cur = *ptr; } if (cur == ';') ptr++; } else { xmlFatalErr(ctxt, XML_ERR_INVALID_CHARREF, NULL); return(0); } *str = ptr;
/* * [ WFC: Legal Character ] * Characters referred to using character references must match the * production for Char. */ if (val >= 0x110000) { xmlFatalErrMsgInt(ctxt, XML_ERR_INVALID_CHAR, "xmlParseStringCharRef: character reference out of bounds\n", val); } else if (IS_CHAR(val)) { return(val); } else { xmlFatalErrMsgInt(ctxt, XML_ERR_INVALID_CHAR, "xmlParseStringCharRef: invalid xmlChar value %d\n", val); } return(0);}
/** * xmlParserHandlePEReference: * @ctxt: the parser context * * DEPRECATED: Internal function, do not use. * * [69] PEReference ::= '%' Name ';' * * [ WFC: No Recursion ] * A parsed entity must not contain a recursive * reference to itself, either directly or indirectly. * * [ WFC: Entity Declared ] * In a document without any DTD, a document with only an internal DTD * subset which contains no parameter entity references, or a document * with "standalone='yes'", ... ... The declaration of a parameter * entity must precede any reference to it... * * [ VC: Entity Declared ] * In a document with an external subset or external parameter entities * with "standalone='no'", ... ... The declaration of a parameter entity * must precede any reference to it... * * [ WFC: In DTD ] * Parameter-entity references may only appear in the DTD. * NOTE: misleading but this is handled. * * A PEReference may have been detected in the current input stream * the handling is done accordingly to * http://www.w3.org/TR/REC-xml#entproc * i.e. * - Included in literal in entity values * - Included as Parameter Entity reference within DTDs */voidxmlParserHandlePEReference(xmlParserCtxtPtr ctxt) { switch(ctxt->instate) { case XML_PARSER_CDATA_SECTION: return; case XML_PARSER_COMMENT: return; case XML_PARSER_START_TAG: return; case XML_PARSER_END_TAG: return; case XML_PARSER_EOF: xmlFatalErr(ctxt, XML_ERR_PEREF_AT_EOF, NULL); return; case XML_PARSER_PROLOG: case XML_PARSER_START: case XML_PARSER_XML_DECL: case XML_PARSER_MISC: xmlFatalErr(ctxt, XML_ERR_PEREF_IN_PROLOG, NULL); return; case XML_PARSER_ENTITY_DECL: case XML_PARSER_CONTENT: case XML_PARSER_ATTRIBUTE_VALUE: case XML_PARSER_PI: case XML_PARSER_SYSTEM_LITERAL: case XML_PARSER_PUBLIC_LITERAL: /* we just ignore it there */ return; case XML_PARSER_EPILOG: xmlFatalErr(ctxt, XML_ERR_PEREF_IN_EPILOG, NULL); return; case XML_PARSER_ENTITY_VALUE: /* * NOTE: in the case of entity values, we don't do the * substitution here since we need the literal * entity value to be able to save the internal * subset of the document. * This will be handled by xmlStringDecodeEntities */ return; case XML_PARSER_DTD: /* * [WFC: Well-Formedness Constraint: PEs in Internal Subset] * In the internal DTD subset, parameter-entity references * can occur only where markup declarations can occur, not * within markup declarations. * In that case this is handled in xmlParseMarkupDecl */ if ((ctxt->external == 0) && (ctxt->inputNr == 1)) return; if (IS_BLANK_CH(NXT(1)) || NXT(1) == 0) return; break; case XML_PARSER_IGNORE: return; }
xmlParsePEReference(ctxt);}
/* * Macro used to grow the current buffer. * buffer##_size is expected to be a size_t * mem_error: is expected to handle memory allocation failures */#define growBuffer(buffer, n) { \ xmlChar *tmp; \ size_t new_size = buffer##_size * 2 + n; \ if (new_size < buffer##_size) goto mem_error; \ tmp = (xmlChar *) xmlRealloc(buffer, new_size); \ if (tmp == NULL) goto mem_error; \ buffer = tmp; \ buffer##_size = new_size; \}
/** * xmlStringDecodeEntitiesInt: * @ctxt: the parser context * @str: the input string * @len: the string length * @what: combination of XML_SUBSTITUTE_REF and XML_SUBSTITUTE_PEREF * @end: an end marker xmlChar, 0 if none * @end2: an end marker xmlChar, 0 if none * @end3: an end marker xmlChar, 0 if none * @check: whether to perform entity checks */static xmlChar *xmlStringDecodeEntitiesInt(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, int what, xmlChar end, xmlChar end2, xmlChar end3, int check) { xmlChar *buffer = NULL; size_t buffer_size = 0; size_t nbchars = 0;
xmlChar *current = NULL; xmlChar *rep = NULL; const xmlChar *last; xmlEntityPtr ent; int c,l;
if (str == NULL) return(NULL); last = str + len;
if (((ctxt->depth > 40) && ((ctxt->options & XML_PARSE_HUGE) == 0)) || (ctxt->depth > 100)) { xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_LOOP, "Maximum entity nesting depth exceeded"); return(NULL); }
/* * allocate a translation buffer. */ buffer_size = XML_PARSER_BIG_BUFFER_SIZE; buffer = (xmlChar *) xmlMallocAtomic(buffer_size); if (buffer == NULL) goto mem_error;
/* * OK loop until we reach one of the ending char or a size limit. * we are operating on already parsed values. */ if (str < last) c = CUR_SCHAR(str, l); else c = 0; while ((c != 0) && (c != end) && /* non input consuming loop */ (c != end2) && (c != end3) && (ctxt->instate != XML_PARSER_EOF)) {
if (c == 0) break; if ((c == '&') && (str[1] == '#')) { int val = xmlParseStringCharRef(ctxt, &str); if (val == 0) goto int_error; COPY_BUF(buffer, nbchars, val); if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { growBuffer(buffer, XML_PARSER_BUFFER_SIZE); } } else if ((c == '&') && (what & XML_SUBSTITUTE_REF)) { if (xmlParserDebugEntities) xmlGenericError(xmlGenericErrorContext, "String decoding Entity Reference: %.30s\n", str); ent = xmlParseStringEntityRef(ctxt, &str); if ((ent != NULL) && (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) { if (ent->content != NULL) { COPY_BUF(buffer, nbchars, ent->content[0]); if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { growBuffer(buffer, XML_PARSER_BUFFER_SIZE); } } else { xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR, "predefined entity has no content\n"); goto int_error; } } else if ((ent != NULL) && (ent->content != NULL)) { if ((check) && (xmlParserEntityCheck(ctxt, ent->length))) goto int_error;
if (ent->flags & XML_ENT_EXPANDING) { xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); xmlHaltParser(ctxt); ent->content[0] = 0; goto int_error; }
ent->flags |= XML_ENT_EXPANDING; ctxt->depth++; rep = xmlStringDecodeEntitiesInt(ctxt, ent->content, ent->length, what, 0, 0, 0, check); ctxt->depth--; ent->flags &= ~XML_ENT_EXPANDING;
if (rep == NULL) { ent->content[0] = 0; goto int_error; }
current = rep; while (*current != 0) { /* non input consuming loop */ buffer[nbchars++] = *current++; if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { growBuffer(buffer, XML_PARSER_BUFFER_SIZE); } } xmlFree(rep); rep = NULL; } else if (ent != NULL) { int i = xmlStrlen(ent->name); const xmlChar *cur = ent->name;
buffer[nbchars++] = '&'; if (nbchars + i + XML_PARSER_BUFFER_SIZE > buffer_size) { growBuffer(buffer, i + XML_PARSER_BUFFER_SIZE); } for (;i > 0;i--) buffer[nbchars++] = *cur++; buffer[nbchars++] = ';'; } } else if (c == '%' && (what & XML_SUBSTITUTE_PEREF)) { if (xmlParserDebugEntities) xmlGenericError(xmlGenericErrorContext, "String decoding PE Reference: %.30s\n", str); ent = xmlParseStringPEReference(ctxt, &str); if (ent != NULL) { if (ent->content == NULL) { /* * Note: external parsed entities will not be loaded, * it is not required for a non-validating parser to * complete external PEReferences coming from the * internal subset */ if (((ctxt->options & XML_PARSE_NOENT) != 0) || ((ctxt->options & XML_PARSE_DTDVALID) != 0) || (ctxt->validate != 0)) { xmlLoadEntityContent(ctxt, ent); } else { xmlWarningMsg(ctxt, XML_ERR_ENTITY_PROCESSING, "not validating will not read content for PE entity %s\n", ent->name, NULL); } }
if ((check) && (xmlParserEntityCheck(ctxt, ent->length))) goto int_error;
if (ent->flags & XML_ENT_EXPANDING) { xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); xmlHaltParser(ctxt); if (ent->content != NULL) ent->content[0] = 0; goto int_error; }
ent->flags |= XML_ENT_EXPANDING; ctxt->depth++; rep = xmlStringDecodeEntitiesInt(ctxt, ent->content, ent->length, what, 0, 0, 0, check); ctxt->depth--; ent->flags &= ~XML_ENT_EXPANDING;
if (rep == NULL) { if (ent->content != NULL) ent->content[0] = 0; goto int_error; } current = rep; while (*current != 0) { /* non input consuming loop */ buffer[nbchars++] = *current++; if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { growBuffer(buffer, XML_PARSER_BUFFER_SIZE); } } xmlFree(rep); rep = NULL; } } else { COPY_BUF(buffer, nbchars, c); str += l; if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { growBuffer(buffer, XML_PARSER_BUFFER_SIZE); } } if (str < last) c = CUR_SCHAR(str, l); else c = 0; } buffer[nbchars] = 0; return(buffer);
mem_error: xmlErrMemory(ctxt, NULL);int_error: if (rep != NULL) xmlFree(rep); if (buffer != NULL) xmlFree(buffer); return(NULL);}
/** * xmlStringLenDecodeEntities: * @ctxt: the parser context * @str: the input string * @len: the string length * @what: combination of XML_SUBSTITUTE_REF and XML_SUBSTITUTE_PEREF * @end: an end marker xmlChar, 0 if none * @end2: an end marker xmlChar, 0 if none * @end3: an end marker xmlChar, 0 if none * * DEPRECATED: Internal function, don't use. * * Takes a entity string content and process to do the adequate substitutions. * * [67] Reference ::= EntityRef | CharRef * * [69] PEReference ::= '%' Name ';' * * Returns A newly allocated string with the substitution done. The caller * must deallocate it ! */xmlChar *xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, int what, xmlChar end, xmlChar end2, xmlChar end3) { if ((ctxt == NULL) || (str == NULL) || (len < 0)) return(NULL); return(xmlStringDecodeEntitiesInt(ctxt, str, len, what, end, end2, end3, 0));}
/** * xmlStringDecodeEntities: * @ctxt: the parser context * @str: the input string * @what: combination of XML_SUBSTITUTE_REF and XML_SUBSTITUTE_PEREF * @end: an end marker xmlChar, 0 if none * @end2: an end marker xmlChar, 0 if none * @end3: an end marker xmlChar, 0 if none * * DEPRECATED: Internal function, don't use. * * Takes a entity string content and process to do the adequate substitutions. * * [67] Reference ::= EntityRef | CharRef * * [69] PEReference ::= '%' Name ';' * * Returns A newly allocated string with the substitution done. The caller * must deallocate it ! */xmlChar *xmlStringDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int what, xmlChar end, xmlChar end2, xmlChar end3) { if ((ctxt == NULL) || (str == NULL)) return(NULL); return(xmlStringDecodeEntitiesInt(ctxt, str, xmlStrlen(str), what, end, end2, end3, 0));}
/************************************************************************ * * * Commodity functions, cleanup needed ? * * * ************************************************************************/
/** * areBlanks: * @ctxt: an XML parser context * @str: a xmlChar * * @len: the size of @str * @blank_chars: we know the chars are blanks * * Is this a sequence of blank chars that one can ignore ? * * Returns 1 if ignorable 0 otherwise. */
static int areBlanks(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, int blank_chars) { int i, ret; xmlNodePtr lastChild;
/* * Don't spend time trying to differentiate them, the same callback is * used ! */ if (ctxt->sax->ignorableWhitespace == ctxt->sax->characters) return(0);
/* * Check for xml:space value. */ if ((ctxt->space == NULL) || (*(ctxt->space) == 1) || (*(ctxt->space) == -2)) return(0);
/* * Check that the string is made of blanks */ if (blank_chars == 0) { for (i = 0;i < len;i++) if (!(IS_BLANK_CH(str[i]))) return(0); }
/* * Look if the element is mixed content in the DTD if available */ if (ctxt->node == NULL) return(0); if (ctxt->myDoc != NULL) { ret = xmlIsMixedElement(ctxt->myDoc, ctxt->node->name); if (ret == 0) return(1); if (ret == 1) return(0); }
/* * Otherwise, heuristic :-\ */ if ((RAW != '<') && (RAW != 0xD)) return(0); if ((ctxt->node->children == NULL) && (RAW == '<') && (NXT(1) == '/')) return(0);
lastChild = xmlGetLastChild(ctxt->node); if (lastChild == NULL) { if ((ctxt->node->type != XML_ELEMENT_NODE) && (ctxt->node->content != NULL)) return(0); } else if (xmlNodeIsText(lastChild)) return(0); else if ((ctxt->node->children != NULL) && (xmlNodeIsText(ctxt->node->children))) return(0); return(1);}
/************************************************************************ * * * Extra stuff for namespace support * * Relates to http://www.w3.org/TR/WD-xml-names * * * ************************************************************************/
/** * xmlSplitQName: * @ctxt: an XML parser context * @name: an XML parser context * @prefix: a xmlChar ** * * parse an UTF8 encoded XML qualified name string * * [NS 5] QName ::= (Prefix ':')? LocalPart * * [NS 6] Prefix ::= NCName * * [NS 7] LocalPart ::= NCName * * Returns the local part, and prefix is updated * to get the Prefix if any. */
xmlChar *xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) { xmlChar buf[XML_MAX_NAMELEN + 5]; xmlChar *buffer = NULL; int len = 0; int max = XML_MAX_NAMELEN; xmlChar *ret = NULL; const xmlChar *cur = name; int c;
if (prefix == NULL) return(NULL); *prefix = NULL;
if (cur == NULL) return(NULL);
#ifndef XML_XML_NAMESPACE /* xml: prefix is not really a namespace */ if ((cur[0] == 'x') && (cur[1] == 'm') && (cur[2] == 'l') && (cur[3] == ':')) return(xmlStrdup(name));#endif
/* nasty but well=formed */ if (cur[0] == ':') return(xmlStrdup(name));
c = *cur++; while ((c != 0) && (c != ':') && (len < max)) { /* tested bigname.xml */ buf[len++] = c; c = *cur++; } if (len >= max) { /* * Okay someone managed to make a huge name, so he's ready to pay * for the processing speed. */ max = len * 2;
buffer = (xmlChar *) xmlMallocAtomic(max); if (buffer == NULL) { xmlErrMemory(ctxt, NULL); return(NULL); } memcpy(buffer, buf, len); while ((c != 0) && (c != ':')) { /* tested bigname.xml */ if (len + 10 > max) { xmlChar *tmp;
max *= 2; tmp = (xmlChar *) xmlRealloc(buffer, max); if (tmp == NULL) { xmlFree(buffer); xmlErrMemory(ctxt, NULL); return(NULL); } buffer = tmp; } buffer[len++] = c; c = *cur++; } buffer[len] = 0; }
if ((c == ':') && (*cur == 0)) { if (buffer != NULL) xmlFree(buffer); *prefix = NULL; return(xmlStrdup(name)); }
if (buffer == NULL) ret = xmlStrndup(buf, len); else { ret = buffer; buffer = NULL; max = XML_MAX_NAMELEN; }
if (c == ':') { c = *cur; *prefix = ret; if (c == 0) { return(xmlStrndup(BAD_CAST "", 0)); } len = 0;
/* * Check that the first character is proper to start * a new name */ if (!(((c >= 0x61) && (c <= 0x7A)) || ((c >= 0x41) && (c <= 0x5A)) || (c == '_') || (c == ':'))) { int l; int first = CUR_SCHAR(cur, l);
if (!IS_LETTER(first) && (first != '_')) { xmlFatalErrMsgStr(ctxt, XML_NS_ERR_QNAME, "Name %s is not XML Namespace compliant\n", name); } } cur++;
while ((c != 0) && (len < max)) { /* tested bigname2.xml */ buf[len++] = c; c = *cur++; } if (len >= max) { /* * Okay someone managed to make a huge name, so he's ready to pay * for the processing speed. */ max = len * 2;
buffer = (xmlChar *) xmlMallocAtomic(max); if (buffer == NULL) { xmlErrMemory(ctxt, NULL); return(NULL); } memcpy(buffer, buf, len); while (c != 0) { /* tested bigname2.xml */ if (len + 10 > max) { xmlChar *tmp;
max *= 2; tmp = (xmlChar *) xmlRealloc(buffer, max); if (tmp == NULL) { xmlErrMemory(ctxt, NULL); xmlFree(buffer); return(NULL); } buffer = tmp; } buffer[len++] = c; c = *cur++; } buffer[len] = 0; }
if (buffer == NULL) ret = xmlStrndup(buf, len); else { ret = buffer; } }
return(ret);}
/************************************************************************ * * * The parser itself * * Relates to http://www.w3.org/TR/REC-xml * * * ************************************************************************/
/************************************************************************ * * * Routines to parse Name, NCName and NmToken * * * ************************************************************************/
/* * The two following functions are related to the change of accepted * characters for Name and NmToken in the Revision 5 of XML-1.0 * They correspond to the modified production [4] and the new production [4a] * changes in that revision. Also note that the macros used for the * productions Letter, Digit, CombiningChar and Extender are not needed * anymore. * We still keep compatibility to pre-revision5 parsing semantic if the * new XML_PARSE_OLD10 option is given to the parser. */static intxmlIsNameStartChar(xmlParserCtxtPtr ctxt, int c) { if ((ctxt->options & XML_PARSE_OLD10) == 0) { /* * Use the new checks of production [4] [4a] amd [5] of the * Update 5 of XML-1.0 */ if ((c != ' ') && (c != '>') && (c != '/') && /* accelerators */ (((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 intxmlIsNameChar(xmlParserCtxtPtr ctxt, int c) { if ((ctxt->options & XML_PARSE_OLD10) == 0) { /* * Use the new checks of production [4] [4a] amd [5] of the * Update 5 of XML-1.0 */ if ((c != ' ') && (c != '>') && (c != '/') && /* accelerators */ (((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);}
static xmlChar * xmlParseAttValueInternal(xmlParserCtxtPtr ctxt, int *len, int *alloc, int normalize);
static const xmlChar *xmlParseNameComplex(xmlParserCtxtPtr ctxt) { int len = 0, l; int c; int maxLength = (ctxt->options & XML_PARSE_HUGE) ? XML_MAX_TEXT_LENGTH : XML_MAX_NAME_LENGTH;
/* * Handler for more complex cases */ c = CUR_CHAR(l); if ((ctxt->options & XML_PARSE_OLD10) == 0) { /* * Use the new checks of production [4] [4a] amd [5] of the * Update 5 of XML-1.0 */ if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ (!(((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(NULL); } len += l; NEXTL(l); c = CUR_CHAR(l); while ((c != ' ') && (c != '>') && (c != '/') && /* accelerators */ (((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)) )) { if (len <= INT_MAX - l) len += l; NEXTL(l); c = CUR_CHAR(l); } } else { if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ (!IS_LETTER(c) && (c != '_') && (c != ':'))) { return(NULL); } len += l; NEXTL(l); c = CUR_CHAR(l);
while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ ((IS_LETTER(c)) || (IS_DIGIT(c)) || (c == '.') || (c == '-') || (c == '_') || (c == ':') || (IS_COMBINING(c)) || (IS_EXTENDER(c)))) { if (len <= INT_MAX - l) len += l; NEXTL(l); c = CUR_CHAR(l); } } if (ctxt->instate == XML_PARSER_EOF) return(NULL); if (len > maxLength) { xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "Name"); return(NULL); } if (ctxt->input->cur - ctxt->input->base < len) { /* * There were a couple of bugs where PERefs lead to to a change * of the buffer. Check the buffer size to avoid passing an invalid * pointer to xmlDictLookup. */ xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, "unexpected change of input buffer"); return (NULL); } if ((*ctxt->input->cur == '\n') && (ctxt->input->cur[-1] == '\r')) return(xmlDictLookup(ctxt->dict, ctxt->input->cur - (len + 1), len)); return(xmlDictLookup(ctxt->dict, ctxt->input->cur - len, len));}
/** * xmlParseName: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * parse an XML name. * * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | * CombiningChar | Extender * * [5] Name ::= (Letter | '_' | ':') (NameChar)* * * [6] Names ::= Name (#x20 Name)* * * Returns the Name parsed or NULL */
const xmlChar *xmlParseName(xmlParserCtxtPtr ctxt) { const xmlChar *in; const xmlChar *ret; size_t count = 0; size_t maxLength = (ctxt->options & XML_PARSE_HUGE) ? XML_MAX_TEXT_LENGTH : XML_MAX_NAME_LENGTH;
GROW; if (ctxt->instate == XML_PARSER_EOF) return(NULL);
/* * Accelerator for simple ASCII names */ in = ctxt->input->cur; if (((*in >= 0x61) && (*in <= 0x7A)) || ((*in >= 0x41) && (*in <= 0x5A)) || (*in == '_') || (*in == ':')) { in++; while (((*in >= 0x61) && (*in <= 0x7A)) || ((*in >= 0x41) && (*in <= 0x5A)) || ((*in >= 0x30) && (*in <= 0x39)) || (*in == '_') || (*in == '-') || (*in == ':') || (*in == '.')) in++; if ((*in > 0) && (*in < 0x80)) { count = in - ctxt->input->cur; if (count > maxLength) { xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "Name"); return(NULL); } ret = xmlDictLookup(ctxt->dict, ctxt->input->cur, count); ctxt->input->cur = in; ctxt->input->col += count; if (ret == NULL) xmlErrMemory(ctxt, NULL); return(ret); } } /* accelerator for special cases */ return(xmlParseNameComplex(ctxt));}
static xmlHashedStringxmlParseNCNameComplex(xmlParserCtxtPtr ctxt) { xmlHashedString ret; int len = 0, l; int c; int maxLength = (ctxt->options & XML_PARSE_HUGE) ? XML_MAX_TEXT_LENGTH : XML_MAX_NAME_LENGTH; size_t startPosition = 0;
ret.name = NULL; ret.hashValue = 0;
/* * Handler for more complex cases */ startPosition = CUR_PTR - BASE_PTR; c = CUR_CHAR(l); if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ (!xmlIsNameStartChar(ctxt, c) || (c == ':'))) { return(ret); }
while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ (xmlIsNameChar(ctxt, c) && (c != ':'))) { if (len <= INT_MAX - l) len += l; NEXTL(l); c = CUR_CHAR(l); } if (ctxt->instate == XML_PARSER_EOF) return(ret); if (len > maxLength) { xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NCName"); return(ret); } ret = xmlDictLookupHashed(ctxt->dict, (BASE_PTR + startPosition), len); return(ret);}
/** * xmlParseNCName: * @ctxt: an XML parser context * @len: length of the string parsed * * parse an XML name. * * [4NS] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | * CombiningChar | Extender * * [5NS] NCName ::= (Letter | '_') (NCNameChar)* * * Returns the Name parsed or NULL */
static xmlHashedStringxmlParseNCName(xmlParserCtxtPtr ctxt) { const xmlChar *in, *e; xmlHashedString ret; size_t count = 0; size_t maxLength = (ctxt->options & XML_PARSE_HUGE) ? XML_MAX_TEXT_LENGTH : XML_MAX_NAME_LENGTH;
ret.name = NULL;
/* * Accelerator for simple ASCII names */ in = ctxt->input->cur; e = ctxt->input->end; if ((((*in >= 0x61) && (*in <= 0x7A)) || ((*in >= 0x41) && (*in <= 0x5A)) || (*in == '_')) && (in < e)) { in++; while ((((*in >= 0x61) && (*in <= 0x7A)) || ((*in >= 0x41) && (*in <= 0x5A)) || ((*in >= 0x30) && (*in <= 0x39)) || (*in == '_') || (*in == '-') || (*in == '.')) && (in < e)) in++; if (in >= e) goto complex; if ((*in > 0) && (*in < 0x80)) { count = in - ctxt->input->cur; if (count > maxLength) { xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NCName"); return(ret); } ret = xmlDictLookupHashed(ctxt->dict, ctxt->input->cur, count); ctxt->input->cur = in; ctxt->input->col += count; if (ret.name == NULL) { xmlErrMemory(ctxt, NULL); } return(ret); } }complex: return(xmlParseNCNameComplex(ctxt));}
/** * xmlParseNameAndCompare: * @ctxt: an XML parser context * * parse an XML name and compares for match * (specialized for endtag parsing) * * Returns NULL for an illegal name, (xmlChar*) 1 for success * and the name for mismatch */
static const xmlChar *xmlParseNameAndCompare(xmlParserCtxtPtr ctxt, xmlChar const *other) { register const xmlChar *cmp = other; register const xmlChar *in; const xmlChar *ret;
GROW; if (ctxt->instate == XML_PARSER_EOF) return(NULL);
in = ctxt->input->cur; while (*in != 0 && *in == *cmp) { ++in; ++cmp; } if (*cmp == 0 && (*in == '>' || IS_BLANK_CH (*in))) { /* success */ ctxt->input->col += in - ctxt->input->cur; ctxt->input->cur = in; return (const xmlChar*) 1; } /* failure (or end of input buffer), check with full function */ ret = xmlParseName (ctxt); /* strings coming from the dictionary direct compare possible */ if (ret == other) { return (const xmlChar*) 1; } return ret;}
/** * xmlParseStringName: * @ctxt: an XML parser context * @str: a pointer to the string pointer (IN/OUT) * * parse an XML name. * * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | * CombiningChar | Extender * * [5] Name ::= (Letter | '_' | ':') (NameChar)* * * [6] Names ::= Name (#x20 Name)* * * Returns the Name parsed or NULL. The @str pointer * is updated to the current location in the string. */
static xmlChar *xmlParseStringName(xmlParserCtxtPtr ctxt, const xmlChar** str) { xmlChar buf[XML_MAX_NAMELEN + 5]; const xmlChar *cur = *str; int len = 0, l; int c; int maxLength = (ctxt->options & XML_PARSE_HUGE) ? XML_MAX_TEXT_LENGTH : XML_MAX_NAME_LENGTH;
c = CUR_SCHAR(cur, l); if (!xmlIsNameStartChar(ctxt, c)) { return(NULL); }
COPY_BUF(buf, len, c); cur += l; c = CUR_SCHAR(cur, l); while (xmlIsNameChar(ctxt, c)) { COPY_BUF(buf, len, c); cur += l; c = CUR_SCHAR(cur, l); if (len >= XML_MAX_NAMELEN) { /* test bigentname.xml */ /* * Okay someone managed to make a huge name, so he's ready to pay * for the processing speed. */ xmlChar *buffer; int max = len * 2;
buffer = (xmlChar *) xmlMallocAtomic(max); if (buffer == NULL) { xmlErrMemory(ctxt, NULL); return(NULL); } memcpy(buffer, buf, len); while (xmlIsNameChar(ctxt, c)) { if (len + 10 > max) { xmlChar *tmp;
max *= 2; tmp = (xmlChar *) xmlRealloc(buffer, max); if (tmp == NULL) { xmlErrMemory(ctxt, NULL); xmlFree(buffer); return(NULL); } buffer = tmp; } COPY_BUF(buffer, len, c); cur += l; c = CUR_SCHAR(cur, l); if (len > maxLength) { xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NCName"); xmlFree(buffer); return(NULL); } } buffer[len] = 0; *str = cur; return(buffer); } } if (len > maxLength) { xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NCName"); return(NULL); } *str = cur; return(xmlStrndup(buf, len));}
/** * xmlParseNmtoken: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * parse an XML Nmtoken. * * [7] Nmtoken ::= (NameChar)+ * * [8] Nmtokens ::= Nmtoken (#x20 Nmtoken)* * * Returns the Nmtoken parsed or NULL */
xmlChar *xmlParseNmtoken(xmlParserCtxtPtr ctxt) { xmlChar buf[XML_MAX_NAMELEN + 5]; int len = 0, l; int c; int maxLength = (ctxt->options & XML_PARSE_HUGE) ? XML_MAX_TEXT_LENGTH : XML_MAX_NAME_LENGTH;
c = CUR_CHAR(l);
while (xmlIsNameChar(ctxt, c)) { COPY_BUF(buf, len, c); NEXTL(l); c = CUR_CHAR(l); if (len >= XML_MAX_NAMELEN) { /* * Okay someone managed to make a huge token, so he's ready to pay * for the processing speed. */ xmlChar *buffer; int max = len * 2;
buffer = (xmlChar *) xmlMallocAtomic(max); if (buffer == NULL) { xmlErrMemory(ctxt, NULL); return(NULL); } memcpy(buffer, buf, len); while (xmlIsNameChar(ctxt, c)) { if (len + 10 > max) { xmlChar *tmp;
max *= 2; tmp = (xmlChar *) xmlRealloc(buffer, max); if (tmp == NULL) { xmlErrMemory(ctxt, NULL); xmlFree(buffer); return(NULL); } buffer = tmp; } COPY_BUF(buffer, len, c); if (len > maxLength) { xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NmToken"); xmlFree(buffer); return(NULL); } NEXTL(l); c = CUR_CHAR(l); } buffer[len] = 0; if (ctxt->instate == XML_PARSER_EOF) { xmlFree(buffer); return(NULL); } return(buffer); } } if (ctxt->instate == XML_PARSER_EOF) return(NULL); if (len == 0) return(NULL); if (len > maxLength) { xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NmToken"); return(NULL); } return(xmlStrndup(buf, len));}
/** * xmlParseEntityValue: * @ctxt: an XML parser context * @orig: if non-NULL store a copy of the original entity value * * DEPRECATED: Internal function, don't use. * * parse a value for ENTITY declarations * * [9] EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' | * "'" ([^%&'] | PEReference | Reference)* "'" * * Returns the EntityValue parsed with reference substituted or NULL */
xmlChar *xmlParseEntityValue(xmlParserCtxtPtr ctxt, xmlChar **orig) { xmlChar *buf = NULL; int len = 0; int size = XML_PARSER_BUFFER_SIZE; int c, l; int maxLength = (ctxt->options & XML_PARSE_HUGE) ? XML_MAX_HUGE_LENGTH : XML_MAX_TEXT_LENGTH; xmlChar stop; xmlChar *ret = NULL; const xmlChar *cur = NULL; xmlParserInputPtr input;
if (RAW == '"') stop = '"'; else if (RAW == '\'') stop = '\''; else { xmlFatalErr(ctxt, XML_ERR_ENTITY_NOT_STARTED, NULL); return(NULL); } buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { xmlErrMemory(ctxt, NULL); return(NULL); }
/* * The content of the entity definition is copied in a buffer. */
ctxt->instate = XML_PARSER_ENTITY_VALUE; input = ctxt->input; GROW; if (ctxt->instate == XML_PARSER_EOF) goto error; NEXT; c = CUR_CHAR(l); /* * NOTE: 4.4.5 Included in Literal * When a parameter entity reference appears in a literal entity * value, ... a single or double quote character in the replacement * text is always treated as a normal data character and will not * terminate the literal. * In practice it means we stop the loop only when back at parsing * the initial entity and the quote is found */ while (((IS_CHAR(c)) && ((c != stop) || /* checked */ (ctxt->input != input))) && (ctxt->instate != XML_PARSER_EOF)) { if (len + 5 >= size) { xmlChar *tmp;
size *= 2; tmp = (xmlChar *) xmlRealloc(buf, size); if (tmp == NULL) { xmlErrMemory(ctxt, NULL); goto error; } buf = tmp; } COPY_BUF(buf, len, c); NEXTL(l);
GROW; c = CUR_CHAR(l); if (c == 0) { GROW; c = CUR_CHAR(l); }
if (len > maxLength) { xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_NOT_FINISHED, "entity value too long\n"); goto error; } } buf[len] = 0; if (ctxt->instate == XML_PARSER_EOF) goto error; if (c != stop) { xmlFatalErr(ctxt, XML_ERR_ENTITY_NOT_FINISHED, NULL); goto error; } NEXT;
/* * Raise problem w.r.t. '&' and '%' being used in non-entities * reference constructs. Note Charref will be handled in * xmlStringDecodeEntities() */ cur = buf; while (*cur != 0) { /* non input consuming */ if ((*cur == '%') || ((*cur == '&') && (cur[1] != '#'))) { xmlChar *name; xmlChar tmp = *cur; int nameOk = 0;
cur++; name = xmlParseStringName(ctxt, &cur); if (name != NULL) { nameOk = 1; xmlFree(name); } if ((nameOk == 0) || (*cur != ';')) { xmlFatalErrMsgInt(ctxt, XML_ERR_ENTITY_CHAR_ERROR, "EntityValue: '%c' forbidden except for entities references\n", tmp); goto error; } if ((tmp == '%') && (ctxt->inSubset == 1) && (ctxt->inputNr == 1)) { xmlFatalErr(ctxt, XML_ERR_ENTITY_PE_INTERNAL, NULL); goto error; } if (*cur == 0) break; } cur++; }
/* * Then PEReference entities are substituted. * * NOTE: 4.4.7 Bypassed * When a general entity reference appears in the EntityValue in * an entity declaration, it is bypassed and left as is. * so XML_SUBSTITUTE_REF is not set here. */ ++ctxt->depth; ret = xmlStringDecodeEntitiesInt(ctxt, buf, len, XML_SUBSTITUTE_PEREF, 0, 0, 0, /* check */ 1); --ctxt->depth;
if (orig != NULL) { *orig = buf; buf = NULL; }
error: if (buf != NULL) xmlFree(buf); return(ret);}
/** * xmlParseAttValueComplex: * @ctxt: an XML parser context * @len: the resulting attribute len * @normalize: whether to apply the inner normalization * * parse a value for an attribute, this is the fallback function * of xmlParseAttValue() when the attribute parsing requires handling * of non-ASCII characters, or normalization compaction. * * Returns the AttValue parsed or NULL. The value has to be freed by the caller. */static xmlChar *xmlParseAttValueComplex(xmlParserCtxtPtr ctxt, int *attlen, int normalize) { xmlChar limit = 0; xmlChar *buf = NULL; xmlChar *rep = NULL; size_t len = 0; size_t buf_size = 0; size_t maxLength = (ctxt->options & XML_PARSE_HUGE) ? XML_MAX_HUGE_LENGTH : XML_MAX_TEXT_LENGTH; int c, l, in_space = 0; xmlChar *current = NULL; xmlEntityPtr ent;
if (NXT(0) == '"') { ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE; limit = '"'; NEXT; } else if (NXT(0) == '\'') { limit = '\''; ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE; NEXT; } else { xmlFatalErr(ctxt, XML_ERR_ATTRIBUTE_NOT_STARTED, NULL); return(NULL); }
/* * allocate a translation buffer. */ buf_size = XML_PARSER_BUFFER_SIZE; buf = (xmlChar *) xmlMallocAtomic(buf_size); if (buf == NULL) goto mem_error;
/* * OK loop until we reach one of the ending char or a size limit. */ c = CUR_CHAR(l); while (((NXT(0) != limit) && /* checked */ (IS_CHAR(c)) && (c != '<')) && (ctxt->instate != XML_PARSER_EOF)) { if (c == '&') { in_space = 0; if (NXT(1) == '#') { int val = xmlParseCharRef(ctxt);
if (val == '&') { if (ctxt->replaceEntities) { if (len + 10 > buf_size) { growBuffer(buf, 10); } buf[len++] = '&'; } else { /* * The reparsing will be done in xmlStringGetNodeList() * called by the attribute() function in SAX.c */ if (len + 10 > buf_size) { growBuffer(buf, 10); } buf[len++] = '&'; buf[len++] = '#'; buf[len++] = '3'; buf[len++] = '8'; buf[len++] = ';'; } } else if (val != 0) { if (len + 10 > buf_size) { growBuffer(buf, 10); } len += xmlCopyChar(0, &buf[len], val); } } else { ent = xmlParseEntityRef(ctxt); if ((ent != NULL) && (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) { if (len + 10 > buf_size) { growBuffer(buf, 10); } if ((ctxt->replaceEntities == 0) && (ent->content[0] == '&')) { buf[len++] = '&'; buf[len++] = '#'; buf[len++] = '3'; buf[len++] = '8'; buf[len++] = ';'; } else { buf[len++] = ent->content[0]; } } else if ((ent != NULL) && (ctxt->replaceEntities != 0)) { if (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY) { if (xmlParserEntityCheck(ctxt, ent->length)) goto error;
++ctxt->depth; rep = xmlStringDecodeEntitiesInt(ctxt, ent->content, ent->length, XML_SUBSTITUTE_REF, 0, 0, 0, /* check */ 1); --ctxt->depth; if (rep != NULL) { current = rep; while (*current != 0) { /* non input consuming */ if ((*current == 0xD) || (*current == 0xA) || (*current == 0x9)) { buf[len++] = 0x20; current++; } else buf[len++] = *current++; if (len + 10 > buf_size) { growBuffer(buf, 10); } } xmlFree(rep); rep = NULL; } } else { if (len + 10 > buf_size) { growBuffer(buf, 10); } if (ent->content != NULL) buf[len++] = ent->content[0]; } } else if (ent != NULL) { int i = xmlStrlen(ent->name); const xmlChar *cur = ent->name;
/* * We also check for recursion and amplification * when entities are not substituted. They're * often expanded later. */ if ((ent->etype != XML_INTERNAL_PREDEFINED_ENTITY) && (ent->content != NULL)) { if ((ent->flags & XML_ENT_CHECKED) == 0) { unsigned long oldCopy = ctxt->sizeentcopy;
ctxt->sizeentcopy = ent->length;
++ctxt->depth; rep = xmlStringDecodeEntitiesInt(ctxt, ent->content, ent->length, XML_SUBSTITUTE_REF, 0, 0, 0, /* check */ 1); --ctxt->depth;
/* * If we're parsing DTD content, the entity * might reference other entities which * weren't defined yet, so the check isn't * reliable. */ if (ctxt->inSubset == 0) { ent->flags |= XML_ENT_CHECKED; ent->expandedSize = ctxt->sizeentcopy; }
if (rep != NULL) { xmlFree(rep); rep = NULL; } else { ent->content[0] = 0; }
if (xmlParserEntityCheck(ctxt, oldCopy)) goto error; } else { if (xmlParserEntityCheck(ctxt, ent->expandedSize)) goto error; } }
/* * Just output the reference */ buf[len++] = '&'; while (len + i + 10 > buf_size) { growBuffer(buf, i + 10); } for (;i > 0;i--) buf[len++] = *cur++; buf[len++] = ';'; } } } else { if ((c == 0x20) || (c == 0xD) || (c == 0xA) || (c == 0x9)) { if ((len != 0) || (!normalize)) { if ((!normalize) || (!in_space)) { COPY_BUF(buf, len, 0x20); while (len + 10 > buf_size) { growBuffer(buf, 10); } } in_space = 1; } } else { in_space = 0; COPY_BUF(buf, len, c); if (len + 10 > buf_size) { growBuffer(buf, 10); } } NEXTL(l); } GROW; c = CUR_CHAR(l); if (len > maxLength) { xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, "AttValue length too long\n"); goto mem_error; } } if (ctxt->instate == XML_PARSER_EOF) goto error;
if ((in_space) && (normalize)) { while ((len > 0) && (buf[len - 1] == 0x20)) len--; } buf[len] = 0; if (RAW == '<') { xmlFatalErr(ctxt, XML_ERR_LT_IN_ATTRIBUTE, NULL); } else if (RAW != limit) { if ((c != 0) && (!IS_CHAR(c))) { xmlFatalErrMsg(ctxt, XML_ERR_INVALID_CHAR, "invalid character in attribute value\n"); } else { xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, "AttValue: ' expected\n"); } } else NEXT;
if (attlen != NULL) *attlen = len; return(buf);
mem_error: xmlErrMemory(ctxt, NULL);error: if (buf != NULL) xmlFree(buf); if (rep != NULL) xmlFree(rep); return(NULL);}
/** * xmlParseAttValue: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * parse a value for an attribute * Note: the parser won't do substitution of entities here, this * will be handled later in xmlStringGetNodeList * * [10] AttValue ::= '"' ([^<&"] | Reference)* '"' | * "'" ([^<&'] | Reference)* "'" * * 3.3.3 Attribute-Value Normalization: * Before the value of an attribute is passed to the application or * checked for validity, the XML processor must normalize it as follows: * - a character reference is processed by appending the referenced * character to the attribute value * - an entity reference is processed by recursively processing the * replacement text of the entity * - a whitespace character (#x20, #xD, #xA, #x9) is processed by * appending #x20 to the normalized value, except that only a single * #x20 is appended for a "#xD#xA" sequence that is part of an external * parsed entity or the literal entity value of an internal parsed entity * - other characters are processed by appending them to the normalized value * 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 a single space (#x20) character. * All attributes for which no declaration has been read should be treated * by a non-validating parser as if declared CDATA. * * Returns the AttValue parsed or NULL. The value has to be freed by the caller. */
xmlChar *xmlParseAttValue(xmlParserCtxtPtr ctxt) { if ((ctxt == NULL) || (ctxt->input == NULL)) return(NULL); return(xmlParseAttValueInternal(ctxt, NULL, NULL, 0));}
/** * xmlParseSystemLiteral: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * parse an XML Literal * * [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'") * * Returns the SystemLiteral parsed or NULL */
xmlChar *xmlParseSystemLiteral(xmlParserCtxtPtr ctxt) { xmlChar *buf = NULL; int len = 0; int size = XML_PARSER_BUFFER_SIZE; int cur, l; int maxLength = (ctxt->options & XML_PARSE_HUGE) ? XML_MAX_TEXT_LENGTH : XML_MAX_NAME_LENGTH; xmlChar stop; int state = ctxt->instate;
if (RAW == '"') { NEXT; stop = '"'; } else if (RAW == '\'') { NEXT; stop = '\''; } else { xmlFatalErr(ctxt, XML_ERR_LITERAL_NOT_STARTED, NULL); return(NULL); }
buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { xmlErrMemory(ctxt, NULL); return(NULL); } ctxt->instate = XML_PARSER_SYSTEM_LITERAL; cur = CUR_CHAR(l); while ((IS_CHAR(cur)) && (cur != stop)) { /* checked */ if (len + 5 >= size) { xmlChar *tmp;
size *= 2; tmp = (xmlChar *) xmlRealloc(buf, size); if (tmp == NULL) { xmlFree(buf); xmlErrMemory(ctxt, NULL); ctxt->instate = (xmlParserInputState) state; return(NULL); } buf = tmp; } COPY_BUF(buf, len, cur); if (len > maxLength) { xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "SystemLiteral"); xmlFree(buf); ctxt->instate = (xmlParserInputState) state; return(NULL); } NEXTL(l); cur = CUR_CHAR(l); } buf[len] = 0; if (ctxt->instate == XML_PARSER_EOF) { xmlFree(buf); return(NULL); } ctxt->instate = (xmlParserInputState) state; if (!IS_CHAR(cur)) { xmlFatalErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED, NULL); } else { NEXT; } return(buf);}
/** * xmlParsePubidLiteral: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * parse an XML public literal * * [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'" * * Returns the PubidLiteral parsed or NULL. */
xmlChar *xmlParsePubidLiteral(xmlParserCtxtPtr ctxt) { xmlChar *buf = NULL; int len = 0; int size = XML_PARSER_BUFFER_SIZE; int maxLength = (ctxt->options & XML_PARSE_HUGE) ? XML_MAX_TEXT_LENGTH : XML_MAX_NAME_LENGTH; xmlChar cur; xmlChar stop; xmlParserInputState oldstate = ctxt->instate;
if (RAW == '"') { NEXT; stop = '"'; } else if (RAW == '\'') { NEXT; stop = '\''; } else { xmlFatalErr(ctxt, XML_ERR_LITERAL_NOT_STARTED, NULL); return(NULL); } buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { xmlErrMemory(ctxt, NULL); return(NULL); } ctxt->instate = XML_PARSER_PUBLIC_LITERAL; cur = CUR; while ((IS_PUBIDCHAR_CH(cur)) && (cur != stop)) { /* checked */ if (len + 1 >= size) { xmlChar *tmp;
size *= 2; tmp = (xmlChar *) xmlRealloc(buf, size); if (tmp == NULL) { xmlErrMemory(ctxt, NULL); xmlFree(buf); return(NULL); } buf = tmp; } buf[len++] = cur; if (len > maxLength) { xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "Public ID"); xmlFree(buf); return(NULL); } NEXT; cur = CUR; } buf[len] = 0; if (ctxt->instate == XML_PARSER_EOF) { xmlFree(buf); return(NULL); } if (cur != stop) { xmlFatalErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED, NULL); } else { NEXTL(1); } ctxt->instate = oldstate; return(buf);}
static void xmlParseCharDataComplex(xmlParserCtxtPtr ctxt, int partial);
/* * used for the test in the inner loop of the char data testing */static const unsigned char test_char_data[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9, CR/LF separated */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x00, 0x27, /* & */ 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x00, 0x3D, 0x3E, 0x3F, /* < */ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x00, 0x5E, 0x5F, /* ] */ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* non-ascii */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/** * xmlParseCharDataInternal: * @ctxt: an XML parser context * @partial: buffer may contain partial UTF-8 sequences * * Parse character data. Always makes progress if the first char isn't * '<' or '&'. * * The right angle bracket (>) may be represented using the string ">", * and must, for compatibility, be escaped using ">" or a character * reference when it appears in the string "]]>" in content, when that * string is not marking the end of a CDATA section. * * [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*) */static voidxmlParseCharDataInternal(xmlParserCtxtPtr ctxt, int partial) { const xmlChar *in; int nbchar = 0; int line = ctxt->input->line; int col = ctxt->input->col; int ccol;
GROW; /* * Accelerated common case where input don't need to be * modified before passing it to the handler. */ in = ctxt->input->cur; do {get_more_space: while (*in == 0x20) { in++; ctxt->input->col++; } if (*in == 0xA) { do { ctxt->input->line++; ctxt->input->col = 1; in++; } while (*in == 0xA); goto get_more_space; } if (*in == '<') { nbchar = in - ctxt->input->cur; if (nbchar > 0) { const xmlChar *tmp = ctxt->input->cur; ctxt->input->cur = in;
if ((ctxt->sax != NULL) && (ctxt->disableSAX == 0) && (ctxt->sax->ignorableWhitespace != ctxt->sax->characters)) { if (areBlanks(ctxt, tmp, nbchar, 1)) { if (ctxt->sax->ignorableWhitespace != NULL) ctxt->sax->ignorableWhitespace(ctxt->userData, tmp, nbchar); } else { if (ctxt->sax->characters != NULL) ctxt->sax->characters(ctxt->userData, tmp, nbchar); if (*ctxt->space == -1) *ctxt->space = -2; } } else if ((ctxt->sax != NULL) && (ctxt->disableSAX == 0) && (ctxt->sax->characters != NULL)) { ctxt->sax->characters(ctxt->userData, tmp, nbchar); } } return; }
get_more: ccol = ctxt->input->col; while (test_char_data[*in]) { in++; ccol++; } ctxt->input->col = ccol; if (*in == 0xA) { do { ctxt->input->line++; ctxt->input->col = 1; in++; } while (*in == 0xA); goto get_more; } if (*in == ']') { if ((in[1] == ']') && (in[2] == '>')) { xmlFatalErr(ctxt, XML_ERR_MISPLACED_CDATA_END, NULL); if (ctxt->instate != XML_PARSER_EOF) ctxt->input->cur = in + 1; return; } in++; ctxt->input->col++; goto get_more; } nbchar = in - ctxt->input->cur; if (nbchar > 0) { if ((ctxt->sax != NULL) && (ctxt->disableSAX == 0) && (ctxt->sax->ignorableWhitespace != ctxt->sax->characters) && (IS_BLANK_CH(*ctxt->input->cur))) { const xmlChar *tmp = ctxt->input->cur; ctxt->input->cur = in;
if (areBlanks(ctxt, tmp, nbchar, 0)) { if (ctxt->sax->ignorableWhitespace != NULL) ctxt->sax->ignorableWhitespace(ctxt->userData, tmp, nbchar); } else { if (ctxt->sax->characters != NULL) ctxt->sax->characters(ctxt->userData, tmp, nbchar); if (*ctxt->space == -1) *ctxt->space = -2; } line = ctxt->input->line; col = ctxt->input->col; } else if ((ctxt->sax != NULL) && (ctxt->disableSAX == 0)) { if (ctxt->sax->characters != NULL) ctxt->sax->characters(ctxt->userData, ctxt->input->cur, nbchar); line = ctxt->input->line; col = ctxt->input->col; } if (ctxt->instate == XML_PARSER_EOF) return; } ctxt->input->cur = in; if (*in == 0xD) { in++; if (*in == 0xA) { ctxt->input->cur = in; in++; ctxt->input->line++; ctxt->input->col = 1; continue; /* while */ } in--; } if (*in == '<') { return; } if (*in == '&') { return; } SHRINK; GROW; if (ctxt->instate == XML_PARSER_EOF) return; in = ctxt->input->cur; } while (((*in >= 0x20) && (*in <= 0x7F)) || (*in == 0x09) || (*in == 0x0a)); ctxt->input->line = line; ctxt->input->col = col; xmlParseCharDataComplex(ctxt, partial);}
/** * xmlParseCharDataComplex: * @ctxt: an XML parser context * @cdata: int indicating whether we are within a CDATA section * * Always makes progress if the first char isn't '<' or '&'. * * parse a CharData section.this is the fallback function * of xmlParseCharData() when the parsing requires handling * of non-ASCII characters. */static voidxmlParseCharDataComplex(xmlParserCtxtPtr ctxt, int partial) { xmlChar buf[XML_PARSER_BIG_BUFFER_SIZE + 5]; int nbchar = 0; int cur, l;
cur = CUR_CHAR(l); while ((cur != '<') && /* checked */ (cur != '&') && (IS_CHAR(cur))) { if ((cur == ']') && (NXT(1) == ']') && (NXT(2) == '>')) { xmlFatalErr(ctxt, XML_ERR_MISPLACED_CDATA_END, NULL); } COPY_BUF(buf, nbchar, cur); /* move current position before possible calling of ctxt->sax->characters */ NEXTL(l); if (nbchar >= XML_PARSER_BIG_BUFFER_SIZE) { buf[nbchar] = 0;
/* * OK the segment is to be consumed as chars. */ if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) { if (areBlanks(ctxt, buf, nbchar, 0)) { if (ctxt->sax->ignorableWhitespace != NULL) ctxt->sax->ignorableWhitespace(ctxt->userData, buf, nbchar); } else { if (ctxt->sax->characters != NULL) ctxt->sax->characters(ctxt->userData, buf, nbchar); if ((ctxt->sax->characters != ctxt->sax->ignorableWhitespace) && (*ctxt->space == -1)) *ctxt->space = -2; } } nbchar = 0; /* something really bad happened in the SAX callback */ if (ctxt->instate != XML_PARSER_CONTENT) return; SHRINK; } cur = CUR_CHAR(l); } if (ctxt->instate == XML_PARSER_EOF) return; if (nbchar != 0) { buf[nbchar] = 0; /* * OK the segment is to be consumed as chars. */ if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) { if (areBlanks(ctxt, buf, nbchar, 0)) { if (ctxt->sax->ignorableWhitespace != NULL) ctxt->sax->ignorableWhitespace(ctxt->userData, buf, nbchar); } else { if (ctxt->sax->characters != NULL) ctxt->sax->characters(ctxt->userData, buf, nbchar); if ((ctxt->sax->characters != ctxt->sax->ignorableWhitespace) && (*ctxt->space == -1)) *ctxt->space = -2; } } } /* * cur == 0 can mean * * - XML_PARSER_EOF or memory error. This is checked above. * - An actual 0 character. * - End of buffer. * - An incomplete UTF-8 sequence. This is allowed if partial is set. */ if (ctxt->input->cur < ctxt->input->end) { if ((cur == 0) && (CUR != 0)) { if (partial == 0) { xmlFatalErrMsgInt(ctxt, XML_ERR_INVALID_CHAR, "Incomplete UTF-8 sequence starting with %02X\n", CUR); NEXTL(1); } } else if ((cur != '<') && (cur != '&')) { /* Generate the error and skip the offending character */ xmlFatalErrMsgInt(ctxt, XML_ERR_INVALID_CHAR, "PCDATA invalid Char value %d\n", cur); NEXTL(l); } }}
/** * xmlParseCharData: * @ctxt: an XML parser context * @cdata: unused * * DEPRECATED: Internal function, don't use. */voidxmlParseCharData(xmlParserCtxtPtr ctxt, ATTRIBUTE_UNUSED int cdata) { xmlParseCharDataInternal(ctxt, 0);}
/** * xmlParseExternalID: * @ctxt: an XML parser context * @publicID: a xmlChar** receiving PubidLiteral * @strict: indicate whether we should restrict parsing to only * production [75], see NOTE below * * DEPRECATED: Internal function, don't use. * * Parse an External ID or a Public ID * * NOTE: Productions [75] and [83] interact badly since [75] can generate * 'PUBLIC' S PubidLiteral S SystemLiteral * * [75] ExternalID ::= 'SYSTEM' S SystemLiteral * | 'PUBLIC' S PubidLiteral S SystemLiteral * * [83] PublicID ::= 'PUBLIC' S PubidLiteral * * Returns the function returns SystemLiteral and in the second * case publicID receives PubidLiteral, is strict is off * it is possible to return NULL and have publicID set. */
xmlChar *xmlParseExternalID(xmlParserCtxtPtr ctxt, xmlChar **publicID, int strict) { xmlChar *URI = NULL;
*publicID = NULL; if (CMP6(CUR_PTR, 'S', 'Y', 'S', 'T', 'E', 'M')) { SKIP(6); if (SKIP_BLANKS == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after 'SYSTEM'\n"); } URI = xmlParseSystemLiteral(ctxt); if (URI == NULL) { xmlFatalErr(ctxt, XML_ERR_URI_REQUIRED, NULL); } } else if (CMP6(CUR_PTR, 'P', 'U', 'B', 'L', 'I', 'C')) { SKIP(6); if (SKIP_BLANKS == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after 'PUBLIC'\n"); } *publicID = xmlParsePubidLiteral(ctxt); if (*publicID == NULL) { xmlFatalErr(ctxt, XML_ERR_PUBID_REQUIRED, NULL); } if (strict) { /* * We don't handle [83] so "S SystemLiteral" is required. */ if (SKIP_BLANKS == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after the Public Identifier\n"); } } else { /* * We handle [83] so we return immediately, if * "S SystemLiteral" is not detected. We skip blanks if no * system literal was found, but this is harmless since we must * be at the end of a NotationDecl. */ if (SKIP_BLANKS == 0) return(NULL); if ((CUR != '\'') && (CUR != '"')) return(NULL); } URI = xmlParseSystemLiteral(ctxt); if (URI == NULL) { xmlFatalErr(ctxt, XML_ERR_URI_REQUIRED, NULL); } } return(URI);}
/** * xmlParseCommentComplex: * @ctxt: an XML parser context * @buf: the already parsed part of the buffer * @len: number of bytes in the buffer * @size: allocated size of the buffer * * Skip an XML (SGML) comment <!-- .... --> * The spec says that "For compatibility, the string "--" (double-hyphen) * must not occur within comments. " * This is the slow routine in case the accelerator for ascii didn't work * * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->' */static voidxmlParseCommentComplex(xmlParserCtxtPtr ctxt, xmlChar *buf, size_t len, size_t size) { int q, ql; int r, rl; int cur, l; size_t maxLength = (ctxt->options & XML_PARSE_HUGE) ? XML_MAX_HUGE_LENGTH : XML_MAX_TEXT_LENGTH; int inputid;
inputid = ctxt->input->id;
if (buf == NULL) { len = 0; size = XML_PARSER_BUFFER_SIZE; buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { xmlErrMemory(ctxt, NULL); return; } } q = CUR_CHAR(ql); if (q == 0) goto not_terminated; if (!IS_CHAR(q)) { xmlFatalErrMsgInt(ctxt, XML_ERR_INVALID_CHAR, "xmlParseComment: invalid xmlChar value %d\n", q); xmlFree (buf); return; } NEXTL(ql); r = CUR_CHAR(rl); if (r == 0) goto not_terminated; if (!IS_CHAR(r)) { xmlFatalErrMsgInt(ctxt, XML_ERR_INVALID_CHAR, "xmlParseComment: invalid xmlChar value %d\n", r); xmlFree (buf); return; } NEXTL(rl); cur = CUR_CHAR(l); if (cur == 0) goto not_terminated; while (IS_CHAR(cur) && /* checked */ ((cur != '>') || (r != '-') || (q != '-'))) { if ((r == '-') && (q == '-')) { xmlFatalErr(ctxt, XML_ERR_HYPHEN_IN_COMMENT, NULL); } if (len + 5 >= size) { xmlChar *new_buf; size_t new_size;
new_size = size * 2; new_buf = (xmlChar *) xmlRealloc(buf, new_size); if (new_buf == NULL) { xmlFree (buf); xmlErrMemory(ctxt, NULL); return; } buf = new_buf; size = new_size; } COPY_BUF(buf, len, q); if (len > maxLength) { xmlFatalErrMsgStr(ctxt, XML_ERR_COMMENT_NOT_FINISHED, "Comment too big found", NULL); xmlFree (buf); return; }
q = r; ql = rl; r = cur; rl = l;
NEXTL(l); cur = CUR_CHAR(l);
} buf[len] = 0; if (ctxt->instate == XML_PARSER_EOF) { xmlFree(buf); return; } if (cur == 0) { xmlFatalErrMsgStr(ctxt, XML_ERR_COMMENT_NOT_FINISHED, "Comment not terminated \n<!--%.50s\n", buf); } else if (!IS_CHAR(cur)) { xmlFatalErrMsgInt(ctxt, XML_ERR_INVALID_CHAR, "xmlParseComment: invalid xmlChar value %d\n", cur); } else { if (inputid != ctxt->input->id) { xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, "Comment doesn't start and stop in the same" " entity\n"); } NEXT; if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL) && (!ctxt->disableSAX)) ctxt->sax->comment(ctxt->userData, buf); } xmlFree(buf); return;not_terminated: xmlFatalErrMsgStr(ctxt, XML_ERR_COMMENT_NOT_FINISHED, "Comment not terminated\n", NULL); xmlFree(buf); return;}
/** * xmlParseComment: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * Parse an XML (SGML) comment. Always consumes '<!'. * * The spec says that "For compatibility, the string "--" (double-hyphen) * must not occur within comments. " * * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->' */voidxmlParseComment(xmlParserCtxtPtr ctxt) { xmlChar *buf = NULL; size_t size = XML_PARSER_BUFFER_SIZE; size_t len = 0; size_t maxLength = (ctxt->options & XML_PARSE_HUGE) ? XML_MAX_HUGE_LENGTH : XML_MAX_TEXT_LENGTH; xmlParserInputState state; const xmlChar *in; size_t nbchar = 0; int ccol; int inputid;
/* * Check that there is a comment right here. */ if ((RAW != '<') || (NXT(1) != '!')) return; SKIP(2); if ((RAW != '-') || (NXT(1) != '-')) return; state = ctxt->instate; ctxt->instate = XML_PARSER_COMMENT; inputid = ctxt->input->id; SKIP(2); GROW;
/* * Accelerated common case where input don't need to be * modified before passing it to the handler. */ in = ctxt->input->cur; do { if (*in == 0xA) { do { ctxt->input->line++; ctxt->input->col = 1; in++; } while (*in == 0xA); }get_more: ccol = ctxt->input->col; while (((*in > '-') && (*in <= 0x7F)) || ((*in >= 0x20) && (*in < '-')) || (*in == 0x09)) { in++; ccol++; } ctxt->input->col = ccol; if (*in == 0xA) { do { ctxt->input->line++; ctxt->input->col = 1; in++; } while (*in == 0xA); goto get_more; } nbchar = in - ctxt->input->cur; /* * save current set of data */ if (nbchar > 0) { if (buf == NULL) { if ((*in == '-') && (in[1] == '-')) size = nbchar + 1; else size = XML_PARSER_BUFFER_SIZE + nbchar; buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { xmlErrMemory(ctxt, NULL); ctxt->instate = state; return; } len = 0; } else if (len + nbchar + 1 >= size) { xmlChar *new_buf; size += len + nbchar + XML_PARSER_BUFFER_SIZE; new_buf = (xmlChar *) xmlRealloc(buf, size); if (new_buf == NULL) { xmlFree (buf); xmlErrMemory(ctxt, NULL); ctxt->instate = state; return; } buf = new_buf; } memcpy(&buf[len], ctxt->input->cur, nbchar); len += nbchar; buf[len] = 0; } if (len > maxLength) { xmlFatalErrMsgStr(ctxt, XML_ERR_COMMENT_NOT_FINISHED, "Comment too big found", NULL); xmlFree (buf); return; } ctxt->input->cur = in; if (*in == 0xA) { in++; ctxt->input->line++; ctxt->input->col = 1; } if (*in == 0xD) { in++; if (*in == 0xA) { ctxt->input->cur = in; in++; ctxt->input->line++; ctxt->input->col = 1; goto get_more; } in--; } SHRINK; GROW; if (ctxt->instate == XML_PARSER_EOF) { xmlFree(buf); return; } in = ctxt->input->cur; if (*in == '-') { if (in[1] == '-') { if (in[2] == '>') { if (ctxt->input->id != inputid) { xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, "comment doesn't start and stop in the" " same entity\n"); } SKIP(3); if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL) && (!ctxt->disableSAX)) { if (buf != NULL) ctxt->sax->comment(ctxt->userData, buf); else ctxt->sax->comment(ctxt->userData, BAD_CAST ""); } if (buf != NULL) xmlFree(buf); if (ctxt->instate != XML_PARSER_EOF) ctxt->instate = state; return; } if (buf != NULL) { xmlFatalErrMsgStr(ctxt, XML_ERR_HYPHEN_IN_COMMENT, "Double hyphen within comment: " "<!--%.50s\n", buf); } else xmlFatalErrMsgStr(ctxt, XML_ERR_HYPHEN_IN_COMMENT, "Double hyphen within comment\n", NULL); if (ctxt->instate == XML_PARSER_EOF) { xmlFree(buf); return; } in++; ctxt->input->col++; } in++; ctxt->input->col++; goto get_more; } } while (((*in >= 0x20) && (*in <= 0x7F)) || (*in == 0x09) || (*in == 0x0a)); xmlParseCommentComplex(ctxt, buf, len, size); ctxt->instate = state; return;}
/** * xmlParsePITarget: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * parse the name of a PI * * [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l')) * * Returns the PITarget name or NULL */
const xmlChar *xmlParsePITarget(xmlParserCtxtPtr ctxt) { const xmlChar *name;
name = xmlParseName(ctxt); if ((name != NULL) && ((name[0] == 'x') || (name[0] == 'X')) && ((name[1] == 'm') || (name[1] == 'M')) && ((name[2] == 'l') || (name[2] == 'L'))) { int i; if ((name[0] == 'x') && (name[1] == 'm') && (name[2] == 'l') && (name[3] == 0)) { xmlFatalErrMsg(ctxt, XML_ERR_RESERVED_XML_NAME, "XML declaration allowed only at the start of the document\n"); return(name); } else if (name[3] == 0) { xmlFatalErr(ctxt, XML_ERR_RESERVED_XML_NAME, NULL); return(name); } for (i = 0;;i++) { if (xmlW3CPIs[i] == NULL) break; if (xmlStrEqual(name, (const xmlChar *)xmlW3CPIs[i])) return(name); } xmlWarningMsg(ctxt, XML_ERR_RESERVED_XML_NAME, "xmlParsePITarget: invalid name prefix 'xml'\n", NULL, NULL); } if ((name != NULL) && (xmlStrchr(name, ':') != NULL)) { xmlNsErr(ctxt, XML_NS_ERR_COLON, "colons are forbidden from PI names '%s'\n", name, NULL, NULL); } return(name);}
#ifdef LIBXML_CATALOG_ENABLED/** * xmlParseCatalogPI: * @ctxt: an XML parser context * @catalog: the PI value string * * parse an XML Catalog Processing Instruction. * * <?oasis-xml-catalog catalog="http://example.com/catalog.xml"?> * * Occurs only if allowed by the user and if happening in the Misc * part of the document before any doctype information * This will add the given catalog to the parsing context in order * to be used if there is a resolution need further down in the document */
static voidxmlParseCatalogPI(xmlParserCtxtPtr ctxt, const xmlChar *catalog) { xmlChar *URL = NULL; const xmlChar *tmp, *base; xmlChar marker;
tmp = catalog; while (IS_BLANK_CH(*tmp)) tmp++; if (xmlStrncmp(tmp, BAD_CAST"catalog", 7)) goto error; tmp += 7; while (IS_BLANK_CH(*tmp)) tmp++; if (*tmp != '=') { return; } tmp++; while (IS_BLANK_CH(*tmp)) tmp++; marker = *tmp; if ((marker != '\'') && (marker != '"')) goto error; tmp++; base = tmp; while ((*tmp != 0) && (*tmp != marker)) tmp++; if (*tmp == 0) goto error; URL = xmlStrndup(base, tmp - base); tmp++; while (IS_BLANK_CH(*tmp)) tmp++; if (*tmp != 0) goto error;
if (URL != NULL) { ctxt->catalogs = xmlCatalogAddLocal(ctxt->catalogs, URL); xmlFree(URL); } return;
error: xmlWarningMsg(ctxt, XML_WAR_CATALOG_PI, "Catalog PI syntax error: %s\n", catalog, NULL); if (URL != NULL) xmlFree(URL);}#endif
/** * xmlParsePI: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * parse an XML Processing Instruction. * * [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>' * * The processing is transferred to SAX once parsed. */
voidxmlParsePI(xmlParserCtxtPtr ctxt) { xmlChar *buf = NULL; size_t len = 0; size_t size = XML_PARSER_BUFFER_SIZE; size_t maxLength = (ctxt->options & XML_PARSE_HUGE) ? XML_MAX_HUGE_LENGTH : XML_MAX_TEXT_LENGTH; int cur, l; const xmlChar *target; xmlParserInputState state;
if ((RAW == '<') && (NXT(1) == '?')) { int inputid = ctxt->input->id; state = ctxt->instate; ctxt->instate = XML_PARSER_PI; /* * this is a Processing Instruction. */ SKIP(2);
/* * Parse the target name and check for special support like * namespace. */ target = xmlParsePITarget(ctxt); if (target != NULL) { if ((RAW == '?') && (NXT(1) == '>')) { if (inputid != ctxt->input->id) { xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, "PI declaration doesn't start and stop in" " the same entity\n"); } SKIP(2);
/* * SAX: PI detected. */ if ((ctxt->sax) && (!ctxt->disableSAX) && (ctxt->sax->processingInstruction != NULL)) ctxt->sax->processingInstruction(ctxt->userData, target, NULL); if (ctxt->instate != XML_PARSER_EOF) ctxt->instate = state; return; } buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { xmlErrMemory(ctxt, NULL); ctxt->instate = state; return; } if (SKIP_BLANKS == 0) { xmlFatalErrMsgStr(ctxt, XML_ERR_SPACE_REQUIRED, "ParsePI: PI %s space expected\n", target); } cur = CUR_CHAR(l); while (IS_CHAR(cur) && /* checked */ ((cur != '?') || (NXT(1) != '>'))) { if (len + 5 >= size) { xmlChar *tmp; size_t new_size = size * 2; tmp = (xmlChar *) xmlRealloc(buf, new_size); if (tmp == NULL) { xmlErrMemory(ctxt, NULL); xmlFree(buf); ctxt->instate = state; return; } buf = tmp; size = new_size; } COPY_BUF(buf, len, cur); if (len > maxLength) { xmlFatalErrMsgStr(ctxt, XML_ERR_PI_NOT_FINISHED, "PI %s too big found", target); xmlFree(buf); ctxt->instate = state; return; } NEXTL(l); cur = CUR_CHAR(l); } buf[len] = 0; if (ctxt->instate == XML_PARSER_EOF) { xmlFree(buf); return; } if (cur != '?') { xmlFatalErrMsgStr(ctxt, XML_ERR_PI_NOT_FINISHED, "ParsePI: PI %s never end ...\n", target); } else { if (inputid != ctxt->input->id) { xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, "PI declaration doesn't start and stop in" " the same entity\n"); } SKIP(2);
#ifdef LIBXML_CATALOG_ENABLED if (((state == XML_PARSER_MISC) || (state == XML_PARSER_START)) && (xmlStrEqual(target, XML_CATALOG_PI))) { xmlCatalogAllow allow = xmlCatalogGetDefaults(); if ((allow == XML_CATA_ALLOW_DOCUMENT) || (allow == XML_CATA_ALLOW_ALL)) xmlParseCatalogPI(ctxt, buf); }#endif
/* * SAX: PI detected. */ if ((ctxt->sax) && (!ctxt->disableSAX) && (ctxt->sax->processingInstruction != NULL)) ctxt->sax->processingInstruction(ctxt->userData, target, buf); } xmlFree(buf); } else { xmlFatalErr(ctxt, XML_ERR_PI_NOT_STARTED, NULL); } if (ctxt->instate != XML_PARSER_EOF) ctxt->instate = state; }}
/** * xmlParseNotationDecl: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * Parse a notation declaration. Always consumes '<!'. * * [82] NotationDecl ::= '<!NOTATION' S Name S (ExternalID | PublicID) S? '>' * * Hence there is actually 3 choices: * 'PUBLIC' S PubidLiteral * 'PUBLIC' S PubidLiteral S SystemLiteral * and 'SYSTEM' S SystemLiteral * * See the NOTE on xmlParseExternalID(). */
voidxmlParseNotationDecl(xmlParserCtxtPtr ctxt) { const xmlChar *name; xmlChar *Pubid; xmlChar *Systemid;
if ((CUR != '<') || (NXT(1) != '!')) return; SKIP(2);
if (CMP8(CUR_PTR, 'N', 'O', 'T', 'A', 'T', 'I', 'O', 'N')) { int inputid = ctxt->input->id; SKIP(8); if (SKIP_BLANKS == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after '<!NOTATION'\n"); return; }
name = xmlParseName(ctxt); if (name == NULL) { xmlFatalErr(ctxt, XML_ERR_NOTATION_NOT_STARTED, NULL); return; } if (xmlStrchr(name, ':') != NULL) { xmlNsErr(ctxt, XML_NS_ERR_COLON, "colons are forbidden from notation names '%s'\n", name, NULL, NULL); } if (SKIP_BLANKS == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after the NOTATION name'\n"); return; }
/* * Parse the IDs. */ Systemid = xmlParseExternalID(ctxt, &Pubid, 0); SKIP_BLANKS;
if (RAW == '>') { if (inputid != ctxt->input->id) { xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, "Notation declaration doesn't start and stop" " in the same entity\n"); } NEXT; if ((ctxt->sax != NULL) && (!ctxt->disableSAX) && (ctxt->sax->notationDecl != NULL)) ctxt->sax->notationDecl(ctxt->userData, name, Pubid, Systemid); } else { xmlFatalErr(ctxt, XML_ERR_NOTATION_NOT_FINISHED, NULL); } if (Systemid != NULL) xmlFree(Systemid); if (Pubid != NULL) xmlFree(Pubid); }}
/** * xmlParseEntityDecl: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * Parse an entity declaration. Always consumes '<!'. * * [70] EntityDecl ::= GEDecl | PEDecl * * [71] GEDecl ::= '<!ENTITY' S Name S EntityDef S? '>' * * [72] PEDecl ::= '<!ENTITY' S '%' S Name S PEDef S? '>' * * [73] EntityDef ::= EntityValue | (ExternalID NDataDecl?) * * [74] PEDef ::= EntityValue | ExternalID * * [76] NDataDecl ::= S 'NDATA' S Name * * [ VC: Notation Declared ] * The Name must match the declared name of a notation. */
voidxmlParseEntityDecl(xmlParserCtxtPtr ctxt) { const xmlChar *name = NULL; xmlChar *value = NULL; xmlChar *URI = NULL, *literal = NULL; const xmlChar *ndata = NULL; int isParameter = 0; xmlChar *orig = NULL;
if ((CUR != '<') || (NXT(1) != '!')) return; SKIP(2);
/* GROW; done in the caller */ if (CMP6(CUR_PTR, 'E', 'N', 'T', 'I', 'T', 'Y')) { int inputid = ctxt->input->id; SKIP(6); if (SKIP_BLANKS == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after '<!ENTITY'\n"); }
if (RAW == '%') { NEXT; if (SKIP_BLANKS == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after '%%'\n"); } isParameter = 1; }
name = xmlParseName(ctxt); if (name == NULL) { xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, "xmlParseEntityDecl: no name\n"); return; } if (xmlStrchr(name, ':') != NULL) { xmlNsErr(ctxt, XML_NS_ERR_COLON, "colons are forbidden from entities names '%s'\n", name, NULL, NULL); } if (SKIP_BLANKS == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after the entity name\n"); }
ctxt->instate = XML_PARSER_ENTITY_DECL; /* * handle the various case of definitions... */ if (isParameter) { if ((RAW == '"') || (RAW == '\'')) { value = xmlParseEntityValue(ctxt, &orig); if (value) { if ((ctxt->sax != NULL) && (!ctxt->disableSAX) && (ctxt->sax->entityDecl != NULL)) ctxt->sax->entityDecl(ctxt->userData, name, XML_INTERNAL_PARAMETER_ENTITY, NULL, NULL, value); } } else { URI = xmlParseExternalID(ctxt, &literal, 1); if ((URI == NULL) && (literal == NULL)) { xmlFatalErr(ctxt, XML_ERR_VALUE_REQUIRED, NULL); } if (URI) { xmlURIPtr uri;
uri = xmlParseURI((const char *) URI); if (uri == NULL) { xmlErrMsgStr(ctxt, XML_ERR_INVALID_URI, "Invalid URI: %s\n", URI); /* * This really ought to be a well formedness error * but the XML Core WG decided otherwise c.f. issue * E26 of the XML erratas. */ } else { if (uri->fragment != NULL) { /* * Okay this is foolish to block those but not * invalid URIs. */ xmlFatalErr(ctxt, XML_ERR_URI_FRAGMENT, NULL); } else { if ((ctxt->sax != NULL) && (!ctxt->disableSAX) && (ctxt->sax->entityDecl != NULL)) ctxt->sax->entityDecl(ctxt->userData, name, XML_EXTERNAL_PARAMETER_ENTITY, literal, URI, NULL); } xmlFreeURI(uri); } } } } else { if ((RAW == '"') || (RAW == '\'')) { value = xmlParseEntityValue(ctxt, &orig); if ((ctxt->sax != NULL) && (!ctxt->disableSAX) && (ctxt->sax->entityDecl != NULL)) ctxt->sax->entityDecl(ctxt->userData, name, XML_INTERNAL_GENERAL_ENTITY, NULL, NULL, value); /* * For expat compatibility in SAX mode. */ if ((ctxt->myDoc == NULL) || (xmlStrEqual(ctxt->myDoc->version, SAX_COMPAT_MODE))) { if (ctxt->myDoc == NULL) { ctxt->myDoc = xmlNewDoc(SAX_COMPAT_MODE); if (ctxt->myDoc == NULL) { xmlErrMemory(ctxt, "New Doc failed"); goto done; } ctxt->myDoc->properties = XML_DOC_INTERNAL; } if (ctxt->myDoc->intSubset == NULL) ctxt->myDoc->intSubset = xmlNewDtd(ctxt->myDoc, BAD_CAST "fake", NULL, NULL);
xmlSAX2EntityDecl(ctxt, name, XML_INTERNAL_GENERAL_ENTITY, NULL, NULL, value); } } else { URI = xmlParseExternalID(ctxt, &literal, 1); if ((URI == NULL) && (literal == NULL)) { xmlFatalErr(ctxt, XML_ERR_VALUE_REQUIRED, NULL); } if (URI) { xmlURIPtr uri;
uri = xmlParseURI((const char *)URI); if (uri == NULL) { xmlErrMsgStr(ctxt, XML_ERR_INVALID_URI, "Invalid URI: %s\n", URI); /* * This really ought to be a well formedness error * but the XML Core WG decided otherwise c.f. issue * E26 of the XML erratas. */ } else { if (uri->fragment != NULL) { /* * Okay this is foolish to block those but not * invalid URIs. */ xmlFatalErr(ctxt, XML_ERR_URI_FRAGMENT, NULL); } xmlFreeURI(uri); } } if ((RAW != '>') && (SKIP_BLANKS == 0)) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required before 'NDATA'\n"); } if (CMP5(CUR_PTR, 'N', 'D', 'A', 'T', 'A')) { SKIP(5); if (SKIP_BLANKS == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after 'NDATA'\n"); } ndata = xmlParseName(ctxt); if ((ctxt->sax != NULL) && (!ctxt->disableSAX) && (ctxt->sax->unparsedEntityDecl != NULL)) ctxt->sax->unparsedEntityDecl(ctxt->userData, name, literal, URI, ndata); } else { if ((ctxt->sax != NULL) && (!ctxt->disableSAX) && (ctxt->sax->entityDecl != NULL)) ctxt->sax->entityDecl(ctxt->userData, name, XML_EXTERNAL_GENERAL_PARSED_ENTITY, literal, URI, NULL); /* * For expat compatibility in SAX mode. * assuming the entity replacement was asked for */ if ((ctxt->replaceEntities != 0) && ((ctxt->myDoc == NULL) || (xmlStrEqual(ctxt->myDoc->version, SAX_COMPAT_MODE)))) { if (ctxt->myDoc == NULL) { ctxt->myDoc = xmlNewDoc(SAX_COMPAT_MODE); if (ctxt->myDoc == NULL) { xmlErrMemory(ctxt, "New Doc failed"); goto done; } ctxt->myDoc->properties = XML_DOC_INTERNAL; }
if (ctxt->myDoc->intSubset == NULL) ctxt->myDoc->intSubset = xmlNewDtd(ctxt->myDoc, BAD_CAST "fake", NULL, NULL); xmlSAX2EntityDecl(ctxt, name, XML_EXTERNAL_GENERAL_PARSED_ENTITY, literal, URI, NULL); } } } } if (ctxt->instate == XML_PARSER_EOF) goto done; SKIP_BLANKS; if (RAW != '>') { xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_NOT_FINISHED, "xmlParseEntityDecl: entity %s not terminated\n", name); xmlHaltParser(ctxt); } else { if (inputid != ctxt->input->id) { xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, "Entity declaration doesn't start and stop in" " the same entity\n"); } NEXT; } if (orig != NULL) { /* * Ugly mechanism to save the raw entity value. */ xmlEntityPtr cur = NULL;
if (isParameter) { if ((ctxt->sax != NULL) && (ctxt->sax->getParameterEntity != NULL)) cur = ctxt->sax->getParameterEntity(ctxt->userData, name); } else { if ((ctxt->sax != NULL) && (ctxt->sax->getEntity != NULL)) cur = ctxt->sax->getEntity(ctxt->userData, name); if ((cur == NULL) && (ctxt->userData==ctxt)) { cur = xmlSAX2GetEntity(ctxt, name); } } if ((cur != NULL) && (cur->orig == NULL)) { cur->orig = orig; orig = NULL; } }
done: if (value != NULL) xmlFree(value); if (URI != NULL) xmlFree(URI); if (literal != NULL) xmlFree(literal); if (orig != NULL) xmlFree(orig); }}
/** * xmlParseDefaultDecl: * @ctxt: an XML parser context * @value: Receive a possible fixed default value for the attribute * * DEPRECATED: Internal function, don't use. * * Parse an attribute default declaration * * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue) * * [ VC: Required Attribute ] * if the default declaration is the keyword #REQUIRED, then the * attribute must be specified for all elements of the type in the * attribute-list declaration. * * [ VC: Attribute Default Legal ] * The declared default value must meet the lexical constraints of * the declared attribute type c.f. xmlValidateAttributeDecl() * * [ VC: Fixed Attribute Default ] * if an attribute has a default value declared with the #FIXED * keyword, instances of that attribute must match the default value. * * [ WFC: No < in Attribute Values ] * handled in xmlParseAttValue() * * returns: XML_ATTRIBUTE_NONE, XML_ATTRIBUTE_REQUIRED, XML_ATTRIBUTE_IMPLIED * or XML_ATTRIBUTE_FIXED. */
intxmlParseDefaultDecl(xmlParserCtxtPtr ctxt, xmlChar **value) { int val; xmlChar *ret;
*value = NULL; if (CMP9(CUR_PTR, '#', 'R', 'E', 'Q', 'U', 'I', 'R', 'E', 'D')) { SKIP(9); return(XML_ATTRIBUTE_REQUIRED); } if (CMP8(CUR_PTR, '#', 'I', 'M', 'P', 'L', 'I', 'E', 'D')) { SKIP(8); return(XML_ATTRIBUTE_IMPLIED); } val = XML_ATTRIBUTE_NONE; if (CMP6(CUR_PTR, '#', 'F', 'I', 'X', 'E', 'D')) { SKIP(6); val = XML_ATTRIBUTE_FIXED; if (SKIP_BLANKS == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after '#FIXED'\n"); } } ret = xmlParseAttValue(ctxt); ctxt->instate = XML_PARSER_DTD; if (ret == NULL) { xmlFatalErrMsg(ctxt, (xmlParserErrors)ctxt->errNo, "Attribute default value declaration error\n"); } else *value = ret; return(val);}
/** * xmlParseNotationType: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * parse an Notation attribute type. * * Note: the leading 'NOTATION' S part has already being parsed... * * [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')' * * [ VC: Notation Attributes ] * Values of this type must match one of the notation names included * in the declaration; all notation names in the declaration must be declared. * * Returns: the notation attribute tree built while parsing */
xmlEnumerationPtrxmlParseNotationType(xmlParserCtxtPtr ctxt) { const xmlChar *name; xmlEnumerationPtr ret = NULL, last = NULL, cur, tmp;
if (RAW != '(') { xmlFatalErr(ctxt, XML_ERR_NOTATION_NOT_STARTED, NULL); return(NULL); } do { NEXT; SKIP_BLANKS; name = xmlParseName(ctxt); if (name == NULL) { xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, "Name expected in NOTATION declaration\n"); xmlFreeEnumeration(ret); return(NULL); } tmp = ret; while (tmp != NULL) { if (xmlStrEqual(name, tmp->name)) { xmlValidityError(ctxt, XML_DTD_DUP_TOKEN, "standalone: attribute notation value token %s duplicated\n", name, NULL); if (!xmlDictOwns(ctxt->dict, name)) xmlFree((xmlChar *) name); break; } tmp = tmp->next; } if (tmp == NULL) { cur = xmlCreateEnumeration(name); if (cur == NULL) { xmlFreeEnumeration(ret); return(NULL); } if (last == NULL) ret = last = cur; else { last->next = cur; last = cur; } } SKIP_BLANKS; } while (RAW == '|'); if (RAW != ')') { xmlFatalErr(ctxt, XML_ERR_NOTATION_NOT_FINISHED, NULL); xmlFreeEnumeration(ret); return(NULL); } NEXT; return(ret);}
/** * xmlParseEnumerationType: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * parse an Enumeration attribute type. * * [59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')' * * [ VC: Enumeration ] * Values of this type must match one of the Nmtoken tokens in * the declaration * * Returns: the enumeration attribute tree built while parsing */
xmlEnumerationPtrxmlParseEnumerationType(xmlParserCtxtPtr ctxt) { xmlChar *name; xmlEnumerationPtr ret = NULL, last = NULL, cur, tmp;
if (RAW != '(') { xmlFatalErr(ctxt, XML_ERR_ATTLIST_NOT_STARTED, NULL); return(NULL); } do { NEXT; SKIP_BLANKS; name = xmlParseNmtoken(ctxt); if (name == NULL) { xmlFatalErr(ctxt, XML_ERR_NMTOKEN_REQUIRED, NULL); return(ret); } tmp = ret; while (tmp != NULL) { if (xmlStrEqual(name, tmp->name)) { xmlValidityError(ctxt, XML_DTD_DUP_TOKEN, "standalone: attribute enumeration value token %s duplicated\n", name, NULL); if (!xmlDictOwns(ctxt->dict, name)) xmlFree(name); break; } tmp = tmp->next; } if (tmp == NULL) { cur = xmlCreateEnumeration(name); if (!xmlDictOwns(ctxt->dict, name)) xmlFree(name); if (cur == NULL) { xmlFreeEnumeration(ret); return(NULL); } if (last == NULL) ret = last = cur; else { last->next = cur; last = cur; } } SKIP_BLANKS; } while (RAW == '|'); if (RAW != ')') { xmlFatalErr(ctxt, XML_ERR_ATTLIST_NOT_FINISHED, NULL); return(ret); } NEXT; return(ret);}
/** * xmlParseEnumeratedType: * @ctxt: an XML parser context * @tree: the enumeration tree built while parsing * * DEPRECATED: Internal function, don't use. * * parse an Enumerated attribute type. * * [57] EnumeratedType ::= NotationType | Enumeration * * [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')' * * * Returns: XML_ATTRIBUTE_ENUMERATION or XML_ATTRIBUTE_NOTATION */
intxmlParseEnumeratedType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) { if (CMP8(CUR_PTR, 'N', 'O', 'T', 'A', 'T', 'I', 'O', 'N')) { SKIP(8); if (SKIP_BLANKS == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after 'NOTATION'\n"); return(0); } *tree = xmlParseNotationType(ctxt); if (*tree == NULL) return(0); return(XML_ATTRIBUTE_NOTATION); } *tree = xmlParseEnumerationType(ctxt); if (*tree == NULL) return(0); return(XML_ATTRIBUTE_ENUMERATION);}
/** * xmlParseAttributeType: * @ctxt: an XML parser context * @tree: the enumeration tree built while parsing * * DEPRECATED: Internal function, don't use. * * parse the Attribute list def for an element * * [54] AttType ::= StringType | TokenizedType | EnumeratedType * * [55] StringType ::= 'CDATA' * * [56] TokenizedType ::= 'ID' | 'IDREF' | 'IDREFS' | 'ENTITY' | * 'ENTITIES' | 'NMTOKEN' | 'NMTOKENS' * * Validity constraints for attribute values syntax are checked in * xmlValidateAttributeValue() * * [ VC: ID ] * Values of type ID must match the Name production. A name must not * appear more than once in an XML document as a value of this type; * i.e., ID values must uniquely identify the elements which bear them. * * [ VC: One ID per Element Type ] * No element type may have more than one ID attribute specified. * * [ VC: ID Attribute Default ] * An ID attribute must have a declared default of #IMPLIED or #REQUIRED. * * [ VC: IDREF ] * Values of type IDREF must match the Name production, and values * of type IDREFS must match Names; each IDREF 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 the Name production, values * of type ENTITIES must match Names; each Entity Name must match the * name of an unparsed entity declared in the DTD. * * [ VC: Name Token ] * Values of type NMTOKEN must match the Nmtoken production; values * of type NMTOKENS must match Nmtokens. * * Returns the attribute type */intxmlParseAttributeType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) { if (CMP5(CUR_PTR, 'C', 'D', 'A', 'T', 'A')) { SKIP(5); return(XML_ATTRIBUTE_CDATA); } else if (CMP6(CUR_PTR, 'I', 'D', 'R', 'E', 'F', 'S')) { SKIP(6); return(XML_ATTRIBUTE_IDREFS); } else if (CMP5(CUR_PTR, 'I', 'D', 'R', 'E', 'F')) { SKIP(5); return(XML_ATTRIBUTE_IDREF); } else if ((RAW == 'I') && (NXT(1) == 'D')) { SKIP(2); return(XML_ATTRIBUTE_ID); } else if (CMP6(CUR_PTR, 'E', 'N', 'T', 'I', 'T', 'Y')) { SKIP(6); return(XML_ATTRIBUTE_ENTITY); } else if (CMP8(CUR_PTR, 'E', 'N', 'T', 'I', 'T', 'I', 'E', 'S')) { SKIP(8); return(XML_ATTRIBUTE_ENTITIES); } else if (CMP8(CUR_PTR, 'N', 'M', 'T', 'O', 'K', 'E', 'N', 'S')) { SKIP(8); return(XML_ATTRIBUTE_NMTOKENS); } else if (CMP7(CUR_PTR, 'N', 'M', 'T', 'O', 'K', 'E', 'N')) { SKIP(7); return(XML_ATTRIBUTE_NMTOKEN); } return(xmlParseEnumeratedType(ctxt, tree));}
/** * xmlParseAttributeListDecl: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * Parse an attribute list declaration for an element. Always consumes '<!'. * * [52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>' * * [53] AttDef ::= S Name S AttType S DefaultDecl * */voidxmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) { const xmlChar *elemName; const xmlChar *attrName; xmlEnumerationPtr tree;
if ((CUR != '<') || (NXT(1) != '!')) return; SKIP(2);
if (CMP7(CUR_PTR, 'A', 'T', 'T', 'L', 'I', 'S', 'T')) { int inputid = ctxt->input->id;
SKIP(7); if (SKIP_BLANKS == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after '<!ATTLIST'\n"); } elemName = xmlParseName(ctxt); if (elemName == NULL) { xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, "ATTLIST: no name for Element\n"); return; } SKIP_BLANKS; GROW; while ((RAW != '>') && (ctxt->instate != XML_PARSER_EOF)) { int type; int def; xmlChar *defaultValue = NULL;
GROW; tree = NULL; attrName = xmlParseName(ctxt); if (attrName == NULL) { xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, "ATTLIST: no name for Attribute\n"); break; } GROW; if (SKIP_BLANKS == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after the attribute name\n"); break; }
type = xmlParseAttributeType(ctxt, &tree); if (type <= 0) { break; }
GROW; if (SKIP_BLANKS == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after the attribute type\n"); if (tree != NULL) xmlFreeEnumeration(tree); break; }
def = xmlParseDefaultDecl(ctxt, &defaultValue); if (def <= 0) { if (defaultValue != NULL) xmlFree(defaultValue); if (tree != NULL) xmlFreeEnumeration(tree); break; } if ((type != XML_ATTRIBUTE_CDATA) && (defaultValue != NULL)) xmlAttrNormalizeSpace(defaultValue, defaultValue);
GROW; if (RAW != '>') { if (SKIP_BLANKS == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after the attribute default value\n"); if (defaultValue != NULL) xmlFree(defaultValue); if (tree != NULL) xmlFreeEnumeration(tree); break; } } if ((ctxt->sax != NULL) && (!ctxt->disableSAX) && (ctxt->sax->attributeDecl != NULL)) ctxt->sax->attributeDecl(ctxt->userData, elemName, attrName, type, def, defaultValue, tree); else if (tree != NULL) xmlFreeEnumeration(tree);
if ((ctxt->sax2) && (defaultValue != NULL) && (def != XML_ATTRIBUTE_IMPLIED) && (def != XML_ATTRIBUTE_REQUIRED)) { xmlAddDefAttrs(ctxt, elemName, attrName, defaultValue); } if (ctxt->sax2) { xmlAddSpecialAttr(ctxt, elemName, attrName, type); } if (defaultValue != NULL) xmlFree(defaultValue); GROW; } if (RAW == '>') { if (inputid != ctxt->input->id) { xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, "Attribute list declaration doesn't start and" " stop in the same entity\n"); } NEXT; } }}
/** * xmlParseElementMixedContentDecl: * @ctxt: an XML parser context * @inputchk: the input used for the current entity, needed for boundary checks * * DEPRECATED: Internal function, don't use. * * parse the declaration for a Mixed Element content * The leading '(' and spaces have been skipped in xmlParseElementContentDecl * * [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' | * '(' S? '#PCDATA' S? ')' * * [ VC: Proper Group/PE Nesting ] applies to [51] too (see [49]) * * [ VC: No Duplicate Types ] * The same name must not appear more than once in a single * mixed-content declaration. * * returns: the list of the xmlElementContentPtr describing the element choices */xmlElementContentPtrxmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt, int inputchk) { xmlElementContentPtr ret = NULL, cur = NULL, n; const xmlChar *elem = NULL;
GROW; if (CMP7(CUR_PTR, '#', 'P', 'C', 'D', 'A', 'T', 'A')) { SKIP(7); SKIP_BLANKS; if (RAW == ')') { if (ctxt->input->id != inputchk) { xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, "Element content declaration doesn't start and" " stop in the same entity\n"); } NEXT; ret = xmlNewDocElementContent(ctxt->myDoc, NULL, XML_ELEMENT_CONTENT_PCDATA); if (ret == NULL) return(NULL); if (RAW == '*') { ret->ocur = XML_ELEMENT_CONTENT_MULT; NEXT; } return(ret); } if ((RAW == '(') || (RAW == '|')) { ret = cur = xmlNewDocElementContent(ctxt->myDoc, NULL, XML_ELEMENT_CONTENT_PCDATA); if (ret == NULL) return(NULL); } while ((RAW == '|') && (ctxt->instate != XML_PARSER_EOF)) { NEXT; if (elem == NULL) { ret = xmlNewDocElementContent(ctxt->myDoc, NULL, XML_ELEMENT_CONTENT_OR); if (ret == NULL) { xmlFreeDocElementContent(ctxt->myDoc, cur); return(NULL); } ret->c1 = cur; if (cur != NULL) cur->parent = ret; cur = ret; } else { n = xmlNewDocElementContent(ctxt->myDoc, NULL, XML_ELEMENT_CONTENT_OR); if (n == NULL) { xmlFreeDocElementContent(ctxt->myDoc, ret); return(NULL); } n->c1 = xmlNewDocElementContent(ctxt->myDoc, elem, XML_ELEMENT_CONTENT_ELEMENT); if (n->c1 != NULL) n->c1->parent = n; cur->c2 = n; if (n != NULL) n->parent = cur; cur = n; } SKIP_BLANKS; elem = xmlParseName(ctxt); if (elem == NULL) { xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, "xmlParseElementMixedContentDecl : Name expected\n"); xmlFreeDocElementContent(ctxt->myDoc, ret); return(NULL); } SKIP_BLANKS; GROW; } if ((RAW == ')') && (NXT(1) == '*')) { if (elem != NULL) { cur->c2 = xmlNewDocElementContent(ctxt->myDoc, elem, XML_ELEMENT_CONTENT_ELEMENT); if (cur->c2 != NULL) cur->c2->parent = cur; } if (ret != NULL) ret->ocur = XML_ELEMENT_CONTENT_MULT; if (ctxt->input->id != inputchk) { xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, "Element content declaration doesn't start and" " stop in the same entity\n"); } SKIP(2); } else { xmlFreeDocElementContent(ctxt->myDoc, ret); xmlFatalErr(ctxt, XML_ERR_MIXED_NOT_STARTED, NULL); return(NULL); }
} else { xmlFatalErr(ctxt, XML_ERR_PCDATA_REQUIRED, NULL); } return(ret);}
/** * xmlParseElementChildrenContentDeclPriv: * @ctxt: an XML parser context * @inputchk: the input used for the current entity, needed for boundary checks * @depth: the level of recursion * * parse the declaration for a Mixed Element content * The leading '(' and spaces have been skipped in xmlParseElementContentDecl * * * [47] children ::= (choice | seq) ('?' | '*' | '+')? * * [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')? * * [49] choice ::= '(' S? cp ( S? '|' S? cp )* S? ')' * * [50] seq ::= '(' S? cp ( S? ',' S? cp )* S? ')' * * [ VC: Proper Group/PE Nesting ] applies to [49] and [50] * TODO Parameter-entity replacement text must be properly nested * with parenthesized groups. That is to say, if either of the * opening or closing parentheses in a choice, seq, or Mixed * construct is contained in the replacement text for a parameter * entity, both must be contained in the same replacement text. For * interoperability, if a parameter-entity reference appears in a * choice, seq, or Mixed construct, its replacement text should not * be empty, and neither the first nor last non-blank character of * the replacement text should be a connector (| or ,). * * Returns the tree of xmlElementContentPtr describing the element * hierarchy. */static xmlElementContentPtrxmlParseElementChildrenContentDeclPriv(xmlParserCtxtPtr ctxt, int inputchk, int depth) { xmlElementContentPtr ret = NULL, cur = NULL, last = NULL, op = NULL; const xmlChar *elem; xmlChar type = 0;
if (((depth > 128) && ((ctxt->options & XML_PARSE_HUGE) == 0)) || (depth > 2048)) { xmlFatalErrMsgInt(ctxt, XML_ERR_ELEMCONTENT_NOT_FINISHED,"xmlParseElementChildrenContentDecl : depth %d too deep, use XML_PARSE_HUGE\n", depth); return(NULL); } SKIP_BLANKS; GROW; if (RAW == '(') { int inputid = ctxt->input->id;
/* Recurse on first child */ NEXT; SKIP_BLANKS; cur = ret = xmlParseElementChildrenContentDeclPriv(ctxt, inputid, depth + 1); if (cur == NULL) return(NULL); SKIP_BLANKS; GROW; } else { elem = xmlParseName(ctxt); if (elem == NULL) { xmlFatalErr(ctxt, XML_ERR_ELEMCONTENT_NOT_STARTED, NULL); return(NULL); } cur = ret = xmlNewDocElementContent(ctxt->myDoc, elem, XML_ELEMENT_CONTENT_ELEMENT); if (cur == NULL) { xmlErrMemory(ctxt, NULL); return(NULL); } GROW; if (RAW == '?') { cur->ocur = XML_ELEMENT_CONTENT_OPT; NEXT; } else if (RAW == '*') { cur->ocur = XML_ELEMENT_CONTENT_MULT; NEXT; } else if (RAW == '+') { cur->ocur = XML_ELEMENT_CONTENT_PLUS; NEXT; } else { cur->ocur = XML_ELEMENT_CONTENT_ONCE; } GROW; } SKIP_BLANKS; while ((RAW != ')') && (ctxt->instate != XML_PARSER_EOF)) { /* * Each loop we parse one separator and one element. */ if (RAW == ',') { if (type == 0) type = CUR;
/* * Detect "Name | Name , Name" error */ else if (type != CUR) { xmlFatalErrMsgInt(ctxt, XML_ERR_SEPARATOR_REQUIRED, "xmlParseElementChildrenContentDecl : '%c' expected\n", type); if ((last != NULL) && (last != ret)) xmlFreeDocElementContent(ctxt->myDoc, last); if (ret != NULL) xmlFreeDocElementContent(ctxt->myDoc, ret); return(NULL); } NEXT;
op = xmlNewDocElementContent(ctxt->myDoc, NULL, XML_ELEMENT_CONTENT_SEQ); if (op == NULL) { if ((last != NULL) && (last != ret)) xmlFreeDocElementContent(ctxt->myDoc, last); xmlFreeDocElementContent(ctxt->myDoc, ret); return(NULL); } if (last == NULL) { op->c1 = ret; if (ret != NULL) ret->parent = op; ret = cur = op; } else { cur->c2 = op; if (op != NULL) op->parent = cur; op->c1 = last; if (last != NULL) last->parent = op; cur =op; last = NULL; } } else if (RAW == '|') { if (type == 0) type = CUR;
/* * Detect "Name , Name | Name" error */ else if (type != CUR) { xmlFatalErrMsgInt(ctxt, XML_ERR_SEPARATOR_REQUIRED, "xmlParseElementChildrenContentDecl : '%c' expected\n", type); if ((last != NULL) && (last != ret)) xmlFreeDocElementContent(ctxt->myDoc, last); if (ret != NULL) xmlFreeDocElementContent(ctxt->myDoc, ret); return(NULL); } NEXT;
op = xmlNewDocElementContent(ctxt->myDoc, NULL, XML_ELEMENT_CONTENT_OR); if (op == NULL) { if ((last != NULL) && (last != ret)) xmlFreeDocElementContent(ctxt->myDoc, last); if (ret != NULL) xmlFreeDocElementContent(ctxt->myDoc, ret); return(NULL); } if (last == NULL) { op->c1 = ret; if (ret != NULL) ret->parent = op; ret = cur = op; } else { cur->c2 = op; if (op != NULL) op->parent = cur; op->c1 = last; if (last != NULL) last->parent = op; cur =op; last = NULL; } } else { xmlFatalErr(ctxt, XML_ERR_ELEMCONTENT_NOT_FINISHED, NULL); if ((last != NULL) && (last != ret)) xmlFreeDocElementContent(ctxt->myDoc, last); if (ret != NULL) xmlFreeDocElementContent(ctxt->myDoc, ret); return(NULL); } GROW; SKIP_BLANKS; GROW; if (RAW == '(') { int inputid = ctxt->input->id; /* Recurse on second child */ NEXT; SKIP_BLANKS; last = xmlParseElementChildrenContentDeclPriv(ctxt, inputid, depth + 1); if (last == NULL) { if (ret != NULL) xmlFreeDocElementContent(ctxt->myDoc, ret); return(NULL); } SKIP_BLANKS; } else { elem = xmlParseName(ctxt); if (elem == NULL) { xmlFatalErr(ctxt, XML_ERR_ELEMCONTENT_NOT_STARTED, NULL); if (ret != NULL) xmlFreeDocElementContent(ctxt->myDoc, ret); return(NULL); } last = xmlNewDocElementContent(ctxt->myDoc, elem, XML_ELEMENT_CONTENT_ELEMENT); if (last == NULL) { if (ret != NULL) xmlFreeDocElementContent(ctxt->myDoc, ret); return(NULL); } if (RAW == '?') { last->ocur = XML_ELEMENT_CONTENT_OPT; NEXT; } else if (RAW == '*') { last->ocur = XML_ELEMENT_CONTENT_MULT; NEXT; } else if (RAW == '+') { last->ocur = XML_ELEMENT_CONTENT_PLUS; NEXT; } else { last->ocur = XML_ELEMENT_CONTENT_ONCE; } } SKIP_BLANKS; GROW; } if ((cur != NULL) && (last != NULL)) { cur->c2 = last; if (last != NULL) last->parent = cur; } if (ctxt->input->id != inputchk) { xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, "Element content declaration doesn't start and stop in" " the same entity\n"); } NEXT; if (RAW == '?') { if (ret != NULL) { if ((ret->ocur == XML_ELEMENT_CONTENT_PLUS) || (ret->ocur == XML_ELEMENT_CONTENT_MULT)) ret->ocur = XML_ELEMENT_CONTENT_MULT; else ret->ocur = XML_ELEMENT_CONTENT_OPT; } NEXT; } else if (RAW == '*') { if (ret != NULL) { ret->ocur = XML_ELEMENT_CONTENT_MULT; cur = ret; /* * Some normalization: * (a | b* | c?)* == (a | b | c)* */ while ((cur != NULL) && (cur->type == XML_ELEMENT_CONTENT_OR)) { if ((cur->c1 != NULL) && ((cur->c1->ocur == XML_ELEMENT_CONTENT_OPT) || (cur->c1->ocur == XML_ELEMENT_CONTENT_MULT))) cur->c1->ocur = XML_ELEMENT_CONTENT_ONCE; if ((cur->c2 != NULL) && ((cur->c2->ocur == XML_ELEMENT_CONTENT_OPT) || (cur->c2->ocur == XML_ELEMENT_CONTENT_MULT))) cur->c2->ocur = XML_ELEMENT_CONTENT_ONCE; cur = cur->c2; } } NEXT; } else if (RAW == '+') { if (ret != NULL) { int found = 0;
if ((ret->ocur == XML_ELEMENT_CONTENT_OPT) || (ret->ocur == XML_ELEMENT_CONTENT_MULT)) ret->ocur = XML_ELEMENT_CONTENT_MULT; else ret->ocur = XML_ELEMENT_CONTENT_PLUS; /* * Some normalization: * (a | b*)+ == (a | b)* * (a | b?)+ == (a | b)* */ while ((cur != NULL) && (cur->type == XML_ELEMENT_CONTENT_OR)) { if ((cur->c1 != NULL) && ((cur->c1->ocur == XML_ELEMENT_CONTENT_OPT) || (cur->c1->ocur == XML_ELEMENT_CONTENT_MULT))) { cur->c1->ocur = XML_ELEMENT_CONTENT_ONCE; found = 1; } if ((cur->c2 != NULL) && ((cur->c2->ocur == XML_ELEMENT_CONTENT_OPT) || (cur->c2->ocur == XML_ELEMENT_CONTENT_MULT))) { cur->c2->ocur = XML_ELEMENT_CONTENT_ONCE; found = 1; } cur = cur->c2; } if (found) ret->ocur = XML_ELEMENT_CONTENT_MULT; } NEXT; } return(ret);}
/** * xmlParseElementChildrenContentDecl: * @ctxt: an XML parser context * @inputchk: the input used for the current entity, needed for boundary checks * * DEPRECATED: Internal function, don't use. * * parse the declaration for a Mixed Element content * The leading '(' and spaces have been skipped in xmlParseElementContentDecl * * [47] children ::= (choice | seq) ('?' | '*' | '+')? * * [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')? * * [49] choice ::= '(' S? cp ( S? '|' S? cp )* S? ')' * * [50] seq ::= '(' S? cp ( S? ',' S? cp )* S? ')' * * [ VC: Proper Group/PE Nesting ] applies to [49] and [50] * TODO Parameter-entity replacement text must be properly nested * with parenthesized groups. That is to say, if either of the * opening or closing parentheses in a choice, seq, or Mixed * construct is contained in the replacement text for a parameter * entity, both must be contained in the same replacement text. For * interoperability, if a parameter-entity reference appears in a * choice, seq, or Mixed construct, its replacement text should not * be empty, and neither the first nor last non-blank character of * the replacement text should be a connector (| or ,). * * Returns the tree of xmlElementContentPtr describing the element * hierarchy. */xmlElementContentPtrxmlParseElementChildrenContentDecl(xmlParserCtxtPtr ctxt, int inputchk) { /* stub left for API/ABI compat */ return(xmlParseElementChildrenContentDeclPriv(ctxt, inputchk, 1));}
/** * xmlParseElementContentDecl: * @ctxt: an XML parser context * @name: the name of the element being defined. * @result: the Element Content pointer will be stored here if any * * DEPRECATED: Internal function, don't use. * * parse the declaration for an Element content either Mixed or Children, * the cases EMPTY and ANY are handled directly in xmlParseElementDecl * * [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children * * returns: the type of element content XML_ELEMENT_TYPE_xxx */
intxmlParseElementContentDecl(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlElementContentPtr *result) {
xmlElementContentPtr tree = NULL; int inputid = ctxt->input->id; int res;
*result = NULL;
if (RAW != '(') { xmlFatalErrMsgStr(ctxt, XML_ERR_ELEMCONTENT_NOT_STARTED, "xmlParseElementContentDecl : %s '(' expected\n", name); return(-1); } NEXT; GROW; if (ctxt->instate == XML_PARSER_EOF) return(-1); SKIP_BLANKS; if (CMP7(CUR_PTR, '#', 'P', 'C', 'D', 'A', 'T', 'A')) { tree = xmlParseElementMixedContentDecl(ctxt, inputid); res = XML_ELEMENT_TYPE_MIXED; } else { tree = xmlParseElementChildrenContentDeclPriv(ctxt, inputid, 1); res = XML_ELEMENT_TYPE_ELEMENT; } SKIP_BLANKS; *result = tree; return(res);}
/** * xmlParseElementDecl: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * Parse an element declaration. Always consumes '<!'. * * [45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>' * * [ VC: Unique Element Type Declaration ] * No element type may be declared more than once * * Returns the type of the element, or -1 in case of error */intxmlParseElementDecl(xmlParserCtxtPtr ctxt) { const xmlChar *name; int ret = -1; xmlElementContentPtr content = NULL;
if ((CUR != '<') || (NXT(1) != '!')) return(ret); SKIP(2);
/* GROW; done in the caller */ if (CMP7(CUR_PTR, 'E', 'L', 'E', 'M', 'E', 'N', 'T')) { int inputid = ctxt->input->id;
SKIP(7); if (SKIP_BLANKS == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after 'ELEMENT'\n"); return(-1); } name = xmlParseName(ctxt); if (name == NULL) { xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, "xmlParseElementDecl: no name for Element\n"); return(-1); } if (SKIP_BLANKS == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after the element name\n"); } if (CMP5(CUR_PTR, 'E', 'M', 'P', 'T', 'Y')) { SKIP(5); /* * Element must always be empty. */ ret = XML_ELEMENT_TYPE_EMPTY; } else if ((RAW == 'A') && (NXT(1) == 'N') && (NXT(2) == 'Y')) { SKIP(3); /* * Element is a generic container. */ ret = XML_ELEMENT_TYPE_ANY; } else if (RAW == '(') { ret = xmlParseElementContentDecl(ctxt, name, &content); } else { /* * [ WFC: PEs in Internal Subset ] error handling. */ if ((RAW == '%') && (ctxt->external == 0) && (ctxt->inputNr == 1)) { xmlFatalErrMsg(ctxt, XML_ERR_PEREF_IN_INT_SUBSET, "PEReference: forbidden within markup decl in internal subset\n"); } else { xmlFatalErrMsg(ctxt, XML_ERR_ELEMCONTENT_NOT_STARTED, "xmlParseElementDecl: 'EMPTY', 'ANY' or '(' expected\n"); } return(-1); }
SKIP_BLANKS;
if (RAW != '>') { xmlFatalErr(ctxt, XML_ERR_GT_REQUIRED, NULL); if (content != NULL) { xmlFreeDocElementContent(ctxt->myDoc, content); } } else { if (inputid != ctxt->input->id) { xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, "Element declaration doesn't start and stop in" " the same entity\n"); }
NEXT; if ((ctxt->sax != NULL) && (!ctxt->disableSAX) && (ctxt->sax->elementDecl != NULL)) { if (content != NULL) content->parent = NULL; ctxt->sax->elementDecl(ctxt->userData, name, ret, content); if ((content != NULL) && (content->parent == NULL)) { /* * this is a trick: if xmlAddElementDecl is called, * instead of copying the full tree it is plugged directly * if called from the parser. Avoid duplicating the * interfaces or change the API/ABI */ xmlFreeDocElementContent(ctxt->myDoc, content); } } else if (content != NULL) { xmlFreeDocElementContent(ctxt->myDoc, content); } } } return(ret);}
/** * xmlParseConditionalSections * @ctxt: an XML parser context * * Parse a conditional section. Always consumes '<!['. * * [61] conditionalSect ::= includeSect | ignoreSect * [62] includeSect ::= '<![' S? 'INCLUDE' S? '[' extSubsetDecl ']]>' * [63] ignoreSect ::= '<![' S? 'IGNORE' S? '[' ignoreSectContents* ']]>' * [64] ignoreSectContents ::= Ignore ('<![' ignoreSectContents ']]>' Ignore)* * [65] Ignore ::= Char* - (Char* ('<![' | ']]>') Char*) */
static voidxmlParseConditionalSections(xmlParserCtxtPtr ctxt) { int *inputIds = NULL; size_t inputIdsSize = 0; size_t depth = 0;
while (ctxt->instate != XML_PARSER_EOF) { if ((RAW == '<') && (NXT(1) == '!') && (NXT(2) == '[')) { int id = ctxt->input->id;
SKIP(3); SKIP_BLANKS;
if (CMP7(CUR_PTR, 'I', 'N', 'C', 'L', 'U', 'D', 'E')) { SKIP(7); SKIP_BLANKS; if (RAW != '[') { xmlFatalErr(ctxt, XML_ERR_CONDSEC_INVALID, NULL); xmlHaltParser(ctxt); goto error; } if (ctxt->input->id != id) { xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, "All markup of the conditional section is" " not in the same entity\n"); } NEXT;
if (inputIdsSize <= depth) { int *tmp;
inputIdsSize = (inputIdsSize == 0 ? 4 : inputIdsSize * 2); tmp = (int *) xmlRealloc(inputIds, inputIdsSize * sizeof(int)); if (tmp == NULL) { xmlErrMemory(ctxt, NULL); goto error; } inputIds = tmp; } inputIds[depth] = id; depth++; } else if (CMP6(CUR_PTR, 'I', 'G', 'N', 'O', 'R', 'E')) { size_t ignoreDepth = 0;
SKIP(6); SKIP_BLANKS; if (RAW != '[') { xmlFatalErr(ctxt, XML_ERR_CONDSEC_INVALID, NULL); xmlHaltParser(ctxt); goto error; } if (ctxt->input->id != id) { xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, "All markup of the conditional section is" " not in the same entity\n"); } NEXT;
while (RAW != 0) { if ((RAW == '<') && (NXT(1) == '!') && (NXT(2) == '[')) { SKIP(3); ignoreDepth++; /* Check for integer overflow */ if (ignoreDepth == 0) { xmlErrMemory(ctxt, NULL); goto error; } } else if ((RAW == ']') && (NXT(1) == ']') && (NXT(2) == '>')) { if (ignoreDepth == 0) break; SKIP(3); ignoreDepth--; } else { NEXT; } }
if (RAW == 0) { xmlFatalErr(ctxt, XML_ERR_CONDSEC_NOT_FINISHED, NULL); goto error; } if (ctxt->input->id != id) { xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, "All markup of the conditional section is" " not in the same entity\n"); } SKIP(3); } else { xmlFatalErr(ctxt, XML_ERR_CONDSEC_INVALID_KEYWORD, NULL); xmlHaltParser(ctxt); goto error; } } else if ((depth > 0) && (RAW == ']') && (NXT(1) == ']') && (NXT(2) == '>')) { depth--; if (ctxt->input->id != inputIds[depth]) { xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, "All markup of the conditional section is not" " in the same entity\n"); } SKIP(3); } else if ((RAW == '<') && ((NXT(1) == '!') || (NXT(1) == '?'))) { xmlParseMarkupDecl(ctxt); } else { xmlFatalErr(ctxt, XML_ERR_EXT_SUBSET_NOT_FINISHED, NULL); xmlHaltParser(ctxt); goto error; }
if (depth == 0) break;
SKIP_BLANKS; SHRINK; GROW; }
error: xmlFree(inputIds);}
/** * xmlParseMarkupDecl: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * Parse markup declarations. Always consumes '<!' or '<?'. * * [29] markupdecl ::= elementdecl | AttlistDecl | EntityDecl | * NotationDecl | PI | Comment * * [ VC: Proper Declaration/PE Nesting ] * Parameter-entity replacement text must be properly nested with * markup declarations. That is to say, if either the first character * or the last character of a markup declaration (markupdecl above) is * contained in the replacement text for a parameter-entity reference, * both must be contained in the same replacement text. * * [ WFC: PEs in Internal Subset ] * In the internal DTD subset, parameter-entity references can occur * only where markup declarations can occur, not within markup declarations. * (This does not apply to references that occur in external parameter * entities or to the external subset.) */voidxmlParseMarkupDecl(xmlParserCtxtPtr ctxt) { GROW; if (CUR == '<') { if (NXT(1) == '!') { switch (NXT(2)) { case 'E': if (NXT(3) == 'L') xmlParseElementDecl(ctxt); else if (NXT(3) == 'N') xmlParseEntityDecl(ctxt); else SKIP(2); break; case 'A': xmlParseAttributeListDecl(ctxt); break; case 'N': xmlParseNotationDecl(ctxt); break; case '-': xmlParseComment(ctxt); break; default: /* there is an error but it will be detected later */ SKIP(2); break; } } else if (NXT(1) == '?') { xmlParsePI(ctxt); } }
/* * detect requirement to exit there and act accordingly * and avoid having instate overridden later on */ if (ctxt->instate == XML_PARSER_EOF) return;
ctxt->instate = XML_PARSER_DTD;}
/** * xmlParseTextDecl: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * parse an XML declaration header for external entities * * [77] TextDecl ::= '<?xml' VersionInfo? EncodingDecl S? '?>' */
voidxmlParseTextDecl(xmlParserCtxtPtr ctxt) { xmlChar *version; int oldstate;
/* * We know that '<?xml' is here. */ if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && (IS_BLANK_CH(NXT(5)))) { SKIP(5); } else { xmlFatalErr(ctxt, XML_ERR_XMLDECL_NOT_STARTED, NULL); return; }
/* Avoid expansion of parameter entities when skipping blanks. */ oldstate = ctxt->instate; ctxt->instate = XML_PARSER_START;
if (SKIP_BLANKS == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space needed after '<?xml'\n"); }
/* * We may have the VersionInfo here. */ version = xmlParseVersionInfo(ctxt); if (version == NULL) version = xmlCharStrdup(XML_DEFAULT_VERSION); else { if (SKIP_BLANKS == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space needed here\n"); } } ctxt->input->version = version;
/* * We must have the encoding declaration */ xmlParseEncodingDecl(ctxt); if (ctxt->instate == XML_PARSER_EOF) return; if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) { /* * The XML REC instructs us to stop parsing right here */ ctxt->instate = oldstate; return; }
SKIP_BLANKS; if ((RAW == '?') && (NXT(1) == '>')) { SKIP(2); } else if (RAW == '>') { /* Deprecated old WD ... */ xmlFatalErr(ctxt, XML_ERR_XMLDECL_NOT_FINISHED, NULL); NEXT; } else { int c;
xmlFatalErr(ctxt, XML_ERR_XMLDECL_NOT_FINISHED, NULL); while ((c = CUR) != 0) { NEXT; if (c == '>') break; } }
if (ctxt->instate != XML_PARSER_EOF) ctxt->instate = oldstate;}
/** * xmlParseExternalSubset: * @ctxt: an XML parser context * @ExternalID: the external identifier * @SystemID: the system identifier (or URL) * * parse Markup declarations from an external subset * * [30] extSubset ::= textDecl? extSubsetDecl * * [31] extSubsetDecl ::= (markupdecl | conditionalSect | PEReference | S) * */voidxmlParseExternalSubset(xmlParserCtxtPtr ctxt, const xmlChar *ExternalID, const xmlChar *SystemID) { xmlDetectSAX2(ctxt);
xmlDetectEncoding(ctxt);
if (CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) { xmlParseTextDecl(ctxt); if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) { /* * The XML REC instructs us to stop parsing right here */ xmlHaltParser(ctxt); return; } } if (ctxt->myDoc == NULL) { ctxt->myDoc = xmlNewDoc(BAD_CAST "1.0"); if (ctxt->myDoc == NULL) { xmlErrMemory(ctxt, "New Doc failed"); return; } ctxt->myDoc->properties = XML_DOC_INTERNAL; } if ((ctxt->myDoc != NULL) && (ctxt->myDoc->intSubset == NULL)) xmlCreateIntSubset(ctxt->myDoc, NULL, ExternalID, SystemID);
ctxt->instate = XML_PARSER_DTD; ctxt->external = 1; SKIP_BLANKS; while ((ctxt->instate != XML_PARSER_EOF) && (RAW != 0)) { GROW; if ((RAW == '<') && (NXT(1) == '!') && (NXT(2) == '[')) { xmlParseConditionalSections(ctxt); } else if ((RAW == '<') && ((NXT(1) == '!') || (NXT(1) == '?'))) { xmlParseMarkupDecl(ctxt); } else { xmlFatalErr(ctxt, XML_ERR_EXT_SUBSET_NOT_FINISHED, NULL); xmlHaltParser(ctxt); return; } SKIP_BLANKS; SHRINK; }
if (RAW != 0) { xmlFatalErr(ctxt, XML_ERR_EXT_SUBSET_NOT_FINISHED, NULL); }
}
/** * xmlParseReference: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * parse and handle entity references in content, depending on the SAX * interface, this may end-up in a call to character() if this is a * CharRef, a predefined entity, if there is no reference() callback. * or if the parser was asked to switch to that mode. * * Always consumes '&'. * * [67] Reference ::= EntityRef | CharRef */voidxmlParseReference(xmlParserCtxtPtr ctxt) { xmlEntityPtr ent; xmlChar *val; int was_checked; xmlNodePtr list = NULL; xmlParserErrors ret = XML_ERR_OK;
if (RAW != '&') return;
/* * Simple case of a CharRef */ if (NXT(1) == '#') { int i = 0; xmlChar out[16]; int value = xmlParseCharRef(ctxt);
if (value == 0) return;
/* * Just encode the value in UTF-8 */ COPY_BUF(out, i, value); out[i] = 0; if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL) && (!ctxt->disableSAX)) ctxt->sax->characters(ctxt->userData, out, i); return; }
/* * We are seeing an entity reference */ ent = xmlParseEntityRef(ctxt); if (ent == NULL) return; if (!ctxt->wellFormed) return; was_checked = ent->flags & XML_ENT_PARSED;
/* special case of predefined entities */ if ((ent->name == NULL) || (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) { val = ent->content; if (val == NULL) return; /* * inline the entity. */ if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL) && (!ctxt->disableSAX)) ctxt->sax->characters(ctxt->userData, val, xmlStrlen(val)); return; }
/* * The first reference to the entity trigger a parsing phase * where the ent->children is filled with the result from * the parsing. * Note: external parsed entities will not be loaded, it is not * required for a non-validating parser, unless the parsing option * of validating, or substituting entities were given. Doing so is * far more secure as the parser will only process data coming from * the document entity by default. * * FIXME: This doesn't work correctly since entities can be * expanded with different namespace declarations in scope. * For example: * * <!DOCTYPE doc [ * <!ENTITY ent "<ns:elem/>"> * ]> * <doc> * <decl1 xmlns:ns="urn:ns1"> * &ent; * </decl1> * <decl2 xmlns:ns="urn:ns2"> * &ent; * </decl2> * </doc> * * Proposed fix: * * - Remove the ent->owner optimization which tries to avoid the * initial copy of the entity. Always make entities own the * subtree. * - Ignore current namespace declarations when parsing the * entity. If a prefix can't be resolved, don't report an error * but mark it as unresolved. * - Try to resolve these prefixes when expanding the entity. * This will require a specialized version of xmlStaticCopyNode * which can also make use of the namespace hash table to avoid * quadratic behavior. * * Alternatively, we could simply reparse the entity on each * expansion like we already do with custom SAX callbacks. * External entity content should be cached in this case. */ if (((ent->flags & XML_ENT_PARSED) == 0) && ((ent->etype != XML_EXTERNAL_GENERAL_PARSED_ENTITY) || (ctxt->options & (XML_PARSE_NOENT | XML_PARSE_DTDVALID)))) { unsigned long oldsizeentcopy = ctxt->sizeentcopy;
/* * This is a bit hackish but this seems the best * way to make sure both SAX and DOM entity support * behaves okay. */ void *user_data; if (ctxt->userData == ctxt) user_data = NULL; else user_data = ctxt->userData;
/* Avoid overflow as much as possible */ ctxt->sizeentcopy = 0;
if (ent->flags & XML_ENT_EXPANDING) { xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); xmlHaltParser(ctxt); return; }
ent->flags |= XML_ENT_EXPANDING;
/* * Check that this entity is well formed * 4.3.2: An internal general parsed entity is well-formed * if its replacement text matches the production labeled * content. */ if (ent->etype == XML_INTERNAL_GENERAL_ENTITY) { ctxt->depth++; ret = xmlParseBalancedChunkMemoryInternal(ctxt, ent->content, user_data, &list); ctxt->depth--;
} else if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) { ctxt->depth++; ret = xmlParseExternalEntityPrivate(ctxt->myDoc, ctxt, ctxt->sax, user_data, ctxt->depth, ent->URI, ent->ExternalID, &list); ctxt->depth--; } else { ret = XML_ERR_ENTITY_PE_INTERNAL; xmlErrMsgStr(ctxt, XML_ERR_INTERNAL_ERROR, "invalid entity type found\n", NULL); }
ent->flags &= ~XML_ENT_EXPANDING; ent->flags |= XML_ENT_PARSED | XML_ENT_CHECKED; ent->expandedSize = ctxt->sizeentcopy; if (ret == XML_ERR_ENTITY_LOOP) { xmlHaltParser(ctxt); xmlFreeNodeList(list); return; } if (xmlParserEntityCheck(ctxt, oldsizeentcopy)) { xmlFreeNodeList(list); return; }
if ((ret == XML_ERR_OK) && (list != NULL)) { ent->children = list; /* * Prune it directly in the generated document * except for single text nodes. */ if ((ctxt->replaceEntities == 0) || (ctxt->parseMode == XML_PARSE_READER) || ((list->type == XML_TEXT_NODE) && (list->next == NULL))) { ent->owner = 1; while (list != NULL) { list->parent = (xmlNodePtr) ent; if (list->doc != ent->doc) xmlSetTreeDoc(list, ent->doc); if (list->next == NULL) ent->last = list; list = list->next; } list = NULL; } else { ent->owner = 0; while (list != NULL) { list->parent = (xmlNodePtr) ctxt->node; list->doc = ctxt->myDoc; if (list->next == NULL) ent->last = list; list = list->next; } list = ent->children;#ifdef LIBXML_LEGACY_ENABLED if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) xmlAddEntityReference(ent, list, NULL);#endif /* LIBXML_LEGACY_ENABLED */ } } else if ((ret != XML_ERR_OK) && (ret != XML_WAR_UNDECLARED_ENTITY)) { xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY, "Entity '%s' failed to parse\n", ent->name); if (ent->content != NULL) ent->content[0] = 0; } else if (list != NULL) { xmlFreeNodeList(list); list = NULL; }
/* Prevent entity from being parsed and expanded twice (Bug 760367). */ was_checked = 0; }
/* * Now that the entity content has been gathered * provide it to the application, this can take different forms based * on the parsing modes. */ if (ent->children == NULL) { /* * Probably running in SAX mode and the callbacks don't * build the entity content. So unless we already went * though parsing for first checking go though the entity * content to generate callbacks associated to the entity */ if (was_checked != 0) { void *user_data; /* * This is a bit hackish but this seems the best * way to make sure both SAX and DOM entity support * behaves okay. */ if (ctxt->userData == ctxt) user_data = NULL; else user_data = ctxt->userData;
if (ent->etype == XML_INTERNAL_GENERAL_ENTITY) { ctxt->depth++; ret = xmlParseBalancedChunkMemoryInternal(ctxt, ent->content, user_data, NULL); ctxt->depth--; } else if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) { unsigned long oldsizeentities = ctxt->sizeentities;
ctxt->depth++; ret = xmlParseExternalEntityPrivate(ctxt->myDoc, ctxt, ctxt->sax, user_data, ctxt->depth, ent->URI, ent->ExternalID, NULL); ctxt->depth--;
/* Undo the change to sizeentities */ ctxt->sizeentities = oldsizeentities; } else { ret = XML_ERR_ENTITY_PE_INTERNAL; xmlErrMsgStr(ctxt, XML_ERR_INTERNAL_ERROR, "invalid entity type found\n", NULL); } if (ret == XML_ERR_ENTITY_LOOP) { xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); return; } if (xmlParserEntityCheck(ctxt, 0)) return; } if ((ctxt->sax != NULL) && (ctxt->sax->reference != NULL) && (ctxt->replaceEntities == 0) && (!ctxt->disableSAX)) { /* * Entity reference callback comes second, it's somewhat * superfluous but a compatibility to historical behaviour */ ctxt->sax->reference(ctxt->userData, ent->name); } return; }
/* * We also check for amplification if entities aren't substituted. * They might be expanded later. */ if ((was_checked != 0) && (xmlParserEntityCheck(ctxt, ent->expandedSize))) return;
/* * If we didn't get any children for the entity being built */ if ((ctxt->sax != NULL) && (ctxt->sax->reference != NULL) && (ctxt->replaceEntities == 0) && (!ctxt->disableSAX)) { /* * Create a node. */ ctxt->sax->reference(ctxt->userData, ent->name); return; }
if (ctxt->replaceEntities) { /* * There is a problem on the handling of _private for entities * (bug 155816): Should we copy the content of the field from * the entity (possibly overwriting some value set by the user * when a copy is created), should we leave it alone, or should * we try to take care of different situations? The problem * is exacerbated by the usage of this field by the xmlReader. * To fix this bug, we look at _private on the created node * and, if it's NULL, we copy in whatever was in the entity. * If it's not NULL we leave it alone. This is somewhat of a * hack - maybe we should have further tests to determine * what to do. */ if (ctxt->node != NULL) { /* * Seems we are generating the DOM content, do * a simple tree copy for all references except the first * In the first occurrence list contains the replacement. */ if (((list == NULL) && (ent->owner == 0)) || (ctxt->parseMode == XML_PARSE_READER)) { xmlNodePtr nw = NULL, cur, firstChild = NULL;
/* * when operating on a reader, the entities definitions * are always owning the entities subtree. if (ctxt->parseMode == XML_PARSE_READER) ent->owner = 1; */
cur = ent->children; while (cur != NULL) { nw = xmlDocCopyNode(cur, ctxt->myDoc, 1); if (nw != NULL) { if (nw->_private == NULL) nw->_private = cur->_private; if (firstChild == NULL){ firstChild = nw; } nw = xmlAddChild(ctxt->node, nw); } if (cur == ent->last) { /* * needed to detect some strange empty * node cases in the reader tests */ if ((ctxt->parseMode == XML_PARSE_READER) && (nw != NULL) && (nw->type == XML_ELEMENT_NODE) && (nw->children == NULL)) nw->extra = 1;
break; } cur = cur->next; }#ifdef LIBXML_LEGACY_ENABLED if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) xmlAddEntityReference(ent, firstChild, nw);#endif /* LIBXML_LEGACY_ENABLED */ } else if ((list == NULL) || (ctxt->inputNr > 0)) { xmlNodePtr nw = NULL, cur, next, last, firstChild = NULL;
/* * Copy the entity child list and make it the new * entity child list. The goal is to make sure any * ID or REF referenced will be the one from the * document content and not the entity copy. */ cur = ent->children; ent->children = NULL; last = ent->last; ent->last = NULL; while (cur != NULL) { next = cur->next; cur->next = NULL; cur->parent = NULL; nw = xmlDocCopyNode(cur, ctxt->myDoc, 1); if (nw != NULL) { if (nw->_private == NULL) nw->_private = cur->_private; if (firstChild == NULL){ firstChild = cur; } xmlAddChild((xmlNodePtr) ent, nw); } xmlAddChild(ctxt->node, cur); if (cur == last) break; cur = next; } if (ent->owner == 0) ent->owner = 1;#ifdef LIBXML_LEGACY_ENABLED if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) xmlAddEntityReference(ent, firstChild, nw);#endif /* LIBXML_LEGACY_ENABLED */ } else { const xmlChar *nbktext;
/* * the name change is to avoid coalescing of the * node with a possible previous text one which * would make ent->children a dangling pointer */ nbktext = xmlDictLookup(ctxt->dict, BAD_CAST "nbktext", -1); if (ent->children->type == XML_TEXT_NODE) ent->children->name = nbktext; if ((ent->last != ent->children) && (ent->last->type == XML_TEXT_NODE)) ent->last->name = nbktext; xmlAddChildList(ctxt->node, ent->children); }
/* * This is to avoid a nasty side effect, see * characters() in SAX.c */ ctxt->nodemem = 0; ctxt->nodelen = 0; return; } }}
/** * xmlParseEntityRef: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * Parse an entitiy reference. Always consumes '&'. * * [68] EntityRef ::= '&' Name ';' * * [ WFC: Entity Declared ] * In a document without any DTD, a document with only an internal DTD * subset which contains no parameter entity references, or a document * with "standalone='yes'", the Name given in the entity reference * must match that in an entity declaration, except that well-formed * documents need not declare any of the following entities: amp, lt, * gt, apos, quot. The declaration of a parameter entity must precede * any reference to it. Similarly, the declaration of a general entity * must precede any reference to it which appears in a default value in an * attribute-list declaration. Note that if entities are declared in the * external subset or in external parameter entities, a non-validating * processor is not obligated to read and process their declarations; * for such documents, the rule that an entity must be declared is a * well-formedness constraint only if standalone='yes'. * * [ WFC: Parsed Entity ] * An entity reference must not contain the name of an unparsed entity * * Returns the xmlEntityPtr if found, or NULL otherwise. */xmlEntityPtrxmlParseEntityRef(xmlParserCtxtPtr ctxt) { const xmlChar *name; xmlEntityPtr ent = NULL;
GROW; if (ctxt->instate == XML_PARSER_EOF) return(NULL);
if (RAW != '&') return(NULL); NEXT; name = xmlParseName(ctxt); if (name == NULL) { xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, "xmlParseEntityRef: no name\n"); return(NULL); } if (RAW != ';') { xmlFatalErr(ctxt, XML_ERR_ENTITYREF_SEMICOL_MISSING, NULL); return(NULL); } NEXT;
/* * Predefined entities override any extra definition */ if ((ctxt->options & XML_PARSE_OLDSAX) == 0) { ent = xmlGetPredefinedEntity(name); if (ent != NULL) return(ent); }
/* * Ask first SAX for entity resolution, otherwise try the * entities which may have stored in the parser context. */ if (ctxt->sax != NULL) { if (ctxt->sax->getEntity != NULL) ent = ctxt->sax->getEntity(ctxt->userData, name); if ((ctxt->wellFormed == 1 ) && (ent == NULL) && (ctxt->options & XML_PARSE_OLDSAX)) ent = xmlGetPredefinedEntity(name); if ((ctxt->wellFormed == 1 ) && (ent == NULL) && (ctxt->userData==ctxt)) { ent = xmlSAX2GetEntity(ctxt, name); } } if (ctxt->instate == XML_PARSER_EOF) return(NULL); /* * [ WFC: Entity Declared ] * In a document without any DTD, a document with only an * internal DTD subset which contains no parameter entity * references, or a document with "standalone='yes'", the * Name given in the entity reference must match that in an * entity declaration, except that well-formed documents * need not declare any of the following entities: amp, lt, * gt, apos, quot. * The declaration of a parameter entity must precede any * reference to it. * Similarly, the declaration of a general entity must * precede any reference to it which appears in a default * value in an attribute-list declaration. Note that if * entities are declared in the external subset or in * external parameter entities, a non-validating processor * is not obligated to read and process their declarations; * for such documents, the rule that an entity must be * declared is a well-formedness constraint only if * standalone='yes'. */ if (ent == NULL) { if ((ctxt->standalone == 1) || ((ctxt->hasExternalSubset == 0) && (ctxt->hasPErefs == 0))) { xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY, "Entity '%s' not defined\n", name); } else { xmlErrMsgStr(ctxt, XML_WAR_UNDECLARED_ENTITY, "Entity '%s' not defined\n", name); if ((ctxt->inSubset == 0) && (ctxt->sax != NULL) && (ctxt->disableSAX == 0) && (ctxt->sax->reference != NULL)) { ctxt->sax->reference(ctxt->userData, name); } } ctxt->valid = 0; }
/* * [ WFC: Parsed Entity ] * An entity reference must not contain the name of an * unparsed entity */ else if (ent->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) { xmlFatalErrMsgStr(ctxt, XML_ERR_UNPARSED_ENTITY, "Entity reference to unparsed entity %s\n", name); }
/* * [ WFC: No External Entity References ] * Attribute values cannot contain direct or indirect * entity references to external entities. */ else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) && (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)) { xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_IS_EXTERNAL, "Attribute references external entity '%s'\n", name); } /* * [ WFC: No < in Attribute Values ] * The replacement text of any entity referred to directly or * indirectly in an attribute value (other than "<") must * not contain a <. */ else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) && (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY)) { if ((ent->flags & XML_ENT_CHECKED_LT) == 0) { if ((ent->content != NULL) && (xmlStrchr(ent->content, '<'))) ent->flags |= XML_ENT_CONTAINS_LT; ent->flags |= XML_ENT_CHECKED_LT; } if (ent->flags & XML_ENT_CONTAINS_LT) xmlFatalErrMsgStr(ctxt, XML_ERR_LT_IN_ATTRIBUTE, "'<' in entity '%s' is not allowed in attributes " "values\n", name); }
/* * Internal check, no parameter entities here ... */ else { switch (ent->etype) { case XML_INTERNAL_PARAMETER_ENTITY: case XML_EXTERNAL_PARAMETER_ENTITY: xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_IS_PARAMETER, "Attempt to reference the parameter entity '%s'\n", name); break; default: break; } }
/* * [ WFC: No Recursion ] * A parsed entity must not contain a recursive reference * to itself, either directly or indirectly. * Done somewhere else */ return(ent);}
/** * xmlParseStringEntityRef: * @ctxt: an XML parser context * @str: a pointer to an index in the string * * parse ENTITY references declarations, but this version parses it from * a string value. * * [68] EntityRef ::= '&' Name ';' * * [ WFC: Entity Declared ] * In a document without any DTD, a document with only an internal DTD * subset which contains no parameter entity references, or a document * with "standalone='yes'", the Name given in the entity reference * must match that in an entity declaration, except that well-formed * documents need not declare any of the following entities: amp, lt, * gt, apos, quot. The declaration of a parameter entity must precede * any reference to it. Similarly, the declaration of a general entity * must precede any reference to it which appears in a default value in an * attribute-list declaration. Note that if entities are declared in the * external subset or in external parameter entities, a non-validating * processor is not obligated to read and process their declarations; * for such documents, the rule that an entity must be declared is a * well-formedness constraint only if standalone='yes'. * * [ WFC: Parsed Entity ] * An entity reference must not contain the name of an unparsed entity * * Returns the xmlEntityPtr if found, or NULL otherwise. The str pointer * is updated to the current location in the string. */static xmlEntityPtrxmlParseStringEntityRef(xmlParserCtxtPtr ctxt, const xmlChar ** str) { xmlChar *name; const xmlChar *ptr; xmlChar cur; xmlEntityPtr ent = NULL;
if ((str == NULL) || (*str == NULL)) return(NULL); ptr = *str; cur = *ptr; if (cur != '&') return(NULL);
ptr++; name = xmlParseStringName(ctxt, &ptr); if (name == NULL) { xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, "xmlParseStringEntityRef: no name\n"); *str = ptr; return(NULL); } if (*ptr != ';') { xmlFatalErr(ctxt, XML_ERR_ENTITYREF_SEMICOL_MISSING, NULL); xmlFree(name); *str = ptr; return(NULL); } ptr++;
/* * Predefined entities override any extra definition */ if ((ctxt->options & XML_PARSE_OLDSAX) == 0) { ent = xmlGetPredefinedEntity(name); if (ent != NULL) { xmlFree(name); *str = ptr; return(ent); } }
/* * Ask first SAX for entity resolution, otherwise try the * entities which may have stored in the parser context. */ if (ctxt->sax != NULL) { if (ctxt->sax->getEntity != NULL) ent = ctxt->sax->getEntity(ctxt->userData, name); if ((ent == NULL) && (ctxt->options & XML_PARSE_OLDSAX)) ent = xmlGetPredefinedEntity(name); if ((ent == NULL) && (ctxt->userData==ctxt)) { ent = xmlSAX2GetEntity(ctxt, name); } } if (ctxt->instate == XML_PARSER_EOF) { xmlFree(name); return(NULL); }
/* * [ WFC: Entity Declared ] * In a document without any DTD, a document with only an * internal DTD subset which contains no parameter entity * references, or a document with "standalone='yes'", the * Name given in the entity reference must match that in an * entity declaration, except that well-formed documents * need not declare any of the following entities: amp, lt, * gt, apos, quot. * The declaration of a parameter entity must precede any * reference to it. * Similarly, the declaration of a general entity must * precede any reference to it which appears in a default * value in an attribute-list declaration. Note that if * entities are declared in the external subset or in * external parameter entities, a non-validating processor * is not obligated to read and process their declarations; * for such documents, the rule that an entity must be * declared is a well-formedness constraint only if * standalone='yes'. */ if (ent == NULL) { if ((ctxt->standalone == 1) || ((ctxt->hasExternalSubset == 0) && (ctxt->hasPErefs == 0))) { xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY, "Entity '%s' not defined\n", name); } else { xmlErrMsgStr(ctxt, XML_WAR_UNDECLARED_ENTITY, "Entity '%s' not defined\n", name); } /* TODO ? check regressions ctxt->valid = 0; */ }
/* * [ WFC: Parsed Entity ] * An entity reference must not contain the name of an * unparsed entity */ else if (ent->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) { xmlFatalErrMsgStr(ctxt, XML_ERR_UNPARSED_ENTITY, "Entity reference to unparsed entity %s\n", name); }
/* * [ WFC: No External Entity References ] * Attribute values cannot contain direct or indirect * entity references to external entities. */ else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) && (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)) { xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_IS_EXTERNAL, "Attribute references external entity '%s'\n", name); } /* * [ WFC: No < in Attribute Values ] * The replacement text of any entity referred to directly or * indirectly in an attribute value (other than "<") must * not contain a <. */ else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) && (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY)) { if ((ent->flags & XML_ENT_CHECKED_LT) == 0) { if ((ent->content != NULL) && (xmlStrchr(ent->content, '<'))) ent->flags |= XML_ENT_CONTAINS_LT; ent->flags |= XML_ENT_CHECKED_LT; } if (ent->flags & XML_ENT_CONTAINS_LT) xmlFatalErrMsgStr(ctxt, XML_ERR_LT_IN_ATTRIBUTE, "'<' in entity '%s' is not allowed in attributes " "values\n", name); }
/* * Internal check, no parameter entities here ... */ else { switch (ent->etype) { case XML_INTERNAL_PARAMETER_ENTITY: case XML_EXTERNAL_PARAMETER_ENTITY: xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_IS_PARAMETER, "Attempt to reference the parameter entity '%s'\n", name); break; default: break; } }
/* * [ WFC: No Recursion ] * A parsed entity must not contain a recursive reference * to itself, either directly or indirectly. * Done somewhere else */
xmlFree(name); *str = ptr; return(ent);}
/** * xmlParsePEReference: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * Parse a parameter entity reference. Always consumes '%'. * * The entity content is handled directly by pushing it's content as * a new input stream. * * [69] PEReference ::= '%' Name ';' * * [ WFC: No Recursion ] * A parsed entity must not contain a recursive * reference to itself, either directly or indirectly. * * [ WFC: Entity Declared ] * In a document without any DTD, a document with only an internal DTD * subset which contains no parameter entity references, or a document * with "standalone='yes'", ... ... The declaration of a parameter * entity must precede any reference to it... * * [ VC: Entity Declared ] * In a document with an external subset or external parameter entities * with "standalone='no'", ... ... The declaration of a parameter entity * must precede any reference to it... * * [ WFC: In DTD ] * Parameter-entity references may only appear in the DTD. * NOTE: misleading but this is handled. */voidxmlParsePEReference(xmlParserCtxtPtr ctxt){ const xmlChar *name; xmlEntityPtr entity = NULL; xmlParserInputPtr input;
if (RAW != '%') return; NEXT; name = xmlParseName(ctxt); if (name == NULL) { xmlFatalErrMsg(ctxt, XML_ERR_PEREF_NO_NAME, "PEReference: no name\n"); return; } if (xmlParserDebugEntities) xmlGenericError(xmlGenericErrorContext, "PEReference: %s\n", name); if (RAW != ';') { xmlFatalErr(ctxt, XML_ERR_PEREF_SEMICOL_MISSING, NULL); return; }
NEXT;
/* * Request the entity from SAX */ if ((ctxt->sax != NULL) && (ctxt->sax->getParameterEntity != NULL)) entity = ctxt->sax->getParameterEntity(ctxt->userData, name); if (ctxt->instate == XML_PARSER_EOF) return; if (entity == NULL) { /* * [ WFC: Entity Declared ] * In a document without any DTD, a document with only an * internal DTD subset which contains no parameter entity * references, or a document with "standalone='yes'", ... * ... The declaration of a parameter entity must precede * any reference to it... */ if ((ctxt->standalone == 1) || ((ctxt->hasExternalSubset == 0) && (ctxt->hasPErefs == 0))) { xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY, "PEReference: %%%s; not found\n", name); } else { /* * [ VC: Entity Declared ] * In a document with an external subset or external * parameter entities with "standalone='no'", ... * ... The declaration of a parameter entity must * precede any reference to it... */ if ((ctxt->validate) && (ctxt->vctxt.error != NULL)) { xmlValidityError(ctxt, XML_WAR_UNDECLARED_ENTITY, "PEReference: %%%s; not found\n", name, NULL); } else xmlWarningMsg(ctxt, XML_WAR_UNDECLARED_ENTITY, "PEReference: %%%s; not found\n", name, NULL); ctxt->valid = 0; } } else { /* * Internal checking in case the entity quest barfed */ if ((entity->etype != XML_INTERNAL_PARAMETER_ENTITY) && (entity->etype != XML_EXTERNAL_PARAMETER_ENTITY)) { xmlWarningMsg(ctxt, XML_WAR_UNDECLARED_ENTITY, "Internal: %%%s; is not a parameter entity\n", name, NULL); } else { unsigned long parentConsumed; xmlEntityPtr oldEnt;
if ((entity->etype == XML_EXTERNAL_PARAMETER_ENTITY) && ((ctxt->options & XML_PARSE_NOENT) == 0) && ((ctxt->options & XML_PARSE_DTDVALID) == 0) && ((ctxt->options & XML_PARSE_DTDLOAD) == 0) && ((ctxt->options & XML_PARSE_DTDATTR) == 0) && (ctxt->replaceEntities == 0) && (ctxt->validate == 0)) return;
if (entity->flags & XML_ENT_EXPANDING) { xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); xmlHaltParser(ctxt); return; }
/* Must be computed from old input before pushing new input. */ parentConsumed = ctxt->input->parentConsumed; oldEnt = ctxt->input->entity; if ((oldEnt == NULL) || ((oldEnt->etype == XML_EXTERNAL_PARAMETER_ENTITY) && ((oldEnt->flags & XML_ENT_PARSED) == 0))) { xmlSaturatedAdd(&parentConsumed, ctxt->input->consumed); xmlSaturatedAddSizeT(&parentConsumed, ctxt->input->cur - ctxt->input->base); }
input = xmlNewEntityInputStream(ctxt, entity); if (xmlPushInput(ctxt, input) < 0) { xmlFreeInputStream(input); return; }
entity->flags |= XML_ENT_EXPANDING;
input->parentConsumed = parentConsumed;
if (entity->etype == XML_EXTERNAL_PARAMETER_ENTITY) { xmlDetectEncoding(ctxt);
if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && (IS_BLANK_CH(NXT(5)))) { xmlParseTextDecl(ctxt); } } } } ctxt->hasPErefs = 1;}
/** * xmlLoadEntityContent: * @ctxt: an XML parser context * @entity: an unloaded system entity * * Load the original content of the given system entity from the * ExternalID/SystemID given. This is to be used for Included in Literal * http://www.w3.org/TR/REC-xml/#inliteral processing of entities references * * Returns 0 in case of success and -1 in case of failure */static intxmlLoadEntityContent(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) { xmlParserInputPtr oldinput, input = NULL; xmlParserInputPtr *oldinputTab; const xmlChar *oldencoding; xmlChar *content = NULL; size_t length, i; int oldinputNr, oldinputMax, oldprogressive; int ret = -1; int res;
if ((ctxt == NULL) || (entity == NULL) || ((entity->etype != XML_EXTERNAL_PARAMETER_ENTITY) && (entity->etype != XML_EXTERNAL_GENERAL_PARSED_ENTITY)) || (entity->content != NULL)) { xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, "xmlLoadEntityContent parameter error"); return(-1); }
if (xmlParserDebugEntities) xmlGenericError(xmlGenericErrorContext, "Reading %s entity content input\n", entity->name);
input = xmlLoadExternalEntity((char *) entity->URI, (char *) entity->ExternalID, ctxt); if (input == NULL) { xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, "xmlLoadEntityContent input error"); return(-1); }
oldinput = ctxt->input; oldinputNr = ctxt->inputNr; oldinputMax = ctxt->inputMax; oldinputTab = ctxt->inputTab; oldencoding = ctxt->encoding; oldprogressive = ctxt->progressive;
ctxt->input = NULL; ctxt->inputNr = 0; ctxt->inputMax = 1; ctxt->encoding = NULL; ctxt->progressive = 0; ctxt->inputTab = xmlMalloc(sizeof(xmlParserInputPtr)); if (ctxt->inputTab == NULL) { xmlErrMemory(ctxt, NULL); xmlFreeInputStream(input); goto error; }
xmlBufResetInput(input->buf->buffer, input);
inputPush(ctxt, input);
xmlDetectEncoding(ctxt);
/* * Parse a possible text declaration first */ if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && (IS_BLANK_CH(NXT(5)))) { xmlParseTextDecl(ctxt); /* * An XML-1.0 document can't reference an entity not XML-1.0 */ if ((xmlStrEqual(ctxt->version, BAD_CAST "1.0")) && (!xmlStrEqual(ctxt->input->version, BAD_CAST "1.0"))) { xmlFatalErrMsg(ctxt, XML_ERR_VERSION_MISMATCH, "Version mismatch between document and entity\n"); } }
if (ctxt->instate == XML_PARSER_EOF) goto error;
length = input->cur - input->base; xmlBufShrink(input->buf->buffer, length); xmlSaturatedAdd(&ctxt->sizeentities, length);
while ((res = xmlParserInputBufferGrow(input->buf, 4096)) > 0) ;
xmlBufResetInput(input->buf->buffer, input);
if (res < 0) { xmlFatalErr(ctxt, input->buf->error, NULL); goto error; }
length = xmlBufUse(input->buf->buffer); content = xmlBufDetach(input->buf->buffer);
if (length > INT_MAX) { xmlErrMemory(ctxt, NULL); goto error; }
for (i = 0; i < length; ) { int clen = length - i; int c = xmlGetUTF8Char(content + i, &clen);
if ((c < 0) || (!IS_CHAR(c))) { xmlFatalErrMsgInt(ctxt, XML_ERR_INVALID_CHAR, "xmlLoadEntityContent: invalid char value %d\n", content[i]); goto error; } i += clen; }
xmlSaturatedAdd(&ctxt->sizeentities, length); entity->content = content; entity->length = length; content = NULL; ret = 0;
error: while (ctxt->inputNr > 0) xmlFreeInputStream(inputPop(ctxt)); xmlFree(ctxt->inputTab); xmlFree((xmlChar *) ctxt->encoding);
ctxt->input = oldinput; ctxt->inputNr = oldinputNr; ctxt->inputMax = oldinputMax; ctxt->inputTab = oldinputTab; ctxt->encoding = oldencoding; ctxt->progressive = oldprogressive;
xmlFree(content);
return(ret);}
/** * xmlParseStringPEReference: * @ctxt: an XML parser context * @str: a pointer to an index in the string * * parse PEReference declarations * * [69] PEReference ::= '%' Name ';' * * [ WFC: No Recursion ] * A parsed entity must not contain a recursive * reference to itself, either directly or indirectly. * * [ WFC: Entity Declared ] * In a document without any DTD, a document with only an internal DTD * subset which contains no parameter entity references, or a document * with "standalone='yes'", ... ... The declaration of a parameter * entity must precede any reference to it... * * [ VC: Entity Declared ] * In a document with an external subset or external parameter entities * with "standalone='no'", ... ... The declaration of a parameter entity * must precede any reference to it... * * [ WFC: In DTD ] * Parameter-entity references may only appear in the DTD. * NOTE: misleading but this is handled. * * Returns the string of the entity content. * str is updated to the current value of the index */static xmlEntityPtrxmlParseStringPEReference(xmlParserCtxtPtr ctxt, const xmlChar **str) { const xmlChar *ptr; xmlChar cur; xmlChar *name; xmlEntityPtr entity = NULL;
if ((str == NULL) || (*str == NULL)) return(NULL); ptr = *str; cur = *ptr; if (cur != '%') return(NULL); ptr++; name = xmlParseStringName(ctxt, &ptr); if (name == NULL) { xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, "xmlParseStringPEReference: no name\n"); *str = ptr; return(NULL); } cur = *ptr; if (cur != ';') { xmlFatalErr(ctxt, XML_ERR_ENTITYREF_SEMICOL_MISSING, NULL); xmlFree(name); *str = ptr; return(NULL); } ptr++;
/* * Request the entity from SAX */ if ((ctxt->sax != NULL) && (ctxt->sax->getParameterEntity != NULL)) entity = ctxt->sax->getParameterEntity(ctxt->userData, name); if (ctxt->instate == XML_PARSER_EOF) { xmlFree(name); *str = ptr; return(NULL); } if (entity == NULL) { /* * [ WFC: Entity Declared ] * In a document without any DTD, a document with only an * internal DTD subset which contains no parameter entity * references, or a document with "standalone='yes'", ... * ... The declaration of a parameter entity must precede * any reference to it... */ if ((ctxt->standalone == 1) || ((ctxt->hasExternalSubset == 0) && (ctxt->hasPErefs == 0))) { xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY, "PEReference: %%%s; not found\n", name); } else { /* * [ VC: Entity Declared ] * In a document with an external subset or external * parameter entities with "standalone='no'", ... * ... The declaration of a parameter entity must * precede any reference to it... */ xmlWarningMsg(ctxt, XML_WAR_UNDECLARED_ENTITY, "PEReference: %%%s; not found\n", name, NULL); ctxt->valid = 0; } } else { /* * Internal checking in case the entity quest barfed */ if ((entity->etype != XML_INTERNAL_PARAMETER_ENTITY) && (entity->etype != XML_EXTERNAL_PARAMETER_ENTITY)) { xmlWarningMsg(ctxt, XML_WAR_UNDECLARED_ENTITY, "%%%s; is not a parameter entity\n", name, NULL); } } ctxt->hasPErefs = 1; xmlFree(name); *str = ptr; return(entity);}
/** * xmlParseDocTypeDecl: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * parse a DOCTYPE declaration * * [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S? * ('[' (markupdecl | PEReference | S)* ']' S?)? '>' * * [ VC: Root Element Type ] * The Name in the document type declaration must match the element * type of the root element. */
voidxmlParseDocTypeDecl(xmlParserCtxtPtr ctxt) { const xmlChar *name = NULL; xmlChar *ExternalID = NULL; xmlChar *URI = NULL;
/* * We know that '<!DOCTYPE' has been detected. */ SKIP(9);
SKIP_BLANKS;
/* * Parse the DOCTYPE name. */ name = xmlParseName(ctxt); if (name == NULL) { xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, "xmlParseDocTypeDecl : no DOCTYPE name !\n"); } ctxt->intSubName = name;
SKIP_BLANKS;
/* * Check for SystemID and ExternalID */ URI = xmlParseExternalID(ctxt, &ExternalID, 1);
if ((URI != NULL) || (ExternalID != NULL)) { ctxt->hasExternalSubset = 1; } ctxt->extSubURI = URI; ctxt->extSubSystem = ExternalID;
SKIP_BLANKS;
/* * Create and update the internal subset. */ if ((ctxt->sax != NULL) && (ctxt->sax->internalSubset != NULL) && (!ctxt->disableSAX)) ctxt->sax->internalSubset(ctxt->userData, name, ExternalID, URI); if (ctxt->instate == XML_PARSER_EOF) return;
/* * Is there any internal subset declarations ? * they are handled separately in xmlParseInternalSubset() */ if (RAW == '[') return;
/* * We should be at the end of the DOCTYPE declaration. */ if (RAW != '>') { xmlFatalErr(ctxt, XML_ERR_DOCTYPE_NOT_FINISHED, NULL); } NEXT;}
/** * xmlParseInternalSubset: * @ctxt: an XML parser context * * parse the internal subset declaration * * [28 end] ('[' (markupdecl | PEReference | S)* ']' S?)? '>' */
static voidxmlParseInternalSubset(xmlParserCtxtPtr ctxt) { /* * Is there any DTD definition ? */ if (RAW == '[') { int baseInputNr = ctxt->inputNr; ctxt->instate = XML_PARSER_DTD; NEXT; /* * Parse the succession of Markup declarations and * PEReferences. * Subsequence (markupdecl | PEReference | S)* */ SKIP_BLANKS; while (((RAW != ']') || (ctxt->inputNr > baseInputNr)) && (ctxt->instate != XML_PARSER_EOF)) {
/* * Conditional sections are allowed from external entities included * by PE References in the internal subset. */ if ((ctxt->inputNr > 1) && (ctxt->input->filename != NULL) && (RAW == '<') && (NXT(1) == '!') && (NXT(2) == '[')) { xmlParseConditionalSections(ctxt); } else if ((RAW == '<') && ((NXT(1) == '!') || (NXT(1) == '?'))) { xmlParseMarkupDecl(ctxt); } else if (RAW == '%') { xmlParsePEReference(ctxt); } else { xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, "xmlParseInternalSubset: error detected in" " Markup declaration\n"); xmlHaltParser(ctxt); return; } SKIP_BLANKS; SHRINK; GROW; } if (RAW == ']') { NEXT; SKIP_BLANKS; } }
/* * We should be at the end of the DOCTYPE declaration. */ if (RAW != '>') { xmlFatalErr(ctxt, XML_ERR_DOCTYPE_NOT_FINISHED, NULL); return; } NEXT;}
#ifdef LIBXML_SAX1_ENABLED/** * xmlParseAttribute: * @ctxt: an XML parser context * @value: a xmlChar ** used to store the value of the attribute * * DEPRECATED: Internal function, don't use. * * parse an attribute * * [41] Attribute ::= Name Eq AttValue * * [ WFC: No External Entity References ] * Attribute values cannot contain direct or indirect entity references * to external entities. * * [ WFC: No < in Attribute Values ] * The replacement text of any entity referred to directly or indirectly in * an attribute value (other than "<") must not contain a <. * * [ VC: Attribute Value Type ] * The attribute must have been declared; the value must be of the type * declared for it. * * [25] Eq ::= S? '=' S? * * With namespace: * * [NS 11] Attribute ::= QName Eq AttValue * * Also the case QName == xmlns:??? is handled independently as a namespace * definition. * * Returns the attribute name, and the value in *value. */
const xmlChar *xmlParseAttribute(xmlParserCtxtPtr ctxt, xmlChar **value) { const xmlChar *name; xmlChar *val;
*value = NULL; GROW; name = xmlParseName(ctxt); if (name == NULL) { xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, "error parsing attribute name\n"); return(NULL); }
/* * read the value */ SKIP_BLANKS; if (RAW == '=') { NEXT; SKIP_BLANKS; val = xmlParseAttValue(ctxt); ctxt->instate = XML_PARSER_CONTENT; } else { xmlFatalErrMsgStr(ctxt, XML_ERR_ATTRIBUTE_WITHOUT_VALUE, "Specification mandates value for attribute %s\n", name); return(name); }
/* * Check that xml:lang conforms to the specification * No more registered as an error, just generate a warning now * since this was deprecated in XML second edition */ if ((ctxt->pedantic) && (xmlStrEqual(name, BAD_CAST "xml:lang"))) { if (!xmlCheckLanguageID(val)) { xmlWarningMsg(ctxt, XML_WAR_LANG_VALUE, "Malformed value for xml:lang : %s\n", val, NULL); } }
/* * Check that xml:space conforms to the specification */ if (xmlStrEqual(name, BAD_CAST "xml:space")) { if (xmlStrEqual(val, BAD_CAST "default")) *(ctxt->space) = 0; else if (xmlStrEqual(val, BAD_CAST "preserve")) *(ctxt->space) = 1; else { xmlWarningMsg(ctxt, XML_WAR_SPACE_VALUE,"Invalid value \"%s\" for xml:space : \"default\" or \"preserve\" expected\n", val, NULL); } }
*value = val; return(name);}
/** * xmlParseStartTag: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * Parse a start tag. Always consumes '<'. * * [40] STag ::= '<' Name (S Attribute)* S? '>' * * [ WFC: Unique Att Spec ] * No attribute name may appear more than once in the same start-tag or * empty-element tag. * * [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>' * * [ WFC: Unique Att Spec ] * No attribute name may appear more than once in the same start-tag or * empty-element tag. * * With namespace: * * [NS 8] STag ::= '<' QName (S Attribute)* S? '>' * * [NS 10] EmptyElement ::= '<' QName (S Attribute)* S? '/>' * * Returns the element name parsed */
const xmlChar *xmlParseStartTag(xmlParserCtxtPtr ctxt) { const xmlChar *name; const xmlChar *attname; xmlChar *attvalue; const xmlChar **atts = ctxt->atts; int nbatts = 0; int maxatts = ctxt->maxatts; int i;
if (RAW != '<') return(NULL); NEXT1;
name = xmlParseName(ctxt); if (name == NULL) { xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, "xmlParseStartTag: invalid element name\n"); return(NULL); }
/* * Now parse the attributes, it ends up with the ending * * (S Attribute)* S? */ SKIP_BLANKS; GROW;
while (((RAW != '>') && ((RAW != '/') || (NXT(1) != '>')) && (IS_BYTE_CHAR(RAW))) && (ctxt->instate != XML_PARSER_EOF)) { attname = xmlParseAttribute(ctxt, &attvalue); if (attname == NULL) { xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR, "xmlParseStartTag: problem parsing attributes\n"); break; } if (attvalue != NULL) { /* * [ WFC: Unique Att Spec ] * No attribute name may appear more than once in the same * start-tag or empty-element tag. */ for (i = 0; i < nbatts;i += 2) { if (xmlStrEqual(atts[i], attname)) { xmlErrAttributeDup(ctxt, NULL, attname); xmlFree(attvalue); goto failed; } } /* * Add the pair to atts */ if (atts == NULL) { maxatts = 22; /* allow for 10 attrs by default */ atts = (const xmlChar **) xmlMalloc(maxatts * sizeof(xmlChar *)); if (atts == NULL) { xmlErrMemory(ctxt, NULL); if (attvalue != NULL) xmlFree(attvalue); goto failed; } ctxt->atts = atts; ctxt->maxatts = maxatts; } else if (nbatts + 4 > maxatts) { const xmlChar **n;
maxatts *= 2; n = (const xmlChar **) xmlRealloc((void *) atts, maxatts * sizeof(const xmlChar *)); if (n == NULL) { xmlErrMemory(ctxt, NULL); if (attvalue != NULL) xmlFree(attvalue); goto failed; } atts = n; ctxt->atts = atts; ctxt->maxatts = maxatts; } atts[nbatts++] = attname; atts[nbatts++] = attvalue; atts[nbatts] = NULL; atts[nbatts + 1] = NULL; } else { if (attvalue != NULL) xmlFree(attvalue); }
failed:
GROW if ((RAW == '>') || (((RAW == '/') && (NXT(1) == '>')))) break; if (SKIP_BLANKS == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "attributes construct error\n"); } SHRINK; GROW; }
/* * SAX: Start of Element ! */ if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL) && (!ctxt->disableSAX)) { if (nbatts > 0) ctxt->sax->startElement(ctxt->userData, name, atts); else ctxt->sax->startElement(ctxt->userData, name, NULL); }
if (atts != NULL) { /* Free only the content strings */ for (i = 1;i < nbatts;i+=2) if (atts[i] != NULL) xmlFree((xmlChar *) atts[i]); } return(name);}
/** * xmlParseEndTag1: * @ctxt: an XML parser context * @line: line of the start tag * @nsNr: number of namespaces on the start tag * * Parse an end tag. Always consumes '</'. * * [42] ETag ::= '</' Name S? '>' * * With namespace * * [NS 9] ETag ::= '</' QName S? '>' */
static voidxmlParseEndTag1(xmlParserCtxtPtr ctxt, int line) { const xmlChar *name;
GROW; if ((RAW != '<') || (NXT(1) != '/')) { xmlFatalErrMsg(ctxt, XML_ERR_LTSLASH_REQUIRED, "xmlParseEndTag: '</' not found\n"); return; } SKIP(2);
name = xmlParseNameAndCompare(ctxt,ctxt->name);
/* * We should definitely be at the ending "S? '>'" part */ GROW; SKIP_BLANKS; if ((!IS_BYTE_CHAR(RAW)) || (RAW != '>')) { xmlFatalErr(ctxt, XML_ERR_GT_REQUIRED, NULL); } else NEXT1;
/* * [ WFC: Element Type Match ] * The Name in an element's end-tag must match the element type in the * start-tag. * */ if (name != (xmlChar*)1) { if (name == NULL) name = BAD_CAST "unparsable"; xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NAME_MISMATCH, "Opening and ending tag mismatch: %s line %d and %s\n", ctxt->name, line, name); }
/* * SAX: End of Tag */ if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL) && (!ctxt->disableSAX)) ctxt->sax->endElement(ctxt->userData, ctxt->name);
namePop(ctxt); spacePop(ctxt); return;}
/** * xmlParseEndTag: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * parse an end of tag * * [42] ETag ::= '</' Name S? '>' * * With namespace * * [NS 9] ETag ::= '</' QName S? '>' */
voidxmlParseEndTag(xmlParserCtxtPtr ctxt) { xmlParseEndTag1(ctxt, 0);}#endif /* LIBXML_SAX1_ENABLED */
/************************************************************************ * * * SAX 2 specific operations * * * ************************************************************************/
/** * xmlParseQNameHashed: * @ctxt: an XML parser context * @prefix: pointer to store the prefix part * * parse an XML Namespace QName * * [6] QName ::= (Prefix ':')? LocalPart * [7] Prefix ::= NCName * [8] LocalPart ::= NCName * * Returns the Name parsed or NULL */
static xmlHashedStringxmlParseQNameHashed(xmlParserCtxtPtr ctxt, xmlHashedString *prefix) { xmlHashedString l, p; int start, isNCName = 0;
l.name = NULL; p.name = NULL;
GROW; if (ctxt->instate == XML_PARSER_EOF) return(l); start = CUR_PTR - BASE_PTR;
l = xmlParseNCName(ctxt); if (l.name != NULL) { isNCName = 1; if (CUR == ':') { NEXT; p = l; l = xmlParseNCName(ctxt); } } if ((l.name == NULL) || (CUR == ':')) { xmlChar *tmp;
l.name = NULL; p.name = NULL; if (ctxt->instate == XML_PARSER_EOF) return(l); if ((isNCName == 0) && (CUR != ':')) return(l); tmp = xmlParseNmtoken(ctxt); if (tmp != NULL) xmlFree(tmp); if (ctxt->instate == XML_PARSER_EOF) return(l); l = xmlDictLookupHashed(ctxt->dict, BASE_PTR + start, CUR_PTR - (BASE_PTR + start)); xmlNsErr(ctxt, XML_NS_ERR_QNAME, "Failed to parse QName '%s'\n", l.name, NULL, NULL); }
*prefix = p; return(l);}
/** * xmlParseQName: * @ctxt: an XML parser context * @prefix: pointer to store the prefix part * * parse an XML Namespace QName * * [6] QName ::= (Prefix ':')? LocalPart * [7] Prefix ::= NCName * [8] LocalPart ::= NCName * * Returns the Name parsed or NULL */
static const xmlChar *xmlParseQName(xmlParserCtxtPtr ctxt, const xmlChar **prefix) { xmlHashedString n, p;
n = xmlParseQNameHashed(ctxt, &p); if (n.name == NULL) return(NULL); *prefix = p.name; return(n.name);}
/** * xmlParseQNameAndCompare: * @ctxt: an XML parser context * @name: the localname * @prefix: the prefix, if any. * * parse an XML name and compares for match * (specialized for endtag parsing) * * Returns NULL for an illegal name, (xmlChar*) 1 for success * and the name for mismatch */
static const xmlChar *xmlParseQNameAndCompare(xmlParserCtxtPtr ctxt, xmlChar const *name, xmlChar const *prefix) { const xmlChar *cmp; const xmlChar *in; const xmlChar *ret; const xmlChar *prefix2;
if (prefix == NULL) return(xmlParseNameAndCompare(ctxt, name));
GROW; in = ctxt->input->cur;
cmp = prefix; while (*in != 0 && *in == *cmp) { ++in; ++cmp; } if ((*cmp == 0) && (*in == ':')) { in++; cmp = name; while (*in != 0 && *in == *cmp) { ++in; ++cmp; } if (*cmp == 0 && (*in == '>' || IS_BLANK_CH (*in))) { /* success */ ctxt->input->col += in - ctxt->input->cur; ctxt->input->cur = in; return((const xmlChar*) 1); } } /* * all strings coms from the dictionary, equality can be done directly */ ret = xmlParseQName (ctxt, &prefix2); if (ret == NULL) return(NULL); if ((ret == name) && (prefix == prefix2)) return((const xmlChar*) 1); return ret;}
/** * xmlParseAttValueInternal: * @ctxt: an XML parser context * @len: attribute len result * @alloc: whether the attribute was reallocated as a new string * @normalize: if 1 then further non-CDATA normalization must be done * * parse a value for an attribute. * NOTE: if no normalization is needed, the routine will return pointers * directly from the data buffer. * * 3.3.3 Attribute-Value Normalization: * Before the value of an attribute is passed to the application or * checked for validity, the XML processor must normalize it as follows: * - a character reference is processed by appending the referenced * character to the attribute value * - an entity reference is processed by recursively processing the * replacement text of the entity * - a whitespace character (#x20, #xD, #xA, #x9) is processed by * appending #x20 to the normalized value, except that only a single * #x20 is appended for a "#xD#xA" sequence that is part of an external * parsed entity or the literal entity value of an internal parsed entity * - other characters are processed by appending them to the normalized value * 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 a single space (#x20) character. * All attributes for which no declaration has been read should be treated * by a non-validating parser as if declared CDATA. * * Returns the AttValue parsed or NULL. The value has to be freed by the * caller if it was copied, this can be detected by val[*len] == 0. */
#define GROW_PARSE_ATT_VALUE_INTERNAL(ctxt, in, start, end) \ const xmlChar *oldbase = ctxt->input->base;\ GROW;\ if (ctxt->instate == XML_PARSER_EOF)\ return(NULL);\ if (oldbase != ctxt->input->base) {\ ptrdiff_t delta = ctxt->input->base - oldbase;\ start = start + delta;\ in = in + delta;\ }\ end = ctxt->input->end;
static xmlChar *xmlParseAttValueInternal(xmlParserCtxtPtr ctxt, int *len, int *alloc, int normalize){ xmlChar limit = 0; const xmlChar *in = NULL, *start, *end, *last; xmlChar *ret = NULL; int line, col; int maxLength = (ctxt->options & XML_PARSE_HUGE) ? XML_MAX_HUGE_LENGTH : XML_MAX_TEXT_LENGTH;
GROW; in = (xmlChar *) CUR_PTR; line = ctxt->input->line; col = ctxt->input->col; if (*in != '"' && *in != '\'') { xmlFatalErr(ctxt, XML_ERR_ATTRIBUTE_NOT_STARTED, NULL); return (NULL); } ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE;
/* * try to handle in this routine the most common case where no * allocation of a new string is required and where content is * pure ASCII. */ limit = *in++; col++; end = ctxt->input->end; start = in; if (in >= end) { GROW_PARSE_ATT_VALUE_INTERNAL(ctxt, in, start, end) } if (normalize) { /* * Skip any leading spaces */ while ((in < end) && (*in != limit) && ((*in == 0x20) || (*in == 0x9) || (*in == 0xA) || (*in == 0xD))) { if (*in == 0xA) { line++; col = 1; } else { col++; } in++; start = in; if (in >= end) { GROW_PARSE_ATT_VALUE_INTERNAL(ctxt, in, start, end) if ((in - start) > maxLength) { xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, "AttValue length too long\n"); return(NULL); } } } while ((in < end) && (*in != limit) && (*in >= 0x20) && (*in <= 0x7f) && (*in != '&') && (*in != '<')) { col++; if ((*in++ == 0x20) && (*in == 0x20)) break; if (in >= end) { GROW_PARSE_ATT_VALUE_INTERNAL(ctxt, in, start, end) if ((in - start) > maxLength) { xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, "AttValue length too long\n"); return(NULL); } } } last = in; /* * skip the trailing blanks */ while ((last[-1] == 0x20) && (last > start)) last--; while ((in < end) && (*in != limit) && ((*in == 0x20) || (*in == 0x9) || (*in == 0xA) || (*in == 0xD))) { if (*in == 0xA) { line++, col = 1; } else { col++; } in++; if (in >= end) { const xmlChar *oldbase = ctxt->input->base; GROW; if (ctxt->instate == XML_PARSER_EOF) return(NULL); if (oldbase != ctxt->input->base) { ptrdiff_t delta = ctxt->input->base - oldbase; start = start + delta; in = in + delta; last = last + delta; } end = ctxt->input->end; if ((in - start) > maxLength) { xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, "AttValue length too long\n"); return(NULL); } } } if ((in - start) > maxLength) { xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, "AttValue length too long\n"); return(NULL); } if (*in != limit) goto need_complex; } else { while ((in < end) && (*in != limit) && (*in >= 0x20) && (*in <= 0x7f) && (*in != '&') && (*in != '<')) { in++; col++; if (in >= end) { GROW_PARSE_ATT_VALUE_INTERNAL(ctxt, in, start, end) if ((in - start) > maxLength) { xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, "AttValue length too long\n"); return(NULL); } } } last = in; if ((in - start) > maxLength) { xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, "AttValue length too long\n"); return(NULL); } if (*in != limit) goto need_complex; } in++; col++; if (len != NULL) { if (alloc) *alloc = 0; *len = last - start; ret = (xmlChar *) start; } else { if (alloc) *alloc = 1; ret = xmlStrndup(start, last - start); } CUR_PTR = in; ctxt->input->line = line; ctxt->input->col = col; return ret;need_complex: if (alloc) *alloc = 1; return xmlParseAttValueComplex(ctxt, len, normalize);}
/** * xmlParseAttribute2: * @ctxt: an XML parser context * @pref: the element prefix * @elem: the element name * @prefix: a xmlChar ** used to store the value of the attribute prefix * @value: a xmlChar ** used to store the value of the attribute * @len: an int * to save the length of the attribute * @alloc: an int * to indicate if the attribute was allocated * * parse an attribute in the new SAX2 framework. * * Returns the attribute name, and the value in *value, . */
static xmlHashedStringxmlParseAttribute2(xmlParserCtxtPtr ctxt, const xmlChar * pref, const xmlChar * elem, xmlHashedString * hprefix, xmlChar ** value, int *len, int *alloc){ xmlHashedString hname; const xmlChar *prefix, *name; xmlChar *val, *internal_val = NULL; int normalize = 0;
*value = NULL; GROW; hname = xmlParseQNameHashed(ctxt, hprefix); if (hname.name == NULL) { xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, "error parsing attribute name\n"); return(hname); } name = hname.name; if (hprefix->name != NULL) prefix = hprefix->name; else prefix = NULL;
/* * get the type if needed */ if (ctxt->attsSpecial != NULL) { int type;
type = (int) (ptrdiff_t) xmlHashQLookup2(ctxt->attsSpecial, pref, elem, prefix, name); if (type != 0) normalize = 1; }
/* * read the value */ SKIP_BLANKS; if (RAW == '=') { NEXT; SKIP_BLANKS; val = xmlParseAttValueInternal(ctxt, len, alloc, normalize); if (val == NULL) { hname.name = NULL; return(hname); } if (normalize) { /* * Sometimes a second normalisation pass for spaces is needed * but that only happens if charrefs or entities references * have been used in the attribute value, i.e. the attribute * value have been extracted in an allocated string already. */ if (*alloc) { const xmlChar *val2;
val2 = xmlAttrNormalizeSpace2(ctxt, val, len); if ((val2 != NULL) && (val2 != val)) { xmlFree(val); val = (xmlChar *) val2; } } } ctxt->instate = XML_PARSER_CONTENT; } else { xmlFatalErrMsgStr(ctxt, XML_ERR_ATTRIBUTE_WITHOUT_VALUE, "Specification mandates value for attribute %s\n", name); return(hname); }
if (prefix == ctxt->str_xml) { /* * Check that xml:lang conforms to the specification * No more registered as an error, just generate a warning now * since this was deprecated in XML second edition */ if ((ctxt->pedantic) && (xmlStrEqual(name, BAD_CAST "lang"))) { internal_val = xmlStrndup(val, *len); if (!xmlCheckLanguageID(internal_val)) { xmlWarningMsg(ctxt, XML_WAR_LANG_VALUE, "Malformed value for xml:lang : %s\n", internal_val, NULL); } }
/* * Check that xml:space conforms to the specification */ if (xmlStrEqual(name, BAD_CAST "space")) { internal_val = xmlStrndup(val, *len); if (xmlStrEqual(internal_val, BAD_CAST "default")) *(ctxt->space) = 0; else if (xmlStrEqual(internal_val, BAD_CAST "preserve")) *(ctxt->space) = 1; else { xmlWarningMsg(ctxt, XML_WAR_SPACE_VALUE, "Invalid value \"%s\" for xml:space : \"default\" or \"preserve\" expected\n", internal_val, NULL); } } if (internal_val) { xmlFree(internal_val); } }
*value = val; return (hname);}
/** * xmlAttrHashInsert: * @ctxt: parser context * @size: size of the hash table * @name: attribute name * @uri: namespace uri * @hashValue: combined hash value of name and uri * @aindex: attribute index (this is a multiple of 5) * * Inserts a new attribute into the hash table. * * Returns INT_MAX if no existing attribute was found, the attribute * index if an attribute was found, -1 if a memory allocation failed. */static intxmlAttrHashInsert(xmlParserCtxtPtr ctxt, unsigned size, const xmlChar *name, const xmlChar *uri, unsigned hashValue, int aindex) { xmlAttrHashBucket *table = ctxt->attrHash; xmlAttrHashBucket *bucket; unsigned hindex;
hindex = hashValue & (size - 1); bucket = &table[hindex];
while (bucket->index >= 0) { const xmlChar **atts = &ctxt->atts[bucket->index];
if (name == atts[0]) { int nsIndex = (int) (ptrdiff_t) atts[2];
if ((nsIndex == NS_INDEX_EMPTY) ? (uri == NULL) : (nsIndex == NS_INDEX_XML) ? (uri == ctxt->str_xml_ns) : (uri == ctxt->nsTab[nsIndex * 2 + 1])) return(bucket->index); }
hindex++; bucket++; if (hindex >= size) { hindex = 0; bucket = table; } }
bucket->index = aindex;
return(INT_MAX);}
/** * xmlParseStartTag2: * @ctxt: an XML parser context * * Parse a start tag. Always consumes '<'. * * This routine is called when running SAX2 parsing * * [40] STag ::= '<' Name (S Attribute)* S? '>' * * [ WFC: Unique Att Spec ] * No attribute name may appear more than once in the same start-tag or * empty-element tag. * * [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>' * * [ WFC: Unique Att Spec ] * No attribute name may appear more than once in the same start-tag or * empty-element tag. * * With namespace: * * [NS 8] STag ::= '<' QName (S Attribute)* S? '>' * * [NS 10] EmptyElement ::= '<' QName (S Attribute)* S? '/>' * * Returns the element name parsed */
static const xmlChar *xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref, const xmlChar **URI, int *nbNsPtr) { xmlHashedString hlocalname; xmlHashedString hprefix; xmlHashedString hattname; xmlHashedString haprefix; const xmlChar *localname; const xmlChar *prefix; const xmlChar *attname; const xmlChar *aprefix; const xmlChar *uri; xmlChar *attvalue = NULL; const xmlChar **atts = ctxt->atts; unsigned attrHashSize = 0; int maxatts = ctxt->maxatts; int nratts, nbatts, nbdef, inputid; int i, j, nbNs, nbTotalDef, attval, nsIndex, maxAtts; int alloc = 0;
if (RAW != '<') return(NULL); NEXT1;
inputid = ctxt->input->id; nbatts = 0; nratts = 0; nbdef = 0; nbNs = 0; nbTotalDef = 0; attval = 0;
if (xmlParserNsStartElement(ctxt->nsdb) < 0) { xmlErrMemory(ctxt, NULL); return(NULL); }
hlocalname = xmlParseQNameHashed(ctxt, &hprefix); if (hlocalname.name == NULL) { xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, "StartTag: invalid element name\n"); return(NULL); } localname = hlocalname.name; prefix = hprefix.name;
/* * Now parse the attributes, it ends up with the ending * * (S Attribute)* S? */ SKIP_BLANKS; GROW;
/* * The ctxt->atts array will be ultimately passed to the SAX callback * containing five xmlChar pointers for each attribute: * * [0] attribute name * [1] attribute prefix * [2] namespace URI * [3] attribute value * [4] end of attribute value * * To save memory, we reuse this array temporarily and store integers * in these pointer variables. * * [0] attribute name * [1] attribute prefix * [2] hash value of attribute prefix, and later namespace index * [3] for non-allocated values: ptrdiff_t offset into input buffer * [4] for non-allocated values: ptrdiff_t offset into input buffer * * The ctxt->attallocs array contains an additional unsigned int for * each attribute, containing the hash value of the attribute name * and the alloc flag in bit 31. */
while (((RAW != '>') && ((RAW != '/') || (NXT(1) != '>')) && (IS_BYTE_CHAR(RAW))) && (ctxt->instate != XML_PARSER_EOF)) { int len = -1;
hattname = xmlParseAttribute2(ctxt, prefix, localname, &haprefix, &attvalue, &len, &alloc); if (hattname.name == NULL) { xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, "xmlParseStartTag: problem parsing attributes\n"); break; } if (attvalue == NULL) goto next_attr; attname = hattname.name; aprefix = haprefix.name; if (len < 0) len = xmlStrlen(attvalue);
if ((attname == ctxt->str_xmlns) && (aprefix == NULL)) { xmlHashedString huri; xmlURIPtr parsedUri;
huri = xmlDictLookupHashed(ctxt->dict, attvalue, len); uri = huri.name; if (uri == NULL) { xmlErrMemory(ctxt, NULL); goto next_attr; } if (*uri != 0) { parsedUri = xmlParseURI((const char *) uri); if (parsedUri == NULL) { xmlNsErr(ctxt, XML_WAR_NS_URI, "xmlns: '%s' is not a valid URI\n", uri, NULL, NULL); } else { if (parsedUri->scheme == NULL) { xmlNsWarn(ctxt, XML_WAR_NS_URI_RELATIVE, "xmlns: URI %s is not absolute\n", uri, NULL, NULL); } xmlFreeURI(parsedUri); } if (uri == ctxt->str_xml_ns) { if (attname != ctxt->str_xml) { xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE, "xml namespace URI cannot be the default namespace\n", NULL, NULL, NULL); } goto next_attr; } if ((len == 29) && (xmlStrEqual(uri, BAD_CAST "http://www.w3.org/2000/xmlns/"))) { xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE, "reuse of the xmlns namespace name is forbidden\n", NULL, NULL, NULL); goto next_attr; } }
if (xmlParserNsPush(ctxt, NULL, &huri, NULL, 0) > 0) nbNs++; } else if (aprefix == ctxt->str_xmlns) { xmlHashedString huri; xmlURIPtr parsedUri;
huri = xmlDictLookupHashed(ctxt->dict, attvalue, len); uri = huri.name; if (uri == NULL) { xmlErrMemory(ctxt, NULL); goto next_attr; }
if (attname == ctxt->str_xml) { if (uri != ctxt->str_xml_ns) { xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE, "xml namespace prefix mapped to wrong URI\n", NULL, NULL, NULL); } /* * Do not keep a namespace definition node */ goto next_attr; } if (uri == ctxt->str_xml_ns) { if (attname != ctxt->str_xml) { xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE, "xml namespace URI mapped to wrong prefix\n", NULL, NULL, NULL); } goto next_attr; } if (attname == ctxt->str_xmlns) { xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE, "redefinition of the xmlns prefix is forbidden\n", NULL, NULL, NULL); goto next_attr; } if ((len == 29) && (xmlStrEqual(uri, BAD_CAST "http://www.w3.org/2000/xmlns/"))) { xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE, "reuse of the xmlns namespace name is forbidden\n", NULL, NULL, NULL); goto next_attr; } if ((uri == NULL) || (uri[0] == 0)) { xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE, "xmlns:%s: Empty XML namespace is not allowed\n", attname, NULL, NULL); goto next_attr; } else { parsedUri = xmlParseURI((const char *) uri); if (parsedUri == NULL) { xmlNsErr(ctxt, XML_WAR_NS_URI, "xmlns:%s: '%s' is not a valid URI\n", attname, uri, NULL); } else { if ((ctxt->pedantic) && (parsedUri->scheme == NULL)) { xmlNsWarn(ctxt, XML_WAR_NS_URI_RELATIVE, "xmlns:%s: URI %s is not absolute\n", attname, uri, NULL); } xmlFreeURI(parsedUri); } }
if (xmlParserNsPush(ctxt, &hattname, &huri, NULL, 0) > 0) nbNs++; } else { /* * Populate attributes array, see above for repurposing * of xmlChar pointers. */ if ((atts == NULL) || (nbatts + 5 > maxatts)) { if (xmlCtxtGrowAttrs(ctxt, nbatts + 5) < 0) { goto next_attr; } maxatts = ctxt->maxatts; atts = ctxt->atts; } ctxt->attallocs[nratts++] = (hattname.hashValue & 0x7FFFFFFF) | ((unsigned) alloc << 31); atts[nbatts++] = attname; atts[nbatts++] = aprefix; atts[nbatts++] = (const xmlChar *) (size_t) haprefix.hashValue; if (alloc) { atts[nbatts++] = attvalue; attvalue += len; atts[nbatts++] = attvalue; } else { /* * attvalue points into the input buffer which can be * reallocated. Store differences to input->base instead. * The pointers will be reconstructed later. */ atts[nbatts++] = (void *) (attvalue - BASE_PTR); attvalue += len; atts[nbatts++] = (void *) (attvalue - BASE_PTR); } /* * tag if some deallocation is needed */ if (alloc != 0) attval = 1; attvalue = NULL; /* moved into atts */ }
next_attr: if ((attvalue != NULL) && (alloc != 0)) { xmlFree(attvalue); attvalue = NULL; }
GROW if (ctxt->instate == XML_PARSER_EOF) break; if ((RAW == '>') || (((RAW == '/') && (NXT(1) == '>')))) break; if (SKIP_BLANKS == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "attributes construct error\n"); break; } GROW; }
if (ctxt->input->id != inputid) { xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, "Unexpected change of input\n"); localname = NULL; goto done; }
/* * Namespaces from default attributes */ if (ctxt->attsDefault != NULL) { xmlDefAttrsPtr defaults;
defaults = xmlHashLookup2(ctxt->attsDefault, localname, prefix); if (defaults != NULL) { for (i = 0; i < defaults->nbAttrs; i++) { xmlDefAttr *attr = &defaults->attrs[i];
attname = attr->name.name; aprefix = attr->prefix.name;
if ((attname == ctxt->str_xmlns) && (aprefix == NULL)) { xmlParserEntityCheck(ctxt, attr->expandedSize);
if (xmlParserNsPush(ctxt, NULL, &attr->value, NULL, 1) > 0) nbNs++; } else if (aprefix == ctxt->str_xmlns) { xmlParserEntityCheck(ctxt, attr->expandedSize);
if (xmlParserNsPush(ctxt, &attr->name, &attr->value, NULL, 1) > 0) nbNs++; } else { nbTotalDef += 1; } } } }
/* * Resolve attribute namespaces */ for (i = 0; i < nbatts; i += 5) { attname = atts[i]; aprefix = atts[i+1];
/* * The default namespace does not apply to attribute names. */ if (aprefix == NULL) { nsIndex = NS_INDEX_EMPTY; } else if (aprefix == ctxt->str_xml) { nsIndex = NS_INDEX_XML; } else { haprefix.name = aprefix; haprefix.hashValue = (size_t) atts[i+2]; nsIndex = xmlParserNsLookup(ctxt, &haprefix, NULL); if (nsIndex == INT_MAX) { xmlNsErr(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE, "Namespace prefix %s for %s on %s is not defined\n", aprefix, attname, localname); nsIndex = NS_INDEX_EMPTY; } }
atts[i+2] = (const xmlChar *) (ptrdiff_t) nsIndex; }
/* * Maximum number of attributes including default attributes. */ maxAtts = nratts + nbTotalDef;
/* * Verify that attribute names are unique. */ if (maxAtts > 1) { attrHashSize = 4; while (attrHashSize / 2 < (unsigned) maxAtts) attrHashSize *= 2;
if (attrHashSize > ctxt->attrHashMax) { xmlAttrHashBucket *tmp;
tmp = xmlRealloc(ctxt->attrHash, attrHashSize * sizeof(tmp[0])); if (tmp == NULL) { xmlErrMemory(ctxt, NULL); goto done; }
ctxt->attrHash = tmp; ctxt->attrHashMax = attrHashSize; }
memset(ctxt->attrHash, -1, attrHashSize * sizeof(ctxt->attrHash[0]));
for (i = 0, j = 0; j < nratts; i += 5, j++) { const xmlChar *nsuri; unsigned hashValue, nameHashValue, uriHashValue; int res;
attname = atts[i]; aprefix = atts[i+1]; nsIndex = (ptrdiff_t) atts[i+2]; /* Hash values always have bit 31 set, see dict.c */ nameHashValue = ctxt->attallocs[j] | 0x80000000;
if (nsIndex == NS_INDEX_EMPTY) { nsuri = NULL; uriHashValue = URI_HASH_EMPTY; } else if (nsIndex == NS_INDEX_XML) { nsuri = ctxt->str_xml_ns; uriHashValue = URI_HASH_XML; } else { nsuri = ctxt->nsTab[nsIndex * 2 + 1]; uriHashValue = ctxt->nsdb->extra[nsIndex].uriHashValue; }
hashValue = xmlDictCombineHash(nameHashValue, uriHashValue); res = xmlAttrHashInsert(ctxt, attrHashSize, attname, nsuri, hashValue, i); if (res < 0) continue;
/* * [ WFC: Unique Att Spec ] * No attribute name may appear more than once in the same * start-tag or empty-element tag. * As extended by the Namespace in XML REC. */ if (res < INT_MAX) { if (aprefix == atts[res+1]) { xmlErrAttributeDup(ctxt, aprefix, attname); } else { xmlNsErr(ctxt, XML_NS_ERR_ATTRIBUTE_REDEFINED, "Namespaced Attribute %s in '%s' redefined\n", attname, nsuri, NULL); } } } }
/* * Default attributes */ if (ctxt->attsDefault != NULL) { xmlDefAttrsPtr defaults;
defaults = xmlHashLookup2(ctxt->attsDefault, localname, prefix); if (defaults != NULL) { for (i = 0; i < defaults->nbAttrs; i++) { xmlDefAttr *attr = &defaults->attrs[i]; const xmlChar *nsuri; unsigned hashValue, uriHashValue; int res;
attname = attr->name.name; aprefix = attr->prefix.name;
if ((attname == ctxt->str_xmlns) && (aprefix == NULL)) continue; if (aprefix == ctxt->str_xmlns) continue;
if (aprefix == NULL) { nsIndex = NS_INDEX_EMPTY; nsuri = NULL; uriHashValue = URI_HASH_EMPTY; } if (aprefix == ctxt->str_xml) { nsIndex = NS_INDEX_XML; nsuri = ctxt->str_xml_ns; uriHashValue = URI_HASH_XML; } else if (aprefix != NULL) { nsIndex = xmlParserNsLookup(ctxt, &attr->prefix, NULL); if (nsIndex == INT_MAX) { xmlNsErr(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE, "Namespace prefix %s for %s on %s is not " "defined\n", aprefix, attname, localname); nsIndex = NS_INDEX_EMPTY; nsuri = NULL; uriHashValue = URI_HASH_EMPTY; } else { nsuri = ctxt->nsTab[nsIndex * 2 + 1]; uriHashValue = ctxt->nsdb->extra[nsIndex].uriHashValue; } }
/* * Check whether the attribute exists */ if (maxAtts > 1) { hashValue = xmlDictCombineHash(attr->name.hashValue, uriHashValue); res = xmlAttrHashInsert(ctxt, attrHashSize, attname, nsuri, hashValue, nbatts); if (res < 0) continue; if (res < INT_MAX) { if (aprefix == atts[res+1]) continue; xmlNsErr(ctxt, XML_NS_ERR_ATTRIBUTE_REDEFINED, "Namespaced Attribute %s in '%s' redefined\n", attname, nsuri, NULL); } }
xmlParserEntityCheck(ctxt, attr->expandedSize);
if ((atts == NULL) || (nbatts + 5 > maxatts)) { if (xmlCtxtGrowAttrs(ctxt, nbatts + 5) < 0) { localname = NULL; goto done; } maxatts = ctxt->maxatts; atts = ctxt->atts; }
atts[nbatts++] = attname; atts[nbatts++] = aprefix; atts[nbatts++] = (const xmlChar *) (ptrdiff_t) nsIndex; atts[nbatts++] = attr->value.name; atts[nbatts++] = attr->valueEnd; if ((ctxt->standalone == 1) && (attr->external != 0)) { xmlValidityError(ctxt, XML_DTD_STANDALONE_DEFAULTED, "standalone: attribute %s on %s defaulted " "from external subset\n", attname, localname); } nbdef++; } } }
/* * Reconstruct attribute pointers */ for (i = 0, j = 0; i < nbatts; i += 5, j++) { /* namespace URI */ nsIndex = (ptrdiff_t) atts[i+2]; if (nsIndex == INT_MAX) atts[i+2] = NULL; else if (nsIndex == INT_MAX - 1) atts[i+2] = ctxt->str_xml_ns; else atts[i+2] = ctxt->nsTab[nsIndex * 2 + 1];
if ((j < nratts) && (ctxt->attallocs[j] & 0x80000000) == 0) { atts[i+3] = BASE_PTR + (ptrdiff_t) atts[i+3]; /* value */ atts[i+4] = BASE_PTR + (ptrdiff_t) atts[i+4]; /* valuend */ } }
uri = xmlParserNsLookupUri(ctxt, &hprefix); if ((prefix != NULL) && (uri == NULL)) { xmlNsErr(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE, "Namespace prefix %s on %s is not defined\n", prefix, localname, NULL); } *pref = prefix; *URI = uri;
/* * SAX callback */ if ((ctxt->sax != NULL) && (ctxt->sax->startElementNs != NULL) && (!ctxt->disableSAX)) { if (nbNs > 0) ctxt->sax->startElementNs(ctxt->userData, localname, prefix, uri, nbNs, ctxt->nsTab + 2 * (ctxt->nsNr - nbNs), nbatts / 5, nbdef, atts); else ctxt->sax->startElementNs(ctxt->userData, localname, prefix, uri, 0, NULL, nbatts / 5, nbdef, atts); }
done: /* * Free allocated attribute values */ if (attval != 0) { for (i = 0, j = 0; j < nratts; i += 5, j++) if (ctxt->attallocs[j] & 0x80000000) xmlFree((xmlChar *) atts[i+3]); }
*nbNsPtr = nbNs; return(localname);}
/** * xmlParseEndTag2: * @ctxt: an XML parser context * @line: line of the start tag * @nsNr: number of namespaces on the start tag * * Parse an end tag. Always consumes '</'. * * [42] ETag ::= '</' Name S? '>' * * With namespace * * [NS 9] ETag ::= '</' QName S? '>' */
static voidxmlParseEndTag2(xmlParserCtxtPtr ctxt, const xmlStartTag *tag) { const xmlChar *name;
GROW; if ((RAW != '<') || (NXT(1) != '/')) { xmlFatalErr(ctxt, XML_ERR_LTSLASH_REQUIRED, NULL); return; } SKIP(2);
if (tag->prefix == NULL) name = xmlParseNameAndCompare(ctxt, ctxt->name); else name = xmlParseQNameAndCompare(ctxt, ctxt->name, tag->prefix);
/* * We should definitely be at the ending "S? '>'" part */ GROW; if (ctxt->instate == XML_PARSER_EOF) return; SKIP_BLANKS; if ((!IS_BYTE_CHAR(RAW)) || (RAW != '>')) { xmlFatalErr(ctxt, XML_ERR_GT_REQUIRED, NULL); } else NEXT1;
/* * [ WFC: Element Type Match ] * The Name in an element's end-tag must match the element type in the * start-tag. * */ if (name != (xmlChar*)1) { if (name == NULL) name = BAD_CAST "unparsable"; xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NAME_MISMATCH, "Opening and ending tag mismatch: %s line %d and %s\n", ctxt->name, tag->line, name); }
/* * SAX: End of Tag */ if ((ctxt->sax != NULL) && (ctxt->sax->endElementNs != NULL) && (!ctxt->disableSAX)) ctxt->sax->endElementNs(ctxt->userData, ctxt->name, tag->prefix, tag->URI);
spacePop(ctxt); if (tag->nsNr != 0) xmlParserNsPop(ctxt, tag->nsNr);}
/** * xmlParseCDSect: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * Parse escaped pure raw content. Always consumes '<!['. * * [18] CDSect ::= CDStart CData CDEnd * * [19] CDStart ::= '<![CDATA[' * * [20] Data ::= (Char* - (Char* ']]>' Char*)) * * [21] CDEnd ::= ']]>' */voidxmlParseCDSect(xmlParserCtxtPtr ctxt) { xmlChar *buf = NULL; int len = 0; int size = XML_PARSER_BUFFER_SIZE; int r, rl; int s, sl; int cur, l; int maxLength = (ctxt->options & XML_PARSE_HUGE) ? XML_MAX_HUGE_LENGTH : XML_MAX_TEXT_LENGTH;
if ((CUR != '<') || (NXT(1) != '!') || (NXT(2) != '[')) return; SKIP(3);
if (!CMP6(CUR_PTR, 'C', 'D', 'A', 'T', 'A', '[')) return; SKIP(6);
ctxt->instate = XML_PARSER_CDATA_SECTION; r = CUR_CHAR(rl); if (!IS_CHAR(r)) { xmlFatalErr(ctxt, XML_ERR_CDATA_NOT_FINISHED, NULL); goto out; } NEXTL(rl); s = CUR_CHAR(sl); if (!IS_CHAR(s)) { xmlFatalErr(ctxt, XML_ERR_CDATA_NOT_FINISHED, NULL); goto out; } NEXTL(sl); cur = CUR_CHAR(l); buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { xmlErrMemory(ctxt, NULL); goto out; } while (IS_CHAR(cur) && ((r != ']') || (s != ']') || (cur != '>'))) { if (len + 5 >= size) { xmlChar *tmp;
tmp = (xmlChar *) xmlRealloc(buf, size * 2); if (tmp == NULL) { xmlErrMemory(ctxt, NULL); goto out; } buf = tmp; size *= 2; } COPY_BUF(buf, len, r); if (len > maxLength) { xmlFatalErrMsg(ctxt, XML_ERR_CDATA_NOT_FINISHED, "CData section too big found\n"); goto out; } r = s; rl = sl; s = cur; sl = l; NEXTL(l); cur = CUR_CHAR(l); } buf[len] = 0; if (ctxt->instate == XML_PARSER_EOF) { xmlFree(buf); return; } if (cur != '>') { xmlFatalErrMsgStr(ctxt, XML_ERR_CDATA_NOT_FINISHED, "CData section not finished\n%.50s\n", buf); goto out; } NEXTL(l);
/* * OK the buffer is to be consumed as cdata. */ if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) { if (ctxt->sax->cdataBlock != NULL) ctxt->sax->cdataBlock(ctxt->userData, buf, len); else if (ctxt->sax->characters != NULL) ctxt->sax->characters(ctxt->userData, buf, len); }
out: if (ctxt->instate != XML_PARSER_EOF) ctxt->instate = XML_PARSER_CONTENT; xmlFree(buf);}
/** * xmlParseContentInternal: * @ctxt: an XML parser context * * Parse a content sequence. Stops at EOF or '</'. Leaves checking of * unexpected EOF to the caller. */
static voidxmlParseContentInternal(xmlParserCtxtPtr ctxt) { int nameNr = ctxt->nameNr;
GROW; while ((ctxt->input->cur < ctxt->input->end) && (ctxt->instate != XML_PARSER_EOF)) { const xmlChar *cur = ctxt->input->cur;
/* * First case : a Processing Instruction. */ if ((*cur == '<') && (cur[1] == '?')) { xmlParsePI(ctxt); }
/* * Second case : a CDSection */ /* 2.6.0 test was *cur not RAW */ else if (CMP9(CUR_PTR, '<', '!', '[', 'C', 'D', 'A', 'T', 'A', '[')) { xmlParseCDSect(ctxt); }
/* * Third case : a comment */ else if ((*cur == '<') && (NXT(1) == '!') && (NXT(2) == '-') && (NXT(3) == '-')) { xmlParseComment(ctxt); ctxt->instate = XML_PARSER_CONTENT; }
/* * Fourth case : a sub-element. */ else if (*cur == '<') { if (NXT(1) == '/') { if (ctxt->nameNr <= nameNr) break; xmlParseElementEnd(ctxt); } else { xmlParseElementStart(ctxt); } }
/* * Fifth case : a reference. If if has not been resolved, * parsing returns it's Name, create the node */
else if (*cur == '&') { xmlParseReference(ctxt); }
/* * Last case, text. Note that References are handled directly. */ else { xmlParseCharDataInternal(ctxt, 0); }
SHRINK; GROW; }}
/** * xmlParseContent: * @ctxt: an XML parser context * * Parse a content sequence. Stops at EOF or '</'. * * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)* */
voidxmlParseContent(xmlParserCtxtPtr ctxt) { int nameNr = ctxt->nameNr;
xmlParseContentInternal(ctxt);
if ((ctxt->instate != XML_PARSER_EOF) && (ctxt->errNo == XML_ERR_OK) && (ctxt->nameNr > nameNr)) { const xmlChar *name = ctxt->nameTab[ctxt->nameNr - 1]; int line = ctxt->pushTab[ctxt->nameNr - 1].line; xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED, "Premature end of data in tag %s line %d\n", name, line, NULL); }}
/** * xmlParseElement: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * parse an XML element * * [39] element ::= EmptyElemTag | STag content ETag * * [ WFC: Element Type Match ] * The Name in an element's end-tag must match the element type in the * start-tag. * */
voidxmlParseElement(xmlParserCtxtPtr ctxt) { if (xmlParseElementStart(ctxt) != 0) return;
xmlParseContentInternal(ctxt); if (ctxt->instate == XML_PARSER_EOF) return;
if (ctxt->input->cur >= ctxt->input->end) { if (ctxt->errNo == XML_ERR_OK) { const xmlChar *name = ctxt->nameTab[ctxt->nameNr - 1]; int line = ctxt->pushTab[ctxt->nameNr - 1].line; xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED, "Premature end of data in tag %s line %d\n", name, line, NULL); } return; }
xmlParseElementEnd(ctxt);}
/** * xmlParseElementStart: * @ctxt: an XML parser context * * Parse the start of an XML element. Returns -1 in case of error, 0 if an * opening tag was parsed, 1 if an empty element was parsed. * * Always consumes '<'. */static intxmlParseElementStart(xmlParserCtxtPtr ctxt) { const xmlChar *name; const xmlChar *prefix = NULL; const xmlChar *URI = NULL; xmlParserNodeInfo node_info; int line; xmlNodePtr cur; int nbNs = 0;
if (((unsigned int) ctxt->nameNr > xmlParserMaxDepth) && ((ctxt->options & XML_PARSE_HUGE) == 0)) { xmlFatalErrMsgInt(ctxt, XML_ERR_INTERNAL_ERROR, "Excessive depth in document: %d use XML_PARSE_HUGE option\n", xmlParserMaxDepth); xmlHaltParser(ctxt); return(-1); }
/* Capture start position */ if (ctxt->record_info) { node_info.begin_pos = ctxt->input->consumed + (CUR_PTR - ctxt->input->base); node_info.begin_line = ctxt->input->line; }
if (ctxt->spaceNr == 0) spacePush(ctxt, -1); else if (*ctxt->space == -2) spacePush(ctxt, -1); else spacePush(ctxt, *ctxt->space);
line = ctxt->input->line;#ifdef LIBXML_SAX1_ENABLED if (ctxt->sax2)#endif /* LIBXML_SAX1_ENABLED */ name = xmlParseStartTag2(ctxt, &prefix, &URI, &nbNs);#ifdef LIBXML_SAX1_ENABLED else name = xmlParseStartTag(ctxt);#endif /* LIBXML_SAX1_ENABLED */ if (ctxt->instate == XML_PARSER_EOF) return(-1); if (name == NULL) { spacePop(ctxt); return(-1); } nameNsPush(ctxt, name, prefix, URI, line, nbNs); cur = ctxt->node;
#ifdef LIBXML_VALID_ENABLED /* * [ VC: Root Element Type ] * The Name in the document type declaration must match the element * type of the root element. */ if (ctxt->validate && ctxt->wellFormed && ctxt->myDoc && ctxt->node && (ctxt->node == ctxt->myDoc->children)) ctxt->valid &= xmlValidateRoot(&ctxt->vctxt, ctxt->myDoc);#endif /* LIBXML_VALID_ENABLED */
/* * Check for an Empty Element. */ if ((RAW == '/') && (NXT(1) == '>')) { SKIP(2); if (ctxt->sax2) { if ((ctxt->sax != NULL) && (ctxt->sax->endElementNs != NULL) && (!ctxt->disableSAX)) ctxt->sax->endElementNs(ctxt->userData, name, prefix, URI);#ifdef LIBXML_SAX1_ENABLED } else { if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL) && (!ctxt->disableSAX)) ctxt->sax->endElement(ctxt->userData, name);#endif /* LIBXML_SAX1_ENABLED */ } namePop(ctxt); spacePop(ctxt); if (nbNs > 0) xmlParserNsPop(ctxt, nbNs); if (cur != NULL && ctxt->record_info) { node_info.node = cur; node_info.end_pos = ctxt->input->consumed + (CUR_PTR - ctxt->input->base); node_info.end_line = ctxt->input->line; xmlParserAddNodeInfo(ctxt, &node_info); } return(1); } if (RAW == '>') { NEXT1; if (cur != NULL && ctxt->record_info) { node_info.node = cur; node_info.end_pos = 0; node_info.end_line = 0; xmlParserAddNodeInfo(ctxt, &node_info); } } else { xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_GT_REQUIRED, "Couldn't find end of Start Tag %s line %d\n", name, line, NULL);
/* * end of parsing of this node. */ nodePop(ctxt); namePop(ctxt); spacePop(ctxt); if (nbNs > 0) xmlParserNsPop(ctxt, nbNs); return(-1); }
return(0);}
/** * xmlParseElementEnd: * @ctxt: an XML parser context * * Parse the end of an XML element. Always consumes '</'. */static voidxmlParseElementEnd(xmlParserCtxtPtr ctxt) { xmlNodePtr cur = ctxt->node;
if (ctxt->nameNr <= 0) { if ((RAW == '<') && (NXT(1) == '/')) SKIP(2); return; }
/* * parse the end of tag: '</' should be here. */ if (ctxt->sax2) { xmlParseEndTag2(ctxt, &ctxt->pushTab[ctxt->nameNr - 1]); namePop(ctxt); }#ifdef LIBXML_SAX1_ENABLED else xmlParseEndTag1(ctxt, 0);#endif /* LIBXML_SAX1_ENABLED */
/* * Capture end position */ if (cur != NULL && ctxt->record_info) { xmlParserNodeInfoPtr node_info;
node_info = (xmlParserNodeInfoPtr) xmlParserFindNodeInfo(ctxt, cur); if (node_info != NULL) { node_info->end_pos = ctxt->input->consumed + (CUR_PTR - ctxt->input->base); node_info->end_line = ctxt->input->line; } }}
/** * xmlParseVersionNum: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * parse the XML version value. * * [26] VersionNum ::= '1.' [0-9]+ * * In practice allow [0-9].[0-9]+ at that level * * Returns the string giving the XML version number, or NULL */xmlChar *xmlParseVersionNum(xmlParserCtxtPtr ctxt) { xmlChar *buf = NULL; int len = 0; int size = 10; xmlChar cur;
buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { xmlErrMemory(ctxt, NULL); return(NULL); } cur = CUR; if (!((cur >= '0') && (cur <= '9'))) { xmlFree(buf); return(NULL); } buf[len++] = cur; NEXT; cur=CUR; if (cur != '.') { xmlFree(buf); return(NULL); } buf[len++] = cur; NEXT; cur=CUR; while ((cur >= '0') && (cur <= '9')) { if (len + 1 >= size) { xmlChar *tmp;
size *= 2; tmp = (xmlChar *) xmlRealloc(buf, size); if (tmp == NULL) { xmlFree(buf); xmlErrMemory(ctxt, NULL); return(NULL); } buf = tmp; } buf[len++] = cur; NEXT; cur=CUR; } buf[len] = 0; return(buf);}
/** * xmlParseVersionInfo: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * parse the XML version. * * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ") * * [25] Eq ::= S? '=' S? * * Returns the version string, e.g. "1.0" */
xmlChar *xmlParseVersionInfo(xmlParserCtxtPtr ctxt) { xmlChar *version = NULL;
if (CMP7(CUR_PTR, 'v', 'e', 'r', 's', 'i', 'o', 'n')) { SKIP(7); SKIP_BLANKS; if (RAW != '=') { xmlFatalErr(ctxt, XML_ERR_EQUAL_REQUIRED, NULL); return(NULL); } NEXT; SKIP_BLANKS; if (RAW == '"') { NEXT; version = xmlParseVersionNum(ctxt); if (RAW != '"') { xmlFatalErr(ctxt, XML_ERR_STRING_NOT_CLOSED, NULL); } else NEXT; } else if (RAW == '\''){ NEXT; version = xmlParseVersionNum(ctxt); if (RAW != '\'') { xmlFatalErr(ctxt, XML_ERR_STRING_NOT_CLOSED, NULL); } else NEXT; } else { xmlFatalErr(ctxt, XML_ERR_STRING_NOT_STARTED, NULL); } } return(version);}
/** * xmlParseEncName: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * parse the XML encoding name * * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')* * * Returns the encoding name value or NULL */xmlChar *xmlParseEncName(xmlParserCtxtPtr ctxt) { xmlChar *buf = NULL; int len = 0; int size = 10; int maxLength = (ctxt->options & XML_PARSE_HUGE) ? XML_MAX_TEXT_LENGTH : XML_MAX_NAME_LENGTH; xmlChar cur;
cur = CUR; if (((cur >= 'a') && (cur <= 'z')) || ((cur >= 'A') && (cur <= 'Z'))) { buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { xmlErrMemory(ctxt, NULL); return(NULL); }
buf[len++] = cur; NEXT; cur = CUR; while (((cur >= 'a') && (cur <= 'z')) || ((cur >= 'A') && (cur <= 'Z')) || ((cur >= '0') && (cur <= '9')) || (cur == '.') || (cur == '_') || (cur == '-')) { if (len + 1 >= size) { xmlChar *tmp;
size *= 2; tmp = (xmlChar *) xmlRealloc(buf, size); if (tmp == NULL) { xmlErrMemory(ctxt, NULL); xmlFree(buf); return(NULL); } buf = tmp; } buf[len++] = cur; if (len > maxLength) { xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "EncName"); xmlFree(buf); return(NULL); } NEXT; cur = CUR; } buf[len] = 0; } else { xmlFatalErr(ctxt, XML_ERR_ENCODING_NAME, NULL); } return(buf);}
/** * xmlParseEncodingDecl: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * parse the XML encoding declaration * * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'") * * this setups the conversion filters. * * Returns the encoding value or NULL */
const xmlChar *xmlParseEncodingDecl(xmlParserCtxtPtr ctxt) { xmlChar *encoding = NULL;
SKIP_BLANKS; if (CMP8(CUR_PTR, 'e', 'n', 'c', 'o', 'd', 'i', 'n', 'g') == 0) return(NULL);
SKIP(8); SKIP_BLANKS; if (RAW != '=') { xmlFatalErr(ctxt, XML_ERR_EQUAL_REQUIRED, NULL); return(NULL); } NEXT; SKIP_BLANKS; if (RAW == '"') { NEXT; encoding = xmlParseEncName(ctxt); if (RAW != '"') { xmlFatalErr(ctxt, XML_ERR_STRING_NOT_CLOSED, NULL); xmlFree((xmlChar *) encoding); return(NULL); } else NEXT; } else if (RAW == '\''){ NEXT; encoding = xmlParseEncName(ctxt); if (RAW != '\'') { xmlFatalErr(ctxt, XML_ERR_STRING_NOT_CLOSED, NULL); xmlFree((xmlChar *) encoding); return(NULL); } else NEXT; } else { xmlFatalErr(ctxt, XML_ERR_STRING_NOT_STARTED, NULL); }
if (encoding == NULL) return(NULL);
xmlSetDeclaredEncoding(ctxt, encoding);
return(ctxt->encoding);}
/** * xmlParseSDDecl: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * parse the XML standalone declaration * * [32] SDDecl ::= S 'standalone' Eq * (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no')'"')) * * [ VC: Standalone Document Declaration ] * TODO The standalone document declaration must have the value "no" * if any external markup declarations contain declarations of: * - attributes with default values, if elements to which these * attributes apply appear in the document without specifications * of values for these attributes, or * - entities (other than amp, lt, gt, apos, quot), if references * to those entities appear in the document, or * - attributes with values subject to normalization, where the * attribute appears in the document with a value which will change * as a result of normalization, or * - element types with element content, if white space occurs directly * within any instance of those types. * * Returns: * 1 if standalone="yes" * 0 if standalone="no" * -2 if standalone attribute is missing or invalid * (A standalone value of -2 means that the XML declaration was found, * but no value was specified for the standalone attribute). */
intxmlParseSDDecl(xmlParserCtxtPtr ctxt) { int standalone = -2;
SKIP_BLANKS; if (CMP10(CUR_PTR, 's', 't', 'a', 'n', 'd', 'a', 'l', 'o', 'n', 'e')) { SKIP(10); SKIP_BLANKS; if (RAW != '=') { xmlFatalErr(ctxt, XML_ERR_EQUAL_REQUIRED, NULL); return(standalone); } NEXT; SKIP_BLANKS; if (RAW == '\''){ NEXT; if ((RAW == 'n') && (NXT(1) == 'o')) { standalone = 0; SKIP(2); } else if ((RAW == 'y') && (NXT(1) == 'e') && (NXT(2) == 's')) { standalone = 1; SKIP(3); } else { xmlFatalErr(ctxt, XML_ERR_STANDALONE_VALUE, NULL); } if (RAW != '\'') { xmlFatalErr(ctxt, XML_ERR_STRING_NOT_CLOSED, NULL); } else NEXT; } else if (RAW == '"'){ NEXT; if ((RAW == 'n') && (NXT(1) == 'o')) { standalone = 0; SKIP(2); } else if ((RAW == 'y') && (NXT(1) == 'e') && (NXT(2) == 's')) { standalone = 1; SKIP(3); } else { xmlFatalErr(ctxt, XML_ERR_STANDALONE_VALUE, NULL); } if (RAW != '"') { xmlFatalErr(ctxt, XML_ERR_STRING_NOT_CLOSED, NULL); } else NEXT; } else { xmlFatalErr(ctxt, XML_ERR_STRING_NOT_STARTED, NULL); } } return(standalone);}
/** * xmlParseXMLDecl: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * parse an XML declaration header * * [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>' */
voidxmlParseXMLDecl(xmlParserCtxtPtr ctxt) { xmlChar *version;
/* * This value for standalone indicates that the document has an * XML declaration but it does not have a standalone attribute. * It will be overwritten later if a standalone attribute is found. */
ctxt->standalone = -2;
/* * We know that '<?xml' is here. */ SKIP(5);
if (!IS_BLANK_CH(RAW)) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Blank needed after '<?xml'\n"); } SKIP_BLANKS;
/* * We must have the VersionInfo here. */ version = xmlParseVersionInfo(ctxt); if (version == NULL) { xmlFatalErr(ctxt, XML_ERR_VERSION_MISSING, NULL); } else { if (!xmlStrEqual(version, (const xmlChar *) XML_DEFAULT_VERSION)) { /* * Changed here for XML-1.0 5th edition */ if (ctxt->options & XML_PARSE_OLD10) { xmlFatalErrMsgStr(ctxt, XML_ERR_UNKNOWN_VERSION, "Unsupported version '%s'\n", version); } else { if ((version[0] == '1') && ((version[1] == '.'))) { xmlWarningMsg(ctxt, XML_WAR_UNKNOWN_VERSION, "Unsupported version '%s'\n", version, NULL); } else { xmlFatalErrMsgStr(ctxt, XML_ERR_UNKNOWN_VERSION, "Unsupported version '%s'\n", version); } } } if (ctxt->version != NULL) xmlFree((void *) ctxt->version); ctxt->version = version; }
/* * We may have the encoding declaration */ if (!IS_BLANK_CH(RAW)) { if ((RAW == '?') && (NXT(1) == '>')) { SKIP(2); return; } xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Blank needed here\n"); } xmlParseEncodingDecl(ctxt); if ((ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) || (ctxt->instate == XML_PARSER_EOF)) { /* * The XML REC instructs us to stop parsing right here */ return; }
/* * We may have the standalone status. */ if ((ctxt->encoding != NULL) && (!IS_BLANK_CH(RAW))) { if ((RAW == '?') && (NXT(1) == '>')) { SKIP(2); return; } xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Blank needed here\n"); }
/* * We can grow the input buffer freely at that point */ GROW;
SKIP_BLANKS; ctxt->standalone = xmlParseSDDecl(ctxt);
SKIP_BLANKS; if ((RAW == '?') && (NXT(1) == '>')) { SKIP(2); } else if (RAW == '>') { /* Deprecated old WD ... */ xmlFatalErr(ctxt, XML_ERR_XMLDECL_NOT_FINISHED, NULL); NEXT; } else { int c;
xmlFatalErr(ctxt, XML_ERR_XMLDECL_NOT_FINISHED, NULL); while ((c = CUR) != 0) { NEXT; if (c == '>') break; } }}
/** * xmlParseMisc: * @ctxt: an XML parser context * * DEPRECATED: Internal function, don't use. * * parse an XML Misc* optional field. * * [27] Misc ::= Comment | PI | S */
voidxmlParseMisc(xmlParserCtxtPtr ctxt) { while (ctxt->instate != XML_PARSER_EOF) { SKIP_BLANKS; GROW; if ((RAW == '<') && (NXT(1) == '?')) { xmlParsePI(ctxt); } else if (CMP4(CUR_PTR, '<', '!', '-', '-')) { xmlParseComment(ctxt); } else { break; } }}
/** * xmlParseDocument: * @ctxt: an XML parser context * * parse an XML document (and build a tree if using the standard SAX * interface). * * [1] document ::= prolog element Misc* * * [22] prolog ::= XMLDecl? Misc* (doctypedecl Misc*)? * * Returns 0, -1 in case of error. the parser context is augmented * as a result of the parsing. */
intxmlParseDocument(xmlParserCtxtPtr ctxt) { xmlInitParser();
if ((ctxt == NULL) || (ctxt->input == NULL)) return(-1);
GROW;
/* * SAX: detecting the level. */ xmlDetectSAX2(ctxt);
/* * SAX: beginning of the document processing. */ if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) ctxt->sax->setDocumentLocator(ctxt->userData, &xmlDefaultSAXLocator); if (ctxt->instate == XML_PARSER_EOF) return(-1);
xmlDetectEncoding(ctxt);
if (CUR == 0) { xmlFatalErr(ctxt, XML_ERR_DOCUMENT_EMPTY, NULL); return(-1); }
GROW; if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && (IS_BLANK_CH(NXT(5)))) {
/* * Note that we will switch encoding on the fly. */ xmlParseXMLDecl(ctxt); if ((ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) || (ctxt->instate == XML_PARSER_EOF)) { /* * The XML REC instructs us to stop parsing right here */ return(-1); } SKIP_BLANKS; } else { ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION); } if ((ctxt->sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX)) ctxt->sax->startDocument(ctxt->userData); if (ctxt->instate == XML_PARSER_EOF) return(-1); if ((ctxt->myDoc != NULL) && (ctxt->input != NULL) && (ctxt->input->buf != NULL) && (ctxt->input->buf->compressed >= 0)) { ctxt->myDoc->compression = ctxt->input->buf->compressed; }
/* * The Misc part of the Prolog */ xmlParseMisc(ctxt);
/* * Then possibly doc type declaration(s) and more Misc * (doctypedecl Misc*)? */ GROW; if (CMP9(CUR_PTR, '<', '!', 'D', 'O', 'C', 'T', 'Y', 'P', 'E')) {
ctxt->inSubset = 1; xmlParseDocTypeDecl(ctxt); if (RAW == '[') { ctxt->instate = XML_PARSER_DTD; xmlParseInternalSubset(ctxt); if (ctxt->instate == XML_PARSER_EOF) return(-1); }
/* * Create and update the external subset. */ ctxt->inSubset = 2; if ((ctxt->sax != NULL) && (ctxt->sax->externalSubset != NULL) && (!ctxt->disableSAX)) ctxt->sax->externalSubset(ctxt->userData, ctxt->intSubName, ctxt->extSubSystem, ctxt->extSubURI); if (ctxt->instate == XML_PARSER_EOF) return(-1); ctxt->inSubset = 0;
xmlCleanSpecialAttr(ctxt);
ctxt->instate = XML_PARSER_PROLOG; xmlParseMisc(ctxt); }
/* * Time to start parsing the tree itself */ GROW; if (RAW != '<') { xmlFatalErrMsg(ctxt, XML_ERR_DOCUMENT_EMPTY, "Start tag expected, '<' not found\n"); } else { ctxt->instate = XML_PARSER_CONTENT; xmlParseElement(ctxt); ctxt->instate = XML_PARSER_EPILOG;
/* * The Misc part at the end */ xmlParseMisc(ctxt);
if (ctxt->input->cur < ctxt->input->end) { if (ctxt->errNo == XML_ERR_OK) xmlFatalErr(ctxt, XML_ERR_DOCUMENT_END, NULL); } else if ((ctxt->input->buf != NULL) && (ctxt->input->buf->encoder != NULL) && (!xmlBufIsEmpty(ctxt->input->buf->raw))) { xmlFatalErrMsg(ctxt, XML_ERR_INVALID_CHAR, "Truncated multi-byte sequence at EOF\n"); } ctxt->instate = XML_PARSER_EOF; }
/* * SAX: end of the document processing. */ if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) ctxt->sax->endDocument(ctxt->userData);
/* * Remove locally kept entity definitions if the tree was not built */ if ((ctxt->myDoc != NULL) && (xmlStrEqual(ctxt->myDoc->version, SAX_COMPAT_MODE))) { xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL; }
if ((ctxt->wellFormed) && (ctxt->myDoc != NULL)) { ctxt->myDoc->properties |= XML_DOC_WELLFORMED; if (ctxt->valid) ctxt->myDoc->properties |= XML_DOC_DTDVALID; if (ctxt->nsWellFormed) ctxt->myDoc->properties |= XML_DOC_NSVALID; if (ctxt->options & XML_PARSE_OLD10) ctxt->myDoc->properties |= XML_DOC_OLD10; } if (! ctxt->wellFormed) { ctxt->valid = 0; return(-1); } return(0);}
/** * xmlParseExtParsedEnt: * @ctxt: an XML parser context * * parse a general parsed entity * An external general parsed entity is well-formed if it matches the * production labeled extParsedEnt. * * [78] extParsedEnt ::= TextDecl? content * * Returns 0, -1 in case of error. the parser context is augmented * as a result of the parsing. */
intxmlParseExtParsedEnt(xmlParserCtxtPtr ctxt) { if ((ctxt == NULL) || (ctxt->input == NULL)) return(-1);
xmlDetectSAX2(ctxt);
/* * SAX: beginning of the document processing. */ if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) ctxt->sax->setDocumentLocator(ctxt->userData, &xmlDefaultSAXLocator);
xmlDetectEncoding(ctxt);
if (CUR == 0) { xmlFatalErr(ctxt, XML_ERR_DOCUMENT_EMPTY, NULL); }
/* * Check for the XMLDecl in the Prolog. */ GROW; if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && (IS_BLANK_CH(NXT(5)))) {
/* * Note that we will switch encoding on the fly. */ xmlParseXMLDecl(ctxt); if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) { /* * The XML REC instructs us to stop parsing right here */ return(-1); } SKIP_BLANKS; } else { ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION); } if ((ctxt->sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX)) ctxt->sax->startDocument(ctxt->userData); if (ctxt->instate == XML_PARSER_EOF) return(-1);
/* * Doing validity checking on chunk doesn't make sense */ ctxt->instate = XML_PARSER_CONTENT; ctxt->validate = 0; ctxt->loadsubset = 0; ctxt->depth = 0;
xmlParseContent(ctxt); if (ctxt->instate == XML_PARSER_EOF) return(-1);
if ((RAW == '<') && (NXT(1) == '/')) { xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); } else if (RAW != 0) { xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL); }
/* * SAX: end of the document processing. */ if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) ctxt->sax->endDocument(ctxt->userData);
if (! ctxt->wellFormed) return(-1); return(0);}
#ifdef LIBXML_PUSH_ENABLED/************************************************************************ * * * Progressive parsing interfaces * * * ************************************************************************/
/** * xmlParseLookupChar: * @ctxt: an XML parser context * @c: character * * Check whether the input buffer contains a character. */static intxmlParseLookupChar(xmlParserCtxtPtr ctxt, int c) { const xmlChar *cur;
if (ctxt->checkIndex == 0) { cur = ctxt->input->cur + 1; } else { cur = ctxt->input->cur + ctxt->checkIndex; }
if (memchr(cur, c, ctxt->input->end - cur) == NULL) { size_t index = ctxt->input->end - ctxt->input->cur;
if (index > LONG_MAX) { ctxt->checkIndex = 0; return(1); } ctxt->checkIndex = index; return(0); } else { ctxt->checkIndex = 0; return(1); }}
/** * xmlParseLookupString: * @ctxt: an XML parser context * @startDelta: delta to apply at the start * @str: string * @strLen: length of string * * Check whether the input buffer contains a string. */static const xmlChar *xmlParseLookupString(xmlParserCtxtPtr ctxt, size_t startDelta, const char *str, size_t strLen) { const xmlChar *cur, *term;
if (ctxt->checkIndex == 0) { cur = ctxt->input->cur + startDelta; } else { cur = ctxt->input->cur + ctxt->checkIndex; }
term = BAD_CAST strstr((const char *) cur, str); if (term == NULL) { const xmlChar *end = ctxt->input->end; size_t index;
/* Rescan (strLen - 1) characters. */ if ((size_t) (end - cur) < strLen) end = cur; else end -= strLen - 1; index = end - ctxt->input->cur; if (index > LONG_MAX) { ctxt->checkIndex = 0; return(ctxt->input->end - strLen); } ctxt->checkIndex = index; } else { ctxt->checkIndex = 0; }
return(term);}
/** * xmlParseLookupCharData: * @ctxt: an XML parser context * * Check whether the input buffer contains terminated char data. */static intxmlParseLookupCharData(xmlParserCtxtPtr ctxt) { const xmlChar *cur = ctxt->input->cur + ctxt->checkIndex; const xmlChar *end = ctxt->input->end; size_t index;
while (cur < end) { if ((*cur == '<') || (*cur == '&')) { ctxt->checkIndex = 0; return(1); } cur++; }
index = cur - ctxt->input->cur; if (index > LONG_MAX) { ctxt->checkIndex = 0; return(1); } ctxt->checkIndex = index; return(0);}
/** * xmlParseLookupGt: * @ctxt: an XML parser context * * Check whether there's enough data in the input buffer to finish parsing * a start tag. This has to take quotes into account. */static intxmlParseLookupGt(xmlParserCtxtPtr ctxt) { const xmlChar *cur; const xmlChar *end = ctxt->input->end; int state = ctxt->endCheckState; size_t index;
if (ctxt->checkIndex == 0) cur = ctxt->input->cur + 1; else cur = ctxt->input->cur + ctxt->checkIndex;
while (cur < end) { if (state) { if (*cur == state) state = 0; } else if (*cur == '\'' || *cur == '"') { state = *cur; } else if (*cur == '>') { ctxt->checkIndex = 0; ctxt->endCheckState = 0; return(1); } cur++; }
index = cur - ctxt->input->cur; if (index > LONG_MAX) { ctxt->checkIndex = 0; ctxt->endCheckState = 0; return(1); } ctxt->checkIndex = index; ctxt->endCheckState = state; return(0);}
/** * xmlParseLookupInternalSubset: * @ctxt: an XML parser context * * Check whether there's enough data in the input buffer to finish parsing * the internal subset. */static intxmlParseLookupInternalSubset(xmlParserCtxtPtr ctxt) { /* * Sorry, but progressive parsing of the internal subset is not * supported. We first check that the full content of the internal * subset is available and parsing is launched only at that point. * Internal subset ends with "']' S? '>'" in an unescaped section and * not in a ']]>' sequence which are conditional sections. */ const xmlChar *cur, *start; const xmlChar *end = ctxt->input->end; int state = ctxt->endCheckState; size_t index;
if (ctxt->checkIndex == 0) { cur = ctxt->input->cur + 1; } else { cur = ctxt->input->cur + ctxt->checkIndex; } start = cur;
while (cur < end) { if (state == '-') { if ((*cur == '-') && (cur[1] == '-') && (cur[2] == '>')) { state = 0; cur += 3; start = cur; continue; } } else if (state == ']') { if (*cur == '>') { ctxt->checkIndex = 0; ctxt->endCheckState = 0; return(1); } if (IS_BLANK_CH(*cur)) { state = ' '; } else if (*cur != ']') { state = 0; start = cur; continue; } } else if (state == ' ') { if (*cur == '>') { ctxt->checkIndex = 0; ctxt->endCheckState = 0; return(1); } if (!IS_BLANK_CH(*cur)) { state = 0; start = cur; continue; } } else if (state != 0) { if (*cur == state) { state = 0; start = cur + 1; } } else if (*cur == '<') { if ((cur[1] == '!') && (cur[2] == '-') && (cur[3] == '-')) { state = '-'; cur += 4; /* Don't treat <!--> as comment */ start = cur; continue; } } else if ((*cur == '"') || (*cur == '\'') || (*cur == ']')) { state = *cur; }
cur++; }
/* * Rescan the three last characters to detect "<!--" and "-->" * split across chunks. */ if ((state == 0) || (state == '-')) { if (cur - start < 3) cur = start; else cur -= 3; } index = cur - ctxt->input->cur; if (index > LONG_MAX) { ctxt->checkIndex = 0; ctxt->endCheckState = 0; return(1); } ctxt->checkIndex = index; ctxt->endCheckState = state; return(0);}
/** * xmlCheckCdataPush: * @cur: pointer to the block of characters * @len: length of the block in bytes * @complete: 1 if complete CDATA block is passed in, 0 if partial block * * Check that the block of characters is okay as SCdata content [20] * * Returns the number of bytes to pass if okay, a negative index where an * UTF-8 error occurred otherwise */static intxmlCheckCdataPush(const xmlChar *utf, int len, int complete) { int ix; unsigned char c; int codepoint;
if ((utf == NULL) || (len <= 0)) return(0);
for (ix = 0; ix < len;) { /* string is 0-terminated */ c = utf[ix]; if ((c & 0x80) == 0x00) { /* 1-byte code, starts with 10 */ if (c >= 0x20) ix++; else if ((c == 0xA) || (c == 0xD) || (c == 0x9)) ix++; else return(-ix); } else if ((c & 0xe0) == 0xc0) {/* 2-byte code, starts with 110 */ if (ix + 2 > len) return(complete ? -ix : ix); if ((utf[ix+1] & 0xc0 ) != 0x80) return(-ix); codepoint = (utf[ix] & 0x1f) << 6; codepoint |= utf[ix+1] & 0x3f; if (!xmlIsCharQ(codepoint)) return(-ix); ix += 2; } else if ((c & 0xf0) == 0xe0) {/* 3-byte code, starts with 1110 */ if (ix + 3 > len) return(complete ? -ix : ix); if (((utf[ix+1] & 0xc0) != 0x80) || ((utf[ix+2] & 0xc0) != 0x80)) return(-ix); codepoint = (utf[ix] & 0xf) << 12; codepoint |= (utf[ix+1] & 0x3f) << 6; codepoint |= utf[ix+2] & 0x3f; if (!xmlIsCharQ(codepoint)) return(-ix); ix += 3; } else if ((c & 0xf8) == 0xf0) {/* 4-byte code, starts with 11110 */ if (ix + 4 > len) return(complete ? -ix : ix); if (((utf[ix+1] & 0xc0) != 0x80) || ((utf[ix+2] & 0xc0) != 0x80) || ((utf[ix+3] & 0xc0) != 0x80)) return(-ix); codepoint = (utf[ix] & 0x7) << 18; codepoint |= (utf[ix+1] & 0x3f) << 12; codepoint |= (utf[ix+2] & 0x3f) << 6; codepoint |= utf[ix+3] & 0x3f; if (!xmlIsCharQ(codepoint)) return(-ix); ix += 4; } else /* unknown encoding */ return(-ix); } return(ix);}
/** * xmlParseTryOrFinish: * @ctxt: an XML parser context * @terminate: last chunk indicator * * Try to progress on parsing * * Returns zero if no parsing was possible */static intxmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { int ret = 0; size_t avail; xmlChar cur, next;
if (ctxt->input == NULL) return(0);
if ((ctxt->input != NULL) && (ctxt->input->cur - ctxt->input->base > 4096)) { xmlParserShrink(ctxt); }
while (ctxt->instate != XML_PARSER_EOF) { if ((ctxt->errNo != XML_ERR_OK) && (ctxt->disableSAX == 1)) return(0);
avail = ctxt->input->end - ctxt->input->cur; if (avail < 1) goto done; switch (ctxt->instate) { case XML_PARSER_EOF: /* * Document parsing is done ! */ goto done; case XML_PARSER_START: /* * Very first chars read from the document flow. */ if ((!terminate) && (avail < 4)) goto done;
/* * We need more bytes to detect EBCDIC code pages. * See xmlDetectEBCDIC. */ if ((CMP4(CUR_PTR, 0x4C, 0x6F, 0xA7, 0x94)) && (!terminate) && (avail < 200)) goto done;
xmlDetectEncoding(ctxt); if (ctxt->instate == XML_PARSER_EOF) goto done; ctxt->instate = XML_PARSER_XML_DECL; break;
case XML_PARSER_XML_DECL: if ((!terminate) && (avail < 2)) goto done; cur = ctxt->input->cur[0]; next = ctxt->input->cur[1]; if ((cur == '<') && (next == '?')) { /* PI or XML decl */ if ((!terminate) && (!xmlParseLookupString(ctxt, 2, "?>", 2))) goto done; if ((ctxt->input->cur[2] == 'x') && (ctxt->input->cur[3] == 'm') && (ctxt->input->cur[4] == 'l') && (IS_BLANK_CH(ctxt->input->cur[5]))) { ret += 5; xmlParseXMLDecl(ctxt); if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) { /* * The XML REC instructs us to stop parsing right * here */ xmlHaltParser(ctxt); return(0); } } else { ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION); } } else { ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION); if (ctxt->version == NULL) { xmlErrMemory(ctxt, NULL); break; } } if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) ctxt->sax->setDocumentLocator(ctxt->userData, &xmlDefaultSAXLocator); if ((ctxt->sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX)) ctxt->sax->startDocument(ctxt->userData); if (ctxt->instate == XML_PARSER_EOF) goto done; ctxt->instate = XML_PARSER_MISC; break; case XML_PARSER_START_TAG: { const xmlChar *name; const xmlChar *prefix = NULL; const xmlChar *URI = NULL; int line = ctxt->input->line; int nbNs = 0;
if ((!terminate) && (avail < 2)) goto done; cur = ctxt->input->cur[0]; if (cur != '<') { xmlFatalErrMsg(ctxt, XML_ERR_DOCUMENT_EMPTY, "Start tag expected, '<' not found"); xmlHaltParser(ctxt); if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) ctxt->sax->endDocument(ctxt->userData); goto done; } if ((!terminate) && (!xmlParseLookupGt(ctxt))) goto done; if (ctxt->spaceNr == 0) spacePush(ctxt, -1); else if (*ctxt->space == -2) spacePush(ctxt, -1); else spacePush(ctxt, *ctxt->space);#ifdef LIBXML_SAX1_ENABLED if (ctxt->sax2)#endif /* LIBXML_SAX1_ENABLED */ name = xmlParseStartTag2(ctxt, &prefix, &URI, &nbNs);#ifdef LIBXML_SAX1_ENABLED else name = xmlParseStartTag(ctxt);#endif /* LIBXML_SAX1_ENABLED */ if (ctxt->instate == XML_PARSER_EOF) goto done; if (name == NULL) { spacePop(ctxt); xmlHaltParser(ctxt); if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) ctxt->sax->endDocument(ctxt->userData); goto done; }#ifdef LIBXML_VALID_ENABLED /* * [ VC: Root Element Type ] * The Name in the document type declaration must match * the element type of the root element. */ if (ctxt->validate && ctxt->wellFormed && ctxt->myDoc && ctxt->node && (ctxt->node == ctxt->myDoc->children)) ctxt->valid &= xmlValidateRoot(&ctxt->vctxt, ctxt->myDoc);#endif /* LIBXML_VALID_ENABLED */
/* * Check for an Empty Element. */ if ((RAW == '/') && (NXT(1) == '>')) { SKIP(2);
if (ctxt->sax2) { if ((ctxt->sax != NULL) && (ctxt->sax->endElementNs != NULL) && (!ctxt->disableSAX)) ctxt->sax->endElementNs(ctxt->userData, name, prefix, URI); if (nbNs > 0) xmlParserNsPop(ctxt, nbNs);#ifdef LIBXML_SAX1_ENABLED } else { if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL) && (!ctxt->disableSAX)) ctxt->sax->endElement(ctxt->userData, name);#endif /* LIBXML_SAX1_ENABLED */ } spacePop(ctxt); } else if (RAW == '>') { NEXT; nameNsPush(ctxt, name, prefix, URI, line, nbNs); } else { xmlFatalErrMsgStr(ctxt, XML_ERR_GT_REQUIRED, "Couldn't find end of Start Tag %s\n", name); nodePop(ctxt); spacePop(ctxt); if (nbNs > 0) xmlParserNsPop(ctxt, nbNs); }
if (ctxt->instate == XML_PARSER_EOF) goto done; if (ctxt->nameNr == 0) ctxt->instate = XML_PARSER_EPILOG; else ctxt->instate = XML_PARSER_CONTENT; break; } case XML_PARSER_CONTENT: { cur = ctxt->input->cur[0];
if (cur == '<') { if ((!terminate) && (avail < 2)) goto done; next = ctxt->input->cur[1];
if (next == '/') { ctxt->instate = XML_PARSER_END_TAG; break; } else if (next == '?') { if ((!terminate) && (!xmlParseLookupString(ctxt, 2, "?>", 2))) goto done; xmlParsePI(ctxt); if (ctxt->instate == XML_PARSER_EOF) goto done; ctxt->instate = XML_PARSER_CONTENT; break; } else if (next == '!') { if ((!terminate) && (avail < 3)) goto done; next = ctxt->input->cur[2];
if (next == '-') { if ((!terminate) && (avail < 4)) goto done; if (ctxt->input->cur[3] == '-') { if ((!terminate) && (!xmlParseLookupString(ctxt, 4, "-->", 3))) goto done; xmlParseComment(ctxt); if (ctxt->instate == XML_PARSER_EOF) goto done; ctxt->instate = XML_PARSER_CONTENT; break; } } else if (next == '[') { if ((!terminate) && (avail < 9)) goto done; if ((ctxt->input->cur[2] == '[') && (ctxt->input->cur[3] == 'C') && (ctxt->input->cur[4] == 'D') && (ctxt->input->cur[5] == 'A') && (ctxt->input->cur[6] == 'T') && (ctxt->input->cur[7] == 'A') && (ctxt->input->cur[8] == '[')) { SKIP(9); ctxt->instate = XML_PARSER_CDATA_SECTION; break; } } } } else if (cur == '&') { if ((!terminate) && (!xmlParseLookupChar(ctxt, ';'))) goto done; xmlParseReference(ctxt); break; } else { /* TODO Avoid the extra copy, handle directly !!! */ /* * Goal of the following test is: * - minimize calls to the SAX 'character' callback * when they are mergeable * - handle an problem for isBlank when we only parse * a sequence of blank chars and the next one is * not available to check against '<' presence. * - tries to homogenize the differences in SAX * callbacks between the push and pull versions * of the parser. */ if (avail < XML_PARSER_BIG_BUFFER_SIZE) { if ((!terminate) && (!xmlParseLookupCharData(ctxt))) goto done; } ctxt->checkIndex = 0; xmlParseCharDataInternal(ctxt, !terminate); break; }
ctxt->instate = XML_PARSER_START_TAG; break; } case XML_PARSER_END_TAG: if ((!terminate) && (!xmlParseLookupChar(ctxt, '>'))) goto done; if (ctxt->sax2) { xmlParseEndTag2(ctxt, &ctxt->pushTab[ctxt->nameNr - 1]); nameNsPop(ctxt); }#ifdef LIBXML_SAX1_ENABLED else xmlParseEndTag1(ctxt, 0);#endif /* LIBXML_SAX1_ENABLED */ if (ctxt->instate == XML_PARSER_EOF) goto done; if (ctxt->nameNr == 0) { ctxt->instate = XML_PARSER_EPILOG; } else { ctxt->instate = XML_PARSER_CONTENT; } break; case XML_PARSER_CDATA_SECTION: { /* * The Push mode need to have the SAX callback for * cdataBlock merge back contiguous callbacks. */ const xmlChar *term;
if (terminate) { /* * Don't call xmlParseLookupString. If 'terminate' * is set, checkIndex is invalid. */ term = BAD_CAST strstr((const char *) ctxt->input->cur, "]]>"); } else { term = xmlParseLookupString(ctxt, 0, "]]>", 3); }
if (term == NULL) { int tmp, size;
if (terminate) { /* Unfinished CDATA section */ size = ctxt->input->end - ctxt->input->cur; } else { if (avail < XML_PARSER_BIG_BUFFER_SIZE + 2) goto done; ctxt->checkIndex = 0; /* XXX: Why don't we pass the full buffer? */ size = XML_PARSER_BIG_BUFFER_SIZE; } tmp = xmlCheckCdataPush(ctxt->input->cur, size, 0); if (tmp <= 0) { tmp = -tmp; ctxt->input->cur += tmp; goto encoding_error; } if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) { if (ctxt->sax->cdataBlock != NULL) ctxt->sax->cdataBlock(ctxt->userData, ctxt->input->cur, tmp); else if (ctxt->sax->characters != NULL) ctxt->sax->characters(ctxt->userData, ctxt->input->cur, tmp); } if (ctxt->instate == XML_PARSER_EOF) goto done; SKIPL(tmp); } else { int base = term - CUR_PTR; int tmp;
tmp = xmlCheckCdataPush(ctxt->input->cur, base, 1); if ((tmp < 0) || (tmp != base)) { tmp = -tmp; ctxt->input->cur += tmp; goto encoding_error; } if ((ctxt->sax != NULL) && (base == 0) && (ctxt->sax->cdataBlock != NULL) && (!ctxt->disableSAX)) { /* * Special case to provide identical behaviour * between pull and push parsers on enpty CDATA * sections */ if ((ctxt->input->cur - ctxt->input->base >= 9) && (!strncmp((const char *)&ctxt->input->cur[-9], "<![CDATA[", 9))) ctxt->sax->cdataBlock(ctxt->userData, BAD_CAST "", 0); } else if ((ctxt->sax != NULL) && (base > 0) && (!ctxt->disableSAX)) { if (ctxt->sax->cdataBlock != NULL) ctxt->sax->cdataBlock(ctxt->userData, ctxt->input->cur, base); else if (ctxt->sax->characters != NULL) ctxt->sax->characters(ctxt->userData, ctxt->input->cur, base); } if (ctxt->instate == XML_PARSER_EOF) goto done; SKIPL(base + 3); ctxt->instate = XML_PARSER_CONTENT; } break; } case XML_PARSER_MISC: case XML_PARSER_PROLOG: case XML_PARSER_EPILOG: SKIP_BLANKS; avail = ctxt->input->end - ctxt->input->cur; if (avail < 1) goto done; if (ctxt->input->cur[0] == '<') { if ((!terminate) && (avail < 2)) goto done; next = ctxt->input->cur[1]; if (next == '?') { if ((!terminate) && (!xmlParseLookupString(ctxt, 2, "?>", 2))) goto done; xmlParsePI(ctxt); if (ctxt->instate == XML_PARSER_EOF) goto done; break; } else if (next == '!') { if ((!terminate) && (avail < 3)) goto done;
if (ctxt->input->cur[2] == '-') { if ((!terminate) && (avail < 4)) goto done; if (ctxt->input->cur[3] == '-') { if ((!terminate) && (!xmlParseLookupString(ctxt, 4, "-->", 3))) goto done; xmlParseComment(ctxt); if (ctxt->instate == XML_PARSER_EOF) goto done; break; } } else if (ctxt->instate == XML_PARSER_MISC) { if ((!terminate) && (avail < 9)) goto done; if ((ctxt->input->cur[2] == 'D') && (ctxt->input->cur[3] == 'O') && (ctxt->input->cur[4] == 'C') && (ctxt->input->cur[5] == 'T') && (ctxt->input->cur[6] == 'Y') && (ctxt->input->cur[7] == 'P') && (ctxt->input->cur[8] == 'E')) { if ((!terminate) && (!xmlParseLookupGt(ctxt))) goto done; ctxt->inSubset = 1; xmlParseDocTypeDecl(ctxt); if (ctxt->instate == XML_PARSER_EOF) goto done; if (RAW == '[') { ctxt->instate = XML_PARSER_DTD; } else { /* * Create and update the external subset. */ ctxt->inSubset = 2; if ((ctxt->sax != NULL) && (!ctxt->disableSAX) && (ctxt->sax->externalSubset != NULL)) ctxt->sax->externalSubset( ctxt->userData, ctxt->intSubName, ctxt->extSubSystem, ctxt->extSubURI); ctxt->inSubset = 0; xmlCleanSpecialAttr(ctxt); if (ctxt->instate == XML_PARSER_EOF) goto done; ctxt->instate = XML_PARSER_PROLOG; } break; } } } }
if (ctxt->instate == XML_PARSER_EPILOG) { if (ctxt->errNo == XML_ERR_OK) xmlFatalErr(ctxt, XML_ERR_DOCUMENT_END, NULL); ctxt->instate = XML_PARSER_EOF; if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) ctxt->sax->endDocument(ctxt->userData); } else { ctxt->instate = XML_PARSER_START_TAG; } break; case XML_PARSER_DTD: { if ((!terminate) && (!xmlParseLookupInternalSubset(ctxt))) goto done; xmlParseInternalSubset(ctxt); if (ctxt->instate == XML_PARSER_EOF) goto done; ctxt->inSubset = 2; if ((ctxt->sax != NULL) && (!ctxt->disableSAX) && (ctxt->sax->externalSubset != NULL)) ctxt->sax->externalSubset(ctxt->userData, ctxt->intSubName, ctxt->extSubSystem, ctxt->extSubURI); ctxt->inSubset = 0; xmlCleanSpecialAttr(ctxt); if (ctxt->instate == XML_PARSER_EOF) goto done; ctxt->instate = XML_PARSER_PROLOG; break; } default: xmlGenericError(xmlGenericErrorContext, "PP: internal error\n"); ctxt->instate = XML_PARSER_EOF; break; } }done: return(ret);encoding_error: if (ctxt->input->end - ctxt->input->cur < 4) { __xmlErrEncoding(ctxt, XML_ERR_INVALID_CHAR, "Input is not proper UTF-8, indicate encoding !\n", NULL, NULL); } else { char buffer[150];
snprintf(buffer, 149, "Bytes: 0x%02X 0x%02X 0x%02X 0x%02X\n", ctxt->input->cur[0], ctxt->input->cur[1], ctxt->input->cur[2], ctxt->input->cur[3]); __xmlErrEncoding(ctxt, XML_ERR_INVALID_CHAR, "Input is not proper UTF-8, indicate encoding !\n%s", BAD_CAST buffer, NULL); } return(0);}
/** * xmlParseChunk: * @ctxt: an XML parser context * @chunk: an char array * @size: the size in byte of the chunk * @terminate: last chunk indicator * * Parse a Chunk of memory * * Returns zero if no error, the xmlParserErrors otherwise. */intxmlParseChunk(xmlParserCtxtPtr ctxt, const char *chunk, int size, int terminate) { int end_in_lf = 0;
if (ctxt == NULL) return(XML_ERR_INTERNAL_ERROR); if ((ctxt->errNo != XML_ERR_OK) && (ctxt->disableSAX == 1)) return(ctxt->errNo); if (ctxt->instate == XML_PARSER_EOF) return(-1); if (ctxt->input == NULL) return(-1);
ctxt->progressive = 1; if (ctxt->instate == XML_PARSER_START) xmlDetectSAX2(ctxt); if ((size > 0) && (chunk != NULL) && (!terminate) && (chunk[size - 1] == '\r')) { end_in_lf = 1; size--; }
if ((size > 0) && (chunk != NULL) && (ctxt->input != NULL) && (ctxt->input->buf != NULL) && (ctxt->instate != XML_PARSER_EOF)) { size_t pos = ctxt->input->cur - ctxt->input->base; int res;
res = xmlParserInputBufferPush(ctxt->input->buf, size, chunk); xmlBufUpdateInput(ctxt->input->buf->buffer, ctxt->input, pos); if (res < 0) { xmlFatalErr(ctxt, ctxt->input->buf->error, NULL); xmlHaltParser(ctxt); return(ctxt->errNo); } }
xmlParseTryOrFinish(ctxt, terminate); if (ctxt->instate == XML_PARSER_EOF) return(ctxt->errNo);
if ((ctxt->input != NULL) && (((ctxt->input->end - ctxt->input->cur) > XML_MAX_LOOKUP_LIMIT) || ((ctxt->input->cur - ctxt->input->base) > XML_MAX_LOOKUP_LIMIT)) && ((ctxt->options & XML_PARSE_HUGE) == 0)) { xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, "Huge input lookup"); xmlHaltParser(ctxt); } if ((ctxt->errNo != XML_ERR_OK) && (ctxt->disableSAX == 1)) return(ctxt->errNo);
if ((end_in_lf == 1) && (ctxt->input != NULL) && (ctxt->input->buf != NULL)) { size_t pos = ctxt->input->cur - ctxt->input->base; int res;
res = xmlParserInputBufferPush(ctxt->input->buf, 1, "\r"); xmlBufUpdateInput(ctxt->input->buf->buffer, ctxt->input, pos); if (res < 0) { xmlFatalErr(ctxt, ctxt->input->buf->error, NULL); xmlHaltParser(ctxt); return(ctxt->errNo); } } if (terminate) { /* * Check for termination */ if ((ctxt->instate != XML_PARSER_EOF) && (ctxt->instate != XML_PARSER_EPILOG)) { if (ctxt->nameNr > 0) { const xmlChar *name = ctxt->nameTab[ctxt->nameNr - 1]; int line = ctxt->pushTab[ctxt->nameNr - 1].line; xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED, "Premature end of data in tag %s line %d\n", name, line, NULL); } else if (ctxt->instate == XML_PARSER_START) { xmlFatalErr(ctxt, XML_ERR_DOCUMENT_EMPTY, NULL); } else { xmlFatalErrMsg(ctxt, XML_ERR_DOCUMENT_EMPTY, "Start tag expected, '<' not found\n"); } } else if ((ctxt->input->buf != NULL) && (ctxt->input->buf->encoder != NULL) && (!xmlBufIsEmpty(ctxt->input->buf->raw))) { xmlFatalErrMsg(ctxt, XML_ERR_INVALID_CHAR, "Truncated multi-byte sequence at EOF\n"); } if (ctxt->instate != XML_PARSER_EOF) { if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) ctxt->sax->endDocument(ctxt->userData); } ctxt->instate = XML_PARSER_EOF; } if (ctxt->wellFormed == 0) return((xmlParserErrors) ctxt->errNo); else return(0);}
/************************************************************************ * * * I/O front end functions to the parser * * * ************************************************************************/
/** * xmlCreatePushParserCtxt: * @sax: a SAX handler * @user_data: The user data returned on SAX callbacks * @chunk: a pointer to an array of chars * @size: number of chars in the array * @filename: an optional file name or URI * * Create a parser context for using the XML parser in push mode. * If @buffer and @size are non-NULL, the data is used to detect * the encoding. The remaining characters will be parsed so they * don't need to be fed in again through xmlParseChunk. * To allow content encoding detection, @size should be >= 4 * The value of @filename is used for fetching external entities * and error/warning reports. * * Returns the new parser context or NULL */
xmlParserCtxtPtrxmlCreatePushParserCtxt(xmlSAXHandlerPtr sax, void *user_data, const char *chunk, int size, const char *filename) { xmlParserCtxtPtr ctxt; xmlParserInputPtr inputStream; xmlParserInputBufferPtr buf;
buf = xmlAllocParserInputBuffer(XML_CHAR_ENCODING_NONE); if (buf == NULL) return(NULL);
ctxt = xmlNewSAXParserCtxt(sax, user_data); if (ctxt == NULL) { xmlErrMemory(NULL, "creating parser: out of memory\n"); xmlFreeParserInputBuffer(buf); return(NULL); } ctxt->dictNames = 1; if (filename == NULL) { ctxt->directory = NULL; } else { ctxt->directory = xmlParserGetDirectory(filename); }
inputStream = xmlNewInputStream(ctxt); if (inputStream == NULL) { xmlFreeParserCtxt(ctxt); xmlFreeParserInputBuffer(buf); return(NULL); }
if (filename == NULL) inputStream->filename = NULL; else { inputStream->filename = (char *) xmlCanonicPath((const xmlChar *) filename); if (inputStream->filename == NULL) { xmlFreeInputStream(inputStream); xmlFreeParserCtxt(ctxt); xmlFreeParserInputBuffer(buf); return(NULL); } } inputStream->buf = buf; xmlBufResetInput(inputStream->buf->buffer, inputStream); inputPush(ctxt, inputStream);
if ((size != 0) && (chunk != NULL) && (ctxt->input != NULL) && (ctxt->input->buf != NULL)) { size_t pos = ctxt->input->cur - ctxt->input->base; int res;
res = xmlParserInputBufferPush(ctxt->input->buf, size, chunk); xmlBufUpdateInput(ctxt->input->buf->buffer, ctxt->input, pos); if (res < 0) { xmlFatalErr(ctxt, ctxt->input->buf->error, NULL); xmlHaltParser(ctxt); } }
return(ctxt);}#endif /* LIBXML_PUSH_ENABLED */
/** * xmlStopParser: * @ctxt: an XML parser context * * Blocks further parser processing */voidxmlStopParser(xmlParserCtxtPtr ctxt) { if (ctxt == NULL) return; xmlHaltParser(ctxt); ctxt->errNo = XML_ERR_USER_STOP;}
/** * xmlCreateIOParserCtxt: * @sax: a SAX handler * @user_data: The user data returned on SAX callbacks * @ioread: an I/O read function * @ioclose: an I/O close function * @ioctx: an I/O handler * @enc: the charset encoding if known * * Create a parser context for using the XML parser with an existing * I/O stream * * Returns the new parser context or NULL */xmlParserCtxtPtrxmlCreateIOParserCtxt(xmlSAXHandlerPtr sax, void *user_data, xmlInputReadCallback ioread, xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) { xmlParserCtxtPtr ctxt; xmlParserInputPtr inputStream; xmlParserInputBufferPtr buf;
if (ioread == NULL) return(NULL);
buf = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx, enc); if (buf == NULL) { if (ioclose != NULL) ioclose(ioctx); return (NULL); }
ctxt = xmlNewSAXParserCtxt(sax, user_data); if (ctxt == NULL) { xmlFreeParserInputBuffer(buf); return(NULL); }
inputStream = xmlNewIOInputStream(ctxt, buf, enc); if (inputStream == NULL) { xmlFreeParserCtxt(ctxt); return(NULL); } inputPush(ctxt, inputStream);
return(ctxt);}
#ifdef LIBXML_VALID_ENABLED/************************************************************************ * * * Front ends when parsing a DTD * * * ************************************************************************/
/** * xmlIOParseDTD: * @sax: the SAX handler block or NULL * @input: an Input Buffer * @enc: the charset encoding if known * * Load and parse a DTD * * Returns the resulting xmlDtdPtr or NULL in case of error. * @input will be freed by the function in any case. */
xmlDtdPtrxmlIOParseDTD(xmlSAXHandlerPtr sax, xmlParserInputBufferPtr input, xmlCharEncoding enc) { xmlDtdPtr ret = NULL; xmlParserCtxtPtr ctxt; xmlParserInputPtr pinput = NULL;
if (input == NULL) return(NULL);
ctxt = xmlNewSAXParserCtxt(sax, NULL); if (ctxt == NULL) { xmlFreeParserInputBuffer(input); return(NULL); }
/* We are loading a DTD */ ctxt->options |= XML_PARSE_DTDLOAD;
xmlDetectSAX2(ctxt);
/* * generate a parser input from the I/O handler */
pinput = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); if (pinput == NULL) { xmlFreeParserInputBuffer(input); xmlFreeParserCtxt(ctxt); return(NULL); }
/* * plug some encoding conversion routines here. */ if (xmlPushInput(ctxt, pinput) < 0) { xmlFreeParserCtxt(ctxt); return(NULL); } if (enc != XML_CHAR_ENCODING_NONE) { xmlSwitchEncoding(ctxt, enc); }
/* * let's parse that entity knowing it's an external subset. */ ctxt->inSubset = 2; ctxt->myDoc = xmlNewDoc(BAD_CAST "1.0"); if (ctxt->myDoc == NULL) { xmlErrMemory(ctxt, "New Doc failed"); return(NULL); } ctxt->myDoc->properties = XML_DOC_INTERNAL; ctxt->myDoc->extSubset = xmlNewDtd(ctxt->myDoc, BAD_CAST "none", BAD_CAST "none", BAD_CAST "none");
xmlDetectEncoding(ctxt);
xmlParseExternalSubset(ctxt, BAD_CAST "none", BAD_CAST "none");
if (ctxt->myDoc != NULL) { if (ctxt->wellFormed) { ret = ctxt->myDoc->extSubset; ctxt->myDoc->extSubset = NULL; if (ret != NULL) { xmlNodePtr tmp;
ret->doc = NULL; tmp = ret->children; while (tmp != NULL) { tmp->doc = NULL; tmp = tmp->next; } } } else { ret = NULL; } xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL; } xmlFreeParserCtxt(ctxt);
return(ret);}
/** * xmlSAXParseDTD: * @sax: the SAX handler block * @ExternalID: a NAME* containing the External ID of the DTD * @SystemID: a NAME* containing the URL to the DTD * * DEPRECATED: Don't use. * * Load and parse an external subset. * * Returns the resulting xmlDtdPtr or NULL in case of error. */
xmlDtdPtrxmlSAXParseDTD(xmlSAXHandlerPtr sax, const xmlChar *ExternalID, const xmlChar *SystemID) { xmlDtdPtr ret = NULL; xmlParserCtxtPtr ctxt; xmlParserInputPtr input = NULL; xmlChar* systemIdCanonic;
if ((ExternalID == NULL) && (SystemID == NULL)) return(NULL);
ctxt = xmlNewSAXParserCtxt(sax, NULL); if (ctxt == NULL) { return(NULL); }
/* We are loading a DTD */ ctxt->options |= XML_PARSE_DTDLOAD;
/* * Canonicalise the system ID */ systemIdCanonic = xmlCanonicPath(SystemID); if ((SystemID != NULL) && (systemIdCanonic == NULL)) { xmlFreeParserCtxt(ctxt); return(NULL); }
/* * Ask the Entity resolver to load the damn thing */
if ((ctxt->sax != NULL) && (ctxt->sax->resolveEntity != NULL)) input = ctxt->sax->resolveEntity(ctxt->userData, ExternalID, systemIdCanonic); if (input == NULL) { xmlFreeParserCtxt(ctxt); if (systemIdCanonic != NULL) xmlFree(systemIdCanonic); return(NULL); }
/* * plug some encoding conversion routines here. */ if (xmlPushInput(ctxt, input) < 0) { xmlFreeParserCtxt(ctxt); if (systemIdCanonic != NULL) xmlFree(systemIdCanonic); return(NULL); }
xmlDetectEncoding(ctxt);
if (input->filename == NULL) input->filename = (char *) systemIdCanonic; else xmlFree(systemIdCanonic);
/* * let's parse that entity knowing it's an external subset. */ ctxt->inSubset = 2; ctxt->myDoc = xmlNewDoc(BAD_CAST "1.0"); if (ctxt->myDoc == NULL) { xmlErrMemory(ctxt, "New Doc failed"); xmlFreeParserCtxt(ctxt); return(NULL); } ctxt->myDoc->properties = XML_DOC_INTERNAL; ctxt->myDoc->extSubset = xmlNewDtd(ctxt->myDoc, BAD_CAST "none", ExternalID, SystemID); xmlParseExternalSubset(ctxt, ExternalID, SystemID);
if (ctxt->myDoc != NULL) { if (ctxt->wellFormed) { ret = ctxt->myDoc->extSubset; ctxt->myDoc->extSubset = NULL; if (ret != NULL) { xmlNodePtr tmp;
ret->doc = NULL; tmp = ret->children; while (tmp != NULL) { tmp->doc = NULL; tmp = tmp->next; } } } else { ret = NULL; } xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL; } xmlFreeParserCtxt(ctxt);
return(ret);}
/** * xmlParseDTD: * @ExternalID: a NAME* containing the External ID of the DTD * @SystemID: a NAME* containing the URL to the DTD * * Load and parse an external subset. * * Returns the resulting xmlDtdPtr or NULL in case of error. */
xmlDtdPtrxmlParseDTD(const xmlChar *ExternalID, const xmlChar *SystemID) { return(xmlSAXParseDTD(NULL, ExternalID, SystemID));}#endif /* LIBXML_VALID_ENABLED */
/************************************************************************ * * * Front ends when parsing an Entity * * * ************************************************************************/
/** * xmlParseCtxtExternalEntity: * @ctx: the existing parsing context * @URL: the URL for the entity to load * @ID: the System ID for the entity to load * @lst: the return value for the set of parsed nodes * * Parse an external general entity within an existing parsing context * An external general parsed entity is well-formed if it matches the * production labeled extParsedEnt. * * [78] extParsedEnt ::= TextDecl? content * * Returns 0 if the entity is well formed, -1 in case of args problem and * the parser error code otherwise */
intxmlParseCtxtExternalEntity(xmlParserCtxtPtr ctx, const xmlChar *URL, const xmlChar *ID, xmlNodePtr *lst) { void *userData;
if (ctx == NULL) return(-1); /* * If the user provided their own SAX callbacks, then reuse the * userData callback field, otherwise the expected setup in a * DOM builder is to have userData == ctxt */ if (ctx->userData == ctx) userData = NULL; else userData = ctx->userData; return xmlParseExternalEntityPrivate(ctx->myDoc, ctx, ctx->sax, userData, ctx->depth + 1, URL, ID, lst);}
/** * xmlParseExternalEntityPrivate: * @doc: the document the chunk pertains to * @oldctxt: the previous parser context if available * @sax: the SAX handler block (possibly NULL) * @user_data: The user data returned on SAX callbacks (possibly NULL) * @depth: Used for loop detection, use 0 * @URL: the URL for the entity to load * @ID: the System ID for the entity to load * @list: the return value for the set of parsed nodes * * Private version of xmlParseExternalEntity() * * Returns 0 if the entity is well formed, -1 in case of args problem and * the parser error code otherwise */
static xmlParserErrorsxmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt, xmlSAXHandlerPtr sax, void *user_data, int depth, const xmlChar *URL, const xmlChar *ID, xmlNodePtr *list) { xmlParserCtxtPtr ctxt; xmlDocPtr newDoc; xmlNodePtr newRoot; xmlParserErrors ret = XML_ERR_OK;
if (((depth > 40) && ((oldctxt == NULL) || (oldctxt->options & XML_PARSE_HUGE) == 0)) || (depth > 100)) { xmlFatalErrMsg(oldctxt, XML_ERR_ENTITY_LOOP, "Maximum entity nesting depth exceeded"); return(XML_ERR_ENTITY_LOOP); }
if (list != NULL) *list = NULL; if ((URL == NULL) && (ID == NULL)) return(XML_ERR_INTERNAL_ERROR); if (doc == NULL) return(XML_ERR_INTERNAL_ERROR);
ctxt = xmlCreateEntityParserCtxtInternal(sax, user_data, URL, ID, NULL, oldctxt); if (ctxt == NULL) return(XML_WAR_UNDECLARED_ENTITY); if (oldctxt != NULL) { ctxt->nbErrors = oldctxt->nbErrors; ctxt->nbWarnings = oldctxt->nbWarnings; } xmlDetectSAX2(ctxt);
newDoc = xmlNewDoc(BAD_CAST "1.0"); if (newDoc == NULL) { xmlFreeParserCtxt(ctxt); return(XML_ERR_INTERNAL_ERROR); } newDoc->properties = XML_DOC_INTERNAL; if (doc) { newDoc->intSubset = doc->intSubset; newDoc->extSubset = doc->extSubset; if (doc->dict) { newDoc->dict = doc->dict; xmlDictReference(newDoc->dict); } if (doc->URL != NULL) { newDoc->URL = xmlStrdup(doc->URL); } } newRoot = xmlNewDocNode(newDoc, NULL, BAD_CAST "pseudoroot", NULL); if (newRoot == NULL) { if (sax != NULL) xmlFreeParserCtxt(ctxt); newDoc->intSubset = NULL; newDoc->extSubset = NULL; xmlFreeDoc(newDoc); return(XML_ERR_INTERNAL_ERROR); } xmlAddChild((xmlNodePtr) newDoc, newRoot); nodePush(ctxt, newDoc->children); if (doc == NULL) { ctxt->myDoc = newDoc; } else { ctxt->myDoc = doc; newRoot->doc = doc; }
xmlDetectEncoding(ctxt);
/* * Parse a possible text declaration first */ if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && (IS_BLANK_CH(NXT(5)))) { xmlParseTextDecl(ctxt); /* * An XML-1.0 document can't reference an entity not XML-1.0 */ if ((xmlStrEqual(oldctxt->version, BAD_CAST "1.0")) && (!xmlStrEqual(ctxt->input->version, BAD_CAST "1.0"))) { xmlFatalErrMsg(ctxt, XML_ERR_VERSION_MISMATCH, "Version mismatch between document and entity\n"); } }
ctxt->instate = XML_PARSER_CONTENT; ctxt->depth = depth; if (oldctxt != NULL) { ctxt->_private = oldctxt->_private; ctxt->loadsubset = oldctxt->loadsubset; ctxt->validate = oldctxt->validate; ctxt->valid = oldctxt->valid; ctxt->replaceEntities = oldctxt->replaceEntities; if (oldctxt->validate) { ctxt->vctxt.error = oldctxt->vctxt.error; ctxt->vctxt.warning = oldctxt->vctxt.warning; ctxt->vctxt.userData = oldctxt->vctxt.userData; ctxt->vctxt.flags = oldctxt->vctxt.flags; } ctxt->external = oldctxt->external; if (ctxt->dict) xmlDictFree(ctxt->dict); ctxt->dict = oldctxt->dict; ctxt->str_xml = xmlDictLookup(ctxt->dict, BAD_CAST "xml", 3); ctxt->str_xmlns = xmlDictLookup(ctxt->dict, BAD_CAST "xmlns", 5); ctxt->str_xml_ns = xmlDictLookup(ctxt->dict, XML_XML_NAMESPACE, 36); ctxt->dictNames = oldctxt->dictNames; ctxt->attsDefault = oldctxt->attsDefault; ctxt->attsSpecial = oldctxt->attsSpecial; ctxt->linenumbers = oldctxt->linenumbers; ctxt->record_info = oldctxt->record_info; ctxt->node_seq.maximum = oldctxt->node_seq.maximum; ctxt->node_seq.length = oldctxt->node_seq.length; ctxt->node_seq.buffer = oldctxt->node_seq.buffer; } else { /* * Doing validity checking on chunk without context * doesn't make sense */ ctxt->_private = NULL; ctxt->validate = 0; ctxt->external = 2; ctxt->loadsubset = 0; }
xmlParseContent(ctxt);
if ((RAW == '<') && (NXT(1) == '/')) { xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); } else if (RAW != 0) { xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL); } if (ctxt->node != newDoc->children) { xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); }
if (!ctxt->wellFormed) { ret = (xmlParserErrors)ctxt->errNo; if (oldctxt != NULL) { oldctxt->errNo = ctxt->errNo; oldctxt->wellFormed = 0; xmlCopyError(&ctxt->lastError, &oldctxt->lastError); } } else { if (list != NULL) { xmlNodePtr cur;
/* * Return the newly created nodeset after unlinking it from * they pseudo parent. */ cur = newDoc->children->children; *list = cur; while (cur != NULL) { cur->parent = NULL; cur = cur->next; } newDoc->children->children = NULL; } ret = XML_ERR_OK; }
/* * Also record the size of the entity parsed */ if (ctxt->input != NULL && oldctxt != NULL) { unsigned long consumed = ctxt->input->consumed;
xmlSaturatedAddSizeT(&consumed, ctxt->input->cur - ctxt->input->base);
xmlSaturatedAdd(&oldctxt->sizeentities, consumed); xmlSaturatedAdd(&oldctxt->sizeentities, ctxt->sizeentities);
xmlSaturatedAdd(&oldctxt->sizeentcopy, consumed); xmlSaturatedAdd(&oldctxt->sizeentcopy, ctxt->sizeentcopy); }
if (oldctxt != NULL) { ctxt->dict = NULL; ctxt->attsDefault = NULL; ctxt->attsSpecial = NULL; oldctxt->nbErrors = ctxt->nbErrors; oldctxt->nbWarnings = ctxt->nbWarnings; oldctxt->validate = ctxt->validate; oldctxt->valid = ctxt->valid; oldctxt->node_seq.maximum = ctxt->node_seq.maximum; oldctxt->node_seq.length = ctxt->node_seq.length; oldctxt->node_seq.buffer = ctxt->node_seq.buffer; } ctxt->node_seq.maximum = 0; ctxt->node_seq.length = 0; ctxt->node_seq.buffer = NULL; xmlFreeParserCtxt(ctxt); newDoc->intSubset = NULL; newDoc->extSubset = NULL; xmlFreeDoc(newDoc);
return(ret);}
#ifdef LIBXML_SAX1_ENABLED/** * xmlParseExternalEntity: * @doc: the document the chunk pertains to * @sax: the SAX handler block (possibly NULL) * @user_data: The user data returned on SAX callbacks (possibly NULL) * @depth: Used for loop detection, use 0 * @URL: the URL for the entity to load * @ID: the System ID for the entity to load * @lst: the return value for the set of parsed nodes * * Parse an external general entity * An external general parsed entity is well-formed if it matches the * production labeled extParsedEnt. * * [78] extParsedEnt ::= TextDecl? content * * Returns 0 if the entity is well formed, -1 in case of args problem and * the parser error code otherwise */
intxmlParseExternalEntity(xmlDocPtr doc, xmlSAXHandlerPtr sax, void *user_data, int depth, const xmlChar *URL, const xmlChar *ID, xmlNodePtr *lst) { return(xmlParseExternalEntityPrivate(doc, NULL, sax, user_data, depth, URL, ID, lst));}
/** * xmlParseBalancedChunkMemory: * @doc: the document the chunk pertains to (must not be NULL) * @sax: the SAX handler block (possibly NULL) * @user_data: The user data returned on SAX callbacks (possibly NULL) * @depth: Used for loop detection, use 0 * @string: the input string in UTF8 or ISO-Latin (zero terminated) * @lst: the return value for the set of parsed nodes * * Parse a well-balanced chunk of an XML document * called by the parser * The allowed sequence for the Well Balanced Chunk is the one defined by * the content production in the XML grammar: * * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)* * * Returns 0 if the chunk is well balanced, -1 in case of args problem and * the parser error code otherwise */
intxmlParseBalancedChunkMemory(xmlDocPtr doc, xmlSAXHandlerPtr sax, void *user_data, int depth, const xmlChar *string, xmlNodePtr *lst) { return xmlParseBalancedChunkMemoryRecover( doc, sax, user_data, depth, string, lst, 0 );}#endif /* LIBXML_SAX1_ENABLED */
/** * xmlParseBalancedChunkMemoryInternal: * @oldctxt: the existing parsing context * @string: the input string in UTF8 or ISO-Latin (zero terminated) * @user_data: the user data field for the parser context * @lst: the return value for the set of parsed nodes * * * Parse a well-balanced chunk of an XML document * called by the parser * The allowed sequence for the Well Balanced Chunk is the one defined by * the content production in the XML grammar: * * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)* * * Returns XML_ERR_OK if the chunk is well balanced, and the parser * error code otherwise * * In case recover is set to 1, the nodelist will not be empty even if * the parsed chunk is not well balanced. */static xmlParserErrorsxmlParseBalancedChunkMemoryInternal(xmlParserCtxtPtr oldctxt, const xmlChar *string, void *user_data, xmlNodePtr *lst) { xmlParserCtxtPtr ctxt; xmlDocPtr newDoc = NULL; xmlNodePtr newRoot; xmlSAXHandlerPtr oldsax = NULL; xmlNodePtr content = NULL; xmlNodePtr last = NULL; xmlParserErrors ret = XML_ERR_OK; xmlHashedString hprefix, huri; unsigned i;
if (((oldctxt->depth > 40) && ((oldctxt->options & XML_PARSE_HUGE) == 0)) || (oldctxt->depth > 100)) { xmlFatalErrMsg(oldctxt, XML_ERR_ENTITY_LOOP, "Maximum entity nesting depth exceeded"); return(XML_ERR_ENTITY_LOOP); }
if (lst != NULL) *lst = NULL; if (string == NULL) return(XML_ERR_INTERNAL_ERROR);
ctxt = xmlCreateDocParserCtxt(string); if (ctxt == NULL) return(XML_WAR_UNDECLARED_ENTITY); ctxt->nbErrors = oldctxt->nbErrors; ctxt->nbWarnings = oldctxt->nbWarnings; if (user_data != NULL) ctxt->userData = user_data; else ctxt->userData = ctxt; if (ctxt->dict != NULL) xmlDictFree(ctxt->dict); ctxt->dict = oldctxt->dict; ctxt->input_id = oldctxt->input_id; ctxt->str_xml = xmlDictLookup(ctxt->dict, BAD_CAST "xml", 3); ctxt->str_xmlns = xmlDictLookup(ctxt->dict, BAD_CAST "xmlns", 5); ctxt->str_xml_ns = xmlDictLookup(ctxt->dict, XML_XML_NAMESPACE, 36);
/* * Propagate namespaces down the entity * * Making entities and namespaces work correctly requires additional * changes, see xmlParseReference. */
/* Default namespace */ hprefix.name = NULL; hprefix.hashValue = 0; huri.name = xmlParserNsLookupUri(oldctxt, &hprefix); huri.hashValue = 0; if (huri.name != NULL) xmlParserNsPush(ctxt, NULL, &huri, NULL, 0);
for (i = 0; i < oldctxt->nsdb->hashSize; i++) { xmlParserNsBucket *bucket = &oldctxt->nsdb->hash[i]; const xmlChar **ns; xmlParserNsExtra *extra; unsigned nsIndex;
if ((bucket->hashValue != 0) && (bucket->index != INT_MAX)) { nsIndex = bucket->index; ns = &oldctxt->nsTab[nsIndex * 2]; extra = &oldctxt->nsdb->extra[nsIndex];
hprefix.name = ns[0]; hprefix.hashValue = bucket->hashValue; huri.name = ns[1]; huri.hashValue = extra->uriHashValue; /* * Don't copy SAX data to avoid a use-after-free with XML reader. * This matches the pre-2.12 behavior. */ xmlParserNsPush(ctxt, &hprefix, &huri, NULL, 0); } }
oldsax = ctxt->sax; ctxt->sax = oldctxt->sax; xmlDetectSAX2(ctxt); ctxt->replaceEntities = oldctxt->replaceEntities; ctxt->options = oldctxt->options;
ctxt->_private = oldctxt->_private; if (oldctxt->myDoc == NULL) { newDoc = xmlNewDoc(BAD_CAST "1.0"); if (newDoc == NULL) { ret = XML_ERR_INTERNAL_ERROR; goto error; } newDoc->properties = XML_DOC_INTERNAL; newDoc->dict = ctxt->dict; xmlDictReference(newDoc->dict); ctxt->myDoc = newDoc; } else { ctxt->myDoc = oldctxt->myDoc; content = ctxt->myDoc->children; last = ctxt->myDoc->last; } newRoot = xmlNewDocNode(ctxt->myDoc, NULL, BAD_CAST "pseudoroot", NULL); if (newRoot == NULL) { ret = XML_ERR_INTERNAL_ERROR; goto error; } ctxt->myDoc->children = NULL; ctxt->myDoc->last = NULL; xmlAddChild((xmlNodePtr) ctxt->myDoc, newRoot); nodePush(ctxt, ctxt->myDoc->children); ctxt->instate = XML_PARSER_CONTENT; ctxt->depth = oldctxt->depth;
ctxt->validate = 0; ctxt->loadsubset = oldctxt->loadsubset; if ((oldctxt->validate) || (oldctxt->replaceEntities != 0)) { /* * ID/IDREF registration will be done in xmlValidateElement below */ ctxt->loadsubset |= XML_SKIP_IDS; } ctxt->dictNames = oldctxt->dictNames; ctxt->attsDefault = oldctxt->attsDefault; ctxt->attsSpecial = oldctxt->attsSpecial;
xmlParseContent(ctxt); if ((RAW == '<') && (NXT(1) == '/')) { xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); } else if (RAW != 0) { xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL); } if (ctxt->node != ctxt->myDoc->children) { xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); }
if (!ctxt->wellFormed) { ret = (xmlParserErrors)ctxt->errNo; oldctxt->errNo = ctxt->errNo; oldctxt->wellFormed = 0; xmlCopyError(&ctxt->lastError, &oldctxt->lastError); } else { ret = XML_ERR_OK; }
if ((lst != NULL) && (ret == XML_ERR_OK)) { xmlNodePtr cur;
/* * Return the newly created nodeset after unlinking it from * they pseudo parent. */ cur = ctxt->myDoc->children->children; *lst = cur; while (cur != NULL) {#ifdef LIBXML_VALID_ENABLED if ((oldctxt->validate) && (oldctxt->wellFormed) && (oldctxt->myDoc) && (oldctxt->myDoc->intSubset) && (cur->type == XML_ELEMENT_NODE)) { oldctxt->valid &= xmlValidateElement(&oldctxt->vctxt, oldctxt->myDoc, cur); }#endif /* LIBXML_VALID_ENABLED */ cur->parent = NULL; cur = cur->next; } ctxt->myDoc->children->children = NULL; } if (ctxt->myDoc != NULL) { xmlFreeNode(ctxt->myDoc->children); ctxt->myDoc->children = content; ctxt->myDoc->last = last; }
/* * Also record the size of the entity parsed */ if (ctxt->input != NULL && oldctxt != NULL) { unsigned long consumed = ctxt->input->consumed;
xmlSaturatedAddSizeT(&consumed, ctxt->input->cur - ctxt->input->base);
xmlSaturatedAdd(&oldctxt->sizeentcopy, consumed); xmlSaturatedAdd(&oldctxt->sizeentcopy, ctxt->sizeentcopy); }
oldctxt->nbErrors = ctxt->nbErrors; oldctxt->nbWarnings = ctxt->nbWarnings;
error: ctxt->sax = oldsax; ctxt->dict = NULL; ctxt->attsDefault = NULL; ctxt->attsSpecial = NULL; xmlFreeParserCtxt(ctxt); if (newDoc != NULL) { xmlFreeDoc(newDoc); }
return(ret);}
/** * xmlParseInNodeContext: * @node: the context node * @data: the input string * @datalen: the input string length in bytes * @options: a combination of xmlParserOption * @lst: the return value for the set of parsed nodes * * Parse a well-balanced chunk of an XML document * within the context (DTD, namespaces, etc ...) of the given node. * * The allowed sequence for the data is a Well Balanced Chunk defined by * the content production in the XML grammar: * * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)* * * Returns XML_ERR_OK if the chunk is well balanced, and the parser * error code otherwise */xmlParserErrorsxmlParseInNodeContext(xmlNodePtr node, const char *data, int datalen, int options, xmlNodePtr *lst) { xmlParserCtxtPtr ctxt; xmlDocPtr doc = NULL; xmlNodePtr fake, cur; int nsnr = 0;
xmlParserErrors ret = XML_ERR_OK;
/* * check all input parameters, grab the document */ if ((lst == NULL) || (node == NULL) || (data == NULL) || (datalen < 0)) return(XML_ERR_INTERNAL_ERROR); switch (node->type) { case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_ENTITY_REF_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: case XML_DOCUMENT_NODE: case XML_HTML_DOCUMENT_NODE: break; default: return(XML_ERR_INTERNAL_ERROR);
} while ((node != NULL) && (node->type != XML_ELEMENT_NODE) && (node->type != XML_DOCUMENT_NODE) && (node->type != XML_HTML_DOCUMENT_NODE)) node = node->parent; if (node == NULL) return(XML_ERR_INTERNAL_ERROR); if (node->type == XML_ELEMENT_NODE) doc = node->doc; else doc = (xmlDocPtr) node; if (doc == NULL) return(XML_ERR_INTERNAL_ERROR);
/* * allocate a context and set-up everything not related to the * node position in the tree */ if (doc->type == XML_DOCUMENT_NODE) ctxt = xmlCreateMemoryParserCtxt((char *) data, datalen);#ifdef LIBXML_HTML_ENABLED else if (doc->type == XML_HTML_DOCUMENT_NODE) { ctxt = htmlCreateMemoryParserCtxt((char *) data, datalen); /* * When parsing in context, it makes no sense to add implied * elements like html/body/etc... */ options |= HTML_PARSE_NOIMPLIED; }#endif else return(XML_ERR_INTERNAL_ERROR);
if (ctxt == NULL) return(XML_ERR_NO_MEMORY);
/* * Use input doc's dict if present, else assure XML_PARSE_NODICT is set. * We need a dictionary for xmlDetectSAX2, so if there's no doc dict * we must wait until the last moment to free the original one. */ if (doc->dict != NULL) { if (ctxt->dict != NULL) xmlDictFree(ctxt->dict); ctxt->dict = doc->dict; } else options |= XML_PARSE_NODICT;
if (doc->encoding != NULL) { xmlCharEncodingHandlerPtr hdlr;
hdlr = xmlFindCharEncodingHandler((const char *) doc->encoding); if (hdlr != NULL) { xmlSwitchToEncoding(ctxt, hdlr); } else { return(XML_ERR_UNSUPPORTED_ENCODING); } }
xmlCtxtUseOptionsInternal(ctxt, options); xmlDetectSAX2(ctxt); ctxt->myDoc = doc; /* parsing in context, i.e. as within existing content */ ctxt->input_id = 2; ctxt->instate = XML_PARSER_CONTENT;
fake = xmlNewDocComment(node->doc, NULL); if (fake == NULL) { xmlFreeParserCtxt(ctxt); return(XML_ERR_NO_MEMORY); } xmlAddChild(node, fake);
if (node->type == XML_ELEMENT_NODE) nodePush(ctxt, node);
if ((ctxt->html == 0) && (node->type == XML_ELEMENT_NODE)) { /* * initialize the SAX2 namespaces stack */ cur = node; while ((cur != NULL) && (cur->type == XML_ELEMENT_NODE)) { xmlNsPtr ns = cur->nsDef; xmlHashedString hprefix, huri;
while (ns != NULL) { hprefix = xmlDictLookupHashed(ctxt->dict, ns->prefix, -1); huri = xmlDictLookupHashed(ctxt->dict, ns->href, -1); if (xmlParserNsPush(ctxt, &hprefix, &huri, ns, 1) > 0) nsnr++; ns = ns->next; } cur = cur->parent; } }
if ((ctxt->validate) || (ctxt->replaceEntities != 0)) { /* * ID/IDREF registration will be done in xmlValidateElement below */ ctxt->loadsubset |= XML_SKIP_IDS; }
#ifdef LIBXML_HTML_ENABLED if (doc->type == XML_HTML_DOCUMENT_NODE) __htmlParseContent(ctxt); else#endif xmlParseContent(ctxt);
xmlParserNsPop(ctxt, nsnr); if ((RAW == '<') && (NXT(1) == '/')) { xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); } else if (RAW != 0) { xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL); } if ((ctxt->node != NULL) && (ctxt->node != node)) { xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); ctxt->wellFormed = 0; }
if (!ctxt->wellFormed) { if (ctxt->errNo == 0) ret = XML_ERR_INTERNAL_ERROR; else ret = (xmlParserErrors)ctxt->errNo; } else { ret = XML_ERR_OK; }
/* * Return the newly created nodeset after unlinking it from * the pseudo sibling. */
cur = fake->next; fake->next = NULL; node->last = fake;
if (cur != NULL) { cur->prev = NULL; }
*lst = cur;
while (cur != NULL) { cur->parent = NULL; cur = cur->next; }
xmlUnlinkNode(fake); xmlFreeNode(fake);
if (ret != XML_ERR_OK) { xmlFreeNodeList(*lst); *lst = NULL; }
if (doc->dict != NULL) ctxt->dict = NULL; xmlFreeParserCtxt(ctxt);
return(ret);}
#ifdef LIBXML_SAX1_ENABLED/** * xmlParseBalancedChunkMemoryRecover: * @doc: the document the chunk pertains to (must not be NULL) * @sax: the SAX handler block (possibly NULL) * @user_data: The user data returned on SAX callbacks (possibly NULL) * @depth: Used for loop detection, use 0 * @string: the input string in UTF8 or ISO-Latin (zero terminated) * @lst: the return value for the set of parsed nodes * @recover: return nodes even if the data is broken (use 0) * * * Parse a well-balanced chunk of an XML document * called by the parser * The allowed sequence for the Well Balanced Chunk is the one defined by * the content production in the XML grammar: * * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)* * * Returns 0 if the chunk is well balanced, -1 in case of args problem and * the parser error code otherwise * * In case recover is set to 1, the nodelist will not be empty even if * the parsed chunk is not well balanced, assuming the parsing succeeded to * some extent. */intxmlParseBalancedChunkMemoryRecover(xmlDocPtr doc, xmlSAXHandlerPtr sax, void *user_data, int depth, const xmlChar *string, xmlNodePtr *lst, int recover) { xmlParserCtxtPtr ctxt; xmlDocPtr newDoc; xmlSAXHandlerPtr oldsax = NULL; xmlNodePtr content, newRoot; int ret = 0;
if (depth > 40) { return(XML_ERR_ENTITY_LOOP); }
if (lst != NULL) *lst = NULL; if (string == NULL) return(-1);
ctxt = xmlCreateDocParserCtxt(string); if (ctxt == NULL) return(-1); ctxt->userData = ctxt; if (sax != NULL) { oldsax = ctxt->sax; ctxt->sax = sax; if (user_data != NULL) ctxt->userData = user_data; } newDoc = xmlNewDoc(BAD_CAST "1.0"); if (newDoc == NULL) { xmlFreeParserCtxt(ctxt); return(-1); } newDoc->properties = XML_DOC_INTERNAL; if ((doc != NULL) && (doc->dict != NULL)) { xmlDictFree(ctxt->dict); ctxt->dict = doc->dict; xmlDictReference(ctxt->dict); ctxt->str_xml = xmlDictLookup(ctxt->dict, BAD_CAST "xml", 3); ctxt->str_xmlns = xmlDictLookup(ctxt->dict, BAD_CAST "xmlns", 5); ctxt->str_xml_ns = xmlDictLookup(ctxt->dict, XML_XML_NAMESPACE, 36); ctxt->dictNames = 1; newDoc->dict = ctxt->dict; xmlDictReference(newDoc->dict); } else { xmlCtxtUseOptionsInternal(ctxt, XML_PARSE_NODICT); } /* doc == NULL is only supported for historic reasons */ if (doc != NULL) { newDoc->intSubset = doc->intSubset; newDoc->extSubset = doc->extSubset; } newRoot = xmlNewDocNode(newDoc, NULL, BAD_CAST "pseudoroot", NULL); if (newRoot == NULL) { if (sax != NULL) ctxt->sax = oldsax; xmlFreeParserCtxt(ctxt); newDoc->intSubset = NULL; newDoc->extSubset = NULL; xmlFreeDoc(newDoc); return(-1); } xmlAddChild((xmlNodePtr) newDoc, newRoot); nodePush(ctxt, newRoot); /* doc == NULL is only supported for historic reasons */ if (doc == NULL) { ctxt->myDoc = newDoc; } else { ctxt->myDoc = newDoc; /* Ensure that doc has XML spec namespace */ xmlSearchNsByHref(doc, (xmlNodePtr)doc, XML_XML_NAMESPACE); newDoc->oldNs = doc->oldNs; } ctxt->instate = XML_PARSER_CONTENT; ctxt->input_id = 2; ctxt->depth = depth;
/* * Doing validity checking on chunk doesn't make sense */ ctxt->validate = 0; ctxt->loadsubset = 0; xmlDetectSAX2(ctxt);
if ( doc != NULL ){ content = doc->children; doc->children = NULL; xmlParseContent(ctxt); doc->children = content; } else { xmlParseContent(ctxt); } if ((RAW == '<') && (NXT(1) == '/')) { xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); } else if (RAW != 0) { xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL); } if (ctxt->node != newDoc->children) { xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); }
if (!ctxt->wellFormed) { if (ctxt->errNo == 0) ret = 1; else ret = ctxt->errNo; } else { ret = 0; }
if ((lst != NULL) && ((ret == 0) || (recover == 1))) { xmlNodePtr cur;
/* * Return the newly created nodeset after unlinking it from * they pseudo parent. */ cur = newDoc->children->children; *lst = cur; while (cur != NULL) { xmlSetTreeDoc(cur, doc); cur->parent = NULL; cur = cur->next; } newDoc->children->children = NULL; }
if (sax != NULL) ctxt->sax = oldsax; xmlFreeParserCtxt(ctxt); newDoc->intSubset = NULL; newDoc->extSubset = NULL; /* This leaks the namespace list if doc == NULL */ newDoc->oldNs = NULL; xmlFreeDoc(newDoc);
return(ret);}
/** * xmlSAXParseEntity: * @sax: the SAX handler block * @filename: the filename * * DEPRECATED: Don't use. * * parse an XML external entity out of context and build a tree. * It use the given SAX function block to handle the parsing callback. * If sax is NULL, fallback to the default DOM tree building routines. * * [78] extParsedEnt ::= TextDecl? content * * This correspond to a "Well Balanced" chunk * * Returns the resulting document tree */
xmlDocPtrxmlSAXParseEntity(xmlSAXHandlerPtr sax, const char *filename) { xmlDocPtr ret; xmlParserCtxtPtr ctxt;
ctxt = xmlCreateFileParserCtxt(filename); if (ctxt == NULL) { return(NULL); } if (sax != NULL) { if (ctxt->sax != NULL) xmlFree(ctxt->sax); ctxt->sax = sax; ctxt->userData = NULL; }
xmlParseExtParsedEnt(ctxt);
if (ctxt->wellFormed) ret = ctxt->myDoc; else { ret = NULL; xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL; } if (sax != NULL) ctxt->sax = NULL; xmlFreeParserCtxt(ctxt);
return(ret);}
/** * xmlParseEntity: * @filename: the filename * * parse an XML external entity out of context and build a tree. * * [78] extParsedEnt ::= TextDecl? content * * This correspond to a "Well Balanced" chunk * * Returns the resulting document tree */
xmlDocPtrxmlParseEntity(const char *filename) { return(xmlSAXParseEntity(NULL, filename));}#endif /* LIBXML_SAX1_ENABLED */
/** * xmlCreateEntityParserCtxtInternal: * @URL: the entity URL * @ID: the entity PUBLIC ID * @base: a possible base for the target URI * @pctx: parser context used to set options on new context * * Create a parser context for an external entity * Automatic support for ZLIB/Compress compressed document is provided * by default if found at compile-time. * * Returns the new parser context or NULL */static xmlParserCtxtPtrxmlCreateEntityParserCtxtInternal(xmlSAXHandlerPtr sax, void *userData, const xmlChar *URL, const xmlChar *ID, const xmlChar *base, xmlParserCtxtPtr pctx) { xmlParserCtxtPtr ctxt; xmlParserInputPtr inputStream; char *directory = NULL; xmlChar *uri;
ctxt = xmlNewSAXParserCtxt(sax, userData); if (ctxt == NULL) { return(NULL); }
if (pctx != NULL) { ctxt->options = pctx->options; ctxt->_private = pctx->_private; ctxt->input_id = pctx->input_id; }
/* Don't read from stdin. */ if (xmlStrcmp(URL, BAD_CAST "-") == 0) URL = BAD_CAST "./-";
uri = xmlBuildURI(URL, base);
if (uri == NULL) { inputStream = xmlLoadExternalEntity((char *)URL, (char *)ID, ctxt); if (inputStream == NULL) { xmlFreeParserCtxt(ctxt); return(NULL); }
inputPush(ctxt, inputStream);
if ((ctxt->directory == NULL) && (directory == NULL)) directory = xmlParserGetDirectory((char *)URL); if ((ctxt->directory == NULL) && (directory != NULL)) ctxt->directory = directory; } else { inputStream = xmlLoadExternalEntity((char *)uri, (char *)ID, ctxt); if (inputStream == NULL) { xmlFree(uri); xmlFreeParserCtxt(ctxt); return(NULL); }
inputPush(ctxt, inputStream);
if ((ctxt->directory == NULL) && (directory == NULL)) directory = xmlParserGetDirectory((char *)uri); if ((ctxt->directory == NULL) && (directory != NULL)) ctxt->directory = directory; xmlFree(uri); } return(ctxt);}
/** * xmlCreateEntityParserCtxt: * @URL: the entity URL * @ID: the entity PUBLIC ID * @base: a possible base for the target URI * * Create a parser context for an external entity * Automatic support for ZLIB/Compress compressed document is provided * by default if found at compile-time. * * Returns the new parser context or NULL */xmlParserCtxtPtrxmlCreateEntityParserCtxt(const xmlChar *URL, const xmlChar *ID, const xmlChar *base) { return xmlCreateEntityParserCtxtInternal(NULL, NULL, URL, ID, base, NULL);
}
/************************************************************************ * * * Front ends when parsing from a file * * * ************************************************************************/
/** * xmlCreateURLParserCtxt: * @filename: the filename or URL * @options: a combination of xmlParserOption * * Create a parser context for a file or URL content. * Automatic support for ZLIB/Compress compressed document is provided * by default if found at compile-time and for file accesses * * Returns the new parser context or NULL */xmlParserCtxtPtrxmlCreateURLParserCtxt(const char *filename, int options){ xmlParserCtxtPtr ctxt; xmlParserInputPtr inputStream; char *directory = NULL;
ctxt = xmlNewParserCtxt(); if (ctxt == NULL) { xmlErrMemory(NULL, "cannot allocate parser context"); return(NULL); }
if (options) xmlCtxtUseOptionsInternal(ctxt, options); ctxt->linenumbers = 1;
inputStream = xmlLoadExternalEntity(filename, NULL, ctxt); if (inputStream == NULL) { xmlFreeParserCtxt(ctxt); return(NULL); }
inputPush(ctxt, inputStream); if ((ctxt->directory == NULL) && (directory == NULL)) directory = xmlParserGetDirectory(filename); if ((ctxt->directory == NULL) && (directory != NULL)) ctxt->directory = directory;
return(ctxt);}
/** * xmlCreateFileParserCtxt: * @filename: the filename * * Create a parser context for a file content. * Automatic support for ZLIB/Compress compressed document is provided * by default if found at compile-time. * * Returns the new parser context or NULL */xmlParserCtxtPtrxmlCreateFileParserCtxt(const char *filename){ return(xmlCreateURLParserCtxt(filename, 0));}
#ifdef LIBXML_SAX1_ENABLED/** * xmlSAXParseFileWithData: * @sax: the SAX handler block * @filename: the filename * @recovery: work in recovery mode, i.e. tries to read no Well Formed * documents * @data: the userdata * * DEPRECATED: Use xmlNewSAXParserCtxt and xmlCtxtReadFile. * * parse an XML file and build a tree. Automatic support for ZLIB/Compress * compressed document is provided by default if found at compile-time. * It use the given SAX function block to handle the parsing callback. * If sax is NULL, fallback to the default DOM tree building routines. * * User data (void *) is stored within the parser context in the * context's _private member, so it is available nearly everywhere in libxml * * Returns the resulting document tree */
xmlDocPtrxmlSAXParseFileWithData(xmlSAXHandlerPtr sax, const char *filename, int recovery, void *data) { xmlDocPtr ret; xmlParserCtxtPtr ctxt;
xmlInitParser();
ctxt = xmlCreateFileParserCtxt(filename); if (ctxt == NULL) { return(NULL); } if (sax != NULL) { if (ctxt->sax != NULL) xmlFree(ctxt->sax); ctxt->sax = sax; } xmlDetectSAX2(ctxt); if (data!=NULL) { ctxt->_private = data; }
if (ctxt->directory == NULL) ctxt->directory = xmlParserGetDirectory(filename);
ctxt->recovery = recovery;
xmlParseDocument(ctxt);
if ((ctxt->wellFormed) || recovery) { ret = ctxt->myDoc; if ((ret != NULL) && (ctxt->input->buf != NULL)) { if (ctxt->input->buf->compressed > 0) ret->compression = 9; else ret->compression = ctxt->input->buf->compressed; } } else { ret = NULL; xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL; } if (sax != NULL) ctxt->sax = NULL; xmlFreeParserCtxt(ctxt);
return(ret);}
/** * xmlSAXParseFile: * @sax: the SAX handler block * @filename: the filename * @recovery: work in recovery mode, i.e. tries to read no Well Formed * documents * * DEPRECATED: Use xmlNewSAXParserCtxt and xmlCtxtReadFile. * * parse an XML file and build a tree. Automatic support for ZLIB/Compress * compressed document is provided by default if found at compile-time. * It use the given SAX function block to handle the parsing callback. * If sax is NULL, fallback to the default DOM tree building routines. * * Returns the resulting document tree */
xmlDocPtrxmlSAXParseFile(xmlSAXHandlerPtr sax, const char *filename, int recovery) { return(xmlSAXParseFileWithData(sax,filename,recovery,NULL));}
/** * xmlRecoverDoc: * @cur: a pointer to an array of xmlChar * * DEPRECATED: Use xmlReadDoc with XML_PARSE_RECOVER. * * parse an XML in-memory document and build a tree. * In the case the document is not Well Formed, a attempt to build a * tree is tried anyway * * Returns the resulting document tree or NULL in case of failure */
xmlDocPtrxmlRecoverDoc(const xmlChar *cur) { return(xmlSAXParseDoc(NULL, cur, 1));}
/** * xmlParseFile: * @filename: the filename * * DEPRECATED: Use xmlReadFile. * * parse an XML file and build a tree. Automatic support for ZLIB/Compress * compressed document is provided by default if found at compile-time. * * Returns the resulting document tree if the file was wellformed, * NULL otherwise. */
xmlDocPtrxmlParseFile(const char *filename) { return(xmlSAXParseFile(NULL, filename, 0));}
/** * xmlRecoverFile: * @filename: the filename * * DEPRECATED: Use xmlReadFile with XML_PARSE_RECOVER. * * parse an XML file and build a tree. Automatic support for ZLIB/Compress * compressed document is provided by default if found at compile-time. * In the case the document is not Well Formed, it attempts to build * a tree anyway * * Returns the resulting document tree or NULL in case of failure */
xmlDocPtrxmlRecoverFile(const char *filename) { return(xmlSAXParseFile(NULL, filename, 1));}
/** * xmlSetupParserForBuffer: * @ctxt: an XML parser context * @buffer: a xmlChar * buffer * @filename: a file name * * DEPRECATED: Don't use. * * Setup the parser context to parse a new buffer; Clears any prior * contents from the parser context. The buffer parameter must not be * NULL, but the filename parameter can be */voidxmlSetupParserForBuffer(xmlParserCtxtPtr ctxt, const xmlChar* buffer, const char* filename){ xmlParserInputPtr input;
if ((ctxt == NULL) || (buffer == NULL)) return;
input = xmlNewInputStream(ctxt); if (input == NULL) { xmlErrMemory(NULL, "parsing new buffer: out of memory\n"); xmlClearParserCtxt(ctxt); return; }
xmlClearParserCtxt(ctxt); if (filename != NULL) input->filename = (char *) xmlCanonicPath((const xmlChar *)filename); input->base = buffer; input->cur = buffer; input->end = &buffer[xmlStrlen(buffer)]; inputPush(ctxt, input);}
/** * xmlSAXUserParseFile: * @sax: a SAX handler * @user_data: The user data returned on SAX callbacks * @filename: a file name * * DEPRECATED: Use xmlNewSAXParserCtxt and xmlCtxtReadFile. * * parse an XML file and call the given SAX handler routines. * Automatic support for ZLIB/Compress compressed document is provided * * Returns 0 in case of success or a error number otherwise */intxmlSAXUserParseFile(xmlSAXHandlerPtr sax, void *user_data, const char *filename) { int ret = 0; xmlParserCtxtPtr ctxt;
ctxt = xmlCreateFileParserCtxt(filename); if (ctxt == NULL) return -1; if (ctxt->sax != (xmlSAXHandlerPtr) &xmlDefaultSAXHandler) xmlFree(ctxt->sax); ctxt->sax = sax; xmlDetectSAX2(ctxt);
if (user_data != NULL) ctxt->userData = user_data;
xmlParseDocument(ctxt);
if (ctxt->wellFormed) ret = 0; else { if (ctxt->errNo != 0) ret = ctxt->errNo; else ret = -1; } if (sax != NULL) ctxt->sax = NULL; if (ctxt->myDoc != NULL) { xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL; } xmlFreeParserCtxt(ctxt);
return ret;}#endif /* LIBXML_SAX1_ENABLED */
/************************************************************************ * * * Front ends when parsing from memory * * * ************************************************************************/
/** * xmlCreateMemoryParserCtxt: * @buffer: a pointer to a char array * @size: the size of the array * * Create a parser context for an XML in-memory document. * * Returns the new parser context or NULL */xmlParserCtxtPtrxmlCreateMemoryParserCtxt(const char *buffer, int size) { xmlParserCtxtPtr ctxt; xmlParserInputPtr input; xmlParserInputBufferPtr buf;
if (buffer == NULL) return(NULL); if (size <= 0) return(NULL);
ctxt = xmlNewParserCtxt(); if (ctxt == NULL) return(NULL);
buf = xmlParserInputBufferCreateMem(buffer, size, XML_CHAR_ENCODING_NONE); if (buf == NULL) { xmlFreeParserCtxt(ctxt); return(NULL); }
input = xmlNewInputStream(ctxt); if (input == NULL) { xmlFreeParserInputBuffer(buf); xmlFreeParserCtxt(ctxt); return(NULL); }
input->filename = NULL; input->buf = buf; xmlBufResetInput(input->buf->buffer, input);
inputPush(ctxt, input); return(ctxt);}
#ifdef LIBXML_SAX1_ENABLED/** * xmlSAXParseMemoryWithData: * @sax: the SAX handler block * @buffer: an pointer to a char array * @size: the size of the array * @recovery: work in recovery mode, i.e. tries to read no Well Formed * documents * @data: the userdata * * DEPRECATED: Use xmlNewSAXParserCtxt and xmlCtxtReadMemory. * * parse an XML in-memory block and use the given SAX function block * to handle the parsing callback. If sax is NULL, fallback to the default * DOM tree building routines. * * User data (void *) is stored within the parser context in the * context's _private member, so it is available nearly everywhere in libxml * * Returns the resulting document tree */
xmlDocPtrxmlSAXParseMemoryWithData(xmlSAXHandlerPtr sax, const char *buffer, int size, int recovery, void *data) { xmlDocPtr ret; xmlParserCtxtPtr ctxt;
xmlInitParser();
ctxt = xmlCreateMemoryParserCtxt(buffer, size); if (ctxt == NULL) return(NULL); if (sax != NULL) { if (ctxt->sax != NULL) xmlFree(ctxt->sax); ctxt->sax = sax; } xmlDetectSAX2(ctxt); if (data!=NULL) { ctxt->_private=data; }
ctxt->recovery = recovery;
xmlParseDocument(ctxt);
if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc; else { ret = NULL; xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL; } if (sax != NULL) ctxt->sax = NULL; xmlFreeParserCtxt(ctxt);
return(ret);}
/** * xmlSAXParseMemory: * @sax: the SAX handler block * @buffer: an pointer to a char array * @size: the size of the array * @recovery: work in recovery mode, i.e. tries to read not Well Formed * documents * * DEPRECATED: Use xmlNewSAXParserCtxt and xmlCtxtReadMemory. * * parse an XML in-memory block and use the given SAX function block * to handle the parsing callback. If sax is NULL, fallback to the default * DOM tree building routines. * * Returns the resulting document tree */xmlDocPtrxmlSAXParseMemory(xmlSAXHandlerPtr sax, const char *buffer, int size, int recovery) { return xmlSAXParseMemoryWithData(sax, buffer, size, recovery, NULL);}
/** * xmlParseMemory: * @buffer: an pointer to a char array * @size: the size of the array * * DEPRECATED: Use xmlReadMemory. * * parse an XML in-memory block and build a tree. * * Returns the resulting document tree */
xmlDocPtr xmlParseMemory(const char *buffer, int size) { return(xmlSAXParseMemory(NULL, buffer, size, 0));}
/** * xmlRecoverMemory: * @buffer: an pointer to a char array * @size: the size of the array * * DEPRECATED: Use xmlReadMemory with XML_PARSE_RECOVER. * * parse an XML in-memory block and build a tree. * In the case the document is not Well Formed, an attempt to * build a tree is tried anyway * * Returns the resulting document tree or NULL in case of error */
xmlDocPtr xmlRecoverMemory(const char *buffer, int size) { return(xmlSAXParseMemory(NULL, buffer, size, 1));}
/** * xmlSAXUserParseMemory: * @sax: a SAX handler * @user_data: The user data returned on SAX callbacks * @buffer: an in-memory XML document input * @size: the length of the XML document in bytes * * DEPRECATED: Use xmlNewSAXParserCtxt and xmlCtxtReadMemory. * * parse an XML in-memory buffer and call the given SAX handler routines. * * Returns 0 in case of success or a error number otherwise */int xmlSAXUserParseMemory(xmlSAXHandlerPtr sax, void *user_data, const char *buffer, int size) { int ret = 0; xmlParserCtxtPtr ctxt;
xmlInitParser();
ctxt = xmlCreateMemoryParserCtxt(buffer, size); if (ctxt == NULL) return -1; if (ctxt->sax != (xmlSAXHandlerPtr) &xmlDefaultSAXHandler) xmlFree(ctxt->sax); ctxt->sax = sax; xmlDetectSAX2(ctxt);
if (user_data != NULL) ctxt->userData = user_data;
xmlParseDocument(ctxt);
if (ctxt->wellFormed) ret = 0; else { if (ctxt->errNo != 0) ret = ctxt->errNo; else ret = -1; } if (sax != NULL) ctxt->sax = NULL; if (ctxt->myDoc != NULL) { xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL; } xmlFreeParserCtxt(ctxt);
return ret;}#endif /* LIBXML_SAX1_ENABLED */
/** * xmlCreateDocParserCtxt: * @str: a pointer to an array of xmlChar * * Creates a parser context for an XML in-memory document. * * Returns the new parser context or NULL */xmlParserCtxtPtrxmlCreateDocParserCtxt(const xmlChar *str) { xmlParserCtxtPtr ctxt; xmlParserInputPtr input; xmlParserInputBufferPtr buf;
if (str == NULL) return(NULL);
ctxt = xmlNewParserCtxt(); if (ctxt == NULL) return(NULL);
buf = xmlParserInputBufferCreateString(str); if (buf == NULL) { xmlFreeParserCtxt(ctxt); return(NULL); }
input = xmlNewInputStream(ctxt); if (input == NULL) { xmlFreeParserInputBuffer(buf); xmlFreeParserCtxt(ctxt); return(NULL); }
input->filename = NULL; input->buf = buf; xmlBufResetInput(input->buf->buffer, input);
inputPush(ctxt, input); return(ctxt);}
#ifdef LIBXML_SAX1_ENABLED/** * xmlSAXParseDoc: * @sax: the SAX handler block * @cur: a pointer to an array of xmlChar * @recovery: work in recovery mode, i.e. tries to read no Well Formed * documents * * DEPRECATED: Use xmlNewSAXParserCtxt and xmlCtxtReadDoc. * * parse an XML in-memory document and build a tree. * It use the given SAX function block to handle the parsing callback. * If sax is NULL, fallback to the default DOM tree building routines. * * Returns the resulting document tree */
xmlDocPtrxmlSAXParseDoc(xmlSAXHandlerPtr sax, const xmlChar *cur, int recovery) { xmlDocPtr ret; xmlParserCtxtPtr ctxt; xmlSAXHandlerPtr oldsax = NULL;
if (cur == NULL) return(NULL);
ctxt = xmlCreateDocParserCtxt(cur); if (ctxt == NULL) return(NULL); if (sax != NULL) { oldsax = ctxt->sax; ctxt->sax = sax; ctxt->userData = NULL; } xmlDetectSAX2(ctxt);
xmlParseDocument(ctxt); if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc; else { ret = NULL; xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL; } if (sax != NULL) ctxt->sax = oldsax; xmlFreeParserCtxt(ctxt);
return(ret);}
/** * xmlParseDoc: * @cur: a pointer to an array of xmlChar * * DEPRECATED: Use xmlReadDoc. * * parse an XML in-memory document and build a tree. * * Returns the resulting document tree */
xmlDocPtrxmlParseDoc(const xmlChar *cur) { return(xmlSAXParseDoc(NULL, cur, 0));}#endif /* LIBXML_SAX1_ENABLED */
#ifdef LIBXML_LEGACY_ENABLED/************************************************************************ * * * Specific function to keep track of entities references * * and used by the XSLT debugger * * * ************************************************************************/
static xmlEntityReferenceFunc xmlEntityRefFunc = NULL;
/** * xmlAddEntityReference: * @ent : A valid entity * @firstNode : A valid first node for children of entity * @lastNode : A valid last node of children entity * * Notify of a reference to an entity of type XML_EXTERNAL_GENERAL_PARSED_ENTITY */static voidxmlAddEntityReference(xmlEntityPtr ent, xmlNodePtr firstNode, xmlNodePtr lastNode){ if (xmlEntityRefFunc != NULL) { (*xmlEntityRefFunc) (ent, firstNode, lastNode); }}
/** * xmlSetEntityReferenceFunc: * @func: A valid function * * Set the function to call call back when a xml reference has been made */voidxmlSetEntityReferenceFunc(xmlEntityReferenceFunc func){ xmlEntityRefFunc = func;}#endif /* LIBXML_LEGACY_ENABLED */
/************************************************************************ * * * New set (2.6.0) of simpler and more flexible APIs * * * ************************************************************************/
/** * 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));
/** * xmlCtxtReset: * @ctxt: an XML parser context * * Reset a parser context */voidxmlCtxtReset(xmlParserCtxtPtr ctxt){ xmlParserInputPtr input; xmlDictPtr dict;
if (ctxt == NULL) return;
dict = ctxt->dict;
while ((input = inputPop(ctxt)) != NULL) { /* Non consuming */ xmlFreeInputStream(input); } ctxt->inputNr = 0; ctxt->input = NULL;
ctxt->spaceNr = 0; if (ctxt->spaceTab != NULL) { ctxt->spaceTab[0] = -1; ctxt->space = &ctxt->spaceTab[0]; } else { ctxt->space = NULL; }
ctxt->nodeNr = 0; ctxt->node = NULL;
ctxt->nameNr = 0; ctxt->name = NULL;
ctxt->nsNr = 0; xmlParserNsReset(ctxt->nsdb);
DICT_FREE(ctxt->version); ctxt->version = NULL; DICT_FREE(ctxt->encoding); ctxt->encoding = NULL; DICT_FREE(ctxt->directory); ctxt->directory = NULL; DICT_FREE(ctxt->extSubURI); ctxt->extSubURI = NULL; DICT_FREE(ctxt->extSubSystem); ctxt->extSubSystem = NULL; if (ctxt->myDoc != NULL) xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;
ctxt->standalone = -1; ctxt->hasExternalSubset = 0; ctxt->hasPErefs = 0; ctxt->html = 0; ctxt->external = 0; ctxt->instate = XML_PARSER_START; ctxt->token = 0;
ctxt->wellFormed = 1; ctxt->nsWellFormed = 1; ctxt->disableSAX = 0; ctxt->valid = 1;#if 0 ctxt->vctxt.userData = ctxt; ctxt->vctxt.error = xmlParserValidityError; ctxt->vctxt.warning = xmlParserValidityWarning;#endif ctxt->record_info = 0; ctxt->checkIndex = 0; ctxt->endCheckState = 0; ctxt->inSubset = 0; ctxt->errNo = XML_ERR_OK; ctxt->depth = 0; ctxt->catalogs = NULL; ctxt->sizeentities = 0; ctxt->sizeentcopy = 0; xmlInitNodeInfoSeq(&ctxt->node_seq);
if (ctxt->attsDefault != NULL) { xmlHashFree(ctxt->attsDefault, xmlHashDefaultDeallocator); ctxt->attsDefault = NULL; } if (ctxt->attsSpecial != NULL) { xmlHashFree(ctxt->attsSpecial, NULL); ctxt->attsSpecial = NULL; }
#ifdef LIBXML_CATALOG_ENABLED if (ctxt->catalogs != NULL) xmlCatalogFreeLocal(ctxt->catalogs);#endif ctxt->nbErrors = 0; ctxt->nbWarnings = 0; if (ctxt->lastError.code != XML_ERR_OK) xmlResetError(&ctxt->lastError);}
/** * xmlCtxtResetPush: * @ctxt: an XML parser context * @chunk: a pointer to an array of chars * @size: number of chars in the array * @filename: an optional file name or URI * @encoding: the document encoding, or NULL * * Reset a push parser context * * Returns 0 in case of success and 1 in case of error */intxmlCtxtResetPush(xmlParserCtxtPtr ctxt, const char *chunk, int size, const char *filename, const char *encoding){ xmlParserInputPtr inputStream; xmlParserInputBufferPtr buf;
if (ctxt == NULL) return(1);
buf = xmlAllocParserInputBuffer(XML_CHAR_ENCODING_NONE); if (buf == NULL) return(1);
if (ctxt == NULL) { xmlFreeParserInputBuffer(buf); return(1); }
xmlCtxtReset(ctxt);
if (filename == NULL) { ctxt->directory = NULL; } else { ctxt->directory = xmlParserGetDirectory(filename); }
inputStream = xmlNewInputStream(ctxt); if (inputStream == NULL) { xmlFreeParserInputBuffer(buf); return(1); }
if (filename == NULL) inputStream->filename = NULL; else inputStream->filename = (char *) xmlCanonicPath((const xmlChar *) filename); inputStream->buf = buf; xmlBufResetInput(buf->buffer, inputStream);
inputPush(ctxt, inputStream);
if ((size > 0) && (chunk != NULL) && (ctxt->input != NULL) && (ctxt->input->buf != NULL)) { size_t pos = ctxt->input->cur - ctxt->input->base; int res;
res = xmlParserInputBufferPush(ctxt->input->buf, size, chunk); xmlBufUpdateInput(ctxt->input->buf->buffer, ctxt->input, pos); if (res < 0) { xmlFatalErr(ctxt, ctxt->input->buf->error, NULL); xmlHaltParser(ctxt); return(1); } }
if (encoding != NULL) { xmlCharEncodingHandlerPtr hdlr;
hdlr = xmlFindCharEncodingHandler(encoding); if (hdlr != NULL) { xmlSwitchToEncoding(ctxt, hdlr); } else { xmlFatalErrMsgStr(ctxt, XML_ERR_UNSUPPORTED_ENCODING, "Unsupported encoding %s\n", BAD_CAST encoding); } }
return(0);}
/** * xmlCtxtUseOptionsInternal: * @ctxt: an XML parser context * @options: a combination of xmlParserOption * @encoding: the user provided encoding to use * * Applies the options to the parser context * * Returns 0 in case of success, the set of unknown or unimplemented options * in case of error. */static intxmlCtxtUseOptionsInternal(xmlParserCtxtPtr ctxt, int options){ if (ctxt == NULL) return(-1); if (options & XML_PARSE_RECOVER) { ctxt->recovery = 1; options -= XML_PARSE_RECOVER; ctxt->options |= XML_PARSE_RECOVER; } else ctxt->recovery = 0; if (options & XML_PARSE_DTDLOAD) { ctxt->loadsubset = XML_DETECT_IDS; options -= XML_PARSE_DTDLOAD; ctxt->options |= XML_PARSE_DTDLOAD; } else ctxt->loadsubset = 0; if (options & XML_PARSE_DTDATTR) { ctxt->loadsubset |= XML_COMPLETE_ATTRS; options -= XML_PARSE_DTDATTR; ctxt->options |= XML_PARSE_DTDATTR; } if (options & XML_PARSE_NOENT) { ctxt->replaceEntities = 1; /* ctxt->loadsubset |= XML_DETECT_IDS; */ options -= XML_PARSE_NOENT; ctxt->options |= XML_PARSE_NOENT; } else ctxt->replaceEntities = 0; if (options & XML_PARSE_PEDANTIC) { ctxt->pedantic = 1; options -= XML_PARSE_PEDANTIC; ctxt->options |= XML_PARSE_PEDANTIC; } else ctxt->pedantic = 0; if (options & XML_PARSE_NOBLANKS) { ctxt->keepBlanks = 0; ctxt->sax->ignorableWhitespace = xmlSAX2IgnorableWhitespace; options -= XML_PARSE_NOBLANKS; ctxt->options |= XML_PARSE_NOBLANKS; } else ctxt->keepBlanks = 1; if (options & XML_PARSE_DTDVALID) { ctxt->validate = 1; if (options & XML_PARSE_NOWARNING) ctxt->vctxt.warning = NULL; if (options & XML_PARSE_NOERROR) ctxt->vctxt.error = NULL; options -= XML_PARSE_DTDVALID; ctxt->options |= XML_PARSE_DTDVALID; } else ctxt->validate = 0; if (options & XML_PARSE_NOWARNING) { ctxt->sax->warning = NULL; options -= XML_PARSE_NOWARNING; } if (options & XML_PARSE_NOERROR) { ctxt->sax->error = NULL; ctxt->sax->fatalError = NULL; options -= XML_PARSE_NOERROR; }#ifdef LIBXML_SAX1_ENABLED if (options & XML_PARSE_SAX1) { ctxt->sax->startElementNs = NULL; ctxt->sax->endElementNs = NULL; ctxt->sax->initialized = 1; options -= XML_PARSE_SAX1; ctxt->options |= XML_PARSE_SAX1; }#endif /* LIBXML_SAX1_ENABLED */ if (options & XML_PARSE_NODICT) { ctxt->dictNames = 0; options -= XML_PARSE_NODICT; ctxt->options |= XML_PARSE_NODICT; } else { ctxt->dictNames = 1; } if (options & XML_PARSE_NOCDATA) { ctxt->sax->cdataBlock = NULL; options -= XML_PARSE_NOCDATA; ctxt->options |= XML_PARSE_NOCDATA; } if (options & XML_PARSE_NSCLEAN) { ctxt->options |= XML_PARSE_NSCLEAN; options -= XML_PARSE_NSCLEAN; } if (options & XML_PARSE_NONET) { ctxt->options |= XML_PARSE_NONET; options -= XML_PARSE_NONET; } if (options & XML_PARSE_COMPACT) { ctxt->options |= XML_PARSE_COMPACT; options -= XML_PARSE_COMPACT; } if (options & XML_PARSE_OLD10) { ctxt->options |= XML_PARSE_OLD10; options -= XML_PARSE_OLD10; } if (options & XML_PARSE_NOBASEFIX) { ctxt->options |= XML_PARSE_NOBASEFIX; options -= XML_PARSE_NOBASEFIX; } if (options & XML_PARSE_HUGE) { ctxt->options |= XML_PARSE_HUGE; options -= XML_PARSE_HUGE; if (ctxt->dict != NULL) xmlDictSetLimit(ctxt->dict, 0); } if (options & XML_PARSE_OLDSAX) { ctxt->options |= XML_PARSE_OLDSAX; options -= XML_PARSE_OLDSAX; } if (options & XML_PARSE_IGNORE_ENC) { ctxt->options |= XML_PARSE_IGNORE_ENC; options -= XML_PARSE_IGNORE_ENC; } if (options & XML_PARSE_BIG_LINES) { ctxt->options |= XML_PARSE_BIG_LINES; options -= XML_PARSE_BIG_LINES; } ctxt->linenumbers = 1; return (options);}
/** * xmlCtxtUseOptions: * @ctxt: an XML parser context * @options: a combination of xmlParserOption * * Applies the options to the parser context * * Returns 0 in case of success, the set of unknown or unimplemented options * in case of error. */intxmlCtxtUseOptions(xmlParserCtxtPtr ctxt, int options){ return(xmlCtxtUseOptionsInternal(ctxt, options));}
/** * xmlCtxtSetMaxAmplification: * @ctxt: an XML parser context * @maxAmpl: maximum amplification factor * * To protect against exponential entity expansion ("billion laughs"), the * size of serialized output is (roughly) limited to the input size * multiplied by this factor. The default value is 5. * * When working with documents making heavy use of entity expansion, it can * be necessary to increase the value. For security reasons, this should only * be considered when processing trusted input. */voidxmlCtxtSetMaxAmplification(xmlParserCtxtPtr ctxt, unsigned maxAmpl){ ctxt->maxAmpl = maxAmpl;}
/** * xmlDoRead: * @ctxt: an XML parser context * @URL: the base URL to use for the document * @encoding: the document encoding, or NULL * @options: a combination of xmlParserOption * @reuse: keep the context for reuse * * Common front-end for the xmlRead functions * * Returns the resulting document tree or NULL */static xmlDocPtrxmlDoRead(xmlParserCtxtPtr ctxt, const char *URL, const char *encoding, int options, int reuse){ xmlDocPtr ret;
xmlCtxtUseOptionsInternal(ctxt, options); if (encoding != NULL) { xmlCharEncodingHandlerPtr hdlr;
/* * TODO: We should consider to set XML_PARSE_IGNORE_ENC if the * caller provided an encoding. Otherwise, we might switch to * the encoding from the XML declaration which is likely to * break things. Also see xmlSwitchInputEncoding. */ hdlr = xmlFindCharEncodingHandler(encoding); if (hdlr != NULL) xmlSwitchToEncoding(ctxt, hdlr); } if ((URL != NULL) && (ctxt->input != NULL) && (ctxt->input->filename == NULL)) ctxt->input->filename = (char *) xmlStrdup((const xmlChar *) URL); xmlParseDocument(ctxt); if ((ctxt->wellFormed) || ctxt->recovery) ret = ctxt->myDoc; else { ret = NULL; if (ctxt->myDoc != NULL) { xmlFreeDoc(ctxt->myDoc); } } ctxt->myDoc = NULL; if (!reuse) { xmlFreeParserCtxt(ctxt); }
return (ret);}
/** * xmlReadDoc: * @cur: a pointer to a zero terminated string * @URL: the base URL to use for the document * @encoding: the document encoding, or NULL * @options: a combination of xmlParserOption * * parse an XML in-memory document and build a tree. * * Returns the resulting document tree */xmlDocPtrxmlReadDoc(const xmlChar * cur, const char *URL, const char *encoding, int options){ xmlParserCtxtPtr ctxt;
if (cur == NULL) return (NULL); xmlInitParser();
ctxt = xmlCreateDocParserCtxt(cur); if (ctxt == NULL) return (NULL); return (xmlDoRead(ctxt, URL, encoding, options, 0));}
/** * xmlReadFile: * @filename: a file or URL * @encoding: the document encoding, or NULL * @options: a combination of xmlParserOption * * parse an XML file from the filesystem or the network. * * Returns the resulting document tree */xmlDocPtrxmlReadFile(const char *filename, const char *encoding, int options){ xmlParserCtxtPtr ctxt;
xmlInitParser(); ctxt = xmlCreateURLParserCtxt(filename, options); if (ctxt == NULL) return (NULL); return (xmlDoRead(ctxt, NULL, encoding, options, 0));}
/** * xmlReadMemory: * @buffer: a pointer to a char array * @size: the size of the array * @URL: the base URL to use for the document * @encoding: the document encoding, or NULL * @options: a combination of xmlParserOption * * parse an XML in-memory document and build a tree. * * Returns the resulting document tree */xmlDocPtrxmlReadMemory(const char *buffer, int size, const char *URL, const char *encoding, int options){ xmlParserCtxtPtr ctxt;
xmlInitParser(); ctxt = xmlCreateMemoryParserCtxt(buffer, size); if (ctxt == NULL) return (NULL); return (xmlDoRead(ctxt, URL, encoding, options, 0));}
/** * xmlReadFd: * @fd: an open file descriptor * @URL: the base URL to use for the document * @encoding: the document encoding, or NULL * @options: a combination of xmlParserOption * * parse an XML from a file descriptor and build a tree. * NOTE that the file descriptor will not be closed when the * reader is closed or reset. * * Returns the resulting document tree */xmlDocPtrxmlReadFd(int fd, const char *URL, const char *encoding, int options){ xmlParserCtxtPtr ctxt; xmlParserInputBufferPtr input; xmlParserInputPtr stream;
if (fd < 0) return (NULL); xmlInitParser();
input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE); if (input == NULL) return (NULL); input->closecallback = NULL; ctxt = xmlNewParserCtxt(); if (ctxt == NULL) { xmlFreeParserInputBuffer(input); return (NULL); } stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); if (stream == NULL) { xmlFreeParserInputBuffer(input); xmlFreeParserCtxt(ctxt); return (NULL); } inputPush(ctxt, stream); return (xmlDoRead(ctxt, URL, encoding, options, 0));}
/** * xmlReadIO: * @ioread: an I/O read function * @ioclose: an I/O close function * @ioctx: an I/O handler * @URL: the base URL to use for the document * @encoding: the document encoding, or NULL * @options: a combination of xmlParserOption * * parse an XML document from I/O functions and source and build a tree. * * Returns the resulting document tree */xmlDocPtrxmlReadIO(xmlInputReadCallback ioread, xmlInputCloseCallback ioclose, void *ioctx, const char *URL, const char *encoding, int options){ xmlParserCtxtPtr ctxt; xmlParserInputBufferPtr input; xmlParserInputPtr stream;
if (ioread == NULL) return (NULL); xmlInitParser();
input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx, XML_CHAR_ENCODING_NONE); if (input == NULL) { if (ioclose != NULL) ioclose(ioctx); return (NULL); } ctxt = xmlNewParserCtxt(); if (ctxt == NULL) { xmlFreeParserInputBuffer(input); return (NULL); } stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); if (stream == NULL) { xmlFreeParserInputBuffer(input); xmlFreeParserCtxt(ctxt); return (NULL); } inputPush(ctxt, stream); return (xmlDoRead(ctxt, URL, encoding, options, 0));}
/** * xmlCtxtReadDoc: * @ctxt: an XML parser context * @str: a pointer to a zero terminated string * @URL: the base URL to use for the document * @encoding: the document encoding, or NULL * @options: a combination of xmlParserOption * * parse an XML in-memory document and build a tree. * This reuses the existing @ctxt parser context * * Returns the resulting document tree */xmlDocPtrxmlCtxtReadDoc(xmlParserCtxtPtr ctxt, const xmlChar *str, const char *URL, const char *encoding, int options){ xmlParserInputBufferPtr input; xmlParserInputPtr stream;
if (ctxt == NULL) return (NULL); if (str == NULL) return (NULL); xmlInitParser();
xmlCtxtReset(ctxt);
input = xmlParserInputBufferCreateString(str); if (input == NULL) { return(NULL); }
stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); if (stream == NULL) { xmlFreeParserInputBuffer(input); return(NULL); }
inputPush(ctxt, stream); return (xmlDoRead(ctxt, URL, encoding, options, 1));}
/** * xmlCtxtReadFile: * @ctxt: an XML parser context * @filename: a file or URL * @encoding: the document encoding, or NULL * @options: a combination of xmlParserOption * * parse an XML file from the filesystem or the network. * This reuses the existing @ctxt parser context * * Returns the resulting document tree */xmlDocPtrxmlCtxtReadFile(xmlParserCtxtPtr ctxt, const char *filename, const char *encoding, int options){ xmlParserInputPtr stream;
if (filename == NULL) return (NULL); if (ctxt == NULL) return (NULL); xmlInitParser();
xmlCtxtReset(ctxt);
stream = xmlLoadExternalEntity(filename, NULL, ctxt); if (stream == NULL) { return (NULL); } inputPush(ctxt, stream); return (xmlDoRead(ctxt, NULL, encoding, options, 1));}
/** * xmlCtxtReadMemory: * @ctxt: an XML parser context * @buffer: a pointer to a char array * @size: the size of the array * @URL: the base URL to use for the document * @encoding: the document encoding, or NULL * @options: a combination of xmlParserOption * * parse an XML in-memory document and build a tree. * This reuses the existing @ctxt parser context * * Returns the resulting document tree */xmlDocPtrxmlCtxtReadMemory(xmlParserCtxtPtr ctxt, const char *buffer, int size, const char *URL, const char *encoding, int options){ xmlParserInputBufferPtr input; xmlParserInputPtr stream;
if (ctxt == NULL) return (NULL); if (buffer == NULL) return (NULL); xmlInitParser();
xmlCtxtReset(ctxt);
input = xmlParserInputBufferCreateStatic(buffer, size, XML_CHAR_ENCODING_NONE); if (input == NULL) { return(NULL); }
stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); if (stream == NULL) { xmlFreeParserInputBuffer(input); return(NULL); }
inputPush(ctxt, stream); return (xmlDoRead(ctxt, URL, encoding, options, 1));}
/** * xmlCtxtReadFd: * @ctxt: an XML parser context * @fd: an open file descriptor * @URL: the base URL to use for the document * @encoding: the document encoding, or NULL * @options: a combination of xmlParserOption * * parse an XML from a file descriptor and build a tree. * This reuses the existing @ctxt parser context * NOTE that the file descriptor will not be closed when the * reader is closed or reset. * * Returns the resulting document tree */xmlDocPtrxmlCtxtReadFd(xmlParserCtxtPtr ctxt, int fd, const char *URL, const char *encoding, int options){ xmlParserInputBufferPtr input; xmlParserInputPtr stream;
if (fd < 0) return (NULL); if (ctxt == NULL) return (NULL); xmlInitParser();
xmlCtxtReset(ctxt);
input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE); if (input == NULL) return (NULL); input->closecallback = NULL; stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); if (stream == NULL) { xmlFreeParserInputBuffer(input); return (NULL); } inputPush(ctxt, stream); return (xmlDoRead(ctxt, URL, encoding, options, 1));}
/** * xmlCtxtReadIO: * @ctxt: an XML parser context * @ioread: an I/O read function * @ioclose: an I/O close function * @ioctx: an I/O handler * @URL: the base URL to use for the document * @encoding: the document encoding, or NULL * @options: a combination of xmlParserOption * * parse an XML document from I/O functions and source and build a tree. * This reuses the existing @ctxt parser context * * Returns the resulting document tree */xmlDocPtrxmlCtxtReadIO(xmlParserCtxtPtr ctxt, xmlInputReadCallback ioread, xmlInputCloseCallback ioclose, void *ioctx, const char *URL, const char *encoding, int options){ xmlParserInputBufferPtr input; xmlParserInputPtr stream;
if (ioread == NULL) return (NULL); if (ctxt == NULL) return (NULL); xmlInitParser();
xmlCtxtReset(ctxt);
input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx, XML_CHAR_ENCODING_NONE); if (input == NULL) { if (ioclose != NULL) ioclose(ioctx); return (NULL); } stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); if (stream == NULL) { xmlFreeParserInputBuffer(input); return (NULL); } inputPush(ctxt, stream); return (xmlDoRead(ctxt, URL, encoding, options, 1));}