XmlTextReader.cs 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547
  1. //
  2. // System.Xml.XmlTextReader
  3. //
  4. // Author:
  5. // Jason Diamond ([email protected])
  6. // Adam Treat ([email protected])
  7. //
  8. // (C) 2001, 2002 Jason Diamond http://injektilo.org/
  9. //
  10. // FIXME:
  11. // This can only parse basic XML: elements, attributes, processing
  12. // instructions, and comments are OK.
  13. //
  14. // It barfs on DOCTYPE declarations.
  15. // => No barfing, but parsing is incomplete.
  16. // DTD nodes are not still created.
  17. //
  18. // There's also no checking being done for either well-formedness
  19. // or validity.
  20. //
  21. // NameTables aren't being used everywhere yet.
  22. //
  23. // Some thought needs to be given to performance. There's too many
  24. // strings being allocated.
  25. //
  26. // Some of the MoveTo methods haven't been implemented yet.
  27. //
  28. // LineNumber and LinePosition aren't being tracked.
  29. //
  30. // xml:space, xml:lang, and xml:base aren't being tracked.
  31. //
  32. using System;
  33. using System.Collections;
  34. using System.IO;
  35. using System.Text;
  36. namespace System.Xml
  37. {
  38. public class XmlTextReader : XmlReader, IXmlLineInfo
  39. {
  40. WhitespaceHandling whitespaceHandling = WhitespaceHandling.All;
  41. #region Constructors
  42. protected XmlTextReader ()
  43. {
  44. }
  45. [MonoTODO]
  46. public XmlTextReader (Stream input)
  47. {
  48. // We can share some code in the constructors (at least for this one and next 2)
  49. XmlNameTable nt = new NameTable ();
  50. XmlNamespaceManager nsMgr = new XmlNamespaceManager (nt);
  51. parserContext = new XmlParserContext (null, nsMgr, null, XmlSpace.None);
  52. Init ();
  53. reader = new StreamReader (input);
  54. }
  55. [MonoTODO]
  56. public XmlTextReader (string url)
  57. {
  58. XmlNameTable nt = new NameTable ();
  59. XmlNamespaceManager nsMgr = new XmlNamespaceManager (nt);
  60. parserContext = new XmlParserContext (null, nsMgr, null, XmlSpace.None);
  61. Init ();
  62. // StreamReader does not support url, only filepath;-)
  63. reader = new StreamReader(url);
  64. }
  65. [MonoTODO]
  66. public XmlTextReader (TextReader input)
  67. {
  68. XmlNameTable nt = new NameTable ();
  69. XmlNamespaceManager nsMgr = new XmlNamespaceManager (nt);
  70. parserContext = new XmlParserContext (null, nsMgr, null, XmlSpace.None);
  71. Init ();
  72. reader = input;
  73. }
  74. [MonoTODO]
  75. protected XmlTextReader (XmlNameTable nt)
  76. {
  77. throw new NotImplementedException ();
  78. }
  79. [MonoTODO]
  80. public XmlTextReader (Stream input, XmlNameTable nt)
  81. {
  82. XmlNamespaceManager nsMgr = new XmlNamespaceManager (nt);
  83. parserContext = new XmlParserContext (null, nsMgr, null, XmlSpace.None);
  84. Init ();
  85. reader = new StreamReader (input);
  86. }
  87. [MonoTODO]
  88. public XmlTextReader (string url, Stream input)
  89. {
  90. throw new NotImplementedException ();
  91. }
  92. [MonoTODO]
  93. public XmlTextReader (string url, TextReader input)
  94. {
  95. throw new NotImplementedException ();
  96. }
  97. [MonoTODO]
  98. public XmlTextReader (string url, XmlNameTable nt)
  99. {
  100. throw new NotImplementedException ();
  101. }
  102. [MonoTODO]
  103. public XmlTextReader (TextReader input, XmlNameTable nt)
  104. {
  105. XmlNamespaceManager nsMgr = new XmlNamespaceManager (nt);
  106. parserContext = new XmlParserContext (null, nsMgr, null, XmlSpace.None);
  107. Init ();
  108. reader = input;
  109. }
  110. [MonoTODO]
  111. public XmlTextReader (Stream xmlFragment, XmlNodeType fragType, XmlParserContext context)
  112. {
  113. parserContext = context;
  114. reader = new StreamReader(xmlFragment);
  115. Init();
  116. // throw new NotImplementedException ();
  117. }
  118. [MonoTODO]
  119. public XmlTextReader (string url, Stream input, XmlNameTable nt)
  120. {
  121. throw new NotImplementedException ();
  122. }
  123. [MonoTODO]
  124. public XmlTextReader (string url, TextReader input, XmlNameTable nt)
  125. {
  126. throw new NotImplementedException ();
  127. }
  128. [MonoTODO]
  129. public XmlTextReader (string xmlFragment, XmlNodeType fragType, XmlParserContext context)
  130. {
  131. //Waiting for Validating reader for fragType rules.
  132. parserContext = context;
  133. Init ();
  134. reader = new StringReader(xmlFragment);
  135. }
  136. #endregion
  137. #region Properties
  138. public override int AttributeCount
  139. {
  140. get { return attributes.Count; }
  141. }
  142. public override string BaseURI
  143. {
  144. get { return parserContext.BaseURI; }
  145. }
  146. public override int Depth
  147. {
  148. get {
  149. return elementDepth;
  150. }
  151. }
  152. public Encoding Encoding
  153. {
  154. get { return parserContext.Encoding; }
  155. }
  156. public override bool EOF
  157. {
  158. get
  159. {
  160. return
  161. readState == ReadState.EndOfFile ||
  162. readState == ReadState.Closed;
  163. }
  164. }
  165. public override bool HasValue
  166. {
  167. get { return value != String.Empty; }
  168. }
  169. public override bool IsDefault
  170. {
  171. get
  172. {
  173. // XmlTextReader does not expand default attributes.
  174. return false;
  175. }
  176. }
  177. public override bool IsEmptyElement
  178. {
  179. get { return isEmptyElement; }
  180. }
  181. public override string this [int i]
  182. {
  183. get { return GetAttribute (i); }
  184. }
  185. public override string this [string name]
  186. {
  187. get { return GetAttribute (name); }
  188. }
  189. public override string this [string localName, string namespaceName]
  190. {
  191. get { return GetAttribute (localName, namespaceName); }
  192. }
  193. public int LineNumber
  194. {
  195. get { return line; }
  196. }
  197. public int LinePosition
  198. {
  199. get { return column; }
  200. }
  201. public override string LocalName
  202. {
  203. get { return localName; }
  204. }
  205. public override string Name
  206. {
  207. get { return name; }
  208. }
  209. [MonoTODO]
  210. public bool Namespaces
  211. {
  212. get { throw new NotImplementedException (); }
  213. set { throw new NotImplementedException (); }
  214. }
  215. public override string NamespaceURI
  216. {
  217. get { return namespaceURI; }
  218. }
  219. public override XmlNameTable NameTable
  220. {
  221. get { return parserContext.NameTable; }
  222. }
  223. public override XmlNodeType NodeType
  224. {
  225. get { return nodeType; }
  226. }
  227. [MonoTODO]
  228. public bool Normalization
  229. {
  230. get { throw new NotImplementedException (); }
  231. set { throw new NotImplementedException (); }
  232. }
  233. public override string Prefix
  234. {
  235. get { return prefix; }
  236. }
  237. [MonoTODO]
  238. public override char QuoteChar
  239. {
  240. get { throw new NotImplementedException (); }
  241. }
  242. public override ReadState ReadState
  243. {
  244. get { return readState; }
  245. }
  246. public override string Value
  247. {
  248. get { return value; }
  249. }
  250. public WhitespaceHandling WhitespaceHandling
  251. {
  252. get { return whitespaceHandling; }
  253. set { whitespaceHandling = value; }
  254. }
  255. [MonoTODO]
  256. public override string XmlLang
  257. {
  258. get { throw new NotImplementedException (); }
  259. }
  260. [MonoTODO]
  261. public XmlResolver XmlResolver
  262. {
  263. set { throw new NotImplementedException (); }
  264. }
  265. [MonoTODO]
  266. public override XmlSpace XmlSpace
  267. {
  268. get { throw new NotImplementedException (); }
  269. }
  270. #endregion
  271. #region Methods
  272. [MonoTODO]
  273. public override void Close ()
  274. {
  275. readState = ReadState.Closed;
  276. }
  277. [MonoTODO]
  278. public override string GetAttribute (int i)
  279. {
  280. if (i > attributes.Count)
  281. throw new ArgumentOutOfRangeException ("i is smaller than AttributeCount");
  282. else
  283. throw new NotImplementedException ();
  284. }
  285. public override string GetAttribute (string name)
  286. {
  287. return attributes.ContainsKey (name) ?
  288. attributes [name] as string : String.Empty;
  289. }
  290. public override string GetAttribute (string localName, string namespaceURI)
  291. {
  292. foreach (DictionaryEntry entry in attributes)
  293. {
  294. string thisName = entry.Key as string;
  295. int indexOfColon = thisName.IndexOf (':');
  296. if (indexOfColon != -1) {
  297. string thisLocalName = thisName.Substring (indexOfColon + 1);
  298. if (localName == thisLocalName) {
  299. string thisPrefix = thisName.Substring (0, indexOfColon);
  300. string thisNamespaceURI = LookupNamespace (thisPrefix);
  301. if (namespaceURI == thisNamespaceURI)
  302. return attributes.ContainsKey (thisName) ?
  303. attributes [thisName] as string : String.Empty;
  304. }
  305. } else if (localName == "xmlns" && namespaceURI == "http://www.w3.org/2000/xmlns/" && thisName == "xmlns")
  306. return attributes.ContainsKey (thisName) ?
  307. attributes [thisName] as string : String.Empty;
  308. }
  309. return String.Empty;
  310. }
  311. [MonoTODO]
  312. public TextReader GetRemainder ()
  313. {
  314. throw new NotImplementedException ();
  315. }
  316. [MonoTODO]
  317. bool IXmlLineInfo.HasLineInfo ()
  318. {
  319. return false;
  320. }
  321. public override string LookupNamespace (string prefix)
  322. {
  323. return parserContext.NamespaceManager.LookupNamespace (prefix);
  324. }
  325. [MonoTODO]
  326. public override void MoveToAttribute (int i)
  327. {
  328. throw new NotImplementedException ();
  329. }
  330. public override bool MoveToAttribute (string name)
  331. {
  332. MoveToElement ();
  333. bool match = false;
  334. if (attributes == null)
  335. return false;
  336. if (orderedAttributesEnumerator == null) {
  337. SaveProperties ();
  338. orderedAttributesEnumerator = orderedAttributes.GetEnumerator ();
  339. }
  340. while (orderedAttributesEnumerator.MoveNext ()) {
  341. if(name == orderedAttributesEnumerator.Current as string) {
  342. match = true;
  343. break;
  344. }
  345. }
  346. if (match) {
  347. string value = attributes [name] as string;
  348. SetProperties (
  349. XmlNodeType.Attribute, // nodeType
  350. name, // name
  351. false, // isEmptyElement
  352. value, // value
  353. false // clearAttributes
  354. );
  355. }
  356. return match;
  357. }
  358. [MonoTODO]
  359. public override bool MoveToAttribute (string localName, string namespaceName)
  360. {
  361. throw new NotImplementedException ();
  362. }
  363. public override bool MoveToElement ()
  364. {
  365. if (orderedAttributesEnumerator != null) {
  366. orderedAttributesEnumerator = null;
  367. RestoreProperties ();
  368. return true;
  369. }
  370. return false;
  371. }
  372. public override bool MoveToFirstAttribute ()
  373. {
  374. MoveToElement ();
  375. return MoveToNextAttribute ();
  376. }
  377. public override bool MoveToNextAttribute ()
  378. {
  379. if (attributes == null)
  380. return false;
  381. if (orderedAttributesEnumerator == null) {
  382. SaveProperties ();
  383. orderedAttributesEnumerator = orderedAttributes.GetEnumerator ();
  384. }
  385. if (orderedAttributesEnumerator.MoveNext ()) {
  386. string name = orderedAttributesEnumerator.Current as string;
  387. string value = attributes [name] as string;
  388. SetProperties (
  389. XmlNodeType.Attribute, // nodeType
  390. name, // name
  391. false, // isEmptyElement
  392. value, // value
  393. false // clearAttributes
  394. );
  395. return true;
  396. }
  397. return false;
  398. }
  399. public override bool Read ()
  400. {
  401. bool more = false;
  402. readState = ReadState.Interactive;
  403. more = ReadContent ();
  404. return more;
  405. }
  406. [MonoTODO]
  407. public override bool ReadAttributeValue ()
  408. {
  409. throw new NotImplementedException ();
  410. }
  411. [MonoTODO]
  412. public int ReadBase64 (byte [] buffer, int offset, int length)
  413. {
  414. throw new NotImplementedException ();
  415. }
  416. [MonoTODO]
  417. public int ReadBinHex (byte [] buffer, int offset, int length)
  418. {
  419. throw new NotImplementedException ();
  420. }
  421. [MonoTODO]
  422. public int ReadChars (char [] buffer, int offset, int length)
  423. {
  424. throw new NotImplementedException ();
  425. }
  426. [MonoTODO]
  427. public override string ReadInnerXml ()
  428. {
  429. // Still need a Well Formedness check.
  430. // Will wait for Validating reader ;-)
  431. if (NodeType == XmlNodeType.Attribute) {
  432. return Value;
  433. } else {
  434. saveToXmlBuffer = true;
  435. string startname = this.Name;
  436. string endname = string.Empty;
  437. readState = ReadState.Interactive;
  438. while (startname != endname) {
  439. ReadContent ();
  440. endname = this.Name;
  441. }
  442. xmlBuffer.Replace(currentTag.ToString (), "");
  443. saveToXmlBuffer = false;
  444. string InnerXml = xmlBuffer.ToString ();
  445. xmlBuffer.Length = 0;
  446. return InnerXml;
  447. }
  448. }
  449. [MonoTODO]
  450. public override string ReadOuterXml ()
  451. {
  452. if (NodeType == XmlNodeType.Attribute) {
  453. return Name+"=\""+Value+"\"";
  454. } else {
  455. saveToXmlBuffer = true;
  456. xmlBuffer.Append(currentTag.ToString ());
  457. string startname = this.Name;
  458. string endname = string.Empty;
  459. readState = ReadState.Interactive;
  460. while (startname != endname) {
  461. ReadContent ();
  462. endname = this.Name;
  463. }
  464. saveToXmlBuffer = false;
  465. string OuterXml = xmlBuffer.ToString ();
  466. xmlBuffer.Length = 0;
  467. return OuterXml;
  468. }
  469. }
  470. [MonoTODO]
  471. public override string ReadString ()
  472. {
  473. throw new NotImplementedException ();
  474. }
  475. [MonoTODO]
  476. public void ResetState ()
  477. {
  478. throw new NotImplementedException ();
  479. }
  480. public override void ResolveEntity ()
  481. {
  482. // XmlTextReaders don't resolve entities.
  483. throw new InvalidOperationException ("XmlTextReaders don't resolve entities.");
  484. }
  485. #endregion
  486. // privates
  487. private XmlParserContext parserContext;
  488. private TextReader reader;
  489. private ReadState readState;
  490. private int depth;
  491. private int elementDepth;
  492. private bool depthDown;
  493. private bool popScope;
  494. private XmlNodeType nodeType;
  495. private string name;
  496. private string prefix;
  497. private string localName;
  498. private string namespaceURI;
  499. private bool isEmptyElement;
  500. private string value;
  501. private XmlNodeType saveNodeType;
  502. private string saveName;
  503. private string savePrefix;
  504. private string saveLocalName;
  505. private string saveNamespaceURI;
  506. private bool saveIsEmptyElement;
  507. private Hashtable attributes;
  508. private ArrayList orderedAttributes;
  509. private IEnumerator orderedAttributesEnumerator;
  510. private bool returnEntityReference;
  511. private string entityReferenceName;
  512. private char [] nameBuffer;
  513. private int nameLength;
  514. private int nameCapacity;
  515. private const int initialNameCapacity = 256;
  516. private char [] valueBuffer;
  517. private int valueLength;
  518. private int valueCapacity;
  519. private const int initialValueCapacity = 8192;
  520. private StringBuilder xmlBuffer; // This is for Read(Inner|Outer)Xml
  521. private StringBuilder currentTag; // A buffer for ReadContent for ReadOuterXml
  522. private bool saveToXmlBuffer;
  523. private int line = 1;
  524. private int column = 1;
  525. private void Init ()
  526. {
  527. readState = ReadState.Initial;
  528. depth = 0;
  529. depthDown = false;
  530. popScope = false;
  531. nodeType = XmlNodeType.None;
  532. name = String.Empty;
  533. prefix = String.Empty;
  534. localName = string.Empty;
  535. isEmptyElement = false;
  536. value = String.Empty;
  537. attributes = new Hashtable ();
  538. orderedAttributes = new ArrayList ();
  539. orderedAttributesEnumerator = null;
  540. returnEntityReference = false;
  541. entityReferenceName = String.Empty;
  542. nameBuffer = new char [initialNameCapacity];
  543. nameLength = 0;
  544. nameCapacity = initialNameCapacity;
  545. valueBuffer = new char [initialValueCapacity];
  546. valueLength = 0;
  547. valueCapacity = initialValueCapacity;
  548. xmlBuffer = new StringBuilder ();
  549. currentTag = new StringBuilder ();
  550. }
  551. // Use this method rather than setting the properties
  552. // directly so that all the necessary properties can
  553. // be changed in harmony with each other. Maybe the
  554. // fields should be in a seperate class to help enforce
  555. // this.
  556. private void SetProperties (
  557. XmlNodeType nodeType,
  558. string name,
  559. bool isEmptyElement,
  560. string value,
  561. bool clearAttributes)
  562. {
  563. this.nodeType = nodeType;
  564. this.name = name;
  565. this.isEmptyElement = isEmptyElement;
  566. this.value = value;
  567. this.elementDepth = depth;
  568. if (clearAttributes)
  569. ClearAttributes ();
  570. int indexOfColon = name.IndexOf (':');
  571. if (indexOfColon == -1) {
  572. prefix = String.Empty;
  573. localName = name;
  574. } else {
  575. prefix = name.Substring (0, indexOfColon);
  576. localName = name.Substring (indexOfColon + 1);
  577. }
  578. namespaceURI = LookupNamespace (prefix);
  579. }
  580. private void SaveProperties ()
  581. {
  582. saveNodeType = nodeType;
  583. saveName = name;
  584. savePrefix = prefix;
  585. saveLocalName = localName;
  586. saveNamespaceURI = namespaceURI;
  587. saveIsEmptyElement = isEmptyElement;
  588. // An element's value is always String.Empty.
  589. }
  590. private void RestoreProperties ()
  591. {
  592. nodeType = saveNodeType;
  593. name = saveName;
  594. prefix = savePrefix;
  595. localName = saveLocalName;
  596. namespaceURI = saveNamespaceURI;
  597. isEmptyElement = saveIsEmptyElement;
  598. value = String.Empty;
  599. }
  600. private void AddAttribute (string name, string value)
  601. {
  602. attributes.Add (name, value);
  603. orderedAttributes.Add (name);
  604. }
  605. private void ClearAttributes ()
  606. {
  607. if (attributes.Count > 0) {
  608. attributes.Clear ();
  609. orderedAttributes.Clear ();
  610. }
  611. orderedAttributesEnumerator = null;
  612. }
  613. private int PeekChar ()
  614. {
  615. return reader.Peek ();
  616. }
  617. private int ReadChar ()
  618. {
  619. int ch = reader.Read ();
  620. if (ch == '\n') {
  621. line++;
  622. column = 1;
  623. } else {
  624. column++;
  625. }
  626. if (saveToXmlBuffer) {
  627. xmlBuffer.Append ((char) ch);
  628. }
  629. currentTag.Append ((char) ch);
  630. return ch;
  631. }
  632. // This should really keep track of some state so
  633. // that it's not possible to have more than one document
  634. // element or text outside of the document element.
  635. private bool ReadContent ()
  636. {
  637. currentTag.Length = 0;
  638. if (popScope) {
  639. parserContext.NamespaceManager.PopScope ();
  640. popScope = false;
  641. }
  642. if (returnEntityReference) {
  643. SetEntityReferenceProperties ();
  644. } else {
  645. switch (PeekChar ())
  646. {
  647. case '<':
  648. ReadChar ();
  649. ReadTag ();
  650. break;
  651. case '\r':
  652. if (whitespaceHandling == WhitespaceHandling.All ||
  653. whitespaceHandling == WhitespaceHandling.Significant)
  654. return ReadWhitespace ();
  655. ReadChar ();
  656. return ReadContent ();
  657. case '\n':
  658. if (whitespaceHandling == WhitespaceHandling.All ||
  659. whitespaceHandling == WhitespaceHandling.Significant)
  660. return ReadWhitespace ();
  661. ReadChar ();
  662. return ReadContent ();
  663. case ' ':
  664. if (whitespaceHandling == WhitespaceHandling.All ||
  665. whitespaceHandling == WhitespaceHandling.Significant)
  666. return ReadWhitespace ();
  667. SkipWhitespace ();
  668. return ReadContent ();
  669. case -1:
  670. readState = ReadState.EndOfFile;
  671. SetProperties (
  672. XmlNodeType.None, // nodeType
  673. String.Empty, // name
  674. false, // isEmptyElement
  675. String.Empty, // value
  676. true // clearAttributes
  677. );
  678. break;
  679. default:
  680. ReadText (true);
  681. break;
  682. }
  683. }
  684. return this.ReadState != ReadState.EndOfFile;
  685. }
  686. private void SetEntityReferenceProperties ()
  687. {
  688. SetProperties (
  689. XmlNodeType.EntityReference, // nodeType
  690. entityReferenceName, // name
  691. false, // isEmptyElement
  692. String.Empty, // value
  693. true // clearAttributes
  694. );
  695. returnEntityReference = false;
  696. entityReferenceName = String.Empty;
  697. }
  698. // The leading '<' has already been consumed.
  699. private void ReadTag ()
  700. {
  701. switch (PeekChar ())
  702. {
  703. case '/':
  704. ReadChar ();
  705. ReadEndTag ();
  706. break;
  707. case '?':
  708. ReadChar ();
  709. ReadProcessingInstruction ();
  710. break;
  711. case '!':
  712. ReadChar ();
  713. ReadDeclaration ();
  714. break;
  715. default:
  716. ReadStartTag ();
  717. break;
  718. }
  719. }
  720. // The leading '<' has already been consumed.
  721. private void ReadStartTag ()
  722. {
  723. parserContext.NamespaceManager.PushScope ();
  724. string name = ReadName ();
  725. SkipWhitespace ();
  726. bool isEmptyElement = false;
  727. ClearAttributes ();
  728. if (XmlChar.IsFirstNameChar (PeekChar ()))
  729. ReadAttributes ();
  730. if (PeekChar () == '/') {
  731. ReadChar ();
  732. isEmptyElement = true;
  733. depthDown = true;
  734. popScope = true;
  735. }
  736. Expect ('>');
  737. SetProperties (
  738. XmlNodeType.Element, // nodeType
  739. name, // name
  740. isEmptyElement, // isEmptyElement
  741. String.Empty, // value
  742. false // clearAttributes
  743. );
  744. if (!depthDown)
  745. ++depth;
  746. else
  747. depthDown = false;
  748. }
  749. // The reader is positioned on the first character
  750. // of the element's name.
  751. private void ReadEndTag ()
  752. {
  753. string name = ReadName ();
  754. SkipWhitespace ();
  755. Expect ('>');
  756. --depth;
  757. SetProperties (
  758. XmlNodeType.EndElement, // nodeType
  759. name, // name
  760. false, // isEmptyElement
  761. String.Empty, // value
  762. true // clearAttributes
  763. );
  764. popScope = true;
  765. }
  766. private void AppendNameChar (int ch)
  767. {
  768. CheckNameCapacity ();
  769. nameBuffer [nameLength++] = (char)ch;
  770. }
  771. private void CheckNameCapacity ()
  772. {
  773. if (nameLength == nameCapacity) {
  774. nameCapacity = nameCapacity * 2;
  775. char [] oldNameBuffer = nameBuffer;
  776. nameBuffer = new char [nameCapacity];
  777. Array.Copy (oldNameBuffer, nameBuffer, nameLength);
  778. }
  779. }
  780. private string CreateNameString ()
  781. {
  782. return new String (nameBuffer, 0, nameLength);
  783. }
  784. private void AppendValueChar (int ch)
  785. {
  786. CheckValueCapacity ();
  787. valueBuffer [valueLength++] = (char)ch;
  788. }
  789. private void CheckValueCapacity ()
  790. {
  791. if (valueLength == valueCapacity) {
  792. valueCapacity = valueCapacity * 2;
  793. char [] oldValueBuffer = valueBuffer;
  794. valueBuffer = new char [valueCapacity];
  795. Array.Copy (oldValueBuffer, valueBuffer, valueLength);
  796. }
  797. }
  798. private string CreateValueString ()
  799. {
  800. return new String (valueBuffer, 0, valueLength);
  801. }
  802. // The reader is positioned on the first character
  803. // of the text.
  804. private void ReadText (bool cleanValue)
  805. {
  806. if (cleanValue)
  807. valueLength = 0;
  808. int ch = PeekChar ();
  809. while (ch != '<' && ch != -1) {
  810. if (ch == '&') {
  811. ReadChar ();
  812. if (ReadReference (false))
  813. break;
  814. } else
  815. AppendValueChar (ReadChar ());
  816. ch = PeekChar ();
  817. }
  818. if (returnEntityReference && valueLength == 0) {
  819. SetEntityReferenceProperties ();
  820. } else {
  821. SetProperties (
  822. XmlNodeType.Text, // nodeType
  823. String.Empty, // name
  824. false, // isEmptyElement
  825. CreateValueString (), // value
  826. true // clearAttributes
  827. );
  828. }
  829. }
  830. // The leading '&' has already been consumed.
  831. // Returns true if the entity reference isn't a simple
  832. // character reference or one of the predefined entities.
  833. // This allows the ReadText method to break so that the
  834. // next call to Read will return the EntityReference node.
  835. private bool ReadReference (bool ignoreEntityReferences)
  836. {
  837. if (PeekChar () == '#') {
  838. ReadChar ();
  839. ReadCharacterReference ();
  840. } else
  841. ReadEntityReference (ignoreEntityReferences);
  842. return returnEntityReference;
  843. }
  844. private void ReadCharacterReference ()
  845. {
  846. int value = 0;
  847. if (PeekChar () == 'x') {
  848. ReadChar ();
  849. while (PeekChar () != ';' && PeekChar () != -1) {
  850. int ch = ReadChar ();
  851. if (ch >= '0' && ch <= '9')
  852. value = (value << 4) + ch - '0';
  853. else if (ch >= 'A' && ch <= 'F')
  854. value = (value << 4) + ch - 'A' + 10;
  855. else if (ch >= 'a' && ch <= 'f')
  856. value = (value << 4) + ch - 'a' + 10;
  857. else
  858. throw new XmlException (
  859. String.Format (
  860. "invalid hexadecimal digit: {0} (#x{1:X})",
  861. (char)ch,
  862. ch));
  863. }
  864. } else {
  865. while (PeekChar () != ';' && PeekChar () != -1) {
  866. int ch = ReadChar ();
  867. if (ch >= '0' && ch <= '9')
  868. value = value * 10 + ch - '0';
  869. else
  870. throw new XmlException (
  871. String.Format (
  872. "invalid decimal digit: {0} (#x{1:X})",
  873. (char)ch,
  874. ch));
  875. }
  876. }
  877. ReadChar (); // ';'
  878. AppendValueChar (value);
  879. }
  880. private void ReadEntityReference (bool ignoreEntityReferences)
  881. {
  882. nameLength = 0;
  883. int ch = PeekChar ();
  884. while (ch != ';' && ch != -1) {
  885. AppendNameChar (ReadChar ());
  886. ch = PeekChar ();
  887. }
  888. Expect (';');
  889. string name = CreateNameString ();
  890. switch (name)
  891. {
  892. case "lt":
  893. AppendValueChar ('<');
  894. break;
  895. case "gt":
  896. AppendValueChar ('>');
  897. break;
  898. case "amp":
  899. AppendValueChar ('&');
  900. break;
  901. case "apos":
  902. AppendValueChar ('\'');
  903. break;
  904. case "quot":
  905. AppendValueChar ('"');
  906. break;
  907. default:
  908. if (ignoreEntityReferences) {
  909. AppendValueChar ('&');
  910. foreach (char ch2 in name) {
  911. AppendValueChar (ch2);
  912. }
  913. AppendValueChar (';');
  914. } else {
  915. returnEntityReference = true;
  916. entityReferenceName = name;
  917. }
  918. break;
  919. }
  920. }
  921. // The reader is positioned on the first character of
  922. // the attribute name.
  923. private void ReadAttributes ()
  924. {
  925. do {
  926. string name = ReadName ();
  927. SkipWhitespace ();
  928. Expect ('=');
  929. SkipWhitespace ();
  930. string value = ReadAttribute ();
  931. SkipWhitespace ();
  932. if (name == "xmlns")
  933. parserContext.NamespaceManager.AddNamespace (String.Empty, value);
  934. else if (name.StartsWith ("xmlns:"))
  935. parserContext.NamespaceManager.AddNamespace (name.Substring (6), value);
  936. AddAttribute (name, value);
  937. } while (PeekChar () != '/' && PeekChar () != '>' && PeekChar () != -1);
  938. }
  939. // The reader is positioned on the quote character.
  940. private string ReadAttribute ()
  941. {
  942. int quoteChar = ReadChar ();
  943. if (quoteChar != '\'' && quoteChar != '\"')
  944. throw new XmlException ("an attribute value was not quoted");
  945. valueLength = 0;
  946. while (PeekChar () != quoteChar) {
  947. int ch = ReadChar ();
  948. switch (ch)
  949. {
  950. case '<':
  951. throw new XmlException ("attribute values cannot contain '<'");
  952. case '&':
  953. ReadReference (true);
  954. break;
  955. case -1:
  956. throw new XmlException ("unexpected end of file in an attribute value");
  957. default:
  958. AppendValueChar (ch);
  959. break;
  960. }
  961. }
  962. ReadChar (); // quoteChar
  963. return CreateValueString ();
  964. }
  965. // The reader is positioned on the first character
  966. // of the target.
  967. //
  968. // Now it also reads XmlDeclaration, this method name became improper...
  969. private void ReadProcessingInstruction ()
  970. {
  971. string target = ReadName ();
  972. SkipWhitespace ();
  973. valueLength = 0;
  974. while (PeekChar () != -1) {
  975. int ch = ReadChar ();
  976. if (ch == '?' && PeekChar () == '>') {
  977. ReadChar ();
  978. break;
  979. }
  980. AppendValueChar ((char)ch);
  981. }
  982. SetProperties (
  983. target == "xml" ?
  984. XmlNodeType.XmlDeclaration :
  985. XmlNodeType.ProcessingInstruction, // nodeType
  986. target, // name
  987. false, // isEmptyElement
  988. CreateValueString (), // value
  989. true // clearAttributes
  990. );
  991. }
  992. // The reader is positioned on the first character after
  993. // the leading '<!'.
  994. private void ReadDeclaration ()
  995. {
  996. int ch = PeekChar ();
  997. switch (ch)
  998. {
  999. case '-':
  1000. Expect ("--");
  1001. ReadComment ();
  1002. break;
  1003. case '[':
  1004. ReadChar ();
  1005. Expect ("CDATA[");
  1006. ReadCDATA ();
  1007. break;
  1008. case 'D':
  1009. Expect ("DOCTYPE");
  1010. ReadDoctypeDecl ();
  1011. break;
  1012. }
  1013. }
  1014. // The reader is positioned on the first character after
  1015. // the leading '<!--'.
  1016. private void ReadComment ()
  1017. {
  1018. valueLength = 0;
  1019. while (PeekChar () != -1) {
  1020. int ch = ReadChar ();
  1021. if (ch == '-' && PeekChar () == '-') {
  1022. ReadChar ();
  1023. if (PeekChar () != '>')
  1024. throw new XmlException ("comments cannot contain '--'");
  1025. ReadChar ();
  1026. break;
  1027. }
  1028. AppendValueChar ((char)ch);
  1029. }
  1030. SetProperties (
  1031. XmlNodeType.Comment, // nodeType
  1032. String.Empty, // name
  1033. false, // isEmptyElement
  1034. CreateValueString (), // value
  1035. true // clearAttributes
  1036. );
  1037. }
  1038. // The reader is positioned on the first character after
  1039. // the leading '<![CDATA['.
  1040. private void ReadCDATA ()
  1041. {
  1042. valueLength = 0;
  1043. while (PeekChar () != -1) {
  1044. int ch = ReadChar ();
  1045. if (ch == ']' && PeekChar () == ']') {
  1046. ch = ReadChar (); // ']'
  1047. if (PeekChar () == '>') {
  1048. ReadChar (); // '>'
  1049. break;
  1050. } else {
  1051. AppendValueChar (']');
  1052. AppendValueChar (']');
  1053. ch = ReadChar ();
  1054. }
  1055. }
  1056. AppendValueChar ((char)ch);
  1057. }
  1058. SetProperties (
  1059. XmlNodeType.CDATA, // nodeType
  1060. String.Empty, // name
  1061. false, // isEmptyElement
  1062. CreateValueString (), // value
  1063. true // clearAttributes
  1064. );
  1065. }
  1066. // The reader is positioned on the first character after
  1067. // the leading '<!DOCTYPE'.
  1068. private void ReadDoctypeDecl ()
  1069. {
  1070. string doctypeName = null;
  1071. string publicId = String.Empty;
  1072. string systemId = String.Empty;
  1073. string internalSubset = String.Empty;
  1074. SkipWhitespace();
  1075. doctypeName = ReadName();
  1076. SkipWhitespace();
  1077. xmlBuffer.Length = 0;
  1078. switch(PeekChar())
  1079. {
  1080. case 'S':
  1081. systemId = ReadSystemLiteral();
  1082. break;
  1083. case 'P':
  1084. /*
  1085. Expect("PUBLIC");
  1086. SkipWhitespace();
  1087. int quoteChar = ReadChar();
  1088. int c = 0;
  1089. while(c != quoteChar)
  1090. {
  1091. c = ReadChar();
  1092. if(c < 0)
  1093. throw new XmlException("Unexpected end of stream in ExternalID.");
  1094. if(c != quoteChar)
  1095. {
  1096. if(XmlChar.IsPubidChar(c)) xmlBuffer.Append((char)c);
  1097. else
  1098. throw new XmlException("character '" + (char)c + "' not allowed for PUBLIC ID");
  1099. }
  1100. }
  1101. publicId = xmlBuffer.ToString();
  1102. */
  1103. publicId = ReadPubidLiteral();
  1104. SkipWhitespace();
  1105. systemId = ReadSystemLiteral();
  1106. break;
  1107. }
  1108. SkipWhitespace();
  1109. if(PeekChar() == '[')
  1110. {
  1111. // read markupdecl etc. or end of decl
  1112. ReadChar();
  1113. saveToXmlBuffer = true;
  1114. do
  1115. {
  1116. ReadDTDInternalSubset();
  1117. } while(nodeType != XmlNodeType.None);
  1118. xmlBuffer.Remove(xmlBuffer.Length -1, 1); // cut off ']'
  1119. saveToXmlBuffer = false;
  1120. }
  1121. // end of DOCTYPE decl.
  1122. SkipWhitespace();
  1123. Expect('>');
  1124. internalSubset = xmlBuffer.ToString();
  1125. // set properties for <!DOCTYPE> node
  1126. SetProperties (
  1127. XmlNodeType.DocumentType, // nodeType
  1128. doctypeName, // name
  1129. false, // isEmptyElement
  1130. internalSubset, // value
  1131. true // clearAttributes
  1132. );
  1133. }
  1134. // Read any one of following:
  1135. // elementdecl, AttlistDecl, EntityDecl, NotationDecl,
  1136. // PI, Comment, Parameter Entity, or doctype termination char(']')
  1137. //
  1138. // returns a node of some nodeType or null, setting nodeType.
  1139. // (if None then ']' was found.)
  1140. private void ReadDTDInternalSubset()
  1141. {
  1142. SkipWhitespace();
  1143. switch(ReadChar())
  1144. {
  1145. case ']':
  1146. nodeType = XmlNodeType.None;
  1147. break;
  1148. case '%':
  1149. string peName = ReadName();
  1150. Expect(';');
  1151. nodeType = XmlNodeType.EntityReference; // It's chating a bit;-)
  1152. break;
  1153. case '<':
  1154. switch(ReadChar())
  1155. {
  1156. case '?':
  1157. ReadProcessingInstruction();
  1158. break;
  1159. case '!':
  1160. switch(ReadChar())
  1161. {
  1162. case '-':
  1163. Expect('-');
  1164. ReadComment();
  1165. break;
  1166. case 'E':
  1167. switch(ReadChar())
  1168. {
  1169. case 'N':
  1170. Expect("TITY");
  1171. ReadEntityDecl();
  1172. break;
  1173. case 'L':
  1174. Expect("EMENT");
  1175. ReadElementDecl();
  1176. break;
  1177. default:
  1178. throw new XmlException("Syntax Error after '<!E' (ELEMENT or ENTITY must be found)");
  1179. }
  1180. break;
  1181. case 'A':
  1182. Expect("TTLIST");
  1183. ReadAttListDecl();
  1184. break;
  1185. case 'N':
  1186. Expect("OTATION");
  1187. ReadNotationDecl();
  1188. break;
  1189. default:
  1190. throw new XmlException("Syntax Error after '<!' characters.");
  1191. }
  1192. break;
  1193. default:
  1194. throw new XmlException("Syntax Error after '<' character.");
  1195. }
  1196. break;
  1197. default:
  1198. throw new XmlException("Syntax Error inside doctypedecl markup.");
  1199. }
  1200. }
  1201. // The reader is positioned on the head of the name.
  1202. private void ReadElementDecl()
  1203. {
  1204. while(ReadChar() != '>');
  1205. }
  1206. private void ReadEntityDecl()
  1207. {
  1208. while(ReadChar() != '>');
  1209. }
  1210. private void ReadAttListDecl()
  1211. {
  1212. while(ReadChar() != '>');
  1213. }
  1214. private void ReadNotationDecl()
  1215. {
  1216. while(ReadChar() != '>');
  1217. }
  1218. // The reader is positioned on the first 'S' of "SYSTEM".
  1219. private string ReadSystemLiteral ()
  1220. {
  1221. Expect("SYSTEM");
  1222. SkipWhitespace();
  1223. int quoteChar = ReadChar(); // apos or quot
  1224. xmlBuffer.Length = 0;
  1225. saveToXmlBuffer = true;
  1226. int c = 0;
  1227. while(c != quoteChar)
  1228. {
  1229. c = ReadChar();
  1230. if(c < 0) throw new XmlException("Unexpected end of stream in ExternalID.");
  1231. }
  1232. saveToXmlBuffer = false;
  1233. xmlBuffer.Remove(xmlBuffer.Length-1, 1); // cut quoteChar
  1234. return xmlBuffer.ToString();
  1235. }
  1236. private string ReadPubidLiteral()
  1237. {
  1238. Expect("PUBLIC");
  1239. SkipWhitespace();
  1240. int quoteChar = ReadChar();
  1241. xmlBuffer.Length = 0;
  1242. saveToXmlBuffer = true;
  1243. int c = 0;
  1244. while(c != quoteChar)
  1245. {
  1246. c = ReadChar();
  1247. if(c < 0) throw new XmlException("Unexpected end of stream in ExternalID.");
  1248. if(c != quoteChar && !XmlChar.IsPubidChar(c))
  1249. throw new XmlException("character '" + (char)c + "' not allowed for PUBLIC ID");
  1250. }
  1251. xmlBuffer.Remove(xmlBuffer.Length-1, 1); // cut quoteChar
  1252. saveToXmlBuffer = false;
  1253. return xmlBuffer.ToString();
  1254. }
  1255. // The reader is positioned on the first character
  1256. // of the name.
  1257. private string ReadName ()
  1258. {
  1259. if (!XmlChar.IsFirstNameChar (PeekChar ()))
  1260. throw new XmlException ("a name did not start with a legal character");
  1261. nameLength = 0;
  1262. AppendNameChar (ReadChar ());
  1263. while (XmlChar.IsNameChar (PeekChar ())) {
  1264. AppendNameChar (ReadChar ());
  1265. }
  1266. return CreateNameString ();
  1267. }
  1268. // Read the next character and compare it against the
  1269. // specified character.
  1270. private void Expect (int expected)
  1271. {
  1272. int ch = ReadChar ();
  1273. if (ch != expected) {
  1274. throw new XmlException (
  1275. String.Format (
  1276. "expected '{0}' ({1:X}) but found '{2}' ({3:X})",
  1277. (char)expected,
  1278. expected,
  1279. (char)ch,
  1280. ch));
  1281. }
  1282. }
  1283. private void Expect (string expected)
  1284. {
  1285. int len = expected.Length;
  1286. for(int i=0; i< len; i++)
  1287. Expect(expected[i]);
  1288. }
  1289. // Does not consume the first non-whitespace character.
  1290. private void SkipWhitespace ()
  1291. {
  1292. //FIXME: Should not skip if whitespaceHandling == WhiteSpaceHandling.None
  1293. while (XmlChar.IsWhitespace (PeekChar ()))
  1294. ReadChar ();
  1295. }
  1296. private bool ReadWhitespace ()
  1297. {
  1298. valueLength = 0;
  1299. int ch = PeekChar ();
  1300. do {
  1301. AppendValueChar (ReadChar ());
  1302. } while ((ch = PeekChar ()) != -1 && XmlChar.IsWhitespace (ch));
  1303. if (ch != -1 && ch != '<')
  1304. ReadText (false);
  1305. else
  1306. SetProperties (XmlNodeType.Whitespace,
  1307. String.Empty,
  1308. false,
  1309. CreateValueString (),
  1310. true);
  1311. return (PeekChar () != -1);
  1312. }
  1313. }
  1314. }