diff --git a/include/boost/filesystem/config.hpp b/include/boost/filesystem/config.hpp index f0f238b..b1f6502 100644 --- a/include/boost/filesystem/config.hpp +++ b/include/boost/filesystem/config.hpp @@ -38,12 +38,22 @@ #include // for BOOST_POSIX_API or BOOST_WINDOWS_API #include -// BOOST_FILESYSTEM_DEPRECATED needed for source compiles -----------------------------// +// BOOST_FILESYSTEM_DEPRECATED needed for source compiles # ifdef BOOST_FILESYSTEM_SOURCE # define BOOST_FILESYSTEM_DEPRECATED # endif +// Support for C++11 char16_t and char32_t paths requires both character type (or +// equivalent typedef) support and header support. + +# if BOOST_FILESYSTEM_VERSION > 3 \ + && !defined(BOOST_NO_CXX11_HDR_CODECVT) \ + && ((!defined(BOOST_NO_CXX11_CHAR16_T) && (!defined(BOOST_NO_CXX11_CHAR32_T)) \ + || (defined(_MSC_VER) && _MSC_VER >= 1600))) +# define BOOST_FILESYSTEM_CHAR16_CHAR32 +#endif + // throw an exception ----------------------------------------------------------------// // // Exceptions were originally thrown via boost::throw_exception(). diff --git a/include/boost/filesystem/config_info.hpp b/include/boost/filesystem/config_info.hpp index a4fc8d9..880b2ea 100644 --- a/include/boost/filesystem/config_info.hpp +++ b/include/boost/filesystem/config_info.hpp @@ -75,6 +75,7 @@ namespace boost << BOOST_FILESYSTEM_SHOW_MACRO(BOOST_FILESYSTEM_NO_DEPRECATED) << '\n' << BOOST_FILESYSTEM_SHOW_MACRO(BOOST_FILESYSTEM_DECL) << '\n' << BOOST_FILESYSTEM_SHOW_MACRO(BOOST_SYMBOL_VISIBLE) << '\n' + << BOOST_FILESYSTEM_SHOW_MACRO(BOOST_FILESYSTEM_CHAR16_CHAR32) << '\n' << BOOST_FILESYSTEM_SHOW_MACRO(BOOST_FILESYSTEM_OPERATIONS_TEST_TEMP) << '\n' ; return os; diff --git a/include/boost/filesystem/path_traits.hpp b/include/boost/filesystem/path_traits.hpp index d868311..24fe25f 100644 --- a/include/boost/filesystem/path_traits.hpp +++ b/include/boost/filesystem/path_traits.hpp @@ -124,6 +124,40 @@ namespace boost { namespace BOOST_FILESYSTEM_NAMESPACE { convert(from, 0, to, cvt); } +# ifdef BOOST_FILESYSTEM_CHAR16_CHAR32 + + BOOST_FILESYSTEM_DECL + void convert(const char32_t* from, + const char32_t* from_end, // 0 for null terminated MBCS + std::wstring & to, + const codecvt_type&); + + //BOOST_FILESYSTEM_DECL + // void convert(const char32_t* from, + // const char32_t* from_end, // 0 for null terminated MBCS + // std::string & to, + // const codecvt_type& cvt); + + //inline + // void convert(const char32_t* from, + // std::wstring & to, + // const codecvt_type& cvt) + //{ + // BOOST_ASSERT(from); + // convert(from, 0, to, cvt); + //} + + //inline + // void convert(const wchar_t* from, + // std::string & to, + // const codecvt_type& cvt) + //{ + // BOOST_ASSERT(from); + // convert(from, 0, to, cvt); + //} + +# endif + // value types same -----------------------------------------------------------------// // char diff --git a/src/path_traits.cpp b/src/path_traits.cpp index a907cda..eb5b1cc 100644 --- a/src/path_traits.cpp +++ b/src/path_traits.cpp @@ -25,6 +25,10 @@ #include // for strlen #include // for wcslen +#ifdef BOOST_FILESYSTEM_CHAR16_CHAR32 +# include +#endif + namespace pt = boost::filesystem::path_traits; namespace fs = boost::filesystem; namespace bs = boost::system; @@ -93,6 +97,46 @@ namespace { target.append(to, to_next); } +#ifdef BOOST_FILESYSTEM_CHAR16_CHAR32 + + //--------------------------------------------------------------------------------------// + // convert_aux const char32_t* to wstring // + //--------------------------------------------------------------------------------------// + + static void convert_aux( + const char32_t* from, + const char32_t* from_end, + wchar_t* to, wchar_t* to_end, + std::wstring& target) + { + //std::cout << std::hex + // << " from=" << std::size_t(from) + // << " from_end=" << std::size_t(from_end) + // << " to=" << std::size_t(to) + // << " to_end=" << std::size_t(to_end) + // << std::endl; + + typedef std::codecvt_utf16 codecvt_type; + static codecvt_type cvt; + + std::mbstate_t state = std::mbstate_t(); // perhaps unneeded, but cuts bug reports + const char32_t* from_next; + wchar_t* to_next; + + std::codecvt_base::result res; + + if ((res = cvt.in(state, from, from_end, from_next, + to, to_end, to_next)) != std::codecvt_base::ok) + { + //std::cout << " result is " << static_cast(res) << std::endl; + BOOST_FILESYSTEM_THROW(bs::system_error(res, fs::codecvt_error_category(), + "boost::filesystem::path codecvt to wstring")); + } + target.append(to, to_next); + } + +#endif + //--------------------------------------------------------------------------------------// // convert_aux const wchar_t* to string // //--------------------------------------------------------------------------------------// @@ -207,4 +251,47 @@ namespace boost { namespace BOOST_FILESYSTEM_NAMESPACE { namespace path_traits { convert_aux(from, from_end, buf, buf+default_codecvt_buf_size, to, cvt); } } + +#ifdef BOOST_FILESYSTEM_CHAR16_CHAR32 + +# ifdef BOOST_WINDOWS_API + + //--------------------------------------------------------------------------------------// + // convert const char32_t* to wstring // + //--------------------------------------------------------------------------------------// + + BOOST_FILESYSTEM_DECL + void convert(const char32_t* from, + const char32_t* from_end, // 0 for null terminated MBCS + std::wstring& to, + const codecvt_type&) + { + BOOST_ASSERT(from); + + if (!from_end) // null terminated + { + for (from_end = from; *from_end; ++from_end); // find end + } + + if (from == from_end) + return; + + std::size_t buf_size = (from_end - from) * 2*4; // perhaps too large, but that's OK + + // dynamically allocate a buffer only if source is unusually large + if (buf_size > default_codecvt_buf_size) + { + boost::scoped_array< wchar_t > buf(new wchar_t[buf_size]); + convert_aux(from, from_end, buf.get(), buf.get()+buf_size, to); + } + else + { + wchar_t buf[default_codecvt_buf_size]; + convert_aux(from, from_end, buf, buf+default_codecvt_buf_size, to); + } + } +# endif + +#endif + }}} // namespace boost::filesystem::path_traits diff --git a/test/issues/hello_filesystem.cpp b/test/issues/hello_filesystem.cpp index 8aa1a6c..e6b73f8 100644 --- a/test/issues/hello_filesystem.cpp +++ b/test/issues/hello_filesystem.cpp @@ -22,14 +22,39 @@ #include #include +#include + using std::cout; using std::endl; namespace fs = boost::filesystem; +using boost::basic_string_ref; +using boost::string_ref; +using boost::wstring_ref; + +void f1(const string_ref&) +{ + cout << "narrow" << endl; +} +void f1(const wstring_ref&) +{ + cout << "wide" << endl; +} + +template +void foo(const T& from) +{ + f1(basic_string_ref(from)); +} //------------------------------------ cpp_main --------------------------------------// int cpp_main(int argc, char* argv[]) { + foo(std::string("string")); + //foo(std::string("string")); + //foo>("string"); + + cout << "Hello, filesystem world" << endl; cout << fs::config() << endl; diff --git a/test/msvc/header_inclusion/header_inclusion.vcxproj b/test/msvc/header_inclusion/header_inclusion.vcxproj index 90d04f4..9a87664 100644 --- a/test/msvc/header_inclusion/header_inclusion.vcxproj +++ b/test/msvc/header_inclusion/header_inclusion.vcxproj @@ -65,12 +65,12 @@ + - diff --git a/test/path_unit_test.cpp b/test/path_unit_test.cpp index 68770ba..1229738 100644 --- a/test/path_unit_test.cpp +++ b/test/path_unit_test.cpp @@ -63,6 +63,12 @@ using std::endl; using std::string; using std::wstring; +#ifdef BOOST_FILESYSTEM_CHAR16_CHAR32 +using std::u16string; +using std::u32string; +#endif + + #define CHECK(x) check(x, __FILE__, __LINE__) #define PATH_IS(a, b) check_path(a, b, __FILE__, __LINE__) #define NATIVE_IS(p, s, ws) check_native(p, s, ws, __FILE__, __LINE__) @@ -160,6 +166,14 @@ namespace boost::container::vector wbv; // see main() for initialization to w, f, u, z #endif +#ifdef BOOST_FILESYSTEM_CHAR16_CHAR32 + const char16_t u16a[] = {'u', '1', '6', 's', 't', 'r', 'i', 'n', 'g', '\0'}; + const char32_t u32a[] = {'u', '3', '2', 's', 't', 'r', 'i', 'n', 'g', '\0'}; + u16string u16s(u16a); + u32string u32s(u32a); + +#endif + class Base {}; class Derived : public Base {}; void fun(const boost::shared_ptr< Base >&) {} @@ -301,6 +315,25 @@ namespace BOOST_TEST_EQ(x19.native().size(), 7U); #endif +#ifdef BOOST_FILESYSTEM_CHAR16_CHAR32 + + { + path x1(u32a); + PATH_IS(x1, L"u32string"); + BOOST_TEST_EQ(x1.native().size(), 9U); + + path x2(u32s); + PATH_IS(x2, L"u32string"); + BOOST_TEST_EQ(x2.native().size(), 9U); + + path x3(&u32a[0], &u32a[8]); + PATH_IS(x3, L"u32string"); + BOOST_TEST_EQ(x3.native().size(), 9U); + } + +#endif + + // easy-to-make coding errors // path e1(x0, path::codecvt()); // fails to compile, and that is OK