Skip to content

Commit 53b055b

Browse files
refactor: re-use windows platform utf-8 functions
1 parent 29d3bb8 commit 53b055b

File tree

16 files changed

+441
-670
lines changed

16 files changed

+441
-670
lines changed

cmake/compile_definitions/windows.cmake

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ set(PLATFORM_TARGET_FILES
5959
"${CMAKE_SOURCE_DIR}/src/platform/windows/display_ram.cpp"
6060
"${CMAKE_SOURCE_DIR}/src/platform/windows/display_wgc.cpp"
6161
"${CMAKE_SOURCE_DIR}/src/platform/windows/audio.cpp"
62-
"${CMAKE_SOURCE_DIR}/src/platform/windows/tools/helper.h"
62+
"${CMAKE_SOURCE_DIR}/src/platform/windows/utf_utils.cpp"
63+
"${CMAKE_SOURCE_DIR}/src/platform/windows/utf_utils.h"
6364
"${CMAKE_SOURCE_DIR}/third-party/ViGEmClient/src/ViGEmClient.cpp"
6465
"${CMAKE_SOURCE_DIR}/third-party/ViGEmClient/include/ViGEm/Client.h"
6566
"${CMAKE_SOURCE_DIR}/third-party/ViGEmClient/include/ViGEm/Common.h"

src/platform/windows/audio.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
#include <synchapi.h>
1414

1515
// local includes
16-
#include "misc.h"
1716
#include "src/config.h"
1817
#include "src/logging.h"
1918
#include "src/platform/common.h"
19+
#include "utf_utils.h"
2020

2121
// Must be the last included file
2222
// clang-format off
@@ -695,7 +695,7 @@ namespace platf::audio {
695695
audio::wstring_t id;
696696
device->GetId(&id);
697697

698-
sink.host = to_utf8(id.get());
698+
sink.host = utf_utils::to_utf8(id.get());
699699
}
700700

701701
// Prepare to search for the device_id of the virtual audio sink device,
@@ -705,14 +705,14 @@ namespace platf::audio {
705705
if (config::audio.virtual_sink.empty()) {
706706
match_list = match_steam_speakers();
707707
} else {
708-
match_list = match_all_fields(from_utf8(config::audio.virtual_sink));
708+
match_list = match_all_fields(utf_utils::from_utf8(config::audio.virtual_sink));
709709
}
710710

711711
// Search for the virtual audio sink device currently present in the system.
712712
auto matched = find_device_id(match_list);
713713
if (matched) {
714714
// Prepare to fill virtual audio sink names with device_id.
715-
auto device_id = to_utf8(matched->second);
715+
auto device_id = utf_utils::to_utf8(matched->second);
716716
// Also prepend format name (basically channel layout at the moment)
717717
// because we don't want to extend the platform interface.
718718
sink.null = std::make_optional(sink_t::null_t {
@@ -728,7 +728,7 @@ namespace platf::audio {
728728
}
729729

730730
bool is_sink_available(const std::string &sink) override {
731-
const auto match_list = match_all_fields(from_utf8(sink));
731+
const auto match_list = match_all_fields(utf_utils::from_utf8(sink));
732732
const auto matched = find_device_id(match_list);
733733
return static_cast<bool>(matched);
734734
}
@@ -750,7 +750,7 @@ namespace platf::audio {
750750
for (const auto &format : formats) {
751751
auto &name = format.name;
752752
if (current.find(name) == 0) {
753-
auto device_id = from_utf8(current.substr(name.size(), current.size() - name.size()));
753+
auto device_id = utf_utils::from_utf8(current.substr(name.size(), current.size() - name.size()));
754754
return std::make_pair(device_id, std::reference_wrapper(format));
755755
}
756756
}
@@ -797,7 +797,7 @@ namespace platf::audio {
797797
// Sink name does not begin with virtual-(format name), hence it's not a virtual sink
798798
// and we don't want to change playback format of the corresponding device.
799799
// Also need to perform matching, sink name is not necessarily device_id in this case.
800-
auto matched = find_device_id(match_all_fields(from_utf8(sink)));
800+
auto matched = find_device_id(match_all_fields(utf_utils::from_utf8(sink)));
801801
if (matched) {
802802
return matched->second;
803803
} else {

src/platform/windows/display_base.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
#include <boost/process/v1.hpp>
1515
#include <MinHook.h>
1616

17+
// local includes
18+
#include "utf_utils.h"
19+
1720
// We have to include boost/process/v1.hpp before display.h due to WinSock.h,
1821
// but that prevents the definition of NTSTATUS so we must define it ourself.
1922
typedef long NTSTATUS;
@@ -464,8 +467,8 @@ namespace platf::dxgi {
464467
return -1;
465468
}
466469

467-
auto adapter_name = from_utf8(config::video.adapter_name);
468-
auto output_name = from_utf8(display_name);
470+
auto adapter_name = utf_utils::from_utf8(config::video.adapter_name);
471+
auto output_name = utf_utils::from_utf8(display_name);
469472

470473
adapter_t::pointer adapter_p;
471474
for (int tries = 0; tries < 2; ++tries) {
@@ -579,7 +582,7 @@ namespace platf::dxgi {
579582
DXGI_ADAPTER_DESC adapter_desc;
580583
adapter->GetDesc(&adapter_desc);
581584

582-
auto description = to_utf8(adapter_desc.Description);
585+
auto description = utf_utils::to_utf8(adapter_desc.Description);
583586
BOOST_LOG(info)
584587
<< std::endl
585588
<< "Device Description : " << description << std::endl
@@ -1051,7 +1054,7 @@ namespace platf {
10511054
BOOST_LOG(debug)
10521055
<< std::endl
10531056
<< "====== ADAPTER ====="sv << std::endl
1054-
<< "Device Name : "sv << to_utf8(adapter_desc.Description) << std::endl
1057+
<< "Device Name : "sv << utf_utils::to_utf8(adapter_desc.Description) << std::endl
10551058
<< "Device Vendor ID : 0x"sv << util::hex(adapter_desc.VendorId).to_string_view() << std::endl
10561059
<< "Device Device ID : 0x"sv << util::hex(adapter_desc.DeviceId).to_string_view() << std::endl
10571060
<< "Device Video Mem : "sv << adapter_desc.DedicatedVideoMemory / 1048576 << " MiB"sv << std::endl
@@ -1067,7 +1070,7 @@ namespace platf {
10671070
DXGI_OUTPUT_DESC desc;
10681071
output->GetDesc(&desc);
10691072

1070-
auto device_name = to_utf8(desc.DeviceName);
1073+
auto device_name = utf_utils::to_utf8(desc.DeviceName);
10711074

10721075
auto width = desc.DesktopCoordinates.right - desc.DesktopCoordinates.left;
10731076
auto height = desc.DesktopCoordinates.bottom - desc.DesktopCoordinates.top;

src/platform/windows/display_vram.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ extern "C" {
2828
#include "src/nvenc/nvenc_d3d11_on_cuda.h"
2929
#include "src/nvenc/nvenc_utils.h"
3030
#include "src/video.h"
31+
#include "utf_utils.h"
3132

3233
#if !defined(SUNSHINE_SHADERS_DIR) // for testing this needs to be defined in cmake as we don't do an install
3334
#define SUNSHINE_SHADERS_DIR SUNSHINE_ASSETS_DIR "/shaders/directx"
@@ -359,7 +360,7 @@ namespace platf::dxgi {
359360
flags |= D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
360361
#endif
361362

362-
auto wFile = from_utf8(file);
363+
auto wFile = utf_utils::from_utf8(file);
363364
auto status = D3DCompileFromFile(wFile.c_str(), nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE, entrypoint, shader_model, flags, 0, &compiled_p, &msg_p);
364365

365366
if (msg_p) {

src/platform/windows/misc.cpp

Lines changed: 14 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "src/logging.h"
4646
#include "src/platform/common.h"
4747
#include "src/utility.h"
48+
#include "utf_utils.h"
4849

4950
// UDP_SEND_MSG_SIZE was added in the Windows 10 20H1 SDK
5051
#ifndef UDP_SEND_MSG_SIZE
@@ -314,7 +315,7 @@ namespace platf {
314315
// Parse the environment block and populate env
315316
for (auto c = (PWCHAR) env_block; *c != UNICODE_NULL; c += wcslen(c) + 1) {
316317
// Environment variable entries end with a null-terminator, so std::wstring() will get an entire entry.
317-
std::string env_tuple = to_utf8(std::wstring {c});
318+
std::string env_tuple = utf_utils::to_utf8(std::wstring {c});
318319
std::string env_name = env_tuple.substr(0, env_tuple.find('='));
319320
std::string env_val = env_tuple.substr(env_tuple.find('=') + 1);
320321

@@ -384,7 +385,7 @@ namespace platf {
384385
for (const auto &entry : env) {
385386
auto name = entry.get_name();
386387
auto value = entry.to_string();
387-
size += from_utf8(name).length() + 1 /* L'=' */ + from_utf8(value).length() + 1 /* L'\0' */;
388+
size += utf_utils::from_utf8(name).length() + 1 /* L'=' */ + utf_utils::from_utf8(value).length() + 1 /* L'\0' */;
388389
}
389390

390391
size += 1 /* L'\0' */;
@@ -396,9 +397,9 @@ namespace platf {
396397
auto value = entry.to_string();
397398

398399
// Construct the NAME=VAL\0 string
399-
append_string_to_environment_block(env_block, offset, from_utf8(name));
400+
append_string_to_environment_block(env_block, offset, utf_utils::from_utf8(name));
400401
env_block[offset++] = L'=';
401-
append_string_to_environment_block(env_block, offset, from_utf8(value));
402+
append_string_to_environment_block(env_block, offset, utf_utils::from_utf8(value));
402403
env_block[offset++] = L'\0';
403404
}
404405

@@ -676,14 +677,14 @@ namespace platf {
676677
* @return A command string suitable for use by CreateProcess().
677678
*/
678679
std::wstring resolve_command_string(const std::string &raw_cmd, const std::wstring &working_dir, HANDLE token, DWORD &creation_flags) {
679-
std::wstring raw_cmd_w = from_utf8(raw_cmd);
680+
std::wstring raw_cmd_w = utf_utils::from_utf8(raw_cmd);
680681

681682
// First, convert the given command into parts so we can get the executable/file/URL without parameters
682683
auto raw_cmd_parts = boost::program_options::split_winmain(raw_cmd_w);
683684
if (raw_cmd_parts.empty()) {
684685
// This is highly unexpected, but we'll just return the raw string and hope for the best.
685686
BOOST_LOG(warning) << "Failed to split command string: "sv << raw_cmd;
686-
return from_utf8(raw_cmd);
687+
return utf_utils::from_utf8(raw_cmd);
687688
}
688689

689690
auto raw_target = raw_cmd_parts.at(0);
@@ -697,7 +698,7 @@ namespace platf {
697698
res = UrlGetPartW(raw_target.c_str(), scheme.data(), &out_len, URL_PART_SCHEME, 0);
698699
if (res != S_OK) {
699700
BOOST_LOG(warning) << "Failed to extract URL scheme from URL: "sv << raw_target << " ["sv << util::hex(res).to_string_view() << ']';
700-
return from_utf8(raw_cmd);
701+
return utf_utils::from_utf8(raw_cmd);
701702
}
702703

703704
// If the target is a URL, the class is found using the URL scheme (prior to and not including the ':')
@@ -708,13 +709,13 @@ namespace platf {
708709
if (extension == nullptr || *extension == 0) {
709710
// If the file has no extension, assume it's a command and allow CreateProcess()
710711
// to try to find it via PATH
711-
return from_utf8(raw_cmd);
712+
return utf_utils::from_utf8(raw_cmd);
712713
} else if (boost::iequals(extension, L".exe")) {
713714
// If the file has an .exe extension, we will bypass the resolution here and
714715
// directly pass the unmodified command string to CreateProcess(). The argument
715716
// escaping rules are subtly different between CreateProcess() and ShellExecute(),
716717
// and we want to preserve backwards compatibility with older configs.
717-
return from_utf8(raw_cmd);
718+
return utf_utils::from_utf8(raw_cmd);
718719
}
719720

720721
// For regular files, the class is found using the file extension (including the dot)
@@ -731,7 +732,7 @@ namespace platf {
731732

732733
// Override HKEY_CLASSES_ROOT and HKEY_CURRENT_USER to ensure we query the correct class info
733734
if (!override_per_user_predefined_keys(token)) {
734-
return from_utf8(raw_cmd);
735+
return utf_utils::from_utf8(raw_cmd);
735736
}
736737

737738
// Find the command string for the specified class
@@ -762,7 +763,7 @@ namespace platf {
762763

763764
if (res != S_OK) {
764765
BOOST_LOG(warning) << "Failed to query command string for raw command: "sv << raw_cmd << " ["sv << util::hex(res).to_string_view() << ']';
765-
return from_utf8(raw_cmd);
766+
return utf_utils::from_utf8(raw_cmd);
766767
}
767768

768769
// Finally, construct the real command string that will be passed into CreateProcess().
@@ -896,7 +897,7 @@ namespace platf {
896897
* @return A `bp::child` object representing the new process, or an empty `bp::child` object if the launch fails.
897898
*/
898899
bp::child run_command(bool elevated, bool interactive, const std::string &cmd, boost::filesystem::path &working_dir, const bp::environment &env, FILE *file, std::error_code &ec, bp::group *group) {
899-
std::wstring start_dir = from_utf8(working_dir.string());
900+
std::wstring start_dir = utf_utils::from_utf8(working_dir.string());
900901
HANDLE job = group ? group->native_handle() : nullptr;
901902
STARTUPINFOEXW startup_info = create_startup_info(file, job ? &job : nullptr, ec);
902903
PROCESS_INFORMATION process_info;
@@ -1687,65 +1688,13 @@ namespace platf {
16871688
return {};
16881689
}
16891690

1690-
std::wstring from_utf8(const std::string &string) {
1691-
// No conversion needed if the string is empty
1692-
if (string.empty()) {
1693-
return {};
1694-
}
1695-
1696-
// Get the output size required to store the string
1697-
auto output_size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, string.data(), string.size(), nullptr, 0);
1698-
if (output_size == 0) {
1699-
auto winerr = GetLastError();
1700-
BOOST_LOG(error) << "Failed to get UTF-16 buffer size: "sv << winerr;
1701-
return {};
1702-
}
1703-
1704-
// Perform the conversion
1705-
std::wstring output(output_size, L'\0');
1706-
output_size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, string.data(), string.size(), output.data(), output.size());
1707-
if (output_size == 0) {
1708-
auto winerr = GetLastError();
1709-
BOOST_LOG(error) << "Failed to convert string to UTF-16: "sv << winerr;
1710-
return {};
1711-
}
1712-
1713-
return output;
1714-
}
1715-
1716-
std::string to_utf8(const std::wstring &string) {
1717-
// No conversion needed if the string is empty
1718-
if (string.empty()) {
1719-
return {};
1720-
}
1721-
1722-
// Get the output size required to store the string
1723-
auto output_size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, string.data(), string.size(), nullptr, 0, nullptr, nullptr);
1724-
if (output_size == 0) {
1725-
auto winerr = GetLastError();
1726-
BOOST_LOG(error) << "Failed to get UTF-8 buffer size: "sv << winerr;
1727-
return {};
1728-
}
1729-
1730-
// Perform the conversion
1731-
std::string output(output_size, '\0');
1732-
output_size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, string.data(), string.size(), output.data(), output.size(), nullptr, nullptr);
1733-
if (output_size == 0) {
1734-
auto winerr = GetLastError();
1735-
BOOST_LOG(error) << "Failed to convert string to UTF-8: "sv << winerr;
1736-
return {};
1737-
}
1738-
1739-
return output;
1740-
}
1741-
17421691
std::string get_host_name() {
17431692
WCHAR hostname[256];
17441693
if (GetHostNameW(hostname, ARRAYSIZE(hostname)) == SOCKET_ERROR) {
17451694
BOOST_LOG(error) << "GetHostNameW() failed: "sv << WSAGetLastError();
17461695
return "Sunshine"s;
17471696
}
1748-
return to_utf8(hostname);
1697+
return utf_utils::to_utf8(hostname);
17491698
}
17501699

17511700
class win32_high_precision_timer: public high_precision_timer {

src/platform/windows/misc.h

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,4 @@ namespace platf {
1919
int64_t qpc_counter();
2020

2121
std::chrono::nanoseconds qpc_time_difference(int64_t performance_counter1, int64_t performance_counter2);
22-
23-
/**
24-
* @brief Convert a UTF-8 string into a UTF-16 wide string.
25-
* @param string The UTF-8 string.
26-
* @return The converted UTF-16 wide string.
27-
*/
28-
std::wstring from_utf8(const std::string &string);
29-
30-
/**
31-
* @brief Convert a UTF-16 wide string into a UTF-8 string.
32-
* @param string The UTF-16 wide string.
33-
* @return The converted UTF-8 string.
34-
*/
35-
std::string to_utf8(const std::wstring &string);
3622
} // namespace platf

src/platform/windows/publish.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "src/nvhttp.h"
2020
#include "src/platform/common.h"
2121
#include "src/thread_safe.h"
22+
#include "utf_utils.h"
2223

2324
#define _FN(x, ret, args) \
2425
typedef ret(*x##_fn) args; \
@@ -109,8 +110,8 @@ namespace platf::publish {
109110
std::wstring domain {SERVICE_TYPE_DOMAIN.data(), SERVICE_TYPE_DOMAIN.size()};
110111

111112
auto hostname = platf::get_host_name();
112-
auto name = from_utf8(net::mdns_instance_name(hostname) + '.') + domain;
113-
auto host = from_utf8(hostname + ".local");
113+
auto name = utf_utils::from_utf8(net::mdns_instance_name(hostname) + '.') + domain;
114+
auto host = utf_utils::from_utf8(hostname + ".local");
114115

115116
DNS_SERVICE_INSTANCE instance {};
116117
instance.pszInstanceName = name.data();

0 commit comments

Comments
 (0)