From 78f7960b1a6e3a2db77d305f12487989cd879c36 Mon Sep 17 00:00:00 2001 From: Deterous <138427222+Deterous@users.noreply.github.com> Date: Thu, 2 Nov 2023 02:25:53 +1300 Subject: [PATCH] Move Header/Footer extraction to method --- LibIRD/PS3ISO.cs | 310 +++++++++++++++++++++++++++-------------------- 1 file changed, 181 insertions(+), 129 deletions(-) diff --git a/LibIRD/PS3ISO.cs b/LibIRD/PS3ISO.cs index cb4b138..b0a2aea 100644 --- a/LibIRD/PS3ISO.cs +++ b/LibIRD/PS3ISO.cs @@ -103,82 +103,13 @@ namespace LibIRD #endregion - /// - /// Process all files and subdirectories recursively - /// - /// - /// - 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); - } - } - - /// - /// Determine PUP file offset via extent - /// - /// - /// - 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[] 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); - } - } - /// /// Constructor for generating values from an ISO file /// /// Path to the ISO /// + /// + /// 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 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[] 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; + /// + /// Process all files and subdirectories recursively + /// + /// + /// + 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); + } + } + + /// + /// Retreives and stores the system version + /// + /// PS3UPDAT.PUP update file version number + /// ISO filestream + /// + /// + private void GetSystemVersion(FileStream fs, CDReader reader) + { + // Determine PUP file offset via cluster + long pupOffset; + DiscUtils.Streams.Range[] 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); + } + } + + /// + /// Retreives and stores the header + /// + /// ISO filestream + /// + 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[] 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; + } + + /// + /// Retreives and stores the footer + /// + /// ISO filestream + /// + 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; } } }