New test.
[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                 public override bool HasValue {
120                         get { return Current.HasValue; }
121                 }
122
123                 public override bool IsDefault {
124                         get { return Current.IsDefault; }
125                 }
126
127                 public override bool IsEmptyElement {
128                         get { return Current.IsEmptyElement; }
129                 }
130
131                 public override string LocalName {
132                         get { return Current.LocalName; }
133                 }
134
135                 public override string Name {
136                         get { return Current.Name; }
137                 }
138
139                 public override string NamespaceURI {
140                         get { return Current.NamespaceURI; }
141                 }
142
143                 public override XmlNameTable NameTable {
144                         get { return Current.NameTable; }
145                 }
146
147                 public override XmlNodeType NodeType {
148                         get {
149                                 if (entity != null) {
150                                         if (entity.ReadState == ReadState.Initial)
151                                                 return source.NodeType;
152                                         return entity.EOF ? XmlNodeType.EndEntity : entity.NodeType;
153                                 }
154                                 return source.NodeType;
155                         }
156                 }
157
158                 internal XmlParserContext ParserContext {
159                         get { return context; }
160                 }
161
162                 XmlParserContext IHasXmlParserContext.ParserContext {
163                         get { return context; }
164                 }
165
166                 public override string Prefix {
167                         get { return Current.Prefix; }
168                 }
169
170                 public override char QuoteChar {
171                         get { return Current.QuoteChar; }
172                 }
173
174                 public override ReadState ReadState {
175                         get { return entity != null ? ReadState.Interactive : source.ReadState; }
176                 }
177
178                 public override string Value {
179                         get { return Current.Value; }
180                 }
181
182                 public override string XmlLang {
183                         get { return Current.XmlLang; }
184                 }
185
186                 public override XmlSpace XmlSpace {
187                         get { return Current.XmlSpace; }
188                 }
189
190                 // non-overrides
191
192                 private void CopyProperties (EntityResolvingXmlReader other)
193                 {
194                         context = other.context;
195                         resolver = other.resolver;
196                         entity_handling = other.entity_handling;
197                 }
198
199                 // public members
200
201                 public EntityHandling EntityHandling {
202                         get { return entity_handling; }
203                         set {
204                                 if (entity != null)
205                                         entity.EntityHandling = value;
206                                 entity_handling = value;
207                         }
208                 }
209
210                 public int LineNumber {
211                         get {
212                                 IXmlLineInfo li = Current as IXmlLineInfo;
213                                 return li == null ? 0 : li.LineNumber;
214                         }
215                 }
216
217                 public int LinePosition {
218                         get {
219                                 IXmlLineInfo li = Current as IXmlLineInfo;
220                                 return li == null ? 0 : li.LinePosition;
221                         }
222                 }
223
224                 public XmlResolver XmlResolver {
225                         set {
226                                 if (entity != null)
227                                         entity.XmlResolver = value;
228                                 resolver = value;
229                         }
230                 }
231
232                 #endregion
233
234                 #region Methods
235
236                 // overrides
237
238                 public override void Close ()
239                 {
240                         if (entity != null)
241                                 entity.Close ();
242                         source.Close ();
243                 }
244
245                 public override string GetAttribute (int i)
246                 {
247                         return Current.GetAttribute (i);
248                 }
249
250                 // MS.NET 1.0 msdn says that this method returns String.Empty
251                 // for absent attribute, but in fact it returns null.
252                 // This description is corrected in MS.NET 1.1 msdn.
253                 public override string GetAttribute (string name)
254                 {
255                         return Current.GetAttribute (name);
256                 }
257
258                 public override string GetAttribute (string localName, string namespaceURI)
259                 {
260                         return Current.GetAttribute (localName, namespaceURI);
261                 }
262
263 #if NET_2_0
264                 public IDictionary<string, string> GetNamespacesInScope (XmlNamespaceScope scope)
265                 {
266                         return ((IXmlNamespaceResolver) Current).GetNamespacesInScope (scope);
267                 }
268
269                 IDictionary<string, string> IXmlNamespaceResolver.GetNamespacesInScope (XmlNamespaceScope scope)
270                 {
271                         return GetNamespacesInScope (scope);
272                 }
273
274                 string IXmlNamespaceResolver.LookupPrefix (string ns)
275                 {
276                         return ((IXmlNamespaceResolver) Current).LookupPrefix (ns);
277                 }
278 #endif
279
280                 public override string LookupNamespace (string prefix)
281                 {
282                         return Current.LookupNamespace (prefix);
283                 }
284
285                 public override void MoveToAttribute (int i)
286                 {
287                         if (entity != null && entity_inside_attr) {
288                                 entity.Close ();
289                                 entity = null;
290                         }
291                         Current.MoveToAttribute (i);
292                         inside_attr = true;
293                 }
294
295                 public override bool MoveToAttribute (string name)
296                 {
297                         if (entity != null && !entity_inside_attr)
298                                 return entity.MoveToAttribute (name);
299                         if (!source.MoveToAttribute (name))
300                                 return false;
301                         if (entity != null && entity_inside_attr) {
302                                 entity.Close ();
303                                 entity = null;
304                         }
305                         inside_attr = true;
306                         return true;
307                 }
308
309                 public override bool MoveToAttribute (string localName, string namespaceName)
310                 {
311                         if (entity != null && !entity_inside_attr)
312                                 return entity.MoveToAttribute (localName, namespaceName);
313                         if (!source.MoveToAttribute (localName, namespaceName))
314                                 return false;
315                         if (entity != null && entity_inside_attr) {
316                                 entity.Close ();
317                                 entity = null;
318                         }
319                         inside_attr = true;
320                         return true;
321                 }
322
323                 public override bool MoveToElement ()
324                 {
325                         if (entity != null && entity_inside_attr) {
326                                 entity.Close ();
327                                 entity = null;
328                         }
329                         if (!Current.MoveToElement ())
330                                 return false;
331                         inside_attr = false;
332                         return true;
333                 }
334
335                 public override bool MoveToFirstAttribute ()
336                 {
337                         if (entity != null && !entity_inside_attr)
338                                 return entity.MoveToFirstAttribute ();
339                         if (!source.MoveToFirstAttribute ())
340                                 return false;
341                         if (entity != null && entity_inside_attr) {
342                                 entity.Close ();
343                                 entity = null;
344                         }
345                         inside_attr = true;
346                         return true;
347                 }
348
349                 public override bool MoveToNextAttribute ()
350                 {
351                         if (entity != null && !entity_inside_attr)
352                                 return entity.MoveToNextAttribute ();
353                         if (!source.MoveToNextAttribute ())
354                                 return false;
355                         if (entity != null && entity_inside_attr) {
356                                 entity.Close ();
357                                 entity = null;
358                         }
359                         inside_attr = true;
360                         return true;
361                 }
362
363                 public override bool Read ()
364                 {
365                         if (do_resolve) {
366                                 DoResolveEntity ();
367                                 do_resolve = false;
368                         }
369
370                         inside_attr = false;
371
372                         if (entity != null && (entity_inside_attr || entity.EOF)) {
373                                 entity.Close ();
374                                 entity = null;
375                         }
376                         if (entity != null) {
377                                 if (entity.Read ())
378                                         return true;
379                                 if (EntityHandling == EntityHandling.ExpandEntities) {
380                                         // EndEntity must be skipped
381                                         entity.Close ();
382                                         entity = null;
383                                         return Read ();
384                                 }
385                                 else
386                                         return true; // either success or EndEntity
387                         }
388                         else {
389                                 if (!source.Read ())
390                                         return false;
391                                 if (EntityHandling == EntityHandling.ExpandEntities
392                                         && source.NodeType == XmlNodeType.EntityReference) {
393                                         ResolveEntity ();
394                                         return Read ();
395                                 }
396                                 return true;
397                         }
398                 }
399
400                 public override bool ReadAttributeValue ()
401                 {
402                         if (entity != null && entity_inside_attr) {
403                                 if (entity.EOF) {
404                                         entity.Close ();
405                                         entity = null;
406                                 }
407                                 else {
408                                         entity.Read ();
409                                         return true; // either success or EndEntity
410                                 }
411                         }
412                         return Current.ReadAttributeValue ();
413                 }
414
415                 public override string ReadString ()
416                 {
417                         return base.ReadString ();
418                 }
419
420                 public override void ResolveEntity ()
421                 {
422 #if NET_2_0
423                         DoResolveEntity ();
424 #else
425                         do_resolve = true;
426 #endif
427                 }
428
429                 void DoResolveEntity ()
430                 {
431                         if (entity != null)
432                                 entity.ResolveEntity ();
433                         else {
434                                 if (source.NodeType != XmlNodeType.EntityReference)
435                                         throw new InvalidOperationException ("The current node is not an Entity Reference");
436                                 if (ParserContext.Dtd == null)
437                                         throw new XmlException (this as IXmlLineInfo, this.BaseURI, String.Format ("Cannot resolve entity without DTD: '{0}'", source.Name));
438                                 XmlReader entReader = ParserContext.Dtd.GenerateEntityContentReader (
439                                         source.Name, ParserContext);
440                                 if (entReader == null)
441                                         throw new XmlException (this as IXmlLineInfo, this.BaseURI, String.Format ("Reference to undeclared entity '{0}'.", source.Name));
442
443                                 entity = new EntityResolvingXmlReader (
444                                         entReader, inside_attr);
445                                 entity.CopyProperties (this);
446                         }
447                 }
448
449                 public override void Skip ()
450                 {
451                         base.Skip ();
452                 }
453
454                 public bool HasLineInfo ()
455                 {
456                         IXmlLineInfo li = Current as IXmlLineInfo;
457                         return li == null ? false : li.HasLineInfo ();
458                 }
459
460                 #endregion
461         }
462 }