~ubuntu-branches/ubuntu/trusty/miro/trusty

« back to all changes in this revision

Viewing changes to portable/libtorrent/include/libtorrent/asio/impl/read_until.ipp

  • Committer: Daniel Hahler
  • Date: 2010-04-13 18:51:35 UTC
  • mfrom: (1.2.10 upstream)
  • Revision ID: ubuntu-launchpad@thequod.de-20100413185135-xi24v1diqg8w406x
Merging shared upstream rev into target branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
//
2
 
// read_until.ipp
3
 
// ~~~~~~~~~~~~~~
4
 
//
5
 
// Copyright (c) 2003-2008 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 ASIO_READ_UNTIL_IPP
12
 
#define ASIO_READ_UNTIL_IPP
13
 
 
14
 
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15
 
# pragma once
16
 
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
 
 
18
 
#include "asio/detail/push_options.hpp"
19
 
 
20
 
#include "asio/detail/push_options.hpp"
21
 
#include <algorithm>
22
 
#include <limits>
23
 
#include <string>
24
 
#include <utility>
25
 
#include "asio/detail/pop_options.hpp"
26
 
 
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"
33
 
 
34
 
namespace asio {
35
 
 
36
 
template <typename SyncReadStream, typename Allocator>
37
 
inline std::size_t read_until(SyncReadStream& s,
38
 
    asio::basic_streambuf<Allocator>& b, char delim)
39
 
{
40
 
  asio::error_code ec;
41
 
  std::size_t bytes_transferred = read_until(s, b, delim, ec);
42
 
  asio::detail::throw_error(ec);
43
 
  return bytes_transferred;
44
 
}
45
 
 
46
 
template <typename SyncReadStream, typename Allocator>
47
 
std::size_t read_until(SyncReadStream& s,
48
 
    asio::basic_streambuf<Allocator>& b, char delim,
49
 
    asio::error_code& ec)
50
 
{
51
 
  std::size_t next_search_start = 0;
52
 
  for (;;)
53
 
  {
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);
62
 
 
63
 
    // Look for a match.
64
 
    iterator iter = std::find(start, end, delim);
65
 
    if (iter != end)
66
 
    {
67
 
      // Found a match. We're done.
68
 
      ec = asio::error_code();
69
 
      return iter - begin + 1;
70
 
    }
71
 
    else
72
 
    {
73
 
      // No match. Next search can start with the new data.
74
 
      next_search_start = end - begin;
75
 
    }
76
 
 
77
 
    // Check if buffer is full.
78
 
    if (b.size() == b.max_size())
79
 
    {
80
 
      ec = error::not_found;
81
 
      return 0;
82
 
    }
83
 
 
84
 
    // Need more data.
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));
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
 
    asio::basic_streambuf<Allocator>& b, const std::string& delim)
96
 
{
97
 
  asio::error_code ec;
98
 
  std::size_t bytes_transferred = read_until(s, b, delim, ec);
99
 
  asio::detail::throw_error(ec);
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
 
    asio::basic_streambuf<Allocator>& b, const std::string& delim,
141
 
    asio::error_code& ec)
142
 
{
143
 
  std::size_t next_search_start = 0;
144
 
  for (;;)
145
 
  {
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);
154
 
 
155
 
    // Look for a match.
156
 
    std::pair<iterator, bool> result = asio::detail::partial_search(
157
 
        start, end, delim.begin(), delim.end());
158
 
    if (result.first != end)
159
 
    {
160
 
      if (result.second)
161
 
      {
162
 
        // Full match. We're done.
163
 
        ec = asio::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
 
        next_search_start = result.first - begin;
170
 
      }
171
 
    }
172
 
    else
173
 
    {
174
 
      // No match. Next search can start with the new data.
175
 
      next_search_start = 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_available =
187
 
      std::min<std::size_t>(512, b.max_size() - b.size());
188
 
    b.commit(s.read_some(b.prepare(bytes_available), ec));
189
 
    if (ec)
190
 
      return 0;
191
 
  }
192
 
}
193
 
 
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)
197
 
