Experimental implementation

This commit is contained in:
Jaime Ita Passos 2021-03-22 23:56:55 -03:00
parent 91c9d667e1
commit dca158096d
18 changed files with 1007 additions and 95 deletions

View file

@ -274,7 +274,7 @@ static int luaB_dofile (lua_State *L) {
UINT16 lumpnum;
int n = lua_gettop(L);
if (wadfiles[numwadfiles - 1]->type != RET_PK3)
if (!W_FileHasFolders(wadfiles[numwadfiles - 1]))
luaL_error(L, "dofile() only works with PK3 files");
snprintf(fullfilename, sizeof(fullfilename), "Lua/%s", filename);

View file

@ -4486,9 +4486,9 @@ static INT16 Consistancy(void)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo = (mobj_t *)th;
if (mo->flags & (MF_SPECIAL | MF_SOLID | MF_PUSHABLE | MF_BOSS | MF_MISSILE | MF_SPRING | MF_MONITOR | MF_FIRE | MF_ENEMY | MF_PAIN | MF_STICKY))
{
ret -= mo->type;

View file

@ -873,10 +873,26 @@ static void D_AddFile(char **list, const char *file)
newfile = malloc(strlen(file) + 1);
if (!newfile)
{
I_Error("No more free memory to AddFile %s",file);
}
strcpy(newfile, file);
list[pnumwadfiles] = newfile;
}
static void D_AddFolder(char **list, const char *file)
{
size_t pnumwadfiles, len = strlen(file);
char *newfile;
for (pnumwadfiles = 0; list[pnumwadfiles]; pnumwadfiles++)
;
newfile = malloc(len + 2); // NULL terminator + path separator
if (!newfile)
I_Error("No more free memory to AddFolder %s",file);
strcpy(newfile, file);
strcat(newfile, PATHSEP);
list[pnumwadfiles] = newfile;
}
@ -1180,7 +1196,7 @@ void D_SRB2Main(void)
{
if (M_CheckParm("-file"))
{
// the parms after p are wadfile/lump names,
// the parms after p are wadfile names,
// until end of parms or another - preceded parm
while (M_IsNextParm())
{
@ -1190,6 +1206,19 @@ void D_SRB2Main(void)
D_AddFile(startuppwads, s);
}
}
if (M_CheckParm("-folder"))
{
// the parms after p are folder names,
// until end of parms or another - preceded parm
while (M_IsNextParm())
{
const char *s = M_GetNextParm();
if (s) // Check for NULL?
D_AddFolder(startuppwads, s);
}
}
}
// get map from parms

View file

@ -63,7 +63,9 @@ static void Got_WeaponPref(UINT8 **cp, INT32 playernum);
static void Got_Mapcmd(UINT8 **cp, INT32 playernum);
static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum);
static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum);
static void Got_RequestAddfoldercmd(UINT8 **cp, INT32 playernum);
static void Got_Addfilecmd(UINT8 **cp, INT32 playernum);
static void Got_Addfoldercmd(UINT8 **cp, INT32 playernum);
static void Got_Pause(UINT8 **cp, INT32 playernum);
static void Got_Suicide(UINT8 **cp, INT32 playernum);
static void Got_RandomSeed(UINT8 **cp, INT32 playernum);
@ -115,6 +117,7 @@ static void Command_Map_f(void);
static void Command_ResetCamera_f(void);
static void Command_Addfile(void);
static void Command_Addfolder(void);
static void Command_ListWADS_f(void);
static void Command_RunSOC(void);
static void Command_Pause(void);
@ -398,16 +401,16 @@ const char *netxcmdnames[MAXNETXCMD - 1] =
"MAP",
"EXITLEVEL",
"ADDFILE",
"ADDFOLDER",
"PAUSE",
"ADDPLAYER",
"TEAMCHANGE",
"CLEARSCORES",
"LOGIN",
"VERIFIED",
"RANDOMSEED",
"RUNSOC",
"REQADDFILE",
"DELFILE", // replace next time we add an XD
"REQADDFOLDER",
"SETMOTD",
"SUICIDE",
"LUACMD",
@ -441,7 +444,9 @@ void D_RegisterServerCommands(void)
RegisterNetXCmd(XD_MAP, Got_Mapcmd);
RegisterNetXCmd(XD_EXITLEVEL, Got_ExitLevelcmd);
RegisterNetXCmd(XD_ADDFILE, Got_Addfilecmd);
RegisterNetXCmd(XD_ADDFOLDER, Got_Addfoldercmd);
RegisterNetXCmd(XD_REQADDFILE, Got_RequestAddfilecmd);
RegisterNetXCmd(XD_REQADDFOLDER, Got_RequestAddfoldercmd);
RegisterNetXCmd(XD_PAUSE, Got_Pause);
RegisterNetXCmd(XD_SUICIDE, Got_Suicide);
RegisterNetXCmd(XD_RUNSOC, Got_RunSOCcmd);
@ -472,6 +477,7 @@ void D_RegisterServerCommands(void)
COM_AddCommand("showmap", Command_Showmap_f);
COM_AddCommand("mapmd5", Command_Mapmd5_f);
COM_AddCommand("addfolder", Command_Addfolder);
COM_AddCommand("addfile", Command_Addfile);
COM_AddCommand("listwad", Command_ListWADS_f);
@ -3323,9 +3329,9 @@ static void Command_Addfile(void)
++p;
// check total packet size and no of files currently loaded
// See W_LoadWadFile in w_wad.c
// See W_InitFile in w_wad.c
if ((numwadfiles >= MAX_WADFILES)
|| ((packetsizetally + nameonlylength(fn) + 22) > MAXFILENEEDED*sizeof(UINT8)))
|| ((packetsizetally + nameonlylength(fn) + FILENEEDEDSIZE) > MAXFILENEEDED*sizeof(UINT8)))
{
CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn);
return;
@ -3373,6 +3379,89 @@ static void Command_Addfile(void)
}
}
static void Command_Addfolder(void)
{
size_t argc = COM_Argc(); // amount of arguments total
size_t curarg; // current argument index
const char *addedfolders[argc]; // list of filenames already processed
size_t numfoldersadded = 0; // the amount of filenames processed
if (argc < 2)
{
CONS_Printf(M_GetText("addfolder <path> [path2...] [...]: Load add-ons\n"));
return;
}
// start at one to skip command name
for (curarg = 1; curarg < argc; curarg++)
{
const char *fn, *p;
char buf[256];
char *buf_p = buf;
INT32 i;
size_t ii;
boolean folderadded = false;
fn = COM_Argv(curarg);
// For the amount of filenames previously processed...
for (ii = 0; ii < numfoldersadded; ii++)
{
// If this is one of them, don't try to add it.
if (!strcmp(fn, addedfolders[ii]))
{
folderadded = true;
break;
}
}
// If we've added this one, skip to the next one.
if (folderadded)
{
CONS_Alert(CONS_WARNING, M_GetText("Already processed %s, skipping\n"), fn);
continue;
}
// Disallow non-printing characters and semicolons.
for (i = 0; fn[i] != '\0'; i++)
if (!isprint(fn[i]) || fn[i] == ';')
return;
// Add file on your client directly if you aren't in a netgame.
if (!(netgame || multiplayer))
{
P_AddFolder(fn);
addedfolders[numfoldersadded++] = fn;
continue;
}
p = fn+strlen(fn);
while(--p >= fn)
if (*p == '\\' || *p == '/' || *p == ':')
break;
++p;
// check total packet size and no of files currently loaded
// See W_InitFile in w_wad.c
if ((numwadfiles >= MAX_WADFILES)
|| ((packetsizetally + strlen(fn) + FILENEEDEDSIZE) > MAXFILENEEDED*sizeof(UINT8)))
{
CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn);
return;
}
WRITESTRINGN(buf_p,p,240);
addedfolders[numfoldersadded++] = fn;
if (IsPlayerAdmin(consoleplayer) && (!server)) // Request to add file
SendNetXCmd(XD_REQADDFOLDER, buf, buf_p - buf);
else
SendNetXCmd(XD_ADDFOLDER, buf, buf_p - buf);
}
}
static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
{
char filename[241];
@ -3401,9 +3490,9 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
return;
}
// See W_LoadWadFile in w_wad.c
// See W_InitFile in w_wad.c
if ((numwadfiles >= MAX_WADFILES)
|| ((packetsizetally + nameonlylength(filename) + 22) > MAXFILENEEDED*sizeof(UINT8)))
|| ((packetsizetally + nameonlylength(filename) + FILENEEDEDSIZE) > MAXFILENEEDED*sizeof(UINT8)))
toomany = true;
else
ncs = findfile(filename,md5sum,true);
@ -3433,6 +3522,64 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
COM_BufAddText(va("addfile %s\n", filename));
}
static void Got_RequestAddfoldercmd(UINT8 **cp, INT32 playernum)
{
char path[241];
filestatus_t ncs = FS_NOTFOUND;
boolean kick = false;
boolean toomany = false;
INT32 i,j;
READSTRINGN(*cp, path, 240);
/// \todo Integrity checks.
// Only the server processes this message.
if (client)
return;
// Disallow non-printing characters and semicolons.
for (i = 0; path[i] != '\0'; i++)
if (!isprint(path[i]) || path[i] == ';')
kick = true;
if ((playernum != serverplayer && !IsPlayerAdmin(playernum)) || kick)
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal addfolder command received from %s\n"), player_names[playernum]);
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
return;
}
// See W_InitFile in w_wad.c
if ((numwadfiles >= MAX_WADFILES)
|| ((packetsizetally + strlen(path) + FILENEEDEDSIZE) > MAXFILENEEDED*sizeof(UINT8)))
toomany = true;
else
ncs = findfolder(path);
if (ncs != FS_FOUND || toomany)
{
char message[256];
if (toomany)
sprintf(message, M_GetText("Too many files loaded to add %s\n"), path);
else if (ncs == FS_NOTFOUND)
sprintf(message, M_GetText("The server doesn't have %s\n"), path);
else
sprintf(message, M_GetText("Unknown error finding folder (%s)\n"), path);
CONS_Printf("%s",message);
for (j = 0; j < MAXPLAYERS; j++)
if (adminplayers[j])
COM_BufAddText(va("sayto %d %s", adminplayers[j], message));
return;
}
COM_BufAddText(va("addfolder \"%s\"\n", path));
}
static void Got_Addfilecmd(UINT8 **cp, INT32 playernum)
{
char filename[241];
@ -3481,6 +3628,49 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum)
G_SetGameModified(true);
}
static void Got_Addfoldercmd(UINT8 **cp, INT32 playernum)
{
char path[241];
filestatus_t ncs = FS_NOTFOUND;
READSTRINGN(*cp, path, 240);
/// \todo Integrity checks.
if (playernum != serverplayer)
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal addfolder command received from %s\n"), player_names[playernum]);
if (server)
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
return;
}
ncs = findfolder(path);
if (ncs != FS_FOUND || !P_AddFolder(path))
{
Command_ExitGame_f();
if (ncs == FS_FOUND)
{
CONS_Printf(M_GetText("The server tried to add %s,\nbut you have too many files added.\nRestart the game to clear loaded files\nand play on this server."), path);
M_StartMessage(va("The server added a folder \n(%s)\nbut you have too many files added.\nRestart the game to clear loaded files.\n\nPress ESC\n",path), NULL, MM_NOTHING);
}
else if (ncs == FS_NOTFOUND)
{
CONS_Printf(M_GetText("The server tried to add %s,\nbut you don't have this file.\nYou need to find it in order\nto play on this server."), path);
M_StartMessage(va("The server added a folder \n(%s)\nthat you do not have.\n\nPress ESC\n",path), NULL, MM_NOTHING);
}
else
{
CONS_Printf(M_GetText("Unknown error finding folder (%s) the server added.\n"), path);
M_StartMessage(va("Unknown error trying to load a folder\nthat the server added \n(%s).\n\nPress ESC\n",path), NULL, MM_NOTHING);
}
return;
}
G_SetGameModified(true);
}
static void Command_ListWADS_f(void)
{
INT32 i = numwadfiles;
@ -3495,6 +3685,8 @@ static void Command_ListWADS_f(void)
CONS_Printf("\x82 * %.2d\x80: %s\n", i, tempname);
else if (!wadfiles[i]->important)
CONS_Printf("\x86 %.2d: %s\n", i, tempname);
else if (wadfiles[i]->type == RET_FOLDER)
CONS_Printf("\x82 * %.2d\x84: %s\n", i, tempname);
else
CONS_Printf(" %.2d: %s\n", i, tempname);
}

