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;
8 using System.Runtime.Serialization;
14 // Note that ASCIIEncoding is optimized with no best fit and ? for fallback.
15 // It doesn't come in other flavors.
17 // Note: ASCIIEncoding is the only encoding that doesn't do best fit (windows has best fit).
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.
22 public class ASCIIEncoding : Encoding
24 // Allow for devirtualization (see https://github.com/dotnet/coreclr/pull/9230)
25 internal sealed class ASCIIEncodingSealed : ASCIIEncoding { }
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();
31 public ASCIIEncoding() : base(Encoding.CodePageASCII)
35 internal override void SetDefaultFallbacks()
37 // For ASCIIEncoding we just use default replacement fallback
38 this.encoderFallback = EncoderFallback.ReplacementFallback;
39 this.decoderFallback = DecoderFallback.ReplacementFallback;
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.
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
51 // Returns the number of bytes required to encode a range of characters in
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
59 public override unsafe int GetByteCount(char[] chars, int index, int count)
61 // Validate input parameters
63 throw new ArgumentNullException("chars", SR.ArgumentNull_Array);
65 if (index < 0 || count < 0)
66 throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"), SR.ArgumentOutOfRange_NeedNonNegNum);
68 if (chars.Length - index < count)
69 throw new ArgumentOutOfRangeException("chars", SR.ArgumentOutOfRange_IndexCountBuffer);
70 Contract.EndContractBlock();
72 // If no input, return 0, avoid fixed empty array problem
76 // Just call the pointer version
77 fixed (char* pChars = chars)
78 return GetByteCount(pChars + index, count, null);
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
86 public override unsafe int GetByteCount(String chars)
90 throw new ArgumentNullException("chars");
91 Contract.EndContractBlock();
93 fixed (char* pChars = chars)
94 return GetByteCount(pChars, chars.Length, null);
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
101 [CLSCompliant(false)]
102 public override unsafe int GetByteCount(char* chars, int count)
104 // Validate Parameters
106 throw new ArgumentNullException("chars", SR.ArgumentNull_Array);
109 throw new ArgumentOutOfRangeException("count", SR.ArgumentOutOfRange_NeedNonNegNum);
110 Contract.EndContractBlock();
112 // Call it with empty encoder
113 return GetByteCount(chars, count, null);
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
121 public override unsafe int GetBytes(String chars, int charIndex, int charCount,
122 byte[] bytes, int byteIndex)
124 if (chars == null || bytes == null)
125 throw new ArgumentNullException((chars == null ? "chars" : "bytes"), SR.ArgumentNull_Array);
127 if (charIndex < 0 || charCount < 0)
128 throw new ArgumentOutOfRangeException((charIndex < 0 ? "charIndex" : "charCount"), SR.ArgumentOutOfRange_NeedNonNegNum);
130 if (chars.Length - charIndex < charCount)
131 throw new ArgumentOutOfRangeException("chars", SR.ArgumentOutOfRange_IndexCount);
133 if (byteIndex < 0 || byteIndex > bytes.Length)
134 throw new ArgumentOutOfRangeException("byteIndex", SR.ArgumentOutOfRange_Index);
135 Contract.EndContractBlock();
137 int byteCount = bytes.Length - byteIndex;
139 // Fixed doesn't like empty byte arrays
140 if (bytes.Length == 0)
143 fixed (char* pChars = chars) fixed (byte* pBytes = &bytes[0])
144 return GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, null);
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.
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
161 public override unsafe int GetBytes(char[] chars, int charIndex, int charCount,
162 byte[] bytes, int byteIndex)
164 // Validate parameters
165 if (chars == null || bytes == null)
166 throw new ArgumentNullException((chars == null ? "chars" : "bytes"), SR.ArgumentNull_Array);
168 if (charIndex < 0 || charCount < 0)
169 throw new ArgumentOutOfRangeException((charIndex < 0 ? "charIndex" : "charCount"), SR.ArgumentOutOfRange_NeedNonNegNum);
171 if (chars.Length - charIndex < charCount)
172 throw new ArgumentOutOfRangeException("chars", SR.ArgumentOutOfRange_IndexCountBuffer);
174 if (byteIndex < 0 || byteIndex > bytes.Length)
175 throw new ArgumentOutOfRangeException("byteIndex", SR.ArgumentOutOfRange_Index);
176 Contract.EndContractBlock();
178 // If nothing to encode return 0, avoid fixed problem
182 // Just call pointer version
183 int byteCount = bytes.Length - byteIndex;
185 // Fixed doesn't like empty byte arrays
186 if (bytes.Length == 0)
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);
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
198 [CLSCompliant(false)]
199 public override unsafe int GetBytes(char* chars, int charCount, byte* bytes, int byteCount)
201 // Validate Parameters
202 if (bytes == null || chars == null)
203 throw new ArgumentNullException(bytes == null ? "bytes" : "chars", SR.ArgumentNull_Array);
205 if (charCount < 0 || byteCount < 0)
206 throw new ArgumentOutOfRangeException((charCount < 0 ? "charCount" : "byteCount"), SR.ArgumentOutOfRange_NeedNonNegNum);
207 Contract.EndContractBlock();
209 return GetBytes(chars, charCount, bytes, byteCount, null);
212 // Returns the number of characters produced by decoding a range of bytes
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
220 public override unsafe int GetCharCount(byte[] bytes, int index, int count)
222 // Validate Parameters
224 throw new ArgumentNullException("bytes", SR.ArgumentNull_Array);
226 if (index < 0 || count < 0)
227 throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"), SR.ArgumentOutOfRange_NeedNonNegNum);
229 if (bytes.Length - index < count)
230 throw new ArgumentOutOfRangeException("bytes", SR.ArgumentOutOfRange_IndexCountBuffer);
231 Contract.EndContractBlock();
233 // If no input just return 0, fixed doesn't like 0 length arrays
237 // Just call pointer version
238 fixed (byte* pBytes = bytes)
239 return GetCharCount(pBytes + index, count, null);
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
246 [CLSCompliant(false)]
247 public override unsafe int GetCharCount(byte* bytes, int count)
249 // Validate Parameters
251 throw new ArgumentNullException("bytes", SR.ArgumentNull_Array);
254 throw new ArgumentOutOfRangeException("count", SR.ArgumentOutOfRange_NeedNonNegNum);
255 Contract.EndContractBlock();
257 return GetCharCount(bytes, count, null);
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
265 public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount,
266 char[] chars, int charIndex)
268 // Validate Parameters
269 if (bytes == null || chars == null)
270 throw new ArgumentNullException(bytes == null ? "bytes" : "chars", SR.ArgumentNull_Array);
272 if (byteIndex < 0 || byteCount < 0)
273 throw new ArgumentOutOfRangeException((byteIndex < 0 ? "byteIndex" : "byteCount"), SR.ArgumentOutOfRange_NeedNonNegNum);
275 if ( bytes.Length - byteIndex < byteCount)
276 throw new ArgumentOutOfRangeException("bytes", SR.ArgumentOutOfRange_IndexCountBuffer);
278 if (charIndex < 0 || charIndex > chars.Length)
279 throw new ArgumentOutOfRangeException("charIndex", SR.ArgumentOutOfRange_Index);
280 Contract.EndContractBlock();
282 // If no input, return 0 & avoid fixed problem
286 // Just call pointer version
287 int charCount = chars.Length - charIndex;
289 // Fixed doesn't like empty char arrays
290 if (chars.Length == 0)
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);
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
302 [CLSCompliant(false)]
303 public unsafe override int GetChars(byte* bytes, int byteCount, char* chars, int charCount)
305 // Validate Parameters
306 if (bytes == null || chars == null)
307 throw new ArgumentNullException(bytes == null ? "bytes" : "chars", SR.ArgumentNull_Array);
309 if (charCount < 0 || byteCount < 0)
310 throw new ArgumentOutOfRangeException((charCount < 0 ? "charCount" : "byteCount"), SR.ArgumentOutOfRange_NeedNonNegNum);
311 Contract.EndContractBlock();
313 return GetChars(bytes, byteCount, chars, charCount, null);
316 // Returns a string containing the decoded representation of a range of
317 // bytes in a byte array.
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
324 public override unsafe String GetString(byte[] bytes, int byteIndex, int byteCount)
326 // Validate Parameters
328 throw new ArgumentNullException("bytes", SR.ArgumentNull_Array);
330 if (byteIndex < 0 || byteCount < 0)
331 throw new ArgumentOutOfRangeException((byteIndex < 0 ? "byteIndex" : "byteCount"), SR.ArgumentOutOfRange_NeedNonNegNum);
334 if (bytes.Length - byteIndex < byteCount)
335 throw new ArgumentOutOfRangeException("bytes", SR.ArgumentOutOfRange_IndexCountBuffer);
336 Contract.EndContractBlock();
338 // Avoid problems with empty input buffer
339 if (byteCount == 0) return String.Empty;
341 fixed (byte* pBytes = bytes)
342 return String.CreateStringFromEncoding(
343 pBytes + byteIndex, byteCount, this);
347 // End of standard methods copied from EncodingNLS.cs
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)
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");
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");
362 char charLeftOver = (char)0;
363 EncoderReplacementFallback fallback = null;
365 // Start by assuming default count, then +/- for fallback characters
366 char* charEnd = chars + charCount;
368 // For fallback we may need a fallback buffer, we know we aren't default fallback.
369 EncoderFallbackBuffer fallbackBuffer = null;
370 char* charsForFallback;
374 charLeftOver = encoder.charLeftOver;
375 Debug.Assert(charLeftOver == 0 || Char.IsHighSurrogate(charLeftOver),
376 "[ASCIIEncoding.GetByteCount]leftover character should be high surrogate");
378 fallback = encoder.Fallback as EncoderReplacementFallback;
380 // We mustn't have left over fallback data when counting
381 if (encoder.InternalHasFallbackBuffer)
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()));
388 // Set our internal fallback interesting things.
389 fallbackBuffer.InternalInitialize(chars, charEnd, encoder, false);
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");
399 fallback = this.EncoderFallback as EncoderReplacementFallback;
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)
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.
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.
413 // Do we have an extra char left over from last time?
414 if (charLeftOver > 0)
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
424 // We may have a left over character from last time, try and process it.
425 if (charLeftOver > 0)
427 Debug.Assert(Char.IsHighSurrogate(charLeftOver), "[ASCIIEncoding.GetByteCount]leftover character should be high surrogate");
428 Debug.Assert(encoder != null, "[ASCIIEncoding.GetByteCount]Expected encoder");
430 // Since left over char was a surrogate, it'll have to be fallen back.
432 fallbackBuffer = encoder.FallbackBuffer;
433 fallbackBuffer.InternalInitialize(chars, charEnd, encoder, false);
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;
441 // Now we may have fallback char[] already from the encoder
443 // Go ahead and do it, including the fallback.
445 while ((ch = (fallbackBuffer == null) ? '\0' : fallbackBuffer.InternalGetNextChar()) != 0 ||
448 // First unwind any fallback
451 // No fallback, just get next char
456 // Check for fallback, this'll catch surrogate pairs too.
457 // no chars >= 0x80 are allowed.
460 if (fallbackBuffer == null)
462 // Initialize the buffer
464 fallbackBuffer = this.encoderFallback.CreateFallbackBuffer();
466 fallbackBuffer = encoder.FallbackBuffer;
467 fallbackBuffer.InternalInitialize(charEnd - charCount, charEnd, encoder, false);
471 charsForFallback = chars; // Avoid passing chars by reference to allow it to be enregistered
472 fallbackBuffer.InternalFallback(ch, ref charsForFallback);
473 chars = charsForFallback;
477 // We'll use this one
481 Debug.Assert(fallbackBuffer == null || fallbackBuffer.Remaining == 0,
482 "[ASCIIEncoding.GetByteCount]Expected Empty fallback buffer");
487 internal override unsafe int GetBytes(char* chars, int charCount,
488 byte* bytes, int byteCount, EncoderNLS encoder)
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");
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");
499 // Get any left over characters
500 char charLeftOver = (char)0;
501 EncoderReplacementFallback fallback = null;
503 // For fallback we may need a fallback buffer, we know we aren't default fallback.
504 EncoderFallbackBuffer fallbackBuffer = null;
505 char* charsForFallback;
508 char* charEnd = chars + charCount;
509 byte* byteStart = bytes;
510 char* charStart = chars;
514 charLeftOver = encoder.charLeftOver;
515 fallback = encoder.Fallback as EncoderReplacementFallback;
517 // We mustn't have left over fallback data when counting
518 if (encoder.InternalHasFallbackBuffer)
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()));
525 // Set our internal fallback interesting things.
526 fallbackBuffer.InternalInitialize(charStart, charEnd, encoder, true);
529 Debug.Assert(charLeftOver == 0 || Char.IsHighSurrogate(charLeftOver),
530 "[ASCIIEncoding.GetBytes]leftover character should be high surrogate");
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");
539 fallback = this.EncoderFallback as EncoderReplacementFallback;
543 // See if we do the fast default or slightly slower fallback
544 if (fallback != null && fallback.MaxCharCount == 1)
547 char cReplacement = fallback.DefaultString[0];
549 // Check for replacements in range, otherwise fall back to slow version.
550 if (cReplacement <= (char)0x7f)
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)
560 // Throw even if doing no throw version because this is just 1 char,
561 // so buffer will never be big enough
563 ThrowBytesOverflow(encoder, true);
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.
570 // This keeps us from overrunning our output buffer
571 if (byteCount < charCount)
573 // Throw or make buffer smaller?
574 ThrowBytesOverflow(encoder, byteCount < 1);
576 // Just use what we can
577 charEnd = chars + byteCount;
580 // We just do a quick copy
581 while (chars < charEnd)
583 char ch2 = *(chars++);
584 if (ch2 >= 0x0080) *(bytes++) = (byte)cReplacement;
585 else *(bytes++) = unchecked((byte)(ch2));
591 encoder.charLeftOver = (char)0;
592 encoder.m_charsUsed = (int)(chars - charStart);
595 return (int)(bytes - byteStart);
599 // Slower version, have to do real fallback.
602 byte* byteEnd = bytes + byteCount;
604 // We may have a left over character from last time, try and process it.
605 if (charLeftOver > 0)
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);
613 // Since left over char was a surrogate, it'll have to be fallen back.
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;
621 // Now we may have fallback char[] already from the encoder
623 // Go ahead and do it, including the fallback.
625 while ((ch = (fallbackBuffer == null) ? '\0' : fallbackBuffer.InternalGetNextChar()) != 0 ||
628 // First unwind any fallback
631 // No fallback, just get next char
636 // Check for fallback, this'll catch surrogate pairs too.
637 // All characters >= 0x80 must fall back.
640 // Initialize the buffer
641 if (fallbackBuffer == null)
644 fallbackBuffer = this.encoderFallback.CreateFallbackBuffer();
646 fallbackBuffer = encoder.FallbackBuffer;
647 fallbackBuffer.InternalInitialize(charEnd - charCount, charEnd, encoder, true);
651 charsForFallback = chars; // Avoid passing chars by reference to allow it to be enregistered
652 fallbackBuffer.InternalFallback(ch, ref charsForFallback);
653 chars = charsForFallback;
655 // Go ahead & continue (& do the fallback)
659 // We'll use this one
661 if (bytes >= byteEnd)
663 // didn't use this char, we'll throw or use buffer
664 if (fallbackBuffer == null || fallbackBuffer.bFallingBack == false)
666 Debug.Assert(chars > charStart || bytes == byteStart,
667 "[ASCIIEncoding.GetBytes]Expected chars to have advanced already.");
668 chars--; // don't use last char
671 fallbackBuffer.MovePrevious();
673 // Are we throwing or using buffer?
674 ThrowBytesOverflow(encoder, bytes == byteStart); // throw?
675 break; // don't throw, stop
678 // Go ahead and add it
679 *bytes = unchecked((byte)ch);
683 // Need to do encoder stuff
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;
691 // Set our chars used count
692 encoder.m_charsUsed = (int)(chars - charStart);
695 Debug.Assert(fallbackBuffer == null || fallbackBuffer.Remaining == 0 ||
696 (encoder != null && !encoder.m_throwOnOverflow),
697 "[ASCIIEncoding.GetBytes]Expected Empty fallback buffer at end");
699 return (int)(bytes - byteStart);
702 // This is internal and called by something else,
703 internal override unsafe int GetCharCount(byte* bytes, int count, DecoderNLS decoder)
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");
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;
713 fallback = this.DecoderFallback as DecoderReplacementFallback;
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");
722 if (fallback != null && fallback.MaxCharCount == 1)
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.
730 // Only need decoder fallback buffer if not using default replacement fallback, no best fit for ASCII
731 DecoderFallbackBuffer fallbackBuffer = null;
733 // Have to do it the hard way.
734 // Assume charCount will be == count
735 int charCount = count;
736 byte[] byteBuffer = new byte[1];
738 // Do it our fast way
739 byte* byteEnd = bytes + count;
742 while (bytes < byteEnd)
744 // Faster if don't use *bytes++;
748 // If unknown we have to do fallback count
751 if (fallbackBuffer == null)
754 fallbackBuffer = this.DecoderFallback.CreateFallbackBuffer();
756 fallbackBuffer = decoder.FallbackBuffer;
757 fallbackBuffer.InternalInitialize(byteEnd - count, null);
760 // Use fallback buffer
762 charCount--; // Have to unreserve the one we already allocated for b
763 charCount += fallbackBuffer.InternalFallback(byteBuffer, bytes);
767 // Fallback buffer must be empty
768 Debug.Assert(fallbackBuffer == null || fallbackBuffer.Remaining == 0,
769 "[ASCIIEncoding.GetCharCount]Expected Empty fallback buffer");
771 // Converted sequence is same length as input
775 internal override unsafe int GetChars(byte* bytes, int byteCount,
776 char* chars, int charCount, DecoderNLS decoder)
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");
784 // Do it fast way if using ? replacement fallback
785 byte* byteEnd = bytes + byteCount;
786 byte* byteStart = bytes;
787 char* charStart = chars;
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;
796 fallback = this.DecoderFallback as DecoderReplacementFallback;
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");
805 if (fallback != null && fallback.MaxCharCount == 1)
807 // Try it the fast way
808 char replacementChar = fallback.DefaultString[0];
810 // Need byteCount chars, otherwise too small buffer
811 if (charCount < byteCount)
813 // Need at least 1 output byte, throw if must throw
814 ThrowCharsOverflow(decoder, charCount < 1);
816 // Not throwing, use what we can
817 byteEnd = bytes + charCount;
820 // Quick loop, just do '?' replacement because we don't have fallbacks for decodings.
821 while (bytes < byteEnd)
825 // This is an invalid byte in the ASCII encoding.
826 *(chars++) = replacementChar;
828 *(chars++) = unchecked((char)b);
831 // bytes & chars used are the same
833 decoder.m_bytesUsed = (int)(bytes - byteStart);
834 return (int)(chars - charStart);
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;
842 // Not quite so fast loop
843 while (bytes < byteEnd)
845 // Faster if don't use *bytes++;
851 // This is an invalid byte in the ASCII encoding.
852 if (fallbackBuffer == null)
855 fallbackBuffer = this.DecoderFallback.CreateFallbackBuffer();
857 fallbackBuffer = decoder.FallbackBuffer;
858 fallbackBuffer.InternalInitialize(byteEnd - byteCount, charEnd);
861 // Use fallback buffer
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;
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
882 // Make sure we have buffer space
883 if (chars >= charEnd)
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
892 *(chars) = unchecked((char)b);
897 // Might have had decoder fallback stuff.
899 decoder.m_bytesUsed = (int)(bytes - byteStart);
901 // Expect Empty fallback buffer for GetChars
902 Debug.Assert(fallbackBuffer == null || fallbackBuffer.Remaining == 0,
903 "[ASCIIEncoding.GetChars]Expected Empty fallback buffer");
905 return (int)(chars - charStart);
909 public override int GetMaxByteCount(int charCount)
912 throw new ArgumentOutOfRangeException(nameof(charCount),
913 SR.ArgumentOutOfRange_NeedNonNegNum);
914 Contract.EndContractBlock();
916 // Characters would be # of characters + 1 in case high surrogate is ? * max fallback
917 long byteCount = (long)charCount + 1;
919 if (EncoderFallback.MaxCharCount > 1)
920 byteCount *= EncoderFallback.MaxCharCount;
922 // 1 to 1 for most characters. Only surrogates with fallbacks have less.
924 if (byteCount > 0x7fffffff)
925 throw new ArgumentOutOfRangeException(nameof(charCount), SR.ArgumentOutOfRange_GetByteCountOverflow);
926 return (int)byteCount;
930 public override int GetMaxCharCount(int byteCount)
933 throw new ArgumentOutOfRangeException(nameof(byteCount),
934 SR.ArgumentOutOfRange_NeedNonNegNum);
935 Contract.EndContractBlock();
937 // Just return length, SBCS stay the same length because they don't map to surrogate
938 long charCount = (long)byteCount;
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;
944 if (charCount > 0x7fffffff)
945 throw new ArgumentOutOfRangeException(nameof(byteCount), SR.ArgumentOutOfRange_GetCharCountOverflow);
947 return (int)charCount;
950 // True if and only if the encoding only uses single byte code points. (Ie, ASCII, 1252, etc)
952 public override bool IsSingleByte
960 public override Decoder GetDecoder()
962 return new DecoderNLS(this);
966 public override Encoder GetEncoder()
968 return new EncoderNLS(this);