cmWindowsRegistry: enhance unicode conversions

This commit is contained in:
Marc Chevrier
2022-04-14 11:58:25 +02:00
parent 253492a6f7
commit 769f25aa3c
2 changed files with 79 additions and 14 deletions

View File

@@ -734,7 +734,7 @@ set(SRCS
bindexplib.cxx bindexplib.cxx
) )
SET_PROPERTY(SOURCE cmProcessOutput.cxx APPEND PROPERTY COMPILE_DEFINITIONS SET_PROPERTY(SOURCE cmProcessOutput.cxx cmWindowsRegistry.cxx APPEND PROPERTY COMPILE_DEFINITIONS
KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE}) KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE})
# Xcode only works on Apple # Xcode only works on Apple

View File

@@ -75,6 +75,8 @@ public:
private: private:
static std::string FormatSystemError(LSTATUS status); static std::string FormatSystemError(LSTATUS status);
static std::wstring ToWide(cm::string_view str);
static std::string ToNarrow(const wchar_t* str, int size = -1);
HKEY Handler; HKEY Handler;
}; };
@@ -104,7 +106,7 @@ KeyHandler KeyHandler::OpenKey(cm::string_view key, View view)
} }
std::wstring subKey; std::wstring subKey;
if (start != cm::string_view::npos) { if (start != cm::string_view::npos) {
subKey = cmsys::Encoding::ToWide(key.substr(start + 1).data()); subKey = ToWide(key.substr(start + 1));
} }
// Update path format // Update path format
std::replace(subKey.begin(), subKey.end(), L'/', L'\\'); std::replace(subKey.begin(), subKey.end(), L'/', L'\\');
@@ -125,21 +127,84 @@ KeyHandler KeyHandler::OpenKey(cm::string_view key, View view)
std::string KeyHandler::FormatSystemError(LSTATUS status) std::string KeyHandler::FormatSystemError(LSTATUS status)
{ {
std::string formattedMessage; std::string formattedMessage{ "Windows Registry: unexpected error." };
LPWSTR message = nullptr; LPWSTR message = nullptr;
DWORD size = 1024; DWORD size = 1024;
if (FormatMessageW( if (FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, nullptr, FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, nullptr,
status, 0, reinterpret_cast<LPWSTR>(&message), size, nullptr) == 0) { status, 0, reinterpret_cast<LPWSTR>(&message), size, nullptr) != 0) {
formattedMessage = "Windows Registry: unexpected error."; try {
} else { formattedMessage = cmTrimWhitespace(ToNarrow(message));
formattedMessage = cmTrimWhitespace(cmsys::Encoding::ToNarrow(message)); } catch (...) {
// ignore any exception because this method can be called
// as part of the raise of an exception
}
} }
LocalFree(message); LocalFree(message);
return formattedMessage; return formattedMessage;
} }
std::wstring KeyHandler::ToWide(cm::string_view str)
{
std::wstring wstr;
if (str.empty()) {
return wstr;
}
const auto wlength =
MultiByteToWideChar(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.data(),
int(str.size()), nullptr, 0);
if (wlength > 0) {
auto wdata = cm::make_unique<wchar_t[]>(wlength);
const auto r =
MultiByteToWideChar(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.data(),
int(str.size()), wdata.get(), wlength);
if (r > 0) {
wstr = std::wstring(wdata.get(), wlength);
} else {
throw registry_error(FormatSystemError(GetLastError()));
}
} else {
throw registry_error(FormatSystemError(GetLastError()));
}
return wstr;
}
std::string KeyHandler::ToNarrow(const wchar_t* wstr, int size)
{
std::string str;
if (size == 0 || (size == -1 && wstr[0] == L'\0')) {
return str;
}
const auto length =
WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, wstr, size,
nullptr, 0, nullptr, nullptr);
if (length > 0) {
auto data = cm::make_unique<char[]>(length);
const auto r =
WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, wstr, size,
data.get(), length, nullptr, nullptr);
if (r > 0) {
if (size == -1) {
str = std::string(data.get());
} else {
str = std::string(data.get(), length);
}
} else {
throw registry_error(FormatSystemError(GetLastError()));
}
} else {
throw registry_error(FormatSystemError(GetLastError()));
}
return str;
}
std::string KeyHandler::ReadValue(cm::string_view name, std::string KeyHandler::ReadValue(cm::string_view name,
cm::string_view separator) cm::string_view separator)
{ {
@@ -153,14 +218,14 @@ std::string KeyHandler::ReadValue(cm::string_view name,
} }
auto data = cm::make_unique<BYTE[]>(size); auto data = cm::make_unique<BYTE[]>(size);
DWORD type; DWORD type;
auto valueName = cmsys::Encoding::ToWide(name.data()); auto valueName = this->ToWide(name);
if ((status = RegQueryValueExW(this->Handler, valueName.c_str(), nullptr, if ((status = RegQueryValueExW(this->Handler, valueName.c_str(), nullptr,
&type, data.get(), &size)) != ERROR_SUCCESS) { &type, data.get(), &size)) != ERROR_SUCCESS) {
throw registry_error(this->FormatSystemError(status)); throw registry_error(this->FormatSystemError(status));
} }
switch (type) { switch (type) {
case REG_SZ: case REG_SZ:
return cmsys::Encoding::ToNarrow(reinterpret_cast<wchar_t*>(data.get())); return this->ToNarrow(reinterpret_cast<wchar_t*>(data.get()));
break; break;
case REG_EXPAND_SZ: { case REG_EXPAND_SZ: {
auto expandSize = ExpandEnvironmentStringsW( auto expandSize = ExpandEnvironmentStringsW(
@@ -170,7 +235,7 @@ std::string KeyHandler::ReadValue(cm::string_view name,
expandData.get(), expandSize + 1) == 0) { expandData.get(), expandSize + 1) == 0) {
throw registry_error(this->FormatSystemError(GetLastError())); throw registry_error(this->FormatSystemError(GetLastError()));
} else { } else {
return cmsys::Encoding::ToNarrow(expandData.get()); return this->ToNarrow(expandData.get());
} }
} break; } break;
case REG_DWORD: case REG_DWORD:
@@ -181,12 +246,12 @@ std::string KeyHandler::ReadValue(cm::string_view name,
break; break;
case REG_MULTI_SZ: { case REG_MULTI_SZ: {
// replace separator with semicolon // replace separator with semicolon
auto sep = cmsys::Encoding::ToWide(separator.data())[0]; auto sep = this->ToWide(separator)[0];
std::replace(reinterpret_cast<wchar_t*>(data.get()), std::replace(reinterpret_cast<wchar_t*>(data.get()),
reinterpret_cast<wchar_t*>(data.get()) + reinterpret_cast<wchar_t*>(data.get()) +
(size / sizeof(wchar_t)) - 1, (size / sizeof(wchar_t)) - 1,
sep, L';'); sep, L';');
return cmsys::Encoding::ToNarrow(reinterpret_cast<wchar_t*>(data.get())); return this->ToNarrow(reinterpret_cast<wchar_t*>(data.get()));
} break; } break;
default: default:
throw registry_error(cmStrCat(type, ": unsupported type.")); throw registry_error(cmStrCat(type, ": unsupported type."));
@@ -213,7 +278,7 @@ std::vector<std::string> KeyHandler::GetValueNames()
while ((status = RegEnumValueW(this->Handler, index, data.get(), &size, while ((status = RegEnumValueW(this->Handler, index, data.get(), &size,
nullptr, nullptr, nullptr, nullptr)) == nullptr, nullptr, nullptr, nullptr)) ==
ERROR_SUCCESS) { ERROR_SUCCESS) {
auto name = cmsys::Encoding::ToNarrow(data.get()); auto name = this->ToNarrow(data.get());
valueNames.push_back(name.empty() ? "(default)" : name); valueNames.push_back(name.empty() ? "(default)" : name);
size = maxSize; size = maxSize;
++index; ++index;
@@ -243,7 +308,7 @@ std::vector<std::string> KeyHandler::GetSubKeys()
while ((status = RegEnumKeyW(this->Handler, index, data.get(), size)) == while ((status = RegEnumKeyW(this->Handler, index, data.get(), size)) ==
ERROR_SUCCESS) { ERROR_SUCCESS) {
subKeys.push_back(cmsys::Encoding::ToNarrow(data.get())); subKeys.push_back(this->ToNarrow(data.get()));
++index; ++index;
} }
if (status != ERROR_NO_MORE_ITEMS) { if (status != ERROR_NO_MORE_ITEMS) {