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.
29 using System.Collections.Generic;
31 using System.Globalization;
33 using System.Security.Permissions;
35 using System.Xml.Schema;
40 [PermissionSet (SecurityAction.InheritanceDemand, Unrestricted = true)]
41 internal class EntityResolvingXmlReader : XmlReader, IXmlNamespaceResolver,
42 IXmlLineInfo, IHasXmlParserContext
44 EntityResolvingXmlReader entity;
46 XmlParserContext context;
48 EntityHandling entity_handling;
49 bool entity_inside_attr;
53 public EntityResolvingXmlReader (XmlReader source)
56 IHasXmlParserContext container = source as IHasXmlParserContext;
57 if (container != null)
58 this.context = container.ParserContext;
60 this.context = new XmlParserContext (source.NameTable, new XmlNamespaceManager (source.NameTable), null, XmlSpace.None);
63 EntityResolvingXmlReader (XmlReader entityContainer,
66 source = entityContainer;
67 this.entity_inside_attr = inside_attr;
72 private XmlReader Current {
73 get { return entity != null && entity.ReadState != ReadState.Initial ? (XmlReader) entity : source; }
76 public override int AttributeCount {
77 get { return Current.AttributeCount; }
80 public override string BaseURI {
81 get { return Current.BaseURI; }
84 public override bool CanResolveEntity {
88 public override int Depth {
90 // On EndEntity, depth is the same as that
91 // of EntityReference.
92 if (entity != null && entity.ReadState == ReadState.Interactive)
93 return source.Depth + entity.Depth + 1;
99 public override bool EOF {
100 get { return source.EOF; }
103 public override bool HasValue {
104 get { return Current.HasValue; }
107 public override bool IsDefault {
108 get { return Current.IsDefault; }
111 public override bool IsEmptyElement {
112 get { return Current.IsEmptyElement; }
115 public override string LocalName {
116 get { return Current.LocalName; }
119 public override string Name {
120 get { return Current.Name; }
123 public override string NamespaceURI {
124 get { return Current.NamespaceURI; }
127 public override XmlNameTable NameTable {
128 get { return Current.NameTable; }
131 public override XmlNodeType NodeType {
133 if (entity != null) {
134 if (entity.ReadState == ReadState.Initial)
135 return source.NodeType;
136 return entity.EOF ? XmlNodeType.EndEntity : entity.NodeType;
138 return source.NodeType;
142 internal XmlParserContext ParserContext {
143 get { return context; }
146 XmlParserContext IHasXmlParserContext.ParserContext {
147 get { return context; }
150 public override string Prefix {
151 get { return Current.Prefix; }
154 public override char QuoteChar {
155 get { return Current.QuoteChar; }
158 public override ReadState ReadState {
159 get { return entity != null ? ReadState.Interactive : source.ReadState; }
162 public override string Value {
163 get { return Current.Value; }
166 public override string XmlLang {
167 get { return Current.XmlLang; }
170 public override XmlSpace XmlSpace {
171 get { return Current.XmlSpace; }
176 private void CopyProperties (EntityResolvingXmlReader other)
178 context = other.context;
179 resolver = other.resolver;
180 entity_handling = other.entity_handling;
185 public EntityHandling EntityHandling {
186 get { return entity_handling; }
189 entity.EntityHandling = value;
190 entity_handling = value;
194 public int LineNumber {
196 IXmlLineInfo li = Current as IXmlLineInfo;
197 return li == null ? 0 : li.LineNumber;
201 public int LinePosition {
203 IXmlLineInfo li = Current as IXmlLineInfo;
204 return li == null ? 0 : li.LinePosition;
208 public XmlResolver XmlResolver {
211 entity.XmlResolver = value;
222 public override void Close ()
229 public override string GetAttribute (int i)
231 return Current.GetAttribute (i);
234 // MS.NET 1.0 msdn says that this method returns String.Empty
235 // for absent attribute, but in fact it returns null.
236 // This description is corrected in MS.NET 1.1 msdn.
237 public override string GetAttribute (string name)
239 return Current.GetAttribute (name);
242 public override string GetAttribute (string localName, string namespaceURI)
244 return Current.GetAttribute (localName, namespaceURI);
247 public IDictionary<string, string> GetNamespacesInScope (XmlNamespaceScope scope)
249 return ((IXmlNamespaceResolver) Current).GetNamespacesInScope (scope);
252 IDictionary<string, string> IXmlNamespaceResolver.GetNamespacesInScope (XmlNamespaceScope scope)
254 return GetNamespacesInScope (scope);
257 string IXmlNamespaceResolver.LookupPrefix (string ns)
259 return ((IXmlNamespaceResolver) Current).LookupPrefix (ns);
262 public override string LookupNamespace (string prefix)
264 return Current.LookupNamespace (prefix);
267 public override void MoveToAttribute (int i)
269 if (entity != null && entity_inside_attr) {
273 Current.MoveToAttribute (i);
277 public override bool MoveToAttribute (string name)
279 if (entity != null && !entity_inside_attr)
280 return entity.MoveToAttribute (name);
281 if (!source.MoveToAttribute (name))
283 if (entity != null && entity_inside_attr) {
291 public override bool MoveToAttribute (string localName, string namespaceName)
293 if (entity != null && !entity_inside_attr)
294 return entity.MoveToAttribute (localName, namespaceName);
295 if (!source.MoveToAttribute (localName, namespaceName))
297 if (entity != null && entity_inside_attr) {
305 public override bool MoveToElement ()
307 if (entity != null && entity_inside_attr) {
311 if (!Current.MoveToElement ())
317 public override bool MoveToFirstAttribute ()
319 if (entity != null && !entity_inside_attr)
320 return entity.MoveToFirstAttribute ();
321 if (!source.MoveToFirstAttribute ())
323 if (entity != null && entity_inside_attr) {
331 public override bool MoveToNextAttribute ()
333 if (entity != null && !entity_inside_attr)
334 return entity.MoveToNextAttribute ();
335 if (!source.MoveToNextAttribute ())
337 if (entity != null && entity_inside_attr) {
345 public override bool Read ()
354 if (entity != null && (entity_inside_attr || entity.EOF)) {
358 if (entity != null) {
361 if (EntityHandling == EntityHandling.ExpandEntities) {
362 // EndEntity must be skipped
368 return true; // either success or EndEntity
373 if (EntityHandling == EntityHandling.ExpandEntities
374 && source.NodeType == XmlNodeType.EntityReference) {
382 public override bool ReadAttributeValue ()
384 if (entity != null && entity_inside_attr) {
391 return true; // either success or EndEntity
394 return Current.ReadAttributeValue ();
397 public override string ReadString ()
399 return base.ReadString ();
402 public override void ResolveEntity ()
407 void DoResolveEntity ()
410 entity.ResolveEntity ();
412 if (source.NodeType != XmlNodeType.EntityReference)
413 throw new InvalidOperationException ("The current node is not an Entity Reference");
414 if (ParserContext.Dtd == null)
415 throw new XmlException (this as IXmlLineInfo, this.BaseURI, String.Format ("Cannot resolve entity without DTD: '{0}'", source.Name));
416 XmlReader entReader = ParserContext.Dtd.GenerateEntityContentReader (
417 source.Name, ParserContext);
418 if (entReader == null)
419 throw new XmlException (this as IXmlLineInfo, this.BaseURI, String.Format ("Reference to undeclared entity '{0}'.", source.Name));
421 entity = new EntityResolvingXmlReader (
422 entReader, inside_attr);
423 entity.CopyProperties (this);
427 public override void Skip ()
432 public bool HasLineInfo ()
434 IXmlLineInfo li = Current as IXmlLineInfo;
435 return li == null ? false : li.HasLineInfo ();