UFO: Alien Invasion
Doxygen documentation generating
files.cpp
Go to the documentation of this file.
1 
11 /*
12 Copyright (C) 1997-2001 Id Software, Inc.
13 
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License
16 as published by the Free Software Foundation; either version 2
17 of the License, or (at your option) any later version.
18 
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22 
23 See the GNU General Public License for more details.
24 
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, write to the Free Software
27 Foundation, 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 
42 static int fs_openedFiles;
45 #define MODS_DIR "mods"
46 
47 void FS_CreateOpenPipeFile (const char* filename, qFILE* f)
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 
68 const 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 
83 void 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 
117 void 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);
141  fs_openedFiles--;
142  } else if (f->z) {
144  fs_openedFiles--;
145  } else {
146  return;
147  }
148  assert(fs_openedFiles >= 0);
149 
150  f->f = nullptr;
151  f->z = nullptr;
152 }
153 
162 int 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) {
175  fs_openedFiles++;
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;
213  fs_openedFiles++;
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 
228  fs_openedFiles++;
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
239 
246 int 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);
260  unzOpenCurrentFile(f->z);
261  /* fall through */
262  case FS_SEEK_CUR:
263  while (remainder > PK3_SEEK_BUFFER_SIZE) {
264  FS_Read(buffer, PK3_SEEK_BUFFER_SIZE, f);
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 
298 int 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 */
312 
327 int 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 
371 int FS_Read (void* buffer, int len, qFILE* f)
372 {
373  return FS_Read2(buffer, len, f, true);
374 }
375 
384 int 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 
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 
411 void FS_FreeFile (void* buffer)
412 {
413  _Mem_Free(buffer, "FS_FreeFile", 0);
414 }
415 
422 static 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 
439  unzGoToFirstFile(uf);
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;
453  unzGoToFirstFile(uf);
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 
485 static char const* const pakFileExt[] = {
486  "pk3", "zip", nullptr
487 };
488 
495 void 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 
562 char** 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  }
574  Sys_FindClose();
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  }
600  Sys_FindClose();
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 
614 const 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 
631 static 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 
655 void 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
684  PKGDATADIR "/" MODS_DIR,
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 
713 static 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 }
729 void 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");
740  Sys_FindClose();
741  break;
742  }
743 
744  Sys_FindClose();
745  }
746 
747  Cbuf_Execute(); /* execute it */
748 }
749 
753 static 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  }
771  l->to = Mem_PoolStrDup(Cmd_Argv(2), com_fileSysPool, 0);
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 
791 static 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 
819 static 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);
828  FS_NextFileFromFileList(nullptr);
829 }
830 
834 static 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 
850 static void FS_RestartFilesystem_f (void)
851 {
852  if (Cmd_Argc() == 2)
854  else
855  FS_RestartFilesystem(nullptr);
856 }
857 
863 static 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 
874 static void FS_RemoveCommands (void)
875 {
876  Cmd_TableCheck();
877  Cmd_TableRemoveList(fs_commands);
878 }
879 
880 static void FS_InitCommandsAndCvars (void)
881 {
882  Cmd_TableAddList(fs_commands);
883 }
884 #endif
885 
890 void 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 
928 typedef struct listBlock_s {
929  char path[MAX_QPATH];
931  struct listBlock_s* next;
932 } listBlock_t;
933 
934 static listBlock_t* fs_blocklist = nullptr;
935 
941 static void _AddToListBlock (linkedList_t** fl, const char* name, bool stripPath)
942 {
943  const char* f;
944 
945  /* strip path */
946  if (stripPath)
947  f = Com_SkipPath(name);
948  else
949  f = name;
950 
951  if (LIST_ContainsString(*fl, f))
952  return;
953 
954  /* add the new file */
955  LIST_AddStringSorted(fl, f);
956 }
957 
962 int 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 
1081 const 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 
1137 const 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 
1196 char* 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 */
1315 static bool fs_mapsInstalledInit = false;
1316 
1320 static 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 
1344 static 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 
1375 void 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 
1389  fs_numInstalledMaps = -1;
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 
1497 int 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 
1513 int 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 
1546 int 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 
1570 const char* FS_GetCwd (void)
1571 {
1572  static char buf[MAX_OSPATH];
1573  Q_strncpyz(buf, Sys_Cwd(), sizeof(buf));
1574  FS_NormPath(buf);
1575  return buf;
1576 }
1577 
1583 bool 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 
1604 void 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;
1627  fs_numInstalledMaps = -1;
1628  fs_blocklist = nullptr;
1629 
1630 #ifdef COMPILE_UFO
1631  FS_RemoveCommands();
1632 #endif
1633 
1635 }
1636 
1643 void 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 
1654 void 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 
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 
1692 void 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 
1709 bool 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 BASEDIRNAME
Definition: filesys.h:34
char * Sys_GetHomeDirectory(void)
Returns the home environment variable (which hold the path of the user&#39;s homedir) ...
Definition: unix_files.cpp:45
const char * Cmd_Argv(int arg)
Returns a given argument.
Definition: cmd.cpp:516
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
char name[MAX_OSPATH]
Definition: filesys.h:57
char filename[MAX_OSPATH]
Definition: filesys.h:95
int ZEXPORT unzGetCurrentFileInfoPosition(unzFile file, unsigned long *pos)
Definition: unzip.cpp:1450
void FS_AddGameDirectory(const char *dir, bool write)
Adds the directory to the head of the search path.
Definition: files.cpp:495
int Q_vsnprintf(char *str, size_t size, const char *format, va_list ap)
Safe (null terminating) vsnprintf implementation.
Definition: shared.cpp:535
void Sys_Error(const char *error,...)
Definition: g_main.cpp:421
Definition: filesys.h:94
void Sys_Mkdir(const char *path)
Definition: unix_files.cpp:208
Definition: filesys.h:54
char path[MAX_QPATH]
Definition: files.cpp:929
int FS_CheckFile(const char *fmt,...)
Just returns the filelength and -1 if the file wasn&#39;t found.
Definition: files.cpp:298
bool write
Definition: filesys.h:104
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_ExecAutoexec(void)
const char * Com_SkipPath(const char *pathname)
Returns just the filename from a given path.
Definition: shared.cpp:37
static char const *const pakFileExt[]
Definition: files.cpp:485
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 * data
Definition: list.h:31
const char * Com_GetExtension(const char *path)
Definition: shared.cpp:282
const char * va(const char *format,...)
does a varargs printf into a temp buffer, so I don&#39;t need to have varargs versions of all text functi...
Definition: shared.cpp:410
void LIST_AddStringSorted(linkedList_t **listDest, const char *data)
Definition: list.cpp:107
struct searchpath_s * next
Definition: filesys.h:106
#define MAX_FILES
Definition: filesys.h:47
voidp unzFile
Definition: unzip.h:70
char name[MAX_QPATH]
Definition: filesys.h:89
int FS_Seek(qFILE *f, long offset, int origin)
Sets the file position of the given file.
Definition: files.cpp:246
#define UNZ_OK
Definition: unzip.h:74
pack_t * pack
Definition: filesys.h:103
static int CheckBSPFile(const char *filename)
Checks for valid BSP-file.
Definition: files.cpp:1344
voidpf uLong int origin
Definition: ioapi.h:45
#define PK3_SEEK_BUFFER_SIZE
Definition: files.cpp:238
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
void Com_StripExtension(const char *in, char *out, const size_t size)
Removes the file extension from a filename.
Definition: shared.cpp:259
bool FS_FileExists(const char *filename,...)
Checks whether a file exists (not in virtual filesystem)
Definition: files.cpp:1583
const char * filename
Definition: ioapi.h:41
int Sys_Rename(const char *oldname, const char *newname)
Definition: unix_files.cpp:250
int ZEXPORT unzGetGlobalInfo(unzFile file, unz_global_info *pglobal_info)
Definition: unzip.cpp:475
void Cbuf_AddText(const char *format,...)
Adds command text at the end of the buffer.
Definition: cmd.cpp:126
int ZEXPORT unzLocateFile(unzFile file, const char *szFileName, int iCaseSensitivity)
Definition: unzip.cpp:731
#define FILE
Definition: test_webapi.cpp:30
void FS_GetMaps(bool reset)
File the fs_maps array with valid maps.
Definition: files.cpp:1375
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 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
void FS_RestartFilesystem(const char *gamedir)
Restart the filesystem (reload all pk3 files)
Definition: files.cpp:1643
void FS_RemoveFile(const char *osPath)
Definition: files.cpp:1692
#define MAX_MAPS
Definition: filesys.h:37
int FS_LoadFile(const char *path, byte **buffer)
Filenames are relative to the quake search path.
Definition: files.cpp:384
unsigned long filepos
Definition: filesys.h:58
#define SFF_SYSTEM
Definition: filesys.h:127
#define MAX_OSPATH
Definition: filesys.h:44
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
static void _AddToListBlock(linkedList_t **fl, const char *name, bool stripPath)
Add one name to the filelist.
Definition: files.cpp:941
int FS_BuildFileList(const char *fileList)
Build a filelist.
Definition: files.cpp:962
#define PKGDATADIR
Definition: config_android.h:7
void LIST_Delete(linkedList_t **list)
Definition: list.cpp:195
int ZEXPORT unzGoToNextFile(unzFile file)
Definition: unzip.cpp:701
#define SFF_SUBDIR
Definition: filesys.h:126
void FS_CopyFile(const char *fromOSPath, const char *toOSPath)
Copy a fully specified file from one place to another.
Definition: files.cpp:1654
voidpf void * buf
Definition: ioapi.h:42
void Cmd_TableRemoveList(const cmdList_t *cmdList)
Definition: cmd.cpp:859
static char findname[MAX_OSPATH]
Definition: win_shared.cpp:167
int LIST_Count(const linkedList_t *list)
Definition: list.cpp:344
#define Q_strvalid(string)
Definition: shared.h:141
#define SFF_HIDDEN
Definition: filesys.h:124
static bool FS_GetHomeDirectory(char *gdir, size_t length)
Definition: files.cpp:631
char * Sys_FindFirst(const char *path, unsigned musthave, unsigned canthave)
Opens the directory and returns the first file that matches our searchrules.
Definition: unix_files.cpp:87
const char * FS_Gamedir(void)
Called to find where to write a file (savegames, etc)
Definition: files.cpp:68
char filename[MAX_OSPATH]
Definition: filesys.h:102
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
void FS_NormPath(char *path)
Convert operating systems path separators to ufo virtual filesystem separators (/) ...
Definition: files.cpp:83
int ZEXPORT unzGoToFirstFile(unzFile file)
Definition: unzip.cpp:681
void _Mem_Free(void *ptr, const char *fileName, const int fileLine)
Definition: mem.cpp:204
#define UFO_VERSION
Definition: common.h:36
uLong uncompressed_size
Definition: unzip.h:114
#define SEEK_END
Definition: ioapi.cpp:26
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
game_import_t gi
Definition: g_main.cpp:39
#define OBJZERO(obj)
Definition: shared.h:178
#define MAX_VAR
Definition: shared.h:36
unzFile ZEXPORT unzOpen(const char *path)
Definition: unzip.cpp:446
QGL_EXTERN GLuint GLsizei GLsizei * length
Definition: r_gl.h:110
int ZEXPORT unzCloseCurrentFile(unzFile file)
Definition: unzip.cpp:1333
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
int ZEXPORT unzSetCurrentFileInfoPosition(unzFile file, unsigned long pos)
Definition: unzip.cpp:1432
int Sys_Remove(const char *filename)
Definition: unix_files.cpp:245
#define MAX_PACKFILES
Definition: files.cpp:483
int FS_GetModList(linkedList_t **mods)
Searches and builds a list of mod directories.
Definition: files.cpp:669
void FS_AddHomeAsGameDirectory(const char *dir, bool write)
Definition: files.cpp:655
void FS_InitFilesystem(bool writeToHomeDir)
Definition: files.cpp:890
void Sys_FindClose(void)
Closes the find handle.
Definition: unix_files.cpp:142
filemode_t
Definition: filesys.h:110
#define MODS_DIR
Definition: files.cpp:45
int FS_WriteFile(const void *buffer, size_t len, const char *filename)
Definition: files.cpp:1546
int FS_Printf(qFILE *f, const char *msg,...)
Can print chunks for 1024 chars into a file.
Definition: files.cpp:1497
struct listBlock_s * next
Definition: files.cpp:931
linkedList_t * next
Definition: list.h:32
const char * FS_GetCwd(void)
Return current working dir.
Definition: files.cpp:1570
static int FS_MapDefSort(const void *map1, const void *map2)
Definition: files.cpp:1320
#define Q_strcasecmp(a, b)
Definition: shared.h:131
int fs_numInstalledMaps
Definition: files.cpp:1314
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
Header for various formats like pak, and model formats as well as bsp format.
#define Mem_FreePool(pool)
Definition: mem.h:37
char * Q_strlwr(char *str)
Converts a string to lowercase.
Definition: shared.cpp:438
void * z
Definition: filesys.h:55
static bool fs_mapsInstalledInit
Definition: files.cpp:1315
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
int FS_FileLength(qFILE *f)
Returns the size of a given file or -1 if no file is opened.
Definition: files.cpp:91
qFILE handle
Definition: filesys.h:96
#define Mem_PoolAllocTypeN(type, n, pool)
Definition: mem.h:42
char * fs_maps[MAX_MAPS]
Definition: files.cpp:1313
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 Sys_Mkfifo(const char *ospath, struct qFILE_s *f)
int FS_Read(void *buffer, int len, qFILE *f)
Definition: files.cpp:371
#define Q_strneq(a, b, n)
Definition: shared.h:137
bool FS_RenameFile(const char *from, const char *to, bool relative)
Renames a file.
Definition: files.cpp:1709
#define MAX_QPATH
Definition: filesys.h:40
QGL_EXTERN GLint i
Definition: r_gl.h:113
QGL_EXTERN GLuint GLchar GLuint * len
Definition: r_gl.h:99
char * Sys_FindNext(unsigned musthave, unsigned canthave)
Returns the next file of the already opened directory (Sys_FindFirst) that matches our search mask...
Definition: unix_files.cpp:125
const char * FS_GetFileData(const char *files)
Returns the buffer of a file.
Definition: files.cpp:1137
char * FS_NextScriptHeader(const char *files, const char **name, const char **text)
Definition: files.cpp:1196
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition: r_gl.h:110
int ZEXPORT unzOpenCurrentFile(unzFile file)
Definition: unzip.cpp:1064
void Cmd_TableCheck(void)
Check both the functiontable and the associated hashtable for invalid entries.
Definition: cmd.cpp:826
#define Mem_Free(ptr)
Definition: mem.h:35
const char int mode
Definition: ioapi.h:41
void Q_strcat(char *dest, size_t destsize, const char *format,...)
Safely (without overflowing the destination buffer) concatenates two strings.
Definition: shared.cpp:475
#define IDBSPHEADER
Definition: qfiles.h:251
linkedList_t * files
Definition: files.cpp:930
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 fs_openedFiles
Definition: files.cpp:42
#define LIST_Foreach(list, type, var)
Iterates over a linked list, it&#39;s safe to delete the returned entry from the list while looping over ...
Definition: list.h:41
int ZEXPORT unzClose(unzFile file)
Definition: unzip.cpp:456
void FS_CreateOpenPipeFile(const char *filename, qFILE *f)
Definition: files.cpp:47
packfile_t * files
Definition: filesys.h:98
definitions common between client and server, but not game lib
FILE * Sys_Fopen(const char *filename, const char *mode)
Definition: unix_files.cpp:240
int Sys_Access(const char *filename, int mode)
Definition: unix_files.cpp:255
static searchpath_t * fs_searchpaths
Definition: files.cpp:44
memPool_t * com_fileSysPool
Definition: common.cpp:72
int Q_StringSort(const void *string1, const void *string2)
Compare two strings.
Definition: shared.cpp:385
#define SEEK_CUR
Definition: ioapi.cpp:22
#define MAX_READ
Definition: files.cpp:311
const char * Cvar_GetString(const char *varName)
Returns the value of cvar as string.
Definition: cvar.cpp:210
#define Q_streq(a, b)
Definition: shared.h:136
#define Mem_PoolStrDup(in, pool, tagNum)
Definition: mem.h:50
#define BSPVERSION
Definition: qfiles.h:253
int numfiles
Definition: filesys.h:97
static filelink_t * fs_links
Definition: files.cpp:43
#define SEEK_SET
Definition: ioapi.cpp:30
void FS_CloseFile(qFILE *f)
Closes a file handle.
Definition: files.cpp:137
#define Mem_PoolAllocType(type, pool)
Definition: mem.h:43
voidpf uLong offset
Definition: ioapi.h:45
char * Sys_Cwd(void)
Get current working dir.
Definition: unix_files.cpp:197
void Sys_NormPath(char *path)
Normalize path (remove all \ )
Definition: unix_files.cpp:50
void Cbuf_Execute(void)
Pulls off terminated lines of text from the command buffer and sends them through Cmd_ExecuteString...
Definition: cmd.cpp:214
uLong compressed_size
Definition: unzip.h:113
unsigned long filelen
Definition: filesys.h:91
uint8_t byte
Definition: ufotypes.h:34
void Sys_ListFilteredFiles(const char *basedir, const char *subdirs, const char *filter, linkedList_t **list)
Definition: unix_files.cpp:151
void FS_CreatePath(const char *path)
Creates any directories needed to store the given filename.
Definition: files.cpp:117
static listBlock_t * fs_blocklist
Definition: files.cpp:934
void FS_Shutdown(void)
Cleanup function.
Definition: files.cpp:1604
char ** FS_ListFiles(const char *findname, int *numfiles, unsigned musthave, unsigned canthave)
Builds a qsorted filelist.
Definition: files.cpp:562
void Com_SkipBlock(const char **text)
Skips a block of {} in our script files.
Definition: parse.cpp:253
void Cmd_TableAddList(const cmdList_t *cmdList)
Definition: cmd.cpp:853
void FS_FreeFile(void *buffer)
Definition: files.cpp:411
#define LittleLong(X)
Definition: byte.h:37
int FS_Write(const void *buffer, int len, qFILE *f)
Properly handles partial writes.
Definition: files.cpp:1513
const char * FS_NextPath(const char *prevpath)
Allows enumerating all of the directories in the search path.
Definition: files.cpp:614
FILE * f
Definition: filesys.h:56
Definition: cmd.h:86
int ZEXPORT unzReadCurrentFile(unzFile file, voidp buf, unsigned len)
Definition: unzip.cpp:1089