aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
Diffstat (limited to 'engines')
-rw-r--r--engines/adl/detection.cpp1
-rw-r--r--engines/adl/disk.cpp181
2 files changed, 179 insertions, 3 deletions
diff --git a/engines/adl/detection.cpp b/engines/adl/detection.cpp
index 41476303e5..4f898b574c 100644
--- a/engines/adl/detection.cpp
+++ b/engines/adl/detection.cpp
@@ -309,6 +309,7 @@ struct DiskImageExt {
};
const DiskImageExt diskImageExts[] = {
+ { Common::kPlatformApple2, ".woz" },
{ Common::kPlatformApple2, ".nib" },
{ Common::kPlatformApple2, ".dsk" },
{ Common::kPlatformApple2, ".d13" },
diff --git a/engines/adl/disk.cpp b/engines/adl/disk.cpp
index b78b709dfb..2e8e762f75 100644
--- a/engines/adl/disk.cpp
+++ b/engines/adl/disk.cpp
@@ -25,6 +25,7 @@
#include "common/memstream.h"
#include "common/md5.h"
#include "common/algorithm.h"
+#include "common/bitstream.h"
#include "adl/disk.h"
@@ -86,9 +87,6 @@ Common::SeekableReadStream *DataBlock_PC::createReadStream() const {
const uint kNibTrackLen = 256 * 26;
static bool detectDOS33(Common::SeekableReadStream &f, uint size) {
- if (f.size() != 232960)
- return false;
-
uint count = 0;
uint dos32 = 0, dos33 = 0;
uint32 window = 0;
@@ -331,9 +329,151 @@ static Common::SeekableReadStream *readImage_NIB(Common::File &f, bool dos33, ui
return new Common::MemoryReadStream(diskImage, imageSize, DisposeAfterUse::YES);
}
+static int getVersion_WOZ(Common::File &f) {
+ f.seek(0);
+ const uint32 fileId = f.readUint32BE();
+
+ if (f.eos() || f.err()) {
+ warning("WOZ: error reading '%s'", f.getName());
+ return 0;
+ }
+
+ if (fileId == MKTAG('W', 'O', 'Z', '1'))
+ return 1;
+ else if (fileId == MKTAG('W', 'O', 'Z', '2'))
+ return 2;
+
+ warning("WOZ: unsupported ID '%s' found in '%s'", tag2str(fileId), f.getName());
+ return 0;
+}
+
+static Common::SeekableReadStream *readTrack_WOZ(Common::File &f, uint track, bool woz2) {
+ f.seek(88 + track * 4);
+ const byte index = f.readByte();
+
+ if (index == 0xff) {
+ warning("WOZ: track %u not found in '%s', skipping", track, f.getName());
+ return nullptr;
+ }
+
+ uint32 offset, byteSize, bitSize;
+
+ if (woz2) {
+ f.seek(256 + index * 8);
+ offset = f.readUint16LE() << 9;
+ byteSize = f.readUint16LE() << 9;
+ bitSize = f.readUint32LE();
+ } else {
+ offset = 256 + index * 6656;
+ f.seek(offset + 6646);
+ byteSize = f.readUint16LE();
+ bitSize = f.readUint16LE();
+ }
+
+ f.seek(offset);
+
+ if (f.eos() || f.err() || byteSize == 0) {
+ warning("WOZ: failed to read track %u in '%s', aborting", track, f.getName());
+ return nullptr;
+ }
+
+ byte *inBuf = (byte *)malloc(byteSize);
+ byte *outBuf = (byte *)malloc(byteSize);
+ uint32 outSize = 0;
+ if (!inBuf || !outBuf) {
+ warning("WOZ: failed to create buffers of size %u for track %u in '%s'", byteSize, track, f.getName());
+ free(inBuf);
+ free(outBuf);
+ return nullptr;
+ }
+
+ if (f.read(inBuf, byteSize) < byteSize) {
+ warning("WOZ: error reading track %u in '%s'", track, f.getName());
+ free(inBuf);
+ free(outBuf);
+ return nullptr;
+ }
+
+ Common::BitStreamMemory8MSB bitStream(new Common::BitStreamMemoryStream(inBuf, byteSize, DisposeAfterUse::YES), DisposeAfterUse::YES);
+
+ byte nibble = 0;
+ bool stop = false;
+ for (;;) {
+ nibble = (nibble << 1) | bitStream.getBit();
+
+ if (nibble & 0x80) {
+ if (stop)
+ break;
+ nibble = 0;
+ }
+
+ if (bitStream.pos() == bitSize) {
+ bitStream.rewind();
+ if (stop) {
+ warning("WOZ: failed to find sync point for track %u in '%s'", track, f.getName());
+ break;
+ }
+ stop = true;
+ }
+ }
+
+ nibble = 0;
+ uint32 bitsRead = 0;
+ do {
+ nibble = (nibble << 1) | bitStream.getBit();
+ ++bitsRead;
+
+ if (nibble & 0x80) {
+ outBuf[outSize++] = nibble;
+ nibble = 0;
+ }
+
+ if (bitStream.pos() == bitSize)
+ bitStream.rewind();
+ } while (bitsRead < bitSize);
+
+ if (nibble != 0)
+ warning("WOZ: failed to sync track %u in '%s'", track, f.getName());
+
+ if (outSize == 0) {
+ warning("WOZ: track %u in '%s' is empty", track, f.getName());
+ free(outBuf);
+ return nullptr;
+ }
+
+ return new Common::MemoryReadStream(outBuf, outSize, DisposeAfterUse::YES);
+}
+
+static Common::SeekableReadStream *readImage_WOZ(Common::File &f, bool dos33, uint tracks = 35) {
+ int version = getVersion_WOZ(f);
+
+ if (version == 0)
+ return nullptr;
+
+ const uint sectorsPerTrack = (dos33 ? 16 : 13);
+ const uint imageSize = tracks * sectorsPerTrack * 256;
+ byte *const diskImage = (byte *)calloc(imageSize, 1);
+ Common::Array<bool> goodSectors(tracks * sectorsPerTrack);
+
+ for (uint track = 0; track < tracks; ++track) {
+ StreamPtr stream(readTrack_WOZ(f, track, version == 2));
+
+ if (stream) {
+ if (!decodeTrack(*stream, stream->size(), dos33, diskImage, tracks, goodSectors))
+ error("WOZ: error reading '%s'", f.getName());
+ }
+ }
+
+ printGoodSectors(goodSectors, sectorsPerTrack);
+
+ return new Common::MemoryReadStream(diskImage, imageSize, DisposeAfterUse::YES);
+}
+
bool DiskImage::open(const Common::String &filename) {
Common::File *f = new Common::File;
+ debug(1, "Opening '%s'", filename.c_str());
+
if (!f->open(filename)) {
warning("Failed to open '%s'", filename.c_str());
delete f;
@@ -365,6 +505,25 @@ bool DiskImage::open(const Common::String &filename) {
f->seek(0);
_stream = readImage_NIB(*f, _sectorsPerTrack == 16);
delete f;
+ } else if (lcName.hasSuffix(".woz")) {
+ _tracks = 35;
+ _sectorsPerTrack = 13;
+ _bytesPerSector = 256;
+
+ int version = getVersion_WOZ(*f);
+
+ if (version > 0) {
+ StreamPtr bitStream(readTrack_WOZ(*f, 0, version == 2));
+ if (bitStream) {
+ if (detectDOS33(*bitStream, bitStream->size()))
+ _sectorsPerTrack = 16;
+ _stream = readImage_WOZ(*f, _sectorsPerTrack == 16);
+ } else {
+ warning("WOZ: failed to load bitstream for track 0 in '%s'", f->getName());
+ }
+ }
+
+ delete f;
} else if (lcName.hasSuffix(".xfd")) {
_tracks = 40;
_sectorsPerTrack = 18;
@@ -447,6 +606,22 @@ int32 computeMD5(const Common::FSNode &node, Common::String &md5, uint32 md5Byte
}
return -1;
+ } else if (node.getName().matchString("*.woz", true)) {
+ int version = getVersion_WOZ(f);
+
+ if (version > 0) {
+ StreamPtr bitStream(readTrack_WOZ(f, 0, version == 2));
+ if (bitStream) {
+ bool isDOS33 = detectDOS33(*bitStream, bitStream->size());
+ StreamPtr stream(readImage_WOZ(f, isDOS33, tracks));
+ if (stream) {
+ md5 = Common::computeStreamMD5AsString(*stream, md5Bytes);
+ return 35 * (isDOS33 ? 16 : 13) * 256;
+ }
+ }
+ }
+
+ return -1;
} else {
md5 = Common::computeStreamMD5AsString(f, md5Bytes);
return f.size();