refs #17, work on wchar_t/wstring support on Windows.

This commit is contained in:
Steffen Schümann 2019-05-18 10:35:25 +02:00
parent 33e3a36044
commit 15788d8eb9
2 changed files with 184 additions and 97 deletions

View File

@ -1,6 +1,6 @@
//---------------------------------------------------------------------------------------
//
// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14
// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++147/C++17
//
//---------------------------------------------------------------------------------------
//
@ -161,7 +161,11 @@
// LWG #2937 enforces that fs::equivalent emits an error, if !fs::exists(p1)||!exists(p2)
#define LWG_2937_BEHAVIOUR
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// UTF8-Everywhere is the original behaviour of ghc::filesystem. With this define you can
// enable the more standard conforming implementation option that uses wstring on Windows
// as ghc::filesystem::string_type.
// #define GHC_WIN_WSTRING_STRING_TYPE
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch)
#define GHC_FILESYSTEM_VERSION 10105L
@ -182,11 +186,18 @@ public:
class GHC_FS_API_CLASS path
{
public:
using value_type = std::string::value_type;
using string_type = std::basic_string<value_type>;
#ifdef GHC_OS_WINDOWS
#ifdef GHC_WIN_WSTRING_STRING_TYPE
#define GHC_USE_WCHAR_T
using value_type = std::wstring::value_type;
#else
using value_type = std::string::value_type;
#endif
using string_type = std::basic_string<value_type>;
static constexpr value_type preferred_separator = '\\';
#else
using value_type = std::string::value_type;
using string_type = std::basic_string<value_type>;
static constexpr value_type preferred_separator = '/';
#endif
// 30.10.10.1 enumeration format
@ -216,11 +227,19 @@ public:
template <typename T1, typename T2 = void>
using path_type = typename std::enable_if<!std::is_same<path, T1>::value, path>::type;
#ifdef GHC_USE_WCHAR_T
template <typename T>
using path_from_string = typename std::enable_if<_is_basic_string<T>::value || std::is_same<char const*, typename std::decay<T>::type>::value || std::is_same<char*, typename std::decay<T>::type>::value ||
std::is_same<wchar_t const*, typename std::decay<T>::type>::value || std::is_same<wchar_t*, typename std::decay<T>::type>::value,
path>::type;
template <typename T>
using path_type_EcharT = typename std::enable_if<std::is_same<T, char>::value || std::is_same<T, char16_t>::value || std::is_same<T, char32_t>::value, path>::type;
#else
template <typename T>
using path_from_string = typename std::enable_if<_is_basic_string<T>::value || std::is_same<char const*, typename std::decay<T>::type>::value || std::is_same<char*, typename std::decay<T>::type>::value, path>::type;
template <typename T>
using path_type_EcharT = typename std::enable_if<std::is_same<T, char>::value || std::is_same<T, char16_t>::value || std::is_same<T, char32_t>::value || std::is_same<T, wchar_t>::value, path>::type;
#endif
// 30.10.8.4.1 constructors and destructor
path() noexcept;
path(const path& p);
@ -266,7 +285,7 @@ public:
path& operator+=(const value_type* x);
path& operator+=(value_type x);
template <class Source>
path_type<Source>& operator+=(const Source& x);
path_from_string<Source>& operator+=(const Source& x);
template <class EcharT>
path_type_EcharT<EcharT>& operator+=(EcharT x);
template <class Source>
@ -346,9 +365,11 @@ public:
iterator end() const;
private:
using impl_value_type = std::string::value_type;
using impl_string_type = std::basic_string<impl_value_type>;
friend class directory_iterator;
void append_name(const char* name);
static constexpr value_type generic_separator = '/';
static constexpr impl_value_type generic_separator = '/';
template <typename InputIterator>
class input_iterator_range
{
@ -372,9 +393,13 @@ private:
};
friend void swap(path& lhs, path& rhs) noexcept;
friend size_t hash_value(const path& p) noexcept;
string_type _path;
static void postprocess_path_with_format(impl_string_type& p, format fmt);
impl_string_type _path;
#ifdef GHC_OS_WINDOWS
impl_string_type native_impl() const;
mutable string_type _native_cache;
#else
const impl_string_type& native_impl() const;
#endif
};
@ -429,7 +454,7 @@ public:
using iterator_category = std::bidirectional_iterator_tag;
iterator();
iterator(const string_type::const_iterator& first, const string_type::const_iterator& last, const string_type::const_iterator& pos);
iterator(const impl_string_type::const_iterator& first, const impl_string_type::const_iterator& last, const impl_string_type::const_iterator& pos);
iterator& operator++();
iterator operator++(int);
iterator& operator--();
@ -440,13 +465,13 @@ public:
pointer operator->() const;
private:
string_type::const_iterator increment(const std::string::const_iterator& pos) const;
string_type::const_iterator decrement(const std::string::const_iterator& pos) const;
impl_string_type::const_iterator increment(const std::string::const_iterator& pos) const;
impl_string_type::const_iterator decrement(const std::string::const_iterator& pos) const;
void updateCurrent();
string_type::const_iterator _first;
string_type::const_iterator _last;
string_type::const_iterator _root;
string_type::const_iterator _iter;
impl_string_type::const_iterator _first;
impl_string_type::const_iterator _last;
impl_string_type::const_iterator _root;
impl_string_type::const_iterator _iter;
path _current;
};
@ -624,11 +649,11 @@ private:
filesystem::path _path;
file_status _status;
file_status _symlink_status;
uintmax_t _file_size;
uintmax_t _file_size = 0;
#ifndef GHC_OS_WINDOWS
uintmax_t _hard_link_count;
#endif
time_t _last_write_time;
time_t _last_write_time = 0;
};
// 30.10.13 Class directory_iterator
@ -1019,7 +1044,7 @@ private:
//-------------------------------------------------------------------------------------------------
namespace detail {
GHC_FS_API void postprocess_path_with_format(path::string_type& p, path::format fmt);
// GHC_FS_API void postprocess_path_with_format(path::impl_string_type& p, path::format fmt);
enum utf8_states_t { S_STRT = 0, S_RJCT = 8 };
GHC_FS_API void appendUTF8(std::string& str, uint32_t unicode);
GHC_FS_API bool is_surrogate(uint32_t c);
@ -1179,12 +1204,15 @@ GHC_INLINE void appendUTF8(std::string& str, uint32_t unicode)
str.push_back(static_cast<char>(((unicode & 0xfff) >> 6) + 128));
str.push_back(static_cast<char>((unicode & 0x3f) + 128));
}
else {
else if (unicode >= 0x10000 && unicode <= 0x10ffff) {
str.push_back(static_cast<char>((unicode >> 18) + 240));
str.push_back(static_cast<char>(((unicode & 0x3ffff) >> 12) + 128));
str.push_back(static_cast<char>(((unicode & 0xfff) >> 6) + 128));
str.push_back(static_cast<char>((unicode & 0x3f) + 128));
}
else {
appendUTF8(str, 0xfffd);
}
}
// Thanks to Bjoern Hoehrmann (https://bjoern.hoehrmann.de/utf-8/decoder/dfa/)
@ -1192,10 +1220,8 @@ GHC_INLINE void appendUTF8(std::string& str, uint32_t unicode)
// Generating debugging and shrinking my own DFA from scratch was a day of fun!
GHC_INLINE unsigned consumeUtf8Fragment(const unsigned state, const uint8_t fragment, uint32_t& codepoint)
{
static const uint32_t utf8_state_info[] = {
0x11111111u, 0x11111111u, 0x77777777u, 0x77777777u, 0x88888888u, 0x88888888u, 0x88888888u, 0x88888888u, 0x22222299u, 0x22222222u, 0x22222222u, 0x22222222u, 0x3333333au, 0x33433333u,
0x9995666bu, 0x99999999u, 0x88888880u, 0x22818108u, 0x88888881u, 0x88888882u, 0x88888884u, 0x88888887u, 0x88888886u, 0x82218108u, 0x82281108u, 0x88888888u, 0x88888883u, 0x88888885u,
};
static const uint32_t utf8_state_info[] = {0x11111111u, 0x11111111u, 0x77777777u, 0x77777777u, 0x88888888u, 0x88888888u, 0x88888888u, 0x88888888u, 0x22222299u, 0x22222222u, 0x22222222u, 0x22222222u, 0x3333333au, 0x33433333u, 0x9995666bu, 0x99999999u,
0x88888880u, 0x22818108u, 0x88888881u, 0x88888882u, 0x88888884u, 0x88888887u, 0x88888886u, 0x82218108u, 0x82281108u, 0x88888888u, 0x88888883u, 0x88888885u, 0u, 0u, 0u, 0u};
uint8_t category = fragment < 128 ? 0 : (utf8_state_info[(fragment >> 3) & 0xf] >> ((fragment & 7) << 2)) & 0xf;
codepoint = (state ? (codepoint << 6) | (fragment & 0x3f) : (0xff >> category) & fragment);
return state == S_RJCT ? static_cast<unsigned>(S_RJCT) : static_cast<unsigned>((utf8_state_info[category + 16] >> (state << 2)) & 0xf);
@ -1207,12 +1233,15 @@ GHC_INLINE unsigned consumeUtf8Fragment(const unsigned state, const uint8_t frag
namespace detail {
template <class StringType>
template <class StringType, typename std::enable_if<(sizeof(typename StringType::value_type) == 1)>::type* = nullptr>
inline StringType fromUtf8(const std::string& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())
{
return StringType(utf8String.begin(), utf8String.end());
}
template <class StringType, typename std::enable_if<(sizeof(typename StringType::value_type) == 2)>::type* = nullptr>
inline StringType fromUtf8(const std::string& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())
{
if (sizeof(typename StringType::value_type) == 1) {
return StringType(utf8String.begin(), utf8String.end());
}
StringType result(alloc);
result.reserve(utf8String.length());
std::string::const_iterator iter = utf8String.begin();
@ -1220,18 +1249,13 @@ inline StringType fromUtf8(const std::string& utf8String, const typename StringT
std::uint32_t codepoint = 0;
while (iter < utf8String.end()) {
if ((utf8_state = consumeUtf8Fragment(utf8_state, (uint8_t)*iter++, codepoint)) == S_STRT) {
if (sizeof(typename StringType::value_type) == 4) {
result += codepoint;
if (codepoint <= 0xffff) {
result += (typename StringType::value_type)codepoint;
}
else {
if (codepoint <= 0xffff) {
result += (typename StringType::value_type)codepoint;
}
else {
codepoint -= 0x10000;
result += (typename StringType::value_type)((codepoint >> 10) + 0xd800);
result += (typename StringType::value_type)((codepoint & 0x3ff) + 0xdc00);
}
codepoint -= 0x10000;
result += (typename StringType::value_type)((codepoint >> 10) + 0xd800);
result += (typename StringType::value_type)((codepoint & 0x3ff) + 0xdc00);
}
codepoint = 0;
}
@ -1247,6 +1271,31 @@ inline StringType fromUtf8(const std::string& utf8String, const typename StringT
return result;
}
template <class StringType, typename std::enable_if<(sizeof(typename StringType::value_type) == 4)>::type* = nullptr>
inline StringType fromUtf8(const std::string& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())
{
StringType result(alloc);
result.reserve(utf8String.length());
std::string::const_iterator iter = utf8String.begin();
unsigned utf8_state = S_STRT;
std::uint32_t codepoint = 0;
while (iter < utf8String.end()) {
if ((utf8_state = consumeUtf8Fragment(utf8_state, (uint8_t)*iter++, codepoint)) == S_STRT) {
result += codepoint;
codepoint = 0;
}
else if (utf8_state == S_RJCT) {
result += (typename StringType::value_type)0xfffd;
utf8_state = S_STRT;
codepoint = 0;
}
}
if (utf8_state) {
result += (typename StringType::value_type)0xfffd;
}
return result;
}
template <typename charT, typename traits, typename Alloc, typename std::enable_if<(sizeof(charT) == 1)>::type* = nullptr>
inline std::string toUtf8(const std::basic_string<charT, traits, Alloc>& unicodeString)
{
@ -1302,7 +1351,9 @@ GHC_INLINE bool startsWith(const std::string& what, const std::string& with)
return with.length() <= what.length() && equal(with.begin(), with.end(), what.begin());
}
GHC_INLINE void postprocess_path_with_format(path::string_type& p, path::format fmt)
} // namespace detail
GHC_INLINE void path::postprocess_path_with_format(path::impl_string_type& p, path::format fmt)
{
switch (fmt) {
#ifndef GHC_OS_WINDOWS
@ -1316,10 +1367,10 @@ GHC_INLINE void postprocess_path_with_format(path::string_type& p, path::format
case path::auto_format:
case path::native_format:
#endif
if (startsWith(p, std::string("\\\\?\\"))) {
if (detail::startsWith(p, std::string("\\\\?\\"))) {
// remove Windows long filename marker
p.erase(0, 4);
if (startsWith(p, std::string("UNC\\"))) {
if (detail::startsWith(p, std::string("UNC\\"))) {
p.erase(0, 2);
p[0] = '\\';
}
@ -1341,33 +1392,31 @@ GHC_INLINE void postprocess_path_with_format(path::string_type& p, path::format
}
}
} // namespace detail
#endif // GHC_EXPAND_IMPL
template <class Source, typename>
inline path::path(const Source& source, format fmt)
: _path(source)
: _path(detail::toUtf8(source))
{
detail::postprocess_path_with_format(_path, fmt);
postprocess_path_with_format(_path, fmt);
}
template <>
inline path::path(const std::wstring& source, format fmt)
{
_path = detail::toUtf8(source);
detail::postprocess_path_with_format(_path, fmt);
postprocess_path_with_format(_path, fmt);
}
template <>
inline path::path(const std::u16string& source, format fmt)
{
_path = detail::toUtf8(source);
detail::postprocess_path_with_format(_path, fmt);
postprocess_path_with_format(_path, fmt);
}
template <>
inline path::path(const std::u32string& source, format fmt)
{
_path = detail::toUtf8(source);
detail::postprocess_path_with_format(_path, fmt);
postprocess_path_with_format(_path, fmt);
}
template <class Source, typename>
@ -1845,9 +1894,13 @@ GHC_INLINE path::path(path&& p) noexcept
}
GHC_INLINE path::path(string_type&& source, format fmt)
#ifdef GHC_USE_WCHAR_T
: _path(detail::toUtf8(source))
#else
: _path(std::move(source))
#endif
{
detail::postprocess_path_with_format(_path, fmt);
postprocess_path_with_format(_path, fmt);
}
#endif // GHC_EXPAND_IMPL
@ -1898,8 +1951,12 @@ GHC_INLINE path& path::operator=(path::string_type&& source)
GHC_INLINE path& path::assign(path::string_type&& source)
{
#ifdef GHC_USE_WCHAR_T
_path = detail::toUtf8(source);
#else
_path = std::move(source);
detail::postprocess_path_with_format(_path, native_format);
#endif
postprocess_path_with_format(_path, native_format);
return *this;
}
@ -1915,7 +1972,7 @@ template <class Source>
inline path& path::assign(const Source& source)
{
_path.assign(detail::toUtf8(source));
detail::postprocess_path_with_format(_path, native_format);
postprocess_path_with_format(_path, native_format);
return *this;
}
@ -1930,7 +1987,7 @@ template <class InputIterator>
inline path& path::assign(InputIterator first, InputIterator last)
{
_path.assign(first, last);
detail::postprocess_path_with_format(_path, native_format);
postprocess_path_with_format(_path, native_format);
return *this;
}
@ -2048,7 +2105,11 @@ GHC_INLINE path& path::operator+=(value_type x)
}
#endif
if (_path.empty() || _path.back() != generic_separator) {
#ifdef GHC_USE_WCHAR_T
_path += detail::toUtf8(string_type(1, x));
#else
_path += x;
#endif
}
return *this;
}
@ -2056,7 +2117,7 @@ GHC_INLINE path& path::operator+=(value_type x)
#endif // GHC_EXPAND_IMPL
template <class Source>
inline path::path_type<Source>& path::operator+=(const Source& x)
inline path::path_from_string<Source>& path::operator+=(const Source& x)
{
return concat(x);
}
@ -2064,7 +2125,7 @@ inline path::path_type<Source>& path::operator+=(const Source& x)
template <class EcharT>
inline path::path_type_EcharT<EcharT>& path::operator+=(EcharT x)
{
std::basic_string<EcharT> part(x);
std::basic_string<EcharT> part(1, x);
concat(detail::toUtf8(part));
return *this;
}
@ -2073,7 +2134,7 @@ template <class Source>
inline path& path::concat(const Source& x)
{
path p(x);
detail::postprocess_path_with_format(p._path, native_format);
postprocess_path_with_format(p._path, native_format);
_path += p._path;
return *this;
}
@ -2081,7 +2142,7 @@ template <class InputIterator>
inline path& path::concat(InputIterator first, InputIterator last)
{
_path.append(first, last);
detail::postprocess_path_with_format(_path, native_format);
postprocess_path_with_format(_path, native_format);
return *this;
}
@ -2133,29 +2194,47 @@ GHC_INLINE void path::swap(path& rhs) noexcept
//-----------------------------------------------------------------------------
// 30.10.8.4.6, native format observers
GHC_INLINE const path::string_type& path::native() const
{
#ifdef GHC_OS_WINDOWS
GHC_INLINE path::impl_string_type path::native_impl() const
{
impl_string_type result;
if (is_absolute() && _path.length() > MAX_PATH - 10) {
// expand long Windows filenames with marker
if (has_root_name() && _path[0] == '/') {
_native_cache = "\\\\?\\UNC" + _path.substr(1);
result = "\\\\?\\UNC" + _path.substr(1);
}
else {
_native_cache = "\\\\?\\" + _path;
result = "\\\\?\\" + _path;
}
}
else {
_native_cache = _path;
result = _path;
}
/*if (has_root_name() && root_name()._path[0] == '/') {
return _path;
}*/
for (auto& c : _native_cache) {
for (auto& c : result) {
if (c == '/') {
c = '\\';
}
}
return result;
}
#else
GHC_INLINE const path::impl_string_type& path::native_impl() const
{
return _path;
}
#endif
GHC_INLINE const path::string_type& path::native() const
{
#ifdef GHC_OS_WINDOWS
#ifdef GHC_USE_WCHAR_T
_native_cache = detail::fromUtf8<string_type>(native_impl());
#else
_native_cache = native_impl();
#endif
return _native_cache;
#else
return _path;
@ -2177,34 +2256,38 @@ GHC_INLINE path::operator path::string_type() const
template <class EcharT, class traits, class Allocator>
inline std::basic_string<EcharT, traits, Allocator> path::string(const Allocator& a) const
{
return detail::fromUtf8<std::basic_string<EcharT, traits, Allocator>>(native(), a);
return detail::fromUtf8<std::basic_string<EcharT, traits, Allocator>>(native_impl(), a);
}
#ifdef GHC_EXPAND_IMPL
GHC_INLINE std::string path::string() const
{
return native();
return native_impl();
}
GHC_INLINE std::wstring path::wstring() const
{
#ifdef GHC_USE_WCHAR_T
return native();
#else
return detail::fromUtf8<std::wstring>(native());
#endif
}
GHC_INLINE std::string path::u8string() const
{
return native();
return native_impl();
}
GHC_INLINE std::u16string path::u16string() const
{
return detail::fromUtf8<std::u16string>(native());
return detail::fromUtf8<std::u16string>(native_impl());
}
GHC_INLINE std::u32string path::u32string() const
{
return detail::fromUtf8<std::u32string>(native());
return detail::fromUtf8<std::u32string>(native_impl());
}
#endif // GHC_EXPAND_IMPL
@ -2278,8 +2361,8 @@ GHC_INLINE path path::root_name() const
}
#endif
if (_path.length() > 2 && _path[0] == '/' && _path[1] == '/' && _path[2] != '/' && std::isprint(_path[2])) {
string_type::size_type pos = _path.find_first_of("/\\", 3);
if (pos == string_type::npos) {
impl_string_type::size_type pos = _path.find_first_of("/\\", 3);
if (pos == impl_string_type::npos) {
return path(_path);
}
else {
@ -2341,10 +2424,10 @@ GHC_INLINE path path::filename() const
GHC_INLINE path path::stem() const
{
string_type fn = filename();
impl_string_type fn = filename().string();
if (fn != "." && fn != "..") {
string_type::size_type n = fn.rfind(".");
if (n != string_type::npos && n != 0) {
impl_string_type::size_type n = fn.rfind(".");
if (n != impl_string_type::npos && n != 0) {
return fn.substr(0, n);
}
}
@ -2353,8 +2436,8 @@ GHC_INLINE path path::stem() const
GHC_INLINE path path::extension() const
{
string_type fn = filename();
string_type::size_type pos = fn.find_last_of('.');
impl_string_type fn = filename().string();
impl_string_type::size_type pos = fn.find_last_of('.');
if (pos == std::string::npos || pos == 0) {
return "";
}
@ -2498,7 +2581,7 @@ GHC_INLINE path path::lexically_proximate(const path& base) const
// 30.10.8.5, iterators
GHC_INLINE path::iterator::iterator() {}
GHC_INLINE path::iterator::iterator(const path::string_type::const_iterator& first, const path::string_type::const_iterator& last, const path::string_type::const_iterator& pos)
GHC_INLINE path::iterator::iterator(const path::impl_string_type::const_iterator& first, const path::impl_string_type::const_iterator& last, const path::impl_string_type::const_iterator& pos)
: _first(first)
, _last(last)
, _iter(pos)
@ -2524,9 +2607,9 @@ GHC_INLINE path::iterator::iterator(const path::string_type::const_iterator& fir
}
}
GHC_INLINE path::string_type::const_iterator path::iterator::increment(const path::string_type::const_iterator& pos) const
GHC_INLINE path::impl_string_type::const_iterator path::iterator::increment(const path::impl_string_type::const_iterator& pos) const
{
std::string::const_iterator i = pos;
path::impl_string_type::const_iterator i = pos;
bool fromStart = i == _first;
if (i != _last) {
// we can only sit on a slash if it is a network name or a root
@ -2557,9 +2640,9 @@ GHC_INLINE path::string_type::const_iterator path::iterator::increment(const pat
return i;
}
GHC_INLINE path::string_type::const_iterator path::iterator::decrement(const path::string_type::const_iterator& pos) const
GHC_INLINE path::impl_string_type::const_iterator path::iterator::decrement(const path::impl_string_type::const_iterator& pos) const
{
std::string::const_iterator i = pos;
path::impl_string_type::const_iterator i = pos;
if (i != _first) {
--i;
// if this is now the root slash or the trailing slash, we are done,
@ -2567,12 +2650,12 @@ GHC_INLINE path::string_type::const_iterator path::iterator::decrement(const pat
if (i != _root && (pos != _last || *i != '/')) {
#ifdef GHC_OS_WINDOWS
static const std::string seps = "/:";
i = std::find_first_of(std::reverse_iterator<std::string::const_iterator>(i), std::reverse_iterator<std::string::const_iterator>(_first), seps.begin(), seps.end()).base();
i = std::find_first_of(std::reverse_iterator<path::impl_string_type::const_iterator>(i), std::reverse_iterator<path::impl_string_type::const_iterator>(_first), seps.begin(), seps.end()).base();
if (i > _first && *i == ':') {
i++;
}
#else
i = std::find(std::reverse_iterator<std::string::const_iterator>(i), std::reverse_iterator<std::string::const_iterator>(_first), '/').base();
i = std::find(std::reverse_iterator<path::impl_string_type::const_iterator>(i), std::reverse_iterator<path::impl_string_type::const_iterator>(_first), '/').base();
#endif
// Now we have to check if this is a network name
if (i - _first == 2 && *_first == '/' && *(_first + 1) == '/') {
@ -3179,7 +3262,7 @@ GHC_INLINE bool create_directories(const path& p, std::error_code& ec) noexcept
{
path current;
ec.clear();
for (const std::string& part : p) {
for (const path::string_type& part : p) {
current /= part;
if (current != p.root_name() && current != p.root_path()) {
std::error_code tec;
@ -3330,7 +3413,7 @@ GHC_INLINE path current_path(std::error_code& ec)
ec.clear();
#ifdef GHC_OS_WINDOWS
DWORD pathlen = ::GetCurrentDirectoryW(0, 0);
std::unique_ptr<wchar_t[]> buffer(new wchar_t[pathlen + 1]);
std::unique_ptr<wchar_t[]> buffer(new wchar_t[size_t(pathlen) + 1]);
if (::GetCurrentDirectoryW(pathlen, buffer.get()) == 0) {
ec = std::error_code(::GetLastError(), std::system_category());
return path();
@ -4532,22 +4615,26 @@ public:
impl(const path& p, directory_options options)
: _base(p)
, _options(options)
, _dirHandle(_base.empty() ? INVALID_HANDLE_VALUE : FindFirstFileW(detail::fromUtf8<std::wstring>((_base / "*").u8string()).c_str(), &_findData))
, _current(_dirHandle != INVALID_HANDLE_VALUE ? _base / std::wstring(_findData.cFileName) : filesystem::path())
, _dirHandle(INVALID_HANDLE_VALUE)
, _findData{0}
{
if (_dirHandle == INVALID_HANDLE_VALUE && !p.empty()) {
auto error = ::GetLastError();
_base = filesystem::path();
if (error != ERROR_ACCESS_DENIED || (options & directory_options::skip_permission_denied) == directory_options::none) {
_ec = std::error_code(::GetLastError(), std::system_category());
}
}
else {
if (std::wstring(_findData.cFileName) == L"." || std::wstring(_findData.cFileName) == L"..") {
increment(_ec);
if (!_base.empty()) {
ZeroMemory(&_findData, sizeof(WIN32_FIND_DATAW));
if ((_dirHandle = FindFirstFileW(detail::fromUtf8<std::wstring>((_base / "*").u8string()).c_str(), &_findData)) != INVALID_HANDLE_VALUE) {
if (std::wstring(_findData.cFileName) == L"." || std::wstring(_findData.cFileName) == L"..") {
increment(_ec);
}
else {
_current = _base / std::wstring(_findData.cFileName);
copyToDirEntry(_ec);
}
}
else {
copyToDirEntry(_ec);
auto error = ::GetLastError();
_base = filesystem::path();
if (error != ERROR_ACCESS_DENIED || (options & directory_options::skip_permission_denied) == directory_options::none) {
_ec = std::error_code(::GetLastError(), std::system_category());
}
}
}
}

View File

@ -386,7 +386,7 @@ TEST_CASE("30.10.8.4.2 path assignments", "[filesystem][path][fs.path.assign]")
REQUIRE(p1 == p3);
p3 = fs::path{"/usr/local"};
REQUIRE(p2 == p3);
#ifdef IS_WCHAR_PATH
#if defined(IS_WCHAR_PATH) || defined(GHC_USE_WCHAR_T)
p3 = fs::path::string_type{L"/foo/bar"};
REQUIRE(p1 == p3);
p3.assign(fs::path::string_type{L"/usr/local"});
@ -508,7 +508,7 @@ TEST_CASE("30.10.8.4.5 path modifiers", "[filesystem][path][fs.path.modifiers]")
TEST_CASE("30.10.8.4.6 path native format observers", "[filesystem][path][fs.path.native.obs]")
{
#ifdef GHC_OS_WINDOWS
#ifdef IS_WCHAR_PATH
#if defined(IS_WCHAR_PATH) || defined(GHC_USE_WCHAR_T)
CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").native() == fs::path::string_type(L"\u00E4\\\u20AC"));
// CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").string() == std::string("ä\\€")); // MSVCs returns local DBCS encoding
#else