diff --git a/Bytes/BFPK.Deserializer.cs b/Bytes/BFPK.Deserializer.cs new file mode 100644 index 00000000..a8556608 --- /dev/null +++ b/Bytes/BFPK.Deserializer.cs @@ -0,0 +1,28 @@ +using System.IO; +using SabreTools.Models.BFPK; + +namespace SabreTools.Serialization.Bytes +{ + public partial class BFPK : IByteSerializer + { + /// +#if NET48 + public Archive Deserialize(byte[] data, int offset) +#else + public Archive? Deserialize(byte[]? data, int offset) +#endif + { + // If the data is invalid + if (data == null) + return null; + + // If the offset is out of bounds + if (offset < 0 || offset >= data.Length) + return null; + + // Create a memory stream and parse that + MemoryStream dataStream = new MemoryStream(data, offset, data.Length - offset); + return new Streams.BFPK().Deserialize(dataStream); + } + } +} \ No newline at end of file diff --git a/Streams/BFPK.Deserializer.cs b/Streams/BFPK.Deserializer.cs new file mode 100644 index 00000000..d423d4f7 --- /dev/null +++ b/Streams/BFPK.Deserializer.cs @@ -0,0 +1,121 @@ +using System.IO; +using System.Text; +using SabreTools.IO; +using SabreTools.Models.BFPK; +using static SabreTools.Models.BFPK.Constants; + +namespace SabreTools.Serialization.Streams +{ + public partial class BFPK : IStreamSerializer + { + /// +#if NET48 + public Archive Deserialize(Stream data) +#else + public Archive? Deserialize(Stream? data) +#endif + { + // If the data is invalid + if (data == null || data.Length == 0 || !data.CanSeek || !data.CanRead) + return null; + + // If the offset is out of bounds + if (data.Position < 0 || data.Position >= data.Length) + return null; + + // Cache the current offset + int initialOffset = (int)data.Position; + + // Create a new archive to fill + var archive = new Archive(); + + #region Header + + // Try to parse the header + var header = ParseHeader(data); + if (header == null) + return null; + + // Set the archive header + archive.Header = header; + + #endregion + + #region Files + + // If we have any files + if (header.Files > 0) + { + var files = new FileEntry[header.Files]; + + // Read all entries in turn + for (int i = 0; i < header.Files; i++) + { + var file = ParseFileEntry(data); + if (file == null) + return null; + + files[i] = file; + } + + // Set the files + archive.Files = files; + } + + #endregion + + return archive; + } + + /// + /// Parse a Stream into a header + /// + /// Stream to parse + /// Filled header on success, null on error + private static Header ParseHeader(Stream data) + { + // TODO: Use marshalling here instead of building + Header header = new Header(); + + byte[] magic = data.ReadBytes(4); + header.Magic = Encoding.ASCII.GetString(magic); + if (header.Magic != SignatureString) + return null; + + header.Version = data.ReadInt32(); + header.Files = data.ReadInt32(); + + return header; + } + + /// + /// Parse a Stream into a file entry + /// + /// Stream to parse + /// Filled file entry on success, null on error + private static FileEntry ParseFileEntry(Stream data) + { + // TODO: Use marshalling here instead of building + FileEntry fileEntry = new FileEntry(); + + fileEntry.NameSize = data.ReadInt32(); + if (fileEntry.NameSize > 0) + { + byte[] name = data.ReadBytes(fileEntry.NameSize); + fileEntry.Name = Encoding.ASCII.GetString(name); + } + + fileEntry.UncompressedSize = data.ReadInt32(); + fileEntry.Offset = data.ReadInt32(); + if (fileEntry.Offset > 0) + { + long currentOffset = data.Position; + data.Seek(fileEntry.Offset, SeekOrigin.Begin); + fileEntry.CompressedSize = data.ReadInt32(); + data.Seek(currentOffset, SeekOrigin.Begin); + } + + return fileEntry; + } + } +} \ No newline at end of file diff --git a/Streams/BFPK.Serializer.cs b/Streams/BFPK.Serializer.cs new file mode 100644 index 00000000..02424635 --- /dev/null +++ b/Streams/BFPK.Serializer.cs @@ -0,0 +1,16 @@ +using System; +using System.IO; +using SabreTools.Models.BFPK; + +namespace SabreTools.Serialization.Streams +{ + public partial class BFPK : IStreamSerializer + { + /// +#if NET48 + public Stream Serialize(Archive obj) => throw new NotImplementedException(); +#else + public Stream? Serialize(Archive? obj) => throw new NotImplementedException(); +#endif + } +} \ No newline at end of file