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,15 +315,15 @@ 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
321322 // Perform a case-insensitive search to see if this variable name already exists
322- auto itr = std::find_if (env.cbegin (), env.cend (), [&](const auto &e) {
323- return boost::iequals (e.get_name (), env_name);
324- });
325- if ( itr != env.cend ()) {
323+ if ( auto itr = std::find_if (env.begin (), env.end (), [&](const auto &e) {
324+ return boost::iequals (e.get_name (), env_name);
325+ });
326+ itr != env.end ()) {
326327 // Use this existing name if it is already present to ensure we merge properly
327328 env_name = itr->get_name ();
328329 }
@@ -379,33 +380,36 @@ namespace platf {
379380 offset += wstr.length ();
380381 }
381382
382- std::wstring create_environment_block (bp::environment &env) {
383+ std::wstring create_environment_block (const bp::environment &env) {
383384 int size = 0 ;
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' */ ;
391392
392- wchar_t env_block[ size] ;
393+ std::vector< wchar_t > env_block ( size) ;
393394 int offset = 0 ;
394395 for (const auto &entry : env) {
395396 auto name = entry.get_name ();
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- env_block[offset++] = L' =' ;
401- append_string_to_environment_block (env_block, offset, from_utf8 (value));
402- env_block[offset++] = L' \0 ' ;
400+ append_string_to_environment_block (env_block.data (), offset, utf_utils::from_utf8 (name));
401+ env_block[offset] = L' =' ;
402+ offset++;
403+ append_string_to_environment_block (env_block.data (), offset, utf_utils::from_utf8 (value));
404+ env_block[offset] = L' \0 ' ;
405+ offset++;
403406 }
404407
405408 // Append a final null terminator
406- env_block[offset++] = L' \0 ' ;
409+ env_block[offset] = L' \0 ' ;
410+ offset++;
407411
408- return std::wstring (env_block, offset);
412+ return std::wstring (env_block. data () , offset);
409413 }
410414
411415 LPPROC_THREAD_ATTRIBUTE_LIST allocate_proc_thread_attr_list (DWORD attribute_count) {
@@ -676,14 +680,14 @@ namespace platf {
676680 * @return A command string suitable for use by CreateProcess().
677681 */
678682 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);
683+ std::wstring raw_cmd_w = utf_utils:: from_utf8 (raw_cmd);
680684
681685 // First, convert the given command into parts so we can get the executable/file/URL without parameters
682686 auto raw_cmd_parts = boost::program_options::split_winmain (raw_cmd_w);
683687 if (raw_cmd_parts.empty ()) {
684688 // This is highly unexpected, but we'll just return the raw string and hope for the best.
685689 BOOST_LOG (warning) << " Failed to split command string: " sv << raw_cmd;
686- return from_utf8 (raw_cmd);
690+ return utf_utils:: from_utf8 (raw_cmd);
687691 }
688692
689693 auto raw_target = raw_cmd_parts.at (0 );
@@ -697,7 +701,7 @@ namespace platf {
697701 res = UrlGetPartW (raw_target.c_str (), scheme.data (), &out_len, URL_PART_SCHEME, 0 );
698702 if (res != S_OK) {
699703 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);
704+ return utf_utils:: from_utf8 (raw_cmd);
701705 }
702706
703707 // If the target is a URL, the class is found using the URL scheme (prior to and not including the ':')
@@ -708,13 +712,13 @@ namespace platf {
708712 if (extension == nullptr || *extension == 0 ) {
709713 // If the file has no extension, assume it's a command and allow CreateProcess()
710714 // to try to find it via PATH
711- return from_utf8 (raw_cmd);
715+ return utf_utils:: from_utf8 (raw_cmd);
712716 } else if (boost::iequals (extension, L" .exe" )) {
713717 // If the file has an .exe extension, we will bypass the resolution here and
714718 // directly pass the unmodified command string to CreateProcess(). The argument
715719 // escaping rules are subtly different between CreateProcess() and ShellExecute(),
716720 // and we want to preserve backwards compatibility with older configs.
717- return from_utf8 (raw_cmd);
721+ return utf_utils:: from_utf8 (raw_cmd);
718722 }
719723
720724 // For regular files, the class is found using the file extension (including the dot)
@@ -731,7 +735,7 @@ namespace platf {
731735
732736 // Override HKEY_CLASSES_ROOT and HKEY_CURRENT_USER to ensure we query the correct class info
733737 if (!override_per_user_predefined_keys (token)) {
734- return from_utf8 (raw_cmd);
738+ return utf_utils:: from_utf8 (raw_cmd);
735739 }
736740
737741 // Find the command string for the specified class
@@ -762,7 +766,7 @@ namespace platf {
762766
763767 if (res != S_OK) {
764768 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);
769+ return utf_utils:: from_utf8 (raw_cmd);
766770 }
767771
768772 // Finally, construct the real command string that will be passed into CreateProcess().
@@ -896,7 +900,7 @@ namespace platf {
896900 * @return A `bp::child` object representing the new process, or an empty `bp::child` object if the launch fails.
897901 */
898902 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 ());
903+ std::wstring start_dir = utf_utils:: from_utf8 (working_dir.string ());
900904 HANDLE job = group ? group->native_handle () : nullptr ;
901905 STARTUPINFOEXW startup_info = create_startup_info (file, job ? &job : nullptr , ec);
902906 PROCESS_INFORMATION process_info;
@@ -1690,65 +1694,13 @@ namespace platf {
16901694 return {};
16911695 }
16921696
1693- std::wstring from_utf8 (const std::string &string) {
1694- // No conversion needed if the string is empty
1695- if (string.empty ()) {
1696- return {};
1697- }
1698-
1699- // Get the output size required to store the string
1700- auto output_size = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, string.data (), string.size (), nullptr , 0 );
1701- if (output_size == 0 ) {
1702- auto winerr = GetLastError ();
1703- BOOST_LOG (error) << " Failed to get UTF-16 buffer size: " sv << winerr;
1704- return {};
1705- }
1706-
1707- // Perform the conversion
1708- std::wstring output (output_size, L' \0 ' );
1709- output_size = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, string.data (), string.size (), output.data (), output.size ());
1710- if (output_size == 0 ) {
1711- auto winerr = GetLastError ();
1712- BOOST_LOG (error) << " Failed to convert string to UTF-16: " sv << winerr;
1713- return {};
1714- }
1715-
1716- return output;
1717- }
1718-
1719- std::string to_utf8 (const std::wstring &string) {
1720- // No conversion needed if the string is empty
1721- if (string.empty ()) {
1722- return {};
1723- }
1724-
1725- // Get the output size required to store the string
1726- auto output_size = WideCharToMultiByte (CP_UTF8, WC_ERR_INVALID_CHARS, string.data (), string.size (), nullptr , 0 , nullptr , nullptr );
1727- if (output_size == 0 ) {
1728- auto winerr = GetLastError ();
1729- BOOST_LOG (error) << " Failed to get UTF-8 buffer size: " sv << winerr;
1730- return {};
1731- }
1732-
1733- // Perform the conversion
1734- std::string output (output_size, ' \0 ' );
1735- output_size = WideCharToMultiByte (CP_UTF8, WC_ERR_INVALID_CHARS, string.data (), string.size (), output.data (), output.size (), nullptr , nullptr );
1736- if (output_size == 0 ) {
1737- auto winerr = GetLastError ();
1738- BOOST_LOG (error) << " Failed to convert string to UTF-8: " sv << winerr;
1739- return {};
1740- }
1741-
1742- return output;
1743- }
1744-
17451697 std::string get_host_name () {
17461698 WCHAR hostname[256 ];
17471699 if (GetHostNameW (hostname, ARRAYSIZE (hostname)) == SOCKET_ERROR) {
17481700 BOOST_LOG (error) << " GetHostNameW() failed: " sv << WSAGetLastError ();
17491701 return " Sunshine" s;
17501702 }
1751- return to_utf8 (hostname);
1703+ return utf_utils:: to_utf8 (hostname);
17521704 }
17531705
17541706 class win32_high_precision_timer : public high_precision_timer {
0 commit comments