2010-03-12 Jb Evain <jbevain@novell.com>
[mono.git] / mcs / class / System.XML / System.Xml / XmlNodeReader2.cs
1 //
2 // System.Xml.XmlNodeReader2.cs - splitted XmlNodeReader that manages entities.
3 //
4 // Author:
5 //      Duncan Mak  (duncan@ximian.com)
6 //      Atsushi Enomoto  (ginga@kit.hi-ho.ne.jp)
7 //
8 // (C) Ximian, Inc.
9 // (C) Atsushi Enomoto
10 //
11
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System;
34 #if NET_2_0
35 using System.Collections.Generic;
36 #endif
37 using System.Xml;
38 using System.Xml.Schema;
39 using System.Text;
40 using Mono.Xml;
41
42 namespace System.Xml
43 {
44 #if NET_2_0
45         public class XmlNodeReader : XmlReader, IHasXmlParserContext, IXmlNamespaceResolver
46 #else
47         public class XmlNodeReader : XmlReader, IHasXmlParserContext
48 #endif
49         {
50                 XmlReader entity;
51                 XmlNodeReaderImpl source;
52                 bool entityInsideAttribute;
53                 bool insideAttribute;
54
55                 #region Constructor
56
57                 public XmlNodeReader (XmlNode node)
58                 {
59                         source = new XmlNodeReaderImpl (node);
60                 }
61                 
62                 private XmlNodeReader (XmlNodeReaderImpl entityContainer, bool insideAttribute)
63                 {
64                         source = new XmlNodeReaderImpl (entityContainer);
65                         this.entityInsideAttribute = insideAttribute;
66                 }
67                 
68                 #endregion
69
70                 #region Properties
71
72                 private XmlReader Current {
73                         get { return entity != null && entity.ReadState != ReadState.Initial ? entity : source; }
74                 }
75
76                 public override int AttributeCount {
77                         get { return Current.AttributeCount; }
78                 }
79
80                 public override string BaseURI {
81                         get { return Current.BaseURI; }
82                 }
83
84 #if NET_2_0
85                 public override bool CanReadBinaryContent {
86                         get { return true; }
87                 }
88
89 /*
90                 public override bool CanReadValueChunk {
91                         get { return true; }
92                 }
93 */
94 #else
95                 internal override bool CanReadBinaryContent {
96                         get { return true; }
97                 }
98
99 /*
100                 internal override bool CanReadValueChunk {
101                         get { return true; }
102                 }
103 */
104 #endif
105
106                 public override bool CanResolveEntity {
107                         get { return true; }
108                 }
109
110                 public override int Depth {
111                         get {
112                                 // On EndEntity, depth is the same as that 
113                                 // of EntityReference.
114                                 if (entity != null && entity.ReadState == ReadState.Interactive)
115                                         return source.Depth + entity.Depth + 1;
116                                 else
117                                         return source.Depth;
118                         }
119                 }
120
121                 public override bool EOF {
122                         get { return source.EOF; }
123                 }
124
125                 public override bool HasAttributes {
126                         get { return Current.HasAttributes; }
127                 }
128
129 #if !NET_2_1 || MONOTOUCH
130                 public override bool HasValue {
131                         get { return Current.HasValue; }
132                 }
133 #endif
134
135                 public override bool IsDefault {
136                         get { return Current.IsDefault; }
137                 }
138
139                 public override bool IsEmptyElement {
140                         get { return Current.IsEmptyElement; }
141                 }
142
143 #if NET_2_0
144 #else
145                 public override string this [int i] {
146                         get { return GetAttribute (i); }
147                 }
148
149                 public override string this [string name] {
150                         get { return GetAttribute (name); }
151                 }
152
153                 public override string this [string name, string namespaceURI] {
154                         get { return GetAttribute (name, namespaceURI); }
155                 }
156 #endif
157
158                 public override string LocalName {
159                         get { return Current.LocalName; }
160                 }
161
162                 public override string Name {
163                         get { return Current.Name; }
164                 }
165
166                 public override string NamespaceURI {
167                         get { return Current.NamespaceURI; }
168                 }
169
170                 public override XmlNameTable NameTable {
171                         get { return Current.NameTable; }
172                 }
173
174                 public override XmlNodeType NodeType {
175                         get {
176                                 if (entity != null)
177                                         return entity.ReadState == ReadState.Initial ?
178                                                 source.NodeType :
179                                                 entity.EOF ? XmlNodeType.EndEntity :
180                                                 entity.NodeType;
181                                 else
182                                         return source.NodeType;
183                         }
184                 }
185
186                 XmlParserContext IHasXmlParserContext.ParserContext {
187                         get { return ((IHasXmlParserContext) Current).ParserContext; }
188                 }
189
190                 public override string Prefix {
191                         get { return Current.Prefix; }
192                 }
193
194 #if NET_2_0
195 #else
196                 public override char QuoteChar {
197                         get { return '"'; }
198                 }
199 #endif
200
201                 public override ReadState ReadState {
202                         get { return entity != null ? ReadState.Interactive : source.ReadState; }
203                 }
204
205 #if NET_2_0
206                 public override IXmlSchemaInfo SchemaInfo {
207                         get { return entity != null ? entity.SchemaInfo : source.SchemaInfo; }
208                 }
209 #endif
210
211                 public override string Value {
212                         get { return Current.Value; }
213                 }
214
215                 public override string XmlLang {
216                         get { return Current.XmlLang; }
217                 }
218
219                 public override XmlSpace XmlSpace {
220                         get { return Current.XmlSpace; }
221                 }
222                 #endregion
223
224                 #region Methods
225
226                 // If current entityReference is a child of an attribute,
227                 // then MoveToAttribute simply means that we no more need this entity Current.
228                 // Otherwise, this invokation means that
229                 // it is expected to move to resolved (maybe) element's attribute.
230                 //
231                 // This rule applies to many methods like MoveTo*Attribute().
232
233                 public override void Close ()
234                 {
235                         if (entity != null)
236                                 entity.Close ();
237                         source.Close ();
238                 }
239
240                 public override string GetAttribute (int attributeIndex)
241                 {
242                         return Current.GetAttribute (attributeIndex);
243                 }
244
245                 public override string GetAttribute (string name)
246                 {
247                         return Current.GetAttribute (name);
248                 }
249
250                 public override string GetAttribute (string name, string namespaceURI)
251                 {
252                         return Current.GetAttribute (name, namespaceURI);
253                 }
254
255 #if NET_2_0
256                 IDictionary<string, string> IXmlNamespaceResolver.GetNamespacesInScope (XmlNamespaceScope scope)
257                 {
258                         return ((IXmlNamespaceResolver) Current).GetNamespacesInScope (scope);
259                 }
260 #endif
261
262                 public override string LookupNamespace (string prefix)
263                 {
264                         return Current.LookupNamespace (prefix);
265                 }
266
267 #if NET_2_0
268                 string IXmlNamespaceResolver.LookupPrefix (string ns)
269                 {
270                         return ((IXmlNamespaceResolver) Current).LookupPrefix (ns);
271                 }
272 #endif
273
274                 public override void MoveToAttribute (int i)
275                 {
276                         if (entity != null && entityInsideAttribute) {
277                                 entity.Close ();
278                                 entity = null;
279                         }
280                         Current.MoveToAttribute (i);
281                         insideAttribute = true;
282                 }
283
284                 public override bool MoveToAttribute (string name)
285                 {
286                         if (entity != null && !entityInsideAttribute)
287                                 return entity.MoveToAttribute (name);
288                         if (!source.MoveToAttribute (name))
289                                 return false;
290                         if (entity != null && entityInsideAttribute) {
291                                 entity.Close ();
292                                 entity = null;
293                         }
294                         insideAttribute = true;
295                         return true;
296                 }
297
298                 public override bool MoveToAttribute (string localName, string namespaceURI)
299                 {
300                         if (entity != null && !entityInsideAttribute)
301                                 return entity.MoveToAttribute (localName, namespaceURI);
302                         if (!source.MoveToAttribute (localName, namespaceURI))
303                                 return false;
304                         if (entity != null && entityInsideAttribute) {
305                                 entity.Close ();
306                                 entity = null;
307                         }
308                         insideAttribute = true;
309                         return true;
310                 }
311
312                 public override bool MoveToElement ()
313                 {
314                         if (entity != null && entityInsideAttribute)
315                                 entity = null;
316                         if (!Current.MoveToElement ())
317                                 return false;
318                         insideAttribute = false;
319                         return true;
320                 }
321
322                 public override bool MoveToFirstAttribute ()
323                 {
324                         if (entity != null && !entityInsideAttribute)
325                                 return entity.MoveToFirstAttribute ();
326                         if (!source.MoveToFirstAttribute ())
327                                 return false;
328                         if (entity != null && entityInsideAttribute) {
329                                 entity.Close ();
330                                 entity = null;
331                         }
332                         insideAttribute = true;
333                         return true;
334                 }
335
336                 public override bool MoveToNextAttribute ()
337                 {
338                         if (entity != null && !entityInsideAttribute)
339                                 return entity.MoveToNextAttribute ();
340                         if (!source.MoveToNextAttribute ())
341                                 return false;
342                         if (entity != null && entityInsideAttribute) {
343                                 entity.Close ();
344                                 entity = null;
345                         }
346                         insideAttribute = true;
347                         return true;
348                 }
349
350                 public override bool Read ()
351                 {
352                         insideAttribute = false;
353                         if (entity != null && (entityInsideAttribute || entity.EOF))
354                                 entity = null;
355                         if (entity != null) {
356                                 entity.Read ();
357                                 return true; // either success or EndEntity
358                         }
359                         else
360                                 return source.Read ();
361                 }
362
363                 public override bool ReadAttributeValue ()
364                 {
365                         if (entity != null && entityInsideAttribute) {
366                                 if (entity.EOF)
367                                         entity = null;
368                                 else {
369                                         entity.Read ();
370                                         return true; // either success or EndEntity
371                                 }
372                         }
373                         return Current.ReadAttributeValue ();
374                 }
375
376 #if NET_2_0
377                 public override int ReadContentAsBase64 (
378                         byte [] buffer, int offset, int length)
379                 {
380 //                      return base.ReadContentAsBase64 (
381 //                              buffer, offset, length);
382                         // FIXME: This is problematic wrt end of entity.
383                         if (entity != null)
384                                 return entity.ReadContentAsBase64 (
385                                         buffer, offset, length);
386                         else
387                                 return source.ReadContentAsBase64 (
388                                         buffer, offset, length);
389                 }
390
391                 public override int ReadContentAsBinHex (
392                         byte [] buffer, int offset, int length)
393                 {
394 //                      return base.ReadContentAsBinHex (
395 //                              buffer, offset, length);
396                         // FIXME: This is problematic wrt end of entity.
397                         if (entity != null)
398                                 return entity.ReadContentAsBinHex (
399                                         buffer, offset, length);
400                         else
401                                 return source.ReadContentAsBinHex (
402                                         buffer, offset, length);
403                 }
404
405                 public override int ReadElementContentAsBase64 (
406                         byte [] buffer, int offset, int length)
407                 {
408 //                      return base.ReadElementContentAsBase64 (
409 //                              buffer, offset, length);
410                         // FIXME: This is problematic wrt end of entity.
411                         if (entity != null)
412                                 return entity.ReadElementContentAsBase64 (
413                                         buffer, offset, length);
414                         else
415                                 return source.ReadElementContentAsBase64 (
416                                         buffer, offset, length);
417                 }
418
419                 public override int ReadElementContentAsBinHex (
420                         byte [] buffer, int offset, int length)
421                 {
422 //                      return base.ReadElementContentAsBinHex (
423 //                              buffer, offset, length);
424                         // FIXME: This is problematic wrt end of entity.
425                         if (entity != null)
426                                 return entity.ReadElementContentAsBinHex (
427                                         buffer, offset, length);
428                         else
429                                 return source.ReadElementContentAsBinHex (
430                                         buffer, offset, length);
431                 }
432 #endif
433
434                 public override string ReadString ()
435                 {
436                         return base.ReadString ();
437                 }
438
439 #if !NET_2_1 || MONOTOUCH
440                 public override void ResolveEntity ()
441                 {
442                         if (entity != null)
443                                 entity.ResolveEntity ();
444                         else {
445                                 if (source.NodeType != XmlNodeType.EntityReference)
446                                         throw new InvalidOperationException ("The current node is not an Entity Reference");
447                                 entity = new XmlNodeReader (source, insideAttribute);
448                         }
449                 }
450 #endif
451
452                 public override void Skip ()
453                 {
454                         if (entity != null && entityInsideAttribute)
455                                 entity = null;
456                         Current.Skip ();
457                 }
458                 #endregion
459         }
460 }