2 * $Logfile: /Freespace2/code/CFile/CfileSystem.cpp $
7 * Functions to keep track of and find files that can exist
8 * on the harddrive, cd-rom, or in a pack file on either of those.
9 * This keeps a list of all the files in packfiles or on CD-rom
10 * and when you need a file you call one function which then searches
11 * all those locations, inherently enforcing precedence orders.
14 * Revision 1.4 2002/05/28 17:26:57 theoddone33
15 * Fill in some timer and palette setting stubs. Still no display
17 * Revision 1.3 2002/05/28 06:45:38 theoddone33
20 * Revision 1.2 2002/05/28 06:28:20 theoddone33
21 * Filesystem mods, actually reads some data files now
23 * Revision 1.1.1.1 2002/05/03 03:28:08 root
27 * 6 9/08/99 10:01p Dave
28 * Make sure game won't run in a drive's root directory. Make sure
29 * standalone routes suqad war messages properly to the host.
31 * 5 9/03/99 1:31a Dave
32 * CD checking by act. Added support to play 2 cutscenes in a row
33 * seamlessly. Fixed super low level cfile bug related to files in the
34 * root directory of a CD. Added cheat code to set campaign mission # in
37 * 4 2/22/99 10:31p Andsager
38 * Get rid of unneeded includes.
40 * 3 10/13/98 9:19a Andsager
41 * Add localization support to cfile. Optional parameter with cfopen that
42 * looks for localized files.
44 * 2 10/07/98 10:52a Dave
47 * 1 10/07/98 10:48a Dave
49 * 14 8/31/98 2:06p Dave
50 * Make cfile sort the ordering or vp files. Added support/checks for
51 * recognizing "mission disk" players.
53 * 13 6/23/98 4:18p Hoffoss
54 * Fixed some bugs with AC release build.
56 * 12 5/20/98 10:46p John
57 * Added code that doesn't include duplicate filenames in any file list
60 * 11 5/14/98 2:14p Lawrance2
61 * Use filespec filtering for packfiles
63 * 10 5/03/98 11:53a John
64 * Fixed filename case mangling.
66 * 9 5/02/98 11:06p Allender
67 * correctly deal with pack pathnames
69 * 8 5/01/98 11:41a Allender
70 * Fixed bug with mission saving in Fred.
72 * 7 5/01/98 10:21a John
73 * Added code to find all pack files in all trees. Added code to create
74 * any directories that we write to.
76 * 6 4/30/98 10:21p John
77 * Added code to cleanup cfilesystem
79 * 5 4/30/98 10:18p John
80 * added source safe header
93 #include <winbase.h> /* needed for memory mapping of file functions */
95 #include <sys/types.h>
101 //#include "outwnd.h"
102 //#include "vecmat.h"
105 #include "cfilesystem.h"
106 #include "localize.h"
109 #define CF_ROOTTYPE_PATH 0
110 #define CF_ROOTTYPE_PACK 1
113 // specifying hard drive tree
114 // searching for pack files on hard drive // Found by searching all known paths
115 // specifying cd-rom tree
116 // searching for pack files on CD-rom tree
117 typedef struct cf_root {
118 char path[CF_MAX_PATHNAME_LENGTH]; // Contains something like c:\projects\freespace or c:\projects\freespace\freespace.vp
119 int roottype; // CF_ROOTTYPE_PATH = Path, CF_ROOTTYPE_PACK =Pack file
122 // convenient type for sorting (see cf_build_pack_list())
123 typedef struct cf_root_sort {
124 char path[CF_MAX_PATHNAME_LENGTH];
129 #define CF_NUM_ROOTS_PER_BLOCK 32
130 #define CF_MAX_ROOT_BLOCKS 256 // Can store 32*256 = 8192 Roots
131 #define CF_MAX_ROOTS (CF_NUM_ROOTS_PER_BLOCK * CF_MAX_ROOT_BLOCKS)
133 typedef struct cf_root_block {
134 cf_root roots[CF_NUM_ROOTS_PER_BLOCK];
137 static int Num_roots = 0;
138 static cf_root_block *Root_blocks[CF_MAX_ROOT_BLOCKS];
141 // Created by searching all roots in order. This means Files is then sorted by precedence.
142 typedef struct cf_file {
143 char name_ext[CF_MAX_FILENAME_LENGTH]; // Filename and extension
144 int root_index; // Where in Roots this is located
145 int pathtype_index; // Where in Paths this is located
146 time_t write_time; // When it was last written
147 int size; // How big it is in bytes
148 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.
151 #define CF_NUM_FILES_PER_BLOCK 256
152 #define CF_MAX_FILE_BLOCKS 128 // Can store 256*128 = 32768 files
154 typedef struct cf_file_block {
155 cf_file files[CF_NUM_FILES_PER_BLOCK];
158 static int Num_files = 0;
159 static cf_file_block *File_blocks[CF_MAX_FILE_BLOCKS];
162 // Return a pointer to to file 'index'.
163 cf_file *cf_get_file(int index)
165 int block = index / CF_NUM_FILES_PER_BLOCK;
166 int offset = index % CF_NUM_FILES_PER_BLOCK;
168 return &File_blocks[block]->files[offset];
171 // Create a new file and return a pointer to it.
172 cf_file *cf_create_file()
174 int block = Num_files / CF_NUM_FILES_PER_BLOCK;
175 int offset = Num_files % CF_NUM_FILES_PER_BLOCK;
177 if ( File_blocks[block] == NULL ) {
178 File_blocks[block] = (cf_file_block *)malloc( sizeof(cf_file_block) );
179 Assert( File_blocks[block] != NULL);
184 return &File_blocks[block]->files[offset];
187 extern int cfile_inited;
189 // Create a new root and return a pointer to it. The structure is assumed unitialized.
190 cf_root *cf_get_root(int n)
192 int block = n / CF_NUM_ROOTS_PER_BLOCK;
193 int offset = n % CF_NUM_ROOTS_PER_BLOCK;
198 return &Root_blocks[block]->roots[offset];
202 // Create a new root and return a pointer to it. The structure is assumed unitialized.
203 cf_root *cf_create_root()
205 int block = Num_roots / CF_NUM_ROOTS_PER_BLOCK;
206 int offset = Num_roots % CF_NUM_ROOTS_PER_BLOCK;
208 if ( Root_blocks[block] == NULL ) {
209 Root_blocks[block] = (cf_root_block *)malloc( sizeof(cf_root_block) );
210 Assert(Root_blocks[block] != NULL);
215 return &Root_blocks[block]->roots[offset];
218 // return the # of packfiles which exist
219 int cf_get_packfile_count(cf_root *root)
221 char filespec[MAX_PATH_LEN];
225 // count up how many packfiles we're gonna have
227 for (i=CF_TYPE_ROOT; i<CF_MAX_PATH_TYPES; i++ ) {
229 strcpy( filespec, root->path );
231 if(strlen(Pathtypes[i].path)){
232 strcat( filespec, Pathtypes[i].path );
233 strcat( filespec, "/" );
239 dirp = opendir (filespec);
241 while ((dir = readdir (dirp)) != NULL)
243 if (!fnmatch ("*.vp", dir->d_name, 0))
248 strcpy( filespec, root->path );
250 if(strlen(Pathtypes[i].path)){
251 strcat( filespec, Pathtypes[i].path );
252 strcat( filespec, "\\" );
255 strcat( filespec, "*.vp" );
260 find_handle = _findfirst( filespec, &find );
262 if (find_handle != -1) {
264 if (!(find.attrib & _A_SUBDIR)) {
268 } while (!_findnext(find_handle, &find));
270 _findclose( find_handle );
275 return packfile_count;
278 // packfile sort function
279 int cf_packfile_sort_func(const void *elem1, const void *elem2)
281 cf_root_sort *r1, *r2;
282 r1 = (cf_root_sort*)elem1;
283 r2 = (cf_root_sort*)elem2;
285 // if the 2 directory types are the same, do a string compare
286 if(r1->cf_type == r2->cf_type){
287 return stricmp(r1->path, r2->path);
290 // otherwise return them in order of CF_TYPE_* precedence
291 return (r1->cf_type < r2->cf_type) ? -1 : 1;
294 // Go through a root and look for pack files
295 void cf_build_pack_list( cf_root *root )
297 char filespec[MAX_PATH_LEN];
299 cf_root_sort *temp_roots_sort, *rptr_sort;
300 int temp_root_count, root_index;
302 // determine how many packfiles there are
303 temp_root_count = cf_get_packfile_count(root);
304 if(temp_root_count <= 0){
308 // allocate a temporary array of temporary roots so we can easily sort them
309 temp_roots_sort = (cf_root_sort*)malloc(sizeof(cf_root_sort) * temp_root_count);
310 if(temp_roots_sort == NULL){
315 // now just setup all the root info
317 for (i=CF_TYPE_ROOT; i<CF_MAX_PATH_TYPES; i++ ) {
320 strcpy( filespec, root->path );
322 if(strlen(Pathtypes[i].path)){
323 strcat( filespec, Pathtypes[i].path );
324 strcat( filespec, "/" );
330 dirp = opendir (filespec);
332 while ((dir = readdir (dirp)) != NULL)
334 if (!fnmatch ("*.vp", dir->d_name, 0))
336 Assert(root_index < temp_root_count);
338 // get a temp pointer
339 rptr_sort = &temp_roots_sort[root_index++];
341 // fill in all the proper info
342 strcpy(rptr_sort->path, root->path);
344 if(strlen(Pathtypes[i].path)){
345 strcat(rptr_sort->path, Pathtypes[i].path );
346 strcat(rptr_sort->path, "/");
349 strcat(rptr_sort->path, dir->d_name );
350 rptr_sort->roottype = CF_ROOTTYPE_PACK;
351 rptr_sort->cf_type = i;
356 strcpy( filespec, root->path );
358 if(strlen(Pathtypes[i].path)){
359 strcat( filespec, Pathtypes[i].path );
360 strcat( filespec, "\\" );
362 strcat( filespec, "*.vp" );
366 find_handle = _findfirst( filespec, &find );
368 if (find_handle != -1) {
371 if (!(find.attrib & _A_SUBDIR)) {
372 Assert(root_index < temp_root_count);
374 // get a temp pointer
375 rptr_sort = &temp_roots_sort[root_index++];
377 // fill in all the proper info
378 strcpy(rptr_sort->path, root->path);
380 if(strlen(Pathtypes[i].path)){
381 strcat(rptr_sort->path, Pathtypes[i].path );
382 strcat(rptr_sort->path, "\\");
385 strcat(rptr_sort->path, find.name );
386 rptr_sort->roottype = CF_ROOTTYPE_PACK;
387 rptr_sort->cf_type = i;
390 } while (!_findnext(find_handle, &find));
392 _findclose( find_handle );
397 // these should always be the same
398 Assert(root_index == temp_root_count);
401 qsort(temp_roots_sort, temp_root_count, sizeof(cf_root_sort), cf_packfile_sort_func);
403 // now insert them all into the real root list properly
405 for(i=0; i<temp_root_count; i++){
406 new_root = cf_create_root();
407 strcpy( new_root->path, root->path );
409 // mwa -- 4/2/98 put in the next 2 lines because the path name needs to be there
410 // to find the files.
411 strcpy(new_root->path, temp_roots_sort[i].path);
412 new_root->roottype = CF_ROOTTYPE_PACK;
415 // free up the temp list
416 free(temp_roots_sort);
420 void cf_build_root_list(char *cdrom_dir)
426 //======================================================
427 // First, check the current directory.
428 // strcpy( root->path, "d:\\projects\\freespace\\" );
430 root = cf_create_root();
432 if ( !_getcwd(root->path, CF_MAX_PATHNAME_LENGTH ) ) {
433 Error(LOCATION, "Can't get current working directory -- %d", errno );
436 // do we already have a slash? as in the case of a root directory install
438 if(strlen(root->path) && (root->path[strlen(root->path)-1] != '/')){
439 strcat(root->path, "/"); // put trailing backslash on for easier path construction
441 if(strlen(root->path) && (root->path[strlen(root->path)-1] != '\\')){
442 strcat(root->path, "\\"); // put trailing backslash on for easier path construction
445 root->roottype = CF_ROOTTYPE_PATH;
447 //======================================================
448 // Next, check any VP files under the current directory.
449 cf_build_pack_list(root);
452 //======================================================
453 // Check the real CD if one...
454 if ( cdrom_dir && strlen(cdrom_dir) ) {
455 root = cf_create_root();
456 strcpy( root->path, cdrom_dir );
457 root->roottype = CF_ROOTTYPE_PATH;
459 //======================================================
460 // Next, check any VP files in the CD-ROM directory.
461 cf_build_pack_list(root);
467 // Given a lower case list of file extensions
468 // separated by spaces, return zero if ext is
470 int is_ext_in_list( char *ext_list, char *ext )
474 strncpy( tmp_ext, ext, 127 );
476 if ( strstr(ext_list, tmp_ext )) {
483 void cf_search_root_path(int root_index)
487 cf_root *root = cf_get_root(root_index);
489 mprintf(( "Searching root '%s'\n", root->path ));
491 char search_path[CF_MAX_PATHNAME_LENGTH];
493 for (i=CF_TYPE_ROOT; i<CF_MAX_PATH_TYPES; i++ ) {
499 strcpy( search_path, root->path );
501 if(strlen(Pathtypes[i].path)){
502 strcat( search_path, Pathtypes[i].path );
503 strcat( search_path, "/" );
506 dirp = opendir (search_path);
508 while ((dir = readdir (dirp)) != NULL)
510 if (!fnmatch ("*.*", dir->d_name, 0))
512 char *ext = strchr( dir->d_name, '.' );
514 if ( is_ext_in_list( Pathtypes[i].extensions, ext ) ) {
516 cf_file *file = cf_create_file();
518 strcpy( file->name_ext, dir->d_name );
519 file->root_index = root_index;
520 file->pathtype_index = i;
522 file->write_time = find.time_write;
523 file->size = find.size;
527 file->pack_offset = 0; // Mark as a non-packed file
529 //mprintf(( "Found file '%s'\n", file->name_ext ));
536 strcpy( search_path, root->path );
538 if(strlen(Pathtypes[i].path)){
539 strcat( search_path, Pathtypes[i].path );
540 strcat( search_path, "\\" );
543 strcat( search_path, "*.*" );
548 find_handle = _findfirst( search_path, &find );
550 if (find_handle != -1) {
552 if (!(find.attrib & _A_SUBDIR)) {
554 char *ext = strchr( find.name, '.' );
556 if ( is_ext_in_list( Pathtypes[i].extensions, ext ) ) {
558 cf_file *file = cf_create_file();
560 strcpy( file->name_ext, find.name );
561 file->root_index = root_index;
562 file->pathtype_index = i;
563 file->write_time = find.time_write;
564 file->size = find.size;
565 file->pack_offset = 0; // Mark as a non-packed file
567 //mprintf(( "Found file '%s'\n", file->name_ext ));
574 } while (!_findnext(find_handle, &find));
576 _findclose( find_handle );
584 typedef struct VP_FILE_HEADER {
591 typedef struct VP_FILE {
598 void cf_search_root_pack(int root_index)
602 cf_root *root = cf_get_root(root_index);
604 //mprintf(( "Searching root pack '%s'\n", root->path ));
608 FILE *fp = fopen( root->path, "rb" );
609 // Read the file header
614 VP_FILE_HEADER VP_header;
616 Assert( sizeof(VP_header) == 16 );
617 fread(&VP_header, 1, sizeof(VP_header), fp);
620 fseek(fp, VP_header.index_offset, SEEK_SET);
622 char search_path[CF_MAX_PATHNAME_LENGTH];
624 strcpy( search_path, "" );
626 // Go through all the files
627 for (i=0; i<VP_header.num_files; i++ ) {
630 fread( &find, sizeof(VP_FILE), 1, fp );
632 if ( find.size == 0 ) {
633 if ( !stricmp( find.filename, ".." )) {
634 int l = strlen(search_path);
635 char *p = &search_path[l-1];
637 while( (p > search_path) && (*p != '/') ) {
639 while( (p > search_path) && (*p != '\\') ) {
645 if ( strlen(search_path) ) {
647 strcat( search_path, "/" );
649 strcat( search_path, "\\" );
652 strcat( search_path, find.filename );
655 //mprintf(( "Current dir = '%s'\n", search_path ));
659 for (j=CF_TYPE_ROOT; j<CF_MAX_PATH_TYPES; j++ ) {
661 if ( !stricmp( search_path, Pathtypes[j].path )) {
663 char *ext = strchr( find.filename, '.' );
665 if ( is_ext_in_list( Pathtypes[j].extensions, ext ) ) {
667 cf_file *file = cf_create_file();
669 strcpy( file->name_ext, find.filename );
670 file->root_index = root_index;
671 file->pathtype_index = j;
672 file->write_time = find.write_time;
673 file->size = find.size;
674 file->pack_offset = find.offset; // Mark as a non-packed file
676 //mprintf(( "Found pack file '%s'\n", file->name_ext ));
690 void cf_build_file_list()
696 // For each root, find all files...
697 for (i=1; i<Num_roots; i++ ) {
698 cf_root *root = cf_get_root(i);
699 if ( root->roottype == CF_ROOTTYPE_PATH ) {
700 cf_search_root_path(i);
701 } else if ( root->roottype == CF_ROOTTYPE_PACK ) {
702 cf_search_root_pack(i);
709 void cf_build_secondary_filelist(char *cdrom_dir)
717 // Init the path types
718 for (i=0; i<CF_MAX_PATH_TYPES; i++ ) {
719 Assert( Pathtypes[i].index == i );
720 if ( Pathtypes[i].extensions ) {
721 strlwr(Pathtypes[i].extensions);
725 // Init the root blocks
726 for (i=0; i<CF_MAX_ROOT_BLOCKS; i++ ) {
727 Root_blocks[i] = NULL;
730 // Init the file blocks
731 for (i=0; i<CF_MAX_FILE_BLOCKS; i++ ) {
732 File_blocks[i] = NULL;
735 mprintf(( "Building file index...\n" ));
737 // build the list of searchable roots
738 cf_build_root_list(cdrom_dir);
740 // build the list of files themselves
741 cf_build_file_list();
743 mprintf(( "Found %d roots and %d files.\n", Num_roots, Num_files ));
746 void cf_free_secondary_filelist()
750 // Free the root blocks
751 for (i=0; i<CF_MAX_ROOT_BLOCKS; i++ ) {
752 if ( Root_blocks[i] ) {
753 free( Root_blocks[i] );
754 Root_blocks[i] = NULL;
759 // Init the file blocks
760 for (i=0; i<CF_MAX_FILE_BLOCKS; i++ ) {
761 if ( File_blocks[i] ) {
762 free( File_blocks[i] );
763 File_blocks[i] = NULL;
769 // Searches for a file. Follows all rules and precedence and searches
770 // CD's and pack files.
771 // Input: filespace - Filename & extension
772 // pathtype - See CF_TYPE_ defines in CFILE.H
773 // Output: pack_filename - Absolute path and filename of this file. Could be a packfile or the actual file.
775 // offset - Offset into pack file. 0 if not a packfile.
776 // Returns: If not found returns 0.
777 int cf_find_file_location( char *filespec, int pathtype, char *pack_filename, int *size, int *offset, bool localize )
781 Assert(filespec && strlen(filespec));
783 // see if we have something other than just a filename
784 // our current rules say that any file that specifies a direct
785 // path will try to be opened on that path. If that open
786 // fails, then we will open the file based on the extension
789 // NOTE: full path should also include localization, if so desired
790 if ( strpbrk(filespec,"/\\:") ) { // do we have a full path already?
791 FILE *fp = fopen(filespec, "rb" );
793 if ( size ) *size = filelength(fileno(fp));
794 if ( offset ) *offset = 0;
795 if ( pack_filename ) {
796 strcpy( pack_filename, filespec );
802 return 0; // If they give a full path, fail if not found.
805 // Search the hard drive for files first.
806 int num_search_dirs = 0;
807 int search_order[CF_MAX_PATH_TYPES];
809 if ( CF_TYPE_SPECIFIED(pathtype) ) {
810 search_order[num_search_dirs++] = pathtype;
813 for (i=CF_TYPE_ROOT; i<CF_MAX_PATH_TYPES; i++) {
814 if ( i != pathtype ) {
815 search_order[num_search_dirs++] = i;
819 for (i=0; i<num_search_dirs; i++ ) {
820 char longname[MAX_PATH_LEN];
822 cf_create_default_path_string( longname, search_order[i], filespec, localize );
824 FILE *fp = fopen(longname, "rb" );
826 if ( size ) *size = filelength(fileno(fp));
827 if ( offset ) *offset = 0;
828 if ( pack_filename ) {
829 strcpy( pack_filename, longname );
836 // Search the pak files and CD-ROM.
838 for (i=0; i<Num_files; i++ ) {
839 cf_file * f = cf_get_file(i);
841 // only search paths we're supposed to...
842 if ( (pathtype != CF_TYPE_ANY) && (pathtype != f->pathtype_index) ) {
847 // create localized filespec
848 char temp[MAX_PATH_LEN];
849 strcpy(temp, filespec);
850 lcl_add_dir_to_path_with_filename(filespec);
852 if ( !stricmp(filespec, f->name_ext) ) {
853 if ( size ) *size = f->size;
854 if ( offset ) *offset = f->pack_offset;
855 if ( pack_filename ) {
856 cf_root * r = cf_get_root(f->root_index);
858 strcpy( pack_filename, r->path );
859 if ( f->pack_offset < 1 ) {
860 strcat( pack_filename, Pathtypes[f->pathtype_index].path );
862 strcat( pack_filename, "/" );
864 strcat( pack_filename, "\\" );
866 strcat( pack_filename, f->name_ext );
871 // restore original filespec
872 strcpy(filespec, temp);
875 // file either not localized or localized version not found
876 if ( !stricmp(filespec, f->name_ext) ) {
877 if ( size ) *size = f->size;
878 if ( offset ) *offset = f->pack_offset;
879 if ( pack_filename ) {
880 cf_root * r = cf_get_root(f->root_index);
882 strcpy( pack_filename, r->path );
883 if ( f->pack_offset < 1 ) {
885 if(strlen(Pathtypes[f->pathtype_index].path)){
886 strcat( pack_filename, Pathtypes[f->pathtype_index].path );
888 strcat( pack_filename, "/" );
890 strcat( pack_filename, "\\" );
894 strcat( pack_filename, f->name_ext );
905 // Returns true if filename matches filespec, else zero if not
906 int cf_matches_spec(char *filespec, char *filename)
908 char *src_ext, *dst_ext;
910 src_ext = strchr(filespec, '.');
916 dst_ext = strchr(filename, '.');
920 return !stricmp(dst_ext, src_ext);
923 int (*Get_file_list_filter)(char *filename) = NULL;
924 int Skip_packfile_search = 0;
926 int cf_file_already_in_list( int num_files, char **list, char *filename )
930 char name_no_extension[MAX_PATH_LEN];
932 strcpy(name_no_extension, filename );
933 char *p = strchr( name_no_extension, '.' );
936 for (i=0; i<num_files; i++ ) {
937 if ( !stricmp(list[i], name_no_extension ) ) {
946 // An alternative cf_get_file_list(), dynamic list version.
947 // This one has a 'type', which is a CF_TYPE_* value. Because this specifies the directory
948 // location, 'filter' only needs to be the filter itself, with no path information.
949 // See above descriptions of cf_get_file_list() for more information about how it all works.
950 int cf_get_file_list( int max, char **list, int pathtype, char *filter, int sort, file_list_info *info )
953 int i, l, find_handle, num_files = 0, own_flag = 0;
959 Get_file_list_filter = NULL;
965 if (!info && (sort == CF_SORT_TIME)) {
966 info = (file_list_info *) malloc(sizeof(file_list_info) * max);
970 char filespec[MAX_PATH_LEN];
972 cf_create_default_path_string( filespec, pathtype, filter );
977 find_handle = _findfirst( filespec, &find );
978 if (find_handle != -1) {
980 if (num_files >= max)
983 if (!(find.attrib & _A_SUBDIR)) {
984 if ( !Get_file_list_filter || (*Get_file_list_filter)(find.name) ) {
985 ptr = strrchr(find.name, '.');
989 l = strlen(find.name);
991 list[num_files] = (char *)malloc(l + 1);
992 strncpy(list[num_files], find.name, l);
993 list[num_files][l] = 0;
995 info[num_files].write_time = find.time_write;
1001 } while (!_findnext(find_handle, &find));
1003 _findclose( find_handle );
1008 // Search all the packfiles and CD.
1009 if ( !Skip_packfile_search ) {
1010 for (i=0; i<Num_files; i++ ) {
1011 cf_file * f = cf_get_file(i);
1013 // only search paths we're supposed to...
1014 if ( (pathtype != CF_TYPE_ANY) && (pathtype != f->pathtype_index) ) {
1018 if (num_files >= max)
1021 if ( !cf_matches_spec( filter,f->name_ext)) {
1025 if ( cf_file_already_in_list(num_files,list,f->name_ext)) {
1029 if ( !Get_file_list_filter || (*Get_file_list_filter)(f->name_ext) ) {
1031 //mprintf(( "Found '%s' in root %d path %d\n", f->name_ext, f->root_index, f->pathtype_index ));
1033 ptr = strrchr(f->name_ext, '.');
1035 l = ptr - f->name_ext;
1037 l = strlen(f->name_ext);
1039 list[num_files] = (char *)malloc(l + 1);
1040 strncpy(list[num_files], f->name_ext, l);
1041 list[num_files][l] = 0;
1044 info[num_files].write_time = f->write_time;
1054 if (sort != CF_SORT_NONE) {
1055 cf_sort_filenames( num_files, list, sort, info );
1062 Get_file_list_filter = NULL;
1066 int cf_file_already_in_list_preallocated( int num_files, char arr[][MAX_FILENAME_LEN], char *filename )
1070 char name_no_extension[MAX_PATH_LEN];
1072 strcpy(name_no_extension, filename );
1073 char *p = strchr( name_no_extension, '.' );
1076 for (i=0; i<num_files; i++ ) {
1077 if ( !stricmp(arr[i], name_no_extension ) ) {
1086 // An alternative cf_get_file_list(), fixed array version.
1087 // This one has a 'type', which is a CF_TYPE_* value. Because this specifies the directory
1088 // location, 'filter' only needs to be the filter itself, with no path information.
1089 // See above descriptions of cf_get_file_list() for more information about how it all works.
1090 int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char **list, int pathtype, char *filter, int sort, file_list_info *info )
1092 int i, num_files = 0, own_flag = 0;
1095 Get_file_list_filter = NULL;
1100 for (i=0; i<max; i++) {
1104 sort = CF_SORT_NONE; // sorting of array directly not supported. Sorting done on list only
1107 if (!info && (sort == CF_SORT_TIME)) {
1108 info = (file_list_info *) malloc(sizeof(file_list_info) * max);
1112 char filespec[MAX_PATH_LEN];
1114 cf_create_default_path_string( filespec, pathtype, filter );
1116 // Search the default directories
1121 dirp = opendir (filespec);
1123 while ((dir = readdir (dirp)) != NULL)
1126 if (num_files >= max)
1130 if ( !Get_file_list_filter || (*Get_file_list_filter)(dir->d_name) ) {
1132 strncpy(arr[num_files], dir->d_name, MAX_FILENAME_LEN - 1 );
1133 char *ptr = strrchr(arr[num_files], '.');
1140 //info[num_files].write_time = find.time_write;
1151 find_handle = _findfirst( filespec, &find );
1152 if (find_handle != -1) {
1154 if (num_files >= max)
1157 if (!(find.attrib & _A_SUBDIR)) {
1159 if ( !Get_file_list_filter || (*Get_file_list_filter)(find.name) ) {
1161 strncpy(arr[num_files], find.name, MAX_FILENAME_LEN - 1 );
1162 char *ptr = strrchr(arr[num_files], '.');
1168 info[num_files].write_time = find.time_write;
1175 } while (!_findnext(find_handle, &find));
1177 _findclose( find_handle );
1182 // Search all the packfiles and CD.
1183 if ( !Skip_packfile_search ) {
1184 for (i=0; i<Num_files; i++ ) {
1185 cf_file * f = cf_get_file(i);
1187 // only search paths we're supposed to...
1188 if ( (pathtype != CF_TYPE_ANY) && (pathtype != f->pathtype_index) ) {
1192 if (num_files >= max)
1195 if ( !cf_matches_spec( filter,f->name_ext)) {
1199 if ( cf_file_already_in_list_preallocated( num_files, arr, f->name_ext )) {
1203 if ( !Get_file_list_filter || (*Get_file_list_filter)(f->name_ext) ) {
1205 //mprintf(( "Found '%s' in root %d path %d\n", f->name_ext, f->root_index, f->pathtype_index ));
1207 strncpy(arr[num_files], f->name_ext, MAX_FILENAME_LEN - 1 );
1208 char *ptr = strrchr(arr[num_files], '.');
1214 info[num_files].write_time = f->write_time;
1223 if (sort != CF_SORT_NONE) {
1225 cf_sort_filenames( num_files, list, sort, info );
1232 Get_file_list_filter = NULL;
1236 // Returns the default storage path for files given a
1237 // particular pathtype. In other words, the path to
1238 // the unpacked, non-cd'd, stored on hard drive path.
1239 // If filename isn't null it will also tack the filename
1240 // on the end, creating a completely valid filename.
1241 // Input: pathtype - CF_TYPE_??
1242 // filename - optional, if set, tacks the filename onto end of path.
1243 // Output: path - Fully qualified pathname.
1244 void cf_create_default_path_string( char *path, int pathtype, char *filename, bool localize )
1247 if ( filename && strpbrk(filename,"/") ) {
1249 if ( filename && strpbrk(filename,"/\\:") ) {
1251 // Already has full path
1252 strcpy( path, filename );
1255 cf_root *root = cf_get_root(0);
1258 strcpy(path, filename);
1262 Assert(CF_TYPE_SPECIFIED(pathtype));
1264 strcpy(path, root->path);
1265 strcat(path, Pathtypes[pathtype].path);
1267 // Don't add slash for root directory
1268 if (Pathtypes[pathtype].path[0] != '\0') {
1278 strcat(path, filename);
1280 // localize filename
1282 // create copy of path
1283 char temp_path[MAX_PATH_LEN];
1284 strcpy(temp_path, path);
1286 // localize the path
1287 lcl_add_dir_to_path_with_filename(path);
1289 // verify localized path
1290 FILE *fp = fopen(path, "rb");
1294 strcpy(path, temp_path);