aboutsummaryrefslogtreecommitdiff
path: root/src/romfile.c
blob: 64abe685e0a10d6f18939d1af64afc5f439dff1c (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
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Access to pseudo "file" interface for configuration information.
//
// Copyright (C) 2012  Kevin O'Connor <kevin@koconnor.net>
//
// This file may be distributed under the terms of the GNU LGPLv3 license.

#include "config.h" // CONFIG_*
#include "byteorder.h" // cpu_to_le16
#include "malloc.h" // free
#include "output.h" // dprintf
#include "romfile.h" // struct romfile_s
#include "string.h" // memcmp

static struct romfile_s *RomfileRoot VARVERIFY32INIT;

void
romfile_add(struct romfile_s *file)
{
    dprintf(3, "Add romfile: %s (size=%d)\n", file->name, file->size);
    file->next = RomfileRoot;
    RomfileRoot = file;
}

// Search for the specified file.
static struct romfile_s *
__romfile_findprefix(const char *prefix, int prefixlen, struct romfile_s *prev)
{
    struct romfile_s *cur = RomfileRoot;
    if (prev)
        cur = prev->next;
    while (cur) {
        if (memcmp(prefix, cur->name, prefixlen) == 0)
            return cur;
        cur = cur->next;
    }
    return NULL;
}

struct romfile_s *
romfile_findprefix(const char *prefix, struct romfile_s *prev)
{
    return __romfile_findprefix(prefix, strlen(prefix), prev);
}

struct romfile_s *
romfile_find(const char *name)
{
    return __romfile_findprefix(name, strlen(name) + 1, NULL);
}

// Helper function to find, malloc_tmphigh, and copy a romfile.  This
// function adds a trailing zero to the malloc'd copy.
void *
romfile_loadfile(const char *name, int *psize)
{
    struct romfile_s *file = romfile_find(name);
    if (!file)
        return NULL;

    int filesize = file->size;
    if (!filesize)
        return NULL;

    char *data = malloc_tmphigh(filesize+1);
    if (!data) {
        warn_noalloc();
        return NULL;
    }

    dprintf(5, "Copying romfile '%s' (len %d)\n", name, filesize);
    int ret = file->copy(file, data, filesize);
    if (ret < 0) {
        free(data);
        return NULL;
    }
    if (psize)
        *psize = filesize;
    data[filesize] = '\0';
    return data;
}

// Attempt to load an integer from the given file - return 'defval'
// if unsuccessful.
u64
romfile_loadint(const char *name, u64 defval)
{
    struct romfile_s *file = romfile_find(name);
    if (!file)
        return defval;

    int filesize = file->size;
    if (!filesize || filesize > sizeof(u64) || (filesize & (filesize-1)))
        // Doesn't look like a valid integer.
        return defval;

    u64 val = 0;
    int ret = file->copy(file, &val, sizeof(val));
    if (ret < 0)
        return defval;
    /* romfile interface stores values in little endian */
    return le64_to_cpu(val);
}

struct const_romfile_s {
    struct romfile_s file;
    void *data;
};

static int
const_read_file(struct romfile_s *file, void *dst, u32 maxlen)
{
    if (file->size > maxlen)
        return -1;
    struct const_romfile_s *cfile;
    cfile = container_of(file, struct const_romfile_s, file);
    if (maxlen > file->size)
        maxlen = file->size;
    memcpy(dst, cfile->data, maxlen);
    return file->size;
}

static void
const_romfile_add(char *name, void *data, int size)
{
    struct const_romfile_s *cfile = malloc_tmp(sizeof(*cfile));
    if (!cfile) {
        warn_noalloc();
        return;
    }
    memset(cfile, 0, sizeof(*cfile));
    strtcpy(cfile->file.name, name, sizeof(cfile->file.name));
    cfile->file.size = size;
    cfile->file.copy = const_read_file;
    cfile->data = data;
    romfile_add(&cfile->file);
}

void
const_romfile_add_int(char *name, u32 value)
{
    u32 *data = malloc_tmp(sizeof(*data));
    if (!data) {
        warn_noalloc();
        return;
    }
    *data = value;
    const_romfile_add(name, data, sizeof(*data));
}