From 217ae84c626dae364474455c2b24ef92fcb01574 Mon Sep 17 00:00:00 2001 From: IntelOrca Date: Fri, 17 Oct 2014 03:22:45 +0100 Subject: [PATCH] add cross platform interface for enumerating files --- src/platform/platform.h | 3 ++ src/platform/windows.c | 66 +++++++++++++++++++++++++++++++++++++++++ src/scenario.c | 18 +++++------ src/scenario.h | 2 +- src/scenario_list.c | 55 +++++++++++++++++----------------- 5 files changed, 105 insertions(+), 39 deletions(-) diff --git a/src/platform/platform.h b/src/platform/platform.h index 63d1806aa2..543f764ca5 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -31,5 +31,8 @@ int platform_file_exists(const char *path); int platform_directory_exists(const char *path); int platform_ensure_directory_exists(const char *path); int platform_lock_single_instance(); +int platform_enumerate_files_begin(const char *pattern); +int platform_enumerate_files_next(int handle, char **outFileName); +void platform_enumerate_files_end(int handle); #endif \ No newline at end of file diff --git a/src/platform/windows.c b/src/platform/windows.c index 30b2b3f5b8..c13a81862d 100644 --- a/src/platform/windows.c +++ b/src/platform/windows.c @@ -121,6 +121,72 @@ int platform_lock_single_instance() } } +typedef struct { + char active; + char pattern[MAX_PATH]; + HANDLE handle; + WIN32_FIND_DATAA data; +} enumerate_file_info; +static enumerate_file_info _enumerateFileInfoList[8] = { 0 }; + +int platform_enumerate_files_begin(const char *pattern) +{ + int i; + enumerate_file_info *enumFileInfo; + + for (i = 0; i < countof(_enumerateFileInfoList); i++) { + enumFileInfo = &_enumerateFileInfoList[i]; + if (!enumFileInfo->active) { + strncpy(enumFileInfo->pattern, pattern, MAX_PATH); + enumFileInfo->handle = NULL; + enumFileInfo->active = 1; + return i; + } + } + + return -1; +} + +int platform_enumerate_files_next(int handle, char **outFileName) +{ + int result; + enumerate_file_info *enumFileInfo; + HANDLE findFileHandle; + + enumFileInfo = &_enumerateFileInfoList[handle]; + + if (enumFileInfo->handle == NULL) { + findFileHandle = FindFirstFile(enumFileInfo->pattern, &enumFileInfo->data); + if (findFileHandle != INVALID_HANDLE_VALUE) { + enumFileInfo->handle = findFileHandle; + result = 1; + } else { + result = 0; + } + } else { + result = FindNextFile(enumFileInfo->handle, &enumFileInfo->data); + } + + if (result) { + *outFileName = enumFileInfo->data.cFileName; + return 1; + } else { + return 0; + } +} + +void platform_enumerate_files_end(int handle) +{ + enumerate_file_info *enumFileInfo; + + enumFileInfo = &_enumerateFileInfoList[handle]; + if (enumFileInfo->handle != NULL) { + FindClose(enumFileInfo->handle); + enumFileInfo->handle = NULL; + } + enumFileInfo->active = 0; +} + /** * http://alter.org.ua/en/docs/win/args/ */ diff --git a/src/scenario.c b/src/scenario.c index b56afe6b49..1a81cbe709 100644 --- a/src/scenario.c +++ b/src/scenario.c @@ -40,28 +40,26 @@ * Loads only the basic information from a scenario. * rct2: 0x006761D6 */ -int scenario_load_basic(const char *path) +int scenario_load_basic(const char *path, rct_s6_header *header, rct_s6_info *info) { FILE *file; - rct_s6_header *s6Header = (rct_s6_header*)0x009E34E4; - rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; file = fopen(path, "rb"); if (file != NULL) { // Read first chunk - sawyercoding_read_chunk(file, (uint8*)s6Header); - if (s6Header->type == S6_TYPE_SCENARIO) { + sawyercoding_read_chunk(file, (uint8*)header); + if (header->type == S6_TYPE_SCENARIO) { // Read second chunk - sawyercoding_read_chunk(file, (uint8*)s6Info); + sawyercoding_read_chunk(file, (uint8*)info); fclose(file); RCT2_GLOBAL(0x009AA00C, uint8) = 0; // Checks for a scenario string object (possibly for localisation) - if ((s6Info->entry.flags & 0xFF) != 255) { - if (object_get_scenario_text(&s6Info->entry)) { + if ((info->entry.flags & 0xFF) != 255) { + if (object_get_scenario_text(&info->entry)) { int ebp = RCT2_GLOBAL(0x009ADAF8, uint32); - format_string(s6Info->name, RCT2_GLOBAL(ebp, sint16), NULL); - format_string(s6Info->details, RCT2_GLOBAL(ebp + 4, sint16), NULL); + format_string(info->name, RCT2_GLOBAL(ebp, sint16), NULL); + format_string(info->details, RCT2_GLOBAL(ebp + 4, sint16), NULL); RCT2_GLOBAL(0x009AA00C, uint8) = RCT2_GLOBAL(ebp + 6, uint8); object_free_scenario_text(); } diff --git a/src/scenario.h b/src/scenario.h index 80e145d9b1..e969e8b34d 100644 --- a/src/scenario.h +++ b/src/scenario.h @@ -402,7 +402,7 @@ extern rct_scenario_basic *gScenarioList; int scenario_scores_save(); void scenario_load_list(); -int scenario_load_basic(const char *path); +int scenario_load_basic(const char *path, rct_s6_header *header, rct_s6_info *info); int scenario_load(const char *path); int scenario_load_and_play(const rct_scenario_basic *scenario); int scenario_load_and_play_from_path(const char *path); diff --git a/src/scenario_list.c b/src/scenario_list.c index c2e7a97df7..13cd812662 100644 --- a/src/scenario_list.c +++ b/src/scenario_list.c @@ -18,9 +18,8 @@ * along with this program. If not, see . *****************************************************************************/ -#include #include "addresses.h" -#include "rct2.h" +#include "platform/platform.h" #include "scenario.h" // Scenario list @@ -49,9 +48,8 @@ static rct_scenario_basic *get_scenario_by_filename(const char *filename) */ void scenario_load_list() { - int i; - HANDLE hFindFile; - WIN32_FIND_DATAA findFileData; + int i, enumFileHandle; + char *enumFileName; // Load scores scenario_scores_load(); @@ -61,12 +59,12 @@ void scenario_load_list() gScenarioList[i].flags &= ~SCENARIO_FLAGS_VISIBLE; // Enumerate through each scenario in the directory - hFindFile = FindFirstFile(RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char), &findFileData); - if (hFindFile != INVALID_HANDLE_VALUE) { - do { - scenario_list_add(findFileData.cFileName); - } while (FindNextFile(hFindFile, &findFileData)); - FindClose(hFindFile); + enumFileHandle = platform_enumerate_files_begin(RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char)); + if (enumFileHandle >= 0) { + while (platform_enumerate_files_next(enumFileHandle, &enumFileName)) { + scenario_list_add(enumFileName); + } + platform_enumerate_files_end(enumFileHandle); } // Sort alphabetically @@ -80,17 +78,18 @@ static void scenario_list_add(const char *path) { char scenarioPath[MAX_PATH]; rct_scenario_basic *scenario; - rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; + rct_s6_header s6Header; + rct_s6_info s6Info; // Get absolute path subsitute_path(scenarioPath, RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char), path); // Load the basic scenario information - if (!scenario_load_basic(scenarioPath)) + if (!scenario_load_basic(scenarioPath, &s6Header, &s6Info)) return; // Ignore scenarios where first header byte is not 255 - if (s6Info->var_000 != 255) + if (s6Info.var_000 != 255) return; // Check if scenario already exists in list, likely if in scores @@ -98,13 +97,13 @@ static void scenario_list_add(const char *path) if (scenario != NULL) { // Update the scenario information scenario->flags |= SCENARIO_FLAGS_VISIBLE; - scenario->category = s6Info->category; - scenario->objective_type = s6Info->objective_type; - scenario->objective_arg_1 = s6Info->objective_arg_1; - scenario->objective_arg_2 = s6Info->objective_arg_2; - scenario->objective_arg_3 = s6Info->objective_arg_3; - strcpy(scenario->name, s6Info->name); - strcpy(scenario->details, s6Info->details); + scenario->category = s6Info.category; + scenario->objective_type = s6Info.objective_type; + scenario->objective_arg_1 = s6Info.objective_arg_1; + scenario->objective_arg_2 = s6Info.objective_arg_2; + scenario->objective_arg_3 = s6Info.objective_arg_3; + strcpy(scenario->name, s6Info.name); + strcpy(scenario->details, s6Info.details); } else { // Check if the scenario list buffer has room for another scenario if (gScenarioListCount >= gScenarioListCapacity) { @@ -122,13 +121,13 @@ static void scenario_list_add(const char *path) scenario->flags = SCENARIO_FLAGS_VISIBLE; if (RCT2_GLOBAL(0x009AA00C, uint8) & 1) scenario->flags |= SCENARIO_FLAGS_SIXFLAGS; - scenario->category = s6Info->category; - scenario->objective_type = s6Info->objective_type; - scenario->objective_arg_1 = s6Info->objective_arg_1; - scenario->objective_arg_2 = s6Info->objective_arg_2; - scenario->objective_arg_3 = s6Info->objective_arg_3; - strcpy(scenario->name, s6Info->name); - strcpy(scenario->details, s6Info->details); + scenario->category = s6Info.category; + scenario->objective_type = s6Info.objective_type; + scenario->objective_arg_1 = s6Info.objective_arg_1; + scenario->objective_arg_2 = s6Info.objective_arg_2; + scenario->objective_arg_3 = s6Info.objective_arg_3; + strcpy(scenario->name, s6Info.name); + strcpy(scenario->details, s6Info.details); } }