{
198
 
  asio::error_code ec;
199
 
  std::size_t bytes_transferred = read_until(s, b, expr, ec);
200
 
  asio::detail::throw_error(ec);
201
 
  return bytes_transferred;
202
 
}
203
 
 
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)
208
 
{
209
 
  std::size_t next_search_start = 0;
210
 
  for (;;)
211
 
  {
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);
220
 
 
221
 
    // Look for a match.
222
 
    boost::match_results<iterator> match_results;
223
 
    if (boost::regex_search(start, end, match_results, expr,
224
 
          boost::match_default | boost::match_partial))
225
 
    {
226
 
      if (match_results[0].matched)
227
 
      {
228
 
        // Full match. We're done.
229
 
        ec = asio::error_code();
230
 
        return match_results[0].second - begin;
231
 
      }
232
 
      else
233
 
      {
234
 
        // Partial match. Next search needs to start from beginning of match.
235
 
        next_search_start = match_results[0].first - begin;
236
 
      }
237
 
    }
238
 
    else
239
 
    {
240
 
      // No match. Next search can start with the new data.
241
 
      next_search_start = end - begin;
242
 
    }
243
 
 
244
 
    // Check if buffer is full.
245
 
    if (b.size() == b.max_size())
246
 
    {
247
 
      ec = error::not_found;
248
 
      return 0;
249
 
    }
250
 
 
251
 
    // Need more data.
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));
255
 
    if (ec)
256
 
      return 0;
257
 
  }
258
 
}
259
 
 
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*)
265
 
{
266
 
  std::size_t next_search_start = 0;
267
 
  for (;;)
268
 
  {
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);
277
 
 
278
 
    // Look for a match.
279
 
    std::pair<iterator, bool> result = match_condition(start, end);
280
 
    if (result.first != end)
281
 
    {
282
 
      if (result.second)
283
 
      {
284
 
        // Full match. We're done.
285
 
        ec = asio::error_code();
286
 
        return result.first - begin;
287
 
      }
288
 
      else
289
 
      {
290
 
        // Partial match. Next search needs to start from beginning of match.
291
 
        next_search_start = result.first - begin;
292
 
      }
293
 
    }
294
 
    else
295
 
    {
296
 
      // No match. Next search can start with the new data.
297
 
      next_search_start = end - begin;
298
 
    }
299
 
 
300
 
    // Check if buffer is full.
301
 
    if (b.size() == b.max_size())
302
 
    {
303
 
      ec = error::not_found;
304
 
      return 0;
305
 
    }
306
 
 
307
 
    // Need more data.
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));
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
 
    asio::basic_streambuf<Allocator>& b, MatchCondition match_condition,
319
 
    typename boost::enable_if<is_match_condition<MatchCondition> >::type*)
320
 
{
321
 
  asio::error_code ec;
322
 
  std::size_t bytes_transferred = read_until(s, b, match_condition, ec);
323
 
  asio::detail::throw_error(ec);
324
 
  return bytes_transferred;
325
 
}
326
 
 
327
 
namespace detail
328
 
