/Src/Dependencies/Boost/boost/asio/impl/read_until.hpp

http://hadesmem.googlecode.com/ · C++ Header · 1086 lines · 882 code · 112 blank · 92 comment · 108 complexity · f0646d20a0e3a9eafb4b98f87473efc0 MD5 · raw file

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