Move Header/Footer extraction to method

This commit is contained in:
Deterous
2023-11-02 02:25:53 +13:00
parent 894b344b2e
commit 78f7960b1a
+181 -129
View File
@@ -103,82 +103,13 @@ namespace LibIRD
#endregion
/// <summary>
/// Process all files and subdirectories recursively
/// </summary>
/// <param name="reader"></param>
/// <param name="path"></param>
private void ParseDir(CDReader reader, string path)
{
DiscDirectoryInfo dir = reader.GetDirectoryInfo(path);
// Process all files in current directory
foreach (DiscFileInfo fileInfo in dir.GetFiles())
{
// Save directory full path
// Save offset
// Save start sector (offset)
// Save total sectors (count)
}
// Process all subfolders
foreach (DiscDirectoryInfo dirInfo in dir.GetDirectories())
{
// Save directory full path
// Save offset
// Save start sector (offset)
// Save total sectors (count)
ParseDir(reader, dirInfo.FullName);
}
}
/// <summary>
/// Determine PUP file offset via extent
/// </summary>
/// <param name="fs"></param>
/// <param name="reader"></param>
private void GetSystemVersion(FileStream fs, CDReader reader)
{
//DiscUtils.Streams.StreamExtent[] a = reader.PathToExtents("\\PS3_UPDATE\\PS3UPDAT.PUP");
//long pupOffset = a[0].Start;
// Determine PUP file offset via cluster
DiscUtils.Streams.Range<long, long>[] updateClusters = reader.PathToClusters("\\PS3_UPDATE\\PS3UPDAT.PUP");
long pupOffset = updateClusters[0] != null ? 2048 * updateClusters[0].Offset : 0;
// Check PUP file Magic
fs.Seek(pupOffset, SeekOrigin.Begin);
byte[] pupMagic = new byte[5];
fs.Read(pupMagic, 0, pupMagic.Length);
if (Encoding.ASCII.GetString(pupMagic) != "SCEUF")
{
// If magic is incorrect, set version to "0000" (unknown)
SystemVersion = "0000";
}
else
{
// Determine location of version string
fs.Seek(pupOffset + 0x3E, SeekOrigin.Begin);
byte[] offset = new byte[2];
fs.Read(offset, 0, 2);
// Move stream to PUP version string
Array.Reverse(offset);
ushort versionOffset = BitConverter.ToUInt16(offset, 0);
fs.Seek(pupOffset + versionOffset, SeekOrigin.Begin);
// Read version string
byte[] version = new byte[4];
fs.Read(version, 0, version.Length);
// Set version string
SystemVersion = Encoding.ASCII.GetString(version);
}
}
/// <summary>
/// Constructor for generating values from an ISO file
/// </summary>
/// <param name="isoPath">Path to the ISO</param>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="FileNotFoundException"></exception>
/// <exception cref="InvalidDataException"></exception>
internal PS3ISO(string isoPath)
{
// Validate ISO path
@@ -198,14 +129,14 @@ namespace LibIRD
FileCount = 13;
FileKeys = new ulong[FileCount];
for (int i = 0; i < FileCount; i++)
FileKeys[i] = (ulong)(i * 16);
FileKeys[i] = 0;
FileHashes = new byte[FileCount][];
for (int i = 0; i < FileCount; i++)
FileHashes[i] = NullMD5;
// Process ISO file
// Parse ISO file as a file stream
using FileStream fs = new FileStream(isoPath, FileMode.Open, FileAccess.Read) ?? throw new FileNotFoundException(isoPath);
// Validate ISO file
// Validate ISO file stream
if (!CDReader.Detect(fs))
throw new InvalidDataException("Not a valid ISO file");
@@ -217,7 +148,6 @@ namespace LibIRD
{
// Parse PARAM.SFO file
ParamSFO paramSFO = new(s);
// Store required values for IRD
TitleID = paramSFO["TITLE_ID"];
Title = paramSFO["TITLE"];
@@ -228,65 +158,187 @@ namespace LibIRD
// Determine system update version
GetSystemVersion(fs, reader);
// Read the ISO header
GetHeader(fs, reader);
// Determine the extent of the Header (Sector 0 to first data sector)
//DiscUtils.Streams.Range<long, long> clusters = reader.PathToClusters("\\").First();
//long firstSector = clusters.Offset;
//long totalSectors = (long) Math.Ceiling(clusters.Count / 2048.0);
// Read the ISO footer
GetFooter(fs, reader);
// Compress the header and store
DiscUtils.Streams.Range<long, long>[] sfbClusters = reader.PathToClusters("\\PS3_DISC.SFB");
long firstSector = sfbClusters[0] != null ? sfbClusters[0].Offset : 0;
using (MemoryStream headerStream = new())
{
using (GZipStream gzs = new(headerStream, CompressionLevel.SmallestSize))
{
fs.Seek(0, SeekOrigin.Begin);
byte[] buf = new byte[2048];
// Read all sectors before the first data sector
for (int i = 0; i < firstSector; i++)
{
int numBytes = fs.Read(buf, 0, buf.Length);
gzs.Write(buf, 0, numBytes);
}
}
Header = headerStream.ToArray();
HeaderLength = (uint)Header.Length;
}
// Compress the footer and store
DiscUtils.Streams.StreamExtent[] updateBytes = reader.PathToExtents("\\PS3_UPDATE\\PS3UPDAT.PUP");
long lastByte = updateBytes[^1].Start + updateBytes[^1].Length;
using (MemoryStream footerStream = new())
{
using (GZipStream gzs = new(footerStream, CompressionLevel.SmallestSize))
{
// Start saving data from after last file
fs.Seek(lastByte, SeekOrigin.Begin);
byte[] buf = new byte[2048];
int numBytes = 2048;
// Keep reading data until there is none left to read
while (numBytes != 0)
{
numBytes = fs.Read(buf, 0, buf.Length);
gzs.Write(buf, 0, numBytes);
}
}
Footer = footerStream.ToArray();
FooterLength = (uint)Footer.Length;
}
// Get info on root directory
//DiscDirectoryInfo rootDir = reader.GetDirectoryInfo("\\");
// Recursively process all subdirectories
// Recursively process all directories and files in ISO
ParseDir(reader, "\\");
}
// Calculate last sector
//DiscDirectoryInfo lastFile = reader.
//lastSector = lastFile.StartSector + lastFile.TotalSectors;
/// <summary>
/// Process all files and subdirectories recursively
/// </summary>
/// <param name="reader"></param>
/// <param name="path"></param>
private void ParseDir(CDReader reader, string path)
{
// Process current directory
DiscDirectoryInfo dir = reader.GetDirectoryInfo(path);
// Process all files in current directory
foreach (DiscFileInfo fileInfo in dir.GetFiles())
{
// Save directory full path
// Save offset
// Save start sector (offset)
// Save total sectors (count)
}
// Recursively process all subfolders of current directory
foreach (DiscDirectoryInfo dirInfo in dir.GetDirectories())
{
// Save directory full path
// Save offset
// Save start sector (offset)
// Save total sectors (count)
ParseDir(reader, dirInfo.FullName);
}
}
/// <summary>
/// Retreives and stores the system version
/// </summary>
/// <remarks>PS3UPDAT.PUP update file version number</remarks>
/// <param name="fs">ISO filestream</param>
/// <param name="reader"></param>
/// <exception cref="InvalidDataException"></exception>
private void GetSystemVersion(FileStream fs, CDReader reader)
{
// Determine PUP file offset via cluster
long pupOffset;
DiscUtils.Streams.Range<long, long>[] updateClusters = reader.PathToClusters("\\PS3_UPDATE\\PS3UPDAT.PUP");
if (updateClusters == null || updateClusters.Length <= 0)
{
// File too small for dedicated cluster, try get the offset from the file extents instead
DiscUtils.Streams.StreamExtent[] updateExtents = reader.PathToExtents("\\PS3_UPDATE\\PS3UPDAT.PUP");
if (updateExtents == null || updateExtents.Length <= 0)
throw new InvalidDataException("Unexpected PS3UPDAT.PUP file extent in ISO filestream");
pupOffset = updateExtents[0].Start;
}
else
{
// PS3UPDAT.PUP file begins at first byte of dedicated cluster
pupOffset = updateClusters[0] != null ? 2048 * updateClusters[0].Offset : 0;
}
// Check PUP file Magic
fs.Seek(pupOffset, SeekOrigin.Begin);
byte[] pupMagic = new byte[5];
fs.Read(pupMagic, 0, pupMagic.Length);
// If magic is incorrect, set version to "0000" (unknown)
if (Encoding.ASCII.GetString(pupMagic) != "SCEUF")
SystemVersion = "0000";
else
{
// Determine location of version string
fs.Seek(pupOffset + 0x3E, SeekOrigin.Begin);
byte[] offset = new byte[2];
fs.Read(offset, 0, 2);
// Move stream to PUP version string
Array.Reverse(offset);
ushort versionOffset = BitConverter.ToUInt16(offset, 0);
fs.Seek(pupOffset + versionOffset, SeekOrigin.Begin);
// Read version string
byte[] version = new byte[4];
fs.Read(version, 0, version.Length);
// Set version string
SystemVersion = Encoding.ASCII.GetString(version);
}
}
/// <summary>
/// Retreives and stores the header
/// </summary>
/// <param name="fs">ISO filestream</param>
/// <param name="reader"></param>
private void GetHeader(FileStream fs, CDReader reader)
{
// Determine the extent of the geader via cluster (Sector 0 to first data sector)
long firstSector;
DiscUtils.Streams.Range<long, long>[] sfbClusters = reader.PathToClusters("\\PS3_DISC.SFB");
if (sfbClusters == null || sfbClusters.Length <= 0)
{
// File too small for dedicated cluster, try get the first sector from the file extents instead
DiscUtils.Streams.StreamExtent[] sfbExtents = reader.PathToExtents("\\PS3_DISC.SFB");
if (sfbExtents == null || sfbExtents.Length <= 0)
throw new InvalidDataException("Unexpected PS3UPDAT.PUP file extent in ISO filestream");
firstSector = sfbExtents[0].Start;
}
else
{
// End of header is at beginning of first byte of dedicated cluster
firstSector = sfbClusters[0] != null ? sfbClusters[0].Offset : 0;
}
// Begin a GZip stream to write header to
using MemoryStream headerStream = new();
using (GZipStream gzs = new(headerStream, CompressionLevel.SmallestSize))
{
// Start reading data from the beginning of the ISO file
fs.Seek(0, SeekOrigin.Begin);
byte[] buf = new byte[2048];
int numBytes;
// Read all data before the first data sector
for (int i = 0; i < firstSector; i++)
{
numBytes = fs.Read(buf, 0, buf.Length);
gzs.Write(buf, 0, numBytes);
}
}
// Save stream to field
Header = headerStream.ToArray();
HeaderLength = (uint)Header.Length;
}
/// <summary>
/// Retreives and stores the footer
/// </summary>
/// <param name="fs">ISO filestream</param>
/// <param name="reader"></param>
private void GetFooter(FileStream fs, CDReader reader)
{
// Determine the extent of the footer via cluster (After last data byte to last ISO sector)
long lastByte;
DiscUtils.Streams.StreamExtent[] updateBytes = reader.PathToExtents("\\PS3_UPDATE\\PS3UPDAT.PUP");
if (updateBytes == null || updateBytes.Length <= 0)
{
// File too small for dedicated cluster, try get the last byte from the file extents instead
DiscUtils.Streams.StreamExtent[] updateExtents = reader.PathToExtents("\\PS3_UPDATE\\PS3UPDAT.PUP");
if (updateExtents == null || updateExtents.Length <= 0)
throw new InvalidDataException("Unexpected PS3UPDAT.PUP file extent in ISO filestream");
lastByte = updateExtents[^1].Start + updateExtents[^1].Length;
}
else
{
// Start of footer is after last byte of dedicated cluster
lastByte = updateBytes[^1].Start + updateBytes[^1].Length;
}
// Begin a GZip stream to write footer to
using MemoryStream footerStream = new();
using (GZipStream gzs = new(footerStream, CompressionLevel.SmallestSize))
{
// Start reading data from after last file
fs.Seek(lastByte, SeekOrigin.Begin);
byte[] buf = new byte[2048];
int numBytes = 2048;
// Keep reading data until there is none left to read
while (numBytes != 0)
{
numBytes = fs.Read(buf, 0, buf.Length);
gzs.Write(buf, 0, numBytes);
}
}
// Save stream to field
Footer = footerStream.ToArray();
FooterLength = (uint)Footer.Length;
}
}
}