Rewrote the remaining parts of the ResourceManager class to work with file streams, thus removing the SCI_detection hack in the fallback detector

svn-id: r49438
This commit is contained in:
Filippos Karapetis 2010-06-05 14:09:52 +00:00
parent b9065aa2d2
commit e9f35fbf4c
3 changed files with 88 additions and 66 deletions

View file

@ -373,19 +373,6 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl
filename.toLowercase(); filename.toLowercase();
if (filename.contains("resource.map") || filename.contains("resmap.00") || filename.contains("Data1")) { if (filename.contains("resource.map") || filename.contains("resmap.00") || filename.contains("Data1")) {
// HACK: resource.map is located in the same directory as the other resource files,
// therefore add the directory here, so that the game files can be opened later on
// We now add the parent directory temporary to our SearchMan so the engine code
// used in the detection can access all files via Common::File without any problems.
// In all branches returning from this function, we need to have a call to
// SearchMan.remove to remove it from the default directory pool again.
//
// A proper solution to remove this hack would be to have the code, which is needed
// for detection, to operate on Stream objects, so they can be easily called from
// the detection code. This might be easily to achieve through refactoring the
// code needed for detection.
assert(!SearchMan.hasArchive("SCI_detection"));
SearchMan.addDirectory("SCI_detection", file->getParent());
foundResMap = true; foundResMap = true;
} }
@ -429,7 +416,6 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl
// If these files aren't found, it can't be SCI // If these files aren't found, it can't be SCI
if (!foundResMap && !foundRes000) { if (!foundResMap && !foundRes000) {
SearchMan.remove("SCI_detection");
return 0; return 0;
} }
@ -437,11 +423,10 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl
ViewType gameViews = resMan->getViewType(); ViewType gameViews = resMan->getViewType();
// Have we identified the game views? If not, stop here // Have we identified the game views? If not, stop here
// Can't be SCI (or unsupported SCI views). Pinball Creep by sierra also uses resource.map/resource.000 files
// but doesnt share sci format at all, if we dont return 0 here we will detect this game as SCI
if (gameViews == kViewUnknown) { if (gameViews == kViewUnknown) {
SearchMan.remove("SCI_detection");
delete resMan; delete resMan;
// Can't be SCI (or unsupported SCI views). Pinball Creep by sierra also uses resource.map/resource.000 files
// but doesnt share sci format at all, if we dont return 0 here we will detect this game as SCI
return 0; return 0;
} }
@ -449,7 +434,6 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl
// Is SCI32 compiled in? If not, and this is a SCI32 game, // Is SCI32 compiled in? If not, and this is a SCI32 game,
// stop here // stop here
if (getSciVersion() >= SCI_VERSION_2) { if (getSciVersion() >= SCI_VERSION_2) {
SearchMan.remove("SCI_detection");
delete resMan; delete resMan;
return (const ADGameDescription *)&s_fallbackDesc; return (const ADGameDescription *)&s_fallbackDesc;
} }
@ -468,7 +452,6 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl
// If we don't have a game id, the game is not SCI // If we don't have a game id, the game is not SCI
if (sierraGameId.empty()) { if (sierraGameId.empty()) {
SearchMan.remove("SCI_detection");
delete resMan; delete resMan;
return 0; return 0;
} }
@ -522,8 +505,6 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl
if (s_fallbackDesc.flags & ADGF_DEMO) if (s_fallbackDesc.flags & ADGF_DEMO)
s_fallbackDesc.extra = "demo"; s_fallbackDesc.extra = "demo";
SearchMan.remove("SCI_detection");
return (const ADGameDescription *)&s_fallbackDesc; return (const ADGameDescription *)&s_fallbackDesc;
} }

View file

