// // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_MQTT5_BASE_DECODERS_HPP #define BOOST_MQTT5_BASE_DECODERS_HPP #include #include #include #include #include #include namespace boost::mqtt5::decoders { template auto type_parse(It& first, const It last, const Parser& p) { using rv_type = typename Parser::attribute_type; std::optional rv; rv_type value {}; if (p.parse(first, last, value)) rv = std::move(value); return rv; } namespace basic { template struct int_parser { using attribute_type = Attr; template bool parse(It& first, const It last, Attr& attr) const { constexpr size_t byte_size = sizeof(Attr); if (std::distance(first, last) < static_cast(byte_size)) return false; using namespace boost::endian; attr = endian_load( reinterpret_cast(static_cast(&*first)) ); first += sizeof(Attr); return true; } }; inline constexpr int_parser byte_; inline constexpr int_parser word_; inline constexpr int_parser dword_; struct varint_parser { using attribute_type = int32_t; template bool parse(It& first, const It last, int32_t& attr) const { auto iter = first; if (iter == last) return false; int32_t result = 0; unsigned bit_shift = 0; for (; iter != last && bit_shift < sizeof(int32_t) * 7; ++iter) { auto val = *iter; if (val & 0b1000'0000u) { result |= (val & 0b0111'1111u) << bit_shift; bit_shift += 7; } else { result |= (static_cast(val) << bit_shift); bit_shift = 0; break; } } if (bit_shift) return false; attr = result; first = ++iter; return true; } }; inline constexpr varint_parser varint_; struct len_prefix_parser { using attribute_type = std::string; template bool parse(It& first, const It last, std::string& attr) const { auto iter = first; typename decltype(word_)::attribute_type len; if (word_.parse(iter, last, len)) { if (std::distance(iter, last) < len) return false; } else return false; attr = std::string(iter, iter + len); first = iter + len; return true; } }; inline constexpr len_prefix_parser utf8_ {}; inline constexpr len_prefix_parser binary_ {}; template struct conditional_parser { using subject_attr_type = typename Subject::attribute_type; using attribute_type = std::optional; Subject p; bool condition; template bool parse(It& first, const It last, attribute_type& attr) const { if (!condition) return true; auto iter = first; subject_attr_type sattr {}; if (!p.parse(iter, last, sattr)) return false; attr.emplace(std::move(sattr)); first = iter; return true; } }; struct conditional_gen { bool _condition; template conditional_parser operator[](const Subject& p) const { return { p, _condition }; } }; constexpr conditional_gen if_(bool condition) { return { condition }; } struct verbatim_parser { using attribute_type = std::string; template bool parse(It& first, const It last, std::string& attr) const { attr = std::string { first, last }; first = last; return true; } }; inline constexpr auto verbatim_ = verbatim_parser{}; template struct seq_parser { using attribute_type = std::tuple; std::tuple parsers; template bool parse(It& first, const It last, attribute_type& attr) const { return parse_impl( first, last, attr, std::make_index_sequence{} ); } private: template bool parse_impl( It& first, const It last, attribute_type& attr, std::index_sequence ) const { auto iter = first; bool rv = ( std::get(parsers).parse(iter, last, std::get(attr)) && ... ); if (rv) first = iter; return rv; } }; template constexpr seq_parser operator>>( const seq_parser& p1, const P2& p2 ) { return { std::tuple_cat(p1.parsers, std::make_tuple(p2)) }; } template constexpr seq_parser operator>>(const P1& p1, const P2& p2) { return { std::make_tuple(p1, p2) }; } template struct attr_parser { using attribute_type = Attr; Attr attr; template bool parse(It&, const It, Attr& attr) const { attr = this->attr; return true; } }; template constexpr attr_parser attr(const Attr& val) { return { val }; } template struct plus_parser { using subject_attr_type = typename Subject::attribute_type; using attribute_type = std::vector; Subject p; template bool parse(It& first, const It last, Attr& attr) const { bool success = false; while (first < last) { subject_attr_type sattr {}; auto iter = first; if (!p.parse(iter, last, sattr)) break; success = true; first = iter; attr.push_back(std::move(sattr)); } return success; } }; template constexpr plus_parser

operator+(const P& p) { return { p }; } } // end namespace basic namespace prop { namespace detail { template bool parse_to_prop(It& iter, const It last, Prop& prop) { using namespace boost::mqtt5::detail; using prop_type = std::remove_reference_t; bool rv = false; if constexpr (std::is_same_v) rv = basic::byte_.parse(iter, last, prop); else if constexpr (std::is_same_v) rv = basic::word_.parse(iter, last, prop); else if constexpr (std::is_same_v) rv = basic::varint_.parse(iter, last, prop); else if constexpr (std::is_same_v) rv = basic::dword_.parse(iter, last, prop); else if constexpr (std::is_same_v) rv = basic::utf8_.parse(iter, last, prop); else if constexpr (is_optional) { typename prop_type::value_type val; rv = parse_to_prop(iter, last, val); if (rv) prop.emplace(std::move(val)); } else if constexpr (is_pair) { rv = parse_to_prop(iter, last, prop.first); rv = parse_to_prop(iter, last, prop.second); } else if constexpr (is_vector || is_small_vector) { typename std::remove_reference_t::value_type value; rv = parse_to_prop(iter, last, value); if (rv) prop.push_back(std::move(value)); } return rv; } } // end namespace detail template struct prop_parser { using attribute_type = Props; template bool parse(It& first, const It last, Props& attr) const { auto iter = first; if (iter == last) return true; int32_t props_length; if (!basic::varint_.parse(iter, last, props_length)) return false; const auto scoped_last = iter + props_length; // attr = Props{}; while (iter < scoped_last) { uint8_t prop_id = *iter++; bool rv = true; It saved = iter; attr.apply_on( prop_id, [&rv, &iter, scoped_last](auto& prop) { rv = detail::parse_to_prop(iter, scoped_last, prop); } ); // either rv = false or property with prop_id was not found if (!rv || iter == saved) return false; } first = iter; return true; } }; template constexpr auto props_ = prop_parser {}; } // end namespace prop } // end namespace boost::mqtt5::decoders #endif // !BOOST_MQTT5_BASE_DECODERS_HPP