FS2_Open
Open source remastering of the Freespace 2 engine
cfilesystem.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) Volition, Inc. 1999. All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9 
10 
11 
12 #include <stdlib.h>
13 #include <string.h>
14 #include <stdio.h>
15 #include <errno.h>
16 #include <sstream>
17 #include <algorithm>
18 
19 #ifdef _WIN32
20 #include <io.h>
21 #include <direct.h>
22 #include <windows.h>
23 #include <winbase.h> /* needed for memory mapping of file functions */
24 #endif
25 
26 #ifdef SCP_UNIX
27 #include <glob.h>
28 #include <sys/types.h>
29 #include <dirent.h>
30 #include <fnmatch.h>
31 #include <sys/stat.h>
32 #include <unistd.h>
33 #endif
34 
35 #include "cfile/cfile.h"
36 #include "cfile/cfilesystem.h"
37 #include "cmdline/cmdline.h"
38 #include "globalincs/pstypes.h"
39 #include "localization/localize.h"
40 
41 
42 #define CF_ROOTTYPE_PATH 0
43 #define CF_ROOTTYPE_PACK 1
44 
45 // for a defined and specifically set location to get/send pilot/campaign files
46 char *Pilot_file_path = NULL;
47 
48 // Created by:
49 // specifying hard drive tree
50 // searching for pack files on hard drive // Found by searching all known paths
51 // specifying cd-rom tree
52 // searching for pack files on CD-rom tree
53 typedef struct cf_root {
54  char path[CF_MAX_PATHNAME_LENGTH]; // Contains something like c:\projects\freespace or c:\projects\freespace\freespace.vp
55  int roottype; // CF_ROOTTYPE_PATH = Path, CF_ROOTTYPE_PACK =Pack file
56 } cf_root;
57 
58 // convenient type for sorting (see cf_build_pack_list())
59 typedef struct cf_root_sort {
61  int roottype;
62  int cf_type;
63 } cf_root_sort;
64 
65 #define CF_NUM_ROOTS_PER_BLOCK 32
66 #define CF_MAX_ROOT_BLOCKS 256 // Can store 32*256 = 8192 Roots
67 #define CF_MAX_ROOTS (CF_NUM_ROOTS_PER_BLOCK * CF_MAX_ROOT_BLOCKS)
68 
69 typedef struct cf_root_block {
72 
73 static int Num_roots = 0;
74 static cf_root_block *Root_blocks[CF_MAX_ROOT_BLOCKS];
75 
76 static int Num_path_roots = 0;
77 
78 // Created by searching all roots in order. This means Files is then sorted by precedence.
79 typedef struct cf_file {
80  char name_ext[CF_MAX_FILENAME_LENGTH]; // Filename and extension
81  int root_index; // Where in Roots this is located
82  int pathtype_index; // Where in Paths this is located
83  time_t write_time; // When it was last written
84  int size; // How big it is in bytes
85  int pack_offset; // For pack files, where it is at. 0 if not in a pack file. This can be used to tell if in a pack file.
86 } cf_file;
87 
88 #define CF_NUM_FILES_PER_BLOCK 512
89 #define CF_MAX_FILE_BLOCKS 128 // Can store 512*128 = 65536 files
90 
91 typedef struct cf_file_block {
94 
95 static uint Num_files = 0;
96 static cf_file_block *File_blocks[CF_MAX_FILE_BLOCKS];
97 
98 
99 // Return a pointer to to file 'index'.
101 {
102  int block = index / CF_NUM_FILES_PER_BLOCK;
103  int offset = index % CF_NUM_FILES_PER_BLOCK;
104 
105  return &File_blocks[block]->files[offset];
106 }
107 
108 // Create a new file and return a pointer to it.
110 {
111  Assertion(Num_files < CF_NUM_FILES_PER_BLOCK * CF_MAX_FILE_BLOCKS, "Too many files found. CFile cannot handle more than %d files.\n", CF_NUM_FILES_PER_BLOCK * CF_MAX_FILE_BLOCKS);
112 
115 
116  if ( File_blocks[block] == NULL ) {
117  File_blocks[block] = (cf_file_block *)vm_malloc( sizeof(cf_file_block) );
118  Assert( File_blocks[block] != NULL);
119  }
120 
121  Num_files++;
122 
123  return &File_blocks[block]->files[offset];
124 }
125 
126 extern int cfile_inited;
127 
128 // Create a new root and return a pointer to it. The structure is assumed unitialized.
130 {
131  int block = n / CF_NUM_ROOTS_PER_BLOCK;
132  int offset = n % CF_NUM_ROOTS_PER_BLOCK;
133 
134  if (!cfile_inited)
135  return NULL;
136 
137  return &Root_blocks[block]->roots[offset];
138 }
139 
140 
141 // Create a new root and return a pointer to it. The structure is assumed unitialized.
143 {
144  int block = Num_roots / CF_NUM_ROOTS_PER_BLOCK;
145  int offset = Num_roots % CF_NUM_ROOTS_PER_BLOCK;
146 
147  if ( Root_blocks[block] == NULL ) {
148  Root_blocks[block] = (cf_root_block *)vm_malloc( sizeof(cf_root_block) );
149  Assert(Root_blocks[block] != NULL);
150  }
151 
152  Num_roots++;
153 
154  return &Root_blocks[block]->roots[offset];
155 }
156 
157 // return the # of packfiles which exist
159 {
160  SCP_string filespec;
161  int i;
162  int packfile_count;
163 
164  // count up how many packfiles we're gonna have
165  packfile_count = 0;
166  for (i=CF_TYPE_ROOT; i<CF_MAX_PATH_TYPES; i++ )
167  {
168  filespec = root->path;
169 
170  if(strlen(Pathtypes[i].path))
171  {
172  filespec += Pathtypes[ i ].path;
173  if ( filespec[ filespec.length( ) - 1 ] != DIR_SEPARATOR_CHAR )
174  {
175  filespec += DIR_SEPARATOR_STR;
176  }
177  }
178 
179 #if defined _WIN32
180  filespec += "*.vp";
181 
182  int find_handle;
183  _finddata_t find;
184 
185  find_handle = _findfirst( filespec.c_str( ), &find );
186 
187  if (find_handle != -1) {
188  do {
189  if (!(find.attrib & _A_SUBDIR)) {
190  packfile_count++;
191  }
192 
193  } while (!_findnext(find_handle, &find));
194 
195  _findclose( find_handle );
196  }
197 #elif defined SCP_UNIX
198  filespec += "*.[vV][pP]";
199 
200  glob_t globinfo;
201  memset(&globinfo, 0, sizeof(globinfo));
202  int status = glob(filespec.c_str( ), 0, NULL, &globinfo);
203  if (status == 0) {
204  for (unsigned int j = 0; j < globinfo.gl_pathc; j++) {
205  // Determine if this is a regular file
206  struct stat statbuf;
207  memset(&statbuf, 0, sizeof(statbuf));
208  stat(globinfo.gl_pathv[j], &statbuf);
209  if (S_ISREG(statbuf.st_mode)) {
210  packfile_count++;
211  }
212  }
213  globfree(&globinfo);
214  }
215 #endif
216  }
217 
218  return packfile_count;
219 }
220 
221 // packfile sort function
223 {
224  // if the 2 directory types are the same, do a string compare
225  if (r1.cf_type == r2.cf_type) {
226  return (stricmp(r1.path, r2.path) < 0);
227  }
228 
229  // otherwise return them in order of CF_TYPE_* precedence
230  return (r1.cf_type < r2.cf_type);
231 }
232 
233 // Go through a root and look for pack files
235 {
236  char filespec[MAX_PATH_LEN];
237  int i;
238  cf_root_sort *temp_roots_sort, *rptr_sort;
239  int temp_root_count, root_index;
240 
241  // determine how many packfiles there are
242  temp_root_count = cf_get_packfile_count(root);
243 
244  if (temp_root_count <= 0)
245  return;
246 
247  // allocate a temporary array of temporary roots so we can easily sort them
248  temp_roots_sort = (cf_root_sort*)vm_malloc(sizeof(cf_root_sort) * temp_root_count);
249 
250  if (temp_roots_sort == NULL) {
251  Int3();
252  return;
253  }
254 
255  // now just setup all the root info
256  root_index = 0;
257  for (i = CF_TYPE_ROOT; i < CF_MAX_PATH_TYPES; i++) {
258  strcpy_s( filespec, root->path );
259 
260  if ( strlen(Pathtypes[i].path) ) {
261  strcat_s( filespec, Pathtypes[i].path );
262 
263  if ( filespec[strlen(filespec)-1] != DIR_SEPARATOR_CHAR )
264  strcat_s( filespec, DIR_SEPARATOR_STR );
265  }
266 
267 #if defined _WIN32
268  strcat_s( filespec, "*.vp" );
269 
270  int find_handle;
271  _finddata_t find;
272 
273  find_handle = _findfirst( filespec, &find );
274 
275  if (find_handle != -1) {
276  do {
277  // add the new item
278  if (!(find.attrib & _A_SUBDIR)) {
279  Assert(root_index < temp_root_count);
280 
281  // get a temp pointer
282  rptr_sort = &temp_roots_sort[root_index++];
283 
284  // fill in all the proper info
285  strcpy_s(rptr_sort->path, root->path);
286 
287  if(strlen(Pathtypes[i].path)) {
288 
289  strcat_s(rptr_sort->path, Pathtypes[i].path );
290  strcat_s(rptr_sort->path, DIR_SEPARATOR_STR);
291  }
292 
293  strcat_s(rptr_sort->path, find.name );
294  rptr_sort->roottype = CF_ROOTTYPE_PACK;
295  rptr_sort->cf_type = i;
296  }
297 
298  } while (!_findnext(find_handle, &find));
299 
300  _findclose( find_handle );
301  }
302 #elif defined SCP_UNIX
303  strcat_s( filespec, "*.[vV][pP]" );
304  glob_t globinfo;
305 
306  memset(&globinfo, 0, sizeof(globinfo));
307 
308  int status = glob(filespec, 0, NULL, &globinfo);
309 
310  if (status == 0) {
311  for (uint j = 0; j < globinfo.gl_pathc; j++) {
312  // Determine if this is a regular file
313  struct stat statbuf;
314  memset(&statbuf, 0, sizeof(statbuf));
315  stat(globinfo.gl_pathv[j], &statbuf);
316 
317  if ( S_ISREG(statbuf.st_mode) ) {
318  Assert(root_index < temp_root_count);
319 
320  // get a temp pointer
321  rptr_sort = &temp_roots_sort[root_index++];
322 
323  // fill in all the proper info
324  strcpy_s(rptr_sort->path, globinfo.gl_pathv[j] );
325  rptr_sort->roottype = CF_ROOTTYPE_PACK;
326  rptr_sort->cf_type = i;
327  }
328  }
329 
330  globfree(&globinfo);
331  }
332 #endif
333  }
334 
335  // these should always be the same
336  Assert(root_index == temp_root_count);
337 
338  // sort the roots
339  std::sort(temp_roots_sort, temp_roots_sort + temp_root_count, cf_packfile_sort_func);
340 
341  // now insert them all into the real root list properly
342  cf_root *new_root;
343  for (i = 0; i < temp_root_count; i++) {
344  new_root = cf_create_root();
345  strcpy_s( new_root->path, root->path );
346 
347 #ifndef NDEBUG
348  uint chksum = 0;
349  cf_chksum_pack(temp_roots_sort[i].path, &chksum);
350  mprintf(("Found root pack '%s' with a checksum of 0x%08x\n", temp_roots_sort[i].path, chksum));
351 #endif
352 
353  // mwa -- 4/2/98 put in the next 2 lines because the path name needs to be there
354  // to find the files.
355  strcpy_s(new_root->path, temp_roots_sort[i].path);
356  new_root->roottype = CF_ROOTTYPE_PACK;
357  }
358 
359  // free up the temp list
360  vm_free(temp_roots_sort);
361 }
362 
363 
364 void cf_build_root_list(const char *cdrom_dir)
365 {
366  Num_roots = 0;
367  Num_path_roots = 0;
368 
369  cf_root *root;
370  char str_temp[CF_MAX_PATHNAME_LENGTH], *cur_pos;
371  int path_len;
372 
373 #ifdef SCP_UNIX
374  // =========================================================================
375  // now look for mods under the users HOME directory to use before system ones
376  if (Cmdline_mod) {
377  for (cur_pos=Cmdline_mod; strlen(cur_pos) != 0; cur_pos+= (strlen(cur_pos)+1))
378  {
379  memset(str_temp, 0, CF_MAX_PATHNAME_LENGTH);
380  strncpy(str_temp, cur_pos, CF_MAX_PATHNAME_LENGTH-1);
381 
382  strncat(str_temp, DIR_SEPARATOR_STR, (CF_MAX_PATHNAME_LENGTH - strlen(str_temp) - 1));
383 
384  // truncated string check
385  if ( (strlen(Cfile_user_dir) + strlen(str_temp) + 1) >= CF_MAX_PATHNAME_LENGTH ) {
386  Error(LOCATION, "Home directory plus mod directory exceeds CF_MAX_PATHNAME_LENGTH\n");
387  }
388 
389  root = cf_create_root();
390 
391  strncpy( root->path, Cfile_user_dir, CF_MAX_PATHNAME_LENGTH-1 );
392 
393  // do we already have a slash? as in the case of a root directory install
394  if ( (strlen(root->path) < (CF_MAX_PATHNAME_LENGTH-1)) && (root->path[strlen(root->path)-1] != DIR_SEPARATOR_CHAR) ) {
395  strcat_s(root->path, DIR_SEPARATOR_STR); // put trailing backslash on for easier path construction
396  }
397 
398  strncat(root->path, str_temp, (CF_MAX_PATHNAME_LENGTH - strlen(root->path) - 1));
399 
400  root->roottype = CF_ROOTTYPE_PATH;
401  cf_build_pack_list(root);
402  }
403  }
404  // =========================================================================
405 
406  // =========================================================================
407  // set users HOME directory as default for loading and saving files
408  root = cf_create_root();
409  strncpy( root->path, Cfile_user_dir, CF_MAX_PATHNAME_LENGTH-1 );
410 
411  // do we already have a slash? as in the case of a root directory install
412  if( (strlen(root->path) < (CF_MAX_PATHNAME_LENGTH-1)) && (root->path[strlen(root->path)-1] != DIR_SEPARATOR_CHAR) ) {
413  strcat_s(root->path, DIR_SEPARATOR_STR); // put trailing backslash on for easier path construction
414  }
415  root->roottype = CF_ROOTTYPE_PATH;
416 
417  // set the default player location to here
418  if ( Pilot_file_path == NULL )
419  Pilot_file_path = root->path;
420 
421  // Next, check any VP files under the current directory.
422  cf_build_pack_list(root);
423  // =========================================================================
424 #endif
425 
426  if(Cmdline_mod) {
427  // stackable Mod support -- Kazan
428  for (cur_pos=Cmdline_mod; *cur_pos != '\0'; cur_pos+= (strlen(cur_pos)+1))
429  {
430  memset(str_temp, 0, CF_MAX_PATHNAME_LENGTH);
431  strncpy(str_temp, cur_pos, CF_MAX_PATHNAME_LENGTH-1);
432 
433  strncat(str_temp, DIR_SEPARATOR_STR, (CF_MAX_PATHNAME_LENGTH - strlen(str_temp) - 1));
434  root = cf_create_root();
435 
436  if ( !_getcwd(root->path, CF_MAX_PATHNAME_LENGTH ) ) {
437  Error(LOCATION, "Can't get current working directory -- %d", errno );
438  }
439 
440  // truncated string check
441  if ( (strlen(root->path) + strlen(str_temp) + 1) >= CF_MAX_PATHNAME_LENGTH ) {
442  Error(LOCATION, "Installed path plus mod directory exceeds CF_MAX_PATHNAME_LENGTH\n");
443  }
444 
445  path_len = strlen(root->path);
446 
447  // do we already have a slash? as in the case of a root directory install
448  if ( (path_len < (CF_MAX_PATHNAME_LENGTH-1)) && (root->path[path_len-1] != DIR_SEPARATOR_CHAR) ) {
449  strcat_s(root->path, DIR_SEPARATOR_STR); // put trailing backslash on for easier path construction
450  path_len++;
451  }
452 
453  strncat(root->path, str_temp, (CF_MAX_PATHNAME_LENGTH - path_len - 1));
454  root->roottype = CF_ROOTTYPE_PATH;
455  cf_build_pack_list(root);
456  }
457  }
458 
459  root = cf_create_root();
460 
461  if ( !_getcwd(root->path, CF_MAX_PATHNAME_LENGTH ) ) {
462  Error(LOCATION, "Can't get current working directory -- %d", errno );
463  }
464 
465  path_len = strlen(root->path);
466 
467  // do we already have a slash? as in the case of a root directory install
468  if ( (path_len < (CF_MAX_PATHNAME_LENGTH-1)) && (root->path[path_len-1] != DIR_SEPARATOR_CHAR) ) {
469  strcat_s(root->path, DIR_SEPARATOR_STR); // put trailing backslash on for easier path construction
470  }
471 
472  root->roottype = CF_ROOTTYPE_PATH;
473 
474  // set the default path for pilot files
475  if ( Pilot_file_path == NULL )
476  Pilot_file_path = root->path;
477 
478  //======================================================
479  // Next, check any VP files under the current directory.
480  cf_build_pack_list(root);
481 
482 
483  //======================================================
484  // Check the real CD if one...
485  if ( cdrom_dir && (strlen(cdrom_dir) < CF_MAX_PATHNAME_LENGTH) ) {
486  root = cf_create_root();
487  strcpy_s( root->path, cdrom_dir );
488  root->roottype = CF_ROOTTYPE_PATH;
489 
490  //======================================================
491  // Next, check any VP files in the CD-ROM directory.
492  cf_build_pack_list(root);
493 
494  }
495 
496 }
497 
498 // Given a lower case list of file extensions
499 // separated by spaces, return zero if ext is
500 // not in the list.
501 int is_ext_in_list( const char *ext_list, const char *ext )
502 {
503  char tmp_ext[128];
504 
505  strcpy_s( tmp_ext, ext);
506  strlwr(tmp_ext);
507  if ( strstr(ext_list, tmp_ext )) {
508  return 1;
509  }
510 
511  return 0;
512 }
513 
514 void cf_search_root_path(int root_index)
515 {
516  int i;
517  int num_files = 0;
518 
519  cf_root *root = cf_get_root(root_index);
520 
521  mprintf(( "Searching root '%s' ... ", root->path ));
522 
523  char search_path[CF_MAX_PATHNAME_LENGTH];
524 
525  for (i=CF_TYPE_ROOT; i<CF_MAX_PATH_TYPES; i++ ) {
526 
527  // we don't want to add player files to the cache - taylor
528  if ( (i == CF_TYPE_SINGLE_PLAYERS) || (i == CF_TYPE_MULTI_PLAYERS) ) {
529  continue;
530  }
531 
532  strcpy_s( search_path, root->path );
533 
534  if(strlen(Pathtypes[i].path)) {
535  strcat_s( search_path, Pathtypes[i].path );
536  if ( search_path[strlen(search_path)-1] != DIR_SEPARATOR_CHAR ) {
537  strcat_s( search_path, DIR_SEPARATOR_STR );
538  }
539  }
540 
541 #if defined _WIN32
542  strcat_s( search_path, "*.*" );
543 
544  int find_handle;
545  _finddata_t find;
546 
547  find_handle = _findfirst( search_path, &find );
548 
549  if (find_handle != -1) {
550  do {
551  if (!(find.attrib & _A_SUBDIR)) {
552 
553  char *ext = strrchr( find.name, '.' );
554  if ( ext ) {
555  if ( is_ext_in_list( Pathtypes[i].extensions, ext ) ) {
556  // Found a file!!!!
557  cf_file *file = cf_create_file();
558 
559  strcpy_s( file->name_ext, find.name );
560  file->root_index = root_index;
561  file->pathtype_index = i;
562  file->write_time = find.time_write;
563  file->size = find.size;
564  file->pack_offset = 0; // Mark as a non-packed file
565 
566  num_files++;
567  //mprintf(( "Found file '%s'\n", file->name_ext ));
568  }
569  }
570 
571  }
572 
573  } while (!_findnext(find_handle, &find));
574 
575  _findclose( find_handle );
576  }
577 #elif defined SCP_UNIX
578  DIR *dirp;
579  struct dirent *dir;
580 
581  dirp = opendir (search_path);
582  if ( dirp ) {
583  while ((dir = readdir (dirp)) != NULL)
584  {
585  if (!fnmatch ("*.*", dir->d_name, 0))
586  {
587  char fn[MAX_PATH];
588  snprintf(fn, MAX_PATH-1, "%s%s", search_path, dir->d_name);
589  fn[MAX_PATH-1] = 0;
590 
591  struct stat buf;
592  if (stat(fn, &buf) == -1) {
593  continue;
594  }
595 
596  if (!S_ISREG(buf.st_mode)) {
597  continue;
598  }
599 
600  char *ext = strrchr( dir->d_name, '.' );
601  if ( ext ) {
602  if ( is_ext_in_list( Pathtypes[i].extensions, ext ) ) {
603  // Found a file!!!!
604  cf_file *file = cf_create_file();
605 
606  strcpy_s( file->name_ext, dir->d_name );
607  file->root_index = root_index;
608  file->pathtype_index = i;
609 
610 
611  file->write_time = buf.st_mtime;
612  file->size = buf.st_size;
613 
614  file->pack_offset = 0; // Mark as a non-packed file
615 
616  num_files++;
617  //mprintf(( "Found file '%s'\n", file->name_ext ));
618  }
619  }
620  }
621  }
622  closedir(dirp);
623  }
624 #endif
625  }
626 
627  mprintf(( "%i files\n", num_files ));
628 }
629 
630 
631 typedef struct VP_FILE_HEADER {
632  char id[4];
633  int version;
637 
638 typedef struct VP_FILE {
639  int offset;
640  int size;
641  char filename[32];
643 } VP_FILE;
644 
645 void cf_search_root_pack(int root_index)
646 {
647  int num_files = 0;
648  cf_root *root = cf_get_root(root_index);
649 
650  Assert( root != NULL );
651 
652  // Open data
653  FILE *fp = fopen( root->path, "rb" );
654  // Read the file header
655  if (!fp) {
656  return;
657  }
658 
659  if ( filelength(fileno(fp)) < (int)(sizeof(VP_FILE_HEADER) + (sizeof(int) * 3)) ) {
660  mprintf(( "Skipping VP file ('%s') of invalid size...\n", root->path ));
661  fclose(fp);
662  return;
663  }
664 
665  VP_FILE_HEADER VP_header;
666 
667  Assert( sizeof(VP_header) == 16 );
668  if (fread(&VP_header, sizeof(VP_header), 1, fp) != 1) {
669  mprintf(("Skipping VP file ('%s') because the header could not be read...\n", root->path));
670  fclose(fp);
671  return;
672  }
673 
674  VP_header.version = INTEL_INT( VP_header.version ); //-V570
675  VP_header.index_offset = INTEL_INT( VP_header.index_offset ); //-V570
676  VP_header.num_files = INTEL_INT( VP_header.num_files ); //-V570
677 
678  mprintf(( "Searching root pack '%s' ... ", root->path ));
679 
680  // Read index info
681  fseek(fp, VP_header.index_offset, SEEK_SET);
682 
683  char search_path[CF_MAX_PATHNAME_LENGTH];
684 
685  strcpy_s( search_path, "" );
686 
687  // Go through all the files
688  int i;
689  for (i=0; i<VP_header.num_files; i++ ) {
690  VP_FILE find;
691 
692  if (fread( &find, sizeof(VP_FILE), 1, fp ) != 1) {
693  mprintf(("Failed to read file entry (currently in directory %s)!\n", search_path));
694  break;
695  }
696 
697  find.offset = INTEL_INT( find.offset ); //-V570
698  find.size = INTEL_INT( find.size ); //-V570
699  find.write_time = INTEL_INT( find.write_time ); //-V570
700  find.filename[sizeof(find.filename)-1] = '\0';
701 
702  if ( find.size == 0 ) {
703  int search_path_len = strlen(search_path);
704  if ( !stricmp( find.filename, ".." )) {
705  char *p = &search_path[search_path_len-1];
706  while( (p > search_path) && (*p != DIR_SEPARATOR_CHAR) ) {
707  p--;
708  }
709  *p = 0;
710  } else {
711  if ( search_path_len && (search_path[search_path_len-1] != DIR_SEPARATOR_CHAR) ) {
712  strcat_s( search_path, DIR_SEPARATOR_STR );
713  }
714  strcat_s( search_path, find.filename );
715  }
716 
717  //mprintf(( "Current dir = '%s'\n", search_path ));
718  } else {
719 
720  int j;
721 
722  for (j=CF_TYPE_ROOT; j<CF_MAX_PATH_TYPES; j++ ) {
723 
724  if ( !stricmp( search_path, Pathtypes[j].path )) {
725  char *ext = strrchr( find.filename, '.' );
726  if ( ext ) {
727  if ( is_ext_in_list( Pathtypes[j].extensions, ext ) ) {
728  // Found a file!!!!
729  cf_file *file = cf_create_file();
730  strcpy_s( file->name_ext, find.filename );
731  file->root_index = root_index;
732  file->pathtype_index = j;
733  file->write_time = (time_t)find.write_time;
734  file->size = find.size;
735  file->pack_offset = find.offset; // Mark as a packed file
736 
737  num_files++;
738  //mprintf(( "Found pack file '%s'\n", file->name_ext ));
739  }
740  }
741  }
742  }
743  }
744  }
745 
746  fclose(fp);
747 
748  mprintf(( "%i files\n", num_files ));
749 }
750 
751 
752 
754 {
755  int i;
756 
757  Num_files = 0;
758 
759  // For each root, find all files...
760  for (i=0; i<Num_roots; i++ ) {
761  cf_root *root = cf_get_root(i);
762  if ( root->roottype == CF_ROOTTYPE_PATH ) {
764  } else if ( root->roottype == CF_ROOTTYPE_PACK ) {
766  }
767  }
768 
769 }
770 
771 
772 void cf_build_secondary_filelist(const char *cdrom_dir)
773 {
774  int i;
775 
776  // Assume no files
777  Num_roots = 0;
778  Num_files = 0;
779 
780  // Init the root blocks
781  for (i=0; i<CF_MAX_ROOT_BLOCKS; i++ ) {
782  Root_blocks[i] = NULL;
783  }
784 
785  // Init the file blocks
786  for (i=0; i<CF_MAX_FILE_BLOCKS; i++ ) {
787  File_blocks[i] = NULL;
788  }
789 
790  mprintf(( "Building file index...\n" ));
791 
792  // build the list of searchable roots
793  cf_build_root_list(cdrom_dir);
794 
795  // build the list of files themselves
797 
798  mprintf(( "Found %d roots and %d files.\n", Num_roots, Num_files ));
799 }
800 
802 {
803  int i;
804 
805  // Free the root blocks
806  for (i=0; i<CF_MAX_ROOT_BLOCKS; i++ ) {
807  if ( Root_blocks[i] ) {
808  vm_free( Root_blocks[i] );
809  Root_blocks[i] = NULL;
810  }
811  }
812  Num_roots = 0;
813 
814  // Init the file blocks
815  for (i=0; i<CF_MAX_FILE_BLOCKS; i++ ) {
816  if ( File_blocks[i] ) {
817  vm_free( File_blocks[i] );
818  File_blocks[i] = NULL;
819  }
820  }
821  Num_files = 0;
822 }
823 
839 int cf_find_file_location( const char *filespec, int pathtype, int max_out, char *pack_filename, int *size, int *offset, bool localize )
840 {
841  int i;
842  uint ui;
843  int cfs_slow_search = 0;
844  char longname[MAX_PATH_LEN];
845 
846 #if defined WIN32
847  long findhandle;
848  _finddata_t findstruct;
849 #endif
850 
851  Assert( (filespec != NULL) && (strlen(filespec) > 0) ); //-V805
852  Assert( (pack_filename == NULL) || (max_out > 1) );
853 
854  // see if we have something other than just a filename
855  // our current rules say that any file that specifies a direct
856  // path will try to be opened on that path. If that open
857  // fails, then we will open the file based on the extension
858  // of the file
859 
860  // NOTE: full path should also include localization, if so desired
861 #ifdef SCP_UNIX
862  if ( strpbrk(filespec, "/") ) { // do we have a full path already?
863 #else
864  if ( strpbrk(filespec,"/\\:") ) { // do we have a full path already?
865 #endif
866  FILE *fp = fopen(filespec, "rb" );
867  if (fp) {
868  if ( size ) *size = filelength(fileno(fp));
869  if ( offset ) *offset = 0;
870  if ( pack_filename ) {
871  strncpy( pack_filename, filespec, max_out );
872  }
873  fclose(fp);
874  return 1;
875  }
876 
877  return 0; // If they give a full path, fail if not found.
878  }
879 
880  // Search the hard drive for files first.
881  uint num_search_dirs = 0;
882  int search_order[CF_MAX_PATH_TYPES];
883 
884  if ( CF_TYPE_SPECIFIED(pathtype) ) {
885  search_order[num_search_dirs++] = pathtype;
886  } else {
887  for (i = CF_TYPE_ROOT; i < CF_MAX_PATH_TYPES; i++) {
888  if (i != pathtype)
889  search_order[num_search_dirs++] = i;
890  }
891  }
892 
893  memset( longname, 0, sizeof(longname) );
894 
895 
896  for (ui=0; ui<num_search_dirs; ui++ ) {
897  switch (search_order[ui])
898  {
899  case CF_TYPE_ROOT:
900  case CF_TYPE_DATA:
903  case CF_TYPE_MULTI_CACHE:
904  case CF_TYPE_MISSIONS:
905  case CF_TYPE_CACHE:
906  cfs_slow_search = 1;
907  break;
908 
909  default:
910  // always hit the disk if we are looking in only one path
911  cfs_slow_search = (num_search_dirs == 1) ? 1 : 0;
912  break;
913  }
914 
915  if (cfs_slow_search) {
916  cf_create_default_path_string( longname, sizeof(longname)-1, search_order[ui], filespec, localize );
917 
918 #if defined _WIN32
919  findhandle = _findfirst(longname, &findstruct);
920  if (findhandle != -1) {
921  if (size)
922  *size = findstruct.size;
923 
924  _findclose(findhandle);
925 
926  if (offset)
927  *offset = 0;
928 
929  if (pack_filename)
930  strncpy( pack_filename, longname, max_out );
931 
932  return 1;
933  }
934 #endif
935  {
936  FILE *fp = fopen(longname, "rb" );
937 
938  if (fp) {
939  if (size)
940  *size = filelength( fileno(fp) );
941 
942  fclose(fp);
943 
944  if (offset)
945  *offset = 0;
946 
947  if (pack_filename)
948  strncpy(pack_filename, longname, max_out);
949 
950  return 1;
951  }
952  }
953  }
954  }
955 
956  // Search the pak files and CD-ROM.
957  for (ui = 0; ui < Num_files; ui++ ) {
958  cf_file *f = cf_get_file(ui);
959 
960  // only search paths we're supposed to...
961  if ( (pathtype != CF_TYPE_ANY) && (pathtype != f->pathtype_index) )
962  continue;
963 
964 
965  if (localize) {
966  // create localized filespec
967  strncpy(longname, filespec, MAX_PATH_LEN - 1);
968 
969  if ( lcl_add_dir_to_path_with_filename(longname, MAX_PATH_LEN - 1) ) {
970  if ( !stricmp(longname, f->name_ext) ) {
971  if (size)
972  *size = f->size;
973 
974  if (offset)
975  *offset = f->pack_offset;
976 
977  if (pack_filename) {
979 
980  strncpy( pack_filename, r->path, max_out );
981 
982  if (f->pack_offset < 1) {
983  strcat_s( pack_filename, max_out, Pathtypes[f->pathtype_index].path );
984 
985  if ( pack_filename[strlen(pack_filename)-1] != DIR_SEPARATOR_CHAR )
986  strcat_s( pack_filename, max_out, DIR_SEPARATOR_STR );
987 
988  strcat_s( pack_filename, max_out, f->name_ext );
989  }
990  }
991 
992  return 1;
993  }
994  }
995  }
996 
997  // file either not localized or localized version not found
998  if ( !stricmp(filespec, f->name_ext) ) {
999  if (size)
1000  *size = f->size;
1001 
1002  if (offset)
1003  *offset = f->pack_offset;
1004 
1005  if (pack_filename) {
1007 
1008  strcpy( pack_filename, r->path );
1009 
1010  if (f->pack_offset < 1) {
1011  if ( strlen(Pathtypes[f->pathtype_index].path) ) {
1012  strcat_s( pack_filename, max_out, Pathtypes[f->pathtype_index].path );
1013 
1014  if ( pack_filename[strlen(pack_filename)-1] != DIR_SEPARATOR_CHAR )
1015  strcat_s( pack_filename, max_out, DIR_SEPARATOR_STR );
1016  }
1017 
1018  strcat_s( pack_filename, max_out, f->name_ext );
1019  }
1020  }
1021 
1022  return 1;
1023  }
1024  }
1025 
1026  return 0;
1027 }
1028 
1029 // -- from parselo.cpp --
1030 extern char *stristr(char *str, const char *substr);
1031 
1050 int cf_find_file_location_ext( const char *filename, const int ext_num, const char **ext_list, int pathtype, int max_out, char *pack_filename, int *size, int *offset, bool localize )
1051 {
1052  int cur_ext, i;
1053  uint ui;
1054  int cfs_slow_search = 0;
1055  char longname[MAX_PATH_LEN];
1056  char filespec[MAX_FILENAME_LEN];
1057  char *p = NULL;
1058 
1059 #if defined WIN32
1060  long findhandle;
1061  _finddata_t findstruct;
1062 #endif
1063 
1064  Assert( (filename != NULL) && (strlen(filename) < MAX_FILENAME_LEN) );
1065  Assert( (ext_list != NULL) && (ext_num > 1) ); // if we are searching for just one ext
1066  // then this is the wrong function to use
1067  Assert( (pack_filename == NULL) || (max_out > 1) );
1068 
1069 
1070  // if we have a full path already then fail. this function if for searching via filter only!
1071 #ifdef SCP_UNIX
1072  if ( strpbrk(filename, "/") ) { // do we have a full path already?
1073 #else
1074  if ( strpbrk(filename,"/\\:") ) { // do we have a full path already?
1075 #endif
1076  Int3();
1077  return 0;
1078  }
1079 
1080  // Search the hard drive for files first.
1081  uint num_search_dirs = 0;
1082  int search_order[CF_MAX_PATH_TYPES];
1083 
1084  if ( CF_TYPE_SPECIFIED(pathtype) ) {
1085  search_order[num_search_dirs++] = pathtype;
1086  } else {
1087  for (i = CF_TYPE_ROOT; i < CF_MAX_PATH_TYPES; i++)
1088  search_order[num_search_dirs++] = i;
1089  }
1090 
1091  memset( longname, 0, sizeof(longname) );
1092  memset( filespec, 0, sizeof(filespec) );
1093 
1094  // strip any existing extension
1095  strncpy(filespec, filename, MAX_FILENAME_LEN-1);
1096 
1097  for (ui = 0; ui < num_search_dirs; ui++) {
1098  // always hit the disk if we are looking in only one path
1099  if (num_search_dirs == 1) {
1100  cfs_slow_search = 1;
1101  }
1102  // otherwise hit based on a directory type
1103  else {
1104  switch (search_order[ui])
1105  {
1106  case CF_TYPE_ROOT:
1107  case CF_TYPE_DATA:
1109  case CF_TYPE_MULTI_PLAYERS:
1110  case CF_TYPE_MULTI_CACHE:
1111  case CF_TYPE_MISSIONS:
1112  case CF_TYPE_CACHE:
1113  cfs_slow_search = 1;
1114  break;
1115  }
1116  }
1117 
1118  if ( !cfs_slow_search )
1119  continue;
1120 
1121  for (cur_ext = 0; cur_ext < ext_num; cur_ext++) {
1122  // strip any extension and add the one we want to check for
1123  // (NOTE: to be fully retail compatible, we need to support multiple periods for something like *_1.5.wav,
1124  // which means that we need to strip a length of >2 only, assuming that all valid ext are at least 2 chars)
1125  p = strrchr(filespec, '.');
1126  if ( p && (strlen(p) > 2) )
1127  (*p) = 0;
1128 
1129  strcat_s( filespec, ext_list[cur_ext] );
1130 
1131  cf_create_default_path_string( longname, sizeof(longname)-1, search_order[ui], filespec, localize );
1132 
1133 #if defined _WIN32
1134  findhandle = _findfirst(longname, &findstruct);
1135  if (findhandle != -1) {
1136  if (size)
1137  *size = findstruct.size;
1138 
1139  _findclose(findhandle);
1140 
1141  if (offset)
1142  *offset = 0;
1143 
1144  if (pack_filename)
1145  strncpy( pack_filename, longname, max_out );
1146 
1147  return cur_ext;
1148  }
1149 #endif
1150  {
1151  FILE *fp = fopen(longname, "rb" );
1152 
1153  if (fp) {
1154  if (size)
1155  *size = filelength( fileno(fp) );
1156 
1157  fclose(fp);
1158 
1159  if (offset)
1160  *offset = 0;
1161 
1162  if (pack_filename)
1163  strncpy(pack_filename, longname, max_out);
1164 
1165  return cur_ext;
1166  }
1167  }
1168  }
1169  }
1170 
1171  // Search the pak files and CD-ROM.
1172 
1173  // first off, make sure that we don't have an extension
1174  // (NOTE: to be fully retail compatible, we need to support multiple periods for something like *_1.5.wav,
1175  // which means that we need to strip a length of >2 only, assuming that all valid ext are at least 2 chars)
1176  p = strrchr(filespec, '.');
1177  if ( p && (strlen(p) > 2) )
1178  (*p) = 0;
1179 
1180  // go ahead and get our length, which is used to test with later
1181  int filespec_len = strlen(filespec);
1182 
1183  // get total legnth, with extension, which is iused to test with later
1184  // (FIXME: this assumes that everything in ext_list[] is the same length!)
1185  uint filespec_len_big = filespec_len + strlen(ext_list[0]);
1186 
1187  SCP_vector< cf_file* > file_list_index;
1188  int last_root_index = -1;
1189  int last_path_index = -1;
1190 
1191  file_list_index.reserve( MIN(ext_num * 4, (int)Num_files) );
1192 
1193  // next, run though and pick out base matches
1194  for (ui = 0; ui < Num_files; ui++) {
1195  cf_file *f = cf_get_file(ui);
1196 
1197  // ... only search paths that we're supposed to
1198  if ( (num_search_dirs == 1) && (pathtype != f->pathtype_index) )
1199  continue;
1200 
1201  // ... check that our names are the same length (accounting for the missing extension on our own name)
1202  if ( strlen(f->name_ext) != filespec_len_big )
1203  continue;
1204 
1205  // ... check that we match the base filename
1206  if ( strnicmp(f->name_ext, filespec, filespec_len) )
1207  continue;
1208 
1209  // ... make sure that it's one of our supported types
1210  bool found_one = false;
1211  for (cur_ext = 0; cur_ext < ext_num; cur_ext++) {
1212  if ( stristr(f->name_ext, ext_list[cur_ext]) ) {
1213  found_one = true;
1214  break;
1215  }
1216  }
1217 
1218  if ( !found_one )
1219  continue;
1220 
1221  // ... we check based on location, so if location changes after the first find then bail
1222  if (last_root_index == -1) {
1223  last_root_index = f->root_index;
1224  last_path_index = f->pathtype_index;
1225  } else {
1226  if (f->root_index != last_root_index)
1227  break;
1228 
1229  if (f->pathtype_index != last_path_index)
1230  break;
1231  }
1232 
1233  // ok, we have a good base match, so add it to our cache
1234  file_list_index.push_back( f );
1235  }
1236 
1237  // now try and find our preferred match
1238  for (cur_ext = 0; cur_ext < ext_num; cur_ext++) {
1239  for (SCP_vector<cf_file*>::iterator fli = file_list_index.begin(); fli != file_list_index.end(); ++fli) {
1240  cf_file *f = *fli;
1241 
1242  strcat_s( filespec, ext_list[cur_ext] );
1243 
1244  if (localize) {
1245  // create localized filespec
1246  strncpy(longname, filespec, MAX_PATH_LEN - 1);
1247 
1248  if ( lcl_add_dir_to_path_with_filename(longname, MAX_PATH_LEN - 1) ) {
1249  if ( !stricmp(longname, f->name_ext) ) {
1250  if (size)
1251  *size = f->size;
1252 
1253  if (offset)
1254  *offset = f->pack_offset;
1255 
1256  if (pack_filename) {
1258 
1259  strncpy( pack_filename, r->path, max_out );
1260 
1261  if (f->pack_offset < 1) {
1262  strcat_s( pack_filename, max_out, Pathtypes[f->pathtype_index].path );
1263 
1264  if ( pack_filename[strlen(pack_filename)-1] != DIR_SEPARATOR_CHAR )
1265  strcat_s( pack_filename, max_out, DIR_SEPARATOR_STR );
1266 
1267  strcat_s( pack_filename, max_out, f->name_ext );
1268  }
1269  }
1270 
1271  // found it, so cleanup and return
1272  file_list_index.clear();
1273 
1274  return cur_ext;
1275  }
1276  }
1277  }
1278 
1279  // file either not localized or localized version not found
1280  if ( !stricmp(filespec, f->name_ext) ) {
1281  if (size)
1282  *size = f->size;
1283 
1284  if (offset)
1285  *offset = f->pack_offset;
1286 
1287  if (pack_filename) {
1289 
1290  strcpy( pack_filename, r->path );
1291 
1292  if (f->pack_offset < 1) {
1293 
1294  if ( strlen(Pathtypes[f->pathtype_index].path) ) {
1295  strcat_s( pack_filename, max_out, Pathtypes[f->pathtype_index].path );
1296 
1297  if ( pack_filename[strlen(pack_filename)-1] != DIR_SEPARATOR_CHAR )
1298  strcat_s( pack_filename, max_out, DIR_SEPARATOR_STR );
1299  }
1300 
1301  strcat_s( pack_filename, max_out, f->name_ext );
1302  }
1303  }
1304 
1305  // found it, so cleanup and return
1306  file_list_index.clear();
1307 
1308  return cur_ext;
1309  }
1310 
1311  // ok, we're still here, so strip off the extension again in order to
1312  // prepare for the next run
1313  p = strrchr(filespec, '.');
1314  if ( p && (strlen(p) > 2) )
1315  (*p) = 0;
1316  }
1317  }
1318 
1319  return -1;
1320 }
1321 
1322 
1323 // Returns true if filename matches filespec, else zero if not
1324 int cf_matches_spec(const char *filespec, const char *filename)
1325 {
1326  const char *src_ext;
1327  const char *dst_ext;
1328 
1329  src_ext = strrchr(filespec, '*');
1330  if(!src_ext)
1331  {
1332  src_ext = strrchr(filespec, '.');
1333  if (!src_ext)
1334  return 1;
1335  }
1336  else
1337  {
1338  src_ext++;
1339  }
1340 
1341  if(strlen(filespec) > strlen(filename))
1342  {
1343  return 0;
1344  }
1345 
1346  dst_ext = filename + strlen(filename) - ((filespec + strlen(filespec)) - src_ext);
1347  if (!dst_ext)
1348  return 1;
1349 
1350  if(src_ext == filespec)
1351  {
1352  return !stricmp(dst_ext, src_ext);
1353  }
1354  else
1355  {
1356  return (!stricmp(dst_ext, src_ext) && !strnicmp(dst_ext, src_ext, src_ext - filespec));
1357  }
1358 }
1359 
1360 int (*Get_file_list_filter)(const char *filename) = NULL;
1361 const char *Get_file_list_child = NULL;
1363 
1364 static bool verify_file_list_child()
1365 {
1366  if (Get_file_list_child == NULL) {
1367  return false;
1368  }
1369 
1370  // empty or too long
1371  size_t len = strlen(Get_file_list_child);
1372  if ( !len || (len > MAX_FILENAME_LEN) ) {
1373  return false;
1374  }
1375 
1376  // can not being with directory separator
1377  if (Get_file_list_child[0] == DIR_SEPARATOR_CHAR) {
1378  return false;
1379  }
1380 
1381  // no ':' or spaces
1382  if ( strchr(Get_file_list_child, ':') || strchr(Get_file_list_child, ' ') ) {
1383  return false;
1384  }
1385 
1386  return true;
1387 }
1388 
1389 static int cf_file_already_in_list( SCP_vector<SCP_string> &list, const char *filename )
1390 {
1391  char name_no_extension[MAX_PATH_LEN];
1392  size_t i, size = list.size();
1393 
1394  if (size == 0) {
1395  return 0;
1396  }
1397 
1398  strcpy_s(name_no_extension, filename );
1399  char *p = strrchr( name_no_extension, '.' );
1400  if ( p ) *p = 0;
1401 
1402  for (i = 0; i < size; i++) {
1403  if ( !stricmp(list[i].c_str(), name_no_extension ) ) {
1404  // Match found!
1405  return 1;
1406  }
1407  }
1408 
1409  // Not found
1410  return 0;
1411 }
1412 
1413 // An alternative cf_get_file_list*(), true dynamic list version.
1414 // This one has a 'type', which is a CF_TYPE_* value. Because this specifies the directory
1415 // location, 'filter' only needs to be the filter itself, with no path information.
1416 // See above descriptions of cf_get_file_list() for more information about how it all works.
1417 int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *filter, int sort, SCP_vector<file_list_info> *info )
1418 {
1419  char *ptr;
1420  uint i;
1421  int l, own_flag = 0;
1423  file_list_info tinfo;
1424 
1425  if ( !info && (sort == CF_SORT_TIME) ) {
1426  info = &my_info;
1427  own_flag = 1;
1428  }
1429 
1430  char filespec[MAX_PATH_LEN];
1431 
1432  bool check_duplicates = !list.empty();
1433 
1434  if ( check_duplicates && (sort != CF_SORT_NONE) ) {
1435  Int3();
1436  sort = CF_SORT_NONE;
1437  }
1438 
1439  if (Get_file_list_child && !verify_file_list_child() ) {
1440  Get_file_list_child = NULL;
1441  }
1442 
1443 #if defined _WIN32
1444  cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, (char*)Get_file_list_child );
1445  strcat_s(filespec, DIR_SEPARATOR_STR);
1446  strcat_s(filespec, filter);
1447 
1448  _finddata_t find;
1449  int find_handle;
1450 
1451  find_handle = _findfirst( filespec, &find );
1452  if (find_handle != -1) {
1453  do {
1454  if (strcmp(strrchr(filter, '.'), strrchr(find.name,'.')) != 0)
1455  continue;
1456 
1457  if (!(find.attrib & _A_SUBDIR)) {
1458  if ( !Get_file_list_filter || (*Get_file_list_filter)(find.name) ) {
1459  if ( check_duplicates && cf_file_already_in_list(list, find.name) ) {
1460  continue;
1461  }
1462 
1463  ptr = strrchr(find.name, '.');
1464  if (ptr)
1465  l = ptr - find.name;
1466  else
1467  l = strlen(find.name);
1468 
1469  list.push_back( SCP_string(find.name, l) );
1470 
1471  if (info) {
1472  tinfo.write_time = find.time_write;
1473  info->push_back( tinfo );
1474  }
1475  }
1476  }
1477 
1478  } while (!_findnext(find_handle, &find));
1479 
1480  _findclose( find_handle );
1481  }
1482 
1483 #elif defined SCP_UNIX
1484  cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, (char*)Get_file_list_child );
1485 
1486  DIR *dirp;
1487  struct dirent *dir;
1488 
1489  dirp = opendir (filespec);
1490  if ( dirp ) {
1491  while ((dir = readdir (dirp)) != NULL) {
1492 
1493  if (fnmatch(filter, dir->d_name, 0) != 0)
1494  continue;
1495 
1496  char fn[MAX_PATH];
1497  snprintf(fn, MAX_PATH-1, "%s/%s", filespec, dir->d_name);
1498  fn[MAX_PATH-1] = 0;
1499 
1500  struct stat buf;
1501  if (stat(fn, &buf) == -1) {
1502  continue;
1503  }
1504 
1505  if (!S_ISREG(buf.st_mode)) {
1506  continue;
1507  }
1508 
1509  if ( !Get_file_list_filter || (*Get_file_list_filter)(dir->d_name) ) {
1510  if ( check_duplicates && cf_file_already_in_list(list, dir->d_name) ) {
1511  continue;
1512  }
1513 
1514  ptr = strrchr(dir->d_name, '.');
1515  if (ptr)
1516  l = ptr - dir->d_name;
1517  else
1518  l = strlen(dir->d_name);
1519 
1520  list.push_back( SCP_string(dir->d_name, l) );
1521 
1522  if (info) {
1523  tinfo.write_time = buf.st_mtime;
1524  info->push_back( tinfo );
1525  }
1526  }
1527  }
1528 
1529  closedir(dirp);
1530  }
1531 #endif
1532 
1533  bool skip_packfiles = (Skip_packfile_search != 0);
1534 
1535  if ( (pathtype == CF_TYPE_PLAYERS) || (pathtype == CF_TYPE_SINGLE_PLAYERS) || (pathtype == CF_TYPE_MULTI_PLAYERS) ) {
1536  skip_packfiles = true;
1537  } else if (Get_file_list_child != NULL) {
1538  skip_packfiles = true;
1539  }
1540 
1541  // Search all the packfiles and CD.
1542  if ( !skip_packfiles ) {
1543  for (i=0; i<Num_files; i++ ) {
1544  cf_file * f = cf_get_file(i);
1545 
1546  // only search paths we're supposed to...
1547  if ( (pathtype != CF_TYPE_ANY) && (pathtype != f->pathtype_index) ) {
1548  continue;
1549  }
1550 
1551  if ( !cf_matches_spec( filter,f->name_ext)) {
1552  continue;
1553  }
1554 
1555  if ( cf_file_already_in_list(list, f->name_ext)) {
1556  continue;
1557  }
1558 
1560  //mprintf(( "Found '%s' in root %d path %d\n", f->name_ext, f->root_index, f->pathtype_index ));
1561 
1562  ptr = strrchr(f->name_ext, '.');
1563  if (ptr)
1564  l = ptr - f->name_ext;
1565  else
1566  l = strlen(f->name_ext);
1567 
1568  list.push_back( SCP_string(f->name_ext, l) );
1569 
1570  if (info) {
1571  tinfo.write_time = f->write_time;
1572  info->push_back( tinfo );
1573  }
1574  }
1575 
1576  }
1577  }
1578 
1579 
1580  if (sort != CF_SORT_NONE) {
1581  cf_sort_filenames( list, sort, info );
1582  }
1583 
1584  if (own_flag) {
1585  my_info.clear();
1586  }
1587 
1588  Get_file_list_filter = NULL;
1589  Get_file_list_child = NULL;
1590 
1591  return (int)list.size();
1592 }
1593 
1594 int cf_file_already_in_list( int num_files, char **list, const char *filename )
1595 {
1596  int i;
1597 
1598  char name_no_extension[MAX_PATH_LEN];
1599 
1600  strcpy_s(name_no_extension, filename );
1601  char *p = strrchr( name_no_extension, '.' );
1602  if ( p ) *p = 0;
1603 
1604  for (i=0; i<num_files; i++ ) {
1605  if ( !stricmp(list[i], name_no_extension ) ) {
1606  // Match found!
1607  return 1;
1608  }
1609  }
1610  // Not found
1611  return 0;
1612 }
1613 
1614 // An alternative cf_get_file_list(), dynamic list version.
1615 // This one has a 'type', which is a CF_TYPE_* value. Because this specifies the directory
1616 // location, 'filter' only needs to be the filter itself, with no path information.
1617 // See above descriptions of cf_get_file_list() for more information about how it all works.
1618 int cf_get_file_list( int max, char **list, int pathtype, const char *filter, int sort, file_list_info *info )
1619 {
1620  char *ptr;
1621  uint i;
1622  int l, num_files = 0, own_flag = 0;
1623 
1624  if (max < 1) {
1625  Get_file_list_filter = NULL;
1626 
1627  return 0;
1628  }
1629 
1630  Assert(list);
1631 
1632  if (!info && (sort == CF_SORT_TIME)) {
1633  info = (file_list_info *) vm_malloc(sizeof(file_list_info) * max);
1634  own_flag = 1;
1635  }
1636 
1637  char filespec[MAX_PATH_LEN];
1638 
1639 #if defined _WIN32
1640  cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, filter );
1641 
1642  _finddata_t find;
1643  int find_handle;
1644 
1645  find_handle = _findfirst( filespec, &find );
1646  if (find_handle != -1) {
1647  do {
1648  if (num_files >= max)
1649  break;
1650 
1651  if (strcmp(strrchr(filter, '.'), strrchr(find.name,'.')) != 0)
1652  continue;
1653 
1654  if ( strlen(find.name) >= MAX_FILENAME_LEN )
1655  continue;
1656 
1657  if (!(find.attrib & _A_SUBDIR)) {
1658  if ( !Get_file_list_filter || (*Get_file_list_filter)(find.name) ) {
1659  ptr = strrchr(find.name, '.');
1660  if (ptr)
1661  l = ptr - find.name;
1662  else
1663  l = strlen(find.name);
1664 
1665  list[num_files] = (char *)vm_malloc(l + 1);
1666  strncpy(list[num_files], find.name, l);
1667  list[num_files][l] = 0;
1668  if (info)
1669  info[num_files].write_time = find.time_write;
1670 
1671  num_files++;
1672  }
1673  }
1674 
1675  } while (!_findnext(find_handle, &find));
1676 
1677  _findclose( find_handle );
1678  }
1679 
1680 #elif defined SCP_UNIX
1681  cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, NULL );
1682 
1683  DIR *dirp;
1684  struct dirent *dir;
1685 
1686  dirp = opendir (filespec);
1687  if ( dirp ) {
1688  while ((dir = readdir (dirp)) != NULL)
1689  {
1690  if (num_files >= max)
1691  break;
1692 
1693  if ( strlen(dir->d_name) >= MAX_FILENAME_LEN ) {
1694  continue;
1695  }
1696 
1697  if (fnmatch(filter, dir->d_name, 0) != 0)
1698  continue;
1699 
1700  char fn[MAX_PATH];
1701  snprintf(fn, MAX_PATH-1, "%s/%s", filespec, dir->d_name);
1702  fn[MAX_PATH-1] = 0;
1703 
1704  struct stat buf;
1705  if (stat(fn, &buf) == -1) {
1706  continue;
1707  }
1708 
1709  if (!S_ISREG(buf.st_mode)) {
1710  continue;
1711  }
1712 
1713  if ( !Get_file_list_filter || (*Get_file_list_filter)(dir->d_name) ) {
1714  ptr = strrchr(dir->d_name, '.');
1715  if (ptr)
1716  l = ptr - dir->d_name;
1717  else
1718  l = strlen(dir->d_name);
1719 
1720  list[num_files] = (char *)vm_malloc(l + 1);
1721  strncpy(list[num_files], dir->d_name, l);
1722  list[num_files][l] = 0;
1723  if (info)
1724  info[num_files].write_time = buf.st_mtime;
1725 
1726  num_files++;
1727  }
1728  }
1729 
1730  closedir(dirp);
1731  }
1732 #endif
1733 
1734  // Search all the packfiles and CD.
1735  if ( !Skip_packfile_search ) {
1736  for (i=0; i<Num_files; i++ ) {
1737  cf_file * f = cf_get_file(i);
1738 
1739  // only search paths we're supposed to...
1740  if ( (pathtype != CF_TYPE_ANY) && (pathtype != f->pathtype_index) ) {
1741  continue;
1742  }
1743 
1744  if (num_files >= max)
1745  break;
1746 
1747  if ( !cf_matches_spec( filter,f->name_ext)) {
1748  continue;
1749  }
1750 
1751  if ( cf_file_already_in_list(num_files,list,f->name_ext)) {
1752  continue;
1753  }
1754 
1756 
1757  //mprintf(( "Found '%s' in root %d path %d\n", f->name_ext, f->root_index, f->pathtype_index ));
1758 
1759  ptr = strrchr(f->name_ext, '.');
1760  if (ptr)
1761  l = ptr - f->name_ext;
1762  else
1763  l = strlen(f->name_ext);
1764 
1765  list[num_files] = (char *)vm_malloc(l + 1);
1766  strncpy(list[num_files], f->name_ext, l);
1767  list[num_files][l] = 0;
1768 
1769  if (info) {
1770  info[num_files].write_time = f->write_time;
1771  }
1772 
1773  num_files++;
1774  }
1775 
1776  }
1777  }
1778 
1779 
1780  if (sort != CF_SORT_NONE) {
1781  cf_sort_filenames( num_files, list, sort, info );
1782  }
1783 
1784  if (own_flag) {
1785  vm_free(info);
1786  }
1787 
1788  Get_file_list_filter = NULL;
1789 
1790  return num_files;
1791 }
1792 
1793 int cf_file_already_in_list_preallocated( int num_files, char arr[][MAX_FILENAME_LEN], const char *filename )
1794 {
1795  int i;
1796 
1797  char name_no_extension[MAX_PATH_LEN];
1798 
1799  strcpy_s(name_no_extension, filename );
1800  char *p = strrchr( name_no_extension, '.' );
1801  if ( p ) *p = 0;
1802 
1803  for (i=0; i<num_files; i++ ) {
1804  if ( !stricmp(arr[i], name_no_extension ) ) {
1805  // Match found!
1806  return 1;
1807  }
1808  }
1809  // Not found
1810  return 0;
1811 }
1812 
1813 // An alternative cf_get_file_list(), fixed array version.
1814 // This one has a 'type', which is a CF_TYPE_* value. Because this specifies the directory
1815 // location, 'filter' only needs to be the filter itself, with no path information.
1816 // See above descriptions of cf_get_file_list() for more information about how it all works.
1817 int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char **list, int pathtype, const char *filter, int sort, file_list_info *info )
1818 {
1819  int num_files = 0, own_flag = 0;
1820 
1821  if (max < 1) {
1822  Get_file_list_filter = NULL;
1823 
1824  return 0;
1825  }
1826 
1827  if (list) {
1828  for (int i=0; i<max; i++) {
1829  list[i] = arr[i];
1830  }
1831  } else {
1832  sort = CF_SORT_NONE; // sorting of array directly not supported. Sorting done on list only
1833  }
1834 
1835  if (!info && (sort == CF_SORT_TIME)) {
1836  info = (file_list_info *) vm_malloc(sizeof(file_list_info) * max);
1837 
1838  if ( info )
1839  own_flag = 1;
1840  }
1841 
1842  char filespec[MAX_PATH_LEN];
1843 
1844  // Search the default directories
1845 #if defined _WIN32
1846  cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, filter );
1847 
1848  int find_handle;
1849  _finddata_t find;
1850 
1851  find_handle = _findfirst( filespec, &find );
1852  if (find_handle != -1) {
1853  do {
1854  if (num_files >= max)
1855  break;
1856 
1857  if (!(find.attrib & _A_SUBDIR)) {
1858 
1859  if (strcmp(strstr(filter, "."), strstr(find.name,".")) != 0)
1860  continue;
1861 
1862  if ( strlen(find.name) >= MAX_FILENAME_LEN )
1863  continue;
1864 
1865  if ( !Get_file_list_filter || (*Get_file_list_filter)(find.name) ) {
1866 
1867  strncpy(arr[num_files], find.name, MAX_FILENAME_LEN - 1 );
1868  char *ptr = strrchr(arr[num_files], '.');
1869  if ( ptr ) {
1870  *ptr = 0;
1871  }
1872 
1873  if (info) {
1874  info[num_files].write_time = find.time_write;
1875  }
1876 
1877  num_files++;
1878  }
1879  }
1880 
1881  } while (!_findnext(find_handle, &find));
1882 
1883  _findclose( find_handle );
1884  }
1885 
1886 #elif defined SCP_UNIX
1887  cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, NULL );
1888 
1889  DIR *dirp;
1890  struct dirent *dir;
1891 
1892  dirp = opendir (filespec);
1893  if ( dirp ) {
1894  while ((dir = readdir (dirp)) != NULL)
1895  {
1896  if (num_files >= max)
1897  break;
1898 
1899  if (fnmatch(filter, dir->d_name, 0) != 0)
1900  continue;
1901 
1902  char fn[MAX_PATH];
1903  snprintf(fn, MAX_PATH-1, "%s/%s", filespec, dir->d_name);
1904  fn[MAX_PATH-1] = 0;
1905 
1906  struct stat buf;
1907  if (stat(fn, &buf) == -1) {
1908  continue;
1909  }
1910 
1911  if (!S_ISREG(buf.st_mode)) {
1912  continue;
1913  }
1914 
1915  if ( strlen(dir->d_name) >= MAX_FILENAME_LEN ) {
1916  continue;
1917  }
1918 
1919  if ( !Get_file_list_filter || (*Get_file_list_filter)(dir->d_name) ) {
1920 
1921  strncpy(arr[num_files], dir->d_name, MAX_FILENAME_LEN - 1 );
1922  char *ptr = strrchr(arr[num_files], '.');
1923  if ( ptr ) {
1924  *ptr = 0;
1925  }
1926 
1927  if (info) {
1928  info[num_files].write_time = buf.st_mtime;
1929  }
1930 
1931  num_files++;
1932  }
1933  }
1934  closedir(dirp);
1935  }
1936 #endif
1937 
1938  // Search all the packfiles and CD.
1939  if ( !Skip_packfile_search ) {
1940  for (uint i=0; i<Num_files; i++ ) {
1941  cf_file * f = cf_get_file(i);
1942 
1943  // only search paths we're supposed to...
1944  if ( (pathtype != CF_TYPE_ANY) && (pathtype != f->pathtype_index) ) {
1945  continue;
1946  }
1947 
1948  if (num_files >= max)
1949 
1950  break;
1951 
1952  if ( !cf_matches_spec( filter,f->name_ext)) {
1953  continue;
1954  }
1955 
1956  if ( cf_file_already_in_list_preallocated( num_files, arr, f->name_ext )) {
1957  continue;
1958  }
1959 
1961 
1962  //mprintf(( "Found '%s' in root %d path %d\n", f->name_ext, f->root_index, f->pathtype_index ));
1963 
1964  strncpy(arr[num_files], f->name_ext, MAX_FILENAME_LEN - 1 );
1965  char *ptr = strrchr(arr[num_files], '.');
1966  if ( ptr ) {
1967  *ptr = 0;
1968  }
1969 
1970  if (info) {
1971  info[num_files].write_time = f->write_time;
1972  }
1973 
1974  num_files++;
1975  }
1976 
1977  }
1978  }
1979 
1980  if (sort != CF_SORT_NONE) {
1981  Assert(list);
1982  cf_sort_filenames( num_files, list, sort, info );
1983  }
1984 
1985  if (own_flag) {
1986  vm_free(info);
1987  }
1988 
1989  Get_file_list_filter = NULL;
1990 
1991  return num_files;
1992 }
1993 
1994 // Returns the default storage path for files given a
1995 // particular pathtype. In other words, the path to
1996 // the unpacked, non-cd'd, stored on hard drive path.
1997 // If filename isn't null it will also tack the filename
1998 // on the end, creating a completely valid filename.
1999 // Input: pathtype - CF_TYPE_??
2000 // path_max - Maximum characters in the path
2001 // filename - optional, if set, tacks the filename onto end of path.
2002 // Output: path - Fully qualified pathname.
2003 //Returns 0 if the result would be too long (invalid result)
2004 int cf_create_default_path_string(char *path, uint path_max, int pathtype, const char *filename, bool localize )
2005 {
2006 #ifdef SCP_UNIX
2007  if ( filename && strpbrk(filename,"/") ) {
2008 #else
2009  if ( filename && strpbrk(filename,"/\\:") ) {
2010 #endif
2011  // Already has full path
2012  strncpy( path, filename, path_max );
2013 
2014  } else {
2015  cf_root *root = cf_get_root(0);
2016 
2017  if (!root) {
2018  Assert( filename != NULL );
2019  strncpy(path, filename, path_max);
2020  return 1;
2021  }
2022 
2023  Assert(CF_TYPE_SPECIFIED(pathtype));
2024 
2025  // force a specific directory to search for player files
2026  if ( (pathtype == CF_TYPE_PLAYERS) || (pathtype == CF_TYPE_SINGLE_PLAYERS) || (pathtype == CF_TYPE_MULTI_PLAYERS) ) {
2027  strncpy(path, Pilot_file_path, path_max);
2028  } else {
2029  strncpy(path, root->path, path_max);
2030  }
2031 
2032  strcat_s(path, path_max, Pathtypes[pathtype].path);
2033 
2034  // Don't add slash for root directory
2035  if (Pathtypes[pathtype].path[0] != '\0') {
2036  if ( path[strlen(path)-1] != DIR_SEPARATOR_CHAR ) {
2037  strcat_s(path, path_max, DIR_SEPARATOR_STR);
2038  }
2039  }
2040 
2041  // add filename
2042  if (filename) {
2043  strcat_s(path, path_max, filename);
2044 
2045  // localize filename
2046  if (localize) {
2047  // create copy of path
2048  char path_tmp[MAX_PATH_LEN] = { 0 };
2049  strncpy( path_tmp, path, MAX_PATH_LEN - 1 );
2050 
2051  // localize the path
2052  if(lcl_add_dir_to_path_with_filename(path_tmp, MAX_PATH_LEN - 1)) {
2053  // verify localized path
2054  FILE *fp = fopen(path, "rb");
2055  if (fp) {
2056  fclose(fp);
2057  return 1;
2058  }
2059  }
2060  }
2061  }
2062  }
2063 
2064  return 1;
2065 }
2066 
2067 // Returns the default storage path for files given a
2068 // particular pathtype. In other words, the path to
2069 // the unpacked, non-cd'd, stored on hard drive path.
2070 // If filename isn't null it will also tack the filename
2071 // on the end, creating a completely valid filename.
2072 // Input: pathtype - CF_TYPE_??
2073 // filename - optional, if set, tacks the filename onto end of path.
2074 // Output: path - Fully qualified pathname.
2075 //Returns 0 if the result would be too long (invalid result)
2076 int cf_create_default_path_string( SCP_string &path, int pathtype, const char *filename, bool localize )
2077 {
2078 #ifdef SCP_UNIX
2079  if ( filename && strpbrk(filename,"/") ) {
2080 #else
2081  if ( filename && strpbrk(filename,"/\\:") ) {
2082 #endif
2083  // Already has full path
2084  path.assign(filename);
2085 
2086  } else {
2087  cf_root *root = cf_get_root(0);
2088 
2089  if (!root) {
2090  Assert( filename != NULL );
2091  path.assign(filename);
2092  return 1;
2093  }
2094 
2095  Assert(CF_TYPE_SPECIFIED(pathtype));
2096  std::ostringstream s_path;
2097 
2098  // force a specific directory to search for player files
2099  if ( (pathtype == CF_TYPE_PLAYERS) || (pathtype == CF_TYPE_SINGLE_PLAYERS) || (pathtype == CF_TYPE_MULTI_PLAYERS) ) {
2100  s_path << Pilot_file_path;
2101  } else {
2102  s_path << root->path;
2103  }
2104 
2105  s_path << Pathtypes[pathtype].path;
2106 
2107  // Don't add slash for root directory
2108  if (Pathtypes[pathtype].path[0] != '\0') {
2109  if ( *(s_path.str().rbegin()) != DIR_SEPARATOR_CHAR ) {
2110  s_path << DIR_SEPARATOR_STR;
2111  }
2112  // if ( path[strlen(path)-1] != DIR_SEPARATOR_CHAR ) {
2113  // strcat_s(path, path_max, DIR_SEPARATOR_STR);
2114  // }
2115  }
2116 
2117  // add filename
2118  if (filename) {
2119  s_path << filename;
2120  }
2121 
2122  path = s_path.str().c_str();
2123  }
2124 
2125  return 1;
2126 }
2127 
2129 {
2130  int i;
2132  char datetime[45];
2133  uint chksum = 0;
2134  time_t my_time;
2135 
2136 #ifdef SCP_UNIX
2137  sprintf(out_path, "%s%svp_crcs.txt", Cfile_user_dir, DIR_SEPARATOR_STR);
2138 #else
2139  sprintf(out_path, "%s%svp_crcs.txt", Cfile_root_dir, DIR_SEPARATOR_STR);
2140 #endif
2141 
2142  FILE *out = fopen(out_path, "w");
2143 
2144  if (out == NULL) {
2145  Int3();
2146  return;
2147  }
2148 
2149  my_time = time(NULL);
2150 
2151  memset( datetime, 0, sizeof(datetime) );
2152  snprintf(datetime, sizeof(datetime)-1, "%s", ctime(&my_time));
2153  // ctime() adds a newline char, so we have to strip it off
2154  datetime[strlen(datetime)-1] = '\0';
2155 
2156  fprintf(out, "Pack file CRC log (%s) ... \n", datetime);
2157  fprintf(out, "-------------------------------------------------------------------------------\n");
2158 
2159  for (i = 0; i < Num_roots; i++) {
2160  cf_root *cur_root = cf_get_root(i);
2161 
2162  if (cur_root->roottype != CF_ROOTTYPE_PACK)
2163  continue;
2164 
2165  chksum = 0;
2166  cf_chksum_pack(cur_root->path, &chksum, true);
2167 
2168  fprintf(out, " %s -- 0x%x\n", cur_root->path, chksum);
2169  }
2170 
2171  fprintf(out, "-------------------------------------------------------------------------------\n");
2172 
2173  fclose(out);
2174 }
int filelength(int fd)
#define MAX_FILENAME_LEN
Definition: pstypes.h:324
int i
Definition: multi_pxo.cpp:466
#define vm_free(ptr)
Definition: pstypes.h:548
#define CF_TYPE_SINGLE_PLAYERS
Definition: cfile.h:70
char * Pilot_file_path
Definition: cfilesystem.cpp:46
#define MIN(a, b)
Definition: pstypes.h:296
void cfile_spew_pack_file_crcs()
const char * Get_file_list_child
void cf_build_root_list(const char *cdrom_dir)
char * path
Definition: cfilesystem.h:24
#define CF_TYPE_PLAYERS
Definition: cfile.h:67
GLuint index
Definition: Glext.h:5608
#define MAX_PATH
Assert(pm!=NULL)
cf_file * cf_create_file()
#define mprintf(args)
Definition: pstypes.h:238
#define DIR_SEPARATOR_CHAR
Definition: pstypes.h:43
char name_ext[CF_MAX_FILENAME_LENGTH]
Definition: cfilesystem.cpp:80
GLclampf f
Definition: Glext.h:7097
void cf_free_secondary_filelist()
long _fs_time_t
Definition: pstypes.h:55
struct VP_FILE VP_FILE
_fs_time_t write_time
#define Assertion(expr, msg,...)
Definition: clang.h:41
#define CF_NUM_ROOTS_PER_BLOCK
Definition: cfilesystem.cpp:65
void cf_search_root_path(int root_index)
struct cf_root cf_root
int pack_offset
Definition: cfilesystem.cpp:85
char path[CF_MAX_PATHNAME_LENGTH]
Definition: cfilesystem.cpp:54
std::basic_string< char, std::char_traits< char >, std::allocator< char > > SCP_string
Definition: vmallocator.h:21
bool cf_packfile_sort_func(const cf_root_sort &r1, const cf_root_sort &r2)
int cf_create_default_path_string(char *path, uint path_max, int pathtype, const char *filename, bool localize)
GLsizeiptr size
Definition: Glext.h:5496
#define Int3()
Definition: pstypes.h:292
char path[CF_MAX_PATHNAME_LENGTH]
Definition: cfilesystem.cpp:60
int root_index
Definition: cfilesystem.cpp:81
int pathtype_index
Definition: cfilesystem.cpp:82
time_t write_time
Definition: cfile.h:35
#define CF_TYPE_MULTI_CACHE
Definition: cfile.h:73
int cf_chksum_pack(const char *filename, uint *chk_long, bool full)
Definition: cfile.cpp:1722
void cf_build_pack_list(cf_root *root)
cf_root roots[CF_NUM_ROOTS_PER_BLOCK]
Definition: cfilesystem.cpp:70
int _getcwd(char *buffer, unsigned int len)
int lcl_add_dir_to_path_with_filename(char *current_path, size_t path_max)
Definition: localize.cpp:536
#define CF_TYPE_ROOT
Definition: cfile.h:45
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
GLintptr offset
Definition: Glext.h:5497
#define CF_MAX_PATHNAME_LENGTH
Definition: cfile.h:40
GLdouble GLdouble GLdouble r
Definition: Glext.h:5337
unsigned int uint
Definition: pstypes.h:64
void cf_search_root_pack(int root_index)
cf_pathtype Pathtypes[CF_MAX_PATH_TYPES]
Definition: cfile.cpp:49
#define CF_TYPE_MULTI_PLAYERS
Definition: cfile.h:71
#define DIR_SEPARATOR_STR
Definition: pstypes.h:44
#define CF_SORT_TIME
Definition: cfile.h:94
struct cf_root_block cf_root_block
char * filename
#define strnicmp(s1, s2, n)
Definition: config.h:272
int cf_get_packfile_count(cf_root *root)
struct cf_file cf_file
cf_file files[CF_NUM_FILES_PER_BLOCK]
Definition: cfilesystem.cpp:92
char * stristr(char *str, const char *substr)
Definition: parselo.cpp:3729
#define CF_NUM_FILES_PER_BLOCK
Definition: cfilesystem.cpp:88
sprintf(buf,"(%f,%f,%f)", v3->xyz.x, v3->xyz.y, v3->xyz.z)
int(* Get_file_list_filter)(const char *filename)
cfbp fp
Definition: cfile.cpp:1065
void cf_sort_filenames(int n, char **list, int sort, file_list_info *info=NULL)
Definition: cfilelist.cpp:115
time_t write_time
Definition: cfilesystem.cpp:83
char filename[32]
int cf_get_file_list_preallocated(int max, char arr[][MAX_FILENAME_LEN], char **list, int pathtype, const char *filter, int sort, file_list_info *info)
GLclampd n
Definition: Glext.h:7286
#define CF_SORT_NONE
Definition: cfile.h:92
int cf_matches_spec(const char *filespec, const char *filename)
cf_root * cf_create_root()
int cf_find_file_location(const char *filespec, int pathtype, int max_out, char *pack_filename, int *size, int *offset, bool localize)
cf_file * cf_get_file(int index)
#define CF_ROOTTYPE_PACK
Definition: cfilesystem.cpp:43
void _cdecl void void _cdecl Error(const char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
#define vm_malloc(size)
Definition: pstypes.h:547
#define CF_TYPE_CACHE
Definition: cfile.h:72
#define INTEL_INT(x)
Definition: pstypes.h:388
#define CF_MAX_FILE_BLOCKS
Definition: cfilesystem.cpp:89
#define MAX_PATH_LEN
Definition: pstypes.h:325
void cf_build_secondary_filelist(const char *cdrom_dir)
#define CF_TYPE_DATA
Definition: cfile.h:46
unsigned int Num_files
int cf_get_file_list(SCP_vector< SCP_string > &list, int pathtype, const char *filter, int sort, SCP_vector< file_list_info > *info)
int cf_find_file_location_ext(const char *filename, const int ext_num, const char **ext_list, int pathtype, int max_out, char *pack_filename, int *size, int *offset, bool localize)
int roottype
Definition: cfilesystem.cpp:55
#define strcat_s(...)
Definition: safe_strings.h:68
char Cfile_root_dir[CFILE_ROOT_DIRECTORY_LEN]
Definition: cfile.cpp:38
#define CF_MAX_ROOT_BLOCKS
Definition: cfilesystem.cpp:66
#define CF_TYPE_SPECIFIED(path_type)
Definition: cfile.h:86
void cf_build_file_list()
#define CFILE_ROOT_DIRECTORY_LEN
Definition: cfile.h:110
GLsizei const GLchar ** path
Definition: Glext.h:6795
#define CF_TYPE_MISSIONS
Definition: cfile.h:74
GLfloat GLfloat p
Definition: Glext.h:8373
#define LOCATION
Definition: pstypes.h:245
int cf_file_already_in_list(int num_files, char **list, const char *filename)
int is_ext_in_list(const char *ext_list, const char *ext)
int cf_file_already_in_list_preallocated(int num_files, char arr[][MAX_FILENAME_LEN], const char *filename)
#define CF_MAX_FILENAME_LENGTH
Definition: cfile.h:39
#define CF_ROOTTYPE_PATH
Definition: cfilesystem.cpp:42
#define CF_MAX_PATH_TYPES
Definition: cfile.h:82
struct cf_root_sort cf_root_sort
struct VP_FILE_HEADER VP_FILE_HEADER
GLenum GLsizei len
Definition: Glext.h:6283
char * Cmdline_mod
Definition: cmdline.cpp:397
#define CF_TYPE_ANY
Definition: cfile.h:42
void strlwr(char *s)
int cfile_inited
Definition: cfile.cpp:94
#define stricmp(s1, s2)
Definition: config.h:271
cf_root * cf_get_root(int n)
int Skip_packfile_search
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: Glext.h:6566
struct cf_file_block cf_file_block
#define strcpy_s(...)
Definition: safe_strings.h:67