From 8b37a22dd0d45f881f2dcc45b757ce24647ed9cc Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 18 Jun 2022 10:58:15 +0300 Subject: [PATCH] Provide compatibility layer for paths on Linux/Mac (#50) See #17 See #49 --- src/audio_file.cc | 2 +- src/automap.cc | 6 ++-- src/config.cc | 4 +-- src/core.cc | 4 +-- src/debug.cc | 2 +- src/dfile.cc | 4 +-- src/file_find.cc | 44 +++++++++++++++++++++++-- src/file_find.h | 3 ++ src/file_utils.cc | 28 ++++++++++------ src/game_sound.cc | 8 ++--- src/loadsave.cc | 73 +++++++++++++++++++++++++----------------- src/map.cc | 3 +- src/platform_compat.cc | 56 +++++++++++++++++++++++++++++++- src/platform_compat.h | 8 +++++ src/xfile.cc | 21 +++++++----- 15 files changed, 200 insertions(+), 66 deletions(-) diff --git a/src/audio_file.cc b/src/audio_file.cc index d4a507d..43d35d8 100644 --- a/src/audio_file.cc +++ b/src/audio_file.cc @@ -69,7 +69,7 @@ int audioFileOpen(const char* fname, int flags, ...) *pm++ = 'b'; } - FILE* stream = fopen(path, mode); + FILE* stream = compat_fopen(path, mode); if (stream == NULL) { return -1; } diff --git a/src/automap.cc b/src/automap.cc index 1808aac..9d36cdd 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); } } @@ -774,7 +774,7 @@ int automapSaveCurrent() // NOTE: Not sure about the size. char automapDbPath[512]; sprintf(automapDbPath, "%s\\%s\\%s", masterPatchesPath, "MAPS", AUTOMAP_DB); - if (remove(automapDbPath) != 0) { + if (compat_remove(automapDbPath) != 0) { debugPrint("\nAUTOMAP: Error removing database!\n"); return -1; } @@ -782,7 +782,7 @@ int automapSaveCurrent() // NOTE: Not sure about the size. char automapTmpPath[512]; sprintf(automapTmpPath, "%s\\%s\\%s", masterPatchesPath, "MAPS", AUTOMAP_TMP); - if (rename(automapTmpPath, automapDbPath) != 0) { + if (compat_rename(automapTmpPath, automapDbPath) != 0) { debugPrint("\nAUTOMAP: Error renaming database!\n"); return -1; } diff --git a/src/config.cc b/src/config.cc index 3dc7e15..e741417 100644 --- a/src/config.cc +++ b/src/config.cc @@ -277,7 +277,7 @@ bool configRead(Config* config, const char* filePath, bool isDb) fileClose(stream); } } else { - FILE* stream = fopen(filePath, "rt"); + FILE* stream = compat_fopen(filePath, "rt"); if (stream != NULL) { while (fgets(string, sizeof(string), stream) != NULL) { configParseLine(config, string); @@ -323,7 +323,7 @@ bool configWrite(Config* config, const char* filePath, bool isDb) fileClose(stream); } else { - FILE* stream = fopen(filePath, "wt"); + FILE* stream = compat_fopen(filePath, "wt"); if (stream == NULL) { return false; } diff --git a/src/core.cc b/src/core.cc index 3e2131d..144427f 100644 --- a/src/core.cc +++ b/src/core.cc @@ -721,7 +721,7 @@ int screenshotHandlerDefaultImpl(int width, int height, unsigned char* data, uns for (index = 0; index < 100000; index++) { sprintf(fileName, "scr%.5d.bmp", index); - stream = fopen(fileName, "rb"); + stream = compat_fopen(fileName, "rb"); if (stream == NULL) { break; } @@ -733,7 +733,7 @@ int screenshotHandlerDefaultImpl(int width, int height, unsigned char* data, uns return -1; } - stream = fopen(fileName, "wb"); + stream = compat_fopen(fileName, "wb"); if (stream == NULL) { return -1; } diff --git a/src/debug.cc b/src/debug.cc index 810a487..959e023 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -53,7 +53,7 @@ void _debug_register_log(const char* fileName, const char* mode) fclose(_fd); } - _fd = fopen(fileName, mode); + _fd = compat_fopen(fileName, mode); gDebugPrintProc = _debug_log; } } 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..8ac3497 100644 --- a/src/file_find.cc +++ b/src/file_find.cc @@ -1,6 +1,9 @@ #include "file_find.h" +#include + #include +#include // 0x4E6380 bool fileFindFirst(const char* path, DirectoryFileFindData* findData) @@ -11,14 +14,33 @@ bool fileFindFirst(const char* path, DirectoryFileFindData* findData) return false; } #else - findData->dir = opendir(path); + strcpy(findData->path, path); + + char drive[COMPAT_MAX_DRIVE]; + char dir[COMPAT_MAX_DIR]; + compat_splitpath(path, drive, dir, NULL, NULL); + + char basePath[COMPAT_MAX_PATH]; + compat_makepath(basePath, drive, dir, NULL, NULL); + + findData->dir = opendir(basePath); if (findData->dir == NULL) { return false; } findData->entry = readdir(findData->dir); + while (findData->entry != NULL) { + char entryPath[COMPAT_MAX_PATH]; + compat_makepath(entryPath, drive, dir, fileFindGetName(findData), NULL); + if (fpattern_match(findData->path, entryPath)) { + break; + } + findData->entry = readdir(findData->dir); + } + if (findData->entry == NULL) { closedir(findData->dir); + findData->dir = NULL; return false; } #endif @@ -34,9 +56,23 @@ bool fileFindNext(DirectoryFileFindData* findData) return false; } #else + char drive[COMPAT_MAX_DRIVE]; + char dir[COMPAT_MAX_DIR]; + compat_splitpath(findData->path, drive, dir, NULL, NULL); + findData->entry = readdir(findData->dir); + while (findData->entry != NULL) { + char entryPath[COMPAT_MAX_PATH]; + compat_makepath(entryPath, drive, dir, fileFindGetName(findData), NULL); + if (fpattern_match(findData->path, entryPath)) { + break; + } + findData->entry = readdir(findData->dir); + } + if (findData->entry == NULL) { closedir(findData->dir); + findData->dir = NULL; return false; } #endif @@ -50,8 +86,10 @@ bool findFindClose(DirectoryFileFindData* findData) #if defined(_MSC_VER) FindClose(findData->hFind); #else - if (closedir(findData->dir) != 0) { - return false; + if (findData->dir != NULL) { + if (closedir(findData->dir) != 0) { + return false; + } } #endif diff --git a/src/file_find.h b/src/file_find.h index 2bba6ed..be58bba 100644 --- a/src/file_find.h +++ b/src/file_find.h @@ -1,6 +1,8 @@ #ifndef FILE_FIND_H #define FILE_FIND_H +#include "platform_compat.h" + #if defined(_WIN32) #define WIN32_LEAN_AND_MEAN #define NOMINMAX @@ -35,6 +37,7 @@ typedef struct DirectoryFileFindData { #else DIR* dir; struct dirent* entry; + char path[COMPAT_MAX_PATH]; #endif } DirectoryFileFindData; diff --git a/src/file_utils.cc b/src/file_utils.cc index 7edba4b..5611de0 100644 --- a/src/file_utils.cc +++ b/src/file_utils.cc @@ -2,8 +2,10 @@ // of regular __usercall. #include "file_utils.h" +#include "platform_compat.h" #include +#include #include #include @@ -11,7 +13,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 +24,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 = compat_gzopen(existingFilePath, "rb"); + FILE* outStream = compat_fopen(newFilePath, "wb"); if (inStream != NULL && outStream != NULL) { for (;;) { @@ -58,7 +60,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 +76,7 @@ int fileCopyCompressed(const char* existingFilePath, const char* newFilePath) fclose(inStream); fileCopy(existingFilePath, newFilePath, true); } else { - gzFile outStream = gzopen(newFilePath, "wb"); + gzFile outStream = compat_gzopen(newFilePath, "wb"); if (outStream == NULL) { fclose(inStream); return -1; @@ -100,7 +102,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 +114,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 = compat_gzopen(existingFilePath, "rb"); if (gzstream == NULL) { return -1; } - stream = fopen(newFilePath, "wb"); + stream = compat_fopen(newFilePath, "wb"); if (stream == NULL) { gzclose(gzstream); return -1; @@ -145,9 +147,17 @@ int _gzdecompress_file(const char* existingFilePath, const char* newFilePath) // `bFailIfExists` param. Update callers accordingly. void fileCopy(const char* existingFilePath, const char* newFilePath, bool overwrite) { + char nativeExistingFilePath[COMPAT_MAX_PATH]; + strcpy(nativeExistingFilePath, existingFilePath); + compat_windows_path_to_native(nativeExistingFilePath); + + char nativeNewFilePath[COMPAT_MAX_PATH]; + strcpy(nativeNewFilePath, newFilePath); + compat_windows_path_to_native(nativeNewFilePath); + std::error_code ec; 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::filesystem::copy_file(std::filesystem::path(nativeExistingFilePath), std::filesystem::path(nativeNewFilePath), options, ec); } diff --git a/src/game_sound.cc b/src/game_sound.cc index 47eab43..c7575a2 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); @@ -1857,7 +1857,7 @@ void gameSoundDeleteOldMusicFile() if (_background_fname_copied[0] != '\0') { char path[COMPAT_MAX_PATH]; sprintf(path, "%s%s%s", "sound\\music\\", _background_fname_copied, ".ACM"); - if (remove(path)) { + if (compat_remove(path)) { if (gGameSoundDebugEnabled) { debugPrint("Deleting old music file failed.\n"); } @@ -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..dda3761 100644 --- a/src/loadsave.cc +++ b/src/loadsave.cc @@ -57,6 +57,18 @@ #define LS_COMMENT_WINDOW_X 169 #define LS_COMMENT_WINDOW_Y 116 +// NOTE: The following are "normalized" path components for "proto/critters" and +// "proto/items". The original code does not use uniform case for them (as +// opposed to other path components like MAPS, SAVE.DAT, etc). It does not have +// effect on Windows, but it's important on Linux and Mac, where filesystem is +// case-sensitive. Lowercase is preferred as it is used in other parts of the +// codebase (see `protoInit`, `gArtListDescriptions`). + +#define PROTO_DIR_NAME "proto" +#define CRITTERS_DIR_NAME "critters" +#define ITEMS_DIR_NAME "items" +#define PROTO_FILE_EXT "pro" + // 0x47B7C0 const int gLoadSaveFrmIds[LOAD_SAVE_FRM_COUNT] = { 237, // lsgame.frm - load/save game @@ -233,16 +245,16 @@ void _InitLoadSave() } _MapDirErase("MAPS\\", "SAV"); - _MapDirErase("PROTO\\CRITTERS\\", "PRO"); - _MapDirErase("PROTO\\ITEMS\\", "PRO"); + _MapDirErase(PROTO_DIR_NAME "\\" CRITTERS_DIR_NAME "\\", PROTO_FILE_EXT); + _MapDirErase(PROTO_DIR_NAME "\\" ITEMS_DIR_NAME "\\", PROTO_FILE_EXT); } // 0x47B85C void _ResetLoadSave() { _MapDirErase("MAPS\\", "SAV"); - _MapDirErase("PROTO\\CRITTERS\\", "PRO"); - _MapDirErase("PROTO\\ITEMS\\", "PRO"); + _MapDirErase(PROTO_DIR_NAME "\\" CRITTERS_DIR_NAME "\\", PROTO_FILE_EXT); + _MapDirErase(PROTO_DIR_NAME "\\" ITEMS_DIR_NAME "\\", PROTO_FILE_EXT); } // SaveGame @@ -1329,15 +1341,15 @@ int lsgPerformSaveGame() sprintf(_gmpath, "%s\\%s\\%s%.2d", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1); compat_mkdir(_gmpath); - strcat(_gmpath, "\\proto"); + strcat(_gmpath, "\\" PROTO_DIR_NAME); compat_mkdir(_gmpath); char* protoBasePath = _gmpath + strlen(_gmpath); - strcpy(protoBasePath, "\\critters"); + strcpy(protoBasePath, "\\" CRITTERS_DIR_NAME); compat_mkdir(_gmpath); - strcpy(protoBasePath, "\\items"); + strcpy(protoBasePath, "\\" ITEMS_DIR_NAME); compat_mkdir(_gmpath); if (_SaveBackup() == -1) { @@ -1576,7 +1588,8 @@ int lsgSaveHeaderInSlot(int slot) char mapName[128]; strcpy(mapName, gMapHeader.name); - char* v1 = _strmfe(_str, mapName, "sav"); + // NOTE: Uppercased from "sav". + char* v1 = _strmfe(_str, mapName, "SAV"); strncpy(ptr->file_name, v1, 16); if (fileWrite(ptr->file_name, 16, 1, _flptr) != 1) { return -1; @@ -2141,7 +2154,9 @@ int _GameMap2Slot(File* stream) continue; } - const char* critterItemPath = (pid >> 24) == OBJ_TYPE_CRITTER ? "PROTO\\CRITTERS" : "PROTO\\ITEMS"; + const char* critterItemPath = (pid >> 24) == OBJ_TYPE_CRITTER + ? PROTO_DIR_NAME "\\" CRITTERS_DIR_NAME + : PROTO_DIR_NAME "\\" ITEMS_DIR_NAME; sprintf(_str0, "%s\\%s\\%s", _patches, critterItemPath, path); sprintf(_str1, "%s\\%s\\%s%.2d\\%s\\%s", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1, critterItemPath, path); if (fileCopyCompressed(_str0, _str1) == -1) { @@ -2177,7 +2192,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]; @@ -2246,15 +2261,15 @@ int _SlotMap2Game(File* stream) return -1; } - sprintf(_str0, "%s\\", "PROTO\\CRITTERS"); + sprintf(_str0, "%s\\", PROTO_DIR_NAME "\\" CRITTERS_DIR_NAME); - if (_MapDirErase(_str0, "PRO") == -1) { + if (_MapDirErase(_str0, PROTO_FILE_EXT) == -1) { debugPrint("LOADSAVE: returning 3\n"); return -1; } - sprintf(_str0, "%s\\", "PROTO\\ITEMS"); - if (_MapDirErase(_str0, "PRO") == -1) { + sprintf(_str0, "%s\\", PROTO_DIR_NAME "\\" ITEMS_DIR_NAME); + if (_MapDirErase(_str0, PROTO_FILE_EXT) == -1) { debugPrint("LOADSAVE: returning 4\n"); return -1; } @@ -2266,7 +2281,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) { @@ -2275,8 +2290,8 @@ int _SlotMap2Game(File* stream) char protoPath[COMPAT_MAX_PATH]; if (_proto_list_str(pid, protoPath) == 0) { const char* basePath = pid >> 24 == OBJ_TYPE_CRITTER - ? "PROTO\\CRITTERS" - : "PROTO\\ITEMS"; + ? PROTO_DIR_NAME "\\" CRITTERS_DIR_NAME + : PROTO_DIR_NAME "\\" ITEMS_DIR_NAME; sprintf(_str0, "%s\\%s\\%s", _patches, basePath, protoPath); sprintf(_str1, "%s\\%s\\%s%.2d\\%s\\%s", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1, basePath, protoPath); @@ -2448,7 +2463,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 +2476,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; } @@ -2483,7 +2498,7 @@ int _SaveBackup() File* stream1 = fileOpen(_str0, "rb"); if (stream1 != NULL) { fileClose(stream1); - if (rename(_str0, _str1) != 0) { + if (compat_rename(_str0, _str1) != 0) { return -1; } } @@ -2505,7 +2520,7 @@ int _SaveBackup() strcat(_str0, fileList[index]); _strmfe(_str1, _str0, "BAK"); - if (rename(_str0, _str1) != 0) { + if (compat_rename(_str0, _str1) != 0) { fileNameListFree(&fileList, 0); return -1; } @@ -2550,9 +2565,9 @@ int _RestoreSave() strcpy(_str0, _gmpath); strcat(_str0, "SAVE.DAT"); _strmfe(_str1, _str0, "BAK"); - remove(_str0); + compat_remove(_str0); - if (rename(_str1, _str0) != 0) { + if (compat_rename(_str1, _str0) != 0) { _EraseSave(); return -1; } @@ -2578,8 +2593,8 @@ int _RestoreSave() strcpy(_str0, _gmpath); strcat(_str0, fileList[index]); _strmfe(_str1, _str0, "SAV"); - remove(_str1); - if (rename(_str0, _str1) != 0) { + compat_remove(_str1); + if (compat_rename(_str0, _str1) != 0) { // FIXME: Probably leaks fileList. _EraseSave(); return -1; @@ -2601,7 +2616,7 @@ int _RestoreSave() strcpy(_str1, _gmpath); strcat(_str1, v2); - if (rename(_str0, _str1) != 0) { + if (compat_rename(_str0, _str1) != 0) { _EraseSave(); return -1; } @@ -2637,7 +2652,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 +2667,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 +2678,7 @@ int _EraseSave() strcpy(_str0, _gmpath); strcat(_str0, v1); - remove(_str0); + compat_remove(_str0); return 0; } diff --git a/src/map.cc b/src/map.cc index b298f51..1623701 100644 --- a/src/map.cc +++ b/src/map.cc @@ -644,7 +644,8 @@ int mapScroll(int dx, int dy) char* mapBuildPath(char* name) { if (*name != '\\') { - sprintf(_map_path, "maps\\%s", name); + // NOTE: Uppercased from "maps". + sprintf(_map_path, "MAPS\\%s", name); return _map_path; } return name; diff --git a/src/platform_compat.cc b/src/platform_compat.cc index 69da2c5..4239d45 100644 --- a/src/platform_compat.cc +++ b/src/platform_compat.cc @@ -132,8 +132,12 @@ long compat_filelength(int fd) int compat_mkdir(const char* path) { + char nativePath[COMPAT_MAX_PATH]; + strcpy(nativePath, path); + compat_windows_path_to_native(nativePath); + std::error_code ec; - if (std::filesystem::create_directory(std::filesystem::path(path), ec)) { + if (std::filesystem::create_directory(std::filesystem::path(nativePath), ec)) { return 0; } @@ -150,3 +154,53 @@ unsigned int compat_timeGetTime() return static_cast(std::chrono::duration_cast(now - start).count()); #endif } + +FILE* compat_fopen(const char* path, const char* mode) +{ + char nativePath[COMPAT_MAX_PATH]; + strcpy(nativePath, path); + compat_windows_path_to_native(nativePath); + return fopen(nativePath, mode); +} + +gzFile compat_gzopen(const char* path, const char* mode) +{ + char nativePath[COMPAT_MAX_PATH]; + strcpy(nativePath, path); + compat_windows_path_to_native(nativePath); + return gzopen(nativePath, mode); +} + +int compat_remove(const char* path) +{ + char nativePath[COMPAT_MAX_PATH]; + strcpy(nativePath, path); + compat_windows_path_to_native(nativePath); + return remove(nativePath); +} + +int compat_rename(const char* oldFileName, const char* newFileName) +{ + char nativeOldFileName[COMPAT_MAX_PATH]; + strcpy(nativeOldFileName, oldFileName); + compat_windows_path_to_native(nativeOldFileName); + + char nativeNewFileName[COMPAT_MAX_PATH]; + strcpy(nativeNewFileName, newFileName); + compat_windows_path_to_native(nativeNewFileName); + + return rename(nativeOldFileName, nativeNewFileName); +} + +void compat_windows_path_to_native(char* path) +{ +#ifndef _WIN32 + char* pch = path; + while (*pch != '\0') { + if (*pch == '\\') { + *pch = '/'; + } + pch++; + } +#endif +} diff --git a/src/platform_compat.h b/src/platform_compat.h index 77b762d..1516a09 100644 --- a/src/platform_compat.h +++ b/src/platform_compat.h @@ -2,6 +2,9 @@ #define PLATFORM_COMPAT_H #include +#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 +34,10 @@ 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* path, const char* mode); +gzFile compat_gzopen(const char* path, const char* mode); +int compat_remove(const char* path); +int compat_rename(const char* oldFileName, const char* newFileName); +void compat_windows_path_to_native(char* path); #endif /* PLATFORM_COMPAT_H */ diff --git a/src/xfile.cc b/src/xfile.cc index 27589db..10a38fa 100644 --- a/src/xfile.cc +++ b/src/xfile.cc @@ -65,7 +65,7 @@ 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; @@ -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,7 +103,7 @@ 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; @@ -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 = compat_gzopen(path, mode); } else { // File is not gzipped. rewind(stream->file); @@ -544,13 +544,17 @@ bool xlistEnumerate(const char* pattern, XListEnumerationHandler* handler, XList context.xlist = xlist; + char nativePattern[COMPAT_MAX_PATH]; + strcpy(nativePattern, pattern); + compat_windows_path_to_native(nativePattern); + char drive[COMPAT_MAX_DRIVE]; char dir[COMPAT_MAX_DIR]; char fileName[COMPAT_MAX_FNAME]; char extension[COMPAT_MAX_EXT]; - compat_splitpath(pattern, drive, dir, fileName, extension); + compat_splitpath(nativePattern, drive, dir, fileName, extension); if (drive[0] != '\0' || dir[0] == '\\' || dir[0] == '/' || dir[0] == '.') { - if (fileFindFirst(pattern, &directoryFileFindData)) { + if (fileFindFirst(nativePattern, &directoryFileFindData)) { do { bool isDirectory = fileFindIsDirectory(&directoryFileFindData); char* entryName = fileFindGetName(&directoryFileFindData); @@ -594,6 +598,7 @@ bool xlistEnumerate(const char* pattern, XListEnumerationHandler* handler, XList } else { char path[COMPAT_MAX_PATH]; sprintf(path, "%s\\%s", xbase->path, pattern); + compat_windows_path_to_native(path); if (fileFindFirst(path, &directoryFileFindData)) { do { @@ -622,8 +627,8 @@ bool xlistEnumerate(const char* pattern, XListEnumerationHandler* handler, XList xbase = xbase->next; } - compat_splitpath(pattern, drive, dir, fileName, extension); - if (fileFindFirst(pattern, &directoryFileFindData)) { + compat_splitpath(nativePattern, drive, dir, fileName, extension); + if (fileFindFirst(nativePattern, &directoryFileFindData)) { do { bool isDirectory = fileFindIsDirectory(&directoryFileFindData); char* entryName = fileFindGetName(&directoryFileFindData);