blob: 66064370bc231c56995c87d093a1c6baedb22f42 [file] [log] [blame]
// filesystem path_traits.cpp --------------------------------------------------------//
// Copyright Beman Dawes 2008, 2009
// Distributed under the Boost Software License, Version 1.0.
// See http://www.boost.org/LICENSE_1_0.txt
// Library home page: http://www.boost.org/libs/filesystem
//--------------------------------------------------------------------------------------//
#include <boost/config.hpp>
#if !defined( BOOST_NO_STD_WSTRING )
// Boost.Filesystem V3 and later requires std::wstring support.
// During the transition to V3, libraries are compiled with both V2 and V3 sources.
// On old compilers that don't support V3 anyhow, we just skip everything so the compile
// will succeed and the library can be built.
// define BOOST_FILESYSTEM_SOURCE so that <boost/system/config.hpp> knows
// the library is being built (possibly exporting rather than importing code)
#define BOOST_FILESYSTEM_SOURCE
#ifndef BOOST_SYSTEM_NO_DEPRECATED
# define BOOST_SYSTEM_NO_DEPRECATED
#endif
#include <boost/filesystem/v3/config.hpp>
#include <boost/filesystem/v3/path_traits.hpp>
#include <boost/system/system_error.hpp>
#include <boost/scoped_array.hpp>
#include <locale> // for codecvt_base::result
#include <cstring> // for strlen
#include <cwchar> // for wcslen
namespace pt = boost::filesystem3::path_traits;
namespace fs = boost::filesystem3;
namespace bs = boost::system;
//--------------------------------------------------------------------------------------//
// configuration //
//--------------------------------------------------------------------------------------//
#ifndef BOOST_FILESYSTEM_CODECVT_BUF_SIZE
# define BOOST_FILESYSTEM_CODECVT_BUF_SIZE 256
#endif
namespace {
const std::size_t default_codecvt_buf_size = BOOST_FILESYSTEM_CODECVT_BUF_SIZE;
//--------------------------------------------------------------------------------------//
// //
// The public convert() functions do buffer management, and then forward to the //
// convert_aux() functions for the actual call to the codecvt facet. //
// //
//--------------------------------------------------------------------------------------//
//--------------------------------------------------------------------------------------//
// convert_aux const char* to wstring //
//--------------------------------------------------------------------------------------//
void convert_aux(
const char* from,
const char* from_end,
wchar_t* to, wchar_t* to_end,
std::wstring & target,
const pt::codecvt_type & cvt)
{
//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;
std::mbstate_t state = std::mbstate_t(); // perhaps unneeded, but cuts bug reports
const char* 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<int>(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);
}
//--------------------------------------------------------------------------------------//
// convert_aux const wchar_t* to string //
//--------------------------------------------------------------------------------------//
void convert_aux(
const wchar_t* from,
const wchar_t* from_end,
char* to, char* to_end,
std::string & target,
const pt::codecvt_type & cvt)
{
//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;
std::mbstate_t state = std::mbstate_t(); // perhaps unneeded, but cuts bug reports
const wchar_t* from_next;
char* to_next;
std::codecvt_base::result res;
if ((res=cvt.out(state, from, from_end, from_next,
to, to_end, to_next)) != std::codecvt_base::ok)
{
//std::cout << " result is " << static_cast<int>(res) << std::endl;
BOOST_FILESYSTEM_THROW(bs::system_error(res, fs::codecvt_error_category(),
"boost::filesystem::path codecvt to string"));
}
target.append(to, to_next);
}
} // unnamed namespace
//--------------------------------------------------------------------------------------//
// path_traits //
//--------------------------------------------------------------------------------------//
namespace boost { namespace filesystem3 { namespace path_traits {
//--------------------------------------------------------------------------------------//
// convert const char* to wstring //
//--------------------------------------------------------------------------------------//
BOOST_FILESYSTEM_DECL
void convert(const char* from,
const char* from_end, // 0 for null terminated MBCS
std::wstring & to,
const codecvt_type & cvt)
{
BOOST_ASSERT(from);
if (!from_end) // null terminated
{
from_end = from + std::strlen(from);
}
if (from == from_end) return;
std::size_t buf_size = (from_end - from) * 3; // 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, cvt);
}
else
{
wchar_t buf[default_codecvt_buf_size];
convert_aux(from, from_end, buf, buf+default_codecvt_buf_size, to, cvt);
}
}
//--------------------------------------------------------------------------------------//
// convert const wchar_t* to string //
//--------------------------------------------------------------------------------------//
BOOST_FILESYSTEM_DECL
void convert(const wchar_t* from,
const wchar_t* from_end, // 0 for null terminated MBCS
std::string & to,
const codecvt_type & cvt)
{
BOOST_ASSERT(from);
if (!from_end) // null terminated
{
from_end = from + std::wcslen(from);
}
if (from == from_end) return;
// The codecvt length functions may not be implemented, and I don't really
// understand them either. Thus this code is just a guess; if it turns
// out the buffer is too small then an error will be reported and the code
// will have to be fixed.
std::size_t buf_size = (from_end - from) * 4; // perhaps too large, but that's OK
buf_size += 4; // encodings like shift-JIS need some prefix space
// dynamically allocate a buffer only if source is unusually large
if (buf_size > default_codecvt_buf_size)
{
boost::scoped_array< char > buf(new char [buf_size]);
convert_aux(from, from_end, buf.get(), buf.get()+buf_size, to, cvt);
}
else
{
char buf[default_codecvt_buf_size];
convert_aux(from, from_end, buf, buf+default_codecvt_buf_size, to, cvt);
}
}
}}} // namespace boost::filesystem3::path_traits
#endif // no wide character support