COMMON: Check CRC16 in Stuffit

This commit is contained in:
Vladimir Serbinenko 2023-01-20 03:30:21 +01:00 committed by Filippos Karapetis
parent 16d1582501
commit 2d3514d13f

View file

@ -32,6 +32,7 @@
#include "common/macresman.h" #include "common/macresman.h"
#include "common/memstream.h" #include "common/memstream.h"
#include "common/substream.h" #include "common/substream.h"
#include "common/crc.h"
namespace Common { namespace Common {
@ -62,6 +63,7 @@ private:
uint32 uncompressedSize; uint32 uncompressedSize;
uint32 compressedSize; uint32 compressedSize;
uint32 offset; uint32 offset;
uint16 crc;
}; };
Common::SeekableReadStream *_stream; Common::SeekableReadStream *_stream;
@ -140,37 +142,47 @@ bool StuffItArchive::open(Common::SeekableReadStream *stream) {
_stream->skip(7); // unknown _stream->skip(7); // unknown
while (_stream->pos() < _stream->size() && !_stream->eos() && _stream->pos() < archiveSize) { Common::CRC16 crc;
byte resForkCompression = _stream->readByte();
byte dataForkCompression = _stream->readByte();
byte fileNameLength = _stream->readByte(); while (_stream->pos() < _stream->size() && !_stream->eos() && _stream->pos() < archiveSize) {
byte header[112];
_stream->read(header, sizeof(header));
Common::MemoryReadStream headStream(header, sizeof(header));
byte resForkCompression = headStream.readByte();
byte dataForkCompression = headStream.readByte();
byte fileNameLength = headStream.readByte();
Common::String name; Common::String name;
if (fileNameLength > 63) if (fileNameLength > 63)
error("File name length too long in stuffit archive: %d at 0x%x", fileNameLength, (int) (_stream->pos() - 3)); error("File name length too long in stuffit archive: %d at 0x%x", fileNameLength, (int) (_stream->pos() - 3));
for (byte i = 0; i < fileNameLength; i++) for (byte i = 0; i < fileNameLength; i++)
name += (char)_stream->readByte(); name += (char)headStream.readByte();
// Skip remaining bytes // Skip remaining bytes
_stream->skip(63 - fileNameLength); headStream.skip(63 - fileNameLength);
MacFinderInfo finfo; MacFinderInfo finfo;
_stream->read(finfo.type, 4); headStream.read(finfo.type, 4);
_stream->read(finfo.creator, 4); headStream.read(finfo.creator, 4);
finfo.flags = _stream->readUint16BE(); finfo.flags = headStream.readUint16BE();
/* uint32 creationDate = */ _stream->readUint32BE(); /* uint32 creationDate = */ headStream.readUint32BE();
/* uint32 modificationDate = */ _stream->readUint32BE(); /* uint32 modificationDate = */ headStream.readUint32BE();
uint32 resForkUncompressedSize = _stream->readUint32BE(); uint32 resForkUncompressedSize = headStream.readUint32BE();
uint32 dataForkUncompressedSize = _stream->readUint32BE(); uint32 dataForkUncompressedSize = headStream.readUint32BE();
uint32 resForkCompressedSize = _stream->readUint32BE(); uint32 resForkCompressedSize = headStream.readUint32BE();
uint32 dataForkCompressedSize = _stream->readUint32BE(); uint32 dataForkCompressedSize = headStream.readUint32BE();
/* uint16 resForkCRC = */ _stream->readUint16BE(); uint16 resForkCRC = headStream.readUint16BE();
/* uint16 dataForkCRC = */ _stream->readUint16BE(); uint16 dataForkCRC = headStream.readUint16BE();
_stream->skip(6); // unknown headStream.skip(6); // unknown
/* uint16 headerCRC = */ _stream->readUint16BE(); uint16 headerCRC = headStream.readUint16BE();
uint16 actualHeaderCRC = crc.crcFast(header, sizeof(header) - 2);
if (actualHeaderCRC != headerCRC)
error ("Header CRC mismatch: %04x vs %04x", actualHeaderCRC, headerCRC);
// Ignore directories for now // Ignore directories for now
if (dataForkCompression == 32 || dataForkCompression == 33) if (dataForkCompression == 32 || dataForkCompression == 33)
@ -186,6 +198,7 @@ bool StuffItArchive::open(Common::SeekableReadStream *stream) {
entry.uncompressedSize = dataForkUncompressedSize; entry.uncompressedSize = dataForkUncompressedSize;
entry.compressedSize = dataForkCompressedSize; entry.compressedSize = dataForkCompressedSize;
entry.offset = _stream->pos() + resForkCompressedSize; entry.offset = _stream->pos() + resForkCompressedSize;
entry.crc = dataForkCRC;
_map[name] = entry; _map[name] = entry;
debug(0, "StuffIt file '%s', Compression = %d", name.c_str(), entry.compression); debug(0, "StuffIt file '%s', Compression = %d", name.c_str(), entry.compression);
@ -202,6 +215,7 @@ bool StuffItArchive::open(Common::SeekableReadStream *stream) {
entry.uncompressedSize = resForkUncompressedSize; entry.uncompressedSize = resForkUncompressedSize;
entry.compressedSize = resForkCompressedSize; entry.compressedSize = resForkCompressedSize;
entry.offset = _stream->pos(); entry.offset = _stream->pos();
entry.crc = resForkCRC;
_map[name] = entry; _map[name] = entry;
debug(0, "StuffIt file '%s', Compression = %d", name.c_str(), entry.compression); debug(0, "StuffIt file '%s', Compression = %d", name.c_str(), entry.compression);
@ -274,6 +288,12 @@ Common::SharedArchiveContents StuffItArchive::readContentsForPath(const Common::
return Common::SharedArchiveContents(); return Common::SharedArchiveContents();
} }
uint16 actualCRC = Common::CRC16().crcFast(uncompressedBlock, entry.uncompressedSize);
if (actualCRC != entry.crc) {
error("CRC mismatch: %04x vs %04x", actualCRC, entry.crc);
}
return Common::SharedArchiveContents(uncompressedBlock, entry.uncompressedSize); return Common::SharedArchiveContents(uncompressedBlock, entry.uncompressedSize);
} }