1 // SONIC ROBO BLAST 2
2 //-----------------------------------------------------------------------------
3 // Copyright (C) 1993-1996 by id Software, Inc.
4 // Copyright (C) 1998-2000 by DooM Legacy Team.
5 // Copyright (C) 1999-2020 by Sonic Team Junior.
6 //
7 // This program is free software distributed under the
8 // terms of the GNU General Public License, version 2.
9 // See the 'LICENSE' file for more details.
10 //-----------------------------------------------------------------------------
11 /// \file  w_wad.c
12 /// \brief Handles WAD file header, directory, lump I/O
13 
14 #ifdef HAVE_ZLIB
15 #ifndef _MSC_VER
16 #ifndef _LARGEFILE64_SOURCE
17 #define _LARGEFILE64_SOURCE
18 #endif
19 #endif
20 
21 #ifndef _LFS64_LARGEFILE
22 #define _LFS64_LARGEFILE
23 #endif
24 
25 #ifndef _FILE_OFFSET_BITS
26 #define _FILE_OFFSET_BITS 0
27 #endif
28 
29 #include <zlib.h>
30 #endif
31 
32 #ifdef __GNUC__
33 #include <unistd.h>
34 #endif
35 
36 #define ZWAD
37 
38 #ifdef ZWAD
39 #include <errno.h>
40 #include "lzf.h"
41 #endif
42 
43 #include "doomdef.h"
44 #include "doomstat.h"
45 #include "doomtype.h"
46 
47 #include "w_wad.h"
48 #include "z_zone.h"
49 #include "fastcmp.h"
50 
51 #include "filesrch.h"
52 
53 #include "i_video.h" // rendermode
54 #include "d_netfil.h"
55 #include "dehacked.h"
56 #include "d_clisrv.h"
57 #include "r_defs.h"
58 #include "r_data.h"
59 #include "r_textures.h"
60 #include "r_patch.h"
61 #include "r_picformats.h"
62 #include "i_system.h"
63 #include "md5.h"
64 #include "lua_script.h"
65 #ifdef SCANTHINGS
66 #include "p_setup.h" // P_ScanThings
67 #endif
68 #include "m_misc.h" // M_MapNumber
69 #include "g_game.h" // G_SetGameModified
70 
71 #ifdef HWRENDER
72 #include "hardware/hw_main.h"
73 #include "hardware/hw_glob.h"
74 #endif
75 
76 #ifdef _DEBUG
77 #include "console.h"
78 #endif
79 
80 #ifndef O_BINARY
81 #define O_BINARY 0
82 #endif
83 
84 
85 typedef struct
86 {
87 	const char *name;
88 	size_t len;
89 } lumpchecklist_t;
90 
91 // Must be a power of two
92 #define LUMPNUMCACHESIZE 64
93 
94 typedef struct lumpnum_cache_s
95 {
96 	char lumpname[32];
97 	lumpnum_t lumpnum;
98 } lumpnum_cache_t;
99 
100 static lumpnum_cache_t lumpnumcache[LUMPNUMCACHESIZE];
101 static UINT16 lumpnumcacheindex = 0;
102 
103 //===========================================================================
104 //                                                                    GLOBALS
105 //===========================================================================
106 UINT16 numwadfiles; // number of active wadfiles
107 wadfile_t *wadfiles[MAX_WADFILES]; // 0 to numwadfiles-1 are valid
108 
109 // W_Shutdown
110 // Closes all of the WAD files before quitting
111 // If not done on a Mac then open wad files
112 // can prevent removable media they are on from
113 // being ejected
W_Shutdown(void)114 void W_Shutdown(void)
115 {
116 	while (numwadfiles--)
117 	{
118 		wadfile_t *wad = wadfiles[numwadfiles];
119 
120 		fclose(wad->handle);
121 		Z_Free(wad->filename);
122 		while (wad->numlumps--)
123 		{
124 			Z_Free(wad->lumpinfo[wad->numlumps].longname);
125 			Z_Free(wad->lumpinfo[wad->numlumps].fullname);
126 		}
127 
128 		Z_Free(wad->lumpinfo);
129 		Z_Free(wad);
130 	}
131 }
132 
133 //===========================================================================
134 //                                                        LUMP BASED ROUTINES
135 //===========================================================================
136 
137 // W_AddFile
138 // All files are optional, but at least one file must be
139 //  found (PWAD, if all required lumps are present).
140 // Files with a .wad extension are wadlink files
141 //  with multiple lumps.
142 // Other files are single lumps with the base filename
143 //  for the lump name.
144 
145 static char filenamebuf[MAX_WADPATH];
146 
147 // W_OpenWadFile
148 // Helper function for opening the WAD file.
149 // Returns the FILE * handle for the file, or NULL if not found or could not be opened
150 // If "useerrors" is true then print errors in the console, else just don't bother
151 // "filename" may be modified to have the correct path the actual file is located in, if necessary
W_OpenWadFile(const char ** filename,boolean useerrors)152 FILE *W_OpenWadFile(const char **filename, boolean useerrors)
153 {
154 	FILE *handle;
155 
156 	// Officially, strncpy should not have overlapping buffers, since W_VerifyNMUSlumps is called after this, and it
157 	// changes filename to point at filenamebuf, it would technically be doing that. I doubt any issue will occur since
158 	// they point to the same location, but it's better to be safe and this is a simple change.
159 	if (filenamebuf != *filename)
160 	{
161 		strncpy(filenamebuf, *filename, MAX_WADPATH);
162 		filenamebuf[MAX_WADPATH - 1] = '\0';
163 		*filename = filenamebuf;
164 	}
165 
166 	// open wad file
167 	if ((handle = fopen(*filename, "rb")) == NULL)
168 	{
169 		// If we failed to load the file with the path as specified by
170 		// the user, strip the directories and search for the file.
171 		nameonly(filenamebuf);
172 
173 		// If findfile finds the file, the full path will be returned
174 		// in filenamebuf == *filename.
175 		if (findfile(filenamebuf, NULL, true))
176 		{
177 			if ((handle = fopen(*filename, "rb")) == NULL)
178 			{
179 				if (useerrors)
180 					CONS_Alert(CONS_ERROR, M_GetText("Can't open %s\n"), *filename);
181 				return NULL;
182 			}
183 		}
184 		else
185 		{
186 			if (useerrors)
187 				CONS_Alert(CONS_ERROR, M_GetText("File %s not found.\n"), *filename);
188 			return NULL;
189 		}
190 	}
191 	return handle;
192 }
193 
194 // Look for all DEHACKED and Lua scripts inside a PK3 archive.
W_LoadDehackedLumpsPK3(UINT16 wadnum,boolean mainfile)195 static inline void W_LoadDehackedLumpsPK3(UINT16 wadnum, boolean mainfile)
196 {
197 	UINT16 posStart, posEnd;
198 
199 	posStart = W_CheckNumForFullNamePK3("Init.lua", wadnum, 0);
200 	if (posStart != INT16_MAX)
201 	{
202 		LUA_LoadLump(wadnum, posStart, true);
203 	}
204 	else
205 	{
206 		posStart = W_CheckNumForFolderStartPK3("Lua/", wadnum, 0);
207 		if (posStart != INT16_MAX)
208 		{
209 			posEnd = W_CheckNumForFolderEndPK3("Lua/", wadnum, posStart);
210 			for (; posStart < posEnd; posStart++)
211 				LUA_LoadLump(wadnum, posStart, true);
212 		}
213 	}
214 
215 	posStart = W_CheckNumForFolderStartPK3("SOC/", wadnum, 0);
216 	if (posStart != INT16_MAX)
217 	{
218 		posEnd = W_CheckNumForFolderEndPK3("SOC/", wadnum, posStart);
219 
220 		for(; posStart < posEnd; posStart++)
221 		{
222 			lumpinfo_t *lump_p = &wadfiles[wadnum]->lumpinfo[posStart];
223 			size_t length = strlen(wadfiles[wadnum]->filename) + 1 + strlen(lump_p->fullname); // length of file name, '|', and lump name
224 			char *name = malloc(length + 1);
225 			sprintf(name, "%s|%s", wadfiles[wadnum]->filename, lump_p->fullname);
226 			name[length] = '\0';
227 			CONS_Printf(M_GetText("Loading SOC from %s\n"), name);
228 			DEH_LoadDehackedLumpPwad(wadnum, posStart, mainfile);
229 			free(name);
230 		}
231 	}
232 }
233 
234 // search for all DEHACKED lump in all wads and load it
W_LoadDehackedLumps(UINT16 wadnum,boolean mainfile)235 static inline void W_LoadDehackedLumps(UINT16 wadnum, boolean mainfile)
236 {
237 	UINT16 lump;
238 
239 	// Find Lua scripts before SOCs to allow new A_Actions in SOC editing.
240 	{
241 		lumpinfo_t *lump_p = wadfiles[wadnum]->lumpinfo;
242 		for (lump = 0; lump < wadfiles[wadnum]->numlumps; lump++, lump_p++)
243 			if (memcmp(lump_p->name,"LUA_",4)==0)
244 				LUA_LoadLump(wadnum, lump, true);
245 	}
246 
247 	{
248 		lumpinfo_t *lump_p = wadfiles[wadnum]->lumpinfo;
249 		for (lump = 0; lump < wadfiles[wadnum]->numlumps; lump++, lump_p++)
250 			if (memcmp(lump_p->name,"SOC_",4)==0) // Check for generic SOC lump
251 			{	// shameless copy+paste of code from LUA_LoadLump
252 				size_t length = strlen(wadfiles[wadnum]->filename) + 1 + strlen(lump_p->fullname); // length of file name, '|', and lump name
253 				char *name = malloc(length + 1);
254 				sprintf(name, "%s|%s", wadfiles[wadnum]->filename, lump_p->fullname);
255 				name[length] = '\0';
256 
257 				CONS_Printf(M_GetText("Loading SOC from %s\n"), name);
258 				DEH_LoadDehackedLumpPwad(wadnum, lump, mainfile);
259 				free(name);
260 			}
261 			else if (memcmp(lump_p->name,"MAINCFG",8)==0) // Check for MAINCFG
262 			{
263 				CONS_Printf(M_GetText("Loading main config from %s\n"), wadfiles[wadnum]->filename);
264 				DEH_LoadDehackedLumpPwad(wadnum, lump, mainfile);
265 			}
266 			else if (memcmp(lump_p->name,"OBJCTCFG",8)==0) // Check for OBJCTCFG
267 			{
268 				CONS_Printf(M_GetText("Loading object config from %s\n"), wadfiles[wadnum]->filename);
269 				DEH_LoadDehackedLumpPwad(wadnum, lump, mainfile);
270 			}
271 	}
272 
273 #ifdef SCANTHINGS
274 	// Scan maps for emblems 'n shit
275 	{
276 		lumpinfo_t *lump_p = wadfiles[wadnum]->lumpinfo;
277 		for (lump = 0; lump < wadfiles[wadnum]->numlumps; lump++, lump_p++)
278 		{
279 			const char *name = lump_p->name;
280 			if (name[0] == 'M' && name[1] == 'A' && name[2] == 'P' && name[5]=='\0')
281 			{
282 				INT16 mapnum = (INT16)M_MapNumber(name[3], name[4]);
283 				P_ScanThings(mapnum, wadnum, lump + ML_THINGS);
284 			}
285 		}
286 	}
287 #endif
288 }
289 
290 /** Compute MD5 message digest for bytes read from STREAM of this filname.
291   *
292   * The resulting message digest number will be written into the 16 bytes
293   * beginning at RESBLOCK.
294   *
295   * \param filename path of file
296   * \param resblock resulting MD5 checksum
297   * \return 0 if MD5 checksum was made, and is at resblock, 1 if error was found
298   */
W_MakeFileMD5(const char * filename,void * resblock)299 static inline INT32 W_MakeFileMD5(const char *filename, void *resblock)
300 {
301 #ifdef NOMD5
302 	(void)filename;
303 	memset(resblock, 0x00, 16);
304 #else
305 	FILE *fhandle;
306 
307 	if ((fhandle = fopen(filename, "rb")) != NULL)
308 	{
309 		tic_t t = I_GetTime();
310 		CONS_Debug(DBG_SETUP, "Making MD5 for %s\n",filename);
311 		if (md5_stream(fhandle, resblock) == 1)
312 		{
313 			fclose(fhandle);
314 			return 1;
315 		}
316 		CONS_Debug(DBG_SETUP, "MD5 calc for %s took %f seconds\n",
317 			filename, (float)(I_GetTime() - t)/NEWTICRATE);
318 		fclose(fhandle);
319 		return 0;
320 	}
321 #endif
322 	return 1;
323 }
324 
325 // Invalidates the cache of lump numbers. Call this whenever a wad is added.
W_InvalidateLumpnumCache(void)326 static void W_InvalidateLumpnumCache(void)
327 {
328 	memset(lumpnumcache, 0, sizeof (lumpnumcache));
329 }
330 
331 /** Detect a file type.
332  * \todo Actually detect the wad/pkzip headers and whatnot, instead of just checking the extensions.
333  */
ResourceFileDetect(const char * filename)334 static restype_t ResourceFileDetect (const char* filename)
335 {
336 	if (!stricmp(&filename[strlen(filename) - 4], ".pk3"))
337 		return RET_PK3;
338 	if (!stricmp(&filename[strlen(filename) - 4], ".soc"))
339 		return RET_SOC;
340 	if (!stricmp(&filename[strlen(filename) - 4], ".lua"))
341 		return RET_LUA;
342 
343 	return RET_WAD;
344 }
345 
346 /** Create a 1-lump lumpinfo_t for standalone files.
347  */
ResGetLumpsStandalone(FILE * handle,UINT16 * numlumps,const char * lumpname)348 static lumpinfo_t* ResGetLumpsStandalone (FILE* handle, UINT16* numlumps, const char* lumpname)
349 {
350 	lumpinfo_t* lumpinfo = Z_Calloc(sizeof (*lumpinfo), PU_STATIC, NULL);
351 	lumpinfo->position = 0;
352 	fseek(handle, 0, SEEK_END);
353 	lumpinfo->size = ftell(handle);
354 	fseek(handle, 0, SEEK_SET);
355 	strcpy(lumpinfo->name, lumpname);
356 
357 	// Allocate the lump's long name.
358 	lumpinfo->longname = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL);
359 	strcpy(lumpinfo->longname, lumpname);
360 	lumpinfo->longname[8] = '\0';
361 
362 	// Allocate the lump's full name.
363 	lumpinfo->fullname = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL);
364 	strcpy(lumpinfo->fullname, lumpname);
365 	lumpinfo->fullname[8] = '\0';
366 
367 	*numlumps = 1;
368 	return lumpinfo;
369 }
370 
371 /** Create a lumpinfo_t array for a WAD file.
372  */
ResGetLumpsWad(FILE * handle,UINT16 * nlmp,const char * filename)373 static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filename)
374 {
375 	UINT16 numlumps = *nlmp;
376 	lumpinfo_t* lumpinfo;
377 	size_t i;
378 	INT32 compressed = 0;
379 
380 	wadinfo_t header;
381 	lumpinfo_t *lump_p;
382 	filelump_t *fileinfo;
383 	void *fileinfov;
384 
385 	// read the header
386 	if (fread(&header, 1, sizeof header, handle) < sizeof header)
387 	{
388 		CONS_Alert(CONS_ERROR, M_GetText("Can't read wad header because %s\n"), M_FileError(handle));
389 		return NULL;
390 	}
391 
392 	if (memcmp(header.identification, "ZWAD", 4) == 0)
393 		compressed = 1;
394 	else if (memcmp(header.identification, "IWAD", 4) != 0
395 		&& memcmp(header.identification, "PWAD", 4) != 0
396 		&& memcmp(header.identification, "SDLL", 4) != 0)
397 	{
398 		CONS_Alert(CONS_ERROR, M_GetText("Invalid WAD header\n"));
399 		return NULL;
400 	}
401 
402 	header.numlumps = LONG(header.numlumps);
403 	header.infotableofs = LONG(header.infotableofs);
404 
405 	// read wad file directory
406 	i = header.numlumps * sizeof (*fileinfo);
407 	fileinfov = fileinfo = malloc(i);
408 	if (fseek(handle, header.infotableofs, SEEK_SET) == -1
409 		|| fread(fileinfo, 1, i, handle) < i)
410 	{
411 		CONS_Alert(CONS_ERROR, M_GetText("Corrupt wadfile directory (%s)\n"), M_FileError(handle));
412 		free(fileinfov);
413 		return NULL;
414 	}
415 
416 	numlumps = header.numlumps;
417 
418 	// fill in lumpinfo for this wad
419 	lump_p = lumpinfo = Z_Malloc(numlumps * sizeof (*lumpinfo), PU_STATIC, NULL);
420 	for (i = 0; i < numlumps; i++, lump_p++, fileinfo++)
421 	{
422 		lump_p->position = LONG(fileinfo->filepos);
423 		lump_p->size = lump_p->disksize = LONG(fileinfo->size);
424 		if (compressed) // wad is compressed, lump might be
425 		{
426 			UINT32 realsize = 0;
427 			if (fseek(handle, lump_p->position, SEEK_SET)
428 				== -1 || fread(&realsize, 1, sizeof realsize,
429 				handle) < sizeof realsize)
430 			{
431 				I_Error("corrupt compressed file: %s; maybe %s", /// \todo Avoid the bailout?
432 					filename, M_FileError(handle));
433 			}
434 			realsize = LONG(realsize);
435 			if (realsize != 0)
436 			{
437 				lump_p->size = realsize;
438 				lump_p->compression = CM_LZF;
439 			}
440 			else
441 			{
442 				lump_p->size -= 4;
443 				lump_p->compression = CM_NOCOMPRESSION;
444 			}
445 
446 			lump_p->position += 4;
447 			lump_p->disksize -= 4;
448 		}
449 		else
450 			lump_p->compression = CM_NOCOMPRESSION;
451 		memset(lump_p->name, 0x00, 9);
452 		strncpy(lump_p->name, fileinfo->name, 8);
453 
454 		// Allocate the lump's long name.
455 		lump_p->longname = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL);
456 		strncpy(lump_p->longname, fileinfo->name, 8);
457 		lump_p->longname[8] = '\0';
458 
459 		// Allocate the lump's full name.
460 		lump_p->fullname = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL);
461 		strncpy(lump_p->fullname, fileinfo->name, 8);
462 		lump_p->fullname[8] = '\0';
463 	}
464 	free(fileinfov);
465 	*nlmp = numlumps;
466 	return lumpinfo;
467 }
468 
469 /** Optimized pattern search in a file.
470  */
ResFindSignature(FILE * handle,char endPat[],UINT32 startpos)471 static boolean ResFindSignature (FILE* handle, char endPat[], UINT32 startpos)
472 {
473 	char *s;
474 	int c;
475 
476 	fseek(handle, startpos, SEEK_SET);
477 	s = endPat;
478 	while((c = fgetc(handle)) != EOF)
479 	{
480 		if (*s != c && s > endPat) // No match?
481 			s = endPat; // We "reset" the counter by sending the s pointer back to the start of the array.
482 		if (*s == c)
483 		{
484 			s++;
485 			if (*s == 0x00) // The array pointer has reached the key char which marks the end. It means we have matched the signature.
486 			{
487 				return true;
488 			}
489 		}
490 	}
491 	return false;
492 }
493 
494 #if defined(_MSC_VER)
495 #pragma pack(1)
496 #endif
497 typedef struct zend_s
498 {
499 	char signature[4];
500 	UINT16 diskpos;
501 	UINT16 cdirdisk;
502 	UINT16 diskentries;
503 	UINT16 entries;
504 	UINT32 cdirsize;
505 	UINT32 cdiroffset;
506 	UINT16 commentlen;
507 } ATTRPACK zend_t;
508 
509 typedef struct zentry_s
510 {
511 	char signature[4];
512 	UINT16 version;
513 	UINT16 versionneeded;
514 	UINT16 flags;
515 	UINT16 compression;
516 	UINT16 modtime;
517 	UINT16 moddate;
518 	UINT32 CRC32;
519 	UINT32 compsize;
520 	UINT32 size;
521 	UINT16 namelen;
522 	UINT16 xtralen;
523 	UINT16 commlen;
524 	UINT16 diskstart;
525 	UINT16 attrint;
526 	UINT32 attrext;
527 	UINT32 offset;
528 } ATTRPACK zentry_t;
529 
530 typedef struct zlentry_s
531 {
532 	char signature[4];
533 	UINT16 versionneeded;
534 	UINT16 flags;
535 	UINT16 compression;
536 	UINT16 modtime;
537 	UINT16 moddate;
538 	UINT32 CRC32;
539 	UINT32 compsize;
540 	UINT32 size;
541 	UINT16 namelen;
542 	UINT16 xtralen;
543 } ATTRPACK zlentry_t;
544 #if defined(_MSC_VER)
545 #pragma pack()
546 #endif
547 
548 /** Create a lumpinfo_t array for a PKZip file.
549  */
ResGetLumpsZip(FILE * handle,UINT16 * nlmp)550 static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp)
551 {
552     zend_t zend;
553     zentry_t zentry;
554     zlentry_t zlentry;
555 
556 	UINT16 numlumps = *nlmp;
557 	lumpinfo_t* lumpinfo;
558 	lumpinfo_t *lump_p;
559 	size_t i;
560 
561 	char pat_central[] = {0x50, 0x4b, 0x01, 0x02, 0x00};
562 	char pat_end[] = {0x50, 0x4b, 0x05, 0x06, 0x00};
563 
564 	// Look for central directory end signature near end of file.
565 	// Contains entry number (number of lumps), and central directory start offset.
566 	fseek(handle, 0, SEEK_END);
567 	if (!ResFindSignature(handle, pat_end, max(0, ftell(handle) - (22 + 65536))))
568 	{
569 		CONS_Alert(CONS_ERROR, "Missing central directory\n");
570 		return NULL;
571 	}
572 
573 	fseek(handle, -4, SEEK_CUR);
574 	if (fread(&zend, 1, sizeof zend, handle) < sizeof zend)
575 	{
576 		CONS_Alert(CONS_ERROR, "Corrupt central directory (%s)\n", M_FileError(handle));
577 		return NULL;
578 	}
579 	numlumps = zend.entries;
580 
581 	lump_p = lumpinfo = Z_Malloc(numlumps * sizeof (*lumpinfo), PU_STATIC, NULL);
582 
583 	fseek(handle, zend.cdiroffset, SEEK_SET);
584 	for (i = 0; i < numlumps; i++, lump_p++)
585 	{
586 		char* fullname;
587 		char* trimname;
588 		char* dotpos;
589 
590 		if (fread(&zentry, 1, sizeof(zentry_t), handle) < sizeof(zentry_t))
591 		{
592 			CONS_Alert(CONS_ERROR, "Failed to read central directory (%s)\n", M_FileError(handle));
593 			Z_Free(lumpinfo);
594 			return NULL;
595 		}
596 		if (memcmp(zentry.signature, pat_central, 4))
597 		{
598 			CONS_Alert(CONS_ERROR, "Central directory is corrupt\n");
599 			Z_Free(lumpinfo);
600 			return NULL;
601 		}
602 
603 		lump_p->position = zentry.offset; // NOT ACCURATE YET: we still need to read the local entry to find our true position
604 		lump_p->disksize = zentry.compsize;
605 		lump_p->size = zentry.size;
606 
607 		fullname = malloc(zentry.namelen + 1);
608 		if (fgets(fullname, zentry.namelen + 1, handle) != fullname)
609 		{
610 			CONS_Alert(CONS_ERROR, "Unable to read lumpname (%s)\n", M_FileError(handle));
611 			Z_Free(lumpinfo);
612 			free(fullname);
613 			return NULL;
614 		}
615 
616 		// Strip away file address and extension for the 8char name.
617 		if ((trimname = strrchr(fullname, '/')) != 0)
618 			trimname++;
619 		else
620 			trimname = fullname; // Care taken for root files.
621 
622 		if ((dotpos = strrchr(trimname, '.')) == 0)
623 			dotpos = fullname + strlen(fullname); // Watch for files without extension.
624 
625 		memset(lump_p->name, '\0', 9); // Making sure they're initialized to 0. Is it necessary?
626 		strncpy(lump_p->name, trimname, min(8, dotpos - trimname));
627 
628 		lump_p->longname = Z_Calloc(dotpos - trimname + 1, PU_STATIC, NULL);
629 		strlcpy(lump_p->longname, trimname, dotpos - trimname + 1);
630 
631 		lump_p->fullname = Z_Calloc(zentry.namelen + 1, PU_STATIC, NULL);
632 		strncpy(lump_p->fullname, fullname, zentry.namelen);
633 
634 		free(fullname);
635 
636 		switch(zentry.compression)
637 		{
638 		case 0:
639 			lump_p->compression = CM_NOCOMPRESSION;
640 			break;
641 #ifdef HAVE_ZLIB
642 		case 8:
643 			lump_p->compression = CM_DEFLATE;
644 			break;
645 #endif
646 		case 14:
647 			lump_p->compression = CM_LZF;
648 			break;
649 		default:
650 			CONS_Alert(CONS_WARNING, "%s: Unsupported compression method\n", fullname);
651 			lump_p->compression = CM_UNSUPPORTED;
652 			break;
653 		}
654 
655 		// skip and ignore comments/extra fields
656 		if (fseek(handle, zentry.xtralen + zentry.commlen, SEEK_CUR) != 0)
657 		{
658 			CONS_Alert(CONS_ERROR, "Central directory is corrupt\n");
659 			Z_Free(lumpinfo);
660 			return NULL;
661 		}
662 	}
663 
664 	// Adjust lump position values properly
665 	for (i = 0, lump_p = lumpinfo; i < numlumps; i++, lump_p++)
666 	{
667 		// skip and ignore comments/extra fields
668 		if ((fseek(handle, lump_p->position, SEEK_SET) != 0) || (fread(&zlentry, 1, sizeof(zlentry_t), handle) < sizeof(zlentry_t)))
669 		{
670 			CONS_Alert(CONS_ERROR, "Local headers for lump %s are corrupt\n", lump_p->fullname);
671 			Z_Free(lumpinfo);
672 			return NULL;
673 		}
674 
675 		lump_p->position += sizeof(zlentry_t) + zlentry.namelen + zlentry.xtralen;
676 	}
677 
678 	*nlmp = numlumps;
679 	return lumpinfo;
680 }
681 
W_InitFileError(const char * filename,boolean exitworthy)682 static UINT16 W_InitFileError (const char *filename, boolean exitworthy)
683 {
684 	if (exitworthy)
685 	{
686 #ifdef _DEBUG
687 		CONS_Error(va("%s was not found or not valid.\nCheck the log for more details.\n", filename));
688 #else
689 		I_Error("%s was not found or not valid.\nCheck the log for more details.\n", filename);
690 #endif
691 	}
692 	else
693 		CONS_Printf(M_GetText("Errors occurred while loading %s; not added.\n"), filename);
694 	return INT16_MAX;
695 }
696 
697 //  Allocate a wadfile, setup the lumpinfo (directory) and
698 //  lumpcache, add the wadfile to the current active wadfiles
699 //
700 //  now returns index into wadfiles[], you can get wadfile_t *
701 //  with:
702 //       wadfiles[<return value>]
703 //
704 //  return -1 in case of problem
705 //
706 // Can now load dehacked files (.soc)
707 //
W_InitFile(const char * filename,boolean mainfile,boolean startup)708 UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
709 {
710 	FILE *handle;
711 	lumpinfo_t *lumpinfo = NULL;
712 	wadfile_t *wadfile;
713 	restype_t type;
714 	UINT16 numlumps = 0;
715 #ifndef NOMD5
716 	size_t i;
717 #endif
718 	size_t packetsize;
719 	UINT8 md5sum[16];
720 	int important;
721 
722 	if (!(refreshdirmenu & REFRESHDIR_ADDFILE))
723 		refreshdirmenu = REFRESHDIR_NORMAL|REFRESHDIR_ADDFILE; // clean out cons_alerts that happened earlier
724 
725 	if (refreshdirname)
726 		Z_Free(refreshdirname);
727 	if (dirmenu)
728 	{
729 		refreshdirname = Z_StrDup(filename);
730 		nameonly(refreshdirname);
731 	}
732 	else
733 		refreshdirname = NULL;
734 
735 	//CONS_Debug(DBG_SETUP, "Loading %s\n", filename);
736 	//
737 	// check if limit of active wadfiles
738 	//
739 	if (numwadfiles >= MAX_WADFILES)
740 	{
741 		CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n"));
742 		refreshdirmenu |= REFRESHDIR_MAX;
743 		return W_InitFileError(filename, startup);
744 	}
745 
746 	// open wad file
747 	if ((handle = W_OpenWadFile(&filename, true)) == NULL)
748 		return W_InitFileError(filename, startup);
749 
750 	important = W_VerifyNMUSlumps(filename, startup);
751 
752 	if (important == -1)
753 	{
754 		fclose(handle);
755 		return INT16_MAX;
756 	}
757 
758 	// Check if wad files will overflow fileneededbuffer. Only the filename part
759 	// is send in the packet; cf.
760 	// see PutFileNeeded in d_netfil.c
761 	if ((important = !important))
762 	{
763 		packetsize = packetsizetally + nameonlylength(filename) + 22;
764 
765 		if (packetsize > MAXFILENEEDED*sizeof(UINT8))
766 		{
767 			CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n"));
768 			refreshdirmenu |= REFRESHDIR_MAX;
769 			if (handle)
770 				fclose(handle);
771 			return W_InitFileError(filename, startup);
772 		}
773 
774 		packetsizetally = packetsize;
775 	}
776 
777 #ifndef NOMD5
778 	//
779 	// w-waiiiit!
780 	// Let's not add a wad file if the MD5 matches
781 	// an MD5 of an already added WAD file!
782 	//
783 	W_MakeFileMD5(filename, md5sum);
784 
785 	for (i = 0; i < numwadfiles; i++)
786 	{
787 		if (!memcmp(wadfiles[i]->md5sum, md5sum, 16))
788 		{
789 			CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), filename);
790 			if (important)
791 				packetsizetally -= nameonlylength(filename) + 22;
792 			if (handle)
793 				fclose(handle);
794 			return W_InitFileError(filename, false);
795 		}
796 	}
797 #endif
798 
799 	switch(type = ResourceFileDetect(filename))
800 	{
801 	case RET_SOC:
802 		lumpinfo = ResGetLumpsStandalone(handle, &numlumps, "OBJCTCFG");
803 		break;
804 	case RET_LUA:
805 		lumpinfo = ResGetLumpsStandalone(handle, &numlumps, "LUA_INIT");
806 		break;
807 	case RET_PK3:
808 		lumpinfo = ResGetLumpsZip(handle, &numlumps);
809 		break;
810 	case RET_WAD:
811 		lumpinfo = ResGetLumpsWad(handle, &numlumps, filename);
812 		break;
813 	default:
814 		CONS_Alert(CONS_ERROR, "Unsupported file format\n");
815 	}
816 
817 	if (lumpinfo == NULL)
818 	{
819 		fclose(handle);
820 		return W_InitFileError(filename, startup);
821 	}
822 
823 	if (important && !mainfile)
824 	{
825 		//G_SetGameModified(true);
826 		modifiedgame = true; // avoid savemoddata being set to false
827 	}
828 
829 	//
830 	// link wad file to search files
831 	//
832 	wadfile = Z_Malloc(sizeof (*wadfile), PU_STATIC, NULL);
833 	wadfile->filename = Z_StrDup(filename);
834 	wadfile->type = type;
835 	wadfile->handle = handle;
836 	wadfile->numlumps = (UINT16)numlumps;
837 	wadfile->lumpinfo = lumpinfo;
838 	wadfile->important = important;
839 	fseek(handle, 0, SEEK_END);
840 	wadfile->filesize = (unsigned)ftell(handle);
841 	wadfile->type = type;
842 
843 	// already generated, just copy it over
844 	M_Memcpy(&wadfile->md5sum, &md5sum, 16);
845 
846 	//
847 	// set up caching
848 	//
849 	Z_Calloc(numlumps * sizeof (*wadfile->lumpcache), PU_STATIC, &wadfile->lumpcache);
850 	Z_Calloc(numlumps * sizeof (*wadfile->patchcache), PU_STATIC, &wadfile->patchcache);
851 
852 	//
853 	// add the wadfile
854 	//
855 	CONS_Printf(M_GetText("Added file %s (%u lumps)\n"), filename, numlumps);
856 	wadfiles[numwadfiles] = wadfile;
857 	numwadfiles++; // must come BEFORE W_LoadDehackedLumps, so any addfile called by COM_BufInsertText called by Lua doesn't overwrite what we just loaded
858 
859 #ifdef HWRENDER
860 	// Read shaders from file
861 	if (rendermode == render_opengl && (vid.glstate == VID_GL_LIBRARY_LOADED))
862 	{
863 		HWR_LoadCustomShadersFromFile(numwadfiles - 1, (type == RET_PK3));
864 		HWR_CompileShaders();
865 	}
866 #endif // HWRENDER
867 
868 	// TODO: HACK ALERT - Load Lua & SOC stuff right here. I feel like this should be out of this place, but... Let's stick with this for now.
869 	switch (wadfile->type)
870 	{
871 	case RET_WAD:
872 		W_LoadDehackedLumps(numwadfiles - 1, mainfile);
873 		break;
874 	case RET_PK3:
875 		W_LoadDehackedLumpsPK3(numwadfiles - 1, mainfile);
876 		break;
877 	case RET_SOC:
878 		CONS_Printf(M_GetText("Loading SOC from %s\n"), wadfile->filename);
879 		DEH_LoadDehackedLumpPwad(numwadfiles - 1, 0, mainfile);
880 		break;
881 	case RET_LUA:
882 		LUA_LoadLump(numwadfiles - 1, 0, true);
883 		break;
884 	default:
885 		break;
886 	}
887 
888 	W_InvalidateLumpnumCache();
889 	return wadfile->numlumps;
890 }
891 
892 /** Tries to load a series of files.
893   * All files are wads unless they have an extension of ".soc" or ".lua".
894   *
895   * Each file is optional, but at least one file must be found or an error will
896   * result. Lump names can appear multiple times. The name searcher looks
897   * backwards, so a later file overrides all earlier ones.
898   *
899   * \param filenames A null-terminated list of files to use.
900   */
W_InitMultipleFiles(char ** filenames)901 void W_InitMultipleFiles(char **filenames)
902 {
903 	// will be realloced as lumps are added
904 	for (; *filenames; filenames++)
905 	{
906 		//CONS_Debug(DBG_SETUP, "Loading %s\n", *filenames);
907 		W_InitFile(*filenames, numwadfiles < mainwads, true);
908 	}
909 }
910 
911 /** Make sure a lump number is valid.
912   * Compiles away to nothing if PARANOIA is not defined.
913   */
TestValidLump(UINT16 wad,UINT16 lump)914 static boolean TestValidLump(UINT16 wad, UINT16 lump)
915 {
916 	I_Assert(wad < MAX_WADFILES);
917 	if (!wadfiles[wad]) // make sure the wad file exists
918 		return false;
919 
920 	I_Assert(lump < wadfiles[wad]->numlumps);
921 	if (lump >= wadfiles[wad]->numlumps) // make sure the lump exists
922 		return false;
923 
924 	return true;
925 }
926 
927 
W_CheckNameForNumPwad(UINT16 wad,UINT16 lump)928 const char *W_CheckNameForNumPwad(UINT16 wad, UINT16 lump)
929 {
930 	if (lump >= wadfiles[wad]->numlumps || !TestValidLump(wad, 0))
931 		return NULL;
932 
933 	return wadfiles[wad]->lumpinfo[lump].name;
934 }
935 
W_CheckNameForNum(lumpnum_t lumpnum)936 const char *W_CheckNameForNum(lumpnum_t lumpnum)
937 {
938 	return W_CheckNameForNumPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum));
939 }
940 
941 //
942 // Same as the original, but checks in one pwad only.
943 // wadid is a wad number
944 // (Used for sprites loading)
945 //
946 // 'startlump' is the lump number to start the search
947 //
W_CheckNumForNamePwad(const char * name,UINT16 wad,UINT16 startlump)948 UINT16 W_CheckNumForNamePwad(const char *name, UINT16 wad, UINT16 startlump)
949 {
950 	UINT16 i;
951 	static char uname[8 + 1];
952 
953 	if (!TestValidLump(wad,0))
954 		return INT16_MAX;
955 
956 	strlcpy(uname, name, sizeof uname);
957 	strupr(uname);
958 
959 	//
960 	// scan forward
961 	// start at 'startlump', useful parameter when there are multiple
962 	//                       resources with the same name
963 	//
964 	if (startlump < wadfiles[wad]->numlumps)
965 	{
966 		lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump;
967 		for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++)
968 			if (!strncmp(lump_p->name, uname, sizeof(uname) - 1))
969 				return i;
970 	}
971 
972 	// not found.
973 	return INT16_MAX;
974 }
975 
976 //
977 // Like W_CheckNumForNamePwad, but can find entries with long names
978 //
979 // Should be the only version, but that's not possible until we fix
980 // all the instances of non null-terminated strings in the codebase...
981 //
W_CheckNumForLongNamePwad(const char * name,UINT16 wad,UINT16 startlump)982 UINT16 W_CheckNumForLongNamePwad(const char *name, UINT16 wad, UINT16 startlump)
983 {
984 	UINT16 i;
985 	static char uname[256 + 1];
986 
987 	if (!TestValidLump(wad,0))
988 		return INT16_MAX;
989 
990 	strlcpy(uname, name, sizeof uname);
991 	strupr(uname);
992 
993 	//
994 	// scan forward
995 	// start at 'startlump', useful parameter when there are multiple
996 	//                       resources with the same name
997 	//
998 	if (startlump < wadfiles[wad]->numlumps)
999 	{
1000 		lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump;
1001 		for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++)
1002 			if (!strcmp(lump_p->longname, uname))
1003 				return i;
1004 	}
1005 
1006 	// not found.
1007 	return INT16_MAX;
1008 }
1009 
1010 UINT16
W_CheckNumForMarkerStartPwad(const char * name,UINT16 wad,UINT16 startlump)1011 W_CheckNumForMarkerStartPwad (const char *name, UINT16 wad, UINT16 startlump)
1012 {
1013 	UINT16 marker;
1014 	marker = W_CheckNumForNamePwad(name, wad, startlump);
1015 	if (marker != INT16_MAX)
1016 		marker++; // Do not count the first marker
1017 	return marker;
1018 }
1019 
1020 // Look for the first lump from a folder.
W_CheckNumForFolderStartPK3(const char * name,UINT16 wad,UINT16 startlump)1021 UINT16 W_CheckNumForFolderStartPK3(const char *name, UINT16 wad, UINT16 startlump)
1022 {
1023 	size_t name_length;
1024 	INT32 i;
1025 	lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump;
1026 	name_length = strlen(name);
1027 	for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++)
1028 	{
1029 		if (strnicmp(name, lump_p->fullname, name_length) == 0)
1030 		{
1031 			/* SLADE is special and puts a single directory entry. Skip that. */
1032 			if (strlen(lump_p->fullname) == name_length)
1033 				i++;
1034 			break;
1035 		}
1036 	}
1037 	return i;
1038 }
1039 
1040 // In a PK3 type of resource file, it looks for the next lumpinfo entry that doesn't share the specified pathfile.
1041 // Useful for finding folder ends.
1042 // Returns the position of the lumpinfo entry.
W_CheckNumForFolderEndPK3(const char * name,UINT16 wad,UINT16 startlump)1043 UINT16 W_CheckNumForFolderEndPK3(const char *name, UINT16 wad, UINT16 startlump)
1044 {
1045 	INT32 i;
1046 	lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump;
1047 	for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++)
1048 	{
1049 		if (strnicmp(name, lump_p->fullname, strlen(name)))
1050 			break;
1051 	}
1052 	return i;
1053 }
1054 
1055 // In a PK3 type of resource file, it looks for an entry with the specified full name.
1056 // Returns lump position in PK3's lumpinfo, or INT16_MAX if not found.
W_CheckNumForFullNamePK3(const char * name,UINT16 wad,UINT16 startlump)1057 UINT16 W_CheckNumForFullNamePK3(const char *name, UINT16 wad, UINT16 startlump)
1058 {
1059 	INT32 i;
1060 	lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump;
1061 	for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++)
1062 	{
1063 		if (!strnicmp(name, lump_p->fullname, strlen(name)))
1064 		{
1065 			return i;
1066 		}
1067 	}
1068 	// Not found at all?
1069 	return INT16_MAX;
1070 }
1071 
1072 //
1073 // W_CheckNumForName
1074 // Returns LUMPERROR if name not found.
1075 //
W_CheckNumForName(const char * name)1076 lumpnum_t W_CheckNumForName(const char *name)
1077 {
1078 	INT32 i;
1079 	lumpnum_t check = INT16_MAX;
1080 
1081 	if (!*name) // some doofus gave us an empty string?
1082 		return LUMPERROR;
1083 
1084 	// Check the lumpnumcache first. Loop backwards so that we check
1085 	// most recent entries first
1086 	for (i = lumpnumcacheindex + LUMPNUMCACHESIZE; i > lumpnumcacheindex; i--)
1087 	{
1088 		if (!lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname[8]
1089 			&& strncmp(lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname, name, 8) == 0)
1090 		{
1091 			lumpnumcacheindex = i & (LUMPNUMCACHESIZE - 1);
1092 			return lumpnumcache[lumpnumcacheindex].lumpnum;
1093 		}
1094 	}
1095 
1096 	// scan wad files backwards so patch lump files take precedence
1097 	for (i = numwadfiles - 1; i >= 0; i--)
1098 	{
1099 		check = W_CheckNumForNamePwad(name,(UINT16)i,0);
1100 		if (check != INT16_MAX)
1101 			break; //found it
1102 	}
1103 
1104 	if (check == INT16_MAX) return LUMPERROR;
1105 	else
1106 	{
1107 		// Update the cache.
1108 		lumpnumcacheindex = (lumpnumcacheindex + 1) & (LUMPNUMCACHESIZE - 1);
1109 		memset(lumpnumcache[lumpnumcacheindex].lumpname, '\0', 32);
1110 		strncpy(lumpnumcache[lumpnumcacheindex].lumpname, name, 8);
1111 		lumpnumcache[lumpnumcacheindex].lumpnum = (i<<16)+check;
1112 
1113 		return lumpnumcache[lumpnumcacheindex].lumpnum;
1114 	}
1115 }
1116 
1117 //
1118 // Like W_CheckNumForName, but can find entries with long names
1119 //
1120 // Should be the only version, but that's not possible until we fix
1121 // all the instances of non null-terminated strings in the codebase...
1122 //
W_CheckNumForLongName(const char * name)1123 lumpnum_t W_CheckNumForLongName(const char *name)
1124 {
1125 	INT32 i;
1126 	lumpnum_t check = INT16_MAX;
1127 
1128 	if (!*name) // some doofus gave us an empty string?
1129 		return LUMPERROR;
1130 
1131 	// Check the lumpnumcache first. Loop backwards so that we check
1132 	// most recent entries first
1133 	for (i = lumpnumcacheindex + LUMPNUMCACHESIZE; i > lumpnumcacheindex; i--)
1134 	{
1135 		if (strcmp(lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname, name) == 0)
1136 		{
1137 			lumpnumcacheindex = i & (LUMPNUMCACHESIZE - 1);
1138 			return lumpnumcache[lumpnumcacheindex].lumpnum;
1139 		}
1140 	}
1141 
1142 	// scan wad files backwards so patch lump files take precedence
1143 	for (i = numwadfiles - 1; i >= 0; i--)
1144 	{
1145 		check = W_CheckNumForLongNamePwad(name,(UINT16)i,0);
1146 		if (check != INT16_MAX)
1147 			break; //found it
1148 	}
1149 
1150 	if (check == INT16_MAX) return LUMPERROR;
1151 	else
1152 	{
1153 		if (strlen(name) < 32)
1154 		{
1155 			// Update the cache.
1156 			lumpnumcacheindex = (lumpnumcacheindex + 1) & (LUMPNUMCACHESIZE - 1);
1157 			memset(lumpnumcache[lumpnumcacheindex].lumpname, '\0', 32);
1158 			strlcpy(lumpnumcache[lumpnumcacheindex].lumpname, name, 32);
1159 			lumpnumcache[lumpnumcacheindex].lumpnum = (i << 16) + check;
1160 		}
1161 
1162 		return (i << 16) + check;
1163 	}
1164 }
1165 
1166 // Look for valid map data through all added files in descendant order.
1167 // Get a map marker for WADs, and a standalone WAD file lump inside PK3s.
1168 // TODO: Make it search through cache first, maybe...?
W_CheckNumForMap(const char * name)1169 lumpnum_t W_CheckNumForMap(const char *name)
1170 {
1171 	UINT16 lumpNum, end;
1172 	UINT32 i;
1173 	for (i = numwadfiles - 1; i < numwadfiles; i--)
1174 	{
1175 		if (wadfiles[i]->type == RET_WAD)
1176 		{
1177 			for (lumpNum = 0; lumpNum < wadfiles[i]->numlumps; lumpNum++)
1178 				if (!strncmp(name, (wadfiles[i]->lumpinfo + lumpNum)->name, 8))
1179 					return (i<<16) + lumpNum;
1180 		}
1181 		else if (wadfiles[i]->type == RET_PK3)
1182 		{
1183 			lumpNum = W_CheckNumForFolderStartPK3("maps/", i, 0);
1184 			if (lumpNum != INT16_MAX)
1185 				end = W_CheckNumForFolderEndPK3("maps/", i, lumpNum);
1186 			else
1187 				continue;
1188 			// Now look for the specified map.
1189 			for (; lumpNum < end; lumpNum++)
1190 				if (!strnicmp(name, (wadfiles[i]->lumpinfo + lumpNum)->name, 8))
1191 					return (i<<16) + lumpNum;
1192 		}
1193 	}
1194 	return LUMPERROR;
1195 }
1196 
1197 //
1198 // W_GetNumForName
1199 //
1200 // Calls W_CheckNumForName, but bombs out if not found.
1201 //
W_GetNumForName(const char * name)1202 lumpnum_t W_GetNumForName(const char *name)
1203 {
1204 	lumpnum_t i;
1205 
1206 	i = W_CheckNumForName(name);
1207 
1208 	if (i == LUMPERROR)
1209 		I_Error("W_GetNumForName: %s not found!\n", name);
1210 
1211 	return i;
1212 }
1213 
1214 //
1215 // Like W_GetNumForName, but can find entries with long names
1216 //
1217 // Should be the only version, but that's not possible until we fix
1218 // all the instances of non null-terminated strings in the codebase...
1219 //
W_GetNumForLongName(const char * name)1220 lumpnum_t W_GetNumForLongName(const char *name)
1221 {
1222 	lumpnum_t i;
1223 
1224 	i = W_CheckNumForLongName(name);
1225 
1226 	if (i == LUMPERROR)
1227 		I_Error("W_GetNumForLongName: %s not found!\n", name);
1228 
1229 	return i;
1230 }
1231 
1232 //
1233 // W_CheckNumForNameInBlock
1234 // Checks only in blocks from blockstart lump to blockend lump
1235 //
W_CheckNumForNameInBlock(const char * name,const char * blockstart,const char * blockend)1236 lumpnum_t W_CheckNumForNameInBlock(const char *name, const char *blockstart, const char *blockend)
1237 {
1238 	INT32 i;
1239 	lumpnum_t bsid, beid;
1240 	lumpnum_t check = INT16_MAX;
1241 
1242 	// scan wad files backwards so patch lump files take precedence
1243 	for (i = numwadfiles - 1; i >= 0; i--)
1244 	{
1245 		if (wadfiles[i]->type == RET_WAD)
1246 		{
1247 			bsid = W_CheckNumForNamePwad(blockstart, (UINT16)i, 0);
1248 			if (bsid == INT16_MAX)
1249 				continue; // Start block doesn't exist?
1250 			beid = W_CheckNumForNamePwad(blockend, (UINT16)i, 0);
1251 			if (beid == INT16_MAX)
1252 				continue; // End block doesn't exist?
1253 
1254 			check = W_CheckNumForNamePwad(name, (UINT16)i, bsid);
1255 			if (check < beid)
1256 				return (i<<16)+check; // found it, in our constraints
1257 		}
1258 	}
1259 	return LUMPERROR;
1260 }
1261 
1262 // Used by Lua. Case sensitive lump checking, quickly...
1263 #include "fastcmp.h"
W_LumpExists(const char * name)1264 UINT8 W_LumpExists(const char *name)
1265 {
1266 	INT32 i,j;
1267 	for (i = numwadfiles - 1; i >= 0; i--)
1268 	{
1269 		lumpinfo_t *lump_p = wadfiles[i]->lumpinfo;
1270 		for (j = 0; j < wadfiles[i]->numlumps; ++j, ++lump_p)
1271 			if (fastcmp(lump_p->longname, name))
1272 				return true;
1273 	}
1274 	return false;
1275 }
1276 
W_LumpLengthPwad(UINT16 wad,UINT16 lump)1277 size_t W_LumpLengthPwad(UINT16 wad, UINT16 lump)
1278 {
1279 	if (!TestValidLump(wad, lump))
1280 		return 0;
1281 	return wadfiles[wad]->lumpinfo[lump].size;
1282 }
1283 
1284 /** Returns the buffer size needed to load the given lump.
1285   *
1286   * \param lump Lump number to look at.
1287   * \return Buffer size needed, in bytes.
1288   */
W_LumpLength(lumpnum_t lumpnum)1289 size_t W_LumpLength(lumpnum_t lumpnum)
1290 {
1291 	return W_LumpLengthPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum));
1292 }
1293 
1294 //
1295 // W_IsLumpWad
1296 // Is the lump a WAD? (presumably in a PK3)
1297 //
W_IsLumpWad(lumpnum_t lumpnum)1298 boolean W_IsLumpWad(lumpnum_t lumpnum)
1299 {
1300 	if (wadfiles[WADFILENUM(lumpnum)]->type == RET_PK3)
1301 	{
1302 		const char *lumpfullName = (wadfiles[WADFILENUM(lumpnum)]->lumpinfo + LUMPNUM(lumpnum))->fullname;
1303 
1304 		if (strlen(lumpfullName) < 4)
1305 			return false; // can't possibly be a WAD can it?
1306 		return !strnicmp(lumpfullName + strlen(lumpfullName) - 4, ".wad", 4);
1307 	}
1308 
1309 	return false; // WADs should never be inside non-PK3s as far as SRB2 is concerned
1310 }
1311 
1312 //
1313 // W_IsLumpFolder
1314 // Is the lump a folder? (in a PK3 obviously)
1315 //
W_IsLumpFolder(UINT16 wad,UINT16 lump)1316 boolean W_IsLumpFolder(UINT16 wad, UINT16 lump)
1317 {
1318 	if (wadfiles[wad]->type == RET_PK3)
1319 	{
1320 		const char *name = wadfiles[wad]->lumpinfo[lump].fullname;
1321 
1322 		return (name[strlen(name)-1] == '/'); // folders end in '/'
1323 	}
1324 
1325 	return false; // non-PK3s don't have folders
1326 }
1327 
1328 #ifdef HAVE_ZLIB
1329 /* report a zlib or i/o error */
zerr(int ret)1330 void zerr(int ret)
1331 {
1332     CONS_Printf("zpipe: ");
1333     switch (ret) {
1334     case Z_ERRNO:
1335         if (ferror(stdin))
1336             CONS_Printf("error reading stdin\n");
1337         if (ferror(stdout))
1338             CONS_Printf("error writing stdout\n");
1339         break;
1340     case Z_STREAM_ERROR:
1341         CONS_Printf("invalid compression level\n");
1342         break;
1343     case Z_DATA_ERROR:
1344         CONS_Printf("invalid or incomplete deflate data\n");
1345         break;
1346     case Z_MEM_ERROR:
1347         CONS_Printf("out of memory\n");
1348         break;
1349     case Z_VERSION_ERROR:
1350         CONS_Printf("zlib version mismatch!\n");
1351     }
1352 }
1353 #endif
1354 
1355 /** Reads bytes from the head of a lump.
1356   * Note: If the lump is compressed, the whole thing has to be read anyway.
1357   *
1358   * \param wad Wad number to read from.
1359   * \param lump Lump number to read from.
1360   * \param dest Buffer in memory to serve as destination.
1361   * \param size Number of bytes to read.
1362   * \param offest Number of bytes to offset.
1363   * \return Number of bytes read (should equal size).
1364   * \sa W_ReadLump, W_RawReadLumpHeader
1365   */
W_ReadLumpHeaderPwad(UINT16 wad,UINT16 lump,void * dest,size_t size,size_t offset)1366 size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, size_t offset)
1367 {
1368 	size_t lumpsize;
1369 	lumpinfo_t *l;
1370 	FILE *handle;
1371 
1372 	if (!TestValidLump(wad,lump))
1373 		return 0;
1374 
1375 	lumpsize = wadfiles[wad]->lumpinfo[lump].size;
1376 	// empty resource (usually markers like S_START, F_END ..)
1377 	if (!lumpsize || lumpsize<offset)
1378 		return 0;
1379 
1380 	// zero size means read all the lump
1381 	if (!size || size+offset > lumpsize)
1382 		size = lumpsize - offset;
1383 
1384 	// Let's get the raw lump data.
1385 	// We setup the desired file handle to read the lump data.
1386 	l = wadfiles[wad]->lumpinfo + lump;
1387 	handle = wadfiles[wad]->handle;
1388 	fseek(handle, (long)(l->position + offset), SEEK_SET);
1389 
1390 	// But let's not copy it yet. We support different compression formats on lumps, so we need to take that into account.
1391 	switch(wadfiles[wad]->lumpinfo[lump].compression)
1392 	{
1393 	case CM_NOCOMPRESSION:		// If it's uncompressed, we directly write the data into our destination, and return the bytes read.
1394 #ifdef NO_PNG_LUMPS
1395 		{
1396 			size_t bytesread = fread(dest, 1, size, handle);
1397 			if (Picture_IsLumpPNG((UINT8 *)dest, bytesread))
1398 				Picture_ThrowPNGError(l->fullname, wadfiles[wad]->filename);
1399 			return bytesread;
1400 		}
1401 #else
1402 		return fread(dest, 1, size, handle);
1403 #endif
1404 	case CM_LZF:		// Is it LZF compressed? Used by ZWADs.
1405 		{
1406 #ifdef ZWAD
1407 			char *rawData; // The lump's raw data.
1408 			char *decData; // Lump's decompressed real data.
1409 			size_t retval; // Helper var, lzf_decompress returns 0 when an error occurs.
1410 
1411 			rawData = Z_Malloc(l->disksize, PU_STATIC, NULL);
1412 			decData = Z_Malloc(l->size, PU_STATIC, NULL);
1413 
1414 			if (fread(rawData, 1, l->disksize, handle) < l->disksize)
1415 				I_Error("wad %d, lump %d: cannot read compressed data", wad, lump);
1416 			retval = lzf_decompress(rawData, l->disksize, decData, l->size);
1417 #ifndef AVOID_ERRNO
1418 			if (retval == 0) // If this was returned, check if errno was set
1419 			{
1420 				// errno is a global var set by the lzf functions when something goes wrong.
1421 				if (errno == E2BIG)
1422 					I_Error("wad %d, lump %d: compressed data too big (bigger than %s)", wad, lump, sizeu1(l->size));
1423 				else if (errno == EINVAL)
1424 					I_Error("wad %d, lump %d: invalid compressed data", wad, lump);
1425 			}
1426 			// Otherwise, fall back on below error (if zero was actually the correct size then ???)
1427 #endif
1428 			if (retval != l->size)
1429 			{
1430 				I_Error("wad %d, lump %d: decompressed to wrong number of bytes (expected %s, got %s)", wad, lump, sizeu1(l->size), sizeu2(retval));
1431 			}
1432 
1433 			if (!decData) // Did we get no data at all?
1434 				return 0;
1435 			M_Memcpy(dest, decData + offset, size);
1436 			Z_Free(rawData);
1437 			Z_Free(decData);
1438 #ifdef NO_PNG_LUMPS
1439 			if (Picture_IsLumpPNG((UINT8 *)dest, size))
1440 				Picture_ThrowPNGError(l->fullname, wadfiles[wad]->filename);
1441 #endif
1442 			return size;
1443 #else
1444 			//I_Error("ZWAD files not supported on this platform.");
1445 			return 0;
1446 #endif
1447 
1448 		}
1449 #ifdef HAVE_ZLIB
1450 	case CM_DEFLATE: // Is it compressed via DEFLATE? Very common in ZIPs/PK3s, also what most doom-related editors support.
1451 		{
1452 			UINT8 *rawData; // The lump's raw data.
1453 			UINT8 *decData; // Lump's decompressed real data.
1454 
1455 			int zErr; // Helper var.
1456 			z_stream strm;
1457 			unsigned long rawSize = l->disksize;
1458 			unsigned long decSize = l->size;
1459 
1460 			rawData = Z_Malloc(rawSize, PU_STATIC, NULL);
1461 			decData = Z_Malloc(decSize, PU_STATIC, NULL);
1462 
1463 			if (fread(rawData, 1, rawSize, handle) < rawSize)
1464 				I_Error("wad %d, lump %d: cannot read compressed data", wad, lump);
1465 
1466 			strm.zalloc = Z_NULL;
1467 			strm.zfree = Z_NULL;
1468 			strm.opaque = Z_NULL;
1469 
1470 			strm.total_in = strm.avail_in = rawSize;
1471 			strm.total_out = strm.avail_out = decSize;
1472 
1473 			strm.next_in = rawData;
1474 			strm.next_out = decData;
1475 
1476 			zErr = inflateInit2(&strm, -15);
1477 			if (zErr == Z_OK)
1478 			{
1479 				zErr = inflate(&strm, Z_FINISH);
1480 				if (zErr == Z_STREAM_END)
1481 				{
1482 					M_Memcpy(dest, decData, size);
1483 				}
1484 				else
1485 				{
1486 					size = 0;
1487 					zerr(zErr);
1488 				}
1489 
1490 				(void)inflateEnd(&strm);
1491 			}
1492 			else
1493 			{
1494 				size = 0;
1495 				zerr(zErr);
1496 			}
1497 
1498 			Z_Free(rawData);
1499 			Z_Free(decData);
1500 
1501 #ifdef NO_PNG_LUMPS
1502 			if (Picture_IsLumpPNG((UINT8 *)dest, size))
1503 				Picture_ThrowPNGError(l->fullname, wadfiles[wad]->filename);
1504 #endif
1505 			return size;
1506 		}
1507 #endif
1508 	default:
1509 		I_Error("wad %d, lump %d: unsupported compression type!", wad, lump);
1510 	}
1511 	return 0;
1512 }
1513 
W_ReadLumpHeader(lumpnum_t lumpnum,void * dest,size_t size,size_t offset)1514 size_t W_ReadLumpHeader(lumpnum_t lumpnum, void *dest, size_t size, size_t offset)
1515 {
1516 	return W_ReadLumpHeaderPwad(WADFILENUM(lumpnum), LUMPNUM(lumpnum), dest, size, offset);
1517 }
1518 
1519 /** Reads a lump into memory.
1520   *
1521   * \param lump Lump number to read from.
1522   * \param dest Buffer in memory to serve as destination. Size must be >=
1523   *             W_LumpLength().
1524   * \sa W_ReadLumpHeader
1525   */
W_ReadLump(lumpnum_t lumpnum,void * dest)1526 void W_ReadLump(lumpnum_t lumpnum, void *dest)
1527 {
1528 	W_ReadLumpHeaderPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum),dest,0,0);
1529 }
1530 
W_ReadLumpPwad(UINT16 wad,UINT16 lump,void * dest)1531 void W_ReadLumpPwad(UINT16 wad, UINT16 lump, void *dest)
1532 {
1533 	W_ReadLumpHeaderPwad(wad, lump, dest, 0, 0);
1534 }
1535 
1536 // ==========================================================================
1537 // W_CacheLumpNum
1538 // ==========================================================================
W_CacheLumpNumPwad(UINT16 wad,UINT16 lump,INT32 tag)1539 void *W_CacheLumpNumPwad(UINT16 wad, UINT16 lump, INT32 tag)
1540 {
1541 	lumpcache_t *lumpcache;
1542 
1543 	if (!TestValidLump(wad,lump))
1544 		return NULL;
1545 
1546 	lumpcache = wadfiles[wad]->lumpcache;
1547 	if (!lumpcache[lump])
1548 	{
1549 		void *ptr = Z_Malloc(W_LumpLengthPwad(wad, lump), tag, &lumpcache[lump]);
1550 		W_ReadLumpHeaderPwad(wad, lump, ptr, 0, 0);  // read the lump in full
1551 	}
1552 	else
1553 		Z_ChangeTag(lumpcache[lump], tag);
1554 
1555 	return lumpcache[lump];
1556 }
1557 
W_CacheLumpNum(lumpnum_t lumpnum,INT32 tag)1558 void *W_CacheLumpNum(lumpnum_t lumpnum, INT32 tag)
1559 {
1560 	return W_CacheLumpNumPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum),tag);
1561 }
1562 
1563 //
1564 // W_CacheLumpNumForce
1565 //
1566 // Forces the lump to be loaded, even if it already is!
1567 //
W_CacheLumpNumForce(lumpnum_t lumpnum,INT32 tag)1568 void *W_CacheLumpNumForce(lumpnum_t lumpnum, INT32 tag)
1569 {
1570 	UINT16 wad, lump;
1571 	void *ptr;
1572 
1573 	wad = WADFILENUM(lumpnum);
1574 	lump = LUMPNUM(lumpnum);
1575 
1576 	if (!TestValidLump(wad,lump))
1577 		return NULL;
1578 
1579 	ptr = Z_Malloc(W_LumpLengthPwad(wad, lump), tag, NULL);
1580 	W_ReadLumpHeaderPwad(wad, lump, ptr, 0, 0);  // read the lump in full
1581 
1582 	return ptr;
1583 }
1584 
1585 //
1586 // W_IsLumpCached
1587 //
1588 // If a lump is already cached return true, otherwise
1589 // return false.
1590 //
1591 // no outside code uses the PWAD form, for now
W_IsLumpCachedPWAD(UINT16 wad,UINT16 lump,void * ptr)1592 static inline boolean W_IsLumpCachedPWAD(UINT16 wad, UINT16 lump, void *ptr)
1593 {
1594 	void *lcache;
1595 
1596 	if (!TestValidLump(wad, lump))
1597 		return false;
1598 
1599 	lcache = wadfiles[wad]->lumpcache[lump];
1600 
1601 	if (ptr)
1602 	{
1603 		if (ptr == lcache)
1604 			return true;
1605 	}
1606 	else if (lcache)
1607 		return true;
1608 
1609 	return false;
1610 }
1611 
W_IsLumpCached(lumpnum_t lumpnum,void * ptr)1612 boolean W_IsLumpCached(lumpnum_t lumpnum, void *ptr)
1613 {
1614 	return W_IsLumpCachedPWAD(WADFILENUM(lumpnum),LUMPNUM(lumpnum), ptr);
1615 }
1616 
1617 //
1618 // W_IsPatchCached
1619 //
1620 // If a patch is already cached return true, otherwise
1621 // return false.
1622 //
1623 // no outside code uses the PWAD form, for now
W_IsPatchCachedPWAD(UINT16 wad,UINT16 lump,void * ptr)1624 static inline boolean W_IsPatchCachedPWAD(UINT16 wad, UINT16 lump, void *ptr)
1625 {
1626 	void *lcache;
1627 
1628 	if (!TestValidLump(wad, lump))
1629 		return false;
1630 
1631 	lcache = wadfiles[wad]->patchcache[lump];
1632 
1633 	if (ptr)
1634 	{
1635 		if (ptr == lcache)
1636 			return true;
1637 	}
1638 	else if (lcache)
1639 		return true;
1640 
1641 	return false;
1642 }
1643 
W_IsPatchCached(lumpnum_t lumpnum,void * ptr)1644 boolean W_IsPatchCached(lumpnum_t lumpnum, void *ptr)
1645 {
1646 	return W_IsPatchCachedPWAD(WADFILENUM(lumpnum),LUMPNUM(lumpnum), ptr);
1647 }
1648 
1649 // ==========================================================================
1650 // W_CacheLumpName
1651 // ==========================================================================
W_CacheLumpName(const char * name,INT32 tag)1652 void *W_CacheLumpName(const char *name, INT32 tag)
1653 {
1654 	return W_CacheLumpNum(W_GetNumForName(name), tag);
1655 }
1656 
1657 // ==========================================================================
1658 //                                         CACHING OF GRAPHIC PATCH RESOURCES
1659 // ==========================================================================
1660 
1661 // Graphic 'patches' are loaded, and if necessary, converted into the format
1662 // the most useful for the current rendermode. For software renderer, the
1663 // graphic patches are kept as is. For the hardware renderer, graphic patches
1664 // are 'unpacked', and are kept into the cache in that unpacked format, and
1665 // the heap memory cache then acts as a 'level 2' cache just after the
1666 // graphics card memory.
1667 
1668 //
1669 // Cache a patch into heap memory, convert the patch format as necessary
1670 //
1671 
W_CacheSoftwarePatchNumPwad(UINT16 wad,UINT16 lump,INT32 tag)1672 void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag)
1673 {
1674 	lumpcache_t *lumpcache = NULL;
1675 
1676 	if (!TestValidLump(wad, lump))
1677 		return NULL;
1678 
1679 	lumpcache = wadfiles[wad]->patchcache;
1680 
1681 	if (!lumpcache[lump])
1682 	{
1683 		size_t len = W_LumpLengthPwad(wad, lump);
1684 		void *ptr, *dest, *lumpdata = Z_Malloc(len, PU_STATIC, NULL);
1685 
1686 		// read the lump in full
1687 		W_ReadLumpHeaderPwad(wad, lump, lumpdata, 0, 0);
1688 		ptr = lumpdata;
1689 
1690 #ifndef NO_PNG_LUMPS
1691 		if (Picture_IsLumpPNG((UINT8 *)lumpdata, len))
1692 			ptr = Picture_PNGConvert((UINT8 *)lumpdata, PICFMT_DOOMPATCH, NULL, NULL, NULL, NULL, len, &len, 0);
1693 #endif
1694 
1695 		dest = Z_Calloc(sizeof(patch_t), tag, &lumpcache[lump]);
1696 		Patch_Create(ptr, len, dest);
1697 
1698 		Z_Free(ptr);
1699 	}
1700 	else
1701 		Z_ChangeTag(lumpcache[lump], tag);
1702 
1703 	return lumpcache[lump];
1704 }
1705 
W_CacheSoftwarePatchNum(lumpnum_t lumpnum,INT32 tag)1706 void *W_CacheSoftwarePatchNum(lumpnum_t lumpnum, INT32 tag)
1707 {
1708 	return W_CacheSoftwarePatchNumPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum),tag);
1709 }
1710 
W_CachePatchNumPwad(UINT16 wad,UINT16 lump,INT32 tag)1711 void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag)
1712 {
1713 	patch_t *patch;
1714 
1715 	if (!TestValidLump(wad, lump))
1716 		return NULL;
1717 
1718 	patch = W_CacheSoftwarePatchNumPwad(wad, lump, tag);
1719 
1720 #ifdef HWRENDER
1721 	// Software-only compile cache the data without conversion
1722 	if (rendermode == render_soft || rendermode == render_none)
1723 #endif
1724 		return (void *)patch;
1725 
1726 #ifdef HWRENDER
1727 	Patch_CreateGL(patch);
1728 	return (void *)patch;
1729 #endif
1730 }
1731 
W_CachePatchNum(lumpnum_t lumpnum,INT32 tag)1732 void *W_CachePatchNum(lumpnum_t lumpnum, INT32 tag)
1733 {
1734 	return W_CachePatchNumPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum),tag);
1735 }
1736 
W_UnlockCachedPatch(void * patch)1737 void W_UnlockCachedPatch(void *patch)
1738 {
1739 	if (!patch)
1740 		return;
1741 
1742 	// The hardware code does its own memory management, as its patches
1743 	// have different lifetimes from software's.
1744 #ifdef HWRENDER
1745 	if (rendermode == render_opengl)
1746 		HWR_UnlockCachedPatch((GLPatch_t *)((patch_t *)patch)->hardware);
1747 	else
1748 #endif
1749 		Z_Unlock(patch);
1750 }
1751 
W_CachePatchName(const char * name,INT32 tag)1752 void *W_CachePatchName(const char *name, INT32 tag)
1753 {
1754 	lumpnum_t num;
1755 
1756 	num = W_CheckNumForName(name);
1757 
1758 	if (num == LUMPERROR)
1759 		return W_CachePatchNum(W_GetNumForName("MISSING"), tag);
1760 	return W_CachePatchNum(num, tag);
1761 }
1762 
W_CachePatchLongName(const char * name,INT32 tag)1763 void *W_CachePatchLongName(const char *name, INT32 tag)
1764 {
1765 	lumpnum_t num;
1766 
1767 	num = W_CheckNumForLongName(name);
1768 
1769 	if (num == LUMPERROR)
1770 		return W_CachePatchNum(W_GetNumForLongName("MISSING"), tag);
1771 	return W_CachePatchNum(num, tag);
1772 }
1773 #ifndef NOMD5
1774 #define MD5_LEN 16
1775 
1776 /**
1777   * Prints an MD5 string into a human-readable textual format.
1778   *
1779   * \param md5 The md5 in binary form -- MD5_LEN (16) bytes.
1780   * \param buf Where to print the textual form. Needs 2*MD5_LEN+1 (33) bytes.
1781   * \author Graue <graue@oceanbase.org>
1782   */
1783 #define MD5_FORMAT \
1784 	"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
PrintMD5String(const UINT8 * md5,char * buf)1785 static void PrintMD5String(const UINT8 *md5, char *buf)
1786 {
1787 	snprintf(buf, 2*MD5_LEN+1, MD5_FORMAT,
1788 		md5[0], md5[1], md5[2], md5[3],
1789 		md5[4], md5[5], md5[6], md5[7],
1790 		md5[8], md5[9], md5[10], md5[11],
1791 		md5[12], md5[13], md5[14], md5[15]);
1792 }
1793 #endif
1794 /** Verifies a file's MD5 is as it should be.
1795   * For releases, used as cheat prevention -- if the MD5 doesn't match, a
1796   * fatal error is thrown. In debug mode, an MD5 mismatch only triggers a
1797   * warning.
1798   *
1799   * \param wadfilenum Number of the loaded wad file to check.
1800   * \param matchmd5   The MD5 sum this wad should have, expressed as a
1801   *                   textual string.
1802   * \author Graue <graue@oceanbase.org>
1803   */
W_VerifyFileMD5(UINT16 wadfilenum,const char * matchmd5)1804 void W_VerifyFileMD5(UINT16 wadfilenum, const char *matchmd5)
1805 {
1806 #ifdef NOMD5
1807 	(void)wadfilenum;
1808 	(void)matchmd5;
1809 #else
1810 	UINT8 realmd5[MD5_LEN];
1811 	INT32 ix;
1812 
1813 	I_Assert(strlen(matchmd5) == 2*MD5_LEN);
1814 	I_Assert(wadfilenum < numwadfiles);
1815 	// Convert an md5 string like "7d355827fa8f981482246d6c95f9bd48"
1816 	// into a real md5.
1817 	for (ix = 0; ix < 2*MD5_LEN; ix++)
1818 	{
1819 		INT32 n, c = matchmd5[ix];
1820 		if (isdigit(c))
1821 			n = c - '0';
1822 		else
1823 		{
1824 			I_Assert(isxdigit(c));
1825 			if (isupper(c)) n = c - 'A' + 10;
1826 			else n = c - 'a' + 10;
1827 		}
1828 		if (ix & 1) realmd5[ix>>1] = (UINT8)(realmd5[ix>>1]+n);
1829 		else realmd5[ix>>1] = (UINT8)(n<<4);
1830 	}
1831 
1832 	if (memcmp(realmd5, wadfiles[wadfilenum]->md5sum, 16))
1833 	{
1834 		char actualmd5text[2*MD5_LEN+1];
1835 		PrintMD5String(wadfiles[wadfilenum]->md5sum, actualmd5text);
1836 #ifdef _DEBUG
1837 		CONS_Printf
1838 #else
1839 		I_Error
1840 #endif
1841 			(M_GetText("File is old, is corrupt or has been modified: %s (found md5: %s, wanted: %s)\n"), wadfiles[wadfilenum]->filename, actualmd5text, matchmd5);
1842 	}
1843 #endif
1844 }
1845 
1846 // Verify versions for different archive
1847 // formats. checklist assumed to be valid.
1848 
1849 static int
W_VerifyName(const char * name,lumpchecklist_t * checklist,boolean status)1850 W_VerifyName (const char *name, lumpchecklist_t *checklist, boolean status)
1851 {
1852 	size_t j;
1853 	for (j = 0; checklist[j].len && checklist[j].name; ++j)
1854 	{
1855 		if (( strncasecmp(name, checklist[j].name,
1856 						checklist[j].len) != false ) == status)
1857 		{
1858 			return true;
1859 		}
1860 	}
1861 	return false;
1862 }
1863 
1864 static int
W_VerifyWAD(FILE * fp,lumpchecklist_t * checklist,boolean status)1865 W_VerifyWAD (FILE *fp, lumpchecklist_t *checklist, boolean status)
1866 {
1867 	size_t i;
1868 
1869 	// assume wad file
1870 	wadinfo_t header;
1871 	filelump_t lumpinfo;
1872 
1873 	// read the header
1874 	if (fread(&header, 1, sizeof header, fp) == sizeof header
1875 			&& header.numlumps < INT16_MAX
1876 			&& strncmp(header.identification, "ZWAD", 4)
1877 			&& strncmp(header.identification, "IWAD", 4)
1878 			&& strncmp(header.identification, "PWAD", 4)
1879 			&& strncmp(header.identification, "SDLL", 4))
1880 	{
1881 		return true;
1882 	}
1883 
1884 	header.numlumps = LONG(header.numlumps);
1885 	header.infotableofs = LONG(header.infotableofs);
1886 
1887 	// let seek to the lumpinfo list
1888 	if (fseek(fp, header.infotableofs, SEEK_SET) == -1)
1889 		return true;
1890 
1891 	for (i = 0; i < header.numlumps; i++)
1892 	{
1893 		// fill in lumpinfo for this wad file directory
1894 		if (fread(&lumpinfo, sizeof (lumpinfo), 1 , fp) != 1)
1895 			return true;
1896 
1897 		lumpinfo.filepos = LONG(lumpinfo.filepos);
1898 		lumpinfo.size = LONG(lumpinfo.size);
1899 
1900 		if (lumpinfo.size == 0)
1901 			continue;
1902 
1903 		if (! W_VerifyName(lumpinfo.name, checklist, status))
1904 			return false;
1905 	}
1906 
1907 	return true;
1908 }
1909 
1910 // List of blacklisted folders to use when checking the PK3
1911 static lumpchecklist_t folderblacklist[] =
1912 {
1913 	{"Lua/", 4},
1914 	{"SOC/", 4},
1915 	{"Sprites/",  8},
1916 	{"Textures/", 9},
1917 	{"Patches/", 8},
1918 	{"Flats/", 6},
1919 	{"Fades/", 6},
1920 	{NULL, 0},
1921 };
1922 
1923 static int
W_VerifyPK3(FILE * fp,lumpchecklist_t * checklist,boolean status)1924 W_VerifyPK3 (FILE *fp, lumpchecklist_t *checklist, boolean status)
1925 {
1926 	int verified = true;
1927 
1928     zend_t zend;
1929     zentry_t zentry;
1930     zlentry_t zlentry;
1931 
1932 	long file_size;/* size of zip file */
1933 	long data_size;/* size of data inside zip file */
1934 
1935 	long old_position;
1936 
1937 	UINT16 numlumps;
1938 	size_t i;
1939 
1940 	char pat_central[] = {0x50, 0x4b, 0x01, 0x02, 0x00};
1941 	char pat_end[] = {0x50, 0x4b, 0x05, 0x06, 0x00};
1942 
1943 	char lumpname[9];
1944 
1945 	// Haha the ResGetLumpsZip function doesn't
1946 	// check for file errors, so neither will I.
1947 
1948 	// Central directory bullshit
1949 
1950 	fseek(fp, 0, SEEK_END);
1951 	file_size = ftell(fp);
1952 
1953 	if (!ResFindSignature(fp, pat_end, max(0, ftell(fp) - (22 + 65536))))
1954 		return true;
1955 
1956 	fseek(fp, -4, SEEK_CUR);
1957 	if (fread(&zend, 1, sizeof zend, fp) < sizeof zend)
1958 		return true;
1959 
1960 	data_size = sizeof zend;
1961 
1962 	numlumps = zend.entries;
1963 
1964 	fseek(fp, zend.cdiroffset, SEEK_SET);
1965 	for (i = 0; i < numlumps; i++)
1966 	{
1967 		char* fullname;
1968 		char* trimname;
1969 		char* dotpos;
1970 
1971 		if (fread(&zentry, 1, sizeof(zentry_t), fp) < sizeof(zentry_t))
1972 			return true;
1973 		if (memcmp(zentry.signature, pat_central, 4))
1974 			return true;
1975 
1976 		if (verified == true)
1977 		{
1978 			fullname = malloc(zentry.namelen + 1);
1979 			if (fgets(fullname, zentry.namelen + 1, fp) != fullname)
1980 				return true;
1981 
1982 			// Strip away file address and extension for the 8char name.
1983 			if ((trimname = strrchr(fullname, '/')) != 0)
1984 				trimname++;
1985 			else
1986 				trimname = fullname; // Care taken for root files.
1987 
1988 			if (*trimname) // Ignore directories, well kinda
1989 			{
1990 				if ((dotpos = strrchr(trimname, '.')) == 0)
1991 					dotpos = fullname + strlen(fullname); // Watch for files without extension.
1992 
1993 				memset(lumpname, '\0', 9); // Making sure they're initialized to 0. Is it necessary?
1994 				strncpy(lumpname, trimname, min(8, dotpos - trimname));
1995 
1996 				if (! W_VerifyName(lumpname, checklist, status))
1997 					verified = false;
1998 
1999 				// Check for directories next, if it's blacklisted it will return false
2000 				else if (W_VerifyName(fullname, folderblacklist, status))
2001 					verified = false;
2002 			}
2003 
2004 			free(fullname);
2005 
2006 			// skip and ignore comments/extra fields
2007 			if (fseek(fp, zentry.xtralen + zentry.commlen, SEEK_CUR) != 0)
2008 				return true;
2009 		}
2010 		else
2011 		{
2012 			if (fseek(fp, zentry.namelen + zentry.xtralen + zentry.commlen, SEEK_CUR) != 0)
2013 				return true;
2014 		}
2015 
2016 		data_size +=
2017 			sizeof zentry + zentry.namelen + zentry.xtralen + zentry.commlen;
2018 
2019 		old_position = ftell(fp);
2020 
2021 		if (fseek(fp, zentry.offset, SEEK_SET) != 0)
2022 			return true;
2023 
2024 		if (fread(&zlentry, 1, sizeof(zlentry_t), fp) < sizeof (zlentry_t))
2025 			return true;
2026 
2027 		data_size +=
2028 			sizeof zlentry + zlentry.namelen + zlentry.xtralen + zlentry.compsize;
2029 
2030 		fseek(fp, old_position, SEEK_SET);
2031 	}
2032 
2033 	if (data_size < file_size)
2034 	{
2035 		const char * error = "ZIP file has holes (%ld extra bytes)\n";
2036 		CONS_Alert(CONS_ERROR, error, (file_size - data_size));
2037 		return -1;
2038 	}
2039 	else if (data_size > file_size)
2040 	{
2041 		const char * error = "Reported size of ZIP file contents exceeds file size (%ld extra bytes)\n";
2042 		CONS_Alert(CONS_ERROR, error, (data_size - file_size));
2043 		return -1;
2044 	}
2045 	else
2046 	{
2047 		return verified;
2048 	}
2049 }
2050 
2051 // Note: This never opens lumps themselves and therefore doesn't have to
2052 // deal with compressed lumps.
W_VerifyFile(const char * filename,lumpchecklist_t * checklist,boolean status)2053 static int W_VerifyFile(const char *filename, lumpchecklist_t *checklist,
2054 	boolean status)
2055 {
2056 	FILE *handle;
2057 	int goodfile = false;
2058 
2059 	if (!checklist)
2060 		I_Error("No checklist for %s\n", filename);
2061 	// open wad file
2062 	if ((handle = W_OpenWadFile(&filename, false)) == NULL)
2063 		return -1;
2064 
2065 	if (stricmp(&filename[strlen(filename) - 4], ".pk3") == 0)
2066 		goodfile = W_VerifyPK3(handle, checklist, status);
2067 	else
2068 	{
2069 		// detect wad file by the absence of the other supported extensions
2070 		if (stricmp(&filename[strlen(filename) - 4], ".soc")
2071 		&& stricmp(&filename[strlen(filename) - 4], ".lua"))
2072 		{
2073 			goodfile = W_VerifyWAD(handle, checklist, status);
2074 		}
2075 	}
2076 	fclose(handle);
2077 	return goodfile;
2078 }
2079 
2080 
2081 /** Checks a wad for lumps other than music and sound.
2082   * Used during game load to verify music.dta is a good file and during a
2083   * netgame join (on the server side) to see if a wad is important enough to
2084   * be sent.
2085   *
2086   * \param filename Filename of the wad to check.
2087   * \param exit_on_error Whether to exit upon file error.
2088   * \return 1 if file contains only music/sound lumps, 0 if it contains other
2089   *         stuff (maps, sprites, dehacked lumps, and so on). -1 if there no
2090   *         file exists with that filename
2091   * \author Alam Arias
2092   */
W_VerifyNMUSlumps(const char * filename,boolean exit_on_error)2093 int W_VerifyNMUSlumps(const char *filename, boolean exit_on_error)
2094 {
2095 	// MIDI, MOD/S3M/IT/XM/OGG/MP3/WAV, WAVE SFX
2096 	// ENDOOM text and palette lumps
2097 	lumpchecklist_t NMUSlist[] =
2098 	{
2099 		{"D_", 2}, // MIDI music
2100 		{"O_", 2}, // Digital music
2101 		{"DS", 2}, // Sound effects
2102 
2103 		{"ENDOOM", 6}, // ENDOOM text lump
2104 
2105 		{"PLAYPAL", 7}, // Palette changes
2106 		{"PAL", 3}, // Palette changes
2107 		{"COLORMAP", 8}, // Colormap changes
2108 		{"CLM", 3}, // Colormap changes
2109 		{"TRANS", 5}, // Translucency map changes
2110 
2111 		{"CONSBACK", 8}, // Console Background graphic
2112 
2113 		{"SAVE", 4}, // Save Select graphics here and below
2114 		{"BLACXLVL", 8},
2115 		{"GAMEDONE", 8},
2116 		{"CONT", 4}, // Continue icons on saves (probably not used anymore)
2117 		{"STNONEX", 7}, // "X" graphic
2118 		{"ULTIMATE", 8}, // Ultimate no-save
2119 
2120 		{"CRFNT", 5}, // Sonic 1 font changes
2121 		{"NTFNT", 5}, // Character Select font changes
2122 		{"NTFNO", 5}, // Character Select font (outline)
2123 		{"LTFNT", 5}, // Level title font changes
2124 		{"TTL", 3}, // Act number changes
2125 		{"STCFN", 5}, // Console font changes
2126 		{"TNYFN", 5}, // Tiny console font changes
2127 
2128 		{"STLIVE", 6}, // Life graphics, background and the "X" that shows under skin's HUDNAME
2129 		{"CROSHAI", 7}, // First person crosshairs
2130 		{"INTERSC", 7}, // Default intermission backgrounds (co-op)
2131 		{"STT", 3}, // Acceptable HUD changes (Score Time Rings)
2132 		{"YB_", 3}, // Intermission graphics, goes with the above
2133 		{"RESULT", 6}, // Used in intermission for competitive modes, above too :3
2134 		{"RACE", 4}, // Race mode graphics, 321go
2135 		{"M_", 2}, // Menu stuff
2136 		{"LT", 2}, // Titlecard changes
2137 
2138 		{"SLID", 4}, // Continue
2139 		{"CONT", 4},
2140 
2141 		{"MINICAPS", 8}, // NiGHTS graphics here and below
2142 		{"BLUESTAT", 8}, // Sphere status
2143 		{"BYELSTAT", 8},
2144 		{"ORNGSTAT", 8},
2145 		{"REDSTAT", 7},
2146 		{"YELSTAT", 7},
2147 		{"NBRACKET", 8},
2148 		{"NGHTLINK", 8},
2149 		{"NGT", 3}, // Link numbers
2150 		{"NARROW", 6},
2151 		{"NREDAR", 6},
2152 		{"NSS", 3},
2153 		{"NBON", 4},
2154 		{"NRNG", 4},
2155 		{"NHUD", 4},
2156 		{"CAPS", 4},
2157 		{"DRILL", 5},
2158 		{"GRADE", 5},
2159 		{"MINUS5", 6},
2160 
2161 		{"MUSICDEF", 8}, // Song definitions (thanks kart)
2162 		{"SHADERS", 7}, // OpenGL shader definitions
2163 		{"SH_", 3}, // GLSL shader
2164 
2165 		{NULL, 0},
2166 	};
2167 
2168 	int status = W_VerifyFile(filename, NMUSlist, false);
2169 
2170 	if (status == -1)
2171 		W_InitFileError(filename, exit_on_error);
2172 
2173 	return status;
2174 }
2175 
2176 /** \brief Generates a virtual resource used for level data loading.
2177  *
2178  * \param lumpnum_t reference
2179  * \return Virtual resource
2180  *
2181  */
vres_GetMap(lumpnum_t lumpnum)2182 virtres_t* vres_GetMap(lumpnum_t lumpnum)
2183 {
2184 	UINT32 i;
2185 	virtres_t* vres = NULL;
2186 	virtlump_t* vlumps = NULL;
2187 	size_t numlumps = 0;
2188 
2189 	if (W_IsLumpWad(lumpnum))
2190 	{
2191 		// Remember that we're assuming that the WAD will have a specific set of lumps in a specific order.
2192 		UINT8 *wadData = W_CacheLumpNum(lumpnum, PU_LEVEL);
2193 		filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs);
2194 		numlumps = ((wadinfo_t *)wadData)->numlumps;
2195 		vlumps = Z_Malloc(sizeof(virtlump_t)*numlumps, PU_LEVEL, NULL);
2196 
2197 		// Build the lumps.
2198 		for (i = 0; i < numlumps; i++)
2199 		{
2200 			vlumps[i].size = (size_t)(((filelump_t *)(fileinfo + i))->size);
2201 			// Play it safe with the name in this case.
2202 			memcpy(vlumps[i].name, (fileinfo + i)->name, 8);
2203 			vlumps[i].name[8] = '\0';
2204 			vlumps[i].data = Z_Malloc(vlumps[i].size, PU_LEVEL, NULL); // This is memory inefficient, sorry about that.
2205 			memcpy(vlumps[i].data, wadData + (fileinfo + i)->filepos, vlumps[i].size);
2206 		}
2207 
2208 		Z_Free(wadData);
2209 	}
2210 	else
2211 	{
2212 		// Count number of lumps until the end of resource OR up until next "MAPXX" lump.
2213 		lumpnum_t lumppos = lumpnum + 1;
2214 		for (i = LUMPNUM(lumppos); i < wadfiles[WADFILENUM(lumpnum)]->numlumps; i++, lumppos++, numlumps++)
2215 			if (memcmp(W_CheckNameForNum(lumppos), "MAP", 3) == 0)
2216 				break;
2217 		numlumps++;
2218 
2219 		vlumps = Z_Malloc(sizeof(virtlump_t)*numlumps, PU_LEVEL, NULL);
2220 		for (i = 0; i < numlumps; i++, lumpnum++)
2221 		{
2222 			vlumps[i].size = W_LumpLength(lumpnum);
2223 			memcpy(vlumps[i].name, W_CheckNameForNum(lumpnum), 8);
2224 			vlumps[i].name[8] = '\0';
2225 			vlumps[i].data = W_CacheLumpNum(lumpnum, PU_LEVEL);
2226 		}
2227 	}
2228 	vres = Z_Malloc(sizeof(virtres_t), PU_LEVEL, NULL);
2229 	vres->vlumps = vlumps;
2230 	vres->numlumps = numlumps;
2231 
2232 	return vres;
2233 }
2234 
2235 /** \brief Frees zone memory for a given virtual resource.
2236  *
2237  * \param Virtual resource
2238  */
vres_Free(virtres_t * vres)2239 void vres_Free(virtres_t* vres)
2240 {
2241 	while (vres->numlumps--)
2242 		Z_Free(vres->vlumps[vres->numlumps].data);
2243 	Z_Free(vres->vlumps);
2244 	Z_Free(vres);
2245 }
2246 
2247 /** (Debug) Prints lumps from a virtual resource into console.
2248  */
2249 /*
2250 static void vres_Diag(const virtres_t* vres)
2251 {
2252 	UINT32 i;
2253 	for (i = 0; i < vres->numlumps; i++)
2254 		CONS_Printf("%s\n", vres->vlumps[i].name);
2255 }
2256 */
2257 
2258 /** \brief Finds a lump in a given virtual resource.
2259  *
2260  * \param Virtual resource
2261  * \param Lump name to look for
2262  * \return Virtual lump if found, NULL otherwise
2263  *
2264  */
vres_Find(const virtres_t * vres,const char * name)2265 virtlump_t* vres_Find(const virtres_t* vres, const char* name)
2266 {
2267 	UINT32 i;
2268 	for (i = 0; i < vres->numlumps; i++)
2269 		if (fastcmp(name, vres->vlumps[i].name))
2270 			return &vres->vlumps[i];
2271 	return NULL;
2272 }
2273