protected unsafe override void ReadBestFitTable()
{
// Lock so we don't confuse ourselves.
lock (InternalSyncObject)
{
// If we got a best fit array already, then don't do this
if (arrayUnicodeBestFit == null)
{
//
// Read in Best Fit table.
//
// First check the SBCS->Unicode best fit table, which starts right after the
// 256 word data table. This table looks like word, word where 1st word is byte and 2nd
// word is replacement for that word. It ends when byte == 0.
byte[] buffer = new byte[m_dataSize - 512];
lock (s_streamLock)
{
s_codePagesEncodingDataStream.Seek(m_firstDataWordOffset + 512, SeekOrigin.Begin);
s_codePagesEncodingDataStream.Read(buffer, 0, buffer.Length);
}
fixed (byte* pBuffer = buffer)
{
byte* pData = pBuffer;
// Need new best fit array
char[] arrayTemp = new char[256];
for (int i = 0; i < 256; i++)
arrayTemp[i] = _mapBytesToUnicode[i];
// See if our words are zero
ushort byteTemp;
while ((byteTemp = *((ushort*)pData)) != 0)
{
Debug.Assert(arrayTemp[byteTemp] == UNKNOWN_CHAR, String.Format(CultureInfo.InvariantCulture,
"[SBCSCodePageEncoding::ReadBestFitTable] Expected unallocated byte (not 0x{2:X2}) for best fit byte at 0x{0:X2} for code page {1}",
byteTemp, CodePage, (int)arrayTemp[byteTemp]));
pData += 2;
arrayTemp[byteTemp] = *((char*)pData);
pData += 2;
}
// Remember our new array
arrayBytesBestFit = arrayTemp;
// It was on 0, it needs to be on next byte
pData += 2;
byte* pUnicodeToSBCS = pData;
// Now count our characters from our Unicode->SBCS best fit table,
// which is right after our 256 byte data table
int iBestFitCount = 0;
// Now do the UnicodeToBytes Best Fit mapping (this is the one we normally think of when we say "best fit")
// pData should be pointing at the first data point for Bytes->Unicode table
int unicodePosition = *((ushort*)pData);
pData += 2;
while (unicodePosition < 0x10000)
{
// Get the next byte
byte input = *pData;
pData++;
// build our table:
if (input == 1)
{
// Use next 2 bytes as our byte position
unicodePosition = *((ushort*)pData);
pData += 2;
}
else if (input < 0x20 && input > 0 && input != 0x1e)
{
// Advance input characters
unicodePosition += input;
}
else
{
// Use this character if it isn't zero
if (input > 0)
iBestFitCount++;
// skip this unicode position in any case
unicodePosition++;
}
}
// Make an array for our best fit data
arrayTemp = new char[iBestFitCount * 2];
// Now actually read in the data
// reset pData should be pointing at the first data point for Bytes->Unicode table
pData = pUnicodeToSBCS;
unicodePosition = *((ushort*)pData);
pData += 2;
iBestFitCount = 0;
while (unicodePosition < 0x10000)
{
// Get the next byte
byte input = *pData;
pData++;
// build our table:
if (input == 1)
{
// Use next 2 bytes as our byte position
unicodePosition = *((ushort*)pData);
pData += 2;
}
else if (input < 0x20 && input > 0 && input != 0x1e)
{
// Advance input characters
unicodePosition += input;
}
else
{
// Check for escape for glyph range
if (input == 0x1e)
{
// Its an escape, so just read next byte directly
input = *pData;
pData++;
}
// 0 means just skip me
if (input > 0)
{
// Use this character
arrayTemp[iBestFitCount++] = (char)unicodePosition;
// Have to map it to Unicode because best fit will need unicode value of best fit char.
arrayTemp[iBestFitCount++] = _mapBytesToUnicode[input];
// This won't work if it won't round trip.
Debug.Assert(arrayTemp[iBestFitCount - 1] != (char)0,
String.Format(CultureInfo.InvariantCulture,
"[SBCSCodePageEncoding.ReadBestFitTable] No valid Unicode value {0:X4} for round trip bytes {1:X4}, encoding {2}",
(int)_mapBytesToUnicode[input], (int)input, CodePage));
}
unicodePosition++;
}
}
// Remember it
arrayUnicodeBestFit = arrayTemp;
} // Fixed()
}
}
}