< Summary

Line coverage
11%
Covered lines: 31
Uncovered lines: 241
Coverable lines: 272
Total lines: 883
Line coverage: 11.3%
Branch coverage
4%
Covered branches: 10
Total branches: 216
Branch coverage: 4.6%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Private.CoreLib/src/System/Text/ASCIIEncoding.cs

#LineLine coverage
 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
 4using System.Buffers;
 5using System.Buffers.Text;
 6using System.Diagnostics;
 7using System.Diagnostics.CodeAnalysis;
 8using System.Runtime.CompilerServices;
 9using System.Runtime.InteropServices;
 10
 11namespace System.Text
 12{
 13    // ASCIIEncoding
 14    //
 15    // Note that ASCIIEncoding is optimized with no best fit and ? for fallback.
 16    // It doesn't come in other flavors.
 17    //
 18    // Note: ASCIIEncoding is the only encoding that doesn't do best fit (windows has best fit).
 19    //
 20    // Note: IsAlwaysNormalized remains false because 1/2 the code points are unassigned, so they'd
 21    //       use fallbacks, and we cannot guarantee that fallbacks are normalized.
 22
 23    public partial class ASCIIEncoding : Encoding
 24    {
 25        // This specialized sealed type has two benefits:
 26        // 1) it allows for devirtualization (see https://github.com/dotnet/coreclr/pull/9230), and
 27        // 2) it allows us to provide highly optimized implementations of certain routines because
 28        //    we can make assumptions about the fallback mechanisms in use (in particular, always
 29        //    replace with "?").
 30        //
 31        // (We don't take advantage of #2 yet, but we can do so in the future because the implementation
 32        // of cloning below allows us to make assumptions about the behaviors of the sealed type.)
 33        internal sealed class ASCIIEncodingSealed : ASCIIEncoding
 34        {
 35            public override object Clone()
 36            {
 37                // The base implementation of Encoding.Clone calls object.MemberwiseClone and marks the new object mutab
 38                // We don't want to do this because it violates the invariants we have set for the sealed type.
 39                // Instead, we'll create a new instance of the base ASCIIEncoding type and mark it mutable.
 40
 041                return new ASCIIEncoding()
 042                {
 043                    IsReadOnly = false
 044                };
 45            }
 46        }
 47
 48        // Used by Encoding.ASCII for lazy initialization
 49        // The initialization code will not be run until a static member of the class is referenced
 050        internal static readonly ASCIIEncodingSealed s_default = new ASCIIEncodingSealed();
 51
 680652        public ASCIIEncoding() : base(CodePageASCII)
 53        {
 680654        }
 55
 56        internal sealed override void SetDefaultFallbacks()
 57        {
 58            // For ASCIIEncoding we just use default replacement fallback
 680659            this.encoderFallback = EncoderFallback.ReplacementFallback;
 680660            this.decoderFallback = DecoderFallback.ReplacementFallback;
 680661        }
 62
 63        // WARNING: GetByteCount(string chars), GetBytes(string chars,...), and GetString(byte[] byteIndex...)
 64        // WARNING: have different variable names than EncodingNLS.cs, so this can't just be cut & pasted,
 65        // WARNING: or it'll break VB's way of calling these.
 66        //
 67        // The following methods are copied from EncodingNLS.cs.
 68        // Unfortunately EncodingNLS.cs is internal and we're public, so we have to re-implement them here.
 69        // These should be kept in sync for the following classes:
 70        // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
 71
 72        // Returns the number of bytes required to encode a range of characters in
 73        // a character array.
 74        //
 75        // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
 76        // So if you fix this, fix the others.  Currently those include:
 77        // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
 78        // parent method is safe
 79
 80        public override unsafe int GetByteCount(char[] chars, int index, int count)
 81        {
 082            if (chars is null)
 83            {
 084                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.chars, ExceptionResource.ArgumentNull_Array);
 85            }
 86
 087            if ((index | count) < 0)
 88            {
 089                ThrowHelper.ThrowArgumentOutOfRangeException((index < 0) ? ExceptionArgument.index : ExceptionArgument.c
 90            }
 91
 092            if (chars.Length - index < count)
 93            {
 094                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.chars, ExceptionResource.ArgumentOutOfRan
 95            }
 96
 097            fixed (char* pChars = chars)
 98            {
 099                return GetByteCountCommon(pChars + index, count);
 100            }
 101        }
 102
 103        // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
 104        // So if you fix this, fix the others.  Currently those include:
 105        // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
 106        // parent method is safe
 107
 108        public override unsafe int GetByteCount(string chars)
 109        {
 0110            if (chars is null)
 111            {
 0112                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.chars);
 113            }
 114
 0115            fixed (char* pChars = chars)
 116            {
 0117                return GetByteCountCommon(pChars, chars.Length);
 118            }
 119        }
 120
 121        // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
 122        // So if you fix this, fix the others.  Currently those include:
 123        // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
 124
 125        [CLSCompliant(false)]
 126        public override unsafe int GetByteCount(char* chars, int count)
 127        {
 0128            if (chars is null)
 129            {
 0130                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.chars);
 131            }
 132
 0133            if (count < 0)
 134            {
 0135                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRan
 136            }
 137
 0138            return GetByteCountCommon(chars, count);
 139        }
 140
 141        public override unsafe int GetByteCount(ReadOnlySpan<char> chars)
 0142        {
 143            // It's ok for us to pass null pointers down to the workhorse below.
 144
 0145            fixed (char* charsPtr = &MemoryMarshal.GetReference(chars))
 146            {
 0147                return GetByteCountCommon(charsPtr, chars.Length);
 148            }
 149        }
 150
 151        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 152        private unsafe int GetByteCountCommon(char* pChars, int charCount)
 153        {
 154            // Common helper method for all non-EncoderNLS entry points to GetByteCount.
 155            // A modification of this method should be copied in to each of the supported encodings: ASCII, UTF8, UTF16,
 156
 0157            Debug.Assert(charCount >= 0, "Caller shouldn't specify negative length buffer.");
 0158            Debug.Assert(pChars is not null || charCount == 0, "Input pointer shouldn't be null if non-zero length speci
 159
 160            // First call into the fast path.
 161
 0162            int totalByteCount = GetByteCountFast(pChars, charCount, EncoderFallback, out int charsConsumed);
 163
 0164            if (charsConsumed != charCount)
 165            {
 166                // If there's still data remaining in the source buffer, go down the fallback path.
 167                // We need to check for integer overflow since the fallback could change the required
 168                // output count in unexpected ways.
 169
 0170                totalByteCount += GetByteCountWithFallback(pChars, charCount, charsConsumed);
 0171                if (totalByteCount < 0)
 172                {
 0173                    ThrowConversionOverflow();
 174                }
 175            }
 176
 0177            return totalByteCount;
 178        }
 179
 180        [MethodImpl(MethodImplOptions.AggressiveInlining)] // called directly by GetByteCountCommon
 181        private protected sealed override unsafe int GetByteCountFast(char* pChars, int charsLength, EncoderFallback? fa
 182        {
 183            // First: Can we short-circuit the entire calculation?
 184            // If an EncoderReplacementFallback is in use, all non-ASCII chars
 185            // (including surrogate halves) are replaced with the default string.
 186            // If the default string consists of a single ASCII value, then we
 187            // know there's a 1:1 char->byte transcoding in all cases.
 188
 0189            int byteCount = charsLength;
 190
 0191            if (!(fallback is EncoderReplacementFallback replacementFallback
 0192                && replacementFallback.MaxCharCount == 1
 0193                && Ascii.IsValid(replacementFallback.DefaultString[0])))
 194            {
 195                // Unrecognized fallback mechanism - count chars manually.
 196
 0197                byteCount = (int)Ascii.GetIndexOfFirstNonAsciiChar(pChars, (uint)charsLength);
 198            }
 199
 0200            charsConsumed = byteCount;
 0201            return byteCount;
 202        }
 203
 204        // Parent method is safe.
 205        // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
 206        // So if you fix this, fix the others.  Currently those include:
 207        // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
 208
 209        public override unsafe int GetBytes(string chars, int charIndex, int charCount,
 210                                              byte[] bytes, int byteIndex)
 211        {
 0212            if (chars is null || bytes is null)
 213            {
 0214                ThrowHelper.ThrowArgumentNullException(
 0215                    argument: (chars is null) ? ExceptionArgument.chars : ExceptionArgument.bytes,
 0216                    resource: ExceptionResource.ArgumentNull_Array);
 217            }
 218
 0219            if ((charIndex | charCount) < 0)
 220            {
 0221                ThrowHelper.ThrowArgumentOutOfRangeException(
 0222                    argument: (charIndex < 0) ? ExceptionArgument.charIndex : ExceptionArgument.charCount,
 0223                    resource: ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
 224            }
 225
 0226            if (chars.Length - charIndex < charCount)
 227            {
 0228                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.chars, ExceptionResource.ArgumentOutOfRan
 229            }
 230
 0231            if ((uint)byteIndex > bytes.Length)
 232            {
 0233                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.byteIndex, ExceptionResource.ArgumentOutO
 234            }
 235
 0236            fixed (char* pChars = chars)
 0237            fixed (byte* pBytes = bytes)
 238            {
 0239                return GetBytesCommon(pChars + charIndex, charCount, pBytes + byteIndex, bytes.Length - byteIndex);
 240            }
 241        }
 242
 243        // Encodes a range of characters in a character array into a range of bytes
 244        // in a byte array. An exception occurs if the byte array is not large
 245        // enough to hold the complete encoding of the characters. The
 246        // GetByteCount method can be used to determine the exact number of
 247        // bytes that will be produced for a given range of characters.
 248        // Alternatively, the GetMaxByteCount method can be used to
 249        // determine the maximum number of bytes that will be produced for a given
 250        // number of characters, regardless of the actual character values.
 251        //
 252        // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
 253        // So if you fix this, fix the others.  Currently those include:
 254        // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
 255        // parent method is safe
 256
 257        public override unsafe int GetBytes(char[] chars, int charIndex, int charCount,
 258                                               byte[] bytes, int byteIndex)
 259        {
 0260            if (chars is null || bytes is null)
 261            {
 0262                ThrowHelper.ThrowArgumentNullException(
 0263                    argument: (chars is null) ? ExceptionArgument.chars : ExceptionArgument.bytes,
 0264                    resource: ExceptionResource.ArgumentNull_Array);
 265            }
 266
 0267            if ((charIndex | charCount) < 0)
 268            {
 0269                ThrowHelper.ThrowArgumentOutOfRangeException(
 0270                    argument: (charIndex < 0) ? ExceptionArgument.charIndex : ExceptionArgument.charCount,
 0271                    resource: ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
 272            }
 273
 0274            if (chars.Length - charIndex < charCount)
 275            {
 0276                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.chars, ExceptionResource.ArgumentOutOfRan
 277            }
 278
 0279            if ((uint)byteIndex > bytes.Length)
 280            {
 0281                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.byteIndex, ExceptionResource.ArgumentOutO
 282            }
 283
 0284            fixed (char* pChars = chars)
 0285            fixed (byte* pBytes = bytes)
 286            {
 0287                return GetBytesCommon(pChars + charIndex, charCount, pBytes + byteIndex, bytes.Length - byteIndex);
 288            }
 289        }
 290
 291        // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
 292        // So if you fix this, fix the others.  Currently those include:
 293        // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
 294
 295        [CLSCompliant(false)]
 296        public override unsafe int GetBytes(char* chars, int charCount, byte* bytes, int byteCount)
 297        {
 0298            if (chars is null || bytes is null)
 299            {
 0300                ThrowHelper.ThrowArgumentNullException(
 0301                    argument: (chars is null) ? ExceptionArgument.chars : ExceptionArgument.bytes,
 0302                    resource: ExceptionResource.ArgumentNull_Array);
 303            }
 304
 0305            if ((charCount | byteCount) < 0)
 306            {
 0307                ThrowHelper.ThrowArgumentOutOfRangeException(
 0308                    argument: (charCount < 0) ? ExceptionArgument.charCount : ExceptionArgument.byteCount,
 0309                    resource: ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
 310            }
 311
 0312            return GetBytesCommon(chars, charCount, bytes, byteCount);
 313        }
 314
 315        public override unsafe int GetBytes(ReadOnlySpan<char> chars, Span<byte> bytes)
 0316        {
 317            // It's ok for us to operate on null / empty spans.
 318
 0319            fixed (char* charsPtr = &MemoryMarshal.GetReference(chars))
 0320            fixed (byte* bytesPtr = &MemoryMarshal.GetReference(bytes))
 321            {
 0322                return GetBytesCommon(charsPtr, chars.Length, bytesPtr, bytes.Length);
 323            }
 324        }
 325
 326        /// <inheritdoc/>
 327        public override unsafe bool TryGetBytes(ReadOnlySpan<char> chars, Span<byte> bytes, out int bytesWritten)
 0328        {
 0329            fixed (char* charsPtr = &MemoryMarshal.GetReference(chars))
 0330            fixed (byte* bytesPtr = &MemoryMarshal.GetReference(bytes))
 331            {
 0332                int written = GetBytesCommon(charsPtr, chars.Length, bytesPtr, bytes.Length, throwForDestinationOverflow
 0333                if (written >= 0)
 334                {
 0335                    bytesWritten = written;
 0336                    return true;
 337                }
 338
 0339                bytesWritten = 0;
 0340                return false;
 341            }
 342        }
 343
 344        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 345        private unsafe int GetBytesCommon(char* pChars, int charCount, byte* pBytes, int byteCount, bool throwForDestina
 346        {
 347            // Common helper method for all non-EncoderNLS entry points to GetBytes.
 348            // A modification of this method should be copied in to each of the supported encodings: ASCII, UTF8, UTF16,
 349
 0350            Debug.Assert(charCount >= 0, "Caller shouldn't specify negative length buffer.");
 0351            Debug.Assert(pChars is not null || charCount == 0, "Input pointer shouldn't be null if non-zero length speci
 0352            Debug.Assert(byteCount >= 0, "Caller shouldn't specify negative length buffer.");
 0353            Debug.Assert(pBytes is not null || byteCount == 0, "Input pointer shouldn't be null if non-zero length speci
 354
 355            // First call into the fast path.
 356
 0357            int bytesWritten = GetBytesFast(pChars, charCount, pBytes, byteCount, out int charsConsumed);
 358
 0359            if (charsConsumed == charCount)
 360            {
 361                // All elements converted - return immediately.
 362
 0363                return bytesWritten;
 364            }
 365            else
 366            {
 367                // Simple narrowing conversion couldn't operate on entire buffer - invoke fallback.
 368
 0369                return GetBytesWithFallback(pChars, charCount, pBytes, byteCount, charsConsumed, bytesWritten, throwForD
 370            }
 371        }
 372
 373        [MethodImpl(MethodImplOptions.AggressiveInlining)] // called directly by GetBytesCommon
 374        private protected sealed override unsafe int GetBytesFast(char* pChars, int charsLength, byte* pBytes, int bytes
 375        {
 3403376            int bytesWritten = (int)Ascii.NarrowUtf16ToAscii(pChars, pBytes, (uint)Math.Min(charsLength, bytesLength));
 377
 3403378            charsConsumed = bytesWritten;
 3403379            return bytesWritten;
 380        }
 381
 382        private protected sealed override int GetBytesWithFallback(ReadOnlySpan<char> chars, int originalCharsLength, Sp
 383        {
 384            // We special-case EncoderReplacementFallback if it's telling us to write a single ASCII char,
 385            // since we believe this to be relatively common and we can handle it more efficiently than
 386            // the base implementation.
 387
 0388            if (((encoder is null) ? this.EncoderFallback : encoder.Fallback) is EncoderReplacementFallback replacementF
 0389                && replacementFallback.MaxCharCount == 1
 0390                && Ascii.IsValid(replacementFallback.DefaultString[0]))
 391            {
 0392                byte replacementByte = (byte)replacementFallback.DefaultString[0];
 393
 0394                int numElementsToConvert = Math.Min(chars.Length, bytes.Length);
 0395                int idx = 0;
 396
 397                // In a loop, replace the non-convertible data, then bulk-convert as much as we can.
 0398                while (idx < numElementsToConvert)
 399                {
 0400                    bytes[idx++] = replacementByte;
 401
 0402                    if (idx < numElementsToConvert)
 403                    {
 0404                        Ascii.FromUtf16(chars.Slice(idx), bytes.Slice(idx), out int charsConsumed);
 405
 0406                        idx += charsConsumed;
 407                    }
 408
 0409                    Debug.Assert(idx <= numElementsToConvert, "Somehow went beyond bounds of source or destination buffe
 410                }
 411
 412                // Slice off how much we consumed / wrote.
 413
 0414                chars = chars.Slice(numElementsToConvert);
 0415                bytes = bytes.Slice(numElementsToConvert);
 416            }
 417
 418            // If we couldn't go through our fast fallback mechanism, or if we still have leftover
 419            // data because we couldn't consume everything in the loop above, we need to go down the
 420            // slow fallback path.
 421
 0422            if (chars.IsEmpty)
 423            {
 0424                return originalBytesLength - bytes.Length; // total number of bytes written
 425            }
 426            else
 427            {
 0428                return base.GetBytesWithFallback(chars, originalCharsLength, bytes, originalBytesLength, encoder, throwF
 429            }
 430        }
 431
 432        // Returns the number of characters produced by decoding a range of bytes
 433        // in a byte array.
 434        //
 435        // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
 436        // So if you fix this, fix the others.  Currently those include:
 437        // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
 438        // parent method is safe
 439
 440        public override unsafe int GetCharCount(byte[] bytes, int index, int count)
 441        {
 0442            if (bytes is null)
 443            {
 0444                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.bytes, ExceptionResource.ArgumentNull_Array);
 445            }
 446
 0447            if ((index | count) < 0)
 448            {
 0449                ThrowHelper.ThrowArgumentOutOfRangeException((index < 0) ? ExceptionArgument.index : ExceptionArgument.c
 450            }
 451
 0452            if (bytes.Length - index < count)
 453            {
 0454                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.bytes, ExceptionResource.ArgumentOutOfRan
 455            }
 456
 0457            fixed (byte* pBytes = bytes)
 458            {
 0459                return GetCharCountCommon(pBytes + index, count);
 460            }
 461        }
 462
 463        // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
 464        // So if you fix this, fix the others.  Currently those include:
 465        // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
 466
 467        [CLSCompliant(false)]
 468        public override unsafe int GetCharCount(byte* bytes, int count)
 469        {
 0470            if (bytes is null)
 471            {
 0472                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.bytes, ExceptionResource.ArgumentNull_Array);
 473            }
 474
 0475            if (count < 0)
 476            {
 0477                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRan
 478            }
 479
 0480            return GetCharCountCommon(bytes, count);
 481        }
 482
 483        public override unsafe int GetCharCount(ReadOnlySpan<byte> bytes)
 0484        {
 485            // It's ok for us to pass null pointers down to the workhorse routine.
 486
 0487            fixed (byte* bytesPtr = &MemoryMarshal.GetReference(bytes))
 488            {
 0489                return GetCharCountCommon(bytesPtr, bytes.Length);
 490            }
 491        }
 492
 493        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 494        private unsafe int GetCharCountCommon(byte* pBytes, int byteCount)
 495        {
 496            // Common helper method for all non-DecoderNLS entry points to GetCharCount.
 497            // A modification of this method should be copied in to each of the supported encodings: ASCII, UTF8, UTF16,
 498
 0499            Debug.Assert(byteCount >= 0, "Caller shouldn't specify negative length buffer.");
 0500            Debug.Assert(pBytes is not null || byteCount == 0, "Input pointer shouldn't be null if non-zero length speci
 501
 502            // First call into the fast path.
 503
 0504            int totalCharCount = GetCharCountFast(pBytes, byteCount, DecoderFallback, out int bytesConsumed);
 505
 0506            if (bytesConsumed != byteCount)
 507            {
 508                // If there's still data remaining in the source buffer, go down the fallback path.
 509                // We need to check for integer overflow since the fallback could change the required
 510                // output count in unexpected ways.
 511
 0512                totalCharCount += GetCharCountWithFallback(pBytes, byteCount, bytesConsumed);
 0513                if (totalCharCount < 0)
 514                {
 0515                    ThrowConversionOverflow();
 516                }
 517            }
 518
 0519            return totalCharCount;
 520        }
 521
 522        [MethodImpl(MethodImplOptions.AggressiveInlining)] // called directly by GetCharCountCommon
 523        private protected sealed override unsafe int GetCharCountFast(byte* pBytes, int bytesLength, DecoderFallback? fa
 524        {
 525            // First: Can we short-circuit the entire calculation?
 526            // If a DecoderReplacementFallback is in use, all non-ASCII bytes are replaced with
 527            // the default string. If the default string consists of a single BMP value, then we
 528            // know there's a 1:1 byte->char transcoding in all cases.
 529
 25840530            int charCount = bytesLength;
 531
 25840532            if (fallback is not DecoderReplacementFallback replacementFallback || replacementFallback.MaxCharCount != 1)
 533            {
 534                // Unrecognized fallback mechanism - count bytes manually.
 535
 0536                charCount = (int)Ascii.GetIndexOfFirstNonAsciiByte(pBytes, (uint)bytesLength);
 537            }
 538
 25840539            bytesConsumed = charCount;
 25840540            return charCount;
 541        }
 542
 543        // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
 544        // So if you fix this, fix the others.  Currently those include:
 545        // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
 546        // parent method is safe
 547
 548        public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount,
 549                                              char[] chars, int charIndex)
 550        {
 0551            if (bytes is null || chars is null)
 552            {
 0553                ThrowHelper.ThrowArgumentNullException(
 0554                    argument: (bytes is null) ? ExceptionArgument.bytes : ExceptionArgument.chars,
 0555                    resource: ExceptionResource.ArgumentNull_Array);
 556            }
 557
 0558            if ((byteIndex | byteCount) < 0)
 559            {
 0560                ThrowHelper.ThrowArgumentOutOfRangeException(
 0561                    argument: (byteIndex < 0) ? ExceptionArgument.byteIndex : ExceptionArgument.byteCount,
 0562                    resource: ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
 563            }
 564
 0565            if (bytes.Length - byteIndex < byteCount)
 566            {
 0567                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.bytes, ExceptionResource.ArgumentOutOfRan
 568            }
 569
 0570            if ((uint)charIndex > (uint)chars.Length)
 571            {
 0572                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.charIndex, ExceptionResource.ArgumentOutO
 573            }
 574
 0575            fixed (byte* pBytes = bytes)
 0576            fixed (char* pChars = chars)
 577            {
 0578                return GetCharsCommon(pBytes + byteIndex, byteCount, pChars + charIndex, chars.Length - charIndex);
 579            }
 580        }
 581
 582        // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
 583        // So if you fix this, fix the others.  Currently those include:
 584        // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
 585
 586        [CLSCompliant(false)]
 587        public override unsafe int GetChars(byte* bytes, int byteCount, char* chars, int charCount)
 588        {
 0589            if (bytes is null || chars is null)
 590            {
 0591                ThrowHelper.ThrowArgumentNullException(
 0592                    argument: (bytes is null) ? ExceptionArgument.bytes : ExceptionArgument.chars,
 0593                    resource: ExceptionResource.ArgumentNull_Array);
 594            }
 595
 0596            if ((byteCount | charCount) < 0)
 597            {
 0598                ThrowHelper.ThrowArgumentOutOfRangeException(
 0599                    argument: (byteCount < 0) ? ExceptionArgument.byteCount : ExceptionArgument.charCount,
 0600                    resource: ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
 601            }
 602
 0603            return GetCharsCommon(bytes, byteCount, chars, charCount);
 604        }
 605
 606        public override unsafe int GetChars(ReadOnlySpan<byte> bytes, Span<char> chars)
 0607        {
 608            // It's ok for us to pass null pointers down to the workhorse below.
 609
 0610            fixed (byte* bytesPtr = &MemoryMarshal.GetReference(bytes))
 0611            fixed (char* charsPtr = &MemoryMarshal.GetReference(chars))
 612            {
 0613                return GetCharsCommon(bytesPtr, bytes.Length, charsPtr, chars.Length);
 614            }
 615        }
 616
 617        /// <inheritdoc/>
 618        public override unsafe bool TryGetChars(ReadOnlySpan<byte> bytes, Span<char> chars, out int charsWritten)
 0619        {
 0620            fixed (byte* bytesPtr = &MemoryMarshal.GetReference(bytes))
 0621            fixed (char* charsPtr = &MemoryMarshal.GetReference(chars))
 622            {
 0623                int written = GetCharsCommon(bytesPtr, bytes.Length, charsPtr, chars.Length, throwForDestinationOverflow
 0624                if (written >= 0)
 625                {
 0626                    charsWritten = written;
 0627                    return true;
 628                }
 629
 0630                charsWritten = 0;
 0631                return false;
 632            }
 633        }
 634
 635        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 636        private unsafe int GetCharsCommon(byte* pBytes, int byteCount, char* pChars, int charCount, bool throwForDestina
 637        {
 638            // Common helper method for all non-DecoderNLS entry points to GetChars.
 639            // A modification of this method should be copied in to each of the supported encodings: ASCII, UTF8, UTF16,
 640
 0641            Debug.Assert(byteCount >= 0, "Caller shouldn't specify negative length buffer.");
 0642            Debug.Assert(pBytes is not null || byteCount == 0, "Input pointer shouldn't be null if non-zero length speci
 0643            Debug.Assert(charCount >= 0, "Caller shouldn't specify negative length buffer.");
 0644            Debug.Assert(pChars is not null || charCount == 0, "Input pointer shouldn't be null if non-zero length speci
 645
 646            // First call into the fast path.
 647
 0648            int charsWritten = GetCharsFast(pBytes, byteCount, pChars, charCount, out int bytesConsumed);
 649
 0650            if (bytesConsumed == byteCount)
 651            {
 652                // All elements converted - return immediately.
 653
 0654                return charsWritten;
 655            }
 656            else
 657            {
 658                // Simple narrowing conversion couldn't operate on entire buffer - invoke fallback.
 659
 0660                return GetCharsWithFallback(pBytes, byteCount, pChars, charCount, bytesConsumed, charsWritten, throwForD
 661            }
 662        }
 663
 664        [MethodImpl(MethodImplOptions.AggressiveInlining)] // called directly by GetCharsCommon
 665        private protected sealed override unsafe int GetCharsFast(byte* pBytes, int bytesLength, char* pChars, int chars
 666        {
 1061900667            bytesConsumed = (int)Ascii.WidenAsciiToUtf16(pBytes, pChars, (uint)Math.Min(charsLength, bytesLength));
 1061900668            return bytesConsumed;
 669        }
 670
 671        private protected sealed override int GetCharsWithFallback(ReadOnlySpan<byte> bytes, int originalBytesLength, Sp
 672        {
 673            // We special-case DecoderReplacementFallback if it's telling us to write a single BMP char,
 674            // since we believe this to be relatively common and we can handle it more efficiently than
 675            // the base implementation.
 676
 411609677            if ((decoder is null ? DecoderFallback : decoder.Fallback) is DecoderReplacementFallback replacementFallback
 411609678                && replacementFallback.MaxCharCount == 1)
 679            {
 411609680                char replacementChar = replacementFallback.DefaultString[0];
 681
 411609682                int numElementsToConvert = Math.Min(bytes.Length, chars.Length);
 411609683                int idx = 0;
 684
 685                // In a loop, replace the non-convertible data, then bulk-convert as much as we can.
 686
 2785489687                while (idx < numElementsToConvert)
 688                {
 2373880689                    chars[idx++] = replacementChar;
 690
 2373880691                    if (idx < numElementsToConvert)
 692                    {
 2014789693                        Ascii.ToUtf16(bytes.Slice(idx), chars.Slice(idx), out int bytesConsumed);
 2014789694                        idx += bytesConsumed;
 695                    }
 696
 2373880697                    Debug.Assert(idx <= numElementsToConvert, "Somehow went beyond bounds of source or destination buffe
 698                }
 699
 700                // Slice off how much we consumed / wrote.
 701
 411609702                bytes = bytes.Slice(numElementsToConvert);
 411609703                chars = chars.Slice(numElementsToConvert);
 704            }
 705
 706            // If we couldn't go through our fast fallback mechanism, or if we still have leftover
 707            // data because we couldn't consume everything in the loop above, we need to go down the
 708            // slow fallback path.
 709
 411609710            if (bytes.IsEmpty)
 711            {
 411609712                return originalCharsLength - chars.Length; // total number of chars written
 713            }
 714            else
 715            {
 0716                return base.GetCharsWithFallback(bytes, originalBytesLength, chars, originalCharsLength, decoder, throwF
 717            }
 718        }
 719
 720        // Returns a string containing the decoded representation of a range of
 721        // bytes in a byte array.
 722        //
 723        // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
 724        // So if you fix this, fix the others.  Currently those include:
 725        // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
 726        // parent method is safe
 727
 728        public override unsafe string GetString(byte[] bytes, int byteIndex, int byteCount)
 729        {
 0730            if (bytes is null)
 731            {
 0732                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.bytes, ExceptionResource.ArgumentNull_Array);
 733            }
 734
 0735            if ((byteIndex | byteCount) < 0)
 736            {
 0737                ThrowHelper.ThrowArgumentOutOfRangeException(
 0738                    argument: (byteIndex < 0) ? ExceptionArgument.byteIndex : ExceptionArgument.byteCount,
 0739                    resource: ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
 740            }
 741
 0742            if (bytes.Length - byteIndex < byteCount)
 743            {
 0744                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.bytes, ExceptionResource.ArgumentOutOfRan
 745            }
 746
 747            // Avoid problems with empty input buffer
 0748            if (byteCount == 0)
 0749                return string.Empty;
 750
 0751            fixed (byte* pBytes = bytes)
 752            {
 0753                return string.CreateStringFromEncoding(pBytes + byteIndex, byteCount, this);
 754            }
 755        }
 756
 757        //
 758        // End of standard methods copied from EncodingNLS.cs
 759        //
 760
 761        //
 762        // Beginning of methods used by shared fallback logic.
 763        //
 764
 765        internal sealed override bool TryGetByteCount(Rune value, out int byteCount)
 766        {
 0767            if (value.IsAscii)
 768            {
 0769                byteCount = 1;
 0770                return true;
 771            }
 772            else
 773            {
 0774                byteCount = default;
 0775                return false;
 776            }
 777        }
 778
 779        internal sealed override OperationStatus EncodeRune(Rune value, Span<byte> bytes, out int bytesWritten)
 780        {
 0781            if (value.IsAscii)
 782            {
 0783                if (!bytes.IsEmpty)
 784                {
 0785                    bytes[0] = (byte)value.Value;
 0786                    bytesWritten = 1;
 0787                    return OperationStatus.Done;
 788                }
 789                else
 790                {
 0791                    bytesWritten = 0;
 0792                    return OperationStatus.DestinationTooSmall;
 793                }
 794            }
 795            else
 796            {
 0797                bytesWritten = 0;
 0798                return OperationStatus.InvalidData;
 799            }
 800        }
 801
 802        internal sealed override OperationStatus DecodeFirstRune(ReadOnlySpan<byte> bytes, out Rune value, out int bytes
 803        {
 0804            if (!bytes.IsEmpty)
 805            {
 0806                byte b = bytes[0];
 0807                if (Ascii.IsValid(b))
 808                {
 809                    // ASCII byte
 810
 0811                    value = new Rune(b);
 0812                    bytesConsumed = 1;
 0813                    return OperationStatus.Done;
 814                }
 815                else
 816                {
 817                    // Non-ASCII byte
 818
 0819                    value = Rune.ReplacementChar;
 0820                    bytesConsumed = 1;
 0821                    return OperationStatus.InvalidData;
 822                }
 823            }
 824            else
 825            {
 826                // No data to decode
 827
 0828                value = Rune.ReplacementChar;
 0829                bytesConsumed = 0;
 0830                return OperationStatus.NeedMoreData;
 831            }
 832        }
 833
 834        //
 835        // End of methods used by shared fallback logic.
 836        //
 837
 838        public override int GetMaxByteCount(int charCount)
 839        {
 0840            ArgumentOutOfRangeException.ThrowIfNegative(charCount);
 841
 842            // Characters would be # of characters + 1 in case high surrogate is ? * max fallback
 0843            long byteCount = (long)charCount + 1;
 844
 0845            if (EncoderFallback.MaxCharCount > 1)
 0846                byteCount *= EncoderFallback.MaxCharCount;
 847
 848            // 1 to 1 for most characters.  Only surrogates with fallbacks have less.
 849
 0850            if (byteCount > 0x7fffffff)
 0851                throw new ArgumentOutOfRangeException(nameof(charCount), SR.ArgumentOutOfRange_GetByteCountOverflow);
 0852            return (int)byteCount;
 853        }
 854
 855
 856        public override int GetMaxCharCount(int byteCount)
 857        {
 0858            ArgumentOutOfRangeException.ThrowIfNegative(byteCount);
 859
 860            // Just return length, SBCS stay the same length because they don't map to surrogate
 0861            long charCount = (long)byteCount;
 862
 863            // 1 to 1 for most characters.  Only surrogates with fallbacks have less, unknown fallbacks could be longer.
 0864            if (DecoderFallback.MaxCharCount > 1)
 0865                charCount *= DecoderFallback.MaxCharCount;
 866
 0867            if (charCount > 0x7fffffff)
 0868                throw new ArgumentOutOfRangeException(nameof(byteCount), SR.ArgumentOutOfRange_GetCharCountOverflow);
 869
 0870            return (int)charCount;
 871        }
 872
 873        // True if and only if the encoding only uses single byte code points.  (Ie, ASCII, 1252, etc)
 874
 0875        public override bool IsSingleByte => true;
 876
 25840877        public override Decoder GetDecoder() => new DecoderNLS(this);
 878
 879
 3403880        public override Encoder GetEncoder() => new EncoderNLS(this);
 881    }
 882}
 883

Methods/Properties

Clone()
.cctor()
.ctor()
SetDefaultFallbacks()
GetByteCount(System.Char[],System.Int32,System.Int32)
GetByteCount(System.String)
GetByteCount(System.Char*,System.Int32)
GetByteCount(System.ReadOnlySpan`1<System.Char>)
GetByteCountCommon(System.Char*,System.Int32)
GetByteCountFast(System.Char*,System.Int32,System.Text.EncoderFallback,System.Int32&)
GetBytes(System.String,System.Int32,System.Int32,System.Byte[],System.Int32)
GetBytes(System.Char[],System.Int32,System.Int32,System.Byte[],System.Int32)
GetBytes(System.Char*,System.Int32,System.Byte*,System.Int32)
GetBytes(System.ReadOnlySpan`1<System.Char>,System.Span`1<System.Byte>)
TryGetBytes(System.ReadOnlySpan`1<System.Char>,System.Span`1<System.Byte>,System.Int32&)
GetBytesCommon(System.Char*,System.Int32,System.Byte*,System.Int32,System.Boolean)
GetBytesFast(System.Char*,System.Int32,System.Byte*,System.Int32,System.Int32&)
GetBytesWithFallback(System.ReadOnlySpan`1<System.Char>,System.Int32,System.Span`1<System.Byte>,System.Int32,System.Text.EncoderNLS,System.Boolean)
GetCharCount(System.Byte[],System.Int32,System.Int32)
GetCharCount(System.Byte*,System.Int32)
GetCharCount(System.ReadOnlySpan`1<System.Byte>)
GetCharCountCommon(System.Byte*,System.Int32)
GetCharCountFast(System.Byte*,System.Int32,System.Text.DecoderFallback,System.Int32&)
GetChars(System.Byte[],System.Int32,System.Int32,System.Char[],System.Int32)
GetChars(System.Byte*,System.Int32,System.Char*,System.Int32)
GetChars(System.ReadOnlySpan`1<System.Byte>,System.Span`1<System.Char>)
TryGetChars(System.ReadOnlySpan`1<System.Byte>,System.Span`1<System.Char>,System.Int32&)
GetCharsCommon(System.Byte*,System.Int32,System.Char*,System.Int32,System.Boolean)
GetCharsFast(System.Byte*,System.Int32,System.Char*,System.Int32,System.Int32&)
GetCharsWithFallback(System.ReadOnlySpan`1<System.Byte>,System.Int32,System.Span`1<System.Char>,System.Int32,System.Text.DecoderNLS,System.Boolean)
GetString(System.Byte[],System.Int32,System.Int32)
TryGetByteCount(System.Text.Rune,System.Int32&)
EncodeRune(System.Text.Rune,System.Span`1<System.Byte>,System.Int32&)
DecodeFirstRune(System.ReadOnlySpan`1<System.Byte>,System.Text.Rune&,System.Int32&)
GetMaxByteCount(System.Int32)
GetMaxCharCount(System.Int32)
IsSingleByte()
GetDecoder()
GetEncoder()