mumble-voip_mumble/plugins/mumble_positional_audio_uti...

214 lines
5.6 KiB
C++

// Copyright 2021-2023 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_POSITIONAL_AUDIO_UTILS_H_
#define MUMBLE_POSITIONAL_AUDIO_UTILS_H_
#include <cmath>
#include <codecvt>
#include <fstream>
#include <locale>
#include <sstream>
#include <vector>
#ifdef OS_LINUX
# include <fenv.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) {}
};
/// Converts from UTF-8 to UTF-16.
static inline std::wstring utf8ToUtf16(const std::string &str) {
try {
std::wstring_convert< std::codecvt_utf8_utf16< wchar_t > > conv;
return conv.from_bytes(str);
} catch (std::range_error &) {
return {};
}
}
/// Converts from UTF-16 to UTF-8.
/// Meant to be used when "wchar_t" is 2 bytes, usually with Windows processes.
static inline std::string utf16ToUtf8(const std::u16string &str) {
try {
std::wstring_convert< std::codecvt_utf8_utf16< char16_t >, char16_t > conv;
return conv.to_bytes(str);
} catch (std::range_error &) {
return {};
}
}
/// Converts from UTF-16 to UTF-8.
/// Meant to be used when "wchar_t" is 4 bytes, usually with Linux processes.
static inline std::string utf16ToUtf8(const std::u32string &str) {
try {
std::wstring_convert< std::codecvt_utf8_utf16< char32_t >, char32_t > conv;
return conv.to_bytes(str);
} catch (std::range_error &) {
return {};
}
}
// 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;
}
}
/// Reads the file's content and returns it in a std::string.
static inline std::string readFile(const std::string &path) {
std::ifstream ifs(path, std::ifstream::binary);
std::string content;
char buf[256];
while (ifs.good()) {
ifs.read(&buf[0], sizeof(buf));
size_t read = ifs.gcount();
if (read > 0) {
content.append(&buf[0], read);
}
}
return content;
}
/// Reads characters from the stream until \p character is encountered.
/// @return Read characters and whether the stream is still good.
static inline std::pair< std::string, bool > readUntil(std::stringstream &stream,
const std::stringstream::int_type character) {
std::string buf;
for (auto input = stream.get(); input != character; input = stream.get()) {
if (!stream) {
return { buf, false };
}
buf.push_back(input);
};
return { buf, true };
}
/// Discards characters in the stream until the specified one is encountered.
/// @param[inverted] Inverts the behavior.
/// @return Whether the stream is still good.
static inline bool skipUntil(std::stringstream &stream, const std::stringstream::int_type character,
const bool inverted) {
for (auto input = stream.get(); inverted ? (input == character) : (input != character); input = stream.get()) {
if (!stream) {
return false;
}
}
return true;
}
/// Returns the index of the specified pattern in the specified buffer.
/// "?" is used as wildcard character.
/// If the pattern is not found, the function returns SIZE_MAX.
static inline size_t searchInBuffer(const std::vector< uint8_t > &pattern, const std::vector< uint8_t > &buffer) {
for (size_t i = 0; i < buffer.size() - pattern.size(); ++i) {
const auto *buf = &buffer[i];
bool match = true;
for (size_t j = 0; j < pattern.size(); ++j) {
if (pattern[j] != '?' && buf[j] != pattern[j]) {
match = false;
break;
}
}
if (match) {
return buf - &buffer[0];
}
}
return SIZE_MAX;
}
/// 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