// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System; namespace SixLabors.Fonts.Tables.Cff { /// /// A lightweight big-endian binary reader over a buffer, /// used for reading Type 2 charstring data without allocations. /// internal ref struct SimpleBinaryReader { private readonly ReadOnlySpan buffer; /// /// Initializes a new instance of the struct. /// /// The byte buffer to read from. public SimpleBinaryReader(ReadOnlySpan buffer) { this.buffer = buffer; this.Position = 0; } /// /// Gets the total length of the underlying buffer. /// public readonly int Length => this.buffer.Length; /// /// Gets or sets the current read position within the buffer. /// // TODO: Bounds checks. public int Position { get; set; } /// /// Gets a value indicating whether there are remaining bytes to read. /// /// if the position is within the buffer; otherwise, . public readonly bool CanRead() => (uint)this.Position < this.buffer.Length; /// /// Reads a single byte and advances the position. /// /// The byte value. public byte ReadByte() => this.buffer[this.Position++]; /// /// Reads a big-endian 16-bit signed integer and advances the position by 2 bytes. /// /// The 16-bit signed integer value. public int ReadInt16BE() { byte b1 = this.buffer[this.Position + 1]; byte b0 = this.buffer[this.Position]; this.Position += 2; return (short)((b0 << 8) | b1); } /// /// Reads a big-endian 16.16 fixed-point number and advances the position by 4 bytes. /// /// The floating-point value. public float ReadFloatFixed1616() { // Read a BE int, we parse it later. byte b3 = this.buffer[this.Position + 3]; byte b2 = this.buffer[this.Position + 2]; byte b1 = this.buffer[this.Position + 1]; byte b0 = this.buffer[this.Position]; this.Position += 4; // This number is interpreted as a Fixed; that is, a signed number with 16 bits of fraction float number = (short)((b0 << 8) | b1); float fraction = (short)((b2 << 8) | b3) / 65536F; return number + fraction; } } }