{
329
 
  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
330
 
  class read_until_delim_handler
331
 
  {
332
 
  public:
333
 
    read_until_delim_handler(AsyncReadStream& stream,
334
 
        asio::basic_streambuf<Allocator>& streambuf, char delim,
335
 
        std::size_t next_search_start, ReadHandler handler)
336
 
      : stream_(stream),
337
 
        streambuf_(streambuf),
338
 
        delim_(delim),
339
 
        next_search_start_(next_search_start),
340
 
        handler_(handler)
341
 
    {
342
 
    }
343
 
 
344
 
    void operator()(const asio::error_code& ec,
345
 
        std::size_t bytes_transferred)
346
 
    {
347
 
      // Check for errors.
348
 
      if (ec)
349
 
      {
350
 
        std::size_t bytes = 0;
351
 
        handler_(ec, bytes);
352
 
        return;
353
 
      }
354
 
 
355
 
      // Commit received data to streambuf's get area.
356
 
      streambuf_.commit(bytes_transferred);
357
 
 
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);
366
 
 
367
 
      // Look for a match.
368
 
      iterator iter = std::find(start, end, delim_);
369
 
      if (iter != end)
370
 
      {
371
 
        // Found a match. We're done.
372
 
        std::size_t bytes = iter - begin + 1;
373
 
        handler_(ec, bytes);
374
 
        return;
375
 
      }
376
 
 
377
 
      // No match. Check if buffer is full.
378
 
      if (streambuf_.size() == streambuf_.max_size())
379
 
      {
380
 
        std::size_t bytes = 0;
381
 
        asio::error_code ec(error::not_found);
382
 
        handler_(ec, bytes);
383
 
        return;
384
 
      }
385
 
 
386
 
      // Next search can start with the new data.
387
 
      next_search_start_ = end - begin;
388
 
 
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);
393
 
    }
394
 
 
395
 
  //private:
396
 
    AsyncReadStream& stream_;
397
 
    asio::basic_streambuf<Allocator>& streambuf_;
398
 
    char delim_;
399
 
    std::size_t next_search_start_;
400
 
    ReadHandler handler_;
401
 
  };
402
 
 
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)
407
 
  {
408
 
    return asio_handler_alloc_helpers::allocate(
409
 
        size, &this_handler->handler_);
410
 
  }
411
 
 
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)
416
 
  {
417
 
    asio_handler_alloc_helpers::deallocate(
418
 
        pointer, size, &this_handler->handler_);
419
 
  }
420
 
 
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)
426
 
  {
427
 
    asio_handler_invoke_helpers::invoke(
428
 
        function, &this_handler->handler_);
429
 
  }
430
 
} // namespace detail
431
 
 
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)
435
 
{
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);
443
 
 
444
 
  // Look for a match.
445
 
  iterator iter = std::find(begin, end, delim);
446
 
  if (iter != end)
447
 
  {
448
 
    // Found a match. We're done.
449
 
    asio::error_code ec;
450
 
    std::size_t bytes = iter - begin + 1;
451
 
    s.io_service().post(detail::bind_handler(handler, ec, bytes));
452
 
    return;
453
 
  }
454
 
 
455
 
  // No match. Check if buffer is full.
456
 
  if (b.size() == b.max_size())
457
 
  {
458
 
    asio::error_code ec(error::not_found);
459
 
    s.io_service().post(detail::bind_handler(handler, ec, 0));
460
 
    return;
461
 
  }
462
 
 
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));
469
 
}
470
 
 
471
 
namespace detail
472
 
{
473
 
  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
474
 
  class read_until_delim_string_handler
475
 
  {
476
 
  public:
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,
480
 
        ReadHandler handler)
481
 
      : stream_(stream),
482
 
        streambuf_(streambuf),
483
 
        delim_(delim),
484
 
        next_search_start_(next_search_start),
485
 
        handler_(handler)
486
 
    {
487
 
    }
488
 
 
489
 
    void operator()(const asio::error_code& ec,
490
 
        std::size_t bytes_transferred)
491
 
    {
492
 
      // Check for errors.
493
 
      if (ec)
494
 
      {
495
 
        std::size_t bytes = 0;
496
 
        handler_(ec, bytes);
497
 
        return;
498
 
      }
499
 
 
500
 
      // Commit received data to streambuf's get area.
501
 
      streambuf_.commit(bytes_transferred);
502
 
 
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);
511
 
 
512
 
      // Look for a match.
513
 
      std::pair<iterator, bool> result = asio::detail::partial_search(
514
 
          start, end, delim_.begin(), delim_.end());
515
 
      if (result.first != end)
516
 
      {
517
 
        if (result.second)
518
 
        {
519
 
          // Full match. We're done.
520
 
          std::size_t bytes = result.first - begin + delim_.length();
521
 
          handler_(ec, bytes);
522
 
          return;
523
 
        }
524
 
        else
525
 
        {
526
 
          // Partial match. Next search needs to start from beginning of match.
527
 
          next_search_start_ = result.first - begin;
528
 
        }
529
 
      }
530
 
      else
531
 
      {
532
 
        // No match. Next search can start with the new data.
533
 
        next_search_start_ = end - begin;
534
 
      }
535
 
 
536
 
      // Check if buffer is full.
537
 
      if (streambuf_.size() == streambuf_.max_size())
538
 
      {
539
 
        std::size_t bytes = 0;
540
 
        asio::error_code ec(error::not_found);
541
 
        handler_(ec, bytes);
542
 
        return;
543
 
      }
544
 
 
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);
549
 
    }
