Refactor filtering if numbered paks.

For historical reasons numbered paks must be loaded before all other
paks. The logic is easy: Add all numbered paks. Iterate over all
available paks, filter out numbered paks and add everything that's left.

Until now a simple glob comparisson against 'pak*' was used for the
filtering. This has two problems:

1. All paks starting with 'pak*' were filtered, regardless if they're
   numbered paks or not.
2. Upper case or mixed case file names that are valid on caseinsenstive
   systems like Windows weren't recognized as numbered paks and added
   twice. Once as numbered pak and once as other pak.

Refactor the logic to only match paks starting with 'pak%d' and use
strcasecmp() for comparison. Closed #730.
This commit is contained in:
Yamagi 2021-08-02 08:44:49 +02:00
parent e2e2bddfa3
commit 7db0a89fe1

View file

@ -25,13 +25,14 @@
* =======================================================================
*/
#include <libgen.h>
#include "header/common.h"
#include "header/glob.h"
#include "unzip/unzip.h"
#include "../client/sound/header/vorbis.h"
#define MAX_HANDLES 512
#define MAX_MODS 32
#define MAX_PAKS 100
@ -1563,12 +1564,15 @@ FS_GetNextRawPath(const char* lastRawPath)
void
FS_AddDirToSearchPath(char *dir, qboolean create) {
char *file;
char **list;
char path[MAX_OSPATH];
int i, j;
char *tmp;
int i, j, k;
int nfiles;
fsPack_t *pack = NULL;
fsSearchPath_t *search;
qboolean nextpak;
size_t len = strlen(dir);
// The directory must not end with an /. It would
@ -1586,7 +1590,8 @@ FS_AddDirToSearchPath(char *dir, qboolean create) {
// be the last directory added to the search path.
Q_strlcpy(fs_gamedir, dir, sizeof(fs_gamedir));
if (create) {
if (create)
{
FS_CreatePath(fs_gamedir);
}
@ -1596,11 +1601,15 @@ FS_AddDirToSearchPath(char *dir, qboolean create) {
search->next = fs_searchPaths;
fs_searchPaths = search;
// We need to add numbered paks in the directory in
// sequence and all other paks after them. Otherwise
// the gamedata may break.
for (i = 0; i < sizeof(fs_packtypes) / sizeof(fs_packtypes[0]); i++) {
for (j = 0; j < MAX_PAKS; j++) {
// Numbered paks contain the official game data, they
// need to be added first and are marked protected.
// Files from protected paks are never offered for
// download.
for (i = 0; i < sizeof(fs_packtypes) / sizeof(fs_packtypes[0]); i++)
{
for (j = 0; j < MAX_PAKS; j++)
{
Com_sprintf(path, sizeof(path), "%s/pak%d.%s", dir, j, fs_packtypes[i].suffix);
switch (fs_packtypes[i].format)
@ -1637,8 +1646,13 @@ FS_AddDirToSearchPath(char *dir, qboolean create) {
}
}
// And as said above all other pak files.
for (i = 0; i < sizeof(fs_packtypes) / sizeof(fs_packtypes[0]); i++) {
// All other pak files are added after the numbered paks.
// They aren't sorted in any way, but added in the same
// sequence as they're returned by FS_ListFiles. This is
// fragile and file system dependend. We cannot change
// this, since it might break existing installations.
for (i = 0; i < sizeof(fs_packtypes) / sizeof(fs_packtypes[0]); i++)
{
Com_sprintf(path, sizeof(path), "%s/*.%s", dir, fs_packtypes[i].suffix);
// Nothing here, next pak type please.
@ -1647,10 +1661,36 @@ FS_AddDirToSearchPath(char *dir, qboolean create) {
continue;
}
Com_sprintf(path, sizeof(path), "%s/pak*.%s", dir, fs_packtypes[i].suffix);
for (j = 0; j < nfiles - 1; j++)
{
// Sort out numbered paks. This is as inefficient as
// it can be, but it doesn't matter. This is done only
// once at client or game startup.
nextpak = false;
for (k = 0; k < MAX_PAKS; k++)
{
// basename() may alter the given string.
// We need to work around that...
tmp = strdup(list[j]);
file = basename(tmp);
Com_sprintf(path, sizeof(path), "pak%d.%s", k, fs_packtypes[i].suffix);
if (Q_strcasecmp(path, file) == 0)
{
nextpak = true;
break;
}
free(tmp);
}
if (nextpak)
{
continue;
}
// If the pak starts with the string 'pak' it's ignored.
// This is somewhat stupid, it would be better to ignore
// just pak%d...