File indexing completed on 2025-01-18 09:38:53
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef BOOST_IOSTREAMS_CODE_CONVERTER_HPP_INCLUDED
0011 #define BOOST_IOSTREAMS_CODE_CONVERTER_HPP_INCLUDED
0012
0013 #if defined(_MSC_VER)
0014 # pragma once
0015 #endif
0016
0017 #include <boost/iostreams/detail/config/wide_streams.hpp>
0018 #if defined(BOOST_IOSTREAMS_NO_WIDE_STREAMS) || \
0019 defined(BOOST_IOSTREAMS_NO_LOCALE) \
0020
0021 # error code conversion not supported on this platform
0022 #endif
0023
0024 #include <algorithm> // max.
0025 #include <cstring> // memcpy.
0026 #include <exception>
0027 #include <boost/config.hpp> // DEDUCED_TYPENAME,
0028 #include <boost/iostreams/char_traits.hpp>
0029 #include <boost/iostreams/constants.hpp> // default_filter_buffer_size.
0030 #include <boost/iostreams/detail/adapter/concept_adapter.hpp>
0031 #include <boost/iostreams/detail/adapter/direct_adapter.hpp>
0032 #include <boost/iostreams/detail/buffer.hpp>
0033 #include <boost/iostreams/detail/call_traits.hpp>
0034 #include <boost/iostreams/detail/codecvt_holder.hpp>
0035 #include <boost/iostreams/detail/codecvt_helper.hpp>
0036 #include <boost/iostreams/detail/double_object.hpp>
0037 #include <boost/iostreams/detail/execute.hpp>
0038 #include <boost/iostreams/detail/forward.hpp>
0039 #include <boost/iostreams/detail/functional.hpp>
0040 #include <boost/iostreams/detail/ios.hpp> // failure, openmode, int types, streamsize.
0041 #include <boost/iostreams/detail/optional.hpp>
0042 #include <boost/iostreams/detail/select.hpp>
0043 #include <boost/iostreams/traits.hpp>
0044 #include <boost/iostreams/operations.hpp>
0045 #include <boost/shared_ptr.hpp>
0046 #include <boost/static_assert.hpp>
0047 #include <boost/throw_exception.hpp>
0048 #include <boost/type_traits/is_convertible.hpp>
0049 #include <boost/type_traits/is_same.hpp>
0050
0051
0052 #include <boost/iostreams/detail/config/disable_warnings.hpp> // Borland 5.x
0053
0054 namespace boost { namespace iostreams {
0055
0056 struct code_conversion_error : BOOST_IOSTREAMS_FAILURE {
0057 code_conversion_error()
0058 : BOOST_IOSTREAMS_FAILURE("code conversion error")
0059 { }
0060 };
0061
0062 namespace detail {
0063
0064
0065
0066
0067 template<bool B>
0068 struct strncpy_if_same_impl;
0069
0070 template<>
0071 struct strncpy_if_same_impl<true> {
0072 template<typename Ch>
0073 static Ch* copy(Ch* tgt, const Ch* src, std::streamsize n)
0074 { return BOOST_IOSTREAMS_CHAR_TRAITS(Ch)::copy(tgt, src, n); }
0075 };
0076
0077 template<>
0078 struct strncpy_if_same_impl<false> {
0079 template<typename Src, typename Tgt>
0080 static Tgt* copy(Tgt* tgt, const Src*, std::streamsize) { return tgt; }
0081 };
0082
0083 template<typename Src, typename Tgt>
0084 Tgt* strncpy_if_same(Tgt* tgt, const Src* src, std::streamsize n)
0085 {
0086 typedef strncpy_if_same_impl<is_same<Src, Tgt>::value> impl;
0087 return impl::copy(tgt, src, n);
0088 }
0089
0090
0091
0092
0093 template<typename Codecvt, typename Alloc>
0094 class conversion_buffer
0095 : public buffer<
0096 BOOST_DEDUCED_TYPENAME detail::codecvt_extern<Codecvt>::type,
0097 Alloc
0098 >
0099 {
0100 public:
0101 typedef typename Codecvt::state_type state_type;
0102 conversion_buffer()
0103 : buffer<
0104 BOOST_DEDUCED_TYPENAME detail::codecvt_extern<Codecvt>::type,
0105 Alloc
0106 >(0)
0107 {
0108 reset();
0109 }
0110 state_type& state() { return state_; }
0111 void reset()
0112 {
0113 if (this->size())
0114 this->set(0, 0);
0115 state_ = state_type();
0116 }
0117 private:
0118 state_type state_;
0119 };
0120
0121
0122
0123
0124 template<typename Device, typename Codecvt, typename Alloc>
0125 struct code_converter_impl {
0126 typedef typename codecvt_extern<Codecvt>::type extern_type;
0127 typedef typename category_of<Device>::type device_category;
0128 typedef is_convertible<device_category, input> can_read;
0129 typedef is_convertible<device_category, output> can_write;
0130 typedef is_convertible<device_category, bidirectional> is_bidir;
0131 typedef typename
0132 iostreams::select<
0133 is_bidir, bidirectional,
0134 can_read, input,
0135 can_write, output
0136 >::type mode;
0137 typedef typename
0138 mpl::if_<
0139 is_direct<Device>,
0140 direct_adapter<Device>,
0141 Device
0142 >::type device_type;
0143 typedef optional< concept_adapter<device_type> > storage_type;
0144 typedef is_convertible<device_category, two_sequence> is_double;
0145 typedef conversion_buffer<Codecvt, Alloc> buffer_type;
0146
0147 code_converter_impl() : cvt_(), flags_(0) { }
0148
0149 ~code_converter_impl()
0150 {
0151 try {
0152 if (flags_ & f_open) close();
0153 } catch (...) { }
0154 }
0155
0156 template <class T>
0157 void open(const T& dev, std::streamsize buffer_size)
0158 {
0159 if (flags_ & f_open)
0160 boost::throw_exception(BOOST_IOSTREAMS_FAILURE("already open"));
0161 if (buffer_size == -1)
0162 buffer_size = default_filter_buffer_size;
0163 std::streamsize max_length = cvt_.get().max_length();
0164 buffer_size = (std::max)(buffer_size, 2 * max_length);
0165 if (can_read::value) {
0166 buf_.first().resize(buffer_size);
0167 buf_.first().set(0, 0);
0168 }
0169 if (can_write::value && !is_double::value) {
0170 buf_.second().resize(buffer_size);
0171 buf_.second().set(0, 0);
0172 }
0173 dev_.reset(concept_adapter<device_type>(dev));
0174 flags_ = f_open;
0175 }
0176
0177 void close()
0178 {
0179 detail::execute_all(
0180 detail::call_member_close(*this, BOOST_IOS::in),
0181 detail::call_member_close(*this, BOOST_IOS::out)
0182 );
0183 }
0184
0185 void close(BOOST_IOS::openmode which)
0186 {
0187 if (which == BOOST_IOS::in && (flags_ & f_input_closed) == 0) {
0188 flags_ |= f_input_closed;
0189 iostreams::close(dev(), BOOST_IOS::in);
0190 }
0191 if (which == BOOST_IOS::out && (flags_ & f_output_closed) == 0) {
0192 flags_ |= f_output_closed;
0193 detail::execute_all(
0194 detail::flush_buffer(buf_.second(), dev(), can_write::value),
0195 detail::call_close(dev(), BOOST_IOS::out),
0196 detail::call_reset(dev_),
0197 detail::call_reset(buf_.first()),
0198 detail::call_reset(buf_.second())
0199 );
0200 }
0201 }
0202
0203 bool is_open() const { return (flags_ & f_open) != 0;}
0204
0205 device_type& dev() { return **dev_; }
0206
0207 enum flag_type {
0208 f_open = 1,
0209 f_input_closed = f_open << 1,
0210 f_output_closed = f_input_closed << 1
0211 };
0212
0213 codecvt_holder<Codecvt> cvt_;
0214 storage_type dev_;
0215 double_object<
0216 buffer_type,
0217 is_double
0218 > buf_;
0219 int flags_;
0220 };
0221
0222 }
0223
0224
0225
0226 #define BOOST_IOSTREAMS_CONVERTER_PARAMS() , std::streamsize buffer_size = -1
0227 #define BOOST_IOSTREAMS_CONVERTER_ARGS() , buffer_size
0228
0229 template<typename Device, typename Codecvt, typename Alloc>
0230 struct code_converter_base {
0231 typedef detail::code_converter_impl<
0232 Device, Codecvt, Alloc
0233 > impl_type;
0234 code_converter_base() : pimpl_(new impl_type) { }
0235 shared_ptr<impl_type> pimpl_;
0236 };
0237
0238 template< typename Device,
0239 typename Codecvt = detail::default_codecvt,
0240 typename Alloc = std::allocator<char> >
0241 class code_converter
0242 : protected code_converter_base<Device, Codecvt, Alloc>
0243 {
0244 private:
0245 typedef detail::code_converter_impl<
0246 Device, Codecvt, Alloc
0247 > impl_type;
0248 typedef typename impl_type::device_type device_type;
0249 typedef typename impl_type::buffer_type buffer_type;
0250 typedef typename detail::codecvt_holder<Codecvt>::codecvt_type codecvt_type;
0251 typedef typename detail::codecvt_intern<Codecvt>::type intern_type;
0252 typedef typename detail::codecvt_extern<Codecvt>::type extern_type;
0253 typedef typename detail::codecvt_state<Codecvt>::type state_type;
0254 public:
0255 typedef intern_type char_type;
0256 struct category
0257 : impl_type::mode, device_tag, closable_tag, localizable_tag
0258 { };
0259 BOOST_STATIC_ASSERT((
0260 is_same<
0261 extern_type,
0262 BOOST_DEDUCED_TYPENAME char_type_of<Device>::type
0263 >::value
0264 ));
0265 public:
0266 code_converter() { }
0267 BOOST_IOSTREAMS_FORWARD( code_converter, open_impl, Device,
0268 BOOST_IOSTREAMS_CONVERTER_PARAMS,
0269 BOOST_IOSTREAMS_CONVERTER_ARGS )
0270
0271
0272
0273 bool is_open() const { return this->pimpl_->is_open(); }
0274 void close(BOOST_IOS::openmode which = BOOST_IOS::in | BOOST_IOS::out )
0275 { impl().close(which); }
0276
0277
0278
0279 std::streamsize read(char_type*, std::streamsize);
0280 std::streamsize write(const char_type*, std::streamsize);
0281 void imbue(const std::locale& loc) { impl().cvt_.imbue(loc); }
0282
0283
0284
0285 Device& operator*() { return detail::unwrap_direct(dev()); }
0286 Device* operator->() { return &detail::unwrap_direct(dev()); }
0287 private:
0288 template<typename T>
0289 void open_impl(const T& t BOOST_IOSTREAMS_CONVERTER_PARAMS())
0290 {
0291 impl().open(t BOOST_IOSTREAMS_CONVERTER_ARGS());
0292 }
0293
0294 const codecvt_type& cvt() { return impl().cvt_.get(); }
0295 device_type& dev() { return impl().dev(); }
0296 buffer_type& in() { return impl().buf_.first(); }
0297 buffer_type& out() { return impl().buf_.second(); }
0298 impl_type& impl() { return *this->pimpl_; }
0299 };
0300
0301
0302
0303
0304
0305 template<typename Device, typename Codevt, typename Alloc>
0306 std::streamsize code_converter<Device, Codevt, Alloc>::read
0307 (char_type* s, std::streamsize n)
0308 {
0309 const extern_type* next;
0310 intern_type* nint;
0311 std::streamsize total = 0;
0312 int status = iostreams::char_traits<char>::good();
0313 bool partial = false;
0314 buffer_type& buf = in();
0315
0316 do {
0317
0318
0319 if (buf.ptr() == buf.eptr() || partial) {
0320 status = buf.fill(dev());
0321 if (buf.ptr() == buf.eptr())
0322 break;
0323 partial = false;
0324 }
0325
0326
0327 std::codecvt_base::result result =
0328 cvt().in( buf.state(),
0329 buf.ptr(), buf.eptr(), next,
0330 s + total, s + n, nint );
0331 buf.ptr() += next - buf.ptr();
0332 total = static_cast<std::streamsize>(nint - s);
0333
0334 switch (result) {
0335 case std::codecvt_base::partial:
0336 partial = true;
0337 break;
0338 case std::codecvt_base::ok:
0339 break;
0340 case std::codecvt_base::noconv:
0341 {
0342 std::streamsize amt =
0343 std::min<std::streamsize>(next - buf.ptr(), n - total);
0344 detail::strncpy_if_same(s + total, buf.ptr(), amt);
0345 total += amt;
0346 }
0347 break;
0348 case std::codecvt_base::error:
0349 default:
0350 buf.state() = state_type();
0351 boost::throw_exception(code_conversion_error());
0352 }
0353
0354 } while (total < n && status != EOF && status != WOULD_BLOCK);
0355
0356 return total == 0 && status == EOF ? -1 : total;
0357 }
0358
0359 template<typename Device, typename Codevt, typename Alloc>
0360 std::streamsize code_converter<Device, Codevt, Alloc>::write
0361 (const char_type* s, std::streamsize n)
0362 {
0363 buffer_type& buf = out();
0364 extern_type* next;
0365 const intern_type* nint;
0366 std::streamsize total = 0;
0367 bool partial = false;
0368
0369 while (total < n) {
0370
0371
0372 if (buf.eptr() == buf.end() || partial) {
0373 if (!buf.flush(dev()))
0374 break;
0375 partial = false;
0376 }
0377
0378
0379 std::codecvt_base::result result =
0380 cvt().out( buf.state(),
0381 s + total, s + n, nint,
0382 buf.eptr(), buf.end(), next );
0383 int progress = (int) (next - buf.eptr());
0384 buf.eptr() += progress;
0385
0386 switch (result) {
0387 case std::codecvt_base::partial:
0388 partial = true;
0389 BOOST_FALLTHROUGH;
0390 case std::codecvt_base::ok:
0391 total = static_cast<std::streamsize>(nint - s);
0392 break;
0393 case std::codecvt_base::noconv:
0394 {
0395 std::streamsize amt =
0396 std::min<std::streamsize>( nint - total - s,
0397 buf.end() - buf.eptr() );
0398 detail::strncpy_if_same(buf.eptr(), s + total, amt);
0399 total += amt;
0400 }
0401 break;
0402 case std::codecvt_base::error:
0403 default:
0404 buf.state() = state_type();
0405 boost::throw_exception(code_conversion_error());
0406 }
0407 }
0408 return total;
0409 }
0410
0411
0412
0413 } }
0414
0415 #include <boost/iostreams/detail/config/enable_warnings.hpp> // Borland 5.x
0416
0417 #endif