diff --git a/LibIRD/IRD.cs b/LibIRD/IRD.cs
index a160393..1999342 100644
--- a/LibIRD/IRD.cs
+++ b/LibIRD/IRD.cs
@@ -406,8 +406,7 @@ namespace LibIRD
private protected static byte[] GenerateD1(byte[] key)
{
// Validate key
- if (key == null)
- throw new ArgumentNullException(nameof(key));
+ ArgumentNullException.ThrowIfNull(key, nameof(key));
if (key.Length != 16)
throw new ArgumentException("Disc Key must be a byte array of length 16", nameof(key));
@@ -441,8 +440,7 @@ namespace LibIRD
private protected static byte[] GenerateDiscKey(byte[] d1)
{
// Validate key
- if (d1 == null)
- throw new ArgumentNullException(nameof(d1));
+ ArgumentNullException.ThrowIfNull(d1, nameof(d1));
if (d1.Length != 16)
throw new ArgumentException("Disc Key must be a byte array of length 16", nameof(d1));
@@ -476,7 +474,7 @@ namespace LibIRD
private protected static byte[] GenerateD2(byte[] d2)
{
// Validate id
- if (d2 == null) throw new ArgumentNullException(nameof(d2));
+ ArgumentNullException.ThrowIfNull(d2, nameof(d2));
if (d2.Length != 16) throw new ArgumentException("Disc ID must be a byte array of length 16", nameof(d2));
// Setup AES encryption
@@ -509,8 +507,7 @@ namespace LibIRD
private protected static byte[] GenerateDiscID(byte[] d2)
{
// Validate id
- if (d2 == null)
- throw new ArgumentNullException(nameof(d2));
+ ArgumentNullException.ThrowIfNull(d2 , nameof(d2));
if (d2.Length != 16)
throw new ArgumentException("Disc ID must be a byte array of length 16", nameof(d2));
@@ -545,8 +542,7 @@ namespace LibIRD
{
// Validate .getkey.log file path
- if (getKeyLog == null)
- throw new ArgumentNullException(nameof(getKeyLog));
+ ArgumentNullException.ThrowIfNull(getKeyLog, nameof(getKeyLog));
if (!File.Exists(getKeyLog))
throw new FileNotFoundException(nameof(getKeyLog));
@@ -643,20 +639,22 @@ namespace LibIRD
// Redump-style IRDs set the lowest bit of ExtraConfig to 1
ExtraConfig |= 0x01;
- // Redump-style IRDs use fields in PS3_DISC.SFB
+ // Redump-style IRDs use fields from PS3_DISC.SFB
using DiscUtils.Streams.SparseStream s = reader.OpenFile("PS3_DISC.SFB", FileMode.Open, FileAccess.Read);
// Parse PS3_DISC.SFB file
PS3_DiscSFB ps3_DiscSFB = new(s);
-
+
+ bool title_id_found = ps3_DiscSFB.Field.TryGetValue("TITLE_ID", out string title_id);
// If a valid TITLE_ID field is present, remove the hyphen to fit into standard IRD file
- if (ps3_DiscSFB.Field.ContainsKey("TITLE_ID") && ps3_DiscSFB.Field["TITLE_ID"].Length == 10 && ps3_DiscSFB.Field["TITLE_ID"][4] == '-')
- TitleID = string.Concat(ps3_DiscSFB.Field["TITLE_ID"].AsSpan(0, 4), ps3_DiscSFB.Field["TITLE_ID"].AsSpan(5, 5));
+ if (title_id_found && title_id.Length == 10 && title_id[4] == '-')
+ TitleID = string.Concat(title_id.AsSpan(0, 4), title_id.AsSpan(5, 5));
// If the version field is present, this is a multi-game disc
// Redump-style IRDs use the VERSION field from PS3_DISC.SFB instead of VERSION from PARAM.SFO
- if (ps3_DiscSFB.Field.ContainsKey("VERSION"))
- DiscVersion = ps3_DiscSFB.Field["VERSION"];
+ bool version_found = ps3_DiscSFB.Field.TryGetValue("VERSION", out string disc_version);
+ if (version_found)
+ DiscVersion = disc_version;
}
// Read PS3 Metadata from PARAM.SFO
diff --git a/LibIRD/ReIRD.cs b/LibIRD/ReIRD.cs
index c869ecc..56821c2 100644
--- a/LibIRD/ReIRD.cs
+++ b/LibIRD/ReIRD.cs
@@ -144,58 +144,86 @@ namespace LibIRD
/// Generates the PIC data for a given ISO size in bytes
///
/// Total ISO size in number of bytes
- /// Layer break value, byte at which disc layers are split across
+ /// Layer break value, byte at which disc layers are split across
/// True to generate a PIC in 3k3y style (0x03 at 115th byte for BD-50 discs)
///
- private static byte[] GeneratePIC(long size, long layerbreak = BDLayerSize, bool exactIRD = false)
+ private static byte[] GeneratePIC(long size, long? layerbreak = null, bool exactIRD = false)
{
// Validate size
- if (size == 0 || (size % SectorSize) != 0)
+ if (size <= 0 || (size % SectorSize) != 0)
throw new ArgumentException("ISO Size in bytes must be a positive integer multiple of 2048", nameof(size));
// Validate layerbreak
- if (layerbreak == 0 || (layerbreak != BDLayerSize && layerbreak >= size))
- throw new ArgumentException("Layerbreak in bytes must be a positive integer less than the ISO Size", nameof(size));
+ if (layerbreak != null)
+ {
+ if (layerbreak <= 0 || (layerbreak >= size))
+ throw new ArgumentException("Layerbreak in bytes must be a positive integer less than the ISO Size", nameof(size));
+ if (layerbreak >= 2 * BDLayerSize || layerbreak % SectorSize != 0)
+ throw new ArgumentException("Unexpected layerbreak value", nameof(size));
+ }
+ // If layerbreak value was not set, assume it is a non-hybrid disc with default layerbreak
+ long layer_break = layerbreak ?? BDLayerSize;
- // TODO: Generate correct PICs for Hybrid PS3 discs (BD-50 with layerbreak value other than 12219392)
+ // Generate the PIC based on the size and layerbreak of the ISO
byte[] pic;
if (size > BDLayerSize) // if BD-50
{
- // num_sectors + layer_sector_end (0x00100000) + sectors_between_layers (0x01358C00 - 0x00CA73FE) - 3
- byte[] total_sectors = BitConverter.GetBytes((uint)(size / SectorSize + 8067071));
+ // Layer 0 start sector = 0x01000000
+ long l0_start_sector = 1048576;
+
+ // Layer 0 end sector = start sector + layerbreak - 2
+ long l0_end_sector = layer_break + l0_start_sector - 2;
+ // Convert end sector location to hex values for PIC
+ byte[] l0es = [(byte)((l0_end_sector >> 24) & 0xFF),
+ (byte)((l0_end_sector >> 16) & 0xFF),
+ (byte)((l0_end_sector >> 8) & 0xFF),
+ (byte)((l0_end_sector >> 0) & 0xFF)];
- // Initial portion of PIC (24 bytes)
- pic = [
- // [4098 bytes] [2x 0x00] ["DI"] [v1] [10units] [DI num]
- 0x10, 0x02, 0x00, 0x00, 0x44, 0x49, 0x01, 0x10, 0x00, 0x00, 0x20, 0x00,
- // ["BDR"] [2 layers]
- 0x42, 0x44, 0x4F, 0x01, 0x21, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
- // Total sectors used on disc (4 bytes)
- total_sectors[3], total_sectors[2], total_sectors[1], total_sectors[0],
- // 1st Layer sector start location (4 bytes)
- 0x00, 0x10, 0x00, 0x00,
- // 1st Layer sector end location (4 bytes)
- 0x00, 0xCA, 0x73, 0xFE,
- // 32 bytes of zeros
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // Initial portion of PIC again, for 2nd layer
- // ["DI"] [v1] [11unit][DI num]
- 0x44, 0x49, 0x01, 0x11, 0x00, 0x01, 0x20, 0x00,
- // ["BDR"] [2 layers]
- 0x42, 0x44, 0x4F, 0x01, 0x21, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
- // Total sectors used on disc
- total_sectors[3], total_sectors[2], total_sectors[1], total_sectors[0],
- // 2nd Layer sector start location
- 0x01, 0x35, 0x8C, 0x00,
- // 2nd Layer sector end location
- 0x01, 0xEF, 0xFF, 0xFE,
- // Remaining 32 bytes are zeroes
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ];
- // 3k3y style: 0x03 at last byte
- if (exactIRD)
- pic[114] = 0x03;
+ // Layer 1 start sector = end of disc (0x01EFFFFE) - layerbreak + 2
+ long l1_start_sector = 32505854 - layer_break + 2;
+ // Convert start of start sector location to hex values for PIC
+ byte[] l1ss = [(byte)((l1_start_sector >> 24) & 0xFF),
+ (byte)((l1_start_sector >> 16) & 0xFF),
+ (byte)((l1_start_sector >> 8) & 0xFF),
+ (byte)((l1_start_sector >> 0) & 0xFF)];
+
+ // Total sectors used = num_sectors + Layer 0 start + sectors_between_layers (usually 0x01358C00 - 0x00CA73FE - 3)
+ long total_sectors = (size / SectorSize) + l0_start_sector + (l1_start_sector - l0_end_sector - 3);
+ byte[] ts = BitConverter.GetBytes((uint) total_sectors);
- }
+ // Define the PIC
+ pic = [
+ // Initial portion of PIC (24 bytes)
+ // [4098 bytes] [2x 0x00] ["DI"] [v1] [10units] [DI num]
+ 0x10, 0x02, 0x00, 0x00, 0x44, 0x49, 0x01, 0x10, 0x00, 0x00, 0x20, 0x00,
+ // ["BDR"] [2 layers]
+ 0x42, 0x44, 0x4F, 0x01, 0x21, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // Total sectors used on disc (4 bytes)
+ ts[3], ts[2], ts[1], ts[0],
+ // 1st Layer sector start location (4 bytes)
+ 0x00, 0x10, 0x00, 0x00,
+ // 1st Layer sector end location (4 bytes), 0x00CA73FE for default BD layerbreak of 12219392
+ l0es[0], l0es[1], l0es[2], l0es[3],
+ // 32 bytes of zeros
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // Initial portion of PIC again, for 2nd layer
+ // ["DI"] [v1] [11unit][DI num]
+ 0x44, 0x49, 0x01, 0x11, 0x00, 0x01, 0x20, 0x00,
+ // ["BDR"] [2 layers]
+ 0x42, 0x44, 0x4F, 0x01, 0x21, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // Total sectors used on disc
+ ts[3], ts[2], ts[1], ts[0],
+ // 2nd Layer sector start location, 0x01358C00 for default BD layerbreak of 12219392
+ l1ss[0], l1ss[1], l1ss[2], l1ss[3],
+ // 2nd Layer sector end location
+ 0x01, 0xEF, 0xFF, 0xFE,
+ // Remaining 32 bytes are zeroes
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ];
+ // 3k3y style: 0x03 at last byte
+ if (exactIRD)
+ pic[114] = 0x03;
+
+ }
else // if BD-25
{
// Total sectors used on disc: num_sectors + layer_sector_end (0x00100000) - 1
@@ -203,21 +231,23 @@ namespace LibIRD
// Layer sector end location: num_sectors + layer_sector_end (0x00100000) - 2
byte[] end_sector = BitConverter.GetBytes((uint)(size / SectorSize + 1048574));
- // Initial portion of PIC (24 bytes)
- pic = [ 0x10, 0x02, 0x00, 0x00, 0x44, 0x49, 0x01, 0x08, 0x00, 0x00, 0x20, 0x00,
- 0x42, 0x44, 0x4F, 0x01, 0x11, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- // Total sectors used on disc (4 bytes)
- total_sectors[3], total_sectors[2], total_sectors[1], total_sectors[0],
- // Layer sector start location (4 bytes)
- 0x00, 0x10, 0x00, 0x00,
- // Layer sector end location (4 bytes)
- end_sector[3], end_sector[2], end_sector[1], end_sector[0],
- // Remaining 79 bytes are zeroes
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ];
+ // Define the PIC
+ pic = [
+ // Initial portion of PIC (24 bytes)
+ 0x10, 0x02, 0x00, 0x00, 0x44, 0x49, 0x01, 0x08, 0x00, 0x00, 0x20, 0x00,
+ 0x42, 0x44, 0x4F, 0x01, 0x11, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // Total sectors used on disc (4 bytes)
+ total_sectors[3], total_sectors[2], total_sectors[1], total_sectors[0],
+ // Layer sector start location (4 bytes)
+ 0x00, 0x10, 0x00, 0x00,
+ // Layer sector end location (4 bytes)
+ end_sector[3], end_sector[2], end_sector[1], end_sector[0],
+ // Remaining 79 bytes are zeroes
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ];
}
return pic;