2005-12-05 Lluis Sanchez Gual <lluis@novell.com>
[mono.git] / mcs / class / System.XML / System.Xml / XmlTextReader2.cs
1 //
2 // System.Xml.XmlTextReader2.cs - XmlTextReader for .NET 2.0
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
31 using XmlTextReaderImpl = Mono.Xml2.XmlTextReader;
32
33 using System.Collections.Generic;
34 using System.Globalization;
35 using System.IO;
36 using System.Security.Permissions;
37 using System.Text;
38 using System.Xml.Schema;
39 using Mono.Xml;
40
41 namespace System.Xml
42 {
43         [PermissionSet (SecurityAction.InheritanceDemand, Unrestricted = true)]
44         public class XmlTextReader : XmlReader,
45                 IXmlLineInfo, IXmlNamespaceResolver, IHasXmlParserContext
46         {
47                 XmlTextReader entity;
48                 XmlTextReaderImpl source;
49                 bool entityInsideAttribute;
50                 bool insideAttribute;
51                 string cachedAttributeValue;
52                 bool attributeValueConsumed;
53
54                 protected XmlTextReader ()
55                 {
56                 }
57
58                 public XmlTextReader (Stream input)
59                         : this (new XmlStreamReader (input))
60                 {
61                 }
62
63                 public XmlTextReader (string url)
64                         : this(url, new NameTable ())
65                 {
66                 }
67
68                 public XmlTextReader (TextReader input)
69                         : this (input, new NameTable ())
70                 {
71                 }
72
73                 protected XmlTextReader (XmlNameTable nt)
74                         : this (String.Empty, XmlNodeType.Element, null)
75                 {
76                 }
77
78                 public XmlTextReader (Stream input, XmlNameTable nt)
79                         : this(new XmlStreamReader (input), nt)
80                 {
81                 }
82
83                 public XmlTextReader (string url, Stream input)
84                         : this (url, new XmlStreamReader (input))
85                 {
86                 }
87
88                 public XmlTextReader (string url, TextReader input)
89                         : this (url, input, new NameTable ())
90                 {
91                 }
92
93                 public XmlTextReader (string url, XmlNameTable nt)
94                 {
95                         source = new XmlTextReaderImpl (url, nt);
96                 }
97
98                 public XmlTextReader (TextReader input, XmlNameTable nt)
99                         : this (String.Empty, input, nt)
100                 {
101                 }
102
103                 public XmlTextReader (Stream xmlFragment, XmlNodeType fragType, XmlParserContext context)
104                 {
105                         source = new XmlTextReaderImpl (xmlFragment, fragType, context);
106                 }
107
108                 public XmlTextReader (string url, Stream input, XmlNameTable nt)
109                         : this (url, new XmlStreamReader (input), nt)
110                 {
111                 }
112
113                 public XmlTextReader (string url, TextReader input, XmlNameTable nt)
114                 {
115                         source = new XmlTextReaderImpl (url, input, nt);
116                 }
117
118                 public XmlTextReader (string xmlFragment, XmlNodeType fragType, XmlParserContext context)
119                 {
120                         source = new XmlTextReaderImpl (xmlFragment, fragType, context);
121                 }
122
123                 internal XmlTextReader (string baseURI, TextReader xmlFragment, XmlNodeType fragType)
124                 {
125                         source = new XmlTextReaderImpl (baseURI, xmlFragment, fragType);
126                 }
127
128                 internal XmlTextReader (string baseURI, TextReader xmlFragment, XmlNodeType fragType, XmlParserContext context)
129                 {
130                         source = new XmlTextReaderImpl (baseURI, xmlFragment, fragType, context);
131                 }
132
133                 internal XmlTextReader (bool dummy, string url, XmlNodeType fragType, XmlParserContext context)
134                 {
135                         source = new XmlTextReaderImpl (dummy, url, fragType, context);
136                 }
137
138                 private XmlTextReader (XmlTextReaderImpl entityContainer, bool insideAttribute)
139                 {
140                         source = entityContainer;
141                         this.entityInsideAttribute = insideAttribute;
142                 }
143
144                 #region Properties
145
146                 private XmlReader Current {
147                         get { return entity != null && entity.ReadState != ReadState.Initial ? (XmlReader) entity : source; }
148                 }
149
150                 public override int AttributeCount {
151                         get { return Current.AttributeCount; }
152                 }
153
154                 public override string BaseURI {
155                         get { return Current.BaseURI; }
156                 }
157
158                 public override bool CanReadBinaryContent {
159                         get { return true; }
160                 }
161
162                 public override bool CanReadValueChunk {
163                         get { return true; }
164                 }
165
166                 public override bool CanResolveEntity {
167                         get { return true; }
168                 }
169
170                 public override int Depth {
171                         get {
172                                 // On EndEntity, depth is the same as that 
173                                 // of EntityReference.
174                                 if (entity != null && entity.ReadState == ReadState.Interactive)
175                                         return source.Depth + entity.Depth + 1;
176                                 else
177                                         return source.Depth;
178                         }
179                 }
180
181                 public override bool EOF {
182                         get { return source.EOF; }
183                 }
184
185                 public override bool HasValue {
186                         get { return Current.HasValue; }
187                 }
188
189                 public override bool IsDefault {
190                         get { return Current.IsDefault; }
191                 }
192
193                 public override bool IsEmptyElement {
194                         get { return Current.IsEmptyElement; }
195                 }
196
197                 public override string LocalName {
198                         get { return Current.LocalName; }
199                 }
200
201                 public override string Name {
202                         get { return Current.Name; }
203                 }
204
205                 public override string NamespaceURI {
206                         get { return Current.NamespaceURI; }
207                 }
208
209                 public override XmlNameTable NameTable {
210                         get { return Current.NameTable; }
211                 }
212
213                 public override XmlNodeType NodeType {
214                         get {
215                                 if (Current == entity)
216                                         return entity.EOF ? XmlNodeType.EndEntity : entity.NodeType;
217                                 else
218                                         return source.NodeType;
219                         }
220                 }
221
222                 internal XmlParserContext ParserContext {
223                         get { return ((IHasXmlParserContext) Current).ParserContext; }
224                 }
225
226                 XmlParserContext IHasXmlParserContext.ParserContext {
227                         get { return this.ParserContext; }
228                 }
229
230                 public override string Prefix {
231                         get { return Current.Prefix; }
232                 }
233
234                 public override char QuoteChar {
235                         get { return Current.QuoteChar; }
236                 }
237
238                 public override ReadState ReadState {
239                         get { return entity != null ? ReadState.Interactive : source.ReadState; }
240                 }
241
242                 public override XmlReaderSettings Settings {
243                         get { return base.Settings; }
244                 }
245
246                 public override string Value {
247                         get { return Current.Value; }
248                 }
249
250                 public override string XmlLang {
251                         get { return Current.XmlLang; }
252                 }
253
254                 public override XmlSpace XmlSpace {
255                         get { return Current.XmlSpace; }
256                 }
257
258                 // non-overrides
259
260                 internal bool CharacterChecking {
261                         get {
262                                 if (entity != null)
263                                         return entity.CharacterChecking;
264                                 else
265                                         return source.CharacterChecking;
266                         }
267                         set {
268                                 if (entity != null)
269                                         entity.CharacterChecking = value;
270                                 source.CharacterChecking = value;
271                         }
272                 }
273
274                 internal bool CloseInput {
275                         get {
276                                 if (entity != null)
277                                         return entity.CloseInput;
278                                 else
279                                         return source.CloseInput;
280                         }
281                         set {
282                                 if (entity != null)
283                                         entity.CloseInput = value;
284                                 source.CloseInput = value;
285                         }
286                 }
287
288                 internal ConformanceLevel Conformance {
289                         set {
290                                 if (entity != null)
291                                         entity.Conformance = value;
292                                 source.Conformance = value;
293                         }
294                 }
295
296                 internal XmlResolver Resolver {
297                         get { return source.Resolver; }
298                 }
299
300                 private void CopyProperties (XmlTextReader other)
301                 {
302                         CharacterChecking = other.CharacterChecking;
303                         CloseInput = other.CloseInput;
304                         if (other.Settings != null)
305                                 Conformance = other.Settings.ConformanceLevel;
306                         XmlResolver = other.Resolver;
307                 }
308
309                 // public members
310
311                 public Encoding Encoding {
312                         get {
313                                 if (entity != null)
314                                         return entity.Encoding;
315                                 else
316                                         return source.Encoding;
317                         }
318                 }
319
320                 public EntityHandling EntityHandling {
321                         get { return source.EntityHandling; }
322                         set {
323                                 if (entity != null)
324                                         entity.EntityHandling = value;
325                                 source.EntityHandling = value;
326                         }
327                 }
328
329                 public int LineNumber {
330                         get {
331                                 if (entity != null)
332                                         return entity.LineNumber;
333                                 else
334                                         return source.LineNumber;
335                         }
336                 }
337
338                 public int LinePosition {
339                         get {
340                                 if (entity != null)
341                                         return entity.LinePosition;
342                                 else
343                                         return source.LinePosition;
344                         }
345                 }
346
347                 public bool Namespaces {
348                         get { return source.Namespaces; }
349                         set {
350                                 if (entity != null)
351                                         entity.Namespaces = value;
352                                 source.Namespaces = value;
353                         }
354                 }
355
356                 public bool Normalization {
357                         get { return source.Normalization; }
358                         set {
359                                 if (entity != null)
360                                         entity.Normalization = value;
361                                 source.Normalization = value;
362                         }
363                 }
364
365                 public bool ProhibitDtd {
366                         get { return source.ProhibitDtd; }
367                         set {
368                                 if (entity != null)
369                                         entity.ProhibitDtd = value;
370                                 source.ProhibitDtd = value;
371                         }
372                 }
373
374                 public WhitespaceHandling WhitespaceHandling {
375                         get { return source.WhitespaceHandling; }
376                         set {
377                                 if (entity != null)
378                                         entity.WhitespaceHandling = value;
379                                 source.WhitespaceHandling = value;
380                         }
381                 }
382
383                 public XmlResolver XmlResolver {
384                         set {
385                                 if (entity != null)
386                                         entity.XmlResolver = value;
387                                 source.XmlResolver = value;
388                         }
389                 }
390
391                 #endregion
392
393                 #region Methods
394
395                 internal void AdjustLineInfoOffset (int lineNumberOffset, int linePositionOffset)
396                 {
397                         if (entity != null)
398                                 entity.AdjustLineInfoOffset (lineNumberOffset, linePositionOffset);
399                         source.AdjustLineInfoOffset (lineNumberOffset, linePositionOffset);
400                 }
401
402                 internal void SetNameTable (XmlNameTable nameTable)
403                 {
404                         if (entity != null)
405                                 entity.SetNameTable (nameTable);
406                         source.SetNameTable (nameTable);
407                 }
408
409                 // overrides
410
411                 public override void Close ()
412                 {
413                         if (entity != null)
414                                 entity.Close ();
415                         source.Close ();
416                 }
417
418                 public override string GetAttribute (int i)
419                 {
420                         return Current.GetAttribute (i);
421                 }
422
423                 // MS.NET 1.0 msdn says that this method returns String.Empty
424                 // for absent attribute, but in fact it returns null.
425                 // This description is corrected in MS.NET 1.1 msdn.
426                 public override string GetAttribute (string name)
427                 {
428                         return Current.GetAttribute (name);
429                 }
430
431                 public override string GetAttribute (string localName, string namespaceURI)
432                 {
433                         return Current.GetAttribute (localName, namespaceURI);
434                 }
435
436                 public IDictionary<string, string> GetNamespacesInScope (XmlNamespaceScope scope)
437                 {
438                         return ((IXmlNamespaceResolver) Current).GetNamespacesInScope (scope);
439                 }
440
441                 IDictionary<string, string> IXmlNamespaceResolver.GetNamespacesInScope (XmlNamespaceScope scope)
442                 {
443                         return GetNamespacesInScope (scope);
444                 }
445
446                 public override string LookupNamespace (string prefix)
447                 {
448                         return Current.LookupNamespace (prefix);
449                 }
450
451                 string IXmlNamespaceResolver.LookupPrefix (string ns)
452                 {
453                         return ((IXmlNamespaceResolver) Current).LookupPrefix (ns);
454                 }
455
456                 public override void MoveToAttribute (int i)
457                 {
458                         if (entity != null && entityInsideAttribute) {
459                                 entity.Close ();
460                                 entity = null;
461                         }
462                         Current.MoveToAttribute (i);
463                         insideAttribute = true;
464                 }
465
466                 public override bool MoveToAttribute (string name)
467                 {
468                         if (entity != null && !entityInsideAttribute)
469                                 return entity.MoveToAttribute (name);
470                         if (!source.MoveToAttribute (name))
471                                 return false;
472                         if (entity != null && entityInsideAttribute) {
473                                 entity.Close ();
474                                 entity = null;
475                         }
476                         insideAttribute = true;
477                         return true;
478                 }
479
480                 public override bool MoveToAttribute (string localName, string namespaceName)
481                 {
482                         if (entity != null && !entityInsideAttribute)
483                                 return entity.MoveToAttribute (localName, namespaceName);
484                         if (!source.MoveToAttribute (localName, namespaceName))
485                                 return false;
486                         if (entity != null && entityInsideAttribute) {
487                                 entity.Close ();
488                                 entity = null;
489                         }
490                         insideAttribute = true;
491                         return true;
492                 }
493
494                 public override bool MoveToElement ()
495                 {
496                         if (entity != null && entityInsideAttribute) {
497                                 entity.Close ();
498                                 entity = null;
499                         }
500                         if (!Current.MoveToElement ())
501                                 return false;
502                         insideAttribute = false;
503                         return true;
504                 }
505
506                 public override bool MoveToFirstAttribute ()
507                 {
508                         if (entity != null && !entityInsideAttribute)
509                                 return entity.MoveToFirstAttribute ();
510                         if (!source.MoveToFirstAttribute ())
511                                 return false;
512                         if (entity != null && entityInsideAttribute) {
513                                 entity.Close ();
514                                 entity = null;
515                         }
516                         insideAttribute = true;
517                         return true;
518                 }
519
520                 public override bool MoveToNextAttribute ()
521                 {
522                         if (entity != null && !entityInsideAttribute)
523                                 return entity.MoveToNextAttribute ();
524                         if (!source.MoveToNextAttribute ())
525                                 return false;
526                         if (entity != null && entityInsideAttribute) {
527                                 entity.Close ();
528                                 entity = null;
529                         }
530                         insideAttribute = true;
531                         return true;
532                 }
533
534                 public override bool Read ()
535                 {
536                         insideAttribute = false;
537
538                         if (entity != null && (entityInsideAttribute || entity.EOF)) {
539                                 entity.Close ();
540                                 entity = null;
541                         }
542                         if (entity != null) {
543                                 if (entity.Read ())
544                                         return true;
545                                 if (EntityHandling == EntityHandling.ExpandEntities) {
546                                         // EndEntity must be skipped
547                                         entity.Close ();
548                                         entity = null;
549                                         return Read ();
550                                 }
551                                 else
552                                         return true; // either success or EndEntity
553                         }
554                         else {
555                                 if (!source.Read ())
556                                         return false;
557                                 if (EntityHandling == EntityHandling.ExpandEntities
558                                         && source.NodeType == XmlNodeType.EntityReference) {
559                                         ResolveEntity ();
560                                         return Read ();
561                                 }
562                                 return true;
563                         }
564                 }
565
566                 public override bool ReadAttributeValue ()
567                 {
568                         if (entity != null && entityInsideAttribute) {
569                                 if (entity.EOF) {
570                                         entity.Close ();
571                                         entity = null;
572                                 }
573                                 else {
574                                         entity.Read ();
575                                         return true; // either success or EndEntity
576                                 }
577                         }
578                         return Current.ReadAttributeValue ();
579                 }
580
581                 public override string ReadString ()
582                 {
583                         return base.ReadString ();
584                 }
585
586                 public void ResetState ()
587                 {
588                         if (entity != null)
589                                 entity.ResetState ();
590                         source.ResetState ();
591                 }
592
593                 public override void ResolveEntity ()
594                 {
595                         if (entity != null)
596                                 entity.ResolveEntity ();
597                         else {
598                                 if (source.NodeType != XmlNodeType.EntityReference)
599                                         throw new InvalidOperationException ("The current node is not an Entity Reference");
600                                 XmlTextReaderImpl entReader = 
601                                         ParserContext.Dtd.GenerateEntityContentReader (source.Name, ParserContext);
602                                 if (entReader == null)
603                                         throw new XmlException (this as IXmlLineInfo, this.BaseURI, String.Format ("Reference to undeclared entity '{0}'.", source.Name));
604                                 entity = new XmlTextReader (
605                                         entReader, insideAttribute);
606                                 entity.CopyProperties (this);
607                         }
608                 }
609
610                 public override void Skip ()
611                 {
612                         base.Skip ();
613                 }
614
615                 [MonoTODO ("Check how expanded entity is handled here.")]
616                 public TextReader GetRemainder ()
617                 {
618                         if (entity != null) {
619                                 entity.Close ();
620                                 entity = null;
621                         }
622                         return source.GetRemainder ();
623                 }
624
625                 public bool HasLineInfo ()
626                 {
627                         return true;
628                 }
629
630                 [MonoTODO ("Check how expanded entity is handled here.")]
631                 public int ReadBase64 (byte [] buffer, int offset, int length)
632                 {
633                         if (entity != null)
634                                 return entity.ReadBase64 (buffer, offset, length);
635                         else
636                                 return source.ReadBase64 (buffer, offset, length);
637                 }
638
639                 [MonoTODO ("Check how expanded entity is handled here.")]
640                 public int ReadBinHex (byte [] buffer, int offset, int length)
641                 {
642                         if (entity != null)
643                                 return entity.ReadBinHex (buffer, offset, length);
644                         else
645                                 return source.ReadBinHex (buffer, offset, length);
646                 }
647
648                 [MonoTODO ("Check how expanded entity is handled here.")]
649                 public int ReadChars (char [] buffer, int offset, int length)
650                 {
651                         if (entity != null)
652                                 return entity.ReadChars (buffer, offset, length);
653                         else
654                                 return source.ReadChars (buffer, offset, length);
655                 }
656
657
658                 [MonoTODO ("Check how expanded entity is handled here.")]
659                 public override int ReadContentAsBase64 (byte [] buffer, int offset, int length)
660                 {
661                         if (entity != null)
662                                 return entity.ReadContentAsBase64 (buffer, offset, length);
663                         else
664                                 return source.ReadContentAsBase64 (buffer, offset, length);
665                 }
666
667                 [MonoTODO ("Check how expanded entity is handled here.")]
668                 public override int ReadContentAsBinHex (byte [] buffer, int offset, int length)
669                 {
670                         if (entity != null)
671                                 return entity.ReadContentAsBinHex (buffer, offset, length);
672                         else
673                                 return source.ReadContentAsBinHex (buffer, offset, length);
674                 }
675
676                 [MonoTODO ("Check how expanded entity is handled here.")]
677                 public override int ReadElementContentAsBase64 (byte [] buffer, int offset, int length)
678                 {
679                         if (entity != null)
680                                 return entity.ReadElementContentAsBase64 (buffer, offset, length);
681                         else
682                                 return source.ReadElementContentAsBase64 (buffer, offset, length);
683                 }
684
685                 [MonoTODO ("Check how expanded entity is handled here.")]
686                 public override int ReadElementContentAsBinHex (byte [] buffer, int offset, int length)
687                 {
688                         if (entity != null)
689                                 return entity.ReadElementContentAsBinHex (buffer, offset, length);
690                         else
691                                 return source.ReadElementContentAsBinHex (buffer, offset, length);
692                 }
693                 #endregion
694         }
695 }
696
697 #endif