From ab44aa7e68c87c41ca8c92fd6c5107f3a404d1a4 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Thu, 28 Aug 2025 08:14:38 -0400 Subject: [PATCH] Start implementing tar --- .../Deserializers/TapeArchive.cs | 104 +++++++++++++++++- 1 file changed, 103 insertions(+), 1 deletion(-) diff --git a/SabreTools.Serialization/Deserializers/TapeArchive.cs b/SabreTools.Serialization/Deserializers/TapeArchive.cs index 56a6fd22..46b95ccc 100644 --- a/SabreTools.Serialization/Deserializers/TapeArchive.cs +++ b/SabreTools.Serialization/Deserializers/TapeArchive.cs @@ -1,4 +1,7 @@ +using System.Collections.Generic; using System.IO; +using System.Text; +using SabreTools.IO.Extensions; using SabreTools.Models.TAR; namespace SabreTools.Serialization.Deserializers @@ -22,7 +25,19 @@ namespace SabreTools.Serialization.Deserializers var archive = new Archive(); - // TODO: Implement everything + // Read all entries sequentially + List entries = []; + while (data.Position < data.Length) + { + var entry = ParseEntry(data); + if (entry == null) + break; + + entries.Add(entry); + } + + // Assign the entries + archive.Entries = [.. entries]; return archive; } @@ -32,5 +47,92 @@ namespace SabreTools.Serialization.Deserializers return null; } } + + /// + /// Parse a Stream into an Entry + /// + /// Stream to parse + /// Filled Entry on success, null on error + public static Entry? ParseEntry(Stream data) + { + var obj = new Entry(); + + #region Header + + var header = ParseHeader(data); + if (header == null) + return null; + + obj.Header = header; + + #endregion + + #region Blocks + + List blocks = []; + + // TODO: Implement + // Each block is 512 bytes of data. The size in the entry + // header is in octal string representation. To the best + // of my knowledge, the number of blocks is just the + // ceiling(size / 512). That is going to be how this is + // implemented. + + obj.Blocks = [.. blocks]; + + #endregion + + return obj; + } + + /// + /// Parse a Stream into a Header + /// + /// Stream to parse + /// Filled Header on success, null on error + public static Header? ParseHeader(Stream data) + { + var obj = new Header(); + + byte[] filenameBytes = data.ReadBytes(100); + obj.FileName = Encoding.ASCII.GetString(filenameBytes); + obj.Mode = data.ReadBytes(8); + obj.UID = data.ReadBytes(8); + obj.GID = data.ReadBytes(8); + obj.Size = data.ReadBytes(12); + obj.ModifiedTime = data.ReadBytes(12); + obj.Checksum = data.ReadBytes(8); + obj.TypeFlag = (TypeFlag)data.ReadByteValue(); + byte[] linkNameBytes = data.ReadBytes(100); + obj.LinkName = Encoding.ASCII.GetString(linkNameBytes); + + // If end of stream has been reached + if (data.Position >= data.Length) + return obj; + + // Peek at the next 6 bytes + byte[] temp = data.ReadBytes(6); + string tempString = Encoding.ASCII.GetString(temp); + data.Seek(-6, SeekOrigin.Current); + if (tempString != "ustar\0") + return obj; + + byte[] magicBytes = data.ReadBytes(6); + obj.Magic = Encoding.ASCII.GetString(magicBytes); + byte[] versionBytes = data.ReadBytes(3); + obj.Version = Encoding.ASCII.GetString(versionBytes); + byte[] userNameBytes = data.ReadBytes(32); + obj.UserName = Encoding.ASCII.GetString(userNameBytes); + byte[] groupNameBytes = data.ReadBytes(32); + obj.GroupName = Encoding.ASCII.GetString(groupNameBytes); + byte[] devMajorBytes = data.ReadBytes(8); + obj.DevMajor = Encoding.ASCII.GetString(devMajorBytes); + byte[] devMinorBytes = data.ReadBytes(8); + obj.DevMinor = Encoding.ASCII.GetString(devMinorBytes); + byte[] prefixBytes = data.ReadBytes(155); + obj.Prefix = Encoding.ASCII.GetString(prefixBytes); + + return obj; + } } }