XmlTextReader.cs 69 KB

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