scummvm/engines/cruise/decompiler.cpp

1386 lines
29 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "cruise/cruise_main.h"
namespace Cruise {
#ifdef DUMP_SCRIPT
#define numMaxLignes 100000
#define lineMaxSize 10000
int currentLineType = 0;
struct decompileLineStruct {
int lineOffset;
char line[lineMaxSize];
int indent;
int type;
int pendingElse;
};
struct decompileLineStruct decompileLineTable[numMaxLignes];
int positionInDecompileLineTable;
int failed;
char *currentDecompScript;
scriptInstanceStruct dummy;
scriptInstanceStruct *currentDecompScriptPtr = &dummy;
uint8 *getDataFromData3(ovlData3Struct * ptr, int param);
opcodeTypeFunction decompOpcodeTypeTable[64];
int currentLineIdx = 0;
unsigned long int currentOffset;
unsigned long int dumpIdx = 0;
FILE *fHandle = NULL; // FIXME: Use Common::DumpFile instead of FILE
#define DECOMPILER_STACK_DEPTH 100
#define DECOMPILER_STACK_ENTRY_SIZE 5000
char tempbuffer[5000];
char decompileStack[DECOMPILER_STACK_DEPTH][DECOMPILER_STACK_ENTRY_SIZE];
unsigned long int decompileStackPosition = 0;
uint8 stringName[256];
ovlData3Struct *currentScript;
ovlDataStruct *currentDecompOvl;
int currentDecompScriptIdx;
char decompSaveOpcodeVar[256];
uint8 *getStringNameFromIdx(uint16 stringTypeIdx, char *offset) {
switch (stringTypeIdx & 7) {
case 2: {
sprintf(stringName, "\"%s\"",
currentScript->dataPtr +
currentScript->offsetToSubData3 + atoi(offset));
break;
}
case 5: {
sprintf(stringName, "vars[%s]", offset);
break;
}
default: {
sprintf(stringName, "string[%d][%s]",
stringTypeIdx & 7, offset);
break;
}
}
return stringName;
}
char *resolveMessage(char *messageIdxString) {
char buffer[500];
int variable;
variable = atoi(messageIdxString);
sprintf(buffer, "%d", variable);
if (strcmp(buffer, messageIdxString)) {
return messageIdxString;
} else {
return currentDecompOvl->stringTable[atoi(messageIdxString)].
string;
}
}
void pushDecomp(char *string, ...) {
va_list va;
va_start(va, string);
vsprintf(decompileStack[decompileStackPosition], string, va);
va_end(va);
// fprintf(fHandle, "----> %s\n",decompileStack[decompileStackPosition]);
decompileStackPosition++;
}
void resolveDecompShort(char *buffer) {
ovlData3Struct *data3Ptr = currentScript;
importScriptStruct *importEntry =
(importScriptStruct *)(data3Ptr->dataPtr +
data3Ptr->offsetToImportData);
for (int i = 0; i < data3Ptr->numRelocGlob; i++) {
switch (importEntry->type) {
case 20: // script
case 30:
case 40:
case 50: {
if (importEntry->offset == currentDecompScriptPtr->var4 - 3) { // param1
sprintf(buffer,
data3Ptr->dataPtr +
data3Ptr->
offsetToImportName +
importEntry->offsetToName);
return;
}
if (importEntry->offset == currentDecompScriptPtr->var4 - 6) { // param2
sprintf(buffer, "linkedIdx");
return;
}
break;
}
default: {
if (importEntry->offset ==
currentDecompScriptPtr->var4 - 4) {
sprintf(buffer,
data3Ptr->dataPtr +
data3Ptr->
offsetToImportName +
importEntry->offsetToName);
return;
}
}
}
importEntry++;
}
buffer[0] = 0;
}
void resolveDecompChar(char *buffer) {
ovlData3Struct *data3Ptr = currentScript;
importScriptStruct *importEntry =
(importScriptStruct *)(data3Ptr->dataPtr +
data3Ptr->offsetToImportData);
for (int i = 0; i < data3Ptr->numRelocGlob; i++) {
switch (importEntry->type) {
default: {
if (importEntry->offset ==
currentDecompScriptPtr->var4 - 2) {
sprintf(buffer,
data3Ptr->dataPtr +
data3Ptr->
offsetToImportName +
importEntry->offsetToName);
return;
}
}
}
importEntry++;
}
buffer[0] = 0;
}
char *popDecomp() {
// printf("<----\n");
if (!decompileStackPosition) {
return ("");
}
decompileStackPosition--;
return decompileStack[decompileStackPosition];
}
void getByteFromDecompScript(char *buffer) {
short int var = currentDecompScript[currentDecompScriptPtr->var4];
currentDecompScriptPtr->var4 = currentDecompScriptPtr->var4 + 1;
if (var == -1) {
resolveDecompChar(buffer);
if (buffer[0])
return;
}
sprintf(buffer, "%d", var);
}
char getByteFromDecompScriptReal() {
short int var = currentDecompScript[currentDecompScriptPtr->var4];
currentDecompScriptPtr->var4 = currentDecompScriptPtr->var4 + 1;
return var;
}
void getShortFromDecompScript(char *buffer) {
int16 var = (int16)READ_BE_UINT16(currentDecompScript + currentDecompScriptPtr->var4);
currentDecompScriptPtr->var4 = currentDecompScriptPtr->var4 + 2;
if (var == -1) {
resolveDecompShort(buffer);
if (buffer[0])
return;
}
sprintf(buffer, "%d", var);
}
int16 getShortFromDecompScriptReal() {
int16 var = (int16)READ_BE_UINT16(currentDecompScript + currentDecompScriptPtr->var4);
currentDecompScriptPtr->var4 = currentDecompScriptPtr->var4 + 2;
return var;
}
void addDecomp(char *string, ...) {
va_list va;
/* fprintf(fHandle,"%d: ",currentLineIdx);
*
* va_start(va,string);
* vfprintf(fHandle,string,va);
* va_end(va);
*
* fprintf(fHandle,"\n"); */
struct decompileLineStruct *pLineStruct =
&decompileLineTable[positionInDecompileLineTable++];
pLineStruct->lineOffset = currentLineIdx;
pLineStruct->indent = 0;
pLineStruct->type = currentLineType;
pLineStruct->line[0] = 0;
pLineStruct->pendingElse = 0;
va_start(va, string);
vsprintf(pLineStruct->line, string, va);
va_end(va);
currentLineIdx = currentDecompScriptPtr->var4;
currentLineType = 0;
/*printf("%d: ",currentOffset);
*
* va_start(va,string);
* vprintf(string,va);
* va_end(va);
*
* printf("\n"); */
}
void resolveVarName(char *ovlIdxString, int varType, char *varIdxString,
char *outputName) {
int varIdx = atoi(varIdxString);
strcpy(outputName, "");
if (varType == 2) {
strcpy(outputName, getStringNameFromIdx(varType,
varIdxString));
return;
}
if (varType == 1) {
sprintf(outputName, "localVar_%s", varIdxString);
return;
}
if (!strcmp(ovlIdxString, "0")) {
for (int i = 0; i < currentDecompOvl->numSymbGlob; i++) {
if (varIdx == currentDecompOvl->arraySymbGlob[i].idx) {
if (((currentDecompOvl->arraySymbGlob[i].var4 & 0xF0) == 0) && varType != 0x20) { // var
strcpy(outputName,
currentDecompOvl->arrayNameSymbGlob +
currentDecompOvl->arraySymbGlob[i].
offsetToName);
return;
}
if ((currentDecompOvl->arraySymbGlob[i].var4) == 20 && varType == 0x20) { // script
strcpy(outputName,
currentDecompOvl->arrayNameSymbGlob +
currentDecompOvl->arraySymbGlob[i].
offsetToName);
return;
}
}
}
sprintf(outputName, "ovl(%s).[%d][%s]", ovlIdxString, varType,
varIdxString);
} else {
strcpy(outputName, ovlIdxString);
}
}
int decompLoadVar() {
switch (currentScriptOpcodeType) {
case 0: {
char buffer[256];
getShortFromDecompScript(buffer);
pushDecomp(buffer);
return (0);
}
// string
case 1: {
char buffer1[256];
char buffer2[256];
char buffer3[256];
char varName[256];
getByteFromDecompScript(buffer1);
getByteFromDecompScript(buffer2);
getShortFromDecompScript(buffer3);
resolveVarName(buffer2, atoi(buffer1) & 7, buffer3,
varName);
pushDecomp("%s", varName);
return (0);
}
case 2: {
char buffer1[256];
char buffer2[256];
char buffer3[256];
char varName[256];
getByteFromDecompScript(buffer1);
getByteFromDecompScript(buffer2);
getShortFromDecompScript(buffer3);
resolveVarName(buffer2, atoi(buffer1) & 7, buffer3,
varName);
pushDecomp("%s", varName);
return (0);
}
case 5: {
char buffer1[256];
char buffer2[256];
char buffer3[256];
char varName[256];
getByteFromDecompScript(buffer1);
getByteFromDecompScript(buffer2);
getShortFromDecompScript(buffer3);
resolveVarName(buffer2, atoi(buffer1) & 7, buffer3,
varName);
pushDecomp("%s[%s]", varName, decompSaveOpcodeVar);
return (0);
}
default: {
debug("Unsupported type %d in opcodeType0",
currentScriptOpcodeType);
failed = 1;
}
}
}
int decompSaveVar() {
// int var = popVar();
switch (currentScriptOpcodeType) {
case 0: {
addDecomp(popDecomp());
return (0);
}
// modify string
case 1: {
char buffer1[256];
char buffer2[256];
char buffer3[256];
char varName[256];
uint8 type;
getByteFromDecompScript(buffer1);
getByteFromDecompScript(buffer2);
getShortFromDecompScript(buffer3);
type = atoi(buffer1) & 7;
resolveVarName(buffer2, type, buffer3, varName);
addDecomp("%s = %s", varName, popDecomp());
break;
}
case 2: {
char buffer1[256];
char buffer2[256];
char buffer3[256];
getByteFromDecompScript(buffer1);
getByteFromDecompScript(buffer2);
getShortFromDecompScript(buffer3);
addDecomp("ovl(%s).setVar(%s,%s) = %s", buffer2,
buffer1, buffer3, popDecomp());
break;
}
case 4: {
strcpy(decompSaveOpcodeVar, popDecomp());
break;
}
case 5: {
char buffer1[256];
char buffer2[256];
char buffer3[256];
char varName[256];
uint8 type;
getByteFromDecompScript(buffer1);
getByteFromDecompScript(buffer2);
getShortFromDecompScript(buffer3);
type = atoi(buffer1) & 7;
resolveVarName(buffer2, type, buffer3, varName);
addDecomp("%s[%s] = %s", varName, decompSaveOpcodeVar,
popDecomp());
break;
}
default: {
debug("Unsupported type %d in opcodeType1",
currentScriptOpcodeType);
failed = 1;
}
}
return (0);
}
int decompOpcodeType2() {
switch (currentScriptOpcodeType) {
case 1: {
char buffer3[256];
char varName[256];
int byte1 = getByteFromDecompScriptReal();
getByteFromDecompScriptReal();
getShortFromDecompScript(buffer3);
resolveVarName("0", byte1 & 7, buffer3, varName);
pushDecomp(varName);
break;
}
case 5: {
int byte1 = getByteFromDecompScriptReal();
getByteFromDecompScriptReal();
short int short1 = getShortFromDecompScriptReal();
int8 *ptr = scriptDataPtrTable[byte1 & 7] + short1;
if ((byte1 & 7) == 2) {
pushDecomp("\"%s\"[%s]", ptr,
decompSaveOpcodeVar);
} else if ((byte1 & 7) == 5) {
pushDecomp("freeString[%d][%s]", short1,
decompSaveOpcodeVar);
} else {
debug("Unsupported type %d in opcodeType2",
byte1 & 7);
failed = 1;
}
break;
}
default: {
debug("Unsupported type %d in opcodeType2",
currentScriptOpcodeType);
failed = 1;
}
}
return (0);
}
int decompMath() {
char *param1 = popDecomp();
char *param2 = popDecomp();
switch (currentScriptOpcodeType) {
case 0: {
sprintf(tempbuffer, "%s+%s", param1, param2);
pushDecomp(tempbuffer);
break;
}
case 1: {
sprintf(tempbuffer, "%s/%s", param1, param2);
pushDecomp(tempbuffer);
break;
}
case 2: {
sprintf(tempbuffer, "%s-%s", param1, param2);
pushDecomp(tempbuffer);
break;
}
case 3: {
sprintf(tempbuffer, "%s*%s", param1, param2);
pushDecomp(tempbuffer);
break;
}
case 4: {
sprintf(tempbuffer, "%s % %s", param1, param2);
pushDecomp(tempbuffer);
break;
}
case 5:
case 7: {
sprintf(tempbuffer, "%s|%s", param1, param2);
pushDecomp(tempbuffer);
break;
}
case 6: {
sprintf(tempbuffer, "%s&%s", param1, param2);
pushDecomp(tempbuffer);
break;
}
default: {
sprintf(tempbuffer, "decompMath(%d,%s,%s)",
currentScriptOpcodeType, param1, param2);
pushDecomp(tempbuffer);
break;
}
}
return (0);
}
int decompBoolCompare() {
char *param1;
char *param2;
param1 = popDecomp();
param2 = popDecomp();
sprintf(tempbuffer, "compare(%s,%s)", param1, param2);
pushDecomp(tempbuffer);
return 0;
}
int decompTest() {
unsigned long int oldOffset = currentDecompScriptPtr->var4;
short int offset = getShortFromDecompScriptReal();
switch (currentScriptOpcodeType) {
case 0: {
currentLineType = 1;
addDecomp("test '!(bitMask & 1)' and goto %d",
offset + oldOffset);
break;
}
case 1: {
currentLineType = 1;
addDecomp("test '(bitMask & 1)' and goto %d",
offset + oldOffset);
break;
}
case 2: {
currentLineType = 1;
addDecomp("test '(bitMask & 2)' and goto %d",
offset + oldOffset);
break;
}
case 3: {
currentLineType = 1;
addDecomp("test '(bitMask & 3)' and goto %d",
offset + oldOffset);
break;
}
case 4: {
currentLineType = 1;
addDecomp("test '(bitMask & 4)' and goto %d",
offset + oldOffset);
break;
}
case 5: {
currentLineType = 1;
addDecomp("test '(bitMask & 5)' and goto %d",
offset + oldOffset);
break;
}
case 6: {
currentLineType = 2;
addDecomp("test 'never' and goto %d",
offset + oldOffset);
break;
}
case 7: {
currentLineType = 3;
addDecomp("goto %d", offset + oldOffset);
break;
}
}
return 0;
}
int decompCompare() {
char *param;
param = popDecomp();
addDecomp("sign(%s)", param);
/*
if (!pop)
si = 1;
if (pop<0) {
si |= 4;
}
if (pop>0) {
si |= 2;
}
currentScriptPtr->bitMask = si;
*/
return 0;
}
int decompSwapStack() {
char *stack1;
char *stack2;
char buffer1[4000];
char buffer2[4000];
stack1 = popDecomp();
stack2 = popDecomp();
strcpy(buffer1, stack1);
strcpy(buffer2, stack2);
pushDecomp(buffer1);
pushDecomp(buffer2);
return 0;
}
int decompFunction() {
currentScriptOpcodeType = getByteFromDecompScriptReal();
switch (currentScriptOpcodeType) {
case 0x1:
pushDecomp("Op_FadeIn()");
break;
case 0x2:
pushDecomp("Op_FadeOut()");
break;
case 0x3:
sprintf(tempbuffer, "Op_loadBackground(%s,%s)", popDecomp(), popDecomp());
pushDecomp(tempbuffer);
break;
case 0x4:
sprintf(tempbuffer, "Op_LoadAbs(%s,%s)", popDecomp(), popDecomp());
pushDecomp(tempbuffer);
break;
case 0x5:
sprintf(tempbuffer, "Op_AddCell(%s,%s,%s)", popDecomp(), popDecomp(), popDecomp());
pushDecomp(tempbuffer);
break;
case 0x6: {
unsigned long int numArg = atoi(popDecomp());
char functionName[100];
char *idxStr = popDecomp();
char *ovlStr = popDecomp();
resolveVarName(ovlStr, 0x20, idxStr, functionName);
sprintf(tempbuffer, "Op_AddProc(%s", functionName);
for (int i = 0; i < numArg; i++) {
strcatuint8(tempbuffer, ",");
strcatuint8(tempbuffer, popDecomp());
}
strcatuint8(tempbuffer, ")");
pushDecomp(tempbuffer);
break;
}
case 0x7: {
char *var1 = popDecomp();
char *objIdxStr = popDecomp();
char *ovlStr = popDecomp();
sprintf(tempbuffer, "Op_InitializeState(ovl:%s,dataIdx:%s,%s)", ovlStr, objIdxStr, var1);
pushDecomp(tempbuffer);
break;
}
case 0x8:
sprintf(tempbuffer, "Op_RemoveCell(%s,%s,%s)", popDecomp(), popDecomp(), popDecomp());
pushDecomp(tempbuffer);
break;
case 0x9:
pushDecomp("Op_FreeCell()");
break;
case 0xA:
sprintf(tempbuffer, "Op_RemoveProc(ovl(%s),%s)", popDecomp(), popDecomp());
pushDecomp(tempbuffer);
break;
case 0xB:
sprintf(tempbuffer, "Op_RemoveFrame(%s,%s)", popDecomp(), popDecomp());
pushDecomp(tempbuffer);
break;
case 0xC:
sprintf(tempbuffer, "Op_LoadOverlay(%s)", popDecomp());
pushDecomp(tempbuffer);
break;
case 0xD:
sprintf(tempbuffer, "Op_SetColor(%s,%s,%s,%s,%s)", popDecomp(), popDecomp(), popDecomp(), popDecomp(), popDecomp());
pushDecomp(tempbuffer);
break;
case 0xE:
sprintf(tempbuffer, "Op_PlayFX(%s,%s,%s,%s)", popDecomp(), popDecomp(), popDecomp(), popDecomp());
pushDecomp(tempbuffer);
break;
case 0x10:
sprintf(tempbuffer, "Op_FreeOverlay(%s)", popDecomp());
pushDecomp(tempbuffer);
break;
case 0x11:
sprintf(tempbuffer, "Op_FindOverlay(%s)", popDecomp());
pushDecomp(tempbuffer);
break;
case 0x13:
sprintf(tempbuffer, "Op_AddMessage(%s,\"%s\",%s,%s,%s,%s)", popDecomp(),
resolveMessage(popDecomp()), popDecomp(), popDecomp(), popDecomp(), popDecomp());
pushDecomp(tempbuffer);
break;
case 0x14:
sprintf(tempbuffer, "Op_RemoveMessage(ovl(%s),%s)", popDecomp(), popDecomp());
pushDecomp(tempbuffer);
break;
case 0x15:
pushDecomp("Op_UserWait()");
break;
case 0x16:
sprintf(tempbuffer, "Op_FreezeCell(%s,%s,%s,%s,%s,%s)", popDecomp(), popDecomp(),
popDecomp(), popDecomp(), popDecomp(), popDecomp());
pushDecomp(tempbuffer);
break;
case 0x17:
sprintf(tempbuffer, "Op_LoadCt(%s)", popDecomp());
pushDecomp(tempbuffer);
break;
case 0x18:
sprintf(tempbuffer, "Op_AddAnimation(%s,%s,%s,%s,%s,%s,%s)", popDecomp(), popDecomp(),
popDecomp(), popDecomp(), popDecomp(), popDecomp(), popDecomp());
pushDecomp(tempbuffer);
break;
case 0x19:
sprintf(tempbuffer, "Op_RemoveAnimation(%s,%s,%s)", popDecomp(), popDecomp(), popDecomp());
pushDecomp(tempbuffer);
break;
case 0x1A:
sprintf(tempbuffer, "Op_SetZoom(%s,%s,%s,%s)", popDecomp(), popDecomp(), popDecomp(), popDecomp());
pushDecomp(tempbuffer);
break;
case 0x1E:
sprintf(tempbuffer, "Op_TrackAnim(%s,%s,%s,%s,%s,%s)", popDecomp(), popDecomp(),
popDecomp(), popDecomp(), popDecomp(), popDecomp());
pushDecomp(tempbuffer);
break;
case 0x21:
sprintf(tempbuffer, "Op_EndAnim(%s,%s,%s)", popDecomp(), popDecomp(), popDecomp());
pushDecomp(tempbuffer);
break;
case 0x22:
sprintf(tempbuffer, "Op_GetZoom(%s)", popDecomp());
pushDecomp(tempbuffer);
break;
case 0x23:
sprintf(tempbuffer, "Op_GetStep(%s,%s)", popDecomp(), popDecomp());
pushDecomp(tempbuffer);
break;
case 0x24:
sprintf(tempbuffer, "Op_SetStringColors(%s,%s,%s,%s)", popDecomp(), popDecomp(),
popDecomp(), popDecomp());
pushDecomp(tempbuffer);
break;
case 0x27:
sprintf(tempbuffer, "Op_getPixel(%s,%s)", popDecomp(), popDecomp());
pushDecomp(tempbuffer);
break;
case 0x28:
sprintf(tempbuffer, "Op_UserOn(%s)", popDecomp());
pushDecomp(tempbuffer);
break;
case 0x29:
pushDecomp("Op_FreeCT()");
break;
case 0x2B:
sprintf(tempbuffer, "Op_FindProc(%s,%s)", popDecomp(), popDecomp());
pushDecomp(tempbuffer);
break;
case 0x2C:
sprintf(tempbuffer, "Op_WriteObject(%s,%s,%s)", popDecomp(), popDecomp(), popDecomp());
pushDecomp(tempbuffer);
break;
case 0x2E:
sprintf(tempbuffer, "Op_RemoveOverlay(%s)", popDecomp());
pushDecomp(tempbuffer);
break;
case 0x2F:
sprintf(tempbuffer, "Op_AddBackgroundIncrust(%s,%s,%s)", popDecomp(), popDecomp(), popDecomp());
pushDecomp(tempbuffer);
break;
case 0x30: {
sprintf(tempbuffer, "_removeBackgroundIncrust(%s,%s)",
popDecomp(), popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x31: {
sprintf(tempbuffer, "_op_31(%s,%s)", popDecomp(),
popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x32: {
pushDecomp("_freeBackgroundInscrustList()");
break;
}
case 0x35: {
sprintf(tempbuffer, "_op35(%s)", popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x37: {
sprintf(tempbuffer, "_op37(%s,%s)", popDecomp(),
popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x38: {
sprintf(tempbuffer, "_removeBackground(%s)",
popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x39: {
sprintf(tempbuffer, "_SetActiveBackgroundPlane(%s)",
popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x3A: {
sprintf(tempbuffer, "_setVar49(%s)", popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x3B: {
pushDecomp("_op3B()");
break;
}
case 0x3C: {
sprintf(tempbuffer, "_rand(%s)", popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x3D: {
sprintf(tempbuffer, "_loadMusic(%s)", popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x3E: {
pushDecomp("_op_3E()");
break;
}
case 0x3F: {
pushDecomp("_op_3F()");
break;
}
case 0x40: {
pushDecomp("_op_40()");
break;
}
case 0x41: {
sprintf(tempbuffer, "_isFileLoaded2(%s)", popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x45: {
pushDecomp("_stopSound()");
break;
}
case 0x49: {
sprintf(tempbuffer, "_op49(%s)", popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x54: {
sprintf(tempbuffer, "_setFontVar(%s)", popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x56: {
sprintf(tempbuffer, "_changeCutSceneState(%s)",
popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x57: {
pushDecomp("_getMouseX()");
break;
}
case 0x58: {
pushDecomp("_getMouseY()");
break;
}
case 0x59: {
pushDecomp("_getMouse3()");
break;
}
case 0x5A: {
sprintf(tempbuffer, "_isFileLoaded(%s)", popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x5B: {
pushDecomp("_regenerateBackgroundIncrust()");
break;
}
case 0x5C: {
sprintf(tempbuffer, "_Op_AddCellC(%s,%s)", popDecomp(),
popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x5E: {
sprintf(tempbuffer, "_Op_AddCellE(%s)", popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x60: {
sprintf(tempbuffer, "_op_60(%s,%s,%s,%s,%s)",
popDecomp(), popDecomp(), popDecomp(), popDecomp(),
popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x61: {
sprintf(tempbuffer, "_op61(%s,%s)", popDecomp(),
popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x62: {
pushDecomp("_pauseCallingScript()");
break;
}
case 0x63: {
pushDecomp("_resumeScript()");
break;
}
case 0x64: {
unsigned long int numArg = atoi(popDecomp());
char *ovlStr;
char *idxStr;
char functionName[256];
idxStr = popDecomp();
ovlStr = popDecomp();
resolveVarName(ovlStr, 0x20, idxStr, functionName);
sprintf(tempbuffer, "%s(", functionName);
for (int i = 0; i < numArg; i++) {
if (i)
strcatuint8(tempbuffer, ",");
strcatuint8(tempbuffer, popDecomp());
}
strcatuint8(tempbuffer, ")");
pushDecomp(tempbuffer);
break;
}
case 0x65: {
sprintf(tempbuffer,
"_addWaitObject(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)",
popDecomp(), popDecomp(), popDecomp(), popDecomp(),
popDecomp(), popDecomp(), popDecomp(), popDecomp(),
popDecomp(), popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x66: {
sprintf(tempbuffer, "_op_66(%s,%s)", popDecomp(),
popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x67: {
sprintf(tempbuffer, "_loadAudioResource(%s,%s)",
popDecomp(), popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x68: {
pushDecomp("_freeMediumVar()");
break;
}
case 0x6A: {
sprintf(tempbuffer, "_op_6A(%s)", popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x6B: {
sprintf(tempbuffer, "_loadData(%s,%s,%s,%s)",
popDecomp(), popDecomp(), popDecomp(),
popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x6C: {
sprintf(tempbuffer, "_op_6C(%s,%s)", popDecomp(),
popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x6D: {
sprintf(tempbuffer, "_strcpy(%s,%s)", popDecomp(),
popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x6E: {
sprintf(tempbuffer, "_op_6E(%s,%s)", popDecomp(),
popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x6F: {
unsigned long int numArg = atoi(popDecomp());
char *ovlStr;
char *idxStr;
idxStr = popDecomp();
ovlStr = popDecomp();
sprintf(tempbuffer, "_op_6F(%s,%s", idxStr, ovlStr);
for (int i = 0; i < numArg; i++) {
strcatuint8(tempbuffer, ",");
strcatuint8(tempbuffer, popDecomp());
}
strcatuint8(tempbuffer, ")");
pushDecomp(tempbuffer);
break;
}
case 0x70: {
sprintf(tempbuffer, "_comment(%s)", popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x71: {
sprintf(tempbuffer, "_op71(%s,%s,%s,%s,%s)",
popDecomp(), popDecomp(), popDecomp(), popDecomp(),
popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x72: {
sprintf(tempbuffer, "_op72(%s,%s)", popDecomp(),
popDecomp(), popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x73: {
sprintf(tempbuffer, "_op73(%s)", popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x74: {
sprintf(tempbuffer, "_getlowMemory()");
pushDecomp(tempbuffer);
break;
}
case 0x76: {
sprintf(tempbuffer, "_Op_InitializeState6(%s,%s)",
popDecomp(), popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x77: {
sprintf(tempbuffer, "_Op_InitializeState7(%s)",
popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x78: {
sprintf(tempbuffer, "_Op_InitializeState8(%s)",
popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x79: {
sprintf(tempbuffer, "_EnterPlayerMenu(%s)",
popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x7B: {
sprintf(tempbuffer, "_Op_InitializeStateB(%s)",
popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x7C: {
sprintf(tempbuffer, "_Op_InitializeStateC(%s)",
popDecomp());
pushDecomp(tempbuffer);
break;
}
case 0x7D: {
pushDecomp("_freeAllMenu()");
break;
}
default: {
addDecomp("OP_%X", currentScriptOpcodeType);
debug("OPCODE: %X", currentScriptOpcodeType);
failed = 1;
break;
}
}
// pushDecomp("functionDummyPush");
return (0);
}
uint8 stop = 0;
int decompStop() {
stop = 1;
addDecomp("stop\n");
return 0;
}
int decompBreak() {
addDecomp("break");
return 0;
}
void generateIndentation() {
for (int i = 0; i < positionInDecompileLineTable; i++) {
if (decompileLineTable[i].type != 0) {
char *gotoStatement;
int destLine;
int destLineIdx;
gotoStatement =
strstr(decompileLineTable[i].line, "goto");
assert(gotoStatement);
gotoStatement = strchr(gotoStatement, ' ') + 1;
destLine = atoi(gotoStatement);
destLineIdx = -1;
for (int j = 0; j < positionInDecompileLineTable; j++) {
if (decompileLineTable[j].lineOffset == destLine) {
destLineIdx = j;
break;
}
}
assert(destLineIdx != -1);
if (destLineIdx > i) {
for (int j = i + 1; j < destLineIdx; j++) {
decompileLineTable[j].indent++;
}
if (strstr(decompileLineTable[destLineIdx - 1].line, "goto") ==
decompileLineTable[destLineIdx - 1].line) {
//decompileLineTable[destLineIdx-1].pendingElse = 1;
}
}
}
}
}
void dumpScript(uint8 *ovlName, ovlDataStruct *ovlData, int idx) {
uint8 opcodeType;
char buffer[256];
char temp[256];
char scriptName[256];
sprintf(temp, "%d", idx);
failed = 0;
currentScript = &ovlData->arrayProc[idx];
currentDecompScript = currentScript->dataPtr;
currentDecompScriptPtr->var4 = 0;
currentDecompOvl = ovlData;
currentDecompScriptIdx = idx;
currentLineIdx = 0;
positionInDecompileLineTable = 0;
currentLineType = 0;
resolveVarName("0", 0x20, temp, scriptName);
debug("decompiling script %d - %s", idx, scriptName);
// return;
// scriptDataPtrTable[1] = *(char**)(ptr+0x6);
scriptDataPtrTable[2] = getDataFromData3(currentScript, 1); // strings
scriptDataPtrTable[5] = ovlData->data4Ptr; // free strings
scriptDataPtrTable[6] = ovlData->ptr8;
stop = 0;
sprintf(buffer, "%s-%02d-%s.txt", ovlName, idx, scriptName);
fHandle = fopen(buffer, "w+");
decompileStackPosition = 0;
for (int i = 0; i < 64; i++)
decompOpcodeTypeTable[i] = NULL;
decompOpcodeTypeTable[1] = decompLoadVar;
decompOpcodeTypeTable[2] = decompSaveVar;
decompOpcodeTypeTable[3] = decompOpcodeType2;
decompOpcodeTypeTable[4] = decompMath;
decompOpcodeTypeTable[5] = decompBoolCompare;
decompOpcodeTypeTable[6] = decompTest;
decompOpcodeTypeTable[7] = decompCompare;
decompOpcodeTypeTable[8] = decompSwapStack;
decompOpcodeTypeTable[9] = decompFunction;
decompOpcodeTypeTable[10] = decompStop;
decompOpcodeTypeTable[12] = decompBreak;
do {
currentOffset = currentDecompScriptPtr->var4;
opcodeType = getByteFromDecompScriptReal();
currentScriptOpcodeType = opcodeType & 7;
if (!decompOpcodeTypeTable[(opcodeType & 0xFB) >> 3]) {
debug("Unsupported opcode type %d in decomp",
(opcodeType & 0xFB) >> 3);
return;
}
//debug("Optype: %d",(opcodeType&0xFB)>>3);
decompOpcodeTypeTable[(opcodeType & 0xFB) >> 3]();
if (failed) {
debug("Aborting decompilation..");
fclose(fHandle);
return;
}
} while (!stop);
dumpIdx++;
generateIndentation();
for (int i = 0; i < positionInDecompileLineTable; i++) {
if (decompileLineTable[i].pendingElse) {
fprintf(fHandle, "%05d:\t",
decompileLineTable[i].lineOffset);
fprintf(fHandle, "else %s\n", decompileLineTable[i].line);
}
fprintf(fHandle, "%05d:\t", decompileLineTable[i].lineOffset);
for (int j = 0; j < decompileLineTable[i].indent; j++)
fprintf(fHandle, "\t");
fprintf(fHandle, "%s\n", decompileLineTable[i].line);
}
fclose(fHandle);
}
#endif
} // End of namespace Cruise