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