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