//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