blob: dc5be2d3ae9f5517cc584fc4eff8c6111da5cf18 [file] [log] [blame]
// Copyright 2020 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
// Functions for encoding and decoding data in Base64 as specified by RFC 3548
// and RFC 4648. See https://tools.ietf.org/html/rfc4648
#pragma once
#include <stdbool.h>
#include <stddef.h>
// C-compatible versions of a subset of the pw_base64 module.
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
// Returns the size of the given number of bytes when encoded as Base64. Base64
//
// Equivalent to pw::base64::EncodedSize().
#define PW_BASE64_ENCODED_SIZE(binary_size_bytes) \
(((size_t)binary_size_bytes + 2) / 3 * 4) // +2 to round up to a 3-byte group
// Encodes the provided data in Base64 and writes the result to the buffer.
// Exactly PW_BASE64_ENCODED_SIZE(binary_size_bytes) bytes will be written. The
// output buffer *MUST* be large enough for the encoded output!
//
// Equivalent to pw::base64::Encode().
void pw_Base64Encode(const void* binary_data,
const size_t binary_size_bytes,
char* output);
// Evaluates to the maximum size of decoded Base64 data in bytes.
//
// Equivalent to pw::base64::MaxDecodedSize().
#define PW_BASE64_MAX_DECODED_SIZE(base64_size_bytes) \
(((size_t)base64_size_bytes) / 4 * 3)
// Decodes the provided Base64 data into raw binary. The output buffer *MUST* be
// at least PW_BASE64_MAX_DECODED_SIZE bytes large.
//
// Equivalent to pw::base64::Decode().
size_t pw_Base64Decode(const char* base64,
size_t base64_size_bytes,
void* output);
// Returns true if provided char is a valid Base64 character.
bool pw_Base64IsValidChar(char base64_char);
// Returns true if the provided string is valid Base64 encoded data. Accepts
// either the standard (+/) or URL-safe (-_) alphabets.
//
// Equivalent to pw::base64::IsValid().
bool pw_Base64IsValid(const char* base64_data, size_t base64_size);
// C++ API, which uses the C functions internally.
#ifdef __cplusplus
} // extern "C"
#include <string_view>
#include <type_traits>
#include "pw_span/span.h"
#include "pw_string/string.h"
namespace pw::base64 {
/// @param[in] binary_size_bytes The size of the binary data in bytes, before
/// encoding.
///
/// @returns The size of `binary_size_bytes` after Base64 encoding.
///
/// @note Base64 encodes 3-byte groups into 4-character strings. The final group
/// is padded to be 3 bytes if it only has 1 or 2.
constexpr size_t EncodedSize(size_t binary_size_bytes) {
return PW_BASE64_ENCODED_SIZE(binary_size_bytes);
}
/// Encodes the provided data in Base64 and writes the result to the buffer.
///
/// @param[in] binary The binary data to encode.
///
/// @param[out] The output buffer where the encoded data is placed. Exactly
/// `EncodedSize(binary_size_bytes)` bytes is written.
///
/// @note Encodes to the standard alphabet with `+` and `/` for characters `62`
/// and `63`.
///
/// @pre
/// * The output buffer **MUST** be large enough for the encoded output!
/// * The input and output buffers **MUST NOT** be the same; encoding cannot
/// occur in place.
///
/// @warning The resulting string in the output is **NOT** null-terminated!
inline void Encode(span<const std::byte> binary, char* output) {
pw_Base64Encode(binary.data(), binary.size_bytes(), output);
}
/// Encodes the provided data in Base64 if the result fits in the provided
/// buffer.
///
/// @param[in] binary The binary data to encode.
///
/// @param[out] output_buffer The output buffer where the encoded data is
/// placed.
///
/// @warning The resulting string in the output is **NOT** null-terminated!
///
/// @returns The number of bytes written. Returns `0` if the output buffer
/// is too small.
size_t Encode(span<const std::byte> binary, span<char> output_buffer);
/// Appends Base64 encoded binary data to the provided `pw::InlineString`.
///
/// @param[in] binary The binary data that has already been Base64-encoded.
///
/// @param[out] output The `pw::InlineString` that `binary` is appended to.
///
/// If the data does not fit in the string, an assertion fails.
void Encode(span<const std::byte> binary, InlineString<>& output);
/// Creates a `pw::InlineString<>` large enough to hold
/// `kMaxBinaryDataSizeBytes` of binary data when encoded as Base64 and encodes
/// the provided span into it.
template <size_t kMaxBinaryDataSizeBytes>
inline InlineString<EncodedSize(kMaxBinaryDataSizeBytes)> Encode(
span<const std::byte> binary) {
InlineString<EncodedSize(kMaxBinaryDataSizeBytes)> output;
Encode(binary, output);
return output;
}
/// Calculates the maximum size of Base64-encoded data after decoding.
///
/// @param[in] base64_size_bytes The size of the Base64-encoded data.
///
/// @pre `base64_size_bytes` must be a multiple of 4, since Base64 encodes
/// 3-byte groups into 4-character strings.
///
/// @returns The maximum size of the Base64-encoded data represented by
/// `base64_bytes_size` after decoding. If the last 3-byte group has padding,
/// the actual decoded size will be 1 or 2 bytes less than the value returned
/// by `MaxDecodedSize()`.
constexpr size_t MaxDecodedSize(size_t base64_size_bytes) {
return PW_BASE64_MAX_DECODED_SIZE(base64_size_bytes);
}
/// Decodes the provided Base64 data into raw binary.
///
/// @pre
/// * The output buffer **MUST** be at least `MaxDecodedSize()` bytes large.
/// * This function does NOT check that the input is valid! Use `IsValid()`
/// or the four-argument overload to check the input formatting.
///
/// @param[in] base64 The Base64 data that should be decoded. Can be encoded
/// with either the standard (`+/`) or URL-safe (`-_`) alphabet. The data must
/// be padded to 4-character blocks with `=`.
///
/// @param[out] output The output buffer where the raw binary will be placed.
/// The output buffer may be the same as the input buffer; decoding can occur
/// in place.
///
/// @returns The number of bytes that were decoded.
inline size_t Decode(std::string_view base64, void* output) {
return pw_Base64Decode(base64.data(), base64.size(), output);
}
/// Decodes the provided Base64 data, if the data is valid and fits in the
/// output buffer.
///
/// @returns The number of bytes written, which will be `0` if the data is
/// invalid or doesn't fit.
size_t Decode(std::string_view base64, span<std::byte> output_buffer);
/// Decodes a `pw::InlineString<>` in place.
template <typename T>
inline void DecodeInPlace(InlineBasicString<T>& buffer) {
static_assert(sizeof(T) == sizeof(char));
buffer.resize(Decode(buffer, buffer.data()));
}
/// @param[in] base64 The string to check. Can be encoded with either the
/// standard (`+/`) or URL-safe (`-_`) alphabet.
///
/// @returns `true` if the provided string is valid Base64-encoded data.
inline bool IsValid(std::string_view base64) {
return pw_Base64IsValid(base64.data(), base64.size());
}
/// @param[in] base64 The character to check. Can be encoded with either the
/// standard (`+/`) or URL-safe (`-_`) alphabet.
///
/// @returns `true` if the provided character is a valid Base64 character.
inline bool IsValidChar(char base64) { return pw_Base64IsValidChar(base64); }
} // namespace pw::base64
#endif // __cplusplus