property.hpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828
  1. // Copyright Takatoshi Kondo 2018
  2. //
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // (See accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. #if !defined(MQTT_PROPERTY_HPP)
  7. #define MQTT_PROPERTY_HPP
  8. #include <string>
  9. #include <vector>
  10. #include <memory>
  11. #include <algorithm>
  12. #include <iosfwd>
  13. #include <iomanip>
  14. #include <boost/asio/buffer.hpp>
  15. #include <boost/numeric/conversion/cast.hpp>
  16. #include <boost/container/static_vector.hpp>
  17. #include <boost/operators.hpp>
  18. #include <mqtt/namespace.hpp>
  19. #include <mqtt/optional.hpp>
  20. #include <mqtt/two_byte_util.hpp>
  21. #include <mqtt/const_buffer_util.hpp>
  22. #include <mqtt/exception.hpp>
  23. #include <mqtt/string_check.hpp>
  24. #include <mqtt/property_id.hpp>
  25. #include <mqtt/four_byte_util.hpp>
  26. #include <mqtt/utf8encoded_strings.hpp>
  27. #include <mqtt/subscribe_options.hpp>
  28. #include <mqtt/variable_length.hpp>
  29. #include <mqtt/buffer.hpp>
  30. #include <mqtt/move.hpp>
  31. #include <mqtt/type.hpp>
  32. namespace MQTT_NS {
  33. namespace as = boost::asio;
  34. namespace v5 {
  35. namespace property {
  36. namespace detail {
  37. enum class ostream_format {
  38. direct,
  39. int_cast,
  40. key_val,
  41. binary_string,
  42. json_like
  43. };
  44. template <std::size_t N>
  45. struct n_bytes_property : private boost::totally_ordered<n_bytes_property<N>> {
  46. explicit n_bytes_property(property::id id)
  47. :id_(id) {}
  48. template <typename It>
  49. n_bytes_property(property::id id, It b, It e)
  50. :id_(id), buf_(force_move(b), force_move(e)) {}
  51. n_bytes_property(property::id id, boost::container::static_vector<char, N> buf)
  52. :id_(id), buf_(force_move(buf)) {}
  53. /**
  54. * @brief Add const buffer sequence into the given buffer.
  55. * @param v buffer to add
  56. */
  57. void add_const_buffer_sequence(std::vector<as::const_buffer>& v) const {
  58. v.emplace_back(as::buffer(&id_, 1));
  59. v.emplace_back(as::buffer(buf_.data(), buf_.size()));
  60. }
  61. /**
  62. * @brief Copy the internal information to the range between b and e
  63. * it is for boost asio APIs
  64. * @param b begin of the range to fill
  65. * @param e end of the range to fill
  66. */
  67. template <typename It>
  68. void fill(It b, It e) const {
  69. (void)e; // Avoid warning in release builds about unused variable
  70. BOOST_ASSERT(static_cast<std::size_t>(std::distance(b, e)) >= size());
  71. *b++ = static_cast<typename std::iterator_traits<It>::value_type>(id_);
  72. std::copy(buf_.begin(), buf_.end(), b);
  73. }
  74. /**
  75. * @brief Get property::id
  76. * @return id
  77. */
  78. property::id id() const {
  79. return id_;
  80. }
  81. /**
  82. * @brief Get whole size of sequence
  83. * @return whole size
  84. */
  85. std::size_t size() const {
  86. return 1 + buf_.size();
  87. }
  88. /**
  89. * @brief Get number of element of const_buffer_sequence
  90. * @return number of element of const_buffer_sequence
  91. */
  92. static constexpr std::size_t num_of_const_buffer_sequence() {
  93. return 2;
  94. }
  95. friend bool operator<(n_bytes_property<N> const& lhs, n_bytes_property<N> const& rhs) {
  96. return std::tie(lhs.id_, lhs.buf_) < std::tie(rhs.id_, rhs.buf_);
  97. }
  98. friend bool operator==(n_bytes_property<N> const& lhs, n_bytes_property<N> const& rhs) {
  99. return std::tie(lhs.id_, lhs.buf_) == std::tie(rhs.id_, rhs.buf_);
  100. }
  101. static constexpr ostream_format const of_ = ostream_format::direct;
  102. property::id id_;
  103. boost::container::static_vector<char, N> buf_;
  104. };
  105. struct binary_property : private boost::totally_ordered<binary_property> {
  106. binary_property(property::id id, buffer buf)
  107. :id_(id),
  108. buf_(force_move(buf)),
  109. length_{ num_to_2bytes(boost::numeric_cast<std::uint16_t>(buf_.size())) } {
  110. if (buf_.size() > 0xffff) throw property_length_error();
  111. }
  112. /**
  113. * @brief Add const buffer sequence into the given buffer.
  114. * @param v buffer to add
  115. */
  116. void add_const_buffer_sequence(std::vector<as::const_buffer>& v) const {
  117. v.emplace_back(as::buffer(&id_, 1));
  118. v.emplace_back(as::buffer(length_.data(), length_.size()));
  119. v.emplace_back(as::buffer(buf_.data(), buf_.size()));
  120. }
  121. /**
  122. * @brief Copy the internal information to the range between b and e
  123. * it is for boost asio APIs
  124. * @param b begin of the range to fill
  125. * @param e end of the range to fill
  126. */
  127. template <typename It>
  128. void fill(It b, It e) const {
  129. (void)e; // Avoid warning in release builds about unused variable
  130. using dt = typename It::difference_type;
  131. BOOST_ASSERT(static_cast<std::size_t>(std::distance(b, e)) >= size());
  132. *b++ = static_cast<typename std::iterator_traits<It>::value_type>(id_);
  133. std::copy(length_.begin(), length_.end(), b);
  134. std::advance(b, static_cast<dt>(length_.size()));
  135. std::copy(buf_.begin(), buf_.end(), b);
  136. }
  137. /**
  138. * @brief Get property::id
  139. * @return id
  140. */
  141. property::id id() const {
  142. return id_;
  143. }
  144. /**
  145. * @brief Get whole size of sequence
  146. * @return whole size
  147. */
  148. std::size_t size() const {
  149. return 1 + length_.size() + buf_.size();
  150. }
  151. /**
  152. * @brief Get number of element of const_buffer_sequence
  153. * @return number of element of const_buffer_sequence
  154. */
  155. static constexpr std::size_t num_of_const_buffer_sequence() {
  156. return 2;
  157. }
  158. constexpr buffer const& val() const {
  159. return buf_;
  160. }
  161. friend bool operator<(binary_property const& lhs, binary_property const& rhs) {
  162. return std::tie(lhs.id_, lhs.buf_) < std::tie(rhs.id_, rhs.buf_);
  163. }
  164. friend bool operator==(binary_property const& lhs, binary_property const& rhs) {
  165. return std::tie(lhs.id_, lhs.buf_) == std::tie(rhs.id_, rhs.buf_);
  166. }
  167. static constexpr ostream_format const of_ = ostream_format::json_like;
  168. property::id id_;
  169. buffer buf_;
  170. boost::container::static_vector<char, 2> length_;
  171. };
  172. struct string_property : binary_property {
  173. string_property(property::id id, buffer buf, bool already_checked)
  174. :binary_property(id, force_move(buf)) {
  175. if (!already_checked) {
  176. auto r = utf8string::validate_contents(this->val());
  177. if (r != utf8string::validation::well_formed) throw utf8string_contents_error(r);
  178. }
  179. }
  180. };
  181. struct variable_property : private boost::totally_ordered<variable_property> {
  182. variable_property(property::id id, std::size_t value)
  183. :id_(id) {
  184. variable_push(value_, value);
  185. }
  186. /**
  187. * @brief Add const buffer sequence into the given buffer.
  188. * @param v buffer to add
  189. */
  190. void add_const_buffer_sequence(std::vector<as::const_buffer>& v) const {
  191. v.emplace_back(as::buffer(&id_, 1));
  192. v.emplace_back(as::buffer(value_.data(), value_.size()));
  193. }
  194. /**
  195. * @brief Copy the internal information to the range between b and e
  196. * it is for boost asio APIs
  197. * @param b begin of the range to fill
  198. * @param e end of the range to fill
  199. */
  200. template <typename It>
  201. void fill(It b, It e) const {
  202. (void)e; // Avoid warning in release builds about unused variable
  203. BOOST_ASSERT(static_cast<std::size_t>(std::distance(b, e)) >= size());
  204. *b++ = static_cast<typename std::iterator_traits<It>::value_type>(id_);
  205. std::copy(value_.begin(), value_.end(), b);
  206. }
  207. /**
  208. * @brief Get property::id
  209. * @return id
  210. */
  211. property::id id() const {
  212. return id_;
  213. }
  214. /**
  215. * @brief Get whole size of sequence
  216. * @return whole size
  217. */
  218. std::size_t size() const {
  219. return 1 + value_.size();
  220. }
  221. /**
  222. * @brief Get number of element of const_buffer_sequence
  223. * @return number of element of const_buffer_sequence
  224. */
  225. static constexpr std::size_t num_of_const_buffer_sequence() {
  226. return 2;
  227. }
  228. constexpr std::size_t val() const {
  229. return std::get<0>(variable_length(value_));
  230. }
  231. friend bool operator<(variable_property const& lhs, variable_property const& rhs) {
  232. auto const& lval = lhs.val();
  233. auto const& rval = rhs.val();
  234. return std::tie(lhs.id_, lval) < std::tie(rhs.id_, rval);
  235. }
  236. friend bool operator==(variable_property const& lhs, variable_property const& rhs) {
  237. auto const& lval = lhs.val();
  238. auto const& rval = rhs.val();
  239. return std::tie(lhs.id_, lval) == std::tie(rhs.id_, rval);
  240. }
  241. static constexpr ostream_format const of_ = ostream_format::direct;
  242. property::id id_;
  243. boost::container::static_vector<char, 4> value_;
  244. };
  245. } // namespace detail
  246. class payload_format_indicator : public detail::n_bytes_property<1> {
  247. public:
  248. using recv = payload_format_indicator;
  249. using store = payload_format_indicator;
  250. enum payload_format {
  251. binary,
  252. string
  253. };
  254. payload_format_indicator(payload_format fmt = binary)
  255. : detail::n_bytes_property<1>(id::payload_format_indicator, { fmt == binary ? char(0) : char(1) } ) {}
  256. template <typename It>
  257. payload_format_indicator(It b, It e)
  258. : detail::n_bytes_property<1>(id::payload_format_indicator, b, e) {}
  259. payload_format val() const {
  260. return ( (buf_.front() == 0)
  261. ? binary
  262. : string);
  263. }
  264. static constexpr detail::ostream_format const of_ = detail::ostream_format::binary_string;
  265. };
  266. class message_expiry_interval : public detail::n_bytes_property<4> {
  267. public:
  268. using recv = message_expiry_interval;
  269. using store = message_expiry_interval;
  270. message_expiry_interval(std::uint32_t val)
  271. : detail::n_bytes_property<4>(id::message_expiry_interval, num_to_4bytes(val) ) {}
  272. template <typename It>
  273. message_expiry_interval(It b, It e)
  274. : detail::n_bytes_property<4>(id::message_expiry_interval, b, e) {}
  275. std::uint32_t val() const {
  276. return make_uint32_t(buf_.begin(), buf_.end());
  277. }
  278. };
  279. class content_type : public detail::string_property {
  280. public:
  281. explicit content_type(buffer val, bool already_checked = false)
  282. : detail::string_property(id::content_type, force_move(val), already_checked) {}
  283. };
  284. class response_topic : public detail::string_property {
  285. public:
  286. explicit response_topic(buffer val, bool already_checked = false)
  287. : detail::string_property(id::response_topic, force_move(val), already_checked) {}
  288. };
  289. class correlation_data : public detail::binary_property {
  290. public:
  291. explicit correlation_data(buffer val)
  292. : detail::binary_property(id::correlation_data, force_move(val)) {}
  293. };
  294. class subscription_identifier : public detail::variable_property {
  295. public:
  296. using recv = subscription_identifier;
  297. using store = subscription_identifier;
  298. subscription_identifier(std::size_t subscription_id)
  299. : detail::variable_property(id::subscription_identifier, subscription_id) {}
  300. };
  301. class session_expiry_interval : public detail::n_bytes_property<4> {
  302. public:
  303. using recv = session_expiry_interval;
  304. using store = session_expiry_interval;
  305. session_expiry_interval(session_expiry_interval_t val)
  306. : detail::n_bytes_property<4>(id::session_expiry_interval, { num_to_4bytes(val) } ) {
  307. static_assert(sizeof(session_expiry_interval_t) == 4, "sizeof(sesion_expiry_interval) should be 4");
  308. }
  309. template <typename It>
  310. session_expiry_interval(It b, It e)
  311. : detail::n_bytes_property<4>(id::session_expiry_interval, b, e) {}
  312. session_expiry_interval_t val() const {
  313. return make_uint32_t(buf_.begin(), buf_.end());
  314. }
  315. };
  316. class assigned_client_identifier : public detail::string_property {
  317. public:
  318. explicit assigned_client_identifier(buffer val, bool already_checked = false)
  319. : detail::string_property(id::assigned_client_identifier, force_move(val), already_checked) {}
  320. };
  321. class server_keep_alive : public detail::n_bytes_property<2> {
  322. public:
  323. using recv = server_keep_alive;
  324. using store = server_keep_alive;
  325. server_keep_alive(std::uint16_t val)
  326. : detail::n_bytes_property<2>(id::server_keep_alive, { num_to_2bytes(val) } ) {}
  327. template <typename It>
  328. server_keep_alive(It b, It e)
  329. : detail::n_bytes_property<2>(id::server_keep_alive, b, e) {}
  330. std::uint16_t val() const {
  331. return make_uint16_t(buf_.begin(), buf_.end());
  332. }
  333. };
  334. class authentication_method : public detail::string_property {
  335. public:
  336. explicit authentication_method(buffer val, bool already_checked = false)
  337. : detail::string_property(id::authentication_method, force_move(val), already_checked) {}
  338. };
  339. class authentication_data : public detail::binary_property {
  340. public:
  341. explicit authentication_data(buffer val)
  342. : detail::binary_property(id::authentication_data, force_move(val)) {}
  343. };
  344. class request_problem_information : public detail::n_bytes_property<1> {
  345. public:
  346. using recv = request_problem_information;
  347. using store = request_problem_information;
  348. request_problem_information(bool value)
  349. : detail::n_bytes_property<1>(id::request_problem_information, { value ? char(1) : char(0) } ) {}
  350. template <typename It>
  351. request_problem_information(It b, It e)
  352. : detail::n_bytes_property<1>(id::request_problem_information, b, e) {}
  353. bool val() const {
  354. return buf_.front() == 1;
  355. }
  356. };
  357. class will_delay_interval : public detail::n_bytes_property<4> {
  358. public:
  359. using recv = will_delay_interval;
  360. using store = will_delay_interval;
  361. will_delay_interval(std::uint32_t val)
  362. : detail::n_bytes_property<4>(id::will_delay_interval, { num_to_4bytes(val) } ) {}
  363. template <typename It>
  364. will_delay_interval(It b, It e)
  365. : detail::n_bytes_property<4>(id::will_delay_interval, b, e) {}
  366. std::uint32_t val() const {
  367. return make_uint32_t(buf_.begin(), buf_.end());
  368. }
  369. };
  370. class request_response_information : public detail::n_bytes_property<1> {
  371. public:
  372. using recv = request_response_information;
  373. using store = request_response_information;
  374. request_response_information(bool value)
  375. : detail::n_bytes_property<1>(id::request_response_information, { value ? char(1) : char(0) } ) {}
  376. template <typename It>
  377. request_response_information(It b, It e)
  378. : detail::n_bytes_property<1>(id::request_response_information, b, e) {}
  379. bool val() const {
  380. return buf_.front() == 1;
  381. }
  382. };
  383. class response_information : public detail::string_property {
  384. public:
  385. explicit response_information(buffer val, bool already_checked = false)
  386. : detail::string_property(id::response_information, force_move(val), already_checked) {}
  387. };
  388. class server_reference : public detail::string_property {
  389. public:
  390. explicit server_reference(buffer val, bool already_checked = false)
  391. : detail::string_property(id::server_reference, force_move(val), already_checked) {}
  392. };
  393. class reason_string : public detail::string_property {
  394. public:
  395. explicit reason_string(buffer val, bool already_checked = false)
  396. : detail::string_property(id::reason_string, force_move(val), already_checked) {}
  397. };
  398. class receive_maximum : public detail::n_bytes_property<2> {
  399. public:
  400. using recv = receive_maximum;
  401. using store = receive_maximum;
  402. receive_maximum(receive_maximum_t val)
  403. : detail::n_bytes_property<2>(id::receive_maximum, { num_to_2bytes(val) } ) {}
  404. template <typename It>
  405. receive_maximum(It b, It e)
  406. : detail::n_bytes_property<2>(id::receive_maximum, b, e) {}
  407. receive_maximum_t val() const {
  408. return make_uint16_t(buf_.begin(), buf_.end());
  409. }
  410. };
  411. class topic_alias_maximum : public detail::n_bytes_property<2> {
  412. public:
  413. using recv = topic_alias_maximum;
  414. using store = topic_alias_maximum;
  415. topic_alias_maximum(topic_alias_t val)
  416. : detail::n_bytes_property<2>(id::topic_alias_maximum, { num_to_2bytes(val) } ) {}
  417. template <typename It>
  418. topic_alias_maximum(It b, It e)
  419. : detail::n_bytes_property<2>(id::topic_alias_maximum, b, e) {}
  420. topic_alias_t val() const {
  421. return make_uint16_t(buf_.begin(), buf_.end());
  422. }
  423. };
  424. class topic_alias : public detail::n_bytes_property<2> {
  425. public:
  426. using recv = topic_alias;
  427. using store = topic_alias;
  428. topic_alias(topic_alias_t val)
  429. : detail::n_bytes_property<2>(id::topic_alias, { num_to_2bytes(val) } ) {}
  430. template <typename It>
  431. topic_alias(It b, It e)
  432. : detail::n_bytes_property<2>(id::topic_alias, b, e) {}
  433. topic_alias_t val() const {
  434. return make_uint16_t(buf_.begin(), buf_.end());
  435. }
  436. };
  437. class maximum_qos : public detail::n_bytes_property<1> {
  438. public:
  439. using recv = maximum_qos;
  440. using store = maximum_qos;
  441. maximum_qos(qos value)
  442. : detail::n_bytes_property<1>(id::maximum_qos, { static_cast<char>(value) } ) {
  443. if (value != qos::at_most_once &&
  444. value != qos::at_least_once &&
  445. value != qos::exactly_once) throw property_parse_error();
  446. }
  447. template <typename It>
  448. maximum_qos(It b, It e)
  449. : detail::n_bytes_property<1>(id::maximum_qos, b, e) {}
  450. std::uint8_t val() const {
  451. return static_cast<std::uint8_t>(buf_.front());
  452. }
  453. static constexpr const detail::ostream_format of_ = detail::ostream_format::int_cast;
  454. };
  455. class retain_available : public detail::n_bytes_property<1> {
  456. public:
  457. using recv = retain_available;
  458. using store = retain_available;
  459. retain_available(bool value)
  460. : detail::n_bytes_property<1>(id::retain_available, { value ? char(1) : char(0) } ) {}
  461. template <typename It>
  462. retain_available(It b, It e)
  463. : detail::n_bytes_property<1>(id::retain_available, b, e) {}
  464. bool val() const {
  465. return buf_.front() == 1;
  466. }
  467. };
  468. class user_property : private boost::totally_ordered<user_property> {
  469. public:
  470. user_property(buffer key, buffer val, bool key_already_checked = false, bool val_already_checked = false)
  471. : key_(force_move(key), key_already_checked), val_(force_move(val), val_already_checked) {}
  472. /**
  473. * @brief Add const buffer sequence into the given buffer.
  474. * @param v buffer to add
  475. */
  476. void add_const_buffer_sequence(std::vector<as::const_buffer>& v) const {
  477. v.emplace_back(as::buffer(&id_, 1));
  478. v.emplace_back(as::buffer(key_.len.data(), key_.len.size()));
  479. v.emplace_back(as::buffer(key_.buf));
  480. v.emplace_back(as::buffer(val_.len.data(), val_.len.size()));
  481. v.emplace_back(as::buffer(val_.buf));
  482. }
  483. template <typename It>
  484. void fill(It b, It e) const {
  485. (void)e; // Avoid warning in release builds about unused variable
  486. using dt = typename It::difference_type;
  487. BOOST_ASSERT(static_cast<std::size_t>(std::distance(b, e)) >= size());
  488. *b++ = static_cast<typename std::iterator_traits<It>::value_type>(id_);
  489. {
  490. std::copy(key_.len.begin(), key_.len.end(), b);
  491. std::advance(b, static_cast<dt>(key_.len.size()));
  492. auto ptr = key_.buf.data();
  493. auto size = key_.buf.size();
  494. std::copy(ptr, std::next(ptr, static_cast<dt>(size)), b);
  495. std::advance(b, static_cast<dt>(size));
  496. }
  497. {
  498. std::copy(val_.len.begin(), val_.len.end(), b);
  499. std::advance(b, static_cast<dt>(val_.len.size()));
  500. auto ptr = val_.buf.data();
  501. auto size = val_.buf.size();
  502. std::copy(ptr, std::next(ptr, static_cast<dt>(size)), b);
  503. std::advance(b, static_cast<dt>(size));
  504. }
  505. }
  506. /**
  507. * @brief Get property::id
  508. * @return id
  509. */
  510. property::id id() const {
  511. return id_;
  512. }
  513. /**
  514. * @brief Get whole size of sequence
  515. * @return whole size
  516. */
  517. std::size_t size() const {
  518. return
  519. 1 + // id_
  520. key_.size() +
  521. val_.size();
  522. }
  523. /**
  524. * @brief Get number of element of const_buffer_sequence
  525. * @return number of element of const_buffer_sequence
  526. */
  527. static constexpr std::size_t num_of_const_buffer_sequence() {
  528. return
  529. 1 + // header
  530. 2 + // key (len, buf)
  531. 2; // val (len, buf)
  532. }
  533. constexpr buffer const& key() const {
  534. return key_.buf;
  535. }
  536. constexpr buffer const& val() const {
  537. return val_.buf;
  538. }
  539. friend bool operator<(user_property const& lhs, user_property const& rhs) {
  540. return std::tie(lhs.id_, lhs.key_.buf, lhs.val_.buf) < std::tie(rhs.id_, rhs.key_.buf, rhs.val_.buf);
  541. }
  542. friend bool operator==(user_property const& lhs, user_property const& rhs) {
  543. return std::tie(lhs.id_, lhs.key_.buf, lhs.val_.buf) == std::tie(rhs.id_, rhs.key_.buf, rhs.val_.buf);
  544. }
  545. static constexpr detail::ostream_format const of_ = detail::ostream_format::key_val;
  546. private:
  547. struct len_str {
  548. explicit len_str(buffer b, bool already_checked = false)
  549. : buf(force_move(b)),
  550. len{ num_to_2bytes(boost::numeric_cast<std::uint16_t>(buf.size())) }
  551. {
  552. if (!already_checked) {
  553. auto r = utf8string::validate_contents(buf);
  554. if (r != utf8string::validation::well_formed) throw utf8string_contents_error(r);
  555. }
  556. }
  557. std::size_t size() const {
  558. return len.size() + buf.size();
  559. }
  560. buffer buf;
  561. boost::container::static_vector<char, 2> len;
  562. };
  563. private:
  564. property::id id_ = id::user_property;
  565. len_str key_;
  566. len_str val_;
  567. };
  568. class maximum_packet_size : public detail::n_bytes_property<4> {
  569. public:
  570. using recv = maximum_packet_size;
  571. using store = maximum_packet_size;
  572. maximum_packet_size(std::uint32_t val)
  573. : detail::n_bytes_property<4>(id::maximum_packet_size, { num_to_4bytes(val) } ) {}
  574. template <typename It>
  575. maximum_packet_size(It b, It e)
  576. : detail::n_bytes_property<4>(id::maximum_packet_size, b, e) {}
  577. std::uint32_t val() const {
  578. return make_uint32_t(buf_.begin(), buf_.end());
  579. }
  580. };
  581. class wildcard_subscription_available : public detail::n_bytes_property<1> {
  582. public:
  583. using recv = wildcard_subscription_available;
  584. using store = wildcard_subscription_available;
  585. wildcard_subscription_available(bool value)
  586. : detail::n_bytes_property<1>(id::wildcard_subscription_available, { value ? char(1) : char(0) } ) {}
  587. template <typename It>
  588. wildcard_subscription_available(It b, It e)
  589. : detail::n_bytes_property<1>(id::wildcard_subscription_available, b, e) {}
  590. bool val() const {
  591. return buf_.front() == 1;
  592. }
  593. };
  594. class subscription_identifier_available : public detail::n_bytes_property<1> {
  595. public:
  596. using recv = subscription_identifier_available;
  597. using store = subscription_identifier_available;
  598. subscription_identifier_available(bool value)
  599. : detail::n_bytes_property<1>(id::subscription_identifier_available, { value ? char(1) : char(0) } ) {}
  600. template <typename It>
  601. subscription_identifier_available(It b, It e)
  602. : detail::n_bytes_property<1>(id::subscription_identifier_available, b, e) {}
  603. bool val() const {
  604. return buf_.front() == 1;
  605. }
  606. };
  607. class shared_subscription_available : public detail::n_bytes_property<1> {
  608. public:
  609. using recv = shared_subscription_available;
  610. using store = shared_subscription_available;
  611. shared_subscription_available(bool value)
  612. : detail::n_bytes_property<1>(id::shared_subscription_available, { value ? char(1) : char(0) } ) {}
  613. template <typename It>
  614. shared_subscription_available(It b, It e)
  615. : detail::n_bytes_property<1>(id::shared_subscription_available, b, e) {}
  616. bool val() const {
  617. return buf_.front() == 1;
  618. }
  619. };
  620. template <typename Property>
  621. std::enable_if_t< Property::of_ == detail::ostream_format::direct, std::ostream& >
  622. operator<<(std::ostream& o, Property const& p) {
  623. o << p.val();
  624. return o;
  625. }
  626. template <typename Property>
  627. std::enable_if_t< Property::of_ == detail::ostream_format::int_cast, std::ostream& >
  628. operator<<(std::ostream& o, Property const& p) {
  629. o << static_cast<int>(p.val());
  630. return o;
  631. }
  632. template <typename Property>
  633. std::enable_if_t< Property::of_ == detail::ostream_format::key_val, std::ostream& >
  634. operator<<(std::ostream& o, Property const& p) {
  635. o << p.key() << ':' << p.val();
  636. return o;
  637. }
  638. template <typename Property>
  639. std::enable_if_t< Property::of_ == detail::ostream_format::binary_string, std::ostream& >
  640. operator<<(std::ostream& o, Property const& p) {
  641. // Note this only compiles because both strings below are the same length.
  642. o << ((p.val() == payload_format_indicator::binary) ? "binary" : "string");
  643. return o;
  644. }
  645. template <typename Property>
  646. std::enable_if_t< Property::of_ == detail::ostream_format::json_like, std::ostream& >
  647. operator<<(std::ostream& o, Property const& p) {
  648. auto const& v = p.val();
  649. for (auto const c : v) {
  650. switch (c) {
  651. case '\\':
  652. o << "\\\\";
  653. break;
  654. case '"':
  655. o << "\\\"";
  656. break;
  657. case '/':
  658. o << "\\/";
  659. break;
  660. case '\b':
  661. o << "\\b";
  662. break;
  663. case '\f':
  664. o << "\\f";
  665. break;
  666. case '\n':
  667. o << "\\n";
  668. break;
  669. case '\r':
  670. o << "\\r";
  671. break;
  672. case '\t':
  673. o << "\\t";
  674. break;
  675. default: {
  676. unsigned int code = static_cast<unsigned int>(c);
  677. if (code < 0x20 || code >= 0x7f) {
  678. std::ios::fmtflags flags(o.flags());
  679. o << "\\u" << std::hex << std::setw(4) << std::setfill('0') << (code & 0xff);
  680. o.flags(flags);
  681. }
  682. else {
  683. o << c;
  684. }
  685. } break;
  686. }
  687. }
  688. return o;
  689. }
  690. } // namespace property
  691. } // namespace v5
  692. } // namespace MQTT_NS
  693. #endif // MQTT_PROPERTY_HPP