xmltextreader.pp 111 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012
  1. {
  2. This file is part of the Free Component Library
  3. TXMLTextReader, a streaming text XML reader
  4. Copyright (c) 1999-2000 by Sebastian Guenther, [email protected]
  5. Modified in 2006 by Sergei Gorelkin, [email protected]
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {$IFNDEF FPC_DOTTEDUNITS}
  13. unit xmltextreader;
  14. {$ENDIF FPC_DOTTEDUNITS}
  15. {$mode objfpc}{$h+}
  16. interface
  17. {$IFDEF FPC_DOTTEDUNITS}
  18. uses
  19. System.SysUtils, System.Classes, Xml.Utils, Xml.Reader, Xml.DtdModel;
  20. {$ELSE FPC_DOTTEDUNITS}
  21. uses
  22. SysUtils, Classes, xmlutils, xmlreader, dtdmodel;
  23. {$ENDIF FPC_DOTTEDUNITS}
  24. type
  25. TDecoder = record
  26. Context: Pointer;
  27. Decode: function(Context: Pointer; InBuf: PAnsiChar; var InCnt: Cardinal; OutBuf: PWideChar; var OutCnt: Cardinal): Integer; stdcall;
  28. Cleanup: procedure(Context: Pointer); stdcall;
  29. end;
  30. TGetDecoderProc = function(const AEncoding: string; out Decoder: TDecoder): Boolean; stdcall;
  31. TXMLSourceKind = (skNone, skInternalSubset, skManualPop);
  32. TXMLTextReader = class;
  33. TXMLCharSource = class(TObject)
  34. private
  35. FBuf: PWideChar;
  36. FBufEnd: PWideChar;
  37. FReader: TXMLTextReader;
  38. FParent: TXMLCharSource;
  39. FEntity: TEntityDecl;
  40. FLineNo: Integer;
  41. LFPos: PWideChar;
  42. FXML11Rules: Boolean;
  43. FSourceURI: XMLString;
  44. FCharCount: Cardinal;
  45. FStartNesting: Integer;
  46. FXMLVersion: TXMLVersion;
  47. FXMLEncoding: XMLString;
  48. function GetSourceURI: XMLString;
  49. protected
  50. function Reload: Boolean; virtual;
  51. public
  52. Kind: TXMLSourceKind;
  53. constructor Create(const AData: XMLString);
  54. procedure NextChar;
  55. procedure NewLine; virtual;
  56. function SkipUntil(var ToFill: TWideCharBuf; const Delim: TSetOfChar;
  57. wsflag: PBoolean = nil): WideChar; virtual;
  58. procedure Initialize; virtual;
  59. function SetEncoding(const AEncoding: string): Boolean; virtual;
  60. function Matches(const arg: XMLString): Boolean;
  61. function MatchesLong(const arg: XMLString): Boolean;
  62. property SourceURI: XMLString read GetSourceURI write FSourceURI;
  63. end;
  64. TElementValidator = object
  65. FElementDef: TElementDecl;
  66. FCurCP: TContentParticle;
  67. FFailed: Boolean;
  68. FSaViolation: Boolean;
  69. FContentType: TElementContentType; // =ctAny when FElementDef is nil
  70. function IsElementAllowed(Def: TElementDecl): Boolean;
  71. function Incomplete: Boolean;
  72. end;
  73. TNodeDataDynArray = array of TNodeData;
  74. TValidatorDynArray = array of TElementValidator;
  75. TCheckNameFlags = set of (cnOptional, cnToken);
  76. TXMLToken = (xtNone, xtEOF, xtText, xtElement, xtEndElement,
  77. xtCDSect, xtComment, xtPI, xtDoctype, xtEntity, xtEntityEnd, xtPopElement,
  78. xtPopEmptyElement, xtPushElement, xtPushEntity, xtPopEntity, xtFakeLF);
  79. TAttributeReadState = (arsNone, arsText, arsEntity, arsEntityEnd, arsPushEntity);
  80. TLiteralType = (ltPlain, ltPubid, ltEntity);
  81. TEntityEvent = procedure(Sender: TXMLTextReader; AEntity: TEntityDecl) of object;
  82. TXMLTextReader = class(TXMLReader, IXmlLineInfo, IGetNodeDataPtr)
  83. private
  84. FSource: TXMLCharSource;
  85. FNameTable: THashTable;
  86. FXML11: Boolean;
  87. FNameTableOwned: Boolean;
  88. FState: (rsProlog, rsDTD, rsAfterDTD, rsRoot, rsEpilog);
  89. FHavePERefs: Boolean;
  90. FInsideDecl: Boolean;
  91. FValue: TWideCharBuf;
  92. FEntityValue: TWideCharBuf;
  93. FName: TWideCharBuf;
  94. FTokenStart: TLocation;
  95. FStandalone: Boolean;
  96. FDocType: TDTDModel;
  97. FPEMap: THashTable;
  98. FForwardRefs: TFPList;
  99. FDTDStartPos: PWideChar;
  100. FIntSubset: TWideCharBuf;
  101. FAttrTag: Cardinal;
  102. FDTDProcessed: Boolean;
  103. FFragmentMode: Boolean;
  104. FNext: TXMLToken;
  105. FCurrEntity: TEntityDecl;
  106. FIDMap: THashTable;
  107. FAttrDefIndex: array of Cardinal;
  108. FNSHelper: TNSSupport;
  109. FNsAttHash: TDblHashArray;
  110. FEmptyStr: PHashItem;
  111. FStdPrefix_xml: PHashItem;
  112. FStdPrefix_xmlns: PHashItem;
  113. FStdUri_xml: PHashItem;
  114. FStdUri_xmlns: PHashItem;
  115. FColonPos: Integer;
  116. FValidate: Boolean; // parsing options, copy of FCtrl.Options
  117. FPreserveWhitespace: Boolean;
  118. FExpandEntities: Boolean;
  119. FIgnoreComments: Boolean;
  120. FCDSectionsAsText: Boolean;
  121. FNamespaces: Boolean;
  122. FDisallowDoctype: Boolean;
  123. FCanonical: Boolean;
  124. FMaxChars: Cardinal;
  125. FOnError: TXMLErrorEvent;
  126. FCurrAttrIndex: Integer;
  127. FOnEntity: TEntityEvent;
  128. procedure CleanAttrReadState;
  129. procedure SetEOFState;
  130. procedure SkipQuote(out Delim: WideChar; required: Boolean = True);
  131. procedure SetSource(ASource: TXMLCharSource);
  132. function ContextPush(AEntity: TEntityDecl; DummySource: Boolean = False): Boolean;
  133. function ContextPop(Forced: Boolean = False): Boolean;
  134. function ParseQuantity: TCPQuant;
  135. procedure StoreLocation(out Loc: TLocation);
  136. procedure ValidateAttrValue(AttrDef: TAttributeDef; attrData: PNodeData);
  137. procedure AddForwardRef(Buf: PWideChar; Length: Integer);
  138. procedure ClearForwardRefs;
  139. procedure CallErrorHandler(E: EXMLReadError);
  140. function FindOrCreateElDef: TElementDecl;
  141. function SkipUntilSeq(const Delim: TSetOfChar; c1: WideChar): Boolean;
  142. procedure CheckMaxChars(ToAdd: Cardinal);
  143. function AllocNodeData(AIndex: Integer): PNodeData;
  144. function AllocAttributeData: PNodeData;
  145. procedure AllocAttributeValueChunk(var APrev: PNodeData; Offset: Integer);
  146. procedure AddPseudoAttribute(aName: PHashItem; const aValue: XMLString;
  147. const nameLoc, valueLoc: TLocation);
  148. procedure CleanupAttribute(aNode: PNodeData);
  149. procedure CleanupAttributes;
  150. procedure SetNodeInfoWithValue(typ: TXMLNodeType; AName: PHashItem = nil);
  151. function SetupFakeLF(nextstate: TXMLToken): Boolean;
  152. function AddId(aNodeData: PNodeData): Boolean;
  153. function QueryInterface(constref iid: TGUID; out obj): HRESULT; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  154. function _AddRef: Longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  155. function _Release: Longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  156. procedure SetFragmentMode(aValue: Boolean);
  157. protected
  158. FNesting: Integer;
  159. FCurrNode: PNodeData;
  160. FAttrCount: Integer;
  161. FPrefixedAttrs: Integer;
  162. FSpecifiedAttrs: Integer;
  163. FNodeStack: TNodeDataDynArray;
  164. FValidatorNesting: Integer;
  165. FValidators: TValidatorDynArray;
  166. FFreeAttrChunk: PNodeData;
  167. FAttrCleanupFlag: Boolean;
  168. // ReadAttributeValue state
  169. FAttrReadState: TAttributeReadState;
  170. FAttrBaseSource: TObject;
  171. procedure DoError(Severity: TErrorSeverity; const descr: string; LineOffs: Integer=0);
  172. procedure DoErrorPos(Severity: TErrorSeverity; const descr: string;
  173. const ErrPos: TLocation); overload;
  174. procedure DoErrorPos(Severity: TErrorSeverity; const descr: string;
  175. const args: array of const; const ErrPos: TLocation); overload;
  176. procedure FatalError(const descr: String; LineOffs: Integer=0); overload;
  177. procedure FatalError(const descr: string; const args: array of const; LineOffs: Integer=0); overload;
  178. procedure FatalError(Expected: WideChar); overload;
  179. function SkipWhitespace(PercentAloneIsOk: Boolean = False): Boolean;
  180. function SkipS(required: Boolean = False): Boolean;
  181. procedure ExpectWhitespace;
  182. procedure ExpectString(const s: String);
  183. procedure ExpectChar(wc: WideChar);
  184. function CheckForChar(c: WideChar): Boolean;
  185. procedure RaiseNameNotFound;
  186. function CheckName(aFlags: TCheckNameFlags = []): Boolean;
  187. procedure CheckNCName;
  188. function ParseLiteral(var ToFill: TWideCharBuf; aType: TLiteralType;
  189. Required: Boolean): Boolean;
  190. procedure ExpectAttValue(attrData: PNodeData; NonCDATA: Boolean); // [10]
  191. procedure ParseComment(discard: Boolean); // [15]
  192. procedure ParsePI; // [16]
  193. procedure ParseXmlOrTextDecl(TextDecl: Boolean);
  194. procedure ExpectEq;
  195. procedure ParseDoctypeDecl; // [28]
  196. procedure ParseMarkupDecl; // [29]
  197. procedure ParseIgnoreSection;
  198. procedure ParseStartTag; // [39]
  199. procedure ParseEndTag; // [42]
  200. procedure HandleEntityStart;
  201. procedure HandleEntityEnd;
  202. procedure DoStartEntity;
  203. procedure ParseAttribute(ElDef: TElementDecl);
  204. function ReadTopLevel: Boolean;
  205. procedure NextAttrValueChunk;
  206. function GetHasLineInfo: Boolean;
  207. function GetLineNumber: Integer;
  208. function GetLinePosition: Integer;
  209. function CurrentNodePtr: PPNodeData;
  210. public
  211. function Read: Boolean; override;
  212. function MoveToFirstAttribute: Boolean; override;
  213. function MoveToNextAttribute: Boolean; override;
  214. function MoveToElement: Boolean; override;
  215. function ReadAttributeValue: Boolean; override;
  216. procedure Close; override;
  217. procedure ResolveEntity; override;
  218. function GetAttribute(i: Integer): XMLString; override;
  219. function GetAttribute(const AName: XMLString): XMLString; override;
  220. function GetAttribute(const ALocalName, nsuri: XMLString): XMLString; override;
  221. function LookupNamespace(const APrefix: XMLString): XMLString; override;
  222. property LineNumber: Integer read GetLineNumber;
  223. property LinePosition: Integer read GetLinePosition;
  224. protected
  225. function GetXmlVersion: TXMLVersion;
  226. function GetXmlEncoding: XMLString;
  227. function GetNameTable: THashTable; override;
  228. function GetDepth: Integer; override;
  229. function GetNodeType: TXmlNodeType; override;
  230. function GetName: XMLString; override;
  231. function GetValue: XMLString; override;
  232. function GetLocalName: XMLString; override;
  233. function GetPrefix: XMLString; override;
  234. function GetNamespaceUri: XMLString; override;
  235. function GetHasValue: Boolean; override;
  236. function GetAttributeCount: Integer; override;
  237. function GetBaseUri: XMLString; override;
  238. function GetIsDefault: Boolean; override;
  239. function ResolvePredefined: Boolean;
  240. function EntityCheck(NoExternals: Boolean = False): TEntityDecl;
  241. function PrefetchEntity(AEntity: TEntityDecl): Boolean;
  242. procedure StartPE;
  243. function ParseRef(var ToFill: TWideCharBuf): Boolean; // [67]
  244. function ParseExternalID(out SysID, PubID: XMLString; // [75]
  245. out PubIDLoc: TLocation; SysIdOptional: Boolean): Boolean;
  246. procedure CheckPENesting(aExpected: TObject);
  247. procedure ParseEntityDecl;
  248. procedure ParseAttlistDecl;
  249. procedure ExpectChoiceOrSeq(CP: TContentParticle; MustEndIn: TObject);
  250. procedure ParseElementDecl;
  251. procedure ParseNotationDecl;
  252. function ResolveResource(const ASystemID, APublicID, ABaseURI: XMLString; out Source: TXMLCharSource): Boolean;
  253. procedure ProcessDefaultAttributes(ElDef: TElementDecl);
  254. procedure ProcessNamespaceAtts;
  255. function AddBinding(attrData: PNodeData): Boolean;
  256. procedure PushVC(aElDef: TElementDecl);
  257. procedure PopElement;
  258. procedure ValidateDTD;
  259. procedure ValidationError(const Msg: string; const args: array of const; LineOffs: Integer = -1);
  260. procedure ValidationErrorWithName(const Msg: string; LineOffs: Integer = -1);
  261. procedure DTDReloadHook;
  262. procedure ConvertSource(SrcIn: TXMLInputSource; out SrcOut: TXMLCharSource);
  263. procedure SetOptions(AValue: TXMLReaderSettings);
  264. procedure SetNametable(ANameTable: THashTable);
  265. public
  266. constructor Create(var AFile: Text; ANameTable: THashTable); overload;
  267. constructor Create(AStream: TStream; const ABaseUri: XMLString; ANameTable: THashTable); overload;
  268. constructor Create(AStream: TStream; const ABaseUri: XMLString; ASettings: TXMLReaderSettings); overload;
  269. constructor Create(ASrc: TXMLCharSource; AParent: TXMLTextReader); overload;
  270. constructor Create(const uri: XMLString; ASettings: TXMLReaderSettings); overload;
  271. constructor Create(ASrc: TXMLInputSource; ASettings: TXMLReaderSettings); overload;
  272. destructor Destroy; override;
  273. procedure AfterConstruction; override;
  274. property OnEntity: TEntityEvent read FOnEntity write FOnEntity;
  275. { stuff needed for TLoader }
  276. property Standalone: Boolean read FStandalone;
  277. property DtdSchemaInfo: TDTDModel read FDocType write FDocType;
  278. property XML11: Boolean write FXML11;
  279. property XMLVersion: TXMLVersion read GetXMLVersion;
  280. property XMLEncoding: XMLString read GetXMLEncoding;
  281. property IDMap: THashTable read FIDMap write FIDMap;
  282. property ExpandEntities: Boolean read FExpandEntities;
  283. property Validate: Boolean read FValidate;
  284. property PreserveWhitespace: Boolean read FPreserveWhitespace;
  285. property IgnoreComments: Boolean read FIgnoreComments;
  286. property FragmentMode: Boolean read FFragmentMode write SetFragmentMode;
  287. procedure ValidateCurrentNode;
  288. procedure ValidateIdRefs;
  289. procedure EntityToSource(AEntity: TEntityDecl; out Src: TXMLCharSource);
  290. procedure ParseDTD;
  291. end;
  292. procedure RegisterDecoder(Proc: TGetDecoderProc);
  293. implementation
  294. {$IFDEF FPC_DOTTEDUNITS}
  295. uses
  296. Fcl.UriParser;
  297. {$ELSE FPC_DOTTEDUNITS}
  298. uses
  299. UriParser;
  300. {$ENDIF FPC_DOTTEDUNITS}
  301. type
  302. TXMLDecodingSource = class(TXMLCharSource)
  303. private
  304. FCharBuf: PAnsiChar;
  305. FCharBufEnd: PAnsiChar;
  306. FBufStart: PWideChar;
  307. FDecoder: TDecoder;
  308. FHasBOM: Boolean;
  309. FFixedUCS2: string;
  310. FBufSize: Integer;
  311. FAssumeUTF16: Boolean;
  312. procedure DecodingError(const Msg: string);
  313. protected
  314. function Reload: Boolean; override;
  315. procedure FetchData; virtual;
  316. public
  317. procedure AfterConstruction; override;
  318. destructor Destroy; override;
  319. function SetEncoding(const AEncoding: string): Boolean; override;
  320. procedure NewLine; override;
  321. function SkipUntil(var ToFill: TWideCharBuf; const Delim: TSetOfChar;
  322. wsflag: PBoolean = nil): WideChar; override;
  323. procedure Initialize; override;
  324. end;
  325. { TXMLStreamInputSource }
  326. TXMLStreamInputSource = class(TXMLDecodingSource)
  327. private
  328. FAllocated: PAnsiChar;
  329. FStream: TStream;
  330. FCapacity: Integer;
  331. FOwnStream: Boolean;
  332. FEof: Boolean;
  333. public
  334. constructor Create(AStream: TStream; AOwnStream: Boolean; aAssumeUTF16 : Boolean = False);
  335. destructor Destroy; override;
  336. procedure FetchData; override;
  337. Property AssumeUTF16 : Boolean Read FAssumeUTF16;
  338. end;
  339. TXMLFileInputSource = class(TXMLDecodingSource)
  340. private
  341. FFile: ^Text;
  342. FString: string;
  343. FTmp: string;
  344. public
  345. constructor Create(var AFile: Text);
  346. procedure FetchData; override;
  347. end;
  348. PForwardRef = ^TForwardRef;
  349. TForwardRef = record
  350. Value: XMLString;
  351. Loc: TLocation;
  352. end;
  353. const
  354. PubidChars: TSetOfChar = [' ', #13, #10, 'a'..'z', 'A'..'Z', '0'..'9',
  355. '-', '''', '(', ')', '+', ',', '.', '/', ':', '=', '?', ';', '!', '*',
  356. '#', '@', '$', '_', '%'];
  357. NullLocation: TLocation = (Line: 0; LinePos: 0);
  358. { Decoders }
  359. var
  360. Decoders: array of TGetDecoderProc;
  361. procedure RegisterDecoder(Proc: TGetDecoderProc);
  362. var
  363. L: Integer;
  364. begin
  365. L := Length(Decoders);
  366. SetLength(Decoders, L+1);
  367. Decoders[L] := Proc;
  368. end;
  369. function FindDecoder(const AEncoding: string; out Decoder: TDecoder): Boolean;
  370. var
  371. I: Integer;
  372. begin
  373. Result := False;
  374. for I := 0 to High(Decoders) do
  375. if Decoders[I](AEncoding, Decoder) then
  376. begin
  377. Result := True;
  378. Exit;
  379. end;
  380. end;
  381. function Is_8859_1(const AEncoding: string): Boolean;
  382. begin
  383. Result := SameText(AEncoding, 'ISO-8859-1') or
  384. SameText(AEncoding, 'ISO_8859-1') or
  385. SameText(AEncoding, 'latin1') or
  386. SameText(AEncoding, 'iso-ir-100') or
  387. SameText(AEncoding, 'l1') or
  388. SameText(AEncoding, 'IBM819') or
  389. SameText(AEncoding, 'CP819') or
  390. SameText(AEncoding, 'csISOLatin1') or
  391. // This one is not in character-sets.txt, but was used in FPC documentation,
  392. // and still being used in fcl-registry package
  393. SameText(AEncoding, 'ISO8859-1');
  394. end;
  395. { TXMLCharSource }
  396. constructor TXMLCharSource.Create(const AData: XMLString);
  397. begin
  398. inherited Create;
  399. FLineNo := 1;
  400. FBuf := PWideChar(AData);
  401. FBufEnd := FBuf + Length(AData);
  402. LFPos := FBuf-1;
  403. FCharCount := Length(AData);
  404. end;
  405. procedure TXMLCharSource.Initialize;
  406. begin
  407. end;
  408. function TXMLCharSource.SetEncoding(const AEncoding: string): Boolean;
  409. begin
  410. Result := True; // always succeed
  411. end;
  412. function TXMLCharSource.GetSourceURI: XMLString;
  413. begin
  414. if FSourceURI <> '' then
  415. Result := FSourceURI
  416. else if Assigned(FParent) then
  417. Result := FParent.SourceURI
  418. else
  419. Result := '';
  420. end;
  421. function TXMLCharSource.Reload: Boolean;
  422. begin
  423. Result := False;
  424. end;
  425. procedure TXMLCharSource.NewLine;
  426. begin
  427. Inc(FLineNo);
  428. LFPos := FBuf;
  429. end;
  430. function TXMLCharSource.SkipUntil(var ToFill: TWideCharBuf; const Delim: TSetOfChar;
  431. wsflag: PBoolean): WideChar;
  432. var
  433. old: PWideChar;
  434. nonws: Boolean;
  435. begin
  436. old := FBuf;
  437. nonws := False;
  438. repeat
  439. if FBuf^ = #10 then
  440. NewLine;
  441. if (FBuf^ < #255) and (AnsiChar(ord(FBuf^)) in Delim) then
  442. Break;
  443. if (FBuf^ > #32) or not (AnsiChar(ord(FBuf^)) in [#32, #9, #10, #13]) then
  444. nonws := True;
  445. Inc(FBuf);
  446. until False;
  447. Result := FBuf^;
  448. BufAppendChunk(ToFill, old, FBuf);
  449. if Assigned(wsflag) then
  450. wsflag^ := wsflag^ or nonws;
  451. end;
  452. function TXMLCharSource.Matches(const arg: XMLString): Boolean;
  453. begin
  454. Result := False;
  455. if (FBufEnd >= FBuf + Length(arg)) or Reload then
  456. Result := CompareMem(Pointer(arg), FBuf, Length(arg)*sizeof(WideChar));
  457. if Result then
  458. begin
  459. Inc(FBuf, Length(arg));
  460. if FBuf >= FBufEnd then
  461. Reload;
  462. end;
  463. end;
  464. { Used to check element name in end-tags, difference from Matches is that
  465. buffer may be reloaded more than once. XML has no restriction on name
  466. length, so a name longer than input buffer may be encountered. }
  467. function TXMLCharSource.MatchesLong(const arg: XMLString): Boolean;
  468. var
  469. idx, len, chunk: Integer;
  470. begin
  471. Result := False;
  472. idx := 1;
  473. len := Length(arg);
  474. repeat
  475. if (FBuf >= FBufEnd) and not Reload then
  476. Exit;
  477. if FBufEnd >= FBuf + len then
  478. chunk := len
  479. else
  480. chunk := FBufEnd - FBuf;
  481. if not CompareMem(@arg[idx], FBuf, chunk*sizeof(WideChar)) then
  482. Exit;
  483. Inc(FBuf, chunk);
  484. Inc(idx,chunk);
  485. Dec(len,chunk);
  486. until len = 0;
  487. Result := True;
  488. if FBuf >= FBufEnd then
  489. Reload;
  490. end;
  491. { TXMLDecodingSource }
  492. procedure TXMLDecodingSource.AfterConstruction;
  493. begin
  494. inherited AfterConstruction;
  495. FBufStart := AllocMem(4096);
  496. FBuf := FBufStart;
  497. FBufEnd := FBuf;
  498. LFPos := FBuf-1;
  499. end;
  500. destructor TXMLDecodingSource.Destroy;
  501. begin
  502. FreeMem(FBufStart);
  503. if Assigned(FDecoder.Cleanup) then
  504. FDecoder.Cleanup(FDecoder.Context);
  505. inherited Destroy;
  506. end;
  507. procedure TXMLDecodingSource.FetchData;
  508. begin
  509. end;
  510. procedure TXMLDecodingSource.DecodingError(const Msg: string);
  511. begin
  512. // count line endings to obtain correct error location
  513. while FBuf < FBufEnd do
  514. begin
  515. if (FBuf^ = #10) or (FBuf^ = #13) or (FXML11Rules and ((FBuf^ = #$85) or (FBuf^ = #$2028))) then
  516. begin
  517. if (FBuf^ = #13) and (FBuf < FBufEnd-1) and
  518. ((FBuf[1] = #10) or (FXML11Rules and (FBuf[1] = #$85))) then
  519. Inc(FBuf);
  520. LFPos := FBuf;
  521. Inc(FLineNo);
  522. end;
  523. Inc(FBuf);
  524. end;
  525. FReader.FatalError(Msg);
  526. end;
  527. function TXMLDecodingSource.Reload: Boolean;
  528. var
  529. Remainder: PtrInt;
  530. r, inLeft: Cardinal;
  531. rslt: Integer;
  532. begin
  533. if Kind = skInternalSubset then
  534. FReader.DTDReloadHook;
  535. Remainder := FBufEnd - FBuf;
  536. if Remainder > 0 then
  537. Move(FBuf^, FBufStart^, Remainder * sizeof(WideChar));
  538. Dec(LFPos, FBuf-FBufStart);
  539. FBuf := FBufStart;
  540. FBufEnd := FBufStart + Remainder;
  541. repeat
  542. inLeft := FCharBufEnd - FCharBuf;
  543. if inLeft < 4 then // may contain an incomplete AnsiChar
  544. begin
  545. FetchData;
  546. inLeft := FCharBufEnd - FCharBuf;
  547. if inLeft <= 0 then
  548. Break;
  549. end;
  550. r := FBufStart + FBufSize - FBufEnd;
  551. if r = 0 then
  552. Break;
  553. rslt := FDecoder.Decode(FDecoder.Context, FCharBuf, inLeft, FBufEnd, r);
  554. { Sanity checks: r and inLeft must not increase. }
  555. if inLeft + FCharBuf <= FCharBufEnd then
  556. FCharBuf := FCharBufEnd - inLeft
  557. else
  558. DecodingError('Decoder error: input byte count out of bounds');
  559. if r + FBufEnd <= FBufStart + FBufSize then
  560. FBufEnd := FBufStart + FBufSize - r
  561. else
  562. DecodingError('Decoder error: output AnsiChar count out of bounds');
  563. if rslt = 0 then
  564. Break
  565. else if rslt < 0 then
  566. DecodingError('Invalid character in input stream')
  567. else
  568. FReader.CheckMaxChars(rslt);
  569. until False;
  570. FBufEnd^ := #0;
  571. Result := FBuf < FBufEnd;
  572. end;
  573. const
  574. XmlSign: array [0..4] of WideChar = ('<', '?', 'x', 'm', 'l');
  575. procedure TXMLDecodingSource.Initialize;
  576. begin
  577. inherited;
  578. FLineNo := 1;
  579. if FAssumeUTF16 then
  580. begin
  581. FFixedUCS2 := {$IFNDEF ENDIAN_BIG} 'UTF-16BE' {$ELSE} 'UTF-16LE' {$ENDIF};
  582. FDecoder.Decode := @Decode_UCS2;
  583. end
  584. else
  585. FDecoder.Decode := @Decode_UTF8;
  586. FFixedUCS2 := '';
  587. if FCharBufEnd-FCharBuf > 1 then
  588. begin
  589. if (FCharBuf[0] = #$FE) and (FCharBuf[1] = #$FF) then
  590. begin
  591. FFixedUCS2 := 'UTF-16BE';
  592. FDecoder.Decode := {$IFNDEF ENDIAN_BIG} @Decode_UCS2_Swapped {$ELSE} @Decode_UCS2 {$ENDIF};
  593. end
  594. else if (FCharBuf[0] = #$FF) and (FCharBuf[1] = #$FE) then
  595. begin
  596. FFixedUCS2 := 'UTF-16LE';
  597. FDecoder.Decode := {$IFDEF ENDIAN_BIG} @Decode_UCS2_Swapped {$ELSE} @Decode_UCS2 {$ENDIF};
  598. end;
  599. end;
  600. FBufSize := 6; // possible BOM and '<?xml'
  601. Reload;
  602. if FBuf^ = #$FEFF then
  603. begin
  604. FHasBOM := True;
  605. Inc(FBuf);
  606. end;
  607. LFPos := FBuf-1;
  608. if CompareMem(FBuf, @XmlSign[0], sizeof(XmlSign)) then
  609. begin
  610. FBufSize := 3; // don't decode past XML declaration
  611. Inc(FBuf, Length(XmlSign));
  612. FReader.ParseXmlOrTextDecl((FParent <> nil) or (FReader.FState <> rsProlog));
  613. end;
  614. FBufSize := 2047;
  615. if FReader.FXML11 then
  616. FXml11Rules := True;
  617. end;
  618. function TXMLDecodingSource.SetEncoding(const AEncoding: string): Boolean;
  619. var
  620. NewDecoder: TDecoder;
  621. begin
  622. Result := True;
  623. if (FFixedUCS2 = '') and SameText(AEncoding, 'UTF-8') then
  624. Exit;
  625. if FFixedUCS2 <> '' then
  626. begin
  627. Result := SameText(AEncoding, FFixedUCS2) or
  628. SameText(AEncoding, 'UTF-16') or
  629. SameText(AEncoding, 'unicode');
  630. Exit;
  631. end;
  632. // TODO: must fail when a byte-based stream is labeled as word-based.
  633. // see rmt-e2e-61, it now fails but for a completely different reason.
  634. FillChar(NewDecoder, sizeof(TDecoder), 0);
  635. if Is_8859_1(AEncoding) then
  636. FDecoder.Decode := @Decode_8859_1
  637. else if FindDecoder(AEncoding, NewDecoder) then
  638. FDecoder := NewDecoder
  639. else
  640. Result := False;
  641. end;
  642. procedure TXMLDecodingSource.NewLine;
  643. begin
  644. case FBuf^ of
  645. #10: ;
  646. #13: begin
  647. // Reload trashes the buffer, it should be consumed beforehand
  648. if (FBufEnd >= FBuf+2) or Reload then
  649. begin
  650. if (FBuf[1] = #10) or (FXML11Rules and (FBuf[1] = #$85)) then
  651. Inc(FBuf);
  652. end;
  653. FBuf^ := #10;
  654. end;
  655. #$85, #$2028: if FXML11Rules then
  656. FBuf^ := #10
  657. else
  658. Exit;
  659. else
  660. Exit;
  661. end;
  662. Inc(FLineNo);
  663. LFPos := FBuf;
  664. end;
  665. { TXMLStreamInputSource }
  666. const
  667. Slack = 16;
  668. constructor TXMLStreamInputSource.Create(AStream: TStream; AOwnStream: Boolean; aAssumeUTF16 : Boolean = False);
  669. begin
  670. FStream := AStream;
  671. FCapacity := 4096;
  672. GetMem(FAllocated, FCapacity+Slack);
  673. FCharBuf := FAllocated+(Slack-4);
  674. FCharBufEnd := FCharBuf;
  675. FOwnStream := AOwnStream;
  676. FetchData;
  677. FAssumeUTF16:=aAssumeUTF16;
  678. end;
  679. destructor TXMLStreamInputSource.Destroy;
  680. begin
  681. FreeMem(FAllocated);
  682. if FOwnStream then
  683. FStream.Free;
  684. inherited Destroy;
  685. end;
  686. procedure TXMLStreamInputSource.FetchData;
  687. var
  688. Remainder, BytesRead: Integer;
  689. OldBuf: PAnsiChar;
  690. begin
  691. Assert(FCharBufEnd - FCharBuf < Slack-4);
  692. if FEof then
  693. Exit;
  694. OldBuf := FCharBuf;
  695. Remainder := FCharBufEnd - FCharBuf;
  696. if Remainder < 0 then
  697. Remainder := 0;
  698. FCharBuf := FAllocated+Slack-4-Remainder;
  699. if Remainder > 0 then
  700. Move(OldBuf^, FCharBuf^, Remainder);
  701. BytesRead := FStream.Read(FAllocated[Slack-4], FCapacity);
  702. if BytesRead < FCapacity then
  703. FEof := True;
  704. FCharBufEnd := FAllocated + (Slack-4) + BytesRead;
  705. { Null-termination has been removed:
  706. 1) Built-in decoders don't need it because they respect the buffer length.
  707. 2) It was causing unaligned access errors on ARM CPUs.
  708. }
  709. //PWideChar(FCharBufEnd)^ := #0;
  710. end;
  711. { TXMLFileInputSource }
  712. constructor TXMLFileInputSource.Create(var AFile: Text);
  713. begin
  714. FFile := @AFile;
  715. SourceURI := FilenameToURI(TTextRec(AFile).Name);
  716. FetchData;
  717. end;
  718. procedure TXMLFileInputSource.FetchData;
  719. var
  720. Remainder: Integer;
  721. begin
  722. if not Eof(FFile^) then
  723. begin
  724. Remainder := FCharBufEnd - FCharBuf;
  725. if Remainder > 0 then
  726. SetString(FTmp, FCharBuf, Remainder);
  727. ReadLn(FFile^, FString);
  728. FString := FString + #10; // bad solution...
  729. if Remainder > 0 then
  730. Insert(FTmp, FString, 1);
  731. FCharBuf := PAnsiChar(FString);
  732. FCharBufEnd := FCharBuf + Length(FString);
  733. end;
  734. end;
  735. { helper that closes handle upon destruction }
  736. type
  737. THandleOwnerStream = class(THandleStream)
  738. public
  739. destructor Destroy; override;
  740. end;
  741. destructor THandleOwnerStream.Destroy;
  742. begin
  743. FileClose(Handle);
  744. inherited Destroy;
  745. end;
  746. { TXMLTextReader }
  747. function TXMLTextReader.QueryInterface(constref iid: TGUID; out obj): HRESULT; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  748. begin
  749. if GetInterface(iid,obj) then
  750. result := S_OK
  751. else
  752. result:= E_NOINTERFACE;
  753. end;
  754. function TXMLTextReader._AddRef: Longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  755. begin
  756. result := -1;
  757. end;
  758. function TXMLTextReader._Release: Longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  759. begin
  760. result := -1;
  761. end;
  762. procedure TXMLTextReader.ConvertSource(SrcIn: TXMLInputSource; out SrcOut: TXMLCharSource);
  763. begin
  764. SrcOut := nil;
  765. if Assigned(SrcIn) then
  766. begin
  767. Case SrcIn.InputSourceType of
  768. istStream:
  769. SrcOut := TXMLStreamInputSource.Create(SrcIn.Stream, False);
  770. istAnsi:
  771. SrcOut := TXMLStreamInputSource.Create(TStringStream.Create(SrcIn.AnsiStringData), True, False);
  772. istUnicode:
  773. SrcOut := TXMLStreamInputSource.Create(TStringStream.Create(SrcIn.UnicodeStringData,TEncoding.Unicode), True, True);
  774. istSystemID:
  775. ResolveResource(SrcIn.SystemID, SrcIn.PublicID, SrcIn.BaseURI, SrcOut);
  776. end;
  777. end;
  778. if (SrcOut = nil) and (FSource = nil) then
  779. DoErrorPos(esFatal, 'No input source specified', NullLocation);
  780. end;
  781. procedure TXMLTextReader.StoreLocation(out Loc: TLocation);
  782. begin
  783. Loc.Line := FSource.FLineNo;
  784. Loc.LinePos := FSource.FBuf-FSource.LFPos;
  785. end;
  786. function TXMLTextReader.ResolveResource(const ASystemID, APublicID, ABaseURI: XMLString; out Source: TXMLCharSource): Boolean;
  787. var
  788. SrcURI: XMLString;
  789. Filename: string;
  790. Stream: TStream;
  791. fd: THandle;
  792. begin
  793. Source := nil;
  794. Result := False;
  795. if not ResolveRelativeURI(ABaseURI, ASystemID, SrcURI) then
  796. Exit;
  797. { TODO: alternative resolvers
  798. These may be 'internal' resolvers or a handler set by application.
  799. Internal resolvers should probably produce a TStream
  800. ( so that internal classes need not be exported ).
  801. External resolver will produce TXMLInputSource that should be converted.
  802. External resolver must NOT be called for root entity.
  803. External resolver can return nil, in which case we do the default }
  804. if URIToFilename(SrcURI, Filename) then
  805. begin
  806. fd := FileOpen(Filename, fmOpenRead + fmShareDenyWrite);
  807. if fd <> THandle(-1) then
  808. begin
  809. Stream := THandleOwnerStream.Create(fd);
  810. Source := TXMLStreamInputSource.Create(Stream, True, False);
  811. Source.SourceURI := SrcURI;
  812. end;
  813. end;
  814. Result := Assigned(Source);
  815. end;
  816. procedure TXMLTextReader.SetSource(ASource: TXMLCharSource);
  817. begin
  818. ASource.FParent := FSource;
  819. FSource := ASource;
  820. FSource.FReader := Self;
  821. FSource.FStartNesting := FNesting;
  822. end;
  823. procedure TXMLTextReader.FatalError(Expected: WideChar);
  824. begin
  825. // FIX: don't output what is found - anything may be found, including exploits...
  826. FatalError('Expected "%1s"', [string(Expected)]);
  827. end;
  828. procedure TXMLTextReader.FatalError(const descr: String; LineOffs: Integer);
  829. begin
  830. DoError(esFatal, descr, LineOffs);
  831. end;
  832. procedure TXMLTextReader.FatalError(const descr: string; const args: array of const; LineOffs: Integer);
  833. begin
  834. DoError(esFatal, Format(descr, args), LineOffs);
  835. end;
  836. procedure TXMLTextReader.ValidationError(const Msg: string; const Args: array of const; LineOffs: Integer);
  837. begin
  838. if FValidate then
  839. DoError(esError, Format(Msg, Args), LineOffs);
  840. end;
  841. procedure TXMLTextReader.ValidationErrorWithName(const Msg: string; LineOffs: Integer);
  842. var
  843. ws: XMLString;
  844. begin
  845. SetString(ws, FName.Buffer, FName.Length);
  846. ValidationError(Msg, [ws], LineOffs);
  847. end;
  848. procedure TXMLTextReader.DoError(Severity: TErrorSeverity; const descr: string; LineOffs: Integer);
  849. var
  850. Loc: TLocation;
  851. begin
  852. StoreLocation(Loc);
  853. if LineOffs >= 0 then
  854. begin
  855. Dec(Loc.LinePos, LineOffs);
  856. DoErrorPos(Severity, descr, Loc);
  857. end
  858. else
  859. DoErrorPos(Severity, descr, FTokenStart);
  860. end;
  861. procedure TXMLTextReader.DoErrorPos(Severity: TErrorSeverity; const descr: string;
  862. const args: array of const; const ErrPos: TLocation);
  863. begin
  864. DoErrorPos(Severity, Format(descr, args), ErrPos);
  865. end;
  866. procedure TXMLTextReader.DoErrorPos(Severity: TErrorSeverity; const descr: string; const ErrPos: TLocation);
  867. var
  868. E: EXMLReadError;
  869. srcuri: XMLString;
  870. begin
  871. if Assigned(FSource) then
  872. begin
  873. srcuri := FSource.FSourceURI;
  874. if (srcuri = '') and Assigned(FSource.FEntity) then
  875. srcuri := FSource.FEntity.FURI;
  876. E := EXMLReadError.Create(severity, descr, ErrPos.Line, ErrPos.LinePos, srcuri);
  877. end
  878. else
  879. E := EXMLReadError.Create(descr);
  880. CallErrorHandler(E);
  881. // No 'finally'! If user handler raises exception, control should not get here
  882. // and the exception will be freed in CallErrorHandler (below)
  883. E.Free;
  884. end;
  885. procedure TXMLTextReader.CheckMaxChars(ToAdd: Cardinal);
  886. var
  887. src: TXMLCharSource;
  888. total: Cardinal;
  889. begin
  890. Inc(FSource.FCharCount, ToAdd);
  891. if FMaxChars = 0 then
  892. Exit;
  893. src := FSource;
  894. total := 0;
  895. repeat
  896. Inc(total, src.FCharCount);
  897. if total > FMaxChars then
  898. FatalError('Exceeded character count limit');
  899. src := src.FParent;
  900. until src = nil;
  901. end;
  902. procedure TXMLTextReader.CallErrorHandler(E: EXMLReadError);
  903. begin
  904. try
  905. if Assigned(FOnError) then
  906. FOnError(E);
  907. if E.Severity = esFatal then
  908. raise E;
  909. except
  910. FReadState := rsError;
  911. if ExceptObject <> E then
  912. E.Free;
  913. raise;
  914. end;
  915. end;
  916. function TXMLTextReader.SkipWhitespace(PercentAloneIsOk: Boolean): Boolean;
  917. begin
  918. Result := False;
  919. repeat
  920. Result := SkipS or Result;
  921. if FSource.FBuf >= FSource.FBufEnd then
  922. begin
  923. Result := True; // report whitespace upon exiting the PE
  924. if not ContextPop then
  925. Break;
  926. end
  927. else if FSource.FBuf^ = '%' then
  928. begin
  929. if (FState <> rsDTD) then
  930. Break;
  931. // This is the only case where look-ahead is needed
  932. if FSource.FBuf > FSource.FBufEnd-2 then
  933. FSource.Reload;
  934. if (not PercentAloneIsOk) or (Byte(FSource.FBuf[1]) in NamingBitmap[NamePages[hi(Word(FSource.FBuf[1]))]]) or
  935. ((FSource.FBuf[1] >= #$D800) and (FSource.FBuf[1] <= #$DB7F)) then
  936. begin
  937. StartPE;
  938. Result := True; // report whitespace upon entering the PE
  939. end
  940. else Break;
  941. end
  942. else
  943. Break;
  944. until False;
  945. end;
  946. procedure TXMLTextReader.ExpectWhitespace;
  947. begin
  948. if not SkipWhitespace then
  949. FatalError('Expected whitespace');
  950. end;
  951. function TXMLTextReader.SkipS(Required: Boolean): Boolean;
  952. var
  953. p: PWideChar;
  954. begin
  955. Result := False;
  956. repeat
  957. p := FSource.FBuf;
  958. repeat
  959. if (p^ = #10) or (p^ = #13) or (FXML11 and ((p^ = #$85) or (p^ = #$2028))) then
  960. begin
  961. FSource.FBuf := p;
  962. FSource.NewLine;
  963. p := FSource.FBuf;
  964. end
  965. else if (p^ <> #32) and (p^ <> #9) then
  966. Break;
  967. Inc(p);
  968. Result := True;
  969. until False;
  970. FSource.FBuf := p;
  971. until (FSource.FBuf < FSource.FBufEnd) or (not FSource.Reload);
  972. if (not Result) and Required then
  973. FatalError('Expected whitespace');
  974. end;
  975. procedure TXMLTextReader.ExpectString(const s: String);
  976. var
  977. I: Integer;
  978. begin
  979. for I := 1 to Length(s) do
  980. begin
  981. if FSource.FBuf^ <> WideChar(ord(s[i])) then
  982. FatalError('Expected "%s"', [s], i-1);
  983. FSource.NextChar;
  984. end;
  985. end;
  986. function TXMLTextReader.CheckForChar(c: WideChar): Boolean;
  987. begin
  988. Result := (FSource.FBuf^ = c);
  989. if Result then
  990. begin
  991. Inc(FSource.FBuf);
  992. if FSource.FBuf >= FSource.FBufEnd then
  993. FSource.Reload;
  994. end;
  995. end;
  996. procedure TXMLTextReader.SkipQuote(out Delim: WideChar; required: Boolean);
  997. begin
  998. Delim := #0;
  999. if (FSource.FBuf^ = '''') or (FSource.FBuf^ = '"') then
  1000. begin
  1001. Delim := FSource.FBuf^;
  1002. FSource.NextChar; // skip quote
  1003. StoreLocation(FTokenStart);
  1004. end
  1005. else if required then
  1006. FatalError('Expected single or double quote');
  1007. end;
  1008. const
  1009. PrefixDefault: array[0..4] of WideChar = ('x','m','l','n','s');
  1010. procedure TXMLTextReader.SetOptions(AValue: TXMLReaderSettings);
  1011. begin
  1012. FValidate := AValue.Validate;
  1013. FPreserveWhitespace := AValue.PreserveWhitespace;
  1014. FExpandEntities := AValue.ExpandEntities;
  1015. FCDSectionsAsText := AValue.CDSectionsAsText;
  1016. FIgnoreComments := AValue.IgnoreComments;
  1017. FNamespaces := AValue.Namespaces;
  1018. FDisallowDoctype := AValue.DisallowDoctype;
  1019. FCanonical := AValue.CanonicalForm;
  1020. FMaxChars := AValue.MaxChars;
  1021. FOnError := AValue.OnError;
  1022. SetFragmentMode(AValue.ConformanceLevel = clFragment);
  1023. end;
  1024. procedure TXMLTextReader.SetFragmentMode(aValue: Boolean);
  1025. begin
  1026. FFragmentMode := aValue;
  1027. if FFragmentMode then
  1028. FState := rsRoot
  1029. else
  1030. FState := rsProlog;
  1031. end;
  1032. constructor TXMLTextReader.Create(ASrc: TXMLInputSource; ASettings: TXMLReaderSettings);
  1033. var
  1034. InputSrc: TXMLCharSource;
  1035. begin
  1036. SetNametable(ASettings.NameTable);
  1037. SetOptions(ASettings);
  1038. ConvertSource(ASrc, InputSrc);
  1039. FSource := InputSrc;
  1040. FSource.FReader := Self;
  1041. end;
  1042. constructor TXMLTextReader.Create(const uri: XMLString; ASettings: TXMLReaderSettings);
  1043. begin
  1044. SetNametable(ASettings.NameTable);
  1045. SetOptions(ASettings);
  1046. if ResolveResource(uri, '', '', FSource) then
  1047. FSource.FReader := Self
  1048. else
  1049. DoErrorPos(esFatal, 'The specified URI could not be resolved', NullLocation);
  1050. end;
  1051. procedure TXMLTextReader.SetNametable(ANameTable: THashTable);
  1052. begin
  1053. if ANameTable = nil then
  1054. begin
  1055. ANameTable := THashTable.Create(256, True);
  1056. FNameTableOwned := True;
  1057. end;
  1058. FNameTable := ANameTable;
  1059. end;
  1060. constructor TXMLTextReader.Create(var AFile: Text; ANameTable: THashTable);
  1061. begin
  1062. SetNametable(ANameTable);
  1063. FSource := TXMLFileInputSource.Create(AFile);
  1064. FSource.FReader := Self;
  1065. end;
  1066. constructor TXMLTextReader.Create(AStream: TStream; const ABaseUri: XMLString; ANameTable: THashTable);
  1067. begin
  1068. SetNametable(ANameTable);
  1069. FSource := TXMLStreamInputSource.Create(AStream, False);
  1070. FSource.SourceURI := ABaseUri;
  1071. FSource.FReader := Self;
  1072. end;
  1073. constructor TXMLTextReader.Create(AStream: TStream; const ABaseUri: XMLString; ASettings: TXMLReaderSettings); overload;
  1074. begin
  1075. SetNametable(ASettings.NameTable);
  1076. SetOptions(ASettings);
  1077. FSource := TXMLStreamInputSource.Create(AStream, False);
  1078. FSource.SourceURI := ABaseUri;
  1079. FSource.FReader := Self;
  1080. end;
  1081. constructor TXMLTextReader.Create(ASrc: TXMLCharSource; AParent: TXMLTextReader);
  1082. begin
  1083. FNameTable := AParent.FNameTable;
  1084. FSource := ASrc;
  1085. FSource.FReader := Self;
  1086. FValidate := AParent.FValidate;
  1087. FPreserveWhitespace := AParent.FPreserveWhitespace;
  1088. FExpandEntities := AParent.FExpandEntities;
  1089. FCDSectionsAsText := AParent.FCDSectionsAsText;
  1090. FIgnoreComments := AParent.FIgnoreComments;
  1091. FNamespaces := AParent.FNamespaces;
  1092. FDisallowDoctype := AParent.FDisallowDoctype;
  1093. FCanonical := AParent.FCanonical;
  1094. FMaxChars := AParent.FMaxChars;
  1095. FOnError := AParent.FOnError;
  1096. end;
  1097. destructor TXMLTextReader.Destroy;
  1098. var
  1099. cur: PNodeData;
  1100. begin
  1101. if FAttrCleanupFlag then
  1102. CleanupAttributes;
  1103. while Assigned(FFreeAttrChunk) do
  1104. begin
  1105. cur := FFreeAttrChunk;
  1106. FFreeAttrChunk := cur^.FNext;
  1107. Dispose(cur);
  1108. end;
  1109. if Assigned(FEntityValue.Buffer) then
  1110. FreeMem(FEntityValue.Buffer);
  1111. FreeMem(FName.Buffer);
  1112. FreeMem(FValue.Buffer);
  1113. if Assigned(FSource) then
  1114. while ContextPop(True) do; // clean input stack
  1115. FSource.Free;
  1116. FPEMap.Free;
  1117. ClearForwardRefs;
  1118. FNsAttHash.Free;
  1119. FNSHelper.Free;
  1120. FDocType.Release;
  1121. FIDMap.Free;
  1122. FForwardRefs.Free;
  1123. if FNameTableOwned then
  1124. FNameTable.Free;
  1125. inherited Destroy;
  1126. end;
  1127. procedure TXMLTextReader.AfterConstruction;
  1128. begin
  1129. BufAllocate(FName, 128);
  1130. BufAllocate(FValue, 512);
  1131. SetLength(FNodeStack, 16);
  1132. SetLength(FValidators, 16);
  1133. FNesting := 0;
  1134. FValidatorNesting := 0;
  1135. FCurrNode := @FNodeStack[0];
  1136. FCurrAttrIndex := -1;
  1137. FEmptyStr := FNameTable.FindOrAdd('');
  1138. if FNamespaces then
  1139. begin
  1140. FNSHelper := TNSSupport.Create(FNameTable);
  1141. FNsAttHash := TDblHashArray.Create;
  1142. FStdPrefix_xml := FNSHelper.GetPrefix(@PrefixDefault, 3);
  1143. FStdPrefix_xmlns := FNSHelper.GetPrefix(@PrefixDefault, 5);
  1144. FStdUri_xmlns := FNameTable.FindOrAdd(stduri_xmlns);
  1145. FStdUri_xml := FNameTable.FindOrAdd(stduri_xml);
  1146. end;
  1147. end;
  1148. function TXMLTextReader.CheckName(aFlags: TCheckNameFlags): Boolean;
  1149. var
  1150. p: PWideChar;
  1151. NameStartFlag: Boolean;
  1152. begin
  1153. p := FSource.FBuf;
  1154. FName.Length := 0;
  1155. FColonPos := -1;
  1156. NameStartFlag := not (cnToken in aFlags);
  1157. repeat
  1158. if NameStartFlag then
  1159. begin
  1160. if (Byte(p^) in NamingBitmap[NamePages[hi(Word(p^))]]) or
  1161. ((p^ = ':') and (not FNamespaces)) then
  1162. Inc(p)
  1163. else if ((p^ >= #$D800) and (p^ <= #$DB7F) and
  1164. (p[1] >= #$DC00) and (p[1] <= #$DFFF)) then
  1165. Inc(p, 2)
  1166. else
  1167. begin
  1168. // here we come either when first AnsiChar of name is bad (it may be a colon),
  1169. // or when a colon is not followed by a valid NameStartChar
  1170. FSource.FBuf := p;
  1171. Result := False;
  1172. Break;
  1173. end;
  1174. NameStartFlag := False;
  1175. end;
  1176. repeat
  1177. if (Byte(p^) in NamingBitmap[NamePages[$100+hi(Word(p^))]]) or
  1178. ((p^= ':') and ((cnToken in aFlags) or not FNamespaces)) then
  1179. Inc(p)
  1180. else if ((p^ >= #$D800) and (p^ <= #$DB7F) and
  1181. (p[1] >= #$DC00) and (p[1] <= #$DFFF)) then
  1182. Inc(p,2)
  1183. else
  1184. Break;
  1185. until False;
  1186. if (p^ = ':') and (FColonPos < 0) then
  1187. begin
  1188. FColonPos := p-FSource.FBuf+FName.Length;
  1189. NameStartFlag := True;
  1190. Inc(p);
  1191. if p < FSource.FBufEnd then Continue;
  1192. end;
  1193. BufAppendChunk(FName, FSource.FBuf, p);
  1194. Result := (FName.Length > 0);
  1195. FSource.FBuf := p;
  1196. if (p < FSource.FBufEnd) or not FSource.Reload then
  1197. Break;
  1198. p := FSource.FBuf;
  1199. until False;
  1200. if not (Result or (cnOptional in aFlags)) then
  1201. RaiseNameNotFound;
  1202. end;
  1203. procedure TXMLTextReader.CheckNCName;
  1204. begin
  1205. if FNamespaces and (FColonPos <> -1) then
  1206. FatalError('Names of entities, notations and processing instructions may not contain colons', FName.Length);
  1207. end;
  1208. procedure TXMLTextReader.RaiseNameNotFound;
  1209. begin
  1210. if FColonPos <> -1 then
  1211. FatalError('Bad QName syntax, local part is missing')
  1212. else
  1213. // Coming at no cost, this allows more user-friendly error messages
  1214. with FSource do
  1215. if (FBuf^ = #32) or (FBuf^ = #10) or (FBuf^ = #9) or (FBuf^ = #13) then
  1216. FatalError('Whitespace is not allowed here')
  1217. else
  1218. FatalError('Name starts with invalid character');
  1219. end;
  1220. function TXMLTextReader.ResolvePredefined: Boolean;
  1221. var
  1222. wc: WideChar;
  1223. begin
  1224. Result := False;
  1225. with FName do
  1226. begin
  1227. if (Length = 2) and (Buffer[1] = 't') then
  1228. begin
  1229. if Buffer[0] = 'l' then
  1230. wc := '<'
  1231. else if Buffer[0] = 'g' then
  1232. wc := '>'
  1233. else Exit;
  1234. end
  1235. else if Buffer[0] = 'a' then
  1236. begin
  1237. if (Length = 3) and (Buffer[1] = 'm') and (Buffer[2] = 'p') then
  1238. wc := '&'
  1239. else if (Length = 4) and (Buffer[1] = 'p') and (Buffer[2] = 'o') and
  1240. (Buffer[3] = 's') then
  1241. wc := ''''
  1242. else Exit;
  1243. end
  1244. else if (Length = 4) and (Buffer[0] = 'q') and (Buffer[1] = 'u') and
  1245. (Buffer[2] = 'o') and (Buffer[3] ='t') then
  1246. wc := '"'
  1247. else
  1248. Exit;
  1249. end; // with
  1250. BufAppend(FValue, wc);
  1251. Result := True;
  1252. end;
  1253. function TXMLTextReader.ParseRef(var ToFill: TWideCharBuf): Boolean; // [67]
  1254. var
  1255. Code: Integer;
  1256. begin
  1257. FSource.NextChar; // skip '&'
  1258. Result := CheckForChar('#');
  1259. if Result then
  1260. begin
  1261. Code := 0;
  1262. if CheckForChar('x') then
  1263. repeat
  1264. case FSource.FBuf^ of
  1265. '0'..'9': Code := Code * 16 + Ord(FSource.FBuf^) - Ord('0');
  1266. 'a'..'f': Code := Code * 16 + Ord(FSource.FBuf^) - (Ord('a') - 10);
  1267. 'A'..'F': Code := Code * 16 + Ord(FSource.FBuf^) - (Ord('A') - 10);
  1268. else
  1269. Break;
  1270. end;
  1271. FSource.NextChar;
  1272. until Code > $10FFFF
  1273. else
  1274. repeat
  1275. case FSource.FBuf^ of
  1276. '0'..'9': Code := Code * 10 + Ord(FSource.FBuf^) - Ord('0');
  1277. else
  1278. Break;
  1279. end;
  1280. FSource.NextChar;
  1281. until Code > $10FFFF;
  1282. case Code of
  1283. $01..$08, $0B..$0C, $0E..$1F:
  1284. if FXML11 then
  1285. BufAppend(ToFill, WideChar(Code))
  1286. else
  1287. FatalError('Invalid character reference');
  1288. $09, $0A, $0D, $20..$D7FF, $E000..$FFFD:
  1289. BufAppend(ToFill, WideChar(Code));
  1290. $10000..$10FFFF:
  1291. begin
  1292. BufAppend(ToFill, WideChar($D7C0 + (Code shr 10)));
  1293. BufAppend(ToFill, WideChar($DC00 xor (Code and $3FF)));
  1294. end;
  1295. else
  1296. FatalError('Invalid character reference');
  1297. end;
  1298. end
  1299. else CheckName;
  1300. ExpectChar(';');
  1301. end;
  1302. const
  1303. AttrDelims: TSetOfChar = [#0, '<', '&', '''', '"', #9, #10, #13];
  1304. GT_Delim: TSetOfChar = [#0, '>'];
  1305. { Parse attribute literal, producing plain string value in AttrData.FValueStr.
  1306. If entity references are encountered and FExpandEntities=False, also builds
  1307. a node chain starting from AttrData.FNext. Node chain is built only for the
  1308. first level. If NonCDATA=True, additionally normalizes whitespace in string value. }
  1309. procedure TXMLTextReader.ExpectAttValue(AttrData: PNodeData; NonCDATA: Boolean);
  1310. var
  1311. wc: WideChar;
  1312. Delim: WideChar;
  1313. ent: TEntityDecl;
  1314. start: TObject;
  1315. curr: PNodeData;
  1316. StartPos: Integer;
  1317. StartLoc: TLocation;
  1318. entName: PHashItem;
  1319. begin
  1320. SkipQuote(Delim);
  1321. AttrData^.FLoc2 := FTokenStart;
  1322. StartLoc := FTokenStart;
  1323. curr := AttrData;
  1324. FValue.Length := 0;
  1325. StartPos := 0;
  1326. start := FSource.FEntity;
  1327. repeat
  1328. wc := FSource.SkipUntil(FValue, AttrDelims);
  1329. if wc = '<' then
  1330. FatalError('Character ''<'' is not allowed in attribute value')
  1331. else if wc = '&' then
  1332. begin
  1333. if ParseRef(FValue) or ResolvePredefined then
  1334. Continue;
  1335. entName := FNameTable.FindOrAdd(FName.Buffer, FName.Length);
  1336. ent := EntityCheck(True);
  1337. if ((ent = nil) or (not FExpandEntities)) and (FSource.FEntity = start) then
  1338. begin
  1339. if FValue.Length > StartPos then
  1340. begin
  1341. AllocAttributeValueChunk(curr, StartPos);
  1342. curr^.FLoc := StartLoc;
  1343. end;
  1344. AllocAttributeValueChunk(curr, FValue.Length);
  1345. curr^.FNodeType := ntEntityReference;
  1346. curr^.FQName := entName;
  1347. StoreLocation(StartLoc);
  1348. curr^.FLoc := StartLoc;
  1349. Dec(curr^.FLoc.LinePos, FName.Length+1);
  1350. end;
  1351. StartPos := FValue.Length;
  1352. if Assigned(ent) then
  1353. ContextPush(ent);
  1354. end
  1355. else if wc <> #0 then
  1356. begin
  1357. FSource.NextChar;
  1358. if (wc = Delim) and (FSource.FEntity = start) then
  1359. Break;
  1360. if (wc = #10) or (wc = #9) or (wc = #13) then
  1361. wc := #32;
  1362. BufAppend(FValue, wc);
  1363. end
  1364. else
  1365. begin
  1366. if (FSource.FEntity = start) or not ContextPop then // #0
  1367. FatalError('Literal has no closing quote', -1);
  1368. StartPos := FValue.Length;
  1369. end;
  1370. until False;
  1371. if Assigned(attrData^.FNext) then
  1372. begin
  1373. FAttrCleanupFlag := True;
  1374. if FValue.Length > StartPos then
  1375. begin
  1376. AllocAttributeValueChunk(curr, StartPos);
  1377. curr^.FLoc := StartLoc;
  1378. end;
  1379. end;
  1380. if nonCDATA then
  1381. BufNormalize(FValue, attrData^.FDenormalized)
  1382. else
  1383. attrData^.FDenormalized := False;
  1384. SetString(attrData^.FValueStr, FValue.Buffer, FValue.Length);
  1385. end;
  1386. const
  1387. PrefixChar: array[Boolean] of string = ('', '%');
  1388. procedure TXMLTextReader.EntityToSource(AEntity: TEntityDecl; out Src: TXMLCharSource);
  1389. begin
  1390. if AEntity.FOnStack then
  1391. FatalError('Entity ''%s%s'' recursively references itself', [PrefixChar[AEntity.FIsPE], AEntity.FName]);
  1392. if (AEntity.FSystemID <> '') and not AEntity.FPrefetched then
  1393. begin
  1394. if not ResolveResource(AEntity.FSystemID, AEntity.FPublicID, AEntity.FURI, Src) then
  1395. begin
  1396. // TODO: a detailed message like SysErrorMessage(GetLastError) would be great here
  1397. ValidationError('Unable to resolve external entity ''%s''', [AEntity.FName]);
  1398. Src := nil;
  1399. Exit;
  1400. end;
  1401. end
  1402. else
  1403. begin
  1404. Src := TXMLCharSource.Create(AEntity.FReplacementText);
  1405. Src.FLineNo := AEntity.FStartLocation.Line;
  1406. Src.LFPos := Src.FBuf - AEntity.FStartLocation.LinePos;
  1407. // needed in case of prefetched external PE
  1408. if AEntity.FSystemID <> '' then
  1409. Src.SourceURI := AEntity.FURI;
  1410. end;
  1411. AEntity.FOnStack := True;
  1412. Src.FEntity := AEntity;
  1413. end;
  1414. function TXMLTextReader.ContextPush(AEntity: TEntityDecl; DummySource: Boolean): Boolean;
  1415. var
  1416. Src: TXMLCharSource;
  1417. begin
  1418. Src := nil;
  1419. if Assigned(AEntity) then
  1420. EntityToSource(AEntity, Src);
  1421. if (Src = nil) and DummySource then
  1422. begin
  1423. Src := TXMLCharSource.Create('');
  1424. if FExpandEntities then
  1425. Src.Kind := skManualPop;
  1426. end;
  1427. Result := Assigned(Src);
  1428. if Result then
  1429. begin
  1430. SetSource(Src);
  1431. Src.Initialize;
  1432. end;
  1433. end;
  1434. function TXMLTextReader.ContextPop(Forced: Boolean): Boolean;
  1435. var
  1436. Src: TXMLCharSource;
  1437. Error: Boolean;
  1438. begin
  1439. Result := Assigned(FSource.FParent) and (Forced or (FSource.Kind = skNone));
  1440. if Result then
  1441. begin
  1442. Src := FSource.FParent;
  1443. Error := False;
  1444. if Assigned(FSource.FEntity) then
  1445. begin
  1446. FSource.FEntity.FOnStack := False;
  1447. FSource.FEntity.FCharCount := FSource.FCharCount;
  1448. // [28a] PE that was started between MarkupDecls may not end inside MarkupDecl
  1449. Error := FSource.FEntity.FBetweenDecls and FInsideDecl;
  1450. end;
  1451. FSource.Free;
  1452. FSource := Src;
  1453. // correct position of this error is after PE reference
  1454. if Error then
  1455. FatalError('Parameter entities must be properly nested');
  1456. end;
  1457. end;
  1458. function TXMLTextReader.EntityCheck(NoExternals: Boolean): TEntityDecl;
  1459. var
  1460. RefName: XMLString;
  1461. cnt: Integer;
  1462. begin
  1463. Result := nil;
  1464. SetString(RefName, FName.Buffer, FName.Length);
  1465. cnt := FName.Length+2;
  1466. if Assigned(FDocType) then
  1467. Result := FDocType.Entities.Get(FName.Buffer, FName.Length) as TEntityDecl;
  1468. if Result = nil then
  1469. begin
  1470. if FStandalone or (FDocType = nil) or not (FHavePERefs or (FDocType.FSystemID <> '')) then
  1471. FatalError('Reference to undefined entity ''%s''', [RefName], cnt)
  1472. else
  1473. ValidationError('Undefined entity ''%s'' referenced', [RefName], cnt);
  1474. Exit;
  1475. end;
  1476. if FStandalone and Result.ExternallyDeclared then
  1477. FatalError('Standalone constraint violation', cnt);
  1478. if Result.FNotationName <> '' then
  1479. FatalError('Reference to unparsed entity ''%s''', [RefName], cnt);
  1480. if NoExternals and (Result.FSystemID <> '') then
  1481. FatalError('External entity reference is not allowed in attribute value', cnt);
  1482. if not Result.FResolved then
  1483. if Assigned(FOnEntity) then
  1484. FOnEntity(Self, Result);
  1485. // at this point we know the charcount of the entity being included
  1486. if Result.FCharCount >= cnt then
  1487. CheckMaxChars(Result.FCharCount - cnt);
  1488. end;
  1489. procedure TXMLTextReader.StartPE;
  1490. var
  1491. PEnt: TEntityDecl;
  1492. begin
  1493. FSource.NextChar; // skip '%'
  1494. CheckName;
  1495. ExpectChar(';');
  1496. if (FSource.Kind = skInternalSubset) and FInsideDecl then
  1497. FatalError('Parameter entity references cannot appear inside markup declarations in internal subset', FName.Length+2);
  1498. PEnt := nil;
  1499. if Assigned(FPEMap) then
  1500. PEnt := FPEMap.Get(FName.Buffer, FName.Length) as TEntityDecl;
  1501. if PEnt = nil then
  1502. begin
  1503. ValidationErrorWithName('Undefined parameter entity ''%s'' referenced', FName.Length+2);
  1504. // cease processing declarations, unless document is standalone.
  1505. FDTDProcessed := FStandalone;
  1506. Exit;
  1507. end;
  1508. { cache an external PE so it's only fetched once }
  1509. if (PEnt.FSystemID <> '') and (not PEnt.FPrefetched) and (not PrefetchEntity(PEnt)) then
  1510. begin
  1511. FDTDProcessed := FStandalone;
  1512. Exit;
  1513. end;
  1514. CheckMaxChars(PEnt.FCharCount);
  1515. PEnt.FBetweenDecls := not FInsideDecl;
  1516. ContextPush(PEnt);
  1517. FHavePERefs := True;
  1518. end;
  1519. function TXMLTextReader.PrefetchEntity(AEntity: TEntityDecl): Boolean;
  1520. begin
  1521. Result := ContextPush(AEntity);
  1522. if Result then
  1523. try
  1524. FValue.Length := 0;
  1525. FSource.SkipUntil(FValue, [#0]);
  1526. SetString(AEntity.FReplacementText, FValue.Buffer, FValue.Length);
  1527. AEntity.FCharCount := FValue.Length;
  1528. AEntity.FStartLocation.Line := 1;
  1529. AEntity.FStartLocation.LinePos := 1;
  1530. AEntity.FURI := FSource.SourceURI; // replace base URI with absolute one
  1531. finally
  1532. ContextPop;
  1533. AEntity.FPrefetched := True;
  1534. FValue.Length := 0;
  1535. end;
  1536. end;
  1537. const
  1538. LiteralDelims: array[TLiteralType] of TSetOfChar = (
  1539. [#0, '''', '"'], // ltPlain
  1540. [#0, '''', '"', #13, #10], // ltPubid
  1541. [#0, '%', '&', '''', '"'] // ltEntity
  1542. );
  1543. function TXMLTextReader.ParseLiteral(var ToFill: TWideCharBuf; aType: TLiteralType;
  1544. Required: Boolean): Boolean;
  1545. var
  1546. start: TObject;
  1547. wc, Delim: WideChar;
  1548. dummy: Boolean;
  1549. begin
  1550. SkipQuote(Delim, Required);
  1551. Result := (Delim <> #0);
  1552. if not Result then
  1553. Exit;
  1554. ToFill.Length := 0;
  1555. start := FSource.FEntity;
  1556. repeat
  1557. wc := FSource.SkipUntil(ToFill, LiteralDelims[aType]);
  1558. if wc = '%' then { ltEntity only }
  1559. StartPE
  1560. else if wc = '&' then { ltEntity }
  1561. begin
  1562. if ParseRef(ToFill) then // charRefs always expanded
  1563. Continue;
  1564. BufAppend(ToFill, '&');
  1565. BufAppendChunk(ToFill, FName.Buffer, FName.Buffer + FName.Length);
  1566. BufAppend(ToFill, ';');
  1567. end
  1568. else if wc <> #0 then
  1569. begin
  1570. FSource.NextChar;
  1571. if (wc = #10) or (wc = #13) then
  1572. wc := #32
  1573. // terminating delimiter must be in the same context as the starting one
  1574. else if (wc = Delim) and (start = FSource.FEntity) then
  1575. Break;
  1576. BufAppend(ToFill, wc);
  1577. end
  1578. else if (FSource.FEntity = start) or not ContextPop then // #0
  1579. FatalError('Literal has no closing quote', -1);
  1580. until False;
  1581. if aType = ltPubid then
  1582. BufNormalize(ToFill, dummy);
  1583. end;
  1584. function TXMLTextReader.SkipUntilSeq(const Delim: TSetOfChar; c1: WideChar): Boolean;
  1585. var
  1586. wc: WideChar;
  1587. begin
  1588. Result := False;
  1589. StoreLocation(FTokenStart);
  1590. repeat
  1591. wc := FSource.SkipUntil(FValue, Delim);
  1592. if wc <> #0 then
  1593. begin
  1594. FSource.NextChar;
  1595. if (FValue.Length > 0) then
  1596. begin
  1597. if (FValue.Buffer[FValue.Length-1] = c1) then
  1598. begin
  1599. Dec(FValue.Length);
  1600. Result := True;
  1601. Exit;
  1602. end;
  1603. end;
  1604. BufAppend(FValue, wc);
  1605. end;
  1606. until wc = #0;
  1607. end;
  1608. procedure TXMLTextReader.ParseComment(discard: Boolean); // [15]
  1609. var
  1610. SaveLength: Integer;
  1611. begin
  1612. ExpectString('--');
  1613. SaveLength := FValue.Length;
  1614. if not SkipUntilSeq([#0, '-'], '-') then
  1615. FatalError('Unterminated comment', -1);
  1616. ExpectChar('>');
  1617. if not discard then
  1618. begin
  1619. FCurrNode := @FNodeStack[FNesting];
  1620. FCurrNode^.FNodeType := ntComment;
  1621. FCurrNode^.FQName := nil;
  1622. FCurrNode^.FValueStart := @FValue.Buffer[SaveLength];
  1623. FCurrNode^.FValueLength := FValue.Length-SaveLength;
  1624. end;
  1625. FValue.Length := SaveLength;
  1626. end;
  1627. procedure TXMLTextReader.ParsePI; // [16]
  1628. begin
  1629. FSource.NextChar; // skip '?'
  1630. CheckName;
  1631. CheckNCName;
  1632. with FName do
  1633. if (Length = 3) and
  1634. ((Buffer[0] = 'X') or (Buffer[0] = 'x')) and
  1635. ((Buffer[1] = 'M') or (Buffer[1] = 'm')) and
  1636. ((Buffer[2] = 'L') or (Buffer[2] = 'l')) then
  1637. begin
  1638. if not BufEquals(FName, 'xml') then
  1639. FatalError('''xml'' is a reserved word; it must be lowercase', FName.Length)
  1640. else
  1641. FatalError('XML declaration is not allowed here', FName.Length);
  1642. end;
  1643. if FSource.FBuf^ <> '?' then
  1644. SkipS(True);
  1645. FValue.Length := 0;
  1646. if not SkipUntilSeq(GT_Delim, '?') then
  1647. FatalError('Unterminated processing instruction', -1);
  1648. SetNodeInfoWithValue(ntProcessingInstruction,
  1649. FNameTable.FindOrAdd(FName.Buffer, FName.Length));
  1650. end;
  1651. const
  1652. vers: array[Boolean] of TXMLVersion = (xmlVersion10, xmlVersion11);
  1653. procedure TXMLTextReader.ParseXmlOrTextDecl(TextDecl: Boolean);
  1654. var
  1655. Delim: WideChar;
  1656. buf: array[0..31] of WideChar;
  1657. I: Integer;
  1658. begin
  1659. SkipS(True);
  1660. // [24] VersionInfo: optional in TextDecl, required in XmlDecl
  1661. if (not TextDecl) or (FSource.FBuf^ = 'v') then
  1662. begin
  1663. ExpectString('version');
  1664. ExpectEq;
  1665. SkipQuote(Delim);
  1666. { !! Definition "VersionNum ::= '1.' [0-9]+" per XML 1.0 Fifth Edition
  1667. implies that version literal can have unlimited length. }
  1668. I := 0;
  1669. while (I < 3) and (FSource.FBuf^ <> Delim) do
  1670. begin
  1671. buf[I] := FSource.FBuf^;
  1672. Inc(I);
  1673. FSource.NextChar;
  1674. end;
  1675. if (I <> 3) or (buf[0] <> '1') or (buf[1] <> '.') or
  1676. (buf[2] < '0') or (buf[2] > '9') then
  1677. FatalError('Illegal version number', -1);
  1678. ExpectChar(Delim);
  1679. FSource.FXMLVersion := vers[buf[2] = '1'];
  1680. if TextDecl and (FSource.FXMLVersion = xmlVersion11) and not FXML11 then
  1681. FatalError('XML 1.0 document cannot invoke XML 1.1 entities', -1);
  1682. if TextDecl or (FSource.FBuf^ <> '?') then
  1683. SkipS(True);
  1684. end;
  1685. // [80] EncodingDecl: required in TextDecl, optional in XmlDecl
  1686. if TextDecl or (FSource.FBuf^ = 'e') then
  1687. begin
  1688. ExpectString('encoding');
  1689. ExpectEq;
  1690. SkipQuote(Delim);
  1691. I := 0;
  1692. while (I < 30) and (FSource.FBuf^ <> Delim) and (FSource.FBuf^ < #127) and
  1693. ((AnsiChar(ord(FSource.FBuf^)) in ['A'..'Z', 'a'..'z']) or
  1694. ((I > 0) and (AnsiChar(ord(FSource.FBuf^)) in ['0'..'9', '.', '-', '_']))) do
  1695. begin
  1696. buf[I] := FSource.FBuf^;
  1697. Inc(I);
  1698. FSource.NextChar;
  1699. end;
  1700. if not CheckForChar(Delim) then
  1701. FatalError('Illegal encoding name', i);
  1702. SetString(FSource.FXMLEncoding, buf, i);
  1703. if not FSource.SetEncoding(FSource.FXMLEncoding) then // <-- Wide2Ansi conversion here
  1704. FatalError('Encoding ''%s'' is not supported', [FSource.FXMLEncoding], i+1);
  1705. if FSource.FBuf^ <> '?' then
  1706. SkipS(not TextDecl);
  1707. end;
  1708. // [32] SDDecl: forbidden in TextDecl, optional in XmlDecl
  1709. if (not TextDecl) and (FSource.FBuf^ = 's') then
  1710. begin
  1711. ExpectString('standalone');
  1712. ExpectEq;
  1713. SkipQuote(Delim);
  1714. if FSource.Matches('yes') then
  1715. FStandalone := True
  1716. else if not FSource.Matches('no') then
  1717. FatalError('Only "yes" or "no" are permitted as values of "standalone"', -1);
  1718. ExpectChar(Delim);
  1719. SkipS;
  1720. end;
  1721. ExpectString('?>');
  1722. { Switch to 1.1 rules only after declaration is parsed completely. This is to
  1723. ensure that NEL and LSEP within declaration are rejected (rmt-056, rmt-057) }
  1724. if FSource.FXMLVersion = xmlVersion11 then
  1725. FXML11 := True;
  1726. end;
  1727. procedure TXMLTextReader.DTDReloadHook;
  1728. var
  1729. p: PWideChar;
  1730. begin
  1731. { FSource converts CR, NEL and LSEP linebreaks to LF, and CR-NEL sequences to CR-LF.
  1732. We must further remove the CR chars and have only LF's left. }
  1733. p := FDTDStartPos;
  1734. while p < FSource.FBuf do
  1735. begin
  1736. while (p < FSource.FBuf) and (p^ <> #13) do
  1737. Inc(p);
  1738. BufAppendChunk(FIntSubset, FDTDStartPos, p);
  1739. if p^ = #13 then
  1740. Inc(p);
  1741. FDTDStartPos := p;
  1742. end;
  1743. FDTDStartPos := TXMLDecodingSource(FSource).FBufStart;
  1744. end;
  1745. procedure TXMLTextReader.ParseDoctypeDecl; // [28]
  1746. var
  1747. Src: TXMLCharSource;
  1748. DTDName: PHashItem;
  1749. Locs: array [0..2] of TLocation;
  1750. HasAtts: Boolean;
  1751. begin
  1752. if FState >= rsDTD then
  1753. FatalError('Markup declaration is not allowed here');
  1754. if FDisallowDoctype then
  1755. FatalError('Document type is prohibited by parser settings');
  1756. ExpectString('DOCTYPE');
  1757. SkipS(True);
  1758. FDocType := TDTDModel.Create(FNameTable);
  1759. FDTDProcessed := True; // assume success
  1760. FState := rsDTD;
  1761. CheckName;
  1762. SetString(FDocType.FName, FName.Buffer, FName.Length);
  1763. DTDName := FNameTable.FindOrAdd(FName.Buffer, FName.Length);
  1764. if SkipS then
  1765. begin
  1766. StoreLocation(Locs[0]);
  1767. HasAtts := ParseExternalID(FDocType.FSystemID, FDocType.FPublicID, Locs[1], False);
  1768. if HasAtts then
  1769. Locs[2] := FTokenStart;
  1770. SkipS;
  1771. end;
  1772. if CheckForChar('[') then
  1773. begin
  1774. BufAllocate(FIntSubset, 256);
  1775. FSource.Kind := skInternalSubset;
  1776. try
  1777. FDTDStartPos := FSource.FBuf;
  1778. ParseMarkupDecl;
  1779. DTDReloadHook; // fetch last chunk
  1780. SetString(FDocType.FInternalSubset, FIntSubset.Buffer, FIntSubset.Length);
  1781. finally
  1782. FreeMem(FIntSubset.Buffer);
  1783. FSource.Kind := skNone;
  1784. end;
  1785. ExpectChar(']');
  1786. SkipS;
  1787. end;
  1788. ExpectChar('>');
  1789. if (FDocType.FSystemID <> '') then
  1790. begin
  1791. if ResolveResource(FDocType.FSystemID, FDocType.FPublicID, FSource.SourceURI, Src) then
  1792. begin
  1793. SetSource(Src);
  1794. Src.Initialize;
  1795. try
  1796. Src.Kind := skManualPop;
  1797. ParseMarkupDecl;
  1798. finally
  1799. ContextPop(True);
  1800. end;
  1801. end
  1802. else
  1803. begin
  1804. ValidationError('Unable to resolve external DTD subset', []);
  1805. FDTDProcessed := FStandalone;
  1806. end;
  1807. end;
  1808. FState := rsAfterDTD;
  1809. FValue.Length := 0;
  1810. BufAppendString(FValue, FDocType.FInternalSubset);
  1811. SetNodeInfoWithValue(ntDocumentType, DTDName);
  1812. if HasAtts then
  1813. begin
  1814. if FDocType.FPublicID <> '' then
  1815. AddPseudoAttribute(FNameTable.FindOrAdd('PUBLIC'), FDocType.FPublicID, Locs[0], Locs[1]);
  1816. AddPseudoAttribute(FNameTable.FindOrAdd('SYSTEM'), FDocType.FSystemID, Locs[0], Locs[2]);
  1817. end;
  1818. end;
  1819. procedure TXMLTextReader.ExpectEq; // [25]
  1820. begin
  1821. if FSource.FBuf^ <> '=' then
  1822. SkipS;
  1823. if FSource.FBuf^ <> '=' then
  1824. FatalError('Expected "="');
  1825. FSource.NextChar;
  1826. SkipS;
  1827. end;
  1828. { DTD stuff }
  1829. procedure TXMLTextReader.CheckPENesting(aExpected: TObject);
  1830. begin
  1831. if FSource.FEntity <> aExpected then
  1832. ValidationError('Parameter entities must be properly nested', [], 0);
  1833. end;
  1834. function TXMLTextReader.ParseQuantity: TCPQuant;
  1835. begin
  1836. case FSource.FBuf^ of
  1837. '?': Result := cqZeroOrOnce;
  1838. '*': Result := cqZeroOrMore;
  1839. '+': Result := cqOnceOrMore;
  1840. else
  1841. Result := cqOnce;
  1842. Exit;
  1843. end;
  1844. FSource.NextChar;
  1845. end;
  1846. function TXMLTextReader.FindOrCreateElDef: TElementDecl;
  1847. var
  1848. p: PHashItem;
  1849. begin
  1850. CheckName;
  1851. p := FNameTable.FindOrAdd(FName.Buffer, FName.Length);
  1852. Result := TElementDecl(p^.Data);
  1853. if Result = nil then
  1854. begin
  1855. Result := TElementDecl.Create;
  1856. p^.Data := Result;
  1857. end;
  1858. end;
  1859. procedure TXMLTextReader.ExpectChoiceOrSeq(CP: TContentParticle; MustEndIn: TObject); // [49], [50]
  1860. var
  1861. Delim: WideChar;
  1862. CurrentCP: TContentParticle;
  1863. begin
  1864. Delim := #0;
  1865. repeat
  1866. CurrentCP := CP.Add;
  1867. SkipWhitespace;
  1868. if CheckForChar('(') then
  1869. ExpectChoiceOrSeq(CurrentCP, FSource.FEntity)
  1870. else
  1871. CurrentCP.Def := FindOrCreateElDef;
  1872. CurrentCP.CPQuant := ParseQuantity;
  1873. SkipWhitespace;
  1874. if FSource.FBuf^ = ')' then
  1875. Break;
  1876. if Delim = #0 then
  1877. begin
  1878. if (FSource.FBuf^ = '|') or (FSource.FBuf^ = ',') then
  1879. Delim := FSource.FBuf^
  1880. else
  1881. FatalError('Expected pipe or comma delimiter');
  1882. end
  1883. else
  1884. if FSource.FBuf^ <> Delim then
  1885. FatalError(Delim);
  1886. FSource.NextChar; // skip delimiter
  1887. until False;
  1888. CheckPENesting(MustEndIn);
  1889. FSource.NextChar;
  1890. if Delim = '|' then
  1891. CP.CPType := ctChoice
  1892. else
  1893. CP.CPType := ctSeq; // '(foo)' is a sequence!
  1894. end;
  1895. procedure TXMLTextReader.ParseElementDecl; // [45]
  1896. var
  1897. ElDef: TElementDecl;
  1898. CurrentEntity: TObject;
  1899. I: Integer;
  1900. CP: TContentParticle;
  1901. Typ: TElementContentType;
  1902. ExtDecl: Boolean;
  1903. begin
  1904. CP := nil;
  1905. Typ := ctUndeclared; // satisfy compiler
  1906. ExpectWhitespace;
  1907. ElDef := FindOrCreateElDef;
  1908. if ElDef.ContentType <> ctUndeclared then
  1909. ValidationErrorWithName('Duplicate declaration of element ''%s''', FName.Length);
  1910. ExtDecl := FSource.Kind <> skInternalSubset;
  1911. ExpectWhitespace;
  1912. if FSource.Matches('EMPTY') then
  1913. Typ := ctEmpty
  1914. else if FSource.Matches('ANY') then
  1915. Typ := ctAny
  1916. else if CheckForChar('(') then
  1917. begin
  1918. CP := TContentParticle.Create;
  1919. try
  1920. CurrentEntity := FSource.FEntity;
  1921. SkipWhitespace;
  1922. if FSource.Matches('#PCDATA') then // Mixed section [51]
  1923. begin
  1924. SkipWhitespace;
  1925. Typ := ctMixed;
  1926. while FSource.FBuf^ <> ')' do
  1927. begin
  1928. ExpectChar('|');
  1929. SkipWhitespace;
  1930. with CP.Add do
  1931. begin
  1932. Def := FindOrCreateElDef;
  1933. for I := CP.ChildCount-2 downto 0 do
  1934. if Def = CP.Children[I].Def then
  1935. ValidationError('Duplicate token in mixed section', [], FName.Length);
  1936. end;
  1937. SkipWhitespace;
  1938. end;
  1939. CheckPENesting(CurrentEntity);
  1940. FSource.NextChar;
  1941. if (not CheckForChar('*')) and (CP.ChildCount > 0) then
  1942. FatalError(WideChar('*'));
  1943. CP.CPQuant := cqZeroOrMore;
  1944. CP.CPType := ctChoice;
  1945. end
  1946. else // Children section [47]
  1947. begin
  1948. Typ := ctChildren;
  1949. ExpectChoiceOrSeq(CP, CurrentEntity);
  1950. CP.CPQuant := ParseQuantity;
  1951. end;
  1952. except
  1953. CP.Free;
  1954. raise;
  1955. end;
  1956. end
  1957. else
  1958. FatalError('Invalid content specification');
  1959. if FDTDProcessed and (ElDef.ContentType = ctUndeclared) then
  1960. begin
  1961. ElDef.ExternallyDeclared := ExtDecl;
  1962. ElDef.ContentType := Typ;
  1963. ElDef.RootCP := CP;
  1964. end
  1965. else
  1966. CP.Free;
  1967. end;
  1968. procedure TXMLTextReader.ParseNotationDecl; // [82]
  1969. var
  1970. NameStr, SysID, PubID: XMLString;
  1971. Notation: TNotationDecl;
  1972. Entry: PHashItem;
  1973. Src: TXMLCharSource;
  1974. dummy: TLocation;
  1975. begin
  1976. Src := FSource;
  1977. ExpectWhitespace;
  1978. CheckName;
  1979. CheckNCName;
  1980. SetString(NameStr, FName.Buffer, FName.Length);
  1981. ExpectWhitespace;
  1982. if not ParseExternalID(SysID, PubID, dummy, True) then
  1983. FatalError('Expected external or public ID');
  1984. if FDTDProcessed then
  1985. begin
  1986. Entry := FDocType.Notations.FindOrAdd(NameStr);
  1987. if Entry^.Data = nil then
  1988. begin
  1989. Notation := TNotationDecl.Create;
  1990. Notation.FName := NameStr;
  1991. Notation.FPublicID := PubID;
  1992. Notation.FSystemID := SysID;
  1993. Notation.FURI := Src.SourceURI;
  1994. Entry^.Data := Notation;
  1995. end
  1996. else
  1997. ValidationError('Duplicate notation declaration: ''%s''', [NameStr]);
  1998. end;
  1999. end;
  2000. const
  2001. AttrDataTypeNames: array[TAttrDataType] of XMLString = (
  2002. 'CDATA',
  2003. 'ID',
  2004. 'IDREF',
  2005. 'IDREFS',
  2006. 'ENTITY',
  2007. 'ENTITIES',
  2008. 'NMTOKEN',
  2009. 'NMTOKENS',
  2010. 'NOTATION'
  2011. );
  2012. procedure TXMLTextReader.ParseAttlistDecl; // [52]
  2013. var
  2014. ElDef: TElementDecl;
  2015. AttDef: TAttributeDef;
  2016. dt: TAttrDataType;
  2017. Found, DiscardIt: Boolean;
  2018. Offsets: array [Boolean] of Integer;
  2019. attrName: PHashItem;
  2020. begin
  2021. ExpectWhitespace;
  2022. ElDef := FindOrCreateElDef;
  2023. SkipWhitespace;
  2024. while FSource.FBuf^ <> '>' do
  2025. begin
  2026. CheckName;
  2027. ExpectWhitespace;
  2028. attrName := FNameTable.FindOrAdd(FName.Buffer, FName.Length);
  2029. AttDef := TAttributeDef.Create(attrName, FColonPos);
  2030. try
  2031. AttDef.ExternallyDeclared := FSource.Kind <> skInternalSubset;
  2032. // In case of duplicate declaration of the same attribute, we must discard it,
  2033. // not modifying ElDef, and suppressing certain validation errors.
  2034. DiscardIt := (not FDTDProcessed) or Assigned(ElDef.GetAttrDef(attrName));
  2035. if CheckForChar('(') then // [59]
  2036. begin
  2037. AttDef.DataType := dtNmToken;
  2038. repeat
  2039. SkipWhitespace;
  2040. CheckName([cnToken]);
  2041. if not AttDef.AddEnumToken(FName.Buffer, FName.Length) then
  2042. ValidationError('Duplicate token in enumerated attribute declaration', [], FName.Length);
  2043. SkipWhitespace;
  2044. until not CheckForChar('|');
  2045. ExpectChar(')');
  2046. ExpectWhitespace;
  2047. end
  2048. else
  2049. begin
  2050. StoreLocation(FTokenStart);
  2051. // search topside-up so that e.g. NMTOKENS is matched before NMTOKEN
  2052. for dt := dtNotation downto dtCData do
  2053. begin
  2054. Found := FSource.Matches(AttrDataTypeNames[dt]);
  2055. if Found then
  2056. Break;
  2057. end;
  2058. if Found and SkipWhitespace then
  2059. begin
  2060. AttDef.DataType := dt;
  2061. if (dt = dtId) and not DiscardIt then
  2062. begin
  2063. if Assigned(ElDef.IDAttr) then
  2064. ValidationError('Only one attribute of type ID is allowed per element',[])
  2065. else
  2066. ElDef.IDAttr := AttDef;
  2067. end
  2068. else if dt = dtNotation then // no test cases for these ?!
  2069. begin
  2070. if not DiscardIt then
  2071. begin
  2072. if Assigned(ElDef.NotationAttr) then
  2073. ValidationError('Only one attribute of type NOTATION is allowed per element',[])
  2074. else
  2075. ElDef.NotationAttr := AttDef;
  2076. if ElDef.ContentType = ctEmpty then
  2077. ValidationError('NOTATION attributes are not allowed on EMPTY elements',[]);
  2078. end;
  2079. ExpectChar('(');
  2080. repeat
  2081. SkipWhitespace;
  2082. StoreLocation(FTokenStart);
  2083. CheckName;
  2084. CheckNCName;
  2085. if not AttDef.AddEnumToken(FName.Buffer, FName.Length) then
  2086. ValidationError('Duplicate token in NOTATION attribute declaration',[], FName.Length);
  2087. if (not DiscardIt) and FValidate and
  2088. (FDocType.Notations.Get(FName.Buffer,FName.Length)=nil) then
  2089. AddForwardRef(FName.Buffer, FName.Length);
  2090. SkipWhitespace;
  2091. until not CheckForChar('|');
  2092. ExpectChar(')');
  2093. ExpectWhitespace;
  2094. end;
  2095. end
  2096. else
  2097. begin
  2098. // don't report 'expected whitespace' if token does not match completely
  2099. Offsets[False] := 0;
  2100. Offsets[True] := Length(AttrDataTypeNames[dt]);
  2101. if Found and (FSource.FBuf^ < 'A') then
  2102. ExpectWhitespace
  2103. else
  2104. FatalError('Illegal attribute type for ''%s''', [attrName^.Key], Offsets[Found]);
  2105. end;
  2106. end;
  2107. StoreLocation(FTokenStart);
  2108. if FSource.Matches('#REQUIRED') then
  2109. AttDef.Default := adRequired
  2110. else if FSource.Matches('#IMPLIED') then
  2111. AttDef.Default := adImplied
  2112. else if FSource.Matches('#FIXED') then
  2113. begin
  2114. AttDef.Default := adFixed;
  2115. ExpectWhitespace;
  2116. end
  2117. else
  2118. AttDef.Default := adDefault;
  2119. if AttDef.Default in [adDefault, adFixed] then
  2120. begin
  2121. if AttDef.DataType = dtId then
  2122. ValidationError('An attribute of type ID cannot have a default value',[]);
  2123. // See comments to valid-sa-094: PE expansion should be disabled in AttDef.
  2124. ExpectAttValue(AttDef.Data, dt <> dtCDATA);
  2125. if not AttDef.ValidateSyntax(AttDef.Data^.FValueStr, FNamespaces) then
  2126. ValidationError('Default value for attribute ''%s'' has wrong syntax', [attrName^.Key]);
  2127. end;
  2128. if DiscardIt then
  2129. AttDef.Free
  2130. else
  2131. ElDef.AddAttrDef(AttDef);
  2132. except
  2133. AttDef.Free;
  2134. raise;
  2135. end;
  2136. SkipWhitespace;
  2137. end;
  2138. end;
  2139. procedure TXMLTextReader.ParseEntityDecl; // [70]
  2140. var
  2141. IsPE, Exists: Boolean;
  2142. Entity: TEntityDecl;
  2143. Map: THashTable;
  2144. Item: PHashItem;
  2145. dummy: TLocation;
  2146. begin
  2147. Entity := TEntityDecl.Create;
  2148. try
  2149. Entity.ExternallyDeclared := FSource.Kind <> skInternalSubset;
  2150. Entity.FURI := FSource.SourceURI;
  2151. if not SkipWhitespace(True) then
  2152. FatalError('Expected whitespace');
  2153. IsPE := CheckForChar('%');
  2154. if IsPE then // [72]
  2155. begin
  2156. ExpectWhitespace;
  2157. if FPEMap = nil then
  2158. FPEMap := THashTable.Create(64, True);
  2159. Map := FPEMap;
  2160. end
  2161. else
  2162. Map := FDocType.Entities;
  2163. Entity.FIsPE := IsPE;
  2164. CheckName;
  2165. CheckNCName;
  2166. Item := Map.FindOrAdd(FName.Buffer, FName.Length, Exists);
  2167. ExpectWhitespace;
  2168. if FEntityValue.Buffer = nil then
  2169. BufAllocate(FEntityValue, 256);
  2170. if ParseLiteral(FEntityValue, ltEntity, False) then
  2171. begin
  2172. SetString(Entity.FReplacementText, FEntityValue.Buffer, FEntityValue.Length);
  2173. Entity.FCharCount := FEntityValue.Length;
  2174. Entity.FStartLocation := FTokenStart;
  2175. end
  2176. else
  2177. begin
  2178. if not ParseExternalID(Entity.FSystemID, Entity.FPublicID, dummy, False) then
  2179. FatalError('Expected entity value or external ID');
  2180. if not IsPE then // [76]
  2181. begin
  2182. if FSource.FBuf^ <> '>' then
  2183. ExpectWhitespace;
  2184. if FSource.Matches('NDATA') then
  2185. begin
  2186. ExpectWhitespace;
  2187. StoreLocation(FTokenStart); { needed for AddForwardRef }
  2188. CheckName;
  2189. SetString(Entity.FNotationName, FName.Buffer, FName.Length);
  2190. if FValidate and (FDocType.Notations.Get(FName.Buffer, FName.Length)=nil) then
  2191. AddForwardRef(FName.Buffer, FName.Length);
  2192. end;
  2193. end;
  2194. end;
  2195. except
  2196. Entity.Free;
  2197. raise;
  2198. end;
  2199. // Repeated declarations of same entity are legal but must be ignored
  2200. if FDTDProcessed and not Exists then
  2201. begin
  2202. Item^.Data := Entity;
  2203. Entity.FName := Item^.Key;
  2204. end
  2205. else
  2206. Entity.Free;
  2207. end;
  2208. procedure TXMLTextReader.ParseIgnoreSection;
  2209. var
  2210. IgnoreLoc: TLocation;
  2211. IgnoreLevel: Integer;
  2212. wc: WideChar;
  2213. begin
  2214. StoreLocation(IgnoreLoc);
  2215. IgnoreLevel := 1;
  2216. repeat
  2217. FValue.Length := 0;
  2218. wc := FSource.SkipUntil(FValue, [#0, '<', ']']);
  2219. if FSource.Matches('<![') then
  2220. Inc(IgnoreLevel)
  2221. else if FSource.Matches(']]>') then
  2222. Dec(IgnoreLevel)
  2223. else if wc <> #0 then
  2224. FSource.NextChar
  2225. else // PE's aren't recognized in ignore section, cannot ContextPop()
  2226. DoErrorPos(esFatal, 'IGNORE section is not closed', IgnoreLoc);
  2227. until IgnoreLevel=0;
  2228. end;
  2229. procedure TXMLTextReader.ParseMarkupDecl; // [29]
  2230. var
  2231. IncludeLevel: Integer;
  2232. CurrentEntity: TObject;
  2233. IncludeLoc: TLocation;
  2234. CondType: (ctUnknown, ctInclude, ctIgnore);
  2235. begin
  2236. IncludeLevel := 0;
  2237. repeat
  2238. SkipWhitespace;
  2239. if (FSource.FBuf^ = ']') and (IncludeLevel > 0) then
  2240. begin
  2241. ExpectString(']]>');
  2242. Dec(IncludeLevel);
  2243. Continue;
  2244. end;
  2245. if not CheckForChar('<') then
  2246. Break;
  2247. CurrentEntity := FSource.FEntity;
  2248. if FSource.FBuf^ = '?' then
  2249. begin
  2250. ParsePI;
  2251. end
  2252. else
  2253. begin
  2254. ExpectChar('!');
  2255. if FSource.FBuf^ = '-' then
  2256. ParseComment(True)
  2257. else if CheckForChar('[') then
  2258. begin
  2259. if FSource.Kind = skInternalSubset then
  2260. FatalError('Conditional sections are not allowed in internal subset', 1);
  2261. SkipWhitespace;
  2262. CondType := ctUnknown; // satisfy compiler
  2263. if FSource.Matches('INCLUDE') then
  2264. CondType := ctInclude
  2265. else if FSource.Matches('IGNORE') then
  2266. CondType := ctIgnore
  2267. else
  2268. FatalError('Expected "INCLUDE" or "IGNORE"');
  2269. SkipWhitespace;
  2270. CheckPENesting(CurrentEntity);
  2271. ExpectChar('[');
  2272. if CondType = ctInclude then
  2273. begin
  2274. if IncludeLevel = 0 then
  2275. StoreLocation(IncludeLoc);
  2276. Inc(IncludeLevel);
  2277. end
  2278. else if CondType = ctIgnore then
  2279. ParseIgnoreSection;
  2280. end
  2281. else
  2282. begin
  2283. FInsideDecl := True;
  2284. if FSource.Matches('ELEMENT') then
  2285. ParseElementDecl
  2286. else if FSource.Matches('ENTITY') then
  2287. ParseEntityDecl
  2288. else if FSource.Matches('ATTLIST') then
  2289. ParseAttlistDecl
  2290. else if FSource.Matches('NOTATION') then
  2291. ParseNotationDecl
  2292. else
  2293. FatalError('Illegal markup declaration');
  2294. SkipWhitespace;
  2295. CheckPENesting(CurrentEntity);
  2296. ExpectChar('>');
  2297. FInsideDecl := False;
  2298. end;
  2299. end;
  2300. until False;
  2301. if IncludeLevel > 0 then
  2302. DoErrorPos(esFatal, 'INCLUDE section is not closed', IncludeLoc);
  2303. if FSource.FBuf < FSource.FBufEnd then
  2304. if (FSource.Kind <> skInternalSubset) or (FSource.FBuf^ <> ']') then
  2305. FatalError('Illegal character in DTD');
  2306. end;
  2307. procedure TXMLTextReader.ParseDTD;
  2308. begin
  2309. FSource.Initialize;
  2310. ParseMarkupDecl;
  2311. end;
  2312. procedure TXMLTextReader.Close;
  2313. begin
  2314. FReadState := rsClosed;
  2315. FTokenStart.Line := 0;
  2316. FTokenStart.LinePos := 0;
  2317. end;
  2318. function TXMLTextReader.GetAttributeCount: Integer;
  2319. begin
  2320. result := FAttrCount;
  2321. end;
  2322. function TXMLTextReader.GetAttribute(i: Integer): XMLString;
  2323. begin
  2324. if (i < 0) or (i >= FAttrCount) then
  2325. raise EArgumentOutOfRangeException.Create('index');
  2326. result := FNodeStack[FNesting+i+1].FValueStr;
  2327. end;
  2328. function TXMLTextReader.GetAttribute(const AName: XMLString): XMLString;
  2329. var
  2330. i: Integer;
  2331. p: PHashItem;
  2332. begin
  2333. p := FNameTable.Find(PWideChar(AName), Length(AName));
  2334. if Assigned(p) then
  2335. for i := 1 to FAttrCount do
  2336. if FNodeStack[FNesting+i].FQName = p then
  2337. begin
  2338. result := FNodeStack[FNesting+i].FValueStr;
  2339. Exit;
  2340. end;
  2341. result := '';
  2342. end;
  2343. function TXMLTextReader.GetAttribute(const aLocalName, nsuri: XMLString): XMLString;
  2344. var
  2345. i: Integer;
  2346. p: PWideChar;
  2347. p1: PHashItem;
  2348. node: PNodeData;
  2349. begin
  2350. p1 := FNameTable.Find(PWideChar(nsuri), Length(nsuri));
  2351. if Assigned(p1) then
  2352. for i := 1 to FAttrCount do
  2353. begin
  2354. node := @FNodeStack[FNesting+i];
  2355. if node^.FNsUri = p1 then
  2356. begin
  2357. P := PWideChar(node^.FQName^.Key);
  2358. if node^.FColonPos > 0 then
  2359. Inc(P, node^.FColonPos+1);
  2360. if (Length(node^.FQName^.Key)-node^.FColonPos-1 = Length(aLocalName)) and
  2361. CompareMem(P, PWideChar(aLocalName), Length(aLocalName)*sizeof(WideChar)) then
  2362. begin
  2363. result := node^.FValueStr;
  2364. Exit;
  2365. end;
  2366. end;
  2367. end;
  2368. result := '';
  2369. end;
  2370. function TXMLTextReader.GetDepth: Integer;
  2371. begin
  2372. result := FNesting;
  2373. if FCurrAttrIndex >= 0 then
  2374. Inc(result);
  2375. if FAttrReadState <> arsNone then
  2376. Inc(result);
  2377. end;
  2378. function TXMLTextReader.GetNameTable: THashTable;
  2379. begin
  2380. result := FNameTable;
  2381. end;
  2382. function TXMLTextReader.GetNodeType: TXmlNodeType;
  2383. begin
  2384. result := FCurrNode^.FNodeType;
  2385. end;
  2386. function TXMLTextReader.GetName: XMLString;
  2387. begin
  2388. if Assigned(FCurrNode^.FQName) then
  2389. result := FCurrNode^.FQName^.Key
  2390. else
  2391. result := '';
  2392. end;
  2393. function TXMLTextReader.GetIsDefault: Boolean;
  2394. begin
  2395. result := FCurrNode^.FIsDefault;
  2396. end;
  2397. function TXMLTextReader.GetBaseUri: XMLString;
  2398. begin
  2399. result := FSource.SourceURI;
  2400. end;
  2401. function TXMLTextReader.GetXmlVersion: TXMLVersion;
  2402. begin
  2403. result := FSource.FXMLVersion;
  2404. end;
  2405. function TXMLTextReader.GetXmlEncoding: XMLString;
  2406. begin
  2407. result := FSource.FXMLEncoding;
  2408. end;
  2409. { IXmlLineInfo methods }
  2410. function TXMLTextReader.GetHasLineInfo: Boolean;
  2411. begin
  2412. result := True;
  2413. end;
  2414. function TXMLTextReader.GetLineNumber: Integer;
  2415. begin
  2416. if (FCurrNode^.FNodeType in [ntElement,ntAttribute,ntEntityReference,ntEndEntity]) or (FAttrReadState <> arsNone) then
  2417. result := FCurrNode^.FLoc.Line
  2418. else
  2419. result := FTokenStart.Line;
  2420. end;
  2421. function TXMLTextReader.GetLinePosition: Integer;
  2422. begin
  2423. if (FCurrNode^.FNodeType in [ntElement,ntAttribute,ntEntityReference,ntEndEntity]) or (FAttrReadState <> arsNone) then
  2424. result := FCurrNode^.FLoc.LinePos
  2425. else
  2426. result := FTokenStart.LinePos;
  2427. end;
  2428. function TXMLTextReader.CurrentNodePtr: PPNodeData;
  2429. begin
  2430. result := @FCurrNode;
  2431. end;
  2432. function TXMLTextReader.LookupNamespace(const APrefix: XMLString): XMLString;
  2433. begin
  2434. if Assigned(FNSHelper) then
  2435. result := FNSHelper.LookupNamespace(APrefix)
  2436. else
  2437. result := '';
  2438. end;
  2439. function TXMLTextReader.MoveToFirstAttribute: Boolean;
  2440. begin
  2441. result := False;
  2442. if FAttrCount = 0 then
  2443. exit;
  2444. FCurrAttrIndex := 0;
  2445. if FAttrReadState <> arsNone then
  2446. CleanAttrReadState;
  2447. FCurrNode := @FNodeStack[FNesting+1];
  2448. result := True;
  2449. end;
  2450. function TXMLTextReader.MoveToNextAttribute: Boolean;
  2451. begin
  2452. result := False;
  2453. if FCurrAttrIndex+1 >= FAttrCount then
  2454. exit;
  2455. Inc(FCurrAttrIndex);
  2456. if FAttrReadState <> arsNone then
  2457. CleanAttrReadState;
  2458. FCurrNode := @FNodeStack[FNesting+1+FCurrAttrIndex];
  2459. result := True;
  2460. end;
  2461. function TXMLTextReader.MoveToElement: Boolean;
  2462. begin
  2463. result := False;
  2464. if FAttrReadState <> arsNone then
  2465. CleanAttrReadState
  2466. else if FCurrNode^.FNodeType <> ntAttribute then
  2467. exit;
  2468. FCurrNode := @FNodeStack[FNesting];
  2469. FCurrAttrIndex := -1;
  2470. result := True;
  2471. end;
  2472. function TXMLTextReader.ReadAttributeValue: Boolean;
  2473. var
  2474. attrNode: PNodeData;
  2475. begin
  2476. Result := False;
  2477. if FAttrReadState = arsNone then
  2478. begin
  2479. if (FReadState <> rsInteractive) or (FCurrAttrIndex < 0) then
  2480. Exit;
  2481. attrNode := @FNodeStack[FNesting+FCurrAttrIndex+1];
  2482. if attrNode^.FNext = nil then
  2483. begin
  2484. if attrNode^.FValueStr = '' then
  2485. Exit; { we don't want to expose empty textnodes }
  2486. FCurrNode := AllocNodeData(FNesting+FAttrCount+1);
  2487. FCurrNode^.FNodeType := ntText;
  2488. FCurrNode^.FValueStr := attrNode^.FValueStr;
  2489. FCurrNode^.FLoc := attrNode^.FLoc2;
  2490. end
  2491. else
  2492. FCurrNode := attrNode^.FNext;
  2493. FAttrReadState := arsText;
  2494. FAttrBaseSource := FSource;
  2495. Result := True;
  2496. end
  2497. else // already reading, advance to next chunk
  2498. begin
  2499. if FSource = FAttrBaseSource then
  2500. begin
  2501. Result := Assigned(FCurrNode^.FNext);
  2502. if Result then
  2503. FCurrNode := FCurrNode^.FNext;
  2504. end
  2505. else
  2506. begin
  2507. NextAttrValueChunk;
  2508. Result := True;
  2509. end;
  2510. end;
  2511. end;
  2512. procedure TXMLTextReader.NextAttrValueChunk;
  2513. var
  2514. wc: WideChar;
  2515. tok: TAttributeReadState;
  2516. begin
  2517. if FAttrReadState = arsPushEntity then
  2518. begin
  2519. Inc(FNesting);
  2520. { make sure that the location is available }
  2521. AllocNodeData(FNesting+FAttrCount+1);
  2522. FAttrReadState := arsText;
  2523. end;
  2524. FCurrNode := @FNodeStack[FNesting+FAttrCount+1];
  2525. StoreLocation(FCurrNode^.FLoc);
  2526. FValue.Length := 0;
  2527. if FAttrReadState = arsText then
  2528. repeat
  2529. wc := FSource.SkipUntil(FValue, [#0, '&', #9, #10, #13]);
  2530. if wc = '&' then
  2531. begin
  2532. if ParseRef(FValue) or ResolvePredefined then
  2533. Continue;
  2534. tok := arsEntity;
  2535. end
  2536. else if wc <> #0 then { #9,#10,#13 -> replace by #32 }
  2537. begin
  2538. FSource.NextChar;
  2539. BufAppend(FValue, #32);
  2540. Continue;
  2541. end
  2542. else // #0
  2543. tok := arsEntityEnd;
  2544. if FValue.Length <> 0 then
  2545. begin
  2546. FCurrNode^.FNodeType := ntText;
  2547. FCurrNode^.FQName := nil;
  2548. SetString(FCurrNode^.FValueStr, FValue.Buffer, FValue.Length);
  2549. FAttrReadState := tok;
  2550. Exit;
  2551. end;
  2552. Break;
  2553. until False
  2554. else
  2555. tok := FAttrReadState;
  2556. if tok = arsEntity then
  2557. begin
  2558. HandleEntityStart;
  2559. FAttrReadState := arsText;
  2560. end
  2561. else if tok = arsEntityEnd then
  2562. begin
  2563. HandleEntityEnd;
  2564. FAttrReadState := arsText;
  2565. end;
  2566. end;
  2567. procedure TXMLTextReader.CleanAttrReadState;
  2568. begin
  2569. while FSource <> FAttrBaseSource do
  2570. ContextPop(True);
  2571. FAttrReadState := arsNone;
  2572. end;
  2573. function TXMLTextReader.GetHasValue: Boolean;
  2574. begin
  2575. result := FCurrNode^.FNodeType in [ntAttribute,ntText,ntCDATA,
  2576. ntProcessingInstruction,ntComment,ntWhitespace,ntSignificantWhitespace,
  2577. ntDocumentType];
  2578. end;
  2579. function TXMLTextReader.GetValue: XMLString;
  2580. begin
  2581. if (FCurrAttrIndex>=0) or (FAttrReadState <> arsNone) then
  2582. result := FCurrNode^.FValueStr
  2583. else
  2584. SetString(result, FCurrNode^.FValueStart, FCurrNode^.FValueLength);
  2585. end;
  2586. function TXMLTextReader.GetPrefix: XMLString;
  2587. begin
  2588. if Assigned(FCurrNode^.FPrefix) then
  2589. result := FCurrNode^.FPrefix^.Key
  2590. else
  2591. result := '';
  2592. end;
  2593. function TXMLTextReader.GetLocalName: XMLString;
  2594. begin
  2595. if FNamespaces and Assigned(FCurrNode^.FQName) then
  2596. if FCurrNode^.FColonPos < 0 then
  2597. Result := FCurrNode^.FQName^.Key
  2598. else
  2599. Result := Copy(FCurrNode^.FQName^.Key, FCurrNode^.FColonPos+2, MaxInt)
  2600. else
  2601. Result := '';
  2602. end;
  2603. function TXMLTextReader.GetNamespaceUri: XMLString;
  2604. begin
  2605. if Assigned(FCurrNode^.FNSURI) then
  2606. result := FCurrNode^.FNSURI^.Key
  2607. else
  2608. result := '';
  2609. end;
  2610. procedure TXMLTextReader.SetEOFState;
  2611. begin
  2612. FCurrNode := @FNodeStack[0];
  2613. Finalize(FCurrNode^);
  2614. FillChar(FCurrNode^, sizeof(TNodeData), 0);
  2615. FReadState := rsEndOfFile;
  2616. end;
  2617. procedure TXMLTextReader.ValidateCurrentNode;
  2618. var
  2619. ElDef: TElementDecl;
  2620. AttDef: TAttributeDef;
  2621. attr: PNodeData;
  2622. i: Integer;
  2623. begin
  2624. case FCurrNode^.FNodeType of
  2625. ntElement:
  2626. begin
  2627. if (FNesting = 0) and (not FFragmentMode) then
  2628. begin
  2629. if Assigned(FDocType) then
  2630. begin
  2631. if FDocType.FName <> FCurrNode^.FQName^.Key then
  2632. DoErrorPos(esError, 'Root element name does not match DTD', FCurrNode^.FLoc);
  2633. end
  2634. else
  2635. DoErrorPos(esError, 'Missing DTD', FCurrNode^.FLoc);
  2636. end;
  2637. ElDef := TElementDecl(FCurrNode^.FQName^.Data);
  2638. if (ElDef = nil) or (ElDef.ContentType = ctUndeclared) then
  2639. DoErrorPos(esError, 'Using undeclared element ''%s''',[FCurrNode^.FQName^.Key], FCurrNode^.FLoc);
  2640. if not FValidators[FValidatorNesting].IsElementAllowed(ElDef) then
  2641. DoErrorPos(esError, 'Element ''%s'' is not allowed in this context',[FCurrNode^.FQName^.Key], FCurrNode^.FLoc);
  2642. PushVC(ElDef);
  2643. if ElDef = nil then
  2644. Exit;
  2645. { Validate attributes }
  2646. for i := 1 to FAttrCount do
  2647. begin
  2648. attr := @FNodeStack[FNesting+i];
  2649. AttDef := TAttributeDef(attr^.FTypeInfo);
  2650. if AttDef = nil then
  2651. DoErrorPos(esError, 'Using undeclared attribute ''%s'' on element ''%s''',
  2652. [attr^.FQName^.Key, FCurrNode^.FQName^.Key], attr^.FLoc)
  2653. else if ((AttDef.DataType <> dtCdata) or (AttDef.Default = adFixed)) then
  2654. begin
  2655. if FStandalone and AttDef.ExternallyDeclared then
  2656. if attr^.FDenormalized then
  2657. DoErrorPos(esError, 'In a standalone document, externally defined attribute cannot cause value normalization', attr^.FLoc2)
  2658. else if i > FSpecifiedAttrs then
  2659. DoError(esError, 'In a standalone document, attribute cannot have a default value defined externally');
  2660. // TODO: what about normalization of AttDef.Value? (Currently it IS normalized)
  2661. if (AttDef.Default = adFixed) and (AttDef.Data^.FValueStr <> attr^.FValueStr) then
  2662. DoErrorPos(esError, 'Value of attribute ''%s'' does not match its #FIXED default',[attr^.FQName^.Key], attr^.FLoc2);
  2663. if not AttDef.ValidateSyntax(attr^.FValueStr, FNamespaces) then
  2664. DoErrorPos(esError, 'Attribute ''%s'' type mismatch', [attr^.FQName^.Key], attr^.FLoc2);
  2665. ValidateAttrValue(AttDef, attr);
  2666. end;
  2667. end;
  2668. { Check presence of #REQUIRED attributes }
  2669. if ElDef.HasRequiredAtts then
  2670. for i := 0 to ElDef.AttrDefCount-1 do
  2671. begin
  2672. if FAttrDefIndex[i] = FAttrTag then
  2673. Continue;
  2674. AttDef := ElDef.AttrDefs[i];
  2675. if AttDef.Default = adRequired then
  2676. ValidationError('Required attribute ''%s'' of element ''%s'' is missing',
  2677. [AttDef.Data^.FQName^.Key, FCurrNode^.FQName^.Key], 0)
  2678. end;
  2679. end;
  2680. ntEndElement:
  2681. begin
  2682. if FValidators[FValidatorNesting].Incomplete then
  2683. ValidationError('Element ''%s'' is missing required sub-elements', [FCurrNode^.FQName^.Key], -1);
  2684. if FValidatorNesting > 0 then
  2685. Dec(FValidatorNesting);
  2686. end;
  2687. ntText, ntSignificantWhitespace:
  2688. case FValidators[FValidatorNesting].FContentType of
  2689. ctChildren:
  2690. if FCurrNode^.FNodeType = ntText then
  2691. ValidationError('Character data is not allowed in element-only content',[])
  2692. else
  2693. begin
  2694. if FValidators[FValidatorNesting].FSaViolation then
  2695. ValidationError('Standalone constraint violation',[]);
  2696. FCurrNode^.FNodeType := ntWhitespace;
  2697. end;
  2698. ctEmpty:
  2699. ValidationError('Character data is not allowed in EMPTY elements', []);
  2700. end;
  2701. ntCDATA:
  2702. if FValidators[FValidatorNesting].FContentType = ctChildren then
  2703. ValidationError('CDATA sections are not allowed in element-only content',[]);
  2704. ntProcessingInstruction:
  2705. if FValidators[FValidatorNesting].FContentType = ctEmpty then
  2706. ValidationError('Processing instructions are not allowed within EMPTY elements', []);
  2707. ntComment:
  2708. if FValidators[FValidatorNesting].FContentType = ctEmpty then
  2709. ValidationError('Comments are not allowed within EMPTY elements', []);
  2710. ntDocumentType:
  2711. ValidateDTD;
  2712. end;
  2713. end;
  2714. procedure TXMLTextReader.HandleEntityStart;
  2715. begin
  2716. FCurrNode := @FNodeStack[FNesting+(FAttrCount+1)*ord(FAttrReadState<>arsNone)];
  2717. FCurrNode^.FNodeType := ntEntityReference;
  2718. FCurrNode^.FQName := FNameTable.FindOrAdd(FName.Buffer, FName.Length);
  2719. FCurrNode^.FColonPos := -1;
  2720. FCurrNode^.FValueStart := nil;
  2721. FCurrNode^.FValueLength := 0;
  2722. FCurrNode^.FValueStr := '';
  2723. StoreLocation(FCurrNode^.FLoc);
  2724. { point past '&' to first AnsiChar of entity name }
  2725. Dec(FCurrNode^.FLoc.LinePos, FName.Length+1);
  2726. end;
  2727. procedure TXMLTextReader.HandleEntityEnd;
  2728. begin
  2729. ContextPop(True);
  2730. if FNesting > 0 then Dec(FNesting);
  2731. FCurrNode := @FNodeStack[FNesting+(FAttrCount+1)*ord(FAttrReadState<>arsNone)];
  2732. FCurrNode^.FNodeType := ntEndEntity;
  2733. { point to trailing ';' }
  2734. Inc(FCurrNode^.FLoc.LinePos, Length(FCurrNode^.FQName^.Key));
  2735. end;
  2736. procedure TXMLTextReader.ResolveEntity;
  2737. var
  2738. n: PNodeData;
  2739. ent: TEntityDecl;
  2740. begin
  2741. if FCurrNode^.FNodeType <> ntEntityReference then
  2742. raise EInvalidOperation.Create('Wrong node type');
  2743. if FAttrReadState <> arsNone then
  2744. begin
  2745. { copy the EntityReference node to the stack if not already there }
  2746. n := AllocNodeData(FNesting+FAttrCount+1);
  2747. if n <> FCurrNode then
  2748. n^ := FCurrNode^;
  2749. ent := nil;
  2750. if Assigned(FDocType) then
  2751. ent := FDocType.Entities.Get(PWideChar(n^.FQName^.Key),Length(n^.FQName^.Key)) as TEntityDecl;
  2752. ContextPush(ent, True);
  2753. FAttrReadState := arsPushEntity;
  2754. end
  2755. else
  2756. FNext := xtPushEntity;
  2757. end;
  2758. procedure TXMLTextReader.DoStartEntity;
  2759. begin
  2760. Inc(FNesting);
  2761. FCurrNode := AllocNodeData(FNesting);
  2762. ContextPush(FCurrEntity, True);
  2763. FNext := xtText;
  2764. end;
  2765. // The code below does the bulk of the parsing, and must be as fast as possible.
  2766. // To minimize CPU cache effects, methods from different classes are kept together
  2767. function TXMLDecodingSource.SkipUntil(var ToFill: TWideCharBuf; const Delim: TSetOfChar;
  2768. wsflag: PBoolean): WideChar;
  2769. var
  2770. old: PWideChar;
  2771. nonws: Boolean;
  2772. wc: WideChar;
  2773. begin
  2774. nonws := False;
  2775. repeat
  2776. old := FBuf;
  2777. repeat
  2778. wc := FBuf^;
  2779. if (wc = #10) or (wc = #13) or (FXML11Rules and ((wc = #$85) or
  2780. (wc = #$2028))) then
  2781. begin
  2782. // strictly this is needed only for 2-byte lineendings
  2783. BufAppendChunk(ToFill, old, FBuf);
  2784. NewLine;
  2785. old := FBuf;
  2786. wc := FBuf^
  2787. end
  2788. else if ((wc < #32) and (not ((wc = #0) and (FBuf >= FBufEnd))) and
  2789. (wc <> #9)) or (wc > #$FFFD) or
  2790. (FXML11Rules and (wc >= #$7F) and (wc <= #$9F)) then
  2791. FReader.FatalError('Invalid character');
  2792. if (wc < #255) and (AnsiChar(ord(wc)) in Delim) then
  2793. Break;
  2794. // the checks above filter away everything below #32 that isn't a whitespace
  2795. if wc > #32 then
  2796. nonws := True;
  2797. Inc(FBuf);
  2798. until False;
  2799. Result := wc;
  2800. BufAppendChunk(ToFill, old, FBuf);
  2801. until (Result <> #0) or (not Reload);
  2802. if Assigned(wsflag) then
  2803. wsflag^ := wsflag^ or nonws;
  2804. end;
  2805. const
  2806. TextDelims: array[Boolean] of TSetOfChar = (
  2807. [#0, '<', '&', '>'],
  2808. [#0, '>']
  2809. );
  2810. textNodeTypes: array[Boolean] of TXMLNodeType = (
  2811. ntSignificantWhitespace,
  2812. ntText
  2813. );
  2814. function TXMLTextReader.ReadTopLevel: Boolean;
  2815. var
  2816. tok: TXMLToken;
  2817. begin
  2818. if FNext = xtFakeLF then
  2819. begin
  2820. Result := SetupFakeLF(xtText);
  2821. Exit;
  2822. end;
  2823. StoreLocation(FTokenStart);
  2824. if FNext = xtText then
  2825. repeat
  2826. SkipS;
  2827. if FSource.FBuf^ = '<' then
  2828. begin
  2829. Inc(FSource.FBuf);
  2830. if FSource.FBufEnd < FSource.FBuf + 2 then
  2831. FSource.Reload;
  2832. if FSource.FBuf^ = '!' then
  2833. begin
  2834. Inc(FSource.FBuf);
  2835. if FSource.FBuf^ = '-' then
  2836. begin
  2837. if FIgnoreComments then
  2838. begin
  2839. ParseComment(True);
  2840. Continue;
  2841. end;
  2842. tok := xtComment;
  2843. end
  2844. else
  2845. tok := xtDoctype;
  2846. end
  2847. else if FSource.FBuf^ = '?' then
  2848. tok := xtPI
  2849. else
  2850. begin
  2851. CheckName;
  2852. tok := xtElement;
  2853. end;
  2854. end
  2855. else if FSource.FBuf >= FSource.FBufEnd then
  2856. begin
  2857. if FState < rsRoot then
  2858. FatalError('Root element is missing');
  2859. tok := xtEOF;
  2860. end
  2861. else
  2862. FatalError('Illegal at document level');
  2863. if FCanonical and (FState > rsRoot) and (tok <> xtEOF) then
  2864. begin
  2865. Result := SetupFakeLF(tok);
  2866. Exit;
  2867. end;
  2868. Break;
  2869. until False
  2870. else // FNext <> xtText
  2871. tok := FNext;
  2872. if FCanonical and (FState < rsRoot) and (tok <> xtDoctype) then
  2873. FNext := xtFakeLF
  2874. else
  2875. FNext := xtText;
  2876. case tok of
  2877. xtElement:
  2878. begin
  2879. if FState > rsRoot then
  2880. FatalError('Only one top-level element allowed', FName.Length)
  2881. else if FState < rsRoot then
  2882. begin
  2883. // dispose notation refs from DTD, if any
  2884. ClearForwardRefs;
  2885. FState := rsRoot;
  2886. end;
  2887. ParseStartTag;
  2888. end;
  2889. xtPI: ParsePI;
  2890. xtComment: ParseComment(False);
  2891. xtDoctype:
  2892. begin
  2893. ParseDoctypeDecl;
  2894. if FCanonical then
  2895. begin
  2896. // recurse, effectively ignoring the DTD
  2897. result := ReadTopLevel();
  2898. Exit;
  2899. end;
  2900. end;
  2901. xtEOF: SetEofState;
  2902. end;
  2903. Result := tok <> xtEOF;
  2904. end;
  2905. function TXMLTextReader.Read: Boolean;
  2906. var
  2907. nonWs: Boolean;
  2908. wc: WideChar;
  2909. InCDATA: Boolean;
  2910. tok: TXMLToken;
  2911. begin
  2912. if FReadState > rsInteractive then
  2913. begin
  2914. Result := False;
  2915. Exit;
  2916. end;
  2917. if FReadState = rsInitial then
  2918. begin
  2919. FReadState := rsInteractive;
  2920. FSource.Initialize;
  2921. FNext := xtText;
  2922. end;
  2923. if FAttrReadState <> arsNone then
  2924. CleanAttrReadState;
  2925. if FNext = xtPopEmptyElement then
  2926. begin
  2927. FNext := xtPopElement;
  2928. FCurrNode^.FNodeType := ntEndElement;
  2929. if FAttrCleanupFlag then
  2930. CleanupAttributes;
  2931. FAttrCount := 0;
  2932. FCurrAttrIndex := -1;
  2933. Result := True;
  2934. Exit;
  2935. end;
  2936. if FNext = xtPushElement then
  2937. begin
  2938. if FAttrCleanupFlag then
  2939. CleanupAttributes;
  2940. FAttrCount := 0;
  2941. Inc(FNesting);
  2942. FCurrAttrIndex := -1;
  2943. FNext := xtText;
  2944. end
  2945. else if FNext = xtPopElement then
  2946. PopElement
  2947. else if FNext = xtPushEntity then
  2948. DoStartEntity;
  2949. if FState <> rsRoot then
  2950. begin
  2951. Result := ReadTopLevel;
  2952. Exit;
  2953. end;
  2954. InCDATA := (FNext = xtCDSect);
  2955. StoreLocation(FTokenStart);
  2956. nonWs := False;
  2957. FValue.Length := 0;
  2958. if FNext in [xtCDSect, xtText] then
  2959. repeat
  2960. wc := FSource.SkipUntil(FValue, TextDelims[InCDATA], @nonWs);
  2961. if wc = '<' then
  2962. begin
  2963. Inc(FSource.FBuf);
  2964. if FSource.FBufEnd < FSource.FBuf + 2 then
  2965. FSource.Reload;
  2966. if FSource.FBuf^ = '/' then
  2967. tok := xtEndElement
  2968. else if CheckName([cnOptional]) then
  2969. tok := xtElement
  2970. else if FSource.FBuf^ = '!' then
  2971. begin
  2972. Inc(FSource.FBuf);
  2973. if FSource.FBuf^ = '[' then
  2974. begin
  2975. ExpectString('[CDATA[');
  2976. StoreLocation(FTokenStart);
  2977. InCDATA := True;
  2978. if FCDSectionsAsText or (FValue.Length = 0) then
  2979. Continue;
  2980. tok := xtCDSect;
  2981. end
  2982. else if FSource.FBuf^ = '-' then
  2983. begin
  2984. { Ignoring comments is tricky in validating mode; discarding a comment which
  2985. is the only child of an EMPTY element will make that element erroneously appear
  2986. as valid. Therefore, at this point we discard only comments which are preceded
  2987. by some text (since presence of text already renders an EMPTY element invalid).
  2988. Other comments should be reported to validation part and discarded there. }
  2989. if FIgnoreComments and (FValue.Length > 0) then
  2990. begin
  2991. ParseComment(True);
  2992. Continue;
  2993. end;
  2994. tok := xtComment;
  2995. end
  2996. else
  2997. tok := xtDoctype;
  2998. end
  2999. else if FSource.FBuf^ = '?' then
  3000. tok := xtPI
  3001. else
  3002. RaiseNameNotFound;
  3003. end
  3004. else if wc = #0 then
  3005. begin
  3006. if InCDATA then
  3007. FatalError('Unterminated CDATA section', -1);
  3008. if FNesting > FSource.FStartNesting then
  3009. FatalError('End-tag is missing for ''%s''', [FNodeStack[FNesting-1].FQName^.Key]);
  3010. if Assigned(FSource.FParent) then
  3011. begin
  3012. if FExpandEntities and ContextPop then
  3013. Continue
  3014. else
  3015. tok := xtEntityEnd;
  3016. end
  3017. else
  3018. tok := xtEOF;
  3019. end
  3020. else if wc = '>' then
  3021. begin
  3022. BufAppend(FValue, wc);
  3023. FSource.NextChar;
  3024. if (FValue.Length <= 2) or (FValue.Buffer[FValue.Length-2] <> ']') or
  3025. (FValue.Buffer[FValue.Length-3] <> ']') then Continue;
  3026. if InCData then // got a ']]>' separator
  3027. begin
  3028. Dec(FValue.Length, 3);
  3029. InCDATA := False;
  3030. if FCDSectionsAsText then
  3031. Continue;
  3032. SetNodeInfoWithValue(ntCDATA);
  3033. FNext := xtText;
  3034. Result := True;
  3035. Exit;
  3036. end
  3037. else
  3038. FatalError('Literal '']]>'' is not allowed in text', 3);
  3039. end
  3040. else if wc = '&' then
  3041. begin
  3042. if FValidators[FValidatorNesting].FContentType = ctEmpty then
  3043. ValidationError('References are illegal in EMPTY elements', []);
  3044. if ParseRef(FValue) or ResolvePredefined then
  3045. begin
  3046. nonWs := True; // CharRef to whitespace is not considered whitespace
  3047. Continue;
  3048. end
  3049. else
  3050. begin
  3051. FCurrEntity := EntityCheck;
  3052. if Assigned(FCurrEntity) and FExpandEntities then
  3053. begin
  3054. ContextPush(FCurrEntity);
  3055. Continue;
  3056. end;
  3057. tok := xtEntity;
  3058. end;
  3059. end;
  3060. if FValue.Length <> 0 then
  3061. begin
  3062. SetNodeInfoWithValue(textNodeTypes[nonWs]);
  3063. FNext := tok;
  3064. Result := True;
  3065. Exit;
  3066. end;
  3067. Break;
  3068. until False
  3069. else // not (FNext in [xtText, xtCDSect])
  3070. tok := FNext;
  3071. FNext := xtText;
  3072. case tok of
  3073. xtEntity: HandleEntityStart;
  3074. xtEntityEnd: HandleEntityEnd;
  3075. xtElement: ParseStartTag;
  3076. xtEndElement: ParseEndTag;
  3077. xtPI: ParsePI;
  3078. xtDoctype: ParseDoctypeDecl;
  3079. xtComment: ParseComment(False);
  3080. xtEOF: SetEofState;
  3081. end;
  3082. Result := tok <> xtEOF;
  3083. end;
  3084. procedure TXMLCharSource.NextChar;
  3085. begin
  3086. Inc(FBuf);
  3087. if FBuf >= FBufEnd then
  3088. Reload;
  3089. end;
  3090. procedure TXMLTextReader.ExpectChar(wc: WideChar);
  3091. begin
  3092. if FSource.FBuf^ = wc then
  3093. FSource.NextChar
  3094. else
  3095. FatalError(wc);
  3096. end;
  3097. // Element name already in FNameBuffer
  3098. procedure TXMLTextReader.ParseStartTag; // [39] [40] [44]
  3099. var
  3100. ElDef: TElementDecl;
  3101. IsEmpty: Boolean;
  3102. ElName: PHashItem;
  3103. b: TBinding;
  3104. Len: Integer;
  3105. begin
  3106. ElName := FNameTable.FindOrAdd(FName.Buffer, FName.Length);
  3107. ElDef := TElementDecl(ElName^.Data);
  3108. if Assigned(ElDef) then
  3109. Len := ElDef.AttrDefCount+8 { overallocate a bit }
  3110. else
  3111. Len := 0;
  3112. // (re)initialize array of attribute definition tags
  3113. if (Len-8 > Length(FAttrDefIndex)) or (FAttrTag = 0) then
  3114. begin
  3115. SetLength(FAttrDefIndex, Len);
  3116. for Len := 0 to High(FAttrDefIndex) do
  3117. FAttrDefIndex[Len] := FAttrTag;
  3118. end;
  3119. // we're about to process a new set of attributes
  3120. {$push}{$r-,q-}
  3121. Dec(FAttrTag);
  3122. {$pop}
  3123. IsEmpty := False;
  3124. FAttrCount := 0;
  3125. FCurrAttrIndex := -1;
  3126. FPrefixedAttrs := 0;
  3127. FSpecifiedAttrs := 0;
  3128. FCurrNode := AllocNodeData(FNesting);
  3129. FCurrNode^.FQName := ElName;
  3130. FCurrNode^.FNodeType := ntElement;
  3131. FCurrNode^.FColonPos := FColonPos;
  3132. StoreLocation(FCurrNode^.FLoc);
  3133. Dec(FCurrNode^.FLoc.LinePos, FName.Length);
  3134. if FNamespaces then
  3135. begin
  3136. FNSHelper.PushScope;
  3137. if FColonPos > 0 then
  3138. FCurrNode^.FPrefix := FNSHelper.GetPrefix(FName.Buffer, FColonPos);
  3139. end;
  3140. while (FSource.FBuf^ <> '>') and (FSource.FBuf^ <> '/') do
  3141. begin
  3142. SkipS(True);
  3143. if (FSource.FBuf^ = '>') or (FSource.FBuf^ = '/') then
  3144. Break;
  3145. ParseAttribute(ElDef);
  3146. end;
  3147. if FSource.FBuf^ = '/' then
  3148. begin
  3149. IsEmpty := True;
  3150. FSource.NextChar;
  3151. end;
  3152. ExpectChar('>');
  3153. if Assigned(ElDef) and ElDef.NeedsDefaultPass then
  3154. ProcessDefaultAttributes(ElDef);
  3155. // Adding attributes might have reallocated FNodeStack, so restore FCurrNode once again
  3156. FCurrNode := @FNodeStack[FNesting];
  3157. if FNamespaces then
  3158. begin
  3159. { Assign namespace URIs to prefixed attrs }
  3160. if FPrefixedAttrs <> 0 then
  3161. ProcessNamespaceAtts;
  3162. { Expand the element name }
  3163. if Assigned(FCurrNode^.FPrefix) then
  3164. begin
  3165. b := TBinding(FCurrNode^.FPrefix^.Data);
  3166. if not (Assigned(b) and Assigned(b.uri) and (b.uri^.Key <> '')) then
  3167. DoErrorPos(esFatal, 'Unbound element name prefix "%s"', [FCurrNode^.FPrefix^.Key],FCurrNode^.FLoc);
  3168. FCurrNode^.FNsUri := b.uri;
  3169. end
  3170. else
  3171. begin
  3172. b := FNSHelper.DefaultNSBinding;
  3173. if Assigned(b) then
  3174. FCurrNode^.FNsUri := b.uri;
  3175. end;
  3176. end;
  3177. if not IsEmpty then
  3178. begin
  3179. if not FPreserveWhitespace then // critical for testsuite compliance
  3180. SkipS;
  3181. FNext := xtPushElement;
  3182. end
  3183. else
  3184. FNext := xtPopEmptyElement;
  3185. end;
  3186. procedure TXMLTextReader.ParseEndTag; // [42]
  3187. var
  3188. ElName: PHashItem;
  3189. begin
  3190. if FNesting <= FSource.FStartNesting then
  3191. FatalError('End-tag is not allowed here');
  3192. if FNesting > 0 then Dec(FNesting);
  3193. Inc(FSource.FBuf);
  3194. FCurrNode := @FNodeStack[FNesting]; // move off the possible child
  3195. FCurrNode^.FNodeType := ntEndElement;
  3196. StoreLocation(FTokenStart);
  3197. FCurrNode^.FLoc := FTokenStart;
  3198. ElName := FCurrNode^.FQName;
  3199. if not FSource.MatchesLong(ElName^.Key) then
  3200. FatalError('Unmatching element end tag (expected "</%s>")', [ElName^.Key], -1);
  3201. if FSource.FBuf^ = '>' then // this handles majority of cases
  3202. FSource.NextChar
  3203. else
  3204. begin // gives somewhat incorrect message for <a></aa>
  3205. SkipS;
  3206. ExpectChar('>');
  3207. end;
  3208. FNext := xtPopElement;
  3209. end;
  3210. procedure TXMLTextReader.ParseAttribute(ElDef: TElementDecl);
  3211. var
  3212. attrName: PHashItem;
  3213. attrData: PNodeData;
  3214. AttDef: TAttributeDef;
  3215. i: Integer;
  3216. begin
  3217. CheckName;
  3218. attrName := FNameTable.FindOrAdd(FName.Buffer, FName.Length);
  3219. attrData := AllocAttributeData;
  3220. attrData^.FQName := attrName;
  3221. attrData^.FColonPos := FColonPos;
  3222. StoreLocation(attrData^.FLoc);
  3223. Dec(attrData^.FLoc.LinePos, FName.Length);
  3224. FSpecifiedAttrs := FAttrCount;
  3225. if Assigned(ElDef) then
  3226. begin
  3227. AttDef := ElDef.GetAttrDef(attrName);
  3228. // mark attribute as specified
  3229. if Assigned(AttDef) then
  3230. FAttrDefIndex[AttDef.Index] := FAttrTag;
  3231. end
  3232. else
  3233. AttDef := nil;
  3234. attrData^.FTypeInfo := AttDef;
  3235. // check for duplicates
  3236. for i := 1 to FAttrCount-1 do
  3237. if FNodeStack[FNesting+i].FQName = attrName then
  3238. FatalError('Duplicate attribute', FName.Length);
  3239. if FNamespaces then
  3240. begin
  3241. if ((FName.Length = 5) or (FColonPos = 5)) and
  3242. (FName.Buffer[0] = 'x') and (FName.Buffer[1] = 'm') and
  3243. (FName.Buffer[2] = 'l') and (FName.Buffer[3] = 'n') and
  3244. (FName.Buffer[4] = 's') then
  3245. begin
  3246. if FColonPos > 0 then
  3247. attrData^.FPrefix := FStdPrefix_xmlns;
  3248. attrData^.FNsUri := FStdUri_xmlns;
  3249. end
  3250. else if FColonPos > 0 then
  3251. begin
  3252. attrData^.FPrefix := FNSHelper.GetPrefix(FName.Buffer, FColonPos);
  3253. Inc(FPrefixedAttrs);
  3254. end;
  3255. end;
  3256. ExpectEq;
  3257. ExpectAttValue(attrData, Assigned(AttDef) and (AttDef.DataType <> dtCDATA));
  3258. if Assigned(attrData^.FNsUri) then
  3259. begin
  3260. if (not AddBinding(attrData)) and FCanonical then
  3261. begin
  3262. CleanupAttribute(attrData);
  3263. Dec(FAttrCount);
  3264. Dec(FSpecifiedAttrs);
  3265. end;
  3266. end;
  3267. end;
  3268. procedure TXMLTextReader.AddForwardRef(Buf: PWideChar; Length: Integer);
  3269. var
  3270. w: PForwardRef;
  3271. begin
  3272. if FForwardRefs = nil then
  3273. FForwardRefs := TFPList.Create;
  3274. New(w);
  3275. SetString(w^.Value, Buf, Length);
  3276. w^.Loc := FTokenStart;
  3277. FForwardRefs.Add(w);
  3278. end;
  3279. procedure TXMLTextReader.ClearForwardRefs;
  3280. var
  3281. I: Integer;
  3282. begin
  3283. if Assigned(FForwardRefs) then
  3284. begin
  3285. for I := 0 to FForwardRefs.Count-1 do
  3286. Dispose(PForwardRef(FForwardRefs.List^[I]));
  3287. FForwardRefs.Clear;
  3288. end;
  3289. end;
  3290. procedure TXMLTextReader.ValidateIdRefs;
  3291. var
  3292. I: Integer;
  3293. begin
  3294. if Assigned(FForwardRefs) then
  3295. begin
  3296. for I := 0 to FForwardRefs.Count-1 do
  3297. with PForwardRef(FForwardRefs.List^[I])^ do
  3298. if (FIDMap = nil) or (FIDMap.Find(PWideChar(Value), Length(Value)) = nil) then
  3299. DoErrorPos(esError, 'The ID ''%s'' does not match any element', [Value], Loc);
  3300. ClearForwardRefs;
  3301. end;
  3302. end;
  3303. procedure TXMLTextReader.ProcessDefaultAttributes(ElDef: TElementDecl);
  3304. var
  3305. I: Integer;
  3306. AttDef: TAttributeDef;
  3307. attrData: PNodeData;
  3308. begin
  3309. for I := 0 to ElDef.AttrDefCount-1 do
  3310. begin
  3311. if FAttrDefIndex[I] <> FAttrTag then // this one wasn't specified
  3312. begin
  3313. AttDef := ElDef.AttrDefs[I];
  3314. case AttDef.Default of
  3315. adDefault, adFixed: begin
  3316. attrData := AllocAttributeData;
  3317. attrData^ := AttDef.Data^;
  3318. if FCanonical then
  3319. attrData^.FIsDefault := False;
  3320. if FNamespaces then
  3321. begin
  3322. if AttDef.IsNamespaceDecl then
  3323. begin
  3324. if attrData^.FColonPos > 0 then
  3325. attrData^.FPrefix := FStdPrefix_xmlns;
  3326. attrData^.FNsUri := FStdUri_xmlns;
  3327. if (not AddBinding(attrData)) and FCanonical then
  3328. Dec(FAttrCount);
  3329. end
  3330. else if attrData^.FColonPos > 0 then
  3331. begin
  3332. attrData^.FPrefix := FNSHelper.GetPrefix(PWideChar(attrData^.FQName^.Key), attrData^.FColonPos);
  3333. Inc(FPrefixedAttrs);
  3334. end
  3335. else
  3336. attrData^.FNsUri := FEmptyStr;
  3337. end;
  3338. end;
  3339. end;
  3340. end;
  3341. end;
  3342. end;
  3343. function TXMLTextReader.AddBinding(attrData: PNodeData): Boolean;
  3344. var
  3345. nsUri, Pfx: PHashItem;
  3346. begin
  3347. nsUri := FNameTable.FindOrAdd(attrData^.FValueStr);
  3348. if attrData^.FColonPos > 0 then
  3349. Pfx := FNSHelper.GetPrefix(@attrData^.FQName^.key[7], Length(attrData^.FQName^.key)-6)
  3350. else
  3351. Pfx := FNSHelper.GetPrefix(nil, 0); { will return the default prefix }
  3352. { 'xml' is allowed to be bound to the correct namespace }
  3353. if ((nsUri = FStduri_xml) <> (Pfx = FStdPrefix_xml)) or
  3354. (Pfx = FStdPrefix_xmlns) or
  3355. (nsUri = FStduri_xmlns) then
  3356. begin
  3357. if (Pfx = FStdPrefix_xml) or (Pfx = FStdPrefix_xmlns) then
  3358. DoErrorPos(esFatal, 'Illegal usage of reserved prefix ''%s''', [Pfx^.Key], attrData^.FLoc)
  3359. else
  3360. DoErrorPos(esFatal, 'Illegal usage of reserved namespace URI ''%s''', [attrData^.FValueStr], attrData^.FLoc2);
  3361. end;
  3362. if (attrData^.FValueStr = '') and not (FXML11 or (Pfx^.Key = '')) then
  3363. DoErrorPos(esFatal, 'Illegal undefining of namespace', attrData^.FLoc2);
  3364. Result := (Pfx^.Data = nil) or (TBinding(Pfx^.Data).uri <> nsUri);
  3365. if Result then
  3366. FNSHelper.BindPrefix(nsUri, Pfx);
  3367. end;
  3368. procedure TXMLTextReader.ProcessNamespaceAtts;
  3369. var
  3370. I, J: Integer;
  3371. Pfx, AttrName: PHashItem;
  3372. attrData: PNodeData;
  3373. b: TBinding;
  3374. begin
  3375. FNsAttHash.Init(FPrefixedAttrs);
  3376. for I := 1 to FAttrCount do
  3377. begin
  3378. attrData := @FNodeStack[FNesting+i];
  3379. if Assigned(attrData^.FNsUri) then
  3380. Continue;
  3381. if (attrData^.FColonPos < 1) then
  3382. begin
  3383. attrData^.FNsUri := FEmptyStr;
  3384. Continue;
  3385. end;
  3386. Pfx := attrData^.FPrefix;
  3387. b := TBinding(Pfx^.Data);
  3388. if not (Assigned(b) and Assigned (b.uri) and (b.uri^.Key <> '')) then
  3389. DoErrorPos(esFatal, 'Unbound attribute name prefix "%s"', [Pfx^.Key], attrData^.FLoc);
  3390. { detect duplicates }
  3391. J := attrData^.FColonPos+1;
  3392. AttrName := attrData^.FQName;
  3393. if FNsAttHash.Locate(b.uri, @AttrName^.Key[J], Length(AttrName^.Key) - J+1) then
  3394. DoErrorPos(esFatal, 'Duplicate prefixed attribute', attrData^.FLoc);
  3395. attrData^.FNsUri := b.uri;
  3396. end;
  3397. end;
  3398. function TXMLTextReader.ParseExternalID(out SysID, PubID: XMLString; // [75]
  3399. out PubIDLoc: TLocation; SysIdOptional: Boolean): Boolean;
  3400. var
  3401. I: Integer;
  3402. wc: WideChar;
  3403. begin
  3404. Result := False;
  3405. if FSource.Matches('SYSTEM') then
  3406. SysIdOptional := False
  3407. else if FSource.Matches('PUBLIC') then
  3408. begin
  3409. ExpectWhitespace;
  3410. ParseLiteral(FValue, ltPubid, True);
  3411. PubIDLoc := FTokenStart;
  3412. SetString(PubID, FValue.Buffer, FValue.Length);
  3413. for I := 1 to Length(PubID) do
  3414. begin
  3415. wc := PubID[I];
  3416. if (wc > #255) or not (AnsiChar(ord(wc)) in PubidChars) then
  3417. FatalError('Illegal Public ID literal', -1);
  3418. end;
  3419. end
  3420. else
  3421. Exit;
  3422. if SysIdOptional then
  3423. SkipWhitespace
  3424. else
  3425. ExpectWhitespace;
  3426. if ParseLiteral(FValue, ltPlain, not SysIdOptional) then
  3427. SetString(SysID, FValue.Buffer, FValue.Length);
  3428. Result := True;
  3429. end;
  3430. procedure TXMLTextReader.ValidateAttrValue(AttrDef: TAttributeDef; attrData: PNodeData);
  3431. var
  3432. L, StartPos, EndPos: Integer;
  3433. Entity: TEntityDecl;
  3434. begin
  3435. L := Length(attrData^.FValueStr);
  3436. case AttrDef.DataType of
  3437. dtId: begin
  3438. if not AddID(attrData) then
  3439. DoErrorPos(esError, 'The ID ''%s'' is not unique', [attrData^.FValueStr], attrData^.FLoc2);
  3440. end;
  3441. dtIdRef, dtIdRefs: begin
  3442. StartPos := 1;
  3443. while StartPos <= L do
  3444. begin
  3445. EndPos := StartPos;
  3446. while (EndPos <= L) and (attrData^.FValueStr[EndPos] <> #32) do
  3447. Inc(EndPos);
  3448. if (FIDMap = nil) or (FIDMap.Find(@attrData^.FValueStr[StartPos], EndPos-StartPos) = nil) then
  3449. AddForwardRef(@attrData^.FValueStr[StartPos], EndPos-StartPos);
  3450. StartPos := EndPos + 1;
  3451. end;
  3452. end;
  3453. dtEntity, dtEntities: begin
  3454. StartPos := 1;
  3455. while StartPos <= L do
  3456. begin
  3457. EndPos := StartPos;
  3458. while (EndPos <= L) and (attrData^.FValueStr[EndPos] <> #32) do
  3459. Inc(EndPos);
  3460. Entity := TEntityDecl(FDocType.Entities.Get(@attrData^.FValueStr[StartPos], EndPos-StartPos));
  3461. if (Entity = nil) or (Entity.FNotationName = '') then
  3462. ValidationError('Attribute ''%s'' type mismatch', [attrData^.FQName^.Key], -1);
  3463. StartPos := EndPos + 1;
  3464. end;
  3465. end;
  3466. end;
  3467. end;
  3468. procedure TXMLTextReader.ValidateDTD;
  3469. var
  3470. I: Integer;
  3471. begin
  3472. if Assigned(FForwardRefs) then
  3473. begin
  3474. for I := 0 to FForwardRefs.Count-1 do
  3475. with PForwardRef(FForwardRefs[I])^ do
  3476. if FDocType.Notations.Get(PWideChar(Value), Length(Value)) = nil then
  3477. DoErrorPos(esError, 'Notation ''%s'' is not declared', [Value], Loc);
  3478. end;
  3479. end;
  3480. function TXMLTextReader.AddId(aNodeData: PNodeData): Boolean;
  3481. var
  3482. e: PHashItem;
  3483. begin
  3484. if FIDMap = nil then
  3485. FIDMap := THashTable.Create(256, False);
  3486. e := FIDMap.FindOrAdd(PWideChar(aNodeData^.FValueStr), Length(aNodeData^.FValueStr), Result);
  3487. Result := not Result;
  3488. if Result then
  3489. aNodeData^.FIDEntry := e;
  3490. end;
  3491. function TXMLTextReader.AllocAttributeData: PNodeData;
  3492. begin
  3493. Result := AllocNodeData(FNesting + FAttrCount + 1);
  3494. Result^.FNodeType := ntAttribute;
  3495. Result^.FIsDefault := False;
  3496. Inc(FAttrCount);
  3497. end;
  3498. procedure TXMLTextReader.AddPseudoAttribute(aName: PHashItem; const aValue: XMLString;
  3499. const nameLoc, valueLoc: TLocation);
  3500. begin
  3501. with AllocAttributeData^ do
  3502. begin
  3503. FQName := aName;
  3504. FColonPos := -1;
  3505. FValueStr := aValue;
  3506. FLoc := nameLoc;
  3507. FLoc2 := valueLoc;
  3508. end;
  3509. end;
  3510. function TXMLTextReader.AllocNodeData(AIndex: Integer): PNodeData;
  3511. begin
  3512. {make sure we have an extra slot to place child text/comment/etc}
  3513. if AIndex >= Length(FNodeStack)-1 then
  3514. SetLength(FNodeStack, AIndex * 2 + 2);
  3515. Result := @FNodeStack[AIndex];
  3516. Result^.FNext := nil;
  3517. Result^.FPrefix := nil;
  3518. Result^.FNsUri := nil;
  3519. Result^.FIDEntry := nil;
  3520. Result^.FValueStart := nil;
  3521. Result^.FValueLength := 0;
  3522. end;
  3523. procedure TXMLTextReader.AllocAttributeValueChunk(var APrev: PNodeData; Offset: Integer);
  3524. var
  3525. chunk: PNodeData;
  3526. begin
  3527. { when parsing DTD, don't take ownership of allocated data }
  3528. chunk := FFreeAttrChunk;
  3529. if Assigned(chunk) and (FState <> rsDTD) then
  3530. begin
  3531. FFreeAttrChunk := chunk^.FNext;
  3532. chunk^.FNext := nil;
  3533. end
  3534. else { no free chunks, create a new one }
  3535. chunk := AllocMem(sizeof(TNodeData));
  3536. APrev^.FNext := chunk;
  3537. APrev := chunk;
  3538. { assume text node, for entity refs it is overridden later }
  3539. chunk^.FNodeType := ntText;
  3540. chunk^.FQName := nil;
  3541. chunk^.FColonPos := -1;
  3542. { without PWideChar typecast and in $T-, FPC treats '@' result as PAnsiChar... }
  3543. SetString(chunk^.FValueStr, PWideChar(@FValue.Buffer[Offset]), FValue.Length-Offset);
  3544. end;
  3545. procedure TXMLTextReader.CleanupAttributes;
  3546. var
  3547. i: Integer;
  3548. begin
  3549. {cleanup only specified attributes; default ones are owned by DTD}
  3550. for i := 1 to FSpecifiedAttrs do
  3551. CleanupAttribute(@FNodeStack[FNesting+i]);
  3552. FAttrCleanupFlag := False;
  3553. end;
  3554. procedure TXMLTextReader.CleanupAttribute(aNode: PNodeData);
  3555. var
  3556. chunk: PNodeData;
  3557. begin
  3558. if Assigned(aNode^.FNext) then
  3559. begin
  3560. chunk := aNode^.FNext;
  3561. while Assigned(chunk^.FNext) do
  3562. chunk := chunk^.FNext;
  3563. chunk^.FNext := FFreeAttrChunk;
  3564. FFreeAttrChunk := aNode^.FNext;
  3565. aNode^.FNext := nil;
  3566. end;
  3567. end;
  3568. procedure TXMLTextReader.SetNodeInfoWithValue(typ: TXMLNodeType; AName: PHashItem = nil);
  3569. begin
  3570. FCurrNode := @FNodeStack[FNesting];
  3571. FCurrNode^.FNodeType := typ;
  3572. FCurrNode^.FQName := AName;
  3573. FCurrNode^.FColonPos := -1;
  3574. FCurrNode^.FValueStart := FValue.Buffer;
  3575. FCurrNode^.FValueLength := FValue.Length;
  3576. end;
  3577. function TXMLTextReader.SetupFakeLF(nextstate: TXMLToken): Boolean;
  3578. begin
  3579. FValue.Buffer[0] := #10;
  3580. FValue.Length := 1;
  3581. SetNodeInfoWithValue(ntWhitespace,nil);
  3582. FNext := nextstate;
  3583. Result := True;
  3584. end;
  3585. procedure TXMLTextReader.PushVC(aElDef: TElementDecl);
  3586. begin
  3587. Inc(FValidatorNesting);
  3588. if FValidatorNesting >= Length(FValidators) then
  3589. SetLength(FValidators, FValidatorNesting * 2);
  3590. with FValidators[FValidatorNesting] do
  3591. begin
  3592. FElementDef := aElDef;
  3593. FCurCP := nil;
  3594. FFailed := False;
  3595. FContentType := ctAny;
  3596. FSaViolation := False;
  3597. if Assigned(aElDef) then
  3598. begin
  3599. FContentType := aElDef.ContentType;
  3600. FSaViolation := FStandalone and aElDef.ExternallyDeclared;
  3601. end;
  3602. end;
  3603. end;
  3604. procedure TXMLTextReader.PopElement;
  3605. begin
  3606. if FNamespaces then
  3607. FNSHelper.PopScope;
  3608. if (FNesting = 0) and (not FFragmentMode) then
  3609. FState := rsEpilog;
  3610. FCurrNode := @FNodeStack[FNesting];
  3611. FNext := xtText;
  3612. end;
  3613. { TElementValidator }
  3614. function TElementValidator.IsElementAllowed(Def: TElementDecl): Boolean;
  3615. var
  3616. Next: TContentParticle;
  3617. begin
  3618. Result := True;
  3619. // if element is not declared, non-validity has been already reported, no need to report again...
  3620. if Assigned(Def) and Assigned(FElementDef) then
  3621. begin
  3622. case FElementDef.ContentType of
  3623. ctEmpty: Result := False;
  3624. ctChildren, ctMixed: begin
  3625. if FFailed then // if already detected a mismatch, don't waste time
  3626. Exit;
  3627. if FCurCP = nil then
  3628. Next := FElementDef.RootCP.FindFirst(Def)
  3629. else
  3630. Next := FCurCP.FindNext(Def, 0); { second arg ignored here }
  3631. Result := Assigned(Next);
  3632. if Result then
  3633. FCurCP := Next
  3634. else
  3635. FFailed := True; // used to prevent extra error at the end of element
  3636. end;
  3637. // ctAny, ctUndeclared: returns True by default
  3638. end;
  3639. end;
  3640. end;
  3641. function TElementValidator.Incomplete: Boolean;
  3642. begin
  3643. if Assigned(FElementDef) and (FElementDef.ContentType = ctChildren) and (not FFailed) then
  3644. begin
  3645. if FCurCP <> nil then
  3646. Result := FCurCP.MoreRequired(0) { arg ignored here }
  3647. else
  3648. Result := FElementDef.RootCP.IsRequired;
  3649. end
  3650. else
  3651. Result := False;
  3652. end;
  3653. end.