read_until.hpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902
  1. //
  2. // impl/read_until.hpp
  3. // ~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2011 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. #ifndef ASIO_IMPL_READ_UNTIL_HPP
  11. #define ASIO_IMPL_READ_UNTIL_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <algorithm>
  16. #include <string>
  17. #include <vector>
  18. #include <utility>
  19. #include <boost/limits.hpp>
  20. #include "asio/buffer.hpp"
  21. #include "asio/buffers_iterator.hpp"
  22. #include "asio/detail/bind_handler.hpp"
  23. #include "asio/detail/handler_alloc_helpers.hpp"
  24. #include "asio/detail/handler_invoke_helpers.hpp"
  25. #include "asio/detail/throw_error.hpp"
  26. #include "asio/detail/push_options.hpp"
  27. namespace asio {
  28. template <typename SyncReadStream, typename Allocator>
  29. inline std::size_t read_until(SyncReadStream& s,
  30. asio::basic_streambuf<Allocator>& b, char delim)
  31. {
  32. asio::error_code ec;
  33. std::size_t bytes_transferred = read_until(s, b, delim, ec);
  34. asio::detail::throw_error(ec);
  35. return bytes_transferred;
  36. }
  37. template <typename SyncReadStream, typename Allocator>
  38. std::size_t read_until(SyncReadStream& s,
  39. asio::basic_streambuf<Allocator>& b, char delim,
  40. asio::error_code& ec)
  41. {
  42. std::size_t search_position = 0;
  43. for (;;)
  44. {
  45. // Determine the range of the data to be searched.
  46. typedef typename asio::basic_streambuf<
  47. Allocator>::const_buffers_type const_buffers_type;
  48. typedef asio::buffers_iterator<const_buffers_type> iterator;
  49. const_buffers_type buffers = b.data();
  50. iterator begin = iterator::begin(buffers);
  51. iterator start = begin + search_position;
  52. iterator end = iterator::end(buffers);
  53. // Look for a match.
  54. iterator iter = std::find(start, end, delim);
  55. if (iter != end)
  56. {
  57. // Found a match. We're done.
  58. ec = asio::error_code();
  59. return iter - begin + 1;
  60. }
  61. else
  62. {
  63. // No match. Next search can start with the new data.
  64. search_position = end - begin;
  65. }
  66. // Check if buffer is full.
  67. if (b.size() == b.max_size())
  68. {
  69. ec = error::not_found;
  70. return 0;
  71. }
  72. // Need more data.
  73. std::size_t bytes_to_read = read_size_helper(b, 65536);
  74. b.commit(s.read_some(b.prepare(bytes_to_read), ec));
  75. if (ec)
  76. return 0;
  77. }
  78. }
  79. template <typename SyncReadStream, typename Allocator>
  80. inline std::size_t read_until(SyncReadStream& s,
  81. asio::basic_streambuf<Allocator>& b, const std::string& delim)
  82. {
  83. asio::error_code ec;
  84. std::size_t bytes_transferred = read_until(s, b, delim, ec);
  85. asio::detail::throw_error(ec);
  86. return bytes_transferred;
  87. }
  88. namespace detail
  89. {
  90. // Algorithm that finds a subsequence of equal values in a sequence. Returns
  91. // (iterator,true) if a full match was found, in which case the iterator
  92. // points to the beginning of the match. Returns (iterator,false) if a
  93. // partial match was found at the end of the first sequence, in which case
  94. // the iterator points to the beginning of the partial match. Returns
  95. // (last1,false) if no full or partial match was found.
  96. template <typename Iterator1, typename Iterator2>
  97. std::pair<Iterator1, bool> partial_search(
  98. Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2)
  99. {
  100. for (Iterator1 iter1 = first1; iter1 != last1; ++iter1)
  101. {
  102. Iterator1 test_iter1 = iter1;
  103. Iterator2 test_iter2 = first2;
  104. for (;; ++test_iter1, ++test_iter2)
  105. {
  106. if (test_iter2 == last2)
  107. return std::make_pair(iter1, true);
  108. if (test_iter1 == last1)
  109. {
  110. if (test_iter2 != first2)
  111. return std::make_pair(iter1, false);
  112. else
  113. break;
  114. }
  115. if (*test_iter1 != *test_iter2)
  116. break;
  117. }
  118. }
  119. return std::make_pair(last1, false);
  120. }
  121. } // namespace detail
  122. template <typename SyncReadStream, typename Allocator>
  123. std::size_t read_until(SyncReadStream& s,
  124. asio::basic_streambuf<Allocator>& b, const std::string& delim,
  125. asio::error_code& ec)
  126. {
  127. std::size_t search_position = 0;
  128. for (;;)
  129. {
  130. // Determine the range of the data to be searched.
  131. typedef typename asio::basic_streambuf<
  132. Allocator>::const_buffers_type const_buffers_type;
  133. typedef asio::buffers_iterator<const_buffers_type> iterator;
  134. const_buffers_type buffers = b.data();
  135. iterator begin = iterator::begin(buffers);
  136. iterator start = begin + search_position;
  137. iterator end = iterator::end(buffers);
  138. // Look for a match.
  139. std::pair<iterator, bool> result = detail::partial_search(
  140. start, end, delim.begin(), delim.end());
  141. if (result.first != end)
  142. {
  143. if (result.second)
  144. {
  145. // Full match. We're done.
  146. ec = asio::error_code();
  147. return result.first - begin + delim.length();
  148. }
  149. else
  150. {
  151. // Partial match. Next search needs to start from beginning of match.
  152. search_position = result.first - begin;
  153. }
  154. }
  155. else
  156. {
  157. // No match. Next search can start with the new data.
  158. search_position = end - begin;
  159. }
  160. // Check if buffer is full.
  161. if (b.size() == b.max_size())
  162. {
  163. ec = error::not_found;
  164. return 0;
  165. }
  166. // Need more data.
  167. std::size_t bytes_to_read = read_size_helper(b, 65536);
  168. b.commit(s.read_some(b.prepare(bytes_to_read), ec));
  169. if (ec)
  170. return 0;
  171. }
  172. }
  173. template <typename SyncReadStream, typename Allocator>
  174. inline std::size_t read_until(SyncReadStream& s,
  175. asio::basic_streambuf<Allocator>& b, const boost::regex& expr)
  176. {
  177. asio::error_code ec;
  178. std::size_t bytes_transferred = read_until(s, b, expr, ec);
  179. asio::detail::throw_error(ec);
  180. return bytes_transferred;
  181. }
  182. template <typename SyncReadStream, typename Allocator>
  183. std::size_t read_until(SyncReadStream& s,
  184. asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
  185. asio::error_code& ec)
  186. {
  187. std::size_t search_position = 0;
  188. for (;;)
  189. {
  190. // Determine the range of the data to be searched.
  191. typedef typename asio::basic_streambuf<
  192. Allocator>::const_buffers_type const_buffers_type;
  193. typedef asio::buffers_iterator<const_buffers_type> iterator;
  194. const_buffers_type buffers = b.data();
  195. iterator begin = iterator::begin(buffers);
  196. iterator start = begin + search_position;
  197. iterator end = iterator::end(buffers);
  198. // Look for a match.
  199. boost::match_results<iterator,
  200. typename std::vector<boost::sub_match<iterator> >::allocator_type>
  201. match_results;
  202. if (regex_search(start, end, match_results, expr,
  203. boost::match_default | boost::match_partial))
  204. {
  205. if (match_results[0].matched)
  206. {
  207. // Full match. We're done.
  208. ec = asio::error_code();
  209. return match_results[0].second - begin;
  210. }
  211. else
  212. {
  213. // Partial match. Next search needs to start from beginning of match.
  214. search_position = match_results[0].first - begin;
  215. }
  216. }
  217. else
  218. {
  219. // No match. Next search can start with the new data.
  220. search_position = end - begin;
  221. }
  222. // Check if buffer is full.
  223. if (b.size() == b.max_size())
  224. {
  225. ec = error::not_found;
  226. return 0;
  227. }
  228. // Need more data.
  229. std::size_t bytes_to_read = read_size_helper(b, 65536);
  230. b.commit(s.read_some(b.prepare(bytes_to_read), ec));
  231. if (ec)
  232. return 0;
  233. }
  234. }
  235. template <typename SyncReadStream, typename Allocator, typename MatchCondition>
  236. std::size_t read_until(SyncReadStream& s,
  237. asio::basic_streambuf<Allocator>& b,
  238. MatchCondition match_condition, asio::error_code& ec,
  239. typename boost::enable_if<is_match_condition<MatchCondition> >::type*)
  240. {
  241. std::size_t search_position = 0;
  242. for (;;)
  243. {
  244. // Determine the range of the data to be searched.
  245. typedef typename asio::basic_streambuf<
  246. Allocator>::const_buffers_type const_buffers_type;
  247. typedef asio::buffers_iterator<const_buffers_type> iterator;
  248. const_buffers_type buffers = b.data();
  249. iterator begin = iterator::begin(buffers);
  250. iterator start = begin + search_position;
  251. iterator end = iterator::end(buffers);
  252. // Look for a match.
  253. std::pair<iterator, bool> result = match_condition(start, end);
  254. if (result.second)
  255. {
  256. // Full match. We're done.
  257. ec = asio::error_code();
  258. return result.first - begin;
  259. }
  260. else if (result.first != end)
  261. {
  262. // Partial match. Next search needs to start from beginning of match.
  263. search_position = result.first - begin;
  264. }
  265. else
  266. {
  267. // No match. Next search can start with the new data.
  268. search_position = end - begin;
  269. }
  270. // Check if buffer is full.
  271. if (b.size() == b.max_size())
  272. {
  273. ec = error::not_found;
  274. return 0;
  275. }
  276. // Need more data.
  277. std::size_t bytes_to_read = read_size_helper(b, 65536);
  278. b.commit(s.read_some(b.prepare(bytes_to_read), ec));
  279. if (ec)
  280. return 0;
  281. }
  282. }
  283. template <typename SyncReadStream, typename Allocator, typename MatchCondition>
  284. inline std::size_t read_until(SyncReadStream& s,
  285. asio::basic_streambuf<Allocator>& b, MatchCondition match_condition,
  286. typename boost::enable_if<is_match_condition<MatchCondition> >::type*)
  287. {
  288. asio::error_code ec;
  289. std::size_t bytes_transferred = read_until(s, b, match_condition, ec);
  290. asio::detail::throw_error(ec);
  291. return bytes_transferred;
  292. }
  293. namespace detail
  294. {
  295. template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
  296. class read_until_delim_op
  297. {
  298. public:
  299. read_until_delim_op(AsyncReadStream& stream,
  300. asio::basic_streambuf<Allocator>& streambuf,
  301. char delim, ReadHandler handler)
  302. : stream_(stream),
  303. streambuf_(streambuf),
  304. delim_(delim),
  305. search_position_(0),
  306. handler_(handler)
  307. {
  308. }
  309. void operator()(const asio::error_code& ec,
  310. std::size_t bytes_transferred, int start = 0)
  311. {
  312. const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
  313. std::size_t bytes_to_read;
  314. switch (start)
  315. {
  316. case 1:
  317. for (;;)
  318. {
  319. {
  320. // Determine the range of the data to be searched.
  321. typedef typename asio::basic_streambuf<
  322. Allocator>::const_buffers_type const_buffers_type;
  323. typedef asio::buffers_iterator<const_buffers_type> iterator;
  324. const_buffers_type buffers = streambuf_.data();
  325. iterator begin = iterator::begin(buffers);
  326. iterator start = begin + search_position_;
  327. iterator end = iterator::end(buffers);
  328. // Look for a match.
  329. iterator iter = std::find(start, end, delim_);
  330. if (iter != end)
  331. {
  332. // Found a match. We're done.
  333. search_position_ = iter - begin + 1;
  334. bytes_to_read = 0;
  335. }
  336. // No match yet. Check if buffer is full.
  337. else if (streambuf_.size() == streambuf_.max_size())
  338. {
  339. search_position_ = not_found;
  340. bytes_to_read = 0;
  341. }
  342. // Need to read some more data.
  343. else
  344. {
  345. // Next search can start with the new data.
  346. search_position_ = end - begin;
  347. bytes_to_read = read_size_helper(streambuf_, 65536);
  348. }
  349. }
  350. // Check if we're done.
  351. if (!start && bytes_to_read == 0)
  352. break;
  353. // Start a new asynchronous read operation to obtain more data.
  354. stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this);
  355. return; default:
  356. streambuf_.commit(bytes_transferred);
  357. if (ec || bytes_transferred == 0)
  358. break;
  359. }
  360. const asio::error_code result_ec =
  361. (search_position_ == not_found)
  362. ? error::not_found : ec;
  363. const std::size_t result_n =
  364. (ec || search_position_ == not_found)
  365. ? 0 : search_position_;
  366. handler_(result_ec, result_n);
  367. }
  368. }
  369. //private:
  370. AsyncReadStream& stream_;
  371. asio::basic_streambuf<Allocator>& streambuf_;
  372. char delim_;
  373. std::size_t search_position_;
  374. ReadHandler handler_;
  375. };
  376. template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
  377. inline void* asio_handler_allocate(std::size_t size,
  378. read_until_delim_op<AsyncReadStream,
  379. Allocator, ReadHandler>* this_handler)
  380. {
  381. return asio_handler_alloc_helpers::allocate(
  382. size, this_handler->handler_);
  383. }
  384. template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
  385. inline void asio_handler_deallocate(void* pointer, std::size_t size,
  386. read_until_delim_op<AsyncReadStream,
  387. Allocator, ReadHandler>* this_handler)
  388. {
  389. asio_handler_alloc_helpers::deallocate(
  390. pointer, size, this_handler->handler_);
  391. }
  392. template <typename Function, typename AsyncReadStream, typename Allocator,
  393. typename ReadHandler>
  394. inline void asio_handler_invoke(const Function& function,
  395. read_until_delim_op<AsyncReadStream,
  396. Allocator, ReadHandler>* this_handler)
  397. {
  398. asio_handler_invoke_helpers::invoke(
  399. function, this_handler->handler_);
  400. }
  401. } // namespace detail
  402. template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
  403. void async_read_until(AsyncReadStream& s,
  404. asio::basic_streambuf<Allocator>& b, char delim, ReadHandler handler)
  405. {
  406. detail::read_until_delim_op<
  407. AsyncReadStream, Allocator, ReadHandler>(
  408. s, b, delim, handler)(
  409. asio::error_code(), 0, 1);
  410. }
  411. namespace detail
  412. {
  413. template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
  414. class read_until_delim_string_op
  415. {
  416. public:
  417. read_until_delim_string_op(AsyncReadStream& stream,
  418. asio::basic_streambuf<Allocator>& streambuf,
  419. const std::string& delim, ReadHandler handler)
  420. : stream_(stream),
  421. streambuf_(streambuf),
  422. delim_(delim),
  423. search_position_(0),
  424. handler_(handler)
  425. {
  426. }
  427. void operator()(const asio::error_code& ec,
  428. std::size_t bytes_transferred, int start = 0)
  429. {
  430. const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
  431. std::size_t bytes_to_read;
  432. switch (start)
  433. {
  434. case 1:
  435. for (;;)
  436. {
  437. {
  438. // Determine the range of the data to be searched.
  439. typedef typename asio::basic_streambuf<
  440. Allocator>::const_buffers_type const_buffers_type;
  441. typedef asio::buffers_iterator<const_buffers_type> iterator;
  442. const_buffers_type buffers = streambuf_.data();
  443. iterator begin = iterator::begin(buffers);
  444. iterator start = begin + search_position_;
  445. iterator end = iterator::end(buffers);
  446. // Look for a match.
  447. std::pair<iterator, bool> result = detail::partial_search(
  448. start, end, delim_.begin(), delim_.end());
  449. if (result.first != end && result.second)
  450. {
  451. // Full match. We're done.
  452. search_position_ = result.first - begin + delim_.length();
  453. bytes_to_read = 0;
  454. }
  455. // No match yet. Check if buffer is full.
  456. else if (streambuf_.size() == streambuf_.max_size())
  457. {
  458. search_position_ = not_found;
  459. bytes_to_read = 0;
  460. }
  461. // Need to read some more data.
  462. else
  463. {
  464. if (result.first != end)
  465. {
  466. // Partial match. Next search needs to start from beginning of
  467. // match.
  468. search_position_ = result.first - begin;
  469. }
  470. else
  471. {
  472. // Next search can start with the new data.
  473. search_position_ = end - begin;
  474. }
  475. bytes_to_read = read_size_helper(streambuf_, 65536);
  476. }
  477. }
  478. // Check if we're done.
  479. if (!start && bytes_to_read == 0)
  480. break;
  481. // Start a new asynchronous read operation to obtain more data.
  482. stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this);
  483. return; default:
  484. streambuf_.commit(bytes_transferred);
  485. if (ec || bytes_transferred == 0)
  486. break;
  487. }
  488. const asio::error_code result_ec =
  489. (search_position_ == not_found)
  490. ? error::not_found : ec;
  491. const std::size_t result_n =
  492. (ec || search_position_ == not_found)
  493. ? 0 : search_position_;
  494. handler_(result_ec, result_n);
  495. }
  496. }
  497. //private:
  498. AsyncReadStream& stream_;
  499. asio::basic_streambuf<Allocator>& streambuf_;
  500. std::string delim_;
  501. std::size_t search_position_;
  502. ReadHandler handler_;
  503. };
  504. template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
  505. inline void* asio_handler_allocate(std::size_t size,
  506. read_until_delim_string_op<AsyncReadStream,
  507. Allocator, ReadHandler>* this_handler)
  508. {
  509. return asio_handler_alloc_helpers::allocate(
  510. size, this_handler->handler_);
  511. }
  512. template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
  513. inline void asio_handler_deallocate(void* pointer, std::size_t size,
  514. read_until_delim_string_op<AsyncReadStream,
  515. Allocator, ReadHandler>* this_handler)
  516. {
  517. asio_handler_alloc_helpers::deallocate(
  518. pointer, size, this_handler->handler_);
  519. }
  520. template <typename Function, typename AsyncReadStream,
  521. typename Allocator, typename ReadHandler>
  522. inline void asio_handler_invoke(const Function& function,
  523. read_until_delim_string_op<AsyncReadStream,
  524. Allocator, ReadHandler>* this_handler)
  525. {
  526. asio_handler_invoke_helpers::invoke(
  527. function, this_handler->handler_);
  528. }
  529. } // namespace detail
  530. template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
  531. void async_read_until(AsyncReadStream& s,
  532. asio::basic_streambuf<Allocator>& b, const std::string& delim,
  533. ReadHandler handler)
  534. {
  535. detail::read_until_delim_string_op<
  536. AsyncReadStream, Allocator, ReadHandler>(
  537. s, b, delim, handler)(
  538. asio::error_code(), 0, 1);
  539. }
  540. namespace detail
  541. {
  542. template <typename AsyncReadStream, typename Allocator,
  543. typename RegEx, typename ReadHandler>
  544. class read_until_expr_op
  545. {
  546. public:
  547. read_until_expr_op(AsyncReadStream& stream,
  548. asio::basic_streambuf<Allocator>& streambuf,
  549. const boost::regex& expr, ReadHandler handler)
  550. : stream_(stream),
  551. streambuf_(streambuf),
  552. expr_(expr),
  553. search_position_(0),
  554. handler_(handler)
  555. {
  556. }
  557. void operator()(const asio::error_code& ec,
  558. std::size_t bytes_transferred, int start = 0)
  559. {
  560. const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
  561. std::size_t bytes_to_read;
  562. switch (start)
  563. {
  564. case 1:
  565. for (;;)
  566. {
  567. {
  568. // Determine the range of the data to be searched.
  569. typedef typename asio::basic_streambuf<
  570. Allocator>::const_buffers_type const_buffers_type;
  571. typedef asio::buffers_iterator<const_buffers_type> iterator;
  572. const_buffers_type buffers = streambuf_.data();
  573. iterator begin = iterator::begin(buffers);
  574. iterator start = begin + search_position_;
  575. iterator end = iterator::end(buffers);
  576. // Look for a match.
  577. boost::match_results<iterator,
  578. typename std::vector<boost::sub_match<iterator> >::allocator_type>
  579. match_results;
  580. bool match = regex_search(start, end, match_results, expr_,
  581. boost::match_default | boost::match_partial);
  582. if (match && match_results[0].matched)
  583. {
  584. // Full match. We're done.
  585. search_position_ = match_results[0].second - begin;
  586. bytes_to_read = 0;
  587. }
  588. // No match yet. Check if buffer is full.
  589. else if (streambuf_.size() == streambuf_.max_size())
  590. {
  591. search_position_ = not_found;
  592. bytes_to_read = 0;
  593. }
  594. // Need to read some more data.
  595. else
  596. {
  597. if (match)
  598. {
  599. // Partial match. Next search needs to start from beginning of
  600. // match.
  601. search_position_ = match_results[0].first - begin;
  602. }
  603. else
  604. {
  605. // Next search can start with the new data.
  606. search_position_ = end - begin;
  607. }
  608. bytes_to_read = read_size_helper(streambuf_, 65536);
  609. }
  610. }
  611. // Check if we're done.
  612. if (!start && bytes_to_read == 0)
  613. break;
  614. // Start a new asynchronous read operation to obtain more data.
  615. stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this);
  616. return; default:
  617. streambuf_.commit(bytes_transferred);
  618. if (ec || bytes_transferred == 0)
  619. break;
  620. }
  621. const asio::error_code result_ec =
  622. (search_position_ == not_found)
  623. ? error::not_found : ec;
  624. const std::size_t result_n =
  625. (ec || search_position_ == not_found)
  626. ? 0 : search_position_;
  627. handler_(result_ec, result_n);
  628. }
  629. }
  630. //private:
  631. AsyncReadStream& stream_;
  632. asio::basic_streambuf<Allocator>& streambuf_;
  633. RegEx expr_;
  634. std::size_t search_position_;
  635. ReadHandler handler_;
  636. };
  637. template <typename AsyncReadStream, typename Allocator,
  638. typename RegEx, typename ReadHandler>
  639. inline void* asio_handler_allocate(std::size_t size,
  640. read_until_expr_op<AsyncReadStream,
  641. Allocator, RegEx, ReadHandler>* this_handler)
  642. {
  643. return asio_handler_alloc_helpers::allocate(
  644. size, this_handler->handler_);
  645. }
  646. template <typename AsyncReadStream, typename Allocator,
  647. typename RegEx, typename ReadHandler>
  648. inline void asio_handler_deallocate(void* pointer, std::size_t size,
  649. read_until_expr_op<AsyncReadStream,
  650. Allocator, RegEx, ReadHandler>* this_handler)
  651. {
  652. asio_handler_alloc_helpers::deallocate(
  653. pointer, size, this_handler->handler_);
  654. }
  655. template <typename Function, typename AsyncReadStream, typename Allocator,
  656. typename RegEx, typename ReadHandler>
  657. inline void asio_handler_invoke(const Function& function,
  658. read_until_expr_op<AsyncReadStream,
  659. Allocator, RegEx, ReadHandler>* this_handler)
  660. {
  661. asio_handler_invoke_helpers::invoke(
  662. function, this_handler->handler_);
  663. }
  664. } // namespace detail
  665. template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
  666. void async_read_until(AsyncReadStream& s,
  667. asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
  668. ReadHandler handler)
  669. {
  670. detail::read_until_expr_op<AsyncReadStream,
  671. Allocator, boost::regex, ReadHandler>(
  672. s, b, expr, handler)(
  673. asio::error_code(), 0, 1);
  674. }
  675. namespace detail
  676. {
  677. template <typename AsyncReadStream, typename Allocator,
  678. typename MatchCondition, typename ReadHandler>
  679. class read_until_match_op
  680. {
  681. public:
  682. read_until_match_op(AsyncReadStream& stream,
  683. asio::basic_streambuf<Allocator>& streambuf,
  684. MatchCondition match_condition, ReadHandler handler)
  685. : stream_(stream),
  686. streambuf_(streambuf),
  687. match_condition_(match_condition),
  688. search_position_(0),
  689. handler_(handler)
  690. {
  691. }
  692. void operator()(const asio::error_code& ec,
  693. std::size_t bytes_transferred, int start = 0)
  694. {
  695. const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
  696. std::size_t bytes_to_read;
  697. switch (start)
  698. {
  699. case 1:
  700. for (;;)
  701. {
  702. {
  703. // Determine the range of the data to be searched.
  704. typedef typename asio::basic_streambuf<
  705. Allocator>::const_buffers_type const_buffers_type;
  706. typedef asio::buffers_iterator<const_buffers_type> iterator;
  707. const_buffers_type buffers = streambuf_.data();
  708. iterator begin = iterator::begin(buffers);
  709. iterator start = begin + search_position_;
  710. iterator end = iterator::end(buffers);
  711. // Look for a match.
  712. std::pair<iterator, bool> result = match_condition_(start, end);
  713. if (result.second)
  714. {
  715. // Full match. We're done.
  716. search_position_ = result.first - begin;
  717. bytes_to_read = 0;
  718. }
  719. // No match yet. Check if buffer is full.
  720. else if (streambuf_.size() == streambuf_.max_size())
  721. {
  722. search_position_ = not_found;
  723. bytes_to_read = 0;
  724. }
  725. // Need to read some more data.
  726. else
  727. {
  728. if (result.first != end)
  729. {
  730. // Partial match. Next search needs to start from beginning of
  731. // match.
  732. search_position_ = result.first - begin;
  733. }
  734. else
  735. {
  736. // Next search can start with the new data.
  737. search_position_ = end - begin;
  738. }
  739. bytes_to_read = read_size_helper(streambuf_, 65536);
  740. }
  741. }
  742. // Check if we're done.
  743. if (!start && bytes_to_read == 0)
  744. break;
  745. // Start a new asynchronous read operation to obtain more data.
  746. stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this);
  747. return; default:
  748. streambuf_.commit(bytes_transferred);
  749. if (ec || bytes_transferred == 0)
  750. break;
  751. }
  752. const asio::error_code result_ec =
  753. (search_position_ == not_found)
  754. ? error::not_found : ec;
  755. const std::size_t result_n =
  756. (ec || search_position_ == not_found)
  757. ? 0 : search_position_;
  758. handler_(result_ec, result_n);
  759. }
  760. }
  761. //private:
  762. AsyncReadStream& stream_;
  763. asio::basic_streambuf<Allocator>& streambuf_;
  764. MatchCondition match_condition_;
  765. std::size_t search_position_;
  766. ReadHandler handler_;
  767. };
  768. template <typename AsyncReadStream, typename Allocator,
  769. typename MatchCondition, typename ReadHandler>
  770. inline void* asio_handler_allocate(std::size_t size,
  771. read_until_match_op<AsyncReadStream,
  772. Allocator, MatchCondition, ReadHandler>* this_handler)
  773. {
  774. return asio_handler_alloc_helpers::allocate(
  775. size, this_handler->handler_);
  776. }
  777. template <typename AsyncReadStream, typename Allocator,
  778. typename MatchCondition, typename ReadHandler>
  779. inline void asio_handler_deallocate(void* pointer, std::size_t size,
  780. read_until_match_op<AsyncReadStream,
  781. Allocator, MatchCondition, ReadHandler>* this_handler)
  782. {
  783. asio_handler_alloc_helpers::deallocate(
  784. pointer, size, this_handler->handler_);
  785. }
  786. template <typename Function, typename AsyncReadStream, typename Allocator,
  787. typename MatchCondition, typename ReadHandler>
  788. inline void asio_handler_invoke(const Function& function,
  789. read_until_match_op<AsyncReadStream,
  790. Allocator, MatchCondition, ReadHandler>* this_handler)
  791. {
  792. asio_handler_invoke_helpers::invoke(
  793. function, this_handler->handler_);
  794. }
  795. } // namespace detail
  796. template <typename AsyncReadStream, typename Allocator,
  797. typename MatchCondition, typename ReadHandler>
  798. void async_read_until(AsyncReadStream& s,
  799. asio::basic_streambuf<Allocator>& b,
  800. MatchCondition match_condition, ReadHandler handler,
  801. typename boost::enable_if<is_match_condition<MatchCondition> >::type*)
  802. {
  803. detail::read_until_match_op<
  804. AsyncReadStream, Allocator, MatchCondition, ReadHandler>(
  805. s, b, match_condition, handler)(
  806. asio::error_code(), 0, 1);
  807. }
  808. } // namespace asio
  809. #include "asio/detail/pop_options.hpp"
  810. #endif // ASIO_IMPL_READ_UNTIL_HPP