File indexing completed on 2025-09-17 08:38:19
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_MQTT5_UTF8_MQTT_HPP
0009 #define BOOST_MQTT5_UTF8_MQTT_HPP
0010
0011 #include <cstdint>
0012 #include <string>
0013 #include <string_view>
0014 #include <utility>
0015
0016 namespace boost::mqtt5::detail {
0017
0018 enum class validation_result : uint8_t {
0019 valid = 0,
0020 has_wildcard_character,
0021 invalid
0022 };
0023
0024 inline int pop_front_unichar(std::string_view& s) {
0025
0026
0027 int n = s[0] & 0xF0;
0028 int ch = -1;
0029
0030 if ((n & 0x80) == 0) {
0031 ch = s[0];
0032 s.remove_prefix(1);
0033 }
0034 else if ((n == 0xC0 || n == 0xD0) && s.size() > 1) {
0035 ch = ((s[0] & 0x1F) << 6) | (s[1] & 0x3F);
0036 s.remove_prefix(2);
0037 }
0038 else if ((n == 0xE0) && s.size() > 2) {
0039 ch = ((s[0] & 0x1F) << 12) | ((s[1] & 0x3F) << 6) | (s[2] & 0x3F);
0040 s.remove_prefix(3);
0041 }
0042 else if ((n == 0xF0) && s.size() > 3) {
0043 ch = ((s[0] & 0x1F) << 18) | ((s[1] & 0x3F) << 12) |
0044 ((s[2] & 0x3F) << 6) | (s[3] & 0x3F);
0045 s.remove_prefix(4);
0046 }
0047
0048 return ch;
0049 }
0050
0051 inline validation_result validate_mqtt_utf8_char(int c) {
0052 constexpr int fe_flag = 0xFE;
0053 constexpr int ff_flag = 0xFF;
0054
0055 constexpr int multi_lvl_wildcard = '#';
0056 constexpr int single_lvl_wildcard = '+';
0057
0058 if (c == multi_lvl_wildcard || c == single_lvl_wildcard)
0059 return validation_result::has_wildcard_character;
0060
0061 if (c > 0x001F &&
0062 (c < 0x007F || c > 0x009F) &&
0063 (c < 0xD800 || c > 0xDFFF) &&
0064 (c < 0xFDD0 || c > 0xFDEF) &&
0065 (c & fe_flag) != fe_flag &&
0066 (c & ff_flag) != ff_flag
0067 )
0068 return validation_result::valid;
0069
0070 return validation_result::invalid;
0071 }
0072
0073 inline bool is_valid_string_size(size_t sz) {
0074 constexpr size_t max_sz = 65535;
0075 return sz <= max_sz;
0076 }
0077
0078 inline bool is_utf8(validation_result result) {
0079 return result == validation_result::valid ||
0080 result == validation_result::has_wildcard_character;
0081 }
0082
0083 template <typename ValidSizeCondition, typename ValidCondition>
0084 validation_result validate_impl(
0085 std::string_view str,
0086 ValidSizeCondition&& size_condition, ValidCondition&& condition
0087 ) {
0088 if (!size_condition(str.size()))
0089 return validation_result::invalid;
0090
0091 validation_result result;
0092 while (!str.empty()) {
0093 int c = pop_front_unichar(str);
0094
0095 result = validate_mqtt_utf8_char(c);
0096 if (!condition(result))
0097 return result;
0098 }
0099
0100 return validation_result::valid;
0101 }
0102
0103 inline validation_result validate_mqtt_utf8(std::string_view str) {
0104 return validate_impl(str, is_valid_string_size, is_utf8);
0105 }
0106
0107 inline bool is_valid_string_pair(
0108 const std::pair<std::string, std::string>& str_pair
0109 ) {
0110 return validate_mqtt_utf8(str_pair.first) == validation_result::valid &&
0111 validate_mqtt_utf8(str_pair.second) == validation_result::valid;
0112 }
0113
0114 }
0115
0116 #endif