mirror of
https://github.com/ineedbots/cod2m.git
synced 2025-04-20 00:12:52 +00:00
Overall cleanup
This commit is contained in:
parent
9564dcec13
commit
b35949ddaf
141
src/Components/Loader.cpp
Normal file
141
src/Components/Loader.cpp
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
|
#include "Modules/Flags.hpp"
|
||||||
|
#include "Modules/HelloWorld.hpp"
|
||||||
|
#include "Modules/Logger.hpp"
|
||||||
|
|
||||||
|
namespace Components
|
||||||
|
{
|
||||||
|
bool Loader::Pregame = true;
|
||||||
|
bool Loader::Postgame = false;
|
||||||
|
bool Loader::Uninitializing = false;
|
||||||
|
std::vector<Component*> Loader::Components;
|
||||||
|
|
||||||
|
bool Loader::IsPregame()
|
||||||
|
{
|
||||||
|
return Loader::Pregame;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Loader::IsPostgame()
|
||||||
|
{
|
||||||
|
return Loader::Postgame;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Loader::IsUninitializing()
|
||||||
|
{
|
||||||
|
return Loader::Uninitializing;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Loader::Initialize(GAMEEXE GameType)
|
||||||
|
{
|
||||||
|
Loader::Pregame = true;
|
||||||
|
Loader::Postgame = false;
|
||||||
|
Loader::Uninitializing = false;
|
||||||
|
Utils::Memory::GetAllocator()->clear();
|
||||||
|
|
||||||
|
Game::Init(GameType);
|
||||||
|
Loader::Register(new Flags());
|
||||||
|
Loader::Register(new HelloWorld());
|
||||||
|
Loader::Register(new Logger());
|
||||||
|
|
||||||
|
Loader::Pregame = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Loader::Uninitialize()
|
||||||
|
{
|
||||||
|
Loader::Uninitializing = true;
|
||||||
|
Loader::PreDestroyNoPostGame();
|
||||||
|
|
||||||
|
std::reverse(Loader::Components.begin(), Loader::Components.end());
|
||||||
|
for (auto component : Loader::Components)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (!Loader::IsPerformingUnitTests())
|
||||||
|
{
|
||||||
|
Logger::Print("Unregistering component: %s\n", component->getName().data());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
delete component;
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader::Components.clear();
|
||||||
|
Utils::Memory::GetAllocator()->clear();
|
||||||
|
Loader::Uninitializing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Loader::PreDestroy()
|
||||||
|
{
|
||||||
|
if (!Loader::Postgame)
|
||||||
|
{
|
||||||
|
Loader::Postgame = true;
|
||||||
|
|
||||||
|
auto components = Loader::Components;
|
||||||
|
|
||||||
|
std::reverse(components.begin(), components.end());
|
||||||
|
for (auto component : components)
|
||||||
|
{
|
||||||
|
component->preDestroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Loader::PreDestroyNoPostGame()
|
||||||
|
{
|
||||||
|
if (!Loader::Postgame)
|
||||||
|
{
|
||||||
|
auto components = Loader::Components;
|
||||||
|
|
||||||
|
std::reverse(components.begin(), components.end());
|
||||||
|
for (auto component : components)
|
||||||
|
{
|
||||||
|
component->preDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader::Postgame = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Loader::PerformUnitTests()
|
||||||
|
{
|
||||||
|
bool result = true;
|
||||||
|
|
||||||
|
Logger::Print("Performing unit tests for components:\n");
|
||||||
|
|
||||||
|
for (auto component : Loader::Components)
|
||||||
|
{
|
||||||
|
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
|
||||||
|
Logger::Print("Testing '%s'...\n", component->getName().data());
|
||||||
|
#endif
|
||||||
|
auto startTime = std::chrono::high_resolution_clock::now();
|
||||||
|
bool testRes = component->unitTest();
|
||||||
|
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - startTime).count();
|
||||||
|
Logger::Print("Test done (%llims): %s\n\n", duration, (testRes ? "Success" : "Error"));
|
||||||
|
result &= testRes;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Loader::IsPerformingUnitTests()
|
||||||
|
{
|
||||||
|
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
|
||||||
|
return Flags::HasFlag("tests");
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Loader::Register(Component* component)
|
||||||
|
{
|
||||||
|
if (component)
|
||||||
|
{
|
||||||
|
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
|
||||||
|
if (!Loader::IsPerformingUnitTests())
|
||||||
|
{
|
||||||
|
Logger::Print("Component registered: %s\n", component->getName().data());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
Loader::Components.push_back(component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
62
src/Components/Loader.hpp
Normal file
62
src/Components/Loader.hpp
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Components
|
||||||
|
{
|
||||||
|
class Component
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Component() {};
|
||||||
|
virtual ~Component() {};
|
||||||
|
|
||||||
|
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
|
||||||
|
virtual std::string getName()
|
||||||
|
{
|
||||||
|
std::string name = typeid(*this).name();
|
||||||
|
Utils::String::Replace(name, "class Components::", "");
|
||||||
|
return name;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// It's illegal to spawn threads in DLLMain, and apparently it causes problems if they are destroyed there as well.
|
||||||
|
// This method is called before DLLMain (if possible) and should to destroy threads.
|
||||||
|
// It's not 100% guaranteed that it's called outside DLLMain, as it depends on the game, but it's 100% guaranteed, that it is called at all.
|
||||||
|
virtual void preDestroy() {};
|
||||||
|
virtual bool unitTest() { return true; }; // Unit testing entry
|
||||||
|
};
|
||||||
|
|
||||||
|
class Loader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void Initialize(GAMEEXE);
|
||||||
|
static void Uninitialize();
|
||||||
|
static void PreDestroy();
|
||||||
|
static void PreDestroyNoPostGame();
|
||||||
|
static bool PerformUnitTests();
|
||||||
|
static bool IsPerformingUnitTests();
|
||||||
|
static void Register(Component* component);
|
||||||
|
|
||||||
|
static bool IsPregame();
|
||||||
|
static bool IsPostgame();
|
||||||
|
static bool IsUninitializing();
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static T* GetInstance()
|
||||||
|
{
|
||||||
|
for (auto& component : Loader::Components)
|
||||||
|
{
|
||||||
|
if (typeid(*component) == typeid(T))
|
||||||
|
{
|
||||||
|
return reinterpret_cast<T*>(component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool Pregame;
|
||||||
|
static bool Postgame;
|
||||||
|
static bool Uninitializing;
|
||||||
|
static std::vector<Component*> Components;
|
||||||
|
};
|
||||||
|
}
|
56
src/Components/Modules/Flags.cpp
Normal file
56
src/Components/Modules/Flags.cpp
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#include "STDInclude.hpp"
|
||||||
|
#include "Flags.hpp"
|
||||||
|
|
||||||
|
namespace Components
|
||||||
|
{
|
||||||
|
std::vector<std::string> Flags::EnabledFlags;
|
||||||
|
|
||||||
|
bool Flags::HasFlag(const std::string& flag)
|
||||||
|
{
|
||||||
|
Flags::ParseFlags();
|
||||||
|
|
||||||
|
for (auto entry : Flags::EnabledFlags)
|
||||||
|
{
|
||||||
|
if (Utils::String::ToLower(entry) == Utils::String::ToLower(flag))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Flags::ParseFlags()
|
||||||
|
{
|
||||||
|
static bool flagsParsed = false;
|
||||||
|
if (flagsParsed) return;
|
||||||
|
flagsParsed = true;
|
||||||
|
|
||||||
|
int numArgs;
|
||||||
|
LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &numArgs);
|
||||||
|
|
||||||
|
if (argv)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < numArgs; ++i)
|
||||||
|
{
|
||||||
|
std::wstring wFlag(argv[i]);
|
||||||
|
if (wFlag[0] == L'-')
|
||||||
|
{
|
||||||
|
Flags::EnabledFlags.push_back(std::string(++wFlag.begin(), wFlag.end()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalFree(argv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Flags::Flags()
|
||||||
|
{
|
||||||
|
Flags::ParseFlags();
|
||||||
|
}
|
||||||
|
|
||||||
|
Flags::~Flags()
|
||||||
|
{
|
||||||
|
Flags::EnabledFlags.clear();
|
||||||
|
}
|
||||||
|
}
|
18
src/Components/Modules/Flags.hpp
Normal file
18
src/Components/Modules/Flags.hpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Components
|
||||||
|
{
|
||||||
|
class Flags : public Component
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Flags();
|
||||||
|
~Flags();
|
||||||
|
|
||||||
|
static bool HasFlag(const std::string& flag);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::vector<std::string> EnabledFlags;
|
||||||
|
|
||||||
|
static void ParseFlags();
|
||||||
|
};
|
||||||
|
}
|
13
src/Components/Modules/HelloWorld.cpp
Normal file
13
src/Components/Modules/HelloWorld.cpp
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#include "STDInclude.hpp"
|
||||||
|
#include "HelloWorld.hpp"
|
||||||
|
|
||||||
|
namespace Components
|
||||||
|
{
|
||||||
|
HelloWorld::HelloWorld()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
HelloWorld::~HelloWorld()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
11
src/Components/Modules/HelloWorld.hpp
Normal file
11
src/Components/Modules/HelloWorld.hpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Components
|
||||||
|
{
|
||||||
|
class HelloWorld : public Component
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HelloWorld();
|
||||||
|
~HelloWorld();
|
||||||
|
};
|
||||||
|
}
|
96
src/Components/Modules/Logger.cpp
Normal file
96
src/Components/Modules/Logger.cpp
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
#include "STDInclude.hpp"
|
||||||
|
#include "Logger.hpp"
|
||||||
|
#include "Flags.hpp"
|
||||||
|
|
||||||
|
namespace Components
|
||||||
|
{
|
||||||
|
bool Logger::IsConsoleReady()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::PrintStub(int channel, const char* message, ...)
|
||||||
|
{
|
||||||
|
return Logger::MessagePrint(channel, Logger::Format(&message));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::Print(const char* message, ...)
|
||||||
|
{
|
||||||
|
return Logger::MessagePrint(0, Logger::Format(&message));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::Print(int channel, const char* message, ...)
|
||||||
|
{
|
||||||
|
return Logger::MessagePrint(channel, Logger::Format(&message));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::MessagePrint([[maybe_unused]] int channel, [[maybe_unused]] const std::string& message)
|
||||||
|
{
|
||||||
|
if (Flags::HasFlag("stdout") || Loader::IsPerformingUnitTests())
|
||||||
|
{
|
||||||
|
printf("%s", message.data());
|
||||||
|
fflush(stdout);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*if (!Logger::IsConsoleReady())
|
||||||
|
{
|
||||||
|
OutputDebugStringA(message.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Game::Sys_IsMainThread())
|
||||||
|
{
|
||||||
|
Logger::EnqueueMessage(message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Game::Com_PrintMessage(channel, message.data(), 0);
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::ErrorPrint([[maybe_unused]] int error, [[maybe_unused]] const std::string& message)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (IsDebuggerPresent()) __debugbreak();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//Game::Com_Error(error, "%s", message.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::Error(int error, const char* message, ...)
|
||||||
|
{
|
||||||
|
return Logger::ErrorPrint(error, Logger::Format(&message));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::Error(const char* message, ...)
|
||||||
|
{
|
||||||
|
return Logger::ErrorPrint(0, Logger::Format(&message));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::SoftError(const char* message, ...)
|
||||||
|
{
|
||||||
|
return Logger::ErrorPrint(2, Logger::Format(&message));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Logger::Format(const char** message)
|
||||||
|
{
|
||||||
|
const size_t bufferSize = 0x10000;
|
||||||
|
Utils::Memory::Allocator allocator;
|
||||||
|
char* buffer = allocator.allocateArray<char>(bufferSize);
|
||||||
|
|
||||||
|
va_list ap = reinterpret_cast<char*>(const_cast<char**>(&message[1]));
|
||||||
|
//va_start(ap, *message);
|
||||||
|
_vsnprintf_s(buffer, bufferSize, bufferSize, *message, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::Logger()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::~Logger()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
26
src/Components/Modules/Logger.hpp
Normal file
26
src/Components/Modules/Logger.hpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Components
|
||||||
|
{
|
||||||
|
class Logger : public Component
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Logger();
|
||||||
|
~Logger();
|
||||||
|
|
||||||
|
static void MessagePrint(int channel, const std::string& message);
|
||||||
|
static void Print(int channel, const char* message, ...);
|
||||||
|
static void Print(const char* message, ...);
|
||||||
|
static void ErrorPrint(int error, const std::string& message);
|
||||||
|
static void Error(const char* message, ...);
|
||||||
|
static void Error(int error, const char* message, ...);
|
||||||
|
static void SoftError(const char* message, ...);
|
||||||
|
static bool IsConsoleReady();
|
||||||
|
|
||||||
|
static void PrintStub(int channel, const char* message, ...);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
static std::string Format(const char** message);
|
||||||
|
};
|
||||||
|
}
|
10
src/Game/Game.cpp
Normal file
10
src/Game/Game.cpp
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
|
namespace Game
|
||||||
|
{
|
||||||
|
void Init(GAMEEXE)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
6
src/Game/Game.hpp
Normal file
6
src/Game/Game.hpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Game
|
||||||
|
{
|
||||||
|
void Init(GAMEEXE);
|
||||||
|
}
|
@ -1,9 +0,0 @@
|
|||||||
#include "STDInclude.hpp"
|
|
||||||
|
|
||||||
namespace MP
|
|
||||||
{
|
|
||||||
void PatchT4()
|
|
||||||
{
|
|
||||||
MessageBoxA(nullptr, "MP", "DEBUG", 0);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
namespace MP
|
|
||||||
{
|
|
||||||
void PatchT4();
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
#include "STDInclude.hpp"
|
|
5
src/Game/Structs.hpp
Normal file
5
src/Game/Structs.hpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Game
|
||||||
|
{
|
||||||
|
}
|
@ -31,7 +31,7 @@ namespace Main
|
|||||||
// detect which executable's patches to apply
|
// detect which executable's patches to apply
|
||||||
DWORD dataStrData = Utils::Hook::Get<DWORD>(0x59B69C);
|
DWORD dataStrData = Utils::Hook::Get<DWORD>(0x59B69C);
|
||||||
if (dataStrData == 0x6C6C6143)
|
if (dataStrData == 0x6C6C6143)
|
||||||
MP::PatchT4();
|
Components::Loader::Initialize(GAMEEXE::MP);
|
||||||
|
|
||||||
hModule = GetModuleHandle(NULL);
|
hModule = GetModuleHandle(NULL);
|
||||||
PIMAGE_DOS_HEADER header = (PIMAGE_DOS_HEADER)hModule;
|
PIMAGE_DOS_HEADER header = (PIMAGE_DOS_HEADER)hModule;
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include <Psapi.h>
|
#include <Psapi.h>
|
||||||
#include <tlhelp32.h>
|
#include <tlhelp32.h>
|
||||||
#include <Shlwapi.h>
|
#include <Shlwapi.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
#pragma warning(disable: 4091)
|
#pragma warning(disable: 4091)
|
||||||
@ -81,9 +82,19 @@ template <size_t S> class Sizer { };
|
|||||||
|
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
|
|
||||||
#include "Utils/Hooking.hpp"
|
enum GAMEEXE
|
||||||
|
{
|
||||||
|
MP
|
||||||
|
};
|
||||||
|
|
||||||
#include "Game/MP.hpp"
|
#include "Utils/Hooking.hpp"
|
||||||
|
#include "Utils/Memory.hpp"
|
||||||
|
#include "Utils/String.hpp"
|
||||||
|
|
||||||
|
#include "Game/Structs.hpp"
|
||||||
|
#include "Game/Game.hpp"
|
||||||
|
|
||||||
|
#include "Components/Loader.hpp"
|
||||||
|
|
||||||
// Libraries
|
// Libraries
|
||||||
#pragma comment(lib, "Winmm.lib")
|
#pragma comment(lib, "Winmm.lib")
|
||||||
|
105
src/Utils/Memory.cpp
Normal file
105
src/Utils/Memory.cpp
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
|
namespace Utils
|
||||||
|
{
|
||||||
|
Utils::Memory::Allocator Memory::MemAllocator;
|
||||||
|
|
||||||
|
void* Memory::AllocateAlign(size_t length, size_t alignment)
|
||||||
|
{
|
||||||
|
void* data = _aligned_malloc(length, alignment);
|
||||||
|
assert(data != nullptr);
|
||||||
|
if (data) ZeroMemory(data, length);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* Memory::Allocate(size_t length)
|
||||||
|
{
|
||||||
|
void* data = calloc(length, 1);
|
||||||
|
assert(data != nullptr);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* Memory::DuplicateString(const std::string& string)
|
||||||
|
{
|
||||||
|
char* newString = Memory::AllocateArray<char>(string.size() + 1);
|
||||||
|
std::memcpy(newString, string.data(), string.size());
|
||||||
|
return newString;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Memory::Free(void* data)
|
||||||
|
{
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Memory::Free(const void* data)
|
||||||
|
{
|
||||||
|
Memory::Free(const_cast<void*>(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Memory::FreeAlign(void* data)
|
||||||
|
{
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
_aligned_free(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Memory::FreeAlign(const void* data)
|
||||||
|
{
|
||||||
|
Memory::FreeAlign(const_cast<void*>(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Complementary function for memset, which checks if memory is filled with a char
|
||||||
|
bool Memory::IsSet(void* mem, char chr, size_t length)
|
||||||
|
{
|
||||||
|
char* memArr = reinterpret_cast<char*>(mem);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < length; ++i)
|
||||||
|
{
|
||||||
|
if (memArr[i] != chr)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Memory::IsBadReadPtr(const void* ptr)
|
||||||
|
{
|
||||||
|
MEMORY_BASIC_INFORMATION mbi = { nullptr };
|
||||||
|
if (VirtualQuery(ptr, &mbi, sizeof(mbi)))
|
||||||
|
{
|
||||||
|
DWORD mask = (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY);
|
||||||
|
bool b = !(mbi.Protect & mask);
|
||||||
|
// check the page is not a guard page
|
||||||
|
if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) b = true;
|
||||||
|
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Memory::IsBadCodePtr(const void* ptr)
|
||||||
|
{
|
||||||
|
MEMORY_BASIC_INFORMATION mbi = { nullptr };
|
||||||
|
if (VirtualQuery(ptr, &mbi, sizeof(mbi)))
|
||||||
|
{
|
||||||
|
DWORD mask = (PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY);
|
||||||
|
bool b = !(mbi.Protect & mask);
|
||||||
|
// check the page is not a guard page
|
||||||
|
if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) b = true;
|
||||||
|
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils::Memory::Allocator* Memory::GetAllocator()
|
||||||
|
{
|
||||||
|
return &Memory::MemAllocator;
|
||||||
|
}
|
||||||
|
}
|
163
src/Utils/Memory.hpp
Normal file
163
src/Utils/Memory.hpp
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Utils
|
||||||
|
{
|
||||||
|
class Memory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
class Allocator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef void(*FreeCallback)(void*);
|
||||||
|
|
||||||
|
Allocator()
|
||||||
|
{
|
||||||
|
this->pool.clear();
|
||||||
|
this->refMemory.clear();
|
||||||
|
}
|
||||||
|
~Allocator()
|
||||||
|
{
|
||||||
|
this->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> _(this->mutex);
|
||||||
|
|
||||||
|
for (auto i = this->refMemory.begin(); i != this->refMemory.end(); ++i)
|
||||||
|
{
|
||||||
|
if (i->first && i->second)
|
||||||
|
{
|
||||||
|
i->second(i->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->refMemory.clear();
|
||||||
|
|
||||||
|
for (auto& data : this->pool)
|
||||||
|
{
|
||||||
|
Memory::Free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->pool.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(void* data)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> _(this->mutex);
|
||||||
|
|
||||||
|
auto i = this->refMemory.find(data);
|
||||||
|
if (i != this->refMemory.end())
|
||||||
|
{
|
||||||
|
i->second(i->first);
|
||||||
|
this->refMemory.erase(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto j = std::find(this->pool.begin(), this->pool.end(), data);
|
||||||
|
if (j != this->pool.end())
|
||||||
|
{
|
||||||
|
Memory::Free(data);
|
||||||
|
this->pool.erase(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(const void* data)
|
||||||
|
{
|
||||||
|
this->free(const_cast<void*>(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
void reference(void* memory, FreeCallback callback)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> _(this->mutex);
|
||||||
|
|
||||||
|
this->refMemory[memory] = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* allocate(size_t length)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> _(this->mutex);
|
||||||
|
|
||||||
|
void* data = Memory::Allocate(length);
|
||||||
|
this->pool.push_back(data);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
template <typename T> inline T* allocate()
|
||||||
|
{
|
||||||
|
return this->allocateArray<T>(1);
|
||||||
|
}
|
||||||
|
template <typename T> inline T* allocateArray(size_t count = 1)
|
||||||
|
{
|
||||||
|
return static_cast<T*>(this->allocate(count * sizeof(T)));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty()
|
||||||
|
{
|
||||||
|
return (this->pool.empty() && this->refMemory.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
char* duplicateString(const std::string& string)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> _(this->mutex);
|
||||||
|
|
||||||
|
char* data = Memory::DuplicateString(string);
|
||||||
|
this->pool.push_back(data);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isPointerMapped(void* ptr)
|
||||||
|
{
|
||||||
|
return this->ptrMap.find(ptr) != this->ptrMap.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> T* getPointer(void* oldPtr)
|
||||||
|
{
|
||||||
|
if (this->isPointerMapped(oldPtr))
|
||||||
|
{
|
||||||
|
return reinterpret_cast<T*>(this->ptrMap[oldPtr]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mapPointer(void* oldPtr, void* newPtr)
|
||||||
|
{
|
||||||
|
this->ptrMap[oldPtr] = newPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::mutex mutex;
|
||||||
|
std::vector<void*> pool;
|
||||||
|
std::unordered_map<void*, void*> ptrMap;
|
||||||
|
std::unordered_map<void*, FreeCallback> refMemory;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void* AllocateAlign(size_t length, size_t alignment);
|
||||||
|
static void* Allocate(size_t length);
|
||||||
|
template <typename T> static inline T* Allocate()
|
||||||
|
{
|
||||||
|
return AllocateArray<T>(1);
|
||||||
|
}
|
||||||
|
template <typename T> static inline T* AllocateArray(size_t count = 1)
|
||||||
|
{
|
||||||
|
return static_cast<T*>(Allocate(count * sizeof(T)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static char* DuplicateString(const std::string& string);
|
||||||
|
|
||||||
|
static void Free(void* data);
|
||||||
|
static void Free(const void* data);
|
||||||
|
|
||||||
|
static void FreeAlign(void* data);
|
||||||
|
static void FreeAlign(const void* data);
|
||||||
|
|
||||||
|
static bool IsSet(void* mem, char chr, size_t length);
|
||||||
|
|
||||||
|
static bool IsBadReadPtr(const void* ptr);
|
||||||
|
static bool IsBadCodePtr(const void* ptr);
|
||||||
|
|
||||||
|
static Utils::Memory::Allocator* GetAllocator();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static Utils::Memory::Allocator MemAllocator;
|
||||||
|
};
|
||||||
|
}
|
208
src/Utils/String.cpp
Normal file
208
src/Utils/String.cpp
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
|
namespace Utils
|
||||||
|
{
|
||||||
|
namespace String
|
||||||
|
{
|
||||||
|
const char *VA(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
static VAProvider<4, 100> globalProvider;
|
||||||
|
static thread_local VAProvider<8, 256> provider;
|
||||||
|
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
|
||||||
|
const char* result;
|
||||||
|
if (Components::Loader::IsUninitializing()) result = globalProvider.get(fmt, ap);
|
||||||
|
else result = provider.get(fmt, ap);
|
||||||
|
|
||||||
|
va_end(ap);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ToLower(std::string input)
|
||||||
|
{
|
||||||
|
std::transform(input.begin(), input.end(), input.begin(), ::tolower);
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ToUpper(std::string input)
|
||||||
|
{
|
||||||
|
std::transform(input.begin(), input.end(), input.begin(), ::toupper);
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string DumpHex(const std::string& data, const std::string& separator)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < data.size(); ++i)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
result.append(separator);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.append(Utils::String::VA("%02X", data[i] & 0xFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string XOR(std::string str, char value)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < str.size(); ++i)
|
||||||
|
{
|
||||||
|
str[i] ^= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> Explode(const std::string& str, char delim)
|
||||||
|
{
|
||||||
|
std::vector<std::string> result;
|
||||||
|
std::istringstream iss(str);
|
||||||
|
|
||||||
|
for (std::string token; std::getline(iss, token, delim);)
|
||||||
|
{
|
||||||
|
std::string _entry = std::move(token);
|
||||||
|
|
||||||
|
// Remove trailing 0x0 bytes
|
||||||
|
while (_entry.size() && !_entry.back())
|
||||||
|
{
|
||||||
|
_entry = _entry.substr(0, _entry.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push_back(_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Replace(std::string &string, const std::string& find, const std::string& replace)
|
||||||
|
{
|
||||||
|
size_t nPos = 0;
|
||||||
|
|
||||||
|
while ((nPos = string.find(find, nPos)) != std::string::npos)
|
||||||
|
{
|
||||||
|
string = string.replace(nPos, find.length(), replace);
|
||||||
|
nPos += replace.length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StartsWith(const std::string& haystack, const std::string& needle)
|
||||||
|
{
|
||||||
|
return (haystack.size() >= needle.size() && haystack.substr(0, needle.size()) == needle);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EndsWith(const std::string& haystack, const std::string& needle)
|
||||||
|
{
|
||||||
|
return (haystack.size() >= needle.size() && haystack.substr(haystack.size() - needle.size()) == needle);
|
||||||
|
}
|
||||||
|
|
||||||
|
int IsSpace(int c)
|
||||||
|
{
|
||||||
|
if (c < -1) return 0;
|
||||||
|
return _isspace_l(c, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim from start
|
||||||
|
std::string <rim(std::string &s)
|
||||||
|
{
|
||||||
|
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int val)
|
||||||
|
{
|
||||||
|
return !IsSpace(val);
|
||||||
|
}));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim from end
|
||||||
|
std::string &RTrim(std::string &s)
|
||||||
|
{
|
||||||
|
s.erase(std::find_if(s.rbegin(), s.rend(), [](int val)
|
||||||
|
{
|
||||||
|
return !IsSpace(val);
|
||||||
|
}).base(), s.end());
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim from both ends
|
||||||
|
std::string &Trim(std::string &s)
|
||||||
|
{
|
||||||
|
return LTrim(RTrim(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string FormatTimeSpan(int milliseconds)
|
||||||
|
{
|
||||||
|
int secondsTotal = milliseconds / 1000;
|
||||||
|
int seconds = secondsTotal % 60;
|
||||||
|
int minutesTotal = secondsTotal / 60;
|
||||||
|
int minutes = minutesTotal % 60;
|
||||||
|
int hoursTotal = minutesTotal / 60;
|
||||||
|
|
||||||
|
return Utils::String::VA("%02d:%02d:%02d", hoursTotal, minutes, seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string FormatBandwidth(size_t bytes, int milliseconds)
|
||||||
|
{
|
||||||
|
static const char* sizes[] =
|
||||||
|
{
|
||||||
|
"B",
|
||||||
|
"KB",
|
||||||
|
"MB",
|
||||||
|
"GB",
|
||||||
|
"TB"
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!milliseconds) return "0.00 B/s";
|
||||||
|
|
||||||
|
double bytesPerSecond = (1000.0 / milliseconds) * bytes;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; bytesPerSecond > 1000 && i < ARRAYSIZE(sizes); ++i) // 1024 or 1000?
|
||||||
|
{
|
||||||
|
bytesPerSecond /= 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Utils::String::VA("%.2f %s/s", static_cast<float>(bytesPerSecond), sizes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_BASE64
|
||||||
|
// Encodes a given string in Base64
|
||||||
|
std::string EncodeBase64(const char* input, const unsigned long inputSize)
|
||||||
|
{
|
||||||
|
unsigned long outlen = long(inputSize + (inputSize / 3.0) + 16);
|
||||||
|
unsigned char* outbuf = new unsigned char[outlen]; //Reserve output memory
|
||||||
|
base64_encode(reinterpret_cast<unsigned char*>(const_cast<char*>(input)), inputSize, outbuf, &outlen);
|
||||||
|
std::string ret(reinterpret_cast<char*>(outbuf), outlen);
|
||||||
|
delete[] outbuf;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encodes a given string in Base64
|
||||||
|
std::string EncodeBase64(const std::string& input)
|
||||||
|
{
|
||||||
|
return EncodeBase64(input.data(), input.size());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_BASE128
|
||||||
|
// Encodes a given string in Base128
|
||||||
|
std::string EncodeBase128(const std::string& input)
|
||||||
|
{
|
||||||
|
base128 encoder;
|
||||||
|
|
||||||
|
void* inbuffer = const_cast<char*>(input.data());
|
||||||
|
char* buffer = encoder.encode(inbuffer, input.size());
|
||||||
|
/*
|
||||||
|
Interesting to see that the buffer returned by the encoder is not a standalone string copy
|
||||||
|
but instead is a pointer to the internal "encoded" field of the encoder. So if you deinitialize
|
||||||
|
the encoder that string will probably become garbage.
|
||||||
|
*/
|
||||||
|
std::string retval(buffer);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
100
src/Utils/String.hpp
Normal file
100
src/Utils/String.hpp
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Utils
|
||||||
|
{
|
||||||
|
namespace String
|
||||||
|
{
|
||||||
|
template <size_t Buffers, size_t MinBufferSize>
|
||||||
|
class VAProvider
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static_assert(Buffers != 0 && MinBufferSize != 0, "Buffers and MinBufferSize mustn't be 0");
|
||||||
|
|
||||||
|
VAProvider() : currentBuffer(0) {}
|
||||||
|
~VAProvider() {}
|
||||||
|
|
||||||
|
const char* get(const char* format, va_list ap)
|
||||||
|
{
|
||||||
|
++this->currentBuffer %= ARRAYSIZE(this->stringPool);
|
||||||
|
auto entry = &this->stringPool[this->currentBuffer];
|
||||||
|
|
||||||
|
if (!entry->size || !entry->buffer)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("String pool not initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
int res = vsnprintf_s(entry->buffer, entry->size, _TRUNCATE, format, ap);
|
||||||
|
if (res > 0) break; // Success
|
||||||
|
if (res == 0) return ""; // Error
|
||||||
|
|
||||||
|
entry->doubleSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
return entry->buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
class Entry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Entry(size_t _size = MinBufferSize) : size(_size), buffer(nullptr)
|
||||||
|
{
|
||||||
|
if (this->size < MinBufferSize) this->size = MinBufferSize;
|
||||||
|
this->allocate();
|
||||||
|
}
|
||||||
|
|
||||||
|
~Entry()
|
||||||
|
{
|
||||||
|
if (this->buffer) Utils::Memory::GetAllocator()->free(this->buffer);
|
||||||
|
this->size = 0;
|
||||||
|
this->buffer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void allocate()
|
||||||
|
{
|
||||||
|
if (this->buffer) Utils::Memory::GetAllocator()->free(this->buffer);
|
||||||
|
this->buffer = Utils::Memory::GetAllocator()->allocateArray<char>(this->size + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void doubleSize()
|
||||||
|
{
|
||||||
|
this->size *= 2;
|
||||||
|
this->allocate();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size;
|
||||||
|
char* buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t currentBuffer;
|
||||||
|
Entry stringPool[Buffers];
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *VA(const char *fmt, ...);
|
||||||
|
|
||||||
|
int IsSpace(int c);
|
||||||
|
std::string ToLower(std::string input);
|
||||||
|
std::string ToUpper(std::string input);
|
||||||
|
bool EndsWith(const std::string& haystack, const std::string& needle);
|
||||||
|
std::vector<std::string> Explode(const std::string& str, char delim);
|
||||||
|
void Replace(std::string &string, const std::string& find, const std::string& replace);
|
||||||
|
bool StartsWith(const std::string& haystack, const std::string& needle);
|
||||||
|
std::string <rim(std::string &s);
|
||||||
|
std::string &RTrim(std::string &s);
|
||||||
|
std::string &Trim(std::string &s);
|
||||||
|
|
||||||
|
std::string FormatTimeSpan(int milliseconds);
|
||||||
|
std::string FormatBandwidth(size_t bytes, int milliseconds);
|
||||||
|
|
||||||
|
std::string DumpHex(const std::string& data, const std::string& separator = " ");
|
||||||
|
|
||||||
|
std::string XOR(const std::string str, char value);
|
||||||
|
|
||||||
|
std::string EncodeBase64(const char* input, const unsigned long inputSize);
|
||||||
|
std::string EncodeBase64(const std::string& input);
|
||||||
|
|
||||||
|
std::string EncodeBase128(const std::string& input);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user