Merge pull request #228 from QuickJack/3e163743eda89cc8c239779a75dd245be12aee3c
[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)
59                 {
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);
66                 }
67
68                 EntityResolvingXmlReader (XmlReader entityContainer,
69                         bool inside_attr)
70                 {
71                         source = entityContainer;
72                         this.entity_inside_attr = inside_attr;
73                 }
74
75                 #region Properties
76
77                 private XmlReader Current {
78                         get { return entity != null && entity.ReadState != ReadState.Initial ? (XmlReader) entity : source; }
79                 }
80
81 #if NET_2_0
82 #else
83                 public override string this [int i] {
84                         get { return GetAttribute (i); }
85                 }
86
87                 public override string this [string name] {
88                         get { return GetAttribute (name); }
89                 }
90
91                 public override string this [string localName, string namespaceName] {
92                         get { return GetAttribute (localName, namespaceName); }
93                 }
94 #endif
95
96                 public override int AttributeCount {
97                         get { return Current.AttributeCount; }
98                 }
99
100                 public override string BaseURI {
101                         get { return Current.BaseURI; }
102                 }
103
104                 public override bool CanResolveEntity {
105                         get { return true; }
106                 }
107
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;
116                         }
117                 }
118
119                 public override bool EOF {
120                         get { return source.EOF; }
121                 }
122
123                 public override bool HasValue {
124                         get { return Current.HasValue; }
125                 }
126
127                 public override bool IsDefault {
128                         get { return Current.IsDefault; }
129                 }
130
131                 public override bool IsEmptyElement {
132                         get { return Current.IsEmptyElement; }
133                 }
134
135                 public override string LocalName {
136                         get { return Current.LocalName; }
137                 }
138
139                 public override string Name {
140                         get { return Current.Name; }
141                 }
142
143                 public override string NamespaceURI {
144                         get { return Current.NamespaceURI; }
145                 }
146
147                 public override XmlNameTable NameTable {
148                         get { return Current.NameTable; }
149                 }
150
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;
157                                 }
158                                 return source.NodeType;
159                         }
160                 }
161
162                 internal XmlParserContext ParserContext {
163                         get { return context; }
164                 }
165
166                 XmlParserContext IHasXmlParserContext.ParserContext {
167                         get { return context; }
168                 }
169
170                 public override string Prefix {
171                         get { return Current.Prefix; }
172                 }
173
174                 public override char QuoteChar {
175                         get { return Current.QuoteChar; }
176                 }
177
178                 public override ReadState ReadState {
179                         get { return entity != null ? ReadState.Interactive : source.ReadState; }
180                 }
181
182                 public override string Value {
183                         get { return Current.Value; }
184                 }
185
186                 public override string XmlLang {
187                         get { return Current.XmlLang; }
188                 }
189
190                 public override XmlSpace XmlSpace {
191                         get { return Current.XmlSpace; }
192                 }
193
194                 // non-overrides
195
196                 private void CopyProperties (EntityResolvingXmlReader other)
197                 {
198                         context = other.context;
199                         resolver = other.resolver;
200                         entity_handling = other.entity_handling;
201                 }
202
203                 // public members
204
205                 public EntityHandling EntityHandling {
206                         get { return entity_handling; }
207                         set {
208                                 if (entity != null)
209                                         entity.EntityHandling = value;
210                                 entity_handling = value;
211                         }
212                 }
213
214                 public int LineNumber {
215                         get {
216                                 IXmlLineInfo li = Current as IXmlLineInfo;
217                                 return li == null ? 0 : li.LineNumber;
218                         }
219                 }
220
221                 public int LinePosition {
222                         get {
223                                 IXmlLineInfo li = Current as IXmlLineInfo;
224                                 return li == null ? 0 : li.LinePosition;
225                         }
226                 }
227
228                 public XmlResolver XmlResolver {
229                         set {
230                                 if (entity != null)
231                                         entity.XmlResolver = value;
232                                 resolver = value;
233                         }
234                 }
235
236                 #endregion
237
238                 #region Methods
239
240                 // overrides
241
242                 public override void Close ()
243                 {
244                         if (entity != null)
245                                 entity.Close ();
246                         source.Close ();
247                 }
248
249                 public override string GetAttribute (int i)
250                 {
251                         return Current.GetAttribute (i);
252                 }
253
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)
258                 {
259                         return Current.GetAttribute (name);
260                 }
261
262                 public override string GetAttribute (string localName, string namespaceURI)
263                 {
264                         return Current.GetAttribute (localName, namespaceURI);
265                 }
266
267 #if NET_2_0
268                 public IDictionary<string, string> GetNamespacesInScope (XmlNamespaceScope scope)
269                 {
270                         return ((IXmlNamespaceResolver) Current).GetNamespacesInScope (scope);
271                 }
272
273                 IDictionary<string, string> IXmlNamespaceResolver.GetNamespacesInScope (XmlNamespaceScope scope)
274                 {
275                         return GetNamespacesInScope (scope);
276                 }
277
278                 string IXmlNamespaceResolver.LookupPrefix (string ns)
279                 {
280                         return ((IXmlNamespaceResolver) Current).LookupPrefix (ns);
281                 }
282 #endif
283
284                 public override string LookupNamespace (string prefix)
285                 {
286                         return Current.LookupNamespace (prefix);
287                 }
288
289                 public override void MoveToAttribute (int i)
290                 {
291                         if (entity != null && entity_inside_attr) {
292                                 entity.Close ();
293                                 entity = null;
294                         }
295                         Current.MoveToAttribute (i);
296                         inside_attr = true;
297                 }
298
299                 public override bool MoveToAttribute (string name)
300                 {
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;
308                         }
309                         inside_attr = true;
310                         return true;
311                 }
312
313                 public override bool MoveToAttribute (string localName, string namespaceName)
314                 {
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;
322                         }
323                         inside_attr = true;
324                         return true;
325                 }
326
327                 public override bool MoveToElement ()
328                 {
329                         if (entity != null && entity_inside_attr) {
330                                 entity.Close ();
331                                 entity = null;
332                         }
333                         if (!Current.MoveToElement ())
334                                 return false;
335                         inside_attr = false;
336                         return true;
337                 }
338
339                 public override bool MoveToFirstAttribute ()
340                 {
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;
348                         }
349                         inside_attr = true;
350                         return true;
351                 }
352
353                 public override bool MoveToNextAttribute ()
354                 {
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;
362                         }
363                         inside_attr = true;
364                         return true;
365                 }
366
367                 public override bool Read ()
368                 {
369                         if (do_resolve) {
370                                 DoResolveEntity ();
371                                 do_resolve = false;
372                         }
373
374                         inside_attr = false;
375
376                         if (entity != null && (entity_inside_attr || entity.EOF)) {
377                                 entity.Close ();
378                                 entity = null;
379                         }
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 ();
388                                 }
389                                 else
390                                         return true; // either success or EndEntity
391                         }
392                         else {
393                                 if (!source.Read ())
394                                         return false;
395                                 if (EntityHandling == EntityHandling.ExpandEntities
396                                         && source.NodeType == XmlNodeType.EntityReference) {
397                                         ResolveEntity ();
398                                         return Read ();
399                                 }
400                                 return true;
401                         }
402                 }
403
404                 public override bool ReadAttributeValue ()
405                 {
406                         if (entity != null && entity_inside_attr) {
407                                 if (entity.EOF) {
408                                         entity.Close ();
409                                         entity = null;
410                                 }
411                                 else {
412                                         entity.Read ();
413                                         return true; // either success or EndEntity
414                                 }
415                         }
416                         return Current.ReadAttributeValue ();
417                 }
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 }