213 lines
6.5 KiB
C#
213 lines
6.5 KiB
C#
// ==++==
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// ==--==
|
|
// DecoderReplacementFallback.cs
|
|
//
|
|
namespace System.Text
|
|
{
|
|
using System;
|
|
using System.Diagnostics.Contracts;
|
|
|
|
[Serializable]
|
|
public sealed class DecoderReplacementFallback : DecoderFallback
|
|
{
|
|
// Our variables
|
|
private String strDefault;
|
|
|
|
// Construction. Default replacement fallback uses no best fit and ? replacement string
|
|
public DecoderReplacementFallback() : this("?")
|
|
{
|
|
}
|
|
|
|
public DecoderReplacementFallback(String replacement)
|
|
{
|
|
if (replacement == null)
|
|
throw new ArgumentNullException("replacement");
|
|
Contract.EndContractBlock();
|
|
|
|
// 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(Environment.GetResourceString("Argument_InvalidCharSequenceNoIndex", "replacement"));
|
|
|
|
strDefault = replacement;
|
|
}
|
|
|
|
public String DefaultString
|
|
{
|
|
get
|
|
{
|
|
return strDefault;
|
|
}
|
|
}
|
|
|
|
public override DecoderFallbackBuffer CreateFallbackBuffer()
|
|
{
|
|
return new DecoderReplacementFallbackBuffer(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)
|
|
{
|
|
DecoderReplacementFallback that = value as DecoderReplacementFallback;
|
|
if (that != null)
|
|
{
|
|
return (this.strDefault == that.strDefault);
|
|
}
|
|
return (false);
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
return strDefault.GetHashCode();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public sealed class DecoderReplacementFallbackBuffer : DecoderFallbackBuffer
|
|
{
|
|
// Store our default string
|
|
private String strDefault;
|
|
int fallbackCount = -1;
|
|
int fallbackIndex = -1;
|
|
|
|
// Construction
|
|
public DecoderReplacementFallbackBuffer(DecoderReplacementFallback fallback)
|
|
{
|
|
this.strDefault = fallback.DefaultString;
|
|
}
|
|
|
|
// Fallback Methods
|
|
public override bool Fallback(byte[] bytesUnknown, int index)
|
|
{
|
|
// We expect no previous fallback in our buffer
|
|
// We can't call recursively but others might (note, we don't test on last char!!!)
|
|
if (fallbackCount >= 1)
|
|
{
|
|
ThrowLastBytesRecursive(bytesUnknown);
|
|
}
|
|
|
|
// Go ahead and get our fallback
|
|
if (strDefault.Length == 0)
|
|
return false;
|
|
|
|
fallbackCount = strDefault.Length;
|
|
fallbackIndex = -1;
|
|
|
|
return true;
|
|
}
|
|
|
|
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
|
|
Contract.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
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
public override unsafe void Reset()
|
|
{
|
|
fallbackCount = -1;
|
|
fallbackIndex = -1;
|
|
byteStart = null;
|
|
}
|
|
|
|
// This version just counts the fallback and doesn't actually copy anything.
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
internal unsafe override int InternalFallback(byte[] bytes, byte* pBytes)
|
|
// Right now this has both bytes and bytes[], since we might have extra bytes, hence the
|
|
// array, and we might need the index, hence the byte*
|
|
{
|
|
// return our replacement string Length
|
|
return strDefault.Length;
|
|
}
|
|
}
|
|
}
|
|
|