550
 
 
551
 
  //private:
552
 
    AsyncReadStream& stream_;
553
 
    asio::basic_streambuf<Allocator>& streambuf_;
554
 
    std::string delim_;
555
 
    std::size_t next_search_start_;
556
 
    ReadHandler handler_;
557
 
  };
558
 
 
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)
563
 
  {
564
 
    return asio_handler_alloc_helpers::allocate(
565
 
        size, &this_handler->handler_);
566
 
  }
567
 
 
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)
572
 
  {
573
 
    asio_handler_alloc_helpers::deallocate(
574
 
        pointer, size, &this_handler->handler_);
575
 
  }
576
 
 
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)
582
 
  {
583
 
    asio_handler_invoke_helpers::invoke(
584
 
        function, &this_handler->handler_);
585
 
  }
586
 
} // namespace detail
587
 
 
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,
591
 
    ReadHandler handler)
592
 
{
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);
600
 
 
601
 
  // Look for a match.
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)
606
 
  {
607
 
    if (result.second)
608
 
    {
609
 
      // Full match. We're done.
610
 
      asio::error_code ec;
611
 
      std::size_t bytes = result.first - begin + delim.length();
612
 
      s.io_service().post(detail::bind_handler(handler, ec, bytes));
613
 
      return;
614
 
    }
615
 
    else
616
 
    {
617
 
      // Partial match. Next search needs to start from beginning of match.
618
 
      next_search_start = result.first - begin;
619
 
    }
620
 
  }
621
 
  else
622
 
  {
623
 
    // No match. Next search can start with the new data.
624
 
    next_search_start = end - begin;
625
 
  }
626
 
 
627
 
  // Check if buffer is full.
628
 
  if (b.size() == b.max_size())
629
 
  {
630
 
    asio::error_code ec(error::not_found);
631
 
    s.io_service().post(detail::bind_handler(handler, ec, 0));
632
 
    return;
633
 
  }
634
 
 
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));
642
 
}
643
 
 
644
 
namespace detail
645
 
