Exemplo n.º 1
0
        /*
         * Read SECTOR_DATA CHUNK type
         */
        bool _load_sector_data_chunk(chunk_header chunkhdr, AtxTrack track, BinaryReader reader)
        {
            int data_size = (int)chunkhdr.length - chunk_header_bytecount;

            if (track.sector_count > 0 && track.sectors.Any() == false)
            {
                Console.WriteLine($"\tWARNING:: SECTOR_DATA chunk presented before SECTOR_LIST chunk");
            }
            else
            {
                int    actual_sectors  = 0;
                string missing_sectors = "";
                foreach (var s in track.sectors)
                {
                    if ((s.status & (byte)SectorStatus.MISSING_DATA) == 0)
                    {
                        actual_sectors++;
                    }
                    else
                    {
                        missing_sectors = "; missing sectors accounted for";
                    }
                }
                int calculated_bytes = actual_sectors * _sector_size;

                if (data_size != calculated_bytes)
                {
                    Console.WriteLine($"\tWARNING:: Chunk data size as given in header ({data_size:N0}) != expected size ({actual_sectors} * {_sector_size} = {calculated_bytes:N0}){missing_sectors}");
                }
            }

            Console.WriteLine($"\tReading {data_size:N0} bytes of track sector data");

            try
            {
                track.data = reader.ReadBytes(data_size);
            }
            catch
            {
                Console.WriteLine($"\tERROR:: Failed to read sector data");
                return(false);
            }

            /*
             * The start_data value in each sector header is an offset into the overall Track Record,
             * including headers and other chunks that preceed it, where that sector's actual data begins
             * in the data chunk.
             *
             * We record the number of bytes into the Track Record the data chunk begins so we
             * can adjust the start_data value later when we want to read the right section from this
             * array of bytes.
             */
            track.offset_to_data_start = track.record_bytes_read;
            // Keep a count of how many bytes we've read into the Track Record
            track.record_bytes_read += data_size;

            _sector_data_bytes += data_size;

            return(true);
        }
Exemplo n.º 2
0
        /*
         * Read EXTENDED_DATA CHUNK type
         */
        bool _load_extended_sector_chunk(chunk_header chunkhdr, AtxTrack track, BinaryReader reader)
        {
            if (chunkhdr.length != chunk_header_bytecount)
            {
                Console.WriteLine($"\tERROR:: Chunk length {chunkhdr.length} != expected ({chunk_header_bytecount})");
            }

            if (chunkhdr.sector_index >= track.sector_count)
            {
                Console.WriteLine("\tERROR:: Extended sector index > track sector count");
                return(false);
            }

            UInt16 xsize;

            switch ((ExtendedSize)chunkhdr.header_data)
            {
            case ExtendedSize.EXTENDEDSIZE_128:
                xsize = 128;
                break;

            case ExtendedSize.EXTENDEDSIZE_256:
                xsize = 256;
                break;

            case ExtendedSize.EXTENDEDSIZE_512:
                xsize = 512;
                break;

            case ExtendedSize.EXTENDEDSIZE_1024:
                xsize = 1024;
                break;

            default:
                Console.WriteLine($"\tERROR:: Invalid extended sector value {chunkhdr.header_data}");
                return(false);
            }

            track.sectors[chunkhdr.sector_index].extendedsize = xsize;

            int sector_number         = track.sectors[chunkhdr.sector_index].number;
            int overall_sector_number = track.track_number * _sectors_per_track + sector_number;

            Console.WriteLine($"\tExtended sector: index={chunkhdr.sector_index}, num={sector_number} ({overall_sector_number}, ${overall_sector_number:x3}), size={xsize}");

            return(true);
        }
Exemplo n.º 3
0
        /*
         * Read WEAK_SECTOR CHUNK type
         */
        bool _load_weak_sector_chunk(chunk_header chunkhdr, AtxTrack track, BinaryReader reader)
        {
            if (chunkhdr.length != chunk_header_bytecount)
            {
                Console.WriteLine($"\tERROR:: Chunk length {chunkhdr.length} != expected ({chunk_header_bytecount})");
            }
            if (chunkhdr.sector_index >= track.sector_count)
            {
                Console.WriteLine("\tERROR:: Weak sector index > track sector count");
                return(false);
            }

            track.sectors[chunkhdr.sector_index].weakoffset = chunkhdr.header_data;

            int sector_number         = track.sectors[chunkhdr.sector_index].number;
            int overall_sector_number = track.track_number * _sectors_per_track + sector_number;

            Console.WriteLine($"\tWeak sector: index={chunkhdr.sector_index}, num={sector_number} ({overall_sector_number}, ${overall_sector_number:x3}), offset={chunkhdr.header_data}");

            return(true);
        }
