diff --git a/src/automap.cc b/src/automap.cc index 1808aac..80a25dd 100644 --- a/src/automap.cc +++ b/src/automap.cc @@ -237,7 +237,7 @@ void automapExit() if (configGetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_MASTER_PATCHES_KEY, &masterPatchesPath)) { char path[COMPAT_MAX_PATH]; sprintf(path, "%s\\%s\\%s", masterPatchesPath, "MAPS", AUTOMAP_DB); - remove(path); + compat_remove(path); } } diff --git a/src/dfile.cc b/src/dfile.cc index 9d71446..cb1cb63 100644 --- a/src/dfile.cc +++ b/src/dfile.cc @@ -16,7 +16,7 @@ DBase* dbaseOpen(const char* filePath) { assert(filePath); // "filename", "dfile.c", 74 - FILE* stream = fopen(filePath, "rb"); + FILE* stream = compat_fopen(filePath, "rb"); if (stream == NULL) { return NULL; } @@ -635,7 +635,7 @@ DFile* dfileOpenInternal(DBase* dbase, const char* filePath, const char* mode, D dfile->entry = entry; // Open stream to .DAT file. - dfile->stream = fopen(dbase->path, "rb"); + dfile->stream = compat_fopen(dbase->path, "rb"); if (dfile->stream == NULL) { goto err; } diff --git a/src/file_find.cc b/src/file_find.cc index 59c3f13..380ba9d 100644 --- a/src/file_find.cc +++ b/src/file_find.cc @@ -1,7 +1,50 @@ #include "file_find.h" +#ifndef _WIN32 +#include +#endif #include +#ifndef _WIN32 +bool findFileRegex(DirectoryFileFindData* findData) { + bool findingNextFile = (findData->filename[0] != '\0'); + + std::string filenameRegex = findData->searchPath.filename().string(); + + auto wildcardPosition = filenameRegex.find("*"); + if (wildcardPosition != std::string::npos) { + filenameRegex = filenameRegex.insert(wildcardPosition, "."); + } + + try { + const std::filesystem::directory_iterator end; + for (std::filesystem::directory_iterator iter{findData->searchPath.parent_path()}; iter != end; iter++) { + + std::string currentFilename = iter->path().filename().string(); + + if (findingNextFile) { + if (currentFilename == findData->filename) { + findingNextFile = false; + } + continue; + } + + if (std::regex_match(currentFilename, std::regex(filenameRegex))) { + + memset(findData->filename, 0, sizeof findData->filename); + currentFilename.copy(findData->filename, currentFilename.length()); + findData->filename[currentFilename.length()] = '\0'; + return true; + } + } + } + catch (std::exception&) {} + + memset(findData->filename, 0, sizeof findData->filename); + return false; +} +#endif + // 0x4E6380 bool fileFindFirst(const char* path, DirectoryFileFindData* findData) { @@ -10,20 +53,12 @@ bool fileFindFirst(const char* path, DirectoryFileFindData* findData) if (findData->hFind == INVALID_HANDLE_VALUE) { return false; } -#else - findData->dir = opendir(path); - if (findData->dir == NULL) { - return false; - } - - findData->entry = readdir(findData->dir); - if (findData->entry == NULL) { - closedir(findData->dir); - return false; - } -#endif - return true; +#else + memset(findData->filename, 0, sizeof findData->filename); + findData->searchPath = compat_convertPathSeparators(path); + return findFileRegex(findData); +#endif } // 0x4E63A8 @@ -33,15 +68,10 @@ bool fileFindNext(DirectoryFileFindData* findData) if (!FindNextFileA(findData->hFind, &(findData->ffd))) { return false; } -#else - findData->entry = readdir(findData->dir); - if (findData->entry == NULL) { - closedir(findData->dir); - return false; - } -#endif - return true; +#else + return findFileRegex(findData); +#endif } // 0x4E63CC @@ -49,10 +79,6 @@ bool findFindClose(DirectoryFileFindData* findData) { #if defined(_MSC_VER) FindClose(findData->hFind); -#else - if (closedir(findData->dir) != 0) { - return false; - } #endif return true; diff --git a/src/file_find.h b/src/file_find.h index 2bba6ed..e8c5c4c 100644 --- a/src/file_find.h +++ b/src/file_find.h @@ -6,7 +6,9 @@ #define NOMINMAX #include #else -#include +#include "platform_compat.h" +#include +#include #endif // NOTE: This structure is significantly different from what was in the @@ -33,8 +35,8 @@ typedef struct DirectoryFileFindData { HANDLE hFind; WIN32_FIND_DATAA ffd; #else - DIR* dir; - struct dirent* entry; + std::filesystem::path searchPath; + char filename[COMPAT_MAX_FNAME]; #endif } DirectoryFileFindData; @@ -49,7 +51,7 @@ static inline bool fileFindIsDirectory(DirectoryFileFindData* findData) #elif defined(__WATCOMC__) return (findData->entry->d_attr & _A_SUBDIR) != 0; #else - return findData->entry->d_type == DT_DIR; + return std::filesystem::is_directory(findData->searchPath); #endif } @@ -58,7 +60,7 @@ static inline char* fileFindGetName(DirectoryFileFindData* findData) #if defined(_WIN32) return findData->ffd.cFileName; #else - return findData->entry->d_name; + return findData->filename; #endif } diff --git a/src/file_utils.cc b/src/file_utils.cc index 7edba4b..a719db6 100644 --- a/src/file_utils.cc +++ b/src/file_utils.cc @@ -2,6 +2,7 @@ // of regular __usercall. #include "file_utils.h" +#include "platform_compat.h" #include #include @@ -11,7 +12,7 @@ // 0x452740 int fileCopyDecompressed(const char* existingFilePath, const char* newFilePath) { - FILE* stream = fopen(existingFilePath, "rb"); + FILE* stream = compat_fopen(existingFilePath, "rb"); if (stream == NULL) { return -1; } @@ -22,8 +23,8 @@ int fileCopyDecompressed(const char* existingFilePath, const char* newFilePath) fclose(stream); if (magic[0] == 0x1F && magic[1] == 0x8B) { - gzFile inStream = gzopen(existingFilePath, "rb"); - FILE* outStream = fopen(newFilePath, "wb"); + gzFile inStream = gzopen(compat_convertPathSeparators(existingFilePath).c_str(), "rb"); + FILE* outStream = compat_fopen(newFilePath, "wb"); if (inStream != NULL && outStream != NULL) { for (;;) { @@ -58,7 +59,7 @@ int fileCopyDecompressed(const char* existingFilePath, const char* newFilePath) // 0x452804 int fileCopyCompressed(const char* existingFilePath, const char* newFilePath) { - FILE* inStream = fopen(existingFilePath, "rb"); + FILE* inStream = compat_fopen(existingFilePath, "rb"); if (inStream == NULL) { return -1; } @@ -74,7 +75,7 @@ int fileCopyCompressed(const char* existingFilePath, const char* newFilePath) fclose(inStream); fileCopy(existingFilePath, newFilePath, true); } else { - gzFile outStream = gzopen(newFilePath, "wb"); + gzFile outStream = gzopen(compat_convertPathSeparators(newFilePath).c_str(), "wb"); if (outStream == NULL) { fclose(inStream); return -1; @@ -100,7 +101,7 @@ int fileCopyCompressed(const char* existingFilePath, const char* newFilePath) // TODO: Check, implementation looks odd. int _gzdecompress_file(const char* existingFilePath, const char* newFilePath) { - FILE* stream = fopen(existingFilePath, "rb"); + FILE* stream = compat_fopen(existingFilePath, "rb"); if (stream == NULL) { return -1; } @@ -112,12 +113,12 @@ int _gzdecompress_file(const char* existingFilePath, const char* newFilePath) // TODO: Is it broken? if (magic[0] != 0x1F || magic[1] != 0x8B) { - gzFile gzstream = gzopen(existingFilePath, "rb"); + gzFile gzstream = gzopen(compat_convertPathSeparators(existingFilePath).c_str(), "rb"); if (gzstream == NULL) { return -1; } - stream = fopen(newFilePath, "wb"); + stream = compat_fopen(newFilePath, "wb"); if (stream == NULL) { gzclose(gzstream); return -1; @@ -149,5 +150,9 @@ void fileCopy(const char* existingFilePath, const char* newFilePath, bool overwr std::filesystem::copy_options options = overwrite ? std::filesystem::copy_options::overwrite_existing : std::filesystem::copy_options::none; - std::filesystem::copy_file(std::filesystem::path(existingFilePath), std::filesystem::path(newFilePath), options, ec); + + std::string compatExistingFilePath = compat_convertPathSeparators(existingFilePath); + std::string compatNewFilePath = compat_convertPathSeparators(newFilePath); + + std::filesystem::copy_file(std::filesystem::path(compatExistingFilePath), std::filesystem::path(compatNewFilePath), options, ec); } diff --git a/src/game_sound.cc b/src/game_sound.cc index 47eab43..be2198d 100644 --- a/src/game_sound.cc +++ b/src/game_sound.cc @@ -1703,7 +1703,7 @@ int gameSoundFindBackgroundSoundPathWithCopy(char* dest, const char* src) char inPath[COMPAT_MAX_PATH]; sprintf(inPath, "%s%s%s", _sound_music_path2, src, ".ACM"); - FILE* inStream = fopen(inPath, "rb"); + FILE* inStream = compat_fopen(inPath, "rb"); if (inStream == NULL) { if (gGameSoundDebugEnabled) { debugPrint("Unable to find music file %s to copy down.\n", src); @@ -1712,7 +1712,7 @@ int gameSoundFindBackgroundSoundPathWithCopy(char* dest, const char* src) return -1; } - FILE* outStream = fopen(outPath, "wb"); + FILE* outStream = compat_fopen(outPath, "wb"); if (outStream == NULL) { if (gGameSoundDebugEnabled) { debugPrint("Unable to open music file %s for copying to.", src); @@ -2026,7 +2026,7 @@ Sound* _gsound_get_sound_ready_for_effect() // 0x4524E0 bool _gsound_file_exists_f(const char* fname) { - FILE* f = fopen(fname, "rb"); + FILE* f = compat_fopen(fname, "rb"); if (f == NULL) { return false; } diff --git a/src/loadsave.cc b/src/loadsave.cc index fefd03f..8e023ac 100644 --- a/src/loadsave.cc +++ b/src/loadsave.cc @@ -2177,7 +2177,7 @@ int _GameMap2Slot(File* stream) sprintf(_gmpath, "%s\\%s\\%s%.2d\\", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1); _strmfe(_str0, "AUTOMAP.DB", "SAV"); strcat(_gmpath, _str0); - remove(_gmpath); + compat_remove(_gmpath); for (int index = 0; index < fileNameListLength; index += 1) { char* string = fileNameList[index]; @@ -2204,7 +2204,7 @@ int _GameMap2Slot(File* stream) return -1; } - sprintf(_str0, "%s\\%s", "MAPS", "AUTOMAP.DB"); + sprintf(_str0, "%s\\%s", "MAPS", AUTOMAP_DB); File* inStream = fileOpen(_str0, "rb"); if (inStream == NULL) { return -1; @@ -2266,7 +2266,7 @@ int _SlotMap2Game(File* stream) } sprintf(_str0, "%s\\%s\\%s", _patches, "MAPS", "AUTOMAP.DB"); - remove(_str0); + compat_remove(_str0); if (gPartyMemberDescriptionsLength > 1) { for (int index = 1; index < gPartyMemberDescriptionsLength; index += 1) { @@ -2323,7 +2323,7 @@ int _SlotMap2Game(File* stream) } if (mapLoadSaved(_LSData[_slot_cursor].file_name) == -1) { - debugPrint("LOADSAVE: returning 13\n"); + debugPrint("\nLOADSAVE: returning 13\n"); return -1; } @@ -2448,7 +2448,7 @@ int _MapDirErase(const char* relativePath, const char* extension) int fileListLength = fileNameListInit(path, &fileList, 0, 0); while (--fileListLength >= 0) { sprintf(path, "%s\\%s%s", _patches, relativePath, fileList[fileListLength]); - remove(path); + compat_remove(path); } fileNameListFree(&fileList, 0); @@ -2461,7 +2461,7 @@ int _MapDirEraseFile_(const char* a1, const char* a2) char path[COMPAT_MAX_PATH]; sprintf(path, "%s\\%s%s", _patches, a1, a2); - if (remove(path) != 0) { + if (compat_remove(path) != 0) { return -1; } @@ -2550,7 +2550,7 @@ int _RestoreSave() strcpy(_str0, _gmpath); strcat(_str0, "SAVE.DAT"); _strmfe(_str1, _str0, "BAK"); - remove(_str0); + compat_remove(_str0); if (rename(_str1, _str0) != 0) { _EraseSave(); @@ -2578,7 +2578,7 @@ int _RestoreSave() strcpy(_str0, _gmpath); strcat(_str0, fileList[index]); _strmfe(_str1, _str0, "SAV"); - remove(_str1); + compat_remove(_str1); if (rename(_str0, _str1) != 0) { // FIXME: Probably leaks fileList. _EraseSave(); @@ -2637,7 +2637,7 @@ int _EraseSave() sprintf(_gmpath, "%s\\%s\\%s%.2d\\", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1); strcpy(_str0, _gmpath); strcat(_str0, "SAVE.DAT"); - remove(_str0); + compat_remove(_str0); sprintf(_gmpath, "%s\\%s%.2d\\", "SAVEGAME", "SLOT", _slot_cursor + 1); sprintf(_str0, "%s*.%s", _gmpath, "SAV"); @@ -2652,7 +2652,7 @@ int _EraseSave() for (int index = fileListLength - 1; index >= 0; index--) { strcpy(_str0, _gmpath); strcat(_str0, fileList[index]); - remove(_str0); + compat_remove(_str0); } fileNameListFree(&fileList, 0); @@ -2663,7 +2663,7 @@ int _EraseSave() strcpy(_str0, _gmpath); strcat(_str0, v1); - remove(_str0); + compat_remove(_str0); return 0; } diff --git a/src/platform_compat.cc b/src/platform_compat.cc index 69da2c5..5ac14b3 100644 --- a/src/platform_compat.cc +++ b/src/platform_compat.cc @@ -2,7 +2,6 @@ #include #include - #include #ifdef _WIN32 @@ -16,6 +15,7 @@ #include #else #include +#include #endif #ifdef _WIN32 @@ -54,7 +54,8 @@ void compat_splitpath(const char* path, char* drive, char* dir, char* fname, cha #if defined(_WIN32) _splitpath(path, drive, dir, fname, ext); #else - std::filesystem::path p(path); + + std::filesystem::path p(compat_convertPathSeparators(path)); if (drive != NULL) { strcpy(drive, p.root_name().string().substr(0, COMPAT_MAX_DRIVE - 1).c_str()); @@ -132,8 +133,10 @@ long compat_filelength(int fd) int compat_mkdir(const char* path) { + auto platformPath = compat_convertPathSeparators(path); + std::error_code ec; - if (std::filesystem::create_directory(std::filesystem::path(path), ec)) { + if (std::filesystem::create_directory(platformPath, ec)) { return 0; } @@ -150,3 +153,25 @@ unsigned int compat_timeGetTime() return static_cast(std::chrono::duration_cast(now - start).count()); #endif } + +std::string compat_convertPathSeparators(const char* path) { + + auto compatPath = std::string(path); + +#ifndef _WIN32 + std::replace(compatPath.begin(), compatPath.end(), '\\','/'); + std::transform(compatPath.begin(), compatPath.end(), compatPath.begin(), ::tolower); +#endif + + return compatPath; +} + +FILE* compat_fopen(const char* filename, const char* mode) +{ + return fopen(compat_convertPathSeparators(filename).c_str(), mode); +} + +int compat_remove(const char* filename) +{ + return remove(compat_convertPathSeparators(filename).c_str()); +} diff --git a/src/platform_compat.h b/src/platform_compat.h index 77b762d..8149dcb 100644 --- a/src/platform_compat.h +++ b/src/platform_compat.h @@ -2,6 +2,7 @@ #define PLATFORM_COMPAT_H #include +#include // TODO: This is compatibility cross-platform layer. Designed to have minimal // impact on the codebase. Remove once it's no longer needed. @@ -31,5 +32,8 @@ long compat_tell(int fileHandle); long compat_filelength(int fd); int compat_mkdir(const char* path); unsigned int compat_timeGetTime(); +FILE* compat_fopen(const char* filename, const char* mode); +int compat_remove(const char* filename); +std::string compat_convertPathSeparators(const char* path); #endif /* PLATFORM_COMPAT_H */ diff --git a/src/xfile.cc b/src/xfile.cc index 27589db..97962dd 100644 --- a/src/xfile.cc +++ b/src/xfile.cc @@ -65,14 +65,14 @@ XFile* xfileOpen(const char* filePath, const char* mode) char path[COMPAT_MAX_PATH]; if (drive[0] != '\0' || dir[0] == '\\' || dir[0] == '/' || dir[0] == '.') { // [filePath] is an absolute path. Attempt to open as plain stream. - stream->file = fopen(filePath, mode); + stream->file = compat_fopen(filePath, mode); if (stream->file == NULL) { free(stream); return NULL; } stream->type = XFILE_TYPE_FILE; - sprintf(path, filePath); + sprintf(path, "%s", filePath); } else { // [filePath] is a relative path. Loop thru open xbases and attempt to // open [filePath] from appropriate xbase. @@ -83,7 +83,7 @@ XFile* xfileOpen(const char* filePath, const char* mode) stream->dfile = dfileOpen(curr->dbase, filePath, mode); if (stream->dfile != NULL) { stream->type = XFILE_TYPE_DFILE; - sprintf(path, filePath); + sprintf(path, "%s", filePath); break; } } else { @@ -91,7 +91,7 @@ XFile* xfileOpen(const char* filePath, const char* mode) sprintf(path, "%s\\%s", curr->path, filePath); // Attempt to open plain stream. - stream->file = fopen(path, mode); + stream->file = compat_fopen(path, mode); if (stream->file != NULL) { stream->type = XFILE_TYPE_FILE; break; @@ -103,14 +103,14 @@ XFile* xfileOpen(const char* filePath, const char* mode) if (stream->file == NULL) { // File was not opened during the loop above. Attempt to open file // relative to the current working directory. - stream->file = fopen(filePath, mode); + stream->file = compat_fopen(filePath, mode); if (stream->file == NULL) { free(stream); return NULL; } stream->type = XFILE_TYPE_FILE; - sprintf(path, filePath); + sprintf(path, "%s", filePath); } } @@ -125,7 +125,7 @@ XFile* xfileOpen(const char* filePath, const char* mode) fclose(stream->file); stream->type = XFILE_TYPE_GZFILE; - stream->gzfile = gzopen(path, mode); + stream->gzfile = gzopen(compat_convertPathSeparators(path).c_str(), mode); } else { // File is not gzipped. rewind(stream->file);