Example #1
0
        // TODO: BBC Master hard disks are untested...
        public bool Identify(IMediaImage imagePlugin, Partition partition)
        {
            if (partition.Start >= partition.End)
            {
                return(false);
            }

            ulong sbSector;
            uint  sectorsToRead;

            if (imagePlugin.Info.SectorSize < 256)
            {
                return(false);
            }

            byte[]   sector;
            GCHandle ptr;

            // ADFS-S, ADFS-M, ADFS-L, ADFS-D without partitions
            if (partition.Start == 0)
            {
                sector = imagePlugin.ReadSector(0);
                byte oldChk0 = AcornMapChecksum(sector, 255);
                ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
                OldMapSector0 oldMap0 =
                    (OldMapSector0)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldMapSector0));

                sector = imagePlugin.ReadSector(1);
                byte oldChk1 = AcornMapChecksum(sector, 255);
                ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
                OldMapSector1 oldMap1 =
                    (OldMapSector1)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldMapSector1));

                DicConsole.DebugWriteLine("ADFS Plugin", "oldMap0.checksum = {0}", oldMap0.checksum);
                DicConsole.DebugWriteLine("ADFS Plugin", "oldChk0 = {0}", oldChk0);

                // According to documentation map1 MUST start on sector 1. On ADFS-D it starts at 0x100, not on sector 1 (0x400)
                if (oldMap0.checksum == oldChk0 && oldMap1.checksum != oldChk1 && sector.Length >= 512)
                {
                    sector = imagePlugin.ReadSector(0);
                    byte[] tmp = new byte[256];
                    Array.Copy(sector, 256, tmp, 0, 256);
                    oldChk1 = AcornMapChecksum(tmp, 255);
                    ptr     = GCHandle.Alloc(tmp, GCHandleType.Pinned);
                    oldMap1 = (OldMapSector1)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldMapSector1));
                }

                DicConsole.DebugWriteLine("ADFS Plugin", "oldMap1.checksum = {0}", oldMap1.checksum);
                DicConsole.DebugWriteLine("ADFS Plugin", "oldChk1 = {0}", oldChk1);

                if (oldMap0.checksum == oldChk0 && oldMap1.checksum == oldChk1 && oldMap0.checksum != 0 &&
                    oldMap1.checksum != 0)
                {
                    sbSector      = OLD_DIRECTORY_LOCATION / imagePlugin.Info.SectorSize;
                    sectorsToRead = OLD_DIRECTORY_SIZE / imagePlugin.Info.SectorSize;
                    if (OLD_DIRECTORY_SIZE % imagePlugin.Info.SectorSize > 0)
                    {
                        sectorsToRead++;
                    }

                    sector = imagePlugin.ReadSectors(sbSector, sectorsToRead);
                    if (sector.Length > OLD_DIRECTORY_SIZE)
                    {
                        byte[] tmp = new byte[OLD_DIRECTORY_SIZE];
                        Array.Copy(sector, 0, tmp, 0, OLD_DIRECTORY_SIZE - 53);
                        Array.Copy(sector, sector.Length - 54, tmp, OLD_DIRECTORY_SIZE - 54, 53);
                        sector = tmp;
                    }
                    ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
                    OldDirectory oldRoot =
                        (OldDirectory)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldDirectory));
                    byte dirChk = AcornDirectoryChecksum(sector, (int)OLD_DIRECTORY_SIZE - 1);

                    DicConsole.DebugWriteLine("ADFS Plugin", "oldRoot.header.magic at 0x200 = {0}",
                                              oldRoot.header.magic);
                    DicConsole.DebugWriteLine("ADFS Plugin", "oldRoot.tail.magic at 0x200 = {0}", oldRoot.tail.magic);
                    DicConsole.DebugWriteLine("ADFS Plugin", "oldRoot.tail.checkByte at 0x200 = {0}",
                                              oldRoot.tail.checkByte);
                    DicConsole.DebugWriteLine("ADFS Plugin", "dirChk at 0x200 = {0}", dirChk);

                    if (oldRoot.header.magic == OLD_DIR_MAGIC && oldRoot.tail.magic == OLD_DIR_MAGIC ||
                        oldRoot.header.magic == NEW_DIR_MAGIC && oldRoot.tail.magic == NEW_DIR_MAGIC)
                    {
                        return(true);
                    }

                    // RISC OS says the old directory can't be in the new location, hard disks created by RISC OS 3.10 do that...
                    sbSector      = NEW_DIRECTORY_LOCATION / imagePlugin.Info.SectorSize;
                    sectorsToRead = NEW_DIRECTORY_SIZE / imagePlugin.Info.SectorSize;
                    if (NEW_DIRECTORY_SIZE % imagePlugin.Info.SectorSize > 0)
                    {
                        sectorsToRead++;
                    }

                    sector = imagePlugin.ReadSectors(sbSector, sectorsToRead);
                    if (sector.Length > OLD_DIRECTORY_SIZE)
                    {
                        byte[] tmp = new byte[OLD_DIRECTORY_SIZE];
                        Array.Copy(sector, 0, tmp, 0, OLD_DIRECTORY_SIZE - 53);
                        Array.Copy(sector, sector.Length - 54, tmp, OLD_DIRECTORY_SIZE - 54, 53);
                        sector = tmp;
                    }
                    ptr     = GCHandle.Alloc(sector, GCHandleType.Pinned);
                    oldRoot = (OldDirectory)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldDirectory));
                    dirChk  = AcornDirectoryChecksum(sector, (int)OLD_DIRECTORY_SIZE - 1);

                    DicConsole.DebugWriteLine("ADFS Plugin", "oldRoot.header.magic at 0x400 = {0}",
                                              oldRoot.header.magic);
                    DicConsole.DebugWriteLine("ADFS Plugin", "oldRoot.tail.magic at 0x400 = {0}", oldRoot.tail.magic);
                    DicConsole.DebugWriteLine("ADFS Plugin", "oldRoot.tail.checkByte at 0x400 = {0}",
                                              oldRoot.tail.checkByte);
                    DicConsole.DebugWriteLine("ADFS Plugin", "dirChk at 0x400 = {0}", dirChk);

                    if (oldRoot.header.magic == OLD_DIR_MAGIC && oldRoot.tail.magic == OLD_DIR_MAGIC ||
                        oldRoot.header.magic == NEW_DIR_MAGIC && oldRoot.tail.magic == NEW_DIR_MAGIC)
                    {
                        return(true);
                    }
                }
            }

            // Partitioning or not, new formats follow:
            DiscRecord drSb;

            sector = imagePlugin.ReadSector(partition.Start);
            byte newChk = NewMapChecksum(sector);

            DicConsole.DebugWriteLine("ADFS Plugin", "newChk = {0}", newChk);
            DicConsole.DebugWriteLine("ADFS Plugin", "map.zoneChecksum = {0}", sector[0]);

            sbSector      = BOOT_BLOCK_LOCATION / imagePlugin.Info.SectorSize;
            sectorsToRead = BOOT_BLOCK_SIZE / imagePlugin.Info.SectorSize;
            if (BOOT_BLOCK_SIZE % imagePlugin.Info.SectorSize > 0)
            {
                sectorsToRead++;
            }

            if (sbSector + partition.Start + sectorsToRead >= partition.End)
            {
                return(false);
            }

            byte[] bootSector = imagePlugin.ReadSectors(sbSector + partition.Start, sectorsToRead);
            int    bootChk    = 0;

            for (int i = 0; i < 0x1FF; i++)
            {
                bootChk = (bootChk & 0xFF) + (bootChk >> 8) + bootSector[i];
            }

            DicConsole.DebugWriteLine("ADFS Plugin", "bootChk = {0}", bootChk);
            DicConsole.DebugWriteLine("ADFS Plugin", "bBlock.checksum = {0}", bootSector[0x1FF]);

            if (newChk == sector[0] && newChk != 0)
            {
                ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
                NewMap nmap = (NewMap)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(NewMap));
                ptr.Free();
                drSb = nmap.discRecord;
            }
            else if (bootChk == bootSector[0x1FF])
            {
                ptr = GCHandle.Alloc(bootSector, GCHandleType.Pinned);
                BootBlock bBlock = (BootBlock)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(BootBlock));
                ptr.Free();
                drSb = bBlock.discRecord;
            }
            else
            {
                return(false);
            }

            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.log2secsize = {0}", drSb.log2secsize);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.idlen = {0}", drSb.idlen);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.disc_size_high = {0}", drSb.disc_size_high);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.disc_size = {0}", drSb.disc_size);
            DicConsole.DebugWriteLine("ADFS Plugin", "IsNullOrEmpty(drSb.reserved) = {0}",
                                      ArrayHelpers.ArrayIsNullOrEmpty(drSb.reserved));

            if (drSb.log2secsize < 8 || drSb.log2secsize > 10)
            {
                return(false);
            }

            if (drSb.idlen < drSb.log2secsize + 3 || drSb.idlen > 19)
            {
                return(false);
            }

            if (drSb.disc_size_high >> drSb.log2secsize != 0)
            {
                return(false);
            }

            if (!ArrayHelpers.ArrayIsNullOrEmpty(drSb.reserved))
            {
                return(false);
            }

            ulong bytes = drSb.disc_size_high;

            bytes *= 0x100000000;
            bytes += drSb.disc_size;

            return(bytes <= imagePlugin.Info.Sectors * imagePlugin.Info.SectorSize);
        }
