• 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/utf_codecs.h>
18 
19 namespace bt {
20 
Copy(MutableByteBuffer * out_buffer) const21 void ByteBuffer::Copy(MutableByteBuffer* out_buffer) const {
22   BT_ASSERT(out_buffer);
23   CopyRaw(out_buffer->mutable_data(), out_buffer->size(), 0, size());
24 }
25 
Copy(MutableByteBuffer * out_buffer,size_t pos,size_t size) const26 void ByteBuffer::Copy(MutableByteBuffer* out_buffer,
27                       size_t pos,
28                       size_t size) const {
29   BT_ASSERT(out_buffer);
30   CopyRaw(out_buffer->mutable_data(), out_buffer->size(), pos, size);
31 }
32 
Printable(size_t pos,size_t size) const33 std::string ByteBuffer::Printable(size_t pos, size_t size) const {
34   BT_ASSERT(pos + size <= this->size());
35   const char* region_start = reinterpret_cast<const char*>(data() + pos);
36   std::string_view view(region_start, size);
37 
38   // If the region already contains only valid UTF-8 characters, it's already
39   // printable
40   if (bt_lib_cpp_string::IsStringUTF8(view)) {
41     return std::string(view);
42   }
43 
44   std::string ret(size, '\0');
45   for (size_t i = 0; i < size; i++) {
46     if (std::isprint(view[i])) {
47       ret[i] = view[i];
48     } else {
49       ret[i] = '.';
50     }
51   }
52 
53   return ret;
54 }
55 
view(size_t pos,size_t size) const56 BufferView ByteBuffer::view(size_t pos, size_t size) const {
57   BT_ASSERT_MSG(pos <= this->size(),
58                 "offset past buffer (pos: %zu, size: %zu)",
59                 pos,
60                 this->size());
61   return BufferView(data() + pos, std::min(size, this->size() - pos));
62 }
63 
subspan(size_t pos,size_t size) const64 pw::span<const std::byte> ByteBuffer::subspan(size_t pos, size_t size) const {
65   BT_ASSERT_MSG(pos <= this->size(),
66                 "offset past buffer (pos: %zu, size: %zu)",
67                 pos,
68                 this->size());
69   return pw::span(reinterpret_cast<const std::byte*>(data()) + pos,
70                   std::min(size, this->size() - pos));
71 }
72 
AsString() const73 std::string_view ByteBuffer::AsString() const {
74   return std::string_view(reinterpret_cast<const char*>(data()), size());
75 }
76 
ToString() const77 std::string ByteBuffer::ToString() const { return std::string(AsString()); }
78 
ToVector() const79 std::vector<uint8_t> ByteBuffer::ToVector() const {
80   std::vector<uint8_t> vec(size());
81   MutableBufferView vec_view(vec.data(), vec.size());
82   vec_view.Write(*this);
83   return vec;
84 }
85 
CopyRaw(void * dst_data,size_t dst_capacity,size_t src_offset,size_t copy_size) const86 void ByteBuffer::CopyRaw(void* dst_data,
87                          size_t dst_capacity,
88                          size_t src_offset,
89                          size_t copy_size) const {
90   BT_ASSERT_MSG(copy_size == 0 || dst_data != nullptr,
91                 "%zu byte write to pointer %p",
92                 copy_size,
93                 dst_data);
94   BT_ASSERT_MSG(copy_size <= dst_capacity,
95                 "destination not large enough (required: %zu, available: %zu)",
96                 copy_size,
97                 dst_capacity);
98   BT_ASSERT_MSG(src_offset <= this->size(),
99                 "offset exceeds source range (begin: %zu, copy_size: %zu)",
100                 src_offset,
101                 this->size());
102   BT_ASSERT_MSG(
103       std::numeric_limits<size_t>::max() - copy_size >= src_offset,
104       "end of source range overflows size_t (src_offset: %zu, copy_size: %zu)",
105       src_offset,
106       copy_size);
107   BT_ASSERT_MSG(src_offset + copy_size <= this->size(),
108                 "end exceeds source range (end: %zu, copy_size: %zu)",
109                 src_offset + copy_size,
110                 this->size());
111 
112   // Data pointers for zero-length buffers are nullptr, over which memcpy has
113   // undefined behavior, even for count = 0. Skip the memcpy invocation in that
114   // case.
115   if (copy_size == 0) {
116     return;
117   }
118   std::memcpy(dst_data, data() + src_offset, copy_size);
119 }
120 
Write(const uint8_t * data,size_t size,size_t pos)121 void MutableByteBuffer::Write(const uint8_t* data, size_t size, size_t pos) {
122   BufferView from(data, size);
123   MutableBufferView to = mutable_view(pos);
124   from.Copy(&to);
125 }
126 
mutable_view(size_t pos,size_t size)127 MutableBufferView MutableByteBuffer::mutable_view(size_t pos, size_t size) {
128   BT_ASSERT_MSG(pos <= this->size(),
129                 "offset past buffer (pos: %zu, size: %zu)",
130                 pos,
131                 this->size());
132   return MutableBufferView(mutable_data() + pos,
133                            std::min(size, this->size() - pos));
134 }
135 
mutable_subspan(size_t pos,size_t size)136 pw::span<std::byte> MutableByteBuffer::mutable_subspan(size_t pos,
137                                                        size_t size) {
138   BT_ASSERT_MSG(pos <= this->size(),
139                 "offset past buffer (pos: %zu, size: %zu)",
140                 pos,
141                 this->size());
142   return pw::span(reinterpret_cast<std::byte*>(mutable_data()) + pos,
143                   std::min(size, this->size() - pos));
144 }
145 
146 DynamicByteBuffer::DynamicByteBuffer() = default;
147 
DynamicByteBuffer(size_t buffer_size)148 DynamicByteBuffer::DynamicByteBuffer(size_t buffer_size)
149     : buffer_size_(buffer_size) {
150   if (buffer_size == 0) {
151     return;
152   }
153 
154   // make_unique value-initializes the buffer to 0.
155   buffer_ = std::make_unique<uint8_t[]>(buffer_size);
156 
157   // TODO(armansito): For now this is dumb but we should properly handle the
158   // case when we're out of memory.
159   BT_ASSERT_MSG(buffer_.get(), "failed to allocate buffer");
160 }
161 
DynamicByteBuffer(const ByteBuffer & buffer)162 DynamicByteBuffer::DynamicByteBuffer(const ByteBuffer& buffer)
163     : buffer_size_(buffer.size()),
164       buffer_(buffer.size() ? std::make_unique<uint8_t[]>(buffer.size())
165                             : nullptr) {
166   BT_ASSERT_MSG(!buffer_size_ || buffer_.get(),
167                 "|buffer| cannot be nullptr when |buffer_size| is non-zero");
168   buffer.Copy(this);
169 }
170 
DynamicByteBuffer(const DynamicByteBuffer & buffer)171 DynamicByteBuffer::DynamicByteBuffer(const DynamicByteBuffer& buffer)
172     : DynamicByteBuffer(static_cast<const ByteBuffer&>(buffer)) {}
173 
DynamicByteBuffer(const std::string & buffer)174 DynamicByteBuffer::DynamicByteBuffer(const std::string& buffer) {
175   buffer_size_ = buffer.length();
176   buffer_ = std::make_unique<uint8_t[]>(buffer_size_);
177   memcpy(buffer_.get(), buffer.data(), buffer_size_);
178 }
179 
DynamicByteBuffer(size_t buffer_size,std::unique_ptr<uint8_t[]> buffer)180 DynamicByteBuffer::DynamicByteBuffer(size_t buffer_size,
181                                      std::unique_ptr<uint8_t[]> buffer)
182     : buffer_size_(buffer_size), buffer_(std::move(buffer)) {
183   BT_ASSERT_MSG(!buffer_size_ || buffer_.get(),
184                 "|buffer| cannot be nullptr when |buffer_size| is non-zero");
185 }
186 
DynamicByteBuffer(DynamicByteBuffer && other)187 DynamicByteBuffer::DynamicByteBuffer(DynamicByteBuffer&& other) {
188   buffer_size_ = other.buffer_size_;
189   other.buffer_size_ = 0u;
190   buffer_ = std::move(other.buffer_);
191 }
192 
operator =(DynamicByteBuffer && other)193 DynamicByteBuffer& DynamicByteBuffer::operator=(DynamicByteBuffer&& other) {
194   buffer_size_ = other.buffer_size_;
195   other.buffer_size_ = 0u;
196   buffer_ = std::move(other.buffer_);
197   return *this;
198 }
199 
data() const200 const uint8_t* DynamicByteBuffer::data() const { return buffer_.get(); }
201 
mutable_data()202 uint8_t* DynamicByteBuffer::mutable_data() { return buffer_.get(); }
203 
size() const204 size_t DynamicByteBuffer::size() const { return buffer_size_; }
205 
Fill(uint8_t value)206 void DynamicByteBuffer::Fill(uint8_t value) {
207   memset(buffer_.get(), value, buffer_size_);
208 }
209 
cbegin() const210 ByteBuffer::const_iterator DynamicByteBuffer::cbegin() const {
211   return buffer_.get();
212 }
213 
cend() const214 ByteBuffer::const_iterator DynamicByteBuffer::cend() const {
215   return buffer_.get() + buffer_size_;
216 }
217 
BufferView(const ByteBuffer & buffer,size_t size)218 BufferView::BufferView(const ByteBuffer& buffer, size_t size) {
219   *this = buffer.view(0u, size);
220 }
221 
BufferView(std::string_view string)222 BufferView::BufferView(std::string_view string) {
223   size_ = string.size();
224   bytes_ = reinterpret_cast<const uint8_t*>(string.data());
225 }
226 
BufferView(const std::vector<uint8_t> & vec)227 BufferView::BufferView(const std::vector<uint8_t>& vec)
228     : BufferView(vec.data(), vec.size()) {}
229 
BufferView(pw::span<const std::byte> bytes)230 BufferView::BufferView(pw::span<const std::byte> bytes)
231     : BufferView(bytes.data(), bytes.size()) {}
232 
BufferView(const void * bytes,size_t size)233 BufferView::BufferView(const void* bytes, size_t size)
234     : size_(size), bytes_(static_cast<const uint8_t*>(bytes)) {
235   // If |size| non-zero then |bytes| cannot be nullptr.
236   BT_ASSERT_MSG(!size_ || bytes_, "|bytes_| cannot be nullptr if |size_| > 0");
237 }
238 
239 BufferView::BufferView() = default;
240 
data() const241 const uint8_t* BufferView::data() const { return bytes_; }
242 
size() const243 size_t BufferView::size() const { return size_; }
244 
cbegin() const245 ByteBuffer::const_iterator BufferView::cbegin() const { return bytes_; }
246 
cend() const247 ByteBuffer::const_iterator BufferView::cend() const { return bytes_ + size_; }
248 
MutableBufferView(MutableByteBuffer * buffer)249 MutableBufferView::MutableBufferView(MutableByteBuffer* buffer) {
250   BT_ASSERT(buffer);
251   size_ = buffer->size();
252   bytes_ = buffer->mutable_data();
253 }
254 
MutableBufferView(void * bytes,size_t size)255 MutableBufferView::MutableBufferView(void* bytes, size_t size)
256     : size_(size), bytes_(static_cast<uint8_t*>(bytes)) {
257   // If |size| non-zero then |bytes| cannot be nullptr.
258   BT_ASSERT_MSG(!size_ || bytes_, "|bytes_| cannot be nullptr if |size_| > 0");
259 }
260 
261 MutableBufferView::MutableBufferView() = default;
262 
data() const263 const uint8_t* MutableBufferView::data() const { return bytes_; }
264 
size() const265 size_t MutableBufferView::size() const { return size_; }
266 
cbegin() const267 ByteBuffer::const_iterator MutableBufferView::cbegin() const { return bytes_; }
268 
cend() const269 ByteBuffer::const_iterator MutableBufferView::cend() const {
270   return bytes_ + size_;
271 }
272 
mutable_data()273 uint8_t* MutableBufferView::mutable_data() { return bytes_; }
274 
Fill(uint8_t value)275 void MutableBufferView::Fill(uint8_t value) { memset(bytes_, value, size_); }
276 
277 }  // namespace bt
278