Exemplo n.º 4
0
        /*
         * Parses a TRACK record type by reading its constitute CHUNKS
         */
        bool _load_track_record(UInt32 length, BinaryReader reader)
        {
            track_header trkhdr;

            try
            {
                trkhdr.track_number = reader.ReadByte();
                trkhdr.reserved1    = reader.ReadByte();
                trkhdr.sector_count = reader.ReadUInt16();
                trkhdr.rate         = reader.ReadUInt16();
                trkhdr.reserved2    = reader.ReadUInt16();
                trkhdr.flags        = reader.ReadUInt32();
                trkhdr.header_size  = reader.ReadUInt32();
                trkhdr.reserved3    = reader.ReadUInt64();
            }
            catch
            {
                Console.WriteLine("ERROR:: Failed to read track header");
                return(false);
            }

            if (trkhdr.track_number != _tracks.Count)
            {
                Console.WriteLine($"WARNING:: Expecting track #{_tracks.Count} but got #{trkhdr.track_number}");
            }

            if (trkhdr.track_number >= 40)
            {
                Console.WriteLine($"WARNING:: Track # greater than 40");
            }

            // See if this track number already exists
            foreach (var t in _tracks)
            {
                if (t.track_number == trkhdr.track_number)
                {
                    Console.WriteLine($"WARNING:: Track #{trkhdr.track_number} already exists");
                    break;
                }
            }

            AtxTrack track = new AtxTrack();

            track.track_number = trkhdr.track_number;
            track.sector_count = trkhdr.sector_count;
            track.rate         = trkhdr.rate;
            track.flags        = trkhdr.flags;
            _tracks.Add(track);

            Console.WriteLine($"Track #{track.track_number:D2}: sectors={track.sector_count}, rate={track.rate}");

            if (track.flags != 0)
            {
                Console.Write($"  Track flags: ");
                if ((track.flags & (uint)TrackFlags.MFM) == (uint)TrackFlags.MFM)
                {
                    Console.Write("MFM ");
                }
                if ((track.flags & (uint)TrackFlags.UNKNOWN_SKEW) == (uint)TrackFlags.UNKNOWN_SKEW)
                {
                    Console.Write("SKEW_NOT_KNOWN");
                }
                Console.WriteLine();

                if ((track.flags & ~((uint)TrackFlags.MFM | (uint)TrackFlags.UNKNOWN_SKEW)) != 0)
                {
                    Console.WriteLine($"WARNING:: Unknown track flags 0x{track.flags:X8}");
                }
            }

            if (_verbose && track.sector_count != _sectors_per_track)
            {
                Console.WriteLine($"WARNING:: Track sector count ({track.sector_count}) != {_sectors_per_track}");
            }

            // Keep a count of how many bytes we've read into the Track Record
            // So far we've read record_header + track_header bytes into this record
            track.record_bytes_read = record_header_bytecount + track_header_bytecount;

            // If needed, skip ahead to the first track chunk given the header size value
            // (The 'header_size' value includes both the current track header and the 'parent' record header)
            int chunk_start_offset = (int)trkhdr.header_size - record_header_bytecount - track_header_bytecount;

            if (chunk_start_offset > 0)
            {
                try
                {
                    reader.BaseStream.Seek(chunk_start_offset, SeekOrigin.Current);
                }
                catch
                {
                    Console.WriteLine($"ERROR:: Failed to seek {chunk_start_offset} bytes to first chunk in track record");
                    return(false);
                }
                // Keep a count of how many bytes we've read into the Track Record
                track.record_bytes_read += chunk_start_offset;
            }

            // Read all the chunks in the track
            int i, j = 0;

            while ((i = _load_track_chunk(trkhdr, track, reader, ++j)) == 0)
            {
                ;
            }

            return(i == 1); // Return FALSE on error condition
        }
Exemplo n.º 5
0
        /*
         * Read a TRACK CHUNK
         * Expected types are SECTOR_DATA, SECTOR_LIST, WEAK_SECTOR, and EXTENDED_HEADER
         *
         * Returns:
         *   0 = Ok
         *   1 = Done (reached terminator chunk)
         *  -1 = Error
         */
        int _load_track_chunk(track_header trkhdr, AtxTrack track, BinaryReader reader, int chunkcount)
        {
            chunk_header chunkhdr;

            try
            {
                chunkhdr.length       = reader.ReadUInt32();
                chunkhdr.type         = reader.ReadByte();
                chunkhdr.sector_index = reader.ReadByte();
                chunkhdr.header_data  = reader.ReadUInt16();
            }
            catch
            {
                Console.WriteLine("  ERROR:: Failed to read chunk header");
                return(-1);
            };

            // Keep a count of how many bytes we've read into the Track Record
            track.record_bytes_read += chunk_header_bytecount;

            // Check for a terminating marker
            if (chunkhdr.length == 0)
            {
                Console.WriteLine("  Chunk terminator");
                return(1); // 1 = done
            }

            string chunktype;

            if (Enum.IsDefined(typeof(ChunkType), (int)chunkhdr.type))
            {
                chunktype = Enum.GetName(typeof(ChunkType), (int)chunkhdr.type);
            }
            else
            {
                chunktype = $"UNKNOWN ({chunkhdr.type})";
            }

            Console.WriteLine($"  Chunk #{chunkcount} type={chunktype}, size={chunkhdr.length}, secIndex={chunkhdr.sector_index}, hdrData=0x{chunkhdr.header_data:X4}");

            switch ((ChunkType)chunkhdr.type)
            {
            case ChunkType.SECTOR_LIST:
                if (false == _load_sector_list_chunk(chunkhdr, track, reader))
                {
                    return(-1);
                }
                break;

            case ChunkType.SECTOR_DATA:
                if (false == _load_sector_data_chunk(chunkhdr, track, reader))
                {
                    return(-1);
                }
                break;

            case ChunkType.WEAK_SECTOR:
                if (false == _load_weak_sector_chunk(chunkhdr, track, reader))
                {
                    return(-1);
                }
                break;

            case ChunkType.EXTENDED_HEADER:
                if (false == _load_extended_sector_chunk(chunkhdr, track, reader))
                {
                    return(-1);
                }
                break;

            default:
                if (false == _load_unknown_chunk(chunkhdr, reader))
                {
                    return(-1);
                }
                return(-1);
            }

            return(0);
        }
