initial commit
Some checks failed
sgraves/cpp-build-system_mac/pipeline/head There was a failure building this commit
sgraves/cpp-build-system/pipeline/head There was a failure building this commit

This commit is contained in:
2025-10-17 07:44:16 -05:00
parent 933c973c79
commit 92e3e495ce
1099 changed files with 102722 additions and 0 deletions

View File

@@ -0,0 +1,61 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_ALL_HPP_
#define FIFTHGRID_INCLUDE_UTILS_ALL_HPP_
#include "utils/config.hpp"
#include "utils/atomic.hpp"
#include "utils/base64.hpp"
#include "utils/collection.hpp"
#if defined(_WIN32)
#include "utils/com_init_wrapper.hpp"
#endif // defined(_WIN32)
#include "utils/common.hpp"
#if defined(PROJECT_ENABLE_SQLITE)
#include "utils/db/sqlite/db_common.hpp"
#include "utils/db/sqlite/db_delete.hpp"
#include "utils/db/sqlite/db_insert.hpp"
#include "utils/db/sqlite/db_select.hpp"
#include "utils/db/sqlite/db_update.hpp"
#endif // defined(PROJECT_ENABLE_SQLITE)
#if defined(PROJECT_ENABLE_LIBSODIUM)
#include "utils/encrypting_reader.hpp"
#include "utils/encryption.hpp"
#endif // defined(PROJECT_ENABLE_LIBSODIUM)
#include "utils/error.hpp"
#include "utils/file.hpp"
#if defined(PROJECT_ENABLE_LIBSODIUM)
#include "utils/hash.hpp"
#endif // defined(PROJECT_ENABLE_LIBSODIUM)
#include "utils/path.hpp"
#include "utils/string.hpp"
#include "utils/time.hpp"
#include "utils/ttl_cache.hpp"
#if !defined(_WIN32)
#include "utils/unix.hpp"
#endif // !defined(_WIN32)
#if defined(_WIN32)
#include "utils/windows.hpp"
#endif // defined(_WIN32)
#endif // FIFTHGRID_INCLUDE_UTILS_ALL_HPP_

View File

@@ -0,0 +1,118 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_ATOMIC_HPP_
#define FIFTHGRID_INCLUDE_UTILS_ATOMIC_HPP_
#include "utils/config.hpp"
namespace fifthgrid::utils {
template <typename data_t> class atomic final {
public:
atomic() : mtx_(std::make_shared<std::mutex>()) {}
atomic(const atomic &at_data)
: data_(at_data.load()), mtx_(std::make_shared<std::mutex>()) {}
atomic(data_t data)
: data_(std::move(data)), mtx_(std::make_shared<std::mutex>()) {}
atomic(atomic &&) = default;
~atomic() = default;
private:
data_t data_;
std::shared_ptr<std::mutex> mtx_;
public:
[[nodiscard]] auto load() const -> data_t {
mutex_lock lock(*mtx_);
return data_;
}
auto store(data_t data) -> data_t {
mutex_lock lock(*mtx_);
data_ = std::move(data);
return data_;
}
auto operator=(const atomic &at_data) -> atomic & {
if (&at_data == this) {
return *this;
}
store(at_data.load());
return *this;
}
auto operator=(atomic &&) -> atomic & = default;
auto operator=(data_t data) -> atomic & {
if (&data == &data_) {
return *this;
}
store(std::move(data));
return *this;
}
[[nodiscard]] auto operator==(const atomic &at_data) const -> bool {
if (&at_data == this) {
return true;
}
mutex_lock lock(*mtx_);
return at_data.load() == data_;
}
[[nodiscard]] auto operator==(const data_t &data) const -> bool {
if (&data == &data_) {
return true;
}
mutex_lock lock(*mtx_);
return data == data_;
}
[[nodiscard]] auto operator!=(const atomic &at_data) const -> bool {
if (&at_data == this) {
return false;
}
mutex_lock lock(*mtx_);
return at_data.load() != data_;
}
[[nodiscard]] auto operator!=(const data_t &data) const -> bool {
if (&data == &data_) {
return false;
}
mutex_lock lock(*mtx_);
return data != data_;
}
[[nodiscard]] operator data_t() const { return load(); }
};
} // namespace fifthgrid::utils
#endif // FIFTHGRID_INCLUDE_UTILS_ATOMIC_HPP_

View File

@@ -0,0 +1,325 @@
// NOLINTBEGIN
#ifndef MACARON_BASE64_H_
#define MACARON_BASE64_H_
/**
* The MIT License (MIT)
* Copyright (c) 2016 tomykaira
* Copyright (c) 2025 scott.e.graves@protonmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunknown-warning-option"
#endif
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
#pragma GCC diagnostic ignored "-Wold-style-cast"
#pragma GCC diagnostic ignored "-Wuseless-cast"
#endif
#include <array>
#include <stdexcept>
#include <string>
#include <string_view>
#include <vector>
namespace macaron::Base64 {
// --- Alphabets --------------------------------------------------------------
static constexpr std::array<unsigned char, 64U> kStdAlphabet{
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/',
};
static constexpr std::array<unsigned char, 64U> kUrlAlphabet{
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_',
};
// Decoding table that accepts BOTH standard and URL-safe alphabets.
static constexpr std::array<unsigned char, 256U> kDecodingTable = [] {
std::array<unsigned char, 256U> t{};
t.fill(64U);
// 'A'-'Z'
for (unsigned char c = 'A'; c <= 'Z'; ++c)
t[c] = static_cast<unsigned char>(c - 'A');
// 'a'-'z'
for (unsigned char c = 'a'; c <= 'z'; ++c)
t[c] = static_cast<unsigned char>(26 + c - 'a');
// '0'-'9'
for (unsigned char c = '0'; c <= '9'; ++c)
t[c] = static_cast<unsigned char>(52 + c - '0');
// Standard extras
t[static_cast<unsigned char>('+')] = 62U;
t[static_cast<unsigned char>('/')] = 63U;
// URL-safe extras
t[static_cast<unsigned char>('-')] = 62U;
t[static_cast<unsigned char>('_')] = 63U;
return t;
}();
// --- Encoding ---------------------------------------------------------------
/**
* Encode to Base64.
* @param data pointer to bytes
* @param len number of bytes
* @param url_safe if true, use URL-safe alphabet ("-","_") instead of ("+","/")
* @param pad if true, add '=' padding; if false, omit padding (RFC 4648
* §5)
*/
static std::string Encode(const unsigned char *data, std::size_t len,
bool url_safe = false, bool pad = true) {
const auto &alpha = url_safe ? kUrlAlphabet : kStdAlphabet;
std::string out;
if (len == 0U) {
return out;
}
const std::size_t full_blocks = len / 3U;
const std::size_t rem = len % 3U;
std::size_t out_len{};
if (pad) {
out_len = 4U * ((len + 2U) / 3U);
} else {
// Unpadded length per RFC 4648 §5
out_len = 4U * full_blocks + (rem == 0U ? 0U : (rem == 1U ? 2U : 3U));
}
out.assign(out_len, '\0');
auto *p = reinterpret_cast<unsigned char *>(out.data());
std::size_t i = 0;
// Full 3-byte blocks -> 4 chars
for (; i + 2U < len; i += 3U) {
const unsigned char b0 = data[i + 0U];
const unsigned char b1 = data[i + 1U];
const unsigned char b2 = data[i + 2U];
*p++ = alpha[(b0 >> 2U) & 0x3F];
*p++ = alpha[((b0 & 0x03U) << 4U) | ((b1 >> 4U) & 0x0FU)];
*p++ = alpha[((b1 & 0x0FU) << 2U) | ((b2 >> 6U) & 0x03U)];
*p++ = alpha[b2 & 0x3FU];
}
// Remainder
if (rem == 1U) {
const unsigned char b0 = data[i];
*p++ = alpha[(b0 >> 2U) & 0x3F];
*p++ = alpha[(b0 & 0x03U) << 4U];
if (pad) {
*p++ = '=';
*p++ = '=';
}
} else if (rem == 2U) {
const unsigned char b0 = data[i + 0U];
const unsigned char b1 = data[i + 1U];
*p++ = alpha[(b0 >> 2U) & 0x3F];
*p++ = alpha[((b0 & 0x03U) << 4U) | ((b1 >> 4U) & 0x0FU)];
*p++ = alpha[(b1 & 0x0FU) << 2U];
if (pad) {
*p++ = '=';
}
}
return out;
}
[[maybe_unused]] static std::string
Encode(std::string_view data, bool url_safe = false, bool pad = true) {
return Encode(reinterpret_cast<const unsigned char *>(data.data()),
data.size(), url_safe, pad);
}
[[maybe_unused]] static std::string
EncodeUrlSafe(const unsigned char *data, std::size_t len, bool pad = false) {
return Encode(data, len, /*url_safe=*/true, /*pad=*/pad);
}
[[maybe_unused]] static std::string EncodeUrlSafe(std::string_view data,
bool pad = false) {
return Encode(reinterpret_cast<const unsigned char *>(data.data()),
data.size(), /*url_safe=*/true, /*pad=*/pad);
}
// --- Decoding ---------------------------------------------------------------
/**
* Decode standard OR URL-safe Base64.
* Accepts inputs with or without '=' padding.
* Throws std::runtime_error on malformed input.
*/
[[maybe_unused]] static std::vector<unsigned char>
Decode(std::string_view input) {
std::vector<unsigned char> out;
if (input.empty()) {
return out;
}
std::size_t inLen = input.size();
std::size_t rem = inLen % 4U;
// padded if multiple of 4 and last char is '='
bool hasPadding = (rem == 0U) && (inLen >= 4U) && (input[inLen - 1U] == '=');
// compute output length
std::size_t outLen{};
if (hasPadding) {
outLen = (inLen / 4U) * 3U;
if (input[inLen - 1U] == '=')
outLen--;
if (input[inLen - 2U] == '=')
outLen--;
} else {
if (rem == 1U) {
throw std::runtime_error("Invalid Base64 length (mod 4 == 1)");
}
outLen = (inLen / 4U) * 3U + (rem == 0U ? 0U : (rem == 2U ? 1U : 2U));
}
out.resize(outLen);
auto readVal = [](unsigned char c) -> unsigned char {
unsigned char v = kDecodingTable[c];
if (v == 64U) {
throw std::runtime_error("Invalid Base64 character");
}
return v;
};
std::size_t i = 0U;
std::size_t j = 0U;
// process all full unpadded quartets
std::size_t lastFull =
hasPadding ? (inLen - 4U) : (rem == 0U ? inLen : (inLen - rem));
while (i + 4U <= lastFull) {
unsigned char a = readVal(static_cast<unsigned char>(input[i + 0U]));
unsigned char b = readVal(static_cast<unsigned char>(input[i + 1U]));
unsigned char c = readVal(static_cast<unsigned char>(input[i + 2U]));
unsigned char d = readVal(static_cast<unsigned char>(input[i + 3U]));
i += 4U;
std::uint32_t triple = (static_cast<std::uint32_t>(a) << 18U) |
(static_cast<std::uint32_t>(b) << 12U) |
(static_cast<std::uint32_t>(c) << 6U) |
(static_cast<std::uint32_t>(d));
if (j < outLen)
out[j++] = static_cast<unsigned char>((triple >> 16U) & 0xFFU);
if (j < outLen)
out[j++] = static_cast<unsigned char>((triple >> 8U) & 0xFFU);
if (j < outLen)
out[j++] = static_cast<unsigned char>(triple & 0xFFU);
}
// tail: padded quartet or unpadded remainder
if (i < inLen) {
std::size_t left = inLen - i;
if (left == 4U) {
bool thirdIsPad = (input[i + 2U] == '=');
bool fourthIsPad = (input[i + 3U] == '=');
// '=' is never allowed in positions 1 or 2 of any quartet
if (input[i + 0U] == '=' || input[i + 1U] == '=') {
throw std::runtime_error("Invalid Base64 padding placement");
}
unsigned char a = readVal(static_cast<unsigned char>(input[i + 0U]));
unsigned char b = readVal(static_cast<unsigned char>(input[i + 1U]));
unsigned char c = 0U;
unsigned char d = 0U;
if (!thirdIsPad) {
c = readVal(static_cast<unsigned char>(input[i + 2U]));
if (!fourthIsPad) {
d = readVal(static_cast<unsigned char>(input[i + 3U]));
}
} else {
// if the 3rd is '=', the 4th must also be '='
if (!fourthIsPad) {
throw std::runtime_error("Invalid Base64 padding placement");
}
}
i += 4U;
std::uint32_t triple = (static_cast<std::uint32_t>(a) << 18U) |
(static_cast<std::uint32_t>(b) << 12U) |
(static_cast<std::uint32_t>(c) << 6U) |
(static_cast<std::uint32_t>(d));
if (j < outLen)
out[j++] = static_cast<unsigned char>((triple >> 16U) & 0xFFU);
if (!thirdIsPad && j < outLen)
out[j++] = static_cast<unsigned char>((triple >> 8U) & 0xFFU);
if (!fourthIsPad && !thirdIsPad && j < outLen)
out[j++] = static_cast<unsigned char>(triple & 0xFFU);
} else if (left == 2U || left == 3U) {
unsigned char a = readVal(static_cast<unsigned char>(input[i + 0U]));
unsigned char b = readVal(static_cast<unsigned char>(input[i + 1U]));
unsigned char c = (left == 3U)
? readVal(static_cast<unsigned char>(input[i + 2U]))
: 0U;
i += left;
std::uint32_t triple = (static_cast<std::uint32_t>(a) << 18U) |
(static_cast<std::uint32_t>(b) << 12U) |
(static_cast<std::uint32_t>(c) << 6U);
if (j < outLen)
out[j++] = static_cast<unsigned char>((triple >> 16U) & 0xFFU);
if (left == 3U && j < outLen)
out[j++] = static_cast<unsigned char>((triple >> 8U) & 0xFFU);
} else {
throw std::runtime_error("Invalid Base64 length (mod 4 == 1)");
}
}
return out;
}
} // namespace macaron::Base64
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#endif /* MACARON_BASE64_H_ */
// NOLINTEND

View File

@@ -0,0 +1,178 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_COLLECTION_HPP_
#define FIFTHGRID_INCLUDE_UTILS_COLLECTION_HPP_
#include "utils/config.hpp"
#include "utils/error.hpp"
#include "utils/string.hpp"
namespace fifthgrid::utils::collection {
template <typename col_t>
[[nodiscard]] inline auto excludes(const col_t &collection,
const typename col_t::value_type &val)
-> bool;
template <typename col_t>
[[nodiscard]] inline auto includes(const col_t &collection,
const typename col_t::value_type &val)
-> bool;
template <typename val_t>
[[nodiscard]] inline auto from_hex_string(std::string_view str, val_t &val)
-> bool;
template <typename val_t>
[[nodiscard]] inline auto from_hex_string(std::wstring_view str, val_t &val)
-> bool;
template <typename col_t>
inline auto remove_element(col_t &collection,
const typename col_t::value_type &value) -> col_t &;
template <typename col_t>
[[nodiscard]] inline auto to_hex_string(const col_t &collection) -> std::string;
template <typename col_t>
[[nodiscard]] inline auto to_hex_wstring(const col_t &collection)
-> std::wstring;
template <typename col_t>
inline auto excludes(const col_t &collection,
const typename col_t::value_type &val) -> bool {
return std::find(collection.begin(), collection.end(), val) ==
collection.end();
}
template <typename col_t>
inline auto includes(const col_t &collection,
const typename col_t::value_type &val) -> bool {
return std::find(collection.begin(), collection.end(), val) !=
collection.end();
}
template <typename val_t>
[[nodiscard]] inline auto from_hex_string_t(std::string_view str, val_t &val)
-> bool {
FIFTHGRID_USES_FUNCTION_NAME();
static constexpr auto base16{16};
try {
val.clear();
std::string fmt_val{str};
utils::string::trim(fmt_val);
if (fmt_val.empty()) {
return true;
}
fmt_val = utils::string::to_lower(fmt_val);
if (utils::string::begins_with(fmt_val, "0x")) {
fmt_val = fmt_val.substr(2U);
}
if (fmt_val.empty()) {
throw utils::error::create_exception(function_name,
{
"hex string is invalid",
str,
});
}
if (fmt_val.length() % 2U) {
fmt_val = '0' + fmt_val;
}
auto iter = std::find_if_not(
fmt_val.begin(), fmt_val.end(), [](auto cur_char) -> bool {
auto check = static_cast<std::uint32_t>(cur_char);
return ((check >= 48U && check <= 57U) ||
(check >= 97U && check <= 102U));
});
if (iter != fmt_val.end()) {
auto invalid_idx{std::distance(fmt_val.begin(), iter)};
throw std::range_error(utils::error::create_error_message({
function_name,
"invalid character in hex string",
std::to_string(invalid_idx),
std::string(1U, str.at(invalid_idx)),
str,
}));
}
val.resize(fmt_val.length() / 2U);
for (std::size_t idx = 0U; idx < fmt_val.length(); idx += 2U) {
val.at(idx / 2U) = static_cast<typename val_t::value_type>(
std::strtoul(fmt_val.substr(idx, 2U).c_str(), nullptr, base16));
}
return true;
} catch (const std::exception &e) {
utils::error::handle_exception(function_name, e);
} catch (...) {
utils::error::handle_exception(function_name);
}
val.clear();
return false;
}
template <typename val_t>
inline auto from_hex_string(std::string_view str, val_t &val) -> bool {
return from_hex_string_t<val_t>(str, val);
}
template <typename val_t>
inline auto from_hex_string(std::wstring_view str, val_t &val) -> bool {
return from_hex_string_t<val_t>(utils::string::to_utf8(str), val);
}
template <typename col_t>
inline auto remove_element(col_t &collection,
const typename col_t::value_type &value) -> col_t & {
collection.erase(std::remove(collection.begin(), collection.end(), value),
collection.end());
return collection;
}
template <typename col_t>
inline auto to_hex_string(const col_t &collection) -> std::string {
static_assert(sizeof(typename col_t::value_type) == 1U,
"value_type must be 1 byte in size");
static constexpr auto mask{0xFF};
std::stringstream stream{};
for (auto &&val : collection) {
stream << std::setfill('0') << std::setw(2) << std::hex
<< (static_cast<std::uint32_t>(val) & mask);
}
return stream.str();
}
template <typename col_t>
inline auto to_hex_wstring(const col_t &collection) -> std::wstring {
return utils::string::from_utf8(to_hex_string<col_t>(collection));
}
} // namespace fifthgrid::utils::collection
#endif // FIFTHGRID_INCLUDE_UTILS_COLLECTION_HPP_

View File

@@ -0,0 +1,54 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_COM_INIT_WRAPPER_HPP_
#define FIFTHGRID_INCLUDE_UTILS_COM_INIT_WRAPPER_HPP_
#if defined(_WIN32)
#include "utils/config.hpp"
namespace fifthgrid::utils {
struct com_init_wrapper final {
com_init_wrapper()
: initialized_(
SUCCEEDED(::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED))) {}
com_init_wrapper(const com_init_wrapper &) = delete;
com_init_wrapper(com_init_wrapper &&) = delete;
~com_init_wrapper() {
if (initialized_) {
::CoUninitialize();
}
}
auto operator=(const com_init_wrapper &) -> com_init_wrapper & = delete;
auto operator=(com_init_wrapper &&) -> com_init_wrapper & = delete;
[[nodiscard]] auto is_initialized() const -> bool { return initialized_; }
private:
BOOL initialized_{};
};
} // namespace fifthgrid::utils
#endif // defined(_WIN32)
#endif // FIFTHGRID_INCLUDE_UTILS_COM_INIT_WRAPPER_HPP_

View File

@@ -0,0 +1,146 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_COMMON_HPP_
#define FIFTHGRID_INCLUDE_UTILS_COMMON_HPP_
#include "utils/config.hpp"
namespace fifthgrid::utils {
struct result final {
std::string function_name;
bool ok{true};
std::string reason{"success"};
[[nodiscard]] operator bool() const { return ok; }
};
using retryable_action_t = std::function<bool()>;
[[nodiscard]] constexpr auto calculate_read_size(std::uint64_t total_size,
std::size_t read_size,
std::uint64_t offset)
-> std::size_t {
return static_cast<std::size_t>(
((offset + read_size) > total_size)
? ((offset < total_size) ? total_size - offset : 0U)
: read_size);
}
[[nodiscard]] auto compare_version_strings(std::string version1,
std::string version2)
-> std::int32_t;
[[nodiscard]] auto compare_version_strings(std::wstring_view version1,
std::wstring_view version2)
-> std::int32_t;
#if defined(PROJECT_ENABLE_STDUUID)
[[nodiscard]] auto create_uuid_string() -> std::string;
[[nodiscard]] auto create_uuid_wstring() -> std::wstring;
#endif // defined(PROJECT_ENABLE_STDUUID)
template <typename result_t, typename data_t>
[[nodiscard]] inline constexpr auto divide_with_ceiling(result_t numerator,
data_t denominator)
-> result_t;
template <typename data_t>
[[nodiscard]] inline auto generate_random_between(data_t begin, data_t end)
-> data_t;
[[nodiscard]] auto generate_random_string(std::size_t length) -> std::string;
[[nodiscard]] auto generate_random_wstring(std::size_t length) -> std::wstring;
#if defined(PROJECT_ENABLE_LIBSODIUM)
template <typename data_t>
[[nodiscard]] inline auto generate_secure_random() -> data_t;
template <typename data_t>
[[nodiscard]] inline auto generate_secure_random(std::size_t size) -> data_t;
#endif // defined(PROJECT_ENABLE_LIBSODIUM)
[[nodiscard]] auto get_environment_variable(std::string_view variable)
-> std::string;
[[nodiscard]] auto get_environment_variable(std::wstring_view variable)
-> std::wstring;
#if defined(PROJECT_ENABLE_BOOST)
[[nodiscard]] auto get_next_available_port(std::uint16_t first_port,
std::uint16_t &available_port)
-> bool;
#endif // defined(PROJECT_ENABLE_BOOST)
[[nodiscard]] auto retry_action(
retryable_action_t action, std::size_t retry_count = 200U,
std::chrono::milliseconds retry_wait = std::chrono::milliseconds(10))
-> bool;
template <typename result_t, typename data_t>
inline constexpr auto divide_with_ceiling(result_t numerator,
data_t denominator) -> result_t {
static_assert(std::is_integral_v<std::remove_cv_t<data_t>>,
"denominator must be an integral type");
return denominator == 0
? 0
: (numerator / denominator) + (numerator % denominator != 0);
}
template <typename data_t>
inline auto generate_random_between(data_t begin, data_t end) -> data_t {
static_assert(std::is_integral_v<std::remove_cv_t<data_t>>,
"data_t must be an integral type");
if (end <= begin) {
throw std::range_error("end must be greater than begin");
}
thread_local std::mt19937 gen(
static_cast<unsigned long>(std::time(nullptr) ^ std::random_device{}()));
std::uniform_int_distribution<data_t> dis(begin, end);
return dis(gen);
}
#if defined(PROJECT_ENABLE_LIBSODIUM)
template <typename data_t> inline auto generate_secure_random() -> data_t {
static_assert(!is_collection<std::decay_t<data_t>>::value,
"data_t is a vector or collection");
data_t ret{};
randombytes_buf(&ret, sizeof(ret));
return ret;
}
template <typename data_t>
inline auto generate_secure_random(std::size_t size) -> data_t {
static_assert(is_collection<std::decay_t<data_t>>::value,
"data_t is not a vector or collection");
data_t ret;
ret.resize(size);
randombytes_buf(ret.data(), ret.size() * sizeof(typename data_t::value_type));
return ret;
}
#endif // defined(PROJECT_ENABLE_LIBSODIUM)
} // namespace fifthgrid::utils
#endif // FIFTHGRID_INCLUDE_UTILS_COMMON_HPP_

