mirror of
				https://github.com/boostorg/mqtt5.git
				synced 2025-11-04 01:41:37 +01:00 
			
		
		
		
	Summary: resolves T13332 Reviewers: ivica Reviewed By: ivica Subscribers: miljen, iljazovic Maniphest Tasks: T13332 Differential Revision: https://repo.mireo.local/D27000
		
			
				
	
	
		
			108 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			108 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#ifndef ASYNC_MQTT5_TOPIC_VALIDATION_HPP
 | 
						|
#define ASYNC_MQTT5_TOPIC_VALIDATION_HPP
 | 
						|
 | 
						|
#include <string>
 | 
						|
 | 
						|
#include <async_mqtt5/detail/utf8_mqtt.hpp>
 | 
						|
 | 
						|
namespace async_mqtt5::detail {
 | 
						|
 | 
						|
static constexpr uint32_t min_subscription_identifier = 1;
 | 
						|
static constexpr uint32_t max_subscription_identifier = 268'435'455;
 | 
						|
 | 
						|
static constexpr std::string_view shared_sub_id = "$share/";
 | 
						|
 | 
						|
inline bool is_utf8_no_wildcard(validation_result result) {
 | 
						|
	return result == validation_result::valid;
 | 
						|
}
 | 
						|
 | 
						|
inline bool is_not_empty(size_t sz) {
 | 
						|
	return sz != 0;
 | 
						|
}
 | 
						|
 | 
						|
inline bool is_valid_topic_size(size_t sz) {
 | 
						|
	return is_not_empty(sz) && is_valid_string_size(sz);
 | 
						|
}
 | 
						|
 | 
						|
inline validation_result validate_topic_name(std::string_view str) {
 | 
						|
	return validate_impl(str, is_valid_topic_size, is_utf8_no_wildcard);
 | 
						|
}
 | 
						|
 | 
						|
inline validation_result validate_share_name(std::string_view str) {
 | 
						|
	return validate_impl(str, is_not_empty, is_utf8_no_wildcard);
 | 
						|
}
 | 
						|
 | 
						|
inline validation_result validate_topic_filter(std::string_view str) {
 | 
						|
	if (!is_valid_topic_size(str.size()))
 | 
						|
		return validation_result::invalid;
 | 
						|
 | 
						|
	constexpr int multi_lvl_wildcard = '#';
 | 
						|
	constexpr int single_lvl_wildcard = '+';
 | 
						|
 | 
						|
	// must be the last character preceded by '/' or stand alone
 | 
						|
	// #, .../#
 | 
						|
	if (str.back() == multi_lvl_wildcard) {
 | 
						|
		str.remove_suffix(1);
 | 
						|
 | 
						|
		if (!str.empty() && str.back() != '/')
 | 
						|
			return validation_result::invalid;
 | 
						|
	}
 | 
						|
 | 
						|
	int last_c = -1;
 | 
						|
	validation_result result;
 | 
						|
	while (!str.empty()) {
 | 
						|
		int c = pop_front_unichar(str);
 | 
						|
 | 
						|
		// can be used at any level, but must occupy an entire level
 | 
						|
		// +, +/..., .../+/..., .../+
 | 
						|
		bool is_valid_single_lvl = (c == single_lvl_wildcard) &&
 | 
						|
			(str.empty() || str.front() == '/') &&
 | 
						|
			(last_c == -1 || last_c == '/');
 | 
						|
 | 
						|
		result = validate_mqtt_utf8_char(c);
 | 
						|
		if (
 | 
						|
			result == validation_result::valid ||
 | 
						|
			is_valid_single_lvl
 | 
						|
		) {
 | 
						|
			last_c = c;
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		return validation_result::invalid;
 | 
						|
	}
 | 
						|
 | 
						|
	return validation_result::valid;
 | 
						|
}
 | 
						|
 | 
						|
inline validation_result validate_shared_topic_filter(
 | 
						|
	std::string_view str, bool wildcard_allowed = true
 | 
						|
) {
 | 
						|
	if (!is_valid_topic_size(str.size()))
 | 
						|
		return validation_result::invalid;
 | 
						|
 | 
						|
	if (str.compare(0, shared_sub_id.size(), shared_sub_id) != 0)
 | 
						|
		return validation_result::invalid;
 | 
						|
 | 
						|
	str.remove_prefix(shared_sub_id.size());
 | 
						|
 | 
						|
	size_t share_name_end = str.find_first_of('/');
 | 
						|
	if (share_name_end == std::string::npos)
 | 
						|
		return validation_result::invalid;
 | 
						|
 | 
						|
	validation_result result;
 | 
						|
	result = validate_share_name(str.substr(0, share_name_end));
 | 
						|
 | 
						|
	if (result != validation_result::valid)
 | 
						|
		return validation_result::invalid;
 | 
						|
 | 
						|
	auto topic_filter = str.substr(share_name_end + 1);
 | 
						|
	return wildcard_allowed ?
 | 
						|
		validate_topic_filter(topic_filter) :
 | 
						|
		validate_topic_name(topic_filter)
 | 
						|
	;
 | 
						|
}
 | 
						|
 | 
						|
} // end namespace async_mqtt5::detail
 | 
						|
 | 
						|
#endif //ASYNC_MQTT5_TOPIC_VALIDATION_HPP
 |