示例#1
0
        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);
        }
示例#2
0
        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);
        }