diff --git a/SabreTools.Serialization/Deserializers/AACS.cs b/SabreTools.Serialization/Deserializers/AACS.cs
index 52a50973..b441e3bc 100644
--- a/SabreTools.Serialization/Deserializers/AACS.cs
+++ b/SabreTools.Serialization/Deserializers/AACS.cs
@@ -1,4 +1,3 @@
-using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
@@ -20,9 +19,6 @@ namespace SabreTools.Serialization.Deserializers
if (data.Position < 0 || data.Position >= data.Length)
return null;
- // Cache the current offset
- int initialOffset = (int)data.Position;
-
// Create a new media key block to fill
var mediaKeyBlock = new MediaKeyBlock();
@@ -73,38 +69,27 @@ namespace SabreTools.Serialization.Deserializers
/// Filled record on success, null on error
private static Record? ParseRecord(Stream data)
{
- // TODO: Use marshalling here instead of building
-
// The first 4 bytes make up the type and length
- byte[]? typeAndLength = data.ReadBytes(4);
- if (typeAndLength == null)
- return null;
-
- RecordType type = (RecordType)typeAndLength[0];
-
- // Remove the first byte and parse as big-endian
- typeAndLength[0] = 0x00;
- Array.Reverse(typeAndLength);
- uint length = BitConverter.ToUInt32(typeAndLength, 0);
+ RecordType type = (RecordType)data.ReadByteValue();
+ uint length = data.ReadUInt24();
// Create a record based on the type
- switch (type)
+ return type switch
{
- // Recognized record types
- case RecordType.EndOfMediaKeyBlock: return ParseEndOfMediaKeyBlockRecord(data, type, length);
- case RecordType.ExplicitSubsetDifference: return ParseExplicitSubsetDifferenceRecord(data, type, length);
- case RecordType.MediaKeyData: return ParseMediaKeyDataRecord(data, type, length);
- case RecordType.SubsetDifferenceIndex: return ParseSubsetDifferenceIndexRecord(data, type, length);
- case RecordType.TypeAndVersion: return ParseTypeAndVersionRecord(data, type, length);
- case RecordType.DriveRevocationList: return ParseDriveRevocationListRecord(data, type, length);
- case RecordType.HostRevocationList: return ParseHostRevocationListRecord(data, type, length);
- case RecordType.VerifyMediaKey: return ParseVerifyMediaKeyRecord(data, type, length);
- case RecordType.Copyright: return ParseCopyrightRecord(data, type, length);
-
- // Unrecognized record type
- default:
- return null;
- }
+ // Known record types
+ RecordType.EndOfMediaKeyBlock => ParseEndOfMediaKeyBlockRecord(data, type, length),
+ RecordType.ExplicitSubsetDifference => ParseExplicitSubsetDifferenceRecord(data, type, length),
+ RecordType.MediaKeyData => ParseMediaKeyDataRecord(data, type, length),
+ RecordType.SubsetDifferenceIndex => ParseSubsetDifferenceIndexRecord(data, type, length),
+ RecordType.TypeAndVersion => ParseTypeAndVersionRecord(data, type, length),
+ RecordType.DriveRevocationList => ParseDriveRevocationListRecord(data, type, length),
+ RecordType.HostRevocationList => ParseHostRevocationListRecord(data, type, length),
+ RecordType.VerifyMediaKey => ParseVerifyMediaKeyRecord(data, type, length),
+ RecordType.Copyright => ParseCopyrightRecord(data, type, length),
+
+ // Unknown record type
+ _ => null,
+ };
}
///
@@ -118,7 +103,6 @@ namespace SabreTools.Serialization.Deserializers
if (type != RecordType.EndOfMediaKeyBlock)
return null;
- // TODO: Use marshalling here instead of building
var record = new EndOfMediaKeyBlockRecord();
record.RecordType = type;
@@ -140,7 +124,6 @@ namespace SabreTools.Serialization.Deserializers
if (type != RecordType.ExplicitSubsetDifference)
return null;
- // TODO: Use marshalling here instead of building
var record = new ExplicitSubsetDifferenceRecord();
record.RecordType = type;
@@ -184,7 +167,6 @@ namespace SabreTools.Serialization.Deserializers
if (type != RecordType.MediaKeyData)
return null;
- // TODO: Use marshalling here instead of building
var record = new MediaKeyDataRecord();
record.RecordType = type;
@@ -221,7 +203,6 @@ namespace SabreTools.Serialization.Deserializers
if (type != RecordType.SubsetDifferenceIndex)
return null;
- // TODO: Use marshalling here instead of building
var record = new SubsetDifferenceIndexRecord();
record.RecordType = type;
@@ -259,7 +240,6 @@ namespace SabreTools.Serialization.Deserializers
if (type != RecordType.TypeAndVersion)
return null;
- // TODO: Use marshalling here instead of building
var record = new TypeAndVersionRecord();
record.RecordType = type;
@@ -281,7 +261,6 @@ namespace SabreTools.Serialization.Deserializers
if (type != RecordType.DriveRevocationList)
return null;
- // TODO: Use marshalling here instead of building
var record = new DriveRevocationListRecord();
record.RecordType = type;
@@ -342,7 +321,6 @@ namespace SabreTools.Serialization.Deserializers
if (type != RecordType.HostRevocationList)
return null;
- // TODO: Use marshalling here instead of building
var record = new HostRevocationListRecord();
record.RecordType = type;
@@ -403,7 +381,6 @@ namespace SabreTools.Serialization.Deserializers
if (type != RecordType.VerifyMediaKey)
return null;
- // TODO: Use marshalling here instead of building
var record = new VerifyMediaKeyRecord();
record.RecordType = type;
@@ -424,7 +401,6 @@ namespace SabreTools.Serialization.Deserializers
if (type != RecordType.Copyright)
return null;
- // TODO: Use marshalling here instead of building
var record = new CopyrightRecord();
record.RecordType = type;
diff --git a/SabreTools.Serialization/Deserializers/BDPlus.cs b/SabreTools.Serialization/Deserializers/BDPlus.cs
index b07bb6f6..b9b0dbfb 100644
--- a/SabreTools.Serialization/Deserializers/BDPlus.cs
+++ b/SabreTools.Serialization/Deserializers/BDPlus.cs
@@ -56,8 +56,8 @@ namespace SabreTools.Serialization.Deserializers
svm.Unknown2 = data.ReadBytes(4);
svm.Length = data.ReadUInt32();
- // if (svm.Length > 0)
- // svm.Data = data.ReadBytes((int)svm.Length);
+ if (svm.Length > 0)
+ svm.Data = data.ReadBytes((int)svm.Length);
return svm;
}
diff --git a/SabreTools.Serialization/Deserializers/BFPK.cs b/SabreTools.Serialization/Deserializers/BFPK.cs
index d3607500..8a567505 100644
--- a/SabreTools.Serialization/Deserializers/BFPK.cs
+++ b/SabreTools.Serialization/Deserializers/BFPK.cs
@@ -40,24 +40,21 @@ namespace SabreTools.Serialization.Deserializers
#region Files
// If we have any files
- if (header.Files > 0)
+ var files = new FileEntry[header.Files];
+
+ // Read all entries in turn
+ for (int i = 0; i < header.Files; i++)
{
- var files = new FileEntry[header.Files];
+ var file = ParseFileEntry(data);
+ if (file == null)
+ return null;
- // Read all entries in turn
- for (int i = 0; i < header.Files; i++)
- {
- var file = ParseFileEntry(data);
- if (file == null)
- return null;
-
- files[i] = file;
- }
-
- // Set the files
- archive.Files = files;
+ files[i] = file;
}
+ // Set the files
+ archive.Files = files;
+
#endregion
return archive;
@@ -72,9 +69,7 @@ namespace SabreTools.Serialization.Deserializers
{
var header = data.ReadType();
- if (header == null)
- return null;
- if (header.Magic != SignatureString)
+ if (header?.Magic != SignatureString)
return null;
return header;
diff --git a/SabreTools.Serialization/Deserializers/BSP.cs b/SabreTools.Serialization/Deserializers/BSP.cs
index 04cde230..01c89f71 100644
--- a/SabreTools.Serialization/Deserializers/BSP.cs
+++ b/SabreTools.Serialization/Deserializers/BSP.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
@@ -20,9 +21,6 @@ namespace SabreTools.Serialization.Deserializers
if (data.Position < 0 || data.Position >= data.Length)
return null;
- // Cache the current offset
- int initialOffset = (int)data.Position;
-
// Create a new Half-Life Level to fill
var file = new BspFile();
@@ -40,326 +38,71 @@ namespace SabreTools.Serialization.Deserializers
#region Lumps
- // LUMP_ENTITIES [0]
- var lumpEntry = header.Lumps[(int)LumpType.LUMP_ENTITIES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
+ for (int l = 0; l < BSP_HEADER_LUMPS; l++)
{
+ // Get the next lump entry
+ var lumpEntry = header.Lumps[l];
+ if (lumpEntry == null)
+ continue;
+ if (lumpEntry.Offset == 0 || lumpEntry.Length == 0)
+ continue;
+
// Seek to the lump offset
data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
- // Read the lump data
- var entities = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
+ // Read according to the lump type
+ switch ((LumpType)l)
{
- // TODO: Read this into sets of key-value pairs
- var sb = new StringBuilder();
- char c = '\0';
- do
- {
- c = (char)data.ReadByteValue();
- sb.Append(c);
- } while (c != '}');
-
- var entity = new Entity();
- entity.Attributes = new List>
- {
- new("REPLACE", sb.ToString()),
- };
- entities.Add(entity);
+ case LumpType.LUMP_ENTITIES:
+ file.Entities = ParseEntitiesLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_PLANES:
+ file.PlanesLump = ParsePlanesLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_TEXTURES:
+ file.TextureLump = ParseTextureLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_VERTICES:
+ file.VerticesLump = ParseVerticesLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_VISIBILITY:
+ // TODO: Assign when Models supports it
+ _ = ParseVisibilityLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_NODES:
+ file.NodesLump = ParseNodesLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_TEXINFO:
+ file.TexinfoLump = ParseTexinfoLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_FACES:
+ file.FacesLump = ParseFacesLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_LIGHTING:
+ file.LightmapLump = ParseLightmapLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_CLIPNODES:
+ file.ClipnodesLump = ParseClipnodesLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_LEAVES:
+ file.LeavesLump = ParseLeavesLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_MARKSURFACES:
+ file.MarksurfacesLump = ParseMarksurfacesLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_EDGES:
+ file.EdgesLump = ParseEdgesLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_SURFEDGES:
+ file.SurfedgesLump = ParseSurfedgesLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_MODELS:
+ file.ModelsLump = ParseModelsLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ default:
+ // Unsupported LumpType value, ignore
+ break;
}
-
- var lump = new EntitiesLump();
- lump.Entities = [.. entities];
-
- file.Entities = lump;
- }
-
- // LUMP_PLANES [1]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_PLANES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var planes = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var plane = data.ReadType();
- if (plane != null)
- planes.Add(plane);
- }
-
- var lump = new PlanesLump();
- lump.Planes = [.. planes];
-
- file.PlanesLump = lump;
- }
-
- // LUMP_TEXTURES [2]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_TEXTURES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the header
- var lump = new TextureLump();
- lump.Header = ParseTextureHeader(data);
-
- // Read the lump data
- var textures = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var texture = data.ReadType();
- if (texture != null)
- textures.Add(texture);
- }
-
- lump.Textures = [.. textures];
-
- file.TextureLump = lump;
- }
-
- // LUMP_VERTICES [3]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_VERTICES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var vertices = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- vertices.Add(data.ReadType());
- }
-
- var lump = new VerticesLump();
- lump.Vertices = [.. vertices];
-
- file.VerticesLump = lump;
- }
-
- // LUMP_VISIBILITY [4]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_VISIBILITY];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // TODO: Parse LUMP_VISIBILITY when added to model
- }
-
- // LUMP_NODES [5]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_NODES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var nodes = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var node = data.ReadType();
- if (node != null)
- nodes.Add(node);
- }
-
- var lump = new BspNodesLump();
- lump.Nodes = [.. nodes];
-
- file.NodesLump = lump;
- }
-
- // LUMP_TEXINFO [6]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_TEXINFO];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var texinfos = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var texinfo = data.ReadType();
- if (texinfo != null)
- texinfos.Add(texinfo);
- }
-
- var lump = new BspTexinfoLump();
- lump.Texinfos = [.. texinfos];
-
- file.TexinfoLump = lump;
- }
-
- // LUMP_FACES [7]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_FACES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var faces = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var face = data.ReadType();
- if (face != null)
- faces.Add(face);
- }
-
- var lump = new BspFacesLump();
- lump.Faces = [.. faces];
-
- file.FacesLump = lump;
- }
-
- // LUMP_LIGHTING [8]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_LIGHTING];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var lump = new LightmapLump();
- lump.Lightmap = new byte[lumpEntry.Length / 3, 3];
-
- for (int i = 0; i < lumpEntry.Length / 3; i++)
- for (int j = 0; j < 3; j++)
- {
- lump.Lightmap[i, j] = data.ReadByteValue();
- }
-
- file.LightmapLump = lump;
- }
-
- // LUMP_CLIPNODES [9]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_CLIPNODES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var clipnodes = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var clipnode = data.ReadType();
- if (clipnode != null)
- clipnodes.Add(clipnode);
- }
-
- var lump = new ClipnodesLump();
- lump.Clipnodes = [.. clipnodes];
-
- file.ClipnodesLump = lump;
- }
-
- // LUMP_LEAVES [10]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_LEAVES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var leaves = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var leaf = data.ReadType();
- if (leaf != null)
- leaves.Add(leaf);
- }
-
- var lump = new BspLeavesLump();
- lump.Leaves = [.. leaves];
-
- file.LeavesLump = lump;
- }
-
- // LUMP_MARKSURFACES [11]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_MARKSURFACES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var marksurfaces = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- marksurfaces.Add(data.ReadUInt16());
- }
-
- var lump = new MarksurfacesLump();
- lump.Marksurfaces = [.. marksurfaces];
-
- file.MarksurfacesLump = lump;
- }
-
- // LUMP_EDGES [12]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_EDGES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var edges = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var edge = data.ReadType();
- if (edge != null)
- edges.Add(edge);
- }
-
- var lump = new EdgesLump();
- lump.Edges = [.. edges];
-
- file.EdgesLump = lump;
- }
-
- // LUMP_SURFEDGES [13]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_SURFEDGES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var surfedges = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- surfedges.Add(data.ReadInt32());
- }
-
- var lump = new SurfedgesLump();
- lump.Surfedges = [.. surfedges];
-
- file.SurfedgesLump = lump;
- }
-
- // LUMP_MODELS [14]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_MODELS];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var models = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var model = data.ReadType();
- if (model != null)
- models.Add(model);
- }
-
- var lump = new BspModelsLump();
- lump.Models = [.. models];
-
- file.ModelsLump = lump;
}
#endregion
@@ -391,6 +134,88 @@ namespace SabreTools.Serialization.Deserializers
return header;
}
+ ///
+ /// Parse a Stream into LUMP_ENTITIES
+ ///
+ /// Stream to parse
+ /// Filled LUMP_ENTITIES on success, null on error
+ private static EntitiesLump? ParseEntitiesLump(Stream data, int offset, int length)
+ {
+ var entities = new List();
+
+ // Read the entire lump as text
+ byte[] lumpData = data.ReadBytes(length);
+ string lumpText = Encoding.ASCII.GetString(lumpData);
+
+ // Break the text by ending curly braces
+ string[] lumpSections = lumpText.Split('}');
+ Array.ForEach(lumpSections, s => s.Trim('{', '}'));
+
+ // Loop through all sections
+ for (int i = 0; i < lumpSections.Length; i++)
+ {
+ // Prepare an attributes list
+ var attributes = new List>();
+
+ // Split the section by newlines
+ string section = lumpSections[i];
+ string[] lines = section.Split('\n');
+ Array.ForEach(lines, l => l.Trim());
+
+ // Convert each line into a key-value pair and add
+ for (int j = 0; j < lines.Length; j++)
+ {
+ // TODO: Split lines and add
+ }
+
+ // Create a new entity and add
+ var entity = new Entity { Attributes = attributes };
+ entities.Add(entity);
+ }
+
+ return new EntitiesLump { Entities = [.. entities] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_PLANES
+ ///
+ /// Stream to parse
+ /// Filled LUMP_PLANES on success, null on error
+ private static PlanesLump? ParsePlanesLump(Stream data, int offset, int length)
+ {
+ var planes = new List();
+ while (data.Position < offset + length)
+ {
+ var plane = data.ReadType();
+ if (plane != null)
+ planes.Add(plane);
+ }
+
+ return new PlanesLump { Planes = [.. planes] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_TEXTURES
+ ///
+ /// Stream to parse
+ /// Filled LUMP_TEXTURES on success, null on error
+ private static TextureLump? ParseTextureLump(Stream data, int offset, int length)
+ {
+ var lump = new TextureLump();
+
+ lump.Header = ParseTextureHeader(data);
+ var textures = new List();
+ while (data.Position < offset + length)
+ {
+ var texture = data.ReadType();
+ if (texture != null)
+ textures.Add(texture);
+ }
+
+ lump.Textures = [.. textures];
+ return lump;
+ }
+
///
/// Parse a Stream into a Half-Life Level texture header
///
@@ -410,5 +235,222 @@ namespace SabreTools.Serialization.Deserializers
return textureHeader;
}
+
+ ///
+ /// Parse a Stream into LUMP_VERTICES
+ ///
+ /// Stream to parse
+ /// Filled LUMP_VERTICES on success, null on error
+ private static VerticesLump? ParseVerticesLump(Stream data, int offset, int length)
+ {
+ var vertices = new List();
+ while (data.Position < offset + length)
+ {
+ vertices.Add(data.ReadType());
+ }
+
+ return new VerticesLump { Vertices = [.. vertices] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_VISIBILITY
+ ///
+ /// Stream to parse
+ /// Filled LUMP_VISIBILITY on success, null on error
+ private static VisibilityLump? ParseVisibilityLump(Stream data, int offset, int length)
+ {
+ var lump = new VisibilityLump();
+
+ lump.NumClusters = data.ReadInt32();
+ lump.ByteOffsets = new int[lump.NumClusters, 2];
+ for (int i = 0; i < lump.NumClusters; i++)
+ {
+ for (int j = 0; j < 2; j++)
+ {
+ lump.ByteOffsets[i, j] = data.ReadInt32();
+ }
+ }
+
+ return lump;
+ }
+
+ ///
+ /// Parse a Stream into LUMP_NODES
+ ///
+ /// Stream to parse
+ /// Filled LUMP_NODES on success, null on error
+ private static BspNodesLump? ParseNodesLump(Stream data, int offset, int length)
+ {
+ var nodes = new List();
+ while (data.Position < offset + length)
+ {
+ var node = data.ReadType();
+ if (node != null)
+ nodes.Add(node);
+ }
+
+ return new BspNodesLump { Nodes = [.. nodes] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_TEXINFO
+ ///
+ /// Stream to parse
+ /// Filled LUMP_TEXINFO on success, null on error
+ private static BspTexinfoLump? ParseTexinfoLump(Stream data, int offset, int length)
+ {
+ var texinfos = new List();
+ while (data.Position < offset + length)
+ {
+ var texinfo = data.ReadType();
+ if (texinfo != null)
+ texinfos.Add(texinfo);
+ }
+
+ return new BspTexinfoLump { Texinfos = [.. texinfos] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_FACES
+ ///
+ /// Stream to parse
+ /// Filled LUMP_FACES on success, null on error
+ private static BspFacesLump? ParseFacesLump(Stream data, int offset, int length)
+ {
+ var faces = new List();
+ while (data.Position < offset + length)
+ {
+ var face = data.ReadType();
+ if (face != null)
+ faces.Add(face);
+ }
+
+ return new BspFacesLump { Faces = [.. faces] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_LIGHTING
+ ///
+ /// Stream to parse
+ /// Filled LUMP_LIGHTING on success, null on error
+ private static LightmapLump? ParseLightmapLump(Stream data, int offset, int length)
+ {
+ var lump = new LightmapLump();
+ lump.Lightmap = new byte[length / 3, 3];
+
+ for (int i = 0; i < length / 3; i++)
+ {
+ for (int j = 0; j < 3; j++)
+ {
+ lump.Lightmap[i, j] = data.ReadByteValue();
+ }
+ }
+
+ return lump;
+ }
+
+ ///
+ /// Parse a Stream into LUMP_CLIPNODES
+ ///
+ /// Stream to parse
+ /// Filled LUMP_CLIPNODES on success, null on error
+ private static ClipnodesLump? ParseClipnodesLump(Stream data, int offset, int length)
+ {
+ var clipnodes = new List();
+ while (data.Position < offset + length)
+ {
+ var clipnode = data.ReadType();
+ if (clipnode != null)
+ clipnodes.Add(clipnode);
+ }
+
+ return new ClipnodesLump { Clipnodes = [.. clipnodes] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_LEAVES
+ ///
+ /// Stream to parse
+ /// Filled LUMP_LEAVES on success, null on error
+ private static BspLeavesLump? ParseLeavesLump(Stream data, int offset, int length)
+ {
+ var leaves = new List();
+ while (data.Position < offset + length)
+ {
+ var leaf = data.ReadType();
+ if (leaf != null)
+ leaves.Add(leaf);
+ }
+
+ return new BspLeavesLump { Leaves = [.. leaves] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_MARKSURFACES
+ ///
+ /// Stream to parse
+ /// Filled LUMP_MARKSURFACES on success, null on error
+ private static MarksurfacesLump? ParseMarksurfacesLump(Stream data, int offset, int length)
+ {
+ var marksurfaces = new List();
+ while (data.Position < offset + length)
+ {
+ marksurfaces.Add(data.ReadUInt16());
+ }
+
+ return new MarksurfacesLump { Marksurfaces = [.. marksurfaces] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_EDGES
+ ///
+ /// Stream to parse
+ /// Filled LUMP_EDGES on success, null on error
+ private static EdgesLump? ParseEdgesLump(Stream data, int offset, int length)
+ {
+ var edges = new List();
+ while (data.Position < offset + length)
+ {
+ var edge = data.ReadType();
+ if (edge != null)
+ edges.Add(edge);
+ }
+
+ return new EdgesLump { Edges = [.. edges] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_SURFEDGES
+ ///
+ /// Stream to parse
+ /// Filled LUMP_SURFEDGES on success, null on error
+ private static SurfedgesLump? ParseSurfedgesLump(Stream data, int offset, int length)
+ {
+ var surfedges = new List();
+ while (data.Position < offset + length)
+ {
+ surfedges.Add(data.ReadInt32());
+ }
+
+ return new SurfedgesLump { Surfedges = [.. surfedges] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_MODELS
+ ///
+ /// Stream to parse
+ /// Filled LUMP_MODELS on success, null on error
+ private static BspModelsLump? ParseModelsLump(Stream data, int offset, int length)
+ {
+ var models = new List();
+ while (data.Position < offset + length)
+ {
+ var model = data.ReadType();
+ if (model != null)
+ models.Add(model);
+ }
+
+ return new BspModelsLump { Models = [.. models] };
+ }
}
}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Deserializers/CFB.cs b/SabreTools.Serialization/Deserializers/CFB.cs
index 75e6b933..cc92efd4 100644
--- a/SabreTools.Serialization/Deserializers/CFB.cs
+++ b/SabreTools.Serialization/Deserializers/CFB.cs
@@ -21,9 +21,6 @@ namespace SabreTools.Serialization.Deserializers
if (data.Position < 0 || data.Position >= data.Length)
return null;
- // Cache the current offset
- int initialOffset = (int)data.Position;
-
// Create a new binary to fill
var binary = new Binary();
@@ -235,9 +232,7 @@ namespace SabreTools.Serialization.Deserializers
{
var header = data.ReadType();
- if (header == null)
- return null;
- if (header.Signature != SignatureUInt64)
+ if (header?.Signature != SignatureUInt64)
return null;
if (header.ByteOrder != 0xFFFE)
return null;
diff --git a/SabreTools.Serialization/Deserializers/CIA.cs b/SabreTools.Serialization/Deserializers/CIA.cs
index a5ee3d1e..96add723 100644
--- a/SabreTools.Serialization/Deserializers/CIA.cs
+++ b/SabreTools.Serialization/Deserializers/CIA.cs
@@ -19,9 +19,6 @@ namespace SabreTools.Serialization.Deserializers
if (data.Position < 0 || data.Position >= data.Length)
return null;
- // Cache the current offset
- int initialOffset = (int)data.Position;
-
// Create a new CIA archive to fill
var cia = new Models.N3DS.CIA();
diff --git a/SabreTools.Serialization/Deserializers/GCF.cs b/SabreTools.Serialization/Deserializers/GCF.cs
index c2e7cca1..895f6bf4 100644
--- a/SabreTools.Serialization/Deserializers/GCF.cs
+++ b/SabreTools.Serialization/Deserializers/GCF.cs
@@ -1,4 +1,3 @@
-using System.Collections.Generic;
using System.IO;
using System.Text;
using SabreTools.IO.Extensions;
@@ -173,7 +172,7 @@ namespace SabreTools.Serialization.Deserializers
long directoryNamesEnd = data.Position + directoryHeader.NameSize;
// Create the string dictionary
- file.DirectoryNames = new Dictionary();
+ file.DirectoryNames = [];
// Loop and read the null-terminated strings
while (data.Position < directoryNamesEnd)
@@ -184,10 +183,7 @@ namespace SabreTools.Serialization.Deserializers
{
data.Seek(-directoryName?.Length ?? 0, SeekOrigin.Current);
byte[]? endingData = data.ReadBytes((int)(directoryNamesEnd - data.Position));
- if (endingData != null)
- directoryName = Encoding.ASCII.GetString(endingData);
- else
- directoryName = null;
+ directoryName = endingData != null ? Encoding.ASCII.GetString(endingData) : null;
}
file.DirectoryNames[nameOffset] = directoryName;
diff --git a/SabreTools.Serialization/Deserializers/Hashfile.cs b/SabreTools.Serialization/Deserializers/Hashfile.cs
index d45d46b9..8dffd4ca 100644
--- a/SabreTools.Serialization/Deserializers/Hashfile.cs
+++ b/SabreTools.Serialization/Deserializers/Hashfile.cs
@@ -88,6 +88,8 @@ namespace SabreTools.Serialization.Deserializers
// Create lists for each hash type
var sfvList = new List();
+ var md2List = new List();
+ var md4List = new List();
var md5List = new List();
var sha1List = new List();
var sha256List = new List();
@@ -115,6 +117,22 @@ namespace SabreTools.Serialization.Deserializers
};
sfvList.Add(sfv);
break;
+ case HashType.MD2:
+ var md2 = new MD2
+ {
+ Hash = lineParts[0],
+ File = string.Join(" ", lineParts, 1, lineParts.Length - 1),
+ };
+ md2List.Add(md2);
+ break;
+ case HashType.MD4:
+ var md4 = new MD4
+ {
+ Hash = lineParts[0],
+ File = string.Join(" ", lineParts, 1, lineParts.Length - 1),
+ };
+ md4List.Add(md4);
+ break;
case HashType.MD5:
var md5 = new MD5
{
@@ -172,6 +190,12 @@ namespace SabreTools.Serialization.Deserializers
case HashType.CRC32:
dat.SFV = [.. sfvList];
break;
+ case HashType.MD2:
+ dat.MD2 = [.. md2List];
+ break;
+ case HashType.MD4:
+ dat.MD4 = [.. md4List];
+ break;
case HashType.MD5:
dat.MD5 = [.. md5List];
break;
diff --git a/SabreTools.Serialization/Deserializers/IRD.cs b/SabreTools.Serialization/Deserializers/IRD.cs
index 37686caa..5233033c 100644
--- a/SabreTools.Serialization/Deserializers/IRD.cs
+++ b/SabreTools.Serialization/Deserializers/IRD.cs
@@ -17,9 +17,6 @@ namespace SabreTools.Serialization.Deserializers
if (data.Position < 0 || data.Position >= data.Length)
return null;
- // Cache the current offset
- int initialOffset = (int)data.Position;
-
// Create a new IRD to fill
var ird = new Models.IRD.File();
diff --git a/SabreTools.Serialization/Deserializers/InstallShieldArchiveV3.cs b/SabreTools.Serialization/Deserializers/InstallShieldArchiveV3.cs
index 5fc303c6..d83c18af 100644
--- a/SabreTools.Serialization/Deserializers/InstallShieldArchiveV3.cs
+++ b/SabreTools.Serialization/Deserializers/InstallShieldArchiveV3.cs
@@ -18,9 +18,6 @@ namespace SabreTools.Serialization.Deserializers
if (data.Position < 0 || data.Position >= data.Length)
return null;
- // Cache the current offset
- int initialOffset = (int)data.Position;
-
// Create a new archive to fill
var archive = new Archive();
@@ -100,7 +97,7 @@ namespace SabreTools.Serialization.Deserializers
if (header == null)
return null;
- if (header.Signature1 != 0x8C655D13) // TODO: Move constant to Models
+ if (header?.Signature1 != Constants.HeaderSignature)
return null;
if (header.TocAddress >= data.Length)
return null;
diff --git a/SabreTools.Serialization/Deserializers/InstallShieldCabinet.cs b/SabreTools.Serialization/Deserializers/InstallShieldCabinet.cs
index e6d5cb0b..9f800490 100644
--- a/SabreTools.Serialization/Deserializers/InstallShieldCabinet.cs
+++ b/SabreTools.Serialization/Deserializers/InstallShieldCabinet.cs
@@ -21,9 +21,6 @@ namespace SabreTools.Serialization.Deserializers
if (data.Position < 0 || data.Position >= data.Length)
return null;
- // Cache the current offset
- int initialOffset = (int)data.Position;
-
// Create a new cabinet to fill
var cabinet = new Cabinet();
@@ -337,9 +334,7 @@ namespace SabreTools.Serialization.Deserializers
{
var commonHeader = data.ReadType();
- if (commonHeader == null)
- return null;
- if (commonHeader.Signature != SignatureString)
+ if (commonHeader?.Signature != SignatureString)
return null;
return commonHeader;
@@ -353,7 +348,7 @@ namespace SabreTools.Serialization.Deserializers
/// Filled volume header on success, null on error
public static VolumeHeader ParseVolumeHeader(Stream data, int majorVersion)
{
- VolumeHeader volumeHeader = new VolumeHeader();
+ var volumeHeader = new VolumeHeader();
// Read the descriptor based on version
if (majorVersion <= 5)
@@ -649,7 +644,7 @@ namespace SabreTools.Serialization.Deserializers
/// Filled file descriptor on success, null on error
public static FileDescriptor ParseFileDescriptor(Stream data, int majorVersion, uint descriptorOffset)
{
- FileDescriptor fileDescriptor = new FileDescriptor();
+ var fileDescriptor = new FileDescriptor();
// Read the descriptor based on version
if (majorVersion <= 5)
diff --git a/SabreTools.Serialization/Deserializers/LinearExecutable.cs b/SabreTools.Serialization/Deserializers/LinearExecutable.cs
index 8203b23d..3968de39 100644
--- a/SabreTools.Serialization/Deserializers/LinearExecutable.cs
+++ b/SabreTools.Serialization/Deserializers/LinearExecutable.cs
@@ -427,9 +427,7 @@ namespace SabreTools.Serialization.Deserializers
{
var informationBlock = data.ReadType();
- if (informationBlock == null)
- return null;
- if (informationBlock.Signature != LESignatureString && informationBlock.Signature != LXSignatureString)
+ if (informationBlock?.Signature != LESignatureString && informationBlock?.Signature != LXSignatureString)
return null;
return informationBlock;
diff --git a/SabreTools.Serialization/Deserializers/MoPaQ.cs b/SabreTools.Serialization/Deserializers/MoPaQ.cs
index 1596929f..220ce8fe 100644
--- a/SabreTools.Serialization/Deserializers/MoPaQ.cs
+++ b/SabreTools.Serialization/Deserializers/MoPaQ.cs
@@ -21,9 +21,6 @@ namespace SabreTools.Serialization.Deserializers
if (data.Position < 0 || data.Position >= data.Length)
return null;
- // Cache the current offset
- int initialOffset = (int)data.Position;
-
// Create a new archive to fill
var archive = new Archive();
@@ -32,7 +29,7 @@ namespace SabreTools.Serialization.Deserializers
// Check for User Data
uint possibleSignature = data.ReadUInt32();
data.Seek(-4, SeekOrigin.Current);
- if (possibleSignature == 0x1B51504D)
+ if (possibleSignature == UserDataSignatureUInt32)
{
// Save the current position for offset correction
long basePtr = data.Position;
@@ -56,7 +53,7 @@ namespace SabreTools.Serialization.Deserializers
// Check for the Header
possibleSignature = data.ReadUInt32();
data.Seek(-4, SeekOrigin.Current);
- if (possibleSignature == 0x1A51504D)
+ if (possibleSignature == ArchiveHeaderSignatureUInt32)
{
// Try to parse the archive header
var archiveHeader = ParseArchiveHeader(data);
@@ -406,9 +403,7 @@ namespace SabreTools.Serialization.Deserializers
{
var userData = data.ReadType();
- if (userData == null)
- return null;
- if (userData.Signature != UserDataSignatureString)
+ if (userData?.Signature != UserDataSignatureString)
return null;
return userData;
diff --git a/SabreTools.Serialization/Deserializers/N3DS.cs b/SabreTools.Serialization/Deserializers/N3DS.cs
index 470bce4e..d9455fe9 100644
--- a/SabreTools.Serialization/Deserializers/N3DS.cs
+++ b/SabreTools.Serialization/Deserializers/N3DS.cs
@@ -20,9 +20,6 @@ namespace SabreTools.Serialization.Deserializers
if (data.Position < 0 || data.Position >= data.Length)
return null;
- // Cache the current offset
- long initialOffset = data.Position;
-
// Create a new cart image to fill
var cart = new Cart();
diff --git a/SabreTools.Serialization/Deserializers/NCF.cs b/SabreTools.Serialization/Deserializers/NCF.cs
index 081981b6..6ab1bdc5 100644
--- a/SabreTools.Serialization/Deserializers/NCF.cs
+++ b/SabreTools.Serialization/Deserializers/NCF.cs
@@ -91,10 +91,7 @@ namespace SabreTools.Serialization.Deserializers
{
data.Seek(-directoryName?.Length ?? 0, SeekOrigin.Current);
byte[]? endingData = data.ReadBytes((int)(directoryNamesEnd - data.Position));
- if (endingData != null)
- directoryName = Encoding.ASCII.GetString(endingData);
- else
- directoryName = null;
+ directoryName = endingData != null ? Encoding.ASCII.GetString(endingData) : null;
}
file.DirectoryNames[nameOffset] = directoryName;
diff --git a/SabreTools.Serialization/Deserializers/NewExecutable.cs b/SabreTools.Serialization/Deserializers/NewExecutable.cs
index a83d1d65..54fcb960 100644
--- a/SabreTools.Serialization/Deserializers/NewExecutable.cs
+++ b/SabreTools.Serialization/Deserializers/NewExecutable.cs
@@ -214,9 +214,7 @@ namespace SabreTools.Serialization.Deserializers
{
var header = data.ReadType();
- if (header == null)
- return null;
- if (header.Magic != SignatureString)
+ if (header?.Magic != SignatureString)
return null;
return header;
diff --git a/SabreTools.Serialization/Deserializers/Nitro.cs b/SabreTools.Serialization/Deserializers/Nitro.cs
index 2397ce9c..b3eb122e 100644
--- a/SabreTools.Serialization/Deserializers/Nitro.cs
+++ b/SabreTools.Serialization/Deserializers/Nitro.cs
@@ -19,9 +19,6 @@ namespace SabreTools.Serialization.Deserializers
if (data.Position < 0 || data.Position >= data.Length)
return null;
- // Cache the current offset
- int initialOffset = (int)data.Position;
-
// Create a new cart image to fill
var cart = new Cart();
diff --git a/SabreTools.Serialization/Deserializers/PAK.cs b/SabreTools.Serialization/Deserializers/PAK.cs
index e8473a9a..6acb4570 100644
--- a/SabreTools.Serialization/Deserializers/PAK.cs
+++ b/SabreTools.Serialization/Deserializers/PAK.cs
@@ -18,9 +18,6 @@ namespace SabreTools.Serialization.Deserializers
if (data.Position < 0 || data.Position >= data.Length)
return null;
- // Cache the current offset
- long initialOffset = data.Position;
-
// Create a new Half-Life Package to fill
var file = new Models.PAK.File();
@@ -73,9 +70,7 @@ namespace SabreTools.Serialization.Deserializers
{
var header = data.ReadType();
- if (header == null)
- return null;
- if (header.Signature != SignatureString)
+ if (header?.Signature != SignatureString)
return null;
return header;
diff --git a/SabreTools.Serialization/Deserializers/PFF.cs b/SabreTools.Serialization/Deserializers/PFF.cs
index 8743ea6e..f9d287ec 100644
--- a/SabreTools.Serialization/Deserializers/PFF.cs
+++ b/SabreTools.Serialization/Deserializers/PFF.cs
@@ -1,5 +1,4 @@
using System.IO;
-using System.Runtime.InteropServices;
using System.Text;
using SabreTools.IO.Extensions;
using SabreTools.Models.PFF;
@@ -20,9 +19,6 @@ namespace SabreTools.Serialization.Deserializers
if (data.Position < 0 || data.Position >= data.Length)
return null;
- // Cache the current offset
- int initialOffset = (int)data.Position;
-
// Create a new archive to fill
var archive = new Archive();
@@ -56,7 +52,7 @@ namespace SabreTools.Serialization.Deserializers
{
var file = ParseSegment(data, header.FileSegmentSize);
if (file == null)
- return null;
+ continue;
archive.Segments[i] = file;
}
diff --git a/SabreTools.Serialization/Deserializers/PKZIP.cs b/SabreTools.Serialization/Deserializers/PKZIP.cs
index 33f3cd48..1f03c51b 100644
--- a/SabreTools.Serialization/Deserializers/PKZIP.cs
+++ b/SabreTools.Serialization/Deserializers/PKZIP.cs
@@ -168,7 +168,7 @@ namespace SabreTools.Serialization.Deserializers
#region Local File
// Setup all of the collections
- var localFileHeaders = new List();
+ var localFileHeaders = new List();
var encryptionHeaders = new List();
var fileData = new List(); // TODO: Should this data be read here?
var dataDescriptors = new List();
@@ -200,7 +200,7 @@ namespace SabreTools.Serialization.Deserializers
if (localFileHeader == null)
{
// Add a placeholder null item
- localFileHeaders.Add(null);
+ localFileHeaders.Add(new LocalFileHeader());
encryptionHeaders.Add(null);
fileData.Add([]);
dataDescriptors.Add(null);
diff --git a/SabreTools.Serialization/Deserializers/PlayJAudio.cs b/SabreTools.Serialization/Deserializers/PlayJAudio.cs
index 5534038b..c237cd60 100644
--- a/SabreTools.Serialization/Deserializers/PlayJAudio.cs
+++ b/SabreTools.Serialization/Deserializers/PlayJAudio.cs
@@ -303,7 +303,7 @@ namespace SabreTools.Serialization.Deserializers
private static UnknownBlock1 ParseUnknownBlock1(Stream data)
{
// TODO: Use marshalling here instead of building
- UnknownBlock1 unknownBlock1 = new UnknownBlock1();
+ var unknownBlock1 = new UnknownBlock1();
unknownBlock1.Length = data.ReadUInt32();
unknownBlock1.Data = data.ReadBytes((int)unknownBlock1.Length);
@@ -319,7 +319,7 @@ namespace SabreTools.Serialization.Deserializers
private static UnknownBlock3 ParseUnknownBlock3(Stream data)
{
// TODO: Use marshalling here instead of building
- UnknownBlock3 unknownBlock3 = new UnknownBlock3();
+ var unknownBlock3 = new UnknownBlock3();
// No-op because we don't even know the length
@@ -334,7 +334,7 @@ namespace SabreTools.Serialization.Deserializers
private static DataFile ParseDataFile(Stream data)
{
// TODO: Use marshalling here instead of building
- DataFile dataFile = new DataFile();
+ var dataFile = new DataFile();
dataFile.FileNameLength = data.ReadUInt16();
byte[]? fileName = data.ReadBytes(dataFile.FileNameLength);
diff --git a/SabreTools.Serialization/Deserializers/PlayJPlaylist.cs b/SabreTools.Serialization/Deserializers/PlayJPlaylist.cs
index 449a0b56..d7d08a15 100644
--- a/SabreTools.Serialization/Deserializers/PlayJPlaylist.cs
+++ b/SabreTools.Serialization/Deserializers/PlayJPlaylist.cs
@@ -17,9 +17,6 @@ namespace SabreTools.Serialization.Deserializers
if (data.Position < 0 || data.Position >= data.Length)
return null;
- // Cache the current offset
- int initialOffset = (int)data.Position;
-
// Create a new playlist to fill
var playlist = new Playlist();
@@ -46,7 +43,7 @@ namespace SabreTools.Serialization.Deserializers
long currentOffset = data.Position;
var entryHeader = PlayJAudio.DeserializeStream(data, currentOffset);
if (entryHeader == null)
- return null;
+ continue;
playlist.AudioFiles[i] = entryHeader;
}
@@ -64,7 +61,7 @@ namespace SabreTools.Serialization.Deserializers
private static PlaylistHeader ParsePlaylistHeader(Stream data)
{
// TODO: Use marshalling here instead of building
- PlaylistHeader playlistHeader = new PlaylistHeader();
+ var playlistHeader = new PlaylistHeader();
playlistHeader.TrackCount = data.ReadUInt32();
playlistHeader.Data = data.ReadBytes(52);
diff --git a/SabreTools.Serialization/Deserializers/Quantum.cs b/SabreTools.Serialization/Deserializers/Quantum.cs
index 4e0f7a1a..3da2a4bd 100644
--- a/SabreTools.Serialization/Deserializers/Quantum.cs
+++ b/SabreTools.Serialization/Deserializers/Quantum.cs
@@ -19,9 +19,6 @@ namespace SabreTools.Serialization.Deserializers
if (data.Position < 0 || data.Position >= data.Length)
return null;
- // Cache the current offset
- int initialOffset = (int)data.Position;
-
// Create a new archive to fill
var archive = new Archive();
@@ -40,24 +37,21 @@ namespace SabreTools.Serialization.Deserializers
#region File List
// If we have any files
- if (header.FileCount > 0)
+ var fileDescriptors = new FileDescriptor[header.FileCount];
+
+ // Read all entries in turn
+ for (int i = 0; i < header.FileCount; i++)
{
- var fileDescriptors = new FileDescriptor[header.FileCount];
+ var file = ParseFileDescriptor(data, header.MinorVersion);
+ if (file == null)
+ return null;
- // Read all entries in turn
- for (int i = 0; i < header.FileCount; i++)
- {
- var file = ParseFileDescriptor(data, header.MinorVersion);
- if (file == null)
- return null;
-
- fileDescriptors[i] = file;
- }
-
- // Set the file list
- archive.FileList = fileDescriptors;
+ fileDescriptors[i] = file;
}
+ // Set the file list
+ archive.FileList = fileDescriptors;
+
#endregion
// Cache the compressed data offset
@@ -75,9 +69,7 @@ namespace SabreTools.Serialization.Deserializers
{
var header = data.ReadType();
- if (header == null)
- return null;
- if (header.Signature != SignatureString)
+ if (header?.Signature != SignatureString)
return null;
return header;
diff --git a/SabreTools.Serialization/Deserializers/SFB.cs b/SabreTools.Serialization/Deserializers/SFB.cs
index 5d2026e2..6cffcc19 100644
--- a/SabreTools.Serialization/Deserializers/SFB.cs
+++ b/SabreTools.Serialization/Deserializers/SFB.cs
@@ -17,9 +17,6 @@ namespace SabreTools.Serialization.Deserializers
if (data.Position < 0 || data.Position >= data.Length)
return null;
- // Cache the current offset
- int initialOffset = (int)data.Position;
-
// Deserialize the SFB
var sfb = data.ReadType();
if (sfb == null)
diff --git a/SabreTools.Serialization/Deserializers/SFO.cs b/SabreTools.Serialization/Deserializers/SFO.cs
index b09b992e..6b9457c1 100644
--- a/SabreTools.Serialization/Deserializers/SFO.cs
+++ b/SabreTools.Serialization/Deserializers/SFO.cs
@@ -17,9 +17,6 @@ namespace SabreTools.Serialization.Deserializers
if (data.Position < 0 || data.Position >= data.Length)
return null;
- // Cache the current offset
- int initialOffset = (int)data.Position;
-
// Create a new SFO to fill
var sfo = new Models.PlayStation3.SFO();
diff --git a/SabreTools.Serialization/Deserializers/SGA.cs b/SabreTools.Serialization/Deserializers/SGA.cs
index 48884bfa..c22639b7 100644
--- a/SabreTools.Serialization/Deserializers/SGA.cs
+++ b/SabreTools.Serialization/Deserializers/SGA.cs
@@ -20,9 +20,6 @@ namespace SabreTools.Serialization.Deserializers
if (data.Position < 0 || data.Position >= data.Length)
return null;
- // Cache the current offset
- long initialOffset = data.Position;
-
// Create a new SGA to fill
var file = new Models.SGA.File();
@@ -78,7 +75,7 @@ namespace SabreTools.Serialization.Deserializers
// Versions 4 and 5 share the same header
case 4:
case 5:
- Header4 header4 = new Header4();
+ var header4 = new Header4();
header4.Signature = signature;
header4.MajorVersion = majorVersion;
@@ -97,7 +94,7 @@ namespace SabreTools.Serialization.Deserializers
// Versions 6 and 7 share the same header
case 6:
case 7:
- Header6 header6 = new Header6();
+ var header6 = new Header6();
header6.Signature = signature;
header6.MajorVersion = majorVersion;
@@ -125,20 +122,24 @@ namespace SabreTools.Serialization.Deserializers
/// Filled SGA directory on success, null on error
private static Models.SGA.Directory? ParseDirectory(Stream data, ushort majorVersion)
{
- #region Directory
-
- // Create the appropriate type of directory
- Models.SGA.Directory directory;
- switch (majorVersion)
+ return majorVersion switch
{
- case 4: directory = new Directory4(); break;
- case 5: directory = new Directory5(); break;
- case 6: directory = new Directory6(); break;
- case 7: directory = new Directory7(); break;
- default: return null;
- }
+ 4 => ParseDirectory4(data),
+ 5 => ParseDirectory5(data),
+ 6 => ParseDirectory6(data),
+ 7 => ParseDirectory7(data),
+ _ => null,
+ };
+ }
- #endregion
+ ///
+ /// Parse a Stream into an SGA directory
+ ///
+ /// Stream to parse
+ /// Filled SGA directory on success, null on error
+ private static Directory4? ParseDirectory4(Stream data)
+ {
+ var directory = new Directory4();
// Cache the current offset
long currentOffset = data.Position;
@@ -146,36 +147,19 @@ namespace SabreTools.Serialization.Deserializers
#region Directory Header
// Try to parse the directory header
- var directoryHeader = ParseDirectoryHeader(data, majorVersion);
+ var directoryHeader = ParseDirectory4Header(data);
if (directoryHeader == null)
return null;
// Set the directory header
- switch (majorVersion)
- {
- case 4: (directory as Directory4)!.DirectoryHeader = directoryHeader as DirectoryHeader4; break;
- case 5: (directory as Directory5)!.DirectoryHeader = directoryHeader as DirectoryHeader5; break;
- case 6: (directory as Directory6)!.DirectoryHeader = directoryHeader as DirectoryHeader5; break;
- case 7: (directory as Directory7)!.DirectoryHeader = directoryHeader as DirectoryHeader7; break;
- default: return null;
- }
+ directory.DirectoryHeader = directoryHeader;
#endregion
#region Sections
- // Get the sections offset
- long sectionOffset;
- switch (majorVersion)
- {
- case 4: sectionOffset = (directoryHeader as DirectoryHeader4)!.SectionOffset; break;
- case 5:
- case 6: sectionOffset = (directoryHeader as DirectoryHeader5)!.SectionOffset; break;
- case 7: sectionOffset = (directoryHeader as DirectoryHeader7)!.SectionOffset; break;
- default: return null;
- }
-
- // Adjust the sections offset based on the directory
+ // Get and adjust the sections offset
+ long sectionOffset = directoryHeader.SectionOffset;
sectionOffset += currentOffset;
// Validate the offset
@@ -185,67 +169,21 @@ namespace SabreTools.Serialization.Deserializers
// Seek to the sections
data.Seek(sectionOffset, SeekOrigin.Begin);
- // Get the section count
- uint sectionCount;
- switch (majorVersion)
- {
- case 4: sectionCount = (directoryHeader as DirectoryHeader4)!.SectionCount; break;
- case 5:
- case 6: sectionCount = (directoryHeader as DirectoryHeader5)!.SectionCount; break;
- case 7: sectionCount = (directoryHeader as DirectoryHeader7)!.SectionCount; break;
- default: return null;
- }
-
// Create the sections array
- object[] sections;
- switch (majorVersion)
- {
- case 4: sections = new Section4[sectionCount]; break;
- case 5:
- case 6:
- case 7: sections = new Section5[sectionCount]; break;
- default: return null;
- }
+ directory.Sections = new Section4[directoryHeader.SectionCount];
// Try to parse the sections
- for (int i = 0; i < sections.Length; i++)
+ for (int i = 0; i < directory.Sections.Length; i++)
{
- switch (majorVersion)
- {
- case 4: sections[i] = ParseSection4(data); break;
- case 5:
- case 6:
- case 7: sections[i] = ParseSection5(data); break;
- default: return null;
- }
- }
-
- // Assign the sections
- switch (majorVersion)
- {
- case 4: (directory as Directory4)!.Sections = sections as Section4[]; break;
- case 5: (directory as Directory5)!.Sections = sections as Section5[]; break;
- case 6: (directory as Directory6)!.Sections = sections as Section5[]; break;
- case 7: (directory as Directory7)!.Sections = sections as Section5[]; break;
- default: return null;
+ directory.Sections[i] = ParseSection4(data);
}
#endregion
#region Folders
- // Get the folders offset
- long folderOffset;
- switch (majorVersion)
- {
- case 4: folderOffset = (directoryHeader as DirectoryHeader4)!.FolderOffset; break;
- case 5: folderOffset = (directoryHeader as DirectoryHeader5)!.FolderOffset; break;
- case 6: folderOffset = (directoryHeader as DirectoryHeader5)!.FolderOffset; break;
- case 7: folderOffset = (directoryHeader as DirectoryHeader7)!.FolderOffset; break;
- default: return null;
- }
-
- // Adjust the folders offset based on the directory
+ // Get and adjust the folders offset
+ long folderOffset = directoryHeader.FolderOffset;
folderOffset += currentOffset;
// Validate the offset
@@ -255,67 +193,21 @@ namespace SabreTools.Serialization.Deserializers
// Seek to the folders
data.Seek(folderOffset, SeekOrigin.Begin);
- // Get the folder count
- uint folderCount;
- switch (majorVersion)
- {
- case 4: folderCount = (directoryHeader as DirectoryHeader4)!.FolderCount; break;
- case 5: folderCount = (directoryHeader as DirectoryHeader5)!.FolderCount; break;
- case 6: folderCount = (directoryHeader as DirectoryHeader5)!.FolderCount; break;
- case 7: folderCount = (directoryHeader as DirectoryHeader7)!.FolderCount; break;
- default: return null;
- }
-
// Create the folders array
- object[] folders;
- switch (majorVersion)
- {
- case 4: folders = new Folder4[folderCount]; break;
- case 5: folders = new Folder5[folderCount]; break;
- case 6: folders = new Folder5[folderCount]; break;
- case 7: folders = new Folder5[folderCount]; break;
- default: return null;
- }
+ directory.Folders = new Folder4[directoryHeader.FolderCount];
// Try to parse the folders
- for (int i = 0; i < folders.Length; i++)
+ for (int i = 0; i < directory.Folders.Length; i++)
{
- switch (majorVersion)
- {
- case 4: folders[i] = ParseFolder4(data); break;
- case 5: folders[i] = ParseFolder5(data); break;
- case 6: folders[i] = ParseFolder5(data); break;
- case 7: folders[i] = ParseFolder5(data); break;
- default: return null;
- }
- }
-
- // Assign the folders
- switch (majorVersion)
- {
- case 4: (directory as Directory4)!.Folders = folders as Folder4[]; break;
- case 5: (directory as Directory5)!.Folders = folders as Folder5[]; break;
- case 6: (directory as Directory6)!.Folders = folders as Folder5[]; break;
- case 7: (directory as Directory7)!.Folders = folders as Folder5[]; break;
- default: return null;
+ directory.Folders[i] = ParseFolder4(data);
}
#endregion
#region Files
- // Get the files offset
- long fileOffset;
- switch (majorVersion)
- {
- case 4: fileOffset = (directoryHeader as DirectoryHeader4)!.FileOffset; break;
- case 5: fileOffset = (directoryHeader as DirectoryHeader5)!.FileOffset; break;
- case 6: fileOffset = (directoryHeader as DirectoryHeader5)!.FileOffset; break;
- case 7: fileOffset = (directoryHeader as DirectoryHeader7)!.FileOffset; break;
- default: return null;
- }
-
- // Adjust the files offset based on the directory
+ // Get and adjust the files offset
+ long fileOffset = directoryHeader.FileOffset;
fileOffset += currentOffset;
// Validate the offset
@@ -326,66 +218,23 @@ namespace SabreTools.Serialization.Deserializers
data.Seek(fileOffset, SeekOrigin.Begin);
// Get the file count
- uint fileCount;
- switch (majorVersion)
- {
- case 4: fileCount = (directoryHeader as DirectoryHeader4)!.FileCount; break;
- case 5: fileCount = (directoryHeader as DirectoryHeader5)!.FileCount; break;
- case 6: fileCount = (directoryHeader as DirectoryHeader5)!.FileCount; break;
- case 7: fileCount = (directoryHeader as DirectoryHeader7)!.FileCount; break;
- default: return null;
- }
+ uint fileCount = directoryHeader.FileCount;
// Create the files array
- object[] files;
- switch (majorVersion)
- {
- case 4: files = new File4[fileCount]; break;
- case 5: files = new File4[fileCount]; break;
- case 6: files = new File6[fileCount]; break;
- case 7: files = new File7[fileCount]; break;
- default: return null;
- }
+ directory.Files = new File4[fileCount];
// Try to parse the files
- for (int i = 0; i < files.Length; i++)
+ for (int i = 0; i < directory.Files.Length; i++)
{
- switch (majorVersion)
- {
- case 4: files[i] = ParseFile4(data); break;
- case 5: files[i] = ParseFile4(data); break;
- case 6: files[i] = ParseFile6(data); break;
- case 7: files[i] = ParseFile7(data); break;
- default: return null;
- }
- }
-
- // Assign the files
- switch (majorVersion)
- {
- case 4: (directory as Directory4)!.Files = files as File4[]; break;
- case 5: (directory as Directory5)!.Files = files as File4[]; break;
- case 6: (directory as Directory6)!.Files = files as File6[]; break;
- case 7: (directory as Directory7)!.Files = files as File7[]; break;
- default: return null;
+ directory.Files[i] = ParseFile4(data);
}
#endregion
#region String Table
- // Get the string table offset
- long stringTableOffset;
- switch (majorVersion)
- {
- case 4: stringTableOffset = (directoryHeader as DirectoryHeader4)!.StringTableOffset; break;
- case 5: stringTableOffset = (directoryHeader as DirectoryHeader5)!.StringTableOffset; break;
- case 6: stringTableOffset = (directoryHeader as DirectoryHeader5)!.StringTableOffset; break;
- case 7: stringTableOffset = (directoryHeader as DirectoryHeader7)!.StringTableOffset; break;
- default: return null;
- }
-
- // Adjust the string table offset based on the directory
+ // Get and adjust the string table offset
+ long stringTableOffset = directoryHeader.StringTableOffset;
stringTableOffset += currentOffset;
// Validate the offset
@@ -395,87 +244,40 @@ namespace SabreTools.Serialization.Deserializers
// Seek to the string table
data.Seek(stringTableOffset, SeekOrigin.Begin);
- // Get the string table count
- uint stringCount;
- switch (majorVersion)
- {
- case 4: stringCount = (directoryHeader as DirectoryHeader4)!.StringTableCount; break;
- case 5: stringCount = (directoryHeader as DirectoryHeader5)!.StringTableCount; break;
- case 6: stringCount = (directoryHeader as DirectoryHeader5)!.StringTableCount; break;
- case 7: stringCount = (directoryHeader as DirectoryHeader7)!.StringTableCount; break;
- default: return null;
- }
-
// TODO: Are these strings actually indexed by number and not position?
// TODO: If indexed by position, I think it needs to be adjusted by start of table
// Create the strings dictionary
- Dictionary strings = new Dictionary((int)stringCount);
+ directory.StringTable = new Dictionary((int)directoryHeader.StringTableCount);
// Get the current position to adjust the offsets
long stringTableStart = data.Position;
// Try to parse the strings
- for (int i = 0; i < stringCount; i++)
+ for (int i = 0; i < directoryHeader.StringTableCount; i++)
{
long currentPosition = data.Position - stringTableStart;
- strings[currentPosition] = data.ReadNullTerminatedAnsiString();
- }
-
- // Assign the files
- switch (majorVersion)
- {
- case 4: (directory as Directory4)!.StringTable = strings; break;
- case 5: (directory as Directory5)!.StringTable = strings; break;
- case 6: (directory as Directory6)!.StringTable = strings; break;
- case 7: (directory as Directory7)!.StringTable = strings; break;
- default: return null;
+ directory.StringTable[currentPosition] = data.ReadNullTerminatedAnsiString();
}
// Loop through all folders to assign names
- for (int i = 0; i < folderCount; i++)
+ for (int i = 0; i < directory.Folders.Length; i++)
{
- uint nameOffset;
- switch (majorVersion)
- {
- case 4: nameOffset = (directory as Directory4)!.Folders![i]!.NameOffset; break;
- case 5: nameOffset = (directory as Directory5)!.Folders![i]!.NameOffset; break;
- case 6: nameOffset = (directory as Directory6)!.Folders![i]!.NameOffset; break;
- case 7: nameOffset = (directory as Directory7)!.Folders![i]!.NameOffset; break;
- default: return null;
- }
+ var folder = directory.Folders[i];
+ if (folder == null)
+ continue;
- switch (majorVersion)
- {
- case 4: (directory as Directory4)!.Folders![i]!.Name = strings[nameOffset]; break;
- case 5: (directory as Directory5)!.Folders![i]!.Name = strings[nameOffset]; break;
- case 6: (directory as Directory6)!.Folders![i]!.Name = strings[nameOffset]; break;
- case 7: (directory as Directory7)!.Folders![i]!.Name = strings[nameOffset]; break;
- default: return null;
- }
+ folder.Name = directory.StringTable[folder.NameOffset];
}
// Loop through all files to assign names
- for (int i = 0; i < fileCount; i++)
+ for (int i = 0; i < directory.Files.Length; i++)
{
- uint nameOffset;
- switch (majorVersion)
- {
- case 4: nameOffset = (directory as Directory4)!.Files![i]!.NameOffset; break;
- case 5: nameOffset = (directory as Directory5)!.Files![i]!.NameOffset; break;
- case 6: nameOffset = (directory as Directory6)!.Files![i]!.NameOffset; break;
- case 7: nameOffset = (directory as Directory7)!.Files![i]!.NameOffset; break;
- default: return null;
- }
+ var file = directory.Files[i];
+ if (file == null)
+ continue;
- switch (majorVersion)
- {
- case 4: (directory as Directory4)!.Files![i]!.Name = strings[nameOffset]; break;
- case 5: (directory as Directory5)!.Files![i]!.Name = strings[nameOffset]; break;
- case 6: (directory as Directory6)!.Files![i]!.Name = strings[nameOffset]; break;
- case 7: (directory as Directory7)!.Files![i]!.Name = strings[nameOffset]; break;
- default: return null;
- }
+ file.Name = directory.StringTable[file.NameOffset];
}
#endregion
@@ -484,21 +286,453 @@ namespace SabreTools.Serialization.Deserializers
}
///
- /// Parse a Stream into an SGA directory header
+ /// Parse a Stream into an SGA directory
///
/// Stream to parse
- /// SGA major version
- /// Filled SGA directory header on success, null on error
- private static object? ParseDirectoryHeader(Stream data, ushort majorVersion)
+ /// Filled SGA directory on success, null on error
+ private static Directory5? ParseDirectory5(Stream data)
{
- switch (majorVersion)
+ var directory = new Directory5();
+
+ // Cache the current offset
+ long currentOffset = data.Position;
+
+ #region Directory Header
+
+ // Try to parse the directory header
+ var directoryHeader = ParseDirectory5Header(data);
+ if (directoryHeader == null)
+ return null;
+
+ // Set the directory header
+ directory.DirectoryHeader = directoryHeader;
+
+ #endregion
+
+ #region Sections
+
+ // Get and adjust the sections offset
+ long sectionOffset = directoryHeader.SectionOffset;
+ sectionOffset += currentOffset;
+
+ // Validate the offset
+ if (sectionOffset < 0 || sectionOffset >= data.Length)
+ return null;
+
+ // Seek to the sections
+ data.Seek(sectionOffset, SeekOrigin.Begin);
+
+ // Create the sections array
+ directory.Sections = new Section5[directoryHeader.SectionCount];
+
+ // Try to parse the sections
+ for (int i = 0; i < directory.Sections.Length; i++)
{
- case 4: return ParseDirectory4Header(data);
- case 5: return ParseDirectory5Header(data);
- case 6: return ParseDirectory5Header(data);
- case 7: return ParseDirectory7Header(data);
- default: return null;
+ directory.Sections[i] = ParseSection5(data);
}
+
+ #endregion
+
+ #region Folders
+
+ // Get and adjust the folders offset
+ long folderOffset = directoryHeader.FolderOffset;
+ folderOffset += currentOffset;
+
+ // Validate the offset
+ if (folderOffset < 0 || folderOffset >= data.Length)
+ return null;
+
+ // Seek to the folders
+ data.Seek(folderOffset, SeekOrigin.Begin);
+
+ // Create the folders array
+ directory.Folders = new Folder5[directoryHeader.FolderCount];
+
+ // Try to parse the folders
+ for (int i = 0; i < directory.Folders.Length; i++)
+ {
+ directory.Folders[i] = ParseFolder5(data);
+ }
+
+ #endregion
+
+ #region Files
+
+ // Get and adjust the files offset
+ long fileOffset = directoryHeader.FileOffset;
+ fileOffset += currentOffset;
+
+ // Validate the offset
+ if (fileOffset < 0 || fileOffset >= data.Length)
+ return null;
+
+ // Seek to the files
+ data.Seek(fileOffset, SeekOrigin.Begin);
+
+ // Create the files array
+ directory.Files = new File4[directoryHeader.FileCount];
+
+ // Try to parse the files
+ for (int i = 0; i < directory.Files.Length; i++)
+ {
+ directory.Files[i] = ParseFile4(data);
+ }
+
+ #endregion
+
+ #region String Table
+
+ // Get and adjust the string table offset
+ long stringTableOffset = directoryHeader.StringTableOffset;
+ stringTableOffset += currentOffset;
+
+ // Validate the offset
+ if (stringTableOffset < 0 || stringTableOffset >= data.Length)
+ return null;
+
+ // Seek to the string table
+ data.Seek(stringTableOffset, SeekOrigin.Begin);
+
+ // TODO: Are these strings actually indexed by number and not position?
+ // TODO: If indexed by position, I think it needs to be adjusted by start of table
+
+ // Create the strings dictionary
+ directory.StringTable = new Dictionary((int)directoryHeader.StringTableCount);
+
+ // Get the current position to adjust the offsets
+ long stringTableStart = data.Position;
+
+ // Try to parse the strings
+ for (int i = 0; i < directoryHeader.StringTableCount; i++)
+ {
+ long currentPosition = data.Position - stringTableStart;
+ directory.StringTable[currentPosition] = data.ReadNullTerminatedAnsiString();
+ }
+
+ // Loop through all folders to assign names
+ for (int i = 0; i < directory.Folders.Length; i++)
+ {
+ var folder = directory.Folders[i];
+ if (folder == null)
+ continue;
+
+ folder.Name = directory.StringTable[folder.NameOffset];
+ }
+
+ // Loop through all files to assign names
+ for (int i = 0; i < directory.Files.Length; i++)
+ {
+ var file = directory.Files[i];
+ if (file == null)
+ continue;
+
+ file.Name = directory.StringTable[file.NameOffset];
+ }
+
+ #endregion
+
+ return directory;
+ }
+
+ ///
+ /// Parse a Stream into an SGA directory
+ ///
+ /// Stream to parse
+ /// Filled SGA directory on success, null on error
+ private static Directory6? ParseDirectory6(Stream data)
+ {
+ var directory = new Directory6();
+
+ // Cache the current offset
+ long currentOffset = data.Position;
+
+ #region Directory Header
+
+ // Try to parse the directory header
+ var directoryHeader = ParseDirectory5Header(data);
+ if (directoryHeader == null)
+ return null;
+
+ // Set the directory header
+ directory.DirectoryHeader = directoryHeader;
+
+ #endregion
+
+ #region Sections
+
+ // Get and adjust the sections offset
+ long sectionOffset = directoryHeader.SectionOffset;
+ sectionOffset += currentOffset;
+
+ // Validate the offset
+ if (sectionOffset < 0 || sectionOffset >= data.Length)
+ return null;
+
+ // Seek to the sections
+ data.Seek(sectionOffset, SeekOrigin.Begin);
+
+ // Create the sections array
+ directory.Sections = new Section5[directoryHeader.SectionCount];
+
+ // Try to parse the sections
+ for (int i = 0; i < directory.Sections.Length; i++)
+ {
+ directory.Sections[i] = ParseSection5(data);
+ }
+
+ #endregion
+
+ #region Folders
+
+ // Get and adjust the folders offset
+ long folderOffset = directoryHeader.FolderOffset;
+ folderOffset += currentOffset;
+
+ // Validate the offset
+ if (folderOffset < 0 || folderOffset >= data.Length)
+ return null;
+
+ // Seek to the folders
+ data.Seek(folderOffset, SeekOrigin.Begin);
+
+ // Create the folders array
+ directory.Folders = new Folder5[directoryHeader.FolderCount];
+
+ // Try to parse the folders
+ for (int i = 0; i < directory.Folders.Length; i++)
+ {
+ directory.Folders[i] = ParseFolder5(data);
+ }
+
+ #endregion
+
+ #region Files
+
+ // Get and adjust the files offset
+ long fileOffset = directoryHeader.FileOffset;
+ fileOffset += currentOffset;
+
+ // Validate the offset
+ if (fileOffset < 0 || fileOffset >= data.Length)
+ return null;
+
+ // Seek to the files
+ data.Seek(fileOffset, SeekOrigin.Begin);
+
+ // Create the files array
+ directory.Files = new File6[directoryHeader.FileCount];
+
+ // Try to parse the files
+ for (int i = 0; i < directory.Files.Length; i++)
+ {
+ directory.Files[i] = ParseFile6(data);
+ }
+
+ #endregion
+
+ #region String Table
+
+ // Get and adjust the string table offset
+ long stringTableOffset = directoryHeader.StringTableOffset;
+ stringTableOffset += currentOffset;
+
+ // Validate the offset
+ if (stringTableOffset < 0 || stringTableOffset >= data.Length)
+ return null;
+
+ // Seek to the string table
+ data.Seek(stringTableOffset, SeekOrigin.Begin);
+
+ // TODO: Are these strings actually indexed by number and not position?
+ // TODO: If indexed by position, I think it needs to be adjusted by start of table
+
+ // Create the strings dictionary
+ directory.StringTable = new Dictionary((int)directoryHeader.StringTableCount);
+
+ // Get the current position to adjust the offsets
+ long stringTableStart = data.Position;
+
+ // Try to parse the strings
+ for (int i = 0; i < directoryHeader.StringTableCount; i++)
+ {
+ long currentPosition = data.Position - stringTableStart;
+ directory.StringTable[currentPosition] = data.ReadNullTerminatedAnsiString();
+ }
+
+ // Loop through all folders to assign names
+ for (int i = 0; i < directory.Folders.Length; i++)
+ {
+ var folder = directory.Folders[i];
+ if (folder == null)
+ continue;
+
+ folder.Name = directory.StringTable[folder.NameOffset];
+ }
+
+ // Loop through all files to assign names
+ for (int i = 0; i < directory.Files.Length; i++)
+ {
+ var file = directory.Files[i];
+ if (file == null)
+ continue;
+
+ file.Name = directory.StringTable[file.NameOffset];
+ }
+
+ #endregion
+
+ return directory;
+ }
+
+ ///
+ /// Parse a Stream into an SGA directory
+ ///
+ /// Stream to parse
+ /// Filled SGA directory on success, null on error
+ private static Directory7? ParseDirectory7(Stream data)
+ {
+ var directory = new Directory7();
+
+ // Cache the current offset
+ long currentOffset = data.Position;
+
+ #region Directory Header
+
+ // Try to parse the directory header
+ var directoryHeader = ParseDirectory7Header(data);
+ if (directoryHeader == null)
+ return null;
+
+ // Set the directory header
+ directory.DirectoryHeader = directoryHeader;
+
+ #endregion
+
+ #region Sections
+
+ // Get and adjust the sections offset
+ long sectionOffset = directoryHeader.SectionOffset;
+ sectionOffset += currentOffset;
+
+ // Validate the offset
+ if (sectionOffset < 0 || sectionOffset >= data.Length)
+ return null;
+
+ // Seek to the sections
+ data.Seek(sectionOffset, SeekOrigin.Begin);
+
+ // Create the sections array
+ directory.Sections = new Section5[directoryHeader.SectionCount];
+
+ // Try to parse the sections
+ for (int i = 0; i < directory.Sections.Length; i++)
+ {
+ directory.Sections[i] = ParseSection5(data);
+ }
+
+ #endregion
+
+ #region Folders
+
+ // Get and adjust the folders offset
+ long folderOffset = directoryHeader.FolderOffset;
+ folderOffset += currentOffset;
+
+ // Validate the offset
+ if (folderOffset < 0 || folderOffset >= data.Length)
+ return null;
+
+ // Seek to the folders
+ data.Seek(folderOffset, SeekOrigin.Begin);
+
+ // Create the folders array
+ directory.Folders = new Folder5[directoryHeader.FolderCount];
+
+ // Try to parse the folders
+ for (int i = 0; i < directory.Folders.Length; i++)
+ {
+ directory.Folders[i] = ParseFolder5(data);
+ }
+
+ #endregion
+
+ #region Files
+
+ // Get and adjust the files offset
+ long fileOffset = directoryHeader.FileOffset;
+ fileOffset += currentOffset;
+
+ // Validate the offset
+ if (fileOffset < 0 || fileOffset >= data.Length)
+ return null;
+
+ // Seek to the files
+ data.Seek(fileOffset, SeekOrigin.Begin);
+
+ // Create the files array
+ directory.Files = new File7[directoryHeader.FileCount];
+
+ // Try to parse the files
+ for (int i = 0; i < directory.Files.Length; i++)
+ {
+ directory.Files[i] = ParseFile7(data);
+ }
+
+ #endregion
+
+ #region String Table
+
+ // Get and adjust the string table offset
+ long stringTableOffset = directoryHeader.StringTableOffset;
+ stringTableOffset += currentOffset;
+
+ // Validate the offset
+ if (stringTableOffset < 0 || stringTableOffset >= data.Length)
+ return null;
+
+ // Seek to the string table
+ data.Seek(stringTableOffset, SeekOrigin.Begin);
+
+ // TODO: Are these strings actually indexed by number and not position?
+ // TODO: If indexed by position, I think it needs to be adjusted by start of table
+
+ // Create the strings dictionary
+ directory.StringTable = new Dictionary((int)directoryHeader.StringTableCount);
+
+ // Get the current position to adjust the offsets
+ long stringTableStart = data.Position;
+
+ // Try to parse the strings
+ for (int i = 0; i < directoryHeader.StringTableCount; i++)
+ {
+ long currentPosition = data.Position - stringTableStart;
+ directory.StringTable[currentPosition] = data.ReadNullTerminatedAnsiString();
+ }
+
+ // Loop through all folders to assign names
+ for (int i = 0; i < directory.Folders.Length; i++)
+ {
+ var folder = directory.Folders[i];
+ if (folder == null)
+ continue;
+
+ folder.Name = directory.StringTable[folder.NameOffset];
+ }
+
+ // Loop through all files to assign names
+ for (int i = 0; i < directory.Files.Length; i++)
+ {
+ var file = directory.Files[i];
+ if (file == null)
+ continue;
+
+ file.Name = directory.StringTable[file.NameOffset];
+ }
+
+ #endregion
+
+ return directory;
}
///
@@ -508,7 +742,7 @@ namespace SabreTools.Serialization.Deserializers
/// Filled SGA directory header version 4 on success, null on error
private static DirectoryHeader4 ParseDirectory4Header(Stream data)
{
- DirectoryHeader4 directoryHeader4 = new DirectoryHeader4();
+ var directoryHeader4 = new DirectoryHeader4();
directoryHeader4.SectionOffset = data.ReadUInt32();
directoryHeader4.SectionCount = data.ReadUInt16();
@@ -529,7 +763,7 @@ namespace SabreTools.Serialization.Deserializers
/// Filled SGA directory header version 5 on success, null on error
private static DirectoryHeader5 ParseDirectory5Header(Stream data)
{
- DirectoryHeader5 directoryHeader5 = new DirectoryHeader5();
+ var directoryHeader5 = new DirectoryHeader5();
directoryHeader5.SectionOffset = data.ReadUInt32();
directoryHeader5.SectionCount = data.ReadUInt32();
@@ -550,7 +784,7 @@ namespace SabreTools.Serialization.Deserializers
/// Filled SGA directory header version 7 on success, null on error
private static DirectoryHeader7 ParseDirectory7Header(Stream data)
{
- DirectoryHeader7 directoryHeader7 = new DirectoryHeader7();
+ var directoryHeader7 = new DirectoryHeader7();
directoryHeader7.SectionOffset = data.ReadUInt32();
directoryHeader7.SectionCount = data.ReadUInt32();
@@ -574,7 +808,7 @@ namespace SabreTools.Serialization.Deserializers
/// Filled SGA section version 4 on success, null on error
private static Section4 ParseSection4(Stream data)
{
- Section4 section4 = new Section4();
+ var section4 = new Section4();
byte[]? section4Alias = data.ReadBytes(64);
if (section4Alias != null)
@@ -599,7 +833,7 @@ namespace SabreTools.Serialization.Deserializers
/// Filled SGA section version 5 on success, null on error
private static Section5 ParseSection5(Stream data)
{
- Section5 section5 = new Section5();
+ var section5 = new Section5();
byte[]? section5Alias = data.ReadBytes(64);
if (section5Alias != null)
@@ -624,7 +858,7 @@ namespace SabreTools.Serialization.Deserializers
/// Filled SGA folder version 4 on success, null on error
private static Folder4 ParseFolder4(Stream data)
{
- Folder4 folder4 = new Folder4();
+ var folder4 = new Folder4();
folder4.NameOffset = data.ReadUInt32();
folder4.Name = null; // Read from string table
@@ -644,7 +878,7 @@ namespace SabreTools.Serialization.Deserializers
/// Filled SGA folder version 5 on success, null on error
private static Folder5 ParseFolder5(Stream data)
{
- Folder5 folder5 = new Folder5();
+ var folder5 = new Folder5();
folder5.NameOffset = data.ReadUInt32();
folder5.Name = null; // Read from string table
@@ -664,7 +898,7 @@ namespace SabreTools.Serialization.Deserializers
/// Filled SGA file version 4 on success, null on error
private static File4 ParseFile4(Stream data)
{
- File4 file4 = new File4();
+ var file4 = new File4();
file4.NameOffset = data.ReadUInt32();
file4.Name = null; // Read from string table
@@ -686,7 +920,7 @@ namespace SabreTools.Serialization.Deserializers
/// Filled SGA file version 6 on success, null on error
private static File6 ParseFile6(Stream data)
{
- File6 file6 = new File6();
+ var file6 = new File6();
file6.NameOffset = data.ReadUInt32();
file6.Name = null; // Read from string table
@@ -709,7 +943,7 @@ namespace SabreTools.Serialization.Deserializers
/// Filled SGA file version 7 on success, null on error
private static File7 ParseFile7(Stream data)
{
- File7 file7 = new File7();
+ var file7 = new File7();
file7.NameOffset = data.ReadUInt32();
file7.Name = null; // Read from string table
diff --git a/SabreTools.Serialization/Deserializers/VBSP.cs b/SabreTools.Serialization/Deserializers/VBSP.cs
index 5c67dc66..52309265 100644
--- a/SabreTools.Serialization/Deserializers/VBSP.cs
+++ b/SabreTools.Serialization/Deserializers/VBSP.cs
@@ -21,9 +21,6 @@ namespace SabreTools.Serialization.Deserializers
if (data.Position < 0 || data.Position >= data.Length)
return null;
- // Cache the current offset
- long initialOffset = data.Position;
-
// Create a new Half-Life 2 Level to fill
var file = new VbspFile();
@@ -41,804 +38,220 @@ namespace SabreTools.Serialization.Deserializers
#region Lumps
- // LUMP_ENTITIES [0]
- var lumpEntry = header.Lumps[(int)LumpType.LUMP_ENTITIES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
+ for (int l = 0; l < VBSP_HEADER_LUMPS; l++)
{
+ // Get the next lump entry
+ var lumpEntry = header.Lumps[l];
+ if (lumpEntry == null)
+ continue;
+ if (lumpEntry.Offset == 0 || lumpEntry.Length == 0)
+ continue;
+
// Seek to the lump offset
data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
- // Read the lump data
- var entities = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
+ // Read according to the lump type
+ switch ((LumpType)l)
{
- // TODO: Read this into sets of key-value pairs
- var sb = new StringBuilder();
- char c = '\0';
- do
- {
- c = (char)data.ReadByteValue();
- sb.Append(c);
- } while (c != '}');
+ case LumpType.LUMP_ENTITIES:
+ file.Entities = ParseEntitiesLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_PLANES:
+ file.PlanesLump = ParsePlanesLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_TEXTURES:
+ file.TexdataLump = ParseTexdataLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_VERTICES:
+ file.VerticesLump = ParseVerticesLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_VISIBILITY:
+ file.VisibilityLump = ParseVisibilityLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_NODES:
+ file.NodesLump = ParseNodesLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_TEXINFO:
+ file.TexinfoLump = ParseTexinfoLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_FACES:
+ file.FacesLump = ParseFacesLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_LIGHTING:
+ file.LightmapLump = ParseLightmapLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_CLIPNODES:
+ file.OcclusionLump = ParseOcclusionLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_LEAVES:
+ file.LeavesLump = ParseLeavesLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_MARKSURFACES:
+ file.MarksurfacesLump = ParseMarksurfacesLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_EDGES:
+ file.EdgesLump = ParseEdgesLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_SURFEDGES:
+ file.SurfedgesLump = ParseSurfedgesLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_MODELS:
+ file.ModelsLump = ParseModelsLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_WORLDLIGHTS:
+ file.LDRWorldLightsLump = ParseWorldLightsLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_LEAFFACES:
+ file.LeafFacesLump = ParseLeafFacesLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_LEAFBRUSHES:
+ file.LeafBrushesLump = ParseLeafBrushesLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_BRUSHES:
+ file.BrushesLump = ParseBrushesLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_BRUSHSIDES:
+ file.BrushsidesLump = ParseBrushsidesLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_AREAS:
+ // TODO: Support LUMP_AREAS [20] when in Models
+ break;
+ case LumpType.LUMP_AREAPORTALS:
+ // TODO: Support LUMP_AREAPORTALS [21] when in Models
+ break;
+ case LumpType.LUMP_PORTALS:
+ // TODO: Support LUMP_PORTALS / LUMP_UNUSED0 / LUMP_PROPCOLLISION [22] when in Models
+ break;
+ case LumpType.LUMP_CLUSTERS:
+ // TODO: Support LUMP_CLUSTERS / LUMP_UNUSED1 / LUMP_PROPHULLS [23] when in Models
+ break;
+ case LumpType.LUMP_PORTALVERTS:
+ // TODO: Support LUMP_PORTALVERTS / LUMP_UNUSED2 / LUMP_FAKEENTITIES / LUMP_PROPHULLVERTS [24] when in Models
+ break;
+ case LumpType.LUMP_CLUSTERPORTALS:
+ // TODO: Support LUMP_CLUSTERPORTALS / LUMP_UNUSED3 / LUMP_PROPTRIS [25] when in Models
+ break;
+ case LumpType.LUMP_DISPINFO:
+ file.DispInfoLump = ParseDispInfosLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_ORIGINALFACES:
+ file.OriginalFacesLump = ParseFacesLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_PHYSDISP:
+ // TODO: Support LUMP_PHYSDISP [28] when in Models
+ break;
+ case LumpType.LUMP_PHYSCOLLIDE:
+ // TODO: Support LUMP_PHYSCOLLIDE [29] when in Models
+ break;
+ case LumpType.LUMP_VERTNORMALS:
+ // TODO: Support LUMP_VERTNORMALS [30] when in Models
+ break;
+ case LumpType.LUMP_VERTNORMALINDICES:
+ // TODO: Support LUMP_VERTNORMALINDICES [31] when in Models
+ break;
+ case LumpType.LUMP_DISP_LIGHTMAP_ALPHAS:
+ // TODO: Support LUMP_DISP_LIGHTMAP_ALPHAS [32] when in Models
+ break;
+ case LumpType.LUMP_DISP_VERTS:
+ file.DispVertLump = ParseDispVertsLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS:
+ // TODO: Support LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS [34] when in Models
+ break;
+ case LumpType.LUMP_GAME_LUMP:
+ file.GameLump = ParseGameLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_LEAFWATERDATA:
+ // TODO: Support LUMP_LEAFWATERDATA [36] when in Models
+ break;
+ case LumpType.LUMP_PRIMITIVES:
+ // TODO: Support LUMP_PRIMITIVES [37] when in Models
+ break;
+ case LumpType.LUMP_PRIMVERTS:
+ // TODO: Support LUMP_PRIMVERTS [38] when in Models
+ break;
+ case LumpType.LUMP_PRIMINDICES:
+ // TODO: Support LUMP_PRIMINDICES [39] when in Models
+ break;
+ case LumpType.LUMP_PAKFILE:
+ // TODO: Support LUMP_PAKFILE [40] when in Models
+ break;
+ case LumpType.LUMP_CLIPPORTALVERTS:
+ // TODO: Support LUMP_CLIPPORTALVERTS [41] when in Models
+ break;
+ case LumpType.LUMP_CUBEMAPS:
+ file.CubemapLump = ParseCubemapsLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_TEXDATA_STRING_DATA:
+ file.TexdataStringData = ParseTexdataStringData(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_TEXDATA_STRING_TABLE:
+ file.TexdataStringTable = ParseTexdataStringTable(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_OVERLAYS:
+ file.OverlaysLump = ParseOverlaysLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_LEAFMINDISTTOWATER:
+ // TODO: Support LUMP_LEAFMINDISTTOWATER [46] when in Models
+ break;
+ case LumpType.LUMP_FACE_MACRO_TEXTURE_INFO:
+ // TODO: Support LUMP_FACE_MACRO_TEXTURE_INFO [47] when in Models
+ break;
+ case LumpType.LUMP_DISP_TRIS:
+ file.DispTrisLump = ParseDispTrisLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_PHYSCOLLIDESURFACE:
+ // TODO: Support LUMP_PHYSCOLLIDESURFACE / LUMP_PROP_BLOB [49] when in Models
+ break;
+ case LumpType.LUMP_WATEROVERLAYS:
+ // TODO: Support LUMP_WATEROVERLAYS [50] when in Models
+ break;
+ case LumpType.LUMP_LIGHTMAPPAGES:
+ file.HDRAmbientIndexLump = ParseAmbientIndexLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_LIGHTMAPPAGEINFOS:
+ file.LDRAmbientIndexLump = ParseAmbientIndexLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_LIGHTING_HDR:
+ // TODO: Support LUMP_LIGHTING_HDR [53] when in Models
+ break;
+ case LumpType.LUMP_WORLDLIGHTS_HDR:
+ file.WorldLightsLump = ParseWorldLightsLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_LEAF_AMBIENT_LIGHTING_HDR:
+ file.HDRAmbientLightingLump = ParseAmbientLightingLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_LEAF_AMBIENT_LIGHTING:
+ file.LDRAmbientLightingLump = ParseAmbientLightingLump(data, lumpEntry.Offset, lumpEntry.Length);
+ break;
+ case LumpType.LUMP_XZIPPAKFILE:
+ // TODO: Support LUMP_XZIPPAKFILE [57] when in Models
+ break;
+ case LumpType.LUMP_FACES_HDR:
+ // TODO: Support LUMP_FACES_HDR [58] when in Models
+ break;
+ case LumpType.LUMP_MAP_FLAGS:
+ // TODO: Support LUMP_MAP_FLAGS [59] when in Models
+ break;
+ case LumpType.LUMP_OVERLAY_FADES:
+ // TODO: Support LUMP_OVERLAY_FADES [60] when in Models
+ break;
+ case LumpType.LUMP_OVERLAY_SYSTEM_LEVELS:
+ // TODO: Support LUMP_OVERLAY_SYSTEM_LEVELS [61] when in Models
+ break;
+ case LumpType.LUMP_PHYSLEVEL:
+ // TODO: Support LUMP_PHYSLEVEL [62] when in Models
+ break;
+ case LumpType.LUMP_DISP_MULTIBLEND:
+ // TODO: Support LUMP_DISP_MULTIBLEND [63] when in Models
+ break;
- var entity = new Entity();
- entity.Attributes = new List>
- {
- new("REPLACE", sb.ToString()),
- };
- entities.Add(entity);
+ default:
+ // Unsupported LumpType value, ignore
+ break;
}
-
- var lump = new EntitiesLump();
- lump.Entities = [.. entities];
-
- file.Entities = lump;
}
- // LUMP_PLANES [1]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_PLANES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var planes = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var plane = data.ReadType();
- if (plane != null)
- planes.Add(plane);
- }
-
- var lump = new PlanesLump();
- lump.Planes = [.. planes];
-
- file.PlanesLump = lump;
- }
-
- // LUMP_TEXDATA [2]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_TEXTURES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var texdatas = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var texdata = data.ReadType();
- if (texdata != null)
- texdatas.Add(texdata);
- }
-
- var lump = new TexdataLump();
- lump.Texdatas = [.. texdatas];
-
- file.TexdataLump = lump;
- }
-
- // LUMP_VERTEXES [3]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_VERTICES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var vertices = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- vertices.Add(data.ReadType());
- }
-
- var lump = new VerticesLump();
- lump.Vertices = [.. vertices];
-
- file.VerticesLump = lump;
- }
-
- // LUMP_VISIBILITY [4]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_VISIBILITY];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var lump = new VisibilityLump();
-
- lump.NumClusters = data.ReadInt32();
- lump.ByteOffsets = new int[lump.NumClusters, 2];
- for (int i = 0; i < lump.NumClusters; i++)
- for (int j = 0; j < 2; j++)
- {
- lump.ByteOffsets[i, j] = data.ReadByteValue();
- }
-
- file.VisibilityLump = lump;
- }
-
- // LUMP_NODES [5]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_NODES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var nodes = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var node = data.ReadType();
- if (node != null)
- nodes.Add(node);
- }
-
- var lump = new VbspNodesLump();
- lump.Nodes = [.. nodes];
-
- file.NodesLump = lump;
- }
-
- // LUMP_TEXINFO [6]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_TEXINFO];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var texinfos = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var texinfo = data.ReadType();
- if (texinfo != null)
- texinfos.Add(texinfo);
- }
-
- var lump = new VbspTexinfoLump();
- lump.Texinfos = [.. texinfos];
-
- file.TexinfoLump = lump;
- }
-
- // LUMP_FACES [7]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_FACES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var faces = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var face = data.ReadType();
- if (face != null)
- faces.Add(face);
- }
-
- var lump = new VbspFacesLump();
- lump.Faces = [.. faces];
-
- file.FacesLump = lump;
- }
-
- // LUMP_LIGHTING [8]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_LIGHTING];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var lump = new LightmapLump();
- lump.Lightmap = new byte[lumpEntry.Length / 3, 3];
-
- for (int i = 0; i < lumpEntry.Length / 3; i++)
- for (int j = 0; j < 3; j++)
- {
- lump.Lightmap[i, j] = data.ReadByteValue();
- }
-
- file.LightmapLump = lump;
- }
-
- // LUMP_OCCLUSION [9]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_CLIPNODES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var lump = new OcclusionLump();
-
- lump.Count = data.ReadInt32();
- lump.Data = new OccluderData[lump.Count];
- for (int i = 0; i < lump.Count; i++)
- {
- var occluderData = data.ReadType();
- if (occluderData != null)
- lump.Data[i] = occluderData;
- }
- lump.PolyDataCount = data.ReadInt32();
- lump.PolyData = new OccluderPolyData[lump.Count];
- for (int i = 0; i < lump.Count; i++)
- {
- var polyData = data.ReadType();
- if (polyData != null)
- lump.PolyData[i] = polyData;
- }
- lump.VertexIndexCount = data.ReadInt32();
- lump.VertexIndices = new int[lump.VertexIndexCount];
- for (int i = 0; i < lump.VertexIndexCount; i++)
- {
- lump.VertexIndices[i] = data.ReadInt32();
- }
-
- file.OcclusionLump = lump;
- }
-
- // LUMP_LEAVES [10]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_LEAVES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var leaves = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- // TODO: Fix parsing between V0 and V1+
- var leaf = data.ReadType();
- if (leaf != null)
- leaves.Add(leaf);
- }
-
- var lump = new VbspLeavesLump();
- lump.Leaves = [.. leaves];
-
- file.LeavesLump = lump;
- }
-
- // LUMP_FACEIDS [11]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_MARKSURFACES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var marksurfaces = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- marksurfaces.Add(data.ReadUInt16());
- }
-
- var lump = new MarksurfacesLump();
- lump.Marksurfaces = [.. marksurfaces];
-
- file.MarksurfacesLump = lump;
- }
-
- // LUMP_EDGES [12]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_EDGES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var edges = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var edge = data.ReadType();
- if (edge != null)
- edges.Add(edge);
- }
-
- var lump = new EdgesLump();
- lump.Edges = [.. edges];
-
- file.EdgesLump = lump;
- }
-
- // LUMP_SURFEDGES [13]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_SURFEDGES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var surfedges = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- surfedges.Add(data.ReadInt32());
- }
-
- var lump = new SurfedgesLump();
- lump.Surfedges = [.. surfedges];
-
- file.SurfedgesLump = lump;
- }
-
- // LUMP_MODELS [14]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_MODELS];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var models = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var model = data.ReadType();
- if (model != null)
- models.Add(model);
- }
-
- var lump = new VbspModelsLump();
- lump.Models = [.. models];
-
- file.ModelsLump = lump;
- }
-
- // LUMP_WORLDLIGHTS [15]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_WORLDLIGHTS];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var worldLights = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var worldLight = data.ReadType();
- if (worldLight != null)
- worldLights.Add(worldLight);
- }
-
- var lump = new WorldLightsLump();
- lump.WorldLights = [.. worldLights];
-
- file.LDRWorldLightsLump = lump;
- }
-
- // LUMP_LEAFFACES [16]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_LEAFFACES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var map = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- map.Add(data.ReadUInt16());
- }
-
- var lump = new LeafFacesLump();
- lump.Map = [.. map];
-
- file.LeafFacesLump = lump;
- }
-
- // LUMP_LEAFBRUSHES [17]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_LEAFBRUSHES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var map = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- map.Add(data.ReadUInt16());
- }
-
- var lump = new LeafBrushesLump();
- lump.Map = [.. map];
-
- file.LeafBrushesLump = lump;
- }
-
- // LUMP_BRUSHES [18]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_BRUSHES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var brushes = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var brush = data.ReadType();
- if (brush != null)
- brushes.Add(brush);
- }
-
- var lump = new BrushesLump();
- lump.Brushes = [.. brushes];
-
- file.BrushesLump = lump;
- }
-
- // LUMP_BRUSHSIDES [19]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_BRUSHSIDES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var brushsides = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var brushside = data.ReadType();
- if (brushside != null)
- brushsides.Add(brushside);
- }
-
- var lump = new BrushsidesLump();
- lump.Brushsides = [.. brushsides];
-
- file.BrushsidesLump = lump;
- }
-
- // TODO: Support LUMP_AREAS [20] when in Models
- // TODO: Support LUMP_AREAPORTALS [21] when in Models
- // TODO: Support LUMP_PORTALS / LUMP_UNUSED0 / LUMP_PROPCOLLISION [22] when in Models
- // TODO: Support LUMP_CLUSTERS / LUMP_UNUSED1 / LUMP_PROPHULLS [23] when in Models
- // TODO: Support LUMP_PORTALVERTS / LUMP_UNUSED2 / LUMP_FAKEENTITIES / LUMP_PROPHULLVERTS [24] when in Models
- // TODO: Support LUMP_CLUSTERPORTALS / LUMP_UNUSED3 / LUMP_PROPTRIS [25] when in Models
-
- // LUMP_DISPINFO [26]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_DISPINFO];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var dispInfos = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var dispInfo = data.ReadType();
- if (dispInfo != null)
- dispInfos.Add(dispInfo);
- }
-
- var lump = new DispInfosLump();
- lump.Infos = [.. dispInfos];
-
- file.DispInfoLump = lump;
- }
-
- // LUMP_ORIGINALFACES [27]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_ORIGINALFACES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var faces = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var face = data.ReadType();
- if (face != null)
- faces.Add(face);
- }
-
- var lump = new VbspFacesLump();
- lump.Faces = [.. faces];
-
- file.OriginalFacesLump = lump;
- }
-
- // TODO: Support LUMP_PHYSDISP [28] when in Models
- // TODO: Support LUMP_PHYSCOLLIDE [29] when in Models
- // TODO: Support LUMP_VERTNORMALS [30] when in Models
- // TODO: Support LUMP_VERTNORMALINDICES [31] when in Models
- // TODO: Support LUMP_DISP_LIGHTMAP_ALPHAS [32] when in Models
-
- // LUMP_DISP_VERTS [33]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_DISP_VERTS];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var verts = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var vert = data.ReadType();
- if (vert != null)
- verts.Add(vert);
- }
-
- var lump = new DispVertsLump();
- lump.Verts = [.. verts];
-
- file.DispVertLump = lump;
- }
-
- // TODO: Support LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS [34] when in Models
-
- // LUMP_GAME_LUMP [35]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_GAME_LUMP];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var lump = new GameLump();
-
- lump.LumpCount = data.ReadInt32();
- lump.Directories = new GameLumpDirectory[lump.LumpCount];
- for (int i = 0; i < lump.LumpCount; i++)
- {
- var dir = data.ReadType();
- if (dir != null)
- lump.Directories[i] = dir;
- }
-
- file.GameLump = lump;
- }
-
- // TODO: Support LUMP_LEAFWATERDATA [36] when in Models
- // TODO: Support LUMP_PRIMITIVES [37] when in Models
- // TODO: Support LUMP_PRIMVERTS [38] when in Models
- // TODO: Support LUMP_PRIMINDICES [39] when in Models
- // TODO: Support LUMP_PAKFILE [40] when in Models
- // TODO: Support LUMP_CLIPPORTALVERTS [41] when in Models
-
- // LUMP_CUBEMAPS [42]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_CUBEMAPS];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var cubemaps = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var cubemap = data.ReadType();
- if (cubemap != null)
- cubemaps.Add(cubemap);
- }
-
- var lump = new CubemapsLump();
- lump.Cubemaps = [.. cubemaps];
-
- file.CubemapLump = lump;
- }
-
- // LUMP_TEXDATA_STRING_DATA [43]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_TEXDATA_STRING_DATA];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var strings = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var str = data.ReadNullTerminatedAnsiString();
- if (str != null)
- strings.Add(str);
- }
-
- var lump = new TexdataStringData();
- lump.Strings = [.. strings];
-
- file.TexdataStringData = lump;
- }
-
- // LUMP_TEXDATA_STRING_TABLE [44]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_TEXDATA_STRING_TABLE];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var offsets = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- offsets.Add(data.ReadInt32());
- }
-
- var lump = new TexdataStringTable();
- lump.Offsets = [.. offsets];
-
- file.TexdataStringTable = lump;
- }
-
- // LUMP_OVERLAYS [45]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_OVERLAYS];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var overlays = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var overlay = data.ReadType();
- if (overlay != null)
- overlays.Add(overlay);
- }
-
- var lump = new OverlaysLump();
- lump.Overlays = [.. overlays];
-
- file.OverlaysLump = lump;
- }
-
- // TODO: Support LUMP_LEAFMINDISTTOWATER [46] when in Models
- // TODO: Support LUMP_FACE_MACRO_TEXTURE_INFO [47] when in Models
-
- // LUMP_DISP_TRIS [48]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_DISP_TRIS];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var tris = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var tri = data.ReadType();
- if (tri != null)
- tris.Add(tri);
- }
-
- var lump = new DispTrisLump();
- lump.Tris = [.. tris];
-
- file.DispTrisLump = lump;
- }
-
- // TODO: Support LUMP_PHYSCOLLIDESURFACE / LUMP_PROP_BLOB [49] when in Models
- // TODO: Support LUMP_WATEROVERLAYS [50] when in Models
-
- // LUMP_LIGHTMAPPAGES / LUMP_LEAF_AMBIENT_INDEX_HDR [51]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_LIGHTMAPPAGES];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var indicies = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var index = data.ReadType();
- if (index != null)
- indicies.Add(index);
- }
-
- var lump = new AmbientIndexLump();
- lump.Indicies = [.. indicies];
-
- file.HDRAmbientIndexLump = lump;
- }
-
- // LUMP_LIGHTMAPPAGEINFOS / LUMP_LEAF_AMBIENT_INDEX [52]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_LIGHTMAPPAGEINFOS];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var indicies = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var index = data.ReadType();
- if (index != null)
- indicies.Add(index);
- }
-
- var lump = new AmbientIndexLump();
- lump.Indicies = [.. indicies];
-
- file.LDRAmbientIndexLump = lump;
- }
-
- // TODO: Support LUMP_LIGHTING_HDR [53] when in Models
-
- // LUMP_WORLDLIGHTS_HDR [54]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_WORLDLIGHTS_HDR];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var worldLights = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var worldLight = data.ReadType();
- if (worldLight != null)
- worldLights.Add(worldLight);
- }
-
- var lump = new WorldLightsLump();
- lump.WorldLights = [.. worldLights];
-
- file.WorldLightsLump = lump;
- }
-
- // LUMP_LEAF_AMBIENT_LIGHTING_HDR [55]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_LEAF_AMBIENT_LIGHTING_HDR];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var lightings = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var lighting = data.ReadType();
- if (lighting != null)
- lightings.Add(lighting);
- }
-
- var lump = new AmbientLightingLump();
- lump.Lightings = [.. lightings];
-
- file.HDRAmbientLightingLump = lump;
- }
-
- // LUMP_LEAF_AMBIENT_LIGHTING [56]
- lumpEntry = header.Lumps[(int)LumpType.LUMP_LEAF_AMBIENT_LIGHTING];
- if (lumpEntry != null && lumpEntry.Offset > 0 && lumpEntry.Length > 0)
- {
- // Seek to the lump offset
- data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
-
- // Read the lump data
- var lightings = new List();
- while (data.Position < lumpEntry.Offset + lumpEntry.Length)
- {
- var lighting = data.ReadType();
- if (lighting != null)
- lightings.Add(lighting);
- }
-
- var lump = new AmbientLightingLump();
- lump.Lightings = [.. lightings];
-
- file.LDRAmbientLightingLump = lump;
- }
-
- // TODO: Support LUMP_XZIPPAKFILE [57] when in Models
- // TODO: Support LUMP_FACES_HDR [58] when in Models
- // TODO: Support LUMP_MAP_FLAGS [59] when in Models
- // TODO: Support LUMP_OVERLAY_FADES [60] when in Models
- // TODO: Support LUMP_OVERLAY_SYSTEM_LEVELS [61] when in Models
- // TODO: Support LUMP_PHYSLEVEL [62] when in Models
- // TODO: Support LUMP_DISP_MULTIBLEND [63] when in Models
-
#endregion
return file;
@@ -860,5 +273,585 @@ namespace SabreTools.Serialization.Deserializers
return header;
}
+
+ ///
+ /// Parse a Stream into LUMP_ENTITIES
+ ///
+ /// Stream to parse
+ /// Filled LUMP_ENTITIES on success, null on error
+ private static EntitiesLump? ParseEntitiesLump(Stream data, int offset, int length)
+ {
+ var entities = new List();
+
+ // Read the entire lump as text
+ byte[] lumpData = data.ReadBytes(length);
+ string lumpText = Encoding.ASCII.GetString(lumpData);
+
+ // Break the text by ending curly braces
+ string[] lumpSections = lumpText.Split('}');
+ Array.ForEach(lumpSections, s => s.Trim('{', '}'));
+
+ // Loop through all sections
+ for (int i = 0; i < lumpSections.Length; i++)
+ {
+ // Prepare an attributes list
+ var attributes = new List>();
+
+ // Split the section by newlines
+ string section = lumpSections[i];
+ string[] lines = section.Split('\n');
+ Array.ForEach(lines, l => l.Trim());
+
+ // Convert each line into a key-value pair and add
+ for (int j = 0; j < lines.Length; j++)
+ {
+ // TODO: Split lines and add
+ }
+
+ // Create a new entity and add
+ var entity = new Entity { Attributes = attributes };
+ entities.Add(entity);
+ }
+
+ return new EntitiesLump { Entities = [.. entities] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_PLANES
+ ///
+ /// Stream to parse
+ /// Filled LUMP_PLANES on success, null on error
+ private static PlanesLump? ParsePlanesLump(Stream data, int offset, int length)
+ {
+ var planes = new List();
+ while (data.Position < offset + length)
+ {
+ var plane = data.ReadType();
+ if (plane != null)
+ planes.Add(plane);
+ }
+
+ return new PlanesLump { Planes = [.. planes] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_TEXDATA
+ ///
+ /// Stream to parse
+ /// Filled LUMP_TEXDATA on success, null on error
+ private static TexdataLump? ParseTexdataLump(Stream data, int offset, int length)
+ {
+ var texdatas = new List();
+ while (data.Position < offset + length)
+ {
+ var texdata = data.ReadType();
+ if (texdata != null)
+ texdatas.Add(texdata);
+ }
+
+ return new TexdataLump { Texdatas = [.. texdatas] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_VERTEXES
+ ///
+ /// Stream to parse
+ /// Filled LUMP_VERTEXES on success, null on error
+ private static VerticesLump? ParseVerticesLump(Stream data, int offset, int length)
+ {
+ var vertices = new List();
+ while (data.Position < offset + length)
+ {
+ vertices.Add(data.ReadType());
+ }
+
+ return new VerticesLump { Vertices = [.. vertices] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_VISIBILITY
+ ///
+ /// Stream to parse
+ /// Filled LUMP_VISIBILITY on success, null on error
+ private static VisibilityLump? ParseVisibilityLump(Stream data, int offset, int length)
+ {
+ var lump = new VisibilityLump();
+
+ lump.NumClusters = data.ReadInt32();
+ lump.ByteOffsets = new int[lump.NumClusters, 2];
+ for (int i = 0; i < lump.NumClusters; i++)
+ {
+ for (int j = 0; j < 2; j++)
+ {
+ lump.ByteOffsets[i, j] = data.ReadInt32();
+ }
+ }
+
+ return lump;
+ }
+
+ ///
+ /// Parse a Stream into LUMP_NODES
+ ///
+ /// Stream to parse
+ /// Filled LUMP_NODES on success, null on error
+ private static VbspNodesLump? ParseNodesLump(Stream data, int offset, int length)
+ {
+ var nodes = new List();
+ while (data.Position < offset + length)
+ {
+ var node = data.ReadType();
+ if (node != null)
+ nodes.Add(node);
+ }
+
+ return new VbspNodesLump { Nodes = [.. nodes] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_TEXINFO
+ ///
+ /// Stream to parse
+ /// Filled LUMP_TEXINFO on success, null on error
+ private static VbspTexinfoLump? ParseTexinfoLump(Stream data, int offset, int length)
+ {
+ var texinfos = new List();
+ while (data.Position < offset + length)
+ {
+ var texinfo = data.ReadType();
+ if (texinfo != null)
+ texinfos.Add(texinfo);
+ }
+
+ return new VbspTexinfoLump { Texinfos = [.. texinfos] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_FACES / LUMP_ORIGINALFACES
+ ///
+ /// Stream to parse
+ /// Filled LUMP_FACES / LUMP_ORIGINALFACES on success, null on error
+ private static VbspFacesLump? ParseFacesLump(Stream data, int offset, int length)
+ {
+ var faces = new List();
+ while (data.Position < offset + length)
+ {
+ var face = data.ReadType();
+ if (face != null)
+ faces.Add(face);
+ }
+
+ return new VbspFacesLump { Faces = [.. faces] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_LIGHTING
+ ///
+ /// Stream to parse
+ /// Filled LUMP_LIGHTING on success, null on error
+ private static LightmapLump? ParseLightmapLump(Stream data, int offset, int length)
+ {
+ var lump = new LightmapLump();
+ lump.Lightmap = new byte[length / 3, 3];
+
+ for (int i = 0; i < length / 3; i++)
+ {
+ for (int j = 0; j < 3; j++)
+ {
+ lump.Lightmap[i, j] = data.ReadByteValue();
+ }
+ }
+
+ return lump;
+ }
+
+ ///
+ /// Parse a Stream into LUMP_OCCLUSION
+ ///
+ /// Stream to parse
+ /// Filled LUMP_OCCLUSION on success, null on error
+ private static OcclusionLump? ParseOcclusionLump(Stream data, int offset, int length)
+ {
+ var lump = new OcclusionLump();
+
+ lump.Count = data.ReadInt32();
+ lump.Data = new OccluderData[lump.Count];
+ for (int i = 0; i < lump.Count; i++)
+ {
+ var occluderData = data.ReadType();
+ if (occluderData != null)
+ lump.Data[i] = occluderData;
+ }
+ lump.PolyDataCount = data.ReadInt32();
+ lump.PolyData = new OccluderPolyData[lump.Count];
+ for (int i = 0; i < lump.Count; i++)
+ {
+ var polyData = data.ReadType();
+ if (polyData != null)
+ lump.PolyData[i] = polyData;
+ }
+ lump.VertexIndexCount = data.ReadInt32();
+ lump.VertexIndices = new int[lump.VertexIndexCount];
+ for (int i = 0; i < lump.VertexIndexCount; i++)
+ {
+ lump.VertexIndices[i] = data.ReadInt32();
+ }
+
+ return lump;
+ }
+
+ ///
+ /// Parse a Stream into LUMP_LEAVES
+ ///
+ /// Stream to parse
+ /// Filled LUMP_LEAVES on success, null on error
+ private static VbspLeavesLump? ParseLeavesLump(Stream data, int offset, int length)
+ {
+ var leaves = new List();
+ while (data.Position < offset + length)
+ {
+ // TODO: Fix parsing between V0 and V1+
+ var leaf = data.ReadType();
+ if (leaf != null)
+ leaves.Add(leaf);
+ }
+
+ return new VbspLeavesLump { Leaves = [.. leaves] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_FACEIDS
+ ///
+ /// Stream to parse
+ /// Filled LUMP_FACEIDS on success, null on error
+ private static MarksurfacesLump? ParseMarksurfacesLump(Stream data, int offset, int length)
+ {
+ var marksurfaces = new List();
+ while (data.Position < offset + length)
+ {
+ marksurfaces.Add(data.ReadUInt16());
+ }
+
+ return new MarksurfacesLump { Marksurfaces = [.. marksurfaces] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_EDGES
+ ///
+ /// Stream to parse
+ /// Filled LUMP_EDGES on success, null on error
+ private static EdgesLump? ParseEdgesLump(Stream data, int offset, int length)
+ {
+ var edges = new List();
+ while (data.Position < offset + length)
+ {
+ var edge = data.ReadType();
+ if (edge != null)
+ edges.Add(edge);
+ }
+
+ return new EdgesLump { Edges = [.. edges] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_SURFEDGES
+ ///
+ /// Stream to parse
+ /// Filled LUMP_SURFEDGES on success, null on error
+ private static SurfedgesLump? ParseSurfedgesLump(Stream data, int offset, int length)
+ {
+ var surfedges = new List();
+ while (data.Position < offset + length)
+ {
+ surfedges.Add(data.ReadInt32());
+ }
+
+ return new SurfedgesLump { Surfedges = [.. surfedges] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_MODELS
+ ///
+ /// Stream to parse
+ /// Filled LUMP_MODELS on success, null on error
+ private static VbspModelsLump? ParseModelsLump(Stream data, int offset, int length)
+ {
+ var models = new List();
+ while (data.Position < offset + length)
+ {
+ var model = data.ReadType();
+ if (model != null)
+ models.Add(model);
+ }
+
+ return new VbspModelsLump { Models = [.. models] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_WORLDLIGHTS / LUMP_WORLDLIGHTS_HDR
+ ///
+ /// Stream to parse
+ /// Filled LUMP_WORLDLIGHTS / LUMP_WORLDLIGHTS_HDR on success, null on error
+ private static WorldLightsLump? ParseWorldLightsLump(Stream data, int offset, int length)
+ {
+ var worldLights = new List();
+ while (data.Position < offset + length)
+ {
+ var worldLight = data.ReadType();
+ if (worldLight != null)
+ worldLights.Add(worldLight);
+ }
+
+ return new WorldLightsLump { WorldLights = [.. worldLights] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_LEAFFACES
+ ///
+ /// Stream to parse
+ /// Filled LUMP_LEAFFACES on success, null on error
+ private static LeafFacesLump? ParseLeafFacesLump(Stream data, int offset, int length)
+ {
+ var map = new List();
+ while (data.Position < offset + length)
+ {
+ map.Add(data.ReadUInt16());
+ }
+
+ return new LeafFacesLump { Map = [.. map] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_LEAFBRUSHES
+ ///
+ /// Stream to parse
+ /// Filled LUMP_LEAFBRUSHES on success, null on error
+ private static LeafBrushesLump? ParseLeafBrushesLump(Stream data, int offset, int length)
+ {
+ var map = new List();
+ while (data.Position < offset + length)
+ {
+ map.Add(data.ReadUInt16());
+ }
+
+ return new LeafBrushesLump { Map = [.. map] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_BRUSHES
+ ///
+ /// Stream to parse
+ /// Filled LUMP_BRUSHES on success, null on error
+ private static BrushesLump? ParseBrushesLump(Stream data, int offset, int length)
+ {
+ var brushes = new List();
+ while (data.Position < offset + length)
+ {
+ var brush = data.ReadType();
+ if (brush != null)
+ brushes.Add(brush);
+ }
+
+ return new BrushesLump { Brushes = [.. brushes] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_BRUSHSIDES
+ ///
+ /// Stream to parse
+ /// Filled LUMP_BRUSHSIDES on success, null on error
+ private static BrushsidesLump? ParseBrushsidesLump(Stream data, int offset, int length)
+ {
+ var brushsides = new List();
+ while (data.Position < offset + length)
+ {
+ var brushside = data.ReadType();
+ if (brushside != null)
+ brushsides.Add(brushside);
+ }
+
+ return new BrushsidesLump { Brushsides = [.. brushsides] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_DISPINFO
+ ///
+ /// Stream to parse
+ /// Filled LUMP_DISPINFO on success, null on error
+ private static DispInfosLump? ParseDispInfosLump(Stream data, int offset, int length)
+ {
+ var dispInfos = new List();
+ while (data.Position < offset + length)
+ {
+ var dispInfo = data.ReadType();
+ if (dispInfo != null)
+ dispInfos.Add(dispInfo);
+ }
+
+ return new DispInfosLump { Infos = [.. dispInfos] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_DISP_VERTS
+ ///
+ /// Stream to parse
+ /// Filled LUMP_DISP_VERTS on success, null on error
+ private static DispVertsLump? ParseDispVertsLump(Stream data, int offset, int length)
+ {
+ var verts = new List();
+ while (data.Position < offset + length)
+ {
+ var vert = data.ReadType();
+ if (vert != null)
+ verts.Add(vert);
+ }
+
+ return new DispVertsLump { Verts = [.. verts] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_GAME_LUMP
+ ///
+ /// Stream to parse
+ /// Filled LUMP_GAME_LUMP on success, null on error
+ private static GameLump? ParseGameLump(Stream data, int offset, int length)
+ {
+ var lump = new GameLump();
+
+ lump.LumpCount = data.ReadInt32();
+ lump.Directories = new GameLumpDirectory[lump.LumpCount];
+ for (int i = 0; i < lump.LumpCount; i++)
+ {
+ var dir = data.ReadType();
+ if (dir != null)
+ lump.Directories[i] = dir;
+ }
+
+ return lump;
+ }
+
+ ///
+ /// Parse a Stream into LUMP_CUBEMAPS
+ ///
+ /// Stream to parse
+ /// Filled LUMP_CUBEMAPS on success, null on error
+ private static CubemapsLump? ParseCubemapsLump(Stream data, int offset, int length)
+ {
+ var cubemaps = new List();
+ while (data.Position < offset + length)
+ {
+ var cubemap = data.ReadType();
+ if (cubemap != null)
+ cubemaps.Add(cubemap);
+ }
+
+ return new CubemapsLump { Cubemaps = [.. cubemaps] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_TEXDATA_STRING_DATA
+ ///
+ /// Stream to parse
+ /// Filled LUMP_TEXDATA_STRING_DATA on success, null on error
+ private static TexdataStringData? ParseTexdataStringData(Stream data, int offset, int length)
+ {
+ var strings = new List();
+ while (data.Position < offset + length)
+ {
+ var str = data.ReadNullTerminatedAnsiString();
+ if (str != null)
+ strings.Add(str);
+ }
+
+ return new TexdataStringData { Strings = [.. strings] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_TEXDATA_STRING_TABLE
+ ///
+ /// Stream to parse
+ /// Filled LUMP_TEXDATA_STRING_TABLE on success, null on error
+ private static TexdataStringTable? ParseTexdataStringTable(Stream data, int offset, int length)
+ {
+ var offsets = new List();
+ while (data.Position < offset + length)
+ {
+ offsets.Add(data.ReadInt32());
+ }
+
+ return new TexdataStringTable { Offsets = [.. offsets] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_OVERLAYS
+ ///
+ /// Stream to parse
+ /// Filled LUMP_OVERLAYS on success, null on error
+ private static OverlaysLump? ParseOverlaysLump(Stream data, int offset, int length)
+ {
+ var overlays = new List();
+ while (data.Position < offset + length)
+ {
+ var overlay = data.ReadType();
+ if (overlay != null)
+ overlays.Add(overlay);
+ }
+
+ return new OverlaysLump { Overlays = [.. overlays] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_DISP_TRIS
+ ///
+ /// Stream to parse
+ /// Filled LUMP_DISP_TRIS on success, null on error
+ private static DispTrisLump? ParseDispTrisLump(Stream data, int offset, int length)
+ {
+ var tris = new List();
+ while (data.Position < offset + length)
+ {
+ var tri = data.ReadType();
+ if (tri != null)
+ tris.Add(tri);
+ }
+
+ return new DispTrisLump { Tris = [.. tris] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_LIGHTMAPPAGES / LUMP_LEAF_AMBIENT_INDEX_HDR / LUMP_LIGHTMAPPAGEINFOS / LUMP_LEAF_AMBIENT_INDEX
+ ///
+ /// Stream to parse
+ /// Filled LUMP_LIGHTMAPPAGES / LUMP_LEAF_AMBIENT_INDEX_HDR / LUMP_LIGHTMAPPAGEINFOS / LUMP_LEAF_AMBIENT_INDEX on success, null on error
+ private static AmbientIndexLump? ParseAmbientIndexLump(Stream data, int offset, int length)
+ {
+ var indicies = new List();
+ while (data.Position < offset + length)
+ {
+ var index = data.ReadType();
+ if (index != null)
+ indicies.Add(index);
+ }
+
+ return new AmbientIndexLump { Indicies = [.. indicies] };
+ }
+
+ ///
+ /// Parse a Stream into LUMP_LEAF_AMBIENT_LIGHTING_HDR / LUMP_LEAF_AMBIENT_LIGHTING
+ ///
+ /// Stream to parse
+ /// Filled LUMP_LEAF_AMBIENT_LIGHTING_HDR / LUMP_LEAF_AMBIENT_LIGHTING on success, null on error
+ private static AmbientLightingLump? ParseAmbientLightingLump(Stream data, int offset, int length)
+ {
+ var lightings = new List();
+ while (data.Position < offset + length)
+ {
+ var lighting = data.ReadType();
+ if (lighting != null)
+ lightings.Add(lighting);
+ }
+
+ return new AmbientLightingLump { Lightings = [.. lightings] };
+ }
}
}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Deserializers/WAD3.cs b/SabreTools.Serialization/Deserializers/WAD3.cs
index 6f3a4d73..a8181436 100644
--- a/SabreTools.Serialization/Deserializers/WAD3.cs
+++ b/SabreTools.Serialization/Deserializers/WAD3.cs
@@ -19,9 +19,6 @@ namespace SabreTools.Serialization.Deserializers
if (data.Position < 0 || data.Position >= data.Length)
return null;
- // Cache the current offset
- long initialOffset = data.Position;
-
// Create a new Half-Life Texture Package to fill
var file = new Models.WAD3.File();
diff --git a/SabreTools.Serialization/Deserializers/XZP.cs b/SabreTools.Serialization/Deserializers/XZP.cs
index cf2aceaf..5c93c269 100644
--- a/SabreTools.Serialization/Deserializers/XZP.cs
+++ b/SabreTools.Serialization/Deserializers/XZP.cs
@@ -1,5 +1,4 @@
using System.IO;
-using System.Text;
using SabreTools.IO.Extensions;
using SabreTools.Models.XZP;
using static SabreTools.Models.XZP.Constants;
@@ -19,9 +18,6 @@ namespace SabreTools.Serialization.Deserializers
if (data.Position < 0 || data.Position >= data.Length)
return null;
- // Cache the current offset
- long initialOffset = data.Position;
-
// Create a new XBox Package File to fill
var file = new Models.XZP.File();
@@ -43,11 +39,11 @@ namespace SabreTools.Serialization.Deserializers
file.DirectoryEntries = new DirectoryEntry[header.DirectoryEntryCount];
// Try to parse the directory entries
- for (int i = 0; i < header.DirectoryEntryCount; i++)
+ for (int i = 0; i < file.DirectoryEntries.Length; i++)
{
var directoryEntry = ParseDirectoryEntry(data);
if (directoryEntry == null)
- return null;
+ continue;
file.DirectoryEntries[i] = directoryEntry;
}
@@ -62,11 +58,11 @@ namespace SabreTools.Serialization.Deserializers
file.PreloadDirectoryEntries = new DirectoryEntry[header.PreloadDirectoryEntryCount];
// Try to parse the preload directory entries
- for (int i = 0; i < header.PreloadDirectoryEntryCount; i++)
+ for (int i = 0; i < file.PreloadDirectoryEntries.Length; i++)
{
var directoryEntry = ParseDirectoryEntry(data);
if (directoryEntry == null)
- return null;
+ continue;
file.PreloadDirectoryEntries[i] = directoryEntry;
}
@@ -82,11 +78,11 @@ namespace SabreTools.Serialization.Deserializers
file.PreloadDirectoryMappings = new DirectoryMapping[header.PreloadDirectoryEntryCount];
// Try to parse the preload directory mappings
- for (int i = 0; i < header.PreloadDirectoryEntryCount; i++)
+ for (int i = 0; i < file.PreloadDirectoryMappings.Length; i++)
{
var directoryMapping = ParseDirectoryMapping(data);
if (directoryMapping == null)
- return null;
+ continue;
file.PreloadDirectoryMappings[i] = directoryMapping;
}
@@ -110,7 +106,7 @@ namespace SabreTools.Serialization.Deserializers
file.DirectoryItems = new DirectoryItem[header.DirectoryItemCount];
// Try to parse the directory items
- for (int i = 0; i < header.DirectoryItemCount; i++)
+ for (int i = 0; i < file.DirectoryItems.Length; i++)
{
var directoryItem = ParseDirectoryItem(data);
file.DirectoryItems[i] = directoryItem;
@@ -146,9 +142,7 @@ namespace SabreTools.Serialization.Deserializers
{
var header = data.ReadType();
- if (header == null)
- return null;
- if (header.Signature != HeaderSignatureString)
+ if (header?.Signature != HeaderSignatureString)
return null;
if (header.Version != 6)
return null;
@@ -214,9 +208,7 @@ namespace SabreTools.Serialization.Deserializers
{
var footer = data.ReadType