View File

@@ -0,0 +1,496 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_CONFIG_HPP_
#define FIFTHGRID_INCLUDE_UTILS_CONFIG_HPP_
#define NOMINMAX
#if defined(_WIN32)
#define WINVER 0x0A00
#define _WIN32_WINNT WINVER
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#if defined(PROJECT_ENABLE_WINFSP)
#include <sddl.h>
#endif // defined(PROJECT_ENABLE_WINFSP)
#include <direct.h>
#if !defined(__cplusplus)
#include <errno.h>
#endif // !defined(__cplusplus)
#include <fcntl.h>
#include <io.h>
#include <iphlpapi.h>
#include <objbase.h>
#include <psapi.h>
#include <rpc.h>
#include <share.h>
#include <shellapi.h>
#include <shlobj.h>
#include <shlwapi.h>
#if !defined(__cplusplus)
#include <stdio.h>
#endif // !defined(__cplusplus)
#include <sys/stat.h>
#include <sys/types.h>
#if !defined(__cplusplus)
#include <time.h>
#endif // !defined(__cplusplus)
#else // !defined(_WIN32)
#include <arpa/inet.h>
#include <dirent.h>
#include <fcntl.h>
#include <grp.h>
#include <libgen.h>
#include <netinet/in.h>
#include <pwd.h>
#include <sys/file.h>
#include <sys/socket.h>
#if defined(__LFS64__)
#include <sys/stat64.h>
#else // !defined(__LFS64__)
#include <sys/stat.h>
#endif // defined(__LFS64__)
#if defined(__linux__)
#include <sys/statfs.h>
#endif // defined(HAS_SETXATTR)
#if defined(HAS_SETXATTR)
#include <sys/types.h>
#include <sys/xattr.h>
#endif // defined(HAS_SETXATTR)
#if defined(__APPLE__)
#include <libproc.h>
#include <sys/attr.h>
#include <sys/mount.h>
#include <sys/statvfs.h>
#include <sys/vnode.h>
#endif // defined(__APPLE__)
#include <unistd.h>
#endif // defined(_WIN32)
#if defined(HAS_WORDEXP_H)
#include <wordexp.h>
#endif // defined(HAS_WORDEXP_H)
#if defined(__cplusplus)
#include <algorithm>
#include <array>
#include <atomic>
#include <bit>
#include <cerrno>
#include <chrono>
#include <climits>
#include <condition_variable>
#include <csignal>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <filesystem>
#include <fstream>
#include <functional>
#include <future>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <limits>
#include <locale>
#include <map>
#include <memory>
#include <mutex>
#include <numeric>
#include <optional>
#include <ostream>
#include <queue>
#include <random>
#include <ranges>
#include <regex>
#include <span>
#include <sstream>
#include <stdexcept>
#include <string>
#include <string_view>
#include <thread>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <variant>
#include <vector>
#include <version>
#endif // defined(__cplusplus)
#include <unicode/uchar.h>
#include <unicode/utf.h>
#if defined(PROJECT_ENABLE_CURL)
#include "curl/curl.h"
#include "curl/multi.h"
#endif // defined(PROJECT_ENABLE_CURL)
#if defined(PROJECT_ENABLE_FUSE)
#if FUSE_USE_VERSION >= 30
#include <fuse.h>
#include <fuse_lowlevel.h>
#else
#include <fuse/fuse.h>
#endif
#endif // defined(PROJECT_ENABLE_FUSE)
#if defined(PROJECT_ENABLE_FZF)
#if defined(__cplusplus)
extern "C" {
#endif // defined(__cplusplus)
#include "fzf.h"
#if defined(__cplusplus)
}
#endif // defined(__cplusplus)
#endif // defined(PROJECT_ENABLE_FZF)
#if defined(PROJECT_ENABLE_OPENSSL)
#include "openssl/ssl.h"
#endif // defined(PROJECT_ENABLE_OPENSSL)
#if defined(PROJECT_ENABLE_LIBDSM)
#if defined(__cplusplus)
extern "C" {
#endif // defined(__cplusplus)
#include "bdsm/bdsm.h"
#if defined(__cplusplus)
}
struct netbios_ns_deleter final {
void operator()(netbios_ns *ns) const {
if (ns != nullptr) {
netbios_ns_destroy(ns);
}
}
};
using netbios_ns_t = std::unique_ptr<netbios_ns, netbios_ns_deleter>;
inline const auto smb_session_deleter = [](smb_session *session) {
if (session != nullptr) {
smb_session_destroy(session);
}
};
using smb_session_t = std::shared_ptr<smb_session>;
struct smb_stat_deleter final {
void operator()(smb_stat st) const {
if (st != nullptr) {
smb_stat_destroy(st);
}
}
};
using smb_stat_t = std::unique_ptr<smb_file, smb_stat_deleter>;
struct smb_stat_list_deleter final {
void operator()(smb_file *list) const {
if (list != nullptr) {
smb_stat_list_destroy(list);
}
}
};
using smb_stat_list_t = std::unique_ptr<smb_file, smb_stat_list_deleter>;
#endif // defined(__cplusplus)
#endif // defined(PROJECT_ENABLE_LIBDSM)
#if defined(PROJECT_ENABLE_LIBEVENT)
#include "event2/buffer.h"
#include "event2/bufferevent.h"
#include "event2/listener.h"
#include "event2/thread.h"
#include "event2/util.h"
#endif // defined(PROJECT_ENABLE_LIBEVENT)
#if defined(PROJECT_ENABLE_LIBSODIUM)
#include "sodium.h"
#endif // defined(PROJECT_ENABLE_LIBSODIUM)
#if defined(PROJECT_ENABLE_SDL)
#include "SDL.h"
#include "SDL_gamecontroller.h"
#include "SDL_joystick.h"
#endif // defined(PROJECT_ENABLE_SDL)
#if defined(PROJECT_ENABLE_SQLITE)
#include "sqlite3.h"
#endif // defined(PROJECT_ENABLE_SQLITE)
#if defined(PROJECT_ENABLE_VLC)
#include <vlc/vlc.h>
#if defined(__cplusplus)
[[nodiscard]] inline auto get_libvlc_error_msg() -> std::string {
const auto *msg = libvlc_errmsg();
return msg == nullptr ? "none" : msg;
}
struct vlc_deleter final {
void operator()(libvlc_instance_t *inst) const {
if (inst != nullptr) {
libvlc_release(inst);
}
}
};
using vlc_t = std::unique_ptr<libvlc_instance_t, vlc_deleter>;
struct vlc_media_deleter final {
void operator()(libvlc_media_t *media) const {
if (media != nullptr) {
libvlc_media_release(media);
}
}
};
using vlc_media_t = std::unique_ptr<libvlc_media_t, vlc_media_deleter>;
struct vlc_media_list_deleter final {
void operator()(libvlc_media_list_t *media_list) const {
if (media_list != nullptr) {
libvlc_media_list_release(media_list);
}
}
};
using vlc_media_list_t =
std::unique_ptr<libvlc_media_list_t, vlc_media_list_deleter>;
struct vlc_string_deleter final {
void operator()(char *str) const {
if (str != nullptr) {
libvlc_free(str);
}
}
};
using vlc_string_t = std::unique_ptr<char, vlc_string_deleter>;
#endif // defined(__cplusplus)
#endif // defined(PROJECT_ENABLE_VLC)
#if !defined(fstat64)
#define fstat64 fstat
#endif // !defined(fstat64)
#if !defined(pread64)
#define pread64 pread
#endif // !defined(pread64)
#if !defined(pwrite64)
#define pwrite64 pwrite
#endif // !defined(pwrite64)
#if !defined(stat64)
#define stat64 stat
#endif // !defined(stat64)
#if !defined(statfs64)
#define statfs64 statfs
#endif // !defined(statfs64)
#if !defined(off64_t)
#define off64_t std::size_t
#endif // !defined(off64_t)
#if !defined(__off64_t)
#define __off64_t off64_t
#endif // !defined(__off64_t)
#if defined(__cplusplus)
#if defined(PROJECT_ENABLE_BOOST)
#include "boost/archive/text_iarchive.hpp"
#include "boost/archive/text_oarchive.hpp"
#include "boost/asio.hpp"
#include "boost/asio/io_context.hpp"
#include "boost/bind/bind.hpp"
#include "boost/dynamic_bitset.hpp"
#include "boost/dynamic_bitset/serialization.hpp"
#include "boost/endian/conversion.hpp"
#include "boost/integer.hpp"
#include "boost/interprocess/sync/named_mutex.hpp"
#include "boost/interprocess/sync/scoped_lock.hpp"
#include "boost/multiprecision/cpp_dec_float.hpp"
#include "boost/multiprecision/cpp_int.hpp"
#include "boost/serialization/vector.hpp"
#endif // defined(PROJECT_ENABLE_BOOST)
#if defined(PROJECT_ENABLE_CLI11)
#if defined(PROJECT_IS_MINGW) && !defined(PROJECT_IS_MINGW_UNIX)
#include "CLI/CLI.hpp"
#else // !defined(PROJECT_IS_MINGW) || defined(PROJECT_IS_MINGW_UNIX)
#include "CLI11.hpp"
#endif // defined(PROJECT_IS_MINGW) && !defined(PROJECT_IS_MINGW_UNIX)
#endif // defined(PROJECT_ENABLE_CLI11)
#if defined(PROJECT_ENABLE_CPP_HTTPLIB)
#include "httplib.h"
#endif // defined(PROJECT_ENABLE_JSON)
#if defined(PROJECT_ENABLE_DTL)
#include "dtl/dtl.hpp"
#endif // defined(PROJECT_ENABLE_DTL)
#if defined(PROJECT_ENABLE_JSON)
#include "json.hpp"
#endif // defined(PROJECT_ENABLE_JSON)
#if defined(PROJECT_ENABLE_NANA)
#include "nana/gui.hpp"
#include "nana/gui/timer.hpp"
#include "nana/gui/widgets/button.hpp"
#include "nana/gui/widgets/combox.hpp"
#include "nana/gui/widgets/group.hpp"
#include "nana/gui/widgets/label.hpp"
#include "nana/gui/widgets/panel.hpp"
#include "nana/gui/widgets/picture.hpp"
#include "nana/gui/widgets/tabbar.hpp"
#endif // defined(PROJECT_ENABLE_NANA)
#if defined(PROJECT_ENABLE_PUGIXML)
#include "pugixml.hpp"
#endif // defined(PROJECT_ENABLE_PUGIXML)
#if defined(PROJECT_ENABLE_ROCKSDB)
#include "rocksdb/db.h"
#include "rocksdb/utilities/transaction_db.h"
#endif // defined(PROJECT_ENABLE_ROCKSDB)
#if defined(PROJECT_ENABLE_SFML)
#include "RoundedRectangleShape.hpp"
#include "SFML/Graphics.hpp"
#include "Text2.hpp"
#endif // defined(PROJECT_ENABLE_SFML)
#if defined(PROJECT_ENABLE_SAGO_PLATFORM_FOLDERS)
#include "platform_folders.hpp"
#endif // defined(PROJECT_ENABLE_SAGO_PLATFORM_FOLDERS)
#if defined(PROJECT_ENABLE_SPDLOG)
#include "spdlog/async.h"
#include "spdlog/fmt/bundled/core.h"
#include "spdlog/fmt/bundled/format.h"
#include "spdlog/fmt/bundled/ranges.h"
#include "spdlog/fmt/chrono.h"
#include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/spdlog.h"
#endif // defined(PROJECT_ENABLE_SPDLOG)
#if defined(PROJECT_ENABLE_FMT)
#include "fmt/chrono.h"
#include "fmt/core.h"
#include "fmt/format.h"
#include "fmt/ranges.h"
#endif // defined(PROJECT_ENABLE_FMT)
#if defined(PROJECT_ENABLE_STDUUID)
#include "uuid.h"
#endif // defined(PROJECT_ENABLE_STDUUID)
#if defined(PROJECT_ENABLE_TPL)
#include "process.hpp"
#endif // defined(PROJECT_ENABLE_TPL)
#if defined(PROJECT_ENABLE_WINFSP)
#if defined(_ReadWriteBarrier)
#undef _ReadWriteBarrier
#endif // defined(_ReadWriteBarrier)
#include "winfsp/winfsp.hpp"
#endif // defined(PROJECT_ENABLE_WINFSP)
namespace fifthgrid {
using data_buffer = std::vector<unsigned char>;
using data_span = std::span<unsigned char>;
using data_cspan = std::span<const unsigned char>;
using mutex_lock = std::lock_guard<std::mutex>;
using recur_mutex_lock = std::lock_guard<std::recursive_mutex>;
using stop_type = std::atomic_bool;
using stop_type_callback = std::function<std::atomic_bool()>;
using unique_mutex_lock = std::unique_lock<std::mutex>;
using unique_recur_mutex_lock = std::unique_lock<std::recursive_mutex>;
#if defined(_WIN32)
#if defined(PROJECT_ENABLE_WIN32_LONG_PATH_NAMES)
inline constexpr auto max_path_length = std::size_t{32767U};
#else // !defined(PROJECT_ENABLE_WIN32_LONG_PATH_NAMES)
inline constexpr auto max_path_length = std::size_t{MAX_PATH};
#endif // defined(PROJECT_ENABLE_WIN32_LONG_PATH_NAMES)
using native_handle = HANDLE;
#else // !defined(_WIN32)
inline constexpr auto max_path_length = std::size_t{PATH_MAX};
using native_handle = int;
#if !defined(INVALID_HANDLE_VALUE)
#define INVALID_HANDLE_VALUE (-1)
#endif // !defined(INVALID_HANDLE_VALUE)
#endif // defined(_WIN32)
template <class... Ts> struct overloaded : Ts... {
using Ts::operator()...;
};
template <class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
template <typename T> struct is_collection {
static const bool value = false;
};
template <typename T, typename A>
struct is_collection<std::vector<T, A>> : std::true_type {};
template <typename T> struct is_collection<std::deque<T>> : std::true_type {};
template <> struct is_collection<std::string> : std::true_type {};
template <> struct is_collection<std::wstring> : std::true_type {};
struct file_deleter final {
void operator()(FILE *file) {
if (file != nullptr) {
fclose(file);
}
}
};
using file_t = std::unique_ptr<FILE, file_deleter>;
struct http_range final {
std::uint64_t begin{};
std::uint64_t end{};
};
using http_headers = std::map<std::string, std::string>;
using http_query_parameters = std::map<std::string, std::string>;
using http_ranges = std::vector<http_range>;
} // namespace fifthgrid
#endif // defined(__cplusplus)
#define FIFTHGRID_USES_FUNCTION_NAME() \
static constexpr std::string_view function_name { \
static_cast<const char *>(__FUNCTION__), \
}
#endif // FIFTHGRID_INCLUDE_UTILS_CONFIG_HPP_

View File

@@ -0,0 +1,170 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_DB_SQLITE_DB_COMMON_HPP_
#define FIFTHGRID_INCLUDE_UTILS_DB_SQLITE_DB_COMMON_HPP_
#if defined(PROJECT_ENABLE_SQLITE)
#include "utils/config.hpp"
#include "utils/error.hpp"
namespace fifthgrid::utils::db::sqlite {
using db_types_t = std::variant<std::int64_t, std::string>;
struct sqlite3_deleter final {
void operator()(sqlite3 *db3) const;
};
using db3_t = std::unique_ptr<sqlite3, sqlite3_deleter>;
struct sqlite3_statement_deleter final {
void operator()(sqlite3_stmt *stmt) const {
if (stmt != nullptr) {
sqlite3_finalize(stmt);
}
}
};
using db3_stmt_t = std::unique_ptr<sqlite3_stmt, sqlite3_statement_deleter>;
[[nodiscard]] auto
create_db(std::string db_path,
const std::map<std::string, std::string> &sql_create_tables) -> db3_t;
[[nodiscard]] auto execute_sql(sqlite3 &db3, const std::string &sql,
std::string &err) -> bool;
void set_journal_mode(sqlite3 &db3);
struct db_comp_data_t final {
std::string column_name;
std::string op_type;
};
struct db_context_t {
db_context_t(sqlite3 *db3_, std::string table_name_)
: db3(db3_), table_name(std::move(table_name_)) {}
sqlite3 *db3{};
std::string table_name;
};
struct db_result final {
struct context final {
db3_stmt_t stmt;
};
class db_column final {
public:
db_column(std::int32_t index, std::string name, db_types_t value) noexcept;
db_column() noexcept = default;
db_column(const db_column &) = default;
db_column(db_column &&column) noexcept = default;
~db_column() = default;
auto operator=(const db_column &) -> db_column & = default;
auto operator=(db_column &&) -> db_column & = default;
private:
std::int32_t index_{};
std::string name_;
db_types_t value_;
public:
[[nodiscard]] auto get_index() const -> std::int32_t { return index_; }
[[nodiscard]] auto get_name() const -> std::string { return name_; }
template <typename data_type>
[[nodiscard]] auto get_value() const -> data_type {
FIFTHGRID_USES_FUNCTION_NAME();
return std::visit(
overloaded{
[](const data_type &value) -> data_type { return value; },
[](auto &&) -> data_type {
throw utils::error::create_exception(
function_name, {
"data type not supported",
});
},
},
value_);
}
#if defined(PROJECT_ENABLE_JSON)
[[nodiscard]] auto get_value_as_json() const -> nlohmann::json;
#endif // defined(PROJECT_ENABLE_JSON)
};
class db_row final {
public:
db_row(std::shared_ptr<context> ctx);
private:
std::map<std::string, db_column> columns_;
public:
[[nodiscard]] auto get_columns() const -> std::vector<db_column>;
[[nodiscard]] auto get_column(std::int32_t index) const -> db_column;
[[nodiscard]] auto get_column(std::string name) const -> db_column;
};
db_result(db3_stmt_t stmt, std::int32_t res);
db_result() = default;
db_result(const db_result &) = default;
db_result(db_result &&) noexcept = default;
auto operator=(const db_result &) -> db_result & = default;
auto operator=(db_result &&) -> db_result & = default;
using row = db_row;
private:
std::shared_ptr<context> ctx_;
mutable std::int32_t res_{};
private:
void set_res(std::int32_t res) const { res_ = res; }
public:
[[nodiscard]] auto get_error() const -> std::int32_t { return res_; }
[[nodiscard]] auto get_error_str() const -> std::string;
[[nodiscard]] auto get_row(std::optional<row> &opt_row) const -> bool;
[[nodiscard]] auto has_row() const -> bool;
void next_row() const;
[[nodiscard]] auto ok() const -> bool;
};
} // namespace fifthgrid::utils::db::sqlite
#endif // defined(PROJECT_ENABLE_SQLITE)
#endif // FIFTHGRID_INCLUDE_UTILS_DB_SQLITE_DB_COMMON_HPP_

View File

@@ -0,0 +1,73 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_DB_SQLITE_DB_DELETE_HPP_
#define FIFTHGRID_INCLUDE_UTILS_DB_SQLITE_DB_DELETE_HPP_
#if defined(PROJECT_ENABLE_SQLITE)
#include "utils/db/sqlite/db_common.hpp"
#include "utils/db/sqlite/db_where_t.hpp"
namespace fifthgrid::utils::db::sqlite {
class db_delete final {
public:
struct context final : db_context_t {
struct db_delete_op_t final {
std::shared_ptr<context> ctx;
[[nodiscard]] auto dump() const -> std::string;
[[nodiscard]] auto go() const -> db_result;
};
context(sqlite3 *db3_, std::string table_name_)
: db_context_t(db3_, table_name_) {}
using w_t = db_where_t<context, db_delete_op_t>;
using wd_t = where_data_t<w_t>;
std::unique_ptr<wd_t> where_data;
};
public:
db_delete(sqlite3 &db3, std::string table_name)
: ctx_(std::make_shared<context>(&db3, table_name)) {}
db_delete(std::shared_ptr<context> ctx) : ctx_(std::move(ctx)) {}
private:
std::shared_ptr<context> ctx_;
public:
[[nodiscard]] auto dump() const -> std::string;
[[nodiscard]] auto go() const -> db_result;
[[nodiscard]] auto
group(context::w_t::group_func_t func) -> context::w_t::wn_t;
[[nodiscard]] auto where(std::string column_name) const -> context::w_t::cn_t;
};
} // namespace fifthgrid::utils::db::sqlite
#endif // defined(PROJECT_ENABLE_SQLITE)
#endif // FIFTHGRID_INCLUDE_UTILS_DB_SQLITE_DB_DELETE_HPP_

View File

