mirror of
https://github.com/KillzXGaming/Switch-Toolbox
synced 2024-11-26 14:30:26 +00:00
1429a00178
Archives now use a link list for archive infos and treenodes. Handling replaced treenodes is easier and fixes renaming issues if a file was opened and renamed. More LM2 archive improvements, with more chunk loading.
314 lines
10 KiB
C#
314 lines
10 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using Syroot.BinaryData;
|
|
using System.IO;
|
|
using System.IO.Compression;
|
|
using OpenTK;
|
|
|
|
namespace Toolbox.Library.IO
|
|
{
|
|
public class FileReader : BinaryDataReader
|
|
{
|
|
public FileReader(Stream stream, bool leaveOpen = false)
|
|
: base(stream, Encoding.ASCII, leaveOpen)
|
|
{
|
|
this.Position = 0;
|
|
}
|
|
|
|
public FileReader(string fileName)
|
|
: this(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
|
|
{
|
|
this.Position = 0;
|
|
}
|
|
public FileReader(byte[] data)
|
|
: this(new MemoryStream(data))
|
|
{
|
|
this.Position = 0;
|
|
}
|
|
|
|
//Checks signature (no stream advancement)
|
|
public bool CheckSignature(int length, string Identifier, long position = 0)
|
|
{
|
|
if (Position + length >= BaseStream.Length || position < 0)
|
|
return false;
|
|
|
|
Position = position;
|
|
string signature = ReadString(length, Encoding.ASCII);
|
|
|
|
//Reset position
|
|
Position = 0;
|
|
|
|
return signature == Identifier;
|
|
}
|
|
|
|
public bool CheckSignature(uint Identifier, long position = 0)
|
|
{
|
|
if (Position + 4 >= BaseStream.Length || position < 0 || position + 4 >= BaseStream.Length)
|
|
return false;
|
|
|
|
Position = position;
|
|
uint signature = ReadUInt32();
|
|
|
|
//Reset position
|
|
Position = 0;
|
|
|
|
return signature == Identifier;
|
|
}
|
|
|
|
public string ReadNameOffset(bool IsRelative, Type OffsetType, bool ReadNameLength = false, bool IsNameLengthShort = false)
|
|
{
|
|
long pos = Position;
|
|
long offset = 0;
|
|
|
|
if (OffsetType == typeof(long))
|
|
offset = ReadInt64();
|
|
if (OffsetType == typeof(ulong))
|
|
offset = (long)ReadUInt64();
|
|
if (OffsetType == typeof(uint))
|
|
offset = ReadUInt32();
|
|
if (OffsetType == typeof(int))
|
|
offset = ReadInt32();
|
|
|
|
if (IsRelative && offset != 0)
|
|
offset += pos;
|
|
|
|
if (offset != 0)
|
|
{
|
|
using (TemporarySeek(offset, SeekOrigin.Begin))
|
|
{
|
|
uint NameLength = 0;
|
|
if (ReadNameLength)
|
|
{
|
|
if (IsNameLengthShort)
|
|
NameLength = ReadUInt16();
|
|
else
|
|
NameLength = ReadUInt32();
|
|
}
|
|
|
|
return ReadString(BinaryStringFormat.ZeroTerminated);
|
|
}
|
|
}
|
|
else
|
|
return "";
|
|
}
|
|
|
|
public List<string> ReadNameOffsets(uint Count, bool IsRelative, Type OffsetType, bool ReadNameLength = false)
|
|
{
|
|
List<string> Names = new List<string>();
|
|
for (int i = 0; i < Count; i++)
|
|
Names.Add(ReadNameOffset(IsRelative, OffsetType, ReadNameLength));
|
|
|
|
return Names;
|
|
}
|
|
|
|
public string ReadZeroTerminatedString()
|
|
{
|
|
return ReadString(BinaryStringFormat.ZeroTerminated);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks the byte order mark to determine the endianness of the reader.
|
|
/// </summary>
|
|
/// <param name="ByteOrderMark">The byte order value being read. 0xFFFE = Little, 0xFEFF = Big. </param>
|
|
/// <returns></returns>
|
|
public void CheckByteOrderMark(uint ByteOrderMark)
|
|
{
|
|
SetByteOrder(ByteOrderMark == 0xFEFF);
|
|
}
|
|
|
|
public void SetByteOrder(bool IsBigEndian)
|
|
{
|
|
if (IsBigEndian)
|
|
ByteOrder = ByteOrder.BigEndian;
|
|
else
|
|
ByteOrder = ByteOrder.LittleEndian;
|
|
}
|
|
|
|
public string ReadSignature(int length, string ExpectedSignature)
|
|
{
|
|
string RealSignature = ReadString(length, Encoding.ASCII);
|
|
|
|
if (RealSignature != ExpectedSignature)
|
|
throw new Exception($"Invalid signature {RealSignature}! Expected {ExpectedSignature}.");
|
|
|
|
return RealSignature;
|
|
}
|
|
|
|
public float ReadByteAsFloat()
|
|
{
|
|
return ReadByte() / 255.0f;
|
|
}
|
|
|
|
public float ReadHalfSingle()
|
|
{
|
|
return new Syroot.IOExtension.Half(ReadUInt16());
|
|
}
|
|
|
|
public Matrix4 ReadMatrix4(bool SwapRows = false)
|
|
{
|
|
Matrix4 mat4 = new Matrix4();
|
|
if (SwapRows)
|
|
{
|
|
mat4.M11 = ReadSingle();
|
|
mat4.M21 = ReadSingle();
|
|
mat4.M31 = ReadSingle();
|
|
mat4.M41 = ReadSingle();
|
|
mat4.M12 = ReadSingle();
|
|
mat4.M22 = ReadSingle();
|
|
mat4.M32 = ReadSingle();
|
|
mat4.M42 = ReadSingle();
|
|
mat4.M13 = ReadSingle();
|
|
mat4.M23 = ReadSingle();
|
|
mat4.M33 = ReadSingle();
|
|
mat4.M43 = ReadSingle();
|
|
mat4.M14 = ReadSingle();
|
|
mat4.M24 = ReadSingle();
|
|
mat4.M34 = ReadSingle();
|
|
mat4.M44 = ReadSingle();
|
|
}
|
|
else
|
|
{
|
|
mat4.M11 = ReadSingle();
|
|
mat4.M12 = ReadSingle();
|
|
mat4.M13 = ReadSingle();
|
|
mat4.M14 = ReadSingle();
|
|
mat4.M21 = ReadSingle();
|
|
mat4.M22 = ReadSingle();
|
|
mat4.M23 = ReadSingle();
|
|
mat4.M24 = ReadSingle();
|
|
mat4.M31 = ReadSingle();
|
|
mat4.M32 = ReadSingle();
|
|
mat4.M33 = ReadSingle();
|
|
mat4.M34 = ReadSingle();
|
|
mat4.M41 = ReadSingle();
|
|
mat4.M42 = ReadSingle();
|
|
mat4.M43 = ReadSingle();
|
|
mat4.M44 = ReadSingle();
|
|
}
|
|
return mat4;
|
|
}
|
|
|
|
public void SeekBegin(uint Offset) { Seek(Offset, SeekOrigin.Begin); }
|
|
public void SeekBegin(int Offset) { Seek(Offset, SeekOrigin.Begin); }
|
|
public void SeekBegin(long Offset) { Seek(Offset, SeekOrigin.Begin); }
|
|
|
|
public long ReadOffset(bool IsRelative, Type OffsetType)
|
|
{
|
|
long pos = Position;
|
|
long offset = 0;
|
|
|
|
if (OffsetType == typeof(long))
|
|
offset = ReadInt64();
|
|
if (OffsetType == typeof(ulong))
|
|
offset = (long)ReadUInt64();
|
|
if (OffsetType == typeof(uint))
|
|
offset = ReadUInt32();
|
|
if (OffsetType == typeof(int))
|
|
offset = ReadInt32();
|
|
|
|
if (IsRelative && offset != 0)
|
|
return pos + offset;
|
|
else
|
|
return offset;
|
|
}
|
|
|
|
public string LoadString(bool IsRelative, Type OffsetType, Encoding encoding = null, uint ReadStringLength = 0)
|
|
{
|
|
long pos = Position;
|
|
|
|
long offset = 0;
|
|
int size = 0;
|
|
|
|
if (OffsetType == typeof(long))
|
|
offset = ReadInt64();
|
|
if (OffsetType == typeof(ulong))
|
|
offset = (long)ReadUInt64();
|
|
if (OffsetType == typeof(uint))
|
|
offset = ReadUInt32();
|
|
if (OffsetType == typeof(int))
|
|
offset = ReadInt32();
|
|
|
|
if (offset == 0) return null;
|
|
|
|
if (IsRelative)
|
|
offset = offset + pos;
|
|
|
|
encoding = encoding ?? Encoding;
|
|
using (TemporarySeek(offset, SeekOrigin.Begin))
|
|
{
|
|
//Read the size of the string if set
|
|
uint stringLength = 0;
|
|
|
|
if (ReadStringLength == 2)
|
|
stringLength = ReadUInt16();
|
|
if (ReadStringLength == 4)
|
|
stringLength = ReadUInt32();
|
|
|
|
return ReadString(BinaryStringFormat.ZeroTerminated, encoding);
|
|
}
|
|
}
|
|
public static byte[] DeflateZLIB(byte[] i)
|
|
{
|
|
MemoryStream output = new MemoryStream();
|
|
output.WriteByte(0x78);
|
|
output.WriteByte(0x9C);
|
|
using (DeflateStream dstream = new DeflateStream(output, CompressionLevel.Optimal))
|
|
{
|
|
dstream.Write(i, 0, i.Length);
|
|
}
|
|
return output.ToArray();
|
|
}
|
|
public byte[] getSection(int offset, int size)
|
|
{
|
|
Position = offset;
|
|
return ReadBytes(size);
|
|
}
|
|
public Vector4 ReadVec4()
|
|
{
|
|
return new Vector4(ReadSingle(), ReadSingle(), ReadSingle(), ReadSingle());
|
|
}
|
|
public Vector3 ReadVec3()
|
|
{
|
|
return new Vector3(ReadSingle(), ReadSingle(), ReadSingle());
|
|
}
|
|
public Syroot.Maths.Vector3F ReadVec3SY()
|
|
{
|
|
return new Syroot.Maths.Vector3F(ReadSingle(), ReadSingle(), ReadSingle());
|
|
}
|
|
public Vector2 ReadVec2()
|
|
{
|
|
return new Vector2(ReadSingle(), ReadSingle());
|
|
}
|
|
public Syroot.Maths.Vector2F ReadVec2SY()
|
|
{
|
|
return new Syroot.Maths.Vector2F(ReadSingle(), ReadSingle());
|
|
}
|
|
public static byte[] InflateZLIB(byte[] i)
|
|
{
|
|
var stream = new MemoryStream();
|
|
var ms = new MemoryStream(i);
|
|
ms.ReadByte();
|
|
ms.ReadByte();
|
|
var zlibStream = new DeflateStream(ms, CompressionMode.Decompress);
|
|
byte[] buffer = new byte[4095];
|
|
while (true)
|
|
{
|
|
int size = zlibStream.Read(buffer, 0, buffer.Length);
|
|
if (size > 0)
|
|
stream.Write(buffer, 0, buffer.Length);
|
|
else
|
|
break;
|
|
}
|
|
zlibStream.Close();
|
|
return stream.ToArray();
|
|
}
|
|
public string ReadMagic(int Offset, int Length)
|
|
{
|
|
Seek(Offset, SeekOrigin.Begin);
|
|
return ReadString(Length);
|
|
}
|
|
}
|
|
}
|