aboutsummaryrefslogtreecommitdiff
path: root/scumm
diff options
context:
space:
mode:
authorMax Horn2004-01-19 20:27:31 +0000
committerMax Horn2004-01-19 20:27:31 +0000
commit923adce4562897a6df4f023622f1770d0eac4c15 (patch)
tree8da9ef77ee87ffa0b98c5d85cf496ae697e51673 /scumm
parent8e89f7d060ca5fac1efc7c244df91b678f7e2c9d (diff)
downloadscummvm-rg350-923adce4562897a6df4f023622f1770d0eac4c15.tar.gz
scummvm-rg350-923adce4562897a6df4f023622f1770d0eac4c15.tar.bz2
scummvm-rg350-923adce4562897a6df4f023622f1770d0eac4c15.zip
fix endian bug when dealing with ArrayHeader's; added a hack to permit save games broken due to this to still work; moved the whole 'Array' stuff into ScummEngine_v6
svn-id: r12521
Diffstat (limited to 'scumm')
-rw-r--r--scumm/intern.h11
-rw-r--r--scumm/resource.cpp31
-rw-r--r--scumm/resource.h16
-rw-r--r--scumm/script.cpp70
-rw-r--r--scumm/script_v6.cpp123
-rw-r--r--scumm/script_v8.cpp24
-rw-r--r--scumm/scumm.h8
7 files changed, 154 insertions, 129 deletions
diff --git a/scumm/intern.h b/scumm/intern.h
index efd5aaf06e..fa40e525bb 100644
--- a/scumm/intern.h
+++ b/scumm/intern.h
@@ -29,6 +29,7 @@
namespace Scumm {
class NutRenderer; // V8 Font Renderer
+struct ArrayHeader;
class ScummEngine_v5 : public ScummEngine {
protected:
@@ -348,11 +349,20 @@ protected:
virtual void setupScummVars();
virtual void decodeParseString(int a, int b);
+ virtual void readArrayFromIndexFile();
virtual void palManipulateInit(int resID, int start, int end, int time);
int getStackList(int *args, uint maxnum);
int popRoomAndObj(int *room);
+
+ ArrayHeader *getArray(int array);
+ ArrayHeader *defineArray(int array, int type, int dim2, int dim1);
+ int findFreeArrayId();
+ void nukeArray(int array);
+ int readArray(int array, int index, int base);
+ void writeArray(int array, int index, int base, int value);
+
void shuffleArray(int num, int minIdx, int maxIdx);
void unknownEA_func(int a, int b, int c, int d, int e);
int readFileToArray(int slot, int32 size);
@@ -575,6 +585,7 @@ protected:
virtual void setupScummVars();
virtual void decodeParseString(int m, int n);
+ virtual void readArrayFromIndexFile();
virtual uint fetchScriptWord();
virtual int fetchScriptWordSigned();
diff --git a/scumm/resource.cpp b/scumm/resource.cpp
index bb719b5d9c..dd7c311732 100644
--- a/scumm/resource.cpp
+++ b/scumm/resource.cpp
@@ -437,36 +437,7 @@ void ScummEngine::readIndexFile() {
}
void ScummEngine::readArrayFromIndexFile() {
- int num;
- int a, b, c;
-
- if (_version == 8) {
- while ((num = _fileHandle.readUint32LE()) != 0) {
- a = _fileHandle.readUint32LE();
- b = _fileHandle.readUint32LE();
-
- // FIXME - seems the COMI scripts have a bug related to array 436.
- // and visible in script 2015, room 20. Basically, the dimensions
- // are swapped in the definition of the array, but its obvious
- // that this must be a script bug simply by looking at the defintions
- // of other arrays and how they are used.
- // Talk to fingolfin if you have questions about this :-)
- if (num == 436)
- defineArray(num, 5, b, a);
- else
- defineArray(num, 5, a, b);
- }
- } else {
- while ((num = _fileHandle.readUint16LE()) != 0) {
- a = _fileHandle.readUint16LE();
- b = _fileHandle.readUint16LE();
- c = _fileHandle.readUint16LE();
- if (c == 1)
- defineArray(num, 1, a, b);
- else
- defineArray(num, 5, a, b);
- }
- }
+ error("readArrayFromIndexFile() not supported in pre-V6 games");
}
void ScummEngine::readResTypeList(int id, uint32 tag, const char *name) {
diff --git a/scumm/resource.h b/scumm/resource.h
index 2cf7f2612f..567981ee14 100644
--- a/scumm/resource.h
+++ b/scumm/resource.h
@@ -31,6 +31,13 @@ struct ResHdr {
uint32 tag, size;
} GCC_PACK;
+struct ArrayHeader {
+ int16 dim1;
+ int16 type;
+ int16 dim2;
+ byte data[1];
+} GCC_PACK;
+
#if !defined(__GNUC__)
#pragma END_PACK_STRUCTS
#endif
@@ -52,15 +59,6 @@ enum {
};
-#define ARRAY_HDR_SIZE 6
-struct ArrayHeader {
- int16 dim1_size;
- int16 type;
- int16 dim2_size;
- byte data[1];
-};
-
-
const byte *findResource(uint32 tag, const byte *searchin);
const byte *findResourceSmall(uint32 tag, const byte *searchin);
diff --git a/scumm/script.cpp b/scumm/script.cpp
index 36cd30f77f..5c329c31ba 100644
--- a/scumm/script.cpp
+++ b/scumm/script.cpp
@@ -980,76 +980,6 @@ bool ScummEngine::isRoomScriptRunning(int script) const {
return false;
}
-int ScummEngine::defineArray(int array, int type, int dim2, int dim1) {
- int id;
- int size;
- ArrayHeader *ah;
-
- if (type != 4)
- type = 5;
-
- nukeArray(array);
-
- id = getArrayId();
-
- if (_version == 8) {
- if (array & 0x40000000) {
- }
-
- if (array & 0x80000000) {
- error("Can't define bit variable as array pointer");
- }
-
- size = (type == 5) ? 32 : 8;
- } else {
- if (array & 0x4000) {
- }
-
- if (array & 0x8000) {
- error("Can't define bit variable as array pointer");
- }
-
- size = (type == 5) ? 16 : 8;
- }
-
- writeVar(array, id);
-
- size *= dim2 + 1;
- size *= dim1 + 1;
- size >>= 3;
-
- ah = (ArrayHeader *)createResource(rtString, id, size + sizeof(ArrayHeader));
-
- ah->type = type;
- ah->dim1_size = dim1 + 1;
- ah->dim2_size = dim2 + 1;
-
- return id;
-}
-
-void ScummEngine::nukeArray(int a) {
- int data;
-
- data = readVar(a);
-
- if (data)
- nukeResource(rtString, data);
-
- writeVar(a, 0);
-}
-
-int ScummEngine::getArrayId() {
- byte **addr = _baseArrays;
- int i;
-
- for (i = 1; i < _numArray; i++) {
- if (!addr[i])
- return i;
- }
- error("Out of array pointers, %d max", _numArray);
- return -1;
-}
-
void ScummEngine::copyScriptString(byte *dst) {
int len = resStrLen(_scriptPointer) + 1;
while (len--)
diff --git a/scumm/script_v6.cpp b/scumm/script_v6.cpp
index 6ca3af6d35..e544be6683 100644
--- a/scumm/script_v6.cpp
+++ b/scumm/script_v6.cpp
@@ -396,24 +396,111 @@ int ScummEngine_v6::popRoomAndObj(int *room) {
return obj;
}
+ArrayHeader *ScummEngine_v6::defineArray(int array, int type, int dim2, int dim1) {
+ int id;
+ int size;
+ ArrayHeader *ah;
+
+ if (type != 4)
+ type = 5;
+
+ nukeArray(array);
+
+ id = findFreeArrayId();
+
+ if (_version == 8) {
+ if (array & 0x40000000) {
+ }
+
+ if (array & 0x80000000) {
+ error("Can't define bit variable as array pointer");
+ }
+
+ size = (type == 5) ? 32 : 8;
+ } else {
+ if (array & 0x4000) {
+ }
+
+ if (array & 0x8000) {
+ error("Can't define bit variable as array pointer");
+ }
+
+ size = (type == 5) ? 16 : 8;
+ }
+
+ writeVar(array, id);
+
+ size *= dim2 + 1;
+ size *= dim1 + 1;
+ size >>= 3;
+
+ ah = (ArrayHeader *)createResource(rtString, id, size + sizeof(ArrayHeader));
+
+ ah->type = TO_LE_16(type);
+ ah->dim1 = TO_LE_16(dim1 + 1);
+ ah->dim2 = TO_LE_16(dim2 + 1);
+
+ return ah;
+}
+
+void ScummEngine_v6::nukeArray(int a) {
+ int data;
-int ScummEngine::readArray(int array, int idx, int base) {
+ data = readVar(a);
+
+ if (data)
+ nukeResource(rtString, data);
+
+ writeVar(a, 0);
+}
+
+int ScummEngine_v6::findFreeArrayId() {
+ byte **addr = _baseArrays;
+ int i;
+
+ for (i = 1; i < _numArray; i++) {
+ if (!addr[i])
+ return i;
+ }
+ error("Out of array pointers, %d max", _numArray);
+ return -1;
+}
+
+ArrayHeader *ScummEngine_v6::getArray(int array) {
ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array));
+ if (!ah)
+ return 0;
+
+ // Workaround for a long standing bug where we save array headers in native
+ // endianess, instead of a fixed endianess. We try to detect savegames
+ // which were created on a big endian system and convert them to little
+ // endian.
+ if ((ah->dim1 & 0xF000) || (ah->dim2 & 0xF000) || (ah->type & 0xFF00)) {
+ SWAP_BYTES_16(ah->dim1);
+ SWAP_BYTES_16(ah->dim2);
+ SWAP_BYTES_16(ah->type);
+ }
+
+ return ah;
+}
+
+int ScummEngine_v6::readArray(int array, int idx, int base) {
+ ArrayHeader *ah = getArray(array);
if (ah == NULL || ah->data == NULL) {
error("readArray: invalid array %d (%d)", array, readVar(array));
}
- base += idx * ah->dim1_size;
+ base += idx * FROM_LE_16(ah->dim1);
// FIXME: comment this for the time being as it was causing ft to crash
// in the minefeild
// FIX THE FIXME: fixing an assert by commenting out is bad. It's evil.
// It's wrong. Find the proper cause, or at least, silently return
// from the function, but don't just go on overwriting memory!
- assert(base >= 0 && base < ah->dim1_size * ah->dim2_size);
+ assert(base >= 0 && base < FROM_LE_16(ah->dim1) * FROM_LE_16(ah->dim2));
- if (ah->type == 4) {
+ if (FROM_LE_16(ah->type) == 4) {
return ah->data[base];
} else if (_version == 8) {
return (int32)READ_LE_UINT32(ah->data + base * 4);
@@ -422,15 +509,15 @@ int ScummEngine::readArray(int array, int idx, int base) {
}
}
-void ScummEngine::writeArray(int array, int idx, int base, int value) {
- ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array));
+void ScummEngine_v6::writeArray(int array, int idx, int base, int value) {
+ ArrayHeader *ah = getArray(array);
if (!ah)
return;
- base += idx * ah->dim1_size;
+ base += idx * FROM_LE_16(ah->dim1);
- assert(base >= 0 && base < ah->dim1_size * ah->dim2_size);
+ assert(base >= 0 && base < FROM_LE_16(ah->dim1) * FROM_LE_16(ah->dim2));
- if (ah->type == 4) {
+ if (FROM_LE_16(ah->type) == 4) {
ah->data[base] = value;
} else if (_version == 8) {
#if defined(SCUMM_NEED_ALIGNMENT)
@@ -449,6 +536,21 @@ void ScummEngine::writeArray(int array, int idx, int base, int value) {
}
}
+void ScummEngine_v6::readArrayFromIndexFile() {
+ int num;
+ int a, b, c;
+
+ while ((num = _fileHandle.readUint16LE()) != 0) {
+ a = _fileHandle.readUint16LE();
+ b = _fileHandle.readUint16LE();
+ c = _fileHandle.readUint16LE();
+ if (c == 1)
+ defineArray(num, 1, a, b);
+ else
+ defineArray(num, 5, a, b);
+ }
+}
+
int ScummEngine_v6::getStackList(int *args, uint maxnum) {
uint num, i;
@@ -2024,8 +2126,7 @@ void ScummEngine_v6::o6_arrayOps() {
case 205: // SO_ASSIGN_STRING
b = pop();
len = resStrLen(_scriptPointer);
- c = defineArray(array, 4, 0, len + 1);
- ah = (ArrayHeader *)getResourceAddress(rtString, c);
+ ah = defineArray(array, 4, 0, len + 1);
copyScriptString(ah->data + b);
break;
case 208: // SO_ASSIGN_INT_LIST
diff --git a/scumm/script_v8.cpp b/scumm/script_v8.cpp
index d33a445b64..2d40dc2b62 100644
--- a/scumm/script_v8.cpp
+++ b/scumm/script_v8.cpp
@@ -535,6 +535,27 @@ void ScummEngine_v8::decodeParseString(int m, int n) {
}
}
+void ScummEngine_v8::readArrayFromIndexFile() {
+ int num;
+ int a, b;
+
+ while ((num = _fileHandle.readUint32LE()) != 0) {
+ a = _fileHandle.readUint32LE();
+ b = _fileHandle.readUint32LE();
+
+ // FIXME - seems the COMI scripts have a bug related to array 436.
+ // and visible in script 2015, room 20. Basically, the dimensions
+ // are swapped in the definition of the array, but its obvious
+ // that this must be a script bug simply by looking at the defintions
+ // of other arrays and how they are used.
+ // Talk to fingolfin if you have questions about this :-)
+ if (num == 436)
+ defineArray(num, 5, b, a);
+ else
+ defineArray(num, 5, a, b);
+ }
+}
+
void ScummEngine_v8::o8_mod() {
int a = pop();
push(pop() % a);
@@ -646,8 +667,7 @@ void ScummEngine_v8::o8_arrayOps() {
case 0x14: // SO_ASSIGN_STRING
b = pop();
len = resStrLen(_scriptPointer);
- c = defineArray(array, 4, 0, len + 1);
- ah = (ArrayHeader *)getResourceAddress(rtString, c);
+ ah = defineArray(array, 4, 0, len + 1);
copyScriptString(ah->data + b);
break;
case 0x15: // SO_ASSIGN_SCUMMVAR_LIST
diff --git a/scumm/scumm.h b/scumm/scumm.h
index 15207c3d2f..c2fba44076 100644
--- a/scumm/scumm.h
+++ b/scumm/scumm.h
@@ -635,7 +635,7 @@ protected:
void loadRoomObjectsSmall();
void loadRoomObjectsOldBundle();
- void readArrayFromIndexFile();
+ virtual void readArrayFromIndexFile();
virtual void readMAXS();
virtual void readIndexFile();
virtual void loadCharset(int i);
@@ -648,12 +648,6 @@ public:
void dumpResource(const char *tag, int index, const byte *ptr, int length = -1);
protected:
- int getArrayId();
- void nukeArray(int a);
- int defineArray(int a, int b, int c, int d);
- int readArray(int array, int index, int base);
- void writeArray(int array, int index, int base, int value);
-
void resourceStats();
void expireResources(uint32 size);
void freeResources();