45 #if defined(_WIN32) && !defined(_XBOX_ONE)
50 #define SUPPORT_LONGPATHS
52 #include <google/protobuf/io/io_win32.h>
60 #include <sys/types.h>
63 #ifndef WIN32_LEAN_AND_MEAN
64 #define WIN32_LEAN_AND_MEAN 1
83 template <
typename char_type>
89 struct CharTraits<char> {
90 static bool is_alpha(
char ch) {
return isalpha(
ch); }
94 struct CharTraits<wchar_t> {
95 static bool is_alpha(
wchar_t ch) {
return iswalpha(
ch); }
98 template <
typename char_type>
100 return s ==
nullptr || *
s == 0;
107 template <
typename char_type>
109 return CharTraits<char_type>::is_alpha(
ch[0]) &&
ch[1] ==
':';
113 template <
typename char_type>
115 return path[0] ==
'\\' &&
path[1] ==
'\\' &&
path[2] ==
'?' &&
119 template <
typename char_type>
121 return c ==
'/' ||
c ==
'\\';
125 template <
typename char_type>
127 return has_drive_letter(
path) && is_separator(
path[2]);
130 template <
typename char_type>
132 return has_drive_letter(
path) && (
path[2] == 0 || !is_separator(
path[2]));
136 if (path1.empty() || is_path_absolute(path2.c_str()) ||
137 has_longpath_prefix(path2.c_str())) {
144 if (is_separator(path1[path1.size() - 1])) {
145 return is_separator(path2[0]) ? (path1 + path2.substr(1))
148 return is_separator(path2[0]) ? (path1 + path2)
149 : (path1 + L
'\\' + path2);
154 if (has_longpath_prefix(
path.c_str())) {
158 static const wstring dot(L
".");
159 static const wstring dotdot(L
"..");
160 const WCHAR*
p =
path.c_str();
162 std::vector<wstring> segments;
163 int segment_start = -1;
165 for (
int i = 0;; ++
i) {
166 if (!is_separator(p[i]) && p[i] != L
'\0') {
169 if (segment_start < 0) {
172 }
else if (segment_start >= 0 && i > segment_start) {
175 wstring segment(p, segment_start, i - segment_start);
177 if (segment == dotdot) {
178 if (!segments.empty() &&
179 (!has_drive_letter(segments[0].
c_str()) || segments.size() > 1)) {
182 }
else if (segment != dot && !segment.empty()) {
183 segments.push_back(segment);
193 if (segments.size() == 1 && segments[0].size() == 2 &&
194 has_drive_letter(segments[0].
c_str())) {
195 return segments[0] +
L'\\';
200 std::wstringstream
result;
201 for (
int i = 0;
i < segments.size(); ++
i) {
209 if (!
path.empty() && is_separator(p[
path.size() - 1])) {
216 if (null_or_empty(
path)) {
221 if (!strings::utf8_to_wcs(
path, &wpath)) {
224 if (has_longpath_prefix(wpath.c_str())) {
228 if (is_separator(
path[0]) || is_drive_relative(
path)) {
233 if (!is_path_absolute(wpath.c_str())) {
234 int size = ::GetCurrentDirectoryW(0,
nullptr);
235 if (
size == 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
238 std::unique_ptr<WCHAR[]> wcwd(
new WCHAR[
size]);
239 ::GetCurrentDirectoryW(
size, wcwd.get());
240 wpath = join_paths(wcwd.get(), wpath);
243 if (!has_longpath_prefix(wpath.c_str())) {
248 wpath =
wstring(L
"\\\\?\\") + wpath;
257 #ifdef SUPPORT_LONGPATHS
259 if (!as_windows_path(
path, &wpath)) {
263 return ::_wopen(wpath.c_str(),
flags,
mode);
269 int mkdir(
const char*
path,
int ) {
270 #ifdef SUPPORT_LONGPATHS
272 if (!as_windows_path(
path, &wpath)) {
276 return ::_wmkdir(wpath.c_str());
277 #else // not SUPPORT_LONGPATHS
278 return ::_mkdir(
path);
279 #endif // not SUPPORT_LONGPATHS
283 #ifdef SUPPORT_LONGPATHS
285 if (!as_windows_path(
path, &wpath)) {
289 return ::_waccess(wpath.c_str(),
mode);
295 int chdir(
const char*
path) {
296 #ifdef SUPPORT_LONGPATHS
298 if (!as_windows_path(
path, &wpath)) {
302 return ::_wchdir(wpath.c_str());
304 return ::_chdir(
path);
309 #ifdef SUPPORT_LONGPATHS
311 if (!as_windows_path(
path, &wpath)) {
315 return ::_wstat(wpath.c_str(),
buffer);
316 #else // not SUPPORT_LONGPATHS
318 #endif // not SUPPORT_LONGPATHS
322 #ifdef SUPPORT_LONGPATHS
323 if (null_or_empty(
path)) {
328 if (!as_windows_path(
path, &wpath)) {
333 if (!strings::utf8_to_wcs(
mode, &wmode)) {
337 return ::_wfopen(wpath.c_str(), wmode.c_str());
343 int close(
int fd) { return ::_close(fd); }
345 int dup(
int fd) { return ::_dup(fd); }
347 int dup2(
int fd1,
int fd2) { return ::_dup2(fd1, fd2); }
353 int setmode(
int fd,
int mode) { return ::_setmode(fd,
mode); }
359 wstring testonly_utf8_to_winpath(
const char*
path) {
361 return as_windows_path(
path, &wpath) ? wpath :
wstring();
364 ExpandWildcardsResult ExpandWildcards(
366 if (
path.find_first_of(
"*?") == string::npos) {
369 return ExpandWildcardsResult::kSuccess;
373 if (!as_windows_path(
path.c_str(), &wpath)) {
374 return ExpandWildcardsResult::kErrorInputPathConversion;
378 static const wstring kDotDot =
L"..";
383 return ExpandWildcardsResult::kErrorNoMatchingFile;
386 string::size_type
pos =
path.find_last_of(
"\\/");
388 if (
pos != string::npos) {
389 dirname =
path.substr(0,
pos + 1);
392 ExpandWildcardsResult matched = ExpandWildcardsResult::kErrorNoMatchingFile;
395 if ((
metadata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0 &&
397 matched = ExpandWildcardsResult::kSuccess;
400 return ExpandWildcardsResult::kErrorOutputPathConversion;
403 if (dirname.empty()) {
416 bool wcs_to_mbs(
const WCHAR* s,
string*
out,
bool outUtf8) {
417 if (null_or_empty(s)) {
423 int size = WideCharToMultiByte(
424 outUtf8 ? CP_UTF8 : CP_ACP, 0, s, -1,
nullptr, 0,
nullptr,
425 outUtf8 ?
nullptr : &usedDefaultChar);
426 if ((
size == 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
427 || usedDefaultChar) {
430 std::unique_ptr<CHAR[]> astr(
new CHAR[
size]);
432 outUtf8 ? CP_UTF8 : CP_ACP, 0, s, -1, astr.get(),
size,
nullptr,
nullptr);
433 out->assign(astr.get());
437 bool mbs_to_wcs(
const char* s,
wstring*
out,
bool inUtf8) {
438 if (null_or_empty(s)) {
445 MultiByteToWideChar(inUtf8 ? CP_UTF8 : CP_ACP, 0, s, -1,
nullptr, 0);
446 if (
size == 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
449 std::unique_ptr<WCHAR[]> wstr(
new WCHAR[
size]);
451 inUtf8 ? CP_UTF8 : CP_ACP, 0, s, -1, wstr.get(),
size + 1);
452 out->assign(wstr.get());
457 return mbs_to_wcs(
input,
out,
true);
460 bool wcs_to_utf8(
const wchar_t*
input,
string*
out) {
461 return wcs_to_mbs(
input,
out,
true);
470 #endif // defined(_WIN32)