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, bool InArchive = false, bool LeaveStreamOpen = false, bool Compressed = false, ICompressionFormat CompressionFormat = null) { IFileFormat format = OpenFileFormat(FileName, LeaveStreamOpen, InArchive); if (format is TreeNode) return (TreeNode)format; else return null; } public static Type CheckFileFormatType(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) return type; } } return typeof(IFileFormat); } 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(); fileFormat.FileName = Path.GetFileName(FileName); fileFormat.FilePath = FileName; return OpenFileFormat(stream, FileName); } } } 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(stream, FileName); } 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 Zstb.SDecompress(data); else return Zstb.SDecompress(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, bool LeaveStreamOpen = false, bool InArchive = false, bool Compressed = false, ICompressionFormat CompressionFormat = null, uint DecompressedSize = 0, uint CompressedSize = 0) { return OpenFileFormat(File.OpenRead(FileName), FileName, LeaveStreamOpen, InArchive, Compressed, CompressionFormat, 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 /// If the file is being compressed or not /// The type of being used /// public static IFileFormat OpenFileFormat(Stream stream, string FileName, bool LeaveStreamOpen = false, bool InArchive = false, bool Compressed = false, ICompressionFormat CompressionFormat = null, long DecompressedSize = 0, long CompressedSize = 0) { if (!Compressed) DecompressedSize = stream.Length; long streamStartPos = stream.Position; if (stream.Length < 8) return null; //Try catch incase it fails, continute to load the file anyways if the check may be false try { //Check all supported compression formats and decompress. Then loop back if (!Compressed) { foreach (ICompressionFormat compressionFormat in FileManager.GetCompressionFormats()) { stream.Position = streamStartPos; if (compressionFormat.Identify(stream, FileName)) { stream.Position = streamStartPos; Stream decompStream = compressionFormat.Decompress(stream); stream.Close(); CompressedSize = decompStream.Length; return OpenFileFormat(decompStream, FileName, LeaveStreamOpen, InArchive, true, compressionFormat, DecompressedSize, CompressedSize); } } } } catch (Exception ex) { Console.WriteLine(ex.ToString()); } stream.Position = streamStartPos; 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 = (uint)DecompressedSize; fileFormat.IFileInfo.CompressedSize = (uint)CompressedSize; return SetFileFormat(fileFormat, FileName, stream, LeaveStreamOpen, InArchive, Compressed, CompressionFormat); } } stream.Close(); return null; } private static IFileFormat SetFileFormat(IFileFormat fileFormat, string FileName, Stream stream, bool LeaveStreamOpen = false, bool InArchive = false, bool Compressed = false, ICompressionFormat FileCompression = null) { fileFormat.IFileInfo.FileCompression = FileCompression; fileFormat.IFileInfo.FileIsCompressed = Compressed; fileFormat.FileName = Path.GetFileName(FileName); fileFormat.FilePath = FileName; fileFormat.IFileInfo.InArchive = InArchive; fileFormat.IFileInfo.FileIsCompressed = Compressed; fileFormat.Load(stream); //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; } } }