mirror of https://github.com/OpenRCT2/OpenRCT2.git
Add sea decryption
This commit is contained in:
parent
0e788918e2
commit
8c81cacc6f
|
@ -13,6 +13,7 @@
|
|||
- Feature: [#11788] Command to extract images from a .DAT file.
|
||||
- Feature: [#11959] Hacked go-kart tracks can now use 2x2 bends, 3x3 bends and S-bends.
|
||||
- Feature: [#12090] Boosters for the Wooden Roller Coaster (if the "Show all track pieces" cheat is enabled).
|
||||
- Feature: [#12184] .sea (RCT Classic) scenario files can now be imported.
|
||||
- Change: [#11209] Warn when user is running OpenRCT2 through Wine.
|
||||
- Change: [#11358] Switch copy and paste button positions in tile inspector.
|
||||
- Change: [#11449] Remove complete circuit requirement from Air Powered Vertical Coaster (for RCT1 parity).
|
||||
|
|
|
@ -150,7 +150,7 @@ static std::vector<LoadSaveListItem> _listItems;
|
|||
static char _directory[MAX_PATH];
|
||||
static char _shortenedDirectory[MAX_PATH];
|
||||
static char _parentDirectory[MAX_PATH];
|
||||
static char _extension[32];
|
||||
static char _extension[256];
|
||||
static char _defaultName[MAX_PATH];
|
||||
static int32_t _type;
|
||||
|
||||
|
@ -218,10 +218,10 @@ static const char* getFilterPatternByType(const int32_t type, const bool isSave)
|
|||
switch (type & 0x0E)
|
||||
{
|
||||
case LOADSAVETYPE_GAME:
|
||||
return isSave ? "*.sv6" : "*.sv6;*.sc6;*.sc4;*.sv4;*.sv7";
|
||||
return isSave ? "*.sv6" : "*.sv6;*.sc6;*.sc4;*.sv4;*.sv7;*.sea;";
|
||||
|
||||
case LOADSAVETYPE_LANDSCAPE:
|
||||
return isSave ? "*.sc6" : "*.sc6;*.sv6;*.sc4;*.sv4;*.sv7";
|
||||
return isSave ? "*.sc6" : "*.sc6;*.sv6;*.sc4;*.sv4;*.sv7;*.sea;";
|
||||
|
||||
case LOADSAVETYPE_SCENARIO:
|
||||
return "*.sc6";
|
||||
|
|
|
@ -541,8 +541,17 @@ namespace OpenRCT2
|
|||
log_verbose("Context::LoadParkFromFile(%s)", path.c_str());
|
||||
try
|
||||
{
|
||||
auto fs = FileStream(path, FILE_MODE_OPEN);
|
||||
return LoadParkFromStream(&fs, path, loadTitleScreenOnFail);
|
||||
if (String::Equals(Path::GetExtension(path), ".sea", true))
|
||||
{
|
||||
auto data = DecryptSea(fs::u8path(path));
|
||||
auto ms = MemoryStream(data.data(), data.size(), MEMORY_ACCESS::READ);
|
||||
return LoadParkFromStream(&ms, path, loadTitleScreenOnFail);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto fs = FileStream(path, FILE_MODE_OPEN);
|
||||
return LoadParkFromStream(&fs, path, loadTitleScreenOnFail);
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
|
|
|
@ -629,6 +629,7 @@
|
|||
<ClCompile Include="rct1\Tables.cpp" />
|
||||
<ClCompile Include="rct2\S6Exporter.cpp" />
|
||||
<ClCompile Include="rct2\S6Importer.cpp" />
|
||||
<ClCompile Include="rct2\SeaDecrypt.cpp" />
|
||||
<ClCompile Include="rct2\T6Exporter.cpp" />
|
||||
<ClCompile Include="rct2\T6Importer.cpp" />
|
||||
<ClCompile Include="ReplayManager.cpp" />
|
||||
|
|
|
@ -10,11 +10,14 @@
|
|||
#pragma once
|
||||
|
||||
#include "../common.h"
|
||||
#include "../core/FileSystem.hpp"
|
||||
#include "../object/Object.h"
|
||||
#include "../rct12/RCT12.h"
|
||||
#include "../ride/RideRatings.h"
|
||||
#include "../ride/Vehicle.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
constexpr const uint8_t RCT2_MAX_STAFF = 200;
|
||||
constexpr const uint8_t RCT2_MAX_BANNERS_IN_PARK = 250;
|
||||
constexpr const uint8_t RCT2_MAX_VEHICLES_PER_RIDE = 31;
|
||||
|
@ -760,3 +763,5 @@ struct RCT2RideRatingCalculationData
|
|||
assert_struct_size(RCT2RideRatingCalculationData, 76);
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
std::vector<uint8_t> DecryptSea(const fs::path& path);
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
/*****************************************************************************
|
||||
* Copyright (c) 2014-2020 OpenRCT2 developers
|
||||
*
|
||||
* For a complete list of all authors, please refer to contributors.md
|
||||
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||
*
|
||||
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||
*****************************************************************************/
|
||||
|
||||
#include "../common.h"
|
||||
#include "../core/File.h"
|
||||
#include "../core/Path.hpp"
|
||||
#include "RCT2.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
|
||||
constexpr int32_t MASK_SIZE = 0x1000;
|
||||
|
||||
struct EncryptionKey
|
||||
{
|
||||
uint32_t Seed0{};
|
||||
uint32_t Seed1{};
|
||||
};
|
||||
|
||||
static EncryptionKey GetEncryptionKey(const std::string_view& fileName)
|
||||
{
|
||||
auto fileNameLen = static_cast<int32_t>(fileName.size());
|
||||
uint32_t s0 = 0;
|
||||
for (int i = fileNameLen - 1; i >= 0; i--)
|
||||
{
|
||||
s0 = (s0 + (s0 << 5)) ^ fileName[i];
|
||||
}
|
||||
|
||||
uint32_t s1 = 0;
|
||||
for (int i = 0; i < fileNameLen; i++)
|
||||
{
|
||||
s1 = (s1 + (s1 << 5)) ^ fileName[i];
|
||||
}
|
||||
|
||||
return EncryptionKey{ s0, s1 };
|
||||
}
|
||||
|
||||
static std::unique_ptr<uint8_t[]> CreateMask(const EncryptionKey& key)
|
||||
{
|
||||
auto result = std::make_unique<uint8_t[]>(MASK_SIZE);
|
||||
auto dst8 = result.get();
|
||||
uint32_t seed0 = key.Seed0;
|
||||
uint32_t seed1 = key.Seed1;
|
||||
int32_t i = MASK_SIZE;
|
||||
while (i > 0)
|
||||
{
|
||||
uint32_t s0 = seed0;
|
||||
uint32_t s1 = seed1 ^ 0xF7654321;
|
||||
seed0 = rol32(s1, 25) + s0;
|
||||
seed1 = rol32(s0, 29);
|
||||
*dst8++ = (s0 >> 3) & 0xFF;
|
||||
if (i >= 2)
|
||||
{
|
||||
*dst8++ = (s0 >> 11) & 0xFF;
|
||||
if (i >= 3)
|
||||
{
|
||||
*dst8++ = (s0 >> 19) & 0xFF;
|
||||
if (i >= 4)
|
||||
{
|
||||
*dst8++ = (seed1 >> 24) & 0xFF;
|
||||
i -= 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void Decrypt(std::vector<uint8_t>& data, const EncryptionKey& key)
|
||||
{
|
||||
auto mask = CreateMask(key);
|
||||
const uint8_t* mask8 = (const uint8_t*)mask.get();
|
||||
|
||||
uint32_t b = 0;
|
||||
uint32_t c = 0;
|
||||
for (size_t i = 0; i < data.size(); i++)
|
||||
{
|
||||
auto a = b % MASK_SIZE;
|
||||
c = c % MASK_SIZE;
|
||||
b = (a + 1) % MASK_SIZE;
|
||||
|
||||
data[i] = (((data[i] - mask8[b]) ^ mask8[c]) + mask8[a]) & 0xFF;
|
||||
|
||||
c += 3;
|
||||
b = a + 7;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> DecryptSea(const fs::path& path)
|
||||
{
|
||||
auto key = GetEncryptionKey(path.filename().u8string());
|
||||
auto data = File::ReadAllBytes(path.u8string());
|
||||
|
||||
// Last 4 bytes is the checksum
|
||||
size_t inputSize = data.size() - 4;
|
||||
uint32_t checksum;
|
||||
std::memcpy(&checksum, data.data() + inputSize, sizeof(checksum));
|
||||
data.resize(inputSize);
|
||||
|
||||
Decrypt(data, key);
|
||||
return data;
|
||||
}
|
Loading…
Reference in New Issue