| /* 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] = KWSYS_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] = KWSYS_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]) : KWSYS_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]) : KWSYS_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()), NULL, 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()), NULL, 0, NULL, NULL); |
| if (length > 0) { |
| char* data = new char[length]; |
| int r = |
| WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.c_str(), |
| int(str.size()), data, length, NULL, NULL); |
| 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(KWSYS_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(KWSYS_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) |
| { |
| std::wstring wsource = Encoding::ToWide(source); |
| |
| // 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, NULL, NULL) + 3; |
| std::vector<wchar_t> wfull(wfull_len); |
| GetFullPathNameW(wsource.c_str(), wfull_len, &wfull[0], NULL); |
| |
| /* 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 Encoding::ToWide(source); |
| } |
| #endif |
| |
| #endif // KWSYS_STL_HAS_WSTRING |
| |
| } // namespace KWSYS_NAMESPACE |