Botcraft 1.21.4
Loading...
Searching...
No Matches
StringUtilities.cpp
Go to the documentation of this file.
3
4
5#if PROTOCOL_VERSION > 758 /* > 1.18.2 */
6#include <array>
7#include <ctime>
8#include <iomanip>
9#endif
10
11namespace Botcraft::Utilities
12{
13 bool StartsWith(const std::string& mainStr, const std::string& toMatch)
14 {
15 return mainStr.find(toMatch) == 0;
16 }
17
18 bool EndsWith(const std::string& mainStr, const std::string& toMatch)
19 {
20 if (toMatch.size() > mainStr.size())
21 {
22 return false;
23 }
24 return std::equal(toMatch.rbegin(), toMatch.rend(), mainStr.rbegin());
25 }
26
27 bool Contains(const std::string& mainStr, const std::string& toFind)
28 {
29 return mainStr.find(toFind) != std::string::npos;
30 }
31
32 std::vector<std::string> SplitString(const std::string& s, const char delimiter)
33 {
34 std::vector<std::string> tokens;
35 std::string token;
36 std::istringstream tokenStream(s);
37 while (std::getline(tokenStream, token, delimiter))
38 {
39 tokens.push_back(token);
40 }
41 return tokens;
42 }
43
44 std::vector<std::string> SplitString(const std::string& s, const std::string& delimiter)
45 {
46 const size_t delimiter_size = delimiter.size();
47 size_t start = 0;
48 size_t end = 0;
49 std::vector<std::string> tokens;
50
51 while ((end = s.find(delimiter, start)) != std::string::npos)
52 {
53 tokens.push_back(s.substr(start, end - start));
54 start = end + delimiter_size;
55 }
56
57 tokens.push_back(s.substr(start));
58
59 return tokens;
60 }
61
62#if PROTOCOL_VERSION > 758 /* > 1.18.2 */
63 std::vector<unsigned char> DecodeBase64(const std::string& s)
64 {
65 static std::array<unsigned char, 128> constexpr decode_table{
66 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
67 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
68 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
69 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
70 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
71 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
72 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
73 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64
74 };
75
76 if (s.size() == 0)
77 {
78 return {};
79 }
80
81 if (s.size() % 4 != 0)
82 {
83 LOG_ERROR("Base64 string size not a multiple of 4");
84 return {};
85 }
86
87 const size_t output_size = s.size() / 4 * 3;
88
89 std::vector<unsigned char> output;
90 output.reserve(output_size);
91
92 for (int i = 0; i < s.size(); i += 4)
93 {
94 const unsigned char c1 = s[i + 0] == '=' ? 0 : decode_table[static_cast<unsigned char>(s[i + 0])];
95 const unsigned char c2 = s[i + 1] == '=' ? 0 : decode_table[static_cast<unsigned char>(s[i + 1])];
96 const unsigned char c3 = s[i + 2] == '=' ? 0 : decode_table[static_cast<unsigned char>(s[i + 2])];
97 const unsigned char c4 = s[i + 3] == '=' ? 0 : decode_table[static_cast<unsigned char>(s[i + 3])];
98
99 const unsigned int bytes = (c1 << 18) | (c2 << 12) | (c3 << 6) | (c4 << 0);
100
101 output.push_back((bytes >> 16) & 0xFF);
102 output.push_back((bytes >> 8) & 0xFF);
103 output.push_back((bytes >> 0) & 0xFF);
104 }
105
106 // If last character is a padding, we'll have one less byte
107 if (s.back() == '=')
108 {
109 output.pop_back();
110 }
111 // If second last character is a padding, we'll have two less bytes
112 if (s[s.size() - 2] == '=')
113 {
114 output.pop_back();
115 }
116
117 return output;
118 }
119
120 std::vector<unsigned char> RSAToBytes(const std::string& s)
121 {
122 const std::vector<std::string> splitted = SplitString(s, '\n');
123 std::string base64 = "";
124 for (int i = 1; i < splitted.size() - 1; ++i)
125 {
126 base64 += splitted[i];
127 }
128 return DecodeBase64(base64);
129 }
130
131 int IsLeap(const int year)
132 {
133 if (year % 400 == 0)
134 {
135 return 1;
136 }
137 if (year % 100 == 0)
138 {
139 return 0;
140 }
141 if (year % 4 == 0)
142 {
143 return 1;
144 }
145 return 0;
146 }
147
148 int DaysFrom0(const int year)
149 {
150 return 365 * (year - 1) + ((year - 1) / 400) - ((year - 1) / 100) + ((year - 1) / 4);
151 }
152
153 int DaysFrom1970(int32_t year)
154 {
155 return DaysFrom0(year) - DaysFrom0(1970);
156 }
157
158 int DaysFrom1Jan(const int year, const int month, const int day)
159 {
160 static constexpr std::array<std::array<int, 12>, 2> days =
161 { {
162 { 0,31,59,90,120,151,181,212,243,273,304,334},
163 { 0,31,60,91,121,152,182,213,244,274,305,335}
164 } };
165
166 return days[IsLeap(year)][month - 1] + day - 1;
167 }
168
169 long long int TimestampMilliFromISO8601(const std::string& s)
170 {
171 std::tm t{};
172 std::stringstream iso8601(s);
173 iso8601 >> std::get_time(&t, "%Y-%m-%dT%H:%M:%S");
174
175 if (iso8601.fail())
176 {
177 LOG_ERROR("Error trying to parse ISO 8601 string: " << s);
178 return 0;
179 }
180
181 std::vector<std::string> splitted_expires = SplitString(s, '.');
182 if (EndsWith(splitted_expires.back(), "Z"))
183 {
184 splitted_expires.back() = splitted_expires.back().substr(0, splitted_expires.back().size() - 1);
185 }
186 const long long int ms = std::stol(splitted_expires.back()) / 1000;
187
188 const int year = t.tm_year + 1900;
189 const int month = t.tm_mon + 1;
190 const int day = t.tm_mday;
191 const int day_of_year = DaysFrom1Jan(year, month, day);
192 const int days_since_epoch = DaysFrom1970(year) + day_of_year;
193
194 const long long int sec = 3600 * 24 * days_since_epoch + 3600 * t.tm_hour + 60 * t.tm_min + t.tm_sec;
195
196 return sec * 1000 + ms;
197 }
198#endif
199} // Botcraft::Utilities
#define LOG_ERROR(osstream)
Definition Logger.hpp:45
bool Contains(const std::string &mainStr, const std::string &toFind)
int DaysFrom0(const int year)
bool StartsWith(const std::string &mainStr, const std::string &toMatch)
std::vector< unsigned char > RSAToBytes(const std::string &s)
std::vector< unsigned char > DecodeBase64(const std::string &s)
int DaysFrom1970(int32_t year)
std::vector< std::string > SplitString(const std::string &s, const char delimiter)
int IsLeap(const int year)
int DaysFrom1Jan(const int year, const int month, const int day)
long long int TimestampMilliFromISO8601(const std::string &s)
bool EndsWith(const std::string &mainStr, const std::string &toMatch)