aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/resource.cpp
diff options
context:
space:
mode:
authorWalter van Niftrik2009-08-16 19:18:19 +0000
committerWalter van Niftrik2009-08-16 19:18:19 +0000
commit00f4794c0a0168a86d7e58e3f585f7fa4d02c7c9 (patch)
tree44f0da44eb3c80367c1921d763c99ffe3be15a42 /engines/sci/resource.cpp
parent582eb13fa2680a60ac5d1770c450fabfbc15a1b5 (diff)
downloadscummvm-rg350-00f4794c0a0168a86d7e58e3f585f7fa4d02c7c9.tar.gz
scummvm-rg350-00f4794c0a0168a86d7e58e3f585f7fa4d02c7c9.tar.bz2
scummvm-rg350-00f4794c0a0168a86d7e58e3f585f7fa4d02c7c9.zip
SCI: Stage 1 of the game detection overhaul. The end goal is to autodetect
as much as possible. All SCI_VERSION_* information was removed from detection.cpp (much of it was incorrect anyway). svn-id: r43449
Diffstat (limited to 'engines/sci/resource.cpp')
-rw-r--r--engines/sci/resource.cpp388
1 files changed, 249 insertions, 139 deletions
diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp
index b42f36bd63..d641dac308 100644
--- a/engines/sci/resource.cpp
+++ b/engines/sci/resource.cpp
@@ -319,63 +319,6 @@ int sci0_get_compression_method(Common::ReadStream &stream) {
return compressionMethod;
}
-SciVersion ResourceManager::guessSciVersion() {
- Common::File file;
- char filename[MAXPATHLEN];
- int compression;
- Resource *res;
- int i;
-
- for (i = 0; i < 1000; i++) {
- res = testResource(ResourceId(kResourceTypeView, i));
-
- if (!res)
- continue;
-
- if (res->source->source_type == kSourceDirectory)
- continue;
-
- strcpy(filename, res->source->location_name.c_str());
-
- if (!file.open(filename))
- continue;
- file.seek(res->file_offset, SEEK_SET);
-
- compression = sci0_get_compression_method(file);
- file.close();
-
- if (compression == 3) {
- return SCI_VERSION_01;
- }
- }
-
- // Try the same thing with pics
- for (i = 0; i < 1000; i++) {
- res = testResource(ResourceId(kResourceTypePic, i));
-
- if (!res)
- continue;
-
- if (res->source->source_type == kSourceDirectory)
- continue;
-
- strcpy(filename, res->source->location_name.c_str());
-
- if (!file.open(filename))
- continue;
- file.seek(res->file_offset, SEEK_SET);
-
- compression = sci0_get_compression_method(file);
- file.close();
-
- if (compression == 3) {
- return SCI_VERSION_01;
- }
- }
-
- return SCI_VERSION_AUTODETECT;
-}
-
int ResourceManager::addAppropriateSources() {
ResourceSource *map;
@@ -484,91 +427,23 @@ ResourceManager::ResourceManager(int maxMemory) {
addInternalSources();
scanNewSources();
- switch (_mapVersion) {
- case kResVersionSci0Sci1Early:
- if (testResource(ResourceId(kResourceTypeVocab, VOCAB_RESOURCE_SCI0_MAIN_VOCAB))) {
- _sciVersion = guessSciVersion() ? SCI_VERSION_01 : SCI_VERSION_0;
- } else if (testResource(ResourceId(kResourceTypeVocab, VOCAB_RESOURCE_SCI1_MAIN_VOCAB))) {
- _sciVersion = guessSciVersion();
- if (_sciVersion != SCI_VERSION_01) {
- _sciVersion = testResource(ResourceId(kResourceTypeVocab, 912)) ? SCI_VERSION_0 : SCI_VERSION_01;
- }
- } else {
- _sciVersion = guessSciVersion() ? SCI_VERSION_01 : SCI_VERSION_0;
- }
- break;
- case kResVersionSci1Middle:
- _sciVersion = SCI_VERSION_01;
- break;
- case kResVersionSci1Late:
- _sciVersion = SCI_VERSION_1;
- break;
- case kResVersionSci11:
- _sciVersion = SCI_VERSION_1_1;
- break;
- case kResVersionSci32:
- _sciVersion = SCI_VERSION_32;
- break;
- default:
- _sciVersion = SCI_VERSION_AUTODETECT;
- }
-
- _isVGA = false;
-
- // Determine if the game is using EGA graphics or not
- if (_sciVersion == SCI_VERSION_0) {
- _isVGA = false; // There is no SCI0 VGA game
- } else if (_sciVersion >= SCI_VERSION_1_1) {
- _isVGA = true; // There is no SCI11 EGA game
- } else {
- // SCI01 or SCI1: EGA games have the second byte of their views set
- // to 0, VGA ones to non-zero
- int i = 0;
-
- while (true) {
- Resource *res = findResource(ResourceId(kResourceTypeView, i), 0);
- if (res) {
- _isVGA = (res->data[1] != 0);
- break;
- }
- i++;
- }
- }
-
- // Workaround for QFG1 VGA (has SCI 1.1 view data with SCI 1 compression)
- if (_sciVersion == SCI_VERSION_1 && !strcmp(((SciEngine*)g_engine)->getGameID(), "qfg1")) {
- debug("Resmgr: Detected QFG1 VGA");
- _isVGA = true;
- }
+ _sciVersion = detectSciVersion();
- // temporary version printout - should be reworked later
- switch (_sciVersion) {
- case SCI_VERSION_0:
- debug("Resmgr: Detected SCI0");
- break;
- case SCI_VERSION_01:
- debug("Resmgr: Detected SCI01");
- break;
- case SCI_VERSION_1:
- debug("Resmgr: Detected SCI1");
- break;
- case SCI_VERSION_1_1:
- debug("Resmgr: Detected SCI1.1");
- break;
-#ifdef ENABLE_SCI32
- case SCI_VERSION_32:
+ if (_sciVersion != SCI_VERSION_AUTODETECT)
+ debug("Resmgr: Detected %s", versionNames[_sciVersion]);
+ else
debug("Resmgr: Couldn't determine SCI version");
+
+ switch (_viewType) {
+ case kViewEga:
+ debug("Resmgr: Detected EGA graphic resources");
break;
-#endif
- default:
- debug("Resmgr: Couldn't determine SCI version");
+ case kViewVga:
+ debug("Resmgr: Detected VGA graphic resources");
break;
+ case kViewVga11:
+ debug("Resmgr: Detected SCI1.1 VGA graphic resources");
}
-
- if (_isVGA)
- debug("Resmgr: Detected VGA graphic resources");
- else
- debug("Resmgr: Detected non-VGA/EGA graphic resources");
}
ResourceManager::~ResourceManager() {
@@ -1408,10 +1283,10 @@ int ResourceManager::readResourceInfo(Resource *res, Common::File *file,
compression = kCompNone;
break;
case 1:
- compression = (_sciVersion == SCI_VERSION_0) ? kCompLZW : kCompHuffman;
+ compression = (_sciVersion <= SCI_VERSION_01) ? kCompLZW : kCompHuffman;
break;
case 2:
- compression = (_sciVersion == SCI_VERSION_0) ? kCompHuffman : kCompLZW1;
+ compression = (_sciVersion <= SCI_VERSION_01) ? kCompHuffman : kCompLZW1;
break;
case 3:
compression = kCompLZW1View;
@@ -1483,4 +1358,239 @@ int ResourceManager::decompress(Resource *res, Common::File *file) {
return error;
}
+ResourceCompression ResourceManager::getViewCompression() {
+ int viewsTested = 0;
+
+ // Test 10 views to see if any are compressed
+ for (int i = 0; i < 1000; i++) {
+ Common::File *file;
+ Resource *res = testResource(ResourceId(kResourceTypeView, i));
+
+ if (!res)
+ continue;
+
+ if (res->source->source_type != kSourceVolume)
+ continue;
+
+ file = getVolumeFile(res->source->location_name.c_str());
+ if (!file)
+ continue;
+ file->seek(res->file_offset, SEEK_SET);
+
+ uint32 szPacked;
+ ResourceCompression compression;
+
+ if (readResourceInfo(res, file, szPacked, compression))
+ continue;
+
+ if (compression != kCompNone)
+ return compression;
+
+ if (++viewsTested == 10)
+ break;
+ }
+
+ return kCompNone;
+}
+
+ResourceManager::ViewType ResourceManager::detectViewType() {
+ for (int i = 0; i < 1000; i++) {
+ Resource *res = findResource(ResourceId(kResourceTypeView, i), 0);
+ if (res) {
+ //FIXME: Amiga
+ switch(res->data[1]) {
+ case 0:
+ return kViewEga;
+ default:
+ return kViewVga;
+ }
+ }
+ }
+
+ warning("Resmgr: Couldn't find any views");
+ return kViewVga;
+}
+
+SciVersion ResourceManager::detectSciVersion() {
+ // We use the view compression to set a preliminary _sciVersion for the sake of getResourceInfo
+ // Pretend we have a SCI0 game
+ _sciVersion = SCI_VERSION_0_EARLY;
+ bool oldDecompressors = true;
+
+ ResourceCompression viewCompression = getViewCompression();
+ if (viewCompression != kCompLZW) {
+ // If it's a different compression type from kCompLZW, the game is probably
+ // SCI_VERSION_1_EGA or later. If the views are uncompressed, it is
+ // likely not an early disk game.
+ _sciVersion = SCI_VERSION_1_EGA;
+ oldDecompressors = false;
+ }
+
+ // Set view type
+ if (viewCompression == kCompDCL) {
+ // SCI1.1 VGA views
+ _viewType = kViewVga11;
+ } else {
+ // Otherwise we detect it from a view
+ _viewType = detectViewType();
+ }
+
+ switch (_mapVersion) {
+ case kResVersionSci0Sci1Early:
+ if (_viewType == kViewVga) {
+ // VGA
+ return SCI_VERSION_1_EARLY;
+ }
+
+ // EGA
+ if (hasOldScriptHeader())
+ return SCI_VERSION_0_EARLY;
+
+ if (oldDecompressors) {
+ // It's either SCI_VERSION_0_LATE or SCI_VERSION_01
+
+ // We first check for SCI1 vocab.999
+ if (testResource(ResourceId(kResourceTypeVocab, 999))) {
+ if (hasSci0Voc999()) {
+ return SCI_VERSION_0_LATE;
+ } else {
+ return SCI_VERSION_01;
+ }
+ }
+
+ // If vocab.999 is missing, we try vocab.900
+ if (testResource(ResourceId(kResourceTypeVocab, 900))) {
+ if (hasSci1Voc900()) {
+ return SCI_VERSION_01;
+ } else {
+ return SCI_VERSION_0_LATE;
+ }
+ }
+
+ warning("Failed to accurately determine SCI version");
+ // No parser, we assume SCI_VERSION_01.
+ return SCI_VERSION_01;
+ }
+
+ // New decompressors. It's either SCI_VERSION_1_EGA or SCI_VERSION_1_EARLY.
+ if (hasSci1Voc900())
+ return SCI_VERSION_1_EGA;
+
+ // SCI_VERSION_1_EARLY EGA versions seem to be lacking a valid vocab.900.
+ // If this turns out to be unreliable, we could do some pic resource checks instead.
+ return SCI_VERSION_1_EARLY;
+ case kResVersionSci1Middle:
+ return SCI_VERSION_1_LATE;
+ case kResVersionSci1Late:
+ if (_viewType == kViewVga11) {
+ // SCI1.1 resources, assume SCI1.1
+ return SCI_VERSION_1_1;
+ }
+ return SCI_VERSION_1_LATE;
+ case kResVersionSci11:
+ return SCI_VERSION_1_1;
+ case kResVersionSci32:
+ return SCI_VERSION_32;
+ default:
+ return SCI_VERSION_AUTODETECT;
+ }
+}
+
+// Functions below are based on PD code by Brian Provinciano (SCI Studio)
+bool ResourceManager::hasOldScriptHeader() {
+ Resource *res = findResource(ResourceId(kResourceTypeScript, 0), 0);
+
+ if (!res) {
+ warning("Resmgr: Failed to find script.000");
+ return false;
+ }
+
+ uint offset = 2;
+ const int objTypes = 17;
+
+ while (offset < res->size) {
+ uint16 objType = READ_LE_UINT16(res->data + offset);
+
+ if (!objType) {
+ offset += 2;
+ // We should be at the end of the resource now
+ return offset == res->size;
+ }
+
+ if (objType >= objTypes) {
+ // Invalid objType
+ return false;
+ }
+
+ int skip = READ_LE_UINT16(res->data + offset + 2);
+
+ if (skip < 2) {
+ // Invalid size
+ return false;
+ }
+
+ offset += skip;
+ }
+
+ return false; }
+
+bool ResourceManager::hasSci0Voc999() {
+ Resource *res = findResource(ResourceId(kResourceTypeVocab, 999), 0);
+
+ if (!res) {
+ // No vocab present, possibly a demo version
+ return false;
+ }
+
+ if (res->size < 2)
+ return false;
+
+ uint16 count = READ_LE_UINT16(res->data);
+
+ // Make sure there's enough room for the pointers
+ if (res->size < (uint)count * 2)
+ return false;
+
+ // Iterate over all pointers
+ for (uint i = 0; i < count; i++) {
+ // Offset to string
+ uint16 offset = READ_LE_UINT16(res->data + 2 + count * 2);
+
+ // Look for end of string
+ do {
+ if (offset >= res->size) {
+ // Out of bounds
+ return false;
+ }
+ } while (res->data[offset++]);
+ }
+
+ return true;
+}
+
+bool ResourceManager::hasSci1Voc900() {
+ Resource *res = findResource(ResourceId(kResourceTypeVocab, 900), 0);
+
+ if (!res )
+ return false;
+
+ if (res->size < 0x1fe)
+ return false;
+
+ uint16 offset = 0x1fe;
+
+ while (offset < res->size) {
+ offset++;
+ do {
+ if (offset >= res->size) {
+ // Out of bounds;
+ return false;
+ }
+ } while (res->data[offset++]);
+ offset += 3;
+ }
+
+ return offset == res->size;
+}
+
} // End of namespace Sci