base_decoders.hpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. //
  2. // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic
  3. //
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. #ifndef BOOST_MQTT5_BASE_DECODERS_HPP
  8. #define BOOST_MQTT5_BASE_DECODERS_HPP
  9. #include <boost/mqtt5/property_types.hpp>
  10. #include <boost/mqtt5/detail/traits.hpp>
  11. #include <boost/endian/conversion.hpp>
  12. #include <cstdint>
  13. #include <string>
  14. #include <utility>
  15. namespace boost::mqtt5::decoders {
  16. template <typename It, typename Parser>
  17. auto type_parse(It& first, const It last, const Parser& p) {
  18. using rv_type = typename Parser::attribute_type;
  19. std::optional<rv_type> rv;
  20. rv_type value {};
  21. if (p.parse(first, last, value))
  22. rv = std::move(value);
  23. return rv;
  24. }
  25. namespace basic {
  26. template <typename Attr>
  27. struct int_parser {
  28. using attribute_type = Attr;
  29. template <typename It>
  30. bool parse(It& first, const It last, Attr& attr) const {
  31. constexpr size_t byte_size = sizeof(Attr);
  32. if (std::distance(first, last) < static_cast<ptrdiff_t>(byte_size))
  33. return false;
  34. using namespace boost::endian;
  35. attr = endian_load<Attr, sizeof(Attr), order::big>(
  36. reinterpret_cast<const uint8_t*>(static_cast<const char*>(&*first))
  37. );
  38. first += sizeof(Attr);
  39. return true;
  40. }
  41. };
  42. inline constexpr int_parser<uint8_t> byte_;
  43. inline constexpr int_parser<uint16_t> word_;
  44. inline constexpr int_parser<uint32_t> dword_;
  45. struct varint_parser {
  46. using attribute_type = int32_t;
  47. template <typename It>
  48. bool parse(It& first, const It last, int32_t& attr) const {
  49. auto iter = first;
  50. if (iter == last)
  51. return false;
  52. int32_t result = 0; unsigned bit_shift = 0;
  53. for (; iter != last && bit_shift < sizeof(int32_t) * 7; ++iter) {
  54. auto val = *iter;
  55. if (val & 0b1000'0000u) {
  56. result |= (val & 0b0111'1111u) << bit_shift;
  57. bit_shift += 7;
  58. }
  59. else {
  60. result |= (static_cast<int32_t>(val) << bit_shift);
  61. bit_shift = 0;
  62. break;
  63. }
  64. }
  65. if (bit_shift)
  66. return false;
  67. attr = result;
  68. first = ++iter;
  69. return true;
  70. }
  71. };
  72. inline constexpr varint_parser varint_;
  73. struct len_prefix_parser {
  74. using attribute_type = std::string;
  75. template <typename It>
  76. bool parse(It& first, const It last, std::string& attr) const {
  77. auto iter = first;
  78. typename decltype(word_)::attribute_type len;
  79. if (word_.parse(iter, last, len)) {
  80. if (std::distance(iter, last) < len)
  81. return false;
  82. }
  83. else
  84. return false;
  85. attr = std::string(iter, iter + len);
  86. first = iter + len;
  87. return true;
  88. }
  89. };
  90. inline constexpr len_prefix_parser utf8_ {};
  91. inline constexpr len_prefix_parser binary_ {};
  92. template <typename Subject>
  93. struct conditional_parser {
  94. using subject_attr_type = typename Subject::attribute_type;
  95. using attribute_type = std::optional<subject_attr_type>;
  96. Subject p;
  97. bool condition;
  98. template <typename It>
  99. bool parse(It& first, const It last, attribute_type& attr) const {
  100. if (!condition)
  101. return true;
  102. auto iter = first;
  103. subject_attr_type sattr {};
  104. if (!p.parse(iter, last, sattr))
  105. return false;
  106. attr.emplace(std::move(sattr));
  107. first = iter;
  108. return true;
  109. }
  110. };
  111. struct conditional_gen {
  112. bool _condition;
  113. template <typename Subject>
  114. conditional_parser<Subject> operator[](const Subject& p) const {
  115. return { p, _condition };
  116. }
  117. };
  118. constexpr conditional_gen if_(bool condition) {
  119. return { condition };
  120. }
  121. struct verbatim_parser {
  122. using attribute_type = std::string;
  123. template <typename It>
  124. bool parse(It& first, const It last, std::string& attr) const {
  125. attr = std::string { first, last };
  126. first = last;
  127. return true;
  128. }
  129. };
  130. inline constexpr auto verbatim_ = verbatim_parser{};
  131. template <typename... Ps>
  132. struct seq_parser {
  133. using attribute_type = std::tuple<typename Ps::attribute_type...>;
  134. std::tuple<Ps...> parsers;
  135. template <typename It>
  136. bool parse(It& first, const It last, attribute_type& attr) const {
  137. return parse_impl(
  138. first, last, attr, std::make_index_sequence<sizeof...(Ps)>{}
  139. );
  140. }
  141. private:
  142. template <typename It, size_t... Is>
  143. bool parse_impl(
  144. It& first, const It last, attribute_type& attr,
  145. std::index_sequence<Is...>
  146. ) const {
  147. auto iter = first;
  148. bool rv = (
  149. std::get<Is>(parsers).parse(iter, last, std::get<Is>(attr))
  150. && ...
  151. );
  152. if (rv)
  153. first = iter;
  154. return rv;
  155. }
  156. };
  157. template <typename... Ps, typename P2>
  158. constexpr seq_parser<Ps..., P2> operator>>(
  159. const seq_parser<Ps...>& p1, const P2& p2
  160. ) {
  161. return { std::tuple_cat(p1.parsers, std::make_tuple(p2)) };
  162. }
  163. template <typename P1, typename P2>
  164. constexpr seq_parser<P1, P2> operator>>(const P1& p1, const P2& p2) {
  165. return { std::make_tuple(p1, p2) };
  166. }
  167. template <typename Attr>
  168. struct attr_parser {
  169. using attribute_type = Attr;
  170. Attr attr;
  171. template <typename It>
  172. bool parse(It&, const It, Attr& attr) const {
  173. attr = this->attr;
  174. return true;
  175. }
  176. };
  177. template <typename Attr>
  178. constexpr attr_parser<Attr> attr(const Attr& val) {
  179. return { val };
  180. }
  181. template <typename Subject>
  182. struct plus_parser {
  183. using subject_attr_type = typename Subject::attribute_type;
  184. using attribute_type = std::vector<subject_attr_type>;
  185. Subject p;
  186. template <typename It, typename Attr>
  187. bool parse(It& first, const It last, Attr& attr) const {
  188. bool success = false;
  189. while (first < last) {
  190. subject_attr_type sattr {};
  191. auto iter = first;
  192. if (!p.parse(iter, last, sattr)) break;
  193. success = true;
  194. first = iter;
  195. attr.push_back(std::move(sattr));
  196. }
  197. return success;
  198. }
  199. };
  200. template <typename P>
  201. constexpr plus_parser<P> operator+(const P& p) {
  202. return { p };
  203. }
  204. } // end namespace basic
  205. namespace prop {
  206. namespace detail {
  207. template <typename It, typename Prop>
  208. bool parse_to_prop(It& iter, const It last, Prop& prop) {
  209. using namespace boost::mqtt5::detail;
  210. using prop_type = std::remove_reference_t<decltype(prop)>;
  211. bool rv = false;
  212. if constexpr (std::is_same_v<prop_type, uint8_t>)
  213. rv = basic::byte_.parse(iter, last, prop);
  214. else if constexpr (std::is_same_v<prop_type, uint16_t>)
  215. rv = basic::word_.parse(iter, last, prop);
  216. else if constexpr (std::is_same_v<prop_type, int32_t>)
  217. rv = basic::varint_.parse(iter, last, prop);
  218. else if constexpr (std::is_same_v<prop_type, uint32_t>)
  219. rv = basic::dword_.parse(iter, last, prop);
  220. else if constexpr (std::is_same_v<prop_type, std::string>)
  221. rv = basic::utf8_.parse(iter, last, prop);
  222. else if constexpr (is_optional<prop_type>) {
  223. typename prop_type::value_type val;
  224. rv = parse_to_prop(iter, last, val);
  225. if (rv) prop.emplace(std::move(val));
  226. }
  227. else if constexpr (is_pair<prop_type>) {
  228. rv = parse_to_prop(iter, last, prop.first);
  229. rv = parse_to_prop(iter, last, prop.second);
  230. }
  231. else if constexpr (is_vector<prop_type> || is_small_vector<prop_type>) {
  232. typename std::remove_reference_t<prop_type>::value_type value;
  233. rv = parse_to_prop(iter, last, value);
  234. if (rv) prop.push_back(std::move(value));
  235. }
  236. return rv;
  237. }
  238. } // end namespace detail
  239. template <typename Props>
  240. struct prop_parser {
  241. using attribute_type = Props;
  242. template <typename It>
  243. bool parse(It& first, const It last, Props& attr) const {
  244. auto iter = first;
  245. if (iter == last)
  246. return true;
  247. int32_t props_length;
  248. if (!basic::varint_.parse(iter, last, props_length))
  249. return false;
  250. const auto scoped_last = iter + props_length;
  251. // attr = Props{};
  252. while (iter < scoped_last) {
  253. uint8_t prop_id = *iter++;
  254. bool rv = true;
  255. It saved = iter;
  256. attr.apply_on(
  257. prop_id,
  258. [&rv, &iter, scoped_last](auto& prop) {
  259. rv = detail::parse_to_prop(iter, scoped_last, prop);
  260. }
  261. );
  262. // either rv = false or property with prop_id was not found
  263. if (!rv || iter == saved)
  264. return false;
  265. }
  266. first = iter;
  267. return true;
  268. }
  269. };
  270. template <typename Props>
  271. constexpr auto props_ = prop_parser<Props> {};
  272. } // end namespace prop
  273. } // end namespace boost::mqtt5::decoders
  274. #endif // !BOOST_MQTT5_BASE_DECODERS_HPP