utils.cpp
5.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#include "utils.h"
#include "sys/time.h"
#include "sys/random.h"
#include <algorithm>
#include "exceptions.h"
std::list<std::__cxx11::string> split(const std::string &input, const char sep, size_t max, bool keep_empty_parts)
{
std::list<std::string> list;
size_t start = 0;
size_t end;
while (list.size() < max && (end = input.find(sep, start)) != std::string::npos)
{
if (start != end || keep_empty_parts)
list.push_back(input.substr(start, end - start));
start = end + 1; // increase by length of seperator.
}
if (start != input.size() || keep_empty_parts)
list.push_back(input.substr(start, std::string::npos));
return list;
}
bool topicsMatch(const std::string &subscribeTopic, const std::string &publishTopic)
{
if (subscribeTopic.find("+") == std::string::npos && subscribeTopic.find("#") == std::string::npos)
return subscribeTopic == publishTopic;
const std::list<std::string> subscribeParts = split(subscribeTopic, '/');
const std::list<std::string> publishParts = split(publishTopic, '/');
auto subscribe_itr = subscribeParts.begin();
auto publish_itr = publishParts.begin();
bool result = true;
while (subscribe_itr != subscribeParts.end() && publish_itr != publishParts.end())
{
const std::string &subscribe_subtopic = *subscribe_itr++;
const std::string &publish_subtopic = *publish_itr++;
if (subscribe_subtopic == "+")
continue;
if (subscribe_subtopic == "#")
return true;
if (subscribe_subtopic != publish_subtopic)
return false;
}
result = subscribe_itr == subscribeParts.end() && publish_itr == publishParts.end();
return result;
}
bool isValidUtf8(const std::string &s)
{
int multibyte_remain = 0;
int cur_code_point = 0;
for(const char &x : s)
{
if (x == 0)
return false;
if(!multibyte_remain)
{
cur_code_point = 0;
if((x & 0b11100000) == 0b11000000) // 2 byte char
{
multibyte_remain = 1;
cur_code_point += ((x & 0b00011111) << 6);
}
else if((x & 0b11110000) == 0b11100000) // 3 byte char
{
multibyte_remain = 2;
cur_code_point += ((x & 0b00001111) << 12);
}
else if((x & 0b11111000) == 0b11110000) // 4 byte char
{
multibyte_remain = 3;
cur_code_point += ((x & 0b00000111) << 18);
}
else if((x & 0b10000000) != 0)
return false;
else
cur_code_point += (x & 0b01111111);
}
else // All remainer bytes of this code point needs to start with 10
{
if((x & 0b11000000) != 0b10000000)
return false;
multibyte_remain--;
cur_code_point += ((x & 0b00111111) << (6*multibyte_remain));
}
if (multibyte_remain == 0)
{
// Invalid range for MQTT. [MQTT-1.5.3-1]
if (cur_code_point >= 0xD800 && cur_code_point <= 0xDFFF) // Dec 55296-57343
return false;
if (cur_code_point >= 0x0001 && cur_code_point <= 0x001F)
return false;
if (cur_code_point >= 0x007F && cur_code_point <= 0x009F)
return false;
if (cur_code_point == 0xFFFF)
return false;
cur_code_point = 0;
}
}
return multibyte_remain == 0;
}
bool strContains(const std::string &s, const std::string &needle)
{
return s.find(needle) != std::string::npos;
}
bool isValidPublishPath(const std::string &s)
{
if (s.empty())
return false;
for (const char c : s)
{
if (c == '#' || c == '+')
return false;
}
return true;
}
std::vector<std::string> splitToVector(const std::string &input, const char sep, size_t max, bool keep_empty_parts)
{
std::vector<std::string> list;
list.reserve(16); // This is somewhat arbitratry, knowing some typical MQTT topic use cases
size_t start = 0;
size_t end;
while (list.size() < max && (end = input.find(sep, start)) != std::string::npos)
{
if (start != end || keep_empty_parts)
list.push_back(input.substr(start, end - start));
start = end + 1; // increase by length of seperator.
}
if (start != input.size() || keep_empty_parts)
list.push_back(input.substr(start, std::string::npos));
return list;
}
void ltrim(std::string &s)
{
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
return !std::isspace(ch);
}));
}
void rtrim(std::string &s)
{
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
return !std::isspace(ch);
}).base(), s.end());
}
void trim(std::string &s)
{
ltrim(s);
rtrim(s);
}
bool startsWith(const std::string &s, const std::string &needle)
{
return s.find(needle) == 0;
}
int64_t currentMSecsSinceEpoch()
{
struct timeval te;
gettimeofday(&te, NULL);
int64_t milliseconds = te.tv_sec*1000LL + te.tv_usec/1000;
return milliseconds;
}
std::string getSecureRandomString(const size_t len)
{
std::vector<char> buf(len);
size_t actual_len = getrandom(buf.data(), len, 0);
if (actual_len < 0 || actual_len != len)
{
throw std::runtime_error("Error requesting random data");
}
const std::string possibleCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrtsuvwxyz1234567890");
const int possibleCharactersCount = possibleCharacters.length();
std::string randomString;
for(const unsigned char &c : buf)
{
unsigned int index = c % possibleCharactersCount;
char nextChar = possibleCharacters.at(index);
randomString.push_back(nextChar);
}
return randomString;
}