Exemplo n.º 6
0
        /*
         * Read SECTOR_LIST CHUNK type
         */
        bool _load_sector_list_chunk(chunk_header chunkhdr, AtxTrack track, BinaryReader reader)
        {
            int expected = chunk_header_bytecount + track.sector_count * sector_header_bytecount;

            if (chunkhdr.length != expected)
            {
                Console.WriteLine($"\tWARNING:: Chunk length {chunkhdr.length} != expected ({expected})");
            }

            // Try to read sector data for sector_count sectors
            for (int i = 0; i < track.sector_count; i++)
            {
                AtxSector sect = new AtxSector();
                try
                {
                    sect.number     = reader.ReadByte();
                    sect.status     = reader.ReadByte();
                    sect.position   = reader.ReadUInt16();
                    sect.start_data = reader.ReadUInt32();

                    track.record_bytes_read += sector_header_bytecount;
                }
                catch
                {
                    Console.WriteLine($"\tERROR:: Failed to read sector list header for sector at index {i}");
                    return(false);
                }

                int    overall_sector_number = track.track_number * _sectors_per_track + sect.number;
                string overall = $"({overall_sector_number}, ${overall_sector_number:x3})";

                if (sect.status != 0)
                {
                    Console.Write($"\tSector index={i}, num={sect.number} {overall}, flags=");
                    if ((sect.status & (byte)SectorStatus.DELETED) != 0)
                    {
                        Console.Write("DELETED ");
                    }
                    if ((sect.status & (byte)SectorStatus.MISSING_DATA) != 0)
                    {
                        Console.Write("MISSING_DATA ");
                    }
                    if ((sect.status & (byte)SectorStatus.EXTENDED) != 0)
                    {
                        Console.Write("EXTENDED ");
                    }
                    if ((sect.status & (byte)SectorStatus.FDC_CRC_ERROR) != 0)
                    {
                        Console.Write("CRC_ERROR ");
                    }
                    if ((sect.status & (byte)SectorStatus.FDC_LOSTDATA_ERROR) != 0)
                    {
                        Console.Write("LOSTDATA_ERROR");
                    }
                    if ((sect.status & (byte)SectorStatus.FDC_DATAREQ_PENDING) != 0)
                    {
                        Console.Write("DATAREQ_PENDING");
                    }
                    Console.WriteLine();

                    if ((sect.status & ~(byte)(SectorStatus.DELETED | SectorStatus.MISSING_DATA |
                                               SectorStatus.EXTENDED | SectorStatus.FDC_CRC_ERROR |
                                               SectorStatus.FDC_DATAREQ_PENDING | SectorStatus.FDC_LOSTDATA_ERROR)) != 0)
                    {
                        Console.WriteLine($"\tWARNING:: Unknown sector status flag 0x{sect.status:X2}");
                    }
                }

                if (sect.number > _sectors_per_track)
                {
                    Console.WriteLine($"\tWARNING:: Sector index={i}, number={sect.number} > {_sectors_per_track}");
                }
                if (sect.number == 0)
                {
                    Console.WriteLine($"\tWARNING:: Sector index={i} has sector #0");
                }

                if (sect.position >= ANGULAR_UNIT_COUNT)
                {
                    Console.WriteLine($"\tWARNING:: Sector index={i}, num={sect.number} {overall}, angular position {sect.position} > {ANGULAR_UNIT_COUNT - 1}");
                }


                // See if this is a duplicate
                foreach (var s in track.sectors)
                {
                    if (s.number == sect.number)
                    {
                        Console.WriteLine($"\tDUPLICATE sector #{sect.number:D2} {overall}");
                        break;
                    }
                }

                // Add to the list
                track.sectors.Add(sect);
            }

            Console.WriteLine($"\tRead {track.sectors.Count} sector headers for track {track.track_number}");

            // Report on any missing sectors
            for (int i = 1; i <= _sectors_per_track; i++)
            {
                if (track.sectors.Find(x => x.number == i) == null)
                {
                    Console.WriteLine($"\tMISSING sector #{i}");
                }
            }

            return(true);
        }