XmlTextReader.cs 23 KB

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