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
)
61 IHasXmlParserContext container
= source
as IHasXmlParserContext
;
62 if (container
!= null)
63 this.context
= container
.ParserContext
;
65 this.context
= new XmlParserContext (source
.NameTable
, new XmlNamespaceManager (source
.NameTable
), null, XmlSpace
.None
);
68 EntityResolvingXmlReader (XmlReader entityContainer
,
71 source
= entityContainer
;
72 this.entity_inside_attr
= inside_attr
;
77 private XmlReader Current
{
78 get { return entity != null && entity.ReadState != ReadState.Initial ? (XmlReader) entity : source; }
83 public override string this [int i
] {
84 get { return GetAttribute (i); }
87 public override string this [string name
] {
88 get { return GetAttribute (name); }
91 public override string this [string localName
, string namespaceName
] {
92 get { return GetAttribute (localName, namespaceName); }
96 public override int AttributeCount
{
97 get { return Current.AttributeCount; }
100 public override string BaseURI
{
101 get { return Current.BaseURI; }
104 public override bool CanResolveEntity
{
108 public override int Depth
{
110 // On EndEntity, depth is the same as that
111 // of EntityReference.
112 if (entity
!= null && entity
.ReadState
== ReadState
.Interactive
)
113 return source
.Depth
+ entity
.Depth
+ 1;
119 public override bool EOF
{
120 get { return source.EOF; }
123 public override bool HasValue
{
124 get { return Current.HasValue; }
127 public override bool IsDefault
{
128 get { return Current.IsDefault; }
131 public override bool IsEmptyElement
{
132 get { return Current.IsEmptyElement; }
135 public override string LocalName
{
136 get { return Current.LocalName; }
139 public override string Name
{
140 get { return Current.Name; }
143 public override string NamespaceURI
{
144 get { return Current.NamespaceURI; }
147 public override XmlNameTable NameTable
{
148 get { return Current.NameTable; }
151 public override XmlNodeType NodeType
{
153 if (entity
!= null) {
154 if (entity
.ReadState
== ReadState
.Initial
)
155 return source
.NodeType
;
156 return entity
.EOF
? XmlNodeType
.EndEntity
: entity
.NodeType
;
158 return source
.NodeType
;
162 internal XmlParserContext ParserContext
{
163 get { return context; }
166 XmlParserContext IHasXmlParserContext
.ParserContext
{
167 get { return context; }
170 public override string Prefix
{
171 get { return Current.Prefix; }
174 public override char QuoteChar
{
175 get { return Current.QuoteChar; }
178 public override ReadState ReadState
{
179 get { return entity != null ? ReadState.Interactive : source.ReadState; }
182 public override string Value
{
183 get { return Current.Value; }
186 public override string XmlLang
{
187 get { return Current.XmlLang; }
190 public override XmlSpace XmlSpace
{
191 get { return Current.XmlSpace; }
196 private void CopyProperties (EntityResolvingXmlReader other
)
198 context
= other
.context
;
199 resolver
= other
.resolver
;
200 entity_handling
= other
.entity_handling
;
205 public EntityHandling EntityHandling
{
206 get { return entity_handling; }
209 entity
.EntityHandling
= value;
210 entity_handling
= value;
214 public int LineNumber
{
216 IXmlLineInfo li
= Current
as IXmlLineInfo
;
217 return li
== null ? 0 : li
.LineNumber
;
221 public int LinePosition
{
223 IXmlLineInfo li
= Current
as IXmlLineInfo
;
224 return li
== null ? 0 : li
.LinePosition
;
228 public XmlResolver XmlResolver
{
231 entity
.XmlResolver
= value;
242 public override void Close ()
249 public override string GetAttribute (int i
)
251 return Current
.GetAttribute (i
);
254 // MS.NET 1.0 msdn says that this method returns String.Empty
255 // for absent attribute, but in fact it returns null.
256 // This description is corrected in MS.NET 1.1 msdn.
257 public override string GetAttribute (string name
)
259 return Current
.GetAttribute (name
);
262 public override string GetAttribute (string localName
, string namespaceURI
)
264 return Current
.GetAttribute (localName
, namespaceURI
);
268 public IDictionary
<string, string> GetNamespacesInScope (XmlNamespaceScope scope
)
270 return ((IXmlNamespaceResolver
) Current
).GetNamespacesInScope (scope
);
273 IDictionary
<string, string> IXmlNamespaceResolver
.GetNamespacesInScope (XmlNamespaceScope scope
)
275 return GetNamespacesInScope (scope
);
278 string IXmlNamespaceResolver
.LookupPrefix (string ns
)
280 return ((IXmlNamespaceResolver
) Current
).LookupPrefix (ns
);
284 public override string LookupNamespace (string prefix
)
286 return Current
.LookupNamespace (prefix
);
289 public override void MoveToAttribute (int i
)
291 if (entity
!= null && entity_inside_attr
) {
295 Current
.MoveToAttribute (i
);
299 public override bool MoveToAttribute (string name
)
301 if (entity
!= null && !entity_inside_attr
)
302 return entity
.MoveToAttribute (name
);
303 if (!source
.MoveToAttribute (name
))
305 if (entity
!= null && entity_inside_attr
) {
313 public override bool MoveToAttribute (string localName
, string namespaceName
)
315 if (entity
!= null && !entity_inside_attr
)
316 return entity
.MoveToAttribute (localName
, namespaceName
);
317 if (!source
.MoveToAttribute (localName
, namespaceName
))
319 if (entity
!= null && entity_inside_attr
) {
327 public override bool MoveToElement ()
329 if (entity
!= null && entity_inside_attr
) {
333 if (!Current
.MoveToElement ())
339 public override bool MoveToFirstAttribute ()
341 if (entity
!= null && !entity_inside_attr
)
342 return entity
.MoveToFirstAttribute ();
343 if (!source
.MoveToFirstAttribute ())
345 if (entity
!= null && entity_inside_attr
) {
353 public override bool MoveToNextAttribute ()
355 if (entity
!= null && !entity_inside_attr
)
356 return entity
.MoveToNextAttribute ();
357 if (!source
.MoveToNextAttribute ())
359 if (entity
!= null && entity_inside_attr
) {
367 public override bool Read ()
376 if (entity
!= null && (entity_inside_attr
|| entity
.EOF
)) {
380 if (entity
!= null) {
383 if (EntityHandling
== EntityHandling
.ExpandEntities
) {
384 // EndEntity must be skipped
390 return true; // either success or EndEntity
395 if (EntityHandling
== EntityHandling
.ExpandEntities
396 && source
.NodeType
== XmlNodeType
.EntityReference
) {
404 public override bool ReadAttributeValue ()
406 if (entity
!= null && entity_inside_attr
) {
413 return true; // either success or EndEntity
416 return Current
.ReadAttributeValue ();
419 public override string ReadString ()
421 return base.ReadString ();
425 void ResolveEntity ()
434 void DoResolveEntity ()
437 entity
.ResolveEntity ();
439 if (source
.NodeType
!= XmlNodeType
.EntityReference
)
440 throw new InvalidOperationException ("The current node is not an Entity Reference");
441 if (ParserContext
.Dtd
== null)
442 throw new XmlException (this as IXmlLineInfo
, this.BaseURI
, String
.Format ("Cannot resolve entity without DTD: '{0}'", source
.Name
));
443 XmlReader entReader
= ParserContext
.Dtd
.GenerateEntityContentReader (
444 source
.Name
, ParserContext
);
445 if (entReader
== null)
446 throw new XmlException (this as IXmlLineInfo
, this.BaseURI
, String
.Format ("Reference to undeclared entity '{0}'.", source
.Name
));
448 entity
= new EntityResolvingXmlReader (
449 entReader
, inside_attr
);
450 entity
.CopyProperties (this);
454 public override void Skip ()
459 public bool HasLineInfo ()
461 IXmlLineInfo li
= Current
as IXmlLineInfo
;
462 return li
== null ? false : li
.HasLineInfo ();