Chris@16
|
1 //
|
Chris@16
|
2 // impl/read_until.hpp
|
Chris@16
|
3 // ~~~~~~~~~~~~~~~~~~~
|
Chris@16
|
4 //
|
Chris@101
|
5 // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
Chris@16
|
6 //
|
Chris@16
|
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
|
Chris@16
|
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
9 //
|
Chris@16
|
10
|
Chris@16
|
11 #ifndef BOOST_ASIO_IMPL_READ_UNTIL_HPP
|
Chris@16
|
12 #define BOOST_ASIO_IMPL_READ_UNTIL_HPP
|
Chris@16
|
13
|
Chris@16
|
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
Chris@16
|
15 # pragma once
|
Chris@16
|
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
Chris@16
|
17
|
Chris@16
|
18 #include <algorithm>
|
Chris@16
|
19 #include <string>
|
Chris@16
|
20 #include <vector>
|
Chris@16
|
21 #include <utility>
|
Chris@16
|
22 #include <boost/asio/buffer.hpp>
|
Chris@16
|
23 #include <boost/asio/buffers_iterator.hpp>
|
Chris@16
|
24 #include <boost/asio/detail/bind_handler.hpp>
|
Chris@16
|
25 #include <boost/asio/detail/handler_alloc_helpers.hpp>
|
Chris@16
|
26 #include <boost/asio/detail/handler_cont_helpers.hpp>
|
Chris@16
|
27 #include <boost/asio/detail/handler_invoke_helpers.hpp>
|
Chris@16
|
28 #include <boost/asio/detail/handler_type_requirements.hpp>
|
Chris@16
|
29 #include <boost/asio/detail/limits.hpp>
|
Chris@16
|
30 #include <boost/asio/detail/throw_error.hpp>
|
Chris@16
|
31
|
Chris@16
|
32 #include <boost/asio/detail/push_options.hpp>
|
Chris@16
|
33
|
Chris@16
|
34 namespace boost {
|
Chris@16
|
35 namespace asio {
|
Chris@16
|
36
|
Chris@16
|
37 template <typename SyncReadStream, typename Allocator>
|
Chris@16
|
38 inline std::size_t read_until(SyncReadStream& s,
|
Chris@16
|
39 boost::asio::basic_streambuf<Allocator>& b, char delim)
|
Chris@16
|
40 {
|
Chris@16
|
41 boost::system::error_code ec;
|
Chris@16
|
42 std::size_t bytes_transferred = read_until(s, b, delim, ec);
|
Chris@16
|
43 boost::asio::detail::throw_error(ec, "read_until");
|
Chris@16
|
44 return bytes_transferred;
|
Chris@16
|
45 }
|
Chris@16
|
46
|
Chris@16
|
47 template <typename SyncReadStream, typename Allocator>
|
Chris@16
|
48 std::size_t read_until(SyncReadStream& s,
|
Chris@16
|
49 boost::asio::basic_streambuf<Allocator>& b, char delim,
|
Chris@16
|
50 boost::system::error_code& ec)
|
Chris@16
|
51 {
|
Chris@16
|
52 std::size_t search_position = 0;
|
Chris@16
|
53 for (;;)
|
Chris@16
|
54 {
|
Chris@16
|
55 // Determine the range of the data to be searched.
|
Chris@16
|
56 typedef typename boost::asio::basic_streambuf<
|
Chris@16
|
57 Allocator>::const_buffers_type const_buffers_type;
|
Chris@16
|
58 typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
|
Chris@16
|
59 const_buffers_type buffers = b.data();
|
Chris@16
|
60 iterator begin = iterator::begin(buffers);
|
Chris@16
|
61 iterator start_pos = begin + search_position;
|
Chris@16
|
62 iterator end = iterator::end(buffers);
|
Chris@16
|
63
|
Chris@16
|
64 // Look for a match.
|
Chris@16
|
65 iterator iter = std::find(start_pos, end, delim);
|
Chris@16
|
66 if (iter != end)
|
Chris@16
|
67 {
|
Chris@16
|
68 // Found a match. We're done.
|
Chris@16
|
69 ec = boost::system::error_code();
|
Chris@16
|
70 return iter - begin + 1;
|
Chris@16
|
71 }
|
Chris@16
|
72 else
|
Chris@16
|
73 {
|
Chris@16
|
74 // No match. Next search can start with the new data.
|
Chris@16
|
75 search_position = end - begin;
|
Chris@16
|
76 }
|
Chris@16
|
77
|
Chris@16
|
78 // Check if buffer is full.
|
Chris@16
|
79 if (b.size() == b.max_size())
|
Chris@16
|
80 {
|
Chris@16
|
81 ec = error::not_found;
|
Chris@16
|
82 return 0;
|
Chris@16
|
83 }
|
Chris@16
|
84
|
Chris@16
|
85 // Need more data.
|
Chris@16
|
86 std::size_t bytes_to_read = read_size_helper(b, 65536);
|
Chris@16
|
87 b.commit(s.read_some(b.prepare(bytes_to_read), ec));
|
Chris@16
|
88 if (ec)
|
Chris@16
|
89 return 0;
|
Chris@16
|
90 }
|
Chris@16
|
91 }
|
Chris@16
|
92
|
Chris@16
|
93 template <typename SyncReadStream, typename Allocator>
|
Chris@16
|
94 inline std::size_t read_until(SyncReadStream& s,
|
Chris@16
|
95 boost::asio::basic_streambuf<Allocator>& b, const std::string& delim)
|
Chris@16
|
96 {
|
Chris@16
|
97 boost::system::error_code ec;
|
Chris@16
|
98 std::size_t bytes_transferred = read_until(s, b, delim, ec);
|
Chris@16
|
99 boost::asio::detail::throw_error(ec, "read_until");
|
Chris@16
|
100 return bytes_transferred;
|
Chris@16
|
101 }
|
Chris@16
|
102
|
Chris@16
|
103 namespace detail
|
Chris@16
|
104 {
|
Chris@16
|
105 // Algorithm that finds a subsequence of equal values in a sequence. Returns
|
Chris@16
|
106 // (iterator,true) if a full match was found, in which case the iterator
|
Chris@16
|
107 // points to the beginning of the match. Returns (iterator,false) if a
|
Chris@16
|
108 // partial match was found at the end of the first sequence, in which case
|
Chris@16
|
109 // the iterator points to the beginning of the partial match. Returns
|
Chris@16
|
110 // (last1,false) if no full or partial match was found.
|
Chris@16
|
111 template <typename Iterator1, typename Iterator2>
|
Chris@16
|
112 std::pair<Iterator1, bool> partial_search(
|
Chris@16
|
113 Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2)
|
Chris@16
|
114 {
|
Chris@16
|
115 for (Iterator1 iter1 = first1; iter1 != last1; ++iter1)
|
Chris@16
|
116 {
|
Chris@16
|
117 Iterator1 test_iter1 = iter1;
|
Chris@16
|
118 Iterator2 test_iter2 = first2;
|
Chris@16
|
119 for (;; ++test_iter1, ++test_iter2)
|
Chris@16
|
120 {
|
Chris@16
|
121 if (test_iter2 == last2)
|
Chris@16
|
122 return std::make_pair(iter1, true);
|
Chris@16
|
123 if (test_iter1 == last1)
|
Chris@16
|
124 {
|
Chris@16
|
125 if (test_iter2 != first2)
|
Chris@16
|
126 return std::make_pair(iter1, false);
|
Chris@16
|
127 else
|
Chris@16
|
128 break;
|
Chris@16
|
129 }
|
Chris@16
|
130 if (*test_iter1 != *test_iter2)
|
Chris@16
|
131 break;
|
Chris@16
|
132 }
|
Chris@16
|
133 }
|
Chris@16
|
134 return std::make_pair(last1, false);
|
Chris@16
|
135 }
|
Chris@16
|
136 } // namespace detail
|
Chris@16
|
137
|
Chris@16
|
138 template <typename SyncReadStream, typename Allocator>
|
Chris@16
|
139 std::size_t read_until(SyncReadStream& s,
|
Chris@16
|
140 boost::asio::basic_streambuf<Allocator>& b, const std::string& delim,
|
Chris@16
|
141 boost::system::error_code& ec)
|
Chris@16
|
142 {
|
Chris@16
|
143 std::size_t search_position = 0;
|
Chris@16
|
144 for (;;)
|
Chris@16
|
145 {
|
Chris@16
|
146 // Determine the range of the data to be searched.
|
Chris@16
|
147 typedef typename boost::asio::basic_streambuf<
|
Chris@16
|
148 Allocator>::const_buffers_type const_buffers_type;
|
Chris@16
|
149 typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
|
Chris@16
|
150 const_buffers_type buffers = b.data();
|
Chris@16
|
151 iterator begin = iterator::begin(buffers);
|
Chris@16
|
152 iterator start_pos = begin + search_position;
|
Chris@16
|
153 iterator end = iterator::end(buffers);
|
Chris@16
|
154
|
Chris@16
|
155 // Look for a match.
|
Chris@16
|
156 std::pair<iterator, bool> result = detail::partial_search(
|
Chris@16
|
157 start_pos, end, delim.begin(), delim.end());
|
Chris@16
|
158 if (result.first != end)
|
Chris@16
|
159 {
|
Chris@16
|
160 if (result.second)
|
Chris@16
|
161 {
|
Chris@16
|
162 // Full match. We're done.
|
Chris@16
|
163 ec = boost::system::error_code();
|
Chris@16
|
164 return result.first - begin + delim.length();
|
Chris@16
|
165 }
|
Chris@16
|
166 else
|
Chris@16
|
167 {
|
Chris@16
|
168 // Partial match. Next search needs to start from beginning of match.
|
Chris@16
|
169 search_position = result.first - begin;
|
Chris@16
|
170 }
|
Chris@16
|
171 }
|
Chris@16
|
172 else
|
Chris@16
|
173 {
|
Chris@16
|
174 // No match. Next search can start with the new data.
|
Chris@16
|
175 search_position = end - begin;
|
Chris@16
|
176 }
|
Chris@16
|
177
|
Chris@16
|
178 // Check if buffer is full.
|
Chris@16
|
179 if (b.size() == b.max_size())
|
Chris@16
|
180 {
|
Chris@16
|
181 ec = error::not_found;
|
Chris@16
|
182 return 0;
|
Chris@16
|
183 }
|
Chris@16
|
184
|
Chris@16
|
185 // Need more data.
|
Chris@16
|
186 std::size_t bytes_to_read = read_size_helper(b, 65536);
|
Chris@16
|
187 b.commit(s.read_some(b.prepare(bytes_to_read), ec));
|
Chris@16
|
188 if (ec)
|
Chris@16
|
189 return 0;
|
Chris@16
|
190 }
|
Chris@16
|
191 }
|
Chris@16
|
192
|
Chris@16
|
193 #if defined(BOOST_ASIO_HAS_BOOST_REGEX)
|
Chris@16
|
194
|
Chris@16
|
195 template <typename SyncReadStream, typename Allocator>
|
Chris@16
|
196 inline std::size_t read_until(SyncReadStream& s,
|
Chris@16
|
197 boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr)
|
Chris@16
|
198 {
|
Chris@16
|
199 boost::system::error_code ec;
|
Chris@16
|
200 std::size_t bytes_transferred = read_until(s, b, expr, ec);
|
Chris@16
|
201 boost::asio::detail::throw_error(ec, "read_until");
|
Chris@16
|
202 return bytes_transferred;
|
Chris@16
|
203 }
|
Chris@16
|
204
|
Chris@16
|
205 template <typename SyncReadStream, typename Allocator>
|
Chris@16
|
206 std::size_t read_until(SyncReadStream& s,
|
Chris@16
|
207 boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
|
Chris@16
|
208 boost::system::error_code& ec)
|
Chris@16
|
209 {
|
Chris@16
|
210 std::size_t search_position = 0;
|
Chris@16
|
211 for (;;)
|
Chris@16
|
212 {
|
Chris@16
|
213 // Determine the range of the data to be searched.
|
Chris@16
|
214 typedef typename boost::asio::basic_streambuf<
|
Chris@16
|
215 Allocator>::const_buffers_type const_buffers_type;
|
Chris@16
|
216 typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
|
Chris@16
|
217 const_buffers_type buffers = b.data();
|
Chris@16
|
218 iterator begin = iterator::begin(buffers);
|
Chris@16
|
219 iterator start_pos = begin + search_position;
|
Chris@16
|
220 iterator end = iterator::end(buffers);
|
Chris@16
|
221
|
Chris@16
|
222 // Look for a match.
|
Chris@16
|
223 boost::match_results<iterator,
|
Chris@16
|
224 typename std::vector<boost::sub_match<iterator> >::allocator_type>
|
Chris@16
|
225 match_results;
|
Chris@16
|
226 if (regex_search(start_pos, end, match_results, expr,
|
Chris@16
|
227 boost::match_default | boost::match_partial))
|
Chris@16
|
228 {
|
Chris@16
|
229 if (match_results[0].matched)
|
Chris@16
|
230 {
|
Chris@16
|
231 // Full match. We're done.
|
Chris@16
|
232 ec = boost::system::error_code();
|
Chris@16
|
233 return match_results[0].second - begin;
|
Chris@16
|
234 }
|
Chris@16
|
235 else
|
Chris@16
|
236 {
|
Chris@16
|
237 // Partial match. Next search needs to start from beginning of match.
|
Chris@16
|
238 search_position = match_results[0].first - begin;
|
Chris@16
|
239 }
|
Chris@16
|
240 }
|
Chris@16
|
241 else
|
Chris@16
|
242 {
|
Chris@16
|
243 // No match. Next search can start with the new data.
|
Chris@16
|
244 search_position = end - begin;
|
Chris@16
|
245 }
|
Chris@16
|
246
|
Chris@16
|
247 // Check if buffer is full.
|
Chris@16
|
248 if (b.size() == b.max_size())
|
Chris@16
|
249 {
|
Chris@16
|
250 ec = error::not_found;
|
Chris@16
|
251 return 0;
|
Chris@16
|
252 }
|
Chris@16
|
253
|
Chris@16
|
254 // Need more data.
|
Chris@16
|
255 std::size_t bytes_to_read = read_size_helper(b, 65536);
|
Chris@16
|
256 b.commit(s.read_some(b.prepare(bytes_to_read), ec));
|
Chris@16
|
257 if (ec)
|
Chris@16
|
258 return 0;
|
Chris@16
|
259 }
|
Chris@16
|
260 }
|
Chris@16
|
261
|
Chris@16
|
262 #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX)
|
Chris@16
|
263
|
Chris@16
|
264 template <typename SyncReadStream, typename Allocator, typename MatchCondition>
|
Chris@16
|
265 std::size_t read_until(SyncReadStream& s,
|
Chris@16
|
266 boost::asio::basic_streambuf<Allocator>& b,
|
Chris@16
|
267 MatchCondition match_condition, boost::system::error_code& ec,
|
Chris@16
|
268 typename enable_if<is_match_condition<MatchCondition>::value>::type*)
|
Chris@16
|
269 {
|
Chris@16
|
270 std::size_t search_position = 0;
|
Chris@16
|
271 for (;;)
|
Chris@16
|
272 {
|
Chris@16
|
273 // Determine the range of the data to be searched.
|
Chris@16
|
274 typedef typename boost::asio::basic_streambuf<
|
Chris@16
|
275 Allocator>::const_buffers_type const_buffers_type;
|
Chris@16
|
276 typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
|
Chris@16
|
277 const_buffers_type buffers = b.data();
|
Chris@16
|
278 iterator begin = iterator::begin(buffers);
|
Chris@16
|
279 iterator start_pos = begin + search_position;
|
Chris@16
|
280 iterator end = iterator::end(buffers);
|
Chris@16
|
281
|
Chris@16
|
282 // Look for a match.
|
Chris@16
|
283 std::pair<iterator, bool> result = match_condition(start_pos, end);
|
Chris@16
|
284 if (result.second)
|
Chris@16
|
285 {
|
Chris@16
|
286 // Full match. We're done.
|
Chris@16
|
287 ec = boost::system::error_code();
|
Chris@16
|
288 return result.first - begin;
|
Chris@16
|
289 }
|
Chris@16
|
290 else if (result.first != end)
|
Chris@16
|
291 {
|
Chris@16
|
292 // Partial match. Next search needs to start from beginning of match.
|
Chris@16
|
293 search_position = result.first - begin;
|
Chris@16
|
294 }
|
Chris@16
|
295 else
|
Chris@16
|
296 {
|
Chris@16
|
297 // No match. Next search can start with the new data.
|
Chris@16
|
298 search_position = end - begin;
|
Chris@16
|
299 }
|
Chris@16
|
300
|
Chris@16
|
301 // Check if buffer is full.
|
Chris@16
|
302 if (b.size() == b.max_size())
|
Chris@16
|
303 {
|
Chris@16
|
304 ec = error::not_found;
|
Chris@16
|
305 return 0;
|
Chris@16
|
306 }
|
Chris@16
|
307
|
Chris@16
|
308 // Need more data.
|
Chris@16
|
309 std::size_t bytes_to_read = read_size_helper(b, 65536);
|
Chris@16
|
310 b.commit(s.read_some(b.prepare(bytes_to_read), ec));
|
Chris@16
|
311 if (ec)
|
Chris@16
|
312 return 0;
|
Chris@16
|
313 }
|
Chris@16
|
314 }
|
Chris@16
|
315
|
Chris@16
|
316 template <typename SyncReadStream, typename Allocator, typename MatchCondition>
|
Chris@16
|
317 inline std::size_t read_until(SyncReadStream& s,
|
Chris@16
|
318 boost::asio::basic_streambuf<Allocator>& b, MatchCondition match_condition,
|
Chris@16
|
319 typename enable_if<is_match_condition<MatchCondition>::value>::type*)
|
Chris@16
|
320 {
|
Chris@16
|
321 boost::system::error_code ec;
|
Chris@16
|
322 std::size_t bytes_transferred = read_until(s, b, match_condition, ec);
|
Chris@16
|
323 boost::asio::detail::throw_error(ec, "read_until");
|
Chris@16
|
324 return bytes_transferred;
|
Chris@16
|
325 }
|
Chris@16
|
326
|
Chris@16
|
327 namespace detail
|
Chris@16
|
328 {
|
Chris@16
|
329 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
|
Chris@16
|
330 class read_until_delim_op
|
Chris@16
|
331 {
|
Chris@16
|
332 public:
|
Chris@16
|
333 read_until_delim_op(AsyncReadStream& stream,
|
Chris@16
|
334 boost::asio::basic_streambuf<Allocator>& streambuf,
|
Chris@16
|
335 char delim, ReadHandler& handler)
|
Chris@16
|
336 : stream_(stream),
|
Chris@16
|
337 streambuf_(streambuf),
|
Chris@16
|
338 delim_(delim),
|
Chris@16
|
339 start_(0),
|
Chris@16
|
340 search_position_(0),
|
Chris@16
|
341 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
|
Chris@16
|
342 {
|
Chris@16
|
343 }
|
Chris@16
|
344
|
Chris@16
|
345 #if defined(BOOST_ASIO_HAS_MOVE)
|
Chris@16
|
346 read_until_delim_op(const read_until_delim_op& other)
|
Chris@16
|
347 : stream_(other.stream_),
|
Chris@16
|
348 streambuf_(other.streambuf_),
|
Chris@16
|
349 delim_(other.delim_),
|
Chris@16
|
350 start_(other.start_),
|
Chris@16
|
351 search_position_(other.search_position_),
|
Chris@16
|
352 handler_(other.handler_)
|
Chris@16
|
353 {
|
Chris@16
|
354 }
|
Chris@16
|
355
|
Chris@16
|
356 read_until_delim_op(read_until_delim_op&& other)
|
Chris@16
|
357 : stream_(other.stream_),
|
Chris@16
|
358 streambuf_(other.streambuf_),
|
Chris@16
|
359 delim_(other.delim_),
|
Chris@16
|
360 start_(other.start_),
|
Chris@16
|
361 search_position_(other.search_position_),
|
Chris@16
|
362 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
|
Chris@16
|
363 {
|
Chris@16
|
364 }
|
Chris@16
|
365 #endif // defined(BOOST_ASIO_HAS_MOVE)
|
Chris@16
|
366
|
Chris@16
|
367 void operator()(const boost::system::error_code& ec,
|
Chris@16
|
368 std::size_t bytes_transferred, int start = 0)
|
Chris@16
|
369 {
|
Chris@16
|
370 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
|
Chris@16
|
371 std::size_t bytes_to_read;
|
Chris@16
|
372 switch (start_ = start)
|
Chris@16
|
373 {
|
Chris@16
|
374 case 1:
|
Chris@16
|
375 for (;;)
|
Chris@16
|
376 {
|
Chris@16
|
377 {
|
Chris@16
|
378 // Determine the range of the data to be searched.
|
Chris@16
|
379 typedef typename boost::asio::basic_streambuf<
|
Chris@16
|
380 Allocator>::const_buffers_type const_buffers_type;
|
Chris@16
|
381 typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
|
Chris@16
|
382 const_buffers_type buffers = streambuf_.data();
|
Chris@16
|
383 iterator begin = iterator::begin(buffers);
|
Chris@16
|
384 iterator start_pos = begin + search_position_;
|
Chris@16
|
385 iterator end = iterator::end(buffers);
|
Chris@16
|
386
|
Chris@16
|
387 // Look for a match.
|
Chris@16
|
388 iterator iter = std::find(start_pos, end, delim_);
|
Chris@16
|
389 if (iter != end)
|
Chris@16
|
390 {
|
Chris@16
|
391 // Found a match. We're done.
|
Chris@16
|
392 search_position_ = iter - begin + 1;
|
Chris@16
|
393 bytes_to_read = 0;
|
Chris@16
|
394 }
|
Chris@16
|
395
|
Chris@16
|
396 // No match yet. Check if buffer is full.
|
Chris@16
|
397 else if (streambuf_.size() == streambuf_.max_size())
|
Chris@16
|
398 {
|
Chris@16
|
399 search_position_ = not_found;
|
Chris@16
|
400 bytes_to_read = 0;
|
Chris@16
|
401 }
|
Chris@16
|
402
|
Chris@16
|
403 // Need to read some more data.
|
Chris@16
|
404 else
|
Chris@16
|
405 {
|
Chris@16
|
406 // Next search can start with the new data.
|
Chris@16
|
407 search_position_ = end - begin;
|
Chris@16
|
408 bytes_to_read = read_size_helper(streambuf_, 65536);
|
Chris@16
|
409 }
|
Chris@16
|
410 }
|
Chris@16
|
411
|
Chris@16
|
412 // Check if we're done.
|
Chris@16
|
413 if (!start && bytes_to_read == 0)
|
Chris@16
|
414 break;
|
Chris@16
|
415
|
Chris@16
|
416 // Start a new asynchronous read operation to obtain more data.
|
Chris@16
|
417 stream_.async_read_some(streambuf_.prepare(bytes_to_read),
|
Chris@16
|
418 BOOST_ASIO_MOVE_CAST(read_until_delim_op)(*this));
|
Chris@16
|
419 return; default:
|
Chris@16
|
420 streambuf_.commit(bytes_transferred);
|
Chris@16
|
421 if (ec || bytes_transferred == 0)
|
Chris@16
|
422 break;
|
Chris@16
|
423 }
|
Chris@16
|
424
|
Chris@16
|
425 const boost::system::error_code result_ec =
|
Chris@16
|
426 (search_position_ == not_found)
|
Chris@16
|
427 ? error::not_found : ec;
|
Chris@16
|
428
|
Chris@16
|
429 const std::size_t result_n =
|
Chris@16
|
430 (ec || search_position_ == not_found)
|
Chris@16
|
431 ? 0 : search_position_;
|
Chris@16
|
432
|
Chris@16
|
433 handler_(result_ec, result_n);
|
Chris@16
|
434 }
|
Chris@16
|
435 }
|
Chris@16
|
436
|
Chris@16
|
437 //private:
|
Chris@16
|
438 AsyncReadStream& stream_;
|
Chris@16
|
439 boost::asio::basic_streambuf<Allocator>& streambuf_;
|
Chris@16
|
440 char delim_;
|
Chris@16
|
441 int start_;
|
Chris@16
|
442 std::size_t search_position_;
|
Chris@16
|
443 ReadHandler handler_;
|
Chris@16
|
444 };
|
Chris@16
|
445
|
Chris@16
|
446 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
|
Chris@16
|
447 inline void* asio_handler_allocate(std::size_t size,
|
Chris@16
|
448 read_until_delim_op<AsyncReadStream,
|
Chris@16
|
449 Allocator, ReadHandler>* this_handler)
|
Chris@16
|
450 {
|
Chris@16
|
451 return boost_asio_handler_alloc_helpers::allocate(
|
Chris@16
|
452 size, this_handler->handler_);
|
Chris@16
|
453 }
|
Chris@16
|
454
|
Chris@16
|
455 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
|
Chris@16
|
456 inline void asio_handler_deallocate(void* pointer, std::size_t size,
|
Chris@16
|
457 read_until_delim_op<AsyncReadStream,
|
Chris@16
|
458 Allocator, ReadHandler>* this_handler)
|
Chris@16
|
459 {
|
Chris@16
|
460 boost_asio_handler_alloc_helpers::deallocate(
|
Chris@16
|
461 pointer, size, this_handler->handler_);
|
Chris@16
|
462 }
|
Chris@16
|
463
|
Chris@16
|
464 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
|
Chris@16
|
465 inline bool asio_handler_is_continuation(
|
Chris@16
|
466 read_until_delim_op<AsyncReadStream,
|
Chris@16
|
467 Allocator, ReadHandler>* this_handler)
|
Chris@16
|
468 {
|
Chris@16
|
469 return this_handler->start_ == 0 ? true
|
Chris@16
|
470 : boost_asio_handler_cont_helpers::is_continuation(
|
Chris@16
|
471 this_handler->handler_);
|
Chris@16
|
472 }
|
Chris@16
|
473
|
Chris@16
|
474 template <typename Function, typename AsyncReadStream, typename Allocator,
|
Chris@16
|
475 typename ReadHandler>
|
Chris@16
|
476 inline void asio_handler_invoke(Function& function,
|
Chris@16
|
477 read_until_delim_op<AsyncReadStream,
|
Chris@16
|
478 Allocator, ReadHandler>* this_handler)
|
Chris@16
|
479 {
|
Chris@16
|
480 boost_asio_handler_invoke_helpers::invoke(
|
Chris@16
|
481 function, this_handler->handler_);
|
Chris@16
|
482 }
|
Chris@16
|
483
|
Chris@16
|
484 template <typename Function, typename AsyncReadStream, typename Allocator,
|
Chris@16
|
485 typename ReadHandler>
|
Chris@16
|
486 inline void asio_handler_invoke(const Function& function,
|
Chris@16
|
487 read_until_delim_op<AsyncReadStream,
|
Chris@16
|
488 Allocator, ReadHandler>* this_handler)
|
Chris@16
|
489 {
|
Chris@16
|
490 boost_asio_handler_invoke_helpers::invoke(
|
Chris@16
|
491 function, this_handler->handler_);
|
Chris@16
|
492 }
|
Chris@16
|
493 } // namespace detail
|
Chris@16
|
494
|
Chris@16
|
495 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
|
Chris@16
|
496 BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
|
Chris@16
|
497 void (boost::system::error_code, std::size_t))
|
Chris@16
|
498 async_read_until(AsyncReadStream& s,
|
Chris@16
|
499 boost::asio::basic_streambuf<Allocator>& b, char delim,
|
Chris@16
|
500 BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
|
Chris@16
|
501 {
|
Chris@16
|
502 // If you get an error on the following line it means that your handler does
|
Chris@16
|
503 // not meet the documented type requirements for a ReadHandler.
|
Chris@16
|
504 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
|
Chris@16
|
505
|
Chris@16
|
506 detail::async_result_init<
|
Chris@16
|
507 ReadHandler, void (boost::system::error_code, std::size_t)> init(
|
Chris@16
|
508 BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
|
Chris@16
|
509
|
Chris@16
|
510 detail::read_until_delim_op<AsyncReadStream,
|
Chris@16
|
511 Allocator, BOOST_ASIO_HANDLER_TYPE(ReadHandler,
|
Chris@16
|
512 void (boost::system::error_code, std::size_t))>(
|
Chris@16
|
513 s, b, delim, init.handler)(
|
Chris@16
|
514 boost::system::error_code(), 0, 1);
|
Chris@16
|
515
|
Chris@16
|
516 return init.result.get();
|
Chris@16
|
517 }
|
Chris@16
|
518
|
Chris@16
|
519 namespace detail
|
Chris@16
|
520 {
|
Chris@16
|
521 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
|
Chris@16
|
522 class read_until_delim_string_op
|
Chris@16
|
523 {
|
Chris@16
|
524 public:
|
Chris@16
|
525 read_until_delim_string_op(AsyncReadStream& stream,
|
Chris@16
|
526 boost::asio::basic_streambuf<Allocator>& streambuf,
|
Chris@16
|
527 const std::string& delim, ReadHandler& handler)
|
Chris@16
|
528 : stream_(stream),
|
Chris@16
|
529 streambuf_(streambuf),
|
Chris@16
|
530 delim_(delim),
|
Chris@16
|
531 start_(0),
|
Chris@16
|
532 search_position_(0),
|
Chris@16
|
533 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
|
Chris@16
|
534 {
|
Chris@16
|
535 }
|
Chris@16
|
536
|
Chris@16
|
537 #if defined(BOOST_ASIO_HAS_MOVE)
|
Chris@16
|
538 read_until_delim_string_op(const read_until_delim_string_op& other)
|
Chris@16
|
539 : stream_(other.stream_),
|
Chris@16
|
540 streambuf_(other.streambuf_),
|
Chris@16
|
541 delim_(other.delim_),
|
Chris@16
|
542 start_(other.start_),
|
Chris@16
|
543 search_position_(other.search_position_),
|
Chris@16
|
544 handler_(other.handler_)
|
Chris@16
|
545 {
|
Chris@16
|
546 }
|
Chris@16
|
547
|
Chris@16
|
548 read_until_delim_string_op(read_until_delim_string_op&& other)
|
Chris@16
|
549 : stream_(other.stream_),
|
Chris@16
|
550 streambuf_(other.streambuf_),
|
Chris@16
|
551 delim_(BOOST_ASIO_MOVE_CAST(std::string)(other.delim_)),
|
Chris@16
|
552 start_(other.start_),
|
Chris@16
|
553 search_position_(other.search_position_),
|
Chris@16
|
554 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
|
Chris@16
|
555 {
|
Chris@16
|
556 }
|
Chris@16
|
557 #endif // defined(BOOST_ASIO_HAS_MOVE)
|
Chris@16
|
558
|
Chris@16
|
559 void operator()(const boost::system::error_code& ec,
|
Chris@16
|
560 std::size_t bytes_transferred, int start = 0)
|
Chris@16
|
561 {
|
Chris@16
|
562 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
|
Chris@16
|
563 std::size_t bytes_to_read;
|
Chris@16
|
564 switch (start_ = start)
|
Chris@16
|
565 {
|
Chris@16
|
566 case 1:
|
Chris@16
|
567 for (;;)
|
Chris@16
|
568 {
|
Chris@16
|
569 {
|
Chris@16
|
570 // Determine the range of the data to be searched.
|
Chris@16
|
571 typedef typename boost::asio::basic_streambuf<
|
Chris@16
|
572 Allocator>::const_buffers_type const_buffers_type;
|
Chris@16
|
573 typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
|
Chris@16
|
574 const_buffers_type buffers = streambuf_.data();
|
Chris@16
|
575 iterator begin = iterator::begin(buffers);
|
Chris@16
|
576 iterator start_pos = begin + search_position_;
|
Chris@16
|
577 iterator end = iterator::end(buffers);
|
Chris@16
|
578
|
Chris@16
|
579 // Look for a match.
|
Chris@16
|
580 std::pair<iterator, bool> result = detail::partial_search(
|
Chris@16
|
581 start_pos, end, delim_.begin(), delim_.end());
|
Chris@16
|
582 if (result.first != end && result.second)
|
Chris@16
|
583 {
|
Chris@16
|
584 // Full match. We're done.
|
Chris@16
|
585 search_position_ = result.first - begin + delim_.length();
|
Chris@16
|
586 bytes_to_read = 0;
|
Chris@16
|
587 }
|
Chris@16
|
588
|
Chris@16
|
589 // No match yet. Check if buffer is full.
|
Chris@16
|
590 else if (streambuf_.size() == streambuf_.max_size())
|
Chris@16
|
591 {
|
Chris@16
|
592 search_position_ = not_found;
|
Chris@16
|
593 bytes_to_read = 0;
|
Chris@16
|
594 }
|
Chris@16
|
595
|
Chris@16
|
596 // Need to read some more data.
|
Chris@16
|
597 else
|
Chris@16
|
598 {
|
Chris@16
|
599 if (result.first != end)
|
Chris@16
|
600 {
|
Chris@16
|
601 // Partial match. Next search needs to start from beginning of
|
Chris@16
|
602 // match.
|
Chris@16
|
603 search_position_ = result.first - begin;
|
Chris@16
|
604 }
|
Chris@16
|
605 else
|
Chris@16
|
606 {
|
Chris@16
|
607 // Next search can start with the new data.
|
Chris@16
|
608 search_position_ = end - begin;
|
Chris@16
|
609 }
|
Chris@16
|
610
|
Chris@16
|
611 bytes_to_read = read_size_helper(streambuf_, 65536);
|
Chris@16
|
612 }
|
Chris@16
|
613 }
|
Chris@16
|
614
|
Chris@16
|
615 // Check if we're done.
|
Chris@16
|
616 if (!start && bytes_to_read == 0)
|
Chris@16
|
617 break;
|
Chris@16
|
618
|
Chris@16
|
619 // Start a new asynchronous read operation to obtain more data.
|
Chris@16
|
620 stream_.async_read_some(streambuf_.prepare(bytes_to_read),
|
Chris@16
|
621 BOOST_ASIO_MOVE_CAST(read_until_delim_string_op)(*this));
|
Chris@16
|
622 return; default:
|
Chris@16
|
623 streambuf_.commit(bytes_transferred);
|
Chris@16
|
624 if (ec || bytes_transferred == 0)
|
Chris@16
|
625 break;
|
Chris@16
|
626 }
|
Chris@16
|
627
|
Chris@16
|
628 const boost::system::error_code result_ec =
|
Chris@16
|
629 (search_position_ == not_found)
|
Chris@16
|
630 ? error::not_found : ec;
|
Chris@16
|
631
|
Chris@16
|
632 const std::size_t result_n =
|
Chris@16
|
633 (ec || search_position_ == not_found)
|
Chris@16
|
634 ? 0 : search_position_;
|
Chris@16
|
635
|
Chris@16
|
636 handler_(result_ec, result_n);
|
Chris@16
|
637 }
|
Chris@16
|
638 }
|
Chris@16
|
639
|
Chris@16
|
640 //private:
|
Chris@16
|
641 AsyncReadStream& stream_;
|
Chris@16
|
642 boost::asio::basic_streambuf<Allocator>& streambuf_;
|
Chris@16
|
643 std::string delim_;
|
Chris@16
|
644 int start_;
|
Chris@16
|
645 std::size_t search_position_;
|
Chris@16
|
646 ReadHandler handler_;
|
Chris@16
|
647 };
|
Chris@16
|
648
|
Chris@16
|
649 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
|
Chris@16
|
650 inline void* asio_handler_allocate(std::size_t size,
|
Chris@16
|
651 read_until_delim_string_op<AsyncReadStream,
|
Chris@16
|
652 Allocator, ReadHandler>* this_handler)
|
Chris@16
|
653 {
|
Chris@16
|
654 return boost_asio_handler_alloc_helpers::allocate(
|
Chris@16
|
655 size, this_handler->handler_);
|
Chris@16
|
656 }
|
Chris@16
|
657
|
Chris@16
|
658 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
|
Chris@16
|
659 inline void asio_handler_deallocate(void* pointer, std::size_t size,
|
Chris@16
|
660 read_until_delim_string_op<AsyncReadStream,
|
Chris@16
|
661 Allocator, ReadHandler>* this_handler)
|
Chris@16
|
662 {
|
Chris@16
|
663 boost_asio_handler_alloc_helpers::deallocate(
|
Chris@16
|
664 pointer, size, this_handler->handler_);
|
Chris@16
|
665 }
|
Chris@16
|
666
|
Chris@16
|
667 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
|
Chris@16
|
668 inline bool asio_handler_is_continuation(
|
Chris@16
|
669 read_until_delim_string_op<AsyncReadStream,
|
Chris@16
|
670 Allocator, ReadHandler>* this_handler)
|
Chris@16
|
671 {
|
Chris@16
|
672 return this_handler->start_ == 0 ? true
|
Chris@16
|
673 : boost_asio_handler_cont_helpers::is_continuation(
|
Chris@16
|
674 this_handler->handler_);
|
Chris@16
|
675 }
|
Chris@16
|
676
|
Chris@16
|
677 template <typename Function, typename AsyncReadStream,
|
Chris@16
|
678 typename Allocator, typename ReadHandler>
|
Chris@16
|
679 inline void asio_handler_invoke(Function& function,
|
Chris@16
|
680 read_until_delim_string_op<AsyncReadStream,
|
Chris@16
|
681 Allocator, ReadHandler>* this_handler)
|
Chris@16
|
682 {
|
Chris@16
|
683 boost_asio_handler_invoke_helpers::invoke(
|
Chris@16
|
684 function, this_handler->handler_);
|
Chris@16
|
685 }
|
Chris@16
|
686
|
Chris@16
|
687 template <typename Function, typename AsyncReadStream,
|
Chris@16
|
688 typename Allocator, typename ReadHandler>
|
Chris@16
|
689 inline void asio_handler_invoke(const Function& function,
|
Chris@16
|
690 read_until_delim_string_op<AsyncReadStream,
|
Chris@16
|
691 Allocator, ReadHandler>* this_handler)
|
Chris@16
|
692 {
|
Chris@16
|
693 boost_asio_handler_invoke_helpers::invoke(
|
Chris@16
|
694 function, this_handler->handler_);
|
Chris@16
|
695 }
|
Chris@16
|
696 } // namespace detail
|
Chris@16
|
697
|
Chris@16
|
698 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
|
Chris@16
|
699 BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
|
Chris@16
|
700 void (boost::system::error_code, std::size_t))
|
Chris@16
|
701 async_read_until(AsyncReadStream& s,
|
Chris@16
|
702 boost::asio::basic_streambuf<Allocator>& b, const std::string& delim,
|
Chris@16
|
703 BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
|
Chris@16
|
704 {
|
Chris@16
|
705 // If you get an error on the following line it means that your handler does
|
Chris@16
|
706 // not meet the documented type requirements for a ReadHandler.
|
Chris@16
|
707 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
|
Chris@16
|
708
|
Chris@16
|
709 detail::async_result_init<
|
Chris@16
|
710 ReadHandler, void (boost::system::error_code, std::size_t)> init(
|
Chris@16
|
711 BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
|
Chris@16
|
712
|
Chris@16
|
713 detail::read_until_delim_string_op<AsyncReadStream,
|
Chris@16
|
714 Allocator, BOOST_ASIO_HANDLER_TYPE(ReadHandler,
|
Chris@16
|
715 void (boost::system::error_code, std::size_t))>(
|
Chris@16
|
716 s, b, delim, init.handler)(
|
Chris@16
|
717 boost::system::error_code(), 0, 1);
|
Chris@16
|
718
|
Chris@16
|
719 return init.result.get();
|
Chris@16
|
720 }
|
Chris@16
|
721
|
Chris@16
|
722 #if defined(BOOST_ASIO_HAS_BOOST_REGEX)
|
Chris@16
|
723
|
Chris@16
|
724 namespace detail
|
Chris@16
|
725 {
|
Chris@16
|
726 template <typename AsyncReadStream, typename Allocator,
|
Chris@16
|
727 typename RegEx, typename ReadHandler>
|
Chris@16
|
728 class read_until_expr_op
|
Chris@16
|
729 {
|
Chris@16
|
730 public:
|
Chris@16
|
731 read_until_expr_op(AsyncReadStream& stream,
|
Chris@16
|
732 boost::asio::basic_streambuf<Allocator>& streambuf,
|
Chris@16
|
733 const boost::regex& expr, ReadHandler& handler)
|
Chris@16
|
734 : stream_(stream),
|
Chris@16
|
735 streambuf_(streambuf),
|
Chris@16
|
736 expr_(expr),
|
Chris@16
|
737 start_(0),
|
Chris@16
|
738 search_position_(0),
|
Chris@16
|
739 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
|
Chris@16
|
740 {
|
Chris@16
|
741 }
|
Chris@16
|
742
|
Chris@16
|
743 #if defined(BOOST_ASIO_HAS_MOVE)
|
Chris@16
|
744 read_until_expr_op(const read_until_expr_op& other)
|
Chris@16
|
745 : stream_(other.stream_),
|
Chris@16
|
746 streambuf_(other.streambuf_),
|
Chris@16
|
747 expr_(other.expr_),
|
Chris@16
|
748 start_(other.start_),
|
Chris@16
|
749 search_position_(other.search_position_),
|
Chris@16
|
750 handler_(other.handler_)
|
Chris@16
|
751 {
|
Chris@16
|
752 }
|
Chris@16
|
753
|
Chris@16
|
754 read_until_expr_op(read_until_expr_op&& other)
|
Chris@16
|
755 : stream_(other.stream_),
|
Chris@16
|
756 streambuf_(other.streambuf_),
|
Chris@16
|
757 expr_(other.expr_),
|
Chris@16
|
758 start_(other.start_),
|
Chris@16
|
759 search_position_(other.search_position_),
|
Chris@16
|
760 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
|
Chris@16
|
761 {
|
Chris@16
|
762 }
|
Chris@16
|
763 #endif // defined(BOOST_ASIO_HAS_MOVE)
|
Chris@16
|
764
|
Chris@16
|
765 void operator()(const boost::system::error_code& ec,
|
Chris@16
|
766 std::size_t bytes_transferred, int start = 0)
|
Chris@16
|
767 {
|
Chris@16
|
768 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
|
Chris@16
|
769 std::size_t bytes_to_read;
|
Chris@16
|
770 switch (start_ = start)
|
Chris@16
|
771 {
|
Chris@16
|
772 case 1:
|
Chris@16
|
773 for (;;)
|
Chris@16
|
774 {
|
Chris@16
|
775 {
|
Chris@16
|
776 // Determine the range of the data to be searched.
|
Chris@16
|
777 typedef typename boost::asio::basic_streambuf<
|
Chris@16
|
778 Allocator>::const_buffers_type const_buffers_type;
|
Chris@16
|
779 typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
|
Chris@16
|
780 const_buffers_type buffers = streambuf_.data();
|
Chris@16
|
781 iterator begin = iterator::begin(buffers);
|
Chris@16
|
782 iterator start_pos = begin + search_position_;
|
Chris@16
|
783 iterator end = iterator::end(buffers);
|
Chris@16
|
784
|
Chris@16
|
785 // Look for a match.
|
Chris@16
|
786 boost::match_results<iterator,
|
Chris@16
|
787 typename std::vector<boost::sub_match<iterator> >::allocator_type>
|
Chris@16
|
788 match_results;
|
Chris@16
|
789 bool match = regex_search(start_pos, end, match_results, expr_,
|
Chris@16
|
790 boost::match_default | boost::match_partial);
|
Chris@16
|
791 if (match && match_results[0].matched)
|
Chris@16
|
792 {
|
Chris@16
|
793 // Full match. We're done.
|
Chris@16
|
794 search_position_ = match_results[0].second - begin;
|
Chris@16
|
795 bytes_to_read = 0;
|
Chris@16
|
796 }
|
Chris@16
|
797
|
Chris@16
|
798 // No match yet. Check if buffer is full.
|
Chris@16
|
799 else if (streambuf_.size() == streambuf_.max_size())
|
Chris@16
|
800 {
|
Chris@16
|
801 search_position_ = not_found;
|
Chris@16
|
802 bytes_to_read = 0;
|
Chris@16
|
803 }
|
Chris@16
|
804
|
Chris@16
|
805 // Need to read some more data.
|
Chris@16
|
806 else
|
Chris@16
|
807 {
|
Chris@16
|
808 if (match)
|
Chris@16
|
809 {
|
Chris@16
|
810 // Partial match. Next search needs to start from beginning of
|
Chris@16
|
811 // match.
|
Chris@16
|
812 search_position_ = match_results[0].first - begin;
|
Chris@16
|
813 }
|
Chris@16
|
814 else
|
Chris@16
|
815 {
|
Chris@16
|
816 // Next search can start with the new data.
|
Chris@16
|
817 search_position_ = end - begin;
|
Chris@16
|
818 }
|
Chris@16
|
819
|
Chris@16
|
820 bytes_to_read = read_size_helper(streambuf_, 65536);
|
Chris@16
|
821 }
|
Chris@16
|
822 }
|
Chris@16
|
823
|
Chris@16
|
824 // Check if we're done.
|
Chris@16
|
825 if (!start && bytes_to_read == 0)
|
Chris@16
|
826 break;
|
Chris@16
|
827
|
Chris@16
|
828 // Start a new asynchronous read operation to obtain more data.
|
Chris@16
|
829 stream_.async_read_some(streambuf_.prepare(bytes_to_read),
|
Chris@16
|
830 BOOST_ASIO_MOVE_CAST(read_until_expr_op)(*this));
|
Chris@16
|
831 return; default:
|
Chris@16
|
832 streambuf_.commit(bytes_transferred);
|
Chris@16
|
833 if (ec || bytes_transferred == 0)
|
Chris@16
|
834 break;
|
Chris@16
|
835 }
|
Chris@16
|
836
|
Chris@16
|
837 const boost::system::error_code result_ec =
|
Chris@16
|
838 (search_position_ == not_found)
|
Chris@16
|
839 ? error::not_found : ec;
|
Chris@16
|
840
|
Chris@16
|
841 const std::size_t result_n =
|
Chris@16
|
842 (ec || search_position_ == not_found)
|
Chris@16
|
843 ? 0 : search_position_;
|
Chris@16
|
844
|
Chris@16
|
845 handler_(result_ec, result_n);
|
Chris@16
|
846 }
|
Chris@16
|
847 }
|
Chris@16
|
848
|
Chris@16
|
849 //private:
|
Chris@16
|
850 AsyncReadStream& stream_;
|
Chris@16
|
851 boost::asio::basic_streambuf<Allocator>& streambuf_;
|
Chris@16
|
852 RegEx expr_;
|
Chris@16
|
853 int start_;
|
Chris@16
|
854 std::size_t search_position_;
|
Chris@16
|
855 ReadHandler handler_;
|
Chris@16
|
856 };
|
Chris@16
|
857
|
Chris@16
|
858 template <typename AsyncReadStream, typename Allocator,
|
Chris@16
|
859 typename RegEx, typename ReadHandler>
|
Chris@16
|
860 inline void* asio_handler_allocate(std::size_t size,
|
Chris@16
|
861 read_until_expr_op<AsyncReadStream,
|
Chris@16
|
862 Allocator, RegEx, ReadHandler>* this_handler)
|
Chris@16
|
863 {
|
Chris@16
|
864 return boost_asio_handler_alloc_helpers::allocate(
|
Chris@16
|
865 size, this_handler->handler_);
|
Chris@16
|
866 }
|
Chris@16
|
867
|
Chris@16
|
868 template <typename AsyncReadStream, typename Allocator,
|
Chris@16
|
869 typename RegEx, typename ReadHandler>
|
Chris@16
|
870 inline void asio_handler_deallocate(void* pointer, std::size_t size,
|
Chris@16
|
871 read_until_expr_op<AsyncReadStream,
|
Chris@16
|
872 Allocator, RegEx, ReadHandler>* this_handler)
|
Chris@16
|
873 {
|
Chris@16
|
874 boost_asio_handler_alloc_helpers::deallocate(
|
Chris@16
|
875 pointer, size, this_handler->handler_);
|
Chris@16
|
876 }
|
Chris@16
|
877
|
Chris@16
|
878 template <typename AsyncReadStream, typename Allocator,
|
Chris@16
|
879 typename RegEx, typename ReadHandler>
|
Chris@16
|
880 inline bool asio_handler_is_continuation(
|
Chris@16
|
881 read_until_expr_op<AsyncReadStream,
|
Chris@16
|
882 Allocator, RegEx, ReadHandler>* this_handler)
|
Chris@16
|
883 {
|
Chris@16
|
884 return this_handler->start_ == 0 ? true
|
Chris@16
|
885 : boost_asio_handler_cont_helpers::is_continuation(
|
Chris@16
|
886 this_handler->handler_);
|
Chris@16
|
887 }
|
Chris@16
|
888
|
Chris@16
|
889 template <typename Function, typename AsyncReadStream, typename Allocator,
|
Chris@16
|
890 typename RegEx, typename ReadHandler>
|
Chris@16
|
891 inline void asio_handler_invoke(Function& function,
|
Chris@16
|
892 read_until_expr_op<AsyncReadStream,
|
Chris@16
|
893 Allocator, RegEx, ReadHandler>* this_handler)
|
Chris@16
|
894 {
|
Chris@16
|
895 boost_asio_handler_invoke_helpers::invoke(
|
Chris@16
|
896 function, this_handler->handler_);
|
Chris@16
|
897 }
|
Chris@16
|
898
|
Chris@16
|
899 template <typename Function, typename AsyncReadStream, typename Allocator,
|
Chris@16
|
900 typename RegEx, typename ReadHandler>
|
Chris@16
|
901 inline void asio_handler_invoke(const Function& function,
|
Chris@16
|
902 read_until_expr_op<AsyncReadStream,
|
Chris@16
|
903 Allocator, RegEx, ReadHandler>* this_handler)
|
Chris@16
|
904 {
|
Chris@16
|
905 boost_asio_handler_invoke_helpers::invoke(
|
Chris@16
|
906 function, this_handler->handler_);
|
Chris@16
|
907 }
|
Chris@16
|
908 } // namespace detail
|
Chris@16
|
909
|
Chris@16
|
910 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
|
Chris@16
|
911 BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
|
Chris@16
|
912 void (boost::system::error_code, std::size_t))
|
Chris@16
|
913 async_read_until(AsyncReadStream& s,
|
Chris@16
|
914 boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
|
Chris@16
|
915 BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
|
Chris@16
|
916 {
|
Chris@16
|
917 // If you get an error on the following line it means that your handler does
|
Chris@16
|
918 // not meet the documented type requirements for a ReadHandler.
|
Chris@16
|
919 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
|
Chris@16
|
920
|
Chris@16
|
921 detail::async_result_init<
|
Chris@16
|
922 ReadHandler, void (boost::system::error_code, std::size_t)> init(
|
Chris@16
|
923 BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
|
Chris@16
|
924
|
Chris@16
|
925 detail::read_until_expr_op<AsyncReadStream, Allocator,
|
Chris@16
|
926 boost::regex, BOOST_ASIO_HANDLER_TYPE(ReadHandler,
|
Chris@16
|
927 void (boost::system::error_code, std::size_t))>(
|
Chris@16
|
928 s, b, expr, init.handler)(
|
Chris@16
|
929 boost::system::error_code(), 0, 1);
|
Chris@16
|
930
|
Chris@16
|
931 return init.result.get();
|
Chris@16
|
932 }
|
Chris@16
|
933
|
Chris@16
|
934 #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX)
|
Chris@16
|
935
|
Chris@16
|
936 namespace detail
|
Chris@16
|
937 {
|
Chris@16
|
938 template <typename AsyncReadStream, typename Allocator,
|
Chris@16
|
939 typename MatchCondition, typename ReadHandler>
|
Chris@16
|
940 class read_until_match_op
|
Chris@16
|
941 {
|
Chris@16
|
942 public:
|
Chris@16
|
943 read_until_match_op(AsyncReadStream& stream,
|
Chris@16
|
944 boost::asio::basic_streambuf<Allocator>& streambuf,
|
Chris@16
|
945 MatchCondition match_condition, ReadHandler& handler)
|
Chris@16
|
946 : stream_(stream),
|
Chris@16
|
947 streambuf_(streambuf),
|
Chris@16
|
948 match_condition_(match_condition),
|
Chris@16
|
949 start_(0),
|
Chris@16
|
950 search_position_(0),
|
Chris@16
|
951 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
|
Chris@16
|
952 {
|
Chris@16
|
953 }
|
Chris@16
|
954
|
Chris@16
|
955 #if defined(BOOST_ASIO_HAS_MOVE)
|
Chris@16
|
956 read_until_match_op(const read_until_match_op& other)
|
Chris@16
|
957 : stream_(other.stream_),
|
Chris@16
|
958 streambuf_(other.streambuf_),
|
Chris@16
|
959 match_condition_(other.match_condition_),
|
Chris@16
|
960 start_(other.start_),
|
Chris@16
|
961 search_position_(other.search_position_),
|
Chris@16
|
962 handler_(other.handler_)
|
Chris@16
|
963 {
|
Chris@16
|
964 }
|
Chris@16
|
965
|
Chris@16
|
966 read_until_match_op(read_until_match_op&& other)
|
Chris@16
|
967 : stream_(other.stream_),
|
Chris@16
|
968 streambuf_(other.streambuf_),
|
Chris@16
|
969 match_condition_(other.match_condition_),
|
Chris@16
|
970 start_(other.start_),
|
Chris@16
|
971 search_position_(other.search_position_),
|
Chris@16
|
972 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
|
Chris@16
|
973 {
|
Chris@16
|
974 }
|
Chris@16
|
975 #endif // defined(BOOST_ASIO_HAS_MOVE)
|
Chris@16
|
976
|
Chris@16
|
977 void operator()(const boost::system::error_code& ec,
|
Chris@16
|
978 std::size_t bytes_transferred, int start = 0)
|
Chris@16
|
979 {
|
Chris@16
|
980 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
|
Chris@16
|
981 std::size_t bytes_to_read;
|
Chris@16
|
982 switch (start_ = start)
|
Chris@16
|
983 {
|
Chris@16
|
984 case 1:
|
Chris@16
|
985 for (;;)
|
Chris@16
|
986 {
|
Chris@16
|
987 {
|
Chris@16
|
988 // Determine the range of the data to be searched.
|
Chris@16
|
989 typedef typename boost::asio::basic_streambuf<
|
Chris@16
|
990 Allocator>::const_buffers_type const_buffers_type;
|
Chris@16
|
991 typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
|
Chris@16
|
992 const_buffers_type buffers = streambuf_.data();
|
Chris@16
|
993 iterator begin = iterator::begin(buffers);
|
Chris@16
|
994 iterator start_pos = begin + search_position_;
|
Chris@16
|
995 iterator end = iterator::end(buffers);
|
Chris@16
|
996
|
Chris@16
|
997 // Look for a match.
|
Chris@16
|
998 std::pair<iterator, bool> result = match_condition_(start_pos, end);
|
Chris@16
|
999 if (result.second)
|
Chris@16
|
1000 {
|
Chris@16
|
1001 // Full match. We're done.
|
Chris@16
|
1002 search_position_ = result.first - begin;
|
Chris@16
|
1003 bytes_to_read = 0;
|
Chris@16
|
1004 }
|
Chris@16
|
1005
|
Chris@16
|
1006 // No match yet. Check if buffer is full.
|
Chris@16
|
1007 else if (streambuf_.size() == streambuf_.max_size())
|
Chris@16
|
1008 {
|
Chris@16
|
1009 search_position_ = not_found;
|
Chris@16
|
1010 bytes_to_read = 0;
|
Chris@16
|
1011 }
|
Chris@16
|
1012
|
Chris@16
|
1013 // Need to read some more data.
|
Chris@16
|
1014 else
|
Chris@16
|
1015 {
|
Chris@16
|
1016 if (result.first != end)
|
Chris@16
|
1017 {
|
Chris@16
|
1018 // Partial match. Next search needs to start from beginning of
|
Chris@16
|
1019 // match.
|
Chris@16
|
1020 search_position_ = result.first - begin;
|
Chris@16
|
1021 }
|
Chris@16
|
1022 else
|
Chris@16
|
1023 {
|
Chris@16
|
1024 // Next search can start with the new data.
|
Chris@16
|
1025 search_position_ = end - begin;
|
Chris@16
|
1026 }
|
Chris@16
|
1027
|
Chris@16
|
1028 bytes_to_read = read_size_helper(streambuf_, 65536);
|
Chris@16
|
1029 }
|
Chris@16
|
1030 }
|
Chris@16
|
1031
|
Chris@16
|
1032 // Check if we're done.
|
Chris@16
|
1033 if (!start && bytes_to_read == 0)
|
Chris@16
|
1034 break;
|
Chris@16
|
1035
|
Chris@16
|
1036 // Start a new asynchronous read operation to obtain more data.
|
Chris@16
|
1037 stream_.async_read_some(streambuf_.prepare(bytes_to_read),
|
Chris@16
|
1038 BOOST_ASIO_MOVE_CAST(read_until_match_op)(*this));
|
Chris@16
|
1039 return; default:
|
Chris@16
|
1040 streambuf_.commit(bytes_transferred);
|
Chris@16
|
1041 if (ec || bytes_transferred == 0)
|
Chris@16
|
1042 break;
|
Chris@16
|
1043 }
|
Chris@16
|
1044
|
Chris@16
|
1045 const boost::system::error_code result_ec =
|
Chris@16
|
1046 (search_position_ == not_found)
|
Chris@16
|
1047 ? error::not_found : ec;
|
Chris@16
|
1048
|
Chris@16
|
1049 const std::size_t result_n =
|
Chris@16
|
1050 (ec || search_position_ == not_found)
|
Chris@16
|
1051 ? 0 : search_position_;
|
Chris@16
|
1052
|
Chris@16
|
1053 handler_(result_ec, result_n);
|
Chris@16
|
1054 }
|
Chris@16
|
1055 }
|
Chris@16
|
1056
|
Chris@16
|
1057 //private:
|
Chris@16
|
1058 AsyncReadStream& stream_;
|
Chris@16
|
1059 boost::asio::basic_streambuf<Allocator>& streambuf_;
|
Chris@16
|
1060 MatchCondition match_condition_;
|
Chris@16
|
1061 int start_;
|
Chris@16
|
1062 std::size_t search_position_;
|
Chris@16
|
1063 ReadHandler handler_;
|
Chris@16
|
1064 };
|
Chris@16
|
1065
|
Chris@16
|
1066 template <typename AsyncReadStream, typename Allocator,
|
Chris@16
|
1067 typename MatchCondition, typename ReadHandler>
|
Chris@16
|
1068 inline void* asio_handler_allocate(std::size_t size,
|
Chris@16
|
1069 read_until_match_op<AsyncReadStream,
|
Chris@16
|
1070 Allocator, MatchCondition, ReadHandler>* this_handler)
|
Chris@16
|
1071 {
|
Chris@16
|
1072 return boost_asio_handler_alloc_helpers::allocate(
|
Chris@16
|
1073 size, this_handler->handler_);
|
Chris@16
|
1074 }
|
Chris@16
|
1075
|
Chris@16
|
1076 template <typename AsyncReadStream, typename Allocator,
|
Chris@16
|
1077 typename MatchCondition, typename ReadHandler>
|
Chris@16
|
1078 inline void asio_handler_deallocate(void* pointer, std::size_t size,
|
Chris@16
|
1079 read_until_match_op<AsyncReadStream,
|
Chris@16
|
1080 Allocator, MatchCondition, ReadHandler>* this_handler)
|
Chris@16
|
1081 {
|
Chris@16
|
1082 boost_asio_handler_alloc_helpers::deallocate(
|
Chris@16
|
1083 pointer, size, this_handler->handler_);
|
Chris@16
|
1084 }
|
Chris@16
|
1085
|
Chris@16
|
1086 template <typename AsyncReadStream, typename Allocator,
|
Chris@16
|
1087 typename MatchCondition, typename ReadHandler>
|
Chris@16
|
1088 inline bool asio_handler_is_continuation(
|
Chris@16
|
1089 read_until_match_op<AsyncReadStream,
|
Chris@16
|
1090 Allocator, MatchCondition, ReadHandler>* this_handler)
|
Chris@16
|
1091 {
|
Chris@16
|
1092 return this_handler->start_ == 0 ? true
|
Chris@16
|
1093 : boost_asio_handler_cont_helpers::is_continuation(
|
Chris@16
|
1094 this_handler->handler_);
|
Chris@16
|
1095 }
|
Chris@16
|
1096
|
Chris@16
|
1097 template <typename Function, typename AsyncReadStream, typename Allocator,
|
Chris@16
|
1098 typename MatchCondition, typename ReadHandler>
|
Chris@16
|
1099 inline void asio_handler_invoke(Function& function,
|
Chris@16
|
1100 read_until_match_op<AsyncReadStream,
|
Chris@16
|
1101 Allocator, MatchCondition, ReadHandler>* this_handler)
|
Chris@16
|
1102 {
|
Chris@16
|
1103 boost_asio_handler_invoke_helpers::invoke(
|
Chris@16
|
1104 function, this_handler->handler_);
|
Chris@16
|
1105 }
|
Chris@16
|
1106
|
Chris@16
|
1107 template <typename Function, typename AsyncReadStream, typename Allocator,
|
Chris@16
|
1108 typename MatchCondition, typename ReadHandler>
|
Chris@16
|
1109 inline void asio_handler_invoke(const Function& function,
|
Chris@16
|
1110 read_until_match_op<AsyncReadStream,
|
Chris@16
|
1111 Allocator, MatchCondition, ReadHandler>* this_handler)
|
Chris@16
|
1112 {
|
Chris@16
|
1113 boost_asio_handler_invoke_helpers::invoke(
|
Chris@16
|
1114 function, this_handler->handler_);
|
Chris@16
|
1115 }
|
Chris@16
|
1116 } // namespace detail
|
Chris@16
|
1117
|
Chris@16
|
1118 template <typename AsyncReadStream, typename Allocator,
|
Chris@16
|
1119 typename MatchCondition, typename ReadHandler>
|
Chris@16
|
1120 BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
|
Chris@16
|
1121 void (boost::system::error_code, std::size_t))
|
Chris@16
|
1122 async_read_until(AsyncReadStream& s,
|
Chris@16
|
1123 boost::asio::basic_streambuf<Allocator>& b,
|
Chris@16
|
1124 MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler,
|
Chris@16
|
1125 typename enable_if<is_match_condition<MatchCondition>::value>::type*)
|
Chris@16
|
1126 {
|
Chris@16
|
1127 // If you get an error on the following line it means that your handler does
|
Chris@16
|
1128 // not meet the documented type requirements for a ReadHandler.
|
Chris@16
|
1129 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
|
Chris@16
|
1130
|
Chris@16
|
1131 detail::async_result_init<
|
Chris@16
|
1132 ReadHandler, void (boost::system::error_code, std::size_t)> init(
|
Chris@16
|
1133 BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
|
Chris@16
|
1134
|
Chris@16
|
1135 detail::read_until_match_op<AsyncReadStream, Allocator,
|
Chris@16
|
1136 MatchCondition, BOOST_ASIO_HANDLER_TYPE(ReadHandler,
|
Chris@16
|
1137 void (boost::system::error_code, std::size_t))>(
|
Chris@16
|
1138 s, b, match_condition, init.handler)(
|
Chris@16
|
1139 boost::system::error_code(), 0, 1);
|
Chris@16
|
1140
|
Chris@16
|
1141 return init.result.get();
|
Chris@16
|
1142 }
|
Chris@16
|
1143
|
Chris@16
|
1144 } // namespace asio
|
Chris@16
|
1145 } // namespace boost
|
Chris@16
|
1146
|
Chris@16
|
1147 #include <boost/asio/detail/pop_options.hpp>
|
Chris@16
|
1148
|
Chris@16
|
1149 #endif // BOOST_ASIO_IMPL_READ_UNTIL_HPP
|