ADL: Add support for reading .xfd Atari disk images

This commit is contained in:
Walter van Niftrik 2016-08-27 01:47:43 +02:00
parent 8f29f067a4
commit 0a053e4ce4
4 changed files with 58 additions and 40 deletions

View File

@ -28,15 +28,7 @@
namespace Adl {
#define TRACKS 35
// The Apple II uses either 13- or 16-sector disks. We currently pad out
// 13-sector disks, so we set SECTORS_PER_TRACK to 16 here.
#define SECTORS_PER_TRACK 16
#define BYTES_PER_SECTOR 256
#define RAW_IMAGE_SIZE(S) (TRACKS * (S) * BYTES_PER_SECTOR)
#define NIB_IMAGE_SIZE (RAW_IMAGE_SIZE(13) * 2)
static Common::SeekableReadStream *readImage_DSK(const Common::String &filename) {
static Common::SeekableReadStream *readImage(const Common::String &filename) {
Common::File *f = new Common::File;
if (!f->open(filename)) {
@ -44,9 +36,6 @@ static Common::SeekableReadStream *readImage_DSK(const Common::String &filename)
return nullptr;
}
if (f->size() != RAW_IMAGE_SIZE(16))
error("Unrecognized DSK image '%s' of size %d bytes", filename.c_str(), f->size());
return f;
}
@ -63,7 +52,7 @@ static Common::SeekableReadStream *readImage_NIB(const Common::String &filename)
if (!f.open(filename))
return nullptr;
if (f.size() != NIB_IMAGE_SIZE)
if (f.size() != 232960)
error("Unrecognized NIB image '%s' of size %d bytes", filename.c_str(), f.size());
// starting at 0xaa, 32 is invalid (see below)
@ -73,7 +62,9 @@ static Common::SeekableReadStream *readImage_NIB(const Common::String &filename)
// we always pad it out
const uint sectorsPerTrack = 16;
byte *diskImage = (byte *)calloc(RAW_IMAGE_SIZE(sectorsPerTrack), 1);
const uint bytesPerSector = 256;
const uint imageSize = 35 * sectorsPerTrack * bytesPerSector;
byte *const diskImage = (byte *)calloc(imageSize, 1);
bool sawAddress = false;
uint8 volNo, track, sector;
@ -120,13 +111,13 @@ static Common::SeekableReadStream *readImage_NIB(const Common::String &filename)
// We should always find the data field after an address field.
// TODO: we ignore volNo?
byte *output = diskImage + (track * sectorsPerTrack + sector) * BYTES_PER_SECTOR;
byte *output = diskImage + (track * sectorsPerTrack + sector) * bytesPerSector;
if (newStyle) {
// We hardcode the DOS 3.3 mapping here. TODO: Do we also need raw/prodos?
int raw2dos[16] = { 0, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 15 };
sector = raw2dos[sector];
output = diskImage + (track * sectorsPerTrack + sector) * BYTES_PER_SECTOR;
output = diskImage + (track * sectorsPerTrack + sector) * bytesPerSector;
// 6-and-2 uses 342 on-disk bytes
byte inbuffer[342];
@ -216,36 +207,59 @@ static Common::SeekableReadStream *readImage_NIB(const Common::String &filename)
}
}
return new Common::MemoryReadStream(diskImage, RAW_IMAGE_SIZE(sectorsPerTrack), DisposeAfterUse::YES);
return new Common::MemoryReadStream(diskImage, imageSize, DisposeAfterUse::YES);
}
bool DiskImage::open(const Common::String &filename) {
Common::String lcName(filename);
lcName.toLowercase();
if (lcName.hasSuffix(".dsk"))
_stream = readImage_DSK(filename);
else if (lcName.hasSuffix(".nib"))
if (lcName.hasSuffix(".dsk")) {
_stream = readImage(filename);
_tracks = 35;
_sectorsPerTrack = 16;
_bytesPerSector = 256;
} else if (lcName.hasSuffix(".nib")) {
_stream = readImage_NIB(filename);
_tracks = 35;
_sectorsPerTrack = 16;
_bytesPerSector = 256;
} else if (lcName.hasSuffix(".xfd")) {
_stream = readImage(filename);
_tracks = 40;
_sectorsPerTrack = 18;
_bytesPerSector = 128;
}
return _stream != nullptr;
int expectedSize = _tracks * _sectorsPerTrack * _bytesPerSector;
if (!_stream)
return false;
if (_stream->size() != expectedSize)
error("Unrecognized disk image '%s' of size %d bytes (expected %d bytes)", filename.c_str(), _stream->size(), expectedSize);
return true;
}
const DataBlockPtr DiskImage::getDataBlock(uint track, uint sector, uint offset, uint size) const {
return DataBlockPtr(new DiskImage::DataBlock(this, track, sector, offset, size, _mode13));
return DataBlockPtr(new DiskImage::DataBlock(this, track, sector, offset, size, _sectorLimit));
}
Common::SeekableReadStream *DiskImage::createReadStream(uint track, uint sector, uint offset, uint size, uint sectorsPerTrackToRead) const {
const uint bytesToRead = size * BYTES_PER_SECTOR + BYTES_PER_SECTOR - offset;
Common::SeekableReadStream *DiskImage::createReadStream(uint track, uint sector, uint offset, uint size, uint sectorLimit) const {
const uint bytesToRead = size * _bytesPerSector + _bytesPerSector - offset;
byte *const data = (byte *)malloc(bytesToRead);
uint dataOffset = 0;
if (sector > sectorsPerTrackToRead - 1)
error("Sector %i is out of bounds for %i-sector reading", sector, sectorsPerTrackToRead);
if (sectorLimit == 0)
sectorLimit = _sectorsPerTrack;
if (sector >= sectorLimit)
error("Sector %i is out of bounds for %i-sector reading", sector, sectorLimit);
while (dataOffset < bytesToRead) {
uint bytesRemInTrack = (sectorsPerTrackToRead - 1 - sector) * BYTES_PER_SECTOR + BYTES_PER_SECTOR - offset;
_stream->seek((track * SECTORS_PER_TRACK + sector) * BYTES_PER_SECTOR + offset);
uint bytesRemInTrack = (sectorLimit - 1 - sector) * _bytesPerSector + _bytesPerSector - offset;
_stream->seek((track * _sectorsPerTrack + sector) * _bytesPerSector + offset);
if (bytesToRead - dataOffset < bytesRemInTrack)
bytesRemInTrack = bytesToRead - dataOffset;

View File

@ -74,7 +74,10 @@ class DiskImage {
public:
DiskImage() :
_stream(nullptr),
_mode13(false) { }
_tracks(0),
_sectorsPerTrack(0),
_bytesPerSector(0),
_sectorLimit(0) { }
~DiskImage() {
delete _stream;
@ -82,32 +85,33 @@ public:
bool open(const Common::String &filename);
const DataBlockPtr getDataBlock(uint track, uint sector, uint offset = 0, uint size = 0) const;
Common::SeekableReadStream *createReadStream(uint track, uint sector, uint offset = 0, uint size = 0, uint sectorsPerTrackToRead = 16) const;
void setMode13(bool enable) { _mode13 = enable; }
Common::SeekableReadStream *createReadStream(uint track, uint sector, uint offset = 0, uint size = 0, uint sectorsUsed = 0) const;
void setSectorLimit(uint sectorLimit) { _sectorLimit = sectorLimit; } // Maximum number of sectors to read per track before stepping
protected:
class DataBlock : public Adl::DataBlock {
public:
DataBlock(const DiskImage *disk, uint track, uint sector, uint offset, uint size, bool mode13) :
DataBlock(const DiskImage *disk, uint track, uint sector, uint offset, uint size, uint sectorLimit) :
_track(track),
_sector(sector),
_offset(offset),
_size(size),
_mode13(mode13),
_sectorLimit(sectorLimit),
_disk(disk) { }
Common::SeekableReadStream *createReadStream() const {
return _disk->createReadStream(_track, _sector, _offset, _size, (_mode13 ? 13 : 16));
return _disk->createReadStream(_track, _sector, _offset, _size, _sectorLimit);
}
private:
uint _track, _sector, _offset, _size;
bool _mode13;
uint _sectorLimit;
const DiskImage *_disk;
};
Common::SeekableReadStream *_stream;
bool _mode13; // Older 13-sector format
uint _tracks, _sectorsPerTrack, _bytesPerSector;
uint _sectorLimit;
};
// Data in plain files

View File

@ -35,7 +35,7 @@ void HiRes0Engine::init() {
if (!_disk->open(IDS_HR0_DISK_IMAGE))
error("Failed to open disk image '" IDS_HR0_DISK_IMAGE "'");
_disk->setMode13(true);
_disk->setSectorLimit(13);
StreamPtr stream(_disk->createReadStream(0x1f, 0x2, 0x00, 2));

View File

@ -37,7 +37,7 @@ void HiRes2Engine::runIntro() const {
// This only works for the 16-sector re-release. The original
// release is not supported at this time, because we don't have
// access to it.
_disk->setMode13(false);
_disk->setSectorLimit(0);
StreamPtr stream(_disk->createReadStream(0x00, 0xd, 0x17, 1));
_display->setMode(DISPLAY_MODE_TEXT);
@ -50,7 +50,7 @@ void HiRes2Engine::runIntro() const {
_display->printString(str);
delay(2000);
_disk->setMode13(true);
_disk->setSectorLimit(13);
}
void HiRes2Engine::init() {
@ -60,7 +60,7 @@ void HiRes2Engine::init() {
if (!_disk->open(IDS_HR2_DISK_IMAGE))
error("Failed to open disk image '" IDS_HR2_DISK_IMAGE "'");
_disk->setMode13(true);
_disk->setSectorLimit(13);
StreamPtr stream(_disk->createReadStream(0x1f, 0x2, 0x00, 4));