xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/host/common/byte_buffer.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2023 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 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
16 
17 #include <cpp-string/string_printf.h>
18 #include <pw_string/utf_codecs.h>
19 
20 #include <string>
21 
22 namespace bt {
23 
Copy(MutableByteBuffer * out_buffer) const24 void ByteBuffer::Copy(MutableByteBuffer* out_buffer) const {
25   PW_CHECK(out_buffer);
26   CopyRaw(out_buffer->mutable_data(), out_buffer->size(), 0, size());
27 }
28 
Copy(MutableByteBuffer * out_buffer,size_t pos,size_t size) const29 void ByteBuffer::Copy(MutableByteBuffer* out_buffer,
30                       size_t pos,
31                       size_t size) const {
32   PW_CHECK(out_buffer);
33   CopyRaw(out_buffer->mutable_data(), out_buffer->size(), pos, size);
34 }
35 
Printable(size_t pos,size_t size) const36 std::string ByteBuffer::Printable(size_t pos, size_t size) const {
37   PW_CHECK(pos + size <= this->size());
38   const char* region_start = reinterpret_cast<const char*>(data() + pos);
39   std::string_view view(region_start, size);
40 
41   // If the region already contains only valid UTF-8 characters, it's already
42   // printable
43   if (pw::utf8::IsStringValid(view)) {
44     return std::string(view);
45   }
46 
47   std::string ret(size, '\0');
48   for (size_t i = 0; i < size; i++) {
49     if (std::isprint(view[i])) {
50       ret[i] = view[i];
51     } else {
52       ret[i] = '.';
53     }
54   }
55 
56   return ret;
57 }
58 
view(size_t pos,size_t size) const59 BufferView ByteBuffer::view(size_t pos, size_t size) const {
60   PW_CHECK(pos <= this->size(),
61            "offset past buffer (pos: %zu, size: %zu)",
62            pos,
63            this->size());
64   return BufferView(data() + pos, std::min(size, this->size() - pos));
65 }
66 
subspan(size_t pos,size_t size) const67 pw::span<const std::byte> ByteBuffer::subspan(size_t pos, size_t size) const {
68   PW_CHECK(pos <= this->size(),
69            "offset past buffer (pos: %zu, size: %zu)",
70            pos,
71            this->size());
72   return pw::span(reinterpret_cast<const std::byte*>(data()) + pos,
73                   std::min(size, this->size() - pos));
74 }
75 
AsString() const76 std::string_view ByteBuffer::AsString() const {
77   return std::string_view(reinterpret_cast<const char*>(data()), size());
78 }
79 
AsHexadecimal() const80 std::string ByteBuffer::AsHexadecimal() const {
81   std::string formatted_string;
82   for (size_t i = 0; i < size(); ++i) {
83     bt_lib_cpp_string::StringAppendf(
84         &formatted_string, "%02x", static_cast<int>(data()[i]));
85     if (i < size() - 1) {
86       formatted_string += " ";
87     }
88   }
89   return formatted_string;
90 }
91 
ToString(bool as_hex) const92 std::string ByteBuffer::ToString(bool as_hex) const {
93   if (as_hex) {
94     return AsHexadecimal();
95   }
96   return std::string(AsString());
97 }
98 
ToVector() const99 std::vector<uint8_t> ByteBuffer::ToVector() const {
100   std::vector<uint8_t> vec(size());
101   MutableBufferView vec_view(vec.data(), vec.size());
102   vec_view.Write(*this);
103   return vec;
104 }
105 
CopyRaw(void * dst_data,size_t dst_capacity,size_t src_offset,size_t copy_size) const106 void ByteBuffer::CopyRaw(void* dst_data,
107                          size_t dst_capacity,
108                          size_t src_offset,
109                          size_t copy_size) const {
110   PW_CHECK(copy_size == 0 || dst_data != nullptr,
111            "%zu byte write to pointer %p",
112            copy_size,
113            dst_data);
114   PW_CHECK(copy_size <= dst_capacity,
115            "destination not large enough (required: %zu, available: %zu)",
116            copy_size,
117            dst_capacity);
118   PW_CHECK(src_offset <= this->size(),
119            "offset exceeds source range (begin: %zu, copy_size: %zu)",
120            src_offset,
121            this->size());
122   PW_CHECK(
123       std::numeric_limits<size_t>::max() - copy_size >= src_offset,
124       "end of source range overflows size_t (src_offset: %zu, copy_size: %zu)",
125       src_offset,
126       copy_size);
127   PW_CHECK(src_offset + copy_size <= this->size(),
128            "end exceeds source range (end: %zu, copy_size: %zu)",
129            src_offset + copy_size,
130            this->size());
131 
132   // Data pointers for zero-length buffers are nullptr, over which memcpy has
133   // undefined behavior, even for count = 0. Skip the memcpy invocation in that
134   // case.
135   if (copy_size == 0) {
136     return;
137   }
138   std::memcpy(dst_data, data() + src_offset, copy_size);
139 }
140 
Write(const uint8_t * data,size_t size,size_t pos)141 void MutableByteBuffer::Write(const uint8_t* data, size_t size, size_t pos) {
142   BufferView from(data, size);
143   MutableBufferView to = mutable_view(pos);
144   from.Copy(&to);
145 }
146 
mutable_view(size_t pos,size_t size)147 MutableBufferView MutableByteBuffer::mutable_view(size_t pos, size_t size) {
148   PW_CHECK(pos <= this->size(),
149            "offset past buffer (pos: %zu, size: %zu)",
150            pos,
151            this->size());
152   return MutableBufferView(mutable_data() + pos,
153                            std::min(size, this->size() - pos));
154 }
155 
mutable_subspan(size_t pos,size_t size)156 pw::span<std::byte> MutableByteBuffer::mutable_subspan(size_t pos,
157                                                        size_t size) {
158   PW_CHECK(pos <= this->size(),
159            "offset past buffer (pos: %zu, size: %zu)",
160            pos,
161            this->size());
162   return pw::span(reinterpret_cast<std::byte*>(mutable_data()) + pos,
163                   std::min(size, this->size() - pos));
164 }
165 
166 DynamicByteBuffer::DynamicByteBuffer() = default;
167 
DynamicByteBuffer(size_t buffer_size)168 DynamicByteBuffer::DynamicByteBuffer(size_t buffer_size)
169     : buffer_size_(buffer_size) {
170   if (buffer_size == 0) {
171     return;
172   }
173 
174   // make_unique value-initializes the buffer to 0.
175   buffer_ = std::make_unique<uint8_t[]>(buffer_size);
176 
177   // TODO(armansito): For now this is dumb but we should properly handle the
178   // case when we're out of memory.
179   PW_CHECK(buffer_.get(), "failed to allocate buffer");
180 }
181 
DynamicByteBuffer(const ByteBuffer & buffer)182 DynamicByteBuffer::DynamicByteBuffer(const ByteBuffer& buffer)
183     : buffer_size_(buffer.size()),
184       buffer_(buffer.size() ? std::make_unique<uint8_t[]>(buffer.size())
185                             : nullptr) {
186   PW_CHECK(!buffer_size_ || buffer_.get(),
187            "|buffer| cannot be nullptr when |buffer_size| is non-zero");
188   buffer.Copy(this);
189 }
190 
DynamicByteBuffer(const DynamicByteBuffer & buffer)191 DynamicByteBuffer::DynamicByteBuffer(const DynamicByteBuffer& buffer)
192     : DynamicByteBuffer(static_cast<const ByteBuffer&>(buffer)) {}
193 
DynamicByteBuffer(const std::string & buffer)194 DynamicByteBuffer::DynamicByteBuffer(const std::string& buffer) {
195   buffer_size_ = buffer.length();
196   buffer_ = std::make_unique<uint8_t[]>(buffer_size_);
197   memcpy(buffer_.get(), buffer.data(), buffer_size_);
198 }
199 
DynamicByteBuffer(size_t buffer_size,std::unique_ptr<uint8_t[]> buffer)200 DynamicByteBuffer::DynamicByteBuffer(size_t buffer_size,
201                                      std::unique_ptr<uint8_t[]> buffer)
202     : buffer_size_(buffer_size), buffer_(std::move(buffer)) {
203   PW_CHECK(!buffer_size_ || buffer_.get(),
204            "|buffer| cannot be nullptr when |buffer_size| is non-zero");
205 }
206 
DynamicByteBuffer(DynamicByteBuffer && other)207 DynamicByteBuffer::DynamicByteBuffer(DynamicByteBuffer&& other) {
208   buffer_size_ = other.buffer_size_;
209   other.buffer_size_ = 0u;
210   buffer_ = std::move(other.buffer_);
211 }
212 
operator =(DynamicByteBuffer && other)213 DynamicByteBuffer& DynamicByteBuffer::operator=(DynamicByteBuffer&& other) {
214   buffer_size_ = other.buffer_size_;
215   other.buffer_size_ = 0u;
216   buffer_ = std::move(other.buffer_);
217   return *this;
218 }
219 
data() const220 const uint8_t* DynamicByteBuffer::data() const { return buffer_.get(); }
221 
mutable_data()222 uint8_t* DynamicByteBuffer::mutable_data() { return buffer_.get(); }
223 
size() const224 size_t DynamicByteBuffer::size() const { return buffer_size_; }
225 
Fill(uint8_t value)226 void DynamicByteBuffer::Fill(uint8_t value) {
227   memset(buffer_.get(), value, buffer_size_);
228 }
229 
expand(size_t new_buffer_size)230 bool DynamicByteBuffer::expand(size_t new_buffer_size) {
231   // we only allow growing the buffer, not shrinking it
232   if (new_buffer_size < buffer_size_) {
233     return false;
234   }
235 
236   // no reason to do extra work
237   if (new_buffer_size == buffer_size_) {
238     return false;
239   }
240 
241   std::unique_ptr<uint8_t[]> new_buffer =
242       std::make_unique<uint8_t[]>(new_buffer_size);
243   memcpy(new_buffer.get(), buffer_.get(), buffer_size_);
244   buffer_.swap(new_buffer);
245   buffer_size_ = new_buffer_size;
246 
247   return true;
248 }
249 
cbegin() const250 ByteBuffer::const_iterator DynamicByteBuffer::cbegin() const {
251   return buffer_.get();
252 }
253 
cend() const254 ByteBuffer::const_iterator DynamicByteBuffer::cend() const {
255   return buffer_.get() + buffer_size_;
256 }
257 
BufferView(const ByteBuffer & buffer,size_t size)258 BufferView::BufferView(const ByteBuffer& buffer, size_t size) {
259   *this = buffer.view(0u, size);
260 }
261 
BufferView(std::string_view string)262 BufferView::BufferView(std::string_view string) {
263   size_ = string.size();
264   bytes_ = reinterpret_cast<const uint8_t*>(string.data());
265 }
266 
BufferView(const std::vector<uint8_t> & vec)267 BufferView::BufferView(const std::vector<uint8_t>& vec)
268     : BufferView(vec.data(), vec.size()) {}
269 
BufferView(pw::span<const std::byte> bytes)270 BufferView::BufferView(pw::span<const std::byte> bytes)
271     : BufferView(bytes.data(), bytes.size()) {}
272 
BufferView(const void * bytes,size_t size)273 BufferView::BufferView(const void* bytes, size_t size)
274     : size_(size), bytes_(static_cast<const uint8_t*>(bytes)) {
275   // If |size| non-zero then |bytes| cannot be nullptr.
276   PW_CHECK(!size_ || bytes_, "|bytes_| cannot be nullptr if |size_| > 0");
277 }
278 
279 BufferView::BufferView() = default;
280 
data() const281 const uint8_t* BufferView::data() const { return bytes_; }
282 
size() const283 size_t BufferView::size() const { return size_; }
284 
cbegin() const285 ByteBuffer::const_iterator BufferView::cbegin() const { return bytes_; }
286 
cend() const287 ByteBuffer::const_iterator BufferView::cend() const { return bytes_ + size_; }
288 
MutableBufferView(MutableByteBuffer * buffer)289 MutableBufferView::MutableBufferView(MutableByteBuffer* buffer) {
290   PW_CHECK(buffer);
291   size_ = buffer->size();
292   bytes_ = buffer->mutable_data();
293 }
294 
MutableBufferView(void * bytes,size_t size)295 MutableBufferView::MutableBufferView(void* bytes, size_t size)
296     : size_(size), bytes_(static_cast<uint8_t*>(bytes)) {
297   // If |size| non-zero then |bytes| cannot be nullptr.
298   PW_CHECK(!size_ || bytes_, "|bytes_| cannot be nullptr if |size_| > 0");
299 }
300 
301 MutableBufferView::MutableBufferView() = default;
302 
data() const303 const uint8_t* MutableBufferView::data() const { return bytes_; }
304 
size() const305 size_t MutableBufferView::size() const { return size_; }
306 
cbegin() const307 ByteBuffer::const_iterator MutableBufferView::cbegin() const { return bytes_; }
308 
cend() const309 ByteBuffer::const_iterator MutableBufferView::cend() const {
310   return bytes_ + size_;
311 }
312 
mutable_data()313 uint8_t* MutableBufferView::mutable_data() { return bytes_; }
314 
Fill(uint8_t value)315 void MutableBufferView::Fill(uint8_t value) { memset(bytes_, value, size_); }
316 
317 }  // namespace bt
318