remove the source files of the ingame overlay project, now it's a dependency

This commit is contained in:
otavepto 2024-03-01 20:38:25 +02:00 committed by otavepto
parent 9792545068
commit 4aa0f58199
54 changed files with 0 additions and 37350 deletions

View File

@ -1,87 +0,0 @@
#include "overlay/Base_Hook.h"
#include <algorithm>
#ifdef EMU_OVERLAY
#ifdef STEAM_WIN32
#include "detours/detours.h"
Base_Hook::Base_Hook():
_library(nullptr)
{}
Base_Hook::~Base_Hook()
{
UnhookAll();
}
const char* Base_Hook::get_lib_name() const
{
return "<no_name>";
}
void Base_Hook::BeginHook()
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
}
void Base_Hook::EndHook()
{
DetourTransactionCommit();
}
void Base_Hook::HookFunc(std::pair<void**, void*> hook)
{
if( DetourAttach(hook.first, hook.second) == 0 )
_hooked_funcs.emplace_back(hook);
}
void Base_Hook::UnhookAll()
{
if (_hooked_funcs.size())
{
BeginHook();
std::for_each(_hooked_funcs.begin(), _hooked_funcs.end(), [](std::pair<void**, void*>& hook) {
DetourDetach(hook.first, hook.second);
});
EndHook();
_hooked_funcs.clear();
}
}
#else
Base_Hook::Base_Hook():
_library(nullptr)
{}
Base_Hook::~Base_Hook()
{
}
const char* Base_Hook::get_lib_name() const
{
return "<no_name>";
}
void Base_Hook::BeginHook()
{
}
void Base_Hook::EndHook()
{
}
void Base_Hook::HookFunc(std::pair<void**, void*> hook)
{
}
void Base_Hook::UnhookAll()
{
}
#endif
#endif//EMU_OVERLAY

File diff suppressed because it is too large Load Diff

View File

@ -1,116 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <type_traits>
namespace System {
template<typename Enum>
struct EnableBitMaskOperators
{
static constexpr bool enable = false;
};
template<typename T>
constexpr typename std::underlying_type<T>::type GetEnumValue(T enum_value)
{
return static_cast<typename std::underlying_type<T>::type>(enum_value);
}
}
template<typename Enum>
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type
operator |(Enum lhs, Enum rhs)
{
using underlying = typename std::underlying_type<Enum>::type;
return static_cast<Enum> (
static_cast<underlying>(lhs) |
static_cast<underlying>(rhs)
);
}
template<typename Enum>
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type
operator &(Enum lhs, Enum rhs)
{
using underlying = typename std::underlying_type<Enum>::type;
return static_cast<Enum> (
static_cast<underlying>(lhs) &
static_cast<underlying>(rhs)
);
}
template<typename Enum>
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type
operator ^(Enum lhs, Enum rhs)
{
using underlying = typename std::underlying_type<Enum>::type;
return static_cast<Enum> (
static_cast<underlying>(lhs) ^
static_cast<underlying>(rhs)
);
}
template<typename Enum>
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type
operator ~(Enum lhs)
{
using underlying = typename std::underlying_type<Enum>::type;
return static_cast<Enum> (~static_cast<underlying>(lhs));
}
template<typename Enum>
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type&
operator |=(Enum& lhs, Enum rhs)
{
lhs = lhs | rhs;
return lhs;
}
template<typename Enum>
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type&
operator &=(Enum& lhs, Enum rhs)
{
lhs = lhs & rhs;
return lhs;
}
template<typename Enum>
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type&
operator ^=(Enum& lhs, Enum rhs)
{
lhs = lhs ^ rhs;
return lhs;
}
template<typename Enum>
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, bool>::type
operator !(Enum lhs)
{
using underlying = typename std::underlying_type<Enum>::type;
return !static_cast<underlying>(lhs);
}
#define UTILS_ENABLE_BITMASK_OPERATORS(T) \
template<> \
struct System::EnableBitMaskOperators<T> \
{ \
static constexpr bool enable = true; \
}

View File

@ -1,45 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <cstddef> // size_t
namespace System {
namespace ConstExpr {
template<typename T, size_t N>
constexpr size_t CountOf(T(&)[N])
{
return N;
}
template<typename T, size_t N>
constexpr size_t StrLen(T(&)[N])
{
return N-1;
}
// Sum of all parameter pack sizeof
template <typename... Ts>
constexpr size_t size_of = 0;
template <typename T, typename... Ts>
constexpr size_t size_of<T, Ts...> = sizeof(T) + size_of<Ts...>;
}
}

View File

@ -1,127 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "System_internals.h"
#include "Encoding.hpp"
#include "utfcpp/utf8.h"
#include <string.h>
#include <algorithm>
namespace System {
namespace Encoding {
namespace details {
template<typename T, size_t s = sizeof(typename T::value_type)>
struct string_deducer
{
static std::string convert_string(T const& str) = delete;
static std::wstring convert_wstring(T const& str) = delete;
};
template<typename T>
struct string_deducer<T, 1>
{
static std::string convert_string(T const& str)
{
return std::string(std::begin(str), std::end(str));
}
static std::wstring convert_wstring(std::string const& str)
{
std::wstring r(std::begin(str), std::end(str));
return r;
}
};
template<typename T>
struct string_deducer<T, 2>
{
static std::string convert_string(T const& str)
{
std::string r;
utf8::utf16to8(std::begin(str), std::end(str), std::back_inserter(r));
return r;
}
static std::wstring convert_wstring(std::string const& str)
{
std::wstring r;
utf8::utf8to16(std::begin(str), std::end(str), std::back_inserter(r));
return r;
}
};
template<typename T>
struct string_deducer<T, 4>
{
static std::string convert_string(T const& str)
{
std::string r;
utf8::utf32to8(std::begin(str), std::end(str), std::back_inserter(r));
return r;
}
static std::wstring convert_wstring(std::string const& str)
{
std::wstring r;
utf8::utf8to32(std::begin(str), std::end(str), std::back_inserter(r));
return r;
}
};
}
std::wstring Utf8ToWChar(std::string const& str)
{
return details::string_deducer<std::wstring>::convert_wstring(str);
}
std::u16string Utf8ToUtf16(std::string const& str)
{
return utf8::utf8to16(str);
}
std::u32string Utf8ToUtf32(std::string const& str)
{
return utf8::utf8to32(str);
}
std::string WCharToUtf8(std::wstring const& str)
{
return details::string_deducer<std::wstring>::convert_string(str);
}
std::string Utf16ToUtf8(std::u16string const& str)
{
return utf8::utf16to8(str);
}
std::string Utf32ToUtf8(std::u32string const& str)
{
return utf8::utf32to8(str);
}
size_t EncodedLength(std::string const& str)
{
return utf8::distance(str.begin(), str.end());
}
}// namespace Encoding
}// namespace System

View File

@ -1,43 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <string>
namespace System {
namespace Encoding {
std::wstring Utf8ToWChar(std::string const& str);
std::u16string Utf8ToUtf16(std::string const& str);
std::u32string Utf8ToUtf32(std::string const& str);
std::string WCharToUtf8(std::wstring const& str);
std::string Utf16ToUtf8(std::u16string const& str);
std::string Utf32ToUtf8(std::u32string const& str);
// Size of UTF8 chars (not the size of the byte buffer).
size_t EncodedLength(std::string const& str);
}
}

View File

@ -1,128 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <cstddef> // size_t
#include <cstdint> // uint*_t
namespace System {
class Endian
{
private:
template<typename T, size_t byte_count>
struct ByteSwapImpl
{
constexpr static inline T swap(T v)
{
for (int i = 0; i < (byte_count/2); ++i)
{
uint8_t tmp = reinterpret_cast<uint8_t*>(&v)[i];
reinterpret_cast<uint8_t*>(&v)[i] = reinterpret_cast<uint8_t*>(&v)[byte_count - i - 1];
reinterpret_cast<uint8_t*>(&v)[byte_count - i - 1] = tmp;
}
return v;
}
};
template<typename T>
struct ByteSwapImpl<T, 1>
{
constexpr static inline T swap(T v) { return v; }
};
template<typename T>
struct ByteSwapImpl<T, 2>
{
constexpr static inline T swap(T v)
{
uint16_t& tmp = *reinterpret_cast<uint16_t*>(&v);
tmp = ((tmp & 0x00ffu) << 8)
| ((tmp & 0xff00u) >> 8);
return v;
}
};
template<typename T>
struct ByteSwapImpl<T, 4>
{
constexpr static inline T swap(T v)
{
uint32_t& tmp = *reinterpret_cast<uint32_t*>(&v);
tmp = ((tmp & 0x000000fful) << 24)
| ((tmp & 0x0000ff00ul) << 8)
| ((tmp & 0x00ff0000ul) >> 8)
| ((tmp & 0xff000000ul) >> 24);
return v;
}
};
template<typename T>
struct ByteSwapImpl<T, 8>
{
constexpr static inline T swap(T v)
{
uint64_t& tmp = *reinterpret_cast<uint64_t*>(&v);
tmp = ((tmp & 0x00000000000000ffull) << 56)
| ((tmp & 0x000000000000ff00ull) << 40)
| ((tmp & 0x0000000000ff0000ull) << 24)
| ((tmp & 0x00000000ff000000ull) << 8)
| ((tmp & 0x000000ff00000000ull) >> 8)
| ((tmp & 0x0000ff0000000000ull) >> 24)
| ((tmp & 0x00ff000000000000ull) >> 40)
| ((tmp & 0xff00000000000000ull) >> 56);
return v;
}
};
public:
static inline bool little()
{
const uint32_t endian_magic = 0x01020304;
return reinterpret_cast<const uint8_t*>(&endian_magic)[0] == 0x04;
}
static inline bool big()
{
const uint32_t endian_magic = 0x01020304;
return reinterpret_cast<const uint8_t*>(&endian_magic)[0] == 0x01;
}
template<typename T, size_t Size = sizeof(T)>
constexpr static inline T net_swap(T v)
{
if(Endian::little())
{
return ByteSwapImpl<T, Size>::swap(v);
}
return v;
}
template<typename T, size_t Size = sizeof(T)>
constexpr static inline T swap(T v)
{
return ByteSwapImpl<T, Size>::swap(v);
}
private:
Endian() = delete;
};
}

View File

