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