628ec9a3fa36ba074ce9a79c8595cb96f0ad03eb
[platform/upstream/coreclr.git] / src / mscorlib / shared / System / Text / ASCIIEncoding.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;
6 using System.Diagnostics;
7 using System.Diagnostics.Contracts;
8 using System.Runtime.Serialization;
9
10 namespace System.Text
11 {
12     // ASCIIEncoding
13     //
14     // Note that ASCIIEncoding is optimized with no best fit and ? for fallback.
15     // It doesn't come in other flavors.
16     //
17     // Note: ASCIIEncoding is the only encoding that doesn't do best fit (windows has best fit).
18     //
19     // Note: IsAlwaysNormalized remains false because 1/2 the code points are unassigned, so they'd
20     //       use fallbacks, and we cannot guarantee that fallbacks are normalized.
21
22     public class ASCIIEncoding : Encoding
23     {
24         // Allow for devirtualization (see https://github.com/dotnet/coreclr/pull/9230)
25         internal sealed class ASCIIEncodingSealed : ASCIIEncoding { }
26
27         // Used by Encoding.ASCII for lazy initialization
28         // The initialization code will not be run until a static member of the class is referenced
29         internal static readonly ASCIIEncodingSealed s_default = new ASCIIEncodingSealed();
30
31         public ASCIIEncoding() : base(Encoding.CodePageASCII)
32         {
33         }
34
35         internal override void SetDefaultFallbacks()
36         {
37             // For ASCIIEncoding we just use default replacement fallback
38             this.encoderFallback = EncoderFallback.ReplacementFallback;
39             this.decoderFallback = DecoderFallback.ReplacementFallback;
40         }
41
42         // WARNING: GetByteCount(string chars), GetBytes(string chars,...), and GetString(byte[] byteIndex...)
43         // WARNING: have different variable names than EncodingNLS.cs, so this can't just be cut & pasted,
44         // WARNING: or it'll break VB's way of calling these.
45         //
46         // The following methods are copied from EncodingNLS.cs.
47         // Unfortunately EncodingNLS.cs is internal and we're public, so we have to re-implement them here.
48         // These should be kept in sync for the following classes:
49         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
50
51         // Returns the number of bytes required to encode a range of characters in
52         // a character array.
53         //
54         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
55         // So if you fix this, fix the others.  Currently those include:
56         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
57         // parent method is safe
58
59         public override unsafe int GetByteCount(char[] chars, int index, int count)
60         {
61             // Validate input parameters
62             if (chars == null)
63                 throw new ArgumentNullException("chars", SR.ArgumentNull_Array);
64
65             if (index < 0 || count < 0)
66                 throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"), SR.ArgumentOutOfRange_NeedNonNegNum);
67
68             if (chars.Length - index < count)
69                 throw new ArgumentOutOfRangeException("chars", SR.ArgumentOutOfRange_IndexCountBuffer);
70             Contract.EndContractBlock();
71
72             // If no input, return 0, avoid fixed empty array problem
73             if (count == 0)
74                 return 0;
75
76             // Just call the pointer version
77             fixed (char* pChars = chars)
78                 return GetByteCount(pChars + index, count, null);
79         }
80
81         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
82         // So if you fix this, fix the others.  Currently those include:
83         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
84         // parent method is safe
85
86         public override unsafe int GetByteCount(String chars)
87         {
88             // Validate input
89             if (chars==null)
90                 throw new ArgumentNullException("chars");
91             Contract.EndContractBlock();
92
93             fixed (char* pChars = chars)
94                 return GetByteCount(pChars, chars.Length, null);
95         }
96
97         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
98         // So if you fix this, fix the others.  Currently those include:
99         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
100
101         [CLSCompliant(false)]
102         public override unsafe int GetByteCount(char* chars, int count)
103         {
104             // Validate Parameters
105             if (chars == null)
106                 throw new ArgumentNullException("chars", SR.ArgumentNull_Array);
107
108             if (count < 0)
109                 throw new ArgumentOutOfRangeException("count", SR.ArgumentOutOfRange_NeedNonNegNum);
110             Contract.EndContractBlock();
111
112             // Call it with empty encoder
113             return GetByteCount(chars, count, null);
114         }
115
116         // Parent method is safe.
117         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
118         // So if you fix this, fix the others.  Currently those include:
119         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
120
121         public override unsafe int GetBytes(String chars, int charIndex, int charCount,
122                                               byte[] bytes, int byteIndex)
123         {
124             if (chars == null || bytes == null)
125                 throw new ArgumentNullException((chars == null ? "chars" : "bytes"), SR.ArgumentNull_Array);
126
127             if (charIndex < 0 || charCount < 0)
128                 throw new ArgumentOutOfRangeException((charIndex < 0 ? "charIndex" : "charCount"), SR.ArgumentOutOfRange_NeedNonNegNum);
129
130             if (chars.Length - charIndex < charCount)
131                 throw new ArgumentOutOfRangeException("chars", SR.ArgumentOutOfRange_IndexCount);
132
133             if (byteIndex < 0 || byteIndex > bytes.Length)
134                 throw new ArgumentOutOfRangeException("byteIndex", SR.ArgumentOutOfRange_Index);
135             Contract.EndContractBlock();
136
137             int byteCount = bytes.Length - byteIndex;
138
139             // Fixed doesn't like empty byte arrays
140             if (bytes.Length == 0)
141                 bytes = new byte[1];
142
143             fixed (char* pChars = chars) fixed (byte* pBytes = &bytes[0])
144                 return GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, null);
145         }
146
147         // Encodes a range of characters in a character array into a range of bytes
148         // in a byte array. An exception occurs if the byte array is not large
149         // enough to hold the complete encoding of the characters. The
150         // GetByteCount method can be used to determine the exact number of
151         // bytes that will be produced for a given range of characters.
152         // Alternatively, the GetMaxByteCount method can be used to
153         // determine the maximum number of bytes that will be produced for a given
154         // number of characters, regardless of the actual character values.
155         //
156         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
157         // So if you fix this, fix the others.  Currently those include:
158         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
159         // parent method is safe
160
161         public override unsafe int GetBytes(char[] chars, int charIndex, int charCount,
162                                                byte[] bytes, int byteIndex)
163         {
164             // Validate parameters
165             if (chars == null || bytes == null)
166                 throw new ArgumentNullException((chars == null ? "chars" : "bytes"), SR.ArgumentNull_Array);
167
168             if (charIndex < 0 || charCount < 0)
169                 throw new ArgumentOutOfRangeException((charIndex < 0 ? "charIndex" : "charCount"), SR.ArgumentOutOfRange_NeedNonNegNum);
170
171             if (chars.Length - charIndex < charCount)
172                 throw new ArgumentOutOfRangeException("chars", SR.ArgumentOutOfRange_IndexCountBuffer);
173
174             if (byteIndex < 0 || byteIndex > bytes.Length)
175                 throw new ArgumentOutOfRangeException("byteIndex", SR.ArgumentOutOfRange_Index);
176             Contract.EndContractBlock();
177
178             // If nothing to encode return 0, avoid fixed problem
179             if (charCount == 0)
180                 return 0;
181
182             // Just call pointer version
183             int byteCount = bytes.Length - byteIndex;
184
185             // Fixed doesn't like empty byte arrays
186             if (bytes.Length == 0)
187                 bytes = new byte[1];
188
189             fixed (char* pChars = chars)  fixed (byte* pBytes = &bytes[0])
190                 // Remember that byteCount is # to decode, not size of array.
191                 return GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, null);
192         }
193
194         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
195         // So if you fix this, fix the others.  Currently those include:
196         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
197
198         [CLSCompliant(false)]
199         public override unsafe int GetBytes(char* chars, int charCount, byte* bytes, int byteCount)
200         {
201             // Validate Parameters
202             if (bytes == null || chars == null)
203                 throw new ArgumentNullException(bytes == null ? "bytes" : "chars", SR.ArgumentNull_Array);
204
205             if (charCount < 0 || byteCount < 0)
206                 throw new ArgumentOutOfRangeException((charCount < 0 ? "charCount" : "byteCount"), SR.ArgumentOutOfRange_NeedNonNegNum);
207             Contract.EndContractBlock();
208
209             return GetBytes(chars, charCount, bytes, byteCount, null);
210         }
211
212         // Returns the number of characters produced by decoding a range of bytes
213         // in a byte array.
214         //
215         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
216         // So if you fix this, fix the others.  Currently those include:
217         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
218         // parent method is safe
219
220         public override unsafe int GetCharCount(byte[] bytes, int index, int count)
221         {
222             // Validate Parameters
223             if (bytes == null)
224                 throw new ArgumentNullException("bytes", SR.ArgumentNull_Array);
225
226             if (index < 0 || count < 0)
227                 throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"), SR.ArgumentOutOfRange_NeedNonNegNum);
228
229             if (bytes.Length - index < count)
230                 throw new ArgumentOutOfRangeException("bytes", SR.ArgumentOutOfRange_IndexCountBuffer);
231             Contract.EndContractBlock();
232
233             // If no input just return 0, fixed doesn't like 0 length arrays
234             if (count == 0)
235                 return 0;
236
237             // Just call pointer version
238             fixed (byte* pBytes = bytes)
239                 return GetCharCount(pBytes + index, count, null);
240         }
241
242         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
243         // So if you fix this, fix the others.  Currently those include:
244         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
245
246         [CLSCompliant(false)]
247         public override unsafe int GetCharCount(byte* bytes, int count)
248         {
249             // Validate Parameters
250             if (bytes == null)
251                 throw new ArgumentNullException("bytes", SR.ArgumentNull_Array);
252
253             if (count < 0)
254                 throw new ArgumentOutOfRangeException("count", SR.ArgumentOutOfRange_NeedNonNegNum);
255             Contract.EndContractBlock();
256
257             return GetCharCount(bytes, count, null);
258         }
259
260         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
261         // So if you fix this, fix the others.  Currently those include:
262         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
263         // parent method is safe
264
265         public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount,
266                                               char[] chars, int charIndex)
267         {
268             // Validate Parameters
269             if (bytes == null || chars == null)
270                 throw new ArgumentNullException(bytes == null ? "bytes" : "chars", SR.ArgumentNull_Array);
271
272             if (byteIndex < 0 || byteCount < 0)
273                 throw new ArgumentOutOfRangeException((byteIndex < 0 ? "byteIndex" : "byteCount"), SR.ArgumentOutOfRange_NeedNonNegNum);
274
275             if ( bytes.Length - byteIndex < byteCount)
276                 throw new ArgumentOutOfRangeException("bytes", SR.ArgumentOutOfRange_IndexCountBuffer);
277
278             if (charIndex < 0 || charIndex > chars.Length)
279                 throw new ArgumentOutOfRangeException("charIndex", SR.ArgumentOutOfRange_Index);
280             Contract.EndContractBlock();
281
282             // If no input, return 0 & avoid fixed problem
283             if (byteCount == 0)
284                 return 0;
285
286             // Just call pointer version
287             int charCount = chars.Length - charIndex;
288
289             // Fixed doesn't like empty char arrays
290             if (chars.Length == 0)
291                 chars = new char[1];
292
293             fixed (byte* pBytes = bytes) fixed (char* pChars = &chars[0])
294                 // Remember that charCount is # to decode, not size of array
295                 return GetChars(pBytes + byteIndex, byteCount, pChars + charIndex, charCount, null);
296         }
297
298         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
299         // So if you fix this, fix the others.  Currently those include:
300         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
301
302         [CLSCompliant(false)]
303         public unsafe override int GetChars(byte* bytes, int byteCount, char* chars, int charCount)
304         {
305             // Validate Parameters
306             if (bytes == null || chars == null)
307                 throw new ArgumentNullException(bytes == null ? "bytes" : "chars", SR.ArgumentNull_Array);
308
309             if (charCount < 0 || byteCount < 0)
310                 throw new ArgumentOutOfRangeException((charCount < 0 ? "charCount" : "byteCount"), SR.ArgumentOutOfRange_NeedNonNegNum);
311             Contract.EndContractBlock();
312
313             return GetChars(bytes, byteCount, chars, charCount, null);
314         }
315
316         // Returns a string containing the decoded representation of a range of
317         // bytes in a byte array.
318         //
319         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
320         // So if you fix this, fix the others.  Currently those include:
321         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
322         // parent method is safe
323
324         public override unsafe String GetString(byte[] bytes, int byteIndex, int byteCount)
325         {
326             // Validate Parameters
327             if (bytes == null)
328                 throw new ArgumentNullException("bytes", SR.ArgumentNull_Array);
329
330             if (byteIndex < 0 || byteCount < 0)
331                 throw new ArgumentOutOfRangeException((byteIndex < 0 ? "byteIndex" : "byteCount"), SR.ArgumentOutOfRange_NeedNonNegNum);
332
333
334             if (bytes.Length - byteIndex < byteCount)
335                 throw new ArgumentOutOfRangeException("bytes", SR.ArgumentOutOfRange_IndexCountBuffer);
336             Contract.EndContractBlock();
337
338             // Avoid problems with empty input buffer
339             if (byteCount == 0) return String.Empty;
340
341             fixed (byte* pBytes = bytes)
342                 return String.CreateStringFromEncoding(
343                     pBytes + byteIndex, byteCount, this);
344         }
345
346         //
347         // End of standard methods copied from EncodingNLS.cs
348         //
349
350         // GetByteCount
351         // Note: We start by assuming that the output will be the same as count.  Having
352         // an encoder or fallback may change that assumption
353         internal override unsafe int GetByteCount(char* chars, int charCount, EncoderNLS encoder)
354         {
355             // Just need to ASSERT, this is called by something else internal that checked parameters already
356             Debug.Assert(charCount >= 0, "[ASCIIEncoding.GetByteCount]count is negative");
357             Debug.Assert(chars != null, "[ASCIIEncoding.GetByteCount]chars is null");
358
359             // Assert because we shouldn't be able to have a null encoder.
360             Debug.Assert(encoderFallback != null, "[ASCIIEncoding.GetByteCount]Attempting to use null fallback encoder");
361
362             char charLeftOver = (char)0;
363             EncoderReplacementFallback fallback = null;
364
365             // Start by assuming default count, then +/- for fallback characters
366             char* charEnd = chars + charCount;
367
368             // For fallback we may need a fallback buffer, we know we aren't default fallback.
369             EncoderFallbackBuffer fallbackBuffer = null;
370             char* charsForFallback;
371
372             if (encoder != null)
373             {
374                 charLeftOver = encoder.charLeftOver;
375                 Debug.Assert(charLeftOver == 0 || Char.IsHighSurrogate(charLeftOver),
376                     "[ASCIIEncoding.GetByteCount]leftover character should be high surrogate");
377
378                 fallback = encoder.Fallback as EncoderReplacementFallback;
379
380                 // We mustn't have left over fallback data when counting
381                 if (encoder.InternalHasFallbackBuffer)
382                 {
383                     // We always need the fallback buffer in get bytes so we can flush any remaining ones if necessary
384                     fallbackBuffer = encoder.FallbackBuffer;
385                     if (fallbackBuffer.Remaining > 0 && encoder.m_throwOnOverflow)
386                         throw new ArgumentException(SR.Format(SR.Argument_EncoderFallbackNotEmpty, this.EncodingName, encoder.Fallback.GetType()));
387
388                     // Set our internal fallback interesting things.
389                     fallbackBuffer.InternalInitialize(chars, charEnd, encoder, false);
390                 }
391
392                 // Verify that we have no fallbackbuffer, for ASCII its always empty, so just assert
393                 Debug.Assert(!encoder.m_throwOnOverflow || !encoder.InternalHasFallbackBuffer ||
394                     encoder.FallbackBuffer.Remaining == 0,
395                     "[ASCIICodePageEncoding.GetByteCount]Expected empty fallback buffer");
396             }
397             else
398             {
399                 fallback = this.EncoderFallback as EncoderReplacementFallback;
400             }
401
402             // If we have an encoder AND we aren't using default fallback,
403             // then we may have a complicated count.
404             if (fallback != null && fallback.MaxCharCount == 1)
405             {
406                 // Replacement fallback encodes surrogate pairs as two ?? (or two whatever), so return size is always
407                 // same as input size.
408                 // Note that no existing SBCS code pages map code points to supplimentary characters, so this is easy.
409
410                 // We could however have 1 extra byte if the last call had an encoder and a funky fallback and
411                 // if we don't use the funky fallback this time.
412
413                 // Do we have an extra char left over from last time?
414                 if (charLeftOver > 0)
415                     charCount++;
416
417                 return (charCount);
418             }
419
420             // Count is more complicated if you have a funky fallback
421             // For fallback we may need a fallback buffer, we know we're not default fallback
422             int byteCount = 0;
423
424             // We may have a left over character from last time, try and process it.
425             if (charLeftOver > 0)
426             {
427                 Debug.Assert(Char.IsHighSurrogate(charLeftOver), "[ASCIIEncoding.GetByteCount]leftover character should be high surrogate");
428                 Debug.Assert(encoder != null, "[ASCIIEncoding.GetByteCount]Expected encoder");
429
430                 // Since left over char was a surrogate, it'll have to be fallen back.
431                 // Get Fallback
432                 fallbackBuffer = encoder.FallbackBuffer;
433                 fallbackBuffer.InternalInitialize(chars, charEnd, encoder, false);
434
435                 // This will fallback a pair if *chars is a low surrogate
436                 charsForFallback = chars; // Avoid passing chars by reference to allow it to be enregistered
437                 fallbackBuffer.InternalFallback(charLeftOver, ref charsForFallback);
438                 chars = charsForFallback;
439             }
440
441             // Now we may have fallback char[] already from the encoder
442
443             // Go ahead and do it, including the fallback.
444             char ch;
445             while ((ch = (fallbackBuffer == null) ? '\0' : fallbackBuffer.InternalGetNextChar()) != 0 ||
446                     chars < charEnd)
447             {
448                 // First unwind any fallback
449                 if (ch == 0)
450                 {
451                     // No fallback, just get next char
452                     ch = *chars;
453                     chars++;
454                 }
455
456                 // Check for fallback, this'll catch surrogate pairs too.
457                 // no chars >= 0x80 are allowed.
458                 if (ch > 0x7f)
459                 {
460                     if (fallbackBuffer == null)
461                     {
462                         // Initialize the buffer
463                         if (encoder == null)
464                             fallbackBuffer = this.encoderFallback.CreateFallbackBuffer();
465                         else
466                             fallbackBuffer = encoder.FallbackBuffer;
467                         fallbackBuffer.InternalInitialize(charEnd - charCount, charEnd, encoder, false);
468                     }
469
470                     // Get Fallback
471                     charsForFallback = chars; // Avoid passing chars by reference to allow it to be enregistered
472                     fallbackBuffer.InternalFallback(ch, ref charsForFallback);
473                     chars = charsForFallback;
474                     continue;
475                 }
476
477                 // We'll use this one
478                 byteCount++;
479             }
480
481             Debug.Assert(fallbackBuffer == null || fallbackBuffer.Remaining == 0,
482                 "[ASCIIEncoding.GetByteCount]Expected Empty fallback buffer");
483
484             return byteCount;
485         }
486
487         internal override unsafe int GetBytes(char* chars, int charCount,
488                                                 byte* bytes, int byteCount, EncoderNLS encoder)
489         {
490             // Just need to ASSERT, this is called by something else internal that checked parameters already
491             Debug.Assert(bytes != null, "[ASCIIEncoding.GetBytes]bytes is null");
492             Debug.Assert(byteCount >= 0, "[ASCIIEncoding.GetBytes]byteCount is negative");
493             Debug.Assert(chars != null, "[ASCIIEncoding.GetBytes]chars is null");
494             Debug.Assert(charCount >= 0, "[ASCIIEncoding.GetBytes]charCount is negative");
495
496             // Assert because we shouldn't be able to have a null encoder.
497             Debug.Assert(encoderFallback != null, "[ASCIIEncoding.GetBytes]Attempting to use null encoder fallback");
498
499             // Get any left over characters
500             char charLeftOver = (char)0;
501             EncoderReplacementFallback fallback = null;
502
503             // For fallback we may need a fallback buffer, we know we aren't default fallback.
504             EncoderFallbackBuffer fallbackBuffer = null;
505             char* charsForFallback;
506
507             // prepare our end
508             char* charEnd = chars + charCount;
509             byte* byteStart = bytes;
510             char* charStart = chars;
511
512             if (encoder != null)
513             {
514                 charLeftOver = encoder.charLeftOver;
515                 fallback = encoder.Fallback as EncoderReplacementFallback;
516
517                 // We mustn't have left over fallback data when counting
518                 if (encoder.InternalHasFallbackBuffer)
519                 {
520                     // We always need the fallback buffer in get bytes so we can flush any remaining ones if necessary
521                     fallbackBuffer = encoder.FallbackBuffer;
522                     if (fallbackBuffer.Remaining > 0 && encoder.m_throwOnOverflow)
523                         throw new ArgumentException(SR.Format(SR.Argument_EncoderFallbackNotEmpty, this.EncodingName, encoder.Fallback.GetType()));
524
525                     // Set our internal fallback interesting things.
526                     fallbackBuffer.InternalInitialize(charStart, charEnd, encoder, true);
527                 }
528
529                 Debug.Assert(charLeftOver == 0 || Char.IsHighSurrogate(charLeftOver),
530                     "[ASCIIEncoding.GetBytes]leftover character should be high surrogate");
531
532                 // Verify that we have no fallbackbuffer, for ASCII its always empty, so just assert
533                 Debug.Assert(!encoder.m_throwOnOverflow || !encoder.InternalHasFallbackBuffer ||
534                     encoder.FallbackBuffer.Remaining == 0,
535                     "[ASCIICodePageEncoding.GetBytes]Expected empty fallback buffer");
536             }
537             else
538             {
539                 fallback = this.EncoderFallback as EncoderReplacementFallback;
540             }
541
542
543             // See if we do the fast default or slightly slower fallback
544             if (fallback != null && fallback.MaxCharCount == 1)
545             {
546                 // Fast version
547                 char cReplacement = fallback.DefaultString[0];
548
549                 // Check for replacements in range, otherwise fall back to slow version.
550                 if (cReplacement <= (char)0x7f)
551                 {
552                     // We should have exactly as many output bytes as input bytes, unless there's a left
553                     // over character, in which case we may need one more.
554                     // If we had a left over character will have to add a ?  (This happens if they had a funky
555                     // fallback last time, but not this time.) (We can't spit any out though
556                     // because with fallback encoder each surrogate is treated as a seperate code point)
557                     if (charLeftOver > 0)
558                     {
559                         // Have to have room
560                         // Throw even if doing no throw version because this is just 1 char,
561                         // so buffer will never be big enough
562                         if (byteCount == 0)
563                             ThrowBytesOverflow(encoder, true);
564
565                         // This'll make sure we still have more room and also make sure our return value is correct.
566                         *(bytes++) = (byte)cReplacement;
567                         byteCount--;                // We used one of the ones we were counting.
568                     }
569
570                     // This keeps us from overrunning our output buffer
571                     if (byteCount < charCount)
572                     {
573                         // Throw or make buffer smaller?
574                         ThrowBytesOverflow(encoder, byteCount < 1);
575
576                         // Just use what we can
577                         charEnd = chars + byteCount;
578                     }
579
580                     // We just do a quick copy
581                     while (chars < charEnd)
582                     {
583                         char ch2 = *(chars++);
584                         if (ch2 >= 0x0080) *(bytes++) = (byte)cReplacement;
585                         else *(bytes++) = unchecked((byte)(ch2));
586                     }
587
588                     // Clear encoder
589                     if (encoder != null)
590                     {
591                         encoder.charLeftOver = (char)0;
592                         encoder.m_charsUsed = (int)(chars - charStart);
593                     }
594
595                     return (int)(bytes - byteStart);
596                 }
597             }
598
599             // Slower version, have to do real fallback.
600
601             // prepare our end
602             byte* byteEnd = bytes + byteCount;
603
604             // We may have a left over character from last time, try and process it.
605             if (charLeftOver > 0)
606             {
607                 // Initialize the buffer
608                 Debug.Assert(encoder != null,
609                     "[ASCIIEncoding.GetBytes]Expected non null encoder if we have surrogate left over");
610                 fallbackBuffer = encoder.FallbackBuffer;
611                 fallbackBuffer.InternalInitialize(chars, charEnd, encoder, true);
612
613                 // Since left over char was a surrogate, it'll have to be fallen back.
614                 // Get Fallback
615                 // This will fallback a pair if *chars is a low surrogate
616                 charsForFallback = chars; // Avoid passing chars by reference to allow it to be enregistered
617                 fallbackBuffer.InternalFallback(charLeftOver, ref charsForFallback);
618                 chars = charsForFallback;
619             }
620
621             // Now we may have fallback char[] already from the encoder
622
623             // Go ahead and do it, including the fallback.
624             char ch;
625             while ((ch = (fallbackBuffer == null) ? '\0' : fallbackBuffer.InternalGetNextChar()) != 0 ||
626                     chars < charEnd)
627             {
628                 // First unwind any fallback
629                 if (ch == 0)
630                 {
631                     // No fallback, just get next char
632                     ch = *chars;
633                     chars++;
634                 }
635
636                 // Check for fallback, this'll catch surrogate pairs too.
637                 // All characters >= 0x80 must fall back.
638                 if (ch > 0x7f)
639                 {
640                     // Initialize the buffer
641                     if (fallbackBuffer == null)
642                     {
643                         if (encoder == null)
644                             fallbackBuffer = this.encoderFallback.CreateFallbackBuffer();
645                         else
646                             fallbackBuffer = encoder.FallbackBuffer;
647                         fallbackBuffer.InternalInitialize(charEnd - charCount, charEnd, encoder, true);
648                     }
649
650                     // Get Fallback
651                     charsForFallback = chars; // Avoid passing chars by reference to allow it to be enregistered
652                     fallbackBuffer.InternalFallback(ch, ref charsForFallback);
653                     chars = charsForFallback;
654
655                     // Go ahead & continue (& do the fallback)
656                     continue;
657                 }
658
659                 // We'll use this one
660                 // Bounds check
661                 if (bytes >= byteEnd)
662                 {
663                     // didn't use this char, we'll throw or use buffer
664                     if (fallbackBuffer == null || fallbackBuffer.bFallingBack == false)
665                     {
666                         Debug.Assert(chars > charStart || bytes == byteStart,
667                             "[ASCIIEncoding.GetBytes]Expected chars to have advanced already.");
668                         chars--;                                        // don't use last char
669                     }
670                     else
671                         fallbackBuffer.MovePrevious();
672
673                     // Are we throwing or using buffer?
674                     ThrowBytesOverflow(encoder, bytes == byteStart);    // throw?
675                     break;                                              // don't throw, stop
676                 }
677
678                 // Go ahead and add it
679                 *bytes = unchecked((byte)ch);
680                 bytes++;
681             }
682
683             // Need to do encoder stuff
684             if (encoder != null)
685             {
686                 // Fallback stuck it in encoder if necessary, but we have to clear MustFlush cases
687                 if (fallbackBuffer != null && !fallbackBuffer.bUsedEncoder)
688                     // Clear it in case of MustFlush
689                     encoder.charLeftOver = (char)0;
690
691                 // Set our chars used count
692                 encoder.m_charsUsed = (int)(chars - charStart);
693             }
694
695             Debug.Assert(fallbackBuffer == null || fallbackBuffer.Remaining == 0 ||
696                 (encoder != null && !encoder.m_throwOnOverflow),
697                 "[ASCIIEncoding.GetBytes]Expected Empty fallback buffer at end");
698
699             return (int)(bytes - byteStart);
700         }
701
702         // This is internal and called by something else,
703         internal override unsafe int GetCharCount(byte* bytes, int count, DecoderNLS decoder)
704         {
705             // Just assert, we're called internally so these should be safe, checked already
706             Debug.Assert(bytes != null, "[ASCIIEncoding.GetCharCount]bytes is null");
707             Debug.Assert(count >= 0, "[ASCIIEncoding.GetCharCount]byteCount is negative");
708
709             // ASCII doesn't do best fit, so don't have to check for it, find out which decoder fallback we're using
710             DecoderReplacementFallback fallback = null;
711
712             if (decoder == null)
713                 fallback = this.DecoderFallback as DecoderReplacementFallback;
714             else
715             {
716                 fallback = decoder.Fallback as DecoderReplacementFallback;
717                 Debug.Assert(!decoder.m_throwOnOverflow || !decoder.InternalHasFallbackBuffer ||
718                     decoder.FallbackBuffer.Remaining == 0,
719                     "[ASCIICodePageEncoding.GetCharCount]Expected empty fallback buffer");
720             }
721
722             if (fallback != null && fallback.MaxCharCount == 1)
723             {
724                 // Just return length, SBCS stay the same length because they don't map to surrogate
725                 // pairs and we don't have a decoder fallback.
726
727                 return count;
728             }
729
730             // Only need decoder fallback buffer if not using default replacement fallback, no best fit for ASCII
731             DecoderFallbackBuffer fallbackBuffer = null;
732
733             // Have to do it the hard way.
734             // Assume charCount will be == count
735             int charCount = count;
736             byte[] byteBuffer = new byte[1];
737
738             // Do it our fast way
739             byte* byteEnd = bytes + count;
740
741             // Quick loop
742             while (bytes < byteEnd)
743             {
744                 // Faster if don't use *bytes++;
745                 byte b = *bytes;
746                 bytes++;
747
748                 // If unknown we have to do fallback count
749                 if (b >= 0x80)
750                 {
751                     if (fallbackBuffer == null)
752                     {
753                         if (decoder == null)
754                             fallbackBuffer = this.DecoderFallback.CreateFallbackBuffer();
755                         else
756                             fallbackBuffer = decoder.FallbackBuffer;
757                         fallbackBuffer.InternalInitialize(byteEnd - count, null);
758                     }
759
760                     // Use fallback buffer
761                     byteBuffer[0] = b;
762                     charCount--;            // Have to unreserve the one we already allocated for b
763                     charCount += fallbackBuffer.InternalFallback(byteBuffer, bytes);
764                 }
765             }
766
767             // Fallback buffer must be empty
768             Debug.Assert(fallbackBuffer == null || fallbackBuffer.Remaining == 0,
769                 "[ASCIIEncoding.GetCharCount]Expected Empty fallback buffer");
770
771             // Converted sequence is same length as input
772             return charCount;
773         }
774
775         internal override unsafe int GetChars(byte* bytes, int byteCount,
776                                                 char* chars, int charCount, DecoderNLS decoder)
777         {
778             // Just need to ASSERT, this is called by something else internal that checked parameters already
779             Debug.Assert(bytes != null, "[ASCIIEncoding.GetChars]bytes is null");
780             Debug.Assert(byteCount >= 0, "[ASCIIEncoding.GetChars]byteCount is negative");
781             Debug.Assert(chars != null, "[ASCIIEncoding.GetChars]chars is null");
782             Debug.Assert(charCount >= 0, "[ASCIIEncoding.GetChars]charCount is negative");
783
784             // Do it fast way if using ? replacement fallback
785             byte* byteEnd = bytes + byteCount;
786             byte* byteStart = bytes;
787             char* charStart = chars;
788
789             // Note: ASCII doesn't do best fit, but we have to fallback if they use something > 0x7f
790             // Only need decoder fallback buffer if not using ? fallback.
791             // ASCII doesn't do best fit, so don't have to check for it, find out which decoder fallback we're using
792             DecoderReplacementFallback fallback = null;
793             char* charsForFallback;
794
795             if (decoder == null)
796                 fallback = this.DecoderFallback as DecoderReplacementFallback;
797             else
798             {
799                 fallback = decoder.Fallback as DecoderReplacementFallback;
800                 Debug.Assert(!decoder.m_throwOnOverflow || !decoder.InternalHasFallbackBuffer ||
801                     decoder.FallbackBuffer.Remaining == 0,
802                     "[ASCIICodePageEncoding.GetChars]Expected empty fallback buffer");
803             }
804
805             if (fallback != null && fallback.MaxCharCount == 1)
806             {
807                 // Try it the fast way
808                 char replacementChar = fallback.DefaultString[0];
809
810                 // Need byteCount chars, otherwise too small buffer
811                 if (charCount < byteCount)
812                 {
813                     // Need at least 1 output byte, throw if must throw
814                     ThrowCharsOverflow(decoder, charCount < 1);
815
816                     // Not throwing, use what we can
817                     byteEnd = bytes + charCount;
818                 }
819
820                 // Quick loop, just do '?' replacement because we don't have fallbacks for decodings.
821                 while (bytes < byteEnd)
822                 {
823                     byte b = *(bytes++);
824                     if (b >= 0x80)
825                         // This is an invalid byte in the ASCII encoding.
826                         *(chars++) = replacementChar;
827                     else
828                         *(chars++) = unchecked((char)b);
829                 }
830
831                 // bytes & chars used are the same
832                 if (decoder != null)
833                     decoder.m_bytesUsed = (int)(bytes - byteStart);
834                 return (int)(chars - charStart);
835             }
836
837             // Slower way's going to need a fallback buffer
838             DecoderFallbackBuffer fallbackBuffer = null;
839             byte[] byteBuffer = new byte[1];
840             char* charEnd = chars + charCount;
841
842             // Not quite so fast loop
843             while (bytes < byteEnd)
844             {
845                 // Faster if don't use *bytes++;
846                 byte b = *(bytes);
847                 bytes++;
848
849                 if (b >= 0x80)
850                 {
851                     // This is an invalid byte in the ASCII encoding.
852                     if (fallbackBuffer == null)
853                     {
854                         if (decoder == null)
855                             fallbackBuffer = this.DecoderFallback.CreateFallbackBuffer();
856                         else
857                             fallbackBuffer = decoder.FallbackBuffer;
858                         fallbackBuffer.InternalInitialize(byteEnd - byteCount, charEnd);
859                     }
860
861                     // Use fallback buffer
862                     byteBuffer[0] = b;
863
864                     // Note that chars won't get updated unless this succeeds
865                     charsForFallback = chars; // Avoid passing chars by reference to allow it to be enregistered
866                     bool fallbackResult = fallbackBuffer.InternalFallback(byteBuffer, bytes, ref charsForFallback);
867                     chars = charsForFallback;
868
869                     if (!fallbackResult)
870                     {
871                         // May or may not throw, but we didn't get this byte
872                         Debug.Assert(bytes > byteStart || chars == charStart,
873                             "[ASCIIEncoding.GetChars]Expected bytes to have advanced already (fallback case)");
874                         bytes--;                                            // unused byte
875                         fallbackBuffer.InternalReset();                     // Didn't fall this back
876                         ThrowCharsOverflow(decoder, chars == charStart);    // throw?
877                         break;                                              // don't throw, but stop loop
878                     }
879                 }
880                 else
881                 {
882                     // Make sure we have buffer space
883                     if (chars >= charEnd)
884                     {
885                         Debug.Assert(bytes > byteStart || chars == charStart,
886                             "[ASCIIEncoding.GetChars]Expected bytes to have advanced already (normal case)");
887                         bytes--;                                            // unused byte
888                         ThrowCharsOverflow(decoder, chars == charStart);    // throw?
889                         break;                                              // don't throw, but stop loop
890                     }
891
892                     *(chars) = unchecked((char)b);
893                     chars++;
894                 }
895             }
896
897             // Might have had decoder fallback stuff.
898             if (decoder != null)
899                 decoder.m_bytesUsed = (int)(bytes - byteStart);
900
901             // Expect Empty fallback buffer for GetChars
902             Debug.Assert(fallbackBuffer == null || fallbackBuffer.Remaining == 0,
903                 "[ASCIIEncoding.GetChars]Expected Empty fallback buffer");
904
905             return (int)(chars - charStart);
906         }
907
908
909         public override int GetMaxByteCount(int charCount)
910         {
911             if (charCount < 0)
912                 throw new ArgumentOutOfRangeException(nameof(charCount),
913                      SR.ArgumentOutOfRange_NeedNonNegNum);
914             Contract.EndContractBlock();
915
916             // Characters would be # of characters + 1 in case high surrogate is ? * max fallback
917             long byteCount = (long)charCount + 1;
918
919             if (EncoderFallback.MaxCharCount > 1)
920                 byteCount *= EncoderFallback.MaxCharCount;
921
922             // 1 to 1 for most characters.  Only surrogates with fallbacks have less.
923
924             if (byteCount > 0x7fffffff)
925                 throw new ArgumentOutOfRangeException(nameof(charCount), SR.ArgumentOutOfRange_GetByteCountOverflow);
926             return (int)byteCount;
927         }
928
929
930         public override int GetMaxCharCount(int byteCount)
931         {
932             if (byteCount < 0)
933                 throw new ArgumentOutOfRangeException(nameof(byteCount),
934                      SR.ArgumentOutOfRange_NeedNonNegNum);
935             Contract.EndContractBlock();
936
937             // Just return length, SBCS stay the same length because they don't map to surrogate
938             long charCount = (long)byteCount;
939
940             // 1 to 1 for most characters.  Only surrogates with fallbacks have less, unknown fallbacks could be longer.
941             if (DecoderFallback.MaxCharCount > 1)
942                 charCount *= DecoderFallback.MaxCharCount;
943
944             if (charCount > 0x7fffffff)
945                 throw new ArgumentOutOfRangeException(nameof(byteCount), SR.ArgumentOutOfRange_GetCharCountOverflow);
946
947             return (int)charCount;
948         }
949
950         // True if and only if the encoding only uses single byte code points.  (Ie, ASCII, 1252, etc)
951
952         public override bool IsSingleByte
953         {
954             get
955             {
956                 return true;
957             }
958         }
959
960         public override Decoder GetDecoder()
961         {
962             return new DecoderNLS(this);
963         }
964
965
966         public override Encoder GetEncoder()
967         {
968             return new EncoderNLS(this);
969         }
970     }
971 }