summaryrefslogtreecommitdiff
path: root/boost/iostreams/code_converter.hpp
diff options
context:
space:
mode:
authorAnas Nashif <anas.nashif@intel.com>2012-10-30 12:57:26 -0700
committerAnas Nashif <anas.nashif@intel.com>2012-10-30 12:57:26 -0700
commit1a78a62555be32868418fe52f8e330c9d0f95d5a (patch)
treed3765a80e7d3b9640ec2e930743630cd6b9fce2b /boost/iostreams/code_converter.hpp
downloadboost-1a78a62555be32868418fe52f8e330c9d0f95d5a.tar.gz
boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.tar.bz2
boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.zip
Imported Upstream version 1.49.0upstream/1.49.0
Diffstat (limited to 'boost/iostreams/code_converter.hpp')
-rw-r--r--boost/iostreams/code_converter.hpp424
1 files changed, 424 insertions, 0 deletions
diff --git a/boost/iostreams/code_converter.hpp b/boost/iostreams/code_converter.hpp
new file mode 100644
index 0000000000..280a5d0974
--- /dev/null
+++ b/boost/iostreams/code_converter.hpp
@@ -0,0 +1,424 @@
+// (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) && (_MSC_VER >= 1020)
+# 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.
+#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, int buffer_size)
+ {
+ if (flags_ & f_open)
+ boost::throw_exception(BOOST_IOSTREAMS_FAILURE("already open"));
+ if (buffer_size == -1)
+ buffer_size = default_filter_buffer_size;
+ int 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() , int 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() { }
+#if BOOST_WORKAROUND(__GNUC__, < 3)
+ code_converter(code_converter& rhs)
+ : code_converter_base<Device, Codecvt, Alloc>(rhs)
+ { }
+ code_converter(const code_converter& rhs)
+ : code_converter_base<Device, Codecvt, Alloc>(rhs)
+ { }
+#endif
+ 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; // Fall through.
+ 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