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);
}
}