1 //------------------------------------------------------------------------
2 // WAD I/O
3 //------------------------------------------------------------------------
4 //
5 // DEH_EDGE Copyright (C) 2004-2005 The EDGE Team
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License (in COPYING.txt) for more details.
16 //
17 //------------------------------------------------------------------------
18 //
19 // DEH_EDGE is based on:
20 //
21 // + DeHackEd source code, by Greg Lewis.
22 // - DOOM source code (C) 1993-1996 id Software, Inc.
23 // - Linux DOOM Hack Editor, by Sam Lantinga.
24 // - PrBoom's DEH/BEX code, by Ty Halderman, TeamTNT.
25 //
26 //------------------------------------------------------------------------
27
28 #include "i_defs.h"
29 #include "dh_plugin.h"
30 #include "wad.h"
31
32 #include "system.h"
33
34 #include <errno.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 namespace Deh_Edge
41 {
42
43 #define PWAD_HEADER "PWAD"
44
45 #define MAX_LUMPS 2000
46
47 #define DEBUG_DDF 0
48
49
50 namespace WAD
51 {
52 // --- TYPES ---
53
54 //
55 // Wad Info
56 //
57 typedef struct
58 {
59 char id[4]; // IWAD (whole) or PWAD (part)
60 int numlumps; // Number of Lumps
61 int infotableofs; // Info table offset
62 }
63 wadinfo_t;
64
65 //
66 // Lump stuff
67 //
68 typedef struct lump_s
69 {
70 byte *data; // Data
71 int filepos; // Position in file
72 int size; // Size
73 char name[8]; // Name
74 }
75 lump_t;
76
77 // Lump list
78 lump_t **lumplist = NULL;
79 int num_lumps;
80
81 lump_t *cur_lump = NULL;
82 int cur_max_size;
83
84 char wad_msg_buf[1024];
85
86 //
87 // PadFile
88 //
89 // Pads a file to the nearest 4 bytes.
90 //
PadFile(FILE * fp)91 void PadFile(FILE *fp)
92 {
93 unsigned char zeros[4] = { 0, 0, 0, 0 };
94
95 int num = ftell(fp) % 4;
96
97 if (num != 0)
98 {
99 fwrite(&zeros, 1, 4 - num, fp);
100 }
101 }
102
103 //
104 // LumpExists
105 //
LumpExists(const char * name)106 int LumpExists(const char *name)
107 {
108 int i;
109
110 for (i = 0; i < num_lumps; i++)
111 {
112 if (strncmp(lumplist[i]->name, name, 8) == 0)
113 return i;
114 }
115
116 return -1;
117 }
118 }
119
120 //
121 // WAD::NewLump
122 //
NewLump(const char * name)123 void WAD::NewLump(const char *name)
124 {
125 if (cur_lump)
126 InternalError("WAD_NewLump: current lump not finished.\n");
127
128 // Check for existing lump, overwrite if need be.
129 int i = WAD::LumpExists(name);
130
131 if (i >= 0)
132 {
133 free(lumplist[i]->data);
134 }
135 else
136 {
137 i = num_lumps;
138
139 num_lumps++;
140
141 if (num_lumps > MAX_LUMPS)
142 FatalError("Too many lumps ! (%d)\n", MAX_LUMPS);
143
144 lumplist[i] = (lump_t *) calloc(sizeof(lump_t), 1);
145
146 if (! lumplist[i])
147 FatalError("Out of memory (adding %dth lump)\n", num_lumps);
148 }
149
150 cur_lump = lumplist[i];
151 cur_max_size = 4;
152
153 cur_lump->size = 0;
154 cur_lump->data = (byte *) malloc(cur_max_size);
155
156 if (! cur_lump->data)
157 FatalError("Out of memory (New lump data)\n");
158
159 strncpy(cur_lump->name, name, 8);
160 }
161
162 //
163 // WAD::AddData
164 //
AddData(const byte * data,int size)165 void WAD::AddData(const byte *data, int size)
166 {
167 if (! cur_lump)
168 InternalError("WAD_AddData: no current lump.\n");
169
170 if (cur_lump->size + size > cur_max_size)
171 {
172 while (cur_lump->size + size > cur_max_size)
173 cur_max_size *= 2;
174
175 cur_lump->data = (byte *) realloc(cur_lump->data, cur_max_size);
176
177 if (! cur_lump->data)
178 FatalError("Out of memory (adding %d bytes)\n", size);
179 }
180
181 memcpy(cur_lump->data + cur_lump->size, data, size);
182
183 cur_lump->size += size;
184 }
185
186 //
187 // WAD::Printf
188 //
Printf(const char * str,...)189 void WAD::Printf(const char *str, ...)
190 {
191 va_list args;
192
193 va_start(args, str);
194 vsprintf(wad_msg_buf, str, args);
195 va_end(args);
196
197 #if (DEBUG_DDF)
198 fprintf(stderr, "%s", wad_msg_buf);
199 #else
200 WAD::AddData((byte *) wad_msg_buf, strlen(wad_msg_buf));
201 #endif
202 }
203
204 //
205 // WAD::FinishLump
206 //
FinishLump(void)207 void WAD::FinishLump(void)
208 {
209 if (! cur_lump)
210 InternalError("WAD_FinishLump: not started.\n");
211
212 cur_lump = NULL;
213 cur_max_size = 0;
214 }
215
216 //
217 // WAD::WriteFile
218 //
WriteFile(const char * name)219 dehret_e WAD::WriteFile(const char *name)
220 {
221 if (cur_lump)
222 InternalError("WAD_WriteFile: lump not finished.\n");
223
224 FILE *fp;
225 const char *pwadstr = PWAD_HEADER;
226
227 // Open File
228 fp = fopen(name, "wb");
229
230 if (!fp)
231 {
232 int err_num = errno;
233
234 SetErrorMsg("Cannot create output file: %s\n[%s]\n", name, strerror(err_num));
235 return DEH_E_NoFile;
236 }
237
238 // Write Header
239 int raw_num = Endian_U32(num_lumps);
240
241 fwrite((void*)pwadstr, 1, 4, fp);
242 fwrite((void*)&raw_num, sizeof(int), 1, fp);
243 fwrite((void*)&raw_num, sizeof(int), 1, fp); // dummy - write later
244
245 ProgressMinor(1, num_lumps+3);
246
247 // Write Lumps
248 int i;
249
250 for (i = 0; i < num_lumps; i++)
251 {
252 PadFile(fp);
253 lumplist[i]->filepos = ftell(fp);
254 fwrite((void*)lumplist[i]->data, 1, lumplist[i]->size, fp);
255
256 ProgressMinor(i+2, num_lumps+3);
257 }
258
259 PadFile(fp);
260 int raw_offset = Endian_U32(ftell(fp));
261
262 // Write Lumpinfos (directory table)
263 for (i = 0; i < num_lumps; i++)
264 {
265 int raw_pos = Endian_U32(lumplist[i]->filepos);
266 int raw_size = Endian_U32(lumplist[i]->size);
267
268 fwrite((void*)&raw_pos, sizeof(int), 1, fp);
269 fwrite((void*)&raw_size, sizeof(int), 1, fp);
270 fwrite((void*)lumplist[i]->name, 1, 8, fp);
271 }
272
273 ProgressMinor(num_lumps+2, num_lumps+3);
274
275 // Write table offset
276 fseek(fp, 8, SEEK_SET);
277 fwrite((void*)&raw_offset, sizeof(int), 1, fp);
278
279 // Close File
280 fclose(fp);
281
282 return DEH_OK;
283 }
284
285 //
286 // WAD::Startup
287 //
Startup(void)288 void WAD::Startup(void)
289 {
290 lumplist = (lump_t **) calloc(sizeof(lump_t *), MAX_LUMPS);
291
292 if (! lumplist)
293 FatalError("Out of memory (WAD_Startup)\n");
294
295 num_lumps = 0;
296 }
297
298 //
299 // WAD::Shutdown
300 //
Shutdown(void)301 void WAD::Shutdown(void)
302 {
303 int i;
304
305 // go through lump list and free lumps
306 for (i = 0; i < num_lumps; i++)
307 {
308 free(lumplist[i]->data);
309 free(lumplist[i]);
310 }
311
312 num_lumps = 0;
313
314 if (lumplist)
315 {
316 free(lumplist);
317 lumplist = 0;
318 }
319 }
320
321 } // Deh_Edge
322