@ -371,6 +371,8 @@ void ResourceManager::loadResource(Resource *res) {
case kSourceWave: case kSourceWave:
fileStream->seek(res->_fileOffset, SEEK_SET); fileStream->seek(res->_fileOffset, SEEK_SET);
loadFromWaveFile(res, fileStream); loadFromWaveFile(res, fileStream);
if (res->_source->resourceFile)
delete fileStream;
return; return;
case kSourceAudioVolume: case kSourceAudioVolume:
@ -408,6 +410,8 @@ void ResourceManager::loadResource(Resource *res) {
case kResourceTypeAudio36: case kResourceTypeAudio36:
// Directly read the stream, compressed audio wont have resource type id and header size for SCI1.1 // Directly read the stream, compressed audio wont have resource type id and header size for SCI1.1
loadFromAudioVolumeSCI1(res, fileStream); loadFromAudioVolumeSCI1(res, fileStream);
if (res->_source->resourceFile)
delete fileStream;
return; return;
default: default:
break; break;
@ -420,11 +424,18 @@ void ResourceManager::loadResource(Resource *res) {
loadFromAudioVolumeSCI1(res, fileStream); loadFromAudioVolumeSCI1(res, fileStream);
else else
loadFromAudioVolumeSCI11(res, fileStream); loadFromAudioVolumeSCI11(res, fileStream);
if (res->_source->resourceFile)
delete fileStream;
return; return;
default: default:
fileStream->seek(res->_fileOffset, SEEK_SET); fileStream->seek(res->_fileOffset, SEEK_SET);
int error = decompress(res, fileStream); int error = decompress(res, fileStream);
if (res->_source->resourceFile)
delete fileStream;
if (error) { if (error) {
warning("Error %d occured while reading %s from resource file: %s", warning("Error %d occured while reading %s from resource file: %s",
error, res->_id.toString().c_str(), sci_error_types[error]); error, res->_id.toString().c_str(), sci_error_types[error]);
@ -437,19 +448,6 @@ Resource *ResourceManager::testResource(ResourceId id) {
return _resMap.getVal(id, NULL); return _resMap.getVal(id, NULL);
} }
int sci0_get_compression_method(Common::ReadStream &stream) {
uint16 compressionMethod;
stream.readUint16LE();
stream.readUint16LE();
stream.readUint16LE();
compressionMethod = stream.readUint16LE();
if (stream.err())
return SCI_ERROR_IO_ERROR;
return compressionMethod;
}
int ResourceManager::addAppropriateSources() { int ResourceManager::addAppropriateSources() {
Common::ArchiveMemberList files; Common::ArchiveMemberList files;
@ -1205,25 +1203,34 @@ void ResourceManager::readResourcePatches(ResourceSource *source) {
} }
int ResourceManager::readResourceMapSCI0(ResourceSource *map) { int ResourceManager::readResourceMapSCI0(ResourceSource *map) {
Common::File file; Common::SeekableReadStream *fileStream = 0;
Resource *res; Resource *res;
ResourceType type; ResourceType type;
uint16 number, id; uint16 number, id;
uint32 offset; uint32 offset;
if (!file.open(map->location_name)) if (map->resourceFile) {
return SCI_ERROR_RESMAP_NOT_FOUND; fileStream = map->resourceFile->createReadStream();
if (!fileStream)
return SCI_ERROR_RESMAP_NOT_FOUND;
} else {
Common::File *file = new Common::File();
if (!file->open(map->location_name))
return SCI_ERROR_RESMAP_NOT_FOUND;
fileStream = file;
}
file.seek(0, SEEK_SET); fileStream->seek(0, SEEK_SET);
byte bMask = (_mapVersion == kResVersionSci1Middle) ? 0xF0 : 0xFC; byte bMask = (_mapVersion == kResVersionSci1Middle) ? 0xF0 : 0xFC;
byte bShift = (_mapVersion == kResVersionSci1Middle) ? 28 : 26; byte bShift = (_mapVersion == kResVersionSci1Middle) ? 28 : 26;
do { do {
id = file.readUint16LE(); id = fileStream->readUint16LE();
offset = file.readUint32LE(); offset = fileStream->readUint32LE();
if (file.eos() || file.err()) { if (fileStream->eos() || fileStream->err()) {
delete fileStream;
warning("Error while reading %s", map->location_name.c_str()); warning("Error while reading %s", map->location_name.c_str());
return SCI_ERROR_RESMAP_NOT_FOUND; return SCI_ERROR_RESMAP_NOT_FOUND;
} }
@ -1252,15 +1259,26 @@ int ResourceManager::readResourceMapSCI0(ResourceSource *map) {
res->_id = resId; res->_id = resId;
_resMap.setVal(resId, res); _resMap.setVal(resId, res);
} }
} while (!file.eos()); } while (!fileStream->eos());
delete fileStream;
return 0; return 0;
} }
int ResourceManager::readResourceMapSCI1(ResourceSource *map) { int ResourceManager::readResourceMapSCI1(ResourceSource *map) {
Common::File file; Common::SeekableReadStream *fileStream = 0;
Resource *res; Resource *res;
if (!file.open(map->location_name))
return SCI_ERROR_RESMAP_NOT_FOUND; if (map->resourceFile) {
fileStream = map->resourceFile->createReadStream();
if (!fileStream)
return SCI_ERROR_RESMAP_NOT_FOUND;
} else {
Common::File *file = new Common::File();
if (!file->open(map->location_name))
return SCI_ERROR_RESMAP_NOT_FOUND;
fileStream = file;
}
resource_index_t resMap[32]; resource_index_t resMap[32];
memset(resMap, 0, sizeof(resource_index_t) * 32); memset(resMap, 0, sizeof(resource_index_t) * 32);
@ -1271,8 +1289,8 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map) {
// Read resource type and offsets to resource offsets block from .MAP file // Read resource type and offsets to resource offsets block from .MAP file
// The last entry has type=0xFF (0x1F) and offset equals to map file length // The last entry has type=0xFF (0x1F) and offset equals to map file length
do { do {
type = file.readByte() & 0x1F; type = fileStream->readByte() & 0x1F;
resMap[type].wOffset = file.readUint16LE(); resMap[type].wOffset = fileStream->readUint16LE();
resMap[prevtype].wSize = (resMap[type].wOffset resMap[prevtype].wSize = (resMap[type].wOffset
- resMap[prevtype].wOffset) / nEntrySize; - resMap[prevtype].wOffset) / nEntrySize;
prevtype = type; prevtype = type;
@ -1283,18 +1301,18 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map) {
for (type = 0; type < 32; type++) { for (type = 0; type < 32; type++) {
if (resMap[type].wOffset == 0) // this resource does not exist in map if (resMap[type].wOffset == 0) // this resource does not exist in map
continue; continue;
file.seek(resMap[type].wOffset); fileStream->seek(resMap[type].wOffset);
for (int i = 0; i < resMap[type].wSize; i++) { for (int i = 0; i < resMap[type].wSize; i++) {
uint16 number = file.readUint16LE(); uint16 number = fileStream->readUint16LE();
int volume_nr = 0; int volume_nr = 0;
if (_mapVersion == kResVersionSci11) { if (_mapVersion == kResVersionSci11) {
// offset stored in 3 bytes // offset stored in 3 bytes
off = file.readUint16LE(); off = fileStream->readUint16LE();
off |= file.readByte() << 16; off |= fileStream->readByte() << 16;
off <<= 1; off <<= 1;
} else { } else {
// offset/volume stored in 4 bytes // offset/volume stored in 4 bytes
off = file.readUint32LE(); off = fileStream->readUint32LE();
if (_mapVersion < kResVersionSci11) { if (_mapVersion < kResVersionSci11) {
volume_nr = off >> 28; // most significant 4 bits volume_nr = off >> 28; // most significant 4 bits
off &= 0x0FFFFFFF; // least significant 28 bits off &= 0x0FFFFFFF; // least significant 28 bits
@ -1302,7 +1320,8 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map) {
// in SCI32 it's a plain offset // in SCI32 it's a plain offset
} }
} }
if (file.eos() || file.err()) { if (fileStream->eos() || fileStream->err()) {
delete fileStream;
warning("Error while reading %s", map->location_name.c_str()); warning("Error while reading %s", map->location_name.c_str());
return SCI_ERROR_RESMAP_NOT_FOUND; return SCI_ERROR_RESMAP_NOT_FOUND;
} }
@ -1322,6 +1341,8 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map) {
} }
} }
} }
delete fileStream;
return 0; return 0;
} }
@ -1574,7 +1595,7 @@ ResourceCompression ResourceManager::getViewCompression() {
// Test 10 views to see if any are compressed // Test 10 views to see if any are compressed
for (int i = 0; i < 1000; i++) { for (int i = 0; i < 1000; i++) {
Common::File *file; Common::SeekableReadStream *fileStream = 0;
Resource *res = testResource(ResourceId(kResourceTypeView, i)); Resource *res = testResource(ResourceId(kResourceTypeView, i));
if (!res) if (!res)
@ -1583,16 +1604,26 @@ ResourceCompression ResourceManager::getViewCompression() {
if (res->_source->source_type != kSourceVolume) if (res->_source->source_type != kSourceVolume)
continue; continue;
file = getVolumeFile(res->_source->location_name.c_str()); if (res->_source->resourceFile)
if (!file) fileStream = res->_source->resourceFile->createReadStream();
else
fileStream = getVolumeFile(res->_source->location_name.c_str());
if (!fileStream)
continue; continue;
file->seek(res->_fileOffset, SEEK_SET); fileStream->seek(res->_fileOffset, SEEK_SET);
uint32 szPacked; uint32 szPacked;
ResourceCompression compression; ResourceCompression compression;
if (readResourceInfo(res, file, szPacked, compression)) if (readResourceInfo(res, fileStream, szPacked, compression)) {
if (res->_source->resourceFile)
delete fileStream;
continue; continue;
}
if (res->_source->resourceFile)
delete fileStream;
if (compression != kCompNone) if (compression != kCompNone)
return compression; return compression;

View file

@ -33,13 +33,20 @@
namespace Sci { namespace Sci {
void ResourceManager::checkIfAudioVolumeIsCompressed(ResourceSource *source) { void ResourceManager::checkIfAudioVolumeIsCompressed(ResourceSource *source) {
Common::File *file = getVolumeFile(source->location_name.c_str()); Common::SeekableReadStream *fileStream;
if (!file) {
if (source->resourceFile)
fileStream = source->resourceFile->createReadStream();
else
fileStream = getVolumeFile(source->location_name.c_str());
if (!fileStream) {
warning("Failed to open %s", source->location_name.c_str()); warning("Failed to open %s", source->location_name.c_str());
return; return;
} }
file->seek(0, SEEK_SET);
uint32 compressionType = file->readUint32BE(); fileStream->seek(0, SEEK_SET);
uint32 compressionType = fileStream->readUint32BE();
switch (compressionType) { switch (compressionType) {
case MKID_BE('MP3 '): case MKID_BE('MP3 '):
case MKID_BE('OGG '): case MKID_BE('OGG '):
@ -47,19 +54,22 @@ void ResourceManager::checkIfAudioVolumeIsCompressed(ResourceSource *source) {
// Detected a compressed audio volume // Detected a compressed audio volume
source->audioCompressionType = compressionType; source->audioCompressionType = compressionType;
// Now read the whole offset mapping table for later usage // Now read the whole offset mapping table for later usage
int32 recordCount = file->readUint32LE(); int32 recordCount = fileStream->readUint32LE();
if (!recordCount) if (!recordCount)
error("compressed audio volume doesn't contain any entries!"); error("compressed audio volume doesn't contain any entries!");
int32 *offsetMapping = new int32[(recordCount + 1) * 2]; int32 *offsetMapping = new int32[(recordCount + 1) * 2];
source->audioCompressionOffsetMapping = offsetMapping; source->audioCompressionOffsetMapping = offsetMapping;
for (int recordNo = 0; recordNo < recordCount; recordNo++) { for (int recordNo = 0; recordNo < recordCount; recordNo++) {
*offsetMapping++ = file->readUint32LE(); *offsetMapping++ = fileStream->readUint32LE();
*offsetMapping++ = file->readUint32LE(); *offsetMapping++ = fileStream->readUint32LE();
} }
// Put ending zero // Put ending zero
*offsetMapping++ = 0; *offsetMapping++ = 0;
*offsetMapping++ = file->size(); *offsetMapping++ = fileStream->size();
} }
if (source->resourceFile)
delete fileStream;
} }
bool ResourceManager::loadFromWaveFile(Resource *res, Common::SeekableReadStream *file) { bool ResourceManager::loadFromWaveFile(Resource *res, Common::SeekableReadStream *file) {