diff --git a/src/openrct2/ParkImporter.cpp b/src/openrct2/ParkImporter.cpp index 9e1ca85930..72d5bbd41a 100644 --- a/src/openrct2/ParkImporter.cpp +++ b/src/openrct2/ParkImporter.cpp @@ -14,22 +14,66 @@ *****************************************************************************/ #pragma endregion +#include #include "core/Path.hpp" #include "core/String.hpp" #include "ParkImporter.h" -IParkImporter * CreateParkImporterForPath(const std::string &path) +namespace ParkImporter { - IParkImporter * parkImporter = nullptr; - std::string extension = Path::GetExtension(path); - if (String::Equals(extension, ".sc4", true) || - String::Equals(extension, ".sv4", true)) + IParkImporter * Create(const std::string &hintPath) { - parkImporter = CreateS4Importer(); + IParkImporter * parkImporter = nullptr; + std::string extension = Path::GetExtension(hintPath); + if (ExtensionIsRCT1(extension)) + { + parkImporter = CreateS4(); + } + else + { + parkImporter = CreateS6(); + } + return parkImporter; } - else + + bool ExtensionIsRCT1(const std::string &extension) { - parkImporter = CreateS6Importer(); + if (String::Equals(extension, ".sc4", true) || + String::Equals(extension, ".sv4", true)) + { + return true; + } + return false; + } + + bool ExtensionIsScenario(const std::string &extension) + { + if (String::Equals(extension, ".sc4", true) || + String::Equals(extension, ".sc6", true)) + { + return true; + } + return false; + } +} + +extern "C" +{ + void park_importer_load_from_stream(void * stream_c, const utf8 * hintPath_c) + { + IStream * stream = (IStream *)stream_c; + std::string hintPath = String::ToStd(hintPath_c); + + std::string extension = Path::GetExtension(hintPath); + bool isScenario = ParkImporter::ExtensionIsScenario(hintPath); + + auto parkImporter = std::unique_ptr(ParkImporter::Create(hintPath)); + parkImporter->LoadFromStream((IStream *)stream, isScenario); + parkImporter->Import(); + } + + bool park_importer_extension_is_scenario(const utf8 * extension) + { + return ParkImporter::ExtensionIsScenario(String::ToStd(extension)); } - return parkImporter; } diff --git a/src/openrct2/ParkImporter.h b/src/openrct2/ParkImporter.h index 1d5cac6938..eb9957fa46 100644 --- a/src/openrct2/ParkImporter.h +++ b/src/openrct2/ParkImporter.h @@ -16,8 +16,11 @@ #pragma once -#include #include "common.h" + +#ifdef __cplusplus + +#include #include "scenario/ScenarioRepository.h" interface IStream; @@ -37,6 +40,25 @@ public: virtual bool GetDetails(scenario_index_entry * dst) abstract; }; -IParkImporter * CreateS4Importer(); -IParkImporter * CreateS6Importer(); -IParkImporter * CreateParkImporterForPath(const std::string &path); +namespace ParkImporter +{ + IParkImporter * Create(const std::string &hintPath); + IParkImporter * CreateS4(); + IParkImporter * CreateS6(); + + bool ExtensionIsRCT1(const std::string &extension); + bool ExtensionIsScenario(const std::string &extension); +} + +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + void park_importer_load_from_stream(void * stream, const utf8 * hintPath); + bool park_importer_extension_is_scenario(const utf8 * extension); + +#ifdef __cplusplus +} +#endif diff --git a/src/openrct2/cmdline/ConvertCommand.cpp b/src/openrct2/cmdline/ConvertCommand.cpp index 8ea4ca937e..9baecaee3b 100644 --- a/src/openrct2/cmdline/ConvertCommand.cpp +++ b/src/openrct2/cmdline/ConvertCommand.cpp @@ -14,6 +14,7 @@ *****************************************************************************/ #pragma endregion +#include #include "../common.h" #include "../core/Console.hpp" #include "../core/Exception.hpp" @@ -109,9 +110,9 @@ exitcode_t CommandLine::HandleCommandConvert(CommandLineArgEnumerator * enumerat if (sourceFileType == FILE_EXTENSION_SV4 || sourceFileType == FILE_EXTENSION_SC4) { - auto s4Importer = CreateS4Importer(); try { + auto s4Importer = std::unique_ptr(ParkImporter::CreateS4()); if (sourceFileType == FILE_EXTENSION_SC4) { s4Importer->LoadScenario(sourcePath); diff --git a/src/openrct2/core/Zip.cpp b/src/openrct2/core/Zip.cpp index cb98bb4851..161c22116e 100644 --- a/src/openrct2/core/Zip.cpp +++ b/src/openrct2/core/Zip.cpp @@ -16,6 +16,7 @@ #include #include "IStream.hpp" +#include "MemoryStream.h" #include "Zip.h" class ZipArchive final : public IZipArchive @@ -99,6 +100,18 @@ public: return data; } + IStream * GetFileStream(const utf8 * path) const override + { + IStream * stream = nullptr; + size_t dataSize; + void * data = GetFileData(path, &dataSize); + if (data != nullptr) + { + stream = new MemoryStream(data, dataSize, MEMORY_ACCESS_READ | MEMORY_ACCESS_OWNER); + } + return stream; + } + void SetFileData(const utf8 * path, void * data, size_t dataSize) override { zip_source_t * source = zip_source_buffer(_zip, data, dataSize, 0); diff --git a/src/openrct2/core/Zip.h b/src/openrct2/core/Zip.h index 8e3c8798ca..677110e78c 100644 --- a/src/openrct2/core/Zip.h +++ b/src/openrct2/core/Zip.h @@ -29,6 +29,7 @@ interface IZipArchive virtual const utf8 * GetFileName(size_t index) const abstract; virtual uint64 GetFileSize(size_t index) const abstract; virtual void * GetFileData(const utf8 * path, size_t * outSize) const abstract; + virtual IStream * GetFileStream(const utf8 * path) const abstract; /** * Creates or overwrites a file within the zip archive to the given data buffer. diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp index 7738f3ef2b..f7c662e184 100644 --- a/src/openrct2/rct1/S4Importer.cpp +++ b/src/openrct2/rct1/S4Importer.cpp @@ -2480,7 +2480,7 @@ private: } }; -IParkImporter * CreateS4Importer() +IParkImporter * ParkImporter::CreateS4() { return new S4Importer(); } diff --git a/src/openrct2/rct2/S6Importer.cpp b/src/openrct2/rct2/S6Importer.cpp index 791d5a9aa8..923efed6e7 100644 --- a/src/openrct2/rct2/S6Importer.cpp +++ b/src/openrct2/rct2/S6Importer.cpp @@ -407,7 +407,7 @@ public: } }; -IParkImporter * CreateS6Importer() +IParkImporter * ParkImporter::CreateS6() { return new S6Importer(); } diff --git a/src/openrct2/scenario/ScenarioRepository.cpp b/src/openrct2/scenario/ScenarioRepository.cpp index 66273a1b88..a5f394ed16 100644 --- a/src/openrct2/scenario/ScenarioRepository.cpp +++ b/src/openrct2/scenario/ScenarioRepository.cpp @@ -308,7 +308,7 @@ private: */ bool GetScenarioInfo(const std::string &path, uint64 timestamp, scenario_index_entry * entry) { - log_verbose("GetScenarioInfo(%s, ...)", path.c_str()); + log_verbose("GetScenarioInfo(%s, %d, ...)", path.c_str(), timestamp); try { std::string extension = Path::GetExtension(path); @@ -316,9 +316,9 @@ private: { // RCT1 scenario bool result = false; - IParkImporter * s4Importer = CreateS4Importer(); try { + auto s4Importer = std::unique_ptr(ParkImporter::CreateS4()); s4Importer->LoadScenario(path.c_str()); if (s4Importer->GetDetails(entry)) { @@ -330,7 +330,6 @@ private: catch (Exception) { } - delete s4Importer; return result; } else diff --git a/src/openrct2/title/TitleSequence.cpp b/src/openrct2/title/TitleSequence.cpp index 68cccd8993..29107f7643 100644 --- a/src/openrct2/title/TitleSequence.cpp +++ b/src/openrct2/title/TitleSequence.cpp @@ -25,6 +25,7 @@ #include "../core/Guard.hpp" #include "../core/Math.hpp" #include "../core/Memory.hpp" +#include "../core/MemoryStream.h" #include "../core/Path.hpp" #include "../core/String.hpp" #include "../core/StringBuilder.hpp" @@ -140,9 +141,8 @@ extern "C" if (zip != nullptr) { handle = Memory::Allocate(); - handle->Data = zip->GetFileData(filename, &handle->DataSize); - handle->RWOps = SDL_RWFromMem(handle->Data, (sint32)handle->DataSize); - handle->IsScenario = String::Equals(Path::GetExtension(filename), ".sc6", true); + handle->Stream = zip->GetFileStream(filename); + handle->HintPath = String::Duplicate(filename); delete zip; } } @@ -153,9 +153,8 @@ extern "C" Path::Append(absolutePath, sizeof(absolutePath), filename); handle = Memory::Allocate(); - handle->Data = nullptr; - handle->RWOps = SDL_RWFromFile(absolutePath, "rb"); - handle->IsScenario = String::Equals(Path::GetExtension(filename), ".sc6", true); + handle->Stream = new FileStream(absolutePath, FILE_MODE_OPEN); + handle->HintPath = String::Duplicate(filename); } } return handle; @@ -165,9 +164,8 @@ extern "C" { if (handle != nullptr) { - SDL_RWclose(handle->RWOps); - Memory::Free(handle->Data); - Memory::Free(handle); + Memory::Free(handle->HintPath); + delete handle->Stream; } } diff --git a/src/openrct2/title/TitleSequence.h b/src/openrct2/title/TitleSequence.h index c6237cb492..924adb687e 100644 --- a/src/openrct2/title/TitleSequence.h +++ b/src/openrct2/title/TitleSequence.h @@ -53,10 +53,8 @@ typedef struct TitleSequence typedef struct TitleSequenceParkHandle { - size_t DataSize; - void * Data; - struct SDL_RWops * RWOps; - bool IsScenario; + const utf8 * HintPath; + void * Stream; } TitleSequenceParkHandle; enum TITLE_SCRIPT diff --git a/src/openrct2/title/TitleSequencePlayer.cpp b/src/openrct2/title/TitleSequencePlayer.cpp index 72a27c98ca..69d5569a1a 100644 --- a/src/openrct2/title/TitleSequencePlayer.cpp +++ b/src/openrct2/title/TitleSequencePlayer.cpp @@ -16,7 +16,6 @@ #include #include "../common.h" -#include #include "../core/Console.hpp" #include "../core/Exception.hpp" #include "../core/Guard.hpp" @@ -286,7 +285,7 @@ private: TitleSequenceParkHandle * parkHandle = TitleSequenceGetParkHandle(_sequence, saveIndex); if (parkHandle != nullptr) { - loadSuccess = LoadParkFromRW(parkHandle->RWOps, parkHandle->IsScenario); + loadSuccess = LoadParkFromStream((IStream *)parkHandle->Stream, parkHandle->HintPath); TitleSequenceCloseParkHandle(parkHandle); } if (!loadSuccess) @@ -357,7 +356,7 @@ private: bool success = false; try { - auto parkImporter = std::unique_ptr(CreateParkImporterForPath(path)); + auto parkImporter = std::unique_ptr(ParkImporter::Create(path)); parkImporter->Load(path); parkImporter->Import(); PrepareParkForPlayback(); @@ -370,15 +369,29 @@ private: return success; } - bool LoadParkFromRW(SDL_RWops * rw, bool isScenario) + /** + * @param stream The stream to read the park data from. + * @param pathHint Hint path, the extension is grabbed to determine what importer to use. + */ + bool LoadParkFromStream(IStream * stream, const std::string &hintPath) { - bool successfulLoad = isScenario ? scenario_load_rw(rw) : - game_load_sv6(rw); - if (successfulLoad) + log_verbose("TitleSequencePlayer::LoadParkFromStream(%s)", hintPath); + bool success = false; + try { + std::string extension = Path::GetExtension(hintPath); + bool isScenario = ParkImporter::ExtensionIsScenario(hintPath); + auto parkImporter = std::unique_ptr(ParkImporter::Create(hintPath)); + parkImporter->LoadFromStream(stream, isScenario); + parkImporter->Import(); PrepareParkForPlayback(); + success = true; } - return successfulLoad; + catch (Exception) + { + Console::Error::WriteLine("Unable to load park: %s", hintPath.c_str()); + } + return success; } void PrepareParkForPlayback() diff --git a/src/openrct2/title/TitleSequencePlayer.h b/src/openrct2/title/TitleSequencePlayer.h index 15ab54f83d..2ac2f1b6d7 100644 --- a/src/openrct2/title/TitleSequencePlayer.h +++ b/src/openrct2/title/TitleSequencePlayer.h @@ -16,8 +16,6 @@ #pragma once -#include - #ifdef __cplusplus interface IScenarioRepository; diff --git a/src/openrct2/windows/title_editor.c b/src/openrct2/windows/title_editor.c index fbf6124264..76c0e5f188 100644 --- a/src/openrct2/windows/title_editor.c +++ b/src/openrct2/windows/title_editor.c @@ -23,6 +23,7 @@ #include "../interface/widget.h" #include "../interface/window.h" #include "../localisation/localisation.h" +#include "../ParkImporter.h" #include "../peep/peep.h" #include "../peep/staff.h" #include "../scenario/scenario.h" @@ -358,11 +359,12 @@ static void window_title_editor_mouseup(rct_window *w, sint32 widgetIndex) case WIDX_TITLE_EDITOR_LOAD_SAVE: if (w->selected_list_item >= 0 && w->selected_list_item < (sint16)_editingTitleSequence->NumSaves) { TitleSequenceParkHandle * handle = TitleSequenceGetParkHandle(_editingTitleSequence, w->selected_list_item); - if (handle->IsScenario) { - scenario_load_rw(handle->RWOps); + const utf8 * extension = path_get_extension(handle->HintPath); + bool isScenario = park_importer_extension_is_scenario(extension); + park_importer_load_from_stream(handle->Stream, handle->HintPath); + if (isScenario) { scenario_begin(); } else { - game_load_sv6(handle->RWOps); game_load_init(); } TitleSequenceCloseParkHandle(handle);