1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
3 #ifdef __osf__
4 # define _OSF_SOURCE
5 # define _POSIX_C_SOURCE 199506L
6 # define _XOPEN_SOURCE_EXTENDED
7 #endif
8
9 #include "kwsysPrivate.h"
10 #include KWSYS_HEADER(Encoding.hxx)
11 #include KWSYS_HEADER(Encoding.h)
12
13 // Work-around CMake dependency scanning limitation. This must
14 // duplicate the above list of headers.
15 #if 0
16 # include "Encoding.h.in"
17 # include "Encoding.hxx.in"
18 #endif
19
20 #include <stdlib.h>
21 #include <string.h>
22 #include <vector>
23
24 #ifdef _MSC_VER
25 # pragma warning(disable : 4786)
26 #endif
27
28 // Windows API.
29 #if defined(_WIN32)
30 # include <windows.h>
31
32 # include <ctype.h>
33 # include <shellapi.h>
34 #endif
35
36 namespace KWSYS_NAMESPACE {
37
Main(int argc,char const * const * argv)38 Encoding::CommandLineArguments Encoding::CommandLineArguments::Main(
39 int argc, char const* const* argv)
40 {
41 #ifdef _WIN32
42 (void)argc;
43 (void)argv;
44
45 int ac;
46 LPWSTR* w_av = CommandLineToArgvW(GetCommandLineW(), &ac);
47
48 std::vector<std::string> av1(ac);
49 std::vector<char const*> av2(ac);
50 for (int i = 0; i < ac; i++) {
51 av1[i] = ToNarrow(w_av[i]);
52 av2[i] = av1[i].c_str();
53 }
54 LocalFree(w_av);
55 return CommandLineArguments(ac, &av2[0]);
56 #else
57 return CommandLineArguments(argc, argv);
58 #endif
59 }
60
CommandLineArguments(int ac,char const * const * av)61 Encoding::CommandLineArguments::CommandLineArguments(int ac,
62 char const* const* av)
63 {
64 this->argv_.resize(ac + 1);
65 for (int i = 0; i < ac; i++) {
66 this->argv_[i] = strdup(av[i]);
67 }
68 this->argv_[ac] = KWSYS_NULLPTR;
69 }
70
CommandLineArguments(int ac,wchar_t const * const * av)71 Encoding::CommandLineArguments::CommandLineArguments(int ac,
72 wchar_t const* const* av)
73 {
74 this->argv_.resize(ac + 1);
75 for (int i = 0; i < ac; i++) {
76 this->argv_[i] = kwsysEncoding_DupToNarrow(av[i]);
77 }
78 this->argv_[ac] = KWSYS_NULLPTR;
79 }
80
~CommandLineArguments()81 Encoding::CommandLineArguments::~CommandLineArguments()
82 {
83 for (size_t i = 0; i < this->argv_.size(); i++) {
84 free(argv_[i]);
85 }
86 }
87
CommandLineArguments(const CommandLineArguments & other)88 Encoding::CommandLineArguments::CommandLineArguments(
89 const CommandLineArguments& other)
90 {
91 this->argv_.resize(other.argv_.size());
92 for (size_t i = 0; i < this->argv_.size(); i++) {
93 this->argv_[i] = other.argv_[i] ? strdup(other.argv_[i]) : KWSYS_NULLPTR;
94 }
95 }
96
operator =(const CommandLineArguments & other)97 Encoding::CommandLineArguments& Encoding::CommandLineArguments::operator=(
98 const CommandLineArguments& other)
99 {
100 if (this != &other) {
101 size_t i;
102 for (i = 0; i < this->argv_.size(); i++) {
103 free(this->argv_[i]);
104 }
105
106 this->argv_.resize(other.argv_.size());
107 for (i = 0; i < this->argv_.size(); i++) {
108 this->argv_[i] = other.argv_[i] ? strdup(other.argv_[i]) : KWSYS_NULLPTR;
109 }
110 }
111
112 return *this;
113 }
114
argc() const115 int Encoding::CommandLineArguments::argc() const
116 {
117 return static_cast<int>(this->argv_.size() - 1);
118 }
119
argv() const120 char const* const* Encoding::CommandLineArguments::argv() const
121 {
122 return &this->argv_[0];
123 }
124
125 #if KWSYS_STL_HAS_WSTRING
126
ToWide(const std::string & str)127 std::wstring Encoding::ToWide(const std::string& str)
128 {
129 std::wstring wstr;
130 # if defined(_WIN32)
131 const int wlength = MultiByteToWideChar(
132 KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.data(), int(str.size()), NULL, 0);
133 if (wlength > 0) {
134 wchar_t* wdata = new wchar_t[wlength];
135 int r = MultiByteToWideChar(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.data(),
136 int(str.size()), wdata, wlength);
137 if (r > 0) {
138 wstr = std::wstring(wdata, wlength);
139 }
140 delete[] wdata;
141 }
142 # else
143 size_t pos = 0;
144 size_t nullPos = 0;
145 do {
146 if (pos < str.size() && str.at(pos) != '\0') {
147 wstr += ToWide(str.c_str() + pos);
148 }
149 nullPos = str.find('\0', pos);
150 if (nullPos != std::string::npos) {
151 pos = nullPos + 1;
152 wstr += wchar_t('\0');
153 }
154 } while (nullPos != std::string::npos);
155 # endif
156 return wstr;
157 }
158
ToNarrow(const std::wstring & str)159 std::string Encoding::ToNarrow(const std::wstring& str)
160 {
161 std::string nstr;
162 # if defined(_WIN32)
163 int length =
164 WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.c_str(),
165 int(str.size()), NULL, 0, NULL, NULL);
166 if (length > 0) {
167 char* data = new char[length];
168 int r =
169 WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.c_str(),
170 int(str.size()), data, length, NULL, NULL);
171 if (r > 0) {
172 nstr = std::string(data, length);
173 }
174 delete[] data;
175 }
176 # else
177 size_t pos = 0;
178 size_t nullPos = 0;
179 do {
180 if (pos < str.size() && str.at(pos) != '\0') {
181 nstr += ToNarrow(str.c_str() + pos);
182 }
183 nullPos = str.find(wchar_t('\0'), pos);
184 if (nullPos != std::string::npos) {
185 pos = nullPos + 1;
186 nstr += '\0';
187 }
188 } while (nullPos != std::string::npos);
189 # endif
190 return nstr;
191 }
192
ToWide(const char * cstr)193 std::wstring Encoding::ToWide(const char* cstr)
194 {
195 std::wstring wstr;
196 size_t length = kwsysEncoding_mbstowcs(KWSYS_NULLPTR, cstr, 0) + 1;
197 if (length > 0) {
198 std::vector<wchar_t> wchars(length);
199 if (kwsysEncoding_mbstowcs(&wchars[0], cstr, length) > 0) {
200 wstr = &wchars[0];
201 }
202 }
203 return wstr;
204 }
205
ToNarrow(const wchar_t * wcstr)206 std::string Encoding::ToNarrow(const wchar_t* wcstr)
207 {
208 std::string str;
209 size_t length = kwsysEncoding_wcstombs(KWSYS_NULLPTR, wcstr, 0) + 1;
210 if (length > 0) {
211 std::vector<char> chars(length);
212 if (kwsysEncoding_wcstombs(&chars[0], wcstr, length) > 0) {
213 str = &chars[0];
214 }
215 }
216 return str;
217 }
218
219 # if defined(_WIN32)
220 // Convert local paths to UNC style paths
ToWindowsExtendedPath(std::string const & source)221 std::wstring Encoding::ToWindowsExtendedPath(std::string const& source)
222 {
223 std::wstring wsource = Encoding::ToWide(source);
224
225 // Resolve any relative paths
226 DWORD wfull_len;
227
228 /* The +3 is a workaround for a bug in some versions of GetFullPathNameW that
229 * won't return a large enough buffer size if the input is too small */
230 wfull_len = GetFullPathNameW(wsource.c_str(), 0, NULL, NULL) + 3;
231 std::vector<wchar_t> wfull(wfull_len);
232 GetFullPathNameW(wsource.c_str(), wfull_len, &wfull[0], NULL);
233
234 /* This should get the correct size without any extra padding from the
235 * previous size workaround. */
236 wfull_len = static_cast<DWORD>(wcslen(&wfull[0]));
237
238 if (wfull_len >= 2 && isalpha(wfull[0]) &&
239 wfull[1] == L':') { /* C:\Foo\bar\FooBar.txt */
240 return L"\\\\?\\" + std::wstring(&wfull[0]);
241 } else if (wfull_len >= 2 && wfull[0] == L'\\' &&
242 wfull[1] == L'\\') { /* Starts with \\ */
243 if (wfull_len >= 4 && wfull[2] == L'?' &&
244 wfull[3] == L'\\') { /* Starts with \\?\ */
245 if (wfull_len >= 8 && wfull[4] == L'U' && wfull[5] == L'N' &&
246 wfull[6] == L'C' &&
247 wfull[7] == L'\\') { /* \\?\UNC\Foo\bar\FooBar.txt */
248 return std::wstring(&wfull[0]);
249 } else if (wfull_len >= 6 && isalpha(wfull[4]) &&
250 wfull[5] == L':') { /* \\?\C:\Foo\bar\FooBar.txt */
251 return std::wstring(&wfull[0]);
252 } else if (wfull_len >= 5) { /* \\?\Foo\bar\FooBar.txt */
253 return L"\\\\?\\UNC\\" + std::wstring(&wfull[4]);
254 }
255 } else if (wfull_len >= 4 && wfull[2] == L'.' &&
256 wfull[3] == L'\\') { /* Starts with \\.\ a device name */
257 if (wfull_len >= 6 && isalpha(wfull[4]) &&
258 wfull[5] == L':') { /* \\.\C:\Foo\bar\FooBar.txt */
259 return L"\\\\?\\" + std::wstring(&wfull[4]);
260 } else if (wfull_len >=
261 5) { /* \\.\Foo\bar\ Device name is left unchanged */
262 return std::wstring(&wfull[0]);
263 }
264 } else if (wfull_len >= 3) { /* \\Foo\bar\FooBar.txt */
265 return L"\\\\?\\UNC\\" + std::wstring(&wfull[2]);
266 }
267 }
268
269 // If this case has been reached, then the path is invalid. Leave it
270 // unchanged
271 return Encoding::ToWide(source);
272 }
273 # endif
274
275 #endif // KWSYS_STL_HAS_WSTRING
276
277 } // namespace KWSYS_NAMESPACE
278