@@ -0,0 +1,64 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_DB_SQLITE_DB_INSERT_HPP_
#define FIFTHGRID_INCLUDE_UTILS_DB_SQLITE_DB_INSERT_HPP_
#if defined(PROJECT_ENABLE_SQLITE)
#include "utils/db/sqlite/db_common.hpp"
namespace fifthgrid::utils::db::sqlite {
class db_insert final {
public:
struct context final : db_context_t {
context(sqlite3 *db3_, std::string table_name_)
: db_context_t(db3_, table_name_) {}
bool or_replace{false};
std::map<std::string, db_types_t> values;
};
public:
db_insert(sqlite3 &db3, std::string table_name)
: ctx_(std::make_shared<context>(&db3, table_name)) {}
db_insert(std::shared_ptr<context> ctx) : ctx_(std::move(ctx)) {}
private:
std::shared_ptr<context> ctx_;
public:
[[nodiscard]] auto or_replace() -> db_insert {
ctx_->or_replace = true;
return *this;
}
[[nodiscard]] auto column_value(std::string column_name, db_types_t value)
-> db_insert;
[[nodiscard]] auto dump() const -> std::string;
[[nodiscard]] auto go() const -> db_result;
};
} // namespace fifthgrid::utils::db::sqlite
#endif // defined(PROJECT_ENABLE_SQLITE)
#endif // FIFTHGRID_INCLUDE_UTILS_DB_SQLITE_DB_INSERT_HPP_

View File

@@ -0,0 +1,104 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_DB_SQLITE_DB_SELECT_HPP_
#define FIFTHGRID_INCLUDE_UTILS_DB_SQLITE_DB_SELECT_HPP_
#if defined(PROJECT_ENABLE_SQLITE)
#include "utils/db/sqlite/db_common.hpp"
#include "utils/db/sqlite/db_where_t.hpp"
namespace fifthgrid::utils::db::sqlite {
class db_select final {
public:
struct context final : db_context_t {
struct db_select_op_t final {
std::shared_ptr<context> ctx;
[[nodiscard]] auto dump() const -> std::string;
[[nodiscard]] auto go() const -> db_result;
[[nodiscard]] auto group_by(std::string column_name) -> db_select_op_t;
[[nodiscard]] auto limit(std::int32_t value) -> db_select_op_t;
[[nodiscard]] auto offset(std::int32_t value) -> db_select_op_t;
[[nodiscard]] auto order_by(std::string column_name, bool ascending)
-> db_select_op_t;
};
context(sqlite3 *db3_, std::string table_name_)
: db_context_t(db3_, table_name_) {}
using w_t = db_where_t<context, db_select_op_t>;
using wd_t = where_data_t<w_t>;
std::vector<std::string> columns;
std::map<std::string, std::string> count_columns;
std::vector<std::string> group_by;
std::optional<std::int32_t> limit;
std::optional<std::int32_t> offset;
std::optional<std::pair<std::string, bool>> order_by;
std::unique_ptr<wd_t> where_data;
};
public:
db_select(sqlite3 &db3, std::string table_name)
: ctx_(std::make_shared<context>(&db3, table_name)) {}
db_select(std::shared_ptr<context> ctx) : ctx_(std::move(ctx)) {}
private:
std::shared_ptr<context> ctx_;
public:
[[nodiscard]] auto column(std::string column_name) -> db_select;
[[nodiscard]] auto count(std::string column_name, std::string as_column_name)
-> db_select;
[[nodiscard]] auto dump() const -> std::string;
[[nodiscard]] auto go() const -> db_result;
[[nodiscard]] auto group_by(std::string column_name) -> db_select;
[[nodiscard]] auto group(context::w_t::group_func_t func)
-> context::w_t::wn_t;
[[nodiscard]] auto limit(std::int32_t value) -> db_select;
[[nodiscard]] auto offset(std::int32_t value) -> db_select;
[[nodiscard]] auto order_by(std::string column_name, bool ascending)
-> db_select;
[[nodiscard]] auto where(std::string column_name) const -> context::w_t::cn_t;
};
} // namespace fifthgrid::utils::db::sqlite
#endif // defined(PROJECT_ENABLE_SQLITE)
#endif // FIFTHGRID_INCLUDE_UTILS_DB_SQLITE_DB_SELECT_HPP_

View File

@@ -0,0 +1,91 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_DB_SQLITE_DB_UPDATE_HPP_
#define FIFTHGRID_INCLUDE_UTILS_DB_SQLITE_DB_UPDATE_HPP_
#if defined(PROJECT_ENABLE_SQLITE)
#include "utils/db/sqlite/db_common.hpp"
#include "utils/db/sqlite/db_where_t.hpp"
namespace fifthgrid::utils::db::sqlite {
class db_update final {
public:
struct context final : db_context_t {
context(sqlite3 *db3_, std::string table_name_)
: db_context_t(db3_, table_name_) {}
struct db_update_op_t final {
std::shared_ptr<context> ctx;
[[nodiscard]] auto dump() const -> std::string;
[[nodiscard]] auto go() const -> db_result;
[[nodiscard]] auto limit(std::int32_t value) -> db_update_op_t;
[[nodiscard]] auto order_by(std::string column_name, bool ascending)
-> db_update_op_t;
};
using w_t = db_where_t<context, db_update_op_t>;
using wd_t = where_data_t<w_t>;
std::map<std::string, db_types_t> column_values;
std::optional<std::int32_t> limit;
std::optional<std::pair<std::string, bool>> order_by;
std::unique_ptr<wd_t> where_data;
};
public:
db_update(sqlite3 &db3, std::string table_name)
: ctx_(std::make_shared<context>(&db3, table_name)) {}
db_update(std::shared_ptr<context> ctx) : ctx_(std::move(ctx)) {}
private:
std::shared_ptr<context> ctx_;
public:
[[nodiscard]] auto column_value(std::string column_name, db_types_t value)
-> db_update;
[[nodiscard]] auto dump() const -> std::string;
[[nodiscard]] auto go() const -> db_result;
[[nodiscard]] auto group(context::w_t::group_func_t func)
-> context::w_t::wn_t;
[[nodiscard]] auto limit(std::int32_t value) -> db_update;
[[nodiscard]] auto order_by(std::string column_name, bool ascending)
-> db_update;
[[nodiscard]] auto where(std::string column_name) const -> context::w_t::cn_t;
};
} // namespace fifthgrid::utils::db::sqlite
#endif // defined(PROJECT_ENABLE_SQLITE)
#endif // FIFTHGRID_INCLUDE_UTILS_DB_SQLITE_DB_UPDATE_HPP_

View File

@@ -0,0 +1,224 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_DB_SQLITE_DB_WHERE_T_HPP_
#define FIFTHGRID_INCLUDE_UTILS_DB_SQLITE_DB_WHERE_T_HPP_
#if defined(PROJECT_ENABLE_SQLITE)
#include "utils/db/sqlite/db_common.hpp"
namespace fifthgrid::utils::db::sqlite {
template <typename w_t> struct where_data_t final {
w_t base;
std::map<std::size_t, std::vector<typename w_t::action_t>> actions;
std::vector<db_types_t> values;
};
template <typename cn_t, typename ctx_t, typename op_t, typename w_t,
typename wn_t>
struct db_next_t final {
std::size_t action_idx{};
std::shared_ptr<ctx_t> ctx;
std::string action;
using group_func_t = std::function<void(w_t &)>;
[[nodiscard]] auto where(std::string column_name) -> cn_t {
return w_t{action_idx, ctx}.where(column_name);
}
[[nodiscard]] auto dump() const -> std::string { return op_t{ctx}.dump(); }
[[nodiscard]] auto dump(std::int32_t &idx) const -> std::string {
return ctx->where_data->base.dump(idx);
}
[[nodiscard]] auto go() const -> auto { return op_t{ctx}.go(); }
[[nodiscard]] auto group(group_func_t func) -> wn_t {
return w_t{action_idx, ctx}.group(std::move(func));
}
[[nodiscard]] auto op() -> op_t {
return op_t{
ctx,
};
}
};
template <typename cn_t, typename ctx_t, typename op_t, typename w_t>
struct db_where_next_t final {
std::size_t action_idx{};
std::shared_ptr<ctx_t> ctx;
using n_t = db_next_t<cn_t, ctx_t, op_t, w_t, db_where_next_t>;
[[nodiscard]] auto and_() -> n_t {
n_t next{
action_idx,
ctx,
"AND",
};
ctx->where_data->actions[action_idx].emplace_back(next);
return next;
}
[[nodiscard]] auto dump() const -> std::string { return op_t{ctx}.dump(); }
[[nodiscard]] auto dump(std::int32_t &idx) const -> std::string {
return ctx->where_data->base.dump(idx);
}
[[nodiscard]] auto go() const -> auto { return op_t{ctx}.go(); }
[[nodiscard]] auto op() -> op_t {
return op_t{
ctx,
};
}
[[nodiscard]] auto or_() -> n_t {
n_t next{
action_idx,
ctx,
"OR",
};
ctx->where_data->actions[action_idx].emplace_back(next);
return next;
}
};
template <typename ctx_t, typename op_t, typename w_t>
struct db_comp_next_t final {
std::size_t action_idx{};
std::shared_ptr<ctx_t> ctx;
std::string column_name;
using wn_t = db_where_next_t<db_comp_next_t, ctx_t, op_t, w_t>;
[[nodiscard]] auto create(std::string operation, db_types_t value) {
ctx->where_data->actions[action_idx].emplace_back(db_comp_data_t{
column_name,
operation,
});
ctx->where_data->values.push_back(value);
return wn_t{
action_idx,
ctx,
};
}
auto equals(db_types_t value) -> wn_t { return create("=", value); };
auto gt(db_types_t value) -> wn_t { return create(">", value); }
auto gte(db_types_t value) -> wn_t { return create(">=", value); }
auto like(db_types_t value) -> wn_t { return create("LIKE", value); }
auto lt(db_types_t value) -> wn_t { return create("<", value); }
auto lte(db_types_t value) -> wn_t { return create("<=", value); }
auto not_equals(db_types_t value) -> wn_t { return create("!=", value); };
};
template <typename ctx_t, typename op_t> struct db_where_t final {
std::size_t action_idx{0U};
std::shared_ptr<ctx_t> ctx;
using cn_t = db_comp_next_t<ctx_t, op_t, db_where_t>;
using wn_t = db_where_next_t<cn_t, ctx_t, op_t, db_where_t>;
using n_t = db_next_t<cn_t, ctx_t, op_t, db_where_t, wn_t>;
using group_func_t = std::function<void(db_where_t &)>;
using action_t = std::variant<db_comp_data_t, n_t, db_where_t>;
[[nodiscard]] static auto dump(std::int32_t &idx,
auto &&actions) -> std::string {
std::stringstream stream;
for (auto &&action : actions) {
std::visit(overloaded{
[&idx, &stream](const db_comp_data_t &comp) {
stream << '"' << comp.column_name << '"' << comp.op_type
<< '?' + std::to_string(++idx);
},
[&idx, &stream](const n_t &next) {
stream << ' ' << next.action << ' ';
},
[&idx, &stream](const db_where_t &where) {
stream << '(' << dump(idx, where.get_actions()) << ')';
},
},
action);
}
return stream.str();
}
[[nodiscard]] auto dump() const -> std::string { return op_t{ctx}.dump(); }
[[nodiscard]] auto dump(std::int32_t &idx) const -> std::string {
return dump(idx, ctx->where_data->actions[action_idx]);
}
[[nodiscard]] auto get_actions() -> auto & {
return ctx->where_data->actions[action_idx];
}
[[nodiscard]] auto get_actions() const -> const auto & {
return ctx->where_data->actions[action_idx];
}
[[nodiscard]] auto group(group_func_t func) -> wn_t {
ctx->where_data->actions[action_idx];
db_where_t where{ctx->where_data->actions.size(), ctx};
func(where);
ctx->where_data->actions[action_idx].emplace_back(where);
return wn_t{
action_idx,
ctx,
};
}
[[nodiscard]] auto where(std::string column_name) -> cn_t {
ctx->where_data->actions[action_idx];
return cn_t{
action_idx,
ctx,
column_name,
};
}
};
} // namespace fifthgrid::utils::db::sqlite
#endif // defined(PROJECT_ENABLE_SQLITE)
#endif // FIFTHGRID_INCLUDE_UTILS_DB_SQLITE_DB_WHERE_T_HPP_

View File

@@ -0,0 +1,239 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_ENCRYPTING_READER_HPP_
#define FIFTHGRID_INCLUDE_UTILS_ENCRYPTING_READER_HPP_
#if defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST)
#include "utils/config.hpp"
#include "utils/encryption.hpp"
#include "utils/hash.hpp"
#include "utils/types/file/i_file.hpp"
namespace fifthgrid::utils::encryption {
class encrypting_reader final {
public:
encrypting_reader(std::string_view file_name, std::string_view source_path,
stop_type_callback stop_requested_cb,
std::string_view token,
std::optional<std::string> relative_parent_path,
std::size_t error_return = 0U);
encrypting_reader(stop_type_callback stop_requested_cb,
std::string_view encrypted_file_path,
std::string_view source_path, std::string_view token,
std::size_t error_return = 0U);
encrypting_reader(
stop_type_callback stop_requested_cb,
std::string_view encrypted_file_path, std::string_view source_path,
std::string_view token,
std::vector<std::array<unsigned char,
crypto_aead_xchacha20poly1305_IETF_NPUBBYTES>>
iv_list,
std::size_t error_return = 0U);
encrypting_reader(std::string_view file_name, std::string_view source_path,
stop_type_callback stop_requested_cb,
std::string_view token, kdf_config cfg,
std::optional<std::string> relative_parent_path,
std::size_t error_return = 0U);
encrypting_reader(stop_type_callback stop_requested_cb,
std::string_view encrypted_file_path,
std::string_view source_path, std::string_view token,
kdf_config cfg, std::size_t error_return = 0U);
encrypting_reader(
stop_type_callback stop_requested_cb,
std::string_view encrypted_file_path, std::string_view source_path,
std::string_view token, kdf_config cfg,
std::vector<std::array<unsigned char,
crypto_aead_xchacha20poly1305_IETF_NPUBBYTES>>
iv_list,
std::size_t error_return = 0U);
encrypting_reader(std::string_view file_name, std::string_view source_path,
stop_type_callback stop_requested_cb,
const utils::hash::hash_256_t &master_key,
const kdf_config &cfg,
std::optional<std::string> relative_parent_path,
std::size_t error_return = 0U);
encrypting_reader(std::string_view file_name, std::string_view source_path,
stop_type_callback stop_requested_cb,
const utils::hash::hash_256_t &master_key,
const std::pair<kdf_config, kdf_config> &configs,
std::optional<std::string> relative_parent_path,
std::size_t error_return = 0U);
encrypting_reader(stop_type_callback stop_requested_cb,
std::string_view encrypted_file_path,
std::string_view source_path,
const utils::hash::hash_256_t &master_key,
const kdf_config &cfg, std::size_t error_return = 0U);
encrypting_reader(
stop_type_callback stop_requested_cb,
std::string_view encrypted_file_path, std::string_view source_path,
const utils::hash::hash_256_t &master_key, const kdf_config &cfg,
std::vector<std::array<unsigned char,
crypto_aead_xchacha20poly1305_IETF_NPUBBYTES>>
iv_list,
std::size_t error_return = 0U);
encrypting_reader(
stop_type_callback stop_requested_cb,
std::string_view encrypted_file_path, std::string_view source_path,
const utils::hash::hash_256_t &master_key,
const std::pair<kdf_config, kdf_config> &configs,
std::vector<std::array<unsigned char,
crypto_aead_xchacha20poly1305_IETF_NPUBBYTES>>
iv_list,
std::size_t error_return = 0U);
encrypting_reader(const encrypting_reader &reader);
encrypting_reader(encrypting_reader &&) = delete;
auto operator=(const encrypting_reader &) -> encrypting_reader & = delete;
auto operator=(encrypting_reader &&) -> encrypting_reader & = delete;
~encrypting_reader() noexcept = default;
public:
using iostream = std::basic_iostream<char, std::char_traits<char>>;
using kdf_pair_t = std::pair<data_buffer, data_buffer>;
using key_pair_t =
std::pair<utils::hash::hash_256_t, utils::hash::hash_256_t>;
using streambuf = std::basic_streambuf<char, std::char_traits<char>>;
private:
key_pair_t keys_;
stop_type_callback stop_requested_cb_;
size_t error_return_;
std::unique_ptr<utils::file::i_file> source_file_;
std::string encrypted_file_name_;
std::string encrypted_file_path_;
std::vector<
std::array<unsigned char, crypto_aead_xchacha20poly1305_IETF_NPUBBYTES>>
iv_list_;
private:
std::unordered_map<std::size_t, data_buffer> chunk_buffers_;
std::optional<kdf_pair_t> kdf_headers_;
std::size_t last_data_chunk_{};
std::size_t last_data_chunk_size_{};
std::uint64_t read_offset_{};
std::uint64_t total_size_{};
private:
static const std::size_t header_size_;
static const std::size_t data_chunk_size_;
static const std::size_t encrypted_chunk_size_;
private:
auto reader_function(char *buffer, size_t size, size_t nitems) -> size_t;
void common_initialize(bool procces_iv_list);
void common_initialize_kdf_data(const kdf_config &cfg,
const utils::hash::hash_256_t &master_key);
void common_initialize_kdf_keys(std::string_view token, kdf_config &cfg);
void common_initialize_kdf_path(const utils::hash::hash_256_t &master_key);
void create_encrypted_paths(std::string_view file_name,
std::optional<std::string> relative_parent_path);
public:
[[nodiscard]] static auto calculate_decrypted_size(std::uint64_t total_size,
bool uses_kdf)
-> std::uint64_t;
[[nodiscard]] static auto
calculate_encrypted_size(std::string_view source_path, bool uses_kdf)
-> std::uint64_t;
[[nodiscard]] static auto calculate_encrypted_size(std::uint64_t size,
bool uses_kdf)
-> std::uint64_t;
[[nodiscard]] auto create_iostream() const -> std::shared_ptr<iostream>;
[[nodiscard]] static constexpr auto get_encrypted_chunk_size()
-> std::size_t {
return encrypted_chunk_size_;
}
[[nodiscard]] static constexpr auto get_data_chunk_size() -> std::size_t {
return data_chunk_size_;
}
[[nodiscard]] auto get_encrypted_file_name() const -> std::string {
return encrypted_file_name_;
}
[[nodiscard]] auto get_encrypted_file_path() const -> std::string {
return encrypted_file_path_;
}
[[nodiscard]] auto get_error_return() const -> std::size_t {
return error_return_;
}
[[nodiscard]] static constexpr auto get_header_size() -> std::size_t {
return header_size_;
}
[[nodiscard]] auto get_iv_list() -> std::vector<
std::array<unsigned char, crypto_aead_xchacha20poly1305_IETF_NPUBBYTES>> {
return iv_list_;
}
[[nodiscard]] auto get_kdf_config_for_data() const
-> std::optional<kdf_config>;
[[nodiscard]] auto get_kdf_config_for_path() const
-> std::optional<kdf_config>;
[[nodiscard]] auto get_stop_requested() const -> bool {
return stop_requested_cb_();
}
[[nodiscard]] auto get_total_size() const -> std::uint64_t {
return total_size_;
}
[[nodiscard]] static auto reader_function(char *buffer, size_t size,
size_t nitems, void *instream)
-> size_t {
return reinterpret_cast<encrypting_reader *>(instream)->reader_function(
buffer, size, nitems);
}
void set_read_position(std::uint64_t position) { read_offset_ = position; }
};
} // namespace fifthgrid::utils::encryption
#endif // defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST)
#endif // FIFTHGRID_INCLUDE_UTILS_ENCRYPTING_READER_HPP_

View File

