public unsafe override int GetBytes(char* chars, int charCount,
byte* bytes, int byteCount, EncoderNLS encoder)
{
// Just need to ASSERT, this is called by something else internal that checked parameters already
Debug.Assert(bytes != null, "[DBCSCodePageEncoding.GetBytes]bytes is null");
Debug.Assert(byteCount >= 0, "[DBCSCodePageEncoding.GetBytes]byteCount is negative");
Debug.Assert(chars != null, "[DBCSCodePageEncoding.GetBytes]chars is null");
Debug.Assert(charCount >= 0, "[DBCSCodePageEncoding.GetBytes]charCount is negative");
// Assert because we shouldn't be able to have a null encoder.
Debug.Assert(EncoderFallback != null, "[DBCSCodePageEncoding.GetBytes]Attempting to use null encoder fallback");
CheckMemorySection();
// For fallback we will need a fallback buffer
EncoderFallbackBuffer fallbackBuffer = null;
// prepare our end
char* charEnd = chars + charCount;
char* charStart = chars;
byte* byteStart = bytes;
byte* byteEnd = bytes + byteCount;
EncoderFallbackBufferHelper fallbackHelper = new EncoderFallbackBufferHelper(fallbackBuffer);
// Get any left over characters
char charLeftOver = (char)0;
if (encoder != null)
{
charLeftOver = encoder.charLeftOver;
Debug.Assert(charLeftOver == 0 || Char.IsHighSurrogate(charLeftOver),
"[DBCSCodePageEncoding.GetBytes]leftover character should be high surrogate");
// Go ahead and get the fallback buffer (need leftover fallback if converting)
fallbackBuffer = encoder.FallbackBuffer;
fallbackHelper = new EncoderFallbackBufferHelper(fallbackBuffer);
fallbackHelper.InternalInitialize(chars, charEnd, encoder, true);
// If we're not converting we must not have a fallback buffer
if (encoder.m_throwOnOverflow && fallbackBuffer.Remaining > 0)
throw new ArgumentException(SR.Format(SR.Argument_EncoderFallbackNotEmpty, EncodingName, encoder.Fallback.GetType()));
// We may have a left over character from last time, try and process it.
if (charLeftOver > 0)
{
Debug.Assert(encoder != null,
"[DBCSCodePageEncoding.GetBytes]Expect to have encoder if we have a charLeftOver");
// Since left over char was a surrogate, it'll have to be fallen back.
// Get Fallback
fallbackHelper.InternalFallback(charLeftOver, ref chars);
}
}
// Now we may have fallback char[] already from the encoder
// Go ahead and do it, including the fallback.
char ch;
while ((ch = (fallbackBuffer == null) ? '\0' : fallbackHelper.InternalGetNextChar()) != 0 ||
chars < charEnd)
{
// First unwind any fallback
if (ch == 0)
{
// No fallback, just get next char
ch = *chars;
chars++;
}
// get byte for this char
ushort sTemp = mapUnicodeToBytes[ch];
// Check for fallback, this'll catch surrogate pairs too.
if (sTemp == 0 && ch != (char)0)
{
if (fallbackBuffer == null)
{
// Initialize the buffer
Debug.Assert(encoder == null,
"[DBCSCodePageEncoding.GetBytes]Expected delayed create fallback only if no encoder.");
fallbackBuffer = EncoderFallback.CreateFallbackBuffer();
fallbackHelper = new EncoderFallbackBufferHelper(fallbackBuffer);
fallbackHelper.InternalInitialize(charEnd - charCount, charEnd, encoder, true);
}
// Get Fallback
fallbackHelper.InternalFallback(ch, ref chars);
continue;
}
// We'll use this one (or two)
// Bounds check
// Go ahead and add it, lead byte 1st if necessary
if (sTemp >= 0x100)
{
if (bytes + 1 >= byteEnd)
{
// didn't use this char, we'll throw or use buffer
if (fallbackBuffer == null || fallbackHelper.bFallingBack == false)
{
Debug.Assert(chars > charStart,
"[DBCSCodePageEncoding.GetBytes]Expected chars to have advanced (double byte case)");
chars--; // don't use last char
}
else
fallbackBuffer.MovePrevious(); // don't use last fallback
ThrowBytesOverflow(encoder, chars == charStart); // throw ?
break; // don't throw, stop
}
*bytes = unchecked((byte)(sTemp >> 8));
bytes++;
}
// Single byte
else if (bytes >= byteEnd)
{
// didn't use this char, we'll throw or use buffer
if (fallbackBuffer == null || fallbackHelper.bFallingBack == false)
{
Debug.Assert(chars > charStart,
"[DBCSCodePageEncoding.GetBytes]Expected chars to have advanced (single byte case)");
chars--; // don't use last char
}
else
fallbackBuffer.MovePrevious(); // don't use last fallback
ThrowBytesOverflow(encoder, chars == charStart); // throw ?
break; // don't throw, stop
}
*bytes = unchecked((byte)(sTemp & 0xff));
bytes++;
}
// encoder stuff if we have one
if (encoder != null)
{
// Fallback stuck it in encoder if necessary, but we have to clear MustFlush cases
if (fallbackBuffer != null && !fallbackHelper.bUsedEncoder)
// Clear it in case of MustFlush
encoder.charLeftOver = (char)0;
// Set our chars used count
encoder.m_charsUsed = (int)(chars - charStart);
}
return (int)(bytes - byteStart);
}