diff --git a/libcxx/include/filesystem b/libcxx/include/filesystem --- a/libcxx/include/filesystem +++ b/libcxx/include/filesystem @@ -690,6 +690,13 @@ typedef char __path_value; #endif +#if defined(_LIBCPP_WIN32API) +_LIBCPP_FUNC_VIS +size_t __wide_to_char(const wstring&, char*, size_t); +_LIBCPP_FUNC_VIS +size_t __char_to_wide(const string&, wchar_t*, size_t); +#endif + template struct _PathCVT; @@ -793,6 +800,48 @@ }; #if defined(_LIBCPP_WIN32API) +template <> +struct _PathCVT { + + static void + __append_string(__path_string& __dest, const basic_string &__str) { + size_t __size = __char_to_wide(__str, nullptr, 0); + size_t __pos = __dest.size(); + __dest.resize(__pos + __size); + __char_to_wide(__str, const_cast<__path_value*>(__dest.data()) + __pos, __size); + } + + template + static typename enable_if<__is_exactly_cpp17_input_iterator<_Iter>::value>::type + __append_range(__path_string& __dest, _Iter __b, _Iter __e) { + basic_string __tmp(__b, __e); + __append_string(__dest, __tmp); + } + + template + static typename enable_if<__is_cpp17_forward_iterator<_Iter>::value>::type + __append_range(__path_string& __dest, _Iter __b, _Iter __e) { + basic_string __tmp(__b, __e); + __append_string(__dest, __tmp); + } + + template + static void __append_range(__path_string& __dest, _Iter __b, _NullSentinel) { + const char __sentinel = char{}; + basic_string __tmp; + for (; *__b != __sentinel; ++__b) + __tmp.push_back(*__b); + __append_string(__dest, __tmp); + } + + template + static void __append_source(__path_string& __dest, _Source const& __s) { + using _Traits = __is_pathable<_Source>; + __append_range(__dest, _Traits::__range_begin(__s), + _Traits::__range_end(__s)); + } +}; + template struct _PathExport { typedef __narrow_to_utf8 _Narrower; @@ -806,6 +855,17 @@ } }; +template <> +struct _PathExport { + template + static void __append(_Str& __dest, const __path_string& __src) { + size_t __size = __wide_to_char(__src, nullptr, 0); + size_t __pos = __dest.size(); + __dest.resize(__size); + __wide_to_char(__src, const_cast(__dest.data()) + __pos, __size); + } +}; + template <> struct _PathExport { template @@ -1110,7 +1170,11 @@ return string(); } _LIBCPP_INLINE_VISIBILITY __u8_string u8string() const { - return string<__u8_string::value_type>(); + using _CVT = __narrow_to_utf8; + __u8_string __s; + __s.reserve(__pn_.size()); + _CVT()(back_inserter(__s), __pn_.data(), __pn_.data() + __pn_.size()); + return __s; } _LIBCPP_INLINE_VISIBILITY _VSTD::u16string u16string() const { @@ -1373,9 +1437,42 @@ is_same::__char_type, char>::value, "u8path(Iter, Iter) requires Iter have a value_type of type 'char'" " or 'char8_t'"); +#if defined(_LIBCPP_WIN32API) + string __tmp(__f, __l); + using _CVT = __widen_from_utf8; + _VSTD::wstring __w; + __w.reserve(__tmp.size()); + _CVT()(back_inserter(__w), __tmp.data(), __tmp.data() + __tmp.size()); + return path(__w); +#else return path(__f, __l); +#endif /* !_LIBCPP_WIN32API */ } +#if defined(_LIBCPP_WIN32API) +template +_LIBCPP_INLINE_VISIBILITY _LIBCPP_DEPRECATED_WITH_CHAR8_T + typename enable_if<__is_pathable<_InputIt>::value, path>::type + u8path(_InputIt __f, _NullSentinel) { + static_assert( +#ifndef _LIBCPP_NO_HAS_CHAR8_T + is_same::__char_type, char8_t>::value || +#endif + is_same::__char_type, char>::value, + "u8path(Iter, Iter) requires Iter have a value_type of type 'char'" + " or 'char8_t'"); + string __tmp; + const char __sentinel = char{}; + for (; *__f != __sentinel; ++__f) + __tmp.push_back(*__f); + using _CVT = __widen_from_utf8; + _VSTD::wstring __w; + __w.reserve(__tmp.size()); + _CVT()(back_inserter(__w), __tmp.data(), __tmp.data() + __tmp.size()); + return path(__w); +} +#endif /* _LIBCPP_WIN32API */ + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_DEPRECATED_WITH_CHAR8_T typename enable_if<__is_pathable<_Source>::value, path>::type @@ -1387,7 +1484,12 @@ is_same::__char_type, char>::value, "u8path(Source const&) requires Source have a character type of type " "'char' or 'char8_t'"); +#if defined(_LIBCPP_WIN32API) + using _Traits = __is_pathable<_Source>; + return u8path(__unwrap_iter(_Traits::__range_begin(__s)), __unwrap_iter(_Traits::__range_end(__s))); +#else return path(__s); +#endif } class _LIBCPP_TYPE_VIS path::iterator { diff --git a/libcxx/src/filesystem/filesystem_common.h b/libcxx/src/filesystem/filesystem_common.h --- a/libcxx/src/filesystem/filesystem_common.h +++ b/libcxx/src/filesystem/filesystem_common.h @@ -126,6 +126,12 @@ bool error_value() { return false; } +#if __SIZEOF_SIZE_T__ != __SIZEOF_LONG_LONG__ +template <> +size_t error_value() { + return size_t(-1); +} +#endif template <> uintmax_t error_value() { return uintmax_t(-1); diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp --- a/libcxx/src/filesystem/operations.cpp +++ b/libcxx/src/filesystem/operations.cpp @@ -17,9 +17,15 @@ #include "filesystem_common.h" -#include -#include -#include +#if defined(_LIBCPP_WIN32API) +# define WIN32_LEAN_AND_MEAN +# define NOMINMAX +# include +#else +# include +# include +# include +#endif #include #include /* values for fchmodat */ @@ -1680,6 +1686,36 @@ return *this; } +#if defined(_LIBCPP_WIN32API) +//////////////////////////////////////////////////////////////////////////// +// Windows path conversions +size_t __wide_to_char(const wstring &str, char *out, size_t outlen) { + if (str.empty()) + return 0; + ErrorHandler err("__wide_to_char", nullptr); + UINT codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; + BOOL used_default = FALSE; + int ret = WideCharToMultiByte(codepage, 0, str.data(), str.size(), out, + outlen, nullptr, &used_default); + if (ret <= 0 || used_default) + return err.report(errc::illegal_byte_sequence); + return ret; +} + +size_t __char_to_wide(const string &str, wchar_t *out, size_t outlen) { + if (str.empty()) + return 0; + ErrorHandler err("__char_to_wide", nullptr); + UINT codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; + int ret = MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, str.data(), + str.size(), out, outlen); + if (ret <= 0) + return err.report(errc::illegal_byte_sequence); + return ret; +} +#endif + + /////////////////////////////////////////////////////////////////////////////// // directory entry definitions ///////////////////////////////////////////////////////////////////////////////