2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2025-06-26 06:11:53 +00:00

Rename ZoneLoader and ZoneWriter components to ZoneLoading and ZoneWriting to make a difference between the executive class and the component class

This commit is contained in:
Jan
2019-09-24 22:35:11 +02:00
parent 0d8432d4f7
commit 42af6df5d8
86 changed files with 22 additions and 13 deletions

View File

@ -0,0 +1,136 @@
#include "ContentLoaderT6.h"
#include "Game/T6/T6.h"
#include "Loading/Exception/UnsupportedAssetTypeException.h"
#include <cassert>
#include "Game/T6/XAssets/rawfile/rawfile_load_db.h"
using namespace T6;
ContentLoaderT6::ContentLoaderT6()
{
// Script String 0 is always empty string
m_script_strings.emplace_back("");
}
void ContentLoaderT6::LoadScriptStringList(ScriptStringList* scriptStringList)
{
m_stream->PushBlock(XFILE_BLOCK_VIRTUAL);
if(scriptStringList->strings != nullptr)
{
assert(scriptStringList->strings == PTR_FOLLOWING);
scriptStringList->strings = m_stream->Alloc<const char*>();
LoadXStringArray(scriptStringList->strings, scriptStringList->count, true);
for(int i = 0; i < scriptStringList->count; i++)
{
m_script_strings.emplace_back(scriptStringList->strings[i]);
}
}
m_stream->PopBlock();
}
void ContentLoaderT6::LoadXAsset(XAsset* pXAsset, const bool atStreamStart)
{
assert(pXAsset != nullptr);
if(atStreamStart)
m_stream->Load<XAsset>();
switch(pXAsset->type)
{
case ASSET_TYPE_RAWFILE:
{
RawFileLoader rawFileLoader(this, m_zone, m_stream);
rawFileLoader.LoadRawFilePtr(&pXAsset->header.rawfile);
break;
}
default:
{
throw UnsupportedAssetTypeException(pXAsset->type);
}
}
}
void ContentLoaderT6::LoadXAssetArray(XAsset* pArray, const size_t count, const bool atStreamStart)
{
assert(pArray != nullptr);
if(atStreamStart)
m_stream->Load<XAsset>(count);
size_t assetCounts[ASSET_TYPE_COUNT]{0};
for(size_t index = 0; index < count; index++)
{
assert(pArray[index].type >= 0 && pArray[index].type < ASSET_TYPE_COUNT);
if(pArray[index].type >= 0 && pArray[index].type < ASSET_TYPE_COUNT)
{
assetCounts[pArray[index].type]++;
}
}
// Special case: CLIPMAP and CLIPMAP_PVS are the same struct and therefore share the same asset pool
assetCounts[ASSET_TYPE_CLIPMAP_PVS] += assetCounts[ASSET_TYPE_CLIPMAP];
assetCounts[ASSET_TYPE_CLIPMAP] = 0;
for(asset_type_t assetType = 0; assetType < ASSET_TYPE_COUNT; assetType++)
{
m_zone->GetPools()->InitPoolStatic(assetType, assetCounts[assetType]);
}
for(size_t index = 0; index < count; index++)
{
LoadXAsset(&pArray[index], false);
}
}
void ContentLoaderT6::Load(Zone* zone, IZoneInputStream* stream)
{
m_zone = zone;
m_stream = stream;
m_stream->PushBlock(XFILE_BLOCK_VIRTUAL);
auto* assetList = m_stream->Alloc<XAssetList>();
m_stream->Load<XAssetList>();
LoadScriptStringList(&assetList->stringList);
if(assetList->depends != nullptr)
{
assert(assetList->depends == PTR_FOLLOWING);
assetList->depends = m_stream->Alloc<const char*>();
LoadXStringArray(assetList->depends, assetList->dependCount, true);
}
if(assetList->assets != nullptr)
{
assert(assetList->assets == PTR_FOLLOWING);
assetList->assets = m_stream->Alloc<XAsset>();
LoadXAssetArray(assetList->assets, assetList->assetCount, true);
}
m_stream->PopBlock();
}
std::string& ContentLoaderT6::GetZoneScriptString(const scr_string_t scrString)
{
assert(scrString >= 0 && scrString < m_script_strings.size());
if(scrString < 0 || scrString >= m_script_strings.size())
{
return m_script_strings[0];
}
return m_script_strings[scrString];
}

View File

@ -0,0 +1,21 @@
#pragma once
#include "Loading/ContentLoader.h"
#include "Loading/IContentLoadingEntryPoint.h"
#include "Game/T6/T6.h"
#include "Loading/IZoneScriptStringProvider.h"
class ContentLoaderT6 final : public ContentLoader, public IContentLoadingEntryPoint, public IZoneScriptStringProvider
{
std::vector<std::string> m_script_strings;
void LoadScriptStringList(T6::ScriptStringList* scriptStringList);
void LoadXAsset(T6::XAsset* pXAsset, bool atStreamStart);
void LoadXAssetArray(T6::XAsset* pArray, size_t count, bool atStreamStart);
public:
ContentLoaderT6();
void Load(Zone* zone, IZoneInputStream* stream) override;
std::string& GetZoneScriptString(scr_string_t scrString) override;
};

View File

@ -0,0 +1,70 @@
#include "rawfile_load_db.h"
#include <cassert>
using namespace T6;
RawFileLoader::RawFileLoader(IZoneScriptStringProvider* scriptStringProvider, Zone* zone, IZoneInputStream* stream)
: AssetLoader(ASSET_TYPE_RAWFILE, scriptStringProvider, zone, stream){}
void RawFileLoader::LoadRawFile(RawFile* pRawFile, const bool atStreamStart)
{
assert(pRawFile != nullptr);
if(atStreamStart)
m_stream->Load<RawFile>();
m_stream->PushBlock(XFILE_BLOCK_VIRTUAL);
LoadXString(&pRawFile->name);
if(pRawFile->buffer != nullptr)
{
assert(pRawFile->buffer == PTR_FOLLOWING);
pRawFile->buffer = m_stream->Alloc<const char>(16);
m_stream->Load<const char>(pRawFile->len + 1);
}
m_stream->PopBlock();
}
void RawFileLoader::LoadRawFileAsset(RawFile** pPtr)
{
assert(pPtr != nullptr);
*pPtr = static_cast<RawFile*>(LinkAsset(GetRawFileName(*pPtr), *pPtr));
}
void RawFileLoader::LoadRawFilePtr(RawFile** pPtr)
{
assert(pPtr != nullptr);
m_stream->PushBlock(XFILE_BLOCK_TEMP);
if(*pPtr != nullptr)
{
if(*pPtr == PTR_FOLLOWING || *pPtr == PTR_INSERT)
{
RawFile** toInsert = nullptr;
if(*pPtr == PTR_INSERT)
toInsert = m_stream->InsertPointer<RawFile>();
*pPtr = m_stream->Alloc<RawFile>();
LoadRawFile(*pPtr, true);
LoadRawFileAsset(pPtr);
if(toInsert != nullptr)
*toInsert = *pPtr;
}
else
{
*pPtr = m_stream->ConvertOffsetToAlias(*pPtr);
}
}
m_stream->PopBlock();
}
std::string RawFileLoader::GetRawFileName(RawFile* pRawFile)
{
return pRawFile->name;
}

View File

@ -0,0 +1,18 @@
#pragma once
#include "Loading/AssetLoader.h"
#include "Game/T6/T6.h"
namespace T6
{
class RawFileLoader final : public AssetLoader
{
void LoadRawFile(RawFile* pRawFile, bool atStreamStart);
void LoadRawFileAsset(RawFile** pPtr);
public:
RawFileLoader(IZoneScriptStringProvider* scriptStringProvider, Zone* zone, IZoneInputStream* stream);
void LoadRawFilePtr(RawFile** pPtr);
static std::string GetRawFileName(RawFile* pRawFile);
};
}

View File

