diff --git a/src/common/filesystem.c b/src/common/filesystem.c index 06355044..90b5ff52 100644 --- a/src/common/filesystem.c +++ b/src/common/filesystem.c @@ -98,9 +98,9 @@ typedef struct } fsPackTypes_t; fsHandle_t fs_handles[MAX_HANDLES]; -fsLink_t *fs_links; -fsSearchPath_t *fs_searchPaths; -fsSearchPath_t *fs_baseSearchPaths; +fsLink_t *fs_links = NULL; +fsSearchPath_t *fs_searchPaths = NULL; +fsSearchPath_t *fs_baseSearchPaths = NULL; /* Pack formats / suffixes. */ fsPackTypes_t fs_packtypes[] = { @@ -197,36 +197,7 @@ static voidpf ZCALLBACK fopen_file_func_utf(voidpf opaque, const char *filename, * */ -/* - * Returns the path up to, but not including the last '/'. - */ -void -Com_FilePath(const char *path, char *dst, int dstSize) -{ - char *pos; /* Position of the last '/'. */ - - if ((pos = strrchr(path, '/')) != NULL) - { - pos--; - - if ((pos - path) < dstSize) - { - memcpy(dst, path, pos - path); - dst[pos - path] = '\0'; - } - else - { - Com_Printf("Com_FilePath: not enough space.\n"); - return; - } - } - else - { - Q_strlcpy(dst, path, dstSize); - } -} - -int +static int FS_FileLength(FILE *f) { int pos; /* Current position. */ @@ -300,7 +271,7 @@ FS_Gamedir(void) /* * Finds a free fileHandle_t. */ -fsHandle_t * +static fsHandle_t * FS_HandleForFile(const char *path, fileHandle_t *f) { int i; @@ -319,7 +290,7 @@ FS_HandleForFile(const char *path, fileHandle_t *f) } /* Failed. */ - Com_Error(ERR_DROP, "FS_HandleForFile: none free"); + Com_Error(ERR_DROP, "%s: none free", __func__); return NULL; } @@ -332,7 +303,7 @@ FS_GetFileByHandle(fileHandle_t f) { if ((f < 0) || (f > MAX_HANDLES)) { - Com_Error(ERR_DROP, "FS_GetFileByHandle: out of range"); + Com_Error(ERR_DROP, "%s: out of range", __func__); } if (f == 0) @@ -366,6 +337,54 @@ FS_FCloseFile(fileHandle_t f) memset(handle, 0, sizeof(*handle)); } +static int +FS_SortPackCompare(const void *p1, const void *p2) +{ + fsPackFile_t *file1, *file2; + + file1 = (fsPackFile_t*)p1; + file2 = (fsPackFile_t*)p2; + return Q_stricmp(file1->name, file2->name); +} + +static void +FS_SortPack(fsPack_t *pak) +{ + qsort(pak->files, pak->numFiles, sizeof(fsPackFile_t), FS_SortPackCompare); +} + +static int +FS_PackQuickSearch(const fsPack_t *pak, const char *name) +{ + int start, end; + + start = 0; + end = pak->numFiles - 1; + + while (start <= end) + { + int i, res; + + i = start + (end - start) / 2; + + res = Q_stricmp(pak->files[i].name, name); + if (res == 0) + { + return i; + } + else if (res < 0) + { + start = i + 1; + } + else + { + end = i - 1; + } + } + + return -1; +} + /* * Finds the file in the search path. Returns filesize and an open FILE *. Used * for streaming data out of either a pak file or a seperate file. @@ -377,14 +396,14 @@ FS_FOpenFile(const char *rawname, fileHandle_t *f, qboolean gamedir_only) fsHandle_t *handle; fsPack_t *pack; fsSearchPath_t *search; - int i; + int input, output; // Remove self references and empty dirs from the requested path. // ZIPs and PAKs don't support them, but they may be hardcoded in // some custom maps or models. char name[MAX_QPATH] = {0}; size_t namelen = strlen(rawname); - for (int input = 0, output = 0; input < namelen; input++) + for (input = 0, output = 0; input < namelen; input++) { // Remove self reference. if (rawname[input] == '.') @@ -458,70 +477,70 @@ FS_FOpenFile(const char *rawname, fileHandle_t *f, qboolean gamedir_only) /* Search inside a pack file. */ if (search->pack) { + int i; + pack = search->pack; + i = FS_PackQuickSearch(pack, handle->name); - for (i = 0; i < pack->numFiles; i++) + if (i >= 0) { - if (Q_stricmp(pack->files[i].name, handle->name) == 0) + /* Found it! */ + if (fs_debug->value) { - /* Found it! */ - if (fs_debug->value) + Com_Printf("%s: '%s' (found in '%s').\n", + __func__, handle->name, pack->name); + } + + // save the name with *correct case* in the handle + // (relevant for savegames, when starting map with wrong case but it's still found + // because it's from pak, but save/bla/MAPname.sav/sv2 will have wrong case and can't be found then) + Q_strlcpy(handle->name, pack->files[i].name, sizeof(handle->name)); + + if (pack->pak) + { + /* PAK */ + if (pack->isProtectedPak) { - Com_Printf("FS_FOpenFile: '%s' (found in '%s').\n", - handle->name, pack->name); + file_from_protected_pak = true; } - // save the name with *correct case* in the handle - // (relevant for savegames, when starting map with wrong case but it's still found - // because it's from pak, but save/bla/MAPname.sav/sv2 will have wrong case and can't be found then) - Q_strlcpy(handle->name, pack->files[i].name, sizeof(handle->name)); + handle->file = Q_fopen(pack->name, "rb"); - if (pack->pak) + if (handle->file) { - /* PAK */ - if (pack->isProtectedPak) - { - file_from_protected_pak = true; - } - - handle->file = Q_fopen(pack->name, "rb"); - - if (handle->file) - { - fseek(handle->file, pack->files[i].offset, SEEK_SET); - return pack->files[i].size; - } + fseek(handle->file, pack->files[i].offset, SEEK_SET); + return pack->files[i].size; } - else if (pack->pk3) + } + else if (pack->pk3) + { + /* PK3 */ + if (pack->isProtectedPak) { - /* PK3 */ - if (pack->isProtectedPak) - { - file_from_protected_pak = true; - } + file_from_protected_pak = true; + } #ifdef _WIN32 - handle->zip = unzOpen2(pack->name, &zlib_file_api); + handle->zip = unzOpen2(pack->name, &zlib_file_api); #else - handle->zip = unzOpen(pack->name); + handle->zip = unzOpen(pack->name); #endif - if (handle->zip) + if (handle->zip) + { + if (unzLocateFile(handle->zip, handle->name, 2) == UNZ_OK) { - if (unzLocateFile(handle->zip, handle->name, 2) == UNZ_OK) + if (unzOpenCurrentFile(handle->zip) == UNZ_OK) { - if (unzOpenCurrentFile(handle->zip) == UNZ_OK) - { - return pack->files[i].size; - } + return pack->files[i].size; } - - unzClose(handle->zip); } - } - Com_Error(ERR_FATAL, "Couldn't reopen '%s'", pack->name); + unzClose(handle->zip); + } } + + Com_Error(ERR_FATAL, "Couldn't reopen '%s'", pack->name); } } else @@ -543,8 +562,8 @@ FS_FOpenFile(const char *rawname, fileHandle_t *f, qboolean gamedir_only) { if (fs_debug->value) { - Com_Printf("FS_FOpenFile: '%s' (found in '%s').\n", - handle->name, search->path); + Com_Printf("%s: '%s' (found in '%s').\n", + __func__, handle->name, search->path); } return FS_FileLength(handle->file); @@ -553,7 +572,7 @@ FS_FOpenFile(const char *rawname, fileHandle_t *f, qboolean gamedir_only) } if (fs_debug->value) { - Com_Printf("FS_FOpenFile: couldn't find '%s'.\n", handle->name); + Com_Printf("%s: couldn't find '%s'.\n", __func__, handle->name); } /* Couldn't open, so free the handle. */ @@ -605,13 +624,15 @@ FS_Read(void *buffer, int size, fileHandle_t f) else { /* Already tried once. */ - Com_Error(ERR_FATAL, "FS_Read: 0 bytes read from '%s'", handle->name); + Com_Error(ERR_FATAL, "%s: 0 bytes read from '%s'", + __func__, handle->name); return size - remaining; } } else if (r == -1) { - Com_Error(ERR_FATAL, "FS_Read: -1 bytes read from '%s'", handle->name); + Com_Error(ERR_FATAL, "%s: -1 bytes read from '%s'", + __func__, handle->name); } remaining -= r; @@ -677,8 +698,8 @@ FS_FRead(void *buffer, int size, int count, fileHandle_t f) else if (r == -1) { Com_Error(ERR_FATAL, - "FS_FRead: -1 bytes read from '%s'", - handle->name); + "%s: -1 bytes read from '%s'", + __func__, handle->name); } remaining -= r; @@ -742,7 +763,8 @@ FS_FreeFile(void *buffer) Z_Free(buffer); } -fsRawPath_t *FS_FreeRawPaths(fsRawPath_t *start, fsRawPath_t *end) +static fsRawPath_t * +FS_FreeRawPaths(fsRawPath_t *start, fsRawPath_t *end) { fsRawPath_t *cur = start; fsRawPath_t *next; @@ -757,7 +779,8 @@ fsRawPath_t *FS_FreeRawPaths(fsRawPath_t *start, fsRawPath_t *end) return cur; } -fsSearchPath_t *FS_FreeSearchPaths(fsSearchPath_t *start, fsSearchPath_t *end) +static fsSearchPath_t * +FS_FreeSearchPaths(fsSearchPath_t *start, fsSearchPath_t *end) { fsSearchPath_t *cur = start; fsSearchPath_t *next; @@ -829,13 +852,13 @@ FS_LoadPAK(const char *packPath) { fclose(handle); Com_Error(ERR_FATAL, "%s: '%s' is too short.", - __func__, packPath); + __func__, packPath); } if (numFiles > MAX_FILES_IN_PACK) { Com_Printf("%s: '%s' has %i > %i files\n", - __func__, packPath, numFiles, MAX_FILES_IN_PACK); + __func__, packPath, numFiles, MAX_FILES_IN_PACK); } info = malloc(header.dirlen); @@ -853,7 +876,8 @@ FS_LoadPAK(const char *packPath) /* Parse the directory. */ for (i = 0; i < numFiles; i++) { - Q_strlcpy(files[i].name, info[i].name, sizeof(files[i].name)); + Q_strlcpy(files[i].name, info[i].name, + Q_min(sizeof(files[i].name), sizeof(files[i].name))); files[i].offset = LittleLong(info[i].filepos); files[i].size = LittleLong(info[i].filelen); } @@ -877,7 +901,7 @@ FS_LoadPAK(const char *packPath) * Loads the header and directory, adding the files at the beginning of the list * so they override previous pack files. */ -fsPack_t * +static fsPack_t * FS_LoadPK3(const char *packPath) { char fileName[MAX_QPATH]; /* File name. */ @@ -904,7 +928,7 @@ FS_LoadPK3(const char *packPath) if (unzGetGlobalInfo(handle, &global) != UNZ_OK) { unzClose(handle); - Com_Error(ERR_FATAL, "FS_LoadPK3: '%s' is not a pack file", packPath); + Com_Error(ERR_FATAL, "%s: '%s' is not a pack file", __func__, packPath); } numFiles = global.number_entry; @@ -924,7 +948,7 @@ FS_LoadPK3(const char *packPath) while (status == UNZ_OK) { fileName[0] = '\0'; - unzGetCurrentFileInfo(handle, &info, fileName, MAX_QPATH, + unzGetCurrentFileInfo(handle, &info, fileName, sizeof(fileName), NULL, 0, NULL, 0); Q_strlcpy(files[i].name, fileName, sizeof(files[i].name)); files[i].offset = -1; /* Not used in ZIP files */ @@ -979,7 +1003,7 @@ FS_NextPath(char *prevPath) return NULL; } -void +static void FS_Path_f(void) { int i; @@ -1035,7 +1059,7 @@ FS_Path_f(void) /* * Creates a filelink_t. */ -void +static void FS_Link_f(void) { fsLink_t *l, **prev; @@ -1149,7 +1173,7 @@ FS_ListFiles(char *findname, int *numfiles, * attributes then a copy of the matching string will be placed there (with * SFF_SUBDIR it changes). */ -qboolean +static qboolean ComparePackFiles(const char *findname, const char *name, unsigned musthave, unsigned canthave, char *output, int size) { @@ -1495,7 +1519,7 @@ FS_ListMods(int *nummods) /* * Directory listing. */ -void +static void FS_Dir_f(void) { char **dirnames; /* File list. */ @@ -1617,8 +1641,12 @@ FS_AddPAKFromGamedir(const char *pak) } else { + fsSearchPath_t *search; + + FS_SortPack(pakfile); + // Add it. - fsSearchPath_t *search = Z_Malloc(sizeof(fsSearchPath_t)); + search = Z_Malloc(sizeof(fsSearchPath_t)); search->pack = pakfile; search->next = fs_searchPaths; fs_searchPaths = search; @@ -1671,7 +1699,7 @@ static char* basename( char* n ) } #endif // _MSC_VER -void +static void FS_AddDirToSearchPath(char *dir, qboolean create) { char *file; char **list; @@ -1745,6 +1773,8 @@ FS_AddDirToSearchPath(char *dir, qboolean create) { continue; } + FS_SortPack(pack); + search = Z_Malloc(sizeof(fsSearchPath_t)); search->pack = pack; search->next = fs_searchPaths; @@ -1813,6 +1843,8 @@ FS_AddDirToSearchPath(char *dir, qboolean create) { continue; } + FS_SortPack(pack); + pack->isProtectedPak = false; search = Z_Malloc(sizeof(fsSearchPath_t)); @@ -1825,7 +1857,8 @@ FS_AddDirToSearchPath(char *dir, qboolean create) { } } -void FS_BuildGenericSearchPath(void) { +static void +FS_BuildGenericSearchPath(void) { // We may not use the va() function from shared.c // since it's buffersize is 1024 while most OS have // a maximum path size of 4096... @@ -2056,7 +2089,9 @@ static void FS_AddDirToRawPath (const char *rawdir, qboolean create, qboolean re } -void FS_BuildRawPath(void) { +static void +FS_BuildRawPath(void) +{ // Add $HOME/.yq2, MUST be the last dir! Required, // otherwise the config cannot be written. if (!is_portable) {