// Parses the format 4 cmap table // Refer to https://www.microsoft.com/typography/otspec/cmap.htm to learn about how this format is organized private void ParseFormat4(byte[] source, ref uint offset, List <GlyphModel> allChars) { CmapFormat4Header header = ParseCmapFormat4Header(source, ref offset); int segCount = (int)header.segCountX2 / 2; ushort[] endCountArray = ReadUshortArrayAndIncreaseIndex(segCount, source, ref offset, sizeof(ushort)); ushort reservedPad = ReadDataAndIncreaseIndex <ushort>(source, ref offset, sizeof(ushort)); ushort[] startCountArray = ReadUshortArrayAndIncreaseIndex(segCount, source, ref offset, sizeof(ushort)); short[] idDeltaArray = ReadShortArrayAndIncreaseIndex(segCount, source, ref offset, sizeof(short)); uint idRangeTableOffset = offset; ushort[] idRangeTable = ReadUshortArrayAndIncreaseIndex(segCount, source, ref offset, sizeof(ushort)); for (byte i = 0; i < startCountArray.Length - 1; i++) { if (idRangeTable[i] == 0) { for (uint j = startCountArray[i]; j <= endCountArray[i]; j++) { GlyphModel newChar = new GlyphModel(); newChar.CodePoint = j; newChar.GlyphID = (ushort)(j + idDeltaArray[i]); byte[] byteJ = BitConverter.GetBytes(j); newChar.Definition = Encoding.UTF32.GetString(byteJ); if (!allChars.Contains(newChar)) { allChars.Add(newChar); } } } else { uint glyphIdOffset = idRangeTableOffset + idRangeTable[i] + (uint)(i * 2); for (uint j = startCountArray[i]; j <= endCountArray[i]; j++) { ushort gID = ReadDataAndIncreaseIndex <ushort>(source, ref glyphIdOffset, sizeof(ushort)); GlyphModel newChar = new GlyphModel(); newChar.CodePoint = j; newChar.GlyphID = gID; byte[] byteJ = BitConverter.GetBytes(j); newChar.Definition = Encoding.UTF32.GetString(byteJ); if (!allChars.Contains(newChar)) { allChars.Add(newChar); } } } } }
// Reads through the header information of the cmap format 4 table private CmapFormat4Header ParseCmapFormat4Header(byte[] source, ref uint offset) { CmapFormat4Header header = new CmapFormat4Header(); header.format = ReadDataAndIncreaseIndex <ushort>(source, ref offset, sizeof(ushort)); Debug.Assert(header.format == 4); header.length = ReadDataAndIncreaseIndex <ushort>(source, ref offset, sizeof(ushort)); header.language = ReadDataAndIncreaseIndex <ushort>(source, ref offset, sizeof(ushort)); header.segCountX2 = ReadDataAndIncreaseIndex <ushort>(source, ref offset, sizeof(ushort)); header.searchRange = ReadDataAndIncreaseIndex <ushort>(source, ref offset, sizeof(ushort)); header.entrySelector = ReadDataAndIncreaseIndex <ushort>(source, ref offset, sizeof(ushort)); header.rangeShift = ReadDataAndIncreaseIndex <ushort>(source, ref offset, sizeof(ushort)); return(header); }