mumble/plugins/mumble_plugin_utils.h
Davide Beatrici d8c4b82efe 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.
2020-09-27 19:59:18 +02:00

116 lines
2.9 KiB
C++

// Copyright 2005-2020 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.
#ifndef MUMBLE_MUMBLE_PLUGIN_UTILS_H_
#define MUMBLE_MUMBLE_PLUGIN_UTILS_H_
#include <codecvt>
#include <locale>
#ifdef OS_LINUX
# include <fenv.h>
#endif
#ifdef _MSC_VER
# include <intrin.h>
#endif
/// This union is used by isBigEndian() to determine the endianness.
union SingleSplit4Bytes {
uint32_t single;
uint8_t split[4];
constexpr SingleSplit4Bytes(const uint32_t value) : single(value) {}
};
static inline std::string utf16ToUtf8(const std::wstring &wstr) {
std::wstring_convert< std::codecvt_utf8_utf16< wchar_t > > conv;
return conv.to_bytes(wstr);
}
// escape lossily converts the given
// string to ASCII, replacing any
// character not within the printable
// ASCII region (32-126) with an ASCII
// space character.
//
// escape also replaces any double quote
// characters with an ASCII space. This
// allows the string to be safely used
// when constructing JSON documents via
// string concatenation.
//
// Finally, escape ensures that the given
// string is NUL-terminated by always
// setting the last byte of the input
// string to the value 0.
static inline void escape(char *str, const size_t &size) {
// Ensure the input string is properly NUL-terminated.
str[size - 1] = 0;
char *c = str;
while (*c != '\0') {
// For JSON compatibility, the string
// can't contain double quotes.
// If a double quote is found, replace
// it with an ASCII space.
if (*c == '"') {
*c = ' ';
}
// Ensure the string is within printable
// ASCII. If not, replace the offending
// byte with an ASCII space.
if (*c < 32 || *c > 126) {
*c = ' ';
}
c += 1;
}
}
/// Calculates sine and cosine of the specified value.
/// On Linux the calculation is guaranteed to be simultaneous.
static inline bool sinCos(const float value, float &outSin, float &outCos) {
#ifdef OS_WINDOWS
outSin = sin(value);
outCos = cos(value);
return true;
#else
errno = 0;
feclearexcept(FE_ALL_EXCEPT);
sincosf(value, &outSin, &outCos);
return fetestexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW) == 0;
#endif
}
/// Converts degrees to radians.
static inline float degreesToRadians(const float degrees) {
constexpr float piOver180 = M_PI / 180.0f;
return piOver180 * degrees;
}
/// Detects whether the architecture is big-endian.
static constexpr bool isBigEndian() {
// An union allows access to a single byte without the need for a cast.
return SingleSplit4Bytes(0x01020304).split[0] == 1;
}
/// Converts from network byte order to host byte order.
static inline uint16_t networkToHost(const uint16_t value) {
if (isBigEndian()) {
return value;
}
#ifdef _MSC_VER
return _byteswap_ushort(value);
#else
return __builtin_bswap16(value);
#endif
}
#endif