DEADSOFTWARE

memory: load and allocate resources in wadres
[flatwaifu.git] / src / common / wadres.c
1 #include <stdint.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <assert.h>
6 #include "wadres.h"
7 #include "streams.h"
8 #include "cp866.h"
10 typedef struct Entry {
11 long offset, size;
12 char name[8];
13 int f;
14 } Entry;
16 typedef struct Block {
17 int id;
18 int ref;
19 char data[];
20 } Block;
22 static int n_wads;
23 static int n_resources;
24 static Stream *wads[MAX_WADS];
25 static Entry resources[MAX_RESOURCES];
26 static Block *blocks[MAX_RESOURCES];
28 static int check_header (Stream *r) {
29 assert(r != NULL);
30 char ident[4];
31 stream_setpos(r, 0); // !!!
32 stream_read(ident, 4, 1, r);
33 return (memcmp(ident, "IWAD", 4) == 0) || (memcmp(ident, "PWAD", 4) == 0);
34 }
36 int WADRES_addwad (Stream *r) {
37 assert(r != NULL);
38 if (n_wads < MAX_WADS && check_header(r)) {
39 wads[n_wads] = r;
40 n_wads += 1;
41 return 1;
42 } else {
43 return 0;
44 }
45 }
47 static int WADRES_addresource (const Entry *e) {
48 assert(e != NULL);
49 for (int i = 0; i < n_resources; ++i) {
50 if (cp866_strncasecmp(resources[i].name, e->name, 8) == 0) {
51 memcpy(&resources[i], e, sizeof(Entry));
52 return i;
53 }
54 }
55 if (n_resources < MAX_RESOURCES) {
56 memcpy(&resources[n_resources], e, sizeof(Entry));
57 n_resources += 1;
58 return n_resources - 1;
59 }
60 return -1;
61 }
63 static int WADRES_read (Stream *r) {
64 stream_setpos(r, 4); // skip magic
65 int32_t n = stream_read32(r);
66 int32_t dir = stream_read32(r);
67 stream_setpos(r, dir);
68 int ok = 1;
69 for (int32_t i = 0; ok && i < n; ++i) {
70 Entry e;
71 e.offset = stream_read32(r);
72 e.size = stream_read32(r);
73 stream_read(e.name, 8, 1, r);
74 ok = WADRES_addresource(&e) != -1;
75 }
76 return ok;
77 }
79 int WADRES_rehash (void) {
80 int ok = 1;
81 for (int i = 0; i < n_wads; ++i) {
82 if (!WADRES_read(wads[i])) {
83 ok = 0;
84 }
85 }
86 return ok;
87 }
89 int WADRES_find (const char name[8]) {
90 int i = n_resources - 1;
91 while (i >= 0 && cp866_strncasecmp(name, resources[i].name, 8) != 0) {
92 i -= 1;
93 }
94 return i;
95 }
97 int WADRES_maxids (void) {
98 return n_resources;
99 }
101 Stream *WADRES_getbasereader (int id) {
102 assert(id >= 0 && id < n_resources);
103 return wads[resources[id].f];
106 long WADRES_getoffset (int id) {
107 assert(id >= 0 && id < n_resources);
108 return resources[id].offset;
111 long WADRES_getsize (int id) {
112 assert(id >= 0 && id < n_resources);
113 return resources[id].size;
116 void WADRES_getname (int id, char *name) {
117 assert(id >= 0 && id < n_resources);
118 strncpy(name, resources[id].name, 8);
121 void WADRES_getdata (int id, void *data) {
122 assert(id >= 0 && id < n_resources);
123 Stream *r = wads[resources[id].f];
124 long pos = stream_getpos(r);
125 stream_setpos(r, resources[id].offset);
126 stream_read(data, resources[id].size, 1, r);
127 stream_setpos(r, pos);
130 void *WADRES_lock (int id) {
131 assert(id >= -1 && id < MAX_RESOURCES);
132 if (id >= 0) {
133 Block *x = blocks[id];
134 if (x) {
135 x->ref += 1;
136 return x->data;
137 } else {
138 x = malloc(sizeof(Block) + WADRES_getsize(id));
139 if (x) {
140 x->id = id;
141 x->ref = 1;
142 WADRES_getdata(id, x->data);
143 blocks[id] = x;
144 return x->data;
148 return NULL;
151 void WADRES_unlock (void *data) {
152 if (data) {
153 Block *x = data - sizeof(Block);
154 int id = x->id;
155 assert(id >= 0 && id < MAX_RESOURCES);
156 x->ref -= 1;
157 assert(x->ref >= 0);
158 #if 0
159 if (x->ref == 0) {
160 blocks[id] = NULL;
161 free(x);
163 #endif
167 int WADRES_locked (int id) {
168 assert(id >= -1 && id < MAX_RESOURCES);
169 return (id >= 0) && (blocks[id] != NULL) && (blocks[id]->ref >= 1);
172 int WADRES_was_locked (int id) {
173 assert(id >= -1 && id < MAX_RESOURCES);
174 return (id >= 0) && (blocks[id] != NULL) && (blocks[id]->ref >= 0);