aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilippos Karapetis2010-06-02 13:17:36 +0000
committerFilippos Karapetis2010-06-02 13:17:36 +0000
commitaf3fec8c26d92005b507dca65d1d50f820feb0e7 (patch)
tree491490e7139bd6f214d35e2e152d93a2e11cdfb2
parent4493080220a98d596ee578bddc8a64c0d3955eac (diff)
downloadscummvm-rg350-af3fec8c26d92005b507dca65d1d50f820feb0e7.tar.gz
scummvm-rg350-af3fec8c26d92005b507dca65d1d50f820feb0e7.tar.bz2
scummvm-rg350-af3fec8c26d92005b507dca65d1d50f820feb0e7.zip
- Fixed findGameObject() to properly handle SCI0-SCI1 games where the first block of script 0 isn't the exports block
- Changed many places where Common::File is used directly to use Common::SeekableReadStream instead (in order to ultimately remove the SCI_detection hack in the fallback detector) svn-id: r49391
-rw-r--r--engines/sci/resource.cpp125
-rw-r--r--engines/sci/resource.h8
-rw-r--r--engines/sci/resource_audio.cpp30
3 files changed, 109 insertions, 54 deletions
diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp
index 11d9492ad5..449effd737 100644
--- a/engines/sci/resource.cpp
+++ b/engines/sci/resource.cpp
@@ -237,6 +237,7 @@ ResourceSource *ResourceManager::addPatchDir(const char *dirname) {
ResourceSource *newsrc = new ResourceSource();
newsrc->source_type = kSourceDirectory;
+ newsrc->resourceFile = 0;
newsrc->scanned = false;
newsrc->location_name = dirname;
@@ -257,7 +258,7 @@ ResourceSource *ResourceManager::getVolume(ResourceSource *map, int volume_nr) {
// Resource manager constructors and operations
-bool ResourceManager::loadPatch(Resource *res, Common::File &file) {
+bool ResourceManager::loadPatch(Resource *res, Common::SeekableReadStream *file) {
// We assume that the resource type matches res->type
// We also assume that the current file position is right at the actual data (behind resourceid/headersize byte)
@@ -272,12 +273,12 @@ bool ResourceManager::loadPatch(Resource *res, Common::File &file) {
unsigned int really_read;
if (res->_headerSize > 0) {
- really_read = file.read(res->_header, res->_headerSize);
+ really_read = file->read(res->_header, res->_headerSize);
if (really_read != res->_headerSize)
error("Read %d bytes from %s but expected %d", really_read, res->_id.toString().c_str(), res->_headerSize);
}
- really_read = file.read(res->data, res->size);
+ really_read = file->read(res->data, res->size);
if (really_read != res->size)
error("Read %d bytes from %s but expected %d", really_read, res->_id.toString().c_str(), res->size);
@@ -295,7 +296,7 @@ bool ResourceManager::loadFromPatchFile(Resource *res) {
}
// Skip resourceid and header size byte
file.seek(2, SEEK_SET);
- return loadPatch(res, file);
+ return loadPatch(res, &file);
}
Common::File *ResourceManager::getVolumeFile(const char *filename) {
@@ -352,10 +353,15 @@ void ResourceManager::loadResource(Resource *res) {
return;
}
- Common::File *file;
+ Common::SeekableReadStream *fileStream;
+
// Either loading from volume or patch loading failed
- file = getVolumeFile(res->_source->location_name.c_str());
- if (!file) {
+ if (res->_source->resourceFile)
+ fileStream = res->_source->resourceFile->createReadStream();
+ else
+ fileStream = getVolumeFile(res->_source->location_name.c_str());
+
+ if (!fileStream) {
warning("Failed to open %s", res->_source->location_name.c_str());
res->unalloc();
return;
@@ -363,8 +369,8 @@ void ResourceManager::loadResource(Resource *res) {
switch(res->_source->source_type) {
case kSourceWave:
- file->seek(res->_fileOffset, SEEK_SET);
- loadFromWaveFile(res, *file);
+ fileStream->seek(res->_fileOffset, SEEK_SET);
+ loadFromWaveFile(res, fileStream);
return;
case kSourceAudioVolume:
@@ -395,30 +401,30 @@ void ResourceManager::loadResource(Resource *res) {
if (!compressedOffset)
error("could not translate offset to compressed offset in audio volume");
- file->seek(compressedOffset, SEEK_SET);
+ fileStream->seek(compressedOffset, SEEK_SET);
switch (res->_id.type) {
case kResourceTypeAudio:
case kResourceTypeAudio36:
// Directly read the stream, compressed audio wont have resource type id and header size for SCI1.1
- loadFromAudioVolumeSCI1(res, *file);
+ loadFromAudioVolumeSCI1(res, fileStream);
return;
default:
break;
}
} else {
// original file, directly seek to given offset and get SCI1/SCI1.1 audio resource
- file->seek(res->_fileOffset, SEEK_SET);
+ fileStream->seek(res->_fileOffset, SEEK_SET);
}
if (getSciVersion() < SCI_VERSION_1_1)
- loadFromAudioVolumeSCI1(res, *file);
+ loadFromAudioVolumeSCI1(res, fileStream);
else
- loadFromAudioVolumeSCI11(res, *file);
+ loadFromAudioVolumeSCI11(res, fileStream);
return;
default:
- file->seek(res->_fileOffset, SEEK_SET);
- int error = decompress(res, file);
+ fileStream->seek(res->_fileOffset, SEEK_SET);
+ int error = decompress(res, fileStream);
if (error) {
warning("Error %d occured while reading %s from resource file: %s",
error, res->_id.toString().c_str(), sci_error_types[error]);
@@ -872,7 +878,6 @@ const char *ResourceManager::versionDescription(ResVersion version) const {
ResourceManager::ResVersion ResourceManager::detectMapVersion() {
Common::SeekableReadStream *fileStream = 0;
- Common::File *file = 0;
byte buff[6];
ResourceSource *rsrc= 0;
@@ -883,7 +888,7 @@ ResourceManager::ResVersion ResourceManager::detectMapVersion() {
if (rsrc->resourceFile) {
fileStream = rsrc->resourceFile->createReadStream();
} else {
- file = new Common::File();
+ Common::File *file = new Common::File();
file->open(rsrc->location_name);
if (file->isOpen())
fileStream = file;
@@ -963,7 +968,6 @@ ResourceManager::ResVersion ResourceManager::detectMapVersion() {
ResourceManager::ResVersion ResourceManager::detectVolVersion() {
Common::SeekableReadStream *fileStream = 0;
- Common::File *file = 0;
ResourceSource *rsrc;
for (Common::List<ResourceSource *>::iterator it = _sources.begin(); it != _sources.end(); ++it) {
@@ -973,7 +977,7 @@ ResourceManager::ResVersion ResourceManager::detectVolVersion() {
if (rsrc->resourceFile) {
fileStream = rsrc->resourceFile->createReadStream();
} else {
- file = new Common::File();
+ Common::File *file = new Common::File();
file->open(rsrc->location_name);
if (file->isOpen())
fileStream = file;
@@ -1063,7 +1067,7 @@ ResourceManager::ResVersion ResourceManager::detectVolVersion() {
// version-agnostic patch application
void ResourceManager::processPatch(ResourceSource *source, ResourceType restype, int resnumber) {
- Common::File file;
+ Common::SeekableReadStream *fileStream = 0;
Resource *newrsc;
ResourceId resId = ResourceId(restype, resnumber);
byte patchtype, patch_data_offset;
@@ -1071,18 +1075,27 @@ void ResourceManager::processPatch(ResourceSource *source, ResourceType restype,
if (resnumber == -1)
return;
- if (!file.open(source->location_name)) {
- warning("ResourceManager::processPatch(): failed to open %s", source->location_name.c_str());
- return;
+
+ if (source->resourceFile) {
+ fileStream = source->resourceFile->createReadStream();
+ } else {
+ Common::File *file = new Common::File();
+ if (!file->open(source->location_name)) {
+ warning("ResourceManager::processPatch(): failed to open %s", source->location_name.c_str());
+ return;
+ }
+ fileStream = file;
}
- fsize = file.size();
+ fsize = fileStream->size();
if (fsize < 3) {
debug("Patching %s failed - file too small", source->location_name.c_str());
return;
}
- patchtype = file.readByte() & 0x7F;
- patch_data_offset = file.readByte();
+ patchtype = fileStream->readByte() & 0x7F;
+ patch_data_offset = fileStream->readByte();
+
+ delete fileStream;
if (patchtype != restype) {
debug("Patching %s failed - resource type mismatch", source->location_name.c_str());
@@ -1097,8 +1110,12 @@ void ResourceManager::processPatch(ResourceSource *source, ResourceType restype,
case 1:
patch_data_offset = 2;
break;
+ case 4:
+ patch_data_offset = 8;
+ break;
default:
- warning("Resource patch unsupported special case %X", patch_data_offset);
+ warning("Resource patch unsupported special case %X", patch_data_offset & 0x7F);
+ return;
}
}
@@ -1180,6 +1197,7 @@ void ResourceManager::readResourcePatches(ResourceSource *source) {
psrcPatch = new ResourceSource;
psrcPatch->source_type = kSourcePatch;
psrcPatch->location_name = name;
+ psrcPatch->resourceFile = 0;
processPatch(psrcPatch, (ResourceType)i, number);
}
}
@@ -1931,7 +1949,31 @@ bool ResourceManager::hasSci1Voc900() {
return offset == res->size;
}
-#define READ_UINT16(ptr) (!isSci11Mac() ? READ_LE_UINT16(ptr) : READ_BE_UINT16(ptr))
+// Same function as Script::findBlock(). Slight code
+// duplication here, but this has been done to keep the resource
+// manager independent from the rest of the engine
+static byte *findSci0ExportsBlock(byte *buffer) {
+ byte *buf = buffer;
+ bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
+
+ if (oldScriptHeader)
+ buf += 2;
+
+ do {
+ int seekerType = READ_LE_UINT16(buf);
+
+ if (seekerType == 0)
+ break;
+ if (seekerType == 7) // exports
+ return buf;
+
+ int seekerSize = READ_LE_UINT16(buf + 2);
+ assert(seekerSize > 0);
+ buf += seekerSize;
+ } while (1);
+
+ return NULL;
+}
reg_t ResourceManager::findGameObject(bool addSci11ScriptOffset) {
Resource *script = findResource(ResourceId(kResourceTypeScript, 0), false);
@@ -1939,11 +1981,26 @@ reg_t ResourceManager::findGameObject(bool addSci11ScriptOffset) {
if (!script)
return NULL_REG;
- int extraBytes = 0;
- if (getSciVersion() == SCI_VERSION_0_EARLY || getSciVersion() >= SCI_VERSION_1_1)
- extraBytes = 2;
+ byte *offsetPtr = 0;
+
+ if (getSciVersion() < SCI_VERSION_1_1) {
+ byte *buf = (getSciVersion() == SCI_VERSION_0_EARLY) ? script->data + 2 : script->data;
+
+ // Check if the first block is the exports block (in most cases, it is)
+ bool exportsIsFirst = (READ_LE_UINT16(buf + 4) == 7);
+ if (exportsIsFirst) {
+ offsetPtr = buf + 4 + 2;
+ } else {
+ offsetPtr = findSci0ExportsBlock(script->data);
+ if (!offsetPtr)
+ error("Unable to find exports block from script 0");
+ offsetPtr += 4 + 2;
+ }
+ } else {
+ offsetPtr = script->data + 4 + 2 + 2;
+ }
- int16 offset = READ_UINT16(script->data + extraBytes + 4 + 2);
+ int16 offset = !isSci11Mac() ? READ_LE_UINT16(offsetPtr) : READ_BE_UINT16(offsetPtr);
// In SCI1.1 and newer, the heap is appended at the end of the script,
// so adjust the offset accordingly
@@ -1986,6 +2043,4 @@ Common::String ResourceManager::findSierraGameId() {
return sierraId;
}
-#undef READ_UINT16
-
} // End of namespace Sci
diff --git a/engines/sci/resource.h b/engines/sci/resource.h
index 65717e4124..f722ca5768 100644
--- a/engines/sci/resource.h
+++ b/engines/sci/resource.h
@@ -395,11 +395,11 @@ protected:
Common::File *getVolumeFile(const char *filename);
void loadResource(Resource *res);
- bool loadPatch(Resource *res, Common::File &file);
+ bool loadPatch(Resource *res, Common::SeekableReadStream *file);
bool loadFromPatchFile(Resource *res);
- bool loadFromWaveFile(Resource *res, Common::File &file);
- bool loadFromAudioVolumeSCI1(Resource *res, Common::File &file);
- bool loadFromAudioVolumeSCI11(Resource *res, Common::File &file);
+ bool loadFromWaveFile(Resource *res, Common::SeekableReadStream *file);
+ bool loadFromAudioVolumeSCI1(Resource *res, Common::SeekableReadStream *file);
+ bool loadFromAudioVolumeSCI11(Resource *res, Common::SeekableReadStream *file);
void freeOldResources();
int decompress(Resource *res, Common::SeekableReadStream *file);
int readResourceInfo(Resource *res, Common::SeekableReadStream *file, uint32&szPacked, ResourceCompression &compression);
diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp
index 5dea36bb07..2fe6a7f3d5 100644
--- a/engines/sci/resource_audio.cpp
+++ b/engines/sci/resource_audio.cpp
@@ -62,10 +62,10 @@ void ResourceManager::checkIfAudioVolumeIsCompressed(ResourceSource *source) {
}
}
-bool ResourceManager::loadFromWaveFile(Resource *res, Common::File &file) {
+bool ResourceManager::loadFromWaveFile(Resource *res, Common::SeekableReadStream *file) {
res->data = new byte[res->size];
- uint32 really_read = file.read(res->data, res->size);
+ uint32 really_read = file->read(res->data, res->size);
if (really_read != res->size)
error("Read %d bytes from %s but expected %d", really_read, res->_id.toString().c_str(), res->size);
@@ -73,26 +73,26 @@ bool ResourceManager::loadFromWaveFile(Resource *res, Common::File &file) {
return true;
}
-bool ResourceManager::loadFromAudioVolumeSCI11(Resource *res, Common::File &file) {
+bool ResourceManager::loadFromAudioVolumeSCI11(Resource *res, Common::SeekableReadStream *file) {
// Check for WAVE files here
- uint32 riffTag = file.readUint32BE();
+ uint32 riffTag = file->readUint32BE();
if (riffTag == MKID_BE('RIFF')) {
res->_headerSize = 0;
- res->size = file.readUint32LE();
- file.seek(-8, SEEK_CUR);
+ res->size = file->readUint32LE();
+ file->seek(-8, SEEK_CUR);
return loadFromWaveFile(res, file);
}
- file.seek(-4, SEEK_CUR);
+ file->seek(-4, SEEK_CUR);
- ResourceType type = (ResourceType)(file.readByte() & 0x7f);
+ ResourceType type = (ResourceType)(file->readByte() & 0x7f);
if (((res->_id.type == kResourceTypeAudio || res->_id.type == kResourceTypeAudio36) && (type != kResourceTypeAudio))
|| ((res->_id.type == kResourceTypeSync || res->_id.type == kResourceTypeSync36) && (type != kResourceTypeSync))) {
- warning("Resource type mismatch loading %s from %s", res->_id.toString().c_str(), file.getName());
+ warning("Resource type mismatch loading %s", res->_id.toString().c_str());
res->unalloc();
return false;
}
- res->_headerSize = file.readByte();
+ res->_headerSize = file->readByte();
if (type == kResourceTypeAudio) {
if (res->_headerSize != 11 && res->_headerSize != 12) {
@@ -102,23 +102,23 @@ bool ResourceManager::loadFromAudioVolumeSCI11(Resource *res, Common::File &file
}
// Load sample size
- file.seek(7, SEEK_CUR);
- res->size = file.readUint32LE();
+ file->seek(7, SEEK_CUR);
+ res->size = file->readUint32LE();
// Adjust offset to point at the header data again
- file.seek(-11, SEEK_CUR);
+ file->seek(-11, SEEK_CUR);
}
return loadPatch(res, file);
}
-bool ResourceManager::loadFromAudioVolumeSCI1(Resource *res, Common::File &file) {
+bool ResourceManager::loadFromAudioVolumeSCI1(Resource *res, Common::SeekableReadStream *file) {
res->data = new byte[res->size];
if (res->data == NULL) {
error("Can't allocate %d bytes needed for loading %s", res->size, res->_id.toString().c_str());
}
- unsigned int really_read = file.read(res->data, res->size);
+ unsigned int really_read = file->read(res->data, res->size);
if (really_read != res->size)
warning("Read %d bytes from %s but expected %d", really_read, res->_id.toString().c_str(), res->size);