@ -0,0 +1,240 @@
#include "ZoneLoaderFactoryT6.h"
#include "Game/T6/T6.h"
#include "Loading/Steps/StepVerifyMagic.h"
#include "Loading/Steps/StepSkipBytes.h"
#include "Loading/Steps/StepVerifyFileName.h"
#include "Loading/Steps/StepLoadSignature.h"
#include "Loading/Steps/StepVerifySignature.h"
#include "Loading/Steps/StepAddProcessor.h"
#include "Loading/Steps/StepAllocXBlocks.h"
#include "Loading/Processor/ProcessorXChunks.h"
#include "Loading/Processor/XChunks/ChunkProcessorSalsa20.h"
#include "Loading/Processor/XChunks/ChunkProcessorInflate.h"
#include "Utils/ClassUtils.h"
#include <cassert>
#include "Loading/Steps/StepLoadZoneContent.h"
#include "ContentLoaderT6.h"
#include "Game/T6/GameAssetPoolT6.h"
#include "Game/T6/GameT6.h"
const std::string ZoneLoaderFactoryT6::MAGIC_SIGNED_TREYARCH = "TAff0100";
const std::string ZoneLoaderFactoryT6::MAGIC_SIGNED_ASSET_BUILDER = "ABff0100";
const std::string ZoneLoaderFactoryT6::MAGIC_UNSIGNED = "TAffu100";
const int ZoneLoaderFactoryT6::VERSION = 147;
const int ZoneLoaderFactoryT6::STREAM_COUNT = 4;
const int ZoneLoaderFactoryT6::XCHUNK_SIZE = 0x8000;
const int ZoneLoaderFactoryT6::OFFSET_BLOCK_BIT_COUNT = 3;
const block_t ZoneLoaderFactoryT6::INSERT_BLOCK = T6::XFILE_BLOCK_VIRTUAL;
const std::string ZoneLoaderFactoryT6::MAGIC_AUTH_HEADER = "PHEEBs71";
const uint8_t ZoneLoaderFactoryT6::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 ZoneLoaderFactoryT6::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 ZoneLoaderFactoryT6::ZoneLoaderFactoryT6Impl
{
static bool CanLoad(ZoneHeader& header, bool* isSecure, bool* isOfficial)
{
assert(isSecure != nullptr);
assert(isOfficial != nullptr);
if(header.m_version != VERSION)
{
return false;
}
if(!memcmp(header.m_magic, MAGIC_SIGNED_TREYARCH.c_str(), 8))
{
*isSecure = true;
*isOfficial = true;
return true;
}
if(!memcmp(header.m_magic, MAGIC_SIGNED_ASSET_BUILDER.c_str(), 8))
{
*isSecure = true;
*isOfficial = false;
return true;
}
if(!memcmp(header.m_magic, MAGIC_UNSIGNED.c_str(), 8))
{
*isSecure = false;
*isOfficial = true;
return true;
}
return false;
}
static void SetupBlock(ZoneLoader* zoneLoader)
{
#define XBLOCK_DEF(name, type) new XBlock(STR(name), name, type)
zoneLoader->AddXBlock(XBLOCK_DEF(T6::XFILE_BLOCK_TEMP, XBlock::BLOCK_TYPE_TEMP));
zoneLoader->AddXBlock(XBLOCK_DEF(T6::XFILE_BLOCK_RUNTIME_VIRTUAL, XBlock::BLOCK_TYPE_RUNTIME));
zoneLoader->AddXBlock(XBLOCK_DEF(T6::XFILE_BLOCK_RUNTIME_PHYSICAL, XBlock::BLOCK_TYPE_RUNTIME));
zoneLoader->AddXBlock(XBLOCK_DEF(T6::XFILE_BLOCK_DELAY_VIRTUAL, XBlock::BLOCK_TYPE_DELAY));
zoneLoader->AddXBlock(XBLOCK_DEF(T6::XFILE_BLOCK_DELAY_PHYSICAL, XBlock::BLOCK_TYPE_DELAY));
zoneLoader->AddXBlock(XBLOCK_DEF(T6::XFILE_BLOCK_VIRTUAL, XBlock::BLOCK_TYPE_NORMAL));
zoneLoader->AddXBlock(XBLOCK_DEF(T6::XFILE_BLOCK_PHYSICAL, XBlock::BLOCK_TYPE_NORMAL));
zoneLoader->AddXBlock(XBLOCK_DEF(T6::XFILE_BLOCK_STREAMER_RESERVE, XBlock::BLOCK_TYPE_NORMAL));
#undef XBLOCK_DEF
}
static IPublicKeyAlgorithm* SetupRSA(const bool isOfficial)
{
if(isOfficial)
{
auto* rsa = Crypto::CreateRSA(IPublicKeyAlgorithm::RSA_HASH_SHA256, Crypto::RSA_PADDING_PSS);
if(!rsa->SetKey(RSA_PUBLIC_KEY_TREYARCH, sizeof(RSA_PUBLIC_KEY_TREYARCH)))
{
printf("Invalid public key for signature checking\n");
delete rsa;
return nullptr;
}
return rsa;
}
else
{
assert(false);
// TODO: Load custom RSA key here
return nullptr;
}
}
static ISignatureProvider* AddAuthHeaderSteps(const bool isSecure, ZoneLoader* zoneLoader, std::string& fileName)
{
// Unsigned zones do not have an auth header
if(!isSecure)
return nullptr;
zoneLoader->AddLoadingStep(new StepVerifyMagic(MAGIC_AUTH_HEADER.c_str()));
zoneLoader->AddLoadingStep(new StepSkipBytes(4)); // Loading Flags which are always zero
zoneLoader->AddLoadingStep(new StepVerifyFileName(fileName, 32));
auto* signatureLoadStep = new StepLoadSignature(256);
zoneLoader->AddLoadingStep(signatureLoadStep);
return signatureLoadStep;
}
static ISignatureDataProvider* AddXChunkProcessor(ZoneLoader* zoneLoader, std::string& fileName)
{
auto* xChunkProcessor = new ProcessorXChunks(STREAM_COUNT, XCHUNK_SIZE);
// First decrypt the chunks with Salsa20
auto* chunkProcessorSalsa20 = new ChunkProcessorSalsa20(STREAM_COUNT, fileName, SALSA20_KEY_TREYARCH, sizeof(SALSA20_KEY_TREYARCH));
xChunkProcessor->AddChunkProcessor(chunkProcessorSalsa20);
// Then decompress the chunks using zlib
xChunkProcessor->AddChunkProcessor(new ChunkProcessorInflate());
zoneLoader->AddLoadingStep(new StepAddProcessor(xChunkProcessor));
// The signed data of the zone is the final hash blocks provided by the Salsa20 IV adaption algorithm
return chunkProcessorSalsa20;
}
public:
static ZoneLoader* CreateLoaderForHeader(ZoneHeader& header, std::string& fileName)
{
bool isSecure;
bool isOfficial;
// Check if this file is a supported T6 zone.
if(!CanLoad(header, &isSecure, &isOfficial))
return nullptr;
// Create new zone
auto* zone = new Zone(fileName, 0, new GameAssetPoolT6(0), &game_t6);
// File is supported. Now setup all required steps for loading this file.
auto* zoneLoader = new ZoneLoader(zone);
SetupBlock(zoneLoader);
// If file is signed setup a RSA instance.
IPublicKeyAlgorithm* rsa = isSecure ? SetupRSA(isOfficial) : nullptr;
// Add steps for loading the auth header which also contain the signature of the zone if it is signed.
ISignatureProvider* signatureProvider = AddAuthHeaderSteps(isSecure, zoneLoader, fileName);
// Setup loading XChunks from the zone from this point on.
ISignatureDataProvider* signatureDataProvider = AddXChunkProcessor(zoneLoader, fileName);
// Start of the XFile struct
zoneLoader->AddLoadingStep(new StepSkipBytes(8)); // Skip size and externalSize fields since they are not interesting for us
zoneLoader->AddLoadingStep(new StepAllocXBlocks());
// Start of the zone content
zoneLoader->AddLoadingStep(new StepLoadZoneContent(new ContentLoaderT6(), zone, OFFSET_BLOCK_BIT_COUNT, INSERT_BLOCK));
if(isSecure)
{
zoneLoader->AddLoadingStep(new StepVerifySignature(rsa, signatureProvider, signatureDataProvider));
}
// Return the fully setup zoneloader
return zoneLoader;
}
};
ZoneLoader* ZoneLoaderFactoryT6::CreateLoaderForHeader(ZoneHeader& header, std::string& fileName)
{
return ZoneLoaderFactoryT6Impl::CreateLoaderForHeader(header, fileName);
}

View File

@ -0,0 +1,26 @@
#pragma once
#include "Loading/IZoneLoaderFactory.h"
#include <string>
class ZoneLoaderFactoryT6 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 int VERSION;
static const int STREAM_COUNT;
static const int XCHUNK_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 ZoneLoaderFactoryT6Impl;
public:
ZoneLoader* CreateLoaderForHeader(ZoneHeader& header, std::string& fileName) override;
};

View File

@ -0,0 +1,53 @@
#include "AssetLoader.h"
AssetLoader::AssetLoader(const asset_type_t assetType, IZoneScriptStringProvider* scriptStringProvider, Zone* zone, IZoneInputStream* stream)
{
m_asset_type = assetType;
m_script_string_provider = scriptStringProvider;
m_zone = zone;
m_stream = stream;
}
void AssetLoader::AddDependency(const asset_type_t type, std::string& name)
{
for(auto& existingDependency : m_dependencies)
{
if(existingDependency.m_type == type
&& existingDependency.m_name == name)
{
return;
}
}
XAssetDependency dependency;
dependency.m_type = type;
dependency.m_name = name;
m_dependencies.push_back(dependency);
}
scr_string_t AssetLoader::UseScriptString(const scr_string_t scrString)
{
std::string& scrStringValue = m_script_string_provider->GetZoneScriptString(scrString);
scr_string_t scriptStringIndex = 0;
for(auto& existingScriptString : m_used_script_strings)
{
if(existingScriptString == scrStringValue)
{
return scriptStringIndex;
}
scriptStringIndex++;
}
scriptStringIndex = static_cast<scr_string_t>(m_used_script_strings.size());
m_used_script_strings.push_back(scrStringValue);
return scriptStringIndex;
}
void* AssetLoader::LinkAsset(std::string name, void* asset)
{
return m_zone->GetPools()->AddAsset(m_asset_type, std::move(name), asset, m_used_script_strings, m_dependencies);
}

View File

@ -0,0 +1,22 @@
#pragma once
#include "ContentLoader.h"
#include "IZoneScriptStringProvider.h"
#include "Zone/XAssetDependency.h"
class AssetLoader : public ContentLoader
{
asset_type_t m_asset_type;
IZoneScriptStringProvider* m_script_string_provider;
std::vector<std::string> m_used_script_strings;
std::vector<XAssetDependency> m_dependencies;
protected:
AssetLoader(asset_type_t assetType, IZoneScriptStringProvider* scriptStringProvider, Zone* zone, IZoneInputStream* stream);
void AddDependency(asset_type_t type, std::string& name);
scr_string_t UseScriptString(scr_string_t scrString);
void* LinkAsset(std::string name, void* asset);
};

View File

@ -0,0 +1,42 @@
#include "ContentLoader.h"
#include <cassert>
const void* ContentLoader::PTR_FOLLOWING = reinterpret_cast<void*>(-1);
const void* ContentLoader::PTR_INSERT = reinterpret_cast<void*>(-2);
ContentLoader::ContentLoader()
{
m_zone = nullptr;
m_stream = nullptr;
}
void ContentLoader::LoadXString(const char** pXString) const
{
assert(pXString != nullptr);
if(*pXString != nullptr)
{
if(*pXString == PTR_FOLLOWING)
{
*pXString = m_stream->Alloc<const char>();
m_stream->LoadNullTerminated();
}
else
{
*pXString = m_stream->ConvertOffsetToPointer<const char>(*pXString);
}
}
}
void ContentLoader::LoadXStringArray(const char** pArray, const size_t count, const bool atStreamStart) const
{
assert(pArray != nullptr);
if(atStreamStart)
m_stream->Load<const char*>(count);
for(size_t index = 0; index < count; index++)
{
LoadXString(&pArray[index]);
}
}

