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