@ -1,562 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "Filesystem.h"
#include "Encoding.hpp"
#include "System_internals.h"
#if defined(SYSTEM_OS_WINDOWS)
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
#define NOMINMAX
#include <Windows.h>
#ifdef CreateDirectory
#undef CreateDirectory
#endif
#ifdef DeleteFile
#undef DeleteFile
#endif
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
#include <sys/types.h>
#include <sys/ioctl.h> // get iface broadcast
#include <sys/stat.h> // stats on a file (is directory, size, mtime)
#include <dirent.h> // to open directories
#include <dlfcn.h> // dlopen (like dll for linux)
#include <string.h>
#include <limits.h> // PATH_MAX
#include <unistd.h>
#else
#error "unknown arch"
#endif
#include <fstream>
#include <algorithm>
#include <iterator>
#include <ctime>
namespace System {
namespace Filesystem {
static void _CleanSlashes(std::string& str);
std::string Filename(std::string const& path)
{
size_t pos = path.find_last_of("/\\");
if (pos != std::string::npos)
return path.substr(pos+1);
return path;
}
std::string Dirname(std::string const& path)
{
std::string r(path);
_CleanSlashes(r);
size_t pos = r.find_last_of("/\\");
if (pos == std::string::npos || (pos == 0 && r.length() == 1))
return std::string();
if (pos == 0)
++pos;
return r.substr(0, pos);
}
std::string Join(StringView r, StringView l)
{
std::string result(r.to_string());
result += Separator;
result += l.to_string();
_CleanSlashes(result);
return result;
}
std::string CanonicalPath(std::string const& path)
{
if (IsAbsolute(path))
return CleanPath(path);
return CleanPath(Join(GetCwd(),path));
}
size_t FileSize(std::string const& path)
{
std::ifstream in_file(path, std::ios::in | std::ios::binary | std::ios::ate);
if (in_file)
{
return in_file.tellg();
}
return 0;
}
std::chrono::system_clock::time_point FileATime(std::string const& path)
{
struct stat file_stat = {};
if (stat(path.c_str(), &file_stat) != 0)
return std::chrono::system_clock::time_point{};
return std::chrono::system_clock::from_time_t(file_stat.st_atime);
}
std::chrono::system_clock::time_point FileMTime(std::string const& path)
{
struct stat file_stat = {};
if (stat(path.c_str(), &file_stat) != 0)
return std::chrono::system_clock::time_point{};
return std::chrono::system_clock::from_time_t(file_stat.st_mtime);
}
std::chrono::system_clock::time_point FileCTime(std::string const& path)
{
struct stat file_stat = {};
if (stat(path.c_str(), &file_stat) != 0)
return std::chrono::system_clock::time_point{};
return std::chrono::system_clock::from_time_t(file_stat.st_ctime);
}
#ifdef SYSTEM_OS_WINDOWS
static void _CleanSlashes(std::string& str)
{
size_t pos;
std::replace(str.begin(), str.end(), '/', '\\');
while ((pos = str.find("\\\\")) != std::string::npos)
str.replace(pos, 2, "\\");
pos = 0;
while ((pos = str.find("\\.", pos)) != std::string::npos)
{
if (str[pos + 2] == '\\' || (pos + 2) >= str.length())
{
str.replace(pos, 3, "\\");
}
else
{
++pos;
}
}
}
std::string GetCwd()
{
DWORD size = GetCurrentDirectoryW(0, nullptr);
if (size == 0)
return ".";
std::wstring wdirectory;
++size;
wdirectory.resize(size);
wdirectory.resize(GetCurrentDirectoryW(size, &wdirectory[0]));
wdirectory += L'\\';
return System::Encoding::WCharToUtf8(wdirectory);
}
bool IsAbsolute(std::string const& path)
{
return path.length() >= 2 && (((path[0] >= 'a' && path[0] <= 'z') || (path[0] >= 'A' && path[0] <= 'Z')) && path[1] == ':');
}
std::string CleanPath(std::string const& path)
{
std::string cleaned_path(path);
size_t pos;
size_t size;
_CleanSlashes(cleaned_path);
pos = 0;
while ((pos = cleaned_path.find("\\..", pos)) != std::string::npos )
{
if (cleaned_path[pos + 3] == '\\' || (pos+3) >= cleaned_path.length())
{
if (pos == 0)
size = 3;
else
{
size_t parent_pos = cleaned_path.rfind("\\", pos - 1);
if (parent_pos == std::string::npos)
{
size = pos + 3;
pos = 0;
}
else
{
size = 3 + pos - parent_pos;
pos = parent_pos;
}
}
cleaned_path.replace(pos, size, "");
}
else
{
++pos;
}
}
return cleaned_path;
}
bool IsDir(std::string const& path)
{
std::wstring wpath(System::Encoding::Utf8ToWChar(path));
DWORD attrs = GetFileAttributesW(wpath.c_str());
return attrs != INVALID_FILE_ATTRIBUTES && attrs & FILE_ATTRIBUTE_DIRECTORY;
}
bool IsFile(std::string const& path)
{
std::wstring wpath(System::Encoding::Utf8ToWChar(path));
DWORD attrs = GetFileAttributesW(wpath.c_str());
return attrs != INVALID_FILE_ATTRIBUTES && ((attrs & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY);
}
bool Exists(std::string const& path)
{
std::wstring wpath(System::Encoding::Utf8ToWChar(path));
DWORD attrs = GetFileAttributesW(wpath.c_str());
return attrs != INVALID_FILE_ATTRIBUTES;
}
bool CreateDirectory(std::string const& directory, bool recursive)
{
size_t pos = 0;
struct _stat sb;
std::wstring sub_dir;
std::wstring wdirectory(System::Encoding::Utf8ToWChar(directory));
if (wdirectory.empty())
return false;
if (recursive)
{
pos = 3;
do
{
pos = wdirectory.find_first_of(L"\\/", pos + 1);
sub_dir = std::move(wdirectory.substr(0, pos));
if (_wstat(sub_dir.c_str(), &sb) == 0)
{
if (!(sb.st_mode & _S_IFDIR))
{// A subpath in the target is not a directory
return false;
}
// Folder Exists
}
else if (CreateDirectoryW(wdirectory.substr(0, pos).c_str(), NULL) == FALSE && GetLastError() != ERROR_ALREADY_EXISTS)
{// Failed to create directory
return false;
}
}
while (pos != std::string::npos);
return true;
}
return (CreateDirectoryW(wdirectory.c_str(), NULL) != FALSE || GetLastError() == ERROR_ALREADY_EXISTS);
}
bool DeleteFile(std::string const& path)
{
std::wstring wpath(System::Encoding::Utf8ToWChar(path));
return DeleteFileW(wpath.c_str()) == TRUE || GetLastError() == ERROR_FILE_NOT_FOUND;
}
static std::vector<std::wstring> ListFiles(std::wstring const& path, bool files_only, bool recursive)
{
std::vector<std::wstring> files;
WIN32_FIND_DATAW hfind_data;
HANDLE hfind = INVALID_HANDLE_VALUE;
std::wstring search_path = path;
if (*path.rbegin() != L'\\')
search_path += L'\\';
search_path += L'*';
// Start iterating over the files in the path directory.
hfind = FindFirstFileW(search_path.c_str(), &hfind_data);
if (hfind != INVALID_HANDLE_VALUE)
{
search_path.pop_back();
do // Managed to locate and create an handle to that folder.
{
if (wcscmp(L".", hfind_data.cFileName) == 0
|| wcscmp(L"..", hfind_data.cFileName) == 0)
continue;
if (hfind_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if (recursive)
{
std::wstring dir_name = hfind_data.cFileName;
std::vector<std::wstring> sub_files = std::move(ListFiles(search_path + dir_name, files_only, true));
std::transform(sub_files.begin(), sub_files.end(), std::back_inserter(files), [&dir_name](std::wstring& Filename)
{
return dir_name + L'\\' + Filename;
});
}
if (!files_only)
{
files.emplace_back(hfind_data.cFileName);
}
}
else
{
files.emplace_back(hfind_data.cFileName);
}
} while (FindNextFileW(hfind, &hfind_data) == TRUE);
FindClose(hfind);
}
return files;
}
std::vector<std::string> ListFiles(std::string const& path, bool files_only, bool recursive)
{
std::vector<std::string> files;
std::wstring wpath(System::Encoding::Utf8ToWChar(path));
std::vector<std::wstring> wfiles(std::move(ListFiles(wpath, files_only, recursive)));
files.reserve(wfiles.size());
std::transform(wfiles.begin(), wfiles.end(), std::back_inserter(files), [](std::wstring const& wFilename)
{
return System::Encoding::WCharToUtf8(wFilename);
});
return files;
}
#else
static void _CleanSlashes(std::string& str)
{
size_t pos;
std::replace(str.begin(), str.end(), '\\', '/');
while ((pos = str.find("//")) != std::string::npos)
str.replace(pos, 2, "/");
pos = 0;
while ((pos = str.find("/.", pos)) != std::string::npos)
{
if (str[pos + 2] == '/' || (pos + 2) >= str.length())
{
str.replace(pos, 3, "/");
}
else
{
++pos;
}
}
}
std::string GetCwd()
{
char buff[4096];
std::string tmp(getcwd(buff, 4096) == nullptr ? "." : buff);
tmp += '/';
return tmp;
}
bool IsAbsolute(std::string const& path)
{
return path[0] == '/';
}
std::string CleanPath(std::string const& path)
{
std::string cleaned_path(path);
size_t pos;
size_t size;
std::replace(cleaned_path.begin(), cleaned_path.end(), '\\', '/');
_CleanSlashes(cleaned_path);
pos = 0;
while ((pos = cleaned_path.find("/..", pos)) != std::string::npos)
{
if (cleaned_path[pos + 3] == '/' || (pos + 3) >= cleaned_path.length())
{
if (pos == 0)
size = 3;
else
{
size_t parent_pos = cleaned_path.rfind("/", pos - 1);
if (parent_pos == std::string::npos)
{
size = pos + 3;
pos = 0;
}
else
{
size = 3 + pos - parent_pos;
pos = parent_pos;
}
}
cleaned_path.replace(pos, size, "");
}
else
{
++pos;
}
}
return cleaned_path;
}
bool IsDir(std::string const& path)
{
struct stat sb;
if (stat(path.c_str(), &sb) == 0)
{
return S_ISDIR(sb.st_mode);
}
return false;
}
bool IsFile(std::string const& path)
{
struct stat sb;
if (stat(path.c_str(), &sb) == 0)
{
return S_ISREG(sb.st_mode);
}
return false;
}
bool Exists(std::string const& path)
{
struct stat sb;
return stat(path.c_str(), &sb) == 0;
}
bool CreateDirectory(std::string const& directory, bool recursive)
{
size_t pos = 0;
struct stat sb;
std::string sub_dir;
do
{
pos = directory.find("/", pos + 1);
sub_dir = std::move(directory.substr(0, pos));
if (stat(sub_dir.c_str(), &sb) == 0)
{
if (!S_ISDIR(sb.st_mode))
{// A subpath in the target is not a directory
return false;
}
// Folder Exists
}
else if (mkdir(sub_dir.c_str(), 0755) < 0 && errno != EEXIST)
{// Failed to create directory (no permission?)
return false;
}
}
while (pos != std::string::npos);
return true;
}
bool DeleteFile(std::string const& path)
{
return unlink(path.c_str()) == 0;
}
std::vector<std::string> ListFiles(std::string const& path, bool files_only, bool recursive)
{
std::vector<std::string> files;
std::string search_path = path;
if (*path.rbegin() != Separator)
search_path += Separator;
DIR* dir = opendir(search_path.c_str());
struct dirent* entry;
if (dir == nullptr)
return files;
while ((entry = readdir(dir)) != nullptr)
{
if (strcmp(entry->d_name, ".") == 0
|| strcmp(entry->d_name, "..") == 0)
continue;
if (entry->d_type == DT_DIR)
{
if (recursive)
{
std::string dir_name = entry->d_name;
std::vector<std::string> sub_files = std::move(ListFiles(search_path + dir_name, true));
std::transform(sub_files.begin(), sub_files.end(), std::back_inserter(files), [&dir_name](std::string& Filename)
{
return dir_name + Separator + Filename;
});
}
if (!files_only)
{
files.emplace_back(entry->d_name);
}
}
else if (entry->d_type == DT_REG)
{
files.emplace_back(entry->d_name);
}
}
closedir(dir);
return files;
}
#endif
}
}

View File

@ -1,77 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <string>
#include <vector>
#include <chrono>
#include "StringView.hpp"
#ifdef CreateDirectory
#undef CreateDirectory
#endif
#ifdef DeleteFile
#undef DeleteFile
#endif
namespace System {
namespace Filesystem {
constexpr static char WindowsSeparator = '\\';
constexpr static char UnixSeparator = '/';
#if defined(WIN64) || defined(_WIN64) || defined(__MINGW64__) || defined(WIN32) || defined(_WIN32) || defined(__MINGW32__)
constexpr static char Separator = WindowsSeparator;
#else
constexpr static char Separator = UnixSeparator;
#endif
std::string CleanPath(std::string const& path);
std::string Filename(std::string const& path);
std::string Dirname(std::string const& path);
bool IsAbsolute(std::string const& path);
inline std::string Join(StringView s) { return s.to_string(); }
std::string Join(StringView r, StringView l);
template<typename ...Args>
std::string Join(StringView path, Args&& ...args)
{
return Join(path, StringView(Join(args...)));
}
std::string GetCwd();
std::string CanonicalPath(std::string const& path);
bool IsDir(std::string const& path);
bool IsFile(std::string const& path);
bool Exists(std::string const& path);
size_t FileSize(std::string const& path);
std::chrono::system_clock::time_point FileATime(std::string const& path);
std::chrono::system_clock::time_point FileMTime(std::string const& path);
std::chrono::system_clock::time_point FileCTime(std::string const& path);
bool CreateDirectory(std::string const& folder, bool recursive = true);
bool DeleteFile(std::string const& path);
std::vector<std::string> ListFiles(std::string const& path, bool files_only, bool recursive = false);
}
}

View File

@ -1,418 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "Library.h"
#include "Encoding.hpp"
#include "System_internals.h"
#include <memory>
#if defined(SYSTEM_OS_WINDOWS)
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
#define NOMINMAX
#include <Windows.h>
constexpr char library_suffix[] = ".dll";
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
#include <dlfcn.h>
#include <cstring>
#if defined(SYSTEM_OS_LINUX)
#include <dirent.h> // to open directories
#include <unistd.h>
constexpr char library_suffix[] = ".so";
#else
#include <mach-o/dyld_images.h>
constexpr char library_suffix[] = ".dylib";
#endif
#endif
namespace System {
namespace Library {
#if defined(SYSTEM_OS_WINDOWS)
void* OpenLibrary(const char* library_name)
{
if (library_name == nullptr)
return nullptr;
std::wstring wide(System::Encoding::Utf8ToWChar(library_name));
return LoadLibraryW(wide.c_str());
}
void CloseLibrary(void* handle)
{
if(handle != nullptr)
FreeLibrary((HMODULE)handle);
}
void* GetSymbol(void* handle, const char* symbol_name)
{
if (symbol_name == nullptr)
return nullptr;
return GetProcAddress((HMODULE)handle, symbol_name);
}
void* GetLibraryHandle(const char* library_name)
{
if (library_name == nullptr)
return nullptr;
std::wstring wide(System::Encoding::Utf8ToWChar(library_name));
return GetModuleHandleW(wide.c_str());
}
std::string GetLibraryPath(void* handle)
{
if (handle == nullptr)
return std::string();
std::wstring wpath(1024, L'\0');
DWORD size;
while ((size = GetModuleFileNameW((HMODULE)handle, &wpath[0], wpath.length())) == wpath.length())
{
wpath.resize(wpath.length() * 2);
}
wpath.resize(size);
return System::Encoding::WCharToUtf8(wpath);
}
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
void* OpenLibrary(const char* library_name)
{
if (library_name == nullptr)
return nullptr;
return dlopen(library_name, RTLD_NOW);
}
void CloseLibrary(void* handle)
{
if(handle != nullptr)
dlclose(handle);
}
void* GetSymbol(void* handle, const char* symbol_name)
{
if (handle == nullptr)
return nullptr;
return dlsym(handle, symbol_name);
}
#if defined(SYSTEM_OS_LINUX)
std::string GetLibraryPath(void* handle)
{
if (handle == nullptr)
return std::string();
std::string const self("/proc/self/map_files/");
DIR* dir;
struct dirent* dir_entry;
std::string file_path;
std::string res;
dir = opendir(self.c_str());
if (dir != nullptr)
{
while ((dir_entry = readdir(dir)) != nullptr)
{
file_path = (self + dir_entry->d_name);
if (dir_entry->d_type != DT_LNK)
{// Not a link
continue;
}
file_path = System::ExpandSymlink(file_path);
void* lib_handle = dlopen(file_path.c_str(), RTLD_NOW);
if (lib_handle != nullptr)
{// Don't increment ref_counter.
dlclose(lib_handle);
if (handle == lib_handle)
{
res = std::move(file_path);
break;
}
}
}
closedir(dir);
}
return res;
}
void* GetLibraryHandle(const char* library_name)
{
if (library_name == nullptr)
return nullptr;
std::string const self("/proc/self/map_files/");
DIR* dir;
struct dirent* dir_entry;
void* res = nullptr;
size_t library_name_len = strlen(library_name);
dir = opendir(self.c_str());
if (dir != nullptr)
{
std::string file_path;
while ((dir_entry = readdir(dir)) != nullptr)
{
file_path = (self + dir_entry->d_name);
if (dir_entry->d_type != DT_LNK)
{// Not a link
continue;
}
file_path = System::ExpandSymlink(file_path);
auto pos = file_path.rfind('/');
if (pos != std::string::npos)
{
++pos;
if (strncmp(file_path.c_str() + pos, library_name, library_name_len) == 0)
{
res = dlopen(file_path.c_str(), RTLD_NOW);
if (res != nullptr)
{// Like Windows' GetModuleHandle, we don't want to increment the ref counter
dlclose(res);
}
break;
}
}
}
closedir(dir);
}
return res;
}
#else
std::string GetLibraryPath(void* handle)
{
if (handle == nullptr)
return std::string();
task_dyld_info dyld_info;
task_t t;
pid_t pid = getpid();
task_for_pid(mach_task_self(), pid, &t);
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
if (task_info(t, TASK_DYLD_INFO, reinterpret_cast<task_info_t>(&dyld_info), &count) == KERN_SUCCESS)
{
dyld_all_image_infos* dyld_img_infos = reinterpret_cast<dyld_all_image_infos*>(dyld_info.all_image_info_addr);
for (int i = 0; i < dyld_img_infos->infoArrayCount; ++i)
{
void* res = dlopen(dyld_img_infos->infoArray[i].imageFilePath, RTLD_NOW);
if (res != nullptr)
{
dlclose(res);
if(res == handle)
return std::string(dyld_img_infos->infoArray[i].imageFilePath);
}
}
}
return std::string();
}
void* GetLibraryHandle(const char* library_name)
{
if (library_name == nullptr)
return nullptr;
void* res = nullptr;
size_t library_name_len = strlen(library_name);
task_dyld_info dyld_info;
task_t t;
pid_t pid = getpid();
task_for_pid(mach_task_self(), pid, &t);
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
if (task_info(t, TASK_DYLD_INFO, reinterpret_cast<task_info_t>(&dyld_info), &count) == KERN_SUCCESS)
{
const char* pos;
dyld_all_image_infos* dyld_img_infos = reinterpret_cast<dyld_all_image_infos*>(dyld_info.all_image_info_addr);
for (int i = 0; i < dyld_img_infos->infoArrayCount; ++i)
{
pos = strrchr(dyld_img_infos->infoArray[i].imageFilePath, '/');
if (pos != nullptr)
{
++pos;
if (strncmp(pos, library_name, library_name_len) == 0)
{
res = dlopen(dyld_img_infos->infoArray[i].imageFilePath, RTLD_NOW);
if (res != nullptr)
{// Like Windows' GetModuleHandle, we don't want to increment the ref counter
dlclose(res);
}
break;
}
}
}
}
return res;
}
#endif
#endif
std::string GetLibraryExtension()
{
return std::string{ library_suffix };
}
class LibraryImpl
{
std::shared_ptr<void> _Handle;
struct LibraryHandleDestructor
{
void operator()(void* h)
{
System::Library::CloseLibrary(h);
}
};
public:
inline bool OpenLibrary(std::string const& library_name, bool append_extension)
{
std::string lib_name = (append_extension ? library_name + library_suffix : library_name);
void* lib = System::Library::OpenLibrary(lib_name.c_str());
if (lib == nullptr)
{
lib_name = "lib" + lib_name;
lib = System::Library::OpenLibrary(lib_name.c_str());
if (lib == nullptr)
return false;
}
_Handle = std::shared_ptr<void>(lib, LibraryHandleDestructor());
return true;
}
inline void CloseLibrary()
{
_Handle.reset();
}
inline void* GetVSymbol(std::string const& symbol_name) const
{
return System::Library::GetSymbol(_Handle.get(), symbol_name.c_str());
}
inline std::string GetLibraryPath() const
{
return System::Library::GetLibraryPath(_Handle.get());
}
inline void* GetLibraryNativeHandle() const
{
return _Handle.get();
}
inline bool IsLoaded() const
{
return _Handle != nullptr;
}
};
Library::Library():
_Impl(new LibraryImpl)
{}
Library::Library(Library const& other):
_Impl(new LibraryImpl(*other._Impl))
{}
Library::Library(Library&& other) noexcept:
_Impl(other._Impl)
{
other._Impl = nullptr;
}
Library& Library::operator=(Library const& other)
{
*_Impl = *other._Impl;
return *this;
}
Library& Library::operator=(Library&& other) noexcept
{
std::swap(_Impl, other._Impl);
return *this;
}
Library::~Library()
{
delete _Impl; _Impl = nullptr;
}
bool Library::OpenLibrary(std::string const& library_name, bool append_extension)
{
return _Impl->OpenLibrary(library_name, append_extension);
}
void Library::CloseLibrary()
{
_Impl->CloseLibrary();
}
void* Library::GetVSymbol(std::string const& symbol_name) const
{
return _Impl->GetVSymbol(symbol_name);
}
std::string Library::GetLibraryPath() const
{
return _Impl->GetLibraryPath();
}
void* Library::GetLibraryNativeHandle() const
{
return _Impl->GetLibraryNativeHandle();
}
bool Library::IsLoaded() const
{
return _Impl->IsLoaded();
}
}
}

View File

@ -1,80 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <string>
namespace System {
namespace Library {
class Library
{
class LibraryImpl* _Impl;
public:
Library();
Library(Library const& other);
Library(Library&& other) noexcept;
Library& operator=(Library const& other);
Library& operator=(Library&& other) noexcept;
~Library();
bool OpenLibrary(std::string const& library_name, bool append_extension);
void CloseLibrary();
void* GetVSymbol(std::string const& symbol_name) const;
template<typename T>
inline T* GetSymbol(std::string const& symbol_name) const
{
return reinterpret_cast<T*>(GetVSymbol(symbol_name));
}
std::string GetLibraryPath() const;
void* GetLibraryNativeHandle() const;
bool IsLoaded() const;
};
// Triies to load the library, I suggest that you use a Library instance instead
void* OpenLibrary(const char* library_name);
// Will decrease the OS' ref counter on the library, use it to close a handle opened by open_library.
// A Library instance will automatically call this in the destructor
void CloseLibrary(void* handle);
// Will try to retrieve a symbol address from the library handle
void* GetSymbol(void* handle, const char* symbol_name);
// Get a pointer to the library, if it is not loaded, will return nullptr. This doesn't increment the OS' internal ref counter
void* GetLibraryHandle(const char* library_name);
// Get the library path of a module handle
std::string GetLibraryPath(void* handle);
// Get the native extension representing a shared library.
std::string GetLibraryExtension();
}
}

View File

@ -1,96 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <tuple>
#include <mutex>
namespace System {
class scoped_lock {
struct value_holder
{
virtual ~value_holder() noexcept {}
};
template<typename... Args>
struct templated_value_holder : value_holder
{
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type unlock(std::tuple<Tp...>& t) { }
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type unlock(std::tuple<Tp...>& t)
{
std::get<I>(t).unlock();
unlock<I + 1, Tp...>(t);
}
explicit templated_value_holder(Args&... mutexes) : _mutexes(mutexes...) { std::lock(mutexes...); }
explicit templated_value_holder(std::adopt_lock_t, Args&... mutexes) : _mutexes(mutexes...) {} // construct but don't lock
virtual ~templated_value_holder() noexcept { unlock(_mutexes); }
std::tuple<Args&...> _mutexes;
};
template<typename Arg>
struct templated_value_holder<Arg> : value_holder
{
explicit templated_value_holder(Arg& mutex) : _mutex(mutex) { _mutex.lock(); }
explicit templated_value_holder(std::adopt_lock_t, Arg& mutex) : _mutex(mutex) {} // construct but don't lock
virtual ~templated_value_holder() noexcept { _mutex.unlock(); }
Arg& _mutex;
};
value_holder* _val;
public:
template<typename... Args>
explicit scoped_lock(Args&... mutexes) : _val(new templated_value_holder<Args&...>(mutexes...)) { }
template<typename... Args>
explicit scoped_lock(std::adopt_lock_t, Args&... mutexes) : _val(new templated_value_holder<Args&...>(std::adopt_lock, mutexes...)) { }
explicit scoped_lock(scoped_lock && other):
_val(other._val)
{
other._val = nullptr;
}
scoped_lock() noexcept:
_val(nullptr)
{}
~scoped_lock() noexcept { delete _val; }
scoped_lock& operator=(scoped_lock && other)
{
_val = other._val;
other._val = nullptr;
return *this;
}
scoped_lock(const scoped_lock&) = delete;
scoped_lock& operator=(const scoped_lock&) = delete;
};
}

View File

@ -1,89 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "System_internals.h"
#include "String.hpp"
#include <string.h>
#include <algorithm>
#include <cctype>
namespace System {
namespace String {
namespace details {
void LeftTrim(std::string& str)
{
str.erase(str.begin(), std::find_if(str.begin(), str.end(), [](const char c)
{
return !std::isspace((unsigned char)c);
}));
}
void RightTrim(std::string& str)
{
str.erase(std::find_if(str.rbegin(), str.rend(), [](const char c)
{
return !std::isspace((unsigned char)c);
}).base(), str.end());
}
void ToUpper(char* str, size_t len)
{
while(len--)
{
unsigned char c = (unsigned char)*str;
*str++ = std::toupper(c);
}
}
void ToLower(char* str, size_t len)
{
while (len--)
{
unsigned char c = (unsigned char)*str;
*str++ = std::tolower(c);
}
}
char* CloneString(System::StringView src)
{
size_t len = src.length() + 1;
char* res = new char[len];
memcpy(res, src.data(), len);
return res;
}
size_t CopyString(System::StringView src, char* dst, size_t dst_size)
{
size_t written = 0;
if (dst != nullptr && dst_size > 0)
{
written = src.length() > dst_size ? dst_size - 1 : src.length();
memcpy(dst, src.data(), written);
dst[written] = '\0';
}
return written;
}
}// namespace details
}// namespace String
}// namespace System

View File

@ -1,290 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <string>
#include <cstdint>
#include <cstring>
#include <iterator>
#include "StringView.hpp"
#include "StringSwitch.hpp"
namespace System {
namespace String {
///////////////////////////////////////////////////////////
// Implementations
namespace details {
void LeftTrim(std::string& str);
void RightTrim(std::string& str);
void ToUpper(char* str, size_t len);
void ToLower(char* str, size_t len);
char* CloneString(System::StringView src);
size_t CopyString(System::StringView src, char *dst, size_t dst_size);
}
inline void LeftTrim(std::string& str)
{
details::LeftTrim(str);
}
inline void RightTrim(std::string& str)
{
details::RightTrim(str);
}
inline void Trim(std::string& str)
{
LeftTrim(str);
RightTrim(str);
}
inline std::string CopyLeftTrim(const char* str)
{
if (str == nullptr)
return std::string();
std::string r(str);
LeftTrim(r);
return r;
}
inline std::string CopyLeftTrim(System::StringView str)
{
std::string r(str.to_string());
LeftTrim(r);
return r;
}
inline std::string CopyLeftTrim(std::string const& str)
{
std::string r(str);
LeftTrim(r);
return r;
}
inline std::string CopyRightTrim(const char* str)
{
if (str == nullptr)
return std::string();
std::string r(str);
RightTrim(r);
return r;
}
inline std::string CopyRightTrim(System::StringView str)
{
std::string r(str.to_string());
RightTrim(r);
return r;
}
inline std::string CopyRightTrim(std::string const& str)
{
std::string r(str);
RightTrim(r);
return r;
}
inline std::string CopyTrim(const char* str)
{
if (str == nullptr)
return std::string();
std::string r(str);
Trim(r);
return r;
}
inline std::string CopyTrim(System::StringView str)
{
std::string r(str.to_string());
Trim(r);
return r;
}
inline std::string CopyTrim(std::string const& str)
{
std::string r(str);
Trim(r);
return r;
}
inline void ToLower(std::string& str)
{
details::ToLower(&str[0], str.length());
}
inline void ToLower(char* str)
{
if (str == nullptr)
return;
details::ToLower(str, strlen(str));
}
inline std::string CopyLower(std::string const& str)
{
std::string r(str);
details::ToLower(&r[0], r.length());
return r;
}
inline std::string CopyLower(const char* str)
{
std::string r(str == nullptr ? "" : str);
details::ToLower(&r[0], r.length());
return r;
}
inline std::string CopyLower(System::StringView str)
{
std::string r = str.to_string();
details::ToLower(&r[0], r.length());
return r;
}
inline void ToUpper(std::string& str)
{
details::ToUpper(&str[0], str.length());
}
inline void ToUpper(char* str)
{
if (str == nullptr)
return;
details::ToUpper(str, strlen(str));
}
inline std::string CopyUpper(std::string const& str)
{
std::string r(str);
details::ToUpper(&r[0], r.length());
return r;
}
inline std::string CopyUpper(const char* str)
{
std::string r(str == nullptr ? "" : str);
details::ToUpper(&r[0], r.length());
return r;
}
inline std::string CopyUpper(System::StringView str)
{
std::string r = str.to_string();
details::ToUpper(&r[0], r.length());
return r;
}
template<typename IteratorType>
inline std::string Join(IteratorType begin, IteratorType end, const std::string& sep)
{
std::string res;
if (begin != end)
res = *begin++;
while (begin != end)
{
res += sep;
res += *begin++;
}
return res;
}
template<typename T>
inline std::string Join(T const& container, const std::string& sep)
{
return Join(std::begin(container), std::end(container), sep);
}
// Clone a string allocated with the "new" operator, if str is nullptr, an empty string ("") will be returned, NOT nullptr !
inline char* CloneString(const char* str)
{
if (str == nullptr)
return details::CloneString(System::StringView(""));
return details::CloneString(System::StringView(str, strlen(str)));
}
inline char* CloneString(std::string const& str)
{
return details::CloneString(System::StringView(str));
}
inline char* CloneString(System::StringView str)
{
return details::CloneString(str);
}
// Will always end the C-String with a null char.
inline size_t CopyString(const char* src, char* dst, size_t dst_size)
{
if (src == nullptr)
return details::CopyString(System::StringView(""), dst, dst_size);
return details::CopyString(System::StringView(src, strlen(src)), dst, dst_size);
}
inline size_t CopyString(System::StringView src, char* dst, size_t dst_size)
{
return details::CopyString(src, dst, dst_size);
}
inline size_t CopyString(std::string const& src, char* dst, size_t dst_size)
{
return details::CopyString(System::StringView(src), dst, dst_size);
}
template<size_t N>
inline size_t CopyString(const char* src, char(&dst)[N])
{
if (src == nullptr)
return details::CopyString(System::StringView(""), dst, N);
return details::CopyString(System::StringView(src, strlen(src)), dst, N);
}
template<size_t N>
inline size_t CopyString(System::StringView src, char(&dst)[N])
{
return details::CopyString(src, dst, N);
}
template<size_t N>
inline size_t CopyString(std::string const& src, char(&dst)[N])
{
return details::CopyString(System::StringView(src), dst, N);
}
}
}

View File

@ -1,64 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <cstdint>
#include <string>
#include "SystemDetector.h"
#include "StringView.hpp"
namespace System {
namespace StringSwitch {
#if defined(SYSTEM_ARCH_X86)
using hash_type = uint32_t;
#else
using hash_type = uint64_t;
#endif
namespace Detail {
constexpr char lower_char(char c) { return ((c >= 'A' && c <= 'Z') ? c + 32 : c); }
}
// switch case on a string
constexpr hash_type Hash(const char* input, size_t len) { return (len > 0 ? static_cast<hash_type>(*input) + 33 * Hash(input + 1, len - 1) : 5381); }
template<size_t N>
constexpr hash_type Hash(const char(&input)[N]) { return Hash(input, N-1); }
constexpr hash_type Hash(System::StringView sv) { return Hash(sv.data(), sv.length()); }
inline hash_type Hash(const std::string& input) { return Hash(input.c_str(), input.length()); }
constexpr hash_type IHash(const char* input, size_t len) { return (len > 0 ? static_cast<hash_type>(Detail::lower_char(*input)) + 33 * IHash(input + 1, len - 1) : 5381); }
template<size_t N>
constexpr inline hash_type IHash(const char(&input)[N]) { return IHash(input, N - 1); }
constexpr hash_type IHash(System::StringView sv) { return IHash(sv.data(), sv.length()); }
inline hash_type IHash(const std::string& input) { return IHash(input.c_str(), input.length()); }
}
}

View File

@ -1,256 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <iterator>
#include <string>
#include <iostream>
#include <array>
namespace System {
template<typename char_type>
class BasicStringView {
const char_type* _string;
size_t _length;
using type = BasicStringView<char_type>;
public:
class iterator {
const char_type* _value;
public:
constexpr iterator(const iterator& o) : _value(o._value) {}
constexpr iterator(const char_type* value) : _value(value) {}
constexpr iterator& operator++() { ++_value; return *this; }
constexpr iterator operator++(int) { iterator retval = *this; ++(*this); return retval; }
constexpr iterator& operator--() { --_value; return *this; }
constexpr iterator operator--(int) { iterator retval = *this; --(*this); return retval; }
constexpr bool operator==(iterator other) const { return _value == other._value; }
constexpr bool operator!=(iterator other) const { return !(*this == other); }
constexpr const char_type& operator*() const { return *_value; }
// iterator traits
using difference_type = long;
using value_type = char_type;
using pointer = const char_type*;
using reference = const char_type&;
using iterator_category = std::random_access_iterator_tag;
};
constexpr BasicStringView() : _string(nullptr), _length(0)
{}
constexpr BasicStringView(const char_type* str, size_t length) : _string(str), _length(length)
{}
constexpr BasicStringView(std::basic_string<char_type, std::char_traits<char_type>, std::allocator<char_type>> const& str) : _string(str.data()), _length(str.length())
{}
template<size_t N>
constexpr BasicStringView(const char_type(&str)[N]) : _string(str), _length(N - 1)
{}
template<size_t N>
constexpr BasicStringView(std::array<char_type, N> const& str) : _string(&str.at[0]), _length(N)
{}
constexpr BasicStringView(type const& other) : _string(other._string), _length(other._length)
{}
constexpr BasicStringView(type&& other) : _string(other._string), _length(other._length)
{}
constexpr type& operator=(type const& other)
{
_string = other._string;
_length = other._length;
return *this;
}
constexpr type& operator=(type&& other)
{
_string = other._string;
_length = other._length;
return *this;
}
constexpr const char_type* data() const { return _string; }
constexpr bool empty() const { return _length == 0; }
constexpr size_t size() const { return _length; }
constexpr size_t length() const { return _length; }
constexpr const char_type& operator[](size_t index) const { return _string[index]; }
constexpr size_t find_first_of(type const& string, const size_t offset = 0) const
{
if(_length == 0)
return std::string::npos;
for (size_t i = offset; i < _length; ++i)
{
for (size_t j = 0; j < string._length; ++j)
{
if (_string[i] == string[j])
return i;
}
}
return std::string::npos;
}
constexpr size_t find_first_not_of(type const& string, const size_t offset = 0) const
{
if(_length == 0)
return std::string::npos;
for (size_t i = offset; i < _length; ++i)
{
for (size_t j = 0; j < string._length; ++j)
{
if (_string[i] == string[j])
break;
if (j == (string._length - 1))
return i;
}
}
return std::string::npos;
}
constexpr size_t find(type const& string, const size_t offset = 0) const
{
if (_length < string._length)
return std::string::npos;
for (size_t i = offset; i < (_length - string._length + 1); ++i)
{
for (size_t j = 0; j < string._length; ++j)
{
if (_string[i + j] != string[j])
break;
if (j == (string._length - 1))
return i;
}
}
return std::string::npos;
}
constexpr size_t find_not(type const& string, const size_t offset = 0) const
{
if (_length < string._length)
return std::string::npos;
for (size_t i = offset; i < (_length - string._length + 1); ++i)
{
for (size_t j = 0; j < string._length; ++j)
{
if (_string[i + j] == string[j])
break;
if (j == (string._length - 1))
return i;
}
}
return std::string::npos;
}
constexpr size_t count(char_type const c) const
{
size_t n = 0;
for (size_t i = 0; i < _length; ++i)
if (_string[i] == c)
++n;
return n;
}
constexpr type substr(size_t offset, size_t length = std::string::npos) const
{
if (offset >= _length)
return type();
return type(_string + offset, (_length - offset) > length ? length : _length - offset);
}
constexpr iterator begin() const
{
return iterator(_string);
}
constexpr iterator end() const
{
return iterator(_string + _length);
}
std::string to_string() const
{
return std::string(_string, _string + _length);
}
size_t copy(char_type* p, size_t p_size) const
{
size_t written = 0;
if (p != nullptr)
{
size_t to_write = (_length > p_size ? p_size : _length);
char_type* b = _string;
while (to_write--)
{
*p++ = *b++;
++written;
}
}
return written;
}
};
using StringView = BasicStringView<char>;
}
template<typename char_type>
std::basic_ostream<char_type>& operator<<(std::basic_ostream<char_type>& os, System::BasicStringView<char_type> const& sv)
{
return os.write(sv.data(), sv.length());
}
template<typename char_type>
std::basic_string<char_type> operator+(std::basic_string<char_type> const& str, System::BasicStringView<char_type> const& sv)
{
std::string r(str);
return r.append(sv.data(), sv.data() + sv.length());
}
template<typename char_type>
std::basic_string<char_type>& operator+=(std::basic_string<char_type>& str, System::BasicStringView<char_type> const& sv)
{
return str.append(sv.data(), sv.data() + sv.length());
}

View File

@ -1,593 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "System.h"
#include "Filesystem.h"
#include "Encoding.hpp"
#include "System_internals.h"
#if defined(SYSTEM_OS_WINDOWS)
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
#define NOMINMAX
#include <Windows.h>
#include <TlHelp32.h>
#include <shellapi.h>
#include <shlobj.h> // (shell32.lib) Infos about current user folders
inline bool handle_is_valid(HANDLE h)
{
return (h != (HANDLE)0 && h != (HANDLE)-1);
}
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
#if defined(SYSTEM_OS_LINUX)
#include <sys/sysinfo.h> // Get uptime (second resolution)
#include <dirent.h>
#else
#include <sys/sysctl.h>
#include <mach-o/dyld_images.h>
#endif
#include <sys/types.h>
#include <pwd.h>
#include <unistd.h>
#include <dlfcn.h>
#else
#error "unknown arch"
#endif
#include <fstream>
namespace System {
std::chrono::microseconds GetUpTime()
{
return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now() - GetBootTime());
}
}
namespace System {
#if defined(SYSTEM_OS_WINDOWS)
std::chrono::system_clock::time_point GetBootTime()
{
static std::chrono::system_clock::time_point boottime(std::chrono::system_clock::now() - std::chrono::milliseconds(GetTickCount64()));
return boottime;
}
std::vector<std::string> GetProcArgs()
{
std::vector<std::string> res;
LPWSTR* szArglist;
int nArgs;
szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
res.reserve(nArgs);
for (int i = 0; i < nArgs; ++i)
{
res.emplace_back(System::Encoding::WCharToUtf8(szArglist[i]));
}
LocalFree(szArglist);
return res;
}
std::string GetEnvVar(std::string const& var)
{
std::wstring wide(System::Encoding::Utf8ToWChar(var));
std::wstring wVar;
DWORD size = GetEnvironmentVariableW(wide.c_str(), nullptr, 0);
// Size can be 0, and the size includes the null char, so resize to size - 1
if (size < 2)
return std::string();
wVar.resize(size - 1);
GetEnvironmentVariableW(wide.c_str(), &wVar[0], size);
return System::Encoding::WCharToUtf8(wVar);
}
std::string GetUserdataPath()
{
WCHAR szPath[4096] = {};
HRESULT hr = SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, 0, szPath);
if (FAILED(hr))
return std::string();
return System::Encoding::WCharToUtf8(std::wstring(szPath));
}
std::string GetExecutablePath()
{
std::string path;
std::wstring wpath(4096, L'\0');
wpath.resize(GetModuleFileNameW(nullptr, &wpath[0], wpath.length()));
return System::Encoding::WCharToUtf8(wpath);
}
std::string GetModulePath()
{
std::string path;
std::wstring wpath(4096, L'\0');
HMODULE hModule;
if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)&GetModulePath, &hModule) != FALSE)
{
DWORD size = GetModuleFileNameW((HINSTANCE)hModule, &wpath[0], wpath.length());
wpath.resize(size);
}
return System::Encoding::WCharToUtf8(wpath);
}
std::vector<std::string> GetModules()
{
std::vector<std::string> paths;
std::wstring wpath;
DWORD size;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetProcessId(GetCurrentProcess()));
if (handle_is_valid(hSnap))
{
MODULEENTRY32W entry{};
entry.dwSize = sizeof(entry);
if (Module32FirstW(hSnap, &entry) != FALSE)
{
wpath.resize(4096);
size = GetModuleFileNameW((HINSTANCE)entry.hModule, &wpath[0], wpath.length());
wpath.resize(size);
paths.emplace_back(System::Encoding::WCharToUtf8(wpath));
while (Module32NextW(hSnap, &entry) != FALSE)
{
wpath.resize(4096);
size = GetModuleFileNameW((HINSTANCE)entry.hModule, &wpath[0], wpath.length());
wpath.resize(size);
paths.emplace_back(System::Encoding::WCharToUtf8(wpath));
}
}
CloseHandle(hSnap);
}
return paths;
}
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
#ifdef SYSTEM_OS_LINUX
std::chrono::system_clock::time_point GetBootTime()
{
static std::chrono::system_clock::time_point boottime(std::chrono::seconds(0));
if (boottime == std::chrono::system_clock::time_point{})
{
std::ifstream uptime_file("/proc/uptime");
double uptime;
if (uptime_file)
{// Get uptime (millisecond resolution)
uptime_file >> uptime;
uptime_file.close();
}
else
{// If we can't open /proc/uptime, fallback to sysinfo (second resolution)
struct sysinfo infos;
if (sysinfo(&infos) != 0)
return boottime;
uptime = infos.uptime;
}
std::chrono::system_clock::time_point now_tp = std::chrono::system_clock::now();
std::chrono::system_clock::time_point uptime_tp(std::chrono::milliseconds(static_cast<uint64_t>(uptime * 1000)));
boottime = std::chrono::system_clock::time_point(now_tp - uptime_tp);
}
return boottime;
}
std::string GetExecutablePath()
{
std::string exec_path("./");
char link[2048] = {};
if (readlink("/proc/self/exe", link, sizeof(link)) > 0)
{
exec_path = link;
}
return exec_path;
}
std::string GetModulePath()
{
std::string const self("/proc/self/map_files/");
DIR* dir;
struct dirent* dir_entry;
std::string file_path;
std::string res;
uint64_t handle = (uint64_t)&GetModulePath;
uint64_t low, high;
char* tmp;
dir = opendir(self.c_str());
if (dir != nullptr)
{
while ((dir_entry = readdir(dir)) != nullptr)
{
file_path = dir_entry->d_name;
if (dir_entry->d_type != DT_LNK)
{// Not a link
continue;
}
tmp = &file_path[0];
low = strtoull(tmp, &tmp, 16);
if ((tmp - file_path.c_str()) < file_path.length())
{
high = strtoull(tmp+1, nullptr, 16);
if (low != 0 && high > low && low <= handle && handle <= high)
{
res = System::ExpandSymlink(self + file_path);
break;
}
}
}
closedir(dir);
}
return res;
}
std::vector<std::string> GetModules()
{
std::string const self("/proc/self/map_files/");
std::vector<std::string> paths;
DIR* dir;
struct dirent* dir_entry;
std::string path;
bool found;
dir = opendir(self.c_str());
if (dir != nullptr)
{
while ((dir_entry = readdir(dir)) != nullptr)
{
if (dir_entry->d_type != DT_LNK)
{// Not a link
continue;
}
found = false;
path = System::ExpandSymlink(self + dir_entry->d_name);
for (auto const& item : paths)
{
if (item == path)
{
found = true;
break;
}
}
if (!found)
paths.emplace_back(std::move(path));
}
closedir(dir);
}
return paths;
}
std::vector<std::string> GetProcArgs()
{
std::vector<std::string> res;
std::ifstream fcmdline("/proc/self/cmdline", std::ios::in | std::ios::binary);
if (fcmdline)
{
for (std::string line; std::getline(fcmdline, line, '\0');)
{
res.emplace_back(std::move(line));
}
}
return res;
}
#else
static int IsProcessTranslated()
{
int ret = 0;
size_t size = sizeof(ret);
// Call the sysctl and if successful return the result
if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) != -1)
return ret;
// If "sysctl.proc_translated" is not present then must be native
if (errno == ENOENT)
return 0;
return -1;
}
std::chrono::system_clock::time_point GetBootTime()
{
static std::chrono::system_clock::time_point boottime{};
if (boottime == std::chrono::system_clock::time_point{})
{
struct timeval boottime_tv;
size_t len = sizeof(boottime_tv);
int mib[2] = { CTL_KERN, KERN_BOOTTIME };
if (sysctl(mib, sizeof(mib)/sizeof(*mib), &boottime_tv, &len, nullptr, 0) < 0)
return boottime;
boottime = std::chrono::system_clock::time_point(
std::chrono::seconds(boottime_tv.tv_sec) +
std::chrono::microseconds(boottime_tv.tv_usec));
}
return boottime;
}
std::string GetExecutablePath()
{
std::string exec_path("./");
task_dyld_info dyld_info;
task_t t;
pid_t pid = getpid();
task_for_pid(mach_task_self(), pid, &t);
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
if (task_info(t, TASK_DYLD_INFO, reinterpret_cast<task_info_t>(&dyld_info), &count) == KERN_SUCCESS)
{
dyld_all_image_infos *dyld_img_infos = reinterpret_cast<dyld_all_image_infos*>(dyld_info.all_image_info_addr);
if (IsProcessTranslated() == 1)
{
for (int i = 0; i < dyld_img_infos->infoArrayCount; ++i)
{
exec_path = dyld_img_infos->infoArray[i].imageFilePath;
if (strcasestr(exec_path.c_str(), "rosetta") != nullptr)
continue;
// In case of a translated process (Rosetta maybe ?), the executable path is not the first entry.
size_t pos;
while ((pos = exec_path.find("/./")) != std::string::npos)
{
exec_path.replace(pos, 3, "/");
}
break;
}
}
else
{
for (int i = 0; i < dyld_img_infos->infoArrayCount; ++i)
{
// For now I don't know how to be sure to get the executable path
// but looks like the 1st entry is the executable path
exec_path = dyld_img_infos->infoArray[i].imageFilePath;
size_t pos;
while ((pos = exec_path.find("/./")) != std::string::npos)
{
exec_path.replace(pos, 3, "/");
}
break;
}
}
}
return exec_path;
}
// Workaround for MacOS, I don't know how to get module path from address.
SYSTEM_EXPORT_API(SYSTEM_EXTERN_C, void, SYSTEM_MODE_EXPORT, SYSTEM_CALL_DEFAULT) GetModulePathPlaceholder() {}
std::string GetModulePath()
{
task_dyld_info dyld_info;
task_t t;
pid_t pid = getpid();
task_for_pid(mach_task_self(), pid, &t);
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
if (task_info(t, TASK_DYLD_INFO, reinterpret_cast<task_info_t>(&dyld_info), &count) == KERN_SUCCESS)
{
dyld_all_image_infos* dyld_img_infos = reinterpret_cast<dyld_all_image_infos*>(dyld_info.all_image_info_addr);
for (int i = 0; i < dyld_img_infos->infoArrayCount; ++i)
{
void* res = dlopen(dyld_img_infos->infoArray[i].imageFilePath, RTLD_NOW);
if (res != nullptr)
{
void* placeholder = dlsym(res, "GetModulePathPlaceholder");
dlclose(res);
if(placeholder == (void*)&GetModulePathPlaceholder)
{
std::string res(dyld_img_infos->infoArray[i].imageFilePath);
size_t pos;
while((pos = res.find("/./")) != std::string::npos)
{
res.replace(pos, 3, "/");
}
return res;
}
}
}
}
return std::string();
}
std::vector<std::string> GetModules()
{
std::vector<std::string> paths;
std::string path;
size_t pos;
task_dyld_info dyld_info;
task_t t;
pid_t pid = getpid();
task_for_pid(mach_task_self(), pid, &t);
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
if (task_info(t, TASK_DYLD_INFO, reinterpret_cast<task_info_t>(&dyld_info), &count) == KERN_SUCCESS)
{
dyld_all_image_infos* dyld_img_infos = reinterpret_cast<dyld_all_image_infos*>(dyld_info.all_image_info_addr);
for (int i = 0; i < dyld_img_infos->infoArrayCount; ++i)
{
path = dyld_img_infos->infoArray[i].imageFilePath;
while ((pos = path.find("/./")) != std::string::npos)
{
path.replace(pos, 3, "/");
}
paths.emplace_back(std::move(path));
}
}
return paths;
}
std::vector<std::string> GetProcArgs()
{
std::vector<std::string> res;
int mib[3];
int argmax;
size_t size;
int nargs;
mib[0] = CTL_KERN;
mib[1] = KERN_ARGMAX;
size = sizeof(argmax);
if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1)
{
return res;
}
std::unique_ptr<char[]> procargs(new char[argmax]);
if (procargs == nullptr)
{
return res;
}
mib[0] = CTL_KERN;
mib[1] = KERN_PROCARGS2;
mib[2] = getpid();
size = (size_t)argmax;
if (sysctl(mib, 3, procargs.get(), &size, NULL, 0) == -1)
{
return res;
}
memcpy(&nargs, procargs.get(), sizeof(nargs));
if (nargs <= 0)
{
return res;
}
char* args_end = procargs.get() + size;
char* arg_iterator = procargs.get() + sizeof(nargs);
// Skip saved exec path
while (*arg_iterator != '\0' && arg_iterator < args_end)
{
++arg_iterator;
}
// Skip trailing(s) '\0'
while (*arg_iterator == '\0' && arg_iterator < args_end)
{
++arg_iterator;
}
res.reserve(nargs);
char* arg = arg_iterator;
for (int i = 0; i < nargs && arg_iterator < args_end; ++arg_iterator)
{
if (*arg_iterator == '\0')
{
++i;
res.emplace_back(arg);
arg = arg_iterator + 1;
}
}
return res;
}
#endif
std::string GetUserdataPath()
{
std::string user_appdata_path;
/*
~/Library/Application Support/<application name>
~/Library/Preferences/<application name>
~/Library/<application name>/
*/
struct passwd* user_entry = getpwuid(getuid());
if (user_entry == nullptr || user_entry->pw_dir == nullptr)
{
char* env_var = getenv("HOME");
if (env_var != nullptr)
{
user_appdata_path = env_var;
}
}
else
{
user_appdata_path = user_entry->pw_dir;
}
if (!user_appdata_path.empty())
{
#ifdef SYSTEM_OS_LINUX
user_appdata_path = System::Filesystem::Join(user_appdata_path, ".config");
#else
user_appdata_path = System::Filesystem::Join(user_appdata_path, "Library", "Application Support");
#endif
}
return user_appdata_path;
}
std::string GetEnvVar(std::string const& var)
{
char* env = getenv(var.c_str());
if (env == nullptr)
return std::string();
return env;
}
#endif
}

