2010-04-07 Jb Evain <jbevain@novell.com>
[mcs.git] / class / System.XML / System.Xml / EntityResolvingXmlReader.cs
blob2f7fb8c31d637a27097a2cfebca77245ea02da6e
1 //
2 // EntityResolvingXmlReader.cs - XmlReader that handles entity resolution
3 //
4 // Author:
5 // Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
6 //
7 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
8 //
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:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
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 #if NET_2_0
30 using System.Collections.Generic;
31 #endif
32 using System;
33 using System.Globalization;
34 using System.IO;
35 using System.Security.Permissions;
36 using System.Text;
37 using System.Xml.Schema;
38 using System.Xml;
40 namespace Mono.Xml
42 [PermissionSet (SecurityAction.InheritanceDemand, Unrestricted = true)]
43 internal class EntityResolvingXmlReader : XmlReader,
44 #if NET_2_0
45 IXmlNamespaceResolver,
46 #endif
47 IXmlLineInfo, IHasXmlParserContext
49 EntityResolvingXmlReader entity;
50 XmlReader source;
51 XmlParserContext context;
52 XmlResolver resolver;
53 EntityHandling entity_handling;
54 bool entity_inside_attr;
55 bool inside_attr;
56 bool do_resolve;
58 public EntityResolvingXmlReader (XmlReader source)
60 this.source = source;
61 IHasXmlParserContext container = source as IHasXmlParserContext;
62 if (container != null)
63 this.context = container.ParserContext;
64 else
65 this.context = new XmlParserContext (source.NameTable, new XmlNamespaceManager (source.NameTable), null, XmlSpace.None);
68 EntityResolvingXmlReader (XmlReader entityContainer,
69 bool inside_attr)
71 source = entityContainer;
72 this.entity_inside_attr = inside_attr;
75 #region Properties
77 private XmlReader Current {
78 get { return entity != null && entity.ReadState != ReadState.Initial ? (XmlReader) entity : source; }
81 #if NET_2_0
82 #else
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); }
94 #endif
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 {
105 get { return true; }
108 public override int Depth {
109 get {
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;
114 else
115 return source.Depth;
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 {
152 get {
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; }
194 // non-overrides
196 private void CopyProperties (EntityResolvingXmlReader other)
198 context = other.context;
199 resolver = other.resolver;
200 entity_handling = other.entity_handling;
203 // public members
205 public EntityHandling EntityHandling {
206 get { return entity_handling; }
207 set {
208 if (entity != null)
209 entity.EntityHandling = value;
210 entity_handling = value;
214 public int LineNumber {
215 get {
216 IXmlLineInfo li = Current as IXmlLineInfo;
217 return li == null ? 0 : li.LineNumber;
221 public int LinePosition {
222 get {
223 IXmlLineInfo li = Current as IXmlLineInfo;
224 return li == null ? 0 : li.LinePosition;
228 public XmlResolver XmlResolver {
229 set {
230 if (entity != null)
231 entity.XmlResolver = value;
232 resolver = value;
236 #endregion
238 #region Methods
240 // overrides
242 public override void Close ()
244 if (entity != null)
245 entity.Close ();
246 source.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);
267 #if NET_2_0
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);
282 #endif
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) {
292 entity.Close ();
293 entity = null;
295 Current.MoveToAttribute (i);
296 inside_attr = true;
299 public override bool MoveToAttribute (string name)
301 if (entity != null && !entity_inside_attr)
302 return entity.MoveToAttribute (name);
303 if (!source.MoveToAttribute (name))
304 return false;
305 if (entity != null && entity_inside_attr) {
306 entity.Close ();
307 entity = null;
309 inside_attr = true;
310 return true;
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))
318 return false;
319 if (entity != null && entity_inside_attr) {
320 entity.Close ();
321 entity = null;
323 inside_attr = true;
324 return true;
327 public override bool MoveToElement ()
329 if (entity != null && entity_inside_attr) {
330 entity.Close ();
331 entity = null;
333 if (!Current.MoveToElement ())
334 return false;
335 inside_attr = false;
336 return true;
339 public override bool MoveToFirstAttribute ()
341 if (entity != null && !entity_inside_attr)
342 return entity.MoveToFirstAttribute ();
343 if (!source.MoveToFirstAttribute ())
344 return false;
345 if (entity != null && entity_inside_attr) {
346 entity.Close ();
347 entity = null;
349 inside_attr = true;
350 return true;
353 public override bool MoveToNextAttribute ()
355 if (entity != null && !entity_inside_attr)
356 return entity.MoveToNextAttribute ();
357 if (!source.MoveToNextAttribute ())
358 return false;
359 if (entity != null && entity_inside_attr) {
360 entity.Close ();
361 entity = null;
363 inside_attr = true;
364 return true;
367 public override bool Read ()
369 if (do_resolve) {
370 DoResolveEntity ();
371 do_resolve = false;
374 inside_attr = false;
376 if (entity != null && (entity_inside_attr || entity.EOF)) {
377 entity.Close ();
378 entity = null;
380 if (entity != null) {
381 if (entity.Read ())
382 return true;
383 if (EntityHandling == EntityHandling.ExpandEntities) {
384 // EndEntity must be skipped
385 entity.Close ();
386 entity = null;
387 return Read ();
389 else
390 return true; // either success or EndEntity
392 else {
393 if (!source.Read ())
394 return false;
395 if (EntityHandling == EntityHandling.ExpandEntities
396 && source.NodeType == XmlNodeType.EntityReference) {
397 ResolveEntity ();
398 return Read ();
400 return true;
404 public override bool ReadAttributeValue ()
406 if (entity != null && entity_inside_attr) {
407 if (entity.EOF) {
408 entity.Close ();
409 entity = null;
411 else {
412 entity.Read ();
413 return true; // either success or EndEntity
416 return Current.ReadAttributeValue ();
419 public override string ReadString ()
421 return base.ReadString ();
424 public override
425 void ResolveEntity ()
427 #if NET_2_0
428 DoResolveEntity ();
429 #else
430 do_resolve = true;
431 #endif
434 void DoResolveEntity ()
436 if (entity != null)
437 entity.ResolveEntity ();
438 else {
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 ()
456 base.Skip ();
459 public bool HasLineInfo ()
461 IXmlLineInfo li = Current as IXmlLineInfo;
462 return li == null ? false : li.HasLineInfo ();
465 #endregion