123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417 |
- // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
- // (C) Copyright 2003-2007 Jonathan Turkanis
- // Distributed under the Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
- // See http://www.boost.org/libs/iostreams for documentation.
- // Contains machinery for performing code conversion.
- #ifndef BOOST_IOSTREAMS_CODE_CONVERTER_HPP_INCLUDED
- #define BOOST_IOSTREAMS_CODE_CONVERTER_HPP_INCLUDED
- #if defined(_MSC_VER)
- # pragma once
- #endif
- #include <boost/iostreams/detail/config/wide_streams.hpp>
- #if defined(BOOST_IOSTREAMS_NO_WIDE_STREAMS) || \
- defined(BOOST_IOSTREAMS_NO_LOCALE) \
- /**/
- # error code conversion not supported on this platform
- #endif
- #include <algorithm> // max.
- #include <cstring> // memcpy.
- #include <exception>
- #include <boost/config.hpp> // DEDUCED_TYPENAME,
- #include <boost/iostreams/char_traits.hpp>
- #include <boost/iostreams/constants.hpp> // default_filter_buffer_size.
- #include <boost/iostreams/detail/adapter/concept_adapter.hpp>
- #include <boost/iostreams/detail/adapter/direct_adapter.hpp>
- #include <boost/iostreams/detail/buffer.hpp>
- #include <boost/iostreams/detail/call_traits.hpp>
- #include <boost/iostreams/detail/codecvt_holder.hpp>
- #include <boost/iostreams/detail/codecvt_helper.hpp>
- #include <boost/iostreams/detail/double_object.hpp>
- #include <boost/iostreams/detail/execute.hpp>
- #include <boost/iostreams/detail/forward.hpp>
- #include <boost/iostreams/detail/functional.hpp>
- #include <boost/iostreams/detail/ios.hpp> // failure, openmode, int types, streamsize.
- #include <boost/iostreams/detail/optional.hpp>
- #include <boost/iostreams/detail/select.hpp>
- #include <boost/iostreams/traits.hpp>
- #include <boost/iostreams/operations.hpp>
- #include <boost/shared_ptr.hpp>
- #include <boost/static_assert.hpp>
- #include <boost/throw_exception.hpp>
- #include <boost/type_traits/is_convertible.hpp>
- #include <boost/type_traits/is_same.hpp>
- // Must come last.
- #include <boost/iostreams/detail/config/disable_warnings.hpp> // Borland 5.x
- namespace boost { namespace iostreams {
- struct code_conversion_error : BOOST_IOSTREAMS_FAILURE {
- code_conversion_error()
- : BOOST_IOSTREAMS_FAILURE("code conversion error")
- { }
- };
- namespace detail {
- //--------------Definition of strncpy_if_same---------------------------------//
- // Helper template for strncpy_if_same, below.
- template<bool B>
- struct strncpy_if_same_impl;
- template<>
- struct strncpy_if_same_impl<true> {
- template<typename Ch>
- static Ch* copy(Ch* tgt, const Ch* src, std::streamsize n)
- { return BOOST_IOSTREAMS_CHAR_TRAITS(Ch)::copy(tgt, src, n); }
- };
- template<>
- struct strncpy_if_same_impl<false> {
- template<typename Src, typename Tgt>
- static Tgt* copy(Tgt* tgt, const Src*, std::streamsize) { return tgt; }
- };
- template<typename Src, typename Tgt>
- Tgt* strncpy_if_same(Tgt* tgt, const Src* src, std::streamsize n)
- {
- typedef strncpy_if_same_impl<is_same<Src, Tgt>::value> impl;
- return impl::copy(tgt, src, n);
- }
- //--------------Definition of conversion_buffer-------------------------------//
- // Buffer and conversion state for reading.
- template<typename Codecvt, typename Alloc>
- class conversion_buffer
- : public buffer<
- BOOST_DEDUCED_TYPENAME detail::codecvt_extern<Codecvt>::type,
- Alloc
- >
- {
- public:
- typedef typename Codecvt::state_type state_type;
- conversion_buffer()
- : buffer<
- BOOST_DEDUCED_TYPENAME detail::codecvt_extern<Codecvt>::type,
- Alloc
- >(0)
- {
- reset();
- }
- state_type& state() { return state_; }
- void reset()
- {
- if (this->size())
- this->set(0, 0);
- state_ = state_type();
- }
- private:
- state_type state_;
- };
- //--------------Definition of converter_impl----------------------------------//
- // Contains member data, open/is_open/close and buffer management functions.
- template<typename Device, typename Codecvt, typename Alloc>
- struct code_converter_impl {
- typedef typename codecvt_extern<Codecvt>::type extern_type;
- typedef typename category_of<Device>::type device_category;
- typedef is_convertible<device_category, input> can_read;
- typedef is_convertible<device_category, output> can_write;
- typedef is_convertible<device_category, bidirectional> is_bidir;
- typedef typename
- iostreams::select< // Disambiguation for Tru64.
- is_bidir, bidirectional,
- can_read, input,
- can_write, output
- >::type mode;
- typedef typename
- mpl::if_<
- is_direct<Device>,
- direct_adapter<Device>,
- Device
- >::type device_type;
- typedef optional< concept_adapter<device_type> > storage_type;
- typedef is_convertible<device_category, two_sequence> is_double;
- typedef conversion_buffer<Codecvt, Alloc> buffer_type;
- code_converter_impl() : cvt_(), flags_(0) { }
- ~code_converter_impl()
- {
- try {
- if (flags_ & f_open) close();
- } catch (...) { /* */ }
- }
- template <class T>
- void open(const T& dev, std::streamsize buffer_size)
- {
- if (flags_ & f_open)
- boost::throw_exception(BOOST_IOSTREAMS_FAILURE("already open"));
- if (buffer_size == -1)
- buffer_size = default_filter_buffer_size;
- std::streamsize max_length = cvt_.get().max_length();
- buffer_size = (std::max)(buffer_size, 2 * max_length);
- if (can_read::value) {
- buf_.first().resize(buffer_size);
- buf_.first().set(0, 0);
- }
- if (can_write::value && !is_double::value) {
- buf_.second().resize(buffer_size);
- buf_.second().set(0, 0);
- }
- dev_.reset(concept_adapter<device_type>(dev));
- flags_ = f_open;
- }
- void close()
- {
- detail::execute_all(
- detail::call_member_close(*this, BOOST_IOS::in),
- detail::call_member_close(*this, BOOST_IOS::out)
- );
- }
- void close(BOOST_IOS::openmode which)
- {
- if (which == BOOST_IOS::in && (flags_ & f_input_closed) == 0) {
- flags_ |= f_input_closed;
- iostreams::close(dev(), BOOST_IOS::in);
- }
- if (which == BOOST_IOS::out && (flags_ & f_output_closed) == 0) {
- flags_ |= f_output_closed;
- detail::execute_all(
- detail::flush_buffer(buf_.second(), dev(), can_write::value),
- detail::call_close(dev(), BOOST_IOS::out),
- detail::call_reset(dev_),
- detail::call_reset(buf_.first()),
- detail::call_reset(buf_.second())
- );
- }
- }
- bool is_open() const { return (flags_ & f_open) != 0;}
- device_type& dev() { return **dev_; }
- enum flag_type {
- f_open = 1,
- f_input_closed = f_open << 1,
- f_output_closed = f_input_closed << 1
- };
- codecvt_holder<Codecvt> cvt_;
- storage_type dev_;
- double_object<
- buffer_type,
- is_double
- > buf_;
- int flags_;
- };
- } // End namespace detail.
- //--------------Definition of converter---------------------------------------//
- #define BOOST_IOSTREAMS_CONVERTER_PARAMS() , std::streamsize buffer_size = -1
- #define BOOST_IOSTREAMS_CONVERTER_ARGS() , buffer_size
- template<typename Device, typename Codecvt, typename Alloc>
- struct code_converter_base {
- typedef detail::code_converter_impl<
- Device, Codecvt, Alloc
- > impl_type;
- code_converter_base() : pimpl_(new impl_type) { }
- shared_ptr<impl_type> pimpl_;
- };
- template< typename Device,
- typename Codecvt = detail::default_codecvt,
- typename Alloc = std::allocator<char> >
- class code_converter
- : protected code_converter_base<Device, Codecvt, Alloc>
- {
- private:
- typedef detail::code_converter_impl<
- Device, Codecvt, Alloc
- > impl_type;
- typedef typename impl_type::device_type device_type;
- typedef typename impl_type::buffer_type buffer_type;
- typedef typename detail::codecvt_holder<Codecvt>::codecvt_type codecvt_type;
- typedef typename detail::codecvt_intern<Codecvt>::type intern_type;
- typedef typename detail::codecvt_extern<Codecvt>::type extern_type;
- typedef typename detail::codecvt_state<Codecvt>::type state_type;
- public:
- typedef intern_type char_type;
- struct category
- : impl_type::mode, device_tag, closable_tag, localizable_tag
- { };
- BOOST_STATIC_ASSERT((
- is_same<
- extern_type,
- BOOST_DEDUCED_TYPENAME char_type_of<Device>::type
- >::value
- ));
- public:
- code_converter() { }
- BOOST_IOSTREAMS_FORWARD( code_converter, open_impl, Device,
- BOOST_IOSTREAMS_CONVERTER_PARAMS,
- BOOST_IOSTREAMS_CONVERTER_ARGS )
- // fstream-like interface.
- bool is_open() const { return this->pimpl_->is_open(); }
- void close(BOOST_IOS::openmode which = BOOST_IOS::in | BOOST_IOS::out )
- { impl().close(which); }
- // Device interface.
- std::streamsize read(char_type*, std::streamsize);
- std::streamsize write(const char_type*, std::streamsize);
- void imbue(const std::locale& loc) { impl().cvt_.imbue(loc); }
- // Direct device access.
- Device& operator*() { return detail::unwrap_direct(dev()); }
- Device* operator->() { return &detail::unwrap_direct(dev()); }
- private:
- template<typename T> // Used for forwarding.
- void open_impl(const T& t BOOST_IOSTREAMS_CONVERTER_PARAMS())
- {
- impl().open(t BOOST_IOSTREAMS_CONVERTER_ARGS());
- }
- const codecvt_type& cvt() { return impl().cvt_.get(); }
- device_type& dev() { return impl().dev(); }
- buffer_type& in() { return impl().buf_.first(); }
- buffer_type& out() { return impl().buf_.second(); }
- impl_type& impl() { return *this->pimpl_; }
- };
- //--------------Implementation of converter-----------------------------------//
- // Implementation note: if end of stream contains a partial character,
- // it is ignored.
- template<typename Device, typename Codevt, typename Alloc>
- std::streamsize code_converter<Device, Codevt, Alloc>::read
- (char_type* s, std::streamsize n)
- {
- const extern_type* next; // Next external char.
- intern_type* nint; // Next internal char.
- std::streamsize total = 0; // Characters read.
- int status = iostreams::char_traits<char>::good();
- bool partial = false;
- buffer_type& buf = in();
- do {
- // Fill buffer.
- if (buf.ptr() == buf.eptr() || partial) {
- status = buf.fill(dev());
- if (buf.ptr() == buf.eptr())
- break;
- partial = false;
- }
- // Convert.
- std::codecvt_base::result result =
- cvt().in( buf.state(),
- buf.ptr(), buf.eptr(), next,
- s + total, s + n, nint );
- buf.ptr() += next - buf.ptr();
- total = static_cast<std::streamsize>(nint - s);
- switch (result) {
- case std::codecvt_base::partial:
- partial = true;
- break;
- case std::codecvt_base::ok:
- break;
- case std::codecvt_base::noconv:
- {
- std::streamsize amt =
- std::min<std::streamsize>(next - buf.ptr(), n - total);
- detail::strncpy_if_same(s + total, buf.ptr(), amt);
- total += amt;
- }
- break;
- case std::codecvt_base::error:
- default:
- buf.state() = state_type();
- boost::throw_exception(code_conversion_error());
- }
- } while (total < n && status != EOF && status != WOULD_BLOCK);
- return total == 0 && status == EOF ? -1 : total;
- }
- template<typename Device, typename Codevt, typename Alloc>
- std::streamsize code_converter<Device, Codevt, Alloc>::write
- (const char_type* s, std::streamsize n)
- {
- buffer_type& buf = out();
- extern_type* next; // Next external char.
- const intern_type* nint; // Next internal char.
- std::streamsize total = 0; // Characters written.
- bool partial = false;
- while (total < n) {
- // Empty buffer.
- if (buf.eptr() == buf.end() || partial) {
- if (!buf.flush(dev()))
- break;
- partial = false;
- }
-
- // Convert.
- std::codecvt_base::result result =
- cvt().out( buf.state(),
- s + total, s + n, nint,
- buf.eptr(), buf.end(), next );
- int progress = (int) (next - buf.eptr());
- buf.eptr() += progress;
- switch (result) {
- case std::codecvt_base::partial:
- partial = true;
- BOOST_FALLTHROUGH;
- case std::codecvt_base::ok:
- total = static_cast<std::streamsize>(nint - s);
- break;
- case std::codecvt_base::noconv:
- {
- std::streamsize amt =
- std::min<std::streamsize>( nint - total - s,
- buf.end() - buf.eptr() );
- detail::strncpy_if_same(buf.eptr(), s + total, amt);
- total += amt;
- }
- break;
- case std::codecvt_base::error:
- default:
- buf.state() = state_type();
- boost::throw_exception(code_conversion_error());
- }
- }
- return total;
- }
- //----------------------------------------------------------------------------//
- } } // End namespaces iostreams, boost.
- #include <boost/iostreams/detail/config/enable_warnings.hpp> // Borland 5.x
- #endif // #ifndef BOOST_IOSTREAMS_CODE_CONVERTER_HPP_INCLUDED
|