code integration
This commit is contained in:
261
sdi_toolBox_2.x.x/toolBox/sdi_toolBox/desktop/utils/base64.h
Normal file
261
sdi_toolBox_2.x.x/toolBox/sdi_toolBox/desktop/utils/base64.h
Normal file
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
Copyright (c) 2026 - SD-Innovation S.A.S. - FRANCE
|
||||
*/
|
||||
|
||||
/*
|
||||
ver: 2.x.x - build: 2026-04-28
|
||||
*/
|
||||
|
||||
/*
|
||||
The zlib License
|
||||
|
||||
Copyright (c) 2026 SD-Innovation S.A.S.
|
||||
|
||||
This software is provided ‘as-is’, without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace sdi_toolBox::desktop::utils
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
/**
|
||||
* @brief Utility class providing Base64 encoding and decoding functionality.
|
||||
*
|
||||
* @details This class implements the Base64 encoding scheme as defined in RFC 4648.
|
||||
* All methods are static and the class is not meant to be instantiated.
|
||||
* Padding is handled via the '=' character.
|
||||
*
|
||||
* @note The standard Base64 alphabet is used ('A-Z', 'a-z', '0-9', '+', '/').
|
||||
*
|
||||
* @par Example - Encoding binary data:
|
||||
* @code{.cpp}
|
||||
* std::vector<std::uint8_t> data = { 0x48, 0x65, 0x6C, 0x6C, 0x6F };
|
||||
* std::string encoded = Base64::encode(data);
|
||||
* // encoded == "SGVsbG8="
|
||||
* @endcode
|
||||
*
|
||||
* @par Example - Encoding a string:
|
||||
* @code{.cpp}
|
||||
* std::string encoded = Base64::encode("Hello, World!");
|
||||
* // encoded == "SGVsbG8sIFdvcmxkIQ=="
|
||||
* @endcode
|
||||
*
|
||||
* @par Example - Decoding:
|
||||
* @code{.cpp}
|
||||
* auto result = Base64::decode_to_string("SGVsbG8sIFdvcmxkIQ==");
|
||||
* if (result)
|
||||
* std::cout << *result; // prints: Hello, World!
|
||||
* @endcode
|
||||
*/
|
||||
class Base64
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Deleted default constructor - this class is not meant to be instantiated.
|
||||
*/
|
||||
Base64() = delete;
|
||||
|
||||
///@name Encoding
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Encodes binary data into a Base64 string.
|
||||
*
|
||||
* @param data A span of bytes to encode.
|
||||
* @return A Base64-encoded string, padded with `'='` characters if necessary.
|
||||
*/
|
||||
[[nodiscard]] static std::string encode(std::span<const std::uint8_t> data);
|
||||
|
||||
/**
|
||||
* @brief Encodes a text string into a Base64 string.
|
||||
*
|
||||
* @param text The input string to encode.
|
||||
* @return A Base64-encoded string, padded with `'='` characters if necessary.
|
||||
*/
|
||||
[[nodiscard]] static std::string encode(std::string_view text);
|
||||
|
||||
///@}
|
||||
///@name Decoding
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Decodes a Base64 string into raw binary data.
|
||||
*
|
||||
* @param input The Base64-encoded string to decode. Must have a length
|
||||
* that is a multiple of 4.
|
||||
* @return A vector of decoded bytes, or `std::nullopt` if the input is
|
||||
* not a valid Base64 string.
|
||||
*/
|
||||
[[nodiscard]] static std::optional<std::vector<std::uint8_t>> decode(std::string_view input);
|
||||
|
||||
/**
|
||||
* @brief Decodes a Base64 string into a text string.
|
||||
*
|
||||
* @param input The Base64-encoded string to decode. Must have a length
|
||||
* that is a multiple of 4.
|
||||
* @return The decoded string, or `std::nullopt` if the input is not a
|
||||
* valid Base64 string.
|
||||
*/
|
||||
[[nodiscard]] static std::optional<std::string> decode_to_string(std::string_view input);
|
||||
|
||||
///@}
|
||||
|
||||
private:
|
||||
///@name Internal helpers
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Decodes a single Base64 character into its 6-bit value.
|
||||
*
|
||||
* @param c The Base64 character to decode.
|
||||
* @return The 6-bit value corresponding to @p c, or `std::nullopt` if
|
||||
* @p c is not a valid Base64 character.
|
||||
*/
|
||||
[[nodiscard]] static std::optional<std::uint8_t> decode_char(char c) noexcept;
|
||||
|
||||
///@}
|
||||
///@name Constants
|
||||
///@{
|
||||
|
||||
/** @brief The Base64 encoding lookup table (RFC 4648 standard alphabet). */
|
||||
static constexpr std::string_view ENCODE_LOOKUP = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
/** @brief The padding character used in Base64 encoding. */
|
||||
static constexpr char PADDING_CAR = '=';
|
||||
|
||||
///@}
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/* Encode binary data to Base64 string */
|
||||
inline std::string Base64::encode(const std::span<const std::uint8_t> data)
|
||||
{
|
||||
std::string result;
|
||||
result.reserve(((data.size() + 2) / 3) * 4);
|
||||
|
||||
for (std::size_t i = 0; i < data.size(); i += 3)
|
||||
{
|
||||
const std::uint32_t b0 = data[i];
|
||||
const std::uint32_t b1 = (i + 1 < data.size()) ? data[i + 1] : 0u;
|
||||
const std::uint32_t b2 = (i + 2 < data.size()) ? data[i + 2] : 0u;
|
||||
|
||||
const std::uint32_t triple = (b0 << 16) | (b1 << 8) | b2;
|
||||
|
||||
result += ENCODE_LOOKUP[(triple >> 18) & 0x3F];
|
||||
result += ENCODE_LOOKUP[(triple >> 12) & 0x3F];
|
||||
result += (i + 1 < data.size()) ? ENCODE_LOOKUP[(triple >> 6) & 0x3F] : PADDING_CAR;
|
||||
result += (i + 2 < data.size()) ? ENCODE_LOOKUP[(triple >> 0) & 0x3F] : PADDING_CAR;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Encode a text string to Base64 string */
|
||||
inline std::string Base64::encode(const std::string_view text)
|
||||
{
|
||||
return encode(std::span(reinterpret_cast<const std::uint8_t *>(text.data()), text.size()));
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Decode a Base64 string to binary data (returns std::nullopt if invalid) */
|
||||
inline std::optional<std::vector<std::uint8_t>> Base64::decode(const std::string_view input)
|
||||
{
|
||||
if (input.size() % 4 != 0)
|
||||
return std::nullopt;
|
||||
|
||||
if (input.empty())
|
||||
return std::vector<std::uint8_t>{};
|
||||
|
||||
// Validate padding: '=' is only allowed in the last group, in position 2 or 3
|
||||
// Valid forms: "xxx=" or "xx=="
|
||||
for (std::size_t i = 0; i < input.size() - 4; ++i)
|
||||
{
|
||||
if (input[i] == PADDING_CAR)
|
||||
return std::nullopt; // '=' found outside the last group
|
||||
}
|
||||
|
||||
const std::string_view last = input.substr(input.size() - 4);
|
||||
// "xx==" : positions 0,1 must be valid chars, positions 2,3 must be '='
|
||||
// "xxx=" : positions 0,1,2 must be valid chars, position 3 must be '='
|
||||
// "xxxx" : all positions must be valid chars
|
||||
if (last[2] == PADDING_CAR && last[3] != PADDING_CAR)
|
||||
return std::nullopt; // "xx=x" is invalid
|
||||
|
||||
std::vector<std::uint8_t> result;
|
||||
result.reserve((input.size() / 4) * 3);
|
||||
|
||||
for (std::size_t i = 0; i < input.size(); i += 4)
|
||||
{
|
||||
const auto v0 = decode_char(input[i]);
|
||||
const auto v1 = decode_char(input[i + 1]);
|
||||
const auto v2 = input[i + 2] == PADDING_CAR ? std::optional<std::uint8_t>{ 0 } : decode_char(input[i + 2]);
|
||||
const auto v3 = input[i + 3] == PADDING_CAR ? std::optional<std::uint8_t>{ 0 } : decode_char(input[i + 3]);
|
||||
|
||||
if (!v0 || !v1 || !v2 || !v3)
|
||||
return std::nullopt;
|
||||
|
||||
const std::uint32_t triple =
|
||||
(static_cast<std::uint32_t>(*v0) << 18) |
|
||||
(static_cast<std::uint32_t>(*v1) << 12) |
|
||||
(static_cast<std::uint32_t>(*v2) << 6) |
|
||||
(static_cast<std::uint32_t>(*v3));
|
||||
|
||||
result.push_back(static_cast<std::uint8_t>((triple >> 16) & 0xFF));
|
||||
if (input[i + 2] != PADDING_CAR)
|
||||
result.push_back(static_cast<std::uint8_t>((triple >> 8) & 0xFF));
|
||||
if (input[i + 3] != PADDING_CAR)
|
||||
result.push_back(static_cast<std::uint8_t>((triple >> 0) & 0xFF));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Decode a Base64 string to a text string (returns std::nullopt if invalid) */
|
||||
inline std::optional<std::string> Base64::decode_to_string(const std::string_view input)
|
||||
{
|
||||
const auto bytes = decode(input);
|
||||
if (!bytes)
|
||||
return std::nullopt;
|
||||
return std::string(reinterpret_cast<const char *>(bytes->data()), bytes->size());
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Helper to decode a single Base64 character to its 6-bit value (returns std::nullopt if invalid) */
|
||||
inline std::optional<std::uint8_t> Base64::decode_char(const char c) noexcept
|
||||
{
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
return static_cast<std::uint8_t>(c - 'A');
|
||||
if (c >= 'a' && c <= 'z')
|
||||
return static_cast<std::uint8_t>(c - 'a' + 26);
|
||||
if (c >= '0' && c <= '9')
|
||||
return static_cast<std::uint8_t>(c - '0' + 52);
|
||||
if (c == '+')
|
||||
return 62;
|
||||
if (c == '/')
|
||||
return 63;
|
||||
return std::nullopt;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_toolBox::desktop::utils
|
||||
219
sdi_toolBox_2.x.x/toolBox/sdi_toolBox/desktop/utils/uuid.h
Normal file
219
sdi_toolBox_2.x.x/toolBox/sdi_toolBox/desktop/utils/uuid.h
Normal file
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
Copyright (c) 2026 - SD-Innovation S.A.S. - FRANCE
|
||||
*/
|
||||
|
||||
/*
|
||||
ver: 2.x.x - build: 2026-04-28
|
||||
*/
|
||||
|
||||
/*
|
||||
The zlib License
|
||||
|
||||
Copyright (c) 2026 SD-Innovation S.A.S.
|
||||
|
||||
This software is provided ‘as-is’, without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <format>
|
||||
#include <iomanip>
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace sdi_toolBox::desktop::utils::uuid
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
/**
|
||||
* @brief Generate a unique identifier based on the current time (microseconds).
|
||||
*
|
||||
* Produces a string identifier derived from the current timestamp in microseconds.
|
||||
* If @p moreEntropy is true, additional random bytes are appended to increase
|
||||
* uniqueness (useful when multiple identifiers are generated in quick succession).
|
||||
*
|
||||
* @param moreEntropy If true, append extra random entropy to the identifier.
|
||||
* @return std::string Generated identifier (ASCII string, format not strictly defined).
|
||||
*/
|
||||
std::string uniqid(bool moreEntropy = false);
|
||||
|
||||
/**
|
||||
* @brief Generate a random UUID (version 4).
|
||||
*
|
||||
* Produces a RFC 4122 compliant UUID version 4 using random data.
|
||||
* The returned string uses the canonical textual representation:
|
||||
* "8-4-4-4-12" hexadecimal digits.
|
||||
*
|
||||
* @return std::string UUID v4 as a text string.
|
||||
*/
|
||||
std::string v4();
|
||||
|
||||
/**
|
||||
* @brief Generate a time-ordered UUID (version 7).
|
||||
*
|
||||
* Produces a UUID v7 combining a timestamp and random bits to allow
|
||||
* roughly time-ordered identifiers while keeping sufficient entropy for uniqueness.
|
||||
* The returned string uses the canonical textual representation:
|
||||
* "8-4-4-4-12" hexadecimal digits.
|
||||
*
|
||||
* @note UUID v7 is a newer specification intended for sortable UUIDs.
|
||||
*
|
||||
* @return std::string UUID v7 as a text string.
|
||||
*/
|
||||
std::string v7();
|
||||
//--------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/* Generates a unique identifier based on the current time in
|
||||
* microseconds. If the `moreEntropy` parameter is set to
|
||||
* `true`, additional random data is appended to the identifier
|
||||
* to increase its uniqueness. The generated identifier is
|
||||
* returned as a string. */
|
||||
inline std::string uniqid(const bool moreEntropy)
|
||||
{
|
||||
const auto now = std::chrono::system_clock::now(); // Get current time point
|
||||
const auto epoch = now.time_since_epoch(); // Get duration since epoch
|
||||
const auto us_since_epoch = std::chrono::duration_cast<std::chrono::microseconds>(epoch).count();
|
||||
|
||||
// PHP format: "%08x%05x" -> 8 hex chars (sec) + 5 hex chars (usec fraction)
|
||||
// sec = full seconds since epoch
|
||||
// usec = microseconds fraction within the current second (0..999999)
|
||||
const auto sec = static_cast<uint32_t>(us_since_epoch / 1'000'000);
|
||||
const auto usec = static_cast<uint32_t>(us_since_epoch % 1'000'000);
|
||||
std::string result = std::format("{:08x}{:05x}", sec, usec);
|
||||
|
||||
// PHP moreEntropy: appends a random float in [0, 10) with 8 decimal places
|
||||
// Example output: "5f68b2056fbac7.12345678"
|
||||
if (moreEntropy)
|
||||
{
|
||||
thread_local auto rng = std::mt19937{ std::random_device{}() };
|
||||
auto f_dist = std::uniform_real_distribution<double>(0.0, 10.0);
|
||||
|
||||
// Append the random data in hexadecimal format
|
||||
result = result + std::format("{:.8f}", f_dist(rng));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Generates a random UUID (version 4) and returns it as a
|
||||
* string. The UUID is generated using random numbers, and it
|
||||
* follows the standard format of 8-4-4-4-12 hexadecimal
|
||||
* characters. */
|
||||
inline std::string v4()
|
||||
{
|
||||
/*
|
||||
* UUID version 4 is a randomly generated UUID.
|
||||
* It's structured as follows:
|
||||
* - 122 bits are random
|
||||
* - 6 bits are fixed to indicate the version and variant
|
||||
* The total is 128 bits, formatted as 8-4-4-4-12 hexadecimal characters.
|
||||
*
|
||||
* The version (4) is set in the 7th byte (index 6) and the variant
|
||||
* is set in the 9th byte (index 8).
|
||||
*/
|
||||
std::array<uint8_t, 16> bytes;
|
||||
|
||||
// Fast thread-local RNG seeded from random_device once per thread
|
||||
thread_local auto rng = std::mt19937{ std::random_device{}() };
|
||||
auto dist = std::uniform_int_distribution<uint32_t>(0, 0xFF);
|
||||
|
||||
// Fill the random bytes
|
||||
for (auto &byte : bytes)
|
||||
byte = static_cast<uint8_t>(dist(rng)); // Generate random bytes (8 bits each)
|
||||
|
||||
// Set version to 4 -> xxxx0100 in the 7th byte (index 6)
|
||||
bytes[6] = static_cast<uint8_t>((bytes[6] & 0x0F) | 0x40);
|
||||
|
||||
// Set variant to 10xxxxxx in the 9th byte (index 8)
|
||||
bytes[8] = static_cast<uint8_t>((bytes[8] & 0x3F) | 0x80);
|
||||
|
||||
// Format as 8-4-4-4-12 hex
|
||||
std::ostringstream oss;
|
||||
oss << std::hex << std::nouppercase << std::setfill('0');
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
oss << std::setw(2) << static_cast<int>(bytes[i]);
|
||||
if (i == 3 || i == 5 || i == 7 || i == 9)
|
||||
oss << '-';
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Generates a UUID (version 7) based on the current timestamp
|
||||
* and random data. The UUID is generated using a combination of
|
||||
* the current time and random numbers, and it follows the
|
||||
* standard format of 8-4-4-4-12 hexadecimal characters. */
|
||||
inline std::string v7()
|
||||
{
|
||||
/*
|
||||
* UUID version 7 is a time-ordered UUID that combines a timestamp with random bits.
|
||||
* It's structured as follows:
|
||||
* - 48 bits for the timestamp (milliseconds since Unix epoch)
|
||||
* - 12 bits for the version (7)
|
||||
* - 62 bits for random data (to ensure uniqueness)
|
||||
* The total is 128 bits, formatted as 8-4-4-4-12 hexadecimal characters.
|
||||
*
|
||||
* The version (7) is set in the 7th byte (index 6) and the variant
|
||||
* is set in the 9th byte (index 8).
|
||||
*/
|
||||
std::array<uint8_t, 16> bytes;
|
||||
|
||||
// Fast thread-local RNG seeded from random_device once per thread
|
||||
thread_local auto rng = std::mt19937{ std::random_device{}() };
|
||||
auto dist = std::uniform_int_distribution<uint32_t>(0, 0xFF);
|
||||
|
||||
const auto now = std::chrono::system_clock::now(); // Get current time point
|
||||
const auto epoch = now.time_since_epoch(); // Get duration since epoch
|
||||
const uint64_t ms_since_epoch = std::chrono::duration_cast<std::chrono::milliseconds>(epoch).count();
|
||||
|
||||
// Fill timestamp (Big-endian)
|
||||
bytes[0] = static_cast<uint8_t>((ms_since_epoch >> 40) & 0xFF);
|
||||
bytes[1] = static_cast<uint8_t>((ms_since_epoch >> 32) & 0xFF);
|
||||
bytes[2] = static_cast<uint8_t>((ms_since_epoch >> 24) & 0xFF);
|
||||
bytes[3] = static_cast<uint8_t>((ms_since_epoch >> 16) & 0xFF);
|
||||
bytes[4] = static_cast<uint8_t>((ms_since_epoch >> 8) & 0xFF);
|
||||
bytes[5] = static_cast<uint8_t>(ms_since_epoch & 0xFF);
|
||||
|
||||
// Generate randomness for the rest
|
||||
for (size_t i = 6; i < 16; ++i)
|
||||
bytes[i] = static_cast<uint8_t>(dist(rng)); // Generate random bytes (8 bits each)
|
||||
|
||||
// Set Version 7 (bits 48-51 -> 0111)
|
||||
bytes[6] = static_cast<uint8_t>((bytes[6] & 0x0F) | 0x70);
|
||||
|
||||
// Set Variant (bits 64-65 -> 10)
|
||||
bytes[8] = static_cast<uint8_t>((bytes[8] & 0x3F) | 0x80);
|
||||
|
||||
// Format as 8-4-4-4-12 hex
|
||||
std::ostringstream oss;
|
||||
oss << std::hex << std::nouppercase << std::setfill('0');
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
oss << std::setw(2) << static_cast<int>(bytes[i]);
|
||||
if (i == 3 || i == 5 || i == 7 || i == 9)
|
||||
oss << '-';
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_toolBox::desktop::utils::uuid
|
||||
Reference in New Issue
Block a user