HTMLparser.c 209 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279
  1. /*
  2. * HTMLparser.c : an HTML 4.0 non-verifying parser
  3. *
  4. * See Copyright for the status of this software.
  5. *
  6. * daniel@veillard.com
  7. */
  8. #define IN_LIBXML
  9. #include "libxml.h"
  10. #ifdef LIBXML_HTML_ENABLED
  11. #include <string.h>
  12. #include <ctype.h>
  13. #include <stdlib.h>
  14. #include <libxml/xmlmemory.h>
  15. #include <libxml/tree.h>
  16. #include <libxml/parser.h>
  17. #include <libxml/parserInternals.h>
  18. #include <libxml/xmlerror.h>
  19. #include <libxml/HTMLparser.h>
  20. #include <libxml/HTMLtree.h>
  21. #include <libxml/entities.h>
  22. #include <libxml/encoding.h>
  23. #include <libxml/valid.h>
  24. #include <libxml/xmlIO.h>
  25. #include <libxml/globals.h>
  26. #include <libxml/uri.h>
  27. #include "buf.h"
  28. #include "enc.h"
  29. #define HTML_MAX_NAMELEN 1000
  30. #define HTML_PARSER_BIG_BUFFER_SIZE 1000
  31. #define HTML_PARSER_BUFFER_SIZE 100
  32. /* #define DEBUG */
  33. /* #define DEBUG_PUSH */
  34. static int htmlOmittedDefaultValue = 1;
  35. xmlChar * htmlDecodeEntities(htmlParserCtxtPtr ctxt, int len,
  36. xmlChar end, xmlChar end2, xmlChar end3);
  37. static void htmlParseComment(htmlParserCtxtPtr ctxt);
  38. /************************************************************************
  39. * *
  40. * Some factorized error routines *
  41. * *
  42. ************************************************************************/
  43. /**
  44. * htmlErrMemory:
  45. * @ctxt: an HTML parser context
  46. * @extra: extra information
  47. *
  48. * Handle a redefinition of attribute error
  49. */
  50. static void
  51. htmlErrMemory(xmlParserCtxtPtr ctxt, const char *extra)
  52. {
  53. if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
  54. (ctxt->instate == XML_PARSER_EOF))
  55. return;
  56. if (ctxt != NULL) {
  57. ctxt->errNo = XML_ERR_NO_MEMORY;
  58. ctxt->instate = XML_PARSER_EOF;
  59. ctxt->disableSAX = 1;
  60. }
  61. if (extra)
  62. __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER,
  63. XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
  64. NULL, NULL, 0, 0,
  65. "Memory allocation failed : %s\n", extra);
  66. else
  67. __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER,
  68. XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
  69. NULL, NULL, 0, 0, "Memory allocation failed\n");
  70. }
  71. /**
  72. * htmlParseErr:
  73. * @ctxt: an HTML parser context
  74. * @error: the error number
  75. * @msg: the error message
  76. * @str1: string infor
  77. * @str2: string infor
  78. *
  79. * Handle a fatal parser error, i.e. violating Well-Formedness constraints
  80. */
  81. static void LIBXML_ATTR_FORMAT(3,0)
  82. htmlParseErr(xmlParserCtxtPtr ctxt, xmlParserErrors error,
  83. const char *msg, const xmlChar *str1, const xmlChar *str2)
  84. {
  85. if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
  86. (ctxt->instate == XML_PARSER_EOF))
  87. return;
  88. if (ctxt != NULL)
  89. ctxt->errNo = error;
  90. __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_HTML, error,
  91. XML_ERR_ERROR, NULL, 0,
  92. (const char *) str1, (const char *) str2,
  93. NULL, 0, 0,
  94. msg, str1, str2);
  95. if (ctxt != NULL)
  96. ctxt->wellFormed = 0;
  97. }
  98. /**
  99. * htmlParseErrInt:
  100. * @ctxt: an HTML parser context
  101. * @error: the error number
  102. * @msg: the error message
  103. * @val: integer info
  104. *
  105. * Handle a fatal parser error, i.e. violating Well-Formedness constraints
  106. */
  107. static void LIBXML_ATTR_FORMAT(3,0)
  108. htmlParseErrInt(xmlParserCtxtPtr ctxt, xmlParserErrors error,
  109. const char *msg, int val)
  110. {
  111. if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
  112. (ctxt->instate == XML_PARSER_EOF))
  113. return;
  114. if (ctxt != NULL)
  115. ctxt->errNo = error;
  116. __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_HTML, error,
  117. XML_ERR_ERROR, NULL, 0, NULL, NULL,
  118. NULL, val, 0, msg, val);
  119. if (ctxt != NULL)
  120. ctxt->wellFormed = 0;
  121. }
  122. /************************************************************************
  123. * *
  124. * Parser stacks related functions and macros *
  125. * *
  126. ************************************************************************/
  127. /**
  128. * htmlnamePush:
  129. * @ctxt: an HTML parser context
  130. * @value: the element name
  131. *
  132. * Pushes a new element name on top of the name stack
  133. *
  134. * Returns 0 in case of error, the index in the stack otherwise
  135. */
  136. static int
  137. htmlnamePush(htmlParserCtxtPtr ctxt, const xmlChar * value)
  138. {
  139. if ((ctxt->html < 3) && (xmlStrEqual(value, BAD_CAST "head")))
  140. ctxt->html = 3;
  141. if ((ctxt->html < 10) && (xmlStrEqual(value, BAD_CAST "body")))
  142. ctxt->html = 10;
  143. if (ctxt->nameNr >= ctxt->nameMax) {
  144. ctxt->nameMax *= 2;
  145. ctxt->nameTab = (const xmlChar * *)
  146. xmlRealloc((xmlChar * *)ctxt->nameTab,
  147. ctxt->nameMax *
  148. sizeof(ctxt->nameTab[0]));
  149. if (ctxt->nameTab == NULL) {
  150. htmlErrMemory(ctxt, NULL);
  151. return (0);
  152. }
  153. }
  154. ctxt->nameTab[ctxt->nameNr] = value;
  155. ctxt->name = value;
  156. return (ctxt->nameNr++);
  157. }
  158. /**
  159. * htmlnamePop:
  160. * @ctxt: an HTML parser context
  161. *
  162. * Pops the top element name from the name stack
  163. *
  164. * Returns the name just removed
  165. */
  166. static const xmlChar *
  167. htmlnamePop(htmlParserCtxtPtr ctxt)
  168. {
  169. const xmlChar *ret;
  170. if (ctxt->nameNr <= 0)
  171. return (NULL);
  172. ctxt->nameNr--;
  173. if (ctxt->nameNr < 0)
  174. return (NULL);
  175. if (ctxt->nameNr > 0)
  176. ctxt->name = ctxt->nameTab[ctxt->nameNr - 1];
  177. else
  178. ctxt->name = NULL;
  179. ret = ctxt->nameTab[ctxt->nameNr];
  180. ctxt->nameTab[ctxt->nameNr] = NULL;
  181. return (ret);
  182. }
  183. /**
  184. * htmlNodeInfoPush:
  185. * @ctxt: an HTML parser context
  186. * @value: the node info
  187. *
  188. * Pushes a new element name on top of the node info stack
  189. *
  190. * Returns 0 in case of error, the index in the stack otherwise
  191. */
  192. static int
  193. htmlNodeInfoPush(htmlParserCtxtPtr ctxt, htmlParserNodeInfo *value)
  194. {
  195. if (ctxt->nodeInfoNr >= ctxt->nodeInfoMax) {
  196. if (ctxt->nodeInfoMax == 0)
  197. ctxt->nodeInfoMax = 5;
  198. ctxt->nodeInfoMax *= 2;
  199. ctxt->nodeInfoTab = (htmlParserNodeInfo *)
  200. xmlRealloc((htmlParserNodeInfo *)ctxt->nodeInfoTab,
  201. ctxt->nodeInfoMax *
  202. sizeof(ctxt->nodeInfoTab[0]));
  203. if (ctxt->nodeInfoTab == NULL) {
  204. htmlErrMemory(ctxt, NULL);
  205. return (0);
  206. }
  207. }
  208. ctxt->nodeInfoTab[ctxt->nodeInfoNr] = *value;
  209. ctxt->nodeInfo = &ctxt->nodeInfoTab[ctxt->nodeInfoNr];
  210. return (ctxt->nodeInfoNr++);
  211. }
  212. /**
  213. * htmlNodeInfoPop:
  214. * @ctxt: an HTML parser context
  215. *
  216. * Pops the top element name from the node info stack
  217. *
  218. * Returns 0 in case of error, the pointer to NodeInfo otherwise
  219. */
  220. static htmlParserNodeInfo *
  221. htmlNodeInfoPop(htmlParserCtxtPtr ctxt)
  222. {
  223. if (ctxt->nodeInfoNr <= 0)
  224. return (NULL);
  225. ctxt->nodeInfoNr--;
  226. if (ctxt->nodeInfoNr < 0)
  227. return (NULL);
  228. if (ctxt->nodeInfoNr > 0)
  229. ctxt->nodeInfo = &ctxt->nodeInfoTab[ctxt->nodeInfoNr - 1];
  230. else
  231. ctxt->nodeInfo = NULL;
  232. return &ctxt->nodeInfoTab[ctxt->nodeInfoNr];
  233. }
  234. /*
  235. * Macros for accessing the content. Those should be used only by the parser,
  236. * and not exported.
  237. *
  238. * Dirty macros, i.e. one need to make assumption on the context to use them
  239. *
  240. * CUR_PTR return the current pointer to the xmlChar to be parsed.
  241. * CUR returns the current xmlChar value, i.e. a 8 bit value if compiled
  242. * in ISO-Latin or UTF-8, and the current 16 bit value if compiled
  243. * in UNICODE mode. This should be used internally by the parser
  244. * only to compare to ASCII values otherwise it would break when
  245. * running with UTF-8 encoding.
  246. * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
  247. * to compare on ASCII based substring.
  248. * UPP(n) returns the n'th next xmlChar converted to uppercase. Same as CUR
  249. * it should be used only to compare on ASCII based substring.
  250. * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
  251. * strings without newlines within the parser.
  252. *
  253. * Clean macros, not dependent of an ASCII context, expect UTF-8 encoding
  254. *
  255. * CURRENT Returns the current char value, with the full decoding of
  256. * UTF-8 if we are using this mode. It returns an int.
  257. * NEXT Skip to the next character, this does the proper decoding
  258. * in UTF-8 mode. It also pop-up unfinished entities on the fly.
  259. * NEXTL(l) Skip the current unicode character of l xmlChars long.
  260. * COPY(to) copy one char to *to, increment CUR_PTR and to accordingly
  261. */
  262. #define UPPER (toupper(*ctxt->input->cur))
  263. #define SKIP(val) ctxt->input->cur += (val),ctxt->input->col+=(val)
  264. #define NXT(val) ctxt->input->cur[(val)]
  265. #define UPP(val) (toupper(ctxt->input->cur[(val)]))
  266. #define CUR_PTR ctxt->input->cur
  267. #define BASE_PTR ctxt->input->base
  268. #define SHRINK if ((ctxt->input->cur - ctxt->input->base > 2 * INPUT_CHUNK) && \
  269. (ctxt->input->end - ctxt->input->cur < 2 * INPUT_CHUNK)) \
  270. xmlParserInputShrink(ctxt->input)
  271. #define GROW if ((ctxt->progressive == 0) && \
  272. (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK)) \
  273. xmlParserInputGrow(ctxt->input, INPUT_CHUNK)
  274. #define CURRENT ((int) (*ctxt->input->cur))
  275. #define SKIP_BLANKS htmlSkipBlankChars(ctxt)
  276. /* Imported from XML */
  277. /* #define CUR (ctxt->token ? ctxt->token : (int) (*ctxt->input->cur)) */
  278. #define CUR ((int) (*ctxt->input->cur))
  279. #define NEXT xmlNextChar(ctxt)
  280. #define RAW (ctxt->token ? -1 : (*ctxt->input->cur))
  281. #define NEXTL(l) do { \
  282. if (*(ctxt->input->cur) == '\n') { \
  283. ctxt->input->line++; ctxt->input->col = 1; \
  284. } else ctxt->input->col++; \
  285. ctxt->token = 0; ctxt->input->cur += l; \
  286. } while (0)
  287. /************
  288. \
  289. if (*ctxt->input->cur == '%') xmlParserHandlePEReference(ctxt); \
  290. if (*ctxt->input->cur == '&') xmlParserHandleReference(ctxt);
  291. ************/
  292. #define CUR_CHAR(l) htmlCurrentChar(ctxt, &l)
  293. #define CUR_SCHAR(s, l) xmlStringCurrentChar(ctxt, s, &l)
  294. #define COPY_BUF(l,b,i,v) \
  295. if (l == 1) b[i++] = (xmlChar) v; \
  296. else i += xmlCopyChar(l,&b[i],v)
  297. /**
  298. * htmlFindEncoding:
  299. * @the HTML parser context
  300. *
  301. * Ty to find and encoding in the current data available in the input
  302. * buffer this is needed to try to switch to the proper encoding when
  303. * one face a character error.
  304. * That's an heuristic, since it's operating outside of parsing it could
  305. * try to use a meta which had been commented out, that's the reason it
  306. * should only be used in case of error, not as a default.
  307. *
  308. * Returns an encoding string or NULL if not found, the string need to
  309. * be freed
  310. */
  311. static xmlChar *
  312. htmlFindEncoding(xmlParserCtxtPtr ctxt) {
  313. const xmlChar *start, *cur, *end;
  314. if ((ctxt == NULL) || (ctxt->input == NULL) ||
  315. (ctxt->input->encoding != NULL) || (ctxt->input->buf == NULL) ||
  316. (ctxt->input->buf->encoder != NULL))
  317. return(NULL);
  318. if ((ctxt->input->cur == NULL) || (ctxt->input->end == NULL))
  319. return(NULL);
  320. start = ctxt->input->cur;
  321. end = ctxt->input->end;
  322. /* we also expect the input buffer to be zero terminated */
  323. if (*end != 0)
  324. return(NULL);
  325. cur = xmlStrcasestr(start, BAD_CAST "HTTP-EQUIV");
  326. if (cur == NULL)
  327. return(NULL);
  328. cur = xmlStrcasestr(cur, BAD_CAST "CONTENT");
  329. if (cur == NULL)
  330. return(NULL);
  331. cur = xmlStrcasestr(cur, BAD_CAST "CHARSET=");
  332. if (cur == NULL)
  333. return(NULL);
  334. cur += 8;
  335. start = cur;
  336. while (((*cur >= 'A') && (*cur <= 'Z')) ||
  337. ((*cur >= 'a') && (*cur <= 'z')) ||
  338. ((*cur >= '0') && (*cur <= '9')) ||
  339. (*cur == '-') || (*cur == '_') || (*cur == ':') || (*cur == '/'))
  340. cur++;
  341. if (cur == start)
  342. return(NULL);
  343. return(xmlStrndup(start, cur - start));
  344. }
  345. /**
  346. * htmlCurrentChar:
  347. * @ctxt: the HTML parser context
  348. * @len: pointer to the length of the char read
  349. *
  350. * The current char value, if using UTF-8 this may actually span multiple
  351. * bytes in the input buffer. Implement the end of line normalization:
  352. * 2.11 End-of-Line Handling
  353. * If the encoding is unspecified, in the case we find an ISO-Latin-1
  354. * char, then the encoding converter is plugged in automatically.
  355. *
  356. * Returns the current char value and its length
  357. */
  358. static int
  359. htmlCurrentChar(xmlParserCtxtPtr ctxt, int *len) {
  360. const unsigned char *cur;
  361. unsigned char c;
  362. unsigned int val;
  363. if (ctxt->instate == XML_PARSER_EOF)
  364. return(0);
  365. if (ctxt->token != 0) {
  366. *len = 0;
  367. return(ctxt->token);
  368. }
  369. if (ctxt->charset != XML_CHAR_ENCODING_UTF8) {
  370. xmlChar * guess;
  371. xmlCharEncodingHandlerPtr handler;
  372. /*
  373. * Assume it's a fixed length encoding (1) with
  374. * a compatible encoding for the ASCII set, since
  375. * HTML constructs only use < 128 chars
  376. */
  377. if ((int) *ctxt->input->cur < 0x80) {
  378. *len = 1;
  379. if ((*ctxt->input->cur == 0) &&
  380. (ctxt->input->cur < ctxt->input->end)) {
  381. htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
  382. "Char 0x%X out of allowed range\n", 0);
  383. return(' ');
  384. }
  385. return((int) *ctxt->input->cur);
  386. }
  387. /*
  388. * Humm this is bad, do an automatic flow conversion
  389. */
  390. guess = htmlFindEncoding(ctxt);
  391. if (guess == NULL) {
  392. xmlSwitchEncoding(ctxt, XML_CHAR_ENCODING_8859_1);
  393. } else {
  394. if (ctxt->input->encoding != NULL)
  395. xmlFree((xmlChar *) ctxt->input->encoding);
  396. ctxt->input->encoding = guess;
  397. handler = xmlFindCharEncodingHandler((const char *) guess);
  398. if (handler != NULL) {
  399. /*
  400. * Don't use UTF-8 encoder which isn't required and
  401. * can produce invalid UTF-8.
  402. */
  403. if (!xmlStrEqual(BAD_CAST handler->name, BAD_CAST "UTF-8"))
  404. xmlSwitchToEncoding(ctxt, handler);
  405. } else {
  406. htmlParseErr(ctxt, XML_ERR_INVALID_ENCODING,
  407. "Unsupported encoding %s", guess, NULL);
  408. }
  409. }
  410. ctxt->charset = XML_CHAR_ENCODING_UTF8;
  411. }
  412. /*
  413. * We are supposed to handle UTF8, check it's valid
  414. * From rfc2044: encoding of the Unicode values on UTF-8:
  415. *
  416. * UCS-4 range (hex.) UTF-8 octet sequence (binary)
  417. * 0000 0000-0000 007F 0xxxxxxx
  418. * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
  419. * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
  420. *
  421. * Check for the 0x110000 limit too
  422. */
  423. cur = ctxt->input->cur;
  424. c = *cur;
  425. if (c & 0x80) {
  426. if ((c & 0x40) == 0)
  427. goto encoding_error;
  428. if (cur[1] == 0) {
  429. xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
  430. cur = ctxt->input->cur;
  431. }
  432. if ((cur[1] & 0xc0) != 0x80)
  433. goto encoding_error;
  434. if ((c & 0xe0) == 0xe0) {
  435. if (cur[2] == 0) {
  436. xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
  437. cur = ctxt->input->cur;
  438. }
  439. if ((cur[2] & 0xc0) != 0x80)
  440. goto encoding_error;
  441. if ((c & 0xf0) == 0xf0) {
  442. if (cur[3] == 0) {
  443. xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
  444. cur = ctxt->input->cur;
  445. }
  446. if (((c & 0xf8) != 0xf0) ||
  447. ((cur[3] & 0xc0) != 0x80))
  448. goto encoding_error;
  449. /* 4-byte code */
  450. *len = 4;
  451. val = (cur[0] & 0x7) << 18;
  452. val |= (cur[1] & 0x3f) << 12;
  453. val |= (cur[2] & 0x3f) << 6;
  454. val |= cur[3] & 0x3f;
  455. if (val < 0x10000)
  456. goto encoding_error;
  457. } else {
  458. /* 3-byte code */
  459. *len = 3;
  460. val = (cur[0] & 0xf) << 12;
  461. val |= (cur[1] & 0x3f) << 6;
  462. val |= cur[2] & 0x3f;
  463. if (val < 0x800)
  464. goto encoding_error;
  465. }
  466. } else {
  467. /* 2-byte code */
  468. *len = 2;
  469. val = (cur[0] & 0x1f) << 6;
  470. val |= cur[1] & 0x3f;
  471. if (val < 0x80)
  472. goto encoding_error;
  473. }
  474. if (!IS_CHAR(val)) {
  475. htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
  476. "Char 0x%X out of allowed range\n", val);
  477. }
  478. return(val);
  479. } else {
  480. if ((*ctxt->input->cur == 0) &&
  481. (ctxt->input->cur < ctxt->input->end)) {
  482. htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
  483. "Char 0x%X out of allowed range\n", 0);
  484. *len = 1;
  485. return(' ');
  486. }
  487. /* 1-byte code */
  488. *len = 1;
  489. return((int) *ctxt->input->cur);
  490. }
  491. encoding_error:
  492. /*
  493. * If we detect an UTF8 error that probably mean that the
  494. * input encoding didn't get properly advertised in the
  495. * declaration header. Report the error and switch the encoding
  496. * to ISO-Latin-1 (if you don't like this policy, just declare the
  497. * encoding !)
  498. */
  499. {
  500. char buffer[150];
  501. if (ctxt->input->end - ctxt->input->cur >= 4) {
  502. snprintf(buffer, 149, "Bytes: 0x%02X 0x%02X 0x%02X 0x%02X\n",
  503. ctxt->input->cur[0], ctxt->input->cur[1],
  504. ctxt->input->cur[2], ctxt->input->cur[3]);
  505. } else {
  506. snprintf(buffer, 149, "Bytes: 0x%02X\n", ctxt->input->cur[0]);
  507. }
  508. htmlParseErr(ctxt, XML_ERR_INVALID_ENCODING,
  509. "Input is not proper UTF-8, indicate encoding !\n",
  510. BAD_CAST buffer, NULL);
  511. }
  512. /*
  513. * Don't switch encodings twice. Note that if there's an encoder, we
  514. * shouldn't receive invalid UTF-8 anyway.
  515. *
  516. * Note that if ctxt->input->buf == NULL, switching encodings is
  517. * impossible, see Gitlab issue #34.
  518. */
  519. if ((ctxt->input->buf != NULL) &&
  520. (ctxt->input->buf->encoder == NULL))
  521. xmlSwitchEncoding(ctxt, XML_CHAR_ENCODING_8859_1);
  522. *len = 1;
  523. return((int) *ctxt->input->cur);
  524. }
  525. /**
  526. * htmlSkipBlankChars:
  527. * @ctxt: the HTML parser context
  528. *
  529. * skip all blanks character found at that point in the input streams.
  530. *
  531. * Returns the number of space chars skipped
  532. */
  533. static int
  534. htmlSkipBlankChars(xmlParserCtxtPtr ctxt) {
  535. int res = 0;
  536. while (IS_BLANK_CH(*(ctxt->input->cur))) {
  537. if ((*ctxt->input->cur == 0) &&
  538. (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) {
  539. xmlPopInput(ctxt);
  540. } else {
  541. if (*(ctxt->input->cur) == '\n') {
  542. ctxt->input->line++; ctxt->input->col = 1;
  543. } else ctxt->input->col++;
  544. ctxt->input->cur++;
  545. if (*ctxt->input->cur == 0)
  546. xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
  547. }
  548. if (res < INT_MAX)
  549. res++;
  550. }
  551. return(res);
  552. }
  553. /************************************************************************
  554. * *
  555. * The list of HTML elements and their properties *
  556. * *
  557. ************************************************************************/
  558. /*
  559. * Start Tag: 1 means the start tag can be omitted
  560. * End Tag: 1 means the end tag can be omitted
  561. * 2 means it's forbidden (empty elements)
  562. * 3 means the tag is stylistic and should be closed easily
  563. * Depr: this element is deprecated
  564. * DTD: 1 means that this element is valid only in the Loose DTD
  565. * 2 means that this element is valid only in the Frameset DTD
  566. *
  567. * Name,Start Tag,End Tag,Save End,Empty,Deprecated,DTD,inline,Description
  568. , subElements , impliedsubelt , Attributes, userdata
  569. */
  570. /* Definitions and a couple of vars for HTML Elements */
  571. #define FONTSTYLE "tt", "i", "b", "u", "s", "strike", "big", "small"
  572. #define NB_FONTSTYLE 8
  573. #define PHRASE "em", "strong", "dfn", "code", "samp", "kbd", "var", "cite", "abbr", "acronym"
  574. #define NB_PHRASE 10
  575. #define SPECIAL "a", "img", "applet", "embed", "object", "font", "basefont", "br", "script", "map", "q", "sub", "sup", "span", "bdo", "iframe"
  576. #define NB_SPECIAL 16
  577. #define INLINE FONTSTYLE, PHRASE, SPECIAL, FORMCTRL
  578. #define NB_INLINE NB_PCDATA + NB_FONTSTYLE + NB_PHRASE + NB_SPECIAL + NB_FORMCTRL
  579. #define BLOCK HEADING, LIST, "pre", "p", "dl", "div", "center", "noscript", "noframes", "blockquote", "form", "isindex", "hr", "table", "fieldset", "address"
  580. #define NB_BLOCK NB_HEADING + NB_LIST + 14
  581. #define FORMCTRL "input", "select", "textarea", "label", "button"
  582. #define NB_FORMCTRL 5
  583. #define PCDATA
  584. #define NB_PCDATA 0
  585. #define HEADING "h1", "h2", "h3", "h4", "h5", "h6"
  586. #define NB_HEADING 6
  587. #define LIST "ul", "ol", "dir", "menu"
  588. #define NB_LIST 4
  589. #define MODIFIER
  590. #define NB_MODIFIER 0
  591. #define FLOW BLOCK,INLINE
  592. #define NB_FLOW NB_BLOCK + NB_INLINE
  593. #define EMPTY NULL
  594. static const char* const html_flow[] = { FLOW, NULL } ;
  595. static const char* const html_inline[] = { INLINE, NULL } ;
  596. /* placeholders: elts with content but no subelements */
  597. static const char* const html_pcdata[] = { NULL } ;
  598. #define html_cdata html_pcdata
  599. /* ... and for HTML Attributes */
  600. #define COREATTRS "id", "class", "style", "title"
  601. #define NB_COREATTRS 4
  602. #define I18N "lang", "dir"
  603. #define NB_I18N 2
  604. #define EVENTS "onclick", "ondblclick", "onmousedown", "onmouseup", "onmouseover", "onmouseout", "onkeypress", "onkeydown", "onkeyup"
  605. #define NB_EVENTS 9
  606. #define ATTRS COREATTRS,I18N,EVENTS
  607. #define NB_ATTRS NB_NB_COREATTRS + NB_I18N + NB_EVENTS
  608. #define CELLHALIGN "align", "char", "charoff"
  609. #define NB_CELLHALIGN 3
  610. #define CELLVALIGN "valign"
  611. #define NB_CELLVALIGN 1
  612. static const char* const html_attrs[] = { ATTRS, NULL } ;
  613. static const char* const core_i18n_attrs[] = { COREATTRS, I18N, NULL } ;
  614. static const char* const core_attrs[] = { COREATTRS, NULL } ;
  615. static const char* const i18n_attrs[] = { I18N, NULL } ;
  616. /* Other declarations that should go inline ... */
  617. static const char* const a_attrs[] = { ATTRS, "charset", "type", "name",
  618. "href", "hreflang", "rel", "rev", "accesskey", "shape", "coords",
  619. "tabindex", "onfocus", "onblur", NULL } ;
  620. static const char* const target_attr[] = { "target", NULL } ;
  621. static const char* const rows_cols_attr[] = { "rows", "cols", NULL } ;
  622. static const char* const alt_attr[] = { "alt", NULL } ;
  623. static const char* const src_alt_attrs[] = { "src", "alt", NULL } ;
  624. static const char* const href_attrs[] = { "href", NULL } ;
  625. static const char* const clear_attrs[] = { "clear", NULL } ;
  626. static const char* const inline_p[] = { INLINE, "p", NULL } ;
  627. static const char* const flow_param[] = { FLOW, "param", NULL } ;
  628. static const char* const applet_attrs[] = { COREATTRS , "codebase",
  629. "archive", "alt", "name", "height", "width", "align",
  630. "hspace", "vspace", NULL } ;
  631. static const char* const area_attrs[] = { "shape", "coords", "href", "nohref",
  632. "tabindex", "accesskey", "onfocus", "onblur", NULL } ;
  633. static const char* const basefont_attrs[] =
  634. { "id", "size", "color", "face", NULL } ;
  635. static const char* const quote_attrs[] = { ATTRS, "cite", NULL } ;
  636. static const char* const body_contents[] = { FLOW, "ins", "del", NULL } ;
  637. static const char* const body_attrs[] = { ATTRS, "onload", "onunload", NULL } ;
  638. static const char* const body_depr[] = { "background", "bgcolor", "text",
  639. "link", "vlink", "alink", NULL } ;
  640. static const char* const button_attrs[] = { ATTRS, "name", "value", "type",
  641. "disabled", "tabindex", "accesskey", "onfocus", "onblur", NULL } ;
  642. static const char* const col_attrs[] = { ATTRS, "span", "width", CELLHALIGN, CELLVALIGN, NULL } ;
  643. static const char* const col_elt[] = { "col", NULL } ;
  644. static const char* const edit_attrs[] = { ATTRS, "datetime", "cite", NULL } ;
  645. static const char* const compact_attrs[] = { ATTRS, "compact", NULL } ;
  646. static const char* const dl_contents[] = { "dt", "dd", NULL } ;
  647. static const char* const compact_attr[] = { "compact", NULL } ;
  648. static const char* const label_attr[] = { "label", NULL } ;
  649. static const char* const fieldset_contents[] = { FLOW, "legend" } ;
  650. static const char* const font_attrs[] = { COREATTRS, I18N, "size", "color", "face" , NULL } ;
  651. static const char* const form_contents[] = { HEADING, LIST, INLINE, "pre", "p", "div", "center", "noscript", "noframes", "blockquote", "isindex", "hr", "table", "fieldset", "address", NULL } ;
  652. static const char* const form_attrs[] = { ATTRS, "method", "enctype", "accept", "name", "onsubmit", "onreset", "accept-charset", NULL } ;
  653. static const char* const frame_attrs[] = { COREATTRS, "longdesc", "name", "src", "frameborder", "marginwidth", "marginheight", "noresize", "scrolling" , NULL } ;
  654. static const char* const frameset_attrs[] = { COREATTRS, "rows", "cols", "onload", "onunload", NULL } ;
  655. static const char* const frameset_contents[] = { "frameset", "frame", "noframes", NULL } ;
  656. static const char* const head_attrs[] = { I18N, "profile", NULL } ;
  657. static const char* const head_contents[] = { "title", "isindex", "base", "script", "style", "meta", "link", "object", NULL } ;
  658. static const char* const hr_depr[] = { "align", "noshade", "size", "width", NULL } ;
  659. static const char* const version_attr[] = { "version", NULL } ;
  660. static const char* const html_content[] = { "head", "body", "frameset", NULL } ;
  661. static const char* const iframe_attrs[] = { COREATTRS, "longdesc", "name", "src", "frameborder", "marginwidth", "marginheight", "scrolling", "align", "height", "width", NULL } ;
  662. static const char* const img_attrs[] = { ATTRS, "longdesc", "name", "height", "width", "usemap", "ismap", NULL } ;
  663. static const char* const embed_attrs[] = { COREATTRS, "align", "alt", "border", "code", "codebase", "frameborder", "height", "hidden", "hspace", "name", "palette", "pluginspace", "pluginurl", "src", "type", "units", "vspace", "width", NULL } ;
  664. static const char* const input_attrs[] = { ATTRS, "type", "name", "value", "checked", "disabled", "readonly", "size", "maxlength", "src", "alt", "usemap", "ismap", "tabindex", "accesskey", "onfocus", "onblur", "onselect", "onchange", "accept", NULL } ;
  665. static const char* const prompt_attrs[] = { COREATTRS, I18N, "prompt", NULL } ;
  666. static const char* const label_attrs[] = { ATTRS, "for", "accesskey", "onfocus", "onblur", NULL } ;
  667. static const char* const legend_attrs[] = { ATTRS, "accesskey", NULL } ;
  668. static const char* const align_attr[] = { "align", NULL } ;
  669. static const char* const link_attrs[] = { ATTRS, "charset", "href", "hreflang", "type", "rel", "rev", "media", NULL } ;
  670. static const char* const map_contents[] = { BLOCK, "area", NULL } ;
  671. static const char* const name_attr[] = { "name", NULL } ;
  672. static const char* const action_attr[] = { "action", NULL } ;
  673. static const char* const blockli_elt[] = { BLOCK, "li", NULL } ;
  674. static const char* const meta_attrs[] = { I18N, "http-equiv", "name", "scheme", "charset", NULL } ;
  675. static const char* const content_attr[] = { "content", NULL } ;
  676. static const char* const type_attr[] = { "type", NULL } ;
  677. static const char* const noframes_content[] = { "body", FLOW MODIFIER, NULL } ;
  678. static const char* const object_contents[] = { FLOW, "param", NULL } ;
  679. static const char* const object_attrs[] = { ATTRS, "declare", "classid", "codebase", "data", "type", "codetype", "archive", "standby", "height", "width", "usemap", "name", "tabindex", NULL } ;
  680. static const char* const object_depr[] = { "align", "border", "hspace", "vspace", NULL } ;
  681. static const char* const ol_attrs[] = { "type", "compact", "start", NULL} ;
  682. static const char* const option_elt[] = { "option", NULL } ;
  683. static const char* const optgroup_attrs[] = { ATTRS, "disabled", NULL } ;
  684. static const char* const option_attrs[] = { ATTRS, "disabled", "label", "selected", "value", NULL } ;
  685. static const char* const param_attrs[] = { "id", "value", "valuetype", "type", NULL } ;
  686. static const char* const width_attr[] = { "width", NULL } ;
  687. static const char* const pre_content[] = { PHRASE, "tt", "i", "b", "u", "s", "strike", "a", "br", "script", "map", "q", "span", "bdo", "iframe", NULL } ;
  688. static const char* const script_attrs[] = { "charset", "src", "defer", "event", "for", NULL } ;
  689. static const char* const language_attr[] = { "language", NULL } ;
  690. static const char* const select_content[] = { "optgroup", "option", NULL } ;
  691. static const char* const select_attrs[] = { ATTRS, "name", "size", "multiple", "disabled", "tabindex", "onfocus", "onblur", "onchange", NULL } ;
  692. static const char* const style_attrs[] = { I18N, "media", "title", NULL } ;
  693. static const char* const table_attrs[] = { ATTRS, "summary", "width", "border", "frame", "rules", "cellspacing", "cellpadding", "datapagesize", NULL } ;
  694. static const char* const table_depr[] = { "align", "bgcolor", NULL } ;
  695. static const char* const table_contents[] = { "caption", "col", "colgroup", "thead", "tfoot", "tbody", "tr", NULL} ;
  696. static const char* const tr_elt[] = { "tr", NULL } ;
  697. static const char* const talign_attrs[] = { ATTRS, CELLHALIGN, CELLVALIGN, NULL} ;
  698. static const char* const th_td_depr[] = { "nowrap", "bgcolor", "width", "height", NULL } ;
  699. static const char* const th_td_attr[] = { ATTRS, "abbr", "axis", "headers", "scope", "rowspan", "colspan", CELLHALIGN, CELLVALIGN, NULL } ;
  700. static const char* const textarea_attrs[] = { ATTRS, "name", "disabled", "readonly", "tabindex", "accesskey", "onfocus", "onblur", "onselect", "onchange", NULL } ;
  701. static const char* const tr_contents[] = { "th", "td", NULL } ;
  702. static const char* const bgcolor_attr[] = { "bgcolor", NULL } ;
  703. static const char* const li_elt[] = { "li", NULL } ;
  704. static const char* const ul_depr[] = { "type", "compact", NULL} ;
  705. static const char* const dir_attr[] = { "dir", NULL} ;
  706. #define DECL (const char**)
  707. static const htmlElemDesc
  708. html40ElementTable[] = {
  709. { "a", 0, 0, 0, 0, 0, 0, 1, "anchor ",
  710. DECL html_inline , NULL , DECL a_attrs , DECL target_attr, NULL
  711. },
  712. { "abbr", 0, 0, 0, 0, 0, 0, 1, "abbreviated form",
  713. DECL html_inline , NULL , DECL html_attrs, NULL, NULL
  714. },
  715. { "acronym", 0, 0, 0, 0, 0, 0, 1, "",
  716. DECL html_inline , NULL , DECL html_attrs, NULL, NULL
  717. },
  718. { "address", 0, 0, 0, 0, 0, 0, 0, "information on author ",
  719. DECL inline_p , NULL , DECL html_attrs, NULL, NULL
  720. },
  721. { "applet", 0, 0, 0, 0, 1, 1, 2, "java applet ",
  722. DECL flow_param , NULL , NULL , DECL applet_attrs, NULL
  723. },
  724. { "area", 0, 2, 2, 1, 0, 0, 0, "client-side image map area ",
  725. EMPTY , NULL , DECL area_attrs , DECL target_attr, DECL alt_attr
  726. },
  727. { "b", 0, 3, 0, 0, 0, 0, 1, "bold text style",
  728. DECL html_inline , NULL , DECL html_attrs, NULL, NULL
  729. },
  730. { "base", 0, 2, 2, 1, 0, 0, 0, "document base uri ",
  731. EMPTY , NULL , NULL , DECL target_attr, DECL href_attrs
  732. },
  733. { "basefont", 0, 2, 2, 1, 1, 1, 1, "base font size " ,
  734. EMPTY , NULL , NULL, DECL basefont_attrs, NULL
  735. },
  736. { "bdo", 0, 0, 0, 0, 0, 0, 1, "i18n bidi over-ride ",
  737. DECL html_inline , NULL , DECL core_i18n_attrs, NULL, DECL dir_attr
  738. },
  739. { "big", 0, 3, 0, 0, 0, 0, 1, "large text style",
  740. DECL html_inline , NULL , DECL html_attrs, NULL, NULL
  741. },
  742. { "blockquote", 0, 0, 0, 0, 0, 0, 0, "long quotation ",
  743. DECL html_flow , NULL , DECL quote_attrs , NULL, NULL
  744. },
  745. { "body", 1, 1, 0, 0, 0, 0, 0, "document body ",
  746. DECL body_contents , "div" , DECL body_attrs, DECL body_depr, NULL
  747. },
  748. { "br", 0, 2, 2, 1, 0, 0, 1, "forced line break ",
  749. EMPTY , NULL , DECL core_attrs, DECL clear_attrs , NULL
  750. },
  751. { "button", 0, 0, 0, 0, 0, 0, 2, "push button ",
  752. DECL html_flow MODIFIER , NULL , DECL button_attrs, NULL, NULL
  753. },
  754. { "caption", 0, 0, 0, 0, 0, 0, 0, "table caption ",
  755. DECL html_inline , NULL , DECL html_attrs, NULL, NULL
  756. },
  757. { "center", 0, 3, 0, 0, 1, 1, 0, "shorthand for div align=center ",
  758. DECL html_flow , NULL , NULL, DECL html_attrs, NULL
  759. },
  760. { "cite", 0, 0, 0, 0, 0, 0, 1, "citation",
  761. DECL html_inline , NULL , DECL html_attrs, NULL, NULL
  762. },
  763. { "code", 0, 0, 0, 0, 0, 0, 1, "computer code fragment",
  764. DECL html_inline , NULL , DECL html_attrs, NULL, NULL
  765. },
  766. { "col", 0, 2, 2, 1, 0, 0, 0, "table column ",
  767. EMPTY , NULL , DECL col_attrs , NULL, NULL
  768. },
  769. { "colgroup", 0, 1, 0, 0, 0, 0, 0, "table column group ",
  770. DECL col_elt , "col" , DECL col_attrs , NULL, NULL
  771. },
  772. { "dd", 0, 1, 0, 0, 0, 0, 0, "definition description ",
  773. DECL html_flow , NULL , DECL html_attrs, NULL, NULL
  774. },
  775. { "del", 0, 0, 0, 0, 0, 0, 2, "deleted text ",
  776. DECL html_flow , NULL , DECL edit_attrs , NULL, NULL
  777. },
  778. { "dfn", 0, 0, 0, 0, 0, 0, 1, "instance definition",
  779. DECL html_inline , NULL , DECL html_attrs, NULL, NULL
  780. },
  781. { "dir", 0, 0, 0, 0, 1, 1, 0, "directory list",
  782. DECL blockli_elt, "li" , NULL, DECL compact_attrs, NULL
  783. },
  784. { "div", 0, 0, 0, 0, 0, 0, 0, "generic language/style container",
  785. DECL html_flow, NULL, DECL html_attrs, DECL align_attr, NULL
  786. },
  787. { "dl", 0, 0, 0, 0, 0, 0, 0, "definition list ",
  788. DECL dl_contents , "dd" , DECL html_attrs, DECL compact_attr, NULL
  789. },
  790. { "dt", 0, 1, 0, 0, 0, 0, 0, "definition term ",
  791. DECL html_inline, NULL, DECL html_attrs, NULL, NULL
  792. },
  793. { "em", 0, 3, 0, 0, 0, 0, 1, "emphasis",
  794. DECL html_inline, NULL, DECL html_attrs, NULL, NULL
  795. },
  796. { "embed", 0, 1, 0, 0, 1, 1, 1, "generic embedded object ",
  797. EMPTY, NULL, DECL embed_attrs, NULL, NULL
  798. },
  799. { "fieldset", 0, 0, 0, 0, 0, 0, 0, "form control group ",
  800. DECL fieldset_contents , NULL, DECL html_attrs, NULL, NULL
  801. },
  802. { "font", 0, 3, 0, 0, 1, 1, 1, "local change to font ",
  803. DECL html_inline, NULL, NULL, DECL font_attrs, NULL
  804. },
  805. { "form", 0, 0, 0, 0, 0, 0, 0, "interactive form ",
  806. DECL form_contents, "fieldset", DECL form_attrs , DECL target_attr, DECL action_attr
  807. },
  808. { "frame", 0, 2, 2, 1, 0, 2, 0, "subwindow " ,
  809. EMPTY, NULL, NULL, DECL frame_attrs, NULL
  810. },
  811. { "frameset", 0, 0, 0, 0, 0, 2, 0, "window subdivision" ,
  812. DECL frameset_contents, "noframes" , NULL , DECL frameset_attrs, NULL
  813. },
  814. { "h1", 0, 0, 0, 0, 0, 0, 0, "heading ",
  815. DECL html_inline, NULL, DECL html_attrs, DECL align_attr, NULL
  816. },
  817. { "h2", 0, 0, 0, 0, 0, 0, 0, "heading ",
  818. DECL html_inline, NULL, DECL html_attrs, DECL align_attr, NULL
  819. },
  820. { "h3", 0, 0, 0, 0, 0, 0, 0, "heading ",
  821. DECL html_inline, NULL, DECL html_attrs, DECL align_attr, NULL
  822. },
  823. { "h4", 0, 0, 0, 0, 0, 0, 0, "heading ",
  824. DECL html_inline, NULL, DECL html_attrs, DECL align_attr, NULL
  825. },
  826. { "h5", 0, 0, 0, 0, 0, 0, 0, "heading ",
  827. DECL html_inline, NULL, DECL html_attrs, DECL align_attr, NULL
  828. },
  829. { "h6", 0, 0, 0, 0, 0, 0, 0, "heading ",
  830. DECL html_inline, NULL, DECL html_attrs, DECL align_attr, NULL
  831. },
  832. { "head", 1, 1, 0, 0, 0, 0, 0, "document head ",
  833. DECL head_contents, NULL, DECL head_attrs, NULL, NULL
  834. },
  835. { "hr", 0, 2, 2, 1, 0, 0, 0, "horizontal rule " ,
  836. EMPTY, NULL, DECL html_attrs, DECL hr_depr, NULL
  837. },
  838. { "html", 1, 1, 0, 0, 0, 0, 0, "document root element ",
  839. DECL html_content , NULL , DECL i18n_attrs, DECL version_attr, NULL
  840. },
  841. { "i", 0, 3, 0, 0, 0, 0, 1, "italic text style",
  842. DECL html_inline, NULL, DECL html_attrs, NULL, NULL
  843. },
  844. { "iframe", 0, 0, 0, 0, 0, 1, 2, "inline subwindow ",
  845. DECL html_flow, NULL, NULL, DECL iframe_attrs, NULL
  846. },
  847. { "img", 0, 2, 2, 1, 0, 0, 1, "embedded image ",
  848. EMPTY, NULL, DECL img_attrs, DECL align_attr, DECL src_alt_attrs
  849. },
  850. { "input", 0, 2, 2, 1, 0, 0, 1, "form control ",
  851. EMPTY, NULL, DECL input_attrs , DECL align_attr, NULL
  852. },
  853. { "ins", 0, 0, 0, 0, 0, 0, 2, "inserted text",
  854. DECL html_flow, NULL, DECL edit_attrs, NULL, NULL
  855. },
  856. { "isindex", 0, 2, 2, 1, 1, 1, 0, "single line prompt ",
  857. EMPTY, NULL, NULL, DECL prompt_attrs, NULL
  858. },
  859. { "kbd", 0, 0, 0, 0, 0, 0, 1, "text to be entered by the user",
  860. DECL html_inline, NULL, DECL html_attrs, NULL, NULL
  861. },
  862. { "label", 0, 0, 0, 0, 0, 0, 1, "form field label text ",
  863. DECL html_inline MODIFIER, NULL, DECL label_attrs , NULL, NULL
  864. },
  865. { "legend", 0, 0, 0, 0, 0, 0, 0, "fieldset legend ",
  866. DECL html_inline, NULL, DECL legend_attrs , DECL align_attr, NULL
  867. },
  868. { "li", 0, 1, 1, 0, 0, 0, 0, "list item ",
  869. DECL html_flow, NULL, DECL html_attrs, NULL, NULL
  870. },
  871. { "link", 0, 2, 2, 1, 0, 0, 0, "a media-independent link ",
  872. EMPTY, NULL, DECL link_attrs, DECL target_attr, NULL
  873. },
  874. { "map", 0, 0, 0, 0, 0, 0, 2, "client-side image map ",
  875. DECL map_contents , NULL, DECL html_attrs , NULL, DECL name_attr
  876. },
  877. { "menu", 0, 0, 0, 0, 1, 1, 0, "menu list ",
  878. DECL blockli_elt , NULL, NULL, DECL compact_attrs, NULL
  879. },
  880. { "meta", 0, 2, 2, 1, 0, 0, 0, "generic metainformation ",
  881. EMPTY, NULL, DECL meta_attrs , NULL , DECL content_attr
  882. },
  883. { "noframes", 0, 0, 0, 0, 0, 2, 0, "alternate content container for non frame-based rendering ",
  884. DECL noframes_content, "body" , DECL html_attrs, NULL, NULL
  885. },
  886. { "noscript", 0, 0, 0, 0, 0, 0, 0, "alternate content container for non script-based rendering ",
  887. DECL html_flow, "div", DECL html_attrs, NULL, NULL
  888. },
  889. { "object", 0, 0, 0, 0, 0, 0, 2, "generic embedded object ",
  890. DECL object_contents , "div" , DECL object_attrs, DECL object_depr, NULL
  891. },
  892. { "ol", 0, 0, 0, 0, 0, 0, 0, "ordered list ",
  893. DECL li_elt , "li" , DECL html_attrs, DECL ol_attrs, NULL
  894. },
  895. { "optgroup", 0, 0, 0, 0, 0, 0, 0, "option group ",
  896. DECL option_elt , "option", DECL optgroup_attrs, NULL, DECL label_attr
  897. },
  898. { "option", 0, 1, 0, 0, 0, 0, 0, "selectable choice " ,
  899. DECL html_pcdata, NULL, DECL option_attrs, NULL, NULL
  900. },
  901. { "p", 0, 1, 0, 0, 0, 0, 0, "paragraph ",
  902. DECL html_inline, NULL, DECL html_attrs, DECL align_attr, NULL
  903. },
  904. { "param", 0, 2, 2, 1, 0, 0, 0, "named property value ",
  905. EMPTY, NULL, DECL param_attrs, NULL, DECL name_attr
  906. },
  907. { "pre", 0, 0, 0, 0, 0, 0, 0, "preformatted text ",
  908. DECL pre_content, NULL, DECL html_attrs, DECL width_attr, NULL
  909. },
  910. { "q", 0, 0, 0, 0, 0, 0, 1, "short inline quotation ",
  911. DECL html_inline, NULL, DECL quote_attrs, NULL, NULL
  912. },
  913. { "s", 0, 3, 0, 0, 1, 1, 1, "strike-through text style",
  914. DECL html_inline, NULL, NULL, DECL html_attrs, NULL
  915. },
  916. { "samp", 0, 0, 0, 0, 0, 0, 1, "sample program output, scripts, etc.",
  917. DECL html_inline, NULL, DECL html_attrs, NULL, NULL
  918. },
  919. { "script", 0, 0, 0, 0, 0, 0, 2, "script statements ",
  920. DECL html_cdata, NULL, DECL script_attrs, DECL language_attr, DECL type_attr
  921. },
  922. { "select", 0, 0, 0, 0, 0, 0, 1, "option selector ",
  923. DECL select_content, NULL, DECL select_attrs, NULL, NULL
  924. },
  925. { "small", 0, 3, 0, 0, 0, 0, 1, "small text style",
  926. DECL html_inline, NULL, DECL html_attrs, NULL, NULL
  927. },
  928. { "span", 0, 0, 0, 0, 0, 0, 1, "generic language/style container ",
  929. DECL html_inline, NULL, DECL html_attrs, NULL, NULL
  930. },
  931. { "strike", 0, 3, 0, 0, 1, 1, 1, "strike-through text",
  932. DECL html_inline, NULL, NULL, DECL html_attrs, NULL
  933. },
  934. { "strong", 0, 3, 0, 0, 0, 0, 1, "strong emphasis",
  935. DECL html_inline, NULL, DECL html_attrs, NULL, NULL
  936. },
  937. { "style", 0, 0, 0, 0, 0, 0, 0, "style info ",
  938. DECL html_cdata, NULL, DECL style_attrs, NULL, DECL type_attr
  939. },
  940. { "sub", 0, 3, 0, 0, 0, 0, 1, "subscript",
  941. DECL html_inline, NULL, DECL html_attrs, NULL, NULL
  942. },
  943. { "sup", 0, 3, 0, 0, 0, 0, 1, "superscript ",
  944. DECL html_inline, NULL, DECL html_attrs, NULL, NULL
  945. },
  946. { "table", 0, 0, 0, 0, 0, 0, 0, "",
  947. DECL table_contents , "tr" , DECL table_attrs , DECL table_depr, NULL
  948. },
  949. { "tbody", 1, 0, 0, 0, 0, 0, 0, "table body ",
  950. DECL tr_elt , "tr" , DECL talign_attrs, NULL, NULL
  951. },
  952. { "td", 0, 0, 0, 0, 0, 0, 0, "table data cell",
  953. DECL html_flow, NULL, DECL th_td_attr, DECL th_td_depr, NULL
  954. },
  955. { "textarea", 0, 0, 0, 0, 0, 0, 1, "multi-line text field ",
  956. DECL html_pcdata, NULL, DECL textarea_attrs, NULL, DECL rows_cols_attr
  957. },
  958. { "tfoot", 0, 1, 0, 0, 0, 0, 0, "table footer ",
  959. DECL tr_elt , "tr" , DECL talign_attrs, NULL, NULL
  960. },
  961. { "th", 0, 1, 0, 0, 0, 0, 0, "table header cell",
  962. DECL html_flow, NULL, DECL th_td_attr, DECL th_td_depr, NULL
  963. },
  964. { "thead", 0, 1, 0, 0, 0, 0, 0, "table header ",
  965. DECL tr_elt , "tr" , DECL talign_attrs, NULL, NULL
  966. },
  967. { "title", 0, 0, 0, 0, 0, 0, 0, "document title ",
  968. DECL html_pcdata, NULL, DECL i18n_attrs, NULL, NULL
  969. },
  970. { "tr", 0, 0, 0, 0, 0, 0, 0, "table row ",
  971. DECL tr_contents , "td" , DECL talign_attrs, DECL bgcolor_attr, NULL
  972. },
  973. { "tt", 0, 3, 0, 0, 0, 0, 1, "teletype or monospaced text style",
  974. DECL html_inline, NULL, DECL html_attrs, NULL, NULL
  975. },
  976. { "u", 0, 3, 0, 0, 1, 1, 1, "underlined text style",
  977. DECL html_inline, NULL, NULL, DECL html_attrs, NULL
  978. },
  979. { "ul", 0, 0, 0, 0, 0, 0, 0, "unordered list ",
  980. DECL li_elt , "li" , DECL html_attrs, DECL ul_depr, NULL
  981. },
  982. { "var", 0, 0, 0, 0, 0, 0, 1, "instance of a variable or program argument",
  983. DECL html_inline, NULL, DECL html_attrs, NULL, NULL
  984. }
  985. };
  986. typedef struct {
  987. const char *oldTag;
  988. const char *newTag;
  989. } htmlStartCloseEntry;
  990. /*
  991. * start tags that imply the end of current element
  992. */
  993. static const htmlStartCloseEntry htmlStartClose[] = {
  994. { "a", "a" },
  995. { "a", "fieldset" },
  996. { "a", "table" },
  997. { "a", "td" },
  998. { "a", "th" },
  999. { "address", "dd" },
  1000. { "address", "dl" },
  1001. { "address", "dt" },
  1002. { "address", "form" },
  1003. { "address", "li" },
  1004. { "address", "ul" },
  1005. { "b", "center" },
  1006. { "b", "p" },
  1007. { "b", "td" },
  1008. { "b", "th" },
  1009. { "big", "p" },
  1010. { "caption", "col" },
  1011. { "caption", "colgroup" },
  1012. { "caption", "tbody" },
  1013. { "caption", "tfoot" },
  1014. { "caption", "thead" },
  1015. { "caption", "tr" },
  1016. { "col", "col" },
  1017. { "col", "colgroup" },
  1018. { "col", "tbody" },
  1019. { "col", "tfoot" },
  1020. { "col", "thead" },
  1021. { "col", "tr" },
  1022. { "colgroup", "colgroup" },
  1023. { "colgroup", "tbody" },
  1024. { "colgroup", "tfoot" },
  1025. { "colgroup", "thead" },
  1026. { "colgroup", "tr" },
  1027. { "dd", "dt" },
  1028. { "dir", "dd" },
  1029. { "dir", "dl" },
  1030. { "dir", "dt" },
  1031. { "dir", "form" },
  1032. { "dir", "ul" },
  1033. { "dl", "form" },
  1034. { "dl", "li" },
  1035. { "dt", "dd" },
  1036. { "dt", "dl" },
  1037. { "font", "center" },
  1038. { "font", "td" },
  1039. { "font", "th" },
  1040. { "form", "form" },
  1041. { "h1", "fieldset" },
  1042. { "h1", "form" },
  1043. { "h1", "li" },
  1044. { "h1", "p" },
  1045. { "h1", "table" },
  1046. { "h2", "fieldset" },
  1047. { "h2", "form" },
  1048. { "h2", "li" },
  1049. { "h2", "p" },
  1050. { "h2", "table" },
  1051. { "h3", "fieldset" },
  1052. { "h3", "form" },
  1053. { "h3", "li" },
  1054. { "h3", "p" },
  1055. { "h3", "table" },
  1056. { "h4", "fieldset" },
  1057. { "h4", "form" },
  1058. { "h4", "li" },
  1059. { "h4", "p" },
  1060. { "h4", "table" },
  1061. { "h5", "fieldset" },
  1062. { "h5", "form" },
  1063. { "h5", "li" },
  1064. { "h5", "p" },
  1065. { "h5", "table" },
  1066. { "h6", "fieldset" },
  1067. { "h6", "form" },
  1068. { "h6", "li" },
  1069. { "h6", "p" },
  1070. { "h6", "table" },
  1071. { "head", "a" },
  1072. { "head", "abbr" },
  1073. { "head", "acronym" },
  1074. { "head", "address" },
  1075. { "head", "b" },
  1076. { "head", "bdo" },
  1077. { "head", "big" },
  1078. { "head", "blockquote" },
  1079. { "head", "body" },
  1080. { "head", "br" },
  1081. { "head", "center" },
  1082. { "head", "cite" },
  1083. { "head", "code" },
  1084. { "head", "dd" },
  1085. { "head", "dfn" },
  1086. { "head", "dir" },
  1087. { "head", "div" },
  1088. { "head", "dl" },
  1089. { "head", "dt" },
  1090. { "head", "em" },
  1091. { "head", "fieldset" },
  1092. { "head", "font" },
  1093. { "head", "form" },
  1094. { "head", "frameset" },
  1095. { "head", "h1" },
  1096. { "head", "h2" },
  1097. { "head", "h3" },
  1098. { "head", "h4" },
  1099. { "head", "h5" },
  1100. { "head", "h6" },
  1101. { "head", "hr" },
  1102. { "head", "i" },
  1103. { "head", "iframe" },
  1104. { "head", "img" },
  1105. { "head", "kbd" },
  1106. { "head", "li" },
  1107. { "head", "listing" },
  1108. { "head", "map" },
  1109. { "head", "menu" },
  1110. { "head", "ol" },
  1111. { "head", "p" },
  1112. { "head", "pre" },
  1113. { "head", "q" },
  1114. { "head", "s" },
  1115. { "head", "samp" },
  1116. { "head", "small" },
  1117. { "head", "span" },
  1118. { "head", "strike" },
  1119. { "head", "strong" },
  1120. { "head", "sub" },
  1121. { "head", "sup" },
  1122. { "head", "table" },
  1123. { "head", "tt" },
  1124. { "head", "u" },
  1125. { "head", "ul" },
  1126. { "head", "var" },
  1127. { "head", "xmp" },
  1128. { "hr", "form" },
  1129. { "i", "center" },
  1130. { "i", "p" },
  1131. { "i", "td" },
  1132. { "i", "th" },
  1133. { "legend", "fieldset" },
  1134. { "li", "li" },
  1135. { "link", "body" },
  1136. { "link", "frameset" },
  1137. { "listing", "dd" },
  1138. { "listing", "dl" },
  1139. { "listing", "dt" },
  1140. { "listing", "fieldset" },
  1141. { "listing", "form" },
  1142. { "listing", "li" },
  1143. { "listing", "table" },
  1144. { "listing", "ul" },
  1145. { "menu", "dd" },
  1146. { "menu", "dl" },
  1147. { "menu", "dt" },
  1148. { "menu", "form" },
  1149. { "menu", "ul" },
  1150. { "ol", "form" },
  1151. { "ol", "ul" },
  1152. { "option", "optgroup" },
  1153. { "option", "option" },
  1154. { "p", "address" },
  1155. { "p", "blockquote" },
  1156. { "p", "body" },
  1157. { "p", "caption" },
  1158. { "p", "center" },
  1159. { "p", "col" },
  1160. { "p", "colgroup" },
  1161. { "p", "dd" },
  1162. { "p", "dir" },
  1163. { "p", "div" },
  1164. { "p", "dl" },
  1165. { "p", "dt" },
  1166. { "p", "fieldset" },
  1167. { "p", "form" },
  1168. { "p", "frameset" },
  1169. { "p", "h1" },
  1170. { "p", "h2" },
  1171. { "p", "h3" },
  1172. { "p", "h4" },
  1173. { "p", "h5" },
  1174. { "p", "h6" },
  1175. { "p", "head" },
  1176. { "p", "hr" },
  1177. { "p", "li" },
  1178. { "p", "listing" },
  1179. { "p", "menu" },
  1180. { "p", "ol" },
  1181. { "p", "p" },
  1182. { "p", "pre" },
  1183. { "p", "table" },
  1184. { "p", "tbody" },
  1185. { "p", "td" },
  1186. { "p", "tfoot" },
  1187. { "p", "th" },
  1188. { "p", "title" },
  1189. { "p", "tr" },
  1190. { "p", "ul" },
  1191. { "p", "xmp" },
  1192. { "pre", "dd" },
  1193. { "pre", "dl" },
  1194. { "pre", "dt" },
  1195. { "pre", "fieldset" },
  1196. { "pre", "form" },
  1197. { "pre", "li" },
  1198. { "pre", "table" },
  1199. { "pre", "ul" },
  1200. { "s", "p" },
  1201. { "script", "noscript" },
  1202. { "small", "p" },
  1203. { "span", "td" },
  1204. { "span", "th" },
  1205. { "strike", "p" },
  1206. { "style", "body" },
  1207. { "style", "frameset" },
  1208. { "tbody", "tbody" },
  1209. { "tbody", "tfoot" },
  1210. { "td", "tbody" },
  1211. { "td", "td" },
  1212. { "td", "tfoot" },
  1213. { "td", "th" },
  1214. { "td", "tr" },
  1215. { "tfoot", "tbody" },
  1216. { "th", "tbody" },
  1217. { "th", "td" },
  1218. { "th", "tfoot" },
  1219. { "th", "th" },
  1220. { "th", "tr" },
  1221. { "thead", "tbody" },
  1222. { "thead", "tfoot" },
  1223. { "title", "body" },
  1224. { "title", "frameset" },
  1225. { "tr", "tbody" },
  1226. { "tr", "tfoot" },
  1227. { "tr", "tr" },
  1228. { "tt", "p" },
  1229. { "u", "p" },
  1230. { "u", "td" },
  1231. { "u", "th" },
  1232. { "ul", "address" },
  1233. { "ul", "form" },
  1234. { "ul", "menu" },
  1235. { "ul", "ol" },
  1236. { "ul", "pre" },
  1237. { "xmp", "dd" },
  1238. { "xmp", "dl" },
  1239. { "xmp", "dt" },
  1240. { "xmp", "fieldset" },
  1241. { "xmp", "form" },
  1242. { "xmp", "li" },
  1243. { "xmp", "table" },
  1244. { "xmp", "ul" }
  1245. };
  1246. /*
  1247. * The list of HTML elements which are supposed not to have
  1248. * CDATA content and where a p element will be implied
  1249. *
  1250. * TODO: extend that list by reading the HTML SGML DTD on
  1251. * implied paragraph
  1252. */
  1253. static const char *const htmlNoContentElements[] = {
  1254. "html",
  1255. "head",
  1256. NULL
  1257. };
  1258. /*
  1259. * The list of HTML attributes which are of content %Script;
  1260. * NOTE: when adding ones, check htmlIsScriptAttribute() since
  1261. * it assumes the name starts with 'on'
  1262. */
  1263. static const char *const htmlScriptAttributes[] = {
  1264. "onclick",
  1265. "ondblclick",
  1266. "onmousedown",
  1267. "onmouseup",
  1268. "onmouseover",
  1269. "onmousemove",
  1270. "onmouseout",
  1271. "onkeypress",
  1272. "onkeydown",
  1273. "onkeyup",
  1274. "onload",
  1275. "onunload",
  1276. "onfocus",
  1277. "onblur",
  1278. "onsubmit",
  1279. "onreset",
  1280. "onchange",
  1281. "onselect"
  1282. };
  1283. /*
  1284. * This table is used by the htmlparser to know what to do with
  1285. * broken html pages. By assigning different priorities to different
  1286. * elements the parser can decide how to handle extra endtags.
  1287. * Endtags are only allowed to close elements with lower or equal
  1288. * priority.
  1289. */
  1290. typedef struct {
  1291. const char *name;
  1292. int priority;
  1293. } elementPriority;
  1294. static const elementPriority htmlEndPriority[] = {
  1295. {"div", 150},
  1296. {"td", 160},
  1297. {"th", 160},
  1298. {"tr", 170},
  1299. {"thead", 180},
  1300. {"tbody", 180},
  1301. {"tfoot", 180},
  1302. {"table", 190},
  1303. {"head", 200},
  1304. {"body", 200},
  1305. {"html", 220},
  1306. {NULL, 100} /* Default priority */
  1307. };
  1308. /************************************************************************
  1309. * *
  1310. * functions to handle HTML specific data *
  1311. * *
  1312. ************************************************************************/
  1313. /**
  1314. * htmlInitAutoClose:
  1315. *
  1316. * DEPRECATED: This function will be made private. Call xmlInitParser to
  1317. * initialize the library.
  1318. *
  1319. * This is a no-op now.
  1320. */
  1321. void
  1322. htmlInitAutoClose(void) {
  1323. }
  1324. static int
  1325. htmlCompareTags(const void *key, const void *member) {
  1326. const xmlChar *tag = (const xmlChar *) key;
  1327. const htmlElemDesc *desc = (const htmlElemDesc *) member;
  1328. return(xmlStrcasecmp(tag, BAD_CAST desc->name));
  1329. }
  1330. /**
  1331. * htmlTagLookup:
  1332. * @tag: The tag name in lowercase
  1333. *
  1334. * Lookup the HTML tag in the ElementTable
  1335. *
  1336. * Returns the related htmlElemDescPtr or NULL if not found.
  1337. */
  1338. const htmlElemDesc *
  1339. htmlTagLookup(const xmlChar *tag) {
  1340. if (tag == NULL)
  1341. return(NULL);
  1342. return((const htmlElemDesc *) bsearch(tag, html40ElementTable,
  1343. sizeof(html40ElementTable) / sizeof(htmlElemDesc),
  1344. sizeof(htmlElemDesc), htmlCompareTags));
  1345. }
  1346. /**
  1347. * htmlGetEndPriority:
  1348. * @name: The name of the element to look up the priority for.
  1349. *
  1350. * Return value: The "endtag" priority.
  1351. **/
  1352. static int
  1353. htmlGetEndPriority (const xmlChar *name) {
  1354. int i = 0;
  1355. while ((htmlEndPriority[i].name != NULL) &&
  1356. (!xmlStrEqual((const xmlChar *)htmlEndPriority[i].name, name)))
  1357. i++;
  1358. return(htmlEndPriority[i].priority);
  1359. }
  1360. static int
  1361. htmlCompareStartClose(const void *vkey, const void *member) {
  1362. const htmlStartCloseEntry *key = (const htmlStartCloseEntry *) vkey;
  1363. const htmlStartCloseEntry *entry = (const htmlStartCloseEntry *) member;
  1364. int ret;
  1365. ret = strcmp(key->oldTag, entry->oldTag);
  1366. if (ret == 0)
  1367. ret = strcmp(key->newTag, entry->newTag);
  1368. return(ret);
  1369. }
  1370. /**
  1371. * htmlCheckAutoClose:
  1372. * @newtag: The new tag name
  1373. * @oldtag: The old tag name
  1374. *
  1375. * Checks whether the new tag is one of the registered valid tags for
  1376. * closing old.
  1377. *
  1378. * Returns 0 if no, 1 if yes.
  1379. */
  1380. static int
  1381. htmlCheckAutoClose(const xmlChar * newtag, const xmlChar * oldtag)
  1382. {
  1383. htmlStartCloseEntry key;
  1384. void *res;
  1385. key.oldTag = (const char *) oldtag;
  1386. key.newTag = (const char *) newtag;
  1387. res = bsearch(&key, htmlStartClose,
  1388. sizeof(htmlStartClose) / sizeof(htmlStartCloseEntry),
  1389. sizeof(htmlStartCloseEntry), htmlCompareStartClose);
  1390. return(res != NULL);
  1391. }
  1392. /**
  1393. * htmlAutoCloseOnClose:
  1394. * @ctxt: an HTML parser context
  1395. * @newtag: The new tag name
  1396. * @force: force the tag closure
  1397. *
  1398. * The HTML DTD allows an ending tag to implicitly close other tags.
  1399. */
  1400. static void
  1401. htmlAutoCloseOnClose(htmlParserCtxtPtr ctxt, const xmlChar * newtag)
  1402. {
  1403. const htmlElemDesc *info;
  1404. int i, priority;
  1405. priority = htmlGetEndPriority(newtag);
  1406. for (i = (ctxt->nameNr - 1); i >= 0; i--) {
  1407. if (xmlStrEqual(newtag, ctxt->nameTab[i]))
  1408. break;
  1409. /*
  1410. * A misplaced endtag can only close elements with lower
  1411. * or equal priority, so if we find an element with higher
  1412. * priority before we find an element with
  1413. * matching name, we just ignore this endtag
  1414. */
  1415. if (htmlGetEndPriority(ctxt->nameTab[i]) > priority)
  1416. return;
  1417. }
  1418. if (i < 0)
  1419. return;
  1420. while (!xmlStrEqual(newtag, ctxt->name)) {
  1421. info = htmlTagLookup(ctxt->name);
  1422. if ((info != NULL) && (info->endTag == 3)) {
  1423. htmlParseErr(ctxt, XML_ERR_TAG_NAME_MISMATCH,
  1424. "Opening and ending tag mismatch: %s and %s\n",
  1425. newtag, ctxt->name);
  1426. }
  1427. if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
  1428. ctxt->sax->endElement(ctxt->userData, ctxt->name);
  1429. htmlnamePop(ctxt);
  1430. }
  1431. }
  1432. /**
  1433. * htmlAutoCloseOnEnd:
  1434. * @ctxt: an HTML parser context
  1435. *
  1436. * Close all remaining tags at the end of the stream
  1437. */
  1438. static void
  1439. htmlAutoCloseOnEnd(htmlParserCtxtPtr ctxt)
  1440. {
  1441. int i;
  1442. if (ctxt->nameNr == 0)
  1443. return;
  1444. for (i = (ctxt->nameNr - 1); i >= 0; i--) {
  1445. if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
  1446. ctxt->sax->endElement(ctxt->userData, ctxt->name);
  1447. htmlnamePop(ctxt);
  1448. }
  1449. }
  1450. /**
  1451. * htmlAutoClose:
  1452. * @ctxt: an HTML parser context
  1453. * @newtag: The new tag name or NULL
  1454. *
  1455. * The HTML DTD allows a tag to implicitly close other tags.
  1456. * The list is kept in htmlStartClose array. This function is
  1457. * called when a new tag has been detected and generates the
  1458. * appropriates closes if possible/needed.
  1459. * If newtag is NULL this mean we are at the end of the resource
  1460. * and we should check
  1461. */
  1462. static void
  1463. htmlAutoClose(htmlParserCtxtPtr ctxt, const xmlChar * newtag)
  1464. {
  1465. while ((newtag != NULL) && (ctxt->name != NULL) &&
  1466. (htmlCheckAutoClose(newtag, ctxt->name))) {
  1467. if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
  1468. ctxt->sax->endElement(ctxt->userData, ctxt->name);
  1469. htmlnamePop(ctxt);
  1470. }
  1471. if (newtag == NULL) {
  1472. htmlAutoCloseOnEnd(ctxt);
  1473. return;
  1474. }
  1475. while ((newtag == NULL) && (ctxt->name != NULL) &&
  1476. ((xmlStrEqual(ctxt->name, BAD_CAST "head")) ||
  1477. (xmlStrEqual(ctxt->name, BAD_CAST "body")) ||
  1478. (xmlStrEqual(ctxt->name, BAD_CAST "html")))) {
  1479. if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
  1480. ctxt->sax->endElement(ctxt->userData, ctxt->name);
  1481. htmlnamePop(ctxt);
  1482. }
  1483. }
  1484. /**
  1485. * htmlAutoCloseTag:
  1486. * @doc: the HTML document
  1487. * @name: The tag name
  1488. * @elem: the HTML element
  1489. *
  1490. * The HTML DTD allows a tag to implicitly close other tags.
  1491. * The list is kept in htmlStartClose array. This function checks
  1492. * if the element or one of it's children would autoclose the
  1493. * given tag.
  1494. *
  1495. * Returns 1 if autoclose, 0 otherwise
  1496. */
  1497. int
  1498. htmlAutoCloseTag(htmlDocPtr doc, const xmlChar *name, htmlNodePtr elem) {
  1499. htmlNodePtr child;
  1500. if (elem == NULL) return(1);
  1501. if (xmlStrEqual(name, elem->name)) return(0);
  1502. if (htmlCheckAutoClose(elem->name, name)) return(1);
  1503. child = elem->children;
  1504. while (child != NULL) {
  1505. if (htmlAutoCloseTag(doc, name, child)) return(1);
  1506. child = child->next;
  1507. }
  1508. return(0);
  1509. }
  1510. /**
  1511. * htmlIsAutoClosed:
  1512. * @doc: the HTML document
  1513. * @elem: the HTML element
  1514. *
  1515. * The HTML DTD allows a tag to implicitly close other tags.
  1516. * The list is kept in htmlStartClose array. This function checks
  1517. * if a tag is autoclosed by one of it's child
  1518. *
  1519. * Returns 1 if autoclosed, 0 otherwise
  1520. */
  1521. int
  1522. htmlIsAutoClosed(htmlDocPtr doc, htmlNodePtr elem) {
  1523. htmlNodePtr child;
  1524. if (elem == NULL) return(1);
  1525. child = elem->children;
  1526. while (child != NULL) {
  1527. if (htmlAutoCloseTag(doc, elem->name, child)) return(1);
  1528. child = child->next;
  1529. }
  1530. return(0);
  1531. }
  1532. /**
  1533. * htmlCheckImplied:
  1534. * @ctxt: an HTML parser context
  1535. * @newtag: The new tag name
  1536. *
  1537. * The HTML DTD allows a tag to exists only implicitly
  1538. * called when a new tag has been detected and generates the
  1539. * appropriates implicit tags if missing
  1540. */
  1541. static void
  1542. htmlCheckImplied(htmlParserCtxtPtr ctxt, const xmlChar *newtag) {
  1543. int i;
  1544. if (ctxt->options & HTML_PARSE_NOIMPLIED)
  1545. return;
  1546. if (!htmlOmittedDefaultValue)
  1547. return;
  1548. if (xmlStrEqual(newtag, BAD_CAST"html"))
  1549. return;
  1550. if (ctxt->nameNr <= 0) {
  1551. htmlnamePush(ctxt, BAD_CAST"html");
  1552. if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL))
  1553. ctxt->sax->startElement(ctxt->userData, BAD_CAST"html", NULL);
  1554. }
  1555. if ((xmlStrEqual(newtag, BAD_CAST"body")) || (xmlStrEqual(newtag, BAD_CAST"head")))
  1556. return;
  1557. if ((ctxt->nameNr <= 1) &&
  1558. ((xmlStrEqual(newtag, BAD_CAST"script")) ||
  1559. (xmlStrEqual(newtag, BAD_CAST"style")) ||
  1560. (xmlStrEqual(newtag, BAD_CAST"meta")) ||
  1561. (xmlStrEqual(newtag, BAD_CAST"link")) ||
  1562. (xmlStrEqual(newtag, BAD_CAST"title")) ||
  1563. (xmlStrEqual(newtag, BAD_CAST"base")))) {
  1564. if (ctxt->html >= 3) {
  1565. /* we already saw or generated an <head> before */
  1566. return;
  1567. }
  1568. /*
  1569. * dropped OBJECT ... i you put it first BODY will be
  1570. * assumed !
  1571. */
  1572. htmlnamePush(ctxt, BAD_CAST"head");
  1573. if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL))
  1574. ctxt->sax->startElement(ctxt->userData, BAD_CAST"head", NULL);
  1575. } else if ((!xmlStrEqual(newtag, BAD_CAST"noframes")) &&
  1576. (!xmlStrEqual(newtag, BAD_CAST"frame")) &&
  1577. (!xmlStrEqual(newtag, BAD_CAST"frameset"))) {
  1578. if (ctxt->html >= 10) {
  1579. /* we already saw or generated a <body> before */
  1580. return;
  1581. }
  1582. for (i = 0;i < ctxt->nameNr;i++) {
  1583. if (xmlStrEqual(ctxt->nameTab[i], BAD_CAST"body")) {
  1584. return;
  1585. }
  1586. if (xmlStrEqual(ctxt->nameTab[i], BAD_CAST"head")) {
  1587. return;
  1588. }
  1589. }
  1590. htmlnamePush(ctxt, BAD_CAST"body");
  1591. if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL))
  1592. ctxt->sax->startElement(ctxt->userData, BAD_CAST"body", NULL);
  1593. }
  1594. }
  1595. /**
  1596. * htmlCheckParagraph
  1597. * @ctxt: an HTML parser context
  1598. *
  1599. * Check whether a p element need to be implied before inserting
  1600. * characters in the current element.
  1601. *
  1602. * Returns 1 if a paragraph has been inserted, 0 if not and -1
  1603. * in case of error.
  1604. */
  1605. static int
  1606. htmlCheckParagraph(htmlParserCtxtPtr ctxt) {
  1607. const xmlChar *tag;
  1608. int i;
  1609. if (ctxt == NULL)
  1610. return(-1);
  1611. tag = ctxt->name;
  1612. if (tag == NULL) {
  1613. htmlAutoClose(ctxt, BAD_CAST"p");
  1614. htmlCheckImplied(ctxt, BAD_CAST"p");
  1615. htmlnamePush(ctxt, BAD_CAST"p");
  1616. if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL))
  1617. ctxt->sax->startElement(ctxt->userData, BAD_CAST"p", NULL);
  1618. return(1);
  1619. }
  1620. if (!htmlOmittedDefaultValue)
  1621. return(0);
  1622. for (i = 0; htmlNoContentElements[i] != NULL; i++) {
  1623. if (xmlStrEqual(tag, BAD_CAST htmlNoContentElements[i])) {
  1624. htmlAutoClose(ctxt, BAD_CAST"p");
  1625. htmlCheckImplied(ctxt, BAD_CAST"p");
  1626. htmlnamePush(ctxt, BAD_CAST"p");
  1627. if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL))
  1628. ctxt->sax->startElement(ctxt->userData, BAD_CAST"p", NULL);
  1629. return(1);
  1630. }
  1631. }
  1632. return(0);
  1633. }
  1634. /**
  1635. * htmlIsScriptAttribute:
  1636. * @name: an attribute name
  1637. *
  1638. * Check if an attribute is of content type Script
  1639. *
  1640. * Returns 1 is the attribute is a script 0 otherwise
  1641. */
  1642. int
  1643. htmlIsScriptAttribute(const xmlChar *name) {
  1644. unsigned int i;
  1645. if (name == NULL)
  1646. return(0);
  1647. /*
  1648. * all script attributes start with 'on'
  1649. */
  1650. if ((name[0] != 'o') || (name[1] != 'n'))
  1651. return(0);
  1652. for (i = 0;
  1653. i < sizeof(htmlScriptAttributes)/sizeof(htmlScriptAttributes[0]);
  1654. i++) {
  1655. if (xmlStrEqual(name, (const xmlChar *) htmlScriptAttributes[i]))
  1656. return(1);
  1657. }
  1658. return(0);
  1659. }
  1660. /************************************************************************
  1661. * *
  1662. * The list of HTML predefined entities *
  1663. * *
  1664. ************************************************************************/
  1665. static const htmlEntityDesc html40EntitiesTable[] = {
  1666. /*
  1667. * the 4 absolute ones, plus apostrophe.
  1668. */
  1669. { 34, "quot", "quotation mark = APL quote, U+0022 ISOnum" },
  1670. { 38, "amp", "ampersand, U+0026 ISOnum" },
  1671. { 39, "apos", "single quote" },
  1672. { 60, "lt", "less-than sign, U+003C ISOnum" },
  1673. { 62, "gt", "greater-than sign, U+003E ISOnum" },
  1674. /*
  1675. * A bunch still in the 128-255 range
  1676. * Replacing them depend really on the charset used.
  1677. */
  1678. { 160, "nbsp", "no-break space = non-breaking space, U+00A0 ISOnum" },
  1679. { 161, "iexcl","inverted exclamation mark, U+00A1 ISOnum" },
  1680. { 162, "cent", "cent sign, U+00A2 ISOnum" },
  1681. { 163, "pound","pound sign, U+00A3 ISOnum" },
  1682. { 164, "curren","currency sign, U+00A4 ISOnum" },
  1683. { 165, "yen", "yen sign = yuan sign, U+00A5 ISOnum" },
  1684. { 166, "brvbar","broken bar = broken vertical bar, U+00A6 ISOnum" },
  1685. { 167, "sect", "section sign, U+00A7 ISOnum" },
  1686. { 168, "uml", "diaeresis = spacing diaeresis, U+00A8 ISOdia" },
  1687. { 169, "copy", "copyright sign, U+00A9 ISOnum" },
  1688. { 170, "ordf", "feminine ordinal indicator, U+00AA ISOnum" },
  1689. { 171, "laquo","left-pointing double angle quotation mark = left pointing guillemet, U+00AB ISOnum" },
  1690. { 172, "not", "not sign, U+00AC ISOnum" },
  1691. { 173, "shy", "soft hyphen = discretionary hyphen, U+00AD ISOnum" },
  1692. { 174, "reg", "registered sign = registered trade mark sign, U+00AE ISOnum" },
  1693. { 175, "macr", "macron = spacing macron = overline = APL overbar, U+00AF ISOdia" },
  1694. { 176, "deg", "degree sign, U+00B0 ISOnum" },
  1695. { 177, "plusmn","plus-minus sign = plus-or-minus sign, U+00B1 ISOnum" },
  1696. { 178, "sup2", "superscript two = superscript digit two = squared, U+00B2 ISOnum" },
  1697. { 179, "sup3", "superscript three = superscript digit three = cubed, U+00B3 ISOnum" },
  1698. { 180, "acute","acute accent = spacing acute, U+00B4 ISOdia" },
  1699. { 181, "micro","micro sign, U+00B5 ISOnum" },
  1700. { 182, "para", "pilcrow sign = paragraph sign, U+00B6 ISOnum" },
  1701. { 183, "middot","middle dot = Georgian comma Greek middle dot, U+00B7 ISOnum" },
  1702. { 184, "cedil","cedilla = spacing cedilla, U+00B8 ISOdia" },
  1703. { 185, "sup1", "superscript one = superscript digit one, U+00B9 ISOnum" },
  1704. { 186, "ordm", "masculine ordinal indicator, U+00BA ISOnum" },
  1705. { 187, "raquo","right-pointing double angle quotation mark right pointing guillemet, U+00BB ISOnum" },
  1706. { 188, "frac14","vulgar fraction one quarter = fraction one quarter, U+00BC ISOnum" },
  1707. { 189, "frac12","vulgar fraction one half = fraction one half, U+00BD ISOnum" },
  1708. { 190, "frac34","vulgar fraction three quarters = fraction three quarters, U+00BE ISOnum" },
  1709. { 191, "iquest","inverted question mark = turned question mark, U+00BF ISOnum" },
  1710. { 192, "Agrave","latin capital letter A with grave = latin capital letter A grave, U+00C0 ISOlat1" },
  1711. { 193, "Aacute","latin capital letter A with acute, U+00C1 ISOlat1" },
  1712. { 194, "Acirc","latin capital letter A with circumflex, U+00C2 ISOlat1" },
  1713. { 195, "Atilde","latin capital letter A with tilde, U+00C3 ISOlat1" },
  1714. { 196, "Auml", "latin capital letter A with diaeresis, U+00C4 ISOlat1" },
  1715. { 197, "Aring","latin capital letter A with ring above = latin capital letter A ring, U+00C5 ISOlat1" },
  1716. { 198, "AElig","latin capital letter AE = latin capital ligature AE, U+00C6 ISOlat1" },
  1717. { 199, "Ccedil","latin capital letter C with cedilla, U+00C7 ISOlat1" },
  1718. { 200, "Egrave","latin capital letter E with grave, U+00C8 ISOlat1" },
  1719. { 201, "Eacute","latin capital letter E with acute, U+00C9 ISOlat1" },
  1720. { 202, "Ecirc","latin capital letter E with circumflex, U+00CA ISOlat1" },
  1721. { 203, "Euml", "latin capital letter E with diaeresis, U+00CB ISOlat1" },
  1722. { 204, "Igrave","latin capital letter I with grave, U+00CC ISOlat1" },
  1723. { 205, "Iacute","latin capital letter I with acute, U+00CD ISOlat1" },
  1724. { 206, "Icirc","latin capital letter I with circumflex, U+00CE ISOlat1" },
  1725. { 207, "Iuml", "latin capital letter I with diaeresis, U+00CF ISOlat1" },
  1726. { 208, "ETH", "latin capital letter ETH, U+00D0 ISOlat1" },
  1727. { 209, "Ntilde","latin capital letter N with tilde, U+00D1 ISOlat1" },
  1728. { 210, "Ograve","latin capital letter O with grave, U+00D2 ISOlat1" },
  1729. { 211, "Oacute","latin capital letter O with acute, U+00D3 ISOlat1" },
  1730. { 212, "Ocirc","latin capital letter O with circumflex, U+00D4 ISOlat1" },
  1731. { 213, "Otilde","latin capital letter O with tilde, U+00D5 ISOlat1" },
  1732. { 214, "Ouml", "latin capital letter O with diaeresis, U+00D6 ISOlat1" },
  1733. { 215, "times","multiplication sign, U+00D7 ISOnum" },
  1734. { 216, "Oslash","latin capital letter O with stroke latin capital letter O slash, U+00D8 ISOlat1" },
  1735. { 217, "Ugrave","latin capital letter U with grave, U+00D9 ISOlat1" },
  1736. { 218, "Uacute","latin capital letter U with acute, U+00DA ISOlat1" },
  1737. { 219, "Ucirc","latin capital letter U with circumflex, U+00DB ISOlat1" },
  1738. { 220, "Uuml", "latin capital letter U with diaeresis, U+00DC ISOlat1" },
  1739. { 221, "Yacute","latin capital letter Y with acute, U+00DD ISOlat1" },
  1740. { 222, "THORN","latin capital letter THORN, U+00DE ISOlat1" },
  1741. { 223, "szlig","latin small letter sharp s = ess-zed, U+00DF ISOlat1" },
  1742. { 224, "agrave","latin small letter a with grave = latin small letter a grave, U+00E0 ISOlat1" },
  1743. { 225, "aacute","latin small letter a with acute, U+00E1 ISOlat1" },
  1744. { 226, "acirc","latin small letter a with circumflex, U+00E2 ISOlat1" },
  1745. { 227, "atilde","latin small letter a with tilde, U+00E3 ISOlat1" },
  1746. { 228, "auml", "latin small letter a with diaeresis, U+00E4 ISOlat1" },
  1747. { 229, "aring","latin small letter a with ring above = latin small letter a ring, U+00E5 ISOlat1" },
  1748. { 230, "aelig","latin small letter ae = latin small ligature ae, U+00E6 ISOlat1" },
  1749. { 231, "ccedil","latin small letter c with cedilla, U+00E7 ISOlat1" },
  1750. { 232, "egrave","latin small letter e with grave, U+00E8 ISOlat1" },
  1751. { 233, "eacute","latin small letter e with acute, U+00E9 ISOlat1" },
  1752. { 234, "ecirc","latin small letter e with circumflex, U+00EA ISOlat1" },
  1753. { 235, "euml", "latin small letter e with diaeresis, U+00EB ISOlat1" },
  1754. { 236, "igrave","latin small letter i with grave, U+00EC ISOlat1" },
  1755. { 237, "iacute","latin small letter i with acute, U+00ED ISOlat1" },
  1756. { 238, "icirc","latin small letter i with circumflex, U+00EE ISOlat1" },
  1757. { 239, "iuml", "latin small letter i with diaeresis, U+00EF ISOlat1" },
  1758. { 240, "eth", "latin small letter eth, U+00F0 ISOlat1" },
  1759. { 241, "ntilde","latin small letter n with tilde, U+00F1 ISOlat1" },
  1760. { 242, "ograve","latin small letter o with grave, U+00F2 ISOlat1" },
  1761. { 243, "oacute","latin small letter o with acute, U+00F3 ISOlat1" },
  1762. { 244, "ocirc","latin small letter o with circumflex, U+00F4 ISOlat1" },
  1763. { 245, "otilde","latin small letter o with tilde, U+00F5 ISOlat1" },
  1764. { 246, "ouml", "latin small letter o with diaeresis, U+00F6 ISOlat1" },
  1765. { 247, "divide","division sign, U+00F7 ISOnum" },
  1766. { 248, "oslash","latin small letter o with stroke, = latin small letter o slash, U+00F8 ISOlat1" },
  1767. { 249, "ugrave","latin small letter u with grave, U+00F9 ISOlat1" },
  1768. { 250, "uacute","latin small letter u with acute, U+00FA ISOlat1" },
  1769. { 251, "ucirc","latin small letter u with circumflex, U+00FB ISOlat1" },
  1770. { 252, "uuml", "latin small letter u with diaeresis, U+00FC ISOlat1" },
  1771. { 253, "yacute","latin small letter y with acute, U+00FD ISOlat1" },
  1772. { 254, "thorn","latin small letter thorn with, U+00FE ISOlat1" },
  1773. { 255, "yuml", "latin small letter y with diaeresis, U+00FF ISOlat1" },
  1774. { 338, "OElig","latin capital ligature OE, U+0152 ISOlat2" },
  1775. { 339, "oelig","latin small ligature oe, U+0153 ISOlat2" },
  1776. { 352, "Scaron","latin capital letter S with caron, U+0160 ISOlat2" },
  1777. { 353, "scaron","latin small letter s with caron, U+0161 ISOlat2" },
  1778. { 376, "Yuml", "latin capital letter Y with diaeresis, U+0178 ISOlat2" },
  1779. /*
  1780. * Anything below should really be kept as entities references
  1781. */
  1782. { 402, "fnof", "latin small f with hook = function = florin, U+0192 ISOtech" },
  1783. { 710, "circ", "modifier letter circumflex accent, U+02C6 ISOpub" },
  1784. { 732, "tilde","small tilde, U+02DC ISOdia" },
  1785. { 913, "Alpha","greek capital letter alpha, U+0391" },
  1786. { 914, "Beta", "greek capital letter beta, U+0392" },
  1787. { 915, "Gamma","greek capital letter gamma, U+0393 ISOgrk3" },
  1788. { 916, "Delta","greek capital letter delta, U+0394 ISOgrk3" },
  1789. { 917, "Epsilon","greek capital letter epsilon, U+0395" },
  1790. { 918, "Zeta", "greek capital letter zeta, U+0396" },
  1791. { 919, "Eta", "greek capital letter eta, U+0397" },
  1792. { 920, "Theta","greek capital letter theta, U+0398 ISOgrk3" },
  1793. { 921, "Iota", "greek capital letter iota, U+0399" },
  1794. { 922, "Kappa","greek capital letter kappa, U+039A" },
  1795. { 923, "Lambda", "greek capital letter lambda, U+039B ISOgrk3" },
  1796. { 924, "Mu", "greek capital letter mu, U+039C" },
  1797. { 925, "Nu", "greek capital letter nu, U+039D" },
  1798. { 926, "Xi", "greek capital letter xi, U+039E ISOgrk3" },
  1799. { 927, "Omicron","greek capital letter omicron, U+039F" },
  1800. { 928, "Pi", "greek capital letter pi, U+03A0 ISOgrk3" },
  1801. { 929, "Rho", "greek capital letter rho, U+03A1" },
  1802. { 931, "Sigma","greek capital letter sigma, U+03A3 ISOgrk3" },
  1803. { 932, "Tau", "greek capital letter tau, U+03A4" },
  1804. { 933, "Upsilon","greek capital letter upsilon, U+03A5 ISOgrk3" },
  1805. { 934, "Phi", "greek capital letter phi, U+03A6 ISOgrk3" },
  1806. { 935, "Chi", "greek capital letter chi, U+03A7" },
  1807. { 936, "Psi", "greek capital letter psi, U+03A8 ISOgrk3" },
  1808. { 937, "Omega","greek capital letter omega, U+03A9 ISOgrk3" },
  1809. { 945, "alpha","greek small letter alpha, U+03B1 ISOgrk3" },
  1810. { 946, "beta", "greek small letter beta, U+03B2 ISOgrk3" },
  1811. { 947, "gamma","greek small letter gamma, U+03B3 ISOgrk3" },
  1812. { 948, "delta","greek small letter delta, U+03B4 ISOgrk3" },
  1813. { 949, "epsilon","greek small letter epsilon, U+03B5 ISOgrk3" },
  1814. { 950, "zeta", "greek small letter zeta, U+03B6 ISOgrk3" },
  1815. { 951, "eta", "greek small letter eta, U+03B7 ISOgrk3" },
  1816. { 952, "theta","greek small letter theta, U+03B8 ISOgrk3" },
  1817. { 953, "iota", "greek small letter iota, U+03B9 ISOgrk3" },
  1818. { 954, "kappa","greek small letter kappa, U+03BA ISOgrk3" },
  1819. { 955, "lambda","greek small letter lambda, U+03BB ISOgrk3" },
  1820. { 956, "mu", "greek small letter mu, U+03BC ISOgrk3" },
  1821. { 957, "nu", "greek small letter nu, U+03BD ISOgrk3" },
  1822. { 958, "xi", "greek small letter xi, U+03BE ISOgrk3" },
  1823. { 959, "omicron","greek small letter omicron, U+03BF NEW" },
  1824. { 960, "pi", "greek small letter pi, U+03C0 ISOgrk3" },
  1825. { 961, "rho", "greek small letter rho, U+03C1 ISOgrk3" },
  1826. { 962, "sigmaf","greek small letter final sigma, U+03C2 ISOgrk3" },
  1827. { 963, "sigma","greek small letter sigma, U+03C3 ISOgrk3" },
  1828. { 964, "tau", "greek small letter tau, U+03C4 ISOgrk3" },
  1829. { 965, "upsilon","greek small letter upsilon, U+03C5 ISOgrk3" },
  1830. { 966, "phi", "greek small letter phi, U+03C6 ISOgrk3" },
  1831. { 967, "chi", "greek small letter chi, U+03C7 ISOgrk3" },
  1832. { 968, "psi", "greek small letter psi, U+03C8 ISOgrk3" },
  1833. { 969, "omega","greek small letter omega, U+03C9 ISOgrk3" },
  1834. { 977, "thetasym","greek small letter theta symbol, U+03D1 NEW" },
  1835. { 978, "upsih","greek upsilon with hook symbol, U+03D2 NEW" },
  1836. { 982, "piv", "greek pi symbol, U+03D6 ISOgrk3" },
  1837. { 8194, "ensp", "en space, U+2002 ISOpub" },
  1838. { 8195, "emsp", "em space, U+2003 ISOpub" },
  1839. { 8201, "thinsp","thin space, U+2009 ISOpub" },
  1840. { 8204, "zwnj", "zero width non-joiner, U+200C NEW RFC 2070" },
  1841. { 8205, "zwj", "zero width joiner, U+200D NEW RFC 2070" },
  1842. { 8206, "lrm", "left-to-right mark, U+200E NEW RFC 2070" },
  1843. { 8207, "rlm", "right-to-left mark, U+200F NEW RFC 2070" },
  1844. { 8211, "ndash","en dash, U+2013 ISOpub" },
  1845. { 8212, "mdash","em dash, U+2014 ISOpub" },
  1846. { 8216, "lsquo","left single quotation mark, U+2018 ISOnum" },
  1847. { 8217, "rsquo","right single quotation mark, U+2019 ISOnum" },
  1848. { 8218, "sbquo","single low-9 quotation mark, U+201A NEW" },
  1849. { 8220, "ldquo","left double quotation mark, U+201C ISOnum" },
  1850. { 8221, "rdquo","right double quotation mark, U+201D ISOnum" },
  1851. { 8222, "bdquo","double low-9 quotation mark, U+201E NEW" },
  1852. { 8224, "dagger","dagger, U+2020 ISOpub" },
  1853. { 8225, "Dagger","double dagger, U+2021 ISOpub" },
  1854. { 8226, "bull", "bullet = black small circle, U+2022 ISOpub" },
  1855. { 8230, "hellip","horizontal ellipsis = three dot leader, U+2026 ISOpub" },
  1856. { 8240, "permil","per mille sign, U+2030 ISOtech" },
  1857. { 8242, "prime","prime = minutes = feet, U+2032 ISOtech" },
  1858. { 8243, "Prime","double prime = seconds = inches, U+2033 ISOtech" },
  1859. { 8249, "lsaquo","single left-pointing angle quotation mark, U+2039 ISO proposed" },
  1860. { 8250, "rsaquo","single right-pointing angle quotation mark, U+203A ISO proposed" },
  1861. { 8254, "oline","overline = spacing overscore, U+203E NEW" },
  1862. { 8260, "frasl","fraction slash, U+2044 NEW" },
  1863. { 8364, "euro", "euro sign, U+20AC NEW" },
  1864. { 8465, "image","blackletter capital I = imaginary part, U+2111 ISOamso" },
  1865. { 8472, "weierp","script capital P = power set = Weierstrass p, U+2118 ISOamso" },
  1866. { 8476, "real", "blackletter capital R = real part symbol, U+211C ISOamso" },
  1867. { 8482, "trade","trade mark sign, U+2122 ISOnum" },
  1868. { 8501, "alefsym","alef symbol = first transfinite cardinal, U+2135 NEW" },
  1869. { 8592, "larr", "leftwards arrow, U+2190 ISOnum" },
  1870. { 8593, "uarr", "upwards arrow, U+2191 ISOnum" },
  1871. { 8594, "rarr", "rightwards arrow, U+2192 ISOnum" },
  1872. { 8595, "darr", "downwards arrow, U+2193 ISOnum" },
  1873. { 8596, "harr", "left right arrow, U+2194 ISOamsa" },
  1874. { 8629, "crarr","downwards arrow with corner leftwards = carriage return, U+21B5 NEW" },
  1875. { 8656, "lArr", "leftwards double arrow, U+21D0 ISOtech" },
  1876. { 8657, "uArr", "upwards double arrow, U+21D1 ISOamsa" },
  1877. { 8658, "rArr", "rightwards double arrow, U+21D2 ISOtech" },
  1878. { 8659, "dArr", "downwards double arrow, U+21D3 ISOamsa" },
  1879. { 8660, "hArr", "left right double arrow, U+21D4 ISOamsa" },
  1880. { 8704, "forall","for all, U+2200 ISOtech" },
  1881. { 8706, "part", "partial differential, U+2202 ISOtech" },
  1882. { 8707, "exist","there exists, U+2203 ISOtech" },
  1883. { 8709, "empty","empty set = null set = diameter, U+2205 ISOamso" },
  1884. { 8711, "nabla","nabla = backward difference, U+2207 ISOtech" },
  1885. { 8712, "isin", "element of, U+2208 ISOtech" },
  1886. { 8713, "notin","not an element of, U+2209 ISOtech" },
  1887. { 8715, "ni", "contains as member, U+220B ISOtech" },
  1888. { 8719, "prod", "n-ary product = product sign, U+220F ISOamsb" },
  1889. { 8721, "sum", "n-ary summation, U+2211 ISOamsb" },
  1890. { 8722, "minus","minus sign, U+2212 ISOtech" },
  1891. { 8727, "lowast","asterisk operator, U+2217 ISOtech" },
  1892. { 8730, "radic","square root = radical sign, U+221A ISOtech" },
  1893. { 8733, "prop", "proportional to, U+221D ISOtech" },
  1894. { 8734, "infin","infinity, U+221E ISOtech" },
  1895. { 8736, "ang", "angle, U+2220 ISOamso" },
  1896. { 8743, "and", "logical and = wedge, U+2227 ISOtech" },
  1897. { 8744, "or", "logical or = vee, U+2228 ISOtech" },
  1898. { 8745, "cap", "intersection = cap, U+2229 ISOtech" },
  1899. { 8746, "cup", "union = cup, U+222A ISOtech" },
  1900. { 8747, "int", "integral, U+222B ISOtech" },
  1901. { 8756, "there4","therefore, U+2234 ISOtech" },
  1902. { 8764, "sim", "tilde operator = varies with = similar to, U+223C ISOtech" },
  1903. { 8773, "cong", "approximately equal to, U+2245 ISOtech" },
  1904. { 8776, "asymp","almost equal to = asymptotic to, U+2248 ISOamsr" },
  1905. { 8800, "ne", "not equal to, U+2260 ISOtech" },
  1906. { 8801, "equiv","identical to, U+2261 ISOtech" },
  1907. { 8804, "le", "less-than or equal to, U+2264 ISOtech" },
  1908. { 8805, "ge", "greater-than or equal to, U+2265 ISOtech" },
  1909. { 8834, "sub", "subset of, U+2282 ISOtech" },
  1910. { 8835, "sup", "superset of, U+2283 ISOtech" },
  1911. { 8836, "nsub", "not a subset of, U+2284 ISOamsn" },
  1912. { 8838, "sube", "subset of or equal to, U+2286 ISOtech" },
  1913. { 8839, "supe", "superset of or equal to, U+2287 ISOtech" },
  1914. { 8853, "oplus","circled plus = direct sum, U+2295 ISOamsb" },
  1915. { 8855, "otimes","circled times = vector product, U+2297 ISOamsb" },
  1916. { 8869, "perp", "up tack = orthogonal to = perpendicular, U+22A5 ISOtech" },
  1917. { 8901, "sdot", "dot operator, U+22C5 ISOamsb" },
  1918. { 8968, "lceil","left ceiling = apl upstile, U+2308 ISOamsc" },
  1919. { 8969, "rceil","right ceiling, U+2309 ISOamsc" },
  1920. { 8970, "lfloor","left floor = apl downstile, U+230A ISOamsc" },
  1921. { 8971, "rfloor","right floor, U+230B ISOamsc" },
  1922. { 9001, "lang", "left-pointing angle bracket = bra, U+2329 ISOtech" },
  1923. { 9002, "rang", "right-pointing angle bracket = ket, U+232A ISOtech" },
  1924. { 9674, "loz", "lozenge, U+25CA ISOpub" },
  1925. { 9824, "spades","black spade suit, U+2660 ISOpub" },
  1926. { 9827, "clubs","black club suit = shamrock, U+2663 ISOpub" },
  1927. { 9829, "hearts","black heart suit = valentine, U+2665 ISOpub" },
  1928. { 9830, "diams","black diamond suit, U+2666 ISOpub" },
  1929. };
  1930. /************************************************************************
  1931. * *
  1932. * Commodity functions to handle entities *
  1933. * *
  1934. ************************************************************************/
  1935. /*
  1936. * Macro used to grow the current buffer.
  1937. */
  1938. #define growBuffer(buffer) { \
  1939. xmlChar *tmp; \
  1940. buffer##_size *= 2; \
  1941. tmp = (xmlChar *) xmlRealloc(buffer, buffer##_size * sizeof(xmlChar)); \
  1942. if (tmp == NULL) { \
  1943. htmlErrMemory(ctxt, "growing buffer\n"); \
  1944. xmlFree(buffer); \
  1945. return(NULL); \
  1946. } \
  1947. buffer = tmp; \
  1948. }
  1949. /**
  1950. * htmlEntityLookup:
  1951. * @name: the entity name
  1952. *
  1953. * Lookup the given entity in EntitiesTable
  1954. *
  1955. * TODO: the linear scan is really ugly, an hash table is really needed.
  1956. *
  1957. * Returns the associated htmlEntityDescPtr if found, NULL otherwise.
  1958. */
  1959. const htmlEntityDesc *
  1960. htmlEntityLookup(const xmlChar *name) {
  1961. unsigned int i;
  1962. for (i = 0;i < (sizeof(html40EntitiesTable)/
  1963. sizeof(html40EntitiesTable[0]));i++) {
  1964. if (xmlStrEqual(name, BAD_CAST html40EntitiesTable[i].name)) {
  1965. return((htmlEntityDescPtr) &html40EntitiesTable[i]);
  1966. }
  1967. }
  1968. return(NULL);
  1969. }
  1970. /**
  1971. * htmlEntityValueLookup:
  1972. * @value: the entity's unicode value
  1973. *
  1974. * Lookup the given entity in EntitiesTable
  1975. *
  1976. * TODO: the linear scan is really ugly, an hash table is really needed.
  1977. *
  1978. * Returns the associated htmlEntityDescPtr if found, NULL otherwise.
  1979. */
  1980. const htmlEntityDesc *
  1981. htmlEntityValueLookup(unsigned int value) {
  1982. unsigned int i;
  1983. for (i = 0;i < (sizeof(html40EntitiesTable)/
  1984. sizeof(html40EntitiesTable[0]));i++) {
  1985. if (html40EntitiesTable[i].value >= value) {
  1986. if (html40EntitiesTable[i].value > value)
  1987. break;
  1988. return((htmlEntityDescPtr) &html40EntitiesTable[i]);
  1989. }
  1990. }
  1991. return(NULL);
  1992. }
  1993. /**
  1994. * UTF8ToHtml:
  1995. * @out: a pointer to an array of bytes to store the result
  1996. * @outlen: the length of @out
  1997. * @in: a pointer to an array of UTF-8 chars
  1998. * @inlen: the length of @in
  1999. *
  2000. * Take a block of UTF-8 chars in and try to convert it to an ASCII
  2001. * plus HTML entities block of chars out.
  2002. *
  2003. * Returns 0 if success, -2 if the transcoding fails, or -1 otherwise
  2004. * The value of @inlen after return is the number of octets consumed
  2005. * as the return value is positive, else unpredictable.
  2006. * The value of @outlen after return is the number of octets consumed.
  2007. */
  2008. int
  2009. UTF8ToHtml(unsigned char* out, int *outlen,
  2010. const unsigned char* in, int *inlen) {
  2011. const unsigned char* processed = in;
  2012. const unsigned char* outend;
  2013. const unsigned char* outstart = out;
  2014. const unsigned char* instart = in;
  2015. const unsigned char* inend;
  2016. unsigned int c, d;
  2017. int trailing;
  2018. if ((out == NULL) || (outlen == NULL) || (inlen == NULL)) return(-1);
  2019. if (in == NULL) {
  2020. /*
  2021. * initialization nothing to do
  2022. */
  2023. *outlen = 0;
  2024. *inlen = 0;
  2025. return(0);
  2026. }
  2027. inend = in + (*inlen);
  2028. outend = out + (*outlen);
  2029. while (in < inend) {
  2030. d = *in++;
  2031. if (d < 0x80) { c= d; trailing= 0; }
  2032. else if (d < 0xC0) {
  2033. /* trailing byte in leading position */
  2034. *outlen = out - outstart;
  2035. *inlen = processed - instart;
  2036. return(-2);
  2037. } else if (d < 0xE0) { c= d & 0x1F; trailing= 1; }
  2038. else if (d < 0xF0) { c= d & 0x0F; trailing= 2; }
  2039. else if (d < 0xF8) { c= d & 0x07; trailing= 3; }
  2040. else {
  2041. /* no chance for this in Ascii */
  2042. *outlen = out - outstart;
  2043. *inlen = processed - instart;
  2044. return(-2);
  2045. }
  2046. if (inend - in < trailing) {
  2047. break;
  2048. }
  2049. for ( ; trailing; trailing--) {
  2050. if ((in >= inend) || (((d= *in++) & 0xC0) != 0x80))
  2051. break;
  2052. c <<= 6;
  2053. c |= d & 0x3F;
  2054. }
  2055. /* assertion: c is a single UTF-4 value */
  2056. if (c < 0x80) {
  2057. if (out + 1 >= outend)
  2058. break;
  2059. *out++ = c;
  2060. } else {
  2061. int len;
  2062. const htmlEntityDesc * ent;
  2063. const char *cp;
  2064. char nbuf[16];
  2065. /*
  2066. * Try to lookup a predefined HTML entity for it
  2067. */
  2068. ent = htmlEntityValueLookup(c);
  2069. if (ent == NULL) {
  2070. snprintf(nbuf, sizeof(nbuf), "#%u", c);
  2071. cp = nbuf;
  2072. }
  2073. else
  2074. cp = ent->name;
  2075. len = strlen(cp);
  2076. if (out + 2 + len >= outend)
  2077. break;
  2078. *out++ = '&';
  2079. memcpy(out, cp, len);
  2080. out += len;
  2081. *out++ = ';';
  2082. }
  2083. processed = in;
  2084. }
  2085. *outlen = out - outstart;
  2086. *inlen = processed - instart;
  2087. return(0);
  2088. }
  2089. /**
  2090. * htmlEncodeEntities:
  2091. * @out: a pointer to an array of bytes to store the result
  2092. * @outlen: the length of @out
  2093. * @in: a pointer to an array of UTF-8 chars
  2094. * @inlen: the length of @in
  2095. * @quoteChar: the quote character to escape (' or ") or zero.
  2096. *
  2097. * Take a block of UTF-8 chars in and try to convert it to an ASCII
  2098. * plus HTML entities block of chars out.
  2099. *
  2100. * Returns 0 if success, -2 if the transcoding fails, or -1 otherwise
  2101. * The value of @inlen after return is the number of octets consumed
  2102. * as the return value is positive, else unpredictable.
  2103. * The value of @outlen after return is the number of octets consumed.
  2104. */
  2105. int
  2106. htmlEncodeEntities(unsigned char* out, int *outlen,
  2107. const unsigned char* in, int *inlen, int quoteChar) {
  2108. const unsigned char* processed = in;
  2109. const unsigned char* outend;
  2110. const unsigned char* outstart = out;
  2111. const unsigned char* instart = in;
  2112. const unsigned char* inend;
  2113. unsigned int c, d;
  2114. int trailing;
  2115. if ((out == NULL) || (outlen == NULL) || (inlen == NULL) || (in == NULL))
  2116. return(-1);
  2117. outend = out + (*outlen);
  2118. inend = in + (*inlen);
  2119. while (in < inend) {
  2120. d = *in++;
  2121. if (d < 0x80) { c= d; trailing= 0; }
  2122. else if (d < 0xC0) {
  2123. /* trailing byte in leading position */
  2124. *outlen = out - outstart;
  2125. *inlen = processed - instart;
  2126. return(-2);
  2127. } else if (d < 0xE0) { c= d & 0x1F; trailing= 1; }
  2128. else if (d < 0xF0) { c= d & 0x0F; trailing= 2; }
  2129. else if (d < 0xF8) { c= d & 0x07; trailing= 3; }
  2130. else {
  2131. /* no chance for this in Ascii */
  2132. *outlen = out - outstart;
  2133. *inlen = processed - instart;
  2134. return(-2);
  2135. }
  2136. if (inend - in < trailing)
  2137. break;
  2138. while (trailing--) {
  2139. if (((d= *in++) & 0xC0) != 0x80) {
  2140. *outlen = out - outstart;
  2141. *inlen = processed - instart;
  2142. return(-2);
  2143. }
  2144. c <<= 6;
  2145. c |= d & 0x3F;
  2146. }
  2147. /* assertion: c is a single UTF-4 value */
  2148. if ((c < 0x80) && (c != (unsigned int) quoteChar) &&
  2149. (c != '&') && (c != '<') && (c != '>')) {
  2150. if (out >= outend)
  2151. break;
  2152. *out++ = c;
  2153. } else {
  2154. const htmlEntityDesc * ent;
  2155. const char *cp;
  2156. char nbuf[16];
  2157. int len;
  2158. /*
  2159. * Try to lookup a predefined HTML entity for it
  2160. */
  2161. ent = htmlEntityValueLookup(c);
  2162. if (ent == NULL) {
  2163. snprintf(nbuf, sizeof(nbuf), "#%u", c);
  2164. cp = nbuf;
  2165. }
  2166. else
  2167. cp = ent->name;
  2168. len = strlen(cp);
  2169. if (out + 2 + len > outend)
  2170. break;
  2171. *out++ = '&';
  2172. memcpy(out, cp, len);
  2173. out += len;
  2174. *out++ = ';';
  2175. }
  2176. processed = in;
  2177. }
  2178. *outlen = out - outstart;
  2179. *inlen = processed - instart;
  2180. return(0);
  2181. }
  2182. /************************************************************************
  2183. * *
  2184. * Commodity functions to handle streams *
  2185. * *
  2186. ************************************************************************/
  2187. #ifdef LIBXML_PUSH_ENABLED
  2188. /**
  2189. * htmlNewInputStream:
  2190. * @ctxt: an HTML parser context
  2191. *
  2192. * Create a new input stream structure
  2193. * Returns the new input stream or NULL
  2194. */
  2195. static htmlParserInputPtr
  2196. htmlNewInputStream(htmlParserCtxtPtr ctxt) {
  2197. htmlParserInputPtr input;
  2198. input = (xmlParserInputPtr) xmlMalloc(sizeof(htmlParserInput));
  2199. if (input == NULL) {
  2200. htmlErrMemory(ctxt, "couldn't allocate a new input stream\n");
  2201. return(NULL);
  2202. }
  2203. memset(input, 0, sizeof(htmlParserInput));
  2204. input->filename = NULL;
  2205. input->directory = NULL;
  2206. input->base = NULL;
  2207. input->cur = NULL;
  2208. input->buf = NULL;
  2209. input->line = 1;
  2210. input->col = 1;
  2211. input->buf = NULL;
  2212. input->free = NULL;
  2213. input->version = NULL;
  2214. input->consumed = 0;
  2215. input->length = 0;
  2216. return(input);
  2217. }
  2218. #endif
  2219. /************************************************************************
  2220. * *
  2221. * Commodity functions, cleanup needed ? *
  2222. * *
  2223. ************************************************************************/
  2224. /*
  2225. * all tags allowing pc data from the html 4.01 loose dtd
  2226. * NOTE: it might be more appropriate to integrate this information
  2227. * into the html40ElementTable array but I don't want to risk any
  2228. * binary incompatibility
  2229. */
  2230. static const char *allowPCData[] = {
  2231. "a", "abbr", "acronym", "address", "applet", "b", "bdo", "big",
  2232. "blockquote", "body", "button", "caption", "center", "cite", "code",
  2233. "dd", "del", "dfn", "div", "dt", "em", "font", "form", "h1", "h2",
  2234. "h3", "h4", "h5", "h6", "i", "iframe", "ins", "kbd", "label", "legend",
  2235. "li", "noframes", "noscript", "object", "p", "pre", "q", "s", "samp",
  2236. "small", "span", "strike", "strong", "td", "th", "tt", "u", "var"
  2237. };
  2238. /**
  2239. * areBlanks:
  2240. * @ctxt: an HTML parser context
  2241. * @str: a xmlChar *
  2242. * @len: the size of @str
  2243. *
  2244. * Is this a sequence of blank chars that one can ignore ?
  2245. *
  2246. * Returns 1 if ignorable 0 otherwise.
  2247. */
  2248. static int areBlanks(htmlParserCtxtPtr ctxt, const xmlChar *str, int len) {
  2249. unsigned int i;
  2250. int j;
  2251. xmlNodePtr lastChild;
  2252. xmlDtdPtr dtd;
  2253. for (j = 0;j < len;j++)
  2254. if (!(IS_BLANK_CH(str[j]))) return(0);
  2255. if (CUR == 0) return(1);
  2256. if (CUR != '<') return(0);
  2257. if (ctxt->name == NULL)
  2258. return(1);
  2259. if (xmlStrEqual(ctxt->name, BAD_CAST"html"))
  2260. return(1);
  2261. if (xmlStrEqual(ctxt->name, BAD_CAST"head"))
  2262. return(1);
  2263. /* Only strip CDATA children of the body tag for strict HTML DTDs */
  2264. if (xmlStrEqual(ctxt->name, BAD_CAST "body") && ctxt->myDoc != NULL) {
  2265. dtd = xmlGetIntSubset(ctxt->myDoc);
  2266. if (dtd != NULL && dtd->ExternalID != NULL) {
  2267. if (!xmlStrcasecmp(dtd->ExternalID, BAD_CAST "-//W3C//DTD HTML 4.01//EN") ||
  2268. !xmlStrcasecmp(dtd->ExternalID, BAD_CAST "-//W3C//DTD HTML 4//EN"))
  2269. return(1);
  2270. }
  2271. }
  2272. if (ctxt->node == NULL) return(0);
  2273. lastChild = xmlGetLastChild(ctxt->node);
  2274. while ((lastChild) && (lastChild->type == XML_COMMENT_NODE))
  2275. lastChild = lastChild->prev;
  2276. if (lastChild == NULL) {
  2277. if ((ctxt->node->type != XML_ELEMENT_NODE) &&
  2278. (ctxt->node->content != NULL)) return(0);
  2279. /* keep ws in constructs like ...<b> </b>...
  2280. for all tags "b" allowing PCDATA */
  2281. for ( i = 0; i < sizeof(allowPCData)/sizeof(allowPCData[0]); i++ ) {
  2282. if ( xmlStrEqual(ctxt->name, BAD_CAST allowPCData[i]) ) {
  2283. return(0);
  2284. }
  2285. }
  2286. } else if (xmlNodeIsText(lastChild)) {
  2287. return(0);
  2288. } else {
  2289. /* keep ws in constructs like <p><b>xy</b> <i>z</i><p>
  2290. for all tags "p" allowing PCDATA */
  2291. for ( i = 0; i < sizeof(allowPCData)/sizeof(allowPCData[0]); i++ ) {
  2292. if ( xmlStrEqual(lastChild->name, BAD_CAST allowPCData[i]) ) {
  2293. return(0);
  2294. }
  2295. }
  2296. }
  2297. return(1);
  2298. }
  2299. /**
  2300. * htmlNewDocNoDtD:
  2301. * @URI: URI for the dtd, or NULL
  2302. * @ExternalID: the external ID of the DTD, or NULL
  2303. *
  2304. * Creates a new HTML document without a DTD node if @URI and @ExternalID
  2305. * are NULL
  2306. *
  2307. * Returns a new document, do not initialize the DTD if not provided
  2308. */
  2309. htmlDocPtr
  2310. htmlNewDocNoDtD(const xmlChar *URI, const xmlChar *ExternalID) {
  2311. xmlDocPtr cur;
  2312. /*
  2313. * Allocate a new document and fill the fields.
  2314. */
  2315. cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
  2316. if (cur == NULL) {
  2317. htmlErrMemory(NULL, "HTML document creation failed\n");
  2318. return(NULL);
  2319. }
  2320. memset(cur, 0, sizeof(xmlDoc));
  2321. cur->type = XML_HTML_DOCUMENT_NODE;
  2322. cur->version = NULL;
  2323. cur->intSubset = NULL;
  2324. cur->doc = cur;
  2325. cur->name = NULL;
  2326. cur->children = NULL;
  2327. cur->extSubset = NULL;
  2328. cur->oldNs = NULL;
  2329. cur->encoding = NULL;
  2330. cur->standalone = 1;
  2331. cur->compression = 0;
  2332. cur->ids = NULL;
  2333. cur->refs = NULL;
  2334. cur->_private = NULL;
  2335. cur->charset = XML_CHAR_ENCODING_UTF8;
  2336. cur->properties = XML_DOC_HTML | XML_DOC_USERBUILT;
  2337. if ((ExternalID != NULL) ||
  2338. (URI != NULL))
  2339. xmlCreateIntSubset(cur, BAD_CAST "html", ExternalID, URI);
  2340. if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
  2341. xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
  2342. return(cur);
  2343. }
  2344. /**
  2345. * htmlNewDoc:
  2346. * @URI: URI for the dtd, or NULL
  2347. * @ExternalID: the external ID of the DTD, or NULL
  2348. *
  2349. * Creates a new HTML document
  2350. *
  2351. * Returns a new document
  2352. */
  2353. htmlDocPtr
  2354. htmlNewDoc(const xmlChar *URI, const xmlChar *ExternalID) {
  2355. if ((URI == NULL) && (ExternalID == NULL))
  2356. return(htmlNewDocNoDtD(
  2357. BAD_CAST "http://www.w3.org/TR/REC-html40/loose.dtd",
  2358. BAD_CAST "-//W3C//DTD HTML 4.0 Transitional//EN"));
  2359. return(htmlNewDocNoDtD(URI, ExternalID));
  2360. }
  2361. /************************************************************************
  2362. * *
  2363. * The parser itself *
  2364. * Relates to http://www.w3.org/TR/html40 *
  2365. * *
  2366. ************************************************************************/
  2367. /************************************************************************
  2368. * *
  2369. * The parser itself *
  2370. * *
  2371. ************************************************************************/
  2372. static const xmlChar * htmlParseNameComplex(xmlParserCtxtPtr ctxt);
  2373. /**
  2374. * htmlParseHTMLName:
  2375. * @ctxt: an HTML parser context
  2376. *
  2377. * parse an HTML tag or attribute name, note that we convert it to lowercase
  2378. * since HTML names are not case-sensitive.
  2379. *
  2380. * Returns the Tag Name parsed or NULL
  2381. */
  2382. static const xmlChar *
  2383. htmlParseHTMLName(htmlParserCtxtPtr ctxt) {
  2384. int i = 0;
  2385. xmlChar loc[HTML_PARSER_BUFFER_SIZE];
  2386. if (!IS_ASCII_LETTER(CUR) && (CUR != '_') &&
  2387. (CUR != ':') && (CUR != '.')) return(NULL);
  2388. while ((i < HTML_PARSER_BUFFER_SIZE) &&
  2389. ((IS_ASCII_LETTER(CUR)) || (IS_ASCII_DIGIT(CUR)) ||
  2390. (CUR == ':') || (CUR == '-') || (CUR == '_') ||
  2391. (CUR == '.'))) {
  2392. if ((CUR >= 'A') && (CUR <= 'Z')) loc[i] = CUR + 0x20;
  2393. else loc[i] = CUR;
  2394. i++;
  2395. NEXT;
  2396. }
  2397. return(xmlDictLookup(ctxt->dict, loc, i));
  2398. }
  2399. /**
  2400. * htmlParseHTMLName_nonInvasive:
  2401. * @ctxt: an HTML parser context
  2402. *
  2403. * parse an HTML tag or attribute name, note that we convert it to lowercase
  2404. * since HTML names are not case-sensitive, this doesn't consume the data
  2405. * from the stream, it's a look-ahead
  2406. *
  2407. * Returns the Tag Name parsed or NULL
  2408. */
  2409. static const xmlChar *
  2410. htmlParseHTMLName_nonInvasive(htmlParserCtxtPtr ctxt) {
  2411. int i = 0;
  2412. xmlChar loc[HTML_PARSER_BUFFER_SIZE];
  2413. if (!IS_ASCII_LETTER(NXT(1)) && (NXT(1) != '_') &&
  2414. (NXT(1) != ':')) return(NULL);
  2415. while ((i < HTML_PARSER_BUFFER_SIZE) &&
  2416. ((IS_ASCII_LETTER(NXT(1+i))) || (IS_ASCII_DIGIT(NXT(1+i))) ||
  2417. (NXT(1+i) == ':') || (NXT(1+i) == '-') || (NXT(1+i) == '_'))) {
  2418. if ((NXT(1+i) >= 'A') && (NXT(1+i) <= 'Z')) loc[i] = NXT(1+i) + 0x20;
  2419. else loc[i] = NXT(1+i);
  2420. i++;
  2421. }
  2422. return(xmlDictLookup(ctxt->dict, loc, i));
  2423. }
  2424. /**
  2425. * htmlParseName:
  2426. * @ctxt: an HTML parser context
  2427. *
  2428. * parse an HTML name, this routine is case sensitive.
  2429. *
  2430. * Returns the Name parsed or NULL
  2431. */
  2432. static const xmlChar *
  2433. htmlParseName(htmlParserCtxtPtr ctxt) {
  2434. const xmlChar *in;
  2435. const xmlChar *ret;
  2436. int count = 0;
  2437. GROW;
  2438. /*
  2439. * Accelerator for simple ASCII names
  2440. */
  2441. in = ctxt->input->cur;
  2442. if (((*in >= 0x61) && (*in <= 0x7A)) ||
  2443. ((*in >= 0x41) && (*in <= 0x5A)) ||
  2444. (*in == '_') || (*in == ':')) {
  2445. in++;
  2446. while (((*in >= 0x61) && (*in <= 0x7A)) ||
  2447. ((*in >= 0x41) && (*in <= 0x5A)) ||
  2448. ((*in >= 0x30) && (*in <= 0x39)) ||
  2449. (*in == '_') || (*in == '-') ||
  2450. (*in == ':') || (*in == '.'))
  2451. in++;
  2452. if (in == ctxt->input->end)
  2453. return(NULL);
  2454. if ((*in > 0) && (*in < 0x80)) {
  2455. count = in - ctxt->input->cur;
  2456. ret = xmlDictLookup(ctxt->dict, ctxt->input->cur, count);
  2457. ctxt->input->cur = in;
  2458. ctxt->input->col += count;
  2459. return(ret);
  2460. }
  2461. }
  2462. return(htmlParseNameComplex(ctxt));
  2463. }
  2464. static const xmlChar *
  2465. htmlParseNameComplex(xmlParserCtxtPtr ctxt) {
  2466. int len = 0, l;
  2467. int c;
  2468. int count = 0;
  2469. const xmlChar *base = ctxt->input->base;
  2470. /*
  2471. * Handler for more complex cases
  2472. */
  2473. GROW;
  2474. c = CUR_CHAR(l);
  2475. if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
  2476. (!IS_LETTER(c) && (c != '_') &&
  2477. (c != ':'))) {
  2478. return(NULL);
  2479. }
  2480. while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
  2481. ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
  2482. (c == '.') || (c == '-') ||
  2483. (c == '_') || (c == ':') ||
  2484. (IS_COMBINING(c)) ||
  2485. (IS_EXTENDER(c)))) {
  2486. if (count++ > 100) {
  2487. count = 0;
  2488. GROW;
  2489. }
  2490. len += l;
  2491. NEXTL(l);
  2492. c = CUR_CHAR(l);
  2493. if (ctxt->input->base != base) {
  2494. /*
  2495. * We changed encoding from an unknown encoding
  2496. * Input buffer changed location, so we better start again
  2497. */
  2498. return(htmlParseNameComplex(ctxt));
  2499. }
  2500. }
  2501. if (ctxt->input->cur - ctxt->input->base < len) {
  2502. /* Sanity check */
  2503. htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
  2504. "unexpected change of input buffer", NULL, NULL);
  2505. return (NULL);
  2506. }
  2507. return(xmlDictLookup(ctxt->dict, ctxt->input->cur - len, len));
  2508. }
  2509. /**
  2510. * htmlParseHTMLAttribute:
  2511. * @ctxt: an HTML parser context
  2512. * @stop: a char stop value
  2513. *
  2514. * parse an HTML attribute value till the stop (quote), if
  2515. * stop is 0 then it stops at the first space
  2516. *
  2517. * Returns the attribute parsed or NULL
  2518. */
  2519. static xmlChar *
  2520. htmlParseHTMLAttribute(htmlParserCtxtPtr ctxt, const xmlChar stop) {
  2521. xmlChar *buffer = NULL;
  2522. int buffer_size = 0;
  2523. xmlChar *out = NULL;
  2524. const xmlChar *name = NULL;
  2525. const xmlChar *cur = NULL;
  2526. const htmlEntityDesc * ent;
  2527. /*
  2528. * allocate a translation buffer.
  2529. */
  2530. buffer_size = HTML_PARSER_BUFFER_SIZE;
  2531. buffer = (xmlChar *) xmlMallocAtomic(buffer_size * sizeof(xmlChar));
  2532. if (buffer == NULL) {
  2533. htmlErrMemory(ctxt, "buffer allocation failed\n");
  2534. return(NULL);
  2535. }
  2536. out = buffer;
  2537. /*
  2538. * Ok loop until we reach one of the ending chars
  2539. */
  2540. while ((CUR != 0) && (CUR != stop)) {
  2541. if ((stop == 0) && (CUR == '>')) break;
  2542. if ((stop == 0) && (IS_BLANK_CH(CUR))) break;
  2543. if (CUR == '&') {
  2544. if (NXT(1) == '#') {
  2545. unsigned int c;
  2546. int bits;
  2547. c = htmlParseCharRef(ctxt);
  2548. if (c < 0x80)
  2549. { *out++ = c; bits= -6; }
  2550. else if (c < 0x800)
  2551. { *out++ =((c >> 6) & 0x1F) | 0xC0; bits= 0; }
  2552. else if (c < 0x10000)
  2553. { *out++ =((c >> 12) & 0x0F) | 0xE0; bits= 6; }
  2554. else
  2555. { *out++ =((c >> 18) & 0x07) | 0xF0; bits= 12; }
  2556. for ( ; bits >= 0; bits-= 6) {
  2557. *out++ = ((c >> bits) & 0x3F) | 0x80;
  2558. }
  2559. if (out - buffer > buffer_size - 100) {
  2560. int indx = out - buffer;
  2561. growBuffer(buffer);
  2562. out = &buffer[indx];
  2563. }
  2564. } else {
  2565. ent = htmlParseEntityRef(ctxt, &name);
  2566. if (name == NULL) {
  2567. *out++ = '&';
  2568. if (out - buffer > buffer_size - 100) {
  2569. int indx = out - buffer;
  2570. growBuffer(buffer);
  2571. out = &buffer[indx];
  2572. }
  2573. } else if (ent == NULL) {
  2574. *out++ = '&';
  2575. cur = name;
  2576. while (*cur != 0) {
  2577. if (out - buffer > buffer_size - 100) {
  2578. int indx = out - buffer;
  2579. growBuffer(buffer);
  2580. out = &buffer[indx];
  2581. }
  2582. *out++ = *cur++;
  2583. }
  2584. } else {
  2585. unsigned int c;
  2586. int bits;
  2587. if (out - buffer > buffer_size - 100) {
  2588. int indx = out - buffer;
  2589. growBuffer(buffer);
  2590. out = &buffer[indx];
  2591. }
  2592. c = ent->value;
  2593. if (c < 0x80)
  2594. { *out++ = c; bits= -6; }
  2595. else if (c < 0x800)
  2596. { *out++ =((c >> 6) & 0x1F) | 0xC0; bits= 0; }
  2597. else if (c < 0x10000)
  2598. { *out++ =((c >> 12) & 0x0F) | 0xE0; bits= 6; }
  2599. else
  2600. { *out++ =((c >> 18) & 0x07) | 0xF0; bits= 12; }
  2601. for ( ; bits >= 0; bits-= 6) {
  2602. *out++ = ((c >> bits) & 0x3F) | 0x80;
  2603. }
  2604. }
  2605. }
  2606. } else {
  2607. unsigned int c;
  2608. int bits, l;
  2609. if (out - buffer > buffer_size - 100) {
  2610. int indx = out - buffer;
  2611. growBuffer(buffer);
  2612. out = &buffer[indx];
  2613. }
  2614. c = CUR_CHAR(l);
  2615. if (c < 0x80)
  2616. { *out++ = c; bits= -6; }
  2617. else if (c < 0x800)
  2618. { *out++ =((c >> 6) & 0x1F) | 0xC0; bits= 0; }
  2619. else if (c < 0x10000)
  2620. { *out++ =((c >> 12) & 0x0F) | 0xE0; bits= 6; }
  2621. else
  2622. { *out++ =((c >> 18) & 0x07) | 0xF0; bits= 12; }
  2623. for ( ; bits >= 0; bits-= 6) {
  2624. *out++ = ((c >> bits) & 0x3F) | 0x80;
  2625. }
  2626. NEXT;
  2627. }
  2628. }
  2629. *out = 0;
  2630. return(buffer);
  2631. }
  2632. /**
  2633. * htmlParseEntityRef:
  2634. * @ctxt: an HTML parser context
  2635. * @str: location to store the entity name
  2636. *
  2637. * parse an HTML ENTITY references
  2638. *
  2639. * [68] EntityRef ::= '&' Name ';'
  2640. *
  2641. * Returns the associated htmlEntityDescPtr if found, or NULL otherwise,
  2642. * if non-NULL *str will have to be freed by the caller.
  2643. */
  2644. const htmlEntityDesc *
  2645. htmlParseEntityRef(htmlParserCtxtPtr ctxt, const xmlChar **str) {
  2646. const xmlChar *name;
  2647. const htmlEntityDesc * ent = NULL;
  2648. if (str != NULL) *str = NULL;
  2649. if ((ctxt == NULL) || (ctxt->input == NULL)) return(NULL);
  2650. if (CUR == '&') {
  2651. NEXT;
  2652. name = htmlParseName(ctxt);
  2653. if (name == NULL) {
  2654. htmlParseErr(ctxt, XML_ERR_NAME_REQUIRED,
  2655. "htmlParseEntityRef: no name\n", NULL, NULL);
  2656. } else {
  2657. GROW;
  2658. if (CUR == ';') {
  2659. if (str != NULL)
  2660. *str = name;
  2661. /*
  2662. * Lookup the entity in the table.
  2663. */
  2664. ent = htmlEntityLookup(name);
  2665. if (ent != NULL) /* OK that's ugly !!! */
  2666. NEXT;
  2667. } else {
  2668. htmlParseErr(ctxt, XML_ERR_ENTITYREF_SEMICOL_MISSING,
  2669. "htmlParseEntityRef: expecting ';'\n",
  2670. NULL, NULL);
  2671. if (str != NULL)
  2672. *str = name;
  2673. }
  2674. }
  2675. }
  2676. return(ent);
  2677. }
  2678. /**
  2679. * htmlParseAttValue:
  2680. * @ctxt: an HTML parser context
  2681. *
  2682. * parse a value for an attribute
  2683. * Note: the parser won't do substitution of entities here, this
  2684. * will be handled later in xmlStringGetNodeList, unless it was
  2685. * asked for ctxt->replaceEntities != 0
  2686. *
  2687. * Returns the AttValue parsed or NULL.
  2688. */
  2689. static xmlChar *
  2690. htmlParseAttValue(htmlParserCtxtPtr ctxt) {
  2691. xmlChar *ret = NULL;
  2692. if (CUR == '"') {
  2693. NEXT;
  2694. ret = htmlParseHTMLAttribute(ctxt, '"');
  2695. if (CUR != '"') {
  2696. htmlParseErr(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED,
  2697. "AttValue: \" expected\n", NULL, NULL);
  2698. } else
  2699. NEXT;
  2700. } else if (CUR == '\'') {
  2701. NEXT;
  2702. ret = htmlParseHTMLAttribute(ctxt, '\'');
  2703. if (CUR != '\'') {
  2704. htmlParseErr(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED,
  2705. "AttValue: ' expected\n", NULL, NULL);
  2706. } else
  2707. NEXT;
  2708. } else {
  2709. /*
  2710. * That's an HTMLism, the attribute value may not be quoted
  2711. */
  2712. ret = htmlParseHTMLAttribute(ctxt, 0);
  2713. if (ret == NULL) {
  2714. htmlParseErr(ctxt, XML_ERR_ATTRIBUTE_WITHOUT_VALUE,
  2715. "AttValue: no value found\n", NULL, NULL);
  2716. }
  2717. }
  2718. return(ret);
  2719. }
  2720. /**
  2721. * htmlParseSystemLiteral:
  2722. * @ctxt: an HTML parser context
  2723. *
  2724. * parse an HTML Literal
  2725. *
  2726. * [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'")
  2727. *
  2728. * Returns the SystemLiteral parsed or NULL
  2729. */
  2730. static xmlChar *
  2731. htmlParseSystemLiteral(htmlParserCtxtPtr ctxt) {
  2732. size_t len = 0, startPosition = 0;
  2733. int err = 0;
  2734. int quote;
  2735. xmlChar *ret = NULL;
  2736. if ((CUR != '"') && (CUR != '\'')) {
  2737. htmlParseErr(ctxt, XML_ERR_LITERAL_NOT_STARTED,
  2738. "SystemLiteral \" or ' expected\n", NULL, NULL);
  2739. return(NULL);
  2740. }
  2741. quote = CUR;
  2742. NEXT;
  2743. if (CUR_PTR < BASE_PTR)
  2744. return(ret);
  2745. startPosition = CUR_PTR - BASE_PTR;
  2746. while ((CUR != 0) && (CUR != quote)) {
  2747. /* TODO: Handle UTF-8 */
  2748. if (!IS_CHAR_CH(CUR)) {
  2749. htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
  2750. "Invalid char in SystemLiteral 0x%X\n", CUR);
  2751. err = 1;
  2752. }
  2753. NEXT;
  2754. len++;
  2755. }
  2756. if (CUR != quote) {
  2757. htmlParseErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED,
  2758. "Unfinished SystemLiteral\n", NULL, NULL);
  2759. } else {
  2760. NEXT;
  2761. if (err == 0)
  2762. ret = xmlStrndup((BASE_PTR+startPosition), len);
  2763. }
  2764. return(ret);
  2765. }
  2766. /**
  2767. * htmlParsePubidLiteral:
  2768. * @ctxt: an HTML parser context
  2769. *
  2770. * parse an HTML public literal
  2771. *
  2772. * [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'"
  2773. *
  2774. * Returns the PubidLiteral parsed or NULL.
  2775. */
  2776. static xmlChar *
  2777. htmlParsePubidLiteral(htmlParserCtxtPtr ctxt) {
  2778. size_t len = 0, startPosition = 0;
  2779. int err = 0;
  2780. int quote;
  2781. xmlChar *ret = NULL;
  2782. if ((CUR != '"') && (CUR != '\'')) {
  2783. htmlParseErr(ctxt, XML_ERR_LITERAL_NOT_STARTED,
  2784. "PubidLiteral \" or ' expected\n", NULL, NULL);
  2785. return(NULL);
  2786. }
  2787. quote = CUR;
  2788. NEXT;
  2789. /*
  2790. * Name ::= (Letter | '_') (NameChar)*
  2791. */
  2792. if (CUR_PTR < BASE_PTR)
  2793. return(ret);
  2794. startPosition = CUR_PTR - BASE_PTR;
  2795. while ((CUR != 0) && (CUR != quote)) {
  2796. if (!IS_PUBIDCHAR_CH(CUR)) {
  2797. htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
  2798. "Invalid char in PubidLiteral 0x%X\n", CUR);
  2799. err = 1;
  2800. }
  2801. len++;
  2802. NEXT;
  2803. }
  2804. if (CUR != quote) {
  2805. htmlParseErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED,
  2806. "Unfinished PubidLiteral\n", NULL, NULL);
  2807. } else {
  2808. NEXT;
  2809. if (err == 0)
  2810. ret = xmlStrndup((BASE_PTR + startPosition), len);
  2811. }
  2812. return(ret);
  2813. }
  2814. /**
  2815. * htmlParseScript:
  2816. * @ctxt: an HTML parser context
  2817. *
  2818. * parse the content of an HTML SCRIPT or STYLE element
  2819. * http://www.w3.org/TR/html4/sgml/dtd.html#Script
  2820. * http://www.w3.org/TR/html4/sgml/dtd.html#StyleSheet
  2821. * http://www.w3.org/TR/html4/types.html#type-script
  2822. * http://www.w3.org/TR/html4/types.html#h-6.15
  2823. * http://www.w3.org/TR/html4/appendix/notes.html#h-B.3.2.1
  2824. *
  2825. * Script data ( %Script; in the DTD) can be the content of the SCRIPT
  2826. * element and the value of intrinsic event attributes. User agents must
  2827. * not evaluate script data as HTML markup but instead must pass it on as
  2828. * data to a script engine.
  2829. * NOTES:
  2830. * - The content is passed like CDATA
  2831. * - the attributes for style and scripting "onXXX" are also described
  2832. * as CDATA but SGML allows entities references in attributes so their
  2833. * processing is identical as other attributes
  2834. */
  2835. static void
  2836. htmlParseScript(htmlParserCtxtPtr ctxt) {
  2837. xmlChar buf[HTML_PARSER_BIG_BUFFER_SIZE + 5];
  2838. int nbchar = 0;
  2839. int cur,l;
  2840. SHRINK;
  2841. cur = CUR_CHAR(l);
  2842. while (cur != 0) {
  2843. if ((cur == '<') && (NXT(1) == '/')) {
  2844. /*
  2845. * One should break here, the specification is clear:
  2846. * Authors should therefore escape "</" within the content.
  2847. * Escape mechanisms are specific to each scripting or
  2848. * style sheet language.
  2849. *
  2850. * In recovery mode, only break if end tag match the
  2851. * current tag, effectively ignoring all tags inside the
  2852. * script/style block and treating the entire block as
  2853. * CDATA.
  2854. */
  2855. if (ctxt->recovery) {
  2856. if (xmlStrncasecmp(ctxt->name, ctxt->input->cur+2,
  2857. xmlStrlen(ctxt->name)) == 0)
  2858. {
  2859. break; /* while */
  2860. } else {
  2861. htmlParseErr(ctxt, XML_ERR_TAG_NAME_MISMATCH,
  2862. "Element %s embeds close tag\n",
  2863. ctxt->name, NULL);
  2864. }
  2865. } else {
  2866. if (((NXT(2) >= 'A') && (NXT(2) <= 'Z')) ||
  2867. ((NXT(2) >= 'a') && (NXT(2) <= 'z')))
  2868. {
  2869. break; /* while */
  2870. }
  2871. }
  2872. }
  2873. if (IS_CHAR(cur)) {
  2874. COPY_BUF(l,buf,nbchar,cur);
  2875. } else {
  2876. htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
  2877. "Invalid char in CDATA 0x%X\n", cur);
  2878. }
  2879. if (nbchar >= HTML_PARSER_BIG_BUFFER_SIZE) {
  2880. buf[nbchar] = 0;
  2881. if (ctxt->sax->cdataBlock!= NULL) {
  2882. /*
  2883. * Insert as CDATA, which is the same as HTML_PRESERVE_NODE
  2884. */
  2885. ctxt->sax->cdataBlock(ctxt->userData, buf, nbchar);
  2886. } else if (ctxt->sax->characters != NULL) {
  2887. ctxt->sax->characters(ctxt->userData, buf, nbchar);
  2888. }
  2889. nbchar = 0;
  2890. }
  2891. GROW;
  2892. NEXTL(l);
  2893. cur = CUR_CHAR(l);
  2894. }
  2895. if ((nbchar != 0) && (ctxt->sax != NULL) && (!ctxt->disableSAX)) {
  2896. buf[nbchar] = 0;
  2897. if (ctxt->sax->cdataBlock!= NULL) {
  2898. /*
  2899. * Insert as CDATA, which is the same as HTML_PRESERVE_NODE
  2900. */
  2901. ctxt->sax->cdataBlock(ctxt->userData, buf, nbchar);
  2902. } else if (ctxt->sax->characters != NULL) {
  2903. ctxt->sax->characters(ctxt->userData, buf, nbchar);
  2904. }
  2905. }
  2906. }
  2907. /**
  2908. * htmlParseCharDataInternal:
  2909. * @ctxt: an HTML parser context
  2910. * @readahead: optional read ahead character in ascii range
  2911. *
  2912. * parse a CharData section.
  2913. * if we are within a CDATA section ']]>' marks an end of section.
  2914. *
  2915. * [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
  2916. */
  2917. static void
  2918. htmlParseCharDataInternal(htmlParserCtxtPtr ctxt, int readahead) {
  2919. xmlChar buf[HTML_PARSER_BIG_BUFFER_SIZE + 6];
  2920. int nbchar = 0;
  2921. int cur, l;
  2922. int chunk = 0;
  2923. if (readahead)
  2924. buf[nbchar++] = readahead;
  2925. SHRINK;
  2926. cur = CUR_CHAR(l);
  2927. while (((cur != '<') || (ctxt->token == '<')) &&
  2928. ((cur != '&') || (ctxt->token == '&')) &&
  2929. (cur != 0)) {
  2930. if (!(IS_CHAR(cur))) {
  2931. htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
  2932. "Invalid char in CDATA 0x%X\n", cur);
  2933. } else {
  2934. COPY_BUF(l,buf,nbchar,cur);
  2935. }
  2936. if (nbchar >= HTML_PARSER_BIG_BUFFER_SIZE) {
  2937. buf[nbchar] = 0;
  2938. /*
  2939. * Ok the segment is to be consumed as chars.
  2940. */
  2941. if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) {
  2942. if (areBlanks(ctxt, buf, nbchar)) {
  2943. if (ctxt->keepBlanks) {
  2944. if (ctxt->sax->characters != NULL)
  2945. ctxt->sax->characters(ctxt->userData, buf, nbchar);
  2946. } else {
  2947. if (ctxt->sax->ignorableWhitespace != NULL)
  2948. ctxt->sax->ignorableWhitespace(ctxt->userData,
  2949. buf, nbchar);
  2950. }
  2951. } else {
  2952. htmlCheckParagraph(ctxt);
  2953. if (ctxt->sax->characters != NULL)
  2954. ctxt->sax->characters(ctxt->userData, buf, nbchar);
  2955. }
  2956. }
  2957. nbchar = 0;
  2958. }
  2959. NEXTL(l);
  2960. chunk++;
  2961. if (chunk > HTML_PARSER_BUFFER_SIZE) {
  2962. chunk = 0;
  2963. SHRINK;
  2964. GROW;
  2965. }
  2966. cur = CUR_CHAR(l);
  2967. if (cur == 0) {
  2968. SHRINK;
  2969. GROW;
  2970. cur = CUR_CHAR(l);
  2971. }
  2972. }
  2973. if (nbchar != 0) {
  2974. buf[nbchar] = 0;
  2975. /*
  2976. * Ok the segment is to be consumed as chars.
  2977. */
  2978. if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) {
  2979. if (areBlanks(ctxt, buf, nbchar)) {
  2980. if (ctxt->keepBlanks) {
  2981. if (ctxt->sax->characters != NULL)
  2982. ctxt->sax->characters(ctxt->userData, buf, nbchar);
  2983. } else {
  2984. if (ctxt->sax->ignorableWhitespace != NULL)
  2985. ctxt->sax->ignorableWhitespace(ctxt->userData,
  2986. buf, nbchar);
  2987. }
  2988. } else {
  2989. htmlCheckParagraph(ctxt);
  2990. if (ctxt->sax->characters != NULL)
  2991. ctxt->sax->characters(ctxt->userData, buf, nbchar);
  2992. }
  2993. }
  2994. } else {
  2995. /*
  2996. * Loop detection
  2997. */
  2998. if (cur == 0)
  2999. ctxt->instate = XML_PARSER_EOF;
  3000. }
  3001. }
  3002. /**
  3003. * htmlParseCharData:
  3004. * @ctxt: an HTML parser context
  3005. *
  3006. * parse a CharData section.
  3007. * if we are within a CDATA section ']]>' marks an end of section.
  3008. *
  3009. * [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
  3010. */
  3011. static void
  3012. htmlParseCharData(htmlParserCtxtPtr ctxt) {
  3013. htmlParseCharDataInternal(ctxt, 0);
  3014. }
  3015. /**
  3016. * htmlParseExternalID:
  3017. * @ctxt: an HTML parser context
  3018. * @publicID: a xmlChar** receiving PubidLiteral
  3019. *
  3020. * Parse an External ID or a Public ID
  3021. *
  3022. * [75] ExternalID ::= 'SYSTEM' S SystemLiteral
  3023. * | 'PUBLIC' S PubidLiteral S SystemLiteral
  3024. *
  3025. * [83] PublicID ::= 'PUBLIC' S PubidLiteral
  3026. *
  3027. * Returns the function returns SystemLiteral and in the second
  3028. * case publicID receives PubidLiteral, is strict is off
  3029. * it is possible to return NULL and have publicID set.
  3030. */
  3031. static xmlChar *
  3032. htmlParseExternalID(htmlParserCtxtPtr ctxt, xmlChar **publicID) {
  3033. xmlChar *URI = NULL;
  3034. if ((UPPER == 'S') && (UPP(1) == 'Y') &&
  3035. (UPP(2) == 'S') && (UPP(3) == 'T') &&
  3036. (UPP(4) == 'E') && (UPP(5) == 'M')) {
  3037. SKIP(6);
  3038. if (!IS_BLANK_CH(CUR)) {
  3039. htmlParseErr(ctxt, XML_ERR_SPACE_REQUIRED,
  3040. "Space required after 'SYSTEM'\n", NULL, NULL);
  3041. }
  3042. SKIP_BLANKS;
  3043. URI = htmlParseSystemLiteral(ctxt);
  3044. if (URI == NULL) {
  3045. htmlParseErr(ctxt, XML_ERR_URI_REQUIRED,
  3046. "htmlParseExternalID: SYSTEM, no URI\n", NULL, NULL);
  3047. }
  3048. } else if ((UPPER == 'P') && (UPP(1) == 'U') &&
  3049. (UPP(2) == 'B') && (UPP(3) == 'L') &&
  3050. (UPP(4) == 'I') && (UPP(5) == 'C')) {
  3051. SKIP(6);
  3052. if (!IS_BLANK_CH(CUR)) {
  3053. htmlParseErr(ctxt, XML_ERR_SPACE_REQUIRED,
  3054. "Space required after 'PUBLIC'\n", NULL, NULL);
  3055. }
  3056. SKIP_BLANKS;
  3057. *publicID = htmlParsePubidLiteral(ctxt);
  3058. if (*publicID == NULL) {
  3059. htmlParseErr(ctxt, XML_ERR_PUBID_REQUIRED,
  3060. "htmlParseExternalID: PUBLIC, no Public Identifier\n",
  3061. NULL, NULL);
  3062. }
  3063. SKIP_BLANKS;
  3064. if ((CUR == '"') || (CUR == '\'')) {
  3065. URI = htmlParseSystemLiteral(ctxt);
  3066. }
  3067. }
  3068. return(URI);
  3069. }
  3070. /**
  3071. * xmlParsePI:
  3072. * @ctxt: an XML parser context
  3073. *
  3074. * parse an XML Processing Instruction.
  3075. *
  3076. * [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'
  3077. */
  3078. static void
  3079. htmlParsePI(htmlParserCtxtPtr ctxt) {
  3080. xmlChar *buf = NULL;
  3081. int len = 0;
  3082. int size = HTML_PARSER_BUFFER_SIZE;
  3083. int cur, l;
  3084. const xmlChar *target;
  3085. xmlParserInputState state;
  3086. int count = 0;
  3087. if ((RAW == '<') && (NXT(1) == '?')) {
  3088. state = ctxt->instate;
  3089. ctxt->instate = XML_PARSER_PI;
  3090. /*
  3091. * this is a Processing Instruction.
  3092. */
  3093. SKIP(2);
  3094. SHRINK;
  3095. /*
  3096. * Parse the target name and check for special support like
  3097. * namespace.
  3098. */
  3099. target = htmlParseName(ctxt);
  3100. if (target != NULL) {
  3101. if (RAW == '>') {
  3102. SKIP(1);
  3103. /*
  3104. * SAX: PI detected.
  3105. */
  3106. if ((ctxt->sax) && (!ctxt->disableSAX) &&
  3107. (ctxt->sax->processingInstruction != NULL))
  3108. ctxt->sax->processingInstruction(ctxt->userData,
  3109. target, NULL);
  3110. ctxt->instate = state;
  3111. return;
  3112. }
  3113. buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar));
  3114. if (buf == NULL) {
  3115. htmlErrMemory(ctxt, NULL);
  3116. ctxt->instate = state;
  3117. return;
  3118. }
  3119. cur = CUR;
  3120. if (!IS_BLANK(cur)) {
  3121. htmlParseErr(ctxt, XML_ERR_SPACE_REQUIRED,
  3122. "ParsePI: PI %s space expected\n", target, NULL);
  3123. }
  3124. SKIP_BLANKS;
  3125. cur = CUR_CHAR(l);
  3126. while ((cur != 0) && (cur != '>')) {
  3127. if (len + 5 >= size) {
  3128. xmlChar *tmp;
  3129. size *= 2;
  3130. tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
  3131. if (tmp == NULL) {
  3132. htmlErrMemory(ctxt, NULL);
  3133. xmlFree(buf);
  3134. ctxt->instate = state;
  3135. return;
  3136. }
  3137. buf = tmp;
  3138. }
  3139. count++;
  3140. if (count > 50) {
  3141. GROW;
  3142. count = 0;
  3143. }
  3144. if (IS_CHAR(cur)) {
  3145. COPY_BUF(l,buf,len,cur);
  3146. } else {
  3147. htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
  3148. "Invalid char in processing instruction "
  3149. "0x%X\n", cur);
  3150. }
  3151. NEXTL(l);
  3152. cur = CUR_CHAR(l);
  3153. if (cur == 0) {
  3154. SHRINK;
  3155. GROW;
  3156. cur = CUR_CHAR(l);
  3157. }
  3158. }
  3159. buf[len] = 0;
  3160. if (cur != '>') {
  3161. htmlParseErr(ctxt, XML_ERR_PI_NOT_FINISHED,
  3162. "ParsePI: PI %s never end ...\n", target, NULL);
  3163. } else {
  3164. SKIP(1);
  3165. /*
  3166. * SAX: PI detected.
  3167. */
  3168. if ((ctxt->sax) && (!ctxt->disableSAX) &&
  3169. (ctxt->sax->processingInstruction != NULL))
  3170. ctxt->sax->processingInstruction(ctxt->userData,
  3171. target, buf);
  3172. }
  3173. xmlFree(buf);
  3174. } else {
  3175. htmlParseErr(ctxt, XML_ERR_PI_NOT_STARTED,
  3176. "PI is not started correctly", NULL, NULL);
  3177. }
  3178. ctxt->instate = state;
  3179. }
  3180. }
  3181. /**
  3182. * htmlParseComment:
  3183. * @ctxt: an HTML parser context
  3184. *
  3185. * Parse an XML (SGML) comment <!-- .... -->
  3186. *
  3187. * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
  3188. */
  3189. static void
  3190. htmlParseComment(htmlParserCtxtPtr ctxt) {
  3191. xmlChar *buf = NULL;
  3192. int len;
  3193. int size = HTML_PARSER_BUFFER_SIZE;
  3194. int q, ql;
  3195. int r, rl;
  3196. int cur, l;
  3197. int next, nl;
  3198. xmlParserInputState state;
  3199. /*
  3200. * Check that there is a comment right here.
  3201. */
  3202. if ((RAW != '<') || (NXT(1) != '!') ||
  3203. (NXT(2) != '-') || (NXT(3) != '-')) return;
  3204. state = ctxt->instate;
  3205. ctxt->instate = XML_PARSER_COMMENT;
  3206. SHRINK;
  3207. SKIP(4);
  3208. buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar));
  3209. if (buf == NULL) {
  3210. htmlErrMemory(ctxt, "buffer allocation failed\n");
  3211. ctxt->instate = state;
  3212. return;
  3213. }
  3214. len = 0;
  3215. buf[len] = 0;
  3216. q = CUR_CHAR(ql);
  3217. if (q == 0)
  3218. goto unfinished;
  3219. if (q == '>') {
  3220. htmlParseErr(ctxt, XML_ERR_COMMENT_ABRUPTLY_ENDED, "Comment abruptly ended", NULL, NULL);
  3221. cur = '>';
  3222. goto finished;
  3223. }
  3224. NEXTL(ql);
  3225. r = CUR_CHAR(rl);
  3226. if (r == 0)
  3227. goto unfinished;
  3228. if (q == '-' && r == '>') {
  3229. htmlParseErr(ctxt, XML_ERR_COMMENT_ABRUPTLY_ENDED, "Comment abruptly ended", NULL, NULL);
  3230. cur = '>';
  3231. goto finished;
  3232. }
  3233. NEXTL(rl);
  3234. cur = CUR_CHAR(l);
  3235. while ((cur != 0) &&
  3236. ((cur != '>') ||
  3237. (r != '-') || (q != '-'))) {
  3238. NEXTL(l);
  3239. next = CUR_CHAR(nl);
  3240. if (next == 0) {
  3241. SHRINK;
  3242. GROW;
  3243. next = CUR_CHAR(nl);
  3244. }
  3245. if ((q == '-') && (r == '-') && (cur == '!') && (next == '>')) {
  3246. htmlParseErr(ctxt, XML_ERR_COMMENT_NOT_FINISHED,
  3247. "Comment incorrectly closed by '--!>'", NULL, NULL);
  3248. cur = '>';
  3249. break;
  3250. }
  3251. if (len + 5 >= size) {
  3252. xmlChar *tmp;
  3253. size *= 2;
  3254. tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
  3255. if (tmp == NULL) {
  3256. xmlFree(buf);
  3257. htmlErrMemory(ctxt, "growing buffer failed\n");
  3258. ctxt->instate = state;
  3259. return;
  3260. }
  3261. buf = tmp;
  3262. }
  3263. if (IS_CHAR(q)) {
  3264. COPY_BUF(ql,buf,len,q);
  3265. } else {
  3266. htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
  3267. "Invalid char in comment 0x%X\n", q);
  3268. }
  3269. q = r;
  3270. ql = rl;
  3271. r = cur;
  3272. rl = l;
  3273. cur = next;
  3274. l = nl;
  3275. }
  3276. finished:
  3277. buf[len] = 0;
  3278. if (cur == '>') {
  3279. NEXT;
  3280. if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL) &&
  3281. (!ctxt->disableSAX))
  3282. ctxt->sax->comment(ctxt->userData, buf);
  3283. xmlFree(buf);
  3284. ctxt->instate = state;
  3285. return;
  3286. }
  3287. unfinished:
  3288. htmlParseErr(ctxt, XML_ERR_COMMENT_NOT_FINISHED,
  3289. "Comment not terminated \n<!--%.50s\n", buf, NULL);
  3290. xmlFree(buf);
  3291. }
  3292. /**
  3293. * htmlParseCharRef:
  3294. * @ctxt: an HTML parser context
  3295. *
  3296. * parse Reference declarations
  3297. *
  3298. * [66] CharRef ::= '&#' [0-9]+ ';' |
  3299. * '&#x' [0-9a-fA-F]+ ';'
  3300. *
  3301. * Returns the value parsed (as an int)
  3302. */
  3303. int
  3304. htmlParseCharRef(htmlParserCtxtPtr ctxt) {
  3305. int val = 0;
  3306. if ((ctxt == NULL) || (ctxt->input == NULL)) {
  3307. htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
  3308. "htmlParseCharRef: context error\n",
  3309. NULL, NULL);
  3310. return(0);
  3311. }
  3312. if ((CUR == '&') && (NXT(1) == '#') &&
  3313. ((NXT(2) == 'x') || NXT(2) == 'X')) {
  3314. SKIP(3);
  3315. while (CUR != ';') {
  3316. if ((CUR >= '0') && (CUR <= '9')) {
  3317. if (val < 0x110000)
  3318. val = val * 16 + (CUR - '0');
  3319. } else if ((CUR >= 'a') && (CUR <= 'f')) {
  3320. if (val < 0x110000)
  3321. val = val * 16 + (CUR - 'a') + 10;
  3322. } else if ((CUR >= 'A') && (CUR <= 'F')) {
  3323. if (val < 0x110000)
  3324. val = val * 16 + (CUR - 'A') + 10;
  3325. } else {
  3326. htmlParseErr(ctxt, XML_ERR_INVALID_HEX_CHARREF,
  3327. "htmlParseCharRef: missing semicolon\n",
  3328. NULL, NULL);
  3329. break;
  3330. }
  3331. NEXT;
  3332. }
  3333. if (CUR == ';')
  3334. NEXT;
  3335. } else if ((CUR == '&') && (NXT(1) == '#')) {
  3336. SKIP(2);
  3337. while (CUR != ';') {
  3338. if ((CUR >= '0') && (CUR <= '9')) {
  3339. if (val < 0x110000)
  3340. val = val * 10 + (CUR - '0');
  3341. } else {
  3342. htmlParseErr(ctxt, XML_ERR_INVALID_DEC_CHARREF,
  3343. "htmlParseCharRef: missing semicolon\n",
  3344. NULL, NULL);
  3345. break;
  3346. }
  3347. NEXT;
  3348. }
  3349. if (CUR == ';')
  3350. NEXT;
  3351. } else {
  3352. htmlParseErr(ctxt, XML_ERR_INVALID_CHARREF,
  3353. "htmlParseCharRef: invalid value\n", NULL, NULL);
  3354. }
  3355. /*
  3356. * Check the value IS_CHAR ...
  3357. */
  3358. if (IS_CHAR(val)) {
  3359. return(val);
  3360. } else if (val >= 0x110000) {
  3361. htmlParseErr(ctxt, XML_ERR_INVALID_CHAR,
  3362. "htmlParseCharRef: value too large\n", NULL, NULL);
  3363. } else {
  3364. htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
  3365. "htmlParseCharRef: invalid xmlChar value %d\n",
  3366. val);
  3367. }
  3368. return(0);
  3369. }
  3370. /**
  3371. * htmlParseDocTypeDecl:
  3372. * @ctxt: an HTML parser context
  3373. *
  3374. * parse a DOCTYPE declaration
  3375. *
  3376. * [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S?
  3377. * ('[' (markupdecl | PEReference | S)* ']' S?)? '>'
  3378. */
  3379. static void
  3380. htmlParseDocTypeDecl(htmlParserCtxtPtr ctxt) {
  3381. const xmlChar *name;
  3382. xmlChar *ExternalID = NULL;
  3383. xmlChar *URI = NULL;
  3384. /*
  3385. * We know that '<!DOCTYPE' has been detected.
  3386. */
  3387. SKIP(9);
  3388. SKIP_BLANKS;
  3389. /*
  3390. * Parse the DOCTYPE name.
  3391. */
  3392. name = htmlParseName(ctxt);
  3393. if (name == NULL) {
  3394. htmlParseErr(ctxt, XML_ERR_NAME_REQUIRED,
  3395. "htmlParseDocTypeDecl : no DOCTYPE name !\n",
  3396. NULL, NULL);
  3397. }
  3398. /*
  3399. * Check that upper(name) == "HTML" !!!!!!!!!!!!!
  3400. */
  3401. SKIP_BLANKS;
  3402. /*
  3403. * Check for SystemID and ExternalID
  3404. */
  3405. URI = htmlParseExternalID(ctxt, &ExternalID);
  3406. SKIP_BLANKS;
  3407. /*
  3408. * We should be at the end of the DOCTYPE declaration.
  3409. */
  3410. if (CUR != '>') {
  3411. htmlParseErr(ctxt, XML_ERR_DOCTYPE_NOT_FINISHED,
  3412. "DOCTYPE improperly terminated\n", NULL, NULL);
  3413. /* Ignore bogus content */
  3414. while ((CUR != 0) && (CUR != '>'))
  3415. NEXT;
  3416. }
  3417. if (CUR == '>')
  3418. NEXT;
  3419. /*
  3420. * Create or update the document accordingly to the DOCTYPE
  3421. */
  3422. if ((ctxt->sax != NULL) && (ctxt->sax->internalSubset != NULL) &&
  3423. (!ctxt->disableSAX))
  3424. ctxt->sax->internalSubset(ctxt->userData, name, ExternalID, URI);
  3425. /*
  3426. * Cleanup, since we don't use all those identifiers
  3427. */
  3428. if (URI != NULL) xmlFree(URI);
  3429. if (ExternalID != NULL) xmlFree(ExternalID);
  3430. }
  3431. /**
  3432. * htmlParseAttribute:
  3433. * @ctxt: an HTML parser context
  3434. * @value: a xmlChar ** used to store the value of the attribute
  3435. *
  3436. * parse an attribute
  3437. *
  3438. * [41] Attribute ::= Name Eq AttValue
  3439. *
  3440. * [25] Eq ::= S? '=' S?
  3441. *
  3442. * With namespace:
  3443. *
  3444. * [NS 11] Attribute ::= QName Eq AttValue
  3445. *
  3446. * Also the case QName == xmlns:??? is handled independently as a namespace
  3447. * definition.
  3448. *
  3449. * Returns the attribute name, and the value in *value.
  3450. */
  3451. static const xmlChar *
  3452. htmlParseAttribute(htmlParserCtxtPtr ctxt, xmlChar **value) {
  3453. const xmlChar *name;
  3454. xmlChar *val = NULL;
  3455. *value = NULL;
  3456. name = htmlParseHTMLName(ctxt);
  3457. if (name == NULL) {
  3458. htmlParseErr(ctxt, XML_ERR_NAME_REQUIRED,
  3459. "error parsing attribute name\n", NULL, NULL);
  3460. return(NULL);
  3461. }
  3462. /*
  3463. * read the value
  3464. */
  3465. SKIP_BLANKS;
  3466. if (CUR == '=') {
  3467. NEXT;
  3468. SKIP_BLANKS;
  3469. val = htmlParseAttValue(ctxt);
  3470. }
  3471. *value = val;
  3472. return(name);
  3473. }
  3474. /**
  3475. * htmlCheckEncodingDirect:
  3476. * @ctxt: an HTML parser context
  3477. * @attvalue: the attribute value
  3478. *
  3479. * Checks an attribute value to detect
  3480. * the encoding
  3481. * If a new encoding is detected the parser is switched to decode
  3482. * it and pass UTF8
  3483. */
  3484. static void
  3485. htmlCheckEncodingDirect(htmlParserCtxtPtr ctxt, const xmlChar *encoding) {
  3486. if ((ctxt == NULL) || (encoding == NULL) ||
  3487. (ctxt->options & HTML_PARSE_IGNORE_ENC))
  3488. return;
  3489. /* do not change encoding */
  3490. if (ctxt->input->encoding != NULL)
  3491. return;
  3492. if (encoding != NULL) {
  3493. xmlCharEncoding enc;
  3494. xmlCharEncodingHandlerPtr handler;
  3495. while ((*encoding == ' ') || (*encoding == '\t')) encoding++;
  3496. if (ctxt->input->encoding != NULL)
  3497. xmlFree((xmlChar *) ctxt->input->encoding);
  3498. ctxt->input->encoding = xmlStrdup(encoding);
  3499. enc = xmlParseCharEncoding((const char *) encoding);
  3500. /*
  3501. * registered set of known encodings
  3502. */
  3503. if (enc != XML_CHAR_ENCODING_ERROR) {
  3504. if (((enc == XML_CHAR_ENCODING_UTF16LE) ||
  3505. (enc == XML_CHAR_ENCODING_UTF16BE) ||
  3506. (enc == XML_CHAR_ENCODING_UCS4LE) ||
  3507. (enc == XML_CHAR_ENCODING_UCS4BE)) &&
  3508. (ctxt->input->buf != NULL) &&
  3509. (ctxt->input->buf->encoder == NULL)) {
  3510. htmlParseErr(ctxt, XML_ERR_INVALID_ENCODING,
  3511. "htmlCheckEncoding: wrong encoding meta\n",
  3512. NULL, NULL);
  3513. } else {
  3514. xmlSwitchEncoding(ctxt, enc);
  3515. }
  3516. ctxt->charset = XML_CHAR_ENCODING_UTF8;
  3517. } else {
  3518. /*
  3519. * fallback for unknown encodings
  3520. */
  3521. handler = xmlFindCharEncodingHandler((const char *) encoding);
  3522. if (handler != NULL) {
  3523. xmlSwitchToEncoding(ctxt, handler);
  3524. ctxt->charset = XML_CHAR_ENCODING_UTF8;
  3525. } else {
  3526. htmlParseErr(ctxt, XML_ERR_UNSUPPORTED_ENCODING,
  3527. "htmlCheckEncoding: unknown encoding %s\n",
  3528. encoding, NULL);
  3529. }
  3530. }
  3531. if ((ctxt->input->buf != NULL) &&
  3532. (ctxt->input->buf->encoder != NULL) &&
  3533. (ctxt->input->buf->raw != NULL) &&
  3534. (ctxt->input->buf->buffer != NULL)) {
  3535. int nbchars;
  3536. int processed;
  3537. /*
  3538. * convert as much as possible to the parser reading buffer.
  3539. */
  3540. processed = ctxt->input->cur - ctxt->input->base;
  3541. xmlBufShrink(ctxt->input->buf->buffer, processed);
  3542. nbchars = xmlCharEncInput(ctxt->input->buf, 1);
  3543. xmlBufResetInput(ctxt->input->buf->buffer, ctxt->input);
  3544. if (nbchars < 0) {
  3545. htmlParseErr(ctxt, XML_ERR_INVALID_ENCODING,
  3546. "htmlCheckEncoding: encoder error\n",
  3547. NULL, NULL);
  3548. }
  3549. }
  3550. }
  3551. }
  3552. /**
  3553. * htmlCheckEncoding:
  3554. * @ctxt: an HTML parser context
  3555. * @attvalue: the attribute value
  3556. *
  3557. * Checks an http-equiv attribute from a Meta tag to detect
  3558. * the encoding
  3559. * If a new encoding is detected the parser is switched to decode
  3560. * it and pass UTF8
  3561. */
  3562. static void
  3563. htmlCheckEncoding(htmlParserCtxtPtr ctxt, const xmlChar *attvalue) {
  3564. const xmlChar *encoding;
  3565. if (!attvalue)
  3566. return;
  3567. encoding = xmlStrcasestr(attvalue, BAD_CAST"charset");
  3568. if (encoding != NULL) {
  3569. encoding += 7;
  3570. }
  3571. /*
  3572. * skip blank
  3573. */
  3574. if (encoding && IS_BLANK_CH(*encoding))
  3575. encoding = xmlStrcasestr(attvalue, BAD_CAST"=");
  3576. if (encoding && *encoding == '=') {
  3577. encoding ++;
  3578. htmlCheckEncodingDirect(ctxt, encoding);
  3579. }
  3580. }
  3581. /**
  3582. * htmlCheckMeta:
  3583. * @ctxt: an HTML parser context
  3584. * @atts: the attributes values
  3585. *
  3586. * Checks an attributes from a Meta tag
  3587. */
  3588. static void
  3589. htmlCheckMeta(htmlParserCtxtPtr ctxt, const xmlChar **atts) {
  3590. int i;
  3591. const xmlChar *att, *value;
  3592. int http = 0;
  3593. const xmlChar *content = NULL;
  3594. if ((ctxt == NULL) || (atts == NULL))
  3595. return;
  3596. i = 0;
  3597. att = atts[i++];
  3598. while (att != NULL) {
  3599. value = atts[i++];
  3600. if ((value != NULL) && (!xmlStrcasecmp(att, BAD_CAST"http-equiv"))
  3601. && (!xmlStrcasecmp(value, BAD_CAST"Content-Type")))
  3602. http = 1;
  3603. else if ((value != NULL) && (!xmlStrcasecmp(att, BAD_CAST"charset")))
  3604. htmlCheckEncodingDirect(ctxt, value);
  3605. else if ((value != NULL) && (!xmlStrcasecmp(att, BAD_CAST"content")))
  3606. content = value;
  3607. att = atts[i++];
  3608. }
  3609. if ((http) && (content != NULL))
  3610. htmlCheckEncoding(ctxt, content);
  3611. }
  3612. /**
  3613. * htmlParseStartTag:
  3614. * @ctxt: an HTML parser context
  3615. *
  3616. * parse a start of tag either for rule element or
  3617. * EmptyElement. In both case we don't parse the tag closing chars.
  3618. *
  3619. * [40] STag ::= '<' Name (S Attribute)* S? '>'
  3620. *
  3621. * [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>'
  3622. *
  3623. * With namespace:
  3624. *
  3625. * [NS 8] STag ::= '<' QName (S Attribute)* S? '>'
  3626. *
  3627. * [NS 10] EmptyElement ::= '<' QName (S Attribute)* S? '/>'
  3628. *
  3629. * Returns 0 in case of success, -1 in case of error and 1 if discarded
  3630. */
  3631. static int
  3632. htmlParseStartTag(htmlParserCtxtPtr ctxt) {
  3633. const xmlChar *name;
  3634. const xmlChar *attname;
  3635. xmlChar *attvalue;
  3636. const xmlChar **atts;
  3637. int nbatts = 0;
  3638. int maxatts;
  3639. int meta = 0;
  3640. int i;
  3641. int discardtag = 0;
  3642. if ((ctxt == NULL) || (ctxt->input == NULL)) {
  3643. htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
  3644. "htmlParseStartTag: context error\n", NULL, NULL);
  3645. return -1;
  3646. }
  3647. if (ctxt->instate == XML_PARSER_EOF)
  3648. return(-1);
  3649. if (CUR != '<') return -1;
  3650. NEXT;
  3651. atts = ctxt->atts;
  3652. maxatts = ctxt->maxatts;
  3653. GROW;
  3654. name = htmlParseHTMLName(ctxt);
  3655. if (name == NULL) {
  3656. htmlParseErr(ctxt, XML_ERR_NAME_REQUIRED,
  3657. "htmlParseStartTag: invalid element name\n",
  3658. NULL, NULL);
  3659. /* Dump the bogus tag like browsers do */
  3660. while ((CUR != 0) && (CUR != '>') &&
  3661. (ctxt->instate != XML_PARSER_EOF))
  3662. NEXT;
  3663. return -1;
  3664. }
  3665. if (xmlStrEqual(name, BAD_CAST"meta"))
  3666. meta = 1;
  3667. /*
  3668. * Check for auto-closure of HTML elements.
  3669. */
  3670. htmlAutoClose(ctxt, name);
  3671. /*
  3672. * Check for implied HTML elements.
  3673. */
  3674. htmlCheckImplied(ctxt, name);
  3675. /*
  3676. * Avoid html at any level > 0, head at any level != 1
  3677. * or any attempt to recurse body
  3678. */
  3679. if ((ctxt->nameNr > 0) && (xmlStrEqual(name, BAD_CAST"html"))) {
  3680. htmlParseErr(ctxt, XML_HTML_STRUCURE_ERROR,
  3681. "htmlParseStartTag: misplaced <html> tag\n",
  3682. name, NULL);
  3683. discardtag = 1;
  3684. ctxt->depth++;
  3685. }
  3686. if ((ctxt->nameNr != 1) &&
  3687. (xmlStrEqual(name, BAD_CAST"head"))) {
  3688. htmlParseErr(ctxt, XML_HTML_STRUCURE_ERROR,
  3689. "htmlParseStartTag: misplaced <head> tag\n",
  3690. name, NULL);
  3691. discardtag = 1;
  3692. ctxt->depth++;
  3693. }
  3694. if (xmlStrEqual(name, BAD_CAST"body")) {
  3695. int indx;
  3696. for (indx = 0;indx < ctxt->nameNr;indx++) {
  3697. if (xmlStrEqual(ctxt->nameTab[indx], BAD_CAST"body")) {
  3698. htmlParseErr(ctxt, XML_HTML_STRUCURE_ERROR,
  3699. "htmlParseStartTag: misplaced <body> tag\n",
  3700. name, NULL);
  3701. discardtag = 1;
  3702. ctxt->depth++;
  3703. }
  3704. }
  3705. }
  3706. /*
  3707. * Now parse the attributes, it ends up with the ending
  3708. *
  3709. * (S Attribute)* S?
  3710. */
  3711. SKIP_BLANKS;
  3712. while ((CUR != 0) &&
  3713. (CUR != '>') &&
  3714. ((CUR != '/') || (NXT(1) != '>'))) {
  3715. GROW;
  3716. attname = htmlParseAttribute(ctxt, &attvalue);
  3717. if (attname != NULL) {
  3718. /*
  3719. * Well formedness requires at most one declaration of an attribute
  3720. */
  3721. for (i = 0; i < nbatts;i += 2) {
  3722. if (xmlStrEqual(atts[i], attname)) {
  3723. htmlParseErr(ctxt, XML_ERR_ATTRIBUTE_REDEFINED,
  3724. "Attribute %s redefined\n", attname, NULL);
  3725. if (attvalue != NULL)
  3726. xmlFree(attvalue);
  3727. goto failed;
  3728. }
  3729. }
  3730. /*
  3731. * Add the pair to atts
  3732. */
  3733. if (atts == NULL) {
  3734. maxatts = 22; /* allow for 10 attrs by default */
  3735. atts = (const xmlChar **)
  3736. xmlMalloc(maxatts * sizeof(xmlChar *));
  3737. if (atts == NULL) {
  3738. htmlErrMemory(ctxt, NULL);
  3739. if (attvalue != NULL)
  3740. xmlFree(attvalue);
  3741. goto failed;
  3742. }
  3743. ctxt->atts = atts;
  3744. ctxt->maxatts = maxatts;
  3745. } else if (nbatts + 4 > maxatts) {
  3746. const xmlChar **n;
  3747. maxatts *= 2;
  3748. n = (const xmlChar **) xmlRealloc((void *) atts,
  3749. maxatts * sizeof(const xmlChar *));
  3750. if (n == NULL) {
  3751. htmlErrMemory(ctxt, NULL);
  3752. if (attvalue != NULL)
  3753. xmlFree(attvalue);
  3754. goto failed;
  3755. }
  3756. atts = n;
  3757. ctxt->atts = atts;
  3758. ctxt->maxatts = maxatts;
  3759. }
  3760. atts[nbatts++] = attname;
  3761. atts[nbatts++] = attvalue;
  3762. atts[nbatts] = NULL;
  3763. atts[nbatts + 1] = NULL;
  3764. }
  3765. else {
  3766. if (attvalue != NULL)
  3767. xmlFree(attvalue);
  3768. /* Dump the bogus attribute string up to the next blank or
  3769. * the end of the tag. */
  3770. while ((CUR != 0) &&
  3771. !(IS_BLANK_CH(CUR)) && (CUR != '>') &&
  3772. ((CUR != '/') || (NXT(1) != '>')))
  3773. NEXT;
  3774. }
  3775. failed:
  3776. SKIP_BLANKS;
  3777. }
  3778. /*
  3779. * Handle specific association to the META tag
  3780. */
  3781. if (meta && (nbatts != 0))
  3782. htmlCheckMeta(ctxt, atts);
  3783. /*
  3784. * SAX: Start of Element !
  3785. */
  3786. if (!discardtag) {
  3787. htmlnamePush(ctxt, name);
  3788. if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL)) {
  3789. if (nbatts != 0)
  3790. ctxt->sax->startElement(ctxt->userData, name, atts);
  3791. else
  3792. ctxt->sax->startElement(ctxt->userData, name, NULL);
  3793. }
  3794. }
  3795. if (atts != NULL) {
  3796. for (i = 1;i < nbatts;i += 2) {
  3797. if (atts[i] != NULL)
  3798. xmlFree((xmlChar *) atts[i]);
  3799. }
  3800. }
  3801. return(discardtag);
  3802. }
  3803. /**
  3804. * htmlParseEndTag:
  3805. * @ctxt: an HTML parser context
  3806. *
  3807. * parse an end of tag
  3808. *
  3809. * [42] ETag ::= '</' Name S? '>'
  3810. *
  3811. * With namespace
  3812. *
  3813. * [NS 9] ETag ::= '</' QName S? '>'
  3814. *
  3815. * Returns 1 if the current level should be closed.
  3816. */
  3817. static int
  3818. htmlParseEndTag(htmlParserCtxtPtr ctxt)
  3819. {
  3820. const xmlChar *name;
  3821. const xmlChar *oldname;
  3822. int i, ret;
  3823. if ((CUR != '<') || (NXT(1) != '/')) {
  3824. htmlParseErr(ctxt, XML_ERR_LTSLASH_REQUIRED,
  3825. "htmlParseEndTag: '</' not found\n", NULL, NULL);
  3826. return (0);
  3827. }
  3828. SKIP(2);
  3829. name = htmlParseHTMLName(ctxt);
  3830. if (name == NULL)
  3831. return (0);
  3832. /*
  3833. * We should definitely be at the ending "S? '>'" part
  3834. */
  3835. SKIP_BLANKS;
  3836. if (CUR != '>') {
  3837. htmlParseErr(ctxt, XML_ERR_GT_REQUIRED,
  3838. "End tag : expected '>'\n", NULL, NULL);
  3839. /* Skip to next '>' */
  3840. while ((CUR != 0) && (CUR != '>'))
  3841. NEXT;
  3842. }
  3843. if (CUR == '>')
  3844. NEXT;
  3845. /*
  3846. * if we ignored misplaced tags in htmlParseStartTag don't pop them
  3847. * out now.
  3848. */
  3849. if ((ctxt->depth > 0) &&
  3850. (xmlStrEqual(name, BAD_CAST "html") ||
  3851. xmlStrEqual(name, BAD_CAST "body") ||
  3852. xmlStrEqual(name, BAD_CAST "head"))) {
  3853. ctxt->depth--;
  3854. return (0);
  3855. }
  3856. /*
  3857. * If the name read is not one of the element in the parsing stack
  3858. * then return, it's just an error.
  3859. */
  3860. for (i = (ctxt->nameNr - 1); i >= 0; i--) {
  3861. if (xmlStrEqual(name, ctxt->nameTab[i]))
  3862. break;
  3863. }
  3864. if (i < 0) {
  3865. htmlParseErr(ctxt, XML_ERR_TAG_NAME_MISMATCH,
  3866. "Unexpected end tag : %s\n", name, NULL);
  3867. return (0);
  3868. }
  3869. /*
  3870. * Check for auto-closure of HTML elements.
  3871. */
  3872. htmlAutoCloseOnClose(ctxt, name);
  3873. /*
  3874. * Well formedness constraints, opening and closing must match.
  3875. * With the exception that the autoclose may have popped stuff out
  3876. * of the stack.
  3877. */
  3878. if ((ctxt->name != NULL) && (!xmlStrEqual(ctxt->name, name))) {
  3879. htmlParseErr(ctxt, XML_ERR_TAG_NAME_MISMATCH,
  3880. "Opening and ending tag mismatch: %s and %s\n",
  3881. name, ctxt->name);
  3882. }
  3883. /*
  3884. * SAX: End of Tag
  3885. */
  3886. oldname = ctxt->name;
  3887. if ((oldname != NULL) && (xmlStrEqual(oldname, name))) {
  3888. if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
  3889. ctxt->sax->endElement(ctxt->userData, name);
  3890. htmlNodeInfoPop(ctxt);
  3891. htmlnamePop(ctxt);
  3892. ret = 1;
  3893. } else {
  3894. ret = 0;
  3895. }
  3896. return (ret);
  3897. }
  3898. /**
  3899. * htmlParseReference:
  3900. * @ctxt: an HTML parser context
  3901. *
  3902. * parse and handle entity references in content,
  3903. * this will end-up in a call to character() since this is either a
  3904. * CharRef, or a predefined entity.
  3905. */
  3906. static void
  3907. htmlParseReference(htmlParserCtxtPtr ctxt) {
  3908. const htmlEntityDesc * ent;
  3909. xmlChar out[6];
  3910. const xmlChar *name;
  3911. if (CUR != '&') return;
  3912. if (NXT(1) == '#') {
  3913. unsigned int c;
  3914. int bits, i = 0;
  3915. c = htmlParseCharRef(ctxt);
  3916. if (c == 0)
  3917. return;
  3918. if (c < 0x80) { out[i++]= c; bits= -6; }
  3919. else if (c < 0x800) { out[i++]=((c >> 6) & 0x1F) | 0xC0; bits= 0; }
  3920. else if (c < 0x10000) { out[i++]=((c >> 12) & 0x0F) | 0xE0; bits= 6; }
  3921. else { out[i++]=((c >> 18) & 0x07) | 0xF0; bits= 12; }
  3922. for ( ; bits >= 0; bits-= 6) {
  3923. out[i++]= ((c >> bits) & 0x3F) | 0x80;
  3924. }
  3925. out[i] = 0;
  3926. htmlCheckParagraph(ctxt);
  3927. if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
  3928. ctxt->sax->characters(ctxt->userData, out, i);
  3929. } else {
  3930. ent = htmlParseEntityRef(ctxt, &name);
  3931. if (name == NULL) {
  3932. htmlCheckParagraph(ctxt);
  3933. if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
  3934. ctxt->sax->characters(ctxt->userData, BAD_CAST "&", 1);
  3935. return;
  3936. }
  3937. if ((ent == NULL) || !(ent->value > 0)) {
  3938. htmlCheckParagraph(ctxt);
  3939. if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL)) {
  3940. ctxt->sax->characters(ctxt->userData, BAD_CAST "&", 1);
  3941. ctxt->sax->characters(ctxt->userData, name, xmlStrlen(name));
  3942. /* ctxt->sax->characters(ctxt->userData, BAD_CAST ";", 1); */
  3943. }
  3944. } else {
  3945. unsigned int c;
  3946. int bits, i = 0;
  3947. c = ent->value;
  3948. if (c < 0x80)
  3949. { out[i++]= c; bits= -6; }
  3950. else if (c < 0x800)
  3951. { out[i++]=((c >> 6) & 0x1F) | 0xC0; bits= 0; }
  3952. else if (c < 0x10000)
  3953. { out[i++]=((c >> 12) & 0x0F) | 0xE0; bits= 6; }
  3954. else
  3955. { out[i++]=((c >> 18) & 0x07) | 0xF0; bits= 12; }
  3956. for ( ; bits >= 0; bits-= 6) {
  3957. out[i++]= ((c >> bits) & 0x3F) | 0x80;
  3958. }
  3959. out[i] = 0;
  3960. htmlCheckParagraph(ctxt);
  3961. if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
  3962. ctxt->sax->characters(ctxt->userData, out, i);
  3963. }
  3964. }
  3965. }
  3966. /**
  3967. * htmlParseContent:
  3968. * @ctxt: an HTML parser context
  3969. *
  3970. * Parse a content: comment, sub-element, reference or text.
  3971. * Kept for compatibility with old code
  3972. */
  3973. static void
  3974. htmlParseContent(htmlParserCtxtPtr ctxt) {
  3975. xmlChar *currentNode;
  3976. int depth;
  3977. const xmlChar *name;
  3978. currentNode = xmlStrdup(ctxt->name);
  3979. depth = ctxt->nameNr;
  3980. while (1) {
  3981. GROW;
  3982. if (ctxt->instate == XML_PARSER_EOF)
  3983. break;
  3984. /*
  3985. * Our tag or one of it's parent or children is ending.
  3986. */
  3987. if ((CUR == '<') && (NXT(1) == '/')) {
  3988. if (htmlParseEndTag(ctxt) &&
  3989. ((currentNode != NULL) || (ctxt->nameNr == 0))) {
  3990. if (currentNode != NULL)
  3991. xmlFree(currentNode);
  3992. return;
  3993. }
  3994. continue; /* while */
  3995. }
  3996. else if ((CUR == '<') &&
  3997. ((IS_ASCII_LETTER(NXT(1))) ||
  3998. (NXT(1) == '_') || (NXT(1) == ':'))) {
  3999. name = htmlParseHTMLName_nonInvasive(ctxt);
  4000. if (name == NULL) {
  4001. htmlParseErr(ctxt, XML_ERR_NAME_REQUIRED,
  4002. "htmlParseStartTag: invalid element name\n",
  4003. NULL, NULL);
  4004. /* Dump the bogus tag like browsers do */
  4005. while ((CUR != 0) && (CUR != '>'))
  4006. NEXT;
  4007. if (currentNode != NULL)
  4008. xmlFree(currentNode);
  4009. return;
  4010. }
  4011. if (ctxt->name != NULL) {
  4012. if (htmlCheckAutoClose(name, ctxt->name) == 1) {
  4013. htmlAutoClose(ctxt, name);
  4014. continue;
  4015. }
  4016. }
  4017. }
  4018. /*
  4019. * Has this node been popped out during parsing of
  4020. * the next element
  4021. */
  4022. if ((ctxt->nameNr > 0) && (depth >= ctxt->nameNr) &&
  4023. (!xmlStrEqual(currentNode, ctxt->name)))
  4024. {
  4025. if (currentNode != NULL) xmlFree(currentNode);
  4026. return;
  4027. }
  4028. if ((CUR != 0) && ((xmlStrEqual(currentNode, BAD_CAST"script")) ||
  4029. (xmlStrEqual(currentNode, BAD_CAST"style")))) {
  4030. /*
  4031. * Handle SCRIPT/STYLE separately
  4032. */
  4033. htmlParseScript(ctxt);
  4034. } else {
  4035. /*
  4036. * Sometimes DOCTYPE arrives in the middle of the document
  4037. */
  4038. if ((CUR == '<') && (NXT(1) == '!') &&
  4039. (UPP(2) == 'D') && (UPP(3) == 'O') &&
  4040. (UPP(4) == 'C') && (UPP(5) == 'T') &&
  4041. (UPP(6) == 'Y') && (UPP(7) == 'P') &&
  4042. (UPP(8) == 'E')) {
  4043. htmlParseErr(ctxt, XML_HTML_STRUCURE_ERROR,
  4044. "Misplaced DOCTYPE declaration\n",
  4045. BAD_CAST "DOCTYPE" , NULL);
  4046. htmlParseDocTypeDecl(ctxt);
  4047. }
  4048. /*
  4049. * First case : a comment
  4050. */
  4051. if ((CUR == '<') && (NXT(1) == '!') &&
  4052. (NXT(2) == '-') && (NXT(3) == '-')) {
  4053. htmlParseComment(ctxt);
  4054. }
  4055. /*
  4056. * Second case : a Processing Instruction.
  4057. */
  4058. else if ((CUR == '<') && (NXT(1) == '?')) {
  4059. htmlParsePI(ctxt);
  4060. }
  4061. /*
  4062. * Third case : a sub-element.
  4063. */
  4064. else if ((CUR == '<') && IS_ASCII_LETTER(NXT(1))) {
  4065. htmlParseElement(ctxt);
  4066. }
  4067. else if (CUR == '<') {
  4068. if ((ctxt->sax != NULL) && (!ctxt->disableSAX) &&
  4069. (ctxt->sax->characters != NULL))
  4070. ctxt->sax->characters(ctxt->userData, BAD_CAST "<", 1);
  4071. NEXT;
  4072. }
  4073. /*
  4074. * Fourth case : a reference. If if has not been resolved,
  4075. * parsing returns it's Name, create the node
  4076. */
  4077. else if (CUR == '&') {
  4078. htmlParseReference(ctxt);
  4079. }
  4080. /*
  4081. * Fifth case : end of the resource
  4082. */
  4083. else if (CUR == 0) {
  4084. htmlAutoCloseOnEnd(ctxt);
  4085. break;
  4086. }
  4087. /*
  4088. * Last case, text. Note that References are handled directly.
  4089. */
  4090. else {
  4091. htmlParseCharData(ctxt);
  4092. }
  4093. }
  4094. GROW;
  4095. }
  4096. if (currentNode != NULL) xmlFree(currentNode);
  4097. }
  4098. /**
  4099. * htmlParseElement:
  4100. * @ctxt: an HTML parser context
  4101. *
  4102. * parse an HTML element, this is highly recursive
  4103. * this is kept for compatibility with previous code versions
  4104. *
  4105. * [39] element ::= EmptyElemTag | STag content ETag
  4106. *
  4107. * [41] Attribute ::= Name Eq AttValue
  4108. */
  4109. void
  4110. htmlParseElement(htmlParserCtxtPtr ctxt) {
  4111. const xmlChar *name;
  4112. xmlChar *currentNode = NULL;
  4113. const htmlElemDesc * info;
  4114. htmlParserNodeInfo node_info;
  4115. int failed;
  4116. int depth;
  4117. const xmlChar *oldptr;
  4118. if ((ctxt == NULL) || (ctxt->input == NULL)) {
  4119. htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
  4120. "htmlParseElement: context error\n", NULL, NULL);
  4121. return;
  4122. }
  4123. if (ctxt->instate == XML_PARSER_EOF)
  4124. return;
  4125. /* Capture start position */
  4126. if (ctxt->record_info) {
  4127. node_info.begin_pos = ctxt->input->consumed +
  4128. (CUR_PTR - ctxt->input->base);
  4129. node_info.begin_line = ctxt->input->line;
  4130. }
  4131. failed = htmlParseStartTag(ctxt);
  4132. name = ctxt->name;
  4133. if ((failed == -1) || (name == NULL)) {
  4134. if (CUR == '>')
  4135. NEXT;
  4136. return;
  4137. }
  4138. /*
  4139. * Lookup the info for that element.
  4140. */
  4141. info = htmlTagLookup(name);
  4142. if (info == NULL) {
  4143. htmlParseErr(ctxt, XML_HTML_UNKNOWN_TAG,
  4144. "Tag %s invalid\n", name, NULL);
  4145. }
  4146. /*
  4147. * Check for an Empty Element labeled the XML/SGML way
  4148. */
  4149. if ((CUR == '/') && (NXT(1) == '>')) {
  4150. SKIP(2);
  4151. if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
  4152. ctxt->sax->endElement(ctxt->userData, name);
  4153. htmlnamePop(ctxt);
  4154. return;
  4155. }
  4156. if (CUR == '>') {
  4157. NEXT;
  4158. } else {
  4159. htmlParseErr(ctxt, XML_ERR_GT_REQUIRED,
  4160. "Couldn't find end of Start Tag %s\n", name, NULL);
  4161. /*
  4162. * end of parsing of this node.
  4163. */
  4164. if (xmlStrEqual(name, ctxt->name)) {
  4165. nodePop(ctxt);
  4166. htmlnamePop(ctxt);
  4167. }
  4168. /*
  4169. * Capture end position and add node
  4170. */
  4171. if (ctxt->record_info) {
  4172. node_info.end_pos = ctxt->input->consumed +
  4173. (CUR_PTR - ctxt->input->base);
  4174. node_info.end_line = ctxt->input->line;
  4175. node_info.node = ctxt->node;
  4176. xmlParserAddNodeInfo(ctxt, &node_info);
  4177. }
  4178. return;
  4179. }
  4180. /*
  4181. * Check for an Empty Element from DTD definition
  4182. */
  4183. if ((info != NULL) && (info->empty)) {
  4184. if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
  4185. ctxt->sax->endElement(ctxt->userData, name);
  4186. htmlnamePop(ctxt);
  4187. return;
  4188. }
  4189. /*
  4190. * Parse the content of the element:
  4191. */
  4192. currentNode = xmlStrdup(ctxt->name);
  4193. depth = ctxt->nameNr;
  4194. while (CUR != 0) {
  4195. oldptr = ctxt->input->cur;
  4196. htmlParseContent(ctxt);
  4197. if (oldptr==ctxt->input->cur) break;
  4198. if (ctxt->nameNr < depth) break;
  4199. }
  4200. /*
  4201. * Capture end position and add node
  4202. */
  4203. if ( currentNode != NULL && ctxt->record_info ) {
  4204. node_info.end_pos = ctxt->input->consumed +
  4205. (CUR_PTR - ctxt->input->base);
  4206. node_info.end_line = ctxt->input->line;
  4207. node_info.node = ctxt->node;
  4208. xmlParserAddNodeInfo(ctxt, &node_info);
  4209. }
  4210. if (CUR == 0) {
  4211. htmlAutoCloseOnEnd(ctxt);
  4212. }
  4213. if (currentNode != NULL)
  4214. xmlFree(currentNode);
  4215. }
  4216. static void
  4217. htmlParserFinishElementParsing(htmlParserCtxtPtr ctxt) {
  4218. /*
  4219. * Capture end position and add node
  4220. */
  4221. if ( ctxt->node != NULL && ctxt->record_info ) {
  4222. ctxt->nodeInfo->end_pos = ctxt->input->consumed +
  4223. (CUR_PTR - ctxt->input->base);
  4224. ctxt->nodeInfo->end_line = ctxt->input->line;
  4225. ctxt->nodeInfo->node = ctxt->node;
  4226. xmlParserAddNodeInfo(ctxt, ctxt->nodeInfo);
  4227. htmlNodeInfoPop(ctxt);
  4228. }
  4229. if (CUR == 0) {
  4230. htmlAutoCloseOnEnd(ctxt);
  4231. }
  4232. }
  4233. /**
  4234. * htmlParseElementInternal:
  4235. * @ctxt: an HTML parser context
  4236. *
  4237. * parse an HTML element, new version, non recursive
  4238. *
  4239. * [39] element ::= EmptyElemTag | STag content ETag
  4240. *
  4241. * [41] Attribute ::= Name Eq AttValue
  4242. */
  4243. static void
  4244. htmlParseElementInternal(htmlParserCtxtPtr ctxt) {
  4245. const xmlChar *name;
  4246. const htmlElemDesc * info;
  4247. htmlParserNodeInfo node_info = { NULL, 0, 0, 0, 0 };
  4248. int failed;
  4249. if ((ctxt == NULL) || (ctxt->input == NULL)) {
  4250. htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
  4251. "htmlParseElementInternal: context error\n", NULL, NULL);
  4252. return;
  4253. }
  4254. if (ctxt->instate == XML_PARSER_EOF)
  4255. return;
  4256. /* Capture start position */
  4257. if (ctxt->record_info) {
  4258. node_info.begin_pos = ctxt->input->consumed +
  4259. (CUR_PTR - ctxt->input->base);
  4260. node_info.begin_line = ctxt->input->line;
  4261. }
  4262. failed = htmlParseStartTag(ctxt);
  4263. name = ctxt->name;
  4264. if ((failed == -1) || (name == NULL)) {
  4265. if (CUR == '>')
  4266. NEXT;
  4267. return;
  4268. }
  4269. /*
  4270. * Lookup the info for that element.
  4271. */
  4272. info = htmlTagLookup(name);
  4273. if (info == NULL) {
  4274. htmlParseErr(ctxt, XML_HTML_UNKNOWN_TAG,
  4275. "Tag %s invalid\n", name, NULL);
  4276. }
  4277. /*
  4278. * Check for an Empty Element labeled the XML/SGML way
  4279. */
  4280. if ((CUR == '/') && (NXT(1) == '>')) {
  4281. SKIP(2);
  4282. if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
  4283. ctxt->sax->endElement(ctxt->userData, name);
  4284. htmlnamePop(ctxt);
  4285. return;
  4286. }
  4287. if (CUR == '>') {
  4288. NEXT;
  4289. } else {
  4290. htmlParseErr(ctxt, XML_ERR_GT_REQUIRED,
  4291. "Couldn't find end of Start Tag %s\n", name, NULL);
  4292. /*
  4293. * end of parsing of this node.
  4294. */
  4295. if (xmlStrEqual(name, ctxt->name)) {
  4296. nodePop(ctxt);
  4297. htmlnamePop(ctxt);
  4298. }
  4299. if (ctxt->record_info)
  4300. htmlNodeInfoPush(ctxt, &node_info);
  4301. htmlParserFinishElementParsing(ctxt);
  4302. return;
  4303. }
  4304. /*
  4305. * Check for an Empty Element from DTD definition
  4306. */
  4307. if ((info != NULL) && (info->empty)) {
  4308. if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
  4309. ctxt->sax->endElement(ctxt->userData, name);
  4310. htmlnamePop(ctxt);
  4311. return;
  4312. }
  4313. if (ctxt->record_info)
  4314. htmlNodeInfoPush(ctxt, &node_info);
  4315. }
  4316. /**
  4317. * htmlParseContentInternal:
  4318. * @ctxt: an HTML parser context
  4319. *
  4320. * Parse a content: comment, sub-element, reference or text.
  4321. * New version for non recursive htmlParseElementInternal
  4322. */
  4323. static void
  4324. htmlParseContentInternal(htmlParserCtxtPtr ctxt) {
  4325. xmlChar *currentNode;
  4326. int depth;
  4327. const xmlChar *name;
  4328. currentNode = xmlStrdup(ctxt->name);
  4329. depth = ctxt->nameNr;
  4330. while (1) {
  4331. GROW;
  4332. if (ctxt->instate == XML_PARSER_EOF)
  4333. break;
  4334. /*
  4335. * Our tag or one of it's parent or children is ending.
  4336. */
  4337. if ((CUR == '<') && (NXT(1) == '/')) {
  4338. if (htmlParseEndTag(ctxt) &&
  4339. ((currentNode != NULL) || (ctxt->nameNr == 0))) {
  4340. if (currentNode != NULL)
  4341. xmlFree(currentNode);
  4342. currentNode = xmlStrdup(ctxt->name);
  4343. depth = ctxt->nameNr;
  4344. }
  4345. continue; /* while */
  4346. }
  4347. else if ((CUR == '<') &&
  4348. ((IS_ASCII_LETTER(NXT(1))) ||
  4349. (NXT(1) == '_') || (NXT(1) == ':'))) {
  4350. name = htmlParseHTMLName_nonInvasive(ctxt);
  4351. if (name == NULL) {
  4352. htmlParseErr(ctxt, XML_ERR_NAME_REQUIRED,
  4353. "htmlParseStartTag: invalid element name\n",
  4354. NULL, NULL);
  4355. /* Dump the bogus tag like browsers do */
  4356. while ((CUR == 0) && (CUR != '>'))
  4357. NEXT;
  4358. htmlParserFinishElementParsing(ctxt);
  4359. if (currentNode != NULL)
  4360. xmlFree(currentNode);
  4361. currentNode = xmlStrdup(ctxt->name);
  4362. depth = ctxt->nameNr;
  4363. continue;
  4364. }
  4365. if (ctxt->name != NULL) {
  4366. if (htmlCheckAutoClose(name, ctxt->name) == 1) {
  4367. htmlAutoClose(ctxt, name);
  4368. continue;
  4369. }
  4370. }
  4371. }
  4372. /*
  4373. * Has this node been popped out during parsing of
  4374. * the next element
  4375. */
  4376. if ((ctxt->nameNr > 0) && (depth >= ctxt->nameNr) &&
  4377. (!xmlStrEqual(currentNode, ctxt->name)))
  4378. {
  4379. htmlParserFinishElementParsing(ctxt);
  4380. if (currentNode != NULL) xmlFree(currentNode);
  4381. currentNode = xmlStrdup(ctxt->name);
  4382. depth = ctxt->nameNr;
  4383. continue;
  4384. }
  4385. if ((CUR != 0) && ((xmlStrEqual(currentNode, BAD_CAST"script")) ||
  4386. (xmlStrEqual(currentNode, BAD_CAST"style")))) {
  4387. /*
  4388. * Handle SCRIPT/STYLE separately
  4389. */
  4390. htmlParseScript(ctxt);
  4391. } else {
  4392. /*
  4393. * Sometimes DOCTYPE arrives in the middle of the document
  4394. */
  4395. if ((CUR == '<') && (NXT(1) == '!') &&
  4396. (UPP(2) == 'D') && (UPP(3) == 'O') &&
  4397. (UPP(4) == 'C') && (UPP(5) == 'T') &&
  4398. (UPP(6) == 'Y') && (UPP(7) == 'P') &&
  4399. (UPP(8) == 'E')) {
  4400. htmlParseErr(ctxt, XML_HTML_STRUCURE_ERROR,
  4401. "Misplaced DOCTYPE declaration\n",
  4402. BAD_CAST "DOCTYPE" , NULL);
  4403. htmlParseDocTypeDecl(ctxt);
  4404. }
  4405. /*
  4406. * First case : a comment
  4407. */
  4408. if ((CUR == '<') && (NXT(1) == '!') &&
  4409. (NXT(2) == '-') && (NXT(3) == '-')) {
  4410. htmlParseComment(ctxt);
  4411. }
  4412. /*
  4413. * Second case : a Processing Instruction.
  4414. */
  4415. else if ((CUR == '<') && (NXT(1) == '?')) {
  4416. htmlParsePI(ctxt);
  4417. }
  4418. /*
  4419. * Third case : a sub-element.
  4420. */
  4421. else if ((CUR == '<') && IS_ASCII_LETTER(NXT(1))) {
  4422. htmlParseElementInternal(ctxt);
  4423. if (currentNode != NULL) xmlFree(currentNode);
  4424. currentNode = xmlStrdup(ctxt->name);
  4425. depth = ctxt->nameNr;
  4426. }
  4427. else if (CUR == '<') {
  4428. if ((ctxt->sax != NULL) && (!ctxt->disableSAX) &&
  4429. (ctxt->sax->characters != NULL))
  4430. ctxt->sax->characters(ctxt->userData, BAD_CAST "<", 1);
  4431. NEXT;
  4432. }
  4433. /*
  4434. * Fourth case : a reference. If if has not been resolved,
  4435. * parsing returns it's Name, create the node
  4436. */
  4437. else if (CUR == '&') {
  4438. htmlParseReference(ctxt);
  4439. }
  4440. /*
  4441. * Fifth case : end of the resource
  4442. */
  4443. else if (CUR == 0) {
  4444. htmlAutoCloseOnEnd(ctxt);
  4445. break;
  4446. }
  4447. /*
  4448. * Last case, text. Note that References are handled directly.
  4449. */
  4450. else {
  4451. htmlParseCharData(ctxt);
  4452. }
  4453. }
  4454. GROW;
  4455. }
  4456. if (currentNode != NULL) xmlFree(currentNode);
  4457. }
  4458. /**
  4459. * htmlParseContent:
  4460. * @ctxt: an HTML parser context
  4461. *
  4462. * Parse a content: comment, sub-element, reference or text.
  4463. * This is the entry point when called from parser.c
  4464. */
  4465. void
  4466. __htmlParseContent(void *ctxt) {
  4467. if (ctxt != NULL)
  4468. htmlParseContentInternal((htmlParserCtxtPtr) ctxt);
  4469. }
  4470. /**
  4471. * htmlParseDocument:
  4472. * @ctxt: an HTML parser context
  4473. *
  4474. * parse an HTML document (and build a tree if using the standard SAX
  4475. * interface).
  4476. *
  4477. * Returns 0, -1 in case of error. the parser context is augmented
  4478. * as a result of the parsing.
  4479. */
  4480. int
  4481. htmlParseDocument(htmlParserCtxtPtr ctxt) {
  4482. xmlChar start[4];
  4483. xmlCharEncoding enc;
  4484. xmlDtdPtr dtd;
  4485. xmlInitParser();
  4486. htmlDefaultSAXHandlerInit();
  4487. if ((ctxt == NULL) || (ctxt->input == NULL)) {
  4488. htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
  4489. "htmlParseDocument: context error\n", NULL, NULL);
  4490. return(XML_ERR_INTERNAL_ERROR);
  4491. }
  4492. ctxt->html = 1;
  4493. ctxt->linenumbers = 1;
  4494. GROW;
  4495. /*
  4496. * SAX: beginning of the document processing.
  4497. */
  4498. if ((ctxt->sax) && (ctxt->sax->setDocumentLocator))
  4499. ctxt->sax->setDocumentLocator(ctxt->userData, &xmlDefaultSAXLocator);
  4500. if ((ctxt->encoding == (const xmlChar *)XML_CHAR_ENCODING_NONE) &&
  4501. ((ctxt->input->end - ctxt->input->cur) >= 4)) {
  4502. /*
  4503. * Get the 4 first bytes and decode the charset
  4504. * if enc != XML_CHAR_ENCODING_NONE
  4505. * plug some encoding conversion routines.
  4506. */
  4507. start[0] = RAW;
  4508. start[1] = NXT(1);
  4509. start[2] = NXT(2);
  4510. start[3] = NXT(3);
  4511. enc = xmlDetectCharEncoding(&start[0], 4);
  4512. if (enc != XML_CHAR_ENCODING_NONE) {
  4513. xmlSwitchEncoding(ctxt, enc);
  4514. }
  4515. }
  4516. /*
  4517. * Wipe out everything which is before the first '<'
  4518. */
  4519. SKIP_BLANKS;
  4520. if (CUR == 0) {
  4521. htmlParseErr(ctxt, XML_ERR_DOCUMENT_EMPTY,
  4522. "Document is empty\n", NULL, NULL);
  4523. }
  4524. if ((ctxt->sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX))
  4525. ctxt->sax->startDocument(ctxt->userData);
  4526. /*
  4527. * Parse possible comments and PIs before any content
  4528. */
  4529. while (((CUR == '<') && (NXT(1) == '!') &&
  4530. (NXT(2) == '-') && (NXT(3) == '-')) ||
  4531. ((CUR == '<') && (NXT(1) == '?'))) {
  4532. htmlParseComment(ctxt);
  4533. htmlParsePI(ctxt);
  4534. SKIP_BLANKS;
  4535. }
  4536. /*
  4537. * Then possibly doc type declaration(s) and more Misc
  4538. * (doctypedecl Misc*)?
  4539. */
  4540. if ((CUR == '<') && (NXT(1) == '!') &&
  4541. (UPP(2) == 'D') && (UPP(3) == 'O') &&
  4542. (UPP(4) == 'C') && (UPP(5) == 'T') &&
  4543. (UPP(6) == 'Y') && (UPP(7) == 'P') &&
  4544. (UPP(8) == 'E')) {
  4545. htmlParseDocTypeDecl(ctxt);
  4546. }
  4547. SKIP_BLANKS;
  4548. /*
  4549. * Parse possible comments and PIs before any content
  4550. */
  4551. while (((CUR == '<') && (NXT(1) == '!') &&
  4552. (NXT(2) == '-') && (NXT(3) == '-')) ||
  4553. ((CUR == '<') && (NXT(1) == '?'))) {
  4554. htmlParseComment(ctxt);
  4555. htmlParsePI(ctxt);
  4556. SKIP_BLANKS;
  4557. }
  4558. /*
  4559. * Time to start parsing the tree itself
  4560. */
  4561. htmlParseContentInternal(ctxt);
  4562. /*
  4563. * autoclose
  4564. */
  4565. if (CUR == 0)
  4566. htmlAutoCloseOnEnd(ctxt);
  4567. /*
  4568. * SAX: end of the document processing.
  4569. */
  4570. if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
  4571. ctxt->sax->endDocument(ctxt->userData);
  4572. if ((!(ctxt->options & HTML_PARSE_NODEFDTD)) && (ctxt->myDoc != NULL)) {
  4573. dtd = xmlGetIntSubset(ctxt->myDoc);
  4574. if (dtd == NULL)
  4575. ctxt->myDoc->intSubset =
  4576. xmlCreateIntSubset(ctxt->myDoc, BAD_CAST "html",
  4577. BAD_CAST "-//W3C//DTD HTML 4.0 Transitional//EN",
  4578. BAD_CAST "http://www.w3.org/TR/REC-html40/loose.dtd");
  4579. }
  4580. if (! ctxt->wellFormed) return(-1);
  4581. return(0);
  4582. }
  4583. /************************************************************************
  4584. * *
  4585. * Parser contexts handling *
  4586. * *
  4587. ************************************************************************/
  4588. /**
  4589. * htmlInitParserCtxt:
  4590. * @ctxt: an HTML parser context
  4591. *
  4592. * Initialize a parser context
  4593. *
  4594. * Returns 0 in case of success and -1 in case of error
  4595. */
  4596. static int
  4597. htmlInitParserCtxt(htmlParserCtxtPtr ctxt)
  4598. {
  4599. htmlSAXHandler *sax;
  4600. if (ctxt == NULL) return(-1);
  4601. memset(ctxt, 0, sizeof(htmlParserCtxt));
  4602. ctxt->dict = xmlDictCreate();
  4603. if (ctxt->dict == NULL) {
  4604. htmlErrMemory(NULL, "htmlInitParserCtxt: out of memory\n");
  4605. return(-1);
  4606. }
  4607. sax = (htmlSAXHandler *) xmlMalloc(sizeof(htmlSAXHandler));
  4608. if (sax == NULL) {
  4609. htmlErrMemory(NULL, "htmlInitParserCtxt: out of memory\n");
  4610. return(-1);
  4611. }
  4612. else
  4613. memset(sax, 0, sizeof(htmlSAXHandler));
  4614. /* Allocate the Input stack */
  4615. ctxt->inputTab = (htmlParserInputPtr *)
  4616. xmlMalloc(5 * sizeof(htmlParserInputPtr));
  4617. if (ctxt->inputTab == NULL) {
  4618. htmlErrMemory(NULL, "htmlInitParserCtxt: out of memory\n");
  4619. ctxt->inputNr = 0;
  4620. ctxt->inputMax = 0;
  4621. ctxt->input = NULL;
  4622. return(-1);
  4623. }
  4624. ctxt->inputNr = 0;
  4625. ctxt->inputMax = 5;
  4626. ctxt->input = NULL;
  4627. ctxt->version = NULL;
  4628. ctxt->encoding = NULL;
  4629. ctxt->standalone = -1;
  4630. ctxt->instate = XML_PARSER_START;
  4631. /* Allocate the Node stack */
  4632. ctxt->nodeTab = (htmlNodePtr *) xmlMalloc(10 * sizeof(htmlNodePtr));
  4633. if (ctxt->nodeTab == NULL) {
  4634. htmlErrMemory(NULL, "htmlInitParserCtxt: out of memory\n");
  4635. ctxt->nodeNr = 0;
  4636. ctxt->nodeMax = 0;
  4637. ctxt->node = NULL;
  4638. ctxt->inputNr = 0;
  4639. ctxt->inputMax = 0;
  4640. ctxt->input = NULL;
  4641. return(-1);
  4642. }
  4643. ctxt->nodeNr = 0;
  4644. ctxt->nodeMax = 10;
  4645. ctxt->node = NULL;
  4646. /* Allocate the Name stack */
  4647. ctxt->nameTab = (const xmlChar **) xmlMalloc(10 * sizeof(xmlChar *));
  4648. if (ctxt->nameTab == NULL) {
  4649. htmlErrMemory(NULL, "htmlInitParserCtxt: out of memory\n");
  4650. ctxt->nameNr = 0;
  4651. ctxt->nameMax = 0;
  4652. ctxt->name = NULL;
  4653. ctxt->nodeNr = 0;
  4654. ctxt->nodeMax = 0;
  4655. ctxt->node = NULL;
  4656. ctxt->inputNr = 0;
  4657. ctxt->inputMax = 0;
  4658. ctxt->input = NULL;
  4659. return(-1);
  4660. }
  4661. ctxt->nameNr = 0;
  4662. ctxt->nameMax = 10;
  4663. ctxt->name = NULL;
  4664. ctxt->nodeInfoTab = NULL;
  4665. ctxt->nodeInfoNr = 0;
  4666. ctxt->nodeInfoMax = 0;
  4667. if (sax == NULL) ctxt->sax = (xmlSAXHandlerPtr) &htmlDefaultSAXHandler;
  4668. else {
  4669. ctxt->sax = sax;
  4670. memcpy(sax, &htmlDefaultSAXHandler, sizeof(xmlSAXHandlerV1));
  4671. }
  4672. ctxt->userData = ctxt;
  4673. ctxt->myDoc = NULL;
  4674. ctxt->wellFormed = 1;
  4675. ctxt->replaceEntities = 0;
  4676. ctxt->linenumbers = xmlLineNumbersDefaultValue;
  4677. ctxt->keepBlanks = xmlKeepBlanksDefaultValue;
  4678. ctxt->html = 1;
  4679. ctxt->vctxt.flags = XML_VCTXT_USE_PCTXT;
  4680. ctxt->vctxt.userData = ctxt;
  4681. ctxt->vctxt.error = xmlParserValidityError;
  4682. ctxt->vctxt.warning = xmlParserValidityWarning;
  4683. ctxt->record_info = 0;
  4684. ctxt->validate = 0;
  4685. ctxt->checkIndex = 0;
  4686. ctxt->catalogs = NULL;
  4687. xmlInitNodeInfoSeq(&ctxt->node_seq);
  4688. return(0);
  4689. }
  4690. /**
  4691. * htmlFreeParserCtxt:
  4692. * @ctxt: an HTML parser context
  4693. *
  4694. * Free all the memory used by a parser context. However the parsed
  4695. * document in ctxt->myDoc is not freed.
  4696. */
  4697. void
  4698. htmlFreeParserCtxt(htmlParserCtxtPtr ctxt)
  4699. {
  4700. xmlFreeParserCtxt(ctxt);
  4701. }
  4702. /**
  4703. * htmlNewParserCtxt:
  4704. *
  4705. * Allocate and initialize a new parser context.
  4706. *
  4707. * Returns the htmlParserCtxtPtr or NULL in case of allocation error
  4708. */
  4709. htmlParserCtxtPtr
  4710. htmlNewParserCtxt(void)
  4711. {
  4712. xmlParserCtxtPtr ctxt;
  4713. ctxt = (xmlParserCtxtPtr) xmlMalloc(sizeof(xmlParserCtxt));
  4714. if (ctxt == NULL) {
  4715. htmlErrMemory(NULL, "NewParserCtxt: out of memory\n");
  4716. return(NULL);
  4717. }
  4718. memset(ctxt, 0, sizeof(xmlParserCtxt));
  4719. if (htmlInitParserCtxt(ctxt) < 0) {
  4720. htmlFreeParserCtxt(ctxt);
  4721. return(NULL);
  4722. }
  4723. return(ctxt);
  4724. }
  4725. /**
  4726. * htmlCreateMemoryParserCtxt:
  4727. * @buffer: a pointer to a char array
  4728. * @size: the size of the array
  4729. *
  4730. * Create a parser context for an HTML in-memory document.
  4731. *
  4732. * Returns the new parser context or NULL
  4733. */
  4734. htmlParserCtxtPtr
  4735. htmlCreateMemoryParserCtxt(const char *buffer, int size) {
  4736. xmlParserCtxtPtr ctxt;
  4737. xmlParserInputPtr input;
  4738. xmlParserInputBufferPtr buf;
  4739. if (buffer == NULL)
  4740. return(NULL);
  4741. if (size <= 0)
  4742. return(NULL);
  4743. ctxt = htmlNewParserCtxt();
  4744. if (ctxt == NULL)
  4745. return(NULL);
  4746. buf = xmlParserInputBufferCreateMem(buffer, size, XML_CHAR_ENCODING_NONE);
  4747. if (buf == NULL) return(NULL);
  4748. input = xmlNewInputStream(ctxt);
  4749. if (input == NULL) {
  4750. xmlFreeParserInputBuffer(buf);
  4751. xmlFreeParserCtxt(ctxt);
  4752. return(NULL);
  4753. }
  4754. input->filename = NULL;
  4755. input->buf = buf;
  4756. xmlBufResetInput(buf->buffer, input);
  4757. inputPush(ctxt, input);
  4758. return(ctxt);
  4759. }
  4760. /**
  4761. * htmlCreateDocParserCtxt:
  4762. * @cur: a pointer to an array of xmlChar
  4763. * @encoding: a free form C string describing the HTML document encoding, or NULL
  4764. *
  4765. * Create a parser context for an HTML document.
  4766. *
  4767. * TODO: check the need to add encoding handling there
  4768. *
  4769. * Returns the new parser context or NULL
  4770. */
  4771. static htmlParserCtxtPtr
  4772. htmlCreateDocParserCtxt(const xmlChar *cur, const char *encoding) {
  4773. int len;
  4774. htmlParserCtxtPtr ctxt;
  4775. if (cur == NULL)
  4776. return(NULL);
  4777. len = xmlStrlen(cur);
  4778. ctxt = htmlCreateMemoryParserCtxt((char *)cur, len);
  4779. if (ctxt == NULL)
  4780. return(NULL);
  4781. if (encoding != NULL) {
  4782. xmlCharEncoding enc;
  4783. xmlCharEncodingHandlerPtr handler;
  4784. if (ctxt->input->encoding != NULL)
  4785. xmlFree((xmlChar *) ctxt->input->encoding);
  4786. ctxt->input->encoding = xmlStrdup((const xmlChar *) encoding);
  4787. enc = xmlParseCharEncoding(encoding);
  4788. /*
  4789. * registered set of known encodings
  4790. */
  4791. if (enc != XML_CHAR_ENCODING_ERROR) {
  4792. xmlSwitchEncoding(ctxt, enc);
  4793. if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) {
  4794. htmlParseErr(ctxt, XML_ERR_UNSUPPORTED_ENCODING,
  4795. "Unsupported encoding %s\n",
  4796. (const xmlChar *) encoding, NULL);
  4797. }
  4798. } else {
  4799. /*
  4800. * fallback for unknown encodings
  4801. */
  4802. handler = xmlFindCharEncodingHandler((const char *) encoding);
  4803. if (handler != NULL) {
  4804. xmlSwitchToEncoding(ctxt, handler);
  4805. } else {
  4806. htmlParseErr(ctxt, XML_ERR_UNSUPPORTED_ENCODING,
  4807. "Unsupported encoding %s\n",
  4808. (const xmlChar *) encoding, NULL);
  4809. }
  4810. }
  4811. }
  4812. return(ctxt);
  4813. }
  4814. #ifdef LIBXML_PUSH_ENABLED
  4815. /************************************************************************
  4816. * *
  4817. * Progressive parsing interfaces *
  4818. * *
  4819. ************************************************************************/
  4820. /**
  4821. * htmlParseLookupSequence:
  4822. * @ctxt: an HTML parser context
  4823. * @first: the first char to lookup
  4824. * @next: the next char to lookup or zero
  4825. * @third: the next char to lookup or zero
  4826. * @ignoreattrval: skip over attribute values
  4827. *
  4828. * Try to find if a sequence (first, next, third) or just (first next) or
  4829. * (first) is available in the input stream.
  4830. * This function has a side effect of (possibly) incrementing ctxt->checkIndex
  4831. * to avoid rescanning sequences of bytes, it DOES change the state of the
  4832. * parser, do not use liberally.
  4833. * This is basically similar to xmlParseLookupSequence()
  4834. *
  4835. * Returns the index to the current parsing point if the full sequence
  4836. * is available, -1 otherwise.
  4837. */
  4838. static int
  4839. htmlParseLookupSequence(htmlParserCtxtPtr ctxt, xmlChar first,
  4840. xmlChar next, xmlChar third, int ignoreattrval)
  4841. {
  4842. int base, len;
  4843. htmlParserInputPtr in;
  4844. const xmlChar *buf;
  4845. int invalue = 0;
  4846. char valdellim = 0x0;
  4847. in = ctxt->input;
  4848. if (in == NULL)
  4849. return (-1);
  4850. base = in->cur - in->base;
  4851. if (base < 0)
  4852. return (-1);
  4853. if (ctxt->checkIndex > base) {
  4854. base = ctxt->checkIndex;
  4855. /* Abuse hasPErefs member to restore current state. */
  4856. invalue = ctxt->hasPErefs & 1 ? 1 : 0;
  4857. }
  4858. if (in->buf == NULL) {
  4859. buf = in->base;
  4860. len = in->length;
  4861. } else {
  4862. buf = xmlBufContent(in->buf->buffer);
  4863. len = xmlBufUse(in->buf->buffer);
  4864. }
  4865. /* take into account the sequence length */
  4866. if (third)
  4867. len -= 2;
  4868. else if (next)
  4869. len--;
  4870. for (; base < len; base++) {
  4871. if (ignoreattrval) {
  4872. if (buf[base] == '"' || buf[base] == '\'') {
  4873. if (invalue) {
  4874. if (buf[base] == valdellim) {
  4875. invalue = 0;
  4876. continue;
  4877. }
  4878. } else {
  4879. valdellim = buf[base];
  4880. invalue = 1;
  4881. continue;
  4882. }
  4883. } else if (invalue) {
  4884. continue;
  4885. }
  4886. }
  4887. if (buf[base] == first) {
  4888. if (third != 0) {
  4889. if ((buf[base + 1] != next) || (buf[base + 2] != third))
  4890. continue;
  4891. } else if (next != 0) {
  4892. if (buf[base + 1] != next)
  4893. continue;
  4894. }
  4895. ctxt->checkIndex = 0;
  4896. #ifdef DEBUG_PUSH
  4897. if (next == 0)
  4898. xmlGenericError(xmlGenericErrorContext,
  4899. "HPP: lookup '%c' found at %d\n",
  4900. first, base);
  4901. else if (third == 0)
  4902. xmlGenericError(xmlGenericErrorContext,
  4903. "HPP: lookup '%c%c' found at %d\n",
  4904. first, next, base);
  4905. else
  4906. xmlGenericError(xmlGenericErrorContext,
  4907. "HPP: lookup '%c%c%c' found at %d\n",
  4908. first, next, third, base);
  4909. #endif
  4910. return (base - (in->cur - in->base));
  4911. }
  4912. }
  4913. ctxt->checkIndex = base;
  4914. /* Abuse hasPErefs member to track current state. */
  4915. if (invalue)
  4916. ctxt->hasPErefs |= 1;
  4917. else
  4918. ctxt->hasPErefs &= ~1;
  4919. #ifdef DEBUG_PUSH
  4920. if (next == 0)
  4921. xmlGenericError(xmlGenericErrorContext,
  4922. "HPP: lookup '%c' failed\n", first);
  4923. else if (third == 0)
  4924. xmlGenericError(xmlGenericErrorContext,
  4925. "HPP: lookup '%c%c' failed\n", first, next);
  4926. else
  4927. xmlGenericError(xmlGenericErrorContext,
  4928. "HPP: lookup '%c%c%c' failed\n", first, next,
  4929. third);
  4930. #endif
  4931. return (-1);
  4932. }
  4933. /**
  4934. * htmlParseLookupCommentEnd:
  4935. * @ctxt: an HTML parser context
  4936. *
  4937. * Try to find a comment end tag in the input stream
  4938. * The search includes "-->" as well as WHATWG-recommended incorrectly-closed tags.
  4939. * (See https://html.spec.whatwg.org/multipage/parsing.html#parse-error-incorrectly-closed-comment)
  4940. * This function has a side effect of (possibly) incrementing ctxt->checkIndex
  4941. * to avoid rescanning sequences of bytes, it DOES change the state of the
  4942. * parser, do not use liberally.
  4943. * This wraps to htmlParseLookupSequence()
  4944. *
  4945. * Returns the index to the current parsing point if the full sequence is available, -1 otherwise.
  4946. */
  4947. static int
  4948. htmlParseLookupCommentEnd(htmlParserCtxtPtr ctxt)
  4949. {
  4950. int mark = 0;
  4951. int cur = CUR_PTR - BASE_PTR;
  4952. while (mark >= 0) {
  4953. mark = htmlParseLookupSequence(ctxt, '-', '-', 0, 0);
  4954. if ((mark < 0) ||
  4955. (NXT(mark+2) == '>') ||
  4956. ((NXT(mark+2) == '!') && (NXT(mark+3) == '>'))) {
  4957. return mark;
  4958. }
  4959. ctxt->checkIndex = cur + mark + 1;
  4960. }
  4961. return mark;
  4962. }
  4963. /**
  4964. * htmlParseTryOrFinish:
  4965. * @ctxt: an HTML parser context
  4966. * @terminate: last chunk indicator
  4967. *
  4968. * Try to progress on parsing
  4969. *
  4970. * Returns zero if no parsing was possible
  4971. */
  4972. static int
  4973. htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
  4974. int ret = 0;
  4975. htmlParserInputPtr in;
  4976. ptrdiff_t avail = 0;
  4977. xmlChar cur, next;
  4978. htmlParserNodeInfo node_info;
  4979. #ifdef DEBUG_PUSH
  4980. switch (ctxt->instate) {
  4981. case XML_PARSER_EOF:
  4982. xmlGenericError(xmlGenericErrorContext,
  4983. "HPP: try EOF\n"); break;
  4984. case XML_PARSER_START:
  4985. xmlGenericError(xmlGenericErrorContext,
  4986. "HPP: try START\n"); break;
  4987. case XML_PARSER_MISC:
  4988. xmlGenericError(xmlGenericErrorContext,
  4989. "HPP: try MISC\n");break;
  4990. case XML_PARSER_COMMENT:
  4991. xmlGenericError(xmlGenericErrorContext,
  4992. "HPP: try COMMENT\n");break;
  4993. case XML_PARSER_PROLOG:
  4994. xmlGenericError(xmlGenericErrorContext,
  4995. "HPP: try PROLOG\n");break;
  4996. case XML_PARSER_START_TAG:
  4997. xmlGenericError(xmlGenericErrorContext,
  4998. "HPP: try START_TAG\n");break;
  4999. case XML_PARSER_CONTENT:
  5000. xmlGenericError(xmlGenericErrorContext,
  5001. "HPP: try CONTENT\n");break;
  5002. case XML_PARSER_CDATA_SECTION:
  5003. xmlGenericError(xmlGenericErrorContext,
  5004. "HPP: try CDATA_SECTION\n");break;
  5005. case XML_PARSER_END_TAG:
  5006. xmlGenericError(xmlGenericErrorContext,
  5007. "HPP: try END_TAG\n");break;
  5008. case XML_PARSER_ENTITY_DECL:
  5009. xmlGenericError(xmlGenericErrorContext,
  5010. "HPP: try ENTITY_DECL\n");break;
  5011. case XML_PARSER_ENTITY_VALUE:
  5012. xmlGenericError(xmlGenericErrorContext,
  5013. "HPP: try ENTITY_VALUE\n");break;
  5014. case XML_PARSER_ATTRIBUTE_VALUE:
  5015. xmlGenericError(xmlGenericErrorContext,
  5016. "HPP: try ATTRIBUTE_VALUE\n");break;
  5017. case XML_PARSER_DTD:
  5018. xmlGenericError(xmlGenericErrorContext,
  5019. "HPP: try DTD\n");break;
  5020. case XML_PARSER_EPILOG:
  5021. xmlGenericError(xmlGenericErrorContext,
  5022. "HPP: try EPILOG\n");break;
  5023. case XML_PARSER_PI:
  5024. xmlGenericError(xmlGenericErrorContext,
  5025. "HPP: try PI\n");break;
  5026. case XML_PARSER_SYSTEM_LITERAL:
  5027. xmlGenericError(xmlGenericErrorContext,
  5028. "HPP: try SYSTEM_LITERAL\n");break;
  5029. }
  5030. #endif
  5031. while (1) {
  5032. in = ctxt->input;
  5033. if (in == NULL) break;
  5034. if (in->buf == NULL)
  5035. avail = in->length - (in->cur - in->base);
  5036. else
  5037. avail = (ptrdiff_t)xmlBufUse(in->buf->buffer) -
  5038. (in->cur - in->base);
  5039. if ((avail == 0) && (terminate)) {
  5040. htmlAutoCloseOnEnd(ctxt);
  5041. if ((ctxt->nameNr == 0) && (ctxt->instate != XML_PARSER_EOF)) {
  5042. /*
  5043. * SAX: end of the document processing.
  5044. */
  5045. ctxt->instate = XML_PARSER_EOF;
  5046. if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
  5047. ctxt->sax->endDocument(ctxt->userData);
  5048. }
  5049. }
  5050. if (avail < 1)
  5051. goto done;
  5052. /*
  5053. * This is done to make progress and avoid an infinite loop
  5054. * if a parsing attempt was aborted by hitting a NUL byte. After
  5055. * changing htmlCurrentChar, this probably isn't necessary anymore.
  5056. * We should consider removing this check.
  5057. */
  5058. cur = in->cur[0];
  5059. if (cur == 0) {
  5060. SKIP(1);
  5061. continue;
  5062. }
  5063. switch (ctxt->instate) {
  5064. case XML_PARSER_EOF:
  5065. /*
  5066. * Document parsing is done !
  5067. */
  5068. goto done;
  5069. case XML_PARSER_START:
  5070. /*
  5071. * Very first chars read from the document flow.
  5072. */
  5073. cur = in->cur[0];
  5074. if (IS_BLANK_CH(cur)) {
  5075. SKIP_BLANKS;
  5076. if (in->buf == NULL)
  5077. avail = in->length - (in->cur - in->base);
  5078. else
  5079. avail = (ptrdiff_t)xmlBufUse(in->buf->buffer) -
  5080. (in->cur - in->base);
  5081. }
  5082. if ((ctxt->sax) && (ctxt->sax->setDocumentLocator))
  5083. ctxt->sax->setDocumentLocator(ctxt->userData,
  5084. &xmlDefaultSAXLocator);
  5085. if ((ctxt->sax) && (ctxt->sax->startDocument) &&
  5086. (!ctxt->disableSAX))
  5087. ctxt->sax->startDocument(ctxt->userData);
  5088. cur = in->cur[0];
  5089. next = in->cur[1];
  5090. if ((cur == '<') && (next == '!') &&
  5091. (UPP(2) == 'D') && (UPP(3) == 'O') &&
  5092. (UPP(4) == 'C') && (UPP(5) == 'T') &&
  5093. (UPP(6) == 'Y') && (UPP(7) == 'P') &&
  5094. (UPP(8) == 'E')) {
  5095. if ((!terminate) &&
  5096. (htmlParseLookupSequence(ctxt, '>', 0, 0, 1) < 0))
  5097. goto done;
  5098. #ifdef DEBUG_PUSH
  5099. xmlGenericError(xmlGenericErrorContext,
  5100. "HPP: Parsing internal subset\n");
  5101. #endif
  5102. htmlParseDocTypeDecl(ctxt);
  5103. ctxt->instate = XML_PARSER_PROLOG;
  5104. #ifdef DEBUG_PUSH
  5105. xmlGenericError(xmlGenericErrorContext,
  5106. "HPP: entering PROLOG\n");
  5107. #endif
  5108. } else {
  5109. ctxt->instate = XML_PARSER_MISC;
  5110. #ifdef DEBUG_PUSH
  5111. xmlGenericError(xmlGenericErrorContext,
  5112. "HPP: entering MISC\n");
  5113. #endif
  5114. }
  5115. break;
  5116. case XML_PARSER_MISC:
  5117. SKIP_BLANKS;
  5118. if (in->buf == NULL)
  5119. avail = in->length - (in->cur - in->base);
  5120. else
  5121. avail = (ptrdiff_t)xmlBufUse(in->buf->buffer) -
  5122. (in->cur - in->base);
  5123. /*
  5124. * no chars in buffer
  5125. */
  5126. if (avail < 1)
  5127. goto done;
  5128. /*
  5129. * not enough chars in buffer
  5130. */
  5131. if (avail < 2) {
  5132. if (!terminate)
  5133. goto done;
  5134. else
  5135. next = ' ';
  5136. } else {
  5137. next = in->cur[1];
  5138. }
  5139. cur = in->cur[0];
  5140. if ((cur == '<') && (next == '!') &&
  5141. (in->cur[2] == '-') && (in->cur[3] == '-')) {
  5142. if ((!terminate) && (htmlParseLookupCommentEnd(ctxt) < 0))
  5143. goto done;
  5144. #ifdef DEBUG_PUSH
  5145. xmlGenericError(xmlGenericErrorContext,
  5146. "HPP: Parsing Comment\n");
  5147. #endif
  5148. htmlParseComment(ctxt);
  5149. ctxt->instate = XML_PARSER_MISC;
  5150. } else if ((cur == '<') && (next == '?')) {
  5151. if ((!terminate) &&
  5152. (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
  5153. goto done;
  5154. #ifdef DEBUG_PUSH
  5155. xmlGenericError(xmlGenericErrorContext,
  5156. "HPP: Parsing PI\n");
  5157. #endif
  5158. htmlParsePI(ctxt);
  5159. ctxt->instate = XML_PARSER_MISC;
  5160. } else if ((cur == '<') && (next == '!') &&
  5161. (UPP(2) == 'D') && (UPP(3) == 'O') &&
  5162. (UPP(4) == 'C') && (UPP(5) == 'T') &&
  5163. (UPP(6) == 'Y') && (UPP(7) == 'P') &&
  5164. (UPP(8) == 'E')) {
  5165. if ((!terminate) &&
  5166. (htmlParseLookupSequence(ctxt, '>', 0, 0, 1) < 0))
  5167. goto done;
  5168. #ifdef DEBUG_PUSH
  5169. xmlGenericError(xmlGenericErrorContext,
  5170. "HPP: Parsing internal subset\n");
  5171. #endif
  5172. htmlParseDocTypeDecl(ctxt);
  5173. ctxt->instate = XML_PARSER_PROLOG;
  5174. #ifdef DEBUG_PUSH
  5175. xmlGenericError(xmlGenericErrorContext,
  5176. "HPP: entering PROLOG\n");
  5177. #endif
  5178. } else if ((cur == '<') && (next == '!') &&
  5179. (avail < 9)) {
  5180. goto done;
  5181. } else {
  5182. ctxt->instate = XML_PARSER_CONTENT;
  5183. #ifdef DEBUG_PUSH
  5184. xmlGenericError(xmlGenericErrorContext,
  5185. "HPP: entering START_TAG\n");
  5186. #endif
  5187. }
  5188. break;
  5189. case XML_PARSER_PROLOG:
  5190. SKIP_BLANKS;
  5191. if (in->buf == NULL)
  5192. avail = in->length - (in->cur - in->base);
  5193. else
  5194. avail = (ptrdiff_t)xmlBufUse(in->buf->buffer) -
  5195. (in->cur - in->base);
  5196. if (avail < 2)
  5197. goto done;
  5198. cur = in->cur[0];
  5199. next = in->cur[1];
  5200. if ((cur == '<') && (next == '!') &&
  5201. (in->cur[2] == '-') && (in->cur[3] == '-')) {
  5202. if ((!terminate) && (htmlParseLookupCommentEnd(ctxt) < 0))
  5203. goto done;
  5204. #ifdef DEBUG_PUSH
  5205. xmlGenericError(xmlGenericErrorContext,
  5206. "HPP: Parsing Comment\n");
  5207. #endif
  5208. htmlParseComment(ctxt);
  5209. ctxt->instate = XML_PARSER_PROLOG;
  5210. } else if ((cur == '<') && (next == '?')) {
  5211. if ((!terminate) &&
  5212. (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
  5213. goto done;
  5214. #ifdef DEBUG_PUSH
  5215. xmlGenericError(xmlGenericErrorContext,
  5216. "HPP: Parsing PI\n");
  5217. #endif
  5218. htmlParsePI(ctxt);
  5219. ctxt->instate = XML_PARSER_PROLOG;
  5220. } else if ((cur == '<') && (next == '!') &&
  5221. (avail < 4)) {
  5222. goto done;
  5223. } else {
  5224. ctxt->instate = XML_PARSER_CONTENT;
  5225. #ifdef DEBUG_PUSH
  5226. xmlGenericError(xmlGenericErrorContext,
  5227. "HPP: entering START_TAG\n");
  5228. #endif
  5229. }
  5230. break;
  5231. case XML_PARSER_EPILOG:
  5232. if (in->buf == NULL)
  5233. avail = in->length - (in->cur - in->base);
  5234. else
  5235. avail = (ptrdiff_t)xmlBufUse(in->buf->buffer) -
  5236. (in->cur - in->base);
  5237. if (avail < 1)
  5238. goto done;
  5239. cur = in->cur[0];
  5240. if (IS_BLANK_CH(cur)) {
  5241. htmlParseCharData(ctxt);
  5242. goto done;
  5243. }
  5244. if (avail < 2)
  5245. goto done;
  5246. next = in->cur[1];
  5247. if ((cur == '<') && (next == '!') &&
  5248. (in->cur[2] == '-') && (in->cur[3] == '-')) {
  5249. if ((!terminate) && (htmlParseLookupCommentEnd(ctxt) < 0))
  5250. goto done;
  5251. #ifdef DEBUG_PUSH
  5252. xmlGenericError(xmlGenericErrorContext,
  5253. "HPP: Parsing Comment\n");
  5254. #endif
  5255. htmlParseComment(ctxt);
  5256. ctxt->instate = XML_PARSER_EPILOG;
  5257. } else if ((cur == '<') && (next == '?')) {
  5258. if ((!terminate) &&
  5259. (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
  5260. goto done;
  5261. #ifdef DEBUG_PUSH
  5262. xmlGenericError(xmlGenericErrorContext,
  5263. "HPP: Parsing PI\n");
  5264. #endif
  5265. htmlParsePI(ctxt);
  5266. ctxt->instate = XML_PARSER_EPILOG;
  5267. } else if ((cur == '<') && (next == '!') &&
  5268. (avail < 4)) {
  5269. goto done;
  5270. } else {
  5271. ctxt->errNo = XML_ERR_DOCUMENT_END;
  5272. ctxt->wellFormed = 0;
  5273. ctxt->instate = XML_PARSER_EOF;
  5274. #ifdef DEBUG_PUSH
  5275. xmlGenericError(xmlGenericErrorContext,
  5276. "HPP: entering EOF\n");
  5277. #endif
  5278. if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
  5279. ctxt->sax->endDocument(ctxt->userData);
  5280. goto done;
  5281. }
  5282. break;
  5283. case XML_PARSER_START_TAG: {
  5284. const xmlChar *name;
  5285. int failed;
  5286. const htmlElemDesc * info;
  5287. /*
  5288. * no chars in buffer
  5289. */
  5290. if (avail < 1)
  5291. goto done;
  5292. /*
  5293. * not enough chars in buffer
  5294. */
  5295. if (avail < 2) {
  5296. if (!terminate)
  5297. goto done;
  5298. else
  5299. next = ' ';
  5300. } else {
  5301. next = in->cur[1];
  5302. }
  5303. cur = in->cur[0];
  5304. if (cur != '<') {
  5305. ctxt->instate = XML_PARSER_CONTENT;
  5306. #ifdef DEBUG_PUSH
  5307. xmlGenericError(xmlGenericErrorContext,
  5308. "HPP: entering CONTENT\n");
  5309. #endif
  5310. break;
  5311. }
  5312. if (next == '/') {
  5313. ctxt->instate = XML_PARSER_END_TAG;
  5314. ctxt->checkIndex = 0;
  5315. #ifdef DEBUG_PUSH
  5316. xmlGenericError(xmlGenericErrorContext,
  5317. "HPP: entering END_TAG\n");
  5318. #endif
  5319. break;
  5320. }
  5321. if ((!terminate) &&
  5322. (htmlParseLookupSequence(ctxt, '>', 0, 0, 1) < 0))
  5323. goto done;
  5324. /* Capture start position */
  5325. if (ctxt->record_info) {
  5326. node_info.begin_pos = ctxt->input->consumed +
  5327. (CUR_PTR - ctxt->input->base);
  5328. node_info.begin_line = ctxt->input->line;
  5329. }
  5330. failed = htmlParseStartTag(ctxt);
  5331. name = ctxt->name;
  5332. if ((failed == -1) ||
  5333. (name == NULL)) {
  5334. if (CUR == '>')
  5335. NEXT;
  5336. break;
  5337. }
  5338. /*
  5339. * Lookup the info for that element.
  5340. */
  5341. info = htmlTagLookup(name);
  5342. if (info == NULL) {
  5343. htmlParseErr(ctxt, XML_HTML_UNKNOWN_TAG,
  5344. "Tag %s invalid\n", name, NULL);
  5345. }
  5346. /*
  5347. * Check for an Empty Element labeled the XML/SGML way
  5348. */
  5349. if ((CUR == '/') && (NXT(1) == '>')) {
  5350. SKIP(2);
  5351. if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
  5352. ctxt->sax->endElement(ctxt->userData, name);
  5353. htmlnamePop(ctxt);
  5354. ctxt->instate = XML_PARSER_CONTENT;
  5355. #ifdef DEBUG_PUSH
  5356. xmlGenericError(xmlGenericErrorContext,
  5357. "HPP: entering CONTENT\n");
  5358. #endif
  5359. break;
  5360. }
  5361. if (CUR == '>') {
  5362. NEXT;
  5363. } else {
  5364. htmlParseErr(ctxt, XML_ERR_GT_REQUIRED,
  5365. "Couldn't find end of Start Tag %s\n",
  5366. name, NULL);
  5367. /*
  5368. * end of parsing of this node.
  5369. */
  5370. if (xmlStrEqual(name, ctxt->name)) {
  5371. nodePop(ctxt);
  5372. htmlnamePop(ctxt);
  5373. }
  5374. if (ctxt->record_info)
  5375. htmlNodeInfoPush(ctxt, &node_info);
  5376. ctxt->instate = XML_PARSER_CONTENT;
  5377. #ifdef DEBUG_PUSH
  5378. xmlGenericError(xmlGenericErrorContext,
  5379. "HPP: entering CONTENT\n");
  5380. #endif
  5381. break;
  5382. }
  5383. /*
  5384. * Check for an Empty Element from DTD definition
  5385. */
  5386. if ((info != NULL) && (info->empty)) {
  5387. if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
  5388. ctxt->sax->endElement(ctxt->userData, name);
  5389. htmlnamePop(ctxt);
  5390. }
  5391. if (ctxt->record_info)
  5392. htmlNodeInfoPush(ctxt, &node_info);
  5393. ctxt->instate = XML_PARSER_CONTENT;
  5394. #ifdef DEBUG_PUSH
  5395. xmlGenericError(xmlGenericErrorContext,
  5396. "HPP: entering CONTENT\n");
  5397. #endif
  5398. break;
  5399. }
  5400. case XML_PARSER_CONTENT: {
  5401. xmlChar chr[2] = { 0, 0 };
  5402. /*
  5403. * Handle preparsed entities and charRef
  5404. */
  5405. if (ctxt->token != 0) {
  5406. chr[0] = (xmlChar) ctxt->token;
  5407. htmlCheckParagraph(ctxt);
  5408. if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
  5409. ctxt->sax->characters(ctxt->userData, chr, 1);
  5410. ctxt->token = 0;
  5411. ctxt->checkIndex = 0;
  5412. }
  5413. if ((avail == 1) && (terminate)) {
  5414. cur = in->cur[0];
  5415. if ((cur != '<') && (cur != '&')) {
  5416. if (ctxt->sax != NULL) {
  5417. chr[0] = cur;
  5418. if (IS_BLANK_CH(cur)) {
  5419. if (ctxt->keepBlanks) {
  5420. if (ctxt->sax->characters != NULL)
  5421. ctxt->sax->characters(
  5422. ctxt->userData, chr, 1);
  5423. } else {
  5424. if (ctxt->sax->ignorableWhitespace != NULL)
  5425. ctxt->sax->ignorableWhitespace(
  5426. ctxt->userData, chr, 1);
  5427. }
  5428. } else {
  5429. htmlCheckParagraph(ctxt);
  5430. if (ctxt->sax->characters != NULL)
  5431. ctxt->sax->characters(
  5432. ctxt->userData, chr, 1);
  5433. }
  5434. }
  5435. ctxt->token = 0;
  5436. ctxt->checkIndex = 0;
  5437. in->cur++;
  5438. break;
  5439. }
  5440. }
  5441. if (avail < 2)
  5442. goto done;
  5443. cur = in->cur[0];
  5444. next = in->cur[1];
  5445. if ((xmlStrEqual(ctxt->name, BAD_CAST"script")) ||
  5446. (xmlStrEqual(ctxt->name, BAD_CAST"style"))) {
  5447. /*
  5448. * Handle SCRIPT/STYLE separately
  5449. */
  5450. if (!terminate) {
  5451. int idx;
  5452. xmlChar val;
  5453. idx = htmlParseLookupSequence(ctxt, '<', '/', 0, 0);
  5454. if (idx < 0)
  5455. goto done;
  5456. val = in->cur[idx + 2];
  5457. if (val == 0) /* bad cut of input */
  5458. goto done;
  5459. }
  5460. htmlParseScript(ctxt);
  5461. if ((cur == '<') && (next == '/')) {
  5462. ctxt->instate = XML_PARSER_END_TAG;
  5463. ctxt->checkIndex = 0;
  5464. #ifdef DEBUG_PUSH
  5465. xmlGenericError(xmlGenericErrorContext,
  5466. "HPP: entering END_TAG\n");
  5467. #endif
  5468. break;
  5469. }
  5470. } else {
  5471. /*
  5472. * Sometimes DOCTYPE arrives in the middle of the document
  5473. */
  5474. if ((cur == '<') && (next == '!') &&
  5475. (UPP(2) == 'D') && (UPP(3) == 'O') &&
  5476. (UPP(4) == 'C') && (UPP(5) == 'T') &&
  5477. (UPP(6) == 'Y') && (UPP(7) == 'P') &&
  5478. (UPP(8) == 'E')) {
  5479. if ((!terminate) &&
  5480. (htmlParseLookupSequence(ctxt, '>', 0, 0, 1) < 0))
  5481. goto done;
  5482. htmlParseErr(ctxt, XML_HTML_STRUCURE_ERROR,
  5483. "Misplaced DOCTYPE declaration\n",
  5484. BAD_CAST "DOCTYPE" , NULL);
  5485. htmlParseDocTypeDecl(ctxt);
  5486. } else if ((cur == '<') && (next == '!') &&
  5487. (in->cur[2] == '-') && (in->cur[3] == '-')) {
  5488. if ((!terminate) && (htmlParseLookupCommentEnd(ctxt) < 0))
  5489. goto done;
  5490. #ifdef DEBUG_PUSH
  5491. xmlGenericError(xmlGenericErrorContext,
  5492. "HPP: Parsing Comment\n");
  5493. #endif
  5494. htmlParseComment(ctxt);
  5495. ctxt->instate = XML_PARSER_CONTENT;
  5496. } else if ((cur == '<') && (next == '?')) {
  5497. if ((!terminate) &&
  5498. (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
  5499. goto done;
  5500. #ifdef DEBUG_PUSH
  5501. xmlGenericError(xmlGenericErrorContext,
  5502. "HPP: Parsing PI\n");
  5503. #endif
  5504. htmlParsePI(ctxt);
  5505. ctxt->instate = XML_PARSER_CONTENT;
  5506. } else if ((cur == '<') && (next == '!') && (avail < 4)) {
  5507. goto done;
  5508. } else if ((cur == '<') && (next == '/')) {
  5509. ctxt->instate = XML_PARSER_END_TAG;
  5510. ctxt->checkIndex = 0;
  5511. #ifdef DEBUG_PUSH
  5512. xmlGenericError(xmlGenericErrorContext,
  5513. "HPP: entering END_TAG\n");
  5514. #endif
  5515. break;
  5516. } else if ((cur == '<') && IS_ASCII_LETTER(next)) {
  5517. if ((!terminate) && (next == 0))
  5518. goto done;
  5519. ctxt->instate = XML_PARSER_START_TAG;
  5520. ctxt->checkIndex = 0;
  5521. #ifdef DEBUG_PUSH
  5522. xmlGenericError(xmlGenericErrorContext,
  5523. "HPP: entering START_TAG\n");
  5524. #endif
  5525. break;
  5526. } else if (cur == '<') {
  5527. if ((ctxt->sax != NULL) && (!ctxt->disableSAX) &&
  5528. (ctxt->sax->characters != NULL))
  5529. ctxt->sax->characters(ctxt->userData,
  5530. BAD_CAST "<", 1);
  5531. NEXT;
  5532. } else {
  5533. /*
  5534. * check that the text sequence is complete
  5535. * before handing out the data to the parser
  5536. * to avoid problems with erroneous end of
  5537. * data detection.
  5538. */
  5539. if ((!terminate) &&
  5540. (htmlParseLookupSequence(ctxt, '<', 0, 0, 0) < 0))
  5541. goto done;
  5542. ctxt->checkIndex = 0;
  5543. #ifdef DEBUG_PUSH
  5544. xmlGenericError(xmlGenericErrorContext,
  5545. "HPP: Parsing char data\n");
  5546. #endif
  5547. while ((ctxt->instate != XML_PARSER_EOF) &&
  5548. (cur != '<') && (in->cur < in->end)) {
  5549. if (cur == '&') {
  5550. htmlParseReference(ctxt);
  5551. } else {
  5552. htmlParseCharData(ctxt);
  5553. }
  5554. cur = in->cur[0];
  5555. }
  5556. }
  5557. }
  5558. break;
  5559. }
  5560. case XML_PARSER_END_TAG:
  5561. if (avail < 2)
  5562. goto done;
  5563. if ((!terminate) &&
  5564. (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
  5565. goto done;
  5566. htmlParseEndTag(ctxt);
  5567. if (ctxt->nameNr == 0) {
  5568. ctxt->instate = XML_PARSER_EPILOG;
  5569. } else {
  5570. ctxt->instate = XML_PARSER_CONTENT;
  5571. }
  5572. ctxt->checkIndex = 0;
  5573. #ifdef DEBUG_PUSH
  5574. xmlGenericError(xmlGenericErrorContext,
  5575. "HPP: entering CONTENT\n");
  5576. #endif
  5577. break;
  5578. case XML_PARSER_CDATA_SECTION:
  5579. htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
  5580. "HPP: internal error, state == CDATA\n",
  5581. NULL, NULL);
  5582. ctxt->instate = XML_PARSER_CONTENT;
  5583. ctxt->checkIndex = 0;
  5584. #ifdef DEBUG_PUSH
  5585. xmlGenericError(xmlGenericErrorContext,
  5586. "HPP: entering CONTENT\n");
  5587. #endif
  5588. break;
  5589. case XML_PARSER_DTD:
  5590. htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
  5591. "HPP: internal error, state == DTD\n",
  5592. NULL, NULL);
  5593. ctxt->instate = XML_PARSER_CONTENT;
  5594. ctxt->checkIndex = 0;
  5595. #ifdef DEBUG_PUSH
  5596. xmlGenericError(xmlGenericErrorContext,
  5597. "HPP: entering CONTENT\n");
  5598. #endif
  5599. break;
  5600. case XML_PARSER_COMMENT:
  5601. htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
  5602. "HPP: internal error, state == COMMENT\n",
  5603. NULL, NULL);
  5604. ctxt->instate = XML_PARSER_CONTENT;
  5605. ctxt->checkIndex = 0;
  5606. #ifdef DEBUG_PUSH
  5607. xmlGenericError(xmlGenericErrorContext,
  5608. "HPP: entering CONTENT\n");
  5609. #endif
  5610. break;
  5611. case XML_PARSER_PI:
  5612. htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
  5613. "HPP: internal error, state == PI\n",
  5614. NULL, NULL);
  5615. ctxt->instate = XML_PARSER_CONTENT;
  5616. ctxt->checkIndex = 0;
  5617. #ifdef DEBUG_PUSH
  5618. xmlGenericError(xmlGenericErrorContext,
  5619. "HPP: entering CONTENT\n");
  5620. #endif
  5621. break;
  5622. case XML_PARSER_ENTITY_DECL:
  5623. htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
  5624. "HPP: internal error, state == ENTITY_DECL\n",
  5625. NULL, NULL);
  5626. ctxt->instate = XML_PARSER_CONTENT;
  5627. ctxt->checkIndex = 0;
  5628. #ifdef DEBUG_PUSH
  5629. xmlGenericError(xmlGenericErrorContext,
  5630. "HPP: entering CONTENT\n");
  5631. #endif
  5632. break;
  5633. case XML_PARSER_ENTITY_VALUE:
  5634. htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
  5635. "HPP: internal error, state == ENTITY_VALUE\n",
  5636. NULL, NULL);
  5637. ctxt->instate = XML_PARSER_CONTENT;
  5638. ctxt->checkIndex = 0;
  5639. #ifdef DEBUG_PUSH
  5640. xmlGenericError(xmlGenericErrorContext,
  5641. "HPP: entering DTD\n");
  5642. #endif
  5643. break;
  5644. case XML_PARSER_ATTRIBUTE_VALUE:
  5645. htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
  5646. "HPP: internal error, state == ATTRIBUTE_VALUE\n",
  5647. NULL, NULL);
  5648. ctxt->instate = XML_PARSER_START_TAG;
  5649. ctxt->checkIndex = 0;
  5650. #ifdef DEBUG_PUSH
  5651. xmlGenericError(xmlGenericErrorContext,
  5652. "HPP: entering START_TAG\n");
  5653. #endif
  5654. break;
  5655. case XML_PARSER_SYSTEM_LITERAL:
  5656. htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
  5657. "HPP: internal error, state == XML_PARSER_SYSTEM_LITERAL\n",
  5658. NULL, NULL);
  5659. ctxt->instate = XML_PARSER_CONTENT;
  5660. ctxt->checkIndex = 0;
  5661. #ifdef DEBUG_PUSH
  5662. xmlGenericError(xmlGenericErrorContext,
  5663. "HPP: entering CONTENT\n");
  5664. #endif
  5665. break;
  5666. case XML_PARSER_IGNORE:
  5667. htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
  5668. "HPP: internal error, state == XML_PARSER_IGNORE\n",
  5669. NULL, NULL);
  5670. ctxt->instate = XML_PARSER_CONTENT;
  5671. ctxt->checkIndex = 0;
  5672. #ifdef DEBUG_PUSH
  5673. xmlGenericError(xmlGenericErrorContext,
  5674. "HPP: entering CONTENT\n");
  5675. #endif
  5676. break;
  5677. case XML_PARSER_PUBLIC_LITERAL:
  5678. htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
  5679. "HPP: internal error, state == XML_PARSER_LITERAL\n",
  5680. NULL, NULL);
  5681. ctxt->instate = XML_PARSER_CONTENT;
  5682. ctxt->checkIndex = 0;
  5683. #ifdef DEBUG_PUSH
  5684. xmlGenericError(xmlGenericErrorContext,
  5685. "HPP: entering CONTENT\n");
  5686. #endif
  5687. break;
  5688. }
  5689. }
  5690. done:
  5691. if ((avail == 0) && (terminate)) {
  5692. htmlAutoCloseOnEnd(ctxt);
  5693. if ((ctxt->nameNr == 0) && (ctxt->instate != XML_PARSER_EOF)) {
  5694. /*
  5695. * SAX: end of the document processing.
  5696. */
  5697. ctxt->instate = XML_PARSER_EOF;
  5698. if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
  5699. ctxt->sax->endDocument(ctxt->userData);
  5700. }
  5701. }
  5702. if ((!(ctxt->options & HTML_PARSE_NODEFDTD)) && (ctxt->myDoc != NULL) &&
  5703. ((terminate) || (ctxt->instate == XML_PARSER_EOF) ||
  5704. (ctxt->instate == XML_PARSER_EPILOG))) {
  5705. xmlDtdPtr dtd;
  5706. dtd = xmlGetIntSubset(ctxt->myDoc);
  5707. if (dtd == NULL)
  5708. ctxt->myDoc->intSubset =
  5709. xmlCreateIntSubset(ctxt->myDoc, BAD_CAST "html",
  5710. BAD_CAST "-//W3C//DTD HTML 4.0 Transitional//EN",
  5711. BAD_CAST "http://www.w3.org/TR/REC-html40/loose.dtd");
  5712. }
  5713. #ifdef DEBUG_PUSH
  5714. xmlGenericError(xmlGenericErrorContext, "HPP: done %d\n", ret);
  5715. #endif
  5716. return(ret);
  5717. }
  5718. /**
  5719. * htmlParseChunk:
  5720. * @ctxt: an HTML parser context
  5721. * @chunk: an char array
  5722. * @size: the size in byte of the chunk
  5723. * @terminate: last chunk indicator
  5724. *
  5725. * Parse a Chunk of memory
  5726. *
  5727. * Returns zero if no error, the xmlParserErrors otherwise.
  5728. */
  5729. int
  5730. htmlParseChunk(htmlParserCtxtPtr ctxt, const char *chunk, int size,
  5731. int terminate) {
  5732. if ((ctxt == NULL) || (ctxt->input == NULL)) {
  5733. htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
  5734. "htmlParseChunk: context error\n", NULL, NULL);
  5735. return(XML_ERR_INTERNAL_ERROR);
  5736. }
  5737. if ((size > 0) && (chunk != NULL) && (ctxt->input != NULL) &&
  5738. (ctxt->input->buf != NULL) && (ctxt->instate != XML_PARSER_EOF)) {
  5739. size_t base = xmlBufGetInputBase(ctxt->input->buf->buffer, ctxt->input);
  5740. size_t cur = ctxt->input->cur - ctxt->input->base;
  5741. int res;
  5742. res = xmlParserInputBufferPush(ctxt->input->buf, size, chunk);
  5743. xmlBufSetInputBaseCur(ctxt->input->buf->buffer, ctxt->input, base, cur);
  5744. if (res < 0) {
  5745. ctxt->errNo = XML_PARSER_EOF;
  5746. ctxt->disableSAX = 1;
  5747. return (XML_PARSER_EOF);
  5748. }
  5749. #ifdef DEBUG_PUSH
  5750. xmlGenericError(xmlGenericErrorContext, "HPP: pushed %d\n", size);
  5751. #endif
  5752. #if 0
  5753. if ((terminate) || (ctxt->input->buf->buffer->use > 80))
  5754. htmlParseTryOrFinish(ctxt, terminate);
  5755. #endif
  5756. } else if (ctxt->instate != XML_PARSER_EOF) {
  5757. if ((ctxt->input != NULL) && ctxt->input->buf != NULL) {
  5758. xmlParserInputBufferPtr in = ctxt->input->buf;
  5759. if ((in->encoder != NULL) && (in->buffer != NULL) &&
  5760. (in->raw != NULL)) {
  5761. int nbchars;
  5762. size_t base = xmlBufGetInputBase(in->buffer, ctxt->input);
  5763. size_t current = ctxt->input->cur - ctxt->input->base;
  5764. nbchars = xmlCharEncInput(in, terminate);
  5765. xmlBufSetInputBaseCur(in->buffer, ctxt->input, base, current);
  5766. if (nbchars < 0) {
  5767. htmlParseErr(ctxt, XML_ERR_INVALID_ENCODING,
  5768. "encoder error\n", NULL, NULL);
  5769. return(XML_ERR_INVALID_ENCODING);
  5770. }
  5771. }
  5772. }
  5773. }
  5774. htmlParseTryOrFinish(ctxt, terminate);
  5775. if (terminate) {
  5776. if ((ctxt->instate != XML_PARSER_EOF) &&
  5777. (ctxt->instate != XML_PARSER_EPILOG) &&
  5778. (ctxt->instate != XML_PARSER_MISC)) {
  5779. ctxt->errNo = XML_ERR_DOCUMENT_END;
  5780. ctxt->wellFormed = 0;
  5781. }
  5782. if (ctxt->instate != XML_PARSER_EOF) {
  5783. if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
  5784. ctxt->sax->endDocument(ctxt->userData);
  5785. }
  5786. ctxt->instate = XML_PARSER_EOF;
  5787. }
  5788. return((xmlParserErrors) ctxt->errNo);
  5789. }
  5790. /************************************************************************
  5791. * *
  5792. * User entry points *
  5793. * *
  5794. ************************************************************************/
  5795. /**
  5796. * htmlCreatePushParserCtxt:
  5797. * @sax: a SAX handler
  5798. * @user_data: The user data returned on SAX callbacks
  5799. * @chunk: a pointer to an array of chars
  5800. * @size: number of chars in the array
  5801. * @filename: an optional file name or URI
  5802. * @enc: an optional encoding
  5803. *
  5804. * Create a parser context for using the HTML parser in push mode
  5805. * The value of @filename is used for fetching external entities
  5806. * and error/warning reports.
  5807. *
  5808. * Returns the new parser context or NULL
  5809. */
  5810. htmlParserCtxtPtr
  5811. htmlCreatePushParserCtxt(htmlSAXHandlerPtr sax, void *user_data,
  5812. const char *chunk, int size, const char *filename,
  5813. xmlCharEncoding enc) {
  5814. htmlParserCtxtPtr ctxt;
  5815. htmlParserInputPtr inputStream;
  5816. xmlParserInputBufferPtr buf;
  5817. xmlInitParser();
  5818. buf = xmlAllocParserInputBuffer(enc);
  5819. if (buf == NULL) return(NULL);
  5820. ctxt = htmlNewParserCtxt();
  5821. if (ctxt == NULL) {
  5822. xmlFreeParserInputBuffer(buf);
  5823. return(NULL);
  5824. }
  5825. if(enc==XML_CHAR_ENCODING_UTF8 || buf->encoder)
  5826. ctxt->charset=XML_CHAR_ENCODING_UTF8;
  5827. if (sax != NULL) {
  5828. if (ctxt->sax != (xmlSAXHandlerPtr) &htmlDefaultSAXHandler)
  5829. xmlFree(ctxt->sax);
  5830. ctxt->sax = (htmlSAXHandlerPtr) xmlMalloc(sizeof(htmlSAXHandler));
  5831. if (ctxt->sax == NULL) {
  5832. xmlFree(buf);
  5833. xmlFree(ctxt);
  5834. return(NULL);
  5835. }
  5836. memcpy(ctxt->sax, sax, sizeof(htmlSAXHandler));
  5837. if (user_data != NULL)
  5838. ctxt->userData = user_data;
  5839. }
  5840. if (filename == NULL) {
  5841. ctxt->directory = NULL;
  5842. } else {
  5843. ctxt->directory = xmlParserGetDirectory(filename);
  5844. }
  5845. inputStream = htmlNewInputStream(ctxt);
  5846. if (inputStream == NULL) {
  5847. xmlFreeParserCtxt(ctxt);
  5848. xmlFree(buf);
  5849. return(NULL);
  5850. }
  5851. if (filename == NULL)
  5852. inputStream->filename = NULL;
  5853. else
  5854. inputStream->filename = (char *)
  5855. xmlCanonicPath((const xmlChar *) filename);
  5856. inputStream->buf = buf;
  5857. xmlBufResetInput(buf->buffer, inputStream);
  5858. inputPush(ctxt, inputStream);
  5859. if ((size > 0) && (chunk != NULL) && (ctxt->input != NULL) &&
  5860. (ctxt->input->buf != NULL)) {
  5861. size_t base = xmlBufGetInputBase(ctxt->input->buf->buffer, ctxt->input);
  5862. size_t cur = ctxt->input->cur - ctxt->input->base;
  5863. xmlParserInputBufferPush(ctxt->input->buf, size, chunk);
  5864. xmlBufSetInputBaseCur(ctxt->input->buf->buffer, ctxt->input, base, cur);
  5865. #ifdef DEBUG_PUSH
  5866. xmlGenericError(xmlGenericErrorContext, "HPP: pushed %d\n", size);
  5867. #endif
  5868. }
  5869. ctxt->progressive = 1;
  5870. return(ctxt);
  5871. }
  5872. #endif /* LIBXML_PUSH_ENABLED */
  5873. /**
  5874. * htmlSAXParseDoc:
  5875. * @cur: a pointer to an array of xmlChar
  5876. * @encoding: a free form C string describing the HTML document encoding, or NULL
  5877. * @sax: the SAX handler block
  5878. * @userData: if using SAX, this pointer will be provided on callbacks.
  5879. *
  5880. * Parse an HTML in-memory document. If sax is not NULL, use the SAX callbacks
  5881. * to handle parse events. If sax is NULL, fallback to the default DOM
  5882. * behavior and return a tree.
  5883. *
  5884. * Returns the resulting document tree unless SAX is NULL or the document is
  5885. * not well formed.
  5886. */
  5887. htmlDocPtr
  5888. htmlSAXParseDoc(const xmlChar *cur, const char *encoding,
  5889. htmlSAXHandlerPtr sax, void *userData) {
  5890. htmlDocPtr ret;
  5891. htmlParserCtxtPtr ctxt;
  5892. xmlInitParser();
  5893. if (cur == NULL) return(NULL);
  5894. ctxt = htmlCreateDocParserCtxt(cur, encoding);
  5895. if (ctxt == NULL) return(NULL);
  5896. if (sax != NULL) {
  5897. if (ctxt->sax != NULL) xmlFree (ctxt->sax);
  5898. ctxt->sax = sax;
  5899. ctxt->userData = userData;
  5900. }
  5901. htmlParseDocument(ctxt);
  5902. ret = ctxt->myDoc;
  5903. if (sax != NULL) {
  5904. ctxt->sax = NULL;
  5905. ctxt->userData = NULL;
  5906. }
  5907. htmlFreeParserCtxt(ctxt);
  5908. return(ret);
  5909. }
  5910. /**
  5911. * htmlParseDoc:
  5912. * @cur: a pointer to an array of xmlChar
  5913. * @encoding: a free form C string describing the HTML document encoding, or NULL
  5914. *
  5915. * parse an HTML in-memory document and build a tree.
  5916. *
  5917. * Returns the resulting document tree
  5918. */
  5919. htmlDocPtr
  5920. htmlParseDoc(const xmlChar *cur, const char *encoding) {
  5921. return(htmlSAXParseDoc(cur, encoding, NULL, NULL));
  5922. }
  5923. /**
  5924. * htmlCreateFileParserCtxt:
  5925. * @filename: the filename
  5926. * @encoding: a free form C string describing the HTML document encoding, or NULL
  5927. *
  5928. * Create a parser context for a file content.
  5929. * Automatic support for ZLIB/Compress compressed document is provided
  5930. * by default if found at compile-time.
  5931. *
  5932. * Returns the new parser context or NULL
  5933. */
  5934. htmlParserCtxtPtr
  5935. htmlCreateFileParserCtxt(const char *filename, const char *encoding)
  5936. {
  5937. htmlParserCtxtPtr ctxt;
  5938. htmlParserInputPtr inputStream;
  5939. char *canonicFilename;
  5940. /* htmlCharEncoding enc; */
  5941. xmlChar *content, *content_line = (xmlChar *) "charset=";
  5942. if (filename == NULL)
  5943. return(NULL);
  5944. ctxt = htmlNewParserCtxt();
  5945. if (ctxt == NULL) {
  5946. return(NULL);
  5947. }
  5948. canonicFilename = (char *) xmlCanonicPath((const xmlChar *) filename);
  5949. if (canonicFilename == NULL) {
  5950. #ifdef LIBXML_SAX1_ENABLED
  5951. if (xmlDefaultSAXHandler.error != NULL) {
  5952. xmlDefaultSAXHandler.error(NULL, "out of memory\n");
  5953. }
  5954. #endif
  5955. xmlFreeParserCtxt(ctxt);
  5956. return(NULL);
  5957. }
  5958. inputStream = xmlLoadExternalEntity(canonicFilename, NULL, ctxt);
  5959. xmlFree(canonicFilename);
  5960. if (inputStream == NULL) {
  5961. xmlFreeParserCtxt(ctxt);
  5962. return(NULL);
  5963. }
  5964. inputPush(ctxt, inputStream);
  5965. /* set encoding */
  5966. if (encoding) {
  5967. size_t l = strlen(encoding);
  5968. if (l < 1000) {
  5969. content = xmlMallocAtomic (xmlStrlen(content_line) + l + 1);
  5970. if (content) {
  5971. strcpy ((char *)content, (char *)content_line);
  5972. strcat ((char *)content, (char *)encoding);
  5973. htmlCheckEncoding (ctxt, content);
  5974. xmlFree (content);
  5975. }
  5976. }
  5977. }
  5978. return(ctxt);
  5979. }
  5980. /**
  5981. * htmlSAXParseFile:
  5982. * @filename: the filename
  5983. * @encoding: a free form C string describing the HTML document encoding, or NULL
  5984. * @sax: the SAX handler block
  5985. * @userData: if using SAX, this pointer will be provided on callbacks.
  5986. *
  5987. * parse an HTML file and build a tree. Automatic support for ZLIB/Compress
  5988. * compressed document is provided by default if found at compile-time.
  5989. * It use the given SAX function block to handle the parsing callback.
  5990. * If sax is NULL, fallback to the default DOM tree building routines.
  5991. *
  5992. * Returns the resulting document tree unless SAX is NULL or the document is
  5993. * not well formed.
  5994. */
  5995. htmlDocPtr
  5996. htmlSAXParseFile(const char *filename, const char *encoding, htmlSAXHandlerPtr sax,
  5997. void *userData) {
  5998. htmlDocPtr ret;
  5999. htmlParserCtxtPtr ctxt;
  6000. htmlSAXHandlerPtr oldsax = NULL;
  6001. xmlInitParser();
  6002. ctxt = htmlCreateFileParserCtxt(filename, encoding);
  6003. if (ctxt == NULL) return(NULL);
  6004. if (sax != NULL) {
  6005. oldsax = ctxt->sax;
  6006. ctxt->sax = sax;
  6007. ctxt->userData = userData;
  6008. }
  6009. htmlParseDocument(ctxt);
  6010. ret = ctxt->myDoc;
  6011. if (sax != NULL) {
  6012. ctxt->sax = oldsax;
  6013. ctxt->userData = NULL;
  6014. }
  6015. htmlFreeParserCtxt(ctxt);
  6016. return(ret);
  6017. }
  6018. /**
  6019. * htmlParseFile:
  6020. * @filename: the filename
  6021. * @encoding: a free form C string describing the HTML document encoding, or NULL
  6022. *
  6023. * parse an HTML file and build a tree. Automatic support for ZLIB/Compress
  6024. * compressed document is provided by default if found at compile-time.
  6025. *
  6026. * Returns the resulting document tree
  6027. */
  6028. htmlDocPtr
  6029. htmlParseFile(const char *filename, const char *encoding) {
  6030. return(htmlSAXParseFile(filename, encoding, NULL, NULL));
  6031. }
  6032. /**
  6033. * htmlHandleOmittedElem:
  6034. * @val: int 0 or 1
  6035. *
  6036. * Set and return the previous value for handling HTML omitted tags.
  6037. *
  6038. * Returns the last value for 0 for no handling, 1 for auto insertion.
  6039. */
  6040. int
  6041. htmlHandleOmittedElem(int val) {
  6042. int old = htmlOmittedDefaultValue;
  6043. htmlOmittedDefaultValue = val;
  6044. return(old);
  6045. }
  6046. /**
  6047. * htmlElementAllowedHere:
  6048. * @parent: HTML parent element
  6049. * @elt: HTML element
  6050. *
  6051. * Checks whether an HTML element may be a direct child of a parent element.
  6052. * Note - doesn't check for deprecated elements
  6053. *
  6054. * Returns 1 if allowed; 0 otherwise.
  6055. */
  6056. int
  6057. htmlElementAllowedHere(const htmlElemDesc* parent, const xmlChar* elt) {
  6058. const char** p ;
  6059. if ( ! elt || ! parent || ! parent->subelts )
  6060. return 0 ;
  6061. for ( p = parent->subelts; *p; ++p )
  6062. if ( !xmlStrcmp((const xmlChar *)*p, elt) )
  6063. return 1 ;
  6064. return 0 ;
  6065. }
  6066. /**
  6067. * htmlElementStatusHere:
  6068. * @parent: HTML parent element
  6069. * @elt: HTML element
  6070. *
  6071. * Checks whether an HTML element may be a direct child of a parent element.
  6072. * and if so whether it is valid or deprecated.
  6073. *
  6074. * Returns one of HTML_VALID, HTML_DEPRECATED, HTML_INVALID
  6075. */
  6076. htmlStatus
  6077. htmlElementStatusHere(const htmlElemDesc* parent, const htmlElemDesc* elt) {
  6078. if ( ! parent || ! elt )
  6079. return HTML_INVALID ;
  6080. if ( ! htmlElementAllowedHere(parent, (const xmlChar*) elt->name ) )
  6081. return HTML_INVALID ;
  6082. return ( elt->dtd == 0 ) ? HTML_VALID : HTML_DEPRECATED ;
  6083. }
  6084. /**
  6085. * htmlAttrAllowed:
  6086. * @elt: HTML element
  6087. * @attr: HTML attribute
  6088. * @legacy: whether to allow deprecated attributes
  6089. *
  6090. * Checks whether an attribute is valid for an element
  6091. * Has full knowledge of Required and Deprecated attributes
  6092. *
  6093. * Returns one of HTML_REQUIRED, HTML_VALID, HTML_DEPRECATED, HTML_INVALID
  6094. */
  6095. htmlStatus
  6096. htmlAttrAllowed(const htmlElemDesc* elt, const xmlChar* attr, int legacy) {
  6097. const char** p ;
  6098. if ( !elt || ! attr )
  6099. return HTML_INVALID ;
  6100. if ( elt->attrs_req )
  6101. for ( p = elt->attrs_req; *p; ++p)
  6102. if ( !xmlStrcmp((const xmlChar*)*p, attr) )
  6103. return HTML_REQUIRED ;
  6104. if ( elt->attrs_opt )
  6105. for ( p = elt->attrs_opt; *p; ++p)
  6106. if ( !xmlStrcmp((const xmlChar*)*p, attr) )
  6107. return HTML_VALID ;
  6108. if ( legacy && elt->attrs_depr )
  6109. for ( p = elt->attrs_depr; *p; ++p)
  6110. if ( !xmlStrcmp((const xmlChar*)*p, attr) )
  6111. return HTML_DEPRECATED ;
  6112. return HTML_INVALID ;
  6113. }
  6114. /**
  6115. * htmlNodeStatus:
  6116. * @node: an htmlNodePtr in a tree
  6117. * @legacy: whether to allow deprecated elements (YES is faster here
  6118. * for Element nodes)
  6119. *
  6120. * Checks whether the tree node is valid. Experimental (the author
  6121. * only uses the HTML enhancements in a SAX parser)
  6122. *
  6123. * Return: for Element nodes, a return from htmlElementAllowedHere (if
  6124. * legacy allowed) or htmlElementStatusHere (otherwise).
  6125. * for Attribute nodes, a return from htmlAttrAllowed
  6126. * for other nodes, HTML_NA (no checks performed)
  6127. */
  6128. htmlStatus
  6129. htmlNodeStatus(const htmlNodePtr node, int legacy) {
  6130. if ( ! node )
  6131. return HTML_INVALID ;
  6132. switch ( node->type ) {
  6133. case XML_ELEMENT_NODE:
  6134. return legacy
  6135. ? ( htmlElementAllowedHere (
  6136. htmlTagLookup(node->parent->name) , node->name
  6137. ) ? HTML_VALID : HTML_INVALID )
  6138. : htmlElementStatusHere(
  6139. htmlTagLookup(node->parent->name) ,
  6140. htmlTagLookup(node->name) )
  6141. ;
  6142. case XML_ATTRIBUTE_NODE:
  6143. return htmlAttrAllowed(
  6144. htmlTagLookup(node->parent->name) , node->name, legacy) ;
  6145. default: return HTML_NA ;
  6146. }
  6147. }
  6148. /************************************************************************
  6149. * *
  6150. * New set (2.6.0) of simpler and more flexible APIs *
  6151. * *
  6152. ************************************************************************/
  6153. /**
  6154. * DICT_FREE:
  6155. * @str: a string
  6156. *
  6157. * Free a string if it is not owned by the "dict" dictionary in the
  6158. * current scope
  6159. */
  6160. #define DICT_FREE(str) \
  6161. if ((str) && ((!dict) || \
  6162. (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
  6163. xmlFree((char *)(str));
  6164. /**
  6165. * htmlCtxtReset:
  6166. * @ctxt: an HTML parser context
  6167. *
  6168. * Reset a parser context
  6169. */
  6170. void
  6171. htmlCtxtReset(htmlParserCtxtPtr ctxt)
  6172. {
  6173. xmlParserInputPtr input;
  6174. xmlDictPtr dict;
  6175. if (ctxt == NULL)
  6176. return;
  6177. xmlInitParser();
  6178. dict = ctxt->dict;
  6179. while ((input = inputPop(ctxt)) != NULL) { /* Non consuming */
  6180. xmlFreeInputStream(input);
  6181. }
  6182. ctxt->inputNr = 0;
  6183. ctxt->input = NULL;
  6184. ctxt->spaceNr = 0;
  6185. if (ctxt->spaceTab != NULL) {
  6186. ctxt->spaceTab[0] = -1;
  6187. ctxt->space = &ctxt->spaceTab[0];
  6188. } else {
  6189. ctxt->space = NULL;
  6190. }
  6191. ctxt->nodeNr = 0;
  6192. ctxt->node = NULL;
  6193. ctxt->nameNr = 0;
  6194. ctxt->name = NULL;
  6195. DICT_FREE(ctxt->version);
  6196. ctxt->version = NULL;
  6197. DICT_FREE(ctxt->encoding);
  6198. ctxt->encoding = NULL;
  6199. DICT_FREE(ctxt->directory);
  6200. ctxt->directory = NULL;
  6201. DICT_FREE(ctxt->extSubURI);
  6202. ctxt->extSubURI = NULL;
  6203. DICT_FREE(ctxt->extSubSystem);
  6204. ctxt->extSubSystem = NULL;
  6205. if (ctxt->myDoc != NULL)
  6206. xmlFreeDoc(ctxt->myDoc);
  6207. ctxt->myDoc = NULL;
  6208. ctxt->standalone = -1;
  6209. ctxt->hasExternalSubset = 0;
  6210. ctxt->hasPErefs = 0;
  6211. ctxt->html = 1;
  6212. ctxt->external = 0;
  6213. ctxt->instate = XML_PARSER_START;
  6214. ctxt->token = 0;
  6215. ctxt->wellFormed = 1;
  6216. ctxt->nsWellFormed = 1;
  6217. ctxt->disableSAX = 0;
  6218. ctxt->valid = 1;
  6219. ctxt->vctxt.userData = ctxt;
  6220. ctxt->vctxt.error = xmlParserValidityError;
  6221. ctxt->vctxt.warning = xmlParserValidityWarning;
  6222. ctxt->record_info = 0;
  6223. ctxt->checkIndex = 0;
  6224. ctxt->inSubset = 0;
  6225. ctxt->errNo = XML_ERR_OK;
  6226. ctxt->depth = 0;
  6227. ctxt->charset = XML_CHAR_ENCODING_NONE;
  6228. ctxt->catalogs = NULL;
  6229. xmlInitNodeInfoSeq(&ctxt->node_seq);
  6230. if (ctxt->attsDefault != NULL) {
  6231. xmlHashFree(ctxt->attsDefault, xmlHashDefaultDeallocator);
  6232. ctxt->attsDefault = NULL;
  6233. }
  6234. if (ctxt->attsSpecial != NULL) {
  6235. xmlHashFree(ctxt->attsSpecial, NULL);
  6236. ctxt->attsSpecial = NULL;
  6237. }
  6238. }
  6239. /**
  6240. * htmlCtxtUseOptions:
  6241. * @ctxt: an HTML parser context
  6242. * @options: a combination of htmlParserOption(s)
  6243. *
  6244. * Applies the options to the parser context
  6245. *
  6246. * Returns 0 in case of success, the set of unknown or unimplemented options
  6247. * in case of error.
  6248. */
  6249. int
  6250. htmlCtxtUseOptions(htmlParserCtxtPtr ctxt, int options)
  6251. {
  6252. if (ctxt == NULL)
  6253. return(-1);
  6254. if (options & HTML_PARSE_NOWARNING) {
  6255. ctxt->sax->warning = NULL;
  6256. ctxt->vctxt.warning = NULL;
  6257. options -= XML_PARSE_NOWARNING;
  6258. ctxt->options |= XML_PARSE_NOWARNING;
  6259. }
  6260. if (options & HTML_PARSE_NOERROR) {
  6261. ctxt->sax->error = NULL;
  6262. ctxt->vctxt.error = NULL;
  6263. ctxt->sax->fatalError = NULL;
  6264. options -= XML_PARSE_NOERROR;
  6265. ctxt->options |= XML_PARSE_NOERROR;
  6266. }
  6267. if (options & HTML_PARSE_PEDANTIC) {
  6268. ctxt->pedantic = 1;
  6269. options -= XML_PARSE_PEDANTIC;
  6270. ctxt->options |= XML_PARSE_PEDANTIC;
  6271. } else
  6272. ctxt->pedantic = 0;
  6273. if (options & XML_PARSE_NOBLANKS) {
  6274. ctxt->keepBlanks = 0;
  6275. ctxt->sax->ignorableWhitespace = xmlSAX2IgnorableWhitespace;
  6276. options -= XML_PARSE_NOBLANKS;
  6277. ctxt->options |= XML_PARSE_NOBLANKS;
  6278. } else
  6279. ctxt->keepBlanks = 1;
  6280. if (options & HTML_PARSE_RECOVER) {
  6281. ctxt->recovery = 1;
  6282. options -= HTML_PARSE_RECOVER;
  6283. } else
  6284. ctxt->recovery = 0;
  6285. if (options & HTML_PARSE_COMPACT) {
  6286. ctxt->options |= HTML_PARSE_COMPACT;
  6287. options -= HTML_PARSE_COMPACT;
  6288. }
  6289. if (options & XML_PARSE_HUGE) {
  6290. ctxt->options |= XML_PARSE_HUGE;
  6291. options -= XML_PARSE_HUGE;
  6292. }
  6293. if (options & HTML_PARSE_NODEFDTD) {
  6294. ctxt->options |= HTML_PARSE_NODEFDTD;
  6295. options -= HTML_PARSE_NODEFDTD;
  6296. }
  6297. if (options & HTML_PARSE_IGNORE_ENC) {
  6298. ctxt->options |= HTML_PARSE_IGNORE_ENC;
  6299. options -= HTML_PARSE_IGNORE_ENC;
  6300. }
  6301. if (options & HTML_PARSE_NOIMPLIED) {
  6302. ctxt->options |= HTML_PARSE_NOIMPLIED;
  6303. options -= HTML_PARSE_NOIMPLIED;
  6304. }
  6305. ctxt->dictNames = 0;
  6306. return (options);
  6307. }
  6308. /**
  6309. * htmlDoRead:
  6310. * @ctxt: an HTML parser context
  6311. * @URL: the base URL to use for the document
  6312. * @encoding: the document encoding, or NULL
  6313. * @options: a combination of htmlParserOption(s)
  6314. * @reuse: keep the context for reuse
  6315. *
  6316. * Common front-end for the htmlRead functions
  6317. *
  6318. * Returns the resulting document tree or NULL
  6319. */
  6320. static htmlDocPtr
  6321. htmlDoRead(htmlParserCtxtPtr ctxt, const char *URL, const char *encoding,
  6322. int options, int reuse)
  6323. {
  6324. htmlDocPtr ret;
  6325. htmlCtxtUseOptions(ctxt, options);
  6326. ctxt->html = 1;
  6327. if (encoding != NULL) {
  6328. xmlCharEncodingHandlerPtr hdlr;
  6329. hdlr = xmlFindCharEncodingHandler(encoding);
  6330. if (hdlr != NULL) {
  6331. xmlSwitchToEncoding(ctxt, hdlr);
  6332. if (ctxt->input->encoding != NULL)
  6333. xmlFree((xmlChar *) ctxt->input->encoding);
  6334. ctxt->input->encoding = xmlStrdup((xmlChar *)encoding);
  6335. }
  6336. }
  6337. if ((URL != NULL) && (ctxt->input != NULL) &&
  6338. (ctxt->input->filename == NULL))
  6339. ctxt->input->filename = (char *) xmlStrdup((const xmlChar *) URL);
  6340. htmlParseDocument(ctxt);
  6341. ret = ctxt->myDoc;
  6342. ctxt->myDoc = NULL;
  6343. if (!reuse) {
  6344. if ((ctxt->dictNames) &&
  6345. (ret != NULL) &&
  6346. (ret->dict == ctxt->dict))
  6347. ctxt->dict = NULL;
  6348. xmlFreeParserCtxt(ctxt);
  6349. }
  6350. return (ret);
  6351. }
  6352. /**
  6353. * htmlReadDoc:
  6354. * @cur: a pointer to a zero terminated string
  6355. * @URL: the base URL to use for the document
  6356. * @encoding: the document encoding, or NULL
  6357. * @options: a combination of htmlParserOption(s)
  6358. *
  6359. * parse an XML in-memory document and build a tree.
  6360. *
  6361. * Returns the resulting document tree
  6362. */
  6363. htmlDocPtr
  6364. htmlReadDoc(const xmlChar * cur, const char *URL, const char *encoding, int options)
  6365. {
  6366. htmlParserCtxtPtr ctxt;
  6367. if (cur == NULL)
  6368. return (NULL);
  6369. xmlInitParser();
  6370. ctxt = htmlCreateDocParserCtxt(cur, NULL);
  6371. if (ctxt == NULL)
  6372. return (NULL);
  6373. return (htmlDoRead(ctxt, URL, encoding, options, 0));
  6374. }
  6375. /**
  6376. * htmlReadFile:
  6377. * @filename: a file or URL
  6378. * @encoding: the document encoding, or NULL
  6379. * @options: a combination of htmlParserOption(s)
  6380. *
  6381. * parse an XML file from the filesystem or the network.
  6382. *
  6383. * Returns the resulting document tree
  6384. */
  6385. htmlDocPtr
  6386. htmlReadFile(const char *filename, const char *encoding, int options)
  6387. {
  6388. htmlParserCtxtPtr ctxt;
  6389. xmlInitParser();
  6390. ctxt = htmlCreateFileParserCtxt(filename, encoding);
  6391. if (ctxt == NULL)
  6392. return (NULL);
  6393. return (htmlDoRead(ctxt, NULL, NULL, options, 0));
  6394. }
  6395. /**
  6396. * htmlReadMemory:
  6397. * @buffer: a pointer to a char array
  6398. * @size: the size of the array
  6399. * @URL: the base URL to use for the document
  6400. * @encoding: the document encoding, or NULL
  6401. * @options: a combination of htmlParserOption(s)
  6402. *
  6403. * parse an XML in-memory document and build a tree.
  6404. *
  6405. * Returns the resulting document tree
  6406. */
  6407. htmlDocPtr
  6408. htmlReadMemory(const char *buffer, int size, const char *URL, const char *encoding, int options)
  6409. {
  6410. htmlParserCtxtPtr ctxt;
  6411. xmlInitParser();
  6412. ctxt = xmlCreateMemoryParserCtxt(buffer, size);
  6413. if (ctxt == NULL)
  6414. return (NULL);
  6415. htmlDefaultSAXHandlerInit();
  6416. if (ctxt->sax != NULL)
  6417. memcpy(ctxt->sax, &htmlDefaultSAXHandler, sizeof(xmlSAXHandlerV1));
  6418. return (htmlDoRead(ctxt, URL, encoding, options, 0));
  6419. }
  6420. /**
  6421. * htmlReadFd:
  6422. * @fd: an open file descriptor
  6423. * @URL: the base URL to use for the document
  6424. * @encoding: the document encoding, or NULL
  6425. * @options: a combination of htmlParserOption(s)
  6426. *
  6427. * parse an HTML from a file descriptor and build a tree.
  6428. * NOTE that the file descriptor will not be closed when the
  6429. * reader is closed or reset.
  6430. *
  6431. * Returns the resulting document tree
  6432. */
  6433. htmlDocPtr
  6434. htmlReadFd(int fd, const char *URL, const char *encoding, int options)
  6435. {
  6436. htmlParserCtxtPtr ctxt;
  6437. xmlParserInputBufferPtr input;
  6438. htmlParserInputPtr stream;
  6439. if (fd < 0)
  6440. return (NULL);
  6441. xmlInitParser();
  6442. input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE);
  6443. if (input == NULL)
  6444. return (NULL);
  6445. input->closecallback = NULL;
  6446. ctxt = htmlNewParserCtxt();
  6447. if (ctxt == NULL) {
  6448. xmlFreeParserInputBuffer(input);
  6449. return (NULL);
  6450. }
  6451. stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE);
  6452. if (stream == NULL) {
  6453. xmlFreeParserInputBuffer(input);
  6454. htmlFreeParserCtxt(ctxt);
  6455. return (NULL);
  6456. }
  6457. inputPush(ctxt, stream);
  6458. return (htmlDoRead(ctxt, URL, encoding, options, 0));
  6459. }
  6460. /**
  6461. * htmlReadIO:
  6462. * @ioread: an I/O read function
  6463. * @ioclose: an I/O close function
  6464. * @ioctx: an I/O handler
  6465. * @URL: the base URL to use for the document
  6466. * @encoding: the document encoding, or NULL
  6467. * @options: a combination of htmlParserOption(s)
  6468. *
  6469. * parse an HTML document from I/O functions and source and build a tree.
  6470. *
  6471. * Returns the resulting document tree
  6472. */
  6473. htmlDocPtr
  6474. htmlReadIO(xmlInputReadCallback ioread, xmlInputCloseCallback ioclose,
  6475. void *ioctx, const char *URL, const char *encoding, int options)
  6476. {
  6477. htmlParserCtxtPtr ctxt;
  6478. xmlParserInputBufferPtr input;
  6479. xmlParserInputPtr stream;
  6480. if (ioread == NULL)
  6481. return (NULL);
  6482. xmlInitParser();
  6483. input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx,
  6484. XML_CHAR_ENCODING_NONE);
  6485. if (input == NULL) {
  6486. if (ioclose != NULL)
  6487. ioclose(ioctx);
  6488. return (NULL);
  6489. }
  6490. ctxt = htmlNewParserCtxt();
  6491. if (ctxt == NULL) {
  6492. xmlFreeParserInputBuffer(input);
  6493. return (NULL);
  6494. }
  6495. stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE);
  6496. if (stream == NULL) {
  6497. xmlFreeParserInputBuffer(input);
  6498. xmlFreeParserCtxt(ctxt);
  6499. return (NULL);
  6500. }
  6501. inputPush(ctxt, stream);
  6502. return (htmlDoRead(ctxt, URL, encoding, options, 0));
  6503. }
  6504. /**
  6505. * htmlCtxtReadDoc:
  6506. * @ctxt: an HTML parser context
  6507. * @cur: a pointer to a zero terminated string
  6508. * @URL: the base URL to use for the document
  6509. * @encoding: the document encoding, or NULL
  6510. * @options: a combination of htmlParserOption(s)
  6511. *
  6512. * parse an XML in-memory document and build a tree.
  6513. * This reuses the existing @ctxt parser context
  6514. *
  6515. * Returns the resulting document tree
  6516. */
  6517. htmlDocPtr
  6518. htmlCtxtReadDoc(htmlParserCtxtPtr ctxt, const xmlChar * cur,
  6519. const char *URL, const char *encoding, int options)
  6520. {
  6521. xmlParserInputPtr stream;
  6522. if (cur == NULL)
  6523. return (NULL);
  6524. if (ctxt == NULL)
  6525. return (NULL);
  6526. xmlInitParser();
  6527. htmlCtxtReset(ctxt);
  6528. stream = xmlNewStringInputStream(ctxt, cur);
  6529. if (stream == NULL) {
  6530. return (NULL);
  6531. }
  6532. inputPush(ctxt, stream);
  6533. return (htmlDoRead(ctxt, URL, encoding, options, 1));
  6534. }
  6535. /**
  6536. * htmlCtxtReadFile:
  6537. * @ctxt: an HTML parser context
  6538. * @filename: a file or URL
  6539. * @encoding: the document encoding, or NULL
  6540. * @options: a combination of htmlParserOption(s)
  6541. *
  6542. * parse an XML file from the filesystem or the network.
  6543. * This reuses the existing @ctxt parser context
  6544. *
  6545. * Returns the resulting document tree
  6546. */
  6547. htmlDocPtr
  6548. htmlCtxtReadFile(htmlParserCtxtPtr ctxt, const char *filename,
  6549. const char *encoding, int options)
  6550. {
  6551. xmlParserInputPtr stream;
  6552. if (filename == NULL)
  6553. return (NULL);
  6554. if (ctxt == NULL)
  6555. return (NULL);
  6556. xmlInitParser();
  6557. htmlCtxtReset(ctxt);
  6558. stream = xmlLoadExternalEntity(filename, NULL, ctxt);
  6559. if (stream == NULL) {
  6560. return (NULL);
  6561. }
  6562. inputPush(ctxt, stream);
  6563. return (htmlDoRead(ctxt, NULL, encoding, options, 1));
  6564. }
  6565. /**
  6566. * htmlCtxtReadMemory:
  6567. * @ctxt: an HTML parser context
  6568. * @buffer: a pointer to a char array
  6569. * @size: the size of the array
  6570. * @URL: the base URL to use for the document
  6571. * @encoding: the document encoding, or NULL
  6572. * @options: a combination of htmlParserOption(s)
  6573. *
  6574. * parse an XML in-memory document and build a tree.
  6575. * This reuses the existing @ctxt parser context
  6576. *
  6577. * Returns the resulting document tree
  6578. */
  6579. htmlDocPtr
  6580. htmlCtxtReadMemory(htmlParserCtxtPtr ctxt, const char *buffer, int size,
  6581. const char *URL, const char *encoding, int options)
  6582. {
  6583. xmlParserInputBufferPtr input;
  6584. xmlParserInputPtr stream;
  6585. if (ctxt == NULL)
  6586. return (NULL);
  6587. if (buffer == NULL)
  6588. return (NULL);
  6589. xmlInitParser();
  6590. htmlCtxtReset(ctxt);
  6591. input = xmlParserInputBufferCreateMem(buffer, size, XML_CHAR_ENCODING_NONE);
  6592. if (input == NULL) {
  6593. return(NULL);
  6594. }
  6595. stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE);
  6596. if (stream == NULL) {
  6597. xmlFreeParserInputBuffer(input);
  6598. return(NULL);
  6599. }
  6600. inputPush(ctxt, stream);
  6601. return (htmlDoRead(ctxt, URL, encoding, options, 1));
  6602. }
  6603. /**
  6604. * htmlCtxtReadFd:
  6605. * @ctxt: an HTML parser context
  6606. * @fd: an open file descriptor
  6607. * @URL: the base URL to use for the document
  6608. * @encoding: the document encoding, or NULL
  6609. * @options: a combination of htmlParserOption(s)
  6610. *
  6611. * parse an XML from a file descriptor and build a tree.
  6612. * This reuses the existing @ctxt parser context
  6613. *
  6614. * Returns the resulting document tree
  6615. */
  6616. htmlDocPtr
  6617. htmlCtxtReadFd(htmlParserCtxtPtr ctxt, int fd,
  6618. const char *URL, const char *encoding, int options)
  6619. {
  6620. xmlParserInputBufferPtr input;
  6621. xmlParserInputPtr stream;
  6622. if (fd < 0)
  6623. return (NULL);
  6624. if (ctxt == NULL)
  6625. return (NULL);
  6626. xmlInitParser();
  6627. htmlCtxtReset(ctxt);
  6628. input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE);
  6629. if (input == NULL)
  6630. return (NULL);
  6631. stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE);
  6632. if (stream == NULL) {
  6633. xmlFreeParserInputBuffer(input);
  6634. return (NULL);
  6635. }
  6636. inputPush(ctxt, stream);
  6637. return (htmlDoRead(ctxt, URL, encoding, options, 1));
  6638. }
  6639. /**
  6640. * htmlCtxtReadIO:
  6641. * @ctxt: an HTML parser context
  6642. * @ioread: an I/O read function
  6643. * @ioclose: an I/O close function
  6644. * @ioctx: an I/O handler
  6645. * @URL: the base URL to use for the document
  6646. * @encoding: the document encoding, or NULL
  6647. * @options: a combination of htmlParserOption(s)
  6648. *
  6649. * parse an HTML document from I/O functions and source and build a tree.
  6650. * This reuses the existing @ctxt parser context
  6651. *
  6652. * Returns the resulting document tree
  6653. */
  6654. htmlDocPtr
  6655. htmlCtxtReadIO(htmlParserCtxtPtr ctxt, xmlInputReadCallback ioread,
  6656. xmlInputCloseCallback ioclose, void *ioctx,
  6657. const char *URL,
  6658. const char *encoding, int options)
  6659. {
  6660. xmlParserInputBufferPtr input;
  6661. xmlParserInputPtr stream;
  6662. if (ioread == NULL)
  6663. return (NULL);
  6664. if (ctxt == NULL)
  6665. return (NULL);
  6666. xmlInitParser();
  6667. htmlCtxtReset(ctxt);
  6668. input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx,
  6669. XML_CHAR_ENCODING_NONE);
  6670. if (input == NULL) {
  6671. if (ioclose != NULL)
  6672. ioclose(ioctx);
  6673. return (NULL);
  6674. }
  6675. stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE);
  6676. if (stream == NULL) {
  6677. xmlFreeParserInputBuffer(input);
  6678. return (NULL);
  6679. }
  6680. inputPush(ctxt, stream);
  6681. return (htmlDoRead(ctxt, URL, encoding, options, 1));
  6682. }
  6683. #endif /* LIBXML_HTML_ENABLED */