{
646
 
  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
647
 
  class read_until_expr_handler
648
 
  {
649
 
  public:
650
 
    read_until_expr_handler(AsyncReadStream& stream,
651
 
        asio::basic_streambuf<Allocator>& streambuf,
652
 
        const boost::regex& expr, std::size_t next_search_start,
653
 
        ReadHandler handler)
654
 
      : stream_(stream),
655
 
        streambuf_(streambuf),
656
 
        expr_(expr),
657
 
        next_search_start_(next_search_start),
658
 
        handler_(handler)
659
 
    {
660
 
    }
661
 
 
662
 
    void operator()(const asio::error_code& ec,
663
 
        std::size_t bytes_transferred)
664
 
    {
665
 
      // Check for errors.
666
 
      if (ec)
667
 
      {
668
 
        std::size_t bytes = 0;
669
 
        handler_(ec, bytes);
670
 
        return;
671
 
      }
672
 
 
673
 
      // Commit received data to streambuf's get area.
674
 
      streambuf_.commit(bytes_transferred);
675
 
 
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);
684
 
 
685
 
      // Look for a match.
686
 
      boost::match_results<iterator> match_results;
687
 
      if (boost::regex_search(start, end, match_results, expr_,
688
 
            boost::match_default | boost::match_partial))
689
 
      {
690
 
        if (match_results[0].matched)
691
 
        {
692
 
          // Full match. We're done.
693
 
          std::size_t bytes = match_results[0].second - begin;
694
 
          handler_(ec, bytes);
695
 
          return;
696
 
        }
697
 
        else
698
 
        {
699
 
          // Partial match. Next search needs to start from beginning of match.
700
 
          next_search_start_ = match_results[0].first - begin;
701
 
        }
702
 
      }
703
 
      else
704
 
      {
705
 
        // No match. Next search can start with the new data.
706
 
        next_search_start_ = end - begin;
707
 
      }
708
 
 
709
 
      // Check if buffer is full.
710
 
      if (streambuf_.size() == streambuf_.max_size())
711
 
      {
712
 
        std::size_t bytes = 0;
713
 
        asio::error_code ec(error::not_found);
714
 
        handler_(ec, bytes);
715
 
        return;
716
 
      }
717
 
 
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);
722
 
    }
723
 
 
724
 
  //private:
725
 
    AsyncReadStream& stream_;
726
 
    asio::basic_streambuf<Allocator>& streambuf_;
727
 
    boost::regex expr_;
728
 
    std::size_t next_search_start_;
729
 
    ReadHandler handler_;
730
 
  };
731
 
 
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)
736
 
  {
737
 
    return asio_handler_alloc_helpers::allocate(
738
 
        size, &this_handler->handler_);
739
 
  }
740
 
 
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)
745
 
  {
746
 
    asio_handler_alloc_helpers::deallocate(
747
 
        pointer, size, &this_handler->handler_);
748
 
  }
749
 
 
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)
755
 
  {
756
 
    asio_handler_invoke_helpers::invoke(
757
 
        function, &this_handler->handler_);
758
 
  }
759
 
} // namespace detail
760
 
 
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,
764
 
    ReadHandler handler)
765
 
{
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);
773
 
 
774
 
  // Look for a match.
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))
779
 
  {
780
 
    if (match_results[0].matched)
781
 
    {
782
 
      // Full match. We're done.
783
 
      asio::error_code ec;
784
 
      std::size_t bytes = match_results[0].second - begin;
785
 
      s.io_service().post(detail::bind_handler(handler, ec, bytes));
786
 
      return;
787
 
    }
788
 
    else
789
 
    {
790
 
      // Partial match. Next search needs to start from beginning of match.
791
 
      next_search_start = match_results[0].first - begin;
792
 
    }
793
 
  }
794
 
  else
795
 
  {
796
 
    // No match. Next search can start with the new data.
797
 
    next_search_start = end - begin;
798
 
  }
799
 
 
800
 
  // Check if buffer is full.
801
 
  if (b.size() == b.max_size())
802
 
  {
803
 
    asio::error_code ec(error::not_found);
804
 
    s.io_service().post(detail::bind_handler(handler, ec, 0));
805
 
    return;
806
 
  }
807
 
 
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));
814
 
}
815
 
 
816
 
namespace detail
817
 
