Statistics
| Revision:

root / tmp / org.txm.statsengine.r.core.win32 / res / win32 / library / BH / include / boost / asio / impl / read_until.hpp @ 2486

History | View | Annotate | Download (37.2 kB)

1
//
2
// impl/read_until.hpp
3
// ~~~~~~~~~~~~~~~~~~~
4
//
5
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6
//
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)
9
//
10

    
11
#ifndef BOOST_ASIO_IMPL_READ_UNTIL_HPP
12
#define BOOST_ASIO_IMPL_READ_UNTIL_HPP
13

    
14
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15
# pragma once
16
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17

    
18
#include <algorithm>
19
#include <string>
20
#include <vector>
21
#include <utility>
22
#include <boost/asio/buffer.hpp>
23
#include <boost/asio/buffers_iterator.hpp>
24
#include <boost/asio/detail/bind_handler.hpp>
25
#include <boost/asio/detail/handler_alloc_helpers.hpp>
26
#include <boost/asio/detail/handler_cont_helpers.hpp>
27
#include <boost/asio/detail/handler_invoke_helpers.hpp>
28
#include <boost/asio/detail/handler_type_requirements.hpp>
29
#include <boost/asio/detail/limits.hpp>
30
#include <boost/asio/detail/throw_error.hpp>
31

    
32
#include <boost/asio/detail/push_options.hpp>
33

    
34
namespace boost {
35
namespace asio {
36

    
37
template <typename SyncReadStream, typename Allocator>
38
inline std::size_t read_until(SyncReadStream& s,
39
    boost::asio::basic_streambuf<Allocator>& b, char delim)
40
{
41
  boost::system::error_code ec;
42
  std::size_t bytes_transferred = read_until(s, b, delim, ec);
43
  boost::asio::detail::throw_error(ec, "read_until");
44
  return bytes_transferred;
45
}
46

    
47
template <typename SyncReadStream, typename Allocator>
48
std::size_t read_until(SyncReadStream& s,
49
    boost::asio::basic_streambuf<Allocator>& b, char delim,
50
    boost::system::error_code& ec)
51
{
52
  std::size_t search_position = 0;
53
  for (;;)
54
  {
55
    // Determine the range of the data to be searched.
56
    typedef typename boost::asio::basic_streambuf<
57
      Allocator>::const_buffers_type const_buffers_type;
58
    typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
59
    const_buffers_type buffers = b.data();
60
    iterator begin = iterator::begin(buffers);
61
    iterator start_pos = begin + search_position;
62
    iterator end = iterator::end(buffers);
63

    
64
    // Look for a match.
65
    iterator iter = std::find(start_pos, end, delim);
66
    if (iter != end)
67
    {
68
      // Found a match. We're done.
69
      ec = boost::system::error_code();
70
      return iter - begin + 1;
71
    }
72
    else
73
    {
74
      // No match. Next search can start with the new data.
75
      search_position = end - begin;
76
    }
77

    
78
    // Check if buffer is full.
79
    if (b.size() == b.max_size())
80
    {
81
      ec = error::not_found;
82
      return 0;
83
    }
84

    
85
    // Need more data.
86
    std::size_t bytes_to_read = read_size_helper(b, 65536);
87
    b.commit(s.read_some(b.prepare(bytes_to_read), ec));
88
    if (ec)
89
      return 0;
90
  }
91
}
92

    
93
template <typename SyncReadStream, typename Allocator>
94
inline std::size_t read_until(SyncReadStream& s,
95
    boost::asio::basic_streambuf<Allocator>& b, const std::string& delim)
96
{
97
  boost::system::error_code ec;
98
  std::size_t bytes_transferred = read_until(s, b, delim, ec);
99
  boost::asio::detail::throw_error(ec, "read_until");
100
  return bytes_transferred;
101
}
102

    
103
namespace detail
104
{
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)
114
  {
115
    for (Iterator1 iter1 = first1; iter1 != last1; ++iter1)
116
    {
117
      Iterator1 test_iter1 = iter1;
118
      Iterator2 test_iter2 = first2;
119
      for (;; ++test_iter1, ++test_iter2)
120
      {
121
        if (test_iter2 == last2)
122
          return std::make_pair(iter1, true);
123
        if (test_iter1 == last1)
124
        {
125
          if (test_iter2 != first2)
126
            return std::make_pair(iter1, false);
127
          else
128
            break;
129
        }
130
        if (*test_iter1 != *test_iter2)
131
          break;
132
      }
133
    }
134
    return std::make_pair(last1, false);
135
  }
136
} // namespace detail
137

    
138
template <typename SyncReadStream, typename Allocator>
139
std::size_t read_until(SyncReadStream& s,
140
    boost::asio::basic_streambuf<Allocator>& b, const std::string& delim,
141
    boost::system::error_code& ec)
142
{
143
  std::size_t search_position = 0;
144
  for (;;)
145
  {
146
    // Determine the range of the data to be searched.
147
    typedef typename boost::asio::basic_streambuf<
148
      Allocator>::const_buffers_type const_buffers_type;
149
    typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
150
    const_buffers_type buffers = b.data();
151
    iterator begin = iterator::begin(buffers);
152
    iterator start_pos = begin + search_position;
153
    iterator end = iterator::end(buffers);
154

    
155
    // Look for a match.
156
    std::pair<iterator, bool> result = detail::partial_search(
157
        start_pos, end, delim.begin(), delim.end());
158
    if (result.first != end)
159
    {
160
      if (result.second)
161
      {
162
        // Full match. We're done.
163
        ec = boost::system::error_code();
164
        return result.first - begin + delim.length();
165
      }
166
      else
167
      {
168
        // Partial match. Next search needs to start from beginning of match.
169
        search_position = result.first - begin;
170
      }
171
    }
172
    else
173
    {
174
      // No match. Next search can start with the new data.
175
      search_position = end - begin;
176
    }
177

    
178
    // Check if buffer is full.
179
    if (b.size() == b.max_size())
180
    {
181
      ec = error::not_found;
182
      return 0;
183
    }
184

    
185
    // Need more data.
186
    std::size_t bytes_to_read = read_size_helper(b, 65536);
187
    b.commit(s.read_some(b.prepare(bytes_to_read), ec));
188
    if (ec)
189
      return 0;
190
  }
191
}
192

    
193
#if defined(BOOST_ASIO_HAS_BOOST_REGEX)
194

    
195
template <typename SyncReadStream, typename Allocator>
196
inline std::size_t read_until(SyncReadStream& s,
197
    boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr)
198
{
199
  boost::system::error_code ec;
200
  std::size_t bytes_transferred = read_until(s, b, expr, ec);
201
  boost::asio::detail::throw_error(ec, "read_until");
202
  return bytes_transferred;
203
}
204

    
205
template <typename SyncReadStream, typename Allocator>
206
std::size_t read_until(SyncReadStream& s,
207
    boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
208
    boost::system::error_code& ec)
209
{
210
  std::size_t search_position = 0;
211
  for (;;)
212
  {
213
    // Determine the range of the data to be searched.
214
    typedef typename boost::asio::basic_streambuf<
215
      Allocator>::const_buffers_type const_buffers_type;
216
    typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
217
    const_buffers_type buffers = b.data();
218
    iterator begin = iterator::begin(buffers);
219
    iterator start_pos = begin + search_position;
220
    iterator end = iterator::end(buffers);
221

    
222
    // Look for a match.
223
    boost::match_results<iterator,
224
      typename std::vector<boost::sub_match<iterator> >::allocator_type>
225
        match_results;
226
    if (regex_search(start_pos, end, match_results, expr,
227
          boost::match_default | boost::match_partial))
228
    {
229
      if (match_results[0].matched)
230
      {
231
        // Full match. We're done.
232
        ec = boost::system::error_code();
233
        return match_results[0].second - begin;
234
      }
235
      else
236
      {
237
        // Partial match. Next search needs to start from beginning of match.
238
        search_position = match_results[0].first - begin;
239
      }
240
    }
241
    else
242
    {
243
      // No match. Next search can start with the new data.
244
      search_position = end - begin;
245
    }
246

    
247
    // Check if buffer is full.
248
    if (b.size() == b.max_size())
249
    {
250
      ec = error::not_found;
251
      return 0;
252
    }
253

    
254
    // Need more data.
255
    std::size_t bytes_to_read = read_size_helper(b, 65536);
256
    b.commit(s.read_some(b.prepare(bytes_to_read), ec));
257
    if (ec)
258
      return 0;
259
  }
260
}
261

    
262
#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX)
263

    
264
template <typename SyncReadStream, typename Allocator, typename MatchCondition>
265
std::size_t read_until(SyncReadStream& s,
266
    boost::asio::basic_streambuf<Allocator>& b,
267
    MatchCondition match_condition, boost::system::error_code& ec,
268
    typename enable_if<is_match_condition<MatchCondition>::value>::type*)
269
{
270
  std::size_t search_position = 0;
271
  for (;;)
272
  {
273
    // Determine the range of the data to be searched.
274
    typedef typename boost::asio::basic_streambuf<
275
      Allocator>::const_buffers_type const_buffers_type;
276
    typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
277
    const_buffers_type buffers = b.data();
278
    iterator begin = iterator::begin(buffers);
279
    iterator start_pos = begin + search_position;
280
    iterator end = iterator::end(buffers);
281

    
282
    // Look for a match.
283
    std::pair<iterator, bool> result = match_condition(start_pos, end);
284
    if (result.second)
285
    {
286
      // Full match. We're done.
287
      ec = boost::system::error_code();
288
      return result.first - begin;
289
    }
290
    else if (result.first != end)
291
    {
292
      // Partial match. Next search needs to start from beginning of match.
293
      search_position = result.first - begin;
294
    }
295
    else
296
    {
297
      // No match. Next search can start with the new data.
298
      search_position = end - begin;
299
    }
300

    
301
    // Check if buffer is full.
302
    if (b.size() == b.max_size())
303
    {
304
      ec = error::not_found;
305
      return 0;
306
    }
307

    
308
    // Need more data.
309
    std::size_t bytes_to_read = read_size_helper(b, 65536);
310
    b.commit(s.read_some(b.prepare(bytes_to_read), ec));
311
    if (ec)
312
      return 0;
313
  }
314
}
315

    
316
template <typename SyncReadStream, typename Allocator, typename MatchCondition>
317
inline std::size_t read_until(SyncReadStream& s,
318
    boost::asio::basic_streambuf<Allocator>& b, MatchCondition match_condition,
319
    typename enable_if<is_match_condition<MatchCondition>::value>::type*)
320
{
321
  boost::system::error_code ec;
322
  std::size_t bytes_transferred = read_until(s, b, match_condition, ec);
323
  boost::asio::detail::throw_error(ec, "read_until");
324
  return bytes_transferred;
325
}
326

    
327
namespace detail
328
{
329
  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
330
  class read_until_delim_op
331
  {
332
  public:
333
    read_until_delim_op(AsyncReadStream& stream,
334
        boost::asio::basic_streambuf<Allocator>& streambuf,
335
        char delim, ReadHandler& handler)
336
      : stream_(stream),
337
        streambuf_(streambuf),
338
        delim_(delim),
339
        start_(0),
340
        search_position_(0),
341
        handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
342
    {
343
    }
344

    
345
#if defined(BOOST_ASIO_HAS_MOVE)
346
    read_until_delim_op(const read_until_delim_op& other)
347
      : stream_(other.stream_),
348
        streambuf_(other.streambuf_),
349
        delim_(other.delim_),
350
        start_(other.start_),
351
        search_position_(other.search_position_),
352
        handler_(other.handler_)
353
    {
354
    }
355

    
356
    read_until_delim_op(read_until_delim_op&& other)
357
      : stream_(other.stream_),
358
        streambuf_(other.streambuf_),
359
        delim_(other.delim_),
360
        start_(other.start_),
361
        search_position_(other.search_position_),
362
        handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
363
    {
364
    }
365
#endif // defined(BOOST_ASIO_HAS_MOVE)
366

    
367
    void operator()(const boost::system::error_code& ec,
368
        std::size_t bytes_transferred, int start = 0)
369
    {
370
      const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
371
      std::size_t bytes_to_read;
372
      switch (start_ = start)
373
      {
374
      case 1:
375
        for (;;)
376
        {
377
          {
378
            // Determine the range of the data to be searched.
379
            typedef typename boost::asio::basic_streambuf<
380
              Allocator>::const_buffers_type const_buffers_type;
381
            typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
382
            const_buffers_type buffers = streambuf_.data();
383
            iterator begin = iterator::begin(buffers);
384
            iterator start_pos = begin + search_position_;
385
            iterator end = iterator::end(buffers);
386

    
387
            // Look for a match.
388
            iterator iter = std::find(start_pos, end, delim_);
389
            if (iter != end)
390
            {
391
              // Found a match. We're done.
392
              search_position_ = iter - begin + 1;
393
              bytes_to_read = 0;
394
            }
395

    
396
            // No match yet. Check if buffer is full.
397
            else if (streambuf_.size() == streambuf_.max_size())
398
            {
399
              search_position_ = not_found;
400
              bytes_to_read = 0;
401
            }
402

    
403
            // Need to read some more data.
404
            else
405
            {
406
              // Next search can start with the new data.
407
              search_position_ = end - begin;
408
              bytes_to_read = read_size_helper(streambuf_, 65536);
409
            }
410
          }
411

    
412
          // Check if we're done.
413
          if (!start && bytes_to_read == 0)
414
            break;
415

    
416
          // Start a new asynchronous read operation to obtain more data.
417
          stream_.async_read_some(streambuf_.prepare(bytes_to_read),
418
              BOOST_ASIO_MOVE_CAST(read_until_delim_op)(*this));
419
          return; default:
420
          streambuf_.commit(bytes_transferred);
421
          if (ec || bytes_transferred == 0)
422
            break;
423
        }
424

    
425
        const boost::system::error_code result_ec =
426
          (search_position_ == not_found)
427
          ? error::not_found : ec;
428

    
429
        const std::size_t result_n =
430
          (ec || search_position_ == not_found)
431
          ? 0 : search_position_;
432

    
433
        handler_(result_ec, result_n);
434
      }
435
    }
436

    
437
  //private:
438
    AsyncReadStream& stream_;
439
    boost::asio::basic_streambuf<Allocator>& streambuf_;
440
    char delim_;
441
    int start_;
442
    std::size_t search_position_;
443
    ReadHandler handler_;
444
  };
445

    
446
  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
447
  inline void* asio_handler_allocate(std::size_t size,
448
      read_until_delim_op<AsyncReadStream,
449
        Allocator, ReadHandler>* this_handler)
450
  {
451
    return boost_asio_handler_alloc_helpers::allocate(
452
        size, this_handler->handler_);
453
  }
454

    
455
  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
456
  inline void asio_handler_deallocate(void* pointer, std::size_t size,
457
      read_until_delim_op<AsyncReadStream,
458
        Allocator, ReadHandler>* this_handler)
459
  {
460
    boost_asio_handler_alloc_helpers::deallocate(
461
        pointer, size, this_handler->handler_);
462
  }
463

    
464
  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
465
  inline bool asio_handler_is_continuation(
466
      read_until_delim_op<AsyncReadStream,
467
        Allocator, ReadHandler>* this_handler)
468
  {
469
    return this_handler->start_ == 0 ? true
470
      : boost_asio_handler_cont_helpers::is_continuation(
471
          this_handler->handler_);
472
  }
473

    
474
  template <typename Function, typename AsyncReadStream, typename Allocator,
475
      typename ReadHandler>
476
  inline void asio_handler_invoke(Function& function,
477
      read_until_delim_op<AsyncReadStream,
478
        Allocator, ReadHandler>* this_handler)
479
  {
480
    boost_asio_handler_invoke_helpers::invoke(
481
        function, this_handler->handler_);
482
  }
483

    
484
  template <typename Function, typename AsyncReadStream, typename Allocator,
485
      typename ReadHandler>
486
  inline void asio_handler_invoke(const Function& function,
487
      read_until_delim_op<AsyncReadStream,
488
        Allocator, ReadHandler>* this_handler)
489
  {
490
    boost_asio_handler_invoke_helpers::invoke(
491
        function, this_handler->handler_);
492
  }
493
} // namespace detail
494

    
495
template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
496
BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
497
    void (boost::system::error_code, std::size_t))
