DEADSOFTWARE

43251c8d9d00507d5a251e24e422400bbd2c034a
[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 s_start, s_end;
30 static int check_header (Stream *r) {
31 assert(r != NULL);
32 char ident[4];
33 stream_setpos(r, 0); // !!!
34 stream_read(ident, 4, 1, r);
35 return (memcmp(ident, "IWAD", 4) == 0) || (memcmp(ident, "PWAD", 4) == 0);
36 }
38 int WADRES_addwad (Stream *r) {
39 assert(r != NULL);
40 if (n_wads < MAX_WADS && check_header(r)) {
41 wads[n_wads] = r;
42 n_wads += 1;
43 return 1;
44 } else {
45 return 0;
46 }
47 }
49 static int WADRES_addresource (const Entry *e) {
50 assert(e != NULL);
51 for (int i = 0; i < n_resources; ++i) {
52 if (cp866_strncasecmp(resources[i].name, e->name, 8) == 0) {
53 memcpy(&resources[i], e, sizeof(Entry));
54 return i;
55 }
56 }
57 if (n_resources < MAX_RESOURCES) {
58 memcpy(&resources[n_resources], e, sizeof(Entry));
59 n_resources += 1;
60 return n_resources - 1;
61 }
62 return -1;
63 }
65 static int WADRES_read (int f) {
66 Stream *r = wads[f];
67 stream_setpos(r, 4); // skip magic
68 int32_t n = stream_read32(r);
69 int32_t dir = stream_read32(r);
70 stream_setpos(r, dir);
71 int ok = 1;
72 for (int32_t i = 0; ok && i < n; ++i) {
73 Entry e;
74 e.offset = stream_read32(r);
75 e.size = stream_read32(r);
76 e.f = f;
77 stream_read(e.name, 8, 1, r);
78 ok = WADRES_addresource(&e) != -1;
79 }
80 return ok;
81 }
83 int WADRES_rehash (void) {
84 int ok = 1;
85 for (int i = 0; i < n_wads; ++i) {
86 if (!WADRES_read(i)) {
87 ok = 0;
88 }
89 }
90 s_start = WADRES_find("S_START");
91 s_end = WADRES_find("S_END");
92 return ok;
93 }
95 int WADRES_find (const char name[8]) {
96 int i = n_resources - 1;
97 while (i >= 0 && cp866_strncasecmp(name, resources[i].name, 8) != 0) {
98 i -= 1;
99 }
100 return i;
103 int WADRES_maxids (void) {
104 return n_resources;
107 int WADRES_findsprite (const char n[4], int s, int d, char *dir) {
108 s += 'A';
109 d += '0';
110 for (int i = s_start + 1; i < s_end; i++) {
111 char a, b;
112 char *wn = resources[i].name;
113 if (cp866_strncasecmp(wn, n, 4) == 0 && (wn[4] == s || wn[6] == s)) {
114 a = wn[4] == s ? wn[5] : 0;
115 b = wn[6] == s ? wn[7] : 0;
116 if (a == '0' || b == '0' || a == d || b == d) {
117 if (dir != NULL) {
118 *dir = (a != '0' && b == '0') || (a != d && b == d);
120 return i;
124 return -1;
127 Stream *WADRES_getbasereader (int id) {
128 assert(id >= 0 && id < n_resources);
129 return wads[resources[id].f];
132 long WADRES_getoffset (int id) {
133 assert(id >= 0 && id < n_resources);
134 return resources[id].offset;
137 long WADRES_getsize (int id) {
138 assert(id >= 0 && id < n_resources);
139 return resources[id].size;
142 void WADRES_getname (int id, char *name) {
143 assert(id >= 0 && id < n_resources);
144 strncpy(name, resources[id].name, 8);
147 void WADRES_getdata (int id, void *data) {
148 assert(id >= 0 && id < n_resources);
149 Stream *r = wads[resources[id].f];
150 long pos = stream_getpos(r);
151 stream_setpos(r, resources[id].offset);
152 stream_read(data, resources[id].size, 1, r);
153 stream_setpos(r, pos);
156 void *WADRES_lock (int id) {
157 assert(id >= -1 && id < MAX_RESOURCES);
158 if (id >= 0) {
159 Block *x = blocks[id];
160 if (x) {
161 x->ref += 1;
162 return x->data;
163 } else {
164 x = malloc(sizeof(Block) + WADRES_getsize(id));
165 if (x) {
166 x->id = id;
167 x->ref = 1;
168 WADRES_getdata(id, x->data);
169 blocks[id] = x;
170 return x->data;
174 return NULL;
177 void WADRES_unlock (void *data) {
178 if (data) {
179 Block *x = data - sizeof(Block);
180 int id = x->id;
181 assert(id >= 0 && id < MAX_RESOURCES);
182 x->ref -= 1;
183 assert(x->ref >= 0);
184 #if 0
185 if (x->ref == 0) {
186 blocks[id] = NULL;
187 free(x);
189 #endif
193 int WADRES_locked (int id) {
194 assert(id >= -1 && id < MAX_RESOURCES);
195 return (id >= 0) && (blocks[id] != NULL) && (blocks[id]->ref >= 1);
198 int WADRES_was_locked (int id) {
199 assert(id >= -1 && id < MAX_RESOURCES);
200 return (id >= 0) && (blocks[id] != NULL) && (blocks[id]->ref >= 0);