using Syroot.BinaryData; using System.IO; using System.IO.Compression; using OpenTK; using K4os.Compression.LZ4.Streams; using System.Windows.Forms; using ICSharpCode.SharpZipLib.Zip.Compression.Streams; namespace Switch_Toolbox.Library.IO { public enum DataType { uint8, int8, uint16, int16, int32, uint32, int64, uint64, } public class STFileSaver { /// /// Saves the as a file from the given /// /// The format instance of the file being saved /// The name of the file /// The Alignment used for compression. Used for Yaz0 compression type. /// Toggle for showing compression dialog /// public static void SaveFileFormat(IFileFormat FileFormat, string FileName, bool EnableDialog = true) { Cursor.Current = Cursors.WaitCursor; FileFormat.FilePath = FileName; SaveFileFormat(FileFormat.Save(), FileFormat.IFileInfo.FileIsCompressed, FileFormat.IFileInfo.Alignment, FileFormat.IFileInfo.CompressionType, FileName, EnableDialog); } public static void SaveFileFormat(byte[] data, bool FileIsCompressed, int Alignment, CompressionType CompressionType, string FileName, bool EnableDialog = true) { string extension = Path.GetExtension(FileName); if (extension == ".szs" || extension == ".sbfres") { FileIsCompressed = true; CompressionType = CompressionType.Yaz0; } if (extension == ".cmp") { FileIsCompressed = true; CompressionType = CompressionType.Lz4f; } if (EnableDialog && FileIsCompressed) { DialogResult save = MessageBox.Show($"Compress file with {CompressionType}?", "File Save", MessageBoxButtons.YesNo); if (save == DialogResult.Yes) { switch (CompressionType) { case CompressionType.Yaz0: data = EveryFileExplorer.YAZ0.Compress(data, Runtime.Yaz0CompressionLevel, (uint)Alignment); break; case CompressionType.Zstb: data = STLibraryCompression.ZSTD.Compress(data); break; case CompressionType.Lz4: data = STLibraryCompression.Type_LZ4.Compress(data); break; case CompressionType.Lz4f: data = STLibraryCompression.Type_LZ4F.Compress(data); break; case CompressionType.Gzip: data = STLibraryCompression.GZIP.Compress(data); break; case CompressionType.Zlib: data = STLibraryCompression.ZLIB.Compress(data, 2); break; default: MessageBox.Show($"Compression Type {CompressionType} not supported!!"); break; } } } File.WriteAllBytes(FileName, data); MessageBox.Show($"File has been saved to {FileName}"); Cursor.Current = Cursors.Default; } } 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; } /// /// 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) { FileReader fileReader; if (data != null) fileReader = new FileReader(data); else fileReader = new FileReader(FileName); 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; 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); } if (MagicHex == 0x28B52FFD || MagicHex == 0xFD2FB528) { data = STLibraryCompression.ZSTD.Decompress(fileReader.getSection(0, data.Length)); return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, CompressionType.Zstb); } if (Path.GetExtension(FileName) == ".z" && CompType == CompressionType.None) { if (data == null) data = File.ReadAllBytes(FileName); data = STLibraryCompression.ZLIB.Decompress(fileReader.getSection(2, data.Length - 2)); return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, CompressionType.Zlib); } 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); } if (MagicHex == 0x1f8b0808 && 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); } 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); } 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); } fileReader.Dispose(); fileReader.Close(); Stream stream; if (data != null) stream = new MemoryStream(data); else stream = File.OpenRead(FileName); 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); fileFormat.IFileInfo = new IFileInfo(); if (fileFormat.Identify(stream)) { 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 (!LeaveStreamOpen) { // stream.Close(); // stream.Dispose(); } return fileFormat; } } public class STLibraryCompression { public static byte[] CompressFile(byte[] data, IFileFormat format) { int Alignment = 0; if (format.IFileInfo != null) Alignment = format.IFileInfo.Alignment; switch (format.IFileInfo.CompressionType) { case CompressionType.Yaz0: return EveryFileExplorer.YAZ0.Compress(data, 3, (uint)Alignment); case CompressionType.None: return data; default: return data; } } public class ZSTD { public static byte[] Decompress(byte[] b) { using (var decompressor = new ZstdNet.Decompressor()) { return decompressor.Unwrap(b); } } public static byte[] Decompress(byte[] b, int MaxDecompressedSize) { using (var decompressor = new ZstdNet.Decompressor()) { return decompressor.Unwrap(b, MaxDecompressedSize); } } public static byte[] Compress(byte[] b) { using (var compressor = new ZstdNet.Compressor()) { return compressor.Wrap(b); } } } public class ZLIB { public static byte[] Decompress(byte[] b) { var output = new MemoryStream(); using (var compressedStream = new MemoryStream(b)) { using (var zipStream = new DeflateStream(compressedStream, CompressionMode.Decompress)) { zipStream.CopyTo(output); return output.ToArray(); } } } public static byte[] Compress(byte[] b, uint Position = 0) { //Set position and write the first 2 bytes if necessary MemoryStream mem = new MemoryStream(); using (var decompressedStream = new FileWriter(new MemoryStream())) { if (Position == 2) { decompressedStream.Write(0x780A); decompressedStream.Write(b); } } var output = new MemoryStream(); using (var decompressedStream = new MemoryStream(mem.ToArray())) { decompressedStream.Position = Position; using (var zipStream = new DeflateStream(output, CompressionMode.Compress)) { decompressedStream.CopyTo(zipStream); return output.ToArray(); } } } public static void CopyStream(System.IO.Stream input, System.IO.Stream output) { byte[] buffer = new byte[2000]; int len; while ((len = input.Read(buffer, 0, 2000)) > 0) { output.Write(buffer, 0, len); } output.Flush(); } } public class LZ77 { /// /// Decompresses LZ77-compressed data from the given input stream. /// /// The input stream to read from. /// The decompressed data. public static byte[] Decompress(byte[] input) { BinaryReader reader = new BinaryReader(new MemoryStream(input)); // Check LZ77 type. // if (reader.ReadByte() != 0x10) // throw new System.Exception("Input stream does not contain LZ77-compressed data."); // Read the size. int size = reader.ReadUInt16() | (reader.ReadByte() << 16); // Create output stream. MemoryStream output = new MemoryStream(size); // Begin decompression. while (output.Length < size) { // Load flags for the next 8 blocks. int flagByte = reader.ReadByte(); // Process the next 8 blocks. for (int i = 0; i < 8; i++) { // Check if the block is compressed. if ((flagByte & (0x80 >> i)) == 0) { // Uncompressed block; copy single byte. output.WriteByte(reader.ReadByte()); } else { // Compressed block; read block. ushort block = reader.ReadUInt16(); // Get byte count. int count = ((block >> 4) & 0xF) + 3; // Get displacement. int disp = ((block & 0xF) << 8) | ((block >> 8) & 0xFF); // Save current position and copying position. long outPos = output.Position; long copyPos = output.Position - disp - 1; // Copy all bytes. for (int j = 0; j < count; j++) { // Read byte to be copied. output.Position = copyPos++; byte b = (byte)output.ReadByte(); // Write byte to be copied. output.Position = outPos++; output.WriteByte(b); } } // If all data has been decompressed, stop. if (output.Length >= size) { break; } } } output.Position = 0; return output.ToArray(); } } public class GZIP { public static byte[] Decompress(byte[] b) { using (MemoryStream mem = new MemoryStream()) { using (GZipStream gzip = new GZipStream(new MemoryStream(b), CompressionMode.Decompress)) { gzip.CopyTo(mem); mem.Write(b, 0, b.Length); } return mem.ToArray(); } } public static byte[] Compress(byte[] b) { using (MemoryStream mem = new MemoryStream()) { using (GZipStream gzip = new GZipStream(mem, CompressionMode.Compress, true)) { gzip.Write(b, 0, b.Length); } return mem.ToArray(); } } } public class Type_LZ4F { public static byte[] Decompress(byte[] data) { using (MemoryStream mem = new MemoryStream()) { using (var source = LZ4Stream.Decode(new MemoryStream(data))) { source.CopyTo(mem); } return mem.ToArray(); } } public static byte[] Compress(byte[] data) { var stream = new MemoryStream(); using (var writer = new FileWriter(stream)) { writer.Write(data.Length); byte[] buffer = LZ4.Frame.LZ4Frame.Compress(new MemoryStream(data), LZ4.Frame.LZ4MaxBlockSize.Auto, true, true, false, true, false); writer.Write(buffer, 0, buffer.Length); } return stream.ToArray(); } } public class Type_LZ4 { public static byte[] Decompress(byte[] data, int inputOffset, int InputLength, int decompressedSize) { return LZ4.LZ4Codec.Decode(data, inputOffset, InputLength, decompressedSize); } public static byte[] Decompress(byte[] data) { using (MemoryStream mem = new MemoryStream()) { using (var source = LZ4Stream.Decode(new MemoryStream(data))) { source.CopyTo(mem); mem.Write(data, 0, data.Length); } return mem.ToArray(); } } public static byte[] Compress(byte[] data, int inputOffset = 0) { return LZ4.LZ4Codec.Encode(data, inputOffset, data.Length); } } } public class FileExt { public static System.Drawing.Color[] ReadColors(int Count) { var colors = new System.Drawing.Color[Count]; for (int i = 0; i < Count; i ++) { colors[i] = new System.Drawing.Color(); } return colors; } public static Vector2 ToVec2(Syroot.Maths.Vector2F v) { return new Vector2(v.X, v.Y); } public static Vector3 ToVec3(Syroot.Maths.Vector3F v) { return new Vector3(v.X, v.Y, v.Z); } public static Vector4 ToVec4(Syroot.Maths.Vector4F v) { return new Vector4(v.X, v.Y, v.Z, v.W); } public static Vector2 ToVec2(float[] v) { return new Vector2(v[0], v[1]); } public static Vector3 ToVec3(float[] v) { return new Vector3(v[0], v[1], v[2]); } public static Vector4 ToVec4(float[] v) { return new Vector4(v[0], v[1], v[2], v[3]); } public static string DataToString(Syroot.Maths.Vector2F v) { return $"{v.X},{v.Y}"; } public static string DataToString(Syroot.Maths.Vector3F v) { return $"{v.X},{v.Y},{v.Z}"; } public static string DataToString(Syroot.Maths.Vector4F v) { return $"{v.X},{v.Y},{v.Z} {v.W}"; } } }