Example #2
0
        // TODO: Find root directory on volumes with DiscRecord
        // TODO: Support big directories (ADFS-G?)
        // TODO: Find the real freemap on volumes with DiscRecord, as DiscRecord's discid may be empty but this one isn't
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding = encoding ?? Encoding.GetEncoding("iso-8859-1");
            StringBuilder sbInformation = new StringBuilder();

            XmlFsType   = new FileSystemType();
            information = "";

            ulong sbSector;

            byte[]   sector;
            uint     sectorsToRead;
            GCHandle ptr;
            ulong    bytes;

            // ADFS-S, ADFS-M, ADFS-L, ADFS-D without partitions
            if (partition.Start == 0)
            {
                sector = imagePlugin.ReadSector(0);
                byte oldChk0 = AcornMapChecksum(sector, 255);
                ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
                OldMapSector0 oldMap0 =
                    (OldMapSector0)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldMapSector0));

                sector = imagePlugin.ReadSector(1);
                byte oldChk1 = AcornMapChecksum(sector, 255);
                ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
                OldMapSector1 oldMap1 =
                    (OldMapSector1)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldMapSector1));

                // According to documentation map1 MUST start on sector 1. On ADFS-D it starts at 0x100, not on sector 1 (0x400)
                if (oldMap0.checksum == oldChk0 && oldMap1.checksum != oldChk1 && sector.Length >= 512)
                {
                    sector = imagePlugin.ReadSector(0);
                    byte[] tmp = new byte[256];
                    Array.Copy(sector, 256, tmp, 0, 256);
                    oldChk1 = AcornMapChecksum(tmp, 255);
                    ptr     = GCHandle.Alloc(tmp, GCHandleType.Pinned);
                    oldMap1 = (OldMapSector1)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldMapSector1));
                }

                if (oldMap0.checksum == oldChk0 && oldMap1.checksum == oldChk1 && oldMap0.checksum != 0 &&
                    oldMap1.checksum != 0)
                {
                    bytes = (ulong)((oldMap0.size[2] << 16) + (oldMap0.size[1] << 8) + oldMap0.size[0]) * 256;
                    byte[] namebytes = new byte[10];
                    for (int i = 0; i < 5; i++)
                    {
                        namebytes[i * 2]     = oldMap0.name[i];
                        namebytes[i * 2 + 1] = oldMap1.name[i];
                    }

                    XmlFsType = new FileSystemType
                    {
                        Bootable    = oldMap1.boot != 0, // Or not?
                        Clusters    = (long)(bytes / imagePlugin.Info.SectorSize),
                        ClusterSize = (int)imagePlugin.Info.SectorSize,
                        Type        = "Acorn Advanced Disc Filing System"
                    };

                    if (ArrayHelpers.ArrayIsNullOrEmpty(namebytes))
                    {
                        sbSector      = OLD_DIRECTORY_LOCATION / imagePlugin.Info.SectorSize;
                        sectorsToRead = OLD_DIRECTORY_SIZE / imagePlugin.Info.SectorSize;
                        if (OLD_DIRECTORY_SIZE % imagePlugin.Info.SectorSize > 0)
                        {
                            sectorsToRead++;
                        }

                        sector = imagePlugin.ReadSectors(sbSector, sectorsToRead);
                        if (sector.Length > OLD_DIRECTORY_SIZE)
                        {
                            byte[] tmp = new byte[OLD_DIRECTORY_SIZE];
                            Array.Copy(sector, 0, tmp, 0, OLD_DIRECTORY_SIZE - 53);
                            Array.Copy(sector, sector.Length - 54, tmp, OLD_DIRECTORY_SIZE - 54, 53);
                            sector = tmp;
                        }
                        ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
                        OldDirectory oldRoot =
                            (OldDirectory)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldDirectory));

                        if (oldRoot.header.magic == OLD_DIR_MAGIC && oldRoot.tail.magic == OLD_DIR_MAGIC)
                        {
                            namebytes = oldRoot.tail.name;
                        }
                        else
                        {
                            // RISC OS says the old directory can't be in the new location, hard disks created by RISC OS 3.10 do that...
                            sbSector      = NEW_DIRECTORY_LOCATION / imagePlugin.Info.SectorSize;
                            sectorsToRead = NEW_DIRECTORY_SIZE / imagePlugin.Info.SectorSize;
                            if (NEW_DIRECTORY_SIZE % imagePlugin.Info.SectorSize > 0)
                            {
                                sectorsToRead++;
                            }

                            sector = imagePlugin.ReadSectors(sbSector, sectorsToRead);
                            if (sector.Length > OLD_DIRECTORY_SIZE)
                            {
                                byte[] tmp = new byte[OLD_DIRECTORY_SIZE];
                                Array.Copy(sector, 0, tmp, 0, OLD_DIRECTORY_SIZE - 53);
                                Array.Copy(sector, sector.Length - 54, tmp, OLD_DIRECTORY_SIZE - 54, 53);
                                sector = tmp;
                            }
                            ptr     = GCHandle.Alloc(sector, GCHandleType.Pinned);
                            oldRoot = (OldDirectory)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(),
                                                                           typeof(OldDirectory));

                            if (oldRoot.header.magic == OLD_DIR_MAGIC && oldRoot.tail.magic == OLD_DIR_MAGIC)
                            {
                                namebytes = oldRoot.tail.name;
                            }
                            else
                            {
                                sector = imagePlugin.ReadSectors(sbSector, sectorsToRead);
                                if (sector.Length > NEW_DIRECTORY_SIZE)
                                {
                                    byte[] tmp = new byte[NEW_DIRECTORY_SIZE];
                                    Array.Copy(sector, 0, tmp, 0, NEW_DIRECTORY_SIZE - 41);
                                    Array.Copy(sector, sector.Length - 42, tmp, NEW_DIRECTORY_SIZE - 42, 41);
                                    sector = tmp;
                                }
                                ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
                                NewDirectory newRoot =
                                    (NewDirectory)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(),
                                                                         typeof(NewDirectory));
                                if (newRoot.header.magic == NEW_DIR_MAGIC && newRoot.tail.magic == NEW_DIR_MAGIC)
                                {
                                    namebytes = newRoot.tail.title;
                                }
                            }
                        }
                    }

                    sbInformation.AppendLine("Acorn Advanced Disc Filing System");
                    sbInformation.AppendLine();
                    sbInformation.AppendFormat("{0} bytes per sector", imagePlugin.Info.SectorSize).AppendLine();
                    sbInformation.AppendFormat("Volume has {0} bytes", bytes).AppendLine();
                    sbInformation.AppendFormat("Volume name: {0}", StringHandlers.CToString(namebytes, Encoding))
                    .AppendLine();
                    if (oldMap1.discId > 0)
                    {
                        XmlFsType.VolumeSerial = $"{oldMap1.discId:X4}";
                        sbInformation.AppendFormat("Volume ID: {0:X4}", oldMap1.discId).AppendLine();
                    }
                    if (!ArrayHelpers.ArrayIsNullOrEmpty(namebytes))
                    {
                        XmlFsType.VolumeName = StringHandlers.CToString(namebytes, Encoding);
                    }

                    information = sbInformation.ToString();

                    return;
                }
            }

            // Partitioning or not, new formats follow:
            DiscRecord drSb;

            sector = imagePlugin.ReadSector(partition.Start);
            byte newChk = NewMapChecksum(sector);

            DicConsole.DebugWriteLine("ADFS Plugin", "newChk = {0}", newChk);
            DicConsole.DebugWriteLine("ADFS Plugin", "map.zoneChecksum = {0}", sector[0]);

            sbSector      = BOOT_BLOCK_LOCATION / imagePlugin.Info.SectorSize;
            sectorsToRead = BOOT_BLOCK_SIZE / imagePlugin.Info.SectorSize;
            if (BOOT_BLOCK_SIZE % imagePlugin.Info.SectorSize > 0)
            {
                sectorsToRead++;
            }

            byte[] bootSector = imagePlugin.ReadSectors(sbSector + partition.Start, sectorsToRead);
            int    bootChk    = 0;

            for (int i = 0; i < 0x1FF; i++)
            {
                bootChk = (bootChk & 0xFF) + (bootChk >> 8) + bootSector[i];
            }

            DicConsole.DebugWriteLine("ADFS Plugin", "bootChk = {0}", bootChk);
            DicConsole.DebugWriteLine("ADFS Plugin", "bBlock.checksum = {0}", bootSector[0x1FF]);

            if (newChk == sector[0] && newChk != 0)
            {
                ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
                NewMap nmap = (NewMap)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(NewMap));
                ptr.Free();
                drSb = nmap.discRecord;
            }
            else if (bootChk == bootSector[0x1FF])
            {
                ptr = GCHandle.Alloc(bootSector, GCHandleType.Pinned);
                BootBlock bBlock = (BootBlock)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(BootBlock));
                ptr.Free();
                drSb = bBlock.discRecord;
            }
            else
            {
                return;
            }

            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.log2secsize = {0}", drSb.log2secsize);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.spt = {0}", drSb.spt);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.heads = {0}", drSb.heads);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.density = {0}", drSb.density);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.idlen = {0}", drSb.idlen);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.log2bpmb = {0}", drSb.log2bpmb);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.skew = {0}", drSb.skew);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.bootoption = {0}", drSb.bootoption);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.lowsector = {0}", drSb.lowsector);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.nzones = {0}", drSb.nzones);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.zone_spare = {0}", drSb.zone_spare);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.root = {0}", drSb.root);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.disc_size = {0}", drSb.disc_size);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.disc_id = {0}", drSb.disc_id);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.disc_name = {0}",
                                      StringHandlers.CToString(drSb.disc_name, Encoding));
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.disc_type = {0}", drSb.disc_type);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.disc_size_high = {0}", drSb.disc_size_high);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.flags = {0}", drSb.flags);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.nzones_high = {0}", drSb.nzones_high);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.format_version = {0}", drSb.format_version);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.root_size = {0}", drSb.root_size);

            if (drSb.log2secsize < 8 || drSb.log2secsize > 10)
            {
                return;
            }

            if (drSb.idlen < drSb.log2secsize + 3 || drSb.idlen > 19)
            {
                return;
            }

            if (drSb.disc_size_high >> drSb.log2secsize != 0)
            {
                return;
            }

            if (!ArrayHelpers.ArrayIsNullOrEmpty(drSb.reserved))
            {
                return;
            }

            bytes  = drSb.disc_size_high;
            bytes *= 0x100000000;
            bytes += drSb.disc_size;

            ulong zones = drSb.nzones_high;

            zones *= 0x100000000;
            zones += drSb.nzones;

            if (bytes > imagePlugin.Info.Sectors * imagePlugin.Info.SectorSize)
            {
                return;
            }

            XmlFsType = new FileSystemType();

            sbInformation.AppendLine("Acorn Advanced Disc Filing System");
            sbInformation.AppendLine();
            sbInformation.AppendFormat("Version {0}", drSb.format_version).AppendLine();
            sbInformation.AppendFormat("{0} bytes per sector", 1 << drSb.log2secsize).AppendLine();
            sbInformation.AppendFormat("{0} sectors per track", drSb.spt).AppendLine();
            sbInformation.AppendFormat("{0} heads", drSb.heads).AppendLine();
            sbInformation.AppendFormat("Density code: {0}", drSb.density).AppendLine();
            sbInformation.AppendFormat("Skew: {0}", drSb.skew).AppendLine();
            sbInformation.AppendFormat("Boot option: {0}", drSb.bootoption).AppendLine();
            // TODO: What the hell is this field refering to?
            sbInformation.AppendFormat("Root starts at frag {0}", drSb.root).AppendLine();
            //sbInformation.AppendFormat("Root is {0} bytes long", drSb.root_size).AppendLine();
            sbInformation.AppendFormat("Volume has {0} bytes in {1} zones", bytes, zones).AppendLine();
            sbInformation.AppendFormat("Volume flags: 0x{0:X4}", drSb.flags).AppendLine();
            if (drSb.disc_id > 0)
            {
                XmlFsType.VolumeSerial = $"{drSb.disc_id:X4}";
                sbInformation.AppendFormat("Volume ID: {0:X4}", drSb.disc_id).AppendLine();
            }
            if (!ArrayHelpers.ArrayIsNullOrEmpty(drSb.disc_name))
            {
                string discname = StringHandlers.CToString(drSb.disc_name, Encoding);
                XmlFsType.VolumeName = discname;
                sbInformation.AppendFormat("Volume name: {0}", discname).AppendLine();
            }

            information = sbInformation.ToString();

            XmlFsType.Bootable   |= drSb.bootoption != 0; // Or not?
            XmlFsType.Clusters    = (long)(bytes / (ulong)(1 << drSb.log2secsize));
            XmlFsType.ClusterSize = 1 << drSb.log2secsize;
            XmlFsType.Type        = "Acorn Advanced Disc Filing System";
        }