| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- // Licensed to the .NET Foundation under one or more agreements.
- // The .NET Foundation licenses this file to you under the MIT license.
- // See the LICENSE file in the project root for more information.
- using System;
- using System.Runtime;
- using System.Diagnostics;
- namespace System.Text
- {
- public sealed class EncoderReplacementFallback : EncoderFallback
- {
- // Our variables
- private string _strDefault;
- // Construction. Default replacement fallback uses no best fit and ? replacement string
- public EncoderReplacementFallback() : this("?")
- {
- }
- public EncoderReplacementFallback(string replacement)
- {
- // Must not be null
- if (replacement == null)
- throw new ArgumentNullException(nameof(replacement));
- // Make sure it doesn't have bad surrogate pairs
- bool bFoundHigh = false;
- for (int i = 0; i < replacement.Length; i++)
- {
- // Found a surrogate?
- if (char.IsSurrogate(replacement, i))
- {
- // High or Low?
- if (char.IsHighSurrogate(replacement, i))
- {
- // if already had a high one, stop
- if (bFoundHigh)
- break; // break & throw at the bFoundHIgh below
- bFoundHigh = true;
- }
- else
- {
- // Low, did we have a high?
- if (!bFoundHigh)
- {
- // Didn't have one, make if fail when we stop
- bFoundHigh = true;
- break;
- }
- // Clear flag
- bFoundHigh = false;
- }
- }
- // If last was high we're in trouble (not surrogate so not low surrogate, so break)
- else if (bFoundHigh)
- break;
- }
- if (bFoundHigh)
- throw new ArgumentException(SR.Format(SR.Argument_InvalidCharSequenceNoIndex, nameof(replacement)));
- _strDefault = replacement;
- }
- public string DefaultString
- {
- get
- {
- return _strDefault;
- }
- }
- public override EncoderFallbackBuffer CreateFallbackBuffer()
- {
- return new EncoderReplacementFallbackBuffer(this);
- }
- // Maximum number of characters that this instance of this fallback could return
- public override int MaxCharCount
- {
- get
- {
- return _strDefault.Length;
- }
- }
- public override bool Equals(object value)
- {
- if (value is EncoderReplacementFallback that)
- {
- return (_strDefault == that._strDefault);
- }
- return (false);
- }
- public override int GetHashCode()
- {
- return _strDefault.GetHashCode();
- }
- }
- public sealed class EncoderReplacementFallbackBuffer : EncoderFallbackBuffer
- {
- // Store our default string
- private string _strDefault;
- private int _fallbackCount = -1;
- private int _fallbackIndex = -1;
- // Construction
- public EncoderReplacementFallbackBuffer(EncoderReplacementFallback fallback)
- {
- // 2X in case we're a surrogate pair
- _strDefault = fallback.DefaultString + fallback.DefaultString;
- }
- // Fallback Methods
- public override bool Fallback(char charUnknown, int index)
- {
- // If we had a buffer already we're being recursive, throw, it's probably at the suspect
- // character in our array.
- if (_fallbackCount >= 1)
- {
- // If we're recursive we may still have something in our buffer that makes this a surrogate
- if (char.IsHighSurrogate(charUnknown) && _fallbackCount >= 0 &&
- char.IsLowSurrogate(_strDefault[_fallbackIndex + 1]))
- ThrowLastCharRecursive(char.ConvertToUtf32(charUnknown, _strDefault[_fallbackIndex + 1]));
- // Nope, just one character
- ThrowLastCharRecursive(unchecked((int)charUnknown));
- }
- // Go ahead and get our fallback
- // Divide by 2 because we aren't a surrogate pair
- _fallbackCount = _strDefault.Length / 2;
- _fallbackIndex = -1;
- return _fallbackCount != 0;
- }
- public override bool Fallback(char charUnknownHigh, char charUnknownLow, int index)
- {
- // Double check input surrogate pair
- if (!char.IsHighSurrogate(charUnknownHigh))
- throw new ArgumentOutOfRangeException(nameof(charUnknownHigh),
- SR.Format(SR.ArgumentOutOfRange_Range, 0xD800, 0xDBFF));
- if (!char.IsLowSurrogate(charUnknownLow))
- throw new ArgumentOutOfRangeException(nameof(charUnknownLow),
- SR.Format(SR.ArgumentOutOfRange_Range, 0xDC00, 0xDFFF));
- // If we had a buffer already we're being recursive, throw, it's probably at the suspect
- // character in our array.
- if (_fallbackCount >= 1)
- ThrowLastCharRecursive(char.ConvertToUtf32(charUnknownHigh, charUnknownLow));
- // Go ahead and get our fallback
- _fallbackCount = _strDefault.Length;
- _fallbackIndex = -1;
- return _fallbackCount != 0;
- }
- public override char GetNextChar()
- {
- // We want it to get < 0 because == 0 means that the current/last character is a fallback
- // and we need to detect recursion. We could have a flag but we already have this counter.
- _fallbackCount--;
- _fallbackIndex++;
- // Do we have anything left? 0 is now last fallback char, negative is nothing left
- if (_fallbackCount < 0)
- return '\0';
- // Need to get it out of the buffer.
- // Make sure it didn't wrap from the fast count-- path
- if (_fallbackCount == int.MaxValue)
- {
- _fallbackCount = -1;
- return '\0';
- }
- // Now make sure its in the expected range
- Debug.Assert(_fallbackIndex < _strDefault.Length && _fallbackIndex >= 0,
- "Index exceeds buffer range");
- return _strDefault[_fallbackIndex];
- }
- public override bool MovePrevious()
- {
- // Back up one, only if we just processed the last character (or earlier)
- if (_fallbackCount >= -1 && _fallbackIndex >= 0)
- {
- _fallbackIndex--;
- _fallbackCount++;
- return true;
- }
- // Return false 'cause we couldn't do it.
- return false;
- }
- // How many characters left to output?
- public override int Remaining
- {
- get
- {
- // Our count is 0 for 1 character left.
- return (_fallbackCount < 0) ? 0 : _fallbackCount;
- }
- }
- // Clear the buffer
- public override unsafe void Reset()
- {
- _fallbackCount = -1;
- _fallbackIndex = 0;
- charStart = null;
- bFallingBack = false;
- }
- }
- }
|