private unsafe int GetBytesCP5022xJP(char* chars, int charCount,
byte* bytes, int byteCount, ISO2022Encoder encoder)
{
// prepare our helpers
EncodingByteBuffer buffer = new EncodingByteBuffer(this, encoder, bytes, byteCount, chars, charCount);
// Get our mode
ISO2022Modes currentMode = ISO2022Modes.ModeASCII; // Mode
ISO2022Modes shiftInMode = ISO2022Modes.ModeASCII; // Mode that shift in will go back to (only used by CP 50222)
// Check our encoder
if (encoder != null)
{
char charLeftOver = encoder.charLeftOver;
currentMode = encoder.currentMode;
shiftInMode = encoder.shiftInOutMode;
// We may have a left over character from last time, try and process it.
if (charLeftOver > 0)
{
Debug.Assert(Char.IsHighSurrogate(charLeftOver), "[ISO2022Encoding.GetBytesCP5022xJP]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 iBytes = mapUnicodeToBytes[ch];
StartConvert:
// Check for halfwidth bytes
byte bLeadByte = (byte)(iBytes >> 8);
byte bTrailByte = (byte)(iBytes & 0xff);
if (bLeadByte == LEADBYTE_HALFWIDTH)
{
// Its Halfwidth Katakana
if (CodePage == 50220)
{
// CodePage 50220 doesn't use halfwidth Katakana, convert to fullwidth
// See if its out of range, fallback if so, throws if recursive fallback
if (bTrailByte < 0x21 || bTrailByte >= 0x21 + s_HalfToFullWidthKanaTable.Length)
{
buffer.Fallback(ch);
continue;
}
// Get the full width katakana char to use.
iBytes = unchecked((ushort)(s_HalfToFullWidthKanaTable[bTrailByte - 0x21] & 0x7F7F));
// May have to do all sorts of fun stuff for mode, go back to start convert
goto StartConvert;
}
// Can use halfwidth Katakana, make sure we're in right mode
// Make sure we're in right mode
if (currentMode != ISO2022Modes.ModeHalfwidthKatakana)
{
// 50222 or 50221, either shift in/out or escape to get to Katakana mode
if (CodePage == 50222)
{
// Shift Out
if (!buffer.AddByte(SHIFT_OUT))
break; // convert out of space, stop
// Don't change modes until after AddByte in case it fails for convert
// We get to shift out to Katakana, make sure we'll go back to the right mode
// (This ends up always being ASCII)
shiftInMode = currentMode;
currentMode = ISO2022Modes.ModeHalfwidthKatakana;
}
else
{
// 50221 does halfwidth katakana by escape sequence
Debug.Assert(CodePage == 50221, "[ISO2022Encoding.GetBytesCP5022xJP]Expected Code Page 50221");
// Add our escape sequence
if (!buffer.AddByte(ESCAPE, unchecked((byte)'('), unchecked((byte)'I')))
break; // convert out of space, stop
currentMode = ISO2022Modes.ModeHalfwidthKatakana;
}
}
// We know we're in Katakana mode now, so add it.
// Go ahead and add the Katakana byte. Our table tail bytes are 0x80 too big.
if (!buffer.AddByte(unchecked((byte)(bTrailByte & 0x7F))))
break; // convert out of space, stop
// Done with this one
continue;
}
else if (bLeadByte != 0)
{
//
// It's a double byte character.
//
// If we're CP 50222 we may have to shift in from Katakana mode first
if (CodePage == 50222 && currentMode == ISO2022Modes.ModeHalfwidthKatakana)
{
// Shift In
if (!buffer.AddByte(SHIFT_IN))
break; // convert out of space, stop
// Need to shift in from katakana. (Still might not be right, but won't be shifted out anyway)
currentMode = shiftInMode;
}
// Make sure we're in the right mode (JIS 0208 or JIS 0212)
// Note: Right now we don't use JIS 0212. Also this table'd be wrong
// Its JIS extension 0208
if (currentMode != ISO2022Modes.ModeJIS0208)
{
// Escape sequence, we can fail after this, mode will be correct for convert
if (!buffer.AddByte(ESCAPE, unchecked((byte)'$'), unchecked((byte)'B')))
break; // Convert out of space, stop
currentMode = ISO2022Modes.ModeJIS0208;
}
// Add our double bytes
if (!buffer.AddByte(unchecked((byte)(bLeadByte)), unchecked((byte)(bTrailByte))))
break; // Convert out of space, stop
continue;
}
else if (iBytes != 0 || ch == 0)
{
// Single byte Char
// If we're CP 50222 we may have to shift in from Katakana mode first
if (CodePage == 50222 && currentMode == ISO2022Modes.ModeHalfwidthKatakana)
{
// Shift IN
if (!buffer.AddByte(SHIFT_IN))
break; // convert ran out of room
// Need to shift in from katakana. (Still might not be right, but won't be shifted out anyway)
currentMode = shiftInMode;
}
// Its a single byte character, switch to ASCII if we have to
if (currentMode != ISO2022Modes.ModeASCII)
{
if (!buffer.AddByte(ESCAPE, unchecked((byte)'('), unchecked((byte)'B')))
break; // convert ran out of room
currentMode = ISO2022Modes.ModeASCII;
}
// Add the ASCII char
if (!buffer.AddByte(bTrailByte))
break; // convert had no room left
continue;
}
// Its unknown, do fallback, throws if recursive (knows because we called InternalGetNextChar)
buffer.Fallback(ch);
}
// Switch back to ASCII if MustFlush or no encoder
if (currentMode != ISO2022Modes.ModeASCII &&
(encoder == null || encoder.MustFlush))
{
// If we're CP 50222 we may have to shift in from Katakana mode first
if (CodePage == 50222 && currentMode == ISO2022Modes.ModeHalfwidthKatakana)
{
// Shift IN, only shift mode if necessary.
if (buffer.AddByte(SHIFT_IN))
// Need to shift in from katakana. (Still might not be right, but won't be shifted out anyway)
currentMode = shiftInMode;
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();
}
// switch back to ASCII to finish neatly
if (currentMode != ISO2022Modes.ModeASCII &&
(CodePage != 50222 || currentMode != ISO2022Modes.ModeHalfwidthKatakana))
{
// only shift if it was successful
if (buffer.AddByte(ESCAPE, unchecked((byte)'('), unchecked((byte)'B')))
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();
}
}
// Remember our encoder state
if (bytes != null && encoder != null)
{
// This is ASCII if we had to flush
encoder.currentMode = currentMode;
encoder.shiftInOutMode = shiftInMode;
if (!buffer.fallbackBufferHelper.bUsedEncoder)
{
encoder.charLeftOver = (char)0;
}
encoder.m_charsUsed = buffer.CharsUsed;
}
// Return our length
return buffer.Count;
}