@@ -0,0 +1,722 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_ENCRYPTION_HPP_
#define FIFTHGRID_INCLUDE_UTILS_ENCRYPTION_HPP_
#if defined(PROJECT_ENABLE_LIBSODIUM)
#include "utils/config.hpp"
#if defined(PROJECT_ENABLE_BOOST) && defined(PROJECT_ENABLE_JSON)
#include "utils/collection.hpp"
#endif // defined(PROJECT_ENABLE_BOOST) && defined(PROJECT_ENABLE_JSON)
#include "utils/error.hpp"
#include "utils/hash.hpp"
namespace fifthgrid::utils::encryption {
inline constexpr std::uint32_t encryption_header_size{
crypto_aead_xchacha20poly1305_IETF_NPUBBYTES +
crypto_aead_xchacha20poly1305_IETF_ABYTES,
};
#if defined(PROJECT_ENABLE_BOOST)
enum class kdf_version : std::uint8_t { v1 };
enum class kdf_type : std::uint8_t { argon2id };
enum class memlimit_level : std::uint8_t {
level1, // 64MiB
level2, // 256MiB
level3, // 512MiB
level4, // 1GiB
};
enum class opslimit_level : std::uint8_t {
level1, // interactive
level2, // moderate
level3, // sensitive
};
[[nodiscard]] inline auto get_memlimit(memlimit_level memlimit) -> size_t {
constexpr auto mib512{512ULL * 1024ULL * 1024ULL};
switch (memlimit) {
case memlimit_level::level1:
return crypto_pwhash_MEMLIMIT_INTERACTIVE;
case memlimit_level::level2:
return crypto_pwhash_MEMLIMIT_MODERATE;
case memlimit_level::level3:
return mib512;
case memlimit_level::level4:
return crypto_pwhash_MEMLIMIT_SENSITIVE;
}
return mib512;
}
[[nodiscard]] inline auto get_opslimit(opslimit_level opslimit)
-> unsigned long long {
switch (opslimit) {
case opslimit_level::level1:
return crypto_pwhash_OPSLIMIT_INTERACTIVE;
case opslimit_level::level2:
return crypto_pwhash_OPSLIMIT_MODERATE;
case opslimit_level::level3:
return crypto_pwhash_OPSLIMIT_SENSITIVE;
}
return crypto_pwhash_OPSLIMIT_MODERATE;
}
enum class kdf_context : std::uint8_t {
data,
path,
undefined,
};
using kdf_ctx_t = std::array<char, crypto_kdf_CONTEXTBYTES>;
namespace kdf {
constexpr inline std::array<
kdf_ctx_t, static_cast<std::size_t>(kdf_context::undefined) + 1U>
KDF_CTXS{
{
{'D', 'A', 'T', 'A', '_', 'C', 'T', 'X'},
{'F', 'I', 'L', 'E', '_', 'C', 'T', 'X'},
{'D', 'E', 'F', 'L', '_', 'C', 'T', 'X'},
},
};
} // namespace kdf
[[nodiscard]] constexpr inline auto get_kdf_context_name(kdf_context ctx)
-> kdf_ctx_t {
const auto idx = static_cast<std::size_t>(ctx);
return idx < kdf::KDF_CTXS.size() ? kdf::KDF_CTXS.at(idx)
: kdf::KDF_CTXS.back();
}
#pragma pack(push, 1)
struct kdf_config final {
using salt_t = std::array<std::uint8_t, crypto_pwhash_SALTBYTES>;
kdf_version version{kdf_version::v1};
kdf_type kdf{kdf_type::argon2id};
memlimit_level memlimit{memlimit_level::level3};
opslimit_level opslimit{opslimit_level::level2};
std::uint64_t unique_id{};
salt_t salt{};
std::uint64_t checksum{};
template <typename hash_t>
[[nodiscard]] auto create_subkey(kdf_context ctx, std::size_t unique_id_,
const hash_t &master_key) const
-> std::pair<hash_t, kdf_config> {
auto sub_key = derive_subkey<hash_t>(ctx, unique_id_, master_key);
auto cfg = *this;
cfg.unique_id = unique_id_;
cfg.checksum = cfg.generate_checksum();
return {sub_key, cfg};
}
template <typename hash_t>
[[nodiscard]] static auto derive_subkey(kdf_context ctx,
std::size_t unique_id_,
const hash_t &master_key) -> hash_t {
FIFTHGRID_USES_FUNCTION_NAME();
hash_t sub_key{};
auto res = crypto_kdf_derive_from_key(
sub_key.data(), sub_key.size(), unique_id_,
get_kdf_context_name(ctx).data(), master_key.data());
if (res != 0) {
throw fifthgrid::utils::error::create_exception(
function_name, {
"failed to derive sub-key",
std::to_string(res),
});
}
return sub_key;
}
template <typename hash_t>
[[nodiscard]] auto recreate_subkey(kdf_context ctx,
const hash_t &master_key) const -> hash_t {
return derive_subkey<hash_t>(ctx, unique_id, master_key);
}
[[nodiscard]] static auto from_header(data_cspan data, kdf_config &cfg,
bool ignore_checksum = false) -> bool;
[[nodiscard]] auto generate_checksum() const -> std::uint64_t;
void seal();
[[nodiscard]] static constexpr auto size() -> std::size_t {
return sizeof(kdf_config);
}
[[nodiscard]] auto to_header() const -> data_buffer;
[[nodiscard]] auto operator==(const kdf_config &) const -> bool = default;
[[nodiscard]] auto operator!=(const kdf_config &) const -> bool = default;
};
#pragma pack(pop)
#endif // defined(PROJECT_ENABLE_BOOST)
template <typename hash_t>
[[nodiscard]] inline auto generate_key(
std::string_view password,
std::function<hash_t(const unsigned char *data, std::size_t size)> hasher =
utils::hash::default_create_hash<hash_t>()) -> hash_t;
template <typename hash_t>
[[nodiscard]] inline auto generate_key(
std::wstring_view password,
std::function<hash_t(const unsigned char *data, std::size_t size)> hasher =
utils::hash::default_create_hash<hash_t>()) -> hash_t;
#if defined(PROJECT_ENABLE_BOOST)
template <typename hash_t>
[[nodiscard]] inline auto generate_key(std::string_view password,
kdf_config &cfg) -> hash_t;
template <typename hash_t>
[[nodiscard]] inline auto generate_key(std::wstring_view password,
kdf_config &cfg) -> hash_t;
template <typename hash_t>
[[nodiscard]] inline auto recreate_key(std::string_view password,
const kdf_config &cfg) -> hash_t;
template <typename hash_t>
[[nodiscard]] inline auto recreate_key(std::wstring_view password,
const kdf_config &cfg) -> hash_t;
template <typename string_t>
[[nodiscard]] auto create_key_argon2id(string_t password, kdf_config &cfg,
utils::hash::hash_256_t &key) -> bool;
template <typename string_t>
[[nodiscard]] auto recreate_key_argon2id(string_t password,
const kdf_config &cfg,
utils::hash::hash_256_t &key) -> bool;
template <typename hash_t, typename string_t>
[[nodiscard]] inline auto
detect_and_recreate_key(string_t password, data_cspan header, hash_t &key,
std::optional<kdf_config> &cfg) -> bool;
template <typename hash_t>
[[nodiscard]] inline auto
detect_and_recreate_key(std::string_view password, data_cspan header,
hash_t &key, std::optional<kdf_config> &cfg) -> bool;
template <typename hash_t>
[[nodiscard]] inline auto
detect_and_recreate_key(std::wstring_view password, data_cspan header,
hash_t &key, std::optional<kdf_config> &cfg) -> bool;
[[nodiscard]] auto decrypt_file_name(std::string_view encryption_token,
std::string &file_name) -> bool;
[[nodiscard]] auto decrypt_file_path(std::string_view encryption_token,
std::string &file_path) -> bool;
[[nodiscard]] auto decrypt_file_name(std::string_view encryption_token,
const kdf_config &cfg,
std::string &file_name) -> bool;
[[nodiscard]] auto decrypt_file_path(std::string_view encryption_token,
const kdf_config &cfg,
std::string &file_path) -> bool;
[[nodiscard]] auto decrypt_file_name(const utils::hash::hash_256_t &master_key,
std::string &file_name) -> bool;
[[nodiscard]] auto decrypt_file_path(const utils::hash::hash_256_t &master_key,
std::string &file_path) -> bool;
template <typename result_t, typename arr_t, std::size_t arr_size>
[[nodiscard]] inline auto decrypt_data(const std::array<arr_t, arr_size> &key,
const unsigned char *buffer,
std::size_t buffer_size, result_t &res)
-> bool {
if (buffer_size > encryption_header_size) {
std::uint32_t size =
boost::endian::native_to_big(static_cast<std::uint32_t>(buffer_size));
res.resize(buffer_size - encryption_header_size);
return crypto_aead_xchacha20poly1305_ietf_decrypt_detached(
reinterpret_cast<unsigned char *>(res.data()), nullptr,
&buffer[encryption_header_size], res.size(),
&buffer[crypto_aead_xchacha20poly1305_IETF_NPUBBYTES],
reinterpret_cast<const unsigned char *>(&size), sizeof(size),
buffer, key.data()) == 0;
}
return false;
}
template <typename buffer_t, typename result_t, typename arr_t,
std::size_t arr_size>
[[nodiscard]] inline auto decrypt_data(const std::array<arr_t, arr_size> &key,
const buffer_t &buf, result_t &res)
-> bool {
return decrypt_data<result_t>(
key, reinterpret_cast<const unsigned char *>(buf.data()), buf.size(),
res);
}
template <typename buffer_t, typename result_t,
typename hash_t = utils::hash::hash_256_t>
[[nodiscard]] inline auto decrypt_data(
std::string_view password, const buffer_t &buf, result_t &res,
std::function<hash_t(const unsigned char *data, std::size_t size)> hasher =
utils::hash::default_create_hash<hash_t>()) -> bool {
return decrypt_data<buffer_t, result_t>(generate_key(password, hasher), buf,
res);
}
template <typename buffer_t, typename result_t,
typename hash_t = utils::hash::hash_256_t>
[[nodiscard]] inline auto decrypt_data(std::string_view password,
const kdf_config &cfg,
const buffer_t &buf, result_t &res)
-> bool {
return decrypt_data<buffer_t, result_t>(recreate_key<hash_t>(password, cfg),
buf, res);
}
template <typename result_t, typename hash_t = utils::hash::hash_256_t>
[[nodiscard]] inline auto decrypt_data(
std::string_view password, const unsigned char *buffer,
std::size_t buffer_size, result_t &res,
std::function<hash_t(const unsigned char *data, std::size_t size)> hasher =
utils::hash::default_create_hash<hash_t>()) -> bool {
return decrypt_data<result_t>(generate_key(password, hasher), buffer,
buffer_size, res);
}
template <typename result_t, typename hash_t = utils::hash::hash_256_t>
[[nodiscard]] inline auto decrypt_data(std::string_view password,
const kdf_config &cfg,
const unsigned char *buffer,
std::size_t buffer_size, result_t &res)
-> bool {
return decrypt_data<result_t>(recreate_key<hash_t>(password, cfg), buffer,
buffer_size, res);
}
template <typename result_t, typename arr_t, std::size_t arr_size>
inline void
encrypt_data(const std::array<unsigned char,
crypto_aead_xchacha20poly1305_IETF_NPUBBYTES> &iv,
const std::array<arr_t, arr_size> &key,
const unsigned char *buffer, std::size_t buffer_size,
result_t &res) {
FIFTHGRID_USES_FUNCTION_NAME();
std::array<unsigned char, crypto_aead_xchacha20poly1305_IETF_ABYTES> mac{};
const std::uint32_t size = boost::endian::native_to_big(
static_cast<std::uint32_t>(buffer_size + encryption_header_size));
res.resize(buffer_size + encryption_header_size);
unsigned long long mac_length{};
if (crypto_aead_xchacha20poly1305_ietf_encrypt_detached(
reinterpret_cast<unsigned char *>(&res[encryption_header_size]),
mac.data(), &mac_length, buffer, buffer_size,
reinterpret_cast<const unsigned char *>(&size), sizeof(size), nullptr,
iv.data(), key.data()) != 0) {
throw fifthgrid::utils::error::create_exception(function_name,
{
"encryption failed",
});
}
std::memcpy(res.data(), iv.data(), iv.size());
std::memcpy(&res[iv.size()], mac.data(), mac.size());
}
template <typename result_t, typename arr_t, std::size_t arr_size>
inline void encrypt_data(const std::array<arr_t, arr_size> &key,
const unsigned char *buffer, std::size_t buffer_size,
result_t &res) {
std::array<unsigned char, crypto_aead_xchacha20poly1305_IETF_NPUBBYTES> iv{};
randombytes_buf(iv.data(), iv.size());
encrypt_data<result_t>(iv, key, buffer, buffer_size, res);
}
template <typename result_t, typename hash_t = utils::hash::hash_256_t>
inline void encrypt_data(
std::string_view password, const unsigned char *buffer,
std::size_t buffer_size, result_t &res,
std::function<hash_t(const unsigned char *data, std::size_t size)> hasher =
utils::hash::default_create_hash<hash_t>()) {
encrypt_data<result_t>(generate_key(password, hasher), buffer, buffer_size,
res);
}
template <typename result_t, typename hash_t = utils::hash::hash_256_t>
inline void encrypt_data(std::string_view password, kdf_config &cfg,
const unsigned char *buffer, std::size_t buffer_size,
result_t &res) {
encrypt_data<result_t>(generate_key<hash_t>(password, cfg), buffer,
buffer_size, res);
}
template <typename buffer_t, typename result_t,
typename hash_t = utils::hash::hash_256_t>
inline void encrypt_data(
std::string_view password, const buffer_t &buf, result_t &res,
std::function<hash_t(const unsigned char *data, std::size_t size)> hasher =
utils::hash::default_create_hash<hash_t>()) {
encrypt_data<result_t>(generate_key(password, hasher),
reinterpret_cast<const unsigned char *>(buf.data()),
buf.size(), res);
}
template <typename buffer_t, typename result_t,
typename hash_t = utils::hash::hash_256_t>
inline void encrypt_data(std::string_view password, kdf_config &cfg,
const buffer_t &buf, result_t &res) {
encrypt_data<result_t>(generate_key<hash_t>(password, cfg),
reinterpret_cast<const unsigned char *>(buf.data()),
buf.size(), res);
}
template <typename buffer_t, typename result_t, typename arr_t,
std::size_t arr_size>
inline void encrypt_data(const std::array<arr_t, arr_size> &key,
const buffer_t &buf, result_t &res) {
encrypt_data<result_t>(key,
reinterpret_cast<const unsigned char *>(buf.data()),
buf.size(), res);
}
template <typename buffer_t, typename result_t, typename arr_t,
std::size_t arr_size>
inline void
encrypt_data(const std::array<unsigned char,
crypto_aead_xchacha20poly1305_IETF_NPUBBYTES> &iv,
const std::array<arr_t, arr_size> &key, const buffer_t &buf,
result_t &res) {
encrypt_data<result_t>(iv, key,
reinterpret_cast<const unsigned char *>(buf.data()),
buf.size(), res);
}
using reader_func_t =
std::function<bool(data_buffer &cypher_text, std::uint64_t start_offset,
std::uint64_t end_offset)>;
[[nodiscard]] auto read_encrypted_range(const http_range &range,
const utils::hash::hash_256_t &key,
bool uses_kdf,
reader_func_t reader_func,
std::uint64_t total_size,
data_buffer &data) -> bool;
[[nodiscard]] auto read_encrypted_range(
const http_range &range, const utils::hash::hash_256_t &key, bool uses_kdf,
reader_func_t reader_func, std::uint64_t total_size, unsigned char *data,
std::size_t size, std::size_t &bytes_read) -> bool;
[[nodiscard]] inline auto
read_encrypted_range(const http_range &range,
const utils::hash::hash_256_t &key,
reader_func_t reader_func, std::uint64_t total_size,
data_buffer &data) -> bool {
return read_encrypted_range(range, key, false, reader_func, total_size, data);
}
[[nodiscard]] inline auto read_encrypted_range(
const http_range &range, const utils::hash::hash_256_t &key,
reader_func_t reader_func, std::uint64_t total_size, unsigned char *data,
std::size_t size, std::size_t &bytes_read) -> bool {
return read_encrypted_range(range, key, false, reader_func, total_size, data,
size, bytes_read);
}
template <typename string_t>
auto create_key_argon2id(string_t password, kdf_config &cfg,
utils::hash::hash_256_t &key) -> bool {
cfg.seal();
return recreate_key_argon2id(password, cfg, key);
}
template <typename string_t>
auto recreate_key_argon2id(string_t password, const kdf_config &cfg,
utils::hash::hash_256_t &key) -> bool {
return crypto_pwhash(
reinterpret_cast<unsigned char *>(key.data()), key.size(),
reinterpret_cast<const char *>(password.data()),
password.size() * sizeof(typename string_t::value_type),
cfg.salt.data(), get_opslimit(cfg.opslimit),
get_memlimit(cfg.memlimit), crypto_pwhash_ALG_ARGON2ID13) == 0;
}
#endif // defined(PROJECT_ENABLE_BOOST)
template <typename hash_t>
inline auto generate_key(
std::string_view password,
std::function<hash_t(const unsigned char *data, std::size_t size)> hasher)
-> hash_t {
return hasher(reinterpret_cast<const unsigned char *>(password.data()),
password.size());
}
template <typename hash_t>
inline auto generate_key(
std::wstring_view password,
std::function<hash_t(const unsigned char *data, std::size_t size)> hasher)
-> hash_t {
return hasher(reinterpret_cast<const unsigned char *>(password.data()),
password.size() * sizeof(wchar_t));
}
#if defined(PROJECT_ENABLE_BOOST)
template <typename hash_t, typename string_t>
inline auto generate_key_impl(string_t password, kdf_config &cfg) -> hash_t {
FIFTHGRID_USES_FUNCTION_NAME();
switch (cfg.version) {
case kdf_version::v1:
switch (cfg.kdf) {
case kdf_type::argon2id: {
hash_t key{};
if (not create_key_argon2id(password, cfg, key)) {
throw utils::error::create_exception(
function_name, {
"failed to generate argon2id key",
});
}
return key;
}
default:
throw utils::error::create_exception(
function_name, {
"unsupported kdf type",
std::to_string(static_cast<std::uint8_t>(cfg.kdf)),
});
}
default:
throw utils::error::create_exception(
function_name,
{
"unsupported kdf version",
std::to_string(static_cast<std::uint8_t>(cfg.version)),
});
}
}
template <typename hash_t, typename string_t>
inline auto recreate_key_impl(string_t password, const kdf_config &cfg)
-> hash_t {
FIFTHGRID_USES_FUNCTION_NAME();
switch (cfg.version) {
case kdf_version::v1:
switch (cfg.kdf) {
case kdf_type::argon2id: {
hash_t key{};
if (not recreate_key_argon2id(password, cfg, key)) {
throw utils::error::create_exception(
function_name, {
"failed to generate argon2id key",
});
}
return key;
}
default:
throw utils::error::create_exception(
function_name, {
"unsupported kdf type",
std::to_string(static_cast<std::uint8_t>(cfg.kdf)),
});
}
default:
throw utils::error::create_exception(
function_name,
{
"unsupported kdf version",
std::to_string(static_cast<std::uint8_t>(cfg.version)),
});
}
}
template <typename hash_t>
inline auto generate_key(std::string_view password, kdf_config &cfg) -> hash_t {
return generate_key_impl<hash_t, std::string_view>(password, cfg);
}
template <typename hash_t>
inline auto generate_key(std::wstring_view password, kdf_config &cfg)
-> hash_t {
return generate_key_impl<hash_t, std::wstring_view>(password, cfg);
}
template <typename hash_t>
inline auto recreate_key(std::string_view password, const kdf_config &cfg)
-> hash_t {
return recreate_key_impl<hash_t, std::string_view>(password, cfg);
}
template <typename hash_t>
inline auto recreate_key(std::wstring_view password, const kdf_config &cfg)
-> hash_t {
return recreate_key_impl<hash_t, std::wstring_view>(password, cfg);
}
template <typename hash_t, typename string_t>
inline auto detect_and_recreate_key(string_t password, data_cspan header,
hash_t &key, std::optional<kdf_config> &cfg)
-> bool {
if (header.size() >= kdf_config::size()) {
kdf_config tmp{};
if (kdf_config::from_header(header.first(kdf_config::size()), tmp)) {
cfg = tmp;
key = recreate_key<hash_t>(password, *cfg);
return true;
}
}
key = generate_key<hash_t>(password);
return false;
}
template <typename hash_t>
inline auto detect_and_recreate_key(std::string_view password,
data_cspan header, hash_t &key,
std::optional<kdf_config> &cfg) -> bool {
return detect_and_recreate_key<hash_t, std::string_view>(password, header,
key, cfg);
}
template <typename hash_t>
inline auto detect_and_recreate_key(std::wstring_view password,
data_cspan header, hash_t &key,
std::optional<kdf_config> &cfg) -> bool {
return detect_and_recreate_key<hash_t, std::wstring_view>(password, header,
key, cfg);
}
#endif // defined(PROJECT_ENABLE_BOOST)
} // namespace fifthgrid::utils::encryption
#if defined(PROJECT_ENABLE_BOOST) && defined(PROJECT_ENABLE_JSON)
NLOHMANN_JSON_NAMESPACE_BEGIN
namespace kdf {
inline constexpr std::string_view JSON_CHECKSUM{"checksum"};
inline constexpr std::string_view JSON_KDF{"kdf"};
inline constexpr std::string_view JSON_MEMLIMIT{"memlimit"};
inline constexpr std::string_view JSON_OPSLIMIT{"opslimit"};
inline constexpr std::string_view JSON_SALT{"salt"};
inline constexpr std::string_view JSON_UNIQUE_ID{"unique_id"};
inline constexpr std::string_view JSON_VERSION{"version"};
} // namespace kdf
template <>
struct adl_serializer<fifthgrid::utils::encryption::kdf_config::salt_t> {
static void
to_json(json &data,
const fifthgrid::utils::encryption::kdf_config::salt_t &value) {
data = fifthgrid::utils::collection::to_hex_string(value);
}
static void
from_json(const json &data,
fifthgrid::utils::encryption::kdf_config::salt_t &value) {
FIFTHGRID_USES_FUNCTION_NAME();
fifthgrid::data_buffer buffer{};
if (not fifthgrid::utils::collection::from_hex_string(
data.get<std::string>(), buffer)) {
throw fifthgrid::utils::error::create_exception(
function_name, {
"failed to convert hex string to salt",
data.get<std::string>(),
});
}
if (buffer.size() != value.size()) {
throw fifthgrid::utils::error::create_exception(
function_name, {
"unexpected length for salt after hex conversion",
"expected",
std::to_string(value.size()),
"actual",
std::to_string(buffer.size()),
});
}
std::copy_n(buffer.begin(), value.size(), value.begin());
}
};
template <> struct adl_serializer<fifthgrid::utils::encryption::kdf_config> {
static void to_json(json &data,
const fifthgrid::utils::encryption::kdf_config &value) {
data[kdf::JSON_CHECKSUM] = value.checksum;
data[kdf::JSON_KDF] = value.kdf;
data[kdf::JSON_MEMLIMIT] = value.memlimit;
data[kdf::JSON_OPSLIMIT] = value.opslimit;
data[kdf::JSON_SALT] = value.salt;
data[kdf::JSON_UNIQUE_ID] = value.unique_id;
data[kdf::JSON_VERSION] = value.version;
}
static void from_json(const json &data,
fifthgrid::utils::encryption::kdf_config &value) {
data.at(kdf::JSON_CHECKSUM).get_to<std::uint64_t>(value.checksum);
data.at(kdf::JSON_KDF)
.get_to<fifthgrid::utils::encryption::kdf_type>(value.kdf);
data.at(kdf::JSON_MEMLIMIT)
.get_to<fifthgrid::utils::encryption::memlimit_level>(value.memlimit);
data.at(kdf::JSON_OPSLIMIT)
.get_to<fifthgrid::utils::encryption::opslimit_level>(value.opslimit);
data.at(kdf::JSON_SALT)
.get_to<fifthgrid::utils::encryption::kdf_config::salt_t>(value.salt);
data.at(kdf::JSON_UNIQUE_ID).get_to<std::uint64_t>(value.unique_id);
data.at(kdf::JSON_VERSION)
.get_to<fifthgrid::utils::encryption::kdf_version>(value.version);
}
};
NLOHMANN_JSON_NAMESPACE_END
#endif // defined(PROJECT_ENABLE_BOOST) && defined(PROJECT_ENABLE_JSON)
#endif // defined(PROJECT_ENABLE_LIBSODIUM)
#endif // FIFTHGRID_INCLUDE_UTILS_ENCRYPTION_HPP_

View File

