mirror of
https://github.com/scummvm/scummvm-tools.git
synced 2026-06-20 05:45:31 +00:00
251 lines
9.0 KiB
C++
251 lines
9.0 KiB
C++
/* ScummVM Tools
|
|
*
|
|
* ScummVM Tools 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include <cxxtest/TestSuite.h>
|
|
|
|
#include "disassembler/pasc.h"
|
|
#include "disassembler/subopcode.h"
|
|
#include "decompiler/scummv6/disassembler.h"
|
|
#include "decompiler/kyra/engine.h"
|
|
|
|
class DisassemblerTestSuite : public CxxTest::TestSuite {
|
|
public:
|
|
void testDisassembly() {
|
|
try {
|
|
InstVec insts;
|
|
PasCDisassembler p(insts);
|
|
p.open("decompiler/test/hanoi20.pasb");
|
|
p.disassemble();
|
|
TS_ASSERT(insts[0]->_address == 0);
|
|
TS_ASSERT(insts[0]->_opcode == 0x00);
|
|
TS_ASSERT(insts[0]->_name == "PUSH");
|
|
TS_ASSERT(insts[0]->_stackChange == 0);
|
|
TS_ASSERT(insts[0]->_params[0]->isInteger());
|
|
TS_ASSERT(insts[0]->_params[0]->getSigned() == 0x60);
|
|
} catch (UnknownOpcodeException &uoe) {
|
|
printf("Exception message: %s\n", uoe.what());
|
|
TS_ASSERT(false);
|
|
} catch (std::exception &ex) {
|
|
printf("Exception message: %s\n", ex.what());
|
|
TS_ASSERT(false);
|
|
}
|
|
}
|
|
|
|
void testSubOpcodeDisassembly() {
|
|
InstVec insts;
|
|
SubOpcodeDisassembler s(insts);
|
|
s.open("decompiler/test/subopcode_test.bin");
|
|
s.disassemble();
|
|
TS_ASSERT(insts[0]->_name == "FOO");
|
|
TS_ASSERT(insts[0]->_opcode == 0xFFFF);
|
|
}
|
|
|
|
void testUnknownOpcodeException() {
|
|
try {
|
|
InstVec insts;
|
|
SubOpcodeDisassembler s(insts);
|
|
s.open("decompiler/test/unknownopcode_test.bin");
|
|
s.disassemble();
|
|
TS_ASSERT(false);
|
|
} catch (UnknownOpcodeException) {
|
|
TS_ASSERT(true);
|
|
}
|
|
}
|
|
|
|
// This test requires script-15.dmp from Sam & Max: Hit The Road.
|
|
// 1ab08298c9c8fb4c77953756989c7449 *script-15.dmp
|
|
void testScummv6DisassemblerScript15() {
|
|
InstVec insts;
|
|
Scumm::v6::Scummv6Disassembler s(insts);
|
|
s.open("decompiler/test/script-15.dmp");
|
|
s.disassemble();
|
|
TS_ASSERT(insts.size() == 11);
|
|
TS_ASSERT(insts[0]->_address == 0);
|
|
TS_ASSERT(insts[0]->_opcode == 0x03);
|
|
TS_ASSERT(insts[0]->_name == "pushWordVar");
|
|
TS_ASSERT(insts[0]->_params[0]->getUnsigned() == 16384);
|
|
TS_ASSERT(insts[1]->_address == 3);
|
|
TS_ASSERT(insts[1]->_opcode == 0x43);
|
|
TS_ASSERT(insts[1]->_name == "writeWordVar");
|
|
TS_ASSERT(insts[1]->_params[0]->getUnsigned() == 197);
|
|
TS_ASSERT(insts[2]->_address == 6);
|
|
TS_ASSERT(insts[2]->_opcode == 0x01);
|
|
TS_ASSERT(insts[2]->_name == "pushWord");
|
|
TS_ASSERT(insts[2]->_params[0]->getSigned() == 0);
|
|
TS_ASSERT(insts[3]->_address == 9);
|
|
TS_ASSERT(insts[3]->_opcode == 0x01);
|
|
TS_ASSERT(insts[3]->_name == "pushWord");
|
|
TS_ASSERT(insts[3]->_params[0]->getSigned() == 11);
|
|
TS_ASSERT(insts[4]->_address == 12);
|
|
TS_ASSERT(insts[4]->_opcode == 0x01);
|
|
TS_ASSERT(insts[4]->_name == "pushWord");
|
|
TS_ASSERT(insts[4]->_params[0]->getSigned() == 0);
|
|
TS_ASSERT(insts[5]->_address == 15);
|
|
TS_ASSERT(insts[5]->_opcode == 0x5E);
|
|
TS_ASSERT(insts[5]->_name == "startScript");
|
|
TS_ASSERT(insts[6]->_address == 16);
|
|
TS_ASSERT(insts[6]->_opcode == 0x01);
|
|
TS_ASSERT(insts[6]->_name == "pushWord");
|
|
TS_ASSERT(insts[6]->_params[0]->getSigned() == 0);
|
|
TS_ASSERT(insts[7]->_address == 19);
|
|
TS_ASSERT(insts[7]->_opcode == 0x01);
|
|
TS_ASSERT(insts[7]->_name == "pushWord");
|
|
TS_ASSERT(insts[7]->_params[0]->getSigned() == 14);
|
|
TS_ASSERT(insts[8]->_address == 22);
|
|
TS_ASSERT(insts[8]->_opcode == 0x01);
|
|
TS_ASSERT(insts[8]->_name == "pushWord");
|
|
TS_ASSERT(insts[8]->_params[0]->getSigned() == 0);
|
|
TS_ASSERT(insts[9]->_address == 25);
|
|
TS_ASSERT(insts[9]->_opcode == 0x5E);
|
|
TS_ASSERT(insts[9]->_name == "startScript");
|
|
TS_ASSERT(insts[10]->_address == 26);
|
|
TS_ASSERT(insts[10]->_opcode == 0x66);
|
|
TS_ASSERT(insts[10]->_name == "stopObjectCodeB");
|
|
}
|
|
|
|
// This test requires script-31.dmp from Sam & Max: Hit The Road.
|
|
// f75f7ce110f378735d449f8eeb4a68e5 *script-31.dmp
|
|
void testScummv6DisassemblerScript31() {
|
|
InstVec insts;
|
|
Scumm::v6::Scummv6Disassembler s(insts);
|
|
s.open("decompiler/test/script-31.dmp");
|
|
s.disassemble();
|
|
TS_ASSERT(insts.size() == 5);
|
|
TS_ASSERT(insts[0]->_address == 0);
|
|
TS_ASSERT(insts[0]->_opcode == 0x01);
|
|
TS_ASSERT(insts[0]->_name == "pushWord");
|
|
TS_ASSERT(insts[0]->_params[0]->getSigned() == 0);
|
|
TS_ASSERT(insts[1]->_address == 3);
|
|
TS_ASSERT(insts[1]->_opcode == 0x43);
|
|
TS_ASSERT(insts[1]->_name == "writeWordVar");
|
|
TS_ASSERT(insts[1]->_params[0]->getUnsigned() == 180);
|
|
TS_ASSERT(insts[2]->_address == 6);
|
|
TS_ASSERT(insts[2]->_opcode == 0x01);
|
|
TS_ASSERT(insts[2]->_name == "pushWord");
|
|
TS_ASSERT(insts[2]->_params[0]->getSigned() == 0);
|
|
TS_ASSERT(insts[3]->_address == 9);
|
|
TS_ASSERT(insts[3]->_opcode == 0x43);
|
|
TS_ASSERT(insts[3]->_name == "writeWordVar");
|
|
TS_ASSERT(insts[3]->_params[0]->getUnsigned() == 181);
|
|
TS_ASSERT(insts[4]->_address == 12);
|
|
TS_ASSERT(insts[4]->_opcode == 0x66);
|
|
TS_ASSERT(insts[4]->_name == "stopObjectCodeB");
|
|
}
|
|
|
|
// This test requires script-33.dmp from Sam & Max: Hit The Road.
|
|
// 9f09418bf34abbdec0ec54f388d8dca4 *script-33.dmp
|
|
void testScummv6DisassemblerScript33() {
|
|
InstVec insts;
|
|
Scumm::v6::Scummv6Disassembler s(insts);
|
|
s.open("decompiler/test/script-33.dmp");
|
|
s.disassemble();
|
|
TS_ASSERT(insts.size() == 10);
|
|
TS_ASSERT(insts[0]->_address == 0);
|
|
TS_ASSERT(insts[0]->_opcode == 0x01);
|
|
TS_ASSERT(insts[0]->_name == "pushWord");
|
|
TS_ASSERT(insts[0]->_params[0]->getSigned() == 0);
|
|
TS_ASSERT(insts[1]->_address == 3);
|
|
TS_ASSERT(insts[1]->_opcode == 0x43);
|
|
TS_ASSERT(insts[1]->_name == "writeWordVar");
|
|
TS_ASSERT(insts[1]->_params[0]->getUnsigned() == 71);
|
|
TS_ASSERT(insts[2]->_address == 6);
|
|
TS_ASSERT(insts[2]->_opcode == 0x03);
|
|
TS_ASSERT(insts[2]->_name == "pushWordVar");
|
|
TS_ASSERT(insts[2]->_params[0]->getUnsigned() == 177);
|
|
TS_ASSERT(insts[3]->_address == 9);
|
|
TS_ASSERT(insts[3]->_opcode == 0x43);
|
|
TS_ASSERT(insts[3]->_name == "writeWordVar");
|
|
TS_ASSERT(insts[3]->_params[0]->getUnsigned() == 173);
|
|
TS_ASSERT(insts[4]->_address == 12);
|
|
TS_ASSERT(insts[4]->_opcode == 0x01);
|
|
TS_ASSERT(insts[4]->_name == "pushWord");
|
|
TS_ASSERT(insts[4]->_params[0]->getSigned() == 874);
|
|
TS_ASSERT(insts[5]->_address == 15);
|
|
TS_ASSERT(insts[5]->_opcode == 0x43);
|
|
TS_ASSERT(insts[5]->_name == "writeWordVar");
|
|
TS_ASSERT(insts[5]->_params[0]->getUnsigned() == 177);
|
|
TS_ASSERT(insts[6]->_address == 18);
|
|
TS_ASSERT(insts[6]->_opcode == 0x03);
|
|
TS_ASSERT(insts[6]->_name == "pushWordVar");
|
|
TS_ASSERT(insts[6]->_params[0]->getUnsigned() == 177);
|
|
TS_ASSERT(insts[7]->_address == 21);
|
|
TS_ASSERT(insts[7]->_opcode == 0x01);
|
|
TS_ASSERT(insts[7]->_name == "pushWord");
|
|
TS_ASSERT(insts[7]->_params[0]->getSigned() == 93);
|
|
TS_ASSERT(insts[8]->_address == 24);
|
|
TS_ASSERT(insts[8]->_opcode == 0x6B99);
|
|
TS_ASSERT(insts[8]->_name == "cursorCommand.setCursorImg");
|
|
TS_ASSERT(insts[9]->_address == 26);
|
|
TS_ASSERT(insts[9]->_opcode == 0x66);
|
|
TS_ASSERT(insts[9]->_name == "stopObjectCodeB");
|
|
}
|
|
|
|
// This test requires room-9-202.dmp from Sam & Max: Hit The Road.
|
|
// f010dc659264674a2b6da298acd0b88b *room-9-202.dmp
|
|
void testScummv6StackChangeFixRoom9202() {
|
|
InstVec insts;
|
|
Scumm::v6::Scummv6Disassembler s(insts);
|
|
s.open("decompiler/test/room-9-202.dmp");
|
|
s.disassemble();
|
|
InstIterator it = insts.end();
|
|
it -= 8;
|
|
TS_ASSERT((*it)->_stackChange == -3);
|
|
}
|
|
|
|
// This test requires script-30.dmp from Sam & Max: Hit The Road.
|
|
// 6e48faca13e1f6df9341567608962744 *script-30.dmp
|
|
void testScummv6StackChangeFixScript30() {
|
|
InstVec insts;
|
|
Scumm::v6::Scummv6Disassembler s(insts);
|
|
s.open("decompiler/test/script-30.dmp");
|
|
s.disassemble();
|
|
InstIterator it = insts.end();
|
|
it -= 3;
|
|
TS_ASSERT((*it)->_stackChange == -6);
|
|
}
|
|
|
|
// This test requires _START04.EMC from the CD demo of
|
|
// Legend of Kyrandia: Hand of Fate, found in MISC_EMC.PAK.
|
|
// Extract using extract_kyra from the scummvm-tools-cli bundle.
|
|
// ba2821ac6da96394ce0af75a3cbe48eb *_START04.EMC
|
|
void testKyra2Start04() {
|
|
InstVec insts;
|
|
Kyra::Kyra2Engine engine;
|
|
Disassembler* s = engine.getDisassembler(insts);
|
|
s->open("decompiler/test/_START04.EMC");
|
|
s->disassemble();
|
|
|
|
TS_ASSERT(insts.size() == 481);
|
|
|
|
//These scripts are far too big to check all instructions, so we just check a few different ones
|
|
TS_ASSERT(insts[16]->_address == 0x20);
|
|
TS_ASSERT(insts[16]->_opcode == 15);
|
|
TS_ASSERT(insts[16]->_name == "ifNotJmp");
|
|
TS_ASSERT(insts[16]->_stackChange == -1);
|
|
TS_ASSERT(insts[38]->_address == 0x54);
|
|
TS_ASSERT(insts[38]->_opcode == 14);
|
|
TS_ASSERT(insts[38]->_name == "o1_setHandItem");
|
|
TS_ASSERT(insts[38]->_stackChange == 0);
|
|
|
|
delete s;
|
|
}
|
|
};
|