using System; using System.Collections.Generic; using System.IO; using System.Text; namespace FontPreview; internal static class FontNameParser { private struct NameRec { public int PlatformID; public int EncodingID; public int LanguageID; public int NameID; public byte[] Data; } private const int TTF_DIRREC_LEN = 16; internal static string GetDisplayName(string fontPath, string fallback) { try { string text = Parse(fontPath); return string.IsNullOrEmpty(text) ? fallback : text; } catch { return fallback; } } private static string Parse(string path) { using FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete); byte[] array = new byte[12]; if (!ReadFully(fileStream, array, 0, 12)) { return null; } long num; if (array[0] == 116 && array[1] == 116 && array[2] == 99 && array[3] == 102) { byte[] array2 = new byte[4]; if (!ReadFully(fileStream, array2, 0, 4)) { return null; } num = Be32(array2, 0); } else { num = 0L; } fileStream.Seek(num + 4, SeekOrigin.Begin); byte[] array3 = new byte[2]; if (!ReadFully(fileStream, array3, 0, 2)) { return null; } int num2 = (array3[0] << 8) | array3[1]; fileStream.Seek(num + 12, SeekOrigin.Begin); long num3 = 0L; long num4 = 0L; byte[] array4 = new byte[16]; for (int i = 0; i < num2; i++) { if (!ReadFully(fileStream, array4, 0, 16)) { return null; } if (array4[0] == 110 && array4[1] == 97 && array4[2] == 109 && array4[3] == 101) { num3 = Be32(array4, 8); num4 = Be32(array4, 12); break; } } if (num3 == 0 || num4 <= 0 || num4 > 4194304) { return null; } byte[] array5 = new byte[num4]; fileStream.Seek(num3, SeekOrigin.Begin); if (!ReadFully(fileStream, array5, 0, (int)num4)) { return null; } List list = new List(); int num5 = (array5[2] << 8) | array5[3]; int num6 = (array5[4] << 8) | array5[5]; int num7 = 6; for (int i = 0; i < num5; i++) { if (num7 + 12 > num4) { break; } int platformID = (array5[num7] << 8) | array5[num7 + 1]; int encodingID = (array5[num7 + 2] << 8) | array5[num7 + 3]; int languageID = (array5[num7 + 4] << 8) | array5[num7 + 5]; int nameID = (array5[num7 + 6] << 8) | array5[num7 + 7]; int num8 = (array5[num7 + 8] << 8) | array5[num7 + 9]; int num9 = (array5[num7 + 10] << 8) | array5[num7 + 11]; if (num9 >= 0 && num8 > 0 && num6 + num9 + num8 <= num4) { NameRec item = default(NameRec); item.PlatformID = platformID; item.EncodingID = encodingID; item.LanguageID = languageID; item.NameID = nameID; item.Data = new byte[num8]; Array.Copy(array5, num6 + num9, item.Data, 0, num8); list.Add(item); } num7 += 12; } int[] array6 = new int[4] { 1, 4, 6, 16 }; int[] array7 = array6; foreach (int nameID2 in array7) { string text = PickBest(list, nameID2); if (!string.IsNullOrEmpty(text)) { return text; } } return null; } private static string PickBest(List recs, int nameID) { List list = new List(); foreach (NameRec rec in recs) { if (rec.NameID == nameID) { list.Add(rec); } } if (list.Count == 0) { return null; } foreach (NameRec item in list) { if (item.PlatformID == 3 && item.LanguageID == 2052) { string text = Decode(item); if (!string.IsNullOrEmpty(text)) { return text; } } } foreach (NameRec item2 in list) { if (item2.PlatformID == 3 && item2.LanguageID == 1033) { string text = Decode(item2); if (!string.IsNullOrEmpty(text)) { return text; } } } foreach (NameRec item3 in list) { if (item3.PlatformID == 3 && item3.LanguageID == 0) { string text = Decode(item3); if (!string.IsNullOrEmpty(text)) { return text; } } } foreach (NameRec item4 in list) { if (item4.PlatformID == 3) { string text = Decode(item4); if (!string.IsNullOrEmpty(text)) { return text; } } } foreach (NameRec item5 in list) { if (item5.PlatformID == 0) { string text = Decode(item5); if (!string.IsNullOrEmpty(text)) { return text; } } } foreach (NameRec item6 in list) { if (item6.PlatformID == 1) { string text = Decode(item6); if (!string.IsNullOrEmpty(text)) { return text; } } } return null; } private static string Decode(NameRec r) { string text; try { text = ((r.PlatformID != 3 && r.PlatformID != 0) ? Encoding.GetEncoding(28591).GetString(r.Data) : Encoding.BigEndianUnicode.GetString(r.Data)); } catch { return null; } text = text.Trim('\0', ' ', '\t', '\r', '\n'); return string.IsNullOrEmpty(text) ? null : text; } private static bool ReadFully(Stream s, byte[] buf, int off, int len) { int num; for (int i = 0; i < len; i += num) { num = s.Read(buf, off + i, len - i); if (num <= 0) { return false; } } return true; } private static uint Be32(byte[] b, int off) { return (uint)((b[off] << 24) | (b[off + 1] << 16) | (b[off + 2] << 8) | b[off + 3]); } }