2019-05-02 00:08:09 +02:00
|
|
|
|
using Syroot.BinaryData;
|
|
|
|
|
using System.IO;
|
2019-06-26 03:23:00 +02:00
|
|
|
|
using System;
|
2019-05-02 00:08:09 +02:00
|
|
|
|
using System.IO.Compression;
|
|
|
|
|
using OpenTK;
|
|
|
|
|
using System.Windows.Forms;
|
|
|
|
|
|
2019-07-16 23:35:21 +02:00
|
|
|
|
namespace Toolbox.Library.IO
|
2019-05-02 00:08:09 +02:00
|
|
|
|
{
|
|
|
|
|
public class STFileLoader
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the <see cref="TreeNodeFile"/> from a file or byte array.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="FileName">The name of the file</param>
|
|
|
|
|
/// <param name="data">The byte array of the data</param>
|
|
|
|
|
/// <param name="InArchive">If the file is in an archive so it can be saved back</param>
|
|
|
|
|
/// <param name="archiveNode">The node being replaced from an archive</param>
|
|
|
|
|
/// <param name="ArchiveHash">The unique hash from an archive for saving</param>
|
|
|
|
|
/// <param name="Compressed">If the file is being compressed or not</param>
|
|
|
|
|
/// <param name="CompType">The type of <see cref="CompressionType"/> being used</param>
|
|
|
|
|
/// <returns></returns>
|
2019-09-16 01:13:01 +02:00
|
|
|
|
public static TreeNode GetNodeFileFormat(string FileName, bool InArchive = false,
|
|
|
|
|
bool LeaveStreamOpen = false, bool Compressed = false, ICompressionFormat CompressionFormat = null)
|
2019-05-02 00:08:09 +02:00
|
|
|
|
{
|
2019-09-16 01:13:01 +02:00
|
|
|
|
IFileFormat format = OpenFileFormat(FileName, LeaveStreamOpen, InArchive);
|
2019-05-02 00:08:09 +02:00
|
|
|
|
|
|
|
|
|
if (format is TreeNode)
|
|
|
|
|
return (TreeNode)format;
|
|
|
|
|
else
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2019-06-26 03:23:00 +02:00
|
|
|
|
|
2019-08-31 00:53:45 +02:00
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-26 18:48:54 +02:00
|
|
|
|
public static IFileFormat OpenFileFormat(string FileName, Type[] FileTypes, byte[] data = null)
|
2019-06-26 03:23:00 +02:00
|
|
|
|
{
|
2019-06-29 02:42:49 +02:00
|
|
|
|
//Todo. Create a compression list like IFileFormat to decompress via an Identiy method
|
|
|
|
|
data = CheckCompression(FileName, data);
|
2019-06-27 20:38:13 +02:00
|
|
|
|
|
2019-06-26 03:23:00 +02:00
|
|
|
|
Stream stream;
|
|
|
|
|
if (data != null)
|
|
|
|
|
stream = new MemoryStream(data);
|
|
|
|
|
else
|
|
|
|
|
stream = File.OpenRead(FileName);
|
|
|
|
|
|
|
|
|
|
foreach (IFileFormat fileFormat in FileManager.GetFileFormats())
|
|
|
|
|
{
|
2019-06-26 18:48:54 +02:00
|
|
|
|
fileFormat.FileName = Path.GetFileName(FileName);
|
|
|
|
|
|
|
|
|
|
foreach (Type type in FileTypes)
|
2019-06-26 03:23:00 +02:00
|
|
|
|
{
|
2019-06-26 18:48:54 +02:00
|
|
|
|
if (fileFormat.Identify(stream) && fileFormat.GetType() == type)
|
2019-08-29 21:45:32 +02:00
|
|
|
|
{
|
|
|
|
|
fileFormat.IFileInfo = new IFileInfo();
|
2020-02-28 22:52:24 +01:00
|
|
|
|
fileFormat.FileName = Path.GetFileName(FileName);
|
|
|
|
|
fileFormat.FilePath = FileName;
|
2019-09-26 23:23:10 +02:00
|
|
|
|
return OpenFileFormat(stream, FileName);
|
2019-08-29 21:45:32 +02:00
|
|
|
|
}
|
2019-06-26 03:23:00 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static IFileFormat OpenFileFormat(string FileName, Type FileType, byte[] data = null)
|
|
|
|
|
{
|
2019-06-27 20:38:13 +02:00
|
|
|
|
CheckCompression(FileName, data);
|
|
|
|
|
|
2019-06-26 03:23:00 +02:00
|
|
|
|
Stream stream;
|
|
|
|
|
if (data != null)
|
|
|
|
|
stream = new MemoryStream(data);
|
|
|
|
|
else
|
|
|
|
|
stream = File.OpenRead(FileName);
|
|
|
|
|
|
|
|
|
|
foreach (IFileFormat fileFormat in FileManager.GetFileFormats())
|
|
|
|
|
{
|
|
|
|
|
if (fileFormat.GetType() == FileType)
|
2019-09-16 01:13:01 +02:00
|
|
|
|
return OpenFileFormat(stream, FileName);
|
2019-06-26 03:23:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-29 02:42:49 +02:00
|
|
|
|
private static byte[] CheckCompression(string FileName, byte[] data)
|
2019-06-27 20:38:13 +02:00
|
|
|
|
{
|
|
|
|
|
if (data != null)
|
|
|
|
|
{
|
|
|
|
|
using (var reader = new FileReader(data))
|
|
|
|
|
{
|
2019-06-29 02:42:49 +02:00
|
|
|
|
return DecompressData(reader, FileName, data);
|
2019-06-27 20:38:13 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
using (var reader = new FileReader(FileName))
|
|
|
|
|
{
|
2019-06-29 02:42:49 +02:00
|
|
|
|
return DecompressData(reader, FileName, data);
|
2019-06-27 20:38:13 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-29 02:42:49 +02:00
|
|
|
|
private static byte[] DecompressData(FileReader reader, string FileName, byte[] data)
|
2019-06-27 20:38:13 +02:00
|
|
|
|
{
|
|
|
|
|
reader.ByteOrder = ByteOrder.BigEndian;
|
2019-06-29 02:42:49 +02:00
|
|
|
|
reader.Position = 0;
|
2019-06-27 20:38:13 +02:00
|
|
|
|
uint MagicHex = reader.ReadUInt32();
|
|
|
|
|
string Magic = reader.ReadMagic(0, 4);
|
|
|
|
|
reader.Position = 0;
|
|
|
|
|
|
|
|
|
|
if (Magic == "Yaz0")
|
|
|
|
|
{
|
|
|
|
|
if (data != null)
|
2019-06-29 02:42:49 +02:00
|
|
|
|
return EveryFileExplorer.YAZ0.Decompress(data);
|
2019-06-27 20:38:13 +02:00
|
|
|
|
else
|
2019-06-29 02:42:49 +02:00
|
|
|
|
return EveryFileExplorer.YAZ0.Decompress(FileName);
|
2019-06-27 20:38:13 +02:00
|
|
|
|
}
|
|
|
|
|
if (MagicHex == 0x28B52FFD || MagicHex == 0xFD2FB528)
|
|
|
|
|
{
|
|
|
|
|
if (data != null)
|
2019-09-16 01:13:01 +02:00
|
|
|
|
return Zstb.SDecompress(data);
|
2019-06-27 20:38:13 +02:00
|
|
|
|
else
|
2019-09-16 01:13:01 +02:00
|
|
|
|
return Zstb.SDecompress(File.ReadAllBytes(FileName));
|
2019-06-27 20:38:13 +02:00
|
|
|
|
}
|
2019-06-29 02:42:49 +02:00
|
|
|
|
|
|
|
|
|
return data;
|
2019-06-27 20:38:13 +02:00
|
|
|
|
}
|
2019-06-26 03:23:00 +02:00
|
|
|
|
|
2019-05-02 00:08:09 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the <see cref="IFileFormat"/> from a file or byte array.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="FileName">The name of the file</param>
|
|
|
|
|
/// <param name="data">The byte array of the data</param>
|
|
|
|
|
/// <param name="InArchive">If the file is in an archive so it can be saved back</param>
|
|
|
|
|
/// <param name="archiveNode">The node being replaced from an archive</param>
|
|
|
|
|
/// <param name="Compressed">If the file is being compressed or not</param>
|
|
|
|
|
/// <param name="CompType">The type of <see cref="CompressionType"/> being used</param>
|
|
|
|
|
/// <returns></returns>
|
2019-09-16 01:13:01 +02:00
|
|
|
|
public static IFileFormat OpenFileFormat(string FileName, bool LeaveStreamOpen = false, bool InArchive = false,
|
|
|
|
|
bool Compressed = false, ICompressionFormat CompressionFormat = null, uint DecompressedSize = 0, uint CompressedSize = 0)
|
2019-05-02 00:08:09 +02:00
|
|
|
|
{
|
2019-09-16 01:13:01 +02:00
|
|
|
|
return OpenFileFormat(File.OpenRead(FileName), FileName, LeaveStreamOpen, InArchive,
|
|
|
|
|
Compressed, CompressionFormat, DecompressedSize, CompressedSize);
|
2019-08-17 15:58:17 +02:00
|
|
|
|
}
|
2019-05-02 00:08:09 +02:00
|
|
|
|
|
2019-08-17 15:58:17 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the <see cref="IFileFormat"/> from a file or byte array.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="FileName">The name of the file</param>
|
|
|
|
|
/// <param name="data">The byte array of the data</param>
|
|
|
|
|
/// <param name="InArchive">If the file is in an archive so it can be saved back</param>
|
|
|
|
|
/// <param name="Compressed">If the file is being compressed or not</param>
|
2019-09-16 01:13:01 +02:00
|
|
|
|
/// <param name="CompressionFormat">The type of <see cref="ICompressionFormat"/> being used</param>
|
2019-08-17 15:58:17 +02:00
|
|
|
|
/// <returns></returns>
|
2019-09-16 01:13:01 +02:00
|
|
|
|
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)
|
2019-08-17 15:58:17 +02:00
|
|
|
|
{
|
2019-09-16 01:13:01 +02:00
|
|
|
|
if (!Compressed)
|
|
|
|
|
DecompressedSize = stream.Length;
|
2019-07-03 03:39:19 +02:00
|
|
|
|
|
2019-09-16 01:13:01 +02:00
|
|
|
|
long streamStartPos = stream.Position;
|
2019-07-01 21:44:19 +02:00
|
|
|
|
|
2019-09-17 22:58:32 +02:00
|
|
|
|
if (stream.Length < 8) return null;
|
|
|
|
|
|
2019-09-19 03:13:02 +02:00
|
|
|
|
//Try catch incase it fails, continute to load the file anyways if the check may be false
|
|
|
|
|
try
|
2019-09-16 01:13:01 +02:00
|
|
|
|
{
|
2019-09-19 03:13:02 +02:00
|
|
|
|
//Check all supported compression formats and decompress. Then loop back
|
|
|
|
|
if (!Compressed)
|
2019-07-01 21:44:19 +02:00
|
|
|
|
{
|
2019-09-19 03:13:02 +02:00
|
|
|
|
foreach (ICompressionFormat compressionFormat in FileManager.GetCompressionFormats())
|
2019-08-17 15:58:17 +02:00
|
|
|
|
{
|
2019-09-16 01:13:01 +02:00
|
|
|
|
stream.Position = streamStartPos;
|
2019-09-19 03:13:02 +02:00
|
|
|
|
if (compressionFormat.Identify(stream, FileName))
|
|
|
|
|
{
|
|
|
|
|
stream.Position = streamStartPos;
|
2019-08-17 15:58:17 +02:00
|
|
|
|
|
2020-09-03 00:50:48 +02:00
|
|
|
|
Stream decompStream = compressionFormat.Decompress(stream);
|
|
|
|
|
stream.Close();
|
2019-08-17 15:58:17 +02:00
|
|
|
|
|
2020-09-03 00:50:48 +02:00
|
|
|
|
CompressedSize = decompStream.Length;
|
|
|
|
|
|
|
|
|
|
return OpenFileFormat(decompStream, FileName, LeaveStreamOpen, InArchive,
|
2019-09-19 03:13:02 +02:00
|
|
|
|
true, compressionFormat, DecompressedSize, CompressedSize);
|
|
|
|
|
}
|
2019-08-17 15:58:17 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-05-02 00:08:09 +02:00
|
|
|
|
}
|
2019-09-19 03:13:02 +02:00
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine(ex.ToString());
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-16 01:13:01 +02:00
|
|
|
|
stream.Position = streamStartPos;
|
2019-05-02 00:08:09 +02:00
|
|
|
|
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))
|
|
|
|
|
{
|
2019-08-29 21:45:32 +02:00
|
|
|
|
fileFormat.IFileInfo = new IFileInfo();
|
2019-09-16 01:13:01 +02:00
|
|
|
|
fileFormat.IFileInfo.DecompressedSize = (uint)DecompressedSize;
|
|
|
|
|
fileFormat.IFileInfo.CompressedSize = (uint)CompressedSize;
|
|
|
|
|
return SetFileFormat(fileFormat, FileName, stream, LeaveStreamOpen, InArchive, Compressed, CompressionFormat);
|
2019-05-02 00:08:09 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-22 23:23:07 +02:00
|
|
|
|
stream.Close();
|
|
|
|
|
|
2019-05-02 00:08:09 +02:00
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static IFileFormat SetFileFormat(IFileFormat fileFormat, string FileName, Stream stream, bool LeaveStreamOpen = false, bool InArchive = false,
|
2019-09-16 01:13:01 +02:00
|
|
|
|
bool Compressed = false, ICompressionFormat FileCompression = null)
|
2019-05-02 00:08:09 +02:00
|
|
|
|
{
|
2019-09-16 01:13:01 +02:00
|
|
|
|
fileFormat.IFileInfo.FileCompression = FileCompression;
|
2019-05-02 00:08:09 +02:00
|
|
|
|
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
|
|
|
|
|
|
2019-08-01 01:45:03 +02:00
|
|
|
|
if (fileFormat is ILeaveOpenOnLoad) {
|
|
|
|
|
LeaveStreamOpen = true;
|
2019-08-01 01:33:45 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-05-02 00:08:09 +02:00
|
|
|
|
if (!LeaveStreamOpen)
|
|
|
|
|
{
|
2019-07-25 03:15:21 +02:00
|
|
|
|
stream.Dispose();
|
2019-07-25 20:31:33 +02:00
|
|
|
|
GC.SuppressFinalize(stream);
|
2019-05-02 00:08:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return fileFormat;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|