• 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 #include "pw_tokenizer/nested_tokenization.h"
35 
36 PW_EXTERN_C_START
37 
38 // Encodes a binary tokenized message as prefixed Base64 with a null terminator.
39 // Returns the encoded string length (excluding the null terminator). Returns 0
40 // if the buffer is too small. Always null terminates if the output buffer is
41 // not empty.
42 //
43 // Equivalent to pw::tokenizer::PrefixedBase64Encode.
44 size_t pw_tokenizer_PrefixedBase64Encode(const void* binary_message,
45                                          size_t binary_size_bytes,
46                                          void* output_buffer,
47                                          size_t output_buffer_size_bytes);
48 
49 // Decodes a prefixed Base64 tokenized message to binary. Returns the size of
50 // the decoded binary data. The resulting data is ready to be passed to
51 // pw::tokenizer::Detokenizer::Detokenize. Returns 0 if the buffer is too small,
52 // the expected prefix character is missing, or the Base64 data is corrupt.
53 //
54 // Equivalent to pw::tokenizer::PrefixedBase64Encode.
55 size_t pw_tokenizer_PrefixedBase64Decode(const void* base64_message,
56                                          size_t base64_size_bytes,
57                                          void* output_buffer,
58                                          size_t output_buffer_size);
59 
60 PW_EXTERN_C_END
61 
62 #ifdef __cplusplus
63 
64 #include <string_view>
65 
66 #include "pw_base64/base64.h"
67 #include "pw_span/span.h"
68 #include "pw_tokenizer/config.h"
69 #include "pw_tokenizer/tokenize.h"
70 
71 namespace pw::tokenizer {
72 
73 // Returns the size of a tokenized message (token + arguments) when encoded as
74 // prefixed Base64. Includes room for the prefix character ($) and encoded
75 // message. This value is the capacity needed to encode to a pw::InlineString.
Base64EncodedStringSize(size_t message_size)76 constexpr size_t Base64EncodedStringSize(size_t message_size) {
77   return sizeof(PW_TOKENIZER_NESTED_PREFIX) + base64::EncodedSize(message_size);
78 }
79 
80 // Same as Base64EncodedStringSize(), but for sizing char buffers. Includes room
81 // for the prefix character ($), encoded message, and a null terminator.
Base64EncodedBufferSize(size_t message_size)82 constexpr size_t Base64EncodedBufferSize(size_t message_size) {
83   return Base64EncodedStringSize(message_size) + sizeof('\0');
84 }
85 
86 // Encodes a binary tokenized message as prefixed Base64 with a null terminator.
87 // Returns the encoded string length (excluding the null terminator). Returns 0
88 // if the buffer is too small. Always null terminates if the output buffer is
89 // not empty.
PrefixedBase64Encode(span<const std::byte> binary_message,span<char> output_buffer)90 inline size_t PrefixedBase64Encode(span<const std::byte> binary_message,
91                                    span<char> output_buffer) {
92   return pw_tokenizer_PrefixedBase64Encode(binary_message.data(),
93                                            binary_message.size(),
94                                            output_buffer.data(),
95                                            output_buffer.size());
96 }
97 
98 // Also accept a span<const uint8_t> for the binary message.
PrefixedBase64Encode(span<const uint8_t> binary_message,span<char> output_buffer)99 inline size_t PrefixedBase64Encode(span<const uint8_t> binary_message,
100                                    span<char> output_buffer) {
101   return PrefixedBase64Encode(as_bytes(binary_message), output_buffer);
102 }
103 
104 // Encodes a binary tokenized message as prefixed Base64 to a pw::InlineString,
105 // appending to any existing contents. Asserts if the message does not fit in
106 // the string.
107 void PrefixedBase64Encode(span<const std::byte> binary_message,
108                           InlineString<>& output);
109 
PrefixedBase64Encode(span<const uint8_t> binary_message,InlineString<> & output)110 inline void PrefixedBase64Encode(span<const uint8_t> binary_message,
111                                  InlineString<>& output) {
112   return PrefixedBase64Encode(as_bytes(binary_message), output);
113 }
114 
115 // Encodes a binary tokenized message as prefixed Base64 to a pw::InlineString.
116 // The pw::InlineString is sized to fit messages up to
117 // kMaxBinaryMessageSizeBytes long. Asserts if the message is larger.
118 template <size_t kMaxBinaryMessageSizeBytes>
PrefixedBase64Encode(span<const std::byte> binary_message)119 auto PrefixedBase64Encode(span<const std::byte> binary_message) {
120   static_assert(kMaxBinaryMessageSizeBytes >= 1, "Messages cannot be empty");
121   InlineString<Base64EncodedStringSize(kMaxBinaryMessageSizeBytes)> string(
122       1, PW_TOKENIZER_NESTED_PREFIX);
123   base64::Encode(binary_message, string);
124   return string;
125 }
126 
127 template <size_t kMaxBinaryMessageSizeBytes>
PrefixedBase64Encode(span<const uint8_t> binary_message)128 auto PrefixedBase64Encode(span<const uint8_t> binary_message) {
129   return PrefixedBase64Encode<kMaxBinaryMessageSizeBytes>(
130       as_bytes(binary_message));
131 }
132 
133 // Decodes a prefixed Base64 tokenized message to binary. Returns the size of
134 // the decoded binary data. The resulting data is ready to be passed to
135 // pw::tokenizer::Detokenizer::Detokenize.
PrefixedBase64Decode(std::string_view base64_message,span<std::byte> output_buffer)136 inline size_t PrefixedBase64Decode(std::string_view base64_message,
137                                    span<std::byte> output_buffer) {
138   return pw_tokenizer_PrefixedBase64Decode(base64_message.data(),
139                                            base64_message.size(),
140                                            output_buffer.data(),
141                                            output_buffer.size());
142 }
143 
144 // Decodes a prefixed Base64 tokenized message to binary in place. Returns the
145 // size of the decoded binary data.
PrefixedBase64DecodeInPlace(span<std::byte> buffer)146 inline size_t PrefixedBase64DecodeInPlace(span<std::byte> buffer) {
147   return pw_tokenizer_PrefixedBase64Decode(
148       buffer.data(), buffer.size(), buffer.data(), buffer.size());
149 }
150 
PrefixedBase64DecodeInPlace(span<char> buffer)151 inline size_t PrefixedBase64DecodeInPlace(span<char> buffer) {
152   return PrefixedBase64DecodeInPlace(as_writable_bytes(buffer));
153 }
154 
155 // Decodes a prefixed Base64 tokenized message to binary in place. Resizes the
156 // string to fit the decoded binary data.
157 template <typename CharT>
PrefixedBase64DecodeInPlace(InlineBasicString<CharT> & string)158 inline void PrefixedBase64DecodeInPlace(InlineBasicString<CharT>& string) {
159   static_assert(sizeof(CharT) == sizeof(char));
160   string.resize(pw_tokenizer_PrefixedBase64Decode(
161       string.data(), string.size(), string.data(), string.size()));
162 }
163 
164 }  // namespace pw::tokenizer
165 
166 #endif  // __cplusplus
167