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;
}
}
}