Merge pull request #347 from JamesB7/master
[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 #if !NET_4_5
258                 public override XmlReaderSettings Settings {
259                         get { return base.Settings; }
260                 }
261 #endif
262
263                 public override string Value {
264                         get { return Current.Value; }
265                 }
266
267                 public override string XmlLang {
268                         get { return Current.XmlLang; }
269                 }
270
271                 public override XmlSpace XmlSpace {
272                         get { return Current.XmlSpace; }
273                 }
274
275                 // non-overrides
276
277                 internal bool CharacterChecking {
278                         get {
279                                 if (entity != null)
280                                         return entity.CharacterChecking;
281                                 else
282                                         return source.CharacterChecking;
283                         }
284                         set {
285                                 if (entity != null)
286                                         entity.CharacterChecking = value;
287                                 source.CharacterChecking = value;
288                         }
289                 }
290
291                 internal bool CloseInput {
292                         get {
293                                 if (entity != null)
294                                         return entity.CloseInput;
295                                 else
296                                         return source.CloseInput;
297                         }
298                         set {
299                                 if (entity != null)
300                                         entity.CloseInput = value;
301                                 source.CloseInput = value;
302                         }
303                 }
304
305                 internal ConformanceLevel Conformance {
306                         get { return source.Conformance; }
307                         set {
308                                 if (entity != null)
309                                         entity.Conformance = value;
310                                 source.Conformance = value;
311                         }
312                 }
313
314                 internal XmlResolver Resolver {
315                         get { return source.Resolver; }
316                 }
317
318                 private void CopyProperties (XmlTextReader other)
319                 {
320                         CharacterChecking = other.CharacterChecking;
321                         CloseInput = other.CloseInput;
322                         if (other.Settings != null)
323                                 Conformance = other.Settings.ConformanceLevel;
324                         XmlResolver = other.Resolver;
325                 }
326
327                 // public members
328
329                 public Encoding Encoding {
330                         get {
331                                 if (entity != null)
332                                         return entity.Encoding;
333                                 else
334                                         return source.Encoding;
335                         }
336                 }
337
338                 public EntityHandling EntityHandling {
339                         get { return source.EntityHandling; }
340                         set {
341                                 if (entity != null)
342                                         entity.EntityHandling = value;
343                                 source.EntityHandling = value;
344                         }
345                 }
346
347                 public int LineNumber {
348                         get {
349                                 if (entity != null)
350                                         return entity.LineNumber;
351                                 else
352                                         return source.LineNumber;
353                         }
354                 }
355
356                 public int LinePosition {
357                         get {
358                                 if (entity != null)
359                                         return entity.LinePosition;
360                                 else
361                                         return source.LinePosition;
362                         }
363                 }
364
365                 public bool Namespaces {
366                         get { return source.Namespaces; }
367                         set {
368                                 if (entity != null)
369                                         entity.Namespaces = value;
370                                 source.Namespaces = value;
371                         }
372                 }
373
374                 public bool Normalization {
375                         get { return source.Normalization; }
376                         set {
377                                 if (entity != null)
378                                         entity.Normalization = value;
379                                 source.Normalization = value;
380                         }
381                 }
382
383                 public bool ProhibitDtd {
384                         get { return source.ProhibitDtd; }
385                         set {
386                                 if (entity != null)
387                                         entity.ProhibitDtd = value;
388                                 source.ProhibitDtd = value;
389                         }
390                 }
391
392                 public WhitespaceHandling WhitespaceHandling {
393                         get { return source.WhitespaceHandling; }
394                         set {
395                                 if (entity != null)
396                                         entity.WhitespaceHandling = value;
397                                 source.WhitespaceHandling = value;
398                         }
399                 }
400
401                 public XmlResolver XmlResolver {
402                         set {
403                                 if (entity != null)
404                                         entity.XmlResolver = value;
405                                 source.XmlResolver = value;
406                         }
407                 }
408
409                 #endregion
410
411                 #region Methods
412
413                 internal void AdjustLineInfoOffset (int lineNumberOffset, int linePositionOffset)
414                 {
415                         if (entity != null)
416                                 entity.AdjustLineInfoOffset (lineNumberOffset, linePositionOffset);
417                         source.AdjustLineInfoOffset (lineNumberOffset, linePositionOffset);
418                 }
419
420                 internal void SetNameTable (XmlNameTable nameTable)
421                 {
422                         if (entity != null)
423                                 entity.SetNameTable (nameTable);
424                         source.SetNameTable (nameTable);
425                 }
426
427                 internal void SkipTextDeclaration ()
428                 {
429                         if (entity != null)
430                                 entity.SkipTextDeclaration ();
431                         else
432                                 source.SkipTextDeclaration ();
433                 }
434
435                 // overrides
436
437                 public override void Close ()
438                 {
439                         if (entity != null)
440                                 entity.Close ();
441                         source.Close ();
442                 }
443
444                 public override string GetAttribute (int i)
445                 {
446                         return Current.GetAttribute (i);
447                 }
448
449                 // MS.NET 1.0 msdn says that this method returns String.Empty
450                 // for absent attribute, but in fact it returns null.
451                 // This description is corrected in MS.NET 1.1 msdn.
452                 public override string GetAttribute (string name)
453                 {
454                         return Current.GetAttribute (name);
455                 }
456
457                 public override string GetAttribute (string localName, string namespaceURI)
458                 {
459                         return Current.GetAttribute (localName, namespaceURI);
460                 }
461
462                 public IDictionary<string, string> GetNamespacesInScope (XmlNamespaceScope scope)
463                 {
464                         return ((IXmlNamespaceResolver) Current).GetNamespacesInScope (scope);
465                 }
466
467                 IDictionary<string, string> IXmlNamespaceResolver.GetNamespacesInScope (XmlNamespaceScope scope)
468                 {
469                         return GetNamespacesInScope (scope);
470                 }
471
472                 public override string LookupNamespace (string prefix)
473                 {
474                         return Current.LookupNamespace (prefix);
475                 }
476
477                 string IXmlNamespaceResolver.LookupPrefix (string ns)
478                 {
479                         return ((IXmlNamespaceResolver) Current).LookupPrefix (ns);
480                 }
481
482                 public override void MoveToAttribute (int i)
483                 {
484                         if (entity != null && entityInsideAttribute)
485                                 CloseEntity ();
486                         Current.MoveToAttribute (i);
487                         insideAttribute = true;
488                 }
489
490                 public override bool MoveToAttribute (string name)
491                 {
492                         if (entity != null && !entityInsideAttribute)
493                                 return entity.MoveToAttribute (name);
494                         if (!source.MoveToAttribute (name))
495                                 return false;
496                         if (entity != null && entityInsideAttribute)
497                                 CloseEntity ();
498                         insideAttribute = true;
499                         return true;
500                 }
501
502                 public override bool MoveToAttribute (string localName, string namespaceURI)
503                 {
504                         if (entity != null && !entityInsideAttribute)
505                                 return entity.MoveToAttribute (localName, namespaceURI);
506                         if (!source.MoveToAttribute (localName, namespaceURI))
507                                 return false;
508                         if (entity != null && entityInsideAttribute)
509                                 CloseEntity ();
510                         insideAttribute = true;
511                         return true;
512                 }
513
514                 public override bool MoveToElement ()
515                 {
516                         if (entity != null && entityInsideAttribute)
517                                 CloseEntity ();
518                         if (!Current.MoveToElement ())
519                                 return false;
520                         insideAttribute = false;
521                         return true;
522                 }
523
524                 public override bool MoveToFirstAttribute ()
525                 {
526                         if (entity != null && !entityInsideAttribute)
527                                 return entity.MoveToFirstAttribute ();
528                         if (!source.MoveToFirstAttribute ())
529                                 return false;
530                         if (entity != null && entityInsideAttribute)
531                                 CloseEntity ();
532                         insideAttribute = true;
533                         return true;
534                 }
535
536                 public override bool MoveToNextAttribute ()
537                 {
538                         if (entity != null && !entityInsideAttribute)
539                                 return entity.MoveToNextAttribute ();
540                         if (!source.MoveToNextAttribute ())
541                                 return false;
542                         if (entity != null && entityInsideAttribute)
543                                 CloseEntity ();
544                         insideAttribute = true;
545                         return true;
546                 }
547
548                 public override bool Read ()
549                 {
550                         insideAttribute = false;
551
552                         if (entity != null && (entityInsideAttribute || entity.EOF))
553                                 CloseEntity ();
554                         if (entity != null) {
555                                 if (entity.Read ())
556                                         return true;
557                                 if (EntityHandling == EntityHandling.ExpandEntities) {
558                                         // EndEntity must be skipped
559                                         CloseEntity ();
560                                         return Read ();
561                                 }
562                                 else
563                                         return true; // either success or EndEntity
564                         }
565                         else {
566                                 if (!source.Read ())
567                                         return false;
568                                 if (EntityHandling == EntityHandling.ExpandEntities
569                                         && source.NodeType == XmlNodeType.EntityReference) {
570                                         ResolveEntity ();
571                                         return Read ();
572                                 }
573                                 return true;
574                         }
575                 }
576
577                 public override bool ReadAttributeValue ()
578                 {
579                         if (entity != null && entityInsideAttribute) {
580                                 if (entity.EOF)
581                                         CloseEntity ();
582                                 else {
583                                         entity.Read ();
584                                         return true; // either success or EndEntity
585                                 }
586                         }
587                         return Current.ReadAttributeValue ();
588                 }
589
590                 public override string ReadString ()
591                 {
592                         return base.ReadString ();
593                 }
594
595                 public void ResetState ()
596                 {
597                         if (entity != null)
598                                 CloseEntity ();
599                         source.ResetState ();
600                 }
601
602                 public override
603                 void ResolveEntity ()
604                 {
605                         if (entity != null)
606                                 entity.ResolveEntity ();
607                         else {
608                                 if (source.NodeType != XmlNodeType.EntityReference)
609                                         throw new InvalidOperationException ("The current node is not an Entity Reference");
610                                 XmlTextReaderImpl entReader = null;
611                                 if (ParserContext.Dtd != null)
612                                         entReader = ParserContext.Dtd.GenerateEntityContentReader (source.Name, ParserContext);
613                                 if (entReader == null)
614                                         throw new XmlException (this as IXmlLineInfo, this.BaseURI, String.Format ("Reference to undeclared entity '{0}'.", source.Name));
615                                 if (entityNameStack == null)
616                                         entityNameStack = new Stack<string> ();
617                                 else if (entityNameStack.Contains (Name))
618                                         throw new XmlException (String.Format ("General entity '{0}' has an invalid recursive reference to itself.", Name));
619                                 entityNameStack.Push (Name);
620                                 entity = new XmlTextReader (
621                                         entReader, insideAttribute);
622                                 entity.entityNameStack = entityNameStack;
623                                 entity.CopyProperties (this);
624                         }
625                 }
626
627                 void CloseEntity ()
628                 {
629                         entity.Close ();
630                         entity = null;
631                         entityNameStack.Pop ();
632                 }
633
634                 public override void Skip ()
635                 {
636                         base.Skip ();
637                 }
638
639                 [MonoTODO] // FIXME: Check how expanded entity is handled here.
640                 public TextReader GetRemainder ()
641                 {
642                         if (entity != null) {
643                                 entity.Close ();
644                                 entity = null;
645                                 entityNameStack.Pop ();
646                         }
647                         return source.GetRemainder ();
648                 }
649
650                 public bool HasLineInfo ()
651                 {
652                         return true;
653                 }
654
655                 [MonoTODO] // FIXME: Check how expanded entity is handled here.
656                 public int ReadBase64 (byte [] array, int offset, int len)
657                 {
658                         if (entity != null)
659                                 return entity.ReadBase64 (array, offset, len);
660                         else
661                                 return source.ReadBase64 (array, offset, len);
662                 }
663
664                 [MonoTODO] // FIXME: Check how expanded entity is handled here.
665                 public int ReadBinHex (byte [] array, int offset, int len)
666                 {
667                         if (entity != null)
668                                 return entity.ReadBinHex (array, offset, len);
669                         else
670                                 return source.ReadBinHex (array, offset, len);
671                 }
672
673                 [MonoTODO] // FIXME: Check how expanded entity is handled here.
674                 public int ReadChars (char [] buffer, int index, int count)
675                 {
676                         if (entity != null)
677                                 return entity.ReadChars (buffer, index, count);
678                         else
679                                 return source.ReadChars (buffer, index, count);
680                 }
681
682
683                 [MonoTODO] // FIXME: Check how expanded entity is handled here.
684                 public override int ReadContentAsBase64 (byte [] buffer, int index, int count)
685                 {
686                         if (entity != null)
687                                 return entity.ReadContentAsBase64 (buffer, index, count);
688                         else
689                                 return source.ReadContentAsBase64 (buffer, index, count);
690                 }
691
692                 [MonoTODO] // FIXME: Check how expanded entity is handled here.
693                 public override int ReadContentAsBinHex (byte [] buffer, int index, int count)
694                 {
695                         if (entity != null)
696                                 return entity.ReadContentAsBinHex (buffer, index, count);
697                         else
698                                 return source.ReadContentAsBinHex (buffer, index, count);
699                 }
700
701                 [MonoTODO] // FIXME: Check how expanded entity is handled here.
702                 public override int ReadElementContentAsBase64 (byte [] buffer, int index, int count)
703                 {
704                         if (entity != null)
705                                 return entity.ReadElementContentAsBase64 (buffer, index, count);
706                         else
707                                 return source.ReadElementContentAsBase64 (buffer, index, count);
708                 }
709
710                 [MonoTODO] // FIXME: Check how expanded entity is handled here.
711                 public override int ReadElementContentAsBinHex (byte [] buffer, int index, int count)
712                 {
713                         if (entity != null)
714                                 return entity.ReadElementContentAsBinHex (buffer, index, count);
715                         else
716                                 return source.ReadElementContentAsBinHex (buffer, index, count);
717                 }
718                 #endregion
719         }
720 }
721
722 #endif