XmlTextReader.cs 78 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039
  1. //
  2. // System.Xml.XmlTextReader
  3. //
  4. // Author:
  5. // Jason Diamond ([email protected])
  6. // Adam Treat ([email protected])
  7. // Atsushi Enomoto ([email protected])
  8. //
  9. // (C) 2001, 2002 Jason Diamond http://injektilo.org/
  10. //
  11. // FIXME:
  12. //
  13. // NameTables aren't being used completely yet.
  14. //
  15. // Some thought needs to be given to performance. There's too many
  16. // strings being allocated.
  17. //
  18. // If current node is on an Attribute, Prefix might be null, and
  19. // in several fields which uses XmlReader, it should be considered.
  20. //
  21. using System;
  22. using System.Collections;
  23. using System.Collections.Specialized;
  24. using System.IO;
  25. using System.Text;
  26. using System.Xml.Schema;
  27. using Mono.Xml;
  28. using Mono.Xml.Native;
  29. namespace System.Xml
  30. {
  31. public class XmlTextReader : XmlReader, IXmlLineInfo
  32. {
  33. #region Constructors
  34. protected XmlTextReader ()
  35. {
  36. }
  37. public XmlTextReader (Stream input)
  38. : this (new XmlStreamReader (input))
  39. {
  40. }
  41. public XmlTextReader (string url)
  42. : this(url, new NameTable ())
  43. {
  44. }
  45. public XmlTextReader (TextReader input)
  46. : this (input, new NameTable ())
  47. {
  48. }
  49. protected XmlTextReader (XmlNameTable nt)
  50. : this (String.Empty, null, XmlNodeType.None, null)
  51. {
  52. }
  53. public XmlTextReader (Stream input, XmlNameTable nt)
  54. : this(new XmlStreamReader (input), nt)
  55. {
  56. }
  57. public XmlTextReader (string url, Stream input)
  58. : this (url, new XmlStreamReader (input))
  59. {
  60. }
  61. public XmlTextReader (string url, TextReader input)
  62. : this (url, input, new NameTable ())
  63. {
  64. }
  65. public XmlTextReader (string url, XmlNameTable nt)
  66. : this (url, new XmlStreamReader (url, null, null), nt)
  67. {
  68. }
  69. public XmlTextReader (TextReader input, XmlNameTable nt)
  70. : this (String.Empty, input, nt)
  71. {
  72. }
  73. public XmlTextReader (Stream xmlFragment, XmlNodeType fragType, XmlParserContext context)
  74. : this (context != null ? context.BaseURI : String.Empty,
  75. new XmlStreamReader (xmlFragment),
  76. fragType,
  77. context)
  78. {
  79. }
  80. public XmlTextReader (string url, Stream input, XmlNameTable nt)
  81. : this (url, new XmlStreamReader (input), nt)
  82. {
  83. }
  84. public XmlTextReader (string url, TextReader input, XmlNameTable nt)
  85. : this (url, input, XmlNodeType.Document, null)
  86. {
  87. }
  88. public XmlTextReader (string xmlFragment, XmlNodeType fragType, XmlParserContext context)
  89. : this (context != null ? context.BaseURI : String.Empty,
  90. new StringReader (xmlFragment),
  91. fragType,
  92. context)
  93. {
  94. }
  95. XmlTextReader (string url, TextReader fragment, XmlNodeType fragType, XmlParserContext context)
  96. {
  97. InitializeContext (url, context, fragment, fragType);
  98. }
  99. #endregion
  100. #region Properties
  101. public override int AttributeCount
  102. {
  103. get { return attributes.Count; }
  104. }
  105. public override string BaseURI
  106. {
  107. get { return parserContext.BaseURI; }
  108. }
  109. public override int Depth
  110. {
  111. get {
  112. if (NodeType == XmlNodeType.Attribute)
  113. return elementDepth + 1;
  114. else if (insideAttribute)
  115. return elementDepth + 2; // inside attribute value.
  116. return elementDepth;
  117. }
  118. }
  119. public Encoding Encoding
  120. {
  121. get { return parserContext.Encoding; }
  122. }
  123. public override bool EOF
  124. {
  125. get
  126. {
  127. return
  128. readState == ReadState.EndOfFile ||
  129. readState == ReadState.Closed;
  130. }
  131. }
  132. public override bool HasValue
  133. {
  134. get {
  135. if (this.valueBuilderAvailable)
  136. return valueBuilder.Length != 0;
  137. else
  138. return value != String.Empty;
  139. }
  140. }
  141. public override bool IsDefault
  142. {
  143. get
  144. {
  145. // XmlTextReader does not expand default attributes.
  146. return false;
  147. }
  148. }
  149. public override bool IsEmptyElement
  150. {
  151. get { return isEmptyElement; }
  152. }
  153. public override string this [int i]
  154. {
  155. get { return GetAttribute (i); }
  156. }
  157. public override string this [string name]
  158. {
  159. get { return GetAttribute (name); }
  160. }
  161. public override string this [string localName, string namespaceName]
  162. {
  163. get { return GetAttribute (localName, namespaceName); }
  164. }
  165. public int LineNumber
  166. {
  167. get { return currentInput.LineNumber; }
  168. }
  169. public int LinePosition
  170. {
  171. get { return currentInput.LinePosition; }
  172. }
  173. public override string LocalName
  174. {
  175. get { return localName; }
  176. }
  177. public override string Name
  178. {
  179. get { return name; }
  180. }
  181. public bool Namespaces
  182. {
  183. get { return namespaces; }
  184. set {
  185. if (readState != ReadState.Initial)
  186. throw new InvalidOperationException ("Namespaces have to be set before reading.");
  187. namespaces = value;
  188. }
  189. }
  190. public override string NamespaceURI
  191. {
  192. get { return namespaceURI; }
  193. }
  194. public override XmlNameTable NameTable
  195. {
  196. get { return parserContext.NameTable; }
  197. }
  198. public override XmlNodeType NodeType
  199. {
  200. get { return nodeType; }
  201. }
  202. [MonoTODO]
  203. public bool Normalization
  204. {
  205. get { return normalization; }
  206. set { normalization = value; }
  207. }
  208. public override string Prefix
  209. {
  210. get { return prefix; }
  211. }
  212. public override char QuoteChar
  213. {
  214. get {
  215. // value string holds attribute quotation char.
  216. if (NodeType == XmlNodeType.Attribute)
  217. return value [0];
  218. else
  219. return '"';
  220. }
  221. }
  222. public override ReadState ReadState
  223. {
  224. get { return readState; }
  225. }
  226. public override string Value
  227. {
  228. get {
  229. string v = value;
  230. if (valueBuilderAvailable)
  231. v = valueBuilder.ToString ();
  232. if(NodeType == XmlNodeType.Attribute)
  233. return UnescapeAttributeValue(v);
  234. else
  235. return v;
  236. }
  237. }
  238. public WhitespaceHandling WhitespaceHandling
  239. {
  240. get { return whitespaceHandling; }
  241. set { whitespaceHandling = value; }
  242. }
  243. public override string XmlLang
  244. {
  245. get { return parserContext.XmlLang; }
  246. }
  247. public XmlResolver XmlResolver
  248. {
  249. set { resolver = value; }
  250. }
  251. public override XmlSpace XmlSpace
  252. {
  253. get { return parserContext.XmlSpace; }
  254. }
  255. #endregion
  256. #region Methods
  257. public override void Close ()
  258. {
  259. readState = ReadState.Closed;
  260. foreach (XmlParserInput input in parserInputStack.ToArray ())
  261. input.Close ();
  262. this.currentInput.Close ();
  263. }
  264. public override string GetAttribute (int i)
  265. {
  266. if (i > attributes.Count)
  267. throw new ArgumentOutOfRangeException ("i is smaller than AttributeCount");
  268. else
  269. return UnescapeAttributeValue (attributes [orderedAttributes [i]] as string);
  270. }
  271. // MS.NET 1.0 documentation says that this method returns String.Empty for
  272. // not-exist attribute, but in fact it returns null.
  273. // That description is corrected in MS.NET 1.1 documentation.
  274. public override string GetAttribute (string name)
  275. {
  276. return UnescapeAttributeValue (attributes [name] as string);
  277. }
  278. private int GetIndexOfQualifiedAttribute (string localName, string namespaceURI)
  279. {
  280. for(int i = 0; i < orderedAttributes.Count; i++)
  281. {
  282. string thisName = (string) orderedAttributes [i];
  283. int indexOfColon = thisName.IndexOf (':');
  284. if (indexOfColon != -1) {
  285. string thisLocalName = thisName.Substring (indexOfColon + 1);
  286. if (localName == thisLocalName) {
  287. string thisPrefix = thisName.Substring (0, indexOfColon);
  288. string thisNamespaceURI = LookupNamespace (thisPrefix);
  289. if (namespaceURI == thisNamespaceURI)
  290. return i;
  291. }
  292. } else if (localName == "xmlns" && namespaceURI == "http://www.w3.org/2000/xmlns/" && thisName == "xmlns")
  293. return i;
  294. }
  295. return -1;
  296. }
  297. internal XmlParserContext GetInternalParserContext ()
  298. {
  299. return parserContext;
  300. }
  301. public override string GetAttribute (string localName, string namespaceURI)
  302. {
  303. int idx = this.GetIndexOfQualifiedAttribute (localName, namespaceURI);
  304. if (idx < 0)
  305. return null;
  306. return UnescapeAttributeValue (attributes [orderedAttributes [idx]] as string);
  307. }
  308. [MonoTODO]
  309. public TextReader GetRemainder ()
  310. {
  311. throw new NotImplementedException ();
  312. }
  313. bool IXmlLineInfo.HasLineInfo ()
  314. {
  315. return true;
  316. }
  317. public override string LookupNamespace (string prefix)
  318. {
  319. return parserContext.NamespaceManager.LookupNamespace (prefix);
  320. }
  321. public override void MoveToAttribute (int i)
  322. {
  323. MoveToElement ();
  324. if (attributes == null || orderedAttributes.Count < i || i < 0)
  325. throw new ArgumentOutOfRangeException ("attribute index out of range.");
  326. if (orderedAttributesPos == -1) {
  327. SaveProperties ();
  328. }
  329. orderedAttributesPos = i;
  330. string name = orderedAttributes [i] as string;
  331. string value = attributes [name] as string;
  332. SetProperties (
  333. XmlNodeType.Attribute, // nodeType
  334. name, // name
  335. false, // isEmptyElement
  336. value, // value
  337. false // clearAttributes
  338. );
  339. insideAttribute = true;
  340. attributeValuePos = 0;
  341. }
  342. public override bool MoveToAttribute (string name)
  343. {
  344. MoveToElement ();
  345. bool match = false;
  346. if (attributes == null)
  347. return false;
  348. if (orderedAttributesPos == -1) {
  349. SaveProperties ();
  350. }
  351. for (orderedAttributesPos = 0; orderedAttributesPos < orderedAttributes.Count; orderedAttributesPos++)
  352. if (name == orderedAttributes [orderedAttributesPos] as string) {
  353. match = true;
  354. break;
  355. }
  356. if (match) {
  357. string value = attributes [name] as string;
  358. SetProperties (
  359. XmlNodeType.Attribute, // nodeType
  360. name, // name
  361. false, // isEmptyElement
  362. value, // value
  363. false // clearAttributes
  364. );
  365. insideAttribute = true;
  366. attributeValuePos = 0;
  367. }
  368. return match;
  369. }
  370. public override bool MoveToAttribute (string localName, string namespaceName)
  371. {
  372. MoveToElement ();
  373. if (attributes == null)
  374. return false;
  375. int idx = GetIndexOfQualifiedAttribute (localName, namespaceName);
  376. if (idx < 0)
  377. return false;
  378. MoveToAttribute (idx);
  379. return true;
  380. }
  381. public override bool MoveToElement ()
  382. {
  383. if (orderedAttributesPos != -1) {
  384. orderedAttributesPos = -1;
  385. if (isPropertySaved)
  386. RestoreProperties ();
  387. insideAttribute = false;
  388. return true;
  389. }
  390. return false;
  391. }
  392. public override bool MoveToFirstAttribute ()
  393. {
  394. MoveToElement ();
  395. return MoveToNextAttribute ();
  396. }
  397. public override bool MoveToNextAttribute ()
  398. {
  399. if (attributes == null)
  400. return false;
  401. if (orderedAttributesPos == -1)
  402. SaveProperties ();
  403. if (++orderedAttributesPos < orderedAttributes.Count) {
  404. string name = orderedAttributes [orderedAttributesPos] as string;
  405. string value = attributes [name] as string;
  406. SetProperties (
  407. XmlNodeType.Attribute, // nodeType
  408. name, // name
  409. false, // isEmptyElement
  410. value, // value
  411. false // clearAttributes
  412. );
  413. insideAttribute = true;
  414. attributeValuePos = 0;
  415. return true;
  416. }
  417. return false;
  418. }
  419. public override bool Read ()
  420. {
  421. bool more = false;
  422. isPropertySaved = false;
  423. readState = ReadState.Interactive;
  424. insideAttribute = false;
  425. // It was moved from end of ReadStartTag ().
  426. if (depthUp)
  427. ++depth;
  428. depthUp = false;
  429. more = ReadContent ();
  430. if (depth == 0 && !allowMultipleRoot && (IsEmptyElement || NodeType == XmlNodeType.EndElement))
  431. currentState = XmlNodeType.EndElement;
  432. if (maybeTextDecl != 0)
  433. maybeTextDecl--;
  434. if (!more && startNodeType == XmlNodeType.Document && currentState != XmlNodeType.EndElement)
  435. throw new XmlException ("Document element did not appear.");
  436. return more;
  437. }
  438. public override bool ReadAttributeValue ()
  439. {
  440. // 'attributeString' holds real string value (without their
  441. // quotation characters).
  442. //
  443. // 'attributeValuePos' holds current position
  444. // of 'attributeString' while iterating ReadAttribute().
  445. // It may be:
  446. // -1 if ReadAttributeValue() has already finished.
  447. // 0 if ReadAttributeValue() ready to start reading.
  448. // >0 if ReadAttributeValue() already got 1 or more values
  449. //
  450. // local 'refPosition' holds the position on the
  451. // attributeString which may be used next time.
  452. if (attributeValuePos < 0)
  453. return false;
  454. // If not started, then initialize attributeString when parsing is at start.
  455. if (attributeValuePos == 0) {
  456. attributeString =
  457. value.Substring (1, value.Length - 2);
  458. // If it has an empty value, this method still returns true.
  459. if (attributeString.Length == 0) {
  460. attributeValuePos = -1;
  461. SetProperties (XmlNodeType.Text,
  462. "",
  463. false,
  464. "",
  465. false);
  466. return true;
  467. }
  468. }
  469. // It occurs when attribute dully consists of entity reference.
  470. if (attributeValuePos == attributeString.Length)
  471. return false;
  472. returnEntityReference = false;
  473. value = String.Empty;
  474. int refPosition;
  475. int loop = 0;
  476. do {
  477. refPosition = attributeString.IndexOf ('&', attributeValuePos);
  478. if (refPosition < 0) {
  479. // Reached to the end of value string.
  480. value += attributeString.Substring (attributeValuePos);
  481. attributeValuePos = -1;
  482. break;
  483. } else if (refPosition == attributeValuePos) {
  484. string parsed = ReadAttributeValueReference ();
  485. if (parsed != null)
  486. value += parsed;
  487. else {
  488. // Found that an entity reference starts from this point.
  489. // reset position to after '&'.
  490. attributeValuePos = refPosition;
  491. if (value.Length <= 0) {
  492. int endNamePos = attributeString.IndexOf (";", attributeValuePos);
  493. value = attributeString.Substring (attributeValuePos+1, endNamePos - attributeValuePos - 1);
  494. attributeValuePos += value.Length + 2;
  495. returnEntityReference = true;
  496. }
  497. break;
  498. }
  499. } else {
  500. value += attributeString.Substring (attributeValuePos,
  501. refPosition - attributeValuePos);
  502. attributeValuePos = refPosition;
  503. continue;
  504. }
  505. } while (++loop > 0);
  506. if (returnEntityReference)
  507. SetProperties (XmlNodeType.EntityReference,
  508. value,
  509. false,
  510. String.Empty,
  511. false);
  512. else
  513. SetProperties (XmlNodeType.Text,
  514. "",
  515. false,
  516. value,
  517. false);
  518. returnEntityReference = false;
  519. return true;
  520. }
  521. [MonoTODO]
  522. public int ReadBase64 (byte [] buffer, int offset, int length)
  523. {
  524. throw new NotImplementedException ();
  525. }
  526. [MonoTODO]
  527. public int ReadBinHex (byte [] buffer, int offset, int length)
  528. {
  529. throw new NotImplementedException ();
  530. }
  531. [MonoTODO]
  532. public int ReadChars (char [] buffer, int offset, int length)
  533. {
  534. throw new NotImplementedException ();
  535. }
  536. #if NET_1_0
  537. public override string ReadInnerXml ()
  538. {
  539. if (readState != ReadState.Interactive)
  540. return String.Empty;
  541. switch (NodeType) {
  542. case XmlNodeType.Attribute:
  543. return value.Substring (1, value.Length - 2);
  544. case XmlNodeType.Element:
  545. if (IsEmptyElement)
  546. return String.Empty;
  547. int startDepth = depth;
  548. if (innerXmlBuilder == null)
  549. innerXmlBuilder = new StringBuilder ();
  550. innerXmlBuilder.Length = 0;
  551. bool loop = true;
  552. do {
  553. Read ();
  554. if (NodeType ==XmlNodeType.None)
  555. throw new XmlException ("unexpected end of xml.");
  556. else if (NodeType == XmlNodeType.EndElement && depth == startDepth) {
  557. loop = false;
  558. Read ();
  559. }
  560. else
  561. innerXmlBuilder.Append (currentTag);
  562. } while (loop);
  563. string xml = innerXmlBuilder.ToString ();
  564. innerXmlBuilder.Length = 0;
  565. return xml;
  566. case XmlNodeType.None:
  567. // MS document is incorrect. Seems not to progress.
  568. return String.Empty;
  569. default:
  570. Read ();
  571. return String.Empty;
  572. }
  573. }
  574. public override string ReadOuterXml ()
  575. {
  576. if (readState != ReadState.Interactive)
  577. return String.Empty;
  578. switch (NodeType) {
  579. case XmlNodeType.Attribute:
  580. // strictly incompatible with MS... (it holds spaces attribute between name, value and "=" char (very trivial).
  581. return String.Format ("{0}={1}{2}{1}", Name, QuoteChar, ReadInnerXml ());
  582. case XmlNodeType.Element:
  583. bool isEmpty = IsEmptyElement;
  584. string startTag = currentTag.ToString ();
  585. string name = Name;
  586. if (NodeType == XmlNodeType.Element && !isEmpty)
  587. return String.Format ("{0}{1}</{2}>", startTag, ReadInnerXml (), name);
  588. else
  589. return currentTag.ToString ();
  590. case XmlNodeType.None:
  591. // MS document is incorrect. Seems not to progress.
  592. return String.Empty;
  593. default:
  594. Read ();
  595. return String.Empty;
  596. }
  597. }
  598. #endif
  599. public override string ReadString ()
  600. {
  601. return ReadStringInternal ();
  602. }
  603. public void ResetState ()
  604. {
  605. Init ();
  606. }
  607. public override void ResolveEntity ()
  608. {
  609. // XmlTextReader does not resolve entities.
  610. throw new InvalidOperationException ("XmlTextReader cannot resolve external entities.");
  611. }
  612. #endregion
  613. #region Internals
  614. // Parsed DTD Objects
  615. internal DTDObjectModel DTD {
  616. get { return parserContext.Dtd; }
  617. }
  618. internal bool MaybeTextDecl {
  619. set { if (value) this.maybeTextDecl = 2; }
  620. }
  621. #endregion
  622. #region Privates
  623. private XmlParserContext parserContext;
  624. private XmlParserInput currentInput;
  625. private Stack parserInputStack;
  626. private ReadState readState;
  627. private int depth;
  628. private int elementDepth;
  629. private bool depthUp;
  630. private bool popScope;
  631. private Stack elementStack;
  632. private bool allowMultipleRoot;
  633. private bool isStandalone;
  634. private XmlNodeType nodeType;
  635. private string name;
  636. private string prefix;
  637. private string localName;
  638. private string namespaceURI;
  639. private bool isEmptyElement;
  640. private string value;
  641. private StringBuilder valueBuilder;
  642. private bool valueBuilderAvailable = false;
  643. private bool insideAttribute;
  644. private bool isPropertySaved;
  645. private XmlNodeType saveNodeType;
  646. private string saveName;
  647. private string savePrefix;
  648. private string saveLocalName;
  649. private string saveNamespaceURI;
  650. private bool saveIsEmptyElement;
  651. private Hashtable attributes;
  652. private ArrayList orderedAttributes;
  653. private int orderedAttributesPos = -1;
  654. private bool returnEntityReference;
  655. private string entityReferenceName;
  656. private char [] nameBuffer;
  657. private int nameLength;
  658. private int nameCapacity;
  659. private const int initialNameCapacity = 256;
  660. private StringBuilder valueBuffer;
  661. // A buffer for ReadContent for ReadOuterXml
  662. private StringBuilder currentTag {
  663. get {
  664. return currentInput.CurrentMarkup;
  665. }
  666. }
  667. private string attributeString;
  668. private int attributeValuePos;
  669. // This should be only referenced(used) by ReadInnerXml(). Kind of flyweight pattern.
  670. private StringBuilder innerXmlBuilder;
  671. // Parameter entity placeholder
  672. private Hashtable parameterEntities;
  673. private int dtdIncludeSect;
  674. private XmlNodeType startNodeType;
  675. // State machine attribute.
  676. // XmlDeclaration: after the first node.
  677. // DocumentType: after doctypedecl
  678. // Element: inside document element
  679. // EndElement: after document element
  680. private XmlNodeType currentState;
  681. private int maybeTextDecl;
  682. // These values are never re-initialized.
  683. private XmlResolver resolver = new XmlUrlResolver ();
  684. private bool namespaces = true;
  685. private WhitespaceHandling whitespaceHandling = WhitespaceHandling.All;
  686. private bool normalization = false;
  687. private void Init ()
  688. {
  689. readState = ReadState.Initial;
  690. currentState = XmlNodeType.None;
  691. maybeTextDecl = 0;
  692. allowMultipleRoot = false;
  693. depth = 0;
  694. depthUp = false;
  695. popScope = false;
  696. parserInputStack = new Stack ();
  697. elementStack = new Stack();
  698. nodeType = XmlNodeType.None;
  699. name = String.Empty;
  700. prefix = String.Empty;
  701. localName = string.Empty;
  702. isEmptyElement = false;
  703. value = String.Empty;
  704. attributes = new Hashtable ();
  705. attributeString = String.Empty;
  706. orderedAttributes = new ArrayList ();
  707. orderedAttributesPos = -1;
  708. returnEntityReference = false;
  709. entityReferenceName = String.Empty;
  710. nameBuffer = new char [initialNameCapacity];
  711. nameLength = 0;
  712. nameCapacity = initialNameCapacity;
  713. valueBuffer = new StringBuilder (8192);
  714. parameterEntities = new Hashtable ();
  715. }
  716. private void InitializeContext (string url, XmlParserContext context, TextReader fragment, XmlNodeType fragType)
  717. {
  718. startNodeType = fragType;
  719. parserContext = context;
  720. if (context == null) {
  721. XmlNameTable nt = new NameTable ();
  722. parserContext = new XmlParserContext (nt,
  723. new XmlNamespaceManager (nt),
  724. String.Empty,
  725. XmlSpace.None);
  726. }
  727. if (url != null && url != String.Empty) {
  728. string path = Path.GetFullPath ("./a");
  729. Uri uri = new Uri (new Uri (path), url);
  730. parserContext.BaseURI = uri.ToString ();
  731. }
  732. Init ();
  733. switch (fragType) {
  734. case XmlNodeType.Attribute:
  735. value = String.Format ("{0}{1}{0}", "'", fragment.ReadToEnd ().Replace ("'", "&apos;"));
  736. break;
  737. case XmlNodeType.Element:
  738. currentState = XmlNodeType.Element;
  739. allowMultipleRoot = true;
  740. break;
  741. case XmlNodeType.Document:
  742. break;
  743. default:
  744. throw new XmlException (String.Format ("NodeType {0} is not allowed to create XmlTextReader.", fragType));
  745. }
  746. this.currentInput = new XmlParserInput (fragment, url);
  747. StreamReader sr = fragment as StreamReader;
  748. }
  749. // Use this method rather than setting the properties
  750. // directly so that all the necessary properties can
  751. // be changed in harmony with each other. Maybe the
  752. // fields should be in a seperate class to help enforce
  753. // this.
  754. private void SetProperties (
  755. XmlNodeType nodeType,
  756. string name,
  757. bool isEmptyElement,
  758. string value,
  759. bool clearAttributes)
  760. {
  761. this.nodeType = nodeType;
  762. this.name = name;
  763. this.isEmptyElement = isEmptyElement;
  764. this.value = value;
  765. this.elementDepth = depth;
  766. this.valueBuilderAvailable = false;
  767. if (clearAttributes)
  768. ClearAttributes ();
  769. if (namespaces) {
  770. int indexOfColon = name.IndexOf (':');
  771. if (indexOfColon == -1) {
  772. prefix = String.Empty;
  773. // prefix = nodeType == XmlNodeType.Attribute ? null : String.Empty;
  774. localName = name;
  775. } else {
  776. prefix = name.Substring (0, indexOfColon);
  777. localName = name.Substring (indexOfColon + 1);
  778. }
  779. } else {
  780. prefix = String.Empty;
  781. localName = name;
  782. }
  783. switch (nodeType) {
  784. case XmlNodeType.Attribute:
  785. if (prefix == string.Empty) namespaceURI = string.Empty;
  786. // if (prefix == string.Empty || prefix == null) namespaceURI = string.Empty;
  787. else namespaceURI = LookupNamespace (prefix);
  788. if (localName == "xmlns" && prefix == "")
  789. namespaceURI = "http://www.w3.org/2000/xmlns/";
  790. break;
  791. case XmlNodeType.Element:
  792. case XmlNodeType.EndElement:
  793. namespaceURI = LookupNamespace (prefix);
  794. break;
  795. default:
  796. namespaceURI = "";
  797. break;
  798. }
  799. }
  800. private void SetProperties (
  801. XmlNodeType nodeType,
  802. string name,
  803. bool isEmptyElement,
  804. StringBuilder value,
  805. bool clearAttributes) {
  806. SetProperties (nodeType, name, isEmptyElement, (string)null, clearAttributes);
  807. this.valueBuilderAvailable = true;
  808. this.valueBuilder = value;
  809. }
  810. private void SaveProperties ()
  811. {
  812. // If already saved, then return.
  813. if (isPropertySaved)
  814. return;
  815. saveNodeType = nodeType;
  816. saveName = name;
  817. savePrefix = prefix;
  818. saveLocalName = localName;
  819. saveNamespaceURI = namespaceURI;
  820. saveIsEmptyElement = isEmptyElement;
  821. // An element's value is always String.Empty.
  822. isPropertySaved = true;
  823. }
  824. private void RestoreProperties ()
  825. {
  826. nodeType = saveNodeType;
  827. name = saveName;
  828. prefix = savePrefix;
  829. localName = saveLocalName;
  830. namespaceURI = saveNamespaceURI;
  831. isEmptyElement = saveIsEmptyElement;
  832. value = String.Empty;
  833. isPropertySaved = false;
  834. }
  835. private void AddAttribute (string name, string value)
  836. {
  837. if (attributes.ContainsKey (name))
  838. throw new XmlException (this as IXmlLineInfo,
  839. String.Format ("Attribute {0} already exists.", name));
  840. attributes.Add (name, value);
  841. orderedAttributes.Add (name);
  842. }
  843. private void ClearAttributes ()
  844. {
  845. if (attributes.Count > 0) {
  846. attributes.Clear ();
  847. orderedAttributes.Clear ();
  848. }
  849. orderedAttributesPos = -1;
  850. }
  851. private int PeekChar ()
  852. {
  853. return currentInput.PeekChar ();
  854. }
  855. private int ReadChar ()
  856. {
  857. return currentInput.ReadChar ();
  858. }
  859. // This should really keep track of some state so
  860. // that it's not possible to have more than one document
  861. // element or text outside of the document element.
  862. private bool ReadContent ()
  863. {
  864. currentTag.Length = 0;
  865. if (popScope) {
  866. parserContext.NamespaceManager.PopScope ();
  867. popScope = false;
  868. }
  869. if (returnEntityReference)
  870. SetEntityReferenceProperties ();
  871. else {
  872. switch (PeekChar ()) {
  873. case '<':
  874. ReadChar ();
  875. ReadTag ();
  876. break;
  877. case '\r': goto case ' ';
  878. case '\n': goto case ' ';
  879. case '\t': goto case ' ';
  880. case ' ':
  881. if (whitespaceHandling == WhitespaceHandling.All ||
  882. whitespaceHandling == WhitespaceHandling.Significant)
  883. ReadWhitespace ();
  884. else {
  885. SkipWhitespace ();
  886. return ReadContent ();
  887. }
  888. break;
  889. case -1:
  890. if (depth > 0)
  891. throw new XmlException ("unexpected end of file. Current depth is " + depth);
  892. readState = ReadState.EndOfFile;
  893. SetProperties (
  894. XmlNodeType.None, // nodeType
  895. String.Empty, // name
  896. false, // isEmptyElement
  897. String.Empty, // value
  898. true // clearAttributes
  899. );
  900. break;
  901. default:
  902. ReadText (true);
  903. break;
  904. }
  905. }
  906. if (NodeType == XmlNodeType.XmlDeclaration && maybeTextDecl == 1)
  907. return ReadContent ();
  908. return this.ReadState != ReadState.EndOfFile;
  909. }
  910. private void SetEntityReferenceProperties ()
  911. {
  912. /*
  913. if (resolver != null) {
  914. if (DTD == null)
  915. throw new XmlException (this as IXmlLineInfo,
  916. "Entity reference is not allowed without document type declaration.");
  917. else if((!DTD.InternalSubsetHasPEReference || isStandalone) &&
  918. DTD.EntityDecls [entityReferenceName] == null)
  919. throw new XmlException (this as IXmlLineInfo,
  920. "Required entity declaration for '" + entityReferenceName + "' was not found.");
  921. string dummy = DTD.EntityDecls [entityReferenceName].EntityValue;
  922. }
  923. */
  924. SetProperties (
  925. XmlNodeType.EntityReference, // nodeType
  926. entityReferenceName, // name
  927. false, // isEmptyElement
  928. String.Empty, // value
  929. true // clearAttributes
  930. );
  931. returnEntityReference = false;
  932. entityReferenceName = String.Empty;
  933. }
  934. // The leading '<' has already been consumed.
  935. private void ReadTag ()
  936. {
  937. switch (PeekChar ())
  938. {
  939. case '/':
  940. ReadChar ();
  941. ReadEndTag ();
  942. break;
  943. case '?':
  944. ReadChar ();
  945. ReadProcessingInstruction ();
  946. break;
  947. case '!':
  948. ReadChar ();
  949. ReadDeclaration ();
  950. break;
  951. default:
  952. ReadStartTag ();
  953. break;
  954. }
  955. }
  956. // The leading '<' has already been consumed.
  957. private void ReadStartTag ()
  958. {
  959. if (currentState == XmlNodeType.EndElement)
  960. throw new XmlException (this as IXmlLineInfo,
  961. "Element cannot appear in this state.");
  962. currentState = XmlNodeType.Element;
  963. parserContext.NamespaceManager.PushScope ();
  964. string name = ReadName ();
  965. if (currentState == XmlNodeType.EndElement)
  966. throw new XmlException (this as IXmlLineInfo,"document has terminated, cannot open new element");
  967. bool isEmptyElement = false;
  968. ClearAttributes ();
  969. SkipWhitespace ();
  970. if (XmlChar.IsFirstNameChar (PeekChar ()))
  971. ReadAttributes (false);
  972. string baseUri = GetAttribute ("xml:base");
  973. if (baseUri != null)
  974. parserContext.BaseURI = baseUri;
  975. string xmlLang = GetAttribute ("xml:lang");
  976. if (xmlLang != null)
  977. parserContext.XmlLang = xmlLang;
  978. string xmlSpaceAttr = GetAttribute ("xml:space");
  979. if (xmlSpaceAttr != null) {
  980. if (xmlSpaceAttr == "preserve")
  981. parserContext.XmlSpace = XmlSpace.Preserve;
  982. else if (xmlSpaceAttr == "default")
  983. parserContext.XmlSpace = XmlSpace.Default;
  984. else
  985. throw new XmlException (this as IXmlLineInfo,String.Format ("Invalid xml:space value: {0}", xmlSpaceAttr));
  986. }
  987. if (PeekChar () == '/') {
  988. ReadChar ();
  989. isEmptyElement = true;
  990. popScope = true;
  991. }
  992. else {
  993. depthUp = true;
  994. elementStack.Push (name);
  995. parserContext.PushScope ();
  996. }
  997. Expect ('>');
  998. SetProperties (
  999. XmlNodeType.Element, // nodeType
  1000. name, // name
  1001. isEmptyElement, // isEmptyElement
  1002. String.Empty, // value
  1003. false // clearAttributes
  1004. );
  1005. }
  1006. // The reader is positioned on the first character
  1007. // of the element's name.
  1008. private void ReadEndTag ()
  1009. {
  1010. if (currentState != XmlNodeType.Element)
  1011. throw new XmlException (this as IXmlLineInfo,
  1012. "End tag cannot appear in this state.");
  1013. string name = ReadName ();
  1014. if (elementStack.Count == 0)
  1015. throw new XmlException (this as IXmlLineInfo,"closing element without matching opening element");
  1016. string expected = (string)elementStack.Pop();
  1017. if (expected != name)
  1018. throw new XmlException (this as IXmlLineInfo,String.Format ("unmatched closing element: expected {0} but found {1}", expected, name));
  1019. parserContext.PopScope ();
  1020. SkipWhitespace ();
  1021. Expect ('>');
  1022. --depth;
  1023. SetProperties (
  1024. XmlNodeType.EndElement, // nodeType
  1025. name, // name
  1026. false, // isEmptyElement
  1027. String.Empty, // value
  1028. true // clearAttributes
  1029. );
  1030. popScope = true;
  1031. }
  1032. private void AppendNameChar (int ch)
  1033. {
  1034. CheckNameCapacity ();
  1035. nameBuffer [nameLength++] = (char)ch;
  1036. }
  1037. private void CheckNameCapacity ()
  1038. {
  1039. if (nameLength == nameCapacity) {
  1040. nameCapacity = nameCapacity * 2;
  1041. char [] oldNameBuffer = nameBuffer;
  1042. nameBuffer = new char [nameCapacity];
  1043. Array.Copy (oldNameBuffer, nameBuffer, nameLength);
  1044. }
  1045. }
  1046. private string CreateNameString ()
  1047. {
  1048. return parserContext.NameTable.Add (nameBuffer, 0, nameLength);
  1049. }
  1050. private void AppendValueChar (int ch)
  1051. {
  1052. valueBuffer.Append ((char)ch);
  1053. }
  1054. private string CreateValueString ()
  1055. {
  1056. return valueBuffer.ToString ();
  1057. }
  1058. private void ClearValueBuffer ()
  1059. {
  1060. valueBuffer.Length = 0;
  1061. }
  1062. // The reader is positioned on the first character
  1063. // of the text.
  1064. private void ReadText (bool notWhitespace)
  1065. {
  1066. if (currentState != XmlNodeType.Element)
  1067. throw new XmlException (this as IXmlLineInfo,
  1068. "Text node cannot appear in this state.");
  1069. if (notWhitespace)
  1070. ClearValueBuffer ();
  1071. int ch = PeekChar ();
  1072. int previousCloseBracketLine = 0;
  1073. int previousCloseBracketColumn = 0;
  1074. while (ch != '<' && ch != -1) {
  1075. if (ch == '&') {
  1076. ReadChar ();
  1077. if (ReadReference (false))
  1078. break;
  1079. } else {
  1080. if (XmlConstructs.IsInvalid (ch))
  1081. throw new XmlException (this as IXmlLineInfo,
  1082. "Not allowed character was found.");
  1083. AppendValueChar (ReadChar ());
  1084. if (ch == ']') {
  1085. if (previousCloseBracketColumn == LinePosition - 1 &&
  1086. previousCloseBracketLine == LineNumber)
  1087. if (PeekChar () == '>')
  1088. throw new XmlException (this as IXmlLineInfo,
  1089. "Inside text content, character sequence ']]>' is not allowed.");
  1090. previousCloseBracketColumn = LinePosition;
  1091. previousCloseBracketLine = LineNumber;
  1092. }
  1093. }
  1094. ch = PeekChar ();
  1095. notWhitespace = true;
  1096. }
  1097. if (returnEntityReference && valueBuffer.Length == 0) {
  1098. SetEntityReferenceProperties ();
  1099. } else {
  1100. XmlNodeType nodeType = notWhitespace ?
  1101. XmlNodeType.Text : XmlNodeType.Whitespace;
  1102. SetProperties (
  1103. nodeType, // nodeType
  1104. String.Empty, // name
  1105. false, // isEmptyElement
  1106. valueBuffer, // value
  1107. true // clearAttributes
  1108. );
  1109. }
  1110. }
  1111. // The leading '&' has already been consumed.
  1112. // Returns true if the entity reference isn't a simple
  1113. // character reference or one of the predefined entities.
  1114. // This allows the ReadText method to break so that the
  1115. // next call to Read will return the EntityReference node.
  1116. private bool ReadReference (bool ignoreEntityReferences)
  1117. {
  1118. if (PeekChar () == '#') {
  1119. ReadChar ();
  1120. ReadCharacterReference ();
  1121. } else
  1122. ReadEntityReference (ignoreEntityReferences);
  1123. return returnEntityReference;
  1124. }
  1125. private void ReadCharacterReference ()
  1126. {
  1127. int value = 0;
  1128. if (PeekChar () == 'x') {
  1129. ReadChar ();
  1130. while (PeekChar () != ';' && PeekChar () != -1) {
  1131. int ch = ReadChar ();
  1132. if (ch >= '0' && ch <= '9')
  1133. value = (value << 4) + ch - '0';
  1134. else if (ch >= 'A' && ch <= 'F')
  1135. value = (value << 4) + ch - 'A' + 10;
  1136. else if (ch >= 'a' && ch <= 'f')
  1137. value = (value << 4) + ch - 'a' + 10;
  1138. else
  1139. throw new XmlException (this as IXmlLineInfo,
  1140. String.Format (
  1141. "invalid hexadecimal digit: {0} (#x{1:X})",
  1142. (char)ch,
  1143. ch));
  1144. }
  1145. } else {
  1146. while (PeekChar () != ';' && PeekChar () != -1) {
  1147. int ch = ReadChar ();
  1148. if (ch >= '0' && ch <= '9')
  1149. value = value * 10 + ch - '0';
  1150. else
  1151. throw new XmlException (this as IXmlLineInfo,
  1152. String.Format (
  1153. "invalid decimal digit: {0} (#x{1:X})",
  1154. (char)ch,
  1155. ch));
  1156. }
  1157. }
  1158. ReadChar (); // ';'
  1159. // FIXME: how to handle such chars larger than 0xffff?
  1160. if (value < 0xffff && !XmlConstructs.IsValid (value))
  1161. throw new XmlException (this as IXmlLineInfo,
  1162. "Referenced character was not allowed in XML.");
  1163. AppendValueChar (value);
  1164. }
  1165. private void ReadEntityReference (bool ignoreEntityReferences)
  1166. {
  1167. nameLength = 0;
  1168. int ch = PeekChar ();
  1169. while (ch != ';' && ch != -1) {
  1170. AppendNameChar (ReadChar ());
  1171. ch = PeekChar ();
  1172. }
  1173. Expect (';');
  1174. string name = CreateNameString ();
  1175. if (!XmlChar.IsName (name))
  1176. throw new XmlException (this as IXmlLineInfo,
  1177. "Invalid entity reference name was found.");
  1178. char predefined = XmlChar.GetPredefinedEntity (name);
  1179. if (predefined != 0)
  1180. AppendValueChar (predefined);
  1181. else {
  1182. if (ignoreEntityReferences) {
  1183. AppendValueChar ('&');
  1184. foreach (char ch2 in name) {
  1185. AppendValueChar (ch2);
  1186. }
  1187. AppendValueChar (';');
  1188. } else {
  1189. returnEntityReference = true;
  1190. entityReferenceName = name;
  1191. }
  1192. }
  1193. }
  1194. // The reader is positioned on the first character of
  1195. // the attribute name.
  1196. private void ReadAttributes (bool allowPIEnd)
  1197. {
  1198. int peekChar = -1;
  1199. bool requireWhitespace = false;
  1200. do {
  1201. if (!SkipWhitespace () && requireWhitespace)
  1202. throw new XmlException ("Unexpected token. Name is required here.");
  1203. string name = ReadName ();
  1204. SkipWhitespace ();
  1205. Expect ('=');
  1206. SkipWhitespace ();
  1207. string value = ReadAttribute (false);
  1208. if (name == "xmlns")
  1209. parserContext.NamespaceManager.AddNamespace (String.Empty, UnescapeAttributeValue (value));
  1210. else if (name.StartsWith ("xmlns:"))
  1211. parserContext.NamespaceManager.AddNamespace (name.Substring (6), UnescapeAttributeValue (value));
  1212. AddAttribute (name, value);
  1213. if (!SkipWhitespace ())
  1214. requireWhitespace = true;
  1215. peekChar = PeekChar ();
  1216. if (peekChar == '?' && allowPIEnd)
  1217. break;
  1218. } while (peekChar != '/' && peekChar != '>' && peekChar != -1);
  1219. }
  1220. // The reader is positioned on the quote character.
  1221. // *Keeps quote char* to value to get_QuoteChar() correctly.
  1222. private string ReadAttribute (bool isDefaultValue)
  1223. {
  1224. ClearValueBuffer ();
  1225. int quoteChar = ReadChar ();
  1226. if (quoteChar != '\'' && quoteChar != '\"')
  1227. throw new XmlException (this as IXmlLineInfo,"an attribute value was not quoted");
  1228. AppendValueChar (quoteChar);
  1229. while (PeekChar () != quoteChar) {
  1230. int ch = ReadChar ();
  1231. switch (ch)
  1232. {
  1233. case '<':
  1234. throw new XmlException (this as IXmlLineInfo,"attribute values cannot contain '<'");
  1235. case -1:
  1236. throw new XmlException (this as IXmlLineInfo,"unexpected end of file in an attribute value");
  1237. /*
  1238. case '&':
  1239. if (isDefaultValue) {
  1240. AppendValueChar (ch);
  1241. break;
  1242. }
  1243. AppendValueChar (ch);
  1244. if (PeekChar () == '#')
  1245. break;
  1246. // Check XML 1.0 section 3.1 WFC.
  1247. string entName = ReadName ();
  1248. Expect (';');
  1249. if (XmlChar.GetPredefinedEntity (entName) == 0) {
  1250. DTDEntityDeclaration entDecl =
  1251. DTD == null ? null : DTD.EntityDecls [entName];
  1252. if (entDecl == null || entDecl.SystemId != null)
  1253. throw new XmlException (this as IXmlLineInfo,
  1254. "Reference to external entities is not allowed in attribute value.");
  1255. }
  1256. valueBuffer.Append (entName);
  1257. AppendValueChar (';');
  1258. break;
  1259. */
  1260. default:
  1261. AppendValueChar (ch);
  1262. break;
  1263. }
  1264. }
  1265. ReadChar (); // quoteChar
  1266. AppendValueChar (quoteChar);
  1267. return CreateValueString ();
  1268. }
  1269. // The reader is positioned on the first character
  1270. // of the target.
  1271. //
  1272. // It may be xml declaration or processing instruction.
  1273. private void ReadProcessingInstruction ()
  1274. {
  1275. string target = ReadName ();
  1276. if (target == "xml") {
  1277. ReadXmlDeclaration ();
  1278. return;
  1279. } else if (target.ToLower () == "xml")
  1280. throw new XmlException (this as IXmlLineInfo,
  1281. "Not allowed processing instruction name which starts with 'X', 'M', 'L' was found.");
  1282. if (currentState == XmlNodeType.None)
  1283. currentState = XmlNodeType.XmlDeclaration;
  1284. if (!SkipWhitespace ())
  1285. if (PeekChar () != '?')
  1286. throw new XmlException (this as IXmlLineInfo,
  1287. "Invalid processing instruction name was found.");
  1288. ClearValueBuffer ();
  1289. while (PeekChar () != -1) {
  1290. int ch = ReadChar ();
  1291. if (ch == '?' && PeekChar () == '>') {
  1292. ReadChar ();
  1293. break;
  1294. }
  1295. AppendValueChar ((char)ch);
  1296. }
  1297. SetProperties (
  1298. XmlNodeType.ProcessingInstruction, // nodeType
  1299. target, // name
  1300. false, // isEmptyElement
  1301. valueBuffer, // value
  1302. true // clearAttributes
  1303. );
  1304. }
  1305. // The reader is positioned after "<?xml "
  1306. private void ReadXmlDeclaration ()
  1307. {
  1308. if (currentState != XmlNodeType.None) {
  1309. if (maybeTextDecl == 0)
  1310. throw new XmlException (this as IXmlLineInfo,
  1311. "XML declaration cannot appear in this state.");
  1312. }
  1313. // Is this required?
  1314. // if (maybeTextDecl != 0)
  1315. // currentState = XmlNodeType.XmlDeclaration;
  1316. ClearAttributes ();
  1317. ReadAttributes (true); // They must have "version."
  1318. string version = (string) attributes ["version"];
  1319. if (version != null)
  1320. version = version.Substring (1, version.Length - 2);
  1321. string message = null;
  1322. if (parserInputStack.Count == 0) {
  1323. if (maybeTextDecl == 0 && (orderedAttributes [0] as string != "version" || version != "1.0"))
  1324. message = "Version 1.0 declaration is required in XML Declaration.";
  1325. else if (orderedAttributes.Count > 1 &&
  1326. (orderedAttributes [1] as string != "encoding" &&
  1327. orderedAttributes [1] as string != "standalone"))
  1328. message = "Invalid Xml Declaration markup was found.";
  1329. else if (orderedAttributes.Count > 2 && orderedAttributes [2] as string != "standalone")
  1330. message = "Invalid Xml Declaration markup was found.";
  1331. string sa = attributes ["standalone"] as string;
  1332. if (sa != null)
  1333. sa = sa.Substring (1, sa.Length - 2);
  1334. if (sa != null && sa != "yes" && sa != "no")
  1335. message = "Only 'yes' or 'no' is allowed for standalone.";
  1336. this.isStandalone = (sa == "yes");
  1337. } else {
  1338. int currentCheck = 0;
  1339. if (orderedAttributes [0] as string == "version") {
  1340. if (version != "1.0")
  1341. message = "Version 1.0 declaration is required in Text Declaration.";
  1342. currentCheck = 1;
  1343. }
  1344. if (orderedAttributes.Count <= currentCheck || orderedAttributes [currentCheck] as string != "encoding")
  1345. message = "Invalid Text Declaration markup was found. encoding specification is required.";
  1346. }
  1347. if (message != null)
  1348. throw new XmlException (this as IXmlLineInfo, message);
  1349. Expect ("?>");
  1350. if (maybeTextDecl != 0)
  1351. if (this ["standalone"] != null)
  1352. throw new XmlException (this as IXmlLineInfo,
  1353. "Invalid text declaration.");
  1354. if (maybeTextDecl == 2)
  1355. maybeTextDecl = 1;
  1356. SetProperties (
  1357. XmlNodeType.XmlDeclaration, // nodeType
  1358. "xml", // name
  1359. false, // isEmptyElement
  1360. currentInput.CurrentMarkup.ToString (6, currentInput.CurrentMarkup.Length - 6), // value
  1361. false // clearAttributes
  1362. );
  1363. }
  1364. // The reader is positioned on the first character after
  1365. // the leading '<!'.
  1366. private void ReadDeclaration ()
  1367. {
  1368. int ch = PeekChar ();
  1369. switch (ch)
  1370. {
  1371. case '-':
  1372. Expect ("--");
  1373. ReadComment ();
  1374. break;
  1375. case '[':
  1376. ReadChar ();
  1377. Expect ("CDATA[");
  1378. ReadCDATA ();
  1379. break;
  1380. case 'D':
  1381. Expect ("DOCTYPE");
  1382. ReadDoctypeDecl ();
  1383. break;
  1384. default:
  1385. throw new XmlException (this as IXmlLineInfo,
  1386. "Unexpected declaration markup was found.");
  1387. }
  1388. }
  1389. // The reader is positioned on the first character after
  1390. // the leading '<!--'.
  1391. private void ReadComment ()
  1392. {
  1393. if (currentState == XmlNodeType.None)
  1394. currentState = XmlNodeType.XmlDeclaration;
  1395. ClearValueBuffer ();
  1396. while (PeekChar () != -1) {
  1397. int ch = ReadChar ();
  1398. if (ch == '-' && PeekChar () == '-') {
  1399. ReadChar ();
  1400. if (PeekChar () != '>')
  1401. throw new XmlException (this as IXmlLineInfo,"comments cannot contain '--'");
  1402. ReadChar ();
  1403. break;
  1404. }
  1405. if (XmlConstructs.IsInvalid (ch))
  1406. throw new XmlException (this as IXmlLineInfo,
  1407. "Not allowed character was found.");
  1408. AppendValueChar ((char)ch);
  1409. }
  1410. SetProperties (
  1411. XmlNodeType.Comment, // nodeType
  1412. String.Empty, // name
  1413. false, // isEmptyElement
  1414. valueBuffer, // value
  1415. true // clearAttributes
  1416. );
  1417. }
  1418. // The reader is positioned on the first character after
  1419. // the leading '<![CDATA['.
  1420. private void ReadCDATA ()
  1421. {
  1422. if (currentState != XmlNodeType.Element)
  1423. throw new XmlException (this as IXmlLineInfo,
  1424. "CDATA section cannot appear in this state.");
  1425. ClearValueBuffer ();
  1426. bool skip = false;
  1427. int ch = 0;
  1428. while (PeekChar () != -1) {
  1429. if (!skip)
  1430. ch = ReadChar ();
  1431. skip = false;
  1432. if (ch == ']' && PeekChar () == ']') {
  1433. ch = ReadChar (); // ']'
  1434. if (PeekChar () == '>') {
  1435. ReadChar (); // '>'
  1436. break;
  1437. } else {
  1438. skip = true;
  1439. // AppendValueChar (']');
  1440. // AppendValueChar (']');
  1441. // ch = ReadChar ();
  1442. }
  1443. }
  1444. AppendValueChar ((char)ch);
  1445. }
  1446. SetProperties (
  1447. XmlNodeType.CDATA, // nodeType
  1448. String.Empty, // name
  1449. false, // isEmptyElement
  1450. valueBuffer, // value
  1451. true // clearAttributes
  1452. );
  1453. }
  1454. // The reader is positioned on the first character after
  1455. // the leading '<!DOCTYPE'.
  1456. private void ReadDoctypeDecl ()
  1457. {
  1458. switch (currentState) {
  1459. case XmlNodeType.DocumentType:
  1460. case XmlNodeType.Element:
  1461. case XmlNodeType.EndElement:
  1462. throw new XmlException (this as IXmlLineInfo,
  1463. "Document type cannot appear in this state.");
  1464. }
  1465. currentState = XmlNodeType.DocumentType;
  1466. string doctypeName = null;
  1467. string publicId = null;
  1468. string systemId = null;
  1469. int intSubsetStartLine = 0;
  1470. int intSubsetStartColumn = 0;
  1471. SkipWhitespace ();
  1472. doctypeName = ReadName ();
  1473. SkipWhitespace ();
  1474. switch(PeekChar ())
  1475. {
  1476. case 'S':
  1477. systemId = ReadSystemLiteral (true);
  1478. break;
  1479. case 'P':
  1480. publicId = ReadPubidLiteral ();
  1481. if (!SkipWhitespace ())
  1482. throw new XmlException (this as IXmlLineInfo,
  1483. "Whitespace is required between PUBLIC id and SYSTEM id.");
  1484. systemId = ReadSystemLiteral (false);
  1485. break;
  1486. }
  1487. SkipWhitespace ();
  1488. if(PeekChar () == '[')
  1489. {
  1490. // read markupdecl etc. or end of decl
  1491. ReadChar ();
  1492. intSubsetStartLine = this.LineNumber;
  1493. intSubsetStartColumn = this.LinePosition;
  1494. int startPos = currentTag.Length;
  1495. ReadInternalSubset ();
  1496. int endPos = currentTag.Length - 1;
  1497. parserContext.InternalSubset = currentTag.ToString (startPos, endPos - startPos);
  1498. }
  1499. // end of DOCTYPE decl.
  1500. SkipWhitespace ();
  1501. Expect ('>');
  1502. GenerateDTDObjectModel (doctypeName, publicId,
  1503. systemId, parserContext.InternalSubset,
  1504. intSubsetStartLine, intSubsetStartColumn);
  1505. // set properties for <!DOCTYPE> node
  1506. SetProperties (
  1507. XmlNodeType.DocumentType, // nodeType
  1508. doctypeName, // name
  1509. false, // isEmptyElement
  1510. parserContext.InternalSubset, // value
  1511. true // clearAttributes
  1512. );
  1513. }
  1514. internal DTDObjectModel GenerateDTDObjectModel (string name, string publicId,
  1515. string systemId, string internalSubset)
  1516. {
  1517. return GenerateDTDObjectModel (name, publicId, systemId, internalSubset, 0, 0);
  1518. }
  1519. internal DTDObjectModel GenerateDTDObjectModel (string name, string publicId,
  1520. string systemId, string internalSubset, int intSubsetStartLine, int intSubsetStartColumn)
  1521. {
  1522. // now compile DTD
  1523. parserContext.Dtd = new DTDObjectModel (); // merges both internal and external subsets in the meantime,
  1524. DTD.BaseURI = BaseURI;
  1525. DTD.Name = name;
  1526. DTD.PublicId = publicId;
  1527. DTD.SystemId = systemId;
  1528. DTD.InternalSubset = internalSubset;
  1529. DTD.XmlResolver = resolver;
  1530. int originalParserDepth = parserInputStack.Count;
  1531. if (internalSubset != null && internalSubset.Length > 0) {
  1532. XmlParserInput original = currentInput;
  1533. currentInput = new XmlParserInput (new StringReader (internalSubset), BaseURI, intSubsetStartLine, intSubsetStartColumn);
  1534. do {
  1535. CompileDTDSubset ();
  1536. if (PeekChar () == -1 && parserInputStack.Count > 0)
  1537. PopParserInput ();
  1538. } while (nodeType != XmlNodeType.None || parserInputStack.Count > originalParserDepth);
  1539. if (dtdIncludeSect != 0)
  1540. throw new XmlException (this as IXmlLineInfo,"INCLUDE section is not ended correctly.");
  1541. currentInput = original;
  1542. }
  1543. if (systemId != null && systemId != String.Empty && resolver != null) {
  1544. PushParserInput (systemId);
  1545. do {
  1546. this.CompileDTDSubset ();
  1547. if (PeekChar () == -1 && parserInputStack.Count > 1)
  1548. PopParserInput ();
  1549. } while (nodeType != XmlNodeType.None || parserInputStack.Count > originalParserDepth + 1);
  1550. PopParserInput ();
  1551. }
  1552. return DTD;
  1553. }
  1554. private void PushParserInput (string url)
  1555. {
  1556. Uri baseUri = null;
  1557. try {
  1558. baseUri = new Uri (BaseURI);
  1559. } catch (UriFormatException) {
  1560. }
  1561. Uri absUri = resolver.ResolveUri (baseUri, url);
  1562. string absPath = absUri.ToString ();
  1563. foreach (XmlParserInput i in parserInputStack.ToArray ()) {
  1564. if (i.BaseURI == absPath)
  1565. throw new XmlException (this as IXmlLineInfo, "Nested inclusion is not allowed: " + url);
  1566. }
  1567. parserInputStack.Push (currentInput);
  1568. currentInput = new XmlParserInput (new XmlStreamReader (url, false, resolver, BaseURI), absPath);
  1569. parserContext.PushScope ();
  1570. parserContext.BaseURI = absPath;
  1571. maybeTextDecl = 2;
  1572. }
  1573. private void PopParserInput ()
  1574. {
  1575. currentInput = parserInputStack.Pop () as XmlParserInput;
  1576. parserContext.PopScope ();
  1577. }
  1578. private enum DtdInputState
  1579. {
  1580. Free = 1,
  1581. ElementDecl,
  1582. AttlistDecl,
  1583. EntityDecl,
  1584. NotationDecl,
  1585. PI,
  1586. Comment,
  1587. InsideSingleQuoted,
  1588. InsideDoubleQuoted,
  1589. }
  1590. private class DtdInputStateStack
  1591. {
  1592. Stack intern = new Stack ();
  1593. public DtdInputStateStack ()
  1594. {
  1595. Push (DtdInputState.Free);
  1596. }
  1597. public DtdInputState Peek ()
  1598. {
  1599. return (DtdInputState) intern.Peek ();
  1600. }
  1601. public DtdInputState Pop ()
  1602. {
  1603. return (DtdInputState) intern.Pop ();
  1604. }
  1605. public void Push (DtdInputState val)
  1606. {
  1607. intern.Push (val);
  1608. }
  1609. }
  1610. DtdInputStateStack stateStack = new DtdInputStateStack ();
  1611. DtdInputState State {
  1612. get { return stateStack.Peek (); }
  1613. }
  1614. // Simply read but not generate any result.
  1615. private void ReadInternalSubset ()
  1616. {
  1617. bool continueParse = true;
  1618. while (continueParse) {
  1619. switch (ReadChar ()) {
  1620. case ']':
  1621. switch (State) {
  1622. case DtdInputState.Free:
  1623. continueParse = false;
  1624. break;
  1625. case DtdInputState.InsideDoubleQuoted:
  1626. continue;
  1627. case DtdInputState.InsideSingleQuoted:
  1628. continue;
  1629. default:
  1630. throw new XmlException (this as IXmlLineInfo,"unexpected end of file at DTD.");
  1631. }
  1632. break;
  1633. case -1:
  1634. throw new XmlException (this as IXmlLineInfo,"unexpected end of file at DTD.");
  1635. case '<':
  1636. if (State == DtdInputState.InsideDoubleQuoted ||
  1637. State == DtdInputState.InsideSingleQuoted)
  1638. continue; // well-formed
  1639. switch (ReadChar ()) {
  1640. case '?':
  1641. stateStack.Push (DtdInputState.PI);
  1642. break;
  1643. case '!':
  1644. switch (ReadChar ()) {
  1645. case 'E':
  1646. switch (ReadChar ()) {
  1647. case 'L':
  1648. Expect ("EMENT");
  1649. stateStack.Push (DtdInputState.ElementDecl);
  1650. break;
  1651. case 'N':
  1652. Expect ("TITY");
  1653. stateStack.Push (DtdInputState.EntityDecl);
  1654. break;
  1655. default:
  1656. throw new XmlException (this as IXmlLineInfo,"unexpected token '<!E'.");
  1657. }
  1658. break;
  1659. case 'A':
  1660. Expect ("TTLIST");
  1661. stateStack.Push (DtdInputState.AttlistDecl);
  1662. break;
  1663. case 'N':
  1664. Expect ("OTATION");
  1665. stateStack.Push (DtdInputState.NotationDecl);
  1666. break;
  1667. case '-':
  1668. Expect ("-");
  1669. stateStack.Push (DtdInputState.Comment);
  1670. break;
  1671. }
  1672. break;
  1673. default:
  1674. throw new XmlException (this as IXmlLineInfo,"unexpected '>'.");
  1675. }
  1676. break;
  1677. case '\'':
  1678. if (State == DtdInputState.InsideSingleQuoted)
  1679. stateStack.Pop ();
  1680. else if (State != DtdInputState.InsideDoubleQuoted && State != DtdInputState.Comment)
  1681. stateStack.Push (DtdInputState.InsideSingleQuoted);
  1682. break;
  1683. case '"':
  1684. if (State == DtdInputState.InsideDoubleQuoted)
  1685. stateStack.Pop ();
  1686. else if (State != DtdInputState.InsideSingleQuoted && State != DtdInputState.Comment)
  1687. stateStack.Push (DtdInputState.InsideDoubleQuoted);
  1688. break;
  1689. case '>':
  1690. switch (State) {
  1691. case DtdInputState.ElementDecl:
  1692. goto case DtdInputState.NotationDecl;
  1693. case DtdInputState.AttlistDecl:
  1694. goto case DtdInputState.NotationDecl;
  1695. case DtdInputState.EntityDecl:
  1696. goto case DtdInputState.NotationDecl;
  1697. case DtdInputState.NotationDecl:
  1698. stateStack.Pop ();
  1699. break;
  1700. case DtdInputState.InsideDoubleQuoted:
  1701. continue;
  1702. case DtdInputState.InsideSingleQuoted:
  1703. continue; // well-formed
  1704. case DtdInputState.Comment:
  1705. continue;
  1706. default:
  1707. throw new XmlException (this as IXmlLineInfo,"unexpected token '>'");
  1708. }
  1709. break;
  1710. case '?':
  1711. if (State == DtdInputState.PI) {
  1712. if (ReadChar () == '>')
  1713. stateStack.Pop ();
  1714. }
  1715. break;
  1716. case '-':
  1717. if (State == DtdInputState.Comment) {
  1718. if (PeekChar () == '-') {
  1719. ReadChar ();
  1720. Expect ('>');
  1721. stateStack.Pop ();
  1722. }
  1723. }
  1724. break;
  1725. case '%':
  1726. if (State != DtdInputState.Free && State != DtdInputState.EntityDecl && State != DtdInputState.Comment && State != DtdInputState.InsideDoubleQuoted && State != DtdInputState.InsideSingleQuoted)
  1727. throw new XmlException (this as IXmlLineInfo,"Parameter Entity Reference cannot appear as a part of markupdecl (see XML spec 2.8).");
  1728. break;
  1729. }
  1730. }
  1731. }
  1732. // Read any one of following:
  1733. // elementdecl, AttlistDecl, EntityDecl, NotationDecl,
  1734. // PI, Comment, Parameter Entity, or doctype termination char(']')
  1735. //
  1736. // returns a node of some nodeType or null, setting nodeType.
  1737. // (if None then ']' was found.)
  1738. private void CompileDTDSubset()
  1739. {
  1740. SkipWhitespace ();
  1741. switch(PeekChar ())
  1742. {
  1743. case -1:
  1744. nodeType = XmlNodeType.None;
  1745. break;
  1746. case '%':
  1747. // It affects on entity references' well-formedness
  1748. if (this.parserInputStack.Count == 0)
  1749. DTD.InternalSubsetHasPEReference = true;
  1750. ReadChar ();
  1751. string peName = ReadName ();
  1752. Expect (';');
  1753. currentInput.InsertParameterEntityBuffer (GetPEValue (peName));
  1754. int currentLine = currentInput.LineNumber;
  1755. int currentColumn = currentInput.LinePosition;
  1756. while (currentInput.HasPEBuffer)
  1757. CompileDTDSubset ();
  1758. if (currentInput.LineNumber != currentLine ||
  1759. currentInput.LinePosition != currentColumn)
  1760. throw new XmlException (this as IXmlLineInfo,
  1761. "Incorrectly nested parameter entity.");
  1762. break;
  1763. case '<':
  1764. ReadChar ();
  1765. switch(ReadChar ())
  1766. {
  1767. case '?':
  1768. // Only read, no store.
  1769. ReadProcessingInstruction ();
  1770. break;
  1771. case '!':
  1772. CompileDeclaration ();
  1773. break;
  1774. default:
  1775. throw new XmlException (this as IXmlLineInfo,"Syntax Error after '<' character.");
  1776. }
  1777. break;
  1778. case ']':
  1779. if (dtdIncludeSect == 0)
  1780. throw new XmlException (this as IXmlLineInfo, "Unbalanced end of INCLUDE/IGNORE section.");
  1781. // End of inclusion
  1782. Expect ("]]>");
  1783. dtdIncludeSect--;
  1784. SkipWhitespace ();
  1785. break;
  1786. default:
  1787. throw new XmlException (this as IXmlLineInfo,String.Format ("Syntax Error inside doctypedecl markup : {0}({1})", PeekChar (), (char) PeekChar ()));
  1788. }
  1789. }
  1790. private void CompileDeclaration ()
  1791. {
  1792. nodeType = XmlNodeType.DocumentType; // Hack!!
  1793. switch(ReadChar ())
  1794. {
  1795. case '-':
  1796. Expect ('-');
  1797. // Only read, no store.
  1798. ReadComment ();
  1799. break;
  1800. case 'E':
  1801. switch(ReadChar ())
  1802. {
  1803. case 'N':
  1804. Expect ("TITY");
  1805. if (!SkipWhitespace ())
  1806. throw new XmlException (this as IXmlLineInfo,
  1807. "Whitespace is required after '<!ENTITY' in DTD entity declaration.");
  1808. LOOPBACK:
  1809. if (PeekChar () == '%') {
  1810. ReadChar ();
  1811. if (!SkipWhitespace ()) {
  1812. ImportAsPERef ();
  1813. goto LOOPBACK;
  1814. } else {
  1815. TryExpandPERef ();
  1816. SkipWhitespace ();
  1817. if (XmlChar.IsNameChar (PeekChar ()))
  1818. ReadParameterEntityDecl ();
  1819. else
  1820. throw new XmlException (this as IXmlLineInfo,"expected name character");
  1821. }
  1822. break;
  1823. }
  1824. DTDEntityDeclaration ent = ReadEntityDecl ();
  1825. if (DTD.EntityDecls [ent.Name] == null)
  1826. DTD.EntityDecls.Add (ent.Name, ent);
  1827. break;
  1828. case 'L':
  1829. Expect ("EMENT");
  1830. DTDElementDeclaration el = ReadElementDecl ();
  1831. DTD.ElementDecls.Add (el.Name, el);
  1832. break;
  1833. default:
  1834. throw new XmlException (this as IXmlLineInfo,"Syntax Error after '<!E' (ELEMENT or ENTITY must be found)");
  1835. }
  1836. break;
  1837. case 'A':
  1838. Expect ("TTLIST");
  1839. DTDAttListDeclaration atl = ReadAttListDecl ();
  1840. // if (DTD.AttListDecls.ContainsKey (atl.Name))
  1841. DTD.AttListDecls.Add (atl.Name, atl);
  1842. break;
  1843. case 'N':
  1844. Expect ("OTATION");
  1845. DTDNotationDeclaration not = ReadNotationDecl ();
  1846. DTD.NotationDecls.Add (not.Name, not);
  1847. break;
  1848. case '[':
  1849. // conditional sections
  1850. SkipWhitespace ();
  1851. TryExpandPERef ();
  1852. SkipWhitespace ();
  1853. Expect ('I');
  1854. switch (ReadChar ()) {
  1855. case 'N':
  1856. Expect ("CLUDE");
  1857. SkipWhitespace ();
  1858. Expect ('[');
  1859. dtdIncludeSect++;
  1860. break;
  1861. case 'G':
  1862. Expect ("NORE");
  1863. ReadIgnoreSect ();
  1864. break;
  1865. }
  1866. break;
  1867. default:
  1868. throw new XmlException (this as IXmlLineInfo,"Syntax Error after '<!' characters.");
  1869. }
  1870. }
  1871. private void ReadIgnoreSect ()
  1872. {
  1873. bool skip = false;
  1874. SkipWhitespace ();
  1875. Expect ('[');
  1876. int dtdIgnoreSect = 1;
  1877. while (dtdIgnoreSect > 0) {
  1878. switch (skip ? PeekChar () : ReadChar ()) {
  1879. case -1:
  1880. throw new XmlException (this as IXmlLineInfo,"Unexpected IGNORE section end.");
  1881. case '<':
  1882. if (ReadChar () == '!' && ReadChar () == '[')
  1883. dtdIgnoreSect++;
  1884. break;
  1885. case ']':
  1886. if (ReadChar () == ']') {
  1887. if (ReadChar () == '>')
  1888. dtdIgnoreSect--;
  1889. else
  1890. skip = true;
  1891. }
  1892. break;
  1893. }
  1894. skip = false;
  1895. }
  1896. }
  1897. // The reader is positioned on the head of the name.
  1898. private DTDElementDeclaration ReadElementDecl ()
  1899. {
  1900. DTDElementDeclaration decl = new DTDElementDeclaration (DTD);
  1901. if (!SkipWhitespace ())
  1902. throw new XmlException (this as IXmlLineInfo,
  1903. "Whitespace is required between '<!ELEMENT' and name in DTD element declaration.");
  1904. TryExpandPERef ();
  1905. SkipWhitespace ();
  1906. decl.Name = ReadName ();
  1907. if (!SkipWhitespace ())
  1908. throw new XmlException (this as IXmlLineInfo,
  1909. "Whitespace is required between name and content in DTD element declaration.");
  1910. TryExpandPERef ();
  1911. ReadContentSpec (decl);
  1912. SkipWhitespace ();
  1913. // This expanding is only allowed as a non-validating parser.
  1914. TryExpandPERef ();
  1915. SkipWhitespace ();
  1916. Expect ('>');
  1917. return decl;
  1918. }
  1919. // read 'children'(BNF) of contentspec
  1920. private void ReadContentSpec (DTDElementDeclaration decl)
  1921. {
  1922. TryExpandPERef ();
  1923. SkipWhitespace ();
  1924. switch(PeekChar ())
  1925. {
  1926. case 'E':
  1927. decl.IsEmpty = true;
  1928. Expect ("EMPTY");
  1929. break;
  1930. case 'A':
  1931. decl.IsAny = true;
  1932. Expect ("ANY");
  1933. break;
  1934. case '(':
  1935. DTDContentModel model = decl.ContentModel;
  1936. ReadChar ();
  1937. SkipWhitespace ();
  1938. TryExpandPERef ();
  1939. SkipWhitespace ();
  1940. if(PeekChar () == '#') {
  1941. // Mixed Contents. "#PCDATA" must appear first.
  1942. decl.IsMixedContent = true;
  1943. model.Occurence = DTDOccurence.ZeroOrMore;
  1944. model.OrderType = DTDContentOrderType.Or;
  1945. Expect ("#PCDATA");
  1946. SkipWhitespace ();
  1947. TryExpandPERef ();
  1948. SkipWhitespace ();
  1949. while(PeekChar () != ')') {
  1950. Expect('|');
  1951. SkipWhitespace ();
  1952. TryExpandPERef ();
  1953. SkipWhitespace ();
  1954. DTDContentModel elem = new DTDContentModel (DTD, decl.Name);
  1955. elem.ElementName = ReadName ();
  1956. model.ChildModels.Add (elem);
  1957. SkipWhitespace ();
  1958. TryExpandPERef ();
  1959. SkipWhitespace ();
  1960. }
  1961. Expect (')');
  1962. if (model.ChildModels.Count > 0)
  1963. Expect ('*');
  1964. else if (PeekChar () == '*')
  1965. Expect ('*');
  1966. } else {
  1967. // Non-Mixed Contents
  1968. model.ChildModels.Add (ReadCP (decl));
  1969. SkipWhitespace ();
  1970. do { // copied from ReadCP() ...;-)
  1971. TryExpandPERef ();
  1972. SkipWhitespace ();
  1973. if(PeekChar ()=='|') {
  1974. // CPType=Or
  1975. if (model.OrderType == DTDContentOrderType.Seq)
  1976. throw new XmlException (this as IXmlLineInfo,
  1977. "Inconsistent choice markup in sequence cp.");
  1978. model.OrderType = DTDContentOrderType.Or;
  1979. ReadChar ();
  1980. SkipWhitespace ();
  1981. model.ChildModels.Add (ReadCP (decl));
  1982. SkipWhitespace ();
  1983. }
  1984. else if(PeekChar () == ',')
  1985. {
  1986. // CPType=Seq
  1987. if (model.OrderType == DTDContentOrderType.Or)
  1988. throw new XmlException (this as IXmlLineInfo,
  1989. "Inconsistent sequence markup in choice cp.");
  1990. model.OrderType = DTDContentOrderType.Seq;
  1991. ReadChar ();
  1992. SkipWhitespace ();
  1993. model.ChildModels.Add (ReadCP (decl));
  1994. SkipWhitespace ();
  1995. }
  1996. else
  1997. break;
  1998. }
  1999. while(true);
  2000. Expect (')');
  2001. switch(PeekChar ())
  2002. {
  2003. case '?':
  2004. model.Occurence = DTDOccurence.Optional;
  2005. ReadChar ();
  2006. break;
  2007. case '*':
  2008. model.Occurence = DTDOccurence.ZeroOrMore;
  2009. ReadChar ();
  2010. break;
  2011. case '+':
  2012. model.Occurence = DTDOccurence.OneOrMore;
  2013. ReadChar ();
  2014. break;
  2015. }
  2016. SkipWhitespace ();
  2017. }
  2018. SkipWhitespace ();
  2019. break;
  2020. }
  2021. }
  2022. // Read 'cp' (BNF) of contentdecl (BNF)
  2023. private DTDContentModel ReadCP (DTDElementDeclaration elem)
  2024. {
  2025. DTDContentModel model = null;
  2026. TryExpandPERef ();
  2027. SkipWhitespace ();
  2028. if(PeekChar () == '(') {
  2029. model = new DTDContentModel (DTD, elem.Name);
  2030. ReadChar ();
  2031. SkipWhitespace ();
  2032. model.ChildModels.Add (ReadCP (elem));
  2033. SkipWhitespace ();
  2034. do {
  2035. TryExpandPERef ();
  2036. SkipWhitespace ();
  2037. if(PeekChar ()=='|') {
  2038. // CPType=Or
  2039. if (model.OrderType == DTDContentOrderType.Seq)
  2040. throw new XmlException (this as IXmlLineInfo,
  2041. "Inconsistent choice markup in sequence cp.");
  2042. model.OrderType = DTDContentOrderType.Or;
  2043. ReadChar ();
  2044. SkipWhitespace ();
  2045. model.ChildModels.Add (ReadCP (elem));
  2046. SkipWhitespace ();
  2047. }
  2048. else if(PeekChar () == ',') {
  2049. // CPType=Seq
  2050. if (model.OrderType == DTDContentOrderType.Or)
  2051. throw new XmlException (this as IXmlLineInfo,
  2052. "Inconsistent sequence markup in choice cp.");
  2053. model.OrderType = DTDContentOrderType.Seq;
  2054. ReadChar ();
  2055. SkipWhitespace ();
  2056. model.ChildModels.Add (ReadCP (elem));
  2057. SkipWhitespace ();
  2058. }
  2059. else
  2060. break;
  2061. }
  2062. while(true);
  2063. SkipWhitespace ();
  2064. Expect (')');
  2065. }
  2066. else {
  2067. TryExpandPERef ();
  2068. model = new DTDContentModel (DTD, elem.Name);
  2069. SkipWhitespace ();
  2070. model.ElementName = ReadName ();
  2071. }
  2072. switch(PeekChar ()) {
  2073. case '?':
  2074. model.Occurence = DTDOccurence.Optional;
  2075. ReadChar ();
  2076. break;
  2077. case '*':
  2078. model.Occurence = DTDOccurence.ZeroOrMore;
  2079. ReadChar ();
  2080. break;
  2081. case '+':
  2082. model.Occurence = DTDOccurence.OneOrMore;
  2083. ReadChar ();
  2084. break;
  2085. }
  2086. return model;
  2087. }
  2088. // The reader is positioned on the first name char.
  2089. private void ReadParameterEntityDecl ()
  2090. {
  2091. DTDParameterEntityDeclaration decl =
  2092. new DTDParameterEntityDeclaration();
  2093. decl.BaseURI = BaseURI;
  2094. decl.Name = ReadName ();
  2095. if (!SkipWhitespace ())
  2096. throw new XmlException (this as IXmlLineInfo,
  2097. "Whitespace is required after name in DTD parameter entity declaration.");
  2098. if (PeekChar () == 'S' || PeekChar () == 'P') {
  2099. // throw new NotImplementedException ("External parameter entity reference is not implemented yet.");
  2100. // read publicId/systemId
  2101. ReadExternalID ();
  2102. decl.PublicId = attributes ["PUBLIC"] as string;
  2103. decl.SystemId = attributes ["SYSTEM"] as string;
  2104. SkipWhitespace ();
  2105. decl.Resolve (resolver);
  2106. }
  2107. else {
  2108. TryExpandPERef ();
  2109. int quoteChar = ReadChar ();
  2110. int start = currentTag.Length;
  2111. ClearValueBuffer ();
  2112. bool loop = true;
  2113. while (loop) {
  2114. int c = PeekChar ();
  2115. switch (c) {
  2116. case -1:
  2117. throw new XmlException ("unexpected end of stream in entity value definition.");
  2118. case '"':
  2119. ReadChar ();
  2120. if (quoteChar == '"')
  2121. loop = false;
  2122. else
  2123. AppendValueChar ('"');
  2124. break;
  2125. case '\'':
  2126. ReadChar ();
  2127. if (quoteChar == '\'')
  2128. loop = false;
  2129. else
  2130. AppendValueChar ('\'');
  2131. break;
  2132. case '&':
  2133. ReadChar ();
  2134. if (PeekChar () == '#') {
  2135. ReadChar ();
  2136. ReadCharacterReference ();
  2137. }
  2138. else
  2139. AppendValueChar ('&');
  2140. break;
  2141. case '%':
  2142. ReadChar ();
  2143. string peName = ReadName ();
  2144. Expect (';');
  2145. valueBuffer.Append (GetPEValue (peName));
  2146. break;
  2147. default:
  2148. AppendValueChar (ReadChar ());
  2149. break;
  2150. }
  2151. }
  2152. decl.LiteralValue = CreateValueString (); // currentTag.ToString (start, currentTag.Length - start - 1);
  2153. ClearValueBuffer ();
  2154. }
  2155. SkipWhitespace ();
  2156. Expect ('>');
  2157. if (parameterEntities [decl.Name] == null) {
  2158. parameterEntities.Add (decl.Name, decl);
  2159. }
  2160. }
  2161. private string GetPEValue (string peName)
  2162. {
  2163. DTDParameterEntityDeclaration peDecl =
  2164. this.parameterEntities [peName] as DTDParameterEntityDeclaration;
  2165. if (peDecl != null)
  2166. return peDecl.Value;
  2167. // See XML 1.0 section 4.1 for both WFC and VC.
  2168. if ((DTD.SystemId == null && !DTD.InternalSubsetHasPEReference) || this.isStandalone)
  2169. throw new XmlException (this as IXmlLineInfo,
  2170. "Parameter entity " + peName + " not found.");
  2171. DTD.AddError (new XmlSchemaException (
  2172. "Parameter entity " + peName + " not found.", null));
  2173. return "";
  2174. }
  2175. private void TryExpandPERef ()
  2176. {
  2177. if (PeekChar () == '%') {
  2178. // ReadChar ();
  2179. // if (!XmlChar.IsNameChar (PeekChar ()))
  2180. // return;
  2181. // ExpandPERef ();
  2182. ImportAsPERef ();
  2183. }
  2184. }
  2185. // reader is positioned on '%'
  2186. private void ImportAsPERef ()
  2187. {
  2188. ReadChar ();
  2189. string peName = ReadName ();
  2190. Expect (';');
  2191. DTDParameterEntityDeclaration peDecl =
  2192. this.parameterEntities [peName] as DTDParameterEntityDeclaration;
  2193. if (peDecl == null) {
  2194. DTD.AddError (new XmlSchemaException ("Parameter entity " + peName + " not found.", null));
  2195. return; // do nothing
  2196. }
  2197. currentInput.InsertParameterEntityBuffer (" " + peDecl.Value + " ");
  2198. }
  2199. // The reader is positioned on the head of the name.
  2200. private DTDEntityDeclaration ReadEntityDecl ()
  2201. {
  2202. DTDEntityDeclaration decl = new DTDEntityDeclaration (DTD);
  2203. decl.IsInternalSubset = (parserInputStack.Count == 0);
  2204. TryExpandPERef ();
  2205. SkipWhitespace ();
  2206. decl.Name = ReadName ();
  2207. if (!SkipWhitespace ())
  2208. throw new XmlException (this as IXmlLineInfo,
  2209. "Whitespace is required between name and content in DTD entity declaration.");
  2210. TryExpandPERef ();
  2211. SkipWhitespace ();
  2212. if (PeekChar () == 'S' || PeekChar () == 'P') {
  2213. // external entity
  2214. ReadExternalID ();
  2215. decl.PublicId = attributes ["PUBLIC"] as string;
  2216. decl.SystemId = attributes ["SYSTEM"] as string;
  2217. if (SkipWhitespace ()) {
  2218. if (PeekChar () == 'N') {
  2219. // NDataDecl
  2220. Expect ("NDATA");
  2221. if (!SkipWhitespace ())
  2222. throw new XmlException (this as IXmlLineInfo,
  2223. "Whitespace is required after NDATA.");
  2224. decl.NotationName = ReadName (); // ndata_name
  2225. }
  2226. }
  2227. }
  2228. else {
  2229. // literal entity
  2230. ReadEntityValueDecl (decl);
  2231. }
  2232. SkipWhitespace ();
  2233. // This expanding is only allowed as a non-validating parser.
  2234. TryExpandPERef ();
  2235. SkipWhitespace ();
  2236. Expect ('>');
  2237. return decl;
  2238. }
  2239. private void ReadEntityValueDecl (DTDEntityDeclaration decl)
  2240. {
  2241. SkipWhitespace ();
  2242. // quotation char will be finally removed on unescaping
  2243. int quoteChar = ReadChar ();
  2244. int start = currentTag.Length;
  2245. if (quoteChar != '\'' && quoteChar != '"')
  2246. throw new XmlException ("quotation char was expected.");
  2247. ClearValueBuffer ();
  2248. while (PeekChar () != quoteChar) {
  2249. switch (PeekChar ()) {
  2250. case '%':
  2251. ReadChar ();
  2252. string name = ReadName ();
  2253. Expect (';');
  2254. if (decl.IsInternalSubset)
  2255. throw new XmlException (this as IXmlLineInfo,
  2256. "Parameter entity is not allowed in internal subset entity '" + name + "'");
  2257. valueBuffer.Append (GetPEValue (name));
  2258. break;
  2259. case -1:
  2260. throw new XmlException ("unexpected end of stream.");
  2261. default:
  2262. AppendValueChar (ReadChar ());
  2263. break;
  2264. }
  2265. }
  2266. // string value = Dereference (currentTag.ToString (start, currentTag.Length - start), false);
  2267. string value = Dereference (CreateValueString (), false);
  2268. ClearValueBuffer ();
  2269. Expect (quoteChar);
  2270. decl.LiteralEntityValue = value;
  2271. }
  2272. private DTDAttListDeclaration ReadAttListDecl ()
  2273. {
  2274. SkipWhitespace ();
  2275. TryExpandPERef ();
  2276. SkipWhitespace ();
  2277. string name = ReadName (); // target element name
  2278. DTDAttListDeclaration decl =
  2279. DTD.AttListDecls [name] as DTDAttListDeclaration;
  2280. if (decl == null)
  2281. decl = new DTDAttListDeclaration (DTD);
  2282. decl.Name = name;
  2283. if (!SkipWhitespace ())
  2284. if (PeekChar () != '>')
  2285. throw new XmlException (this as IXmlLineInfo,
  2286. "Whitespace is required between name and content in non-empty DTD attlist declaration.");
  2287. TryExpandPERef ();
  2288. SkipWhitespace ();
  2289. while (XmlChar.IsNameChar ((char) PeekChar ())) {
  2290. DTDAttributeDefinition def = ReadAttributeDefinition ();
  2291. if (decl [def.Name] == null)
  2292. decl.Add (def);
  2293. SkipWhitespace ();
  2294. TryExpandPERef ();
  2295. SkipWhitespace ();
  2296. }
  2297. SkipWhitespace ();
  2298. // This expanding is only allowed as a non-validating parser.
  2299. TryExpandPERef ();
  2300. SkipWhitespace ();
  2301. Expect ('>');
  2302. return decl;
  2303. }
  2304. private DTDAttributeDefinition ReadAttributeDefinition ()
  2305. {
  2306. DTDAttributeDefinition def = new DTDAttributeDefinition ();
  2307. // attr_name
  2308. TryExpandPERef ();
  2309. SkipWhitespace ();
  2310. def.Name = ReadName ();
  2311. if (!SkipWhitespace ())
  2312. throw new XmlException (this as IXmlLineInfo,
  2313. "Whitespace is required between name and content in DTD attribute definition.");
  2314. // attr_value
  2315. TryExpandPERef ();
  2316. SkipWhitespace ();
  2317. switch(PeekChar ()) {
  2318. case 'C': // CDATA
  2319. Expect ("CDATA");
  2320. def.Datatype = XmlSchemaDatatype.FromName ("normalizedString");
  2321. break;
  2322. case 'I': // ID, IDREF, IDREFS
  2323. Expect ("ID");
  2324. if(PeekChar () == 'R') {
  2325. Expect ("REF");
  2326. if(PeekChar () == 'S') {
  2327. // IDREFS
  2328. ReadChar ();
  2329. def.Datatype = XmlSchemaDatatype.FromName ("IDREFS");
  2330. }
  2331. else // IDREF
  2332. def.Datatype = XmlSchemaDatatype.FromName ("IDREF");
  2333. }
  2334. else // ID
  2335. def.Datatype = XmlSchemaDatatype.FromName ("ID");
  2336. break;
  2337. case 'E': // ENTITY, ENTITIES
  2338. Expect ("ENTIT");
  2339. switch(ReadChar ()) {
  2340. case 'Y': // ENTITY
  2341. def.Datatype = XmlSchemaDatatype.FromName ("ENTITY");
  2342. break;
  2343. case 'I': // ENTITIES
  2344. Expect ("ES");
  2345. def.Datatype = XmlSchemaDatatype.FromName ("ENTITIES");
  2346. break;
  2347. }
  2348. break;
  2349. case 'N': // NMTOKEN, NMTOKENS, NOTATION
  2350. ReadChar ();
  2351. switch(PeekChar ()) {
  2352. case 'M':
  2353. Expect ("MTOKEN");
  2354. if(PeekChar ()=='S') { // NMTOKENS
  2355. ReadChar ();
  2356. def.Datatype = XmlSchemaDatatype.FromName ("NMTOKENS");
  2357. }
  2358. else // NMTOKEN
  2359. def.Datatype = XmlSchemaDatatype.FromName ("NMTOKEN");
  2360. break;
  2361. case 'O':
  2362. Expect ("OTATION");
  2363. def.Datatype = XmlSchemaDatatype.FromName ("NOTATION");
  2364. if (!SkipWhitespace ())
  2365. throw new XmlException (this as IXmlLineInfo,
  2366. "Whitespace is required between name and content in DTD attribute definition.");
  2367. Expect ('(');
  2368. SkipWhitespace ();
  2369. def.EnumeratedNotations.Add (ReadName ()); // notation name
  2370. SkipWhitespace ();
  2371. while(PeekChar () == '|') {
  2372. ReadChar ();
  2373. SkipWhitespace ();
  2374. def.EnumeratedNotations.Add (ReadName ()); // notation name
  2375. SkipWhitespace ();
  2376. }
  2377. Expect (')');
  2378. break;
  2379. default:
  2380. throw new XmlException ("attribute declaration syntax error.");
  2381. }
  2382. break;
  2383. default: // Enumerated Values
  2384. def.Datatype = XmlSchemaDatatype.FromName ("NMTOKEN");
  2385. TryExpandPERef ();
  2386. SkipWhitespace ();
  2387. Expect ('(');
  2388. SkipWhitespace ();
  2389. def.EnumeratedAttributeDeclaration.Add (
  2390. def.Datatype.Normalize (ReadNmToken ())); // enum value
  2391. SkipWhitespace ();
  2392. while(PeekChar () == '|') {
  2393. ReadChar ();
  2394. SkipWhitespace ();
  2395. def.EnumeratedAttributeDeclaration.Add (
  2396. def.Datatype.Normalize (ReadNmToken ())); // enum value
  2397. SkipWhitespace ();
  2398. }
  2399. Expect (')');
  2400. break;
  2401. }
  2402. TryExpandPERef ();
  2403. if (!SkipWhitespace ())
  2404. throw new XmlException (this as IXmlLineInfo,
  2405. "Whitespace is required between type and occurence in DTD attribute definition.");
  2406. // def_value
  2407. if(PeekChar () == '#')
  2408. {
  2409. ReadChar ();
  2410. switch(PeekChar ())
  2411. {
  2412. case 'R':
  2413. Expect ("REQUIRED");
  2414. def.OccurenceType = DTDAttributeOccurenceType.Required;
  2415. break;
  2416. case 'I':
  2417. Expect ("IMPLIED");
  2418. def.OccurenceType = DTDAttributeOccurenceType.Optional;
  2419. break;
  2420. case 'F':
  2421. Expect ("FIXED");
  2422. def.OccurenceType = DTDAttributeOccurenceType.Fixed;
  2423. if (!SkipWhitespace ())
  2424. throw new XmlException (this as IXmlLineInfo,
  2425. "Whitespace is required between FIXED and actual value in DTD attribute definition.");
  2426. def.UnresolvedDefaultValue = ReadAttribute (true);
  2427. break;
  2428. }
  2429. } else {
  2430. // one of the enumerated value
  2431. TryExpandPERef ();
  2432. SkipWhitespace ();
  2433. def.UnresolvedDefaultValue = ReadAttribute (true);
  2434. }
  2435. return def;
  2436. }
  2437. private DTDNotationDeclaration ReadNotationDecl()
  2438. {
  2439. DTDNotationDeclaration decl = new DTDNotationDeclaration ();
  2440. TryExpandPERef ();
  2441. SkipWhitespace ();
  2442. decl.Name = ReadName (); // notation name
  2443. if (namespaces) { // copy from SetProperties ;-)
  2444. int indexOfColon = decl.Name.IndexOf (':');
  2445. if (indexOfColon == -1) {
  2446. decl.Prefix = String.Empty;
  2447. decl.LocalName = decl.Name;
  2448. } else {
  2449. decl.Prefix = decl.Name.Substring (0, indexOfColon);
  2450. decl.LocalName = decl.Name.Substring (indexOfColon + 1);
  2451. }
  2452. } else {
  2453. decl.Prefix = String.Empty;
  2454. decl.LocalName = decl.Name;
  2455. }
  2456. SkipWhitespace ();
  2457. if(PeekChar () == 'P') {
  2458. decl.PublicId = ReadPubidLiteral ();
  2459. bool wsSkipped = SkipWhitespace ();
  2460. if (PeekChar () == '\'' || PeekChar () == '"') {
  2461. if (!wsSkipped)
  2462. throw new XmlException (this as IXmlLineInfo,
  2463. "Whitespace is required between public id and system id.");
  2464. decl.SystemId = ReadSystemLiteral (false);
  2465. SkipWhitespace ();
  2466. }
  2467. } else if(PeekChar () == 'S') {
  2468. decl.SystemId = ReadSystemLiteral (true);
  2469. SkipWhitespace ();
  2470. }
  2471. if(decl.PublicId == null && decl.SystemId == null)
  2472. throw new XmlException ("public or system declaration required for \"NOTATION\" declaration.");
  2473. // This expanding is only allowed as a non-validating parser.
  2474. TryExpandPERef ();
  2475. SkipWhitespace ();
  2476. Expect ('>');
  2477. return decl;
  2478. }
  2479. private void ReadExternalID() {
  2480. switch(PeekChar ()) {
  2481. case 'S':
  2482. attributes ["PUBLIC"] = null;
  2483. attributes ["SYSTEM"] = ReadSystemLiteral (true);
  2484. break;
  2485. case 'P':
  2486. attributes ["PUBLIC"] = ReadPubidLiteral ();
  2487. if (!SkipWhitespace ())
  2488. throw new XmlException (this as IXmlLineInfo,
  2489. "Whitespace is required between PUBLIC id and SYSTEM id.");
  2490. attributes ["SYSTEM"] = ReadSystemLiteral (false);
  2491. break;
  2492. }
  2493. }
  2494. // The reader is positioned on the first 'S' of "SYSTEM".
  2495. private string ReadSystemLiteral (bool expectSYSTEM)
  2496. {
  2497. if(expectSYSTEM) {
  2498. Expect ("SYSTEM");
  2499. if (!SkipWhitespace ())
  2500. throw new XmlException (this as IXmlLineInfo,
  2501. "Whitespace is required after 'SYSTEM'.");
  2502. }
  2503. else
  2504. SkipWhitespace ();
  2505. int quoteChar = ReadChar (); // apos or quot
  2506. int startPos = currentTag.Length;
  2507. int c = 0;
  2508. while(c != quoteChar) {
  2509. c = ReadChar ();
  2510. if(c < 0) throw new XmlException (this as IXmlLineInfo,"Unexpected end of stream in ExternalID.");
  2511. }
  2512. return currentTag.ToString (startPos, currentTag.Length - 1 - startPos);
  2513. }
  2514. private string ReadPubidLiteral()
  2515. {
  2516. Expect ("PUBLIC");
  2517. if (!SkipWhitespace ())
  2518. throw new XmlException (this as IXmlLineInfo,
  2519. "Whitespace is required after 'PUBLIC'.");
  2520. int quoteChar = ReadChar ();
  2521. int startPos = currentTag.Length;
  2522. int c = 0;
  2523. while(c != quoteChar)
  2524. {
  2525. c = ReadChar ();
  2526. if(c < 0) throw new XmlException (this as IXmlLineInfo,"Unexpected end of stream in ExternalID.");
  2527. if(c != quoteChar && !XmlChar.IsPubidChar (c))
  2528. throw new XmlException (this as IXmlLineInfo,"character '" + (char)c + "' not allowed for PUBLIC ID");
  2529. }
  2530. return currentTag.ToString (startPos, currentTag.Length - 1 - startPos);
  2531. }
  2532. // The reader is positioned on the first character
  2533. // of the name.
  2534. internal string ReadName ()
  2535. {
  2536. return ReadNameOrNmToken(false);
  2537. }
  2538. // The reader is positioned on the first character
  2539. // of the name.
  2540. private string ReadNmToken ()
  2541. {
  2542. return ReadNameOrNmToken(true);
  2543. }
  2544. private string ReadNameOrNmToken(bool isNameToken)
  2545. {
  2546. int ch = PeekChar ();
  2547. if(isNameToken) {
  2548. if (!XmlChar.IsNameChar ((char) ch))
  2549. throw new XmlException (this as IXmlLineInfo,String.Format ("a nmtoken did not start with a legal character {0} ({1})", ch, (char)ch));
  2550. }
  2551. else {
  2552. if (!XmlChar.IsFirstNameChar (ch))
  2553. throw new XmlException (this as IXmlLineInfo,String.Format ("a name did not start with a legal character {0} ({1})", ch, (char)ch));
  2554. }
  2555. nameLength = 0;
  2556. AppendNameChar (ReadChar ());
  2557. while (XmlChar.IsNameChar (PeekChar ())) {
  2558. AppendNameChar (ReadChar ());
  2559. }
  2560. return CreateNameString ();
  2561. }
  2562. // Read the next character and compare it against the
  2563. // specified character.
  2564. private void Expect (int expected)
  2565. {
  2566. int ch = ReadChar ();
  2567. if (ch != expected) {
  2568. throw new XmlException (this as IXmlLineInfo,
  2569. String.Format (
  2570. "expected '{0}' ({1:X}) but found '{2}' ({3:X})",
  2571. (char)expected,
  2572. expected,
  2573. (char)ch,
  2574. ch));
  2575. }
  2576. }
  2577. private void Expect (string expected)
  2578. {
  2579. int len = expected.Length;
  2580. for(int i=0; i< len; i++)
  2581. Expect (expected[i]);
  2582. }
  2583. // Does not consume the first non-whitespace character.
  2584. private bool SkipWhitespace ()
  2585. {
  2586. //FIXME: Should not skip if whitespaceHandling == WhiteSpaceHandling.None
  2587. bool skipped = XmlChar.IsWhitespace (PeekChar ());
  2588. while (XmlChar.IsWhitespace (PeekChar ()))
  2589. ReadChar ();
  2590. return skipped;
  2591. }
  2592. private void ReadWhitespace ()
  2593. {
  2594. if (currentState == XmlNodeType.None)
  2595. currentState = XmlNodeType.XmlDeclaration;
  2596. ClearValueBuffer ();
  2597. int ch = PeekChar ();
  2598. do {
  2599. AppendValueChar (ReadChar ());
  2600. } while ((ch = PeekChar ()) != -1 && XmlChar.IsWhitespace (ch));
  2601. if (currentState == XmlNodeType.Element && ch != -1 && ch != '<')
  2602. ReadText (false);
  2603. else
  2604. SetProperties (XmlNodeType.Whitespace,
  2605. String.Empty,
  2606. false,
  2607. valueBuffer,
  2608. true);
  2609. return; // (PeekChar () != -1);
  2610. }
  2611. // read entity reference from attribute string and if parsable then return the value.
  2612. private string ReadAttributeValueReference ()
  2613. {
  2614. int endEntityPosition = attributeString.IndexOf(';',
  2615. attributeValuePos);
  2616. if (endEntityPosition < 0)
  2617. throw new XmlException ("Insufficient markup of entity reference");
  2618. string entityName = attributeString.Substring (attributeValuePos + 1,
  2619. endEntityPosition - attributeValuePos - 1);
  2620. attributeValuePos = endEntityPosition + 1;
  2621. if(entityName [0] == '#') {
  2622. char c;
  2623. // character entity
  2624. if(entityName [1] == 'x') {
  2625. // hexadecimal
  2626. c = (char) int.Parse ("0" + entityName.Substring (2),
  2627. System.Globalization.NumberStyles.HexNumber);
  2628. } else {
  2629. // decimal
  2630. c = (char) int.Parse (entityName.Substring (1));
  2631. }
  2632. return c.ToString();
  2633. }
  2634. else {
  2635. switch(entityName)
  2636. {
  2637. case "lt": return "<";
  2638. case "gt": return ">";
  2639. case "amp": return "&";
  2640. case "quot": return "\"";
  2641. case "apos": return "'";
  2642. default: return null;
  2643. }
  2644. }
  2645. }
  2646. private string UnescapeAttributeValue (string unresolved)
  2647. {
  2648. if(unresolved == null) return null;
  2649. // trim start/end edge of quotation character.
  2650. return Dereference (unresolved.Substring (1, unresolved.Length - 2), true);
  2651. }
  2652. private string Dereference (string unresolved, bool expandPredefined)
  2653. {
  2654. StringBuilder resolved = new StringBuilder();
  2655. int pos = 0;
  2656. int next = unresolved.IndexOf ('&');
  2657. if(next < 0)
  2658. return unresolved;
  2659. while(next >= 0) {
  2660. if(pos < next)
  2661. resolved.Append (unresolved.Substring (pos, next - pos));// - 1);
  2662. int endPos = unresolved.IndexOf (';', next+1);
  2663. string entityName =
  2664. unresolved.Substring (next + 1, endPos - next - 1);
  2665. if(entityName [0] == '#') {
  2666. char c;
  2667. // character entity
  2668. if(entityName [1] == 'x') {
  2669. // hexadecimal
  2670. c = (char) int.Parse ("0" + entityName.Substring (2),
  2671. System.Globalization.NumberStyles.HexNumber);
  2672. } else {
  2673. // decimal
  2674. c = (char) int.Parse (entityName.Substring (1));
  2675. }
  2676. resolved.Append (c);
  2677. } else {
  2678. char predefined = XmlChar.GetPredefinedEntity (entityName);
  2679. if (expandPredefined && predefined != 0)
  2680. resolved.Append (predefined);
  2681. else
  2682. // With respect to "Value", MS document is helpless
  2683. // and the implemention returns inconsistent value
  2684. // (e.g. XML: "&ent; &amp;ent;" ---> Value: "&ent; &ent;".)
  2685. resolved.Append ("&" + entityName + ";");
  2686. }
  2687. pos = endPos + 1;
  2688. if(pos > unresolved.Length)
  2689. break;
  2690. next = unresolved.IndexOf('&', pos);
  2691. }
  2692. resolved.Append (unresolved.Substring(pos));
  2693. return resolved.ToString();
  2694. }
  2695. #endregion
  2696. }
  2697. }