⇤ ← 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()); //} }