aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/resource.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/resource.cpp')
-rw-r--r--engines/sci/resource.cpp146
1 files changed, 123 insertions, 23 deletions
diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp
index 10740a8b7b..f35781231b 100644
--- a/engines/sci/resource.cpp
+++ b/engines/sci/resource.cpp
@@ -82,8 +82,12 @@ const char *getSciVersionDesc(SciVersion version) {
return "SCI1.1";
case SCI_VERSION_2:
return "SCI2";
- case SCI_VERSION_2_1:
- return "SCI2.1";
+ case SCI_VERSION_2_1_EARLY:
+ return "Early SCI2.1";
+ case SCI_VERSION_2_1_MIDDLE:
+ return "Middle SCI2.1";
+ case SCI_VERSION_2_1_LATE:
+ return "Late SCI2.1";
case SCI_VERSION_3:
return "SCI3";
default:
@@ -2121,6 +2125,79 @@ ViewType ResourceManager::detectViewType() {
return kViewUnknown;
}
+// to detect selector "wordFail" in LE vocab resource
+static const byte detectSci21EarlySignature[] = {
+ 10, // size of signature
+ 0x08, 0x00, 'w', 'o', 'r', 'd', 'F', 'a', 'i', 'l'
+};
+
+// to detect selector "wordFail" in BE vocab resource (SCI2.1 Early)
+static const byte detectSci21EarlyBESignature[] = {
+ 10, // size of signature
+ 0x00, 0x08, 'w', 'o', 'r', 'd', 'F', 'a', 'i', 'l'
+};
+
+// to detect new kString calling to detect SCI2.1 Late
+static const byte detectSci21NewStringSignature[] = {
+ 8, // size of signature
+ 0x78, // push1
+ 0x78, // push1
+ 0x39, 0x09, // pushi 09
+ 0x59, 0x01, // rest 01
+ 0x43, 0x5c, // callk String
+};
+
+bool ResourceManager::checkResourceDataForSignature(Resource *resource, const byte *signature) {
+ byte signatureSize = *signature;
+ const byte *resourceData = resource->data;
+
+ signature++; // skip over size byte
+ if (signatureSize < 4)
+ error("resource signature is too small, internal error");
+ if (signatureSize > resource->size)
+ return false;
+
+ const uint32 signatureDWord = *((const uint32 *)signature);
+ signature += 4; signatureSize -= 4;
+
+ const uint32 searchLimit = resource->size - signatureSize + 1;
+ uint32 DWordOffset = 0;
+ while (DWordOffset < searchLimit) {
+ if (signatureDWord == READ_UINT32(resourceData + DWordOffset)) {
+ // magic DWORD found, check if the rest matches as well
+ uint32 offset = DWordOffset + 4;
+ uint32 signaturePos = 0;
+ while (signaturePos < signatureSize) {
+ if (resourceData[offset] != signature[signaturePos])
+ break;
+ offset++;
+ signaturePos++;
+ }
+ if (signaturePos >= signatureSize)
+ return true; // signature found
+ }
+ DWordOffset++;
+ }
+ return false;
+}
+
+bool ResourceManager::checkResourceForSignatures(ResourceType resourceType, uint16 resourceNr, const byte *signature1, const byte *signature2) {
+ Resource *resource = findResource(ResourceId(resourceType, resourceNr), false);
+
+ if (resource) {
+ // resource found and loaded, check for signatures
+ if (signature1) {
+ if (checkResourceDataForSignature(resource, signature1))
+ return true;
+ }
+ if (signature2) {
+ if (checkResourceDataForSignature(resource, signature2))
+ return true;
+ }
+ }
+ return false;
+}
+
void ResourceManager::detectSciVersion() {
// We use the view compression to set a preliminary s_sciVersion for the sake of getResourceInfo
// Pretend we have a SCI0 game
@@ -2180,31 +2257,52 @@ void ResourceManager::detectSciVersion() {
// no Mac SCI2 games. Yes, that means that GK1 Mac is SCI2.1 and not SCI2.
// TODO: Decide between SCI2.1 and SCI3
- if (res)
- s_sciVersion = SCI_VERSION_2_1;
- else
+ if (res) {
+ s_sciVersion = SCI_VERSION_2_1_EARLY; // we check for SCI2.1 specifics a bit later
+ } else {
s_sciVersion = SCI_VERSION_1_1;
- return;
+ return;
+ }
}
// Handle SCI32 versions here
- if (_volVersion >= kResVersionSci2) {
- Common::List<ResourceId> heaps = listResources(kResourceTypeHeap);
- bool hasHeapResources = !heaps.empty();
-
- // SCI2.1/3 and SCI1 Late resource maps are the same, except that
- // SCI1 Late resource maps have the resource types or'd with
- // 0x80. We differentiate between SCI2 and SCI2.1/3 based on that.
- if (_mapVersion == kResVersionSci1Late) {
- s_sciVersion = SCI_VERSION_2;
- return;
- } else if (hasHeapResources) {
- s_sciVersion = SCI_VERSION_2_1;
+ if (s_sciVersion != SCI_VERSION_2_1_EARLY) {
+ if (_volVersion >= kResVersionSci2) {
+ Common::List<ResourceId> heaps = listResources(kResourceTypeHeap);
+ bool hasHeapResources = !heaps.empty();
+
+ // SCI2.1/3 and SCI1 Late resource maps are the same, except that
+ // SCI1 Late resource maps have the resource types or'd with
+ // 0x80. We differentiate between SCI2 and SCI2.1/3 based on that.
+ if (_mapVersion == kResVersionSci1Late) {
+ s_sciVersion = SCI_VERSION_2;
+ return;
+ } else if (hasHeapResources) {
+ s_sciVersion = SCI_VERSION_2_1_EARLY; // exact SCI2.1 version is checked a bit later
+ } else {
+ s_sciVersion = SCI_VERSION_3;
+ return;
+ }
+ }
+ }
+
+ if (s_sciVersion == SCI_VERSION_2_1_EARLY) {
+ // we only know that it's SCI2.1, not which exact version it is
+
+ // check, if selector "wordFail" inside vocab 997 exists, if it does it's SCI2.1 Early
+ if ((checkResourceForSignatures(kResourceTypeVocab, 997, detectSci21EarlySignature, detectSci21EarlyBESignature))) {
+ // found -> it is SCI2.1 early
return;
- } else {
- s_sciVersion = SCI_VERSION_3;
+ }
+
+ s_sciVersion = SCI_VERSION_2_1_MIDDLE;
+ if (checkResourceForSignatures(kResourceTypeScript, 64918, detectSci21NewStringSignature, nullptr)) {
+ // new kString call detected, it's SCI2.1 late
+ // TODO: this call seems to be different on Mac
+ s_sciVersion = SCI_VERSION_2_1_LATE;
return;
}
+ return;
}
// Check for transitive SCI1/SCI1.1 games, like PQ1 here
@@ -2537,7 +2635,7 @@ reg_t ResourceManager::findGameObject(bool addSci11ScriptOffset) {
int16 offset = !isSci11Mac() ? READ_LE_UINT16(offsetPtr) : READ_BE_UINT16(offsetPtr);
return make_reg(1, offset);
- } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
+ } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
offsetPtr = script->data + 4 + 2 + 2;
// In SCI1.1 - SCI2.1, the heap is appended at the end of the script,
@@ -2565,7 +2663,7 @@ Common::String ResourceManager::findSierraGameId() {
if (getSciVersion() < SCI_VERSION_1_1) {
heap = findResource(ResourceId(kResourceTypeScript, 0), false);
- } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
+ } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
heap = findResource(ResourceId(kResourceTypeHeap, 0), false);
nameSelector += 5;
} else if (getSciVersion() == SCI_VERSION_3) {
@@ -2581,7 +2679,9 @@ Common::String ResourceManager::findSierraGameId() {
return "";
// Seek to the name selector of the first export
- byte *seeker = heap->data + READ_UINT16(heap->data + gameObjectOffset + nameSelector * 2);
+ byte *offsetPtr = heap->data + gameObjectOffset + nameSelector * 2;
+ uint16 offset = !isSci11Mac() ? READ_LE_UINT16(offsetPtr) : READ_BE_UINT16(offsetPtr);
+ byte *seeker = heap->data + offset;
Common::String sierraId;
sierraId += (const char *)seeker;