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
|