Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor win encoding conversion #2939

Merged
merged 3 commits into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 0 additions & 9 deletions libmamba/include/mamba/core/util_os.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,6 @@ namespace mamba
void init_console();
void reset_console();

#ifdef _WIN32
std::string to_utf8(const wchar_t* windows_unicode_text, size_t size);
std::string to_utf8(const wchar_t* windows_unicode_text);
std::string to_utf8(const std::wstring& windows_unicode_text);
std::wstring to_windows_unicode(const std::string_view utf8_text);
#endif

/* Test whether a given `std::ostream` object refers to a terminal. */
bool is_atty(const std::ostream& stream);

Expand All @@ -65,8 +58,6 @@ namespace mamba
int get_console_height();

void codesign(const fs::u8path& path, bool verbose = false);

std::string fix_win_path(const std::string& path);
}

#endif
10 changes: 8 additions & 2 deletions libmamba/include/mamba/util/os_win.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
#ifndef MAMBA_UTIL_OS_WIN_HPP
#define MAMBA_UTIL_OS_WIN_HPP

#include "mamba/fs/filesystem.hpp"
#include <string>
#include <string_view>

#include "mamba/fs/filesystem.hpp"

namespace mamba::util
{
Expand All @@ -22,6 +24,10 @@ namespace mamba::util
RoamingAppData,
};

auto get_windows_known_user_folder(WindowsKnowUserFolder dir) -> fs::u8path;
[[nodiscard]] auto get_windows_known_user_folder(WindowsKnowUserFolder dir) -> fs::u8path;

[[nodiscard]] auto utf8_to_windows_encoding(const std::string_view utf8_text) -> std::wstring;

[[nodiscard]] auto windows_encoding_to_utf8(std::wstring_view) -> std::string;
}
#endif
8 changes: 4 additions & 4 deletions libmamba/src/core/environment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ namespace mamba::env
);
};

