Files
Matt Nadareski 8f49e190d8 Fix everything
2026-03-24 19:17:25 -04:00

948 lines
34 KiB
C#

using System.Collections.Generic;
using System.IO;
using System.Text;
using SabreTools.Data.Models.SGA;
using SabreTools.IO.Extensions;
using SabreTools.Numerics.Extensions;
using SabreTools.Text.Extensions;
using static SabreTools.Data.Models.SGA.Constants;
#pragma warning disable IDE0017 // Simplify object initialization
namespace SabreTools.Serialization.Readers
{
public class SGA : BaseBinaryReader<Archive>
{
/// <inheritdoc/>
public override Archive? Deserialize(Stream? data)
{
// If the data is invalid
if (data is null || !data.CanRead)
return null;
try
{
// Cache the current offset
long initialOffset = data.Position;
// Create a new SGA to fill
var archive = new Archive();
#region Header
// Try to parse the header
var header = ParseHeader(data);
if (header is null)
return null;
// Set the SGA header
archive.Header = header;
#endregion
#region Directory
// Try to parse the directory
var directory = ParseDirectory(data, header.MajorVersion);
if (directory is null)
return null;
// Set the SGA directory
archive.Directory = directory;
#endregion
return archive;
}
catch
{
// Ignore the actual error
return null;
}
}
/// <summary>
/// Parse a Stream into an SGA header
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled SGA header on success, null on error</returns>
private static Header? ParseHeader(Stream data)
{
byte[] signatureBytes = data.ReadBytes(8);
string signature = Encoding.ASCII.GetString(signatureBytes);
if (signature != SignatureString)
return null;
ushort majorVersion = data.ReadUInt16LittleEndian();
ushort minorVersion = data.ReadUInt16LittleEndian();
if (minorVersion != 0)
return null;
switch (majorVersion)
{
// Versions 4 and 5 share the same header
case 4:
case 5:
var header4 = new Header4();
header4.Signature = signature;
header4.MajorVersion = majorVersion;
header4.MinorVersion = minorVersion;
header4.FileMD5 = data.ReadBytes(0x10);
byte[] header4Name = data.ReadBytes(count: 128);
header4.Name = Encoding.Unicode.GetString(header4Name).TrimEnd('\0');
header4.HeaderMD5 = data.ReadBytes(0x10);
header4.HeaderLength = data.ReadUInt32LittleEndian();
header4.FileDataOffset = data.ReadUInt32LittleEndian();
header4.Dummy0 = data.ReadUInt32LittleEndian();
return header4;
// Versions 6 and 7 share the same header
case 6:
case 7:
var header6 = new Header6();
header6.Signature = signature;
header6.MajorVersion = majorVersion;
header6.MinorVersion = minorVersion;
byte[] header6Name = data.ReadBytes(count: 128);
header6.Name = Encoding.Unicode.GetString(header6Name).TrimEnd('\0');
header6.HeaderLength = data.ReadUInt32LittleEndian();
header6.FileDataOffset = data.ReadUInt32LittleEndian();
header6.Dummy0 = data.ReadUInt32LittleEndian();
return header6;
// No other major versions are recognized
default:
return null;
}
}
/// <summary>
/// Parse a Stream into an SGA directory
/// </summary>
/// <param name="data">Stream to parse</param>
/// <param name="majorVersion">SGA major version</param>
/// <returns>Filled SGA directory on success, null on error</returns>
private static Data.Models.SGA.Directory? ParseDirectory(Stream data, ushort majorVersion)
{
return majorVersion switch
{
4 => ParseDirectory4(data),
5 => ParseDirectory5(data),
6 => ParseDirectory6(data),
7 => ParseDirectory7(data),
_ => null,
};
}
/// <summary>
/// Parse a Stream into an SGA directory
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled SGA directory on success, null on error</returns>
private static Directory4? ParseDirectory4(Stream data)
{
var directory = new Directory4();
// Cache the current offset
long currentOffset = data.Position;
#region Directory Header
// Try to parse the directory header
var directoryHeader = ParseDirectory4Header(data);
if (directoryHeader is null)
return null;
// Set the directory header
directory.DirectoryHeader = directoryHeader;
#endregion
#region Sections
// Get and adjust the sections offset
long sectionOffset = currentOffset + directoryHeader.SectionOffset;
// Validate the offset
if (sectionOffset < currentOffset || sectionOffset >= data.Length)
return null;
// Seek to the sections
data.SeekIfPossible(sectionOffset, SeekOrigin.Begin);
// Create the sections array
directory.Sections = new Section4[directoryHeader.SectionCount];
// Try to parse the sections
for (int i = 0; i < directory.Sections.Length; i++)
{
directory.Sections[i] = ParseSection4(data);
}
#endregion
#region Folders
// Get and adjust the folders offset
long folderOffset = currentOffset + directoryHeader.FolderOffset;
// Validate the offset
if (folderOffset < currentOffset || folderOffset >= data.Length)
return null;
// Seek to the folders
data.SeekIfPossible(folderOffset, SeekOrigin.Begin);
// Create the folders array
directory.Folders = new Folder4[directoryHeader.FolderCount];
// Try to parse the folders
for (int i = 0; i < directory.Folders.Length; i++)
{
directory.Folders[i] = ParseFolder4(data);
}
#endregion
#region Files
// Get and adjust the files offset
long fileOffset = currentOffset + directoryHeader.FileOffset;
// Validate the offset
if (fileOffset < currentOffset || fileOffset >= data.Length)
return null;
// Seek to the files
data.SeekIfPossible(fileOffset, SeekOrigin.Begin);
// Get the file count
uint fileCount = directoryHeader.FileCount;
// Create the files array
directory.Files = new File4[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 = currentOffset + directoryHeader.StringTableOffset;
// Validate the offset
if (stringTableOffset < currentOffset || stringTableOffset >= data.Length)
return null;
// Seek to the string table
data.SeekIfPossible(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<long, string>(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() ?? string.Empty;
}
// Loop through all folders to assign names
for (int i = 0; i < directory.Folders.Length; i++)
{
var folder = directory.Folders[i];
if (folder is 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 is null)
continue;
file.Name = directory.StringTable[file.NameOffset];
}
#endregion
return directory;
}
/// <summary>
/// Parse a Stream into an SGA directory
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled SGA directory on success, null on error</returns>
private static Directory5? ParseDirectory5(Stream data)
{
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 is null)
return null;
// Set the directory header
directory.DirectoryHeader = directoryHeader;
#endregion
#region Sections
// Get and adjust the sections offset
long sectionOffset = currentOffset + directoryHeader.SectionOffset;
// Validate the offset
if (sectionOffset < currentOffset || sectionOffset >= data.Length)
return null;
// Seek to the sections
data.SeekIfPossible(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 = currentOffset + directoryHeader.FolderOffset;
// Validate the offset
if (folderOffset < currentOffset || folderOffset >= data.Length)
return null;
// Seek to the folders
data.SeekIfPossible(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 = currentOffset + directoryHeader.FileOffset;
// Validate the offset
if (fileOffset < currentOffset || fileOffset >= data.Length)
return null;
// Seek to the files
data.SeekIfPossible(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 = currentOffset + directoryHeader.StringTableOffset;
// Validate the offset
if (stringTableOffset < currentOffset || stringTableOffset >= data.Length)
return null;
// Seek to the string table
data.SeekIfPossible(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<long, string>((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() ?? string.Empty;
}
// Loop through all folders to assign names
for (int i = 0; i < directory.Folders.Length; i++)
{
var folder = directory.Folders[i];
if (folder is 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 is null)
continue;
file.Name = directory.StringTable[file.NameOffset];
}
#endregion
return directory;
}
/// <summary>
/// Parse a Stream into an SGA directory
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled SGA directory on success, null on error</returns>
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 is null)
return null;
// Set the directory header
directory.DirectoryHeader = directoryHeader;
#endregion
#region Sections
// Get and adjust the sections offset
long sectionOffset = currentOffset + directoryHeader.SectionOffset;
// Validate the offset
if (sectionOffset < currentOffset || sectionOffset >= data.Length)
return null;
// Seek to the sections
data.SeekIfPossible(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 = currentOffset + directoryHeader.FolderOffset;
// Validate the offset
if (folderOffset < currentOffset || folderOffset >= data.Length)
return null;
// Seek to the folders
data.SeekIfPossible(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 = currentOffset + directoryHeader.FileOffset;
// Validate the offset
if (fileOffset < currentOffset || fileOffset >= data.Length)
return null;
// Seek to the files
data.SeekIfPossible(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 = currentOffset + directoryHeader.StringTableOffset;
// Validate the offset
if (stringTableOffset < currentOffset || stringTableOffset >= data.Length)
return null;
// Seek to the string table
data.SeekIfPossible(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<long, string>((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() ?? string.Empty;
}
// Loop through all folders to assign names
for (int i = 0; i < directory.Folders.Length; i++)
{
var folder = directory.Folders[i];
if (folder is 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 is null)
continue;
file.Name = directory.StringTable[file.NameOffset];
}
#endregion
return directory;
}
/// <summary>
/// Parse a Stream into an SGA directory
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled SGA directory on success, null on error</returns>
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 is null)
return null;
// Set the directory header
directory.DirectoryHeader = directoryHeader;
#endregion
#region Sections
// Get and adjust the sections offset
long sectionOffset = currentOffset + directoryHeader.SectionOffset;
// Validate the offset
if (sectionOffset < currentOffset || sectionOffset >= data.Length)
return null;
// Seek to the sections
data.SeekIfPossible(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 = currentOffset + directoryHeader.FolderOffset;
// Validate the offset
if (folderOffset < currentOffset || folderOffset >= data.Length)
return null;
// Seek to the folders
data.SeekIfPossible(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 = currentOffset + directoryHeader.FileOffset;
// Validate the offset
if (fileOffset < currentOffset || fileOffset >= data.Length)
return null;
// Seek to the files
data.SeekIfPossible(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 = currentOffset + directoryHeader.StringTableOffset;
// Validate the offset
if (stringTableOffset < currentOffset || stringTableOffset >= data.Length)
return null;
// Seek to the string table
data.SeekIfPossible(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<long, string>((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() ?? string.Empty;
}
// Loop through all folders to assign names
for (int i = 0; i < directory.Folders.Length; i++)
{
var folder = directory.Folders[i];
if (folder is 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 is null)
continue;
file.Name = directory.StringTable[file.NameOffset];
}
#endregion
return directory;
}
/// <summary>
/// Parse a Stream into an SGA directory header version 4
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled SGA directory header version 4 on success, null on error</returns>
private static DirectoryHeader4 ParseDirectory4Header(Stream data)
{
var directoryHeader4 = new DirectoryHeader4();
directoryHeader4.SectionOffset = data.ReadUInt32LittleEndian();
directoryHeader4.SectionCount = data.ReadUInt16LittleEndian();
directoryHeader4.FolderOffset = data.ReadUInt32LittleEndian();
directoryHeader4.FolderCount = data.ReadUInt16LittleEndian();
directoryHeader4.FileOffset = data.ReadUInt32LittleEndian();
directoryHeader4.FileCount = data.ReadUInt16LittleEndian();
directoryHeader4.StringTableOffset = data.ReadUInt32LittleEndian();
directoryHeader4.StringTableCount = data.ReadUInt16LittleEndian();
return directoryHeader4;
}
/// <summary>
/// Parse a Stream into an SGA directory header version 5
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled SGA directory header version 5 on success, null on error</returns>
private static DirectoryHeader5 ParseDirectory5Header(Stream data)
{
var directoryHeader5 = new DirectoryHeader5();
directoryHeader5.SectionOffset = data.ReadUInt32LittleEndian();
directoryHeader5.SectionCount = data.ReadUInt32LittleEndian();
directoryHeader5.FolderOffset = data.ReadUInt32LittleEndian();
directoryHeader5.FolderCount = data.ReadUInt32LittleEndian();
directoryHeader5.FileOffset = data.ReadUInt32LittleEndian();
directoryHeader5.FileCount = data.ReadUInt32LittleEndian();
directoryHeader5.StringTableOffset = data.ReadUInt32LittleEndian();
directoryHeader5.StringTableCount = data.ReadUInt32LittleEndian();
return directoryHeader5;
}
/// <summary>
/// Parse a Stream into an SGA directory header version 7
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled SGA directory header version 7 on success, null on error</returns>
private static DirectoryHeader7 ParseDirectory7Header(Stream data)
{
var directoryHeader7 = new DirectoryHeader7();
directoryHeader7.SectionOffset = data.ReadUInt32LittleEndian();
directoryHeader7.SectionCount = data.ReadUInt32LittleEndian();
directoryHeader7.FolderOffset = data.ReadUInt32LittleEndian();
directoryHeader7.FolderCount = data.ReadUInt32LittleEndian();
directoryHeader7.FileOffset = data.ReadUInt32LittleEndian();
directoryHeader7.FileCount = data.ReadUInt32LittleEndian();
directoryHeader7.StringTableOffset = data.ReadUInt32LittleEndian();
directoryHeader7.StringTableCount = data.ReadUInt32LittleEndian();
directoryHeader7.HashTableOffset = data.ReadUInt32LittleEndian();
directoryHeader7.BlockSize = data.ReadUInt32LittleEndian();
return directoryHeader7;
}
/// <summary>
/// Parse a Stream into an SGA section version 4
/// </summary>
/// <param name="data">Stream to parse</param>
/// <param name="majorVersion">SGA major version</param>
/// <returns>Filled SGA section version 4 on success, null on error</returns>
private static Section4 ParseSection4(Stream data)
{
var section4 = new Section4();
byte[] section4Alias = data.ReadBytes(64);
section4.Alias = Encoding.ASCII.GetString(section4Alias).TrimEnd('\0');
byte[] section4Name = data.ReadBytes(64);
section4.Name = Encoding.ASCII.GetString(section4Name).TrimEnd('\0');
section4.FolderStartIndex = data.ReadUInt16LittleEndian();
section4.FolderEndIndex = data.ReadUInt16LittleEndian();
section4.FileStartIndex = data.ReadUInt16LittleEndian();
section4.FileEndIndex = data.ReadUInt16LittleEndian();
section4.FolderRootIndex = data.ReadUInt16LittleEndian();
return section4;
}
/// <summary>
/// Parse a Stream into an SGA section version 5
/// </summary>
/// <param name="data">Stream to parse</param>
/// <param name="majorVersion">SGA major version</param>
/// <returns>Filled SGA section version 5 on success, null on error</returns>
private static Section5 ParseSection5(Stream data)
{
var section5 = new Section5();
byte[] section5Alias = data.ReadBytes(64);
section5.Alias = Encoding.ASCII.GetString(section5Alias).TrimEnd('\0');
byte[] section5Name = data.ReadBytes(64);
section5.Name = Encoding.ASCII.GetString(section5Name).TrimEnd('\0');
section5.FolderStartIndex = data.ReadUInt32LittleEndian();
section5.FolderEndIndex = data.ReadUInt32LittleEndian();
section5.FileStartIndex = data.ReadUInt32LittleEndian();
section5.FileEndIndex = data.ReadUInt32LittleEndian();
section5.FolderRootIndex = data.ReadUInt32LittleEndian();
return section5;
}
/// <summary>
/// Parse a Stream into an SGA folder version 4
/// </summary>
/// <param name="data">Stream to parse</param>
/// <param name="majorVersion">SGA major version</param>
/// <returns>Filled SGA folder version 4 on success, null on error</returns>
private static Folder4 ParseFolder4(Stream data)
{
var folder4 = new Folder4();
folder4.NameOffset = data.ReadUInt32LittleEndian();
folder4.Name = null; // Read from string table
folder4.FolderStartIndex = data.ReadUInt16LittleEndian();
folder4.FolderEndIndex = data.ReadUInt16LittleEndian();
folder4.FileStartIndex = data.ReadUInt16LittleEndian();
folder4.FileEndIndex = data.ReadUInt16LittleEndian();
return folder4;
}
/// <summary>
/// Parse a Stream into an SGA folder version 5
/// </summary>
/// <param name="data">Stream to parse</param>
/// <param name="majorVersion">SGA major version</param>
/// <returns>Filled SGA folder version 5 on success, null on error</returns>
private static Folder5 ParseFolder5(Stream data)
{
var folder5 = new Folder5();
folder5.NameOffset = data.ReadUInt32LittleEndian();
folder5.Name = null; // Read from string table
folder5.FolderStartIndex = data.ReadUInt32LittleEndian();
folder5.FolderEndIndex = data.ReadUInt32LittleEndian();
folder5.FileStartIndex = data.ReadUInt32LittleEndian();
folder5.FileEndIndex = data.ReadUInt32LittleEndian();
return folder5;
}
/// <summary>
/// Parse a Stream into an SGA file version 4
/// </summary>
/// <param name="data">Stream to parse</param>
/// <param name="majorVersion">SGA major version</param>
/// <returns>Filled SGA file version 4 on success, null on error</returns>
private static File4 ParseFile4(Stream data)
{
var file4 = new File4();
file4.NameOffset = data.ReadUInt32LittleEndian();
file4.Name = string.Empty; // Read from string table
file4.Offset = data.ReadUInt32LittleEndian();
file4.SizeOnDisk = data.ReadUInt32LittleEndian();
file4.Size = data.ReadUInt32LittleEndian();
file4.TimeModified = data.ReadUInt32LittleEndian();
file4.Dummy0 = data.ReadByteValue();
file4.Type = data.ReadByteValue();
return file4;
}
/// <summary>
/// Parse a Stream into an SGA file version 6
/// </summary>
/// <param name="data">Stream to parse</param>
/// <param name="majorVersion">SGA major version</param>
/// <returns>Filled SGA file version 6 on success, null on error</returns>
private static File6 ParseFile6(Stream data)
{
var file6 = new File6();
file6.NameOffset = data.ReadUInt32LittleEndian();
file6.Name = string.Empty; // Read from string table
file6.Offset = data.ReadUInt32LittleEndian();
file6.SizeOnDisk = data.ReadUInt32LittleEndian();
file6.Size = data.ReadUInt32LittleEndian();
file6.TimeModified = data.ReadUInt32LittleEndian();
file6.Dummy0 = data.ReadByteValue();
file6.Type = data.ReadByteValue();
file6.CRC32 = data.ReadUInt32LittleEndian();
return file6;
}
/// <summary>
/// Parse a Stream into an SGA file version 7
/// </summary>
/// <param name="data">Stream to parse</param>
/// <param name="majorVersion">SGA major version</param>
/// <returns>Filled SGA file version 7 on success, null on error</returns>
private static File7 ParseFile7(Stream data)
{
var file7 = new File7();
file7.NameOffset = data.ReadUInt32LittleEndian();
file7.Name = string.Empty; // Read from string table
file7.Offset = data.ReadUInt32LittleEndian();
file7.SizeOnDisk = data.ReadUInt32LittleEndian();
file7.Size = data.ReadUInt32LittleEndian();
file7.TimeModified = data.ReadUInt32LittleEndian();
file7.Dummy0 = data.ReadByteValue();
file7.Type = data.ReadByteValue();
file7.CRC32 = data.ReadUInt32LittleEndian();
file7.HashOffset = data.ReadUInt32LittleEndian();
return file7;
}
}
}