mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-09-21 22:35:06 +00:00
Minor cleanup to previous commit
This commit is contained in:
@@ -10,6 +10,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
public class SecuROMMatroschkaPackage : BaseBinaryDeserializer<MatroshkaPackage>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
/// TODO: Unify matroschka spelling to "Matroschka"
|
||||
public override MatroshkaPackage? Deserialize(Stream? data)
|
||||
{
|
||||
// If the data is invalid
|
||||
@@ -20,18 +21,15 @@ namespace SabreTools.Serialization.Deserializers
|
||||
{
|
||||
// Cache the initial offset
|
||||
long initialOffset = data.Position;
|
||||
|
||||
// TODO: Unify matroschka spelling. They spell it matroschka in all official stuff, as far as has been observed. Will double check.
|
||||
|
||||
// Try to parse the header
|
||||
var package = ParsePreEntryHeader(data);
|
||||
var package = ParseMatroshkaPackage(data);
|
||||
if (package == null)
|
||||
return null;
|
||||
|
||||
var entries = ParseEntries(data, package);
|
||||
if (entries == null)
|
||||
return null;
|
||||
|
||||
package.Entries = entries;
|
||||
// Try to parse the entries
|
||||
package.Entries = ParseEntries(data, package.EntryCount);
|
||||
|
||||
return package;
|
||||
}
|
||||
catch
|
||||
@@ -41,10 +39,15 @@ namespace SabreTools.Serialization.Deserializers
|
||||
}
|
||||
}
|
||||
|
||||
private static MatroshkaPackage? ParsePreEntryHeader(Stream data)
|
||||
{
|
||||
/// <summary>
|
||||
/// Parse a Stream into a MatroshkaPackage
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled MatroshkaPackage on success, null on error</returns>
|
||||
public static MatroshkaPackage? ParseMatroshkaPackage(Stream data)
|
||||
{
|
||||
var obj = new MatroshkaPackage();
|
||||
|
||||
|
||||
byte[] magic = data.ReadBytes(4);
|
||||
obj.Signature = Encoding.ASCII.GetString(magic);
|
||||
if (obj.Signature != MatroshkaMagicString)
|
||||
@@ -62,88 +65,74 @@ namespace SabreTools.Serialization.Deserializers
|
||||
uint tempValue = data.ReadUInt32LittleEndian();
|
||||
data.Seek(tempPosition, SeekOrigin.Begin);
|
||||
|
||||
if (tempValue < 2) // Only little-endian 0 or 1 have been observed for long sections.
|
||||
// Only 0 or 1 have been observed for long sections
|
||||
if (tempValue < 2)
|
||||
{
|
||||
obj.UnknownRCValue1 = data.ReadUInt32LittleEndian();
|
||||
obj.UnknownRCValue2 = data.ReadUInt32LittleEndian();
|
||||
obj.UnknownRCValue3 = data.ReadUInt32LittleEndian();
|
||||
|
||||
// Exact byte count has to be used because non-RC executables have all 0x00 here.
|
||||
var keyHexBytes = data.ReadBytes(32);
|
||||
obj.KeyHexString = Encoding.ASCII.GetString(keyHexBytes);
|
||||
if (!data.ReadBytes(4).EqualsExactly([0x00, 0x00, 0x00, 0x00]))
|
||||
return null;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static MatroshkaEntry[]? ParseEntries(Stream data, MatroshkaPackage package)
|
||||
/// <summary>
|
||||
/// Parse a Stream into a MatroshkaEntry array
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <param name="entryCount">Number of entries in the array</param>
|
||||
/// <returns>Filled MatroshkaEntry array on success, null on error</returns>
|
||||
private static MatroshkaEntry[] ParseEntries(Stream data, uint entryCount)
|
||||
{
|
||||
|
||||
// If we have any entries
|
||||
var obj = new MatroshkaEntry[package.EntryCount];
|
||||
var obj = new MatroshkaEntry[entryCount];
|
||||
|
||||
int matGapType = 0;
|
||||
bool? matHasUnknown = null;
|
||||
|
||||
// Read entries
|
||||
for (int i = 0; i < obj.Length; i++)
|
||||
{
|
||||
var entry = new MatroshkaEntry();
|
||||
// Determine if file path size is 256 or 512 bytes
|
||||
if (matGapType == 0)
|
||||
matGapType = GapHelper(data);
|
||||
|
||||
// TODO: Spaces/non-ASCII have not yet been observed. Still, probably safer to store as byte array?
|
||||
// TODO: Read as string and trim once models is bumped. For now, this needs to be trimmed by anything reading it.
|
||||
entry.Path = data.ReadBytes((int)matGapType);
|
||||
|
||||
// Entry type isn't currently validated as it's always predictable anyways, nor necessary to know.
|
||||
entry.EntryType = (MatroshkaEntryType)data.ReadUInt32LittleEndian();
|
||||
entry.Size = data.ReadUInt32LittleEndian();
|
||||
entry.Offset = data.ReadUInt32LittleEndian();
|
||||
|
||||
// Check for unknown 4-byte 0x00 value. Not correlated with 256 vs 512-byte gaps.
|
||||
if (matHasUnknown == null)
|
||||
matHasUnknown = UnknownHelper(data, entry);
|
||||
|
||||
if (matHasUnknown == true) // If already known, read or don't read the unknown value.
|
||||
entry.Unknown = data.ReadUInt32LittleEndian(); // TODO: Validate it's zero?
|
||||
|
||||
entry.ModifiedTime = data.ReadUInt64LittleEndian();
|
||||
entry.CreatedTime = data.ReadUInt64LittleEndian();
|
||||
entry.AccessedTime = data.ReadUInt64LittleEndian();
|
||||
entry.MD5 = data.ReadBytes(16);
|
||||
|
||||
obj[i] = entry;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static int GapHelper(Stream data)
|
||||
{
|
||||
var tempPosition = data.Position;
|
||||
// Determine if file path size is 256 or 512 bytes
|
||||
long tempPosition = data.Position;
|
||||
data.Seek(data.Position + 256, SeekOrigin.Begin);
|
||||
var tempValue = data.ReadUInt32LittleEndian();
|
||||
data.Seek(tempPosition, SeekOrigin.Begin);
|
||||
if (tempValue <= 0) // Gap is 512 bytes. Actually just == 0, but ST prefers ranges.
|
||||
return 512;
|
||||
|
||||
// Otherwise, gap is 256 bytes.
|
||||
return 256;
|
||||
}
|
||||
|
||||
private static bool UnknownHelper(Stream data, MatroshkaEntry entry)
|
||||
{
|
||||
var tempPosition = data.Position;
|
||||
var tempValue = data.ReadUInt32LittleEndian();
|
||||
data.Seek(tempPosition, SeekOrigin.Begin);
|
||||
if (tempValue > 0) // Entry does not have the Unknown value.
|
||||
return false;
|
||||
int gapSize = tempValue == 0 ? 512 : 256;
|
||||
|
||||
// Entry does have the unknown value.
|
||||
return true;
|
||||
// Set default value for unknown value checking
|
||||
bool? hasUnknown = null;
|
||||
|
||||
// Read entries
|
||||
for (int i = 0; i < obj.Length; i++)
|
||||
{
|
||||
var entry = new MatroshkaEntry();
|
||||
|
||||
entry.Path = data.ReadBytes(gapSize);
|
||||
entry.EntryType = (MatroshkaEntryType)data.ReadUInt32LittleEndian();
|
||||
entry.Size = data.ReadUInt32LittleEndian();
|
||||
entry.Offset = data.ReadUInt32LittleEndian();
|
||||
|
||||
// On the first entry, determine if the unknown value exists
|
||||
if (hasUnknown == null)
|
||||
{
|
||||
tempPosition = data.Position;
|
||||
tempValue = data.ReadUInt32LittleEndian();
|
||||
data.Seek(tempPosition, SeekOrigin.Begin);
|
||||
hasUnknown = tempValue == 0;
|
||||
}
|
||||
|
||||
// TODO: Validate it's zero?
|
||||
if (hasUnknown == true)
|
||||
entry.Unknown = data.ReadUInt32LittleEndian();
|
||||
|
||||
entry.ModifiedTime = data.ReadUInt64LittleEndian();
|
||||
entry.CreatedTime = data.ReadUInt64LittleEndian();
|
||||
entry.AccessedTime = data.ReadUInt64LittleEndian();
|
||||
entry.MD5 = data.ReadBytes(16);
|
||||
|
||||
obj[i] = entry;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
/// - Archives and executables in the overlay
|
||||
/// - Archives and executables in resource data
|
||||
/// - CExe-compressed resource data
|
||||
/// - SecuROM Matroschka package sections
|
||||
/// - SFX archives (7z, MS-CAB, PKZIP, RAR)
|
||||
/// - Wise installers
|
||||
/// </remarks>
|
||||
|
||||
@@ -184,7 +184,10 @@ namespace SabreTools.Serialization.Wrappers
|
||||
|
||||
/// <inheritdoc cref="Executable.ImportTable"/>
|
||||
public ImportTable? ImportTable => Model.ImportTable;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// SecuROM Matroschka package wrapper, if it exists
|
||||
/// </summary>
|
||||
public SecuROMMatroschkaPackage? MatroschkaPackage
|
||||
{
|
||||
get
|
||||
@@ -194,11 +197,11 @@ namespace SabreTools.Serialization.Wrappers
|
||||
// Use the cached data if possible
|
||||
if (_matroschkaPackage != null)
|
||||
return _matroschkaPackage;
|
||||
|
||||
|
||||
// Check to see if creation has already been attempted
|
||||
if (_matroschkaPackageFailed)
|
||||
return null;
|
||||
|
||||
|
||||
// Get the available source length, if possible
|
||||
var dataLength = Length;
|
||||
if (dataLength == -1)
|
||||
@@ -213,10 +216,9 @@ namespace SabreTools.Serialization.Wrappers
|
||||
_matroschkaPackageFailed = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
SectionHeader? section = null;
|
||||
|
||||
|
||||
// Find the matrosch or rcpacker section
|
||||
SectionHeader? section = null;
|
||||
foreach (var searchedSection in SectionTable)
|
||||
{
|
||||
string sectionName = Encoding.ASCII.GetString(searchedSection.Name ?? []).TrimEnd('\0');
|
||||
@@ -233,31 +235,29 @@ namespace SabreTools.Serialization.Wrappers
|
||||
_matroschkaPackageFailed = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// Get the offset
|
||||
long offset = section.VirtualAddress.ConvertVirtualAddress(SectionTable);
|
||||
if (offset < 0 || offset >= Length)
|
||||
{
|
||||
_matroschkaPackageFailed = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Read the section into a local array
|
||||
var sectionLength = (int)section.VirtualSize;
|
||||
var sectionData = ReadRangeFromSource(offset, sectionLength);
|
||||
|
||||
// Parse the section header
|
||||
var header = SecuROMMatroschkaPackage.Create(sectionData, 0);
|
||||
|
||||
// If header creation failed, or if Entries does not exist
|
||||
if (header?.Entries == null)
|
||||
if (sectionData.Length == 0)
|
||||
{
|
||||
_matroschkaPackageFailed = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
// Otherwise, cache and return the data
|
||||
_matroschkaPackage = header;
|
||||
// Parse the package
|
||||
_matroschkaPackage = SecuROMMatroschkaPackage.Create(sectionData, 0);
|
||||
if (_matroschkaPackage?.Entries == null)
|
||||
_matroschkaPackageFailed = true;
|
||||
|
||||
return _matroschkaPackage;
|
||||
}
|
||||
}
|
||||
@@ -622,7 +622,12 @@ namespace SabreTools.Serialization.Wrappers
|
||||
|
||||
// Read the section into a local array
|
||||
int sectionLength = (int)wiseSection.VirtualSize;
|
||||
byte[]? sectionData = ReadRangeFromSource(offset, sectionLength);
|
||||
byte[] sectionData = ReadRangeFromSource(offset, sectionLength);
|
||||
if (sectionData.Length == 0)
|
||||
{
|
||||
_wiseSectionHeaderMissing = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
// Parse the section header
|
||||
_wiseSectionHeader = WiseSectionHeader.Create(sectionData, 0);
|
||||
@@ -862,7 +867,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
/// Lock object for <see cref="_headerPaddingStrings"/>
|
||||
/// </summary>
|
||||
private readonly object _headerPaddingStringsLock = new();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Matroschka Package wrapper, if it exists
|
||||
/// </summary>
|
||||
@@ -872,12 +877,12 @@ namespace SabreTools.Serialization.Wrappers
|
||||
/// Lock object for <see cref="_matroschkaPackage"/>
|
||||
/// </summary>
|
||||
private readonly object _matroschkaPackageLock = new();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Cached attempt at creation for <see cref="_matroschkaPackage"/>
|
||||
/// </summary>
|
||||
private bool _matroschkaPackageFailed = false;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Address of the overlay, if it exists
|
||||
/// </summary>
|
||||
@@ -1619,30 +1624,6 @@ namespace SabreTools.Serialization.Wrappers
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the location of a SecuROM Matroschka section, if it exists
|
||||
/// </summary>
|
||||
/// <returns>Matroschka section on success, null otherwise</returns>
|
||||
public Models.PortableExecutable.SectionHeader? FindMatroschkaSection()
|
||||
{
|
||||
// If the section table is invalid
|
||||
if (SectionTable == null)
|
||||
return null;
|
||||
|
||||
// Find the matrosch or rcpacker section
|
||||
foreach (var section in SectionTable)
|
||||
{
|
||||
var sectionName = Encoding.ASCII.GetString(section.Name ?? []).TrimEnd('\0');
|
||||
if (sectionName != "matrosch" && sectionName != "rcpacker")
|
||||
continue;
|
||||
|
||||
return section;
|
||||
}
|
||||
|
||||
// Otherwise, it could not be found
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Resource Parsing
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.Hashing;
|
||||
using SabreTools.Models.SecuROM;
|
||||
using SabreTools.Serialization.Interfaces;
|
||||
@@ -11,59 +12,44 @@ namespace SabreTools.Serialization.Wrappers
|
||||
/// <inheritdoc/>
|
||||
public bool Extract(string outputDirectory, bool includeDebug)
|
||||
{
|
||||
// Extract the packaged files
|
||||
var extracted = ExtractPackagedFiles(outputDirectory, includeDebug);
|
||||
if (!extracted)
|
||||
{
|
||||
if (includeDebug) Console.Error.WriteLine("Could not extract packaged files");
|
||||
// If we have no entries
|
||||
if (Entries == null || Entries.Length == 0)
|
||||
return false;
|
||||
|
||||
// Loop through and extract all files to the output
|
||||
bool allExtracted = true;
|
||||
for (var i = 0; i < Entries.Length; i++)
|
||||
{
|
||||
allExtracted &= ExtractFile(i, outputDirectory, includeDebug);
|
||||
}
|
||||
|
||||
return true;
|
||||
return allExtracted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract the packaged files.
|
||||
/// Extract a file from the package to an output directory by index
|
||||
/// </summary>
|
||||
/// <param name="index">File index to extract</param>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>True if the files extracted successfully, false otherwise</returns>
|
||||
private bool ExtractPackagedFiles(string outputDirectory, bool includeDebug)
|
||||
/// <returns>True if the file extracted, false otherwise</returns>
|
||||
public bool ExtractFile(int index, string outputDirectory, bool includeDebug)
|
||||
{
|
||||
if (Entries == null)
|
||||
return false;
|
||||
|
||||
var successful = true;
|
||||
// If we have no entries
|
||||
if (Entries == null || Entries.Length == 0)
|
||||
return false;
|
||||
|
||||
// Extract entries
|
||||
for (var i = 0; i < Entries.Length; i++)
|
||||
{
|
||||
var entry = Entries[i];
|
||||
|
||||
// Extract file
|
||||
if (!ExtractFile(entry, outputDirectory, includeDebug))
|
||||
successful = false;
|
||||
}
|
||||
|
||||
return successful;
|
||||
}
|
||||
// If the entry index is invalid
|
||||
if (index < 0 || index >= Entries.Length)
|
||||
return false;
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to extract a file
|
||||
/// </summary>
|
||||
/// <param name="entry">Matroschka file entry being extracted</param>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>Boolean representing true on success or false on failure</returns>
|
||||
/// <remarks>Assumes that the current stream position is the end of where the data lives</remarks>
|
||||
private bool ExtractFile(MatroshkaEntry entry, string outputDirectory, bool includeDebug)
|
||||
{
|
||||
// Get the entry
|
||||
var entry = Entries[index];
|
||||
if (entry.Path == null)
|
||||
return false;
|
||||
|
||||
var filename = System.Text.Encoding.ASCII.GetString(entry.Path).TrimEnd('\0');
|
||||
|
||||
// Ensure directory separators are consistent
|
||||
string filename = Encoding.ASCII.GetString(entry.Path).TrimEnd('\0');
|
||||
if (Path.DirectorySeparatorChar == '\\')
|
||||
filename = filename.Replace('/', '\\');
|
||||
else if (Path.DirectorySeparatorChar == '/')
|
||||
@@ -72,9 +58,8 @@ namespace SabreTools.Serialization.Wrappers
|
||||
if (includeDebug) Console.WriteLine($"Attempting to extract {filename}");
|
||||
|
||||
// Read the file
|
||||
var fileData = ReadFile(entry, includeDebug);
|
||||
|
||||
if (fileData == null)
|
||||
var data = ReadFile(entry, includeDebug);
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
// Ensure the full output directory exists
|
||||
@@ -83,47 +68,63 @@ namespace SabreTools.Serialization.Wrappers
|
||||
if (directoryName != null && !Directory.Exists(directoryName))
|
||||
Directory.CreateDirectory(directoryName);
|
||||
|
||||
// Write the output file
|
||||
File.WriteAllBytes(filename, fileData);
|
||||
// Try to write the data
|
||||
try
|
||||
{
|
||||
// Open the output file for writing
|
||||
using Stream fs = File.OpenWrite(filename);
|
||||
fs.Write(data, 0, data.Length);
|
||||
fs.Flush();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.Error.WriteLine(ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read file and check bytes to be extracted against MD5 checksum.
|
||||
/// Read file and check bytes to be extracted against MD5 checksum
|
||||
/// </summary>
|
||||
/// <param name="entry">Entry being extracted</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>Byte array of the file data if successful, null if unsuccessful.</returns>
|
||||
public byte[]? ReadFile(MatroshkaEntry entry, bool includeDebug)
|
||||
/// <returns>Byte array of the file data if successful, null otherwise</returns>
|
||||
private byte[]? ReadFile(MatroshkaEntry entry, bool includeDebug)
|
||||
{
|
||||
var fileData = ReadRangeFromSource(entry.Offset, (int)entry.Size); // TODO: safety? validation? anything?
|
||||
// Debug output
|
||||
if (includeDebug) Console.WriteLine($"Offset: {entry.Offset:X8}, Expected Size: {entry.Size}");
|
||||
// Skip if the entry is incomplete
|
||||
if (entry.Path == null || entry.MD5 == null)
|
||||
return null;
|
||||
|
||||
string expectedMd5 = BitConverter.ToString(entry.MD5!);
|
||||
// Cache the expected MD5
|
||||
string expectedMd5 = BitConverter.ToString(entry.MD5);
|
||||
expectedMd5 = expectedMd5.ToLowerInvariant().Replace("-", string.Empty);
|
||||
|
||||
// Debug output
|
||||
if (includeDebug) Console.WriteLine($"Expected MD5: {expectedMd5}");
|
||||
if (includeDebug) Console.WriteLine($"Offset: {entry.Offset:X8}, Expected Size: {entry.Size}, Expected MD5: {expectedMd5}");
|
||||
|
||||
if (fileData == null)
|
||||
return null;
|
||||
|
||||
var hashBytes = HashTool.GetByteArrayHashArray(fileData, HashType.MD5);
|
||||
|
||||
string actualMd5 = BitConverter.ToString(hashBytes!);
|
||||
actualMd5 = actualMd5.ToLowerInvariant().Replace("-", string.Empty);
|
||||
|
||||
// Debug output
|
||||
if (includeDebug) Console.WriteLine($"Actual MD5: {actualMd5}");
|
||||
|
||||
if (hashBytes == null || actualMd5 != expectedMd5)
|
||||
// Attempt to read from the offset
|
||||
var fileData = ReadRangeFromSource(entry.Offset, (int)entry.Size);
|
||||
if (fileData.Length == 0)
|
||||
{
|
||||
var filename = System.Text.Encoding.ASCII.GetString(entry.Path!).TrimEnd('\0');
|
||||
Console.Error.WriteLine($"MD5 checksum failure for file {filename})");
|
||||
if (includeDebug) Console.Error.WriteLine($"Could not read {entry.Size} bytes from {entry.Offset:X8}");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get the actual MD5 of the data
|
||||
string actualMd5 = HashTool.GetByteArrayHash(fileData, HashType.MD5) ?? string.Empty;
|
||||
|
||||
// Debug output
|
||||
if (includeDebug) Console.WriteLine($"Actual MD5: {actualMd5}");
|
||||
|
||||
// Do not return on a hash mismatch
|
||||
if (actualMd5 != expectedMd5)
|
||||
{
|
||||
string filename = Encoding.ASCII.GetString(entry.Path).TrimEnd('\0');
|
||||
if (includeDebug) Console.Error.WriteLine($"MD5 checksum failure for file {filename})");
|
||||
return null;
|
||||
}
|
||||
|
||||
return fileData;
|
||||
}
|
||||
|
||||
@@ -38,32 +38,38 @@ namespace SabreTools.Serialization.Wrappers
|
||||
/// <inheritdoc cref="MatroshkaPackage.Entries"/>
|
||||
public MatroshkaEntry[]? Entries => Model.Entries;
|
||||
|
||||
// TODO: Use entries from model after models update.
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SecuROMMatroschkaPackage(MatroshkaPackage model, byte[] data, int offset)
|
||||
: base(model, data, offset)
|
||||
{
|
||||
// All logic is handled by the base class
|
||||
}
|
||||
public SecuROMMatroschkaPackage(MatroshkaPackage model, byte[] data) : base(model, data) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SecuROMMatroschkaPackage(MatroshkaPackage model, Stream data)
|
||||
: base(model, data)
|
||||
{
|
||||
// All logic is handled by the base class
|
||||
}
|
||||
public SecuROMMatroschkaPackage(MatroshkaPackage model, byte[] data, int offset) : base(model, data, offset) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SecuROMMatroschkaPackage(MatroshkaPackage model, byte[] data, int offset, int length) : base(model, data, offset, length) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SecuROMMatroschkaPackage(MatroshkaPackage model, Stream data) : base(model, data) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SecuROMMatroschkaPackage(MatroshkaPackage model, Stream data, long offset) : base(model, data, offset) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SecuROMMatroschkaPackage(MatroshkaPackage model, Stream data, long offset, long length) : base(model, data, offset, length) { }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Static Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Create a SecuROM Matroschka Package section from a byte array and offset
|
||||
/// Create a SecuROM Matroschka package from a byte array and offset
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array representing the section</param>
|
||||
/// <param name="data">Byte array representing the package</param>
|
||||
/// <param name="offset">Offset within the array to parse</param>
|
||||
/// <returns>A SecuROM Matroschka Package section wrapper on success, null on failure</returns>
|
||||
/// <returns>A SecuROM Matroschka package wrapper on success, null on failure</returns>
|
||||
public static SecuROMMatroschkaPackage? Create(byte[]? data, int offset)
|
||||
{
|
||||
// If the data is invalid
|
||||
@@ -80,10 +86,10 @@ namespace SabreTools.Serialization.Wrappers
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a SecuROM Matroschka Package section from a Stream
|
||||
/// Create a SecuROM Matroschka package from a Stream
|
||||
/// </summary>
|
||||
/// <param name="data">Stream representing the section</param>
|
||||
/// <returns>A SecuROM Matroschka Package section wrapper on success, null on failure</returns>
|
||||
/// <param name="data">Stream representing the package</param>
|
||||
/// <returns>A SecuROM Matroschka package wrapper on success, null on failure</returns>
|
||||
public static SecuROMMatroschkaPackage? Create(Stream? data)
|
||||
{
|
||||
// If the data is invalid
|
||||
@@ -99,8 +105,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
if (model == null)
|
||||
return null;
|
||||
|
||||
data.Seek(currentOffset, SeekOrigin.Begin);
|
||||
return new SecuROMMatroschkaPackage(model, data);
|
||||
return new SecuROMMatroschkaPackage(model, data, currentOffset);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user