aboutsummaryrefslogtreecommitdiff
path: root/pw_base64/public/pw_base64/base64.h
blob: dc5be2d3ae9f5517cc584fc4eff8c6111da5cf18 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
// 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