namespace UglyToad.PdfPig.Fonts { using System; using System.Collections.Generic; using System.Globalization; using System.Text; using Encodings; /// /// A list which maps PostScript glyph names to unicode values. /// public class GlyphList { private const string NotDefined = ".notdef"; private readonly IReadOnlyDictionary nameToUnicode; private readonly IReadOnlyDictionary unicodeToName; private readonly Dictionary oddNameToUnicodeCache = new Dictionary(); private static readonly Lazy LazyAdobeGlyphList = new Lazy(() => GlyphListFactory.Get("glyphlist")); /// /// The Adobe Glyph List. /// public static GlyphList AdobeGlyphList => LazyAdobeGlyphList.Value; private static readonly Lazy LazyAdditionalGlyphList = new Lazy(() => GlyphListFactory.Get("additional")); /// /// An extension to the Adobe Glyph List. /// public static GlyphList AdditionalGlyphList => LazyAdditionalGlyphList.Value; private static readonly Lazy LazyZapfDingbatsGlyphList = new Lazy(() => GlyphListFactory.Get("zapfdingbats")); /// /// Zapf Dingbats. /// public static GlyphList ZapfDingbats => LazyZapfDingbatsGlyphList.Value; internal GlyphList(IReadOnlyDictionary namesToUnicode) { nameToUnicode = namesToUnicode; var unicodeToNameTemp = new Dictionary(); foreach (var pair in namesToUnicode) { var forceOverride = WinAnsiEncoding.Instance.ContainsName(pair.Key) || MacRomanEncoding.Instance.ContainsName(pair.Key) || MacExpertEncoding.Instance.ContainsName(pair.Key) || SymbolEncoding.Instance.ContainsName(pair.Key) || ZapfDingbatsEncoding.Instance.ContainsName(pair.Key); if (!unicodeToNameTemp.ContainsKey(pair.Value) || forceOverride) { unicodeToNameTemp[pair.Value] = pair.Key; } } unicodeToName = unicodeToNameTemp; } /// /// Get the name for the unicode code point value. /// public string UnicodeCodePointToName(int unicodeValue) { var value = char.ConvertFromUtf32(unicodeValue); if (unicodeToName.TryGetValue(value, out var result)) { return result; } return NotDefined; } /// /// Get the unicode value for the glyph name. /// public string NameToUnicode(string name) { if (name == null) { return null; } if (nameToUnicode.TryGetValue(name, out var unicodeValue)) { return unicodeValue; } if (oddNameToUnicodeCache.TryGetValue(name, out var result)) { return result; } string unicode; // Remove suffixes if (name.IndexOf('.') > 0) { unicode = NameToUnicode(name.Substring(0, name.IndexOf('.'))); } else if (name.StartsWith("uni") && name.Length == 7) { // test for Unicode name in the format uniXXXX where X is hex int nameLength = name.Length; var uniStr = new StringBuilder(); var foundUnicode = true; for (int chPos = 3; chPos + 4 <= nameLength; chPos += 4) { if (!int.TryParse(name.Substring(chPos, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var codePoint)) { foundUnicode = false; break; } if (codePoint > 0xD7FF && codePoint < 0xE000) { throw new InvalidFontFormatException($"Unicode character name with disallowed code area: {name}"); } uniStr.Append((char)codePoint); } if (!foundUnicode) { return null; } unicode = uniStr.ToString(); } else if (name.StartsWith("u") && name.Length == 5) { // test for an alternate Unicode name representation uXXXX var codePoint = int.Parse(name.Substring(1), NumberStyles.HexNumber, CultureInfo.InvariantCulture); if (codePoint > 0xD7FF && codePoint < 0xE000) { throw new InvalidFontFormatException( $"Unicode character name with disallowed code area: {name}"); } unicode = char.ConvertFromUtf32(codePoint); } else { return null; } oddNameToUnicodeCache[name] = unicode; return unicode; } } }