View File

@ -0,0 +1,22 @@
#pragma once
#include "Zone/Zone.h"
#include "Zone/Stream/IZoneInputStream.h"
class ContentLoader
{
protected:
static const void* PTR_FOLLOWING;
static const void* PTR_INSERT;
Zone* m_zone;
IZoneInputStream* m_stream;
ContentLoader();
void LoadXString(const char** pXString) const;
void LoadXStringArray(const char** pArray, size_t count, bool atStreamStart) const;
public:
virtual ~ContentLoader() = default;
};

View File

@ -0,0 +1,16 @@
#include "BlockOverflowException.h"
BlockOverflowException::BlockOverflowException(XBlock* block)
{
m_block = block;
}
std::string BlockOverflowException::DetailedMessage()
{
return "XBlock " + m_block->m_name + " overflowed while trying to load zone.";
}
char const* BlockOverflowException::what() const
{
return "Invalid Zone. XBlock overflowed.";
}

View File

@ -0,0 +1,14 @@
#pragma once
#include "LoadingException.h"
#include "Zone/XBlock.h"
class BlockOverflowException final : public LoadingException
{
XBlock* m_block;
public:
explicit BlockOverflowException(XBlock* block);
std::string DetailedMessage() override;
char const* what() const override;
};

View File

@ -0,0 +1,30 @@
#include "InvalidChunkSizeException.h"
InvalidChunkSizeException::InvalidChunkSizeException(const size_t size)
{
m_size = size;
m_max = 0;
}
InvalidChunkSizeException::InvalidChunkSizeException(const size_t size, const size_t max)
{
m_size = size;
m_max = max;
}
std::string InvalidChunkSizeException::DetailedMessage()
{
if(m_max > 0)
{
return "Zone chunk size has a chunk size of " + std::to_string(m_size) + " which is larger than the maximum of " + std::to_string(m_max);
}
else
{
return "Zone chunk size has an invalid chunk size of " + std::to_string(m_size);
}
}
char const* InvalidChunkSizeException::what() const
{
return "Zone has invalid chunk size";
}

View File

@ -0,0 +1,15 @@
#pragma once
#include "LoadingException.h"
class InvalidChunkSizeException final : public LoadingException
{
size_t m_size;
size_t m_max;
public:
explicit InvalidChunkSizeException(size_t size);
InvalidChunkSizeException(size_t size, size_t max);
std::string DetailedMessage() override;
char const* what() const override;
};

View File

@ -0,0 +1,11 @@
#include "InvalidCompressionException.h"
std::string InvalidCompressionException::DetailedMessage()
{
return "Zone has invalid or unsupported compression. Inflate failed";
}
char const* InvalidCompressionException::what() const
{
return "Zone has invalid or unsupported compression. Inflate failed";
}

View File

@ -0,0 +1,9 @@
#pragma once
#include "LoadingException.h"
class InvalidCompressionException final : public LoadingException
{
public:
std::string DetailedMessage() override;
char const* what() const override;
};

View File

@ -0,0 +1,17 @@
#include "InvalidFileNameException.h"
InvalidFileNameException::InvalidFileNameException(std::string& actualFileName, std::string& expectedFileName)
{
m_actual_file_name = actualFileName;
m_expected_file_name = expectedFileName;
}
std::string InvalidFileNameException::DetailedMessage()
{
return "Name verification failed: The fastfile was created as '" + m_expected_file_name + "' but loaded as '" + m_actual_file_name + "'";
}
char const* InvalidFileNameException::what() const
{
return "The filename when created and when loaded does not match";
}

View File

@ -0,0 +1,14 @@
#pragma once
#include "LoadingException.h"
class InvalidFileNameException final : public LoadingException
{
std::string m_actual_file_name;
std::string m_expected_file_name;
public:
InvalidFileNameException(std::string& actualFileName, std::string& expectedFileName);
std::string DetailedMessage() override;
char const* what() const override;
};

View File

@ -0,0 +1,16 @@
#include "InvalidMagicException.h"
InvalidMagicException::InvalidMagicException(const char* expectedMagic)
{
m_expected_magic = expectedMagic;
}
std::string InvalidMagicException::DetailedMessage()
{
return "Expected magic '" + std::string(m_expected_magic) + "'";
}
char const* InvalidMagicException::what() const
{
return "Encountered invalid magic when loading.";
}

View File

@ -0,0 +1,13 @@
#pragma once
#include "LoadingException.h"
class InvalidMagicException final : public LoadingException
{
const char* m_expected_magic;
public:
explicit InvalidMagicException(const char* expectedMagic);
std::string DetailedMessage() override;
char const* what() const override;
};

View File

@ -0,0 +1,16 @@
#include "InvalidOffsetBlockException.h"
InvalidOffsetBlockException::InvalidOffsetBlockException(const block_t referencedBlock)
{
m_referenced_block = referencedBlock;
}
std::string InvalidOffsetBlockException::DetailedMessage()
{
return "Zone tried to reference invalid block " + std::to_string(m_referenced_block);
}
char const* InvalidOffsetBlockException::what() const
{
return "Zone referenced invalid block";
}

View File

@ -0,0 +1,14 @@
#pragma once
#include "LoadingException.h"
#include "Zone/ZoneTypes.h"
class InvalidOffsetBlockException final : public LoadingException
{
block_t m_referenced_block;
public:
explicit InvalidOffsetBlockException(block_t referencedBlock);
std::string DetailedMessage() override;
char const* what() const override;
};

View File

@ -0,0 +1,18 @@
#include "InvalidOffsetBlockOffsetException.h"
InvalidOffsetBlockOffsetException::InvalidOffsetBlockOffsetException(XBlock* block, const size_t referencedOffset)
{
m_referenced_block = block;
m_referenced_offset = referencedOffset;
}
std::string InvalidOffsetBlockOffsetException::DetailedMessage()
{
return "Zone referenced offset" + std::to_string(m_referenced_offset) + " of block " + m_referenced_block->m_name
+ " which is larger than its size " + std::to_string(m_referenced_block->m_buffer_size);
}
char const* InvalidOffsetBlockOffsetException::what() const
{
return "Zone referenced offset of block that is out of bounds";
}

View File

@ -0,0 +1,15 @@
#pragma once
#include "LoadingException.h"
#include "Zone/XBlock.h"
class InvalidOffsetBlockOffsetException final : public LoadingException
{
XBlock* m_referenced_block;
size_t m_referenced_offset;
public:
InvalidOffsetBlockOffsetException(XBlock* block, size_t referencedOffset);
std::string DetailedMessage() override;
char const* what() const override;
};

View File

@ -0,0 +1,11 @@
#include "InvalidSignatureException.h"
std::string InvalidSignatureException::DetailedMessage()
{
return "Loaded fastfile has an invalid signature.";
}
char const* InvalidSignatureException::what() const
{
return "Loaded fastfile has an invalid signature.";
}

View File

@ -0,0 +1,9 @@
#pragma once
#include "LoadingException.h"
class InvalidSignatureException final : public LoadingException
{
public:
std::string DetailedMessage() override;
char const* what() const override;
};

View File

@ -0,0 +1,17 @@
#include "InvalidVersionException.h"
InvalidVersionException::InvalidVersionException(const unsigned int expectedVersion, const unsigned int actualVersion)
{
m_expected_version = expectedVersion;
m_actual_version = actualVersion;
}
std::string InvalidVersionException::DetailedMessage()
{
return "Expected version " + std::to_string(m_expected_version) + " but encountered version " + std::to_string(m_actual_version);
}
char const* InvalidVersionException::what() const
{
return "Encountered invalid version when loading.";
}

View File

@ -0,0 +1,14 @@
#pragma once
#include "LoadingException.h"
class InvalidVersionException final : public LoadingException
{
unsigned int m_expected_version;
unsigned int m_actual_version;
public:
InvalidVersionException(unsigned int expectedVersion, unsigned int actualVersion);
std::string DetailedMessage() override;
char const* what() const override;
};

View File

@ -0,0 +1,17 @@
#include "InvalidXBlockSizeException.h"
InvalidXBlockSizeException::InvalidXBlockSizeException(const uint64_t size, const uint64_t max)
{
m_size = size;
m_max = max;
}
std::string InvalidXBlockSizeException::DetailedMessage()
{
return "Zone uses more XBlock memory than allowed: " + std::to_string(m_size) + " (max is " + std::to_string(m_max) + ")";
}
char const* InvalidXBlockSizeException::what() const
{
return "Zone has invalid block size";
}

View File

@ -0,0 +1,14 @@
#pragma once
#include "LoadingException.h"
class InvalidXBlockSizeException final : public LoadingException
{
uint64_t m_size;
uint64_t m_max;
public:
InvalidXBlockSizeException(uint64_t size, uint64_t max);
std::string DetailedMessage() override;
char const* what() const override;
};

View File

@ -0,0 +1,9 @@
#pragma once
#include <exception>
#include <string>
class LoadingException : public std::exception
{
public:
virtual std::string DetailedMessage() = 0;
};

View File

@ -0,0 +1,13 @@
#include "UnexpectedEndOfFileException.h"
UnexpectedEndOfFileException::UnexpectedEndOfFileException() = default;
std::string UnexpectedEndOfFileException::DetailedMessage()
{
return "Unexpected end of file";
}
char const* UnexpectedEndOfFileException::what() const
{
return "Unexpected end of file";
}

View File

@ -0,0 +1,11 @@
#pragma once
#include "LoadingException.h"
class UnexpectedEndOfFileException final : public LoadingException
{
public:
UnexpectedEndOfFileException();
std::string DetailedMessage() override;
char const* what() const override;
};

