#include "stringutil.hpp" #include #include #include #include #include #include #include namespace { // Size limit for formatted strings. constexpr size_t VA_BUFFER_SIZE = 0x1000; // These characters get replaced by spaces when path is sanitized. constexpr std::array FORBIDDEN_PATH_CHARACTERS = {L',', L'/', L'\\', L'<', L'>', L':', L'"', L'|', L'?', L'*', L'™', L'©', L'®'}; } // namespace std::string stringutil::get_formatted_string(const char *format, ...) { std::array vaBuffer = {0}; std::va_list vaList; va_start(vaList, format); vsnprintf(vaBuffer.data(), VA_BUFFER_SIZE, format, vaList); va_end(vaList); return std::string(vaBuffer.data()); } void stringutil::replace_in_string(std::string &target, std::string_view find, std::string_view replace) { const size_t findLength = find.length(); const size_t replaceLength = replace.length(); for (size_t i = target.find(find); i != target.npos; i = target.find(find, i + replaceLength)) { target.replace(i, findLength, replace); } } void stringutil::strip_character(char c, std::string &target) { for (size_t i = target.find_first_of(c); i != target.npos; i = target.find_first_of(c, i)) { target.erase(target.begin() + i); } } bool stringutil::sanitize_string_for_path(const char *stringIn, char *stringOut, size_t stringOutSize) { uint32_t codepoint{}; const size_t length = std::char_traits::length(stringIn); for (size_t i = 0, offset = 0; i < length;) { const uint8_t *point = reinterpret_cast(&stringIn[i]); const ssize_t count = decode_utf8(&codepoint, point); const bool countCheck = count <= 0 || i + count >= stringOutSize; const bool codeCheck = codepoint < 0x20 || codepoint > 0x7E; if (countCheck) { break; } else if (codeCheck) { return false; } const bool forbidden = std::find(FORBIDDEN_PATH_CHARACTERS.begin(), FORBIDDEN_PATH_CHARACTERS.end(), codepoint) != FORBIDDEN_PATH_CHARACTERS.end(); if (forbidden) { stringOut[offset++] = 0x20; } else if (codepoint == L'é') { stringOut[offset++] = 'e'; } else { std::memcpy(&stringOut[offset], &stringIn[i], static_cast(count)); offset += count; } i += count; } const int outLength = std::char_traits::length(stringOut) - 1; for (int i = outLength; i > 0 && (stringOut[i] == ' ' || stringOut[i] == '.'); --i) { stringOut[i] = '\0'; } return true; } std::string stringutil::get_date_string(stringutil::DateFormat format) { char stringBuffer[0x80] = {0}; std::time_t timer; std::time(&timer); std::tm *localTime = std::localtime(&timer); switch (format) { case stringutil::DateFormat::YearMonthDay: { std::strftime(stringBuffer, 0x80, "%Y-%m-%d_%H-%M-%S", localTime); } break; case stringutil::DateFormat::YearDayMonth: { std::strftime(stringBuffer, 0x80, "%Y-%d-%m_%H-%M-%S", localTime); } break; } return std::string(stringBuffer); }