using Syroot.BinaryData; using System.IO; using System; using System.IO.Compression; using OpenTK; using System.Windows.Forms; namespace Toolbox.Library.IO { public class STFileLoader { /// /// Gets the from a file or byte array. /// /// The name of the file /// The byte array of the data /// If the file is in an archive so it can be saved back /// The node being replaced from an archive /// The unique hash from an archive for saving /// If the file is being compressed or not /// The type of being used /// public static TreeNode GetNodeFileFormat(string FileName, byte[] data = null, bool InArchive = false, TreeNode archiveNode = null, bool LeaveStreamOpen = false, bool Compressed = false, CompressionType CompType = 0) { IFileFormat format = OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode); if (format is TreeNode) return (TreeNode)format; else return null; } public static IFileFormat OpenFileFormat(string FileName, Type[] FileTypes, byte[] data = null) { //Todo. Create a compression list like IFileFormat to decompress via an Identiy method data = CheckCompression(FileName, data); Stream stream; if (data != null) stream = new MemoryStream(data); else stream = File.OpenRead(FileName); foreach (IFileFormat fileFormat in FileManager.GetFileFormats()) { fileFormat.FileName = Path.GetFileName(FileName); foreach (Type type in FileTypes) { if (fileFormat.Identify(stream) && fileFormat.GetType() == type) { fileFormat.IFileInfo = new IFileInfo(); return OpenFileFormat(FileName, data); } } } return null; } public static IFileFormat OpenFileFormat(string FileName, Type FileType, byte[] data = null) { CheckCompression(FileName, data); Stream stream; if (data != null) stream = new MemoryStream(data); else stream = File.OpenRead(FileName); foreach (IFileFormat fileFormat in FileManager.GetFileFormats()) { if (fileFormat.GetType() == FileType) return OpenFileFormat(FileName, data); } return null; } private static byte[] CheckCompression(string FileName, byte[] data) { if (data != null) { using (var reader = new FileReader(data)) { return DecompressData(reader, FileName, data); } } else { using (var reader = new FileReader(FileName)) { return DecompressData(reader, FileName, data); } } } private static byte[] DecompressData(FileReader reader, string FileName, byte[] data) { reader.ByteOrder = ByteOrder.BigEndian; reader.Position = 0; uint MagicHex = reader.ReadUInt32(); string Magic = reader.ReadMagic(0, 4); reader.Position = 0; if (Magic == "Yaz0") { if (data != null) return EveryFileExplorer.YAZ0.Decompress(data); else return EveryFileExplorer.YAZ0.Decompress(FileName); } if (MagicHex == 0x28B52FFD || MagicHex == 0xFD2FB528) { if (data != null) return STLibraryCompression.ZSTD.Decompress(data); else return STLibraryCompression.ZSTD.Decompress(File.ReadAllBytes(FileName)); } return data; } /// /// Gets the from a file or byte array. /// /// The name of the file /// The byte array of the data /// If the file is in an archive so it can be saved back /// The node being replaced from an archive /// If the file is being compressed or not /// The type of being used /// public static IFileFormat OpenFileFormat(string FileName, byte[] data = null, bool LeaveStreamOpen = false, bool InArchive = false, TreeNode archiveNode = null, bool Compressed = false, CompressionType CompType = 0, uint DecompressedSize = 0, uint CompressedSize = 0) { Stream stream; if (data != null) stream = new MemoryStream(data); else stream = File.OpenRead(FileName); return OpenFileFormat(stream, FileName, data, LeaveStreamOpen, InArchive, archiveNode, Compressed, CompType, DecompressedSize, CompressedSize); } /// /// Gets the from a file or byte array. /// /// The name of the file /// The byte array of the data /// If the file is in an archive so it can be saved back /// The node being replaced from an archive /// If the file is being compressed or not /// The type of being used /// public static IFileFormat OpenFileFormat(Stream stream, string FileName, byte[] data = null, bool LeaveStreamOpen = false, bool InArchive = false, TreeNode archiveNode = null, bool Compressed = false, CompressionType CompType = 0, uint DecompressedSize = 0, uint CompressedSize = 0) { uint DecompressedFileSize = 0; uint CompressedFileSize = 0; using (var fileReader = new FileReader(stream, true)) { if (CompType == CompressionType.None) DecompressedFileSize = (uint)fileReader.BaseStream.Length; if (CompType != CompressionType.None) CompressedFileSize = (uint)fileReader.BaseStream.Length; if (fileReader.BaseStream.Length <= 4) { fileReader.Close(); fileReader.Dispose(); return null; } Cursor.Current = Cursors.WaitCursor; fileReader.ByteOrder = ByteOrder.BigEndian; uint MagicHex = fileReader.ReadUInt32(); string Magic = fileReader.ReadMagic(0, 4); fileReader.Position = 0; ushort MagicHex2 = fileReader.ReadUInt16(); //Another hacky magic check if decomp size is first fileReader.Position = 4; ushort MagicHex3 = fileReader.ReadUInt16(); //Note this method will soon be how all compression formats are handled rather than being checked here foreach (ICompressionFormat compressionFormat in FileManager.GetCompressionFormats()) { if (compressionFormat.Identify(stream)) { stream = compressionFormat.Decompress(stream); } } if (Magic == "Yaz0") { if (data != null) data = EveryFileExplorer.YAZ0.Decompress(data); else data = EveryFileExplorer.YAZ0.Decompress(FileName); return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, CompressionType.Yaz0, DecompressedFileSize, CompressedFileSize); } if (Path.GetExtension(FileName) == ".cbtex") { fileReader.Position = 0; byte compType = fileReader.ReadByte(); if (compType == 0x50) { if (data == null) data = File.ReadAllBytes(FileName); fileReader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian; fileReader.Seek(4, System.IO.SeekOrigin.Begin); uint decompSize = fileReader.ReadUInt32(); uint compSize = (uint)fileReader.BaseStream.Length - 8; var comp = new STLibraryCompression.MTA_CUSTOM(); data = comp.Decompress(data, decompSize); return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, CompressionType.MarioTennisCustom, DecompressedFileSize, CompressedFileSize); } fileReader.Position = 0; } if (Path.GetExtension(FileName) == ".lz") { if (data == null) data = File.ReadAllBytes(FileName); data = LZ77_WII.Decompress(fileReader.getSection(16, data.Length - 16)); return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, CompressionType.Yaz0, DecompressedFileSize, CompressedFileSize); } if (MagicHex == 0x28B52FFD || MagicHex == 0xFD2FB528) { if (data != null) data = STLibraryCompression.ZSTD.Decompress(fileReader.getSection(0, data.Length)); else data = STLibraryCompression.ZSTD.Decompress(File.ReadAllBytes(FileName)); return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, CompressionType.Zstb, DecompressedFileSize, CompressedFileSize); } if (Magic == "ZCMP" || MagicHex2 == 0x789C || MagicHex2 == 0x78DA || Path.GetExtension(FileName) == ".z" && CompType == CompressionType.None) { if (data == null) data = File.ReadAllBytes(FileName); data = STLibraryCompression.ZLIB.Decompress(data); return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, CompressionType.Zlib, DecompressedFileSize, CompressedFileSize); } if (MagicHex3 == 0x789C || MagicHex3 == 0x78DA && CompType == CompressionType.None) { if (data == null) data = File.ReadAllBytes(FileName); fileReader.Position = 0; int OuSize = fileReader.ReadInt32(); int InSize = data.Length - 4; data = STLibraryCompression.ZLIB.Decompress(fileReader.getSection(4, InSize)); return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, CompressionType.Zlib, DecompressedFileSize, CompressedFileSize); } if (Path.GetExtension(FileName) == ".carc" && CompType == CompressionType.None) { if (data == null) data = File.ReadAllBytes(FileName); data = STLibraryCompression.ZLIB.Decompress(fileReader.getSection(0x10, data.Length - 0x10)); return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, CompressionType.Zlib, DecompressedFileSize, CompressedFileSize); } if (Magic == "ZLIB") { if (data == null) data = File.ReadAllBytes(FileName); data = STLibraryCompression.GZIP.Decompress(fileReader.getSection(64, data.Length - 64)); return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, CompressionType.Zlib, DecompressedFileSize, CompressedFileSize); } if (MagicHex == 0x1f8b0808 || MagicHex2 == 0x1f8b && CompType == CompressionType.None) { if (data == null) data = File.ReadAllBytes(FileName); data = STLibraryCompression.GZIP.Decompress(data); return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, CompressionType.Gzip, DecompressedFileSize, CompressedFileSize); } if (MagicHex == 0x184D2204) { if (data == null) data = File.ReadAllBytes(FileName); data = STLibraryCompression.Type_LZ4.Decompress(data); return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, CompressionType.Lz4, DecompressedFileSize, CompressedFileSize); } if (Path.GetExtension(FileName) == ".lz" && CompType == CompressionType.None) { if (data == null) data = File.ReadAllBytes(FileName); data = STLibraryCompression.LZ77.Decompress(fileReader.getSection(16, data.Length - 16)); return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, CompressionType.Zlib, DecompressedFileSize, CompressedFileSize); } if (Path.GetExtension(FileName) == ".cmp" && CompType == CompressionType.None) { if (data == null) data = File.ReadAllBytes(FileName); fileReader.Position = 0; int OuSize = fileReader.ReadInt32(); int InSize = data.Length - 4; data = STLibraryCompression.Type_LZ4F.Decompress(fileReader.getSection(4, InSize)); return OpenFileFormat(FileName, data, InArchive, LeaveStreamOpen, archiveNode, true, CompressionType.Lz4f, DecompressedFileSize, CompressedFileSize); } } foreach (IFileFormat fileFormat in FileManager.GetFileFormats()) { //Set the file name so we can check it's extension in the identifier. //Most is by magic but some can be extension or name. fileFormat.FileName = Path.GetFileName(FileName); if (fileFormat.Identify(stream)) { fileFormat.IFileInfo = new IFileInfo(); fileFormat.IFileInfo.DecompressedSize = DecompressedFileSize; fileFormat.IFileInfo.CompressedSize = CompressedFileSize; return SetFileFormat(fileFormat, FileName, stream, LeaveStreamOpen, InArchive, archiveNode, Compressed, CompType); } } return null; } private static IFileFormat SetFileFormat(IFileFormat fileFormat, string FileName, Stream stream, bool LeaveStreamOpen = false, bool InArchive = false, TreeNode archiveNode = null, bool Compressed = false, CompressionType CompType = 0) { fileFormat.IFileInfo.CompressionType = CompType; fileFormat.IFileInfo.FileIsCompressed = Compressed; fileFormat.FileName = Path.GetFileName(FileName); fileFormat.FilePath = FileName; fileFormat.IFileInfo.InArchive = InArchive; fileFormat.IFileInfo.FileIsCompressed = Compressed; if (Compressed) fileFormat.IFileInfo.CompressionType = CompType; fileFormat.Load(stream); if (fileFormat is TreeNode) { if (archiveNode != null) { ((TreeNode)fileFormat).Text = archiveNode.Text; ((TreeNode)fileFormat).ImageKey = archiveNode.ImageKey; ((TreeNode)fileFormat).SelectedImageKey = archiveNode.SelectedImageKey; } } //After file has been loaded and read, we'll dispose unless left open if (fileFormat is ILeaveOpenOnLoad) { LeaveStreamOpen = true; } if (!LeaveStreamOpen) { stream.Dispose(); GC.SuppressFinalize(stream); } return fileFormat; } } }