]> icculus.org git repositories - taylor/freespace2.git/blob - src/cfile/cfilesystem.cpp
byte-swapping changes for bigendian systems
[taylor/freespace2.git] / src / cfile / cfilesystem.cpp
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
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/CFile/CfileSystem.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Functions to keep track of and find files that can exist
16  * on the harddrive, cd-rom, or in a pack file on either of those.
17  * This keeps a list of all the files in packfiles or on CD-rom
18  * and when you need a file you call one function which then searches
19  * all those locations, inherently enforcing precedence orders.
20  *
21  * $Log$
22  * Revision 1.10  2004/06/11 00:29:22  tigital
23  * byte-swapping changes for bigendian systems
24  *
25  * Revision 1.9  2003/05/27 03:03:11  taylor
26  * fix second root (gamedir) searching
27  *
28  * Revision 1.8  2003/02/20 17:41:07  theoddone33
29  * Userdir patch from Taylor Richards
30  *
31  * Revision 1.7  2002/06/22 23:57:39  relnev
32  * remove writable strings.
33  *
34  * fix compile for intel compiler.
35  *
36  * Revision 1.6  2002/06/09 04:41:15  relnev
37  * added copyright header
38  *
39  * Revision 1.5  2002/06/05 04:03:32  relnev
40  * finished cfilesystem.
41  *
42  * removed some old code.
43  *
44  * fixed mouse save off-by-one.
45  *
46  * sound cleanups.
47  *
48  * Revision 1.4  2002/05/28 17:26:57  theoddone33
49  * Fill in some timer and palette setting stubs.  Still no display
50  *
51  * Revision 1.3  2002/05/28 06:45:38  theoddone33
52  * Cleanup some stuff
53  *
54  * Revision 1.2  2002/05/28 06:28:20  theoddone33
55  * Filesystem mods, actually reads some data files now
56  *
57  * Revision 1.1.1.1  2002/05/03 03:28:08  root
58  * Initial import.
59  *
60  * 
61  * 6     9/08/99 10:01p Dave
62  * Make sure game won't run in a drive's root directory. Make sure
63  * standalone routes suqad war messages properly to the host.
64  * 
65  * 5     9/03/99 1:31a Dave
66  * CD checking by act. Added support to play 2 cutscenes in a row
67  * seamlessly. Fixed super low level cfile bug related to files in the
68  * root directory of a CD. Added cheat code to set campaign mission # in
69  * main hall.
70  * 
71  * 4     2/22/99 10:31p Andsager
72  * Get rid of unneeded includes.
73  * 
74  * 3     10/13/98 9:19a Andsager
75  * Add localization support to cfile.  Optional parameter with cfopen that
76  * looks for localized files.
77  * 
78  * 2     10/07/98 10:52a Dave
79  * Initial checkin.
80  * 
81  * 1     10/07/98 10:48a Dave
82  * 
83  * 14    8/31/98 2:06p Dave
84  * Make cfile sort the ordering or vp files. Added support/checks for
85  * recognizing "mission disk" players.
86  * 
87  * 13    6/23/98 4:18p Hoffoss
88  * Fixed some bugs with AC release build.
89  * 
90  * 12    5/20/98 10:46p John
91  * Added code that doesn't include duplicate filenames in any file list
92  * functions.
93  * 
94  * 11    5/14/98 2:14p Lawrance2
95  * Use filespec filtering for packfiles
96  * 
97  * 10    5/03/98 11:53a John
98  * Fixed filename case mangling.
99  * 
100  * 9     5/02/98 11:06p Allender
101  * correctly deal with pack pathnames
102  * 
103  * 8     5/01/98 11:41a Allender
104  * Fixed bug with mission saving in Fred.
105  * 
106  * 7     5/01/98 10:21a John
107  * Added code to find all pack files in all trees.   Added code to create
108  * any directories that we write to.
109  * 
110  * 6     4/30/98 10:21p John
111  * Added code to cleanup cfilesystem
112  * 
113  * 5     4/30/98 10:18p John
114  * added source safe header
115  *
116  * $NoKeywords: $
117  */
118
119 #include <stdlib.h>
120 #include <string.h>
121 #include <stdio.h>
122 #include <errno.h>
123 #ifndef PLAT_UNIX
124 #include <io.h>
125 #include <direct.h>
126 #include <windows.h>
127 #include <winbase.h>            /* needed for memory mapping of file functions */
128 #else
129 #include <sys/types.h>
130 #include <dirent.h>
131 #include <fnmatch.h>
132 #include <sys/stat.h>
133 #include <unistd.h>
134 #endif
135
136 #include "pstypes.h"
137 //#include "outwnd.h"
138 //#include "vecmat.h"
139 //#include "timer.h"
140 #include "cfile.h"
141 #include "cfilesystem.h"
142 #include "localize.h"
143
144
145 #define CF_ROOTTYPE_PATH 0
146 #define CF_ROOTTYPE_PACK 1
147
148 //  Created by:
149 //    specifying hard drive tree
150 //    searching for pack files on hard drive            // Found by searching all known paths
151 //    specifying cd-rom tree
152 //    searching for pack files on CD-rom tree
153 typedef struct cf_root {
154         char                            path[CF_MAX_PATHNAME_LENGTH];           // Contains something like c:\projects\freespace or c:\projects\freespace\freespace.vp
155         int                             roottype;                                                               // CF_ROOTTYPE_PATH  = Path, CF_ROOTTYPE_PACK =Pack file
156 } cf_root;
157
158 // convenient type for sorting (see cf_build_pack_list())
159 typedef struct cf_root_sort { 
160         char                            path[CF_MAX_PATHNAME_LENGTH];
161         int                             roottype;
162         int                             cf_type;
163 } cf_root_sort;
164
165 #define CF_NUM_ROOTS_PER_BLOCK   32
166 #define CF_MAX_ROOT_BLOCKS                      256                             // Can store 32*256 = 8192 Roots
167 #define CF_MAX_ROOTS                                    (CF_NUM_ROOTS_PER_BLOCK * CF_MAX_ROOT_BLOCKS)
168
169 typedef struct cf_root_block {
170         cf_root                 roots[CF_NUM_ROOTS_PER_BLOCK];
171 } cf_root_block;
172
173 static int Num_roots = 0;
174 static cf_root_block  *Root_blocks[CF_MAX_ROOT_BLOCKS];
175   
176
177 // Created by searching all roots in order.   This means Files is then sorted by precedence.
178 typedef struct cf_file {
179         char            name_ext[CF_MAX_FILENAME_LENGTH];               // Filename and extension
180         int             root_index;                                                                             // Where in Roots this is located
181         int             pathtype_index;                                                         // Where in Paths this is located
182         time_t  write_time;                                                                             // When it was last written
183         int             size;                                                                                           // How big it is in bytes
184         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.
185 } cf_file;
186
187 #define CF_NUM_FILES_PER_BLOCK   256
188 #define CF_MAX_FILE_BLOCKS                      128                                             // Can store 256*128 = 32768 files
189
190 typedef struct cf_file_block {
191         cf_file                                         files[CF_NUM_FILES_PER_BLOCK];
192 } cf_file_block;
193
194 static int Num_files = 0;
195 static cf_file_block  *File_blocks[CF_MAX_FILE_BLOCKS];
196
197
198 // Return a pointer to to file 'index'.
199 cf_file *cf_get_file(int index)
200 {
201         int block = index / CF_NUM_FILES_PER_BLOCK;
202         int offset = index % CF_NUM_FILES_PER_BLOCK;
203
204         return &File_blocks[block]->files[offset];
205 }
206
207 // Create a new file and return a pointer to it.
208 cf_file *cf_create_file()
209 {
210         int block = Num_files / CF_NUM_FILES_PER_BLOCK;
211         int offset = Num_files % CF_NUM_FILES_PER_BLOCK;
212         
213         if ( File_blocks[block] == NULL )       {
214                 File_blocks[block] = (cf_file_block *)malloc( sizeof(cf_file_block) );
215                 Assert( File_blocks[block] != NULL);
216         }
217
218         Num_files++;
219
220         return &File_blocks[block]->files[offset];
221 }
222
223 extern int cfile_inited;
224
225 // Create a new root and return a pointer to it.  The structure is assumed unitialized.
226 cf_root *cf_get_root(int n)
227 {
228         int block = n / CF_NUM_ROOTS_PER_BLOCK;
229         int offset = n % CF_NUM_ROOTS_PER_BLOCK;
230
231         if (!cfile_inited)
232                 return NULL;
233
234         return &Root_blocks[block]->roots[offset];
235 }
236
237
238 // Create a new root and return a pointer to it.  The structure is assumed unitialized.
239 cf_root *cf_create_root()
240 {
241         int block = Num_roots / CF_NUM_ROOTS_PER_BLOCK;
242         int offset = Num_roots % CF_NUM_ROOTS_PER_BLOCK;
243         
244         if ( Root_blocks[block] == NULL )       {
245                 Root_blocks[block] = (cf_root_block *)malloc( sizeof(cf_root_block) );
246                 Assert(Root_blocks[block] != NULL);
247         }
248
249         Num_roots++;
250
251         return &Root_blocks[block]->roots[offset];
252 }
253
254 // return the # of packfiles which exist
255 int cf_get_packfile_count(cf_root *root)
256 {
257         char filespec[MAX_PATH_LEN];
258         int i;
259         int packfile_count;
260
261         // count up how many packfiles we're gonna have
262         packfile_count = 0;
263         for (i=CF_TYPE_ROOT; i<CF_MAX_PATH_TYPES; i++ ) {
264 #ifdef PLAT_UNIX
265                 strcpy( filespec, root->path );
266
267                 if(strlen(Pathtypes[i].path)){
268                         strcat( filespec, Pathtypes[i].path );
269                         strcat( filespec, "/" );
270                 }
271
272                 DIR *dirp;
273                 struct dirent *dir;
274
275                 dirp = opendir (filespec);
276                 if ( dirp ) {
277                         while ((dir = readdir (dirp)) != NULL)
278                         {
279                                 if (!fnmatch ("*.vp", dir->d_name, 0))
280                                         packfile_count++;
281                         }
282                         closedir(dirp);
283                 }
284 #else
285                 strcpy( filespec, root->path );
286
287                 if(strlen(Pathtypes[i].path)){
288                         strcat( filespec, Pathtypes[i].path );
289                         strcat( filespec, "\\" );
290                 }
291
292                 strcat( filespec, "*.vp" );
293
294                 int find_handle;
295                 _finddata_t find;
296                 
297                 find_handle = _findfirst( filespec, &find );
298
299                 if (find_handle != -1) {
300                         do {
301                                 if (!(find.attrib & _A_SUBDIR)) {
302                                         packfile_count++;
303                                 }
304
305                         } while (!_findnext(find_handle, &find));
306
307                         _findclose( find_handle );
308                 }       
309 #endif
310         }       
311
312         return packfile_count;
313 }
314
315 // packfile sort function
316 int cf_packfile_sort_func(const void *elem1, const void *elem2)
317 {
318         cf_root_sort *r1, *r2;
319         r1 = (cf_root_sort*)elem1;
320         r2 = (cf_root_sort*)elem2;
321
322         // if the 2 directory types are the same, do a string compare
323         if(r1->cf_type == r2->cf_type){
324                 return stricmp(r1->path, r2->path);
325         }
326
327         // otherwise return them in order of CF_TYPE_* precedence
328         return (r1->cf_type < r2->cf_type) ? -1 : 1;
329 }
330
331 // Go through a root and look for pack files
332 void cf_build_pack_list( cf_root *root )
333 {
334         char filespec[MAX_PATH_LEN];
335         int i;
336         cf_root_sort *temp_roots_sort, *rptr_sort;
337         int temp_root_count, root_index;
338
339         // determine how many packfiles there are
340         temp_root_count = cf_get_packfile_count(root);
341         if(temp_root_count <= 0){
342                 return;
343         }
344
345         // allocate a temporary array of temporary roots so we can easily sort them
346         temp_roots_sort = (cf_root_sort*)malloc(sizeof(cf_root_sort) * temp_root_count);
347         if(temp_roots_sort == NULL){
348                 Int3();
349                 return;
350         }
351
352         // now just setup all the root info
353         root_index = 0;
354         for (i=CF_TYPE_ROOT; i<CF_MAX_PATH_TYPES; i++ ) {
355
356 #ifdef PLAT_UNIX
357                 strcpy( filespec, root->path );
358
359                 if(strlen(Pathtypes[i].path)){
360                         strcat( filespec, Pathtypes[i].path );          
361                         strcat( filespec, "/" );
362                 }
363
364                 DIR *dirp;
365                 struct dirent *dir;
366
367                 dirp = opendir (filespec);
368                 if ( dirp ) {
369                         while ((dir = readdir (dirp)) != NULL)
370                         {
371                                 if (!fnmatch ("*.vp", dir->d_name, 0))
372                                 {
373                                         Assert(root_index < temp_root_count);
374
375                                         char fn[MAX_PATH];
376                                         snprintf(fn, MAX_PATH-1, "%s/%s", filespec, dir->d_name);
377                                         fn[MAX_PATH-1] = 0;
378                                                         
379                                         struct stat buf;
380                                         if (stat(fn, &buf) == -1) {
381                                                 continue;
382                                         }
383                                         
384                                         if (!S_ISREG(buf.st_mode)) {
385                                                 continue;
386                                         }
387                                         
388                                         // get a temp pointer
389                                         rptr_sort = &temp_roots_sort[root_index++];
390
391                                         // fill in all the proper info
392                                         strcpy(rptr_sort->path, root->path);
393
394                                         if(strlen(Pathtypes[i].path)){
395                                                 strcat(rptr_sort->path, Pathtypes[i].path );                                    
396                                                 strcat(rptr_sort->path, "/");
397                                         }
398
399                                         strcat(rptr_sort->path, dir->d_name );
400                                         rptr_sort->roottype = CF_ROOTTYPE_PACK;
401                                         rptr_sort->cf_type = i;
402                                 }
403                         }
404                         closedir(dirp);
405                 }
406 #else
407                 strcpy( filespec, root->path );
408
409                 if(strlen(Pathtypes[i].path)){
410                         strcat( filespec, Pathtypes[i].path );          
411                         strcat( filespec, "\\" );
412                 }
413                 strcat( filespec, "*.vp" );
414                 int find_handle;
415                 _finddata_t find;
416                 
417                 find_handle = _findfirst( filespec, &find );
418
419                 if (find_handle != -1) {
420                         do {
421                                 // add the new item
422                                 if (!(find.attrib & _A_SUBDIR)) {                                       
423                                         Assert(root_index < temp_root_count);
424
425                                         // get a temp pointer
426                                         rptr_sort = &temp_roots_sort[root_index++];
427
428                                         // fill in all the proper info
429                                         strcpy(rptr_sort->path, root->path);
430
431                                         if(strlen(Pathtypes[i].path)){
432                                                 strcat(rptr_sort->path, Pathtypes[i].path );                                    
433                                                 strcat(rptr_sort->path, "\\");
434                                         }
435
436                                         strcat(rptr_sort->path, find.name );
437                                         rptr_sort->roottype = CF_ROOTTYPE_PACK;
438                                         rptr_sort->cf_type = i;
439                                 }
440
441                         } while (!_findnext(find_handle, &find));
442
443                         _findclose( find_handle );
444                 }       
445 #endif
446         }       
447
448         // these should always be the same
449         Assert(root_index == temp_root_count);
450
451         // sort tht roots
452         qsort(temp_roots_sort,  temp_root_count, sizeof(cf_root_sort), cf_packfile_sort_func);
453
454         // now insert them all into the real root list properly
455         cf_root *new_root;
456         for(i=0; i<temp_root_count; i++){               
457                 new_root = cf_create_root();
458                 strcpy( new_root->path, root->path );
459
460                 // mwa -- 4/2/98 put in the next 2 lines because the path name needs to be there
461                 // to find the files.
462                 strcpy(new_root->path, temp_roots_sort[i].path);                
463                 new_root->roottype = CF_ROOTTYPE_PACK;          
464         }
465
466         // free up the temp list
467         free(temp_roots_sort);
468 }
469
470
471 void cf_build_root_list(char *cdrom_dir)
472 {
473         Num_roots = 0;
474
475         cf_root *root;
476
477 #ifdef PLAT_UNIX
478         // ================================================================
479         // use users HOME directory as default for loading and saving files
480         root = cf_create_root();
481         strcpy( root->path, Cfile_user_dir );
482
483         // do we already have a slash? as in the case of a root directory install
484         if(strlen(root->path) && (root->path[strlen(root->path)-1] != '/')){
485                 strcat(root->path, "/");                // put trailing backslash on for easier path construction
486         }
487         root->roottype = CF_ROOTTYPE_PATH;
488
489    //======================================================
490         // Next, check any VP files under the current directory.
491         cf_build_pack_list(root);
492 #endif
493
494    //======================================================
495         // First, check the current directory.
496         // strcpy( root->path, "d:\\projects\\freespace\\" );
497
498         root = cf_create_root();
499
500         if ( !_getcwd(root->path, CF_MAX_PATHNAME_LENGTH ) ) {
501                 Error(LOCATION, "Can't get current working directory -- %d", errno );
502         }
503
504         // do we already have a slash? as in the case of a root directory install
505 #ifdef PLAT_UNIX
506         if(strlen(root->path) && (root->path[strlen(root->path)-1] != '/')){
507                 strcat(root->path, "/");                // put trailing backslash on for easier path construction
508 #else
509         if(strlen(root->path) && (root->path[strlen(root->path)-1] != '\\')){
510                 strcat(root->path, "\\");               // put trailing backslash on for easier path construction
511 #endif
512         }
513         root->roottype = CF_ROOTTYPE_PATH;
514
515    //======================================================
516         // Next, check any VP files under the current directory.
517         cf_build_pack_list(root);
518
519
520    //======================================================
521         // Check the real CD if one...
522         if ( cdrom_dir && strlen(cdrom_dir) )   {
523                 root = cf_create_root();
524                 strcpy( root->path, cdrom_dir );
525                 root->roottype = CF_ROOTTYPE_PATH;
526
527                 //======================================================
528                 // Next, check any VP files in the CD-ROM directory.
529                 cf_build_pack_list(root);
530
531         }
532
533 }
534
535 // Given a lower case list of file extensions 
536 // separated by spaces, return zero if ext is
537 // not in the list.
538 int is_ext_in_list( char *ext_list, char *ext )
539 {
540         char tmp_ext[128];
541
542         strncpy( tmp_ext, ext, 127 );
543         strlwr(tmp_ext);
544         if ( strstr(ext_list, tmp_ext ))        {
545                 return 1;
546         }       
547
548         return 0;
549 }
550
551 void cf_search_root_path(int root_index)
552 {
553         int i;
554
555         cf_root *root = cf_get_root(root_index);
556
557         mprintf(( "Searching root '%s'\n", root->path ));
558
559         char search_path[CF_MAX_PATHNAME_LENGTH];
560
561         for (i=CF_TYPE_ROOT; i<CF_MAX_PATH_TYPES; i++ ) {
562
563 #ifdef PLAT_UNIX
564                 DIR *dirp;
565                 struct dirent *dir;
566
567                 strcpy( search_path, root->path );
568
569                 if(strlen(Pathtypes[i].path)){
570                         strcat( search_path, Pathtypes[i].path );
571                         strcat( search_path, "/" );
572                 } 
573
574                 dirp = opendir (search_path);
575                 if ( dirp ) {
576                         while ((dir = readdir (dirp)) != NULL)
577                         {
578                                 if (!fnmatch ("*.*", dir->d_name, 0))
579                                 {
580                                         char fn[MAX_PATH];
581                                         snprintf(fn, MAX_PATH-1, "%s/%s", search_path, dir->d_name);
582                                         fn[MAX_PATH-1] = 0;
583                                                         
584                                         struct stat buf;
585                                         if (stat(fn, &buf) == -1) {
586                                                 continue;
587                                         }
588                                         
589                                         if (!S_ISREG(buf.st_mode)) {
590                                                 continue;
591                                         }
592                                         
593                                         char *ext = strchr( dir->d_name, '.' );
594                                         if ( ext )      {
595                                                 if ( is_ext_in_list( Pathtypes[i].extensions, ext ) )   {
596                                                         // Found a file!!!!
597                                                         cf_file *file = cf_create_file();
598
599                                                         strcpy( file->name_ext, dir->d_name );
600                                                         file->root_index = root_index;
601                                                         file->pathtype_index = i;
602
603
604                                                         file->write_time = buf.st_mtime;
605                                                         file->size = buf.st_size;
606
607                                                         file->pack_offset = 0;                  // Mark as a non-packed file
608
609                                                         //mprintf(( "Found file '%s'\n", file->name_ext ));
610                                                 }
611                                         }
612                                 }
613                         }
614                         closedir(dirp);
615                 }
616 #else
617                 strcpy( search_path, root->path );
618
619                 if(strlen(Pathtypes[i].path)){
620                         strcat( search_path, Pathtypes[i].path );
621                         strcat( search_path, "\\" );
622                 } 
623
624                 strcat( search_path, "*.*" );
625
626                 int find_handle;
627                 _finddata_t find;
628                 
629                 find_handle = _findfirst( search_path, &find );
630
631                 if (find_handle != -1) {
632                         do {
633                                 if (!(find.attrib & _A_SUBDIR)) {
634
635                                         char *ext = strchr( find.name, '.' );
636                                         if ( ext )      {
637                                                 if ( is_ext_in_list( Pathtypes[i].extensions, ext ) )   {
638                                                         // Found a file!!!!
639                                                         cf_file *file = cf_create_file();
640
641                                                         strcpy( file->name_ext, find.name );
642                                                         file->root_index = root_index;
643                                                         file->pathtype_index = i;
644                                                         file->write_time = find.time_write;
645                                                         file->size = find.size;
646                                                         file->pack_offset = 0;                  // Mark as a non-packed file
647
648                                                         //mprintf(( "Found file '%s'\n", file->name_ext ));
649
650                                                 }
651                                         }
652
653                                 }
654
655                         } while (!_findnext(find_handle, &find));
656
657                         _findclose( find_handle );
658                 }
659 #endif
660
661         }
662 }
663
664
665 typedef struct VP_FILE_HEADER {
666         char id[4];
667         int version;
668         int index_offset;
669         int num_files;
670 } VP_FILE_HEADER;
671
672 typedef struct VP_FILE {
673         int     offset;
674         int     size;
675         char    filename[32];
676         time_t write_time;
677 } VP_FILE;
678
679 void cf_search_root_pack(int root_index)
680 {
681         int i;
682
683         cf_root *root = cf_get_root(root_index);
684
685         //mprintf(( "Searching root pack '%s'\n", root->path ));
686
687         // Open data
688                 
689         FILE *fp = fopen( root->path, "rb" );
690         // Read the file header
691         if (!fp) {
692                 return;
693         }
694
695         VP_FILE_HEADER VP_header;
696
697         Assert( sizeof(VP_header) == 16 );
698         fread(&VP_header, 1, sizeof(VP_header), fp);
699
700     VP_header.version = INTEL_INT( VP_header.version);
701     VP_header.index_offset = INTEL_INT( VP_header.index_offset);
702     VP_header.num_files = INTEL_INT( VP_header.num_files);
703         
704         // Read index info
705         fseek(fp, VP_header.index_offset, SEEK_SET);
706
707         char search_path[CF_MAX_PATHNAME_LENGTH];
708
709         strcpy( search_path, "" );
710         
711         // Go through all the files
712         for (i=0; i<VP_header.num_files; i++ )  {
713                 VP_FILE find;
714
715                 fread( &find, sizeof(VP_FILE), 1, fp );
716
717         find.offset = INTEL_INT( find.offset );
718         find.size = INTEL_INT( find.size );
719                 find.write_time = INTEL_INT(find.write_time);
720
721                 if ( find.size == 0 )   {
722                         if ( !stricmp( find.filename, ".." ))   {
723                                 int l = strlen(search_path);
724                                 char *p = &search_path[l-1];
725 #ifdef PLAT_UNIX
726                                 while( (p > search_path) && (*p != '/') )       {
727 #else
728                                 while( (p > search_path) && (*p != '\\') )      {
729 #endif
730                                         p--;
731                                 }
732                                 *p = 0;
733                         } else {
734                                 if ( strlen(search_path)        )       {
735 #ifdef PLAT_UNIX
736                                         strcat( search_path,    "/" );
737 #else
738                                         strcat( search_path,    "\\" );
739 #endif
740                                 }
741                                 strcat( search_path, find.filename );
742                         }
743
744                         //mprintf(( "Current dir = '%s'\n", search_path ));
745                 } else {
746         
747                         int j;
748                         for (j=CF_TYPE_ROOT; j<CF_MAX_PATH_TYPES; j++ ) {
749
750                                 if ( !stricmp( search_path, Pathtypes[j].path ))        {
751
752                                         char *ext = strchr( find.filename, '.' );
753                                         if ( ext )      {
754                                                 if ( is_ext_in_list( Pathtypes[j].extensions, ext ) )   {
755                                                         // Found a file!!!!
756                                                         cf_file *file = cf_create_file();
757                                                         
758                                                         strcpy( file->name_ext, find.filename );
759                                                         file->root_index = root_index;
760                                                         file->pathtype_index = j;
761                                                         file->write_time = find.write_time;
762                                                         file->size = find.size;
763                                                         file->pack_offset = find.offset;                        // Mark as a non-packed file
764
765                                                         //mprintf(( "Found pack file '%s'\n", file->name_ext ));
766                                                 }
767                                         }
768                                         
769
770                                 }
771                         }
772
773                 }
774         }
775         fclose(fp);
776 }
777
778
779 void cf_build_file_list()
780 {
781         int i;
782
783         Num_files = 0;
784
785         // For each root, find all files...
786         for (i=1; i<Num_roots; i++ )    {
787                 cf_root *root = cf_get_root(i);
788                 if ( root->roottype == CF_ROOTTYPE_PATH )       {
789                         cf_search_root_path(i);
790                 } else if ( root->roottype == CF_ROOTTYPE_PACK )        {
791                         cf_search_root_pack(i);
792                 }
793         }
794
795 }
796
797
798 void cf_build_secondary_filelist(char *cdrom_dir)
799 {
800         int i;
801
802         // Assume no files
803         Num_roots = 0;
804         Num_files = 0;
805
806         // Init the path types
807         for (i=0; i<CF_MAX_PATH_TYPES; i++ )    {
808                 Assert( Pathtypes[i].index == i );
809 #if 0 /* they are already lowercased -- SBF */
810                 if ( Pathtypes[i].extensions )  {
811                         strlwr(Pathtypes[i].extensions);
812                 }
813 #endif          
814         }
815         
816         // Init the root blocks
817         for (i=0; i<CF_MAX_ROOT_BLOCKS; i++ )   {
818                 Root_blocks[i] = NULL;
819         }
820
821         // Init the file blocks 
822         for (i=0; i<CF_MAX_FILE_BLOCKS; i++ )   {
823                 File_blocks[i] = NULL;
824         }
825
826         mprintf(( "Building file index...\n" ));
827         
828         // build the list of searchable roots
829         cf_build_root_list(cdrom_dir);  
830
831         // build the list of files themselves
832         cf_build_file_list();
833
834         mprintf(( "Found %d roots and %d files.\n", Num_roots, Num_files ));
835 }
836
837 void cf_free_secondary_filelist()
838 {
839         int i;
840
841         // Free the root blocks
842         for (i=0; i<CF_MAX_ROOT_BLOCKS; i++ )   {
843                 if ( Root_blocks[i] )   {
844                         free( Root_blocks[i] );
845                         Root_blocks[i] = NULL;
846                 }
847         }
848         Num_roots = 0;
849
850         // Init the file blocks 
851         for (i=0; i<CF_MAX_FILE_BLOCKS; i++ )   {
852                 if ( File_blocks[i] )   {
853                         free( File_blocks[i] );
854                         File_blocks[i] = NULL;
855                 }
856         }
857         Num_files = 0;
858 }
859
860 // Searches for a file.   Follows all rules and precedence and searches
861 // CD's and pack files.
862 // Input:  filespace   - Filename & extension
863 //         pathtype    - See CF_TYPE_ defines in CFILE.H
864 // Output: pack_filename - Absolute path and filename of this file.   Could be a packfile or the actual file.
865 //         size        - File size
866 //         offset      - Offset into pack file.  0 if not a packfile.
867 // Returns: If not found returns 0.
868 int cf_find_file_location( char *filespec, int pathtype, char *pack_filename, int *size, int *offset, bool localize )
869 {
870         int i;
871
872         Assert(filespec && strlen(filespec));
873
874         // see if we have something other than just a filename
875         // our current rules say that any file that specifies a direct
876         // path will try to be opened on that path.  If that open
877         // fails, then we will open the file based on the extension
878         // of the file
879
880         // NOTE: full path should also include localization, if so desired
881         if ( strpbrk(filespec,"/\\:")  ) {              // do we have a full path already?
882                 FILE *fp = fopen(filespec, "rb" );
883                 if (fp) {
884                         if ( size ) *size = filelength(fileno(fp));
885                         if ( offset ) *offset = 0;
886                         if ( pack_filename ) {
887                                 strcpy( pack_filename, filespec );
888                         }                               
889                         fclose(fp);
890                         return 1;               
891                 }
892
893                 return 0;               // If they give a full path, fail if not found.
894         }
895
896         // Search the hard drive for files first.
897         int num_search_dirs = 0;
898         int search_order[CF_MAX_PATH_TYPES];
899
900         if ( CF_TYPE_SPECIFIED(pathtype) )      {
901                 search_order[num_search_dirs++] = pathtype;
902         }
903
904         for (i=CF_TYPE_ROOT; i<CF_MAX_PATH_TYPES; i++)  {
905                 if ( i != pathtype )    {
906                         search_order[num_search_dirs++] = i;
907                 }
908         }
909
910         for (i=0; i<num_search_dirs; i++ )      {
911                 char longname[MAX_PATH_LEN];
912
913                 cf_create_default_path_string( longname, search_order[i], filespec, localize );
914
915                 FILE *fp = fopen(longname, "rb" );
916                 if (fp) {
917                         if ( size ) *size = filelength(fileno(fp));
918                         if ( offset ) *offset = 0;
919                         if ( pack_filename ) {
920                                 strcpy( pack_filename, longname );
921                         }                               
922                         fclose(fp);
923                         return 1;               
924                 }
925         } 
926
927 #ifdef PLAT_UNIX
928         // search the secondary directory (game directory) as well since the user dir is default
929         for (i=0; i<num_search_dirs; i++ )      {
930                 char longname[MAX_PATH_LEN];
931
932                 cf_create_secondary_path_string( longname, search_order[i], filespec, localize );
933
934                 FILE *fp = fopen(longname, "rb" );
935                 if (fp) {
936                         if ( size ) *size = filelength(fileno(fp));
937                         if ( offset ) *offset = 0;
938                         if ( pack_filename ) {
939                                 strcpy( pack_filename, longname );
940                         }                               
941                         fclose(fp);
942                         return 1;               
943                 }
944         }
945 #endif
946
947         // Search the pak files and CD-ROM.
948
949                 for (i=0; i<Num_files; i++ )    {
950                         cf_file * f = cf_get_file(i);
951
952                         // only search paths we're supposed to...
953                         if ( (pathtype != CF_TYPE_ANY) && (pathtype != f->pathtype_index)  )    {
954                                 continue;
955                         }
956
957                         if (localize) {
958                                 // create localized filespec
959                                 char temp[MAX_PATH_LEN];
960                                 strcpy(temp, filespec);
961                                 lcl_add_dir_to_path_with_filename(filespec);
962                         
963                                 if ( !stricmp(filespec, f->name_ext) )  {
964                                         if ( size ) *size = f->size;
965                                         if ( offset ) *offset = f->pack_offset;
966                                         if ( pack_filename ) {
967                                                 cf_root * r = cf_get_root(f->root_index);
968
969                                                 strcpy( pack_filename, r->path );
970                                                 if ( f->pack_offset < 1 )       {
971                                                         strcat( pack_filename, Pathtypes[f->pathtype_index].path );
972 #ifdef PLAT_UNIX
973                                                         strcat( pack_filename, "/" );
974 #else
975                                                         strcat( pack_filename, "\\" );
976 #endif
977                                                         strcat( pack_filename, f->name_ext );
978                                                 }
979                                         }                               
980                                         return 1;               
981                                 }
982                                 // restore original filespec
983                                 strcpy(filespec, temp);
984                         }
985
986                         // file either not localized or localized version not found
987                         if ( !stricmp(filespec, f->name_ext) )  {
988                                 if ( size ) *size = f->size;
989                                 if ( offset ) *offset = f->pack_offset;
990                                 if ( pack_filename ) {
991                                         cf_root * r = cf_get_root(f->root_index);
992
993                                         strcpy( pack_filename, r->path );
994                                         if ( f->pack_offset < 1 )       {
995
996                                                 if(strlen(Pathtypes[f->pathtype_index].path)){
997                                                         strcat( pack_filename, Pathtypes[f->pathtype_index].path );
998 #ifdef PLAT_UNIX
999                                                         strcat( pack_filename, "/" );
1000 #else
1001                                                         strcat( pack_filename, "\\" );
1002 #endif
1003                                                 }
1004
1005                                                 strcat( pack_filename, f->name_ext );
1006                                         }
1007                                 }                               
1008                                 return 1;               
1009                         }
1010                 }
1011         
1012         return 0;
1013 }
1014
1015
1016 // Returns true if filename matches filespec, else zero if not
1017 int cf_matches_spec(char *filespec, char *filename)
1018 {
1019         char *src_ext, *dst_ext;
1020
1021         src_ext = strchr(filespec, '.');
1022         if (!src_ext)
1023                 return 1;
1024         if (*src_ext == '*')
1025                 return 1;
1026
1027         dst_ext = strchr(filename, '.');
1028         if (!dst_ext)
1029                 return 1;
1030         
1031         return !stricmp(dst_ext, src_ext);
1032 }
1033
1034 int (*Get_file_list_filter)(char *filename) = NULL;
1035 int Skip_packfile_search = 0;
1036
1037 int cf_file_already_in_list( int num_files, char **list, char *filename )
1038 {
1039         int i;
1040
1041         char name_no_extension[MAX_PATH_LEN];
1042
1043         strcpy(name_no_extension, filename );
1044         char *p = strchr( name_no_extension, '.' );
1045         if ( p ) *p = 0;
1046
1047         for (i=0; i<num_files; i++ )    {
1048                 if ( !stricmp(list[i], name_no_extension ) )    {
1049                         // Match found!
1050                         return 1;
1051                 }
1052         }
1053         // Not found
1054         return 0;
1055 }
1056
1057 // An alternative cf_get_file_list(), dynamic list version.
1058 // This one has a 'type', which is a CF_TYPE_* value.  Because this specifies the directory
1059 // location, 'filter' only needs to be the filter itself, with no path information.
1060 // See above descriptions of cf_get_file_list() for more information about how it all works.
1061 int cf_get_file_list( int max, char **list, int pathtype, char *filter, int sort, file_list_info *info )
1062 {
1063         char *ptr;
1064         int i, l, num_files = 0, own_flag = 0;
1065 #ifndef PLAT_UNIX
1066         int find_handle;
1067         _finddata_t find;
1068 #endif
1069
1070         if (max < 1) {
1071                 Get_file_list_filter = NULL;
1072                 return 0;
1073         }
1074
1075         Assert(list);
1076
1077         if (!info && (sort == CF_SORT_TIME)) {
1078                 info = (file_list_info *) malloc(sizeof(file_list_info) * max);
1079                 own_flag = 1;
1080         }
1081
1082         char filespec[MAX_PATH_LEN];
1083
1084 #ifdef PLAT_UNIX
1085         cf_create_default_path_string( filespec, pathtype, NULL );
1086
1087                 DIR *dirp;
1088                 struct dirent *dir;
1089
1090                 dirp = opendir (filespec);
1091                 if ( dirp ) {
1092                         while ((dir = readdir (dirp)) != NULL)
1093                         {
1094                                 if (num_files >= max)
1095                                         break;
1096                                 
1097                                 if (fnmatch(filter, dir->d_name, 0) != 0)
1098                                         continue;
1099                                 
1100                                 char fn[MAX_PATH];
1101                                 snprintf(fn, MAX_PATH-1, "%s/%s", filespec, dir->d_name);
1102                                 fn[MAX_PATH-1] = 0;
1103                                                         
1104                                 struct stat buf;
1105                                 if (stat(fn, &buf) == -1) {
1106                                         continue;
1107                                 }
1108                                 
1109                                 if (!S_ISREG(buf.st_mode)) {
1110                                         continue;
1111                                 }
1112                                 
1113                                 if ( !Get_file_list_filter || (*Get_file_list_filter)(dir->d_name) ) {
1114                                         ptr = strrchr(dir->d_name, '.');
1115                                         if (ptr)
1116                                                 l = ptr - dir->d_name;
1117                                         else
1118                                                 l = strlen(dir->d_name);
1119
1120                                         list[num_files] = (char *)malloc(l + 1);
1121                                         strncpy(list[num_files], dir->d_name, l);
1122                                         list[num_files][l] = 0;
1123                                         if (info)
1124                                                 info[num_files].write_time = buf.st_mtime;
1125
1126                                         num_files++;
1127                                 }
1128                         }
1129                         
1130                         closedir(dirp);
1131                 }
1132
1133         // grab secondary (game) directory as well but be sure to skip the pilot
1134         // directories as that would be a bad thing to load read-only pilots
1135         if (pathtype != (CF_TYPE_PLAYERS || CF_TYPE_SINGLE_PLAYERS || CF_TYPE_MULTI_PLAYERS)) {
1136                 cf_create_secondary_path_string( filespec, pathtype, NULL );
1137
1138                 DIR *dirp;
1139                 struct dirent *dir;
1140
1141                 dirp = opendir (filespec);
1142                 if ( dirp ) {
1143                         while ((dir = readdir (dirp)) != NULL)
1144                         {
1145                                 if (num_files >= max)
1146                                         break;
1147                                 
1148                                 if (fnmatch(filter, dir->d_name, 0) != 0)
1149                                         continue;
1150                                 
1151                                 char fn[MAX_PATH];
1152                                 snprintf(fn, MAX_PATH-1, "%s/%s", filespec, dir->d_name);
1153                                 fn[MAX_PATH-1] = 0;
1154                                                         
1155                                 struct stat buf;
1156                                 if (stat(fn, &buf) == -1) {
1157                                         continue;
1158                                 }
1159                                 
1160                                 if (!S_ISREG(buf.st_mode)) {
1161                                         continue;
1162                                 }
1163                                 
1164                                 if ( !Get_file_list_filter || (*Get_file_list_filter)(dir->d_name) ) {
1165                                         ptr = strrchr(dir->d_name, '.');
1166                                         if (ptr)
1167                                                 l = ptr - dir->d_name;
1168                                         else
1169                                                 l = strlen(dir->d_name);
1170
1171                                         list[num_files] = (char *)malloc(l + 1);
1172                                         strncpy(list[num_files], dir->d_name, l);
1173                                         list[num_files][l] = 0;
1174                                         if (info)
1175                                                 info[num_files].write_time = buf.st_mtime;
1176
1177                                         num_files++;
1178                                 }
1179                         }
1180
1181                         closedir(dirp);
1182                 }
1183         }
1184 #else
1185         cf_create_default_path_string( filespec, pathtype, filter );
1186         
1187         find_handle = _findfirst( filespec, &find );
1188         if (find_handle != -1) {
1189                 do {
1190                         if (num_files >= max)
1191                                 break;
1192
1193                         if (!(find.attrib & _A_SUBDIR)) {
1194                                 if ( !Get_file_list_filter || (*Get_file_list_filter)(find.name) ) {
1195                                         ptr = strrchr(find.name, '.');
1196                                         if (ptr)
1197                                                 l = ptr - find.name;
1198                                         else
1199                                                 l = strlen(find.name);
1200
1201                                         list[num_files] = (char *)malloc(l + 1);
1202                                         strncpy(list[num_files], find.name, l);
1203                                         list[num_files][l] = 0;
1204                                         if (info)
1205                                                 info[num_files].write_time = find.time_write;
1206
1207                                         num_files++;
1208                                 }
1209                         }
1210
1211                 } while (!_findnext(find_handle, &find));
1212
1213                 _findclose( find_handle );
1214         }
1215 #endif
1216
1217
1218         // Search all the packfiles and CD.
1219         if ( !Skip_packfile_search )    {
1220                 for (i=0; i<Num_files; i++ )    {
1221                         cf_file * f = cf_get_file(i);
1222
1223                         // only search paths we're supposed to...
1224                         if ( (pathtype != CF_TYPE_ANY) && (pathtype != f->pathtype_index)  )    {
1225                                 continue;
1226                         }
1227
1228                         if (num_files >= max)
1229                                 break;
1230
1231                         if ( !cf_matches_spec( filter,f->name_ext))     {
1232                                 continue;
1233                         }
1234
1235                         if ( cf_file_already_in_list(num_files,list,f->name_ext))       {
1236                                 continue;
1237                         }
1238
1239                         if ( !Get_file_list_filter || (*Get_file_list_filter)(f->name_ext) ) {
1240
1241                                 //mprintf(( "Found '%s' in root %d path %d\n", f->name_ext, f->root_index, f->pathtype_index ));
1242
1243                                         ptr = strrchr(f->name_ext, '.');
1244                                         if (ptr)
1245                                                 l = ptr - f->name_ext;
1246                                         else
1247                                                 l = strlen(f->name_ext);
1248
1249                                         list[num_files] = (char *)malloc(l + 1);
1250                                         strncpy(list[num_files], f->name_ext, l);
1251                                         list[num_files][l] = 0;
1252
1253                                 if (info)       {
1254                                         info[num_files].write_time = f->write_time;
1255                                 }
1256
1257                                 num_files++;
1258                         }
1259
1260                 }
1261         }
1262
1263
1264         if (sort != CF_SORT_NONE)       {
1265                 cf_sort_filenames( num_files, list, sort, info );
1266         }
1267
1268         if (own_flag)   {
1269                 free(info);
1270         }
1271
1272         Get_file_list_filter = NULL;
1273         return num_files;
1274 }
1275
1276 int cf_file_already_in_list_preallocated( int num_files, char arr[][MAX_FILENAME_LEN], char *filename )
1277 {
1278         int i;
1279
1280         char name_no_extension[MAX_PATH_LEN];
1281
1282         strcpy(name_no_extension, filename );
1283         char *p = strchr( name_no_extension, '.' );
1284         if ( p ) *p = 0;
1285
1286         for (i=0; i<num_files; i++ )    {
1287                 if ( !stricmp(arr[i], name_no_extension ) )     {
1288                         // Match found!
1289                         return 1;
1290                 }
1291         }
1292         // Not found
1293         return 0;
1294 }
1295
1296 // An alternative cf_get_file_list(), fixed array version.
1297 // This one has a 'type', which is a CF_TYPE_* value.  Because this specifies the directory
1298 // location, 'filter' only needs to be the filter itself, with no path information.
1299 // See above descriptions of cf_get_file_list() for more information about how it all works.
1300 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 )
1301 {
1302         int i, num_files = 0, own_flag = 0;
1303
1304         if (max < 1) {
1305                 Get_file_list_filter = NULL;
1306                 return 0;
1307         }
1308
1309         if (list) {
1310                 for (i=0; i<max; i++)   {
1311                         list[i] = arr[i];
1312                 }
1313         } else {
1314                 sort = CF_SORT_NONE;  // sorting of array directly not supported.  Sorting done on list only
1315         }
1316
1317         if (!info && (sort == CF_SORT_TIME)) {
1318                 info = (file_list_info *) malloc(sizeof(file_list_info) * max);
1319                 own_flag = 1;
1320         }
1321
1322         char filespec[MAX_PATH_LEN];
1323
1324         // Search the default directories
1325 #ifdef PLAT_UNIX
1326         cf_create_default_path_string( filespec, pathtype, NULL );
1327         
1328                 DIR *dirp;
1329                 struct dirent *dir;
1330
1331                 dirp = opendir (filespec);
1332                 if ( dirp ) {
1333                         while ((dir = readdir (dirp)) != NULL)
1334                         {
1335                                 if (num_files >= max)
1336                                         break;
1337                                 
1338                                 if (fnmatch(filter, dir->d_name, 0) != 0)
1339                                         continue;
1340                                 
1341                                 char fn[MAX_PATH];
1342                                 snprintf(fn, MAX_PATH-1, "%s/%s", filespec, dir->d_name);
1343                                 fn[MAX_PATH-1] = 0;
1344                                                         
1345                                 struct stat buf;
1346                                 if (stat(fn, &buf) == -1) {
1347                                         continue;
1348                                 }
1349                                 
1350                                 if (!S_ISREG(buf.st_mode)) {
1351                                         continue;
1352                                 }
1353                                 
1354                                 if ( !Get_file_list_filter || (*Get_file_list_filter)(dir->d_name) ) {
1355
1356                                         strncpy(arr[num_files], dir->d_name, MAX_FILENAME_LEN - 1 );
1357                                         char *ptr = strrchr(arr[num_files], '.');
1358                                         if ( ptr ) {
1359                                                 *ptr = 0;
1360                                         }
1361
1362                                         if (info)       {
1363                                                 info[num_files].write_time = buf.st_mtime;
1364                                         }
1365
1366                                         num_files++;
1367                                 }
1368                         }
1369                         closedir(dirp);
1370                 }
1371
1372         // grab secondary (game) directory as well but be sure to skip the pilot
1373         // directories as that would be a bad thing to load read-only pilots
1374         if (pathtype != (CF_TYPE_PLAYERS || CF_TYPE_SINGLE_PLAYERS || CF_TYPE_MULTI_PLAYERS)) {
1375                 cf_create_secondary_path_string( filespec, pathtype, NULL );
1376         
1377                 DIR *dirp;
1378                 struct dirent *dir;
1379
1380                 dirp = opendir (filespec);
1381                 if ( dirp ) {
1382                         while ((dir = readdir (dirp)) != NULL)
1383                         {
1384                                 if (num_files >= max)
1385                                         break;
1386                                 
1387                                 if (fnmatch(filter, dir->d_name, 0) != 0)
1388                                         continue;
1389                                 
1390                                 char fn[MAX_PATH];
1391                                 snprintf(fn, MAX_PATH-1, "%s/%s", filespec, dir->d_name);
1392                                 fn[MAX_PATH-1] = 0;
1393                                                         
1394                                 struct stat buf;
1395                                 if (stat(fn, &buf) == -1) {
1396                                         continue;
1397                                 }
1398                                 
1399                                 if (!S_ISREG(buf.st_mode)) {
1400                                         continue;
1401                                 }
1402                                 
1403                                 if ( !Get_file_list_filter || (*Get_file_list_filter)(dir->d_name) ) {
1404
1405                                         strncpy(arr[num_files], dir->d_name, MAX_FILENAME_LEN - 1 );
1406                                         char *ptr = strrchr(arr[num_files], '.');
1407                                         if ( ptr ) {
1408                                                 *ptr = 0;
1409                                         }
1410
1411                                         if (info)       {
1412                                                 info[num_files].write_time = buf.st_mtime;
1413                                         }
1414
1415                                         num_files++;
1416                                 }
1417                         }
1418                         closedir(dirp);
1419                 }
1420         }
1421 #else
1422         cf_create_default_path_string( filespec, pathtype, filter );
1423         
1424         int find_handle;
1425         _finddata_t find;
1426         
1427         find_handle = _findfirst( filespec, &find );
1428         if (find_handle != -1) {
1429                 do {
1430                         if (num_files >= max)
1431                                 break;
1432
1433                         if (!(find.attrib & _A_SUBDIR)) {
1434
1435                                 if ( !Get_file_list_filter || (*Get_file_list_filter)(find.name) ) {
1436
1437                                         strncpy(arr[num_files], find.name, MAX_FILENAME_LEN - 1 );
1438                                         char *ptr = strrchr(arr[num_files], '.');
1439                                         if ( ptr ) {
1440                                                 *ptr = 0;
1441                                         }
1442
1443                                         if (info)       {
1444                                                 info[num_files].write_time = find.time_write;
1445                                         }
1446
1447                                         num_files++;
1448                                 }
1449                         }
1450
1451                 } while (!_findnext(find_handle, &find));
1452
1453                 _findclose( find_handle );
1454         }
1455 #endif
1456                 
1457
1458         // Search all the packfiles and CD.
1459         if ( !Skip_packfile_search )    {
1460                 for (i=0; i<Num_files; i++ )    {
1461                         cf_file * f = cf_get_file(i);
1462
1463                         // only search paths we're supposed to...
1464                         if ( (pathtype != CF_TYPE_ANY) && (pathtype != f->pathtype_index)  )    {
1465                                 continue;
1466                         }
1467
1468                         if (num_files >= max)
1469                                 break;
1470
1471                         if ( !cf_matches_spec( filter,f->name_ext))     {
1472                                 continue;
1473                         }
1474
1475                         if ( cf_file_already_in_list_preallocated( num_files, arr, f->name_ext ))       {
1476                                 continue;
1477                         }
1478
1479                         if ( !Get_file_list_filter || (*Get_file_list_filter)(f->name_ext) ) {
1480
1481                                 //mprintf(( "Found '%s' in root %d path %d\n", f->name_ext, f->root_index, f->pathtype_index ));
1482
1483                                 strncpy(arr[num_files], f->name_ext, MAX_FILENAME_LEN - 1 );
1484                                 char *ptr = strrchr(arr[num_files], '.');
1485                                 if ( ptr ) {
1486                                         *ptr = 0;
1487                                 }
1488
1489                                 if (info)       {
1490                                         info[num_files].write_time = f->write_time;
1491                                 }
1492
1493                                 num_files++;
1494                         }
1495
1496                 }
1497         }
1498
1499         if (sort != CF_SORT_NONE) {
1500                 Assert(list);
1501                 cf_sort_filenames( num_files, list, sort, info );
1502         }
1503
1504         if (own_flag)   {
1505                 free(info);
1506         }
1507
1508         Get_file_list_filter = NULL;
1509         return num_files;
1510 }
1511
1512 // Returns the default storage path for files given a 
1513 // particular pathtype.   In other words, the path to 
1514 // the unpacked, non-cd'd, stored on hard drive path.
1515 // If filename isn't null it will also tack the filename
1516 // on the end, creating a completely valid filename.
1517 // Input:   pathtype  - CF_TYPE_??
1518 //          filename  - optional, if set, tacks the filename onto end of path.
1519 // Output:  path      - Fully qualified pathname.
1520 void cf_create_default_path_string( char *path, int pathtype, char *filename, bool localize )
1521 {
1522 #ifdef PLAT_UNIX
1523         if ( filename && strpbrk(filename,"/")  ) {  
1524 #else
1525         if ( filename && strpbrk(filename,"/\\:")  ) {  
1526 #endif
1527                 // Already has full path
1528                 strcpy( path, filename );
1529
1530         } else {
1531                 cf_root *root = cf_get_root(0);
1532
1533                 if (!root) {
1534                         strcpy(path, filename);
1535                         return;
1536                 }
1537
1538                 Assert(CF_TYPE_SPECIFIED(pathtype));
1539
1540                 strcpy(path, root->path);
1541                 strcat(path, Pathtypes[pathtype].path);
1542
1543                 // Don't add slash for root directory
1544                 if (Pathtypes[pathtype].path[0] != '\0') {
1545 #ifdef PLAT_UNIX
1546                         strcat(path, "/");
1547 #else
1548                         strcat(path, "\\");
1549 #endif
1550                 }
1551
1552                 // add filename
1553                 if (filename) {
1554                         strcat(path, filename);
1555
1556                         // localize filename
1557                         if (localize) {
1558                                 // create copy of path
1559                                 char temp_path[MAX_PATH_LEN];
1560                                 strcpy(temp_path, path);
1561
1562                                 // localize the path
1563                                 lcl_add_dir_to_path_with_filename(path);
1564
1565                                 // verify localized path
1566                                 FILE *fp = fopen(path, "rb");
1567                                 if (fp) {
1568                                         fclose(fp);
1569                                 } else {
1570                                         strcpy(path, temp_path);
1571                                 }
1572                         }
1573                 }
1574         }
1575 }
1576
1577 #ifdef PLAT_UNIX
1578 // this is the same as cf_create_default_path_string above but as it only shows
1579 // files in the users directory this function will find files in the game
1580 // installation directory
1581 void cf_create_secondary_path_string( char *path, int pathtype, char *filename, bool localize )
1582 {
1583         if ( filename && strpbrk(filename,"/")  ) {  
1584
1585                 // Already has full path
1586                 strcpy( path, filename );
1587
1588         } else {
1589                 cf_root *root = cf_get_root(1);
1590
1591                 if (!root) {
1592                         strcpy(path, filename);
1593                         return;
1594                 }
1595
1596                 Assert(CF_TYPE_SPECIFIED(pathtype));
1597
1598                 strcpy(path, root->path);
1599                 strcat(path, Pathtypes[pathtype].path);
1600
1601                 // Don't add slash for root directory
1602                 if (Pathtypes[pathtype].path[0] != '\0') {
1603                         strcat(path, "/");
1604                 }
1605
1606                 // add filename
1607                 if (filename) {
1608                         strcat(path, filename);
1609
1610                         // localize filename
1611                         if (localize) {
1612                                 // create copy of path
1613                                 char temp_path[MAX_PATH_LEN];
1614                                 strcpy(temp_path, path);
1615
1616                                 // localize the path
1617                                 lcl_add_dir_to_path_with_filename(path);
1618
1619                                 // verify localized path
1620                                 FILE *fp = fopen(path, "rb");
1621                                 if (fp) {
1622                                         fclose(fp);
1623                                 } else {
1624                                         strcpy(path, temp_path);
1625                                 }
1626                         }
1627                 }
1628         }
1629 }
1630 #endif