mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-05 17:20:30 +00:00
ADL: Refactor disk image handling
This commit is contained in:
parent
9f479c9b17
commit
23870196f5
@ -28,25 +28,9 @@
|
||||
|
||||
namespace Adl {
|
||||
|
||||
static Common::SeekableReadStream *readImage(const Common::String &filename) {
|
||||
Common::File *f = new Common::File;
|
||||
|
||||
if (!f->open(filename)) {
|
||||
delete f;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
static bool detectDOS33_NIB(const Common::String &filename) {
|
||||
Common::File f;
|
||||
|
||||
if (!f.open(filename))
|
||||
error("Failed to open '%s'", filename.c_str());
|
||||
|
||||
static bool detectDOS33_NIB(Common::SeekableReadStream &f) {
|
||||
if (f.size() != 232960)
|
||||
error("Unrecognized NIB image '%s' of size %d bytes", filename.c_str(), f.size());
|
||||
return false;
|
||||
|
||||
uint count = 0;
|
||||
uint dos32 = 0, dos33 = 0;
|
||||
@ -58,7 +42,7 @@ static bool detectDOS33_NIB(const Common::String &filename) {
|
||||
window |= f.readByte();
|
||||
|
||||
if (f.err() || f.eos())
|
||||
error("Failed to read '%s'", filename.c_str());
|
||||
return false;
|
||||
|
||||
if (window == 0xd5aa96)
|
||||
++dos33;
|
||||
@ -66,13 +50,51 @@ static bool detectDOS33_NIB(const Common::String &filename) {
|
||||
++dos32;
|
||||
}
|
||||
|
||||
f.close();
|
||||
|
||||
return dos33 > dos32;
|
||||
}
|
||||
|
||||
const uint trackLen = 256 * 26;
|
||||
|
||||
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);
|
||||
} else
|
||||
memcpy(outBuf, inBuf + (pos % trackLen), size);
|
||||
pos += size;
|
||||
|
||||
byte oldVal = 0;
|
||||
for (uint n = 0; n < size; ++n) {
|
||||
// expand
|
||||
assert(outBuf[n] >= minNibble); // corrupt file (TODO: assert?)
|
||||
if (outBuf[n] == 0xd5) {
|
||||
// Early end of block.
|
||||
pos -= (size - n);
|
||||
warning("NIB: early end of block @ %x (%d, %d)", n, track, sector);
|
||||
return false;
|
||||
}
|
||||
byte val = lookup[outBuf[n] - minNibble];
|
||||
if (val == 0x40) {
|
||||
// Badly-encoded nibbles, stop trying to decode here.
|
||||
pos -= (size - n);
|
||||
warning("NIB: bad nibble %02x @ %x (%d, %d)", outBuf[n], n, track, sector);
|
||||
return false;
|
||||
}
|
||||
// undo checksum
|
||||
oldVal = val ^ oldVal;
|
||||
outBuf[n] = oldVal;
|
||||
}
|
||||
|
||||
byte checksum = inBuf[pos++ % trackLen];
|
||||
if (checksum < minNibble || oldVal != lookup[checksum - minNibble]) {
|
||||
warning("NIB: checksum mismatch @ (%d, %d)", track, sector);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 4-and-4 encoding (odd-even)
|
||||
static uint8 read44(byte *buffer, uint &pos) {
|
||||
// 1s in the other fields, so we can just AND
|
||||
@ -80,17 +102,14 @@ static uint8 read44(byte *buffer, uint &pos) {
|
||||
return ((ret << 1) | 1) & buffer[pos++ % trackLen];
|
||||
}
|
||||
|
||||
static Common::SeekableReadStream *readImage_NIB(const Common::String &filename, bool dos33) {
|
||||
Common::File f;
|
||||
|
||||
if (!f.open(filename))
|
||||
static Common::SeekableReadStream *readImage_NIB(Common::File &f, bool dos33) {
|
||||
if (f.size() != 232960) {
|
||||
warning("NIB: image '%s' has invalid size of %d bytes", f.getName(), f.size());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (f.size() != 232960)
|
||||
error("Unrecognized NIB image '%s' of size %d bytes", filename.c_str(), f.size());
|
||||
|
||||
// starting at 0xaa, 32 is invalid (see below)
|
||||
const byte c_5and3_lookup[] = { 32, 0, 32, 1, 2, 3, 32, 32, 32, 32, 32, 4, 5, 6, 32, 32, 7, 8, 32, 9, 10, 11, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 12, 13, 32, 32, 14, 15, 32, 16, 17, 18, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 19, 20, 32, 21, 22, 23, 32, 32, 32, 32, 32, 24, 25, 26, 32, 32, 27, 28, 32, 29, 30, 31 };
|
||||
// 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)
|
||||
const byte c_6and2_lookup[] = { 0, 1, 64, 64, 2, 3, 64, 4, 5, 6, 64, 64, 64, 64, 64, 64, 7, 8, 64, 64, 64, 9, 10, 11, 12, 13, 64, 64, 14, 15, 16, 17, 18, 19, 64, 20, 21, 22, 23, 24, 25, 26, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 27, 64, 28, 29, 30, 64, 64, 64, 31, 64, 64, 32, 33, 64, 34, 35, 36, 37, 38, 39, 40, 64, 64, 64, 64, 64, 41, 42, 43, 64, 44, 45, 46, 47, 48, 49, 50, 64, 64, 51, 52, 53, 54, 55, 56, 64, 57, 58, 59, 60, 61, 62, 63 };
|
||||
|
||||
@ -132,12 +151,10 @@ static Common::SeekableReadStream *readImage_NIB(const Common::String &filename,
|
||||
// We should always find the address field first.
|
||||
if (prologue != (dos33 ? 0x96 : 0xb5)) {
|
||||
// Accept a DOS 3.3(?) header at the start.
|
||||
if (prologue == (dos33 ? 0xb5 : 0x96) || prologue == 0xad || prologue == 0xfd) {
|
||||
sawAddress = false;
|
||||
continue;
|
||||
} else {
|
||||
error("unknown NIB field prologue %02x", prologue);
|
||||
}
|
||||
if (prologue != (dos33 ? 0xb5 : 0x96) && prologue != 0xad && prologue != 0xfd)
|
||||
warning("NIB: unknown field prologue %02x", prologue);
|
||||
sawAddress = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
volNo = read44(buffer, pos);
|
||||
@ -145,7 +162,7 @@ static Common::SeekableReadStream *readImage_NIB(const Common::String &filename,
|
||||
sector = read44(buffer, pos);
|
||||
uint8 checksum = read44(buffer, pos);
|
||||
if ((volNo ^ track ^ sector) != checksum) {
|
||||
warning("invalid NIB checksum (volNo %d, track %d, sector %d)", volNo, track, sector);
|
||||
warning("NIB: invalid checksum (volNo %d, track %d, sector %d)", volNo, track, sector);
|
||||
sawAddress = false;
|
||||
continue;
|
||||
}
|
||||
@ -175,34 +192,10 @@ static Common::SeekableReadStream *readImage_NIB(const Common::String &filename,
|
||||
sector = raw2dos[sector];
|
||||
output = diskImage + (track * sectorsPerTrack + sector) * bytesPerSector;
|
||||
|
||||
// 6-and-2 uses 342 on-disk bytes
|
||||
byte inbuffer[342];
|
||||
uint z = trackLen - (pos % trackLen);
|
||||
if (z < 342) {
|
||||
memcpy(inbuffer, buffer + (pos % trackLen), z);
|
||||
memcpy(inbuffer + z, buffer, 342 - z);
|
||||
} else
|
||||
memcpy(inbuffer, buffer + (pos % trackLen), 342);
|
||||
pos += 342;
|
||||
|
||||
byte oldVal = 0;
|
||||
for (uint n = 0; n < 342; ++n) {
|
||||
// expand
|
||||
assert(inbuffer[n] >= 0x96); // corrupt file (TODO: assert?)
|
||||
byte val = c_6and2_lookup[inbuffer[n] - 0x96];
|
||||
if (val == 0x40) {
|
||||
error("NIB: invalid nibble value %02x", inbuffer[n]);
|
||||
}
|
||||
// undo checksum
|
||||
oldVal = val ^ oldVal;
|
||||
inbuffer[n] = oldVal;
|
||||
}
|
||||
|
||||
byte checksum = buffer[pos++ % trackLen];
|
||||
if (checksum < 0x96 || oldVal != c_6and2_lookup[checksum - 0x96]) {
|
||||
warning("NIB: checksum mismatch @ (%x, %x)", track, sector);
|
||||
if (!readSector_NIB(inbuffer, buffer, sizeof(inbuffer), pos, 0x96, c_6and2_lookup, track, sector))
|
||||
continue;
|
||||
}
|
||||
|
||||
for (uint n = 0; n < 256; ++n) {
|
||||
output[n] = inbuffer[86 + n] << 2;
|
||||
@ -220,48 +213,10 @@ static Common::SeekableReadStream *readImage_NIB(const Common::String &filename,
|
||||
} else {
|
||||
// 5-and-3 uses 410 on-disk bytes, decoding to just over 256 bytes
|
||||
byte inbuffer[410];
|
||||
uint z = trackLen - (pos % trackLen);
|
||||
if (z < 410) {
|
||||
memcpy(inbuffer, buffer + (pos % trackLen), z);
|
||||
memcpy(inbuffer + z, buffer, 410 - z);
|
||||
} else
|
||||
memcpy(inbuffer, buffer + (pos % trackLen), 410);
|
||||
pos += 410;
|
||||
|
||||
bool truncated = false;
|
||||
byte oldVal = 0;
|
||||
for (uint n = 0; n < 410; ++n) {
|
||||
// expand
|
||||
assert(inbuffer[n] >= 0xaa); // corrupt file (TODO: assert?)
|
||||
if (inbuffer[n] == 0xd5) {
|
||||
// Early end of block.
|
||||
truncated = true;
|
||||
pos -= (410 - n);
|
||||
warning("NIB: early end of block @ 0x%x (%x, %x)", f.pos(), track, sector);
|
||||
break;
|
||||
}
|
||||
byte val = c_5and3_lookup[inbuffer[n] - 0xaa];
|
||||
if (val == 0x20) {
|
||||
// Badly-encoded nibbles, stop trying to decode here.
|
||||
truncated = true;
|
||||
warning("NIB: bad nibble %02x @ 0x%x (%x, %x)", inbuffer[n], f.pos(), track, sector);
|
||||
pos -= (410 - n);
|
||||
break;
|
||||
}
|
||||
// undo checksum
|
||||
oldVal = val ^ oldVal;
|
||||
inbuffer[n] = oldVal;
|
||||
}
|
||||
|
||||
if (truncated)
|
||||
if (!readSector_NIB(inbuffer, buffer, sizeof(inbuffer), pos, 0xaa, c_5and3_lookup, track, sector))
|
||||
continue;
|
||||
|
||||
byte checksum = buffer[pos++ % trackLen];
|
||||
if (checksum < 0xaa || oldVal != c_5and3_lookup[checksum - 0xaa]) {
|
||||
warning("NIB: checksum mismatch @ (%x, %x)", track, sector);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 8 bytes of nibbles expand to 5 bytes
|
||||
// so we have 51 of these batches (255 bytes), plus 2 bytes of 'leftover' nibbles for byte 256
|
||||
for (uint n = 0; n < 51; ++n) {
|
||||
@ -285,6 +240,14 @@ static Common::SeekableReadStream *readImage_NIB(const Common::String &filename,
|
||||
}
|
||||
|
||||
bool DiskImage::open(const Common::String &filename) {
|
||||
Common::File *f = new Common::File;
|
||||
|
||||
if (!f->open(filename)) {
|
||||
warning("Failed to open '%s'", filename.c_str());
|
||||
delete f;
|
||||
return false;
|
||||
}
|
||||
|
||||
Common::String lcName(filename);
|
||||
lcName.toLowercase();
|
||||
|
||||
@ -292,27 +255,29 @@ bool DiskImage::open(const Common::String &filename) {
|
||||
_tracks = 35;
|
||||
_sectorsPerTrack = 16;
|
||||
_bytesPerSector = 256;
|
||||
_stream = readImage(filename);
|
||||
_stream = f;
|
||||
} else if (lcName.hasSuffix(".d13")) {
|
||||
_tracks = 35;
|
||||
_sectorsPerTrack = 13;
|
||||
_bytesPerSector = 256;
|
||||
_stream = readImage(filename);
|
||||
_stream = f;
|
||||
} else if (lcName.hasSuffix(".nib")) {
|
||||
_tracks = 35;
|
||||
|
||||
if (detectDOS33_NIB(filename))
|
||||
if (detectDOS33_NIB(*f))
|
||||
_sectorsPerTrack = 16;
|
||||
else
|
||||
_sectorsPerTrack = 13;
|
||||
|
||||
_bytesPerSector = 256;
|
||||
_stream = readImage_NIB(filename, _sectorsPerTrack == 16);
|
||||
f->seek(0);
|
||||
_stream = readImage_NIB(*f, _sectorsPerTrack == 16);
|
||||
delete f;
|
||||
} else if (lcName.hasSuffix(".xfd")) {
|
||||
_tracks = 40;
|
||||
_sectorsPerTrack = 18;
|
||||
_bytesPerSector = 128;
|
||||
_stream = readImage(filename);
|
||||
_stream = f;
|
||||
}
|
||||
|
||||
int expectedSize = _tracks * _sectorsPerTrack * _bytesPerSector;
|
||||
|
Loading…
Reference in New Issue
Block a user