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/loadsave.cc b/src/loadsave.cc index fefd03f..9af13cd 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) { @@ -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; } @@ -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); 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/xfile.cc b/src/xfile.cc index 0354d63..10a38fa 100644 --- a/src/xfile.cc +++ b/src/xfile.cc @@ -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);