diff --git a/src/ZoneCommon/Game/IW4/ZoneConstantsIW4.h b/src/ZoneCommon/Game/IW4/ZoneConstantsIW4.h new file mode 100644 index 00000000..e69de29b diff --git a/src/ZoneCommon/Game/T6/ZoneConstantsT6.h b/src/ZoneCommon/Game/T6/ZoneConstantsT6.h new file mode 100644 index 00000000..d872093f --- /dev/null +++ b/src/ZoneCommon/Game/T6/ZoneConstantsT6.h @@ -0,0 +1,83 @@ +#pragma once +#include +#include + +#include "Zone/ZoneTypes.h" +#include "Game/T6/T6.h" + +namespace T6 +{ + class ZoneConstants final + { + ZoneConstants() = default; + + public: + static constexpr const char* MAGIC_SIGNED_TREYARCH = "TAff0100"; + static constexpr const char* MAGIC_SIGNED_OAT = "ABff0100"; + static constexpr const char* MAGIC_UNSIGNED = "TAffu100"; + static constexpr const char* MAGIC_UNSIGNED_SERVER = "TAsvu100"; + + static_assert(std::char_traits::length(MAGIC_SIGNED_TREYARCH) == sizeof(ZoneHeader::m_magic)); + static_assert(std::char_traits::length(MAGIC_SIGNED_OAT) == sizeof(ZoneHeader::m_magic)); + static_assert(std::char_traits::length(MAGIC_UNSIGNED) == sizeof(ZoneHeader::m_magic)); + static_assert(std::char_traits::length(MAGIC_UNSIGNED_SERVER) == sizeof(ZoneHeader::m_magic)); + + static constexpr int ZONE_VERSION = 147; + static constexpr int STREAM_COUNT = 4; + static constexpr int XCHUNK_SIZE = 0x8000; + static constexpr int VANILLA_BUFFER_SIZE = 0x80000; + static constexpr int OFFSET_BLOCK_BIT_COUNT = 3; + static constexpr block_t INSERT_BLOCK = XFILE_BLOCK_VIRTUAL; + + static constexpr const char* MAGIC_AUTH_HEADER = "PHEEBs71"; + inline static const uint8_t SALSA20_KEY_TREYARCH[] + { + 0x64, 0x1D, 0x8A, 0x2F, + 0xE3, 0x1D, 0x3A, 0xA6, + 0x36, 0x22, 0xBB, 0xC9, + 0xCE, 0x85, 0x87, 0x22, + 0x9D, 0x42, 0xB0, 0xF8, + 0xED, 0x9B, 0x92, 0x41, + 0x30, 0xBF, 0x88, 0xB6, + 0x5E, 0xDC, 0x50, 0xBE + }; + + inline static const uint8_t RSA_PUBLIC_KEY_TREYARCH[] + { + 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, + 0x00, 0xc7, 0x9d, 0x33, 0xe0, 0x75, 0xaf, 0xef, + 0x08, 0x08, 0x2b, 0x89, 0xd9, 0x3b, 0xf3, 0xd5, + 0x9a, 0x65, 0xa6, 0xde, 0x3b, 0x1e, 0x20, 0xde, + 0x59, 0x19, 0x43, 0x88, 0x1a, 0x8b, 0x39, 0x13, + 0x60, 0x12, 0xd3, 0xb2, 0x77, 0x6d, 0xe1, 0x99, + 0x75, 0x24, 0xb4, 0x0d, 0x8c, 0xb7, 0x84, 0xf2, + 0x48, 0x8f, 0xd5, 0x4c, 0xb7, 0x64, 0x44, 0xa3, + 0xa8, 0x4a, 0xac, 0x2d, 0x54, 0x15, 0x2b, 0x1f, + 0xb3, 0xf4, 0x4c, 0x16, 0xa0, 0x92, 0x8e, 0xd2, + 0xfa, 0xcc, 0x11, 0x6a, 0x74, 0x6a, 0x70, 0xb8, + 0xd3, 0x34, 0x6b, 0x39, 0xc6, 0x2a, 0x69, 0xde, + 0x31, 0x34, 0xdf, 0xe7, 0x8b, 0x7e, 0x17, 0xa3, + 0x17, 0xd9, 0x5e, 0x88, 0x39, 0x21, 0xf8, 0x7d, + 0x3c, 0x29, 0x21, 0x6c, 0x0e, 0xf1, 0xb4, 0x09, + 0x54, 0xe8, 0x20, 0x34, 0x90, 0x2e, 0xb4, 0x1a, + 0x95, 0x95, 0x90, 0xe5, 0xfb, 0xce, 0xfe, 0x8a, + 0xbf, 0xea, 0xaf, 0x09, 0x0c, 0x0b, 0x87, 0x22, + 0xe1, 0xfe, 0x82, 0x6e, 0x91, 0xe8, 0xd1, 0xb6, + 0x35, 0x03, 0x4f, 0xdb, 0xc1, 0x31, 0xe2, 0xba, + 0xa0, 0x13, 0xf6, 0xdb, 0x07, 0x9b, 0xcb, 0x99, + 0xce, 0x9f, 0x49, 0xc4, 0x51, 0x8e, 0xf1, 0x04, + 0x9b, 0x30, 0xc3, 0x02, 0xff, 0x7b, 0x94, 0xca, + 0x12, 0x69, 0x1e, 0xdb, 0x2d, 0x3e, 0xbd, 0x48, + 0x16, 0xe1, 0x72, 0x37, 0xb8, 0x5f, 0x61, 0xfa, + 0x24, 0x16, 0x3a, 0xde, 0xbf, 0x6a, 0x71, 0x62, + 0x32, 0xf3, 0xaa, 0x7f, 0x28, 0x3a, 0x0c, 0x27, + 0xeb, 0xa9, 0x0a, 0x4c, 0x79, 0x88, 0x84, 0xb3, + 0xe2, 0x52, 0xb9, 0x68, 0x1e, 0x82, 0xcf, 0x67, + 0x43, 0xf3, 0x68, 0xf7, 0x26, 0x19, 0xaa, 0xdd, + 0x3f, 0x1e, 0xc6, 0x46, 0x11, 0x9f, 0x24, 0x23, + 0xa7, 0xb0, 0x1b, 0x79, 0xa7, 0x0c, 0x5a, 0xfe, + 0x96, 0xf7, 0xe7, 0x88, 0x09, 0xa6, 0x69, 0xe3, + 0x8b, 0x02, 0x03, 0x01, 0x00, 0x01 + }; + }; +} \ No newline at end of file diff --git a/src/ZoneLoading/Loading/ICapturedDataProvider.h b/src/ZoneCommon/Utils/ICapturedDataProvider.h similarity index 100% rename from src/ZoneLoading/Loading/ICapturedDataProvider.h rename to src/ZoneCommon/Utils/ICapturedDataProvider.h diff --git a/src/ZoneCommon/Zone/Stream/IZoneStream.h b/src/ZoneCommon/Zone/Stream/IZoneStream.h index 8a87ed60..cefdf803 100644 --- a/src/ZoneCommon/Zone/Stream/IZoneStream.h +++ b/src/ZoneCommon/Zone/Stream/IZoneStream.h @@ -4,7 +4,12 @@ class IZoneStream { public: + IZoneStream() = default; virtual ~IZoneStream() = default; + IZoneStream(const IZoneStream& other) = default; + IZoneStream(IZoneStream&& other) noexcept = default; + IZoneStream& operator=(const IZoneStream& other) = default; + IZoneStream& operator=(IZoneStream&& other) noexcept = default; virtual void PushBlock(block_t block) = 0; virtual block_t PopBlock() = 0; diff --git a/src/ZoneLoading/Game/T6/ZoneLoaderFactoryT6.cpp b/src/ZoneLoading/Game/T6/ZoneLoaderFactoryT6.cpp index d367a57c..b8100dde 100644 --- a/src/ZoneLoading/Game/T6/ZoneLoaderFactoryT6.cpp +++ b/src/ZoneLoading/Game/T6/ZoneLoaderFactoryT6.cpp @@ -4,6 +4,7 @@ #include #include "Game/T6/T6.h" +#include "Game/T6/ZoneConstantsT6.h" #include "Utils/ClassUtils.h" #include "ContentLoaderT6.h" @@ -21,81 +22,19 @@ #include "Loading/Steps/StepAddProcessor.h" #include "Loading/Steps/StepAllocXBlocks.h" #include "Loading/Steps/StepLoadZoneContent.h" +#include "Loading/Steps/StepLoadZoneSizes.h" using namespace T6; -const std::string ZoneLoaderFactory::MAGIC_SIGNED_TREYARCH = "TAff0100"; -const std::string ZoneLoaderFactory::MAGIC_SIGNED_ASSET_BUILDER = "ABff0100"; -const std::string ZoneLoaderFactory::MAGIC_UNSIGNED = "TAffu100"; -const std::string ZoneLoaderFactory::MAGIC_UNSIGNED_SERVER = "TAsvu100"; -const int ZoneLoaderFactory::VERSION = 147; - -const int ZoneLoaderFactory::STREAM_COUNT = 4; -const int ZoneLoaderFactory::XCHUNK_SIZE = 0x8000; -const int ZoneLoaderFactory::VANILLA_BUFFER_SIZE = 0x80000; -const int ZoneLoaderFactory::OFFSET_BLOCK_BIT_COUNT = 3; -const block_t ZoneLoaderFactory::INSERT_BLOCK = T6::XFILE_BLOCK_VIRTUAL; - -const std::string ZoneLoaderFactory::MAGIC_AUTH_HEADER = "PHEEBs71"; -const uint8_t ZoneLoaderFactory::SALSA20_KEY_TREYARCH[] -{ - 0x64, 0x1D, 0x8A, 0x2F, - 0xE3, 0x1D, 0x3A, 0xA6, - 0x36, 0x22, 0xBB, 0xC9, - 0xCE, 0x85, 0x87, 0x22, - 0x9D, 0x42, 0xB0, 0xF8, - 0xED, 0x9B, 0x92, 0x41, - 0x30, 0xBF, 0x88, 0xB6, - 0x5E, 0xDC, 0x50, 0xBE -}; - -const uint8_t ZoneLoaderFactory::RSA_PUBLIC_KEY_TREYARCH[] -{ - 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, - 0x00, 0xc7, 0x9d, 0x33, 0xe0, 0x75, 0xaf, 0xef, - 0x08, 0x08, 0x2b, 0x89, 0xd9, 0x3b, 0xf3, 0xd5, - 0x9a, 0x65, 0xa6, 0xde, 0x3b, 0x1e, 0x20, 0xde, - 0x59, 0x19, 0x43, 0x88, 0x1a, 0x8b, 0x39, 0x13, - 0x60, 0x12, 0xd3, 0xb2, 0x77, 0x6d, 0xe1, 0x99, - 0x75, 0x24, 0xb4, 0x0d, 0x8c, 0xb7, 0x84, 0xf2, - 0x48, 0x8f, 0xd5, 0x4c, 0xb7, 0x64, 0x44, 0xa3, - 0xa8, 0x4a, 0xac, 0x2d, 0x54, 0x15, 0x2b, 0x1f, - 0xb3, 0xf4, 0x4c, 0x16, 0xa0, 0x92, 0x8e, 0xd2, - 0xfa, 0xcc, 0x11, 0x6a, 0x74, 0x6a, 0x70, 0xb8, - 0xd3, 0x34, 0x6b, 0x39, 0xc6, 0x2a, 0x69, 0xde, - 0x31, 0x34, 0xdf, 0xe7, 0x8b, 0x7e, 0x17, 0xa3, - 0x17, 0xd9, 0x5e, 0x88, 0x39, 0x21, 0xf8, 0x7d, - 0x3c, 0x29, 0x21, 0x6c, 0x0e, 0xf1, 0xb4, 0x09, - 0x54, 0xe8, 0x20, 0x34, 0x90, 0x2e, 0xb4, 0x1a, - 0x95, 0x95, 0x90, 0xe5, 0xfb, 0xce, 0xfe, 0x8a, - 0xbf, 0xea, 0xaf, 0x09, 0x0c, 0x0b, 0x87, 0x22, - 0xe1, 0xfe, 0x82, 0x6e, 0x91, 0xe8, 0xd1, 0xb6, - 0x35, 0x03, 0x4f, 0xdb, 0xc1, 0x31, 0xe2, 0xba, - 0xa0, 0x13, 0xf6, 0xdb, 0x07, 0x9b, 0xcb, 0x99, - 0xce, 0x9f, 0x49, 0xc4, 0x51, 0x8e, 0xf1, 0x04, - 0x9b, 0x30, 0xc3, 0x02, 0xff, 0x7b, 0x94, 0xca, - 0x12, 0x69, 0x1e, 0xdb, 0x2d, 0x3e, 0xbd, 0x48, - 0x16, 0xe1, 0x72, 0x37, 0xb8, 0x5f, 0x61, 0xfa, - 0x24, 0x16, 0x3a, 0xde, 0xbf, 0x6a, 0x71, 0x62, - 0x32, 0xf3, 0xaa, 0x7f, 0x28, 0x3a, 0x0c, 0x27, - 0xeb, 0xa9, 0x0a, 0x4c, 0x79, 0x88, 0x84, 0xb3, - 0xe2, 0x52, 0xb9, 0x68, 0x1e, 0x82, 0xcf, 0x67, - 0x43, 0xf3, 0x68, 0xf7, 0x26, 0x19, 0xaa, 0xdd, - 0x3f, 0x1e, 0xc6, 0x46, 0x11, 0x9f, 0x24, 0x23, - 0xa7, 0xb0, 0x1b, 0x79, 0xa7, 0x0c, 0x5a, 0xfe, - 0x96, 0xf7, 0xe7, 0x88, 0x09, 0xa6, 0x69, 0xe3, - 0x8b, 0x02, 0x03, 0x01, 0x00, 0x01 -}; - class ZoneLoaderFactory::Impl { static GameLanguage GetZoneLanguage(std::string& zoneName) { auto languagePrefixes = g_GameT6.GetLanguagePrefixes(); - for(const auto& languagePrefix : languagePrefixes) + for (const auto& languagePrefix : languagePrefixes) { - if(zoneName.compare(0, languagePrefix.m_prefix.length(), languagePrefix.m_prefix) == 0) + if (zoneName.compare(0, languagePrefix.m_prefix.length(), languagePrefix.m_prefix) == 0) { return languagePrefix.m_language; } @@ -109,20 +48,20 @@ class ZoneLoaderFactory::Impl assert(isSecure != nullptr); assert(isOfficial != nullptr); - if(header.m_version != VERSION) + if (header.m_version != ZoneConstants::ZONE_VERSION) { return false; } - if(!memcmp(header.m_magic, MAGIC_SIGNED_TREYARCH.c_str(), 8)) + if (!memcmp(header.m_magic, ZoneConstants::MAGIC_SIGNED_TREYARCH, 8)) { *isSecure = true; *isOfficial = true; *isEncrypted = true; return true; } - - if(!memcmp(header.m_magic, MAGIC_SIGNED_ASSET_BUILDER.c_str(), 8)) + + if (!memcmp(header.m_magic, ZoneConstants::MAGIC_SIGNED_OAT, 8)) { *isSecure = true; *isOfficial = false; @@ -130,7 +69,7 @@ class ZoneLoaderFactory::Impl return true; } - if(!memcmp(header.m_magic, MAGIC_UNSIGNED.c_str(), 8)) + if (!memcmp(header.m_magic, ZoneConstants::MAGIC_UNSIGNED, 8)) { *isSecure = false; *isOfficial = true; @@ -138,7 +77,7 @@ class ZoneLoaderFactory::Impl return true; } - if(!memcmp(header.m_magic, MAGIC_UNSIGNED_SERVER.c_str(), 8)) + if (!memcmp(header.m_magic, ZoneConstants::MAGIC_UNSIGNED_SERVER, 8)) { *isSecure = false; *isOfficial = true; @@ -167,11 +106,11 @@ class ZoneLoaderFactory::Impl static IPublicKeyAlgorithm* SetupRSA(const bool isOfficial) { - if(isOfficial) + if (isOfficial) { auto* rsa = Crypto::CreateRSA(IPublicKeyAlgorithm::HashingAlgorithm::RSA_HASH_SHA256, Crypto::RSAPaddingMode::RSA_PADDING_PSS); - if(!rsa->SetKey(RSA_PUBLIC_KEY_TREYARCH, sizeof(RSA_PUBLIC_KEY_TREYARCH))) + if (!rsa->SetKey(ZoneConstants::RSA_PUBLIC_KEY_TREYARCH, sizeof(ZoneConstants::RSA_PUBLIC_KEY_TREYARCH))) { printf("Invalid public key for signature checking\n"); @@ -193,10 +132,10 @@ class ZoneLoaderFactory::Impl static ISignatureProvider* AddAuthHeaderSteps(const bool isSecure, ZoneLoader* zoneLoader, std::string& fileName) { // Unsigned zones do not have an auth header - if(!isSecure) + if (!isSecure) return nullptr; - - zoneLoader->AddLoadingStep(std::make_unique(MAGIC_AUTH_HEADER.c_str())); + + zoneLoader->AddLoadingStep(std::make_unique(ZoneConstants::MAGIC_AUTH_HEADER)); zoneLoader->AddLoadingStep(std::make_unique(4)); // Loading Flags which are always zero zoneLoader->AddLoadingStep(std::make_unique(fileName, 32)); @@ -210,12 +149,13 @@ class ZoneLoaderFactory::Impl static ICapturedDataProvider* AddXChunkProcessor(bool isEncrypted, ZoneLoader* zoneLoader, std::string& fileName) { ICapturedDataProvider* result = nullptr; - auto xChunkProcessor = std::make_unique(STREAM_COUNT, XCHUNK_SIZE, VANILLA_BUFFER_SIZE); + auto xChunkProcessor = std::make_unique(ZoneConstants::STREAM_COUNT, ZoneConstants::XCHUNK_SIZE, ZoneConstants::VANILLA_BUFFER_SIZE); - if(isEncrypted) + if (isEncrypted) { // If zone is encrypted, the decryption is applied before the decompression. T6 Zones always use Salsa20. - auto chunkProcessorSalsa20 = std::make_unique(STREAM_COUNT, fileName, SALSA20_KEY_TREYARCH, sizeof(SALSA20_KEY_TREYARCH)); + auto chunkProcessorSalsa20 = std::make_unique(ZoneConstants::STREAM_COUNT, fileName, ZoneConstants::SALSA20_KEY_TREYARCH, + sizeof(ZoneConstants::SALSA20_KEY_TREYARCH)); result = chunkProcessorSalsa20.get(); xChunkProcessor->AddChunkProcessor(std::move(chunkProcessorSalsa20)); } @@ -236,14 +176,14 @@ public: bool isEncrypted; // Check if this file is a supported T6 zone. - if(!CanLoad(header, &isSecure, &isOfficial, &isEncrypted)) + if (!CanLoad(header, &isSecure, &isOfficial, &isEncrypted)) return nullptr; // Create new zone auto* zone = new Zone(fileName, 0, &g_GameT6); zone->m_pools = std::make_unique(zone, 0); zone->m_language = GetZoneLanguage(fileName); - + // File is supported. Now setup all required steps for loading this file. auto* zoneLoader = new ZoneLoader(zone); @@ -259,13 +199,13 @@ public: ICapturedDataProvider* signatureDataProvider = AddXChunkProcessor(isEncrypted, zoneLoader, fileName); // Start of the XFile struct - zoneLoader->AddLoadingStep(std::make_unique(8)); // Skip size and externalSize fields since they are not interesting for us + zoneLoader->AddLoadingStep(std::make_unique()); zoneLoader->AddLoadingStep(std::make_unique()); // Start of the zone content - zoneLoader->AddLoadingStep(std::make_unique(std::make_unique(), zone, OFFSET_BLOCK_BIT_COUNT, INSERT_BLOCK)); + zoneLoader->AddLoadingStep(std::make_unique(std::make_unique(), zone, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK)); - if(isSecure) + if (isSecure) { zoneLoader->AddLoadingStep(std::make_unique(rsa, signatureProvider, signatureDataProvider)); } @@ -278,4 +218,4 @@ public: ZoneLoader* ZoneLoaderFactory::CreateLoaderForHeader(ZoneHeader& header, std::string& fileName) { return Impl::CreateLoaderForHeader(header, fileName); -} \ No newline at end of file +} diff --git a/src/ZoneLoading/Game/T6/ZoneLoaderFactoryT6.h b/src/ZoneLoading/Game/T6/ZoneLoaderFactoryT6.h index 8554ae2b..4ff8af07 100644 --- a/src/ZoneLoading/Game/T6/ZoneLoaderFactoryT6.h +++ b/src/ZoneLoading/Game/T6/ZoneLoaderFactoryT6.h @@ -7,22 +7,6 @@ namespace T6 { class ZoneLoaderFactory final : public IZoneLoaderFactory { - static const std::string MAGIC_SIGNED_TREYARCH; - static const std::string MAGIC_SIGNED_ASSET_BUILDER; - static const std::string MAGIC_UNSIGNED; - static const std::string MAGIC_UNSIGNED_SERVER; - static const int VERSION; - - static const int STREAM_COUNT; - static const int XCHUNK_SIZE; - static const int VANILLA_BUFFER_SIZE; - static const int OFFSET_BLOCK_BIT_COUNT; - static const block_t INSERT_BLOCK; - - static const std::string MAGIC_AUTH_HEADER; - static const uint8_t SALSA20_KEY_TREYARCH[]; - static const uint8_t RSA_PUBLIC_KEY_TREYARCH[]; - class Impl; public: diff --git a/src/ZoneLoading/Loading/LoadingFileStream.h b/src/ZoneLoading/Loading/LoadingFileStream.h index cd334855..21a7cc32 100644 --- a/src/ZoneLoading/Loading/LoadingFileStream.h +++ b/src/ZoneLoading/Loading/LoadingFileStream.h @@ -1,5 +1,4 @@ #pragma once - #include #include "ILoadingStream.h" diff --git a/src/ZoneLoading/Loading/Processor/ProcessorCaptureData.h b/src/ZoneLoading/Loading/Processor/ProcessorCaptureData.h index 1c827404..28f46bd8 100644 --- a/src/ZoneLoading/Loading/Processor/ProcessorCaptureData.h +++ b/src/ZoneLoading/Loading/Processor/ProcessorCaptureData.h @@ -2,7 +2,7 @@ #include #include "Loading/StreamProcessor.h" -#include "Loading/ICapturedDataProvider.h" +#include "Utils/ICapturedDataProvider.h" class ProcessorCaptureData final : public StreamProcessor, public ICapturedDataProvider { diff --git a/src/ZoneLoading/Loading/Processor/XChunks/ChunkProcessorSalsa20.h b/src/ZoneLoading/Loading/Processor/XChunks/ChunkProcessorSalsa20.h index 7ddb4a3f..4868268e 100644 --- a/src/ZoneLoading/Loading/Processor/XChunks/ChunkProcessorSalsa20.h +++ b/src/ZoneLoading/Loading/Processor/XChunks/ChunkProcessorSalsa20.h @@ -1,6 +1,6 @@ #pragma once #include "IXChunkProcessor.h" -#include "Loading/ICapturedDataProvider.h" +#include "Utils/ICapturedDataProvider.h" #include class ChunkProcessorSalsa20 : public IXChunkProcessor, public ICapturedDataProvider diff --git a/src/ZoneLoading/Loading/Steps/StepLoadHash.h b/src/ZoneLoading/Loading/Steps/StepLoadHash.h index 8d1e8652..bc5dbe57 100644 --- a/src/ZoneLoading/Loading/Steps/StepLoadHash.h +++ b/src/ZoneLoading/Loading/Steps/StepLoadHash.h @@ -2,7 +2,7 @@ #include -#include "Loading/ICapturedDataProvider.h" +#include "Utils/ICapturedDataProvider.h" #include "Loading/ILoadingStep.h" #include "Loading/IHashProvider.h" diff --git a/src/ZoneLoading/Loading/Steps/StepLoadZoneSizes.cpp b/src/ZoneLoading/Loading/Steps/StepLoadZoneSizes.cpp new file mode 100644 index 00000000..b9cd87e6 --- /dev/null +++ b/src/ZoneLoading/Loading/Steps/StepLoadZoneSizes.cpp @@ -0,0 +1,23 @@ +#include "StepLoadZoneSizes.h" + +StepLoadZoneSizes::StepLoadZoneSizes() + : m_size(0), + m_external_size(0) +{ +} + +void StepLoadZoneSizes::PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream) +{ + stream->Load(&m_size, sizeof(m_size)); + stream->Load(&m_external_size, sizeof(m_external_size)); +} + +size_t StepLoadZoneSizes::GetSize() const +{ + return m_size; +} + +size_t StepLoadZoneSizes::GetExternalSize() const +{ + return m_external_size; +} diff --git a/src/ZoneLoading/Loading/Steps/StepLoadZoneSizes.h b/src/ZoneLoading/Loading/Steps/StepLoadZoneSizes.h new file mode 100644 index 00000000..eac0c3cb --- /dev/null +++ b/src/ZoneLoading/Loading/Steps/StepLoadZoneSizes.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +#include "Utils/ClassUtils.h" +#include "Loading/ILoadingStep.h" + +class StepLoadZoneSizes final : public ILoadingStep +{ + size_t m_size; + size_t m_external_size; + +public: + StepLoadZoneSizes(); + + void PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream) override; + + _NODISCARD size_t GetSize() const; + _NODISCARD size_t GetExternalSize() const; +}; diff --git a/src/ZoneLoading/Loading/Steps/StepVerifyHash.h b/src/ZoneLoading/Loading/Steps/StepVerifyHash.h index 397cb5fb..bc3bcb7b 100644 --- a/src/ZoneLoading/Loading/Steps/StepVerifyHash.h +++ b/src/ZoneLoading/Loading/Steps/StepVerifyHash.h @@ -4,7 +4,7 @@ #include "Crypto.h" #include "Loading/ILoadingStep.h" -#include "Loading/ICapturedDataProvider.h" +#include "Utils/ICapturedDataProvider.h" #include "Loading/IHashProvider.h" class StepVerifyHash final : public ILoadingStep diff --git a/src/ZoneLoading/Loading/Steps/StepVerifySignature.h b/src/ZoneLoading/Loading/Steps/StepVerifySignature.h index 722190a6..fe8c60f0 100644 --- a/src/ZoneLoading/Loading/Steps/StepVerifySignature.h +++ b/src/ZoneLoading/Loading/Steps/StepVerifySignature.h @@ -3,7 +3,7 @@ #include "Loading/ILoadingStep.h" #include "Crypto.h" #include "Loading/ISignatureProvider.h" -#include "Loading/ICapturedDataProvider.h" +#include "Utils/ICapturedDataProvider.h" class StepVerifySignature final : public ILoadingStep { diff --git a/src/ZoneWriting/Game/IW4/ContentWriterIW4.cpp b/src/ZoneWriting/Game/IW4/ContentWriterIW4.cpp new file mode 100644 index 00000000..e69de29b diff --git a/src/ZoneWriting/Game/IW4/ContentWriterIW4.h b/src/ZoneWriting/Game/IW4/ContentWriterIW4.h new file mode 100644 index 00000000..e69de29b diff --git a/src/ZoneWriting/Game/IW4/ZoneWriterFactoryIW4.cpp b/src/ZoneWriting/Game/IW4/ZoneWriterFactoryIW4.cpp new file mode 100644 index 00000000..e69de29b diff --git a/src/ZoneWriting/Game/IW4/ZoneWriterFactoryIW4.h b/src/ZoneWriting/Game/IW4/ZoneWriterFactoryIW4.h new file mode 100644 index 00000000..9a8ac370 --- /dev/null +++ b/src/ZoneWriting/Game/IW4/ZoneWriterFactoryIW4.h @@ -0,0 +1,12 @@ +#pragma once +#include "Writing/IZoneWriterFactory.h" + +namespace IW4 +{ + class ZoneWriterFactory final : public IZoneWriterFactory + { + public: + _NODISCARD bool SupportsZone(Zone* zone) const override; + _NODISCARD std::unique_ptr CreateWriter(Zone* zone) const override; + }; +} diff --git a/src/ZoneWriting/Game/T6/ContentWriterT6.cpp b/src/ZoneWriting/Game/T6/ContentWriterT6.cpp new file mode 100644 index 00000000..e69de29b diff --git a/src/ZoneWriting/Game/T6/ContentWriterT6.h b/src/ZoneWriting/Game/T6/ContentWriterT6.h new file mode 100644 index 00000000..7800f742 --- /dev/null +++ b/src/ZoneWriting/Game/T6/ContentWriterT6.h @@ -0,0 +1,23 @@ +#pragma once +#include "Writing/ContentWriterBase.h" +#include "Writing/IContentWritingEntryPoint.h" +#include "Game/T6/T6.h" + +namespace T6 +{ + class ContentWriter final : public ContentWriterBase, public IContentWritingEntryPoint + { + XAsset* varXAsset; + ScriptStringList* varScriptStringList; + + void LoadScriptStringList(bool atStreamStart); + + void LoadXAsset(bool atStreamStart); + void LoadXAssetArray(bool atStreamStart, size_t count); + + public: + ContentWriter(); + + void WriteContent(Zone* zone, IZoneOutputStream* stream) override; + }; +} diff --git a/src/ZoneWriting/Game/T6/ZoneWriterFactoryT6.cpp b/src/ZoneWriting/Game/T6/ZoneWriterFactoryT6.cpp new file mode 100644 index 00000000..ce25f863 --- /dev/null +++ b/src/ZoneWriting/Game/T6/ZoneWriterFactoryT6.cpp @@ -0,0 +1,133 @@ +#include "ZoneWriterFactoryT6.h" + +#include + +#include "ContentWriterT6.h" +#include "Utils/ICapturedDataProvider.h" +#include "Game/T6/T6.h" +#include "Game/T6/GameT6.h" +#include "Game/T6/ZoneConstantsT6.h" +#include "Writing/Processor/OutputProcessorXChunks.h" +#include "Writing/Processor/XChunks/XChunkOutputProcessorDeflate.h" +#include "Writing/Processor/XChunks/XChunkOutputProcessorSalsa20.h" +#include "Writing/Steps/StepAddOutputProcessor.h" +#include "Writing/Steps/StepWriteXBlockSizes.h" +#include "Writing/Steps/StepWriteZoneContentToFile.h" +#include "Writing/Steps/StepWriteZoneContentToMemory.h" +#include "Writing/Steps/StepWriteZoneHeader.h" + +using namespace T6; + +class ZoneWriterFactory::Impl +{ + Zone* m_zone; + std::unique_ptr m_writer; + +public: + explicit Impl(Zone* zone) + : m_zone(zone), + m_writer(std::make_unique()) + { + } + + void SetupBlocks() const + { +#define XBLOCK_DEF(name, type) std::make_unique(STR(name), name, type) + + m_writer->AddXBlock(XBLOCK_DEF(T6::XFILE_BLOCK_TEMP, XBlock::Type::BLOCK_TYPE_TEMP)); + m_writer->AddXBlock(XBLOCK_DEF(T6::XFILE_BLOCK_RUNTIME_VIRTUAL, XBlock::Type::BLOCK_TYPE_RUNTIME)); + m_writer->AddXBlock(XBLOCK_DEF(T6::XFILE_BLOCK_RUNTIME_PHYSICAL, XBlock::Type::BLOCK_TYPE_RUNTIME)); + m_writer->AddXBlock(XBLOCK_DEF(T6::XFILE_BLOCK_DELAY_VIRTUAL, XBlock::Type::BLOCK_TYPE_DELAY)); + m_writer->AddXBlock(XBLOCK_DEF(T6::XFILE_BLOCK_DELAY_PHYSICAL, XBlock::Type::BLOCK_TYPE_DELAY)); + m_writer->AddXBlock(XBLOCK_DEF(T6::XFILE_BLOCK_VIRTUAL, XBlock::Type::BLOCK_TYPE_NORMAL)); + m_writer->AddXBlock(XBLOCK_DEF(T6::XFILE_BLOCK_PHYSICAL, XBlock::Type::BLOCK_TYPE_NORMAL)); + m_writer->AddXBlock(XBLOCK_DEF(T6::XFILE_BLOCK_STREAMER_RESERVE, XBlock::Type::BLOCK_TYPE_NORMAL)); + +#undef XBLOCK_DEF + } + + static ZoneHeader CreateHeaderForParams(const bool isSecure, const bool isOfficial, const bool isEncrypted) + { + ZoneHeader header{}; + header.m_version = ZoneConstants::ZONE_VERSION; + + if(isSecure) + { + if (isOfficial) + memcpy(header.m_magic, ZoneConstants::MAGIC_SIGNED_TREYARCH, sizeof(ZoneHeader::m_magic)); + else + memcpy(header.m_magic, ZoneConstants::MAGIC_SIGNED_OAT, sizeof(ZoneHeader::m_magic)); + } + else + { + if (isEncrypted) + memcpy(header.m_magic, ZoneConstants::MAGIC_UNSIGNED, sizeof(ZoneHeader::m_magic)); + else + memcpy(header.m_magic, ZoneConstants::MAGIC_UNSIGNED_SERVER, sizeof(ZoneHeader::m_magic)); + } + + return header; + } + + ICapturedDataProvider* AddXChunkProcessor(const bool isEncrypted) + { + ICapturedDataProvider* result = nullptr; + auto xChunkProcessor = std::make_unique(ZoneConstants::STREAM_COUNT, ZoneConstants::XCHUNK_SIZE, ZoneConstants::VANILLA_BUFFER_SIZE); + + if (isEncrypted) + { + // If zone is encrypted, the decryption is applied before the decompression. T6 Zones always use Salsa20. + auto chunkProcessorSalsa20 = std::make_unique(ZoneConstants::STREAM_COUNT, m_zone->m_name, ZoneConstants::SALSA20_KEY_TREYARCH, + sizeof(ZoneConstants::SALSA20_KEY_TREYARCH)); + result = chunkProcessorSalsa20.get(); + xChunkProcessor->AddChunkProcessor(std::move(chunkProcessorSalsa20)); + } + + // Decompress the chunks using zlib + xChunkProcessor->AddChunkProcessor(std::make_unique()); + m_writer->AddWritingStep(std::make_unique(std::move(xChunkProcessor))); + + // If there is encryption, the signed data of the zone is the final hash blocks provided by the Salsa20 IV adaption algorithm + return result; + } + + std::unique_ptr CreateWriter() + { + // TODO Support signed fastfiles + bool isSecure = false; + bool isEncrypted = true; + + SetupBlocks(); + + auto contentInMemory = std::make_unique(std::make_unique(), m_zone, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK); + auto* contentInMemoryPtr = contentInMemory.get(); + m_writer->AddWritingStep(std::move(contentInMemory)); + + // Write zone header + m_writer->AddWritingStep(std::make_unique(CreateHeaderForParams(isSecure, false, isEncrypted))); + + // Setup loading XChunks from the zone from this point on. + auto* signatureDataProvider = AddXChunkProcessor(isEncrypted); + + // Start of the XFile struct + //m_writer->AddWritingStep(std::make_unique(8)); // Skip size and externalSize fields since they are not interesting for us + m_writer->AddWritingStep(std::make_unique(m_zone)); + + // Start of the zone content + m_writer->AddWritingStep(std::make_unique(contentInMemoryPtr)); + + // Return the fully setup zoneloader + return std::move(m_writer); + } +}; + +bool ZoneWriterFactory::SupportsZone(Zone* zone) const +{ + return zone->m_game == &g_GameT6; +} + +std::unique_ptr ZoneWriterFactory::CreateWriter(Zone* zone) const +{ + Impl impl(zone); + return impl.CreateWriter(); +} diff --git a/src/ZoneWriting/Game/T6/ZoneWriterFactoryT6.h b/src/ZoneWriting/Game/T6/ZoneWriterFactoryT6.h new file mode 100644 index 00000000..a7ba249e --- /dev/null +++ b/src/ZoneWriting/Game/T6/ZoneWriterFactoryT6.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +#include "Writing/IZoneWriterFactory.h" + +namespace T6 +{ + class ZoneWriterFactory final : public IZoneWriterFactory + { + class Impl; + + public: + _NODISCARD bool SupportsZone(Zone* zone) const override; + _NODISCARD std::unique_ptr CreateWriter(Zone* zone) const override; + }; +} diff --git a/src/ZoneWriting/Writing/AssetWriter.cpp b/src/ZoneWriting/Writing/AssetWriter.cpp new file mode 100644 index 00000000..e69de29b diff --git a/src/ZoneWriting/Writing/AssetWriter.h b/src/ZoneWriting/Writing/AssetWriter.h new file mode 100644 index 00000000..04a59d49 --- /dev/null +++ b/src/ZoneWriting/Writing/AssetWriter.h @@ -0,0 +1,6 @@ +#pragma once + +class AssetWriter +{ + +}; \ No newline at end of file diff --git a/src/ZoneWriting/Writing/ContentWriterBase.cpp b/src/ZoneWriting/Writing/ContentWriterBase.cpp new file mode 100644 index 00000000..e69de29b diff --git a/src/ZoneWriting/Writing/ContentWriterBase.h b/src/ZoneWriting/Writing/ContentWriterBase.h new file mode 100644 index 00000000..5cf0a471 --- /dev/null +++ b/src/ZoneWriting/Writing/ContentWriterBase.h @@ -0,0 +1,29 @@ +#pragma once + +#include "Zone/Zone.h" +#include "Zone/Stream/IZoneOutputStream.h" + +class ContentWriterBase +{ +protected: + static constexpr void* PTR_FOLLOWING = reinterpret_cast(-1); + static constexpr void* PTR_INSERT = reinterpret_cast(-2); + + const char** varXString; + + Zone* m_zone; + IZoneOutputStream* m_stream; + + ContentWriterBase(); + ContentWriterBase(Zone* zone, IZoneOutputStream* stream); + + void WriteXString(bool atStreamStart) const; + void WriteXStringArray(bool atStreamStart, size_t count); + +public: + virtual ~ContentWriterBase() = default; + ContentWriterBase(const ContentWriterBase& other) = default; + ContentWriterBase(ContentWriterBase&& other) noexcept = default; + ContentWriterBase& operator=(const ContentWriterBase& other) = default; + ContentWriterBase& operator=(ContentWriterBase&& other) noexcept = default; +}; diff --git a/src/ZoneWriting/Writing/IContentWritingEntryPoint.h b/src/ZoneWriting/Writing/IContentWritingEntryPoint.h new file mode 100644 index 00000000..d00f82d1 --- /dev/null +++ b/src/ZoneWriting/Writing/IContentWritingEntryPoint.h @@ -0,0 +1,17 @@ +#pragma once + +#include "Zone/Zone.h" +#include "Zone/Stream/IZoneOutputStream.h" + +class IContentWritingEntryPoint +{ +public: + IContentWritingEntryPoint() = default; + virtual ~IContentWritingEntryPoint() = default; + IContentWritingEntryPoint(const IContentWritingEntryPoint& other) = default; + IContentWritingEntryPoint(IContentWritingEntryPoint&& other) noexcept = default; + IContentWritingEntryPoint& operator=(const IContentWritingEntryPoint& other) = default; + IContentWritingEntryPoint& operator=(IContentWritingEntryPoint&& other) noexcept = default; + + virtual void WriteContent(Zone* zone, IZoneOutputStream* stream) = 0; +}; \ No newline at end of file diff --git a/src/ZoneWriting/Writing/IWritingStep.h b/src/ZoneWriting/Writing/IWritingStep.h new file mode 100644 index 00000000..43abf30c --- /dev/null +++ b/src/ZoneWriting/Writing/IWritingStep.h @@ -0,0 +1,19 @@ +#pragma once + +#include "Writing/ZoneWriter.h" +#include "IWritingStream.h" + +class ZoneWriter; + +class IWritingStep +{ +public: + IWritingStep() = default; + virtual ~IWritingStep() = default; + IWritingStep(const IWritingStep& other) = default; + IWritingStep(IWritingStep&& other) noexcept = default; + IWritingStep& operator=(const IWritingStep& other) = default; + IWritingStep& operator=(IWritingStep&& other) noexcept = default; + + virtual void PerformStep(ZoneWriter* zoneWriter, IWritingStream* stream) = 0; +}; diff --git a/src/ZoneWriting/Writing/IWritingStream.h b/src/ZoneWriting/Writing/IWritingStream.h new file mode 100644 index 00000000..5332e586 --- /dev/null +++ b/src/ZoneWriting/Writing/IWritingStream.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include + +class IWritingStream +{ +public: + IWritingStream() = default; + virtual ~IWritingStream() = default; + IWritingStream(const IWritingStream& other) = default; + IWritingStream(IWritingStream&& other) noexcept = default; + IWritingStream& operator=(const IWritingStream& other) = default; + IWritingStream& operator=(IWritingStream&& other) noexcept = default; + + virtual void Write(const void* buffer, size_t length) = 0; + virtual int64_t Pos() = 0; +}; \ No newline at end of file diff --git a/src/ZoneWriting/Writing/IZoneWriterFactory.h b/src/ZoneWriting/Writing/IZoneWriterFactory.h new file mode 100644 index 00000000..e855b55f --- /dev/null +++ b/src/ZoneWriting/Writing/IZoneWriterFactory.h @@ -0,0 +1,19 @@ +#pragma once + +#include "Utils/ClassUtils.h" +#include "ZoneWriter.h" +#include "Zone/Zone.h" + +class IZoneWriterFactory +{ +public: + IZoneWriterFactory() = default; + virtual ~IZoneWriterFactory() = default; + IZoneWriterFactory(const IZoneWriterFactory& other) = default; + IZoneWriterFactory(IZoneWriterFactory&& other) noexcept = default; + IZoneWriterFactory& operator=(const IZoneWriterFactory& other) = default; + IZoneWriterFactory& operator=(IZoneWriterFactory&& other) noexcept = default; + + _NODISCARD virtual bool SupportsZone(Zone* zone) const = 0; + _NODISCARD virtual std::unique_ptr CreateWriter(Zone* zone) const = 0; +}; \ No newline at end of file diff --git a/src/ZoneWriting/Writing/InMemoryZoneData.cpp b/src/ZoneWriting/Writing/InMemoryZoneData.cpp new file mode 100644 index 00000000..35d8df1c --- /dev/null +++ b/src/ZoneWriting/Writing/InMemoryZoneData.cpp @@ -0,0 +1,31 @@ +#include "InMemoryZoneData.h" + +#include + +InMemoryZoneData::InMemoryZoneData() + : m_total_size(0) +{ + m_buffers.emplace_back(BUFFER_SIZE); +} + +InMemoryZoneData::MemoryBuffer::MemoryBuffer(const size_t size) + : m_data(std::make_unique(size)), + m_size(0) +{ +} + +void* InMemoryZoneData::GetBufferOfSize(const size_t size) +{ + assert(size <= BUFFER_SIZE); + + if(m_buffers.back().m_size + size > BUFFER_SIZE) + { + m_buffers.emplace_back(BUFFER_SIZE); + } + + auto& backBuffer = m_buffers.back(); + void* result = &backBuffer.m_data[backBuffer.m_size]; + backBuffer.m_size += size; + m_total_size += size; + return result; +} diff --git a/src/ZoneWriting/Writing/InMemoryZoneData.h b/src/ZoneWriting/Writing/InMemoryZoneData.h new file mode 100644 index 00000000..52ec3453 --- /dev/null +++ b/src/ZoneWriting/Writing/InMemoryZoneData.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +class InMemoryZoneData +{ + static constexpr size_t BUFFER_SIZE = 0x10000; + +public: + class MemoryBuffer + { + public: + std::unique_ptr m_data; + size_t m_size; + + explicit MemoryBuffer(size_t size); + }; + + int64_t m_total_size; + std::vector m_buffers; + + InMemoryZoneData(); + void* GetBufferOfSize(size_t size); +}; \ No newline at end of file diff --git a/src/ZoneWriting/Writing/OutputStreamProcessor.cpp b/src/ZoneWriting/Writing/OutputStreamProcessor.cpp new file mode 100644 index 00000000..81f5e86e --- /dev/null +++ b/src/ZoneWriting/Writing/OutputStreamProcessor.cpp @@ -0,0 +1,11 @@ +#include "OutputStreamProcessor.h" + +OutputStreamProcessor::OutputStreamProcessor() +{ + m_base_stream = nullptr; +} + +void OutputStreamProcessor::SetBaseStream(IWritingStream* baseStream) +{ + m_base_stream = baseStream; +} \ No newline at end of file diff --git a/src/ZoneWriting/Writing/OutputStreamProcessor.h b/src/ZoneWriting/Writing/OutputStreamProcessor.h new file mode 100644 index 00000000..6f109076 --- /dev/null +++ b/src/ZoneWriting/Writing/OutputStreamProcessor.h @@ -0,0 +1,14 @@ +#pragma once + +#include "IWritingStream.h" + +class OutputStreamProcessor : public IWritingStream +{ +protected: + IWritingStream* m_base_stream; + +public: + OutputStreamProcessor(); + + void SetBaseStream(IWritingStream* baseStream); +}; diff --git a/src/ZoneWriting/Writing/Processor/OutputProcessorXChunks.cpp b/src/ZoneWriting/Writing/Processor/OutputProcessorXChunks.cpp new file mode 100644 index 00000000..4c2285c4 --- /dev/null +++ b/src/ZoneWriting/Writing/Processor/OutputProcessorXChunks.cpp @@ -0,0 +1,46 @@ +#include "OutputProcessorXChunks.h" + +class OutputProcessorXChunks::Impl +{ + +}; + +OutputProcessorXChunks::OutputProcessorXChunks(int numStreams, size_t xChunkSize) +{ +} + +OutputProcessorXChunks::OutputProcessorXChunks(int numStreams, size_t xChunkSize, size_t vanillaBufferSize) +{ +} + +OutputProcessorXChunks::~OutputProcessorXChunks() +{ + delete m_impl; + m_impl = nullptr; +} + +OutputProcessorXChunks::OutputProcessorXChunks(OutputProcessorXChunks&& other) noexcept + : m_impl(other.m_impl) +{ + other.m_impl = nullptr; +} + +OutputProcessorXChunks& OutputProcessorXChunks::operator=(OutputProcessorXChunks&& other) noexcept +{ + m_impl = other.m_impl; + other.m_impl = nullptr; + return *this; +} + +void OutputProcessorXChunks::AddChunkProcessor(std::unique_ptr chunkProcessor) const +{ +} + +void OutputProcessorXChunks::Write(const void* buffer, size_t length) +{ +} + +int64_t OutputProcessorXChunks::Pos() +{ + return 0; +} diff --git a/src/ZoneWriting/Writing/Processor/OutputProcessorXChunks.h b/src/ZoneWriting/Writing/Processor/OutputProcessorXChunks.h new file mode 100644 index 00000000..458bec90 --- /dev/null +++ b/src/ZoneWriting/Writing/Processor/OutputProcessorXChunks.h @@ -0,0 +1,26 @@ +#pragma once +#include + +#include "Writing/OutputStreamProcessor.h" +#include "XChunks/IXChunkOutputProcessor.h" + +class OutputProcessorXChunks final : public OutputStreamProcessor +{ + class Impl; + Impl* m_impl; + +public: + OutputProcessorXChunks(int numStreams, size_t xChunkSize); + OutputProcessorXChunks(int numStreams, size_t xChunkSize, size_t vanillaBufferSize); + ~OutputProcessorXChunks() override; + + OutputProcessorXChunks(const OutputProcessorXChunks& other) = delete; + OutputProcessorXChunks(OutputProcessorXChunks&& other) noexcept; + OutputProcessorXChunks& operator=(const OutputProcessorXChunks& other) = delete; + OutputProcessorXChunks& operator=(OutputProcessorXChunks&& other) noexcept; + + void AddChunkProcessor(std::unique_ptr chunkProcessor) const; + + void Write(const void* buffer, size_t length) override; + int64_t Pos() override; +}; diff --git a/src/ZoneWriting/Writing/Processor/XChunks/IXChunkOutputProcessor.h b/src/ZoneWriting/Writing/Processor/XChunks/IXChunkOutputProcessor.h new file mode 100644 index 00000000..60b5270c --- /dev/null +++ b/src/ZoneWriting/Writing/Processor/XChunks/IXChunkOutputProcessor.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +class IXChunkOutputProcessor +{ +public: + IXChunkOutputProcessor() = default; + virtual ~IXChunkOutputProcessor() = default; + IXChunkOutputProcessor(const IXChunkOutputProcessor& other) = default; + IXChunkOutputProcessor(IXChunkOutputProcessor&& other) noexcept = default; + IXChunkOutputProcessor& operator=(const IXChunkOutputProcessor& other) = default; + IXChunkOutputProcessor& operator=(IXChunkOutputProcessor&& other) noexcept = default; + + virtual size_t Process(int streamNumber, const uint8_t* input, size_t inputLength, uint8_t* output, size_t outputBufferSize) = 0; +}; diff --git a/src/ZoneWriting/Writing/Processor/XChunks/XChunkOutputProcessorDeflate.cpp b/src/ZoneWriting/Writing/Processor/XChunks/XChunkOutputProcessorDeflate.cpp new file mode 100644 index 00000000..e69de29b diff --git a/src/ZoneWriting/Writing/Processor/XChunks/XChunkOutputProcessorDeflate.h b/src/ZoneWriting/Writing/Processor/XChunks/XChunkOutputProcessorDeflate.h new file mode 100644 index 00000000..870731b0 --- /dev/null +++ b/src/ZoneWriting/Writing/Processor/XChunks/XChunkOutputProcessorDeflate.h @@ -0,0 +1,8 @@ +#pragma once +#include "IXChunkOutputProcessor.h" + +class XChunkOutputProcessorDeflate final : public IXChunkOutputProcessor +{ +public: + size_t Process(int streamNumber, const uint8_t* input, size_t inputLength, uint8_t* output, size_t outputBufferSize) override; +}; diff --git a/src/ZoneWriting/Writing/Processor/XChunks/XChunkOutputProcessorSalsa20.cpp b/src/ZoneWriting/Writing/Processor/XChunks/XChunkOutputProcessorSalsa20.cpp new file mode 100644 index 00000000..e69de29b diff --git a/src/ZoneWriting/Writing/Processor/XChunks/XChunkOutputProcessorSalsa20.h b/src/ZoneWriting/Writing/Processor/XChunks/XChunkOutputProcessorSalsa20.h new file mode 100644 index 00000000..120fb761 --- /dev/null +++ b/src/ZoneWriting/Writing/Processor/XChunks/XChunkOutputProcessorSalsa20.h @@ -0,0 +1,20 @@ +#pragma once +#include "IXChunkOutputProcessor.h" +#include "Utils/ICapturedDataProvider.h" + +class XChunkOutputProcessorSalsa20 final : public IXChunkOutputProcessor, public ICapturedDataProvider +{ + class Impl; + Impl* m_impl; + +public: + XChunkOutputProcessorSalsa20(int streamCount, std::string& zoneName, const uint8_t* salsa20Key, size_t keySize); + ~XChunkOutputProcessorSalsa20() override; + XChunkOutputProcessorSalsa20(const XChunkOutputProcessorSalsa20& other) = delete; + XChunkOutputProcessorSalsa20(XChunkOutputProcessorSalsa20&& other) noexcept = default; + XChunkOutputProcessorSalsa20& operator=(const XChunkOutputProcessorSalsa20& other) = delete; + XChunkOutputProcessorSalsa20& operator=(XChunkOutputProcessorSalsa20&& other) noexcept = default; + + size_t Process(int streamNumber, const uint8_t* input, size_t inputLength, uint8_t* output, size_t outputBufferSize) override; + void GetCapturedData(const uint8_t** pCapturedData, size_t* pSize) override; +}; diff --git a/src/ZoneWriting/Writing/Steps/StepAddOutputProcessor.cpp b/src/ZoneWriting/Writing/Steps/StepAddOutputProcessor.cpp new file mode 100644 index 00000000..fbcb4598 --- /dev/null +++ b/src/ZoneWriting/Writing/Steps/StepAddOutputProcessor.cpp @@ -0,0 +1,16 @@ +#include "StepAddOutputProcessor.h" +#include + +StepAddOutputProcessor::StepAddOutputProcessor(std::unique_ptr streamProcessor) + : m_stream_processor(std::move(streamProcessor)) +{ +} + +void StepAddOutputProcessor::PerformStep(ZoneWriter* zoneLoader, IWritingStream* stream) +{ + assert(zoneLoader != nullptr); + assert(m_stream_processor != nullptr); + + zoneLoader->AddStreamProcessor(std::move(m_stream_processor)); + m_stream_processor = nullptr; +} \ No newline at end of file diff --git a/src/ZoneWriting/Writing/Steps/StepAddOutputProcessor.h b/src/ZoneWriting/Writing/Steps/StepAddOutputProcessor.h new file mode 100644 index 00000000..87453c1b --- /dev/null +++ b/src/ZoneWriting/Writing/Steps/StepAddOutputProcessor.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#include "Writing/IWritingStep.h" + +class StepAddOutputProcessor final : public IWritingStep +{ + std::unique_ptr m_stream_processor; + +public: + explicit StepAddOutputProcessor(std::unique_ptr streamProcessor); + + void PerformStep(ZoneWriter* zoneLoader, IWritingStream* stream) override; +}; diff --git a/src/ZoneWriting/Writing/Steps/StepWriteXBlockSizes.cpp b/src/ZoneWriting/Writing/Steps/StepWriteXBlockSizes.cpp new file mode 100644 index 00000000..eae6a854 --- /dev/null +++ b/src/ZoneWriting/Writing/Steps/StepWriteXBlockSizes.cpp @@ -0,0 +1,10 @@ +#include "StepWriteXBlockSizes.h" + +StepWriteXBlockSizes::StepWriteXBlockSizes(Zone* zone) + : m_zone(zone) +{ +} + +void StepWriteXBlockSizes::PerformStep(ZoneWriter* zoneWriter, IWritingStream* stream) +{ +} diff --git a/src/ZoneWriting/Writing/Steps/StepWriteXBlockSizes.h b/src/ZoneWriting/Writing/Steps/StepWriteXBlockSizes.h new file mode 100644 index 00000000..88923283 --- /dev/null +++ b/src/ZoneWriting/Writing/Steps/StepWriteXBlockSizes.h @@ -0,0 +1,13 @@ +#pragma once +#include "Writing/IWritingStep.h" +#include "Zone/Zone.h" + +class StepWriteXBlockSizes final : public IWritingStep +{ + Zone* m_zone; + +public: + explicit StepWriteXBlockSizes(Zone* zone); + + void PerformStep(ZoneWriter* zoneWriter, IWritingStream* stream) override; +}; diff --git a/src/ZoneWriting/Writing/Steps/StepWriteZero.cpp b/src/ZoneWriting/Writing/Steps/StepWriteZero.cpp new file mode 100644 index 00000000..940df2ae --- /dev/null +++ b/src/ZoneWriting/Writing/Steps/StepWriteZero.cpp @@ -0,0 +1,20 @@ +#include "StepWriteZero.h" + +#include + +StepWriteZero::StepWriteZero(const size_t count) + : m_count(count) +{ +} + +void StepWriteZero::PerformStep(ZoneWriter* zoneWriter, IWritingStream* stream) +{ + const uint64_t num = 0; + size_t toWrite; + + for(auto i = 0u; i < m_count; i += toWrite) + { + toWrite = std::min(sizeof(uint64_t), m_count - i); + stream->Write(&num, toWrite); + } +} diff --git a/src/ZoneWriting/Writing/Steps/StepWriteZero.h b/src/ZoneWriting/Writing/Steps/StepWriteZero.h new file mode 100644 index 00000000..2c406414 --- /dev/null +++ b/src/ZoneWriting/Writing/Steps/StepWriteZero.h @@ -0,0 +1,12 @@ +#pragma once +#include "Writing/IWritingStep.h" + +class StepWriteZero final : public IWritingStep +{ + size_t m_count; + +public: + explicit StepWriteZero(size_t count); + + void PerformStep(ZoneWriter* zoneWriter, IWritingStream* stream) override; +}; diff --git a/src/ZoneWriting/Writing/Steps/StepWriteZoneContentToFile.cpp b/src/ZoneWriting/Writing/Steps/StepWriteZoneContentToFile.cpp new file mode 100644 index 00000000..8ba6d1bc --- /dev/null +++ b/src/ZoneWriting/Writing/Steps/StepWriteZoneContentToFile.cpp @@ -0,0 +1,10 @@ +#include "StepWriteZoneContentToFile.h" + +StepWriteZoneContentToFile::StepWriteZoneContentToFile(StepWriteZoneContentToMemory* zoneMemory) + : m_memory(zoneMemory) +{ +} + +void StepWriteZoneContentToFile::PerformStep(ZoneWriter* zoneWriter, IWritingStream* stream) +{ +} diff --git a/src/ZoneWriting/Writing/Steps/StepWriteZoneContentToFile.h b/src/ZoneWriting/Writing/Steps/StepWriteZoneContentToFile.h new file mode 100644 index 00000000..48f05162 --- /dev/null +++ b/src/ZoneWriting/Writing/Steps/StepWriteZoneContentToFile.h @@ -0,0 +1,13 @@ +#pragma once +#include "StepWriteZoneContentToMemory.h" +#include "Writing/IWritingStep.h" + +class StepWriteZoneContentToFile final : public IWritingStep +{ + StepWriteZoneContentToMemory* m_memory; + +public: + explicit StepWriteZoneContentToFile(StepWriteZoneContentToMemory* zoneMemory); + + void PerformStep(ZoneWriter* zoneWriter, IWritingStream* stream) override; +}; diff --git a/src/ZoneWriting/Writing/Steps/StepWriteZoneContentToMemory.cpp b/src/ZoneWriting/Writing/Steps/StepWriteZoneContentToMemory.cpp new file mode 100644 index 00000000..225367a8 --- /dev/null +++ b/src/ZoneWriting/Writing/Steps/StepWriteZoneContentToMemory.cpp @@ -0,0 +1,27 @@ +#include "StepWriteZoneContentToMemory.h" + +#include "Zone/Stream/Impl/InMemoryZoneOutputStream.h" + +StepWriteZoneContentToMemory::StepWriteZoneContentToMemory(std::unique_ptr entryPoint, Zone* zone, int offsetBlockBitCount, block_t insertBlock) + : m_content_loader(std::move(entryPoint)), + m_zone_data(std::make_unique()), + m_zone(zone), + m_offset_block_bit_count(offsetBlockBitCount), + m_insert_block(insertBlock) +{ +} + +void StepWriteZoneContentToMemory::PerformStep(ZoneWriter* zoneWriter, IWritingStream* stream) +{ + std::vector blocks; + for (const auto& block : zoneWriter->m_blocks) + blocks.push_back(block.get()); + + const auto zoneOutputStream = std::make_unique(m_zone_data.get(), std::move(blocks), m_offset_block_bit_count, m_insert_block); + m_content_loader->WriteContent(m_zone, zoneOutputStream.get()); +} + +InMemoryZoneData* StepWriteZoneContentToMemory::GetData() const +{ + return m_zone_data.get(); +} diff --git a/src/ZoneWriting/Writing/Steps/StepWriteZoneContentToMemory.h b/src/ZoneWriting/Writing/Steps/StepWriteZoneContentToMemory.h new file mode 100644 index 00000000..6ec4713e --- /dev/null +++ b/src/ZoneWriting/Writing/Steps/StepWriteZoneContentToMemory.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +#include "Utils/ClassUtils.h" +#include "Writing/IContentWritingEntryPoint.h" +#include "Writing/InMemoryZoneData.h" +#include "Writing/IWritingStep.h" + +class StepWriteZoneContentToMemory final : public IWritingStep +{ + std::unique_ptr m_content_loader; + std::unique_ptr m_zone_data; + Zone* m_zone; + int m_offset_block_bit_count; + block_t m_insert_block; + +public: + StepWriteZoneContentToMemory(std::unique_ptr entryPoint, Zone* zone, int offsetBlockBitCount, block_t insertBlock); + + void PerformStep(ZoneWriter* zoneWriter, IWritingStream* stream) override; + _NODISCARD InMemoryZoneData* GetData() const; +}; diff --git a/src/ZoneWriting/Writing/Steps/StepWriteZoneHeader.cpp b/src/ZoneWriting/Writing/Steps/StepWriteZoneHeader.cpp new file mode 100644 index 00000000..ebe34b2e --- /dev/null +++ b/src/ZoneWriting/Writing/Steps/StepWriteZoneHeader.cpp @@ -0,0 +1,11 @@ +#include "StepWriteZoneHeader.h" + +StepWriteZoneHeader::StepWriteZoneHeader(const ZoneHeader header) + : m_header(header) +{ +} + +void StepWriteZoneHeader::PerformStep(ZoneWriter* zoneWriter, IWritingStream* stream) +{ + stream->Write(&m_header, sizeof(m_header)); +} diff --git a/src/ZoneWriting/Writing/Steps/StepWriteZoneHeader.h b/src/ZoneWriting/Writing/Steps/StepWriteZoneHeader.h new file mode 100644 index 00000000..249673c3 --- /dev/null +++ b/src/ZoneWriting/Writing/Steps/StepWriteZoneHeader.h @@ -0,0 +1,12 @@ +#pragma once +#include "Writing/IWritingStep.h" + +class StepWriteZoneHeader final : public IWritingStep +{ + ZoneHeader m_header; + +public: + explicit StepWriteZoneHeader(ZoneHeader header); + + void PerformStep(ZoneWriter* zoneWriter, IWritingStream* stream) override; +}; diff --git a/src/ZoneWriting/Writing/Steps/StepWriteZoneSizes.cpp b/src/ZoneWriting/Writing/Steps/StepWriteZoneSizes.cpp new file mode 100644 index 00000000..282159a8 --- /dev/null +++ b/src/ZoneWriting/Writing/Steps/StepWriteZoneSizes.cpp @@ -0,0 +1,15 @@ +#include "StepWriteZoneSizes.h" + +StepWriteZoneSizes::StepWriteZoneSizes(StepWriteZoneContentToMemory* memory) + : m_memory(memory) +{ +} + +void StepWriteZoneSizes::PerformStep(ZoneWriter* zoneWriter, IWritingStream* stream) +{ + auto totalSize = static_cast(m_memory->GetData()->m_total_size); + size_t externalSize = 0; + + stream->Write(&totalSize, sizeof(totalSize)); + stream->Write(&externalSize, sizeof(externalSize)); +} diff --git a/src/ZoneWriting/Writing/Steps/StepWriteZoneSizes.h b/src/ZoneWriting/Writing/Steps/StepWriteZoneSizes.h new file mode 100644 index 00000000..158e0fdf --- /dev/null +++ b/src/ZoneWriting/Writing/Steps/StepWriteZoneSizes.h @@ -0,0 +1,13 @@ +#pragma once +#include "StepWriteZoneContentToMemory.h" +#include "Writing/IWritingStep.h" + +class StepWriteZoneSizes final : public IWritingStep +{ + StepWriteZoneContentToMemory* m_memory; + +public: + explicit StepWriteZoneSizes(StepWriteZoneContentToMemory* memory); + + void PerformStep(ZoneWriter* zoneWriter, IWritingStream* stream) override; +}; diff --git a/src/ZoneWriting/Writing/WritingException.cpp b/src/ZoneWriting/Writing/WritingException.cpp new file mode 100644 index 00000000..a9361c21 --- /dev/null +++ b/src/ZoneWriting/Writing/WritingException.cpp @@ -0,0 +1,16 @@ +#include "WritingException.h" + +WritingException::WritingException(std::string message) + : m_error_message(std::move(message)) +{ +} + +char const* WritingException::what() const +{ + return m_error_message.c_str(); +} + +const std::string& WritingException::Message() const +{ + return m_error_message; +} diff --git a/src/ZoneWriting/Writing/WritingException.h b/src/ZoneWriting/Writing/WritingException.h new file mode 100644 index 00000000..3772c5cc --- /dev/null +++ b/src/ZoneWriting/Writing/WritingException.h @@ -0,0 +1,16 @@ +#pragma once +#include +#include + +#include "Utils/ClassUtils.h" + +class WritingException final : public std::exception +{ + std::string m_error_message; + +public: + explicit WritingException(std::string message); + + _NODISCARD char const* what() const override; + _NODISCARD const std::string& Message() const; +}; diff --git a/src/ZoneWriting/Writing/WritingFileStream.cpp b/src/ZoneWriting/Writing/WritingFileStream.cpp new file mode 100644 index 00000000..86e891ce --- /dev/null +++ b/src/ZoneWriting/Writing/WritingFileStream.cpp @@ -0,0 +1,16 @@ +#include "WritingFileStream.h" + +WritingFileStream::WritingFileStream(std::ostream& stream) + : m_stream(stream) +{ +} + +void WritingFileStream::Write(const void* buffer, const size_t length) +{ + m_stream.write(static_cast(buffer), length); +} + +int64_t WritingFileStream::Pos() +{ + return m_stream.tellp(); +} diff --git a/src/ZoneWriting/Writing/WritingFileStream.h b/src/ZoneWriting/Writing/WritingFileStream.h new file mode 100644 index 00000000..2960dc41 --- /dev/null +++ b/src/ZoneWriting/Writing/WritingFileStream.h @@ -0,0 +1,15 @@ +#pragma once +#include + +#include "IWritingStream.h" + +class WritingFileStream final : public IWritingStream +{ + std::ostream& m_stream; + +public: + explicit WritingFileStream(std::ostream& stream); + + void Write(const void* buffer, size_t length) override; + int64_t Pos() override; +}; diff --git a/src/ZoneWriting/Writing/ZoneWriter.cpp b/src/ZoneWriting/Writing/ZoneWriter.cpp new file mode 100644 index 00000000..9ac765ed --- /dev/null +++ b/src/ZoneWriting/Writing/ZoneWriter.cpp @@ -0,0 +1,79 @@ +#include "ZoneWriter.h" + +#include + +#include "WritingException.h" +#include "WritingFileStream.h" + +ZoneWriter::ZoneWriter() + : m_processor_chain_dirty(false) +{ +} + +IWritingStream* ZoneWriter::BuildWritingChain(IWritingStream* rootStream) +{ + auto* currentStream = rootStream; + + for (const auto& processor : m_processors) + { + processor->SetBaseStream(currentStream); + + currentStream = processor.get(); + } + + m_processor_chain_dirty = false; + return currentStream; +} + +void ZoneWriter::AddXBlock(std::unique_ptr block) +{ + m_blocks.emplace_back(std::move(block)); +} + +void ZoneWriter::AddWritingStep(std::unique_ptr step) +{ + m_steps.emplace_back(std::move(step)); +} + +void ZoneWriter::AddStreamProcessor(std::unique_ptr streamProcessor) +{ + m_processors.push_back(std::move(streamProcessor)); + m_processor_chain_dirty = true; +} + +void ZoneWriter::RemoveStreamProcessor(OutputStreamProcessor* streamProcessor) +{ + for (auto i = m_processors.begin(); i < m_processors.end(); ++i) + { + if (i->get() == streamProcessor) + { + m_processors.erase(i); + m_processor_chain_dirty = true; + break; + } + } +} + +bool ZoneWriter::WriteZone(std::ostream& stream) +{ + WritingFileStream fileStream(stream); + auto* endStream = BuildWritingChain(&fileStream); + + try + { + for (const auto& step : m_steps) + { + step->PerformStep(this, endStream); + + if (m_processor_chain_dirty) + endStream = BuildWritingChain(&fileStream); + } + } + catch (WritingException& e) + { + std::cout << "Writing fastfile failed: " << e.Message() << std::endl; + return false; + } + + return true; +} diff --git a/src/ZoneWriting/Writing/ZoneWriter.h b/src/ZoneWriting/Writing/ZoneWriter.h new file mode 100644 index 00000000..05cae4a4 --- /dev/null +++ b/src/ZoneWriting/Writing/ZoneWriter.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +#include "IWritingStep.h" +#include "OutputStreamProcessor.h" +#include "Zone/Zone.h" + +class IWritingStep; + +class ZoneWriter +{ + std::vector> m_steps; + std::vector> m_processors; + + bool m_processor_chain_dirty; + + IWritingStream* BuildWritingChain(IWritingStream* rootStream); + +public: + std::vector> m_blocks; + + ZoneWriter(); + + void AddXBlock(std::unique_ptr block); + void AddWritingStep(std::unique_ptr step); + void AddStreamProcessor(std::unique_ptr streamProcessor); + + void RemoveStreamProcessor(OutputStreamProcessor* streamProcessor); + + bool WriteZone(std::ostream& stream); +}; diff --git a/src/ZoneWriting/Zone/Stream/IZoneOutputStream.h b/src/ZoneWriting/Zone/Stream/IZoneOutputStream.h index 7aafa40a..b5a484dc 100644 --- a/src/ZoneWriting/Zone/Stream/IZoneOutputStream.h +++ b/src/ZoneWriting/Zone/Stream/IZoneOutputStream.h @@ -1,7 +1,50 @@ #pragma once -class IZoneOutputStream +#include +#include +#include + +#include "Zone/Stream/IZoneStream.h" + +class IZoneOutputStream : public IZoneStream { public: virtual void Align(int alignTo) = 0; -}; \ No newline at end of file + + virtual void* WriteDataRaw(void* dst, size_t size) = 0; + virtual void* WriteDataInBlock(void* dst, size_t size) = 0; + virtual void IncBlockPos(size_t size) = 0; + virtual void WriteNullTerminated(void* dst) = 0; + + virtual bool ReusableShouldWrite(void** pPtr, size_t size, size_t count, std::type_index type) = 0; + + template + bool ReusableShouldWrite(T** pPtr) + { + return ReusableShouldWrite(pPtr, sizeof(T), 1, std::type_index(typeid(T))); + } + + template + bool ReusableShouldWrite(T** pPtr, size_t count) + { + return ReusableShouldWrite(pPtr, sizeof(T), count, std::type_index(typeid(T))); + } + + template + T* Write(T* dst) + { + return static_cast(WriteDataInBlock(const_cast(reinterpret_cast(dst)), sizeof(T))); + } + + template + T* Write(T* dst, const uint32_t count) + { + return static_cast(WriteDataInBlock(const_cast(reinterpret_cast(dst)), count * sizeof(T))); + } + + template + T* WritePartial(T* dst, const size_t size) + { + return static_cast(WriteDataInBlock(const_cast(reinterpret_cast(dst)), size)); + } +}; diff --git a/src/ZoneWriting/Zone/Stream/Impl/InMemoryZoneOutputStream.cpp b/src/ZoneWriting/Zone/Stream/Impl/InMemoryZoneOutputStream.cpp new file mode 100644 index 00000000..92c03637 --- /dev/null +++ b/src/ZoneWriting/Zone/Stream/Impl/InMemoryZoneOutputStream.cpp @@ -0,0 +1,196 @@ +#include "InMemoryZoneOutputStream.h" + +#include + +InMemoryZoneOutputStream::InMemoryZoneOutputStream(InMemoryZoneData* zoneData, std::vector blocks, const int blockBitCount, const block_t insertBlock) + : m_zone_data(zoneData), + m_blocks(std::move(blocks)), + m_block_bit_count(blockBitCount), + m_insert_block(m_blocks[insertBlock]) +{ +} + +InMemoryZoneOutputStream::ReusableEntry::ReusableEntry(void* startPtr, const size_t entrySize, const size_t entryCount, const uintptr_t startZonePtr) + : m_start_ptr(startPtr), + m_end_ptr(reinterpret_cast(reinterpret_cast(startPtr) + entrySize * entryCount)), + m_start_zone_ptr(startZonePtr), + m_entry_size(entrySize), m_entry_count(entryCount) +{ +} + +void InMemoryZoneOutputStream::PushBlock(const block_t block) +{ + assert(block >= 0 && block < static_cast(m_blocks.size())); + + auto* newBlock = m_blocks[block]; + + assert(newBlock->m_index == block); + + m_block_stack.push(newBlock); + + if (newBlock->m_type == XBlock::Type::BLOCK_TYPE_TEMP) + { + if (m_temp_sizes.empty()) + m_temp_sizes.push(0); + else + m_temp_sizes.push(m_temp_sizes.top()); + } +} + +block_t InMemoryZoneOutputStream::PopBlock() +{ + assert(!m_block_stack.empty()); + + if (m_block_stack.empty()) + return -1; + + auto* poppedBlock = m_block_stack.top(); + m_block_stack.pop(); + + // If temp block is popped, see if its size is bigger than the current maximum temp size + if (poppedBlock->m_type == XBlock::Type::BLOCK_TYPE_TEMP) + { + const auto tempSize = m_temp_sizes.top(); + m_temp_sizes.pop(); + + if (tempSize > poppedBlock->m_buffer_size) + poppedBlock->m_buffer_size = tempSize; + } + + return poppedBlock->m_index; +} + +void InMemoryZoneOutputStream::Align(const int align) +{ + assert(!m_block_stack.empty()); + + if (align > 0) + { + auto* block = m_block_stack.top(); + + if (block->m_type == XBlock::Type::BLOCK_TYPE_TEMP) + m_temp_sizes.top() = (m_temp_sizes.top() + align - 1) / align * align; + else + block->m_buffer_size = (block->m_buffer_size + align - 1) / align * align; + } +} + +void* InMemoryZoneOutputStream::WriteDataRaw(void* src, const size_t size) +{ + auto* result = m_zone_data->GetBufferOfSize(size); + memcpy(result, src, size); + return result; +} + +void* InMemoryZoneOutputStream::WriteDataInBlock(void* src, const size_t size) +{ + assert(!m_block_stack.empty()); + + if (m_block_stack.empty()) + return nullptr; + + auto* block = m_block_stack.top(); + + void* result = nullptr; + switch (block->m_type) + { + case XBlock::Type::BLOCK_TYPE_TEMP: + case XBlock::Type::BLOCK_TYPE_NORMAL: + result = m_zone_data->GetBufferOfSize(size); + memcpy(result, src, size); + break; + + case XBlock::Type::BLOCK_TYPE_RUNTIME: + break; + + case XBlock::Type::BLOCK_TYPE_DELAY: + assert(false); + break; + } + + IncBlockPos(size); + return result; +} + +void InMemoryZoneOutputStream::IncBlockPos(const size_t size) +{ + assert(!m_block_stack.empty()); + + if (m_block_stack.empty()) + return; + + auto* block = m_block_stack.top(); + if (block->m_type == XBlock::Type::BLOCK_TYPE_TEMP) + { + m_temp_sizes.top() += size; + } + else + { + block->m_buffer_size += size; + } +} + +void InMemoryZoneOutputStream::WriteNullTerminated(void* src) +{ + const auto len = strlen(static_cast(src)); + WriteDataInBlock(src, len + 1); +} + +uintptr_t InMemoryZoneOutputStream::GetCurrentZonePointer() +{ + assert(!m_block_stack.empty()); + + uintptr_t ptr = 0; + ptr |= static_cast(m_block_stack.top()->m_index) << (sizeof(uintptr_t) * 8 - m_block_bit_count); + ptr |= m_block_stack.top()->m_buffer_size & (UINTPTR_MAX >> m_block_bit_count); + ptr++; + + return ptr; +} + +uintptr_t InMemoryZoneOutputStream::InsertPointer() +{ + PushBlock(m_insert_block->m_index); + + Align(sizeof(uintptr_t)); + const auto result = GetCurrentZonePointer(); + IncBlockPos(sizeof(uintptr_t)); + + PopBlock(); + + return result; +} + +bool InMemoryZoneOutputStream::ReusableShouldWrite(void** pPtr, const size_t entrySize, const size_t entryCount, std::type_index type) +{ + assert(!m_block_stack.empty()); + + const auto inTemp = m_block_stack.top()->m_type == XBlock::Type::BLOCK_TYPE_TEMP; + const auto foundEntriesForType = m_reusable_entries.find(type); + if (foundEntriesForType == m_reusable_entries.end()) + { + std::vector entries; + auto zoneOffset = inTemp ? InsertPointer() : GetCurrentZonePointer(); + entries.emplace_back(*pPtr, entrySize, entryCount, zoneOffset); + m_reusable_entries.emplace(std::make_pair(type, std::move(entries))); + + *pPtr = inTemp ? PTR_INSERT : PTR_FOLLOWING; + return true; + } + + for(const auto& entry : foundEntriesForType->second) + { + if(*pPtr >= entry.m_start_ptr && *pPtr < entry.m_end_ptr) + { + assert((reinterpret_cast(*pPtr) - reinterpret_cast(entry.m_start_ptr)) % entrySize == 0); + *pPtr = reinterpret_cast(entry.m_start_zone_ptr + (reinterpret_cast(*pPtr) - reinterpret_cast(entry.m_start_ptr))); + return false; + } + } + + auto zoneOffset = inTemp ? InsertPointer() : GetCurrentZonePointer(); + foundEntriesForType->second.emplace_back(*pPtr, entrySize, entryCount, zoneOffset); + + *pPtr = inTemp ? PTR_INSERT : PTR_FOLLOWING; + return true; +} diff --git a/src/ZoneWriting/Zone/Stream/Impl/InMemoryZoneOutputStream.h b/src/ZoneWriting/Zone/Stream/Impl/InMemoryZoneOutputStream.h new file mode 100644 index 00000000..aa01081a --- /dev/null +++ b/src/ZoneWriting/Zone/Stream/Impl/InMemoryZoneOutputStream.h @@ -0,0 +1,52 @@ +#pragma once +#include +#include +#include + +#include "Writing/InMemoryZoneData.h" +#include "Zone/XBlock.h" +#include "Zone/Stream/IZoneOutputStream.h" + +class InMemoryZoneOutputStream final : public IZoneOutputStream +{ + static constexpr void* PTR_FOLLOWING = reinterpret_cast(-1); + static constexpr void* PTR_INSERT = reinterpret_cast(-2); + + class ReusableEntry + { + public: + void* m_start_ptr; + void* m_end_ptr; + uintptr_t m_start_zone_ptr; + size_t m_entry_size; + size_t m_entry_count; + + ReusableEntry(void* startPtr, size_t entrySize, size_t entryCount, uintptr_t startZonePtr); + }; + + InMemoryZoneData* m_zone_data; + std::vector m_blocks; + + std::stack m_block_stack; + std::stack m_temp_sizes; + + int m_block_bit_count; + XBlock* m_insert_block; + + std::unordered_map> m_reusable_entries; + + uintptr_t GetCurrentZonePointer(); + uintptr_t InsertPointer(); + +public: + InMemoryZoneOutputStream(InMemoryZoneData* zoneData, std::vector blocks, int blockBitCount, block_t insertBlock); + + void PushBlock(block_t block) override; + block_t PopBlock() override; + void Align(int align) override; + void* WriteDataRaw(void* src, size_t size) override; + void* WriteDataInBlock(void* src, size_t size) override; + void IncBlockPos(size_t size) override; + void WriteNullTerminated(void* src) override; + bool ReusableShouldWrite(void** pPtr, size_t entrySize, size_t entryCount, std::type_index type) override; +}; diff --git a/src/ZoneWriting/ZoneWriting.cpp b/src/ZoneWriting/ZoneWriting.cpp index a19d79d0..e5044081 100644 --- a/src/ZoneWriting/ZoneWriting.cpp +++ b/src/ZoneWriting/ZoneWriting.cpp @@ -1,6 +1,16 @@ #include "ZoneWriting.h" -bool ZoneWriting::WriteZone(Zone* zone) +#include "Game/IW4/ZoneWriterFactoryIW4.h" +#include "Game/T6/ZoneWriterFactoryT6.h" +#include "Writing/IZoneWriterFactory.h" + +IZoneWriterFactory* ZoneWriterFactories[] +{ + new IW4::ZoneWriterFactory(), + new T6::ZoneWriterFactory() +}; + +bool ZoneWriting::WriteZone(std::ostream& stream, Zone* zone) { return true; } diff --git a/src/ZoneWriting/ZoneWriting.h b/src/ZoneWriting/ZoneWriting.h index 680d82dc..8d11f67c 100644 --- a/src/ZoneWriting/ZoneWriting.h +++ b/src/ZoneWriting/ZoneWriting.h @@ -1,9 +1,11 @@ #pragma once #include +#include + #include "Zone/Zone.h" class ZoneWriting { public: - static bool WriteZone(Zone* zone); + static bool WriteZone(std::ostream& stream, Zone* zone); }; \ No newline at end of file