393 lines
20 KiB
C#
393 lines
20 KiB
C#
using System;
|
|
using KKdMainLib.Types;
|
|
using MSIO = System.IO;
|
|
|
|
namespace KKdMainLib.IO
|
|
{
|
|
public unsafe class Stream : IDisposable
|
|
{
|
|
private MSIO.Stream stream;
|
|
private int I, i, i0, TempBitRead, TempBitWrite;
|
|
private ushort ValRead;
|
|
private byte BitRead, BitWrite, ValWrite;
|
|
private byte[] buf;
|
|
private byte[] data;
|
|
|
|
private Main.Format _format = Main.Format.NULL;
|
|
|
|
public Main.Format Format
|
|
{ get => _format;
|
|
set { _format = value;
|
|
IsBE = _format == Main.Format.F2BE;
|
|
IsX = _format == Main.Format.X || _format == Main.Format.XHD; } }
|
|
|
|
public bool IsBE = false;
|
|
public bool IsX = false;
|
|
|
|
public int Offset { get => ( int)LongOffset; set => LongOffset = value; }
|
|
public uint UIntOffset { get => (uint)LongOffset; set => LongOffset = value; }
|
|
public long LongOffset;
|
|
|
|
public int Length { get => ( int)stream.Length - Offset; set => stream.SetLength(value + Offset); }
|
|
public uint UIntLength { get => (uint)stream.Length - UIntOffset; set => stream.SetLength(value + UIntOffset); }
|
|
public long LongLength { get => stream.Length - LongOffset; set => stream.SetLength(value + LongOffset); }
|
|
|
|
public int Position
|
|
{ get => ( int)stream.Position - Offset; set => stream.Position = value + Offset; }
|
|
public uint UIntPosition
|
|
{ get => (uint)stream.Position - UIntOffset; set => stream.Position = value + UIntOffset; }
|
|
public long LongPosition
|
|
{ get => stream.Position - LongOffset; set => stream.Position = value + LongOffset; }
|
|
|
|
public bool CanRead => stream.CanRead;
|
|
public bool CanSeek => stream.CanSeek;
|
|
public bool CanTimeout => stream.CanTimeout;
|
|
public bool CanWrite => stream.CanWrite;
|
|
|
|
public string File = null;
|
|
|
|
public Stream(MSIO.Stream output = null, byte[] Data = null, bool isBE = false)
|
|
{
|
|
if (output == null) output = MSIO.Stream.Null;
|
|
LongOffset = 0;
|
|
BitRead = 8;
|
|
ValRead = ValRead = BitWrite = 0;
|
|
stream = output;
|
|
Format = Main.Format.NULL;
|
|
buf = new byte[128];
|
|
IsBE = isBE;
|
|
data = Data;
|
|
}
|
|
|
|
public void Close() => Dispose();
|
|
|
|
public void Flush() => stream.Flush();
|
|
|
|
public void SetLength(long length = 0) => stream.SetLength(length);
|
|
|
|
public long Seek(long offset, SeekOrigin origin = 0) =>
|
|
stream.Seek(offset, (MSIO.SeekOrigin)(int)origin);
|
|
|
|
public long? Seek(long? offset, SeekOrigin origin)
|
|
{ if (offset == null) return null; return stream.Seek((long)offset, (MSIO.SeekOrigin)(int)origin); }
|
|
|
|
public void Dispose()
|
|
{ CheckWrited(); Dispose(true); }
|
|
|
|
private void Dispose(bool disposing)
|
|
{ if (disposing && stream != MSIO.Stream.Null) stream.Flush(); stream.Dispose(); data = null; }
|
|
|
|
public MSIO.Stream BaseStream
|
|
{ get { stream.Flush(); return stream; } set { stream = value; } }
|
|
|
|
public void Align(long Align)
|
|
{
|
|
long Al = Align - Position % Align;
|
|
if (Position % Align != 0)
|
|
stream.Seek(Position + Al, 0);
|
|
}
|
|
|
|
public void Align(long Align, bool SetLength)
|
|
{
|
|
if (SetLength) stream.SetLength(Position);
|
|
long Al = Align - Position % Align;
|
|
if (Position % Align != 0) stream.Seek(Position + Al, 0);
|
|
if (SetLength) stream.SetLength(Position);
|
|
}
|
|
|
|
public void Align(long Align, bool SetLength0, bool SetLength1)
|
|
{
|
|
if (SetLength0) stream.SetLength(Position);
|
|
long Al = Align - Position % Align;
|
|
if (Position % Align != 0) stream.Seek(Position + Al, 0);
|
|
if (SetLength1) stream.SetLength(Position);
|
|
}
|
|
|
|
public bool ReadBoolean() => stream.ReadByte() == 1;
|
|
public sbyte ReadSByte() => ( sbyte)stream.ReadByte();
|
|
public byte ReadByte() => ( byte)stream.ReadByte();
|
|
public sbyte ReadInt8() => ( sbyte) IntFromArray(1);
|
|
public byte ReadUInt8() => ( byte)UIntFromArray(1);
|
|
public short ReadInt16() => ( short) IntFromArray(2);
|
|
public ushort ReadUInt16() => (ushort)UIntFromArray(2);
|
|
public int ReadInt24() => ( int) IntFromArray(3);
|
|
public int ReadInt32() => ( int) IntFromArray(4);
|
|
public uint ReadUInt32() => ( uint)UIntFromArray(4);
|
|
public long ReadInt64() => IntFromArray(8);
|
|
public ulong ReadUInt64() => UIntFromArray(8);
|
|
public Half ReadHalf() { ushort a = ReadUInt16(); return ( Half ) a; }
|
|
public float ReadSingle() { uint a = ReadUInt32(); return *( float*)&a; }
|
|
public double ReadDouble() { ulong a = ReadUInt64(); return *(double*)&a; }
|
|
|
|
public short ReadInt16Endian() => ( short) IntFromArray(2, IsBE);
|
|
public ushort ReadUInt16Endian() => (ushort)UIntFromArray(2, IsBE);
|
|
public int ReadInt24Endian() => ( int) IntFromArray(3, IsBE);
|
|
public int ReadInt32Endian() => ( int) IntFromArray(4, IsBE);
|
|
public uint ReadUInt32Endian() => ( uint)UIntFromArray(4, IsBE);
|
|
public long ReadInt64Endian() => IntFromArray(8, IsBE);
|
|
public ulong ReadUInt64Endian() => UIntFromArray(8, IsBE);
|
|
public Half ReadHalfEndian() { ushort a = ReadUInt16Endian(); return ( Half ) a; }
|
|
public float ReadSingleEndian() { uint a = ReadUInt32Endian(); return *( float*)&a; }
|
|
public double ReadDoubleEndian() { ulong a = ReadUInt64Endian(); return *(double*)&a; }
|
|
|
|
public short ReadInt16Endian(bool IsBE) => ( short) IntFromArray(2, IsBE);
|
|
public ushort ReadUInt16Endian(bool IsBE) => (ushort)UIntFromArray(2, IsBE);
|
|
public int ReadInt24Endian(bool IsBE) => ( int) IntFromArray(3, IsBE);
|
|
public int ReadInt32Endian(bool IsBE) => ( int) IntFromArray(4, IsBE);
|
|
public uint ReadUInt32Endian(bool IsBE) => ( uint)UIntFromArray(4, IsBE);
|
|
public long ReadInt64Endian(bool IsBE) => IntFromArray(8, IsBE);
|
|
public ulong ReadUInt64Endian(bool IsBE) => UIntFromArray(8, IsBE);
|
|
public Half ReadHalfEndian(bool IsBE)
|
|
{ ushort a = ReadUInt16Endian(IsBE); return ( Half ) a; }
|
|
public float ReadSingleEndian(bool IsBE)
|
|
{ uint a = ReadUInt32Endian(IsBE); return *( float*)&a; }
|
|
public double ReadDoubleEndian(bool IsBE)
|
|
{ ulong a = ReadUInt64Endian(IsBE); return *(double*)&a; }
|
|
|
|
public void Write(byte[] Val) => stream.Write(Val, 0, Val. Length);
|
|
public void Write(byte[] Val, int Length) => stream.Write(Val, 0 , Length);
|
|
public void Write(byte[] Val, int Offset, int Length) => stream.Write(Val, Offset, Length);
|
|
public void Write(char[] val, bool UTF8 = true)
|
|
{ if (UTF8) Write(val.ToUTF8()); else Write(val.ToASCII()); }
|
|
|
|
public void WriteByte(byte val) => stream.WriteByte(val);
|
|
|
|
public void Write( bool val) => stream.WriteByte((byte)(val ? 1 : 0));
|
|
public void Write( sbyte val) => stream.WriteByte((byte) val);
|
|
public void Write( byte val) => stream.WriteByte( val);
|
|
public void Write( short val) => ToArray(2, val);
|
|
public void Write(ushort val) => ToArray(2, val);
|
|
public void Write( int val) => ToArray(4, val);
|
|
public void Write( uint val) => ToArray(4, val);
|
|
public void Write( long val) => ToArray(8, val);
|
|
public void Write( ulong val) => ToArray(8, val);
|
|
public void Write( Half val) => ToArray(2, (ushort) val);
|
|
public void Write( float val) => ToArray(4, *( uint*)&val);
|
|
public void Write(double val) => ToArray(8, *(ulong*)&val);
|
|
|
|
public void Write( sbyte? val) => Write(val.GetValueOrDefault());
|
|
public void Write( byte? val) => Write(val.GetValueOrDefault());
|
|
public void Write( short? val) => Write(val.GetValueOrDefault());
|
|
public void Write(ushort? val) => Write(val.GetValueOrDefault());
|
|
public void Write( int? val) => Write(val.GetValueOrDefault());
|
|
public void Write( uint? val) => Write(val.GetValueOrDefault());
|
|
public void Write( long? val) => Write(val.GetValueOrDefault());
|
|
public void Write( ulong? val) => Write(val.GetValueOrDefault());
|
|
public void Write( float? val) => Write(val.GetValueOrDefault());
|
|
public void Write(double? val) => Write(val.GetValueOrDefault());
|
|
|
|
public void Write( bool* val, int Length)
|
|
{ for (i = 0; i < Length; i++) stream.WriteByte((byte)(val[i] ? 1 : 0)); }
|
|
public void Write( sbyte* val, int Length)
|
|
{ for (i = 0; i < Length; i++) stream.WriteByte((byte) val[i]); }
|
|
public void Write( byte* val, int Length)
|
|
{ for (i = 0; i < Length; i++) stream.WriteByte( val[i]); }
|
|
public void Write( short* val, int Length)
|
|
{ for (i = 0; i < Length; i++) ToArray(2, val[i]); }
|
|
public void Write(ushort* val, int Length)
|
|
{ for (i = 0; i < Length; i++) ToArray(2, val[i]); }
|
|
public void Write( int* val, int Length)
|
|
{ for (i = 0; i < Length; i++) ToArray(4, val[i]); }
|
|
public void Write( uint* val, int Length)
|
|
{ for (i = 0; i < Length; i++) ToArray(4, val[i]); }
|
|
public void Write( long* val, int Length)
|
|
{ for (i = 0; i < Length; i++) ToArray(8, val[i]); }
|
|
public void Write( ulong* val, int Length)
|
|
{ for (i = 0; i < Length; i++) ToArray(8, val[i]); }
|
|
public void Write( float* val, int Length)
|
|
{ for (i = 0; i < Length; i++) ToArray(4, *( uint*)&val[i]); }
|
|
public void Write(double* val, int Length)
|
|
{ for (i = 0; i < Length; i++) ToArray(4, *(ulong*)&val[i]); }
|
|
|
|
public void WriteEndian( short* val, int Length)
|
|
{ for (i = 0; i < Length; i++) ToArray(2, Endian(val[i], 2, IsBE)); }
|
|
public void WriteEndian(ushort* val, int Length)
|
|
{ for (i = 0; i < Length; i++) ToArray(2, Endian(val[i], 2, IsBE)); }
|
|
public void WriteEndian( int* val, int Length)
|
|
{ for (i = 0; i < Length; i++) ToArray(4, Endian(val[i], 4, IsBE)); }
|
|
public void WriteEndian( uint* val, int Length)
|
|
{ for (i = 0; i < Length; i++) ToArray(4, Endian(val[i], 4, IsBE)); }
|
|
public void WriteEndian( long* val, int Length)
|
|
{ for (i = 0; i < Length; i++) ToArray(8, Endian(val[i], 8, IsBE)); }
|
|
public void WriteEndian( ulong* val, int Length)
|
|
{ for (i = 0; i < Length; i++) ToArray(8, Endian(val[i], 8, IsBE)); }
|
|
public void WriteEndian( float* val, int Length)
|
|
{ for (i = 0; i < Length; i++) ToArray(4, Endian(*( uint*)&val[i], 4, IsBE)); }
|
|
public void WriteEndian(double* val, int Length)
|
|
{ for (i = 0; i < Length; i++) ToArray(8, Endian(*(ulong*)&val[i], 8, IsBE)); }
|
|
|
|
public void WriteEndian( short* val, int Length, bool IsBE)
|
|
{ for (i = 0; i < Length; i++) ToArray(2, Endian(val[i], 2, IsBE)); }
|
|
public void WriteEndian(ushort* val, int Length, bool IsBE)
|
|
{ for (i = 0; i < Length; i++) ToArray(2, Endian(val[i], 2, IsBE)); }
|
|
public void WriteEndian( int* val, int Length, bool IsBE)
|
|
{ for (i = 0; i < Length; i++) ToArray(4, Endian(val[i], 4, IsBE)); }
|
|
public void WriteEndian( uint* val, int Length, bool IsBE)
|
|
{ for (i = 0; i < Length; i++) ToArray(4, Endian(val[i], 4, IsBE)); }
|
|
public void WriteEndian( long* val, int Length, bool IsBE)
|
|
{ for (i = 0; i < Length; i++) ToArray(8, Endian(val[i], 8, IsBE)); }
|
|
public void WriteEndian( ulong* val, int Length, bool IsBE)
|
|
{ for (i = 0; i < Length; i++) ToArray(8, Endian(val[i], 8, IsBE)); }
|
|
public void WriteEndian( float* val, int Length, bool IsBE)
|
|
{ for (i = 0; i < Length; i++) ToArray(4, Endian(*( uint*)&val[i], 4, IsBE)); }
|
|
public void WriteEndian(double* val, int Length, bool IsBE)
|
|
{ for (i = 0; i < Length; i++) ToArray(8, Endian(*(ulong*)&val[i], 8, IsBE)); }
|
|
|
|
public void Write( char val, bool UTF8 = true)
|
|
{ if (UTF8) Write(val.ToString().ToUTF8()); else Write(val.ToString().ToASCII()); }
|
|
public void Write(string val, bool UTF8 = true)
|
|
{ if (UTF8) Write(val .ToUTF8()); else Write(val .ToASCII()); }
|
|
|
|
public void WriteEndian( short val) => ToArray(2, Endian(val, 2, IsBE));
|
|
public void WriteEndian(ushort val) => ToArray(2, Endian(val, 2, IsBE));
|
|
public void WriteEndian( int val) => ToArray(4, Endian(val, 4, IsBE));
|
|
public void WriteEndian( uint val) => ToArray(4, Endian(val, 4, IsBE));
|
|
public void WriteEndian( long val) => ToArray(8, Endian(val, 8, IsBE));
|
|
public void WriteEndian( ulong val) => ToArray(8, Endian(val, 8, IsBE));
|
|
public void WriteEndian( float val) => ToArray(4, Endian(*( uint*)&val, 4, IsBE));
|
|
public void WriteEndian(double val) => ToArray(8, Endian(*(ulong*)&val, 8, IsBE));
|
|
|
|
public void WriteEndian( short val, bool IsBE) => ToArray(2, Endian(val, 2, IsBE));
|
|
public void WriteEndian(ushort val, bool IsBE) => ToArray(2, Endian(val, 2, IsBE));
|
|
public void WriteEndian( int val, bool IsBE) => ToArray(4, Endian(val, 4, IsBE));
|
|
public void WriteEndian( uint val, bool IsBE) => ToArray(4, Endian(val, 4, IsBE));
|
|
public void WriteEndian( long val, bool IsBE) => ToArray(8, Endian(val, 8, IsBE));
|
|
public void WriteEndian( ulong val, bool IsBE) => ToArray(8, Endian(val, 8, IsBE));
|
|
public void WriteEndian( float val, bool IsBE) => ToArray(4, Endian(*( uint*)&val, 4, IsBE));
|
|
public void WriteEndian(double val, bool IsBE) => ToArray(8, Endian(*(ulong*)&val, 8, IsBE));
|
|
|
|
public long Endian( long BE, byte Length, bool IsBE)
|
|
{ if (IsBE) { for (I = 0; I < Length; I++) { buf[I] = (byte)BE; BE >>= 8; } BE = 0;
|
|
for (I = 0; I < Length; I++) { BE |= buf[I]; if (I < Length - 1) BE <<= 8; } } return BE; }
|
|
|
|
public ulong Endian( ulong BE, byte Length, bool IsBE)
|
|
{ if (IsBE) { for (I = 0; I < Length; I++) { buf[I] = (byte)BE; BE >>= 8; } BE = 0;
|
|
for (I = 0; I < Length; I++) { BE |= buf[I]; if (I < Length - 1) BE <<= 8; } } return BE; }
|
|
|
|
private void ToArray(byte L, long val)
|
|
{ CheckWrited(); for (I = 0; I < L; I++) { buf[I] = (byte)val; val >>= 8; } stream.Write(buf, 0, L); }
|
|
|
|
private void ToArray(byte L, ulong val)
|
|
{ CheckWrited(); for (I = 0; I < L; I++) { buf[I] = (byte)val; val >>= 8; } stream.Write(buf, 0, L); }
|
|
|
|
private long IntFromArray(byte L) { stream.Read(buf, 0, L); long val = 0;
|
|
for (I = L; I > 0; I--) { val <<= 8; val |= buf[I - 1]; } return val; }
|
|
|
|
private ulong UIntFromArray(byte L) { stream.Read(buf, 0, L); ulong val = 0;
|
|
for (I = L; I > 0; I--) { val <<= 8; val |= buf[I - 1]; } return val; }
|
|
|
|
private long IntFromArray(byte L, bool IsBE) { stream.Read(buf, 0, L); long val = 0; if (IsBE)
|
|
for (I = 0; I < L; I++) { val <<= 8; val |= buf[I ]; } else
|
|
for (I = L; I > 0; I--) { val <<= 8; val |= buf[I - 1]; } return val; }
|
|
|
|
private ulong UIntFromArray(byte L, bool IsBE) { stream.Read(buf, 0, L); ulong val = 0; if (IsBE)
|
|
for (I = 0; I < L; I++) { val <<= 8; val |= buf[I ]; } else
|
|
for (I = L; I > 0; I--) { val <<= 8; val |= buf[I - 1]; } return val; }
|
|
|
|
public char ReadChar(bool UTF8 = true)
|
|
{ if (UTF8) return ReadCharUTF8();
|
|
else return (char)stream.ReadByte(); }
|
|
|
|
public char ReadCharUTF8()
|
|
{
|
|
byte t;
|
|
int T;
|
|
int val = 0;
|
|
for (I = 0, i0 = 4; I < i0; I++)
|
|
{
|
|
T = stream.ReadByte();
|
|
if (T == -1) return '\uFFFF';
|
|
t = (byte)T;
|
|
|
|
if ((t & 0xC0) == 0x80 && I > 0) val = (val << 6) | (t & 0x3F);
|
|
else if ((t & 0x80) == 0x00 && I == 0) return (char)t;
|
|
else if ((t & 0xE0) == 0xC0 && I == 0) { val = t & 0x1F; i0 = 2; }
|
|
else if ((t & 0xF0) == 0xE0 && I == 0) { val = t & 0x0F; i0 = 3; }
|
|
else if ((t & 0xF8) == 0xF0 && I == 0) { val = t & 0x07; i0 = 4; }
|
|
else return '\uFFFF';
|
|
}
|
|
return (char)val;
|
|
}
|
|
|
|
public string ReadString(long Length, bool UTF8 = true)
|
|
{ if (UTF8) return ReadStringUTF8 (Length);
|
|
else return ReadStringASCII(Length); }
|
|
|
|
public string ReadStringUTF8 (long Length) => ReadBytes(Length).ToUTF8 ();
|
|
public string ReadStringASCII(long Length) => ReadBytes(Length).ToASCII();
|
|
|
|
|
|
public string ReadString(long? Length, bool UTF8 = true)
|
|
{ if (UTF8) return ReadStringUTF8 (Length);
|
|
else return ReadStringASCII(Length); }
|
|
|
|
public string ReadStringUTF8 (long? Length) => ReadBytes(Length).ToUTF8 ();
|
|
public string ReadStringASCII(long? Length) => ReadBytes(Length).ToASCII();
|
|
|
|
public byte[] ReadBytes(long Length, int Offset = 0)
|
|
{ byte[] Buf = new byte[Length]; if (Offset > 0) stream.Position = Offset;
|
|
stream.Read(Buf, 0, (int)Length); return Buf; }
|
|
|
|
public void ReadBytes(long Length, byte[] Buf, long Offset = 0)
|
|
{ if (Offset > 0) stream.Position = Offset; stream.Read(Buf, 0, (int)Length); }
|
|
|
|
public byte[] ReadBytes(long? Length, int Offset = 0)
|
|
{ if (Length == null) return new byte[0]; else return ReadBytes((long)Length, Offset); }
|
|
|
|
public void ReadBytes(long Length, byte Bits, byte[] Buf, long Offset = 0)
|
|
{ if (Offset > 0) stream.Seek(Offset, 0);
|
|
if (Bits > 0 && Bits < 8) for (i0 = 0; i0 < Length; i0++) Buf[i0] = ReadBits(Bits); }
|
|
|
|
public byte ReadBits(byte Bits)
|
|
{
|
|
BitRead += Bits;
|
|
TempBitRead = 8 - BitRead;
|
|
if (TempBitRead < 0)
|
|
{
|
|
BitRead = (byte)-TempBitRead;
|
|
TempBitRead = 8 + TempBitRead;
|
|
ValRead = (ushort)((ValRead << 8) | (byte)stream.ReadByte());
|
|
}
|
|
return (byte)((ValRead >> TempBitRead) & ((1 << Bits) - 1));
|
|
}
|
|
|
|
public byte ReadHalfByte() => ReadBits(4);
|
|
|
|
public void Write(byte val, byte Bits)
|
|
{
|
|
BitWrite += Bits;
|
|
TempBitWrite = 8 - BitWrite;
|
|
if (TempBitWrite < 0)
|
|
{
|
|
BitWrite = (byte)-TempBitWrite;
|
|
TempBitWrite = 8 + TempBitWrite;
|
|
stream.WriteByte((byte)(ValWrite | (val >> BitWrite)));
|
|
ValWrite = 0;
|
|
}
|
|
ValWrite |= (byte)(val << TempBitWrite);
|
|
}
|
|
|
|
public void CheckRead () { if (BitRead > 0) ValRead = 0; BitRead = 8; }
|
|
public void CheckWrited() { if (BitWrite > 0) { Write(ValWrite); ValWrite = BitWrite = 0; } }
|
|
|
|
public byte[] ToArray(bool Close)
|
|
{ byte[] Data = ToArray(); if (Close) this.Close(); return Data; }
|
|
|
|
public byte[] ToArray()
|
|
{
|
|
long Offset = stream.Position;
|
|
LongPosition = 0;
|
|
byte[] Data = ReadBytes(stream.Length);
|
|
LongPosition = Offset;
|
|
return Data;
|
|
}
|
|
}
|
|
|
|
public enum SeekOrigin
|
|
{
|
|
Begin = 0,
|
|
Current = 1,
|
|
End = 2,
|
|
}
|
|
}
|