public unsafe override int GetBytes(char* chars, int charCount, byte* bytes, int byteCount, EncoderNLS baseEncoder)
{
// Allow null bytes for counting
Debug.Assert(chars != null, "[ISCIIEncoding.GetBytes]chars!=null");
// Debug.Assert(bytes != null, "[ISCIIEncoding.GetBytes]bytes!=null");
Debug.Assert(charCount >= 0, "[ISCIIEncoding.GetBytes]charCount >=0");
Debug.Assert(byteCount >= 0, "[ISCIIEncoding.GetBytes]byteCount >=0");
// Need the ISCII Encoder
ISCIIEncoder encoder = (ISCIIEncoder)baseEncoder;
// prepare our helpers
EncodingByteBuffer buffer = new EncodingByteBuffer(this, encoder, bytes, byteCount, chars, charCount);
int currentCodePage = _defaultCodePage;
bool bLastVirama = false;
// Use encoder info if available
if (encoder != null)
{
// Remember our old state
currentCodePage = encoder.currentCodePage;
bLastVirama = encoder.bLastVirama;
// If we have a high surrogate left over, then fall it back
if (encoder.charLeftOver > 0)
{
buffer.Fallback(encoder.charLeftOver);
bLastVirama = false; // Redundant
}
}
while (buffer.MoreData)
{
// Get our data
char ch = buffer.GetNextChar();
// See if its a Multi Byte Character
if (ch < MultiByteBegin)
{
// Its a boring low character, add it.
if (!buffer.AddByte((byte)ch))
break;
bLastVirama = false;
continue;
}
// See if its outside of the Indic script range
if ((ch < IndicBegin) || (ch > IndicEnd))
{
// See if its a ZWJ or ZWNJ and if we has bLastVirama;
if (bLastVirama && (ch == ZWNJ || ch == ZWJ))
{
// It was a bLastVirama and ZWNJ || ZWJ
if (ch == ZWNJ)
{
if (!buffer.AddByte(Virama))
break;
}
else // ZWJ
{
if (!buffer.AddByte(Nukta))
break;
}
// bLastVirama now counts as false
bLastVirama = false;
continue;
}
// Have to do our fallback
//
// Note that this will fallback 2 chars if this is a high surrogate.
// Throws if recursive (knows because we called InternalGetNextChar)
buffer.Fallback(ch);
bLastVirama = false;
continue;
}
// Its in the Unicode Indic script range
int indicInfo = s_UnicodeToIndicChar[ch - IndicBegin];
byte byteIndic = (byte)indicInfo;
int indicScript = (0x000f & (indicInfo >> 8));
int indicTwoBytes = (0xf000 & indicInfo);
// If IndicInfo is 0 then have to do fallback
if (indicInfo == 0)
{
// Its some Unicode character we don't have indic for.
// Have to do our fallback
// Add Fallback Count
// Note that chars was preincremented, and GetEncoderFallbackString might add an extra
// if chars != charEnd and there's a surrogate.
// Throws if recursive (knows because we called InternalGetNextChar)
buffer.Fallback(ch);
bLastVirama = false;
continue;
}
// See if our code page ("font" in ISCII spec) has to change
// (This if doesn't add character, just changes character set)
Debug.Assert(indicScript != 0, "[ISCIIEncoding.GetBytes]expected an indic script value");
if (indicScript != currentCodePage)
{
// It changed, spit out the ATR
if (!buffer.AddByte(ControlATR, (byte)(indicScript | ControlCodePageStart)))
break;
// Now spit out the new code page (& remember it) (do this afterwards in case AddByte failed)
currentCodePage = indicScript;
// We only know how to map from Unicode to pages from Devanagari to Punjabi (2 to 11)
Debug.Assert(currentCodePage >= CodeDevanagari && currentCodePage <= CodePunjabi,
"[ISCIIEncoding.GetBytes]Code page (" + currentCodePage + " shouldn't appear in ISCII from Unicode table!");
}
// Safe to add our byte now
if (!buffer.AddByte(byteIndic, indicTwoBytes != 0 ? 1 : 0))
break;
// Remember if this one was a Virama
bLastVirama = (byteIndic == Virama);
// Some characters need extra bytes
if (indicTwoBytes != 0)
{
// This one needs another byte
Debug.Assert((indicTwoBytes >> 12) > 0 && (indicTwoBytes >> 12) <= 3,
"[ISCIIEncoding.GetBytes]Expected indicTwoBytes from 1-3, not " + (indicTwoBytes >> 12));
// Already did buffer checking, but...
if (!buffer.AddByte(s_SecondIndicByte[indicTwoBytes >> 12]))
break;
}
}
// May need to switch back to our default code page
if (currentCodePage != _defaultCodePage && (encoder == null || encoder.MustFlush))
{
// It changed, spit out the ATR
if (buffer.AddByte(ControlATR, (byte)(_defaultCodePage | ControlCodePageStart)))
currentCodePage = _defaultCodePage;
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();
bLastVirama = false;
}
// Make sure we remember our state if necessary
// Note that we don't care about flush because Virama and code page
// changes are legal at the end.
// Don't set encoder if we're just counting
if (encoder != null && bytes != null)
{
// Clear Encoder if necessary.
if (!buffer.fallbackBufferHelper.bUsedEncoder)
{
encoder.charLeftOver = (char)0;
}
// Remember our code page/virama state
encoder.currentCodePage = currentCodePage;
encoder.bLastVirama = bLastVirama;
// How many chars were used?
encoder.m_charsUsed = buffer.CharsUsed;
}
// Return our length
return buffer.Count;
}