Differences between revisions 1 and 2
Revision 1 as of 2017-09-29 06:43:41
Size: 4755
Editor: weh
Comment:
Revision 2 as of 2017-09-29 06:51:35
Size: 4755
Editor: weh
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());
    //}
}

Lucifen Library (last edited 2017-10-01 11:21:51 by weh)