using System; using System.IO; using SabreTools.Data.Models.SGA; namespace SabreTools.Wrappers { public partial class SGA : WrapperBase { #region Descriptive Properties /// public override string DescriptionString => "SGA"; #endregion #region Extension Properties /// /// Directory data /// public Data.Models.SGA.Directory Directory => Model.Directory; /// /// Number of files in the directory /// public int FileCount { get { return Directory switch { Directory4 d4 => d4.Files.Length, Directory5 d5 => d5.Files.Length, Directory6 d6 => d6.Files.Length, Directory7 d7 => d7.Files.Length, _ => 0, }; } } /// /// Offset to the file data /// public long FileDataOffset { get { return Model.Header switch { Header4 h4 => h4.FileDataOffset, Header6 h6 => h6.FileDataOffset, _ => -1, }; } } #endregion #region Constructors /// public SGA(Archive model, byte[] data) : base(model, data) { } /// public SGA(Archive model, byte[] data, int offset) : base(model, data, offset) { } /// public SGA(Archive model, byte[] data, int offset, int length) : base(model, data, offset, length) { } /// public SGA(Archive model, Stream data) : base(model, data) { } /// public SGA(Archive model, Stream data, long offset) : base(model, data, offset) { } /// public SGA(Archive model, Stream data, long offset, long length) : base(model, data, offset, length) { } #endregion #region Static Constructors /// /// Create an SGA from a byte array and offset /// /// Byte array representing the SGA /// Offset within the array to parse /// An SGA wrapper on success, null on failure public static SGA? Create(byte[]? data, int offset) { // If the data is invalid if (data is null || data.Length == 0) return null; // If the offset is out of bounds if (offset < 0 || offset >= data.Length) return null; // Create a memory stream and use that var dataStream = new MemoryStream(data, offset, data.Length - offset); return Create(dataStream); } /// /// Create a SGA from a Stream /// /// Stream representing the SGA /// An SGA wrapper on success, null on failure public static SGA? Create(Stream? data) { // If the data is invalid if (data is null || !data.CanRead) return null; try { // Cache the current offset long currentOffset = data.Position; var model = new Serialization.Readers.SGA().Deserialize(data); if (model is null) return null; return new SGA(model, data, currentOffset); } catch { return null; } } #endregion #region File /// /// Get the compressed size of a file /// public long GetCompressedSize(int index) { // If the index is invalid if (index < 0 || index >= FileCount) return -1; // Get the file and return the name var file = GetFile(index); return file?.Size ?? -1L; } /// /// Get the uncompressed size of a file /// public long GetUncompressedSize(int index) { // If the index is invalid if (index < 0 || index >= FileCount) return -1; // Get the file and return the name var file = GetFile(index); return file?.SizeOnDisk ?? -1L; } /// /// Get a file header from the archive /// public Data.Models.SGA.File? GetFile(int index) { // If the index is invalid if (index < 0 || index >= FileCount) return null; return Directory switch { Directory4 d4 => d4.Files![index], Directory5 d5 => d5.Files![index], Directory6 d6 => d6.Files![index], Directory7 d7 => d7.Files![index], _ => null, }; } /// /// Get a file name from the archive /// public string? GetFileName(int index) { // If the index is invalid if (index < 0 || index >= FileCount) return null; // Get the file and return the name var file = GetFile(index); return file?.Name; } /// /// Get a file offset from the archive /// public long GetFileOffset(int index) { // If the index is invalid if (index < 0 || index >= FileCount) return -1; // Get the file and return the name var file = GetFile(index); return file?.Offset ?? -1L; } /// /// Get the parent name for a file /// public string? GetParentName(int index) { // If the index is invalid if (index < 0 || index >= FileCount) return null; // Get the folder Folder? folder = Directory switch { Directory4 d4 => Array.Find(d4.Folders, f => f is not null && index >= f.FileStartIndex && index <= f.FileEndIndex), Directory5 d5 => Array.Find(d5.Folders, f => f is not null && index >= f.FileStartIndex && index <= f.FileEndIndex), Directory6 d6 => Array.Find(d6.Folders, f => f is not null && index >= f.FileStartIndex && index <= f.FileEndIndex), Directory7 d7 => Array.Find(d7.Folders, f => f is not null && index >= f.FileStartIndex && index <= f.FileEndIndex), _ => default, }; // Get the folder name return folder switch { Folder4 f4 => f4.Name, Folder5 f5 => f5.Name, _ => null, }; } #endregion } }