/* ScummVM - Scumm Interpreter * Copyright (C) 2006 The ScummVM project * * cinE Engine is (C) 2004-2005 by CinE Team * * 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. * * $URL$ * $Id$ * */ #include "cruise/cruise_main.h" namespace Cruise { #include #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; #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; { int i; importScriptStruct* importEntry = (importScriptStruct*) (data3Ptr->dataPtr + data3Ptr->offsetToImportData); for(i=0;inumImport;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; { int i; importScriptStruct* importEntry = (importScriptStruct*) (data3Ptr->dataPtr + data3Ptr->offsetToImportData); for(i=0;inumImport;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(void) { short int var = currentDecompScript[currentDecompScriptPtr->var4]; currentDecompScriptPtr->var4 = currentDecompScriptPtr->var4+1; return var; } void getShortFromDecompScript(char* buffer) { short int var = *(int16*)(currentDecompScript+currentDecompScriptPtr->var4); currentDecompScriptPtr->var4 = currentDecompScriptPtr->var4+2; flipShort(&var); if(var == -1) { resolveDecompShort(buffer); if(buffer[0]) return; } sprintf(buffer,"%d",var); } short int getShortFromDecompScriptReal(void) { short int var = *(int16*)(currentDecompScript+currentDecompScriptPtr->var4); currentDecompScriptPtr->var4 = currentDecompScriptPtr->var4+2; flipShort(&var); 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")) { int i; for(i=0;inumExport;i++) { if(varIdx == currentDecompOvl->exportDataPtr[i].idx) { if( ((currentDecompOvl->exportDataPtr[i].var4&0xF0) == 0) && varType != 0x20) // var { strcpy(outputName, currentDecompOvl->exportNamesPtr + currentDecompOvl->exportDataPtr[i].offsetToName); return; } if( (currentDecompOvl->exportDataPtr[i].var4) == 20 && varType == 0x20) // script { strcpy(outputName, currentDecompOvl->exportNamesPtr + currentDecompOvl->exportDataPtr[i].offsetToName); return; } } } sprintf(outputName, "ovl(%s).[%d][%s]", ovlIdxString, varType, varIdxString); } else { strcpy(outputName, ovlIdxString); } } int decompLoadVar(void) { 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: { printf("Unsupported type %d in opcodeType0\n",currentScriptOpcodeType); failed = 1; } } } int decompSaveVar(void) { // 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: { printf("Unsupported type %d in opcodeType1\n",currentScriptOpcodeType); failed = 1; } } return(0); } int decompOpcodeType2(void) { switch(currentScriptOpcodeType) { case 1: { char buffer3[256]; char varName[256]; int byte1 = getByteFromDecompScriptReal(); int byte2 = getByteFromDecompScriptReal(); getShortFromDecompScript(buffer3); resolveVarName("0",byte1 & 7,buffer3, varName); pushDecomp(varName); break; } case 5: { int byte1 = getByteFromDecompScriptReal(); int byte2 = 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 { printf("Unsupported type %d in opcodeType2\n",byte1 & 7); failed = 1; } break; } default: { printf("Unsupported type %d in opcodeType2\n",currentScriptOpcodeType); failed = 1; } } return(0); } int decompMath(void) { 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(void) { char* param1; char* param2; param1 = popDecomp(); param2 = popDecomp(); sprintf(tempbuffer,"compare(%s,%s)",param1,param2); pushDecomp(tempbuffer); return 0; } int decompTest(void) { 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(void) { 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(void) { char* stack1; char* stack2; char buffer1[4000]; char buffer2[4000]; stack1 = popDecomp(); stack2 = popDecomp(); strcpyuint8(buffer1,stack1); strcpyuint8(buffer2,stack2); pushDecomp(buffer1); pushDecomp(buffer2); return 0; } int decompFunction(void) { currentScriptOpcodeType = getByteFromDecompScriptReal(); // addDecomp("OP_%X", currentScriptOpcodeType); switch(currentScriptOpcodeType) { case 0x1: { pushDecomp("_setMain5()"); break; } case 0x2: { pushDecomp("_prepareFade()"); break; } case 0x3: { sprintf(tempbuffer,"_loadBackground(%s,%s)",popDecomp(),popDecomp()); pushDecomp(tempbuffer); break; } case 0x4: { sprintf(tempbuffer,"_loadFullBundle(%s,%s)",popDecomp(),popDecomp()); pushDecomp(tempbuffer); break; } case 0x5: { sprintf(tempbuffer,"_addCell(%s,%s,%s)",popDecomp(),popDecomp(),popDecomp()); pushDecomp(tempbuffer); break; } case 0x6: { unsigned long int numArg = atoi(popDecomp()); char* ovlStr; char* idxStr; int i; char functionName[100]; idxStr = popDecomp(); ovlStr = popDecomp(); resolveVarName(ovlStr, 0x20, idxStr, functionName); sprintf(tempbuffer,"_startASync(%s",functionName); for(i=0;ii) { int j; for(j=i+1;jdata3Table[idx]; currentDecompScript = currentScript->dataPtr; currentDecompScriptPtr->var4 = 0; currentDecompOvl = ovlData; currentDecompScriptIdx = idx; currentLineIdx = 0; positionInDecompileLineTable = 0; currentLineType = 0; resolveVarName("0",0x20,temp, scriptName); printf("decompiling script %d - %s\n",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(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]) { printf("Unsupported opcode type %d in decomp\n",(opcodeType&0xFB)>>3); return; } //printf("Optype: %d\n",(opcodeType&0xFB)>>3); decompOpcodeTypeTable[(opcodeType&0xFB)>>3](); if(failed) { printf("Aborting decompilation..\n"); fclose(fHandle); return; } }while(!stop); dumpIdx++; generateIndentation(); for(i=0;i