diff --git a/SabreTools.Serialization/Wrappers/AACSMediaKeyBlock.cs b/SabreTools.Serialization/Wrappers/AACSMediaKeyBlock.cs
index 0c429e68..6ae70ba0 100644
--- a/SabreTools.Serialization/Wrappers/AACSMediaKeyBlock.cs
+++ b/SabreTools.Serialization/Wrappers/AACSMediaKeyBlock.cs
@@ -27,13 +27,21 @@ namespace SabreTools.Serialization.Wrappers
{
get
{
+ // Use the cached value, if it exists
+ if (field != null)
+ return field;
+
+ // Find the type and version record, if possible
var record = Array.Find(Records, r => r.RecordType == RecordType.TypeAndVersion);
if (record is TypeAndVersionRecord tavr)
- return tavr.VersionNumber.ToString();
+ {
+ field = tavr.VersionNumber.ToString();
+ return field;
+ }
- return null;
+ return field;
}
- }
+ } = null;
#endregion
diff --git a/SabreTools.Serialization/Wrappers/CFB.cs b/SabreTools.Serialization/Wrappers/CFB.cs
index 0a068289..59f36f91 100644
--- a/SabreTools.Serialization/Wrappers/CFB.cs
+++ b/SabreTools.Serialization/Wrappers/CFB.cs
@@ -41,7 +41,7 @@ namespace SabreTools.Serialization.Wrappers
return field;
// If there are no directory entries
- if (DirectoryEntries == null || DirectoryEntries.Length == 0)
+ if (DirectoryEntries.Length == 0)
return [];
// Get the mini stream offset from root object
@@ -56,12 +56,12 @@ namespace SabreTools.Serialization.Wrappers
///
/// Normal sector size in bytes
///
- public long SectorSize => (long)Math.Pow(2, Header?.SectorShift ?? 0);
+ public long SectorSize => (long)Math.Pow(2, Header.SectorShift);
///
/// Mini sector size in bytes
///
- public long MiniSectorSize => (long)Math.Pow(2, Header?.MiniSectorShift ?? 0);
+ public long MiniSectorSize => (long)Math.Pow(2, Header.MiniSectorShift);
#endregion
diff --git a/SabreTools.Serialization/Wrappers/GCF.cs b/SabreTools.Serialization/Wrappers/GCF.cs
index d7c952d1..adaa4b17 100644
--- a/SabreTools.Serialization/Wrappers/GCF.cs
+++ b/SabreTools.Serialization/Wrappers/GCF.cs
@@ -24,7 +24,7 @@ namespace SabreTools.Serialization.Wrappers
{
get
{
- // Use the cached value if we have it
+ // Use the cached value, if it exists
if (field != null)
return field;
@@ -48,14 +48,10 @@ namespace SabreTools.Serialization.Wrappers
{
get
{
- // Use the cached value if we have it
+ // Use the cached value, if it exists
if (field != null)
return field;
- // If we don't have a required property
- if (Model.DirectoryEntries == null || Model.DirectoryMapEntries == null)
- return null;
-
// Otherwise, scan and build the files
var files = new List();
for (int i = 0; i < Model.DirectoryEntries.Length; i++)
@@ -82,7 +78,7 @@ namespace SabreTools.Serialization.Wrappers
Encrypted = directoryEntry.DirectoryFlags.HasFlag(Data.Models.GCF.HL_GCF_FLAG.HL_GCF_FLAG_ENCRYPTED),
#endif
};
- var pathParts = new List { Model.DirectoryNames![directoryEntry.NameOffset] ?? string.Empty };
+ var pathParts = new List { Model.DirectoryNames[directoryEntry.NameOffset] ?? string.Empty };
var blockEntries = new List();
// Traverse the parent tree
@@ -90,7 +86,7 @@ namespace SabreTools.Serialization.Wrappers
while (index != 0xFFFFFFFF)
{
var parentDirectoryEntry = Model.DirectoryEntries[index];
- pathParts.Add(Model.DirectoryNames![parentDirectoryEntry.NameOffset] ?? string.Empty);
+ pathParts.Add(Model.DirectoryNames[parentDirectoryEntry.NameOffset] ?? string.Empty);
index = parentDirectoryEntry.ParentIndex;
}
diff --git a/SabreTools.Serialization/Wrappers/GZip.cs b/SabreTools.Serialization/Wrappers/GZip.cs
index bc19274d..97e0f34b 100644
--- a/SabreTools.Serialization/Wrappers/GZip.cs
+++ b/SabreTools.Serialization/Wrappers/GZip.cs
@@ -27,11 +27,16 @@ namespace SabreTools.Serialization.Wrappers
if (!IsTorrentGZip)
return null;
+ // Use the cached value, if it exists
+ if (field != null)
+ return field;
+
// CRC-32 is the second packed field
int extraIndex = 0x10;
- return Header.ExtraFieldBytes.ReadBytes(ref extraIndex, 0x04);
+ field = Header.ExtraFieldBytes.ReadBytes(ref extraIndex, 0x04);
+ return field;
}
- }
+ } = null;
///
/// Content MD5 as stored in the extra field
@@ -45,11 +50,16 @@ namespace SabreTools.Serialization.Wrappers
if (!IsTorrentGZip)
return null;
+ // Use the cached value, if it exists
+ if (field != null)
+ return field;
+
// MD5 is the first packed field
int extraIndex = 0x00;
- return Header.ExtraFieldBytes.ReadBytes(ref extraIndex, 0x10);
+ field = Header.ExtraFieldBytes.ReadBytes(ref extraIndex, 0x10);
+ return field;
}
- }
+ } = null;
///
/// Content size as stored in the extra field
@@ -63,11 +73,16 @@ namespace SabreTools.Serialization.Wrappers
if (!IsTorrentGZip)
return 0;
- // MD5 is the first packed field
- int extraIndex = 0x00;
- return Header.ExtraFieldBytes.ReadUInt64LittleEndian(ref extraIndex);
+ // Use the cached value, if it exists
+ if (field > 0)
+ return field;
+
+ // Size is the third packed field
+ int extraIndex = 0x14;
+ field = Header.ExtraFieldBytes.ReadUInt64LittleEndian(ref extraIndex);
+ return field;
}
- }
+ } = 0;
///
/// Offset to the compressed data
@@ -77,6 +92,7 @@ namespace SabreTools.Serialization.Wrappers
{
get
{
+ // Use the cached value, if it exists
if (field > -1)
return field;
diff --git a/SabreTools.Serialization/Wrappers/LinearExecutable.cs b/SabreTools.Serialization/Wrappers/LinearExecutable.cs
index 770ebcc0..c35ef588 100644
--- a/SabreTools.Serialization/Wrappers/LinearExecutable.cs
+++ b/SabreTools.Serialization/Wrappers/LinearExecutable.cs
@@ -17,16 +17,49 @@ namespace SabreTools.Serialization.Wrappers
#region Extension Properties
///
- public InformationBlock? InformationBlock => Model.InformationBlock;
+ public InformationBlock InformationBlock => Model.InformationBlock;
///
- public ObjectPageMapEntry[]? ObjectPageMap => Model.ObjectPageMap;
+ public ObjectPageMapEntry[] ObjectPageMap => Model.ObjectPageMap;
///
- public ResourceTableEntry[]? ResourceTable => Model.ResourceTable;
+ public ResourceTableEntry[] ResourceTable => Model.ResourceTable;
///
- public Data.Models.MSDOS.Executable? Stub => Model.Stub;
+ public Data.Models.MSDOS.Executable Stub => Model.Stub;
+
+ ///
+ /// Stub executable data, if it exists
+ ///
+ public byte[] StubExecutableData
+ {
+ get
+ {
+ lock (_stubExecutableDataLock)
+ {
+ // If we already have cached data, just use that immediately
+ if (field != null)
+ return field;
+
+ // Populate the raw stub executable data based on the source
+ int endOfStubHeader = 0x40;
+ int lengthOfStubExecutableData = (int)Stub.Header.NewExeHeaderAddr - endOfStubHeader;
+ field = ReadRangeFromSource(endOfStubHeader, lengthOfStubExecutableData);
+
+ // Cache and return the stub executable data, even if null
+ return field;
+ }
+ }
+ } = null;
+
+ #endregion
+
+ #region Instance Variables
+
+ ///
+ /// Lock object for
+ ///
+ private readonly object _stubExecutableDataLock = new();
#endregion
diff --git a/SabreTools.Serialization/Wrappers/PortableExecutable.cs b/SabreTools.Serialization/Wrappers/PortableExecutable.cs
index e3675dc5..37885348 100644
--- a/SabreTools.Serialization/Wrappers/PortableExecutable.cs
+++ b/SabreTools.Serialization/Wrappers/PortableExecutable.cs
@@ -34,19 +34,19 @@ namespace SabreTools.Serialization.Wrappers
lock (_debugDataLock)
{
// Use the cached data if possible
- if (_debugData.Count != 0)
- return _debugData;
+ if (field.Count != 0)
+ return field;
// If we have no resource table, just return
if (DebugDirectoryTable == null || DebugDirectoryTable.Length == 0)
- return _debugData;
+ return field;
// Otherwise, build and return the cached dictionary
- ParseDebugTable();
- return _debugData;
+ field = ParseDebugTable();
+ return field;
}
}
- }
+ } = [];
///
public Data.Models.PortableExecutable.DebugData.Entry[]? DebugDirectoryTable
@@ -822,12 +822,7 @@ namespace SabreTools.Serialization.Wrappers
#region Instance Variables
///
- /// Cached debug data
- ///
- private readonly Dictionary _debugData = [];
-
- ///
- /// Lock object for
+ /// Lock object for
///
private readonly object _debugDataLock = new();
@@ -1200,11 +1195,14 @@ namespace SabreTools.Serialization.Wrappers
///
/// Parse the debug directory table information
///
- private void ParseDebugTable()
+ private Dictionary ParseDebugTable()
{
// If there is no debug table
if (DebugDirectoryTable == null || DebugDirectoryTable.Length == 0)
- return;
+ return [];
+
+ // Create a new debug table
+ Dictionary debugData = [];
// Loop through all debug table entries
for (int i = 0; i < DebugDirectoryTable.Length; i++)
@@ -1223,7 +1221,7 @@ namespace SabreTools.Serialization.Wrappers
}
catch (EndOfStreamException)
{
- return;
+ return debugData;
}
// If we have CodeView debug data, try to parse it
@@ -1242,7 +1240,7 @@ namespace SabreTools.Serialization.Wrappers
var nb10ProgramDatabase = entryData.ParseNB10ProgramDatabase(ref offset);
if (nb10ProgramDatabase != null)
{
- _debugData[i] = nb10ProgramDatabase;
+ debugData[i] = nb10ProgramDatabase;
continue;
}
}
@@ -1253,16 +1251,18 @@ namespace SabreTools.Serialization.Wrappers
var rsdsProgramDatabase = entryData.ParseRSDSProgramDatabase(ref offset);
if (rsdsProgramDatabase != null)
{
- _debugData[i] = rsdsProgramDatabase;
+ debugData[i] = rsdsProgramDatabase;
continue;
}
}
}
else
{
- _debugData[i] = entryData;
+ debugData[i] = entryData;
}
}
+
+ return debugData;
}
#endregion
diff --git a/SabreTools.Serialization/Wrappers/VPK.cs b/SabreTools.Serialization/Wrappers/VPK.cs
index bf3768fa..a5f11a01 100644
--- a/SabreTools.Serialization/Wrappers/VPK.cs
+++ b/SabreTools.Serialization/Wrappers/VPK.cs
@@ -22,7 +22,7 @@ namespace SabreTools.Serialization.Wrappers
{
get
{
- // Use the cached value if we have it
+ // Use the cached value, if it exists
if (field != null)
return field;