2020-01-05 12:08:01 +00:00
namespace UglyToad.PdfPig.Fonts.CompactFontFormat
2018-11-16 21:30:59 +00:00
{
using System ;
2018-11-24 19:02:06 +00:00
using System.Collections.Generic ;
2018-11-18 13:53:43 +00:00
using System.Diagnostics ;
2018-11-16 21:30:59 +00:00
using System.Text ;
2020-01-04 16:38:18 +00:00
using Core ;
2018-11-16 21:30:59 +00:00
/// <summary>
/// Provides access to the raw bytes of this Compact Font Format file with utility methods for reading data types from it.
/// </summary>
2020-01-05 12:08:01 +00:00
public class CompactFontFormatData
2018-11-16 21:30:59 +00:00
{
2018-11-24 19:02:06 +00:00
private readonly IReadOnlyList < byte > dataBytes ;
2018-11-16 21:30:59 +00:00
2020-01-05 12:08:01 +00:00
/// <summary>
/// The current position in the data.
/// </summary>
2018-11-16 21:30:59 +00:00
public int Position { get ; private set ; } = - 1 ;
2020-01-05 12:08:01 +00:00
/// <summary>
/// The length of the data.
/// </summary>
2018-11-24 19:02:06 +00:00
public int Length = > dataBytes . Count ;
2018-11-18 13:53:43 +00:00
2020-01-05 12:08:01 +00:00
/// <summary>
/// Create a new <see cref="CompactFontFormatData"/>.
/// </summary>
2018-11-18 13:53:43 +00:00
[DebuggerStepThrough]
2018-11-24 19:02:06 +00:00
public CompactFontFormatData ( IReadOnlyList < byte > dataBytes )
2018-11-16 21:30:59 +00:00
{
this . dataBytes = dataBytes ;
}
2020-01-05 12:08:01 +00:00
/// <summary>
/// Read a string of the specified length.
/// </summary>
2018-11-16 21:30:59 +00:00
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 ) ;
}
2020-01-05 12:08:01 +00:00
/// <summary>
/// Read Card8 format.
/// </summary>
2018-11-16 21:30:59 +00:00
public byte ReadCard8 ( )
{
return ReadByte ( ) ;
}
2020-01-05 12:08:01 +00:00
/// <summary>
/// Read Card16 format.
/// </summary>
2018-11-16 21:30:59 +00:00
public ushort ReadCard16 ( )
{
return ( ushort ) ( ReadByte ( ) < < 8 | ReadByte ( ) ) ;
}
2020-01-05 12:08:01 +00:00
/// <summary>
/// Read Offsize.
/// </summary>
2018-11-16 21:30:59 +00:00
public byte ReadOffsize ( )
{
return ReadByte ( ) ;
}
2020-01-05 12:08:01 +00:00
/// <summary>
/// Read Offset.
/// </summary>
2018-11-16 21:30:59 +00:00
public int ReadOffset ( int offsetSize )
{
var value = 0 ;
for ( var i = 0 ; i < offsetSize ; i + + )
{
value = value < < 8 | ReadByte ( ) ;
}
return value ;
}
2020-01-05 12:08:01 +00:00
/// <summary>
/// Read byte.
/// </summary>
2018-11-16 21:30:59 +00:00
public byte ReadByte ( )
{
Position + + ;
2018-11-24 19:02:06 +00:00
if ( Position > = dataBytes . Count )
2018-11-16 21:30:59 +00:00
{
2018-11-24 19:02:06 +00:00
throw new IndexOutOfRangeException ( $"Cannot read byte at position {Position} of an array which is {dataBytes.Count} bytes long." ) ;
2018-11-16 21:30:59 +00:00
}
return dataBytes [ Position ] ;
}
2020-01-05 12:08:01 +00:00
/// <summary>
/// Peek the next byte without advancing the data.
/// </summary>
2018-11-16 21:30:59 +00:00
public byte Peek ( )
{
return dataBytes [ Position + 1 ] ;
}
2020-01-05 12:08:01 +00:00
/// <summary>
/// Whether there's more data to read in the input.
/// </summary>
2018-11-16 21:30:59 +00:00
public bool CanRead ( )
{
2018-11-24 19:02:06 +00:00
return Position < dataBytes . Count - 1 ;
2018-11-16 21:30:59 +00:00
}
2020-01-05 12:08:01 +00:00
/// <summary>
/// Move to the given offset from the beginning.
/// </summary>
2018-11-16 21:30:59 +00:00
public void Seek ( int offset )
{
Position = offset - 1 ;
}
2020-01-05 12:08:01 +00:00
/// <summary>
/// Read long.
/// </summary>
2018-11-16 21:30:59 +00:00
public long ReadLong ( )
{
return ( ReadCard16 ( ) < < 16 ) | ReadCard16 ( ) ;
}
2020-01-05 12:08:01 +00:00
/// <summary>
/// Read sid.
/// </summary>
2018-11-16 23:32:18 +00:00
public int ReadSid ( )
{
return ReadByte ( ) < < 8 | ReadByte ( ) ;
}
2020-01-05 12:08:01 +00:00
/// <summary>
/// Read byte array of given length.
/// </summary>
2018-11-16 21:30:59 +00:00
public byte [ ] ReadBytes ( int length )
{
var result = new byte [ length ] ;
for ( int i = 0 ; i < length ; i + + )
{
result [ i ] = ReadByte ( ) ;
}
return result ;
}
2018-11-18 13:53:43 +00:00
2020-01-05 12:08:01 +00:00
/// <summary>
/// Create a new <see cref="CompactFontFormatData"/> from this data with a snapshot at the position and length.
/// </summary>
2018-11-18 13:53:43 +00:00
public CompactFontFormatData SnapshotPortion ( int startLocation , int length )
{
2019-05-11 10:00:04 +01:00
if ( length = = 0 )
{
2024-03-13 18:59:05 -07:00
return new CompactFontFormatData ( Array . Empty < byte > ( ) ) ;
2019-05-11 10:00:04 +01:00
}
2018-11-24 19:02:06 +00:00
if ( startLocation > dataBytes . Count - 1 | | startLocation + length > dataBytes . Count )
2018-11-18 13:53:43 +00:00
{
2018-11-24 19:02:06 +00:00
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}." ) ;
2018-11-18 13:53:43 +00:00
}
var newData = new byte [ length ] ;
2018-11-24 19:02:06 +00:00
var newI = 0 ;
for ( var i = startLocation ; i < startLocation + length ; i + + )
{
newData [ newI ] = dataBytes [ i ] ;
newI + + ;
}
2018-11-18 13:53:43 +00:00
return new CompactFontFormatData ( newData ) ;
}
2018-11-16 21:30:59 +00:00
}
}