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;