45 #if defined(_WIN32) && !defined(_XBOX_ONE)
50 #define SUPPORT_LONGPATHS
59 #include <sys/types.h>
79 template <
typename char_type>
81 static bool is_alpha(char_type
ch);
85 struct CharTraits<char> {
86 static bool is_alpha(
char ch) {
return isalpha(
ch); }
90 struct CharTraits<wchar_t> {
91 static bool is_alpha(
wchar_t ch) {
return iswalpha(
ch); }
94 template <
typename char_type>
95 bool null_or_empty(
const char_type* s) {
96 return s ==
nullptr || *
s == 0;
103 template <
typename char_type>
104 bool has_drive_letter(
const char_type*
ch) {
105 return CharTraits<char_type>::is_alpha(
ch[0]) &&
ch[1] ==
':';
109 template <
typename char_type>
110 bool has_longpath_prefix(
const char_type*
path) {
111 return path[0] ==
'\\' &&
path[1] ==
'\\' &&
path[2] ==
'?' &&
115 template <
typename char_type>
117 return c ==
'/' || c ==
'\\';
121 template <
typename char_type>
122 bool is_path_absolute(
const char_type*
path) {
126 template <
typename char_type>
127 bool is_drive_relative(
const char_type*
path) {
132 if (path1.empty() || is_path_absolute(path2.c_str()) ||
133 has_longpath_prefix(path2.c_str())) {
141 return is_separator(path2[0]) ? (path1 + path2.substr(1))
145 : (path1 + L
'\\' + path2);
150 if (has_longpath_prefix(
path.c_str())) {
154 static const wstring dot(L
".");
155 static const wstring dotdot(L
"..");
156 const WCHAR*
p =
path.c_str();
158 std::vector<wstring> segments;
159 int segment_start = -1;
161 for (
int i = 0;; ++
i) {
165 if (segment_start < 0) {
168 }
else if (segment_start >= 0 &&
i > segment_start) {
171 wstring segment(
p, segment_start,
i - segment_start);
173 if (segment == dotdot) {
174 if (!segments.empty() &&
175 (!has_drive_letter(segments[0].c_str()) || segments.size() > 1)) {
178 }
else if (segment != dot && !segment.empty()) {
179 segments.push_back(segment);
189 if (segments.size() == 1 && segments[0].size() == 2 &&
190 has_drive_letter(segments[0].c_str())) {
191 return segments[0] + L
'\\';
196 std::wstringstream result;
197 for (
int i = 0;
i < segments.size(); ++
i) {
202 result << segments[
i];
211 bool as_windows_path(
const char*
path,
wstring* result) {
212 if (null_or_empty(
path)) {
217 if (!strings::utf8_to_wcs(
path, &wpath)) {
220 if (has_longpath_prefix(wpath.c_str())) {
229 if (!is_path_absolute(wpath.c_str())) {
230 int size = ::GetCurrentDirectoryW(0,
nullptr);
231 if (
size == 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
234 std::unique_ptr<WCHAR[]> wcwd(
new WCHAR[
size]);
235 ::GetCurrentDirectoryW(
size, wcwd.get());
236 wpath = join_paths(wcwd.get(), wpath);
239 if (!has_longpath_prefix(wpath.c_str())) {
244 wpath =
wstring(L
"\\\\?\\") + wpath;
253 #ifdef SUPPORT_LONGPATHS
255 if (!as_windows_path(
path, &wpath)) {
259 return ::_wopen(wpath.c_str(),
flags,
mode);
265 int mkdir(
const char*
path,
int _mode) {
266 #ifdef SUPPORT_LONGPATHS
268 if (!as_windows_path(
path, &wpath)) {
272 return ::_wmkdir(wpath.c_str());
273 #else // not SUPPORT_LONGPATHS
274 return ::_mkdir(
path);
275 #endif // not SUPPORT_LONGPATHS
279 #ifdef SUPPORT_LONGPATHS
281 if (!as_windows_path(
path, &wpath)) {
285 return ::_waccess(wpath.c_str(),
mode);
291 int chdir(
const char*
path) {
292 #ifdef SUPPORT_LONGPATHS
294 if (!as_windows_path(
path, &wpath)) {
298 return ::_wchdir(wpath.c_str());
300 return ::_chdir(
path);
304 int stat(
const char*
path,
struct _stat*
buffer) {
305 #ifdef SUPPORT_LONGPATHS
307 if (!as_windows_path(
path, &wpath)) {
311 return ::_wstat(wpath.c_str(),
buffer);
312 #else // not SUPPORT_LONGPATHS
314 #endif // not SUPPORT_LONGPATHS
317 FILE* fopen(
const char*
path,
const char*
mode) {
318 #ifdef SUPPORT_LONGPATHS
319 if (null_or_empty(
path)) {
324 if (!as_windows_path(
path, &wpath)) {
329 if (!strings::utf8_to_wcs(
mode, &wmode)) {
333 return ::_wfopen(wpath.c_str(), wmode.c_str());
339 int close(
int fd) { return ::_close(fd); }
341 int dup(
int fd) { return ::_dup(fd); }
343 int dup2(
int fd1,
int fd2) { return ::_dup2(fd1, fd2); }
349 int setmode(
int fd,
int mode) { return ::_setmode(fd,
mode); }
351 int write(
int fd,
const void*
buffer,
size_t size) {
355 wstring testonly_utf8_to_winpath(
const char*
path) {
357 return as_windows_path(
path, &wpath) ? wpath :
wstring();
362 bool wcs_to_mbs(
const WCHAR* s,
string* out,
bool outUtf8) {
363 if (null_or_empty(s)) {
367 BOOL usedDefaultChar = FALSE;
369 int size = WideCharToMultiByte(
370 outUtf8 ? CP_UTF8 : CP_ACP, 0, s, -1,
nullptr, 0,
nullptr,
371 outUtf8 ?
nullptr : &usedDefaultChar);
372 if ((
size == 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
373 || usedDefaultChar) {
376 std::unique_ptr<CHAR[]> astr(
new CHAR[
size]);
378 outUtf8 ? CP_UTF8 : CP_ACP, 0, s, -1, astr.get(),
size,
nullptr,
nullptr);
379 out->assign(astr.get());
383 bool mbs_to_wcs(
const char* s,
wstring* out,
bool inUtf8) {
384 if (null_or_empty(s)) {
391 MultiByteToWideChar(inUtf8 ? CP_UTF8 : CP_ACP, 0, s, -1,
nullptr, 0);
392 if (
size == 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
395 std::unique_ptr<WCHAR[]> wstr(
new WCHAR[
size]);
397 inUtf8 ? CP_UTF8 : CP_ACP, 0, s, -1, wstr.get(),
size + 1);
398 out->assign(wstr.get());
403 return mbs_to_wcs(
input, out,
true);
406 bool wcs_to_utf8(
const wchar_t*
input,
string* out) {
407 return wcs_to_mbs(
input, out,
true);
416 #endif // defined(_WIN32)