using System; using System.Buffers.Binary; using System.Collections.Generic; using System.IO; using System.Text; namespace AssetStudio { public class EndianBinaryReader : BinaryReader { private readonly byte[] buffer; public EndianType Endian; public EndianBinaryReader(Stream stream, EndianType endian = EndianType.BigEndian, bool leaveOpen = false) : base(stream, Encoding.UTF8, leaveOpen) { Endian = endian; buffer = new byte[8]; } public long Position { get => BaseStream.Position; set => BaseStream.Position = value; } public long Length => BaseStream.Length; public long Remaining => Length - Position; public override short ReadInt16() { if (Endian == EndianType.BigEndian) { Read(buffer, 0, 2); return BinaryPrimitives.ReadInt16BigEndian(buffer); } return base.ReadInt16(); } public override int ReadInt32() { if (Endian == EndianType.BigEndian) { Read(buffer, 0, 4); return BinaryPrimitives.ReadInt32BigEndian(buffer); } return base.ReadInt32(); } public override long ReadInt64() { if (Endian == EndianType.BigEndian) { Read(buffer, 0, 8); return BinaryPrimitives.ReadInt64BigEndian(buffer); } return base.ReadInt64(); } public override ushort ReadUInt16() { if (Endian == EndianType.BigEndian) { Read(buffer, 0, 2); return BinaryPrimitives.ReadUInt16BigEndian(buffer); } return base.ReadUInt16(); } public override uint ReadUInt32() { if (Endian == EndianType.BigEndian) { Read(buffer, 0, 4); return BinaryPrimitives.ReadUInt32BigEndian(buffer); } return base.ReadUInt32(); } public override ulong ReadUInt64() { if (Endian == EndianType.BigEndian) { Read(buffer, 0, 8); return BinaryPrimitives.ReadUInt64BigEndian(buffer); } return base.ReadUInt64(); } public override float ReadSingle() { if (Endian == EndianType.BigEndian) { Read(buffer, 0, 4); Array.Reverse(buffer, 0, 4); return BitConverter.ToSingle(buffer, 0); } return base.ReadSingle(); } public override double ReadDouble() { if (Endian == EndianType.BigEndian) { Read(buffer, 0, 8); Array.Reverse(buffer); return BitConverter.ToDouble(buffer, 0); } return base.ReadDouble(); } public void AlignStream() { AlignStream(4); } public void AlignStream(int alignment) { var pos = Position; var mod = pos % alignment; if (mod != 0) { Position += alignment - mod; } } public string ReadAlignedString() { var length = ReadInt32(); if (length > 0 && length <= Remaining) { var stringData = ReadBytes(length); var result = Encoding.UTF8.GetString(stringData); AlignStream(4); return result; } return ""; } public string ReadStringToNull(int maxLength = 32767) { var bytes = new List(); int count = 0; while (Remaining > 0 && count < maxLength) { var b = ReadByte(); if (b == 0) { break; } bytes.Add(b); count++; } return Encoding.UTF8.GetString(bytes.ToArray()); } public Quaternion ReadQuaternion() { return new Quaternion(ReadSingle(), ReadSingle(), ReadSingle(), ReadSingle()); } public Vector2 ReadVector2() { return new Vector2(ReadSingle(), ReadSingle()); } public Vector3 ReadVector3() { return new Vector3(ReadSingle(), ReadSingle(), ReadSingle()); } public Vector4 ReadVector4() { return new Vector4(ReadSingle(), ReadSingle(), ReadSingle(), ReadSingle()); } public Color ReadColor4() { return new Color(ReadSingle(), ReadSingle(), ReadSingle(), ReadSingle()); } public Matrix4x4 ReadMatrix() { return new Matrix4x4(ReadSingleArray(16)); } public XForm ReadXForm(int[] version, bool isVector4 = false) { var t = (version[0] > 5 || (version[0] == 5 && version[1] >= 4)) && !isVector4 ? ReadVector3() : (Vector3)ReadVector4();//5.4 and up var q = ReadQuaternion(); var s = (version[0] > 5 || (version[0] == 5 && version[1] >= 4)) && !isVector4 ? ReadVector3() : (Vector3)ReadVector4();//5.4 and up return new XForm(t, q, s); } public Float ReadFloat() { return new Float(ReadSingle()); } public int ReadMhy0Int() { var buffer = ReadBytes(6); return buffer[2] | (buffer[4] << 8) | (buffer[0] << 0x10) | (buffer[5] << 0x18); } public uint ReadMhy0UInt() { var buffer = ReadBytes(7); return (uint)(buffer[1] | (buffer[6] << 8) | (buffer[3] << 0x10) | (buffer[2] << 0x18)); } public string ReadMhy0String() { var pos = BaseStream.Position; var str = ReadStringToNull(); BaseStream.Position += 0x105 - (BaseStream.Position - pos); return str; } private T[] ReadArray(Func del, int length) { var array = new T[length]; for (int i = 0; i < length; i++) { array[i] = del(); } return array; } public bool[] ReadBooleanArray() { return ReadArray(ReadBoolean, ReadInt32()); } public byte[] ReadUInt8Array() { return ReadBytes(ReadInt32()); } public short[] ReadInt16Array() { return ReadArray(ReadInt16, ReadInt32()); } public short[] ReadInt16Array(int length) { return ReadArray(ReadInt16, length); } public ushort[] ReadUInt16Array() { return ReadArray(ReadUInt16, ReadInt32()); } public int[] ReadInt32Array() { return ReadArray(ReadInt32, ReadInt32()); } public int[] ReadInt32Array(int length) { return ReadArray(ReadInt32, length); } public uint[] ReadUInt32Array() { return ReadArray(ReadUInt32, ReadInt32()); } public uint[][] ReadUInt32ArrayArray() { return ReadArray(ReadUInt32Array, ReadInt32()); } public uint[] ReadUInt32Array(int length) { return ReadArray(ReadUInt32, length); } public float[] ReadSingleArray() { return ReadArray(ReadSingle, ReadInt32()); } public float[] ReadSingleArray(int length) { return ReadArray(ReadSingle, length); } public string[] ReadStringArray() { return ReadArray(ReadAlignedString, ReadInt32()); } public Vector2[] ReadVector2Array() { return ReadArray(ReadVector2, ReadInt32()); } public Vector4[] ReadVector4Array() { return ReadArray(ReadVector4, ReadInt32()); } public Matrix4x4[] ReadMatrixArray() { return ReadArray(ReadMatrix, ReadInt32()); } } }