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