Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:38:19

0001 //
0002 // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic
0003 //
0004 // Distributed under the Boost Software License, Version 1.0.
0005 // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
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     // assuming that s.length() is > 0
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 && // U+0000...U+001F control characters
0062         (c < 0x007F || c > 0x009F) && // U+007F...0+009F control characters
0063         (c < 0xD800 || c > 0xDFFF) && // U+D800...U+DFFF surrogates
0064         (c < 0xFDD0 || c > 0xFDEF) && // U+FDD0...U+FDEF non-characters
0065         (c & fe_flag) != fe_flag && // non-characters
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 } // namespace boost::mqtt5::detail
0115 
0116 #endif //BOOST_MQTT5_UTF8_MQTT_HPP