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