private unsafe int GetCharsCP50225KR(byte* bytes, int byteCount,
char* chars, int charCount, ISO2022Decoder decoder)
{
// Get our info.
EncodingCharBuffer buffer = new EncodingCharBuffer(this, decoder, chars, charCount, bytes, byteCount);
// No mode information yet
ISO2022Modes currentMode = ISO2022Modes.ModeASCII; // Our current Mode
byte[] escapeBytes = new byte[4];
int escapeCount = 0;
if (decoder != null)
{
currentMode = decoder.currentMode;
// See if we have leftover decoder buffer to use
// Load our bytesLeftOver
escapeCount = decoder.bytesLeftOverCount;
// Don't want to mess up decoder if we're counting or throw an exception
for (int i = 0; i < escapeCount; i++)
escapeBytes[i] = decoder.bytesLeftOver[i];
}
// Do this until the end, just do '?' replacement because we don't have fallbacks for decodings.
while (buffer.MoreData || escapeCount > 0)
{
byte ch;
if (escapeCount > 0)
{
// Get more escape sequences if necessary
if (escapeBytes[0] == ESCAPE)
{
// Stop if no more input
if (!buffer.MoreData)
{
if (decoder != null && !decoder.MustFlush)
break;
}
else
{
// Add it to the sequence we can check
escapeBytes[escapeCount++] = buffer.GetNextByte();
// We have an escape sequence
ISO2022Modes modeReturn =
CheckEscapeSequenceKR(escapeBytes, escapeCount);
if (modeReturn != ISO2022Modes.ModeInvalidEscape)
{
if (modeReturn != ISO2022Modes.ModeIncompleteEscape)
{
// Processed escape correctly, no effect (we know about KR mode)
escapeCount = 0;
}
// Either way, continue to get next escape or real byte
continue;
}
}
// If ModeInvalidEscape, or no input & must flush, then fall through to add escape.
}
// Still have something left over in escape buffer
// Get it and move them down one
ch = DecrementEscapeBytes(ref escapeBytes, ref escapeCount);
}
else
{
// Get our next byte
ch = buffer.GetNextByte();
if (ch == ESCAPE)
{
// We'll have an escape sequence, use it if we don't have one buffered already
if (escapeCount == 0)
{
// Start this new escape sequence
escapeBytes[0] = ch;
escapeCount = 1;
continue;
}
// Flush previous escape sequence, then reuse this escape byte
buffer.AdjustBytes(-1);
}
}
if (ch == SHIFT_OUT)
{
currentMode = ISO2022Modes.ModeKR;
continue;
}
else if (ch == SHIFT_IN)
{
currentMode = ISO2022Modes.ModeASCII;
continue;
}
// Get our full character
ushort iBytes = ch;
bool b2Bytes = false;
// MLANG was passing through ' ', '\t' and '\n', so we do so as well, but I don't see that in the RFC.
if (currentMode == ISO2022Modes.ModeKR && ch != ' ' && ch != '\t' && ch != '\n')
{
//
// To handle errors, we need to check:
// 1. if trailbyte is there
// 2. if code is valid
//
if (escapeCount > 0)
{
// Let another escape fall through
if (escapeBytes[0] != ESCAPE)
{
// Move them down one & get the next data
iBytes <<= 8;
iBytes |= DecrementEscapeBytes(ref escapeBytes, ref escapeCount);
b2Bytes = true;
}
}
else if (buffer.MoreData)
{
iBytes <<= 8;
iBytes |= buffer.GetNextByte();
b2Bytes = true;
}
else
{
// Not enough input, use decoder if possible
if (decoder == null || decoder.MustFlush)
{
// No decoder, do fallback for lonely 1st byte
buffer.Fallback(ch);
break;
}
// Stick it in the decoder if we're not counting
if (chars != null)
{
escapeBytes[0] = ch;
escapeCount = 1;
}
break;
}
}
// We have a iBytes to try to convert.
char c = mapBytesToUnicode[iBytes];
// See if it was unknown
if (c == UNKNOWN_CHAR_FLAG && iBytes != 0)
{
// Have to do fallback
if (b2Bytes)
{
if (!buffer.Fallback((byte)(iBytes >> 8), (byte)iBytes))
break;
}
else
{
if (!buffer.Fallback(ch))
break;
}
}
else
{
if (!buffer.AddChar(c, b2Bytes ? 2 : 1))
break;
}
}
// Make sure our decoder state matches our mode, if not counting
if (chars != null && decoder != null)
{
// Remember it if we don't flush
if (!decoder.MustFlush || escapeCount != 0)
{
// Either not flushing or had state (from convert)
Debug.Assert(!decoder.MustFlush || !decoder.m_throwOnOverflow,
"[ISO2022Encoding.GetCharsCP50225KR]Expected no state or not converting or not flushing");
decoder.currentMode = currentMode;
// Remember escape buffer
decoder.bytesLeftOverCount = escapeCount;
decoder.bytesLeftOver = escapeBytes;
}
else
{
// We flush, clear buffer
decoder.currentMode = ISO2022Modes.ModeASCII;
decoder.shiftInOutMode = ISO2022Modes.ModeASCII;
decoder.bytesLeftOverCount = 0;
}
decoder.m_bytesUsed = buffer.BytesUsed;
}
// Return # of characters we found
return buffer.Count;
}