XmlTextReader.cs 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280
  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. //
  16. // There's also no checking being done for either well-formedness
  17. // or validity.
  18. //
  19. // NameTables aren't being used everywhere yet.
  20. //
  21. // Some thought needs to be given to performance. There's too many
  22. // strings being allocated.
  23. //
  24. // Some of the MoveTo methods haven't been implemented yet.
  25. //
  26. // LineNumber and LinePosition aren't being tracked.
  27. //
  28. // xml:space, xml:lang, and xml:base aren't being tracked.
  29. //
  30. using System;
  31. using System.Collections;
  32. using System.IO;
  33. using System.Text;
  34. namespace System.Xml
  35. {
  36. public class XmlTextReader : XmlReader, IXmlLineInfo
  37. {
  38. #region Constructors
  39. [MonoTODO]
  40. protected XmlTextReader ()
  41. {
  42. throw new NotImplementedException ();
  43. }
  44. [MonoTODO]
  45. public XmlTextReader (Stream input)
  46. {
  47. throw new NotImplementedException ();
  48. }
  49. [MonoTODO]
  50. public XmlTextReader (string url)
  51. {
  52. XmlNameTable nt = new NameTable ();
  53. XmlNamespaceManager nsMgr = new XmlNamespaceManager (nt);
  54. parserContext = new XmlParserContext (null, nsMgr, null, XmlSpace.None);
  55. Init ();
  56. reader = new StreamReader(url);
  57. }
  58. [MonoTODO]
  59. public XmlTextReader (TextReader input)
  60. {
  61. XmlNameTable nt = new NameTable ();
  62. XmlNamespaceManager nsMgr = new XmlNamespaceManager (nt);
  63. parserContext = new XmlParserContext (null, nsMgr, null, XmlSpace.None);
  64. Init ();
  65. reader = input;
  66. }
  67. [MonoTODO]
  68. protected XmlTextReader (XmlNameTable nt)
  69. {
  70. throw new NotImplementedException ();
  71. }
  72. [MonoTODO]
  73. public XmlTextReader (Stream input, XmlNameTable nt)
  74. {
  75. throw new NotImplementedException ();
  76. }
  77. [MonoTODO]
  78. public XmlTextReader (string url, Stream input)
  79. {
  80. throw new NotImplementedException ();
  81. }
  82. [MonoTODO]
  83. public XmlTextReader (string url, TextReader input)
  84. {
  85. throw new NotImplementedException ();
  86. }
  87. [MonoTODO]
  88. public XmlTextReader (string url, XmlNameTable nt)
  89. {
  90. throw new NotImplementedException ();
  91. }
  92. [MonoTODO]
  93. public XmlTextReader (TextReader input, XmlNameTable nt)
  94. {
  95. throw new NotImplementedException ();
  96. }
  97. [MonoTODO]
  98. public XmlTextReader (Stream xmlFragment, XmlNodeType fragType, XmlParserContext context)
  99. {
  100. throw new NotImplementedException ();
  101. }
  102. [MonoTODO]
  103. public XmlTextReader (string url, Stream input, XmlNameTable nt)
  104. {
  105. throw new NotImplementedException ();
  106. }
  107. [MonoTODO]
  108. public XmlTextReader (string url, TextReader input, XmlNameTable nt)
  109. {
  110. throw new NotImplementedException ();
  111. }
  112. [MonoTODO]
  113. public XmlTextReader (string xmlFragment, XmlNodeType fragType, XmlParserContext context)
  114. {
  115. //Waiting for Validating reader for fragType rules.
  116. parserContext = context;
  117. Init ();
  118. reader = new StringReader(xmlFragment);
  119. }
  120. #endregion
  121. #region Properties
  122. public override int AttributeCount
  123. {
  124. get { return attributes.Count; }
  125. }
  126. [MonoTODO]
  127. public override string BaseURI
  128. {
  129. get { throw new NotImplementedException (); }
  130. }
  131. public override int Depth
  132. {
  133. get { return depth > 0 ? depth : 0; }
  134. }
  135. [MonoTODO]
  136. public Encoding Encoding
  137. {
  138. get { throw new NotImplementedException (); }
  139. }
  140. public override bool EOF
  141. {
  142. get
  143. {
  144. return
  145. readState == ReadState.EndOfFile ||
  146. readState == ReadState.Closed;
  147. }
  148. }
  149. public override bool HasValue
  150. {
  151. get { return value != String.Empty; }
  152. }
  153. public override bool IsDefault
  154. {
  155. get
  156. {
  157. // XmlTextReader does not expand default attributes.
  158. return false;
  159. }
  160. }
  161. public override bool IsEmptyElement
  162. {
  163. get { return isEmptyElement; }
  164. }
  165. public override string this [int i]
  166. {
  167. get { return GetAttribute (i); }
  168. }
  169. public override string this [string name]
  170. {
  171. get { return GetAttribute (name); }
  172. }
  173. public override string this [string localName, string namespaceName]
  174. {
  175. get { return GetAttribute (localName, namespaceName); }
  176. }
  177. [MonoTODO]
  178. public int LineNumber
  179. {
  180. get { throw new NotImplementedException (); }
  181. }
  182. [MonoTODO]
  183. public int LinePosition
  184. {
  185. get { throw new NotImplementedException (); }
  186. }
  187. public override string LocalName
  188. {
  189. get { return localName; }
  190. }
  191. public override string Name
  192. {
  193. get { return name; }
  194. }
  195. [MonoTODO]
  196. public bool Namespaces
  197. {
  198. get { throw new NotImplementedException (); }
  199. set { throw new NotImplementedException (); }
  200. }
  201. public override string NamespaceURI
  202. {
  203. get { return namespaceURI; }
  204. }
  205. public override XmlNameTable NameTable
  206. {
  207. get { return parserContext.NameTable; }
  208. }
  209. public override XmlNodeType NodeType
  210. {
  211. get { return nodeType; }
  212. }
  213. [MonoTODO]
  214. public bool Normalization
  215. {
  216. get { throw new NotImplementedException (); }
  217. set { throw new NotImplementedException (); }
  218. }
  219. public override string Prefix
  220. {
  221. get { return prefix; }
  222. }
  223. [MonoTODO]
  224. public override char QuoteChar
  225. {
  226. get { throw new NotImplementedException (); }
  227. }
  228. public override ReadState ReadState
  229. {
  230. get { return readState; }
  231. }
  232. public override string Value
  233. {
  234. get { return value; }
  235. }
  236. [MonoTODO]
  237. public WhitespaceHandling WhitespaceHandling
  238. {
  239. get { throw new NotImplementedException (); }
  240. set { throw new NotImplementedException (); }
  241. }
  242. [MonoTODO]
  243. public override string XmlLang
  244. {
  245. get { throw new NotImplementedException (); }
  246. }
  247. [MonoTODO]
  248. public XmlResolver XmlResolver
  249. {
  250. set { throw new NotImplementedException (); }
  251. }
  252. [MonoTODO]
  253. public override XmlSpace XmlSpace
  254. {
  255. get { throw new NotImplementedException (); }
  256. }
  257. #endregion
  258. #region Methods
  259. [MonoTODO]
  260. public override void Close ()
  261. {
  262. readState = ReadState.Closed;
  263. }
  264. [MonoTODO]
  265. public override string GetAttribute (int i)
  266. {
  267. throw new NotImplementedException ();
  268. }
  269. public override string GetAttribute (string name)
  270. {
  271. return attributes [name] as string;
  272. }
  273. public override string GetAttribute (string localName, string namespaceURI)
  274. {
  275. foreach (DictionaryEntry entry in attributes)
  276. {
  277. string thisName = entry.Key as string;
  278. int indexOfColon = thisName.IndexOf (':');
  279. if (indexOfColon != -1) {
  280. string thisLocalName = thisName.Substring (indexOfColon + 1);
  281. if (localName == thisLocalName) {
  282. string thisPrefix = thisName.Substring (0, indexOfColon);
  283. string thisNamespaceURI = LookupNamespace (thisPrefix);
  284. if (namespaceURI == thisNamespaceURI)
  285. return attributes [thisName] as string;
  286. }
  287. } else if (localName == "xmlns" && namespaceURI == "http://www.w3.org/2000/xmlns/" && thisName == "xmlns")
  288. return attributes [thisName] as string;
  289. }
  290. return String.Empty;
  291. }
  292. [MonoTODO]
  293. public TextReader GetRemainder ()
  294. {
  295. throw new NotImplementedException ();
  296. }
  297. [MonoTODO]
  298. bool IXmlLineInfo.HasLineInfo ()
  299. {
  300. throw new NotImplementedException ();
  301. }
  302. public override string LookupNamespace (string prefix)
  303. {
  304. return parserContext.NamespaceManager.LookupNamespace (prefix);
  305. }
  306. [MonoTODO]
  307. public override void MoveToAttribute (int i)
  308. {
  309. throw new NotImplementedException ();
  310. }
  311. public override bool MoveToAttribute (string name)
  312. {
  313. MoveToElement ();
  314. bool match = false;
  315. if (attributes == null)
  316. return false;
  317. if (orderedAttributesEnumerator == null) {
  318. SaveProperties ();
  319. orderedAttributesEnumerator = orderedAttributes.GetEnumerator ();
  320. }
  321. while (orderedAttributesEnumerator.MoveNext ()) {
  322. if(name == orderedAttributesEnumerator.Current as string) {
  323. match = true;
  324. break;
  325. }
  326. }
  327. if (match) {
  328. string value = attributes [name] as string;
  329. SetProperties (
  330. XmlNodeType.Attribute, // nodeType
  331. name, // name
  332. false, // isEmptyElement
  333. value, // value
  334. false // clearAttributes
  335. );
  336. }
  337. return match;
  338. }
  339. [MonoTODO]
  340. public override bool MoveToAttribute (string localName, string namespaceName)
  341. {
  342. throw new NotImplementedException ();
  343. }
  344. public override bool MoveToElement ()
  345. {
  346. if (orderedAttributesEnumerator != null) {
  347. orderedAttributesEnumerator = null;
  348. RestoreProperties ();
  349. return true;
  350. }
  351. return false;
  352. }
  353. public override bool MoveToFirstAttribute ()
  354. {
  355. MoveToElement ();
  356. return MoveToNextAttribute ();
  357. }
  358. public override bool MoveToNextAttribute ()
  359. {
  360. if (attributes == null)
  361. return false;
  362. if (orderedAttributesEnumerator == null) {
  363. SaveProperties ();
  364. orderedAttributesEnumerator = orderedAttributes.GetEnumerator ();
  365. }
  366. if (orderedAttributesEnumerator.MoveNext ()) {
  367. string name = orderedAttributesEnumerator.Current as string;
  368. string value = attributes [name] as string;
  369. SetProperties (
  370. XmlNodeType.Attribute, // nodeType
  371. name, // name
  372. false, // isEmptyElement
  373. value, // value
  374. false // clearAttributes
  375. );
  376. return true;
  377. }
  378. return false;
  379. }
  380. public override bool Read ()
  381. {
  382. bool more = false;
  383. readState = ReadState.Interactive;
  384. more = ReadContent ();
  385. return more;
  386. }
  387. [MonoTODO]
  388. public override bool ReadAttributeValue ()
  389. {
  390. throw new NotImplementedException ();
  391. }
  392. [MonoTODO]
  393. public int ReadBase64 (byte [] buffer, int offset, int length)
  394. {
  395. throw new NotImplementedException ();
  396. }
  397. [MonoTODO]
  398. public int ReadBinHex (byte [] buffer, int offset, int length)
  399. {
  400. throw new NotImplementedException ();
  401. }
  402. [MonoTODO]
  403. public int ReadChars (char [] buffer, int offset, int length)
  404. {
  405. throw new NotImplementedException ();
  406. }
  407. [MonoTODO]
  408. public override string ReadInnerXml ()
  409. {
  410. // Still need a Well Formedness check.
  411. // Will wait for Validating reader ;-)
  412. if (NodeType == XmlNodeType.Attribute) {
  413. return Value;
  414. } else {
  415. saveToXmlBuffer = true;
  416. string startname = this.Name;
  417. string endname = string.Empty;
  418. readState = ReadState.Interactive;
  419. while (startname != endname) {
  420. ReadContent ();
  421. endname = this.Name;
  422. }
  423. xmlBuffer.Replace(currentTag.ToString (), "");
  424. saveToXmlBuffer = false;
  425. string InnerXml = xmlBuffer.ToString ();
  426. xmlBuffer.Length = 0;
  427. return InnerXml;
  428. }
  429. }
  430. [MonoTODO]
  431. public override string ReadOuterXml ()
  432. {
  433. // Still need a Well Formedness check.
  434. // Will wait for Validating reader ;-)
  435. if (NodeType == XmlNodeType.Attribute) {
  436. return Name+"=\""+Value+"\"";
  437. } else {
  438. saveToXmlBuffer = true;
  439. xmlBuffer.Append(currentTag.ToString ());
  440. string startname = this.Name;
  441. string endname = string.Empty;
  442. readState = ReadState.Interactive;
  443. while (startname != endname) {
  444. ReadContent ();
  445. endname = this.Name;
  446. }
  447. saveToXmlBuffer = false;
  448. string OuterXml = xmlBuffer.ToString ();
  449. xmlBuffer.Length = 0;
  450. return OuterXml;
  451. }
  452. }
  453. [MonoTODO]
  454. public override string ReadString ()
  455. {
  456. throw new NotImplementedException ();
  457. }
  458. [MonoTODO]
  459. public void ResetState ()
  460. {
  461. throw new NotImplementedException ();
  462. }
  463. public override void ResolveEntity ()
  464. {
  465. // XmlTextReaders don't resolve entities.
  466. throw new InvalidOperationException ("XmlTextReaders don't resolve entities.");
  467. }
  468. #endregion
  469. // privates
  470. private XmlParserContext parserContext;
  471. private TextReader reader;
  472. private ReadState readState;
  473. private int depth;
  474. private bool depthDown;
  475. private bool popScope;
  476. private XmlNodeType nodeType;
  477. private string name;
  478. private string prefix;
  479. private string localName;
  480. private string namespaceURI;
  481. private bool isEmptyElement;
  482. private string value;
  483. private XmlNodeType saveNodeType;
  484. private string saveName;
  485. private string savePrefix;
  486. private string saveLocalName;
  487. private string saveNamespaceURI;
  488. private bool saveIsEmptyElement;
  489. private Hashtable attributes;
  490. private ArrayList orderedAttributes;
  491. private IEnumerator orderedAttributesEnumerator;
  492. private bool returnEntityReference;
  493. private string entityReferenceName;
  494. private char [] nameBuffer;
  495. private int nameLength;
  496. private int nameCapacity;
  497. private const int initialNameCapacity = 256;
  498. private char [] valueBuffer;
  499. private int valueLength;
  500. private int valueCapacity;
  501. private const int initialValueCapacity = 8192;
  502. private StringBuilder xmlBuffer; // This is for Read(Inner|Outer)Xml
  503. private StringBuilder currentTag; // A buffer for ReadContent for ReadOuterXml
  504. private bool saveToXmlBuffer;
  505. private void Init ()
  506. {
  507. readState = ReadState.Initial;
  508. depth = -1;
  509. depthDown = false;
  510. popScope = false;
  511. nodeType = XmlNodeType.None;
  512. name = String.Empty;
  513. prefix = String.Empty;
  514. localName = string.Empty;
  515. isEmptyElement = false;
  516. value = String.Empty;
  517. attributes = new Hashtable ();
  518. orderedAttributes = new ArrayList ();
  519. orderedAttributesEnumerator = null;
  520. returnEntityReference = false;
  521. entityReferenceName = String.Empty;
  522. nameBuffer = new char [initialNameCapacity];
  523. nameLength = 0;
  524. nameCapacity = initialNameCapacity;
  525. valueBuffer = new char [initialValueCapacity];
  526. valueLength = 0;
  527. valueCapacity = initialValueCapacity;
  528. xmlBuffer = new StringBuilder ();
  529. currentTag = new StringBuilder ();
  530. }
  531. // Use this method rather than setting the properties
  532. // directly so that all the necessary properties can
  533. // be changed in harmony with each other. Maybe the
  534. // fields should be in a seperate class to help enforce
  535. // this.
  536. private void SetProperties (
  537. XmlNodeType nodeType,
  538. string name,
  539. bool isEmptyElement,
  540. string value,
  541. bool clearAttributes)
  542. {
  543. this.nodeType = nodeType;
  544. this.name = name;
  545. this.isEmptyElement = isEmptyElement;
  546. this.value = value;
  547. if (clearAttributes)
  548. ClearAttributes ();
  549. int indexOfColon = name.IndexOf (':');
  550. if (indexOfColon == -1) {
  551. prefix = String.Empty;
  552. localName = name;
  553. } else {
  554. prefix = name.Substring (0, indexOfColon);
  555. localName = name.Substring (indexOfColon + 1);
  556. }
  557. namespaceURI = LookupNamespace (prefix);
  558. }
  559. private void SaveProperties ()
  560. {
  561. saveNodeType = nodeType;
  562. saveName = name;
  563. savePrefix = prefix;
  564. saveLocalName = localName;
  565. saveNamespaceURI = namespaceURI;
  566. saveIsEmptyElement = isEmptyElement;
  567. // An element's value is always String.Empty.
  568. }
  569. private void RestoreProperties ()
  570. {
  571. nodeType = saveNodeType;
  572. name = saveName;
  573. prefix = savePrefix;
  574. localName = saveLocalName;
  575. namespaceURI = saveNamespaceURI;
  576. isEmptyElement = saveIsEmptyElement;
  577. value = String.Empty;
  578. }
  579. private void AddAttribute (string name, string value)
  580. {
  581. attributes.Add (name, value);
  582. orderedAttributes.Add (name);
  583. }
  584. private void ClearAttributes ()
  585. {
  586. if (attributes.Count > 0) {
  587. attributes.Clear ();
  588. orderedAttributes.Clear ();
  589. }
  590. orderedAttributesEnumerator = null;
  591. }
  592. private int PeekChar ()
  593. {
  594. return reader.Peek ();
  595. }
  596. private int ReadChar ()
  597. {
  598. int ch = reader.Read ();
  599. if (saveToXmlBuffer) {
  600. xmlBuffer.Append ((char) ch);
  601. }
  602. currentTag.Append ((char) ch);
  603. return ch;
  604. }
  605. // This should really keep track of some state so
  606. // that it's not possible to have more than one document
  607. // element or text outside of the document element.
  608. private bool ReadContent ()
  609. {
  610. bool more = false;
  611. currentTag.Length = 0;
  612. if (popScope) {
  613. parserContext.NamespaceManager.PopScope ();
  614. popScope = false;
  615. }
  616. if (depthDown)
  617. --depth;
  618. if (returnEntityReference) {
  619. ++depth;
  620. SetEntityReferenceProperties ();
  621. more = true;
  622. } else {
  623. switch (PeekChar ())
  624. {
  625. case '<':
  626. ReadChar ();
  627. ReadTag ();
  628. more = true;
  629. break;
  630. case -1:
  631. readState = ReadState.EndOfFile;
  632. SetProperties (
  633. XmlNodeType.None, // nodeType
  634. String.Empty, // name
  635. false, // isEmptyElement
  636. String.Empty, // value
  637. true // clearAttributes
  638. );
  639. more = false;
  640. break;
  641. default:
  642. ReadText ();
  643. more = true;
  644. break;
  645. }
  646. }
  647. return more;
  648. }
  649. private void SetEntityReferenceProperties ()
  650. {
  651. SetProperties (
  652. XmlNodeType.EntityReference, // nodeType
  653. entityReferenceName, // name
  654. false, // isEmptyElement
  655. String.Empty, // value
  656. true // clearAttributes
  657. );
  658. returnEntityReference = false;
  659. entityReferenceName = String.Empty;
  660. }
  661. // The leading '<' has already been consumed.
  662. private void ReadTag ()
  663. {
  664. switch (PeekChar ())
  665. {
  666. case '/':
  667. ReadChar ();
  668. ReadEndTag ();
  669. break;
  670. case '?':
  671. ReadChar ();
  672. ReadProcessingInstruction ();
  673. break;
  674. case '!':
  675. ReadChar ();
  676. ReadDeclaration ();
  677. break;
  678. default:
  679. ReadStartTag ();
  680. break;
  681. }
  682. }
  683. // The leading '<' has already been consumed.
  684. private void ReadStartTag ()
  685. {
  686. parserContext.NamespaceManager.PushScope ();
  687. string name = ReadName ();
  688. SkipWhitespace ();
  689. bool isEmptyElement = false;
  690. ClearAttributes ();
  691. if (XmlChar.IsFirstNameChar (PeekChar ()))
  692. ReadAttributes ();
  693. if (PeekChar () == '/') {
  694. ReadChar ();
  695. isEmptyElement = true;
  696. depthDown = true;
  697. popScope = true;
  698. }
  699. Expect ('>');
  700. ++depth;
  701. SetProperties (
  702. XmlNodeType.Element, // nodeType
  703. name, // name
  704. isEmptyElement, // isEmptyElement
  705. String.Empty, // value
  706. false // clearAttributes
  707. );
  708. }
  709. // The reader is positioned on the first character
  710. // of the element's name.
  711. private void ReadEndTag ()
  712. {
  713. string name = ReadName ();
  714. SkipWhitespace ();
  715. Expect ('>');
  716. --depth;
  717. SetProperties (
  718. XmlNodeType.EndElement, // nodeType
  719. name, // name
  720. false, // isEmptyElement
  721. String.Empty, // value
  722. true // clearAttributes
  723. );
  724. popScope = true;
  725. }
  726. private void AppendNameChar (int ch)
  727. {
  728. CheckNameCapacity ();
  729. nameBuffer [nameLength++] = (char)ch;
  730. }
  731. private void CheckNameCapacity ()
  732. {
  733. if (nameLength == nameCapacity) {
  734. nameCapacity = nameCapacity * 2;
  735. char [] oldNameBuffer = nameBuffer;
  736. nameBuffer = new char [nameCapacity];
  737. Array.Copy (oldNameBuffer, nameBuffer, nameLength);
  738. }
  739. }
  740. private string CreateNameString ()
  741. {
  742. return new String (nameBuffer, 0, nameLength);
  743. }
  744. private void AppendValueChar (int ch)
  745. {
  746. CheckValueCapacity ();
  747. valueBuffer [valueLength++] = (char)ch;
  748. }
  749. private void CheckValueCapacity ()
  750. {
  751. if (valueLength == valueCapacity) {
  752. valueCapacity = valueCapacity * 2;
  753. char [] oldValueBuffer = valueBuffer;
  754. valueBuffer = new char [valueCapacity];
  755. Array.Copy (oldValueBuffer, valueBuffer, valueLength);
  756. }
  757. }
  758. private string CreateValueString ()
  759. {
  760. return new String (valueBuffer, 0, valueLength);
  761. }
  762. // The reader is positioned on the first character
  763. // of the text.
  764. private void ReadText ()
  765. {
  766. valueLength = 0;
  767. int ch = PeekChar ();
  768. while (ch != '<' && ch != -1) {
  769. if (ch == '&') {
  770. ReadChar ();
  771. if (ReadReference (false))
  772. break;
  773. } else
  774. AppendValueChar (ReadChar ());
  775. ch = PeekChar ();
  776. }
  777. if (returnEntityReference && valueLength == 0) {
  778. ++depth;
  779. SetEntityReferenceProperties ();
  780. } else {
  781. if (depth >= 0) {
  782. ++depth;
  783. depthDown = true;
  784. }
  785. SetProperties (
  786. XmlNodeType.Text, // nodeType
  787. String.Empty, // name
  788. false, // isEmptyElement
  789. CreateValueString (), // value
  790. true // clearAttributes
  791. );
  792. }
  793. }
  794. // The leading '&' has already been consumed.
  795. // Returns true if the entity reference isn't a simple
  796. // character reference or one of the predefined entities.
  797. // This allows the ReadText method to break so that the
  798. // next call to Read will return the EntityReference node.
  799. private bool ReadReference (bool ignoreEntityReferences)
  800. {
  801. if (PeekChar () == '#') {
  802. ReadChar ();
  803. ReadCharacterReference ();
  804. } else
  805. ReadEntityReference (ignoreEntityReferences);
  806. return returnEntityReference;
  807. }
  808. private void ReadCharacterReference ()
  809. {
  810. int value = 0;
  811. if (PeekChar () == 'x') {
  812. ReadChar ();
  813. while (PeekChar () != ';' && PeekChar () != -1) {
  814. int ch = ReadChar ();
  815. if (ch >= '0' && ch <= '9')
  816. value = (value << 4) + ch - '0';
  817. else if (ch >= 'A' && ch <= 'F')
  818. value = (value << 4) + ch - 'A' + 10;
  819. else if (ch >= 'a' && ch <= 'f')
  820. value = (value << 4) + ch - 'a' + 10;
  821. else
  822. throw new XmlException (
  823. String.Format (
  824. "invalid hexadecimal digit: {0} (#x{1:X})",
  825. (char)ch,
  826. ch));
  827. }
  828. } else {
  829. while (PeekChar () != ';' && PeekChar () != -1) {
  830. int ch = ReadChar ();
  831. if (ch >= '0' && ch <= '9')
  832. value = value * 10 + ch - '0';
  833. else
  834. throw new XmlException (
  835. String.Format (
  836. "invalid decimal digit: {0} (#x{1:X})",
  837. (char)ch,
  838. ch));
  839. }
  840. }
  841. ReadChar (); // ';'
  842. AppendValueChar (value);
  843. }
  844. private void ReadEntityReference (bool ignoreEntityReferences)
  845. {
  846. nameLength = 0;
  847. int ch = PeekChar ();
  848. while (ch != ';' && ch != -1) {
  849. AppendNameChar (ReadChar ());
  850. ch = PeekChar ();
  851. }
  852. Expect (';');
  853. string name = CreateNameString ();
  854. switch (name)
  855. {
  856. case "lt":
  857. AppendValueChar ('<');
  858. break;
  859. case "gt":
  860. AppendValueChar ('>');
  861. break;
  862. case "amp":
  863. AppendValueChar ('&');
  864. break;
  865. case "apos":
  866. AppendValueChar ('\'');
  867. break;
  868. case "quot":
  869. AppendValueChar ('"');
  870. break;
  871. default:
  872. if (ignoreEntityReferences) {
  873. AppendValueChar ('&');
  874. foreach (char ch2 in name) {
  875. AppendValueChar (ch2);
  876. }
  877. AppendValueChar (';');
  878. } else {
  879. returnEntityReference = true;
  880. entityReferenceName = name;
  881. }
  882. break;
  883. }
  884. }
  885. // The reader is positioned on the first character of
  886. // the attribute name.
  887. private void ReadAttributes ()
  888. {
  889. do {
  890. string name = ReadName ();
  891. SkipWhitespace ();
  892. Expect ('=');
  893. SkipWhitespace ();
  894. string value = ReadAttribute ();
  895. SkipWhitespace ();
  896. if (name == "xmlns")
  897. parserContext.NamespaceManager.AddNamespace (String.Empty, value);
  898. else if (name.StartsWith ("xmlns:"))
  899. parserContext.NamespaceManager.AddNamespace (name.Substring (6), value);
  900. AddAttribute (name, value);
  901. } while (PeekChar () != '/' && PeekChar () != '>' && PeekChar () != -1);
  902. }
  903. // The reader is positioned on the quote character.
  904. private string ReadAttribute ()
  905. {
  906. int quoteChar = ReadChar ();
  907. if (quoteChar != '\'' && quoteChar != '\"')
  908. throw new XmlException ("an attribute value was not quoted");
  909. valueLength = 0;
  910. while (PeekChar () != quoteChar) {
  911. int ch = ReadChar ();
  912. switch (ch)
  913. {
  914. case '<':
  915. throw new XmlException ("attribute values cannot contain '<'");
  916. case '&':
  917. ReadReference (true);
  918. break;
  919. case -1:
  920. throw new XmlException ("unexpected end of file in an attribute value");
  921. default:
  922. AppendValueChar (ch);
  923. break;
  924. }
  925. }
  926. ReadChar (); // quoteChar
  927. return CreateValueString ();
  928. }
  929. // The reader is positioned on the first character
  930. // of the target.
  931. private void ReadProcessingInstruction ()
  932. {
  933. string target = ReadName ();
  934. SkipWhitespace ();
  935. valueLength = 0;
  936. while (PeekChar () != -1) {
  937. int ch = ReadChar ();
  938. if (ch == '?' && PeekChar () == '>') {
  939. ReadChar ();
  940. break;
  941. }
  942. AppendValueChar ((char)ch);
  943. }
  944. SetProperties (
  945. XmlNodeType.ProcessingInstruction, // nodeType
  946. target, // name
  947. false, // isEmptyElement
  948. CreateValueString (), // value
  949. true // clearAttributes
  950. );
  951. }
  952. // The reader is positioned on the first character after
  953. // the leading '<!'.
  954. private void ReadDeclaration ()
  955. {
  956. int ch = PeekChar ();
  957. switch (ch)
  958. {
  959. case '-':
  960. Expect ('-');
  961. Expect ('-');
  962. ReadComment ();
  963. break;
  964. case '[':
  965. ReadChar ();
  966. Expect ('C');
  967. Expect ('D');
  968. Expect ('A');
  969. Expect ('T');
  970. Expect ('A');
  971. Expect ('[');
  972. ReadCDATA ();
  973. break;
  974. }
  975. }
  976. // The reader is positioned on the first character after
  977. // the leading '<!--'.
  978. private void ReadComment ()
  979. {
  980. valueLength = 0;
  981. while (PeekChar () != -1) {
  982. int ch = ReadChar ();
  983. if (ch == '-' && PeekChar () == '-') {
  984. ReadChar ();
  985. if (PeekChar () != '>')
  986. throw new XmlException ("comments cannot contain '--'");
  987. ReadChar ();
  988. break;
  989. }
  990. AppendValueChar ((char)ch);
  991. }
  992. SetProperties (
  993. XmlNodeType.Comment, // nodeType
  994. String.Empty, // name
  995. false, // isEmptyElement
  996. CreateValueString (), // value
  997. true // clearAttributes
  998. );
  999. }
  1000. // The reader is positioned on the first character after
  1001. // the leading '<![CDATA['.
  1002. private void ReadCDATA ()
  1003. {
  1004. valueLength = 0;
  1005. while (PeekChar () != -1) {
  1006. int ch = ReadChar ();
  1007. if (ch == ']' && PeekChar () == ']') {
  1008. ch = ReadChar (); // ']'
  1009. if (PeekChar () == '>') {
  1010. ReadChar (); // '>'
  1011. break;
  1012. } else {
  1013. AppendValueChar (']');
  1014. AppendValueChar (']');
  1015. ch = ReadChar ();
  1016. }
  1017. }
  1018. AppendValueChar ((char)ch);
  1019. }
  1020. ++depth;
  1021. SetProperties (
  1022. XmlNodeType.CDATA, // nodeType
  1023. String.Empty, // name
  1024. false, // isEmptyElement
  1025. CreateValueString (), // value
  1026. true // clearAttributes
  1027. );
  1028. }
  1029. // The reader is positioned on the first character
  1030. // of the name.
  1031. private string ReadName ()
  1032. {
  1033. if (!XmlChar.IsFirstNameChar (PeekChar ()))
  1034. throw new XmlException ("a name did not start with a legal character");
  1035. nameLength = 0;
  1036. AppendNameChar (ReadChar ());
  1037. while (XmlChar.IsNameChar (PeekChar ())) {
  1038. AppendNameChar (ReadChar ());
  1039. }
  1040. return CreateNameString ();
  1041. }
  1042. // Read the next character and compare it against the
  1043. // specified character.
  1044. private void Expect (int expected)
  1045. {
  1046. int ch = ReadChar ();
  1047. if (ch != expected) {
  1048. throw new XmlException (
  1049. String.Format (
  1050. "expected '{0}' ({1:X}) but found '{2}' ({3:X})",
  1051. (char)expected,
  1052. expected,
  1053. (char)ch,
  1054. ch));
  1055. }
  1056. }
  1057. // Does not consume the first non-whitespace character.
  1058. private void SkipWhitespace ()
  1059. {
  1060. while (XmlChar.IsWhitespace (PeekChar ()))
  1061. ReadChar ();
  1062. }
  1063. }
  1064. }