summaryrefslogtreecommitdiff
path: root/src/preprocess/CompTool.cpp
blob: f453050babd480eaf26bdf34b0bd715bd0102881 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include "CompTool.h"
#include "utils/Decompressor.h"
#include "lib/binarytools/BinaryWriter.h"
#include "lib/binarytools/BinaryReader.h"
#include <fstream>
#include <cstring>

uint32_t CompTool::FindFileTable(std::vector<uint8_t>& rom) {
    uint8_t query_one[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x50, 0x00, 0x00, 0x00, 0x00 };
    uint8_t query_two[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00 };

    for(size_t i = 0; i < rom.size() - sizeof(query_one); i++) {
        if(memcmp(rom.data() + i, query_one, sizeof(query_one)) == 0){
            return i;
        }

        if(memcmp(rom.data() + i, query_two, sizeof(query_two)) == 0){
            return i;
        }
    }

    throw std::runtime_error("Failed to find file table");
}

std::vector<uint8_t> CompTool::Decompress(std::vector<uint8_t> rom){
    LUS::BinaryReader basefile((char*) rom.data(), rom.size());
    basefile.SetEndianness(Torch::Endianness::Big);

    LUS::BinaryWriter decompfile;
    decompfile.SetEndianness(Torch::Endianness::Big);
    decompfile.Write((uint8_t)0x80);

    uint32_t table = CompTool::FindFileTable(rom);
    uint32_t count = 0;
    while (true){
        auto entry = table + 0x10 * count;
        basefile.Seek(entry, LUS::SeekOffsetType::Start);

        auto v_begin = basefile.ReadInt32();
        auto p_begin = basefile.ReadInt32();
        auto p_end = basefile.ReadInt32();
        auto comp_flag = basefile.ReadInt32();

        auto p_size = p_end - p_begin;
        auto v_size = (int32_t) 0;
        DataChunk* decoded = nullptr;

        if(v_begin == 0 && p_end == 0){
            break;
        }

        basefile.Seek(p_begin, LUS::SeekOffsetType::Start);

        auto bytes = new uint8_t[p_size];
        basefile.Read((char*) bytes, p_size);

        switch ((CompType) comp_flag) {
            case CompType::UNCOMPRESSED:
                v_size = p_size;
                break;
            case CompType::COMPRESSED:
                decoded = Decompressor::Decode(std::vector(bytes, bytes + p_size), 0, CompressionType::MIO0, true);
                bytes = decoded->data;
                v_size = decoded->size;
                break;
            default:
                throw std::runtime_error("Invalid compression flag. There may be a problem with your ROM.");
        }

        decompfile.Seek(v_begin, LUS::SeekOffsetType::Start);
        decompfile.Write((char*) bytes, v_size);
        auto v_end = v_begin + v_size;

        decompfile.Seek(entry + 4, LUS::SeekOffsetType::Start);
        decompfile.Write(v_begin);
        decompfile.Write(v_end);
        decompfile.Write((uint32_t) CompType::UNCOMPRESSED);
        count++;
    }

    decompfile.Seek(0x10, LUS::SeekOffsetType::Start);
    decompfile.Write(0xA7D5F194); // CRC1
    decompfile.Write(0xFE3DF761); // CRC2

    auto result = decompfile.ToVector();
    return { (uint8_t*) result.data(), (uint8_t*) result.data() + result.size() };
}