498
async_read_until(AsyncReadStream& s,
499
    boost::asio::basic_streambuf<Allocator>& b, char delim,
500
    BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
501
{
502
  // If you get an error on the following line it means that your handler does
503
  // not meet the documented type requirements for a ReadHandler.
504
  BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
505

    
506
  detail::async_result_init<
507
    ReadHandler, void (boost::system::error_code, std::size_t)> init(
508
      BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
509

    
510
  detail::read_until_delim_op<AsyncReadStream,
511
    Allocator, BOOST_ASIO_HANDLER_TYPE(ReadHandler,
512
      void (boost::system::error_code, std::size_t))>(
513
        s, b, delim, init.handler)(
514
          boost::system::error_code(), 0, 1);
515

    
516
  return init.result.get();
517
}
518

    
519
namespace detail
520
{
521
  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
522
  class read_until_delim_string_op
523
  {
524
  public:
525
    read_until_delim_string_op(AsyncReadStream& stream,
526
        boost::asio::basic_streambuf<Allocator>& streambuf,
527
        const std::string& delim, ReadHandler& handler)
528
      : stream_(stream),
529
        streambuf_(streambuf),
530
        delim_(delim),
531
        start_(0),
532
        search_position_(0),
533
        handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
534
    {
535
    }
536

    
537
#if defined(BOOST_ASIO_HAS_MOVE)
538
    read_until_delim_string_op(const read_until_delim_string_op& other)
539
      : stream_(other.stream_),
540
        streambuf_(other.streambuf_),
541
        delim_(other.delim_),
542
        start_(other.start_),
543
        search_position_(other.search_position_),
544
        handler_(other.handler_)
545
    {
546
    }
547

    
548
    read_until_delim_string_op(read_until_delim_string_op&& other)
549
      : stream_(other.stream_),
550
        streambuf_(other.streambuf_),
551
        delim_(BOOST_ASIO_MOVE_CAST(std::string)(other.delim_)),
552
        start_(other.start_),
553
        search_position_(other.search_position_),
554
        handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
555
    {
556
    }
557
#endif // defined(BOOST_ASIO_HAS_MOVE)
558

    
559
    void operator()(const boost::system::error_code& ec,
560
        std::size_t bytes_transferred, int start = 0)
561
    {
562
      const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
563
      std::size_t bytes_to_read;
564
      switch (start_ = start)
565
      {
566
      case 1:
567
        for (;;)
568
        {
569
          {
570
            // Determine the range of the data to be searched.
571
            typedef typename boost::asio::basic_streambuf<
572
              Allocator>::const_buffers_type const_buffers_type;
573
            typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
574
            const_buffers_type buffers = streambuf_.data();
575
            iterator begin = iterator::begin(buffers);
576
            iterator start_pos = begin + search_position_;
577
            iterator end = iterator::end(buffers);
578

    
579
            // Look for a match.
580
            std::pair<iterator, bool> result = detail::partial_search(
581
                start_pos, end, delim_.begin(), delim_.end());
582
            if (result.first != end && result.second)
583
            {
584
              // Full match. We're done.
585
              search_position_ = result.first - begin + delim_.length();
586
              bytes_to_read = 0;
587
            }
588

    
589
            // No match yet. Check if buffer is full.
590
            else if (streambuf_.size() == streambuf_.max_size())
591
            {
592
              search_position_ = not_found;
593
              bytes_to_read = 0;
594
            }
595

    
596
            // Need to read some more data.
597
            else
598
            {
599
              if (result.first != end)
600
              {
601
                // Partial match. Next search needs to start from beginning of
602
                // match.
603
                search_position_ = result.first - begin;
604
              }
605
              else
606
              {
607
                // Next search can start with the new data.
608
                search_position_ = end - begin;
609
              }
610

    
611
              bytes_to_read = read_size_helper(streambuf_, 65536);
612
            }
613
          }
614

    
615
          // Check if we're done.
616
          if (!start && bytes_to_read == 0)
617
            break;
618

    
619
          // Start a new asynchronous read operation to obtain more data.
620
          stream_.async_read_some(streambuf_.prepare(bytes_to_read),
621
              BOOST_ASIO_MOVE_CAST(read_until_delim_string_op)(*this));
622
          return; default:
623
          streambuf_.commit(bytes_transferred);
624
          if (ec || bytes_transferred == 0)
625
            break;
626
        }
627

    
628
        const boost::system::error_code result_ec =
629
          (search_position_ == not_found)
630
          ? error::not_found : ec;
631

    
632
        const std::size_t result_n =
633
          (ec || search_position_ == not_found)
634
          ? 0 : search_position_;
635

    
636
        handler_(result_ec, result_n);
637
      }
638
    }
639

    
640
  //private:
641
    AsyncReadStream& stream_;
642
    boost::asio::basic_streambuf<Allocator>& streambuf_;
643
    std::string delim_;
644
    int start_;
645
    std::size_t search_position_;
646
    ReadHandler handler_;
647
  };
648

    
649
  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
650
  inline void* asio_handler_allocate(std::size_t size,
651
      read_until_delim_string_op<AsyncReadStream,
652
        Allocator, ReadHandler>* this_handler)
653
  {
654
    return boost_asio_handler_alloc_helpers::allocate(
655
        size, this_handler->handler_);
656
  }
657

    
658
  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
659
  inline void asio_handler_deallocate(void* pointer, std::size_t size,
660
      read_until_delim_string_op<AsyncReadStream,
661
        Allocator, ReadHandler>* this_handler)
662
  {
663
    boost_asio_handler_alloc_helpers::deallocate(
664
        pointer, size, this_handler->handler_);
665
  }
666

    
667
  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
668
  inline bool asio_handler_is_continuation(
669
      read_until_delim_string_op<AsyncReadStream,
670
        Allocator, ReadHandler>* this_handler)
671
  {
672
    return this_handler->start_ == 0 ? true
673
      : boost_asio_handler_cont_helpers::is_continuation(
674
          this_handler->handler_);
675
  }
676

    
677
  template <typename Function, typename AsyncReadStream,
678
      typename Allocator, typename ReadHandler>
679
  inline void asio_handler_invoke(Function& function,
680
      read_until_delim_string_op<AsyncReadStream,
681
        Allocator, ReadHandler>* this_handler)
682
  {
683
    boost_asio_handler_invoke_helpers::invoke(
684
        function, this_handler->handler_);
685
  }
686

    
687
  template <typename Function, typename AsyncReadStream,
688
      typename Allocator, typename ReadHandler>
689
  inline void asio_handler_invoke(const Function& function,
690
      read_until_delim_string_op<AsyncReadStream,
691
        Allocator, ReadHandler>* this_handler)
692
  {
693
    boost_asio_handler_invoke_helpers::invoke(
694
        function, this_handler->handler_);
695
  }
696
} // namespace detail
697

    
698
template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
699
BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
700
    void (boost::system::error_code, std::size_t))
701
async_read_until(AsyncReadStream& s,
702
    boost::asio::basic_streambuf<Allocator>& b, const std::string& delim,
703
    BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
704
{
705
  // If you get an error on the following line it means that your handler does
706
  // not meet the documented type requirements for a ReadHandler.
707
  BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
708

    
709
  detail::async_result_init<
710
    ReadHandler, void (boost::system::error_code, std::size_t)> init(
711
      BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
712

    
713
  detail::read_until_delim_string_op<AsyncReadStream,
714
    Allocator, BOOST_ASIO_HANDLER_TYPE(ReadHandler,
715
      void (boost::system::error_code, std::size_t))>(
716
        s, b, delim, init.handler)(
717
          boost::system::error_code(), 0, 1);
718

    
719
  return init.result.get();
720
}
721

    
722
#if defined(BOOST_ASIO_HAS_BOOST_REGEX)
723

    
724
namespace detail
725
{
726
  template <typename AsyncReadStream, typename Allocator,
727
      typename RegEx, typename ReadHandler>
728
  class read_until_expr_op
729
  {
730
  public:
731
    read_until_expr_op(AsyncReadStream& stream,
732
        boost::asio::basic_streambuf<Allocator>& streambuf,
733
        const boost::regex& expr, ReadHandler& handler)
734
      : stream_(stream),
735
        streambuf_(streambuf),
736
        expr_(expr),
737
        start_(0),
738
        search_position_(0),
739
        handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
740
    {
741
    }
742

    
743
#if defined(BOOST_ASIO_HAS_MOVE)
744
    read_until_expr_op(const read_until_expr_op& other)
745
      : stream_(other.stream_),
746
        streambuf_(other.streambuf_),
747
        expr_(other.expr_),
748
        start_(other.start_),
749
        search_position_(other.search_position_),
750
        handler_(other.handler_)
751
    {
752
    }
753

    
754
    read_until_expr_op(read_until_expr_op&& other)
755
      : stream_(other.stream_),
756
        streambuf_(other.streambuf_),
757
        expr_(other.expr_),
758
        start_(other.start_),
759
        search_position_(other.search_position_),
760
        handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
761
    {
762
    }
763
#endif // defined(BOOST_ASIO_HAS_MOVE)
764

    
765
    void operator()(const boost::system::error_code& ec,
766
        std::size_t bytes_transferred, int start = 0)
767
    {
768
      const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
769
      std::size_t bytes_to_read;
770
      switch (start_ = start)
771
      {
772
      case 1:
773
        for (;;)
774
        {
775
          {
776
            // Determine the range of the data to be searched.
777
            typedef typename boost::asio::basic_streambuf<
778
              Allocator>::const_buffers_type const_buffers_type;
779
            typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
780
            const_buffers_type buffers = streambuf_.data();
781
            iterator begin = iterator::begin(buffers);
782
            iterator start_pos = begin + search_position_;
783
            iterator end = iterator::end(buffers);
784

    
785
            // Look for a match.
786
            boost::match_results<iterator,
787
              typename std::vector<boost::sub_match<iterator> >::allocator_type>
788
                match_results;
789
            bool match = regex_search(start_pos, end, match_results, expr_,
790
                boost::match_default | boost::match_partial);
791
            if (match && match_results[0].matched)
792
            {
793
              // Full match. We're done.
794
              search_position_ = match_results[0].second - begin;
795
              bytes_to_read = 0;
796
            }
797

    
798
            // No match yet. Check if buffer is full.
799
            else if (streambuf_.size() == streambuf_.max_size())
800
            {
801
              search_position_ = not_found;
802
              bytes_to_read = 0;
803
            }
804

    
805
            // Need to read some more data.
806
            else
807
            {
808
              if (match)
809
              {
810
                // Partial match. Next search needs to start from beginning of
811
                // match.
812
                search_position_ = match_results[0].first - begin;
813
              }
814
              else
815
              {
816
                // Next search can start with the new data.
817
                search_position_ = end - begin;
818
              }
819

    
820
              bytes_to_read = read_size_helper(streambuf_, 65536);
821
            }
822
          }
823

    
824
          // Check if we're done.
825
          if (!start && bytes_to_read == 0)
826
            break;
827

    
828
          // Start a new asynchronous read operation to obtain more data.
829
          stream_.async_read_some(streambuf_.prepare(bytes_to_read),
830
              BOOST_ASIO_MOVE_CAST(read_until_expr_op)(*this));
831
          return; default:
832
          streambuf_.commit(bytes_transferred);
833
          if (ec || bytes_transferred == 0)
834
            break;
835
        }
836

    
837
        const boost::system::error_code result_ec =
838
          (search_position_ == not_found)
839
          ? error::not_found : ec;
840

    
841
        const std::size_t result_n =
842
          (ec || search_position_ == not_found)
843
          ? 0 : search_position_;
844

    
845
        handler_(result_ec, result_n);
846
      }
847
    }
848

    
849
  //private:
850
    AsyncReadStream& stream_;
851
    boost::asio::basic_streambuf<Allocator>& streambuf_;
852
    RegEx expr_;
853
    int start_;
854
    std::size_t search_position_;
855
    ReadHandler handler_;
856
  };
857

    
858
  template <typename AsyncReadStream, typename Allocator,
859
      typename RegEx, typename ReadHandler>
860
  inline void* asio_handler_allocate(std::size_t size,
861
      read_until_expr_op<AsyncReadStream,
862
        Allocator, RegEx, ReadHandler>* this_handler)
863
  {
864
    return boost_asio_handler_alloc_helpers::allocate(
865
        size, this_handler->handler_);
866
  }
867

    
868
  template <typename AsyncReadStream, typename Allocator,
869
      typename RegEx, typename ReadHandler>
870
  inline void asio_handler_deallocate(void* pointer, std::size_t size,
871
      read_until_expr_op<AsyncReadStream,
872
        Allocator, RegEx, ReadHandler>* this_handler)
873
  {
874
    boost_asio_handler_alloc_helpers::deallocate(
875
        pointer, size, this_handler->handler_);
876
  }
877

    
878
  template <typename AsyncReadStream, typename Allocator,
879
      typename RegEx, typename ReadHandler>
880
  inline bool asio_handler_is_continuation(
881
      read_until_expr_op<AsyncReadStream,
882
        Allocator, RegEx, ReadHandler>* this_handler)
883
  {
884
    return this_handler->start_ == 0 ? true
885
      : boost_asio_handler_cont_helpers::is_continuation(
886
          this_handler->handler_);
887
  }
888

    
889
  template <typename Function, typename AsyncReadStream, typename Allocator,
890
      typename RegEx, typename ReadHandler>
891
  inline void asio_handler_invoke(Function& function,
892
      read_until_expr_op<AsyncReadStream,
893
        Allocator, RegEx, ReadHandler>* this_handler)
894
  {
895
    boost_asio_handler_invoke_helpers::invoke(
896
        function, this_handler->handler_);
897
  }
898

    
899
  template <typename Function, typename AsyncReadStream, typename Allocator,
900
      typename RegEx, typename ReadHandler>
901
  inline void asio_handler_invoke(const Function& function,
902
      read_until_expr_op<AsyncReadStream,
903
        Allocator, RegEx, ReadHandler>* this_handler)
904
  {
905
    boost_asio_handler_invoke_helpers::invoke(
906
        function, this_handler->handler_);
907
  }
908
} // namespace detail
909

    
910
template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
911
BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
912
    void (boost::system::error_code, std::size_t))
913
async_read_until(AsyncReadStream& s,
914
    boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
915
    BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
916
{
917
  // If you get an error on the following line it means that your handler does
918
  // not meet the documented type requirements for a ReadHandler.
919
  BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
920

    
921
  detail::async_result_init<
922
    ReadHandler, void (boost::system::error_code, std::size_t)> init(
923
      BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
924

    
925
  detail::read_until_expr_op<AsyncReadStream, Allocator,
926
    boost::regex, BOOST_ASIO_HANDLER_TYPE(ReadHandler,
927
      void (boost::system::error_code, std::size_t))>(
928
        s, b, expr, init.handler)(
929
          boost::system::error_code(), 0, 1);
930

    
931
  return init.result.get();
932
}
933

    
934
#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX)
935

    
936
namespace detail
937
{
938
  template <typename AsyncReadStream, typename Allocator,
939
      typename MatchCondition, typename ReadHandler>
940
  class read_until_match_op
941
  {
942
  public:
943
    read_until_match_op(AsyncReadStream& stream,
944
        boost::asio::basic_streambuf<Allocator>& streambuf,
945
        MatchCondition match_condition, ReadHandler& handler)
946
      : stream_(stream),
947
        streambuf_(streambuf),
948
        match_condition_(match_condition),
949
        start_(0),
950
        search_position_(0),
951
        handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
952
    {
953
    }
954

    
955
#if defined(BOOST_ASIO_HAS_MOVE)
956
    read_until_match_op(const read_until_match_op& other)
957
      : stream_(other.stream_),
958
        streambuf_(other.streambuf_),
959
        match_condition_(other.match_condition_),
960
        start_(other.start_),
961
        search_position_(other.search_position_),
962
        handler_(other.handler_)
963
    {
964
    }
965

    
966
    read_until_match_op(read_until_match_op&& other)
967
      : stream_(other.stream_),
968
        streambuf_(other.streambuf_),
969
        match_condition_(other.match_condition_),
970
        start_(other.start_),
971
        search_position_(other.search_position_),
972
        handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
973
    {
974
    }
975
#endif // defined(BOOST_ASIO_HAS_MOVE)
976

    
977
    void operator()(const boost::system::error_code& ec,
978
        std::size_t bytes_transferred, int start = 0)
979
    {
980
      const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
981
      std::size_t bytes_to_read;
982
      switch (start_ = start)
983
      {
984
      case 1:
985
        for (;;)
986
        {
987
          {
988
            // Determine the range of the data to be searched.
989
            typedef typename boost::asio::basic_streambuf<
990
              Allocator>::const_buffers_type const_buffers_type;
991
            typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
992
            const_buffers_type buffers = streambuf_.data();
993
            iterator begin = iterator::begin(buffers);
994
            iterator start_pos = begin + search_position_;
995
            iterator end = iterator::end(buffers);
996

    
997
            // Look for a match.
998
            std::pair<iterator, bool> result = match_condition_(start_pos, end);
999
            if (result.second)
1000
            {
1001
              // Full match. We're done.
1002
              search_position_ = result.first - begin;
1003
              bytes_to_read = 0;
1004
            }
1005

    
1006
            // No match yet. Check if buffer is full.
1007
            else if (streambuf_.size() == streambuf_.max_size())
1008
            {
1009
              search_position_ = not_found;
1010
              bytes_to_read = 0;
1011
            }
1012

    
1013
            // Need to read some more data.
1014
            else
1015
            {
1016
              if (result.first != end)
1017
              {
1018
                // Partial match. Next search needs to start from beginning of
1019
                // match.
1020
                search_position_ = result.first - begin;
1021
              }
1022
              else
1023
              {
1024
                // Next search can start with the new data.
1025
                search_position_ = end - begin;
1026
              }
1027

    
1028
              bytes_to_read = read_size_helper(streambuf_, 65536);
1029
            }
1030
          }
1031

    
1032
          // Check if we're done.
1033
          if (!start && bytes_to_read == 0)
1034
            break;
1035

    
1036
          // Start a new asynchronous read operation to obtain more data.
1037
          stream_.async_read_some(streambuf_.prepare(bytes_to_read),
1038
              BOOST_ASIO_MOVE_CAST(read_until_match_op)(*this));
1039
          return; default:
1040
          streambuf_.commit(bytes_transferred);
1041
          if (ec || bytes_transferred == 0)
1042
            break;
1043
        }
1044

    
1045
        const boost::system::error_code result_ec =
1046
          (search_position_ == not_found)
1047
          ? error::not_found : ec;
1048

    
1049
        const std::size_t result_n =
1050
          (ec || search_position_ == not_found)
1051
          ? 0 : search_position_;
1052

    
1053
        handler_(result_ec, result_n);
1054
      }
1055
    }
1056

    
1057
  //private:
1058
    AsyncReadStream& stream_;
1059
    boost::asio::basic_streambuf<Allocator>& streambuf_;
1060
    MatchCondition match_condition_;
1061
    int start_;
1062
    std::size_t search_position_;
1063
    ReadHandler handler_;
1064
  };
1065

    
1066
  template <typename AsyncReadStream, typename Allocator,
1067
      typename MatchCondition, typename ReadHandler>
1068
  inline void* asio_handler_allocate(std::size_t size,
1069
      read_until_match_op<AsyncReadStream,
1070
        Allocator, MatchCondition, ReadHandler>* this_handler)
1071
  {
1072
    return boost_asio_handler_alloc_helpers::allocate(
1073
        size, this_handler->handler_);
1074
  }
1075

    
1076
  template <typename AsyncReadStream, typename Allocator,
1077
      typename MatchCondition, typename ReadHandler>
1078
  inline void asio_handler_deallocate(void* pointer, std::size_t size,
1079
      read_until_match_op<AsyncReadStream,
1080
        Allocator, MatchCondition, ReadHandler>* this_handler)
1081
  {
1082
    boost_asio_handler_alloc_helpers::deallocate(
1083
        pointer, size, this_handler->handler_);
1084
  }
1085

    
1086
  template <typename AsyncReadStream, typename Allocator,
1087
      typename MatchCondition, typename ReadHandler>
1088
  inline bool asio_handler_is_continuation(
1089
      read_until_match_op<AsyncReadStream,
1090
        Allocator, MatchCondition, ReadHandler>* this_handler)
1091
  {
1092
    return this_handler->start_ == 0 ? true
1093
      : boost_asio_handler_cont_helpers::is_continuation(
1094
          this_handler->handler_);
1095
  }
1096

    
1097
  template <typename Function, typename AsyncReadStream, typename Allocator,
1098
      typename MatchCondition, typename ReadHandler>
1099
  inline void asio_handler_invoke(Function& function,
1100
      read_until_match_op<AsyncReadStream,
1101
        Allocator, MatchCondition, ReadHandler>* this_handler)
1102
  {
1103
    boost_asio_handler_invoke_helpers::invoke(
1104
        function, this_handler->handler_);
1105
  }
1106

    
1107
  template <typename Function, typename AsyncReadStream, typename Allocator,
1108
      typename MatchCondition, typename ReadHandler>
1109
  inline void asio_handler_invoke(const Function& function,
1110
      read_until_match_op<AsyncReadStream,
1111
        Allocator, MatchCondition, ReadHandler>* this_handler)
1112
  {
1113
    boost_asio_handler_invoke_helpers::invoke(
1114
        function, this_handler->handler_);
1115
  }
1116
} // namespace detail
1117

    
1118
template <typename AsyncReadStream, typename Allocator,
1119
    typename MatchCondition, typename ReadHandler>
1120
BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
1121
    void (boost::system::error_code, std::size_t))
1122
async_read_until(AsyncReadStream& s,
1123
    boost::asio::basic_streambuf<Allocator>& b,
1124
    MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler,
1125
    typename enable_if<is_match_condition<MatchCondition>::value>::type*)
1126
{
1127
  // If you get an error on the following line it means that your handler does
1128
  // not meet the documented type requirements for a ReadHandler.
1129
  BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
1130

    
1131
  detail::async_result_init<
1132
    ReadHandler, void (boost::system::error_code, std::size_t)> init(
1133
      BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
1134

    
1135
  detail::read_until_match_op<AsyncReadStream, Allocator,
1136
    MatchCondition, BOOST_ASIO_HANDLER_TYPE(ReadHandler,
1137
      void (boost::system::error_code, std::size_t))>(
1138
        s, b, match_condition, init.handler)(
1139
          boost::system::error_code(), 0, 1);
1140

    
1141
  return init.result.get();
1142
}
1143

    
1144
} // namespace asio
1145
} // namespace boost
1146

    
1147
#include <boost/asio/detail/pop_options.hpp>
1148

    
1149
#endif // BOOST_ASIO_IMPL_READ_UNTIL_HPP