mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-07-09 02:16:55 +00:00
Fix tar parsing and printing
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
@@ -65,19 +66,38 @@ namespace SabreTools.Serialization.Deserializers
|
||||
|
||||
obj.Header = header;
|
||||
|
||||
// TODO: Replace this with AlignToBoundary when IO is updated
|
||||
// Align to the block size
|
||||
while (data.Position % 512 != 0 && data.Position < data.Length)
|
||||
{
|
||||
_ = data.ReadByteValue();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Blocks
|
||||
|
||||
List<Block> blocks = [];
|
||||
// Exit if the size is invalid
|
||||
string sizeOctalString = Encoding.ASCII.GetString(header.Size!).TrimEnd('\0');
|
||||
if (sizeOctalString.Length == 0)
|
||||
return obj;
|
||||
|
||||
// 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.
|
||||
// Get the block count from the size
|
||||
int octalSize = Convert.ToInt32(sizeOctalString, 8);
|
||||
int blockCount = (int)Math.Ceiling((decimal)octalSize / 512);
|
||||
|
||||
// Read all blocks sequentially
|
||||
var blocks = new Block[blockCount];
|
||||
for (int i = 0; i < blocks.Length; i++)
|
||||
{
|
||||
var block = ParseBlock(data);
|
||||
if (block == null)
|
||||
break;
|
||||
|
||||
blocks[i] = block;
|
||||
}
|
||||
|
||||
// TODO: Make this a direct assignment when Models is updated
|
||||
obj.Blocks = [.. blocks];
|
||||
|
||||
#endregion
|
||||
@@ -110,14 +130,14 @@ namespace SabreTools.Serialization.Deserializers
|
||||
if (data.Position >= data.Length)
|
||||
return obj;
|
||||
|
||||
// Peek at the next 6 bytes
|
||||
byte[] temp = data.ReadBytes(6);
|
||||
// Peek at the next 5 bytes
|
||||
byte[] temp = data.ReadBytes(5);
|
||||
string tempString = Encoding.ASCII.GetString(temp);
|
||||
data.Seek(-6, SeekOrigin.Current);
|
||||
if (tempString != "ustar\0")
|
||||
data.Seek(-5, SeekOrigin.Current);
|
||||
if (tempString != "ustar")
|
||||
return obj;
|
||||
|
||||
byte[] magicBytes = data.ReadBytes(6);
|
||||
byte[] magicBytes = data.ReadBytes(5);
|
||||
obj.Magic = Encoding.ASCII.GetString(magicBytes);
|
||||
byte[] versionBytes = data.ReadBytes(3);
|
||||
obj.Version = Encoding.ASCII.GetString(versionBytes);
|
||||
@@ -134,5 +154,24 @@ namespace SabreTools.Serialization.Deserializers
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a Block
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled Block on success, null on error</returns>
|
||||
public static Block? ParseBlock(Stream data)
|
||||
{
|
||||
// Handle incomplete blocks
|
||||
if (data.Position + 512 >= data.Length)
|
||||
return null;
|
||||
|
||||
var obj = new Block();
|
||||
|
||||
// TODO: Assign this to obj.Data when Models is updated
|
||||
_ = data.ReadBytes(512);
|
||||
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ namespace SabreTools.Serialization
|
||||
Wrapper.CHD item => item.PrettyPrint(),
|
||||
Wrapper.CIA item => item.PrettyPrint(),
|
||||
Wrapper.GCF item => item.PrettyPrint(),
|
||||
Wrapper.GZip item => item.PrettyPrint(),
|
||||
Wrapper.InstallShieldArchiveV3 item => item.PrettyPrint(),
|
||||
Wrapper.InstallShieldCabinet item => item.PrettyPrint(),
|
||||
Wrapper.IRD item => item.PrettyPrint(),
|
||||
@@ -66,6 +67,7 @@ namespace SabreTools.Serialization
|
||||
Wrapper.Quantum item => item.PrettyPrint(),
|
||||
Wrapper.SecuROMDFA item => item.PrettyPrint(),
|
||||
Wrapper.SGA item => item.PrettyPrint(),
|
||||
Wrapper.TapeArchive item => item.PrettyPrint(),
|
||||
Wrapper.VBSP item => item.PrettyPrint(),
|
||||
Wrapper.VPK item => item.PrettyPrint(),
|
||||
Wrapper.WAD3 item => item.PrettyPrint(),
|
||||
@@ -92,6 +94,7 @@ namespace SabreTools.Serialization
|
||||
Wrapper.CHD item => item.ExportJSON(),
|
||||
Wrapper.CIA item => item.ExportJSON(),
|
||||
Wrapper.GCF item => item.ExportJSON(),
|
||||
Wrapper.GZip item => item.ExportJSON(),
|
||||
Wrapper.InstallShieldArchiveV3 item => item.ExportJSON(),
|
||||
Wrapper.InstallShieldCabinet item => item.ExportJSON(),
|
||||
Wrapper.IRD item => item.ExportJSON(),
|
||||
@@ -116,6 +119,7 @@ namespace SabreTools.Serialization
|
||||
Wrapper.Quantum item => item.ExportJSON(),
|
||||
Wrapper.SecuROMDFA item => item.ExportJSON(),
|
||||
Wrapper.SGA item => item.ExportJSON(),
|
||||
Wrapper.TapeArchive item => item.ExportJSON(),
|
||||
Wrapper.VBSP item => item.ExportJSON(),
|
||||
Wrapper.VPK item => item.ExportJSON(),
|
||||
Wrapper.WAD3 item => item.ExportJSON(),
|
||||
@@ -209,6 +213,16 @@ namespace SabreTools.Serialization
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Export the item information as pretty-printed text
|
||||
/// </summary>
|
||||
private static StringBuilder PrettyPrint(this Wrapper.GZip item)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
GZip.Print(builder, item.Model);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Export the item information as pretty-printed text
|
||||
/// </summary>
|
||||
@@ -449,6 +463,16 @@ namespace SabreTools.Serialization
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Export the item information as pretty-printed text
|
||||
/// </summary>
|
||||
private static StringBuilder PrettyPrint(this Wrapper.TapeArchive item)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
TapeArchive.Print(builder, item.Model);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Export the item information as pretty-printed text
|
||||
/// </summary>
|
||||
|
||||
22
SabreTools.Serialization/Printers/GZip.cs
Normal file
22
SabreTools.Serialization/Printers/GZip.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System.Text;
|
||||
using SabreTools.Models.GZIP;
|
||||
using SabreTools.Serialization.Interfaces;
|
||||
|
||||
namespace SabreTools.Serialization.Printers
|
||||
{
|
||||
public class GZip : IPrinter<Archive>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public void PrintInformation(StringBuilder builder, Archive model)
|
||||
=> Print(builder, model);
|
||||
|
||||
public static void Print(StringBuilder builder, Archive file)
|
||||
{
|
||||
builder.AppendLine("gzip Information:");
|
||||
builder.AppendLine("-------------------------");
|
||||
builder.AppendLine();
|
||||
|
||||
// TODO: Implement
|
||||
}
|
||||
}
|
||||
}
|
||||
72
SabreTools.Serialization/Printers/TapeArchive.cs
Normal file
72
SabreTools.Serialization/Printers/TapeArchive.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using SabreTools.Models.TAR;
|
||||
using SabreTools.Serialization.Interfaces;
|
||||
|
||||
namespace SabreTools.Serialization.Printers
|
||||
{
|
||||
public class TapeArchive : IPrinter<Archive>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public void PrintInformation(StringBuilder builder, Archive model)
|
||||
=> Print(builder, model);
|
||||
|
||||
public static void Print(StringBuilder builder, Archive file)
|
||||
{
|
||||
builder.AppendLine("Tape Archive Information:");
|
||||
builder.AppendLine("-------------------------");
|
||||
builder.AppendLine();
|
||||
|
||||
Print(builder, file.Entries);
|
||||
}
|
||||
|
||||
// TODO: Fix the entry type when Models is updated
|
||||
//private static void Print(StringBuilder builder, Entry[]? entries)
|
||||
private static void Print(StringBuilder builder, List<Entry>? entries)
|
||||
{
|
||||
builder.AppendLine(" Entries Information:");
|
||||
builder.AppendLine(" -------------------------");
|
||||
if (entries == null || entries.Count == 0)
|
||||
{
|
||||
builder.AppendLine(" No entries");
|
||||
builder.AppendLine();
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < entries.Count; i++)
|
||||
{
|
||||
var entry = entries[i];
|
||||
|
||||
builder.AppendLine($" Entry {i}");
|
||||
|
||||
var header = entry.Header;
|
||||
if (header == null)
|
||||
{
|
||||
builder.AppendLine(" Header: [NULL]");
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AppendLine(" Header:");
|
||||
builder.AppendLine(header.FileName?.TrimEnd('\0'), " File name");
|
||||
builder.AppendLine(header.Mode, " Mode");
|
||||
builder.AppendLine(header.UID, " UID");
|
||||
builder.AppendLine(header.GID, " GID");
|
||||
builder.AppendLine(header.Size, " Size");
|
||||
builder.AppendLine(header.ModifiedTime, " Modified time");
|
||||
builder.AppendLine(header.Checksum, " Checksum");
|
||||
builder.AppendLine($" Type flag: {header.TypeFlag} (0x{(byte)header.TypeFlag:X2})");
|
||||
builder.AppendLine(header.LinkName?.TrimEnd('\0'), " Link name");
|
||||
builder.AppendLine(header.Magic, " Magic");
|
||||
builder.AppendLine(header.Version?.TrimEnd('\0'), " Version");
|
||||
builder.AppendLine(header.UserName?.TrimEnd('\0'), " User name");
|
||||
builder.AppendLine(header.GroupName?.TrimEnd('\0'), " Group name");
|
||||
builder.AppendLine(header.DevMajor?.TrimEnd('\0'), " Device major");
|
||||
builder.AppendLine(header.DevMinor?.TrimEnd('\0'), " Device minor");
|
||||
builder.AppendLine(header.Prefix?.TrimEnd('\0'), " Prefix");
|
||||
}
|
||||
}
|
||||
|
||||
builder.AppendLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -666,7 +666,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
return WrapperType.TapeArchive;
|
||||
|
||||
if (extension.Equals("tar", StringComparison.OrdinalIgnoreCase))
|
||||
return WrapperType.SevenZip;
|
||||
return WrapperType.TapeArchive;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
Reference in New Issue
Block a user