View File

@ -0,0 +1,16 @@
#include "UnsupportedAssetTypeException.h"
UnsupportedAssetTypeException::UnsupportedAssetTypeException(const int assetType)
{
m_asset_type = assetType;
}
std::string UnsupportedAssetTypeException::DetailedMessage()
{
return "Zone has an unsupported asset type " + std::to_string(m_asset_type) + " and therefore cannot be loaded.";
}
char const* UnsupportedAssetTypeException::what() const
{
return "Zone has unsupported asset type.";
}

View File

@ -0,0 +1,13 @@
#pragma once
#include "LoadingException.h"
class UnsupportedAssetTypeException final : public LoadingException
{
int m_asset_type;
public:
explicit UnsupportedAssetTypeException(int assetType);
std::string DetailedMessage() override;
char const* what() const override;
};

View File

@ -0,0 +1,12 @@
#pragma once
#include "Zone/Zone.h"
#include "Zone/Stream/IZoneInputStream.h"
class IContentLoadingEntryPoint
{
public:
virtual ~IContentLoadingEntryPoint() = default;
virtual void Load(Zone* zone, IZoneInputStream* stream) = 0;
};

View File

@ -0,0 +1,14 @@
#pragma once
#include "Loading/ZoneLoader.h"
#include "ILoadingStream.h"
class ZoneLoader;
class ILoadingStep
{
public:
virtual ~ILoadingStep() = default;
virtual void PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream) = 0;
};

View File

@ -0,0 +1,9 @@
#pragma once
class ILoadingStream
{
public:
virtual ~ILoadingStream() = default;
virtual size_t Load(void* buffer, size_t length) = 0;
};

View File

@ -0,0 +1,8 @@
#pragma once
#include <cstdint>
class ISignatureDataProvider
{
public:
virtual void GetSignatureData(const uint8_t** pSignatureData, size_t* pSize) = 0;
};

View File

@ -0,0 +1,8 @@
#pragma once
#include <cstdint>
class ISignatureProvider
{
public:
virtual void GetSignature(const uint8_t** pSignature, size_t* pSize) = 0;
};

View File

@ -0,0 +1,12 @@
#pragma once
#include "Zone/ZoneTypes.h"
#include "ZoneLoader.h"
class IZoneLoaderFactory
{
public:
virtual ~IZoneLoaderFactory() = default;
virtual ZoneLoader* CreateLoaderForHeader(ZoneHeader& header, std::string& fileName) = 0;
};

View File

@ -0,0 +1,10 @@
#pragma once
#include "Zone/ZoneTypes.h"
#include <string>
class IZoneScriptStringProvider
{
public:
virtual std::string& GetZoneScriptString(scr_string_t scrString) = 0;
};

View File

@ -0,0 +1,11 @@
#include "LoadingFileStream.h"
LoadingFileStream::LoadingFileStream(FileAPI::File* file)
{
m_file = file;
}
size_t LoadingFileStream::Load(void* buffer, const size_t length)
{
return m_file->Read(buffer, 1, length);
}

View File

@ -0,0 +1,13 @@
#pragma once
#include "ILoadingStream.h"
#include "Utils/FileAPI.h"
class LoadingFileStream : public ILoadingStream
{
FileAPI::File* m_file;
public:
explicit LoadingFileStream(FileAPI::File* file);
size_t Load(void* buffer, size_t length) override;
};

View File

@ -0,0 +1,73 @@
#include "ProcessorInflate.h"
#include "zlib.h"
#include <exception>
#include "zutil.h"
#include <cstdint>
class ProcessorInflate::ProcessorInflateImpl
{
z_stream m_stream{};
uint8_t m_in_buffer[0x800];
ProcessorInflate* m_base;
public:
ProcessorInflateImpl(ProcessorInflate* baseClass)
{
m_base = baseClass;
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 = inflateInit2(&m_stream, -DEF_WBITS);
if(ret != Z_OK)
{
throw std::exception("Initializing inflate failed");
}
}
~ProcessorInflateImpl()
{
inflateEnd(&m_stream);
}
size_t Load(void* buffer, size_t length)
{
m_stream.next_out = static_cast<Bytef*>(buffer);
m_stream.avail_out = length;
while(m_stream.avail_out > 0)
{
if(m_stream.avail_in == 0)
{
m_stream.avail_in = m_base->m_base_stream->Load(m_in_buffer, sizeof(m_in_buffer));
if(m_stream.avail_in == 0) // EOF
return length - m_stream.avail_out;
}
inflate(&m_stream, Z_FULL_FLUSH);
}
return m_stream.avail_out;
}
};
ProcessorInflate::ProcessorInflate()
{
m_impl = new ProcessorInflateImpl(this);
}
ProcessorInflate::~ProcessorInflate()
{
delete m_impl;
m_impl = nullptr;
}
size_t ProcessorInflate::Load(void* buffer, const size_t length)
{
return m_impl->Load(buffer, length);
}

View File

@ -0,0 +1,14 @@
#pragma once
#include "Loading/StreamProcessor.h"
class ProcessorInflate final : public StreamProcessor
{
class ProcessorInflateImpl;
ProcessorInflateImpl* m_impl;
public:
ProcessorInflate();
~ProcessorInflate() override;
size_t Load(void* buffer, size_t length) override;
};

View File

@ -0,0 +1,28 @@
#include "ProcessorStreamCipher.h"
ProcessorStreamCipher::ProcessorStreamCipher(IStreamCipher* cipher)
{
m_cipher = cipher;
}
ProcessorStreamCipher::~ProcessorStreamCipher()
{
delete m_cipher;
m_cipher = nullptr;
}
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);
if(readSize > 0)
m_cipher->Process(buffer, buffer, readSize);
return readSize;
}
return 0;
}

View File

@ -0,0 +1,14 @@
#pragma once
#include "Loading/StreamProcessor.h"
#include "Crypto.h"
class ProcessorStreamCipher final : public StreamProcessor
{
IStreamCipher* m_cipher;
public:
explicit ProcessorStreamCipher(IStreamCipher* cipher);
~ProcessorStreamCipher() override;
size_t Load(void* buffer, size_t length) override;
};

View File

