PRIVATE: integrated first version of the decompiler

This commit is contained in:
neuromancer 2021-04-20 18:53:43 -03:00 committed by Eugene Sandulenko
parent f10fb7fbad
commit 6c80b049af
7 changed files with 99 additions and 77 deletions

View File

@ -1,53 +1,49 @@
#include <fstream>
#include <sstream>
#include "decompiler.h"
#include "private/decompiler.h"
namespace Private {
Decompiler::~Decompiler() {
Decompiler::Decompiler(char *buf, uint32 fileSize, bool mac) {
Common::Array<unsigned char> array;
uint32 i = 0;
while (i < fileSize) {
array.push_back(buf[i]);
i++;
}
decompile(array, mac);
}
Decompiler::Decompiler(const std::string &fileName, bool mac) {
std::ifstream infile(fileName);
if (!infile.good())
throw std::invalid_argument("File does not exist");
std::ifstream input(fileName, std::ios::binary);
std::vector<unsigned char> buffer(std::istreambuf_iterator<char>(input), {});
decompile(buffer, mac);
}
Decompiler::Decompiler(std::vector<unsigned char> &buffer, bool mac) {
decompile(buffer, mac);
}
void Decompiler::decompile(Common::Array<unsigned char> &buffer, bool mac) {
Common::Array<unsigned char>::iterator it = buffer.begin();
void Decompiler::decompile(std::vector<unsigned char> &buffer, bool mac) {
std::vector<unsigned char>::iterator it = buffer.begin();
Common::String firstBytes((const char *) it, (const char *) it + kHeader.size());
//debug("first bytes \"%s\"", firstBytes.c_str());
std::string firstBytes(it, it + kHeader.length());
if (firstBytes != kHeader) {
throw std::invalid_argument("Not a precompiled game matrix");
error("Not a precompiled game matrix");
}
std::stringstream ss;
Common::String ss;
bool inDefineRects = false;
for (it += kHeader.length() ; it != buffer.end() ; ) {
for (it += kHeader.size() ; it != buffer.end() ; ) {
unsigned char byte = *it++;
if (byte == kCodeString) {
unsigned char len = *it++;
std::string s(it,it+len);
Common::String s((const char *)it,(const char *)it+len);
it += len;
ss << "\"" << s << "\"";
ss += Common::String::format("\"%s\"", s.c_str());
} else if (byte == kCodeShortLiteral || byte == kCodeShortId) {
unsigned char b1 = *it++;
unsigned char b2 = *it++;
unsigned int number = mac ? b2 + (b1 << 8) : b1 + (b2 << 8);
if (byte == kCodeShortId) ss << "k";
ss << number;
if (byte == kCodeShortId) ss += "k";
ss += Common::String::format("%d", number);
} else if (byte == kCodeRect && inDefineRects) {
ss << "RECT"; // override CRect
} else if (byte <= kCodeShortId && kCodeTable[byte].length() > 0) {
ss << kCodeTable[byte];
ss += "RECT"; // override CRect
} else if (byte <= kCodeShortId && strlen(kCodeTable[byte]) > 0) {
ss += kCodeTable[byte];
} else {
throw std::invalid_argument("Unknown byte code");
error("Unknown byte code");
}
if (byte == kCodeRects) {
@ -56,11 +52,11 @@ void Decompiler::decompile(std::vector<unsigned char> &buffer, bool mac) {
inDefineRects = false;
}
}
_result = ss.str();
_result = ss;
}
void Decompiler::getResult(std::string &result) const {
result = _result;
Common::String Decompiler::getResult() const {
return _result;
}
}

View File

@ -1,9 +1,13 @@
#include <vector>
#include <string>
#ifndef PRIVATE_DECOMPILER_H
#define PRIVATE_DECOMPILER_H
#include "common/array.h"
#include "common/str.h"
#include "common/debug.h"
namespace Private {
const std::string kHeader("Precompiled Game Matrix");
const Common::String kHeader = "Precompiled Game Matrix";
const unsigned char kCodeString = 0x01;
const unsigned char kCodeShortLiteral = 0x02;
@ -12,7 +16,7 @@ const unsigned char kCodeRect = 0x2e;
const unsigned char kCodeRects = 0x4f;
const unsigned char kCodeShortId = 0x50;
const std::vector<std::string> kCodeTable = {"", //
const static char *kCodeTable[] = {"", //
"", // 0x01 (string)
"", // 0x02 (short literal)
" {\n", // 0x03
@ -92,18 +96,19 @@ const std::vector<std::string> kCodeTable = {"", //
"", //
"", //
"rects", // 0x4f
""}; // 0x50 (short id)
""
}; // 0x50 (short id)
class Decompiler {
public:
Decompiler(const std::string &filename, bool mac = false);
Decompiler(std::vector<unsigned char> &buffer, bool mac = false);
virtual ~Decompiler();
void getResult(std::string &result) const;
Decompiler(char *buf, uint32 fileSize, bool mac = false);
Common::String getResult() const;
private:
void decompile(std::vector<unsigned char> &buffer, bool mac);
std::string _result;
void decompile(Common::Array<unsigned char> &buffer, bool mac);
Common::String _result;
};
}
#endif

View File

@ -65,7 +65,7 @@ static const ADGameDescription gameDescriptions[] = {
"bklynlgo.bmp", "1dfb703349a46f8ec183de107992b7f5", 33118),
Common::EN_GRB,
Common::kPlatformWindows,
ADGF_UNSUPPORTED,
ADGF_UNSTABLE,
GUIO1(GUIO_NOMIDI)
},
{
@ -75,7 +75,7 @@ static const ADGameDescription gameDescriptions[] = {
"bklynlgo.bmp", "1dfb703349a46f8ec183de107992b7f5", 33118),
Common::EN_GRB,
Common::kPlatformWindows,
ADGF_DEMO | ADGF_TESTING,
ADGF_DEMO | ADGF_UNSTABLE,
GUIO1(GUIO_NOMIDI)
},
{
@ -100,32 +100,32 @@ static const ADGameDescription gameDescriptions[] = {
},
{
"private-eye", // EU release (ES)
"It uses different file format for the assest",
"Demo",
AD_ENTRY2s("pvteye.ex_", "f41770550ab717086b2d0c805fef4b8f", 498176,
"bklynlgo.bmp", "1dfb703349a46f8ec183de107992b7f5", 33118),
Common::ES_ESP,
Common::kPlatformWindows,
ADGF_UNSUPPORTED,
ADGF_UNSTABLE,
GUIO1(GUIO_NOMIDI)
},
{
"private-eye", // Demo from the EU release (ES)
"It uses different file format for the assest",
"Demo",
AD_ENTRY2s("pvtdemo.ex_", "048f751acd7a0f1a87b20d6dc5229210", 497152,
"bklynlgo.bmp", "1dfb703349a46f8ec183de107992b7f5", 33118),
Common::ES_ESP,
Common::kPlatformWindows,
ADGF_DEMO | ADGF_UNSUPPORTED,
ADGF_DEMO | ADGF_UNSTABLE,
GUIO1(GUIO_NOMIDI)
},
{
"private-eye", // EU release (FR)
"It uses different file format for the assest",
"Demo",
AD_ENTRY2s("pvteye.ex_", "ae0dec43b2f54d45c8a1c93e97092141", 600576,
"bklynlgo.bmp", "1dfb703349a46f8ec183de107992b7f5", 33118),
Common::FR_FRA,
Common::kPlatformWindows,
ADGF_UNSUPPORTED,
ADGF_UNSTABLE,
GUIO1(GUIO_NOMIDI)
},
{
@ -139,13 +139,13 @@ static const ADGameDescription gameDescriptions[] = {
GUIO1(GUIO_NOMIDI)
},
{
"private-eye", // Demo from the EU release
"private-eye", // Demo from the EU release (UK)
"Demo",
AD_ENTRY2s("Private Eye Demo", "", 284129,
"bklynlgo.bmp", "1dfb703349a46f8ec183de107992b7f5", 33118),
Common::EN_GRB,
Common::kPlatformWindows,
ADGF_DEMO | ADGF_UNSUPPORTED,
ADGF_DEMO | ADGF_UNSTABLE,
GUIO1(GUIO_NOMIDI)
},
/*

View File

@ -3,6 +3,7 @@ MODULE := engines/private
MODULE_OBJS := \
code.o \
cursors.o \
decompiler.o \
funcs.o \
grammar.o \
lexer.o \

View File

@ -39,6 +39,7 @@
#include "private/private.h"
#include "private/tokens.h"
#include "private/grammar.h"
#include "private/decompiler.h"
namespace Private {
@ -122,8 +123,14 @@ void PrivateEngine::initializePath(const Common::FSNode &gamePath) {
Common::Error PrivateEngine::run() {
assert(_installerArchive.open("SUPPORT/ASSETS.Z"));
Common::File *test = new Common::File();
Common::SeekableReadStream *file = NULL;
if (isDemo() && test->open("SUPPORT/ASSETS/DEMOGAME.WIN")) {
file = (Common::SeekableReadStream *) test;
} else {
assert(_installerArchive.open("SUPPORT/ASSETS.Z"));
// if the full game is used
if (!isDemo()) {
assert(_installerArchive.hasFile("GAME.DAT"));
@ -137,25 +144,29 @@ Common::Error PrivateEngine::run() {
else if (_installerArchive.hasFile("DEMOGAME.DAT"))
file = _installerArchive.createReadStreamForMember("DEMOGAME.DAT");
else {
Common::File *f = new Common::File();
f->open("SUPPORT/GAME.DUMP");
file = f;
debug("unknown version");
}
}
}
// Read assets file
assert(file != NULL);
const int32 fileSize = file->size();
const uint32 fileSize = file->size();
char *buf = (char *)malloc(fileSize + 1);
file->read(buf, fileSize);
buf[fileSize] = '\0';
Decompiler decomp(buf, fileSize, false);
free(buf);
buf = (char*) decomp.getResult().c_str();
debug("%s", buf);
// Initialize stuff
Gen::g_vm = new Gen::VM();
Settings::g_setts = new Settings::SettingMaps();
initFuncs();
parse(buf);
free(buf);
delete file;
assert(maps.constants.size() > 0);

View File

@ -118,6 +118,14 @@ Symbol *SymbolMaps::lookupRect(Common::String *n) {
return lookup(*n, rects);
}
Symbol *SymbolMaps::lookupVariable(Common::String *n) {
debug("looking variable up %s", n->c_str());
assert(variables.contains(*n));
return lookup(*n, variables);
}
/* lookup some name in some symbol table */
Symbol *SymbolMaps::lookupName(const char *n) {
debug("looking up %s", n);

View File

@ -71,6 +71,7 @@ public:
NameList locationList;
Symbol *constant(int t, int d, const char *s);
Symbol *lookupVariable(Common::String *n);
Symbol *lookupRect(Common::String *n);
Symbol *lookupName(const char *n);
void installAll(const char *n);