< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 45
Coverable lines: 45
Total lines: 195
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 26
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%110%
Fallback(...)0%880%
Fallback(...)0%660%
GetNextChar()0%660%
MovePrevious()0%440%
Reset()100%110%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Private.CoreLib/src/System/Text/EncoderReplacementFallback.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.Diagnostics;
 5using System.Diagnostics.CodeAnalysis;
 6
 7namespace System.Text
 8{
 9    public sealed class EncoderReplacementFallback : EncoderFallback
 10    {
 11        internal static readonly EncoderReplacementFallback s_default = new EncoderReplacementFallback();
 12
 13        // Our variables
 14        private readonly string _strDefault;
 15
 16        // Construction.  Default replacement fallback uses no best fit and ? replacement string
 17        public EncoderReplacementFallback() : this("?")
 18        {
 19        }
 20
 21        public EncoderReplacementFallback(string replacement)
 22        {
 23            ArgumentNullException.ThrowIfNull(replacement);
 24
 25            // Make sure it doesn't have bad surrogate pairs
 26            bool bFoundHigh = false;
 27            foreach (char c in replacement)
 28            {
 29                // Found a surrogate?
 30                if (char.IsSurrogate(c))
 31                {
 32                    // High or Low?
 33                    if (char.IsHighSurrogate(c))
 34                    {
 35                        // if already had a high one, stop
 36                        if (bFoundHigh)
 37                            break;  // break & throw at the bFoundHIgh below
 38                        bFoundHigh = true;
 39                    }
 40                    else
 41                    {
 42                        // Low, did we have a high?
 43                        if (!bFoundHigh)
 44                        {
 45                            // Didn't have one, make if fail when we stop
 46                            bFoundHigh = true;
 47                            break;
 48                        }
 49
 50                        // Clear flag
 51                        bFoundHigh = false;
 52                    }
 53                }
 54                // If last was high we're in trouble (not surrogate so not low surrogate, so break)
 55                else if (bFoundHigh)
 56                    break;
 57            }
 58            if (bFoundHigh)
 59                throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(replacement));
 60
 61            _strDefault = replacement;
 62        }
 63
 64        public string DefaultString => _strDefault;
 65
 66        public override EncoderFallbackBuffer CreateFallbackBuffer() =>
 67            new EncoderReplacementFallbackBuffer(this);
 68
 69        // Maximum number of characters that this instance of this fallback could return
 70        public override int MaxCharCount => _strDefault.Length;
 71
 72        public override bool Equals([NotNullWhen(true)] object? value) =>
 73            value is EncoderReplacementFallback that &&
 74            _strDefault == that._strDefault;
 75
 76        public override int GetHashCode() => _strDefault.GetHashCode();
 77    }
 78
 79    public sealed class EncoderReplacementFallbackBuffer : EncoderFallbackBuffer
 80    {
 81        // Store our default string
 82        private readonly string _strDefault;
 083        private int _fallbackCount = -1;
 084        private int _fallbackIndex = -1;
 85
 86        // Construction
 087        public EncoderReplacementFallbackBuffer(EncoderReplacementFallback fallback)
 88        {
 89            // 2X in case we're a surrogate pair
 090            _strDefault = fallback.DefaultString + fallback.DefaultString;
 091        }
 92
 93        // Fallback Methods
 94        public override bool Fallback(char charUnknown, int index)
 95        {
 96            // If we had a buffer already we're being recursive, throw, it's probably at the suspect
 97            // character in our array.
 098            if (_fallbackCount >= 1)
 99            {
 100                // If we're recursive we may still have something in our buffer that makes this a surrogate
 0101                if (char.IsHighSurrogate(charUnknown) && _fallbackCount >= 0 &&
 0102                    char.IsLowSurrogate(_strDefault[_fallbackIndex + 1]))
 0103                    ThrowLastCharRecursive(char.ConvertToUtf32(charUnknown, _strDefault[_fallbackIndex + 1]));
 104
 105                // Nope, just one character
 0106                ThrowLastCharRecursive(unchecked((int)charUnknown));
 107            }
 108
 109            // Go ahead and get our fallback
 110            // Divide by 2 because we aren't a surrogate pair
 0111            _fallbackCount = _strDefault.Length / 2;
 0112            _fallbackIndex = -1;
 113
 0114            return _fallbackCount != 0;
 115        }
 116
 117        public override bool Fallback(char charUnknownHigh, char charUnknownLow, int index)
 118        {
 119            // Double check input surrogate pair
 0120            if (!char.IsHighSurrogate(charUnknownHigh))
 0121                throw new ArgumentOutOfRangeException(nameof(charUnknownHigh),
 0122                    SR.Format(SR.ArgumentOutOfRange_Range, 0xD800, 0xDBFF));
 123
 0124            if (!char.IsLowSurrogate(charUnknownLow))
 0125                throw new ArgumentOutOfRangeException(nameof(charUnknownLow),
 0126                    SR.Format(SR.ArgumentOutOfRange_Range, 0xDC00, 0xDFFF));
 127
 128            // If we had a buffer already we're being recursive, throw, it's probably at the suspect
 129            // character in our array.
 0130            if (_fallbackCount >= 1)
 0131                ThrowLastCharRecursive(char.ConvertToUtf32(charUnknownHigh, charUnknownLow));
 132
 133            // Go ahead and get our fallback
 0134            _fallbackCount = _strDefault.Length;
 0135            _fallbackIndex = -1;
 136
 0137            return _fallbackCount != 0;
 138        }
 139
 140        public override char GetNextChar()
 141        {
 142            // We want it to get < 0 because == 0 means that the current/last character is a fallback
 143            // and we need to detect recursion.  We could have a flag but we already have this counter.
 0144            _fallbackCount--;
 0145            _fallbackIndex++;
 146
 147            // Do we have anything left? 0 is now last fallback char, negative is nothing left
 0148            if (_fallbackCount < 0)
 0149                return '\0';
 150
 151            // Need to get it out of the buffer.
 152            // Make sure it didn't wrap from the fast count-- path
 0153            if (_fallbackCount == int.MaxValue)
 154            {
 0155                _fallbackCount = -1;
 0156                return '\0';
 157            }
 158
 159            // Now make sure its in the expected range
 0160            Debug.Assert(_fallbackIndex < _strDefault.Length && _fallbackIndex >= 0,
 0161                            "Index exceeds buffer range");
 162
 0163            return _strDefault[_fallbackIndex];
 164        }
 165
 166        public override bool MovePrevious()
 167        {
 168            // Back up one, only if we just processed the last character (or earlier)
 0169            if (_fallbackCount >= -1 && _fallbackIndex >= 0)
 170            {
 0171                _fallbackIndex--;
 0172                _fallbackCount++;
 0173                return true;
 174            }
 175
 176            // Return false 'cause we couldn't do it.
 0177            return false;
 178        }
 179
 180        // How many characters left to output?
 181        public override int Remaining =>
 182                // Our count is 0 for 1 character left.
 0183                (_fallbackCount < 0) ? 0 : _fallbackCount;
 184
 185        // Clear the buffer
 186        public override unsafe void Reset()
 187        {
 0188            _fallbackCount = -1;
 0189            _fallbackIndex = 0;
 0190            charStart = null;
 0191            bFallingBack = false;
 0192        }
 193    }
 194}
 195