5
// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
7
// Distributed under the Boost Software License, Version 1.0. (See accompanying
8
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
11
#ifndef ASIO_READ_UNTIL_IPP
12
#define ASIO_READ_UNTIL_IPP
14
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
16
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
18
#include "asio/detail/push_options.hpp"
20
#include "asio/detail/push_options.hpp"
25
#include "asio/detail/pop_options.hpp"
27
#include "asio/buffer.hpp"
28
#include "asio/buffers_iterator.hpp"
29
#include "asio/detail/bind_handler.hpp"
30
#include "asio/detail/handler_alloc_helpers.hpp"
31
#include "asio/detail/handler_invoke_helpers.hpp"
32
#include "asio/detail/throw_error.hpp"
36
template <typename SyncReadStream, typename Allocator>
37
inline std::size_t read_until(SyncReadStream& s,
38
asio::basic_streambuf<Allocator>& b, char delim)
41
std::size_t bytes_transferred = read_until(s, b, delim, ec);
42
asio::detail::throw_error(ec);
43
return bytes_transferred;
46
template <typename SyncReadStream, typename Allocator>
47
std::size_t read_until(SyncReadStream& s,
48
asio::basic_streambuf<Allocator>& b, char delim,
51
std::size_t next_search_start = 0;
54
// Determine the range of the data to be searched.
55
typedef typename asio::basic_streambuf<
56
Allocator>::const_buffers_type const_buffers_type;
57
typedef asio::buffers_iterator<const_buffers_type> iterator;
58
const_buffers_type buffers = b.data();
59
iterator begin = iterator::begin(buffers);
60
iterator start = begin + next_search_start;
61
iterator end = iterator::end(buffers);
64
iterator iter = std::find(start, end, delim);
67
// Found a match. We're done.
68
ec = asio::error_code();
69
return iter - begin + 1;
73
// No match. Next search can start with the new data.
74
next_search_start = end - begin;
77
// Check if buffer is full.
78
if (b.size() == b.max_size())
80
ec = error::not_found;
85
std::size_t bytes_available =
86
std::min<std::size_t>(512, b.max_size() - b.size());
87
b.commit(s.read_some(b.prepare(bytes_available), ec));
93
template <typename SyncReadStream, typename Allocator>
94
inline std::size_t read_until(SyncReadStream& s,
95
asio::basic_streambuf<Allocator>& b, const std::string& delim)
98
std::size_t bytes_transferred = read_until(s, b, delim, ec);
99
asio::detail::throw_error(ec);
100
return bytes_transferred;
105
// Algorithm that finds a subsequence of equal values in a sequence. Returns
106
// (iterator,true) if a full match was found, in which case the iterator
107
// points to the beginning of the match. Returns (iterator,false) if a
108
// partial match was found at the end of the first sequence, in which case
109
// the iterator points to the beginning of the partial match. Returns
110
// (last1,false) if no full or partial match was found.
111
template <typename Iterator1, typename Iterator2>
112
std::pair<Iterator1, bool> partial_search(
113
Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2)
115
for (Iterator1 iter1 = first1; iter1 != last1; ++iter1)
117
Iterator1 test_iter1 = iter1;
118
Iterator2 test_iter2 = first2;
119
for (;; ++test_iter1, ++test_iter2)
121
if (test_iter2 == last2)
122
return std::make_pair(iter1, true);
123
if (test_iter1 == last1)
125
if (test_iter2 != first2)
126
return std::make_pair(iter1, false);
130
if (*test_iter1 != *test_iter2)
134
return std::make_pair(last1, false);
136
} // namespace detail
138
template <typename SyncReadStream, typename Allocator>
139
std::size_t read_until(SyncReadStream& s,
140
asio::basic_streambuf<Allocator>& b, const std::string& delim,
141
asio::error_code& ec)
143
std::size_t next_search_start = 0;
146
// Determine the range of the data to be searched.
147
typedef typename asio::basic_streambuf<
148
Allocator>::const_buffers_type const_buffers_type;
149
typedef asio::buffers_iterator<const_buffers_type> iterator;
150
const_buffers_type buffers = b.data();
151
iterator begin = iterator::begin(buffers);
152
iterator start = begin + next_search_start;
153
iterator end = iterator::end(buffers);
156
std::pair<iterator, bool> result = asio::detail::partial_search(
157
start, end, delim.begin(), delim.end());
158
if (result.first != end)
162
// Full match. We're done.
163
ec = asio::error_code();
164
return result.first - begin + delim.length();
168
// Partial match. Next search needs to start from beginning of match.
169
next_search_start = result.first - begin;
174
// No match. Next search can start with the new data.
175
next_search_start = end - begin;
178
// Check if buffer is full.
179
if (b.size() == b.max_size())
181
ec = error::not_found;
186
std::size_t bytes_available =
187
std::min<std::size_t>(512, b.max_size() - b.size());
188
b.commit(s.read_some(b.prepare(bytes_available), ec));
194
template <typename SyncReadStream, typename Allocator>
195
inline std::size_t read_until(SyncReadStream& s,
196
asio::basic_streambuf<Allocator>& b, const boost::regex& expr)
199
std::size_t bytes_transferred = read_until(s, b, expr, ec);
200
asio::detail::throw_error(ec);
201
return bytes_transferred;
204
template <typename SyncReadStream, typename Allocator>
205
std::size_t read_until(SyncReadStream& s,
206
asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
207
asio::error_code& ec)
209
std::size_t next_search_start = 0;
212
// Determine the range of the data to be searched.
213
typedef typename asio::basic_streambuf<
214
Allocator>::const_buffers_type const_buffers_type;
215
typedef asio::buffers_iterator<const_buffers_type> iterator;
216
const_buffers_type buffers = b.data();
217
iterator begin = iterator::begin(buffers);
218
iterator start = begin + next_search_start;
219
iterator end = iterator::end(buffers);
222
boost::match_results<iterator> match_results;
223
if (boost::regex_search(start, end, match_results, expr,
224
boost::match_default | boost::match_partial))
226
if (match_results[0].matched)
228
// Full match. We're done.
229
ec = asio::error_code();
230
return match_results[0].second - begin;
234
// Partial match. Next search needs to start from beginning of match.
235
next_search_start = match_results[0].first - begin;
240
// No match. Next search can start with the new data.
241
next_search_start = end - begin;
244
// Check if buffer is full.
245
if (b.size() == b.max_size())
247
ec = error::not_found;
252
std::size_t bytes_available =
253
std::min<std::size_t>(512, b.max_size() - b.size());
254
b.commit(s.read_some(b.prepare(bytes_available), ec));
260
template <typename SyncReadStream, typename Allocator, typename MatchCondition>
261
std::size_t read_until(SyncReadStream& s,
262
asio::basic_streambuf<Allocator>& b,
263
MatchCondition match_condition, asio::error_code& ec,
264
typename boost::enable_if<is_match_condition<MatchCondition> >::type*)
266
std::size_t next_search_start = 0;
269
// Determine the range of the data to be searched.
270
typedef typename asio::basic_streambuf<
271
Allocator>::const_buffers_type const_buffers_type;
272
typedef asio::buffers_iterator<const_buffers_type> iterator;
273
const_buffers_type buffers = b.data();
274
iterator begin = iterator::begin(buffers);
275
iterator start = begin + next_search_start;
276
iterator end = iterator::end(buffers);
279
std::pair<iterator, bool> result = match_condition(start, end);
280
if (result.first != end)
284
// Full match. We're done.
285
ec = asio::error_code();
286
return result.first - begin;
290
// Partial match. Next search needs to start from beginning of match.
291
next_search_start = result.first - begin;
296
// No match. Next search can start with the new data.
297
next_search_start = end - begin;
300
// Check if buffer is full.
301
if (b.size() == b.max_size())
303
ec = error::not_found;
308
std::size_t bytes_available =
309
std::min<std::size_t>(512, b.max_size() - b.size());
310
b.commit(s.read_some(b.prepare(bytes_available), ec));
316
template <typename SyncReadStream, typename Allocator, typename MatchCondition>
317
inline std::size_t read_until(SyncReadStream& s,
318
asio::basic_streambuf<Allocator>& b, MatchCondition match_condition,
319
typename boost::enable_if<is_match_condition<MatchCondition> >::type*)
322
std::size_t bytes_transferred = read_until(s, b, match_condition, ec);
323
asio::detail::throw_error(ec);
324
return bytes_transferred;
329
template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
330
class read_until_delim_handler
333
read_until_delim_handler(AsyncReadStream& stream,
334
asio::basic_streambuf<Allocator>& streambuf, char delim,
335
std::size_t next_search_start, ReadHandler handler)
337
streambuf_(streambuf),
339
next_search_start_(next_search_start),
344
void operator()(const asio::error_code& ec,
345
std::size_t bytes_transferred)
350
std::size_t bytes = 0;
355
// Commit received data to streambuf's get area.
356
streambuf_.commit(bytes_transferred);
358
// Determine the range of the data to be searched.
359
typedef typename asio::basic_streambuf<
360
Allocator>::const_buffers_type const_buffers_type;
361
typedef asio::buffers_iterator<const_buffers_type> iterator;
362
const_buffers_type buffers = streambuf_.data();
363
iterator begin = iterator::begin(buffers);
364
iterator start = begin + next_search_start_;
365
iterator end = iterator::end(buffers);
368
iterator iter = std::find(start, end, delim_);
371
// Found a match. We're done.
372
std::size_t bytes = iter - begin + 1;
377
// No match. Check if buffer is full.
378
if (streambuf_.size() == streambuf_.max_size())
380
std::size_t bytes = 0;
381
asio::error_code ec(error::not_found);
386
// Next search can start with the new data.
387
next_search_start_ = end - begin;
389
// Start a new asynchronous read operation to obtain more data.
390
std::size_t bytes_available =
391
std::min<std::size_t>(512, streambuf_.max_size() - streambuf_.size());
392
stream_.async_read_some(streambuf_.prepare(bytes_available), *this);
396
AsyncReadStream& stream_;
397
asio::basic_streambuf<Allocator>& streambuf_;
399
std::size_t next_search_start_;
400
ReadHandler handler_;
403
template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
404
inline void* asio_handler_allocate(std::size_t size,
405
read_until_delim_handler<AsyncReadStream,
406
Allocator, ReadHandler>* this_handler)
408
return asio_handler_alloc_helpers::allocate(
409
size, &this_handler->handler_);
412
template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
413
inline void asio_handler_deallocate(void* pointer, std::size_t size,
414
read_until_delim_handler<AsyncReadStream,
415
Allocator, ReadHandler>* this_handler)
417
asio_handler_alloc_helpers::deallocate(
418
pointer, size, &this_handler->handler_);
421
template <typename Function, typename AsyncReadStream, typename Allocator,
422
typename ReadHandler>
423
inline void asio_handler_invoke(const Function& function,
424
read_until_delim_handler<AsyncReadStream,
425
Allocator, ReadHandler>* this_handler)
427
asio_handler_invoke_helpers::invoke(
428
function, &this_handler->handler_);
430
} // namespace detail
432
template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
433
void async_read_until(AsyncReadStream& s,
434
asio::basic_streambuf<Allocator>& b, char delim, ReadHandler handler)
436
// Determine the range of the data to be searched.
437
typedef typename asio::basic_streambuf<
438
Allocator>::const_buffers_type const_buffers_type;
439
typedef asio::buffers_iterator<const_buffers_type> iterator;
440
const_buffers_type buffers = b.data();
441
iterator begin = iterator::begin(buffers);
442
iterator end = iterator::end(buffers);
445
iterator iter = std::find(begin, end, delim);
448
// Found a match. We're done.
450
std::size_t bytes = iter - begin + 1;
451
s.io_service().post(detail::bind_handler(handler, ec, bytes));
455
// No match. Check if buffer is full.
456
if (b.size() == b.max_size())
458
asio::error_code ec(error::not_found);
459
s.io_service().post(detail::bind_handler(handler, ec, 0));
463
// Start a new asynchronous read operation to obtain more data.
464
std::size_t bytes_available =
465
std::min<std::size_t>(512, b.max_size() - b.size());
466
s.async_read_some(b.prepare(bytes_available),
467
detail::read_until_delim_handler<AsyncReadStream, Allocator, ReadHandler>(
468
s, b, delim, end - begin, handler));
473
template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
474
class read_until_delim_string_handler
477
read_until_delim_string_handler(AsyncReadStream& stream,
478
asio::basic_streambuf<Allocator>& streambuf,
479
const std::string& delim, std::size_t next_search_start,
482
streambuf_(streambuf),
484
next_search_start_(next_search_start),
489
void operator()(const asio::error_code& ec,
490
std::size_t bytes_transferred)
495
std::size_t bytes = 0;
500
// Commit received data to streambuf's get area.
501
streambuf_.commit(bytes_transferred);
503
// Determine the range of the data to be searched.
504
typedef typename asio::basic_streambuf<
505
Allocator>::const_buffers_type const_buffers_type;
506
typedef asio::buffers_iterator<const_buffers_type> iterator;
507
const_buffers_type buffers = streambuf_.data();
508
iterator begin = iterator::begin(buffers);
509
iterator start = begin + next_search_start_;
510
iterator end = iterator::end(buffers);
513
std::pair<iterator, bool> result = asio::detail::partial_search(
514
start, end, delim_.begin(), delim_.end());
515
if (result.first != end)
519
// Full match. We're done.
520
std::size_t bytes = result.first - begin + delim_.length();
526
// Partial match. Next search needs to start from beginning of match.
527
next_search_start_ = result.first - begin;
532
// No match. Next search can start with the new data.
533
next_search_start_ = end - begin;
536
// Check if buffer is full.
537
if (streambuf_.size() == streambuf_.max_size())
539
std::size_t bytes = 0;
540
asio::error_code ec(error::not_found);
545
// Start a new asynchronous read operation to obtain more data.
546
std::size_t bytes_available =
547
std::min<std::size_t>(512, streambuf_.max_size() - streambuf_.size());
548
stream_.async_read_some(streambuf_.prepare(bytes_available), *this);
552
AsyncReadStream& stream_;
553
asio::basic_streambuf<Allocator>& streambuf_;
555
std::size_t next_search_start_;
556
ReadHandler handler_;
559
template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
560
inline void* asio_handler_allocate(std::size_t size,
561
read_until_delim_string_handler<AsyncReadStream,
562
Allocator, ReadHandler>* this_handler)
564
return asio_handler_alloc_helpers::allocate(
565
size, &this_handler->handler_);
568
template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
569
inline void asio_handler_deallocate(void* pointer, std::size_t size,
570
read_until_delim_string_handler<AsyncReadStream,
571
Allocator, ReadHandler>* this_handler)
573
asio_handler_alloc_helpers::deallocate(
574
pointer, size, &this_handler->handler_);
577
template <typename Function, typename AsyncReadStream,
578
typename Allocator, typename ReadHandler>
579
inline void asio_handler_invoke(const Function& function,
580
read_until_delim_string_handler<AsyncReadStream,
581
Allocator, ReadHandler>* this_handler)
583
asio_handler_invoke_helpers::invoke(
584
function, &this_handler->handler_);
586
} // namespace detail
588
template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
589
void async_read_until(AsyncReadStream& s,
590
asio::basic_streambuf<Allocator>& b, const std::string& delim,
593
// Determine the range of the data to be searched.
594
typedef typename asio::basic_streambuf<
595
Allocator>::const_buffers_type const_buffers_type;
596
typedef asio::buffers_iterator<const_buffers_type> iterator;
597
const_buffers_type buffers = b.data();
598
iterator begin = iterator::begin(buffers);
599
iterator end = iterator::end(buffers);
602
std::size_t next_search_start;
603
std::pair<iterator, bool> result = asio::detail::partial_search(
604
begin, end, delim.begin(), delim.end());
605
if (result.first != end)
609
// Full match. We're done.
611
std::size_t bytes = result.first - begin + delim.length();
612
s.io_service().post(detail::bind_handler(handler, ec, bytes));
617
// Partial match. Next search needs to start from beginning of match.
618
next_search_start = result.first - begin;
623
// No match. Next search can start with the new data.
624
next_search_start = end - begin;
627
// Check if buffer is full.
628
if (b.size() == b.max_size())
630
asio::error_code ec(error::not_found);
631
s.io_service().post(detail::bind_handler(handler, ec, 0));
635
// Start a new asynchronous read operation to obtain more data.
636
std::size_t bytes_available =
637
std::min<std::size_t>(512, b.max_size() - b.size());
638
s.async_read_some(b.prepare(bytes_available),
639
detail::read_until_delim_string_handler<
640
AsyncReadStream, Allocator, ReadHandler>(
641
s, b, delim, next_search_start, handler));
646
template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
647
class read_until_expr_handler
650
read_until_expr_handler(AsyncReadStream& stream,
651
asio::basic_streambuf<Allocator>& streambuf,
652
const boost::regex& expr, std::size_t next_search_start,
655
streambuf_(streambuf),
657
next_search_start_(next_search_start),
662
void operator()(const asio::error_code& ec,
663
std::size_t bytes_transferred)
668
std::size_t bytes = 0;
673
// Commit received data to streambuf's get area.
674
streambuf_.commit(bytes_transferred);
676
// Determine the range of the data to be searched.
677
typedef typename asio::basic_streambuf<
678
Allocator>::const_buffers_type const_buffers_type;
679
typedef asio::buffers_iterator<const_buffers_type> iterator;
680
const_buffers_type buffers = streambuf_.data();
681
iterator begin = iterator::begin(buffers);
682
iterator start = begin + next_search_start_;
683
iterator end = iterator::end(buffers);
686
boost::match_results<iterator> match_results;
687
if (boost::regex_search(start, end, match_results, expr_,
688
boost::match_default | boost::match_partial))
690
if (match_results[0].matched)
692
// Full match. We're done.
693
std::size_t bytes = match_results[0].second - begin;
699
// Partial match. Next search needs to start from beginning of match.
700
next_search_start_ = match_results[0].first - begin;
705
// No match. Next search can start with the new data.
706
next_search_start_ = end - begin;
709
// Check if buffer is full.
710
if (streambuf_.size() == streambuf_.max_size())
712
std::size_t bytes = 0;
713
asio::error_code ec(error::not_found);
718
// Start a new asynchronous read operation to obtain more data.
719
std::size_t bytes_available =
720
std::min<std::size_t>(512, streambuf_.max_size() - streambuf_.size());
721
stream_.async_read_some(streambuf_.prepare(bytes_available), *this);
725
AsyncReadStream& stream_;
726
asio::basic_streambuf<Allocator>& streambuf_;
728
std::size_t next_search_start_;
729
ReadHandler handler_;
732
template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
733
inline void* asio_handler_allocate(std::size_t size,
734
read_until_expr_handler<AsyncReadStream,
735
Allocator, ReadHandler>* this_handler)
737
return asio_handler_alloc_helpers::allocate(
738
size, &this_handler->handler_);
741
template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
742
inline void asio_handler_deallocate(void* pointer, std::size_t size,
743
read_until_expr_handler<AsyncReadStream,
744
Allocator, ReadHandler>* this_handler)
746
asio_handler_alloc_helpers::deallocate(
747
pointer, size, &this_handler->handler_);
750
template <typename Function, typename AsyncReadStream, typename Allocator,
751
typename ReadHandler>
752
inline void asio_handler_invoke(const Function& function,
753
read_until_expr_handler<AsyncReadStream,
754
Allocator, ReadHandler>* this_handler)
756
asio_handler_invoke_helpers::invoke(
757
function, &this_handler->handler_);
759
} // namespace detail
761
template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
762
void async_read_until(AsyncReadStream& s,
763
asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
766
// Determine the range of the data to be searched.
767
typedef typename asio::basic_streambuf<
768
Allocator>::const_buffers_type const_buffers_type;
769
typedef asio::buffers_iterator<const_buffers_type> iterator;
770
const_buffers_type buffers = b.data();
771
iterator begin = iterator::begin(buffers);
772
iterator end = iterator::end(buffers);
775
std::size_t next_search_start;
776
boost::match_results<iterator> match_results;
777
if (boost::regex_search(begin, end, match_results, expr,
778
boost::match_default | boost::match_partial))
780
if (match_results[0].matched)
782
// Full match. We're done.
784
std::size_t bytes = match_results[0].second - begin;
785
s.io_service().post(detail::bind_handler(handler, ec, bytes));
790
// Partial match. Next search needs to start from beginning of match.
791
next_search_start = match_results[0].first - begin;
796
// No match. Next search can start with the new data.
797
next_search_start = end - begin;
800
// Check if buffer is full.
801
if (b.size() == b.max_size())
803
asio::error_code ec(error::not_found);
804
s.io_service().post(detail::bind_handler(handler, ec, 0));
808
// Start a new asynchronous read operation to obtain more data.
809
std::size_t bytes_available =
810
std::min<std::size_t>(512, b.max_size() - b.size());
811
s.async_read_some(b.prepare(bytes_available),
812
detail::read_until_expr_handler<AsyncReadStream, Allocator, ReadHandler>(
813
s, b, expr, next_search_start, handler));
818
template <typename AsyncReadStream, typename Allocator,
819
typename MatchCondition, typename ReadHandler>
820
class read_until_match_handler
823
read_until_match_handler(AsyncReadStream& stream,
824
asio::basic_streambuf<Allocator>& streambuf,
825
MatchCondition match_condition, std::size_t next_search_start,
828
streambuf_(streambuf),
829
match_condition_(match_condition),
830
next_search_start_(next_search_start),
835
void operator()(const asio::error_code& ec,
836
std::size_t bytes_transferred)
841
std::size_t bytes = 0;
846
// Commit received data to streambuf's get area.
847
streambuf_.commit(bytes_transferred);
849
// Determine the range of the data to be searched.
850
typedef typename asio::basic_streambuf<
851
Allocator>::const_buffers_type const_buffers_type;
852
typedef asio::buffers_iterator<const_buffers_type> iterator;
853
const_buffers_type buffers = streambuf_.data();
854
iterator begin = iterator::begin(buffers);
855
iterator start = begin + next_search_start_;
856
iterator end = iterator::end(buffers);
859
std::pair<iterator, bool> result = match_condition_(start, end);
860
if (result.first != end)
864
// Full match. We're done.
865
std::size_t bytes = result.first - begin;
871
// Partial match. Next search needs to start from beginning of match.
872
next_search_start_ = result.first - begin;
877
// No match. Next search can start with the new data.
878
next_search_start_ = end - begin;
881
// Check if buffer is full.
882
if (streambuf_.size() == streambuf_.max_size())
884
std::size_t bytes = 0;
885
asio::error_code ec(error::not_found);
890
// Start a new asynchronous read operation to obtain more data.
891
std::size_t bytes_available =
892
std::min<std::size_t>(512, streambuf_.max_size() - streambuf_.size());
893
stream_.async_read_some(streambuf_.prepare(bytes_available), *this);
897
AsyncReadStream& stream_;
898
asio::basic_streambuf<Allocator>& streambuf_;
899
MatchCondition match_condition_;
900
std::size_t next_search_start_;
901
ReadHandler handler_;
904
template <typename AsyncReadStream, typename Allocator,
905
typename MatchCondition, typename ReadHandler>
906
inline void* asio_handler_allocate(std::size_t size,
907
read_until_match_handler<AsyncReadStream,
908
Allocator, MatchCondition, ReadHandler>* this_handler)
910
return asio_handler_alloc_helpers::allocate(
911
size, &this_handler->handler_);
914
template <typename AsyncReadStream, typename Allocator,
915
typename MatchCondition, typename ReadHandler>
916
inline void asio_handler_deallocate(void* pointer, std::size_t size,
917
read_until_match_handler<AsyncReadStream,
918
Allocator, MatchCondition, ReadHandler>* this_handler)
920
asio_handler_alloc_helpers::deallocate(
921
pointer, size, &this_handler->handler_);
924
template <typename Function, typename AsyncReadStream, typename Allocator,
925
typename MatchCondition, typename ReadHandler>
926
inline void asio_handler_invoke(const Function& function,
927
read_until_match_handler<AsyncReadStream,
928
Allocator, MatchCondition, ReadHandler>* this_handler)
930
asio_handler_invoke_helpers::invoke(
931
function, &this_handler->handler_);
933
} // namespace detail
935
template <typename AsyncReadStream, typename Allocator,
936
typename MatchCondition, typename ReadHandler>
937
void async_read_until(AsyncReadStream& s,
938
asio::basic_streambuf<Allocator>& b,
939
MatchCondition match_condition, ReadHandler handler,
940
typename boost::enable_if<is_match_condition<MatchCondition> >::type*)
942
// Determine the range of the data to be searched.
943
typedef typename asio::basic_streambuf<
944
Allocator>::const_buffers_type const_buffers_type;
945
typedef asio::buffers_iterator<const_buffers_type> iterator;
946
const_buffers_type buffers = b.data();
947
iterator begin = iterator::begin(buffers);
948
iterator end = iterator::end(buffers);
951
std::size_t next_search_start;
952
std::pair<iterator, bool> result = match_condition(begin, end);
953
if (result.first != end)
957
// Full match. We're done.
959
std::size_t bytes = result.first - begin;
960
s.io_service().post(detail::bind_handler(handler, ec, bytes));
965
// Partial match. Next search needs to start from beginning of match.
966
next_search_start = result.first - begin;
971
// No match. Next search can start with the new data.
972
next_search_start = end - begin;
975
// Check if buffer is full.
976
if (b.size() == b.max_size())
978
asio::error_code ec(error::not_found);
979
s.io_service().post(detail::bind_handler(handler, ec, 0));
983
// Start a new asynchronous read operation to obtain more data.
984
std::size_t bytes_available =
985
std::min<std::size_t>(512, b.max_size() - b.size());
986
s.async_read_some(b.prepare(bytes_available),
987
detail::read_until_match_handler<
988
AsyncReadStream, Allocator, MatchCondition, ReadHandler>(
989
s, b, match_condition, next_search_start, handler));
994
#include "asio/detail/pop_options.hpp"
996
#endif // ASIO_READ_UNTIL_IPP