mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
Added decoding of El Torito boot catalog.
This commit is contained in:
@@ -37,6 +37,8 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
{
|
||||
readonly string IsoMagic = "CD001";
|
||||
readonly string HighSierraMagic = "CDROM";
|
||||
const ushort ElToritoMagic = 0xAA55;
|
||||
const int ElToritoEntrySize = 32;
|
||||
|
||||
[Flags]
|
||||
enum FileFlags : byte
|
||||
@@ -76,5 +78,39 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
ISO1539 = 1,
|
||||
ControlContained = 2,
|
||||
}
|
||||
|
||||
enum ElToritoIndicator : byte
|
||||
{
|
||||
Header = 1,
|
||||
Extension = 0x44,
|
||||
Bootable = 0x88,
|
||||
MoreHeaders = 0x90,
|
||||
LastHeader = 0x91
|
||||
}
|
||||
|
||||
enum ElToritoPlatform : byte
|
||||
{
|
||||
x86 = 0,
|
||||
PowerPC = 1,
|
||||
Macintosh = 2
|
||||
}
|
||||
|
||||
enum ElToritoEmulation : byte
|
||||
{
|
||||
None = 0,
|
||||
Md2hd = 1,
|
||||
Mf2hd = 2,
|
||||
Mf2ed = 3,
|
||||
Hdd = 4
|
||||
}
|
||||
|
||||
[Flags]
|
||||
enum ElToritoFlags : byte
|
||||
{
|
||||
Reserved = 0x10,
|
||||
Continued = 0x20,
|
||||
ATAPI = 0x40,
|
||||
SCSI = 0x08
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,6 +93,7 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
PrimaryVolumeDescriptor? jolietvd = null;
|
||||
BootRecord? bvd = null;
|
||||
HighSierraPrimaryVolumeDescriptor? hsvd = null;
|
||||
ElToritoBootRecord? torito = null;
|
||||
|
||||
// ISO9660 is designed for 2048 bytes/sector devices
|
||||
if(imagePlugin.GetSectorSize() < 2048)
|
||||
@@ -143,7 +144,7 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
|
||||
switch(VDType)
|
||||
{
|
||||
case 0: // TODO
|
||||
case 0:
|
||||
{
|
||||
bvd = new BootRecord();
|
||||
IntPtr ptr = Marshal.AllocHGlobal(2048);
|
||||
@@ -154,7 +155,14 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
BootSpec = "Unknown";
|
||||
|
||||
if(CurrentEncoding.GetString(bvd.Value.system_id).Substring(0, 23) == "EL TORITO SPECIFICATION")
|
||||
{
|
||||
BootSpec = "El Torito";
|
||||
torito = new ElToritoBootRecord();
|
||||
ptr = Marshal.AllocHGlobal(2048);
|
||||
Marshal.Copy(vd_sector, hs_off, ptr, 2048 - hs_off);
|
||||
torito = (ElToritoBootRecord)Marshal.PtrToStructure(ptr, typeof(ElToritoBootRecord));
|
||||
Marshal.FreeHGlobal(ptr);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -278,9 +286,9 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
ISOMetadata.AppendLine("This is a Sega Dreamcast disc.");
|
||||
ISOMetadata.AppendLine(Decoders.Sega.Dreamcast.Prettify(Dreamcast));
|
||||
}
|
||||
ISOMetadata.AppendLine("--------------------------------");
|
||||
ISOMetadata.AppendLine("------------------------------");
|
||||
ISOMetadata.AppendLine("VOLUME DESCRIPTOR INFORMATION:");
|
||||
ISOMetadata.AppendLine("--------------------------------");
|
||||
ISOMetadata.AppendLine("------------------------------");
|
||||
ISOMetadata.AppendFormat("System identifier: {0}", decodedVD.SystemIdentifier).AppendLine();
|
||||
ISOMetadata.AppendFormat("Volume identifier: {0}", decodedVD.VolumeIdentifier).AppendLine();
|
||||
ISOMetadata.AppendFormat("Volume set identifier: {0}", decodedVD.VolumeSetIdentifier).AppendLine();
|
||||
@@ -304,9 +312,9 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
|
||||
if(jolietvd != null)
|
||||
{
|
||||
ISOMetadata.AppendLine("---------------------------------------");
|
||||
ISOMetadata.AppendLine("-------------------------------------");
|
||||
ISOMetadata.AppendLine("JOLIET VOLUME DESCRIPTOR INFORMATION:");
|
||||
ISOMetadata.AppendLine("---------------------------------------");
|
||||
ISOMetadata.AppendLine("-------------------------------------");
|
||||
ISOMetadata.AppendFormat("System identifier: {0}", decodedJolietVD.SystemIdentifier).AppendLine();
|
||||
ISOMetadata.AppendFormat("Volume identifier: {0}", decodedJolietVD.VolumeIdentifier).AppendLine();
|
||||
ISOMetadata.AppendFormat("Volume set identifier: {0}", decodedJolietVD.VolumeSetIdentifier).AppendLine();
|
||||
@@ -328,6 +336,166 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
ISOMetadata.AppendFormat("Volume has always been effective.").AppendLine();
|
||||
}
|
||||
|
||||
if(torito != null)
|
||||
{
|
||||
vd_sector = imagePlugin.ReadSector(torito.Value.catalog_sector + partition.Start);
|
||||
Checksums.SHA1Context sha1Ctx = new Checksums.SHA1Context();
|
||||
sha1Ctx.Init();
|
||||
byte[] boot_image;
|
||||
|
||||
int torito_off = 0;
|
||||
|
||||
if(vd_sector[torito_off] != 1)
|
||||
goto exit_torito;
|
||||
|
||||
ElToritoValidationEntry valentry = new ElToritoValidationEntry();
|
||||
IntPtr ptr = Marshal.AllocHGlobal(ElToritoEntrySize);
|
||||
Marshal.Copy(vd_sector, torito_off, ptr, ElToritoEntrySize);
|
||||
valentry = (ElToritoValidationEntry)Marshal.PtrToStructure(ptr, typeof(ElToritoValidationEntry));
|
||||
Marshal.FreeHGlobal(ptr);
|
||||
|
||||
if(valentry.signature != ElToritoMagic)
|
||||
goto exit_torito;
|
||||
|
||||
torito_off += ElToritoEntrySize;
|
||||
|
||||
ElToritoInitialEntry initial_entry = new ElToritoInitialEntry();
|
||||
ptr = Marshal.AllocHGlobal(ElToritoEntrySize);
|
||||
Marshal.Copy(vd_sector, torito_off, ptr, ElToritoEntrySize);
|
||||
initial_entry = (ElToritoInitialEntry)Marshal.PtrToStructure(ptr, typeof(ElToritoInitialEntry));
|
||||
Marshal.FreeHGlobal(ptr);
|
||||
initial_entry.boot_type = (ElToritoEmulation)((byte)initial_entry.boot_type & 0xF);
|
||||
|
||||
boot_image = imagePlugin.ReadSectors(initial_entry.load_rba + partition.Start, initial_entry.sector_count);
|
||||
|
||||
ISOMetadata.AppendLine("----------------------");
|
||||
ISOMetadata.AppendLine("EL TORITO INFORMATION:");
|
||||
ISOMetadata.AppendLine("----------------------");
|
||||
|
||||
ISOMetadata.AppendLine("Initial entry:");
|
||||
ISOMetadata.AppendFormat("\tDeveloper ID: {0}", CurrentEncoding.GetString(valentry.developer_id)).AppendLine();
|
||||
if(initial_entry.bootable == ElToritoIndicator.Bootable)
|
||||
{
|
||||
ISOMetadata.AppendFormat("\tBootable on {0}", valentry.platform_id).AppendLine();
|
||||
ISOMetadata.AppendFormat("\tBootable image starts at sector {0} and runs for {1} sectors", initial_entry.load_rba, initial_entry.sector_count).AppendLine();
|
||||
if(valentry.platform_id == ElToritoPlatform.x86)
|
||||
ISOMetadata.AppendFormat("\tBootable image will be loaded at segment {0:X4}h", initial_entry.load_seg == 0 ? 0x7C0 : initial_entry.load_seg).AppendLine();
|
||||
else
|
||||
ISOMetadata.AppendFormat("\tBootable image will be loaded at 0x{0:X8}", (uint)initial_entry.load_seg * 10).AppendLine();
|
||||
switch(initial_entry.boot_type)
|
||||
{
|
||||
case ElToritoEmulation.None:
|
||||
ISOMetadata.AppendLine("\tImage uses no emulation");
|
||||
break;
|
||||
case ElToritoEmulation.Md2hd:
|
||||
ISOMetadata.AppendLine("\tImage emulates a 5.25\" high-density (MD2HD, 1.2Mb) floppy");
|
||||
break;
|
||||
case ElToritoEmulation.Mf2hd:
|
||||
ISOMetadata.AppendLine("\tImage emulates a 3.5\" high-density (MF2HD, 1.44Mb) floppy");
|
||||
break;
|
||||
case ElToritoEmulation.Mf2ed:
|
||||
ISOMetadata.AppendLine("\tImage emulates a 3.5\" extra-density (MF2ED, 2.88Mb) floppy");
|
||||
break;
|
||||
default:
|
||||
ISOMetadata.AppendFormat("\tImage uses unknown emulation type {0}", (byte)initial_entry.boot_type).AppendLine();
|
||||
break;
|
||||
}
|
||||
ISOMetadata.AppendFormat("\tSystem type: 0x{0:X2}", initial_entry.system_type).AppendLine();
|
||||
ISOMetadata.AppendFormat("\tBootable image's SHA1: {0}", sha1Ctx.Data(boot_image, out byte[] hash)).AppendLine();
|
||||
}
|
||||
else
|
||||
ISOMetadata.AppendLine("\tNot bootable");
|
||||
|
||||
torito_off += ElToritoEntrySize;
|
||||
|
||||
int section_counter = 2;
|
||||
|
||||
while(torito_off < vd_sector.Length && (vd_sector[torito_off] == (byte)ElToritoIndicator.Header || vd_sector[torito_off] == (byte)ElToritoIndicator.LastHeader))
|
||||
{
|
||||
ElToritoSectionHeaderEntry section_header = new ElToritoSectionHeaderEntry();
|
||||
ptr = Marshal.AllocHGlobal(ElToritoEntrySize);
|
||||
Marshal.Copy(vd_sector, torito_off, ptr, ElToritoEntrySize);
|
||||
section_header = (ElToritoSectionHeaderEntry)Marshal.PtrToStructure(ptr, typeof(ElToritoSectionHeaderEntry));
|
||||
Marshal.FreeHGlobal(ptr);
|
||||
torito_off += ElToritoEntrySize;
|
||||
|
||||
ISOMetadata.AppendFormat("Boot section {0}:", section_counter);
|
||||
ISOMetadata.AppendFormat("\tSection ID: {0}", CurrentEncoding.GetString(section_header.identifier)).AppendLine();
|
||||
|
||||
for(int entry_counter = 1; entry_counter <= section_header.entries && torito_off < vd_sector.Length; entry_counter++)
|
||||
{
|
||||
ElToritoSectionEntry section_entry = new ElToritoSectionEntry();
|
||||
ptr = Marshal.AllocHGlobal(ElToritoEntrySize);
|
||||
Marshal.Copy(vd_sector, torito_off, ptr, ElToritoEntrySize);
|
||||
section_entry = (ElToritoSectionEntry)Marshal.PtrToStructure(ptr, typeof(ElToritoSectionEntry));
|
||||
Marshal.FreeHGlobal(ptr);
|
||||
torito_off += ElToritoEntrySize;
|
||||
|
||||
ISOMetadata.AppendFormat("\tEntry {0}:", entry_counter);
|
||||
if(section_entry.bootable == ElToritoIndicator.Bootable)
|
||||
{
|
||||
boot_image = imagePlugin.ReadSectors(section_entry.load_rba + partition.Start, section_entry.sector_count);
|
||||
ISOMetadata.AppendFormat("\t\tBootable on {0}", section_header.platform_id).AppendLine();
|
||||
ISOMetadata.AppendFormat("\t\tBootable image starts at sector {0} and runs for {1} sectors", section_entry.load_rba, section_entry.sector_count).AppendLine();
|
||||
if(valentry.platform_id == ElToritoPlatform.x86)
|
||||
ISOMetadata.AppendFormat("\t\tBootable image will be loaded at segment {0:X4}h", section_entry.load_seg == 0 ? 0x7C0 : section_entry.load_seg).AppendLine();
|
||||
else
|
||||
ISOMetadata.AppendFormat("\t\tBootable image will be loaded at 0x{0:X8}", (uint)section_entry.load_seg * 10).AppendLine();
|
||||
switch((ElToritoEmulation)((byte)section_entry.boot_type & 0xF))
|
||||
{
|
||||
case ElToritoEmulation.None:
|
||||
ISOMetadata.AppendLine("\t\tImage uses no emulation");
|
||||
break;
|
||||
case ElToritoEmulation.Md2hd:
|
||||
ISOMetadata.AppendLine("\t\tImage emulates a 5.25\" high-density (MD2HD, 1.2Mb) floppy");
|
||||
break;
|
||||
case ElToritoEmulation.Mf2hd:
|
||||
ISOMetadata.AppendLine("\t\tImage emulates a 3.5\" high-density (MF2HD, 1.44Mb) floppy");
|
||||
break;
|
||||
case ElToritoEmulation.Mf2ed:
|
||||
ISOMetadata.AppendLine("\t\tImage emulates a 3.5\" extra-density (MF2ED, 2.88Mb) floppy");
|
||||
break;
|
||||
default:
|
||||
ISOMetadata.AppendFormat("\t\tImage uses unknown emulation type {0}", (byte)initial_entry.boot_type).AppendLine();
|
||||
break;
|
||||
}
|
||||
|
||||
ISOMetadata.AppendFormat("\t\tSelection criteria type: {0}", section_entry.selection_criteria_type).AppendLine();
|
||||
ISOMetadata.AppendFormat("\t\tSystem type: 0x{0:X2}", section_entry.system_type).AppendLine();
|
||||
ISOMetadata.AppendFormat("\t\tBootable image's SHA1: {0}", sha1Ctx.Data(boot_image, out byte[] hash)).AppendLine();
|
||||
}
|
||||
else
|
||||
ISOMetadata.AppendLine("\t\tNot bootable");
|
||||
|
||||
ElToritoFlags flags = (ElToritoFlags)((byte)section_entry.boot_type & 0xF0);
|
||||
if(flags.HasFlag(ElToritoFlags.ATAPI))
|
||||
ISOMetadata.AppendLine("\t\tImage contains ATAPI drivers");
|
||||
if(flags.HasFlag(ElToritoFlags.SCSI))
|
||||
ISOMetadata.AppendLine("\t\tImage contains SCSI drivers");
|
||||
|
||||
if(flags.HasFlag(ElToritoFlags.Continued))
|
||||
{
|
||||
while(true && torito_off < vd_sector.Length)
|
||||
{
|
||||
ElToritoSectionEntryExtension section_extension = new ElToritoSectionEntryExtension();
|
||||
ptr = Marshal.AllocHGlobal(ElToritoEntrySize);
|
||||
Marshal.Copy(vd_sector, torito_off, ptr, ElToritoEntrySize);
|
||||
section_extension = (ElToritoSectionEntryExtension)Marshal.PtrToStructure(ptr, typeof(ElToritoSectionEntryExtension));
|
||||
Marshal.FreeHGlobal(ptr);
|
||||
torito_off += ElToritoEntrySize;
|
||||
|
||||
if(!section_extension.extension_flags.HasFlag(ElToritoFlags.Continued))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(section_header.header_id == ElToritoIndicator.LastHeader)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
exit_torito:
|
||||
xmlFSType.Type = HighSierra ? "High Sierra Format" : "ISO9660";
|
||||
|
||||
if(jolietvd != null)
|
||||
|
||||
@@ -181,6 +181,22 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
public byte[] boot_use;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ElToritoBootRecord
|
||||
{
|
||||
public byte type;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
|
||||
public byte[] id;
|
||||
public byte version;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
|
||||
public byte[] system_id;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
|
||||
public byte[] boot_id;
|
||||
public uint catalog_sector;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1974)]
|
||||
public byte[] boot_use;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct PartitionDescriptor
|
||||
{
|
||||
@@ -272,6 +288,66 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
public ushort app_use_len_be;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ElToritoValidationEntry
|
||||
{
|
||||
public ElToritoIndicator header_id;
|
||||
public ElToritoPlatform platform_id;
|
||||
public ushort reserved;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)]
|
||||
public byte[] developer_id;
|
||||
public ushort checksum;
|
||||
public ushort signature;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ElToritoInitialEntry
|
||||
{
|
||||
public ElToritoIndicator bootable;
|
||||
public ElToritoEmulation boot_type;
|
||||
public ushort load_seg;
|
||||
public byte system_type;
|
||||
public byte reserved1;
|
||||
public ushort sector_count;
|
||||
public uint load_rba;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
|
||||
public byte[] reserved2;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ElToritoSectionHeaderEntry
|
||||
{
|
||||
public ElToritoIndicator header_id;
|
||||
public ElToritoPlatform platform_id;
|
||||
public ushort entries;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 28)]
|
||||
public byte[] identifier;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ElToritoSectionEntry
|
||||
{
|
||||
public ElToritoIndicator bootable;
|
||||
public ElToritoEmulation boot_type;
|
||||
public ushort load_seg;
|
||||
public byte system_type;
|
||||
public byte reserved1;
|
||||
public ushort sector_count;
|
||||
public uint load_rba;
|
||||
public byte selection_criteria_type;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 19)]
|
||||
public byte[] selection_criterias;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ElToritoSectionEntryExtension
|
||||
{
|
||||
public ElToritoIndicator extension_indicator;
|
||||
public ElToritoFlags extension_flags;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 30)]
|
||||
public byte[] selection_criterias;
|
||||
}
|
||||
|
||||
struct DecodedVolumeDescriptor
|
||||
{
|
||||
public string SystemIdentifier;
|
||||
|
||||
Reference in New Issue
Block a user