const std::wstring unicode_key = to_windows_unicode(key);
const std::wstring unicode_key = util::utf8_to_windows_encoding(key);
size_t required_size = 0;
if (auto error_code = _wgetenv_s(&required_size, nullptr, 0, unicode_key.c_str());
error_code == 0)
Expand All @@ -68,7 +68,7 @@ namespace mamba::env
{
value.pop_back(); // Remove the `\0` that was written in, otherwise any future
// concatenation will fail.
return mamba::to_utf8(value);
return util::windows_encoding_to_utf8(value);
}
else
{
Expand Down Expand Up @@ -99,8 +99,8 @@ namespace mamba::env
// functions are not thread-safe, this
// is to prevent related issues.

const std::wstring unicode_key = to_windows_unicode(key);
const std::wstring unicode_value = to_windows_unicode(value);
const std::wstring unicode_key = util::utf8_to_windows_encoding(key);
const std::wstring unicode_value = util::utf8_to_windows_encoding(value);
auto res = _wputenv_s(unicode_key.c_str(), unicode_value.c_str());
if (res != 0)
{
Expand Down
10 changes: 6 additions & 4 deletions libmamba/src/core/shell_init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#include <reproc++/run.hpp>
#ifdef _WIN32
#include <WinReg.hpp>

#include "mamba/util/os_win.hpp"
#endif

#include "mamba/core/activation.hpp"
Expand All @@ -33,14 +35,14 @@ namespace mamba
{
namespace
{
static std::regex const MAMBA_INITIALIZE_RE_BLOCK("\n?# >>> mamba initialize >>>(?:\n|\r\n)?"
static const std::regex MAMBA_INITIALIZE_RE_BLOCK("\n?# >>> mamba initialize >>>(?:\n|\r\n)?"
"([\\s\\S]*?)"
"# <<< mamba initialize <<<(?:\n|\r\n)?");

static std::regex const MAMBA_INITIALIZE_PS_RE_BLOCK("\n?#region mamba initialize(?:\n|\r\n)?"
static const std::regex MAMBA_INITIALIZE_PS_RE_BLOCK("\n?#region mamba initialize(?:\n|\r\n)?"
"([\\s\\S]*?)"
"#endregion(?:\n|\r\n)?");
static std::wregex const
static const std::wregex
MAMBA_CMDEXE_HOOK_REGEX(L"(\"[^\"]*?mamba[-_]hook\\.bat\")", std::regex_constants::icase);

}
Expand Down Expand Up @@ -126,7 +128,7 @@ namespace mamba
fmt::print(
out,
"Setting cmd.exe AUTORUN to: {}",
fmt::styled(to_utf8(value), graphics.palette.success)
fmt::styled(util::windows_encoding_to_utf8(value), graphics.palette.success)
);

winreg::RegKey key{ HKEY_CURRENT_USER, reg_path };
Expand Down
110 changes: 0 additions & 110 deletions libmamba/src/core/util_os.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -486,97 +486,6 @@ namespace mamba
#endif
}

#ifdef _WIN32
std::string to_utf8(const wchar_t* w, size_t s)
{
std::string output;
if (s != 0)
{
assert(s <= INT_MAX);
const int size = WideCharToMultiByte(
CP_UTF8,
0,
w,
static_cast<int>(s),
nullptr,
0,
nullptr,
nullptr
);
if (size <= 0)
{
unsigned long last_error = ::GetLastError();
LOG_ERROR << "Failed to convert string to UTF-8 "
<< std::system_category().message(static_cast<int>(last_error));
throw std::runtime_error("Failed to convert string to UTF-8");
}

output.resize(size);
int res_size = WideCharToMultiByte(
CP_UTF8,
0,
w,
static_cast<int>(s),
output.data(),
static_cast<int>(size),
nullptr,
nullptr
);
assert(res_size == size);
}

return output;
}

std::string to_utf8(const wchar_t* w)
{
return to_utf8(w, wcslen(w));
}

std::string to_utf8(const std::wstring& s)
{
return to_utf8(s.data(), s.size());
}

std::wstring to_windows_unicode(const std::string_view utf8_text)
{
std::wstring output;
if (!utf8_text.empty())
{
assert(utf8_text.size() <= INT_MAX);
const int size = MultiByteToWideChar(
CP_UTF8,
0,
utf8_text.data(),
utf8_text.size(),
nullptr,
0
);
if (size <= 0)
{
unsigned long last_error = ::GetLastError();
LOG_ERROR << "Failed to convert UTF-8 string to Windows Unicode (UTF-16)"
<< std::system_category().message(static_cast<int>(last_error));
throw std::runtime_error("Failed to convert UTF-8 string to UTF-16");
}

output.resize(size);
int res_size = MultiByteToWideChar(
CP_UTF8,
0,
utf8_text.data(),
utf8_text.size(),
output.data(),
output.size()
);
assert(res_size == size);
}

return output;
}

#endif

/* From https://github.com/ikalnytskyi/termcolor
*
* copyright: (c) 2013 by Ihor Kalnytskyi.
Expand Down Expand Up @@ -687,23 +596,4 @@ namespace mamba
throw std::runtime_error(std::string("Could not codesign executable: ") + ec.message());
}
}

std::string fix_win_path(const std::string& path)
{
#ifdef _WIN32
if (util::starts_with(path, "file:"))
{
std::regex re(R"(\\(?! ))");
std::string res = std::regex_replace(path, re, R"(/)");
util::replace_all(res, ":////", "://");
return res;
}
else
{
return path;
}
#else
return path;
#endif
}
}
102 changes: 94 additions & 8 deletions libmamba/src/util/os_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@

#ifdef _WIN32

#include <cassert>
#include <limits>
#include <stdexcept>

#include <fmt/format.h>
#include <Shlobj.h>

#include "mamba/util/os_win.hpp"
Expand All @@ -22,17 +25,17 @@ namespace mamba::util
switch (dir)
{
case (WindowsKnowUserFolder::Documents):
return FOLDERID_Documents;
return ::FOLDERID_Documents;
case (WindowsKnowUserFolder::Profile):
return FOLDERID_Profile;
return ::FOLDERID_Profile;
case (WindowsKnowUserFolder::Programs):
return FOLDERID_Programs;
return ::FOLDERID_Programs;
case (WindowsKnowUserFolder::ProgramData):
return FOLDERID_ProgramData;
return ::FOLDERID_ProgramData;
case (WindowsKnowUserFolder::LocalAppData):
return FOLDERID_LocalAppData;
return ::FOLDERID_LocalAppData;
case (WindowsKnowUserFolder::RoamingAppData):
return FOLDERID_RoamingAppData;
return ::FOLDERID_RoamingAppData;
}
throw std::invalid_argument("Invalid enum");
}
Expand All @@ -41,7 +44,7 @@ namespace mamba::util
{
~COMwstr()
{
CoTaskMemFree(str);
::CoTaskMemFree(str);
}

wchar_t* str = nullptr;
Expand All @@ -52,7 +55,7 @@ namespace mamba::util
{
auto localAppData = COMwstr{ nullptr };

HRESULT const hres = SHGetKnownFolderPath(
const auto hres = SHGetKnownFolderPath(
get_windows_known_user_folder_raw(dir),
KF_FLAG_DONT_VERIFY,
nullptr,
Expand All @@ -66,6 +69,79 @@ namespace mamba::util

return fs::u8path(localAppData.str);
}

auto utf8_to_windows_encoding(const std::string_view utf8_text) -> std::wstring
{
if (utf8_text.empty())
{
return {};
}

assert(utf8_text.size() <= std::numeric_limits<int>::max());
const int size = ::MultiByteToWideChar(CP_UTF8, 0, utf8_text.data(), utf8_text.size(), nullptr, 0);
if (size <= 0)
{
throw std::runtime_error(fmt::format(
R"(Failed to convert UTF-8 string "{}" to UTF-16: {})",
utf8_text,
std::system_category().message(static_cast<int>(::GetLastError()))
));
}

auto output = std::wstring(static_cast<std::size_t>(size), char(0));
[[maybe_unused]] const int res_size = ::MultiByteToWideChar(
CP_UTF8,
0,
utf8_text.data(),
utf8_text.size(),
output.data(),
output.size()
);
assert(res_size == size);
return output;
}

auto windows_encoding_to_utf8(std::wstring_view str) -> std::string
{
if (str.empty())
{
return {};
}

assert(str.size() <= std::numeric_limits<int>::max());
const int size = ::WideCharToMultiByte(
CP_UTF8,
0,
str.data(),
static_cast<int>(str.size()),
nullptr,
0,
nullptr,
nullptr
);
if (size <= 0)
{
throw std::runtime_error(fmt::format(
R"(Failed to convert UTF-16 string to UTF-8: {})",
std::system_category().message(static_cast<int>(::GetLastError()))
));
}

auto output = std::string(static_cast<std::size_t>(size), char(0));
[[maybe_unused]] const int res_size = ::WideCharToMultiByte(
CP_UTF8,
0,
str.data(),
static_cast<int>(str.size()),
output.data(),
static_cast<int>(size),
nullptr,
nullptr
);
assert(res_size == size);

return output;
}
}

#else // #ifdef _WIN32
Expand All @@ -91,6 +167,16 @@ namespace mamba::util
{
throw_not_implemented("get_windows_known_user_folder");
}

auto utf8_to_windows_encoding(const std::string_view) -> std::wstring
{
throw_not_implemented("utf8_to_windows_unicode");
}

auto windows_encoding_to_utf8(std::wstring_view) -> std::string
{
throw_not_implemented("windows_encoding_to_utf8");
}
}

#endif // #ifdef _WIN32
Loading