@ -0,0 +1,310 @@
#include "ProcessorXChunks.h"
#include "Zone/ZoneTypes.h"
#include "Loading/Exception/InvalidChunkSizeException.h"
#include <vector>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <cassert>
class DBLoadStream
{
int m_index;
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<IXChunkProcessor*>& m_processors;
void Load()
{
std::lock_guard<std::mutex> lock(m_load_mutex);
bool firstProcessor = true;
for(auto processor : m_processors)
{
if(!firstProcessor)
{
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();
}
public:
DBLoadStream(const int streamIndex, const size_t chunkSize, std::vector<IXChunkProcessor*>& chunkProcessors) : m_processors(chunkProcessors)
{
m_index = streamIndex;
m_chunk_size = chunkSize;
m_input_buffer = new uint8_t[chunkSize];
m_output_buffer = new uint8_t[chunkSize];
m_input_size = 0;
m_output_size = 0;
m_is_loading = false;
}
~DBLoadStream()
{
delete[] m_input_buffer;
m_input_buffer = nullptr;
delete[] m_output_buffer;
m_output_buffer = nullptr;
}
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);
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<std::mutex> lock(m_load_mutex);
if(m_is_loading)
{
m_loading_finished.wait(lock);
}
*pBuffer = m_output_buffer;
*pSize = m_output_size;
}
};
class ProcessorXChunks::ProcessorXChunksImpl
{
ProcessorXChunks* m_base;
std::vector<DBLoadStream*> m_streams;
size_t m_chunk_size;
std::vector<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;
bool m_eof_reached;
unsigned int m_eof_stream;
void AdvanceStream(const unsigned int streamNum)
{
assert(streamNum >= 0 && streamNum < m_streams.size());
if(m_eof_reached)
return;
xchunk_size_t chunkSize;
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);
}
auto* stream = m_streams[streamNum];
const size_t loadedChunkSize = m_base->m_base_stream->Load(stream->GetInputBuffer(), chunkSize);
if(loadedChunkSize != chunkSize)
{
throw InvalidChunkSizeException(chunkSize);
}
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;
const unsigned int streamCount = m_streams.size();
for(unsigned int streamNum = 0; 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);
}
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.push_back(new DBLoadStream(streamIndex, xChunkSize, m_chunk_processors));
}
m_chunk_size = xChunkSize;
m_initialized_streams = false;
m_current_stream = 0;
m_current_chunk = nullptr;
m_current_chunk_size = 0;
m_current_chunk_offset = 0;
m_eof_reached = false;
m_eof_stream = 0;
}
~ProcessorXChunksImpl()
{
for(auto* stream : m_streams)
{
delete stream;
}
m_streams.clear();
for(auto* processor : m_chunk_processors)
{
delete processor;
}
m_chunk_processors.clear();
}
void AddChunkProcessor(IXChunkProcessor* streamProcessor)
{
assert(streamProcessor != nullptr);
m_chunk_processors.push_back(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)
{
memcpy_s(bufferPos, sizeToRead, &m_current_chunk[m_current_chunk_offset], bytesLeftInCurrentChunk);
loadedSize += bytesLeftInCurrentChunk;
NextStream();
}
else
{
memcpy_s(bufferPos, sizeToRead, &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;
}
};
ProcessorXChunks::ProcessorXChunks(const int numStreams, const size_t xChunkSize)
{
m_impl = new ProcessorXChunksImpl(this, numStreams, xChunkSize);
}
ProcessorXChunks::~ProcessorXChunks()
{
delete m_impl;
m_impl = nullptr;
}
void ProcessorXChunks::AddChunkProcessor(IXChunkProcessor* chunkProcessor) const
{
m_impl->AddChunkProcessor(chunkProcessor);
}
size_t ProcessorXChunks::Load(void* buffer, const size_t length)
{
return m_impl->Load(buffer, length);
}

View File

@ -0,0 +1,17 @@
#pragma once
#include "Loading/StreamProcessor.h"
#include "XChunks/IXChunkProcessor.h"
class ProcessorXChunks : public StreamProcessor
{
class ProcessorXChunksImpl;
ProcessorXChunksImpl* m_impl;
public:
ProcessorXChunks(int numStreams, size_t xChunkSize);
~ProcessorXChunks() override;
size_t Load(void* buffer, size_t length) override;
void AddChunkProcessor(IXChunkProcessor* chunkProcessor) const;
};

View File

@ -0,0 +1,36 @@
#include "ChunkProcessorInflate.h"
#include "zlib.h"
#include "zutil.h"
#include <exception>
#include "Loading/Exception/InvalidCompressionException.h"
size_t ChunkProcessorInflate::Process(int streamNumber, const uint8_t* input, const size_t inputLength, uint8_t* output, const size_t outputBufferSize)
{
z_stream stream{};
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
stream.opaque = Z_NULL;
int ret = inflateInit2(&stream, -DEF_WBITS);
if(ret != Z_OK)
{
throw std::exception("Initializing inflate failed.");
}
stream.avail_in = inputLength;
stream.next_in = input;
stream.avail_out = outputBufferSize;
stream.next_out = output;
ret = inflate(&stream, Z_FULL_FLUSH);
if(ret != Z_STREAM_END)
{
throw InvalidCompressionException();
}
const size_t outputSize = stream.total_out;
inflateEnd(&stream);
return outputSize;
}

View File

@ -0,0 +1,8 @@
#pragma once
#include "IXChunkProcessor.h"
class ChunkProcessorInflate : public IXChunkProcessor
{
public:
size_t Process(int streamNumber, const uint8_t* input, size_t inputLength, uint8_t* output, size_t outputBufferSize) override;
};

View File

@ -0,0 +1,156 @@
#include "ChunkProcessorSalsa20.h"
#include "Crypto.h"
#include <cassert>
class StreamContextSalsa20
{
public:
IStreamCipher* m_salsa20;
IHashFunction* m_sha1;
StreamContextSalsa20()
{
m_salsa20 = nullptr;
m_sha1 = nullptr;
}
~StreamContextSalsa20()
{
delete m_salsa20;
m_salsa20 = nullptr;
delete m_sha1;
m_sha1 = nullptr;
}
};
class ChunkProcessorSalsa20::ChunkProcessorSalsa20Impl
{
static const int BLOCK_HASHES_COUNT = 200;
static const int SHA1_HASH_SIZE = 20;
static const int SALSA20_IV_SIZE = 8;
int m_stream_count;
StreamContextSalsa20* m_stream_contexts;
// m_block_hashes[BLOCK_HASHES_COUNT][numStreams][HASH_SIZE]
uint8_t* m_block_hashes;
unsigned int* m_stream_block_indices;
uint8_t* GetHashBlock(const int streamNumber) const
{
const size_t blockIndexOffset = m_stream_block_indices[streamNumber] * m_stream_count * SHA1_HASH_SIZE;
const size_t streamOffset = streamNumber * SHA1_HASH_SIZE;
return &m_block_hashes[blockIndexOffset + streamOffset];
}
public:
ChunkProcessorSalsa20Impl(const int streamCount, std::string& zoneName, const uint8_t* salsa20Key, size_t keySize)
{
m_stream_count = streamCount;
m_stream_contexts = new StreamContextSalsa20[streamCount];
m_block_hashes = new uint8_t[BLOCK_HASHES_COUNT * streamCount * SHA1_HASH_SIZE];
m_stream_block_indices = new unsigned int[streamCount];
InitStreams(zoneName, salsa20Key, keySize);
}
~ChunkProcessorSalsa20Impl()
{
delete[] m_stream_contexts;
delete[] m_block_hashes;
m_block_hashes = nullptr;
delete[] m_stream_block_indices;
m_stream_block_indices = nullptr;
}
void InitStreams(std::string& zoneName, const uint8_t* salsa20Key, size_t keySize) const
{
const int zoneNameLength = zoneName.length();
const size_t blockHashBufferSize = BLOCK_HASHES_COUNT * m_stream_count * SHA1_HASH_SIZE;
assert(blockHashBufferSize % 4 == 0);
size_t zoneNameOffset = 0;
for(size_t i = 0; i < blockHashBufferSize; i += 4)
{
*reinterpret_cast<uint32_t*>(&m_block_hashes[i]) = 0x1010101 * zoneName[zoneNameOffset++];
zoneNameOffset %= zoneNameLength;
}
for(int stream = 0; stream < m_stream_count; stream++)
{
m_stream_block_indices[stream] = 0;
m_stream_contexts[stream].m_salsa20 = Crypto::CreateSalsa20(salsa20Key, keySize);
m_stream_contexts[stream].m_sha1 = Crypto::CreateSHA1();
}
}
size_t Process(const int streamNumber, const uint8_t* input, const size_t inputLength, uint8_t* output, const size_t outputBufferSize) const
{
assert(streamNumber >= 0 && streamNumber < m_stream_count);
assert(input != nullptr);
assert(output != nullptr);
assert(inputLength <= outputBufferSize);
StreamContextSalsa20& streamContext = m_stream_contexts[streamNumber];
// Initialize Salsa20 with an IV of the first 8 bytes of the current hash block
streamContext.m_salsa20->SetIV(GetHashBlock(streamNumber), SALSA20_IV_SIZE);
streamContext.m_salsa20->Process(input, output, inputLength);
// Hash decrypted XChunk
uint8_t blockSha1Hash[SHA1_HASH_SIZE];
streamContext.m_sha1->Init();
streamContext.m_sha1->Process(output, inputLength);
streamContext.m_sha1->Finish(&blockSha1Hash);
// Advance index to next hash block
m_stream_block_indices[streamNumber] = (m_stream_block_indices[streamNumber] + 1) % BLOCK_HASHES_COUNT;
uint8_t* nextHashBlock = GetHashBlock(streamNumber);
// XOR the upcoming hash block with the hash of the XChunk utilizing the previous hash block
for(unsigned int hashOffset = 0; hashOffset < sizeof(blockSha1Hash); hashOffset++)
{
nextHashBlock[hashOffset] ^= blockSha1Hash[hashOffset];
}
return inputLength;
}
void GetSignatureData(const uint8_t** pSignatureData, size_t* pSize) const
{
assert(pSignatureData != nullptr);
assert(pSize != nullptr);
*pSignatureData = m_block_hashes;
*pSize = BLOCK_HASHES_COUNT * m_stream_count * SHA1_HASH_SIZE;
}
};
ChunkProcessorSalsa20::ChunkProcessorSalsa20(const int streamCount, std::string& zoneName, const uint8_t* salsa20Key, size_t keySize)
{
m_impl = new ChunkProcessorSalsa20Impl(streamCount, zoneName, salsa20Key, keySize);
}
ChunkProcessorSalsa20::~ChunkProcessorSalsa20()
{
delete m_impl;
m_impl = nullptr;
}
size_t ChunkProcessorSalsa20::Process(const int streamNumber, const uint8_t* input, const size_t inputLength, uint8_t* output, const size_t outputBufferSize)
{
return m_impl->Process(streamNumber, input, inputLength, output, outputBufferSize);
}
void ChunkProcessorSalsa20::GetSignatureData(const uint8_t** pSignatureData, size_t* pSize)
{
m_impl->GetSignatureData(pSignatureData, pSize);
}

View File

@ -0,0 +1,17 @@
#pragma once
#include "IXChunkProcessor.h"
#include "Loading/ISignatureDataProvider.h"
#include <string>
class ChunkProcessorSalsa20 : public IXChunkProcessor, public ISignatureDataProvider
{
class ChunkProcessorSalsa20Impl;
ChunkProcessorSalsa20Impl* m_impl;
public:
ChunkProcessorSalsa20(int streamCount, std::string& zoneName, const uint8_t* salsa20Key, size_t keySize);
~ChunkProcessorSalsa20() override;
size_t Process(int streamNumber, const uint8_t* input, size_t inputLength, uint8_t* output, size_t outputBufferSize) override;
void GetSignatureData(const uint8_t** pSignatureData, size_t* pSize) override;
};

View File

@ -0,0 +1,9 @@
#pragma once
#include <cstdint>
class IXChunkProcessor
{
public:
virtual ~IXChunkProcessor() = default;
virtual size_t Process(int streamNumber, const uint8_t* input, size_t inputLength, uint8_t* output, size_t outputBufferSize) = 0;
};

View File

@ -0,0 +1,22 @@
#include "StepAddProcessor.h"
#include <cassert>
StepAddProcessor::StepAddProcessor(StreamProcessor* streamProcessor)
{
m_stream_processor = streamProcessor;
}
StepAddProcessor::~StepAddProcessor()
{
delete m_stream_processor;
m_stream_processor = nullptr;
}
void StepAddProcessor::PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream)
{
assert(zoneLoader != nullptr);
assert(m_stream_processor != nullptr);
zoneLoader->AddStreamProcessor(m_stream_processor);
m_stream_processor = nullptr;
}

View File

@ -0,0 +1,14 @@
#pragma once
#include "Loading/ILoadingStep.h"
class StepAddProcessor final : public ILoadingStep
{
StreamProcessor* m_stream_processor;
public:
explicit StepAddProcessor(StreamProcessor* streamProcessor);
~StepAddProcessor() override;
void PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream) override;
};

View File

@ -0,0 +1,30 @@
#include "StepAllocXBlocks.h"
#include "Loading/Exception/InvalidXBlockSizeException.h"
const uint64_t StepAllocXBlocks::MAX_XBLOCK_SIZE = 0x3C000000;
void StepAllocXBlocks::PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream)
{
const unsigned int blockCount = zoneLoader->m_blocks.size();
auto* blockSizes = new xblock_size_t[blockCount];
stream->Load(blockSizes, sizeof(xblock_size_t) * blockCount);
uint64_t totalMemory = 0;
for(unsigned int block = 0; block < blockCount; block++)
{
totalMemory += blockSizes[block];
}
if(totalMemory > MAX_XBLOCK_SIZE)
{
throw InvalidXBlockSizeException(totalMemory, MAX_XBLOCK_SIZE);
}
for(unsigned int block = 0; block < blockCount; block++)
{
zoneLoader->m_blocks[block]->Alloc(blockSizes[block]);
}
delete[] blockSizes;
}

