예제 #1
0
        /// <summary>
        /// Parse a BIOS Parameter Block from a stream
        /// </summary>
        /// <param name="reader">A binary reader around the stream</param>
        /// <param name="offset">The offset in the stream of the BPB</param>
        /// <returns>A BIOS Parameter block</returns>
        public static BiosParameterBlock Parse(BinaryReader reader, long offset)
        {
            reader.BaseStream.Seek(offset, SeekOrigin.Begin); //BPB offset

            var bpb = new BiosParameterBlock
            {
                BytesPerLogicalSector    = reader.ReadUInt16(),
                LogicalSectorsPerCluster = reader.ReadByte(),
                ReservedLogicalSectors   = reader.ReadUInt16(),
                NumberOfFATs             = reader.ReadByte(),
                RootDirectoryEntries     = reader.ReadUInt16(),
                TotalLogicalSectors      = reader.ReadUInt16(),
                MediaDescriptor          = reader.ReadByte(),
                LogicalSectorsPerFAT     = reader.ReadUInt16()
            };

            //Parsing a standard BPB
            if (offset == 0x0B)
            {
                bpb.PhysicalSectorsPerTrack = reader.ReadUInt16();
                bpb.NumberOfHeads           = reader.ReadUInt16();

                if (bpb.TotalLogicalSectors != 0)
                {
                    bpb.HiddenSectors = reader.ReadUInt16();
                    reader.BaseStream.Seek(6, SeekOrigin.Current);
                }
                else
                {
                    bpb.HiddenSectors       = reader.ReadUInt32();
                    bpb.TotalLogicalSectors = reader.ReadUInt32();
                }
            }

            //Parsing an Apricot BPB, which doesn't have the number of heads and SPT, so we have to make some manual adjustments
            else if (offset == 0x50)
            {
                if (bpb.MediaDescriptor == 0xFC) //315k
                {
                    bpb.NumberOfHeads           = 1;
                    bpb.PhysicalSectorsPerTrack = 70;
                }
                else if (bpb.MediaDescriptor == 0xFE) //720k
                {
                    bpb.NumberOfHeads           = 2;
                    bpb.PhysicalSectorsPerTrack = 80;
                }
            }

            if (!bpb.Validate())
            {
                throw new InvalidDataException("At least one of BPB parameters is 0");
            }

            uint tracks = (uint)(bpb.TotalLogicalSectors / bpb.NumberOfHeads / bpb.PhysicalSectorsPerTrack);

            // TODO: This probably needs reviewing to better check BPB params match the correct size
            if (tracks == 0)
            {
                throw new InvalidDataException("BPB paramaters don't match image size");
            }

            // Parsing a standard BPB, read boot sector
            if (offset == 0x0B)
            {
                long endOffset = reader.BaseStream.Position;

                reader.BaseStream.Seek(0, SeekOrigin.Begin);
                bpb.BootJump = reader.ReadBytes(3);
                bpb.OemId    = new string(reader.ReadChars(8)).TrimEnd(' ').ToUpper();

                reader.BaseStream.Seek(endOffset, SeekOrigin.Begin);
            }

            if (bpb.LogicalSectorsPerFAT == 0)
            {
                // This could be a FAT32 BPB.
                return(Fat32BiosParameterBlock.ContinueParsing(bpb, reader) ?? throw new InvalidDataException("FAT size is 0"));
            }
            else
            {
                //So far, the BPB seems to be OK, so try to read it further as a DOS 4.0 BPB.
                return(ExtendedBiosParameterBlock.ContinueParsing(bpb, reader) ?? bpb);
            }
        }