From b876591543854b480d8d93ff440437f0e5b41d1d Mon Sep 17 00:00:00 2001 From: zsilencer Date: Sat, 4 Jul 2015 22:36:25 -0600 Subject: [PATCH] use SDL_RWops for save games --- src/audio/mixer.cpp | 15 +--- src/editor.c | 40 ++++----- src/game.c | 91 ++++++++++---------- src/game.h | 5 +- src/object.c | 48 +++++------ src/object.h | 7 +- src/object_list.c | 4 +- src/platform/platform.h | 1 + src/platform/shared.c | 8 ++ src/scenario.c | 125 ++++++++++++---------------- src/scenario.h | 4 +- src/title.c | 12 ++- src/util/sawyercoding.c | 21 ++--- src/util/sawyercoding.h | 4 +- src/windows/editor_bottom_toolbar.c | 6 +- src/windows/loadsave.c | 45 ++++++---- 16 files changed, 229 insertions(+), 207 deletions(-) diff --git a/src/audio/mixer.cpp b/src/audio/mixer.cpp index 6f242f933b..0d6844b616 100644 --- a/src/audio/mixer.cpp +++ b/src/audio/mixer.cpp @@ -90,11 +90,8 @@ bool Source_Sample::LoadWAV(const char* filename) { log_verbose("Source_Sample::LoadWAV(%s)", filename); - utf8 utf8filename[512]; - win1252_to_utf8(utf8filename, filename, sizeof(utf8filename)); - Unload(); - SDL_RWops* rw = SDL_RWFromFile(utf8filename, "rb"); + SDL_RWops* rw = platform_sdl_rwfromfile(filename, "rb"); if (rw == NULL) { log_verbose("Error loading %s", filename); return false; @@ -122,11 +119,8 @@ bool Source_Sample::LoadCSS1(const char* filename, unsigned int offset) { log_verbose("Source_Sample::LoadCSS1(%s, %d)", filename, offset); - utf8 utf8filename[512]; - win1252_to_utf8(utf8filename, filename, sizeof(utf8filename)); - Unload(); - SDL_RWops* rw = SDL_RWFromFile(utf8filename, "rb"); + SDL_RWops* rw = platform_sdl_rwfromfile(filename, "rb"); if (rw == NULL) { log_verbose("Unable to load %s", filename); return false; @@ -854,10 +848,7 @@ void* Mixer_Play_Music(int pathid, int loop, int streaming) if (streaming) { const char* filename = get_file_path(pathid); - utf8 utf8filename[512]; - win1252_to_utf8(utf8filename, filename, sizeof(utf8filename)); - - SDL_RWops* rw = SDL_RWFromFile(utf8filename, "rb"); + SDL_RWops* rw = platform_sdl_rwfromfile(filename, "rb"); if (rw == NULL) { return 0; } diff --git a/src/editor.c b/src/editor.c index 8c80024260..bb9bef8c2c 100644 --- a/src/editor.c +++ b/src/editor.c @@ -339,16 +339,16 @@ static int editor_load_landscape_from_sc4(const char *path) static int editor_read_s6(const char *path) { int i, j; - FILE *file; + SDL_RWops* rw; rct_s6_header *s6Header = (rct_s6_header*)0x009E34E4; rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; log_verbose("loading landscape, %s", path); - file = fopen(path, "rb"); - if (file != NULL) { - if (!sawyercoding_validate_checksum(file)) { - fclose(file); + rw = platform_sdl_rwfromfile(path, "rb"); + if (rw != NULL) { + if (!sawyercoding_validate_checksum(rw)) { + SDL_RWclose(rw); RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 255; RCT2_GLOBAL(RCT2_ADDRESS_ERROR_STRING_ID, uint16) = STR_FILE_CONTAINS_INVALID_DATA; @@ -357,10 +357,10 @@ static int editor_read_s6(const char *path) } // Read first chunk - sawyercoding_read_chunk(file, (uint8*)s6Header); + sawyercoding_read_chunk(rw, (uint8*)s6Header); if (s6Header->type == S6_TYPE_SCENARIO) { // Read second chunk - sawyercoding_read_chunk(file, (uint8*)s6Info); + sawyercoding_read_chunk(rw, (uint8*)s6Info); if (s6Info->var_000 == 255) s6Info->var_000 = 1; @@ -374,50 +374,50 @@ static int editor_read_s6(const char *path) if (s6Header->num_packed_objects > 0) { j = 0; for (i = 0; i < s6Header->num_packed_objects; i++) - j += object_load_packed(file); + j += object_load_packed(rw); if (j > 0) object_list_load(); } - uint8 load_success = object_read_and_load_entries(file); + uint8 load_success = object_read_and_load_entries(rw); // Read flags (16 bytes). Loads: // RCT2_ADDRESS_CURRENT_MONTH_YEAR // RCT2_ADDRESS_CURRENT_MONTH_TICKS // RCT2_ADDRESS_SCENARIO_TICKS - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_MONTH_YEAR); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_MONTH_YEAR); // Read map elements memset((void*)RCT2_ADDRESS_MAP_ELEMENTS, 0, MAX_MAP_ELEMENTS * sizeof(rct_map_element)); - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_MAP_ELEMENTS); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_MAP_ELEMENTS); // Read game data, including sprites - sawyercoding_read_chunk(file, (uint8*)0x010E63B8); + sawyercoding_read_chunk(rw, (uint8*)0x010E63B8); if (s6Header->type == S6_TYPE_SCENARIO) { // Read number of guests in park and something else - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_GUESTS_IN_PARK); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_GUESTS_IN_PARK); // Read ? - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_LAST_GUESTS_IN_PARK); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_LAST_GUESTS_IN_PARK); // Read park rating - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_PARK_RATING); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_PARK_RATING); // Read ? - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES); // Read ? - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_EXPENDITURE); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_EXPENDITURE); // Read ? - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_PARK_VALUE); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_PARK_VALUE); // Read more game data, including research items and rides - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_COMPLETED_COMPANY_VALUE); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_COMPLETED_COMPANY_VALUE); } - fclose(file); + SDL_RWclose(rw); if (!load_success){ log_error("failed to load all entries."); set_load_objects_fail_reason(); diff --git a/src/game.c b/src/game.c index 4c50bb68ae..f014533ff2 100644 --- a/src/game.c +++ b/src/game.c @@ -593,32 +593,12 @@ static void load_landscape() * * rct2: 0x00675E1B */ -int game_load_sv6(const char *path) +int game_load_sv6(SDL_RWops* rw) { - FILE *file; int i, j; - log_verbose("loading saved game, %s", path); - - strcpy((char*)0x0141EF68, path); - strcpy((char*)RCT2_ADDRESS_SAVED_GAMES_PATH_2, path); - - strcpy(gScenarioSaveName, path_get_filename(path)); - path_remove_extension(gScenarioSaveName); - - file = fopen(path, "rb"); - if (file == NULL) { - log_error("unable to open %s", path); - - RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 255; - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, uint16) = STR_FILE_CONTAINS_INVALID_DATA; - return 0; - } - - if (!sawyercoding_validate_checksum(file)) { - fclose(file); - - log_error("invalid checksum, %s", path); + if (!sawyercoding_validate_checksum(rw)) { + log_error("invalid checksum"); RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 255; RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, uint16) = STR_FILE_CONTAINS_INVALID_DATA; @@ -629,31 +609,29 @@ int game_load_sv6(const char *path) rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; // Read first chunk - sawyercoding_read_chunk(file, (uint8*)s6Header); + sawyercoding_read_chunk(rw, (uint8*)s6Header); if (s6Header->type == S6_TYPE_SAVEDGAME) { // Read packed objects if (s6Header->num_packed_objects > 0) { j = 0; for (i = 0; i < s6Header->num_packed_objects; i++) - j += object_load_packed(file); + j += object_load_packed(rw); if (j > 0) object_list_load(); } } - uint8 load_success = object_read_and_load_entries(file); + uint8 load_success = object_read_and_load_entries(rw); // Read flags (16 bytes) - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_MONTH_YEAR); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_MONTH_YEAR); // Read map elements memset((void*)RCT2_ADDRESS_MAP_ELEMENTS, 0, MAX_MAP_ELEMENTS * sizeof(rct_map_element)); - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_MAP_ELEMENTS); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_MAP_ELEMENTS); // Read game data, including sprites - sawyercoding_read_chunk(file, (uint8*)0x010E63B8); - - fclose(file); + sawyercoding_read_chunk(rw, (uint8*)0x010E63B8); if (!load_success){ set_load_objects_fail_reason(); @@ -683,12 +661,30 @@ int game_load_save(const char *path) { rct_window *mainWindow; - if (!game_load_sv6(path)) { - title_load(); - rct2_endupdate(); + log_verbose("loading saved game, %s", path); + + strcpy((char*)0x0141EF68, path); + strcpy((char*)RCT2_ADDRESS_SAVED_GAMES_PATH_2, path); + + strcpy(gScenarioSaveName, path_get_filename(path)); + path_remove_extension(gScenarioSaveName); + + SDL_RWops* rw = platform_sdl_rwfromfile(path, "rb"); + if (rw == NULL) { + log_error("unable to open %s", path); + RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 255; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, uint16) = STR_FILE_CONTAINS_INVALID_DATA; return 0; } + if (!game_load_sv6(rw)) { + title_load(); + rct2_endupdate(); + SDL_RWclose(rw); + return 0; + } + SDL_RWclose(rw); + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) = SCREEN_FLAGS_PLAYING; viewport_init_all(); game_create_windows(); @@ -803,7 +799,7 @@ static int show_save_game_dialog(char *resultPath) return result; } -char save_game() +int save_game() { window_loadsave_open(LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME, gScenarioSaveName); return 0; @@ -818,13 +814,17 @@ char save_game() // Ensure path has .SV6 extension path_set_extension(path, ".SV6"); - if (scenario_save(path, gConfigGeneral.save_plugin_data ? 1 : 0)) { - game_do_command(0, 1047, 0, -1, GAME_COMMAND_SET_RIDE_APPEARANCE, 0, 0); - gfx_invalidate_screen(); - return 1; - } else { - return 0; + SDL_RWops* rw = platform_sdl_rwfromfile(path, "wb+"); + if (rw != NULL) { + int success = scenario_save(rw, gConfigGeneral.save_plugin_data ? 1 : 0); + SDL_RWclose(rw); + if (success) { + game_do_command(0, 1047, 0, -1, GAME_COMMAND_SET_RIDE_APPEARANCE, 0, 0); + gfx_invalidate_screen(); + return 1; + } } + return 0; } void game_autosave() @@ -834,7 +834,14 @@ void game_autosave() platform_get_user_directory(path, "save"); strcat(path, "autosave.sv6"); - scenario_save(path, 0x80000000); + strcpy(gScenarioSaveName, path_get_filename(path)); + path_remove_extension(gScenarioSaveName); + + SDL_RWops* rw = platform_sdl_rwfromfile(path, "wb+"); + if (rw != NULL) { + scenario_save(rw, 0x80000000); + SDL_RWclose(rw); + } } /** diff --git a/src/game.h b/src/game.h index e46e48c8f5..5a2911113b 100644 --- a/src/game.h +++ b/src/game.h @@ -22,6 +22,7 @@ #define _GAME_H_ #include "common.h" +#include "platform/platform.h" enum GAME_COMMAND { GAME_COMMAND_SET_RIDE_APPEARANCE, @@ -107,11 +108,11 @@ void game_increase_game_speed(); void game_reduce_game_speed(); void game_load_or_quit_no_save_prompt(); -int game_load_sv6(const char *path); +int game_load_sv6(SDL_RWops* rw); int game_load_save(const char *path); void game_pause_toggle(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); void pause_toggle(); -char save_game(); +int save_game(); void rct2_exit(); void rct2_exit_reason(rct_string_id title, rct_string_id body); void game_autosave(); diff --git a/src/object.c b/src/object.c index 2056562cff..2d44166568 100644 --- a/src/object.c +++ b/src/object.c @@ -55,19 +55,19 @@ int object_load_file(int groupIndex, const rct_object_entry *entry, int* chunkSi uint8 objectType; rct_object_entry openedEntry; char path[260]; - FILE *file; + SDL_RWops* rw; subsitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), (char*)installedObject + 16); log_verbose("loading object, %s", path); - file = fopen(path, "rb"); - if (file == NULL) + rw = platform_sdl_rwfromfile(path, "rb"); + if (rw == NULL) return 0; - fread(&openedEntry, sizeof(rct_object_entry), 1, file); + SDL_RWread(rw, &openedEntry, sizeof(rct_object_entry), 1); if (!object_entry_compare(&openedEntry, entry)) { - fclose(file); + SDL_RWclose(rw); return 0; } @@ -82,14 +82,14 @@ int object_load_file(int groupIndex, const rct_object_entry *entry, int* chunkSi if (*chunkSize == 0xFFFFFFFF) { chunk = rct2_malloc(0x600000); - *chunkSize = sawyercoding_read_chunk(file, chunk); + *chunkSize = sawyercoding_read_chunk(rw, chunk); chunk = rct2_realloc(chunk, *chunkSize); } else { chunk = rct2_malloc(*chunkSize); - *chunkSize = sawyercoding_read_chunk(file, chunk); + *chunkSize = sawyercoding_read_chunk(rw, chunk); } - fclose(file); + SDL_RWclose(rw); @@ -177,7 +177,7 @@ int object_load(int groupIndex, rct_object_entry *entry, int* chunkSize) * ebx : file * ebp : entry */ -int write_object_file(FILE *file, rct_object_entry* entry){ +int write_object_file(SDL_RWops *rw, rct_object_entry* entry){ uint8 entryGroupIndex = 0, type = 0; uint8* chunk = 0; @@ -201,7 +201,7 @@ int write_object_file(FILE *file, rct_object_entry* entry){ chunkHeader.length = installed_entry->chunk_size; size_dst += sawyercoding_write_chunk_buffer(dst_buffer + sizeof(rct_object_entry), chunk, chunkHeader); - fwrite(dst_buffer, 1, size_dst, file); + SDL_RWwrite(rw, dst_buffer, 1, size_dst); free(dst_buffer); return 1; @@ -211,16 +211,16 @@ int write_object_file(FILE *file, rct_object_entry* entry){ * * rct2: 0x006AA2B7 */ -int object_load_packed(FILE *file) +int object_load_packed(SDL_RWops* rw) { object_unload_all(); rct_object_entry entry; - fread(&entry, 16, 1, file); + SDL_RWread(rw, &entry, 16, 1); uint8* chunk = rct2_malloc(0x600000); - uint32 chunkSize = sawyercoding_read_chunk(file, chunk); + uint32 chunkSize = sawyercoding_read_chunk(rw, chunk); chunk = rct2_realloc(chunk, chunkSize); if (chunk == NULL){ @@ -315,11 +315,11 @@ int object_load_packed(FILE *file) } // Actually write the object to the file - FILE* obj_file = fopen(path, "wb"); - if (obj_file){ - uint8 result = write_object_file(obj_file, &entry); + SDL_RWops* rw_out = platform_sdl_rwfromfile(path, "wb"); + if (rw_out != NULL){ + uint8 result = write_object_file(rw_out, &entry); - fclose(obj_file); + SDL_RWclose(rw_out); object_unload_all(); return result; @@ -1514,9 +1514,9 @@ int object_get_scenario_text(rct_object_entry *entry) subsitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), objectPath); rct_object_entry openedEntry; - FILE *file = fopen(path, "rb"); - if (file != NULL) { - fread(&openedEntry, sizeof(rct_object_entry), 1, file); + SDL_RWops* rw = platform_sdl_rwfromfile(path, "rb"); + if (rw != NULL) { + SDL_RWread(rw, &openedEntry, sizeof(rct_object_entry), 1); if (object_entry_compare(&openedEntry, entry)) { // Skip over the object entry @@ -1530,14 +1530,14 @@ int object_get_scenario_text(rct_object_entry *entry) char *chunk; if (chunkSize == 0xFFFFFFFF) { chunk = malloc(0x600000); - chunkSize = sawyercoding_read_chunk(file, chunk); + chunkSize = sawyercoding_read_chunk(rw, chunk); chunk = realloc(chunk, chunkSize); } else { chunk = malloc(chunkSize); - sawyercoding_read_chunk(file, chunk); + sawyercoding_read_chunk(rw, chunk); } - fclose(file); + SDL_RWclose(rw); // Calculate and check checksum if (object_calculate_checksum(&openedEntry, chunk, chunkSize) != openedEntry.checksum) { @@ -1578,7 +1578,7 @@ int object_get_scenario_text(rct_object_entry *entry) return 1; } log_error("Opened object didn't match."); - fclose(file); + SDL_RWclose(rw); return 0; } log_error("File failed to open."); diff --git a/src/object.h b/src/object.h index 7d80e1841a..0294c98865 100644 --- a/src/object.h +++ b/src/object.h @@ -22,6 +22,7 @@ #define _OBJECT_H_ #include "common.h" +#include "platform/platform.h" // First 0xF of rct_object_entry->flags typedef enum{ @@ -94,8 +95,8 @@ extern rct_object_entry_group object_entry_groups[]; int object_load_entry(const char *path, rct_object_entry *outEntry); void object_list_load(); void set_load_objects_fail_reason(); -int object_read_and_load_entries(FILE *file); -int object_load_packed(FILE *file); +int object_read_and_load_entries(SDL_RWops* rw); +int object_load_packed(SDL_RWops* rw); void object_unload_all(); int check_object_entry(rct_object_entry *entry); @@ -109,7 +110,7 @@ int object_entry_compare(const rct_object_entry *a, const rct_object_entry *b); int object_calculate_checksum(const rct_object_entry *entry, const char *data, int dataLength); int object_paint(int type, int eax, int ebx, int ecx, int edx, int esi, int edi, int ebp); rct_object_entry *object_get_next(rct_object_entry *entry); -int write_object_file(FILE *file, rct_object_entry* entry); +int write_object_file(SDL_RWops* rw, rct_object_entry* entry); void reset_loaded_objects(); int find_object_in_entry_group(rct_object_entry* entry, uint8* entry_type, uint8* entry_index); void object_create_identifier_name(uint8* string_buffer, rct_object_entry* object); diff --git a/src/object_list.c b/src/object_list.c index de0ac3f4c7..8283f74139 100644 --- a/src/object_list.c +++ b/src/object_list.c @@ -518,7 +518,7 @@ void set_load_objects_fail_reason(){ * * rct2: 0x006AA0C6 */ -int object_read_and_load_entries(FILE *file) +int object_read_and_load_entries(SDL_RWops* rw) { object_unload_all(); @@ -529,7 +529,7 @@ int object_read_and_load_entries(FILE *file) // Read all the object entries entries = malloc(OBJECT_ENTRY_COUNT * sizeof(rct_object_entry)); - sawyercoding_read_chunk(file, (uint8*)entries); + sawyercoding_read_chunk(rw, (uint8*)entries); uint8 load_fail = 0; // Load each object diff --git a/src/platform/platform.h b/src/platform/platform.h index 3a6c7c6ba9..b7f5e0feb7 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -82,6 +82,7 @@ void platform_process_messages(); int platform_scancode_to_rct_keycode(int sdl_key); void platform_start_text_input(char* buffer, int max_length); void platform_stop_text_input(); +SDL_RWops* platform_sdl_rwfromfile(const char* filename, const char* mode); // Platform specific definitions char platform_get_path_separator(); diff --git a/src/platform/shared.c b/src/platform/shared.c index 8531d0a897..d0e33ae639 100644 --- a/src/platform/shared.c +++ b/src/platform/shared.c @@ -28,6 +28,7 @@ #include "../interface/keyboard_shortcut.h" #include "../interface/window.h" #include "../input.h" +#include "../localisation/localisation.h" #include "../openrct2.h" #include "platform.h" @@ -605,6 +606,13 @@ void platform_stop_text_input() gTextInput = NULL; } +SDL_RWops* platform_sdl_rwfromfile(const char* filename, const char* mode) +{ + utf8 utf8filename[512]; + win1252_to_utf8(utf8filename, filename, sizeof(utf8filename)); + return SDL_RWFromFile(utf8filename, mode); +} + static void platform_unload_cursors() { for (int i = 0; i < CURSOR_COUNT; i++) diff --git a/src/scenario.c b/src/scenario.c index e15ed1911b..49f1fe1275 100644 --- a/src/scenario.c +++ b/src/scenario.c @@ -58,18 +58,18 @@ static void scenario_objective_check(); */ int scenario_load_basic(const char *path, rct_s6_header *header, rct_s6_info *info) { - FILE *file; + SDL_RWops* rw; log_verbose("loading scenario details, %s", path); - file = fopen(path, "rb"); - if (file != NULL) { + rw = platform_sdl_rwfromfile(path, "rb"); + if (rw != NULL) { // Read first chunk - sawyercoding_read_chunk(file, (uint8*)header); + sawyercoding_read_chunk(rw, (uint8*)header); if (header->type == S6_TYPE_SCENARIO) { // Read second chunk - sawyercoding_read_chunk(file, (uint8*)info); - fclose(file); + sawyercoding_read_chunk(rw, (uint8*)info); + SDL_RWclose(rw); RCT2_GLOBAL(0x009AA00C, uint8) = 0; // Checks for a scenario string object (possibly for localisation) @@ -84,7 +84,7 @@ int scenario_load_basic(const char *path, rct_s6_header *header, rct_s6_info *in } return 1; } - fclose(file); + SDL_RWclose(rw); } log_error("invalid scenario, %s", path); @@ -102,15 +102,15 @@ int scenario_load(const char *path) { log_verbose("loading scenario, %s", path); - FILE *file; + SDL_RWops* rw; int i, j; rct_s6_header *s6Header = (rct_s6_header*)0x009E34E4; rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; - file = fopen(path, "rb"); - if (file != NULL) { - if (!sawyercoding_validate_checksum(file)) { - fclose(file); + rw = platform_sdl_rwfromfile(path, "rb"); + if (rw != NULL) { + if (!sawyercoding_validate_checksum(rw)) { + SDL_RWclose(rw); RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 255; RCT2_GLOBAL(RCT2_ADDRESS_ERROR_STRING_ID, uint16) = STR_FILE_CONTAINS_INVALID_DATA; @@ -119,57 +119,57 @@ int scenario_load(const char *path) } // Read first chunk - sawyercoding_read_chunk(file, (uint8*)s6Header); + sawyercoding_read_chunk(rw, (uint8*)s6Header); if (s6Header->type == S6_TYPE_SCENARIO) { // Read second chunk - sawyercoding_read_chunk(file, (uint8*)s6Info); + sawyercoding_read_chunk(rw, (uint8*)s6Info); // Read packed objects if (s6Header->num_packed_objects > 0) { j = 0; for (i = 0; i < s6Header->num_packed_objects; i++) - j += object_load_packed(file); + j += object_load_packed(rw); if (j > 0) object_list_load(); } - uint8 load_success = object_read_and_load_entries(file); + uint8 load_success = object_read_and_load_entries(rw); // Read flags (16 bytes). Loads: // RCT2_ADDRESS_CURRENT_MONTH_YEAR // RCT2_ADDRESS_CURRENT_MONTH_TICKS // RCT2_ADDRESS_SCENARIO_TICKS - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_MONTH_YEAR); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_MONTH_YEAR); // Read map elements memset((void*)RCT2_ADDRESS_MAP_ELEMENTS, 0, MAX_MAP_ELEMENTS * sizeof(rct_map_element)); - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_MAP_ELEMENTS); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_MAP_ELEMENTS); // Read game data, including sprites - sawyercoding_read_chunk(file, (uint8*)0x010E63B8); + sawyercoding_read_chunk(rw, (uint8*)0x010E63B8); // Read number of guests in park and something else - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_GUESTS_IN_PARK); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_GUESTS_IN_PARK); // Read ? - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_LAST_GUESTS_IN_PARK); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_LAST_GUESTS_IN_PARK); // Read park rating - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_PARK_RATING); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_PARK_RATING); // Read ? - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES); // Read ? - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_EXPENDITURE); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_EXPENDITURE); // Read ? - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_PARK_VALUE); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_PARK_VALUE); // Read more game data, including research items and rides - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_COMPLETED_COMPANY_VALUE); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_COMPLETED_COMPANY_VALUE); - fclose(file); + SDL_RWclose(rw); if (!load_success){ log_error("failed to load all entries."); set_load_objects_fail_reason(); @@ -183,7 +183,7 @@ int scenario_load(const char *path) return 1; } - fclose(file); + SDL_RWclose(rw); } log_error("failed to find scenario file."); @@ -745,7 +745,7 @@ int scenario_get_num_packed_objects_to_write() * * rct2: 0x006AA26E */ -int scenario_write_packed_objects(FILE *file) +int scenario_write_packed_objects(SDL_RWops* rw) { int i; rct_object_entry_extended *entry = (rct_object_entry_extended*)0x00F3F03C; @@ -753,7 +753,7 @@ int scenario_write_packed_objects(FILE *file) if (RCT2_ADDRESS(0x009ACFA4, uint32)[i] == 0xFFFFFFFF || (entry->flags & 0xF0)) continue; - if (!write_object_file(file, (rct_object_entry*)entry)) + if (!write_object_file(rw, (rct_object_entry*)entry)) return 0; } @@ -878,21 +878,16 @@ static scenario_fix_ghosts(rct_s6_data *s6) * rct2: 0x006754F5 * @param flags bit 0: pack objects, 1: save as scenario */ -int scenario_save(char *path, int flags) +int scenario_save(SDL_RWops* rw, int flags) { rct_window *w; rct_viewport *viewport; int viewX, viewY, viewZoom, viewRotation; - if (strcmp(path_get_filename(path), "autosave.sv6")) { - strcpy(gScenarioSaveName, path_get_filename(path)); - path_remove_extension(gScenarioSaveName); - } - if (flags & 2) - log_verbose("saving scenario, %s", path); + log_verbose("saving scenario"); else - log_verbose("saving game, %s", path); + log_verbose("saving game"); if (!(flags & 0x80000000)) @@ -949,7 +944,7 @@ int scenario_save(char *path, int flags) memcpy(&s6->dword_010E63B8, (void*)0x010E63B8, 0x2E8570); scenario_fix_ghosts(s6); - scenario_save_s6(path, s6); + scenario_save_s6(rw, s6); free(s6); @@ -961,25 +956,17 @@ int scenario_save(char *path, int flags) return 1; } -bool scenario_save_s6(char *path, rct_s6_data *s6) +bool scenario_save_s6(SDL_RWops* rw, rct_s6_data *s6) { - FILE *file; char *buffer; sawyercoding_chunk_header chunkHeader; int encodedLength; long fileSize; uint32 checksum; - file = fopen(path, "wb+"); - if (file == NULL) { - log_error("Unable to write to %s", path); - return false; - } - buffer = malloc(0x600000); if (buffer == NULL) { log_error("Unable to allocate enough space for a write buffer."); - fclose(file); return false; } @@ -987,21 +974,20 @@ bool scenario_save_s6(char *path, rct_s6_data *s6) chunkHeader.encoding = CHUNK_ENCODING_ROTATE; chunkHeader.length = sizeof(rct_s6_header); encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->header, chunkHeader); - fwrite(buffer, encodedLength, 1, file); + SDL_RWwrite(rw, buffer, encodedLength, 1); // 1: Write scenario info chunk if (s6->header.type == S6_TYPE_SCENARIO) { chunkHeader.encoding = CHUNK_ENCODING_ROTATE; chunkHeader.length = sizeof(rct_s6_info); encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->info, chunkHeader); - fwrite(buffer, encodedLength, 1, file); + SDL_RWwrite(rw, buffer, encodedLength, 1); } // 2: Write packed objects if (s6->header.num_packed_objects > 0) { - if (!scenario_write_packed_objects(file)) { + if (!scenario_write_packed_objects(rw)) { free(buffer); - fclose(file); return false; } } @@ -1010,92 +996,91 @@ bool scenario_save_s6(char *path, rct_s6_data *s6) chunkHeader.encoding = CHUNK_ENCODING_ROTATE; chunkHeader.length = 721 * sizeof(rct_object_entry); encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)s6->objects, chunkHeader); - fwrite(buffer, encodedLength, 1, file); + SDL_RWwrite(rw, buffer, encodedLength, 1); // 4: Misc fields (data, rand...) chunk chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 16; encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->elapsed_months, chunkHeader); - fwrite(buffer, encodedLength, 1, file); + SDL_RWwrite(rw, buffer, encodedLength, 1); // 5: Map elements + sprites and other fields chunk chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 0x180000; encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)s6->map_elements, chunkHeader); - fwrite(buffer, encodedLength, 1, file); + SDL_RWwrite(rw, buffer, encodedLength, 1); if (s6->header.type == S6_TYPE_SCENARIO) { // 6: chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 0x27104C; encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->dword_010E63B8, chunkHeader); - fwrite(buffer, encodedLength, 1, file); + SDL_RWwrite(rw, buffer, encodedLength, 1); // 7: chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 4; encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->guests_in_park, chunkHeader); - fwrite(buffer, encodedLength, 1, file); + SDL_RWwrite(rw, buffer, encodedLength, 1); // 8: chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 8; encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->last_guests_in_park, chunkHeader); - fwrite(buffer, encodedLength, 1, file); + SDL_RWwrite(rw, buffer, encodedLength, 1); // 9: chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 2; encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->park_rating, chunkHeader); - fwrite(buffer, encodedLength, 1, file); + SDL_RWwrite(rw, buffer, encodedLength, 1); // 10: chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 1082; encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->active_research_types, chunkHeader); - fwrite(buffer, encodedLength, 1, file); + SDL_RWwrite(rw, buffer, encodedLength, 1); // 11: chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 16; encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->current_expenditure, chunkHeader); - fwrite(buffer, encodedLength, 1, file); + SDL_RWwrite(rw, buffer, encodedLength, 1); // 12: chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 4; encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->park_value, chunkHeader); - fwrite(buffer, encodedLength, 1, file); + SDL_RWwrite(rw, buffer, encodedLength, 1); // 13: chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 0x761E8; encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->completed_company_value, chunkHeader); - fwrite(buffer, encodedLength, 1, file); + SDL_RWwrite(rw, buffer, encodedLength, 1); } else { // 6: Everything else... chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 0x2E8570; encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->dword_010E63B8, chunkHeader); - fwrite(buffer, encodedLength, 1, file); + SDL_RWwrite(rw, buffer, encodedLength, 1); } free(buffer); // Determine number of bytes written - fileSize = ftell(file); - fseek(file, 0, SEEK_SET); + fileSize = (long)SDL_RWtell(rw); + SDL_RWseek(rw, 0, RW_SEEK_SET); // Read all written bytes back into a single buffer buffer = malloc(fileSize); - fread(buffer, fileSize, 1, file); + SDL_RWread(rw, buffer, fileSize, 1); checksum = sawyercoding_calculate_checksum(buffer, fileSize); free(buffer); // Append the checksum - fseek(file, fileSize, SEEK_SET); - fwrite(&checksum, sizeof(uint32), 1, file); - fclose(file); + SDL_RWseek(rw, fileSize, RW_SEEK_SET); + SDL_RWwrite(rw, &checksum, sizeof(uint32), 1); return true; } diff --git a/src/scenario.h b/src/scenario.h index 7fc1878d1a..5f4f842221 100644 --- a/src/scenario.h +++ b/src/scenario.h @@ -425,8 +425,8 @@ void scenario_update(); unsigned int scenario_rand(); unsigned int scenario_rand_max(unsigned int max); int scenario_prepare_for_save(); -int scenario_save(char *path, int flags); -bool scenario_save_s6(char *path, rct_s6_data *s6); +int scenario_save(SDL_RWops* rw, int flags); +bool scenario_save_s6(SDL_RWops* rw, rct_s6_data *s6); void scenario_set_filename(const char *value); void scenario_failure(); void scenario_success(); diff --git a/src/title.c b/src/title.c index 6fe269bd0b..79148ac83c 100644 --- a/src/title.c +++ b/src/title.c @@ -168,9 +168,15 @@ static int title_load_park(const char *path) rct_window* w; int successfulLoad; - successfulLoad = _strcmpi(path_get_extension(path), ".sv6") == 0 ? - game_load_sv6(path) : - scenario_load(path); + if (_strcmpi(path_get_extension(path), ".sv6") == 0) { + SDL_RWops* rw = platform_sdl_rwfromfile(path, "rb"); + if (rw != NULL) { + successfulLoad = game_load_sv6(rw); + SDL_RWclose(rw); + } + } else { + successfulLoad = scenario_load(path); + } if (!successfulLoad) return 0; diff --git a/src/util/sawyercoding.c b/src/util/sawyercoding.c index f11ddeb7cb..5f75cc2480 100644 --- a/src/util/sawyercoding.c +++ b/src/util/sawyercoding.c @@ -19,6 +19,7 @@ *****************************************************************************/ #include "../addresses.h" +#include "../platform/platform.h" #include "sawyercoding.h" static int decode_chunk_rle(uint8* src_buffer, uint8* dst_buffer, int length); @@ -42,24 +43,24 @@ uint32 sawyercoding_calculate_checksum(uint8* buffer, uint32 length) * * rct2: 0x00676FD2 */ -int sawyercoding_validate_checksum(FILE *file) +int sawyercoding_validate_checksum(SDL_RWops* rw) { uint32 i, checksum, fileChecksum, dataSize, bufferSize; uint8 buffer[1024]; // Get data size - fseek(file, 0, SEEK_END); - dataSize = ftell(file); + SDL_RWseek(rw, 0, RW_SEEK_END); + dataSize = (uint32)SDL_RWtell(rw); if (dataSize < 8) return 0; dataSize -= 4; // Calculate checksum - fseek(file, 0, SEEK_SET); + SDL_RWseek(rw, 0, RW_SEEK_SET); checksum = 0; do { bufferSize = min(dataSize, 1024); - if (fread(buffer, bufferSize, 1, file) != 1) + if (SDL_RWread(rw, buffer, bufferSize, 1) != 1) return 0; for (i = 0; i < bufferSize; i++) @@ -68,11 +69,11 @@ int sawyercoding_validate_checksum(FILE *file) } while (dataSize != 0); // Read file checksum - if (fread(&fileChecksum, sizeof(fileChecksum), 1, file) != 1) + if (SDL_RWread(rw, &fileChecksum, sizeof(fileChecksum), 1) != 1) return 0; // Reset file position - fseek(file, 0, SEEK_SET); + SDL_RWseek(rw, 0, RW_SEEK_SET); // Validate return checksum == fileChecksum; @@ -83,12 +84,12 @@ int sawyercoding_validate_checksum(FILE *file) * rct2: 0x0067685F * buffer (esi) */ -int sawyercoding_read_chunk(FILE *file, uint8 *buffer) +int sawyercoding_read_chunk(SDL_RWops* rw, uint8 *buffer) { sawyercoding_chunk_header chunkHeader; // Read chunk header - if (fread(&chunkHeader, sizeof(sawyercoding_chunk_header), 1, file) != 1) { + if (SDL_RWread(rw, &chunkHeader, sizeof(sawyercoding_chunk_header), 1) != 1) { log_error("Unable to read chunk header!"); return -1; } @@ -96,7 +97,7 @@ int sawyercoding_read_chunk(FILE *file, uint8 *buffer) uint8* src_buffer = malloc(chunkHeader.length); // Read chunk data - if (fread(src_buffer, chunkHeader.length, 1, file) != 1) { + if (SDL_RWread(rw, src_buffer, chunkHeader.length, 1) != 1) { free(src_buffer); log_error("Unable to read chunk data!"); return -1; diff --git a/src/util/sawyercoding.h b/src/util/sawyercoding.h index a1c702b334..f12e589ec6 100644 --- a/src/util/sawyercoding.h +++ b/src/util/sawyercoding.h @@ -47,9 +47,9 @@ enum { FILE_TYPE_SC4 = (2 << 2) }; -int sawyercoding_validate_checksum(FILE *file); +int sawyercoding_validate_checksum(SDL_RWops* rw); uint32 sawyercoding_calculate_checksum(uint8* buffer, uint32 length); -int sawyercoding_read_chunk(FILE *file, uint8 *buffer); +int sawyercoding_read_chunk(SDL_RWops* rw, uint8 *buffer); int sawyercoding_write_chunk_buffer(uint8 *dst_file, uint8* buffer, sawyercoding_chunk_header chunkHeader); int sawyercoding_decode_sv4(char *src, char *dst, int length); int sawyercoding_decode_sc4(char *src, char *dst, int length); diff --git a/src/windows/editor_bottom_toolbar.c b/src/windows/editor_bottom_toolbar.c index 5a3a4dbe38..e6d7614c7e 100644 --- a/src/windows/editor_bottom_toolbar.c +++ b/src/windows/editor_bottom_toolbar.c @@ -377,7 +377,11 @@ void window_editor_bottom_toolbar_jump_forward_to_save_scenario() // Save the scenario parkFlagsBackup = RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32); RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_18; - success = scenario_save(path, gConfigGeneral.save_plugin_data ? 3 : 2); + SDL_RWops* rw = platform_sdl_rwfromfile(path, "wb+"); + if (rw != NULL) { + success = scenario_save(rw, gConfigGeneral.save_plugin_data ? 3 : 2); + SDL_RWclose(rw); + } RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) = parkFlagsBackup; if (success) { diff --git a/src/windows/loadsave.c b/src/windows/loadsave.c index 55da869e33..baa9ae3273 100644 --- a/src/windows/loadsave.c +++ b/src/windows/loadsave.c @@ -724,6 +724,7 @@ static void window_loadsave_populate_list(int includeNewItem, bool browsable, co static void window_loadsave_select(rct_window *w, const char *path) { + SDL_RWops* rw; switch (_loadsaveType) { case (LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME) : if (gLoadSaveTitleSequenceSave) { @@ -752,13 +753,19 @@ static void window_loadsave_select(rct_window *w, const char *path) } break; case (LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME) : - if (scenario_save((char*)path, gConfigGeneral.save_plugin_data ? 1 : 0)) { - window_close(w); + rw = platform_sdl_rwfromfile(path, "wb+"); + if (rw != NULL) { + int success = scenario_save(rw, gConfigGeneral.save_plugin_data ? 1 : 0); + SDL_RWclose(rw); + if (success) { + window_close(w); - game_do_command(0, 1047, 0, -1, GAME_COMMAND_SET_RIDE_APPEARANCE, 0, 0); - gfx_invalidate_screen(); - } - else { + game_do_command(0, 1047, 0, -1, GAME_COMMAND_SET_RIDE_APPEARANCE, 0, 0); + gfx_invalidate_screen(); + } else { + window_error_open(STR_SAVE_GAME, 1047); + } + } else { window_error_open(STR_SAVE_GAME, 1047); } break; @@ -774,11 +781,17 @@ static void window_loadsave_select(rct_window *w, const char *path) } break; case (LOADSAVETYPE_SAVE | LOADSAVETYPE_LANDSCAPE) : - if (scenario_save((char*)path, gConfigGeneral.save_plugin_data ? 3 : 2)) { - window_close(w); - gfx_invalidate_screen(); - } - else { + rw = platform_sdl_rwfromfile(path, "wb+"); + if (rw != NULL) { + int success = scenario_save(rw, gConfigGeneral.save_plugin_data ? 3 : 2); + SDL_RWclose(rw); + if (success) { + window_close(w); + gfx_invalidate_screen(); + } else { + window_error_open(STR_SAVE_LANDSCAPE, 1049); + } + } else { window_error_open(STR_SAVE_LANDSCAPE, 1049); } break; @@ -788,14 +801,18 @@ static void window_loadsave_select(rct_window *w, const char *path) int parkFlagsBackup = RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32); RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_18; s6Info->var_000 = 255; - int success = scenario_save((char*)path, gConfigGeneral.save_plugin_data ? 3 : 2); + rw = platform_sdl_rwfromfile(path, "wb+"); + int success = 0; + if (rw != NULL) { + success = scenario_save(rw, gConfigGeneral.save_plugin_data ? 3 : 2); + SDL_RWclose(rw); + } RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) = parkFlagsBackup; if (success) { window_close(w); title_load(); - } - else { + } else { window_error_open(STR_SAVE_SCENARIO, STR_SCENARIO_SAVE_FAILED); s6Info->var_000 = 4; }