Add SecuROM DFA

This commit is contained in:
Matt Nadareski
2025-07-24 10:40:31 -04:00
parent 2bf3d6f9a6
commit b6561719a7
6 changed files with 243 additions and 0 deletions

View File

@@ -0,0 +1,80 @@
using System.Collections.Generic;
using System.IO;
using System.Text;
using SabreTools.IO.Extensions;
using SabreTools.Matching;
using SabreTools.Models.SecuROM;
using static SabreTools.Models.SecuROM.Constants;
namespace SabreTools.Serialization.Deserializers
{
public class SecuROMDFA : BaseBinaryDeserializer<DFAFile>
{
/// <inheritdoc/>
public override DFAFile? Deserialize(Stream? data)
{
// If the data is invalid
if (data == null || !data.CanRead)
return null;
try
{
// Create a new file to fill
var dfa = new DFAFile();
#region Header
// Try to parse the header
dfa.Signature = data.ReadBytes(8);
if (!dfa.Signature.EqualsExactly(DFAMagicBytes))
return null;
dfa.BlockOrHeaderSize = data.ReadUInt32();
#endregion
#region Entries
// If we have any entries
List<DFAEntry> entries = [];
// Read entries while there is data
while (data.Position < data.Length)
{
var entry = ParseDFAEntry(data);
entries.Add(entry);
}
// Set the entries list
dfa.Entries = [.. entries];
#endregion
return dfa;
}
catch
{
// Ignore the actual error
return null;
}
}
/// <summary>
/// Parse a Stream into a DFAEntry
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled DFAEntry on success, null on error</returns>
public static DFAEntry ParseDFAEntry(Stream data)
{
var obj = new DFAEntry();
byte[] name = data.ReadBytes(4);
obj.Name = Encoding.ASCII.GetString(name);
obj.Length = data.ReadUInt32();
if (obj.Length > 0)
obj.Value = data.ReadBytes((int)obj.Length);
return obj;
}
}
}

View File

@@ -64,6 +64,7 @@ namespace SabreTools.Serialization
Wrapper.PlayJPlaylist item => item.PrettyPrint(),
Wrapper.PortableExecutable item => item.PrettyPrint(),
Wrapper.Quantum item => item.PrettyPrint(),
Wrapper.SecuROMDFA item => item.PrettyPrint(),
Wrapper.SGA item => item.PrettyPrint(),
Wrapper.VBSP item => item.PrettyPrint(),
Wrapper.VPK item => item.PrettyPrint(),
@@ -113,6 +114,7 @@ namespace SabreTools.Serialization
Wrapper.PlayJPlaylist item => item.ExportJSON(),
Wrapper.PortableExecutable item => item.ExportJSON(),
Wrapper.Quantum item => item.ExportJSON(),
Wrapper.SecuROMDFA item => item.ExportJSON(),
Wrapper.SGA item => item.ExportJSON(),
Wrapper.VBSP item => item.ExportJSON(),
Wrapper.VPK item => item.ExportJSON(),
@@ -427,6 +429,16 @@ namespace SabreTools.Serialization
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.SecuROMDFA item)
{
var builder = new StringBuilder();
SecuROMDFA.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>

View File

@@ -0,0 +1,59 @@
using System.Text;
using SabreTools.Models.SecuROM;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Printers
{
public class SecuROMDFA : IPrinter<DFAFile>
{
/// <inheritdoc/>
public void PrintInformation(StringBuilder builder, DFAFile model)
=> Print(builder, model);
public static void Print(StringBuilder builder, DFAFile dfaFile)
{
builder.AppendLine("SecuROM DFA File Information:");
builder.AppendLine("-------------------------");
builder.AppendLine(dfaFile.Signature, "Signature");
builder.AppendLine(dfaFile.BlockOrHeaderSize, "Block or header size");
builder.AppendLine();
Print(builder, dfaFile.Entries);
}
private static void Print(StringBuilder builder, DFAEntry[]? entries)
{
builder.AppendLine(" Entries Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
Print(builder, entry, i);
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, DFAEntry? entry, int index)
{
builder.AppendLine($" Entry {index}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
return;
}
builder.AppendLine(entry.Name, " Name");
builder.AppendLine(entry.Length, " Length");
builder.AppendLine(entry.Value, " Value");
}
}
}

View File

@@ -0,0 +1,79 @@
using System.IO;
using SabreTools.Models.SecuROM;
namespace SabreTools.Serialization.Wrappers
{
public class SecuROMDFA : WrapperBase<DFAFile>
{
#region Descriptive Properties
/// <inheritdoc/>
public override string DescriptionString => "SecuROM DFA File";
#endregion
#region Constructors
/// <inheritdoc/>
public SecuROMDFA(DFAFile? model, byte[]? data, int offset)
: base(model, data, offset)
{
// All logic is handled by the base class
}
/// <inheritdoc/>
public SecuROMDFA(DFAFile? model, Stream? data)
: base(model, data)
{
// All logic is handled by the base class
}
/// <summary>
/// Create a SecuROM DFA file from a byte array and offset
/// </summary>
/// <param name="data">Byte array representing the archive</param>
/// <param name="offset">Offset within the array to parse</param>
/// <returns>A SecuROM DFA file wrapper on success, null on failure</returns>
public static SecuROMDFA? 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);
}
/// <summary>
/// Create a SecuROM DFA file from a Stream
/// </summary>
/// <param name="data">Stream representing the archive</param>
/// <returns>A SecuROM DFA file wrapper on success, null on failure</returns>
public static SecuROMDFA? Create(Stream? data)
{
// If the data is invalid
if (data == null || !data.CanRead)
return null;
try
{
var file = Deserializers.SecuROMDFA.DeserializeStream(data);
if (file == null)
return null;
return new SecuROMDFA(file, data);
}
catch
{
return null;
}
}
#endregion
}
}

View File

@@ -49,6 +49,7 @@ namespace SabreTools.Serialization.Wrappers
WrapperType.RAR => null,// TODO: Implement wrapper
WrapperType.RealArcadeInstaller => null,// TODO: Implement wrapper
WrapperType.RealArcadeMezzanine => null,// TODO: Implement wrapper
WrapperType.SecuROMDFA => SecuROMDFA.Create(data),
WrapperType.SevenZip => null,// TODO: Implement wrapper
WrapperType.SFFS => null,// TODO: Implement wrapper
WrapperType.SGA => SGA.Create(data),
@@ -616,6 +617,13 @@ namespace SabreTools.Serialization.Wrappers
#endregion
#region SecuROM DFA
if (magic.StartsWith(Models.SecuROM.Constants.DFAMagicBytes))
return WrapperType.SecuROMDFA;
#endregion
// TODO: Use constants from Models here
#region SevenZip

View File

@@ -185,6 +185,11 @@ namespace SabreTools.Serialization.Wrappers
/// <remarks>Currently has no IWrapper implementation</remarks>
RealArcadeMezzanine,
/// <summary>
/// SecuROM DFA File
/// </summary>
SecuROMDFA,
/// <summary>
/// 7-zip archive
/// </summary>