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