static BpbKind DetectBpbKind(byte[] bpbSector, IMediaImage imagePlugin, Partition partition, out BiosParameterBlockEbpb fakeBpb, out HumanParameterBlock humanBpb, out AtariParameterBlock atariBpb, out byte minBootNearJump, out bool andosOemCorrect, out bool bootable) { fakeBpb = new BiosParameterBlockEbpb(); minBootNearJump = 0; andosOemCorrect = false; bootable = false; humanBpb = Marshal.ByteArrayToStructureBigEndian <HumanParameterBlock>(bpbSector); atariBpb = Marshal.ByteArrayToStructureLittleEndian <AtariParameterBlock>(bpbSector); ulong expectedClusters = humanBpb.bpc > 0 ? partition.Size / humanBpb.bpc : 0; // Check clusters for Human68k are correct bool humanClustersCorrect = humanBpb.clusters == 0 ? humanBpb.big_clusters == expectedClusters : humanBpb.clusters == expectedClusters; // Check OEM for Human68k is correct bool humanOemCorrect = bpbSector[2] >= 0x20 && bpbSector[3] >= 0x20 && bpbSector[4] >= 0x20 && bpbSector[5] >= 0x20 && bpbSector[6] >= 0x20 && bpbSector[7] >= 0x20 && bpbSector[8] >= 0x20 && bpbSector[9] >= 0x20 && bpbSector[10] >= 0x20 && bpbSector[11] >= 0x20 && bpbSector[12] >= 0x20 && bpbSector[13] >= 0x20 && bpbSector[14] >= 0x20 && bpbSector[15] >= 0x20 && bpbSector[16] >= 0x20 && bpbSector[17] >= 0x20; // Check correct branch for Human68k bool humanBranchCorrect = bpbSector[0] == 0x60 && bpbSector[1] >= 0x1C && bpbSector[1] < 0xFE; AaruConsole.DebugWriteLine("FAT plugin", "humanClustersCorrect = {0}", humanClustersCorrect); AaruConsole.DebugWriteLine("FAT plugin", "humanOemCorrect = {0}", humanOemCorrect); AaruConsole.DebugWriteLine("FAT plugin", "humanBranchCorrect = {0}", humanBranchCorrect); // If all Human68k checks are correct, it is a Human68k FAT16 bool useHumanBpb = humanClustersCorrect && humanOemCorrect && humanBranchCorrect && expectedClusters > 0; if (useHumanBpb) { AaruConsole.DebugWriteLine("FAT plugin", "Using Human68k BPB"); fakeBpb.jump = humanBpb.jump; fakeBpb.oem_name = humanBpb.oem_name; fakeBpb.bps = (ushort)imagePlugin.Info.SectorSize; fakeBpb.spc = (byte)(humanBpb.bpc / fakeBpb.bps); fakeBpb.fats_no = 2; fakeBpb.root_ent = humanBpb.root_ent; fakeBpb.media = humanBpb.media; fakeBpb.spfat = (ushort)(humanBpb.cpfat * fakeBpb.spc); fakeBpb.boot_code = humanBpb.boot_code; fakeBpb.sectors = humanBpb.clusters; fakeBpb.big_sectors = humanBpb.big_clusters; fakeBpb.rsectors = 1; return(BpbKind.Human); } var msxBpb = new MsxParameterBlock(); var dos2Bpb = new BiosParameterBlock2(); var dos30Bpb = new BiosParameterBlock30(); var dos32Bpb = new BiosParameterBlock32(); var dos33Bpb = new BiosParameterBlock33(); var shortEbpb = new BiosParameterBlockShortEbpb(); var ebpb = new BiosParameterBlockEbpb(); var apricotBpb = new ApricotLabel(); bool useAtariBpb = false; bool useMsxBpb = false; bool useDos2Bpb = false; bool useDos3Bpb = false; bool useDos32Bpb = false; bool useDos33Bpb = false; bool userShortExtendedBpb = false; bool useExtendedBpb = false; bool useShortFat32 = false; bool useLongFat32 = false; bool useApricotBpb = false; bool useDecRainbowBpb = false; if (imagePlugin.Info.SectorSize >= 256) { msxBpb = Marshal.ByteArrayToStructureLittleEndian <MsxParameterBlock>(bpbSector); dos2Bpb = Marshal.ByteArrayToStructureLittleEndian <BiosParameterBlock2>(bpbSector); dos30Bpb = Marshal.ByteArrayToStructureLittleEndian <BiosParameterBlock30>(bpbSector); dos32Bpb = Marshal.ByteArrayToStructureLittleEndian <BiosParameterBlock32>(bpbSector); dos33Bpb = Marshal.ByteArrayToStructureLittleEndian <BiosParameterBlock33>(bpbSector); shortEbpb = Marshal.ByteArrayToStructureLittleEndian <BiosParameterBlockShortEbpb>(bpbSector); ebpb = Marshal.ByteArrayToStructureLittleEndian <BiosParameterBlockEbpb>(bpbSector); Fat32ParameterBlockShort shortFat32Bpb = Marshal.ByteArrayToStructureLittleEndian <Fat32ParameterBlockShort>(bpbSector); Fat32ParameterBlock fat32Bpb = Marshal.ByteArrayToStructureLittleEndian <Fat32ParameterBlock>(bpbSector); apricotBpb = Marshal.ByteArrayToStructureLittleEndian <ApricotLabel>(bpbSector); int bitsInBpsMsx = CountBits.Count(msxBpb.bps); int bitsInBpsDos33 = CountBits.Count(dos33Bpb.bps); int bitsInBpsDos40 = CountBits.Count(ebpb.bps); int bitsInBpsFat32Short = CountBits.Count(shortFat32Bpb.bps); int bitsInBpsFat32 = CountBits.Count(fat32Bpb.bps); int bitsInBpsApricot = CountBits.Count(apricotBpb.mainBPB.bps); bool correctSpcMsx = msxBpb.spc == 1 || msxBpb.spc == 2 || msxBpb.spc == 4 || msxBpb.spc == 8 || msxBpb.spc == 16 || msxBpb.spc == 32 || msxBpb.spc == 64; bool correctSpcDos33 = dos33Bpb.spc == 1 || dos33Bpb.spc == 2 || dos33Bpb.spc == 4 || dos33Bpb.spc == 8 || dos33Bpb.spc == 16 || dos33Bpb.spc == 32 || dos33Bpb.spc == 64; bool correctSpcDos40 = ebpb.spc == 1 || ebpb.spc == 2 || ebpb.spc == 4 || ebpb.spc == 8 || ebpb.spc == 16 || ebpb.spc == 32 || ebpb.spc == 64; bool correctSpcFat32Short = shortFat32Bpb.spc == 1 || shortFat32Bpb.spc == 2 || shortFat32Bpb.spc == 4 || shortFat32Bpb.spc == 8 || shortFat32Bpb.spc == 16 || shortFat32Bpb.spc == 32 || shortFat32Bpb.spc == 64; bool correctSpcFat32 = fat32Bpb.spc == 1 || fat32Bpb.spc == 2 || fat32Bpb.spc == 4 || fat32Bpb.spc == 8 || fat32Bpb.spc == 16 || fat32Bpb.spc == 32 || fat32Bpb.spc == 64; bool correctSpcApricot = apricotBpb.mainBPB.spc == 1 || apricotBpb.mainBPB.spc == 2 || apricotBpb.mainBPB.spc == 4 || apricotBpb.mainBPB.spc == 8 || apricotBpb.mainBPB.spc == 16 || apricotBpb.mainBPB.spc == 32 || apricotBpb.mainBPB.spc == 64; // This is to support FAT partitions on hybrid ISO/USB images if (imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc) { atariBpb.sectors /= 4; msxBpb.sectors /= 4; dos2Bpb.sectors /= 4; dos30Bpb.sectors /= 4; dos32Bpb.sectors /= 4; dos33Bpb.sectors /= 4; dos33Bpb.big_sectors /= 4; shortEbpb.sectors /= 4; shortEbpb.big_sectors /= 4; ebpb.sectors /= 4; ebpb.big_sectors /= 4; shortFat32Bpb.sectors /= 4; shortFat32Bpb.big_sectors /= 4; shortFat32Bpb.huge_sectors /= 4; fat32Bpb.sectors /= 4; fat32Bpb.big_sectors /= 4; apricotBpb.mainBPB.sectors /= 4; } andosOemCorrect = dos33Bpb.oem_name[0] < 0x20 && dos33Bpb.oem_name[1] >= 0x20 && dos33Bpb.oem_name[2] >= 0x20 && dos33Bpb.oem_name[3] >= 0x20 && dos33Bpb.oem_name[4] >= 0x20 && dos33Bpb.oem_name[5] >= 0x20 && dos33Bpb.oem_name[6] >= 0x20 && dos33Bpb.oem_name[7] >= 0x20; if (bitsInBpsFat32 == 1 && correctSpcFat32 && fat32Bpb.fats_no <= 2 && fat32Bpb.sectors == 0 && fat32Bpb.spfat == 0 && fat32Bpb.signature == 0x29 && Encoding.ASCII.GetString(fat32Bpb.fs_type) == "FAT32 ") { AaruConsole.DebugWriteLine("FAT plugin", "Using FAT32 BPB"); minBootNearJump = 0x58; return(BpbKind.LongFat32); } if (bitsInBpsFat32Short == 1 && correctSpcFat32Short && shortFat32Bpb.fats_no <= 2 && shortFat32Bpb.sectors == 0 && shortFat32Bpb.spfat == 0 && shortFat32Bpb.signature == 0x28) { AaruConsole.DebugWriteLine("FAT plugin", "Using short FAT32 BPB"); minBootNearJump = 0x57; return(BpbKind.ShortFat32); } if (bitsInBpsMsx == 1 && correctSpcMsx && msxBpb.fats_no <= 2 && msxBpb.root_ent > 0 && msxBpb.sectors <= (partition.End - partition.Start) + 1 && msxBpb.spfat > 0 && Encoding.ASCII.GetString(msxBpb.vol_id) == "VOL_ID") { AaruConsole.DebugWriteLine("FAT plugin", "Using MSX BPB"); useMsxBpb = true; } else if (bitsInBpsApricot == 1 && correctSpcApricot && apricotBpb.mainBPB.fats_no <= 2 && apricotBpb.mainBPB.root_ent > 0 && apricotBpb.mainBPB.sectors <= (partition.End - partition.Start) + 1 && apricotBpb.mainBPB.spfat > 0 && apricotBpb.partitionCount == 0) { AaruConsole.DebugWriteLine("FAT plugin", "Using Apricot BPB"); useApricotBpb = true; } else if (bitsInBpsDos40 == 1 && correctSpcDos40 && ebpb.fats_no <= 2 && ebpb.root_ent > 0 && ebpb.spfat > 0 && (ebpb.signature == 0x28 || ebpb.signature == 0x29 || andosOemCorrect)) { if (ebpb.sectors == 0) { if (ebpb.big_sectors <= (partition.End - partition.Start) + 1) { if (ebpb.signature == 0x29 || andosOemCorrect) { AaruConsole.DebugWriteLine("FAT plugin", "Using DOS 4.0 BPB"); useExtendedBpb = true; minBootNearJump = 0x3C; } else { AaruConsole.DebugWriteLine("FAT plugin", "Using DOS 3.4 BPB"); userShortExtendedBpb = true; minBootNearJump = 0x29; } } } else if (ebpb.sectors <= (partition.End - partition.Start) + 1) { if (ebpb.signature == 0x29 || andosOemCorrect) { AaruConsole.DebugWriteLine("FAT plugin", "Using DOS 4.0 BPB"); useExtendedBpb = true; minBootNearJump = 0x3C; } else { AaruConsole.DebugWriteLine("FAT plugin", "Using DOS 3.4 BPB"); userShortExtendedBpb = true; minBootNearJump = 0x29; } } } else if (bitsInBpsDos33 == 1 && correctSpcDos33 && dos33Bpb.rsectors < partition.End - partition.Start && dos33Bpb.fats_no <= 2 && dos33Bpb.root_ent > 0 && dos33Bpb.spfat > 0) { if (dos33Bpb.sectors == 0 && dos33Bpb.hsectors <= partition.Start && dos33Bpb.big_sectors > 0 && dos33Bpb.big_sectors <= (partition.End - partition.Start) + 1) { AaruConsole.DebugWriteLine("FAT plugin", "Using DOS 3.3 BPB"); useDos33Bpb = true; minBootNearJump = 0x22; } else if (dos33Bpb.big_sectors == 0 && dos33Bpb.hsectors <= partition.Start && dos33Bpb.sectors > 0 && dos33Bpb.sectors <= (partition.End - partition.Start) + 1) { if (atariBpb.jump[0] == 0x60 || (atariBpb.jump[0] == 0xE9 && atariBpb.jump[1] == 0x00 && Encoding.ASCII.GetString(dos33Bpb.oem_name) != "NEXT ")) { AaruConsole.DebugWriteLine("FAT plugin", "Using Atari BPB"); useAtariBpb = true; } else { AaruConsole.DebugWriteLine("FAT plugin", "Using DOS 3.3 BPB"); useDos33Bpb = true; minBootNearJump = 0x22; } } else { if (dos32Bpb.hsectors <= partition.Start && dos32Bpb.hsectors + dos32Bpb.sectors == dos32Bpb.total_sectors) { AaruConsole.DebugWriteLine("FAT plugin", "Using DOS 3.2 BPB"); useDos32Bpb = true; minBootNearJump = 0x1E; } else if (dos30Bpb.sptrk > 0 && dos30Bpb.sptrk < 64 && dos30Bpb.heads > 0 && dos30Bpb.heads < 256) { if (atariBpb.jump[0] == 0x60 || (atariBpb.jump[0] == 0xE9 && atariBpb.jump[1] == 0x00 && Encoding.ASCII.GetString(dos33Bpb.oem_name) != "NEXT ")) { AaruConsole.DebugWriteLine("FAT plugin", "Using Atari BPB"); useAtariBpb = true; } else { AaruConsole.DebugWriteLine("FAT plugin", "Using DOS 3.0 BPB"); useDos3Bpb = true; minBootNearJump = 0x1C; } } else { if (atariBpb.jump[0] == 0x60 || (atariBpb.jump[0] == 0xE9 && atariBpb.jump[1] == 0x00 && Encoding.ASCII.GetString(dos33Bpb.oem_name) != "NEXT ")) { AaruConsole.DebugWriteLine("FAT plugin", "Using Atari BPB"); useAtariBpb = true; } else { AaruConsole.DebugWriteLine("FAT plugin", "Using DOS 2.0 BPB"); useDos2Bpb = true; minBootNearJump = 0x16; } } } } } // DEC Rainbow, lacks a BPB but has a very concrete structure... if (imagePlugin.Info.Sectors == 800 && imagePlugin.Info.SectorSize == 512 && !useAtariBpb && !useMsxBpb && !useDos2Bpb && !useDos3Bpb && !useDos32Bpb && !useDos33Bpb && !userShortExtendedBpb && !useExtendedBpb && !useShortFat32 && !useLongFat32 && !useApricotBpb) { // DEC Rainbow boots up with a Z80, first byte should be DI (disable interrupts) byte z80Di = bpbSector[0]; // First FAT1 sector resides at LBA 0x14 byte[] fat1Sector0 = imagePlugin.ReadSector(0x14); // First FAT2 sector resides at LBA 0x1A byte[] fat2Sector0 = imagePlugin.ReadSector(0x1A); bool equalFatIds = fat1Sector0[0] == fat2Sector0[0] && fat1Sector0[1] == fat2Sector0[1]; // Volume is software interleaved 2:1 var rootMs = new MemoryStream(); foreach (byte[] tmp in from ulong rootSector in new[] { 0x17, 0x19, 0x1B, 0x1D, 0x1E, 0x20 } select imagePlugin.ReadSector(rootSector)) { rootMs.Write(tmp, 0, tmp.Length); } byte[] rootDir = rootMs.ToArray(); bool validRootDir = true; // Iterate all root directory for (int e = 0; e < 96 * 32; e += 32) { for (int c = 0; c < 11; c++) { if ((rootDir[c + e] < 0x20 && rootDir[c + e] != 0x00 && rootDir[c + e] != 0x05) || rootDir[c + e] == 0xFF || rootDir[c + e] == 0x2E) { validRootDir = false; break; } } if (!validRootDir) { break; } } if (z80Di == 0xF3 && equalFatIds && (fat1Sector0[0] & 0xF0) == 0xF0 && fat1Sector0[1] == 0xFF && validRootDir) { useDecRainbowBpb = true; AaruConsole.DebugWriteLine("FAT plugin", "Using DEC Rainbow hardcoded BPB."); fakeBpb.bps = 512; fakeBpb.spc = 1; fakeBpb.rsectors = 20; fakeBpb.fats_no = 2; fakeBpb.root_ent = 96; fakeBpb.sectors = 800; fakeBpb.media = 0xFA; fakeBpb.sptrk = 10; fakeBpb.heads = 1; fakeBpb.hsectors = 0; fakeBpb.spfat = 3; bootable = true; fakeBpb.boot_code = bpbSector; return(BpbKind.DecRainbow); } } if (!useAtariBpb && !useMsxBpb && !useDos2Bpb && !useDos3Bpb && !useDos32Bpb && !useDos33Bpb && !useHumanBpb && !userShortExtendedBpb && !useExtendedBpb && !useShortFat32 && !useLongFat32 && !useApricotBpb && !useDecRainbowBpb) { byte[] fatSector = imagePlugin.ReadSector(1 + partition.Start); switch (fatSector[0]) { case 0xE5: if (imagePlugin.Info.Sectors == 2002 && imagePlugin.Info.SectorSize == 128) { AaruConsole.DebugWriteLine("FAT plugin", "Using hardcoded BPB."); fakeBpb.bps = 128; fakeBpb.spc = 4; fakeBpb.rsectors = 1; fakeBpb.fats_no = 2; fakeBpb.root_ent = 64; fakeBpb.sectors = 2002; fakeBpb.media = 0xE5; fakeBpb.sptrk = 26; fakeBpb.heads = 1; fakeBpb.hsectors = 0; fakeBpb.spfat = 1; } break; case 0xFD: if (imagePlugin.Info.Sectors == 4004 && imagePlugin.Info.SectorSize == 128) { AaruConsole.DebugWriteLine("FAT plugin", "Using hardcoded BPB."); fakeBpb.bps = 128; fakeBpb.spc = 4; fakeBpb.rsectors = 4; fakeBpb.fats_no = 2; fakeBpb.root_ent = 68; fakeBpb.sectors = 4004; fakeBpb.media = 0xFD; fakeBpb.sptrk = 26; fakeBpb.heads = 2; fakeBpb.hsectors = 0; fakeBpb.spfat = 6; } else if (imagePlugin.Info.Sectors == 2002 && imagePlugin.Info.SectorSize == 128) { AaruConsole.DebugWriteLine("FAT plugin", "Using hardcoded BPB."); fakeBpb.bps = 128; fakeBpb.spc = 4; fakeBpb.rsectors = 4; fakeBpb.fats_no = 2; fakeBpb.root_ent = 68; fakeBpb.sectors = 2002; fakeBpb.media = 0xFD; fakeBpb.sptrk = 26; fakeBpb.heads = 1; fakeBpb.hsectors = 0; fakeBpb.spfat = 6; } break; case 0xFE: if (imagePlugin.Info.Sectors == 320 && imagePlugin.Info.SectorSize == 512) { AaruConsole.DebugWriteLine("FAT plugin", "Using hardcoded BPB for 5.25\" SSDD."); fakeBpb.bps = 512; fakeBpb.spc = 1; fakeBpb.rsectors = 1; fakeBpb.fats_no = 2; fakeBpb.root_ent = 64; fakeBpb.sectors = 320; fakeBpb.media = 0xFE; fakeBpb.sptrk = 8; fakeBpb.heads = 1; fakeBpb.hsectors = 0; fakeBpb.spfat = 1; } else if (imagePlugin.Info.Sectors == 2002 && imagePlugin.Info.SectorSize == 128) { AaruConsole.DebugWriteLine("FAT plugin", "Using hardcoded BPB."); fakeBpb.bps = 128; fakeBpb.spc = 4; fakeBpb.rsectors = 1; fakeBpb.fats_no = 2; fakeBpb.root_ent = 68; fakeBpb.sectors = 2002; fakeBpb.media = 0xFE; fakeBpb.sptrk = 26; fakeBpb.heads = 1; fakeBpb.hsectors = 0; fakeBpb.spfat = 6; } else if (imagePlugin.Info.Sectors == 1232 && imagePlugin.Info.SectorSize == 1024) { AaruConsole.DebugWriteLine("FAT plugin", "Using hardcoded BPB."); fakeBpb.bps = 1024; fakeBpb.spc = 1; fakeBpb.rsectors = 1; fakeBpb.fats_no = 2; fakeBpb.root_ent = 192; fakeBpb.sectors = 1232; fakeBpb.media = 0xFE; fakeBpb.sptrk = 8; fakeBpb.heads = 2; fakeBpb.hsectors = 0; fakeBpb.spfat = 2; } else if (imagePlugin.Info.Sectors == 616 && imagePlugin.Info.SectorSize == 1024) { AaruConsole.DebugWriteLine("FAT plugin", "Using hardcoded BPB."); fakeBpb.bps = 1024; fakeBpb.spc = 1; fakeBpb.rsectors = 1; fakeBpb.fats_no = 2; fakeBpb.root_ent = 6192; fakeBpb.sectors = 616; fakeBpb.media = 0xFE; fakeBpb.sptrk = 8; fakeBpb.heads = 2; fakeBpb.hsectors = 0; } else if (imagePlugin.Info.Sectors == 720 && imagePlugin.Info.SectorSize == 128) { AaruConsole.DebugWriteLine("FAT plugin", "Using hardcoded BPB."); fakeBpb.bps = 128; fakeBpb.spc = 2; fakeBpb.rsectors = 54; fakeBpb.fats_no = 2; fakeBpb.root_ent = 64; fakeBpb.sectors = 720; fakeBpb.media = 0xFE; fakeBpb.sptrk = 18; fakeBpb.heads = 1; fakeBpb.hsectors = 0; fakeBpb.spfat = 4; } else if (imagePlugin.Info.Sectors == 640 && imagePlugin.Info.SectorSize == 512) { AaruConsole.DebugWriteLine("FAT plugin", "Using hardcoded BPB for 5.25\" DSDD."); fakeBpb.bps = 512; fakeBpb.spc = 2; fakeBpb.rsectors = 1; fakeBpb.fats_no = 2; fakeBpb.root_ent = 112; fakeBpb.sectors = 640; fakeBpb.media = 0xFF; fakeBpb.sptrk = 8; fakeBpb.heads = 2; fakeBpb.hsectors = 0; fakeBpb.spfat = 1; } break; case 0xFF: if (imagePlugin.Info.Sectors == 640 && imagePlugin.Info.SectorSize == 512) { AaruConsole.DebugWriteLine("FAT plugin", "Using hardcoded BPB for 5.25\" DSDD."); fakeBpb.bps = 512; fakeBpb.spc = 2; fakeBpb.rsectors = 1; fakeBpb.fats_no = 2; fakeBpb.root_ent = 112; fakeBpb.sectors = 640; fakeBpb.media = 0xFF; fakeBpb.sptrk = 8; fakeBpb.heads = 2; fakeBpb.hsectors = 0; fakeBpb.spfat = 1; } break; } // This assumes a bootable sector will jump somewhere or disable interrupts in x86 code bootable |= bpbSector[0] == 0xFA || (bpbSector[0] == 0xEB && bpbSector[1] <= 0x7F) || (bpbSector[0] == 0xE9 && BitConverter.ToUInt16(bpbSector, 1) <= 0x1FC); fakeBpb.boot_code = bpbSector; return(BpbKind.Hardcoded); } if (useExtendedBpb) { fakeBpb = ebpb; return(BpbKind.Extended); } if (userShortExtendedBpb) { fakeBpb.jump = shortEbpb.jump; fakeBpb.oem_name = shortEbpb.oem_name; fakeBpb.bps = shortEbpb.bps; fakeBpb.spc = shortEbpb.spc; fakeBpb.rsectors = shortEbpb.rsectors; fakeBpb.fats_no = shortEbpb.fats_no; fakeBpb.root_ent = shortEbpb.root_ent; fakeBpb.sectors = shortEbpb.sectors; fakeBpb.media = shortEbpb.media; fakeBpb.spfat = shortEbpb.spfat; fakeBpb.sptrk = shortEbpb.sptrk; fakeBpb.heads = shortEbpb.heads; fakeBpb.hsectors = shortEbpb.hsectors; fakeBpb.big_sectors = shortEbpb.big_sectors; fakeBpb.drive_no = shortEbpb.drive_no; fakeBpb.flags = shortEbpb.flags; fakeBpb.signature = shortEbpb.signature; fakeBpb.serial_no = shortEbpb.serial_no; fakeBpb.boot_code = shortEbpb.boot_code; fakeBpb.boot_signature = shortEbpb.boot_signature; return(BpbKind.ShortExtended); } if (useDos33Bpb) { fakeBpb.jump = dos33Bpb.jump; fakeBpb.oem_name = dos33Bpb.oem_name; fakeBpb.bps = dos33Bpb.bps; fakeBpb.spc = dos33Bpb.spc; fakeBpb.rsectors = dos33Bpb.rsectors; fakeBpb.fats_no = dos33Bpb.fats_no; fakeBpb.root_ent = dos33Bpb.root_ent; fakeBpb.sectors = dos33Bpb.sectors; fakeBpb.media = dos33Bpb.media; fakeBpb.spfat = dos33Bpb.spfat; fakeBpb.sptrk = dos33Bpb.sptrk; fakeBpb.heads = dos33Bpb.heads; fakeBpb.hsectors = dos33Bpb.hsectors; fakeBpb.big_sectors = dos33Bpb.big_sectors; fakeBpb.boot_code = dos33Bpb.boot_code; fakeBpb.boot_signature = dos33Bpb.boot_signature; return(BpbKind.Dos33); } if (useDos32Bpb) { fakeBpb.jump = dos32Bpb.jump; fakeBpb.oem_name = dos32Bpb.oem_name; fakeBpb.bps = dos32Bpb.bps; fakeBpb.spc = dos32Bpb.spc; fakeBpb.rsectors = dos32Bpb.rsectors; fakeBpb.fats_no = dos32Bpb.fats_no; fakeBpb.root_ent = dos32Bpb.root_ent; fakeBpb.sectors = dos32Bpb.sectors; fakeBpb.media = dos32Bpb.media; fakeBpb.spfat = dos32Bpb.spfat; fakeBpb.sptrk = dos32Bpb.sptrk; fakeBpb.heads = dos32Bpb.heads; fakeBpb.hsectors = dos32Bpb.hsectors; fakeBpb.boot_code = dos32Bpb.boot_code; fakeBpb.boot_signature = dos32Bpb.boot_signature; return(BpbKind.Dos32); } if (useDos3Bpb) { fakeBpb.jump = dos30Bpb.jump; fakeBpb.oem_name = dos30Bpb.oem_name; fakeBpb.bps = dos30Bpb.bps; fakeBpb.spc = dos30Bpb.spc; fakeBpb.rsectors = dos30Bpb.rsectors; fakeBpb.fats_no = dos30Bpb.fats_no; fakeBpb.root_ent = dos30Bpb.root_ent; fakeBpb.sectors = dos30Bpb.sectors; fakeBpb.media = dos30Bpb.media; fakeBpb.spfat = dos30Bpb.spfat; fakeBpb.sptrk = dos30Bpb.sptrk; fakeBpb.heads = dos30Bpb.heads; fakeBpb.hsectors = dos30Bpb.hsectors; fakeBpb.boot_code = dos30Bpb.boot_code; fakeBpb.boot_signature = dos30Bpb.boot_signature; return(BpbKind.Dos3); } if (useDos2Bpb) { fakeBpb.jump = dos2Bpb.jump; fakeBpb.oem_name = dos2Bpb.oem_name; fakeBpb.bps = dos2Bpb.bps; fakeBpb.spc = dos2Bpb.spc; fakeBpb.rsectors = dos2Bpb.rsectors; fakeBpb.fats_no = dos2Bpb.fats_no; fakeBpb.root_ent = dos2Bpb.root_ent; fakeBpb.sectors = dos2Bpb.sectors; fakeBpb.media = dos2Bpb.media; fakeBpb.spfat = dos2Bpb.spfat; fakeBpb.boot_code = dos2Bpb.boot_code; fakeBpb.boot_signature = dos2Bpb.boot_signature; return(BpbKind.Dos2); } if (useMsxBpb) { fakeBpb.jump = msxBpb.jump; fakeBpb.oem_name = msxBpb.oem_name; fakeBpb.bps = msxBpb.bps; fakeBpb.spc = msxBpb.spc; fakeBpb.rsectors = msxBpb.rsectors; fakeBpb.fats_no = msxBpb.fats_no; fakeBpb.root_ent = msxBpb.root_ent; fakeBpb.sectors = msxBpb.sectors; fakeBpb.media = msxBpb.media; fakeBpb.spfat = msxBpb.spfat; fakeBpb.sptrk = msxBpb.sptrk; fakeBpb.heads = msxBpb.heads; fakeBpb.hsectors = msxBpb.hsectors; fakeBpb.boot_code = msxBpb.boot_code; fakeBpb.boot_signature = msxBpb.boot_signature; fakeBpb.serial_no = msxBpb.serial_no; // TODO: Is there any way to check this? bootable = true; return(BpbKind.Msx); } if (useAtariBpb) { fakeBpb.jump = atariBpb.jump; fakeBpb.oem_name = atariBpb.oem_name; fakeBpb.bps = atariBpb.bps; fakeBpb.spc = atariBpb.spc; fakeBpb.rsectors = atariBpb.rsectors; fakeBpb.fats_no = atariBpb.fats_no; fakeBpb.root_ent = atariBpb.root_ent; fakeBpb.sectors = atariBpb.sectors; fakeBpb.media = atariBpb.media; fakeBpb.spfat = atariBpb.spfat; fakeBpb.sptrk = atariBpb.sptrk; fakeBpb.heads = atariBpb.heads; fakeBpb.boot_code = atariBpb.boot_code; return(BpbKind.Atari); } if (useApricotBpb) { fakeBpb.bps = apricotBpb.mainBPB.bps; fakeBpb.spc = apricotBpb.mainBPB.spc; fakeBpb.rsectors = apricotBpb.mainBPB.rsectors; fakeBpb.fats_no = apricotBpb.mainBPB.fats_no; fakeBpb.root_ent = apricotBpb.mainBPB.root_ent; fakeBpb.sectors = apricotBpb.mainBPB.sectors; fakeBpb.media = apricotBpb.mainBPB.media; fakeBpb.spfat = apricotBpb.mainBPB.spfat; fakeBpb.sptrk = apricotBpb.spt; bootable = apricotBpb.bootType > 0; if (apricotBpb.bootLocation > 0 && apricotBpb.bootLocation + apricotBpb.bootSize < imagePlugin.Info.Sectors) { fakeBpb.boot_code = imagePlugin.ReadSectors(apricotBpb.bootLocation, (uint)(apricotBpb.sectorSize * apricotBpb.bootSize) / imagePlugin.Info.SectorSize); } return(BpbKind.Apricot); } return(BpbKind.None); }
public bool GetInformation(IMediaImage imagePlugin, out List <Partition> partitions, ulong sectorOffset) { partitions = new List <Partition>(); // I think Apricot can't chain partitions so. if (sectorOffset != 0) { return(false); } byte[] sector = imagePlugin.ReadSector(0); if (sector.Length < 512) { return(false); } ApricotLabel label = Marshal.ByteArrayToStructureLittleEndian <ApricotLabel>(sector); // Not much to check but... ulong deviceSectors = imagePlugin.Info.Sectors; ulong deviceSizeAccordingToLabel = label.cylinders * label.heads * label.spt; if (label.operatingSystem > 4 || label.bootType > 5 || label.partitionCount > 8 || deviceSizeAccordingToLabel > deviceSectors || label.firstDataBlock > deviceSectors) { return(false); } DicConsole.DebugWriteLine("Apricot partitions", "label.version = \"{0}\"", StringHandlers.CToString(label.version)); DicConsole.DebugWriteLine("Apricot partitions", "label.operatingSystem = {0} ({1})", label.operatingSystem, label.operatingSystem < operatingSystemCodes.Length ? operatingSystemCodes[label.operatingSystem] : "Unknown"); DicConsole.DebugWriteLine("Apricot partitions", "label.writeProtected = {0}", label.writeProtected); DicConsole.DebugWriteLine("Apricot partitions", "label.copyProtected = {0}", label.copyProtected); DicConsole.DebugWriteLine("Apricot partitions", "label.bootType = {0} ({1})", label.bootType, label.bootType < bootTypeCodes.Length ? bootTypeCodes[label.bootType] : "Unknown"); DicConsole.DebugWriteLine("Apricot partitions", "label.partitionCount = {0}", label.partitionCount); DicConsole.DebugWriteLine("Apricot partitions", "label.winchester = {0}", label.winchester); DicConsole.DebugWriteLine("Apricot partitions", "label.sectorSize = {0}", label.sectorSize); DicConsole.DebugWriteLine("Apricot partitions", "label.spt = {0}", label.spt); DicConsole.DebugWriteLine("Apricot partitions", "label.cylinders = {0}", label.cylinders); DicConsole.DebugWriteLine("Apricot partitions", "label.heads = {0}", label.heads); DicConsole.DebugWriteLine("Apricot partitions", "label.interleave = {0}", label.interleave); DicConsole.DebugWriteLine("Apricot partitions", "label.skew = {0}", label.skew); DicConsole.DebugWriteLine("Apricot partitions", "label.bootLocation = {0}", label.bootLocation); DicConsole.DebugWriteLine("Apricot partitions", "label.bootSize = {0}", label.bootSize); DicConsole.DebugWriteLine("Apricot partitions", "label.bootAddress = 0x{0:X8}", label.bootAddress); DicConsole.DebugWriteLine("Apricot partitions", "label.bootOffset:label.bootSegment = {0:X4}:{1:X4}", label.bootOffset, label.bootSegment); DicConsole.DebugWriteLine("Apricot partitions", "label.firstDataBlock = {0}", label.firstDataBlock); DicConsole.DebugWriteLine("Apricot partitions", "label.generation = {0}", label.generation); DicConsole.DebugWriteLine("Apricot partitions", "label.copyCount = {0}", label.copyCount); DicConsole.DebugWriteLine("Apricot partitions", "label.maxCopies = {0}", label.maxCopies); DicConsole.DebugWriteLine("Apricot partitions", "label.serialNumber = \"{0}\"", StringHandlers.CToString(label.serialNumber)); DicConsole.DebugWriteLine("Apricot partitions", "label.partNumber = \"{0}\"", StringHandlers.CToString(label.partNumber)); DicConsole.DebugWriteLine("Apricot partitions", "label.copyright = \"{0}\"", StringHandlers.CToString(label.copyright)); DicConsole.DebugWriteLine("Apricot partitions", "label.mainBPB.bps = {0}", label.mainBPB.bps); DicConsole.DebugWriteLine("Apricot partitions", "label.mainBPB.spc = {0}", label.mainBPB.spc); DicConsole.DebugWriteLine("Apricot partitions", "label.mainBPB.rsectors = {0}", label.mainBPB.rsectors); DicConsole.DebugWriteLine("Apricot partitions", "label.mainBPB.fats_no = {0}", label.mainBPB.fats_no); DicConsole.DebugWriteLine("Apricot partitions", "label.mainBPB.root_ent = {0}", label.mainBPB.root_ent); DicConsole.DebugWriteLine("Apricot partitions", "label.mainBPB.sectors = {0}", label.mainBPB.sectors); DicConsole.DebugWriteLine("Apricot partitions", "label.mainBPB.media = {0}", label.mainBPB.media); DicConsole.DebugWriteLine("Apricot partitions", "label.mainBPB.spfat = {0}", label.mainBPB.spfat); DicConsole.DebugWriteLine("Apricot partitions", "label.mainBPB.diskType = {0} ({1})", label.mainBPB.diskType, label.mainBPB.diskType < diskTypeCodes.Length ? diskTypeCodes[label.mainBPB.diskType] : "Unknown"); DicConsole.DebugWriteLine("Apricot partitions", "label.mainBPB.startSector = {0}", label.mainBPB.startSector); DicConsole.DebugWriteLine("Apricot partitions", "label.fontName = \"{0}\"", StringHandlers.CToString(label.fontName)); DicConsole.DebugWriteLine("Apricot partitions", "label.keyboardName = \"{0}\"", StringHandlers.CToString(label.keyboardName)); DicConsole.DebugWriteLine("Apricot partitions", "label.biosMajorVersion = {0}", label.biosMajorVersion); DicConsole.DebugWriteLine("Apricot partitions", "label.biosMinorVersion = {0}", label.biosMinorVersion); DicConsole.DebugWriteLine("Apricot partitions", "label.diagnosticsFlag = {0}", label.diagnosticsFlag); DicConsole.DebugWriteLine("Apricot partitions", "label.prnDevice = {0} ({1})", label.prnDevice, label.prnDevice < printDevices.Length ? printDevices[label.prnDevice] : "Unknown"); DicConsole.DebugWriteLine("Apricot partitions", "label.bellVolume = {0}", label.bellVolume); DicConsole.DebugWriteLine("Apricot partitions", "label.enableCache = {0}", label.enableCache); DicConsole.DebugWriteLine("Apricot partitions", "label.enableGraphics = {0}", label.enableGraphics); DicConsole.DebugWriteLine("Apricot partitions", "label.dosLength = {0}", label.dosLength); DicConsole.DebugWriteLine("Apricot partitions", "label.fontLength = {0}", label.fontLength); DicConsole.DebugWriteLine("Apricot partitions", "label.keyboardLength = {0}", label.keyboardLength); DicConsole.DebugWriteLine("Apricot partitions", "label.dosStart = {0}", label.dosStart); DicConsole.DebugWriteLine("Apricot partitions", "label.fontStart = {0}", label.fontStart); DicConsole.DebugWriteLine("Apricot partitions", "label.keyboardStart = {0}", label.keyboardStart); DicConsole.DebugWriteLine("Apricot partitions", "label.keyboardVolume = {0}", label.keyboardVolume); DicConsole.DebugWriteLine("Apricot partitions", "label.autorepeat = {0}", label.autorepeat); DicConsole.DebugWriteLine("Apricot partitions", "label.autorepeatLeadIn = {0}", label.autorepeatLeadIn); DicConsole.DebugWriteLine("Apricot partitions", "label.autorepeatInterval = {0}", label.autorepeatInterval); DicConsole.DebugWriteLine("Apricot partitions", "label.microscreenMode = {0}", label.microscreenMode); DicConsole.DebugWriteLine("Apricot partitions", "label.spareKeyboard is null? = {0}", ArrayHelpers.ArrayIsNullOrEmpty(label.spareKeyboard)); DicConsole.DebugWriteLine("Apricot partitions", "label.lineMode = {0} ({1} lines)", label.lineMode, label.lineMode < lineModes.Length ? lineModes[label.lineMode] : 0); DicConsole.DebugWriteLine("Apricot partitions", "label.lineWidth = {0} ({1} columns)", label.lineWidth, label.lineWidth < lineWidths.Length ? lineWidths[label.lineWidth] : 0); DicConsole.DebugWriteLine("Apricot partitions", "label.imageOff = {0}", label.imageOff); DicConsole.DebugWriteLine("Apricot partitions", "label.spareScreen is null? = {0}", ArrayHelpers.ArrayIsNullOrEmpty(label.spareScreen)); DicConsole.DebugWriteLine("Apricot partitions", "label.txBaudRate = {0} ({1} bps)", label.txBaudRate, label.txBaudRate < baudRates.Length ? baudRates[label.txBaudRate] : 0); DicConsole.DebugWriteLine("Apricot partitions", "label.rxBaudRate = {0} ({1} bps)", label.rxBaudRate, label.rxBaudRate < baudRates.Length ? baudRates[label.rxBaudRate] : 0); DicConsole.DebugWriteLine("Apricot partitions", "label.txBits = {0}", label.txBits); DicConsole.DebugWriteLine("Apricot partitions", "label.rxBits = {0}", label.rxBits); DicConsole.DebugWriteLine("Apricot partitions", "label.stopBits = {0} ({1} bits)", label.stopBits, label.stopBits < stopBits.Length ? stopBits[label.stopBits] : 0); DicConsole.DebugWriteLine("Apricot partitions", "label.parityCheck = {0}", label.parityCheck); DicConsole.DebugWriteLine("Apricot partitions", "label.parityType = {0} ({1})", label.parityType, label.parityType < parityTypes.Length ? parityTypes[label.parityType] : "Unknown"); DicConsole.DebugWriteLine("Apricot partitions", "label.txXonXoff = {0}", label.txXonXoff); DicConsole.DebugWriteLine("Apricot partitions", "label.rxXonXoff = {0}", label.rxXonXoff); DicConsole.DebugWriteLine("Apricot partitions", "label.xonCharacter = {0}", label.xonCharacter); DicConsole.DebugWriteLine("Apricot partitions", "label.xoffCharacter = {0}", label.xoffCharacter); DicConsole.DebugWriteLine("Apricot partitions", "label.rxXonXoffBuffer = {0}", label.rxXonXoffBuffer); DicConsole.DebugWriteLine("Apricot partitions", "label.dtrDsr = {0}", label.dtrDsr); DicConsole.DebugWriteLine("Apricot partitions", "label.ctsRts = {0}", label.ctsRts); DicConsole.DebugWriteLine("Apricot partitions", "label.nullsAfterCr = {0}", label.nullsAfterCr); DicConsole.DebugWriteLine("Apricot partitions", "label.nullsAfterFF = {0}", label.nullsAfterFF); DicConsole.DebugWriteLine("Apricot partitions", "label.lfAfterCRSerial = {0}", label.lfAfterCRSerial); DicConsole.DebugWriteLine("Apricot partitions", "label.biosErrorReportSerial = {0}", label.biosErrorReportSerial); DicConsole.DebugWriteLine("Apricot partitions", "label.spareSerial is null? = {0}", ArrayHelpers.ArrayIsNullOrEmpty(label.spareSerial)); DicConsole.DebugWriteLine("Apricot partitions", "label.lfAfterCrParallel = {0}", label.lfAfterCrParallel); DicConsole.DebugWriteLine("Apricot partitions", "label.selectLine = {0}", label.selectLine); DicConsole.DebugWriteLine("Apricot partitions", "label.paperEmpty = {0}", label.paperEmpty); DicConsole.DebugWriteLine("Apricot partitions", "label.faultLine = {0}", label.faultLine); DicConsole.DebugWriteLine("Apricot partitions", "label.biosErrorReportParallel = {0}", label.biosErrorReportParallel); DicConsole.DebugWriteLine("Apricot partitions", "label.spareParallel is null? = {0}", ArrayHelpers.ArrayIsNullOrEmpty(label.spareParallel)); DicConsole.DebugWriteLine("Apricot partitions", "label.spareWinchester is null? = {0}", ArrayHelpers.ArrayIsNullOrEmpty(label.spareWinchester)); DicConsole.DebugWriteLine("Apricot partitions", "label.parkingEnabled = {0}", label.parkingEnabled); DicConsole.DebugWriteLine("Apricot partitions", "label.formatProtection = {0}", label.formatProtection); DicConsole.DebugWriteLine("Apricot partitions", "label.spareRamDisk is null? = {0}", ArrayHelpers.ArrayIsNullOrEmpty(label.spareRamDisk)); for (int i = 0; i < 32; i++) { DicConsole.DebugWriteLine("Apricot partitions", "label.badBlocks[{1}] = {0}", label.badBlocks[i], i); } for (int i = 0; i < 8; i++) { DicConsole.DebugWriteLine("Apricot partitions", "label.partitions[{1}].bps = {0}", label.partitions[i].bps, i); DicConsole.DebugWriteLine("Apricot partitions", "label.partitions[{1}].spc = {0}", label.partitions[i].spc, i); DicConsole.DebugWriteLine("Apricot partitions", "label.partitions[{1}].rsectors = {0}", label.partitions[i].rsectors, i); DicConsole.DebugWriteLine("Apricot partitions", "label.partitions[{1}].fats_no = {0}", label.partitions[i].fats_no, i); DicConsole.DebugWriteLine("Apricot partitions", "label.partitions[{1}].root_ent = {0}", label.partitions[i].root_ent, i); DicConsole.DebugWriteLine("Apricot partitions", "label.partitions[{1}].sectors = {0}", label.partitions[i].sectors, i); DicConsole.DebugWriteLine("Apricot partitions", "label.partitions[{1}].media = {0}", label.partitions[i].media, i); DicConsole.DebugWriteLine("Apricot partitions", "label.partitions[{1}].spfat = {0}", label.partitions[i].spfat, i); DicConsole.DebugWriteLine("Apricot partitions", "label.partitions[{1}].diskType = {0} ({2})", label.partitions[i].diskType, i, label.partitions[i].diskType < diskTypeCodes.Length ? diskTypeCodes[label.partitions[i].diskType] : "Unknown"); DicConsole.DebugWriteLine("Apricot partitions", "label.partitions[{1}].startSector = {0}", label.partitions[i].startSector, i); } DicConsole.DebugWriteLine("Apricot partitions", "label.spare is null? = {0}", ArrayHelpers.ArrayIsNullOrEmpty(label.spare)); DicConsole.DebugWriteLine("Apricot partitions", "label.cpmDoubleSided = {0}", label.cpmDoubleSided); // Only hard disks can contain partitions if (!label.winchester) { return(false); } for (byte i = 0; i < label.partitionCount; i++) { Partition part = new Partition { Start = label.partitions[i].startSector, Size = (ulong)(label.partitions[i].sectors * label.sectorSize), Length = label.partitions[i].sectors, Type = "ACT Apricot partition", Sequence = i, Scheme = Name, Offset = (ulong)(label.partitions[i].startSector * label.sectorSize) }; if (part.Start < deviceSectors && part.End < deviceSectors) { partitions.Add(part); } } return(partitions.Count > 0); }