namespace UglyToad.PdfPig.Fonts.CompactFontFormat { using System; using System.Collections.Generic; using System.Diagnostics; using System.Text; using Core; /// /// Provides access to the raw bytes of this Compact Font Format file with utility methods for reading data types from it. /// public class CompactFontFormatData { private readonly IReadOnlyList dataBytes; /// /// The current position in the data. /// public int Position { get; private set; } = -1; /// /// The length of the data. /// public int Length => dataBytes.Count; /// /// Create a new . /// [DebuggerStepThrough] public CompactFontFormatData(IReadOnlyList dataBytes) { this.dataBytes = dataBytes; } /// /// Read a string of the specified length. /// public string ReadString(int length, Encoding encoding) { var bytes = new byte[length]; for (var i = 0; i < bytes.Length; i++) { bytes[i] = ReadByte(); } return encoding.GetString(bytes); } /// /// Read Card8 format. /// public byte ReadCard8() { return ReadByte(); } /// /// Read Card16 format. /// public ushort ReadCard16() { return (ushort)(ReadByte() << 8 | ReadByte()); } /// /// Read Offsize. /// public byte ReadOffsize() { return ReadByte(); } /// /// Read Offset. /// public int ReadOffset(int offsetSize) { var value = 0; for (var i = 0; i < offsetSize; i++) { value = value << 8 | ReadByte(); } return value; } /// /// Read byte. /// public byte ReadByte() { Position++; if (Position >= dataBytes.Count) { throw new IndexOutOfRangeException($"Cannot read byte at position {Position} of an array which is {dataBytes.Count} bytes long."); } return dataBytes[Position]; } /// /// Peek the next byte without advancing the data. /// public byte Peek() { return dataBytes[Position + 1]; } /// /// Whether there's more data to read in the input. /// public bool CanRead() { return Position < dataBytes.Count - 1; } /// /// Move to the given offset from the beginning. /// public void Seek(int offset) { Position = offset - 1; } /// /// Read long. /// public long ReadLong() { return (ReadCard16() << 16) | ReadCard16(); } /// /// Read sid. /// public int ReadSid() { return ReadByte() << 8 | ReadByte(); } /// /// Read byte array of given length. /// public byte[] ReadBytes(int length) { var result = new byte[length]; for (int i = 0; i < length; i++) { result[i] = ReadByte(); } return result; } /// /// Create a new from this data with a snapshot at the position and length. /// public CompactFontFormatData SnapshotPortion(int startLocation, int length) { if (length == 0) { return new CompactFontFormatData(EmptyArray.Instance); } if (startLocation > dataBytes.Count - 1 || startLocation + length > dataBytes.Count) { throw new ArgumentException($"Attempted to create a snapshot of an invalid portion of the data. Length was {dataBytes.Count}, requested start: {startLocation} and requested length: {length}."); } var newData = new byte[length]; var newI = 0; for (var i = startLocation; i < startLocation + length; i++) { newData[newI] = dataBytes[i]; newI++; } return new CompactFontFormatData(newData); } } }