Chris@16: // Chris@16: // impl/read_until.hpp Chris@16: // ~~~~~~~~~~~~~~~~~~~ Chris@16: // Chris@101: // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com) Chris@16: // Chris@16: // Distributed under the Boost Software License, Version 1.0. (See accompanying Chris@16: // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: // Chris@16: Chris@16: #ifndef BOOST_ASIO_IMPL_READ_UNTIL_HPP Chris@16: #define BOOST_ASIO_IMPL_READ_UNTIL_HPP Chris@16: Chris@16: #if defined(_MSC_VER) && (_MSC_VER >= 1200) Chris@16: # pragma once Chris@16: #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: Chris@16: namespace boost { Chris@16: namespace asio { Chris@16: Chris@16: template Chris@16: inline std::size_t read_until(SyncReadStream& s, Chris@16: boost::asio::basic_streambuf& b, char delim) Chris@16: { Chris@16: boost::system::error_code ec; Chris@16: std::size_t bytes_transferred = read_until(s, b, delim, ec); Chris@16: boost::asio::detail::throw_error(ec, "read_until"); Chris@16: return bytes_transferred; Chris@16: } Chris@16: Chris@16: template Chris@16: std::size_t read_until(SyncReadStream& s, Chris@16: boost::asio::basic_streambuf& b, char delim, Chris@16: boost::system::error_code& ec) Chris@16: { Chris@16: std::size_t search_position = 0; Chris@16: for (;;) Chris@16: { Chris@16: // Determine the range of the data to be searched. Chris@16: typedef typename boost::asio::basic_streambuf< Chris@16: Allocator>::const_buffers_type const_buffers_type; Chris@16: typedef boost::asio::buffers_iterator iterator; Chris@16: const_buffers_type buffers = b.data(); Chris@16: iterator begin = iterator::begin(buffers); Chris@16: iterator start_pos = begin + search_position; Chris@16: iterator end = iterator::end(buffers); Chris@16: Chris@16: // Look for a match. Chris@16: iterator iter = std::find(start_pos, end, delim); Chris@16: if (iter != end) Chris@16: { Chris@16: // Found a match. We're done. Chris@16: ec = boost::system::error_code(); Chris@16: return iter - begin + 1; Chris@16: } Chris@16: else Chris@16: { Chris@16: // No match. Next search can start with the new data. Chris@16: search_position = end - begin; Chris@16: } Chris@16: Chris@16: // Check if buffer is full. Chris@16: if (b.size() == b.max_size()) Chris@16: { Chris@16: ec = error::not_found; Chris@16: return 0; Chris@16: } Chris@16: Chris@16: // Need more data. Chris@16: std::size_t bytes_to_read = read_size_helper(b, 65536); Chris@16: b.commit(s.read_some(b.prepare(bytes_to_read), ec)); Chris@16: if (ec) Chris@16: return 0; Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: inline std::size_t read_until(SyncReadStream& s, Chris@16: boost::asio::basic_streambuf& b, const std::string& delim) Chris@16: { Chris@16: boost::system::error_code ec; Chris@16: std::size_t bytes_transferred = read_until(s, b, delim, ec); Chris@16: boost::asio::detail::throw_error(ec, "read_until"); Chris@16: return bytes_transferred; Chris@16: } Chris@16: Chris@16: namespace detail Chris@16: { Chris@16: // Algorithm that finds a subsequence of equal values in a sequence. Returns Chris@16: // (iterator,true) if a full match was found, in which case the iterator Chris@16: // points to the beginning of the match. Returns (iterator,false) if a Chris@16: // partial match was found at the end of the first sequence, in which case Chris@16: // the iterator points to the beginning of the partial match. Returns Chris@16: // (last1,false) if no full or partial match was found. Chris@16: template Chris@16: std::pair partial_search( Chris@16: Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2) Chris@16: { Chris@16: for (Iterator1 iter1 = first1; iter1 != last1; ++iter1) Chris@16: { Chris@16: Iterator1 test_iter1 = iter1; Chris@16: Iterator2 test_iter2 = first2; Chris@16: for (;; ++test_iter1, ++test_iter2) Chris@16: { Chris@16: if (test_iter2 == last2) Chris@16: return std::make_pair(iter1, true); Chris@16: if (test_iter1 == last1) Chris@16: { Chris@16: if (test_iter2 != first2) Chris@16: return std::make_pair(iter1, false); Chris@16: else Chris@16: break; Chris@16: } Chris@16: if (*test_iter1 != *test_iter2) Chris@16: break; Chris@16: } Chris@16: } Chris@16: return std::make_pair(last1, false); Chris@16: } Chris@16: } // namespace detail Chris@16: Chris@16: template Chris@16: std::size_t read_until(SyncReadStream& s, Chris@16: boost::asio::basic_streambuf& b, const std::string& delim, Chris@16: boost::system::error_code& ec) Chris@16: { Chris@16: std::size_t search_position = 0; Chris@16: for (;;) Chris@16: { Chris@16: // Determine the range of the data to be searched. Chris@16: typedef typename boost::asio::basic_streambuf< Chris@16: Allocator>::const_buffers_type const_buffers_type; Chris@16: typedef boost::asio::buffers_iterator iterator; Chris@16: const_buffers_type buffers = b.data(); Chris@16: iterator begin = iterator::begin(buffers); Chris@16: iterator start_pos = begin + search_position; Chris@16: iterator end = iterator::end(buffers); Chris@16: Chris@16: // Look for a match. Chris@16: std::pair result = detail::partial_search( Chris@16: start_pos, end, delim.begin(), delim.end()); Chris@16: if (result.first != end) Chris@16: { Chris@16: if (result.second) Chris@16: { Chris@16: // Full match. We're done. Chris@16: ec = boost::system::error_code(); Chris@16: return result.first - begin + delim.length(); Chris@16: } Chris@16: else Chris@16: { Chris@16: // Partial match. Next search needs to start from beginning of match. Chris@16: search_position = result.first - begin; Chris@16: } Chris@16: } Chris@16: else Chris@16: { Chris@16: // No match. Next search can start with the new data. Chris@16: search_position = end - begin; Chris@16: } Chris@16: Chris@16: // Check if buffer is full. Chris@16: if (b.size() == b.max_size()) Chris@16: { Chris@16: ec = error::not_found; Chris@16: return 0; Chris@16: } Chris@16: Chris@16: // Need more data. Chris@16: std::size_t bytes_to_read = read_size_helper(b, 65536); Chris@16: b.commit(s.read_some(b.prepare(bytes_to_read), ec)); Chris@16: if (ec) Chris@16: return 0; Chris@16: } Chris@16: } Chris@16: Chris@16: #if defined(BOOST_ASIO_HAS_BOOST_REGEX) Chris@16: Chris@16: template Chris@16: inline std::size_t read_until(SyncReadStream& s, Chris@16: boost::asio::basic_streambuf& b, const boost::regex& expr) Chris@16: { Chris@16: boost::system::error_code ec; Chris@16: std::size_t bytes_transferred = read_until(s, b, expr, ec); Chris@16: boost::asio::detail::throw_error(ec, "read_until"); Chris@16: return bytes_transferred; Chris@16: } Chris@16: Chris@16: template Chris@16: std::size_t read_until(SyncReadStream& s, Chris@16: boost::asio::basic_streambuf& b, const boost::regex& expr, Chris@16: boost::system::error_code& ec) Chris@16: { Chris@16: std::size_t search_position = 0; Chris@16: for (;;) Chris@16: { Chris@16: // Determine the range of the data to be searched. Chris@16: typedef typename boost::asio::basic_streambuf< Chris@16: Allocator>::const_buffers_type const_buffers_type; Chris@16: typedef boost::asio::buffers_iterator iterator; Chris@16: const_buffers_type buffers = b.data(); Chris@16: iterator begin = iterator::begin(buffers); Chris@16: iterator start_pos = begin + search_position; Chris@16: iterator end = iterator::end(buffers); Chris@16: Chris@16: // Look for a match. Chris@16: boost::match_results >::allocator_type> Chris@16: match_results; Chris@16: if (regex_search(start_pos, end, match_results, expr, Chris@16: boost::match_default | boost::match_partial)) Chris@16: { Chris@16: if (match_results[0].matched) Chris@16: { Chris@16: // Full match. We're done. Chris@16: ec = boost::system::error_code(); Chris@16: return match_results[0].second - begin; Chris@16: } Chris@16: else Chris@16: { Chris@16: // Partial match. Next search needs to start from beginning of match. Chris@16: search_position = match_results[0].first - begin; Chris@16: } Chris@16: } Chris@16: else Chris@16: { Chris@16: // No match. Next search can start with the new data. Chris@16: search_position = end - begin; Chris@16: } Chris@16: Chris@16: // Check if buffer is full. Chris@16: if (b.size() == b.max_size()) Chris@16: { Chris@16: ec = error::not_found; Chris@16: return 0; Chris@16: } Chris@16: Chris@16: // Need more data. Chris@16: std::size_t bytes_to_read = read_size_helper(b, 65536); Chris@16: b.commit(s.read_some(b.prepare(bytes_to_read), ec)); Chris@16: if (ec) Chris@16: return 0; Chris@16: } Chris@16: } Chris@16: Chris@16: #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) Chris@16: Chris@16: template Chris@16: std::size_t read_until(SyncReadStream& s, Chris@16: boost::asio::basic_streambuf& b, Chris@16: MatchCondition match_condition, boost::system::error_code& ec, Chris@16: typename enable_if::value>::type*) Chris@16: { Chris@16: std::size_t search_position = 0; Chris@16: for (;;) Chris@16: { Chris@16: // Determine the range of the data to be searched. Chris@16: typedef typename boost::asio::basic_streambuf< Chris@16: Allocator>::const_buffers_type const_buffers_type; Chris@16: typedef boost::asio::buffers_iterator iterator; Chris@16: const_buffers_type buffers = b.data(); Chris@16: iterator begin = iterator::begin(buffers); Chris@16: iterator start_pos = begin + search_position; Chris@16: iterator end = iterator::end(buffers); Chris@16: Chris@16: // Look for a match. Chris@16: std::pair result = match_condition(start_pos, end); Chris@16: if (result.second) Chris@16: { Chris@16: // Full match. We're done. Chris@16: ec = boost::system::error_code(); Chris@16: return result.first - begin; Chris@16: } Chris@16: else if (result.first != end) Chris@16: { Chris@16: // Partial match. Next search needs to start from beginning of match. Chris@16: search_position = result.first - begin; Chris@16: } Chris@16: else Chris@16: { Chris@16: // No match. Next search can start with the new data. Chris@16: search_position = end - begin; Chris@16: } Chris@16: Chris@16: // Check if buffer is full. Chris@16: if (b.size() == b.max_size()) Chris@16: { Chris@16: ec = error::not_found; Chris@16: return 0; Chris@16: } Chris@16: Chris@16: // Need more data. Chris@16: std::size_t bytes_to_read = read_size_helper(b, 65536); Chris@16: b.commit(s.read_some(b.prepare(bytes_to_read), ec)); Chris@16: if (ec) Chris@16: return 0; Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: inline std::size_t read_until(SyncReadStream& s, Chris@16: boost::asio::basic_streambuf& b, MatchCondition match_condition, Chris@16: typename enable_if::value>::type*) Chris@16: { Chris@16: boost::system::error_code ec; Chris@16: std::size_t bytes_transferred = read_until(s, b, match_condition, ec); Chris@16: boost::asio::detail::throw_error(ec, "read_until"); Chris@16: return bytes_transferred; Chris@16: } Chris@16: Chris@16: namespace detail Chris@16: { Chris@16: template Chris@16: class read_until_delim_op Chris@16: { Chris@16: public: Chris@16: read_until_delim_op(AsyncReadStream& stream, Chris@16: boost::asio::basic_streambuf& streambuf, Chris@16: char delim, ReadHandler& handler) Chris@16: : stream_(stream), Chris@16: streambuf_(streambuf), Chris@16: delim_(delim), Chris@16: start_(0), Chris@16: search_position_(0), Chris@16: handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) Chris@16: { Chris@16: } Chris@16: Chris@16: #if defined(BOOST_ASIO_HAS_MOVE) Chris@16: read_until_delim_op(const read_until_delim_op& other) Chris@16: : stream_(other.stream_), Chris@16: streambuf_(other.streambuf_), Chris@16: delim_(other.delim_), Chris@16: start_(other.start_), Chris@16: search_position_(other.search_position_), Chris@16: handler_(other.handler_) Chris@16: { Chris@16: } Chris@16: Chris@16: read_until_delim_op(read_until_delim_op&& other) Chris@16: : stream_(other.stream_), Chris@16: streambuf_(other.streambuf_), Chris@16: delim_(other.delim_), Chris@16: start_(other.start_), Chris@16: search_position_(other.search_position_), Chris@16: handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) Chris@16: { Chris@16: } Chris@16: #endif // defined(BOOST_ASIO_HAS_MOVE) Chris@16: Chris@16: void operator()(const boost::system::error_code& ec, Chris@16: std::size_t bytes_transferred, int start = 0) Chris@16: { Chris@16: const std::size_t not_found = (std::numeric_limits::max)(); Chris@16: std::size_t bytes_to_read; Chris@16: switch (start_ = start) Chris@16: { Chris@16: case 1: Chris@16: for (;;) Chris@16: { Chris@16: { Chris@16: // Determine the range of the data to be searched. Chris@16: typedef typename boost::asio::basic_streambuf< Chris@16: Allocator>::const_buffers_type const_buffers_type; Chris@16: typedef boost::asio::buffers_iterator iterator; Chris@16: const_buffers_type buffers = streambuf_.data(); Chris@16: iterator begin = iterator::begin(buffers); Chris@16: iterator start_pos = begin + search_position_; Chris@16: iterator end = iterator::end(buffers); Chris@16: Chris@16: // Look for a match. Chris@16: iterator iter = std::find(start_pos, end, delim_); Chris@16: if (iter != end) Chris@16: { Chris@16: // Found a match. We're done. Chris@16: search_position_ = iter - begin + 1; Chris@16: bytes_to_read = 0; Chris@16: } Chris@16: Chris@16: // No match yet. Check if buffer is full. Chris@16: else if (streambuf_.size() == streambuf_.max_size()) Chris@16: { Chris@16: search_position_ = not_found; Chris@16: bytes_to_read = 0; Chris@16: } Chris@16: Chris@16: // Need to read some more data. Chris@16: else Chris@16: { Chris@16: // Next search can start with the new data. Chris@16: search_position_ = end - begin; Chris@16: bytes_to_read = read_size_helper(streambuf_, 65536); Chris@16: } Chris@16: } Chris@16: Chris@16: // Check if we're done. Chris@16: if (!start && bytes_to_read == 0) Chris@16: break; Chris@16: Chris@16: // Start a new asynchronous read operation to obtain more data. Chris@16: stream_.async_read_some(streambuf_.prepare(bytes_to_read), Chris@16: BOOST_ASIO_MOVE_CAST(read_until_delim_op)(*this)); Chris@16: return; default: Chris@16: streambuf_.commit(bytes_transferred); Chris@16: if (ec || bytes_transferred == 0) Chris@16: break; Chris@16: } Chris@16: Chris@16: const boost::system::error_code result_ec = Chris@16: (search_position_ == not_found) Chris@16: ? error::not_found : ec; Chris@16: Chris@16: const std::size_t result_n = Chris@16: (ec || search_position_ == not_found) Chris@16: ? 0 : search_position_; Chris@16: Chris@16: handler_(result_ec, result_n); Chris@16: } Chris@16: } Chris@16: Chris@16: //private: Chris@16: AsyncReadStream& stream_; Chris@16: boost::asio::basic_streambuf& streambuf_; Chris@16: char delim_; Chris@16: int start_; Chris@16: std::size_t search_position_; Chris@16: ReadHandler handler_; Chris@16: }; Chris@16: Chris@16: template Chris@16: inline void* asio_handler_allocate(std::size_t size, Chris@16: read_until_delim_op* this_handler) Chris@16: { Chris@16: return boost_asio_handler_alloc_helpers::allocate( Chris@16: size, this_handler->handler_); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void asio_handler_deallocate(void* pointer, std::size_t size, Chris@16: read_until_delim_op* this_handler) Chris@16: { Chris@16: boost_asio_handler_alloc_helpers::deallocate( Chris@16: pointer, size, this_handler->handler_); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool asio_handler_is_continuation( Chris@16: read_until_delim_op* this_handler) Chris@16: { Chris@16: return this_handler->start_ == 0 ? true Chris@16: : boost_asio_handler_cont_helpers::is_continuation( Chris@16: this_handler->handler_); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void asio_handler_invoke(Function& function, Chris@16: read_until_delim_op* this_handler) Chris@16: { Chris@16: boost_asio_handler_invoke_helpers::invoke( Chris@16: function, this_handler->handler_); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void asio_handler_invoke(const Function& function, Chris@16: read_until_delim_op* this_handler) Chris@16: { Chris@16: boost_asio_handler_invoke_helpers::invoke( Chris@16: function, this_handler->handler_); Chris@16: } Chris@16: } // namespace detail Chris@16: Chris@16: template Chris@16: BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, Chris@16: void (boost::system::error_code, std::size_t)) Chris@16: async_read_until(AsyncReadStream& s, Chris@16: boost::asio::basic_streambuf& b, char delim, Chris@16: BOOST_ASIO_MOVE_ARG(ReadHandler) handler) Chris@16: { Chris@16: // If you get an error on the following line it means that your handler does Chris@16: // not meet the documented type requirements for a ReadHandler. Chris@16: BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; Chris@16: Chris@16: detail::async_result_init< Chris@16: ReadHandler, void (boost::system::error_code, std::size_t)> init( Chris@16: BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); Chris@16: Chris@16: detail::read_until_delim_op( Chris@16: s, b, delim, init.handler)( Chris@16: boost::system::error_code(), 0, 1); Chris@16: Chris@16: return init.result.get(); Chris@16: } Chris@16: Chris@16: namespace detail Chris@16: { Chris@16: template Chris@16: class read_until_delim_string_op Chris@16: { Chris@16: public: Chris@16: read_until_delim_string_op(AsyncReadStream& stream, Chris@16: boost::asio::basic_streambuf& streambuf, Chris@16: const std::string& delim, ReadHandler& handler) Chris@16: : stream_(stream), Chris@16: streambuf_(streambuf), Chris@16: delim_(delim), Chris@16: start_(0), Chris@16: search_position_(0), Chris@16: handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) Chris@16: { Chris@16: } Chris@16: Chris@16: #if defined(BOOST_ASIO_HAS_MOVE) Chris@16: read_until_delim_string_op(const read_until_delim_string_op& other) Chris@16: : stream_(other.stream_), Chris@16: streambuf_(other.streambuf_), Chris@16: delim_(other.delim_), Chris@16: start_(other.start_), Chris@16: search_position_(other.search_position_), Chris@16: handler_(other.handler_) Chris@16: { Chris@16: } Chris@16: Chris@16: read_until_delim_string_op(read_until_delim_string_op&& other) Chris@16: : stream_(other.stream_), Chris@16: streambuf_(other.streambuf_), Chris@16: delim_(BOOST_ASIO_MOVE_CAST(std::string)(other.delim_)), Chris@16: start_(other.start_), Chris@16: search_position_(other.search_position_), Chris@16: handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) Chris@16: { Chris@16: } Chris@16: #endif // defined(BOOST_ASIO_HAS_MOVE) Chris@16: Chris@16: void operator()(const boost::system::error_code& ec, Chris@16: std::size_t bytes_transferred, int start = 0) Chris@16: { Chris@16: const std::size_t not_found = (std::numeric_limits::max)(); Chris@16: std::size_t bytes_to_read; Chris@16: switch (start_ = start) Chris@16: { Chris@16: case 1: Chris@16: for (;;) Chris@16: { Chris@16: { Chris@16: // Determine the range of the data to be searched. Chris@16: typedef typename boost::asio::basic_streambuf< Chris@16: Allocator>::const_buffers_type const_buffers_type; Chris@16: typedef boost::asio::buffers_iterator iterator; Chris@16: const_buffers_type buffers = streambuf_.data(); Chris@16: iterator begin = iterator::begin(buffers); Chris@16: iterator start_pos = begin + search_position_; Chris@16: iterator end = iterator::end(buffers); Chris@16: Chris@16: // Look for a match. Chris@16: std::pair result = detail::partial_search( Chris@16: start_pos, end, delim_.begin(), delim_.end()); Chris@16: if (result.first != end && result.second) Chris@16: { Chris@16: // Full match. We're done. Chris@16: search_position_ = result.first - begin + delim_.length(); Chris@16: bytes_to_read = 0; Chris@16: } Chris@16: Chris@16: // No match yet. Check if buffer is full. Chris@16: else if (streambuf_.size() == streambuf_.max_size()) Chris@16: { Chris@16: search_position_ = not_found; Chris@16: bytes_to_read = 0; Chris@16: } Chris@16: Chris@16: // Need to read some more data. Chris@16: else Chris@16: { Chris@16: if (result.first != end) Chris@16: { Chris@16: // Partial match. Next search needs to start from beginning of Chris@16: // match. Chris@16: search_position_ = result.first - begin; Chris@16: } Chris@16: else Chris@16: { Chris@16: // Next search can start with the new data. Chris@16: search_position_ = end - begin; Chris@16: } Chris@16: Chris@16: bytes_to_read = read_size_helper(streambuf_, 65536); Chris@16: } Chris@16: } Chris@16: Chris@16: // Check if we're done. Chris@16: if (!start && bytes_to_read == 0) Chris@16: break; Chris@16: Chris@16: // Start a new asynchronous read operation to obtain more data. Chris@16: stream_.async_read_some(streambuf_.prepare(bytes_to_read), Chris@16: BOOST_ASIO_MOVE_CAST(read_until_delim_string_op)(*this)); Chris@16: return; default: Chris@16: streambuf_.commit(bytes_transferred); Chris@16: if (ec || bytes_transferred == 0) Chris@16: break; Chris@16: } Chris@16: Chris@16: const boost::system::error_code result_ec = Chris@16: (search_position_ == not_found) Chris@16: ? error::not_found : ec; Chris@16: Chris@16: const std::size_t result_n = Chris@16: (ec || search_position_ == not_found) Chris@16: ? 0 : search_position_; Chris@16: Chris@16: handler_(result_ec, result_n); Chris@16: } Chris@16: } Chris@16: Chris@16: //private: Chris@16: AsyncReadStream& stream_; Chris@16: boost::asio::basic_streambuf& streambuf_; Chris@16: std::string delim_; Chris@16: int start_; Chris@16: std::size_t search_position_; Chris@16: ReadHandler handler_; Chris@16: }; Chris@16: Chris@16: template Chris@16: inline void* asio_handler_allocate(std::size_t size, Chris@16: read_until_delim_string_op* this_handler) Chris@16: { Chris@16: return boost_asio_handler_alloc_helpers::allocate( Chris@16: size, this_handler->handler_); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void asio_handler_deallocate(void* pointer, std::size_t size, Chris@16: read_until_delim_string_op* this_handler) Chris@16: { Chris@16: boost_asio_handler_alloc_helpers::deallocate( Chris@16: pointer, size, this_handler->handler_); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool asio_handler_is_continuation( Chris@16: read_until_delim_string_op* this_handler) Chris@16: { Chris@16: return this_handler->start_ == 0 ? true Chris@16: : boost_asio_handler_cont_helpers::is_continuation( Chris@16: this_handler->handler_); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void asio_handler_invoke(Function& function, Chris@16: read_until_delim_string_op* this_handler) Chris@16: { Chris@16: boost_asio_handler_invoke_helpers::invoke( Chris@16: function, this_handler->handler_); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void asio_handler_invoke(const Function& function, Chris@16: read_until_delim_string_op* this_handler) Chris@16: { Chris@16: boost_asio_handler_invoke_helpers::invoke( Chris@16: function, this_handler->handler_); Chris@16: } Chris@16: } // namespace detail Chris@16: Chris@16: template Chris@16: BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, Chris@16: void (boost::system::error_code, std::size_t)) Chris@16: async_read_until(AsyncReadStream& s, Chris@16: boost::asio::basic_streambuf& b, const std::string& delim, Chris@16: BOOST_ASIO_MOVE_ARG(ReadHandler) handler) Chris@16: { Chris@16: // If you get an error on the following line it means that your handler does Chris@16: // not meet the documented type requirements for a ReadHandler. Chris@16: BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; Chris@16: Chris@16: detail::async_result_init< Chris@16: ReadHandler, void (boost::system::error_code, std::size_t)> init( Chris@16: BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); Chris@16: Chris@16: detail::read_until_delim_string_op( Chris@16: s, b, delim, init.handler)( Chris@16: boost::system::error_code(), 0, 1); Chris@16: Chris@16: return init.result.get(); Chris@16: } Chris@16: Chris@16: #if defined(BOOST_ASIO_HAS_BOOST_REGEX) Chris@16: Chris@16: namespace detail Chris@16: { Chris@16: template Chris@16: class read_until_expr_op Chris@16: { Chris@16: public: Chris@16: read_until_expr_op(AsyncReadStream& stream, Chris@16: boost::asio::basic_streambuf& streambuf, Chris@16: const boost::regex& expr, ReadHandler& handler) Chris@16: : stream_(stream), Chris@16: streambuf_(streambuf), Chris@16: expr_(expr), Chris@16: start_(0), Chris@16: search_position_(0), Chris@16: handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) Chris@16: { Chris@16: } Chris@16: Chris@16: #if defined(BOOST_ASIO_HAS_MOVE) Chris@16: read_until_expr_op(const read_until_expr_op& other) Chris@16: : stream_(other.stream_), Chris@16: streambuf_(other.streambuf_), Chris@16: expr_(other.expr_), Chris@16: start_(other.start_), Chris@16: search_position_(other.search_position_), Chris@16: handler_(other.handler_) Chris@16: { Chris@16: } Chris@16: Chris@16: read_until_expr_op(read_until_expr_op&& other) Chris@16: : stream_(other.stream_), Chris@16: streambuf_(other.streambuf_), Chris@16: expr_(other.expr_), Chris@16: start_(other.start_), Chris@16: search_position_(other.search_position_), Chris@16: handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) Chris@16: { Chris@16: } Chris@16: #endif // defined(BOOST_ASIO_HAS_MOVE) Chris@16: Chris@16: void operator()(const boost::system::error_code& ec, Chris@16: std::size_t bytes_transferred, int start = 0) Chris@16: { Chris@16: const std::size_t not_found = (std::numeric_limits::max)(); Chris@16: std::size_t bytes_to_read; Chris@16: switch (start_ = start) Chris@16: { Chris@16: case 1: Chris@16: for (;;) Chris@16: { Chris@16: { Chris@16: // Determine the range of the data to be searched. Chris@16: typedef typename boost::asio::basic_streambuf< Chris@16: Allocator>::const_buffers_type const_buffers_type; Chris@16: typedef boost::asio::buffers_iterator iterator; Chris@16: const_buffers_type buffers = streambuf_.data(); Chris@16: iterator begin = iterator::begin(buffers); Chris@16: iterator start_pos = begin + search_position_; Chris@16: iterator end = iterator::end(buffers); Chris@16: Chris@16: // Look for a match. Chris@16: boost::match_results >::allocator_type> Chris@16: match_results; Chris@16: bool match = regex_search(start_pos, end, match_results, expr_, Chris@16: boost::match_default | boost::match_partial); Chris@16: if (match && match_results[0].matched) Chris@16: { Chris@16: // Full match. We're done. Chris@16: search_position_ = match_results[0].second - begin; Chris@16: bytes_to_read = 0; Chris@16: } Chris@16: Chris@16: // No match yet. Check if buffer is full. Chris@16: else if (streambuf_.size() == streambuf_.max_size()) Chris@16: { Chris@16: search_position_ = not_found; Chris@16: bytes_to_read = 0; Chris@16: } Chris@16: Chris@16: // Need to read some more data. Chris@16: else Chris@16: { Chris@16: if (match) Chris@16: { Chris@16: // Partial match. Next search needs to start from beginning of Chris@16: // match. Chris@16: search_position_ = match_results[0].first - begin; Chris@16: } Chris@16: else Chris@16: { Chris@16: // Next search can start with the new data. Chris@16: search_position_ = end - begin; Chris@16: } Chris@16: Chris@16: bytes_to_read = read_size_helper(streambuf_, 65536); Chris@16: } Chris@16: } Chris@16: Chris@16: // Check if we're done. Chris@16: if (!start && bytes_to_read == 0) Chris@16: break; Chris@16: Chris@16: // Start a new asynchronous read operation to obtain more data. Chris@16: stream_.async_read_some(streambuf_.prepare(bytes_to_read), Chris@16: BOOST_ASIO_MOVE_CAST(read_until_expr_op)(*this)); Chris@16: return; default: Chris@16: streambuf_.commit(bytes_transferred); Chris@16: if (ec || bytes_transferred == 0) Chris@16: break; Chris@16: } Chris@16: Chris@16: const boost::system::error_code result_ec = Chris@16: (search_position_ == not_found) Chris@16: ? error::not_found : ec; Chris@16: Chris@16: const std::size_t result_n = Chris@16: (ec || search_position_ == not_found) Chris@16: ? 0 : search_position_; Chris@16: Chris@16: handler_(result_ec, result_n); Chris@16: } Chris@16: } Chris@16: Chris@16: //private: Chris@16: AsyncReadStream& stream_; Chris@16: boost::asio::basic_streambuf& streambuf_; Chris@16: RegEx expr_; Chris@16: int start_; Chris@16: std::size_t search_position_; Chris@16: ReadHandler handler_; Chris@16: }; Chris@16: Chris@16: template Chris@16: inline void* asio_handler_allocate(std::size_t size, Chris@16: read_until_expr_op* this_handler) Chris@16: { Chris@16: return boost_asio_handler_alloc_helpers::allocate( Chris@16: size, this_handler->handler_); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void asio_handler_deallocate(void* pointer, std::size_t size, Chris@16: read_until_expr_op* this_handler) Chris@16: { Chris@16: boost_asio_handler_alloc_helpers::deallocate( Chris@16: pointer, size, this_handler->handler_); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool asio_handler_is_continuation( Chris@16: read_until_expr_op* this_handler) Chris@16: { Chris@16: return this_handler->start_ == 0 ? true Chris@16: : boost_asio_handler_cont_helpers::is_continuation( Chris@16: this_handler->handler_); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void asio_handler_invoke(Function& function, Chris@16: read_until_expr_op* this_handler) Chris@16: { Chris@16: boost_asio_handler_invoke_helpers::invoke( Chris@16: function, this_handler->handler_); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void asio_handler_invoke(const Function& function, Chris@16: read_until_expr_op* this_handler) Chris@16: { Chris@16: boost_asio_handler_invoke_helpers::invoke( Chris@16: function, this_handler->handler_); Chris@16: } Chris@16: } // namespace detail Chris@16: Chris@16: template Chris@16: BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, Chris@16: void (boost::system::error_code, std::size_t)) Chris@16: async_read_until(AsyncReadStream& s, Chris@16: boost::asio::basic_streambuf& b, const boost::regex& expr, Chris@16: BOOST_ASIO_MOVE_ARG(ReadHandler) handler) Chris@16: { Chris@16: // If you get an error on the following line it means that your handler does Chris@16: // not meet the documented type requirements for a ReadHandler. Chris@16: BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; Chris@16: Chris@16: detail::async_result_init< Chris@16: ReadHandler, void (boost::system::error_code, std::size_t)> init( Chris@16: BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); Chris@16: Chris@16: detail::read_until_expr_op( Chris@16: s, b, expr, init.handler)( Chris@16: boost::system::error_code(), 0, 1); Chris@16: Chris@16: return init.result.get(); Chris@16: } Chris@16: Chris@16: #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) Chris@16: Chris@16: namespace detail Chris@16: { Chris@16: template Chris@16: class read_until_match_op Chris@16: { Chris@16: public: Chris@16: read_until_match_op(AsyncReadStream& stream, Chris@16: boost::asio::basic_streambuf& streambuf, Chris@16: MatchCondition match_condition, ReadHandler& handler) Chris@16: : stream_(stream), Chris@16: streambuf_(streambuf), Chris@16: match_condition_(match_condition), Chris@16: start_(0), Chris@16: search_position_(0), Chris@16: handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) Chris@16: { Chris@16: } Chris@16: Chris@16: #if defined(BOOST_ASIO_HAS_MOVE) Chris@16: read_until_match_op(const read_until_match_op& other) Chris@16: : stream_(other.stream_), Chris@16: streambuf_(other.streambuf_), Chris@16: match_condition_(other.match_condition_), Chris@16: start_(other.start_), Chris@16: search_position_(other.search_position_), Chris@16: handler_(other.handler_) Chris@16: { Chris@16: } Chris@16: Chris@16: read_until_match_op(read_until_match_op&& other) Chris@16: : stream_(other.stream_), Chris@16: streambuf_(other.streambuf_), Chris@16: match_condition_(other.match_condition_), Chris@16: start_(other.start_), Chris@16: search_position_(other.search_position_), Chris@16: handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) Chris@16: { Chris@16: } Chris@16: #endif // defined(BOOST_ASIO_HAS_MOVE) Chris@16: Chris@16: void operator()(const boost::system::error_code& ec, Chris@16: std::size_t bytes_transferred, int start = 0) Chris@16: { Chris@16: const std::size_t not_found = (std::numeric_limits::max)(); Chris@16: std::size_t bytes_to_read; Chris@16: switch (start_ = start) Chris@16: { Chris@16: case 1: Chris@16: for (;;) Chris@16: { Chris@16: { Chris@16: // Determine the range of the data to be searched. Chris@16: typedef typename boost::asio::basic_streambuf< Chris@16: Allocator>::const_buffers_type const_buffers_type; Chris@16: typedef boost::asio::buffers_iterator iterator; Chris@16: const_buffers_type buffers = streambuf_.data(); Chris@16: iterator begin = iterator::begin(buffers); Chris@16: iterator start_pos = begin + search_position_; Chris@16: iterator end = iterator::end(buffers); Chris@16: Chris@16: // Look for a match. Chris@16: std::pair result = match_condition_(start_pos, end); Chris@16: if (result.second) Chris@16: { Chris@16: // Full match. We're done. Chris@16: search_position_ = result.first - begin; Chris@16: bytes_to_read = 0; Chris@16: } Chris@16: Chris@16: // No match yet. Check if buffer is full. Chris@16: else if (streambuf_.size() == streambuf_.max_size()) Chris@16: { Chris@16: search_position_ = not_found; Chris@16: bytes_to_read = 0; Chris@16: } Chris@16: Chris@16: // Need to read some more data. Chris@16: else Chris@16: { Chris@16: if (result.first != end) Chris@16: { Chris@16: // Partial match. Next search needs to start from beginning of Chris@16: // match. Chris@16: search_position_ = result.first - begin; Chris@16: } Chris@16: else Chris@16: { Chris@16: // Next search can start with the new data. Chris@16: search_position_ = end - begin; Chris@16: } Chris@16: Chris@16: bytes_to_read = read_size_helper(streambuf_, 65536); Chris@16: } Chris@16: } Chris@16: Chris@16: // Check if we're done. Chris@16: if (!start && bytes_to_read == 0) Chris@16: break; Chris@16: Chris@16: // Start a new asynchronous read operation to obtain more data. Chris@16: stream_.async_read_some(streambuf_.prepare(bytes_to_read), Chris@16: BOOST_ASIO_MOVE_CAST(read_until_match_op)(*this)); Chris@16: return; default: Chris@16: streambuf_.commit(bytes_transferred); Chris@16: if (ec || bytes_transferred == 0) Chris@16: break; Chris@16: } Chris@16: Chris@16: const boost::system::error_code result_ec = Chris@16: (search_position_ == not_found) Chris@16: ? error::not_found : ec; Chris@16: Chris@16: const std::size_t result_n = Chris@16: (ec || search_position_ == not_found) Chris@16: ? 0 : search_position_; Chris@16: Chris@16: handler_(result_ec, result_n); Chris@16: } Chris@16: } Chris@16: Chris@16: //private: Chris@16: AsyncReadStream& stream_; Chris@16: boost::asio::basic_streambuf& streambuf_; Chris@16: MatchCondition match_condition_; Chris@16: int start_; Chris@16: std::size_t search_position_; Chris@16: ReadHandler handler_; Chris@16: }; Chris@16: Chris@16: template Chris@16: inline void* asio_handler_allocate(std::size_t size, Chris@16: read_until_match_op* this_handler) Chris@16: { Chris@16: return boost_asio_handler_alloc_helpers::allocate( Chris@16: size, this_handler->handler_); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void asio_handler_deallocate(void* pointer, std::size_t size, Chris@16: read_until_match_op* this_handler) Chris@16: { Chris@16: boost_asio_handler_alloc_helpers::deallocate( Chris@16: pointer, size, this_handler->handler_); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool asio_handler_is_continuation( Chris@16: read_until_match_op* this_handler) Chris@16: { Chris@16: return this_handler->start_ == 0 ? true Chris@16: : boost_asio_handler_cont_helpers::is_continuation( Chris@16: this_handler->handler_); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void asio_handler_invoke(Function& function, Chris@16: read_until_match_op* this_handler) Chris@16: { Chris@16: boost_asio_handler_invoke_helpers::invoke( Chris@16: function, this_handler->handler_); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void asio_handler_invoke(const Function& function, Chris@16: read_until_match_op* this_handler) Chris@16: { Chris@16: boost_asio_handler_invoke_helpers::invoke( Chris@16: function, this_handler->handler_); Chris@16: } Chris@16: } // namespace detail Chris@16: Chris@16: template Chris@16: BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, Chris@16: void (boost::system::error_code, std::size_t)) Chris@16: async_read_until(AsyncReadStream& s, Chris@16: boost::asio::basic_streambuf& b, Chris@16: MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, Chris@16: typename enable_if::value>::type*) Chris@16: { Chris@16: // If you get an error on the following line it means that your handler does Chris@16: // not meet the documented type requirements for a ReadHandler. Chris@16: BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; Chris@16: Chris@16: detail::async_result_init< Chris@16: ReadHandler, void (boost::system::error_code, std::size_t)> init( Chris@16: BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); Chris@16: Chris@16: detail::read_until_match_op( Chris@16: s, b, match_condition, init.handler)( Chris@16: boost::system::error_code(), 0, 1); Chris@16: Chris@16: return init.result.get(); Chris@16: } Chris@16: Chris@16: } // namespace asio Chris@16: } // namespace boost Chris@16: Chris@16: #include Chris@16: Chris@16: #endif // BOOST_ASIO_IMPL_READ_UNTIL_HPP