File indexing completed on 2025-09-18 08:51:36
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_MQTT5_BASE_DECODERS_HPP
0009 #define BOOST_MQTT5_BASE_DECODERS_HPP
0010
0011 #include <boost/mqtt5/property_types.hpp>
0012
0013 #include <boost/mqtt5/detail/traits.hpp>
0014
0015 #include <boost/fusion/adapted/std_tuple.hpp>
0016 #include <boost/fusion/container/deque.hpp>
0017 #include <boost/optional/optional.hpp>
0018 #include <boost/spirit/home/x3.hpp>
0019 #include <boost/spirit/home/x3/binary/binary.hpp>
0020
0021 #include <cstdint>
0022 #include <string>
0023 #include <utility>
0024
0025 namespace boost::mqtt5::decoders {
0026
0027 namespace x3 = boost::spirit::x3;
0028
0029 template <typename T>
0030 struct convert { using type = T; };
0031
0032 template <typename ...Args>
0033 struct convert<boost::fusion::deque<Args...>> {
0034 using type = std::tuple<typename convert<Args>::type...>;
0035 };
0036
0037 template <typename T>
0038 struct convert<boost::optional<T>> {
0039 using type = std::optional<T>;
0040 };
0041
0042 template <typename T>
0043 struct convert<std::vector<T>> {
0044 using type = std::vector<typename convert<T>::type>;
0045 };
0046
0047 template <typename T, typename Parser>
0048 constexpr auto as(Parser&& p) {
0049 return x3::rule<struct _, T>{} = std::forward<Parser>(p);
0050 }
0051
0052
0053 template <typename It, typename Parser>
0054 auto type_parse(It& first, const It last, const Parser& p) {
0055 using ctx_type = decltype(x3::make_context<struct _>(std::declval<Parser&>()));
0056 using attr_type = typename x3::traits::attribute_of<Parser, ctx_type>::type;
0057
0058 using rv_type = typename convert<attr_type>::type;
0059
0060 std::optional<rv_type> rv;
0061 rv_type value {};
0062 if (x3::phrase_parse(first, last, as<rv_type>(p), x3::eps(false), value))
0063 rv = std::move(value);
0064 return rv;
0065 }
0066
0067
0068 template <typename AttributeType, typename It, typename Parser>
0069 auto type_parse(It& first, const It last, const Parser& p) {
0070 std::optional<AttributeType> rv;
0071 AttributeType value {};
0072 if (x3::phrase_parse(first, last, as<AttributeType>(p), x3::eps(false), value))
0073 rv = std::move(value);
0074 return rv;
0075 }
0076
0077 namespace basic {
0078
0079 template <typename T>
0080 constexpr auto to(T& arg) {
0081 return [&](auto& ctx) {
0082 using ctx_type = decltype(ctx);
0083 using attr_type = decltype(x3::_attr(std::declval<const ctx_type&>()));
0084 if constexpr (detail::is_boost_iterator<attr_type>)
0085 arg = T { x3::_attr(ctx).begin(), x3::_attr(ctx).end() };
0086 else
0087 arg = x3::_attr(ctx);
0088 };
0089 }
0090
0091 template <typename LenParser, typename Subject, typename Enable = void>
0092 class scope_limit {};
0093
0094 template <typename LenParser, typename Subject>
0095 class scope_limit<
0096 LenParser, Subject,
0097 std::enable_if_t<x3::traits::is_parser<LenParser>::value>
0098 > :
0099 public x3::unary_parser<Subject, scope_limit<LenParser, Subject>>
0100 {
0101 using base_type = x3::unary_parser<Subject, scope_limit<LenParser, Subject>>;
0102 LenParser _lp;
0103 public:
0104 using ctx_type =
0105 decltype(x3::make_context<struct _>(std::declval<Subject&>()));
0106 using attribute_type =
0107 typename x3::traits::attribute_of<Subject, ctx_type>::type;
0108
0109 static bool const has_attribute = true;
0110
0111 scope_limit(const LenParser& lp, const Subject& subject) :
0112 base_type(subject), _lp(lp)
0113 {}
0114
0115 template <typename It, typename Ctx, typename RCtx, typename Attr>
0116 bool parse(
0117 It& first, const It last,
0118 const Ctx& ctx, RCtx& rctx, Attr& attr
0119 ) const {
0120
0121 It iter = first;
0122 typename x3::traits::attribute_of<LenParser, Ctx>::type len;
0123 if (!_lp.parse(iter, last, ctx, rctx, len))
0124 return false;
0125 if (iter + len > last)
0126 return false;
0127
0128 if (!base_type::subject.parse(iter, iter + len, ctx, rctx, attr))
0129 return false;
0130
0131 first = iter;
0132 return true;
0133 }
0134 };
0135
0136 template <typename Size, typename Subject>
0137 class scope_limit<
0138 Size, Subject,
0139 std::enable_if_t<std::is_arithmetic_v<Size>>
0140 > :
0141 public x3::unary_parser<Subject, scope_limit<Size, Subject>>
0142 {
0143 using base_type = x3::unary_parser<Subject, scope_limit<Size, Subject>>;
0144 size_t _limit;
0145 public:
0146 using ctx_type =
0147 decltype(x3::make_context<struct _>(std::declval<Subject&>()));
0148 using attribute_type =
0149 typename x3::traits::attribute_of<Subject, ctx_type>::type;
0150
0151 static bool const has_attribute = true;
0152
0153 scope_limit(Size limit, const Subject& subject) :
0154 base_type(subject), _limit(limit)
0155 {}
0156
0157 template <typename It, typename Ctx, typename RCtx, typename Attr>
0158 bool parse(
0159 It& first, const It last,
0160 const Ctx& ctx, RCtx& rctx, Attr& attr
0161 ) const {
0162
0163 It iter = first;
0164 if (iter + _limit > last)
0165 return false;
0166
0167 if (!base_type::subject.parse(iter, iter + _limit, ctx, rctx, attr))
0168 return false;
0169
0170 first = iter;
0171 return true;
0172 }
0173 };
0174
0175 template <typename LenParser, typename Enable = void>
0176 struct scope_limit_gen {
0177 template <typename Subject>
0178 auto operator[](const Subject& p) const {
0179 return scope_limit<LenParser, Subject> { _lp, x3::as_parser(p) };
0180 }
0181 LenParser _lp;
0182 };
0183
0184 template <typename Size>
0185 struct scope_limit_gen<
0186 Size,
0187 std::enable_if_t<std::is_arithmetic_v<Size>>
0188 > {
0189 template <typename Subject>
0190 auto operator[](const Subject& p) const {
0191 return scope_limit<Size, Subject> { limit, x3::as_parser(p) };
0192 }
0193 Size limit;
0194 };
0195
0196 template <
0197 typename Parser,
0198 std::enable_if_t<x3::traits::is_parser<Parser>::value, bool> = true
0199 >
0200 scope_limit_gen<Parser> scope_limit_(const Parser& p) {
0201 return { p };
0202 }
0203
0204 template <
0205 typename Size,
0206 std::enable_if_t<std::is_arithmetic_v<Size>, bool> = true
0207 >
0208 scope_limit_gen<Size> scope_limit_(Size limit) {
0209 return { limit };
0210 }
0211
0212 struct verbatim_parser : x3::parser<verbatim_parser> {
0213 using attribute_type = std::string;
0214 static bool const has_attribute = true;
0215
0216 template <typename It, typename Ctx, typename RCtx, typename Attr>
0217 bool parse(It& first, const It last, const Ctx&, RCtx&, Attr& attr) const {
0218 attr = std::string { first, last };
0219 first = last;
0220 return true;
0221 }
0222 };
0223
0224 constexpr auto verbatim_ = verbatim_parser{};
0225
0226 struct varint_parser : x3::parser<varint_parser> {
0227 using attribute_type = int32_t;
0228 static bool const has_attribute = true;
0229
0230 template <typename It, typename Ctx, typename RCtx, typename Attr>
0231 bool parse(
0232 It& first, const It last,
0233 const Ctx& ctx, RCtx&, Attr& attr
0234 ) const {
0235
0236 It iter = first;
0237 x3::skip_over(iter, last, ctx);
0238
0239 if (iter == last)
0240 return false;
0241
0242 int32_t result = 0; unsigned bit_shift = 0;
0243
0244 for (; iter != last && bit_shift < sizeof(int32_t) * 7; ++iter) {
0245 auto val = *iter;
0246 if (val & 0b1000'0000u) {
0247 result |= (val & 0b0111'1111u) << bit_shift;
0248 bit_shift += 7;
0249 }
0250 else {
0251 result |= (static_cast<int32_t>(val) << bit_shift);
0252 bit_shift = 0;
0253 break;
0254 }
0255 }
0256 if (bit_shift)
0257 return false;
0258
0259 attr = result;
0260 first = ++iter;
0261 return true;
0262 }
0263 };
0264
0265 constexpr varint_parser varint_{};
0266
0267 struct len_prefix_parser : x3::parser<len_prefix_parser> {
0268 using attribute_type = std::string;
0269 static bool const has_attribute = true;
0270
0271 template <typename It, typename Ctx, typename RCtx, typename Attr>
0272 bool parse(
0273 It& first, const It last,
0274 const Ctx& ctx, RCtx& rctx, Attr& attr
0275 ) const {
0276 It iter = first;
0277 x3::skip_over(iter, last, ctx);
0278
0279 typename x3::traits::attribute_of<decltype(x3::big_word), Ctx>::type len;
0280 if (x3::big_word.parse(iter, last, ctx, rctx, len)) {
0281 if (std::distance(iter, last) < len)
0282 return false;
0283 }
0284 else
0285 return false;
0286
0287 attr = std::string(iter, iter + len);
0288 first = iter + len;
0289 return true;
0290 }
0291 };
0292
0293 constexpr len_prefix_parser utf8_ {};
0294 constexpr len_prefix_parser binary_ {};
0295
0296
0297
0298
0299
0300
0301
0302 template <typename Subject>
0303 class conditional_parser :
0304 public x3::unary_parser<Subject, conditional_parser<Subject>> {
0305
0306 using base_type = x3::unary_parser<Subject, conditional_parser<Subject>>;
0307 bool _condition;
0308 public:
0309 using ctx_type =
0310 decltype(x3::make_context<struct _>(std::declval<Subject&>()));
0311 using subject_attr_type =
0312 typename x3::traits::attribute_of<Subject, ctx_type>::type;
0313
0314 using attribute_type = boost::optional<subject_attr_type>;
0315 static bool const has_attribute = true;
0316
0317 conditional_parser(const Subject& s, bool condition) :
0318 base_type(s), _condition(condition) {}
0319
0320 template <typename It, typename Ctx, typename RCtx, typename Attr>
0321 bool parse(
0322 It& first, const It last,
0323 const Ctx& ctx, RCtx& rctx, Attr& attr
0324 ) const {
0325 if (!_condition)
0326 return true;
0327
0328 It iter = first;
0329 subject_attr_type sattr {};
0330 if (!base_type::subject.parse(iter, last, ctx, rctx, sattr))
0331 return false;
0332
0333 attr.emplace(std::move(sattr));
0334 first = iter;
0335 return true;
0336 }
0337 };
0338
0339 struct conditional_gen {
0340 bool _condition;
0341
0342 template <typename Subject>
0343 auto operator[](const Subject& p) const {
0344 return conditional_parser<Subject> { p, _condition };
0345 }
0346 };
0347
0348 inline conditional_gen if_(bool condition) {
0349 return { condition };
0350 }
0351
0352 }
0353
0354
0355 namespace prop {
0356
0357 namespace basic = boost::mqtt5::decoders::basic;
0358
0359 namespace detail {
0360
0361 template <typename It, typename Ctx, typename RCtx, typename Prop>
0362 bool parse_to_prop(
0363 It& iter, const It last,
0364 const Ctx& ctx, RCtx& rctx, Prop& prop
0365 ) {
0366 using namespace boost::mqtt5::detail;
0367 using prop_type = std::remove_reference_t<decltype(prop)>;
0368
0369 bool rv = false;
0370
0371 if constexpr (std::is_same_v<prop_type, uint8_t>)
0372 rv = x3::byte_.parse(iter, last, ctx, rctx, prop);
0373 else if constexpr (std::is_same_v<prop_type, uint16_t>)
0374 rv = x3::big_word.parse(iter, last, ctx, rctx, prop);
0375 else if constexpr (std::is_same_v<prop_type, int32_t>)
0376 rv = basic::varint_.parse(iter, last, ctx, rctx, prop);
0377 else if constexpr (std::is_same_v<prop_type, uint32_t>)
0378 rv = x3::big_dword.parse(iter, last, ctx, rctx, prop);
0379 else if constexpr (std::is_same_v<prop_type, std::string>)
0380 rv = basic::utf8_.parse(iter, last, ctx, rctx, prop);
0381
0382 else if constexpr (is_optional<prop_type>) {
0383 typename prop_type::value_type val;
0384 rv = parse_to_prop(iter, last, ctx, rctx, val);
0385 if (rv) prop.emplace(std::move(val));
0386 }
0387
0388 else if constexpr (is_pair<prop_type>) {
0389 rv = parse_to_prop(iter, last, ctx, rctx, prop.first);
0390 rv = parse_to_prop(iter, last, ctx, rctx, prop.second);
0391 }
0392
0393 else if constexpr (is_vector<prop_type> || is_small_vector<prop_type>) {
0394 typename std::remove_reference_t<prop_type>::value_type value;
0395 rv = parse_to_prop(iter, last, ctx, rctx, value);
0396 if (rv) prop.push_back(std::move(value));
0397 }
0398
0399 return rv;
0400 }
0401
0402 }
0403
0404 template <typename Props>
0405 class prop_parser : public x3::parser<prop_parser<Props>> {
0406 public:
0407 using attribute_type = Props;
0408 static bool const has_attribute = true;
0409
0410 template <typename It, typename Ctx, typename RCtx, typename Attr>
0411 bool parse(
0412 It& first, const It last,
0413 const Ctx& ctx, RCtx& rctx, Attr& attr
0414 ) const {
0415
0416 It iter = first;
0417 x3::skip_over(iter, last, ctx);
0418
0419 if (iter == last)
0420 return true;
0421
0422 int32_t props_length;
0423 if (!basic::varint_.parse(iter, last, ctx, rctx, props_length))
0424 return false;
0425
0426 const It scoped_last = iter + props_length;
0427
0428
0429 while (iter < scoped_last) {
0430 uint8_t prop_id = *iter++;
0431 bool rv = true;
0432 It saved = iter;
0433
0434 attr.apply_on(
0435 prop_id,
0436 [&rv, &iter, scoped_last, &ctx, &rctx](auto& prop) {
0437 rv = detail::parse_to_prop(
0438 iter, scoped_last, ctx, rctx, prop
0439 );
0440 }
0441 );
0442
0443
0444 if (!rv || iter == saved)
0445 return false;
0446 }
0447
0448 first = iter;
0449 return true;
0450 }
0451 };
0452
0453
0454 template <typename Props>
0455 constexpr auto props_ = prop_parser<Props> {};
0456
0457 }
0458
0459
0460 }
0461
0462 #endif