//using System.Runtime.InteropServices;
using System.IO;
using System;
#pragma warning disable CS3001, CS3002, CS3003, CS1591
namespace FastReport.Fonts
{
public class FontStream : IDisposable
{
private readonly byte[] _buffer;
private bool _leaveOpen;
private bool _disposedValue;
private readonly Stream _stream;
private string _fast_name;
///
/// Creates a new instance of the class.
///
/// TrueType raw data stream
/// Keep open raw data stream after disposing FontStream
public FontStream(Stream stream, bool leaveOpen = false)
{
this._stream = stream;
this._buffer = new byte[16];
this._leaveOpen = leaveOpen;
// Trace.WriteLine.WriteLine("FontStream constructor");
}
public bool CanRead => _stream.CanRead;
public bool CanSeek => _stream.CanSeek;
public long Length => _stream.Length;
public long Position
{
get => _stream.Position;
set => _stream.Position = value;
}
///
/// FastName of font stream
///
internal string StreamFontFastName
{
get => _fast_name;
set => _fast_name = value;
}
internal bool LeaveOpen
{
set => _leaveOpen = value;
}
public long Seek(long offset, SeekOrigin origin)
{
return _stream.Seek(offset, origin);
}
internal void Read(byte[] data, int length)
{
_stream.Read(data, 0, length);
}
internal void Write(byte[] data, int length)
{
_stream.Write(data, 0, length);
}
protected virtual void Dispose(bool disposing)
{
#if SAVE_COPY_OF_SUBSETTET_FONT_TO_FILE
if (_stream.CanWrite)
{
_stream.Position = 0;
FileStream debug = File.OpenWrite("FONT-" + DateTime.Now.Ticks + ".ttf");
if (debug != null && debug.CanWrite)
{
_stream.CopyTo(debug);
debug.Close();
}
}
#endif
if (!_disposedValue)
{
if (!_leaveOpen)
_stream.Dispose();
_disposedValue = true;
}
}
public void Dispose()
{
// DO NOT CHANGE THIS CODE! If you need clenup code - put it into "Dispose(bool disposing)" method.
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
private void ReadInternal(int size)
{
int n;
if (size == 1)
{
n = _stream.ReadByte();
if (n == -1)
throw new EndOfStreamException();
_buffer[0] = (byte)n;
return;
}
int bytesRead = 0;
do
{
n = _stream.Read(_buffer, bytesRead, size - bytesRead);
if (n == 0)
{
throw new EndOfStreamException();
}
bytesRead += n;
} while (bytesRead < size);
}
public uint ReadUInt32()
{
ReadInternal(4);
if (BitConverter.IsLittleEndian)
return (uint)(_buffer[3] | _buffer[2] << 8 | _buffer[1] << 16 | _buffer[0] << 24);
else
return (uint)(_buffer[0] | _buffer[1] << 8 | _buffer[2] << 16 | _buffer[3] << 24);
}
internal void WriteUInt32(uint word)
{
byte[] holder = new byte[4];
if (BitConverter.IsLittleEndian)
{
holder[3] = (byte)(word);
holder[2] = (byte)(word >> 8);
holder[1] = (byte)(word >> 16);
holder[0] = (byte)(word >> 24);
}
else
{
holder[0] = (byte)(word);
holder[1] = (byte)(word >> 8);
holder[2] = (byte)(word >> 16);
holder[3] = (byte)(word >> 24);
}
_stream.Write(holder, 0, 4);
}
public int ReadInt32()
{
ReadInternal(4);
if (BitConverter.IsLittleEndian)
return (int)(_buffer[3] | _buffer[2] << 8 | _buffer[1] << 16 | _buffer[0] << 24);
else
return (int)(_buffer[0] | _buffer[1] << 8 | _buffer[2] << 16 | _buffer[3] << 24);
}
public byte ReadByte()
{
int b = _stream.ReadByte();
if (b == -1)
throw new EndOfStreamException();
return (byte)b;
}
public virtual sbyte ReadSByte()
{
ReadInternal(1);
return (sbyte)(_buffer[0]);
}
public ushort ReadUInt16()
{
ReadInternal(2);
if (BitConverter.IsLittleEndian)
return (ushort)(_buffer[1] | _buffer[0] << 8);
else
return (ushort)(_buffer[0] | _buffer[1] << 8);
}
public short ReadInt16()
{
ReadInternal(2);
if (BitConverter.IsLittleEndian)
return (short)(_buffer[1] | _buffer[0] << 8);
else
return (short)(_buffer[0] | _buffer[1] << 8);
}
public ulong ReadUInt64()
{
uint hi, lo;
ReadInternal(8);
if (BitConverter.IsLittleEndian)
{
lo = (uint)(_buffer[7] | _buffer[6] << 8 | _buffer[5] << 16 | _buffer[4] << 24);
hi = (uint)(_buffer[3] | _buffer[2] << 8 | _buffer[1] << 16 | _buffer[0] << 24);
}
else
{
lo = (uint)(_buffer[0] | _buffer[1] << 8 | _buffer[2] << 16 | _buffer[3] << 24);
hi = (uint)(_buffer[4] | _buffer[5] << 8 | _buffer[6] << 16 | _buffer[7] << 24);
}
return ((ulong)hi) << 32 | lo;
}
public virtual long ReadInt64()
{
uint hi, lo;
ReadInternal(8);
if (BitConverter.IsLittleEndian)
{
lo = (uint)(_buffer[7] | _buffer[6] << 8 | _buffer[5] << 16 | _buffer[4] << 24);
hi = (uint)(_buffer[3] | _buffer[2] << 8 | _buffer[1] << 16 | _buffer[0] << 24);
}
else
{
lo = (uint)(_buffer[0] | _buffer[1] << 8 | _buffer[2] << 16 | _buffer[3] << 24);
hi = (uint)(_buffer[4] | _buffer[5] << 8 | _buffer[6] << 16 | _buffer[7] << 24);
}
return (long)((ulong)hi) << 32 | lo;
}
internal void WriteUInt16(ushort data16)
{
byte[] data8 = new byte[2];
if (BitConverter.IsLittleEndian)
{
data8[1] = (byte)(data16);
data8[0] = (byte)(data16 >> 8);
}
else
{
data8[0] = (byte)(data16);
data8[1] = (byte)(data16 >> 8);
}
_stream.Write(data8, 0, 2);
}
internal void WriteInt16(short ascender)
{
WriteUInt16((ushort)ascender);
}
internal void WriteByte(byte data8)
{
_stream.WriteByte(data8);
}
internal void WriteUInt64(ulong data64)
{
Byte[] bytes = BitConverter.GetBytes(data64);
if (BitConverter.IsLittleEndian)
Array.Reverse(bytes);
_stream.Write(bytes, 0, 8);
}
internal void WriteInt32(uint data4)
{
WriteUInt32((uint)data4);
}
}
}
#pragma warning restore