3030#include < fnmatch.h>
3131#include < sys/stat.h>
3232#include < unistd.h>
33+ #include < libgen.h>
3334#endif
3435
3536#include " cfile/cfile.h"
3839#include " globalincs/pstypes.h"
3940#include " localization/localize.h"
4041#include " osapi/osapi.h"
42+ #include " parse/parselo.h"
4143
4244#define CF_ROOTTYPE_PATH 0
4345#define CF_ROOTTYPE_PACK 1
@@ -77,12 +79,13 @@ static int Num_path_roots = 0;
7779
7880// Created by searching all roots in order. This means Files is then sorted by precedence.
7981typedef struct cf_file {
80- char name_ext[CF_MAX_FILENAME_LENGTH]; // Filename and extension
81- int root_index; // Where in Roots this is located
82- int pathtype_index; // Where in Paths this is located
83- time_t write_time; // When it was last written
84- int size; // How big it is in bytes
85- int pack_offset; // For pack files, where it is at. 0 if not in a pack file. This can be used to tell if in a pack file.
82+ char name_ext[CF_MAX_FILENAME_LENGTH]; // Filename and extension
83+ int root_index; // Where in Roots this is located
84+ int pathtype_index; // Where in Paths this is located
85+ time_t write_time; // When it was last written
86+ int size; // How big it is in bytes
87+ 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.
88+ char * real_name; // For real files, the full path
8689} cf_file;
8790
8891#define CF_NUM_FILES_PER_BLOCK 512
@@ -115,6 +118,7 @@ cf_file *cf_create_file()
115118 if ( File_blocks[block] == NULL ) {
116119 File_blocks[block] = (cf_file_block *)vm_malloc ( sizeof (cf_file_block) );
117120 Assert ( File_blocks[block] != NULL );
121+ memset (File_blocks[block], 0 , sizeof (cf_file_block));
118122 }
119123
120124 Num_files++;
@@ -534,6 +538,10 @@ void cf_search_root_path(int root_index)
534538 mprintf (( " Searching root '%s' ... " , root->path ));
535539
536540 char search_path[CF_MAX_PATHNAME_LENGTH];
541+ #ifdef SCP_UNIX
542+ // This map stores the mapping between a specific path type and the actual path that we use for it
543+ SCP_unordered_map<int , SCP_string> pathTypeToRealPath;
544+ #endif
537545
538546 for (i=CF_TYPE_ROOT; i<CF_MAX_PATH_TYPES; i++ ) {
539547
@@ -552,6 +560,7 @@ void cf_search_root_path(int root_index)
552560 }
553561
554562#if defined _WIN32
563+ SCP_string search_directory = search_path;
555564 strcat_s ( search_path, " *.*" );
556565
557566 intptr_t find_handle;
@@ -576,6 +585,11 @@ void cf_search_root_path(int root_index)
576585 file->size = find.size ;
577586 file->pack_offset = 0 ; // Mark as a non-packed file
578587
588+ SCP_string file_name;
589+ sprintf (file_name, " %s%s%s" , search_directory.c_str (), DIR_SEPARATOR_STR, find.name );
590+
591+ file->real_name = vm_strdup (file_name.c_str ());
592+
579593 num_files++;
580594 // mprintf(( "Found file '%s'\n", file->name_ext ));
581595 }
@@ -588,21 +602,80 @@ void cf_search_root_path(int root_index)
588602 _findclose ( find_handle );
589603 }
590604#elif defined SCP_UNIX
591- DIR *dirp;
592- struct dirent *dir;
605+ DIR *dirp = nullptr ;
606+ SCP_string search_dir;
607+ {
608+ if (i == CF_TYPE_ROOT) {
609+ // Don't search for the same name for the root case since we would be searching in other mod directories in that case
610+ dirp = opendir (search_path);
611+ search_dir.assign (search_path);
612+ } else {
613+ // On Unix we can have a different case for the search paths so we also need to account for that
614+ // We do that by looking at the parent of search_path and enumerating all directories and the check if any of
615+ // them are a case-insensitive match
616+ SCP_string directory_name;
617+
618+ auto parentPathIter = pathTypeToRealPath.find (Pathtypes[i].parent_index );
619+
620+ if (parentPathIter == pathTypeToRealPath.end ()) {
621+ // No parent known yet, use the standard dirname
622+ char dirname_copy[CF_MAX_PATHNAME_LENGTH];
623+ memcpy (dirname_copy, search_path, sizeof (search_path));
624+ // According to the documentation of directory_name and basename, the return value does not need to be freed
625+ directory_name.assign (dirname (dirname_copy));
626+ } else {
627+ // we have a valid parent path -> use that
628+ directory_name = parentPathIter->second ;
629+ }
630+
631+ char basename_copy[CF_MAX_PATHNAME_LENGTH];
632+ memcpy (basename_copy, search_path, sizeof (search_path));
633+ // According to the documentation of dirname and basename, the return value does not need to be freed
634+ auto search_name = basename (basename_copy);
635+
636+ auto parentDirP = opendir (directory_name.c_str ());
637+
638+ if (parentDirP) {
639+ struct dirent *dir = nullptr ;
640+ while ((dir = readdir (parentDirP)) != nullptr ) {
641+
642+ if (stricmp (search_name, dir->d_name )) {
643+ continue ;
644+ }
645+
646+ SCP_string fn;
647+ sprintf (fn, " %s/%s" , directory_name.c_str (), dir->d_name );
648+
649+ struct stat buf;
650+ if (stat (fn.c_str (), &buf) == -1 ) {
651+ continue ;
652+ }
653+
654+ if (S_ISDIR (buf.st_mode )) {
655+ // Found a case insensitive match
656+ dirp = opendir (fn.c_str ());
657+ search_dir = fn;
658+ // We also need to store this in our mapping since we may need it in the future
659+ pathTypeToRealPath.insert (std::make_pair (i, fn));
660+ break ;
661+ }
662+ }
663+ closedir (parentDirP);
664+ }
665+ }
666+ }
593667
594- dirp = opendir (search_path);
595668 if ( dirp ) {
669+ struct dirent *dir = nullptr ;
596670 while ((dir = readdir (dirp)) != NULL )
597671 {
598672 if (!fnmatch (" *.*" , dir->d_name , 0 ))
599673 {
600- char fn[MAX_PATH];
601- snprintf (fn, MAX_PATH-1 , " %s%s" , search_path, dir->d_name );
602- fn[MAX_PATH-1 ] = 0 ;
674+ SCP_string fn;
675+ sprintf (fn, " %s/%s" , search_dir.c_str (), dir->d_name );
603676
604677 struct stat buf;
605- if (stat (fn, &buf) == -1 ) {
678+ if (stat (fn. c_str () , &buf) == -1 ) {
606679 continue ;
607680 }
608681
@@ -626,6 +699,8 @@ void cf_search_root_path(int root_index)
626699
627700 file->pack_offset = 0 ; // Mark as a non-packed file
628701
702+ file->real_name = vm_strdup (fn.c_str ());
703+
629704 num_files++;
630705 // mprintf(( "Found file '%s'\n", file->name_ext ));
631706 }
@@ -827,6 +902,14 @@ void cf_free_secondary_filelist()
827902 // Init the file blocks
828903 for (i=0 ; i<CF_MAX_FILE_BLOCKS; i++ ) {
829904 if ( File_blocks[i] ) {
905+ // Free file paths
906+ for (auto & f : File_blocks[i]->files ) {
907+ if (f.real_name ) {
908+ vm_free (f.real_name );
909+ f.real_name = nullptr ;
910+ }
911+ }
912+
830913 vm_free ( File_blocks[i] );
831914 File_blocks[i] = NULL ;
832915 }
@@ -985,17 +1068,14 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
9851068 *offset = (size_t )f->pack_offset ;
9861069
9871070 if (pack_filename) {
988- cf_root *r = cf_get_root (f->root_index );
989-
990- strncpy ( pack_filename, r->path , max_out );
991-
9921071 if (f->pack_offset < 1 ) {
993- strcat_s ( pack_filename, max_out, Pathtypes[f->pathtype_index ].path );
994-
995- if ( pack_filename[strlen (pack_filename)-1 ] != DIR_SEPARATOR_CHAR )
996- strcat_s ( pack_filename, max_out, DIR_SEPARATOR_STR );
1072+ // This is a real file, return the actual file path
1073+ strncpy ( pack_filename, f->real_name , max_out );
1074+ } else {
1075+ // File is in a pack file
1076+ cf_root *r = cf_get_root (f->root_index );
9971077
998- strcat_s ( pack_filename, max_out, f-> name_ext );
1078+ strncpy ( pack_filename, r-> path , max_out );
9991079 }
10001080 }
10011081
@@ -1013,19 +1093,14 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
10131093 *offset = (size_t )f->pack_offset ;
10141094
10151095 if (pack_filename) {
1016- cf_root *r = cf_get_root (f->root_index );
1017-
1018- strcpy ( pack_filename, r->path );
1019-
10201096 if (f->pack_offset < 1 ) {
1021- if ( strlen (Pathtypes[f->pathtype_index ].path ) ) {
1022- strcat_s ( pack_filename, max_out, Pathtypes[f->pathtype_index ].path );
1023-
1024- if ( pack_filename[strlen (pack_filename)-1 ] != DIR_SEPARATOR_CHAR )
1025- strcat_s ( pack_filename, max_out, DIR_SEPARATOR_STR );
1026- }
1097+ // This is a real file, return the actual file path
1098+ strncpy ( pack_filename, f->real_name , max_out );
1099+ } else {
1100+ // File is in a pack file
1101+ cf_root *r = cf_get_root (f->root_index );
10271102
1028- strcat_s ( pack_filename, max_out, f-> name_ext );
1103+ strncpy ( pack_filename, r-> path , max_out );
10291104 }
10301105 }
10311106
@@ -1260,17 +1335,14 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
12601335 *offset = f->pack_offset ;
12611336
12621337 if (pack_filename) {
1263- cf_root *r = cf_get_root (f->root_index );
1264-
1265- strncpy ( pack_filename, r->path , max_out );
1266-
12671338 if (f->pack_offset < 1 ) {
1268- strcat_s ( pack_filename, max_out, Pathtypes[f->pathtype_index ].path );
1339+ // This is a real file, return the actual file path
1340+ strncpy ( pack_filename, f->real_name , max_out );
1341+ } else {
1342+ // File is in a pack file
1343+ cf_root *r = cf_get_root (f->root_index );
12691344
1270- if ( pack_filename[strlen (pack_filename)-1 ] != DIR_SEPARATOR_CHAR )
1271- strcat_s ( pack_filename, max_out, DIR_SEPARATOR_STR );
1272-
1273- strcat_s ( pack_filename, max_out, f->name_ext );
1345+ strncpy ( pack_filename, r->path , max_out );
12741346 }
12751347 }
12761348
@@ -1291,20 +1363,14 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
12911363 *offset = f->pack_offset ;
12921364
12931365 if (pack_filename) {
1294- cf_root *r = cf_get_root (f->root_index );
1295-
1296- strcpy ( pack_filename, r->path );
1297-
12981366 if (f->pack_offset < 1 ) {
1367+ // This is a real file, return the actual file path
1368+ strncpy ( pack_filename, f->real_name , max_out );
1369+ } else {
1370+ // File is in a pack file
1371+ cf_root *r = cf_get_root (f->root_index );
12991372
1300- if ( strlen (Pathtypes[f->pathtype_index ].path ) ) {
1301- strcat_s ( pack_filename, max_out, Pathtypes[f->pathtype_index ].path );
1302-
1303- if ( pack_filename[strlen (pack_filename)-1 ] != DIR_SEPARATOR_CHAR )
1304- strcat_s ( pack_filename, max_out, DIR_SEPARATOR_STR );
1305- }
1306-
1307- strcat_s ( pack_filename, max_out, f->name_ext );
1373+ strncpy ( pack_filename, r->path , max_out );
13081374 }
13091375 }
13101376
0 commit comments