using Cryville.Common.IO; using System; using System.Collections; using System.Collections.Generic; using System.IO; namespace Cryville.Common.Font { public abstract class FontFile : IEnumerable { public abstract int Count { get; } public abstract Typeface this[int index] { get; } protected FileInfo File { get; private set; } protected BinaryReader Reader { get; private set; } public FontFile(FileInfo file) { File = file; Reader = new BinaryReaderBE(new FileStream(file.FullName, FileMode.Open, FileAccess.Read)); } public void Close() { Reader.Close(); } public static FontFile Create(FileInfo file) { switch (file.Extension) { case ".ttf": case ".otf": return new FontFileTTF(file); case ".ttc": case ".otc": return new FontFileTTC(file); default: return null; } } public Enumerator GetEnumerator() { return new Enumerator(this); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public struct Enumerator : IEnumerator { readonly FontFile _self; int _index; internal Enumerator(FontFile self) { _self = self; _index = -1; } public Typeface Current { get { if (_index < 0) throw new InvalidOperationException(_index == -1 ? "Enum not started" : "Enum ended"); return _self[_index]; } } object IEnumerator.Current { get { return Current; } } public void Dispose() { _index = -2; } public bool MoveNext() { if (_index == -2) return false; _index++; if (_index >= _self.Count) { _index = -2; return false; } return true; } public void Reset() { _index = -1; } } } public class FontFileTTF : FontFile { public override int Count { get { return 1; } } public override Typeface this[int index] { get { if (index != 0) throw new ArgumentOutOfRangeException("index"); try { return new TypefaceTTF(Reader, File, index); } catch (Exception) { throw new InvalidDataException("Invalid font"); } } } public FontFileTTF(FileInfo file) : base(file) { } } public class FontFileTTC : FontFile { readonly IReadOnlyList _offsets; public override int Count { get { return _offsets.Count; } } public override Typeface this[int index] { get { if (index < 0 || index >= Count) throw new ArgumentOutOfRangeException("index"); Reader.BaseStream.Position = _offsets[index]; try { return new TypefaceTTF(Reader, File, index); } catch (Exception) { throw new InvalidDataException("Invalid font"); } } } public FontFileTTC(FileInfo file) : base(file) { try { _offsets = new TTCHeader(Reader, 0).GetItems(); } catch (Exception) { throw new InvalidDataException("Invalid font"); } } } }