diff options
-rw-r--r-- | engines/adl/disk.cpp | 60 | ||||
-rw-r--r-- | engines/adl/disk.h | 42 |
2 files changed, 92 insertions, 10 deletions
diff --git a/engines/adl/disk.cpp b/engines/adl/disk.cpp index b2746bcee7..5ee9b268ae 100644 --- a/engines/adl/disk.cpp +++ b/engines/adl/disk.cpp @@ -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; diff --git a/engines/adl/disk.h b/engines/adl/disk.h index a13c2eeb47..97b66a9a9e 100644 --- a/engines/adl/disk.h +++ b/engines/adl/disk.h @@ -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 |