View File

@ -1,44 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <chrono>
#include <string>
#include <vector>
namespace System {
std::chrono::system_clock::time_point GetBootTime();
std::chrono::microseconds GetUpTime();
// Get the current process argv
std::vector<std::string> GetProcArgs();
// Get User env variable
std::string GetEnvVar(std::string const& var);
// User appdata full path
std::string GetUserdataPath();
// Executable full path
std::string GetExecutablePath();
// .dll, .so or .dylib full path
std::string GetModulePath();
// List all loaded modules
std::vector<std::string> GetModules();
}

View File

@ -1,105 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#if defined(WIN64) || defined(_WIN64) || defined(__MINGW64__) || defined(WIN32) || defined(_WIN32) || defined(__MINGW32__)
#define SYSTEM_OS_WINDOWS
#if defined(_M_IX86)
#define SYSTEM_ARCH_X86
#elif defined(_M_AMD64)
#define SYSTEM_ARCH_X64
#elif defined(_M_ARM)
#define SYSTEM_ARCH_ARM
#elif defined(_M_ARM64)
#define SYSTEM_ARCH_ARM64
#else
#error "Unhandled arch"
#endif
#elif defined(__linux__) || defined(linux)
#define SYSTEM_OS_LINUX
#if defined(__i386__) || defined(__i386) || defined(i386)
#define SYSTEM_ARCH_X86
#elif defined(__x86_64__) || defined(__x86_64) || defined(__amd64) || defined(__amd64__)
#define SYSTEM_ARCH_X64
#elif defined(__arm__)
#define SYSTEM_ARCH_ARM
#elif defined(__aarch64__)
#define SYSTEM_ARCH_ARM64
#else
#error "Unhandled arch"
#endif
#elif defined(__APPLE__)
#define SYSTEM_OS_APPLE
#if defined(__i386__) || defined(__i386) || defined(i386)
#define SYSTEM_ARCH_X86
#elif defined(__x86_64__) || defined(__x86_64) || defined(__amd64) || defined(__amd64__)
#define SYSTEM_ARCH_X64
#elif defined(__arm__)
#define SYSTEM_ARCH_ARM
#elif defined(__aarch64__)
#define SYSTEM_ARCH_ARM64
#else
#error "Unhandled arch"
#endif
#else
//#error "Unknown OS"
#endif
#ifdef __cplusplus
// Some constexpr for C++17 constexpr if.
namespace System {
enum class OperatingSystem {
Windows = 0,
Linux = 1,
Apple = 2,
};
enum class Arch {
x86 = 0,
x64 = 1,
arm = 2,
aarch64 = 3,
};
static constexpr OperatingSystem os =
#if defined(SYSTEM_OS_WINDOWS)
OperatingSystem::Windows;
#elif defined(SYSTEM_OS_LINUX)
OperatingSystem::Linux;
#elif defined(SYSTEM_OS_APPLE)
OperatingSystem::Apple;
#endif
static constexpr Arch arch =
#if defined(SYSTEM_ARCH_X86)
Arch::x86;
#elif defined(SYSTEM_ARCH_X64)
Arch::x64;
#elif defined(SYSTEM_ARCH_ARM)
Arch::arm;
#elif defined(SYSTEM_ARCH_ARM64)
Arch::aarch64;
#endif
}
#endif

View File

@ -1,125 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "SystemDetector.h"
#ifdef __cplusplus
#define SYSTEM_EXTERN_NONE
#define SYSTEM_EXTERN_C extern "C"
#define SYSTEM_EXTERN_CXX extern
#else
#define SYSTEM_EXTERN_NONE
#define SYSTEM_EXTERN_C extern
#define SYSTEM_EXTERN_CXX #error "No C++ export in C"
#endif
#if defined(SYSTEM_OS_WINDOWS)
#if defined(__clang__)
#define SYSTEM_CALL_DEFAULT
#define SYSTEM_CALL_STDL __stdcall
#define SYSTEM_CALL_CDECL __cdecl
#define SYSTEM_CALL_FAST __fastcall
#define SYSTEM_CALL_THIS __thiscall
#define SYSTEM_MODE_DEFAULT
#define SYSTEM_MODE_EXPORT __declspec(dllexport)
#define SYSTEM_MODE_IMPORT __declspec(dllimport)
#define SYSTEM_MODE_HIDDEN
#define SYSTEM_HIDE_CLASS(keyword) SYSTEM_EXTERN_NONE SYSTEM_MODE_HIDDEN keyword
#define SYSTEM_HIDE_API(return_type, call_convention) SYSTEM_EXTERN_NONE SYSTEM_MODE_HIDDEN return_type call_convention
#define SYSTEM_EXPORT_API(extern_type, return_type, mode, call_convention) extern_type mode return_type call_convention
#else
#define SYSTEM_CALL_DEFAULT
#define SYSTEM_CALL_STDL __stdcall
#define SYSTEM_CALL_CDECL __cdecl
#define SYSTEM_CALL_FAST __fastcall
#define SYSTEM_CALL_THIS __thiscall
#define SYSTEM_MODE_DEFAULT
#define SYSTEM_MODE_EXPORT __declspec(dllexport)
#define SYSTEM_MODE_IMPORT __declspec(dllimport)
#define SYSTEM_MODE_HIDDEN
#define SYSTEM_HIDE_CLASS(keyword) SYSTEM_EXTERN_NONE SYSTEM_MODE_HIDDEN keyword
#define SYSTEM_HIDE_API(return_type, call_convention) SYSTEM_EXTERN_NONE SYSTEM_MODE_HIDDEN return_type call_convention
#define SYSTEM_EXPORT_API(extern_type, return_type, mode, call_convention) extern_type mode return_type call_convention
#endif
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
#define SYSTEM_CALL_DEFAULT
#define SYSTEM_CALL_STD __attribute__((stdcall))
#define SYSTEM_CALL_CDECL __attribute__((cdecl))
#define SYSTEM_CALL_FAST __attribute__((fastcall))
#define SYSTEM_CALL_THIS __attribute__((thiscall))
#define SYSTEM_MODE_DEFAULT
#define SYSTEM_MODE_EXPORT __attribute__((visibility("default")))
#define SYSTEM_MODE_IMPORT __attribute__((visibility("default")))
#define SYSTEM_MODE_HIDDEN __attribute__((visibility("hidden")))
#define SYSTEM_HIDE_CLASS(keyword) SYSTEM_EXTERN_NONE keyword SYSTEM_MODE_HIDDEN
#define SYSTEM_HIDE_API(return_type, call_convention) SYSTEM_EXTERN_NONE SYSTEM_MODE_HIDDEN return_type call_convention
#define SYSTEM_EXPORT_API(extern_type, return_type, mode, call_convention) extern_type mode return_type call_convention
//#define LOCAL_API __attribute__((visibility ("internal")))
#endif
/*
Copy/Paste this code in some source file if you want to call a function when the shared_library is loaded/unloaded.
#if defined(SYSTEM_OS_WINDOWS)
#define VC_EXTRALEAN
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
shared_library_load();
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
shared_library_unload();
break;
}
return TRUE;
}
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
__attribute__((constructor)) SYSTEM_HIDE_API(void, SYSTEM_CALL_DEFAULT) system_shared_library_constructor()
{
shared_library_load();
}
__attribute__((destructor)) SYSTEM_HIDE_API(void, SYSTEM_CALL_DEFAULT) system_shared_library_destructor()
{
shared_library_unload();
}
#endif
*/

View File

@ -1,60 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "System_internals.h"
#if defined(SYSTEM_OS_WINDOWS)
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
#define NOMINMAX
#include <Windows.h>
namespace System {
}
#elif defined(SYSTEM_OS_LINUX)
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
namespace System {
SYSTEM_HIDE_API(std::string, SYSTEM_CALL_DEFAULT) ExpandSymlink(std::string file_path)
{
struct stat file_stat;
std::string link_target;
ssize_t name_len = 128;
while(lstat(file_path.c_str(), &file_stat) >= 0 && S_ISLNK(file_stat.st_mode) == 1)
{
do
{
name_len *= 2;
link_target.resize(name_len);
name_len = readlink(file_path.c_str(), &link_target[0], link_target.length());
} while (name_len == link_target.length());
link_target.resize(name_len);
file_path = std::move(link_target);
}
return file_path;
}
}
#endif

View File

@ -1,37 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "SystemExports.h"
#if defined(SYSTEM_OS_WINDOWS)
#include <string>
namespace System {
}
#elif defined(SYSTEM_OS_LINUX)
#include <string>
namespace System {
SYSTEM_HIDE_API(std::string , SYSTEM_CALL_DEFAULT) ExpandSymlink(std::string file_path);
}
#endif

View File

@ -1,164 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <atomic>
#include <condition_variable>
#include <functional>
#include <future>
#include <memory>
#include <mutex>
#include <queue>
#include <thread>
#include <type_traits>
#include <vector>
namespace System {
class ThreadPool
{
using task_t = std::function<void()>;
std::atomic<bool> _StopWorkers;
std::atomic<std::size_t> _ActiveCount;
std::condition_variable _WorkerNotifier;
std::mutex _Mutex;
std::vector<std::thread> _Workers;
std::queue<task_t> _Tasks;
public:
explicit ThreadPool():
_ActiveCount(0)
{
}
~ThreadPool()
{
Join();
}
ThreadPool(ThreadPool const &) = delete;
ThreadPool(ThreadPool&&) = default;
ThreadPool&operator=(ThreadPool const &) = delete;
ThreadPool&operator=(ThreadPool&&) = default;
template <class Func, class... Args>
auto Push(Func &&fn, Args &&...args)
{
using return_type = typename std::result_of<Func(Args...)>::type;
auto task{ std::make_shared<std::packaged_task<return_type()>>(
std::bind(std::forward<Func>(fn), std::forward<Args>(args)...)
) };
auto future{ task->get_future() };
{
std::lock_guard<std::mutex> lock(_Mutex);
_Tasks.emplace([task]()
{
(*task)();
});
}
_WorkerNotifier.notify_one();
return future;
}
// Remove all pending tasks from the queue
void Clear()
{
std::lock_guard<std::mutex> lock(_Mutex);
_Tasks = {};
}
// Stops all previous and creates new worker threads.
void Start(std::size_t worker_count = std::thread::hardware_concurrency())
{
Join();
_StopWorkers = false;
for (std::size_t i = 0; i < worker_count; ++i)
_Workers.emplace_back(std::bind(&ThreadPool::_WorkerLoop, this));
}
// Wait all workers to finish
void Join()
{
_StopWorkers = true;
_WorkerNotifier.notify_all();
for (auto &thread : _Workers)
{
if (thread.joinable())
thread.join();
}
_Workers.clear();
}
std::size_t WorkerCount() const
{
return _Workers.size();
}
// Get the number of active workers
std::size_t ActiveCount() const
{
return _ActiveCount;
}
private:
void _WorkerLoop()
{
while (true)
{
auto task{ _NextTask() };
if (task)
{
++_ActiveCount;
task();
--_ActiveCount;
}
else if (_StopWorkers)
{
break;
}
}
}
task_t _NextTask()
{
std::unique_lock<std::mutex> lock{ _Mutex };
_WorkerNotifier.wait(lock, [this]() { return !_Tasks.empty() || _StopWorkers; });
if (_Tasks.empty())
return {};
auto task{ _Tasks.front() };
_Tasks.pop();
return task;
}
};
}

View File

@ -1,34 +0,0 @@
// Copyright 2006 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
#define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
#include "utf8/checked.h"
#include "utf8/unchecked.h"
#endif // header guard

View File

