diff options
Diffstat (limited to 'Source/kwsys/EncodingCXX.cxx')
-rw-r--r-- | Source/kwsys/EncodingCXX.cxx | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/Source/kwsys/EncodingCXX.cxx b/Source/kwsys/EncodingCXX.cxx new file mode 100644 index 0000000..5cad934 --- /dev/null +++ b/Source/kwsys/EncodingCXX.cxx @@ -0,0 +1,288 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifdef __osf__ +# define _OSF_SOURCE +# define _POSIX_C_SOURCE 199506L +# define _XOPEN_SOURCE_EXTENDED +#endif + +#include "kwsysPrivate.h" +#include KWSYS_HEADER(Encoding.hxx) +#include KWSYS_HEADER(Encoding.h) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "Encoding.h.in" +# include "Encoding.hxx.in" +#endif + +#include <stdlib.h> +#include <string.h> +#include <vector> + +#ifdef _MSC_VER +# pragma warning(disable : 4786) +#endif + +// Windows API. +#if defined(_WIN32) +# include <windows.h> + +# include <ctype.h> +# include <shellapi.h> +#endif + +namespace KWSYS_NAMESPACE { + +Encoding::CommandLineArguments Encoding::CommandLineArguments::Main( + int argc, char const* const* argv) +{ +#ifdef _WIN32 + (void)argc; + (void)argv; + + int ac; + LPWSTR* w_av = CommandLineToArgvW(GetCommandLineW(), &ac); + + std::vector<std::string> av1(ac); + std::vector<char const*> av2(ac); + for (int i = 0; i < ac; i++) { + av1[i] = ToNarrow(w_av[i]); + av2[i] = av1[i].c_str(); + } + LocalFree(w_av); + return CommandLineArguments(ac, &av2[0]); +#else + return CommandLineArguments(argc, argv); +#endif +} + +Encoding::CommandLineArguments::CommandLineArguments(int ac, + char const* const* av) +{ + this->argv_.resize(ac + 1); + for (int i = 0; i < ac; i++) { + this->argv_[i] = strdup(av[i]); + } + this->argv_[ac] = nullptr; +} + +Encoding::CommandLineArguments::CommandLineArguments(int ac, + wchar_t const* const* av) +{ + this->argv_.resize(ac + 1); + for (int i = 0; i < ac; i++) { + this->argv_[i] = kwsysEncoding_DupToNarrow(av[i]); + } + this->argv_[ac] = nullptr; +} + +Encoding::CommandLineArguments::~CommandLineArguments() +{ + for (size_t i = 0; i < this->argv_.size(); i++) { + free(argv_[i]); + } +} + +Encoding::CommandLineArguments::CommandLineArguments( + const CommandLineArguments& other) +{ + this->argv_.resize(other.argv_.size()); + for (size_t i = 0; i < this->argv_.size(); i++) { + this->argv_[i] = other.argv_[i] ? strdup(other.argv_[i]) : nullptr; + } +} + +Encoding::CommandLineArguments& Encoding::CommandLineArguments::operator=( + const CommandLineArguments& other) +{ + if (this != &other) { + size_t i; + for (i = 0; i < this->argv_.size(); i++) { + free(this->argv_[i]); + } + + this->argv_.resize(other.argv_.size()); + for (i = 0; i < this->argv_.size(); i++) { + this->argv_[i] = other.argv_[i] ? strdup(other.argv_[i]) : nullptr; + } + } + + return *this; +} + +int Encoding::CommandLineArguments::argc() const +{ + return static_cast<int>(this->argv_.size() - 1); +} + +char const* const* Encoding::CommandLineArguments::argv() const +{ + return &this->argv_[0]; +} + +#if KWSYS_STL_HAS_WSTRING + +std::wstring Encoding::ToWide(const std::string& str) +{ + std::wstring wstr; +# if defined(_WIN32) + const int wlength = + MultiByteToWideChar(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.data(), + int(str.size()), nullptr, 0); + if (wlength > 0) { + wchar_t* wdata = new wchar_t[wlength]; + int r = MultiByteToWideChar(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.data(), + int(str.size()), wdata, wlength); + if (r > 0) { + wstr = std::wstring(wdata, wlength); + } + delete[] wdata; + } +# else + size_t pos = 0; + size_t nullPos = 0; + do { + if (pos < str.size() && str.at(pos) != '\0') { + wstr += ToWide(str.c_str() + pos); + } + nullPos = str.find('\0', pos); + if (nullPos != std::string::npos) { + pos = nullPos + 1; + wstr += wchar_t('\0'); + } + } while (nullPos != std::string::npos); +# endif + return wstr; +} + +std::string Encoding::ToNarrow(const std::wstring& str) +{ + std::string nstr; +# if defined(_WIN32) + int length = + WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.c_str(), + int(str.size()), nullptr, 0, nullptr, nullptr); + if (length > 0) { + char* data = new char[length]; + int r = + WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.c_str(), + int(str.size()), data, length, nullptr, nullptr); + if (r > 0) { + nstr = std::string(data, length); + } + delete[] data; + } +# else + size_t pos = 0; + size_t nullPos = 0; + do { + if (pos < str.size() && str.at(pos) != '\0') { + nstr += ToNarrow(str.c_str() + pos); + } + nullPos = str.find(wchar_t('\0'), pos); + if (nullPos != std::string::npos) { + pos = nullPos + 1; + nstr += '\0'; + } + } while (nullPos != std::string::npos); +# endif + return nstr; +} + +std::wstring Encoding::ToWide(const char* cstr) +{ + std::wstring wstr; + size_t length = kwsysEncoding_mbstowcs(nullptr, cstr, 0) + 1; + if (length > 0) { + std::vector<wchar_t> wchars(length); + if (kwsysEncoding_mbstowcs(&wchars[0], cstr, length) > 0) { + wstr = &wchars[0]; + } + } + return wstr; +} + +std::string Encoding::ToNarrow(const wchar_t* wcstr) +{ + std::string str; + size_t length = kwsysEncoding_wcstombs(nullptr, wcstr, 0) + 1; + if (length > 0) { + std::vector<char> chars(length); + if (kwsysEncoding_wcstombs(&chars[0], wcstr, length) > 0) { + str = &chars[0]; + } + } + return str; +} + +# if defined(_WIN32) +// Convert local paths to UNC style paths +std::wstring Encoding::ToWindowsExtendedPath(std::string const& source) +{ + return ToWindowsExtendedPath(ToWide(source)); +} + +// Convert local paths to UNC style paths +std::wstring Encoding::ToWindowsExtendedPath(const char* source) +{ + return ToWindowsExtendedPath(ToWide(source)); +} + +// Convert local paths to UNC style paths +std::wstring Encoding::ToWindowsExtendedPath(std::wstring const& wsource) +{ + // Resolve any relative paths + DWORD wfull_len; + + /* The +3 is a workaround for a bug in some versions of GetFullPathNameW that + * won't return a large enough buffer size if the input is too small */ + wfull_len = GetFullPathNameW(wsource.c_str(), 0, nullptr, nullptr) + 3; + std::vector<wchar_t> wfull(wfull_len); + GetFullPathNameW(wsource.c_str(), wfull_len, &wfull[0], nullptr); + + /* This should get the correct size without any extra padding from the + * previous size workaround. */ + wfull_len = static_cast<DWORD>(wcslen(&wfull[0])); + + if (wfull_len >= 2 && isalpha(wfull[0]) && + wfull[1] == L':') { /* C:\Foo\bar\FooBar.txt */ + return L"\\\\?\\" + std::wstring(&wfull[0]); + } else if (wfull_len >= 2 && wfull[0] == L'\\' && + wfull[1] == L'\\') { /* Starts with \\ */ + if (wfull_len >= 4 && wfull[2] == L'?' && + wfull[3] == L'\\') { /* Starts with \\?\ */ + if (wfull_len >= 8 && wfull[4] == L'U' && wfull[5] == L'N' && + wfull[6] == L'C' && + wfull[7] == L'\\') { /* \\?\UNC\Foo\bar\FooBar.txt */ + return std::wstring(&wfull[0]); + } else if (wfull_len >= 6 && isalpha(wfull[4]) && + wfull[5] == L':') { /* \\?\C:\Foo\bar\FooBar.txt */ + return std::wstring(&wfull[0]); + } else if (wfull_len >= 5) { /* \\?\Foo\bar\FooBar.txt */ + return L"\\\\?\\UNC\\" + std::wstring(&wfull[4]); + } + } else if (wfull_len >= 4 && wfull[2] == L'.' && + wfull[3] == L'\\') { /* Starts with \\.\ a device name */ + if (wfull_len >= 6 && isalpha(wfull[4]) && + wfull[5] == L':') { /* \\.\C:\Foo\bar\FooBar.txt */ + return L"\\\\?\\" + std::wstring(&wfull[4]); + } else if (wfull_len >= + 5) { /* \\.\Foo\bar\ Device name is left unchanged */ + return std::wstring(&wfull[0]); + } + } else if (wfull_len >= 3) { /* \\Foo\bar\FooBar.txt */ + return L"\\\\?\\UNC\\" + std::wstring(&wfull[2]); + } + } + + // If this case has been reached, then the path is invalid. Leave it + // unchanged + return wsource; +} +# endif + +#endif // KWSYS_STL_HAS_WSTRING + +} // namespace KWSYS_NAMESPACE |