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_TOPIC_VALIDATION_HPP
0009 #define BOOST_MQTT5_TOPIC_VALIDATION_HPP
0010 
0011 #include <boost/mqtt5/detail/utf8_mqtt.hpp>
0012 
0013 #include <cstdint>
0014 #include <string_view>
0015 
0016 namespace boost::mqtt5::detail {
0017 
0018 static constexpr int32_t min_subscription_identifier = 1;
0019 static constexpr int32_t max_subscription_identifier = 268'435'455;
0020 
0021 static constexpr std::string_view shared_sub_prefix = "$share/";
0022 
0023 inline bool is_utf8_no_wildcard(validation_result result) {
0024     return result == validation_result::valid;
0025 }
0026 
0027 inline bool is_not_empty(size_t sz) {
0028     return sz != 0;
0029 }
0030 
0031 inline bool is_valid_topic_size(size_t sz) {
0032     return is_not_empty(sz) && is_valid_string_size(sz);
0033 }
0034 
0035 inline validation_result validate_topic_name(std::string_view str) {
0036     return validate_impl(str, is_valid_topic_size, is_utf8_no_wildcard);
0037 }
0038 
0039 inline validation_result validate_topic_alias_name(std::string_view str) {
0040     return validate_impl(str, is_valid_string_size, is_utf8_no_wildcard);
0041 }
0042 
0043 inline validation_result validate_shared_topic_name(std::string_view str) {
0044     return validate_impl(str, is_not_empty, is_utf8_no_wildcard);
0045 }
0046 
0047 inline validation_result validate_topic_filter(std::string_view str) {
0048     if (!is_valid_topic_size(str.size()))
0049         return validation_result::invalid;
0050 
0051     constexpr int multi_lvl_wildcard = '#';
0052     constexpr int single_lvl_wildcard = '+';
0053 
0054     // must be the last character preceded by '/' or stand alone
0055     // #, .../#
0056     if (str.back() == multi_lvl_wildcard) {
0057         str.remove_suffix(1);
0058 
0059         if (!str.empty() && str.back() != '/')
0060             return validation_result::invalid;
0061     }
0062 
0063     int last_c = -1;
0064     validation_result result;
0065     while (!str.empty()) {
0066         int c = pop_front_unichar(str);
0067 
0068         // can be used at any level, but must occupy an entire level
0069         // +, +/..., .../+/..., .../+
0070         bool is_valid_single_lvl = (c == single_lvl_wildcard) &&
0071             (str.empty() || str.front() == '/') &&
0072             (last_c == -1 || last_c == '/');
0073 
0074         result = validate_mqtt_utf8_char(c);
0075         if (
0076             result == validation_result::valid ||
0077             is_valid_single_lvl
0078         ) {
0079             last_c = c;
0080             continue;
0081         }
0082 
0083         return validation_result::invalid;
0084     }
0085 
0086     return validation_result::valid;
0087 }
0088 
0089 inline validation_result validate_shared_topic_filter(
0090     std::string_view str, bool wildcard_allowed = true
0091 ) {
0092     if (!is_valid_topic_size(str.size()))
0093         return validation_result::invalid;
0094 
0095     if (str.compare(0, shared_sub_prefix.size(), shared_sub_prefix) != 0)
0096         return validation_result::invalid;
0097 
0098     str.remove_prefix(shared_sub_prefix.size());
0099 
0100     size_t share_name_end = str.find_first_of('/');
0101     if (share_name_end == std::string::npos)
0102         return validation_result::invalid;
0103 
0104     validation_result result;
0105     result = validate_shared_topic_name(str.substr(0, share_name_end));
0106 
0107     if (result != validation_result::valid)
0108         return validation_result::invalid;
0109 
0110     auto topic_filter = str.substr(share_name_end + 1);
0111     return wildcard_allowed ?
0112         validate_topic_filter(topic_filter) :
0113         validate_topic_name(topic_filter)
0114     ;
0115 }
0116 
0117 } // end namespace boost::mqtt5::detail
0118 
0119 #endif //BOOST_MQTT5_TOPIC_VALIDATION_HPP