[Scummvm-git-logs] scummvm master -> c0a515bcf8d5b9bf70f08addace21c29a1c53cde
waltervn
walter at vanniftrik-it.nl
Fri Jul 19 14:36:12 CEST 2019
This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
82ed1475f1 ADL: Refactor .NIB floppy image reading
c0a515bcf8 ADL: Add support for .WOZ floppy images
Commit: 82ed1475f1686ca3c7b0daefc7810a5bb280a61a
https://github.com/scummvm/scummvm/commit/82ed1475f1686ca3c7b0daefc7810a5bb280a61a
Author: Walter van Niftrik (walter at scummvm.org)
Date: 2019-07-19T14:24:43+02:00
Commit Message:
ADL: Refactor .NIB floppy image reading
Changed paths:
engines/adl/disk.cpp
diff --git a/engines/adl/disk.cpp b/engines/adl/disk.cpp
index 5ee9b26..b78b709 100644
--- a/engines/adl/disk.cpp
+++ b/engines/adl/disk.cpp
@@ -83,9 +83,9 @@ Common::SeekableReadStream *DataBlock_PC::createReadStream() const {
return new Common::MemoryReadStream(buf, blockSize, DisposeAfterUse::YES);
}
-const uint trackLen = 256 * 26;
+const uint kNibTrackLen = 256 * 26;
-static bool detectDOS33_NIB(Common::SeekableReadStream &f) {
+static bool detectDOS33(Common::SeekableReadStream &f, uint size) {
if (f.size() != 232960)
return false;
@@ -93,7 +93,7 @@ static bool detectDOS33_NIB(Common::SeekableReadStream &f) {
uint dos32 = 0, dos33 = 0;
uint32 window = 0;
- while (count++ < trackLen) {
+ while (count++ < size) {
window &= 0xffff;
window <<= 8;
window |= f.readByte();
@@ -110,21 +110,21 @@ static bool detectDOS33_NIB(Common::SeekableReadStream &f) {
return dos33 > dos32;
}
-static bool readSector_NIB(byte outBuf[], const byte inBuf[], uint size, uint &pos, const byte minNibble, const byte lookup[], const uint track, const uint sector) {
- uint z = trackLen - (pos % trackLen);
- if (z < size) {
- memcpy(outBuf, inBuf + (pos % trackLen), z);
- memcpy(outBuf + z, inBuf, size - z);
+static bool readSector_NIB(byte outBuf[], uint outBufSize, const byte inBuf[], uint inBufSize, uint &pos, const byte minNibble, const byte lookup[], const uint track, const uint sector) {
+ uint z = inBufSize - (pos % inBufSize);
+ if (z < outBufSize) {
+ memcpy(outBuf, inBuf + (pos % inBufSize), z);
+ memcpy(outBuf + z, inBuf, outBufSize - z);
} else
- memcpy(outBuf, inBuf + (pos % trackLen), size);
- pos += size;
+ memcpy(outBuf, inBuf + (pos % inBufSize), outBufSize);
+ pos += outBufSize;
byte oldVal = 0;
- for (uint n = 0; n < size; ++n) {
+ for (uint n = 0; n < outBufSize; ++n) {
// expand
if (outBuf[n] == 0xd5) {
// Early end of block.
- pos -= (size - n);
+ pos -= (outBufSize - n);
debug(2, "NIB: early end of block @ %x (%d, %d)", n, track, sector);
return false;
}
@@ -136,7 +136,7 @@ static bool readSector_NIB(byte outBuf[], const byte inBuf[], uint size, uint &p
if (val == 0x40) {
// Badly-encoded nibbles, stop trying to decode here.
- pos -= (size - n);
+ pos -= (outBufSize - n);
debug(2, "NIB: bad nibble %02x @ %x (%d, %d)", outBuf[n], n, track, sector);
return false;
}
@@ -146,7 +146,7 @@ static bool readSector_NIB(byte outBuf[], const byte inBuf[], uint size, uint &p
outBuf[n] = oldVal;
}
- byte checksum = inBuf[pos++ % trackLen];
+ byte checksum = inBuf[pos++ % inBufSize];
if (checksum < minNibble || oldVal != lookup[checksum - minNibble]) {
debug(2, "NIB: checksum mismatch @ (%d, %d)", track, sector);
return false;
@@ -156,18 +156,13 @@ static bool readSector_NIB(byte outBuf[], const byte inBuf[], uint size, uint &p
}
// 4-and-4 encoding (odd-even)
-static uint8 read44(byte *buffer, uint &pos) {
+static uint8 read44(byte *buffer, uint size, uint &pos) {
// 1s in the other fields, so we can just AND
- uint8 ret = buffer[pos++ % trackLen];
- return ((ret << 1) | 1) & buffer[pos++ % trackLen];
+ uint8 ret = buffer[pos++ % size];
+ return ((ret << 1) | 1) & buffer[pos++ % size];
}
-static Common::SeekableReadStream *readImage_NIB(Common::File &f, bool dos33, uint tracks = 35) {
- if (f.size() != 35 * trackLen) {
- warning("NIB: image '%s' has invalid size of %d bytes", f.getName(), f.size());
- return nullptr;
- }
-
+static bool decodeTrack(Common::SeekableReadStream &stream, uint trackLen, bool dos33, byte *const diskImage, uint tracks, Common::Array<bool> &goodSectors) {
// starting at 0xaa, 64 is invalid (see below)
const byte c_5and3_lookup[] = { 64, 0, 64, 1, 2, 3, 64, 64, 64, 64, 64, 4, 5, 6, 64, 64, 7, 8, 64, 9, 10, 11, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 12, 13, 64, 64, 14, 15, 64, 16, 17, 18, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 19, 20, 64, 21, 22, 23, 64, 64, 64, 64, 64, 24, 25, 26, 64, 64, 27, 28, 64, 29, 30, 31 };
// starting at 0x96, 64 is invalid (see below)
@@ -175,32 +170,22 @@ static Common::SeekableReadStream *readImage_NIB(Common::File &f, bool dos33, ui
const uint sectorsPerTrack = (dos33 ? 16 : 13);
const uint bytesPerSector = 256;
- const uint imageSize = tracks * sectorsPerTrack * bytesPerSector;
- byte *const diskImage = (byte *)calloc(imageSize, 1);
bool sawAddress = false;
uint8 volNo = 0, track = 0, sector = 0;
- byte buffer[trackLen];
- Common::Array<bool> goodSectors(tracks * sectorsPerTrack);
+ byte *const buffer = (byte *)malloc(trackLen);
uint firstGoodTrackPos = 0;
- uint pos = trackLen; // force read
-
- while (true) {
- if (pos >= trackLen+firstGoodTrackPos) {
- if (f.pos() == (int)(tracks * trackLen))
- break;
+ uint pos = 0;
- if (f.read(buffer, sizeof(buffer)) < sizeof(buffer)) {
- warning("NIB: error reading '%s'", f.getName());
- free(diskImage);
- return nullptr;
- }
+ if (stream.read(buffer, trackLen) < trackLen) {
+ free(buffer);
+ return false;
+ }
- firstGoodTrackPos = 0;
- pos = 0;
- sawAddress = false;
- }
+ while (true) {
+ if (pos >= trackLen + firstGoodTrackPos)
+ break;
// Read until we find two sync bytes.
if (buffer[pos++ % trackLen] != 0xd5 || buffer[pos++ % trackLen] != 0xaa)
@@ -224,10 +209,10 @@ static Common::SeekableReadStream *readImage_NIB(Common::File &f, bool dos33, ui
continue;
}
- volNo = read44(buffer, pos);
- track = read44(buffer, pos);
- sector = read44(buffer, pos);
- uint8 checksum = read44(buffer, pos);
+ volNo = read44(buffer, trackLen, pos);
+ track = read44(buffer, trackLen, pos);
+ sector = read44(buffer, trackLen, pos);
+ uint8 checksum = read44(buffer, trackLen, pos);
if ((volNo ^ track ^ sector) != checksum) {
debug(2, "NIB: invalid checksum (volNo %d, track %d, sector %d)", volNo, track, sector);
sawAddress = false;
@@ -261,7 +246,7 @@ static Common::SeekableReadStream *readImage_NIB(Common::File &f, bool dos33, ui
byte inbuffer[342];
- if (!readSector_NIB(inbuffer, buffer, sizeof(inbuffer), pos, 0x96, c_6and2_lookup, track, sector))
+ if (!readSector_NIB(inbuffer, sizeof(inbuffer), buffer, trackLen, pos, 0x96, c_6and2_lookup, track, sector))
continue;
for (uint n = 0; n < 256; ++n) {
@@ -281,7 +266,7 @@ static Common::SeekableReadStream *readImage_NIB(Common::File &f, bool dos33, ui
// 5-and-3 uses 410 on-disk bytes, decoding to just over 256 bytes
byte inbuffer[410];
- if (!readSector_NIB(inbuffer, buffer, sizeof(inbuffer), pos, 0xaa, c_5and3_lookup, track, sector))
+ if (!readSector_NIB(inbuffer, sizeof(inbuffer), buffer, trackLen, pos, 0xaa, c_5and3_lookup, track, sector))
continue;
// 8 bytes of nibbles expand to 5 bytes
@@ -305,6 +290,11 @@ static Common::SeekableReadStream *readImage_NIB(Common::File &f, bool dos33, ui
goodSectors[track * sectorsPerTrack + sector] = true;
}
+ free(buffer);
+ return true;
+}
+
+static void printGoodSectors(Common::Array<bool> &goodSectors, uint sectorsPerTrack) {
if (Common::find(goodSectors.begin(), goodSectors.end(), false) != goodSectors.end()) {
debugN(1, "NIB: Bad/missing sectors:");
@@ -315,6 +305,28 @@ static Common::SeekableReadStream *readImage_NIB(Common::File &f, bool dos33, ui
debugN(1, "\n");
}
+}
+
+static Common::SeekableReadStream *readImage_NIB(Common::File &f, bool dos33, uint tracks = 35) {
+ if (f.size() != 35 * kNibTrackLen) {
+ warning("NIB: image '%s' has invalid size of %d bytes", f.getName(), f.size());
+ 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) {
+ if (!decodeTrack(f, kNibTrackLen, dos33, diskImage, tracks, goodSectors)) {
+ warning("NIB: error reading '%s'", f.getName());
+ free(diskImage);
+ return nullptr;
+ }
+ }
+
+ printGoodSectors(goodSectors, sectorsPerTrack);
return new Common::MemoryReadStream(diskImage, imageSize, DisposeAfterUse::YES);
}
@@ -344,7 +356,7 @@ bool DiskImage::open(const Common::String &filename) {
} else if (lcName.hasSuffix(".nib")) {
_tracks = 35;
- if (detectDOS33_NIB(*f))
+ if (detectDOS33(*f, kNibTrackLen))
_sectorsPerTrack = 16;
else
_sectorsPerTrack = 13;
@@ -421,19 +433,10 @@ int32 computeMD5(const Common::FSNode &node, Common::String &md5, uint32 md5Byte
if (!f.open(node))
return -1;
- if (node.getName().matchString("*.nib", true) && f.size() == 35 * trackLen) {
- uint lastSector = md5Bytes / 256;
- uint tracks;
- bool isDOS33 = detectDOS33_NIB(f);
-
- if (isDOS33)
- tracks = (lastSector / 16) + 1;
- else
- tracks = (lastSector / 13) + 1;
+ const uint tracks = md5Bytes / (13 * 256) + 1;
- // Tracks 1 and 2 are swapped in some copy protections, so we read three tracks when two tracks are needed
- if (tracks == 2)
- tracks = 3;
+ if (node.getName().matchString("*.nib", true) && f.size() == 35 * kNibTrackLen) {
+ bool isDOS33 = detectDOS33(f, kNibTrackLen);
f.seek(0);
Common::SeekableReadStream *stream = readImage_NIB(f, isDOS33, tracks);
Commit: c0a515bcf8d5b9bf70f08addace21c29a1c53cde
https://github.com/scummvm/scummvm/commit/c0a515bcf8d5b9bf70f08addace21c29a1c53cde
Author: Walter van Niftrik (walter at scummvm.org)
Date: 2019-07-19T14:24:43+02:00
Commit Message:
ADL: Add support for .WOZ floppy images
Changed paths:
engines/adl/detection.cpp
engines/adl/disk.cpp
diff --git a/engines/adl/detection.cpp b/engines/adl/detection.cpp
index 4147630..4f898b5 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 b78b709..2e8e762 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();
More information about the Scummvm-git-logs
mailing list