diff --git a/IRDKit/IRDKit.csproj b/IRDKit/IRDKit.csproj
index 910c6ef..c1ede4e 100644
--- a/IRDKit/IRDKit.csproj
+++ b/IRDKit/IRDKit.csproj
@@ -5,9 +5,11 @@
Exe
irdkit
irdkit
- net6.0;net7.0;net8.0
+ net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0
win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64
+ false
latest
+ true
true
0.6.1
@@ -28,7 +30,8 @@
-
+
+
diff --git a/IRDKit/Program.cs b/IRDKit/Program.cs
index c5ddafc..658529d 100644
--- a/IRDKit/Program.cs
+++ b/IRDKit/Program.cs
@@ -2,13 +2,13 @@
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
-using System.IO.Hashing;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Xml.Linq;
using CommandLine;
using LibIRD;
+using SabreTools.Hashing;
using SabreTools.RedumpLib.Web;
namespace IRDKit
@@ -704,7 +704,7 @@ namespace IRDKit
for (int i = 0; i < regionCount; i++)
{
if (!IRD1.RegionHashes[i].SequenceEqual(IRD2.RegionHashes[i]))
- printText.AppendLine($"Region {i} Hash: {Convert.ToHexString(IRD1.RegionHashes[i])} vs {Convert.ToHexString(IRD2.RegionHashes[i])}");
+ printText.AppendLine($"Region {i} Hash: {LibIRD.IRD.ByteArrayToHexString(IRD1.RegionHashes[i])} vs {LibIRD.IRD.ByteArrayToHexString(IRD2.RegionHashes[i])}");
}
// Print the difference in number of files, if not 0
@@ -720,7 +720,7 @@ namespace IRDKit
if (j == -1)
missingOffsets2.Add(IRD1.FileKeys[i]);
if (j != -1 && !IRD1.FileHashes[i].SequenceEqual(IRD2.FileHashes[j]))
- printText.AppendLine($"File Hash at Offset {IRD1.FileKeys[i]}: {Convert.ToHexString(IRD1.FileHashes[i])} vs {Convert.ToHexString(IRD2.FileHashes[j])}");
+ printText.AppendLine($"File Hash at Offset {IRD1.FileKeys[i]}: {LibIRD.IRD.ByteArrayToHexString(IRD1.FileHashes[i])} vs {LibIRD.IRD.ByteArrayToHexString(IRD2.FileHashes[j])}");
}
for (int i = 0; i < IRD2.FileKeys.Length; i++)
{
@@ -748,15 +748,15 @@ namespace IRDKit
// Print any data 1 key difference
if (!IRD1.Data1Key.SequenceEqual(IRD2.Data1Key))
- printText.AppendLine($"Data 1 Key: {Convert.ToHexString(IRD1.Data1Key)} vs {Convert.ToHexString(IRD2.Data1Key)}");
+ printText.AppendLine($"Data 1 Key: {LibIRD.IRD.ByteArrayToHexString(IRD1.Data1Key)} vs {LibIRD.IRD.ByteArrayToHexString(IRD2.Data1Key)}");
// Print any data 2 key difference
if (!IRD1.Data2Key.SequenceEqual(IRD2.Data2Key))
- printText.AppendLine($"Data 2 Key: {Convert.ToHexString(IRD1.Data2Key)} vs {Convert.ToHexString(IRD2.Data2Key)}");
+ printText.AppendLine($"Data 2 Key: {LibIRD.IRD.ByteArrayToHexString(IRD1.Data2Key)} vs {LibIRD.IRD.ByteArrayToHexString(IRD2.Data2Key)}");
// Print any PIC difference
if (!IRD1.PIC.SequenceEqual(IRD2.PIC))
- printText.AppendLine($"PIC: {Convert.ToHexString(IRD1.PIC)} vs {Convert.ToHexString(IRD2.PIC)}");
+ printText.AppendLine($"PIC: {LibIRD.IRD.ByteArrayToHexString(IRD1.PIC)} vs {LibIRD.IRD.ByteArrayToHexString(IRD2.PIC)}");
// Write formatted string to file if output path provided, otherwise to console
if (outPath != null)
@@ -808,7 +808,7 @@ namespace IRDKit
try
{
// Get disc key from hex string
- byte[] discKey = Convert.FromHexString(hexKey);
+ byte[] discKey = LibIRD.IRD.HexStringToByteArray(hexKey);
if (discKey == null || discKey.Length != 16)
Console.Error.WriteLine($"{hexKey} is not a valid key, detecting key automatically...");
else
@@ -844,7 +844,7 @@ namespace IRDKit
Console.Error.WriteLine($"{hexKey} is not a valid key, detecting key automatically...");
else
{
- Console.WriteLine($"Creating {irdPath} with Key: {Convert.ToHexString(discKey)}");
+ Console.WriteLine($"Creating {irdPath} with Key: {LibIRD.IRD.ByteArrayToHexString(discKey)}");
IRD ird1 = new ReIRD(isoPath, discKey, layerbreak);
ird1.Write(irdPath);
if (verbose)
@@ -892,7 +892,7 @@ namespace IRDKit
Console.Error.WriteLine($"{hexKey} is not a valid key, detecting key automatically...");
else
{
- Console.WriteLine($"Creating {irdPath} with Key: {Convert.ToHexString(discKey)}");
+ Console.WriteLine($"Creating {irdPath} with Key: {LibIRD.IRD.ByteArrayToHexString(discKey)}");
IRD ird1 = new ReIRD(isoPath, discKey, layerbreak);
ird1.Write(irdPath);
if (verbose)
@@ -934,22 +934,17 @@ namespace IRDKit
Console.WriteLine("No key provided... Searching for key on redump.org");
// Compute CRC32 hash
- byte[] crc32;
- uint crc32UInt;
- using (FileStream fs = File.OpenRead(isoPath))
- {
- Crc32 hasher = new();
- hasher.Append(fs);
- crc32 = hasher.GetCurrentHash();
- crc32UInt = BitConverter.ToUInt32(crc32);
- // Change endianness
- Array.Reverse(crc32);
- }
- string crc32_hash = Convert.ToHexString(crc32).ToLower();
+ string crc32String = HashTool.GetFileHash(isoPath, HashType.CRC32); // TODO: Output byte[] once ST.Hashing supports it
+ uint crc32UInt = BitConverter.ToUInt32(LibIRD.IRD.HexStringToByteArray(crc32String), 0);
// Search for ISO on redump.org
+#if !NETFRAMEWORK
RedumpHttpClient redump = new();
- List ids = redump.CheckSingleSitePage("http://redump.org/discs/system/ps3/quicksearch/" + crc32_hash).ConfigureAwait(false).GetAwaiter().GetResult();
+ List ids = redump.CheckSingleSitePage("http://redump.org/discs/system/ps3/quicksearch/" + crc32String).ConfigureAwait(false).GetAwaiter().GetResult();
+#else
+ RedumpWebClient redump = new();
+ List ids = redump.CheckSingleSitePage("http://redump.org/discs/system/ps3/quicksearch/" + crc32String);
+#endif
int id;
if (ids.Count == 0)
{
@@ -965,10 +960,14 @@ namespace IRDKit
SHA1 hasher = SHA1.Create();
sha1 = hasher.ComputeHash(fs);
}
- string sha1_hash = Convert.ToHexString(sha1).ToLower();
+ string sha1_hash = LibIRD.IRD.ByteArrayToHexString(sha1).ToLower();
// Search redump.org for SHA1 hash
+#if !NETFRAMEWORK
List ids2 = redump.CheckSingleSitePage("http://redump.org/discs/system/ps3/quicksearch/" + sha1_hash).ConfigureAwait(false).GetAwaiter().GetResult();
+#else
+ List ids2 = redump.CheckSingleSitePage("http://redump.org/discs/system/ps3/quicksearch/" + sha1_hash);
+#endif
if (ids2.Count == 0)
{
Console.Error.WriteLine("ISO not found in redump and no valid key provided, cannot create IRD");
@@ -988,7 +987,11 @@ namespace IRDKit
}
// Download key file from redump.org
+#if !NETFRAMEWORK
byte[] key = redump.GetByteArrayAsync($"http://redump.org/disc/{id}/key").ConfigureAwait(false).GetAwaiter().GetResult();
+#else
+ byte[] key = redump.DownloadData($"http://redump.org/disc/{id}/key");
+#endif
if (key.Length != 16)
{
Console.Error.WriteLine("Invalid key obtained from redump and no valid key provided, cannot create IRD");
@@ -996,7 +999,7 @@ namespace IRDKit
}
// Create IRD with key from redump
- Console.WriteLine($"Creating {irdPath} with Key from redump.org: {Convert.ToHexString(key)}");
+ Console.WriteLine($"Creating {irdPath} with Key from redump.org: {LibIRD.IRD.ByteArrayToHexString(key)}");
try
{
IRD ird = new ReIRD(isoPath, key, layerbreak, crc32UInt);
@@ -1045,7 +1048,7 @@ namespace IRDKit
if (filename == null)
throw new ArgumentException($"Cannot determine DAT filename for {irdPath}");
if (serial)
- filename += $" [{ird.TitleID[..4]}-{ird.TitleID[4..9]}]";
+ filename += $" [{ird.TitleID.Substring(0, 4)}-{ird.TitleID.Substring(5, 5)}]";
if (crc)
filename += $" [{ird.UID:X8}]";
@@ -1071,7 +1074,7 @@ namespace IRDKit
}
}
- #endregion
+#endregion
#region Helper Functions
diff --git a/LibIRD/IRD.cs b/LibIRD/IRD.cs
index d01c6b1..abd0afe 100644
--- a/LibIRD/IRD.cs
+++ b/LibIRD/IRD.cs
@@ -2,12 +2,12 @@
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
-using System.IO.Hashing;
using System.Security.Cryptography;
using System.Text;
using LibIRD.DiscUtils;
using LibIRD.DiscUtils.Iso9660;
using LibIRD.DiscUtils.Streams;
+using SabreTools.Hashing;
namespace LibIRD
{
@@ -803,9 +803,11 @@ namespace LibIRD
// Begin a GZip stream to write header to
using MemoryStream headerStream = new();
#if NET6_0_OR_GREATER
- using (GZipStream gzs = new(headerStream, CompressionLevel.SmallestSize))
+ using GZipStream gzStream = new(headerStream, CompressionLevel.SmallestSize);
+#elif NETCOREAPP || NET45_OR_GREATER
+ using GZipStream gzStream = new(headerStream, CompressionLevel.Optimal);
#else
- using (GZipStream gzs = new(headerStream, CompressionLevel.Optimal))
+ using GZipStream gzStream = new(headerStream, CompressionMode.Compress);
#endif
{
// Start reading data from the beginning of the ISO file
@@ -817,7 +819,7 @@ namespace LibIRD
for (int i = 0; i < FirstDataSector; i++)
{
numBytes = fs.Read(buf, 0, buf.Length);
- gzs.Write(buf, 0, numBytes);
+ gzStream.Write(buf, 0, numBytes);
}
}
@@ -835,9 +837,11 @@ namespace LibIRD
// Begin a GZip stream to write footer to
using MemoryStream footerStream = new();
#if NET6_0_OR_GREATER
- using (GZipStream gzs = new(footerStream, CompressionLevel.SmallestSize))
+ using GZipStream gzStream = new(footerStream, CompressionLevel.SmallestSize);
+#elif NETCOREAPP || NET45_OR_GREATER
+ using GZipStream gzStream = new(footerStream, CompressionLevel.Optimal);
#else
- using (GZipStream gzs = new(footerStream, CompressionLevel.Optimal))
+ using GZipStream gzStream = new(footerStream, CompressionMode.Compress);
#endif
{
// Start reading data from after last file (PS3UPDAT.PUP)
@@ -849,7 +853,7 @@ namespace LibIRD
while (numBytes != 0)
{
numBytes = fs.Read(buf, 0, buf.Length);
- gzs.Write(buf, 0, numBytes);
+ gzStream.Write(buf, 0, numBytes);
}
}
@@ -1038,7 +1042,7 @@ namespace LibIRD
{
// Initialise CRC32 ISO hasher, only used if making redump-style IRD
byte[] crc32;
- Crc32 isoHasher = new();
+ HashWrapper isoHasher = new(HashType.CRC32);
// Initialise MD5 region hashes
List regions = [];
@@ -1077,7 +1081,7 @@ namespace LibIRD
// If making redump-style IRD, save CRC32 hash to UID field
if (redump)
{
- crc32 = isoHasher.GetCurrentHash();
+ crc32 = isoHasher.CurrentHashBytes;
UID = BitConverter.ToUInt32(crc32, 0);
}
return;
@@ -1109,7 +1113,7 @@ namespace LibIRD
// Hash ISO
if (redump)
- isoHasher.Append(new ReadOnlySpan(buf, 0, numBytes));
+ isoHasher.Process(buf, 0, numBytes);
// Hash regions
List regionsEnded = [];
@@ -1241,112 +1245,112 @@ namespace LibIRD
// Create new stream to uncompressed IRD contents
using MemoryStream stream = new();
- // Write IRD data to stream in order
- using (BinaryWriter bw = new(stream, Encoding.UTF8, true))
+ // Write IRD data to stream as UTF8
+ using BinaryWriter bw = new(stream, Encoding.UTF8);
+
+ // IRD File Signature
+ bw.Write(Magic);
+
+ // IRD File Version
+ bw.Write(Version);
+
+ // PARAM.SFO / TITLE_ID
+ byte[] titleIDBuf = Encoding.ASCII.GetBytes(TitleID);
+ bw.Write(titleIDBuf, 0, 9);
+
+ // PARAM.SFO / TITLE
+ bw.Write(Title);
+
+ // PARAM.SFO / PS3_SYSTEM_VER
+ byte[] systemVersionBuf = Encoding.ASCII.GetBytes(SystemVersion);
+ bw.Write(systemVersionBuf, 0, 4);
+
+ // PARAM.SFO / VERSION
+ byte[] buf = Encoding.ASCII.GetBytes(DiscVersion);
+ byte[] discVersionBuf = new byte[5];
+ Array.Copy(buf, 0, discVersionBuf, 0, buf.Length);
+ bw.Write(discVersionBuf, 0, 5);
+
+ // PARAM.SFO / APP_VER
+ buf = Encoding.ASCII.GetBytes(AppVersion);
+ byte[] appVersionBuf = new byte[5];
+ Array.Copy(buf, 0, appVersionBuf, 0, buf.Length);
+ bw.Write(appVersionBuf, 0, 5);
+
+ // IRD Unique Identifier, for version 7
+ if (_version == 7)
+ bw.Write(UID);
+
+ // Compress Header
+ bw.Write(HeaderLength);
+ bw.Write(Header, 0, (int)HeaderLength);
+
+ // Compress Footer
+ bw.Write(FooterLength);
+ bw.Write(Footer, 0, (int)FooterLength);
+
+ // Number of regions hashed
+ bw.Write(RegionCount);
+
+ // Hashes for each region
+ for (int i = 0; i < RegionCount; i++)
{
- // IRD File Signature
- bw.Write(Magic);
-
- // IRD File Version
- bw.Write(Version);
-
- // PARAM.SFO / TITLE_ID
- byte[] titleIDBuf = Encoding.ASCII.GetBytes(TitleID);
- bw.Write(titleIDBuf, 0, 9);
-
- // PARAM.SFO / TITLE
- bw.Write(Title);
-
- // PARAM.SFO / PS3_SYSTEM_VER
- byte[] systemVersionBuf = Encoding.ASCII.GetBytes(SystemVersion);
- bw.Write(systemVersionBuf, 0, 4);
-
- // PARAM.SFO / VERSION
- byte[] buf = Encoding.ASCII.GetBytes(DiscVersion);
- byte[] discVersionBuf = new byte[5];
- Array.Copy(buf, 0, discVersionBuf, 0, buf.Length);
- bw.Write(discVersionBuf, 0, 5);
-
- // PARAM.SFO / APP_VER
- buf = Encoding.ASCII.GetBytes(AppVersion);
- byte[] appVersionBuf = new byte[5];
- Array.Copy(buf, 0, appVersionBuf, 0, buf.Length);
- bw.Write(appVersionBuf, 0, 5);
-
- // IRD Unique Identifier, for version 7
- if (_version == 7)
- bw.Write(UID);
-
- // Compress Header
- bw.Write(HeaderLength);
- bw.Write(Header, 0, (int)HeaderLength);
-
- // Compress Footer
- bw.Write(FooterLength);
- bw.Write(Footer, 0, (int)FooterLength);
-
- // Number of regions hashed
- bw.Write(RegionCount);
-
- // Hashes for each region
- for (int i = 0; i < RegionCount; i++)
- {
- if (RegionHashes[i] == null)
- bw.Write(NullMD5);
- else
- bw.Write(RegionHashes[i], 0, 16);
- }
-
- // Number of files hashed
- bw.Write(FileCount);
-
- // Hashes for each file
- for (int i = 0; i < FileCount; i++)
- {
- bw.Write(FileKeys[i]);
- if (FileHashes[i] == null)
- bw.Write(NullMD5);
- else
- bw.Write(FileHashes[i], 0, 16);
- }
-
- // Reserved fields
- bw.Write(ExtraConfig);
- bw.Write(Attachments);
-
- // PIC data is placed here for Version 9
- if (_version >= 9)
- bw.Write(PIC, 0, 115);
-
- // Disc Authentication keys
- bw.Write(Data1Key, 0, 16);
- bw.Write(Data2Key, 0, 16);
-
- // PIC data is placed here prior to Version 9
- if (_version < 9)
- bw.Write(PIC, 0, 115);
-
- // IRD Unique Identifier, for versions after 7
- if (_version > 7)
- bw.Write(UID);
+ if (RegionHashes[i] == null)
+ bw.Write(NullMD5);
+ else
+ bw.Write(RegionHashes[i], 0, 16);
}
+ // Number of files hashed
+ bw.Write(FileCount);
+
+ // Hashes for each file
+ for (int i = 0; i < FileCount; i++)
+ {
+ bw.Write(FileKeys[i]);
+ if (FileHashes[i] == null)
+ bw.Write(NullMD5);
+ else
+ bw.Write(FileHashes[i], 0, 16);
+ }
+
+ // Reserved fields
+ bw.Write(ExtraConfig);
+ bw.Write(Attachments);
+
+ // PIC data is placed here for Version 9
+ if (_version >= 9)
+ bw.Write(PIC, 0, 115);
+
+ // Disc Authentication keys
+ bw.Write(Data1Key, 0, 16);
+ bw.Write(Data2Key, 0, 16);
+
+ // PIC data is placed here prior to Version 9
+ if (_version < 9)
+ bw.Write(PIC, 0, 115);
+
+ // IRD Unique Identifier, for versions after 7
+ if (_version > 7)
+ bw.Write(UID);
+
// Calculate the little-endian 32-bit "IEEE 802.3" CRC value of the IRD contents so far
stream.Position = 0;
- Crc32 crc32 = new();
- crc32.Append(stream);
- byte[] crc = crc32.GetCurrentHash();
+ string crc32String = HashTool.GetStreamHash(stream, HashType.CRC32);
+ byte[] crc32 = HexStringToByteArray(crc32String);
// Write final CRC value to the stream
- stream.Write(crc, 0, 4);
+ stream.Write(crc32, 0, 4);
// Create the IRD file stream
using FileStream fs = new(irdPath, FileMode.Create, FileAccess.Write);
// Create a GZipped IRD file stream
#if NET6_0_OR_GREATER
using GZipStream gzStream = new(fs, CompressionLevel.SmallestSize);
-#else
+#elif NETCOREAPP || NET45_OR_GREATER
using GZipStream gzStream = new(fs, CompressionLevel.Optimal);
+#else
+ using GZipStream gzStream = new(fs, CompressionMode.Compress);
#endif
// Write entire gzipped IRD stream to file
stream.Position = 0;
@@ -1374,7 +1378,7 @@ namespace LibIRD
// Check for IRD file signature
byte[] magic = br.ReadBytes(4);
- if (!((ReadOnlySpan)Magic).SequenceEqual(magic))
+ if (magic == null || magic.Length != 4 || magic[0] != Magic[0] || magic[1] != Magic[1] || magic[2] != Magic[2] || magic[3] != Magic[3])
throw new InvalidDataException("IRD file not recognised");
// Read file version
diff --git a/LibIRD/LibIRD.csproj b/LibIRD/LibIRD.csproj
index 1175f2d..e48d273 100644
--- a/LibIRD/LibIRD.csproj
+++ b/LibIRD/LibIRD.csproj
@@ -2,8 +2,9 @@
- net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0
+ net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0
win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64
+ false
latest
true
true
@@ -28,7 +29,7 @@
-
+
diff --git a/LibIRD/ReIRD.cs b/LibIRD/ReIRD.cs
index 27d5829..fcbc884 100644
--- a/LibIRD/ReIRD.cs
+++ b/LibIRD/ReIRD.cs
@@ -1,6 +1,6 @@
using System;
using System.IO;
-using System.IO.Hashing;
+using SabreTools.Hashing;
namespace LibIRD
{
@@ -252,13 +252,8 @@ namespace LibIRD
throw new FileNotFoundException(nameof(isoPath));
// Compute CRC32 hash
- byte[] crc32;
- using (FileStream fs = File.OpenRead(isoPath))
- {
- Crc32 hasher = new();
- hasher.Append(fs);
- crc32 = hasher.GetCurrentHash();
- }
+ string crc32String = HashTool.GetFileHash(isoPath, HashType.CRC32); // TODO: Output byte[] once ST.Hashing supports it
+ byte[] crc32 = HexStringToByteArray(crc32String);
// Redump ISO CRC32 hash is used as the Unique ID in the reproducible IRD
return BitConverter.ToUInt32(crc32, 0);