@@ -0,0 +1,164 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_ERROR_HPP_
#define FIFTHGRID_INCLUDE_UTILS_ERROR_HPP_
#include "utils/config.hpp"
namespace fifthgrid::utils::error {
[[nodiscard]] auto create_error_message(std::vector<std::string_view> items)
-> std::string;
[[nodiscard]] auto create_error_message(std::string_view function_name,
std::vector<std::string_view> items)
-> std::string;
[[nodiscard]] auto create_exception(std::string_view function_name,
std::vector<std::string_view> items)
-> std::runtime_error;
struct i_exception_handler {
virtual ~i_exception_handler() {}
i_exception_handler(const i_exception_handler &) noexcept = delete;
i_exception_handler(i_exception_handler &&) noexcept = delete;
auto operator=(const i_exception_handler &) noexcept = delete;
auto operator=(i_exception_handler &&) noexcept = delete;
#if defined(PROJECT_ENABLE_V2_ERRORS)
virtual void handle_debug(std::string_view function_name,
std::string_view msg) const = 0;
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
virtual void handle_error(std::string_view function_name,
std::string_view msg) const = 0;
virtual void handle_exception(std::string_view function_name) const = 0;
virtual void handle_exception(std::string_view function_name,
const std::exception &ex) const = 0;
#if defined(PROJECT_ENABLE_V2_ERRORS)
virtual void handle_info(std::string_view function_name,
std::string_view msg) const = 0;
virtual void handle_trace(std::string_view function_name,
std::string_view msg) const = 0;
virtual void handle_warn(std::string_view function_name,
std::string_view msg) const = 0;
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
protected:
i_exception_handler() = default;
};
struct iostream_exception_handler final : public i_exception_handler {
#if defined(PROJECT_ENABLE_V2_ERRORS)
void handle_debug(std::string_view function_name,
std::string_view msg) const override;
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
void handle_error(std::string_view function_name,
std::string_view msg) const override;
void handle_exception(std::string_view function_name) const override;
void handle_exception(std::string_view function_name,
const std::exception &ex) const override;
#if defined(PROJECT_ENABLE_V2_ERRORS)
void handle_info(std::string_view function_name,
std::string_view msg) const override;
void handle_trace(std::string_view function_name,
std::string_view msg) const override;
void handle_warn(std::string_view function_name,
std::string_view msg) const override;
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
};
#if defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS)
struct spdlog_exception_handler final : public i_exception_handler {
void handle_debug(std::string_view function_name,
std::string_view msg) const override;
void handle_error(std::string_view function_name,
std::string_view msg) const override;
void handle_exception(std::string_view function_name) const override;
void handle_exception(std::string_view function_name,
const std::exception &ex) const override;
void handle_info(std::string_view function_name,
std::string_view msg) const override;
void handle_trace(std::string_view function_name,
std::string_view msg) const override;
void handle_warn(std::string_view function_name,
std::string_view msg) const override;
private:
iostream_exception_handler fallback{};
};
#endif // defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS)
#if defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS)
inline const spdlog_exception_handler default_exception_handler{};
#else // !defined(PROJECT_ENABLE_SPDLOG) || !defined(PROJECT_ENABLE_V2_ERRORS)
inline const iostream_exception_handler default_exception_handler{};
#endif // defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS)
#if defined(PROJECT_ENABLE_V2_ERRORS)
void handle_debug(std::string_view function_name, std::string_view msg);
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
void handle_error(std::string_view function_name, std::string_view msg);
void handle_exception(std::string_view function_name);
void handle_exception(std::string_view function_name, const std::exception &ex);
#if defined(PROJECT_ENABLE_V2_ERRORS)
void handle_info(std::string_view function_name, std::string_view msg);
void handle_trace(std::string_view function_name, std::string_view msg);
void handle_warn(std::string_view function_name, std::string_view msg);
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
void set_exception_handler(const i_exception_handler *handler);
#if defined(PROJECT_ENABLE_TESTING)
extern std::atomic<const i_exception_handler *> exception_handler;
[[nodiscard]] inline auto get_exception_handler()
-> const i_exception_handler * {
return exception_handler;
}
#endif // defined(PROJECT_ENABLE_TESTING)
} // namespace fifthgrid::utils::error
#endif // FIFTHGRID_INCLUDE_UTILS_ERROR_HPP_

View File

@@ -0,0 +1,190 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_FILE_HPP_
#define FIFTHGRID_INCLUDE_UTILS_FILE_HPP_
#include "utils/config.hpp"
#include "utils/path.hpp"
#include "utils/string.hpp"
#include "utils/types/file/i_directory.hpp"
#include "utils/types/file/i_file.hpp"
#include "utils/types/file/i_fs_item.hpp"
namespace fifthgrid::utils::directory {
[[nodiscard]] auto temp() -> std::string;
}
namespace fifthgrid::utils::file {
[[nodiscard]] auto change_to_process_directory() -> bool;
// INFO: has test
[[nodiscard]] auto create_temp_name(std::string_view file_part) -> std::string;
// INFO: has test
[[nodiscard]] auto create_temp_name(std::wstring_view file_part)
-> std::wstring;
// INFO: has test
[[nodiscard]] inline auto
directory_exists_in_path(std::string_view path, std::string_view sub_directory)
-> bool;
// INFO: has test
[[nodiscard]] inline auto
directory_exists_in_path(std::wstring_view path,
std::wstring_view sub_directory) -> bool;
// INFO: has test
[[nodiscard]] inline auto file_exists_in_path(std::string_view path,
std::string_view file_name)
-> bool;
// INFO: has test
[[nodiscard]] inline auto file_exists_in_path(std::wstring_view path,
std::wstring_view file_name)
-> bool;
// INFO: has test
[[nodiscard]] auto get_free_drive_space(std::string_view path)
-> std::optional<std::uint64_t>;
// INFO: has test
[[nodiscard]] auto get_free_drive_space(std::wstring_view path)
-> std::optional<std::uint64_t>;
// INFO: has test
[[nodiscard]] auto get_time(std::string_view path, time_type type)
-> std::optional<std::uint64_t>;
// INFO: has test
[[nodiscard]] auto get_time(std::wstring_view path, time_type type)
-> std::optional<std::uint64_t>;
// INFO: has test
[[nodiscard]] auto get_times(std::string_view path)
-> std::optional<file_times>;
// INFO: has test
[[nodiscard]] auto get_times(std::wstring_view path)
-> std::optional<file_times>;
// INFO: has test
[[nodiscard]] auto get_total_drive_space(std::string_view path)
-> std::optional<std::uint64_t>;
// INFO: has test
[[nodiscard]] auto get_total_drive_space(std::wstring_view path)
-> std::optional<std::uint64_t>;
#if defined(PROJECT_ENABLE_LIBDSM)
[[nodiscard]] auto
smb_create_and_validate_relative_path(std::string_view smb_path,
std::string_view rel_path) -> std::string;
// INFO: has test
[[nodiscard]] auto smb_create_relative_path(std::string_view smb_path)
-> std::string;
// INFO: has test
[[nodiscard]] auto smb_create_search_path(std::string_view smb_path)
-> std::string;
// INFO: has test
[[nodiscard]] auto smb_create_smb_path(std::string_view smb_path,
std::string_view rel_path)
-> std::string;
[[nodiscard]] auto smb_get_parent_path(std::string_view smb_path)
-> std::string;
[[nodiscard]] auto smb_get_root_path(std::string_view smb_path) -> std::string;
[[nodiscard]] auto smb_get_unc_path(std::string_view smb_path) -> std::string;
[[nodiscard]] auto smb_get_uri_path(std::string_view smb_path) -> std::string;
[[nodiscard]] auto smb_get_uri_path(std::string_view smb_path,
std::string_view user,
std::string_view password) -> std::string;
// INFO: has test
[[nodiscard]] auto smb_parent_is_same(std::string_view smb_path1,
std::string_view smb_path2) -> bool;
#define SMB_MOD_RW2 \
(SMB_MOD_READ | SMB_MOD_WRITE | SMB_MOD_READ_EXT | SMB_MOD_WRITE_EXT | \
SMB_MOD_READ_ATTR | SMB_MOD_WRITE_ATTR | SMB_MOD_READ_CTL)
#endif // defined(PROJECT_ENABLE_LIBDSM)
#if defined(PROJECT_ENABLE_JSON)
#if defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST)
// INFO: has test
[[nodiscard]] auto
read_json_file(std::string_view path, nlohmann::json &data,
std::optional<std::string_view> password = std::nullopt) -> bool;
// INFO: has test
[[nodiscard]] auto
read_json_file(std::wstring_view path, nlohmann::json &data,
std::optional<std::wstring_view> password = std::nullopt)
-> bool;
// INFO: has test
[[nodiscard]] auto
write_json_file(std::string_view path, const nlohmann::json &data,
std::optional<std::string_view> password = std::nullopt)
-> bool;
// INFO: has test
[[nodiscard]] auto
write_json_file(std::wstring_view path, const nlohmann::json &data,
std::optional<std::wstring_view> password = std::nullopt)
-> bool;
#else // !defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST)
// INFO: has test
[[nodiscard]] auto read_json_file(std::string_view path, nlohmann::json &data)
-> bool;
// INFO: has test
[[nodiscard]] auto read_json_file(std::wstring_view path, nlohmann::json &data)
-> bool;
// INFO: has test
[[nodiscard]] auto write_json_file(std::string_view path,
const nlohmann::json &data) -> bool;
// INFO: has test
[[nodiscard]] auto write_json_file(std::wstring_view path,
const nlohmann::json &data) -> bool;
#endif // defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST)
#endif // defined(PROJECT_ENABLE_JSON)
} // namespace fifthgrid::utils::file
#endif // FIFTHGRID_INCLUDE_UTILS_FILE_HPP_
#include "utils/file_directory.hpp"
#include "utils/file_enc_file.hpp"
#include "utils/file_file.hpp"
#include "utils/file_smb_directory.hpp"
#include "utils/file_smb_file.hpp"
#include "utils/file_thread_file.hpp"

View File

@@ -0,0 +1,124 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_FILE_DIRECTORY_HPP_
#define FIFTHGRID_INCLUDE_UTILS_FILE_DIRECTORY_HPP_
#include "utils/file.hpp"
namespace fifthgrid::utils::file {
class directory final : public i_directory {
public:
using directory_t = std::unique_ptr<directory>;
directory() noexcept = default;
directory(std::string_view path, stop_type *stop_requested = nullptr)
: path_(utils::path::absolute(path)), stop_requested_(stop_requested) {}
directory(std::wstring_view path, stop_type *stop_requested = nullptr)
: path_(utils::path::absolute(utils::string::to_utf8(path))),
stop_requested_(stop_requested) {}
directory(const directory &) noexcept = delete;
directory(directory &&move_dir) noexcept = default;
~directory() override = default;
private:
std::string path_;
stop_type *stop_requested_{nullptr};
public:
[[nodiscard]] auto copy_to(std::string_view new_path, bool overwrite) const
-> bool override;
[[nodiscard]] auto count(bool recursive = false) const
-> std::uint64_t override;
[[nodiscard]] auto create_directory(std::string_view path = "") const
-> fs_directory_t override;
[[nodiscard]] auto create_file(std::string_view file_name,
bool read_only) const -> fs_file_t override;
[[nodiscard]] auto exists() const -> bool override;
[[nodiscard]] auto get_directory(std::string_view path) const
-> fs_directory_t override;
[[nodiscard]] auto get_directories() const
-> std::vector<fs_directory_t> override;
[[nodiscard]] auto get_file(std::string_view path) const
-> fs_file_t override;
[[nodiscard]] auto get_files() const -> std::vector<fs_file_t> override;
[[nodiscard]] auto get_items() const -> std::vector<fs_item_t> override;
[[nodiscard]] auto get_path() const -> std::string override { return path_; }
[[nodiscard]] auto is_stop_requested() const -> bool override;
[[nodiscard]] auto is_symlink() const -> bool override;
[[nodiscard]] auto move_to(std::string_view new_path) -> bool override;
[[nodiscard]] auto remove() -> bool override;
[[nodiscard]] auto remove_recursively() -> bool override;
[[nodiscard]] auto size(bool recursive = false) const
-> std::uint64_t override;
public:
auto operator=(const directory &) noexcept -> directory & = delete;
auto operator=(directory &&move_dir) noexcept -> directory & = default;
[[nodiscard]] operator bool() const override { return exists(); }
};
// INFO: has test
template <typename string_t>
[[nodiscard]] inline auto directory_exists_in_path_t(
std::basic_string_view<typename string_t::value_type> path,
std::basic_string_view<typename string_t::value_type> sub_directory)
-> bool {
return directory(utils::path::combine(path, {sub_directory})).exists();
}
// INFO: has test
inline auto directory_exists_in_path(std::string_view path,
std::string_view sub_directory) -> bool {
return directory_exists_in_path_t<std::string>(path, sub_directory);
}
// INFO: has test
inline auto directory_exists_in_path(std::wstring_view path,
std::wstring_view sub_directory) -> bool {
return directory_exists_in_path_t<std::wstring>(path, sub_directory);
}
} // namespace fifthgrid::utils::file
#endif // FIFTHGRID_INCLUDE_UTILS_FILE_DIRECTORY_HPP_

View File

@@ -0,0 +1,124 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_FILE_ENC_FILE_HPP_
#define FIFTHGRID_INCLUDE_UTILS_FILE_ENC_FILE_HPP_
#if defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST)
#include "utils/file.hpp"
namespace fifthgrid::utils::file {
class enc_file final : public i_file {
public:
[[nodiscard]] static auto attach_file(fs_file_t file) -> fs_file_t;
public:
enc_file() noexcept = default;
protected:
enc_file(fs_file_t file);
public:
enc_file(const enc_file &) = delete;
enc_file(enc_file &&move_file) noexcept : file_(std::move(move_file.file_)) {}
~enc_file() override { close(); }
private:
fs_file_t file_;
std::string encryption_token_;
public:
void close() override;
[[nodiscard]] auto copy_to(std::string_view new_path, bool overwrite) const
-> bool override;
[[nodiscard]] auto exists() const -> bool override { return file_->exists(); }
void flush() const override;
[[nodiscard]] auto get_handle() const -> native_handle override {
return file_->get_handle();
}
[[nodiscard]] auto get_path() const -> std::string override {
return file_->get_path();
}
[[nodiscard]] auto get_read_buffer_size() const -> std::uint32_t override {
return file_->get_read_buffer_size();
}
[[nodiscard]] auto get_time(time_type type) const
-> std::optional<std::uint64_t> override {
return file_->get_time(type);
}
[[nodiscard]] auto is_read_only() const -> bool override {
return file_->is_read_only();
}
[[nodiscard]] auto is_symlink() const -> bool override {
return file_->is_symlink();
}
[[nodiscard]] auto move_to(std::string_view new_path) -> bool override;
[[nodiscard]] auto read(unsigned char *data, std::size_t to_read,
std::uint64_t offset,
std::size_t *total_read = nullptr) -> bool override;
[[nodiscard]] auto remove() -> bool override;
auto set_read_buffer_size(std::uint32_t size) -> std::uint32_t override {
return file_->set_read_buffer_size(size);
}
[[nodiscard]] auto size() const -> std::optional<std::uint64_t> override;
[[nodiscard]] auto truncate(std::size_t size) -> bool override;
[[nodiscard]] auto write(const unsigned char *data, std::size_t to_write,
std::size_t offset,
std::size_t *total_written = nullptr)
-> bool override;
public:
[[nodiscard]] operator bool() const override {
return static_cast<bool>(*file_);
}
auto operator=(const enc_file &) noexcept -> enc_file & = delete;
auto operator=(enc_file &&move_file) noexcept -> enc_file & {
if (&move_file != this) {
file_ = std::move(move_file.file_);
}
return *this;
}
};
} // namespace fifthgrid::utils::file
#endif // defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST)
#endif // FIFTHGRID_INCLUDE_UTILS_FILE_ENC_FILE_HPP_

View File

@@ -0,0 +1,176 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_FILE_FILE_HPP_
#define FIFTHGRID_INCLUDE_UTILS_FILE_FILE_HPP_
#include "utils/file.hpp"
namespace fifthgrid::utils::file {
class file final : public i_file {
public:
// [[nodiscard]] static auto
// attach_file(native_handle handle,
// bool read_only = false) -> fs_file_t;
// INFO: has test
[[nodiscard]] static auto open_file(std::string_view path,
bool read_only = false) -> fs_file_t;
[[nodiscard]] static auto open_file(std::wstring_view path,
bool read_only = false) -> fs_file_t {
return open_file(utils::string::to_utf8(path), read_only);
}
// INFO: has test
[[nodiscard]] static auto
open_or_create_file(std::string_view path,
bool read_only = false) -> fs_file_t;
[[nodiscard]] static auto
open_or_create_file(std::wstring_view path,
bool read_only = false) -> fs_file_t {
return open_or_create_file(utils::string::to_utf8(path), read_only);
}
public:
file() noexcept = default;
file(std::string_view path)
: file_(nullptr), path_(utils::path::absolute(path)) {}
file(std::wstring_view path)
: file_(nullptr),
path_(utils::path::absolute(utils::string::to_utf8(path))) {}
private:
file(file_t file_ptr, std::string_view path, bool read_only)
: file_(std::move(file_ptr)), path_(path), read_only_(read_only) {}
public:
file(const file &) = delete;
file(file &&move_file) noexcept
: file_(std::move(move_file.file_)),
path_(std::move(move_file.path_)),
read_only_(move_file.read_only_) {}
~file() override { close(); }
private:
file_t file_;
std::string path_;
bool read_only_{false};
private:
std::atomic_uint32_t read_buffer_size{65536U};
private:
void open();
public:
void close() override;
[[nodiscard]] auto copy_to(std::string_view new_path,
bool overwrite) const -> bool override;
[[nodiscard]] auto exists() const -> bool override;
void flush() const override;
[[nodiscard]] auto get_handle() const -> native_handle override;
[[nodiscard]] auto get_path() const -> std::string override { return path_; }
[[nodiscard]] auto get_read_buffer_size() const -> std::uint32_t override {
return read_buffer_size;
}
[[nodiscard]] auto is_read_only() const -> bool override {
return read_only_;
}
[[nodiscard]] auto is_symlink() const -> bool override;
[[nodiscard]] auto move_to(std::string_view new_path) -> bool override;
[[nodiscard]] auto read(unsigned char *data, std::size_t to_read,
std::uint64_t offset,
std::size_t *total_read = nullptr) -> bool override;
[[nodiscard]] auto remove() -> bool override;
auto set_read_buffer_size(std::uint32_t size) -> std::uint32_t override {
read_buffer_size = size;
return read_buffer_size;
}
#if defined(PROJECT_ENABLE_LIBSODIUM)
[[nodiscard]] auto sha256() -> std::optional<std::string>;
#endif // defined(PROJECT_ENABLE_LIBSODIUM)
[[nodiscard]] auto size() const -> std::optional<std::uint64_t> override;
[[nodiscard]] auto truncate(std::size_t size) -> bool override;
[[nodiscard]] auto
write(const unsigned char *data, std::size_t to_write, std::size_t offset,
std::size_t *total_written = nullptr) -> bool override;
public:
auto operator=(const file &) noexcept -> file & = delete;
auto operator=(file &&move_file) noexcept -> file & {
if (&move_file != this) {
file_ = std::move(move_file.file_);
path_ = std::move(move_file.path_);
read_only_ = move_file.read_only_;
}
return *this;
}
[[nodiscard]] operator bool() const override { return file_ != nullptr; }
};
// INFO: has test
template <typename string_t>
[[nodiscard]] inline auto file_exists_in_path_t(
std::basic_string_view<typename string_t::value_type> path,
std::basic_string_view<typename string_t::value_type> file_name) -> bool {
return file(utils::path::combine(path, {file_name})).exists();
}
// INFO: has test
inline auto file_exists_in_path(std::string_view path,
std::string_view file_name) -> bool {
return file_exists_in_path_t<std::string>(path, file_name);
}
// INFO: has test
inline auto file_exists_in_path(std::wstring_view path,
std::wstring_view file_name) -> bool {
return file_exists_in_path_t<std::wstring>(path, file_name);
}
} // namespace fifthgrid::utils::file
#endif // FIFTHGRID_INCLUDE_UTILS_FILE_FILE_HPP_

View File

@@ -0,0 +1,140 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_FILE_SMB_DIRECTORY_HPP_
#define FIFTHGRID_INCLUDE_UTILS_FILE_SMB_DIRECTORY_HPP_
#if defined(PROJECT_ENABLE_LIBDSM)
#include "utils/file.hpp"
namespace fifthgrid::utils::file {
class smb_directory final : public i_directory {
public:
using smb_directory_t = std::unique_ptr<smb_directory>;
[[nodiscard]] static auto
open(std::string_view host, std::string_view user, std::string_view password,
std::string_view path,
stop_type *stop_requested = nullptr) -> smb_directory_t;
[[nodiscard]] static auto
open(std::wstring_view host, std::wstring_view user,
std::wstring_view password, std::wstring_view path,
stop_type *stop_requested = nullptr) -> smb_directory_t;
public:
smb_directory() noexcept = default;
smb_directory(const smb_directory &) noexcept = delete;
smb_directory(smb_directory &&) noexcept = default;
~smb_directory() override = default;
private:
smb_directory(std::string path, smb_session_t session,
std::string_view share_name, smb_tid tid,
stop_type *stop_requested)
: path_(std::move(path)),
session_(std::move(session)),
share_name_(share_name),
tid_(tid),
stop_requested_(stop_requested) {}
private:
std::string path_{};
smb_session_t session_{};
std::string share_name_{};
smb_tid tid_{};
stop_type *stop_requested_{nullptr};
public:
[[nodiscard]] auto
count(bool recursive = false) const -> std::uint64_t override;
[[nodiscard]] auto copy_to(std::string_view new_path,
bool overwrite) const -> bool override;
[[nodiscard]] auto
create_directory(std::string_view path = "") const -> fs_directory_t override;
[[nodiscard]] auto create_file(std::string_view file_name,
bool read_only) const -> fs_file_t override;
[[nodiscard]] auto exists() const -> bool override;
[[nodiscard]] auto
get_directory(std::string_view path) const -> fs_directory_t override;
[[nodiscard]] auto
get_directories() const -> std::vector<fs_directory_t> override;
[[nodiscard]] auto
get_file(std::string_view path) const -> fs_file_t override;
[[nodiscard]] auto get_files() const -> std::vector<fs_file_t> override;
[[nodiscard]] auto get_items() const -> std::vector<fs_item_t> override;
[[nodiscard]] auto get_path() const -> std::string override { return path_; }
[[nodiscard]] auto
get_time(time_type type) const -> std::optional<std::uint64_t> override;
[[nodiscard]] auto get_unc_path() const -> std::string {
return smb_get_unc_path(path_);
}
[[nodiscard]] auto get_uri_path() const -> std::string {
return smb_get_uri_path(path_);
}
[[nodiscard]] auto
get_uri_path(std::string_view user,
std::string_view password) const -> std::string {
return smb_get_uri_path(path_, user, password);
}
[[nodiscard]] auto is_stop_requested() const -> bool override;
[[nodiscard]] auto is_symlink() const -> bool override;
[[nodiscard]] auto move_to(std::string_view new_path) -> bool override;
[[nodiscard]] auto remove() -> bool override;
[[nodiscard]] auto remove_recursively() -> bool override;
[[nodiscard]] auto
size(bool recursive = false) const -> std::uint64_t override;
public:
auto operator=(const smb_directory &) noexcept -> smb_directory & = delete;
auto
operator=(smb_directory &&move_dir) noexcept -> smb_directory & = default;
[[nodiscard]] operator bool() const override { return session_ != nullptr; }
};
} // namespace fifthgrid::utils::file
#endif // defined(PROJECT_ENABLE_LIBDSM)
#endif // FIFTHGRID_INCLUDE_UTILS_FILE_SMB_DIRECTORY_HPP_

