mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-11-18 03:02:07 +00:00
chore: add possibility to provide loading progress callback when loading zones
This commit is contained in:
@@ -2,10 +2,11 @@
|
|||||||
|
|
||||||
#include "GameLanguage.h"
|
#include "GameLanguage.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
enum class GameId
|
enum class GameId : std::uint8_t
|
||||||
{
|
{
|
||||||
IW3,
|
IW3,
|
||||||
IW4,
|
IW4,
|
||||||
@@ -18,7 +19,7 @@ enum class GameId
|
|||||||
|
|
||||||
// The full uppercase names are macros in the standard lib
|
// The full uppercase names are macros in the standard lib
|
||||||
// So unfortunately not usable as values in the enum
|
// So unfortunately not usable as values in the enum
|
||||||
enum class GameEndianness
|
enum class GameEndianness : std::uint8_t
|
||||||
{
|
{
|
||||||
/* Little endian */
|
/* Little endian */
|
||||||
LE,
|
LE,
|
||||||
@@ -26,12 +27,19 @@ enum class GameEndianness
|
|||||||
BE
|
BE
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class GameWordSize
|
enum class GameWordSize : std::uint8_t
|
||||||
{
|
{
|
||||||
ARCH_32,
|
ARCH_32,
|
||||||
ARCH_64
|
ARCH_64
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class GamePlatform : std::uint8_t
|
||||||
|
{
|
||||||
|
PC,
|
||||||
|
XBOX,
|
||||||
|
PS3
|
||||||
|
};
|
||||||
|
|
||||||
static constexpr const char* GameId_Names[]{
|
static constexpr const char* GameId_Names[]{
|
||||||
"IW3",
|
"IW3",
|
||||||
"IW4",
|
"IW4",
|
||||||
|
|||||||
9
src/Common/Utils/ProgressCallback.h
Normal file
9
src/Common/Utils/ProgressCallback.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
class ProgressCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void OnProgress(size_t current, size_t total) = 0;
|
||||||
|
};
|
||||||
@@ -364,7 +364,7 @@ class LinkerImpl final : public Linker
|
|||||||
zoneDirectory = fs::current_path();
|
zoneDirectory = fs::current_path();
|
||||||
auto absoluteZoneDirectory = absolute(zoneDirectory).string();
|
auto absoluteZoneDirectory = absolute(zoneDirectory).string();
|
||||||
|
|
||||||
auto maybeZone = ZoneLoading::LoadZone(zonePath);
|
auto maybeZone = ZoneLoading::LoadZone(zonePath, std::nullopt);
|
||||||
if (!maybeZone)
|
if (!maybeZone)
|
||||||
{
|
{
|
||||||
con::error("Failed to load zone \"{}\": {}", zonePath, maybeZone.error());
|
con::error("Failed to load zone \"{}\": {}", zonePath, maybeZone.error());
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ void FastFileContext::Destroy()
|
|||||||
|
|
||||||
result::Expected<Zone*, std::string> FastFileContext::LoadFastFile(const std::string& path)
|
result::Expected<Zone*, std::string> FastFileContext::LoadFastFile(const std::string& path)
|
||||||
{
|
{
|
||||||
auto zone = ZoneLoading::LoadZone(path);
|
auto zone = ZoneLoading::LoadZone(path, std::nullopt);
|
||||||
if (!zone)
|
if (!zone)
|
||||||
return result::Unexpected(std::move(zone.error()));
|
return result::Unexpected(std::move(zone.error()));
|
||||||
|
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ private:
|
|||||||
auto absoluteZoneDirectory = absolute(std::filesystem::path(zonePath).remove_filename()).string();
|
auto absoluteZoneDirectory = absolute(std::filesystem::path(zonePath).remove_filename()).string();
|
||||||
|
|
||||||
auto searchPathsForZone = paths.GetSearchPathsForZone(absoluteZoneDirectory);
|
auto searchPathsForZone = paths.GetSearchPathsForZone(absoluteZoneDirectory);
|
||||||
auto maybeZone = ZoneLoading::LoadZone(zonePath);
|
auto maybeZone = ZoneLoading::LoadZone(zonePath, std::nullopt);
|
||||||
if (!maybeZone)
|
if (!maybeZone)
|
||||||
{
|
{
|
||||||
con::error("Failed to load zone \"{}\": {}", zonePath, maybeZone.error());
|
con::error("Failed to load zone \"{}\": {}", zonePath, maybeZone.error());
|
||||||
@@ -289,7 +289,7 @@ private:
|
|||||||
|
|
||||||
auto searchPathsForZone = paths.GetSearchPathsForZone(absoluteZoneDirectory);
|
auto searchPathsForZone = paths.GetSearchPathsForZone(absoluteZoneDirectory);
|
||||||
|
|
||||||
auto maybeZone = ZoneLoading::LoadZone(zonePath);
|
auto maybeZone = ZoneLoading::LoadZone(zonePath, std::nullopt);
|
||||||
if (!maybeZone)
|
if (!maybeZone)
|
||||||
{
|
{
|
||||||
con::error("Failed to load zone \"{}\": {}", zonePath, maybeZone.error());
|
con::error("Failed to load zone \"{}\": {}", zonePath, maybeZone.error());
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
#include "Loading/Steps/StepAllocXBlocks.h"
|
#include "Loading/Steps/StepAllocXBlocks.h"
|
||||||
#include "Loading/Steps/StepLoadZoneContent.h"
|
#include "Loading/Steps/StepLoadZoneContent.h"
|
||||||
#include "Loading/Steps/StepLoadZoneSizes.h"
|
#include "Loading/Steps/StepLoadZoneSizes.h"
|
||||||
#include "Loading/Steps/StepSkipBytes.h"
|
|
||||||
#include "Utils/ClassUtils.h"
|
#include "Utils/ClassUtils.h"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@@ -22,24 +21,6 @@ using namespace IW3;
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
bool CanLoad(const ZoneHeader& header, bool* isSecure, bool* isOfficial)
|
|
||||||
{
|
|
||||||
assert(isSecure != nullptr);
|
|
||||||
assert(isOfficial != nullptr);
|
|
||||||
|
|
||||||
if (header.m_version != ZoneConstants::ZONE_VERSION)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_UNSIGNED, std::char_traits<char>::length(ZoneConstants::MAGIC_UNSIGNED)))
|
|
||||||
{
|
|
||||||
*isSecure = false;
|
|
||||||
*isOfficial = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetupBlock(ZoneLoader& zoneLoader)
|
void SetupBlock(ZoneLoader& zoneLoader)
|
||||||
{
|
{
|
||||||
#define XBLOCK_DEF(name, type) std::make_unique<XBlock>(STR(name), name, type)
|
#define XBLOCK_DEF(name, type) std::make_unique<XBlock>(STR(name), name, type)
|
||||||
@@ -58,13 +39,33 @@ namespace
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(ZoneHeader& header, std::string& fileName) const
|
std::optional<ZoneLoaderInspectionResult> ZoneLoaderFactory::InspectZoneHeader(const ZoneHeader& header) const
|
||||||
{
|
{
|
||||||
bool isSecure;
|
if (header.m_version != ZoneConstants::ZONE_VERSION)
|
||||||
bool isOfficial;
|
return std::nullopt;
|
||||||
|
|
||||||
// Check if this file is a supported IW4 zone.
|
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_UNSIGNED, std::char_traits<char>::length(ZoneConstants::MAGIC_UNSIGNED)))
|
||||||
if (!CanLoad(header, &isSecure, &isOfficial))
|
{
|
||||||
|
return ZoneLoaderInspectionResult{
|
||||||
|
.m_game_id = GameId::IW3,
|
||||||
|
.m_endianness = GameEndianness::LE,
|
||||||
|
.m_word_size = GameWordSize::ARCH_32,
|
||||||
|
.m_platform = GamePlatform::PC,
|
||||||
|
.m_is_official = true,
|
||||||
|
.m_is_signed = false,
|
||||||
|
.m_is_encrypted = false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(const ZoneHeader& header,
|
||||||
|
const std::string& fileName,
|
||||||
|
std::optional<std::unique_ptr<ProgressCallback>> progressCallback) const
|
||||||
|
{
|
||||||
|
const auto inspectResult = InspectZoneHeader(header);
|
||||||
|
if (!inspectResult)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// Create new zone
|
// Create new zone
|
||||||
@@ -93,7 +94,8 @@ std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(ZoneHeader&
|
|||||||
32u,
|
32u,
|
||||||
ZoneConstants::OFFSET_BLOCK_BIT_COUNT,
|
ZoneConstants::OFFSET_BLOCK_BIT_COUNT,
|
||||||
ZoneConstants::INSERT_BLOCK,
|
ZoneConstants::INSERT_BLOCK,
|
||||||
zonePtr->Memory()));
|
zonePtr->Memory(),
|
||||||
|
std::move(progressCallback)));
|
||||||
|
|
||||||
return zoneLoader;
|
return zoneLoader;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ namespace IW3
|
|||||||
class ZoneLoaderFactory final : public IZoneLoaderFactory
|
class ZoneLoaderFactory final : public IZoneLoaderFactory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::unique_ptr<ZoneLoader> CreateLoaderForHeader(ZoneHeader& header, std::string& fileName) const override;
|
[[nodiscard]] std::optional<ZoneLoaderInspectionResult> InspectZoneHeader(const ZoneHeader& header) const override;
|
||||||
|
[[nodiscard]] std::unique_ptr<ZoneLoader> CreateLoaderForHeader(const ZoneHeader& header,
|
||||||
|
const std::string& fileName,
|
||||||
|
std::optional<std::unique_ptr<ProgressCallback>> progressCallback) const override;
|
||||||
};
|
};
|
||||||
} // namespace IW3
|
} // namespace IW3
|
||||||
|
|||||||
@@ -34,47 +34,75 @@ using namespace IW4;
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
bool CanLoad(ZoneHeader& header, bool* isSecure, bool* isOfficial, bool* isIw4x)
|
struct ZoneLoaderInspectionResultIW4
|
||||||
{
|
{
|
||||||
assert(isSecure != nullptr);
|
ZoneLoaderInspectionResult m_generic_result;
|
||||||
assert(isOfficial != nullptr);
|
bool m_is_iw4x;
|
||||||
assert(isIw4x != nullptr);
|
};
|
||||||
|
|
||||||
if (header.m_version != ZoneConstants::ZONE_VERSION)
|
std::optional<ZoneLoaderInspectionResultIW4> InspectZoneHeaderIw4(const ZoneHeader& header)
|
||||||
{
|
{
|
||||||
return false;
|
if (header.m_version != ZoneConstants::ZONE_VERSION)
|
||||||
}
|
return std::nullopt;
|
||||||
|
|
||||||
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_IW4X, std::char_traits<char>::length(ZoneConstants::MAGIC_IW4X)))
|
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_IW4X, std::char_traits<char>::length(ZoneConstants::MAGIC_IW4X)))
|
||||||
{
|
{
|
||||||
if (*reinterpret_cast<uint32_t*>(&header.m_magic[std::char_traits<char>::length(ZoneConstants::MAGIC_IW4X)]) == ZoneConstants::IW4X_ZONE_VERSION)
|
if (*reinterpret_cast<const uint32_t*>(&header.m_magic[std::char_traits<char>::length(ZoneConstants::MAGIC_IW4X)])
|
||||||
|
== ZoneConstants::IW4X_ZONE_VERSION)
|
||||||
{
|
{
|
||||||
*isSecure = false;
|
return ZoneLoaderInspectionResultIW4{
|
||||||
*isOfficial = false;
|
.m_generic_result =
|
||||||
*isIw4x = true;
|
ZoneLoaderInspectionResult{
|
||||||
return true;
|
.m_game_id = GameId::IW4,
|
||||||
|
.m_endianness = GameEndianness::LE,
|
||||||
|
.m_word_size = GameWordSize::ARCH_32,
|
||||||
|
.m_platform = GamePlatform::PC,
|
||||||
|
.m_is_official = false,
|
||||||
|
.m_is_signed = false,
|
||||||
|
.m_is_encrypted = false,
|
||||||
|
},
|
||||||
|
.m_is_iw4x = true,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_SIGNED_INFINITY_WARD, std::char_traits<char>::length(ZoneConstants::MAGIC_SIGNED_INFINITY_WARD)))
|
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_SIGNED_INFINITY_WARD, std::char_traits<char>::length(ZoneConstants::MAGIC_SIGNED_INFINITY_WARD)))
|
||||||
{
|
{
|
||||||
*isSecure = true;
|
return ZoneLoaderInspectionResultIW4{
|
||||||
*isOfficial = true;
|
.m_generic_result =
|
||||||
*isIw4x = false;
|
ZoneLoaderInspectionResult{
|
||||||
return true;
|
.m_game_id = GameId::IW4,
|
||||||
|
.m_endianness = GameEndianness::LE,
|
||||||
|
.m_word_size = GameWordSize::ARCH_32,
|
||||||
|
.m_platform = GamePlatform::PC,
|
||||||
|
.m_is_official = true,
|
||||||
|
.m_is_signed = true,
|
||||||
|
.m_is_encrypted = false,
|
||||||
|
},
|
||||||
|
.m_is_iw4x = false,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_UNSIGNED, std::char_traits<char>::length(ZoneConstants::MAGIC_UNSIGNED)))
|
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_UNSIGNED, std::char_traits<char>::length(ZoneConstants::MAGIC_UNSIGNED)))
|
||||||
{
|
{
|
||||||
*isSecure = false;
|
return ZoneLoaderInspectionResultIW4{
|
||||||
*isOfficial = true;
|
.m_generic_result =
|
||||||
*isIw4x = false;
|
ZoneLoaderInspectionResult{
|
||||||
return true;
|
.m_game_id = GameId::IW4,
|
||||||
|
.m_endianness = GameEndianness::LE,
|
||||||
|
.m_word_size = GameWordSize::ARCH_32,
|
||||||
|
.m_platform = GamePlatform::PC,
|
||||||
|
.m_is_official = false,
|
||||||
|
.m_is_signed = false,
|
||||||
|
.m_is_encrypted = false,
|
||||||
|
},
|
||||||
|
.m_is_iw4x = false,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetupBlock(ZoneLoader& zoneLoader)
|
void SetupBlock(ZoneLoader& zoneLoader)
|
||||||
@@ -116,14 +144,14 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddAuthHeaderSteps(const bool isSecure, const bool isOfficial, ZoneLoader& zoneLoader, std::string& fileName)
|
void AddAuthHeaderSteps(const ZoneLoaderInspectionResultIW4& inspectResult, ZoneLoader& zoneLoader, const std::string& fileName)
|
||||||
{
|
{
|
||||||
// Unsigned zones do not have an auth header
|
// Unsigned zones do not have an auth header
|
||||||
if (!isSecure)
|
if (!inspectResult.m_generic_result.m_is_signed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// If file is signed setup a RSA instance.
|
// If file is signed setup a RSA instance.
|
||||||
auto rsa = SetupRsa(isOfficial);
|
auto rsa = SetupRsa(inspectResult.m_generic_result.m_is_official);
|
||||||
|
|
||||||
zoneLoader.AddLoadingStep(step::CreateStepVerifyMagic(ZoneConstants::MAGIC_AUTH_HEADER));
|
zoneLoader.AddLoadingStep(step::CreateStepVerifyMagic(ZoneConstants::MAGIC_AUTH_HEADER));
|
||||||
zoneLoader.AddLoadingStep(step::CreateStepSkipBytes(4)); // Skip reserved
|
zoneLoader.AddLoadingStep(step::CreateStepSkipBytes(4)); // Skip reserved
|
||||||
@@ -165,14 +193,21 @@ namespace
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(ZoneHeader& header, std::string& fileName) const
|
std::optional<ZoneLoaderInspectionResult> ZoneLoaderFactory::InspectZoneHeader(const ZoneHeader& header) const
|
||||||
{
|
{
|
||||||
bool isSecure;
|
auto resultIw4 = InspectZoneHeaderIw4(header);
|
||||||
bool isOfficial;
|
if (!resultIw4)
|
||||||
bool isIw4x;
|
return std::nullopt;
|
||||||
|
|
||||||
// Check if this file is a supported IW4 zone.
|
return resultIw4->m_generic_result;
|
||||||
if (!CanLoad(header, &isSecure, &isOfficial, &isIw4x))
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(const ZoneHeader& header,
|
||||||
|
const std::string& fileName,
|
||||||
|
std::optional<std::unique_ptr<ProgressCallback>> progressCallback) const
|
||||||
|
{
|
||||||
|
const auto inspectResult = InspectZoneHeaderIw4(header);
|
||||||
|
if (!inspectResult)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// Create new zone
|
// Create new zone
|
||||||
@@ -193,11 +228,11 @@ std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(ZoneHeader&
|
|||||||
zoneLoader->AddLoadingStep(step::CreateStepSkipBytes(8));
|
zoneLoader->AddLoadingStep(step::CreateStepSkipBytes(8));
|
||||||
|
|
||||||
// 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(*inspectResult, *zoneLoader, fileName);
|
||||||
|
|
||||||
zoneLoader->AddLoadingStep(step::CreateStepAddProcessor(processor::CreateProcessorInflate(ZoneConstants::AUTHED_CHUNK_SIZE)));
|
zoneLoader->AddLoadingStep(step::CreateStepAddProcessor(processor::CreateProcessorInflate(ZoneConstants::AUTHED_CHUNK_SIZE)));
|
||||||
|
|
||||||
if (isIw4x) // IW4x has one extra byte of padding here for protection purposes
|
if (inspectResult->m_is_iw4x) // IW4x has one extra byte of padding here for protection purposes
|
||||||
{
|
{
|
||||||
zoneLoader->AddLoadingStep(step::CreateStepAddProcessor(processor::CreateProcessorIW4xDecryption()));
|
zoneLoader->AddLoadingStep(step::CreateStepAddProcessor(processor::CreateProcessorIW4xDecryption()));
|
||||||
zoneLoader->AddLoadingStep(step::CreateStepSkipBytes(1));
|
zoneLoader->AddLoadingStep(step::CreateStepSkipBytes(1));
|
||||||
@@ -216,7 +251,8 @@ std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(ZoneHeader&
|
|||||||
32u,
|
32u,
|
||||||
ZoneConstants::OFFSET_BLOCK_BIT_COUNT,
|
ZoneConstants::OFFSET_BLOCK_BIT_COUNT,
|
||||||
ZoneConstants::INSERT_BLOCK,
|
ZoneConstants::INSERT_BLOCK,
|
||||||
zonePtr->Memory()));
|
zonePtr->Memory(),
|
||||||
|
std::move(progressCallback)));
|
||||||
|
|
||||||
return zoneLoader;
|
return zoneLoader;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ namespace IW4
|
|||||||
class ZoneLoaderFactory final : public IZoneLoaderFactory
|
class ZoneLoaderFactory final : public IZoneLoaderFactory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::unique_ptr<ZoneLoader> CreateLoaderForHeader(ZoneHeader& header, std::string& fileName) const override;
|
[[nodiscard]] std::optional<ZoneLoaderInspectionResult> InspectZoneHeader(const ZoneHeader& header) const override;
|
||||||
|
[[nodiscard]] std::unique_ptr<ZoneLoader> CreateLoaderForHeader(const ZoneHeader& header,
|
||||||
|
const std::string& fileName,
|
||||||
|
std::optional<std::unique_ptr<ProgressCallback>> progressCallback) const override;
|
||||||
};
|
};
|
||||||
} // namespace IW4
|
} // namespace IW4
|
||||||
|
|||||||
@@ -33,33 +33,6 @@ using namespace IW5;
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
bool CanLoad(const ZoneHeader& header, bool* isSecure, bool* isOfficial)
|
|
||||||
{
|
|
||||||
assert(isSecure != nullptr);
|
|
||||||
assert(isOfficial != nullptr);
|
|
||||||
|
|
||||||
if (header.m_version != ZoneConstants::ZONE_VERSION)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_SIGNED_INFINITY_WARD, std::char_traits<char>::length(ZoneConstants::MAGIC_SIGNED_INFINITY_WARD)))
|
|
||||||
{
|
|
||||||
*isSecure = true;
|
|
||||||
*isOfficial = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_UNSIGNED, std::char_traits<char>::length(ZoneConstants::MAGIC_UNSIGNED)))
|
|
||||||
{
|
|
||||||
*isSecure = false;
|
|
||||||
*isOfficial = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetupBlock(ZoneLoader& zoneLoader)
|
void SetupBlock(ZoneLoader& zoneLoader)
|
||||||
{
|
{
|
||||||
#define XBLOCK_DEF(name, type) std::make_unique<XBlock>(STR(name), name, type)
|
#define XBLOCK_DEF(name, type) std::make_unique<XBlock>(STR(name), name, type)
|
||||||
@@ -100,14 +73,14 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddAuthHeaderSteps(const bool isSecure, const bool isOfficial, ZoneLoader& zoneLoader, std::string& fileName)
|
void AddAuthHeaderSteps(const ZoneLoaderInspectionResult& inspectResult, ZoneLoader& zoneLoader, const std::string& fileName)
|
||||||
{
|
{
|
||||||
// Unsigned zones do not have an auth header
|
// Unsigned zones do not have an auth header
|
||||||
if (!isSecure)
|
if (!inspectResult.m_is_signed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// If file is signed setup a RSA instance.
|
// If file is signed setup a RSA instance.
|
||||||
auto rsa = SetupRsa(isOfficial);
|
auto rsa = SetupRsa(inspectResult.m_is_official);
|
||||||
|
|
||||||
zoneLoader.AddLoadingStep(step::CreateStepVerifyMagic(ZoneConstants::MAGIC_AUTH_HEADER));
|
zoneLoader.AddLoadingStep(step::CreateStepVerifyMagic(ZoneConstants::MAGIC_AUTH_HEADER));
|
||||||
zoneLoader.AddLoadingStep(step::CreateStepSkipBytes(4)); // Skip reserved
|
zoneLoader.AddLoadingStep(step::CreateStepSkipBytes(4)); // Skip reserved
|
||||||
@@ -149,13 +122,46 @@ namespace
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(ZoneHeader& header, std::string& fileName) const
|
std::optional<ZoneLoaderInspectionResult> ZoneLoaderFactory::InspectZoneHeader(const ZoneHeader& header) const
|
||||||
{
|
{
|
||||||
bool isSecure;
|
if (header.m_version != ZoneConstants::ZONE_VERSION)
|
||||||
bool isOfficial;
|
return std::nullopt;
|
||||||
|
|
||||||
// Check if this file is a supported IW4 zone.
|
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_SIGNED_INFINITY_WARD, std::char_traits<char>::length(ZoneConstants::MAGIC_SIGNED_INFINITY_WARD)))
|
||||||
if (!CanLoad(header, &isSecure, &isOfficial))
|
{
|
||||||
|
return ZoneLoaderInspectionResult{
|
||||||
|
.m_game_id = GameId::IW5,
|
||||||
|
.m_endianness = GameEndianness::LE,
|
||||||
|
.m_word_size = GameWordSize::ARCH_32,
|
||||||
|
.m_platform = GamePlatform::PC,
|
||||||
|
.m_is_official = true,
|
||||||
|
.m_is_signed = true,
|
||||||
|
.m_is_encrypted = false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_UNSIGNED, std::char_traits<char>::length(ZoneConstants::MAGIC_UNSIGNED)))
|
||||||
|
{
|
||||||
|
return ZoneLoaderInspectionResult{
|
||||||
|
.m_game_id = GameId::IW5,
|
||||||
|
.m_endianness = GameEndianness::LE,
|
||||||
|
.m_word_size = GameWordSize::ARCH_32,
|
||||||
|
.m_platform = GamePlatform::PC,
|
||||||
|
.m_is_official = false,
|
||||||
|
.m_is_signed = false,
|
||||||
|
.m_is_encrypted = false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(const ZoneHeader& header,
|
||||||
|
const std::string& fileName,
|
||||||
|
std::optional<std::unique_ptr<ProgressCallback>> progressCallback) const
|
||||||
|
{
|
||||||
|
const auto inspectResult = InspectZoneHeader(header);
|
||||||
|
if (!inspectResult)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// Create new zone
|
// Create new zone
|
||||||
@@ -176,7 +182,7 @@ std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(ZoneHeader&
|
|||||||
zoneLoader->AddLoadingStep(step::CreateStepSkipBytes(8));
|
zoneLoader->AddLoadingStep(step::CreateStepSkipBytes(8));
|
||||||
|
|
||||||
// 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(*inspectResult, *zoneLoader, fileName);
|
||||||
|
|
||||||
zoneLoader->AddLoadingStep(step::CreateStepAddProcessor(processor::CreateProcessorInflate(ZoneConstants::AUTHED_CHUNK_SIZE)));
|
zoneLoader->AddLoadingStep(step::CreateStepAddProcessor(processor::CreateProcessorInflate(ZoneConstants::AUTHED_CHUNK_SIZE)));
|
||||||
|
|
||||||
@@ -193,7 +199,8 @@ std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(ZoneHeader&
|
|||||||
32u,
|
32u,
|
||||||
ZoneConstants::OFFSET_BLOCK_BIT_COUNT,
|
ZoneConstants::OFFSET_BLOCK_BIT_COUNT,
|
||||||
ZoneConstants::INSERT_BLOCK,
|
ZoneConstants::INSERT_BLOCK,
|
||||||
zonePtr->Memory()));
|
zonePtr->Memory(),
|
||||||
|
std::move(progressCallback)));
|
||||||
|
|
||||||
return zoneLoader;
|
return zoneLoader;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ namespace IW5
|
|||||||
class ZoneLoaderFactory final : public IZoneLoaderFactory
|
class ZoneLoaderFactory final : public IZoneLoaderFactory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::unique_ptr<ZoneLoader> CreateLoaderForHeader(ZoneHeader& header, std::string& fileName) const override;
|
[[nodiscard]] std::optional<ZoneLoaderInspectionResult> InspectZoneHeader(const ZoneHeader& header) const override;
|
||||||
|
[[nodiscard]] std::unique_ptr<ZoneLoader> CreateLoaderForHeader(const ZoneHeader& header,
|
||||||
|
const std::string& fileName,
|
||||||
|
std::optional<std::unique_ptr<ProgressCallback>> progressCallback) const override;
|
||||||
};
|
};
|
||||||
} // namespace IW5
|
} // namespace IW5
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
#include "Loading/Steps/StepAllocXBlocks.h"
|
#include "Loading/Steps/StepAllocXBlocks.h"
|
||||||
#include "Loading/Steps/StepLoadZoneContent.h"
|
#include "Loading/Steps/StepLoadZoneContent.h"
|
||||||
#include "Loading/Steps/StepLoadZoneSizes.h"
|
#include "Loading/Steps/StepLoadZoneSizes.h"
|
||||||
#include "Loading/Steps/StepSkipBytes.h"
|
|
||||||
#include "Utils/ClassUtils.h"
|
#include "Utils/ClassUtils.h"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@@ -22,26 +21,6 @@ using namespace T5;
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
bool CanLoad(const ZoneHeader& header, bool* isSecure, bool* isOfficial)
|
|
||||||
{
|
|
||||||
assert(isSecure != nullptr);
|
|
||||||
assert(isOfficial != nullptr);
|
|
||||||
|
|
||||||
if (header.m_version != ZoneConstants::ZONE_VERSION)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_UNSIGNED, std::char_traits<char>::length(ZoneConstants::MAGIC_UNSIGNED)))
|
|
||||||
{
|
|
||||||
*isSecure = false;
|
|
||||||
*isOfficial = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetupBlock(ZoneLoader& zoneLoader)
|
void SetupBlock(ZoneLoader& zoneLoader)
|
||||||
{
|
{
|
||||||
#define XBLOCK_DEF(name, type) std::make_unique<XBlock>(STR(name), name, type)
|
#define XBLOCK_DEF(name, type) std::make_unique<XBlock>(STR(name), name, type)
|
||||||
@@ -58,13 +37,34 @@ namespace
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(ZoneHeader& header, std::string& fileName) const
|
std::optional<ZoneLoaderInspectionResult> ZoneLoaderFactory::InspectZoneHeader(const ZoneHeader& header) const
|
||||||
{
|
{
|
||||||
bool isSecure;
|
if (header.m_version != ZoneConstants::ZONE_VERSION)
|
||||||
bool isOfficial;
|
return std::nullopt;
|
||||||
|
|
||||||
// Check if this file is a supported IW4 zone.
|
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_UNSIGNED, std::char_traits<char>::length(ZoneConstants::MAGIC_UNSIGNED)))
|
||||||
if (!CanLoad(header, &isSecure, &isOfficial))
|
{
|
||||||
|
return ZoneLoaderInspectionResult{
|
||||||
|
.m_game_id = GameId::T5,
|
||||||
|
.m_endianness = GameEndianness::LE,
|
||||||
|
.m_word_size = GameWordSize::ARCH_32,
|
||||||
|
.m_platform = GamePlatform::PC,
|
||||||
|
// There is no way to know whether unsigned zones are official.
|
||||||
|
.m_is_official = false,
|
||||||
|
.m_is_signed = false,
|
||||||
|
.m_is_encrypted = false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(const ZoneHeader& header,
|
||||||
|
const std::string& fileName,
|
||||||
|
std::optional<std::unique_ptr<ProgressCallback>> progressCallback) const
|
||||||
|
{
|
||||||
|
const auto inspectResult = InspectZoneHeader(header);
|
||||||
|
if (!inspectResult)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// Create new zone
|
// Create new zone
|
||||||
@@ -93,7 +93,8 @@ std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(ZoneHeader&
|
|||||||
32u,
|
32u,
|
||||||
ZoneConstants::OFFSET_BLOCK_BIT_COUNT,
|
ZoneConstants::OFFSET_BLOCK_BIT_COUNT,
|
||||||
ZoneConstants::INSERT_BLOCK,
|
ZoneConstants::INSERT_BLOCK,
|
||||||
zonePtr->Memory()));
|
zonePtr->Memory(),
|
||||||
|
std::move(progressCallback)));
|
||||||
|
|
||||||
return zoneLoader;
|
return zoneLoader;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ namespace T5
|
|||||||
class ZoneLoaderFactory final : public IZoneLoaderFactory
|
class ZoneLoaderFactory final : public IZoneLoaderFactory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::unique_ptr<ZoneLoader> CreateLoaderForHeader(ZoneHeader& header, std::string& fileName) const override;
|
[[nodiscard]] std::optional<ZoneLoaderInspectionResult> InspectZoneHeader(const ZoneHeader& header) const override;
|
||||||
|
[[nodiscard]] std::unique_ptr<ZoneLoader> CreateLoaderForHeader(const ZoneHeader& header,
|
||||||
|
const std::string& fileName,
|
||||||
|
std::optional<std::unique_ptr<ProgressCallback>> progressCallback) const override;
|
||||||
};
|
};
|
||||||
} // namespace T5
|
} // namespace T5
|
||||||
|
|||||||
@@ -24,11 +24,10 @@
|
|||||||
#include "Zone/XChunk/XChunkProcessorSalsa20Decryption.h"
|
#include "Zone/XChunk/XChunkProcessorSalsa20Decryption.h"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstdio>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <iostream>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
using namespace T6;
|
using namespace T6;
|
||||||
@@ -36,6 +35,130 @@ namespace fs = std::filesystem;
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
enum class ZoneCompressionTypeT6 : std::uint8_t
|
||||||
|
{
|
||||||
|
DEFLATE,
|
||||||
|
LZX
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ZoneLoaderInspectionResultT6
|
||||||
|
{
|
||||||
|
ZoneLoaderInspectionResult m_generic_result;
|
||||||
|
ZoneCompressionTypeT6 m_compression_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::optional<ZoneLoaderInspectionResultT6> InspectZoneHeaderT6(const ZoneHeader& header)
|
||||||
|
{
|
||||||
|
if (endianness::FromLittleEndian(header.m_version) == ZoneConstants::ZONE_VERSION_PC)
|
||||||
|
{
|
||||||
|
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_SIGNED_TREYARCH, 8))
|
||||||
|
{
|
||||||
|
return ZoneLoaderInspectionResultT6{
|
||||||
|
.m_generic_result =
|
||||||
|
ZoneLoaderInspectionResult{
|
||||||
|
.m_game_id = GameId::T6,
|
||||||
|
.m_endianness = GameEndianness::LE,
|
||||||
|
.m_word_size = GameWordSize::ARCH_32,
|
||||||
|
.m_platform = GamePlatform::PC,
|
||||||
|
.m_is_official = true,
|
||||||
|
.m_is_signed = true,
|
||||||
|
.m_is_encrypted = true,
|
||||||
|
},
|
||||||
|
.m_compression_type = ZoneCompressionTypeT6::DEFLATE,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_SIGNED_OAT, 8))
|
||||||
|
{
|
||||||
|
return ZoneLoaderInspectionResultT6{
|
||||||
|
.m_generic_result =
|
||||||
|
ZoneLoaderInspectionResult{
|
||||||
|
.m_game_id = GameId::T6,
|
||||||
|
.m_endianness = GameEndianness::LE,
|
||||||
|
.m_word_size = GameWordSize::ARCH_32,
|
||||||
|
.m_platform = GamePlatform::PC,
|
||||||
|
.m_is_official = false,
|
||||||
|
.m_is_signed = true,
|
||||||
|
.m_is_encrypted = true,
|
||||||
|
},
|
||||||
|
.m_compression_type = ZoneCompressionTypeT6::DEFLATE,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_UNSIGNED, 8))
|
||||||
|
{
|
||||||
|
return ZoneLoaderInspectionResultT6{
|
||||||
|
.m_generic_result =
|
||||||
|
ZoneLoaderInspectionResult{
|
||||||
|
.m_game_id = GameId::T6,
|
||||||
|
.m_endianness = GameEndianness::LE,
|
||||||
|
.m_word_size = GameWordSize::ARCH_32,
|
||||||
|
.m_platform = GamePlatform::PC,
|
||||||
|
.m_is_official = false,
|
||||||
|
.m_is_signed = false,
|
||||||
|
.m_is_encrypted = true,
|
||||||
|
},
|
||||||
|
.m_compression_type = ZoneCompressionTypeT6::DEFLATE,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_UNSIGNED_SERVER, 8))
|
||||||
|
{
|
||||||
|
return ZoneLoaderInspectionResultT6{
|
||||||
|
.m_generic_result =
|
||||||
|
ZoneLoaderInspectionResult{
|
||||||
|
.m_game_id = GameId::T6,
|
||||||
|
.m_endianness = GameEndianness::LE,
|
||||||
|
.m_word_size = GameWordSize::ARCH_32,
|
||||||
|
.m_platform = GamePlatform::PC,
|
||||||
|
.m_is_official = true,
|
||||||
|
.m_is_signed = false,
|
||||||
|
.m_is_encrypted = false,
|
||||||
|
},
|
||||||
|
.m_compression_type = ZoneCompressionTypeT6::DEFLATE,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (endianness::FromBigEndian(header.m_version) == ZoneConstants::ZONE_VERSION_XENON)
|
||||||
|
{
|
||||||
|
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_SIGNED_TREYARCH, 8))
|
||||||
|
{
|
||||||
|
return ZoneLoaderInspectionResultT6{
|
||||||
|
.m_generic_result =
|
||||||
|
ZoneLoaderInspectionResult{
|
||||||
|
.m_game_id = GameId::T6,
|
||||||
|
.m_endianness = GameEndianness::BE,
|
||||||
|
.m_word_size = GameWordSize::ARCH_32,
|
||||||
|
.m_platform = GamePlatform::XBOX,
|
||||||
|
.m_is_official = true,
|
||||||
|
.m_is_signed = true,
|
||||||
|
.m_is_encrypted = true,
|
||||||
|
},
|
||||||
|
.m_compression_type = ZoneCompressionTypeT6::DEFLATE,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_SIGNED_LZX_TREYARCH, 8))
|
||||||
|
{
|
||||||
|
return ZoneLoaderInspectionResultT6{
|
||||||
|
.m_generic_result =
|
||||||
|
ZoneLoaderInspectionResult{
|
||||||
|
.m_game_id = GameId::T6,
|
||||||
|
.m_endianness = GameEndianness::BE,
|
||||||
|
.m_word_size = GameWordSize::ARCH_32,
|
||||||
|
.m_platform = GamePlatform::XBOX,
|
||||||
|
.m_is_official = true,
|
||||||
|
.m_is_signed = true,
|
||||||
|
.m_is_encrypted = true,
|
||||||
|
},
|
||||||
|
.m_compression_type = ZoneCompressionTypeT6::LZX,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
GameLanguage GetZoneLanguage(const std::string& zoneName)
|
GameLanguage GetZoneLanguage(const std::string& zoneName)
|
||||||
{
|
{
|
||||||
const auto& languagePrefixes = IGame::GetGameById(GameId::T6)->GetLanguagePrefixes();
|
const auto& languagePrefixes = IGame::GetGameById(GameId::T6)->GetLanguagePrefixes();
|
||||||
@@ -51,68 +174,6 @@ namespace
|
|||||||
return GameLanguage::LANGUAGE_NONE;
|
return GameLanguage::LANGUAGE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CanLoad(const ZoneHeader& header, bool& isBigEndian, bool& isSecure, bool& isOfficial, bool& isEncrypted, bool& isLzxCompressed)
|
|
||||||
{
|
|
||||||
if (endianness::FromLittleEndian(header.m_version) == ZoneConstants::ZONE_VERSION_PC)
|
|
||||||
{
|
|
||||||
isBigEndian = false;
|
|
||||||
isLzxCompressed = false;
|
|
||||||
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_SIGNED_TREYARCH, 8))
|
|
||||||
{
|
|
||||||
isSecure = true;
|
|
||||||
isOfficial = true;
|
|
||||||
isEncrypted = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_SIGNED_OAT, 8))
|
|
||||||
{
|
|
||||||
isSecure = true;
|
|
||||||
isOfficial = false;
|
|
||||||
isEncrypted = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_UNSIGNED, 8))
|
|
||||||
{
|
|
||||||
isSecure = false;
|
|
||||||
isOfficial = true;
|
|
||||||
isEncrypted = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_UNSIGNED_SERVER, 8))
|
|
||||||
{
|
|
||||||
isSecure = false;
|
|
||||||
isOfficial = true;
|
|
||||||
isEncrypted = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (endianness::FromBigEndian(header.m_version) == ZoneConstants::ZONE_VERSION_XENON)
|
|
||||||
{
|
|
||||||
isBigEndian = true;
|
|
||||||
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_SIGNED_TREYARCH, 8))
|
|
||||||
{
|
|
||||||
isSecure = true;
|
|
||||||
isOfficial = true;
|
|
||||||
isEncrypted = true;
|
|
||||||
isLzxCompressed = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_SIGNED_LZX_TREYARCH, 8))
|
|
||||||
{
|
|
||||||
isSecure = true;
|
|
||||||
isOfficial = true;
|
|
||||||
isEncrypted = true;
|
|
||||||
isLzxCompressed = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetupBlock(ZoneLoader& zoneLoader)
|
void SetupBlock(ZoneLoader& zoneLoader)
|
||||||
{
|
{
|
||||||
#define XBLOCK_DEF(name, type) std::make_unique<XBlock>(STR(name), name, type)
|
#define XBLOCK_DEF(name, type) std::make_unique<XBlock>(STR(name), name, type)
|
||||||
@@ -169,26 +230,16 @@ namespace
|
|||||||
return signatureLoadStepPtr;
|
return signatureLoadStepPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ICapturedDataProvider*
|
ICapturedDataProvider* AddXChunkProcessor(const ZoneLoaderInspectionResultT6& inspectResult, ZoneLoader& zoneLoader, const std::string& fileName)
|
||||||
AddXChunkProcessor(const bool isBigEndian, const bool isEncrypted, const bool isLzxCompressed, ZoneLoader& zoneLoader, std::string& fileName)
|
|
||||||
{
|
{
|
||||||
ICapturedDataProvider* result = nullptr;
|
ICapturedDataProvider* result = nullptr;
|
||||||
std::unique_ptr<processor::IProcessorXChunks> xChunkProcessor;
|
auto xChunkProcessor = processor::CreateProcessorXChunks(
|
||||||
|
ZoneConstants::STREAM_COUNT, ZoneConstants::XCHUNK_SIZE, inspectResult.m_generic_result.m_endianness, ZoneConstants::VANILLA_BUFFER_SIZE);
|
||||||
|
|
||||||
if (isBigEndian)
|
const uint8_t (&salsa20Key)[32] = inspectResult.m_generic_result.m_platform == GamePlatform::XBOX ? ZoneConstants::SALSA20_KEY_TREYARCH_XENON
|
||||||
{
|
: ZoneConstants::SALSA20_KEY_TREYARCH_PC;
|
||||||
xChunkProcessor = processor::CreateProcessorXChunks(
|
|
||||||
ZoneConstants::STREAM_COUNT, ZoneConstants::XCHUNK_SIZE, GameEndianness::BE, ZoneConstants::VANILLA_BUFFER_SIZE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
xChunkProcessor = processor::CreateProcessorXChunks(
|
|
||||||
ZoneConstants::STREAM_COUNT, ZoneConstants::XCHUNK_SIZE, GameEndianness::LE, ZoneConstants::VANILLA_BUFFER_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t (&salsa20Key)[32] = isBigEndian ? ZoneConstants::SALSA20_KEY_TREYARCH_XENON : ZoneConstants::SALSA20_KEY_TREYARCH_PC;
|
if (inspectResult.m_generic_result.m_is_encrypted)
|
||||||
|
|
||||||
if (isEncrypted)
|
|
||||||
{
|
{
|
||||||
// If zone is encrypted, the decryption is applied before the decompression. T6 Zones always use Salsa20.
|
// If zone is encrypted, the decryption is applied before the decompression. T6 Zones always use Salsa20.
|
||||||
auto chunkProcessorSalsa20 =
|
auto chunkProcessorSalsa20 =
|
||||||
@@ -197,7 +248,7 @@ namespace
|
|||||||
xChunkProcessor->AddChunkProcessor(std::move(chunkProcessorSalsa20));
|
xChunkProcessor->AddChunkProcessor(std::move(chunkProcessorSalsa20));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isLzxCompressed)
|
if (inspectResult.m_compression_type == ZoneCompressionTypeT6::LZX)
|
||||||
{
|
{
|
||||||
// Decompress the chunks using lzx
|
// Decompress the chunks using lzx
|
||||||
xChunkProcessor->AddChunkProcessor(std::make_unique<XChunkProcessorLzxDecompress>(ZoneConstants::STREAM_COUNT));
|
xChunkProcessor->AddChunkProcessor(std::make_unique<XChunkProcessorLzxDecompress>(ZoneConstants::STREAM_COUNT));
|
||||||
@@ -215,12 +266,21 @@ namespace
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(ZoneHeader& header, std::string& fileName) const
|
std::optional<ZoneLoaderInspectionResult> ZoneLoaderFactory::InspectZoneHeader(const ZoneHeader& header) const
|
||||||
{
|
{
|
||||||
bool isBigEndian, isSecure, isOfficial, isEncrypted, isLzxCompressed;
|
auto resultT6 = InspectZoneHeaderT6(header);
|
||||||
|
if (!resultT6)
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
// Check if this file is a supported T6 zone.
|
return resultT6->m_generic_result;
|
||||||
if (!CanLoad(header, isBigEndian, isSecure, isOfficial, isEncrypted, isLzxCompressed))
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(const ZoneHeader& header,
|
||||||
|
const std::string& fileName,
|
||||||
|
std::optional<std::unique_ptr<ProgressCallback>> progressCallback) const
|
||||||
|
{
|
||||||
|
const auto inspectResult = InspectZoneHeaderT6(header);
|
||||||
|
if (!inspectResult)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// Create new zone
|
// Create new zone
|
||||||
@@ -235,15 +295,15 @@ std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(ZoneHeader&
|
|||||||
SetupBlock(*zoneLoader);
|
SetupBlock(*zoneLoader);
|
||||||
|
|
||||||
// If file is signed setup a RSA instance.
|
// If file is signed setup a RSA instance.
|
||||||
auto rsa = isSecure ? SetupRsa(isOfficial) : nullptr;
|
auto rsa = inspectResult->m_generic_result.m_is_signed ? SetupRsa(inspectResult->m_generic_result.m_is_official) : nullptr;
|
||||||
|
|
||||||
// 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.
|
||||||
ISignatureProvider* signatureProvider = AddAuthHeaderSteps(isSecure, *zoneLoader, fileName);
|
ISignatureProvider* signatureProvider = AddAuthHeaderSteps(inspectResult->m_generic_result.m_is_signed, *zoneLoader, fileName);
|
||||||
|
|
||||||
// Setup loading XChunks from the zone from this point on.
|
// Setup loading XChunks from the zone from this point on.
|
||||||
ICapturedDataProvider* signatureDataProvider = AddXChunkProcessor(isBigEndian, isEncrypted, isLzxCompressed, *zoneLoader, fileName);
|
ICapturedDataProvider* signatureDataProvider = AddXChunkProcessor(*inspectResult, *zoneLoader, fileName);
|
||||||
|
|
||||||
if (!isBigEndian)
|
if (inspectResult->m_generic_result.m_endianness == GameEndianness::LE)
|
||||||
{
|
{
|
||||||
// Start of the XFile struct
|
// Start of the XFile struct
|
||||||
zoneLoader->AddLoadingStep(step::CreateStepLoadZoneSizes());
|
zoneLoader->AddLoadingStep(step::CreateStepLoadZoneSizes());
|
||||||
@@ -258,13 +318,12 @@ std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(ZoneHeader&
|
|||||||
32u,
|
32u,
|
||||||
ZoneConstants::OFFSET_BLOCK_BIT_COUNT,
|
ZoneConstants::OFFSET_BLOCK_BIT_COUNT,
|
||||||
ZoneConstants::INSERT_BLOCK,
|
ZoneConstants::INSERT_BLOCK,
|
||||||
zonePtr->Memory()));
|
zonePtr->Memory(),
|
||||||
|
std::move(progressCallback)));
|
||||||
|
|
||||||
if (isSecure)
|
if (inspectResult->m_generic_result.m_is_signed)
|
||||||
{
|
|
||||||
zoneLoader->AddLoadingStep(step::CreateStepVerifySignature(std::move(rsa), signatureProvider, signatureDataProvider));
|
zoneLoader->AddLoadingStep(step::CreateStepVerifySignature(std::move(rsa), signatureProvider, signatureDataProvider));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fs::path dumpFileNamePath = fs::path(fileName).filename();
|
fs::path dumpFileNamePath = fs::path(fileName).filename();
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ namespace T6
|
|||||||
class ZoneLoaderFactory final : public IZoneLoaderFactory
|
class ZoneLoaderFactory final : public IZoneLoaderFactory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::unique_ptr<ZoneLoader> CreateLoaderForHeader(ZoneHeader& header, std::string& fileName) const override;
|
[[nodiscard]] std::optional<ZoneLoaderInspectionResult> InspectZoneHeader(const ZoneHeader& header) const override;
|
||||||
|
[[nodiscard]] std::unique_ptr<ZoneLoader> CreateLoaderForHeader(const ZoneHeader& header,
|
||||||
|
const std::string& fileName,
|
||||||
|
std::optional<std::unique_ptr<ProgressCallback>> progressCallback) const override;
|
||||||
};
|
};
|
||||||
} // namespace T6
|
} // namespace T6
|
||||||
|
|||||||
@@ -1,9 +1,30 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Game/IGame.h"
|
||||||
|
#include "Utils/ProgressCallback.h"
|
||||||
#include "Zone/ZoneTypes.h"
|
#include "Zone/ZoneTypes.h"
|
||||||
#include "ZoneLoader.h"
|
#include "ZoneLoader.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
struct ZoneLoaderInspectionResult
|
||||||
|
{
|
||||||
|
// The game this zone is created for.
|
||||||
|
GameId m_game_id;
|
||||||
|
// Whether the zone is meant for a little-endian or big-endian loader.
|
||||||
|
GameEndianness m_endianness;
|
||||||
|
// Whether the zone is meant for a 32bit or 64bit loader.
|
||||||
|
GameWordSize m_word_size;
|
||||||
|
// The platform this zone is for.
|
||||||
|
GamePlatform m_platform;
|
||||||
|
// Whether this zone is confirmed official. False if not official or unknown.
|
||||||
|
bool m_is_official;
|
||||||
|
// Whether this zone contains a signature confirming the identity of the creator.
|
||||||
|
bool m_is_signed;
|
||||||
|
// Whether this zone is encrypted.
|
||||||
|
bool m_is_encrypted;
|
||||||
|
};
|
||||||
|
|
||||||
class IZoneLoaderFactory
|
class IZoneLoaderFactory
|
||||||
{
|
{
|
||||||
@@ -15,7 +36,10 @@ public:
|
|||||||
IZoneLoaderFactory& operator=(const IZoneLoaderFactory& other) = default;
|
IZoneLoaderFactory& operator=(const IZoneLoaderFactory& other) = default;
|
||||||
IZoneLoaderFactory& operator=(IZoneLoaderFactory&& other) noexcept = default;
|
IZoneLoaderFactory& operator=(IZoneLoaderFactory&& other) noexcept = default;
|
||||||
|
|
||||||
virtual std::unique_ptr<ZoneLoader> CreateLoaderForHeader(ZoneHeader& header, std::string& fileName) const = 0;
|
[[nodiscard]] virtual std::optional<ZoneLoaderInspectionResult> InspectZoneHeader(const ZoneHeader& header) const = 0;
|
||||||
|
[[nodiscard]] virtual std::unique_ptr<ZoneLoader> CreateLoaderForHeader(const ZoneHeader& header,
|
||||||
|
const std::string& fileName,
|
||||||
|
std::optional<std::unique_ptr<ProgressCallback>> progressCallback) const = 0;
|
||||||
|
|
||||||
static const IZoneLoaderFactory* GetZoneLoaderFactoryForGame(GameId game);
|
static const IZoneLoaderFactory* GetZoneLoaderFactoryForGame(GameId game);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,19 +11,21 @@ namespace
|
|||||||
const unsigned pointerBitCount,
|
const unsigned pointerBitCount,
|
||||||
const unsigned offsetBlockBitCount,
|
const unsigned offsetBlockBitCount,
|
||||||
const block_t insertBlock,
|
const block_t insertBlock,
|
||||||
MemoryManager& memory)
|
MemoryManager& memory,
|
||||||
|
std::optional<std::unique_ptr<ProgressCallback>> progressCallback)
|
||||||
: m_entry_point_factory(std::move(entryPointFactory)),
|
: m_entry_point_factory(std::move(entryPointFactory)),
|
||||||
m_pointer_bit_count(pointerBitCount),
|
m_pointer_bit_count(pointerBitCount),
|
||||||
m_offset_block_bit_count(offsetBlockBitCount),
|
m_offset_block_bit_count(offsetBlockBitCount),
|
||||||
m_insert_block(insertBlock),
|
m_insert_block(insertBlock),
|
||||||
m_memory(memory)
|
m_memory(memory),
|
||||||
|
m_progress_callback(std::move(progressCallback))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void PerformStep(ZoneLoader& zoneLoader, ILoadingStream& stream) override
|
void PerformStep(ZoneLoader& zoneLoader, ILoadingStream& stream) override
|
||||||
{
|
{
|
||||||
const auto inputStream =
|
const auto inputStream = ZoneInputStream::Create(
|
||||||
ZoneInputStream::Create(m_pointer_bit_count, m_offset_block_bit_count, zoneLoader.m_blocks, m_insert_block, stream, m_memory);
|
m_pointer_bit_count, m_offset_block_bit_count, zoneLoader.m_blocks, m_insert_block, stream, m_memory, std::move(m_progress_callback));
|
||||||
|
|
||||||
const auto entryPoint = m_entry_point_factory(*inputStream);
|
const auto entryPoint = m_entry_point_factory(*inputStream);
|
||||||
assert(entryPoint);
|
assert(entryPoint);
|
||||||
@@ -37,6 +39,7 @@ namespace
|
|||||||
unsigned m_offset_block_bit_count;
|
unsigned m_offset_block_bit_count;
|
||||||
block_t m_insert_block;
|
block_t m_insert_block;
|
||||||
MemoryManager& m_memory;
|
MemoryManager& m_memory;
|
||||||
|
std::optional<std::unique_ptr<ProgressCallback>> m_progress_callback;
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@@ -46,8 +49,10 @@ namespace step
|
|||||||
const unsigned pointerBitCount,
|
const unsigned pointerBitCount,
|
||||||
const unsigned offsetBlockBitCount,
|
const unsigned offsetBlockBitCount,
|
||||||
const block_t insertBlock,
|
const block_t insertBlock,
|
||||||
MemoryManager& memory)
|
MemoryManager& memory,
|
||||||
|
std::optional<std::unique_ptr<ProgressCallback>> progressCallback)
|
||||||
{
|
{
|
||||||
return std::make_unique<StepLoadZoneContent>(std::move(entryPointFactory), pointerBitCount, offsetBlockBitCount, insertBlock, memory);
|
return std::make_unique<StepLoadZoneContent>(
|
||||||
|
std::move(entryPointFactory), pointerBitCount, offsetBlockBitCount, insertBlock, memory, std::move(progressCallback));
|
||||||
}
|
}
|
||||||
} // namespace step
|
} // namespace step
|
||||||
|
|||||||
@@ -13,5 +13,6 @@ namespace step
|
|||||||
unsigned pointerBitCount,
|
unsigned pointerBitCount,
|
||||||
unsigned offsetBlockBitCount,
|
unsigned offsetBlockBitCount,
|
||||||
block_t insertBlock,
|
block_t insertBlock,
|
||||||
MemoryManager& memory);
|
MemoryManager& memory,
|
||||||
|
std::optional<std::unique_ptr<ProgressCallback>> progressCallback);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,8 @@ namespace
|
|||||||
std::vector<XBlock*>& blocks,
|
std::vector<XBlock*>& blocks,
|
||||||
const block_t insertBlock,
|
const block_t insertBlock,
|
||||||
ILoadingStream& stream,
|
ILoadingStream& stream,
|
||||||
MemoryManager& memory)
|
MemoryManager& memory,
|
||||||
|
std::optional<std::unique_ptr<ProgressCallback>> progressCallback)
|
||||||
: m_blocks(blocks),
|
: m_blocks(blocks),
|
||||||
m_stream(stream),
|
m_stream(stream),
|
||||||
m_memory(memory),
|
m_memory(memory),
|
||||||
@@ -58,7 +59,11 @@ namespace
|
|||||||
m_block_mask((std::numeric_limits<uintptr_t>::max() >> (sizeof(uintptr_t) * 8 - blockBitCount)) << (pointerBitCount - blockBitCount)),
|
m_block_mask((std::numeric_limits<uintptr_t>::max() >> (sizeof(uintptr_t) * 8 - blockBitCount)) << (pointerBitCount - blockBitCount)),
|
||||||
m_block_shift(pointerBitCount - blockBitCount),
|
m_block_shift(pointerBitCount - blockBitCount),
|
||||||
m_offset_mask(std::numeric_limits<uintptr_t>::max() >> (sizeof(uintptr_t) * 8 - (pointerBitCount - blockBitCount))),
|
m_offset_mask(std::numeric_limits<uintptr_t>::max() >> (sizeof(uintptr_t) * 8 - (pointerBitCount - blockBitCount))),
|
||||||
m_last_fill_size(0)
|
m_last_fill_size(0),
|
||||||
|
m_has_progress_callback(progressCallback.has_value()),
|
||||||
|
m_progress_callback(std::move(progressCallback).value_or(nullptr)),
|
||||||
|
m_progress_current_size(0uz),
|
||||||
|
m_progress_total_size(0uz)
|
||||||
{
|
{
|
||||||
assert(pointerBitCount % 8u == 0u);
|
assert(pointerBitCount % 8u == 0u);
|
||||||
assert(insertBlock < static_cast<block_t>(blocks.size()));
|
assert(insertBlock < static_cast<block_t>(blocks.size()));
|
||||||
@@ -68,6 +73,8 @@ namespace
|
|||||||
std::memset(m_block_offsets.get(), 0, sizeof(size_t) * blockCount);
|
std::memset(m_block_offsets.get(), 0, sizeof(size_t) * blockCount);
|
||||||
|
|
||||||
m_insert_block = blocks[insertBlock];
|
m_insert_block = blocks[insertBlock];
|
||||||
|
|
||||||
|
m_progress_total_size = CalculateTotalSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] unsigned GetPointerBitCount() const override
|
[[nodiscard]] unsigned GetPointerBitCount() const override
|
||||||
@@ -444,6 +451,12 @@ namespace
|
|||||||
void IncBlockPos(const XBlock& block, const size_t size)
|
void IncBlockPos(const XBlock& block, const size_t size)
|
||||||
{
|
{
|
||||||
m_block_offsets[block.m_index] += size;
|
m_block_offsets[block.m_index] += size;
|
||||||
|
|
||||||
|
if (m_has_progress_callback)
|
||||||
|
{
|
||||||
|
m_progress_current_size += size;
|
||||||
|
m_progress_callback->OnProgress(m_progress_current_size, m_progress_total_size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Align(const XBlock& block, const unsigned align)
|
void Align(const XBlock& block, const unsigned align)
|
||||||
@@ -455,6 +468,16 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] size_t CalculateTotalSize() const
|
||||||
|
{
|
||||||
|
size_t result = 0uz;
|
||||||
|
|
||||||
|
for (const auto& block : m_blocks)
|
||||||
|
result += block->m_buffer_size;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<XBlock*>& m_blocks;
|
std::vector<XBlock*>& m_blocks;
|
||||||
std::unique_ptr<size_t[]> m_block_offsets;
|
std::unique_ptr<size_t[]> m_block_offsets;
|
||||||
|
|
||||||
@@ -475,6 +498,11 @@ namespace
|
|||||||
// These lookups map a block offset to a pointer in case of a platform mismatch
|
// These lookups map a block offset to a pointer in case of a platform mismatch
|
||||||
std::unordered_map<uintptr_t, void*> m_pointer_redirect_lookup;
|
std::unordered_map<uintptr_t, void*> m_pointer_redirect_lookup;
|
||||||
std::unordered_map<uintptr_t, void*> m_alias_redirect_lookup;
|
std::unordered_map<uintptr_t, void*> m_alias_redirect_lookup;
|
||||||
|
|
||||||
|
bool m_has_progress_callback;
|
||||||
|
std::unique_ptr<ProgressCallback> m_progress_callback;
|
||||||
|
size_t m_progress_current_size;
|
||||||
|
size_t m_progress_total_size;
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@@ -483,7 +511,8 @@ std::unique_ptr<ZoneInputStream> ZoneInputStream::Create(const unsigned pointerB
|
|||||||
std::vector<XBlock*>& blocks,
|
std::vector<XBlock*>& blocks,
|
||||||
const block_t insertBlock,
|
const block_t insertBlock,
|
||||||
ILoadingStream& stream,
|
ILoadingStream& stream,
|
||||||
MemoryManager& memory)
|
MemoryManager& memory,
|
||||||
|
std::optional<std::unique_ptr<ProgressCallback>> progressCallback)
|
||||||
{
|
{
|
||||||
return std::make_unique<XBlockInputStream>(pointerBitCount, blockBitCount, blocks, insertBlock, stream, memory);
|
return std::make_unique<XBlockInputStream>(pointerBitCount, blockBitCount, blocks, insertBlock, stream, memory, std::move(progressCallback));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "Loading/Exception/InvalidLookupPositionException.h"
|
#include "Loading/Exception/InvalidLookupPositionException.h"
|
||||||
#include "Loading/ILoadingStream.h"
|
#include "Loading/ILoadingStream.h"
|
||||||
#include "Utils/MemoryManager.h"
|
#include "Utils/MemoryManager.h"
|
||||||
|
#include "Utils/ProgressCallback.h"
|
||||||
#include "Zone/Stream/IZoneStream.h"
|
#include "Zone/Stream/IZoneStream.h"
|
||||||
#include "Zone/XBlock.h"
|
#include "Zone/XBlock.h"
|
||||||
|
|
||||||
@@ -10,6 +11,7 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -238,6 +240,11 @@ public:
|
|||||||
virtual void DebugOffsets(size_t assetIndex) const = 0;
|
virtual void DebugOffsets(size_t assetIndex) const = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static std::unique_ptr<ZoneInputStream> Create(
|
static std::unique_ptr<ZoneInputStream> Create(unsigned pointerBitCount,
|
||||||
unsigned pointerBitCount, unsigned blockBitCount, std::vector<XBlock*>& blocks, block_t insertBlock, ILoadingStream& stream, MemoryManager& memory);
|
unsigned blockBitCount,
|
||||||
|
std::vector<XBlock*>& blocks,
|
||||||
|
block_t insertBlock,
|
||||||
|
ILoadingStream& stream,
|
||||||
|
MemoryManager& memory,
|
||||||
|
std::optional<std::unique_ptr<ProgressCallback>> progressCallback);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,11 +7,11 @@
|
|||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
result::Expected<std::unique_ptr<Zone>, std::string> ZoneLoading::LoadZone(const std::string& path)
|
result::Expected<std::unique_ptr<Zone>, std::string> ZoneLoading::LoadZone(const std::string& path,
|
||||||
|
std::optional<std::unique_ptr<ProgressCallback>> progressCallback)
|
||||||
{
|
{
|
||||||
auto zoneName = fs::path(path).filename().replace_extension().string();
|
auto zoneName = fs::path(path).filename().replace_extension().string();
|
||||||
std::ifstream file(path, std::fstream::in | std::fstream::binary);
|
std::ifstream file(path, std::fstream::in | std::fstream::binary);
|
||||||
@@ -28,7 +28,7 @@ result::Expected<std::unique_ptr<Zone>, std::string> ZoneLoading::LoadZone(const
|
|||||||
for (auto game = 0u; game < static_cast<unsigned>(GameId::COUNT); game++)
|
for (auto game = 0u; game < static_cast<unsigned>(GameId::COUNT); game++)
|
||||||
{
|
{
|
||||||
const auto* factory = IZoneLoaderFactory::GetZoneLoaderFactoryForGame(static_cast<GameId>(game));
|
const auto* factory = IZoneLoaderFactory::GetZoneLoaderFactoryForGame(static_cast<GameId>(game));
|
||||||
zoneLoader = factory->CreateLoaderForHeader(header, zoneName);
|
zoneLoader = factory->CreateLoaderForHeader(header, zoneName, std::move(progressCallback));
|
||||||
|
|
||||||
if (zoneLoader)
|
if (zoneLoader)
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Utils/ProgressCallback.h"
|
||||||
#include "Utils/Result.h"
|
#include "Utils/Result.h"
|
||||||
#include "Zone/Zone.h"
|
#include "Zone/Zone.h"
|
||||||
|
|
||||||
@@ -8,5 +9,6 @@
|
|||||||
class ZoneLoading
|
class ZoneLoading
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static result::Expected<std::unique_ptr<Zone>, std::string> LoadZone(const std::string& path);
|
static result::Expected<std::unique_ptr<Zone>, std::string> LoadZone(const std::string& path,
|
||||||
|
std::optional<std::unique_ptr<ProgressCallback>> progressCallback);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user