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
|
||||
Reference in New Issue
Block a user