• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 // This file provides functions for working with the prefixed Base64 format for
16 // tokenized messages. This format is useful for transmitting tokenized messages
17 // as plain text.
18 //
19 // The format uses a prefix character ($), followed by the Base64 version of the
20 // tokenized message. For example, consider a tokenized message with token
21 // 0xfeb35a42 and encoded argument 0x13. This messsage would be encoded as
22 // follows:
23 //
24 //            Binary: 42 5a b3 fe 13  [5 bytes]
25 //
26 //   Prefixed Base64: $Qlqz/hM=       [9 bytes]
27 //
28 #pragma once
29 
30 #include <stddef.h>
31 
32 #include "pw_preprocessor/util.h"
33 #include "pw_tokenizer/config.h"
34 
35 // This character is used to mark the start of a Base64-encoded tokenized
36 // message. For consistency, it is recommended to always use $ if possible.
37 // If required, a different non-Base64 character may be used as a prefix.
38 #define PW_TOKENIZER_BASE64_PREFIX '$'
39 
40 PW_EXTERN_C_START
41 
42 // Encodes a binary tokenized message as prefixed Base64 with a null terminator.
43 // Returns the encoded string length (excluding the null terminator). Returns 0
44 // if the buffer is too small. Always null terminates if the output buffer is
45 // not empty.
46 //
47 // Equivalent to pw::tokenizer::PrefixedBase64Encode.
48 size_t pw_tokenizer_PrefixedBase64Encode(const void* binary_message,
49                                          size_t binary_size_bytes,
50                                          void* output_buffer,
51                                          size_t output_buffer_size_bytes);
52 
53 // Decodes a prefixed Base64 tokenized message to binary. Returns the size of
54 // the decoded binary data. The resulting data is ready to be passed to
55 // pw::tokenizer::Detokenizer::Detokenize. Returns 0 if the buffer is too small,
56 // the expected prefix character is missing, or the Base64 data is corrupt.
57 //
58 // Equivalent to pw::tokenizer::PrefixedBase64Encode.
59 size_t pw_tokenizer_PrefixedBase64Decode(const void* base64_message,
60                                          size_t base64_size_bytes,
61                                          void* output_buffer,
62                                          size_t output_buffer_size);
63 
64 PW_EXTERN_C_END
65 
66 #ifdef __cplusplus
67 
68 #include <string_view>
69 
70 #include "pw_base64/base64.h"
71 #include "pw_span/span.h"
72 #include "pw_tokenizer/config.h"
73 #include "pw_tokenizer/tokenize.h"
74 
75 namespace pw::tokenizer {
76 
77 inline constexpr char kBase64Prefix = PW_TOKENIZER_BASE64_PREFIX;
78 
79 #undef PW_TOKENIZER_BASE64_PREFIX  // In C++, use the variable, not the macro.
80 
81 // Returns the size of a tokenized message (token + arguments) when encoded as
82 // prefixed Base64. Includes room for the prefix character ($) and encoded
83 // message. This value is the capacity needed to encode to a pw::InlineString.
Base64EncodedStringSize(size_t message_size)84 constexpr size_t Base64EncodedStringSize(size_t message_size) {
85   return sizeof(kBase64Prefix) + base64::EncodedSize(message_size);
86 }
87 
88 // Same as Base64EncodedStringSize(), but for sizing char buffers. Includes room
89 // for the prefix character ($), encoded message, and a null terminator.
Base64EncodedBufferSize(size_t message_size)90 constexpr size_t Base64EncodedBufferSize(size_t message_size) {
91   return Base64EncodedStringSize(message_size) + sizeof('\0');
92 }
93 
94 // The minimum buffer size that can hold a tokenized message that is
95 // PW_TOKENIZER_CFG_ENCODING_BUFFER_SIZE_BYTES long encoded as prefixed Base64.
96 inline constexpr size_t kDefaultBase64EncodedBufferSize =
97     Base64EncodedBufferSize(PW_TOKENIZER_CFG_ENCODING_BUFFER_SIZE_BYTES);
98 
99 // Encodes a binary tokenized message as prefixed Base64 with a null terminator.
100 // Returns the encoded string length (excluding the null terminator). Returns 0
101 // if the buffer is too small. Always null terminates if the output buffer is
102 // not empty.
PrefixedBase64Encode(span<const std::byte> binary_message,span<char> output_buffer)103 inline size_t PrefixedBase64Encode(span<const std::byte> binary_message,
104                                    span<char> output_buffer) {
105   return pw_tokenizer_PrefixedBase64Encode(binary_message.data(),
106                                            binary_message.size(),
107                                            output_buffer.data(),
108                                            output_buffer.size());
109 }
110 
111 // Also accept a span<const uint8_t> for the binary message.
PrefixedBase64Encode(span<const uint8_t> binary_message,span<char> output_buffer)112 inline size_t PrefixedBase64Encode(span<const uint8_t> binary_message,
113                                    span<char> output_buffer) {
114   return PrefixedBase64Encode(as_bytes(binary_message), output_buffer);
115 }
116 
117 // Encodes a binary tokenized message as prefixed Base64 to a pw::InlineString,
118 // appending to any existing contents. Asserts if the message does not fit in
119 // the string.
120 void PrefixedBase64Encode(span<const std::byte> binary_message,
121                           InlineString<>& output);
122 
PrefixedBase64Encode(span<const uint8_t> binary_message,InlineString<> & output)123 inline void PrefixedBase64Encode(span<const uint8_t> binary_message,
124                                  InlineString<>& output) {
125   return PrefixedBase64Encode(as_bytes(binary_message), output);
126 }
127 
128 // Encodes a binary tokenized message as prefixed Base64 to a pw::InlineString.
129 // The pw::InlineString is sized to fit messages up to
130 // kMaxBinaryMessageSizeBytes long. Asserts if the message is larger.
131 template <size_t kMaxBinaryMessageSizeBytes =
132               PW_TOKENIZER_CFG_ENCODING_BUFFER_SIZE_BYTES>
PrefixedBase64Encode(span<const std::byte> binary_message)133 auto PrefixedBase64Encode(span<const std::byte> binary_message) {
134   static_assert(kMaxBinaryMessageSizeBytes >= 1, "Messages cannot be empty");
135   InlineString<Base64EncodedStringSize(kMaxBinaryMessageSizeBytes)> string(
136       1, kBase64Prefix);
137   base64::Encode(binary_message, string);
138   return string;
139 }
140 
141 template <size_t kMaxBinaryMessageSizeBytes =
142               PW_TOKENIZER_CFG_ENCODING_BUFFER_SIZE_BYTES>
PrefixedBase64Encode(span<const uint8_t> binary_message)143 auto PrefixedBase64Encode(span<const uint8_t> binary_message) {
144   return PrefixedBase64Encode<kMaxBinaryMessageSizeBytes>(
145       as_bytes(binary_message));
146 }
147 
148 // Decodes a prefixed Base64 tokenized message to binary. Returns the size of
149 // the decoded binary data. The resulting data is ready to be passed to
150 // pw::tokenizer::Detokenizer::Detokenize.
PrefixedBase64Decode(std::string_view base64_message,span<std::byte> output_buffer)151 inline size_t PrefixedBase64Decode(std::string_view base64_message,
152                                    span<std::byte> output_buffer) {
153   return pw_tokenizer_PrefixedBase64Decode(base64_message.data(),
154                                            base64_message.size(),
155                                            output_buffer.data(),
156                                            output_buffer.size());
157 }
158 
159 // Decodes a prefixed Base64 tokenized message to binary in place. Returns the
160 // size of the decoded binary data.
PrefixedBase64DecodeInPlace(span<std::byte> buffer)161 inline size_t PrefixedBase64DecodeInPlace(span<std::byte> buffer) {
162   return pw_tokenizer_PrefixedBase64Decode(
163       buffer.data(), buffer.size(), buffer.data(), buffer.size());
164 }
165 
166 // Decodes a prefixed Base64 tokenized message to binary in place. Resizes the
167 // string to fit the decoded binary data.
168 template <typename CharT>
PrefixedBase64DecodeInPlace(InlineBasicString<CharT> & string)169 inline void PrefixedBase64DecodeInPlace(InlineBasicString<CharT>& string) {
170   static_assert(sizeof(CharT) == sizeof(char));
171   string.resize(pw_tokenizer_PrefixedBase64Decode(
172       string.data(), string.size(), string.data(), string.size()));
173 }
174 
175 }  // namespace pw::tokenizer
176 
177 #endif  // __cplusplus
178