@ -1,336 +0,0 @@
// Copyright 2006-2016 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#include "core.h"
#include <stdexcept>
namespace utf8
{
// Base for the exceptions that may be thrown from the library
class exception : public ::std::exception {
};
// Exceptions that may be thrown from the library functions.
class invalid_code_point : public exception {
uint32_t cp;
public:
invalid_code_point(uint32_t codepoint) : cp(codepoint) {}
virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid code point"; }
uint32_t code_point() const {return cp;}
};
class invalid_utf8 : public exception {
uint8_t u8;
public:
invalid_utf8 (uint8_t u) : u8(u) {}
virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid UTF-8"; }
uint8_t utf8_octet() const {return u8;}
};
class invalid_utf16 : public exception {
uint16_t u16;
public:
invalid_utf16 (uint16_t u) : u16(u) {}
virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid UTF-16"; }
uint16_t utf16_word() const {return u16;}
};
class not_enough_room : public exception {
public:
virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Not enough space"; }
};
/// The library API - functions intended to be called by the users
template <typename octet_iterator>
octet_iterator append(uint32_t cp, octet_iterator result)
{
if (!utf8::internal::is_code_point_valid(cp))
throw invalid_code_point(cp);
if (cp < 0x80) // one octet
*(result++) = static_cast<uint8_t>(cp);
else if (cp < 0x800) { // two octets
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else if (cp < 0x10000) { // three octets
*(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else { // four octets
*(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
*(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
return result;
}
template <typename octet_iterator, typename output_iterator>
output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement)
{
while (start != end) {
octet_iterator sequence_start = start;
internal::utf_error err_code = utf8::internal::validate_next(start, end);
switch (err_code) {
case internal::UTF8_OK :
for (octet_iterator it = sequence_start; it != start; ++it)
*out++ = *it;
break;
case internal::NOT_ENOUGH_ROOM:
out = utf8::append (replacement, out);
start = end;
break;
case internal::INVALID_LEAD:
out = utf8::append (replacement, out);
++start;
break;
case internal::INCOMPLETE_SEQUENCE:
case internal::OVERLONG_SEQUENCE:
case internal::INVALID_CODE_POINT:
out = utf8::append (replacement, out);
++start;
// just one replacement mark for the sequence
while (start != end && utf8::internal::is_trail(*start))
++start;
break;
}
}
return out;
}
template <typename octet_iterator, typename output_iterator>
inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out)
{
static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd);
return utf8::replace_invalid(start, end, out, replacement_marker);
}
template <typename octet_iterator>
uint32_t next(octet_iterator& it, octet_iterator end)
{
uint32_t cp = 0;
internal::utf_error err_code = utf8::internal::validate_next(it, end, cp);
switch (err_code) {
case internal::UTF8_OK :
break;
case internal::NOT_ENOUGH_ROOM :
throw not_enough_room();
case internal::INVALID_LEAD :
case internal::INCOMPLETE_SEQUENCE :
case internal::OVERLONG_SEQUENCE :
throw invalid_utf8(*it);
case internal::INVALID_CODE_POINT :
throw invalid_code_point(cp);
}
return cp;
}
template <typename octet_iterator>
uint32_t peek_next(octet_iterator it, octet_iterator end)
{
return utf8::next(it, end);
}
template <typename octet_iterator>
uint32_t prior(octet_iterator& it, octet_iterator start)
{
// can't do much if it == start
if (it == start)
throw not_enough_room();
octet_iterator end = it;
// Go back until we hit either a lead octet or start
while (utf8::internal::is_trail(*(--it)))
if (it == start)
throw invalid_utf8(*it); // error - no lead byte in the sequence
return utf8::peek_next(it, end);
}
template <typename octet_iterator, typename distance_type>
void advance (octet_iterator& it, distance_type n, octet_iterator end)
{
const distance_type zero(0);
if (n < zero) {
// backward
for (distance_type i = n; i < zero; ++i)
utf8::prior(it, end);
} else {
// forward
for (distance_type i = zero; i < n; ++i)
utf8::next(it, end);
}
}
template <typename octet_iterator>
typename std::iterator_traits<octet_iterator>::difference_type
distance (octet_iterator first, octet_iterator last)
{
typename std::iterator_traits<octet_iterator>::difference_type dist;
for (dist = 0; first < last; ++dist)
utf8::next(first, last);
return dist;
}
template <typename u16bit_iterator, typename octet_iterator>
octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
{
while (start != end) {
uint32_t cp = utf8::internal::mask16(*start++);
// Take care of surrogate pairs first
if (utf8::internal::is_lead_surrogate(cp)) {
if (start != end) {
uint32_t trail_surrogate = utf8::internal::mask16(*start++);
if (utf8::internal::is_trail_surrogate(trail_surrogate))
cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
else
throw invalid_utf16(static_cast<uint16_t>(trail_surrogate));
}
else
throw invalid_utf16(static_cast<uint16_t>(cp));
}
// Lone trail surrogate
else if (utf8::internal::is_trail_surrogate(cp))
throw invalid_utf16(static_cast<uint16_t>(cp));
result = utf8::append(cp, result);
}
return result;
}
template <typename u16bit_iterator, typename octet_iterator>
u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
{
while (start < end) {
uint32_t cp = utf8::next(start, end);
if (cp > 0xffff) { //make a surrogate pair
*result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
*result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
}
else
*result++ = static_cast<uint16_t>(cp);
}
return result;
}
template <typename octet_iterator, typename u32bit_iterator>
octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
{
while (start != end)
result = utf8::append(*(start++), result);
return result;
}
template <typename octet_iterator, typename u32bit_iterator>
u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
{
while (start < end)
(*result++) = utf8::next(start, end);
return result;
}
// The iterator class
template <typename octet_iterator>
class iterator {
octet_iterator it;
octet_iterator range_start;
octet_iterator range_end;
public:
typedef uint32_t value_type;
typedef uint32_t* pointer;
typedef uint32_t& reference;
typedef std::ptrdiff_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
iterator () {}
explicit iterator (const octet_iterator& octet_it,
const octet_iterator& rangestart,
const octet_iterator& rangeend) :
it(octet_it), range_start(rangestart), range_end(rangeend)
{
if (it < range_start || it > range_end)
throw std::out_of_range("Invalid utf-8 iterator position");
}
// the default "big three" are OK
octet_iterator base () const { return it; }
uint32_t operator * () const
{
octet_iterator temp = it;
return utf8::next(temp, range_end);
}
bool operator == (const iterator& rhs) const
{
if (range_start != rhs.range_start || range_end != rhs.range_end)
throw std::logic_error("Comparing utf-8 iterators defined with different ranges");
return (it == rhs.it);
}
bool operator != (const iterator& rhs) const
{
return !(operator == (rhs));
}
iterator& operator ++ ()
{
utf8::next(it, range_end);
return *this;
}
iterator operator ++ (int)
{
iterator temp = *this;
utf8::next(it, range_end);
return temp;
}
iterator& operator -- ()
{
utf8::prior(it, range_start);
return *this;
}
iterator operator -- (int)
{
iterator temp = *this;
utf8::prior(it, range_start);
return temp;
}
}; // class iterator
} // namespace utf8
#if UTF_CPP_CPLUSPLUS >= 201703L // C++ 17 or later
#include "cpp17.h"
//#elif UTF_CPP_CPLUSPLUS >= 201103L // C++ 11 or later
#else
#include "cpp11.h"
#endif // C++ 11 or later
#endif //header guard

View File

@ -1,338 +0,0 @@
// Copyright 2006 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#include <iterator>
// Determine the C++ standard version.
// If the user defines UTF_CPP_CPLUSPLUS, use that.
// Otherwise, trust the unreliable predefined macro __cplusplus
#if !defined UTF_CPP_CPLUSPLUS
#define UTF_CPP_CPLUSPLUS __cplusplus
#endif
#if UTF_CPP_CPLUSPLUS >= 201103L // C++ 11 or later
#define UTF_CPP_OVERRIDE override
#define UTF_CPP_NOEXCEPT noexcept
#else // C++ 98/03
#define UTF_CPP_OVERRIDE
#define UTF_CPP_NOEXCEPT throw()
#endif // C++ 11 or later
namespace utf8
{
// The typedefs for 8-bit, 16-bit and 32-bit unsigned integers
// You may need to change them to match your system.
// These typedefs have the same names as ones from cstdint, or boost/cstdint
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
// Helper code - not intended to be directly called by the library users. May be changed at any time
namespace internal
{
// Unicode constants
// Leading (high) surrogates: 0xd800 - 0xdbff
// Trailing (low) surrogates: 0xdc00 - 0xdfff
const uint16_t LEAD_SURROGATE_MIN = 0xd800u;
const uint16_t LEAD_SURROGATE_MAX = 0xdbffu;
const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u;
const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu;
const uint16_t LEAD_OFFSET = 0xd7c0u; // LEAD_SURROGATE_MIN - (0x10000 >> 10)
const uint32_t SURROGATE_OFFSET = 0xfca02400u; // 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN
// Maximum valid value for a Unicode code point
const uint32_t CODE_POINT_MAX = 0x0010ffffu;
template<typename octet_type>
inline uint8_t mask8(octet_type oc)
{
return static_cast<uint8_t>(0xff & oc);
}
template<typename u16_type>
inline uint16_t mask16(u16_type oc)
{
return static_cast<uint16_t>(0xffff & oc);
}
template<typename octet_type>
inline bool is_trail(octet_type oc)
{
return ((utf8::internal::mask8(oc) >> 6) == 0x2);
}
template <typename u16>
inline bool is_lead_surrogate(u16 cp)
{
return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX);
}
template <typename u16>
inline bool is_trail_surrogate(u16 cp)
{
return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
}
template <typename u16>
inline bool is_surrogate(u16 cp)
{
return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
}
template <typename u32>
inline bool is_code_point_valid(u32 cp)
{
return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp));
}
template <typename octet_iterator>
inline typename std::iterator_traits<octet_iterator>::difference_type
sequence_length(octet_iterator lead_it)
{
uint8_t lead = utf8::internal::mask8(*lead_it);
if (lead < 0x80)
return 1;
else if ((lead >> 5) == 0x6)
return 2;
else if ((lead >> 4) == 0xe)
return 3;
else if ((lead >> 3) == 0x1e)
return 4;
else
return 0;
}
template <typename octet_difference_type>
inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length)
{
if (cp < 0x80) {
if (length != 1)
return true;
}
else if (cp < 0x800) {
if (length != 2)
return true;
}
else if (cp < 0x10000) {
if (length != 3)
return true;
}
return false;
}
enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT};
/// Helper for get_sequence_x
template <typename octet_iterator>
utf_error increase_safely(octet_iterator& it, octet_iterator end)
{
if (++it == end)
return NOT_ENOUGH_ROOM;
if (!utf8::internal::is_trail(*it))
return INCOMPLETE_SEQUENCE;
return UTF8_OK;
}
#define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;}
/// get_sequence_x functions decode utf-8 sequences of the length x
template <typename octet_iterator>
utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
return UTF8_OK;
}
template <typename octet_iterator>
utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f);
return UTF8_OK;
}
template <typename octet_iterator>
utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point += (*it) & 0x3f;
return UTF8_OK;
}
template <typename octet_iterator>
utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point += (utf8::internal::mask8(*it) << 6) & 0xfff;
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point += (*it) & 0x3f;
return UTF8_OK;
}
#undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR
template <typename octet_iterator>
utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
// Save the original value of it so we can go back in case of failure
// Of course, it does not make much sense with i.e. stream iterators
octet_iterator original_it = it;
uint32_t cp = 0;
// Determine the sequence length based on the lead octet
typedef typename std::iterator_traits<octet_iterator>::difference_type octet_difference_type;
const octet_difference_type length = utf8::internal::sequence_length(it);
// Get trail octets and calculate the code point
utf_error err = UTF8_OK;
switch (length) {
case 0:
return INVALID_LEAD;
case 1:
err = utf8::internal::get_sequence_1(it, end, cp);
break;
case 2:
err = utf8::internal::get_sequence_2(it, end, cp);
break;
case 3:
err = utf8::internal::get_sequence_3(it, end, cp);
break;
case 4:
err = utf8::internal::get_sequence_4(it, end, cp);
break;
}
if (err == UTF8_OK) {
// Decoding succeeded. Now, security checks...
if (utf8::internal::is_code_point_valid(cp)) {
if (!utf8::internal::is_overlong_sequence(cp, length)){
// Passed! Return here.
code_point = cp;
++it;
return UTF8_OK;
}
else
err = OVERLONG_SEQUENCE;
}
else
err = INVALID_CODE_POINT;
}
// Failure branch - restore the original value of the iterator
it = original_it;
return err;
}
template <typename octet_iterator>
inline utf_error validate_next(octet_iterator& it, octet_iterator end) {
uint32_t ignored;
return utf8::internal::validate_next(it, end, ignored);
}
} // namespace internal
/// The library API - functions intended to be called by the users
// Byte order mark
constexpr uint8_t bom[] = {0xef, 0xbb, 0xbf};
template <typename octet_iterator>
octet_iterator find_invalid(octet_iterator start, octet_iterator end)
{
octet_iterator result = start;
while (result != end) {
utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end);
if (err_code != internal::UTF8_OK)
return result;
}
return result;
}
template <typename octet_iterator>
inline bool is_valid(octet_iterator start, octet_iterator end)
{
return (utf8::find_invalid(start, end) == end);
}
template <typename octet_iterator>
inline bool starts_with_bom (octet_iterator it, octet_iterator end)
{
return (
((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) &&
((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) &&
((it != end) && (utf8::internal::mask8(*it)) == bom[2])
);
}
} // namespace utf8
#endif // header guard

View File

@ -1,103 +0,0 @@
// Copyright 2018 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_a184c22c_d012_11e8_a8d5_f2801f1b9fd1
#define UTF8_FOR_CPP_a184c22c_d012_11e8_a8d5_f2801f1b9fd1
#include "checked.h"
#include <string>
namespace utf8
{
inline void append(char32_t cp, std::string& s)
{
append(uint32_t(cp), std::back_inserter(s));
}
inline std::string utf16to8(const std::u16string& s)
{
std::string result;
utf16to8(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::u16string utf8to16(const std::string& s)
{
std::u16string result;
utf8to16(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::string utf32to8(const std::u32string& s)
{
std::string result;
utf32to8(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::u32string utf8to32(const std::string& s)
{
std::u32string result;
utf8to32(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::size_t find_invalid(const std::string& s)
{
std::string::const_iterator invalid = find_invalid(s.begin(), s.end());
return (invalid == s.end()) ? std::string::npos : (invalid - s.begin());
}
inline bool is_valid(const std::string& s)
{
return is_valid(s.begin(), s.end());
}
inline std::string replace_invalid(const std::string& s, char32_t replacement)
{
std::string result;
replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement);
return result;
}
inline std::string replace_invalid(const std::string& s)
{
std::string result;
replace_invalid(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline bool starts_with_bom(const std::string& s)
{
return starts_with_bom(s.begin(), s.end());
}
} // namespace utf8
#endif // header guard

View File

@ -1,103 +0,0 @@
// Copyright 2018 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_7e906c01_03a3_4daf_b420_ea7ea952b3c9
#define UTF8_FOR_CPP_7e906c01_03a3_4daf_b420_ea7ea952b3c9
#include "checked.h"
#include <string>
namespace utf8
{
inline void append(char32_t cp, std::string& s)
{
append(uint32_t(cp), std::back_inserter(s));
}
inline std::string utf16to8(std::u16string_view s)
{
std::string result;
utf16to8(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::u16string utf8to16(std::string_view s)
{
std::u16string result;
utf8to16(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::string utf32to8(std::u32string_view s)
{
std::string result;
utf32to8(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::u32string utf8to32(std::string_view s)
{
std::u32string result;
utf8to32(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::size_t find_invalid(std::string_view s)
{
std::string_view::const_iterator invalid = find_invalid(s.begin(), s.end());
return (invalid == s.end()) ? std::string_view::npos : (invalid - s.begin());
}
inline bool is_valid(std::string_view s)
{
return is_valid(s.begin(), s.end());
}
inline std::string replace_invalid(std::string_view s, char32_t replacement)
{
std::string result;
replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement);
return result;
}
inline std::string replace_invalid(std::string_view s)
{
std::string result;
replace_invalid(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline bool starts_with_bom(std::string_view s)
{
return starts_with_bom(s.begin(), s.end());
}
} // namespace utf8
#endif // header guard

View File

@ -1,274 +0,0 @@
// Copyright 2006 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#include "core.h"
namespace utf8
{
namespace unchecked
{
template <typename octet_iterator>
octet_iterator append(uint32_t cp, octet_iterator result)
{
if (cp < 0x80) // one octet
*(result++) = static_cast<uint8_t>(cp);
else if (cp < 0x800) { // two octets
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else if (cp < 0x10000) { // three octets
*(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else { // four octets
*(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
*(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f)| 0x80);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
return result;
}
template <typename octet_iterator, typename output_iterator>
output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement)
{
while (start != end) {
octet_iterator sequence_start = start;
internal::utf_error err_code = utf8::internal::validate_next(start, end);
switch (err_code) {
case internal::UTF8_OK :
for (octet_iterator it = sequence_start; it != start; ++it)
*out++ = *it;
break;
case internal::NOT_ENOUGH_ROOM:
out = utf8::unchecked::append (replacement, out);
start = end;
break;
case internal::INVALID_LEAD:
out = utf8::unchecked::append (replacement, out);
++start;
break;
case internal::INCOMPLETE_SEQUENCE:
case internal::OVERLONG_SEQUENCE:
case internal::INVALID_CODE_POINT:
out = utf8::unchecked::append (replacement, out);
++start;
// just one replacement mark for the sequence
while (start != end && utf8::internal::is_trail(*start))
++start;
break;
}
}
return out;
}
template <typename octet_iterator, typename output_iterator>
inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out)
{
static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd);
return utf8::unchecked::replace_invalid(start, end, out, replacement_marker);
}
template <typename octet_iterator>
uint32_t next(octet_iterator& it)
{
uint32_t cp = utf8::internal::mask8(*it);
typename std::iterator_traits<octet_iterator>::difference_type length = utf8::internal::sequence_length(it);
switch (length) {
case 1:
break;
case 2:
it++;
cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f);
break;
case 3:
++it;
cp = ((cp << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
++it;
cp += (*it) & 0x3f;
break;
case 4:
++it;
cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
++it;
cp += (utf8::internal::mask8(*it) << 6) & 0xfff;
++it;
cp += (*it) & 0x3f;
break;
}
++it;
return cp;
}
template <typename octet_iterator>
uint32_t peek_next(octet_iterator it)
{
return utf8::unchecked::next(it);
}
template <typename octet_iterator>
uint32_t prior(octet_iterator& it)
{
while (utf8::internal::is_trail(*(--it))) ;
octet_iterator temp = it;
return utf8::unchecked::next(temp);
}
template <typename octet_iterator, typename distance_type>
void advance (octet_iterator& it, distance_type n)
{
const distance_type zero(0);
if (n < zero) {
// backward
for (distance_type i = n; i < zero; ++i)
utf8::unchecked::prior(it);
} else {
// forward
for (distance_type i = zero; i < n; ++i)
utf8::unchecked::next(it);
}
}
template <typename octet_iterator>
typename std::iterator_traits<octet_iterator>::difference_type
distance (octet_iterator first, octet_iterator last)
{
typename std::iterator_traits<octet_iterator>::difference_type dist;
for (dist = 0; first < last; ++dist)
utf8::unchecked::next(first);
return dist;
}
template <typename u16bit_iterator, typename octet_iterator>
octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
{
while (start != end) {
uint32_t cp = utf8::internal::mask16(*start++);
// Take care of surrogate pairs first
if (utf8::internal::is_lead_surrogate(cp)) {
uint32_t trail_surrogate = utf8::internal::mask16(*start++);
cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
}
result = utf8::unchecked::append(cp, result);
}
return result;
}
template <typename u16bit_iterator, typename octet_iterator>
u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
{
while (start < end) {
uint32_t cp = utf8::unchecked::next(start);
if (cp > 0xffff) { //make a surrogate pair
*result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
*result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
}
else
*result++ = static_cast<uint16_t>(cp);
}
return result;
}
template <typename octet_iterator, typename u32bit_iterator>
octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
{
while (start != end)
result = utf8::unchecked::append(*(start++), result);
return result;
}
template <typename octet_iterator, typename u32bit_iterator>
u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
{
while (start < end)
(*result++) = utf8::unchecked::next(start);
return result;
}
// The iterator class
template <typename octet_iterator>
class iterator {
octet_iterator it;
public:
typedef uint32_t value_type;
typedef uint32_t* pointer;
typedef uint32_t& reference;
typedef std::ptrdiff_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
iterator () {}
explicit iterator (const octet_iterator& octet_it): it(octet_it) {}
// the default "big three" are OK
octet_iterator base () const { return it; }
uint32_t operator * () const
{
octet_iterator temp = it;
return utf8::unchecked::next(temp);
}
bool operator == (const iterator& rhs) const
{
return (it == rhs.it);
}
bool operator != (const iterator& rhs) const
{
return !(operator == (rhs));
}
iterator& operator ++ ()
{
::std::advance(it, utf8::internal::sequence_length(it));
return *this;
}
iterator operator ++ (int)
{
iterator temp = *this;
::std::advance(it, utf8::internal::sequence_length(it));
return temp;
}
iterator& operator -- ()
{
utf8::unchecked::prior(it);
return *this;
}
iterator operator -- (int)
{
iterator temp = *this;
utf8::unchecked::prior(it);
return temp;
}
}; // class iterator
} // namespace utf8::unchecked
} // namespace utf8
#endif // header guard

File diff suppressed because one or more lines are too long

View File

@ -1,237 +0,0 @@
/*
* Copyright (C) 2019-2020 Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include <glad/gl.h>
#include "OpenGLX_Hook.h"
#include "X11_Hook.h"
#include <imgui.h>
#include <backends/imgui_impl_opengl3.h>
OpenGLX_Hook* OpenGLX_Hook::_inst = nullptr;
constexpr decltype(OpenGLX_Hook::DLL_NAME) OpenGLX_Hook::DLL_NAME;
bool OpenGLX_Hook::StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys)
{
if (!_Hooked)
{
if (glXSwapBuffers == nullptr)
{
SPDLOG_WARN("Failed to hook OpenGLX: Rendering functions missing.");
return false;
}
if (!X11_Hook::Inst()->StartHook(key_combination_callback, toggle_keys))
return false;
_X11Hooked = true;
SPDLOG_INFO("Hooked OpenGLX");
_Hooked = true;
UnhookAll();
BeginHook();
HookFuncs(
std::make_pair<void**, void*>((void**)&glXSwapBuffers, (void*)&OpenGLX_Hook::MyglXSwapBuffers)
);
EndHook();
}
return true;
}
bool OpenGLX_Hook::IsStarted()
{
return _Hooked;
}
void OpenGLX_Hook::_ResetRenderState()
{
if (_Initialized)
{
OverlayHookReady(false);
ImGui_ImplOpenGL3_Shutdown();
X11_Hook::Inst()->ResetRenderState();
ImGui::DestroyContext();
glXDestroyContext(_Display, _Context);
_Display = nullptr;
_Initialized = false;
}
}
// Try to make this function and overlay's proc as short as possible or it might affect game's fps.
void OpenGLX_Hook::_PrepareForOverlay(Display* display, GLXDrawable drawable)
{
if( !_Initialized )
{
ImGui::CreateContext((ImFontAtlas *)ImGuiFontAtlas);
ImGui_ImplOpenGL3_Init();
//int attributes[] = { //can't be const b/c X11 doesn't like it. Not sure if that's intentional or just stupid.
// GLX_RGBA, //apparently nothing comes after this?
// GLX_RED_SIZE, 8,
// GLX_GREEN_SIZE, 8,
// GLX_BLUE_SIZE, 8,
// GLX_ALPHA_SIZE, 8,
// //Ideally, the size would be 32 (or at least 24), but I have actually seen
// // this size (on a modern OS even).
// GLX_DEPTH_SIZE, 16,
// GLX_DOUBLEBUFFER, True,
// None
//};
//
//XVisualInfo* visual_info = glXChooseVisual(_Display, DefaultScreen(_Display), attributes);
//if (visual_info == nullptr)
// return;
//
//_Context = glXCreateContext(_Display, visual_info, nullptr, True);
//if (_Context == nullptr)
// return;
_Display = display;
X11_Hook::Inst()->SetInitialWindowSize(_Display, (Window)drawable);
_Initialized = true;
OverlayHookReady(true);
}
//auto oldContext = glXGetCurrentContext();
//glXMakeCurrent(_Display, drawable, _Context);
if (ImGui_ImplOpenGL3_NewFrame() && X11_Hook::Inst()->PrepareForOverlay(_Display, (Window)drawable))
{
ImGui::NewFrame();
OverlayProc();
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
}
//glXMakeCurrent(_Display, drawable, oldContext);
}
void OpenGLX_Hook::MyglXSwapBuffers(Display* display, GLXDrawable drawable)
{
OpenGLX_Hook::Inst()->_PrepareForOverlay(display, drawable);
OpenGLX_Hook::Inst()->glXSwapBuffers(display, drawable);
}
OpenGLX_Hook::OpenGLX_Hook():
_Initialized(false),
_Hooked(false),
_X11Hooked(false),
glXSwapBuffers(nullptr)
{
//_library = dlopen(DLL_NAME);
}
OpenGLX_Hook::~OpenGLX_Hook()
{
SPDLOG_INFO("OpenGLX Hook removed");
if (_X11Hooked)
delete X11_Hook::Inst();
if (_Initialized)
{
ImGui_ImplOpenGL3_Shutdown();
ImGui::DestroyContext();
glXDestroyContext(_Display, _Context);
}
//dlclose(_library);
_inst = nullptr;
}
OpenGLX_Hook* OpenGLX_Hook::Inst()
{
if (_inst == nullptr)
_inst = new OpenGLX_Hook;
return _inst;
}
std::string OpenGLX_Hook::GetLibraryName() const
{
return LibraryName;
}
void OpenGLX_Hook::LoadFunctions(decltype(::glXSwapBuffers)* pfnglXSwapBuffers)
{
glXSwapBuffers = pfnglXSwapBuffers;
}
std::weak_ptr<uint64_t> OpenGLX_Hook::CreateImageResource(const void* image_data, uint32_t width, uint32_t height)
{
GLuint* texture = new GLuint(0);
glGenTextures(1, texture);
if (glGetError() != GL_NO_ERROR)
{
delete texture;
return std::shared_ptr<uint64_t>(nullptr);
}
// Save old texture id
GLint oldTex;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTex);
glBindTexture(GL_TEXTURE_2D, *texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Upload pixels into texture
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
glBindTexture(GL_TEXTURE_2D, oldTex);
auto ptr = std::shared_ptr<uint64_t>((uint64_t*)texture, [](uint64_t* handle)
{
if (handle != nullptr)
{
GLuint* texture = (GLuint*)handle;
glDeleteTextures(1, texture);
delete texture;
}
});
_ImageResources.emplace(ptr);
return ptr;
}
void OpenGLX_Hook::ReleaseImageResource(std::weak_ptr<uint64_t> resource)
{
auto ptr = resource.lock();
if (ptr)
{
auto it = _ImageResources.find(ptr);
if (it != _ImageResources.end())
_ImageResources.erase(it);
}
}

View File

@ -1,70 +0,0 @@
/*
* Copyright (C) 2019-2020 Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <ingame_overlay/Renderer_Hook.h>
#include "overlay/internal_includes.h"
#include <GL/glx.h>
class OpenGLX_Hook :
public ingame_overlay::Renderer_Hook,
public Base_Hook
{
public:
static constexpr const char *DLL_NAME = "libGLX.so";
private:
static OpenGLX_Hook* _inst;
// Variables
bool _Hooked;
bool _X11Hooked;
bool _Initialized;
Display *_Display;
GLXContext _Context;
std::set<std::shared_ptr<uint64_t>> _ImageResources;
// Functions
OpenGLX_Hook();
void _ResetRenderState();
void _PrepareForOverlay(Display* display, GLXDrawable drawable);
// Hook to render functions
decltype(::glXSwapBuffers)* glXSwapBuffers;
public:
std::string LibraryName;
static void MyglXSwapBuffers(Display* display, GLXDrawable drawable);
virtual ~OpenGLX_Hook();
virtual bool StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys);
virtual bool IsStarted();
static OpenGLX_Hook* Inst();
virtual std::string GetLibraryName() const;
void LoadFunctions(decltype(::glXSwapBuffers)* pfnglXSwapBuffers);
virtual std::weak_ptr<uint64_t> CreateImageResource(const void* image_data, uint32_t width, uint32_t height);
virtual void ReleaseImageResource(std::weak_ptr<uint64_t> resource);
};

View File

@ -1,333 +0,0 @@
/*
* Copyright (C) 2019-2020 Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "X11_Hook.h"
#include <imgui.h>
#include <backends/imgui_impl_x11.h>
#include <System/Library.h>
extern int ImGui_ImplX11_EventHandler(XEvent &event);
constexpr decltype(X11_Hook::DLL_NAME) X11_Hook::DLL_NAME;
X11_Hook* X11_Hook::_inst = nullptr;
uint32_t ToggleKeyToNativeKey(ingame_overlay::ToggleKey k)
{
struct {
ingame_overlay::ToggleKey lib_key;
uint32_t native_key;
} mapping[] = {
{ ingame_overlay::ToggleKey::ALT , XK_Alt_L },
{ ingame_overlay::ToggleKey::CTRL , XK_Control_L },
{ ingame_overlay::ToggleKey::SHIFT, XK_Shift_L },
{ ingame_overlay::ToggleKey::TAB , XK_Tab },
{ ingame_overlay::ToggleKey::F1 , XK_F1 },
{ ingame_overlay::ToggleKey::F2 , XK_F2 },
{ ingame_overlay::ToggleKey::F3 , XK_F3 },
{ ingame_overlay::ToggleKey::F4 , XK_F4 },
{ ingame_overlay::ToggleKey::F5 , XK_F5 },
{ ingame_overlay::ToggleKey::F6 , XK_F6 },
{ ingame_overlay::ToggleKey::F7 , XK_F7 },
{ ingame_overlay::ToggleKey::F8 , XK_F8 },
{ ingame_overlay::ToggleKey::F9 , XK_F9 },
{ ingame_overlay::ToggleKey::F10 , XK_F10 },
{ ingame_overlay::ToggleKey::F11 , XK_F11 },
{ ingame_overlay::ToggleKey::F12 , XK_F12 },
};
for (auto const& item : mapping)
{
if (item.lib_key == k)
return item.native_key;
}
return 0;
}
bool GetKeyState(Display* d, KeySym keySym, char szKey[32])
{
int iKeyCodeToFind = XKeysymToKeycode(d, keySym);
return szKey[iKeyCodeToFind / 8] & (1 << (iKeyCodeToFind % 8));
}
bool X11_Hook::StartHook(std::function<bool(bool)>& _key_combination_callback, std::set<ingame_overlay::ToggleKey> const& toggle_keys)
{
if (!_Hooked)
{
if (!_key_combination_callback)
{
SPDLOG_ERROR("Failed to hook X11: No key combination callback.");
return false;
}
if (toggle_keys.empty())
{
SPDLOG_ERROR("Failed to hook X11: No key combination.");
return false;
}
void* hX11 = System::Library::GetLibraryHandle(DLL_NAME);
if (hX11 == nullptr)
{
SPDLOG_WARN("Failed to hook X11: Cannot find {}", DLL_NAME);
return false;
}
System::Library::Library libX11;
LibraryName = System::Library::GetLibraryPath(hX11);
if (!libX11.OpenLibrary(LibraryName, false))
{
SPDLOG_WARN("Failed to hook X11: Cannot load {}", LibraryName);
return false;
}
struct {
void** func_ptr;
void* hook_ptr;
const char* func_name;
} hook_array[] = {
{ (void**)&XEventsQueued, &X11_Hook::MyXEventsQueued, "XEventsQueued" },
{ (void**)&XPending , &X11_Hook::MyXPending , "XPending" },
};
for (auto& entry : hook_array)
{
*entry.func_ptr = libX11.GetSymbol<void*>(entry.func_name);
if (entry.func_ptr == nullptr)
{
SPDLOG_ERROR("Failed to hook X11: Event function {} missing.", entry.func_name);
return false;
}
}
SPDLOG_INFO("Hooked X11");
_KeyCombinationCallback = std::move(_key_combination_callback);
for (auto& key : toggle_keys)
{
uint32_t k = ToggleKeyToNativeKey(key);
if (k != 0)
{
_NativeKeyCombination.insert(k);
}
}
_Hooked = true;
BeginHook();
for (auto& entry : hook_array)
{
HookFunc(std::make_pair(entry.func_ptr, entry.hook_ptr));
}
EndHook();
}
return true;
}
void X11_Hook::ResetRenderState()
{
if (_Initialized)
{
_GameWnd = 0;
_Initialized = false;
ImGui_ImplX11_Shutdown();
}
}
void X11_Hook::SetInitialWindowSize(Display* display, Window wnd)
{
unsigned int width, height;
Window unused_window;
int unused_int;
unsigned int unused_unsigned_int;
XGetGeometry(display, wnd, &unused_window, &unused_int, &unused_int, &width, &height, &unused_unsigned_int, &unused_unsigned_int);
ImGui::GetIO().DisplaySize = ImVec2((float)width, (float)height);
}
bool X11_Hook::PrepareForOverlay(Display *display, Window wnd)
{
if(!_Hooked)
return false;
if (_GameWnd != wnd)
ResetRenderState();
if (!_Initialized)
{
ImGui_ImplX11_Init(display, (void*)wnd);
_GameWnd = wnd;
_Initialized = true;
}
ImGui_ImplX11_NewFrame();
return true;
}
/////////////////////////////////////////////////////////////////////////////////////
// X11 window hooks
bool IgnoreEvent(XEvent &event)
{
switch(event.type)
{
// Keyboard
case KeyPress: case KeyRelease:
// MouseButton
case ButtonPress: case ButtonRelease:
// Mouse move
case MotionNotify:
// Copy to clipboard request
case SelectionRequest:
return true;
}
return false;
}
int X11_Hook::_CheckForOverlay(Display *d, int num_events)
{
static Time prev_time = {};
X11_Hook* inst = Inst();
char szKey[32];
if( _Initialized )
{
XEvent event;
while(num_events)
{
bool skip_input = _KeyCombinationCallback(false);
XPeekEvent(d, &event);
ImGui_ImplX11_EventHandler(event);
// Is the event is a key press
if (event.type == KeyPress || event.type == KeyRelease)
{
XQueryKeymap(d, szKey);
int key_count = 0;
for (auto const& key : inst->_NativeKeyCombination)
{
if (GetKeyState(d, key, szKey))
++key_count;
}
if (key_count == inst->_NativeKeyCombination.size())
{// All shortcut keys are pressed
if (!inst->_KeyCombinationPushed)
{
if (inst->_KeyCombinationCallback(true))
{
skip_input = true;
// Save the last known cursor pos when opening the overlay
// so we can spoof the GetCursorPos return value.
//inst->GetCursorPos(&inst->_SavedCursorPos);
}
inst->_KeyCombinationPushed = true;
}
}
else
{
inst->_KeyCombinationPushed = false;
}
}
if (!skip_input || !IgnoreEvent(event))
{
if(num_events)
num_events = 1;
break;
}
XNextEvent(d, &event);
--num_events;
}
}
return num_events;
}
int X11_Hook::MyXEventsQueued(Display *display, int mode)
{
X11_Hook* inst = X11_Hook::Inst();
int res = inst->XEventsQueued(display, mode);
if( res )
{
res = inst->_CheckForOverlay(display, res);
}
return res;
}
int X11_Hook::MyXPending(Display* display)
{
int res = Inst()->XPending(display);
if( res )
{
res = Inst()->_CheckForOverlay(display, res);
}
return res;
}
/////////////////////////////////////////////////////////////////////////////////////
X11_Hook::X11_Hook() :
_Initialized(false),
_Hooked(false),
_GameWnd(0),
_KeyCombinationPushed(false),
XEventsQueued(nullptr),
XPending(nullptr)
{
}
X11_Hook::~X11_Hook()
{
SPDLOG_INFO("X11 Hook removed");
ResetRenderState();
_inst = nullptr;
}
X11_Hook* X11_Hook::Inst()
{
if (_inst == nullptr)
_inst = new X11_Hook;
return _inst;
}
std::string X11_Hook::GetLibraryName() const
{
return LibraryName;
}

View File

@ -1,75 +0,0 @@
/*
* Copyright (C) 2019-2020 Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <ingame_overlay/Renderer_Hook.h>
#include "overlay/internal_includes.h"
#include <X11/X.h> // XEvent types
#include <X11/Xlib.h> // XEvent structure
#include <X11/Xutil.h> // XEvent keysym
class X11_Hook :
public Base_Hook
{
public:
static constexpr const char* DLL_NAME = "libX11.so";
private:
static X11_Hook* _inst;
// Variables
bool _Hooked;
bool _Initialized;
Window _GameWnd;
// In (bool): Is toggle wanted
// Out(bool): Is the overlay visible, if true, inputs will be disabled
std::function<bool(bool)> _KeyCombinationCallback;
std::set<uint32_t> _NativeKeyCombination;
bool _KeyCombinationPushed;
// Functions
X11_Hook();
int _CheckForOverlay(Display *d, int num_events);
// Hook to X11 window messages
decltype(::XEventsQueued)* XEventsQueued;
decltype(::XPending)* XPending;
static int MyXEventsQueued(Display * display, int mode);
static int MyXPending(Display* display);
public:
std::string LibraryName;
virtual ~X11_Hook();
void ResetRenderState();
void SetInitialWindowSize(Display* display, Window wnd);
bool PrepareForOverlay(Display *display, Window wnd);
Window GetGameWnd() const{ return _GameWnd; }
bool StartHook(std::function<bool(bool)>& key_combination_callback, std::set<ingame_overlay::ToggleKey> const& toggle_keys);
static X11_Hook* Inst();
virtual std::string GetLibraryName() const;
};

View File

@ -1,47 +0,0 @@
#ifndef __INCLUDED_BASE_HOOK_H__
#define __INCLUDED_BASE_HOOK_H__
#include "dll/base.h"
#ifdef EMU_OVERLAY
class Base_Hook
{
protected:
std::vector<std::pair<void**, void*>> _hooked_funcs;
void* _library;
Base_Hook(const Base_Hook&) = delete;
Base_Hook(Base_Hook&&) = delete;
Base_Hook& operator =(const Base_Hook&) = delete;
Base_Hook& operator =(Base_Hook&&) = delete;
public:
Base_Hook();
virtual ~Base_Hook();
void BeginHook();
void EndHook();
void UnhookAll();
virtual const char* get_lib_name() const;
void HookFunc(std::pair<void**, void*> hook);
template<typename T>
void HookFuncs(std::pair<T*, T> funcs)
{
HookFunc(funcs);
}
template<typename T, typename ...Args>
void HookFuncs(std::pair<T*, T> funcs, Args... args)
{
HookFunc(funcs);
HookFuncs(args...);
}
};
#endif//EMU_OVERLAY
#endif//__INCLUDED_BASE_HOOK_H__

View File

@ -1,36 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "dll/base.h"
#include <future>
#include <chrono>
#include <memory>
#include "Renderer_Hook.h"
namespace ingame_overlay {
std::future<Renderer_Hook*> DetectRenderer(std::chrono::milliseconds timeout = std::chrono::milliseconds{ -1 });
void StopRendererDetection();
void FreeDetector();
}

View File

@ -1,61 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <functional>
#include <string>
#include <memory>
#include <cstdint>
#include <set>
namespace ingame_overlay {
enum class ToggleKey
{
SHIFT, CTRL, ALT,
TAB,
F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
};
class Renderer_Hook
{
public:
Renderer_Hook():
OverlayProc(&DefaultOverlayProc),
OverlayHookReady(&DefaultOverlayHookReady),
ImGuiFontAtlas(nullptr)
{}
static void DefaultOverlayProc() {}
static void DefaultOverlayHookReady(bool) {}
std::function<void()> OverlayProc;
std::function<void(bool)> OverlayHookReady;
void *ImGuiFontAtlas;
virtual bool StartHook(std::function<bool(bool)> key_combination_callback, std::set<ToggleKey> toggle_keys) = 0;
virtual bool IsStarted() = 0;
// Returns a Handle to the renderer image ressource or nullptr if it failed to create the resource, the handle can be used in ImGui's Image calls, image_buffer must be RGBA ordered
virtual std::weak_ptr<uint64_t> CreateImageResource(const void* image_data, uint32_t width, uint32_t height) = 0;
virtual void ReleaseImageResource(std::weak_ptr<uint64_t> resource) = 0;
virtual std::string GetLibraryName() const = 0;
};
}

View File

@ -1,55 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <set>
#include "Base_Hook.h"
#include "Renderer_Hook.h"
#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64)
#include <windows.h>
#ifdef GetModuleHandle
#undef GetModuleHandle
#endif
#endif
#ifdef USE_SPDLOG
#define SPDLOG_ACTIVE_LEVEL 0
#include <spdlog/spdlog.h>
#endif
#ifndef SPDLOG_TRACE
#define SPDLOG_TRACE(x, ...) PRINT_DEBUG(x "\n", __VA_ARGS__)
#endif
#ifndef SPDLOG_DEBUG
#define SPDLOG_DEBUG(x, ...) PRINT_DEBUG(x "\n", __VA_ARGS__)
#endif
#ifndef SPDLOG_INFO
#define SPDLOG_INFO(x, ...) PRINT_DEBUG(x "\n", __VA_ARGS__)
#endif
#ifndef SPDLOG_WARN
#define SPDLOG_WARN(x, ...) PRINT_DEBUG(x "\n", __VA_ARGS__)
#endif
#ifndef SPDLOG_ERROR
#define SPDLOG_ERROR(x, ...) PRINT_DEBUG(x "\n", __VA_ARGS__)
#endif

View File

@ -1,290 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "DX10_Hook.h"
#include "Windows_Hook.h"
#include <imgui.h>
#include <backends/imgui_impl_dx10.h>
DX10_Hook* DX10_Hook::_inst = nullptr;
template<typename T>
inline void SafeRelease(T*& pUnk)
{
if (pUnk != nullptr)
{
pUnk->Release();
pUnk = nullptr;
}
}
bool DX10_Hook::StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys)
{
if (!_Hooked)
{
if (Present == nullptr || ResizeTarget == nullptr || ResizeBuffers == nullptr)
{
SPDLOG_WARN("Failed to hook DirectX 11: Rendering functions missing.");
return false;
}
if (!Windows_Hook::Inst()->StartHook(key_combination_callback, toggle_keys))
return false;
_WindowsHooked = true;
SPDLOG_INFO("Hooked DirectX 10");
_Hooked = true;
BeginHook();
HookFuncs(
std::make_pair<void**, void*>(&(PVOID&)Present , &DX10_Hook::MyPresent),
std::make_pair<void**, void*>(&(PVOID&)ResizeTarget , &DX10_Hook::MyResizeTarget),
std::make_pair<void**, void*>(&(PVOID&)ResizeBuffers, &DX10_Hook::MyResizeBuffers)
);
if (Present1 != nullptr)
{
HookFuncs(
std::make_pair<void**, void*>(&(PVOID&)Present1, &DX10_Hook::MyPresent1)
);
}
EndHook();
}
return true;
}
bool DX10_Hook::IsStarted()
{
return _Hooked;
}
void DX10_Hook::_ResetRenderState()
{
if (_Initialized)
{
OverlayHookReady(false);
ImGui_ImplDX10_Shutdown();
Windows_Hook::Inst()->ResetRenderState();
ImGui::DestroyContext();
SafeRelease(mainRenderTargetView);
SafeRelease(pDevice);
_Initialized = false;
}
}
// Try to make this function and overlay's proc as short as possible or it might affect game's fps.
void DX10_Hook::_PrepareForOverlay(IDXGISwapChain* pSwapChain)
{
DXGI_SWAP_CHAIN_DESC desc;
pSwapChain->GetDesc(&desc);
if (!_Initialized)
{
if (FAILED(pSwapChain->GetDevice(IID_PPV_ARGS(&pDevice))))
return;
ID3D10Texture2D* pBackBuffer = nullptr;
pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
if (pBackBuffer == nullptr)
{
pDevice->Release();
return;
}
pDevice->CreateRenderTargetView(pBackBuffer, nullptr, &mainRenderTargetView);
pBackBuffer->Release();
ImGui::CreateContext((ImFontAtlas *)ImGuiFontAtlas);
ImGui_ImplDX10_Init(pDevice);
Windows_Hook::Inst()->SetInitialWindowSize(desc.OutputWindow);
_Initialized = true;
OverlayHookReady(true);
}
if (ImGui_ImplDX10_NewFrame() && Windows_Hook::Inst()->PrepareForOverlay(desc.OutputWindow))
{
ImGui::NewFrame();
OverlayProc();
ImGui::Render();
pDevice->OMSetRenderTargets(1, &mainRenderTargetView, nullptr);
ImGui_ImplDX10_RenderDrawData(ImGui::GetDrawData());
}
}
HRESULT STDMETHODCALLTYPE DX10_Hook::MyPresent(IDXGISwapChain *_this, UINT SyncInterval, UINT Flags)
{
auto inst= DX10_Hook::Inst();
inst->_PrepareForOverlay(_this);
return (_this->*inst->Present)(SyncInterval, Flags);
}
HRESULT STDMETHODCALLTYPE DX10_Hook::MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters)
{
auto inst= DX10_Hook::Inst();
inst->_ResetRenderState();
return (_this->*inst->ResizeTarget)(pNewTargetParameters);
}
HRESULT STDMETHODCALLTYPE DX10_Hook::MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags)
{
auto inst= DX10_Hook::Inst();
inst->_ResetRenderState();
return (_this->*inst->ResizeBuffers)(BufferCount, Width, Height, NewFormat, SwapChainFlags);
}
HRESULT STDMETHODCALLTYPE DX10_Hook::MyPresent1(IDXGISwapChain1* _this, UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters)
{
auto inst = DX10_Hook::Inst();
inst->_PrepareForOverlay(_this);
return (_this->*inst->Present1)(SyncInterval, Flags, pPresentParameters);
}
DX10_Hook::DX10_Hook():
_Initialized(false),
_Hooked(false),
_WindowsHooked(false),
pDevice(nullptr),
mainRenderTargetView(nullptr),
Present(nullptr),
ResizeBuffers(nullptr),
ResizeTarget(nullptr),
Present1(nullptr)
{
}
DX10_Hook::~DX10_Hook()
{
//SPDLOG_INFO("DX10 Hook removed");
if (_WindowsHooked)
delete Windows_Hook::Inst();
if (_Initialized)
{
mainRenderTargetView->Release();
ImGui_ImplDX10_InvalidateDeviceObjects();
ImGui::DestroyContext();
_Initialized = false;
}
_inst = nullptr;
}
DX10_Hook* DX10_Hook::Inst()
{
if (_inst == nullptr)
_inst = new DX10_Hook;
return _inst;
}
std::string DX10_Hook::GetLibraryName() const
{
return LibraryName;
}
void DX10_Hook::LoadFunctions(
decltype(Present) PresentFcn,
decltype(ResizeBuffers) ResizeBuffersFcn,
decltype(ResizeTarget) ResizeTargetFcn,
decltype(Present1) Present1Fcn)
{
Present = PresentFcn;
ResizeBuffers = ResizeBuffersFcn;
ResizeTarget = ResizeTargetFcn;
Present1 = Present1Fcn;
}
std::weak_ptr<uint64_t> DX10_Hook::CreateImageResource(const void* image_data, uint32_t width, uint32_t height)
{
ID3D10ShaderResourceView** resource = new ID3D10ShaderResourceView*(nullptr);
// Create texture
D3D10_TEXTURE2D_DESC desc = {};
desc.Width = static_cast<UINT>(width);
desc.Height = static_cast<UINT>(height);
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.Usage = D3D10_USAGE_DEFAULT;
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
ID3D10Texture2D* pTexture = nullptr;
D3D10_SUBRESOURCE_DATA subResource;
subResource.pSysMem = image_data;
subResource.SysMemPitch = desc.Width * 4;
subResource.SysMemSlicePitch = 0;
pDevice->CreateTexture2D(&desc, &subResource, &pTexture);
if (pTexture != nullptr)
{
// Create texture view
D3D10_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srvDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = desc.MipLevels;
srvDesc.Texture2D.MostDetailedMip = 0;
pDevice->CreateShaderResourceView(pTexture, &srvDesc, resource);
// Release Texure, the shader resource increases the reference count.
pTexture->Release();
}
if (*resource == nullptr)
return std::shared_ptr<uint64_t>();
auto ptr = std::shared_ptr<uint64_t>((uint64_t*)resource, [](uint64_t* handle)
{
if (handle != nullptr)
{
ID3D10ShaderResourceView** resource = reinterpret_cast<ID3D10ShaderResourceView**>(handle);
(*resource)->Release();
delete resource;
}
});
_ImageResources.emplace(ptr);
return ptr;
}
void DX10_Hook::ReleaseImageResource(std::weak_ptr<uint64_t> resource)
{
auto ptr = resource.lock();
if (ptr)
{
auto it = _ImageResources.find(ptr);
if (it != _ImageResources.end())
_ImageResources.erase(it);
}
}

View File

@ -1,80 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "overlay/internal_includes.h"
#include <d3d10.h>
#include <dxgi1_2.h>
class DX10_Hook :
public ingame_overlay::Renderer_Hook,
public Base_Hook
{
public:
static constexpr const char *DLL_NAME = "d3d10.dll";
private:
static DX10_Hook* _inst;
// Variables
bool _Hooked;
bool _WindowsHooked;
bool _Initialized;
ID3D10Device* pDevice;
ID3D10RenderTargetView* mainRenderTargetView;
std::set<std::shared_ptr<uint64_t>> _ImageResources;
// Functions
DX10_Hook();
void _ResetRenderState();
void _PrepareForOverlay(IDXGISwapChain *pSwapChain);
// Hook to render functions
static HRESULT STDMETHODCALLTYPE MyPresent(IDXGISwapChain* _this, UINT SyncInterval, UINT Flags);
static HRESULT STDMETHODCALLTYPE MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters);
static HRESULT STDMETHODCALLTYPE MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags);
static HRESULT STDMETHODCALLTYPE MyPresent1(IDXGISwapChain1* _this, UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters);
decltype(&IDXGISwapChain::Present) Present;
decltype(&IDXGISwapChain::ResizeBuffers) ResizeBuffers;
decltype(&IDXGISwapChain::ResizeTarget) ResizeTarget;
decltype(&IDXGISwapChain1::Present1) Present1;
public:
std::string LibraryName;
virtual ~DX10_Hook();
virtual bool StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys);
virtual bool IsStarted();
static DX10_Hook* Inst();
virtual std::string GetLibraryName() const;
void LoadFunctions(
decltype(Present) PresentFcn,
decltype(ResizeBuffers) ResizeBuffersFcn,
decltype(ResizeTarget) ResizeTargetFcn,
decltype(Present1) Present1Fcn);
virtual std::weak_ptr<uint64_t> CreateImageResource(const void* image_data, uint32_t width, uint32_t height);
virtual void ReleaseImageResource(std::weak_ptr<uint64_t> resource);
};

View File

@ -1,328 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "DX11_Hook.h"
#include "Windows_Hook.h"
#include <imgui.h>
#include <backends/imgui_impl_dx11.h>
DX11_Hook* DX11_Hook::_inst = nullptr;
template<typename T>
inline void SafeRelease(T*& pUnk)
{
if (pUnk != nullptr)
{
pUnk->Release();
pUnk = nullptr;
}
}
static HRESULT GetDeviceAndCtxFromSwapchain(IDXGISwapChain* pSwapChain, ID3D11Device** ppDevice, ID3D11DeviceContext** ppContext)
{
HRESULT ret = pSwapChain->GetDevice(IID_PPV_ARGS(ppDevice));
if (SUCCEEDED(ret))
(*ppDevice)->GetImmediateContext(ppContext);
return ret;
}
bool DX11_Hook::StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys)
{
if (!_Hooked)
{
if (Present == nullptr || ResizeTarget == nullptr || ResizeBuffers == nullptr)
{
SPDLOG_WARN("Failed to hook DirectX 11: Rendering functions missing.");
return false;
}
if (!Windows_Hook::Inst()->StartHook(key_combination_callback, toggle_keys))
return false;
_WindowsHooked = true;
SPDLOG_INFO("Hooked DirectX 11");
_Hooked = true;
BeginHook();
HookFuncs(
std::make_pair<void**, void*>(&(PVOID&)Present , &DX11_Hook::MyPresent),
std::make_pair<void**, void*>(&(PVOID&)ResizeTarget , &DX11_Hook::MyResizeTarget),
std::make_pair<void**, void*>(&(PVOID&)ResizeBuffers, &DX11_Hook::MyResizeBuffers)
);
if (Present1 != nullptr)
{
HookFuncs(
std::make_pair<void**, void*>(&(PVOID&)Present1, &DX11_Hook::MyPresent1)
);
}
EndHook();
}
return true;
}
bool DX11_Hook::IsStarted()
{
return _Hooked;
}
void DX11_Hook::_ResetRenderState()
{
if (_Initialized)
{
OverlayHookReady(false);
ImGui_ImplDX11_Shutdown();
Windows_Hook::Inst()->ResetRenderState();
//ImGui::DestroyContext();
SafeRelease(mainRenderTargetView);
SafeRelease(pContext);
SafeRelease(pDevice);
_Initialized = false;
}
}
// Try to make this function and overlay's proc as short as possible or it might affect game's fps.
void DX11_Hook::_PrepareForOverlay(IDXGISwapChain* pSwapChain)
{
DXGI_SWAP_CHAIN_DESC desc;
pSwapChain->GetDesc(&desc);
if (!_Initialized)
{
pDevice = nullptr;
if (FAILED(GetDeviceAndCtxFromSwapchain(pSwapChain, &pDevice, &pContext)))
return;
ID3D11Texture2D* pBackBuffer;
pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
pDevice->CreateRenderTargetView(pBackBuffer, NULL, &mainRenderTargetView);
//ID3D11RenderTargetView* targets[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = {};
//pContext->OMGetRenderTargets(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, targets, NULL);
//bool bind_target = true;
//
//for (unsigned i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT && targets[i] != nullptr; ++i)
//{
// ID3D11Resource* res = NULL;
// targets[i]->GetResource(&res);
// if (res)
// {
// if (res == (ID3D11Resource*)pBackBuffer)
// {
// pDevice->CreateRenderTargetView(pBackBuffer, NULL, &mainRenderTargetView);
// }
//
// res->Release();
// }
//
// targets[i]->Release();
//}
SafeRelease(pBackBuffer);
if (mainRenderTargetView == nullptr)
return;
if(ImGui::GetCurrentContext() == nullptr)
ImGui::CreateContext((ImFontAtlas *)ImGuiFontAtlas);
ImGui_ImplDX11_Init(pDevice, pContext);
Windows_Hook::Inst()->SetInitialWindowSize(desc.OutputWindow);
_Initialized = true;
OverlayHookReady(true);
}
if (ImGui_ImplDX11_NewFrame() && Windows_Hook::Inst()->PrepareForOverlay(desc.OutputWindow))
{
ImGui::NewFrame();
OverlayProc();
ImGui::Render();
if (mainRenderTargetView)
{
pContext->OMSetRenderTargets(1, &mainRenderTargetView, NULL);
}
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
}
}
HRESULT STDMETHODCALLTYPE DX11_Hook::MyPresent(IDXGISwapChain *_this, UINT SyncInterval, UINT Flags)
{
auto inst = DX11_Hook::Inst();
inst->_PrepareForOverlay(_this);
return (_this->*inst->Present)(SyncInterval, Flags);
}
HRESULT STDMETHODCALLTYPE DX11_Hook::MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters)
{
auto inst = DX11_Hook::Inst();
inst->_ResetRenderState();
return (_this->*inst->ResizeTarget)(pNewTargetParameters);
}
HRESULT STDMETHODCALLTYPE DX11_Hook::MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags)
{
auto inst = DX11_Hook::Inst();
inst->_ResetRenderState();
return (_this->*inst->ResizeBuffers)(BufferCount, Width, Height, NewFormat, SwapChainFlags);
}
HRESULT STDMETHODCALLTYPE DX11_Hook::MyPresent1(IDXGISwapChain1* _this, UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters)
{
auto inst = DX11_Hook::Inst();
inst->_PrepareForOverlay(_this);
return (_this->*inst->Present1)(SyncInterval, Flags, pPresentParameters);
}
DX11_Hook::DX11_Hook():
_Initialized(false),
_Hooked(false),
_WindowsHooked(false),
pContext(nullptr),
mainRenderTargetView(nullptr),
Present(nullptr),
ResizeBuffers(nullptr),
ResizeTarget(nullptr),
Present1(nullptr)
{
}
DX11_Hook::~DX11_Hook()
{
SPDLOG_INFO("DX11 Hook removed");
if (_WindowsHooked)
delete Windows_Hook::Inst();
if (_Initialized)
{
SafeRelease(mainRenderTargetView);
SafeRelease(pContext);
ImGui_ImplDX11_InvalidateDeviceObjects();
ImGui::DestroyContext();
_Initialized = false;
}
_inst = nullptr;
}
DX11_Hook* DX11_Hook::Inst()
{
if (_inst == nullptr)
_inst = new DX11_Hook;
return _inst;
}
std::string DX11_Hook::GetLibraryName() const
{
return LibraryName;
}
void DX11_Hook::LoadFunctions(
decltype(Present) PresentFcn,
decltype(ResizeBuffers) ResizeBuffersFcn,
decltype(ResizeTarget) ResizeTargetFcn,
decltype(Present1) Present1Fcn)
{
Present = PresentFcn;
ResizeBuffers = ResizeBuffersFcn;
ResizeTarget = ResizeTargetFcn;
Present1 = Present1Fcn;
}
std::weak_ptr<uint64_t> DX11_Hook::CreateImageResource(const void* image_data, uint32_t width, uint32_t height)
{
ID3D11ShaderResourceView** resource = new ID3D11ShaderResourceView*(nullptr);
// Create texture
D3D11_TEXTURE2D_DESC desc = {};
desc.Width = static_cast<UINT>(width);
desc.Height = static_cast<UINT>(height);
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
ID3D11Texture2D* pTexture = nullptr;
D3D11_SUBRESOURCE_DATA subResource;
subResource.pSysMem = image_data;
subResource.SysMemPitch = desc.Width * 4;
subResource.SysMemSlicePitch = 0;
pDevice->CreateTexture2D(&desc, &subResource, &pTexture);
if (pTexture != nullptr)
{
// Create texture view
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc{};
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = desc.MipLevels;
srvDesc.Texture2D.MostDetailedMip = 0;
pDevice->CreateShaderResourceView(pTexture, &srvDesc, resource);
// Release Texture, the shader resource increases the reference count.
pTexture->Release();
}
if (*resource == nullptr)
return std::shared_ptr<uint64_t>();
auto ptr = std::shared_ptr<uint64_t>((uint64_t*)resource, [](uint64_t* handle)
{
if(handle != nullptr)
{
ID3D11ShaderResourceView** resource = reinterpret_cast<ID3D11ShaderResourceView**>(handle);
(*resource)->Release();
delete resource;
}
});
_ImageResources.emplace(ptr);
return ptr;
}
void DX11_Hook::ReleaseImageResource(std::weak_ptr<uint64_t> resource)
{
auto ptr = resource.lock();
if (ptr)
{
auto it = _ImageResources.find(ptr);
if (it != _ImageResources.end())
_ImageResources.erase(it);
}
}

View File

@ -1,81 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "overlay/internal_includes.h"
#include <d3d11.h>
#include <dxgi1_2.h>
class DX11_Hook :
public ingame_overlay::Renderer_Hook,
public Base_Hook
{
public:
static constexpr const char *DLL_NAME = "d3d11.dll";
private:
static DX11_Hook* _inst;
// Variables
bool _Hooked;
bool _WindowsHooked;
bool _Initialized;
ID3D11Device* pDevice;
ID3D11DeviceContext* pContext;
ID3D11RenderTargetView* mainRenderTargetView;
std::set<std::shared_ptr<uint64_t>> _ImageResources;
// Functions
DX11_Hook();
void _ResetRenderState();
void _PrepareForOverlay(IDXGISwapChain* pSwapChain);
// Hook to render functions
static HRESULT STDMETHODCALLTYPE MyPresent(IDXGISwapChain* _this, UINT SyncInterval, UINT Flags);
static HRESULT STDMETHODCALLTYPE MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters);
static HRESULT STDMETHODCALLTYPE MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags);
static HRESULT STDMETHODCALLTYPE MyPresent1(IDXGISwapChain1* _this, UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters);
decltype(&IDXGISwapChain::Present) Present;
decltype(&IDXGISwapChain::ResizeBuffers) ResizeBuffers;
decltype(&IDXGISwapChain::ResizeTarget) ResizeTarget;
decltype(&IDXGISwapChain1::Present1) Present1;
public:
std::string LibraryName;
virtual ~DX11_Hook();
virtual bool StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys);
virtual bool IsStarted();
static DX11_Hook* Inst();
virtual std::string GetLibraryName() const;
void LoadFunctions(
decltype(Present) PresentFcn,
decltype(ResizeBuffers) ResizeBuffersFcn,
decltype(ResizeTarget) ResizeTargetFcn,
decltype(Present1) Present1Fcn);
virtual std::weak_ptr<uint64_t> CreateImageResource(const void* image_data, uint32_t width, uint32_t height);
virtual void ReleaseImageResource(std::weak_ptr<uint64_t> resource);
};

View File

@ -1,719 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
// read this:
//https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples#example-for-directx12-users
#include "DX12_Hook.h"
#include "Windows_Hook.h"
#include <imgui.h>
#include <backends/imgui_impl_dx12.h>
DX12_Hook* DX12_Hook::_inst = nullptr;
template<typename T>
inline void SafeRelease(T*& pUnk)
{
if (pUnk != nullptr)
{
pUnk->Release();
pUnk = nullptr;
}
}
bool DX12_Hook::StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys)
{
if (!_Hooked)
{
if (Present == nullptr || ResizeTarget == nullptr || ResizeBuffers == nullptr || ExecuteCommandLists == nullptr)
{
SPDLOG_WARN("Failed to hook DirectX 12: Rendering functions missing.");
return false;
}
if (!Windows_Hook::Inst()->StartHook(key_combination_callback, toggle_keys))
return false;
_WindowsHooked = true;
SPDLOG_INFO("Hooked DirectX 12");
_Hooked = true;
BeginHook();
HookFuncs(
std::make_pair<void**, void*>(&(PVOID&)Present , &DX12_Hook::MyPresent),
std::make_pair<void**, void*>(&(PVOID&)ResizeTarget , &DX12_Hook::MyResizeTarget),
std::make_pair<void**, void*>(&(PVOID&)ResizeBuffers , &DX12_Hook::MyResizeBuffers),
std::make_pair<void**, void*>(&(PVOID&)ExecuteCommandLists, &DX12_Hook::MyExecuteCommandLists)
);
if (Present1 != nullptr)
{
HookFuncs(
std::make_pair<void**, void*>(&(PVOID&)Present1, &DX12_Hook::MyPresent1)
);
}
EndHook();
}
return true;
}
bool DX12_Hook::IsStarted()
{
return _Hooked;
}
DX12_Hook::heap_t DX12_Hook::get_free_texture_heap()
{
uint32_t i;
for (i = 0; i < srvDescHeapBitmap.size(); ++i) {
if (!srvDescHeapBitmap[i]) {
srvDescHeapBitmap[i] = true;
break;
}
}
if (i == srvDescHeapBitmap.size())
return heap_t{ {}, {}, -1 };
UINT inc = pDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
return heap_t{
// i * 2 because each 2 handles are used per 1 image,
// 1st handle for ImGui internal font, 2nd for our texture
// then +1 because the 1st handle is reserved for internal font
pSrvDescHeap->GetGPUDescriptorHandleForHeapStart().ptr + inc * ((i * 2) + 1),
pSrvDescHeap->GetCPUDescriptorHandleForHeapStart().ptr + inc * ((i * 2) + 1),
i
};
}
bool DX12_Hook::release_texture_heap(int64_t heap_id)
{
srvDescHeapBitmap[heap_id] = false;
return true;
}
ID3D12CommandQueue* DX12_Hook::_FindCommandQueueFromSwapChain(IDXGISwapChain* pSwapChain)
{
ID3D12CommandQueue* pCommandQueue = nullptr;
if (CommandQueueOffset == 0 && pCmdQueue != nullptr)
{
for (size_t i = 0; i < 1024; ++i)
{
if (*reinterpret_cast<ID3D12CommandQueue**>(reinterpret_cast<uintptr_t>(pSwapChain) + i) == pCmdQueue)
{
SPDLOG_INFO("Found IDXGISwapChain::ppCommandQueue at offset {}.", i);
CommandQueueOffset = i;
break;
}
}
}
if (CommandQueueOffset != 0)
pCommandQueue = *reinterpret_cast<ID3D12CommandQueue**>(reinterpret_cast<uintptr_t>(pSwapChain) + CommandQueueOffset);
return pCommandQueue;
}
void DX12_Hook::_ResetRenderState()
{
if (_Initialized)
{
OverlayHookReady(false);
ImGui_ImplDX12_Shutdown();
Windows_Hook::Inst()->ResetRenderState();
ImGui::DestroyContext();
_ResetStatesOnly();
_Initialized = false;
}
}
void DX12_Hook::_ResetStatesOnly()
{
// each image texture holds a reference to its CPU and GPU descriptors
// when the state is reset we have to reload everything again
// I don't know a better way to handle this
while (_ImageResources.size()) {
_ImageResources.erase(std::prev(_ImageResources.end()));
}
srvDescHeapBitmap.clear();
OverlayFrames.clear();
SafeRelease(pCmdList);
SafeRelease(pSrvDescHeap);
SafeRelease(pRtvDescHeap);
SafeRelease(pDevice);
}
// https://github.com/ocornut/imgui/blob/06ce312745e0b25bfa8412b324503393964e3812/examples/example_win32_directx12/main.cpp#L237
// Try to make this function and overlay's proc as short as possible or it might affect game's fps.
void DX12_Hook::_PrepareForOverlay(IDXGISwapChain* pSwapChain, ID3D12CommandQueue* pCommandQueue)
{
if (!pCommandQueue || !pSwapChain)
return;
IDXGISwapChain3* pSwapChain3 = nullptr;
pSwapChain->QueryInterface(IID_PPV_ARGS(&pSwapChain3));
if (pSwapChain3 == nullptr)
return;
DXGI_SWAP_CHAIN_DESC sc_desc{};
SecureZeroMemory(&sc_desc, sizeof(sc_desc));
pSwapChain3->GetDesc(&sc_desc);
if (!_Initialized)
{
// UINT bufferIndex = pSwapChain3->GetCurrentBackBufferIndex();
pDevice = nullptr;
if (pSwapChain3->GetDevice(IID_PPV_ARGS(&pDevice)) != S_OK) {
_ResetStatesOnly();
pSwapChain3->Release();
return;
}
// https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples#example-for-directx12-users
srvDescHeapBitmap.clear();
constexpr const static UINT DESCRIPTOR_COUNT = 1024;
{
D3D12_DESCRIPTOR_HEAP_DESC desc = {};
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
// desc.NumDescriptors = 1;
// <-- Set this value to 2 (the first descriptor is used for the built-in font texture, the second for our new texture)
desc.NumDescriptors = DESCRIPTOR_COUNT * 2;
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
pSrvDescHeap = nullptr;
if (pDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&pSrvDescHeap)) != S_OK)
{
_ResetStatesOnly();
pSwapChain3->Release();
return;
}
}
srvDescHeapBitmap.resize(DESCRIPTOR_COUNT, false);
const UINT bufferCount = sc_desc.BufferCount;
{
D3D12_DESCRIPTOR_HEAP_DESC desc = {};
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
desc.NumDescriptors = bufferCount;
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
desc.NodeMask = 1;
pRtvDescHeap = nullptr;
if (pDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&pRtvDescHeap)) != S_OK)
{
_ResetStatesOnly();
pSwapChain3->Release();
return;
}
SIZE_T rtvDescriptorSize = pDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = pRtvDescHeap->GetCPUDescriptorHandleForHeapStart();
OverlayFrames.clear();
pCmdList = nullptr;
for (UINT i = 0; i < bufferCount; ++i)
{
ID3D12CommandAllocator* pCmdAlloc = nullptr;
if (pDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&pCmdAlloc)) != S_OK || pCmdAlloc == nullptr)
{
_ResetStatesOnly();
SafeRelease(pSwapChain3);
return;
}
if (i == 0)
{
if (pDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, pCmdAlloc, NULL, IID_PPV_ARGS(&pCmdList)) != S_OK ||
pCmdList == nullptr ||
pCmdList->Close() != S_OK)
{
pCmdAlloc->Release();
_ResetStatesOnly();
pSwapChain3->Release();
return;
}
}
ID3D12Resource* pBackBuffer = nullptr;
if (pSwapChain3->GetBuffer(i, IID_PPV_ARGS(&pBackBuffer)) != S_OK || pBackBuffer == nullptr)
{
pCmdAlloc->Release();
_ResetStatesOnly();
pSwapChain3->Release();
return;
}
pDevice->CreateRenderTargetView(pBackBuffer, NULL, rtvHandle);
OverlayFrames.emplace_back(rtvHandle, pCmdAlloc, pBackBuffer);
rtvHandle.ptr += rtvDescriptorSize;
}
}
// auto heaps = std::move(get_free_texture_heap());
if(ImGui::GetCurrentContext() == nullptr)
ImGui::CreateContext((ImFontAtlas *)ImGuiFontAtlas);
ImGui_ImplDX12_Init(pDevice, bufferCount, DXGI_FORMAT_R8G8B8A8_UNORM, pSrvDescHeap,
pSrvDescHeap->GetCPUDescriptorHandleForHeapStart(),
pSrvDescHeap->GetGPUDescriptorHandleForHeapStart());
// heaps.cpu_handle,
// heaps.gpu_handle);
Windows_Hook::Inst()->SetInitialWindowSize(sc_desc.OutputWindow);
_Initialized = true;
OverlayHookReady(true);
}
if (ImGui_ImplDX12_NewFrame() && Windows_Hook::Inst()->PrepareForOverlay(sc_desc.OutputWindow))
{
ImGui::NewFrame();
OverlayProc();
ImGui::Render();
const UINT bufferIndex = pSwapChain3->GetCurrentBackBufferIndex();
OverlayFrames[bufferIndex].pCmdAlloc->Reset();
D3D12_RESOURCE_BARRIER barrier = {};
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrier.Transition.pResource = OverlayFrames[bufferIndex].pBackBuffer;
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
pCmdList->Reset(OverlayFrames[bufferIndex].pCmdAlloc, NULL);
pCmdList->ResourceBarrier(1, &barrier);
pCmdList->OMSetRenderTargets(1, &OverlayFrames[bufferIndex].RenderTarget, FALSE, NULL);
pCmdList->SetDescriptorHeaps(1, &pSrvDescHeap);
ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), pCmdList);
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
pCmdList->ResourceBarrier(1, &barrier);
pCmdList->Close();
pCommandQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&pCmdList);
}
pSwapChain3->Release();
}
HRESULT STDMETHODCALLTYPE DX12_Hook::MyPresent(IDXGISwapChain *_this, UINT SyncInterval, UINT Flags)
{
auto inst = DX12_Hook::Inst();
ID3D12CommandQueue* pCommandQueue = inst->_FindCommandQueueFromSwapChain(_this);
if (pCommandQueue != nullptr)
{
inst->_PrepareForOverlay(_this, pCommandQueue);
}
return (_this->*inst->Present)(SyncInterval, Flags);
}
HRESULT STDMETHODCALLTYPE DX12_Hook::MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters)
{
auto inst = DX12_Hook::Inst();
inst->_ResetRenderState();
return (_this->*inst->ResizeTarget)(pNewTargetParameters);
}
HRESULT STDMETHODCALLTYPE DX12_Hook::MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags)
{
auto inst = DX12_Hook::Inst();
inst->_ResetRenderState();
return (_this->*inst->ResizeBuffers)(BufferCount, Width, Height, NewFormat, SwapChainFlags);
}
void STDMETHODCALLTYPE DX12_Hook::MyExecuteCommandLists(ID3D12CommandQueue *_this, UINT NumCommandLists, ID3D12CommandList* const* ppCommandLists)
{
auto inst = DX12_Hook::Inst();
inst->pCmdQueue = _this;
(_this->*inst->ExecuteCommandLists)(NumCommandLists, ppCommandLists);
}
HRESULT STDMETHODCALLTYPE DX12_Hook::MyPresent1(IDXGISwapChain1* _this, UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters)
{
auto inst = DX12_Hook::Inst();
ID3D12CommandQueue* pCommandQueue = inst->_FindCommandQueueFromSwapChain(_this);
if (pCommandQueue != nullptr)
{
inst->_PrepareForOverlay(_this, pCommandQueue);
}
return (_this->*inst->Present1)(SyncInterval, Flags, pPresentParameters);
}
DX12_Hook::DX12_Hook():
_Initialized(false),
CommandQueueOffset(0),
pDevice(nullptr),
pCmdQueue(nullptr),
pSrvDescHeap(nullptr),
pCmdList(nullptr),
pRtvDescHeap(nullptr),
_Hooked(false),
_WindowsHooked(false),
Present(nullptr),
ResizeBuffers(nullptr),
ResizeTarget(nullptr),
ExecuteCommandLists(nullptr),
Present1(nullptr)
{
SPDLOG_WARN("DX12 support is experimental, don't complain if it doesn't work as expected.");
}
DX12_Hook::~DX12_Hook()
{
SPDLOG_INFO("DX12 Hook removed");
if (_WindowsHooked)
delete Windows_Hook::Inst();
if (_Initialized)
{
_ResetStatesOnly();
ImGui_ImplDX12_InvalidateDeviceObjects();
ImGui::DestroyContext();
_Initialized = false;
}
_inst = nullptr;
}
DX12_Hook* DX12_Hook::Inst()
{
if (_inst == nullptr)
_inst = new DX12_Hook();
return _inst;
}
std::string DX12_Hook::GetLibraryName() const
{
return LibraryName;
}
void DX12_Hook::LoadFunctions(
decltype(Present) PresentFcn,
decltype(ResizeBuffers) ResizeBuffersFcn,
decltype(ResizeTarget) ResizeTargetFcn,
decltype(ExecuteCommandLists) ExecuteCommandListsFcn,
decltype(Present1) Present1Fcn)
{
Present = PresentFcn;
ResizeBuffers = ResizeBuffersFcn;
ResizeTarget = ResizeTargetFcn;
ExecuteCommandLists = ExecuteCommandListsFcn;
Present1 = Present1Fcn;
}
// source: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples#example-for-directx12-users
std::weak_ptr<uint64_t> DX12_Hook::CreateImageResource(const void* image_data, uint32_t width, uint32_t height)
{
heap_t heap = get_free_texture_heap();
if (heap.id == -1) return {};
D3D12_HEAP_PROPERTIES props;
SecureZeroMemory(&props, sizeof(props));
props.Type = D3D12_HEAP_TYPE_DEFAULT;
props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
D3D12_RESOURCE_DESC desc;
SecureZeroMemory(&desc, sizeof(desc));
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
desc.Alignment = 0;
desc.Width = static_cast<UINT64>(width);
desc.Height = static_cast<UINT>(height);
desc.DepthOrArraySize = 1;
desc.MipLevels = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
ID3D12Resource* pTexture = NULL;
HRESULT hr = pDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
D3D12_RESOURCE_STATE_COPY_DEST, NULL, IID_PPV_ARGS(&pTexture));
if (!SUCCEEDED(hr)) {
release_texture_heap(heap.id);
return {};
}
UINT uploadPitch = (width * 4 + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u);
UINT uploadSize = height * uploadPitch;
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
desc.Alignment = 0;
desc.Width = uploadSize;
desc.Height = 1;
desc.DepthOrArraySize = 1;
desc.MipLevels = 1;
desc.Format = DXGI_FORMAT_UNKNOWN;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
props.Type = D3D12_HEAP_TYPE_UPLOAD;
props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
ID3D12Resource* uploadBuffer = NULL;
hr = pDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&uploadBuffer));
if (!SUCCEEDED(hr)) {
pTexture->Release();
release_texture_heap(heap.id);
return {};
}
void* mapped = NULL;
D3D12_RANGE range = { 0, uploadSize };
hr = uploadBuffer->Map(0, &range, &mapped);
if (!SUCCEEDED(hr)) {
uploadBuffer->Release();
pTexture->Release();
release_texture_heap(heap.id);
return {};
}
for (int y = 0; y < height; y++) {
memcpy(
(void*)((uintptr_t)mapped + y * uploadPitch),
reinterpret_cast<const uint8_t*>(image_data) + y * width * 4,
width * 4
);
}
uploadBuffer->Unmap(0, &range);
D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
srcLocation.pResource = uploadBuffer;
srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
srcLocation.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srcLocation.PlacedFootprint.Footprint.Width = width;
srcLocation.PlacedFootprint.Footprint.Height = height;
srcLocation.PlacedFootprint.Footprint.Depth = 1;
srcLocation.PlacedFootprint.Footprint.RowPitch = uploadPitch;
D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
dstLocation.pResource = pTexture;
dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
dstLocation.SubresourceIndex = 0;
D3D12_RESOURCE_BARRIER barrier = {};
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrier.Transition.pResource = pTexture;
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
ID3D12Fence* fence = NULL;
hr = pDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence));
if (!SUCCEEDED(hr)) {
uploadBuffer->Unmap(0, &range);
uploadBuffer->Release();
pTexture->Release();
release_texture_heap(heap.id);
return {};
}
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
queueDesc.NodeMask = 1;
ID3D12CommandQueue* cmdQueue = NULL;
hr = pDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&cmdQueue));
if (!SUCCEEDED(hr)) {
fence->Release();
uploadBuffer->Unmap(0, &range);
uploadBuffer->Release();
pTexture->Release();
release_texture_heap(heap.id);
return {};
}
ID3D12CommandAllocator* cmdAlloc = NULL;
hr = pDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAlloc));
if (!SUCCEEDED(hr)) {
cmdQueue->Release();
fence->Release();
uploadBuffer->Unmap(0, &range);
uploadBuffer->Release();
pTexture->Release();
release_texture_heap(heap.id);
return {};
}
ID3D12GraphicsCommandList* cmdList = NULL;
hr = pDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, cmdAlloc, NULL, IID_PPV_ARGS(&cmdList));
if (!SUCCEEDED(hr)) {
cmdAlloc->Release();
cmdQueue->Release();
fence->Release();
uploadBuffer->Unmap(0, &range);
uploadBuffer->Release();
pTexture->Release();
release_texture_heap(heap.id);
return {};
}
HANDLE event = CreateEventW(0, 0, 0, 0);
if (!event) {
cmdList->Release();
cmdAlloc->Release();
cmdQueue->Release();
fence->Release();
uploadBuffer->Unmap(0, &range);
uploadBuffer->Release();
pTexture->Release();
release_texture_heap(heap.id);
return {};
}
cmdList->CopyTextureRegion(&dstLocation, 0, 0, 0, &srcLocation, NULL);
cmdList->ResourceBarrier(1, &barrier);
hr = cmdList->Close();
if (!SUCCEEDED(hr)) {
CloseHandle(event);
cmdList->Release();
cmdAlloc->Release();
cmdQueue->Release();
fence->Release();
uploadBuffer->Unmap(0, &range);
uploadBuffer->Release();
pTexture->Release();
release_texture_heap(heap.id);
return {};
}
cmdQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmdList);
hr = cmdQueue->Signal(fence, 1);
if (!SUCCEEDED(hr)) {
CloseHandle(event);
cmdList->Close();
cmdList->Release();
cmdAlloc->Release();
cmdQueue->Release();
fence->Release();
uploadBuffer->Unmap(0, &range);
uploadBuffer->Release();
pTexture->Release();
release_texture_heap(heap.id);
return {};
}
hr = fence->SetEventOnCompletion(1, event);
if (!SUCCEEDED(hr)) {
CloseHandle(event);
cmdList->Close();
cmdList->Release();
cmdAlloc->Release();
cmdQueue->Release();
fence->Release();
uploadBuffer->Unmap(0, &range);
uploadBuffer->Release();
pTexture->Release();
release_texture_heap(heap.id);
return {};
}
WaitForSingleObject(event, INFINITE);
CloseHandle(event);
cmdList->Release();
cmdAlloc->Release();
cmdQueue->Release();
fence->Release();
uploadBuffer->Release();
// Create texture view
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
SecureZeroMemory(&srvDesc, sizeof(srvDesc));
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = desc.MipLevels;
srvDesc.Texture2D.MostDetailedMip = 0;
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
pDevice->CreateShaderResourceView(pTexture, &srvDesc, heap.cpu_handle);
texture_t* texture_data = new texture_t;
texture_data->gpu_handle = heap.gpu_handle.ptr;
texture_data->pTexture = pTexture;
texture_data->heap_id = heap.id;
auto ptr = std::shared_ptr<uint64_t>((uint64_t*)texture_data, [this](uint64_t* handle)
{
if (handle != nullptr) {
texture_t* pTextureData = reinterpret_cast<texture_t*>(handle);
pTextureData->pTexture->Release();
release_texture_heap(pTextureData->heap_id);
delete pTextureData;
}
});
_ImageResources.emplace(ptr);
return ptr;
}
void DX12_Hook::ReleaseImageResource(std::weak_ptr<uint64_t> resource)
{
auto ptr = resource.lock();
if (ptr)
{
auto it = _ImageResources.find(ptr);
if (it != _ImageResources.end())
_ImageResources.erase(it);
}
}

View File

@ -1,155 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "overlay/internal_includes.h"
#include <d3d12.h>
#include <dxgi1_4.h>
class DX12_Hook :
public ingame_overlay::Renderer_Hook,
public Base_Hook
{
public:
static constexpr const char *DLL_NAME = "d3d12.dll";
private:
static DX12_Hook* _inst;
std::set<std::shared_ptr<uint64_t>> _ImageResources;
struct texture_t{
using gpu_heap_t = decltype(D3D12_GPU_DESCRIPTOR_HANDLE::ptr);
gpu_heap_t gpu_handle; // This must be the first member, ImGui will use the content of the pointer as a D3D12_GPU_DESCRIPTOR_HANDLE::ptr
ID3D12Resource* pTexture;
int64_t heap_id;
};
struct DX12Frame_t
{
D3D12_CPU_DESCRIPTOR_HANDLE RenderTarget = {};
ID3D12CommandAllocator* pCmdAlloc = nullptr;
ID3D12Resource* pBackBuffer = nullptr;
inline void Reset()
{
pCmdAlloc = nullptr;
pBackBuffer = nullptr;
}
DX12Frame_t() {}
DX12Frame_t(DX12Frame_t const&) = delete;
DX12Frame_t& operator=(DX12Frame_t const&) = delete;
DX12Frame_t(D3D12_CPU_DESCRIPTOR_HANDLE RenderTarget, ID3D12CommandAllocator* pCmdAlloc, ID3D12Resource* pBackBuffer):
RenderTarget(RenderTarget), pCmdAlloc(pCmdAlloc), pBackBuffer(pBackBuffer)
{}
DX12Frame_t(DX12Frame_t&& other) noexcept:
RenderTarget(other.RenderTarget), pCmdAlloc(other.pCmdAlloc), pBackBuffer(other.pBackBuffer)
{
other.Reset();
}
DX12Frame_t& operator=(DX12Frame_t&& other) noexcept
{
DX12Frame_t tmp(std::move(other));
RenderTarget = tmp.RenderTarget;
pCmdAlloc = tmp.pCmdAlloc;
pBackBuffer = tmp.pBackBuffer;
tmp.Reset();
return *this;
}
~DX12Frame_t()
{
if (pCmdAlloc != nullptr) pCmdAlloc->Release();
if (pBackBuffer != nullptr) pBackBuffer->Release();
}
};
struct heap_t
{
D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle;
D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle;
int64_t id;
};
// Variables
bool _Hooked;
bool _WindowsHooked;
bool _Initialized;
size_t CommandQueueOffset;
ID3D12CommandQueue* pCmdQueue;
ID3D12Device* pDevice;
std::vector<DX12Frame_t> OverlayFrames;
std::vector<bool> srvDescHeapBitmap;
ID3D12DescriptorHeap* pSrvDescHeap;
ID3D12GraphicsCommandList* pCmdList;
ID3D12DescriptorHeap* pRtvDescHeap;
// Functions
DX12_Hook();
heap_t get_free_texture_heap();
bool release_texture_heap(int64_t heap_id);
ID3D12CommandQueue* _FindCommandQueueFromSwapChain(IDXGISwapChain* pSwapChain);
void _ResetRenderState();
void _ResetStatesOnly();
void _PrepareForOverlay(IDXGISwapChain* pSwapChain, ID3D12CommandQueue* pCommandQueue);
// Hook to render functions
static HRESULT STDMETHODCALLTYPE MyPresent(IDXGISwapChain* _this, UINT SyncInterval, UINT Flags);
static HRESULT STDMETHODCALLTYPE MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters);
static HRESULT STDMETHODCALLTYPE MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags);
static void STDMETHODCALLTYPE MyExecuteCommandLists(ID3D12CommandQueue *_this, UINT NumCommandLists, ID3D12CommandList* const* ppCommandLists);
static HRESULT STDMETHODCALLTYPE MyPresent1(IDXGISwapChain1* _this, UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters);
decltype(&IDXGISwapChain::Present) Present;
decltype(&IDXGISwapChain::ResizeBuffers) ResizeBuffers;
decltype(&IDXGISwapChain::ResizeTarget) ResizeTarget;
decltype(&ID3D12CommandQueue::ExecuteCommandLists) ExecuteCommandLists;
decltype(&IDXGISwapChain1::Present1) Present1;
public:
std::string LibraryName;
virtual ~DX12_Hook();
virtual bool StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys);
virtual bool IsStarted();
static DX12_Hook* Inst();
virtual std::string GetLibraryName() const;
void LoadFunctions(
decltype(Present) PresentFcn,
decltype(ResizeBuffers) ResizeBuffersFcn,
decltype(ResizeTarget) ResizeTargetFcn,
decltype(ExecuteCommandLists) ExecuteCommandListsFcn,
decltype(Present1) Present1Fcn1);
virtual std::weak_ptr<uint64_t> CreateImageResource(const void* image_data, uint32_t width, uint32_t height);
virtual void ReleaseImageResource(std::weak_ptr<uint64_t> resource);
};

View File

@ -1,328 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "DX9_Hook.h"
#include "Windows_Hook.h"
#include "DirectX_VTables.h"
#include <imgui.h>
#include <backends/imgui_impl_dx9.h>
DX9_Hook* DX9_Hook::_inst = nullptr;
template<typename T>
inline void SafeRelease(T*& pUnk)
{
if (pUnk != nullptr)
{
pUnk->Release();
pUnk = nullptr;
}
}
bool DX9_Hook::StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys)
{
if (!_Hooked)
{
if (Reset == nullptr || Present == nullptr)
{
SPDLOG_WARN("Failed to hook DirectX 9: Rendering functions missing.");
return false;
}
if (!Windows_Hook::Inst()->StartHook(key_combination_callback, toggle_keys))
return false;
_WindowsHooked = true;
SPDLOG_INFO("Hooked DirectX 9");
_Hooked = true;
BeginHook();
HookFuncs(
std::make_pair<void**, void*>(&(PVOID&)Reset, &DX9_Hook::MyReset),
std::make_pair<void**, void*>(&(PVOID&)Present, &DX9_Hook::MyPresent)
);
if (PresentEx != nullptr)
{
HookFuncs(
std::make_pair<void**, void*>(&(PVOID&)PresentEx, &DX9_Hook::MyPresentEx)
);
}
if (SwapChainPresent != nullptr)
{
HookFuncs(
std::make_pair<void**, void*>(&(PVOID&)SwapChainPresent, &DX9_Hook::MySwapChainPresent)
);
}
EndHook();
}
return true;
}
bool DX9_Hook::IsStarted()
{
return _Hooked;
}
void DX9_Hook::_ResetRenderState()
{
if (_Initialized)
{
OverlayHookReady(false);
ImGui_ImplDX9_Shutdown();
Windows_Hook::Inst()->ResetRenderState();
ImGui::DestroyContext();
SafeRelease(_pDevice);
_LastWindow = nullptr;
_Initialized = false;
}
}
// Try to make this function and overlay's proc as short as possible or it might affect game's fps.
void DX9_Hook::_PrepareForOverlay(IDirect3DDevice9 *pDevice, HWND destWindow)
{
if (!destWindow)
{
IDirect3DSwapChain9 *pSwapChain = nullptr;
if (pDevice->GetSwapChain(0, &pSwapChain) == D3D_OK)
{
D3DPRESENT_PARAMETERS params;
if (pSwapChain->GetPresentParameters(&params) == D3D_OK)
{
destWindow = params.hDeviceWindow;
}
pSwapChain->Release();
}
}
//Is this necessary anymore?
if (!destWindow)
{
D3DDEVICE_CREATION_PARAMETERS param;
pDevice->GetCreationParameters(&param);
destWindow = param.hFocusWindow;
}
// Workaround to detect if we changed window.
if (destWindow != _LastWindow || _pDevice != pDevice)
_ResetRenderState();
if (!_Initialized)
{
pDevice->AddRef();
_pDevice = pDevice;
ImGui::CreateContext((ImFontAtlas *)ImGuiFontAtlas);
ImGui_ImplDX9_Init(pDevice);
_LastWindow = destWindow;
Windows_Hook::Inst()->SetInitialWindowSize(destWindow);
_Initialized = true;
OverlayHookReady(true);
}
if (ImGui_ImplDX9_NewFrame() && Windows_Hook::Inst()->PrepareForOverlay(destWindow))
{
ImGui::NewFrame();
OverlayProc();
ImGui::Render();
ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData());
}
}
HRESULT STDMETHODCALLTYPE DX9_Hook::MyReset(IDirect3DDevice9* _this, D3DPRESENT_PARAMETERS* pPresentationParameters)
{
auto inst = DX9_Hook::Inst();
inst->_ResetRenderState();
return (_this->*inst->Reset)(pPresentationParameters);
}
HRESULT STDMETHODCALLTYPE DX9_Hook::MyPresent(IDirect3DDevice9* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion)
{
auto inst = DX9_Hook::Inst();
inst->_PrepareForOverlay(_this, hDestWindowOverride);
return (_this->*inst->Present)(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion);
}
HRESULT STDMETHODCALLTYPE DX9_Hook::MyPresentEx(IDirect3DDevice9Ex* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion, DWORD dwFlags)
{
auto inst = DX9_Hook::Inst();
inst->_PrepareForOverlay(_this, hDestWindowOverride);
return (_this->*inst->PresentEx)(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags);
}
HRESULT STDMETHODCALLTYPE DX9_Hook::MySwapChainPresent(IDirect3DSwapChain9* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion, DWORD dwFlags)
{
IDirect3DDevice9* pDevice;
auto inst = DX9_Hook::Inst();
if (SUCCEEDED(_this->GetDevice(&pDevice)))
{
HWND destWindow = hDestWindowOverride;
if (!destWindow)
{
D3DPRESENT_PARAMETERS param;
if (_this->GetPresentParameters(&param) == D3D_OK)
{
destWindow = param.hDeviceWindow;
}
}
inst->_PrepareForOverlay(pDevice, destWindow);
pDevice->Release();
}
return (_this->*inst->SwapChainPresent)(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags);
}
DX9_Hook::DX9_Hook():
_Initialized(false),
_Hooked(false),
_WindowsHooked(false),
_LastWindow(nullptr),
Present(nullptr),
PresentEx(nullptr),
Reset(nullptr)
{
}
DX9_Hook::~DX9_Hook()
{
SPDLOG_INFO("DX9 Hook removed");
if (_WindowsHooked)
delete Windows_Hook::Inst();
if (_Initialized)
{
ImGui_ImplDX9_InvalidateDeviceObjects();
ImGui::DestroyContext();
}
_inst = nullptr;
}
DX9_Hook* DX9_Hook::Inst()
{
if( _inst == nullptr )
_inst = new DX9_Hook;
return _inst;
}
std::string DX9_Hook::GetLibraryName() const
{
return LibraryName;
}
void DX9_Hook::LoadFunctions(decltype(Present) PresentFcn, decltype(Reset) ResetFcn, decltype(PresentEx) PresentExFcn, decltype(&IDirect3DSwapChain9::Present) SwapChainPresentFcn)
{
Present = PresentFcn;
Reset = ResetFcn;
PresentEx = PresentExFcn;
SwapChainPresent = SwapChainPresentFcn;
}
std::weak_ptr<uint64_t> DX9_Hook::CreateImageResource(const void* image_data, uint32_t width, uint32_t height)
{
IDirect3DTexture9** pTexture = new IDirect3DTexture9*(nullptr);
_pDevice->CreateTexture(
width,
height,
1,
D3DUSAGE_DYNAMIC,
D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT,
pTexture,
nullptr
);
if (*pTexture != nullptr)
{
D3DLOCKED_RECT rect;
if (SUCCEEDED((*pTexture)->LockRect(0, &rect, nullptr, D3DLOCK_DISCARD)))
{
const uint32_t* pixels = reinterpret_cast<const uint32_t*>(image_data);
uint8_t* texture_bits = reinterpret_cast<uint8_t*>(rect.pBits);
for (int32_t i = 0; i < height; ++i)
{
for (int32_t j = 0; j < width; ++j)
{
// RGBA to ARGB Conversion, DX9 doesn't have a RGBA loader
uint32_t color = *pixels++;
reinterpret_cast<uint32_t*>(texture_bits)[j] = ((color & 0xff) << 16) | (color & 0xff00) | ((color & 0xff0000) >> 16) | (color & 0xff000000);
}
texture_bits += rect.Pitch;
}
if (FAILED((*pTexture)->UnlockRect(0)))
{
(*pTexture)->Release();
delete pTexture;
pTexture = nullptr;
}
}
else
{
(*pTexture)->Release();
delete pTexture;
pTexture = nullptr;
}
}
if (pTexture == nullptr)
return std::shared_ptr<uint64_t>();
auto ptr = std::shared_ptr<uint64_t>((uint64_t*)pTexture, [](uint64_t* handle)
{
if (handle != nullptr)
{
IDirect3DTexture9** resource = reinterpret_cast<IDirect3DTexture9**>(handle);
(*resource)->Release();
delete resource;
}
});
_ImageResources.emplace(ptr);
return ptr;
}
void DX9_Hook::ReleaseImageResource(std::weak_ptr<uint64_t> resource)
{
auto ptr = resource.lock();
if (ptr)
{
auto it = _ImageResources.find(ptr);
if (it != _ImageResources.end())
_ImageResources.erase(it);
}
}

View File

@ -1,75 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "overlay/internal_includes.h"
#include <d3d9.h>
class DX9_Hook :
public ingame_overlay::Renderer_Hook,
public Base_Hook
{
public:
static constexpr const char *DLL_NAME = "d3d9.dll";
private:
static DX9_Hook* _inst;
// Variables
bool _Hooked;
bool _WindowsHooked;
bool _Initialized;
HWND _LastWindow;
IDirect3DDevice9* _pDevice;
std::set<std::shared_ptr<uint64_t>> _ImageResources;
// Functions
DX9_Hook();
void _ResetRenderState();
void _PrepareForOverlay(IDirect3DDevice9* pDevice, HWND destWindow);
// Hook to render functions
decltype(&IDirect3DDevice9::Reset) Reset;
decltype(&IDirect3DDevice9::Present) Present;
decltype(&IDirect3DDevice9Ex::PresentEx) PresentEx;
decltype(&IDirect3DSwapChain9::Present) SwapChainPresent;
static HRESULT STDMETHODCALLTYPE MyReset(IDirect3DDevice9* _this, D3DPRESENT_PARAMETERS* pPresentationParameters);
static HRESULT STDMETHODCALLTYPE MyPresent(IDirect3DDevice9* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion);
static HRESULT STDMETHODCALLTYPE MyPresentEx(IDirect3DDevice9Ex* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion, DWORD dwFlags);
static HRESULT STDMETHODCALLTYPE MySwapChainPresent(IDirect3DSwapChain9* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion, DWORD dwFlags);
public:
std::string LibraryName;
virtual ~DX9_Hook();
virtual bool StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys);
virtual bool IsStarted();
static DX9_Hook* Inst();
virtual std::string GetLibraryName() const;
void LoadFunctions(decltype(Present) PresentFcn, decltype(Reset) ResetFcn, decltype(PresentEx) PresentExFcn, decltype(&IDirect3DSwapChain9::Present) SwapChainPresentFcn);
virtual std::weak_ptr<uint64_t> CreateImageResource(const void* image_data, uint32_t width, uint32_t height);
virtual void ReleaseImageResource(std::weak_ptr<uint64_t> resource);
};

View File

@ -1,487 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
enum class IDXGISwapChainVTable
{
// IUnknown
QueryInterface,
AddRef,
Release,
// IDXGIObject
SetPrivateData,
SetPrivateDataInterface,
GetPrivateData,
GetParent,
// IDXGIDeviceSubObject
GetDevice,
// IDXGISwapChain
Present,
GetBuffer,
SetFullscreenState,
GetFullscreenState,
GetDesc,
ResizeBuffers,
ResizeTarget,
GetContainingOutput,
GetFrameStatistics,
GetLastPresentCount,
// IDXGISwapChain1
GetDesc1,
GetFullscreenDesc,
GetHwnd,
GetCoreWindow,
Present1,
IsTemporaryMonoSupported,
GetRestrictToOutput,
SetBackgroundColor,
GetBackgroundColor,
SetRotation,
GetRotation,
};
enum class ID3D12CommandQueueVTable
{
// IUnknown
QueryInterface,
AddRef,
Release,
// ID3D12Object
GetPrivateData,
SetPrivateData,
SetPrivateDataInterface,
SetName,
// ID3D12DeviceChild
GetDevice,
// ID3D12Pageable
// ID3D12CommandQueue
UpdateTileMappings,
CopyTileMappings,
ExecuteCommandLists,
SetMarker,
BeginEvent,
EndEvent,
Signal,
Wait,
GetTimestampFrequency,
GetClockCalibration,
GetDesc,
};
enum class ID3D12GraphicsCommandListVTable
{
// IUnknown
QueryInterface,
AddRef,
Release,
// ID3D12Object
GetPrivateData,
SetPrivateData,
SetPrivateDataInterface,
SetName,
// ID3D12DeviceChild
GetDevice,
// ID3D12CommandList
GetType,
// ID3D12GraphicsCommandList
Close,
Reset,
ClearState,
DrawInstanced,
DrawIndexedInstanced,
Dispatch,
CopyBufferRegion,
CopyTextureRegion,
CopyResource,
CopyTiles,
ResolveSubresource,
IASetPrimitiveTopology,
RSSetViewports,
RSSetScissorRects,
OMSetBlendFactor,
OMSetStencilRef,
SetPipelineState,
ResourceBarrier,
ExecuteBundle,
SetDescriptorHeaps,
SetComputeRootSignature,
SetGraphicsRootSignature,
SetComputeRootDescriptorTable,
SetGraphicsRootDescriptorTable,
SetComputeRoot32BitConstant,
SetGraphicsRoot32BitConstant,
SetComputeRoot32BitConstants,
SetGraphicsRoot32BitConstants,
SetComputeRootConstantBufferView,
SetGraphicsRootConstantBufferView,
SetComputeRootShaderResourceView,
SetGraphicsRootShaderResourceView,
SetComputeRootUnorderedAccessView,
SetGraphicsRootUnorderedAccessView,
IASetIndexBuffer,
IASetVertexBuffers,
SOSetTargets,
OMSetRenderTargets,
ClearDepthStencilView,
ClearRenderTargetView,
ClearUnorderedAccessViewUint,
ClearUnorderedAccessViewFloat,
DiscardResource,
BeginQuery,
EndQuery,
ResolveQueryData,
SetPredication,
SetMarker,
BeginEvent,
EndEvent,
ExecuteIndirect,
};
enum class ID3D11DeviceVTable
{
// IUnknown
QueryInterface,
AddRef,
Release,
// ID3D11Device
CreateBuffer,
CreateTexture1D,
CreateTexture2D,
CreateTexture3D,
CreateShaderResourceView,
CreateUnorderedAccessView,
CreateRenderTargetView,
CreateDepthStencilView,
CreateInputLayout,
CreateVertexShader,
CreateGeometryShader,
CreateGeometryShaderWithStreamOutput,
CreatePixelShader,
CreateHullShader,
CreateDomainShader,
CreateComputeShader,
CreateClassLinkage,
CreateBlendState,
CreateDepthStencilState,
CreateRasterizerState,
CreateSamplerState,
CreateQuery,
CreatePredicate,
CreateCounter,
CreateDeferredContext,
OpenSharedResource,
CheckFormatSupport,
CheckMultisampleQualityLevels,
CheckCounterInfo,
CheckCounter,
CheckFeatureSupport,
GetPrivateData,
SetPrivateData,
SetPrivateDataInterface,
GetFeatureLevel,
GetCreationFlags,
GetDeviceRemovedReason,
GetImmediateContext,
SetExceptionMode,
GetExceptionMode,
};
enum class ID3D10DeviceVTable
{
// IUnknown
QueryInterface,
AddRef,
Release,
// ID3D10Device
VSSetConstantBuffers,
PSSetShaderResources,
PSSetShader,
PSSetSamplers,
VSSetShader,
DrawIndexed,
Draw,
PSSetConstantBuffers,
IASetInputLayout,
IASetVertexBuffers,
IASetIndexBuffer,
DrawIndexedInstanced,
DrawInstanced,
GSSetConstantBuffers,
GSSetShader,
IASetPrimitiveTopology,
VSSetShaderResources,
VSSetSamplers,
SetPredication,
GSSetShaderResources,
GSSetSamplers,
OMSetRenderTargets,
OMSetBlendState,
OMSetDepthStencilState,
SOSetTargets,
DrawAuto,
RSSetState,
RSSetViewports,
RSSetScissorRects,
CopySubresourceRegion,
CopyResource,
UpdateSubresource,
ClearRenderTargetView,
ClearDepthStencilView,
GenerateMips,
ResolveSubresource,
VSGetConstantBuffers,
PSGetShaderResources,
PSGetShader,
PSGetSamplers,
VSGetShader,
PSGetConstantBuffers,
IAGetInputLayout,
IAGetVertexBuffers,
IAGetIndexBuffer,
GSGetConstantBuffers,
GSGetShader,
IAGetPrimitiveTopology,
VSGetShaderResources,
VSGetSamplers,
GetPredication,
GSGetShaderResources,
GSGetSamplers,
OMGetRenderTargets,
OMGetBlendState,
OMGetDepthStencilState,
SOGetTargets,
RSGetState,
RSGetViewports,
RSGetScissorRects,
GetDeviceRemovedReason,
SetExceptionMode,
GetExceptionMode,
GetPrivateData,
SetPrivateData,
SetPrivateDataInterface,
ClearState,
Flush,
CreateBuffer,
CreateTexture1D,
CreateTexture2D,
CreateTexture3D,
CreateShaderResourceView,
CreateRenderTargetView,
CreateDepthStencilView,
CreateInputLayout,
CreateVertexShader,
CreateGeometryShader,
CreateGeometryShaderWithStreamOutput,
CreatePixelShader,
CreateBlendState,
CreateDepthStencilState,
CreateRasterizerState,
CreateSamplerState,
CreateQuery,
CreatePredicate,
CreateCounter,
CheckFormatSupport,
CheckMultisampleQualityLevels,
CheckCounterInfo,
CheckCounter,
GetCreationFlags,
OpenSharedResource,
SetTextFilterSize,
GetTextFilterSize,
};
enum class IDirect3DDevice9VTable
{
// IUnknown
QueryInterface,
AddRef,
Release,
// IDirect3DDevice9
TestCooperativeLevel,
GetAvailableTextureMem,
EvictManagedResources,
GetDirect3D,
GetDeviceCaps,
GetDisplayMode,
GetCreationParameters,
SetCursorProperties,
SetCursorPosition,
ShowCursor,
CreateAdditionalSwapChain,
GetSwapChain,
GetNumberOfSwapChains,
Reset,
Present,
GetBackBuffer,
GetRasterStatus,
SetDialogBoxMode,
SetGammaRamp,
GetGammaRamp,
CreateTexture,
CreateVolumeTexture,
CreateCubeTexture,
CreateVertexBuffer,
CreateIndexBuffer,
CreateRenderTarget,
CreateDepthStencilSurface,
UpdateSurface,
UpdateTexture,
GetRenderTargetData,
GetFrontBufferData,
StretchRect,
ColorFill,
CreateOffscreenPlainSurface,
SetRenderTarget,
GetRenderTarget,
SetDepthStencilSurface,
GetDepthStencilSurface,
BeginScene,
EndScene,
Clear,
SetTransform,
GetTransform,
MultiplyTransform,
SetViewport,
GetViewport,
SetMaterial,
GetMaterial,
SetLight,
GetLight,
LightEnable,
GetLightEnable,
SetClipPlane,
GetClipPlane,
SetRenderState,
GetRenderState,
CreateStateBlock,
BeginStateBlock,
EndStateBlock,
SetClipStatus,
GetClipStatus,
GetTexture,
SetTexture,
GetTextureStageState,
SetTextureStageState,
GetSamplerState,
SetSamplerState,
ValidateDevice,
SetPaletteEntries,
GetPaletteEntries,
SetCurrentTexturePalette,
GetCurrentTexturePalette,
SetScissorRect,
GetScissorRect,
SetSoftwareVertexProcessing,
GetSoftwareVertexProcessing,
SetNPatchMode,
GetNPatchMode,
DrawPrimitive,
DrawIndexedPrimitive,
DrawPrimitiveUP,
DrawIndexedPrimitiveUP,
ProcessVertices,
CreateVertexDeclaration,
SetVertexDeclaration,
GetVertexDeclaration,
SetFVF,
GetFVF,
CreateVertexShader,
SetVertexShader,
GetVertexShader,
SetVertexShaderConstantF,
GetVertexShaderConstantF,
SetVertexShaderConstantI,
GetVertexShaderConstantI,
SetVertexShaderConstantB,
GetVertexShaderConstantB,
SetStreamSource,
GetStreamSource,
SetStreamSourceFreq,
GetStreamSourceFreq,
SetIndices,
GetIndices,
CreatePixelShader,
SetPixelShader,
GetPixelShader,
SetPixelShaderConstantF,
GetPixelShaderConstantF,
SetPixelShaderConstantI,
GetPixelShaderConstantI,
SetPixelShaderConstantB,
GetPixelShaderConstantB,
DrawRectPatch,
DrawTriPatch,
DeletePatch,
CreateQuery,
// IDirect3DDevice9Ex
SetConvolutionMonoKernel,
ComposeRects,
PresentEx,
GetGPUThreadPriority,
SetGPUThreadPriority,
WaitForVBlank,
CheckResourceResidency,
SetMaximumFrameLatency,
GetMaximumFrameLatency,
CheckDeviceState,
CreateRenderTargetEx,
CreateOffscreenPlainSurfaceEx,
CreateDepthStencilSurfaceEx,
ResetEx,
GetDisplayModeEx,
};
enum class IDirect3DSwapChain9VTable
{
// IUnknown
QueryInterface,
AddRef,
Release,
// IDirect3DSwapChain9
Present,
GetFrontBufferData,
GetBackBuffer,
GetRasterStatus,
GetDisplayMode,
GetDevice,
GetPresentParameters,
// IDirect3DSwapChain9Ex
GetLastPresentCount,
GetPresentStats,
GetDisplayModeEx,
};

View File

@ -1,210 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "OpenGL_Hook.h"
#include "Windows_Hook.h"
#include <imgui.h>
#include <backends/imgui_impl_opengl3.h>
#include <glad/gl.h>
OpenGL_Hook* OpenGL_Hook::_inst = nullptr;
bool OpenGL_Hook::StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys)
{
if (!_Hooked)
{
if (wglSwapBuffers == nullptr)
{
SPDLOG_WARN("Failed to hook OpenGL: Rendering functions missing.");
return false;
}
if (!Windows_Hook::Inst()->StartHook(key_combination_callback, toggle_keys))
return false;
_WindowsHooked = true;
SPDLOG_INFO("Hooked OpenGL");
_Hooked = true;
UnhookAll();
BeginHook();
HookFuncs(
std::make_pair<void**, void*>(&(PVOID&)wglSwapBuffers, &OpenGL_Hook::MywglSwapBuffers)
);
EndHook();
}
return true;
}
bool OpenGL_Hook::IsStarted()
{
return _Hooked;
}
void OpenGL_Hook::_ResetRenderState()
{
if (_Initialized)
{
OverlayHookReady(false);
ImGui_ImplOpenGL3_Shutdown();
Windows_Hook::Inst()->ResetRenderState();
ImGui::DestroyContext();
_LastWindow = nullptr;
_Initialized = false;
}
}
// Try to make this function and overlay's proc as short as possible or it might affect game's fps.
void OpenGL_Hook::_PrepareForOverlay(HDC hDC)
{
HWND hWnd = WindowFromDC(hDC);
if (hWnd != _LastWindow)
_ResetRenderState();
if (!_Initialized)
{
ImGui::CreateContext((ImFontAtlas *)ImGuiFontAtlas);
ImGui_ImplOpenGL3_Init();
_LastWindow = hWnd;
Windows_Hook::Inst()->SetInitialWindowSize(hWnd);
_Initialized = true;
OverlayHookReady(true);
}
if (ImGui_ImplOpenGL3_NewFrame() && Windows_Hook::Inst()->PrepareForOverlay(hWnd))
{
ImGui::NewFrame();
OverlayProc();
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
}
}
BOOL WINAPI OpenGL_Hook::MywglSwapBuffers(HDC hDC)
{
auto inst = OpenGL_Hook::Inst();
inst->_PrepareForOverlay(hDC);
return inst->wglSwapBuffers(hDC);
}
OpenGL_Hook::OpenGL_Hook():
_Hooked(false),
_WindowsHooked(false),
_Initialized(false),
_LastWindow(nullptr),
wglSwapBuffers(nullptr)
{
}
OpenGL_Hook::~OpenGL_Hook()
{
SPDLOG_INFO("OpenGL Hook removed");
if (_WindowsHooked)
delete Windows_Hook::Inst();
if (_Initialized)
{
ImGui_ImplOpenGL3_Shutdown();
ImGui::DestroyContext();
}
_inst = nullptr;
}
OpenGL_Hook* OpenGL_Hook::Inst()
{
if (_inst == nullptr)
_inst = new OpenGL_Hook;
return _inst;
}
std::string OpenGL_Hook::GetLibraryName() const
{
return LibraryName;
}
void OpenGL_Hook::LoadFunctions(wglSwapBuffers_t pfnwglSwapBuffers)
{
wglSwapBuffers = pfnwglSwapBuffers;
}
std::weak_ptr<uint64_t> OpenGL_Hook::CreateImageResource(const void* image_data, uint32_t width, uint32_t height)
{
GLuint* texture = new GLuint(0);
glGenTextures(1, texture);
if (glGetError() != GL_NO_ERROR)
{
delete texture;
return std::shared_ptr<uint64_t>(nullptr);
}
// Save old texture id
GLint oldTex;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTex);
glBindTexture(GL_TEXTURE_2D, *texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Upload pixels into texture
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
glBindTexture(GL_TEXTURE_2D, oldTex);
auto ptr = std::shared_ptr<uint64_t>((uint64_t*)texture, [](uint64_t* handle)
{
if (handle != nullptr)
{
GLuint* texture = (GLuint*)handle;
glDeleteTextures(1, texture);
delete texture;
}
});
_ImageResources.emplace(ptr);
return ptr;
}
void OpenGL_Hook::ReleaseImageResource(std::weak_ptr<uint64_t> resource)
{
auto ptr = resource.lock();
if (ptr)
{
auto it = _ImageResources.find(ptr);
if (it != _ImageResources.end())
_ImageResources.erase(it);
}
}

View File

@ -1,67 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "overlay/internal_includes.h"
class OpenGL_Hook :
public ingame_overlay::Renderer_Hook,
public Base_Hook
{
public:
static constexpr const char *DLL_NAME = "opengl32.dll";
using wglSwapBuffers_t = BOOL(WINAPI*)(HDC);
private:
static OpenGL_Hook* _inst;
// Variables
bool _Hooked;
bool _WindowsHooked;
bool _Initialized;
HWND _LastWindow;
std::set<std::shared_ptr<uint64_t>> _ImageResources;
// Functions
OpenGL_Hook();
void _ResetRenderState();
void _PrepareForOverlay(HDC hDC);
// Hook to render functions
static BOOL WINAPI MywglSwapBuffers(HDC hDC);
wglSwapBuffers_t wglSwapBuffers;
public:
std::string LibraryName;
virtual ~OpenGL_Hook();
virtual bool StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys);
virtual bool IsStarted();
static OpenGL_Hook* Inst();
virtual std::string GetLibraryName() const;
void LoadFunctions(wglSwapBuffers_t pfnwglSwapBuffers);
virtual std::weak_ptr<uint64_t> CreateImageResource(const void* image_data, uint32_t width, uint32_t height);
virtual void ReleaseImageResource(std::weak_ptr<uint64_t> resource);
};

View File

@ -1,128 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "Vulkan_Hook.h"
#include "Windows_Hook.h"
#include <imgui.h>
#include <backends/imgui_impl_vulkan.h>
Vulkan_Hook* Vulkan_Hook::_inst = nullptr;
bool Vulkan_Hook::StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys)
{
SPDLOG_WARN("Vulkan overlay is not yet supported.");
return false;
if (!_Hooked)
{
if (vkQueuePresentKHR == nullptr)
{
SPDLOG_WARN("Failed to hook Vulkan: Rendering functions missing.");
return false;
}
if (!Windows_Hook::Inst()->StartHook(key_combination_callback, toggle_keys))
return false;
_WindowsHooked = true;
SPDLOG_INFO("Hooked Vulkan");
_Hooked = true;
BeginHook();
HookFuncs(
std::make_pair<void**, void*>(&(PVOID&)vkQueuePresentKHR, &Vulkan_Hook::MyvkQueuePresentKHR)
);
EndHook();
}
return true;
}
bool Vulkan_Hook::IsStarted()
{
return _Hooked;
}
void Vulkan_Hook::_ResetRenderState()
{
}
// Try to make this function and overlay's proc as short as possible or it might affect game's fps.
void Vulkan_Hook::_PrepareForOverlay()
{
}
VKAPI_ATTR VkResult VKAPI_CALL Vulkan_Hook::MyvkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* pPresentInfo)
{
auto inst = Vulkan_Hook::Inst();
inst->_PrepareForOverlay();
return inst->vkQueuePresentKHR(queue, pPresentInfo);
}
Vulkan_Hook::Vulkan_Hook():
_Hooked(false),
_WindowsHooked(false),
_Initialized(false),
vkQueuePresentKHR(nullptr)
{
}
Vulkan_Hook::~Vulkan_Hook()
{
SPDLOG_INFO("Vulkan_Hook Hook removed");
if (_WindowsHooked)
delete Windows_Hook::Inst();
if (_Initialized)
{
}
_inst = nullptr;
}
Vulkan_Hook* Vulkan_Hook::Inst()
{
if (_inst == nullptr)
_inst = new Vulkan_Hook;
return _inst;
}
std::string Vulkan_Hook::GetLibraryName() const
{
return LibraryName;
}
void Vulkan_Hook::LoadFunctions(decltype(::vkQueuePresentKHR)* _vkQueuePresentKHR)
{
vkQueuePresentKHR = _vkQueuePresentKHR;
}
std::weak_ptr<uint64_t> Vulkan_Hook::CreateImageResource(const void* image_data, uint32_t width, uint32_t height)
{
return std::shared_ptr<uint64_t>(nullptr);
}
void Vulkan_Hook::ReleaseImageResource(std::weak_ptr<uint64_t> resource)
{
}

View File

@ -1,65 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "overlay/internal_includes.h"
#include <vulkan/vulkan.h>
class Vulkan_Hook :
public ingame_overlay::Renderer_Hook,
public Base_Hook
{
public:
static constexpr const char *DLL_NAME = "vulkan-1.dll";
private:
static Vulkan_Hook* _inst;
// Variables
bool _Hooked;
bool _WindowsHooked;
bool _Initialized;
// Functions
Vulkan_Hook();
void _ResetRenderState();
void _PrepareForOverlay();
// Hook to render functions
static VKAPI_ATTR VkResult VKAPI_CALL MyvkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* pPresentInfo);
decltype(::vkQueuePresentKHR)* vkQueuePresentKHR;
public:
std::string LibraryName;
virtual ~Vulkan_Hook();
virtual bool StartHook(std::function<bool(bool)> key_combination_callback, std::set<ingame_overlay::ToggleKey> toggle_keys);
virtual bool IsStarted();
static Vulkan_Hook* Inst();
virtual std::string GetLibraryName() const;
void LoadFunctions(decltype(::vkQueuePresentKHR)* _vkQueuePresentKHR);
virtual std::weak_ptr<uint64_t> CreateImageResource(const void* image_data, uint32_t width, uint32_t height);
virtual void ReleaseImageResource(std::weak_ptr<uint64_t> resource);
};

View File

@ -1,480 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "Windows_Hook.h"
#include <imgui.h>
#include <backends/imgui_impl_win32.h>
#include <System/Library.h>
extern LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
constexpr decltype(Windows_Hook::DLL_NAME) Windows_Hook::DLL_NAME;
Windows_Hook* Windows_Hook::_inst = nullptr;
int ToggleKeyToNativeKey(ingame_overlay::ToggleKey k)
{
struct {
ingame_overlay::ToggleKey lib_key;
int native_key;
} mapping[] = {
{ ingame_overlay::ToggleKey::ALT , VK_MENU },
{ ingame_overlay::ToggleKey::CTRL , VK_CONTROL },
{ ingame_overlay::ToggleKey::SHIFT, VK_SHIFT },
{ ingame_overlay::ToggleKey::TAB , VK_TAB },
{ ingame_overlay::ToggleKey::F1 , VK_F1 },
{ ingame_overlay::ToggleKey::F2 , VK_F2 },
{ ingame_overlay::ToggleKey::F3 , VK_F3 },
{ ingame_overlay::ToggleKey::F4 , VK_F4 },
{ ingame_overlay::ToggleKey::F5 , VK_F5 },
{ ingame_overlay::ToggleKey::F6 , VK_F6 },
{ ingame_overlay::ToggleKey::F7 , VK_F7 },
{ ingame_overlay::ToggleKey::F8 , VK_F8 },
{ ingame_overlay::ToggleKey::F9 , VK_F9 },
{ ingame_overlay::ToggleKey::F10 , VK_F10 },
{ ingame_overlay::ToggleKey::F11 , VK_F11 },
{ ingame_overlay::ToggleKey::F12 , VK_F12 },
};
for (auto const& item : mapping)
{
if (item.lib_key == k)
return item.native_key;
}
return 0;
}
bool Windows_Hook::StartHook(std::function<bool(bool)>& _key_combination_callback, std::set<ingame_overlay::ToggleKey> const& toggle_keys)
{
if (!_Hooked)
{
if (!_key_combination_callback)
{
SPDLOG_ERROR("Failed to hook Windows: No key combination callback.");
return false;
}
if (toggle_keys.empty())
{
SPDLOG_ERROR("Failed to hook Windows: No key combination.");
return false;
}
void* hUser32 = System::Library::GetLibraryHandle(DLL_NAME);
if (hUser32 == nullptr)
{
SPDLOG_WARN("Failed to hook Windows: Cannot find {}", DLL_NAME);
return false;
}
System::Library::Library libUser32;
LibraryName = System::Library::GetLibraryPath(hUser32);
if (!libUser32.OpenLibrary(LibraryName, false))
{
SPDLOG_WARN("Failed to hook Windows: Cannot load {}", LibraryName);
return false;
}
struct {
void** func_ptr;
void* hook_ptr;
const char* func_name;
} hook_array[] = {
{ (void**)&GetRawInputBuffer, &Windows_Hook::MyGetRawInputBuffer, "GetRawInputBuffer" },
{ (void**)&GetRawInputData , &Windows_Hook::MyGetRawInputData , "GetRawInputData" },
{ (void**)&GetKeyState , &Windows_Hook::MyGetKeyState , "GetKeyState" },
{ (void**)&GetAsyncKeyState , &Windows_Hook::MyGetAsyncKeyState , "GetAsyncKeyState" },
{ (void**)&GetKeyboardState , &Windows_Hook::MyGetKeyboardState , "GetKeyboardState" },
{ (void**)&GetCursorPos , &Windows_Hook::MyGetCursorPos , "GetCursorPos" },
{ (void**)&SetCursorPos , &Windows_Hook::MySetCursorPos , "SetCursorPos" },
{ (void**)&GetClipCursor , &Windows_Hook::MyGetClipCursor , "GetClipCursor" },
{ (void**)&ClipCursor , &Windows_Hook::MyClipCursor , "ClipCursor" },
};
for (auto& entry : hook_array)
{
*entry.func_ptr = libUser32.GetSymbol<void*>(entry.func_name);
if (entry.func_ptr == nullptr)
{
SPDLOG_ERROR("Failed to hook Windows: Events function {} missing.", entry.func_name);
return false;
}
}
SPDLOG_INFO("Hooked Windows");
_KeyCombinationCallback = std::move(_key_combination_callback);
for (auto& key : toggle_keys)
{
uint32_t k = ToggleKeyToNativeKey(key);
if (k != 0)
{
_NativeKeyCombination.insert(k);
}
}
BeginHook();
for (auto& entry : hook_array)
{
HookFunc(std::make_pair(entry.func_ptr, entry.hook_ptr));
}
EndHook();
_Hooked = true;
}
return true;
}
void Windows_Hook::ResetRenderState()
{
if (_Initialized)
{
_Initialized = false;
SetWindowLongPtr(_GameHwnd, GWLP_WNDPROC, (LONG_PTR)_GameWndProc);
_GameHwnd = nullptr;
_GameWndProc = nullptr;
ImGui_ImplWin32_Shutdown();
}
}
void Windows_Hook::SetInitialWindowSize(HWND hWnd)
{
RECT rect = { 0, 0, 0, 0 };
::GetClientRect(hWnd, &rect);
ImGui::GetIO().DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top));
}
bool Windows_Hook::PrepareForOverlay(HWND hWnd)
{
if (_GameHwnd != hWnd)
ResetRenderState();
if (!_Initialized)
{
_GameHwnd = hWnd;
ImGui_ImplWin32_Init(_GameHwnd);
_GameWndProc = (WNDPROC)SetWindowLongPtr(_GameHwnd, GWLP_WNDPROC, (LONG_PTR)&Windows_Hook::HookWndProc);
_Initialized = true;
}
if (_Initialized)
{
void* current_proc = (void*)GetWindowLongPtr(_GameHwnd, GWLP_WNDPROC);
if (current_proc == nullptr)
return false;
ImGui_ImplWin32_NewFrame();
// Read keyboard modifiers inputs
auto& io = ImGui::GetIO();
POINT pos;
if (this->GetCursorPos(&pos) && ScreenToClient(hWnd, &pos))
{
io.AddMousePosEvent((float)pos.x, (float)pos.y);
}
return true;
}
return false;
}
HWND Windows_Hook::GetGameHwnd() const
{
return _GameHwnd;
}
WNDPROC Windows_Hook::GetGameWndProc() const
{
return _GameWndProc;
}
/////////////////////////////////////////////////////////////////////////////////////
// Windows window hooks
bool IgnoreMsg(UINT uMsg)
{
switch (uMsg)
{
// Mouse Events
case WM_MOUSEMOVE:
case WM_MOUSEWHEEL: case WM_MOUSEHWHEEL:
case WM_LBUTTONUP: case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK:
case WM_RBUTTONUP: case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK:
case WM_MBUTTONUP: case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK:
case WM_XBUTTONUP: case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK:
case WM_MOUSEACTIVATE: case WM_MOUSEHOVER: case WM_MOUSELEAVE:
// Keyboard Events
case WM_KEYDOWN: case WM_KEYUP:
case WM_SYSKEYDOWN: case WM_SYSKEYUP: case WM_SYSDEADCHAR:
case WM_CHAR: case WM_UNICHAR: case WM_DEADCHAR:
// Raw Input Events
case WM_INPUT:
return true;
}
return false;
}
void RawEvent(RAWINPUT& raw)
{
HWND hWnd = Windows_Hook::Inst()->GetGameHwnd();
switch(raw.header.dwType)
{
case RIM_TYPEMOUSE:
if (raw.data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN)
ImGui_ImplWin32_WndProcHandler(hWnd, WM_LBUTTONDOWN, 0, 0);
if (raw.data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP)
ImGui_ImplWin32_WndProcHandler(hWnd, WM_LBUTTONUP, 0, 0);
if (raw.data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN)
ImGui_ImplWin32_WndProcHandler(hWnd, WM_RBUTTONDOWN, 0, 0);
if (raw.data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_UP)
ImGui_ImplWin32_WndProcHandler(hWnd, WM_RBUTTONUP, 0, 0);
if (raw.data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN)
ImGui_ImplWin32_WndProcHandler(hWnd, WM_MBUTTONDOWN, 0, 0);
if (raw.data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_UP)
ImGui_ImplWin32_WndProcHandler(hWnd, WM_MBUTTONUP, 0, 0);
if (raw.data.mouse.usButtonFlags & RI_MOUSE_WHEEL)
ImGui_ImplWin32_WndProcHandler(hWnd, WM_MOUSEWHEEL, ((WPARAM)raw.data.mouse.usButtonData) << 16, 0);
if (raw.data.mouse.usButtonFlags & RI_MOUSE_HWHEEL)
ImGui_ImplWin32_WndProcHandler(hWnd, WM_MOUSEHWHEEL, ((WPARAM)raw.data.mouse.usButtonData) << 16, 0);
break;
//case RIM_TYPEKEYBOARD:
//ImGui_ImplWin32_WndProcHandler(hWnd, raw.data.keyboard.Message, raw.data.keyboard.VKey, 0);
//break;
}
}
LRESULT CALLBACK Windows_Hook::HookWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
Windows_Hook* inst = Windows_Hook::Inst();
bool skip_input = inst->_KeyCombinationCallback(false);
bool clean_keys = false;
if (inst->_Initialized)
{
// Is the event is a key press
if (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN || uMsg == WM_KEYUP || uMsg == WM_SYSKEYUP)
{
int key_count = 0;
for (auto const& key : inst->_NativeKeyCombination)
{
if (inst->GetAsyncKeyState(key) & (1 << 15))
++key_count;
}
if (key_count == inst->_NativeKeyCombination.size())
{// All shortcut keys are pressed
if (!inst->_KeyCombinationPushed)
{
if (inst->_KeyCombinationCallback(true))
{
skip_input = true;
// Save the last known cursor pos when opening the overlay
// so we can spoof the GetCursorPos return value.
inst->GetCursorPos(&inst->_SavedCursorPos);
inst->GetClipCursor(&inst->_SavedClipCursor);
}
else
{
inst->ClipCursor(&inst->_SavedClipCursor);
}
inst->_KeyCombinationPushed = true;
}
}
else
{
inst->_KeyCombinationPushed = false;
}
}
if (skip_input && IgnoreMsg(uMsg))
{
ImGui_ImplWin32_WndProcHandler(hWnd, uMsg, wParam, lParam);
if (clean_keys)
{
auto& io = ImGui::GetIO();
io.ClearInputKeys();
io.ClearInputCharacters();
}
return 0;
}
}
// Protect against recursive call of the WindowProc...
if (inst->_RecurseCallCount > 16)
return 0;
++inst->_RecurseCallCount;
// Call the overlay window procedure
auto res = CallWindowProc(Windows_Hook::Inst()->_GameWndProc, hWnd, uMsg, wParam, lParam);
--inst->_RecurseCallCount;
return res;
}
UINT WINAPI Windows_Hook::MyGetRawInputBuffer(PRAWINPUT pData, PUINT pcbSize, UINT cbSizeHeader)
{
Windows_Hook* inst = Windows_Hook::Inst();
int res = inst->GetRawInputBuffer(pData, pcbSize, cbSizeHeader);
if (!inst->_Initialized)
return res;
if (pData != nullptr)
{
for (int i = 0; i < res; ++i)
RawEvent(pData[i]);
}
if (!inst->_KeyCombinationCallback(false))
return res;
return 0;
}
UINT WINAPI Windows_Hook::MyGetRawInputData(HRAWINPUT hRawInput, UINT uiCommand, LPVOID pData, PUINT pcbSize, UINT cbSizeHeader)
{
Windows_Hook* inst = Windows_Hook::Inst();
auto res = inst->GetRawInputData(hRawInput, uiCommand, pData, pcbSize, cbSizeHeader);
if (!inst->_Initialized || pData == nullptr)
return res;
if (uiCommand == RID_INPUT && res == sizeof(RAWINPUT))
RawEvent(*reinterpret_cast<RAWINPUT*>(pData));
if (!inst->_KeyCombinationCallback(false))
return res;
memset(pData, 0, *pcbSize);
*pcbSize = 0;
return 0;
}
SHORT WINAPI Windows_Hook::MyGetKeyState(int nVirtKey)
{
Windows_Hook* inst = Windows_Hook::Inst();
if (inst->_Initialized && inst->_KeyCombinationCallback(false))
return 0;
return inst->GetKeyState(nVirtKey);
}
SHORT WINAPI Windows_Hook::MyGetAsyncKeyState(int vKey)
{
Windows_Hook* inst = Windows_Hook::Inst();
if (inst->_Initialized && inst->_KeyCombinationCallback(false))
return 0;
return inst->GetAsyncKeyState(vKey);
}
BOOL WINAPI Windows_Hook::MyGetKeyboardState(PBYTE lpKeyState)
{
Windows_Hook* inst = Windows_Hook::Inst();
if (inst->_Initialized && inst->_KeyCombinationCallback(false))
return FALSE;
return inst->GetKeyboardState(lpKeyState);
}
BOOL WINAPI Windows_Hook::MyGetCursorPos(LPPOINT lpPoint)
{
Windows_Hook* inst = Windows_Hook::Inst();
BOOL res = inst->GetCursorPos(lpPoint);
if (inst->_Initialized && inst->_KeyCombinationCallback(false) && lpPoint != nullptr)
{
*lpPoint = inst->_SavedCursorPos;
}
return res;
}
BOOL WINAPI Windows_Hook::MySetCursorPos(int X, int Y)
{
Windows_Hook* inst = Windows_Hook::Inst();
if (!inst->_Initialized || !inst->_KeyCombinationCallback(false))
return inst->SetCursorPos(X, Y);
return TRUE;
}
BOOL WINAPI Windows_Hook::MyGetClipCursor(RECT* lpRect)
{
Windows_Hook* inst = Windows_Hook::Inst();
if (lpRect == nullptr || !inst->_Initialized || !inst->_KeyCombinationCallback(false))
return inst->GetClipCursor(lpRect);
*lpRect = inst->_SavedClipCursor;
return TRUE;
}
BOOL WINAPI Windows_Hook::MyClipCursor(CONST RECT* lpRect)
{
Windows_Hook* inst = Windows_Hook::Inst();
CONST RECT* v = lpRect == nullptr ? &inst->_DefaultClipCursor : lpRect;
inst->_SavedClipCursor = *v;
if (!inst->_Initialized || !inst->_KeyCombinationCallback(false))
return inst->ClipCursor(v);
return inst->ClipCursor(&inst->_DefaultClipCursor);
}
/////////////////////////////////////////////////////////////////////////////////////
Windows_Hook::Windows_Hook() :
_Initialized(false),
_Hooked(false),
_RecurseCallCount(0),
_GameHwnd(nullptr),
_GameWndProc(nullptr),
_DefaultClipCursor{ LONG(0xFFFF8000), LONG(0xFFFF8000), LONG(0x00007FFF), LONG(0x00007FFF) },
_KeyCombinationPushed(false)
{
}
Windows_Hook::~Windows_Hook()
{
SPDLOG_INFO("Windows Hook removed");
ResetRenderState();
_inst = nullptr;
}
Windows_Hook* Windows_Hook::Inst()
{
if (_inst == nullptr)
_inst = new Windows_Hook;
return _inst;
}
std::string Windows_Hook::GetLibraryName() const
{
return LibraryName;
}

View File

@ -1,89 +0,0 @@
/*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "overlay/internal_includes.h"
class Windows_Hook :
public Base_Hook
{
public:
static constexpr const char* DLL_NAME = "user32.dll";
private:
static Windows_Hook* _inst;
// Variables
bool _Hooked;
bool _Initialized;
int _RecurseCallCount;
HWND _GameHwnd;
WNDPROC _GameWndProc;
POINT _SavedCursorPos;
RECT _SavedClipCursor;
CONST RECT _DefaultClipCursor;
// In (bool): Is toggle wanted
// Out(bool): Is the overlay visible, if true, inputs will be disabled
std::function<bool(bool)> _KeyCombinationCallback;
std::set<int> _NativeKeyCombination;
bool _KeyCombinationPushed;
// Functions
Windows_Hook();
// Hook to Windows window messages
decltype(::GetRawInputBuffer) *GetRawInputBuffer;
decltype(::GetRawInputData) *GetRawInputData;
decltype(::GetKeyState) *GetKeyState;
decltype(::GetAsyncKeyState) *GetAsyncKeyState;
decltype(::GetKeyboardState) *GetKeyboardState;
decltype(::GetCursorPos) *GetCursorPos;
decltype(::SetCursorPos) *SetCursorPos;
decltype(::GetClipCursor) *GetClipCursor;
decltype(::ClipCursor) *ClipCursor;
static LRESULT CALLBACK HookWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static UINT WINAPI MyGetRawInputBuffer(PRAWINPUT pData, PUINT pcbSize, UINT cbSizeHeader);
static UINT WINAPI MyGetRawInputData(HRAWINPUT hRawInput, UINT uiCommand, LPVOID pData, PUINT pcbSize, UINT cbSizeHeader);
static SHORT WINAPI MyGetKeyState(int nVirtKey);
static SHORT WINAPI MyGetAsyncKeyState(int vKey);
static BOOL WINAPI MyGetKeyboardState(PBYTE lpKeyState);
static BOOL WINAPI MyGetCursorPos(LPPOINT lpPoint);
static BOOL WINAPI MySetCursorPos(int X, int Y);
static BOOL WINAPI MyGetClipCursor(RECT* lpRect);
static BOOL WINAPI MyClipCursor(CONST RECT* lpRect);
public:
std::string LibraryName;
virtual ~Windows_Hook();
void ResetRenderState();
void SetInitialWindowSize(HWND hWnd);
bool PrepareForOverlay(HWND hWnd);
HWND GetGameHwnd() const;
WNDPROC GetGameWndProc() const;
bool StartHook(std::function<bool(bool)>& key_combination_callback, std::set<ingame_overlay::ToggleKey> const& toggle_keys);
static Windows_Hook* Inst();
virtual std::string GetLibraryName() const;
};

File diff suppressed because it is too large Load Diff