mirror of
https://github.com/Detanup01/gbe_fork.git
synced 2024-11-27 05:04:01 +08:00
remove the source files of the ingame overlay project, now it's a dependency
This commit is contained in:
parent
9792545068
commit
4aa0f58199
@ -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
@ -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; \
|
||||
}
|
@ -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...>;
|
||||
}
|
||||
}
|
@ -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
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
@ -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;
|
||||
};
|
||||
}
|
@ -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
|
||||
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
@ -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
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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()); }
|
||||
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
@ -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
|
||||
|
||||
}
|
@ -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();
|
||||
|
||||
}
|
@ -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
|
@ -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
|
||||
*/
|
@ -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
|
@ -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
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
@ -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__
|
@ -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();
|
||||
|
||||
}
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
@ -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
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
@ -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(¶ms) == D3D_OK)
|
||||
{
|
||||
destWindow = params.hDeviceWindow;
|
||||
}
|
||||
|
||||
pSwapChain->Release();
|
||||
}
|
||||
}
|
||||
|
||||
//Is this necessary anymore?
|
||||
if (!destWindow)
|
||||
{
|
||||
D3DDEVICE_CREATION_PARAMETERS param;
|
||||
pDevice->GetCreationParameters(¶m);
|
||||
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(¶m) == 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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
@ -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,
|
||||
};
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
@ -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)
|
||||
{
|
||||
|
||||
}
|
@ -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);
|
||||
};
|
@ -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;
|
||||
}
|
@ -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
Loading…
Reference in New Issue
Block a user