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