Add more sections to the dsb decompiler

This commit is contained in:
Hannes Mann 2016-06-20 05:05:31 +02:00
parent ce39ade17f
commit d2a4f6d5b5
5 changed files with 1998 additions and 1819 deletions

File diff suppressed because it is too large Load diff

View file

@ -10,7 +10,6 @@ namespace openrayman
{
bool data_extractor::extract(const std::string& install_folder)
{
// TODO: is this how c++ works even?!?
return
check_prerequisites(install_folder) &&
create_base() &&
@ -78,6 +77,6 @@ namespace openrayman
{
std::cout << "[openrayman::data_extractor] Decompiling Game.dsb" << std::endl;
dsb_decompiler decompiler;
return decompiler.decompile_dsb(install_folder + "/Data/Game.dsb", m_backend_specifics.get_data_path() + "/games/rayman2/game.db");
return decompiler.decompile_dsb(install_folder + "/Data/Game.dsb", m_backend_specifics.get_data_path() + "/games/rayman2/game.odsb", dsb_format::openrayman);
}
}

View file

@ -1,10 +1,12 @@
#include <data_extractor/dsb/dsb_decompiler.h>
#include <data_extractor/data_decoder.h>
#include <info.h>
#include <cstdint>
#include <unordered_map>
namespace openrayman
{
bool dsb_decompiler::decompile_dsb(const std::string& source, const std::string& target)
bool dsb_decompiler::decompile_dsb(const std::string& source, const std::string& target, dsb_format fmt)
{
std::cout << "[openrayman::dsb_decompiler] Reading dsb " << source << " to " << target << std::endl;
std::ifstream source_stream(source, std::ifstream::in | std::ifstream::binary);
@ -28,12 +30,13 @@ namespace openrayman
decoder.set_virtual_position(0);
decoder.decode_array(buffer, length - 4);
// TODO: decompile DSB
std::ofstream target_stream(target, std::ofstream::out | std::ofstream::binary);
if(target_stream.is_open())
{
decompile_ids(buffer, length - 4, target_stream);
if(fmt == dsb_format::openrayman)
decompile_sections(buffer, length - 4, target_stream);
else
target_stream.write(buffer, length - 4);
return true;
}
}
@ -48,9 +51,10 @@ namespace openrayman
}
};
// different "sections"?!?
void dsb_decompiler::decompile_ids(char* source, std::size_t source_length, std::ofstream& target)
void dsb_decompiler::decompile_sections(char* source, std::size_t source_length, std::ofstream& target)
{
target << "# Generated by OpenRayman " << openrayman::version << "\n";
target << "\n";
memorybuf streambuf(source, source + source_length);
std::istream in(&streambuf);
std::int32_t id;
@ -58,23 +62,21 @@ namespace openrayman
while(id != 0xFFFF)
{
#define DECOMPILE_ID(id, name, function) \
#define DECOMPILE_SECTION(id, name, function) \
case (id): \
std::cout << "[openrayman::dsb_decompiler].decompile_sections: decompiling " << std::hex << "0x" << (id) << " \"" << (name) << "\"" << std::endl; \
target << "section " << (name) << "\n"; \
target << "{\n"; \
(function)(in, target); \
target << "}\n\n"; \
target << "\n"; \
break;
switch(id)
{
DECOMPILE_ID(0x00, "alloc", decompile_alloc);
DECOMPILE_ID(0x1E, "levels", decompile_lvl_list);
DECOMPILE_ID(0x28, "data_directories", decompile_data_directories);
case 0x20:
break;
case 0x46:
break;
DECOMPILE_SECTION(0x00, "alloc", decompile_alloc);
DECOMPILE_SECTION(0x1E, "levels", decompile_lvl_list);
DECOMPILE_SECTION(0x28, "data_directories", decompile_data_directories);
DECOMPILE_SECTION(0x20, "unknown_blob_0x20", decompile_unknown_blob_0x20);
DECOMPILE_SECTION(0x46, "vignette", decompile_vignette);
case 0x40:
break;
case 0x5A:
@ -106,7 +108,7 @@ namespace openrayman
std::int32_t a, b;
source.read((char*)&a, sizeof(std::int32_t));
source.read((char*)&b, sizeof(std::int32_t));
target << std::to_string(a) << ", " << std::to_string(b) << ");\n";
target << std::to_string(a) << ", " << std::to_string(b) << ")\n";
}
else
{
@ -116,7 +118,7 @@ namespace openrayman
source.read((char*)&a, sizeof(std::int32_t));
if(a == 0xFFFF)
return;
target << std::to_string(a) << ");\n";
target << std::to_string(a) << ")\n";
}
source.read((char*)&id, sizeof(std::int32_t));
}
@ -142,7 +144,7 @@ namespace openrayman
target << c;
source.read(&c, 1);
}
target << " \");";
target << " \")";
}
source.read((char*)&id, sizeof(std::int32_t));
}
@ -179,7 +181,115 @@ namespace openrayman
source.read(str, str_length);
// dir(name, path);
if(dir != "")
target << " dir(" << dir << ", \"" << str << "\");\n";
target << " dir(" << dir << ", \"" << str << "\")\n";
source.read((char*)&id, sizeof(std::int32_t));
}
}
// TODO: what is this?!?
// is this ever found?!?!
void dsb_decompiler::decompile_unknown_blob_0x20(std::istream& source, std::ofstream& target)
{
std::uint32_t size;
source.read((char*)&size, sizeof(std::uint32_t));
target << " size(" << size << ")\n";
std::int32_t id;
source.read((char*)&id, sizeof(std::int32_t));
std::unordered_map<std::int32_t, int> encountered_ids;
while(id != 0xFFFF)
{
if(encountered_ids.count(id) == 0)
encountered_ids[id] = 0;
encountered_ids[id]++;
source.read((char*)&id, sizeof(std::int32_t));
}
for(std::pair<std::int32_t, int> pair : encountered_ids)
target << " id_encounter(" << std::hex << "0x" << pair.first << std::dec << ", " << pair.second << ")\n";
}
// vignettes are basically loading screens
// TODO: there are some .pgbs in rayman 2 /data
void dsb_decompiler::decompile_vignette(std::istream& source, std::ofstream& target)
{
std::int32_t id;
source.read((char*)&id, sizeof(std::int32_t));
while(id != 0xFFFF)
{
switch(id)
{
case 71:
{
target << " load_img(\"";
char c;
source.read(&c, 1);
while(c != '\0')
{
target << c;
source.read(&c, 1);
}
target << "\")\n";
break;
}
case 72:
{
std::uint16_t length;
source.read((char*)&length, sizeof(std::uint16_t));
char str[length];
source.read(str, length);
target << " load_img(\"" << str << "\")\n";
break;
}
case 75:
{
target << " display()\n";
break;
}
case 76:
case 77:
{
std::int32_t tmp;
// skip these three
// TODO
for(int n = 0; n < 3; n++)
source.read((char*)&tmp, sizeof(std::int32_t));
std::uint8_t r, g, b, a;
source.read((char*)&r, 1); source.read((char*)&g, 1); source.read((char*)&b, 1); source.read((char*)&a, 1);
target << " color("
<< (id == 76 ? "outline" : "inline")
<< ", " << std::to_string(r)
<< ", " << std::to_string(g)
<< ", " << std::to_string(b)
<< ", " << std::to_string(a)
<< ")\n";
break;
}
case 78:
{
char tmp[16 * 4];
// four pairs of 16?!?!
source.read(tmp, 16 * 4);
break;
}
case 79:
{
char tmp[sizeof(std::int32_t) * 4];
// four pairs of int32_t?!?!
source.read(tmp, sizeof(std::int32_t) * 4);
break;
}
case 80:
{
target << " add_bar()\n";
break;
}
case 81:
{
std::int32_t max;
source.read((char*)&max, sizeof(std::int32_t));
target << " set_bar_max(" << max << ")\n";
break;
}
}
source.read((char*)&id, sizeof(std::int32_t));
}
}

