diff --git a/src/openrct2/cmdline/ConvertCommand.cpp b/src/openrct2/cmdline/ConvertCommand.cpp index 9baecaee3b..6387a3e10b 100644 --- a/src/openrct2/cmdline/ConvertCommand.cpp +++ b/src/openrct2/cmdline/ConvertCommand.cpp @@ -21,6 +21,7 @@ #include "../core/Guard.hpp" #include "../core/Path.hpp" #include "../ParkImporter.h" +#include "../rct2/S6Exporter.h" #include "CommandLine.hpp" extern "C" @@ -102,74 +103,56 @@ exitcode_t CommandLine::HandleCommandConvert(CommandLineArgEnumerator * enumerat WriteConvertFromAndToMessage(sourceFileType, destinationFileType); gOpenRCT2Headless = true; - if (!openrct2_initialise()) { + if (!openrct2_initialise()) + { Console::Error::WriteLine("Error while initialising OpenRCT2."); return EXITCODE_FAIL; } - if (sourceFileType == FILE_EXTENSION_SV4 || - sourceFileType == FILE_EXTENSION_SC4) + try { - try - { - auto s4Importer = std::unique_ptr(ParkImporter::CreateS4()); - if (sourceFileType == FILE_EXTENSION_SC4) - { - s4Importer->LoadScenario(sourcePath); - } - if (sourceFileType == FILE_EXTENSION_SV4) - { - s4Importer->LoadSavedGame(sourcePath); - } - - s4Importer->Import(); - - if (sourceFileType == FILE_EXTENSION_SC4) - { - // We are converting a scenario, so reset the park - scenario_begin(); - } - } - catch (const Exception &ex) - { - Console::Error::WriteLine(ex.GetMessage()); - return EXITCODE_FAIL; - } + auto importer = std::unique_ptr(ParkImporter::Create(sourcePath)); + importer->Load(sourcePath); + importer->Import(); } - else + catch (const Exception &ex) { - if (sourceFileType == FILE_EXTENSION_SC6) - { - scenario_load_and_play_from_path(sourcePath); - } - if (sourceFileType == FILE_EXTENSION_SV6) - { - game_load_save(sourcePath); - } + Console::Error::WriteLine(ex.GetMessage()); + return EXITCODE_FAIL; } - SDL_RWops* rw = SDL_RWFromFile(destinationPath, "wb+"); - if (rw != NULL) { + if (sourceFileType == FILE_EXTENSION_SC4 || + sourceFileType == FILE_EXTENSION_SC6) + { + // We are converting a scenario, so reset the park + scenario_begin(); + } + + try + { + auto exporter = std::make_unique(); + // HACK remove the main window so it saves the park with the // correct initial view window_close_by_class(WC_MAIN_WINDOW); + exporter->Export(); if (destinationFileType == FILE_EXTENSION_SC6) { - scenario_save(rw, 0x80000002); + exporter->SaveScenario(destinationPath); } else { - scenario_save(rw, 0x80000001); + exporter->SaveGame(destinationPath); } - SDL_RWclose(rw); - Console::WriteLine("Conversion successful!"); } - else + catch (const Exception &ex) { - Console::Error::WriteLine("Unable to write destination file."); + Console::Error::WriteLine(ex.GetMessage()); return EXITCODE_FAIL; } + + Console::WriteLine("Conversion successful!"); return EXITCODE_OK; } diff --git a/src/openrct2/core/FileStream.hpp b/src/openrct2/core/FileStream.hpp index a0c3821896..8eb5aa9e44 100644 --- a/src/openrct2/core/FileStream.hpp +++ b/src/openrct2/core/FileStream.hpp @@ -25,7 +25,8 @@ enum { FILE_MODE_OPEN, - FILE_MODE_WRITE + FILE_MODE_WRITE, + FILE_MODE_APPEND, }; /** @@ -61,6 +62,11 @@ public: _canRead = true; _canWrite = true; break; + case FILE_MODE_APPEND: + mode = "a"; + _canRead = false; + _canWrite = true; + break; default: throw; } diff --git a/src/openrct2/core/MemoryStream.cpp b/src/openrct2/core/MemoryStream.cpp index 341387300a..9a7f66cd31 100644 --- a/src/openrct2/core/MemoryStream.cpp +++ b/src/openrct2/core/MemoryStream.cpp @@ -63,7 +63,12 @@ MemoryStream::~MemoryStream() _data = nullptr; } -void * MemoryStream::GetData() const +const void * MemoryStream::GetData() const +{ + return _data; +} + +void * MemoryStream::GetDataCopy() const { return Memory::Duplicate(_data, _dataSize); } @@ -173,7 +178,9 @@ void MemoryStream::EnsureCapacity(size_t capacity) newCapacity *= 2; } + uint64 position = GetPosition(); _dataCapacity = newCapacity; - Memory::Reallocate(_data, _dataCapacity); + _data = Memory::Reallocate(_data, _dataCapacity); + _position = (void *)((uintptr_t)_data + (uintptr_t)position); } } diff --git a/src/openrct2/core/MemoryStream.h b/src/openrct2/core/MemoryStream.h index f7d490872c..81c6b64082 100644 --- a/src/openrct2/core/MemoryStream.h +++ b/src/openrct2/core/MemoryStream.h @@ -46,7 +46,8 @@ public: MemoryStream(const void * data, size_t dataSize); virtual ~MemoryStream(); - void * GetData() const; + const void * GetData() const; + void * GetDataCopy() const; void * TakeData(); /////////////////////////////////////////////////////////////////////////// diff --git a/src/openrct2/game.h b/src/openrct2/game.h index 8c70bbb44d..87336a8db6 100644 --- a/src/openrct2/game.h +++ b/src/openrct2/game.h @@ -168,7 +168,6 @@ sint32 game_do_command_p(sint32 command, sint32 *eax, sint32 *ebx, sint32 *ecx, void game_load_or_quit_no_save_prompt(); bool game_load_sv6_path(const char * path); bool game_load_sv6(SDL_RWops* rw); -sint32 game_load_network(SDL_RWops* rw); bool game_load_save(const utf8 *path); void game_load_init(); void game_pause_toggle(sint32 *eax, sint32 *ebx, sint32 *ecx, sint32 *edx, sint32 *esi, sint32 *edi, sint32 *ebp); diff --git a/src/openrct2/network/NetworkKey.cpp b/src/openrct2/network/NetworkKey.cpp index 51dffa1e66..d2e4c8e843 100644 --- a/src/openrct2/network/NetworkKey.cpp +++ b/src/openrct2/network/NetworkKey.cpp @@ -16,13 +16,14 @@ #ifndef DISABLE_NETWORK -#include "NetworkKey.h" -#include "../diagnostic.h" - -#include -#include -#include #include +#include +#include +#include + +#include "../core/IStream.hpp" +#include "../diagnostic.h" +#include "NetworkKey.h" #define KEY_TYPE EVP_PKEY_RSA @@ -90,10 +91,11 @@ bool NetworkKey::Generate() return true; } -bool NetworkKey::LoadPrivate(SDL_RWops * file) +bool NetworkKey::LoadPrivate(IStream * stream) { - assert(file != nullptr); - size_t size = (size_t)file->size(file); + Guard::ArgumentNotNull(stream); + + size_t size = (size_t)stream->GetLength(); if (size == (size_t)-1) { log_error("unknown size, refusing to load key"); @@ -105,7 +107,7 @@ bool NetworkKey::LoadPrivate(SDL_RWops * file) return false; } char * priv_key = new char[size]; - file->read(file, priv_key, 1, size); + stream->Read(priv_key, size); BIO * bio = BIO_new_mem_buf(priv_key, (sint32)size); if (bio == nullptr) { @@ -134,10 +136,11 @@ bool NetworkKey::LoadPrivate(SDL_RWops * file) return true; } -bool NetworkKey::LoadPublic(SDL_RWops * file) +bool NetworkKey::LoadPublic(IStream * stream) { - assert(file != nullptr); - size_t size = (size_t)file->size(file); + Guard::ArgumentNotNull(stream); + + size_t size = (size_t)stream->GetLength(); if (size == (size_t)-1) { log_error("unknown size, refusing to load key"); @@ -149,7 +152,7 @@ bool NetworkKey::LoadPublic(SDL_RWops * file) return false; } char * pub_key = new char[size]; - file->read(file, pub_key, 1, size); + stream->Read(pub_key, size); BIO * bio = BIO_new_mem_buf(pub_key, (sint32)size); if (bio == nullptr) { @@ -171,7 +174,7 @@ bool NetworkKey::LoadPublic(SDL_RWops * file) return true; } -bool NetworkKey::SavePrivate(SDL_RWops *file) +bool NetworkKey::SavePrivate(IStream * stream) { if (_key == nullptr) { @@ -208,7 +211,7 @@ bool NetworkKey::SavePrivate(SDL_RWops *file) sint32 keylen = BIO_pending(bio); char * pem_key = new char[keylen]; BIO_read(bio, pem_key, keylen); - file->write(file, pem_key, keylen, 1); + stream->Write(pem_key, keylen); log_verbose("saving key of length %u", keylen); BIO_free_all(bio); delete [] pem_key; @@ -219,7 +222,7 @@ bool NetworkKey::SavePrivate(SDL_RWops *file) return true; } -bool NetworkKey::SavePublic(SDL_RWops *file) +bool NetworkKey::SavePublic(IStream * stream) { if (_key == nullptr) { @@ -250,7 +253,7 @@ bool NetworkKey::SavePublic(SDL_RWops *file) sint32 keylen = BIO_pending(bio); char * pem_key = new char[keylen]; BIO_read(bio, pem_key, keylen); - file->write(file, pem_key, keylen, 1); + stream->Write(pem_key, keylen); BIO_free_all(bio); delete [] pem_key; diff --git a/src/openrct2/network/NetworkKey.h b/src/openrct2/network/NetworkKey.h index 1ccd305778..3955ee789b 100644 --- a/src/openrct2/network/NetworkKey.h +++ b/src/openrct2/network/NetworkKey.h @@ -21,22 +21,23 @@ #include "../common.h" -#include #include typedef struct evp_pkey_st EVP_PKEY; typedef struct evp_pkey_ctx_st EVP_PKEY_CTX; +interface IStream; + class NetworkKey final { public: NetworkKey(); ~NetworkKey(); bool Generate(); - bool LoadPrivate(SDL_RWops * file); - bool LoadPublic(SDL_RWops * file); - bool SavePrivate(SDL_RWops * file); - bool SavePublic(SDL_RWops * file); + bool LoadPrivate(IStream * stream); + bool LoadPublic(IStream * stream); + bool SavePrivate(IStream * stream); + bool SavePublic(IStream * stream); std::string PublicKeyString(); std::string PublicKeyHash(); void Unload(); diff --git a/src/openrct2/network/TcpSocket.cpp b/src/openrct2/network/TcpSocket.cpp index bdc58f5500..8ee4aeaeb0 100644 --- a/src/openrct2/network/TcpSocket.cpp +++ b/src/openrct2/network/TcpSocket.cpp @@ -66,6 +66,10 @@ constexpr uint32 CONNECT_TIMEOUT_MS = 3000; +#ifdef __WINDOWS__ + static bool _wsaInitialised = false; +#endif + class TcpSocket; class SocketException : public Exception @@ -431,7 +435,7 @@ private: explicit TcpSocket(SOCKET socket) { _socket = socket; - _status = SOCKET_STATUS_CONNECTED; + _status = SOCKET_STATUS_CONNECTED; } void CloseSocket() @@ -492,4 +496,48 @@ ITcpSocket * CreateTcpSocket() return new TcpSocket(); } +bool InitialiseWSA() +{ +#ifdef __WINDOWS__ + if (!_wsaInitialised) + { + log_verbose("Initialising WSA"); + WSADATA wsa_data; + if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0) + { + log_error("Unable to initialise winsock."); + return false; + } + _wsaInitialised = true; + } + return _wsaInitialised; +#else + return true; +#endif +} + +void DisposeWSA() +{ +#ifdef __WINDOWS__ + if (_wsaInitialised) + { + WSACleanup(); + _wsaInitialised = false; + } +#endif +} + +namespace Convert +{ + uint16 HostToNetwork(uint16 value) + { + return htons(value); + } + + uint16 NetworkToHost(uint16 value) + { + return ntohs(value); + } +} + #endif diff --git a/src/openrct2/network/TcpSocket.h b/src/openrct2/network/TcpSocket.h index 1e7f9e0320..a13df908c1 100644 --- a/src/openrct2/network/TcpSocket.h +++ b/src/openrct2/network/TcpSocket.h @@ -62,3 +62,12 @@ public: }; ITcpSocket * CreateTcpSocket(); + +bool InitialiseWSA(); +void DisposeWSA(); + +namespace Convert +{ + uint16 HostToNetwork(uint16 value); + uint16 NetworkToHost(uint16 value); +} diff --git a/src/openrct2/network/network.cpp b/src/openrct2/network/network.cpp index 3dcf61a75a..3ec5a3a7a6 100644 --- a/src/openrct2/network/network.cpp +++ b/src/openrct2/network/network.cpp @@ -16,19 +16,12 @@ #include -#ifdef __WINDOWS__ - // winsock2 must be included before windows.h - #include -#else - #include -#endif - #include "../core/Guard.hpp" +#include "../OpenRCT2.h" extern "C" { -#include "../OpenRCT2.h" -#include "../platform/platform.h" -#include "../util/sawyercoding.h" + #include "../platform/platform.h" + #include "../util/sawyercoding.h" } #include "network.h" @@ -45,13 +38,16 @@ sint32 _pickup_peep_old_x = SPRITE_LOCATION_NULL; #include #include "../core/Console.hpp" +#include "../core/FileStream.hpp" #include "../core/Json.hpp" #include "../core/Math.hpp" +#include "../core/MemoryStream.h" #include "../core/Path.hpp" #include "../core/String.hpp" #include "../core/Util.hpp" #include "../object/ObjectManager.h" #include "../object/ObjectRepository.h" +#include "../ParkImporter.h" #include "../rct2/S6Exporter.h" extern "C" { @@ -130,17 +126,9 @@ Network::~Network() bool Network::Init() { -#ifdef __WINDOWS__ - if (!wsa_initialized) { - log_verbose("Initialising WSA"); - WSADATA wsa_data; - if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0) { - log_error("Unable to initialise winsock."); - return false; - } - wsa_initialized = true; + if (!InitialiseWSA()) { + return false; } -#endif status = NETWORK_STATUS_READY; @@ -183,12 +171,7 @@ void Network::Close() player_list.clear(); group_list.clear(); -#ifdef __WINDOWS__ - if (wsa_initialized) { - WSACleanup(); - wsa_initialized = false; - } -#endif + DisposeWSA(); CloseChatLog(); gfx_invalidate_screen(); @@ -229,36 +212,47 @@ bool Network::BeginClient(const char* host, uint16 port) return false; } - SDL_RWops *privkey = SDL_RWFromFile(keyPath, "wb+"); - if (privkey == nullptr) { + try + { + auto fs = FileStream(keyPath, FILE_MODE_WRITE); + _key.SavePrivate(&fs); + } + catch (Exception) + { log_error("Unable to save private key at %s.", keyPath); return false; } - _key.SavePrivate(privkey); - SDL_RWclose(privkey); const std::string hash = _key.PublicKeyHash(); const utf8 *publicKeyHash = hash.c_str(); network_get_public_key_path(keyPath, sizeof(keyPath), gConfigNetwork.player_name, publicKeyHash); Console::WriteLine("Key generated, saving public bits as %s", keyPath); - SDL_RWops *pubkey = SDL_RWFromFile(keyPath, "wb+"); - if (pubkey == nullptr) { + + try + { + auto fs = FileStream(keyPath, FILE_MODE_WRITE); + _key.SavePublic(&fs); + } + catch (Exception) + { log_error("Unable to save public key at %s.", keyPath); return false; } - _key.SavePublic(pubkey); - SDL_RWclose(pubkey); } else { - log_verbose("Loading key from %s", keyPath); - SDL_RWops *privkey = SDL_RWFromFile(keyPath, "rb"); - if (privkey == nullptr) { + // LoadPrivate returns validity of loaded key + bool ok = false; + try + { + log_verbose("Loading key from %s", keyPath); + auto fs = FileStream(keyPath, FILE_MODE_OPEN); + ok = _key.LoadPrivate(&fs); + } + catch (Exception) + { log_error("Unable to read private key from %s.", keyPath); return false; } - // LoadPrivate returns validity of loaded key - bool ok = _key.LoadPrivate(privkey); - SDL_RWclose(privkey); // Don't store private key in memory when it's not in use. _key.Unload(); return ok; @@ -813,10 +807,11 @@ void Network::AppendChatLog(const utf8 *text) utf8 directory[MAX_PATH]; Path::GetDirectory(directory, sizeof(directory), chatLogPath); if (platform_ensure_directory_exists(directory)) { - _chatLogStream = SDL_RWFromFile(chatLogPath, "a"); - if (_chatLogStream != nullptr) { - utf8 buffer[256]; + try + { + _chatLogStream = new FileStream(chatLogPath, FILE_MODE_APPEND); + utf8 buffer[256]; time_t timer; struct tm * tmInfo; time(&timer); @@ -827,8 +822,12 @@ void Network::AppendChatLog(const utf8 *text) utf8_remove_formatting(buffer, false); String::Append(buffer, sizeof(buffer), PLATFORM_NEWLINE); - SDL_RWwrite(_chatLogStream, buffer, strlen(buffer), 1); - SDL_RWclose(_chatLogStream); + _chatLogStream->Write(buffer, strlen(buffer)); + delete _chatLogStream; + _chatLogStream = nullptr; + } + catch (const Exception &) + { } } } @@ -916,14 +915,6 @@ void Network::Server_Send_AUTH(NetworkConnection& connection) void Network::Server_Send_MAP(NetworkConnection* connection) { - FILE* temp = tmpfile(); - if (!temp) { - log_warning("Failed to create temporary file to save map."); - return; - } - SDL_RWops* rw = SDL_RWFromFP(temp, SDL_TRUE); - size_t out_size; - uint8 *header; std::vector objects; if (connection) { objects = connection->RequestedObjects; @@ -933,8 +924,9 @@ void Network::Server_Send_MAP(NetworkConnection* connection) IObjectManager * objManager = GetObjectManager(); objects = objManager->GetPackableObjects(); } - header = save_for_network(rw, out_size, objects); - SDL_RWclose(rw); + + size_t out_size; + uint8 * header = save_for_network(out_size, objects); if (header == nullptr) { if (connection) { connection->SetLastDisconnectReason(STR_MULTIPLAYER_CONNECTION_CLOSED); @@ -957,22 +949,24 @@ void Network::Server_Send_MAP(NetworkConnection* connection) free(header); } -uint8 * Network::save_for_network(SDL_RWops *rw_buffer, size_t &out_size, const std::vector &objects) const +uint8 * Network::save_for_network(size_t &out_size, const std::vector &objects) const { uint8 * header = nullptr; out_size = 0; bool RLEState = gUseRLE; gUseRLE = false; - scenario_save_network(rw_buffer, objects); - gUseRLE = RLEState; - sint32 size = (sint32)SDL_RWtell(rw_buffer); - std::vector buffer(size); - SDL_RWseek(rw_buffer, 0, RW_SEEK_SET); - if (SDL_RWread(rw_buffer, &buffer[0], size, 1) == 0) { - log_warning("Failed to read temporary map file into memory."); + + auto ms = MemoryStream(); + if (!SaveMap(&ms, objects)) { + log_warning("Failed to export map."); return nullptr; } - uint8 *compressed = util_zlib_deflate(&buffer[0], size, &out_size); + gUseRLE = RLEState; + + const void * data = ms.GetData(); + sint32 size = ms.GetLength(); + + uint8 *compressed = util_zlib_deflate((const uint8 *)data, size, &out_size); if (compressed != NULL) { header = (uint8 *)_strdup("open2_sv6_zlib"); @@ -993,7 +987,7 @@ uint8 * Network::save_for_network(SDL_RWops *rw_buffer, size_t &out_size, const log_error("Failed to allocate %u bytes.", size); } else { out_size = size; - memcpy(header, &buffer[0], size); + memcpy(header, data, size); } } return header; @@ -1381,15 +1375,23 @@ void Network::Client_Handle_TOKEN(NetworkConnection& connection, NetworkPacket& log_error("Key file (%s) was not found. Restart client to re-generate it.", keyPath); return; } - SDL_RWops *privkey = SDL_RWFromFile(keyPath, "rb"); - bool ok = _key.LoadPrivate(privkey); - SDL_RWclose(privkey); - if (!ok) { + + try + { + auto fs = FileStream(keyPath, FILE_MODE_OPEN); + if (!_key.LoadPrivate(&fs)) + { + throw Exception(); + } + } + catch (Exception) + { log_error("Failed to load key %s", keyPath); connection.SetLastDisconnectReason(STR_MULTIPLAYER_VERIFICATION_FAILURE); connection.Socket->Disconnect(); return; } + uint32 challenge_size; packet >> challenge_size; const char *challenge = (const char *)packet.Read(challenge_size); @@ -1398,7 +1400,7 @@ void Network::Client_Handle_TOKEN(NetworkConnection& connection, NetworkPacket& const std::string pubkey = _key.PublicKeyString(); _challenge.resize(challenge_size); memcpy(_challenge.data(), challenge, challenge_size); - ok = _key.Sign(_challenge.data(), _challenge.size(), &signature, &sigsize); + bool ok = _key.Sign(_challenge.data(), _challenge.size(), &signature, &sigsize); if (!ok) { log_error("Failed to sign server's challenge."); connection.SetLastDisconnectReason(STR_MULTIPLAYER_VERIFICATION_FAILURE); @@ -1552,26 +1554,45 @@ void Network::Server_Handle_AUTH(NetworkConnection& connection, NetworkPacket& p if (pubkey == nullptr) { connection.AuthStatus = NETWORK_AUTH_VERIFICATIONFAILURE; } else { - const char *signature = (const char *)packet.Read(sigsize); - SDL_RWops *pubkey_rw = SDL_RWFromConstMem(pubkey, (sint32)strlen(pubkey)); - if (signature == nullptr || pubkey_rw == nullptr) { - connection.AuthStatus = NETWORK_AUTH_VERIFICATIONFAILURE; - log_verbose("Signature verification failed, invalid data!"); - } else { - connection.Key.LoadPublic(pubkey_rw); - SDL_RWclose(pubkey_rw); + try + { + const char *signature = (const char *)packet.Read(sigsize); + if (signature == nullptr) + { + throw Exception(); + } + + auto ms = MemoryStream(pubkey, strlen(pubkey)); + if (!connection.Key.LoadPublic(&ms)) + { + throw Exception(); + } + bool verified = connection.Key.Verify(connection.Challenge.data(), connection.Challenge.size(), signature, sigsize); const std::string hash = connection.Key.PublicKeyHash(); - if (verified) { - connection.AuthStatus = NETWORK_AUTH_VERIFIED; + if (verified) + { log_verbose("Signature verification ok. Hash %s", hash.c_str()); - } else { + if (gConfigNetwork.known_keys_only && _userManager.GetUserByHash(hash) == nullptr) + { + log_verbose("Hash %s, not known", hash.c_str()); + connection.AuthStatus = NETWORK_AUTH_UNKNOWN_KEY_DISALLOWED; + } + else + { + connection.AuthStatus = NETWORK_AUTH_VERIFIED; + } + } + else + { connection.AuthStatus = NETWORK_AUTH_VERIFICATIONFAILURE; log_verbose("Signature verification failed!"); } - if (gConfigNetwork.known_keys_only && _userManager.GetUserByHash(hash) == nullptr) { - connection.AuthStatus = NETWORK_AUTH_UNKNOWN_KEY_DISALLOWED; - } + } + catch (Exception) + { + connection.AuthStatus = NETWORK_AUTH_VERIFICATIONFAILURE; + log_verbose("Signature verification failed, invalid data!"); } } @@ -1649,8 +1670,10 @@ void Network::Client_Handle_MAP(NetworkConnection& connection, NetworkPacket& pa } else { log_verbose("Assuming received map is in plain sv6 format"); } - SDL_RWops* rw = SDL_RWFromMem(data, (sint32)data_size); - if (game_load_network(rw)) { + + auto ms = MemoryStream(data, data_size); + if (LoadMap(&ms)) + { game_load_init(); game_command_queue.clear(); server_tick = gCurrentTicks; @@ -1667,7 +1690,6 @@ void Network::Client_Handle_MAP(NetworkConnection& connection, NetworkPacket& pa //Something went wrong, game is not loaded. Return to main screen. game_do_command(0, GAME_COMMAND_FLAG_APPLY, 0, 0, GAME_COMMAND_LOAD_OR_QUIT, 1, 0); } - SDL_RWclose(rw); if (has_to_free) { free(data); @@ -1675,6 +1697,99 @@ void Network::Client_Handle_MAP(NetworkConnection& connection, NetworkPacket& pa } } +bool Network::LoadMap(IStream * stream) +{ + bool result = false; + try + { + auto importer = std::unique_ptr(ParkImporter::CreateS6()); + importer->LoadFromStream(stream, false); + importer->Import(); + + sprite_position_tween_reset(); + + // Read checksum + uint32 checksum = stream->ReadValue(); + UNUSED(checksum); + + // Read other data not in normal save files + stream->Read(gSpriteSpatialIndex, 0x10001 * sizeof(uint16)); + gGamePaused = stream->ReadValue(); + _guestGenerationProbability = stream->ReadValue(); + _suggestedGuestMaximum = stream->ReadValue(); + gCheatsSandboxMode = stream->ReadValue() != 0; + gCheatsDisableClearanceChecks = stream->ReadValue() != 0; + gCheatsDisableSupportLimits = stream->ReadValue() != 0; + gCheatsDisableTrainLengthLimit = stream->ReadValue() != 0; + gCheatsEnableChainLiftOnAllTrack = stream->ReadValue() != 0; + gCheatsShowAllOperatingModes = stream->ReadValue() != 0; + gCheatsShowVehiclesFromOtherTrackTypes = stream->ReadValue() != 0; + gCheatsFastLiftHill = stream->ReadValue() != 0; + gCheatsDisableBrakesFailure = stream->ReadValue() != 0; + gCheatsDisableAllBreakdowns = stream->ReadValue() != 0; + gCheatsUnlockAllPrices = stream->ReadValue() != 0; + gCheatsBuildInPauseMode = stream->ReadValue() != 0; + gCheatsIgnoreRideIntensity = stream->ReadValue() != 0; + gCheatsDisableVandalism = stream->ReadValue() != 0; + gCheatsDisableLittering = stream->ReadValue() != 0; + gCheatsNeverendingMarketing = stream->ReadValue() != 0; + gCheatsFreezeClimate = stream->ReadValue() != 0; + gCheatsDisablePlantAging = stream->ReadValue() != 0; + gCheatsAllowArbitraryRideTypeChanges = stream->ReadValue() != 0; + + gLastAutoSaveUpdate = AUTOSAVE_PAUSE; + result = true; + } + catch (const Exception &) + { + } + return result; +} + +bool Network::SaveMap(IStream * stream, const std::vector &objects) const +{ + bool result = false; + viewport_set_saved_view(); + try + { + auto s6exporter = std::make_unique(); + s6exporter->ExportObjectsList = objects; + s6exporter->Export(); + s6exporter->SaveGame(stream); + + // Write other data not in normal save files + stream->Write(gSpriteSpatialIndex, 0x10001 * sizeof(uint16)); + stream->WriteValue(gGamePaused); + stream->WriteValue(_guestGenerationProbability); + stream->WriteValue(_suggestedGuestMaximum); + stream->WriteValue(gCheatsSandboxMode); + stream->WriteValue(gCheatsDisableClearanceChecks); + stream->WriteValue(gCheatsDisableSupportLimits); + stream->WriteValue(gCheatsDisableTrainLengthLimit); + stream->WriteValue(gCheatsEnableChainLiftOnAllTrack); + stream->WriteValue(gCheatsShowAllOperatingModes); + stream->WriteValue(gCheatsShowVehiclesFromOtherTrackTypes); + stream->WriteValue(gCheatsFastLiftHill); + stream->WriteValue(gCheatsDisableBrakesFailure); + stream->WriteValue(gCheatsDisableAllBreakdowns); + stream->WriteValue(gCheatsUnlockAllPrices); + stream->WriteValue(gCheatsBuildInPauseMode); + stream->WriteValue(gCheatsIgnoreRideIntensity); + stream->WriteValue(gCheatsDisableVandalism); + stream->WriteValue(gCheatsDisableLittering); + stream->WriteValue(gCheatsNeverendingMarketing); + stream->WriteValue(gCheatsFreezeClimate); + stream->WriteValue(gCheatsDisablePlantAging); + stream->WriteValue(gCheatsAllowArbitraryRideTypeChanges); + + result = true; + } + catch (const Exception &) + { + } + return result; +} + void Network::Client_Handle_CHAT(NetworkConnection& connection, NetworkPacket& packet) { const char* text = packet.ReadString(); @@ -1955,19 +2070,6 @@ void Network::Client_Handle_GAMEINFO(NetworkConnection& connection, NetworkPacke network_chat_show_server_greeting(); } -namespace Convert -{ - uint16 HostToNetwork(uint16 value) - { - return htons(value); - } - - uint16 NetworkToHost(uint16 value) - { - return ntohs(value); - } -} - sint32 network_init() { return gNetwork.Init(); @@ -2456,8 +2558,16 @@ void network_send_password(const char* password) log_error("Private key %s missing! Restart the game to generate it.", keyPath); return; } - SDL_RWops *privkey = SDL_RWFromFile(keyPath, "rb"); - gNetwork._key.LoadPrivate(privkey); + try + { + auto fs = FileStream(keyPath, FILE_MODE_OPEN); + gNetwork._key.LoadPrivate(&fs); + } + catch (Exception) + { + log_error("Error reading private key from %s.", keyPath); + return; + } const std::string pubkey = gNetwork._key.PublicKeyString(); size_t sigsize; char *signature; diff --git a/src/openrct2/network/network.h b/src/openrct2/network/network.h index 2af7c1eca7..1667d90f7a 100644 --- a/src/openrct2/network/network.h +++ b/src/openrct2/network/network.h @@ -67,7 +67,6 @@ extern "C" { #include #include #include -#include #include "../core/Json.hpp" #include "../core/Nullable.hpp" #include "NetworkConnection.h" @@ -174,6 +173,9 @@ private: std::string GenerateAdvertiseKey(); void SetupDefaultGroups(); + bool LoadMap(IStream * stream); + bool SaveMap(IStream * stream, const std::vector &objects) const; + struct GameCommand { GameCommand(uint32 t, uint32* args, uint8 p, uint8 cb) { @@ -211,7 +213,7 @@ private: INetworkServerAdvertiser * _advertiser = nullptr; uint32 server_connect_time = 0; uint8 default_group = 0; - SDL_RWops *_chatLogStream = nullptr; + IStream * _chatLogStream = nullptr; std::string _chatLogPath; uint32 game_commands_processed_this_tick = 0; @@ -245,15 +247,9 @@ private: void Client_Handle_OBJECTS(NetworkConnection& connection, NetworkPacket& packet); void Server_Handle_OBJECTS(NetworkConnection& connection, NetworkPacket& packet); - uint8 * save_for_network(SDL_RWops *buffer, size_t &out_size, const std::vector &objects) const; + uint8 * save_for_network(size_t &out_size, const std::vector &objects) const; }; -namespace Convert -{ - uint16 HostToNetwork(uint16 value); - uint16 NetworkToHost(uint16 value); -} - #endif // __cplusplus #else /* DISABLE_NETWORK */ #define NETWORK_STREAM_ID "Multiplayer disabled" diff --git a/src/openrct2/object.h b/src/openrct2/object.h index 53606e34ab..6990b18261 100644 --- a/src/openrct2/object.h +++ b/src/openrct2/object.h @@ -107,7 +107,6 @@ assert_struct_size(rct_object_filters, 3); extern const rct_object_entry_group object_entry_groups[]; void object_list_load(); -bool object_read_and_load_entries(SDL_RWops* rw); bool object_load_entries(rct_object_entry* entries); bool object_saved_packed(SDL_RWops* rw, const rct_object_entry * entry); diff --git a/src/openrct2/object/ObjectFactory.cpp b/src/openrct2/object/ObjectFactory.cpp index 96cfc6d5ad..f214b0b039 100644 --- a/src/openrct2/object/ObjectFactory.cpp +++ b/src/openrct2/object/ObjectFactory.cpp @@ -18,8 +18,9 @@ #include "../core/FileStream.hpp" #include "../core/Memory.hpp" #include "../core/MemoryStream.h" -#include "../core/String.hpp" #include "../core/Path.hpp" +#include "../core/String.hpp" +#include "../rct12/SawyerChunkReader.h" #include "BannerObject.h" #include "EntranceObject.h" #include "FootpathItemObject.h" @@ -102,64 +103,40 @@ namespace ObjectFactory } } - static MemoryStream * GetDecodedChunkStream(IReadObjectContext * context, SDL_RWops * file) - { - size_t bufferSize = 0x600000; - void * buffer = Memory::Allocate(bufferSize); - if (buffer == nullptr) - { - log_error("Unable to allocate data buffer."); - return nullptr; - } - - bufferSize = sawyercoding_read_chunk_with_size(file, (uint8 *)buffer, bufferSize); - if (bufferSize == SIZE_MAX) - { - context->LogError(OBJECT_ERROR_BAD_ENCODING, "Unable to decode chunk."); - Memory::Free(buffer); - return nullptr; - } - else - { - buffer = Memory::Reallocate(buffer, bufferSize); - return new MemoryStream(buffer, bufferSize, MEMORY_ACCESS::READ | MEMORY_ACCESS::OWNER); - } - } - Object * CreateObjectFromLegacyFile(const utf8 * path) { + log_verbose("CreateObjectFromLegacyFile(\"%s\")", path); + Object * result = nullptr; - - SDL_RWops * file = SDL_RWFromFile(path, "rb"); - if (file != nullptr) + try { - rct_object_entry entry; - if (SDL_RWread(file, &entry, sizeof(entry), 1) == 1) + auto fs = FileStream(path, FILE_MODE_OPEN); + auto chunkReader = SawyerChunkReader(&fs); + + rct_object_entry entry = fs.ReadValue(); + result = CreateObject(entry); + + utf8 objectName[9] = { 0 }; + object_entry_get_name_fixed(objectName, sizeof(objectName), &entry); + log_verbose(" entry: { 0x%08X, \"%s\", 0x%08X }", entry.flags, objectName, entry.checksum); + + auto chunk = chunkReader.ReadChunk(); + log_verbose(" size: %zu", chunk->GetLength()); + + auto chunkStream = MemoryStream(chunk->GetData(), chunk->GetLength()); + auto readContext = ReadObjectContext(objectName); + ReadObjectLegacy(result, &readContext, &chunkStream); + if (readContext.WasError()) { - result = CreateObject(entry); - if (result != nullptr) - { - utf8 objectName[9] = { 0 }; - Memory::Copy(objectName, entry.name, 8); - - auto readContext = ReadObjectContext(objectName); - auto chunkStream = GetDecodedChunkStream(&readContext, file); - if (chunkStream != nullptr) - { - ReadObjectLegacy(result, &readContext, chunkStream); - delete chunkStream; - } - - if (readContext.WasError()) - { - Console::Error::WriteLine("Error reading object: '%s'", path); - - delete result; - result = nullptr; - } - } + throw Exception("Object has errors"); } - SDL_RWclose(file); + } + catch (Exception) + { + Console::Error::WriteLine("Unable to open or read '%s'", path); + + delete result; + result = nullptr; } return result; } @@ -190,8 +167,7 @@ namespace ObjectFactory Object * CreateObject(const rct_object_entry &entry) { - Object * result = nullptr; - + Object * result; uint8 objectType = entry.flags & 0x0F; switch (objectType) { case OBJECT_TYPE_RIDE: @@ -227,8 +203,9 @@ namespace ObjectFactory case OBJECT_TYPE_SCENARIO_TEXT: result = new StexObject(entry); break; + default: + throw Exception("Invalid object type"); } - return result; } } diff --git a/src/openrct2/object_list.c b/src/openrct2/object_list.c index 7b08f65b26..0bfea2d5f2 100644 --- a/src/openrct2/object_list.c +++ b/src/openrct2/object_list.c @@ -127,20 +127,6 @@ void object_create_identifier_name(char* string_buffer, size_t size, const rct_o snprintf(string_buffer, size, "%.8s/%4X%4X", object->name, object->flags, object->checksum); } -/** - * - * rct2: 0x006AA0C6 - */ -bool object_read_and_load_entries(SDL_RWops* rw) -{ - // Read all the object entries - rct_object_entry *entries = malloc(OBJECT_ENTRY_COUNT * sizeof(rct_object_entry)); - sawyercoding_read_chunk_with_size(rw, (uint8*)entries, OBJECT_ENTRY_COUNT * sizeof(rct_object_entry)); - bool result = object_load_entries(entries); - free(entries); - return result; -} - /** * * rct2: 0x006A9DA2 diff --git a/src/openrct2/platform/crash.cpp b/src/openrct2/platform/crash.cpp index 871f8f78cf..0fa6d81a54 100644 --- a/src/openrct2/platform/crash.cpp +++ b/src/openrct2/platform/crash.cpp @@ -18,6 +18,7 @@ #include "crash.h" #ifdef USE_BREAKPAD +#include #include #if defined(__WINDOWS__) @@ -28,13 +29,16 @@ #error Breakpad support not implemented yet for this platform #endif -extern "C" { +extern "C" +{ #include "../localisation/language.h" #include "../scenario/scenario.h" #include "platform.h" } #include "../core/Console.hpp" +#include "../core/Exception.hpp" +#include "../rct2/S6Exporter.h" #define WSZ(x) L"" x @@ -86,21 +90,25 @@ static bool OnCrash(const wchar_t * dumpPath, wprintf(L"Version: %s\n", WSZ(OPENRCT2_VERSION)); wprintf(L"Commit: %s\n", _wszCommitSha1Short); - utf8 * saveFilePathUTF8 = widechar_to_utf8(saveFilePath); - SDL_RWops * rw = SDL_RWFromFile(saveFilePathUTF8, "wb+"); - free(saveFilePathUTF8); - bool savedGameDumped = false; - if (rw != NULL) { - scenario_save(rw, 0x80000000); + utf8 * saveFilePathUTF8 = widechar_to_utf8(saveFilePath); + try + { + auto exporter = std::make_unique(); + exporter->Export(); + exporter->SaveGame(saveFilePathUTF8); savedGameDumped = true; - SDL_RWclose(rw); } + catch (const Exception &) + { + } + free(saveFilePathUTF8); if (gOpenRCT2SilentBreakpad) { return succeeded; } + constexpr const wchar_t * MessageFormat = L"A crash has occurred and a dump was created at\n%s.\n\nPlease file an issue with OpenRCT2 on GitHub, and provide the dump and saved game there.\n\nVersion: %s\nCommit: %s"; wchar_t message[MAX_PATH * 2]; swprintf_s(message, diff --git a/src/openrct2/rct2/S6Exporter.cpp b/src/openrct2/rct2/S6Exporter.cpp index 2c4bef975c..d9c0edcd9a 100644 --- a/src/openrct2/rct2/S6Exporter.cpp +++ b/src/openrct2/rct2/S6Exporter.cpp @@ -396,61 +396,6 @@ uint32 S6Exporter::GetLoanHash(money32 initialCash, money32 bankLoan, uint32 max return value; } -// Save game state without modifying any of the state for multiplayer -sint32 scenario_save_network(SDL_RWops * rw, const std::vector &objects) -{ - viewport_set_saved_view(); - - bool result = false; - auto s6exporter = new S6Exporter(); - try - { - auto rwStream = FileStream(rw, FILE_MODE_WRITE); - - s6exporter->ExportObjectsList = objects; - s6exporter->Export(); - s6exporter->SaveGame(&rwStream); - result = true; - } - catch (const Exception &) - { - } - delete s6exporter; - - if (!result) - { - return 0; - } - - // Write other data not in normal save files - SDL_RWwrite(rw, gSpriteSpatialIndex, 0x10001 * sizeof(uint16), 1); - SDL_WriteLE32(rw, gGamePaused); - SDL_WriteLE32(rw, _guestGenerationProbability); - SDL_WriteLE32(rw, _suggestedGuestMaximum); - SDL_WriteU8(rw, gCheatsSandboxMode); - SDL_WriteU8(rw, gCheatsDisableClearanceChecks); - SDL_WriteU8(rw, gCheatsDisableSupportLimits); - SDL_WriteU8(rw, gCheatsDisableTrainLengthLimit); - SDL_WriteU8(rw, gCheatsEnableChainLiftOnAllTrack); - SDL_WriteU8(rw, gCheatsShowAllOperatingModes); - SDL_WriteU8(rw, gCheatsShowVehiclesFromOtherTrackTypes); - SDL_WriteU8(rw, gCheatsFastLiftHill); - SDL_WriteU8(rw, gCheatsDisableBrakesFailure); - SDL_WriteU8(rw, gCheatsDisableAllBreakdowns); - SDL_WriteU8(rw, gCheatsUnlockAllPrices); - SDL_WriteU8(rw, gCheatsBuildInPauseMode); - SDL_WriteU8(rw, gCheatsIgnoreRideIntensity); - SDL_WriteU8(rw, gCheatsDisableVandalism); - SDL_WriteU8(rw, gCheatsDisableLittering); - SDL_WriteU8(rw, gCheatsNeverendingMarketing); - SDL_WriteU8(rw, gCheatsFreezeClimate); - SDL_WriteU8(rw, gCheatsDisablePlantAging); - SDL_WriteU8(rw, gCheatsAllowArbitraryRideTypeChanges); - - gfx_invalidate_screen(); - return 1; -} - extern "C" { enum { diff --git a/src/openrct2/rct2/S6Exporter.h b/src/openrct2/rct2/S6Exporter.h index a0dc5a908b..af0e691bb1 100644 --- a/src/openrct2/rct2/S6Exporter.h +++ b/src/openrct2/rct2/S6Exporter.h @@ -30,8 +30,6 @@ extern "C" interface IStream; struct ObjectRepositoryItem; -sint32 scenario_save_network(SDL_RWops* rw, const std::vector &objects); - /** * Class to export RollerCoaster Tycoon 2 scenarios (*.SC6) and saved games (*.SV6). */ diff --git a/src/openrct2/rct2/S6Importer.cpp b/src/openrct2/rct2/S6Importer.cpp index e5db2d1309..ea2f50f4c2 100644 --- a/src/openrct2/rct2/S6Importer.cpp +++ b/src/openrct2/rct2/S6Importer.cpp @@ -486,42 +486,6 @@ extern "C" return result; } - bool scenario_load_rw(SDL_RWops * rw) - { - bool result = false; - auto stream = FileStream(rw, FILE_MODE_OPEN); - auto s6Importer = new S6Importer(); - try - { - s6Importer->LoadFromStream(&stream, true); - s6Importer->Import(); - - game_fix_save_vars(); - sprite_position_tween_reset(); - result = true; - } - catch (ObjectLoadException) - { - gErrorType = ERROR_TYPE_FILE_LOAD; - gErrorStringId = STR_GAME_SAVE_FAILED; - } - catch (IOException) - { - gErrorType = ERROR_TYPE_FILE_LOAD; - gErrorStringId = STR_GAME_SAVE_FAILED; - } - catch (Exception) - { - gErrorType = ERROR_TYPE_FILE_LOAD; - gErrorStringId = STR_FILE_CONTAINS_INVALID_DATA; - } - delete s6Importer; - - gScreenAge = 0; - gLastAutoSaveUpdate = AUTOSAVE_PAUSE; - return result; - } - /** * * rct2: 0x00676053 @@ -561,63 +525,4 @@ extern "C" gLastAutoSaveUpdate = AUTOSAVE_PAUSE; return result; } - - sint32 game_load_network(SDL_RWops* rw) - { - bool result = false; - auto stream = FileStream(rw, FILE_MODE_OPEN); - auto s6Importer = new S6Importer(); - try - { - s6Importer->LoadFromStream(&stream, false); - s6Importer->Import(); - - sprite_position_tween_reset(); - result = true; - } - catch (const ObjectLoadException &) - { - } - catch (const Exception &) - { - } - delete s6Importer; - - if (!result) - { - return 0; - } - - // Read checksum - uint32 checksum; - SDL_RWread(rw, &checksum, sizeof(uint32), 1); - - // Read other data not in normal save files - SDL_RWread(rw, gSpriteSpatialIndex, 0x10001 * sizeof(uint16), 1); - gGamePaused = SDL_ReadLE32(rw); - _guestGenerationProbability = SDL_ReadLE32(rw); - _suggestedGuestMaximum = SDL_ReadLE32(rw); - gCheatsSandboxMode = SDL_ReadU8(rw) != 0; - gCheatsDisableClearanceChecks = SDL_ReadU8(rw) != 0; - gCheatsDisableSupportLimits = SDL_ReadU8(rw) != 0; - gCheatsDisableTrainLengthLimit = SDL_ReadU8(rw) != 0; - gCheatsEnableChainLiftOnAllTrack = SDL_ReadU8(rw) != 0; - gCheatsShowAllOperatingModes = SDL_ReadU8(rw) != 0; - gCheatsShowVehiclesFromOtherTrackTypes = SDL_ReadU8(rw) != 0; - gCheatsFastLiftHill = SDL_ReadU8(rw) != 0; - gCheatsDisableBrakesFailure = SDL_ReadU8(rw) != 0; - gCheatsDisableAllBreakdowns = SDL_ReadU8(rw) != 0; - gCheatsUnlockAllPrices = SDL_ReadU8(rw) != 0; - gCheatsBuildInPauseMode = SDL_ReadU8(rw) != 0; - gCheatsIgnoreRideIntensity = SDL_ReadU8(rw) != 0; - gCheatsDisableVandalism = SDL_ReadU8(rw) != 0; - gCheatsDisableLittering = SDL_ReadU8(rw) != 0; - gCheatsNeverendingMarketing = SDL_ReadU8(rw) != 0; - gCheatsFreezeClimate = SDL_ReadU8(rw) != 0; - gCheatsDisablePlantAging = SDL_ReadU8(rw) != 0; - gCheatsAllowArbitraryRideTypeChanges = SDL_ReadU8(rw) != 0; - - gLastAutoSaveUpdate = AUTOSAVE_PAUSE; - return 1; - } } diff --git a/src/openrct2/scenario/scenario.h b/src/openrct2/scenario/scenario.h index 7c4a2b4026..6456a5cd9a 100644 --- a/src/openrct2/scenario/scenario.h +++ b/src/openrct2/scenario/scenario.h @@ -376,7 +376,6 @@ extern uint32 gLastAutoSaveUpdate; extern const char *_scenarioFileName; -bool scenario_load_rw(SDL_RWops * rw); sint32 scenario_load(const char *path); sint32 scenario_load_and_play_from_path(const char *path); void scenario_begin(); diff --git a/src/openrct2/title/TitleSequence.cpp b/src/openrct2/title/TitleSequence.cpp index 2181254a74..2154fb99c6 100644 --- a/src/openrct2/title/TitleSequence.cpp +++ b/src/openrct2/title/TitleSequence.cpp @@ -15,7 +15,6 @@ #pragma endregion #include -#include #include "../common.h" #include "../core/Collections.hpp" #include "../core/Console.hpp" @@ -39,7 +38,7 @@ static std::vector GetSaves(const utf8 * path); static std::vector GetSaves(IZipArchive * zip); static std::vector LegacyScriptRead(utf8 * script, size_t scriptLength, std::vector saves); -static void LegacyScriptGetLine(SDL_RWops * file, char * parts); +static void LegacyScriptGetLine(IStream * stream, char * parts); static void * ReadScriptFile(const utf8 * path, size_t * outSize); static utf8 * LegacyScriptWrite(TitleSequence * seq); @@ -392,10 +391,11 @@ static std::vector GetSaves(IZipArchive * zip) static std::vector LegacyScriptRead(utf8 * script, size_t scriptLength, std::vector saves) { std::vector commands; - SDL_RWops * file = SDL_RWFromMem(script, (sint32)scriptLength); - do { + auto fs = MemoryStream(script, scriptLength); + do + { char parts[3 * 128], *token, *part1, *part2; - LegacyScriptGetLine(file, parts); + LegacyScriptGetLine(&fs, parts); token = &parts[0 * 128]; part1 = &parts[1 * 128]; @@ -466,13 +466,12 @@ static std::vector LegacyScriptRead(utf8 * script, size_t scriptLe { commands.push_back(command); } - } while (SDL_RWtell(file) < (sint32)scriptLength); - SDL_RWclose(file); - + } + while (fs.GetPosition() < scriptLength); return commands; } -static void LegacyScriptGetLine(SDL_RWops * file, char * parts) +static void LegacyScriptGetLine(IStream * stream, char * parts) { for (sint32 i = 0; i < 3; i++) { @@ -486,7 +485,7 @@ static void LegacyScriptGetLine(SDL_RWops * file, char * parts) for (; part < 3;) { sint32 c = 0; - if (SDL_RWread(file, &c, 1, 1) != 1) + if (stream->TryRead(&c, 1) != 1) { c = EOF; } diff --git a/src/openrct2/title/TitleSequence.h b/src/openrct2/title/TitleSequence.h index 924adb687e..259d2354fd 100644 --- a/src/openrct2/title/TitleSequence.h +++ b/src/openrct2/title/TitleSequence.h @@ -18,8 +18,6 @@ #include "../common.h" -struct SDL_RWops; - typedef struct TitleCommand { uint8 Type; diff --git a/src/openrct2/util/util.c b/src/openrct2/util/util.c index 62616f8f52..514b7d8270 100644 --- a/src/openrct2/util/util.c +++ b/src/openrct2/util/util.c @@ -495,7 +495,7 @@ uint8 *util_zlib_inflate(uint8 *data, size_t data_in_size, size_t *data_out_size * @return Returns a pointer to memory holding compressed data or NULL on failure. * @note It is caller's responsibility to free() the returned pointer once done with it. */ -uint8 *util_zlib_deflate(uint8 *data, size_t data_in_size, size_t *data_out_size) +uint8 *util_zlib_deflate(const uint8 *data, size_t data_in_size, size_t *data_out_size) { sint32 ret = Z_OK; uLongf out_size = (uLongf)*data_out_size; diff --git a/src/openrct2/util/util.h b/src/openrct2/util/util.h index f33b483d7b..34d00a35b7 100644 --- a/src/openrct2/util/util.h +++ b/src/openrct2/util/util.h @@ -53,7 +53,7 @@ bool str_is_null_or_empty(const char *str); void util_srand(sint32 source); uint32 util_rand(); -uint8 *util_zlib_deflate(uint8 *data, size_t data_in_size, size_t *data_out_size); +uint8 *util_zlib_deflate(const uint8 *data, size_t data_in_size, size_t *data_out_size); uint8 *util_zlib_inflate(uint8 *data, size_t data_in_size, size_t *data_out_size); #endif