View file

@ -128,16 +128,16 @@ typedef enum
XD_MAP, // 6
XD_EXITLEVEL, // 7
XD_ADDFILE, // 8
XD_PAUSE, // 9
XD_ADDPLAYER, // 10
XD_TEAMCHANGE, // 11
XD_CLEARSCORES, // 12
// UNUSED 13 (Because I don't want to change these comments)
XD_VERIFIED = 14,//14
XD_ADDFOLDER, // 9
XD_PAUSE, // 10
XD_ADDPLAYER, // 11
XD_TEAMCHANGE, // 12
XD_CLEARSCORES, // 13
XD_VERIFIED, // 14
XD_RANDOMSEED, // 15
XD_RUNSOC, // 16
XD_REQADDFILE, // 17
XD_DELFILE, // 18 - replace next time we add an XD
XD_REQADDFOLDER,// 18
XD_SETMOTD, // 19
XD_SUICIDE, // 20
XD_DEMOTED, // 21

View file

@ -120,7 +120,7 @@ char luafiledir[256 + 16] = "luafiles";
/** Fills a serverinfo packet with information about wad files loaded.
*
* \todo Give this function a better name since it is in global scope.
* Used to have size limiting built in - now handled via W_LoadWadFile in w_wad.c
* Used to have size limiting built in - now handled via W_InitFile in w_wad.c
*
*/
UINT8 *PutFileNeeded(void)
@ -128,7 +128,7 @@ UINT8 *PutFileNeeded(void)
size_t i, count = 0;
UINT8 *p = netbuffer->u.serverinfo.fileneeded;
char wadfilename[MAX_WADPATH] = "";
UINT8 filestatus;
UINT8 filestatus, folder;
for (i = 0; i < numwadfiles; i++)
{
@ -137,9 +137,10 @@ UINT8 *PutFileNeeded(void)
continue;
filestatus = 1; // Importance - not really used any more, holds 1 by default for backwards compat with MS
folder = (wadfiles[i]->type == RET_FOLDER);
// Store in the upper four bits
if (!cv_downloading.value)
if (!cv_downloading.value || folder) /// \todo Implement folder downloading.
filestatus += (2 << 4); // Won't send
else if ((wadfiles[i]->filesize <= (UINT32)cv_maxsend.value * 1024))
filestatus += (1 << 4); // Will send if requested
@ -147,6 +148,7 @@ UINT8 *PutFileNeeded(void)
// filestatus += (0 << 4); -- Won't send, too big
WRITEUINT8(p, filestatus);
WRITEUINT8(p, folder);
count++;
WRITEUINT32(p, wadfiles[i]->filesize);
@ -178,6 +180,7 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr)
fileneeded[i].status = FS_NOTFOUND; // We haven't even started looking for the file yet
fileneeded[i].justdownloaded = false;
filestatus = READUINT8(p); // The first byte is the file status
fileneeded[i].folder = READUINT8(p); // The second byte is the folder flag
fileneeded[i].willsend = (UINT8)(filestatus >> 4);
fileneeded[i].totalsize = READUINT32(p); // The four next bytes are the file size
fileneeded[i].file = NULL; // The file isn't open yet
@ -420,7 +423,7 @@ INT32 CL_CheckFiles(void)
return 1;
}
// See W_LoadWadFile in w_wad.c
// See W_InitFile in w_wad.c
packetsize = packetsizetally;
for (i = 1; i < fileneedednum; i++)
@ -442,7 +445,10 @@ INT32 CL_CheckFiles(void)
if (fileneeded[i].status != FS_NOTFOUND)
continue;
packetsize += nameonlylength(fileneeded[i].filename) + 22;
if (fileneeded[i].folder)
packetsize += strlen(fileneeded[i].filename) + FILENEEDEDSIZE;
else
packetsize += nameonlylength(fileneeded[i].filename) + FILENEEDEDSIZE;
if ((numwadfiles+filestoget >= MAX_WADFILES)
|| (packetsize > MAXFILENEEDED*sizeof(UINT8)))
@ -450,7 +456,10 @@ INT32 CL_CheckFiles(void)
filestoget++;
fileneeded[i].status = findfile(fileneeded[i].filename, fileneeded[i].md5sum, true);
if (fileneeded[i].folder)
fileneeded[i].status = findfolder(fileneeded[i].filename);
else
fileneeded[i].status = findfile(fileneeded[i].filename, fileneeded[i].md5sum, true);
CONS_Debug(DBG_NETPLAY, "found %d\n", fileneeded[i].status);
if (fileneeded[i].status != FS_FOUND)
ret = 0;
@ -472,7 +481,10 @@ void CL_LoadServerFiles(void)
continue; // Already loaded
else if (fileneeded[i].status == FS_FOUND)
{
P_AddWadFile(fileneeded[i].filename);
if (fileneeded[i].folder)
P_AddFolder(fileneeded[i].filename);
else
P_AddWadFile(fileneeded[i].filename);
G_SetGameModified(true);
fileneeded[i].status = FS_OPEN;
}
@ -757,7 +769,7 @@ static boolean AddFileToSendQueue(INT32 node, const char *filename, UINT8 fileid
// This formerly checked if (!findfile(p->id.filename, NULL, true))
// Not found
// Don't inform client (probably someone who thought they could leak 2.2 ACZ)
// Don't inform client
DEBFILE(va("Client %d request %s: not found\n", node, filename));
free(p->id.filename);
free(p);
@ -1556,3 +1568,23 @@ filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum, boolean complet
return (badmd5 ? FS_MD5SUMBAD : FS_NOTFOUND); // md5 sum bad or file not found
}
filestatus_t findfolder(const char *path)
{
// Check the path by itself first.
if (checkfolderpath(path, NULL, true))
return FS_FOUND;
#define checkpath(startpath) { \
if (checkfolderpath(path, startpath, true)) \
return FS_FOUND; \
}
checkpath(srb2home) // Then, look in srb2home.
checkpath(srb2path) // Now, look in srb2path.
checkpath(".") // Finally, look in ".".
#undef checkpath
return FS_NOTFOUND;
}

