From 07a3a3a7f19bf03761158aa0c6f336a9f6f7343a Mon Sep 17 00:00:00 2001
From: Deterous <138427222+Deterous@users.noreply.github.com>
Date: Wed, 31 Jan 2024 20:13:42 +0900
Subject: [PATCH] Correct number of files for non-contiguous ISOs
---
IRDKit/IRDKit.csproj | 4 ++--
IRDKit/Program.cs | 18 +++++++++++++++---
LibIRD/IRD.cs | 36 ++++++++++++++++++++++++++++--------
LibIRD/LibIRD.csproj | 4 ++--
README.md | 13 +++++--------
5 files changed, 52 insertions(+), 23 deletions(-)
diff --git a/IRDKit/IRDKit.csproj b/IRDKit/IRDKit.csproj
index d5c468c..b972c8c 100644
--- a/IRDKit/IRDKit.csproj
+++ b/IRDKit/IRDKit.csproj
@@ -10,7 +10,7 @@
win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64
latest
true
- 0.2.1
+ 0.3.0
Deterous
@@ -32,7 +32,7 @@
-
+
diff --git a/IRDKit/Program.cs b/IRDKit/Program.cs
index ce8e6b1..17c9fca 100644
--- a/IRDKit/Program.cs
+++ b/IRDKit/Program.cs
@@ -382,7 +382,7 @@ namespace IRDKit
// Write PS3_DISC.SFB info
try
{
- using DiscUtils.Streams.SparseStream s = reader.OpenFile(Path.Combine($"{Path.DirectorySeparatorChar}", "PS3_DISC.SFB"), FileMode.Open, FileAccess.Read);
+ using DiscUtils.Streams.SparseStream s = reader.OpenFile("\\PS3_DISC.SFB", FileMode.Open, FileAccess.Read);
PS3_DiscSFB ps3_DiscSFB = new(s);
if (json)
{
@@ -419,7 +419,7 @@ namespace IRDKit
// Write PARAM.SFO info
try
{
- using DiscUtils.Streams.SparseStream s = reader.OpenFile(Path.Combine("PS3_GAME", "PARAM.SFO"), FileMode.Open, FileAccess.Read);
+ using DiscUtils.Streams.SparseStream s = reader.OpenFile("\\PS3_GAME\\PARAM.SFO", FileMode.Open, FileAccess.Read);
ParamSFO paramSFO = new(s);
if (json)
{
@@ -520,6 +520,10 @@ namespace IRDKit
printText.AppendLine($"Region Count: {IRD1.RegionCount} vs {IRD2.RegionCount}");
int regionCount = IRD2.RegionCount < IRD1.RegionCount ? IRD2.RegionCount : IRD1.RegionCount;
+ if (regionCount > IRD1.RegionHashes.Length)
+ regionCount = IRD1.RegionHashes.Length;
+ if (regionCount > IRD2.RegionHashes.Length)
+ regionCount = IRD2.RegionHashes.Length;
for (int i = 0; i < regionCount; i++)
{
if (!IRD1.RegionHashes[i].SequenceEqual(IRD2.RegionHashes[i]))
@@ -529,7 +533,15 @@ namespace IRDKit
if (IRD1.FileCount != IRD2.FileCount)
printText.AppendLine($"File Count: {IRD1.FileCount} vs {IRD2.FileCount}");
- uint fileCount = IRD2.FileCount < IRD1.FileCount ? IRD2.FileCount : IRD1.FileCount;
+ int fileCount = IRD2.FileCount < IRD1.FileCount ? (int)IRD2.FileCount : (int)IRD1.FileCount;
+ if (fileCount > IRD1.FileKeys.Length)
+ fileCount = IRD1.FileKeys.Length;
+ if (fileCount > IRD2.FileKeys.Length)
+ fileCount = IRD2.FileKeys.Length;
+ if (fileCount > IRD1.FileHashes.Length)
+ fileCount = IRD1.FileHashes.Length;
+ if (fileCount > IRD2.FileHashes.Length)
+ fileCount = IRD2.FileHashes.Length;
for (int i = 0; i < fileCount; i++)
{
if (IRD1.FileKeys[i] != IRD2.FileKeys[i])
diff --git a/LibIRD/IRD.cs b/LibIRD/IRD.cs
index 6a7b441..7677689 100644
--- a/LibIRD/IRD.cs
+++ b/LibIRD/IRD.cs
@@ -658,7 +658,7 @@ namespace LibIRD
}
// Read PS3 Metadata from PARAM.SFO
- using (DiscUtils.Streams.SparseStream s = reader.OpenFile(Path.Combine($"{Path.DirectorySeparatorChar}", "PS3_GAME", "PARAM.SFO"), FileMode.Open, FileAccess.Read))
+ using (DiscUtils.Streams.SparseStream s = reader.OpenFile("\\PS3_GAME\\PARAM.SFO", FileMode.Open, FileAccess.Read))
{
// Parse PARAM.SFO file
ParamSFO paramSFO = new(s);
@@ -710,7 +710,7 @@ namespace LibIRD
// TODO: Speed up program by hashing regions and files at the same time (read from filesystem only once)
// Recursively count all files in ISO to allocate file arrays
- DiscDirectoryInfo rootDir = reader.GetDirectoryInfo($"{Path.DirectorySeparatorChar}");
+ DiscDirectoryInfo rootDir = reader.GetDirectoryInfo("\\");
FileCount = 0;
CountFiles(rootDir);
FileKeys = new long[FileCount];
@@ -721,7 +721,12 @@ namespace LibIRD
FileCount = 0;
HashFiles(fs, reader, rootDir);
if (FileCount != fileCount)
- throw new InvalidFileSystemException("Unexpected ISO filesystem error: ");
+ {
+ Console.WriteLine($"Likely contains non-contiguous files: detected {FileCount} out of {fileCount} expected files");
+ long[] tempFileKeys = FileKeys;
+ Array.Resize(ref tempFileKeys, (int)FileCount);
+ FileKeys = tempFileKeys;
+ }
Array.Sort(FileKeys, FileHashes);
}
@@ -739,7 +744,7 @@ namespace LibIRD
private void GetSystemVersion(FileStream fs, CDReader reader)
{
// Determine PUP file offset via cluster
- DiscUtils.Streams.Range[] updateClusters = reader.PathToClusters(Path.Combine($"{Path.DirectorySeparatorChar}", "PS3_UPDATE", "PS3UPDAT.PUP"));
+ DiscUtils.Streams.Range[] updateClusters = reader.PathToClusters("\\PS3_UPDATE\\PS3UPDAT.PUP");
if (updateClusters == null && updateClusters.Length == 0 && updateClusters[0] == null)
throw new InvalidFileSystemException("Invalid file extents for PS3UPDAT.PUP");
@@ -782,7 +787,7 @@ namespace LibIRD
private void GetHeader(FileStream fs, CDReader reader)
{
// Determine the extent of the header via cluster (Sector 0 to first data sector)
- DiscUtils.Streams.Range[] sfbClusters = reader.PathToClusters("PS3_DISC.SFB");
+ DiscUtils.Streams.Range[] sfbClusters = reader.PathToClusters("\\PS3_DISC.SFB");
if (sfbClusters == null && sfbClusters.Length == 0 && sfbClusters[0] == null)
throw new InvalidFileSystemException("Invalid file extents for PS3_DISC.SFB");
// End of header is at beginning of first byte of dedicated cluster
@@ -927,11 +932,26 @@ namespace LibIRD
DiscUtils.Streams.Range[] fileClusters = reader.PathToClusters(filePath);
// If invalid clusters were returned, we can't hash this file
- if (fileClusters == null && fileClusters.Length == 0 && fileClusters[0] == null)
+ if (fileClusters == null && fileClusters.Length == 0)
throw new InvalidFileSystemException($"Unexpected file extents for {filePath}");
- // Determine file offset
- int firstSector = (int)(fileClusters[0].Offset); // TODO: Check smallest of all [i] rather than take [0]
+ // Determine smallest file offset as first sector
+ long smallestOffset = fileClusters[0].Offset;
+ for (int i = 1; i < fileClusters.Length; i++)
+ {
+ if (fileClusters[i] == null)
+ throw new InvalidFileSystemException($"Unexpected file extents for {filePath}");
+
+ if (fileClusters[i].Offset < smallestOffset)
+ smallestOffset = fileClusters[i].Offset;
+ }
+ int firstSector = (int)(smallestOffset);
+
+ // If already encountered file offset, skip this file
+ if (Array.Exists(FileKeys, element => element == firstSector))
+ continue;
+
+ // Add file offset to keys
FileKeys[FileCount] = firstSector;
// Determine whether file is in encrypted or decrypted region
diff --git a/LibIRD/LibIRD.csproj b/LibIRD/LibIRD.csproj
index ea65758..60e5a78 100644
--- a/LibIRD/LibIRD.csproj
+++ b/LibIRD/LibIRD.csproj
@@ -6,7 +6,7 @@
win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64
latest
true
- 0.2.1
+ 0.3.0
Deterous
@@ -20,7 +20,7 @@
-
+
diff --git a/README.md b/README.md
index 2a8ec42..a9bcc0e 100644
--- a/README.md
+++ b/README.md
@@ -8,16 +8,13 @@ IRD files contain a summary of what data is on a PlayStation 3 disc. It can be u
## How to use IRDKit
-IRDKit is a tool that allows direct use of LibIRD functionality from the command line interface. The basic usage is:
-```
-irdkit create game.iso
-```
+IRDKit is a tool that allows direct use of LibIRD functionality from a command line interface. The basic usage is:
+- Printing info about an ISO: `irdkit info game.iso`
+- Printing info about all ISOs and IRDs in a folder: `irdkit info .`
+- Creating an IRD from an ISO: `irdkit create game.iso`
+- Finding differences between two IRDs: `irdkit diff game1.ird game2.ird`
For detailed usage, read more [here](IRDKit).
## Using the LibIRD library
LibIRD was originally made for creating reproducible, redump-style IRDs when dumping PS3 discs with [MPF](https://github.com/SabreTools/MPF). If you wish to integrate LibIRD into your own application, read the examples [here](LibIRD).
-
-## Limitations
-
-Currently, LibIRD does not produce correct IRDs for ISOs with non-contiguous files. Therefore, do not consider this library "stable" until v1.0.0 is released.
\ No newline at end of file