diff --git a/src/openrct2/rct1.c b/src/openrct2/rct1.c index 3efc42f7a5..087dbfc049 100644 --- a/src/openrct2/rct1.c +++ b/src/openrct2/rct1.c @@ -21,62 +21,6 @@ #include "util/sawyercoding.h" #include "util/util.h" -bool rct1_read_sc4(const char *path, rct1_s4 *s4) -{ - uint8 *buffer, *decodedBuffer; - size_t length, decodedLength; - bool success; - - if (!readentirefile(path, (void**)&buffer, &length)) { - gErrorType = ERROR_TYPE_FILE_LOAD; - gErrorStringId = STR_FILE_CONTAINS_INVALID_DATA; - return 0; - } - - sint32 fileType = sawyercoding_detect_file_type(buffer, length); - - decodedBuffer = malloc(sizeof(rct1_s4)); - decodedLength = (fileType & FILE_VERSION_MASK) == FILE_VERSION_RCT1 ? - sawyercoding_decode_sv4(buffer, decodedBuffer, length, sizeof(rct1_s4)) : - sawyercoding_decode_sc4(buffer, decodedBuffer, length, sizeof(rct1_s4)); - if (decodedLength == sizeof(rct1_s4)) { - memcpy(s4, decodedBuffer, sizeof(rct1_s4)); - success = true; - } else { - success = false; - } - - free(buffer); - free(decodedBuffer); - return success; -} - -bool rct1_read_sv4(const char *path, rct1_s4 *s4) -{ - uint8 *buffer, *decodedBuffer; - size_t length, decodedLength; - bool success; - - if (!readentirefile(path, (void**)&buffer, &length)) { - gErrorType = ERROR_TYPE_FILE_LOAD; - gErrorStringId = STR_FILE_CONTAINS_INVALID_DATA; - return 0; - } - - decodedBuffer = malloc(sizeof(rct1_s4)); - decodedLength = sawyercoding_decode_sv4(buffer, decodedBuffer, length, sizeof(rct1_s4)); - if (decodedLength == sizeof(rct1_s4)) { - memcpy(s4, decodedBuffer, sizeof(rct1_s4)); - success = true; - } else { - success = false; - } - - free(buffer); - free(decodedBuffer); - return success; -} - bool rideTypeShouldLoseSeparateFlag(const rct_ride_entry *rideEntry) { if (!gConfigInterface.select_by_track_type) { diff --git a/src/openrct2/rct1.h b/src/openrct2/rct1.h index d67e1fc677..da53723295 100644 --- a/src/openrct2/rct1.h +++ b/src/openrct2/rct1.h @@ -1189,10 +1189,6 @@ enum { extern const uint8 gRideCategories[0x60]; -bool rct1_read_sc4(const char *path, rct1_s4 *s4); -bool rct1_read_sv4(const char *path, rct1_s4 *s4); -void rct1_import_s4(rct1_s4 *s4); -void rct1_fix_landscape(); sint32 vehicle_preference_compare(uint8 rideType, const char * a, const char * b); bool rideTypeShouldLoseSeparateFlag(const rct_ride_entry *rideEntry); diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp index aa840eca83..6e497d3e4f 100644 --- a/src/openrct2/rct1/S4Importer.cpp +++ b/src/openrct2/rct1/S4Importer.cpp @@ -14,11 +14,14 @@ *****************************************************************************/ #pragma endregion +#include #include #include "../core/Collections.hpp" #include "../core/Console.hpp" #include "../core/Exception.hpp" +#include "../core/FileStream.hpp" #include "../core/Guard.hpp" +#include "../core/IStream.hpp" #include "../core/Memory.hpp" #include "../core/Path.hpp" #include "../core/String.hpp" @@ -91,9 +94,9 @@ public: class S4Importer final : public IS4Importer { private: - const utf8 * _s4Path; - rct1_s4 _s4; - uint8 _gameVersion; + const utf8 * _s4Path = nullptr; + rct1_s4 _s4 = { 0 }; + uint8 _gameVersion = 0; // Lists of dynamic object entries EntryList _rideEntries; @@ -120,24 +123,6 @@ private: uint8 _researchRideTypeUsed[128]; public: - void LoadSavedGame(const utf8 * path) override - { - if (!rct1_read_sv4(path, &_s4)) - { - throw Exception("Unable to load SV4."); - } - _s4Path = path; - } - - void LoadScenario(const utf8 * path) override - { - if (!rct1_read_sc4(path, &_s4)) - { - throw Exception("Unable to load SC4."); - } - _s4Path = path; - } - void Load(const utf8 * path) override { const utf8 * extension = Path::GetExtension(path); @@ -155,6 +140,47 @@ public: } } + void LoadSavedGame(const utf8 * path) override + { + auto fs = FileStream(path, FILE_MODE_OPEN); + LoadFromStream(&fs, false); + _s4Path = path; + } + + void LoadScenario(const utf8 * path) override + { + auto fs = FileStream(path, FILE_MODE_OPEN); + LoadFromStream(&fs, true); + _s4Path = path; + } + + void LoadFromStream(IStream * stream, bool isScenario) override + { + size_t dataSize = stream->GetLength() - stream->GetPosition(); + std::unique_ptr data = std::unique_ptr(stream->ReadArray(dataSize)); + std::unique_ptr decodedData = std::unique_ptr(Memory::Allocate(sizeof(rct1_s4))); + + size_t decodedSize; + if (isScenario) + { + decodedSize = sawyercoding_decode_sc4(data.get(), decodedData.get(), dataSize, sizeof(rct1_s4)); + } + else + { + decodedSize = sawyercoding_decode_sv4(data.get(), decodedData.get(), dataSize, sizeof(rct1_s4)); + } + + if (decodedSize == sizeof(rct1_s4)) + { + Memory::Copy(&_s4, decodedData.get(), sizeof(rct1_s4)); + _s4Path = ""; + } + else + { + throw Exception("Unable to decode park."); + } + } + void Import() override { Initialise(); diff --git a/src/openrct2/rct1/S4Importer.h b/src/openrct2/rct1/S4Importer.h index 91d67965bb..78a7d95037 100644 --- a/src/openrct2/rct1/S4Importer.h +++ b/src/openrct2/rct1/S4Importer.h @@ -19,16 +19,19 @@ #include "../common.h" #include "../scenario/ScenarioRepository.h" +interface IStream; + /** * Interface to import RollerCoaster Tycoon 1 scenarios (*.SC4) and saved games (*.SV4). */ interface IS4Importer { public: - virtual ~IS4Importer() { } + virtual ~IS4Importer() = default; + virtual void Load(const utf8 * path) abstract; virtual void LoadSavedGame(const utf8 * path) abstract; virtual void LoadScenario(const utf8 * path) abstract; - virtual void Load(const utf8 * path) abstract; + virtual void LoadFromStream(IStream * stream, bool isScenario) abstract; virtual void Import() abstract; virtual bool GetDetails(scenario_index_entry * dst) abstract; }; diff --git a/src/openrct2/scenario/ScenarioRepository.cpp b/src/openrct2/scenario/ScenarioRepository.cpp index c37881ec27..430ab503ac 100644 --- a/src/openrct2/scenario/ScenarioRepository.cpp +++ b/src/openrct2/scenario/ScenarioRepository.cpp @@ -317,12 +317,18 @@ private: // RCT1 scenario bool result = false; IS4Importer * s4Importer = CreateS4Importer(); - s4Importer->LoadScenario(path.c_str()); - if (s4Importer->GetDetails(entry)) + try + { + s4Importer->LoadScenario(path.c_str()); + if (s4Importer->GetDetails(entry)) + { + String::Set(entry->path, sizeof(entry->path), path.c_str()); + entry->timestamp = timestamp; + result = true; + } + } + catch (Exception) { - String::Set(entry->path, sizeof(entry->path), path.c_str()); - entry->timestamp = timestamp; - result = true; } delete s4Importer; return result;