View File

@ -0,0 +1,11 @@
#pragma once
#include "Loading/ILoadingStep.h"
class StepAllocXBlocks final : public ILoadingStep
{
static const uint64_t MAX_XBLOCK_SIZE;
public:
void PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream) override;
};

View File

@ -0,0 +1,34 @@
#include "StepLoadSignature.h"
#include "Loading/Exception/UnexpectedEndOfFileException.h"
#include <cassert>
StepLoadSignature::StepLoadSignature(const size_t signatureSize)
{
m_signature_size = signatureSize;
m_signature = new uint8_t[signatureSize];
}
StepLoadSignature::~StepLoadSignature()
{
delete[] m_signature;
m_signature = nullptr;
}
void StepLoadSignature::PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream)
{
assert(stream != nullptr);
if(stream->Load(m_signature, m_signature_size) != m_signature_size)
throw UnexpectedEndOfFileException();
}
void StepLoadSignature::GetSignature(const uint8_t** pSignature, size_t* pSize)
{
assert(pSignature != nullptr);
assert(pSize != nullptr);
assert(m_signature != nullptr);
*pSignature = m_signature;
*pSize = m_signature_size;
}

View File

@ -0,0 +1,17 @@
#pragma once
#include "Loading/ILoadingStep.h"
#include "Loading/ISignatureProvider.h"
class StepLoadSignature final : public ILoadingStep, public ISignatureProvider
{
uint8_t* m_signature;
size_t m_signature_size;
public:
explicit StepLoadSignature(size_t signatureSize);
~StepLoadSignature() override;
void PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream) override;
void GetSignature(const uint8_t** pSignature, size_t* pSize) override;
};

View File

@ -0,0 +1,26 @@
#include "StepLoadZoneContent.h"
#include "Zone/Stream/Impl/XBlockInputStream.h"
#include <cassert>
StepLoadZoneContent::StepLoadZoneContent(IContentLoadingEntryPoint* entryPoint, Zone* zone, const int offsetBlockBitCount, const block_t insertBlock)
{
m_content_loader = entryPoint;
m_zone = zone;
m_offset_block_bit_count = offsetBlockBitCount;
m_insert_block = insertBlock;
}
StepLoadZoneContent::~StepLoadZoneContent()
{
delete m_content_loader;
m_content_loader = nullptr;
}
void StepLoadZoneContent::PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream)
{
auto* inputStream = new XBlockInputStream(zoneLoader->m_blocks, stream, m_offset_block_bit_count, m_insert_block);
m_content_loader->Load(m_zone, inputStream);
delete inputStream;
}

View File

@ -0,0 +1,18 @@
#pragma once
#include "Loading/ILoadingStep.h"
#include "Loading/IContentLoadingEntryPoint.h"
class StepLoadZoneContent final : public ILoadingStep
{
IContentLoadingEntryPoint* m_content_loader;
Zone* m_zone;
int m_offset_block_bit_count;
block_t m_insert_block;
public:
StepLoadZoneContent(IContentLoadingEntryPoint* entryPoint, Zone* zone, int offsetBlockBitCount, block_t insertBlock);
~StepLoadZoneContent();
void PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream) override;
};

View File

@ -0,0 +1,30 @@
#include "StepSkipBytes.h"
StepSkipBytes::StepSkipBytes(const unsigned int skipCount)
{
m_skip_count = skipCount;
}
void StepSkipBytes::PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream)
{
uint8_t tempBuffer[128];
unsigned int skippedBytes = 0;
while(skippedBytes < m_skip_count)
{
unsigned int toSkip;
if(m_skip_count - skippedBytes < sizeof(tempBuffer))
{
toSkip = m_skip_count - skippedBytes;
}
else
{
toSkip = sizeof(tempBuffer);
}
stream->Load(tempBuffer, toSkip);
skippedBytes += toSkip;
}
}

View File

@ -0,0 +1,13 @@
#pragma once
#include "Loading/ILoadingStep.h"
class StepSkipBytes final : public ILoadingStep
{
unsigned int m_skip_count;
public:
explicit StepSkipBytes(unsigned int skipCount);
void PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream) override;
};

View File

@ -0,0 +1,42 @@
#include "StepVerifyFileName.h"
#include "Loading/Exception/InvalidFileNameException.h"
StepVerifyFileName::StepVerifyFileName(std::string fileName, const size_t fileNameBufferSize)
{
m_file_name = std::move(fileName);
m_file_name_buffer_size = fileNameBufferSize;
if(m_file_name.length() > m_file_name_buffer_size)
m_file_name.erase(m_file_name_buffer_size);
}
void StepVerifyFileName::PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream)
{
std::string originalFileName;
unsigned bufferOffset = 0;
char c;
for(; bufferOffset < m_file_name_buffer_size; bufferOffset++)
{
stream->Load(&c, sizeof(char));
if(c == '\00')
{
bufferOffset++;
break;
}
originalFileName += c;
}
// Skip the rest of the buffer which should be null bytes
while(bufferOffset < m_file_name_buffer_size)
{
stream->Load(&c, sizeof(char));
bufferOffset++;
}
if(originalFileName != m_file_name)
throw InvalidFileNameException(m_file_name, originalFileName);
}

View File

@ -0,0 +1,14 @@
#pragma once
#include "Loading/ILoadingStep.h"
class StepVerifyFileName final : public ILoadingStep
{
std::string m_file_name;
size_t m_file_name_buffer_size;
public:
explicit StepVerifyFileName(std::string fileName, size_t fileNameBufferSize);
void PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream) override;
};

View File

@ -0,0 +1,21 @@
#include "StepVerifyMagic.h"
#include "Loading/Exception/InvalidMagicException.h"
StepVerifyMagic::StepVerifyMagic(const char* magic)
{
m_magic = magic;
}
void StepVerifyMagic::PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream)
{
const size_t magicLength = strlen(m_magic);
char currentCharacter;
for(unsigned i = 0; i < magicLength; i++)
{
stream->Load(&currentCharacter, sizeof(char));
if(currentCharacter != m_magic[i])
throw InvalidMagicException(m_magic);
}
}

View File

@ -0,0 +1,13 @@
#pragma once
#include "Loading/ILoadingStep.h"
class StepVerifyMagic final : public ILoadingStep
{
const char* m_magic;
public:
explicit StepVerifyMagic(const char* magic);
void PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream) override;
};

View File

@ -0,0 +1,36 @@
#include "StepVerifySignature.h"
#include "Loading/Exception/InvalidSignatureException.h"
#include <cassert>
StepVerifySignature::StepVerifySignature(IPublicKeyAlgorithm* signatureAlgorithm, ISignatureProvider* signatureProvider, ISignatureDataProvider* signatureDataProvider)
{
m_algorithm = signatureAlgorithm;
m_signature_provider = signatureProvider;
m_signature_data_provider = signatureDataProvider;
}
StepVerifySignature::~StepVerifySignature()
{
delete m_algorithm;
m_algorithm = nullptr;
}
void StepVerifySignature::PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream)
{
assert(m_algorithm != nullptr);
assert(m_signature_provider != nullptr);
assert(m_signature_data_provider != nullptr);
const uint8_t* signature;
size_t signatureSize;
m_signature_provider->GetSignature(&signature, &signatureSize);
const uint8_t* signatureData;
size_t signatureDataSize;
m_signature_data_provider->GetSignatureData(&signatureData, &signatureDataSize);
if(!m_algorithm->Verify(signatureData, signatureDataSize, signature, signatureSize))
{
throw InvalidSignatureException();
}
}

View File

@ -0,0 +1,19 @@
#pragma once
#include "Loading/ILoadingStep.h"
#include "Crypto.h"
#include "Loading/ISignatureProvider.h"
#include "Loading/ISignatureDataProvider.h"
class StepVerifySignature final : public ILoadingStep
{
IPublicKeyAlgorithm* m_algorithm;
ISignatureProvider* m_signature_provider;
ISignatureDataProvider* m_signature_data_provider;
public:
StepVerifySignature(IPublicKeyAlgorithm* signatureAlgorithm, ISignatureProvider* signatureProvider, ISignatureDataProvider* signatureDataProvider);
~StepVerifySignature();
void PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream) override;
};

View File

@ -0,0 +1,11 @@
#include "StreamProcessor.h"
StreamProcessor::StreamProcessor()
{
m_base_stream = nullptr;
}
void StreamProcessor::SetBaseStream(ILoadingStream* baseStream)
{
m_base_stream = baseStream;
}

View File

@ -0,0 +1,13 @@
#pragma once
#include "ILoadingStream.h"
class StreamProcessor : public ILoadingStream
{
protected:
ILoadingStream* m_base_stream;
public:
StreamProcessor();
void SetBaseStream(ILoadingStream* baseStream);
};

View File

