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.
6 using System.Diagnostics;
7 using System.Diagnostics.Contracts;
13 // Note that ASCIIEncoding is optimized with no best fit and ? for fallback.
14 // It doesn't come in other flavors.
16 // Note: ASCIIEncoding is the only encoding that doesn't do best fit (windows has best fit).
18 // Note: IsAlwaysNormalized remains false because 1/2 the code points are unassigned, so they'd
19 // use fallbacks, and we cannot guarantee that fallbacks are normalized.
21 public class ASCIIEncoding : Encoding
23 // Allow for devirtualization (see https://github.com/dotnet/coreclr/pull/9230)
24 internal sealed class ASCIIEncodingSealed : ASCIIEncoding { }
26 // Used by Encoding.ASCII for lazy initialization
27 // The initialization code will not be run until a static member of the class is referenced
28 internal static readonly ASCIIEncodingSealed s_default = new ASCIIEncodingSealed();
30 public ASCIIEncoding() : base(Encoding.CodePageASCII)
34 internal override void SetDefaultFallbacks()
36 // For ASCIIEncoding we just use default replacement fallback
37 this.encoderFallback = EncoderFallback.ReplacementFallback;
38 this.decoderFallback = DecoderFallback.ReplacementFallback;
41 // WARNING: GetByteCount(string chars), GetBytes(string chars,...), and GetString(byte[] byteIndex...)
42 // WARNING: have different variable names than EncodingNLS.cs, so this can't just be cut & pasted,
43 // WARNING: or it'll break VB's way of calling these.
45 // The following methods are copied from EncodingNLS.cs.
46 // Unfortunately EncodingNLS.cs is internal and we're public, so we have to re-implement them here.
47 // These should be kept in sync for the following classes:
48 // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
50 // Returns the number of bytes required to encode a range of characters in
53 // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
54 // So if you fix this, fix the others. Currently those include:
55 // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
56 // parent method is safe
58 public override unsafe int GetByteCount(char[] chars, int index, int count)
60 // Validate input parameters
62 throw new ArgumentNullException("chars", SR.ArgumentNull_Array);
64 if (index < 0 || count < 0)
65 throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"), SR.ArgumentOutOfRange_NeedNonNegNum);
67 if (chars.Length - index < count)
68 throw new ArgumentOutOfRangeException("chars", SR.ArgumentOutOfRange_IndexCountBuffer);
69 Contract.EndContractBlock();
71 // If no input, return 0, avoid fixed empty array problem
75 // Just call the pointer version
76 fixed (char* pChars = chars)
77 return GetByteCount(pChars + index, count, null);
80 // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
81 // So if you fix this, fix the others. Currently those include:
82 // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
83 // parent method is safe
85 public override unsafe int GetByteCount(String chars)
89 throw new ArgumentNullException("chars");
90 Contract.EndContractBlock();
92 fixed (char* pChars = chars)
93 return GetByteCount(pChars, chars.Length, null);
96 // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
97 // So if you fix this, fix the others. Currently those include:
98 // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
100 [CLSCompliant(false)]
101 public override unsafe int GetByteCount(char* chars, int count)
103 // Validate Parameters
105 throw new ArgumentNullException("chars", SR.ArgumentNull_Array);
108 throw new ArgumentOutOfRangeException("count", SR.ArgumentOutOfRange_NeedNonNegNum);
109 Contract.EndContractBlock();
111 // Call it with empty encoder
112 return GetByteCount(chars, count, null);
115 // Parent method is safe.
116 // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
117 // So if you fix this, fix the others. Currently those include:
118 // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
120 public override unsafe int GetBytes(String chars, int charIndex, int charCount,
121 byte[] bytes, int byteIndex)
123 if (chars == null || bytes == null)
124 throw new ArgumentNullException((chars == null ? "chars" : "bytes"), SR.ArgumentNull_Array);
126 if (charIndex < 0 || charCount < 0)
127 throw new ArgumentOutOfRangeException((charIndex < 0 ? "charIndex" : "charCount"), SR.ArgumentOutOfRange_NeedNonNegNum);
129 if (chars.Length - charIndex < charCount)
130 throw new ArgumentOutOfRangeException("chars", SR.ArgumentOutOfRange_IndexCount);
132 if (byteIndex < 0 || byteIndex > bytes.Length)
133 throw new ArgumentOutOfRangeException("byteIndex", SR.ArgumentOutOfRange_Index);
134 Contract.EndContractBlock();
136 int byteCount = bytes.Length - byteIndex;
138 // Fixed doesn't like empty byte arrays
139 if (bytes.Length == 0)
142 fixed (char* pChars = chars) fixed (byte* pBytes = &bytes[0])
143 return GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, null);
146 // Encodes a range of characters in a character array into a range of bytes
147 // in a byte array. An exception occurs if the byte array is not large
148 // enough to hold the complete encoding of the characters. The
149 // GetByteCount method can be used to determine the exact number of
150 // bytes that will be produced for a given range of characters.
151 // Alternatively, the GetMaxByteCount method can be used to
152 // determine the maximum number of bytes that will be produced for a given
153 // number of characters, regardless of the actual character values.
155 // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
156 // So if you fix this, fix the others. Currently those include:
157 // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
158 // parent method is safe
160 public override unsafe int GetBytes(char[] chars, int charIndex, int charCount,
161 byte[] bytes, int byteIndex)
163 // Validate parameters
164 if (chars == null || bytes == null)
165 throw new ArgumentNullException((chars == null ? "chars" : "bytes"), SR.ArgumentNull_Array);
167 if (charIndex < 0 || charCount < 0)
168 throw new ArgumentOutOfRangeException((charIndex < 0 ? "charIndex" : "charCount"), SR.ArgumentOutOfRange_NeedNonNegNum);
170 if (chars.Length - charIndex < charCount)
171 throw new ArgumentOutOfRangeException("chars", SR.ArgumentOutOfRange_IndexCountBuffer);
173 if (byteIndex < 0 || byteIndex > bytes.Length)
174 throw new ArgumentOutOfRangeException("byteIndex", SR.ArgumentOutOfRange_Index);
175 Contract.EndContractBlock();
177 // If nothing to encode return 0, avoid fixed problem
181 // Just call pointer version
182 int byteCount = bytes.Length - byteIndex;
184 // Fixed doesn't like empty byte arrays
185 if (bytes.Length == 0)
188 fixed (char* pChars = chars) fixed (byte* pBytes = &bytes[0])
189 // Remember that byteCount is # to decode, not size of array.
190 return GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, null);
193 // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
194 // So if you fix this, fix the others. Currently those include:
195 // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
197 [CLSCompliant(false)]
198 public override unsafe int GetBytes(char* chars, int charCount, byte* bytes, int byteCount)
200 // Validate Parameters
201 if (bytes == null || chars == null)
202 throw new ArgumentNullException(bytes == null ? "bytes" : "chars", SR.ArgumentNull_Array);
204 if (charCount < 0 || byteCount < 0)
205 throw new ArgumentOutOfRangeException((charCount < 0 ? "charCount" : "byteCount"), SR.ArgumentOutOfRange_NeedNonNegNum);
206 Contract.EndContractBlock();
208 return GetBytes(chars, charCount, bytes, byteCount, null);
211 // Returns the number of characters produced by decoding a range of bytes
214 // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
215 // So if you fix this, fix the others. Currently those include:
216 // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
217 // parent method is safe
219 public override unsafe int GetCharCount(byte[] bytes, int index, int count)
221 // Validate Parameters
223 throw new ArgumentNullException("bytes", SR.ArgumentNull_Array);
225 if (index < 0 || count < 0)
226 throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"), SR.ArgumentOutOfRange_NeedNonNegNum);
228 if (bytes.Length - index < count)
229 throw new ArgumentOutOfRangeException("bytes", SR.ArgumentOutOfRange_IndexCountBuffer);
230 Contract.EndContractBlock();
232 // If no input just return 0, fixed doesn't like 0 length arrays
236 // Just call pointer version
237 fixed (byte* pBytes = bytes)
238 return GetCharCount(pBytes + index, count, null);
241 // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
242 // So if you fix this, fix the others. Currently those include:
243 // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
245 [CLSCompliant(false)]
246 public override unsafe int GetCharCount(byte* bytes, int count)
248 // Validate Parameters
250 throw new ArgumentNullException("bytes", SR.ArgumentNull_Array);
253 throw new ArgumentOutOfRangeException("count", SR.ArgumentOutOfRange_NeedNonNegNum);
254 Contract.EndContractBlock();
256 return GetCharCount(bytes, count, null);
259 // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
260 // So if you fix this, fix the others. Currently those include:
261 // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
262 // parent method is safe
264 public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount,
265 char[] chars, int charIndex)
267 // Validate Parameters
268 if (bytes == null || chars == null)
269 throw new ArgumentNullException(bytes == null ? "bytes" : "chars", SR.ArgumentNull_Array);
271 if (byteIndex < 0 || byteCount < 0)
272 throw new ArgumentOutOfRangeException((byteIndex < 0 ? "byteIndex" : "byteCount"), SR.ArgumentOutOfRange_NeedNonNegNum);
274 if ( bytes.Length - byteIndex < byteCount)
275 throw new ArgumentOutOfRangeException("bytes", SR.ArgumentOutOfRange_IndexCountBuffer);
277 if (charIndex < 0 || charIndex > chars.Length)
278 throw new ArgumentOutOfRangeException("charIndex", SR.ArgumentOutOfRange_Index);
279 Contract.EndContractBlock();
281 // If no input, return 0 & avoid fixed problem
285 // Just call pointer version
286 int charCount = chars.Length - charIndex;
288 // Fixed doesn't like empty char arrays
289 if (chars.Length == 0)
292 fixed (byte* pBytes = bytes) fixed (char* pChars = &chars[0])
293 // Remember that charCount is # to decode, not size of array
294 return GetChars(pBytes + byteIndex, byteCount, pChars + charIndex, charCount, null);
297 // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
298 // So if you fix this, fix the others. Currently those include:
299 // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
301 [CLSCompliant(false)]
302 public unsafe override int GetChars(byte* bytes, int byteCount, char* chars, int charCount)
304 // Validate Parameters
305 if (bytes == null || chars == null)
306 throw new ArgumentNullException(bytes == null ? "bytes" : "chars", SR.ArgumentNull_Array);
308 if (charCount < 0 || byteCount < 0)
309 throw new ArgumentOutOfRangeException((charCount < 0 ? "charCount" : "byteCount"), SR.ArgumentOutOfRange_NeedNonNegNum);
310 Contract.EndContractBlock();
312 return GetChars(bytes, byteCount, chars, charCount, null);
315 // Returns a string containing the decoded representation of a range of
316 // bytes in a byte array.
318 // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
319 // So if you fix this, fix the others. Currently those include:
320 // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
321 // parent method is safe
323 public override unsafe String GetString(byte[] bytes, int byteIndex, int byteCount)
325 // Validate Parameters
327 throw new ArgumentNullException("bytes", SR.ArgumentNull_Array);
329 if (byteIndex < 0 || byteCount < 0)
330 throw new ArgumentOutOfRangeException((byteIndex < 0 ? "byteIndex" : "byteCount"), SR.ArgumentOutOfRange_NeedNonNegNum);
333 if (bytes.Length - byteIndex < byteCount)
334 throw new ArgumentOutOfRangeException("bytes", SR.ArgumentOutOfRange_IndexCountBuffer);
335 Contract.EndContractBlock();
337 // Avoid problems with empty input buffer
338 if (byteCount == 0) return String.Empty;
340 fixed (byte* pBytes = bytes)
341 return String.CreateStringFromEncoding(
342 pBytes + byteIndex, byteCount, this);
346 // End of standard methods copied from EncodingNLS.cs
350 // Note: We start by assuming that the output will be the same as count. Having
351 // an encoder or fallback may change that assumption
352 internal override unsafe int GetByteCount(char* chars, int charCount, EncoderNLS encoder)
354 // Just need to ASSERT, this is called by something else internal that checked parameters already
355 Debug.Assert(charCount >= 0, "[ASCIIEncoding.GetByteCount]count is negative");
356 Debug.Assert(chars != null, "[ASCIIEncoding.GetByteCount]chars is null");
358 // Assert because we shouldn't be able to have a null encoder.
359 Debug.Assert(encoderFallback != null, "[ASCIIEncoding.GetByteCount]Attempting to use null fallback encoder");
361 char charLeftOver = (char)0;
362 EncoderReplacementFallback fallback = null;
364 // Start by assuming default count, then +/- for fallback characters
365 char* charEnd = chars + charCount;
367 // For fallback we may need a fallback buffer, we know we aren't default fallback.
368 EncoderFallbackBuffer fallbackBuffer = null;
369 char* charsForFallback;
373 charLeftOver = encoder._charLeftOver;
374 Debug.Assert(charLeftOver == 0 || Char.IsHighSurrogate(charLeftOver),
375 "[ASCIIEncoding.GetByteCount]leftover character should be high surrogate");
377 fallback = encoder.Fallback as EncoderReplacementFallback;
379 // We mustn't have left over fallback data when counting
380 if (encoder.InternalHasFallbackBuffer)
382 // We always need the fallback buffer in get bytes so we can flush any remaining ones if necessary
383 fallbackBuffer = encoder.FallbackBuffer;
384 if (fallbackBuffer.Remaining > 0 && encoder._throwOnOverflow)
385 throw new ArgumentException(SR.Format(SR.Argument_EncoderFallbackNotEmpty, this.EncodingName, encoder.Fallback.GetType()));
387 // Set our internal fallback interesting things.
388 fallbackBuffer.InternalInitialize(chars, charEnd, encoder, false);
391 // Verify that we have no fallbackbuffer, for ASCII its always empty, so just assert
392 Debug.Assert(!encoder._throwOnOverflow || !encoder.InternalHasFallbackBuffer ||
393 encoder.FallbackBuffer.Remaining == 0,
394 "[ASCIICodePageEncoding.GetByteCount]Expected empty fallback buffer");
398 fallback = this.EncoderFallback as EncoderReplacementFallback;
401 // If we have an encoder AND we aren't using default fallback,
402 // then we may have a complicated count.
403 if (fallback != null && fallback.MaxCharCount == 1)
405 // Replacement fallback encodes surrogate pairs as two ?? (or two whatever), so return size is always
406 // same as input size.
407 // Note that no existing SBCS code pages map code points to supplimentary characters, so this is easy.
409 // We could however have 1 extra byte if the last call had an encoder and a funky fallback and
410 // if we don't use the funky fallback this time.
412 // Do we have an extra char left over from last time?
413 if (charLeftOver > 0)
419 // Count is more complicated if you have a funky fallback
420 // For fallback we may need a fallback buffer, we know we're not default fallback
423 // We may have a left over character from last time, try and process it.
424 if (charLeftOver > 0)
426 Debug.Assert(Char.IsHighSurrogate(charLeftOver), "[ASCIIEncoding.GetByteCount]leftover character should be high surrogate");
427 Debug.Assert(encoder != null, "[ASCIIEncoding.GetByteCount]Expected encoder");
429 // Since left over char was a surrogate, it'll have to be fallen back.
431 fallbackBuffer = encoder.FallbackBuffer;
432 fallbackBuffer.InternalInitialize(chars, charEnd, encoder, false);
434 // This will fallback a pair if *chars is a low surrogate
435 charsForFallback = chars; // Avoid passing chars by reference to allow it to be enregistered
436 fallbackBuffer.InternalFallback(charLeftOver, ref charsForFallback);
437 chars = charsForFallback;
440 // Now we may have fallback char[] already from the encoder
442 // Go ahead and do it, including the fallback.
444 while ((ch = (fallbackBuffer == null) ? '\0' : fallbackBuffer.InternalGetNextChar()) != 0 ||
447 // First unwind any fallback
450 // No fallback, just get next char
455 // Check for fallback, this'll catch surrogate pairs too.
456 // no chars >= 0x80 are allowed.
459 if (fallbackBuffer == null)
461 // Initialize the buffer
463 fallbackBuffer = this.encoderFallback.CreateFallbackBuffer();
465 fallbackBuffer = encoder.FallbackBuffer;
466 fallbackBuffer.InternalInitialize(charEnd - charCount, charEnd, encoder, false);
470 charsForFallback = chars; // Avoid passing chars by reference to allow it to be enregistered
471 fallbackBuffer.InternalFallback(ch, ref charsForFallback);
472 chars = charsForFallback;
476 // We'll use this one
480 Debug.Assert(fallbackBuffer == null || fallbackBuffer.Remaining == 0,
481 "[ASCIIEncoding.GetByteCount]Expected Empty fallback buffer");
486 internal override unsafe int GetBytes(char* chars, int charCount,
487 byte* bytes, int byteCount, EncoderNLS encoder)
489 // Just need to ASSERT, this is called by something else internal that checked parameters already
490 Debug.Assert(bytes != null, "[ASCIIEncoding.GetBytes]bytes is null");
491 Debug.Assert(byteCount >= 0, "[ASCIIEncoding.GetBytes]byteCount is negative");
492 Debug.Assert(chars != null, "[ASCIIEncoding.GetBytes]chars is null");
493 Debug.Assert(charCount >= 0, "[ASCIIEncoding.GetBytes]charCount is negative");
495 // Assert because we shouldn't be able to have a null encoder.
496 Debug.Assert(encoderFallback != null, "[ASCIIEncoding.GetBytes]Attempting to use null encoder fallback");
498 // Get any left over characters
499 char charLeftOver = (char)0;
500 EncoderReplacementFallback fallback = null;
502 // For fallback we may need a fallback buffer, we know we aren't default fallback.
503 EncoderFallbackBuffer fallbackBuffer = null;
504 char* charsForFallback;
507 char* charEnd = chars + charCount;
508 byte* byteStart = bytes;
509 char* charStart = chars;
513 charLeftOver = encoder._charLeftOver;
514 fallback = encoder.Fallback as EncoderReplacementFallback;
516 // We mustn't have left over fallback data when counting
517 if (encoder.InternalHasFallbackBuffer)
519 // We always need the fallback buffer in get bytes so we can flush any remaining ones if necessary
520 fallbackBuffer = encoder.FallbackBuffer;
521 if (fallbackBuffer.Remaining > 0 && encoder._throwOnOverflow)
522 throw new ArgumentException(SR.Format(SR.Argument_EncoderFallbackNotEmpty, this.EncodingName, encoder.Fallback.GetType()));
524 // Set our internal fallback interesting things.
525 fallbackBuffer.InternalInitialize(charStart, charEnd, encoder, true);
528 Debug.Assert(charLeftOver == 0 || Char.IsHighSurrogate(charLeftOver),
529 "[ASCIIEncoding.GetBytes]leftover character should be high surrogate");
531 // Verify that we have no fallbackbuffer, for ASCII its always empty, so just assert
532 Debug.Assert(!encoder._throwOnOverflow || !encoder.InternalHasFallbackBuffer ||
533 encoder.FallbackBuffer.Remaining == 0,
534 "[ASCIICodePageEncoding.GetBytes]Expected empty fallback buffer");
538 fallback = this.EncoderFallback as EncoderReplacementFallback;
542 // See if we do the fast default or slightly slower fallback
543 if (fallback != null && fallback.MaxCharCount == 1)
546 char cReplacement = fallback.DefaultString[0];
548 // Check for replacements in range, otherwise fall back to slow version.
549 if (cReplacement <= (char)0x7f)
551 // We should have exactly as many output bytes as input bytes, unless there's a left
552 // over character, in which case we may need one more.
553 // If we had a left over character will have to add a ? (This happens if they had a funky
554 // fallback last time, but not this time.) (We can't spit any out though
555 // because with fallback encoder each surrogate is treated as a seperate code point)
556 if (charLeftOver > 0)
559 // Throw even if doing no throw version because this is just 1 char,
560 // so buffer will never be big enough
562 ThrowBytesOverflow(encoder, true);
564 // This'll make sure we still have more room and also make sure our return value is correct.
565 *(bytes++) = (byte)cReplacement;
566 byteCount--; // We used one of the ones we were counting.
569 // This keeps us from overrunning our output buffer
570 if (byteCount < charCount)
572 // Throw or make buffer smaller?
573 ThrowBytesOverflow(encoder, byteCount < 1);
575 // Just use what we can
576 charEnd = chars + byteCount;
579 // We just do a quick copy
580 while (chars < charEnd)
582 char ch2 = *(chars++);
583 if (ch2 >= 0x0080) *(bytes++) = (byte)cReplacement;
584 else *(bytes++) = unchecked((byte)(ch2));
590 encoder._charLeftOver = (char)0;
591 encoder._charsUsed = (int)(chars - charStart);
594 return (int)(bytes - byteStart);
598 // Slower version, have to do real fallback.
601 byte* byteEnd = bytes + byteCount;
603 // We may have a left over character from last time, try and process it.
604 if (charLeftOver > 0)
606 // Initialize the buffer
607 Debug.Assert(encoder != null,
608 "[ASCIIEncoding.GetBytes]Expected non null encoder if we have surrogate left over");
609 fallbackBuffer = encoder.FallbackBuffer;
610 fallbackBuffer.InternalInitialize(chars, charEnd, encoder, true);
612 // Since left over char was a surrogate, it'll have to be fallen back.
614 // This will fallback a pair if *chars is a low surrogate
615 charsForFallback = chars; // Avoid passing chars by reference to allow it to be enregistered
616 fallbackBuffer.InternalFallback(charLeftOver, ref charsForFallback);
617 chars = charsForFallback;
620 // Now we may have fallback char[] already from the encoder
622 // Go ahead and do it, including the fallback.
624 while ((ch = (fallbackBuffer == null) ? '\0' : fallbackBuffer.InternalGetNextChar()) != 0 ||
627 // First unwind any fallback
630 // No fallback, just get next char
635 // Check for fallback, this'll catch surrogate pairs too.
636 // All characters >= 0x80 must fall back.
639 // Initialize the buffer
640 if (fallbackBuffer == null)
643 fallbackBuffer = this.encoderFallback.CreateFallbackBuffer();
645 fallbackBuffer = encoder.FallbackBuffer;
646 fallbackBuffer.InternalInitialize(charEnd - charCount, charEnd, encoder, true);
650 charsForFallback = chars; // Avoid passing chars by reference to allow it to be enregistered
651 fallbackBuffer.InternalFallback(ch, ref charsForFallback);
652 chars = charsForFallback;
654 // Go ahead & continue (& do the fallback)
658 // We'll use this one
660 if (bytes >= byteEnd)
662 // didn't use this char, we'll throw or use buffer
663 if (fallbackBuffer == null || fallbackBuffer.bFallingBack == false)
665 Debug.Assert(chars > charStart || bytes == byteStart,
666 "[ASCIIEncoding.GetBytes]Expected chars to have advanced already.");
667 chars--; // don't use last char
670 fallbackBuffer.MovePrevious();
672 // Are we throwing or using buffer?
673 ThrowBytesOverflow(encoder, bytes == byteStart); // throw?
674 break; // don't throw, stop
677 // Go ahead and add it
678 *bytes = unchecked((byte)ch);
682 // Need to do encoder stuff
685 // Fallback stuck it in encoder if necessary, but we have to clear MustFlush cases
686 if (fallbackBuffer != null && !fallbackBuffer.bUsedEncoder)
687 // Clear it in case of MustFlush
688 encoder._charLeftOver = (char)0;
690 // Set our chars used count
691 encoder._charsUsed = (int)(chars - charStart);
694 Debug.Assert(fallbackBuffer == null || fallbackBuffer.Remaining == 0 ||
695 (encoder != null && !encoder._throwOnOverflow),
696 "[ASCIIEncoding.GetBytes]Expected Empty fallback buffer at end");
698 return (int)(bytes - byteStart);
701 // This is internal and called by something else,
702 internal override unsafe int GetCharCount(byte* bytes, int count, DecoderNLS decoder)
704 // Just assert, we're called internally so these should be safe, checked already
705 Debug.Assert(bytes != null, "[ASCIIEncoding.GetCharCount]bytes is null");
706 Debug.Assert(count >= 0, "[ASCIIEncoding.GetCharCount]byteCount is negative");
708 // ASCII doesn't do best fit, so don't have to check for it, find out which decoder fallback we're using
709 DecoderReplacementFallback fallback = null;
712 fallback = this.DecoderFallback as DecoderReplacementFallback;
715 fallback = decoder.Fallback as DecoderReplacementFallback;
716 Debug.Assert(!decoder._throwOnOverflow || !decoder.InternalHasFallbackBuffer ||
717 decoder.FallbackBuffer.Remaining == 0,
718 "[ASCIICodePageEncoding.GetCharCount]Expected empty fallback buffer");
721 if (fallback != null && fallback.MaxCharCount == 1)
723 // Just return length, SBCS stay the same length because they don't map to surrogate
724 // pairs and we don't have a decoder fallback.
729 // Only need decoder fallback buffer if not using default replacement fallback, no best fit for ASCII
730 DecoderFallbackBuffer fallbackBuffer = null;
732 // Have to do it the hard way.
733 // Assume charCount will be == count
734 int charCount = count;
735 byte[] byteBuffer = new byte[1];
737 // Do it our fast way
738 byte* byteEnd = bytes + count;
741 while (bytes < byteEnd)
743 // Faster if don't use *bytes++;
747 // If unknown we have to do fallback count
750 if (fallbackBuffer == null)
753 fallbackBuffer = this.DecoderFallback.CreateFallbackBuffer();
755 fallbackBuffer = decoder.FallbackBuffer;
756 fallbackBuffer.InternalInitialize(byteEnd - count, null);
759 // Use fallback buffer
761 charCount--; // Have to unreserve the one we already allocated for b
762 charCount += fallbackBuffer.InternalFallback(byteBuffer, bytes);
766 // Fallback buffer must be empty
767 Debug.Assert(fallbackBuffer == null || fallbackBuffer.Remaining == 0,
768 "[ASCIIEncoding.GetCharCount]Expected Empty fallback buffer");
770 // Converted sequence is same length as input
774 internal override unsafe int GetChars(byte* bytes, int byteCount,
775 char* chars, int charCount, DecoderNLS decoder)
777 // Just need to ASSERT, this is called by something else internal that checked parameters already
778 Debug.Assert(bytes != null, "[ASCIIEncoding.GetChars]bytes is null");
779 Debug.Assert(byteCount >= 0, "[ASCIIEncoding.GetChars]byteCount is negative");
780 Debug.Assert(chars != null, "[ASCIIEncoding.GetChars]chars is null");
781 Debug.Assert(charCount >= 0, "[ASCIIEncoding.GetChars]charCount is negative");
783 // Do it fast way if using ? replacement fallback
784 byte* byteEnd = bytes + byteCount;
785 byte* byteStart = bytes;
786 char* charStart = chars;
788 // Note: ASCII doesn't do best fit, but we have to fallback if they use something > 0x7f
789 // Only need decoder fallback buffer if not using ? fallback.
790 // ASCII doesn't do best fit, so don't have to check for it, find out which decoder fallback we're using
791 DecoderReplacementFallback fallback = null;
792 char* charsForFallback;
795 fallback = this.DecoderFallback as DecoderReplacementFallback;
798 fallback = decoder.Fallback as DecoderReplacementFallback;
799 Debug.Assert(!decoder._throwOnOverflow || !decoder.InternalHasFallbackBuffer ||
800 decoder.FallbackBuffer.Remaining == 0,
801 "[ASCIICodePageEncoding.GetChars]Expected empty fallback buffer");
804 if (fallback != null && fallback.MaxCharCount == 1)
806 // Try it the fast way
807 char replacementChar = fallback.DefaultString[0];
809 // Need byteCount chars, otherwise too small buffer
810 if (charCount < byteCount)
812 // Need at least 1 output byte, throw if must throw
813 ThrowCharsOverflow(decoder, charCount < 1);
815 // Not throwing, use what we can
816 byteEnd = bytes + charCount;
819 // Quick loop, just do '?' replacement because we don't have fallbacks for decodings.
820 while (bytes < byteEnd)
824 // This is an invalid byte in the ASCII encoding.
825 *(chars++) = replacementChar;
827 *(chars++) = unchecked((char)b);
830 // bytes & chars used are the same
832 decoder._bytesUsed = (int)(bytes - byteStart);
833 return (int)(chars - charStart);
836 // Slower way's going to need a fallback buffer
837 DecoderFallbackBuffer fallbackBuffer = null;
838 byte[] byteBuffer = new byte[1];
839 char* charEnd = chars + charCount;
841 // Not quite so fast loop
842 while (bytes < byteEnd)
844 // Faster if don't use *bytes++;
850 // This is an invalid byte in the ASCII encoding.
851 if (fallbackBuffer == null)
854 fallbackBuffer = this.DecoderFallback.CreateFallbackBuffer();
856 fallbackBuffer = decoder.FallbackBuffer;
857 fallbackBuffer.InternalInitialize(byteEnd - byteCount, charEnd);
860 // Use fallback buffer
863 // Note that chars won't get updated unless this succeeds
864 charsForFallback = chars; // Avoid passing chars by reference to allow it to be enregistered
865 bool fallbackResult = fallbackBuffer.InternalFallback(byteBuffer, bytes, ref charsForFallback);
866 chars = charsForFallback;
870 // May or may not throw, but we didn't get this byte
871 Debug.Assert(bytes > byteStart || chars == charStart,
872 "[ASCIIEncoding.GetChars]Expected bytes to have advanced already (fallback case)");
873 bytes--; // unused byte
874 fallbackBuffer.InternalReset(); // Didn't fall this back
875 ThrowCharsOverflow(decoder, chars == charStart); // throw?
876 break; // don't throw, but stop loop
881 // Make sure we have buffer space
882 if (chars >= charEnd)
884 Debug.Assert(bytes > byteStart || chars == charStart,
885 "[ASCIIEncoding.GetChars]Expected bytes to have advanced already (normal case)");
886 bytes--; // unused byte
887 ThrowCharsOverflow(decoder, chars == charStart); // throw?
888 break; // don't throw, but stop loop
891 *(chars) = unchecked((char)b);
896 // Might have had decoder fallback stuff.
898 decoder._bytesUsed = (int)(bytes - byteStart);
900 // Expect Empty fallback buffer for GetChars
901 Debug.Assert(fallbackBuffer == null || fallbackBuffer.Remaining == 0,
902 "[ASCIIEncoding.GetChars]Expected Empty fallback buffer");
904 return (int)(chars - charStart);
908 public override int GetMaxByteCount(int charCount)
911 throw new ArgumentOutOfRangeException(nameof(charCount),
912 SR.ArgumentOutOfRange_NeedNonNegNum);
913 Contract.EndContractBlock();
915 // Characters would be # of characters + 1 in case high surrogate is ? * max fallback
916 long byteCount = (long)charCount + 1;
918 if (EncoderFallback.MaxCharCount > 1)
919 byteCount *= EncoderFallback.MaxCharCount;
921 // 1 to 1 for most characters. Only surrogates with fallbacks have less.
923 if (byteCount > 0x7fffffff)
924 throw new ArgumentOutOfRangeException(nameof(charCount), SR.ArgumentOutOfRange_GetByteCountOverflow);
925 return (int)byteCount;
929 public override int GetMaxCharCount(int byteCount)
932 throw new ArgumentOutOfRangeException(nameof(byteCount),
933 SR.ArgumentOutOfRange_NeedNonNegNum);
934 Contract.EndContractBlock();
936 // Just return length, SBCS stay the same length because they don't map to surrogate
937 long charCount = (long)byteCount;
939 // 1 to 1 for most characters. Only surrogates with fallbacks have less, unknown fallbacks could be longer.
940 if (DecoderFallback.MaxCharCount > 1)
941 charCount *= DecoderFallback.MaxCharCount;
943 if (charCount > 0x7fffffff)
944 throw new ArgumentOutOfRangeException(nameof(byteCount), SR.ArgumentOutOfRange_GetCharCountOverflow);
946 return (int)charCount;
949 // True if and only if the encoding only uses single byte code points. (Ie, ASCII, 1252, etc)
951 public override bool IsSingleByte
959 public override Decoder GetDecoder()
961 return new DecoderNLS(this);
965 public override Encoder GetEncoder()
967 return new EncoderNLS(this);