Mercurial > hg > vamp-build-and-test
comparison DEPENDENCIES/generic/include/boost/iostreams/code_converter.hpp @ 16:2665513ce2d3
Add boost headers
author | Chris Cannam |
---|---|
date | Tue, 05 Aug 2014 11:11:38 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
15:663ca0da4350 | 16:2665513ce2d3 |
---|---|
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) && (_MSC_VER >= 1020) | |
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. | |
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, int 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 int 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() , int 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 #if BOOST_WORKAROUND(__GNUC__, < 3) | |
268 code_converter(code_converter& rhs) | |
269 : code_converter_base<Device, Codecvt, Alloc>(rhs) | |
270 { } | |
271 code_converter(const code_converter& rhs) | |
272 : code_converter_base<Device, Codecvt, Alloc>(rhs) | |
273 { } | |
274 #endif | |
275 BOOST_IOSTREAMS_FORWARD( code_converter, open_impl, Device, | |
276 BOOST_IOSTREAMS_CONVERTER_PARAMS, | |
277 BOOST_IOSTREAMS_CONVERTER_ARGS ) | |
278 | |
279 // fstream-like interface. | |
280 | |
281 bool is_open() const { return this->pimpl_->is_open(); } | |
282 void close(BOOST_IOS::openmode which = BOOST_IOS::in | BOOST_IOS::out ) | |
283 { impl().close(which); } | |
284 | |
285 // Device interface. | |
286 | |
287 std::streamsize read(char_type*, std::streamsize); | |
288 std::streamsize write(const char_type*, std::streamsize); | |
289 void imbue(const std::locale& loc) { impl().cvt_.imbue(loc); } | |
290 | |
291 // Direct device access. | |
292 | |
293 Device& operator*() { return detail::unwrap_direct(dev()); } | |
294 Device* operator->() { return &detail::unwrap_direct(dev()); } | |
295 private: | |
296 template<typename T> // Used for forwarding. | |
297 void open_impl(const T& t BOOST_IOSTREAMS_CONVERTER_PARAMS()) | |
298 { | |
299 impl().open(t BOOST_IOSTREAMS_CONVERTER_ARGS()); | |
300 } | |
301 | |
302 const codecvt_type& cvt() { return impl().cvt_.get(); } | |
303 device_type& dev() { return impl().dev(); } | |
304 buffer_type& in() { return impl().buf_.first(); } | |
305 buffer_type& out() { return impl().buf_.second(); } | |
306 impl_type& impl() { return *this->pimpl_; } | |
307 }; | |
308 | |
309 //--------------Implementation of converter-----------------------------------// | |
310 | |
311 // Implementation note: if end of stream contains a partial character, | |
312 // it is ignored. | |
313 template<typename Device, typename Codevt, typename Alloc> | |
314 std::streamsize code_converter<Device, Codevt, Alloc>::read | |
315 (char_type* s, std::streamsize n) | |
316 { | |
317 const extern_type* next; // Next external char. | |
318 intern_type* nint; // Next internal char. | |
319 std::streamsize total = 0; // Characters read. | |
320 int status = iostreams::char_traits<char>::good(); | |
321 bool partial = false; | |
322 buffer_type& buf = in(); | |
323 | |
324 do { | |
325 | |
326 // Fill buffer. | |
327 if (buf.ptr() == buf.eptr() || partial) { | |
328 status = buf.fill(dev()); | |
329 if (buf.ptr() == buf.eptr()) | |
330 break; | |
331 partial = false; | |
332 } | |
333 | |
334 // Convert. | |
335 std::codecvt_base::result result = | |
336 cvt().in( buf.state(), | |
337 buf.ptr(), buf.eptr(), next, | |
338 s + total, s + n, nint ); | |
339 buf.ptr() += next - buf.ptr(); | |
340 total = static_cast<std::streamsize>(nint - s); | |
341 | |
342 switch (result) { | |
343 case std::codecvt_base::partial: | |
344 partial = true; | |
345 break; | |
346 case std::codecvt_base::ok: | |
347 break; | |
348 case std::codecvt_base::noconv: | |
349 { | |
350 std::streamsize amt = | |
351 std::min<std::streamsize>(next - buf.ptr(), n - total); | |
352 detail::strncpy_if_same(s + total, buf.ptr(), amt); | |
353 total += amt; | |
354 } | |
355 break; | |
356 case std::codecvt_base::error: | |
357 default: | |
358 buf.state() = state_type(); | |
359 boost::throw_exception(code_conversion_error()); | |
360 } | |
361 | |
362 } while (total < n && status != EOF && status != WOULD_BLOCK); | |
363 | |
364 return total == 0 && status == EOF ? -1 : total; | |
365 } | |
366 | |
367 template<typename Device, typename Codevt, typename Alloc> | |
368 std::streamsize code_converter<Device, Codevt, Alloc>::write | |
369 (const char_type* s, std::streamsize n) | |
370 { | |
371 buffer_type& buf = out(); | |
372 extern_type* next; // Next external char. | |
373 const intern_type* nint; // Next internal char. | |
374 std::streamsize total = 0; // Characters written. | |
375 bool partial = false; | |
376 | |
377 while (total < n) { | |
378 | |
379 // Empty buffer. | |
380 if (buf.eptr() == buf.end() || partial) { | |
381 if (!buf.flush(dev())) | |
382 break; | |
383 partial = false; | |
384 } | |
385 | |
386 // Convert. | |
387 std::codecvt_base::result result = | |
388 cvt().out( buf.state(), | |
389 s + total, s + n, nint, | |
390 buf.eptr(), buf.end(), next ); | |
391 int progress = (int) (next - buf.eptr()); | |
392 buf.eptr() += progress; | |
393 | |
394 switch (result) { | |
395 case std::codecvt_base::partial: | |
396 partial = true; | |
397 BOOST_FALLTHROUGH; | |
398 case std::codecvt_base::ok: | |
399 total = static_cast<std::streamsize>(nint - s); | |
400 break; | |
401 case std::codecvt_base::noconv: | |
402 { | |
403 std::streamsize amt = | |
404 std::min<std::streamsize>( nint - total - s, | |
405 buf.end() - buf.eptr() ); | |
406 detail::strncpy_if_same(buf.eptr(), s + total, amt); | |
407 total += amt; | |
408 } | |
409 break; | |
410 case std::codecvt_base::error: | |
411 default: | |
412 buf.state() = state_type(); | |
413 boost::throw_exception(code_conversion_error()); | |
414 } | |
415 } | |
416 return total; | |
417 } | |
418 | |
419 //----------------------------------------------------------------------------// | |
420 | |
421 } } // End namespaces iostreams, boost. | |
422 | |
423 #include <boost/iostreams/detail/config/enable_warnings.hpp> // Borland 5.x | |
424 | |
425 #endif // #ifndef BOOST_IOSTREAMS_CODE_CONVERTER_HPP_INCLUDED |