Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mumble-voip/mumble.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavide Beatrici <git@davidebeatrici.dev>2020-09-27 20:59:18 +0300
committerDavide Beatrici <git@davidebeatrici.dev>2020-09-27 20:59:18 +0300
commitd8c4b82efee8f2e0785f04ed8d9e7c8b24cdca4d (patch)
treeb503b8314a8cca8de00549f904c2d8bc98fba10f /plugins/mumble_plugin_main.h
parent6e33d349b07d26cd3ebb97067df7daa41a9b508f (diff)
FEAT(client): add several new functions to be used in positional audio plugins
- peekProcString(): reads the specified amount of data at the specified address and returns it as std::string. An empty std::string is returned in case of error. If length is 0, the function reads one byte at a time and stops when either '\0' is found or 3 seconds have passed. The successfully read data is returned, also in case of error. - peekProcVector(): can be used to read a dynamic array (size known at runtime) from the process' memory. Dynamic arrays are part of C99, which should be supported by most compilers nowadays, but std::vector provides many advantages (e.g. easy resize) over a raw array. - getVirtualFunction(): gets the address of a virtual function given its index and the class object's base address. A macro called GET_POINTER_SIZE is added because "is64Bit ? 8 : 4" is used in two places now. Also, it's useful and intuitive for plugin(s) programmers. - sinCos(): calculates sine and cosine of the specified value. On Linux the calculation is guaranteed to be simultaneous. - degreesToRadians(): converts degrees to radians. - isBigEndian(): returns whether the architecture is big-endian, by checking how a 4-byte value is stored in memory. - networkToHost() converts from network byte order to host byte order. I decided to create our own function because ntohs() is part of winsock(2).h on Windows, which means we would have to link to "ws2_32". This commit also adds and makes use of the new "OS_WINDOWS" and "OS_LINUX" definitions. The reason behind their existence is the "_WIN32" and "__linux__" definitions not being intuitive, mainly because they don't follow the same naming convention.
Diffstat (limited to 'plugins/mumble_plugin_main.h')
-rw-r--r--plugins/mumble_plugin_main.h99
1 files changed, 95 insertions, 4 deletions
diff --git a/plugins/mumble_plugin_main.h b/plugins/mumble_plugin_main.h
index 6088cdbd8..f4b5be5b1 100644
--- a/plugins/mumble_plugin_main.h
+++ b/plugins/mumble_plugin_main.h
@@ -14,12 +14,18 @@
#ifndef MUMBLE_PLUGIN_MAIN_H_
#define MUMBLE_PLUGIN_MAIN_H_
+#if !defined(OS_WINDOWS) && !defined(OS_LINUX)
+# error "Please define either OS_WINDOWS or OS_LINUX"
+#endif
+
#include "mumble_plugin.h"
#include "mumble_plugin_win32_internals.h"
+#include <chrono>
#include <cstring>
+#include <vector>
-#ifdef WIN32
+#ifdef OS_WINDOWS
static const bool isWin32 = true;
#else
static bool isWin32;
@@ -29,6 +35,8 @@ static bool is64Bit;
static procid_t pPid;
static procptr_t pModule;
+#define GET_POINTER_SIZE (is64Bit ? 8 : 4)
+
static inline bool peekProc(const procptr_t &addr, void *dest, const size_t &len);
static inline procptr_t getModuleAddr(const procid_t &pid, const wchar_t *modname);
@@ -50,21 +58,104 @@ template< class T > static inline T peekProc(const procptr_t &addr) {
return ret;
}
+template< typename T > static inline std::vector< T > peekProcVector(const procptr_t addr, const size_t elements) {
+ try {
+ std::vector< T > var(elements);
+ peekProc(addr, &var[0], sizeof(T) * elements);
+ return var;
+ } catch (std::bad_alloc &) {
+ return std::vector< T >();
+ }
+}
+
+/// This function is very useful when there is an array of structures and we only need to store a part of each.
+/// The Source Engine plugin needs it because there is a structure that happens to be larger in the Linux version of
+/// Left 4 Dead 2. Since the extra members are unknown, we simply discard the extra bytes when reading the array of
+/// structures.
+template< typename T >
+static inline std::vector< T > peekProcVector(const procptr_t addr, const size_t elements,
+ const size_t realStructSize) {
+ if (realStructSize == sizeof(T)) {
+ // If the structure's size is correct, there is no need for this special function.
+ return peekProcVector< T >(addr, elements);
+ } else if (realStructSize < sizeof(T)) {
+ return std::vector< T >();
+ }
+
+ // Read the full structures into a vector.
+ const std::vector< uint8_t > fullStructs = peekProcVector< uint8_t >(addr, realStructSize * elements);
+
+ // Allocate vector for the known structures.
+ std::vector< T > ret(elements);
+
+ // Copy elements from the vector containing the full structures, discarding extra bytes.
+ const uint8_t *seek = &fullStructs[0];
+
+ for (size_t i = 0; i < elements; ++i, seek += realStructSize) {
+ memcpy(&ret[i], seek, sizeof(T));
+ }
+
+ return ret;
+}
+
+/// Reads the specified amount of data at the specified address and returns it as std::string.
+/// An empty std::string is returned in case of error.
+///
+/// If \p length is 0, the function reads one byte at a time and stops when either '\0' is found or 3 seconds have
+/// passed. The successfully read data is returned, also in case of error.
+static inline std::string peekProcString(const procptr_t addr, const size_t length = 0) {
+ std::string string;
+
+ if (length > 0) {
+ string.resize(length);
+
+ if (!peekProc(addr, &string[0], length)) {
+ return std::string();
+ }
+ } else {
+ auto now = std::chrono::steady_clock::now();
+ const auto end = now + std::chrono::seconds(3);
+
+ for (procptr_t i = 0; now < end; ++i) {
+ char ch = 0;
+ if (!peekProc(addr + i, &ch, sizeof(ch)) || ch == '\0') {
+ break;
+ }
+
+ string += ch;
+
+ // Update current time.
+ now = std::chrono::steady_clock::now();
+ }
+ }
+
+ return string;
+}
+
static inline procptr_t peekProcPtr(const procptr_t &addr) {
procptr_t v = 0;
- if (!peekProc(addr, &v, is64Bit ? 8 : 4)) {
+ if (!peekProc(addr, &v, GET_POINTER_SIZE)) {
return 0;
}
return v;
}
+static inline procptr_t getVirtualFunction(const procptr_t classObject, const size_t index) {
+ const auto vTable = peekProcPtr(classObject);
+ if (!vTable) {
+ return 0;
+ }
+
+ return peekProcPtr(vTable + (index * GET_POINTER_SIZE));
+}
+
// This function returns:
// -1 in case of failure.
// 0 if the process is 32-bit.
// 1 if the process is 64-bit.
-#ifdef WIN32
+#ifdef OS_WINDOWS
static inline int8_t isProcess64Bit(const procptr_t &baseAddress) {
#else
// We use a different name because the function is called by the Linux version
@@ -91,7 +182,7 @@ static inline int8_t isWin32Process64Bit(const procptr_t &baseAddress) {
}
}
-#ifdef WIN32
+#ifdef OS_WINDOWS
# include "../mumble_plugin_win32.h"
#else
# include "../mumble_plugin_linux.h"