2 // System.Xml.XmlTextReader2.cs - XmlTextReader for .NET 2.0
5 // Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
7 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using XmlTextReaderImpl = Mono.Xml2.XmlTextReader;
33 using System.Collections.Generic;
34 using System.Globalization;
36 using System.Security.Permissions;
38 using System.Xml.Schema;
43 [PermissionSet (SecurityAction.InheritanceDemand, Unrestricted = true)]
44 public class XmlTextReader : XmlReader,
45 IXmlLineInfo, IXmlNamespaceResolver, IHasXmlParserContext
48 XmlTextReaderImpl source; // dtd2xsd expects this field's existence.
49 bool entityInsideAttribute;
51 Stack<string> entityNameStack;
53 protected XmlTextReader ()
57 public XmlTextReader (Stream input)
58 : this (new XmlStreamReader (input))
62 public XmlTextReader (string url)
63 : this(url, new NameTable ())
67 public XmlTextReader (TextReader input)
68 : this (input, new NameTable ())
72 protected XmlTextReader (XmlNameTable nt)
73 : this (String.Empty, XmlNodeType.Element, null)
77 public XmlTextReader (Stream input, XmlNameTable nt)
78 : this(new XmlStreamReader (input), nt)
82 public XmlTextReader (string url, Stream input)
83 : this (url, new XmlStreamReader (input))
87 public XmlTextReader (string url, TextReader input)
88 : this (url, input, new NameTable ())
92 public XmlTextReader (string url, XmlNameTable nt)
94 source = new XmlTextReaderImpl (url, nt);
97 public XmlTextReader (TextReader input, XmlNameTable nt)
98 : this (String.Empty, input, nt)
102 public XmlTextReader (Stream xmlFragment, XmlNodeType fragType, XmlParserContext context)
104 source = new XmlTextReaderImpl (xmlFragment, fragType, context);
107 public XmlTextReader (string url, Stream input, XmlNameTable nt)
108 : this (url, new XmlStreamReader (input), nt)
112 public XmlTextReader (string url, TextReader input, XmlNameTable nt)
114 source = new XmlTextReaderImpl (url, input, nt);
117 public XmlTextReader (string xmlFragment, XmlNodeType fragType, XmlParserContext context)
119 source = new XmlTextReaderImpl (xmlFragment, fragType, context);
122 internal XmlTextReader (string baseURI, TextReader xmlFragment, XmlNodeType fragType)
124 source = new XmlTextReaderImpl (baseURI, xmlFragment, fragType);
127 internal XmlTextReader (string baseURI, TextReader xmlFragment, XmlNodeType fragType, XmlParserContext context)
129 source = new XmlTextReaderImpl (baseURI, xmlFragment, fragType, context);
132 internal XmlTextReader (bool dummy, string url, XmlNodeType fragType, XmlParserContext context)
134 source = new XmlTextReaderImpl (dummy, url, fragType, context);
137 private XmlTextReader (XmlTextReaderImpl entityContainer, bool insideAttribute)
139 source = entityContainer;
140 this.entityInsideAttribute = insideAttribute;
145 private XmlReader Current {
146 get { return entity != null && entity.ReadState != ReadState.Initial ? (XmlReader) entity : source; }
149 public override int AttributeCount {
150 get { return Current.AttributeCount; }
153 public override string BaseURI {
154 get { return Current.BaseURI; }
157 public override bool CanReadBinaryContent {
161 public override bool CanReadValueChunk {
165 public override bool CanResolveEntity {
169 public override int Depth {
171 // On EndEntity, depth is the same as that
172 // of EntityReference.
173 if (entity != null && entity.ReadState == ReadState.Interactive)
174 return source.Depth + entity.Depth + 1;
180 public override bool EOF {
181 get { return source.EOF; }
184 public override bool HasValue {
185 get { return Current.HasValue; }
188 public override bool IsDefault {
189 get { return Current.IsDefault; }
192 public override bool IsEmptyElement {
193 get { return Current.IsEmptyElement; }
196 public override string LocalName {
197 get { return Current.LocalName; }
200 public override string Name {
201 get { return Current.Name; }
204 public override string NamespaceURI {
205 get { return Current.NamespaceURI; }
208 public override XmlNameTable NameTable {
209 get { return Current.NameTable; }
212 public override XmlNodeType NodeType {
215 return entity.ReadState == ReadState.Initial ?
217 entity.EOF ? XmlNodeType.EndEntity :
220 return source.NodeType;
224 internal XmlParserContext ParserContext {
225 get { return ((IHasXmlParserContext) Current).ParserContext; }
228 XmlParserContext IHasXmlParserContext.ParserContext {
229 get { return this.ParserContext; }
232 public override string Prefix {
233 get { return Current.Prefix; }
236 public override char QuoteChar {
237 get { return Current.QuoteChar; }
240 public override ReadState ReadState {
241 get { return entity != null ? ReadState.Interactive : source.ReadState; }
244 public override XmlReaderSettings Settings {
245 get { return base.Settings; }
248 public override string Value {
249 get { return Current.Value; }
252 public override string XmlLang {
253 get { return Current.XmlLang; }
256 public override XmlSpace XmlSpace {
257 get { return Current.XmlSpace; }
262 internal bool CharacterChecking {
265 return entity.CharacterChecking;
267 return source.CharacterChecking;
271 entity.CharacterChecking = value;
272 source.CharacterChecking = value;
276 internal bool CloseInput {
279 return entity.CloseInput;
281 return source.CloseInput;
285 entity.CloseInput = value;
286 source.CloseInput = value;
290 internal ConformanceLevel Conformance {
291 get { return source.Conformance; }
294 entity.Conformance = value;
295 source.Conformance = value;
299 internal XmlResolver Resolver {
300 get { return source.Resolver; }
303 private void CopyProperties (XmlTextReader other)
305 CharacterChecking = other.CharacterChecking;
306 CloseInput = other.CloseInput;
307 if (other.Settings != null)
308 Conformance = other.Settings.ConformanceLevel;
309 XmlResolver = other.Resolver;
314 public Encoding Encoding {
317 return entity.Encoding;
319 return source.Encoding;
323 public EntityHandling EntityHandling {
324 get { return source.EntityHandling; }
327 entity.EntityHandling = value;
328 source.EntityHandling = value;
332 public int LineNumber {
335 return entity.LineNumber;
337 return source.LineNumber;
341 public int LinePosition {
344 return entity.LinePosition;
346 return source.LinePosition;
350 public bool Namespaces {
351 get { return source.Namespaces; }
354 entity.Namespaces = value;
355 source.Namespaces = value;
359 public bool Normalization {
360 get { return source.Normalization; }
363 entity.Normalization = value;
364 source.Normalization = value;
368 public bool ProhibitDtd {
369 get { return source.ProhibitDtd; }
372 entity.ProhibitDtd = value;
373 source.ProhibitDtd = value;
377 public WhitespaceHandling WhitespaceHandling {
378 get { return source.WhitespaceHandling; }
381 entity.WhitespaceHandling = value;
382 source.WhitespaceHandling = value;
386 public XmlResolver XmlResolver {
389 entity.XmlResolver = value;
390 source.XmlResolver = value;
398 internal void AdjustLineInfoOffset (int lineNumberOffset, int linePositionOffset)
401 entity.AdjustLineInfoOffset (lineNumberOffset, linePositionOffset);
402 source.AdjustLineInfoOffset (lineNumberOffset, linePositionOffset);
405 internal void SetNameTable (XmlNameTable nameTable)
408 entity.SetNameTable (nameTable);
409 source.SetNameTable (nameTable);
412 internal void SkipTextDeclaration ()
415 entity.SkipTextDeclaration ();
417 source.SkipTextDeclaration ();
422 public override void Close ()
429 public override string GetAttribute (int i)
431 return Current.GetAttribute (i);
434 // MS.NET 1.0 msdn says that this method returns String.Empty
435 // for absent attribute, but in fact it returns null.
436 // This description is corrected in MS.NET 1.1 msdn.
437 public override string GetAttribute (string name)
439 return Current.GetAttribute (name);
442 public override string GetAttribute (string localName, string namespaceURI)
444 return Current.GetAttribute (localName, namespaceURI);
447 public IDictionary<string, string> GetNamespacesInScope (XmlNamespaceScope scope)
449 return ((IXmlNamespaceResolver) Current).GetNamespacesInScope (scope);
452 IDictionary<string, string> IXmlNamespaceResolver.GetNamespacesInScope (XmlNamespaceScope scope)
454 return GetNamespacesInScope (scope);
457 public override string LookupNamespace (string prefix)
459 return Current.LookupNamespace (prefix);
462 string IXmlNamespaceResolver.LookupPrefix (string ns)
464 return ((IXmlNamespaceResolver) Current).LookupPrefix (ns);
467 public override void MoveToAttribute (int i)
469 if (entity != null && entityInsideAttribute)
471 Current.MoveToAttribute (i);
472 insideAttribute = true;
475 public override bool MoveToAttribute (string name)
477 if (entity != null && !entityInsideAttribute)
478 return entity.MoveToAttribute (name);
479 if (!source.MoveToAttribute (name))
481 if (entity != null && entityInsideAttribute)
483 insideAttribute = true;
487 public override bool MoveToAttribute (string localName, string namespaceName)
489 if (entity != null && !entityInsideAttribute)
490 return entity.MoveToAttribute (localName, namespaceName);
491 if (!source.MoveToAttribute (localName, namespaceName))
493 if (entity != null && entityInsideAttribute)
495 insideAttribute = true;
499 public override bool MoveToElement ()
501 if (entity != null && entityInsideAttribute)
503 if (!Current.MoveToElement ())
505 insideAttribute = false;
509 public override bool MoveToFirstAttribute ()
511 if (entity != null && !entityInsideAttribute)
512 return entity.MoveToFirstAttribute ();
513 if (!source.MoveToFirstAttribute ())
515 if (entity != null && entityInsideAttribute)
517 insideAttribute = true;
521 public override bool MoveToNextAttribute ()
523 if (entity != null && !entityInsideAttribute)
524 return entity.MoveToNextAttribute ();
525 if (!source.MoveToNextAttribute ())
527 if (entity != null && entityInsideAttribute)
529 insideAttribute = true;
533 public override bool Read ()
535 insideAttribute = false;
537 if (entity != null && (entityInsideAttribute || entity.EOF))
539 if (entity != null) {
542 if (EntityHandling == EntityHandling.ExpandEntities) {
543 // EndEntity must be skipped
548 return true; // either success or EndEntity
553 if (EntityHandling == EntityHandling.ExpandEntities
554 && source.NodeType == XmlNodeType.EntityReference) {
562 public override bool ReadAttributeValue ()
564 if (entity != null && entityInsideAttribute) {
569 return true; // either success or EndEntity
572 return Current.ReadAttributeValue ();
575 public override string ReadString ()
577 return base.ReadString ();
580 public void ResetState ()
583 entity.ResetState ();
584 source.ResetState ();
587 public override void ResolveEntity ()
590 entity.ResolveEntity ();
592 if (source.NodeType != XmlNodeType.EntityReference)
593 throw new InvalidOperationException ("The current node is not an Entity Reference");
594 XmlTextReaderImpl entReader =
595 ParserContext.Dtd.GenerateEntityContentReader (source.Name, ParserContext);
596 if (entReader == null)
597 throw new XmlException (this as IXmlLineInfo, this.BaseURI, String.Format ("Reference to undeclared entity '{0}'.", source.Name));
598 if (entityNameStack == null)
599 entityNameStack = new Stack<string> ();
600 else if (entityNameStack.Contains (Name))
601 throw new XmlException (String.Format ("General entity '{0}' has an invalid recursive reference to itself.", Name));
602 entityNameStack.Push (Name);
603 entity = new XmlTextReader (
604 entReader, insideAttribute);
605 entity.entityNameStack = entityNameStack;
606 entity.CopyProperties (this);
614 entityNameStack.Pop ();
617 public override void Skip ()
622 [MonoTODO ("Check how expanded entity is handled here.")]
623 public TextReader GetRemainder ()
625 if (entity != null) {
628 entityNameStack.Pop ();
630 return source.GetRemainder ();
633 public bool HasLineInfo ()
638 [MonoTODO ("Check how expanded entity is handled here.")]
639 public int ReadBase64 (byte [] buffer, int offset, int length)
642 return entity.ReadBase64 (buffer, offset, length);
644 return source.ReadBase64 (buffer, offset, length);
647 [MonoTODO ("Check how expanded entity is handled here.")]
648 public int ReadBinHex (byte [] buffer, int offset, int length)
651 return entity.ReadBinHex (buffer, offset, length);
653 return source.ReadBinHex (buffer, offset, length);
656 [MonoTODO ("Check how expanded entity is handled here.")]
657 public int ReadChars (char [] buffer, int offset, int length)
660 return entity.ReadChars (buffer, offset, length);
662 return source.ReadChars (buffer, offset, length);
666 [MonoTODO ("Check how expanded entity is handled here.")]
667 public override int ReadContentAsBase64 (byte [] buffer, int offset, int length)
670 return entity.ReadContentAsBase64 (buffer, offset, length);
672 return source.ReadContentAsBase64 (buffer, offset, length);
675 [MonoTODO ("Check how expanded entity is handled here.")]
676 public override int ReadContentAsBinHex (byte [] buffer, int offset, int length)
679 return entity.ReadContentAsBinHex (buffer, offset, length);
681 return source.ReadContentAsBinHex (buffer, offset, length);
684 [MonoTODO ("Check how expanded entity is handled here.")]
685 public override int ReadElementContentAsBase64 (byte [] buffer, int offset, int length)
688 return entity.ReadElementContentAsBase64 (buffer, offset, length);
690 return source.ReadElementContentAsBase64 (buffer, offset, length);
693 [MonoTODO ("Check how expanded entity is handled here.")]
694 public override int ReadElementContentAsBinHex (byte [] buffer, int offset, int length)
697 return entity.ReadElementContentAsBinHex (buffer, offset, length);
699 return source.ReadElementContentAsBinHex (buffer, offset, length);