@ -0,0 +1,94 @@
#include "ZoneLoader.h"
#include "Exception/LoadingException.h"
#include "LoadingFileStream.h"
#include <algorithm>
ZoneLoader::ZoneLoader(Zone* zone)
{
m_zone = zone;
m_processor_chain_dirty = false;
}
ZoneLoader::~ZoneLoader()
{
for(auto step : m_steps)
{
delete step;
}
m_steps.clear();
for(auto processor : m_processors)
{
delete processor;
}
m_processors.clear();
}
ILoadingStream* ZoneLoader::BuildLoadingChain(ILoadingStream* rootStream)
{
ILoadingStream* currentStream = rootStream;
for(auto processor : m_processors)
{
processor->SetBaseStream(currentStream);
currentStream = processor;
}
m_processor_chain_dirty = false;
return currentStream;
}
void ZoneLoader::AddXBlock(XBlock* block)
{
m_blocks.push_back(block);
std::sort(m_blocks.begin(), m_blocks.end(), [](XBlock* b1, XBlock* b2) -> bool
{
return b1->m_index < b2->m_index;
});
}
void ZoneLoader::AddLoadingStep(ILoadingStep* step)
{
m_steps.push_back(step);
}
void ZoneLoader::AddStreamProcessor(StreamProcessor* streamProcessor)
{
m_processors.push_back(streamProcessor);
m_processor_chain_dirty = true;
}
Zone* ZoneLoader::LoadZone(FileAPI::File* file)
{
LoadingFileStream fileStream(file);
ILoadingStream* endStream = BuildLoadingChain(&fileStream);
try
{
for(auto step : m_steps)
{
step->PerformStep(this, endStream);
if(m_processor_chain_dirty)
{
endStream = BuildLoadingChain(&fileStream);
}
}
}
catch (LoadingException& e)
{
const std::string detailedMessage = e.DetailedMessage();
printf("Loading fastfile failed: %s\n", detailedMessage.c_str());
delete m_zone;
return nullptr;
}
m_zone->m_game->AddZone(m_zone);
return m_zone;
}

View File

@ -0,0 +1,35 @@
#pragma once
#include "ILoadingStep.h"
#include "Zone/Zone.h"
#include "Zone/XBlock.h"
#include "Utils/FileAPI.h"
#include "StreamProcessor.h"
#include <vector>
class ILoadingStep;
class ZoneLoader
{
std::vector<ILoadingStep*> m_steps;
std::vector<StreamProcessor*> m_processors;
bool m_processor_chain_dirty;
Zone* m_zone;
ILoadingStream* BuildLoadingChain(ILoadingStream* rootStream);
public:
std::vector<XBlock*> m_blocks;
explicit ZoneLoader(Zone* zone);
~ZoneLoader();
void AddXBlock(XBlock* block);
void AddLoadingStep(ILoadingStep* step);
void AddStreamProcessor(StreamProcessor* streamProcessor);
Zone* LoadZone(FileAPI::File* file);
};

View File

@ -0,0 +1,58 @@
#pragma once
#include "Zone/Stream/IZoneStream.h"
#include <cstdint>
class IZoneInputStream : public IZoneStream
{
public:
virtual void* Alloc(int align) = 0;
template<typename T>
T* Alloc(const int align)
{
return static_cast<T*>(Alloc(align));
}
template<typename T>
T* Alloc()
{
return static_cast<T*>(Alloc(alignof(T)));
}
virtual void LoadData(size_t size) = 0;
virtual void LoadNullTerminated() = 0;
template<typename T>
void Load()
{
LoadData(sizeof(T));
}
template<typename T>
void Load(const uint32_t count)
{
LoadData(count * sizeof(T));
}
virtual void** InsertPointer() = 0;
template<typename T>
T** InsertPointer()
{
return reinterpret_cast<T**>(InsertPointer());
}
virtual void* ConvertOffsetToPointer(const void* offset) = 0;
template<typename T>
T* ConvertOffsetToPointer(T* offset)
{
return static_cast<T*>(ConvertOffsetToPointer(static_cast<const void*>(offset)));
}
virtual void* ConvertOffsetToAlias(const void* offset) = 0;
template<typename T>
T* ConvertOffsetToAlias(T* offset)
{
return static_cast<T*>(ConvertOffsetToAlias(static_cast<const void*>(offset)));
}
};

View File

@ -0,0 +1,197 @@
#include "XBlockInputStream.h"
#include "Loading/Exception/BlockOverflowException.h"
#include "Loading/Exception/InvalidOffsetBlockException.h"
#include "Loading/Exception/InvalidOffsetBlockOffsetException.h"
#include <cassert>
XBlockInputStream::XBlockInputStream(std::vector<XBlock*>& blocks, ILoadingStream* stream, const int blockBitCount, const block_t insertBlock) : m_blocks(blocks)
{
m_stream = stream;
const unsigned int blockCount = blocks.size();
m_block_offsets = new size_t[blockCount]{0};
m_block_in_stack = new unsigned int[blockCount]{0};
m_block_bit_count = blockBitCount;
assert(insertBlock >= 0 && insertBlock < static_cast<block_t>(blocks.size()));
m_insert_block = blocks[insertBlock];
}
XBlockInputStream::~XBlockInputStream()
{
delete[] m_block_offsets;
m_block_offsets = nullptr;
delete[] m_block_in_stack;
m_block_in_stack = nullptr;
assert(m_block_stack.empty());
}
void XBlockInputStream::Align(const int align)
{
assert(!m_block_stack.empty());
if(align > 0)
{
const block_t blockIndex = m_block_stack.top()->m_index;
m_block_offsets[blockIndex] = (m_block_offsets[blockIndex] + align - 1) / align * align;
}
}
void XBlockInputStream::PushBlock(const block_t block)
{
assert(block >= 0 && block < static_cast<block_t>(m_blocks.size()));
XBlock* newBlock = m_blocks[block];
assert(newBlock->m_index == block);
m_block_stack.push(newBlock);
m_block_in_stack[newBlock->m_index]++;
}
block_t XBlockInputStream::PopBlock()
{
assert(!m_block_stack.empty());
if(m_block_stack.empty())
return -1;
const XBlock* poppedBlock = m_block_stack.top();
m_block_stack.pop();
m_block_in_stack[poppedBlock->m_index]--;
// If the temp block is not used anymore right now, reset it to the buffer start since as the name suggests, the data inside is temporary.
if(poppedBlock->m_type == XBlock::BLOCK_TYPE_TEMP && m_block_in_stack[poppedBlock->m_index] == 0)
{
m_block_offsets[poppedBlock->m_index] = 0;
}
return poppedBlock->m_index;
}
void* XBlockInputStream::Alloc(const int align)
{
assert(!m_block_stack.empty());
if(m_block_stack.empty())
return nullptr;
XBlock* block = m_block_stack.top();
Align(align);
if(m_block_offsets[block->m_index] >= block->m_buffer_size)
{
throw BlockOverflowException(block);
}
return &block->m_buffer[m_block_offsets[block->m_index]];
}
void XBlockInputStream::LoadData(const size_t size)
{
assert(!m_block_stack.empty());
if(m_block_stack.empty())
return;
XBlock* block = m_block_stack.top();
if(m_block_offsets[block->m_index] + size >= block->m_buffer_size)
{
throw BlockOverflowException(block);
}
m_stream->Load(&block->m_buffer[m_block_offsets[block->m_index]], size);
m_block_offsets[block->m_index] += size;
}
void XBlockInputStream::LoadNullTerminated()
{
assert(!m_block_stack.empty());
if(m_block_stack.empty())
return;
XBlock* block = m_block_stack.top();
uint8_t byte;
size_t offset = m_block_offsets[block->m_index];
do
{
m_stream->Load(&byte, 1);
block->m_buffer[offset++] = byte;
if(offset >= block->m_buffer_size)
{
throw BlockOverflowException(block);
}
} while(byte != 0);
m_block_offsets[block->m_index] = offset;
}
void** XBlockInputStream::InsertPointer()
{
m_block_stack.push(m_insert_block);
Align(sizeof(void*));
if(m_block_offsets[m_insert_block->m_index] + sizeof(void*) >= m_insert_block->m_buffer_size)
{
throw BlockOverflowException(m_insert_block);
}
void** ptr = reinterpret_cast<void**>(&m_insert_block->m_buffer[m_block_offsets[m_insert_block->m_index]]);
m_block_stack.pop();
return ptr;
}
void* XBlockInputStream::ConvertOffsetToPointer(const void* offset)
{
const block_t blockNum = reinterpret_cast<uintptr_t>(offset) >> (sizeof(offset) * 8 - m_block_bit_count);
const size_t blockOffset = reinterpret_cast<uintptr_t>(offset) & (UINTPTR_MAX >> m_block_bit_count);
if(blockNum < 0 || blockNum >= static_cast<block_t>(m_blocks.size()))
{
throw InvalidOffsetBlockException(blockNum);
}
XBlock* block = m_blocks[blockNum];
if(block->m_buffer_size <= blockOffset)
{
throw InvalidOffsetBlockOffsetException(block, blockOffset);
}
return &block->m_buffer[blockOffset];
}
void* XBlockInputStream::ConvertOffsetToAlias(const void* offset)
{
const block_t blockNum = reinterpret_cast<uintptr_t>(offset) >> (sizeof(offset) * 8 - m_block_bit_count);
const size_t blockOffset = reinterpret_cast<uintptr_t>(offset) & (UINTPTR_MAX >> m_block_bit_count);
if(blockNum < 0 || blockNum >= static_cast<block_t>(m_blocks.size()))
{
throw InvalidOffsetBlockException(blockNum);
}
XBlock* block = m_blocks[blockNum];
if(block->m_buffer_size <= blockOffset + sizeof(void*))
{
throw InvalidOffsetBlockOffsetException(block, blockOffset);
}
return *reinterpret_cast<void**>(&block->m_buffer[blockOffset]);
}

View File

@ -0,0 +1,40 @@
#pragma once
#include "Zone/Stream/IZoneInputStream.h"
#include "Zone/XBlock.h"
#include "Loading/ILoadingStream.h"
#include <vector>
#include <stack>
class XBlockInputStream final : public IZoneInputStream
{
std::vector<XBlock*>& m_blocks;
size_t* m_block_offsets;
unsigned int* m_block_in_stack;
std::stack<XBlock*> m_block_stack;
ILoadingStream* m_stream;
int m_block_bit_count;
XBlock* m_insert_block;
void Align(int align);
public:
XBlockInputStream(std::vector<XBlock*>& blocks, ILoadingStream* stream, int blockBitCount, block_t insertBlock);
~XBlockInputStream() override;
void PushBlock(block_t block) override;
block_t PopBlock() override;
void* Alloc(int align) override;
void LoadData(size_t size) override;
void LoadNullTerminated() override;
void** InsertPointer() override;
void* ConvertOffsetToPointer(const void* offset) override;
void* ConvertOffsetToAlias(const void* offset) override;
};

