1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-22 14:30:29 +00:00

Flounder around file contents.

This commit is contained in:
Thomas Harte 2024-02-22 22:19:19 -05:00
parent 4b5456c9ba
commit 8460fe2118
2 changed files with 49 additions and 12 deletions

View File

@ -10,36 +10,71 @@
#include "Utility/ImplicitSectors.hpp"
namespace {
constexpr int sectors_per_track = 16;
constexpr int sector_size = 1;
}
using namespace Storage::Disk;
AcornADF::AcornADF(const std::string &file_name) : MFMSectorDump(file_name) {
// Check that the disk image contains a whole number of sector.
using sizeT = decltype(file_.stats().st_size);
if(file_.stats().st_size % sizeT(128 << sector_size)) throw Error::InvalidFormat;
const auto size = file_.stats().st_size;
if(size < 1024) throw Error::InvalidFormat;
// Definitely true: a directory signature of 'Hugo' can be read by both 8-bit
// machines and the Archimedes. 'Nick' can be read only by the Archimedes.
//
// https://mdfs.net/Docs/Comp/Disk/Format/ADFS then falsely states that:
//
// The type of ADFS filesystem can be determined by looking for the "Hugo"/
// "Nick" identifier that marks the start of the root directory 512 bytes into
// the filesystem and 1024 bytes in.
//
// In terms of .ADF files:
//
// all 8-bit files seem to have 'Hugo' at offset 513;
// ADFS-D (early Arc, late BBC Master) has 'Nick' or 'Hugo' at 1025; but
// ADFS-E (most Arc) has 'Hugo' at 2049.
//
// Even allowing for the document having failed to account for the directory ID,
// I can't reconcile that 2049 offset with being 1024 bytes into the file system.
//
// That document claims that ADFS-D and ADFS-E are logically interleaved but
// https://github.com/android444/fluxengine/blob/master/doc/disk-acornadfs.md
// states that:
//
// Acorn logical block numbering goes all the way up side 0 and then all the
// way up side 1. However, FluxEngine uses traditional disk images with alternating
// sides, with the blocks from track 0 side 0 then track 0 side 1 then track 1 side 0 etc.
// Most Acorn emulators will use both formats, but they might require nudging as the side
// order can't be reliably autodetected.
//
// So then .ADF files might be track-interleaved and might not be.
switch(size) {
default:
sector_size_ = 1;
sectors_per_track_ = 16;
break;
}
// Check that the disk image is at least large enough to hold an ADFS catalogue.
if(file_.stats().st_size < 7 * sizeT(128 << sector_size)) throw Error::InvalidFormat;
if(file_.stats().st_size < 7 * sizeT(128 << sector_size_)) throw Error::InvalidFormat;
// Check that the initial directory's 'Hugo's or 'Nick's are present.
// TODO: check other locations, to pick sector size and count.
file_.seek(513, SEEK_SET);
uint8_t bytes[4];
file_.read(bytes, 4);
if(memcmp(bytes, "Hugo", 4)) throw Error::InvalidFormat;
if(memcmp(bytes, "Hugo", 4) && memcmp(bytes, "Nick", 4)) throw Error::InvalidFormat;
file_.seek(0x6fb, SEEK_SET);
file_.read(bytes, 4);
if(memcmp(bytes, "Hugo", 4)) throw Error::InvalidFormat;
if(memcmp(bytes, "Hugo", 4) && memcmp(bytes, "Nick", 4)) throw Error::InvalidFormat;
// Pick a number of heads; treat this image as double sided if it's too large to be single-sided.
head_count_ = 1 + (file_.stats().st_size > sectors_per_track * sizeT(128 << sector_size) * 80);
head_count_ = 1 + (file_.stats().st_size > sectors_per_track_ * sizeT(128 << sector_size_) * 80);
// Announce disk geometry.
set_geometry(sectors_per_track, sector_size, 0, Encodings::MFM::Density::Double);
set_geometry(sectors_per_track_, sector_size_, 0, Encodings::MFM::Density::Double);
}
HeadPosition AcornADF::get_maximum_head_position() {
@ -51,5 +86,5 @@ int AcornADF::get_head_count() {
}
long AcornADF::get_file_offset_for_position(Track::Address address) {
return (address.position.as_int() * head_count_ + address.head) * (128 << sector_size) * sectors_per_track;
return (address.position.as_int() * head_count_ + address.head) * (128 << sector_size_) * sectors_per_track_;
}

View File

@ -33,6 +33,8 @@ class AcornADF: public MFMSectorDump {
private:
long get_file_offset_for_position(Track::Address address) final;
int head_count_ = 1;
uint8_t sector_size_ = 1;
int sectors_per_track_ = 16;
};
}