Merge pull request dotnet/corert#4080 from dotnet/nmirror
[platform/upstream/coreclr.git] / src / mscorlib / shared / System / Text / Encoding.cs
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 // See the LICENSE file in the project root for more information.
4
5 using System.Diagnostics;
6 using System.Diagnostics.Contracts;
7 using System.Threading;
8 using System.Runtime.Serialization;
9 using System.Diagnostics.CodeAnalysis;
10
11 namespace System.Text
12 {
13     // This abstract base class represents a character encoding. The class provides
14     // methods to convert arrays and strings of Unicode characters to and from
15     // arrays of bytes. A number of Encoding implementations are provided in
16     // the System.Text package, including:
17     //
18     // ASCIIEncoding, which encodes Unicode characters as single 7-bit
19     // ASCII characters. This encoding only supports character values between 0x00
20     //     and 0x7F.
21     // BaseCodePageEncoding, which encapsulates a Windows code page. Any
22     //     installed code page can be accessed through this encoding, and conversions
23     //     are performed using the WideCharToMultiByte and
24     //     MultiByteToWideChar Windows API functions.
25     // UnicodeEncoding, which encodes each Unicode character as two
26     //    consecutive bytes. Both little-endian (code page 1200) and big-endian (code
27     //    page 1201) encodings are recognized.
28     // UTF7Encoding, which encodes Unicode characters using the UTF-7
29     //     encoding (UTF-7 stands for UCS Transformation Format, 7-bit form). This
30     //     encoding supports all Unicode character values, and can also be accessed
31     //     as code page 65000.
32     // UTF8Encoding, which encodes Unicode characters using the UTF-8
33     //     encoding (UTF-8 stands for UCS Transformation Format, 8-bit form). This
34     //     encoding supports all Unicode character values, and can also be accessed
35     //     as code page 65001.
36     // UTF32Encoding, both 12000 (little endian) & 12001 (big endian)
37     //
38     // In addition to directly instantiating Encoding objects, an
39     // application can use the ForCodePage, GetASCII,
40     // GetDefault, GetUnicode, GetUTF7, and GetUTF8
41     // methods in this class to obtain encodings.
42     //
43     // Through an encoding, the GetBytes method is used to convert arrays
44     // of characters to arrays of bytes, and the GetChars method is used to
45     // convert arrays of bytes to arrays of characters. The GetBytes and
46     // GetChars methods maintain no state between conversions, and are
47     // generally intended for conversions of complete blocks of bytes and
48     // characters in one operation. When the data to be converted is only available
49     // in sequential blocks (such as data read from a stream) or when the amount of
50     // data is so large that it needs to be divided into smaller blocks, an
51     // application may choose to use a Decoder or an Encoder to
52     // perform the conversion. Decoders and encoders allow sequential blocks of
53     // data to be converted and they maintain the state required to support
54     // conversions of data that spans adjacent blocks. Decoders and encoders are
55     // obtained using the GetDecoder and GetEncoder methods.
56     //
57     // The core GetBytes and GetChars methods require the caller
58     // to provide the destination buffer and ensure that the buffer is large enough
59     // to hold the entire result of the conversion. When using these methods,
60     // either directly on an Encoding object or on an associated
61     // Decoder or Encoder, an application can use one of two methods
62     // to allocate destination buffers.
63     //
64     // The GetByteCount and GetCharCount methods can be used to
65     // compute the exact size of the result of a particular conversion, and an
66     // appropriately sized buffer for that conversion can then be allocated.
67     // The GetMaxByteCount and GetMaxCharCount methods can be
68     // be used to compute the maximum possible size of a conversion of a given
69     // number of bytes or characters, and a buffer of that size can then be reused
70     // for multiple conversions.
71     //
72     // The first method generally uses less memory, whereas the second method
73     // generally executes faster.
74     //
75
76     public abstract class Encoding : ICloneable
77     {
78         // For netcore we use UTF8 as default encoding since ANSI isn't available
79         private static readonly UTF8Encoding.UTF8EncodingSealed s_defaultEncoding  = new UTF8Encoding.UTF8EncodingSealed(encoderShouldEmitUTF8Identifier: false);
80
81         // Returns an encoding for the system's current ANSI code page.
82         public static Encoding Default => s_defaultEncoding;
83
84         //
85         // The following values are from mlang.idl.  These values
86         // should be in sync with those in mlang.idl.
87         //
88         internal const int MIMECONTF_MAILNEWS = 0x00000001;
89         internal const int MIMECONTF_BROWSER = 0x00000002;
90         internal const int MIMECONTF_SAVABLE_MAILNEWS = 0x00000100;
91         internal const int MIMECONTF_SAVABLE_BROWSER = 0x00000200;
92
93         // Special Case Code Pages
94         private const int CodePageDefault = 0;
95         private const int CodePageNoOEM = 1;        // OEM Code page not supported
96         private const int CodePageNoMac = 2;        // MAC code page not supported
97         private const int CodePageNoThread = 3;        // Thread code page not supported
98         private const int CodePageNoSymbol = 42;       // Symbol code page not supported
99         private const int CodePageUnicode = 1200;     // Unicode
100         private const int CodePageBigEndian = 1201;     // Big Endian Unicode
101         private const int CodePageWindows1252 = 1252;     // Windows 1252 code page
102
103         // 20936 has same code page as 10008, so we'll special case it
104         private const int CodePageMacGB2312 = 10008;
105         private const int CodePageGB2312 = 20936;
106         private const int CodePageMacKorean = 10003;
107         private const int CodePageDLLKorean = 20949;
108
109         // ISO 2022 Code Pages
110         private const int ISO2022JP = 50220;
111         private const int ISO2022JPESC = 50221;
112         private const int ISO2022JPSISO = 50222;
113         private const int ISOKorean = 50225;
114         private const int ISOSimplifiedCN = 50227;
115         private const int EUCJP = 51932;
116         private const int ChineseHZ = 52936;    // HZ has ~}~{~~ sequences
117
118         // 51936 is the same as 936
119         private const int DuplicateEUCCN = 51936;
120         private const int EUCCN = 936;
121
122         private const int EUCKR = 51949;
123
124         // Latin 1 & ASCII Code Pages
125         internal const int CodePageASCII = 20127;    // ASCII
126         internal const int ISO_8859_1 = 28591;    // Latin1
127
128         // ISCII
129         private const int ISCIIAssemese = 57006;
130         private const int ISCIIBengali = 57003;
131         private const int ISCIIDevanagari = 57002;
132         private const int ISCIIGujarathi = 57010;
133         private const int ISCIIKannada = 57008;
134         private const int ISCIIMalayalam = 57009;
135         private const int ISCIIOriya = 57007;
136         private const int ISCIIPanjabi = 57011;
137         private const int ISCIITamil = 57004;
138         private const int ISCIITelugu = 57005;
139
140         // GB18030
141         private const int GB18030 = 54936;
142
143         // Other
144         private const int ISO_8859_8I = 38598;
145         private const int ISO_8859_8_Visual = 28598;
146
147         // 50229 is currently unsupported // "Chinese Traditional (ISO-2022)"
148         private const int ENC50229 = 50229;
149
150         // Special code pages
151         private const int CodePageUTF7 = 65000;
152         private const int CodePageUTF8 = 65001;
153         private const int CodePageUTF32 = 12000;
154         private const int CodePageUTF32BE = 12001;
155
156         internal int m_codePage = 0;
157
158         // dataItem should be internal (not private). otherwise it will break during the deserialization
159         // of the data came from Everett
160         internal CodePageDataItem dataItem = null;
161
162         [NonSerialized]
163         internal bool m_deserializedFromEverett = false;
164
165         // Because of encoders we may be read only
166         [OptionalField(VersionAdded = 2)]
167         private bool m_isReadOnly = true;
168
169         // Encoding (encoder) fallback
170         [OptionalField(VersionAdded = 2)]
171         internal EncoderFallback encoderFallback = null;
172         [OptionalField(VersionAdded = 2)]
173         internal DecoderFallback decoderFallback = null;
174
175         protected Encoding() : this(0)
176         {
177         }
178
179
180         protected Encoding(int codePage)
181         {
182             // Validate code page
183             if (codePage < 0)
184             {
185                 throw new ArgumentOutOfRangeException(nameof(codePage));
186             }
187             Contract.EndContractBlock();
188
189             // Remember code page
190             m_codePage = codePage;
191
192             // Use default encoder/decoder fallbacks
193             this.SetDefaultFallbacks();
194         }
195
196         // This constructor is needed to allow any sub-classing implementation to provide encoder/decoder fallback objects 
197         // because the encoding object is always created as read-only object and don't allow setting encoder/decoder fallback 
198         // after the creation is done. 
199         protected Encoding(int codePage, EncoderFallback encoderFallback, DecoderFallback decoderFallback)
200         {
201             // Validate code page
202             if (codePage < 0)
203             {
204                 throw new ArgumentOutOfRangeException(nameof(codePage));
205             }
206             Contract.EndContractBlock();
207
208             // Remember code page
209             m_codePage = codePage;
210
211             this.encoderFallback = encoderFallback ?? new InternalEncoderBestFitFallback(this);
212             this.decoderFallback = decoderFallback ?? new InternalDecoderBestFitFallback(this);
213         }
214
215         // Default fallback that we'll use.
216         internal virtual void SetDefaultFallbacks()
217         {
218             // For UTF-X encodings, we use a replacement fallback with an "\xFFFD" string,
219             // For ASCII we use "?" replacement fallback, etc.
220             this.encoderFallback = new InternalEncoderBestFitFallback(this);
221             this.decoderFallback = new InternalDecoderBestFitFallback(this);
222         }
223
224
225         #region Serialization
226         internal void OnDeserializing()
227         {
228             // intialize the optional Whidbey fields
229             encoderFallback = null;
230             decoderFallback = null;
231             m_isReadOnly = true;
232         }
233
234         internal void OnDeserialized()
235         {
236             if (encoderFallback == null || decoderFallback == null)
237             {
238                 m_deserializedFromEverett = true;
239                 SetDefaultFallbacks();
240             }
241
242             // dataItem is always recalculated from the code page #
243             dataItem = null;
244         }
245
246         [OnDeserializing]
247         private void OnDeserializing(StreamingContext ctx)
248         {
249             OnDeserializing();
250         }
251
252
253         [OnDeserialized]
254         private void OnDeserialized(StreamingContext ctx)
255         {
256             OnDeserialized();
257         }
258
259         [OnSerializing]
260         private void OnSerializing(StreamingContext ctx)
261         {
262             // to be consistent with SerializeEncoding
263             dataItem = null;
264         }
265
266         // the following two methods are used for the inherited classes which implemented ISerializable
267         // Deserialization Helper
268         internal void DeserializeEncoding(SerializationInfo info, StreamingContext context)
269         {
270             // Any info?
271             if (info == null) throw new ArgumentNullException(nameof(info));
272             Contract.EndContractBlock();
273
274             // All versions have a code page
275             this.m_codePage = (int)info.GetValue("m_codePage", typeof(int));
276
277             // We can get dataItem on the fly if needed, and the index is different between versions
278             // so ignore whatever dataItem data we get from Everett.
279             this.dataItem = null;
280
281             // See if we have a code page
282             try
283             {
284                 //
285                 // Try Whidbey V2.0 Fields
286                 //
287
288                 m_isReadOnly = (bool)info.GetValue("m_isReadOnly", typeof(bool));
289
290                 this.encoderFallback = (EncoderFallback)info.GetValue("encoderFallback", typeof(EncoderFallback));
291                 this.decoderFallback = (DecoderFallback)info.GetValue("decoderFallback", typeof(DecoderFallback));
292             }
293             catch (SerializationException)
294             {
295                 //
296                 // Didn't have Whidbey things, must be Everett
297                 //
298                 this.m_deserializedFromEverett = true;
299
300                 // May as well be read only
301                 m_isReadOnly = true;
302                 SetDefaultFallbacks();
303             }
304         }
305
306         // Serialization Helper
307         internal void SerializeEncoding(SerializationInfo info, StreamingContext context)
308         {
309             // Any Info?
310             if (info == null) throw new ArgumentNullException(nameof(info));
311             Contract.EndContractBlock();
312
313             // These are new V2.0 Whidbey stuff
314             info.AddValue("m_isReadOnly", m_isReadOnly);
315             info.AddValue("encoderFallback", this.EncoderFallback);
316             info.AddValue("decoderFallback", this.DecoderFallback);
317
318             // These were in Everett V1.1 as well
319             info.AddValue("m_codePage", this.m_codePage);
320
321             // This was unique to Everett V1.1
322             info.AddValue("dataItem", null);
323
324             // Everett duplicated these fields, so these are needed for portability
325             info.AddValue("Encoding+m_codePage", this.m_codePage);
326             info.AddValue("Encoding+dataItem", null);
327         }
328
329         #endregion Serialization
330
331         // Converts a byte array from one encoding to another. The bytes in the
332         // bytes array are converted from srcEncoding to
333         // dstEncoding, and the returned value is a new byte array
334         // containing the result of the conversion.
335         //
336         [Pure]
337         public static byte[] Convert(Encoding srcEncoding, Encoding dstEncoding,
338             byte[] bytes)
339         {
340             if (bytes == null)
341                 throw new ArgumentNullException(nameof(bytes));
342             Contract.Ensures(Contract.Result<byte[]>() != null);
343
344             return Convert(srcEncoding, dstEncoding, bytes, 0, bytes.Length);
345         }
346
347         // Converts a range of bytes in a byte array from one encoding to another.
348         // This method converts count bytes from bytes starting at
349         // index index from srcEncoding to dstEncoding, and
350         // returns a new byte array containing the result of the conversion.
351         //
352         [Pure]
353         public static byte[] Convert(Encoding srcEncoding, Encoding dstEncoding,
354             byte[] bytes, int index, int count)
355         {
356             if (srcEncoding == null || dstEncoding == null)
357             {
358                 throw new ArgumentNullException((srcEncoding == null ? nameof(srcEncoding) : nameof(dstEncoding)),
359                     SR.ArgumentNull_Array);
360             }
361             if (bytes == null)
362             {
363                 throw new ArgumentNullException(nameof(bytes),
364                     SR.ArgumentNull_Array);
365             }
366             Contract.Ensures(Contract.Result<byte[]>() != null);
367
368             return dstEncoding.GetBytes(srcEncoding.GetChars(bytes, index, count));
369         }
370
371         public static void RegisterProvider(EncodingProvider provider)
372         {
373             // Parameters validated inside EncodingProvider
374             EncodingProvider.AddProvider(provider);
375         }
376
377         [Pure]
378         public static Encoding GetEncoding(int codepage)
379         {
380             Encoding result = EncodingProvider.GetEncodingFromProvider(codepage);
381             if (result != null)
382                 return result;
383
384             //
385             // NOTE: If you add a new encoding that can be retrieved by codepage, be sure to
386             // add the corresponding item in EncodingTable.
387             // Otherwise, the code below will throw exception when trying to call
388             // EncodingTable.GetDataItem().
389             //
390             if (codepage < 0 || codepage > 65535)
391             {
392                 throw new ArgumentOutOfRangeException(
393                     nameof(codepage), SR.Format(SR.ArgumentOutOfRange_Range, 0, 65535));
394             }
395
396             Contract.EndContractBlock();
397
398             switch (codepage)
399             {
400                 case CodePageDefault: return Default;            // 0
401                 case CodePageUnicode: return Unicode;            // 1200
402                 case CodePageBigEndian: return BigEndianUnicode; // 1201
403                 case CodePageUTF32: return UTF32;                // 12000
404                 case CodePageUTF32BE: return BigEndianUTF32;     // 12001
405                 case CodePageUTF7: return UTF7;                  // 65000
406                 case CodePageUTF8: return UTF8;                  // 65001
407                 case CodePageASCII: return ASCII;                // 20127
408                 case ISO_8859_1: return Latin1;                  // 28591
409
410                 // We don't allow the following special code page values that Win32 allows.
411                 case CodePageNoOEM:                              // 1 CP_OEMCP
412                 case CodePageNoMac:                              // 2 CP_MACCP
413                 case CodePageNoThread:                           // 3 CP_THREAD_ACP
414                 case CodePageNoSymbol:                           // 42 CP_SYMBOL
415                     throw new ArgumentException(SR.Format(SR.Argument_CodepageNotSupported, codepage), nameof(codepage));
416             }
417
418             // Is it a valid code page?
419             if (EncodingTable.GetCodePageDataItem(codepage) == null)
420             {
421                 throw new NotSupportedException(
422                     SR.Format(SR.NotSupported_NoCodepageData, codepage));
423             }
424
425             return UTF8;
426         }
427
428         [Pure]
429         public static Encoding GetEncoding(int codepage,
430             EncoderFallback encoderFallback, DecoderFallback decoderFallback)
431         {
432             Encoding baseEncoding = EncodingProvider.GetEncodingFromProvider(codepage, encoderFallback, decoderFallback);
433
434             if (baseEncoding != null)
435                 return baseEncoding;
436
437             // Get the default encoding (which is cached and read only)
438             baseEncoding = GetEncoding(codepage);
439
440             // Clone it and set the fallback
441             Encoding fallbackEncoding = (Encoding)baseEncoding.Clone();
442             fallbackEncoding.EncoderFallback = encoderFallback;
443             fallbackEncoding.DecoderFallback = decoderFallback;
444
445             return fallbackEncoding;
446         }
447
448         // Returns an Encoding object for a given name or a given code page value.
449         //
450         [Pure]
451         public static Encoding GetEncoding(String name)
452         {
453             Encoding baseEncoding = EncodingProvider.GetEncodingFromProvider(name);
454             if (baseEncoding != null)
455                 return baseEncoding;
456
457             //
458             // NOTE: If you add a new encoding that can be requested by name, be sure to
459             // add the corresponding item in EncodingTable.
460             // Otherwise, the code below will throw exception when trying to call
461             // EncodingTable.GetCodePageFromName().
462             //
463             return GetEncoding(EncodingTable.GetCodePageFromName(name));
464         }
465
466         // Returns an Encoding object for a given name or a given code page value.
467         //
468         [Pure]
469         public static Encoding GetEncoding(String name,
470             EncoderFallback encoderFallback, DecoderFallback decoderFallback)
471         {
472             Encoding baseEncoding = EncodingProvider.GetEncodingFromProvider(name, encoderFallback, decoderFallback);
473             if (baseEncoding != null)
474                 return baseEncoding;
475
476             //
477             // NOTE: If you add a new encoding that can be requested by name, be sure to
478             // add the corresponding item in EncodingTable.
479             // Otherwise, the code below will throw exception when trying to call
480             // EncodingTable.GetCodePageFromName().
481             //
482             return (GetEncoding(EncodingTable.GetCodePageFromName(name), encoderFallback, decoderFallback));
483         }
484
485         // Return a list of all EncodingInfo objects describing all of our encodings
486         [Pure]
487         public static EncodingInfo[] GetEncodings()
488         {
489             return EncodingTable.GetEncodings();
490         }
491
492         [Pure]
493         public virtual byte[] GetPreamble()
494         {
495             return Array.Empty<byte>();
496         }
497
498         private void GetDataItem()
499         {
500             if (dataItem == null)
501             {
502                 dataItem = EncodingTable.GetCodePageDataItem(m_codePage);
503                 if (dataItem == null)
504                 {
505                     throw new NotSupportedException(
506                         SR.Format(SR.NotSupported_NoCodepageData, m_codePage));
507                 }
508             }
509         }
510
511         // Returns the name for this encoding that can be used with mail agent body tags.
512         // If the encoding may not be used, the string is empty.
513
514         public virtual String BodyName
515         {
516             get
517             {
518                 if (dataItem == null)
519                 {
520                     GetDataItem();
521                 }
522                 return (dataItem.BodyName);
523             }
524         }
525
526         // Returns the human-readable description of the encoding ( e.g. Hebrew (DOS)).
527 #if PROJECTN
528         public virtual String EncodingName
529         {
530             get
531             {
532                 string encodingName = GetLocalizedEncodingNameResource(this.CodePage);
533                 if (encodingName == null)
534                 {
535                     throw new NotSupportedException(SR.Format(SR.MissingEncodingNameResource, this.CodePage));
536                 }
537
538                 if (encodingName.StartsWith("Globalization_cp_", StringComparison.Ordinal))
539                 {
540                     // On ProjectN, resource strings are stripped from retail builds and replaced by
541                     // their identifier names. Since this property is meant to be a localized string,
542                     // but we don't localize ProjectN, we specifically need to do something reasonable
543                     // in this case. This currently returns the English name of the encoding from a
544                     // static data table.
545                     encodingName = EncodingTable.GetCodePageDataItem(this.CodePage).EnglishName;
546                     if (encodingName == null)
547                     {
548                         throw new NotSupportedException(SR.Format(SR.MissingEncodingNameResource, this.WebName, this.CodePage));
549                     }
550                 }
551                 return encodingName;
552             }
553         }
554
555         private static string GetLocalizedEncodingNameResource(int codePage)
556         {
557             switch (codePage)
558             {
559                 case 1200: return SR.Globalization_cp_1200;
560                 case 1201: return SR.Globalization_cp_1201;
561                 case 12000: return SR.Globalization_cp_12000;
562                 case 12001: return SR.Globalization_cp_12001;
563                 case 20127: return SR.Globalization_cp_20127;
564                 case 28591: return SR.Globalization_cp_28591;
565                 case 65000: return SR.Globalization_cp_65000;
566                 case 65001: return SR.Globalization_cp_65001;
567                 default: return null;
568             }
569         }
570 #else
571         public virtual String EncodingName
572         {
573             get
574             {
575                 return SR.GetResourceString("Globalization_cp_" + m_codePage.ToString());
576             }
577         }
578 #endif
579         // Returns the name for this encoding that can be used with mail agent header
580         // tags.  If the encoding may not be used, the string is empty.
581
582         public virtual String HeaderName
583         {
584             get
585             {
586                 if (dataItem == null)
587                 {
588                     GetDataItem();
589                 }
590                 return (dataItem.HeaderName);
591             }
592         }
593
594         // Returns the IANA preferred name for this encoding.
595         public virtual String WebName
596         {
597             get
598             {
599                 if (dataItem == null)
600                 {
601                     GetDataItem();
602                 }
603                 return (dataItem.WebName);
604             }
605         }
606
607         // Returns the windows code page that most closely corresponds to this encoding.
608
609         public virtual int WindowsCodePage
610         {
611             get
612             {
613                 if (dataItem == null)
614                 {
615                     GetDataItem();
616                 }
617                 return (dataItem.UIFamilyCodePage);
618             }
619         }
620
621
622         // True if and only if the encoding is used for display by browsers clients.
623
624         public virtual bool IsBrowserDisplay
625         {
626             get
627             {
628                 if (dataItem == null)
629                 {
630                     GetDataItem();
631                 }
632                 return ((dataItem.Flags & MIMECONTF_BROWSER) != 0);
633             }
634         }
635
636         // True if and only if the encoding is used for saving by browsers clients.
637
638         public virtual bool IsBrowserSave
639         {
640             get
641             {
642                 if (dataItem == null)
643                 {
644                     GetDataItem();
645                 }
646                 return ((dataItem.Flags & MIMECONTF_SAVABLE_BROWSER) != 0);
647             }
648         }
649
650         // True if and only if the encoding is used for display by mail and news clients.
651
652         public virtual bool IsMailNewsDisplay
653         {
654             get
655             {
656                 if (dataItem == null)
657                 {
658                     GetDataItem();
659                 }
660                 return ((dataItem.Flags & MIMECONTF_MAILNEWS) != 0);
661             }
662         }
663
664
665         // True if and only if the encoding is used for saving documents by mail and
666         // news clients
667
668         public virtual bool IsMailNewsSave
669         {
670             get
671             {
672                 if (dataItem == null)
673                 {
674                     GetDataItem();
675                 }
676                 return ((dataItem.Flags & MIMECONTF_SAVABLE_MAILNEWS) != 0);
677             }
678         }
679
680         // True if and only if the encoding only uses single byte code points.  (Ie, ASCII, 1252, etc)
681
682         public virtual bool IsSingleByte
683         {
684             get
685             {
686                 return false;
687             }
688         }
689
690
691         public EncoderFallback EncoderFallback
692         {
693             get
694             {
695                 return encoderFallback;
696             }
697
698             set
699             {
700                 if (this.IsReadOnly)
701                     throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
702
703                 if (value == null)
704                     throw new ArgumentNullException(nameof(value));
705                 Contract.EndContractBlock();
706
707                 encoderFallback = value;
708             }
709         }
710
711
712         public DecoderFallback DecoderFallback
713         {
714             get
715             {
716                 return decoderFallback;
717             }
718
719             set
720             {
721                 if (this.IsReadOnly)
722                     throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
723
724                 if (value == null)
725                     throw new ArgumentNullException(nameof(value));
726                 Contract.EndContractBlock();
727
728                 decoderFallback = value;
729             }
730         }
731
732
733         public virtual Object Clone()
734         {
735             Encoding newEncoding = (Encoding)this.MemberwiseClone();
736
737             // New one should be readable
738             newEncoding.m_isReadOnly = false;
739             return newEncoding;
740         }
741
742
743         public bool IsReadOnly
744         {
745             get
746             {
747                 return (m_isReadOnly);
748             }
749         }
750
751         // Returns an encoding for the ASCII character set. The returned encoding
752         // will be an instance of the ASCIIEncoding class.
753
754         public static Encoding ASCII => ASCIIEncoding.s_default;
755
756         // Returns an encoding for the Latin1 character set. The returned encoding
757         // will be an instance of the Latin1Encoding class.
758         //
759         // This is for our optimizations
760         private static Encoding Latin1 => Latin1Encoding.s_default;
761
762         // Returns the number of bytes required to encode the given character
763         // array.
764         //
765         [Pure]
766         public virtual int GetByteCount(char[] chars)
767         {
768             if (chars == null)
769             {
770                 throw new ArgumentNullException(nameof(chars),
771                     SR.ArgumentNull_Array);
772             }
773             Contract.EndContractBlock();
774
775             return GetByteCount(chars, 0, chars.Length);
776         }
777
778         [Pure]
779         public virtual int GetByteCount(String s)
780         {
781             if (s == null)
782                 throw new ArgumentNullException(nameof(s));
783             Contract.EndContractBlock();
784
785             char[] chars = s.ToCharArray();
786             return GetByteCount(chars, 0, chars.Length);
787         }
788
789         // Returns the number of bytes required to encode a range of characters in
790         // a character array.
791         //
792         [Pure]
793         public abstract int GetByteCount(char[] chars, int index, int count);
794
795         // Returns the number of bytes required to encode a string range.
796         //
797         [Pure]
798         public int GetByteCount(string s, int index, int count)
799         {
800             if (s == null)
801                 throw new ArgumentNullException(nameof(s),
802                     SR.ArgumentNull_String);
803             if (index < 0)
804                 throw new ArgumentOutOfRangeException(nameof(index),
805                       SR.ArgumentOutOfRange_NeedNonNegNum);
806             if (count < 0)
807                 throw new ArgumentOutOfRangeException(nameof(count),
808                       SR.ArgumentOutOfRange_NeedNonNegNum);
809             if (index > s.Length - count)
810                 throw new ArgumentOutOfRangeException(nameof(index),
811                       SR.ArgumentOutOfRange_IndexCount);
812             Contract.EndContractBlock();
813
814             unsafe
815             {
816                 fixed (char* pChar = s)
817                 {
818                     return GetByteCount(pChar + index, count);
819                 }
820             }
821         }
822
823         // We expect this to be the workhorse for NLS encodings
824         // unfortunately for existing overrides, it has to call the [] version,
825         // which is really slow, so this method should be avoided if you're calling
826         // a 3rd party encoding.
827         [Pure]
828         [CLSCompliant(false)]
829         public virtual unsafe int GetByteCount(char* chars, int count)
830         {
831             // Validate input parameters
832             if (chars == null)
833                 throw new ArgumentNullException(nameof(chars),
834                       SR.ArgumentNull_Array);
835
836             if (count < 0)
837                 throw new ArgumentOutOfRangeException(nameof(count),
838                       SR.ArgumentOutOfRange_NeedNonNegNum);
839             Contract.EndContractBlock();
840
841             char[] arrChar = new char[count];
842             int index;
843
844             for (index = 0; index < count; index++)
845                 arrChar[index] = chars[index];
846
847             return GetByteCount(arrChar, 0, count);
848         }
849
850         // For NLS Encodings, workhorse takes an encoder (may be null)
851         // Always validate parameters before calling internal version, which will only assert.
852         internal virtual unsafe int GetByteCount(char* chars, int count, EncoderNLS encoder)
853         {
854             Debug.Assert(chars != null);
855             Debug.Assert(count >= 0);
856
857             return GetByteCount(chars, count);
858         }
859
860         // Returns a byte array containing the encoded representation of the given
861         // character array.
862         //
863         [Pure]
864         public virtual byte[] GetBytes(char[] chars)
865         {
866             if (chars == null)
867             {
868                 throw new ArgumentNullException(nameof(chars),
869                     SR.ArgumentNull_Array);
870             }
871             Contract.EndContractBlock();
872             return GetBytes(chars, 0, chars.Length);
873         }
874
875         // Returns a byte array containing the encoded representation of a range
876         // of characters in a character array.
877         //
878         [Pure]
879         public virtual byte[] GetBytes(char[] chars, int index, int count)
880         {
881             byte[] result = new byte[GetByteCount(chars, index, count)];
882             GetBytes(chars, index, count, result, 0);
883             return result;
884         }
885
886         // Encodes a range of characters in a character array into a range of bytes
887         // in a byte array. An exception occurs if the byte array is not large
888         // enough to hold the complete encoding of the characters. The
889         // GetByteCount method can be used to determine the exact number of
890         // bytes that will be produced for a given range of characters.
891         // Alternatively, the GetMaxByteCount method can be used to
892         // determine the maximum number of bytes that will be produced for a given
893         // number of characters, regardless of the actual character values.
894         //
895         public abstract int GetBytes(char[] chars, int charIndex, int charCount,
896             byte[] bytes, int byteIndex);
897
898         // Returns a byte array containing the encoded representation of the given
899         // string.
900         //
901         [Pure]
902         public virtual byte[] GetBytes(String s)
903         {
904             if (s == null)
905                 throw new ArgumentNullException(nameof(s),
906                     SR.ArgumentNull_String);
907             Contract.EndContractBlock();
908
909             int byteCount = GetByteCount(s);
910             byte[] bytes = new byte[byteCount];
911             int bytesReceived = GetBytes(s, 0, s.Length, bytes, 0);
912             Debug.Assert(byteCount == bytesReceived);
913             return bytes;
914         }
915
916         // Returns a byte array containing the encoded representation of the given
917         // string range.
918         //
919         [Pure]
920         public byte[] GetBytes(string s, int index, int count)
921         {
922             if (s == null)
923                 throw new ArgumentNullException(nameof(s),
924                     SR.ArgumentNull_String);
925             if (index < 0)
926                 throw new ArgumentOutOfRangeException(nameof(index),
927                       SR.ArgumentOutOfRange_NeedNonNegNum);
928             if (count < 0)
929                 throw new ArgumentOutOfRangeException(nameof(count),
930                       SR.ArgumentOutOfRange_NeedNonNegNum);
931             if (index > s.Length - count)
932                 throw new ArgumentOutOfRangeException(nameof(index),
933                       SR.ArgumentOutOfRange_IndexCount);
934             Contract.EndContractBlock();
935
936             unsafe
937             {
938                 fixed (char* pChar = s)
939                 {
940                     int byteCount = GetByteCount(pChar + index, count);
941                     if (byteCount == 0)
942                         return Array.Empty<byte>();
943
944                     byte[] bytes = new byte[byteCount];
945                     fixed (byte* pBytes = &bytes[0])
946                     {
947                         int bytesReceived = GetBytes(pChar + index, count, pBytes, byteCount);
948                         Debug.Assert(byteCount == bytesReceived);
949                     }
950                     return bytes;
951                 }
952             }
953         }
954
955         public virtual int GetBytes(String s, int charIndex, int charCount,
956                                        byte[] bytes, int byteIndex)
957         {
958             if (s == null)
959                 throw new ArgumentNullException(nameof(s));
960             Contract.EndContractBlock();
961             return GetBytes(s.ToCharArray(), charIndex, charCount, bytes, byteIndex);
962         }
963
964         // This is our internal workhorse
965         // Always validate parameters before calling internal version, which will only assert.
966         internal virtual unsafe int GetBytes(char* chars, int charCount,
967                                                 byte* bytes, int byteCount, EncoderNLS encoder)
968         {
969             return GetBytes(chars, charCount, bytes, byteCount);
970         }
971
972         // We expect this to be the workhorse for NLS Encodings, but for existing
973         // ones we need a working (if slow) default implementation)
974         //
975         // WARNING WARNING WARNING
976         //
977         // WARNING: If this breaks it could be a security threat.  Obviously we
978         // call this internally, so you need to make sure that your pointers, counts
979         // and indexes are correct when you call this method.
980         //
981         // In addition, we have internal code, which will be marked as "safe" calling
982         // this code.  However this code is dependent upon the implementation of an
983         // external GetBytes() method, which could be overridden by a third party and
984         // the results of which cannot be guaranteed.  We use that result to copy
985         // the byte[] to our byte* output buffer.  If the result count was wrong, we
986         // could easily overflow our output buffer.  Therefore we do an extra test
987         // when we copy the buffer so that we don't overflow byteCount either.
988
989         [CLSCompliant(false)]
990         public virtual unsafe int GetBytes(char* chars, int charCount,
991                                               byte* bytes, int byteCount)
992         {
993             // Validate input parameters
994             if (bytes == null || chars == null)
995                 throw new ArgumentNullException(bytes == null ? nameof(bytes) : nameof(chars),
996                     SR.ArgumentNull_Array);
997
998             if (charCount < 0 || byteCount < 0)
999                 throw new ArgumentOutOfRangeException((charCount < 0 ? nameof(charCount) : nameof(byteCount)),
1000                     SR.ArgumentOutOfRange_NeedNonNegNum);
1001             Contract.EndContractBlock();
1002
1003             // Get the char array to convert
1004             char[] arrChar = new char[charCount];
1005
1006             int index;
1007             for (index = 0; index < charCount; index++)
1008                 arrChar[index] = chars[index];
1009
1010             // Get the byte array to fill
1011             byte[] arrByte = new byte[byteCount];
1012
1013             // Do the work
1014             int result = GetBytes(arrChar, 0, charCount, arrByte, 0);
1015
1016             Debug.Assert(result <= byteCount, "[Encoding.GetBytes]Returned more bytes than we have space for");
1017
1018             // Copy the byte array
1019             // WARNING: We MUST make sure that we don't copy too many bytes.  We can't
1020             // rely on result because it could be a 3rd party implementation.  We need
1021             // to make sure we never copy more than byteCount bytes no matter the value
1022             // of result
1023             if (result < byteCount)
1024                 byteCount = result;
1025
1026             // Copy the data, don't overrun our array!
1027             for (index = 0; index < byteCount; index++)
1028                 bytes[index] = arrByte[index];
1029
1030             return byteCount;
1031         }
1032
1033         // Returns the number of characters produced by decoding the given byte
1034         // array.
1035         //
1036         [Pure]
1037         public virtual int GetCharCount(byte[] bytes)
1038         {
1039             if (bytes == null)
1040             {
1041                 throw new ArgumentNullException(nameof(bytes),
1042                     SR.ArgumentNull_Array);
1043             }
1044             Contract.EndContractBlock();
1045             return GetCharCount(bytes, 0, bytes.Length);
1046         }
1047
1048         // Returns the number of characters produced by decoding a range of bytes
1049         // in a byte array.
1050         //
1051         [Pure]
1052         public abstract int GetCharCount(byte[] bytes, int index, int count);
1053
1054         // We expect this to be the workhorse for NLS Encodings, but for existing
1055         // ones we need a working (if slow) default implementation)
1056         [Pure]
1057         [CLSCompliant(false)]
1058         public virtual unsafe int GetCharCount(byte* bytes, int count)
1059         {
1060             // Validate input parameters
1061             if (bytes == null)
1062                 throw new ArgumentNullException(nameof(bytes),
1063                       SR.ArgumentNull_Array);
1064
1065             if (count < 0)
1066                 throw new ArgumentOutOfRangeException(nameof(count),
1067                       SR.ArgumentOutOfRange_NeedNonNegNum);
1068             Contract.EndContractBlock();
1069
1070             byte[] arrbyte = new byte[count];
1071             int index;
1072
1073             for (index = 0; index < count; index++)
1074                 arrbyte[index] = bytes[index];
1075
1076             return GetCharCount(arrbyte, 0, count);
1077         }
1078
1079         // This is our internal workhorse
1080         // Always validate parameters before calling internal version, which will only assert.
1081         internal virtual unsafe int GetCharCount(byte* bytes, int count, DecoderNLS decoder)
1082         {
1083             return GetCharCount(bytes, count);
1084         }
1085
1086         // Returns a character array containing the decoded representation of a
1087         // given byte array.
1088         //
1089         [Pure]
1090         public virtual char[] GetChars(byte[] bytes)
1091         {
1092             if (bytes == null)
1093             {
1094                 throw new ArgumentNullException(nameof(bytes),
1095                     SR.ArgumentNull_Array);
1096             }
1097             Contract.EndContractBlock();
1098             return GetChars(bytes, 0, bytes.Length);
1099         }
1100
1101         // Returns a character array containing the decoded representation of a
1102         // range of bytes in a byte array.
1103         //
1104         [Pure]
1105         public virtual char[] GetChars(byte[] bytes, int index, int count)
1106         {
1107             char[] result = new char[GetCharCount(bytes, index, count)];
1108             GetChars(bytes, index, count, result, 0);
1109             return result;
1110         }
1111
1112         // Decodes a range of bytes in a byte array into a range of characters in a
1113         // character array. An exception occurs if the character array is not large
1114         // enough to hold the complete decoding of the bytes. The
1115         // GetCharCount method can be used to determine the exact number of
1116         // characters that will be produced for a given range of bytes.
1117         // Alternatively, the GetMaxCharCount method can be used to
1118         // determine the maximum number of characterss that will be produced for a
1119         // given number of bytes, regardless of the actual byte values.
1120         //
1121
1122         public abstract int GetChars(byte[] bytes, int byteIndex, int byteCount,
1123                                        char[] chars, int charIndex);
1124
1125
1126         // We expect this to be the workhorse for NLS Encodings, but for existing
1127         // ones we need a working (if slow) default implementation)
1128         //
1129         // WARNING WARNING WARNING
1130         //
1131         // WARNING: If this breaks it could be a security threat.  Obviously we
1132         // call this internally, so you need to make sure that your pointers, counts
1133         // and indexes are correct when you call this method.
1134         //
1135         // In addition, we have internal code, which will be marked as "safe" calling
1136         // this code.  However this code is dependent upon the implementation of an
1137         // external GetChars() method, which could be overridden by a third party and
1138         // the results of which cannot be guaranteed.  We use that result to copy
1139         // the char[] to our char* output buffer.  If the result count was wrong, we
1140         // could easily overflow our output buffer.  Therefore we do an extra test
1141         // when we copy the buffer so that we don't overflow charCount either.
1142
1143         [CLSCompliant(false)]
1144         public virtual unsafe int GetChars(byte* bytes, int byteCount,
1145                                               char* chars, int charCount)
1146         {
1147             // Validate input parameters
1148             if (chars == null || bytes == null)
1149                 throw new ArgumentNullException(chars == null ? nameof(chars) : nameof(bytes),
1150                     SR.ArgumentNull_Array);
1151
1152             if (byteCount < 0 || charCount < 0)
1153                 throw new ArgumentOutOfRangeException((byteCount < 0 ? nameof(byteCount) : nameof(charCount)),
1154                     SR.ArgumentOutOfRange_NeedNonNegNum);
1155             Contract.EndContractBlock();
1156
1157             // Get the byte array to convert
1158             byte[] arrByte = new byte[byteCount];
1159
1160             int index;
1161             for (index = 0; index < byteCount; index++)
1162                 arrByte[index] = bytes[index];
1163
1164             // Get the char array to fill
1165             char[] arrChar = new char[charCount];
1166
1167             // Do the work
1168             int result = GetChars(arrByte, 0, byteCount, arrChar, 0);
1169
1170             Debug.Assert(result <= charCount, "[Encoding.GetChars]Returned more chars than we have space for");
1171
1172             // Copy the char array
1173             // WARNING: We MUST make sure that we don't copy too many chars.  We can't
1174             // rely on result because it could be a 3rd party implementation.  We need
1175             // to make sure we never copy more than charCount chars no matter the value
1176             // of result
1177             if (result < charCount)
1178                 charCount = result;
1179
1180             // Copy the data, don't overrun our array!
1181             for (index = 0; index < charCount; index++)
1182                 chars[index] = arrChar[index];
1183
1184             return charCount;
1185         }
1186
1187
1188         // This is our internal workhorse
1189         // Always validate parameters before calling internal version, which will only assert.
1190         internal virtual unsafe int GetChars(byte* bytes, int byteCount,
1191                                                 char* chars, int charCount, DecoderNLS decoder)
1192         {
1193             return GetChars(bytes, byteCount, chars, charCount);
1194         }
1195
1196
1197         [CLSCompliant(false)]
1198         public unsafe string GetString(byte* bytes, int byteCount)
1199         {
1200             if (bytes == null)
1201                 throw new ArgumentNullException(nameof(bytes), SR.ArgumentNull_Array);
1202
1203             if (byteCount < 0)
1204                 throw new ArgumentOutOfRangeException(nameof(byteCount), SR.ArgumentOutOfRange_NeedNonNegNum);
1205             Contract.EndContractBlock();
1206
1207             return String.CreateStringFromEncoding(bytes, byteCount, this);
1208         }
1209
1210         // Returns the code page identifier of this encoding. The returned value is
1211         // an integer between 0 and 65535 if the encoding has a code page
1212         // identifier, or -1 if the encoding does not represent a code page.
1213         //
1214
1215         public virtual int CodePage
1216         {
1217             get
1218             {
1219                 return m_codePage;
1220             }
1221         }
1222
1223         // IsAlwaysNormalized
1224         // Returns true if the encoding is always normalized for the specified encoding form
1225         [Pure]
1226         public bool IsAlwaysNormalized()
1227         {
1228             return this.IsAlwaysNormalized(NormalizationForm.FormC);
1229         }
1230
1231         [Pure]
1232         public virtual bool IsAlwaysNormalized(NormalizationForm form)
1233         {
1234             // Assume false unless the encoding knows otherwise
1235             return false;
1236         }
1237
1238         // Returns a Decoder object for this encoding. The returned object
1239         // can be used to decode a sequence of bytes into a sequence of characters.
1240         // Contrary to the GetChars family of methods, a Decoder can
1241         // convert partial sequences of bytes into partial sequences of characters
1242         // by maintaining the appropriate state between the conversions.
1243         //
1244         // This default implementation returns a Decoder that simply
1245         // forwards calls to the GetCharCount and GetChars methods to
1246         // the corresponding methods of this encoding. Encodings that require state
1247         // to be maintained between successive conversions should override this
1248         // method and return an instance of an appropriate Decoder
1249         // implementation.
1250         //
1251
1252         public virtual Decoder GetDecoder()
1253         {
1254             return new DefaultDecoder(this);
1255         }
1256
1257         // Returns an Encoder object for this encoding. The returned object
1258         // can be used to encode a sequence of characters into a sequence of bytes.
1259         // Contrary to the GetBytes family of methods, an Encoder can
1260         // convert partial sequences of characters into partial sequences of bytes
1261         // by maintaining the appropriate state between the conversions.
1262         //
1263         // This default implementation returns an Encoder that simply
1264         // forwards calls to the GetByteCount and GetBytes methods to
1265         // the corresponding methods of this encoding. Encodings that require state
1266         // to be maintained between successive conversions should override this
1267         // method and return an instance of an appropriate Encoder
1268         // implementation.
1269         //
1270
1271         public virtual Encoder GetEncoder()
1272         {
1273             return new DefaultEncoder(this);
1274         }
1275
1276         // Returns the maximum number of bytes required to encode a given number of
1277         // characters. This method can be used to determine an appropriate buffer
1278         // size for byte arrays passed to the GetBytes method of this
1279         // encoding or the GetBytes method of an Encoder for this
1280         // encoding. All encodings must guarantee that no buffer overflow
1281         // exceptions will occur if buffers are sized according to the results of
1282         // this method.
1283         //
1284         // WARNING: If you're using something besides the default replacement encoder fallback,
1285         // then you could have more bytes than this returned from an actual call to GetBytes().
1286         //
1287         [Pure]
1288         public abstract int GetMaxByteCount(int charCount);
1289
1290         // Returns the maximum number of characters produced by decoding a given
1291         // number of bytes. This method can be used to determine an appropriate
1292         // buffer size for character arrays passed to the GetChars method of
1293         // this encoding or the GetChars method of a Decoder for this
1294         // encoding. All encodings must guarantee that no buffer overflow
1295         // exceptions will occur if buffers are sized according to the results of
1296         // this method.
1297         //
1298         [Pure]
1299         public abstract int GetMaxCharCount(int byteCount);
1300
1301         // Returns a string containing the decoded representation of a given byte
1302         // array.
1303         //
1304         [Pure]
1305         public virtual String GetString(byte[] bytes)
1306         {
1307             if (bytes == null)
1308                 throw new ArgumentNullException(nameof(bytes),
1309                     SR.ArgumentNull_Array);
1310             Contract.EndContractBlock();
1311
1312             return GetString(bytes, 0, bytes.Length);
1313         }
1314
1315         // Returns a string containing the decoded representation of a range of
1316         // bytes in a byte array.
1317         //
1318         // Internally we override this for performance
1319         //
1320         [Pure]
1321         public virtual String GetString(byte[] bytes, int index, int count)
1322         {
1323             return new String(GetChars(bytes, index, count));
1324         }
1325
1326         // Returns an encoding for Unicode format. The returned encoding will be
1327         // an instance of the UnicodeEncoding class.
1328         //
1329         // It will use little endian byte order, but will detect
1330         // input in big endian if it finds a byte order mark per Unicode 2.0.
1331
1332         public static Encoding Unicode => UnicodeEncoding.s_littleEndianDefault;
1333
1334         // Returns an encoding for Unicode format. The returned encoding will be
1335         // an instance of the UnicodeEncoding class.
1336         //
1337         // It will use big endian byte order, but will detect
1338         // input in little endian if it finds a byte order mark per Unicode 2.0.
1339
1340         public static Encoding BigEndianUnicode => UnicodeEncoding.s_bigEndianDefault;
1341
1342         // Returns an encoding for the UTF-7 format. The returned encoding will be
1343         // an instance of the UTF7Encoding class.
1344
1345         public static Encoding UTF7 => UTF7Encoding.s_default;
1346
1347         // Returns an encoding for the UTF-8 format. The returned encoding will be
1348         // an instance of the UTF8Encoding class.
1349
1350         public static Encoding UTF8 => UTF8Encoding.s_default;
1351
1352         // Returns an encoding for the UTF-32 format. The returned encoding will be
1353         // an instance of the UTF32Encoding class.
1354
1355         public static Encoding UTF32 => UTF32Encoding.s_default;
1356
1357         // Returns an encoding for the UTF-32 format. The returned encoding will be
1358         // an instance of the UTF32Encoding class.
1359         //
1360         // It will use big endian byte order.
1361
1362         private static Encoding BigEndianUTF32 => UTF32Encoding.s_bigEndianDefault;
1363
1364         public override bool Equals(Object value)
1365         {
1366             Encoding that = value as Encoding;
1367             if (that != null)
1368                 return (m_codePage == that.m_codePage) &&
1369                        (EncoderFallback.Equals(that.EncoderFallback)) &&
1370                        (DecoderFallback.Equals(that.DecoderFallback));
1371             return (false);
1372         }
1373
1374
1375         public override int GetHashCode()
1376         {
1377             return m_codePage + this.EncoderFallback.GetHashCode() + this.DecoderFallback.GetHashCode();
1378         }
1379
1380         internal virtual char[] GetBestFitUnicodeToBytesData()
1381         {
1382             // Normally we don't have any best fit data.
1383             return Array.Empty<char>();
1384         }
1385
1386         internal virtual char[] GetBestFitBytesToUnicodeData()
1387         {
1388             // Normally we don't have any best fit data.
1389             return Array.Empty<char>();
1390         }
1391
1392         internal void ThrowBytesOverflow()
1393         {
1394             // Special message to include fallback type in case fallback's GetMaxCharCount is broken
1395             // This happens if user has implimented an encoder fallback with a broken GetMaxCharCount
1396             throw new ArgumentException(
1397                 SR.Format(SR.Argument_EncodingConversionOverflowBytes, EncodingName, EncoderFallback.GetType()), "bytes");
1398         }
1399
1400         internal void ThrowBytesOverflow(EncoderNLS encoder, bool nothingEncoded)
1401         {
1402             if (encoder == null || encoder.m_throwOnOverflow || nothingEncoded)
1403             {
1404                 if (encoder != null && encoder.InternalHasFallbackBuffer)
1405                     encoder.FallbackBuffer.InternalReset();
1406                 // Special message to include fallback type in case fallback's GetMaxCharCount is broken
1407                 // This happens if user has implimented an encoder fallback with a broken GetMaxCharCount
1408                 ThrowBytesOverflow();
1409             }
1410
1411             // If we didn't throw, we are in convert and have to remember our flushing
1412             encoder.ClearMustFlush();
1413         }
1414
1415         internal void ThrowCharsOverflow()
1416         {
1417             // Special message to include fallback type in case fallback's GetMaxCharCount is broken
1418             // This happens if user has implimented a decoder fallback with a broken GetMaxCharCount
1419             throw new ArgumentException(
1420                 SR.Format(SR.Argument_EncodingConversionOverflowChars, EncodingName, DecoderFallback.GetType()), "chars");
1421         }
1422
1423         internal void ThrowCharsOverflow(DecoderNLS decoder, bool nothingDecoded)
1424         {
1425             if (decoder == null || decoder.m_throwOnOverflow || nothingDecoded)
1426             {
1427                 if (decoder != null && decoder.InternalHasFallbackBuffer)
1428                     decoder.FallbackBuffer.InternalReset();
1429
1430                 // Special message to include fallback type in case fallback's GetMaxCharCount is broken
1431                 // This happens if user has implimented a decoder fallback with a broken GetMaxCharCount
1432                 ThrowCharsOverflow();
1433             }
1434
1435             // If we didn't throw, we are in convert and have to remember our flushing
1436             decoder.ClearMustFlush();
1437         }
1438
1439         internal sealed class DefaultEncoder : Encoder, IObjectReference, ISerializable
1440         {
1441             private Encoding m_encoding;
1442
1443             public DefaultEncoder(Encoding encoding)
1444             {
1445                 m_encoding = encoding;
1446             }
1447             
1448             public Object GetRealObject(StreamingContext context)
1449             {
1450                 throw new PlatformNotSupportedException();
1451             }
1452
1453             // ISerializable implementation, get data for this object
1454             void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
1455             {
1456                 throw new PlatformNotSupportedException();
1457             }
1458
1459             // Returns the number of bytes the next call to GetBytes will
1460             // produce if presented with the given range of characters and the given
1461             // value of the flush parameter. The returned value takes into
1462             // account the state in which the encoder was left following the last call
1463             // to GetBytes. The state of the encoder is not affected by a call
1464             // to this method.
1465             //
1466
1467             public override int GetByteCount(char[] chars, int index, int count, bool flush)
1468             {
1469                 return m_encoding.GetByteCount(chars, index, count);
1470             }
1471
1472             [SuppressMessage("Microsoft.Contracts", "CC1055")]  // Skip extra error checking to avoid *potential* AppCompat problems.
1473             public unsafe override int GetByteCount(char* chars, int count, bool flush)
1474             {
1475                 return m_encoding.GetByteCount(chars, count);
1476             }
1477
1478             // Encodes a range of characters in a character array into a range of bytes
1479             // in a byte array. The method encodes charCount characters from
1480             // chars starting at index charIndex, storing the resulting
1481             // bytes in bytes starting at index byteIndex. The encoding
1482             // takes into account the state in which the encoder was left following the
1483             // last call to this method. The flush parameter indicates whether
1484             // the encoder should flush any shift-states and partial characters at the
1485             // end of the conversion. To ensure correct termination of a sequence of
1486             // blocks of encoded bytes, the last call to GetBytes should specify
1487             // a value of true for the flush parameter.
1488             //
1489             // An exception occurs if the byte array is not large enough to hold the
1490             // complete encoding of the characters. The GetByteCount method can
1491             // be used to determine the exact number of bytes that will be produced for
1492             // a given range of characters. Alternatively, the GetMaxByteCount
1493             // method of the Encoding that produced this encoder can be used to
1494             // determine the maximum number of bytes that will be produced for a given
1495             // number of characters, regardless of the actual character values.
1496             //
1497
1498             public override int GetBytes(char[] chars, int charIndex, int charCount,
1499                                           byte[] bytes, int byteIndex, bool flush)
1500             {
1501                 return m_encoding.GetBytes(chars, charIndex, charCount, bytes, byteIndex);
1502             }
1503
1504             [SuppressMessage("Microsoft.Contracts", "CC1055")]  // Skip extra error checking to avoid *potential* AppCompat problems.
1505             public unsafe override int GetBytes(char* chars, int charCount,
1506                                                  byte* bytes, int byteCount, bool flush)
1507             {
1508                 return m_encoding.GetBytes(chars, charCount, bytes, byteCount);
1509             }
1510         }
1511
1512         internal sealed class DefaultDecoder : Decoder, IObjectReference, ISerializable
1513         {
1514             private Encoding m_encoding;
1515
1516             public DefaultDecoder(Encoding encoding)
1517             {
1518                 m_encoding = encoding;
1519             }
1520
1521             public Object GetRealObject(StreamingContext context)
1522             {
1523                 throw new PlatformNotSupportedException();
1524             }
1525
1526             // ISerializable implementation
1527             void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
1528             {
1529                 throw new PlatformNotSupportedException();
1530             }
1531
1532             // Returns the number of characters the next call to GetChars will
1533             // produce if presented with the given range of bytes. The returned value
1534             // takes into account the state in which the decoder was left following the
1535             // last call to GetChars. The state of the decoder is not affected
1536             // by a call to this method.
1537             //
1538
1539             public override int GetCharCount(byte[] bytes, int index, int count)
1540             {
1541                 return GetCharCount(bytes, index, count, false);
1542             }
1543
1544             public override int GetCharCount(byte[] bytes, int index, int count, bool flush)
1545             {
1546                 return m_encoding.GetCharCount(bytes, index, count);
1547             }
1548
1549             [SuppressMessage("Microsoft.Contracts", "CC1055")]  // Skip extra error checking to avoid *potential* AppCompat problems.
1550             public unsafe override int GetCharCount(byte* bytes, int count, bool flush)
1551             {
1552                 // By default just call the encoding version, no flush by default
1553                 return m_encoding.GetCharCount(bytes, count);
1554             }
1555
1556             // Decodes a range of bytes in a byte array into a range of characters
1557             // in a character array. The method decodes byteCount bytes from
1558             // bytes starting at index byteIndex, storing the resulting
1559             // characters in chars starting at index charIndex. The
1560             // decoding takes into account the state in which the decoder was left
1561             // following the last call to this method.
1562             //
1563             // An exception occurs if the character array is not large enough to
1564             // hold the complete decoding of the bytes. The GetCharCount method
1565             // can be used to determine the exact number of characters that will be
1566             // produced for a given range of bytes. Alternatively, the
1567             // GetMaxCharCount method of the Encoding that produced this
1568             // decoder can be used to determine the maximum number of characters that
1569             // will be produced for a given number of bytes, regardless of the actual
1570             // byte values.
1571             //
1572
1573             public override int GetChars(byte[] bytes, int byteIndex, int byteCount,
1574                                            char[] chars, int charIndex)
1575             {
1576                 return GetChars(bytes, byteIndex, byteCount, chars, charIndex, false);
1577             }
1578
1579             public override int GetChars(byte[] bytes, int byteIndex, int byteCount,
1580                                            char[] chars, int charIndex, bool flush)
1581             {
1582                 return m_encoding.GetChars(bytes, byteIndex, byteCount, chars, charIndex);
1583             }
1584
1585             [SuppressMessage("Microsoft.Contracts", "CC1055")]  // Skip extra error checking to avoid *potential* AppCompat problems.
1586             public unsafe override int GetChars(byte* bytes, int byteCount,
1587                                                   char* chars, int charCount, bool flush)
1588             {
1589                 // By default just call the encoding's version
1590                 return m_encoding.GetChars(bytes, byteCount, chars, charCount);
1591             }
1592         }
1593
1594         internal class EncodingCharBuffer
1595         {
1596             private unsafe char* _chars;
1597             private unsafe char* _charStart;
1598             private unsafe char* _charEnd;
1599             private int _charCountResult = 0;
1600             private Encoding _enc;
1601             private DecoderNLS _decoder;
1602             private unsafe byte* _byteStart;
1603             private unsafe byte* _byteEnd;
1604             private unsafe byte* _bytes;
1605             private DecoderFallbackBuffer _fallbackBuffer;
1606
1607             internal unsafe EncodingCharBuffer(Encoding enc, DecoderNLS decoder, char* charStart, int charCount,
1608                                                     byte* byteStart, int byteCount)
1609             {
1610                 _enc = enc;
1611                 _decoder = decoder;
1612
1613                 _chars = charStart;
1614                 _charStart = charStart;
1615                 _charEnd = charStart + charCount;
1616
1617                 _byteStart = byteStart;
1618                 _bytes = byteStart;
1619                 _byteEnd = byteStart + byteCount;
1620
1621                 if (_decoder == null)
1622                     _fallbackBuffer = enc.DecoderFallback.CreateFallbackBuffer();
1623                 else
1624                     _fallbackBuffer = _decoder.FallbackBuffer;
1625
1626                 // If we're getting chars or getting char count we don't expect to have
1627                 // to remember fallbacks between calls (so it should be empty)
1628                 Debug.Assert(_fallbackBuffer.Remaining == 0,
1629                     "[Encoding.EncodingCharBuffer.EncodingCharBuffer]Expected empty fallback buffer for getchars/charcount");
1630                 _fallbackBuffer.InternalInitialize(_bytes, _charEnd);
1631             }
1632
1633             internal unsafe bool AddChar(char ch, int numBytes)
1634             {
1635                 if (_chars != null)
1636                 {
1637                     if (_chars >= _charEnd)
1638                     {
1639                         // Throw maybe
1640                         _bytes -= numBytes;                                        // Didn't encode these bytes
1641                         _enc.ThrowCharsOverflow(_decoder, _bytes <= _byteStart);    // Throw?
1642                         return false;                                           // No throw, but no store either
1643                     }
1644
1645                     *(_chars++) = ch;
1646                 }
1647                 _charCountResult++;
1648                 return true;
1649             }
1650
1651             internal unsafe bool AddChar(char ch)
1652             {
1653                 return AddChar(ch, 1);
1654             }
1655
1656
1657             internal unsafe bool AddChar(char ch1, char ch2, int numBytes)
1658             {
1659                 // Need room for 2 chars
1660                 if (_chars >= _charEnd - 1)
1661                 {
1662                     // Throw maybe
1663                     _bytes -= numBytes;                                        // Didn't encode these bytes
1664                     _enc.ThrowCharsOverflow(_decoder, _bytes <= _byteStart);    // Throw?
1665                     return false;                                           // No throw, but no store either
1666                 }
1667                 return AddChar(ch1, numBytes) && AddChar(ch2, numBytes);
1668             }
1669
1670             internal unsafe void AdjustBytes(int count)
1671             {
1672                 _bytes += count;
1673             }
1674
1675             internal unsafe bool MoreData
1676             {
1677                 get
1678                 {
1679                     return _bytes < _byteEnd;
1680                 }
1681             }
1682
1683             // Do we have count more bytes?
1684             internal unsafe bool EvenMoreData(int count)
1685             {
1686                 return (_bytes <= _byteEnd - count);
1687             }
1688
1689             // GetNextByte shouldn't be called unless the caller's already checked more data or even more data,
1690             // but we'll double check just to make sure.
1691             internal unsafe byte GetNextByte()
1692             {
1693                 Debug.Assert(_bytes < _byteEnd, "[EncodingCharBuffer.GetNextByte]Expected more date");
1694                 if (_bytes >= _byteEnd)
1695                     return 0;
1696                 return *(_bytes++);
1697             }
1698
1699             internal unsafe int BytesUsed
1700             {
1701                 get
1702                 {
1703                     return (int)(_bytes - _byteStart);
1704                 }
1705             }
1706
1707             internal unsafe bool Fallback(byte fallbackByte)
1708             {
1709                 // Build our buffer
1710                 byte[] byteBuffer = new byte[] { fallbackByte };
1711
1712                 // Do the fallback and add the data.
1713                 return Fallback(byteBuffer);
1714             }
1715
1716             internal unsafe bool Fallback(byte byte1, byte byte2)
1717             {
1718                 // Build our buffer
1719                 byte[] byteBuffer = new byte[] { byte1, byte2 };
1720
1721                 // Do the fallback and add the data.
1722                 return Fallback(byteBuffer);
1723             }
1724
1725             internal unsafe bool Fallback(byte byte1, byte byte2, byte byte3, byte byte4)
1726             {
1727                 // Build our buffer
1728                 byte[] byteBuffer = new byte[] { byte1, byte2, byte3, byte4 };
1729
1730                 // Do the fallback and add the data.
1731                 return Fallback(byteBuffer);
1732             }
1733
1734             internal unsafe bool Fallback(byte[] byteBuffer)
1735             {
1736                 // Do the fallback and add the data.
1737                 if (_chars != null)
1738                 {
1739                     char* pTemp = _chars;
1740                     if (_fallbackBuffer.InternalFallback(byteBuffer, _bytes, ref _chars) == false)
1741                     {
1742                         // Throw maybe
1743                         _bytes -= byteBuffer.Length;                             // Didn't use how many ever bytes we're falling back
1744                         _fallbackBuffer.InternalReset();                         // We didn't use this fallback.
1745                         _enc.ThrowCharsOverflow(_decoder, _chars == _charStart);    // Throw?
1746                         return false;                                           // No throw, but no store either
1747                     }
1748                     _charCountResult += unchecked((int)(_chars - pTemp));
1749                 }
1750                 else
1751                 {
1752                     _charCountResult += _fallbackBuffer.InternalFallback(byteBuffer, _bytes);
1753                 }
1754
1755                 return true;
1756             }
1757
1758             internal unsafe int Count
1759             {
1760                 get
1761                 {
1762                     return _charCountResult;
1763                 }
1764             }
1765         }
1766
1767         internal class EncodingByteBuffer
1768         {
1769             private unsafe byte* _bytes;
1770             private unsafe byte* _byteStart;
1771             private unsafe byte* _byteEnd;
1772             private unsafe char* _chars;
1773             private unsafe char* _charStart;
1774             private unsafe char* _charEnd;
1775             private int _byteCountResult = 0;
1776             private Encoding _enc;
1777             private EncoderNLS _encoder;
1778             internal EncoderFallbackBuffer fallbackBuffer;
1779
1780             internal unsafe EncodingByteBuffer(Encoding inEncoding, EncoderNLS inEncoder,
1781                         byte* inByteStart, int inByteCount, char* inCharStart, int inCharCount)
1782             {
1783                 _enc = inEncoding;
1784                 _encoder = inEncoder;
1785
1786                 _charStart = inCharStart;
1787                 _chars = inCharStart;
1788                 _charEnd = inCharStart + inCharCount;
1789
1790                 _bytes = inByteStart;
1791                 _byteStart = inByteStart;
1792                 _byteEnd = inByteStart + inByteCount;
1793
1794                 if (_encoder == null)
1795                     this.fallbackBuffer = _enc.EncoderFallback.CreateFallbackBuffer();
1796                 else
1797                 {
1798                     this.fallbackBuffer = _encoder.FallbackBuffer;
1799                     // If we're not converting we must not have data in our fallback buffer
1800                     if (_encoder.m_throwOnOverflow && _encoder.InternalHasFallbackBuffer &&
1801                         this.fallbackBuffer.Remaining > 0)
1802                         throw new ArgumentException(SR.Format(SR.Argument_EncoderFallbackNotEmpty,
1803                             _encoder.Encoding.EncodingName, _encoder.Fallback.GetType()));
1804                 }
1805                 fallbackBuffer.InternalInitialize(_chars, _charEnd, _encoder, _bytes != null);
1806             }
1807
1808             internal unsafe bool AddByte(byte b, int moreBytesExpected)
1809             {
1810                 Debug.Assert(moreBytesExpected >= 0, "[EncodingByteBuffer.AddByte]expected non-negative moreBytesExpected");
1811                 if (_bytes != null)
1812                 {
1813                     if (_bytes >= _byteEnd - moreBytesExpected)
1814                     {
1815                         // Throw maybe.  Check which buffer to back up (only matters if Converting)
1816                         this.MovePrevious(true);            // Throw if necessary
1817                         return false;                       // No throw, but no store either
1818                     }
1819
1820                     *(_bytes++) = b;
1821                 }
1822                 _byteCountResult++;
1823                 return true;
1824             }
1825
1826             internal unsafe bool AddByte(byte b1)
1827             {
1828                 return (AddByte(b1, 0));
1829             }
1830
1831             internal unsafe bool AddByte(byte b1, byte b2)
1832             {
1833                 return (AddByte(b1, b2, 0));
1834             }
1835
1836             internal unsafe bool AddByte(byte b1, byte b2, int moreBytesExpected)
1837             {
1838                 return (AddByte(b1, 1 + moreBytesExpected) && AddByte(b2, moreBytesExpected));
1839             }
1840
1841             internal unsafe bool AddByte(byte b1, byte b2, byte b3)
1842             {
1843                 return AddByte(b1, b2, b3, (int)0);
1844             }
1845
1846             internal unsafe bool AddByte(byte b1, byte b2, byte b3, int moreBytesExpected)
1847             {
1848                 return (AddByte(b1, 2 + moreBytesExpected) &&
1849                         AddByte(b2, 1 + moreBytesExpected) &&
1850                         AddByte(b3, moreBytesExpected));
1851             }
1852
1853             internal unsafe bool AddByte(byte b1, byte b2, byte b3, byte b4)
1854             {
1855                 return (AddByte(b1, 3) &&
1856                         AddByte(b2, 2) &&
1857                         AddByte(b3, 1) &&
1858                         AddByte(b4, 0));
1859             }
1860
1861             internal unsafe void MovePrevious(bool bThrow)
1862             {
1863                 if (fallbackBuffer.bFallingBack)
1864                     fallbackBuffer.MovePrevious();                      // don't use last fallback
1865                 else
1866                 {
1867                     Debug.Assert(_chars > _charStart ||
1868                         ((bThrow == true) && (_bytes == _byteStart)),
1869                         "[EncodingByteBuffer.MovePrevious]expected previous data or throw");
1870                     if (_chars > _charStart)
1871                         _chars--;                                        // don't use last char
1872                 }
1873
1874                 if (bThrow)
1875                     _enc.ThrowBytesOverflow(_encoder, _bytes == _byteStart);    // Throw? (and reset fallback if not converting)
1876             }
1877
1878             internal unsafe bool Fallback(char charFallback)
1879             {
1880                 // Do the fallback
1881                 return fallbackBuffer.InternalFallback(charFallback, ref _chars);
1882             }
1883
1884             internal unsafe bool MoreData
1885             {
1886                 get
1887                 {
1888                     // See if fallbackBuffer is not empty or if there's data left in chars buffer.
1889                     return ((fallbackBuffer.Remaining > 0) || (_chars < _charEnd));
1890                 }
1891             }
1892
1893             internal unsafe char GetNextChar()
1894             {
1895                 // See if there's something in our fallback buffer
1896                 char cReturn = fallbackBuffer.InternalGetNextChar();
1897
1898                 // Nothing in the fallback buffer, return our normal data.
1899                 if (cReturn == 0)
1900                 {
1901                     if (_chars < _charEnd)
1902                         cReturn = *(_chars++);
1903                 }
1904
1905                 return cReturn;
1906             }
1907
1908             internal unsafe int CharsUsed
1909             {
1910                 get
1911                 {
1912                     return (int)(_chars - _charStart);
1913                 }
1914             }
1915
1916             internal unsafe int Count
1917             {
1918                 get
1919                 {
1920                     return _byteCountResult;
1921                 }
1922             }
1923         }
1924     }
1925 }