aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWalter van Niftrik2016-03-24 19:01:01 +0100
committerWalter van Niftrik2016-06-06 20:35:49 +0200
commit71ca8de7e65d535e97d87bb1d30cbc1d9098cc07 (patch)
treea7c9d3cf722dd2cfcb1bef1a316202abce12ffd4
parent3b67b07364616548e0fdc9809bdb503ba7faad88 (diff)
downloadscummvm-rg350-71ca8de7e65d535e97d87bb1d30cbc1d9098cc07.tar.gz
scummvm-rg350-71ca8de7e65d535e97d87bb1d30cbc1d9098cc07.tar.bz2
scummvm-rg350-71ca8de7e65d535e97d87bb1d30cbc1d9098cc07.zip
ADL: Add support for Apple DOS 3.3 disk images
-rw-r--r--engines/adl/disk.cpp187
-rw-r--r--engines/adl/disk.h46
2 files changed, 227 insertions, 6 deletions
diff --git a/engines/adl/disk.cpp b/engines/adl/disk.cpp
index e2c3da3d5c..b7de55a78e 100644
--- a/engines/adl/disk.cpp
+++ b/engines/adl/disk.cpp
@@ -22,6 +22,7 @@
#include "common/stream.h"
#include "common/substream.h"
+#include "common/memstream.h"
#include "adl/disk.h"
@@ -80,12 +81,11 @@ bool DiskImage_DSK::open(const Common::String &filename) {
_tracks = 35;
_sectorsPerTrack = 16;
_bytesPerSector = 256;
- break;
- default:
- warning("Unrecognized disk image '%s' of size %d bytes", filename.c_str(), filesize);
+ return true;
}
- return true;
+ warning("Unrecognized disk image '%s' of size %d bytes", filename.c_str(), filesize);
+ return false;
}
Common::SeekableReadStream *FilesDataBlock::createReadStream() const {
@@ -108,4 +108,183 @@ Common::SeekableReadStream *PlainFiles::createReadStream(const Common::String &f
return new Common::SeekableSubReadStream(f, offset, f->size(), DisposeAfterUse::YES);
}
+Files_DOS33::~Files_DOS33() {
+ delete _disk;
+}
+
+Files_DOS33::Files_DOS33() :
+ _disk(nullptr) {
+}
+
+void Files_DOS33::readSectorList(TrackSector start, Common::Array<TrackSector> &list) {
+ TrackSector index = start;
+
+ while (index.track != 0) {
+ Common::ScopedPtr<Common::SeekableReadStream> stream(_disk->createReadStream(index.track, index.sector));
+
+ stream->readByte();
+ index.track = stream->readByte();
+ index.sector = stream->readByte();
+
+ stream->seek(9, SEEK_CUR);
+
+ // This only handles sequential files
+ TrackSector ts;
+ ts.track = stream->readByte();
+ ts.sector = stream->readByte();
+
+ while (ts.track != 0) {
+ list.push_back(ts);
+
+ ts.track = stream->readByte();
+ ts.sector = stream->readByte();
+
+ if (stream->err())
+ error("Error reading sector list");
+
+ if (stream->eos())
+ break;
+ }
+ }
+}
+
+void Files_DOS33::readVTOC() {
+ Common::ScopedPtr<Common::SeekableReadStream> stream(_disk->createReadStream(0x11, 0x00));
+ stream->readByte();
+ byte track = stream->readByte();
+ byte sector = stream->readByte();
+
+ while (track != 0) {
+ char name[kFilenameLen + 1] = { };
+
+ stream.reset(_disk->createReadStream(track, sector));
+ stream->readByte();
+ track = stream->readByte();
+ sector = stream->readByte();
+ stream->seek(8, SEEK_CUR);
+
+ for (uint i = 0; i < 7; ++i) {
+ TOCEntry entry;
+ TrackSector sectorList;
+ sectorList.track = stream->readByte();
+ sectorList.sector = stream->readByte();
+ entry.type = stream->readByte();
+ stream->read(name, kFilenameLen);
+
+ // Convert to ASCII
+ for (uint j = 0; j < kFilenameLen; j++)
+ name[j] &= 0x7f;
+
+ // Strip trailing spaces
+ for (int j = kFilenameLen - 1; j >= 0; --j) {
+ if (name[j] == ' ')
+ name[j] = 0;
+ else
+ break;
+ }
+
+ entry.totalSectors = stream->readUint16BE();
+
+ if (sectorList.track != 0) {
+ readSectorList(sectorList, entry.sectors);
+ _toc[name] = entry;
+ }
+ }
+ }
+}
+
+const DataBlockPtr Files_DOS33::getDataBlock(const Common::String &filename, uint offset) const {
+ return Common::SharedPtr<FilesDataBlock>(new FilesDataBlock(this, filename, offset));
+}
+
+Common::SeekableReadStream *Files_DOS33::createReadStreamText(const TOCEntry &entry) const {
+ byte *buf = (byte *)malloc(entry.sectors.size() * kSectorSize);
+ byte *p = buf;
+
+ for (uint i = 0; i < entry.sectors.size(); ++i) {
+ Common::ScopedPtr<Common::SeekableReadStream> stream(_disk->createReadStream(entry.sectors[i].track, entry.sectors[i].sector));
+
+ assert(stream->size() == kSectorSize);
+
+ while (true) {
+ byte textChar = stream->readByte();
+
+ if (stream->eos() || textChar == 0)
+ break;
+
+ if (stream->err())
+ error("Error reading text file");
+
+ *p++ = textChar;
+ }
+ }
+
+ return new Common::MemoryReadStream(buf, p - buf, DisposeAfterUse::YES);
+}
+
+Common::SeekableReadStream *Files_DOS33::createReadStreamBinary(const TOCEntry &entry) const {
+ byte *buf = (byte *)malloc(entry.sectors.size() * kSectorSize);
+
+ Common::ScopedPtr<Common::SeekableReadStream> stream(_disk->createReadStream(entry.sectors[0].track, entry.sectors[0].sector));
+
+ if (entry.type == kFileTypeBinary)
+ stream->readUint16LE(); // Skip start address
+
+ uint16 size = stream->readUint16LE();
+ uint16 offset = 0;
+ uint16 sectorIdx = 1;
+
+ while (true) {
+ offset += stream->read(buf + offset, size - offset);
+
+ if (offset == size)
+ break;
+
+ if (stream->err())
+ error("Error reading binary file");
+
+ assert(stream->eos());
+
+ if (sectorIdx == entry.sectors.size())
+ error("Not enough sectors for binary file size");
+
+ stream.reset(_disk->createReadStream(entry.sectors[sectorIdx].track, entry.sectors[sectorIdx].sector));
+ ++sectorIdx;
+ }
+
+ return new Common::MemoryReadStream(buf, size, DisposeAfterUse::YES);
+}
+
+Common::SeekableReadStream *Files_DOS33::createReadStream(const Common::String &filename, uint offset) const {
+ if (!_toc.contains(filename))
+ error("Failed to locate '%s'", filename.c_str());
+
+ const TOCEntry &entry = _toc[filename];
+
+ Common::SeekableReadStream *stream;
+
+ switch(entry.type) {
+ case kFileTypeText:
+ stream = createReadStreamText(entry);
+ break;
+ case kFileTypeAppleSoft:
+ case kFileTypeBinary:
+ stream = createReadStreamBinary(entry);
+ break;
+ default:
+ error("Unsupported file type %i", entry.type);
+ }
+
+ return new Common::SeekableSubReadStream(stream, offset, stream->size(), DisposeAfterUse::YES);
+}
+
+bool Files_DOS33::open(const Common::String &filename) {
+ _disk = new DiskImage_DSK();
+ if (!_disk->open(filename))
+ return false;
+
+ readVTOC();
+ return true;
+}
+
} // End of namespace Adl
diff --git a/engines/adl/disk.h b/engines/adl/disk.h
index b6a5c60262..799fa371df 100644
--- a/engines/adl/disk.h
+++ b/engines/adl/disk.h
@@ -22,6 +22,7 @@
#include "common/ptr.h"
#include "common/file.h"
+#include "common/debug.h"
#ifndef ADL_DISK_H
#define ADL_DISK_H
@@ -47,8 +48,8 @@ class Files {
public:
virtual ~Files() { }
- virtual const DataBlockPtr getDataBlock(const Common::String &filename, uint offset) const = 0;
- virtual Common::SeekableReadStream *createReadStream(const Common::String &filename, uint offset) const = 0;
+ virtual const DataBlockPtr getDataBlock(const Common::String &filename, uint offset = 0) const = 0;
+ virtual Common::SeekableReadStream *createReadStream(const Common::String &filename, uint offset = 0) const = 0;
};
class FilesDataBlock : public DataBlock {
@@ -103,6 +104,47 @@ public:
Common::SeekableReadStream *createReadStream(uint track, uint sector, uint offset = 0, uint size = 0) const;
};
+class Files_DOS33 : public Files {
+public:
+ Files_DOS33();
+ ~Files_DOS33();
+
+ bool open(const Common::String &filename);
+ const DataBlockPtr getDataBlock(const Common::String &filename, uint offset = 0) const;
+ Common::SeekableReadStream *createReadStream(const Common::String &filename, uint offset = 0) const;
+
+private:
+ enum FileType {
+ kFileTypeText = 0,
+ kFileTypeAppleSoft = 2,
+ kFileTypeBinary = 4
+ };
+
+ enum {
+ kSectorSize = 256,
+ kFilenameLen = 30
+ };
+
+ struct TrackSector {
+ byte track;
+ byte sector;
+ };
+
+ struct TOCEntry {
+ byte type;
+ uint16 totalSectors;
+ Common::Array<TrackSector> sectors;
+ };
+
+ void readVTOC();
+ void readSectorList(TrackSector start, Common::Array<TrackSector> &list);
+ Common::SeekableReadStream *createReadStreamText(const TOCEntry &entry) const;
+ Common::SeekableReadStream *createReadStreamBinary(const TOCEntry &entry) const;
+
+ DiskImage_DSK *_disk;
+ Common::HashMap<Common::String, TOCEntry> _toc;
+};
+
} // End of namespace Adl
#endif