annotate DEPENDENCIES/generic/include/boost/iostreams/code_converter.hpp @ 125:34e428693f5d vext

Vext -> Repoint
author Chris Cannam
date Thu, 14 Jun 2018 11:15:39 +0100
parents 2665513ce2d3
children
rev   line source
Chris@16 1 // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
Chris@16 2 // (C) Copyright 2003-2007 Jonathan Turkanis
Chris@16 3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
Chris@16 4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
Chris@16 5
Chris@16 6 // See http://www.boost.org/libs/iostreams for documentation.
Chris@16 7
Chris@16 8 // Contains machinery for performing code conversion.
Chris@16 9
Chris@16 10 #ifndef BOOST_IOSTREAMS_CODE_CONVERTER_HPP_INCLUDED
Chris@16 11 #define BOOST_IOSTREAMS_CODE_CONVERTER_HPP_INCLUDED
Chris@16 12
Chris@16 13 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
Chris@16 14 # pragma once
Chris@16 15 #endif
Chris@16 16
Chris@16 17 #include <boost/iostreams/detail/config/wide_streams.hpp>
Chris@16 18 #if defined(BOOST_IOSTREAMS_NO_WIDE_STREAMS) || \
Chris@16 19 defined(BOOST_IOSTREAMS_NO_LOCALE) \
Chris@16 20 /**/
Chris@16 21 # error code conversion not supported on this platform
Chris@16 22 #endif
Chris@16 23
Chris@16 24 #include <algorithm> // max.
Chris@16 25 #include <cstring> // memcpy.
Chris@16 26 #include <exception>
Chris@16 27 #include <boost/config.hpp> // DEDUCED_TYPENAME,
Chris@16 28 #include <boost/iostreams/char_traits.hpp>
Chris@16 29 #include <boost/iostreams/constants.hpp> // default_filter_buffer_size.
Chris@16 30 #include <boost/iostreams/detail/adapter/concept_adapter.hpp>
Chris@16 31 #include <boost/iostreams/detail/adapter/direct_adapter.hpp>
Chris@16 32 #include <boost/iostreams/detail/buffer.hpp>
Chris@16 33 #include <boost/iostreams/detail/call_traits.hpp>
Chris@16 34 #include <boost/iostreams/detail/codecvt_holder.hpp>
Chris@16 35 #include <boost/iostreams/detail/codecvt_helper.hpp>
Chris@16 36 #include <boost/iostreams/detail/double_object.hpp>
Chris@16 37 #include <boost/iostreams/detail/execute.hpp>
Chris@16 38 #include <boost/iostreams/detail/forward.hpp>
Chris@16 39 #include <boost/iostreams/detail/functional.hpp>
Chris@16 40 #include <boost/iostreams/detail/ios.hpp> // failure, openmode, int types.
Chris@16 41 #include <boost/iostreams/detail/optional.hpp>
Chris@16 42 #include <boost/iostreams/detail/select.hpp>
Chris@16 43 #include <boost/iostreams/traits.hpp>
Chris@16 44 #include <boost/iostreams/operations.hpp>
Chris@16 45 #include <boost/shared_ptr.hpp>
Chris@16 46 #include <boost/static_assert.hpp>
Chris@16 47 #include <boost/throw_exception.hpp>
Chris@16 48 #include <boost/type_traits/is_convertible.hpp>
Chris@16 49 #include <boost/type_traits/is_same.hpp>
Chris@16 50
Chris@16 51 // Must come last.
Chris@16 52 #include <boost/iostreams/detail/config/disable_warnings.hpp> // Borland 5.x
Chris@16 53
Chris@16 54 namespace boost { namespace iostreams {
Chris@16 55
Chris@16 56 struct code_conversion_error : BOOST_IOSTREAMS_FAILURE {
Chris@16 57 code_conversion_error()
Chris@16 58 : BOOST_IOSTREAMS_FAILURE("code conversion error")
Chris@16 59 { }
Chris@16 60 };
Chris@16 61
Chris@16 62 namespace detail {
Chris@16 63
Chris@16 64 //--------------Definition of strncpy_if_same---------------------------------//
Chris@16 65
Chris@16 66 // Helper template for strncpy_if_same, below.
Chris@16 67 template<bool B>
Chris@16 68 struct strncpy_if_same_impl;
Chris@16 69
Chris@16 70 template<>
Chris@16 71 struct strncpy_if_same_impl<true> {
Chris@16 72 template<typename Ch>
Chris@16 73 static Ch* copy(Ch* tgt, const Ch* src, std::streamsize n)
Chris@16 74 { return BOOST_IOSTREAMS_CHAR_TRAITS(Ch)::copy(tgt, src, n); }
Chris@16 75 };
Chris@16 76
Chris@16 77 template<>
Chris@16 78 struct strncpy_if_same_impl<false> {
Chris@16 79 template<typename Src, typename Tgt>
Chris@16 80 static Tgt* copy(Tgt* tgt, const Src*, std::streamsize) { return tgt; }
Chris@16 81 };
Chris@16 82
Chris@16 83 template<typename Src, typename Tgt>
Chris@16 84 Tgt* strncpy_if_same(Tgt* tgt, const Src* src, std::streamsize n)
Chris@16 85 {
Chris@16 86 typedef strncpy_if_same_impl<is_same<Src, Tgt>::value> impl;
Chris@16 87 return impl::copy(tgt, src, n);
Chris@16 88 }
Chris@16 89
Chris@16 90 //--------------Definition of conversion_buffer-------------------------------//
Chris@16 91
Chris@16 92 // Buffer and conversion state for reading.
Chris@16 93 template<typename Codecvt, typename Alloc>
Chris@16 94 class conversion_buffer
Chris@16 95 : public buffer<
Chris@16 96 BOOST_DEDUCED_TYPENAME detail::codecvt_extern<Codecvt>::type,
Chris@16 97 Alloc
Chris@16 98 >
Chris@16 99 {
Chris@16 100 public:
Chris@16 101 typedef typename Codecvt::state_type state_type;
Chris@16 102 conversion_buffer()
Chris@16 103 : buffer<
Chris@16 104 BOOST_DEDUCED_TYPENAME detail::codecvt_extern<Codecvt>::type,
Chris@16 105 Alloc
Chris@16 106 >(0)
Chris@16 107 {
Chris@16 108 reset();
Chris@16 109 }
Chris@16 110 state_type& state() { return state_; }
Chris@16 111 void reset()
Chris@16 112 {
Chris@16 113 if (this->size())
Chris@16 114 this->set(0, 0);
Chris@16 115 state_ = state_type();
Chris@16 116 }
Chris@16 117 private:
Chris@16 118 state_type state_;
Chris@16 119 };
Chris@16 120
Chris@16 121 //--------------Definition of converter_impl----------------------------------//
Chris@16 122
Chris@16 123 // Contains member data, open/is_open/close and buffer management functions.
Chris@16 124 template<typename Device, typename Codecvt, typename Alloc>
Chris@16 125 struct code_converter_impl {
Chris@16 126 typedef typename codecvt_extern<Codecvt>::type extern_type;
Chris@16 127 typedef typename category_of<Device>::type device_category;
Chris@16 128 typedef is_convertible<device_category, input> can_read;
Chris@16 129 typedef is_convertible<device_category, output> can_write;
Chris@16 130 typedef is_convertible<device_category, bidirectional> is_bidir;
Chris@16 131 typedef typename
Chris@16 132 iostreams::select< // Disambiguation for Tru64.
Chris@16 133 is_bidir, bidirectional,
Chris@16 134 can_read, input,
Chris@16 135 can_write, output
Chris@16 136 >::type mode;
Chris@16 137 typedef typename
Chris@16 138 mpl::if_<
Chris@16 139 is_direct<Device>,
Chris@16 140 direct_adapter<Device>,
Chris@16 141 Device
Chris@16 142 >::type device_type;
Chris@16 143 typedef optional< concept_adapter<device_type> > storage_type;
Chris@16 144 typedef is_convertible<device_category, two_sequence> is_double;
Chris@16 145 typedef conversion_buffer<Codecvt, Alloc> buffer_type;
Chris@16 146
Chris@16 147 code_converter_impl() : cvt_(), flags_(0) { }
Chris@16 148
Chris@16 149 ~code_converter_impl()
Chris@16 150 {
Chris@16 151 try {
Chris@16 152 if (flags_ & f_open) close();
Chris@16 153 } catch (...) { /* */ }
Chris@16 154 }
Chris@16 155
Chris@16 156 template <class T>
Chris@16 157 void open(const T& dev, int buffer_size)
Chris@16 158 {
Chris@16 159 if (flags_ & f_open)
Chris@16 160 boost::throw_exception(BOOST_IOSTREAMS_FAILURE("already open"));
Chris@16 161 if (buffer_size == -1)
Chris@16 162 buffer_size = default_filter_buffer_size;
Chris@16 163 int max_length = cvt_.get().max_length();
Chris@16 164 buffer_size = (std::max)(buffer_size, 2 * max_length);
Chris@16 165 if (can_read::value) {
Chris@16 166 buf_.first().resize(buffer_size);
Chris@16 167 buf_.first().set(0, 0);
Chris@16 168 }
Chris@16 169 if (can_write::value && !is_double::value) {
Chris@16 170 buf_.second().resize(buffer_size);
Chris@16 171 buf_.second().set(0, 0);
Chris@16 172 }
Chris@16 173 dev_.reset(concept_adapter<device_type>(dev));
Chris@16 174 flags_ = f_open;
Chris@16 175 }
Chris@16 176
Chris@16 177 void close()
Chris@16 178 {
Chris@16 179 detail::execute_all(
Chris@16 180 detail::call_member_close(*this, BOOST_IOS::in),
Chris@16 181 detail::call_member_close(*this, BOOST_IOS::out)
Chris@16 182 );
Chris@16 183 }
Chris@16 184
Chris@16 185 void close(BOOST_IOS::openmode which)
Chris@16 186 {
Chris@16 187 if (which == BOOST_IOS::in && (flags_ & f_input_closed) == 0) {
Chris@16 188 flags_ |= f_input_closed;
Chris@16 189 iostreams::close(dev(), BOOST_IOS::in);
Chris@16 190 }
Chris@16 191 if (which == BOOST_IOS::out && (flags_ & f_output_closed) == 0) {
Chris@16 192 flags_ |= f_output_closed;
Chris@16 193 detail::execute_all(
Chris@16 194 detail::flush_buffer(buf_.second(), dev(), can_write::value),
Chris@16 195 detail::call_close(dev(), BOOST_IOS::out),
Chris@16 196 detail::call_reset(dev_),
Chris@16 197 detail::call_reset(buf_.first()),
Chris@16 198 detail::call_reset(buf_.second())
Chris@16 199 );
Chris@16 200 }
Chris@16 201 }
Chris@16 202
Chris@16 203 bool is_open() const { return (flags_ & f_open) != 0;}
Chris@16 204
Chris@16 205 device_type& dev() { return **dev_; }
Chris@16 206
Chris@16 207 enum flag_type {
Chris@16 208 f_open = 1,
Chris@16 209 f_input_closed = f_open << 1,
Chris@16 210 f_output_closed = f_input_closed << 1
Chris@16 211 };
Chris@16 212
Chris@16 213 codecvt_holder<Codecvt> cvt_;
Chris@16 214 storage_type dev_;
Chris@16 215 double_object<
Chris@16 216 buffer_type,
Chris@16 217 is_double
Chris@16 218 > buf_;
Chris@16 219 int flags_;
Chris@16 220 };
Chris@16 221
Chris@16 222 } // End namespace detail.
Chris@16 223
Chris@16 224 //--------------Definition of converter---------------------------------------//
Chris@16 225
Chris@16 226 #define BOOST_IOSTREAMS_CONVERTER_PARAMS() , int buffer_size = -1
Chris@16 227 #define BOOST_IOSTREAMS_CONVERTER_ARGS() , buffer_size
Chris@16 228
Chris@16 229 template<typename Device, typename Codecvt, typename Alloc>
Chris@16 230 struct code_converter_base {
Chris@16 231 typedef detail::code_converter_impl<
Chris@16 232 Device, Codecvt, Alloc
Chris@16 233 > impl_type;
Chris@16 234 code_converter_base() : pimpl_(new impl_type) { }
Chris@16 235 shared_ptr<impl_type> pimpl_;
Chris@16 236 };
Chris@16 237
Chris@16 238 template< typename Device,
Chris@16 239 typename Codecvt = detail::default_codecvt,
Chris@16 240 typename Alloc = std::allocator<char> >
Chris@16 241 class code_converter
Chris@16 242 : protected code_converter_base<Device, Codecvt, Alloc>
Chris@16 243 {
Chris@16 244 private:
Chris@16 245 typedef detail::code_converter_impl<
Chris@16 246 Device, Codecvt, Alloc
Chris@16 247 > impl_type;
Chris@16 248 typedef typename impl_type::device_type device_type;
Chris@16 249 typedef typename impl_type::buffer_type buffer_type;
Chris@16 250 typedef typename detail::codecvt_holder<Codecvt>::codecvt_type codecvt_type;
Chris@16 251 typedef typename detail::codecvt_intern<Codecvt>::type intern_type;
Chris@16 252 typedef typename detail::codecvt_extern<Codecvt>::type extern_type;
Chris@16 253 typedef typename detail::codecvt_state<Codecvt>::type state_type;
Chris@16 254 public:
Chris@16 255 typedef intern_type char_type;
Chris@16 256 struct category
Chris@16 257 : impl_type::mode, device_tag, closable_tag, localizable_tag
Chris@16 258 { };
Chris@16 259 BOOST_STATIC_ASSERT((
Chris@16 260 is_same<
Chris@16 261 extern_type,
Chris@16 262 BOOST_DEDUCED_TYPENAME char_type_of<Device>::type
Chris@16 263 >::value
Chris@16 264 ));
Chris@16 265 public:
Chris@16 266 code_converter() { }
Chris@16 267 #if BOOST_WORKAROUND(__GNUC__, < 3)
Chris@16 268 code_converter(code_converter& rhs)
Chris@16 269 : code_converter_base<Device, Codecvt, Alloc>(rhs)
Chris@16 270 { }
Chris@16 271 code_converter(const code_converter& rhs)
Chris@16 272 : code_converter_base<Device, Codecvt, Alloc>(rhs)
Chris@16 273 { }
Chris@16 274 #endif
Chris@16 275 BOOST_IOSTREAMS_FORWARD( code_converter, open_impl, Device,
Chris@16 276 BOOST_IOSTREAMS_CONVERTER_PARAMS,
Chris@16 277 BOOST_IOSTREAMS_CONVERTER_ARGS )
Chris@16 278
Chris@16 279 // fstream-like interface.
Chris@16 280
Chris@16 281 bool is_open() const { return this->pimpl_->is_open(); }
Chris@16 282 void close(BOOST_IOS::openmode which = BOOST_IOS::in | BOOST_IOS::out )
Chris@16 283 { impl().close(which); }
Chris@16 284
Chris@16 285 // Device interface.
Chris@16 286
Chris@16 287 std::streamsize read(char_type*, std::streamsize);
Chris@16 288 std::streamsize write(const char_type*, std::streamsize);
Chris@16 289 void imbue(const std::locale& loc) { impl().cvt_.imbue(loc); }
Chris@16 290
Chris@16 291 // Direct device access.
Chris@16 292
Chris@16 293 Device& operator*() { return detail::unwrap_direct(dev()); }
Chris@16 294 Device* operator->() { return &detail::unwrap_direct(dev()); }
Chris@16 295 private:
Chris@16 296 template<typename T> // Used for forwarding.
Chris@16 297 void open_impl(const T& t BOOST_IOSTREAMS_CONVERTER_PARAMS())
Chris@16 298 {
Chris@16 299 impl().open(t BOOST_IOSTREAMS_CONVERTER_ARGS());
Chris@16 300 }
Chris@16 301
Chris@16 302 const codecvt_type& cvt() { return impl().cvt_.get(); }
Chris@16 303 device_type& dev() { return impl().dev(); }
Chris@16 304 buffer_type& in() { return impl().buf_.first(); }
Chris@16 305 buffer_type& out() { return impl().buf_.second(); }
Chris@16 306 impl_type& impl() { return *this->pimpl_; }
Chris@16 307 };
Chris@16 308
Chris@16 309 //--------------Implementation of converter-----------------------------------//
Chris@16 310
Chris@16 311 // Implementation note: if end of stream contains a partial character,
Chris@16 312 // it is ignored.
Chris@16 313 template<typename Device, typename Codevt, typename Alloc>
Chris@16 314 std::streamsize code_converter<Device, Codevt, Alloc>::read
Chris@16 315 (char_type* s, std::streamsize n)
Chris@16 316 {
Chris@16 317 const extern_type* next; // Next external char.
Chris@16 318 intern_type* nint; // Next internal char.
Chris@16 319 std::streamsize total = 0; // Characters read.
Chris@16 320 int status = iostreams::char_traits<char>::good();
Chris@16 321 bool partial = false;
Chris@16 322 buffer_type& buf = in();
Chris@16 323
Chris@16 324 do {
Chris@16 325
Chris@16 326 // Fill buffer.
Chris@16 327 if (buf.ptr() == buf.eptr() || partial) {
Chris@16 328 status = buf.fill(dev());
Chris@16 329 if (buf.ptr() == buf.eptr())
Chris@16 330 break;
Chris@16 331 partial = false;
Chris@16 332 }
Chris@16 333
Chris@16 334 // Convert.
Chris@16 335 std::codecvt_base::result result =
Chris@16 336 cvt().in( buf.state(),
Chris@16 337 buf.ptr(), buf.eptr(), next,
Chris@16 338 s + total, s + n, nint );
Chris@16 339 buf.ptr() += next - buf.ptr();
Chris@16 340 total = static_cast<std::streamsize>(nint - s);
Chris@16 341
Chris@16 342 switch (result) {
Chris@16 343 case std::codecvt_base::partial:
Chris@16 344 partial = true;
Chris@16 345 break;
Chris@16 346 case std::codecvt_base::ok:
Chris@16 347 break;
Chris@16 348 case std::codecvt_base::noconv:
Chris@16 349 {
Chris@16 350 std::streamsize amt =
Chris@16 351 std::min<std::streamsize>(next - buf.ptr(), n - total);
Chris@16 352 detail::strncpy_if_same(s + total, buf.ptr(), amt);
Chris@16 353 total += amt;
Chris@16 354 }
Chris@16 355 break;
Chris@16 356 case std::codecvt_base::error:
Chris@16 357 default:
Chris@16 358 buf.state() = state_type();
Chris@16 359 boost::throw_exception(code_conversion_error());
Chris@16 360 }
Chris@16 361
Chris@16 362 } while (total < n && status != EOF && status != WOULD_BLOCK);
Chris@16 363
Chris@16 364 return total == 0 && status == EOF ? -1 : total;
Chris@16 365 }
Chris@16 366
Chris@16 367 template<typename Device, typename Codevt, typename Alloc>
Chris@16 368 std::streamsize code_converter<Device, Codevt, Alloc>::write
Chris@16 369 (const char_type* s, std::streamsize n)
Chris@16 370 {
Chris@16 371 buffer_type& buf = out();
Chris@16 372 extern_type* next; // Next external char.
Chris@16 373 const intern_type* nint; // Next internal char.
Chris@16 374 std::streamsize total = 0; // Characters written.
Chris@16 375 bool partial = false;
Chris@16 376
Chris@16 377 while (total < n) {
Chris@16 378
Chris@16 379 // Empty buffer.
Chris@16 380 if (buf.eptr() == buf.end() || partial) {
Chris@16 381 if (!buf.flush(dev()))
Chris@16 382 break;
Chris@16 383 partial = false;
Chris@16 384 }
Chris@16 385
Chris@16 386 // Convert.
Chris@16 387 std::codecvt_base::result result =
Chris@16 388 cvt().out( buf.state(),
Chris@16 389 s + total, s + n, nint,
Chris@16 390 buf.eptr(), buf.end(), next );
Chris@16 391 int progress = (int) (next - buf.eptr());
Chris@16 392 buf.eptr() += progress;
Chris@16 393
Chris@16 394 switch (result) {
Chris@16 395 case std::codecvt_base::partial:
Chris@16 396 partial = true;
Chris@16 397 BOOST_FALLTHROUGH;
Chris@16 398 case std::codecvt_base::ok:
Chris@16 399 total = static_cast<std::streamsize>(nint - s);
Chris@16 400 break;
Chris@16 401 case std::codecvt_base::noconv:
Chris@16 402 {
Chris@16 403 std::streamsize amt =
Chris@16 404 std::min<std::streamsize>( nint - total - s,
Chris@16 405 buf.end() - buf.eptr() );
Chris@16 406 detail::strncpy_if_same(buf.eptr(), s + total, amt);
Chris@16 407 total += amt;
Chris@16 408 }
Chris@16 409 break;
Chris@16 410 case std::codecvt_base::error:
Chris@16 411 default:
Chris@16 412 buf.state() = state_type();
Chris@16 413 boost::throw_exception(code_conversion_error());
Chris@16 414 }
Chris@16 415 }
Chris@16 416 return total;
Chris@16 417 }
Chris@16 418
Chris@16 419 //----------------------------------------------------------------------------//
Chris@16 420
Chris@16 421 } } // End namespaces iostreams, boost.
Chris@16 422
Chris@16 423 #include <boost/iostreams/detail/config/enable_warnings.hpp> // Borland 5.x
Chris@16 424
Chris@16 425 #endif // #ifndef BOOST_IOSTREAMS_CODE_CONVERTER_HPP_INCLUDED