View file

@ -38,6 +38,7 @@ typedef enum
typedef struct
{
UINT8 willsend; // Is the server willing to send it?
UINT8 folder; // File is a folder
char filename[MAX_WADPATH];
UINT8 md5sum[16];
filestatus_t status; // The value returned by recsearch
@ -54,6 +55,8 @@ typedef struct
UINT32 ackresendposition; // Used when resuming downloads
} fileneeded_t;
#define FILENEEDEDSIZE 23
extern INT32 fileneedednum;
extern fileneeded_t fileneeded[MAX_WADFILES];
extern char downloaddir[512];
@ -133,6 +136,9 @@ filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum,
boolean completepath);
filestatus_t checkfilemd5(char *filename, const UINT8 *wantedmd5sum);
// Searches for a folder
filestatus_t findfolder(const char *path);
void nameonly(char *s);
size_t nameonlylength(const char *s);

View file

@ -29,6 +29,7 @@
#include "m_misc.h"
#include "z_zone.h"
#include "m_menu.h" // Addons_option_Onchange
#include "w_wad.h"
#if defined (_WIN32) && defined (_MSC_VER)
@ -340,6 +341,11 @@ char *refreshdirname = NULL;
size_t packetsizetally = 0;
size_t mainwadstally = 0;
#define folderpathlen 1024
#define maxfolderdepth 48
#define isuptree(dirent) ((dirent)[0]=='.' && ((dirent)[1]=='\0' || ((dirent)[1]=='.' && (dirent)[2]=='\0')))
filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth)
{
filestatus_t retval = FS_NOTFOUND;
@ -387,10 +393,7 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want
continue;
}
if (dent->d_name[0]=='.' &&
(dent->d_name[1]=='\0' ||
(dent->d_name[1]=='.' &&
dent->d_name[2]=='\0')))
if (isuptree(dent->d_name))
{
// we don't want to scan uptree
continue;
@ -445,6 +448,329 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want
return retval;
}
// Called from findfolder and ResGetLumpsFolder in w_wad.c.
// Call with cleanup true if the path has to be verified.
boolean checkfolderpath(const char *path, const char *startpath, boolean cleanup)
{
char folderpath[folderpathlen], basepath[folderpathlen], *fn = NULL;
DIR *dirhandle;
// Remove path separators from the filename, and don't try adding "/".
// See also the same code in W_InitFolder.
if (cleanup)
{
const char *p = path + strlen(path);
size_t len;
--p;
while (*p == '\\' || *p == '/' || *p == ':')
{
p--;
if (p < path)
return false;
}
++p;
// Allocate the new path name.
len = (p - path) + 1;
fn = ZZ_Alloc(len);
strlcpy(fn, path, len);
}
if (startpath)
{
snprintf(basepath, sizeof basepath, "%s" PATHSEP, startpath);
if (cleanup)
{
snprintf(folderpath, sizeof folderpath, "%s%s", basepath, fn);
Z_Free(fn); // Don't need this anymore.
}
else
snprintf(folderpath, sizeof folderpath, "%s%s", basepath, path);
// Home path and folder path are the same? Not valid.
if (!strcmp(basepath, folderpath))
return false;
}
else if (cleanup)
{
snprintf(folderpath, sizeof folderpath, "%s", fn);
Z_Free(fn); // Don't need this anymore.
}
else
snprintf(folderpath, sizeof folderpath, "%s", path);
dirhandle = opendir(folderpath);
if (dirhandle == NULL)
return false;
else
closedir(dirhandle);
return true;
}
INT32 pathisfolder(const char *path)
{
struct stat fsstat;
if (stat(path, &fsstat) < 0)
return -1;
else if (S_ISDIR(fsstat.st_mode))
return 1;
return 0;
}
INT32 samepaths(const char *path1, const char *path2)
{
struct stat stat1;
struct stat stat2;
if (stat(path1, &stat1) < 0)
return -1;
if (stat(path2, &stat2) < 0)
return -1;
if (stat1.st_dev == stat2.st_dev)
{
#if !defined(_WIN32)
return (stat1.st_ino == stat2.st_ino);
#else
HANDLE file1 = CreateFileA(path1, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
HANDLE file2 = CreateFileA(path2, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
BY_HANDLE_FILE_INFORMATION file1info, file2info;
boolean ok = false;
if (file1 != INVALID_HANDLE_VALUE && file2 != INVALID_HANDLE_VALUE)
{
if (GetFileInformationByHandle(file1, &file1info) && GetFileInformationByHandle(file2, &file2info))
{
if (file1info.dwVolumeSerialNumber == file2info.dwVolumeSerialNumber
&& file1info.nFileIndexLow == file2info.nFileIndexLow
&& file1info.nFileIndexHigh == file2info.nFileIndexHigh)
ok = true;
}
}
if (file1 != INVALID_HANDLE_VALUE)
CloseHandle(file1);
if (file2 != INVALID_HANDLE_VALUE)
CloseHandle(file2);
return ok;
#endif
}
return false;
}
//
// Folder loading
//
static void initfolderpath(char *folderpath, size_t *folderpathindex, int depthleft)
{
folderpathindex[depthleft] = strlen(folderpath) + 1;
if (folderpath[folderpathindex[depthleft]-2] != PATHSEP[0])
{
folderpath[folderpathindex[depthleft]-1] = PATHSEP[0];
folderpath[folderpathindex[depthleft]] = 0;
}
else
folderpathindex[depthleft]--;
}
lumpinfo_t *getfolderfiles(const char *path, UINT16 *nlmp, UINT16 *nfiles, UINT16 *nfolders)
{
DIR **dirhandle;
struct dirent *dent;
struct stat fsstat;
int rootfolder = (maxfolderdepth - 1);
int depthleft = rootfolder;
char folderpath[folderpathlen];
size_t *folderpathindex;
lumpinfo_t *lumpinfo, *lump_p;
UINT16 i = 0, numlumps = (*nlmp);
dirhandle = (DIR **)malloc(maxfolderdepth * sizeof (DIR*));
folderpathindex = (size_t *)malloc(maxfolderdepth * sizeof(size_t));
// Open the root directory
strlcpy(folderpath, path, folderpathlen);
dirhandle[depthleft] = opendir(folderpath);
if (dirhandle[depthleft] == NULL)
{
free(dirhandle);
free(folderpathindex);
return NULL;
}
initfolderpath(folderpath, folderpathindex, depthleft);
(*nfiles) = 0;
(*nfolders) = 0;
// Count files and directories
while (depthleft < maxfolderdepth)
{
folderpath[folderpathindex[depthleft]] = 0;
dent = readdir(dirhandle[depthleft]);
if (!dent)
{
if (depthleft != rootfolder) // Don't close the root directory
closedir(dirhandle[depthleft]);
depthleft++;
continue;
}
else if (isuptree(dent->d_name))
continue;
strcpy(&folderpath[folderpathindex[depthleft]], dent->d_name);
if (stat(folderpath, &fsstat) < 0)
;
else if (S_ISDIR(fsstat.st_mode) && depthleft)
{
folderpathindex[--depthleft] = strlen(folderpath) + 1;
dirhandle[depthleft] = opendir(folderpath);
if (dirhandle[depthleft])
{
numlumps++;
(*nfolders)++;
}
else
depthleft++;
folderpath[folderpathindex[depthleft]-1] = '/';
folderpath[folderpathindex[depthleft]] = 0;
}
else
{
numlumps++;
(*nfiles)++;
}
if (numlumps == (UINT16_MAX-1))
break;
}
// Failure: No files have been found.
if (!(*nfiles))
{
(*nfiles) = UINT16_MAX;
free(folderpathindex);
free(dirhandle);
for (; depthleft < maxfolderdepth; closedir(dirhandle[depthleft++])); // Close any open directories.
return NULL;
}
// Create the files and directories as lump entries
// It's possible to create lumps and count files at the same time,
// but I didn't to constantly have to reallocate memory for every lump.
rewinddir(dirhandle[rootfolder]);
depthleft = rootfolder;
strlcpy(folderpath, path, folderpathlen);
initfolderpath(folderpath, folderpathindex, depthleft);
lump_p = lumpinfo = Z_Calloc(numlumps * sizeof(lumpinfo_t), PU_STATIC, NULL);
while (depthleft < maxfolderdepth)
{
char *fullname, *trimname;
folderpath[folderpathindex[depthleft]] = 0;
dent = readdir(dirhandle[depthleft]);
if (!dent)
{
closedir(dirhandle[depthleft++]);
continue;
}
else if (isuptree(dent->d_name))
continue;
strcpy(&folderpath[folderpathindex[depthleft]], dent->d_name);
if (stat(folderpath, &fsstat) < 0)
continue;
else if (S_ISDIR(fsstat.st_mode) && depthleft)
{
folderpathindex[--depthleft] = strlen(folderpath) + 1;
dirhandle[depthleft] = opendir(folderpath);
if (!dirhandle[depthleft])
{
depthleft++;
continue;
}
folderpath[folderpathindex[depthleft]-1] = '/';
folderpath[folderpathindex[depthleft]] = 0;
}
lump_p->diskpath = Z_StrDup(folderpath); // Path in the filesystem to the file
lump_p->compression = CM_NOCOMPRESSION; // Lump is uncompressed
// Remove the folder path.
fullname = lump_p->diskpath;
if (strstr(fullname, path))
fullname += strlen(path) + 1;
// Get the 8-character long lump name.
trimname = strrchr(fullname, '/');
if (trimname)
trimname++;
else
trimname = fullname;
if (trimname[0])
{
char *dotpos = strrchr(trimname, '.');
if (dotpos == NULL)
dotpos = fullname + strlen(fullname);
strncpy(lump_p->name, trimname, min(8, dotpos - trimname));
// The name of the file, without the extension.
lump_p->longname = Z_Calloc(dotpos - trimname + 1, PU_STATIC, NULL);
strlcpy(lump_p->longname, trimname, dotpos - trimname + 1);
}
else
lump_p->longname = Z_Calloc(1, PU_STATIC, NULL);
// The complete name of the file, with its extension,
// excluding the path of the folder where it resides.
lump_p->fullname = Z_StrDup(fullname);
lump_p++;
i++;
if (i > numlumps || i == (UINT16_MAX-1))
{
for (; depthleft < maxfolderdepth; closedir(dirhandle[depthleft++])); // Close any open directories.
break;
}
}
free(folderpathindex);
free(dirhandle);
(*nlmp) = numlumps;
return lumpinfo;
}
//
// Addons menu
//
char exttable[NUM_EXT_TABLE][7] = { // maximum extension length (currently 4) plus 3 (null terminator, stop, and length including previous two)
"\5.txt", "\5.cfg", // exec
"\5.wad",
@ -455,7 +781,6 @@ char exttable[NUM_EXT_TABLE][7] = { // maximum extension length (currently 4) pl
char filenamebuf[MAX_WADFILES][MAX_WADPATH];
static boolean filemenucmp(char *haystack, char *needle)
{
static char localhaystack[128];
@ -640,10 +965,7 @@ boolean preparefilemenu(boolean samedepth)
if (!dent)
break;
else if (dent->d_name[0]=='.' &&
(dent->d_name[1]=='\0' ||
(dent->d_name[1]=='.' &&
dent->d_name[2]=='\0')))
else if (isuptree(dent->d_name))
continue; // we don't want to scan uptree
strcpy(&menupath[menupathindex[menudepthleft]],dent->d_name);
@ -704,10 +1026,7 @@ boolean preparefilemenu(boolean samedepth)
if (!dent)
break;
else if (dent->d_name[0]=='.' &&
(dent->d_name[1]=='\0' ||
(dent->d_name[1]=='.' &&
dent->d_name[2]=='\0')))
else if (isuptree(dent->d_name))
continue; // we don't want to scan uptree
strcpy(&menupath[menupathindex[menudepthleft]],dent->d_name);

View file

@ -7,6 +7,7 @@
#include "doomdef.h"
#include "d_netfil.h"
#include "m_menu.h" // MAXSTRINGLENGTH
#include "w_wad.h"
extern consvar_t cv_addons_option, cv_addons_folder, cv_addons_md5, cv_addons_showall, cv_addons_search_case, cv_addons_search_type;
@ -28,6 +29,12 @@ extern consvar_t cv_addons_option, cv_addons_folder, cv_addons_md5, cv_addons_sh
filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum,
boolean completepath, int maxsearchdepth);
INT32 pathisfolder(const char *path);
boolean checkfolderpath(const char *path, const char *startpath, boolean cleanup);
INT32 samepaths(const char *path1, const char *path2);
lumpinfo_t *getfolderfiles(const char *path, UINT16 *nlmp, UINT16 *nfiles, UINT16 *nfolders);
#define menudepth 20
extern char menupath[1024];
@ -94,5 +101,4 @@ typedef enum
void closefilemenu(boolean validsize);
void searchfilemenu(char *tempname);
boolean preparefilemenu(boolean samedepth);
#endif // __FILESRCH_H__

View file

@ -6681,7 +6681,7 @@ void HWR_LoadAllCustomShaders(void)
// read every custom shader
for (i = 0; i < numwadfiles; i++)
HWR_LoadCustomShadersFromFile(i, (wadfiles[i]->type == RET_PK3));
HWR_LoadCustomShadersFromFile(i, W_FileHasFolders(wadfiles[i]));
}
void HWR_LoadCustomShadersFromFile(UINT16 wadnum, boolean PK3)

View file

@ -2688,3 +2688,22 @@ const char * M_Ftrim (double f)
return &dig[1];/* skip the 0 */
}
}
// Returns true if the string is empty.
boolean M_IsStringEmpty(const char *s)
{
const char *ch = s;
if (ch == NULL || (ch && strlen(ch) < 1))
return true;
for (;;ch++)
{
if (!(*ch))
break;
if (!isspace((*ch)))
return false;
}
return true;
}

View file

@ -117,6 +117,9 @@ trailing zeros, or "" if the fractional part is zero.
*/
const char * M_Ftrim (double);
// Returns true if the string is empty.
boolean M_IsStringEmpty(const char *s);
// counting bits, for weapon ammo code, usually
FUNCMATH UINT8 M_CountBits(UINT32 num, UINT8 size);

View file

@ -4385,10 +4385,9 @@ static lumpinfo_t* FindFolder(const char *folName, UINT16 *start, UINT16 *end, l
// Add a wadfile to the active wad files,
// replace sounds, musics, patches, textures, sprites and maps
//
boolean P_AddWadFile(const char *wadfilename)
static boolean P_LoadAddon(UINT16 wadnum, UINT16 numlumps)
{
size_t i, j, sreplaces = 0, mreplaces = 0, digmreplaces = 0;
UINT16 numlumps, wadnum;
char *name;
lumpinfo_t *lumpinfo;
@ -4409,18 +4408,10 @@ boolean P_AddWadFile(const char *wadfilename)
// UINT16 flaPos, flaNum = 0;
// UINT16 mapPos, mapNum = 0;
// Init file.
if ((numlumps = W_InitFile(wadfilename, false, false)) == INT16_MAX)
{
refreshdirmenu |= REFRESHDIR_NOTLOADED;
return false;
}
else
wadnum = (UINT16)(numwadfiles-1);
switch(wadfiles[wadnum]->type)
{
case RET_PK3:
case RET_FOLDER:
// Look for the lumps that act as resource delimitation markers.
lumpinfo = wadfiles[wadnum]->lumpinfo;
for (i = 0; i < numlumps; i++, lumpinfo++)
@ -4584,3 +4575,35 @@ boolean P_AddWadFile(const char *wadfilename)
return true;
}
boolean P_AddWadFile(const char *wadfilename)
{
UINT16 numlumps, wadnum;
// Init file.
if ((numlumps = W_InitFile(wadfilename, false, false)) == INT16_MAX)
{
refreshdirmenu |= REFRESHDIR_NOTLOADED;
return false;
}
else
wadnum = (UINT16)(numwadfiles-1);
return P_LoadAddon(wadnum, numlumps);
}
boolean P_AddFolder(const char *folderpath)
{
UINT16 numlumps, wadnum;
// Init file.
if ((numlumps = W_InitFolder(folderpath, false, false)) == INT16_MAX)
{
refreshdirmenu |= REFRESHDIR_NOTLOADED;
return false;
}
else
wadnum = (UINT16)(numwadfiles-1);
return P_LoadAddon(wadnum, numlumps);
}

View file

@ -103,6 +103,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate);
void HWR_LoadLevel(void);
#endif
boolean P_AddWadFile(const char *wadfilename);
boolean P_AddFolder(const char *folderpath);
boolean P_RunSOC(const char *socfilename);
void P_LoadSoundsRange(UINT16 wadnum, UINT16 first, UINT16 num);
void P_LoadMusicsRange(UINT16 wadnum, UINT16 first, UINT16 num);

View file

@ -732,7 +732,7 @@ Rloadflats (INT32 i, INT32 w)
texpatch_t *patch;
// Yes
if (wadfiles[w]->type == RET_PK3)
if (W_FileHasFolders(wadfiles[w]))
{
texstart = W_CheckNumForFolderStartPK3("flats/", (UINT16)w, 0);
texend = W_CheckNumForFolderEndPK3("flats/", (UINT16)w, texstart);
@ -754,7 +754,7 @@ Rloadflats (INT32 i, INT32 w)
size_t lumplength;
size_t flatsize = 0;
if (wadfiles[w]->type == RET_PK3)
if (W_FileHasFolders(wadfiles[w]))
{
if (W_IsLumpFolder(wadnum, lumpnum)) // Check if lump is a folder
continue; // If it is then SKIP IT
@ -844,7 +844,7 @@ Rloadtextures (INT32 i, INT32 w)
texpatch_t *patch;
// Get the lump numbers for the markers in the WAD, if they exist.
if (wadfiles[w]->type == RET_PK3)
if (W_FileHasFolders(wadfiles[w]))
{
texstart = W_CheckNumForFolderStartPK3("textures/", (UINT16)w, 0);
texend = W_CheckNumForFolderEndPK3("textures/", (UINT16)w, texstart);
@ -875,7 +875,7 @@ Rloadtextures (INT32 i, INT32 w)
size_t lumplength;
#endif
if (wadfiles[w]->type == RET_PK3)
if (W_FileHasFolders(wadfiles[w]))
{
if (W_IsLumpFolder(wadnum, lumpnum)) // Check if lump is a folder
continue; // If it is then SKIP IT
@ -964,7 +964,7 @@ void R_LoadTextures(void)
{
#ifdef WALLFLATS
// Count flats
if (wadfiles[w]->type == RET_PK3)
if (W_FileHasFolders(wadfiles[w]))
{
texstart = W_CheckNumForFolderStartPK3("flats/", (UINT16)w, 0);
texend = W_CheckNumForFolderEndPK3("flats/", (UINT16)w, texstart);
@ -978,7 +978,7 @@ void R_LoadTextures(void)
if (!( texstart == INT16_MAX || texend == INT16_MAX ))
{
// PK3s have subfolders, so we can't just make a simple sum
if (wadfiles[w]->type == RET_PK3)
if (W_FileHasFolders(wadfiles[w]))
{
for (j = texstart; j < texend; j++)
{
@ -1002,7 +1002,7 @@ void R_LoadTextures(void)
}
// Count single-patch textures
if (wadfiles[w]->type == RET_PK3)
if (W_FileHasFolders(wadfiles[w]))
{
texstart = W_CheckNumForFolderStartPK3("textures/", (UINT16)w, 0);
texend = W_CheckNumForFolderEndPK3("textures/", (UINT16)w, texstart);
@ -1017,7 +1017,7 @@ void R_LoadTextures(void)
continue;
// PK3s have subfolders, so we can't just make a simple sum
if (wadfiles[w]->type == RET_PK3)
if (W_FileHasFolders(wadfiles[w]))
{
for (j = texstart; j < texend; j++)
{
@ -1558,6 +1558,7 @@ lumpnum_t R_GetFlatNumForName(const char *name)
continue;
break;
case RET_PK3:
case RET_FOLDER:
if ((start = W_CheckNumForFolderStartPK3("Flats/", i, 0)) == INT16_MAX)
continue;
if ((end = W_CheckNumForFolderEndPK3("Flats/", i, start)) == INT16_MAX)

View file

@ -443,6 +443,7 @@ void R_AddSpriteDefs(UINT16 wadnum)
end = W_CheckNumForNamePwad("SS_END",wadnum,start); //deutex compatib.
break;
case RET_PK3:
case RET_FOLDER:
start = W_CheckNumForFolderStartPK3("Sprites/", wadnum, 0);
end = W_CheckNumForFolderEndPK3("Sprites/", wadnum, start);
break;

View file

@ -50,16 +50,17 @@
#include "filesrch.h"
#include "i_video.h" // rendermode
#include "d_main.h"
#include "d_netfil.h"
#include "dehacked.h"
#include "d_clisrv.h"
#include "dehacked.h"
#include "r_defs.h"
#include "r_data.h"
#include "r_textures.h"
#include "r_patch.h"
#include "r_picformats.h"
#include "i_system.h"
#include "i_video.h" // rendermode
#include "md5.h"
#include "lua_script.h"
#ifdef SCANTHINGS
@ -117,10 +118,15 @@ void W_Shutdown(void)
{
wadfile_t *wad = wadfiles[numwadfiles];
fclose(wad->handle);
if (wad->handle)
fclose(wad->handle);
Z_Free(wad->filename);
if (wad->path)
Z_Free(wad->path);
while (wad->numlumps--)
{
if (wad->lumpinfo[wad->numlumps].diskpath)
Z_Free(wad->lumpinfo[wad->numlumps].diskpath);
Z_Free(wad->lumpinfo[wad->numlumps].longname);
Z_Free(wad->lumpinfo[wad->numlumps].fullname);
}
@ -421,6 +427,7 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen
{
lump_p->position = LONG(fileinfo->filepos);
lump_p->size = lump_p->disksize = LONG(fileinfo->size);
lump_p->diskpath = NULL;
if (compressed) // wad is compressed, lump might be
{
UINT32 realsize = 0;
@ -602,6 +609,7 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp)
lump_p->position = zentry.offset; // NOT ACCURATE YET: we still need to read the local entry to find our true position
lump_p->disksize = zentry.compsize;
lump_p->diskpath = NULL;
lump_p->size = zentry.size;
fullname = malloc(zentry.namelen + 1);
@ -679,6 +687,58 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp)
return lumpinfo;
}
// Checks if the combination of the first path and the second path are valid.
// If they are, the concatenated path is returned.
static char *W_CheckFolderPath(const char *startpath, const char *path)
{
if (checkfolderpath(path, startpath, false))
{
char *fn;
if (startpath)
{
size_t len = strlen(startpath) + strlen(path) + strlen(PATHSEP) + 1;
fn = ZZ_Alloc(len);
snprintf(fn, len, "%s" PATHSEP "%s", startpath, path);
}
else
fn = Z_StrDup(path);
return fn;
}
return NULL;
}
// Returns the first valid path for a folder.
static char *W_GetFullFolderPath(const char *path)
{
// Check the path by itself first.
char *fn = W_CheckFolderPath(NULL, path);
if (fn)
return fn;
#define checkpath(startpath) { \
fn = W_CheckFolderPath(startpath, path); \
if (fn) \
return fn; \
} \
checkpath(srb2home) // Then, look in srb2home.
checkpath(srb2path) // Now, look in srb2path.
checkpath(".") // Finally, look in ".".
#undef checkpath
return NULL;
}
// Loads files from a folder into a lumpinfo structure.
static lumpinfo_t *ResGetLumpsFolder(const char *path, UINT16 *nlmp, UINT16 *nfiles, UINT16 *nfolders)
{
return getfolderfiles(path, nlmp, nfiles, nfolders);
}
static UINT16 W_InitFileError (const char *filename, boolean exitworthy)
{
if (exitworthy)
@ -694,6 +754,19 @@ static UINT16 W_InitFileError (const char *filename, boolean exitworthy)
return INT16_MAX;
}
static void W_ReadFileShaders(wadfile_t *wadfile)
{
#ifdef HWRENDER
if (rendermode == render_opengl && (vid.glstate == VID_GL_LIBRARY_LOADED))
{
HWR_LoadCustomShadersFromFile(numwadfiles - 1, W_FileHasFolders(wadfile));
HWR_CompileShaders();
}
#else
(void)wadfile;
#endif
}
// Allocate a wadfile, setup the lumpinfo (directory) and
// lumpcache, add the wadfile to the current active wadfiles
//
@ -760,7 +833,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
// see PutFileNeeded in d_netfil.c
if ((important = !important))
{
packetsize = packetsizetally + nameonlylength(filename) + 22;
packetsize = packetsizetally + nameonlylength(filename) + FILENEEDEDSIZE;
if (packetsize > MAXFILENEEDED*sizeof(UINT8))
{
@ -788,7 +861,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
{
CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), filename);
if (important)
packetsizetally -= nameonlylength(filename) + 22;
packetsizetally -= nameonlylength(filename) + FILENEEDEDSIZE;
if (handle)
fclose(handle);
return W_InitFileError(filename, false);
@ -828,9 +901,11 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
//
wadfile = Z_Malloc(sizeof (*wadfile), PU_STATIC, NULL);
wadfile->filename = Z_StrDup(filename);
wadfile->path = NULL;
wadfile->type = type;
wadfile->handle = handle;
wadfile->numlumps = (UINT16)numlumps;
wadfile->numlumps = numlumps;
wadfile->filecount = wadfile->foldercount = 0;
wadfile->lumpinfo = lumpinfo;
wadfile->important = important;
fseek(handle, 0, SEEK_END);
@ -853,14 +928,8 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
wadfiles[numwadfiles] = wadfile;
numwadfiles++; // must come BEFORE W_LoadDehackedLumps, so any addfile called by COM_BufInsertText called by Lua doesn't overwrite what we just loaded
#ifdef HWRENDER
// Read shaders from file
if (rendermode == render_opengl && (vid.glstate == VID_GL_LIBRARY_LOADED))
{
HWR_LoadCustomShadersFromFile(numwadfiles - 1, (type == RET_PK3));
HWR_CompileShaders();
}
#endif // HWRENDER
W_ReadFileShaders(wadfile);
// 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.
switch (wadfile->type)
@ -886,6 +955,153 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
return wadfile->numlumps;
}
//
// Loads a folder as a WAD.
//
UINT16 W_InitFolder(const char *path, boolean mainfile, boolean startup)
{
lumpinfo_t *lumpinfo = NULL;
wadfile_t *wadfile;
UINT16 numlumps = 0;
UINT16 filecount, foldercount;
size_t i;
char *fn, *fullpath;
const char *p;
int important;
if (!(refreshdirmenu & REFRESHDIR_ADDFILE))
refreshdirmenu = REFRESHDIR_NORMAL|REFRESHDIR_ADDFILE; // clean out cons_alerts that happened earlier
if (refreshdirname)
Z_Free(refreshdirname);
if (dirmenu)
refreshdirname = Z_StrDup(path);
else
refreshdirname = NULL;
if (numwadfiles >= MAX_WADFILES)
{
CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n"));
refreshdirmenu |= REFRESHDIR_MAX;
return W_InitFileError(path, startup);
}
important = 0; // ???
/// \todo Implement a W_VerifyFolder.
if ((important = !important))
{
size_t packetsize = packetsizetally + strlen(path) + FILENEEDEDSIZE;
if (packetsize > MAXFILENEEDED*sizeof(UINT8))
{
CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n"));
refreshdirmenu |= REFRESHDIR_MAX;
return W_InitFileError(path, startup);
}
packetsizetally = packetsize;
}
// Remove path separators from the filename, and don't try adding "/".
p = path+strlen(path);
--p;
while (*p == '\\' || *p == '/' || *p == ':')
{
p--;
if (p < path)
{
CONS_Alert(CONS_ERROR, M_GetText("Path %s is prohibited\n"), path);
return W_InitFileError(path, startup);
}
}
p++;
// Allocate the new path name.
i = (p - path) + 1;
fn = ZZ_Alloc(i);
strlcpy(fn, path, i);
if (M_IsStringEmpty(fn))
{
CONS_Alert(CONS_ERROR, M_GetText("Folder name is empty\n"));
Z_Free(fn);
if (startup)
return W_InitFileError("A folder", true);
else
return W_InitFileError("a folder", false);
}
// Get the full path for this filename.
fullpath = W_GetFullFolderPath(fn);
if (fullpath == NULL)
{
Z_Free(fn);
return W_InitFileError(path, false);
}
for (i = 0; i < numwadfiles; i++)
{
if (wadfiles[i]->type != RET_FOLDER)
continue;
if (samepaths(wadfiles[i]->path, fullpath) > 0)
{
CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), path);
if (important)
packetsizetally -= strlen(path) + FILENEEDEDSIZE;
Z_Free(fn);
Z_Free(fullpath);
return W_InitFileError(path, false);
}
}
lumpinfo = ResGetLumpsFolder(fullpath, &numlumps, &filecount, &foldercount);
if (lumpinfo == NULL)
{
if (filecount == UINT16_MAX)
CONS_Alert(CONS_ERROR, M_GetText("Folder %s is empty\n"), path);
Z_Free(fn);
Z_Free(fullpath);
return W_InitFileError(path, startup);
}
if (important && !mainfile)
G_SetGameModified(true);
wadfile = Z_Malloc(sizeof (*wadfile), PU_STATIC, NULL);
wadfile->filename = fn;
wadfile->path = fullpath;
wadfile->type = RET_FOLDER;
wadfile->handle = NULL;
wadfile->numlumps = numlumps;
wadfile->filecount = filecount;
wadfile->foldercount = foldercount;
wadfile->lumpinfo = lumpinfo;
wadfile->important = important;
// Irrelevant.
wadfile->filesize = 0;
memset(wadfile->md5sum, 0x00, 16);
Z_Calloc(numlumps * sizeof (*wadfile->lumpcache), PU_STATIC, &wadfile->lumpcache);
Z_Calloc(numlumps * sizeof (*wadfile->patchcache), PU_STATIC, &wadfile->patchcache);
CONS_Printf(M_GetText("Added folder %s (%u files, %u folders)\n"), fn, filecount, foldercount);
wadfiles[numwadfiles] = wadfile;
numwadfiles++;
W_ReadFileShaders(wadfile);
W_LoadDehackedLumpsPK3(numwadfiles - 1, mainfile);
W_InvalidateLumpnumCache();
return wadfile->numlumps;
}
/** Tries to load a series of files.
* All files are wads unless they have an extension of ".soc" or ".lua".
*
@ -897,11 +1113,18 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
*/
void W_InitMultipleFiles(char **filenames)
{
// will be realloced as lumps are added
for (; *filenames; filenames++)
{
//CONS_Debug(DBG_SETUP, "Loading %s\n", *filenames);
W_InitFile(*filenames, numwadfiles < mainwads, true);
const char *fn = (*filenames);
char pathsep = fn[strlen(fn) - 1];
boolean mainfile = (numwadfiles < mainwads);
//CONS_Debug(DBG_SETUP, "Loading %s\n", fn);
if (pathsep == '\\' || pathsep == '/')
W_InitFolder(fn, mainfile, true);
else
W_InitFile(fn, mainfile, true);
}
}
@ -1175,7 +1398,7 @@ lumpnum_t W_CheckNumForMap(const char *name)
if (!strncmp(name, (wadfiles[i]->lumpinfo + lumpNum)->name, 8))
return (i<<16) + lumpNum;
}
else if (wadfiles[i]->type == RET_PK3)
else if (W_FileHasFolders(wadfiles[i]))
{
lumpNum = W_CheckNumForFolderStartPK3("maps/", i, 0);
if (lumpNum != INT16_MAX)
@ -1273,9 +1496,34 @@ UINT8 W_LumpExists(const char *name)
size_t W_LumpLengthPwad(UINT16 wad, UINT16 lump)
{
lumpinfo_t *l;
if (!TestValidLump(wad, lump))
return 0;
return wadfiles[wad]->lumpinfo[lump].size;
l = wadfiles[wad]->lumpinfo + lump;
if (wadfiles[wad]->type == RET_FOLDER)
{
INT32 stat = pathisfolder(l->diskpath);
if (stat < 0)
I_Error("W_LumpLengthPwad: could not stat %s", l->diskpath);
else if (stat == 1) // Path is a folder.
return 0;
else
{
FILE *handle = fopen(l->diskpath, "rb");
if (handle == NULL)
I_Error("W_LumpLengthPwad: could not open file %s", l->diskpath);
fseek(handle, 0, SEEK_END);
l->size = l->disksize = ftell(handle);
fclose(handle);
}
}
return l->size;
}
/** Returns the buffer size needed to load the given lump.
@ -1294,7 +1542,7 @@ size_t W_LumpLength(lumpnum_t lumpnum)
//
boolean W_IsLumpWad(lumpnum_t lumpnum)
{
if (wadfiles[WADFILENUM(lumpnum)]->type == RET_PK3)
if (W_FileHasFolders(wadfiles[WADFILENUM(lumpnum)]))
{
const char *lumpfullName = (wadfiles[WADFILENUM(lumpnum)]->lumpinfo + LUMPNUM(lumpnum))->fullname;
@ -1312,7 +1560,7 @@ boolean W_IsLumpWad(lumpnum_t lumpnum)
//
boolean W_IsLumpFolder(UINT16 wad, UINT16 lump)
{
if (wadfiles[wad]->type == RET_PK3)
if (W_FileHasFolders(wadfiles[wad]))
{
const char *name = wadfiles[wad]->lumpinfo[lump].fullname;
@ -1362,17 +1610,44 @@ void zerr(int ret)
*/
size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, size_t offset)
{
size_t lumpsize;
size_t lumpsize, bytesread;
lumpinfo_t *l;
FILE *handle;
FILE *handle = NULL;
if (!TestValidLump(wad,lump))
return 0;
l = wadfiles[wad]->lumpinfo + lump;
// Open the external file for this lump, if the WAD is a folder.
if (wadfiles[wad]->type == RET_FOLDER)
{
INT32 stat = pathisfolder(l->diskpath);
if (stat < 0)
I_Error("W_ReadLumpHeaderPwad: could not stat %s", l->diskpath);
else if (stat == 1) // Path is a folder.
return 0;
else
{
handle = fopen(l->diskpath, "rb");
if (handle == NULL)
I_Error("W_ReadLumpHeaderPwad: could not open file %s", l->diskpath);
// Find length of file
fseek(handle, 0, SEEK_END);
l->size = l->disksize = ftell(handle);
}
}
lumpsize = wadfiles[wad]->lumpinfo[lump].size;
// empty resource (usually markers like S_START, F_END ..)
if (!lumpsize || lumpsize<offset)
{
if (wadfiles[wad]->type == RET_FOLDER)
fclose(handle);
return 0;
}
// zero size means read all the lump
if (!size || size+offset > lumpsize)
@ -1380,24 +1655,22 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si
// Let's get the raw lump data.
// We setup the desired file handle to read the lump data.
l = wadfiles[wad]->lumpinfo + lump;
handle = wadfiles[wad]->handle;
if (wadfiles[wad]->type != RET_FOLDER)
handle = wadfiles[wad]->handle;
fseek(handle, (long)(l->position + offset), SEEK_SET);
// But let's not copy it yet. We support different compression formats on lumps, so we need to take that into account.
switch(wadfiles[wad]->lumpinfo[lump].compression)
{
case CM_NOCOMPRESSION: // If it's uncompressed, we directly write the data into our destination, and return the bytes read.
bytesread = fread(dest, 1, size, handle);
if (wadfiles[wad]->type == RET_FOLDER)
fclose(handle);
#ifdef NO_PNG_LUMPS
{
size_t bytesread = fread(dest, 1, size, handle);
if (Picture_IsLumpPNG((UINT8 *)dest, bytesread))
Picture_ThrowPNGError(l->fullname, wadfiles[wad]->filename);
return bytesread;
}
#else
return fread(dest, 1, size, handle);
if (Picture_IsLumpPNG((UINT8 *)dest, bytesread))
Picture_ThrowPNGError(l->fullname, wadfiles[wad]->filename);
#endif
return bytesread;
case CM_LZF: // Is it LZF compressed? Used by ZWADs.
{
#ifdef ZWAD

View file

@ -69,6 +69,7 @@ typedef struct
char name[9]; // filelump_t name[] e.g. "LongEntr"
char *longname; // e.g. "LongEntryName"
char *fullname; // e.g. "Folder/Subfolder/LongEntryName.extension"
char *diskpath; // path to the file e.g. "/usr/games/srb2/Addon/Folder/Subfolder/LongEntryName.extension"
size_t size; // real (uncompressed) size
compmethod compression; // lump compression method
} lumpinfo_t;
@ -109,17 +110,19 @@ typedef enum restype
RET_SOC,
RET_LUA,
RET_PK3,
RET_FOLDER,
RET_UNKNOWN,
} restype_t;
typedef struct wadfile_s
{
char *filename;
char *filename, *path;
restype_t type;
lumpinfo_t *lumpinfo;
lumpcache_t *lumpcache;
lumpcache_t *patchcache;
UINT16 numlumps; // this wad's number of resources
UINT16 filecount, foldercount; // file and folder count
FILE *handle;
UINT32 filesize; // for network
UINT8 md5sum[16];
@ -127,7 +130,7 @@ typedef struct wadfile_s
boolean important; // also network - !W_VerifyNMUSlumps
} wadfile_t;
#define WADFILENUM(lumpnum) (UINT16)((lumpnum)>>16) // wad flumpnum>>16) // wad file number in upper word
#define WADFILENUM(lumpnum) (UINT16)((lumpnum)>>16) // wad file number in upper word
#define LUMPNUM(lumpnum) (UINT16)((lumpnum)&0xFFFF) // lump number for this pwad
extern UINT16 numwadfiles;
@ -141,10 +144,14 @@ void W_Shutdown(void);
FILE *W_OpenWadFile(const char **filename, boolean useerrors);
// Load and add a wadfile to the active wad files, returns numbers of lumps, INT16_MAX on error
UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup);
// Adds a folder as a file
UINT16 W_InitFolder(const char *path, boolean mainfile, boolean startup);
// W_InitMultipleFiles exits if a file was not found, but not if all is okay.
void W_InitMultipleFiles(char **filenames);
#define W_FileHasFolders(wadfile) ((wadfile)->type == RET_PK3 || (wadfile)->type == RET_FOLDER)
const char *W_CheckNameForNumPwad(UINT16 wad, UINT16 lump);
const char *W_CheckNameForNum(lumpnum_t lumpnum);