re-enable ResolveEntity in XmlReader and derived classes
[mono.git] / mcs / class / System.XML / System.Xml / EntityResolvingXmlReader.cs
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.
27 //
28
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;
39
40 namespace Mono.Xml
41 {
42         [PermissionSet (SecurityAction.InheritanceDemand, Unrestricted = true)]
43         internal class EntityResolvingXmlReader : XmlReader,
44 #if NET_2_0
45                 IXmlNamespaceResolver,
46 #endif
47                 IXmlLineInfo, IHasXmlParserContext
48         {
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;
57
58                 public EntityResolvingXmlReader (XmlReader source, XmlParserContext context)
59                 {
60                         this.source = source;
61                         this.context = context;
62                 }
63
64                 EntityResolvingXmlReader (XmlReader entityContainer,
65                         bool inside_attr)
66                 {
67                         source = entityContainer;
68                         this.entity_inside_attr = inside_attr;
69                 }
70
71                 #region Properties
72
73                 private XmlReader Current {
74                         get { return entity != null && entity.ReadState != ReadState.Initial ? (XmlReader) entity : source; }
75                 }
76
77 #if NET_2_0
78 #else
79                 public override string this [int i] {
80                         get { return GetAttribute (i); }
81                 }
82
83                 public override string this [string name] {
84                         get { return GetAttribute (name); }
85                 }
86
87                 public override string this [string localName, string namespaceName] {
88                         get { return GetAttribute (localName, namespaceName); }
89                 }
90 #endif
91
92                 public override int AttributeCount {
93                         get { return Current.AttributeCount; }
94                 }
95
96                 public override string BaseURI {
97                         get { return Current.BaseURI; }
98                 }
99
100                 public override bool CanResolveEntity {
101                         get { return true; }
102                 }
103
104                 public override int Depth {
105                         get {
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;
110                                 else
111                                         return source.Depth;
112                         }
113                 }
114
115                 public override bool EOF {
116                         get { return source.EOF; }
117                 }
118
119 #if !NET_2_1
120                 public override bool HasValue {
121                         get { return Current.HasValue; }
122                 }
123 #endif
124
125                 public override bool IsDefault {
126                         get { return Current.IsDefault; }
127                 }
128
129                 public override bool IsEmptyElement {
130                         get { return Current.IsEmptyElement; }
131                 }
132
133                 public override string LocalName {
134                         get { return Current.LocalName; }
135                 }
136
137                 public override string Name {
138                         get { return Current.Name; }
139                 }
140
141                 public override string NamespaceURI {
142                         get { return Current.NamespaceURI; }
143                 }
144
145                 public override XmlNameTable NameTable {
146                         get { return Current.NameTable; }
147                 }
148
149                 public override XmlNodeType NodeType {
150                         get {
151                                 if (entity != null) {
152                                         if (entity.ReadState == ReadState.Initial)
153                                                 return source.NodeType;
154                                         return entity.EOF ? XmlNodeType.EndEntity : entity.NodeType;
155                                 }
156                                 return source.NodeType;
157                         }
158                 }
159
160                 internal XmlParserContext ParserContext {
161                         get { return context; }
162                 }
163
164                 XmlParserContext IHasXmlParserContext.ParserContext {
165                         get { return context; }
166                 }
167
168                 public override string Prefix {
169                         get { return Current.Prefix; }
170                 }
171
172                 public override char QuoteChar {
173                         get { return Current.QuoteChar; }
174                 }
175
176                 public override ReadState ReadState {
177                         get { return entity != null ? ReadState.Interactive : source.ReadState; }
178                 }
179
180                 public override string Value {
181                         get { return Current.Value; }
182                 }
183
184                 public override string XmlLang {
185                         get { return Current.XmlLang; }
186                 }
187
188                 public override XmlSpace XmlSpace {
189                         get { return Current.XmlSpace; }
190                 }
191
192                 // non-overrides
193
194                 private void CopyProperties (EntityResolvingXmlReader other)
195                 {
196                         context = other.context;
197                         resolver = other.resolver;
198                         entity_handling = other.entity_handling;
199                 }
200
201                 // public members
202
203                 public EntityHandling EntityHandling {
204                         get { return entity_handling; }
205                         set {
206                                 if (entity != null)
207                                         entity.EntityHandling = value;
208                                 entity_handling = value;
209                         }
210                 }
211
212                 public int LineNumber {
213                         get {
214                                 IXmlLineInfo li = Current as IXmlLineInfo;
215                                 return li == null ? 0 : li.LineNumber;
216                         }
217                 }
218
219                 public int LinePosition {
220                         get {
221                                 IXmlLineInfo li = Current as IXmlLineInfo;
222                                 return li == null ? 0 : li.LinePosition;
223                         }
224                 }
225
226                 public XmlResolver XmlResolver {
227                         set {
228                                 if (entity != null)
229                                         entity.XmlResolver = value;
230                                 resolver = value;
231                         }
232                 }
233
234                 #endregion
235
236                 #region Methods
237
238                 // overrides
239
240                 public override void Close ()
241                 {
242                         if (entity != null)
243                                 entity.Close ();
244                         source.Close ();
245                 }
246
247                 public override string GetAttribute (int i)
248                 {
249                         return Current.GetAttribute (i);
250                 }
251
252                 // MS.NET 1.0 msdn says that this method returns String.Empty
253                 // for absent attribute, but in fact it returns null.
254                 // This description is corrected in MS.NET 1.1 msdn.
255                 public override string GetAttribute (string name)
256                 {
257                         return Current.GetAttribute (name);
258                 }
259
260                 public override string GetAttribute (string localName, string namespaceURI)
261                 {
262                         return Current.GetAttribute (localName, namespaceURI);
263                 }
264
265 #if NET_2_0
266                 public IDictionary<string, string> GetNamespacesInScope (XmlNamespaceScope scope)
267                 {
268                         return ((IXmlNamespaceResolver) Current).GetNamespacesInScope (scope);
269                 }
270
271                 IDictionary<string, string> IXmlNamespaceResolver.GetNamespacesInScope (XmlNamespaceScope scope)
272                 {
273                         return GetNamespacesInScope (scope);
274                 }
275
276                 string IXmlNamespaceResolver.LookupPrefix (string ns)
277                 {
278                         return ((IXmlNamespaceResolver) Current).LookupPrefix (ns);
279                 }
280 #endif
281
282                 public override string LookupNamespace (string prefix)
283                 {
284                         return Current.LookupNamespace (prefix);
285                 }
286
287                 public override void MoveToAttribute (int i)
288                 {
289                         if (entity != null && entity_inside_attr) {
290                                 entity.Close ();
291                                 entity = null;
292                         }
293                         Current.MoveToAttribute (i);
294                         inside_attr = true;
295                 }
296
297                 public override bool MoveToAttribute (string name)
298                 {
299                         if (entity != null && !entity_inside_attr)
300                                 return entity.MoveToAttribute (name);
301                         if (!source.MoveToAttribute (name))
302                                 return false;
303                         if (entity != null && entity_inside_attr) {
304                                 entity.Close ();
305                                 entity = null;
306                         }
307                         inside_attr = true;
308                         return true;
309                 }
310
311                 public override bool MoveToAttribute (string localName, string namespaceName)
312                 {
313                         if (entity != null && !entity_inside_attr)
314                                 return entity.MoveToAttribute (localName, namespaceName);
315                         if (!source.MoveToAttribute (localName, namespaceName))
316                                 return false;
317                         if (entity != null && entity_inside_attr) {
318                                 entity.Close ();
319                                 entity = null;
320                         }
321                         inside_attr = true;
322                         return true;
323                 }
324
325                 public override bool MoveToElement ()
326                 {
327                         if (entity != null && entity_inside_attr) {
328                                 entity.Close ();
329                                 entity = null;
330                         }
331                         if (!Current.MoveToElement ())
332                                 return false;
333                         inside_attr = false;
334                         return true;
335                 }
336
337                 public override bool MoveToFirstAttribute ()
338                 {
339                         if (entity != null && !entity_inside_attr)
340                                 return entity.MoveToFirstAttribute ();
341                         if (!source.MoveToFirstAttribute ())
342                                 return false;
343                         if (entity != null && entity_inside_attr) {
344                                 entity.Close ();
345                                 entity = null;
346                         }
347                         inside_attr = true;
348                         return true;
349                 }
350
351                 public override bool MoveToNextAttribute ()
352                 {
353                         if (entity != null && !entity_inside_attr)
354                                 return entity.MoveToNextAttribute ();
355                         if (!source.MoveToNextAttribute ())
356                                 return false;
357                         if (entity != null && entity_inside_attr) {
358                                 entity.Close ();
359                                 entity = null;
360                         }
361                         inside_attr = true;
362                         return true;
363                 }
364
365                 public override bool Read ()
366                 {
367                         if (do_resolve) {
368                                 DoResolveEntity ();
369                                 do_resolve = false;
370                         }
371
372                         inside_attr = false;
373
374                         if (entity != null && (entity_inside_attr || entity.EOF)) {
375                                 entity.Close ();
376                                 entity = null;
377                         }
378                         if (entity != null) {
379                                 if (entity.Read ())
380                                         return true;
381                                 if (EntityHandling == EntityHandling.ExpandEntities) {
382                                         // EndEntity must be skipped
383                                         entity.Close ();
384                                         entity = null;
385                                         return Read ();
386                                 }
387                                 else
388                                         return true; // either success or EndEntity
389                         }
390                         else {
391                                 if (!source.Read ())
392                                         return false;
393                                 if (EntityHandling == EntityHandling.ExpandEntities
394                                         && source.NodeType == XmlNodeType.EntityReference) {
395                                         ResolveEntity ();
396                                         return Read ();
397                                 }
398                                 return true;
399                         }
400                 }
401
402 #if !NET_2_1
403                 public override bool ReadAttributeValue ()
404                 {
405                         if (entity != null && entity_inside_attr) {
406                                 if (entity.EOF) {
407                                         entity.Close ();
408                                         entity = null;
409                                 }
410                                 else {
411                                         entity.Read ();
412                                         return true; // either success or EndEntity
413                                 }
414                         }
415                         return Current.ReadAttributeValue ();
416                 }
417 #endif
418
419                 public override string ReadString ()
420                 {
421                         return base.ReadString ();
422                 }
423
424                 public override
425                 void ResolveEntity ()
426                 {
427 #if NET_2_0
428                         DoResolveEntity ();
429 #else
430                         do_resolve = true;
431 #endif
432                 }
433
434                 void DoResolveEntity ()
435                 {
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));
447
448                                 entity = new EntityResolvingXmlReader (
449                                         entReader, inside_attr);
450                                 entity.CopyProperties (this);
451                         }
452                 }
453
454                 public override void Skip ()
455                 {
456                         base.Skip ();
457                 }
458
459                 public bool HasLineInfo ()
460                 {
461                         IXmlLineInfo li = Current as IXmlLineInfo;
462                         return li == null ? false : li.HasLineInfo ();
463                 }
464
465                 #endregion
466         }
467 }