mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-02-07 05:44:39 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce016c5eb0 | ||
|
|
2225c1f2d8 | ||
|
|
2d0c0d5845 | ||
|
|
60f1756cbb | ||
|
|
738a1d250a | ||
|
|
c8e65e1e30 | ||
|
|
ecb09ce6f2 | ||
|
|
72a1484a71 |
@@ -10,7 +10,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>1.9.0</Version>
|
||||
<Version>1.9.1</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Support All Frameworks -->
|
||||
@@ -66,7 +66,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SabreTools.IO" Version="1.7.1" />
|
||||
<PackageReference Include="SabreTools.IO" Version="1.7.2" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.8" Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND !$(TargetFramework.StartsWith(`net452`))" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>1.9.0</Version>
|
||||
<Version>1.9.1</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Support All Frameworks -->
|
||||
@@ -32,7 +32,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SabreTools.IO" Version="1.7.1" />
|
||||
<PackageReference Include="SabreTools.IO" Version="1.7.2" />
|
||||
<PackageReference Include="SabreTools.Hashing" Version="1.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageReference Include="SabreTools.Hashing" Version="1.5.0" />
|
||||
<PackageReference Include="SabreTools.Models" Version="1.7.0" />
|
||||
<PackageReference Include="SabreTools.Models" Version="1.7.1" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
{
|
||||
// Central Directory File Header
|
||||
case CentralDirectoryFileHeaderSignature:
|
||||
var cdr = ParseCentralDirectoryFileHeader(data, out _);
|
||||
var cdr = ParseCentralDirectoryFileHeader(data);
|
||||
if (cdr == null)
|
||||
return null;
|
||||
|
||||
@@ -170,10 +170,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled central directory file header on success, null on error</returns>
|
||||
public static CentralDirectoryFileHeader? ParseCentralDirectoryFileHeader(Stream data, out ExtensibleDataField[]? extraFields)
|
||||
public static CentralDirectoryFileHeader? ParseCentralDirectoryFileHeader(Stream data)
|
||||
{
|
||||
var obj = new CentralDirectoryFileHeader();
|
||||
extraFields = null;
|
||||
|
||||
obj.Signature = data.ReadUInt32LittleEndian();
|
||||
if (obj.Signature != CentralDirectoryFileHeaderSignature)
|
||||
@@ -220,8 +219,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
if (extraBytes.Length != obj.ExtraFieldLength)
|
||||
return null;
|
||||
|
||||
// TODO: This should live on the model instead of the byte representation
|
||||
extraFields = ParseExtraFields(obj, extraBytes);
|
||||
obj.ExtraFields = ParseExtraFields(obj, extraBytes);
|
||||
}
|
||||
if (obj.FileCommentLength > 0 && data.Position + obj.FileCommentLength <= data.Length)
|
||||
{
|
||||
@@ -416,7 +414,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
#region Local File Header
|
||||
|
||||
// Try to read the header
|
||||
var localFileHeader = ParseLocalFileHeader(data, out var extraFields);
|
||||
var localFileHeader = ParseLocalFileHeader(data);
|
||||
if (localFileHeader == null)
|
||||
return null;
|
||||
|
||||
@@ -424,9 +422,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
obj.LocalFileHeader = localFileHeader;
|
||||
|
||||
ulong compressedSize = localFileHeader.CompressedSize;
|
||||
if (extraFields != null)
|
||||
if (localFileHeader.ExtraFields != null)
|
||||
{
|
||||
foreach (var field in extraFields)
|
||||
foreach (var field in localFileHeader.ExtraFields)
|
||||
{
|
||||
if (field is not Zip64ExtendedInformationExtraField infoField)
|
||||
continue;
|
||||
@@ -532,10 +530,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled local file header on success, null on error</returns>
|
||||
public static LocalFileHeader? ParseLocalFileHeader(Stream data, out ExtensibleDataField[]? extraFields)
|
||||
public static LocalFileHeader? ParseLocalFileHeader(Stream data)
|
||||
{
|
||||
var obj = new LocalFileHeader();
|
||||
extraFields = null;
|
||||
|
||||
obj.Signature = data.ReadUInt32LittleEndian();
|
||||
if (obj.Signature != LocalFileHeaderSignature)
|
||||
@@ -575,8 +572,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
if (extraBytes.Length != obj.ExtraFieldLength)
|
||||
return null;
|
||||
|
||||
// TODO: This should live on the model instead of the byte representation
|
||||
extraFields = ParseExtraFields(obj, extraBytes);
|
||||
obj.ExtraFields = ParseExtraFields(obj, extraBytes);
|
||||
}
|
||||
|
||||
return obj;
|
||||
|
||||
@@ -381,10 +381,10 @@ namespace SabreTools.Serialization.Deserializers
|
||||
{
|
||||
var obj = new CLRTokenDefinition();
|
||||
|
||||
obj.AuxFormat6AuxType = data.ReadByteValue();
|
||||
obj.AuxFormat6Reserved1 = data.ReadByteValue();
|
||||
obj.AuxFormat6SymbolTableIndex = data.ReadUInt32LittleEndian();
|
||||
obj.AuxFormat6Reserved2 = data.ReadBytes(12);
|
||||
obj.AuxType = data.ReadByteValue();
|
||||
obj.Reserved1 = data.ReadByteValue();
|
||||
obj.SymbolTableIndex = data.ReadUInt32LittleEndian();
|
||||
obj.Reserved2 = data.ReadBytes(12);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
@@ -69,10 +69,7 @@ namespace SabreTools.Serialization.Printers
|
||||
builder.AppendLine(localFileHeader.FileNameLength, " [Local File Header] File name length");
|
||||
builder.AppendLine(localFileHeader.ExtraFieldLength, " [Local File Header] Extra field length");
|
||||
builder.AppendLine(localFileHeader.FileName, " [Local File Header] File name");
|
||||
|
||||
// TODO: Reenable this when models are fixed
|
||||
// var extraFields = Deserializers.PKZIP.ParseExtraFields(localFileHeader, localFileHeader.ExtraField);
|
||||
// Print(builder, " [Local File Header] Extra Fields", extraFields);
|
||||
Print(builder, " [Local File Header] Extra Fields", localFileHeader.ExtraFields);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -241,10 +238,7 @@ namespace SabreTools.Serialization.Printers
|
||||
builder.AppendLine(entry.RelativeOffsetOfLocalHeader, " Relative offset of local header");
|
||||
builder.AppendLine(entry.FileName, " File name");
|
||||
builder.AppendLine(entry.FileComment, " File comment");
|
||||
|
||||
// TODO: Reenable this when models are fixed
|
||||
// var extraFields = Deserializers.PKZIP.ParseExtraFields(entry, entry.ExtraField);
|
||||
// Print(builder, " Extra Fields", extraFields);
|
||||
Print(builder, " Extra Fields", entry.ExtraFields);
|
||||
}
|
||||
|
||||
builder.AppendLine();
|
||||
|
||||
@@ -410,10 +410,10 @@ namespace SabreTools.Serialization.Printers
|
||||
private static void Print(StringBuilder builder, CLRTokenDefinition entry, int i)
|
||||
{
|
||||
builder.AppendLine($" COFF Symbol Table Entry {i} (CLR Token Defintion)");
|
||||
builder.AppendLine(entry.AuxFormat6AuxType, " Aux type");
|
||||
builder.AppendLine(entry.AuxFormat6Reserved1, " Reserved");
|
||||
builder.AppendLine(entry.AuxFormat6SymbolTableIndex, " Symbol table index");
|
||||
builder.AppendLine(entry.AuxFormat6Reserved2, " Reserved");
|
||||
builder.AppendLine(entry.AuxType, " Aux type");
|
||||
builder.AppendLine(entry.Reserved1, " Reserved");
|
||||
builder.AppendLine(entry.SymbolTableIndex, " Symbol table index");
|
||||
builder.AppendLine(entry.Reserved2, " Reserved");
|
||||
}
|
||||
|
||||
private static void Print(StringBuilder builder, COFFStringTable? stringTable)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>1.9.0</Version>
|
||||
<Version>1.9.1</Version>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski</Authors>
|
||||
@@ -63,10 +63,10 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="SabreTools.ASN1" Version="1.6.0" />
|
||||
<PackageReference Include="SabreTools.ASN1" Version="1.6.2" />
|
||||
<PackageReference Include="SabreTools.Hashing" Version="1.5.0" />
|
||||
<PackageReference Include="SabreTools.IO" Version="1.7.1" />
|
||||
<PackageReference Include="SabreTools.Models" Version="1.7.0" />
|
||||
<PackageReference Include="SabreTools.IO" Version="1.7.2" />
|
||||
<PackageReference Include="SabreTools.Models" Version="1.7.1" />
|
||||
<PackageReference Include="SabreTools.Matching" Version="1.6.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.40.0" Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND !$(TargetFramework.StartsWith(`net452`))" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -167,7 +167,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
using FileStream fs = File.OpenWrite(filename);
|
||||
|
||||
// Read the data block
|
||||
var data = _dataSource.ReadFrom(offset, compressedSize, retainPosition: true);
|
||||
var data = ReadRangeFromSource(offset, compressedSize);
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
|
||||
// Read the data
|
||||
var lump = Lumps[index];
|
||||
var data = _dataSource.ReadFrom(lump.Offset, lump.Length, retainPosition: true);
|
||||
var data = ReadRangeFromSource(lump.Offset, lump.Length);
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -322,7 +322,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
return null;
|
||||
|
||||
// Try to read the sector data
|
||||
var sectorData = _dataSource.ReadFrom(sectorDataOffset, (int)SectorSize, retainPosition: true);
|
||||
var sectorData = ReadRangeFromSource(sectorDataOffset, (int)SectorSize);
|
||||
if (sectorData == null)
|
||||
return null;
|
||||
|
||||
|
||||
@@ -321,7 +321,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
for (int i = 0; i < dataBlockOffsets.Count; i++)
|
||||
{
|
||||
int readSize = (int)Math.Min(BlockSize, fileSize);
|
||||
var data = _dataSource.ReadFrom((int)dataBlockOffsets[i], readSize, retainPosition: true);
|
||||
var data = ReadRangeFromSource((int)dataBlockOffsets[i], readSize);
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -240,7 +240,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
long outputFileSize = file.UncompressedSize;
|
||||
|
||||
// Read the compressed data directly
|
||||
var compressedData = _dataSource.ReadFrom((int)fileOffset, (int)fileSize, retainPosition: true);
|
||||
var compressedData = ReadRangeFromSource((int)fileOffset, (int)fileSize);
|
||||
if (compressedData == null)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
return false;
|
||||
|
||||
// Read in the data as an array
|
||||
byte[]? contents = _dataSource.ReadFrom(DataOffset, (int)compressedSize, retainPosition: true);
|
||||
byte[]? contents = ReadRangeFromSource(DataOffset, (int)compressedSize);
|
||||
if (contents == null)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
return false;
|
||||
|
||||
// Read in the data as an array
|
||||
byte[]? contents = _dataSource.ReadFrom(12, (int)compressedSize, retainPosition: true);
|
||||
byte[]? contents = ReadRangeFromSource(12, (int)compressedSize);
|
||||
if (contents == null)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
return false;
|
||||
|
||||
// Read in the data as an array
|
||||
byte[]? contents = _dataSource.ReadFrom(14, (int)compressedSize, retainPosition: true);
|
||||
byte[]? contents = ReadRangeFromSource(14, (int)compressedSize);
|
||||
if (contents == null)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
return [];
|
||||
|
||||
// Read the entry data and return
|
||||
return _dataSource.ReadFrom(offset, length, retainPosition: true);
|
||||
return ReadRangeFromSource(offset, length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -315,7 +315,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
if (length == -1)
|
||||
length = Length;
|
||||
|
||||
return _dataSource.ReadFrom(rangeStart, (int)length, retainPosition: true);
|
||||
return ReadRangeFromSource(rangeStart, (int)length);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_sourceDataLock)
|
||||
lock (_overlayAddressLock)
|
||||
{
|
||||
// Use the cached data if possible
|
||||
if (_overlayAddress != null)
|
||||
@@ -65,10 +65,13 @@ namespace SabreTools.Serialization.Wrappers
|
||||
if (entry.FlagWord.HasFlag(SegmentTableEntryFlag.RELOCINFO))
|
||||
#endif
|
||||
{
|
||||
_dataSource.Seek(offset, SeekOrigin.Begin);
|
||||
var relocationData = Deserializers.NewExecutable.ParsePerSegmentData(_dataSource);
|
||||
lock (_dataSourceLock)
|
||||
{
|
||||
_dataSource.Seek(offset, SeekOrigin.Begin);
|
||||
var relocationData = Deserializers.NewExecutable.ParsePerSegmentData(_dataSource);
|
||||
|
||||
offset = _dataSource.Position;
|
||||
offset = _dataSource.Position;
|
||||
}
|
||||
}
|
||||
|
||||
if (offset > endOfSectionData)
|
||||
@@ -94,6 +97,10 @@ namespace SabreTools.Serialization.Wrappers
|
||||
if (endOfSectionData <= 0)
|
||||
endOfSectionData = -1;
|
||||
|
||||
// Adjust the position of the data by 705 bytes
|
||||
// TODO: Investigate what the byte data is
|
||||
endOfSectionData += 705;
|
||||
|
||||
// Cache and return the position
|
||||
_overlayAddress = endOfSectionData;
|
||||
return _overlayAddress.Value;
|
||||
@@ -105,11 +112,11 @@ namespace SabreTools.Serialization.Wrappers
|
||||
/// Overlay data, if it exists
|
||||
/// </summary>
|
||||
/// <see href="https://codeberg.org/CYBERDEV/REWise/src/branch/master/src/exefile.c"/>
|
||||
public byte[]? OverlayData
|
||||
public byte[] OverlayData
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_sourceDataLock)
|
||||
lock (_overlayDataLock)
|
||||
{
|
||||
// Use the cached data if possible
|
||||
if (_overlayData != null)
|
||||
@@ -118,54 +125,27 @@ namespace SabreTools.Serialization.Wrappers
|
||||
// Get the available source length, if possible
|
||||
long dataLength = Length;
|
||||
if (dataLength == -1)
|
||||
return null;
|
||||
{
|
||||
_overlayData = [];
|
||||
return _overlayData;
|
||||
}
|
||||
|
||||
// If a required property is missing
|
||||
if (Header == null || SegmentTable == null || ResourceTable?.ResourceTypes == null)
|
||||
return null;
|
||||
|
||||
// Search through the segments table to find the furthest
|
||||
long endOfSectionData = -1;
|
||||
foreach (var entry in SegmentTable)
|
||||
{
|
||||
// Get end of segment data
|
||||
long offset = (entry.Offset * (1 << Header.SegmentAlignmentShiftCount)) + entry.Length;
|
||||
|
||||
// Read and find the end of the relocation data
|
||||
#if NET20 || NET35
|
||||
if ((entry.FlagWord & SegmentTableEntryFlag.RELOCINFO) != 0)
|
||||
#else
|
||||
if (entry.FlagWord.HasFlag(SegmentTableEntryFlag.RELOCINFO))
|
||||
#endif
|
||||
{
|
||||
_dataSource.Seek(offset, SeekOrigin.Begin);
|
||||
var relocationData = Deserializers.NewExecutable.ParsePerSegmentData(_dataSource);
|
||||
|
||||
offset = _dataSource.Position;
|
||||
}
|
||||
|
||||
if (offset > endOfSectionData)
|
||||
endOfSectionData = offset;
|
||||
_overlayData = [];
|
||||
return _overlayData;
|
||||
}
|
||||
|
||||
// Search through the resources table to find the furthest
|
||||
foreach (var entry in ResourceTable.ResourceTypes)
|
||||
{
|
||||
// Skip invalid entries
|
||||
if (entry.ResourceCount == 0 || entry.Resources == null || entry.Resources.Length == 0)
|
||||
continue;
|
||||
|
||||
foreach (var resource in entry.Resources)
|
||||
{
|
||||
int offset = (resource.Offset << ResourceTable.AlignmentShiftCount) + resource.Length;
|
||||
if (offset > endOfSectionData)
|
||||
endOfSectionData = offset;
|
||||
}
|
||||
}
|
||||
// Get the overlay address if possible
|
||||
long endOfSectionData = OverlayAddress;
|
||||
|
||||
// If we didn't find the end of section data
|
||||
if (endOfSectionData <= 0)
|
||||
return null;
|
||||
{
|
||||
_overlayData = [];
|
||||
return _overlayData;
|
||||
}
|
||||
|
||||
// If we're at the end of the file, cache an empty byte array
|
||||
if (endOfSectionData >= dataLength)
|
||||
@@ -176,7 +156,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
|
||||
// Otherwise, cache and return the data
|
||||
long overlayLength = dataLength - endOfSectionData;
|
||||
_overlayData = _dataSource.ReadFrom((int)endOfSectionData, (int)overlayLength, retainPosition: true);
|
||||
_overlayData = ReadRangeFromSource((int)endOfSectionData, (int)overlayLength);
|
||||
return _overlayData;
|
||||
}
|
||||
}
|
||||
@@ -185,11 +165,11 @@ namespace SabreTools.Serialization.Wrappers
|
||||
/// <summary>
|
||||
/// Overlay strings, if they exist
|
||||
/// </summary>
|
||||
public List<string>? OverlayStrings
|
||||
public List<string> OverlayStrings
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_sourceDataLock)
|
||||
lock (_overlayStringsLock)
|
||||
{
|
||||
// Use the cached data if possible
|
||||
if (_overlayStrings != null)
|
||||
@@ -198,57 +178,21 @@ namespace SabreTools.Serialization.Wrappers
|
||||
// Get the available source length, if possible
|
||||
long dataLength = Length;
|
||||
if (dataLength == -1)
|
||||
return null;
|
||||
|
||||
// If a required property is missing
|
||||
if (Header == null || SegmentTable == null || ResourceTable?.ResourceTypes == null)
|
||||
return null;
|
||||
|
||||
// Search through the segments table to find the furthest
|
||||
int endOfSectionData = -1;
|
||||
foreach (var entry in SegmentTable)
|
||||
{
|
||||
int offset = (entry.Offset << Header.SegmentAlignmentShiftCount) + entry.Length;
|
||||
if (offset > endOfSectionData)
|
||||
endOfSectionData = offset;
|
||||
}
|
||||
|
||||
// Search through the resources table to find the furthest
|
||||
foreach (var entry in ResourceTable.ResourceTypes)
|
||||
{
|
||||
// Skip invalid entries
|
||||
if (entry.ResourceCount == 0 || entry.Resources == null || entry.Resources.Length == 0)
|
||||
continue;
|
||||
|
||||
foreach (var resource in entry.Resources)
|
||||
{
|
||||
int offset = (resource.Offset << ResourceTable.AlignmentShiftCount) + resource.Length;
|
||||
if (offset > endOfSectionData)
|
||||
endOfSectionData = offset;
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't find the end of section data
|
||||
if (endOfSectionData <= 0)
|
||||
return null;
|
||||
|
||||
// Adjust the position of the data by 705 bytes
|
||||
// TODO: Investigate what the byte data is
|
||||
endOfSectionData += 705;
|
||||
|
||||
// If we're at the end of the file, cache an empty list
|
||||
if (endOfSectionData >= dataLength)
|
||||
{
|
||||
_overlayStrings = [];
|
||||
return _overlayStrings;
|
||||
}
|
||||
|
||||
// TODO: Revisit the 16 MiB limit
|
||||
// Cap the check for overlay strings to 16 MiB (arbitrary)
|
||||
long overlayLength = Math.Min(dataLength - endOfSectionData, 16 * 1024 * 1024);
|
||||
// Get the overlay data, if possible
|
||||
var overlayData = OverlayData;
|
||||
if (overlayData.Length == 0)
|
||||
{
|
||||
_overlayStrings = [];
|
||||
return _overlayStrings;
|
||||
}
|
||||
|
||||
// Otherwise, cache and return the strings
|
||||
_overlayStrings = _dataSource.ReadStringsFrom(endOfSectionData, (int)overlayLength, charLimit: 3);
|
||||
_overlayStrings = overlayData.ReadStringsFrom(charLimit: 3) ?? [];
|
||||
return _overlayStrings;
|
||||
}
|
||||
}
|
||||
@@ -269,23 +213,26 @@ namespace SabreTools.Serialization.Wrappers
|
||||
/// <summary>
|
||||
/// Stub executable data, if it exists
|
||||
/// </summary>
|
||||
public byte[]? StubExecutableData
|
||||
public byte[] StubExecutableData
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_sourceDataLock)
|
||||
lock (_stubExecutableDataLock)
|
||||
{
|
||||
// If we already have cached data, just use that immediately
|
||||
if (_stubExecutableData != null)
|
||||
return _stubExecutableData;
|
||||
|
||||
if (Stub?.Header?.NewExeHeaderAddr == null)
|
||||
return null;
|
||||
{
|
||||
_stubExecutableData = [];
|
||||
return _stubExecutableData;
|
||||
}
|
||||
|
||||
// Populate the raw stub executable data based on the source
|
||||
int endOfStubHeader = 0x40;
|
||||
int lengthOfStubExecutableData = (int)Stub.Header.NewExeHeaderAddr - endOfStubHeader;
|
||||
_stubExecutableData = _dataSource.ReadFrom(endOfStubHeader, lengthOfStubExecutableData, retainPosition: true);
|
||||
_stubExecutableData = ReadRangeFromSource(endOfStubHeader, lengthOfStubExecutableData);
|
||||
|
||||
// Cache and return the stub executable data, even if null
|
||||
return _stubExecutableData;
|
||||
@@ -302,25 +249,40 @@ namespace SabreTools.Serialization.Wrappers
|
||||
/// </summary>
|
||||
private long? _overlayAddress = null;
|
||||
|
||||
/// <summary>
|
||||
/// Lock object for <see cref="_overlayAddress"/>
|
||||
/// </summary>
|
||||
private readonly object _overlayAddressLock = new();
|
||||
|
||||
/// <summary>
|
||||
/// Overlay data, if it exists
|
||||
/// </summary>
|
||||
private byte[]? _overlayData = null;
|
||||
|
||||
/// <summary>
|
||||
/// Lock object for <see cref="_overlayData"/>
|
||||
/// </summary>
|
||||
private readonly object _overlayDataLock = new();
|
||||
|
||||
/// <summary>
|
||||
/// Overlay strings, if they exist
|
||||
/// </summary>
|
||||
private List<string>? _overlayStrings = null;
|
||||
|
||||
/// <summary>
|
||||
/// Lock object for <see cref="_overlayStrings"/>
|
||||
/// </summary>
|
||||
private readonly object _overlayStringsLock = new();
|
||||
|
||||
/// <summary>
|
||||
/// Stub executable data, if it exists
|
||||
/// </summary>
|
||||
private byte[]? _stubExecutableData = null;
|
||||
|
||||
/// <summary>
|
||||
/// Lock object for reading from the source
|
||||
/// Lock object for <see cref="_stubExecutableData"/>
|
||||
/// </summary>
|
||||
private readonly object _sourceDataLock = new();
|
||||
private readonly object _stubExecutableDataLock = new();
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -420,7 +382,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
{
|
||||
// Cache the overlay data for easier reading
|
||||
var overlayData = OverlayData;
|
||||
if (overlayData == null || overlayData.Length == 0)
|
||||
if (overlayData.Length == 0)
|
||||
return false;
|
||||
|
||||
// Set the output variables
|
||||
@@ -605,28 +567,31 @@ namespace SabreTools.Serialization.Wrappers
|
||||
if (overlayOffset < 0 || overlayOffset >= Length)
|
||||
return -1;
|
||||
|
||||
// Attempt to get the overlay header
|
||||
_dataSource.Seek(overlayOffset, SeekOrigin.Begin);
|
||||
var header = WiseOverlayHeader.Create(_dataSource);
|
||||
if (header != null)
|
||||
return overlayOffset;
|
||||
|
||||
// Align and loop to see if it can be found
|
||||
_dataSource.Seek(overlayOffset, SeekOrigin.Begin);
|
||||
_dataSource.AlignToBoundary(0x10);
|
||||
overlayOffset = _dataSource.Position;
|
||||
while (_dataSource.Position < Length)
|
||||
lock (_dataSourceLock)
|
||||
{
|
||||
// Attempt to get the overlay header
|
||||
_dataSource.Seek(overlayOffset, SeekOrigin.Begin);
|
||||
header = WiseOverlayHeader.Create(_dataSource);
|
||||
var header = WiseOverlayHeader.Create(_dataSource);
|
||||
if (header != null)
|
||||
return overlayOffset;
|
||||
|
||||
overlayOffset += 0x10;
|
||||
}
|
||||
// Align and loop to see if it can be found
|
||||
_dataSource.Seek(overlayOffset, SeekOrigin.Begin);
|
||||
_dataSource.AlignToBoundary(0x10);
|
||||
overlayOffset = _dataSource.Position;
|
||||
while (_dataSource.Position < Length)
|
||||
{
|
||||
_dataSource.Seek(overlayOffset, SeekOrigin.Begin);
|
||||
header = WiseOverlayHeader.Create(_dataSource);
|
||||
if (header != null)
|
||||
return overlayOffset;
|
||||
|
||||
header = null;
|
||||
return -1;
|
||||
overlayOffset += 0x10;
|
||||
}
|
||||
|
||||
header = null;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -692,7 +657,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
return [];
|
||||
|
||||
// Read the resource data and return
|
||||
return _dataSource.ReadFrom(offset, length, retainPosition: true);
|
||||
return ReadRangeFromSource(offset, length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -784,7 +749,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
return [];
|
||||
|
||||
// Read the segment data and return
|
||||
return _dataSource.ReadFrom(offset, length, retainPosition: true);
|
||||
return ReadRangeFromSource(offset, length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -854,7 +819,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
if (length == -1)
|
||||
length = Length;
|
||||
|
||||
return _dataSource.ReadFrom(rangeStart, (int)length, retainPosition: true);
|
||||
return ReadRangeFromSource(rangeStart, (int)length);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -128,7 +128,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
|
||||
// Read the item data
|
||||
var directoryItem = DirectoryItems[index];
|
||||
var data = _dataSource.ReadFrom((int)directoryItem.ItemOffset, (int)directoryItem.ItemLength, retainPosition: true);
|
||||
var data = ReadRangeFromSource((int)directoryItem.ItemOffset, (int)directoryItem.ItemLength);
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
using FileStream fs = File.OpenWrite(filename);
|
||||
|
||||
// Read the data block
|
||||
var data = _dataSource.ReadFrom(offset, size, retainPosition: true);
|
||||
var data = ReadRangeFromSource(offset, size);
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -141,7 +141,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
// Read the entire compressed data
|
||||
int compressedDataOffset = (int)CompressedDataOffset;
|
||||
long compressedDataLength = Length - compressedDataOffset;
|
||||
var compressedData = _dataSource.ReadFrom(compressedDataOffset, (int)compressedDataLength, retainPosition: true);
|
||||
var compressedData = ReadRangeFromSource(compressedDataOffset, (int)compressedDataLength);
|
||||
|
||||
// Print a debug reminder
|
||||
if (includeDebug) Console.WriteLine("Quantum archive extraction is unsupported");
|
||||
|
||||
@@ -204,7 +204,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
long outputFileSize = GetUncompressedSize(index);
|
||||
|
||||
// Read the compressed data directly
|
||||
var compressedData = _dataSource.ReadFrom((int)fileOffset, (int)fileSize, retainPosition: true);
|
||||
var compressedData = ReadRangeFromSource((int)fileOffset, (int)fileSize);
|
||||
if (compressedData == null)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
|
||||
// Read the data
|
||||
var lump = Lumps[index];
|
||||
var data = _dataSource.ReadFrom(lump.Offset, lump.Length, retainPosition: true);
|
||||
var data = ReadRangeFromSource(lump.Offset, lump.Length);
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
|
||||
// Read the data -- TODO: Handle uncompressed lumps (see BSP.ExtractTexture)
|
||||
var lump = DirEntries[index];
|
||||
var data = _dataSource.ReadFrom((int)lump.Offset, (int)lump.Length, retainPosition: true);
|
||||
var data = ReadRangeFromSource((int)lump.Offset, (int)lump.Length);
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -232,76 +232,79 @@ namespace SabreTools.Serialization.Wrappers
|
||||
/// <remarks>On success, this sets <see cref="InstallerDataOffset"/></remarks>
|
||||
public bool ExtractHeaderDefinedFiles(string outputDirectory, bool includeDebug)
|
||||
{
|
||||
// Seek to the compressed data offset
|
||||
_dataSource.Seek(CompressedDataOffset, SeekOrigin.Begin);
|
||||
if (includeDebug) Console.WriteLine($"Beginning of header-defined files: {CompressedDataOffset}");
|
||||
lock (_dataSourceLock)
|
||||
{
|
||||
// Seek to the compressed data offset
|
||||
_dataSource.Seek(CompressedDataOffset, SeekOrigin.Begin);
|
||||
if (includeDebug) Console.WriteLine($"Beginning of header-defined files: {CompressedDataOffset}");
|
||||
|
||||
// Extract WiseColors.dib, if it exists
|
||||
var expected = new DeflateInfo { InputSize = DibDeflatedSize, OutputSize = DibInflatedSize, Crc32 = 0 };
|
||||
if (InflateWrapper.ExtractFile(_dataSource, "WiseColors.dib", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
|
||||
return false;
|
||||
// Extract WiseColors.dib, if it exists
|
||||
var expected = new DeflateInfo { InputSize = DibDeflatedSize, OutputSize = DibInflatedSize, Crc32 = 0 };
|
||||
if (InflateWrapper.ExtractFile(_dataSource, "WiseColors.dib", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
|
||||
return false;
|
||||
|
||||
// Extract WiseScript.bin
|
||||
expected = new DeflateInfo { InputSize = WiseScriptDeflatedSize, OutputSize = WiseScriptInflatedSize, Crc32 = 0 };
|
||||
if (InflateWrapper.ExtractFile(_dataSource, "WiseScript.bin", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
|
||||
return false;
|
||||
// Extract WiseScript.bin
|
||||
expected = new DeflateInfo { InputSize = WiseScriptDeflatedSize, OutputSize = WiseScriptInflatedSize, Crc32 = 0 };
|
||||
if (InflateWrapper.ExtractFile(_dataSource, "WiseScript.bin", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
|
||||
return false;
|
||||
|
||||
// Extract WISE0001.DLL, if it exists
|
||||
expected = new DeflateInfo { InputSize = WiseDllDeflatedSize, OutputSize = -1, Crc32 = 0 };
|
||||
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "WISE0001.DLL", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
|
||||
return false;
|
||||
// Extract WISE0001.DLL, if it exists
|
||||
expected = new DeflateInfo { InputSize = WiseDllDeflatedSize, OutputSize = -1, Crc32 = 0 };
|
||||
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "WISE0001.DLL", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
|
||||
return false;
|
||||
|
||||
// Extract CTL3D32.DLL, if it exists
|
||||
expected = new DeflateInfo { InputSize = Ctl3d32DeflatedSize, OutputSize = -1, Crc32 = 0 };
|
||||
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "CTL3D32.DLL", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
|
||||
return false;
|
||||
// Extract CTL3D32.DLL, if it exists
|
||||
expected = new DeflateInfo { InputSize = Ctl3d32DeflatedSize, OutputSize = -1, Crc32 = 0 };
|
||||
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "CTL3D32.DLL", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
|
||||
return false;
|
||||
|
||||
// Extract FILE0004, if it exists
|
||||
expected = new DeflateInfo { InputSize = SomeData4DeflatedSize, OutputSize = -1, Crc32 = 0 };
|
||||
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "FILE0004", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
|
||||
return false;
|
||||
// Extract FILE0004, if it exists
|
||||
expected = new DeflateInfo { InputSize = SomeData4DeflatedSize, OutputSize = -1, Crc32 = 0 };
|
||||
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "FILE0004", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
|
||||
return false;
|
||||
|
||||
// Extract Ocxreg32.EXE, if it exists
|
||||
expected = new DeflateInfo { InputSize = RegToolDeflatedSize, OutputSize = -1, Crc32 = 0 };
|
||||
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "Ocxreg32.EXE", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
|
||||
return false;
|
||||
// Extract Ocxreg32.EXE, if it exists
|
||||
expected = new DeflateInfo { InputSize = RegToolDeflatedSize, OutputSize = -1, Crc32 = 0 };
|
||||
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "Ocxreg32.EXE", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
|
||||
return false;
|
||||
|
||||
// Extract PROGRESS.DLL, if it exists
|
||||
expected = new DeflateInfo { InputSize = ProgressDllDeflatedSize, OutputSize = -1, Crc32 = 0 };
|
||||
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "PROGRESS.DLL", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
|
||||
return false;
|
||||
// Extract PROGRESS.DLL, if it exists
|
||||
expected = new DeflateInfo { InputSize = ProgressDllDeflatedSize, OutputSize = -1, Crc32 = 0 };
|
||||
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "PROGRESS.DLL", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
|
||||
return false;
|
||||
|
||||
// Extract FILE0007, if it exists
|
||||
expected = new DeflateInfo { InputSize = SomeData7DeflatedSize, OutputSize = -1, Crc32 = 0 };
|
||||
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "FILE0007", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
|
||||
return false;
|
||||
// Extract FILE0007, if it exists
|
||||
expected = new DeflateInfo { InputSize = SomeData7DeflatedSize, OutputSize = -1, Crc32 = 0 };
|
||||
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "FILE0007", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
|
||||
return false;
|
||||
|
||||
// Extract FILE0008, if it exists
|
||||
expected = new DeflateInfo { InputSize = SomeData8DeflatedSize, OutputSize = -1, Crc32 = 0 };
|
||||
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "FILE0008", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
|
||||
return false;
|
||||
// Extract FILE0008, if it exists
|
||||
expected = new DeflateInfo { InputSize = SomeData8DeflatedSize, OutputSize = -1, Crc32 = 0 };
|
||||
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "FILE0008", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
|
||||
return false;
|
||||
|
||||
// Extract FILE0009, if it exists
|
||||
expected = new DeflateInfo { InputSize = SomeData9DeflatedSize, OutputSize = -1, Crc32 = 0 };
|
||||
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "FILE0009", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
|
||||
return false;
|
||||
// Extract FILE0009, if it exists
|
||||
expected = new DeflateInfo { InputSize = SomeData9DeflatedSize, OutputSize = -1, Crc32 = 0 };
|
||||
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "FILE0009", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
|
||||
return false;
|
||||
|
||||
// Extract FILE000A, if it exists
|
||||
expected = new DeflateInfo { InputSize = SomeData10DeflatedSize, OutputSize = -1, Crc32 = 0 };
|
||||
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "FILE000A", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
|
||||
return false;
|
||||
// Extract FILE000A, if it exists
|
||||
expected = new DeflateInfo { InputSize = SomeData10DeflatedSize, OutputSize = -1, Crc32 = 0 };
|
||||
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "FILE000A", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
|
||||
return false;
|
||||
|
||||
// Extract install script, if it exists
|
||||
expected = new DeflateInfo { InputSize = InstallScriptDeflatedSize, OutputSize = -1, Crc32 = 0 };
|
||||
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "INSTALL_SCRIPT", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
|
||||
return false;
|
||||
// Extract install script, if it exists
|
||||
expected = new DeflateInfo { InputSize = InstallScriptDeflatedSize, OutputSize = -1, Crc32 = 0 };
|
||||
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "INSTALL_SCRIPT", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
|
||||
return false;
|
||||
|
||||
// Extract FILE000{n}.DAT, if it exists
|
||||
expected = new DeflateInfo { InputSize = FinalFileDeflatedSize, OutputSize = FinalFileInflatedSize, Crc32 = 0 };
|
||||
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "FILE00XX.DAT", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
|
||||
return false;
|
||||
// Extract FILE000{n}.DAT, if it exists
|
||||
expected = new DeflateInfo { InputSize = FinalFileDeflatedSize, OutputSize = FinalFileInflatedSize, Crc32 = 0 };
|
||||
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "FILE00XX.DAT", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
|
||||
return false;
|
||||
|
||||
InstallerDataOffset = _dataSource.Position;
|
||||
InstallerDataOffset = _dataSource.Position;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -328,13 +331,17 @@ namespace SabreTools.Serialization.Wrappers
|
||||
// Perform path replacements
|
||||
string filename = obj.DestinationPathname ?? $"WISE{index:X4}";
|
||||
filename = filename.Replace("%", string.Empty);
|
||||
_dataSource.Seek(InstallerDataOffset + obj.DeflateStart, SeekOrigin.Begin);
|
||||
return InflateWrapper.ExtractFile(_dataSource,
|
||||
filename,
|
||||
outputDirectory,
|
||||
expected,
|
||||
IsPKZIP,
|
||||
includeDebug);
|
||||
|
||||
lock (_dataSourceLock)
|
||||
{
|
||||
_dataSource.Seek(InstallerDataOffset + obj.DeflateStart, SeekOrigin.Begin);
|
||||
return InflateWrapper.ExtractFile(_dataSource,
|
||||
filename,
|
||||
outputDirectory,
|
||||
expected,
|
||||
IsPKZIP,
|
||||
includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -373,8 +380,12 @@ namespace SabreTools.Serialization.Wrappers
|
||||
|
||||
// Perform path replacements
|
||||
string filename = $"{baseName}{i:X4}";
|
||||
_dataSource.Seek(InstallerDataOffset + info.DeflateStart, SeekOrigin.Begin);
|
||||
_ = InflateWrapper.ExtractFile(_dataSource, filename, outputDirectory, expected, IsPKZIP, includeDebug);
|
||||
|
||||
lock (_dataSourceLock)
|
||||
{
|
||||
_dataSource.Seek(InstallerDataOffset + info.DeflateStart, SeekOrigin.Begin);
|
||||
_ = InflateWrapper.ExtractFile(_dataSource, filename, outputDirectory, expected, IsPKZIP, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
// Always return good -- TODO: Fix this
|
||||
@@ -402,8 +413,12 @@ namespace SabreTools.Serialization.Wrappers
|
||||
// Perform path replacements
|
||||
string filename = $"CustomDialogSet_{obj.DisplayVariable}-{obj.Name}";
|
||||
filename = filename.Replace("%", string.Empty);
|
||||
_dataSource.Seek(InstallerDataOffset + obj.DeflateStart, SeekOrigin.Begin);
|
||||
return InflateWrapper.ExtractFile(_dataSource, filename, outputDirectory, expected, IsPKZIP, includeDebug);
|
||||
|
||||
lock (_dataSourceLock)
|
||||
{
|
||||
_dataSource.Seek(InstallerDataOffset + obj.DeflateStart, SeekOrigin.Begin);
|
||||
return InflateWrapper.ExtractFile(_dataSource, filename, outputDirectory, expected, IsPKZIP, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
/// to ensure that all possible values before the temp string are found
|
||||
/// and read properly
|
||||
public long CompressedDataOffset { get; private set; }
|
||||
|
||||
|
||||
/// <inheritdoc cref="SectionHeader.UnknownDataSize"/>
|
||||
public uint UnknownDataSize => Model.UnknownDataSize;
|
||||
|
||||
@@ -159,7 +159,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
long endOffset = data.Position - currentOffset;
|
||||
|
||||
data.Seek(currentOffset, SeekOrigin.Begin);
|
||||
return new WiseSectionHeader(model, data) { CompressedDataOffset = endOffset};
|
||||
return new WiseSectionHeader(model, data) { CompressedDataOffset = endOffset };
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -181,7 +181,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
if (includeDebug) Console.Error.WriteLine("Could not extract header-defined files");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -196,37 +196,40 @@ namespace SabreTools.Serialization.Wrappers
|
||||
/// <returns>True if the files extracted successfully, false otherwise</returns>
|
||||
private bool ExtractHeaderDefinedFiles(string outputDirectory, bool includeDebug)
|
||||
{
|
||||
// Seek to the compressed data offset
|
||||
_dataSource.Seek(CompressedDataOffset, SeekOrigin.Begin);
|
||||
bool successful = true;
|
||||
|
||||
// Extract first executable, if it exists
|
||||
if (ExtractFile("FirstExecutable.exe", outputDirectory, FirstExecutableFileEntryLength, includeDebug) != ExtractionStatus.GOOD)
|
||||
successful = false;
|
||||
|
||||
// Extract second executable, if it exists
|
||||
// If there's a size provided for the second executable but no size for the first executable, the size of
|
||||
// the second executable appears to be some unrelated value that's larger than the second executable
|
||||
// actually is. Currently unable to extract properly in these cases, as no header value in such installers
|
||||
// seems to actually correspond to the real size of the second executable.
|
||||
if (ExtractFile("SecondExecutable.exe", outputDirectory, SecondExecutableFileEntryLength, includeDebug) != ExtractionStatus.GOOD)
|
||||
successful = false;
|
||||
|
||||
// Extract third executable, if it exists
|
||||
if (ExtractFile("ThirdExecutable.exe", outputDirectory, ThirdExecutableFileEntryLength, includeDebug) != ExtractionStatus.GOOD)
|
||||
successful = false;
|
||||
|
||||
// Extract main MSI file
|
||||
if (ExtractFile("ExtractedMsi.msi", outputDirectory, MsiFileEntryLength, includeDebug) != ExtractionStatus.GOOD)
|
||||
lock (_dataSourceLock)
|
||||
{
|
||||
// Fallback- seek to the position that's the length of the MSI file entry from the end, then try and
|
||||
// extract from there.
|
||||
_dataSource.Seek(-MsiFileEntryLength + 1, SeekOrigin.End);
|
||||
if (ExtractFile("ExtractedMsi.msi", outputDirectory, MsiFileEntryLength, includeDebug) != ExtractionStatus.GOOD)
|
||||
return false; // The fallback also failed.
|
||||
}
|
||||
// Seek to the compressed data offset
|
||||
_dataSource.Seek(CompressedDataOffset, SeekOrigin.Begin);
|
||||
bool successful = true;
|
||||
|
||||
return successful;
|
||||
// Extract first executable, if it exists
|
||||
if (ExtractFile("FirstExecutable.exe", outputDirectory, FirstExecutableFileEntryLength, includeDebug) != ExtractionStatus.GOOD)
|
||||
successful = false;
|
||||
|
||||
// Extract second executable, if it exists
|
||||
// If there's a size provided for the second executable but no size for the first executable, the size of
|
||||
// the second executable appears to be some unrelated value that's larger than the second executable
|
||||
// actually is. Currently unable to extract properly in these cases, as no header value in such installers
|
||||
// seems to actually correspond to the real size of the second executable.
|
||||
if (ExtractFile("SecondExecutable.exe", outputDirectory, SecondExecutableFileEntryLength, includeDebug) != ExtractionStatus.GOOD)
|
||||
successful = false;
|
||||
|
||||
// Extract third executable, if it exists
|
||||
if (ExtractFile("ThirdExecutable.exe", outputDirectory, ThirdExecutableFileEntryLength, includeDebug) != ExtractionStatus.GOOD)
|
||||
successful = false;
|
||||
|
||||
// Extract main MSI file
|
||||
if (ExtractFile("ExtractedMsi.msi", outputDirectory, MsiFileEntryLength, includeDebug) != ExtractionStatus.GOOD)
|
||||
{
|
||||
// Fallback- seek to the position that's the length of the MSI file entry from the end, then try and
|
||||
// extract from there.
|
||||
_dataSource.Seek(-MsiFileEntryLength + 1, SeekOrigin.End);
|
||||
if (ExtractFile("ExtractedMsi.msi", outputDirectory, MsiFileEntryLength, includeDebug) != ExtractionStatus.GOOD)
|
||||
return false; // The fallback also failed.
|
||||
}
|
||||
|
||||
return successful;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using SabreTools.IO.Extensions;
|
||||
using SabreTools.IO.Streams;
|
||||
using SabreTools.Serialization.Interfaces;
|
||||
|
||||
@@ -57,6 +58,11 @@ namespace SabreTools.Serialization.Wrappers
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Lock for accessing <see cref="_dataSource"/>
|
||||
/// </summary>
|
||||
protected readonly object _dataSourceLock = new();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
@@ -89,6 +95,33 @@ namespace SabreTools.Serialization.Wrappers
|
||||
|
||||
#endregion
|
||||
|
||||
#region Data
|
||||
|
||||
/// <summary>
|
||||
/// Read a number of bytes from an offset fomr the data source, if possible
|
||||
/// </summary>
|
||||
/// <param name="offset">Offset within the data source to start reading</param>
|
||||
/// <param name="length">Number of bytes to read from the offset</param>
|
||||
/// <returns>Filled byte array on success, null on error</returns>
|
||||
/// <remarks>
|
||||
/// This method locks the data source to avoid potential conflicts in reading
|
||||
/// from the data source. This should be the preferred way of reading in cases
|
||||
/// where there may be multiple threads accessing the wrapper.
|
||||
///
|
||||
/// This method will return an empty array if the length is greater than what is left
|
||||
/// in the stream. This is different behavior than a normal stream read that would
|
||||
/// attempt to read as much as possible, returning the amount of bytes read.
|
||||
/// </remarks>
|
||||
protected byte[] ReadRangeFromSource(long offset, int length)
|
||||
{
|
||||
lock (_dataSourceLock)
|
||||
{
|
||||
return _dataSource.ReadFrom(offset, length, retainPosition: true) ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region JSON Export
|
||||
|
||||
#if NETCOREAPP
|
||||
|
||||
@@ -139,7 +139,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
return false;
|
||||
|
||||
// Load the item data
|
||||
var data = _dataSource.ReadFrom((int)directoryEntry.EntryOffset, (int)directoryEntry.EntryLength, retainPosition: true);
|
||||
var data = ReadRangeFromSource((int)directoryEntry.EntryOffset, (int)directoryEntry.EntryLength);
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user