< Summary

Line coverage
46%
Covered lines: 12
Uncovered lines: 14
Coverable lines: 26
Total lines: 195
Line coverage: 46.1%
Branch coverage
31%
Covered branches: 5
Total branches: 16
Branch coverage: 31.2%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.cctor()100%11100%
.ctor()100%11100%
.ctor(...)35.71%141452.94%
CreateFallbackBuffer()100%110%
Equals(...)0%220%
GetHashCode()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    {
 111        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
 117        public EncoderReplacementFallback() : this("?")
 18        {
 119        }
 20
 621        public EncoderReplacementFallback(string replacement)
 22        {
 623            ArgumentNullException.ThrowIfNull(replacement);
 24
 25            // Make sure it doesn't have bad surrogate pairs
 626            bool bFoundHigh = false;
 2427            foreach (char c in replacement)
 28            {
 29                // Found a surrogate?
 630                if (char.IsSurrogate(c))
 31                {
 32                    // High or Low?
 033                    if (char.IsHighSurrogate(c))
 34                    {
 35                        // if already had a high one, stop
 036                        if (bFoundHigh)
 37                            break;  // break & throw at the bFoundHIgh below
 038                        bFoundHigh = true;
 39                    }
 40                    else
 41                    {
 42                        // Low, did we have a high?
 043                        if (!bFoundHigh)
 44                        {
 45                            // Didn't have one, make if fail when we stop
 046                            bFoundHigh = true;
 047                            break;
 48                        }
 49
 50                        // Clear flag
 051                        bFoundHigh = false;
 52                    }
 53                }
 54                // If last was high we're in trouble (not surrogate so not low surrogate, so break)
 655                else if (bFoundHigh)
 56                    break;
 57            }
 658            if (bFoundHigh)
 059                throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(replacement));
 60
 661            _strDefault = replacement;
 662        }
 63
 064        public string DefaultString => _strDefault;
 65
 66        public override EncoderFallbackBuffer CreateFallbackBuffer() =>
 067            new EncoderReplacementFallbackBuffer(this);
 68
 69        // Maximum number of characters that this instance of this fallback could return
 070        public override int MaxCharCount => _strDefault.Length;
 71
 72        public override bool Equals([NotNullWhen(true)] object? value) =>
 073            value is EncoderReplacementFallback that &&
 074            _strDefault == that._strDefault;
 75
 076        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;
 83        private int _fallbackCount = -1;
 84        private int _fallbackIndex = -1;
 85
 86        // Construction
 87        public EncoderReplacementFallbackBuffer(EncoderReplacementFallback fallback)
 88        {
 89            // 2X in case we're a surrogate pair
 90            _strDefault = fallback.DefaultString + fallback.DefaultString;
 91        }
 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.
 98            if (_fallbackCount >= 1)
 99            {
 100                // If we're recursive we may still have something in our buffer that makes this a surrogate
 101                if (char.IsHighSurrogate(charUnknown) && _fallbackCount >= 0 &&
 102                    char.IsLowSurrogate(_strDefault[_fallbackIndex + 1]))
 103                    ThrowLastCharRecursive(char.ConvertToUtf32(charUnknown, _strDefault[_fallbackIndex + 1]));
 104
 105                // Nope, just one character
 106                ThrowLastCharRecursive(unchecked((int)charUnknown));
 107            }
 108
 109            // Go ahead and get our fallback
 110            // Divide by 2 because we aren't a surrogate pair
 111            _fallbackCount = _strDefault.Length / 2;
 112            _fallbackIndex = -1;
 113
 114            return _fallbackCount != 0;
 115        }
 116
 117        public override bool Fallback(char charUnknownHigh, char charUnknownLow, int index)
 118        {
 119            // Double check input surrogate pair
 120            if (!char.IsHighSurrogate(charUnknownHigh))
 121                throw new ArgumentOutOfRangeException(nameof(charUnknownHigh),
 122                    SR.Format(SR.ArgumentOutOfRange_Range, 0xD800, 0xDBFF));
 123
 124            if (!char.IsLowSurrogate(charUnknownLow))
 125                throw new ArgumentOutOfRangeException(nameof(charUnknownLow),
 126                    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.
 130            if (_fallbackCount >= 1)
 131                ThrowLastCharRecursive(char.ConvertToUtf32(charUnknownHigh, charUnknownLow));
 132
 133            // Go ahead and get our fallback
 134            _fallbackCount = _strDefault.Length;
 135            _fallbackIndex = -1;
 136
 137            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.
 144            _fallbackCount--;
 145            _fallbackIndex++;
 146
 147            // Do we have anything left? 0 is now last fallback char, negative is nothing left
 148            if (_fallbackCount < 0)
 149                return '\0';
 150
 151            // Need to get it out of the buffer.
 152            // Make sure it didn't wrap from the fast count-- path
 153            if (_fallbackCount == int.MaxValue)
 154            {
 155                _fallbackCount = -1;
 156                return '\0';
 157            }
 158
 159            // Now make sure its in the expected range
 160            Debug.Assert(_fallbackIndex < _strDefault.Length && _fallbackIndex >= 0,
 161                            "Index exceeds buffer range");
 162
 163            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)
 169            if (_fallbackCount >= -1 && _fallbackIndex >= 0)
 170            {
 171                _fallbackIndex--;
 172                _fallbackCount++;
 173                return true;
 174            }
 175
 176            // Return false 'cause we couldn't do it.
 177            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.
 183                (_fallbackCount < 0) ? 0 : _fallbackCount;
 184
 185        // Clear the buffer
 186        public override unsafe void Reset()
 187        {
 188            _fallbackCount = -1;
 189            _fallbackIndex = 0;
 190            charStart = null;
 191            bFallingBack = false;
 192        }
 193    }
 194}
 195