SAGA: Rewrote the MacBinary resource loading code

This simplifies the overall code and makes it easier to understand. Also, a bug with the
speech in the MacBinary packed version has been corrected, so there are no more clicking
sounds before each sample.
The Common::MacResMan code isn't really useful here, since it doesn't expose the offsets
and sizes of the actual files, which is what is needed in SAGA.

svn-id: r55674
This commit is contained in:
Filippos Karapetis 2011-01-31 10:46:52 +00:00
parent a256b74e0a
commit 90d58cf487
3 changed files with 72 additions and 154 deletions

View File

@ -83,7 +83,7 @@ bool ResourceContext::loadResV1(uint32 contextOffset, uint32 contextSize) {
resourceData = &_table[i];
resourceData->offset = contextOffset + readS1.readUint32();
resourceData->size = readS1.readUint32();
//sanity check
// Sanity check
if ((resourceData->offset > (uint)_fileSize) || (resourceData->size > contextSize)) {
result = false;
break;
@ -103,15 +103,12 @@ bool ResourceContext::load(SagaEngine *vm, Resource *resource) {
uint32 subjectResourceId;
uint32 patchResourceId;
ResourceData *subjectResourceData;
bool isMacBinary;
if (_fileName == NULL) { // IHNM special case
if (_fileName == NULL) // IHNM special case
return true;
}
if (!_file.open(_fileName)) {
if (!_file.open(_fileName))
return false;
}
_fileSize = _file.size();
_isBigEndian = vm->isBigEndian();
@ -119,20 +116,25 @@ bool ResourceContext::load(SagaEngine *vm, Resource *resource) {
if (_fileType & GAME_SWAPENDIAN)
_isBigEndian = !_isBigEndian;
isMacBinary = (_fileType & GAME_MACBINARY) > 0;
_fileType &= ~GAME_MACBINARY;
if (!isMacBinary) {
if (!loadRes(0, _fileSize)) {
return false;
}
} else {
if (!loadMac()) {
return false;
if (_fileType & GAME_MACBINARY) {
// Special case for the MacBinary packed files in the old Mac ITE
// release. There are no patch files in this case.
if (!(_fileType & GAME_MUSICFILE_GM)) {
// Find the actual size, as there may be padded data in the end.
_file.seek(83);
uint32 macDataSize = _file.readSint32BE();
// Skip the MacBinary headers, and read the resource data.
return loadRes(MAC_BINARY_HEADER_SIZE, macDataSize);
} else {
// Unpack MacBinady packed MIDI files
return loadMacMIDI();
}
}
//process internal patch files
if (!loadRes(0, _fileSize))
return false;
// Process internal patch files
if (_fileType & GAME_PATCHFILE) {
subjectResourceType = ~GAME_PATCHFILE & _fileType;
subjectContext = resource->getContext((GameFileTypes)subjectResourceType);
@ -155,7 +157,7 @@ bool ResourceContext::load(SagaEngine *vm, Resource *resource) {
}
}
//process external patch files
// Process external patch files
for (patchDescription = vm->getPatchDescriptions(); patchDescription && patchDescription->fileName; ++patchDescription) {
if ((patchDescription->fileType & _fileType) != 0) {
if (patchDescription->resourceId < _table.size()) {

View File

@ -84,22 +84,6 @@ class ResourceDataArray : public Common::Array<ResourceData> {
class ResourceContext {
friend class Resource;
protected:
const char *_fileName;
uint16 _fileType;
bool _isCompressed;
int _serial; // IHNM speech files
bool _isBigEndian;
ResourceDataArray _table;
Common::File _file;
int32 _fileSize;
bool load(SagaEngine *_vm, Resource *resource);
bool loadResV1(uint32 contextOffset, uint32 contextSize);
virtual bool loadMac() = 0;
virtual bool loadRes(uint32 contextOffset, uint32 contextSize) = 0;
public:
ResourceContext():
@ -172,6 +156,22 @@ public:
}
return -1;
}
protected:
const char *_fileName;
uint16 _fileType;
bool _isCompressed;
int _serial; // IHNM speech files
bool _isBigEndian;
ResourceDataArray _table;
Common::File _file;
int32 _fileSize;
bool load(SagaEngine *_vm, Resource *resource);
bool loadResV1(uint32 contextOffset, uint32 contextSize);
virtual bool loadMacMIDI() = 0;
virtual bool loadRes(uint32 contextOffset, uint32 contextSize) = 0;
};
class ResourceContextList : public Common::List<ResourceContext*> {
@ -228,7 +228,7 @@ public:
// ITE
class ResourceContext_RSC: public ResourceContext {
protected:
virtual bool loadMac();
virtual bool loadMacMIDI();
virtual bool loadRes(uint32 contextOffset, uint32 contextSize) {
return loadResV1(contextOffset, contextSize);
}
@ -237,7 +237,9 @@ protected:
class Resource_RSC : public Resource {
public:
Resource_RSC(SagaEngine *vm) : Resource(vm) {}
virtual uint32 convertResourceId(uint32 resourceId);
virtual uint32 convertResourceId(uint32 resourceId) {
return _vm->isMacResources() ? resourceId - 2 : resourceId;
}
virtual void loadGlobalResources(int chapter, int actorsEntrance) {}
virtual MetaResource* getMetaResource() {
MetaResource *dummy = 0;
@ -253,20 +255,16 @@ protected:
// IHNM
class ResourceContext_RES: public ResourceContext {
protected:
virtual bool loadMac() {
return false;
}
virtual bool loadMacMIDI() { return false; }
virtual bool loadRes(uint32 contextOffset, uint32 contextSize) {
return loadResV1(0, contextSize);
}
};
//TODO: move load routines from sndres
// TODO: move load routines from sndres
class VoiceResourceContext_RES: public ResourceContext {
protected:
virtual bool loadMac() {
return false;
}
virtual bool loadMacMIDI() { return false; }
virtual bool loadRes(uint32 contextOffset, uint32 contextSize) {
return false;
}
@ -298,9 +296,7 @@ class ResourceContext_HRS: public ResourceContext {
protected:
ResourceDataArray _categories;
virtual bool loadMac() {
return false;
}
virtual bool loadMacMIDI() { return false; }
virtual bool loadRes(uint32 contextOffset, uint32 contextSize) {
return loadResV2(contextSize);
}

View File

@ -26,142 +26,62 @@
// RSC Resource file management module (SAGA 1, used in ITE)
#include "saga/saga.h"
#include "saga/actor.h"
#include "saga/animation.h"
#include "saga/interface.h"
#include "saga/music.h"
#include "saga/resource.h"
#include "saga/scene.h"
#include "saga/sndres.h"
#include "engines/advancedDetector.h"
namespace Saga {
struct MacResource {
int16 id;
int32 dataOffset;
MacResource() : id(0), dataOffset(0) {}
};
class MacResourceArray : public Common::Array<MacResource> {
};
struct MacResType {
uint32 id;
int16 maxItemId;
int16 offset;
MacResourceArray resources;
MacResType() : id(0), maxItemId(0), offset(0) {
}
};
class MacResTypeArray : public Common::Array<MacResType> {
};
#define ID_MIDI MKID_BE('Midi')
bool ResourceContext_RSC::loadMac() {
int32 macDataSize, macResSizePad, macResOffset;
uint32 macMapOffset, macDataOffset;
MacResTypeArray macResTypes;
bool notSagaContext = false;
bool ResourceContext_RSC::loadMacMIDI() {
// Sanity check
if (_fileSize < RSC_MIN_FILESIZE + MAC_BINARY_HEADER_SIZE)
return false;
_file.seek(82);
if (_file.readByte() != 0)
return false;
_file.seek(83);
int macDataSize = _file.readSint32BE();
int macResOffset = MAC_BINARY_HEADER_SIZE + (((macDataSize + 127) >> 7) << 7);
macDataSize = _file.readSint32BE();
macResOffset = MAC_BINARY_HEADER_SIZE + (((macDataSize + 127) >> 7) << 7);
macResSizePad = (((_file.readSint32BE() + 127) >> 7) << 7);
_file.seek(macResOffset);
macDataOffset = _file.readUint32BE() + macResOffset;
macMapOffset = _file.readUint32BE() + macResOffset;
// Used for sanity checks
uint32 macDataLength = _file.readUint32BE();
uint32 macMapLength = _file.readUint32BE();
if (macDataOffset >= (uint)_fileSize || macMapOffset >= (uint)_fileSize ||
macDataLength + macMapLength > (uint)_fileSize)
return false;
uint32 macDataOffset = _file.readUint32BE() + macResOffset;
uint32 macMapOffset = _file.readUint32BE() + macResOffset;
_file.seek(macMapOffset + 22);
_file.readUint16BE(); // resAttr
int16 typeOffset = _file.readUint16BE();
_file.readUint16BE(); // nameOffset
int16 numTypes = _file.readUint16BE() + 1;
macResTypes.resize(numTypes);
uint16 numTypes = _file.readUint16BE() + 1;
_file.seek(macMapOffset + typeOffset + 2);
for (MacResTypeArray::iterator k = macResTypes.begin(); k != macResTypes.end(); ++k) {
k->id = _file.readUint32BE();
int16 items = _file.readUint16BE() + 1;
k->resources.resize(items);
k->offset = _file.readUint16BE();
}
// Find the MIDI files
for (uint16 i = 0; i < numTypes; i++) {
uint32 id = _file.readUint32BE();
uint16 items = _file.readUint16BE() + 1;
uint16 offset = _file.readUint16BE();
for (MacResTypeArray::iterator k = macResTypes.begin(); k != macResTypes.end(); ++k) {
_file.seek(k->offset + macMapOffset + typeOffset);
if (id == ID_MIDI) {
for (uint16 curMidi = 0; curMidi < items; curMidi++) {
// Jump to the header of the entry and read its fields
_file.seek(offset + macMapOffset + typeOffset + curMidi * 12);
uint16 midiID = _file.readUint16BE();
_file.readUint16BE(); // nameOffset
uint32 midiOffset = _file.readUint32BE() & 0xFFFFFF;
_file.readUint32BE(); // macResSize
for (MacResourceArray::iterator j = k->resources.begin(); j != k->resources.end(); ++j) {
j->id = _file.readUint16BE();
_file.readUint16BE(); // nameOffset
j->dataOffset = _file.readUint32BE();
_file.readUint32BE(); // macResSize
// Jump to the actual data and read the file size
_file.seek(macDataOffset + midiOffset);
uint32 midiSize = _file.readUint32BE();
j->dataOffset &= 0xFFFFFF;
if (j->id > k->maxItemId)
k->maxItemId = j->id;
}
}
//
for (MacResTypeArray::iterator k = macResTypes.begin(); k != macResTypes.end(); ++k) {
//getting offsets & sizes of midi
if (((_fileType & GAME_MUSICFILE_GM) > 0) && (k->id == ID_MIDI)) {
_table.resize(k->maxItemId + 1);
for (MacResourceArray::iterator j = k->resources.begin(); j != k->resources.end(); ++j) {
_file.seek(macDataOffset + j->dataOffset);
_table[j->id].size = _file.readUint32BE();
_table[j->id].offset = _file.pos();
// Add the entry
if (_table.size() <= midiID)
_table.resize(midiID + 1);
_table[midiID].offset = macDataOffset + midiOffset + 4;
_table[midiID].size = midiSize;
}
notSagaContext = true;
break;
}
}
if ((!notSagaContext) && (!loadRes(MAC_BINARY_HEADER_SIZE, macDataSize))) {
return false;
}
return true;
}
uint32 Resource_RSC::convertResourceId(uint32 resourceId) {
if (_vm->isMacResources()) {
if (resourceId > 1537) {
return resourceId - 2;
} else {
if (resourceId == 1535 || resourceId == 1536) {
error("Wrong resource number %d for Mac ITE", resourceId);
}
}
}
return resourceId;
}
} // End of namespace Saga