{
818
 
  template <typename AsyncReadStream, typename Allocator,
819
 
      typename MatchCondition, typename ReadHandler>
820
 
  class read_until_match_handler
821
 
  {
822
 
  public:
823
 
    read_until_match_handler(AsyncReadStream& stream,
824
 
        asio::basic_streambuf<Allocator>& streambuf,
825
 
        MatchCondition match_condition, std::size_t next_search_start,
826
 
        ReadHandler handler)
827
 
      : stream_(stream),
828
 
        streambuf_(streambuf),
829
 
        match_condition_(match_condition),
830
 
        next_search_start_(next_search_start),
831
 
        handler_(handler)
832
 
    {
833
 
    }
834
 
 
835
 
    void operator()(const asio::error_code& ec,
836
 
        std::size_t bytes_transferred)
837
 
    {
838
 
      // Check for errors.
839
 
      if (ec)
840
 
      {
841
 
        std::size_t bytes = 0;
842
 
        handler_(ec, bytes);
843
 
        return;
844
 
      }
845
 
 
846
 
      // Commit received data to streambuf's get area.
847
 
      streambuf_.commit(bytes_transferred);
848
 
 
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);
857
 
 
858
 
      // Look for a match.
859
 
      std::pair<iterator, bool> result = match_condition_(start, end);
860
 
      if (result.first != end)
861
 
      {
862
 
        if (result.second)
863
 
        {
864
 
          // Full match. We're done.
865
 
          std::size_t bytes = result.first - begin;
866
 
          handler_(ec, bytes);
867
 
          return;
868
 
        }
869
 
        else
870
 
        {
871
 
          // Partial match. Next search needs to start from beginning of match.
872
 
          next_search_start_ = result.first - begin;
873
 
        }
874
 
      }
875
 
      else
876
 
      {
877
 
        // No match. Next search can start with the new data.
878
 
        next_search_start_ = end - begin;
879
 
      }
880
 
 
881
 
      // Check if buffer is full.
882
 
      if (streambuf_.size() == streambuf_.max_size())
883
 
      {
884
 
        std::size_t bytes = 0;
885
 
        asio::error_code ec(error::not_found);
886
 
        handler_(ec, bytes);
887
 
        return;
888
 
      }
889
 
 
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);
894
 
    }
895
 
 
896
 
  //private:
897
 
    AsyncReadStream& stream_;
898
 
    asio::basic_streambuf<Allocator>& streambuf_;
899
 
    MatchCondition match_condition_;
900
 
    std::size_t next_search_start_;
901
 
    ReadHandler handler_;
902
 
  };
903
 
 
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)
909
 
  {
910
 
    return asio_handler_alloc_helpers::allocate(
911
 
        size, &this_handler->handler_);
912
 
  }
913
 
 
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)
919
 
  {
920
 
    asio_handler_alloc_helpers::deallocate(
921
 
        pointer, size, &this_handler->handler_);
922
 
  }
923
 
 
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)
929
 
  {
930
 
    asio_handler_invoke_helpers::invoke(
931
 
        function, &this_handler->handler_);
932
 
  }
933
 
} // namespace detail
934
 
 
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*)
941
 
{
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);
949
 
 
950
 
  // Look for a match.
951
 
  std::size_t next_search_start;
952
 
  std::pair<iterator, bool> result = match_condition(begin, end);
953
 
  if (result.first != end)
954
 
  {
955
 
    if (result.second)
956
 
    {
957
 
      // Full match. We're done.
958
 
      asio::error_code ec;
959
 
      std::size_t bytes = result.first - begin;
960
 
      s.io_service().post(detail::bind_handler(handler, ec, bytes));
961
 
      return;
962
 
    }
963
 
    else
964
 
    {
965
 
      // Partial match. Next search needs to start from beginning of match.
966
 
      next_search_start = result.first - begin;
967
 
    }
968
 
  }
969
 
  else
970
 
  {
971
 
    // No match. Next search can start with the new data.
972
 
    next_search_start = end - begin;
973
 
  }
974
 
 
975
 
  // Check if buffer is full.
976
 
  if (b.size() == b.max_size())
977
 
  {
978
 
    asio::error_code ec(error::not_found);
979
 
    s.io_service().post(detail::bind_handler(handler, ec, 0));
980
 
    return;
981
 
  }
982
 
 
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));
990
 
}
991
 
 
992
 
} // namespace asio
993
 
 
994
 
#include "asio/detail/pop_options.hpp"
995
 
 
996
 
#endif // ASIO_READ_UNTIL_IPP