aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorrbrunner7 <rbrunner@dreamshare.ch>2018-02-22 19:52:55 +0100
committerrbrunner7 <rbrunner@dreamshare.ch>2018-02-25 12:57:58 +0100
commit430268224d71bfc6a359f20c6db712462ce0bb25 (patch)
treef095671ade4fa74e93fac65a442cb7c4c587f812 /src
parentMerge pull request #3245 (diff)
downloadmonero-430268224d71bfc6a359f20c6db712462ce0bb25.tar.xz
Wallet2 + CLI wallet: UTF-8 support for filenames and paths under Windows
Diffstat (limited to 'src')
-rw-r--r--src/common/util.cpp23
-rw-r--r--src/simplewallet/CMakeLists.txt1
-rw-r--r--src/simplewallet/simplewallet.cpp36
-rw-r--r--src/wallet/api/wallet.cpp10
-rw-r--r--src/wallet/wallet2.cpp12
5 files changed, 74 insertions, 8 deletions
diff --git a/src/common/util.cpp b/src/common/util.cpp
index e0f3cd655..d01da0fb7 100644
--- a/src/common/util.cpp
+++ b/src/common/util.cpp
@@ -435,15 +435,17 @@ std::string get_nix_version_display_string()
#ifdef WIN32
std::string get_special_folder_path(int nfolder, bool iscreate)
{
- namespace fs = boost::filesystem;
- char psz_path[MAX_PATH] = "";
+ WCHAR psz_path[MAX_PATH] = L"";
- if(SHGetSpecialFolderPathA(NULL, psz_path, nfolder, iscreate))
+ if (SHGetSpecialFolderPathW(NULL, psz_path, nfolder, iscreate))
{
- return psz_path;
+ int size_needed = WideCharToMultiByte(CP_UTF8, 0, psz_path, wcslen(psz_path), NULL, 0, NULL, NULL);
+ std::string folder_name(size_needed, 0);
+ WideCharToMultiByte(CP_UTF8, 0, psz_path, wcslen(psz_path), &folder_name[0], size_needed, NULL, NULL);
+ return folder_name;
}
- LOG_ERROR("SHGetSpecialFolderPathA() failed, could not obtain requested path.");
+ LOG_ERROR("SHGetSpecialFolderPathW() failed, could not obtain requested path.");
return "";
}
#endif
@@ -501,13 +503,18 @@ std::string get_nix_version_display_string()
int code;
#if defined(WIN32)
// Maximizing chances for success
- DWORD attributes = ::GetFileAttributes(replaced_name.c_str());
+ WCHAR wide_replacement_name[1000];
+ MultiByteToWideChar(CP_UTF8, 0, replacement_name.c_str(), replacement_name.size() + 1, wide_replacement_name, 1000);
+ WCHAR wide_replaced_name[1000];
+ MultiByteToWideChar(CP_UTF8, 0, replaced_name.c_str(), replaced_name.size() + 1, wide_replaced_name, 1000);
+
+ DWORD attributes = ::GetFileAttributesW(wide_replaced_name);
if (INVALID_FILE_ATTRIBUTES != attributes)
{
- ::SetFileAttributes(replaced_name.c_str(), attributes & (~FILE_ATTRIBUTE_READONLY));
+ ::SetFileAttributesW(wide_replaced_name, attributes & (~FILE_ATTRIBUTE_READONLY));
}
- bool ok = 0 != ::MoveFileEx(replacement_name.c_str(), replaced_name.c_str(), MOVEFILE_REPLACE_EXISTING);
+ bool ok = 0 != ::MoveFileExW(wide_replacement_name, wide_replaced_name, MOVEFILE_REPLACE_EXISTING);
code = ok ? 0 : static_cast<int>(::GetLastError());
#else
bool ok = 0 == std::rename(replacement_name.c_str(), replaced_name.c_str());
diff --git a/src/simplewallet/CMakeLists.txt b/src/simplewallet/CMakeLists.txt
index 4230e32c0..8bb295931 100644
--- a/src/simplewallet/CMakeLists.txt
+++ b/src/simplewallet/CMakeLists.txt
@@ -54,6 +54,7 @@ target_link_libraries(simplewallet
${Boost_CHRONO_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY}
${Boost_FILESYSTEM_LIBRARY}
+ ${ICU_LIBRARIES}
${Boost_THREAD_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
${GNU_READLINE_LIBRARY}
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index c67a6bc6c..958fe5edc 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -64,6 +64,11 @@
#include "wallet/wallet_args.h"
#include <stdexcept>
+#ifdef WIN32
+#include <boost/locale.hpp>
+#include <boost/filesystem.hpp>
+#endif
+
#ifdef HAVE_READLINE
#include "readline_buffer.h"
#endif
@@ -130,6 +135,28 @@ namespace
const command_line::arg_descriptor< std::vector<std::string> > arg_command = {"command", ""};
+#ifdef WIN32
+ // Translate from CP850 to UTF-8;
+ // std::getline for a Windows console returns a string in CP437 or CP850; as simplewallet,
+ // like all of Monero, is assumed to work internally with UTF-8 throughout, even on Windows
+ // (although only implemented partially), a translation to UTF-8 is needed for input.
+ //
+ // Note that if a program is started inside the MSYS2 shell somebody already translates
+ // console input to UTF-8, but it's not clear how one could detect that in order to avoid
+ // double-translation; this code here thus breaks UTF-8 input within a MSYS2 shell,
+ // unfortunately.
+ //
+ // Note also that input for passwords is NOT translated, to remain compatible with any
+ // passwords containing special characters that predate this switch to UTF-8 support.
+ static std::string cp850_to_utf8(const std::string &cp850_str)
+ {
+ boost::locale::generator gen;
+ gen.locale_cache_enabled(true);
+ std::locale loc = gen("en_US.CP850");
+ return boost::locale::conv::to_utf<char>(cp850_str, loc);
+ }
+#endif
+
std::string input_line(const std::string& prompt)
{
#ifdef HAVE_READLINE
@@ -139,6 +166,9 @@ namespace
std::string buf;
std::getline(std::cin, buf);
+#ifdef WIN32
+ buf = cp850_to_utf8(buf);
+#endif
return epee::string_tools::trim(buf);
}
@@ -6751,6 +6781,12 @@ void simple_wallet::commit_or_save(std::vector<tools::wallet2::pending_tx>& ptx_
//----------------------------------------------------------------------------------------------------
int main(int argc, char* argv[])
{
+#ifdef WIN32
+ // Activate UTF-8 support for Boost filesystem classes on Windows
+ std::locale::global(boost::locale::generator().generate(""));
+ boost::filesystem::path::imbue(std::locale());
+#endif
+
po::options_description desc_params(wallet_args::tr("Wallet options"));
tools::wallet2::init_options(desc_params);
command_line::add_arg(desc_params, arg_wallet_file);
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index 5ce8ede8d..de17e5608 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -44,6 +44,11 @@
#include <sstream>
#include <unordered_map>
+#ifdef WIN32
+#include <boost/locale.hpp>
+#include <boost/filesystem.hpp>
+#endif
+
using namespace std;
using namespace cryptonote;
@@ -291,6 +296,11 @@ uint64_t Wallet::maximumAllowedAmount()
}
void Wallet::init(const char *argv0, const char *default_log_base_name) {
+#ifdef WIN32
+ // Activate UTF-8 support for Boost filesystem classes on Windows
+ std::locale::global(boost::locale::generator().generate(""));
+ boost::filesystem::path::imbue(std::locale());
+#endif
epee::string_tools::set_module_name_and_folder(argv0);
mlog_configure(mlog_get_default_log_path(default_log_base_name), true);
}
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 3bad743cf..92b683552 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -3737,12 +3737,24 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
}
} else {
// save to new file
+#ifdef WIN32
+ // On Windows avoid using std::ofstream which does not work with UTF-8 filenames
+ // The price to pay is temporary higher memory consumption for string stream + binary archive
+ std::ostringstream oss;
+ binary_archive<true> oar(oss);
+ bool success = ::serialization::serialize(oar, cache_file_data);
+ if (success) {
+ success = epee::file_io_utils::save_string_to_file(new_file, oss.str());
+ }
+ THROW_WALLET_EXCEPTION_IF(!success, error::file_save_error, new_file);
+#else
std::ofstream ostr;
ostr.open(new_file, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc);
binary_archive<true> oar(ostr);
bool success = ::serialization::serialize(oar, cache_file_data);
ostr.close();
THROW_WALLET_EXCEPTION_IF(!success || !ostr.good(), error::file_save_error, new_file);
+#endif
// here we have "*.new" file, we need to rename it to be without ".new"
std::error_code e = tools::replace_file(new_file, m_wallet_file);