public unsafe override int GetChars(byte* bytes, int byteCount,
char* chars, int charCount, DecoderNLS decoder)
{
// Just need to ASSERT, this is called by something else internal that checked parameters already
Debug.Assert(bytes != null, "[SBCSCodePageEncoding.GetChars]bytes is null");
Debug.Assert(byteCount >= 0, "[SBCSCodePageEncoding.GetChars]byteCount is negative");
Debug.Assert(chars != null, "[SBCSCodePageEncoding.GetChars]chars is null");
Debug.Assert(charCount >= 0, "[SBCSCodePageEncoding.GetChars]charCount is negative");
CheckMemorySection();
// See if we have best fit
bool bUseBestFit = false;
// Do it fast way if using ? replacement or best fit fallbacks
byte* byteEnd = bytes + byteCount;
byte* byteStart = bytes;
char* charStart = chars;
// Only need decoder fallback buffer if not using default replacement fallback or best fit fallback.
DecoderReplacementFallback fallback = null;
if (decoder == null)
{
fallback = DecoderFallback as DecoderReplacementFallback;
bUseBestFit = DecoderFallback is InternalDecoderBestFitFallback;
}
else
{
fallback = decoder.Fallback as DecoderReplacementFallback;
bUseBestFit = decoder.Fallback is InternalDecoderBestFitFallback;
Debug.Assert(!decoder.m_throwOnOverflow || !decoder.InternalHasFallbackBuffer ||
decoder.FallbackBuffer.Remaining == 0,
"[SBCSCodePageEncoding.GetChars]Expected empty fallback buffer at start");
}
if (bUseBestFit || (fallback != null && fallback.MaxCharCount == 1))
{
// Try it the fast way
char replacementChar;
if (fallback == null)
replacementChar = '?'; // Best fit always has ? for fallback for SBCS
else
replacementChar = fallback.DefaultString[0];
// Need byteCount chars, otherwise too small buffer
if (charCount < byteCount)
{
// Need at least 1 output byte, throw if must throw
ThrowCharsOverflow(decoder, charCount < 1);
// Not throwing, use what we can
byteEnd = bytes + charCount;
}
// Quick loop, just do '?' replacement because we don't have fallbacks for decodings.
while (bytes < byteEnd)
{
char c;
if (bUseBestFit)
{
if (arrayBytesBestFit == null)
{
ReadBestFitTable();
}
c = arrayBytesBestFit[*bytes];
}
else
c = _mapBytesToUnicode[*bytes];
bytes++;
if (c == UNKNOWN_CHAR)
// This is an invalid byte in the ASCII encoding.
*chars = replacementChar;
else
*chars = c;
chars++;
}
// bytes & chars used are the same
if (decoder != null)
decoder.m_bytesUsed = (int)(bytes - byteStart);
return (int)(chars - charStart);
}
// Slower way's going to need a fallback buffer
DecoderFallbackBuffer fallbackBuffer = null;
byte[] byteBuffer = new byte[1];
char* charEnd = chars + charCount;
DecoderFallbackBufferHelper fallbackHelper = new DecoderFallbackBufferHelper(
decoder != null ? decoder.FallbackBuffer : DecoderFallback.CreateFallbackBuffer());
// Not quite so fast loop
while (bytes < byteEnd)
{
// Faster if don't use *bytes++;
char c = _mapBytesToUnicode[*bytes];
bytes++;
// See if it was unknown
if (c == UNKNOWN_CHAR)
{
// Make sure we have a fallback buffer
if (fallbackBuffer == null)
{
if (decoder == null)
fallbackBuffer = DecoderFallback.CreateFallbackBuffer();
else
fallbackBuffer = decoder.FallbackBuffer;
fallbackHelper = new DecoderFallbackBufferHelper(fallbackBuffer);
fallbackHelper.InternalInitialize(byteEnd - byteCount, charEnd);
}
// Use fallback buffer
Debug.Assert(bytes > byteStart,
"[SBCSCodePageEncoding.GetChars]Expected bytes to have advanced already (unknown byte)");
byteBuffer[0] = *(bytes - 1);
// Fallback adds fallback to chars, but doesn't increment chars unless the whole thing fits.
if (!fallbackHelper.InternalFallback(byteBuffer, bytes, ref chars))
{
// May or may not throw, but we didn't get this byte
bytes--; // unused byte
fallbackHelper.InternalReset(); // Didn't fall this back
ThrowCharsOverflow(decoder, bytes == byteStart); // throw?
break; // don't throw, but stop loop
}
}
else
{
// Make sure we have buffer space
if (chars >= charEnd)
{
Debug.Assert(bytes > byteStart,
"[SBCSCodePageEncoding.GetChars]Expected bytes to have advanced already (known byte)");
bytes--; // unused byte
ThrowCharsOverflow(decoder, bytes == byteStart); // throw?
break; // don't throw, but stop loop
}
*(chars) = c;
chars++;
}
}
// Might have had decoder fallback stuff.
if (decoder != null)
decoder.m_bytesUsed = (int)(bytes - byteStart);
// Expect Empty fallback buffer for GetChars
Debug.Assert(fallbackBuffer == null || fallbackBuffer.Remaining == 0,
"[SBCSEncoding.GetChars]Expected Empty fallback buffer at end");
return (int)(chars - charStart);
}