View file

@ -8,19 +8,39 @@
namespace openrayman
{
// Decodes and decompiles DSB files into database files.
enum class dsb_format
{
// The default format.
// This is a more human readable/editable format than the binary format used by Rayman 2.
// This can be interpreted by the dsb engine.
// Uses the extension .odsb
openrayman,
// The format used by the Rayman 2: The Great Escape engine, decoded.
// This is a binary format.
// This can not be interpreted by OpenRayman.
// The only operation that is performed by the dsb decompiler when this format is specified
// is to decode the dsb.
// Uses the extension .rdsb
rayman2_decoded
};
// Decodes and optionally decompiles DSB files.
// This is all heavily adapted from Rayman2Lib's DSBDecompiler
class dsb_decompiler
{
public:
// Decompiles the specified DSB file into the target file.
// Decodes and optionally decompiles the specified DSB file into the target file.
// This function assumes that the source file exists and that the target location is accessible.
// Returns true if the decompilation succeeded.
bool decompile_dsb(const std::string& source, const std::string& target);
// Returns true if the function succeeded.
bool decompile_dsb(const std::string& source, const std::string& target, dsb_format fmt);
private:
void decompile_ids(char* source, std::size_t source_length, std::ofstream& target);
void decompile_sections(char* source, std::size_t source_length, std::ofstream& target);
void decompile_alloc(std::istream& source, std::ofstream& target);
void decompile_lvl_list(std::istream& source, std::ofstream& target);
void decompile_data_directories(std::istream& source, std::ofstream& target);
void decompile_unknown_blob_0x20(std::istream& source, std::ofstream& target);
void decompile_vignette(std::istream& source, std::ofstream& target);
data_decoder m_decoder;
};

View file

@ -2,6 +2,7 @@
#include <iostream>
#include <info.h>
#include <engine.h>
#include <data_extractor/dsb/dsb_decompiler.h>
bool console_open = false;
@ -30,8 +31,7 @@ int main(int argc, char** argv)
n++;
if(n >= argc)
{
make_sure_console_open();
std::cout << "No game was specified." << std::endl;
make_sure_console_open(); std::cout << "No game was specified." << std::endl;
return EXIT_FAILURE;
}
std::string game(argv[n]);
@ -42,26 +42,76 @@ int main(int argc, char** argv)
n++;
if(n >= argc)
{
make_sure_console_open();
std::cout << "No install folder was specified." << std::endl;
make_sure_console_open(); std::cout << "No install folder was specified." << std::endl;
return EXIT_FAILURE;
}
std::string install_folder(argv[n]);
selected_install_folder = install_folder;
}
if(str == "--decompile")
{
n++;
if(n >= argc)
{
make_sure_console_open(); std::cout << "No type was specified." << std::endl;
return EXIT_FAILURE;
}
std::string type(argv[n]);
n++;
if(n >= argc)
{
make_sure_console_open(); std::cout << "No path was specified." << std::endl;
return EXIT_FAILURE;
}
std::string path(argv[n]);
n++;
if(n >= argc)
{
make_sure_console_open(); std::cout << "No target was specified." << std::endl;
return EXIT_FAILURE;
}
std::string target(argv[n]);
if(type == "odsb" || type == "rdsb")
{
openrayman::dsb_decompiler decompiler;
if(decompiler.decompile_dsb(
path,
target,
type == "odsb" ?
openrayman::dsb_format::openrayman :
openrayman::dsb_format::rayman2_decoded))
{
return EXIT_SUCCESS;
}
else
{
std::cout << "Operation failed" << std::endl;
return EXIT_FAILURE;
}
}
else
{
make_sure_console_open(); std::cout << "Invalid type specified." << std::endl;
return EXIT_FAILURE;
}
}
// Follow GNU format
if(str == "--help")
{
make_sure_console_open();
std::cout << "Usage: openrayman [options] ..." << std::endl;
std::cout << "Options:" << std::endl;
std::cout << " --version Display version information" << std::endl;
std::cout << " --game \"game name\" Specifies what game OpenRayman should load" << std::endl;
std::cout << " This will default to the game set in the config file if no game is specified" << std::endl;
std::cout << " --convert-data \"install folder\" Converts the install folder specified into a format that OpenRayman can read" << std::endl;
std::cout << " This is needed to ease modding support" << std::endl;
std::cout << " This can also be done by starting the game without extracted data" << std::endl;
std::cout << " In that case, you will get a directory picker" << std::endl;
std::cout << " --version Display version information" << std::endl;
std::cout << " --game \"game name\" Specifies what game OpenRayman should load" << std::endl;
std::cout << " This will default to the game set in the config file if no game is specified" << std::endl;
std::cout << " --convert-data \"install folder\" Converts the install folder specified into a format that OpenRayman can read" << std::endl;
std::cout << " This is needed to ease modding support" << std::endl;
std::cout << " This can also be done by starting the game without extracted data" << std::endl;
std::cout << " In that case, you will get a directory picker" << std::endl;
std::cout << " --decompile \"type\" \"path\" \"target\" Decompiles the specified file into target." << std::endl;
std::cout << " Type can be any of:" << std::endl;
std::cout << " \"odsb\": Creates an OpenRayman dsb file" << std::endl;
std::cout << " \"rdsb\": Decodes a dsb file" << std::endl;
return EXIT_SUCCESS;
}
if(str == "--version")