Files
PdfPig/src/UglyToad.PdfPig.Fonts/CompactFontFormat/CompactFontFormatData.cs

190 lines
5.1 KiB
C#
Raw Normal View History

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