147fca02494fbb9a3ce2bcc5b91957a02dba2b83
[platform/upstream/dotnet/runtime.git] /
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3
4 using System.Collections.Generic;
5 using System.Diagnostics.CodeAnalysis;
6 using System.Globalization;
7 using System.Runtime.Serialization.DataContracts;
8 using System.Xml;
9 using System.Xml.Serialization;
10
11 namespace System.Runtime.Serialization
12 {
13     internal class XmlReaderDelegator
14     {
15         protected XmlReader reader;
16         protected XmlDictionaryReader? dictionaryReader;
17         protected bool isEndOfEmptyElement;
18
19         public XmlReaderDelegator(XmlReader reader)
20         {
21             ArgumentNullException.ThrowIfNull(reader);
22
23             this.reader = reader;
24             this.dictionaryReader = reader as XmlDictionaryReader;
25         }
26
27         internal XmlReader UnderlyingReader
28         {
29             get { return reader; }
30         }
31
32         internal ExtensionDataReader? UnderlyingExtensionDataReader
33         {
34             get { return reader as ExtensionDataReader; }
35         }
36
37         internal int AttributeCount
38         {
39             get { return isEndOfEmptyElement ? 0 : reader.AttributeCount; }
40         }
41
42         internal string? GetAttribute(string name)
43         {
44             return isEndOfEmptyElement ? null : reader.GetAttribute(name);
45         }
46
47         internal string? GetAttribute(string name, string namespaceUri)
48         {
49             return isEndOfEmptyElement ? null : reader.GetAttribute(name, namespaceUri);
50         }
51
52         internal string GetAttribute(int i)
53         {
54             if (isEndOfEmptyElement)
55                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(i), SR.XmlElementAttributes));
56             return reader.GetAttribute(i);
57         }
58
59         [SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Conceptually, this property describes this instance. Callers should expect to have an instance on hand to 'ask' about this 'emtpy' circumstance.")]
60         internal bool IsEmptyElement
61         {
62             get { return false; }
63         }
64
65         internal bool IsNamespaceURI(string ns)
66         {
67             if (dictionaryReader == null)
68                 return ns == reader.NamespaceURI;
69             else
70                 return dictionaryReader.IsNamespaceUri(ns);
71         }
72
73         internal bool IsLocalName(string localName)
74         {
75             if (dictionaryReader == null)
76                 return localName == reader.LocalName;
77             else
78                 return dictionaryReader.IsLocalName(localName);
79         }
80
81         internal bool IsNamespaceUri(XmlDictionaryString ns)
82         {
83             if (dictionaryReader == null)
84                 return ns.Value == reader.NamespaceURI;
85             else
86                 return dictionaryReader.IsNamespaceUri(ns);
87         }
88
89         internal bool IsLocalName(XmlDictionaryString localName)
90         {
91             if (dictionaryReader == null)
92                 return localName.Value == reader.LocalName;
93             else
94                 return dictionaryReader.IsLocalName(localName);
95         }
96
97         internal int IndexOfLocalName(XmlDictionaryString[] localNames, XmlDictionaryString ns)
98         {
99             if (dictionaryReader != null)
100                 return dictionaryReader.IndexOfLocalName(localNames, ns);
101
102             if (reader.NamespaceURI == ns.Value)
103             {
104                 string localName = this.LocalName;
105                 for (int i = 0; i < localNames.Length; i++)
106                 {
107                     if (localName == localNames[i].Value)
108                     {
109                         return i;
110                     }
111                 }
112             }
113
114             return -1;
115         }
116
117         internal bool IsStartElement()
118         {
119             return !isEndOfEmptyElement && reader.IsStartElement();
120         }
121
122         internal bool IsStartElement(string localname, string ns)
123         {
124             return !isEndOfEmptyElement && reader.IsStartElement(localname, ns);
125         }
126
127         internal bool IsStartElement(XmlDictionaryString localname, XmlDictionaryString ns)
128         {
129             if (dictionaryReader == null)
130                 return !isEndOfEmptyElement && reader.IsStartElement(localname.Value, ns.Value);
131             else
132                 return !isEndOfEmptyElement && dictionaryReader.IsStartElement(localname, ns);
133         }
134
135         internal bool MoveToAttribute(string name)
136         {
137             return isEndOfEmptyElement ? false : reader.MoveToAttribute(name);
138         }
139
140         internal bool MoveToAttribute(string name, string ns)
141         {
142             return isEndOfEmptyElement ? false : reader.MoveToAttribute(name, ns);
143         }
144
145         internal void MoveToAttribute(int i)
146         {
147             if (isEndOfEmptyElement)
148                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(i), SR.XmlElementAttributes));
149             reader.MoveToAttribute(i);
150         }
151
152         internal bool MoveToElement()
153         {
154             return isEndOfEmptyElement ? false : reader.MoveToElement();
155         }
156
157         internal bool MoveToFirstAttribute()
158         {
159             return isEndOfEmptyElement ? false : reader.MoveToFirstAttribute();
160         }
161
162         internal bool MoveToNextAttribute()
163         {
164             return isEndOfEmptyElement ? false : reader.MoveToNextAttribute();
165         }
166
167         internal XmlNodeType NodeType
168         {
169             get { return isEndOfEmptyElement ? XmlNodeType.EndElement : reader.NodeType; }
170         }
171
172         internal bool Read()
173         {
174             //reader.MoveToFirstAttribute();
175             //if (NodeType == XmlNodeType.Attribute)
176             reader.MoveToElement();
177             if (!reader.IsEmptyElement)
178                 return reader.Read();
179             if (isEndOfEmptyElement)
180             {
181                 isEndOfEmptyElement = false;
182                 return reader.Read();
183             }
184             isEndOfEmptyElement = true;
185             return true;
186         }
187
188         internal XmlNodeType MoveToContent()
189         {
190             if (isEndOfEmptyElement)
191                 return XmlNodeType.EndElement;
192
193             return reader.MoveToContent();
194         }
195
196         internal bool ReadAttributeValue()
197         {
198             return isEndOfEmptyElement ? false : reader.ReadAttributeValue();
199         }
200
201         internal void ReadEndElement()
202         {
203             if (isEndOfEmptyElement)
204                 Read();
205             else
206                 reader.ReadEndElement();
207         }
208
209         private static InvalidDataContractException CreateInvalidPrimitiveTypeException(Type type)
210         {
211             return new InvalidDataContractException(SR.Format(
212                 type.IsInterface ? SR.InterfaceTypeCannotBeCreated : SR.InvalidPrimitiveType_Serialization,
213                 DataContract.GetClrTypeFullName(type)));
214         }
215
216         public object ReadElementContentAsAnyType(Type valueType)
217         {
218             Read();
219             object o = ReadContentAsAnyType(valueType);
220             ReadEndElement();
221             return o;
222         }
223
224         internal object ReadContentAsAnyType(Type valueType)
225         {
226             switch (Type.GetTypeCode(valueType))
227             {
228                 case TypeCode.Boolean:
229                     return ReadContentAsBoolean();
230                 case TypeCode.Char:
231                     return ReadContentAsChar();
232                 case TypeCode.Byte:
233                     return ReadContentAsUnsignedByte();
234                 case TypeCode.Int16:
235                     return ReadContentAsShort();
236                 case TypeCode.Int32:
237                     return ReadContentAsInt();
238                 case TypeCode.Int64:
239                     return ReadContentAsLong();
240                 case TypeCode.Single:
241                     return ReadContentAsSingle();
242                 case TypeCode.Double:
243                     return ReadContentAsDouble();
244                 case TypeCode.Decimal:
245                     return ReadContentAsDecimal();
246                 case TypeCode.DateTime:
247                     return ReadContentAsDateTime();
248                 case TypeCode.String:
249                     return ReadContentAsString();
250
251                 case TypeCode.SByte:
252                     return ReadContentAsSignedByte();
253                 case TypeCode.UInt16:
254                     return ReadContentAsUnsignedShort();
255                 case TypeCode.UInt32:
256                     return ReadContentAsUnsignedInt();
257                 case TypeCode.UInt64:
258                     return ReadContentAsUnsignedLong();
259                 case TypeCode.Empty:
260                 case TypeCode.DBNull:
261                 case TypeCode.Object:
262                 default:
263                     if (valueType == Globals.TypeOfByteArray)
264                         return ReadContentAsBase64();
265                     else if (valueType == Globals.TypeOfObject)
266                         return new object();
267                     else if (valueType == Globals.TypeOfTimeSpan)
268                         return ReadContentAsTimeSpan();
269                     else if (valueType == Globals.TypeOfGuid)
270                         return ReadContentAsGuid();
271                     else if (valueType == Globals.TypeOfUri)
272                         return ReadContentAsUri();
273                     else if (valueType == Globals.TypeOfXmlQualifiedName)
274                         return ReadContentAsQName();
275                     break;
276             }
277             throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateInvalidPrimitiveTypeException(valueType));
278         }
279
280         internal IDataNode ReadExtensionData(Type valueType)
281         {
282             switch (Type.GetTypeCode(valueType))
283             {
284                 case TypeCode.Boolean:
285                     return new DataNode<bool>(ReadContentAsBoolean());
286                 case TypeCode.Char:
287                     return new DataNode<char>(ReadContentAsChar());
288                 case TypeCode.Byte:
289                     return new DataNode<byte>(ReadContentAsUnsignedByte());
290                 case TypeCode.Int16:
291                     return new DataNode<short>(ReadContentAsShort());
292                 case TypeCode.Int32:
293                     return new DataNode<int>(ReadContentAsInt());
294                 case TypeCode.Int64:
295                     return new DataNode<long>(ReadContentAsLong());
296                 case TypeCode.Single:
297                     return new DataNode<float>(ReadContentAsSingle());
298                 case TypeCode.Double:
299                     return new DataNode<double>(ReadContentAsDouble());
300                 case TypeCode.Decimal:
301                     return new DataNode<decimal>(ReadContentAsDecimal());
302                 case TypeCode.DateTime:
303                     return new DataNode<DateTime>(ReadContentAsDateTime());
304                 case TypeCode.String:
305                     return new DataNode<string>(ReadContentAsString());
306                 case TypeCode.SByte:
307                     return new DataNode<sbyte>(ReadContentAsSignedByte());
308                 case TypeCode.UInt16:
309                     return new DataNode<ushort>(ReadContentAsUnsignedShort());
310                 case TypeCode.UInt32:
311                     return new DataNode<uint>(ReadContentAsUnsignedInt());
312                 case TypeCode.UInt64:
313                     return new DataNode<ulong>(ReadContentAsUnsignedLong());
314                 case TypeCode.Empty:
315                 case TypeCode.DBNull:
316                 case TypeCode.Object:
317                 default:
318                     if (valueType == Globals.TypeOfByteArray)
319                         return new DataNode<byte[]>(ReadContentAsBase64());
320                     else if (valueType == Globals.TypeOfObject)
321                         return new DataNode<object>(new object());
322                     else if (valueType == Globals.TypeOfTimeSpan)
323                         return new DataNode<TimeSpan>(ReadContentAsTimeSpan());
324                     else if (valueType == Globals.TypeOfGuid)
325                         return new DataNode<Guid>(ReadContentAsGuid());
326                     else if (valueType == Globals.TypeOfUri)
327                         return new DataNode<Uri>(ReadContentAsUri());
328                     else if (valueType == Globals.TypeOfXmlQualifiedName)
329                         return new DataNode<XmlQualifiedName>(ReadContentAsQName());
330                     break;
331             }
332             throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateInvalidPrimitiveTypeException(valueType));
333         }
334
335         [DoesNotReturn]
336         private void ThrowConversionException(string value, string type)
337         {
338             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(XmlObjectSerializer.TryAddLineInfo(this, SR.Format(SR.XmlInvalidConversion, value, type))));
339         }
340
341         [DoesNotReturn]
342         private static void ThrowNotAtElement()
343         {
344             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.Format(SR.XmlStartElementExpected, "EndElement")));
345         }
346
347         internal virtual char ReadElementContentAsChar()
348         {
349             return ToChar(ReadElementContentAsInt());
350         }
351
352         internal virtual char ReadContentAsChar()
353         {
354             return ToChar(ReadContentAsInt());
355         }
356
357         private char ToChar(int value)
358         {
359             if (value < char.MinValue || value > char.MaxValue)
360             {
361                 ThrowConversionException(value.ToString(NumberFormatInfo.CurrentInfo), "Char");
362             }
363             return (char)value;
364         }
365
366         internal string ReadElementContentAsString()
367         {
368             if (isEndOfEmptyElement)
369                 ThrowNotAtElement();
370
371             return reader.ReadElementContentAsString();
372         }
373
374         internal string ReadContentAsString()
375         {
376             return isEndOfEmptyElement ? string.Empty : reader.ReadContentAsString();
377         }
378
379         internal bool ReadElementContentAsBoolean()
380         {
381             if (isEndOfEmptyElement)
382                 ThrowNotAtElement();
383
384             return reader.ReadElementContentAsBoolean();
385         }
386
387         internal bool ReadContentAsBoolean()
388         {
389             if (isEndOfEmptyElement)
390                 ThrowConversionException(string.Empty, "Boolean");
391
392             return reader.ReadContentAsBoolean();
393         }
394
395         internal float ReadElementContentAsFloat()
396         {
397             if (isEndOfEmptyElement)
398                 ThrowNotAtElement();
399
400             return reader.ReadElementContentAsFloat();
401         }
402
403         internal float ReadContentAsSingle()
404         {
405             if (isEndOfEmptyElement)
406                 ThrowConversionException(string.Empty, "Float");
407
408             return reader.ReadContentAsFloat();
409         }
410
411         internal double ReadElementContentAsDouble()
412         {
413             if (isEndOfEmptyElement)
414                 ThrowNotAtElement();
415
416             return reader.ReadElementContentAsDouble();
417         }
418
419         internal double ReadContentAsDouble()
420         {
421             if (isEndOfEmptyElement)
422                 ThrowConversionException(string.Empty, "Double");
423
424             return reader.ReadContentAsDouble();
425         }
426
427         internal decimal ReadElementContentAsDecimal()
428         {
429             if (isEndOfEmptyElement)
430                 ThrowNotAtElement();
431
432             return reader.ReadElementContentAsDecimal();
433         }
434
435         internal decimal ReadContentAsDecimal()
436         {
437             if (isEndOfEmptyElement)
438                 ThrowConversionException(string.Empty, "Decimal");
439
440             return reader.ReadContentAsDecimal();
441         }
442
443         internal virtual byte[] ReadElementContentAsBase64()
444         {
445             if (isEndOfEmptyElement)
446                 ThrowNotAtElement();
447
448             if (dictionaryReader == null)
449             {
450                 return ReadContentAsBase64(reader.ReadElementContentAsString());
451             }
452             else
453             {
454                 return dictionaryReader.ReadElementContentAsBase64();
455             }
456         }
457
458         public virtual byte[] ReadContentAsBase64()
459         {
460             if (isEndOfEmptyElement)
461                 return Array.Empty<byte>();
462
463             if (dictionaryReader == null)
464             {
465                 return ReadContentAsBase64(reader.ReadContentAsString());
466             }
467             else
468             {
469                 return dictionaryReader.ReadContentAsBase64();
470             }
471         }
472
473         [return: NotNullIfNotNull(nameof(str))]
474         internal static byte[]? ReadContentAsBase64(string? str)
475         {
476             if (str == null)
477                 return null;
478             str = str.Trim();
479             if (str.Length == 0)
480                 return Array.Empty<byte>();
481
482             try
483             {
484                 return Convert.FromBase64String(str);
485             }
486             catch (ArgumentException exception)
487             {
488                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(str, "byte[]", exception));
489             }
490             catch (FormatException exception)
491             {
492                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(str, "byte[]", exception));
493             }
494         }
495
496         internal virtual DateTime ReadElementContentAsDateTime()
497         {
498             if (isEndOfEmptyElement)
499                 ThrowNotAtElement();
500
501             return reader.ReadElementContentAsDateTime();
502         }
503
504         internal virtual DateTime ReadContentAsDateTime()
505         {
506             if (isEndOfEmptyElement)
507                 ThrowConversionException(string.Empty, "DateTime");
508
509             return reader.ReadContentAsDateTime();
510         }
511
512         internal int ReadElementContentAsInt()
513         {
514             if (isEndOfEmptyElement)
515                 ThrowNotAtElement();
516
517             return reader.ReadElementContentAsInt();
518         }
519
520         internal int ReadContentAsInt()
521         {
522             if (isEndOfEmptyElement)
523                 ThrowConversionException(string.Empty, "Int32");
524
525             return reader.ReadContentAsInt();
526         }
527
528         internal long ReadElementContentAsLong()
529         {
530             if (isEndOfEmptyElement)
531                 ThrowNotAtElement();
532
533             return reader.ReadElementContentAsLong();
534         }
535
536         internal long ReadContentAsLong()
537         {
538             if (isEndOfEmptyElement)
539                 ThrowConversionException(string.Empty, "Int64");
540
541             return reader.ReadContentAsLong();
542         }
543
544         internal short ReadElementContentAsShort()
545         {
546             return ToShort(ReadElementContentAsInt());
547         }
548
549         internal short ReadContentAsShort()
550         {
551             return ToShort(ReadContentAsInt());
552         }
553
554         private short ToShort(int value)
555         {
556             if (value < short.MinValue || value > short.MaxValue)
557             {
558                 ThrowConversionException(value.ToString(NumberFormatInfo.CurrentInfo), "Int16");
559             }
560             return (short)value;
561         }
562
563         internal byte ReadElementContentAsUnsignedByte()
564         {
565             return ToByte(ReadElementContentAsInt());
566         }
567
568         internal byte ReadContentAsUnsignedByte()
569         {
570             return ToByte(ReadContentAsInt());
571         }
572
573         private byte ToByte(int value)
574         {
575             if (value < byte.MinValue || value > byte.MaxValue)
576             {
577                 ThrowConversionException(value.ToString(NumberFormatInfo.CurrentInfo), "Byte");
578             }
579             return (byte)value;
580         }
581
582         internal sbyte ReadElementContentAsSignedByte()
583         {
584             return ToSByte(ReadElementContentAsInt());
585         }
586
587         internal sbyte ReadContentAsSignedByte()
588         {
589             return ToSByte(ReadContentAsInt());
590         }
591
592         private sbyte ToSByte(int value)
593         {
594             if (value < sbyte.MinValue || value > sbyte.MaxValue)
595             {
596                 ThrowConversionException(value.ToString(NumberFormatInfo.CurrentInfo), "SByte");
597             }
598             return (sbyte)value;
599         }
600
601         internal uint ReadElementContentAsUnsignedInt()
602         {
603             return ToUInt32(ReadElementContentAsLong());
604         }
605
606         internal uint ReadContentAsUnsignedInt()
607         {
608             return ToUInt32(ReadContentAsLong());
609         }
610
611         private uint ToUInt32(long value)
612         {
613             if (value < uint.MinValue || value > uint.MaxValue)
614             {
615                 ThrowConversionException(value.ToString(NumberFormatInfo.CurrentInfo), "UInt32");
616             }
617             return (uint)value;
618         }
619
620         internal virtual ulong ReadElementContentAsUnsignedLong()
621         {
622             if (isEndOfEmptyElement)
623                 ThrowNotAtElement();
624
625             string str = reader.ReadElementContentAsString();
626
627             if (str == null || str.Length == 0)
628                 ThrowConversionException(string.Empty, "UInt64");
629
630             return XmlConverter.ToUInt64(str);
631         }
632
633         internal virtual ulong ReadContentAsUnsignedLong()
634         {
635             string str = reader.ReadContentAsString();
636
637             if (str == null || str.Length == 0)
638                 ThrowConversionException(string.Empty, "UInt64");
639
640             return XmlConverter.ToUInt64(str);
641         }
642
643         internal ushort ReadElementContentAsUnsignedShort()
644         {
645             return ToUInt16(ReadElementContentAsInt());
646         }
647
648         internal ushort ReadContentAsUnsignedShort()
649         {
650             return ToUInt16(ReadContentAsInt());
651         }
652
653         private ushort ToUInt16(int value)
654         {
655             if (value < ushort.MinValue || value > ushort.MaxValue)
656             {
657                 ThrowConversionException(value.ToString(NumberFormatInfo.CurrentInfo), "UInt16");
658             }
659             return (ushort)value;
660         }
661
662         internal TimeSpan ReadElementContentAsTimeSpan()
663         {
664             if (isEndOfEmptyElement)
665                 ThrowNotAtElement();
666
667             string str = reader.ReadElementContentAsString();
668             return XmlConverter.ToTimeSpan(str);
669         }
670
671         internal TimeSpan ReadContentAsTimeSpan()
672         {
673             string str = reader.ReadContentAsString();
674             return XmlConverter.ToTimeSpan(str);
675         }
676
677         internal Guid ReadElementContentAsGuid()
678         {
679             if (isEndOfEmptyElement)
680                 ThrowNotAtElement();
681
682             string str = reader.ReadElementContentAsString();
683             try
684             {
685                 return new Guid(str);
686             }
687             catch (ArgumentException exception)
688             {
689                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(str, "Guid", exception));
690             }
691             catch (FormatException exception)
692             {
693                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(str, "Guid", exception));
694             }
695             catch (OverflowException exception)
696             {
697                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(str, "Guid", exception));
698             }
699         }
700
701         internal Guid ReadContentAsGuid()
702         {
703             string str = reader.ReadContentAsString();
704             try
705             {
706                 return Guid.Parse(str);
707             }
708             catch (ArgumentException exception)
709             {
710                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(str, "Guid", exception));
711             }
712             catch (FormatException exception)
713             {
714                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(str, "Guid", exception));
715             }
716             catch (OverflowException exception)
717             {
718                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(str, "Guid", exception));
719             }
720         }
721
722         internal Uri ReadElementContentAsUri()
723         {
724             if (isEndOfEmptyElement)
725                 ThrowNotAtElement();
726
727             string str = ReadElementContentAsString();
728             try
729             {
730                 return new Uri(str, UriKind.RelativeOrAbsolute);
731             }
732             catch (ArgumentException exception)
733             {
734                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(str, "Uri", exception));
735             }
736             catch (FormatException exception)
737             {
738                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(str, "Uri", exception));
739             }
740         }
741
742         internal Uri ReadContentAsUri()
743         {
744             string str = ReadContentAsString();
745             try
746             {
747                 return new Uri(str, UriKind.RelativeOrAbsolute);
748             }
749             catch (ArgumentException exception)
750             {
751                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(str, "Uri", exception));
752             }
753             catch (FormatException exception)
754             {
755                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(str, "Uri", exception));
756             }
757         }
758
759         internal XmlQualifiedName ReadElementContentAsQName()
760         {
761             Read();
762             XmlQualifiedName obj = ReadContentAsQName();
763             ReadEndElement();
764             return obj;
765         }
766
767         internal virtual XmlQualifiedName ReadContentAsQName()
768         {
769             return ParseQualifiedName(ReadContentAsString());
770         }
771
772         private XmlQualifiedName ParseQualifiedName(string str)
773         {
774             string name;
775             string? ns;
776             if (str == null || str.Length == 0)
777                 name = ns = string.Empty;
778             else
779                 XmlObjectSerializerReadContext.ParseQualifiedName(str, this, out name, out ns, out _);
780             return new XmlQualifiedName(name, ns);
781         }
782
783         private static void CheckExpectedArrayLength(XmlObjectSerializerReadContext context, int arrayLength)
784         {
785             context.IncrementItemCount(arrayLength);
786         }
787
788         protected int GetArrayLengthQuota(XmlObjectSerializerReadContext context)
789         {
790             if (dictionaryReader?.Quotas == null)
791                 return context.RemainingItemCount;
792
793             return Math.Min(context.RemainingItemCount, dictionaryReader.Quotas.MaxArrayLength);
794         }
795
796         private static void CheckActualArrayLength(int expectedLength, int actualLength, XmlDictionaryString itemName, XmlDictionaryString itemNamespace)
797         {
798             if (expectedLength != actualLength)
799                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ArrayExceededSizeAttribute, expectedLength, itemName.Value, itemNamespace.Value)));
800         }
801
802         internal bool TryReadBooleanArray(XmlObjectSerializerReadContext context,
803             XmlDictionaryString itemName, XmlDictionaryString itemNamespace,
804             int arrayLength, [NotNullWhen(true)] out bool[]? array)
805         {
806             if (dictionaryReader == null)
807             {
808                 array = null;
809                 return false;
810             }
811
812             if (arrayLength != -1)
813             {
814                 CheckExpectedArrayLength(context, arrayLength);
815                 array = new bool[arrayLength];
816                 int read, offset = 0;
817                 while ((read = dictionaryReader.ReadArray(itemName, itemNamespace, array, offset, arrayLength - offset)) > 0)
818                 {
819                     offset += read;
820                 }
821                 CheckActualArrayLength(arrayLength, offset, itemName, itemNamespace);
822             }
823             else
824             {
825                 array = BooleanArrayHelperWithDictionaryString.Instance.ReadArray(
826                     dictionaryReader, itemName, itemNamespace, GetArrayLengthQuota(context));
827                 context.IncrementItemCount(array.Length);
828             }
829             return true;
830         }
831
832         internal virtual bool TryReadDateTimeArray(XmlObjectSerializerReadContext context,
833             XmlDictionaryString itemName, XmlDictionaryString itemNamespace,
834             int arrayLength, [NotNullWhen(true)] out DateTime[]? array)
835         {
836             if (dictionaryReader == null)
837             {
838                 array = null;
839                 return false;
840             }
841
842             if (arrayLength != -1)
843             {
844                 CheckExpectedArrayLength(context, arrayLength);
845                 array = new DateTime[arrayLength];
846                 int read, offset = 0;
847                 while ((read = dictionaryReader.ReadArray(itemName, itemNamespace, array, offset, arrayLength - offset)) > 0)
848                 {
849                     offset += read;
850                 }
851                 CheckActualArrayLength(arrayLength, offset, itemName, itemNamespace);
852             }
853             else
854             {
855                 array = DateTimeArrayHelperWithDictionaryString.Instance.ReadArray(
856                     dictionaryReader, itemName, itemNamespace, GetArrayLengthQuota(context));
857                 context.IncrementItemCount(array.Length);
858             }
859             return true;
860         }
861
862         internal bool TryReadDecimalArray(XmlObjectSerializerReadContext context,
863             XmlDictionaryString itemName, XmlDictionaryString itemNamespace,
864             int arrayLength, [NotNullWhen(true)] out decimal[]? array)
865         {
866             if (dictionaryReader == null)
867             {
868                 array = null;
869                 return false;
870             }
871
872             if (arrayLength != -1)
873             {
874                 CheckExpectedArrayLength(context, arrayLength);
875                 array = new decimal[arrayLength];
876                 int read, offset = 0;
877                 while ((read = dictionaryReader.ReadArray(itemName, itemNamespace, array, offset, arrayLength - offset)) > 0)
878                 {
879                     offset += read;
880                 }
881                 CheckActualArrayLength(arrayLength, offset, itemName, itemNamespace);
882             }
883             else
884             {
885                 array = DecimalArrayHelperWithDictionaryString.Instance.ReadArray(
886                     dictionaryReader, itemName, itemNamespace, GetArrayLengthQuota(context));
887                 context.IncrementItemCount(array.Length);
888             }
889             return true;
890         }
891
892         internal bool TryReadInt32Array(XmlObjectSerializerReadContext context,
893             XmlDictionaryString itemName, XmlDictionaryString itemNamespace,
894             int arrayLength, [NotNullWhen(true)] out int[]? array)
895         {
896             if (dictionaryReader == null)
897             {
898                 array = null;
899                 return false;
900             }
901
902             if (arrayLength != -1)
903             {
904                 CheckExpectedArrayLength(context, arrayLength);
905                 array = new int[arrayLength];
906                 int read, offset = 0;
907                 while ((read = dictionaryReader.ReadArray(itemName, itemNamespace, array, offset, arrayLength - offset)) > 0)
908                 {
909                     offset += read;
910                 }
911                 CheckActualArrayLength(arrayLength, offset, itemName, itemNamespace);
912             }
913             else
914             {
915                 array = Int32ArrayHelperWithDictionaryString.Instance.ReadArray(
916                     dictionaryReader, itemName, itemNamespace, GetArrayLengthQuota(context));
917                 context.IncrementItemCount(array.Length);
918             }
919             return true;
920         }
921
922         internal bool TryReadInt64Array(XmlObjectSerializerReadContext context,
923             XmlDictionaryString itemName, XmlDictionaryString itemNamespace,
924             int arrayLength, [NotNullWhen(true)] out long[]? array)
925         {
926             if (dictionaryReader == null)
927             {
928                 array = null;
929                 return false;
930             }
931
932             if (arrayLength != -1)
933             {
934                 CheckExpectedArrayLength(context, arrayLength);
935                 array = new long[arrayLength];
936                 int read, offset = 0;
937                 while ((read = dictionaryReader.ReadArray(itemName, itemNamespace, array, offset, arrayLength - offset)) > 0)
938                 {
939                     offset += read;
940                 }
941                 CheckActualArrayLength(arrayLength, offset, itemName, itemNamespace);
942             }
943             else
944             {
945                 array = Int64ArrayHelperWithDictionaryString.Instance.ReadArray(
946                     dictionaryReader, itemName, itemNamespace, GetArrayLengthQuota(context));
947                 context.IncrementItemCount(array.Length);
948             }
949             return true;
950         }
951
952         internal bool TryReadSingleArray(XmlObjectSerializerReadContext context,
953             XmlDictionaryString itemName, XmlDictionaryString itemNamespace,
954             int arrayLength, [NotNullWhen(true)] out float[]? array)
955         {
956             if (dictionaryReader == null)
957             {
958                 array = null;
959                 return false;
960             }
961
962             if (arrayLength != -1)
963             {
964                 CheckExpectedArrayLength(context, arrayLength);
965                 array = new float[arrayLength];
966                 int read, offset = 0;
967                 while ((read = dictionaryReader.ReadArray(itemName, itemNamespace, array, offset, arrayLength - offset)) > 0)
968                 {
969                     offset += read;
970                 }
971                 CheckActualArrayLength(arrayLength, offset, itemName, itemNamespace);
972             }
973             else
974             {
975                 array = SingleArrayHelperWithDictionaryString.Instance.ReadArray(
976                     dictionaryReader, itemName, itemNamespace, GetArrayLengthQuota(context));
977                 context.IncrementItemCount(array.Length);
978             }
979             return true;
980         }
981
982         internal bool TryReadDoubleArray(XmlObjectSerializerReadContext context,
983             XmlDictionaryString itemName, XmlDictionaryString itemNamespace,
984             int arrayLength, [NotNullWhen(true)] out double[]? array)
985         {
986             if (dictionaryReader == null)
987             {
988                 array = null;
989                 return false;
990             }
991
992             if (arrayLength != -1)
993             {
994                 CheckExpectedArrayLength(context, arrayLength);
995                 array = new double[arrayLength];
996                 int read, offset = 0;
997                 while ((read = dictionaryReader.ReadArray(itemName, itemNamespace, array, offset, arrayLength - offset)) > 0)
998                 {
999                     offset += read;
1000                 }
1001                 CheckActualArrayLength(arrayLength, offset, itemName, itemNamespace);
1002             }
1003             else
1004             {
1005                 array = DoubleArrayHelperWithDictionaryString.Instance.ReadArray(
1006                     dictionaryReader, itemName, itemNamespace, GetArrayLengthQuota(context));
1007                 context.IncrementItemCount(array.Length);
1008             }
1009             return true;
1010         }
1011
1012         internal IDictionary<string, string>? GetNamespacesInScope(XmlNamespaceScope scope)
1013         {
1014             return (reader is IXmlNamespaceResolver) ? ((IXmlNamespaceResolver)reader).GetNamespacesInScope(scope) : null;
1015         }
1016
1017         // IXmlLineInfo members
1018         internal bool HasLineInfo()
1019         {
1020             IXmlLineInfo? iXmlLineInfo = reader as IXmlLineInfo;
1021             return (iXmlLineInfo == null) ? false : iXmlLineInfo.HasLineInfo();
1022         }
1023
1024         internal int LineNumber
1025         {
1026             get
1027             {
1028                 IXmlLineInfo? iXmlLineInfo = reader as IXmlLineInfo;
1029                 return (iXmlLineInfo == null) ? 0 : iXmlLineInfo.LineNumber;
1030             }
1031         }
1032
1033         internal int LinePosition
1034         {
1035             get
1036             {
1037                 IXmlLineInfo? iXmlLineInfo = reader as IXmlLineInfo;
1038                 return (iXmlLineInfo == null) ? 0 : iXmlLineInfo.LinePosition;
1039             }
1040         }
1041
1042         // IXmlTextParser members
1043         internal bool Normalized
1044         {
1045             get
1046             {
1047                 if (reader is not XmlTextReader xmlTextReader)
1048                 {
1049                     IXmlTextParser? xmlTextParser = reader as IXmlTextParser;
1050                     return (xmlTextParser == null) ? false : xmlTextParser.Normalized;
1051                 }
1052                 else
1053                     return xmlTextReader.Normalization;
1054             }
1055             set
1056             {
1057                 if (reader is not XmlTextReader xmlTextReader)
1058                 {
1059                     if (reader is IXmlTextParser xmlTextParser)
1060                         xmlTextParser.Normalized = value;
1061                 }
1062                 else
1063                     xmlTextReader.Normalization = value;
1064             }
1065         }
1066
1067         internal WhitespaceHandling WhitespaceHandling
1068         {
1069             get
1070             {
1071                 if (reader is not XmlTextReader xmlTextReader)
1072                 {
1073                     IXmlTextParser? xmlTextParser = reader as IXmlTextParser;
1074                     return (xmlTextParser == null) ? WhitespaceHandling.None : xmlTextParser.WhitespaceHandling;
1075                 }
1076                 else
1077                     return xmlTextReader.WhitespaceHandling;
1078             }
1079             set
1080             {
1081                 if (reader is not XmlTextReader xmlTextReader)
1082                 {
1083                     if (reader is IXmlTextParser xmlTextParser)
1084                         xmlTextParser.WhitespaceHandling = value;
1085                 }
1086                 else
1087                     xmlTextReader.WhitespaceHandling = value;
1088             }
1089         }
1090
1091         // delegating properties and methods
1092         internal string Name { get { return reader.Name; } }
1093         internal string LocalName { get { return reader.LocalName; } }
1094         internal string NamespaceURI { get { return reader.NamespaceURI; } }
1095         internal string Value { get { return reader.Value; } }
1096         internal Type ValueType { get { return reader.ValueType; } }
1097         internal int Depth { get { return reader.Depth; } }
1098         internal string? LookupNamespace(string prefix) { return reader.LookupNamespace(prefix); }
1099         internal bool EOF { get { return reader.EOF; } }
1100
1101         internal void Skip()
1102         {
1103             reader.Skip();
1104             isEndOfEmptyElement = false;
1105         }
1106     }
1107 }