aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/adl/disk.cpp60
-rw-r--r--engines/adl/disk.h42
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