aboutsummaryrefslogtreecommitdiff
path: root/src/rez/rez.cpp
blob: 2351c0593eecb89d32327324257d84297b06b422 (plain) (blame)
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include <rez.h>
#include <rez/dir.h>
#include <rez/io.h>
#include <cctype>
#include <iostream>
#include <memory>
#include <sstream>
#include <variant>

std::string rez::ball::toupper(const std::string &s) const
{
    std::string ret;

    // Assume ASCII encoding.
    for (const auto &c: s)
        ret += std::toupper(c);

    return ret;
}

std::unique_ptr<rez::file> rez::ball::open(const char *path)
{
    std::istringstream stream(path);
    std::string token;
    const rez::dir *dir = &root_dir;
    const rez::resource *resource = nullptr;

    while (std::getline(stream, token, '/'))
    {
        std::string uctoken = toupper(token);
        const auto &map = dir->entries();
        auto it = map.find(uctoken);

        if (it == map.end())
            return nullptr;

        const rez::dir::direntry &de = it->second;

        if (std::holds_alternative<rez::dir>(de))
            dir = &std::get<rez::dir>(de);
        else if (std::holds_alternative<rez::resource>(de))
        {
            dir = nullptr;
            resource = &std::get<rez::resource>(de);
        }
    }

    if (dir)
    {
        std::cerr << path << " is a directory\n";
        return nullptr;
    }
    else if (!resource)
    {
        std::cerr << io.path() << ": could not find " << path << '\n';
        return nullptr;
    }

    return std::make_unique<rez::file>(*resource, io);
}

int rez::ball::parse()
{
    static const char title[63] =
        "\r\nRezMgr Version 1 Copyright (C) 1995 MONOLITH INC.           ",
        subtitle[65] =
        "\r\nLithTech Resource File                                      \r\n";

    if (io.open())
        return -1;
    else if (io.check(title))
    {
        std::cerr << path << ": wrong title\n";
        return -1;
    }
    else if (io.check(subtitle))
    {
        std::cerr << path << ": wrong subtitle\n";
        return -1;
    }
    else if (io.check(0x1a))
    {
        std::cerr << path << ": wrong EOF\n";
        return -1;
    }

    struct
    {
        uint32_t w[N_WORDS];
        uint8_t is_sorted;
    } header;

    for (auto &w : header.w)
        if (io.read_le(w))
            return -1;

    if (header.w[FILE_FORMAT_VERSION] != 1)
    {
        std::cerr << path << ": expected file format version 1, got "
            << header.w[FILE_FORMAT_VERSION] << '\n';
        return -1;
    }
    else if (io.read(header.is_sorted))
    {
        std::cerr << path << ": could not read sorted flag" << '\n';
        return -1;
    }

    struct rez::entry::cfg cfg = {0};

    cfg.size = header.w[ROOT_DIR_SIZE];
    cfg.offset = header.w[ROOT_DIR_POS];
    cfg.maxcomlen = header.w[MAX_COMMENT_SIZE];
    cfg.maxdirlen = header.w[MAX_DIR_NAME_SIZE];
    cfg.maxreslen = header.w[MAX_REZ_NAME_SIZE];
    root_dir.read(cfg, io, 0);
    return 0;
}

rez::ball::ball(const char *path) :
    path(path),
    io(path)
{
}