aboutsummaryrefslogtreecommitdiff
path: root/pw_base64/public/pw_base64/base64.h
blob: a0dcc82cbe78e260dd5cf3e3fe7654fc0a19d91c (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
// 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 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 {

// Returns the size of the given number of bytes when encoded as Base64. 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.
// Encodes to the standard alphabet with + and / for characters 62 and 63.
// Exactly EncodedSize(binary_size_bytes) bytes will be written. 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.
//
// 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. Returns the number of bytes written, which will be 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. 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.
// If the data is larger than kMaxBinaryDataSizeBytes, an assertion fails.
template <size_t kMaxBinaryDataSizeBytes>
inline InlineString<EncodedSize(kMaxBinaryDataSizeBytes)> Encode(
    span<const std::byte> binary) {
  InlineString<EncodedSize(kMaxBinaryDataSizeBytes)> output;
  Encode(binary, output);
  return output;
}

// Returns the maximum size of decoded Base64 data in bytes. base64_size_bytes
// must be a multiple of 4, since Base64 encodes 3-byte groups into 4-character
// strings. If the last 3-byte group has padding, the actual decoded size would
// be 1 or 2 bytes less than 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. The output buffer *MUST* be
// at least MaxDecodedSize bytes large. The output buffer may be the same as the
// input buffer; decoding can occur in place. Returns the number of bytes that
// were decoded.
//
// Decodes either standard (+/) or URL-safe (-_) alphabets. The data must be
// padded to 4-character blocks with =. This function does NOT check that the
// input is valid! Use IsValid or the four-argument overload to check the
// input formatting.
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);

template <typename T>
inline void DecodeInPlace(InlineBasicString<T>& buffer) {
  static_assert(sizeof(T) == sizeof(char));
  buffer.resize(Decode(buffer, buffer.data()));
}

// Returns true if the provided string is valid Base64 encoded data. Accepts
// either the standard (+/) or URL-safe (-_) alphabets.
inline bool IsValid(std::string_view base64) {
  return pw_Base64IsValid(base64.data(), base64.size());
}

}  // namespace pw::base64

#endif  // __cplusplus