private unsafe int GetBytesCP52936(char* chars, int charCount,
byte* bytes, int byteCount, ISO2022Encoder encoder)
{
// prepare our helpers
EncodingByteBuffer buffer = new EncodingByteBuffer(this, encoder, bytes, byteCount, chars, charCount);
// Mode
ISO2022Modes currentMode = ISO2022Modes.ModeASCII;
// Check our encoder
if (encoder != null)
{
char charLeftOver = encoder.charLeftOver;
currentMode = encoder.currentMode;
// We may have a left over character from last time, try and process it.
if (charLeftOver > 0)
{
Debug.Assert(Char.IsHighSurrogate(charLeftOver), "[ISO2022Encoding.GetBytesCP52936]leftover character should be high surrogate");
// It has to be a high surrogate, which we don't support, so it has to be a fallback
buffer.Fallback(charLeftOver);
}
}
while (buffer.MoreData)
{
// Get our char
char ch = buffer.GetNextChar();
// Get our bytes
ushort sChar = mapUnicodeToBytes[ch];
if (sChar == 0 && ch != 0)
{
// Wasn't a legal byte sequence, its a surrogate or fallback
// Throws if recursive (knows because we called InternalGetNextChar)
buffer.Fallback(ch);
// Done with our char, now process fallback
continue;
}
// Check for halfwidth bytes
byte bLeadByte = (byte)(sChar >> 8);
byte bTrailByte = (byte)(sChar & 0xff);
// If its a double byte, it has to fit in the lead byte 0xa1 - 0xf7, trail byte 0xa1 - 0xfe range
// (including the 0x8080 that our codepage or's to the value)
if ((bLeadByte != 0 &&
(bLeadByte < 0xa1 || bLeadByte > 0xf7 || bTrailByte < 0xa1 || bTrailByte > 0xfe)) ||
(bLeadByte == 0 && bTrailByte > 0x80 && bTrailByte != 0xff))
{
// Illegal character, in 936 code page, but not in HZ subset, get fallback for it
buffer.Fallback(ch);
continue;
}
// sChar is now either ASCII or has an 0x8080 mask
if (bLeadByte != 0)
{
// Its a double byte mode
if (currentMode != ISO2022Modes.ModeHZ)
{
// Need to add the double byte mode marker
if (!buffer.AddByte((byte)'~', (byte)'{', 2))
break; // Stop if no buffer space in convert
currentMode = ISO2022Modes.ModeHZ;
}
// Go ahead and add the 2 bytes
if (!buffer.AddByte(unchecked((byte)(bLeadByte & 0x7f)), unchecked((byte)(bTrailByte & 0x7f))))
break; // Stop if no buffer space in convert
}
else
{
// Its supposed to be ASCII
if (currentMode != ISO2022Modes.ModeASCII)
{
// Need to add the ASCII mode marker
// Will have 1 more byte (or 2 if ~)
if (!buffer.AddByte((byte)'~', (byte)'}', bTrailByte == '~' ? 2 : 1))
break;
currentMode = ISO2022Modes.ModeASCII;
}
// If its a '~' we'll need an extra one
if (bTrailByte == '~')
{
// Need to add the extra ~
if (!buffer.AddByte((byte)'~', 1))
break;
}
// Need to add the character
if (!buffer.AddByte(bTrailByte))
break;
}
}
// Add ASCII shift out if we're at end of decoder
if (currentMode != ISO2022Modes.ModeASCII &&
(encoder == null || encoder.MustFlush))
{
// Need to add the ASCII mode marker
// Only turn off other mode if this works
if (buffer.AddByte((byte)'~', (byte)'}'))
currentMode = ISO2022Modes.ModeASCII;
else
// If not successful, convert will maintain state for next time, also
// AddByte will have decremented our char count, however we need it to remain the same
buffer.GetNextChar();
}
// Need to remember our mode
if (encoder != null && bytes != null)
{
// This is ASCII if we had to flush
encoder.currentMode = currentMode;
if (!buffer.fallbackBufferHelper.bUsedEncoder)
{
encoder.charLeftOver = (char)0;
}
encoder.m_charsUsed = buffer.CharsUsed;
}
// Return our length
return buffer.Count;
}