< Summary

Line coverage
57%
Covered lines: 19
Uncovered lines: 14
Coverable lines: 33
Total lines: 173
Line coverage: 57.5%
Branch coverage
43%
Covered branches: 7
Total branches: 16
Branch coverage: 43.7%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%11100%
Fallback(...)50%4471.42%
GetNextChar()66.66%6680%
MovePrevious()0%440%
Reset()100%110%
InternalFallback(...)100%110%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Private.CoreLib/src/System/Text/DecoderReplacementFallback.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 DecoderReplacementFallback : DecoderFallback
 10    {
 11        internal static readonly DecoderReplacementFallback s_default = new DecoderReplacementFallback();
 12
 13        // Our variables
 14        private readonly string _strDefault;
 15
 16        // Construction.  Default replacement fallback uses no best fit and ? replacement string
 17        public DecoderReplacementFallback() : this("?")
 18        {
 19        }
 20
 21        public DecoderReplacementFallback(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 DecoderFallbackBuffer CreateFallbackBuffer() =>
 67            new DecoderReplacementFallbackBuffer(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 DecoderReplacementFallback that &&
 74            _strDefault == that._strDefault;
 75
 76        public override int GetHashCode() => _strDefault.GetHashCode();
 77    }
 78
 79    public sealed class DecoderReplacementFallbackBuffer : DecoderFallbackBuffer
 80    {
 81        // Store our default string
 82        private readonly string _strDefault;
 1445783        private int _fallbackCount = -1;
 1445784        private int _fallbackIndex = -1;
 85
 86        // Construction
 1445787        public DecoderReplacementFallbackBuffer(DecoderReplacementFallback fallback)
 88        {
 1445789            _strDefault = fallback.DefaultString;
 1445790        }
 91
 92        // Fallback Methods
 93        public override bool Fallback(byte[] bytesUnknown, int index)
 94        {
 95            // We expect no previous fallback in our buffer
 96            // We can't call recursively but others might (note, we don't test on last char!)
 100065097            if (_fallbackCount >= 1)
 98            {
 099                ThrowLastBytesRecursive(bytesUnknown);
 100            }
 101
 102            // Go ahead and get our fallback
 1000650103            if (_strDefault.Length == 0)
 0104                return false;
 105
 1000650106            _fallbackCount = _strDefault.Length;
 1000650107            _fallbackIndex = -1;
 108
 1000650109            return true;
 110        }
 111
 112        public override char GetNextChar()
 113        {
 114            // We want it to get < 0 because == 0 means that the current/last character is a fallback
 115            // and we need to detect recursion.  We could have a flag but we already have this counter.
 4669700116            _fallbackCount--;
 4669700117            _fallbackIndex++;
 118
 119            // Do we have anything left? 0 is now last fallback char, negative is nothing left
 4669700120            if (_fallbackCount < 0)
 1000650121                return '\0';
 122
 123            // Need to get it out of the buffer.
 124            // Make sure it didn't wrap from the fast count-- path
 3669050125            if (_fallbackCount == int.MaxValue)
 126            {
 0127                _fallbackCount = -1;
 0128                return '\0';
 129            }
 130
 131            // Now make sure its in the expected range
 3669050132            Debug.Assert(_fallbackIndex < _strDefault.Length && _fallbackIndex >= 0,
 3669050133                            "Index exceeds buffer range");
 134
 3669050135            return _strDefault[_fallbackIndex];
 136        }
 137
 138        public override bool MovePrevious()
 139        {
 140            // Back up one, only if we just processed the last character (or earlier)
 0141            if (_fallbackCount >= -1 && _fallbackIndex >= 0)
 142            {
 0143                _fallbackIndex--;
 0144                _fallbackCount++;
 0145                return true;
 146            }
 147
 148            // Return false 'cause we couldn't do it.
 0149            return false;
 150        }
 151
 152        // How many characters left to output?
 153        public override int Remaining =>
 154            // Our count is 0 for 1 character left.
 14457155            (_fallbackCount < 0) ? 0 : _fallbackCount;
 156
 157        // Clear the buffer
 158        public override unsafe void Reset()
 159        {
 0160            _fallbackCount = -1;
 0161            _fallbackIndex = -1;
 0162            byteStart = null;
 0163        }
 164
 165        // This version just counts the fallback and doesn't actually copy anything.
 166        internal override unsafe int InternalFallback(byte[] bytes, byte* pBytes) =>
 167            // Right now this has both bytes and bytes[], since we might have extra bytes,
 168            // hence the array, and we might need the index, hence the byte*.
 169            // Return our replacement string Length
 0170            _strDefault.Length;
 171    }
 172}
 173