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
// We'll allow null bytes as a count
// Debug.Assert(bytes != null, "[GB18030Encoding.GetBytes]bytes is null");
Debug.Assert(byteCount >= 0, "[GB18030Encoding.GetBytes]byteCount is negative");
Debug.Assert(chars != null, "[GB18030Encoding.GetBytes]chars is null");
Debug.Assert(charCount >= 0, "[GB18030Encoding.GetBytes]charCount is negative");
// Assert because we shouldn't be able to have a null encoder.
Debug.Assert(EncoderFallback != null, "[GB18030Encoding.GetBytes]Attempting to use null encoder fallback");
// Get any left over characters
char charLeftOver = (char)0;
if (encoder != null)
charLeftOver = encoder.charLeftOver;
// prepare our helpers
EncodingByteBuffer buffer = new EncodingByteBuffer(this, encoder, bytes, byteCount, chars, charCount);
// Try again if we were MustFlush
TryAgain:
// Go ahead and do it, including the fallback.
while (buffer.MoreData)
{
// Get next char
char ch = buffer.GetNextChar();
// Have to check for charLeftOver
if (charLeftOver != 0)
{
Debug.Assert(Char.IsHighSurrogate(charLeftOver),
"[GB18030Encoding.GetBytes] leftover character should be high surrogate, not 0x" + ((int)charLeftOver).ToString("X4", CultureInfo.InvariantCulture));
// If our next char isn't a low surrogate, then we need to do fallback.
if (!Char.IsLowSurrogate(ch))
{
// No low surrogate, fallback high surrogate & try this one again
buffer.MovePrevious(false); // (Ignoring this character, don't throw)
if (!buffer.Fallback(charLeftOver))
{
charLeftOver = (char)0;
break;
}
charLeftOver = (char)0;
continue;
}
else
{
// Next is a surrogate, add it as surrogate pair
// Need 4 bytes for surrogates
// Get our offset
int offset = ((charLeftOver - 0xd800) << 10) + (ch - 0xdc00);
byte byte4 = (byte)((offset % 0x0a) + 0x30);
offset /= 0x0a;
byte byte3 = (byte)((offset % 0x7e) + 0x81);
offset /= 0x7e;
byte byte2 = (byte)((offset % 0x0a) + 0x30);
offset /= 0x0a;
Debug.Assert(offset < 0x6f,
"[GB18030Encoding.GetBytes](1) Expected offset < 0x6f, not 0x" + offset.ToString("X2", CultureInfo.InvariantCulture));
charLeftOver = (char)0;
if (!buffer.AddByte((byte)(offset + 0x90), byte2, byte3, byte4))
{
// Didn't work, need to back up for both surrogates (AddByte already backed up one)
buffer.MovePrevious(false); // (don't throw)
break;
}
}
charLeftOver = '\0';
}
// ASCII's easiest
else if (ch <= 0x7f)
{
// Need a byte
if (!buffer.AddByte((byte)ch))
break;
}
// See if its a surrogate pair
else if (Char.IsHighSurrogate(ch))
{
// Remember it for next time
charLeftOver = ch;
}
else if (Char.IsLowSurrogate(ch))
{
// Low surrogates should've been found already
if (!buffer.Fallback(ch))
break;
}
else
{
// Not surrogate or ASCII, get value
ushort iBytes = mapUnicodeToBytes[ch];
// See what kind it is
if (Is4Byte(ch))
{
//
// This Unicode character will be converted to four-byte GB18030.
//
// Need 4 bytes
byte byte4 = (byte)((iBytes % 0x0a) + 0x30);
iBytes /= 0x0a;
byte byte3 = (byte)((iBytes % 0x7e) + 0x81);
iBytes /= 0x7e;
byte byte2 = (byte)((iBytes % 0x0a) + 0x30);
iBytes /= 0x0a;
Debug.Assert(iBytes < 0x7e,
"[GB18030Encoding.GetBytes]Expected iBytes < 0x7e, not 0x" + iBytes.ToString("X2", CultureInfo.InvariantCulture));
if (!buffer.AddByte((byte)(iBytes + 0x81), byte2, byte3, byte4))
break;
}
else
{
// Its 2 byte, use it
if (!buffer.AddByte(unchecked((byte)(iBytes >> 8)), unchecked((byte)(iBytes & 0xff))))
break;
}
}
}
// Do we need to flush our charLeftOver?
if ((encoder == null || encoder.MustFlush) && (charLeftOver > 0))
{
// Fall it back
buffer.Fallback(charLeftOver);
charLeftOver = (char)0;
goto TryAgain;
}
// Fallback stuck it in encoder if necessary, but we have to clear MustFlash cases
// (Check bytes != null, don't clear it if we're just counting)
if (encoder != null)
{
// Remember our charLeftOver
if (bytes != null)
encoder.charLeftOver = charLeftOver;
encoder.m_charsUsed = buffer.CharsUsed;
}
// Return our length
return buffer.Count;
}