// /*************************************************************************** // Aaru Data Preservation Suite // ---------------------------------------------------------------------------- // // Filename : BPB.cs // Author(s) : Natalia Portillo // // Component : Microsoft FAT filesystem plugin. // // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation; either version 2.1 of the // License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, see . // // ---------------------------------------------------------------------------- // Copyright © 2011-2025 Natalia Portillo // ****************************************************************************/ using System; using System.IO; using System.Text; using Aaru.CommonTypes; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.Helpers; using Aaru.Logging; namespace Aaru.Filesystems; public sealed partial class FAT { 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(bpbSector); atariBpb = Marshal.ByteArrayToStructureLittleEndian(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; AaruLogging.Debug(MODULE_NAME, "humanClustersCorrect = {0}", humanClustersCorrect); AaruLogging.Debug(MODULE_NAME, "humanOemCorrect = {0}", humanOemCorrect); AaruLogging.Debug(MODULE_NAME, "humanBranchCorrect = {0}", humanBranchCorrect); // If all Human68k checks are correct, it is a Human68k FAT16 bool useHumanBpb = humanClustersCorrect && humanOemCorrect && humanBranchCorrect && expectedClusters > 0; if(useHumanBpb) { AaruLogging.Debug(MODULE_NAME, Localization.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(); var useAtariBpb = false; var useMsxBpb = false; var useDos2Bpb = false; var useDos3Bpb = false; var useDos32Bpb = false; var useDos33Bpb = false; var userShortExtendedBpb = false; var useExtendedBpb = false; var useApricotBpb = false; if(imagePlugin.Info.SectorSize >= 256) { msxBpb = Marshal.ByteArrayToStructureLittleEndian(bpbSector); dos2Bpb = Marshal.ByteArrayToStructureLittleEndian(bpbSector); dos30Bpb = Marshal.ByteArrayToStructureLittleEndian(bpbSector); dos32Bpb = Marshal.ByteArrayToStructureLittleEndian(bpbSector); dos33Bpb = Marshal.ByteArrayToStructureLittleEndian(bpbSector); shortEbpb = Marshal.ByteArrayToStructureLittleEndian(bpbSector); ebpb = Marshal.ByteArrayToStructureLittleEndian(bpbSector); Fat32ParameterBlockShort shortFat32Bpb = Marshal.ByteArrayToStructureLittleEndian(bpbSector); Fat32ParameterBlock fat32Bpb = Marshal.ByteArrayToStructureLittleEndian(bpbSector); apricotBpb = Marshal.ByteArrayToStructureLittleEndian(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 is 1 or 2 or 4 or 8 or 16 or 32 or 64; bool correctSpcDos33 = dos33Bpb.spc is 1 or 2 or 4 or 8 or 16 or 32 or 64; bool correctSpcDos40 = ebpb.spc is 1 or 2 or 4 or 8 or 16 or 32 or 64; bool correctSpcFat32Short = shortFat32Bpb.spc is 1 or 2 or 4 or 8 or 16 or 32 or 64; bool correctSpcFat32 = fat32Bpb.spc is 1 or 2 or 4 or 8 or 16 or 32 or 64; bool correctSpcApricot = apricotBpb.mainBPB.spc is 1 or 2 or 4 or 8 or 16 or 32 or 64; // This is to support FAT partitions on hybrid ISO/USB images if(imagePlugin.Info.MetadataMediaType == MetadataMediaType.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 is { spfat: 0, signature: 0x29 } && Encoding.ASCII.GetString(fat32Bpb.fs_type) == "FAT32 ") { AaruLogging.Debug(MODULE_NAME, Localization.Using_FAT32_BPB); minBootNearJump = 0x58; return BpbKind.LongFat32; } if(bitsInBpsFat32Short == 1 && correctSpcFat32Short && shortFat32Bpb is { fats_no: <= 2, sectors: 0 } and { spfat: 0, signature: 0x28 }) { AaruLogging.Debug(MODULE_NAME, Localization.Using_short_FAT32_BPB); minBootNearJump = 0x57; return BpbKind.ShortFat32; } if(bitsInBpsMsx == 1 && correctSpcMsx && msxBpb is { fats_no: <= 2, root_ent: > 0 } && msxBpb.sectors <= partition.End - partition.Start + 1 && msxBpb.spfat > 0 && Encoding.ASCII.GetString(msxBpb.vol_id) == "VOL_ID") { AaruLogging.Debug(MODULE_NAME, Localization.Using_MSX_BPB); useMsxBpb = true; } else if(bitsInBpsApricot == 1 && correctSpcApricot && apricotBpb.mainBPB is { fats_no: <= 2, root_ent: > 0 } && apricotBpb.mainBPB.sectors <= partition.End - partition.Start + 1 && apricotBpb.mainBPB.spfat > 0 && apricotBpb.partitionCount == 0) { AaruLogging.Debug(MODULE_NAME, Localization.Using_Apricot_BPB); useApricotBpb = true; } else if(bitsInBpsDos40 == 1 && correctSpcDos40 && ebpb.fats_no <= 2 && ebpb is { root_ent: > 0, spfat: > 0 } && (ebpb.signature is 0x28 or 0x29 || andosOemCorrect)) { if(ebpb.sectors == 0) { if(ebpb.big_sectors <= partition.End - partition.Start + 1) { if(ebpb.signature == 0x29 || andosOemCorrect) { AaruLogging.Debug(MODULE_NAME, Localization.Using_DOS_4_0_BPB); useExtendedBpb = true; minBootNearJump = 0x3C; } else { AaruLogging.Debug(MODULE_NAME, Localization.Using_DOS_3_4_BPB); userShortExtendedBpb = true; minBootNearJump = 0x29; } } } else if(ebpb.sectors <= partition.End - partition.Start + 1) { if(ebpb.signature == 0x29 || andosOemCorrect) { AaruLogging.Debug(MODULE_NAME, Localization.Using_DOS_4_0_BPB); useExtendedBpb = true; minBootNearJump = 0x3C; } else { AaruLogging.Debug(MODULE_NAME, Localization.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 is { root_ent: > 0, spfat: > 0 }) { if(dos33Bpb.sectors == 0 && dos33Bpb.hsectors <= partition.Start && dos33Bpb.big_sectors > 0 && dos33Bpb.big_sectors <= partition.End - partition.Start + 1) { AaruLogging.Debug(MODULE_NAME, Localization.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 " || partition.Type is "GEM" or "BGM") { AaruLogging.Debug(MODULE_NAME, Localization.Using_Atari_BPB); useAtariBpb = true; } else { AaruLogging.Debug(MODULE_NAME, Localization.Using_DOS_3_3_BPB); useDos33Bpb = true; minBootNearJump = 0x22; } } else { if(dos32Bpb.hsectors <= partition.Start && dos32Bpb.hsectors + dos32Bpb.sectors == dos32Bpb.total_sectors) { AaruLogging.Debug(MODULE_NAME, Localization.Using_DOS_3_2_BPB); useDos32Bpb = true; minBootNearJump = 0x1E; } else if(dos30Bpb.sptrk is > 0 and < 64 && dos30Bpb.heads is > 0 and < 256) { if(atariBpb.jump[0] == 0x60 || atariBpb.jump[0] == 0xE9 && atariBpb.jump[1] == 0x00 && Encoding.ASCII.GetString(dos33Bpb.oem_name) != "NEXT ") { AaruLogging.Debug(MODULE_NAME, Localization.Using_Atari_BPB); useAtariBpb = true; } else { AaruLogging.Debug(MODULE_NAME, Localization.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 ") { AaruLogging.Debug(MODULE_NAME, Localization.Using_Atari_BPB); useAtariBpb = true; } else { AaruLogging.Debug(MODULE_NAME, Localization.Using_DOS_2_0_BPB); useDos2Bpb = true; minBootNearJump = 0x16; } } } } } // DEC Rainbow, lacks a BPB but has a very concrete structure... if(imagePlugin.Info is { Sectors: 800, SectorSize: 512 } && !useAtariBpb && !useMsxBpb && !useDos2Bpb && !useDos3Bpb && !useDos32Bpb && !useDos33Bpb && !userShortExtendedBpb && !useExtendedBpb && !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 imagePlugin.ReadSector(0x14, false, out byte[] fat1Sector0, out _); // First FAT2 sector resides at LBA 0x1A imagePlugin.ReadSector(0x1A, false, out byte[] fat2Sector0, out _); bool equalFatIds = fat1Sector0[0] == fat2Sector0[0] && fat1Sector0[1] == fat2Sector0[1]; // Volume is software interleaved 2:1 var rootMs = new MemoryStream(); foreach(ulong rootSector in new ulong[] { 0x17, 0x19, 0x1B, 0x1D, 0x1E, 0x20 }) { imagePlugin.ReadSector(rootSector, false, out byte[] tmp, out _); rootMs.Write(tmp, 0, tmp.Length); } byte[] rootDir = rootMs.ToArray(); var validRootDir = true; // Iterate all root directory for(var e = 0; e < 96 * 32; e += 32) { for(var 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) continue; validRootDir = false; break; } if(!validRootDir) break; } if(z80Di == 0xF3 && equalFatIds && (fat1Sector0[0] & 0xF0) == 0xF0 && fat1Sector0[1] == 0xFF && validRootDir) { AaruLogging.Debug(MODULE_NAME, Localization.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 && !useApricotBpb) { imagePlugin.ReadSector(1 + partition.Start, false, out byte[] fatSector, out _); switch(fatSector[0]) { case 0xE5: if(imagePlugin.Info is { Sectors: 2002, SectorSize: 128 }) { AaruLogging.Debug(MODULE_NAME, Localization.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: switch(imagePlugin.Info.Sectors) { case 4004 when imagePlugin.Info.SectorSize == 128: AaruLogging.Debug(MODULE_NAME, Localization.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; break; case 2002 when imagePlugin.Info.SectorSize == 128: AaruLogging.Debug(MODULE_NAME, Localization.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; } break; case 0xFE: switch(imagePlugin.Info.Sectors) { case 320 when imagePlugin.Info.SectorSize == 512: AaruLogging.Debug(MODULE_NAME, Localization.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; break; case 2002 when imagePlugin.Info.SectorSize == 128: AaruLogging.Debug(MODULE_NAME, Localization.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; break; case 1232 when imagePlugin.Info.SectorSize == 1024: AaruLogging.Debug(MODULE_NAME, Localization.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; break; case 616 when imagePlugin.Info.SectorSize == 1024: AaruLogging.Debug(MODULE_NAME, Localization.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; break; case 720 when imagePlugin.Info.SectorSize == 128: AaruLogging.Debug(MODULE_NAME, Localization.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; break; case 640 when imagePlugin.Info.SectorSize == 512: AaruLogging.Debug(MODULE_NAME, Localization.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; } break; case 0xFF: if(imagePlugin.Info is { Sectors: 640, SectorSize: 512 }) { AaruLogging.Debug(MODULE_NAME, Localization.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) return BpbKind.None; 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) { imagePlugin.ReadSectors(apricotBpb.bootLocation, false, (uint)(apricotBpb.sectorSize * apricotBpb.bootSize) / imagePlugin.Info.SectorSize, out fakeBpb.boot_code, out _); } return BpbKind.Apricot; } }