Skip to content

Commit

Permalink
ADL: Add support for reading .xfd Atari disk images
Browse files Browse the repository at this point in the history
  • Loading branch information
waltervn committed Aug 28, 2016
1 parent 8f29f06 commit 0a053e4
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 40 deletions.
70 changes: 42 additions & 28 deletions engines/adl/disk.cpp
Expand Up @@ -28,25 +28,14 @@

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)) {
delete f;
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;
}

Expand All @@ -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)
Expand All @@ -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;
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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;
}

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 _stream != nullptr;
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;
Expand Down
20 changes: 12 additions & 8 deletions engines/adl/disk.h
Expand Up @@ -74,40 +74,44 @@ class DiskImage {
public:
DiskImage() :
_stream(nullptr),
_mode13(false) { }
_tracks(0),
_sectorsPerTrack(0),
_bytesPerSector(0),
_sectorLimit(0) { }

~DiskImage() {
delete _stream;
}

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
Expand Down
2 changes: 1 addition & 1 deletion engines/adl/hires0.cpp
Expand Up @@ -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));

Expand Down
6 changes: 3 additions & 3 deletions engines/adl/hires2.cpp
Expand Up @@ -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);
Expand All @@ -50,7 +50,7 @@ void HiRes2Engine::runIntro() const {
_display->printString(str);
delay(2000);

_disk->setMode13(true);
_disk->setSectorLimit(13);
}

void HiRes2Engine::init() {
Expand All @@ -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));

Expand Down

0 comments on commit 0a053e4

Please sign in to comment.