mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-05-07 13:04:58 +00:00
refactor: hide implementation details of zone loading processors
This commit is contained in:
parent
eb16dfcd00
commit
955df98279
@ -77,7 +77,7 @@ std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(ZoneHeader&
|
|||||||
|
|
||||||
SetupBlock(*zoneLoader);
|
SetupBlock(*zoneLoader);
|
||||||
|
|
||||||
zoneLoader->AddLoadingStep(std::make_unique<StepAddProcessor>(std::make_unique<ProcessorInflate>(ZoneConstants::AUTHED_CHUNK_SIZE)));
|
zoneLoader->AddLoadingStep(std::make_unique<StepAddProcessor>(processor::CreateProcessorInflate(ZoneConstants::AUTHED_CHUNK_SIZE)));
|
||||||
|
|
||||||
// Start of the XFile struct
|
// Start of the XFile struct
|
||||||
zoneLoader->AddLoadingStep(std::make_unique<StepSkipBytes>(8));
|
zoneLoader->AddLoadingStep(std::make_unique<StepSkipBytes>(8));
|
||||||
|
@ -136,7 +136,7 @@ namespace
|
|||||||
|
|
||||||
zoneLoader.AddLoadingStep(std::make_unique<StepVerifySignature>(std::move(rsa), subHeaderHashSignaturePtr, subHeaderHashPtr));
|
zoneLoader.AddLoadingStep(std::make_unique<StepVerifySignature>(std::move(rsa), subHeaderHashSignaturePtr, subHeaderHashPtr));
|
||||||
|
|
||||||
auto subHeaderCapture = std::make_unique<ProcessorCaptureData>(sizeof(DB_AuthSubHeader));
|
auto subHeaderCapture = processor::CreateProcessorCaptureData(sizeof(DB_AuthSubHeader));
|
||||||
auto* subHeaderCapturePtr = subHeaderCapture.get();
|
auto* subHeaderCapturePtr = subHeaderCapture.get();
|
||||||
zoneLoader.AddLoadingStep(std::make_unique<StepAddProcessor>(std::move(subHeaderCapture)));
|
zoneLoader.AddLoadingStep(std::make_unique<StepAddProcessor>(std::move(subHeaderCapture)));
|
||||||
|
|
||||||
@ -155,11 +155,11 @@ namespace
|
|||||||
zoneLoader.AddLoadingStep(std::make_unique<StepSkipBytes>(ZoneConstants::AUTHED_CHUNK_SIZE - sizeof(DB_AuthHeader)));
|
zoneLoader.AddLoadingStep(std::make_unique<StepSkipBytes>(ZoneConstants::AUTHED_CHUNK_SIZE - sizeof(DB_AuthHeader)));
|
||||||
|
|
||||||
zoneLoader.AddLoadingStep(std::make_unique<StepAddProcessor>(
|
zoneLoader.AddLoadingStep(std::make_unique<StepAddProcessor>(
|
||||||
std::make_unique<ProcessorAuthedBlocks>(ZoneConstants::AUTHED_CHUNK_COUNT_PER_GROUP,
|
processor::CreateProcessorAuthedBlocks(ZoneConstants::AUTHED_CHUNK_COUNT_PER_GROUP,
|
||||||
ZoneConstants::AUTHED_CHUNK_SIZE,
|
ZoneConstants::AUTHED_CHUNK_SIZE,
|
||||||
static_cast<unsigned>(std::extent_v<decltype(DB_AuthSubHeader::masterBlockHashes)>),
|
static_cast<unsigned>(std::extent_v<decltype(DB_AuthSubHeader::masterBlockHashes)>),
|
||||||
cryptography::CreateSha256(),
|
cryptography::CreateSha256(),
|
||||||
masterBlockHashesPtr)));
|
masterBlockHashesPtr)));
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@ -193,11 +193,11 @@ std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(ZoneHeader&
|
|||||||
// Add steps for loading the auth header which also contain the signature of the zone if it is signed.
|
// Add steps for loading the auth header which also contain the signature of the zone if it is signed.
|
||||||
AddAuthHeaderSteps(isSecure, isOfficial, *zoneLoader, fileName);
|
AddAuthHeaderSteps(isSecure, isOfficial, *zoneLoader, fileName);
|
||||||
|
|
||||||
zoneLoader->AddLoadingStep(std::make_unique<StepAddProcessor>(std::make_unique<ProcessorInflate>(ZoneConstants::AUTHED_CHUNK_SIZE)));
|
zoneLoader->AddLoadingStep(std::make_unique<StepAddProcessor>(processor::CreateProcessorInflate(ZoneConstants::AUTHED_CHUNK_SIZE)));
|
||||||
|
|
||||||
if (isIw4x) // IW4x has one extra byte of padding here for protection purposes
|
if (isIw4x) // IW4x has one extra byte of padding here for protection purposes
|
||||||
{
|
{
|
||||||
zoneLoader->AddLoadingStep(std::make_unique<StepAddProcessor>(std::make_unique<ProcessorIW4xDecryption>()));
|
zoneLoader->AddLoadingStep(std::make_unique<StepAddProcessor>(processor::CreateProcessorIW4xDecryption()));
|
||||||
zoneLoader->AddLoadingStep(std::make_unique<StepSkipBytes>(1));
|
zoneLoader->AddLoadingStep(std::make_unique<StepSkipBytes>(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ namespace
|
|||||||
|
|
||||||
zoneLoader.AddLoadingStep(std::make_unique<StepVerifySignature>(std::move(rsa), subHeaderHashSignaturePtr, subHeaderHashPtr));
|
zoneLoader.AddLoadingStep(std::make_unique<StepVerifySignature>(std::move(rsa), subHeaderHashSignaturePtr, subHeaderHashPtr));
|
||||||
|
|
||||||
auto subHeaderCapture = std::make_unique<ProcessorCaptureData>(sizeof(DB_AuthSubHeader));
|
auto subHeaderCapture = processor::CreateProcessorCaptureData(sizeof(DB_AuthSubHeader));
|
||||||
auto* subHeaderCapturePtr = subHeaderCapture.get();
|
auto* subHeaderCapturePtr = subHeaderCapture.get();
|
||||||
zoneLoader.AddLoadingStep(std::make_unique<StepAddProcessor>(std::move(subHeaderCapture)));
|
zoneLoader.AddLoadingStep(std::make_unique<StepAddProcessor>(std::move(subHeaderCapture)));
|
||||||
|
|
||||||
@ -139,11 +139,11 @@ namespace
|
|||||||
zoneLoader.AddLoadingStep(std::make_unique<StepSkipBytes>(ZoneConstants::AUTHED_CHUNK_SIZE - sizeof(DB_AuthHeader)));
|
zoneLoader.AddLoadingStep(std::make_unique<StepSkipBytes>(ZoneConstants::AUTHED_CHUNK_SIZE - sizeof(DB_AuthHeader)));
|
||||||
|
|
||||||
zoneLoader.AddLoadingStep(std::make_unique<StepAddProcessor>(
|
zoneLoader.AddLoadingStep(std::make_unique<StepAddProcessor>(
|
||||||
std::make_unique<ProcessorAuthedBlocks>(ZoneConstants::AUTHED_CHUNK_COUNT_PER_GROUP,
|
processor::CreateProcessorAuthedBlocks(ZoneConstants::AUTHED_CHUNK_COUNT_PER_GROUP,
|
||||||
ZoneConstants::AUTHED_CHUNK_SIZE,
|
ZoneConstants::AUTHED_CHUNK_SIZE,
|
||||||
static_cast<unsigned>(std::extent_v<decltype(DB_AuthSubHeader::masterBlockHashes)>),
|
static_cast<unsigned>(std::extent_v<decltype(DB_AuthSubHeader::masterBlockHashes)>),
|
||||||
cryptography::CreateSha256(),
|
cryptography::CreateSha256(),
|
||||||
masterBlockHashesPtr)));
|
masterBlockHashesPtr)));
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@ -176,7 +176,7 @@ std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(ZoneHeader&
|
|||||||
// Add steps for loading the auth header which also contain the signature of the zone if it is signed.
|
// Add steps for loading the auth header which also contain the signature of the zone if it is signed.
|
||||||
AddAuthHeaderSteps(isSecure, isOfficial, *zoneLoader, fileName);
|
AddAuthHeaderSteps(isSecure, isOfficial, *zoneLoader, fileName);
|
||||||
|
|
||||||
zoneLoader->AddLoadingStep(std::make_unique<StepAddProcessor>(std::make_unique<ProcessorInflate>(ZoneConstants::AUTHED_CHUNK_SIZE)));
|
zoneLoader->AddLoadingStep(std::make_unique<StepAddProcessor>(processor::CreateProcessorInflate(ZoneConstants::AUTHED_CHUNK_SIZE)));
|
||||||
|
|
||||||
// Start of the XFile struct
|
// Start of the XFile struct
|
||||||
zoneLoader->AddLoadingStep(std::make_unique<StepSkipBytes>(8));
|
zoneLoader->AddLoadingStep(std::make_unique<StepSkipBytes>(8));
|
||||||
|
@ -77,7 +77,7 @@ std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(ZoneHeader&
|
|||||||
|
|
||||||
SetupBlock(*zoneLoader);
|
SetupBlock(*zoneLoader);
|
||||||
|
|
||||||
zoneLoader->AddLoadingStep(std::make_unique<StepAddProcessor>(std::make_unique<ProcessorInflate>(ZoneConstants::AUTHED_CHUNK_SIZE)));
|
zoneLoader->AddLoadingStep(std::make_unique<StepAddProcessor>(processor::CreateProcessorInflate(ZoneConstants::AUTHED_CHUNK_SIZE)));
|
||||||
|
|
||||||
// Start of the XFile struct
|
// Start of the XFile struct
|
||||||
zoneLoader->AddLoadingStep(std::make_unique<StepSkipBytes>(8));
|
zoneLoader->AddLoadingStep(std::make_unique<StepSkipBytes>(8));
|
||||||
|
@ -148,7 +148,7 @@ namespace
|
|||||||
ICapturedDataProvider* AddXChunkProcessor(const bool isEncrypted, ZoneLoader& zoneLoader, std::string& fileName)
|
ICapturedDataProvider* AddXChunkProcessor(const bool isEncrypted, ZoneLoader& zoneLoader, std::string& fileName)
|
||||||
{
|
{
|
||||||
ICapturedDataProvider* result = nullptr;
|
ICapturedDataProvider* result = nullptr;
|
||||||
auto xChunkProcessor = std::make_unique<ProcessorXChunks>(ZoneConstants::STREAM_COUNT, ZoneConstants::XCHUNK_SIZE, ZoneConstants::VANILLA_BUFFER_SIZE);
|
auto xChunkProcessor = processor::CreateProcessorXChunks(ZoneConstants::STREAM_COUNT, ZoneConstants::XCHUNK_SIZE, ZoneConstants::VANILLA_BUFFER_SIZE);
|
||||||
|
|
||||||
if (isEncrypted)
|
if (isEncrypted)
|
||||||
{
|
{
|
||||||
|
@ -5,39 +5,19 @@
|
|||||||
#include "Loading/Exception/TooManyAuthedGroupsException.h"
|
#include "Loading/Exception/TooManyAuthedGroupsException.h"
|
||||||
#include "Loading/Exception/UnexpectedEndOfFileException.h"
|
#include "Loading/Exception/UnexpectedEndOfFileException.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class ProcessorAuthedBlocks::Impl
|
class ProcessorAuthedBlocks final : public StreamProcessor
|
||||||
{
|
{
|
||||||
ProcessorAuthedBlocks* const m_base;
|
|
||||||
|
|
||||||
const unsigned m_authed_chunk_count;
|
|
||||||
const size_t m_chunk_size;
|
|
||||||
const unsigned m_max_master_block_count;
|
|
||||||
|
|
||||||
const std::unique_ptr<cryptography::IHashFunction> m_hash_function;
|
|
||||||
IHashProvider* const m_master_block_hash_provider;
|
|
||||||
const std::unique_ptr<uint8_t[]> m_chunk_hashes_buffer;
|
|
||||||
const std::unique_ptr<uint8_t[]> m_current_chunk_hash_buffer;
|
|
||||||
|
|
||||||
const std::unique_ptr<uint8_t[]> m_chunk_buffer;
|
|
||||||
unsigned m_current_group;
|
|
||||||
unsigned m_current_chunk_in_group;
|
|
||||||
|
|
||||||
size_t m_current_chunk_offset;
|
|
||||||
size_t m_current_chunk_size;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Impl(ProcessorAuthedBlocks* base,
|
ProcessorAuthedBlocks(const unsigned authedChunkCount,
|
||||||
const unsigned authedChunkCount,
|
const size_t chunkSize,
|
||||||
const size_t chunkSize,
|
const unsigned maxMasterBlockCount,
|
||||||
const unsigned maxMasterBlockCount,
|
std::unique_ptr<cryptography::IHashFunction> hashFunction,
|
||||||
std::unique_ptr<cryptography::IHashFunction> hashFunction,
|
IHashProvider* masterBlockHashProvider)
|
||||||
IHashProvider* masterBlockHashProvider)
|
: m_authed_chunk_count(authedChunkCount),
|
||||||
: m_base(base),
|
|
||||||
m_authed_chunk_count(authedChunkCount),
|
|
||||||
m_chunk_size(chunkSize),
|
m_chunk_size(chunkSize),
|
||||||
m_max_master_block_count(maxMasterBlockCount),
|
m_max_master_block_count(maxMasterBlockCount),
|
||||||
m_hash_function(std::move(hashFunction)),
|
m_hash_function(std::move(hashFunction)),
|
||||||
@ -53,13 +33,43 @@ public:
|
|||||||
assert(m_authed_chunk_count * m_hash_function->GetHashSize() <= m_chunk_size);
|
assert(m_authed_chunk_count * m_hash_function->GetHashSize() <= m_chunk_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t Load(void* buffer, const size_t length) override
|
||||||
|
{
|
||||||
|
size_t loadedSize = 0;
|
||||||
|
|
||||||
|
while (loadedSize < length)
|
||||||
|
{
|
||||||
|
if (m_current_chunk_offset >= m_current_chunk_size)
|
||||||
|
{
|
||||||
|
if (!NextChunk())
|
||||||
|
return loadedSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sizeToWrite = length - loadedSize;
|
||||||
|
sizeToWrite = std::min(sizeToWrite, m_current_chunk_size - m_current_chunk_offset);
|
||||||
|
|
||||||
|
assert(length - loadedSize >= sizeToWrite);
|
||||||
|
memcpy(&static_cast<uint8_t*>(buffer)[loadedSize], &m_chunk_buffer[m_current_chunk_offset], sizeToWrite);
|
||||||
|
loadedSize += sizeToWrite;
|
||||||
|
m_current_chunk_offset += sizeToWrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
return loadedSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t Pos() override
|
||||||
|
{
|
||||||
|
return m_base_stream->Pos() - static_cast<int64_t>(m_current_chunk_size - m_current_chunk_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
bool NextChunk()
|
bool NextChunk()
|
||||||
{
|
{
|
||||||
m_current_chunk_offset = 0;
|
m_current_chunk_offset = 0;
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
m_current_chunk_size = m_base->m_base_stream->Load(m_chunk_buffer.get(), m_chunk_size);
|
m_current_chunk_size = m_base_stream->Load(m_chunk_buffer.get(), m_chunk_size);
|
||||||
|
|
||||||
if (m_current_chunk_size == 0)
|
if (m_current_chunk_size == 0)
|
||||||
return false;
|
return false;
|
||||||
@ -79,7 +89,9 @@ public:
|
|||||||
|
|
||||||
if (masterBlockHashSize != m_hash_function->GetHashSize()
|
if (masterBlockHashSize != m_hash_function->GetHashSize()
|
||||||
|| std::memcmp(m_current_chunk_hash_buffer.get(), masterBlockHash, m_hash_function->GetHashSize()) != 0)
|
|| std::memcmp(m_current_chunk_hash_buffer.get(), masterBlockHash, m_hash_function->GetHashSize()) != 0)
|
||||||
|
{
|
||||||
throw InvalidHashException();
|
throw InvalidHashException();
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(m_chunk_hashes_buffer.get(), m_chunk_buffer.get(), m_authed_chunk_count * m_hash_function->GetHashSize());
|
memcpy(m_chunk_hashes_buffer.get(), m_chunk_buffer.get(), m_authed_chunk_count * m_hash_function->GetHashSize());
|
||||||
|
|
||||||
@ -91,7 +103,9 @@ public:
|
|||||||
&m_chunk_hashes_buffer[(m_current_chunk_in_group - 1) * m_hash_function->GetHashSize()],
|
&m_chunk_hashes_buffer[(m_current_chunk_in_group - 1) * m_hash_function->GetHashSize()],
|
||||||
m_hash_function->GetHashSize())
|
m_hash_function->GetHashSize())
|
||||||
!= 0)
|
!= 0)
|
||||||
|
{
|
||||||
throw InvalidHashException();
|
throw InvalidHashException();
|
||||||
|
}
|
||||||
|
|
||||||
if (++m_current_chunk_in_group > m_authed_chunk_count)
|
if (++m_current_chunk_in_group > m_authed_chunk_count)
|
||||||
{
|
{
|
||||||
@ -107,58 +121,31 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Load(void* buffer, const size_t length)
|
const unsigned m_authed_chunk_count;
|
||||||
{
|
const size_t m_chunk_size;
|
||||||
size_t loadedSize = 0;
|
const unsigned m_max_master_block_count;
|
||||||
|
|
||||||
while (loadedSize < length)
|
const std::unique_ptr<cryptography::IHashFunction> m_hash_function;
|
||||||
{
|
IHashProvider* const m_master_block_hash_provider;
|
||||||
if (m_current_chunk_offset >= m_current_chunk_size)
|
const std::unique_ptr<uint8_t[]> m_chunk_hashes_buffer;
|
||||||
{
|
const std::unique_ptr<uint8_t[]> m_current_chunk_hash_buffer;
|
||||||
if (!NextChunk())
|
|
||||||
return loadedSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t sizeToWrite = length - loadedSize;
|
const std::unique_ptr<uint8_t[]> m_chunk_buffer;
|
||||||
if (sizeToWrite > m_current_chunk_size - m_current_chunk_offset)
|
unsigned m_current_group;
|
||||||
sizeToWrite = m_current_chunk_size - m_current_chunk_offset;
|
unsigned m_current_chunk_in_group;
|
||||||
|
|
||||||
assert(length - loadedSize >= sizeToWrite);
|
size_t m_current_chunk_offset;
|
||||||
memcpy(&static_cast<uint8_t*>(buffer)[loadedSize], &m_chunk_buffer[m_current_chunk_offset], sizeToWrite);
|
size_t m_current_chunk_size;
|
||||||
loadedSize += sizeToWrite;
|
|
||||||
m_current_chunk_offset += sizeToWrite;
|
|
||||||
}
|
|
||||||
|
|
||||||
return loadedSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t Pos()
|
|
||||||
{
|
|
||||||
return m_base->m_base_stream->Pos() - (m_current_chunk_size - m_current_chunk_offset);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ProcessorAuthedBlocks::ProcessorAuthedBlocks(const unsigned authedChunkCount,
|
namespace processor
|
||||||
const size_t chunkSize,
|
|
||||||
const unsigned maxMasterBlockCount,
|
|
||||||
std::unique_ptr<cryptography::IHashFunction> hashFunction,
|
|
||||||
IHashProvider* masterBlockHashProvider)
|
|
||||||
: m_impl(new Impl(this, authedChunkCount, chunkSize, maxMasterBlockCount, std::move(hashFunction), masterBlockHashProvider))
|
|
||||||
{
|
{
|
||||||
}
|
std::unique_ptr<StreamProcessor> CreateProcessorAuthedBlocks(unsigned authedChunkCount,
|
||||||
|
size_t chunkSize,
|
||||||
ProcessorAuthedBlocks::~ProcessorAuthedBlocks()
|
unsigned maxMasterBlockCount,
|
||||||
{
|
std::unique_ptr<cryptography::IHashFunction> hashFunction,
|
||||||
delete m_impl;
|
IHashProvider* masterBlockHashProvider)
|
||||||
m_impl = nullptr;
|
{
|
||||||
}
|
return std::make_unique<ProcessorAuthedBlocks>(authedChunkCount, chunkSize, maxMasterBlockCount, std::move(hashFunction), masterBlockHashProvider);
|
||||||
|
}
|
||||||
size_t ProcessorAuthedBlocks::Load(void* buffer, const size_t length)
|
} // namespace processor
|
||||||
{
|
|
||||||
return m_impl->Load(buffer, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t ProcessorAuthedBlocks::Pos()
|
|
||||||
{
|
|
||||||
return m_impl->Pos();
|
|
||||||
}
|
|
||||||
|
@ -6,23 +6,11 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class ProcessorAuthedBlocks final : public StreamProcessor
|
namespace processor
|
||||||
{
|
{
|
||||||
class Impl;
|
std::unique_ptr<StreamProcessor> CreateProcessorAuthedBlocks(unsigned authedChunkCount,
|
||||||
Impl* m_impl;
|
size_t chunkSize,
|
||||||
|
unsigned maxMasterBlockCount,
|
||||||
public:
|
std::unique_ptr<cryptography::IHashFunction> hashFunction,
|
||||||
ProcessorAuthedBlocks(unsigned authedChunkCount,
|
IHashProvider* masterBlockHashProvider);
|
||||||
size_t chunkSize,
|
}
|
||||||
unsigned maxMasterBlockCount,
|
|
||||||
std::unique_ptr<cryptography::IHashFunction> hashFunction,
|
|
||||||
IHashProvider* masterBlockHashProvider);
|
|
||||||
~ProcessorAuthedBlocks() override;
|
|
||||||
ProcessorAuthedBlocks(const ProcessorAuthedBlocks& other) = delete;
|
|
||||||
ProcessorAuthedBlocks(ProcessorAuthedBlocks&& other) noexcept = default;
|
|
||||||
ProcessorAuthedBlocks& operator=(const ProcessorAuthedBlocks& other) = delete;
|
|
||||||
ProcessorAuthedBlocks& operator=(ProcessorAuthedBlocks&& other) noexcept = default;
|
|
||||||
|
|
||||||
size_t Load(void* buffer, size_t length) override;
|
|
||||||
int64_t Pos() override;
|
|
||||||
};
|
|
||||||
|
@ -1,51 +1,67 @@
|
|||||||
#include "ProcessorCaptureData.h"
|
#include "ProcessorCaptureData.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
ProcessorCaptureData::ProcessorCaptureData(const size_t captureSize)
|
namespace
|
||||||
: m_data(std::make_unique<uint8_t[]>(captureSize)),
|
|
||||||
m_capture_size(captureSize),
|
|
||||||
m_captured_data_size(0)
|
|
||||||
{
|
{
|
||||||
}
|
class ProcessorCaptureData final : public processor::IProcessorCaptureData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ProcessorCaptureData(const size_t captureSize)
|
||||||
|
: m_data(std::make_unique<uint8_t[]>(captureSize)),
|
||||||
|
m_capture_size(captureSize),
|
||||||
|
m_captured_data_size(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
ProcessorCaptureData::~ProcessorCaptureData() = default;
|
size_t Load(void* buffer, const size_t length) override
|
||||||
|
{
|
||||||
|
if (m_captured_data_size >= m_capture_size)
|
||||||
|
return m_base_stream->Load(buffer, length);
|
||||||
|
|
||||||
size_t ProcessorCaptureData::Load(void* buffer, const size_t length)
|
auto dataToCapture = m_capture_size - m_captured_data_size;
|
||||||
|
dataToCapture = std::min(length, dataToCapture);
|
||||||
|
|
||||||
|
auto loadedSize = m_base_stream->Load(&m_data[m_captured_data_size], dataToCapture);
|
||||||
|
assert(length >= loadedSize);
|
||||||
|
memcpy(buffer, &m_data[m_captured_data_size], loadedSize);
|
||||||
|
|
||||||
|
m_captured_data_size += loadedSize;
|
||||||
|
|
||||||
|
if (length > dataToCapture)
|
||||||
|
loadedSize += m_base_stream->Load(&static_cast<uint8_t*>(buffer)[dataToCapture], length - dataToCapture);
|
||||||
|
|
||||||
|
return loadedSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t Pos() override
|
||||||
|
{
|
||||||
|
return m_base_stream->Pos();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetCapturedData(const uint8_t** pCapturedData, size_t* pSize) override
|
||||||
|
{
|
||||||
|
assert(pCapturedData != nullptr);
|
||||||
|
assert(pSize != nullptr);
|
||||||
|
|
||||||
|
assert(m_captured_data_size == m_capture_size);
|
||||||
|
|
||||||
|
*pCapturedData = m_data.get();
|
||||||
|
*pSize = m_captured_data_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<uint8_t[]> m_data;
|
||||||
|
size_t m_capture_size;
|
||||||
|
size_t m_captured_data_size;
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace processor
|
||||||
{
|
{
|
||||||
if (m_captured_data_size >= m_capture_size)
|
std::unique_ptr<IProcessorCaptureData> CreateProcessorCaptureData(size_t captureSize)
|
||||||
return m_base_stream->Load(buffer, length);
|
{
|
||||||
|
return std::make_unique<ProcessorCaptureData>(captureSize);
|
||||||
size_t dataToCapture = m_capture_size - m_captured_data_size;
|
}
|
||||||
|
} // namespace processor
|
||||||
if (length < dataToCapture)
|
|
||||||
dataToCapture = length;
|
|
||||||
|
|
||||||
size_t loadedSize = m_base_stream->Load(&m_data[m_captured_data_size], dataToCapture);
|
|
||||||
assert(length >= loadedSize);
|
|
||||||
memcpy(buffer, &m_data[m_captured_data_size], loadedSize);
|
|
||||||
|
|
||||||
m_captured_data_size += loadedSize;
|
|
||||||
|
|
||||||
if (length > dataToCapture)
|
|
||||||
loadedSize += m_base_stream->Load(&static_cast<uint8_t*>(buffer)[dataToCapture], length - dataToCapture);
|
|
||||||
|
|
||||||
return loadedSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t ProcessorCaptureData::Pos()
|
|
||||||
{
|
|
||||||
return m_base_stream->Pos();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProcessorCaptureData::GetCapturedData(const uint8_t** pCapturedData, size_t* pSize)
|
|
||||||
{
|
|
||||||
assert(pCapturedData != nullptr);
|
|
||||||
assert(pSize != nullptr);
|
|
||||||
|
|
||||||
assert(m_captured_data_size == m_capture_size);
|
|
||||||
|
|
||||||
*pCapturedData = m_data.get();
|
|
||||||
*pSize = m_captured_data_size;
|
|
||||||
}
|
|
||||||
|
@ -1,20 +1,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Loading/StreamProcessor.h"
|
#include "Loading/StreamProcessor.h"
|
||||||
#include "Utils/ICapturedDataProvider.h"
|
#include "Utils/ICapturedDataProvider.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class ProcessorCaptureData final : public StreamProcessor, public ICapturedDataProvider
|
namespace processor
|
||||||
{
|
{
|
||||||
std::unique_ptr<uint8_t[]> m_data;
|
class IProcessorCaptureData : public StreamProcessor, public ICapturedDataProvider
|
||||||
const size_t m_capture_size;
|
{
|
||||||
size_t m_captured_data_size;
|
};
|
||||||
|
|
||||||
public:
|
std::unique_ptr<IProcessorCaptureData> CreateProcessorCaptureData(size_t captureSize);
|
||||||
explicit ProcessorCaptureData(size_t captureSize);
|
} // namespace processor
|
||||||
~ProcessorCaptureData() override;
|
|
||||||
|
|
||||||
size_t Load(void* buffer, size_t length) override;
|
|
||||||
int64_t Pos() override;
|
|
||||||
void GetCapturedData(const uint8_t** pCapturedData, size_t* pSize) override;
|
|
||||||
};
|
|
||||||
|
@ -2,44 +2,62 @@
|
|||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
ProcessorIW4xDecryption::ProcessorIW4xDecryption()
|
namespace
|
||||||
: m_last_byte(0u)
|
|
||||||
{
|
{
|
||||||
}
|
uint8_t RotateLeft(const uint8_t value, const unsigned count)
|
||||||
|
|
||||||
uint8_t ProcessorIW4xDecryption::RotateLeft(const uint8_t value, const unsigned count)
|
|
||||||
{
|
|
||||||
assert(count < sizeof(value) * 8);
|
|
||||||
return static_cast<uint8_t>(value << count | (value >> ((sizeof(value) * 8) - count)));
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t ProcessorIW4xDecryption::RotateRight(uint8_t value, const unsigned count)
|
|
||||||
{
|
|
||||||
assert(count < sizeof(value) * 8);
|
|
||||||
return static_cast<uint8_t>(value >> count | (value << ((sizeof(value) * 8) - count)));
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t ProcessorIW4xDecryption::Load(void* buffer, const size_t length)
|
|
||||||
{
|
|
||||||
const auto readLen = m_base_stream->Load(buffer, length);
|
|
||||||
|
|
||||||
auto* charBuffer = static_cast<uint8_t*>(buffer);
|
|
||||||
for (auto i = 0u; i < readLen; i++)
|
|
||||||
{
|
{
|
||||||
auto value = charBuffer[i];
|
assert(count < sizeof(value) * 8);
|
||||||
value ^= m_last_byte;
|
return static_cast<uint8_t>(value << count | (value >> ((sizeof(value) * 8) - count)));
|
||||||
value = RotateLeft(value, 4);
|
|
||||||
value ^= -1;
|
|
||||||
value = RotateRight(value, 6);
|
|
||||||
|
|
||||||
charBuffer[i] = value;
|
|
||||||
m_last_byte = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return readLen;
|
uint8_t RotateRight(const uint8_t value, const unsigned count)
|
||||||
}
|
{
|
||||||
|
assert(count < sizeof(value) * 8);
|
||||||
|
return static_cast<uint8_t>(value >> count | (value << ((sizeof(value) * 8) - count)));
|
||||||
|
}
|
||||||
|
|
||||||
int64_t ProcessorIW4xDecryption::Pos()
|
class ProcessorIW4xDecryption final : public StreamProcessor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ProcessorIW4xDecryption()
|
||||||
|
: m_last_byte(0u)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Load(void* buffer, const size_t length) override
|
||||||
|
{
|
||||||
|
const auto readLen = m_base_stream->Load(buffer, length);
|
||||||
|
|
||||||
|
auto* charBuffer = static_cast<uint8_t*>(buffer);
|
||||||
|
for (auto i = 0u; i < readLen; i++)
|
||||||
|
{
|
||||||
|
auto value = charBuffer[i];
|
||||||
|
value ^= m_last_byte;
|
||||||
|
value = RotateLeft(value, 4);
|
||||||
|
value ^= -1;
|
||||||
|
value = RotateRight(value, 6);
|
||||||
|
|
||||||
|
charBuffer[i] = value;
|
||||||
|
m_last_byte = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return readLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t Pos() override
|
||||||
|
{
|
||||||
|
return m_base_stream->Pos();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t m_last_byte;
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace processor
|
||||||
{
|
{
|
||||||
return m_base_stream->Pos();
|
std::unique_ptr<StreamProcessor> CreateProcessorIW4xDecryption()
|
||||||
}
|
{
|
||||||
|
return std::make_unique<ProcessorIW4xDecryption>();
|
||||||
|
}
|
||||||
|
} // namespace processor
|
||||||
|
@ -1,16 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Loading/StreamProcessor.h"
|
#include "Loading/StreamProcessor.h"
|
||||||
|
|
||||||
class ProcessorIW4xDecryption final : public StreamProcessor
|
#include <memory>
|
||||||
|
|
||||||
|
namespace processor
|
||||||
{
|
{
|
||||||
uint8_t m_last_byte;
|
std::unique_ptr<StreamProcessor> CreateProcessorIW4xDecryption();
|
||||||
|
}
|
||||||
static uint8_t RotateLeft(uint8_t value, unsigned count);
|
|
||||||
static uint8_t RotateRight(uint8_t value, unsigned count);
|
|
||||||
|
|
||||||
public:
|
|
||||||
ProcessorIW4xDecryption();
|
|
||||||
|
|
||||||
size_t Load(void* buffer, size_t length) override;
|
|
||||||
int64_t Pos() override;
|
|
||||||
};
|
|
||||||
|
@ -8,93 +8,85 @@
|
|||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#include <zutil.h>
|
#include <zutil.h>
|
||||||
|
|
||||||
class ProcessorInflate::Impl
|
namespace
|
||||||
{
|
{
|
||||||
z_stream m_stream{};
|
constexpr size_t DEFAULT_BUFFER_SIZE = 0x2000;
|
||||||
ProcessorInflate* m_base;
|
|
||||||
|
|
||||||
std::unique_ptr<uint8_t[]> m_buffer;
|
class ProcessorInflate final : public StreamProcessor
|
||||||
size_t m_buffer_size;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Impl(ProcessorInflate* baseClass, const size_t bufferSize)
|
|
||||||
: m_buffer(std::make_unique<uint8_t[]>(bufferSize)),
|
|
||||||
m_buffer_size(bufferSize)
|
|
||||||
{
|
{
|
||||||
m_base = baseClass;
|
public:
|
||||||
|
explicit ProcessorInflate(const size_t bufferSize)
|
||||||
m_stream.zalloc = Z_NULL;
|
: m_buffer(std::make_unique<uint8_t[]>(bufferSize)),
|
||||||
m_stream.zfree = Z_NULL;
|
m_buffer_size(bufferSize)
|
||||||
m_stream.opaque = Z_NULL;
|
|
||||||
m_stream.avail_in = 0;
|
|
||||||
m_stream.next_in = Z_NULL;
|
|
||||||
|
|
||||||
const int ret = inflateInit(&m_stream);
|
|
||||||
|
|
||||||
if (ret != Z_OK)
|
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Initializing inflate failed");
|
m_stream.zalloc = Z_NULL;
|
||||||
|
m_stream.zfree = Z_NULL;
|
||||||
|
m_stream.opaque = Z_NULL;
|
||||||
|
m_stream.avail_in = 0;
|
||||||
|
m_stream.next_in = Z_NULL;
|
||||||
|
|
||||||
|
const int ret = inflateInit(&m_stream);
|
||||||
|
|
||||||
|
if (ret != Z_OK)
|
||||||
|
throw std::runtime_error("Initializing inflate failed");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
~Impl()
|
~ProcessorInflate() override
|
||||||
{
|
|
||||||
inflateEnd(&m_stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
Impl(const Impl& other) = delete;
|
|
||||||
Impl(Impl&& other) noexcept = default;
|
|
||||||
Impl& operator=(const Impl& other) = delete;
|
|
||||||
Impl& operator=(Impl&& other) noexcept = default;
|
|
||||||
|
|
||||||
size_t Load(void* buffer, const size_t length)
|
|
||||||
{
|
|
||||||
m_stream.next_out = static_cast<Bytef*>(buffer);
|
|
||||||
m_stream.avail_out = static_cast<unsigned>(length);
|
|
||||||
|
|
||||||
while (m_stream.avail_out > 0)
|
|
||||||
{
|
{
|
||||||
if (m_stream.avail_in == 0)
|
inflateEnd(&m_stream);
|
||||||
{
|
}
|
||||||
m_stream.avail_in = static_cast<unsigned>(m_base->m_base_stream->Load(m_buffer.get(), m_buffer_size));
|
|
||||||
m_stream.next_in = m_buffer.get();
|
|
||||||
|
|
||||||
if (m_stream.avail_in == 0) // EOF
|
ProcessorInflate(const ProcessorInflate& other) = delete;
|
||||||
return length - m_stream.avail_out;
|
ProcessorInflate(ProcessorInflate&& other) noexcept = default;
|
||||||
|
ProcessorInflate& operator=(const ProcessorInflate& other) = delete;
|
||||||
|
ProcessorInflate& operator=(ProcessorInflate&& other) noexcept = default;
|
||||||
|
|
||||||
|
size_t Load(void* buffer, const size_t length) override
|
||||||
|
{
|
||||||
|
m_stream.next_out = static_cast<Bytef*>(buffer);
|
||||||
|
m_stream.avail_out = static_cast<unsigned>(length);
|
||||||
|
|
||||||
|
while (m_stream.avail_out > 0)
|
||||||
|
{
|
||||||
|
if (m_stream.avail_in == 0)
|
||||||
|
{
|
||||||
|
m_stream.avail_in = static_cast<unsigned>(m_base_stream->Load(m_buffer.get(), m_buffer_size));
|
||||||
|
m_stream.next_in = m_buffer.get();
|
||||||
|
|
||||||
|
if (m_stream.avail_in == 0) // EOF
|
||||||
|
return length - m_stream.avail_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto ret = inflate(&m_stream, Z_SYNC_FLUSH);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
throw InvalidCompressionException();
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto ret = inflate(&m_stream, Z_SYNC_FLUSH);
|
return length - m_stream.avail_out;
|
||||||
|
|
||||||
if (ret < 0)
|
|
||||||
throw InvalidCompressionException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return length - m_stream.avail_out;
|
int64_t Pos() override
|
||||||
|
{
|
||||||
|
return m_base_stream->Pos();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
z_stream m_stream{};
|
||||||
|
std::unique_ptr<uint8_t[]> m_buffer;
|
||||||
|
size_t m_buffer_size;
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace processor
|
||||||
|
{
|
||||||
|
std::unique_ptr<StreamProcessor> CreateProcessorInflate()
|
||||||
|
{
|
||||||
|
return std::make_unique<ProcessorInflate>(DEFAULT_BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
ProcessorInflate::ProcessorInflate()
|
std::unique_ptr<StreamProcessor> CreateProcessorInflate(size_t bufferSize)
|
||||||
: ProcessorInflate(DEFAULT_BUFFER_SIZE)
|
{
|
||||||
{
|
return std::make_unique<ProcessorInflate>(bufferSize);
|
||||||
}
|
}
|
||||||
|
} // namespace processor
|
||||||
ProcessorInflate::ProcessorInflate(const size_t bufferSize)
|
|
||||||
: m_impl(new Impl(this, bufferSize))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessorInflate::~ProcessorInflate()
|
|
||||||
{
|
|
||||||
delete m_impl;
|
|
||||||
m_impl = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t ProcessorInflate::Load(void* buffer, const size_t length)
|
|
||||||
{
|
|
||||||
return m_impl->Load(buffer, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t ProcessorInflate::Pos()
|
|
||||||
{
|
|
||||||
return m_base_stream->Pos();
|
|
||||||
}
|
|
||||||
|
@ -1,22 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Loading/StreamProcessor.h"
|
#include "Loading/StreamProcessor.h"
|
||||||
|
|
||||||
class ProcessorInflate final : public StreamProcessor
|
#include <memory>
|
||||||
|
|
||||||
|
namespace processor
|
||||||
{
|
{
|
||||||
class Impl;
|
std::unique_ptr<StreamProcessor> CreateProcessorInflate();
|
||||||
Impl* m_impl;
|
std::unique_ptr<StreamProcessor> CreateProcessorInflate(size_t bufferSize);
|
||||||
|
} // namespace processor
|
||||||
static constexpr size_t DEFAULT_BUFFER_SIZE = 0x2000;
|
|
||||||
|
|
||||||
public:
|
|
||||||
ProcessorInflate();
|
|
||||||
ProcessorInflate(size_t bufferSize);
|
|
||||||
~ProcessorInflate() override;
|
|
||||||
ProcessorInflate(const ProcessorInflate& other) = delete;
|
|
||||||
ProcessorInflate(ProcessorInflate&& other) noexcept = default;
|
|
||||||
ProcessorInflate& operator=(const ProcessorInflate& other) = delete;
|
|
||||||
ProcessorInflate& operator=(ProcessorInflate&& other) noexcept = default;
|
|
||||||
|
|
||||||
size_t Load(void* buffer, size_t length) override;
|
|
||||||
int64_t Pos() override;
|
|
||||||
};
|
|
||||||
|
@ -1,21 +1,44 @@
|
|||||||
#include "ProcessorStreamCipher.h"
|
#include "ProcessorStreamCipher.h"
|
||||||
|
|
||||||
ProcessorStreamCipher::ProcessorStreamCipher(std::unique_ptr<cryptography::IStreamCipher> cipher)
|
namespace
|
||||||
: m_cipher(std::move(cipher))
|
|
||||||
{
|
{
|
||||||
}
|
class ProcessorStreamCipher final : public StreamProcessor
|
||||||
|
|
||||||
size_t ProcessorStreamCipher::Load(void* buffer, const size_t length)
|
|
||||||
{
|
|
||||||
if (m_base_stream != nullptr)
|
|
||||||
{
|
{
|
||||||
const size_t readSize = m_base_stream->Load(buffer, length);
|
public:
|
||||||
|
explicit ProcessorStreamCipher(std::unique_ptr<cryptography::IStreamCipher> cipher)
|
||||||
|
: m_cipher(std::move(cipher))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
if (readSize > 0)
|
size_t Load(void* buffer, const size_t length) override
|
||||||
m_cipher->Process(buffer, buffer, readSize);
|
{
|
||||||
|
if (m_base_stream != nullptr)
|
||||||
|
{
|
||||||
|
const size_t readSize = m_base_stream->Load(buffer, length);
|
||||||
|
|
||||||
return readSize;
|
if (readSize > 0)
|
||||||
|
m_cipher->Process(buffer, buffer, readSize);
|
||||||
|
|
||||||
|
return readSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t Pos() override
|
||||||
|
{
|
||||||
|
return m_base_stream->Pos();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<cryptography::IStreamCipher> m_cipher;
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace processor
|
||||||
|
{
|
||||||
|
std::unique_ptr<StreamProcessor> CreateProcessorStreamCipher(std::unique_ptr<cryptography::IStreamCipher> cipher)
|
||||||
|
{
|
||||||
|
return std::make_unique<ProcessorStreamCipher>(std::move(cipher));
|
||||||
}
|
}
|
||||||
|
} // namespace processor
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
@ -5,13 +5,7 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class ProcessorStreamCipher final : public StreamProcessor
|
namespace processor
|
||||||
{
|
{
|
||||||
public:
|
std::unique_ptr<StreamProcessor> CreateProcessorStreamCipher(std::unique_ptr<cryptography::IStreamCipher> cipher);
|
||||||
explicit ProcessorStreamCipher(std::unique_ptr<cryptography::IStreamCipher> cipher);
|
}
|
||||||
|
|
||||||
size_t Load(void* buffer, size_t length) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::unique_ptr<cryptography::IStreamCipher> m_cipher;
|
|
||||||
};
|
|
||||||
|
@ -5,334 +5,304 @@
|
|||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <cstring>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <optional>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class DBLoadStream
|
namespace
|
||||||
{
|
{
|
||||||
int m_index;
|
class DbLoadStream
|
||||||
|
|
||||||
std::unique_ptr<uint8_t[]> m_buffers[2];
|
|
||||||
|
|
||||||
uint8_t* m_input_buffer;
|
|
||||||
size_t m_input_size;
|
|
||||||
|
|
||||||
uint8_t* m_output_buffer;
|
|
||||||
size_t m_output_size;
|
|
||||||
|
|
||||||
size_t m_chunk_size;
|
|
||||||
|
|
||||||
bool m_is_loading;
|
|
||||||
std::mutex m_load_mutex;
|
|
||||||
std::condition_variable m_loading_finished;
|
|
||||||
std::thread m_load_thread;
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<IXChunkProcessor>>& m_processors;
|
|
||||||
|
|
||||||
void Load()
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(m_load_mutex);
|
public:
|
||||||
|
DbLoadStream(const int streamIndex, const size_t chunkSize, std::vector<std::unique_ptr<IXChunkProcessor>>& chunkProcessors)
|
||||||
bool firstProcessor = true;
|
: m_index(streamIndex),
|
||||||
|
m_input_size(0),
|
||||||
for (const auto& processor : m_processors)
|
m_output_size(0),
|
||||||
|
m_chunk_size(chunkSize),
|
||||||
|
m_is_loading(false),
|
||||||
|
m_processors(chunkProcessors)
|
||||||
{
|
{
|
||||||
if (!firstProcessor)
|
for (auto& buffer : m_buffers)
|
||||||
{
|
buffer = std::make_unique<uint8_t[]>(chunkSize);
|
||||||
uint8_t* previousInputBuffer = m_input_buffer;
|
|
||||||
m_input_buffer = m_output_buffer;
|
|
||||||
m_output_buffer = previousInputBuffer;
|
|
||||||
|
|
||||||
m_input_size = m_output_size;
|
m_input_buffer = m_buffers[0].get();
|
||||||
m_output_size = 0;
|
m_output_buffer = m_buffers[1].get();
|
||||||
}
|
|
||||||
|
|
||||||
m_output_size = processor->Process(m_index, m_input_buffer, m_input_size, m_output_buffer, m_chunk_size);
|
|
||||||
|
|
||||||
firstProcessor = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_is_loading = false;
|
[[nodiscard]] uint8_t* GetInputBuffer() const
|
||||||
m_loading_finished.notify_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
DBLoadStream(const int streamIndex, const size_t chunkSize, std::vector<std::unique_ptr<IXChunkProcessor>>& chunkProcessors)
|
|
||||||
: m_processors(chunkProcessors)
|
|
||||||
{
|
|
||||||
m_index = streamIndex;
|
|
||||||
m_chunk_size = chunkSize;
|
|
||||||
|
|
||||||
for (auto& buffer : m_buffers)
|
|
||||||
buffer = std::make_unique<uint8_t[]>(chunkSize);
|
|
||||||
|
|
||||||
m_input_buffer = m_buffers[0].get();
|
|
||||||
m_output_buffer = m_buffers[1].get();
|
|
||||||
|
|
||||||
m_input_size = 0;
|
|
||||||
m_output_size = 0;
|
|
||||||
|
|
||||||
m_is_loading = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] uint8_t* GetInputBuffer() const
|
|
||||||
{
|
|
||||||
return m_input_buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StartLoading(const size_t inputSize)
|
|
||||||
{
|
|
||||||
if (inputSize > 0)
|
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(m_load_mutex);
|
return m_input_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StartLoading(const size_t inputSize)
|
||||||
|
{
|
||||||
|
if (inputSize > 0)
|
||||||
|
{
|
||||||
|
std::unique_lock lock(m_load_mutex);
|
||||||
|
|
||||||
|
if (m_is_loading)
|
||||||
|
{
|
||||||
|
m_loading_finished.wait(lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_input_size = inputSize;
|
||||||
|
m_is_loading = true;
|
||||||
|
m_load_thread = std::thread(&DbLoadStream::Load, this);
|
||||||
|
m_load_thread.detach();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_output_size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetOutput(const uint8_t** pBuffer, size_t* pSize)
|
||||||
|
{
|
||||||
|
assert(pBuffer != nullptr);
|
||||||
|
assert(pSize != nullptr);
|
||||||
|
|
||||||
|
std::unique_lock lock(m_load_mutex);
|
||||||
if (m_is_loading)
|
if (m_is_loading)
|
||||||
{
|
{
|
||||||
m_loading_finished.wait(lock);
|
m_loading_finished.wait(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_input_size = inputSize;
|
*pBuffer = m_output_buffer;
|
||||||
m_is_loading = true;
|
*pSize = m_output_size;
|
||||||
m_load_thread = std::thread(&DBLoadStream::Load, this);
|
|
||||||
m_load_thread.detach();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_output_size = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetOutput(const uint8_t** pBuffer, size_t* pSize)
|
|
||||||
{
|
|
||||||
assert(pBuffer != nullptr);
|
|
||||||
assert(pSize != nullptr);
|
|
||||||
|
|
||||||
std::unique_lock<std::mutex> lock(m_load_mutex);
|
|
||||||
if (m_is_loading)
|
|
||||||
{
|
|
||||||
m_loading_finished.wait(lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*pBuffer = m_output_buffer;
|
private:
|
||||||
*pSize = m_output_size;
|
void Load()
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ProcessorXChunks::ProcessorXChunksImpl
|
|
||||||
{
|
|
||||||
ProcessorXChunks* m_base;
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<DBLoadStream>> m_streams;
|
|
||||||
size_t m_chunk_size;
|
|
||||||
size_t m_vanilla_buffer_size;
|
|
||||||
std::vector<std::unique_ptr<IXChunkProcessor>> m_chunk_processors;
|
|
||||||
|
|
||||||
bool m_initialized_streams;
|
|
||||||
unsigned int m_current_stream;
|
|
||||||
const uint8_t* m_current_chunk;
|
|
||||||
size_t m_current_chunk_size;
|
|
||||||
size_t m_current_chunk_offset;
|
|
||||||
size_t m_vanilla_buffer_offset;
|
|
||||||
|
|
||||||
bool m_eof_reached;
|
|
||||||
unsigned int m_eof_stream;
|
|
||||||
|
|
||||||
void AdvanceStream(const unsigned streamNum)
|
|
||||||
{
|
|
||||||
assert(streamNum < m_streams.size());
|
|
||||||
|
|
||||||
if (m_eof_reached)
|
|
||||||
return;
|
|
||||||
|
|
||||||
xchunk_size_t chunkSize;
|
|
||||||
if (m_vanilla_buffer_size > 0)
|
|
||||||
{
|
{
|
||||||
if (m_vanilla_buffer_offset + sizeof(chunkSize) > m_vanilla_buffer_size)
|
std::lock_guard lock(m_load_mutex);
|
||||||
|
|
||||||
|
bool firstProcessor = true;
|
||||||
|
|
||||||
|
for (const auto& processor : m_processors)
|
||||||
{
|
{
|
||||||
m_base->m_base_stream->Load(&chunkSize, m_vanilla_buffer_size - m_vanilla_buffer_offset);
|
if (!firstProcessor)
|
||||||
m_vanilla_buffer_offset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_vanilla_buffer_offset = (m_vanilla_buffer_offset + sizeof(chunkSize)) % m_vanilla_buffer_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t readSize = m_base->m_base_stream->Load(&chunkSize, sizeof(chunkSize));
|
|
||||||
|
|
||||||
if (readSize == 0)
|
|
||||||
{
|
|
||||||
m_eof_reached = true;
|
|
||||||
m_eof_stream = streamNum;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chunkSize > m_chunk_size)
|
|
||||||
{
|
|
||||||
throw InvalidChunkSizeException(chunkSize, m_chunk_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& stream = m_streams[streamNum];
|
|
||||||
const size_t loadedChunkSize = m_base->m_base_stream->Load(stream->GetInputBuffer(), chunkSize);
|
|
||||||
|
|
||||||
if (loadedChunkSize != chunkSize)
|
|
||||||
{
|
|
||||||
throw InvalidChunkSizeException(chunkSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_vanilla_buffer_size > 0)
|
|
||||||
{
|
|
||||||
m_vanilla_buffer_offset = (m_vanilla_buffer_offset + loadedChunkSize) % m_vanilla_buffer_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
stream->StartLoading(loadedChunkSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NextStream()
|
|
||||||
{
|
|
||||||
AdvanceStream(m_current_stream);
|
|
||||||
|
|
||||||
m_current_stream = (m_current_stream + 1) % m_streams.size();
|
|
||||||
m_current_chunk_offset = 0;
|
|
||||||
m_streams[m_current_stream]->GetOutput(&m_current_chunk, &m_current_chunk_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitStreams()
|
|
||||||
{
|
|
||||||
m_initialized_streams = true;
|
|
||||||
m_vanilla_buffer_offset = static_cast<size_t>(m_base->m_base_stream->Pos());
|
|
||||||
|
|
||||||
const auto streamCount = static_cast<unsigned>(m_streams.size());
|
|
||||||
for (auto streamNum = 0u; streamNum < streamCount; streamNum++)
|
|
||||||
{
|
|
||||||
AdvanceStream(streamNum);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_current_stream = 0;
|
|
||||||
m_current_chunk_offset = 0;
|
|
||||||
m_streams[0]->GetOutput(&m_current_chunk, &m_current_chunk_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] bool EndOfStream() const
|
|
||||||
{
|
|
||||||
return m_eof_reached && m_eof_stream == m_current_stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
ProcessorXChunksImpl(ProcessorXChunks* base, const int numStreams, const size_t xChunkSize)
|
|
||||||
{
|
|
||||||
assert(base != nullptr);
|
|
||||||
assert(numStreams > 0);
|
|
||||||
assert(xChunkSize > 0);
|
|
||||||
|
|
||||||
m_base = base;
|
|
||||||
|
|
||||||
for (int streamIndex = 0; streamIndex < numStreams; streamIndex++)
|
|
||||||
{
|
|
||||||
m_streams.emplace_back(std::make_unique<DBLoadStream>(streamIndex, xChunkSize, m_chunk_processors));
|
|
||||||
}
|
|
||||||
|
|
||||||
m_chunk_size = xChunkSize;
|
|
||||||
m_vanilla_buffer_size = 0;
|
|
||||||
|
|
||||||
m_initialized_streams = false;
|
|
||||||
m_current_stream = 0;
|
|
||||||
m_current_chunk = nullptr;
|
|
||||||
m_current_chunk_size = 0;
|
|
||||||
m_current_chunk_offset = 0;
|
|
||||||
m_vanilla_buffer_offset = 0;
|
|
||||||
|
|
||||||
m_eof_reached = false;
|
|
||||||
m_eof_stream = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessorXChunksImpl(ProcessorXChunks* base, const int numStreams, const size_t xChunkSize, const size_t vanillaBufferSize)
|
|
||||||
: ProcessorXChunksImpl(base, numStreams, xChunkSize)
|
|
||||||
{
|
|
||||||
m_vanilla_buffer_size = vanillaBufferSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddChunkProcessor(std::unique_ptr<IXChunkProcessor> streamProcessor)
|
|
||||||
{
|
|
||||||
assert(streamProcessor != nullptr);
|
|
||||||
|
|
||||||
m_chunk_processors.emplace_back(std::move(streamProcessor));
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t Load(void* buffer, const size_t length)
|
|
||||||
{
|
|
||||||
assert(buffer != nullptr);
|
|
||||||
|
|
||||||
if (!m_initialized_streams)
|
|
||||||
{
|
|
||||||
InitStreams();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t loadedSize = 0;
|
|
||||||
while (!EndOfStream() && loadedSize < length)
|
|
||||||
{
|
|
||||||
auto* bufferPos = static_cast<uint8_t*>(buffer) + loadedSize;
|
|
||||||
const size_t sizeToRead = length - loadedSize;
|
|
||||||
const size_t bytesLeftInCurrentChunk = m_current_chunk_size - m_current_chunk_offset;
|
|
||||||
|
|
||||||
if (sizeToRead > bytesLeftInCurrentChunk)
|
|
||||||
{
|
|
||||||
assert(sizeToRead >= bytesLeftInCurrentChunk);
|
|
||||||
memcpy(bufferPos, &m_current_chunk[m_current_chunk_offset], bytesLeftInCurrentChunk);
|
|
||||||
loadedSize += bytesLeftInCurrentChunk;
|
|
||||||
|
|
||||||
NextStream();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(bufferPos, &m_current_chunk[m_current_chunk_offset], sizeToRead);
|
|
||||||
loadedSize += sizeToRead;
|
|
||||||
m_current_chunk_offset += sizeToRead;
|
|
||||||
|
|
||||||
if (m_current_chunk_offset == m_current_chunk_size)
|
|
||||||
{
|
{
|
||||||
|
uint8_t* previousInputBuffer = m_input_buffer;
|
||||||
|
m_input_buffer = m_output_buffer;
|
||||||
|
m_output_buffer = previousInputBuffer;
|
||||||
|
|
||||||
|
m_input_size = m_output_size;
|
||||||
|
m_output_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_output_size = processor->Process(m_index, m_input_buffer, m_input_size, m_output_buffer, m_chunk_size);
|
||||||
|
|
||||||
|
firstProcessor = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_is_loading = false;
|
||||||
|
m_loading_finished.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
int m_index;
|
||||||
|
|
||||||
|
std::unique_ptr<uint8_t[]> m_buffers[2];
|
||||||
|
|
||||||
|
uint8_t* m_input_buffer;
|
||||||
|
size_t m_input_size;
|
||||||
|
|
||||||
|
uint8_t* m_output_buffer;
|
||||||
|
size_t m_output_size;
|
||||||
|
|
||||||
|
size_t m_chunk_size;
|
||||||
|
|
||||||
|
bool m_is_loading;
|
||||||
|
std::mutex m_load_mutex;
|
||||||
|
std::condition_variable m_loading_finished;
|
||||||
|
std::thread m_load_thread;
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<IXChunkProcessor>>& m_processors;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ProcessorXChunks final : public processor::IProcessorXChunks
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ProcessorXChunks(const int numStreams, const size_t xChunkSize, const std::optional<size_t> vanillaBufferSize)
|
||||||
|
: m_chunk_size(xChunkSize),
|
||||||
|
m_vanilla_buffer_size(vanillaBufferSize),
|
||||||
|
m_initialized_streams(false),
|
||||||
|
m_current_stream(0),
|
||||||
|
m_current_chunk(nullptr),
|
||||||
|
m_current_chunk_size(0),
|
||||||
|
m_current_chunk_offset(0),
|
||||||
|
m_vanilla_buffer_offset(0),
|
||||||
|
m_eof_reached(false),
|
||||||
|
m_eof_stream(0)
|
||||||
|
{
|
||||||
|
assert(numStreams > 0);
|
||||||
|
assert(xChunkSize > 0);
|
||||||
|
|
||||||
|
for (int streamIndex = 0; streamIndex < numStreams; streamIndex++)
|
||||||
|
{
|
||||||
|
m_streams.emplace_back(std::make_unique<DbLoadStream>(streamIndex, xChunkSize, m_chunk_processors));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Load(void* buffer, const size_t length) override
|
||||||
|
{
|
||||||
|
assert(buffer != nullptr);
|
||||||
|
|
||||||
|
if (!m_initialized_streams)
|
||||||
|
{
|
||||||
|
InitStreams();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t loadedSize = 0;
|
||||||
|
while (!EndOfStream() && loadedSize < length)
|
||||||
|
{
|
||||||
|
auto* bufferPos = static_cast<uint8_t*>(buffer) + loadedSize;
|
||||||
|
const size_t sizeToRead = length - loadedSize;
|
||||||
|
const size_t bytesLeftInCurrentChunk = m_current_chunk_size - m_current_chunk_offset;
|
||||||
|
|
||||||
|
if (sizeToRead > bytesLeftInCurrentChunk)
|
||||||
|
{
|
||||||
|
assert(sizeToRead >= bytesLeftInCurrentChunk);
|
||||||
|
memcpy(bufferPos, &m_current_chunk[m_current_chunk_offset], bytesLeftInCurrentChunk);
|
||||||
|
loadedSize += bytesLeftInCurrentChunk;
|
||||||
|
|
||||||
NextStream();
|
NextStream();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(bufferPos, &m_current_chunk[m_current_chunk_offset], sizeToRead);
|
||||||
|
loadedSize += sizeToRead;
|
||||||
|
m_current_chunk_offset += sizeToRead;
|
||||||
|
|
||||||
|
if (m_current_chunk_offset == m_current_chunk_size)
|
||||||
|
{
|
||||||
|
NextStream();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return loadedSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
return loadedSize;
|
int64_t Pos() override
|
||||||
}
|
{
|
||||||
|
return m_base_stream->Pos();
|
||||||
|
}
|
||||||
|
|
||||||
int64_t Pos() const
|
void AddChunkProcessor(std::unique_ptr<IXChunkProcessor> chunkProcessor) override
|
||||||
|
{
|
||||||
|
assert(chunkProcessor);
|
||||||
|
|
||||||
|
m_chunk_processors.emplace_back(std::move(chunkProcessor));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void AdvanceStream(const unsigned streamNum)
|
||||||
|
{
|
||||||
|
assert(streamNum < m_streams.size());
|
||||||
|
|
||||||
|
if (m_eof_reached)
|
||||||
|
return;
|
||||||
|
|
||||||
|
xchunk_size_t chunkSize;
|
||||||
|
if (m_vanilla_buffer_size.has_value())
|
||||||
|
{
|
||||||
|
if (m_vanilla_buffer_offset + sizeof(chunkSize) > *m_vanilla_buffer_size)
|
||||||
|
{
|
||||||
|
m_base_stream->Load(&chunkSize, *m_vanilla_buffer_size - m_vanilla_buffer_offset);
|
||||||
|
m_vanilla_buffer_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_vanilla_buffer_offset = (m_vanilla_buffer_offset + sizeof(chunkSize)) % *m_vanilla_buffer_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t readSize = m_base_stream->Load(&chunkSize, sizeof(chunkSize));
|
||||||
|
|
||||||
|
if (readSize == 0)
|
||||||
|
{
|
||||||
|
m_eof_reached = true;
|
||||||
|
m_eof_stream = streamNum;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chunkSize > m_chunk_size)
|
||||||
|
{
|
||||||
|
throw InvalidChunkSizeException(chunkSize, m_chunk_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& stream = m_streams[streamNum];
|
||||||
|
const size_t loadedChunkSize = m_base_stream->Load(stream->GetInputBuffer(), chunkSize);
|
||||||
|
|
||||||
|
if (loadedChunkSize != chunkSize)
|
||||||
|
{
|
||||||
|
throw InvalidChunkSizeException(chunkSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_vanilla_buffer_size.has_value())
|
||||||
|
{
|
||||||
|
m_vanilla_buffer_offset = (m_vanilla_buffer_offset + loadedChunkSize) % *m_vanilla_buffer_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->StartLoading(loadedChunkSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NextStream()
|
||||||
|
{
|
||||||
|
AdvanceStream(m_current_stream);
|
||||||
|
|
||||||
|
m_current_stream = (m_current_stream + 1) % m_streams.size();
|
||||||
|
m_current_chunk_offset = 0;
|
||||||
|
m_streams[m_current_stream]->GetOutput(&m_current_chunk, &m_current_chunk_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitStreams()
|
||||||
|
{
|
||||||
|
m_initialized_streams = true;
|
||||||
|
m_vanilla_buffer_offset = static_cast<size_t>(m_base_stream->Pos());
|
||||||
|
|
||||||
|
const auto streamCount = static_cast<unsigned>(m_streams.size());
|
||||||
|
for (auto streamNum = 0u; streamNum < streamCount; streamNum++)
|
||||||
|
{
|
||||||
|
AdvanceStream(streamNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_current_stream = 0;
|
||||||
|
m_current_chunk_offset = 0;
|
||||||
|
m_streams[0]->GetOutput(&m_current_chunk, &m_current_chunk_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool EndOfStream() const
|
||||||
|
{
|
||||||
|
return m_eof_reached && m_eof_stream == m_current_stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<DbLoadStream>> m_streams;
|
||||||
|
size_t m_chunk_size;
|
||||||
|
std::optional<size_t> m_vanilla_buffer_size;
|
||||||
|
std::vector<std::unique_ptr<IXChunkProcessor>> m_chunk_processors;
|
||||||
|
|
||||||
|
bool m_initialized_streams;
|
||||||
|
unsigned int m_current_stream;
|
||||||
|
const uint8_t* m_current_chunk;
|
||||||
|
size_t m_current_chunk_size;
|
||||||
|
size_t m_current_chunk_offset;
|
||||||
|
size_t m_vanilla_buffer_offset;
|
||||||
|
|
||||||
|
bool m_eof_reached;
|
||||||
|
unsigned int m_eof_stream;
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace processor
|
||||||
|
{
|
||||||
|
std::unique_ptr<IProcessorXChunks> CreateProcessorXChunks(int numStreams, const size_t xChunkSize)
|
||||||
{
|
{
|
||||||
return m_base->m_base_stream->Pos();
|
return std::make_unique<ProcessorXChunks>(numStreams, xChunkSize, std::nullopt);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
ProcessorXChunks::ProcessorXChunks(const int numStreams, const size_t xChunkSize)
|
std::unique_ptr<IProcessorXChunks> CreateProcessorXChunks(int numStreams, const size_t xChunkSize, const size_t vanillaBufferSize)
|
||||||
{
|
{
|
||||||
m_impl = new ProcessorXChunksImpl(this, numStreams, xChunkSize);
|
return std::make_unique<ProcessorXChunks>(numStreams, xChunkSize, vanillaBufferSize);
|
||||||
}
|
}
|
||||||
|
} // namespace processor
|
||||||
ProcessorXChunks::ProcessorXChunks(const int numStreams, const size_t xChunkSize, const size_t vanillaBufferSize)
|
|
||||||
{
|
|
||||||
m_impl = new ProcessorXChunksImpl(this, numStreams, xChunkSize, vanillaBufferSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessorXChunks::~ProcessorXChunks()
|
|
||||||
{
|
|
||||||
delete m_impl;
|
|
||||||
m_impl = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProcessorXChunks::AddChunkProcessor(std::unique_ptr<IXChunkProcessor> chunkProcessor) const
|
|
||||||
{
|
|
||||||
m_impl->AddChunkProcessor(std::move(chunkProcessor));
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t ProcessorXChunks::Load(void* buffer, const size_t length)
|
|
||||||
{
|
|
||||||
return m_impl->Load(buffer, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t ProcessorXChunks::Pos()
|
|
||||||
{
|
|
||||||
return m_impl->Pos();
|
|
||||||
}
|
|
||||||
|
@ -4,18 +4,14 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class ProcessorXChunks : public StreamProcessor
|
namespace processor
|
||||||
{
|
{
|
||||||
class ProcessorXChunksImpl;
|
class IProcessorXChunks : public StreamProcessor
|
||||||
ProcessorXChunksImpl* m_impl;
|
{
|
||||||
|
public:
|
||||||
|
virtual void AddChunkProcessor(std::unique_ptr<IXChunkProcessor> chunkProcessor) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
std::unique_ptr<IProcessorXChunks> CreateProcessorXChunks(int numStreams, size_t xChunkSize);
|
||||||
ProcessorXChunks(int numStreams, size_t xChunkSize);
|
std::unique_ptr<IProcessorXChunks> CreateProcessorXChunks(int numStreams, size_t xChunkSize, size_t vanillaBufferSize);
|
||||||
ProcessorXChunks(int numStreams, size_t xChunkSize, size_t vanillaBufferSize);
|
} // namespace processor
|
||||||
~ProcessorXChunks() override;
|
|
||||||
|
|
||||||
size_t Load(void* buffer, size_t length) override;
|
|
||||||
int64_t Pos() override;
|
|
||||||
|
|
||||||
void AddChunkProcessor(std::unique_ptr<IXChunkProcessor> chunkProcessor) const;
|
|
||||||
};
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user