ADL: Add support for Serenia data blocks

This commit is contained in:
Walter van Niftrik 2017-08-12 12:02:26 +02:00
parent 14bfe02b81
commit e937838b91
2 changed files with 92 additions and 10 deletions

View File

@ -30,6 +30,59 @@
namespace Adl {
void DataBlock_PC::read(Common::SeekableReadStream &stream, byte *const dataPtr, const uint32 size) const {
uint32 ofs = 0;
while (ofs < size) {
const uint bps = _disk->getBytesPerSector();
uint bytesToRead = bps - ((_offset + stream.pos()) % bps);
if (bytesToRead == bps) {
stream.readByte(); // Skip volume byte
--bytesToRead;
}
if (bytesToRead > size - ofs)
bytesToRead = size - ofs;
if (stream.read(dataPtr + ofs, bytesToRead) < bytesToRead)
error("Failed to read data block");
ofs += bytesToRead;
}
}
Common::SeekableReadStream *DataBlock_PC::createReadStream() const {
const uint bps = _disk->getBytesPerSector();
uint sectors = 0;
// Every data sector starts with a volume byte that we need to skip,
// so we need to take that into account during our computations here
if (_offset == bps - 1)
sectors = 1;
StreamPtr diskStream(_disk->createReadStream(_track, _sector, _offset, sectors));
byte sizeBuf[2];
read(*diskStream, sizeBuf, 2);
uint16 blockSize = READ_LE_UINT16(sizeBuf);
sectors = 0;
const uint16 remSize = _disk->getBytesPerSector() - MAX<uint>(_offset, 1);
if (blockSize + 2 > remSize)
sectors = (blockSize + 2 - remSize - 1) / (_disk->getBytesPerSector() - 1) + 1;
diskStream.reset(_disk->createReadStream(_track, _sector, _offset, sectors));
read(*diskStream, sizeBuf, 2);
byte *buf = static_cast<byte *>(malloc(blockSize));
read(*diskStream, buf, blockSize);
return new Common::MemoryReadStream(buf, blockSize, DisposeAfterUse::YES);
}
const uint trackLen = 256 * 26;
static bool detectDOS33_NIB(Common::SeekableReadStream &f) {
@ -309,6 +362,7 @@ bool DiskImage::open(const Common::String &filename) {
_tracks = 40;
_sectorsPerTrack = 8;
_bytesPerSector = 512;
_firstSector = 1;
_stream = f;
}
@ -335,8 +389,10 @@ Common::SeekableReadStream *DiskImage::createReadStream(uint track, uint sector,
if (sectorLimit == 0)
sectorLimit = _sectorsPerTrack;
if (sector >= sectorLimit)
error("Sector %i is out of bounds for %i-sector reading", sector, sectorLimit);
if (sector < _firstSector || sector >= sectorLimit + _firstSector)
error("Sector %u is out of bounds for %u-sector %u-based reading", sector, sectorLimit, _firstSector);
sector -= _firstSector;
while (dataOffset < bytesToRead) {
uint bytesRemInTrack = (sectorLimit - 1 - sector) * _bytesPerSector + _bytesPerSector - offset;

View File

@ -62,7 +62,7 @@ protected:
_filename(filename),
_offset(offset) { }
Common::SeekableReadStream *createReadStream() const {
Common::SeekableReadStream *createReadStream() const override {
return _files->createReadStream(_filename, _offset);
}
@ -80,7 +80,8 @@ public:
_tracks(0),
_sectorsPerTrack(0),
_bytesPerSector(0),
_sectorLimit(0) { }
_sectorLimit(0),
_firstSector(0) { }
~DiskImage() {
delete _stream;
@ -105,7 +106,7 @@ protected:
_sectorLimit(sectorLimit),
_disk(disk) { }
Common::SeekableReadStream *createReadStream() const {
Common::SeekableReadStream *createReadStream() const override {
return _disk->createReadStream(_track, _sector, _offset, _size, _sectorLimit);
}
@ -116,15 +117,15 @@ protected:
};
Common::SeekableReadStream *_stream;
uint _tracks, _sectorsPerTrack, _bytesPerSector;
uint _tracks, _sectorsPerTrack, _bytesPerSector, _firstSector;
uint _sectorLimit;
};
// Data in plain files
class Files_Plain : public Files {
public:
const DataBlockPtr getDataBlock(const Common::String &filename, uint offset = 0) const;
Common::SeekableReadStream *createReadStream(const Common::String &filename, uint offset = 0) const;
const DataBlockPtr getDataBlock(const Common::String &filename, uint offset = 0) const override;
Common::SeekableReadStream *createReadStream(const Common::String &filename, uint offset = 0) const override;
};
// Data in files contained in Apple DOS 3.3 disk image
@ -134,8 +135,8 @@ public:
~Files_AppleDOS();
bool open(const Common::String &filename, uint trackVTOC = 17);
const DataBlockPtr getDataBlock(const Common::String &filename, uint offset = 0) const;
Common::SeekableReadStream *createReadStream(const Common::String &filename, uint offset = 0) const;
const DataBlockPtr getDataBlock(const Common::String &filename, uint offset = 0) const override;
Common::SeekableReadStream *createReadStream(const Common::String &filename, uint offset = 0) const override;
private:
enum FileType {
@ -169,6 +170,31 @@ private:
Common::HashMap<Common::String, TOCEntry> _toc;
};
// On the Apple II, sector headers contain a disk volume number. This number
// is used by ADL multi-disk games. The PC port has the disk volume number
// as the first data byte of every sector that contains game data. We need
// to skip this number as we read in the data. Additionally, the data is now
// prefixed with an uint16 containing the data size.
class DataBlock_PC : public DataBlock {
public:
DataBlock_PC(DiskImage *disk, byte track, byte sector, uint16 offset = 0) :
_disk(disk),
_track(track),
_sector(sector),
_offset(offset) { }
virtual ~DataBlock_PC() { }
Common::SeekableReadStream *createReadStream() const override;
private:
void read(Common::SeekableReadStream &stream, byte *const dataPtr, const uint32 size) const;
DiskImage *_disk;
byte _track, _sector;
uint16 _offset;
};
} // End of namespace Adl
#endif