From 923adce4562897a6df4f023622f1770d0eac4c15 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 19 Jan 2004 20:27:31 +0000 Subject: 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 --- scumm/intern.h | 11 +++++ scumm/resource.cpp | 31 +------------ scumm/resource.h | 16 +++---- scumm/script.cpp | 70 ------------------------------ scumm/script_v6.cpp | 123 +++++++++++++++++++++++++++++++++++++++++++++++----- scumm/script_v8.cpp | 24 +++++++++- scumm/scumm.h | 8 +--- 7 files changed, 154 insertions(+), 129 deletions(-) (limited to 'scumm') 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(); -- cgit v1.2.3