diff --git a/SabreTools.Serialization/Wrappers/BFPK.cs b/SabreTools.Serialization/Wrappers/BFPK.cs index 027a95f7..0bc7038a 100644 --- a/SabreTools.Serialization/Wrappers/BFPK.cs +++ b/SabreTools.Serialization/Wrappers/BFPK.cs @@ -15,9 +15,7 @@ namespace SabreTools.Serialization.Wrappers #region Extension Properties - /// /// - /// public FileEntry[] Files => Model.Files ?? []; #endregion diff --git a/SabreTools.Serialization/Wrappers/Quantum.cs b/SabreTools.Serialization/Wrappers/Quantum.cs index e8c547f9..676a4d04 100644 --- a/SabreTools.Serialization/Wrappers/Quantum.cs +++ b/SabreTools.Serialization/Wrappers/Quantum.cs @@ -1,8 +1,9 @@ using System.IO; +using SabreTools.Models.Quantum; namespace SabreTools.Serialization.Wrappers { - public class Quantum : WrapperBase + public class Quantum : WrapperBase { #region Descriptive Properties @@ -14,14 +15,14 @@ namespace SabreTools.Serialization.Wrappers #region Constructors /// - public Quantum(Models.Quantum.Archive? model, byte[]? data, int offset) + public Quantum(Archive? model, byte[]? data, int offset) : base(model, data, offset) { // All logic is handled by the base class } /// - public Quantum(Models.Quantum.Archive? model, Stream? data) + public Quantum(Archive? model, Stream? data) : base(model, data) { // All logic is handled by the base class @@ -74,5 +75,130 @@ namespace SabreTools.Serialization.Wrappers } #endregion + + #region Extension Properties + + /// + public long CompressedDataOffset => Model.CompressedDataOffset; + + /// + public ushort FileCount => Model.Header?.FileCount ?? 0; + + /// + public FileDescriptor[] FileList => Model.FileList ?? []; + + #endregion + + #region Extraction + + /// + /// Extract all files from the Quantum archive to an output directory + /// + /// Output directory to write to + /// True if all files extracted, false otherwise + public bool ExtractAll(string outputDirectory) + { + // If we have no files + if (FileList == null || FileList.Length == 0) + return false; + + // Loop through and extract all files to the output + bool allExtracted = true; + for (int i = 0; i < FileList.Length; i++) + { + allExtracted &= ExtractFile(i, outputDirectory); + } + + return allExtracted; + } + + /// + /// Extract a file from the Quantum archive to an output directory by index + /// + /// File index to extract + /// Output directory to write to + /// True if the file extracted, false otherwise + public bool ExtractFile(int index, string outputDirectory) + { + // If we have no files + if (Model.Header == null || FileCount == 0 || FileList == null || FileList.Length == 0) + return false; + + // If we have an invalid index + if (index < 0 || index >= FileList.Length) + return false; + + // Get the file information + var fileDescriptor = FileList[index]; + + // Read the entire compressed data + int compressedDataOffset = (int)CompressedDataOffset; + int compressedDataLength = GetEndOfFile() - compressedDataOffset; + var compressedData = ReadFromDataSource(compressedDataOffset, compressedDataLength); + + // TODO: Figure out decompression + // - Single-file archives seem to work + // - Single-file archives with files that span a window boundary seem to work + // - The first files in each archive seem to work + return false; + + // // Setup the decompression state + // State state = new State(); + // Decompressor.InitState(state, TableSize, CompressionFlags); + + // // Decompress the entire array + // int decompressedDataLength = (int)FileList.Sum(fd => fd.ExpandedFileSize); + // byte[] decompressedData = new byte[decompressedDataLength]; + // Decompressor.Decompress(state, compressedData.Length, compressedData, decompressedData.Length, decompressedData); + + // // Read the data + // int offset = (int)FileList.Take(index).Sum(fd => fd.ExpandedFileSize); + // byte[] data = new byte[fileDescriptor.ExpandedFileSize]; + // Array.Copy(decompressedData, offset, data, 0, data.Length); + + // // Loop through all files before the current + // for (int i = 0; i < index; i++) + // { + // // Decompress the next block of data + // byte[] tempData = new byte[FileList[i].ExpandedFileSize]; + // int lastRead = Decompressor.Decompress(state, compressedData.Length, compressedData, tempData.Length, tempData); + // compressedData = new ReadOnlySpan(compressedData, (lastRead), compressedData.Length - (lastRead)).ToArray(); + // } + + // // Read the data + // byte[] data = new byte[fileDescriptor.ExpandedFileSize]; + // _ = Decompressor.Decompress(state, compressedData.Length, compressedData, data.Length, data); + + // // Create the filename + // string filename = fileDescriptor.FileName; + + // // If we have an invalid output directory + // if (string.IsNullOrEmpty(outputDirectory)) + // return false; + + // // Create the full output path + // filename = Path.Combine(outputDirectory, filename); + + // // Ensure the output directory is created + // Directory.CreateDirectory(Path.GetDirectoryName(filename)); + + // // Try to write the data + // try + // { + // // Open the output file for writing + // using (Stream fs = File.OpenWrite(filename)) + // { + // fs.Write(data, 0, data.Length); + // } + // } + // catch + // { + // return false; + // } + + // return true; + } + + #endregion } } \ No newline at end of file