UFO: Alien Invasion
Loading...
Searching...
No Matches
files.cpp
Go to the documentation of this file.
1
10
11/*
12Copyright (C) 1997-2001 Id Software, Inc.
13
14This program is free software; you can redistribute it and/or
15modify it under the terms of the GNU General Public License
16as published by the Free Software Foundation; either version 2
17of the License, or (at your option) any later version.
18
19This program is distributed in the hope that it will be useful,
20but WITHOUT ANY WARRANTY; without even the implied warranty of
21MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22
23See the GNU General Public License for more details.
24
25You should have received a copy of the GNU General Public License
26along with this program; if not, write to the Free Software
27Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28
29*/
30
31#include "common.h"
32#include "qfiles.h"
33#include "unzip.h"
34#include "../ports/system.h"
35#include "../shared/defines.h"
36#include "../shared/parse.h"
37#ifndef _MSC_VER
38#include <unistd.h>
39#endif
40
42static int fs_openedFiles;
45#define MODS_DIR "mods"
46
48{
49 if (fs_searchpaths == nullptr) {
50 Sys_Error("Filesystem call made without initialization");
51 }
52
53 OBJZERO(*f);
54
55 Q_strncpyz(f->name, filename, sizeof(f->name));
56 Sys_Mkfifo(va("%s/%s", FS_Gamedir(), filename), f);
57
58 if (f->f != nullptr) {
59 Com_Printf("created pipe %s\n", filename);
61 }
62}
63
68const char* FS_Gamedir (void)
69{
70 for (const searchpath_t* search = fs_searchpaths; search; search = search->next) {
71 if (search->write)
72 return search->filename;
73 }
74
75 return nullptr;
76}
77
83void FS_NormPath (char* path)
84{
85 Sys_NormPath(path);
86}
87
92{
93 if (f->f) {
94 const int pos = ftell(f->f);
95
96 fseek(f->f, 0, SEEK_END);
97 const int end = ftell(f->f);
98 fseek(f->f, pos, SEEK_SET);
99
100 return end;
101 } else if (f->z) {
102 unz_file_info info;
103 if (unzGetCurrentFileInfo(f->z, &info, nullptr, 0, nullptr, 0, nullptr, 0) != UNZ_OK)
104 Sys_Error("Couldn't get size of %s", f->name);
105 return info.uncompressed_size;
106 }
107
108 return -1;
109}
110
117void FS_CreatePath (const char* path)
118{
119 char pathCopy[MAX_OSPATH];
120
121 Q_strncpyz(pathCopy, path, sizeof(pathCopy));
122
123 for (char* ofs = pathCopy + 1; *ofs; ofs++) {
124 /* create the directory */
125 if (*ofs == '/') {
126 *ofs = 0;
127 Sys_Mkdir(pathCopy);
128 *ofs = '/';
129 }
130 }
131}
132
138{
139 if (f->f) {
140 fclose(f->f);
142 } else if (f->z) {
145 } else {
146 return;
147 }
148 assert(fs_openedFiles >= 0);
149
150 f->f = nullptr;
151 f->z = nullptr;
152}
153
162int FS_OpenFile (const char* filename, qFILE* file, filemode_t mode)
163{
164 char netpath[MAX_OSPATH];
165
166 file->z = file->f = nullptr;
167
168 /* open for write or append in gamedir and return */
169 if (mode == FILE_WRITE || mode == FILE_APPEND) {
170 Com_sprintf(netpath, sizeof(netpath), "%s/%s", FS_Gamedir(), filename);
171 FS_CreatePath(netpath);
172
173 file->f = Sys_Fopen(netpath, (mode == FILE_WRITE ? "wb" : "ab"));
174 if (file->f) {
176 return 0;
177 }
178
179 return -1;
180 }
181
182 Q_strncpyz(file->name, filename, sizeof(file->name));
183
184 /* check for links first */
185 for (const filelink_t* link = fs_links; link; link = link->next) {
186 if (!strncmp(filename, link->from, link->fromlength)) {
187 Com_sprintf(netpath, sizeof(netpath), "%s%s", link->to, filename + link->fromlength);
188 const int length = FS_OpenFile(netpath, file, mode);
189 Q_strncpyz(file->name, filename, sizeof(file->name));
190 if (length == -1)
191 Com_Printf("linked file could not be opened: %s\n", netpath);
192 return length;
193 }
194 }
195
196 /* search through the path, one element at a time */
197 for (const searchpath_t* search = fs_searchpaths; search; search = search->next) {
198 /* is the element a pak file? */
199 if (search->pack) {
200 /* look through all the pak file elements */
201 const pack_t* pak = search->pack;
202 for (int i = 0; i < pak->numfiles; i++) {
203 /* found it! */
204 if (!Q_strcasecmp(pak->files[i].name, filename)) {
205 /* open a new file on the pakfile */
206 if (unzLocateFile(pak->handle.z, filename, 2) == UNZ_OK) { /* found it! */
207 if (unzOpenCurrentFile(pak->handle.z) == UNZ_OK) {
208 unz_file_info info;
209 if (unzGetCurrentFileInfo(pak->handle.z, &info, nullptr, 0, nullptr, 0, nullptr, 0) != UNZ_OK)
210 Sys_Error("Couldn't get size of %s in %s", filename, pak->filename);
212 file->z = pak->handle.z;
214 return info.uncompressed_size;
215 }
216 }
217 return pak->files[i].filelen;
218 }
219 }
220 } else {
221 /* check a file in the directory tree */
222 Com_sprintf(netpath, sizeof(netpath), "%s/%s", search->filename, filename);
223
224 file->f = Sys_Fopen(netpath, "rb");
225 if (!file->f)
226 continue;
227
229 return FS_FileLength(file);
230 }
231 }
232
233 file->f = nullptr;
234 file->z = nullptr;
235 return -1;
236}
237
238#define PK3_SEEK_BUFFER_SIZE 65536
246int FS_Seek (qFILE* f, long offset, int origin)
247{
248 if (f->z) {
249 byte buffer[PK3_SEEK_BUFFER_SIZE];
250 int remainder = offset;
251
252 if (offset < 0 || origin == FS_SEEK_END) {
253 Sys_Error("Negative offsets and FS_SEEK_END not implemented "
254 "for FS_Seek on pk3 file contents\n");
255 }
256
257 switch (origin) {
258 case FS_SEEK_SET:
259 unzSetCurrentFileInfoPosition(f->z, (unsigned long)f->filepos);
261 /* fall through */
262 case FS_SEEK_CUR:
263 while (remainder > PK3_SEEK_BUFFER_SIZE) {
265 remainder -= PK3_SEEK_BUFFER_SIZE;
266 }
267 FS_Read(buffer, remainder, f);
268 return offset;
269
270 default:
271 Sys_Error("Bad origin in FS_Seek");
272 }
273 } else if (f->f) {
274 int _origin;
275 switch (origin) {
276 case FS_SEEK_CUR:
277 _origin = SEEK_CUR;
278 break;
279 case FS_SEEK_END:
280 _origin = SEEK_END;
281 break;
282 case FS_SEEK_SET:
283 _origin = SEEK_SET;
284 break;
285 default:
286 Sys_Error("Bad origin in FS_Seek");
287 }
288 return fseek(f->f, offset, _origin);
289 } else
290 Sys_Error("FS_Seek: no file opened");
291}
292
298int FS_CheckFile (const char* fmt, ...)
299{
300 va_list ap;
301 char filename[MAX_QPATH];
302
303 va_start(ap, fmt);
304 Q_vsnprintf(filename, sizeof(filename), fmt, ap);
305 va_end(ap);
306
307 ScopedFile file;
308 return FS_OpenFile(filename, &file, FILE_READ);
309}
310
311#define MAX_READ 0x10000 /* read in blocks of 64k */
327int FS_Read2 (void* buffer, int len, qFILE* f, bool failOnEmptyRead)
328{
329 byte* buf = (byte*) buffer;
330
331 if (f->z) {
332 const int read = unzReadCurrentFile(f->z, buf, len);
333 if (read == -1)
334 Sys_Error("FS_Read (zipfile): -1 bytes read");
335
336 return read;
337 }
338
339 int remaining = len;
340 int tries = 0;
341 while (remaining) {
342 int block = remaining;
343 if (block > MAX_READ)
344 block = MAX_READ;
345 const int read = fread(buf, 1, block, f->f);
346
347 /* end of file reached */
348 if (read != block && feof(f->f))
349 return (len - remaining + read);
350
351 if (read == 0) {
352 /* we might have been trying to read from a CD */
353 if (!tries)
354 tries = 1;
355 else if (failOnEmptyRead)
356 Sys_Error("FS_Read: 0 bytes read");
357 else
358 return len - remaining;
359 }
360
361 if (read == -1)
362 Sys_Error("FS_Read: -1 bytes read");
363
364 /* do some progress bar thing here... */
365 remaining -= read;
366 buf += read;
367 }
368 return len;
369}
370
371int FS_Read (void* buffer, int len, qFILE* f)
372{
373 return FS_Read2(buffer, len, f, true);
374}
375
384int FS_LoadFile (const char* path, byte** buffer)
385{
386 ScopedFile h;
387
388 /* look for it in the filesystem or pack files */
389 const int len = FS_OpenFile(path, &h, FILE_READ);
390 if (!h) {
391 if (buffer)
392 *buffer = nullptr;
393 return -1;
394 }
395
396 if (!buffer) {
397 return len;
398 }
399
400 byte* const buf = Mem_PoolAllocTypeN(byte, len + 1, com_fileSysPool);
401 if (!buf)
402 return -1;
403 *buffer = buf;
404
405 FS_Read(buf, len, &h);
406 buf[len] = 0;
407
408 return len;
409}
410
411void FS_FreeFile (void* buffer)
412{
413 _Mem_Free(buffer, "FS_FreeFile", 0);
414}
415
422static pack_t* FS_LoadPackFile (const char* packfile)
423{
424 const char* extension = Com_GetExtension(packfile);
425
426 if (Q_streq(extension, "pk3") || Q_streq(extension, "zip")) {
427 int i;
428 unz_file_info file_info;
430 unzFile uf = unzOpen(packfile);
431 unsigned int err = unzGetGlobalInfo(uf, &gi);
432 char filenameInZip[MAX_QPATH];
433
434 if (err != UNZ_OK) {
435 Com_Printf("Could not load '%s'\n", packfile);
436 return nullptr;
437 }
438
440 for (i = 0; i < gi.number_entry; i++) {
441 err = unzGetCurrentFileInfo(uf, &file_info, filenameInZip, sizeof(filenameInZip), nullptr, 0, nullptr, 0);
442 if (err != UNZ_OK) {
443 break;
444 }
445 unzGoToNextFile(uf);
446 }
447
449 Q_strncpyz(pack->filename, packfile, sizeof(pack->filename));
450 pack->handle.z = uf;
451 pack->handle.f = nullptr;
452 pack->numfiles = gi.number_entry;
454
455 /* Allocate space for array of packfile structures (filename, offset, length) */
457
458 for (i = 0; i < gi.number_entry; i++) {
459 err = unzGetCurrentFileInfo(uf, &file_info, filenameInZip, sizeof(filenameInZip), nullptr, 0, nullptr, 0);
460 if (err != UNZ_OK)
461 break;
462 Q_strlwr(filenameInZip);
463
464 unzGetCurrentFileInfoPosition(uf, &newfiles[i].filepos);
465 Q_strncpyz(newfiles[i].name, filenameInZip, sizeof(newfiles[i].name));
466 newfiles[i].filelen = file_info.compressed_size;
467 unzGoToNextFile(uf);
468 }
469 pack->files = newfiles;
470
471 /* Sort our list alphabetically - also rearrange the unsigned long values */
472 qsort((void*)pack->files, i, sizeof(*newfiles), Q_StringSort);
473
474 Com_Printf("Added packfile %s (%li files)\n", packfile, gi.number_entry);
475 return pack;
476 } else {
477 /* Unrecognized file type! */
478 Com_Printf("Pack file type %s unrecognized\n", extension);
479 return nullptr;
480 }
481}
482
483#define MAX_PACKFILES 1024
484
485static char const* const pakFileExt[] = {
486 "pk3", "zip", nullptr
487};
488
495void FS_AddGameDirectory (const char* dir, bool write)
496{
497 int ndirs = 0;
498 char pakfile_list[MAX_PACKFILES][MAX_OSPATH];
499 int pakfile_count = 0;
500 char pattern[MAX_OSPATH];
501
502 for (searchpath_t* search = fs_searchpaths; search; search = search->next) {
503 if (Q_streq(search->filename, dir))
504 return;
505 if (write && search->write) {
506 Com_Printf("change writing directory to %s\n", dir);
507 search->write = false;
508 }
509 }
510
511 Com_Printf("Adding game dir: %s\n", dir);
512
513 for (char const* const* extList = pakFileExt; *extList; ++extList) {
514 Com_sprintf(pattern, sizeof(pattern), "%s/*.%s", dir, *extList);
515 char** dirnames = FS_ListFiles(pattern, &ndirs, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM);
516 if (dirnames != nullptr) {
517 for (int i = 0; i < ndirs - 1; i++) {
518 if (strrchr(dirnames[i], '/')) {
519 Q_strncpyz(pakfile_list[pakfile_count], dirnames[i], sizeof(pakfile_list[pakfile_count]));
520 pakfile_count++;
521 if (pakfile_count >= MAX_PACKFILES) {
522 Com_Printf("Warning: Max allowed pakfiles reached (%i) - skipping the rest\n", MAX_PACKFILES);
523 break;
524 }
525 }
526 Mem_Free(dirnames[i]);
527 }
528 Mem_Free(dirnames);
529 }
530 }
531
532 /* Sort our list alphabetically */
533 qsort((void*)pakfile_list, pakfile_count, MAX_OSPATH, Q_StringSort);
534
535 for (int i = 0; i < pakfile_count; i++) {
536 pack_t* pak = FS_LoadPackFile(pakfile_list[i]);
537 if (!pak)
538 continue;
539
541 search->pack = pak;
542 search->next = fs_searchpaths;
543 search->write = false;
544 fs_searchpaths = search;
545 }
546
547 /* add the directory to the search path */
549 Q_strncpyz(search->filename, dir, sizeof(search->filename));
550 search->next = fs_searchpaths;
551 search->write = write;
552 fs_searchpaths = search;
553}
554
562char** FS_ListFiles (const char* findname, int* numfiles, unsigned musthave, unsigned canthave)
563{
564 int nfiles = 0;
565
566 *numfiles = 0;
567
568 char* s = Sys_FindFirst(findname, musthave, canthave);
569 while (s) {
570 if (s[strlen(s) - 1] != '.')
571 nfiles++;
572 s = Sys_FindNext(musthave, canthave);
573 }
575
576 if (!nfiles)
577 return nullptr;
578
579 nfiles++; /* add space for a guard */
580 *numfiles = nfiles;
581
582 char** const list = Mem_PoolAllocTypeN(char*, nfiles, com_fileSysPool);
583 char tempList[MAX_FILES][MAX_OSPATH];
584 OBJZERO(tempList);
585
586 s = Sys_FindFirst(findname, musthave, canthave);
587 nfiles = 0;
588 while (s) {
589 if (s[strlen(s) - 1] != '.') {
590 Q_strncpyz(tempList[nfiles], s, sizeof(tempList[nfiles]));
591#ifdef _WIN32
592 Q_strlwr(tempList[nfiles]);
593#endif
594 nfiles++;
595 if (nfiles >= MAX_FILES)
596 break;
597 }
598 s = Sys_FindNext(musthave, canthave);
599 }
601
602 qsort(tempList, nfiles, MAX_OSPATH, Q_StringSort);
603 for (int i = 0; i < nfiles; i++) {
604 list[i] = Mem_PoolStrDup(tempList[i], com_fileSysPool, 0);
605 }
606
607 return list;
608}
609
614const char* FS_NextPath (const char* prevpath)
615{
616 if (!prevpath)
617 return FS_Gamedir();
618
619 char* prev = nullptr;
620 for (searchpath_t* s = fs_searchpaths; s; s = s->next) {
621 if (s->pack)
622 continue;
623 if (prev && Q_streq(prevpath, prev))
624 return s->filename;
625 prev = s->filename;
626 }
627
628 return nullptr;
629}
630
631static bool FS_GetHomeDirectory (char* gdir, size_t length)
632{
633 const char* homedir = Sys_GetHomeDirectory();
634
635 if (homedir) {
636#ifdef _WIN32
637 Com_sprintf(gdir, length, "%s/" UFO_VERSION, homedir);
638#elif defined (__APPLE__) || defined (MACOSX)
639 Com_sprintf(gdir, length, "%s/Documents/UFOAI-" UFO_VERSION, homedir);
640#else
641 Com_sprintf(gdir, length, "%s/.ufoai/" UFO_VERSION, homedir);
642#endif
643 return true;
644 }
645 Com_Printf("could not find the home directory\n");
646 return false;
647}
648
655void FS_AddHomeAsGameDirectory (const char* dir, bool write)
656{
657 char gdir[MAX_OSPATH];
658
659 if (FS_GetHomeDirectory(gdir, sizeof(gdir))) {
660 Q_strcat(gdir, sizeof(gdir), "/%s", dir);
661 FS_CreatePath(va("%s/", gdir));
662 FS_AddGameDirectory(gdir, write);
663 }
664}
665
670{
671 char gdir[MAX_OSPATH];
672 const char* homedir;
673
674 if (FS_GetHomeDirectory(gdir, sizeof(gdir))) {
675 char const* const append = "/" MODS_DIR;
676 Q_strcat(gdir, sizeof(gdir), append);
677 homedir = gdir;
678 } else {
679 homedir = nullptr;
680 }
681
682 char const* searchpaths[] = {
683#ifdef PKGDATADIR
685#endif
686 "./" MODS_DIR,
687 homedir,
688 nullptr
689 };
690
692 int numberMods = 1;
693 /* it is likely that we have duplicate names now, which we will cleanup below */
694 for (const char** path = searchpaths; *path; path++) {
695 const char* pattern = *path;
696 int ndirs = 0;
697 char** dirnames = FS_ListFiles(va("%s/*", pattern), &ndirs, SFF_SUBDIR, SFF_HIDDEN | SFF_SYSTEM);
698 if (dirnames != nullptr) {
699 for (int i = 0; i < ndirs - 1; i++) {
700 LIST_AddString(mods, dirnames[i] + (strlen(pattern) + 1));
701 numberMods++;
702 Mem_Free(dirnames[i]);
703 }
704 Mem_Free(dirnames);
705 }
706 }
707
708 return numberMods;
709}
710
711#ifdef COMPILE_UFO
712
713static void FS_Mod_f (void)
714{
715 if (Cmd_Argc() == 1) {
716 linkedList_t* list = nullptr;
717 FS_GetModList(&list);
718 LIST_Foreach(list, const char, mod) {
719 Com_Printf("mod: %s\n", mod);
720 }
721 LIST_Delete(&list);
722 } else {
724 }
725}
729void FS_ExecAutoexec (void)
730{
731 /* search through all the paths for an autoexec.cfg file */
732 for (searchpath_t* s = fs_searchpaths; s != nullptr; s = s->next) {
733 char name[MAX_QPATH];
734 if (snprintf(name, sizeof(name), "%s/autoexec.cfg", s->filename)) {
735 continue;
736 }
737
739 Cbuf_AddText("exec autoexec.cfg\n");
741 break;
742 }
743
745 }
746
747 Cbuf_Execute(); /* execute it */
748}
749
753static void FS_Link_f (void)
754{
755 if (Cmd_Argc() != 3) {
756 Com_Printf("Usage: %s <from> <to>\n", Cmd_Argv(0));
757 return;
758 }
759
760 /* see if the link already exists */
761 filelink_t** prev = &fs_links;
762 for (filelink_t* l = fs_links; l; l = l->next) {
763 if (Q_streq(l->from, Cmd_Argv(1))) {
764 Mem_Free(l->to);
765 if (!strlen(Cmd_Argv(2))) { /* delete it */
766 *prev = l->next;
767 Mem_Free(l->from);
768 Mem_Free(l);
769 return;
770 }
772 return;
773 }
774 prev = &l->next;
775 }
776
777 /* create a new link */
779 l->next = fs_links;
780 fs_links = l;
782 l->fromlength = strlen(l->from);
784}
785
791static void FS_Dir_f (void)
792{
793 char const* wildcard = Cmd_Argc() != 1 ? Cmd_Argv(1) : "*.*";
794 const char* path = nullptr;
795 char findname[1024];
796 int ndirs;
797
798 while ((path = FS_NextPath(path)) != nullptr) {
799 Com_sprintf(findname, sizeof(findname), "%s/%s", path, wildcard);
801
802 Com_Printf("Directory of %s\n", findname);
803 Com_Printf("----\n");
804
805 char** dirnames = FS_ListFiles(findname, &ndirs, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM);
806 if (dirnames != nullptr) {
807 for (int i = 0; i < ndirs - 1; i++) {
808 char const* const slash = strrchr(dirnames[i], '/');
809 Com_Printf("%s\n", slash ? slash + 1 : dirnames[i]);
810
811 Mem_Free(dirnames[i]);
812 }
813 Mem_Free(dirnames);
814 }
815 Com_Printf("\n");
816 }
817}
818
819static void FS_List_f (void)
820{
821 char const* wildcard = Cmd_Argc() == 2 ? Cmd_Argv(1) : "*.*";
822 const char* filename;
823
824 Com_Printf("Show files for '%s'\n", wildcard);
825 FS_BuildFileList(wildcard);
826 while ((filename = FS_NextFileFromFileList(wildcard)) != nullptr)
827 Com_Printf("%s\n", filename);
829}
830
834static void FS_Info_f (void)
835{
836 Com_Printf("Filesystem information\n");
837 Com_Printf("...write dir: '%s'\n", FS_Gamedir());
838
839 for (searchpath_t* search = fs_searchpaths; search; search = search->next) {
840 if (search->pack == nullptr)
841 Com_Printf("...path: '%s'\n", search->filename);
842 else
843 Com_Printf("...pakfile: '%s' (%i files)\n", search->pack->filename, search->pack->numfiles);
844 }
845
846 for (filelink_t* l = fs_links; l; l = l->next)
847 Com_Printf("...link: %s : %s\n", l->from, l->to);
848}
849
850static void FS_RestartFilesystem_f (void)
851{
852 if (Cmd_Argc() == 2)
854 else
855 FS_RestartFilesystem(nullptr);
856}
857
863static const cmdList_t fs_commands[] = {
864 {"fs_restart", FS_RestartFilesystem_f, "Reloads the file subsystem"},
865 {"link", FS_Link_f, "Create file links"},
866 {"dir", FS_Dir_f, "Show the filesystem contents per game dir - also supports wildcarding"},
867 {"ls", FS_List_f, "Show the filesystem contents"},
868 {"fs_info", FS_Info_f, "Show information about the virtual filesystem"},
869 {"fs_mod", FS_Mod_f, "Show or activate mods"},
870
871 {nullptr, nullptr, nullptr}
872};
873
874static void FS_RemoveCommands (void)
875{
877 Cmd_TableRemoveList(fs_commands);
878}
879
880static void FS_InitCommandsAndCvars (void)
881{
882 Cmd_TableAddList(fs_commands);
883}
884#endif
885
890void FS_InitFilesystem (bool writeToHomeDir)
891{
892 Com_Printf("\n---- filesystem initialization -----\n");
893
894#ifdef PKGDATADIR
895 /* add the system search path */
897#endif
898
899 FS_AddGameDirectory("./" BASEDIRNAME, !writeToHomeDir);
900 FS_AddHomeAsGameDirectory(BASEDIRNAME, writeToHomeDir);
901#ifdef COMPILE_UFO
902 const char* fsGameDir = Cvar_GetString("fs_gamedir");
903 if (Q_strvalid(fsGameDir)) {
904 char path[MAX_QPATH];
905 Com_sprintf(path, sizeof(path), "./%s", fsGameDir);
906 if (!FS_FileExists("%s", path)) {
907 Com_sprintf(path, sizeof(path), "./" MODS_DIR "/%s", fsGameDir);
908 }
909 FS_AddGameDirectory(path, !writeToHomeDir);
910 FS_AddHomeAsGameDirectory(fsGameDir, writeToHomeDir);
911 }
912#endif
913
914#ifdef COMPILE_UFO
915 FS_InitCommandsAndCvars();
916 Cbuf_AddText("exec filesystem.cfg\n");
917#endif
918
919 Com_Printf("using %s for writing\n", FS_Gamedir());
920}
921
927
928typedef struct listBlock_s {
931 struct listBlock_s* next;
933
934static listBlock_t* fs_blocklist = nullptr;
935
941static void _AddToListBlock (linkedList_t** fl, const char* name, bool stripPath)
942{
943 const char* f;
944
945 /* strip path */
946 if (stripPath)
948 else
949 f = name;
950
951 if (LIST_ContainsString(*fl, f))
952 return;
953
954 /* add the new file */
956}
957
962int FS_BuildFileList (const char* fileList)
963{
964 char files[MAX_QPATH];
965
966 /* bring it into normal form */
967 Q_strncpyz(files, fileList, sizeof(files));
968 FS_NormPath(files);
969
970 /* check the blocklist for older searches
971 * and do a new one after deleting them */
972 for (listBlock_t** anchor = &fs_blocklist; *anchor;) {
973 listBlock_t* const block = *anchor;
974 if (Q_streq(block->path, files)) {
975 *anchor = block->next;
976
977 LIST_Delete(&block->files);
978 Mem_Free(block);
979 } else {
980 anchor = &block->next;
981 }
982 }
983
984 /* allocate a new block and link it into the list */
986 block->next = fs_blocklist;
987 fs_blocklist = block;
988
989 /* store the search string */
990 Q_strncpyz(block->path, files, sizeof(block->path));
991
992 /* search for the files */
993 LIST_Delete(&block->files);
994
995 /* search through the path, one element at a time */
996 char findname[1024];
997 for (searchpath_t* search = fs_searchpaths; search; search = search->next) {
998 /* is the element a pak file? */
999 if (search->pack) {
1000 const char* ext = strrchr(files, '.');
1001 const pack_t* pak = search->pack;
1002 size_t l = strlen(files);
1003 if (!ext)
1004 break;
1005 Q_strncpyz(findname, files, sizeof(findname));
1007 l -= (strlen(ext) + 1);
1008 findname[l] = '\0';
1009
1010 /* look through all the pak file elements */
1011 for (int i = 0; i < pak->numfiles; i++) {
1012 /* found it! */
1013 const char* fileNameEntry = pak->files[i].name;
1014 bool matchAlsoInSubDirs = (findname[0] == '*' || !strncmp(fileNameEntry, findname, l))
1015 && (ext[0] == '*' || strstr(fileNameEntry, ext));
1016 if (matchAlsoInSubDirs) {
1017 bool add = false;
1018 if (strstr(findname, "**"))
1019 add = true;
1020 else {
1021 char pathName[MAX_QPATH];
1022 char pathNameEntry[MAX_QPATH];
1023 Com_FilePath(findname, pathName, sizeof(pathName));
1024 Com_FilePath(fileNameEntry, pathNameEntry, sizeof(pathNameEntry));
1025 if (Q_streq(pathNameEntry, pathName))
1026 add = true;
1027 }
1028
1029 if (add)
1030 _AddToListBlock(&block->files, pak->files[i].name, true);
1031 }
1032 }
1033 } else if (strstr(files, "**")) {
1034 linkedList_t* list = nullptr;
1035 const char* wildcard = strstr(files, "**");
1036 const size_t l = strlen(files) - strlen(wildcard);
1037
1038 Q_strncpyz(findname, files, sizeof(findname));
1040 findname[l] = '\0';
1041 if (l > 0 && findname[l - 1] == '/')
1042 findname[l - 1] = '\0';
1043
1044 Sys_ListFilteredFiles(search->filename, findname, &findname[l + 1], &list);
1045
1046 LIST_Foreach(list, const char, name) {
1047 _AddToListBlock(&block->files, name, false);
1048 }
1049
1050 LIST_Delete(&list);
1051 } else {
1052 int nfiles = 0;
1053
1054 Com_sprintf(findname, sizeof(findname), "%s/%s", search->filename, files);
1056
1057 char** filenames = FS_ListFiles(findname, &nfiles, 0, SFF_HIDDEN | SFF_SYSTEM);
1058 if (filenames != nullptr) {
1059 for (int i = 0; i < nfiles - 1; i++) {
1060 _AddToListBlock(&block->files, filenames[i], true);
1061 Mem_Free(filenames[i]);
1062 }
1063 Mem_Free(filenames);
1064 }
1065 }
1066 }
1067
1068 return LIST_Count(block->files);
1069}
1070
1081const char* FS_NextFileFromFileList (const char* files)
1082{
1083 static linkedList_t* listEntry = nullptr;
1084 static listBlock_t* _block = nullptr;
1085
1086 /* restart the list? */
1087 if (files == nullptr) {
1088 _block = nullptr;
1089 return nullptr;
1090 }
1091
1092 listBlock_t* block;
1093 for (block = fs_blocklist; block; block = block->next) {
1094 if (!strncmp(files, block->path, MAX_QPATH))
1095 break;
1096 }
1097
1098 if (!block) {
1099 FS_BuildFileList(files);
1100 for (block = fs_blocklist; block; block = block->next) {
1101 if (!strncmp(files, block->path, MAX_QPATH))
1102 break;
1103 }
1104 if (!block) {
1105 /* still no filelist */
1106 Com_Printf("FS_NextFileFromFileList: Could not create filelist for %s\n", files);
1107 return nullptr;
1108 }
1109 }
1110
1111 /* everytime we switch between different blocks we get the
1112 * first file again when we switch back */
1113 if (_block != block) {
1114 _block = block;
1115 listEntry = block->files;
1116 }
1117
1118 const char* file = nullptr;
1119 if (listEntry) {
1120 file = (const char*)listEntry->data;
1121 listEntry = listEntry->next;
1122 }
1123
1124 /* finished */
1125 return file;
1126}
1127
1137const char* FS_GetFileData (const char* files)
1138{
1139 static linkedList_t* fileList = nullptr;
1140 static byte* buffer = nullptr;
1141
1142 /* free the old file */
1143 if (buffer) {
1144 FS_FreeFile(buffer);
1145 buffer = nullptr;
1146 }
1147
1148 if (!files) {
1149 fileList = nullptr;
1150 return nullptr;
1151 }
1152
1153 listBlock_t* block;
1154 for (block = fs_blocklist; block; block = block->next) {
1155 if (Q_streq(files, block->path))
1156 break;
1157 }
1158
1159 if (!block) {
1160 /* didn't find any valid file list */
1161 fileList = nullptr;
1162 FS_BuildFileList(files);
1163 for (block = fs_blocklist; block; block = block->next) {
1164 if (Q_streq(files, block->path))
1165 break;
1166 }
1167 if (!block) {
1168 /* still no filelist */
1169 Com_Printf("FS_GetFileData: Could not create filelist for %s\n", files);
1170 return nullptr;
1171 }
1172 }
1173
1174 if (!fileList)
1175 /* start the list */
1176 fileList = block->files;
1177 else
1178 /* search a new file */
1179 fileList = fileList->next;
1180
1181 if (fileList) {
1182 char filename[MAX_QPATH];
1183
1184 /* load a new file */
1185 Q_strncpyz(filename, block->path, sizeof(filename));
1186 strcpy(strrchr(filename, '/') + 1, (const char*)fileList->data);
1187
1188 FS_LoadFile(filename, &buffer);
1189 return (const char*)buffer;
1190 }
1191
1192 /* finished */
1193 return nullptr;
1194}
1195
1196char* FS_NextScriptHeader (const char* files, const char** name, const char** text)
1197{
1198 static char lastList[MAX_QPATH];
1199 static listBlock_t* lBlock;
1200 static linkedList_t* lFile;
1201 static byte* lBuffer;
1202 static char headerType[MAX_VAR];
1203 static char headerName[512];
1204
1205 if (!text) {
1206 *lastList = 0;
1207
1208 /* free the old file */
1209 if (lBuffer) {
1210 FS_FreeFile(lBuffer);
1211 lBuffer = nullptr;
1212 }
1213
1214 return nullptr;
1215 }
1216
1217 if (!Q_streq(files, lastList)) {
1218 /* search for file lists */
1219 Q_strncpyz(lastList, files, sizeof(lastList));
1220
1221 listBlock_t* block;
1222 for (block = fs_blocklist; block; block = block->next) {
1223 if (Q_streq(files, block->path))
1224 break;
1225 }
1226
1227 if (!block)
1228 /* didn't find any valid file list */
1229 return nullptr;
1230
1231 lBlock = block;
1232 lFile = block->files;
1233 }
1234
1235 while (lBlock) {
1236 if (lBuffer) {
1237 /* continue reading the current file */
1238 if (*text) {
1239 const char* token = Com_Parse(text);
1240 if (*token == '{') {
1241 Com_SkipBlock(text);
1242 continue;
1243 }
1244
1245 Q_strncpyz(headerType, token, sizeof(headerType));
1246 if (*text) {
1247 token = Com_Parse(text);
1248 Q_strncpyz(headerName, token, sizeof(headerName));
1249 *name = headerName;
1250 return headerType;
1251 }
1252 }
1253
1254 /* search a new file */
1255 lFile = lFile->next;
1256
1257 while (!lFile && lBlock) {
1258 /* it was the last file in the block, continue to next block */
1259 for (lBlock = lBlock->next; lBlock; lBlock = lBlock->next) {
1260 if (Q_streq(files, lBlock->path)) {
1261 lFile = lBlock->files;
1262 break;
1263 }
1264 }
1265 }
1266 }
1267
1268 if (lFile) {
1269 char filename[MAX_QPATH];
1270
1271 /* free the old file */
1272 if (lBuffer) {
1273 FS_FreeFile(lBuffer);
1274 lBuffer = nullptr;
1275 }
1276
1277 /* load a new file */
1278 Q_strncpyz(filename, lBlock->path, sizeof(filename));
1279 strcpy(strrchr(filename, '/') + 1, (const char*)lFile->data);
1280
1281 FS_LoadFile(filename, &lBuffer);
1282 /* skip a file that couldn't get loaded */
1283 if (!lBuffer) {
1284 lFile = lFile->next;
1285 continue;
1286 }
1287 *text = (char*)lBuffer;
1288
1289 /* test if the contents of this file starts with the string "--!usr/bin/lua", if yes, the
1290 file is a lua script file and should be returned immediately with type set to "lua" */
1291 if (Q_strneq (*text, "--!usr/bin/lua", 14)) {
1292 /* copy filename to header */
1293 Q_strncpyz(headerName, (const char*)lFile->data, sizeof(headerName));
1294 *name = headerName;
1295 static char luaType[] = "lua";
1296 return luaType;
1297 }
1298 } else if (!lBuffer)
1299 break;
1300 }
1301
1302 /* free the old file */
1303 if (lBuffer) {
1304 FS_FreeFile(lBuffer);
1305 lBuffer = nullptr;
1306 }
1307
1308 /* finished */
1309 return nullptr;
1310}
1311
1312/* global vars for maplisting */
1315static bool fs_mapsInstalledInit = false;
1316
1320static int FS_MapDefSort (const void* map1, const void* map2)
1321{
1322 const char* mapStr1 = *(const char* const*)map1;
1323 const char* mapStr2 = *(const char* const*)map2;
1324
1325 /* skip special map chars for rma and base attack */
1326 if (mapStr1[0] == '+')
1327 mapStr1++;
1328 if (mapStr2[0] == '+')
1329 mapStr2++;
1330
1331 return Q_StringSort(mapStr1, mapStr2);
1332}
1333
1344static int CheckBSPFile (const char* filename)
1345{
1346 /* load the file */
1347 char name[MAX_QPATH];
1348 Com_sprintf(name, sizeof(name), "maps/%s.bsp", filename);
1349
1350 ScopedFile file;
1351 FS_OpenFile(name, &file, FILE_READ);
1352 if (!file)
1353 return 1;
1354
1355 int header[2];
1356 FS_Read(header, sizeof(header), &file);
1357
1358 for (int i = 0; i < 2; i++)
1359 header[i] = LittleLong(header[i]);
1360
1361 if (header[0] != IDBSPHEADER)
1362 return 2;
1363 if (header[1] != BSPVERSION)
1364 return 3;
1365
1366 /* valid BSP-File */
1367 return 0;
1368}
1369
1375void FS_GetMaps (bool reset)
1376{
1377 char filename[MAX_QPATH];
1378 const char* baseMapName = nullptr;
1379 int ndirs;
1380
1381 /* force a reread */
1382 if (!reset && fs_mapsInstalledInit)
1383 return;
1384 else if (fs_mapsInstalledInit) {
1385 for (int i = 0; i <= fs_numInstalledMaps; i++)
1386 Mem_Free(fs_maps[i]);
1387 }
1388
1390
1391 /* search through the path, one element at a time */
1392 char findname[MAX_OSPATH];
1393 for (searchpath_t* search = fs_searchpaths; search; search = search->next) {
1394 /* is the element a pak file? */
1395 if (search->pack) {
1396 /* look through all the pak file elements */
1397 pack_t* pak = search->pack;
1398 for (int i = 0; i < pak->numfiles; i++) {
1399 /* found it! */
1400 baseMapName = strchr(pak->files[i].name, '/');
1401 if (baseMapName) {
1403 baseMapName = strchr(baseMapName + 1, '/');
1404 /* ugly hack - only show the maps in base/maps - not in base/maps/b and so on */
1405 if (baseMapName)
1406 continue;
1407 } else
1408 continue;
1409
1410 if (strstr(pak->files[i].name, ".bsp") || strstr(pak->files[i].name, ".ump") ) {
1411 if (fs_numInstalledMaps + 1 >= MAX_MAPS) {
1412 Com_Printf("FS_GetMaps: Max maps limit hit\n");
1413 break;
1414 }
1416 if (fs_maps[fs_numInstalledMaps + 1] == nullptr) {
1417 Com_Printf("Could not allocate memory in FS_GetMaps\n");
1418 continue;
1419 }
1420 Q_strncpyz(findname, pak->files[i].name, sizeof(findname));
1422 baseMapName = Com_SkipPath(findname);
1423 Com_StripExtension(baseMapName, filename, sizeof(filename));
1425 if (strstr(findname, ".ump"))
1427 else
1429 }
1430 }
1431 } else {
1432 Com_sprintf(findname, sizeof(findname), "%s/maps/*.bsp", search->filename);
1434
1435 char** dirnames = FS_ListFiles(findname, &ndirs, 0, SFF_HIDDEN | SFF_SYSTEM);
1436 if (dirnames != nullptr) {
1437 for (int i = 0; i < ndirs - 1; i++) {
1438 baseMapName = Com_SkipPath(dirnames[i]);
1439 Com_StripExtension(baseMapName, filename, sizeof(filename));
1440 const int status = CheckBSPFile(filename);
1441 if (!status) {
1442 if (fs_numInstalledMaps + 1 >= MAX_MAPS) {
1443 Com_Printf("FS_GetMaps: Max maps limit hit\n");
1444 break;
1445 }
1447 if (fs_maps[fs_numInstalledMaps + 1] == nullptr) {
1448 Com_Printf("Could not allocate memory in FS_GetMaps\n");
1449 Mem_Free(dirnames[i]);
1450 continue;
1451 }
1454 } else
1455 Com_Printf("invalid mapstatus: %i (%s)\n", status, dirnames[i]);
1456 Mem_Free(dirnames[i]);
1457 }
1458 Mem_Free(dirnames);
1459 }
1460 /* +RMA to maplisting */
1461 Com_sprintf(findname, sizeof(findname), "%s/maps/*.ump", search->filename);
1463
1464 dirnames = FS_ListFiles(findname, &ndirs, 0, SFF_HIDDEN | SFF_SYSTEM);
1465 if (dirnames != nullptr) {
1466 for (int i = 0; i < ndirs - 1; i++) {
1467 baseMapName = Com_SkipPath(dirnames[i]);
1468 Com_StripExtension(baseMapName, filename, sizeof(filename));
1469 if (fs_numInstalledMaps + 1 >= MAX_MAPS) {
1470 Com_Printf("FS_GetMaps: Max maps limit hit\n");
1471 break;
1472 }
1474 if (fs_maps[fs_numInstalledMaps + 1] == nullptr) {
1475 Com_Printf("Could not allocate memory in FS_GetMaps\n");
1476 Mem_Free(dirnames[i]);
1477 continue;
1478 }
1481 Mem_Free(dirnames[i]);
1482 }
1483 Mem_Free(dirnames);
1484 }
1485 }
1486 }
1487
1488 fs_mapsInstalledInit = true;
1489
1490 qsort(fs_maps, fs_numInstalledMaps + 1, sizeof(char*), FS_MapDefSort);
1491}
1492
1497int FS_Printf (qFILE* f, const char* msg, ...)
1498{
1499 va_list ap;
1500 char buf[1024];
1501
1502 va_start(ap, msg);
1503 Q_vsnprintf(buf, sizeof(buf), msg, ap);
1504 const int len = fprintf(f->f, "%s", buf);
1505 va_end(ap);
1506
1507 return len;
1508}
1509
1513int FS_Write (const void* buffer, int len, qFILE* f)
1514{
1515 if (!f->f)
1516 return 0;
1517
1518 const byte* buf = (const byte*) buffer;
1519
1520 int remaining = len;
1521 int tries = 0;
1522 while (remaining) {
1523 const int block = remaining;
1524 const int written = fwrite(buf, 1, block, f->f);
1525 if (written == 0) {
1526 if (!tries) {
1527 tries = 1;
1528 } else {
1529 Com_Printf("FS_Write: 0 bytes written\n");
1530 return 0;
1531 }
1532 }
1533
1534 if (written == -1) {
1535 Com_Printf("FS_Write: -1 bytes written\n");
1536 return 0;
1537 }
1538
1539 remaining -= written;
1540 buf += written;
1541 }
1542 return len;
1543}
1544
1545
1546int FS_WriteFile (const void* buffer, size_t len, const char* filename)
1547{
1548 ScopedFile f;
1550 if (!f)
1551 return 0;
1552
1553 const int c = FS_Write(buffer, len, &f);
1554 const int lencheck = FS_FileLength(&f);
1555
1556 /* if file write failed (file is incomplete) then delete it */
1557 if (c != len || lencheck != len) {
1558 Com_Printf("FS_WriteFile: failed to finish writing '%s'\n", filename);
1559 if (Sys_Remove(va("%s/%s", FS_Gamedir(), filename)))
1560 Com_Printf("FS_WriteFile: could not remove file: %s\n", filename);
1561 return 0;
1562 }
1563
1564 return c;
1565}
1566
1570const char* FS_GetCwd (void)
1571{
1572 static char buf[MAX_OSPATH];
1573 Q_strncpyz(buf, Sys_Cwd(), sizeof(buf));
1575 return buf;
1576}
1577
1583bool FS_FileExists (const char* filename, ...)
1584{
1585 char path[MAX_OSPATH];
1586 va_list ap;
1587
1588 va_start(ap, filename);
1589 Q_vsnprintf(path, sizeof(path), filename, ap);
1590 va_end(ap);
1591
1592#ifdef _WIN32
1593 return (Sys_Access(path, 00) == 0);
1594#else
1595 return (Sys_Access(path, R_OK) == 0);
1596#endif
1597}
1598
1604void FS_Shutdown (void)
1605{
1606 if (fs_openedFiles != 0) {
1607 Com_Printf("There are still %i opened files\n", fs_openedFiles);
1608 }
1609
1610 /* free everything */
1611 searchpath_t* next;
1612 for (searchpath_t* p = fs_searchpaths; p; p = next) {
1613 next = p->next;
1614
1615 if (p->pack) {
1616 unzClose(p->pack->handle.z);
1617 Mem_Free(p->pack->files);
1618 Mem_Free(p->pack);
1619 }
1620 Mem_Free(p);
1621 }
1622
1623 /* any FS_ calls will now be an error until reinitialized */
1624 fs_searchpaths = nullptr;
1625 fs_links = nullptr;
1626 fs_mapsInstalledInit = false;
1628 fs_blocklist = nullptr;
1629
1630#ifdef COMPILE_UFO
1631 FS_RemoveCommands();
1632#endif
1633
1635}
1636
1643void FS_RestartFilesystem (const char* gamedir)
1644{
1645 if (gamedir != nullptr)
1646 Com_Printf("restarting with gamedir set to %s\n", gamedir);
1647 throw comRestart_t(gamedir);
1648}
1649
1654void FS_CopyFile (const char* fromOSPath, const char* toOSPath)
1655{
1656 if (!fs_searchpaths)
1657 Sys_Error("Filesystem call made without initialization");
1658
1659 Com_Printf("FS_CopyFile: copy %s to %s\n", fromOSPath, toOSPath);
1660
1661 FILE* f = Sys_Fopen(fromOSPath, "rb");
1662 if (!f)
1663 return;
1664
1665 fseek(f, 0, SEEK_END);
1666 const int len = ftell(f);
1667 fseek(f, 0, SEEK_SET);
1668
1669 byte* const buf = Mem_PoolAllocTypeN(byte, len, com_fileSysPool);
1670 if (fread(buf, 1, len, f) != len)
1671 Sys_Error("Short read in FS_CopyFile");
1672 fclose(f);
1673
1674 FS_CreatePath(toOSPath);
1675
1676 f = Sys_Fopen(toOSPath, "wb");
1677 if (!f) {
1678 Mem_Free(buf);
1679 return;
1680 }
1681
1682 if (fwrite(buf, 1, len, f) != len)
1683 Sys_Error("Short write in FS_CopyFile");
1684
1685 fclose(f);
1686 Mem_Free(buf);
1687}
1688
1692void FS_RemoveFile (const char* osPath)
1693{
1694 if (!fs_searchpaths)
1695 Sys_Error("Filesystem call made without initialization");
1696
1697 Com_Printf("FS_RemoveFile: remove %s\n", osPath);
1698 Sys_Remove(osPath);
1699}
1700
1709bool FS_RenameFile (const char* from, const char* to, bool relative)
1710{
1711 char from_buf[MAX_OSPATH];
1712 char to_buf[MAX_OSPATH];
1713
1714 if (!fs_searchpaths)
1715 Sys_Error("Filesystem call made without initialization");
1716
1717 if (relative) {
1718 Com_sprintf(from_buf, sizeof(from_buf), "%s/%s", FS_Gamedir(), from);
1719 Com_sprintf(to_buf, sizeof(to_buf), "%s/%s", FS_Gamedir(), to);
1720 from = from_buf;
1721 to = to_buf;
1722 }
1723
1724 return Sys_Rename(from, to) == 0;
1725}
#define LittleLong(X)
Definition byte.h:37
const char * Cmd_Argv(int arg)
Returns a given argument.
Definition cmd.cpp:516
void Cmd_TableAddList(const cmdList_t *cmdList)
Definition cmd.cpp:853
void Cbuf_Execute(void)
Pulls off terminated lines of text from the command buffer and sends them through Cmd_ExecuteString...
Definition cmd.cpp:214
void Cmd_TableCheck(void)
Check both the functiontable and the associated hashtable for invalid entries.
Definition cmd.cpp:826
int Cmd_Argc(void)
Return the number of arguments of the current command. "command parameter" will result in a argc of 2...
Definition cmd.cpp:505
void Cbuf_AddText(const char *format,...)
Adds command text at the end of the buffer.
Definition cmd.cpp:126
void Cmd_TableRemoveList(const cmdList_t *cmdList)
Definition cmd.cpp:859
void Com_Printf(const char *const fmt,...)
Definition common.cpp:428
memPool_t * com_fileSysPool
Definition common.cpp:71
definitions common between client and server, but not game lib
#define UFO_VERSION
Definition common.h:36
#define PKGDATADIR
const char * Cvar_GetString(const char *varName)
Returns the value of cvar as string.
Definition cvar.cpp:210
Defined CONSTANTS (Macros are elsewhere).
static listBlock_t * fs_blocklist
Definition files.cpp:934
#define MAX_READ
Definition files.cpp:311
int FS_Seek(qFILE *f, long offset, int origin)
Sets the file position of the given file.
Definition files.cpp:246
const char * FS_GetFileData(const char *files)
Returns the buffer of a file.
Definition files.cpp:1137
void FS_CreatePath(const char *path)
Creates any directories needed to store the given filename.
Definition files.cpp:117
int FS_Read2(void *buffer, int len, qFILE *f, bool failOnEmptyRead)
Read a file into a given buffer in memory.
Definition files.cpp:327
static int CheckBSPFile(const char *filename)
Checks for valid BSP-file.
Definition files.cpp:1344
int fs_numInstalledMaps
Definition files.cpp:1314
static void _AddToListBlock(linkedList_t **fl, const char *name, bool stripPath)
Add one name to the filelist.
Definition files.cpp:941
const char * FS_NextPath(const char *prevpath)
Allows enumerating all of the directories in the search path.
Definition files.cpp:614
static char const *const pakFileExt[]
Definition files.cpp:485
static bool fs_mapsInstalledInit
Definition files.cpp:1315
int FS_Printf(qFILE *f, const char *msg,...)
Can print chunks for 1024 chars into a file.
Definition files.cpp:1497
#define PK3_SEEK_BUFFER_SIZE
Definition files.cpp:238
void FS_InitFilesystem(bool writeToHomeDir)
Definition files.cpp:890
void FS_RemoveFile(const char *osPath)
Definition files.cpp:1692
int FS_Write(const void *buffer, int len, qFILE *f)
Properly handles partial writes.
Definition files.cpp:1513
int FS_CheckFile(const char *fmt,...)
Just returns the filelength and -1 if the file wasn't found.
Definition files.cpp:298
int FS_LoadFile(const char *path, byte **buffer)
Filenames are relative to the quake search path.
Definition files.cpp:384
static searchpath_t * fs_searchpaths
Definition files.cpp:44
#define MAX_PACKFILES
Definition files.cpp:483
void FS_CopyFile(const char *fromOSPath, const char *toOSPath)
Copy a fully specified file from one place to another.
Definition files.cpp:1654
char * FS_NextScriptHeader(const char *files, const char **name, const char **text)
Definition files.cpp:1196
void FS_FreeFile(void *buffer)
Definition files.cpp:411
int FS_GetModList(linkedList_t **mods)
Searches and builds a list of mod directories.
Definition files.cpp:669
const char * FS_NextFileFromFileList(const char *files)
Returns the next file that is found in the virtual filesystem identified by the given file pattern.
Definition files.cpp:1081
void FS_AddHomeAsGameDirectory(const char *dir, bool write)
Definition files.cpp:655
int FS_WriteFile(const void *buffer, size_t len, const char *filename)
Definition files.cpp:1546
static int FS_MapDefSort(const void *map1, const void *map2)
Definition files.cpp:1320
void FS_RestartFilesystem(const char *gamedir)
Restart the filesystem (reload all pk3 files).
Definition files.cpp:1643
bool FS_RenameFile(const char *from, const char *to, bool relative)
Renames a file.
Definition files.cpp:1709
char ** FS_ListFiles(const char *findname, int *numfiles, unsigned musthave, unsigned canthave)
Builds a qsorted filelist.
Definition files.cpp:562
int FS_FileLength(qFILE *f)
Returns the size of a given file or -1 if no file is opened.
Definition files.cpp:91
void FS_CloseFile(qFILE *f)
Closes a file handle.
Definition files.cpp:137
static bool FS_GetHomeDirectory(char *gdir, size_t length)
Definition files.cpp:631
const char * FS_GetCwd(void)
Return current working dir.
Definition files.cpp:1570
int FS_Read(void *buffer, int len, qFILE *f)
Definition files.cpp:371
void FS_Shutdown(void)
Cleanup function.
Definition files.cpp:1604
void FS_CreateOpenPipeFile(const char *filename, qFILE *f)
Definition files.cpp:47
static filelink_t * fs_links
Definition files.cpp:43
int FS_OpenFile(const char *filename, qFILE *file, filemode_t mode)
Finds and opens the file in the search path.
Definition files.cpp:162
void FS_NormPath(char *path)
Convert operating systems path separators to ufo virtual filesystem separators (/).
Definition files.cpp:83
static pack_t * FS_LoadPackFile(const char *packfile)
Takes an explicit (not game tree related) path to a pak file. Adding the files at the beginning of th...
Definition files.cpp:422
void FS_GetMaps(bool reset)
File the fs_maps array with valid maps.
Definition files.cpp:1375
const char * FS_Gamedir(void)
Called to find where to write a file (savegames, etc).
Definition files.cpp:68
void FS_AddGameDirectory(const char *dir, bool write)
Adds the directory to the head of the search path.
Definition files.cpp:495
int FS_BuildFileList(const char *fileList)
Build a filelist.
Definition files.cpp:962
static int fs_openedFiles
Definition files.cpp:42
bool FS_FileExists(const char *filename,...)
Checks whether a file exists (not in virtual filesystem).
Definition files.cpp:1583
#define MODS_DIR
Definition files.cpp:45
char * fs_maps[MAX_MAPS]
Definition files.cpp:1313
#define MAX_OSPATH
Definition filesys.h:44
#define MAX_FILES
Definition filesys.h:47
#define SFF_HIDDEN
Definition filesys.h:124
#define BASEDIRNAME
Definition filesys.h:34
#define SFF_SUBDIR
Definition filesys.h:126
void FS_ExecAutoexec(void)
#define MAX_MAPS
Definition filesys.h:37
#define MAX_QPATH
Definition filesys.h:40
filemode_t
Definition filesys.h:110
@ FILE_APPEND
Definition filesys.h:111
@ FILE_READ
Definition filesys.h:111
@ FILE_WRITE
Definition filesys.h:111
#define SFF_SYSTEM
Definition filesys.h:127
@ FS_SEEK_END
Definition filesys.h:76
@ FS_SEEK_CUR
Definition filesys.h:75
@ FS_SEEK_SET
Definition filesys.h:77
game_import_t gi
Definition g_main.cpp:39
void Sys_Error(const char *error,...)
Definition g_main.cpp:421
#define SEEK_SET
Definition ioapi.cpp:30
#define SEEK_CUR
Definition ioapi.cpp:22
#define SEEK_END
Definition ioapi.cpp:26
voidpf uLong int origin
Definition ioapi.h:45
const char * filename
Definition ioapi.h:41
voidpf void * buf
Definition ioapi.h:42
const char int mode
Definition ioapi.h:41
voidpf uLong offset
Definition ioapi.h:45
void LIST_AddStringSorted(linkedList_t **listDest, const char *data)
Definition list.cpp:107
void LIST_AddString(linkedList_t **listDest, const char *data)
Adds an string to a new or to an already existing linked list. The string is copied here.
Definition list.cpp:139
void LIST_Delete(linkedList_t **list)
Definition list.cpp:195
int LIST_Count(const linkedList_t *list)
Definition list.cpp:344
const linkedList_t * LIST_ContainsString(const linkedList_t *list, const char *string)
Searches for the first occurrence of a given string.
Definition list.cpp:73
#define LIST_Foreach(list, type, var)
Iterates over a linked list, it's safe to delete the returned entry from the list while looping over ...
Definition list.h:41
void _Mem_Free(void *ptr, const char *fileName, const int fileLine)
Definition mem.cpp:204
#define Mem_FreePool(pool)
Definition mem.h:37
#define Mem_PoolAllocTypeN(type, n, pool)
Definition mem.h:42
#define Mem_Free(ptr)
Definition mem.h:35
#define Mem_PoolStrDup(in, pool, tagNum)
Definition mem.h:50
#define Mem_PoolAllocType(type, pool)
Definition mem.h:43
const char * Com_Parse(const char *data_p[], char *target, size_t size, bool replaceWhitespaces)
Parse a token out of a string.
Definition parse.cpp:107
void Com_SkipBlock(const char **text)
Skips a block of {} in our script files.
Definition parse.cpp:253
Shared parsing functions.
Header for various formats like pak, and model formats as well as bsp format.
#define IDBSPHEADER
Definition qfiles.h:251
#define BSPVERSION
Definition qfiles.h:253
QGL_EXTERN GLuint GLchar GLuint * len
Definition r_gl.h:99
QGL_EXTERN GLuint GLsizei GLsizei * length
Definition r_gl.h:110
QGL_EXTERN GLfloat f
Definition r_gl.h:114
QGL_EXTERN GLint i
Definition r_gl.h:113
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition r_gl.h:110
#define Q_strvalid(string)
Definition shared.h:141
#define Q_strcasecmp(a, b)
Definition shared.h:131
#define Q_streq(a, b)
Definition shared.h:136
#define Q_strneq(a, b, n)
Definition shared.h:137
#define OBJZERO(obj)
Definition shared.h:178
#define MAX_VAR
Definition shared.h:36
char * Q_strlwr(char *str)
Converts a string to lowercase.
Definition shared.cpp:438
void Com_StripExtension(const char *in, char *out, const size_t size)
Removes the file extension from a filename.
Definition shared.cpp:259
const char * Com_SkipPath(const char *pathname)
Returns just the filename from a given path.
Definition shared.cpp:37
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition shared.cpp:457
int Q_StringSort(const void *string1, const void *string2)
Compare two strings.
Definition shared.cpp:385
void Com_FilePath(const char *in, char *out, size_t size)
Returns the path up to, but not including the last /.
Definition shared.cpp:319
int Q_vsnprintf(char *str, size_t size, const char *format, va_list ap)
Safe (null terminating) vsnprintf implementation.
Definition shared.cpp:535
const char * Com_GetExtension(const char *path)
Definition shared.cpp:282
void Q_strcat(char *dest, size_t destsize, const char *format,...)
Safely (without overflowing the destination buffer) concatenates two strings.
Definition shared.cpp:475
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition shared.cpp:494
const char * va(const char *format,...)
does a varargs printf into a temp buffer, so I don't need to have varargs versions of all text functi...
Definition shared.cpp:410
void * data
Definition list.h:31
linkedList_t * next
Definition list.h:32
linkedList_t * files
Definition files.cpp:930
char path[MAX_QPATH]
Definition files.cpp:929
struct listBlock_s * next
Definition files.cpp:931
int numfiles
Definition filesys.h:97
qFILE handle
Definition filesys.h:96
char filename[MAX_OSPATH]
Definition filesys.h:95
packfile_t * files
Definition filesys.h:98
char name[MAX_QPATH]
Definition filesys.h:89
unsigned long filelen
Definition filesys.h:91
char name[MAX_OSPATH]
Definition filesys.h:57
void * z
Definition filesys.h:55
FILE * f
Definition filesys.h:56
unsigned long filepos
Definition filesys.h:58
pack_t * pack
Definition filesys.h:103
struct searchpath_s * next
Definition filesys.h:106
char filename[MAX_OSPATH]
Definition filesys.h:102
uLong compressed_size
Definition unzip.h:113
uLong uncompressed_size
Definition unzip.h:114
System specific stuff.
char * Sys_Cwd(void)
Get current working dir.
void Sys_NormPath(char *path)
Normalize path (remove all \ ).
FILE * Sys_Fopen(const char *filename, const char *mode)
int Sys_Remove(const char *filename)
int Sys_Rename(const char *oldname, const char *newname)
char * Sys_GetHomeDirectory(void)
Returns the home environment variable (which hold the path of the user's homedir).
void Sys_ListFilteredFiles(const char *basedir, const char *subdirs, const char *filter, linkedList_t **list)
char * Sys_FindFirst(const char *path, unsigned musthave, unsigned canthave)
Opens the directory and returns the first file that matches our searchrules.
void Sys_Mkdir(const char *path)
void Sys_FindClose(void)
Closes the find handle.
void Sys_Mkfifo(const char *ospath, struct qFILE_s *f)
int Sys_Access(const char *filename, int mode)
char * Sys_FindNext(unsigned musthave, unsigned canthave)
Returns the next file of the already opened directory (Sys_FindFirst) that matches our search mask.
#define FILE
int ZEXPORT unzLocateFile(unzFile file, const char *szFileName, int iCaseSensitivity)
Definition unzip.cpp:731
unzFile ZEXPORT unzOpen(const char *path)
Definition unzip.cpp:446
int ZEXPORT unzGoToFirstFile(unzFile file)
Definition unzip.cpp:681
int ZEXPORT unzSetCurrentFileInfoPosition(unzFile file, unsigned long pos)
Definition unzip.cpp:1432
int ZEXPORT unzOpenCurrentFile(unzFile file)
Definition unzip.cpp:1064
int ZEXPORT unzGetCurrentFileInfoPosition(unzFile file, unsigned long *pos)
Definition unzip.cpp:1450
int ZEXPORT unzReadCurrentFile(unzFile file, voidp buf, unsigned len)
Definition unzip.cpp:1089
int ZEXPORT unzCloseCurrentFile(unzFile file)
Definition unzip.cpp:1333
int ZEXPORT unzGetCurrentFileInfo(unzFile file, unz_file_info *pfile_info, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize)
Definition unzip.cpp:669
int ZEXPORT unzGoToNextFile(unzFile file)
Definition unzip.cpp:701
int ZEXPORT unzGetGlobalInfo(unzFile file, unz_global_info *pglobal_info)
Definition unzip.cpp:475
int ZEXPORT unzClose(unzFile file)
Definition unzip.cpp:456
voidp unzFile
Definition unzip.h:70
#define UNZ_OK
Definition unzip.h:74
static char findname[MAX_OSPATH]