mirror of
https://github.com/libretro/scummvm.git
synced 2025-03-05 17:57:14 +00:00
AGI: Detect V3 volume format in V2 games
The CoCo3 version of Xmas Card 86 has a volume file with a V3 format. The V2 loader now detects this and ignores the extra header bytes. Fixes bug #14699
This commit is contained in:
parent
bca50cd100
commit
a5656b43fe
@ -639,14 +639,17 @@ public:
|
||||
class AgiLoader_v2 : public AgiLoader {
|
||||
private:
|
||||
AgiEngine *_vm;
|
||||
bool _hasV3VolumeFormat;
|
||||
|
||||
int loadDir(AgiDir *agid, const char *fname);
|
||||
uint8 *loadVolRes(AgiDir *agid);
|
||||
bool detectV3VolumeFormat();
|
||||
|
||||
public:
|
||||
|
||||
AgiLoader_v2(AgiEngine *vm) {
|
||||
_vm = vm;
|
||||
_hasV3VolumeFormat = false;
|
||||
}
|
||||
|
||||
int init() override;
|
||||
|
@ -83,6 +83,51 @@ int AgiLoader_v2::loadDir(AgiDir *agid, const char *fname) {
|
||||
return errOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects if the volume format is really V3.
|
||||
*
|
||||
* The volume format for a V2 game should have 5 byte headers.
|
||||
* The CoCo3 version of Xmas Card 86 has 7 byte headers.
|
||||
* The resource length repeats as if it were a V3 volume with no compression.
|
||||
*
|
||||
* This function detects if a volume has this unusual structure so that
|
||||
* loadVolRes() can ignore the two extra header bytes.
|
||||
*/
|
||||
bool AgiLoader_v2::detectV3VolumeFormat() {
|
||||
uint8 volume = _vm->_game.dirLogic[0].volume;
|
||||
Common::Path path(Common::String::format("vol.%i", volume));
|
||||
Common::File volumeFile;
|
||||
if (!volumeFile.open(path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// read the first few entries and see if they match the 7 byte header
|
||||
uint8 volumeHeader[7];
|
||||
for (int i = 0; i < 5; i++) {
|
||||
if (volumeFile.read(&volumeHeader, 7) != 7) {
|
||||
return false;
|
||||
}
|
||||
// signature
|
||||
if (READ_BE_UINT16(volumeHeader) != 0x1234) {
|
||||
return false;
|
||||
}
|
||||
// volume number
|
||||
if (volumeHeader[2] != volume) {
|
||||
return false;
|
||||
}
|
||||
// duplicate resource lengths
|
||||
uint16 resourceLength1 = READ_LE_UINT16(volumeHeader + 3);
|
||||
uint16 resourceLength2 = READ_LE_UINT16(volumeHeader + 5);
|
||||
if (resourceLength1 != resourceLength2) {
|
||||
return false;
|
||||
}
|
||||
if (!volumeFile.seek(resourceLength1, SEEK_CUR)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int AgiLoader_v2::init() {
|
||||
int ec = errOK;
|
||||
|
||||
@ -94,6 +139,8 @@ int AgiLoader_v2::init() {
|
||||
ec = loadDir(_vm->_game.dirView, VIEWDIR);
|
||||
if (ec == errOK)
|
||||
ec = loadDir(_vm->_game.dirSound, SNDDIR);
|
||||
if (ec == errOK)
|
||||
_hasV3VolumeFormat = detectV3VolumeFormat();
|
||||
|
||||
return ec;
|
||||
}
|
||||
@ -138,11 +185,11 @@ int AgiLoader_v2::unloadResource(int16 resourceType, int16 resourceNr) {
|
||||
/**
|
||||
* This function loads a raw resource into memory,
|
||||
* if further decoding is required, it must be done by another
|
||||
* routine. NULL is returned if unsucsessfull.
|
||||
* routine. NULL is returned if unsuccessful.
|
||||
*/
|
||||
uint8 *AgiLoader_v2::loadVolRes(struct AgiDir *agid) {
|
||||
uint8 *data = nullptr;
|
||||
char x[6];
|
||||
uint8 volumeHeader[7];
|
||||
Common::File fp;
|
||||
unsigned int sig;
|
||||
Common::Path path(Common::String::format("vol.%i", agid->volume));
|
||||
@ -152,9 +199,9 @@ uint8 *AgiLoader_v2::loadVolRes(struct AgiDir *agid) {
|
||||
if (agid->offset != _EMPTY && fp.open(path)) {
|
||||
debugC(3, kDebugLevelResources, "loading resource at offset %d", agid->offset);
|
||||
fp.seek(agid->offset, SEEK_SET);
|
||||
fp.read(&x, 5);
|
||||
if ((sig = READ_BE_UINT16((uint8 *) x)) == 0x1234) {
|
||||
agid->len = READ_LE_UINT16((uint8 *) x + 3);
|
||||
fp.read(&volumeHeader, _hasV3VolumeFormat ? 7 : 5);
|
||||
if ((sig = READ_BE_UINT16(volumeHeader)) == 0x1234) {
|
||||
agid->len = READ_LE_UINT16(volumeHeader + 3);
|
||||
data = (uint8 *)calloc(1, agid->len + 32);
|
||||
if (data != nullptr) {
|
||||
fp.read(data, agid->len);
|
||||
|
@ -194,7 +194,7 @@ int AgiLoader_v3::unloadResource(int16 resourceType, int16 resourceNr) {
|
||||
* If further decoding is required, it must be done by another
|
||||
* routine.
|
||||
*
|
||||
* NULL is returned if unsucsessful.
|
||||
* NULL is returned if unsuccessful.
|
||||
*/
|
||||
uint8 *AgiLoader_v3::loadVolRes(AgiDir *agid) {
|
||||
char x[8];
|
||||
|
Loading…
x
Reference in New Issue
Block a user