|
⇤ ← Revision 1 as of 2017-09-29 06:43:41
Size: 4755
Comment:
|
Size: 4755
Comment:
|
| Deletions are marked like this. | Additions are marked like this. |
| Line 3: | Line 3: |
| {{{#!highlighter c++ | {{{#!highlighter cpp |
.sob files, 32-bit word bytecode packed with a lookup table in the header and a string table at the end. I have NO IDEA what the VN engine actually does to execute its logic, only how to get the text out of the scripts, and I'm not 100% certain it's correct, it just seems to work properly.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <map>
#include <vector>
std::vector<std::map<uint32_t, uint32_t>> maps;
std::map<uint32_t, std::string> examples;
int main(int argc, char ** argv)
{
int strings = 0;
for(int i = 0; i < argc; i++)
{
maps.clear();
auto f = fopen(argv[i], "rb");
if(!f) continue;
char magic[4];
int n = fread(magic, 1, 4, f);
if(n != 4 or strncmp(magic, "SOB0", 4) != 0) continue;
uint32_t table_size;
fread(&table_size, 4, 1, f);
uint32_t table_end = table_size + 0x8;
int header_count = 0;
while(ftell(f) < table_end)
{
//printf("Header at %08X\n", ftell(f));
uint32_t word_pairs;
fread(&word_pairs, 4, 1, f);
std::map<uint32_t, uint32_t> newmap;
for(int i = 0; i < word_pairs; i++)
{
uint32_t key;
uint32_t value;
fread(&key, 4, 1, f);
fread(&value, 4, 1, f);
newmap[key] = value;
}
maps.push_back(newmap);
header_count += 1;
}
if(maps.size() < 5)
{
puts("not enough maps");
exit(0);
}
fseek(f, table_end, SEEK_SET);
uint32_t strings_start;
uint32_t strings_end;
fread(&strings_start, 4, 1, f);
fread(&strings_end, 4, 1, f);
uint32_t header_end = ftell(f);
//printf("String range: %08X~%08X\n", strings_start, strings_end);
// can't tell if text is content text until a command tries to use it? I think?
std::string text_memory;
bool justdidtext = false;
// no idea if commands have proper inline arguments in this bytecode lol
while(ftell(f) < strings_start)
{
uint32_t address = ftell(f)-header_end;
uint32_t command;
fread(&command, 4, 1, f);
if((command & 0xFFF00000) == 0x01800000)
{
if(maps[4].count(address) and maps[4][address] >= strings_start and maps[4][address] < strings_end)
{
//printf("Found command that uses string: ");
//printf("%08X: %08X (%08X) / ", address, command, maps[4][address], argv[i]);
//printf("|%08X|:(|%08X|) [%s]\n", address+header_end, maps[4][address]+header_end, argv[i]);
strings++;
fseek(f, maps[4][address]+header_end, SEEK_SET);
int c = fgetc(f);
if(c == 0) // 00 XX XX <string
fseek(f, 2, SEEK_CUR);
else // <string>
fseek(f, -1, SEEK_CUR);
auto start = ftell(f);
while((c = fgetc(f)) != 0);
auto end = ftell(f);
char * text = (char *)malloc(end-start);
fseek(f, start, SEEK_SET);
fread(text, 1, end-start, f);
std::string str = std::string(text);
if(!examples.count(command))
examples[command] = str;
//if(str != "")
// printf("%08X text %s\n", command, text);
//printf("%08X: %08X %s\n", address+header_end, command, text);
text_memory = text;
free(text);
justdidtext = true;
}
}
else
{
//printf("%08X\n", command);
// I have NO CERTAINTY that this is correct
if(command == 0x000001C8 and text_memory != "")
puts(text_memory.data());
justdidtext = false;
}
fseek(f, address+header_end+4, SEEK_SET);
}
fclose(f);
}
//printf("Total strings: %d\n", strings);
//for(auto &[k, v] : examples)
//{
// printf("%08X: %s\n", k, v.data());
//}
}