2 // EntityResolvingXmlReader.cs - XmlReader that handles entity resolution
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.
30 using System.Collections.Generic;
33 using System.Globalization;
35 using System.Security.Permissions;
37 using System.Xml.Schema;
42 [PermissionSet (SecurityAction.InheritanceDemand, Unrestricted = true)]
43 internal class EntityResolvingXmlReader : XmlReader,
45 IXmlNamespaceResolver,
47 IXmlLineInfo, IHasXmlParserContext
49 EntityResolvingXmlReader entity;
51 XmlParserContext context;
53 EntityHandling entity_handling;
54 bool entity_inside_attr;
58 public EntityResolvingXmlReader (XmlReader source, XmlParserContext context)
61 this.context = context;
64 EntityResolvingXmlReader (XmlReader entityContainer,
67 source = entityContainer;
68 this.entity_inside_attr = inside_attr;
73 private XmlReader Current {
74 get { return entity != null && entity.ReadState != ReadState.Initial ? (XmlReader) entity : source; }
79 public override string this [int i] {
80 get { return GetAttribute (i); }
83 public override string this [string name] {
84 get { return GetAttribute (name); }
87 public override string this [string localName, string namespaceName] {
88 get { return GetAttribute (localName, namespaceName); }
92 public override int AttributeCount {
93 get { return Current.AttributeCount; }
96 public override string BaseURI {
97 get { return Current.BaseURI; }
100 public override bool CanResolveEntity {
104 public override int Depth {
106 // On EndEntity, depth is the same as that
107 // of EntityReference.
108 if (entity != null && entity.ReadState == ReadState.Interactive)
109 return source.Depth + entity.Depth + 1;
115 public override bool EOF {
116 get { return source.EOF; }
119 public override bool HasValue {
120 get { return Current.HasValue; }
123 public override bool IsDefault {
124 get { return Current.IsDefault; }
127 public override bool IsEmptyElement {
128 get { return Current.IsEmptyElement; }
131 public override string LocalName {
132 get { return Current.LocalName; }
135 public override string Name {
136 get { return Current.Name; }
139 public override string NamespaceURI {
140 get { return Current.NamespaceURI; }
143 public override XmlNameTable NameTable {
144 get { return Current.NameTable; }
147 public override XmlNodeType NodeType {
149 if (entity != null) {
150 if (entity.ReadState == ReadState.Initial)
151 return source.NodeType;
152 return entity.EOF ? XmlNodeType.EndEntity : entity.NodeType;
154 return source.NodeType;
158 internal XmlParserContext ParserContext {
159 get { return context; }
162 XmlParserContext IHasXmlParserContext.ParserContext {
163 get { return context; }
166 public override string Prefix {
167 get { return Current.Prefix; }
170 public override char QuoteChar {
171 get { return Current.QuoteChar; }
174 public override ReadState ReadState {
175 get { return entity != null ? ReadState.Interactive : source.ReadState; }
178 public override string Value {
179 get { return Current.Value; }
182 public override string XmlLang {
183 get { return Current.XmlLang; }
186 public override XmlSpace XmlSpace {
187 get { return Current.XmlSpace; }
192 private void CopyProperties (EntityResolvingXmlReader other)
194 context = other.context;
195 resolver = other.resolver;
196 entity_handling = other.entity_handling;
201 public EntityHandling EntityHandling {
202 get { return entity_handling; }
205 entity.EntityHandling = value;
206 entity_handling = value;
210 public int LineNumber {
212 IXmlLineInfo li = Current as IXmlLineInfo;
213 return li == null ? 0 : li.LineNumber;
217 public int LinePosition {
219 IXmlLineInfo li = Current as IXmlLineInfo;
220 return li == null ? 0 : li.LinePosition;
224 public XmlResolver XmlResolver {
227 entity.XmlResolver = value;
238 public override void Close ()
245 public override string GetAttribute (int i)
247 return Current.GetAttribute (i);
250 // MS.NET 1.0 msdn says that this method returns String.Empty
251 // for absent attribute, but in fact it returns null.
252 // This description is corrected in MS.NET 1.1 msdn.
253 public override string GetAttribute (string name)
255 return Current.GetAttribute (name);
258 public override string GetAttribute (string localName, string namespaceURI)
260 return Current.GetAttribute (localName, namespaceURI);
264 public IDictionary<string, string> GetNamespacesInScope (XmlNamespaceScope scope)
266 return ((IXmlNamespaceResolver) Current).GetNamespacesInScope (scope);
269 IDictionary<string, string> IXmlNamespaceResolver.GetNamespacesInScope (XmlNamespaceScope scope)
271 return GetNamespacesInScope (scope);
274 string IXmlNamespaceResolver.LookupPrefix (string ns)
276 return ((IXmlNamespaceResolver) Current).LookupPrefix (ns);
280 public override string LookupNamespace (string prefix)
282 return Current.LookupNamespace (prefix);
285 public override void MoveToAttribute (int i)
287 if (entity != null && entity_inside_attr) {
291 Current.MoveToAttribute (i);
295 public override bool MoveToAttribute (string name)
297 if (entity != null && !entity_inside_attr)
298 return entity.MoveToAttribute (name);
299 if (!source.MoveToAttribute (name))
301 if (entity != null && entity_inside_attr) {
309 public override bool MoveToAttribute (string localName, string namespaceName)
311 if (entity != null && !entity_inside_attr)
312 return entity.MoveToAttribute (localName, namespaceName);
313 if (!source.MoveToAttribute (localName, namespaceName))
315 if (entity != null && entity_inside_attr) {
323 public override bool MoveToElement ()
325 if (entity != null && entity_inside_attr) {
329 if (!Current.MoveToElement ())
335 public override bool MoveToFirstAttribute ()
337 if (entity != null && !entity_inside_attr)
338 return entity.MoveToFirstAttribute ();
339 if (!source.MoveToFirstAttribute ())
341 if (entity != null && entity_inside_attr) {
349 public override bool MoveToNextAttribute ()
351 if (entity != null && !entity_inside_attr)
352 return entity.MoveToNextAttribute ();
353 if (!source.MoveToNextAttribute ())
355 if (entity != null && entity_inside_attr) {
363 public override bool Read ()
372 if (entity != null && (entity_inside_attr || entity.EOF)) {
376 if (entity != null) {
379 if (EntityHandling == EntityHandling.ExpandEntities) {
380 // EndEntity must be skipped
386 return true; // either success or EndEntity
391 if (EntityHandling == EntityHandling.ExpandEntities
392 && source.NodeType == XmlNodeType.EntityReference) {
400 public override bool ReadAttributeValue ()
402 if (entity != null && entity_inside_attr) {
409 return true; // either success or EndEntity
412 return Current.ReadAttributeValue ();
415 public override string ReadString ()
417 return base.ReadString ();
420 public override void ResolveEntity ()
429 void DoResolveEntity ()
432 entity.ResolveEntity ();
434 if (source.NodeType != XmlNodeType.EntityReference)
435 throw new InvalidOperationException ("The current node is not an Entity Reference");
436 if (ParserContext.Dtd == null)
437 throw new XmlException (this as IXmlLineInfo, this.BaseURI, String.Format ("Cannot resolve entity without DTD: '{0}'", source.Name));
438 XmlReader entReader = ParserContext.Dtd.GenerateEntityContentReader (
439 source.Name, ParserContext);
440 if (entReader == null)
441 throw new XmlException (this as IXmlLineInfo, this.BaseURI, String.Format ("Reference to undeclared entity '{0}'.", source.Name));
443 entity = new EntityResolvingXmlReader (
444 entReader, inside_attr);
445 entity.CopyProperties (this);
449 public override void Skip ()
454 public bool HasLineInfo ()
456 IXmlLineInfo li = Current as IXmlLineInfo;
457 return li == null ? false : li.HasLineInfo ();