View File

@ -0,0 +1,6 @@
#include "ZoneLoading.h"
bool ZoneLoading::LoadZone(std::string& path)
{
return false;
}

View File

@ -0,0 +1,8 @@
#pragma once
#include <string>
class ZoneLoading
{
public:
static bool LoadZone(std::string& path);
};

View File

@ -0,0 +1,269 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Game\T6\XAssets\rawfile\rawfile_load_db.h" />
<ClInclude Include="Loading\AssetLoader.h" />
<ClInclude Include="Loading\ContentLoader.h" />
<ClInclude Include="Loading\Exception\BlockOverflowException.h" />
<ClInclude Include="Loading\Exception\InvalidChunkSizeException.h" />
<ClInclude Include="Loading\Exception\InvalidCompressionException.h" />
<ClInclude Include="Loading\Exception\InvalidFileNameException.h" />
<ClInclude Include="Loading\Exception\InvalidMagicException.h" />
<ClInclude Include="Loading\Exception\InvalidOffsetBlockException.h" />
<ClInclude Include="Loading\Exception\InvalidOffsetBlockOffsetException.h" />
<ClInclude Include="Loading\Exception\InvalidSignatureException.h" />
<ClInclude Include="Loading\Exception\InvalidVersionException.h" />
<ClInclude Include="Loading\Exception\InvalidXBlockSizeException.h" />
<ClInclude Include="Loading\Exception\LoadingException.h" />
<ClInclude Include="Loading\Exception\UnexpectedEndOfFileException.h" />
<ClInclude Include="Loading\Exception\UnsupportedAssetTypeException.h" />
<ClInclude Include="Loading\IContentLoadingEntryPoint.h" />
<ClInclude Include="Loading\ILoadingStep.h" />
<ClInclude Include="Loading\ILoadingStream.h" />
<ClInclude Include="Loading\ISignatureDataProvider.h" />
<ClInclude Include="Loading\ISignatureProvider.h" />
<ClInclude Include="Loading\IZoneLoaderFactory.h" />
<ClInclude Include="Loading\IZoneScriptStringProvider.h" />
<ClInclude Include="Loading\LoadingFileStream.h" />
<ClInclude Include="Loading\Processor\ProcessorInflate.h" />
<ClInclude Include="Loading\Processor\ProcessorStreamCipher.h" />
<ClInclude Include="Loading\Processor\ProcessorXChunks.h" />
<ClInclude Include="Loading\Processor\XChunks\ChunkProcessorInflate.h" />
<ClInclude Include="Loading\Processor\XChunks\ChunkProcessorSalsa20.h" />
<ClInclude Include="Loading\Processor\XChunks\IXChunkProcessor.h" />
<ClInclude Include="Loading\Steps\StepAddProcessor.h" />
<ClInclude Include="Loading\Steps\StepAllocXBlocks.h" />
<ClInclude Include="Loading\Steps\StepLoadSignature.h" />
<ClInclude Include="Loading\Steps\StepLoadZoneContent.h" />
<ClInclude Include="Loading\Steps\StepSkipBytes.h" />
<ClInclude Include="Loading\Steps\StepVerifyFileName.h" />
<ClInclude Include="Loading\Steps\StepVerifyMagic.h" />
<ClInclude Include="Loading\Steps\StepVerifySignature.h" />
<ClInclude Include="Loading\StreamProcessor.h" />
<ClInclude Include="Game\T6\ContentLoaderT6.h" />
<ClInclude Include="Game\T6\ZoneLoaderFactoryT6.h" />
<ClInclude Include="Loading\ZoneLoader.h" />
<ClInclude Include="ZoneLoading.h" />
<ClInclude Include="Zone\Stream\Impl\XBlockInputStream.h" />
<ClInclude Include="Zone\Stream\IZoneInputStream.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Game\T6\XAssets\rawfile\rawfile_load_db.cpp" />
<ClCompile Include="Loading\AssetLoader.cpp" />
<ClCompile Include="Loading\ContentLoader.cpp" />
<ClCompile Include="Loading\Exception\BlockOverflowException.cpp" />
<ClCompile Include="Loading\Exception\InvalidChunkSizeException.cpp" />
<ClCompile Include="Loading\Exception\InvalidCompressionException.cpp" />
<ClCompile Include="Loading\Exception\InvalidFileNameException.cpp" />
<ClCompile Include="Loading\Exception\InvalidMagicException.cpp" />
<ClCompile Include="Loading\Exception\InvalidOffsetBlockException.cpp" />
<ClCompile Include="Loading\Exception\InvalidOffsetBlockOffsetException.cpp" />
<ClCompile Include="Loading\Exception\InvalidSignatureException.cpp" />
<ClCompile Include="Loading\Exception\InvalidVersionException.cpp" />
<ClCompile Include="Loading\Exception\InvalidXBlockSizeException.cpp" />
<ClCompile Include="Loading\Exception\UnexpectedEndOfFileException.cpp" />
<ClCompile Include="Loading\Exception\UnsupportedAssetTypeException.cpp" />
<ClCompile Include="Loading\LoadingFileStream.cpp" />
<ClCompile Include="Loading\Processor\ProcessorInflate.cpp" />
<ClCompile Include="Loading\Processor\ProcessorStreamCipher.cpp" />
<ClCompile Include="Loading\Processor\ProcessorXChunks.cpp" />
<ClCompile Include="Loading\Processor\XChunks\ChunkProcessorInflate.cpp" />
<ClCompile Include="Loading\Processor\XChunks\ChunkProcessorSalsa20.cpp" />
<ClCompile Include="Loading\Steps\StepAddProcessor.cpp" />
<ClCompile Include="Loading\Steps\StepAllocXBlocks.cpp" />
<ClCompile Include="Loading\Steps\StepLoadSignature.cpp" />
<ClCompile Include="Loading\Steps\StepLoadZoneContent.cpp" />
<ClCompile Include="Loading\Steps\StepSkipBytes.cpp" />
<ClCompile Include="Loading\Steps\StepVerifyFileName.cpp" />
<ClCompile Include="Loading\Steps\StepVerifyMagic.cpp" />
<ClCompile Include="Loading\Steps\StepVerifySignature.cpp" />
<ClCompile Include="Loading\StreamProcessor.cpp" />
<ClCompile Include="Game\T6\ContentLoaderT6.cpp" />
<ClCompile Include="Game\T6\ZoneLoaderFactoryT6.cpp" />
<ClCompile Include="Loading\ZoneLoader.cpp" />
<ClCompile Include="ZoneLoading.cpp" />
<ClCompile Include="Zone\Stream\Impl\XBlockInputStream.cpp" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{C3308B0A-D7C7-4560-B5F7-3654DD4B668D}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>ZoneLoading</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
<ProjectName>ZoneLoading</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(SolutionDir)obj\$(ProjectName)\$(Configuration)_$(Platform)\</IntDir>
<OutDir>$(SolutionDir)lib\$(Configuration)_$(Platform)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(SolutionDir)obj\$(ProjectName)\$(Configuration)_$(Platform)\</IntDir>
<OutDir>$(SolutionDir)lib\$(Configuration)_$(Platform)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(SolutionDir)obj\$(ProjectName)\$(Configuration)_$(Platform)\</IntDir>
<OutDir>$(SolutionDir)lib\$(Configuration)_$(Platform)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(SolutionDir)obj\$(ProjectName)\$(Configuration)_$(Platform)\</IntDir>
<OutDir>$(SolutionDir)lib\$(Configuration)_$(Platform)\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir);$(SolutionDir)src\Crypto\;$(SolutionDir)src\Utils\;$(SolutionDir)src\ZoneCommon\;$(SolutionDir)thirdparty\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<TreatSpecificWarningsAsErrors>4715;%(TreatSpecificWarningsAsErrors)</TreatSpecificWarningsAsErrors>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<AdditionalDependencies>Crypto.lib;Utils.lib;ZoneCommon.lib;zlib.lib</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)lib\$(Configuration)_$(Platform)\</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4221</AdditionalOptions>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir);$(SolutionDir)src\Crypto\;$(SolutionDir)src\Utils\;$(SolutionDir)src\ZoneCommon\;$(SolutionDir)thirdparty\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<TreatSpecificWarningsAsErrors>4715;%(TreatSpecificWarningsAsErrors)</TreatSpecificWarningsAsErrors>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<AdditionalDependencies>Crypto.lib;Utils.lib;ZoneCommon.lib;zlib.lib</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)lib\$(Configuration)_$(Platform)\</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4221</AdditionalOptions>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir);$(SolutionDir)src\Crypto\;$(SolutionDir)src\Utils\;$(SolutionDir)src\ZoneCommon\;$(SolutionDir)thirdparty\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<TreatSpecificWarningsAsErrors>4715;%(TreatSpecificWarningsAsErrors)</TreatSpecificWarningsAsErrors>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<AdditionalDependencies>Crypto.lib;Utils.lib;ZoneCommon.lib;zlib.lib</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)lib\$(Configuration)_$(Platform)\</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4221</AdditionalOptions>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir);$(SolutionDir)src\Crypto\;$(SolutionDir)src\Utils\;$(SolutionDir)src\ZoneCommon\;$(SolutionDir)thirdparty\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<TreatSpecificWarningsAsErrors>4715;%(TreatSpecificWarningsAsErrors)</TreatSpecificWarningsAsErrors>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<AdditionalDependencies>Crypto.lib;Utils.lib;ZoneCommon.lib;zlib.lib</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)lib\$(Configuration)_$(Platform)\</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4221</AdditionalOptions>
</Lib>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>