diff --git a/SabreTools.Serialization/WrapperFactory.cs b/SabreTools.Serialization/WrapperFactory.cs index 6e5c2c85..5517144a 100644 --- a/SabreTools.Serialization/WrapperFactory.cs +++ b/SabreTools.Serialization/WrapperFactory.cs @@ -51,6 +51,7 @@ namespace SabreTools.Serialization WrapperType.RealArcadeMezzanine => RealArcadeMezzanine.Create(data), WrapperType.SecuROMDFA => SecuROMDFA.Create(data), WrapperType.SevenZip => SevenZip.Create(data), + WrapperType.Skeleton => Skeleton.Create(data), WrapperType.SFFS => SFFS.Create(data), WrapperType.SGA => SGA.Create(data), WrapperType.TapeArchive => TapeArchive.Create(data), @@ -669,6 +670,13 @@ namespace SabreTools.Serialization #endregion + #region Skeleton + + if (extension.Equals("skeleton", StringComparison.OrdinalIgnoreCase)) + return WrapperType.Skeleton; + + #endregion + // TODO: Use constants from Models here #region TapeArchive diff --git a/SabreTools.Serialization/Wrappers/Skeleton.cs b/SabreTools.Serialization/Wrappers/Skeleton.cs new file mode 100644 index 00000000..f8437d8d --- /dev/null +++ b/SabreTools.Serialization/Wrappers/Skeleton.cs @@ -0,0 +1,107 @@ +using System.Collections.Generic; +using System.IO; +using SabreTools.Data.Models.ISO9660; + +namespace SabreTools.Serialization.Wrappers +{ + public class Skeleton : WrapperBase + { + #region Descriptive Properties + + /// + public override string DescriptionString => "Redumper Skeleton"; + + #endregion + + #region Extension Properties + + /// + public byte[] SystemArea => Model.SystemArea ?? []; + + /// + public VolumeDescriptor[] VolumeDescriptorSet => Model.VolumeDescriptorSet ?? []; + + /// + public PathTableGroup[] PathTableGroups => Model.PathTableGroups ?? []; + + /// + public Dictionary DirectoryDescriptors => Model.DirectoryDescriptors ?? []; + + #endregion + + #region Constructors + + /// + public Skeleton(Volume model, byte[] data) : base(model, data) { } + + /// + public Skeleton(Volume model, byte[] data, int offset) : base(model, data, offset) { } + + /// + public Skeleton(Volume model, byte[] data, int offset, int length) : base(model, data, offset, length) { } + + /// + public Skeleton(Volume model, Stream data) : base(model, data) { } + + /// + public Skeleton(Volume model, Stream data, long offset) : base(model, data, offset) { } + + /// + public Skeleton(Volume model, Stream data, long offset, long length) : base(model, data, offset, length) { } + + #endregion + + #region Static Constructors + + /// + /// Create an Skeleton Volume from a byte array and offset + /// + /// Byte array representing the archive + /// Offset within the array to parse + /// An Skeleton Volume wrapper on success, null on failure + public static Skeleton? Create(byte[]? data, int offset) + { + // If the data is invalid + if (data == 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 an Skeleton Volume from a Stream + /// + /// Stream representing the archive + /// An Skeleton Volume wrapper on success, null on failure + public static Skeleton? Create(Stream? data) + { + // If the data is invalid + if (data == null || !data.CanRead) + return null; + + try + { + // Cache the current offset + long currentOffset = data.Position; + + var model = new Readers.ISO9660().Deserialize(data); + if (model == null) + return null; + + return new Skeleton(model, data, currentOffset); + } + catch + { + return null; + } + } + + #endregion + } +} diff --git a/SabreTools.Serialization/Wrappers/WrapperType.cs b/SabreTools.Serialization/Wrappers/WrapperType.cs index 4dcbeac3..ce086fe3 100644 --- a/SabreTools.Serialization/Wrappers/WrapperType.cs +++ b/SabreTools.Serialization/Wrappers/WrapperType.cs @@ -207,6 +207,11 @@ namespace SabreTools.Serialization.Wrappers /// SGA, + /// + /// Redumper skeleton (Wiped ISO9660 disc image) + /// + Skeleton, + /// /// Tape archive ///