View File

@@ -0,0 +1,157 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_FILE_SMB_FILE_HPP_
#define FIFTHGRID_INCLUDE_UTILS_FILE_SMB_FILE_HPP_
#if defined(PROJECT_ENABLE_LIBDSM)
#include "utils/file.hpp"
namespace fifthgrid::utils::file {
class smb_file final : public i_file {
public:
smb_file() = default;
smb_file(std::optional<smb_fd> fd, std::string path, smb_session_t session,
std::string_view share_name, smb_tid tid)
: fd_(std::move(fd)),
path_(std::move(path)),
session_(std::move(session)),
share_name_(share_name),
tid_(tid) {}
smb_file(const smb_file &) = delete;
smb_file(smb_file &&f) noexcept
: fd_(std::move(f.fd_)),
path_(std::move(f.path_)),
read_buffer_size(f.get_read_buffer_size()),
read_only_(f.read_only_),
session_(std::move(f.session_)),
share_name_(std::move(f.share_name_)),
tid_(f.tid_) {}
~smb_file() override { close(); }
private:
std::optional<smb_fd> fd_;
std::string path_;
std::atomic_uint32_t read_buffer_size{65536U};
bool read_only_;
smb_session_t session_;
std::string share_name_;
smb_tid tid_;
public:
void close() override;
[[nodiscard]] auto copy_to(std::string_view new_path,
bool overwrite) const -> bool override;
[[nodiscard]] auto exists() const -> bool override;
void flush() const override;
[[nodiscard]] auto get_handle() const -> native_handle override {
return INVALID_HANDLE_VALUE;
}
[[nodiscard]] auto get_path() const -> std::string override { return path_; }
[[nodiscard]] auto get_read_buffer_size() const -> std::uint32_t override {
return read_buffer_size;
}
[[nodiscard]] static auto
get_time(smb_session *session, smb_tid tid, std::string path,
time_type type) -> std::optional<std::uint64_t>;
[[nodiscard]] auto
get_time(time_type type) const -> std::optional<std::uint64_t> override {
return get_time(session_.get(), tid_, path_, type);
}
[[nodiscard]] auto get_unc_path() const -> std::string {
return smb_get_unc_path(path_);
}
[[nodiscard]] auto get_uri_path() const -> std::string {
return smb_get_uri_path(path_);
}
[[nodiscard]] auto
get_uri_path(std::string_view user,
std::string_view password) const -> std::string {
return smb_get_uri_path(path_, user, password);
}
[[nodiscard]] auto is_read_only() const -> bool override {
return read_only_;
}
[[nodiscard]] auto is_symlink() const -> bool override;
[[nodiscard]] auto move_to(std::string_view new_path) -> bool override;
[[nodiscard]] auto open(bool read_only) -> bool;
[[nodiscard]] auto read(unsigned char *data, std::size_t to_read,
std::uint64_t offset,
std::size_t *total_read = nullptr) -> bool override;
[[nodiscard]] auto remove() -> bool override;
auto set_read_buffer_size(std::uint32_t size) -> std::uint32_t override {
read_buffer_size = size;
return read_buffer_size;
}
[[nodiscard]] auto size() const -> std::optional<std::uint64_t> override;
[[nodiscard]] auto truncate(std::size_t size) -> bool override;
[[nodiscard]] auto
write(const unsigned char *data, std::size_t to_write, std::size_t offset,
std::size_t *total_written = nullptr) -> bool override;
public:
auto operator=(const smb_file &) noexcept -> smb_file & = delete;
auto operator=(smb_file &&move_file) noexcept -> smb_file & {
if (this != &move_file) {
fd_ = std::move(move_file.fd_);
path_ = std::move(move_file.path_);
read_buffer_size = move_file.get_read_buffer_size();
read_only_ = move_file.read_only_;
session_ = std::move(move_file.session_);
share_name_ = std::move(move_file.share_name_);
tid_ = move_file.tid_;
}
return *this;
}
[[nodiscard]] operator bool() const override { return fd_.has_value(); }
};
} // namespace fifthgrid::utils::file
#endif // defined(PROJECT_ENABLE_LIBDSM)
#endif // FIFTHGRID_INCLUDE_UTILS_FILE_SMB_FILE_HPP_

View File

@@ -0,0 +1,180 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_FILE_THREAD_FILE_HPP_
#define FIFTHGRID_INCLUDE_UTILS_FILE_THREAD_FILE_HPP_
#include "utils/file.hpp"
namespace fifthgrid::utils::file {
class thread_file final : public i_file {
public:
// [[nodiscard]] static auto
// attach_file(native_handle handle,
// bool read_only = false) -> fs_file_t;
[[nodiscard]] static auto attach_file(fs_file_t file) -> fs_file_t;
[[nodiscard]] static auto open_file(std::string_view path,
bool read_only = false) -> fs_file_t;
[[nodiscard]] static auto open_file(std::wstring_view path,
bool read_only = false) -> fs_file_t {
return open_file(utils::string::to_utf8(path), read_only);
}
[[nodiscard]] static auto
open_or_create_file(std::string_view path,
bool read_only = false) -> fs_file_t;
[[nodiscard]] static auto
open_or_create_file(std::wstring_view path,
bool read_only = false) -> fs_file_t {
return open_or_create_file(utils::string::to_utf8(path), read_only);
}
public:
thread_file() noexcept = default;
thread_file(std::string_view path);
thread_file(std::wstring_view path);
protected:
thread_file(fs_file_t file);
public:
thread_file(const thread_file &) = delete;
thread_file(thread_file &&move_file) noexcept
: file_(std::move(move_file.file_)) {}
~thread_file() override;
private:
using action_t = std::function<bool()>;
struct io_item final {
action_t action;
bool complete{false};
std::unique_ptr<std::mutex> mtx{
std::make_unique<std::mutex>(),
};
mutable std::unique_ptr<std::condition_variable> notify{
std::make_unique<std::condition_variable>(),
};
bool success{false};
void done(bool result);
void wait() const;
};
private:
fs_file_t file_;
private:
mutable std::vector<std::shared_ptr<io_item>> actions_;
mutable std::unique_ptr<std::thread> io_thread_;
mutable std::unique_ptr<std::mutex> mtx_{std::make_unique<std::mutex>()};
mutable std::unique_ptr<std::condition_variable> notify_{
std::make_unique<std::condition_variable>(),
};
stop_type stop_requested_{false};
private:
auto do_io(action_t action) const -> bool;
void thread_func() const;
public:
void close() override;
[[nodiscard]] auto copy_to(std::string_view new_path,
bool overwrite) const -> bool override;
[[nodiscard]] auto exists() const -> bool override { return file_->exists(); }
void flush() const override;
[[nodiscard]] auto get_handle() const -> native_handle override {
return file_->get_handle();
}
[[nodiscard]] auto get_path() const -> std::string override {
return file_->get_path();
}
[[nodiscard]] auto get_read_buffer_size() const -> std::uint32_t override {
return file_->get_read_buffer_size();
}
[[nodiscard]] auto
get_time(time_type type) const -> std::optional<std::uint64_t> override {
return file_->get_time(type);
}
[[nodiscard]] auto is_read_only() const -> bool override {
return file_->is_read_only();
}
[[nodiscard]] auto is_symlink() const -> bool override {
return file_->is_symlink();
}
[[nodiscard]] auto move_to(std::string_view new_path) -> bool override;
[[nodiscard]] auto read(unsigned char *data, std::size_t to_read,
std::uint64_t offset,
std::size_t *total_read = nullptr) -> bool override;
[[nodiscard]] auto remove() -> bool override;
auto set_read_buffer_size(std::uint32_t size) -> std::uint32_t override {
return file_->set_read_buffer_size(size);
}
[[nodiscard]] auto size() const -> std::optional<std::uint64_t> override;
[[nodiscard]] auto truncate(std::size_t size) -> bool override;
[[nodiscard]] auto
write(const unsigned char *data, std::size_t to_write, std::size_t offset,
std::size_t *total_written = nullptr) -> bool override;
public:
[[nodiscard]] operator bool() const override {
return static_cast<bool>(*file_);
}
auto operator=(const thread_file &) noexcept -> thread_file & = delete;
auto operator=(thread_file &&move_file) noexcept -> thread_file & {
if (&move_file != this) {
file_ = std::move(move_file.file_);
}
return *this;
}
};
} // namespace fifthgrid::utils::file
#endif // FIFTHGRID_INCLUDE_UTILS_FILE_THREAD_FILE_HPP_

View File

@@ -0,0 +1,243 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_HASH_HPP_
#define FIFTHGRID_INCLUDE_UTILS_HASH_HPP_
#if defined(PROJECT_ENABLE_LIBSODIUM)
#include "utils/config.hpp"
#include "utils/error.hpp"
namespace fifthgrid::utils::hash {
using hash_32_t = std::array<unsigned char, 4U>;
using hash_64_t = std::array<unsigned char, 8U>;
using hash_128_t = std::array<unsigned char, 16U>;
using hash_256_t = std::array<unsigned char, 32U>;
using hash_384_t = std::array<unsigned char, 48U>;
using hash_512_t = std::array<unsigned char, 64U>;
[[nodiscard]] auto create_hash_blake2b_32(std::string_view data) -> hash_32_t;
[[nodiscard]] auto create_hash_blake2b_32(std::wstring_view data) -> hash_32_t;
[[nodiscard]] auto create_hash_blake2b_32(const data_buffer &data) -> hash_32_t;
[[nodiscard]] auto create_hash_blake2b_64(std::string_view data) -> hash_64_t;
[[nodiscard]] auto create_hash_blake2b_64(std::wstring_view data) -> hash_64_t;
[[nodiscard]] auto create_hash_blake2b_64(const data_buffer &data) -> hash_64_t;
[[nodiscard]] auto create_hash_blake2b_128(std::string_view data) -> hash_128_t;
[[nodiscard]] auto create_hash_blake2b_128(std::wstring_view data)
-> hash_128_t;
[[nodiscard]] auto create_hash_blake2b_128(const data_buffer &data)
-> hash_128_t;
[[nodiscard]] auto create_hash_blake2b_256(std::string_view data) -> hash_256_t;
[[nodiscard]] auto create_hash_blake2b_256(std::wstring_view data)
-> hash_256_t;
[[nodiscard]] auto create_hash_blake2b_256(const data_buffer &data)
-> hash_256_t;
[[nodiscard]] auto create_hash_blake2b_384(std::string_view data) -> hash_384_t;
[[nodiscard]] auto create_hash_blake2b_384(std::wstring_view data)
-> hash_384_t;
[[nodiscard]] auto create_hash_blake2b_384(const data_buffer &data)
-> hash_384_t;
[[nodiscard]] auto create_hash_blake2b_512(std::wstring_view data)
-> hash_512_t;
[[nodiscard]] auto create_hash_blake2b_512(const data_buffer &data)
-> hash_512_t;
[[nodiscard]] auto create_hash_blake2b_512(std::string_view data) -> hash_512_t;
template <typename hash_t>
[[nodiscard]] auto create_hash_blake2b_t(const unsigned char *data,
std::size_t data_size) -> hash_t;
[[nodiscard]] auto create_hash_sha256(std::string_view data) -> hash_256_t;
[[nodiscard]] auto create_hash_sha256(std::wstring_view data) -> hash_256_t;
[[nodiscard]] auto create_hash_sha256(const data_buffer &data) -> hash_256_t;
[[nodiscard]] auto create_hash_sha256(const unsigned char *data,
std::size_t data_size) -> hash_256_t;
[[nodiscard]] auto create_hash_sha512(std::string_view data) -> hash_512_t;
[[nodiscard]] auto create_hash_sha512(std::wstring_view data) -> hash_512_t;
[[nodiscard]] auto create_hash_sha512(const data_buffer &data) -> hash_512_t;
[[nodiscard]] auto create_hash_sha512(const unsigned char *data,
std::size_t data_size) -> hash_512_t;
template <typename hash_t>
[[nodiscard]] inline auto default_create_hash() -> const
std::function<hash_t(const unsigned char *data, std::size_t size)> &;
template <typename hash_t>
auto create_hash_blake2b_t(const unsigned char *data, std::size_t data_size)
-> hash_t {
FIFTHGRID_USES_FUNCTION_NAME();
hash_t hash{};
crypto_generichash_blake2b_state state{};
auto res = crypto_generichash_blake2b_init(&state, nullptr, 0U, hash.size());
if (res != 0) {
throw utils::error::create_exception(function_name,
{
"failed to initialize blake2b",
std::to_string(hash.size() * 8U),
std::to_string(res),
});
}
res = crypto_generichash_blake2b_update(&state, data, data_size);
if (res != 0) {
throw utils::error::create_exception(function_name,
{
"failed to update blake2b",
std::to_string(hash.size() * 8U),
std::to_string(res),
});
}
res = crypto_generichash_blake2b_final(&state, hash.data(), hash.size());
if (res != 0) {
throw utils::error::create_exception(function_name,
{
"failed to finalize blake2b",
std::to_string(hash.size() * 8U),
std::to_string(res),
});
}
return hash;
}
inline const std::function<hash_32_t(const unsigned char *data,
std::size_t size)>
blake2b_32_hasher =
[](const unsigned char *data, std::size_t data_size) -> hash_32_t {
return create_hash_blake2b_t<hash_32_t>(data, data_size);
};
inline const std::function<hash_64_t(const unsigned char *data,
std::size_t size)>
blake2b_64_hasher =
[](const unsigned char *data, std::size_t data_size) -> hash_64_t {
return create_hash_blake2b_t<hash_64_t>(data, data_size);
};
inline const std::function<hash_128_t(const unsigned char *data,
std::size_t size)>
blake2b_128_hasher =
[](const unsigned char *data, std::size_t data_size) -> hash_128_t {
return create_hash_blake2b_t<hash_128_t>(data, data_size);
};
inline const std::function<hash_256_t(const unsigned char *data,
std::size_t size)>
blake2b_256_hasher =
[](const unsigned char *data, std::size_t data_size) -> hash_256_t {
return create_hash_blake2b_t<hash_256_t>(data, data_size);
};
inline const std::function<hash_384_t(const unsigned char *data,
std::size_t size)>
blake2b_384_hasher =
[](const unsigned char *data, std::size_t data_size) -> hash_384_t {
return create_hash_blake2b_t<hash_384_t>(data, data_size);
};
inline const std::function<hash_512_t(const unsigned char *data,
std::size_t size)>
blake2b_512_hasher =
[](const unsigned char *data, std::size_t data_size) -> hash_512_t {
return create_hash_blake2b_t<hash_512_t>(data, data_size);
};
inline const std::function<hash_256_t(const unsigned char *data,
std::size_t size)>
sha256_hasher =
[](const unsigned char *data, std::size_t data_size) -> hash_256_t {
return create_hash_sha256(data, data_size);
};
inline const std::function<hash_512_t(const unsigned char *data,
std::size_t size)>
sha512_hasher =
[](const unsigned char *data, std::size_t data_size) -> hash_512_t {
return create_hash_sha512(data, data_size);
};
template <>
[[nodiscard]] inline auto default_create_hash<hash_32_t>() -> const
std::function<hash_32_t(const unsigned char *data, std::size_t size)> & {
return blake2b_32_hasher;
}
template <>
[[nodiscard]] inline auto default_create_hash<hash_64_t>() -> const
std::function<hash_64_t(const unsigned char *data, std::size_t size)> & {
return blake2b_64_hasher;
}
template <>
[[nodiscard]] inline auto default_create_hash<hash_128_t>() -> const
std::function<hash_128_t(const unsigned char *data, std::size_t size)> & {
return blake2b_128_hasher;
}
template <>
[[nodiscard]] inline auto default_create_hash<hash_256_t>() -> const
std::function<hash_256_t(const unsigned char *data, std::size_t size)> & {
return blake2b_256_hasher;
}
template <>
[[nodiscard]] inline auto default_create_hash<hash_384_t>() -> const
std::function<hash_384_t(const unsigned char *data, std::size_t size)> & {
return blake2b_384_hasher;
}
template <>
[[nodiscard]] inline auto default_create_hash<hash_512_t>() -> const
std::function<hash_512_t(const unsigned char *data, std::size_t size)> & {
return blake2b_512_hasher;
}
} // namespace fifthgrid::utils::hash
#endif // defined(PROJECT_ENABLE_LIBSODIUM)
#endif // FIFTHGRID_INCLUDE_UTILS_HASH_HPP_

View File

