From ca7b489c17af889a54f99b01c3717c90f7aab9fc Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Sun, 8 Oct 2017 18:55:06 +0100 Subject: [PATCH] Refactor IP.BIN decoders. --- DiscImageChef.Decoders/Sega/CD.cs | 232 ++++++++++------------- DiscImageChef.Decoders/Sega/Dreamcast.cs | 142 +++++++------- DiscImageChef.Decoders/Sega/Saturn.cs | 97 +++++----- 3 files changed, 223 insertions(+), 248 deletions(-) diff --git a/DiscImageChef.Decoders/Sega/CD.cs b/DiscImageChef.Decoders/Sega/CD.cs index 65a503410..190fff5dc 100644 --- a/DiscImageChef.Decoders/Sega/CD.cs +++ b/DiscImageChef.Decoders/Sega/CD.cs @@ -31,6 +31,7 @@ // ****************************************************************************/ using System; using System.Globalization; +using System.Runtime.InteropServices; using System.Text; using DiscImageChef.Console; @@ -38,40 +39,88 @@ namespace DiscImageChef.Decoders.Sega { public static class CD { + // TODO: Check if it is big or little endian + [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct IPBin { - public byte[] SegaHardwareID; //16 - public byte[] volume_name; //11 // 0x010, Varies - public byte[] spare_space1; //1 // 0x01B, 0x00 - public byte[] volume_version; //2 // 0x01C, Volume version in BCD. <100 = Prerelease. - public byte[] volume_type; //2 // 0x01E, Bit 0 = 1 => CD-ROM. Rest should be 0. - public byte[] system_name; //11 // 0x020, Unknown, varies! - public byte[] spare_space2; //1 // 0x02B, 0x00 - public byte[] system_version; //2 // 0x02C, Should be 1 - public byte[] spare_space3; //2 // 0x02E, 0x0000 - public byte[] ip_address; //4 // 0x030, Initial program address - public byte[] ip_loadsize; //4 // 0x034, Load size of initial program - public byte[] ip_entry_address; //4 // 0x038, Initial program entry address - public byte[] ip_work_ram_size; //4 // 0x03C, Initial program work RAM size in bytes - public byte[] sp_address; //4 // 0x040, System program address - public byte[] sp_loadsize; //4 // 0x044, Load size of system program - public byte[] sp_entry_address; //4 // 0x048, System program entry address - public byte[] sp_work_ram_size; //4 // 0x04C, System program work RAM size in bytes - public byte[] release_date; //8 // 0x050, MMDDYYYY - public byte[] unknown1; //7 // 0x058, Seems to be all 0x20s - public byte[] spare_space4; //1 // 0x05F, 0x00 ? - public byte[] system_reserved; //160 // 0x060, System Reserved Area - public byte[] hardware_id; //16 // 0x100, Hardware ID - public byte[] copyright; //3 // 0x110, "(C)" -- Can be the developer code directly!, if that is the code release date will be displaced - public byte[] developer_code; //5 // 0x113 or 0x110, "SEGA" or "T-xx" - public byte[] release_date2; //8 // 0x118, Another release date, this with month in letters? - public byte[] domestic_title; //48 // 0x120, Domestic version of the game title - public byte[] overseas_title; //48 // 0x150, Overseas version of the game title - public byte[] product_code; //13 // 0x180, Official product code - public byte[] peripherals; //16 // 0x190, Supported peripherals, see above - public byte[] spare_space6; //16 // 0x1A0, 0x20 - public byte[] spare_space7; //64 // 0x1B0, Inside here should be modem information, but I need to get a modem-enabled game - public byte[] region_codes; //16 // 0x1F0, Region codes, space-filled + /// Must be "SEGADISCSYSTEM " or "SEGADATADISC " or "SEGAOS " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] SegaHardwareID; + /// 0x010, Varies + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] + public byte[] volume_name; + /// 0x01B, 0x00 + public byte spare_space1; + /// 0x01C, Volume version in BCD. <100 = Prerelease. + public ushort volume_version; + /// 0x01E, Bit 0 = 1 => CD-ROM. Rest should be 0. + public ushort volume_type; + /// 0x020, Unknown, varies! + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] + public byte[] system_name; + /// 0x02B, 0x00 + public byte spare_space2; + /// 0x02C, Should be 1 + public ushort system_version; + /// 0x02E, 0x0000 + public ushort spare_space3; + /// 0x030, Initial program address + public uint ip_address; + /// 0x034, Load size of initial program + public uint ip_loadsize; + /// 0x038, Initial program entry address + public uint ip_entry_address; + /// 0x03C, Initial program work RAM size in bytes + public uint ip_work_ram_size; + /// 0x040, System program address + public uint sp_address; + /// 0x044, Load size of system program + public uint sp_loadsize; + /// 0x048, System program entry address + public uint sp_entry_address; + /// 0x04C, System program work RAM size in bytes + public uint sp_work_ram_size; + /// 0x050, MMDDYYYY + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] release_date; + /// 0x058, Seems to be all 0x20s + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] + public byte[] unknown1; + /// 0x05F, 0x00 ? + public byte spare_space4; + /// 0x060, System Reserved Area + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 160)] + public byte[] system_reserved; + /// 0x100, Hardware ID + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] hardware_id; + /// 0x113 or 0x110, "SEGA" or "T-xx" + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] + public byte[] developer_code; + /// 0x118, Another release date, this with month in letters? + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] release_date2; + /// 0x120, Domestic version of the game title + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)] + public byte[] domestic_title; + /// 0x150, Overseas version of the game title + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)] + public byte[] overseas_title; + /// 0x180, Official product code + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 13)] + public byte[] product_code; + /// 0x190, Supported peripherals, see above + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] peripherals; + /// 0x1A0, 0x20 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] spare_space6; + /// 0x1B0, Inside here should be modem information, but I need to get a modem-enabled game + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] + public byte[] spare_space7; + /// 0x1F0, Region codes, space-filled + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] region_codes; } public static IPBin? DecodeIPBin(byte[] ipbin_sector) @@ -83,92 +132,24 @@ namespace DiscImageChef.Decoders.Sega return null; IPBin ipbin = new IPBin(); - ipbin.SegaHardwareID = new byte[16]; - // Definitions following - ipbin.volume_name = new byte[11]; // 0x010, Varies - ipbin.spare_space1 = new byte[1]; // 0x01B, 0x00 - ipbin.volume_version = new byte[2]; // 0x01C, Volume version in BCD. <100 = Prerelease. - ipbin.volume_type = new byte[2]; // 0x01E, Bit 0 = 1 => CD-ROM. Rest should be 0. - ipbin.system_name = new byte[11]; // 0x020, Unknown, varies! - ipbin.spare_space2 = new byte[1]; // 0x02B, 0x00 - ipbin.system_version = new byte[2]; // 0x02C, Should be 1 - ipbin.spare_space3 = new byte[2]; // 0x02E, 0x0000 - ipbin.ip_address = new byte[4]; // 0x030, Initial program address - ipbin.ip_loadsize = new byte[4]; // 0x034, Load size of initial program - ipbin.ip_entry_address = new byte[4]; // 0x038, Initial program entry address - ipbin.ip_work_ram_size = new byte[4]; // 0x03C, Initial program work RAM size in bytes - ipbin.sp_address = new byte[4]; // 0x040, System program address - ipbin.sp_loadsize = new byte[4]; // 0x044, Load size of system program - ipbin.sp_entry_address = new byte[4]; // 0x048, System program entry address - ipbin.sp_work_ram_size = new byte[4]; // 0x04C, System program work RAM size in bytes - ipbin.release_date = new byte[8]; // 0x050, MMDDYYYY - ipbin.unknown1 = new byte[7]; // 0x058, Seems to be all 0x20s - ipbin.spare_space4 = new byte[1]; // 0x05F, 0x00 ? - ipbin.system_reserved = new byte[160]; // 0x060, System Reserved Area - ipbin.hardware_id = new byte[16]; // 0x100, Hardware ID - ipbin.copyright = new byte[3]; // 0x110, "(C)" -- Can be the developer code directly!, if that is the code release date will be displaced - ipbin.developer_code = new byte[5]; // 0x113 or 0x110, "SEGA" or "T-xx" - ipbin.release_date2 = new byte[8]; // 0x118, Another release date, this with month in letters? - ipbin.domestic_title = new byte[48]; // 0x120, Domestic version of the game title - ipbin.overseas_title = new byte[48]; // 0x150, Overseas version of the game title - ipbin.product_code = new byte[13]; // 0x180, Official product code - ipbin.peripherals = new byte[16]; // 0x190, Supported peripherals, see above - ipbin.spare_space6 = new byte[16]; // 0x1A0, 0x20 - ipbin.spare_space7 = new byte[64]; // 0x1B0, Inside here should be modem information, but I need to get a modem-enabled game - ipbin.region_codes = new byte[16]; // 0x1F0, Region codes, space-filled - - //Reading all data - Array.Copy(ipbin_sector, 0x000, ipbin.SegaHardwareID, 0, 16); - Array.Copy(ipbin_sector, 0x010, ipbin.volume_name, 0, 11); // Varies - Array.Copy(ipbin_sector, 0x01B, ipbin.spare_space1, 0, 1); // 0x00 - Array.Copy(ipbin_sector, 0x01C, ipbin.volume_version, 0, 2); // Volume version in BCD. <100 = Prerelease. - Array.Copy(ipbin_sector, 0x01E, ipbin.volume_type, 0, 2); // Bit 0 = 1 => CD-ROM. Rest should be 0. - Array.Copy(ipbin_sector, 0x020, ipbin.system_name, 0, 11); // Unknown, varies! - Array.Copy(ipbin_sector, 0x02B, ipbin.spare_space2, 0, 1); // 0x00 - Array.Copy(ipbin_sector, 0x02C, ipbin.system_version, 0, 2); // Should be 1 - Array.Copy(ipbin_sector, 0x02E, ipbin.spare_space3, 0, 2); // 0x0000 - Array.Copy(ipbin_sector, 0x030, ipbin.ip_address, 0, 4); // Initial program address - Array.Copy(ipbin_sector, 0x034, ipbin.ip_loadsize, 0, 4); // Load size of initial program - Array.Copy(ipbin_sector, 0x038, ipbin.ip_entry_address, 0, 4); // Initial program entry address - Array.Copy(ipbin_sector, 0x03C, ipbin.ip_work_ram_size, 0, 4); // Initial program work RAM size in bytes - Array.Copy(ipbin_sector, 0x040, ipbin.sp_address, 0, 4); // System program address - Array.Copy(ipbin_sector, 0x044, ipbin.sp_loadsize, 0, 4); // Load size of system program - Array.Copy(ipbin_sector, 0x048, ipbin.sp_entry_address, 0, 4); // System program entry address - Array.Copy(ipbin_sector, 0x04C, ipbin.sp_work_ram_size, 0, 4); // System program work RAM size in bytes - Array.Copy(ipbin_sector, 0x050, ipbin.release_date, 0, 8); // MMDDYYYY - Array.Copy(ipbin_sector, 0x058, ipbin.unknown1, 0, 7); // Seems to be all 0x20s - Array.Copy(ipbin_sector, 0x05F, ipbin.spare_space4, 0, 1); // 0x00 ? - Array.Copy(ipbin_sector, 0x060, ipbin.system_reserved, 0, 160); // System Reserved Area - Array.Copy(ipbin_sector, 0x100, ipbin.hardware_id, 0, 16); // Hardware ID - Array.Copy(ipbin_sector, 0x110, ipbin.copyright, 0, 3); // "(C)" -- Can be the developer code directly!, if that is the code release date will be displaced - if(Encoding.ASCII.GetString(ipbin.copyright) == "(C)") - Array.Copy(ipbin_sector, 0x113, ipbin.developer_code, 0, 5); // "SEGA" or "T-xx" - else - Array.Copy(ipbin_sector, 0x110, ipbin.developer_code, 0, 5); // "SEGA" or "T-xx" - Array.Copy(ipbin_sector, 0x118, ipbin.release_date2, 0, 8); // Another release date, this with month in letters? - Array.Copy(ipbin_sector, 0x120, ipbin.domestic_title, 0, 48); // Domestic version of the game title - Array.Copy(ipbin_sector, 0x150, ipbin.overseas_title, 0, 48); // Overseas version of the game title - //Array.Copy(ipbin_sector, 0x000, application_type, 0, 2); // Application type - //Array.Copy(ipbin_sector, 0x000, space_space5, 0, 1); // 0x20 - Array.Copy(ipbin_sector, 0x180, ipbin.product_code, 0, 13); // Official product code - Array.Copy(ipbin_sector, 0x190, ipbin.peripherals, 0, 16); // Supported peripherals, see above - Array.Copy(ipbin_sector, 0x1A0, ipbin.spare_space6, 0, 16); // 0x20 - Array.Copy(ipbin_sector, 0x1B0, ipbin.spare_space7, 0, 64); // Inside here should be modem information, but I need to get a modem-enabled game - Array.Copy(ipbin_sector, 0x1F0, ipbin.region_codes, 0, 16); // Region codes, space-filled + IntPtr ptr = Marshal.AllocHGlobal(512); + Marshal.Copy(ipbin_sector, 0, ptr, 512); + ipbin = (IPBin)Marshal.PtrToStructure(ptr, typeof(IPBin)); + Marshal.FreeHGlobal(ptr); DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.volume_name = \"{0}\"", Encoding.ASCII.GetString(ipbin.volume_name)); DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.system_name = \"{0}\"", Encoding.ASCII.GetString(ipbin.system_name)); - DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.volume_version = \"{0}\"", Encoding.ASCII.GetString(ipbin.volume_version)); - DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.volume_type = 0x{0}", BitConverter.ToInt16(ipbin.volume_type, 0).ToString("X")); - DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.system_version = 0x{0}", BitConverter.ToInt16(ipbin.system_version, 0).ToString("X")); - DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.ip_address = 0x{0}", BitConverter.ToInt32(ipbin.ip_address, 0).ToString("X")); - DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.ip_loadsize = {0}", BitConverter.ToInt32(ipbin.ip_loadsize, 0)); - DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.ip_entry_address = 0x{0}", BitConverter.ToInt32(ipbin.ip_entry_address, 0).ToString("X")); - DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.ip_work_ram_size = {0}", BitConverter.ToInt32(ipbin.ip_work_ram_size, 0)); - DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.sp_address = 0x{0}", BitConverter.ToInt32(ipbin.sp_address, 0).ToString("X")); - DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.sp_loadsize = {0}", BitConverter.ToInt32(ipbin.sp_loadsize, 0)); - DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.sp_entry_address = 0x{0}", BitConverter.ToInt32(ipbin.sp_entry_address, 0).ToString("X")); - DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.sp_work_ram_size = {0}", BitConverter.ToInt32(ipbin.sp_work_ram_size, 0)); + DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.volume_version = \"{0:X}\"", ipbin.volume_version); + DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.volume_type = 0x{0:X8}", ipbin.volume_type); + DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.system_version = 0x{0:X8}", ipbin.system_version); + DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.ip_address = 0x{0:X8}", ipbin.ip_address); + DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.ip_loadsize = {0}", ipbin.ip_loadsize); + DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.ip_entry_address = 0x{0:X8}", ipbin.ip_entry_address); + DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.ip_work_ram_size = {0}", ipbin.ip_work_ram_size); + DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.sp_address = 0x{0:X8}", ipbin.sp_address); + DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.sp_loadsize = {0}", ipbin.sp_loadsize); + DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.sp_entry_address = 0x{0:X8}", ipbin.sp_entry_address); + DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.sp_work_ram_size = {0}", ipbin.sp_work_ram_size); DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.release_date = \"{0}\"", Encoding.ASCII.GetString(ipbin.release_date)); DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.release_date2 = \"{0}\"", Encoding.ASCII.GetString(ipbin.release_date2)); DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.developer_code = \"{0}\"", Encoding.ASCII.GetString(ipbin.developer_code)); @@ -180,10 +161,7 @@ namespace DiscImageChef.Decoders.Sega string id = Encoding.ASCII.GetString(ipbin.SegaHardwareID); - if(id == "SEGADISCSYSTEM " || id == "SEGADATADISC " || id == "SEGAOS ") - return ipbin; - else - return null; + return id == "SEGADISCSYSTEM " || id == "SEGADATADISC " || id == "SEGAOS " ? ipbin : (IPBin?)null; } public static string Prettify(IPBin? decoded) @@ -237,14 +215,14 @@ namespace DiscImageChef.Decoders.Sega //IPBinInformation.AppendFormat("{0}", Encoding.ASCII.GetString(ipbin.volume_type)).AppendLine(); IPBinInformation.AppendFormat("System name: {0}", Encoding.ASCII.GetString(ipbin.system_name)).AppendLine(); //IPBinInformation.AppendFormat("System version: {0}", Encoding.ASCII.GetString(ipbin.system_version)).AppendLine(); - IPBinInformation.AppendFormat("Initial program address: 0x{0}", BitConverter.ToInt32(ipbin.ip_address, 0).ToString("X")).AppendLine(); - IPBinInformation.AppendFormat("Initial program load size: {0} bytes", BitConverter.ToInt32(ipbin.ip_loadsize, 0)).AppendLine(); - IPBinInformation.AppendFormat("Initial program entry address: 0x{0}", BitConverter.ToInt32(ipbin.ip_entry_address, 0).ToString("X")).AppendLine(); - IPBinInformation.AppendFormat("Initial program work RAM: {0} bytes", BitConverter.ToInt32(ipbin.ip_work_ram_size, 0)).AppendLine(); - IPBinInformation.AppendFormat("System program address: 0x{0}", BitConverter.ToInt32(ipbin.sp_address, 0).ToString("X")).AppendLine(); - IPBinInformation.AppendFormat("System program load size: {0} bytes", BitConverter.ToInt32(ipbin.sp_loadsize, 0)).AppendLine(); - IPBinInformation.AppendFormat("System program entry address: 0x{0}", BitConverter.ToInt32(ipbin.sp_entry_address, 0).ToString("X")).AppendLine(); - IPBinInformation.AppendFormat("System program work RAM: {0} bytes", BitConverter.ToInt32(ipbin.sp_work_ram_size, 0)).AppendLine(); + IPBinInformation.AppendFormat("Initial program address: 0x{0:X8}", ipbin.ip_address).AppendLine(); + IPBinInformation.AppendFormat("Initial program load size: {0} bytes", ipbin.ip_loadsize).AppendLine(); + IPBinInformation.AppendFormat("Initial program entry address: 0x{0:X8}", ipbin.ip_entry_address).AppendLine(); + IPBinInformation.AppendFormat("Initial program work RAM: {0} bytes", ipbin.ip_work_ram_size).AppendLine(); + IPBinInformation.AppendFormat("System program address: 0x{0:X8}", ipbin.sp_address).AppendLine(); + IPBinInformation.AppendFormat("System program load size: {0} bytes", ipbin.sp_loadsize).AppendLine(); + IPBinInformation.AppendFormat("System program entry address: 0x{0:X8}", ipbin.sp_entry_address).AppendLine(); + IPBinInformation.AppendFormat("System program work RAM: {0} bytes", ipbin.sp_work_ram_size).AppendLine(); if(ipbindate != DateTime.MinValue) IPBinInformation.AppendFormat("Release date: {0}", ipbindate).AppendLine(); //IPBinInformation.AppendFormat("Release date (other format): {0}", Encoding.ASCII.GetString(release_date2)).AppendLine(); diff --git a/DiscImageChef.Decoders/Sega/Dreamcast.cs b/DiscImageChef.Decoders/Sega/Dreamcast.cs index a14586bb7..6f7488819 100644 --- a/DiscImageChef.Decoders/Sega/Dreamcast.cs +++ b/DiscImageChef.Decoders/Sega/Dreamcast.cs @@ -31,33 +31,71 @@ // ****************************************************************************/ using System; using System.Globalization; +using System.Runtime.InteropServices; using System.Text; using DiscImageChef.Console; namespace DiscImageChef.Decoders.Sega { - public class Dreamcast + public static class Dreamcast { + [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct IPBin { - public byte[] SegaHardwareID; //16 - public byte[] maker_id; //16 // 0x010, "SEGA ENTERPRISES" - public byte[] dreamcast_crc; //4 // 0x020, CRC of product_no and product_version - public byte[] spare_space1; //1 // 0x024, " " - public byte[] dreamcast_media; //6 // 0x025, "GD-ROM" - public byte[] disc_no; //1 // 0x02B, Disc number - public byte[] disc_no_separator; //1 // 0x02C, '/' - public byte[] disc_total_nos; //1 // 0x02D, Total number of discs - public byte[] spare_space2; //2 // 0x02E, " " - public byte[] region_codes; //8 // 0x030, Region codes, space-filled - public byte[] peripherals; //7 // 0x038, Supported peripherals, bitwise - public byte[] product_no; //10 // 0x03C, Product number - public byte[] product_version; //6 // 0x046, Product version - public byte[] release_date; //8 // 0x04C, YYYYMMDD - public byte[] spare_space3; //8 // 0x054, " " - public byte[] boot_filename; //12 // 0x05C, Usually "1ST_READ.BIN" or "0WINCE.BIN " - public byte[] producer; //16 // 0x068, Game producer, space-filled - public byte[] product_name; //128 // 0x078, Game name, space-filled + /// Must be "SEGA SEGAKATANA " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] SegaHardwareID; + /// 0x010, "SEGA ENTERPRISES" + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] maker_id; + /// 0x020, CRC of product_no and product_version + public uint dreamcast_crc; + /// 0x024, " " + public byte spare_space1; + /// 0x025, "GD-ROM" + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public byte[] dreamcast_media; + /// 0x02B, Disc number + public byte disc_no; + /// 0x02C, '/' + public byte disc_no_separator; + /// 0x02D, Total number of discs + public byte disc_total_nos; + /// 0x02E, " " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public byte[] spare_space2; + /// 0x030, Region codes, space-filled + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] region_codes; + /// 0x038, Supported peripherals, bitwise + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] + public byte[] peripherals; + /// 0x03F, ' ' + public byte spare_space3; + /// 0x040, Product number + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] + public byte[] product_no; + /// 0x04A, Product version + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public byte[] product_version; + /// 0x050, YYYYMMDD + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] release_date; + /// 0x058, " " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] spare_space4; + /// 0x060, Usually "1ST_READ.BIN" or "0WINCE.BIN " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public byte[] boot_filename; + /// 0x06C, " " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public byte[] spare_space5; + /// 0x070, Game producer, space-filled + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] producer; + /// 0x080, Game name, space-filled + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] + public byte[] product_name; } public static IPBin? DecodeIPBin(byte[] ipbin_sector) @@ -69,68 +107,29 @@ namespace DiscImageChef.Decoders.Sega return null; IPBin ipbin = new IPBin(); - ipbin.SegaHardwareID = new byte[16]; - // Declarations following - ipbin.maker_id = new byte[16]; // 0x010, "SEGA ENTERPRISES" - ipbin.dreamcast_crc = new byte[4]; // 0x020, CRC of product_no and product_version - ipbin.spare_space1 = new byte[1]; // 0x024, " " - ipbin.dreamcast_media = new byte[6]; // 0x025, "GD-ROM" - ipbin.disc_no = new byte[1]; // 0x02B, Disc number - ipbin.disc_no_separator = new byte[1]; // 0x02C, '/' - ipbin.disc_total_nos = new byte[1]; // 0x02D, Total number of discs - ipbin.spare_space2 = new byte[2]; // 0x02E, " " - ipbin.region_codes = new byte[8]; // 0x030, Region codes, space-filled - ipbin.peripherals = new byte[7]; // 0x038, Supported peripherals, bitwise - ipbin.product_no = new byte[10]; // 0x03C, Product number - ipbin.product_version = new byte[6]; // 0x046, Product version - ipbin.release_date = new byte[8]; // 0x04C, YYYYMMDD - ipbin.spare_space3 = new byte[8]; // 0x054, " " - ipbin.boot_filename = new byte[12]; // 0x05C, Usually "1ST_READ.BIN" or "0WINCE.BIN " - ipbin.producer = new byte[16]; // 0x068, Game producer, space-filled - ipbin.product_name = new byte[128]; // 0x078, Game name, space-filled - // Reading all data - Array.Copy(ipbin_sector, 0x010, ipbin.maker_id, 0, 16); // "SEGA ENTERPRISES" - Array.Copy(ipbin_sector, 0x020, ipbin.dreamcast_crc, 0, 4); // CRC of product_no and product_version (hex) - Array.Copy(ipbin_sector, 0x024, ipbin.spare_space1, 0, 1); // " " - Array.Copy(ipbin_sector, 0x025, ipbin.dreamcast_media, 0, 6); // "GD-ROM" - Array.Copy(ipbin_sector, 0x02B, ipbin.disc_no, 0, 1); // Disc number - Array.Copy(ipbin_sector, 0x02C, ipbin.disc_no_separator, 0, 1); // '/' - Array.Copy(ipbin_sector, 0x02D, ipbin.disc_total_nos, 0, 1); // Total number of discs - Array.Copy(ipbin_sector, 0x02E, ipbin.spare_space2, 0, 2); // " " - Array.Copy(ipbin_sector, 0x030, ipbin.region_codes, 0, 8); // Region codes, space-filled - Array.Copy(ipbin_sector, 0x038, ipbin.peripherals, 0, 7); // Supported peripherals, hexadecimal - Array.Copy(ipbin_sector, 0x040, ipbin.product_no, 0, 10); // Product number - Array.Copy(ipbin_sector, 0x04A, ipbin.product_version, 0, 6); // Product version - Array.Copy(ipbin_sector, 0x050, ipbin.release_date, 0, 8); // YYYYMMDD - Array.Copy(ipbin_sector, 0x058, ipbin.spare_space3, 0, 8); // " " - Array.Copy(ipbin_sector, 0x060, ipbin.boot_filename, 0, 12); // Usually "1ST_READ.BIN" or "0WINCE.BIN " - Array.Copy(ipbin_sector, 0x070, ipbin.producer, 0, 16); // Game producer, space-filled - Array.Copy(ipbin_sector, 0x080, ipbin.product_name, 0, 128); // Game name, space-filled + IntPtr ptr = Marshal.AllocHGlobal(512); + Marshal.Copy(ipbin_sector, 0, ptr, 512); + ipbin = (IPBin)Marshal.PtrToStructure(ptr, typeof(IPBin)); + Marshal.FreeHGlobal(ptr); DicConsole.DebugWriteLine("ISO9660 plugin", "dreamcast_ipbin.maker_id = \"{0}\"", Encoding.ASCII.GetString(ipbin.maker_id)); - DicConsole.DebugWriteLine("ISO9660 plugin", "dreamcast_ipbin.dreamcast_crc = 0x{0}", Encoding.ASCII.GetString(ipbin.dreamcast_crc)); - DicConsole.DebugWriteLine("ISO9660 plugin", "dreamcast_ipbin.spare_space1 = \"{0}\"", Encoding.ASCII.GetString(ipbin.spare_space1)); + DicConsole.DebugWriteLine("ISO9660 plugin", "dreamcast_ipbin.spare_space1 = \"{0}\"", (char)ipbin.spare_space1); DicConsole.DebugWriteLine("ISO9660 plugin", "dreamcast_ipbin.dreamcast_media = \"{0}\"", Encoding.ASCII.GetString(ipbin.dreamcast_media)); - DicConsole.DebugWriteLine("ISO9660 plugin", "dreamcast_ipbin.disc_no = {0}", Encoding.ASCII.GetString(ipbin.disc_no)); - DicConsole.DebugWriteLine("ISO9660 plugin", "dreamcast_ipbin.disc_no_separator = \"{0}\"", Encoding.ASCII.GetString(ipbin.disc_no_separator)); - DicConsole.DebugWriteLine("ISO9660 plugin", "dreamcast_ipbin.disc_total_nos = \"{0}\"", Encoding.ASCII.GetString(ipbin.disc_total_nos)); + DicConsole.DebugWriteLine("ISO9660 plugin", "dreamcast_ipbin.disc_no = {0}", (char)ipbin.disc_no); + DicConsole.DebugWriteLine("ISO9660 plugin", "dreamcast_ipbin.disc_no_separator = \"{0}\"", (char)ipbin.disc_no_separator); + DicConsole.DebugWriteLine("ISO9660 plugin", "dreamcast_ipbin.disc_total_nos = \"{0}\"", (char)ipbin.disc_total_nos); DicConsole.DebugWriteLine("ISO9660 plugin", "dreamcast_ipbin.spare_space2 = \"{0}\"", Encoding.ASCII.GetString(ipbin.spare_space2)); DicConsole.DebugWriteLine("ISO9660 plugin", "dreamcast_ipbin.region_codes = \"{0}\"", Encoding.ASCII.GetString(ipbin.region_codes)); DicConsole.DebugWriteLine("ISO9660 plugin", "dreamcast_ipbin.peripherals = \"{0}\"", Encoding.ASCII.GetString(ipbin.peripherals)); DicConsole.DebugWriteLine("ISO9660 plugin", "dreamcast_ipbin.product_no = \"{0}\"", Encoding.ASCII.GetString(ipbin.product_no)); DicConsole.DebugWriteLine("ISO9660 plugin", "dreamcast_ipbin.product_version = \"{0}\"", Encoding.ASCII.GetString(ipbin.product_version)); DicConsole.DebugWriteLine("ISO9660 plugin", "dreamcast_ipbin.release_date = \"{0}\"", Encoding.ASCII.GetString(ipbin.release_date)); - DicConsole.DebugWriteLine("ISO9660 plugin", "dreamcast_ipbin.spare_space3 = \"{0}\"", Encoding.ASCII.GetString(ipbin.spare_space3)); + DicConsole.DebugWriteLine("ISO9660 plugin", "dreamcast_ipbin.spare_space3 = \"{0}\"", (char)ipbin.spare_space3); DicConsole.DebugWriteLine("ISO9660 plugin", "dreamcast_ipbin.boot_filename = \"{0}\"", Encoding.ASCII.GetString(ipbin.boot_filename)); DicConsole.DebugWriteLine("ISO9660 plugin", "dreamcast_ipbin.producer = \"{0}\"", Encoding.ASCII.GetString(ipbin.producer)); DicConsole.DebugWriteLine("ISO9660 plugin", "dreamcast_ipbin.product_name = \"{0}\"", Encoding.ASCII.GetString(ipbin.product_name)); - string id = Encoding.ASCII.GetString(ipbin.SegaHardwareID); - - if(id == "SEGA SEGAKATANA ") - return ipbin; - else - return null; + return Encoding.ASCII.GetString(ipbin.SegaHardwareID) == "SEGA SEGAKATANA " ? ipbin : (IPBin?)null; } public static string Prettify(IPBin? decoded) @@ -152,9 +151,10 @@ namespace DiscImageChef.Decoders.Sega ipbindate = DateTime.ParseExact(Encoding.ASCII.GetString(ipbin.release_date), "yyyyMMdd", provider); IPBinInformation.AppendFormat("Product name: {0}", Encoding.ASCII.GetString(ipbin.product_name)).AppendLine(); IPBinInformation.AppendFormat("Product version: {0}", Encoding.ASCII.GetString(ipbin.product_version)).AppendLine(); + IPBinInformation.AppendFormat("Product CRC: 0x{0:X8}", ipbin.dreamcast_crc).AppendLine(); IPBinInformation.AppendFormat("Producer: {0}", Encoding.ASCII.GetString(ipbin.producer)).AppendLine(); IPBinInformation.AppendFormat("Disc media: {0}", Encoding.ASCII.GetString(ipbin.dreamcast_media)).AppendLine(); - IPBinInformation.AppendFormat("Disc number {0} of {1}", Encoding.ASCII.GetString(ipbin.disc_no), Encoding.ASCII.GetString(ipbin.disc_total_nos)).AppendLine(); + IPBinInformation.AppendFormat("Disc number {0} of {1}", (char)ipbin.disc_no, (char)ipbin.disc_total_nos).AppendLine(); IPBinInformation.AppendFormat("Release date: {0}", ipbindate).AppendLine(); switch(Encoding.ASCII.GetString(ipbin.boot_filename)) { @@ -240,8 +240,8 @@ namespace DiscImageChef.Decoders.Sega if((iPeripherals & 0x08000000) == 0x08000000) IPBinInformation.AppendLine("Game supports Mouse."); - if((iPeripherals & 0xF00000EE) != 0) - IPBinInformation.AppendFormat("Game supports unknown peripherals mask {0:X2}", (iPeripherals & 0xF00000EE)); + if((iPeripherals & 0xEE) != 0) + IPBinInformation.AppendFormat("Game supports unknown peripherals mask {0:X2}", (iPeripherals & 0xEE)); return IPBinInformation.ToString(); } diff --git a/DiscImageChef.Decoders/Sega/Saturn.cs b/DiscImageChef.Decoders/Sega/Saturn.cs index d8ba75cee..9fe4787e5 100644 --- a/DiscImageChef.Decoders/Sega/Saturn.cs +++ b/DiscImageChef.Decoders/Sega/Saturn.cs @@ -31,6 +31,7 @@ // ****************************************************************************/ using System; using System.Globalization; +using System.Runtime.InteropServices; using System.Text; using DiscImageChef.Console; @@ -38,21 +39,45 @@ namespace DiscImageChef.Decoders.Sega { public static class Saturn { + [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct IPBin { - public byte[] SegaHardwareID; //16 - public byte[] maker_id; //[16 // 0x010, "SEGA ENTERPRISES" - public byte[] product_no; //[10 // 0x020, Product number - public byte[] product_version; //[6 // 0x02A, Product version - public byte[] release_date; //[8 // 0x030, YYYYMMDD - public byte[] saturn_media; //[3 // 0x038, "CD-" - public byte[] disc_no; //[1 // 0x03B, Disc number - public byte[] disc_no_separator; //[1 // 0x03C, '/' - public byte[] disc_total_nos; //[1 // 0x03D, Total number of discs - public byte[] spare_space1; //[2 // 0x03E, " " - public byte[] region_codes; //[16 // 0x040, Region codes, space-filled - public byte[] peripherals; //[16 // 0x050, Supported peripherals, see above - public byte[] product_name; //[112 // 0x060, Game name, space-filled + /// Must be "SEGA SEGASATURN " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] SegaHardwareID; + /// 0x010, "SEGA ENTERPRISES" + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] maker_id; + /// 0x020, Product number + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] + public byte[] product_no; + /// 0x02A, Product version + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public byte[] product_version; + /// 0x030, YYYYMMDD + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] release_date; + /// 0x038, "CD-" + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] saturn_media; + /// 0x03B, Disc number + public byte disc_no; + /// // 0x03C, '/' + public byte disc_no_separator; + /// // 0x03D, Total number of discs + public byte disc_total_nos; + /// 0x03E, " " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public byte[] spare_space1; + /// 0x040, Region codes, space-filled + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] region_codes; + /// 0x050, Supported peripherals, see above + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] peripherals; + /// 0x060, Game name, space-filled + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 112)] + public byte[] product_name; } public static IPBin? DecodeIPBin(byte[] ipbin_sector) @@ -64,54 +89,26 @@ namespace DiscImageChef.Decoders.Sega return null; IPBin ipbin = new IPBin(); - ipbin.SegaHardwareID = new byte[16]; - // Definitions following - ipbin.maker_id = new byte[16]; // 0x010, "SEGA ENTERPRISES" - ipbin.product_no = new byte[10]; // 0x020, Product number - ipbin.product_version = new byte[6]; // 0x02A, Product version - ipbin.release_date = new byte[8]; // 0x030, YYYYMMDD - ipbin.saturn_media = new byte[3]; // 0x038, "CD-" - ipbin.disc_no = new byte[1]; // 0x03B, Disc number - ipbin.disc_no_separator = new byte[1]; // 0x03C, '/' - ipbin.disc_total_nos = new byte[1]; // 0x03D, Total number of discs - ipbin.spare_space1 = new byte[2]; // 0x03E, " " - ipbin.region_codes = new byte[16]; // 0x040, Region codes, space-filled - ipbin.peripherals = new byte[16]; // 0x050, Supported peripherals, see above - ipbin.product_name = new byte[112]; // 0x060, Game name, space-filled - // Reading all data - Array.Copy(ipbin_sector, 0x010, ipbin.maker_id, 0, 16); // "SEGA ENTERPRISES" - Array.Copy(ipbin_sector, 0x020, ipbin.product_no, 0, 10); // Product number - Array.Copy(ipbin_sector, 0x02A, ipbin.product_version, 0, 6); // Product version - Array.Copy(ipbin_sector, 0x030, ipbin.release_date, 0, 8); // YYYYMMDD - Array.Copy(ipbin_sector, 0x038, ipbin.saturn_media, 0, 3); // "CD-" - Array.Copy(ipbin_sector, 0x03B, ipbin.disc_no, 0, 1); // Disc number - Array.Copy(ipbin_sector, 0x03C, ipbin.disc_no_separator, 0, 1); // '/' - Array.Copy(ipbin_sector, 0x03D, ipbin.disc_total_nos, 0, 1); // Total number of discs - Array.Copy(ipbin_sector, 0x03E, ipbin.spare_space1, 0, 2); // " " - Array.Copy(ipbin_sector, 0x040, ipbin.region_codes, 0, 16); // Region codes, space-filled - Array.Copy(ipbin_sector, 0x050, ipbin.peripherals, 0, 16); // Supported peripherals, see above - Array.Copy(ipbin_sector, 0x060, ipbin.product_name, 0, 112); // Game name, space-filled + IntPtr ptr = Marshal.AllocHGlobal(512); + Marshal.Copy(ipbin_sector, 0, ptr, 512); + ipbin = (IPBin)Marshal.PtrToStructure(ptr, typeof(IPBin)); + Marshal.FreeHGlobal(ptr); DicConsole.DebugWriteLine("ISO9660 plugin", "saturn_ipbin.maker_id = \"{0}\"", Encoding.ASCII.GetString(ipbin.maker_id)); DicConsole.DebugWriteLine("ISO9660 plugin", "saturn_ipbin.product_no = \"{0}\"", Encoding.ASCII.GetString(ipbin.product_no)); DicConsole.DebugWriteLine("ISO9660 plugin", "saturn_ipbin.product_version = \"{0}\"", Encoding.ASCII.GetString(ipbin.product_version)); DicConsole.DebugWriteLine("ISO9660 plugin", "saturn_ipbin.release_datedate = \"{0}\"", Encoding.ASCII.GetString(ipbin.release_date)); DicConsole.DebugWriteLine("ISO9660 plugin", "saturn_ipbin.saturn_media = \"{0}\"", Encoding.ASCII.GetString(ipbin.saturn_media)); - DicConsole.DebugWriteLine("ISO9660 plugin", "saturn_ipbin.disc_no = {0}", Encoding.ASCII.GetString(ipbin.disc_no)); - DicConsole.DebugWriteLine("ISO9660 plugin", "saturn_ipbin.disc_no_separator = \"{0}\"", Encoding.ASCII.GetString(ipbin.disc_no_separator)); - DicConsole.DebugWriteLine("ISO9660 plugin", "saturn_ipbin.disc_total_nos = {0}", Encoding.ASCII.GetString(ipbin.disc_total_nos)); + DicConsole.DebugWriteLine("ISO9660 plugin", "saturn_ipbin.disc_no = {0}", (char)ipbin.disc_no); + DicConsole.DebugWriteLine("ISO9660 plugin", "saturn_ipbin.disc_no_separator = \"{0}\"", (char)ipbin.disc_no_separator); + DicConsole.DebugWriteLine("ISO9660 plugin", "saturn_ipbin.disc_total_nos = {0}", (char)ipbin.disc_total_nos); DicConsole.DebugWriteLine("ISO9660 plugin", "saturn_ipbin.release_date = \"{0}\"", Encoding.ASCII.GetString(ipbin.release_date)); DicConsole.DebugWriteLine("ISO9660 plugin", "saturn_ipbin.spare_space1 = \"{0}\"", Encoding.ASCII.GetString(ipbin.spare_space1)); DicConsole.DebugWriteLine("ISO9660 plugin", "saturn_ipbin.region_codes = \"{0}\"", Encoding.ASCII.GetString(ipbin.region_codes)); DicConsole.DebugWriteLine("ISO9660 plugin", "saturn_ipbin.peripherals = \"{0}\"", Encoding.ASCII.GetString(ipbin.peripherals)); DicConsole.DebugWriteLine("ISO9660 plugin", "saturn_ipbin.product_name = \"{0}\"", Encoding.ASCII.GetString(ipbin.product_name)); - string id = Encoding.ASCII.GetString(ipbin.SegaHardwareID); - - if(id == "SEGA SEGASATURN ") - return ipbin; - else - return null; + return Encoding.ASCII.GetString(ipbin.SegaHardwareID) == "SEGA SEGASATURN " ? ipbin : (IPBin?)null; } public static string Prettify(IPBin? decoded) @@ -135,7 +132,7 @@ namespace DiscImageChef.Decoders.Sega IPBinInformation.AppendFormat("Product number: {0}", Encoding.ASCII.GetString(ipbin.product_no)).AppendLine(); IPBinInformation.AppendFormat("Product version: {0}", Encoding.ASCII.GetString(ipbin.product_version)).AppendLine(); IPBinInformation.AppendFormat("Release date: {0}", ipbindate).AppendLine(); - IPBinInformation.AppendFormat("Disc number {0} of {1}", Encoding.ASCII.GetString(ipbin.disc_no), Encoding.ASCII.GetString(ipbin.disc_total_nos)).AppendLine(); + IPBinInformation.AppendFormat("Disc number {0} of {1}", (char)ipbin.disc_no, (char)ipbin.disc_total_nos).AppendLine(); IPBinInformation.AppendFormat("Peripherals:").AppendLine(); foreach(byte peripheral in ipbin.peripherals)