Switch-Toolbox/Switch_Toolbox_Library/IO/STFileLoader.cs
KillzXGaming 8569f3461b Some fixes and additions.
Force close streams if formats are not loaded.
Fix compression menu with null returns. (Used if settings is canceled)
Some msbt saving progress. Need to fixup TXT2 section.
Add VIBS saving
2019-09-22 17:23:07 -04:00

261 lines
10 KiB
C#

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
{
/// <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>
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();
return OpenFileFormat(new MemoryStream(data), 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;
}
/// <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>
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);
}
/// <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>
/// <param name="CompressionFormat">The type of <see cref="ICompressionFormat"/> being used</param>
/// <returns></returns>
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 = compressionFormat.Decompress(stream);
CompressedSize = stream.Length;
return OpenFileFormat(stream, 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;
}
}
}