@@ -0,0 +1,526 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_PATH_HPP_
#define FIFTHGRID_INCLUDE_UTILS_PATH_HPP_
#include "utils/config.hpp"
#include "utils/string.hpp"
namespace fifthgrid::utils::path {
inline constexpr std::string_view backslash{"\\"};
inline constexpr std::wstring_view backslash_w{L"\\"};
inline constexpr std::string_view dot{"."};
inline constexpr std::wstring_view dot_w{L"."};
inline constexpr std::string_view dot_backslash{".\\"};
inline constexpr std::wstring_view dot_backslash_w{L".\\"};
inline constexpr std::string_view dot_slash{"./"};
inline constexpr std::wstring_view dot_slash_w{L"./"};
inline constexpr std::string_view long_notation{"\\\\?\\"};
inline constexpr std::wstring_view long_notation_w{L"\\\\?\\"};
inline constexpr std::string_view slash{"/"};
inline constexpr std::wstring_view slash_w{L"/"};
#if defined(_WIN32)
inline constexpr std::string_view directory_seperator{backslash};
inline constexpr std::wstring_view directory_seperator_w{backslash_w};
inline constexpr std::string_view not_directory_seperator{slash};
inline constexpr std::wstring_view not_directory_seperator_w{slash_w};
inline constexpr std::string_view unc_notation{"\\\\"};
inline constexpr std::wstring_view unc_notation_w{L"\\\\"};
#else // !defined(_WIN32)
inline constexpr std::string_view directory_seperator{slash};
inline constexpr std::wstring_view directory_seperator_w{slash_w};
inline constexpr std::string_view not_directory_seperator{backslash};
inline constexpr std::wstring_view not_directory_seperator_w{backslash_w};
#endif // defined(_WIN32)
template <typename char_t>
[[nodiscard]] inline constexpr auto
get_backslash() -> std::basic_string_view<char_t>;
template <>
[[nodiscard]] inline constexpr auto
get_backslash<char>() -> std::basic_string_view<char> {
return backslash;
}
template <>
[[nodiscard]] inline constexpr auto
get_backslash<wchar_t>() -> std::basic_string_view<wchar_t> {
return backslash_w;
}
template <typename char_t>
[[nodiscard]] inline constexpr auto
get_directory_seperator() -> std::basic_string_view<char_t>;
template <>
[[nodiscard]] inline constexpr auto
get_directory_seperator<char>() -> std::basic_string_view<char> {
return directory_seperator;
}
template <>
[[nodiscard]] inline constexpr auto
get_directory_seperator<wchar_t>() -> std::basic_string_view<wchar_t> {
return directory_seperator_w;
}
template <typename char_t>
[[nodiscard]] inline constexpr auto
get_not_directory_seperator() -> std::basic_string_view<char_t>;
template <>
[[nodiscard]] inline constexpr auto
get_not_directory_seperator<char>() -> std::basic_string_view<char> {
return not_directory_seperator;
}
template <>
[[nodiscard]] inline constexpr auto
get_not_directory_seperator<wchar_t>() -> std::basic_string_view<wchar_t> {
return not_directory_seperator_w;
}
template <typename char_t>
[[nodiscard]] inline constexpr auto get_dot() -> std::basic_string_view<char_t>;
template <>
[[nodiscard]] inline constexpr auto
get_dot<char>() -> std::basic_string_view<char> {
return dot;
}
template <>
[[nodiscard]] inline constexpr auto
get_dot<wchar_t>() -> std::basic_string_view<wchar_t> {
return dot_w;
}
template <typename char_t>
[[nodiscard]] inline constexpr auto
get_dot_backslash() -> std::basic_string_view<char_t>;
template <>
[[nodiscard]] inline constexpr auto
get_dot_backslash<char>() -> std::basic_string_view<char> {
return dot_backslash;
}
template <>
[[nodiscard]] inline constexpr auto
get_dot_backslash<wchar_t>() -> std::basic_string_view<wchar_t> {
return dot_backslash_w;
}
template <typename char_t>
[[nodiscard]] inline constexpr auto
get_dot_slash() -> std::basic_string_view<char_t>;
template <>
[[nodiscard]] inline constexpr auto
get_dot_slash<char>() -> std::basic_string_view<char> {
return dot_slash;
}
template <>
[[nodiscard]] inline constexpr auto
get_dot_slash<wchar_t>() -> std::basic_string_view<wchar_t> {
return dot_slash_w;
}
template <typename char_t>
[[nodiscard]] inline constexpr auto
get_long_notation() -> std::basic_string_view<char_t>;
template <>
[[nodiscard]] inline constexpr auto
get_long_notation<char>() -> std::basic_string_view<char> {
return long_notation;
}
template <>
[[nodiscard]] inline constexpr auto
get_long_notation<wchar_t>() -> std::basic_string_view<wchar_t> {
return long_notation_w;
}
template <typename char_t>
[[nodiscard]] inline constexpr auto
get_slash() -> std::basic_string_view<char_t>;
template <>
[[nodiscard]] inline constexpr auto
get_slash<char>() -> std::basic_string_view<char> {
return slash;
}
template <>
[[nodiscard]] inline constexpr auto
get_slash<wchar_t>() -> std::basic_string_view<wchar_t> {
return slash_w;
}
#if defined(_WIN32)
template <typename char_t>
[[nodiscard]] inline constexpr auto
get_unc_notation() -> std::basic_string_view<char_t>;
template <>
[[nodiscard]] inline constexpr auto
get_unc_notation<char>() -> std::basic_string_view<char> {
return unc_notation;
}
template <>
[[nodiscard]] inline constexpr auto
get_unc_notation<wchar_t>() -> std::basic_string_view<wchar_t> {
return unc_notation_w;
}
#endif // defined(_WIN32)
template <typename string_t>
[[nodiscard]] inline auto get_current_path() -> string_t;
[[nodiscard]] auto absolute(std::string_view path) -> std::string;
[[nodiscard]] auto absolute(std::wstring_view path) -> std::wstring;
[[nodiscard]] inline auto
combine(std::string_view path,
const std::vector<std::string_view> &paths) -> std::string;
[[nodiscard]] inline auto
combine(std::wstring_view path,
const std::vector<std::wstring_view> &paths) -> std::wstring;
[[nodiscard]] auto contains_trash_directory(std::string_view path) -> bool;
[[nodiscard]] auto contains_trash_directory(std::wstring_view path) -> bool;
[[nodiscard]] auto inline create_api_path(std::string_view path) -> std::string;
[[nodiscard]] auto inline create_api_path(std::wstring_view path)
-> std::wstring;
[[nodiscard]] auto exists(std::string_view path) -> bool;
[[nodiscard]] auto exists(std::wstring_view path) -> bool;
[[nodiscard]] inline auto finalize(std::string_view path) -> std::string;
[[nodiscard]] inline auto finalize(std::wstring_view path) -> std::wstring;
[[nodiscard]] auto
find_program_in_path(const std::string &name_without_extension) -> std::string;
[[nodiscard]] auto
find_program_in_path(std::wstring_view name_without_extension) -> std::wstring;
template <typename string_t>
inline auto
format_path(string_t &path,
std::basic_string_view<typename string_t::value_type> sep,
std::basic_string_view<typename string_t::value_type> not_sep)
-> string_t &;
[[nodiscard]] inline auto
get_parent_api_path(std::string_view path) -> std::string;
[[nodiscard]] inline auto
get_parent_api_path(std::wstring_view path) -> std::wstring;
[[nodiscard]] auto get_parent_path(std::string_view path) -> std::string;
[[nodiscard]] auto get_parent_path(std::wstring_view path) -> std::wstring;
[[nodiscard]] inline auto
get_parts(std::string_view path) -> std::vector<std::string>;
[[nodiscard]] inline auto
get_parts_w(std::wstring_view path) -> std::vector<std::wstring>;
[[nodiscard]] auto get_relative_path(std::string_view path,
std::string_view root_path) -> std::string;
[[nodiscard]] auto
get_relative_path(std::wstring_view path,
std::wstring_view root_path) -> std::wstring;
[[nodiscard]] auto make_file_uri(std::string_view path) -> std::string;
[[nodiscard]] auto make_file_uri(std::wstring_view path) -> std::wstring;
[[nodiscard]] auto strip_to_file_name(std::string path) -> std::string;
[[nodiscard]] auto strip_to_file_name(std::wstring path) -> std::wstring;
[[nodiscard]] auto unmake_file_uri(std::string_view uri) -> std::string;
[[nodiscard]] auto unmake_file_uri(std::wstring_view uri) -> std::wstring;
template <typename string_t>
[[nodiscard]] inline auto combine_t(
std::basic_string_view<typename string_t::value_type> path,
const std::vector<std::basic_string_view<typename string_t::value_type>>
&paths) -> string_t {
auto dir_sep_t =
string_t{get_directory_seperator<typename string_t::value_type>()};
return absolute(
std::accumulate(paths.begin(), paths.end(),
std::basic_string<typename string_t::value_type>{path},
[&dir_sep_t](auto next_path, auto &&path_part) {
if (next_path.empty()) {
return string_t{path_part};
}
return next_path + dir_sep_t + string_t{path_part};
}));
}
inline auto combine(std::string_view path,
const std::vector<std::string_view> &paths) -> std::string {
return combine_t<std::string>(path, paths);
}
inline auto
combine(std::wstring_view path,
const std::vector<std::wstring_view> &paths) -> std::wstring {
return combine_t<std::wstring>(path, paths);
}
template <typename string_t>
[[nodiscard]] inline auto create_api_path_t(
std::basic_string_view<typename string_t::value_type> path) -> string_t {
auto backslash_t = get_backslash<typename string_t::value_type>();
auto dot_backslash_t = get_dot_backslash<typename string_t::value_type>();
auto dot_slash_t = get_dot_slash<typename string_t::value_type>();
auto dot_t = get_dot<typename string_t::value_type>();
auto slash_t = get_slash<typename string_t::value_type>();
#if defined(_WIN32)
auto long_notation_t = get_long_notation<typename string_t::value_type>();
if (utils::string::begins_with(path, long_notation_t)) {
path = path.substr(long_notation_t.size());
}
#endif // defined(_WIN32)
if (path.empty() || path == backslash_t || path == dot_t ||
path == dot_slash_t || path == slash_t || path == dot_backslash_t) {
return string_t{slash_t};
}
string_t api_path{path};
#if defined(_WIN32)
if ((api_path.size() >= 2U) && (api_path.at(1U) == ':')) {
api_path = api_path.substr(2U);
}
#endif // defined(_WIN32)
format_path(api_path, slash_t, backslash_t);
while (utils::string::begins_with(api_path, dot_slash_t)) {
api_path = api_path.substr(dot_slash_t.size());
}
if (api_path.at(0U) != slash_t.at(0U)) {
return string_t{slash_t} + api_path;
}
return api_path;
}
inline auto create_api_path(std::string_view path) -> std::string {
return create_api_path_t<std::string>(path);
}
inline auto create_api_path(std::wstring_view path) -> std::wstring {
return create_api_path_t<std::wstring>(path);
}
template <typename string_t>
[[nodiscard]] inline auto finalize_t(
std::basic_string_view<typename string_t::value_type> path) -> string_t {
string_t dir_sep_t{get_directory_seperator<typename string_t::value_type>()};
string_t fmt_path{path};
if (fmt_path.empty()) {
return fmt_path;
}
format_path(fmt_path, dir_sep_t,
get_not_directory_seperator<typename string_t::value_type>());
#if defined(_WIN32)
auto unc_notation_t = get_unc_notation<typename string_t::value_type>();
if (utils::string::begins_with(fmt_path, unc_notation_t)) {
return fmt_path;
}
auto dot_t = get_dot<typename string_t::value_type>();
auto dot_sep_t = string_t{dot_t} + dir_sep_t;
if (fmt_path == dot_t || fmt_path == dot_sep_t) {
return get_current_path<string_t>();
}
if (fmt_path == dir_sep_t) {
#if defined(PROJECT_ENABLE_WIN32_LONG_PATH_NAMES)
return get_current_path<string_t>().substr(0U, long_notation.size() + 2U);
#else // !defined(PROJECT_ENABLE_WIN32_LONG_PATH_NAMES)
return get_current_path<string_t>().substr(0U, 2U);
#endif // defined(PROJECT_ENABLE_WIN32_LONG_PATH_NAMES)
}
if (utils::string::begins_with(fmt_path, dir_sep_t)) {
#if defined(PROJECT_ENABLE_WIN32_LONG_PATH_NAMES)
return get_current_path<string_t>().substr(0U, long_notation.size() + 2U) +
fmt_path;
#else // !defined(PROJECT_ENABLE_WIN32_LONG_PATH_NAMES)
return get_current_path<string_t>().substr(0U, 2U) + fmt_path;
#endif // defined(PROJECT_ENABLE_WIN32_LONG_PATH_NAMES)
}
if (utils::string::begins_with(fmt_path, dot_sep_t)) {
return get_current_path<string_t>() + dir_sep_t + fmt_path.substr(2U);
}
#if defined(PROJECT_ENABLE_WIN32_LONG_PATH_NAMES)
return string_t{get_long_notation<typename string_t::value_type>()} +
fmt_path;
#endif // defined(PROJECT_ENABLE_WIN32_LONG_PATH_NAMES)
#endif // defined(_WIN32)
return fmt_path;
}
inline auto finalize(std::string_view path) -> std::string {
return finalize_t<std::string>(path);
}
inline auto finalize(std::wstring_view path) -> std::wstring {
return finalize_t<std::wstring>(path);
}
template <typename string_t>
inline auto
format_path(string_t &path,
std::basic_string_view<typename string_t::value_type> sep,
std::basic_string_view<typename string_t::value_type> not_sep)
-> string_t & {
utils::string::replace(path, not_sep, sep);
#if defined(_WIN32)
auto is_unc{false};
auto long_notation_t = get_long_notation<typename string_t::value_type>();
auto unc_notation_t = get_unc_notation<typename string_t::value_type>();
if (utils::string::begins_with(path, long_notation_t)) {
path = path.substr(long_notation_t.size());
} else if (utils::string::begins_with(path, unc_notation_t)) {
path = path.substr(unc_notation_t.size());
utils::string::left_trim(path, sep.at(0U));
is_unc = true;
}
#endif // defined(_WIN32)
string_t double_sep(2U, sep.at(0U));
while (utils::string::contains(path, double_sep)) {
utils::string::replace(path, double_sep, sep);
}
if (path != sep) {
utils::string::right_trim(path, sep.at(0U));
}
#if defined(_WIN32)
if (is_unc) {
path = string_t{unc_notation_t} + path;
} else if ((path.size() >= 2U) && (path.at(1U) == ':')) {
path[0U] = utils::string::to_lower(string_t(1U, path.at(0U))).at(0U);
}
#endif // defined(_WIN32)
return path;
}
template <>
[[nodiscard]] inline auto get_current_path<std::string>() -> std::string {
#if defined(_WIN32)
std::string path;
path.resize(fifthgrid::max_path_length + 1U);
::GetCurrentDirectoryA(static_cast<DWORD>(path.size()), path.data());
path = path.c_str();
return finalize(path);
#else // !defined(_WIN32)
return finalize(std::filesystem::current_path().string());
#endif // defined(_WIN32)
}
template <>
[[nodiscard]] inline auto get_current_path<std::wstring>() -> std::wstring {
return utils::string::from_utf8(get_current_path<std::string>());
}
template <typename string_t>
[[nodiscard]] inline auto get_parent_api_path_t(
std::basic_string_view<typename string_t::value_type> path) -> string_t {
auto slash_t = get_slash<typename string_t::value_type>();
string_t ret{path};
utils::string::right_trim(ret, slash_t.at(0U));
if (ret == slash_t || ret.empty()) {
return string_t{path};
}
auto sub_path = ret.substr(0, ret.rfind(slash_t) + 1);
if (sub_path == slash_t) {
return string_t{sub_path};
}
return sub_path;
}
inline auto get_parent_api_path(std::string_view path) -> std::string {
return create_api_path(get_parent_api_path_t<std::string>(path));
}
inline auto get_parent_api_path(std::wstring_view path) -> std::wstring {
return create_api_path(get_parent_api_path_t<std::wstring>(path));
}
template <typename string_t>
[[nodiscard]] inline auto
get_parts_t(std::basic_string_view<typename string_t::value_type> path)
-> std::vector<string_t> {
return utils::string::split(
path, get_directory_seperator<typename string_t::value_type>().at(0U),
false);
}
inline auto get_parts(std::string_view path) -> std::vector<std::string> {
return get_parts_t<std::string>(path);
}
inline auto get_parts_w(std::wstring_view path) -> std::vector<std::wstring> {
return get_parts_t<std::wstring>(path);
}
} // namespace fifthgrid::utils::path
#endif // FIFTHGRID_INCLUDE_UTILS_PATH_HPP_

View File

@@ -0,0 +1,469 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_STRING_HPP_
#define FIFTHGRID_INCLUDE_UTILS_STRING_HPP_
#include "utils/config.hpp"
namespace fifthgrid::utils::string {
template <typename string_t> struct chain_replace_with_hex;
template <typename string_t>
[[nodiscard]] inline auto
char_to_hex(typename string_t::value_type character) -> string_t;
[[nodiscard]] inline auto begins_with(std::string_view str,
std::string_view val) -> bool;
[[nodiscard]] inline auto begins_with(std::wstring_view str,
std::wstring_view val) -> bool;
template <typename string_t>
[[nodiscard]] inline auto case_insensitive_find_string(string_t in_str,
string_t for_str) ->
typename string_t::const_iterator;
[[nodiscard]] inline auto contains(std::string_view str,
std::string_view search) -> bool;
[[nodiscard]] inline auto contains(std::wstring_view str,
std::wstring_view search) -> bool;
[[nodiscard]] inline auto ends_with(std::string_view str,
std::string_view val) -> bool;
[[nodiscard]] inline auto ends_with(std::wstring_view str,
std::wstring_view val) -> bool;
[[nodiscard]] auto from_bool(bool val) -> std::string;
#if defined(PROJECT_ENABLE_BOOST)
[[nodiscard]] auto
from_dynamic_bitset(const boost::dynamic_bitset<> &bitset) -> std::string;
#endif // defined(PROJECT_ENABLE_BOOST)
[[nodiscard]] auto from_utf8(std::string_view str) -> std::wstring;
[[nodiscard]] inline auto is_numeric(std::string_view str) -> bool;
[[nodiscard]] inline auto is_numeric(std::wstring_view str) -> bool;
template <typename string_t>
[[nodiscard]] inline auto join(const std::vector<string_t> &arr,
typename string_t::value_type delim) -> string_t;
template <typename string_t>
auto left_trim(string_t &str,
typename string_t::value_type trim_ch = ' ') -> string_t &;
template <typename string_t>
inline auto replace(string_t &src, typename string_t::value_type character,
typename string_t::value_type with,
std::size_t start_pos = 0U) -> string_t &;
template <typename string_t>
inline auto replace(string_t &src,
std::basic_string_view<typename string_t::value_type> find,
std::basic_string_view<typename string_t::value_type> with,
std::size_t start_pos = 0U) -> string_t &;
template <typename string_t>
[[nodiscard]] inline auto replace_copy(string_t src,
typename string_t::value_type character,
typename string_t::value_type with,
std::size_t start_pos = 0U) -> string_t;
template <typename string_t>
[[nodiscard]] inline auto
replace_copy(string_t src,
std::basic_string_view<typename string_t::value_type> find,
std::basic_string_view<typename string_t::value_type> with,
std::size_t start_pos = 0U) -> string_t;
template <typename string_t>
[[nodiscard]] inline auto
replace_with_hex(string_t &str, typename string_t::value_type character)
-> chain_replace_with_hex<string_t>;
template <typename string_t>
inline auto
right_trim(string_t &str,
typename string_t::value_type trim_ch = ' ') -> string_t &;
[[nodiscard]] inline auto split(std::string_view str, char delim,
bool should_trim) -> std::vector<std::string>;
[[nodiscard]] inline auto split(std::wstring_view str, wchar_t delim,
bool should_trim) -> std::vector<std::wstring>;
[[nodiscard]] inline auto split(std::string_view str, std::string_view delim,
bool should_trim) -> std::vector<std::string>;
[[nodiscard]] inline auto split(std::wstring_view str, std::wstring_view delim,
bool should_trim) -> std::vector<std::wstring>;
#if defined(PROJECT_ENABLE_SFML)
auto replace_sf(sf::String &src, const sf::String &find, const sf::String &with,
std::size_t start_pos = 0U) -> sf::String &;
[[nodiscard]] auto split_sf(sf::String str, wchar_t delim,
bool should_trim) -> std::vector<sf::String>;
#endif // defined(PROJECT_ENABLE_SFML)
[[nodiscard]] auto to_bool(std::string val) -> bool;
[[nodiscard]] auto to_double(const std::string &str) -> double;
#if defined(PROJECT_ENABLE_BOOST)
[[nodiscard]] auto
to_dynamic_bitset(const std::string &val) -> boost::dynamic_bitset<>;
#endif // defined(PROJECT_ENABLE_BOOST)
template <typename string_t>
[[nodiscard]] inline auto to_lower(string_t str) -> string_t;
[[nodiscard]] auto to_int32(const std::string &val) -> std::int32_t;
[[nodiscard]] auto to_int64(const std::string &val) -> std::int64_t;
[[nodiscard]] auto to_size_t(const std::string &val) -> std::size_t;
[[nodiscard]] auto to_uint8(const std::string &val) -> std::uint8_t;
[[nodiscard]] auto to_uint16(const std::string &val) -> std::uint16_t;
[[nodiscard]] auto to_uint32(const std::string &val) -> std::uint32_t;
[[nodiscard]] auto to_uint64(const std::string &val) -> std::uint64_t;
template <typename string_t>
[[nodiscard]] inline auto to_upper(string_t str) -> string_t;
[[nodiscard]] auto to_utf8(std::string_view str) -> std::string;
[[nodiscard]] auto to_utf8(std::wstring_view str) -> std::string;
template <typename string_t>
[[nodiscard]] inline auto zero_pad(string_t str, std::size_t count) -> string_t;
template <typename string_t> struct chain_replace_with_hex final {
explicit chain_replace_with_hex(string_t &value) : str(value) {}
chain_replace_with_hex(const chain_replace_with_hex &) = delete;
chain_replace_with_hex(chain_replace_with_hex &&) = delete;
~chain_replace_with_hex() = default;
auto operator=(const chain_replace_with_hex &) -> chain_replace_with_hex & =
delete;
auto
operator=(chain_replace_with_hex &&) -> chain_replace_with_hex & = delete;
auto operator()(typename string_t::value_type character)
-> chain_replace_with_hex {
return replace_with_hex<string_t>(str, character);
}
string_t &str;
};
template <typename string_t>
inline auto trim(string_t &str,
typename string_t::value_type trim_ch = ' ') -> string_t &;
template <typename string_t>
[[nodiscard]] inline auto
trim_copy(string_t str,
typename string_t::value_type trim_ch = ' ') -> string_t;
template <typename char_t>
[[nodiscard]] inline auto
begins_with_t(std::basic_string_view<char_t> str,
std::basic_string_view<char_t> val) -> bool {
return (str.find(val) == 0U);
}
inline auto begins_with(std::string_view str, std::string_view val) -> bool {
return begins_with_t<std::string_view::value_type>(str, val);
}
inline auto begins_with(std::wstring_view str, std::wstring_view val) -> bool {
return begins_with_t<std::wstring_view::value_type>(str, val);
}
template <typename string_t>
inline auto case_insensitive_find_string(string_t in_str, string_t for_str) ->
typename string_t::const_iterator {
static const auto compare_chars =
[](typename string_t::value_type char_a,
typename string_t::value_type char_b) -> bool {
return (std::tolower(char_a) == std::tolower(char_b));
};
return (std::search(in_str.begin(), in_str.end(), for_str.begin(),
for_str.end(), compare_chars));
}
template <typename string_t>
inline auto char_to_hex(typename string_t::value_type character) -> string_t {
std::basic_stringstream<typename string_t::value_type> stream;
stream << '%' << std::setfill<typename string_t::value_type>('0')
<< std::setw(sizeof(character)) << std::hex
<< static_cast<std::uint32_t>(character);
return stream.str();
}
template <typename char_t>
[[nodiscard]] inline auto
contains_t(std::basic_string_view<char_t> str,
std::basic_string_view<char_t> search) -> bool {
return (str.find(search) != std::basic_string_view<char_t>::npos);
}
inline auto contains(std::string_view str, std::string_view search) -> bool {
return contains_t<std::string_view::value_type>(str, search);
}
inline auto contains(std::wstring_view str, std::wstring_view search) -> bool {
return contains_t<std::wstring_view::value_type>(str, search);
}
template <typename char_t>
[[nodiscard]] inline auto
ends_with_t(std::basic_string_view<char_t> str,
std::basic_string_view<char_t> val) -> bool {
if (val.size() > str.size()) {
return false;
}
return std::equal(val.rbegin(), val.rend(), str.rbegin());
}
inline auto ends_with(std::string_view str, std::string_view val) -> bool {
return ends_with_t<std::string_view::value_type>(str, val);
}
inline auto ends_with(std::wstring_view str, std::wstring_view val) -> bool {
return ends_with_t<std::wstring_view::value_type>(str, val);
}
template <typename char_t>
[[nodiscard]] inline auto
is_numeric_t(std::basic_string_view<char_t> str) -> bool {
if ((str.length() > 1U) && (str.at(0U) == '+' || str.at(0U) == '-')) {
str = str.substr(1U);
}
if (str.empty()) {
return false;
}
auto has_decimal{false};
return std::find_if(str.begin(), str.end(),
[&has_decimal](auto &&cur_ch) -> bool {
if (has_decimal && cur_ch == '.') {
return true;
}
has_decimal = has_decimal || cur_ch == '.';
if (has_decimal) {
return false;
}
return std::isdigit(cur_ch) == 0;
}) == str.end();
}
inline auto is_numeric(std::string_view str) -> bool {
return is_numeric_t<std::string_view::value_type>(str);
}
inline auto is_numeric(std::wstring_view str) -> bool {
return is_numeric_t<std::wstring_view::value_type>(str);
}
template <typename string_t>
inline auto join(const std::vector<string_t> &arr,
typename string_t::value_type delim) -> string_t {
if (arr.empty()) {
return {};
}
return std::accumulate(
std::next(arr.begin()), arr.end(), arr[0U],
[&delim](auto str, const auto &cur) { return str + delim + cur; });
}
template <typename string_t>
auto left_trim(string_t &str,
typename string_t::value_type trim_ch) -> string_t & {
str.erase(0, str.find_first_not_of(trim_ch));
return str;
}
template <typename string_t>
inline auto replace(string_t &src, typename string_t::value_type character,
typename string_t::value_type with,
std::size_t start_pos) -> string_t & {
if (start_pos < src.size()) {
std::replace(std::next(src.begin(), start_pos), src.end(), character, with);
}
return src;
}
template <typename string_t>
inline auto replace(string_t &src,
std::basic_string_view<typename string_t::value_type> find,
std::basic_string_view<typename string_t::value_type> with,
std::size_t start_pos) -> string_t & {
if (start_pos < src.size()) {
while ((start_pos = src.find(find, start_pos)) != string_t::npos) {
src.replace(start_pos, find.size(), with);
start_pos += with.size();
}
}
return src;
}
template <typename string_t>
inline auto replace_copy(string_t src, typename string_t::value_type character,
typename string_t::value_type with,
std::size_t start_pos) -> string_t {
return replace(src, character, with, start_pos);
}
template <typename string_t>
inline auto
replace_copy(string_t src,
std::basic_string_view<typename string_t::value_type> find,
std::basic_string_view<typename string_t::value_type> with,
std::size_t start_pos) -> string_t {
return replace(src, find, with, start_pos);
}
template <typename string_t>
inline auto replace_with_hex(string_t &str,
typename string_t::value_type character)
-> chain_replace_with_hex<string_t> {
return chain_replace_with_hex(
replace(str, string_t{1U, character}, char_to_hex<string_t>(character)));
}
template <typename string_t>
inline auto right_trim(string_t &str,
typename string_t::value_type trim_ch) -> string_t & {
str.erase(str.find_last_not_of(trim_ch) + 1);
return str;
}
template <typename string_t> inline auto to_lower(string_t str) -> string_t {
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
return str;
}
template <typename string_t> inline auto to_upper(string_t str) -> string_t {
std::transform(str.begin(), str.end(), str.begin(), ::toupper);
return str;
}
template <typename string_t>
inline auto trim(string_t &str,
typename string_t::value_type trim_ch) -> string_t & {
return right_trim(left_trim(str, trim_ch), trim_ch);
}
template <typename string_t>
inline auto trim_copy(string_t str,
typename string_t::value_type trim_ch) -> string_t {
return trim(str, trim_ch);
}
template <typename string_t>
[[nodiscard]] inline auto
split_t(std::basic_string_view<typename string_t::value_type> str,
typename string_t::value_type delim,
bool should_trim) -> std::vector<string_t> {
std::vector<string_t> ret;
std::basic_stringstream<typename string_t::value_type> stream{string_t{str}};
string_t val;
while (std::getline(stream, val, delim)) {
if (should_trim) {
trim(val);
}
ret.push_back(std::move(val));
}
return ret;
}
inline auto split(std::string_view str, char delim,
bool should_trim) -> std::vector<std::string> {
return split_t<std::string>(str, delim, should_trim);
}
inline auto split(std::wstring_view str, wchar_t delim,
bool should_trim) -> std::vector<std::wstring> {
return split_t<std::wstring>(str, delim, should_trim);
}
template <typename string_t>
[[nodiscard]] inline auto
split_t(std::basic_string_view<typename string_t::value_type> str,
std::basic_string_view<typename string_t::value_type> delim,
bool should_trim) -> std::vector<string_t> {
auto result = std::views::split(str, delim);
std::vector<string_t> ret{};
for (auto &&word : result) {
auto val = string_t{word.begin(), word.end()};
if (should_trim) {
trim(val);
}
ret.push_back(std::move(val));
}
return ret;
}
inline auto split(std::string_view str, std::string_view delim,
bool should_trim) -> std::vector<std::string> {
return split_t<std::string>(str, delim, should_trim);
}
inline auto split(std::wstring_view str, std::wstring_view delim,
bool should_trim) -> std::vector<std::wstring> {
return split_t<std::wstring>(str, delim, should_trim);
}
template <typename string_t>
inline auto zero_pad(string_t str, std::size_t count) -> string_t {
str.insert(str.begin(), count - str.length(), '0');
return str;
}
} // namespace fifthgrid::utils::string
#endif // FIFTHGRID_INCLUDE_UTILS_STRING_HPP_

