utils.h 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. #ifndef UTILS_H
  2. #define UTILS_H
  3. #include <string>
  4. #include <vector>
  5. #include <algorithm>
  6. #include <cstdint>
  7. #include <sstream>
  8. #include <iomanip>
  9. namespace Utils {
  10. /**
  11. * @brief Base64 encoding table
  12. */
  13. static const char base64_chars[] =
  14. "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  15. "abcdefghijklmnopqrstuvwxyz"
  16. "0123456789+/";
  17. /**
  18. * @brief Encode binary data to base64
  19. *
  20. * @param data The binary data to encode
  21. * @return Base64 encoded string
  22. */
  23. inline std::string base64Encode(const std::vector<uint8_t>& data) {
  24. std::string ret;
  25. int i = 0;
  26. int j = 0;
  27. uint8_t char_array_3[3];
  28. uint8_t char_array_4[4];
  29. size_t in_len = data.size();
  30. const uint8_t* bytes_to_encode = data.data();
  31. while (in_len--) {
  32. char_array_3[i++] = *(bytes_to_encode++);
  33. if (i == 3) {
  34. char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
  35. char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
  36. char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
  37. char_array_4[3] = char_array_3[2] & 0x3f;
  38. for(i = 0; i < 4; i++)
  39. ret += base64_chars[char_array_4[i]];
  40. i = 0;
  41. }
  42. }
  43. if (i) {
  44. for(j = i; j < 3; j++)
  45. char_array_3[j] = '\0';
  46. char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
  47. char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
  48. char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
  49. char_array_4[3] = char_array_3[2] & 0x3f;
  50. for (j = 0; j < i + 1; j++)
  51. ret += base64_chars[char_array_4[j]];
  52. while((i++ < 3))
  53. ret += '=';
  54. }
  55. return ret;
  56. }
  57. /**
  58. * @brief Check if a character is a base64 character
  59. *
  60. * @param c The character to check
  61. * @return true if the character is a base64 character, false otherwise
  62. */
  63. inline bool isBase64(unsigned char c) {
  64. return (isalnum(c) || (c == '+') || (c == '/'));
  65. }
  66. /**
  67. * @brief Decode base64 string to binary data
  68. *
  69. * @param encoded_string The base64 encoded string
  70. * @return Decoded binary data
  71. */
  72. inline std::vector<uint8_t> base64Decode(const std::string& encoded_string) {
  73. size_t in_len = encoded_string.size();
  74. size_t i = 0;
  75. size_t j = 0;
  76. int in_ = 0;
  77. uint8_t char_array_4[4], char_array_3[3];
  78. std::vector<uint8_t> ret;
  79. while (in_len-- && (encoded_string[in_] != '=') && isBase64(encoded_string[in_])) {
  80. char_array_4[i++] = encoded_string[in_]; in_++;
  81. if (i == 4) {
  82. for (i = 0; i < 4; i++)
  83. char_array_4[i] = static_cast<uint8_t>(std::string(base64_chars).find(char_array_4[i]));
  84. char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
  85. char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
  86. char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
  87. for (i = 0; i < 3; i++)
  88. ret.push_back(char_array_3[i]);
  89. i = 0;
  90. }
  91. }
  92. if (i) {
  93. for (j = 0; j < i; j++)
  94. char_array_4[j] = static_cast<uint8_t>(std::string(base64_chars).find(char_array_4[j]));
  95. char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
  96. char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
  97. for (j = 0; j < i - 1; j++)
  98. ret.push_back(char_array_3[j]);
  99. }
  100. return ret;
  101. }
  102. /**
  103. * @brief Check if a string ends with a given suffix
  104. *
  105. * @param str The string to check
  106. * @param suffix The suffix to look for
  107. * @return true if str ends with suffix, false otherwise
  108. */
  109. inline bool endsWith(const std::string& str, const std::string& suffix) {
  110. return str.size() >= suffix.size() &&
  111. str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
  112. }
  113. /**
  114. * @brief Check if a string starts with a given prefix
  115. *
  116. * @param str The string to check
  117. * @param prefix The prefix to look for
  118. * @return true if str starts with prefix, false otherwise
  119. */
  120. inline bool startsWith(const std::string& str, const std::string& prefix) {
  121. return str.size() >= prefix.size() &&
  122. str.compare(0, prefix.size(), prefix) == 0;
  123. }
  124. /**
  125. * @brief Convert string to lowercase
  126. *
  127. * @param str The string to convert
  128. * @return Lowercase version of the string
  129. */
  130. inline std::string toLower(const std::string& str) {
  131. std::string result = str;
  132. std::transform(result.begin(), result.end(), result.begin(), ::tolower);
  133. return result;
  134. }
  135. /**
  136. * @brief Convert string to uppercase
  137. *
  138. * @param str The string to convert
  139. * @return Uppercase version of the string
  140. */
  141. inline std::string toUpper(const std::string& str) {
  142. std::string result = str;
  143. std::transform(result.begin(), result.end(), result.begin(), ::toupper);
  144. return result;
  145. }
  146. /**
  147. * @brief Trim whitespace from start of string
  148. *
  149. * @param str The string to trim
  150. * @return Trimmed string
  151. */
  152. inline std::string trimLeft(const std::string& str) {
  153. size_t start = str.find_first_not_of(" \t\n\r\f\v");
  154. return (start == std::string::npos) ? "" : str.substr(start);
  155. }
  156. /**
  157. * @brief Trim whitespace from end of string
  158. *
  159. * @param str The string to trim
  160. * @return Trimmed string
  161. */
  162. inline std::string trimRight(const std::string& str) {
  163. size_t end = str.find_last_not_of(" \t\n\r\f\v");
  164. return (end == std::string::npos) ? "" : str.substr(0, end + 1);
  165. }
  166. /**
  167. * @brief Trim whitespace from both ends of string
  168. *
  169. * @param str The string to trim
  170. * @return Trimmed string
  171. */
  172. inline std::string trim(const std::string& str) {
  173. return trimLeft(trimRight(str));
  174. }
  175. /**
  176. * @brief Split a string by delimiter
  177. *
  178. * @param str The string to split
  179. * @param delimiter The delimiter character
  180. * @return Vector of string parts
  181. */
  182. inline std::vector<std::string> split(const std::string& str, char delimiter) {
  183. std::vector<std::string> result;
  184. std::string current;
  185. for (char c : str) {
  186. if (c == delimiter) {
  187. if (!current.empty()) {
  188. result.push_back(current);
  189. current.clear();
  190. }
  191. } else {
  192. current += c;
  193. }
  194. }
  195. if (!current.empty()) {
  196. result.push_back(current);
  197. }
  198. return result;
  199. }
  200. /**
  201. * @brief Join strings with a delimiter
  202. *
  203. * @param parts The strings to join
  204. * @param delimiter The delimiter to use
  205. * @return Joined string
  206. */
  207. inline std::string join(const std::vector<std::string>& parts, const std::string& delimiter) {
  208. if (parts.empty()) return "";
  209. std::string result = parts[0];
  210. for (size_t i = 1; i < parts.size(); i++) {
  211. result += delimiter + parts[i];
  212. }
  213. return result;
  214. }
  215. /**
  216. * @brief URL decode a string
  217. *
  218. * @param encoded The URL-encoded string
  219. * @return Decoded string
  220. */
  221. inline std::string urlDecode(const std::string& encoded) {
  222. std::string decoded;
  223. for (size_t i = 0; i < encoded.length(); ++i) {
  224. if (encoded[i] == '%' && i + 2 < encoded.length()) {
  225. // Convert %XX to character
  226. int hexValue;
  227. std::istringstream hexStream(encoded.substr(i + 1, 2));
  228. if (hexStream >> std::hex >> hexValue) {
  229. decoded += static_cast<char>(hexValue);
  230. i += 2;
  231. } else {
  232. decoded += encoded[i];
  233. }
  234. } else if (encoded[i] == '+') {
  235. // Convert '+' to space
  236. decoded += ' ';
  237. } else {
  238. decoded += encoded[i];
  239. }
  240. }
  241. return decoded;
  242. }
  243. /**
  244. * @brief Check if file is an image based on extension
  245. *
  246. * @param filename The filename to check
  247. * @return true if file is an image, false otherwise
  248. */
  249. inline bool isImageFile(const std::string& filename) {
  250. std::string lowerFilename = toLower(filename);
  251. return endsWith(lowerFilename, ".png") ||
  252. endsWith(lowerFilename, ".jpg") ||
  253. endsWith(lowerFilename, ".jpeg") ||
  254. endsWith(lowerFilename, ".gif") ||
  255. endsWith(lowerFilename, ".webp") ||
  256. endsWith(lowerFilename, ".bmp") ||
  257. endsWith(lowerFilename, ".tiff") ||
  258. endsWith(lowerFilename, ".tif");
  259. }
  260. } // namespace Utils
  261. #endif // UTILS_H