View File

@@ -0,0 +1,69 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_TIME_HPP_
#define FIFTHGRID_INCLUDE_UTILS_TIME_HPP_
#include "utils/config.hpp"
namespace fifthgrid::utils::time {
inline constexpr auto NANOS_PER_SECOND{1000000000ULL};
inline constexpr auto WIN32_TIME_CONVERSION{116444736000000000ULL};
inline constexpr auto WIN32_TIME_NANOS_PER_TICK{100ULL};
#if defined(PROJECT_ENABLE_SPDLOG) || defined(PROJECT_ENABLE_FMT)
[[nodiscard]] inline auto convert_to_utc(time_t time) -> std::time_t {
auto calendar_time = fmt::gmtime(time);
return std::mktime(&calendar_time);
}
#endif // defined(PROJECT_ENABLE_SPDLOG) || defined(PROJECT_ENABLE_FMT)
#if defined(PROJECT_ENABLE_SPDLOG) || defined(PROJECT_ENABLE_FMT)
[[nodiscard]] inline auto get_current_time_utc() -> std::time_t {
auto calendar_time = fmt::gmtime(std::time(nullptr));
return std::mktime(&calendar_time);
}
#endif // defined(PROJECT_ENABLE_SPDLOG) || defined(PROJECT_ENABLE_FMT)
void get_local_time_now(struct tm &local_time);
[[nodiscard]] auto get_time_now() -> std::uint64_t;
#if defined(_WIN32)
auto strptime(const char *s, const char *f, struct tm *tm) -> const char *;
[[nodiscard]] auto unix_time_to_filetime(std::uint64_t unix_time) -> FILETIME;
[[nodiscard]] auto
windows_file_time_to_unix_time(FILETIME win_time) -> std::uint64_t;
[[nodiscard]] auto
windows_time_t_to_unix_time(__time64_t win_time) -> std::uint64_t;
#endif // defined(_WIN32)
[[nodiscard]] auto
unix_time_to_windows_time(std::uint64_t unix_time) -> std::uint64_t;
[[nodiscard]] auto
windows_time_to_unix_time(std::uint64_t win_time) -> std::uint64_t;
} // namespace fifthgrid::utils::time
#endif // FIFTHGRID_INCLUDE_UTILS_TIME_HPP_

View File

@@ -0,0 +1,59 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_TIMEOUT_HPP_
#define FIFTHGRID_INCLUDE_UTILS_TIMEOUT_HPP_
#include "utils/config.hpp"
namespace fifthgrid::utils {
class timeout final {
public:
using callback_t = std::function<void()>;
public:
timeout(const timeout &) noexcept = delete;
timeout(timeout &&) noexcept = delete;
auto operator=(const timeout &) noexcept -> timeout & = delete;
auto operator=(timeout &&) noexcept -> timeout & = delete;
public:
timeout(callback_t timeout_callback,
std::chrono::system_clock::duration duration);
~timeout();
private:
std::chrono::system_clock::duration duration_;
callback_t timeout_callback_;
std::atomic<bool> timeout_killed_{false};
std::unique_ptr<std::thread> timeout_thread_{nullptr};
std::mutex timeout_mutex_;
std::condition_variable timeout_notify_;
public:
void disable();
void reset();
};
} // namespace fifthgrid::utils
#endif // FIFTHGRID_INCLUDE_UTILS_TIMEOUT_HPP_

View File

@@ -0,0 +1,100 @@
#ifndef FIFTHGRID_INCLUDE_UTILS_TTL_CACHE_HPP_
#define FIFTHGRID_INCLUDE_UTILS_TTL_CACHE_HPP_
#include "utils/config.hpp"
namespace fifthgrid::utils {
template <typename data_t, template <typename> class atomic_t = std::atomic>
class ttl_cache final {
public:
using clock = std::chrono::steady_clock;
using duration = std::chrono::milliseconds;
using entry_t = atomic_t<data_t>;
using entry_ptr_t = std::shared_ptr<entry_t>;
static constexpr auto default_expiration{duration(60000U)};
private:
struct entry final {
entry_ptr_t data;
clock::time_point expires_at;
};
public:
ttl_cache(duration ttl = default_expiration) : ttl_{ttl} {}
private:
duration ttl_;
private:
mutable std::mutex mutex_;
std::unordered_map<std::string, entry> entries_;
public:
void clear() {
mutex_lock lock(mutex_);
entries_.clear();
}
void erase(const std::string &api_path) {
mutex_lock lock(mutex_);
entries_.erase(api_path);
}
[[nodiscard]] auto contains(const std::string &api_path) -> bool {
mutex_lock lock(mutex_);
return entries_.contains(api_path);
}
[[nodiscard]] auto get(const std::string &api_path) -> entry_ptr_t {
mutex_lock lock(mutex_);
auto iter = entries_.find(api_path);
if (iter == entries_.end()) {
return nullptr;
}
iter->second.expires_at = clock::now() + ttl_;
return iter->second.data;
}
void purge_expired() {
mutex_lock lock(mutex_);
auto now = clock::now();
for (auto iter = entries_.begin(); iter != entries_.end();) {
if (iter->second.expires_at <= now) {
iter = entries_.erase(iter);
continue;
}
++iter;
}
}
[[nodiscard]] auto get_ttl() const -> duration {
mutex_lock lock(mutex_);
return ttl_;
}
void set(const std::string &api_path, const data_t &data) {
mutex_lock lock(mutex_);
if (entries_.contains(api_path)) {
auto &entry = entries_.at(api_path);
entry.data->store(data);
entry.expires_at = clock::now() + ttl_;
return;
}
entries_.emplace(api_path, entry{
.data = std::make_shared<entry_t>(data),
.expires_at = clock::now() + ttl_,
});
}
void set_ttl(duration ttl) {
mutex_lock lock(mutex_);
ttl_ = ttl;
}
};
} // namespace fifthgrid::utils
#endif // FIFTHGRID_INCLUDE_UTILS_TTL_CACHE_HPP_

View File

@@ -0,0 +1,81 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_TYPES_FILE_I_DIRECTORY_HPP_
#define FIFTHGRID_INCLUDE_TYPES_FILE_I_DIRECTORY_HPP_
#include "utils/config.hpp"
#include "utils/types/file/i_file.hpp"
#include "utils/types/file/i_fs_item.hpp"
namespace fifthgrid::utils::file {
struct i_directory : public i_fs_item {
using fs_directory_t = std::unique_ptr<i_directory>;
using fs_file_t = i_file::fs_file_t;
virtual ~i_directory() = default;
[[nodiscard]] virtual auto
count(bool recursive = false) const -> std::uint64_t = 0;
[[nodiscard]] virtual auto
create_directory(std::string_view path = "") const -> fs_directory_t = 0;
[[nodiscard]] virtual auto create_file(std::string_view file_name,
bool read_only) const -> fs_file_t = 0;
[[nodiscard]] virtual auto
get_directory(std::string_view path) const -> fs_directory_t = 0;
[[nodiscard]] virtual auto
get_directories() const -> std::vector<fs_directory_t> = 0;
[[nodiscard]] virtual auto
get_file(std::string_view path) const -> fs_file_t = 0;
[[nodiscard]] virtual auto get_files() const -> std::vector<fs_file_t> = 0;
[[nodiscard]] virtual auto get_items() const -> std::vector<fs_item_t> = 0;
[[nodiscard]] auto is_directory_item() const -> bool override { return true; }
[[nodiscard]] virtual auto is_stop_requested() const -> bool = 0;
[[nodiscard]] virtual auto remove_recursively() -> bool = 0;
[[nodiscard]] virtual auto
size(bool recursive = false) const -> std::uint64_t = 0;
protected:
i_directory() noexcept = default;
i_directory(const i_directory &) noexcept = default;
i_directory(i_directory &&) noexcept = default;
auto operator=(i_directory &&) noexcept -> i_directory & = default;
auto operator=(const i_directory &) noexcept -> i_directory & = default;
};
} // namespace fifthgrid::utils::file
#endif // FIFTHGRID_INCLUDE_TYPES_FILE_I_DIRECTORY_HPP_

View File

@@ -0,0 +1,93 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_TYPES_FILE_I_FILE_HPP_
#define FIFTHGRID_INCLUDE_TYPES_FILE_I_FILE_HPP_
#include "utils/config.hpp"
#include "utils/types/file/i_fs_item.hpp"
namespace fifthgrid::utils::file {
struct i_file : public i_fs_item {
using fs_file_t = std::unique_ptr<i_file>;
virtual ~i_file() = default;
virtual void close() = 0;
virtual void flush() const = 0;
[[nodiscard]] virtual auto get_handle() const -> native_handle = 0;
[[nodiscard]] virtual auto get_read_buffer_size() const -> std::uint32_t = 0;
[[nodiscard]] auto is_directory_item() const -> bool override {
return false;
}
[[nodiscard]] virtual auto is_read_only() const -> bool = 0;
[[nodiscard]] virtual auto read(data_buffer &data, std::uint64_t offset,
std::size_t *total_read = nullptr) -> bool {
return read(data.data(), data.size(), offset, total_read);
}
[[nodiscard]] virtual auto
read(unsigned char *data, std::size_t to_read, std::uint64_t offset,
std::size_t *total_read = nullptr) -> bool = 0;
[[nodiscard]] virtual auto
read_all(data_buffer &data, std::uint64_t offset,
std::size_t *total_read = nullptr) -> bool;
virtual auto set_read_buffer_size(std::uint32_t size) -> std::uint32_t = 0;
[[nodiscard]] virtual auto size() const -> std::optional<std::uint64_t> = 0;
[[nodiscard]] virtual auto truncate() -> bool { return truncate(0U); }
[[nodiscard]] virtual auto truncate(std::size_t size) -> bool = 0;
[[nodiscard]] virtual auto
write(const data_buffer &data, std::uint64_t offset,
std::size_t *total_written = nullptr) -> bool {
return write(data.data(), data.size(), offset, total_written);
}
[[nodiscard]] virtual auto
write(const unsigned char *data, std::size_t to_write, std::size_t offset,
std::size_t *total_written = nullptr) -> bool = 0;
protected:
i_file() noexcept = default;
i_file(const i_file &) noexcept = default;
i_file(i_file &&) noexcept = default;
auto operator=(i_file &&) noexcept -> i_file & = default;
auto operator=(const i_file &) noexcept -> i_file & = default;
};
} // namespace fifthgrid::utils::file
#endif // FIFTHGRID_INCLUDE_TYPES_FILE_I_FILE_HPP_

View File

@@ -0,0 +1,121 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_TYPES_FILE_I_FS_ITEM_HPP_
#define FIFTHGRID_INCLUDE_TYPES_FILE_I_FS_ITEM_HPP_
#include "utils/config.hpp"
#include "utils/error.hpp"
#include "utils/string.hpp"
namespace fifthgrid::utils::file {
enum class time_type {
accessed,
changed,
created,
modified,
written,
};
struct file_times final {
std::uint64_t accessed{};
std::uint64_t changed{};
std::uint64_t created{};
std::uint64_t modified{};
std::uint64_t written{};
[[nodiscard]] auto get(time_type type) const -> std::uint64_t {
FIFTHGRID_USES_FUNCTION_NAME();
switch (type) {
case time_type::accessed:
return accessed;
case time_type::changed:
return changed;
case time_type::created:
return created;
case time_type::modified:
return modified;
case time_type::written:
return written;
}
throw utils::error::create_exception(function_name,
{
"type_type not supported",
});
}
};
struct i_fs_item {
using fs_item_t = std::unique_ptr<i_fs_item>;
virtual ~i_fs_item() = default;
[[nodiscard]] virtual auto copy_to(std::string_view to_path,
bool overwrite) const -> bool = 0;
[[nodiscard]] virtual auto copy_to(std::wstring_view new_path, bool overwrite)
-> bool {
return copy_to(utils::string::to_utf8(new_path), overwrite);
}
[[nodiscard]] virtual auto exists() const -> bool = 0;
[[nodiscard]] virtual auto get_path() const -> std::string = 0;
[[nodiscard]] virtual auto get_time(time_type type) const
-> std::optional<std::uint64_t>;
[[nodiscard]] virtual auto is_directory_item() const -> bool = 0;
[[nodiscard]] auto is_file_item() const -> bool {
return not is_directory_item();
}
[[nodiscard]] virtual auto is_symlink() const -> bool = 0;
[[nodiscard]] virtual auto move_to(std::string_view new_path) -> bool = 0;
[[nodiscard]] virtual auto move_to(std::wstring_view new_path) -> bool {
return move_to(utils::string::to_utf8(new_path));
}
[[nodiscard]] virtual auto remove() -> bool = 0;
public:
[[nodiscard]] virtual operator bool() const = 0;
protected:
i_fs_item() noexcept = default;
i_fs_item(const i_fs_item &) noexcept = default;
i_fs_item(i_fs_item &&) noexcept = default;
auto operator=(i_fs_item &&) noexcept -> i_fs_item & = default;
auto operator=(const i_fs_item &) noexcept -> i_fs_item & = default;
};
} // namespace fifthgrid::utils::file
#endif // FIFTHGRID_INCLUDE_TYPES_FILE_I_FS_ITEM_HPP_

View File

@@ -0,0 +1,124 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_UNIX_HPP_
#define FIFTHGRID_INCLUDE_UTILS_UNIX_HPP_
#if !defined(_WIN32)
#include "utils/common.hpp"
#include "utils/config.hpp"
namespace fifthgrid::utils {
#if defined(__linux__)
struct autostart_cfg final {
std::string app_name;
std::optional<std::string> comment;
bool enabled{true};
std::vector<std::string> exec_args;
std::string exec_path;
std::optional<std::string> icon_path;
std::vector<std::string> only_show_in;
bool terminal{false};
};
#endif // defined(__linux__)
#if defined(__APPLE__)
enum class launchctl_type : std::uint8_t {
bootout,
bootstrap,
kickstart,
};
#if defined(PROJECT_ENABLE_PUGIXML)
struct plist_cfg final {
std::vector<std::string> args;
bool keep_alive{false};
std::string label;
std::string plist_path;
bool run_at_load{false};
std::string stderr_log{"/tmp/stderr.log"};
std::string stdout_log{"/tmp/stdout.log"};
std::string working_dir{"/tmp"};
};
#endif // defined(PROJECT_ENABLE_PUGIXML)
#endif // defined(__APPLE__)
using passwd_callback_t = std::function<void(struct passwd *pass)>;
#if defined(__APPLE__)
template <typename thread_t>
[[nodiscard]] auto convert_to_uint64(const thread_t *thread_ptr)
-> std::uint64_t;
#else // !defined(__APPLE__)
[[nodiscard]] auto convert_to_uint64(const pthread_t &thread) -> std::uint64_t;
#endif // defined(__APPLE__)
#if defined(__linux__)
[[nodiscard]] auto create_autostart_entry(const autostart_cfg &cfg,
bool overwrite_existing = true)
-> bool;
#endif // defined(__linux__)
[[nodiscard]] auto get_last_error_code() -> int;
[[nodiscard]] auto get_thread_id() -> std::uint64_t;
[[nodiscard]] auto is_uid_member_of_group(uid_t uid, gid_t gid) -> bool;
void set_last_error_code(int error_code);
[[nodiscard]] auto use_getpwuid(uid_t uid, passwd_callback_t callback)
-> utils::result;
#if defined(__linux__)
[[nodiscard]] auto remove_autostart_entry(std::string_view name) -> bool;
#endif // defined(__linux__)
#if defined(__APPLE__)
#if defined(PROJECT_ENABLE_PUGIXML)
[[nodiscard]] auto generate_launchd_plist(const plist_cfg &cfg,
bool overwrite_existing = true)
-> bool;
#endif // defined(PROJECT_ENABLE_PUGIXML)
#if defined(PROJECT_ENABLE_SPDLOG) || defined(PROJECT_ENABLE_FMT)
[[nodiscard]] auto launchctl_command(std::string_view label,
launchctl_type type) -> int;
[[nodiscard]] auto remove_launchd_plist(std::string_view plist_path,
std::string_view label,
bool should_bootout) -> bool;
#endif // defined(PROJECT_ENABLE_SPDLOG) || defined(PROJECT_ENABLE_FMT)
#endif // defined(__APPLE__)
// template implementations
#if defined(__APPLE__)
template <typename thread_t>
[[nodiscard]] auto convert_to_uint64(const thread_t *thread_ptr)
-> std::uint64_t {
return static_cast<std::uint64_t>(
reinterpret_cast<std::uintptr_t>(thread_ptr));
}
#endif // defined(__APPLE__)
} // namespace fifthgrid::utils
#endif // !defined(_WIN32)
#endif // FIFTHGRID_INCLUDE_UTILS_UNIX_HPP_

View File

@@ -0,0 +1,72 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIFTHGRID_INCLUDE_UTILS_WINDOWS_HPP_
#define FIFTHGRID_INCLUDE_UTILS_WINDOWS_HPP_
#if defined(_WIN32)
#include "utils/config.hpp"
namespace fifthgrid::utils {
void create_console();
void free_console();
[[nodiscard]] auto get_available_drive_letter(char first = 'a')
-> std::optional<std::string_view>;
[[nodiscard]] auto get_available_drive_letters(char first = 'a')
-> std::vector<std::string_view>;
[[nodiscard]] auto get_local_app_data_directory() -> const std::string &;
[[nodiscard]] auto get_last_error_code() -> DWORD;
[[nodiscard]] auto get_startup_folder() -> std::wstring;
[[nodiscard]] auto get_thread_id() -> std::uint64_t;
[[nodiscard]] auto is_process_elevated() -> bool;
[[nodiscard]] auto run_process_elevated(std::vector<const char *> args) -> int;
struct shortcut_cfg final {
std::wstring arguments;
std::wstring exe_path;
std::wstring icon_path;
std::wstring location{get_startup_folder()};
std::wstring shortcut_name;
std::wstring working_directory;
};
[[nodiscard]]
auto create_shortcut(const shortcut_cfg &cfg, bool overwrite_existing = true)
-> bool;
[[nodiscard]] auto
remove_shortcut(std::wstring shortcut_name,
const std::wstring &location = get_startup_folder()) -> bool;
void set_last_error_code(DWORD error_code);
} // namespace fifthgrid::utils
#endif // defined(_WIN32)
#endif // FIFTHGRID_INCLUDE_UTILS_WINDOWS_HPP_