/proc/self/cwd/pw_bluetooth_sapphire/host/sdp/data_element.cc
Line | Count | Source (jump to first uncovered line) |
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/sdp/data_element.h" |
16 | | |
17 | | #include <cpp-string/string_printf.h> |
18 | | #include <pw_assert/check.h> |
19 | | #include <pw_bytes/endian.h> |
20 | | |
21 | | #include <algorithm> |
22 | | #include <cinttypes> |
23 | | #include <set> |
24 | | #include <vector> |
25 | | |
26 | | #include "pw_bluetooth_sapphire/internal/host/common/log.h" |
27 | | |
28 | | // Returns true if |url| is a valid URI. |
29 | 41.4k | bool IsValidUrl(const std::string& url) { |
30 | | // Pulled from [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986). |
31 | | // See Section 2.2 for the set of reserved characters. |
32 | | // See Section 2.3 for the set of unreserved characters. |
33 | 41.4k | constexpr char kValidUrlChars[] = |
34 | 41.4k | "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~!#$&'(" |
35 | 41.4k | ")*+,/:;=?@[]"; |
36 | 41.4k | return url.find_first_not_of(kValidUrlChars) == std::string::npos; |
37 | 41.4k | } |
38 | | |
39 | | namespace bt::sdp { |
40 | | |
41 | | namespace { |
42 | | |
43 | | // Size Descriptor occupies the lowest 3 bits of the header byte. |
44 | | // v5.0, Vol 3, Part B, Sec 3.3. |
45 | | constexpr uint8_t kDataElementSizeTypeMask = 0x07; |
46 | | |
47 | 85.1k | DataElement::Size SizeToSizeType(size_t size) { |
48 | 85.1k | switch (size) { |
49 | 14.9k | case 1: |
50 | 14.9k | return DataElement::Size::kOneByte; |
51 | 46.1k | case 2: |
52 | 46.1k | return DataElement::Size::kTwoBytes; |
53 | 9.75k | case 4: |
54 | 9.75k | return DataElement::Size::kFourBytes; |
55 | 4.39k | case 8: |
56 | 4.39k | return DataElement::Size::kEightBytes; |
57 | 9.87k | case 16: |
58 | 9.87k | return DataElement::Size::kSixteenBytes; |
59 | 0 | default: |
60 | 0 | PW_CRASH("invalid data element size: %zu", size); |
61 | 85.1k | } |
62 | 0 | return DataElement::Size::kNextFour; |
63 | 85.1k | } |
64 | | |
65 | 87.4k | size_t AggregateSize(const std::vector<DataElement>& aggregate) { |
66 | 87.4k | size_t total_size = 0; |
67 | 3.97M | for (const auto& elem : aggregate) { |
68 | 3.97M | total_size += elem.WriteSize(); |
69 | 3.97M | } |
70 | 87.4k | return total_size; |
71 | 87.4k | } |
72 | | |
73 | 0 | size_t WriteLength(MutableByteBuffer* buf, size_t length) { |
74 | 0 | if (length <= std::numeric_limits<uint8_t>::max()) { |
75 | 0 | uint8_t val = static_cast<uint8_t>(length); |
76 | 0 | buf->Write(&val, sizeof(val)); |
77 | 0 | return sizeof(uint8_t); |
78 | 0 | } |
79 | | |
80 | 0 | if (length <= std::numeric_limits<uint16_t>::max()) { |
81 | 0 | buf->WriteObj(pw::bytes::ConvertOrderTo(cpp20::endian::big, |
82 | 0 | static_cast<uint16_t>(length))); |
83 | 0 | return sizeof(uint16_t); |
84 | 0 | } |
85 | | |
86 | 0 | if (length <= std::numeric_limits<uint32_t>::max()) { |
87 | 0 | buf->WriteObj(pw::bytes::ConvertOrderTo(cpp20::endian::big, |
88 | 0 | static_cast<uint32_t>(length))); |
89 | 0 | return sizeof(uint32_t); |
90 | 0 | } |
91 | | |
92 | 0 | return 0; |
93 | 0 | } |
94 | | |
95 | | } // namespace |
96 | | |
97 | 3.74M | DataElement::DataElement() : type_(Type::kNull), size_(Size::kOneByte) {} |
98 | | |
99 | | DataElement::DataElement(const DataElement& other) |
100 | 15.0k | : type_(other.type_), size_(other.size_) { |
101 | 15.0k | switch (type_) { |
102 | 7.85k | case Type::kNull: |
103 | 7.85k | return; |
104 | 1.09k | case Type::kUnsignedInt: |
105 | 1.09k | uint_value_ = other.uint_value_; |
106 | 1.09k | return; |
107 | 460 | case Type::kBoolean: |
108 | 869 | case Type::kSignedInt: |
109 | 869 | int_value_ = other.int_value_; |
110 | 869 | return; |
111 | 714 | case Type::kUuid: |
112 | 714 | uuid_ = other.uuid_; |
113 | 714 | return; |
114 | 1.51k | case Type::kString: |
115 | 2.16k | case Type::kUrl: |
116 | 2.16k | bytes_ = DynamicByteBuffer(other.bytes_); |
117 | 2.16k | return; |
118 | 957 | case Type::kSequence: |
119 | 2.32k | case Type::kAlternative: |
120 | 12.1k | for (const auto& it : other.aggregate_) { |
121 | 12.1k | aggregate_.emplace_back(DataElement(it)); |
122 | 12.1k | } |
123 | 2.32k | return; |
124 | 15.0k | } |
125 | 15.0k | } |
126 | | |
127 | | template <> |
128 | 10.2k | void DataElement::Set<uint8_t>(uint8_t value) { |
129 | 10.2k | type_ = Type::kUnsignedInt; |
130 | 10.2k | size_ = SizeToSizeType(sizeof(uint8_t)); |
131 | 10.2k | uint_value_ = value; |
132 | 10.2k | } |
133 | | |
134 | | template <> |
135 | 8.03k | void DataElement::Set<uint16_t>(uint16_t value) { |
136 | 8.03k | type_ = Type::kUnsignedInt; |
137 | 8.03k | size_ = SizeToSizeType(sizeof(uint16_t)); |
138 | 8.03k | uint_value_ = value; |
139 | 8.03k | } |
140 | | |
141 | | template <> |
142 | 1.46k | void DataElement::Set<uint32_t>(uint32_t value) { |
143 | 1.46k | type_ = Type::kUnsignedInt; |
144 | 1.46k | size_ = SizeToSizeType(sizeof(uint32_t)); |
145 | 1.46k | uint_value_ = value; |
146 | 1.46k | } |
147 | | |
148 | | template <> |
149 | 1.62k | void DataElement::Set<uint64_t>(uint64_t value) { |
150 | 1.62k | type_ = Type::kUnsignedInt; |
151 | 1.62k | size_ = SizeToSizeType(sizeof(uint64_t)); |
152 | 1.62k | uint_value_ = value; |
153 | 1.62k | } |
154 | | |
155 | | template <> |
156 | 4.68k | void DataElement::Set<int8_t>(int8_t value) { |
157 | 4.68k | type_ = Type::kSignedInt; |
158 | 4.68k | size_ = SizeToSizeType(sizeof(int8_t)); |
159 | 4.68k | int_value_ = value; |
160 | 4.68k | } |
161 | | |
162 | | template <> |
163 | 2.17k | void DataElement::Set<int16_t>(int16_t value) { |
164 | 2.17k | type_ = Type::kSignedInt; |
165 | 2.17k | size_ = SizeToSizeType(sizeof(int16_t)); |
166 | 2.17k | int_value_ = value; |
167 | 2.17k | } |
168 | | |
169 | | template <> |
170 | 2.93k | void DataElement::Set<int32_t>(int32_t value) { |
171 | 2.93k | type_ = Type::kSignedInt; |
172 | 2.93k | size_ = SizeToSizeType(sizeof(int32_t)); |
173 | 2.93k | int_value_ = value; |
174 | 2.93k | } |
175 | | |
176 | | template <> |
177 | 2.76k | void DataElement::Set<int64_t>(int64_t value) { |
178 | 2.76k | type_ = Type::kSignedInt; |
179 | 2.76k | size_ = SizeToSizeType(sizeof(int64_t)); |
180 | 2.76k | int_value_ = value; |
181 | 2.76k | } |
182 | | |
183 | | template <> |
184 | 11.2k | void DataElement::Set<bool>(bool value) { |
185 | 11.2k | type_ = Type::kBoolean; |
186 | 11.2k | size_ = Size::kOneByte; |
187 | 11.2k | int_value_ = (value ? 1 : 0); |
188 | 11.2k | } |
189 | | |
190 | | template <> |
191 | 3.50M | void DataElement::Set<std::nullptr_t>(std::nullptr_t) { |
192 | 3.50M | type_ = Type::kNull; |
193 | 3.50M | size_ = Size::kOneByte; |
194 | 3.50M | } |
195 | | |
196 | | template <> |
197 | 48.3k | void DataElement::Set<UUID>(UUID value) { |
198 | 48.3k | type_ = Type::kUuid; |
199 | 48.3k | size_ = SizeToSizeType(value.CompactSize()); |
200 | 48.3k | uuid_ = value; |
201 | 48.3k | } |
202 | | |
203 | 68.3k | void DataElement::Set(const bt::DynamicByteBuffer& value) { |
204 | 68.3k | type_ = Type::kString; |
205 | 68.3k | SetVariableSize(value.size()); |
206 | 68.3k | bytes_ = DynamicByteBuffer(value); |
207 | 68.3k | } |
208 | | |
209 | 0 | void DataElement::Set(const std::string& value) { |
210 | 0 | type_ = Type::kString; |
211 | 0 | SetVariableSize(value.size()); |
212 | 0 | bytes_ = DynamicByteBuffer(value); |
213 | 0 | } |
214 | | |
215 | 25.4k | void DataElement::Set(std::vector<DataElement>&& value) { |
216 | 25.4k | type_ = Type::kSequence; |
217 | 25.4k | aggregate_ = std::move(value); |
218 | 25.4k | SetVariableSize(AggregateSize(aggregate_)); |
219 | 25.4k | } |
220 | | |
221 | 41.4k | void DataElement::SetUrl(const std::string& url) { |
222 | 41.4k | if (!IsValidUrl(url)) { |
223 | 12.0k | bt_log(WARN, "sdp", "Invalid URL in SetUrl: %s", url.c_str()); |
224 | 12.0k | return; |
225 | 12.0k | } |
226 | | |
227 | 29.4k | type_ = Type::kUrl; |
228 | 29.4k | SetVariableSize(url.size()); |
229 | 29.4k | bytes_ = DynamicByteBuffer(url); |
230 | 29.4k | } |
231 | | |
232 | 9.00k | void DataElement::SetAlternative(std::vector<DataElement>&& items) { |
233 | 9.00k | type_ = Type::kAlternative; |
234 | 9.00k | aggregate_ = std::move(items); |
235 | 9.00k | SetVariableSize(AggregateSize(aggregate_)); |
236 | 9.00k | } |
237 | | |
238 | | template <> |
239 | 0 | std::optional<uint8_t> DataElement::Get<uint8_t>() const { |
240 | 0 | if (type_ == Type::kUnsignedInt && size_ == SizeToSizeType(sizeof(uint8_t))) { |
241 | 0 | return static_cast<uint8_t>(uint_value_); |
242 | 0 | } |
243 | | |
244 | 0 | return std::nullopt; |
245 | 0 | } |
246 | | |
247 | | template <> |
248 | 3.14k | std::optional<uint16_t> DataElement::Get<uint16_t>() const { |
249 | 3.14k | if (type_ == Type::kUnsignedInt && |
250 | 3.14k | size_ == SizeToSizeType(sizeof(uint16_t))) { |
251 | 2.88k | return static_cast<uint16_t>(uint_value_); |
252 | 2.88k | } |
253 | | |
254 | 256 | return std::nullopt; |
255 | 3.14k | } |
256 | | |
257 | | template <> |
258 | 0 | std::optional<uint32_t> DataElement::Get<uint32_t>() const { |
259 | 0 | if (type_ == Type::kUnsignedInt && |
260 | 0 | size_ == SizeToSizeType(sizeof(uint32_t))) { |
261 | 0 | return static_cast<uint32_t>(uint_value_); |
262 | 0 | } |
263 | | |
264 | 0 | return std::nullopt; |
265 | 0 | } |
266 | | |
267 | | template <> |
268 | 0 | std::optional<uint64_t> DataElement::Get<uint64_t>() const { |
269 | 0 | if (type_ == Type::kUnsignedInt && |
270 | 0 | size_ == SizeToSizeType(sizeof(uint64_t))) { |
271 | 0 | return uint_value_; |
272 | 0 | } |
273 | | |
274 | 0 | return std::nullopt; |
275 | 0 | } |
276 | | |
277 | | template <> |
278 | 0 | std::optional<int8_t> DataElement::Get<int8_t>() const { |
279 | 0 | if (type_ == Type::kSignedInt && size_ == SizeToSizeType(sizeof(int8_t))) { |
280 | 0 | return static_cast<int8_t>(int_value_); |
281 | 0 | } |
282 | | |
283 | 0 | return std::nullopt; |
284 | 0 | } |
285 | | |
286 | | template <> |
287 | 0 | std::optional<int16_t> DataElement::Get<int16_t>() const { |
288 | 0 | if (type_ == Type::kSignedInt && size_ == SizeToSizeType(sizeof(int16_t))) { |
289 | 0 | return static_cast<int16_t>(int_value_); |
290 | 0 | } |
291 | | |
292 | 0 | return std::nullopt; |
293 | 0 | } |
294 | | |
295 | | template <> |
296 | 0 | std::optional<int32_t> DataElement::Get<int32_t>() const { |
297 | 0 | if (type_ == Type::kSignedInt && size_ == SizeToSizeType(sizeof(int32_t))) { |
298 | 0 | return static_cast<int32_t>(int_value_); |
299 | 0 | } |
300 | | |
301 | 0 | return std::nullopt; |
302 | 0 | ; |
303 | 0 | } |
304 | | |
305 | | template <> |
306 | 0 | std::optional<int64_t> DataElement::Get<int64_t>() const { |
307 | 0 | if (type_ == Type::kSignedInt && size_ == SizeToSizeType(sizeof(int64_t))) { |
308 | 0 | return static_cast<int64_t>(int_value_); |
309 | 0 | } |
310 | | |
311 | 0 | return std::nullopt; |
312 | 0 | } |
313 | | |
314 | | template <> |
315 | 0 | std::optional<bool> DataElement::Get<bool>() const { |
316 | 0 | if (type_ != Type::kBoolean) { |
317 | 0 | return std::nullopt; |
318 | 0 | } |
319 | | |
320 | 0 | return (int_value_ == 1); |
321 | 0 | } |
322 | | |
323 | | template <> |
324 | 0 | std::optional<std::nullptr_t> DataElement::Get<std::nullptr_t>() const { |
325 | 0 | if (type_ != Type::kNull) { |
326 | 0 | return std::nullopt; |
327 | 0 | } |
328 | | |
329 | 0 | return nullptr; |
330 | 0 | } |
331 | | |
332 | | template <> |
333 | | std::optional<bt::DynamicByteBuffer> DataElement::Get<bt::DynamicByteBuffer>() |
334 | 0 | const { |
335 | 0 | if (type_ != Type::kString) { |
336 | 0 | return std::nullopt; |
337 | 0 | } |
338 | | |
339 | 0 | return DynamicByteBuffer(bytes_); |
340 | 0 | } |
341 | | |
342 | | template <> |
343 | 0 | std::optional<std::string> DataElement::Get<std::string>() const { |
344 | 0 | if (type_ != Type::kString) { |
345 | 0 | return std::nullopt; |
346 | 0 | } |
347 | | |
348 | 0 | return std::string(reinterpret_cast<const char*>(bytes_.data()), |
349 | 0 | bytes_.size()); |
350 | 0 | } |
351 | | |
352 | | template <> |
353 | 0 | std::optional<UUID> DataElement::Get<UUID>() const { |
354 | 0 | if (type_ != Type::kUuid) { |
355 | 0 | return std::nullopt; |
356 | 0 | } |
357 | | |
358 | 0 | return uuid_; |
359 | 0 | } |
360 | | |
361 | | template <> |
362 | | std::optional<std::vector<DataElement>> |
363 | 0 | DataElement::Get<std::vector<DataElement>>() const { |
364 | 0 | if ((type_ != Type::kSequence) && (type_ != Type::kAlternative)) { |
365 | 0 | return std::nullopt; |
366 | 0 | } |
367 | | |
368 | 0 | std::vector<DataElement> aggregate_copy; |
369 | 0 | for (const auto& it : aggregate_) { |
370 | 0 | aggregate_copy.emplace_back(it.Clone()); |
371 | 0 | } |
372 | |
|
373 | 0 | return aggregate_copy; |
374 | 0 | } |
375 | | |
376 | 0 | std::optional<std::string> DataElement::GetUrl() const { |
377 | 0 | if (type_ != Type::kUrl) { |
378 | 0 | return std::nullopt; |
379 | 0 | } |
380 | | |
381 | 0 | return std::string(reinterpret_cast<const char*>(bytes_.data()), |
382 | 0 | bytes_.size()); |
383 | 0 | } |
384 | | |
385 | 132k | void DataElement::SetVariableSize(size_t length) { |
386 | 132k | if (length <= std::numeric_limits<uint8_t>::max()) { |
387 | 128k | size_ = Size::kNextOne; |
388 | 128k | } else if (length <= std::numeric_limits<uint16_t>::max()) { |
389 | 3.97k | size_ = Size::kNextTwo; |
390 | 3.97k | } else { |
391 | 24 | size_ = Size::kNextFour; |
392 | 24 | } |
393 | 132k | } |
394 | | |
395 | 3.74M | size_t DataElement::Read(DataElement* elem, const ByteBuffer& buffer) { |
396 | 3.74M | if (buffer.size() == 0) { |
397 | 7 | return 0; |
398 | 7 | } |
399 | 3.74M | Type type_desc = static_cast<Type>(buffer[0] & kTypeMask); |
400 | 3.74M | Size size_desc = static_cast<Size>(buffer[0] & kDataElementSizeTypeMask); |
401 | 3.74M | size_t data_bytes = 0; |
402 | 3.74M | size_t bytes_read = 1; |
403 | 3.74M | BufferView cursor = buffer.view(bytes_read); |
404 | 3.74M | switch (size_desc) { |
405 | 3.53M | case DataElement::Size::kOneByte: |
406 | 3.57M | case DataElement::Size::kTwoBytes: |
407 | 3.58M | case DataElement::Size::kFourBytes: |
408 | 3.58M | case DataElement::Size::kEightBytes: |
409 | 3.60M | case DataElement::Size::kSixteenBytes: |
410 | 3.60M | if (type_desc != Type::kNull) { |
411 | 93.7k | data_bytes = (1 << static_cast<uint8_t>(size_desc)); |
412 | 3.50M | } else { |
413 | 3.50M | data_bytes = 0; |
414 | 3.50M | } |
415 | 3.60M | break; |
416 | 127k | case DataElement::Size::kNextOne: { |
417 | 127k | if (cursor.size() < sizeof(uint8_t)) { |
418 | 20 | return 0; |
419 | 20 | } |
420 | 127k | data_bytes = cursor.To<uint8_t>(); |
421 | 127k | bytes_read += sizeof(uint8_t); |
422 | 127k | break; |
423 | 127k | } |
424 | 14.0k | case DataElement::Size::kNextTwo: { |
425 | 14.0k | if (cursor.size() < sizeof(uint16_t)) { |
426 | 18 | return 0; |
427 | 18 | } |
428 | 14.0k | data_bytes = pw::bytes::ConvertOrderFrom(cpp20::endian::big, |
429 | 14.0k | cursor.To<uint16_t>()); |
430 | 14.0k | bytes_read += sizeof(uint16_t); |
431 | 14.0k | break; |
432 | 14.0k | } |
433 | 4.28k | case DataElement::Size::kNextFour: { |
434 | 4.28k | if (cursor.size() < sizeof(uint32_t)) { |
435 | 24 | return 0; |
436 | 24 | } |
437 | 4.26k | data_bytes = pw::bytes::ConvertOrderFrom(cpp20::endian::big, |
438 | 4.26k | cursor.To<uint32_t>()); |
439 | 4.26k | bytes_read += sizeof(uint32_t); |
440 | 4.26k | break; |
441 | 4.28k | } |
442 | 3.74M | } |
443 | 3.74M | cursor = buffer.view(bytes_read); |
444 | 3.74M | if (cursor.size() < data_bytes) { |
445 | 374 | return 0; |
446 | 374 | } |
447 | | |
448 | 3.74M | switch (type_desc) { |
449 | 3.50M | case Type::kNull: { |
450 | 3.50M | if (size_desc != Size::kOneByte) { |
451 | 57 | return 0; |
452 | 57 | } |
453 | 3.50M | elem->Set(nullptr); |
454 | 3.50M | return bytes_read + data_bytes; |
455 | 3.50M | } |
456 | 11.2k | case Type::kBoolean: { |
457 | 11.2k | if (size_desc != Size::kOneByte) { |
458 | 11 | return 0; |
459 | 11 | } |
460 | 11.2k | elem->Set(cursor.To<uint8_t>() != 0); |
461 | 11.2k | return bytes_read + data_bytes; |
462 | 11.2k | } |
463 | 21.4k | case Type::kUnsignedInt: { |
464 | 21.4k | if (size_desc == Size::kOneByte) { |
465 | 10.2k | elem->Set(cursor.To<uint8_t>()); |
466 | 11.1k | } else if (size_desc == Size::kTwoBytes) { |
467 | 8.03k | elem->Set(pw::bytes::ConvertOrderFrom(cpp20::endian::big, |
468 | 8.03k | cursor.To<uint16_t>())); |
469 | 8.03k | } else if (size_desc == Size::kFourBytes) { |
470 | 1.46k | elem->Set(pw::bytes::ConvertOrderFrom(cpp20::endian::big, |
471 | 1.46k | cursor.To<uint32_t>())); |
472 | 1.63k | } else if (size_desc == Size::kEightBytes) { |
473 | 1.62k | elem->Set(pw::bytes::ConvertOrderFrom(cpp20::endian::big, |
474 | 1.62k | cursor.To<uint64_t>())); |
475 | 1.62k | } else { |
476 | | // TODO(fxbug.dev/42078670): support 128-bit uints |
477 | | // Invalid size. |
478 | 10 | return 0; |
479 | 10 | } |
480 | 21.3k | return bytes_read + data_bytes; |
481 | 21.4k | } |
482 | 12.5k | case Type::kSignedInt: { |
483 | 12.5k | if (size_desc == Size::kOneByte) { |
484 | 4.68k | elem->Set(cursor.To<int8_t>()); |
485 | 7.88k | } else if (size_desc == Size::kTwoBytes) { |
486 | 2.17k | elem->Set(pw::bytes::ConvertOrderFrom(cpp20::endian::big, |
487 | 2.17k | cursor.To<int16_t>())); |
488 | 5.70k | } else if (size_desc == Size::kFourBytes) { |
489 | 2.93k | elem->Set(pw::bytes::ConvertOrderFrom(cpp20::endian::big, |
490 | 2.93k | cursor.To<int32_t>())); |
491 | 2.93k | } else if (size_desc == Size::kEightBytes) { |
492 | 2.76k | elem->Set(pw::bytes::ConvertOrderFrom(cpp20::endian::big, |
493 | 2.76k | cursor.To<int64_t>())); |
494 | 2.76k | } else { |
495 | | // TODO(fxbug.dev/42078670): support 128-bit uints |
496 | | // Invalid size. |
497 | 9 | return 0; |
498 | 9 | } |
499 | 12.5k | return bytes_read + data_bytes; |
500 | 12.5k | } |
501 | 48.3k | case Type::kUuid: { |
502 | 48.3k | if (size_desc == Size::kTwoBytes) { |
503 | 29.0k | elem->Set(UUID(pw::bytes::ConvertOrderFrom(cpp20::endian::big, |
504 | 29.0k | cursor.To<uint16_t>()))); |
505 | 29.0k | } else if (size_desc == Size::kFourBytes) { |
506 | 3.39k | elem->Set(UUID(pw::bytes::ConvertOrderFrom(cpp20::endian::big, |
507 | 3.39k | cursor.To<uint32_t>()))); |
508 | 15.8k | } else if (size_desc == Size::kSixteenBytes) { |
509 | 15.8k | StaticByteBuffer<16> uuid_bytes; |
510 | | // UUID expects these to be in little-endian order. |
511 | 15.8k | cursor.Copy(&uuid_bytes, 0, 16); |
512 | 15.8k | std::reverse(uuid_bytes.mutable_data(), uuid_bytes.mutable_data() + 16); |
513 | 15.8k | UUID uuid(uuid_bytes); |
514 | 15.8k | elem->Set(uuid); |
515 | 15.8k | } else { |
516 | 12 | return 0; |
517 | 12 | } |
518 | 48.3k | return bytes_read + data_bytes; |
519 | 48.3k | } |
520 | 68.3k | case Type::kString: { |
521 | 68.3k | if (static_cast<uint8_t>(size_desc) < 5) { |
522 | 15 | return 0; |
523 | 15 | } |
524 | 68.3k | bt::DynamicByteBuffer str(data_bytes); |
525 | 68.3k | str.Write(cursor.data(), data_bytes); |
526 | 68.3k | elem->Set(str); |
527 | 68.3k | return bytes_read + data_bytes; |
528 | 68.3k | } |
529 | 25.9k | case Type::kSequence: |
530 | 35.4k | case Type::kAlternative: { |
531 | 35.4k | if (static_cast<uint8_t>(size_desc) < 5) { |
532 | 18 | return 0; |
533 | 18 | } |
534 | 35.4k | BufferView sequence_buf = cursor.view(0, data_bytes); |
535 | 35.4k | size_t remaining = data_bytes; |
536 | 35.4k | PW_DCHECK(sequence_buf.size() == data_bytes); |
537 | | |
538 | 35.4k | std::vector<DataElement> seq; |
539 | 3.77M | while (remaining > 0) { |
540 | 3.74M | DataElement next; |
541 | 3.74M | size_t used = Read(&next, sequence_buf.view(data_bytes - remaining)); |
542 | 3.74M | if (used == 0 || used > remaining) { |
543 | 946 | return 0; |
544 | 946 | } |
545 | 3.74M | seq.push_back(std::move(next)); |
546 | 3.74M | remaining -= used; |
547 | 3.74M | } |
548 | 34.4k | PW_DCHECK(remaining == 0); |
549 | 34.4k | if (type_desc == Type::kAlternative) { |
550 | 9.00k | elem->SetAlternative(std::move(seq)); |
551 | 25.4k | } else { |
552 | 25.4k | elem->Set(std::move(seq)); |
553 | 25.4k | } |
554 | 34.4k | return bytes_read + data_bytes; |
555 | 34.4k | } |
556 | 41.5k | case Type::kUrl: { |
557 | 41.5k | if (static_cast<uint8_t>(size_desc) < 5) { |
558 | 10 | return 0; |
559 | 10 | } |
560 | 41.4k | std::string str(cursor.data(), cursor.data() + data_bytes); |
561 | 41.4k | elem->SetUrl(str); |
562 | 41.4k | return bytes_read + data_bytes; |
563 | 41.5k | } |
564 | 3.74M | } |
565 | 56 | return 0; |
566 | 3.74M | } |
567 | | |
568 | 3.99M | size_t DataElement::WriteSize() const { |
569 | 3.99M | switch (type_) { |
570 | 3.69M | case Type::kNull: |
571 | 3.69M | return 1; |
572 | 13.1k | case Type::kBoolean: |
573 | 13.1k | return 2; |
574 | 42.2k | case Type::kUnsignedInt: |
575 | 68.7k | case Type::kSignedInt: |
576 | 122k | case Type::kUuid: |
577 | 122k | return 1 + (1 << static_cast<uint8_t>(size_)); |
578 | 69.5k | case Type::kString: |
579 | 111k | case Type::kUrl: |
580 | 111k | return 1 + (1 << (static_cast<uint8_t>(size_) - 5)) + bytes_.size(); |
581 | 33.6k | case Type::kSequence: |
582 | 53.0k | case Type::kAlternative: |
583 | 53.0k | return 1 + (1 << (static_cast<uint8_t>(size_) - 5)) + |
584 | 53.0k | AggregateSize(aggregate_); |
585 | 3.99M | } |
586 | 3.99M | } |
587 | | |
588 | 0 | size_t DataElement::Write(MutableByteBuffer* buffer) const { |
589 | 0 | if (buffer->size() < WriteSize()) { |
590 | 0 | bt_log(TRACE, |
591 | 0 | "sdp", |
592 | 0 | "not enough space in buffer (%zu < %zu)", |
593 | 0 | buffer->size(), |
594 | 0 | WriteSize()); |
595 | 0 | return 0; |
596 | 0 | } |
597 | | |
598 | 0 | uint8_t type_and_size = |
599 | 0 | static_cast<uint8_t>(type_) | static_cast<uint8_t>(size_); |
600 | 0 | buffer->Write(&type_and_size, 1); |
601 | 0 | size_t pos = 1; |
602 | |
|
603 | 0 | MutableBufferView cursor = buffer->mutable_view(pos); |
604 | |
|
605 | 0 | switch (type_) { |
606 | 0 | case Type::kNull: { |
607 | 0 | return pos; |
608 | 0 | } |
609 | 0 | case Type::kBoolean: { |
610 | 0 | uint8_t val = int_value_ != 0 ? 1 : 0; |
611 | 0 | cursor.Write(&val, sizeof(val)); |
612 | 0 | pos += 1; |
613 | 0 | return pos; |
614 | 0 | } |
615 | 0 | case Type::kUnsignedInt: { |
616 | 0 | if (size_ == Size::kOneByte) { |
617 | 0 | uint8_t val = static_cast<uint8_t>(uint_value_); |
618 | 0 | cursor.Write(reinterpret_cast<uint8_t*>(&val), sizeof(val)); |
619 | 0 | pos += sizeof(val); |
620 | 0 | } else if (size_ == Size::kTwoBytes) { |
621 | 0 | cursor.WriteObj(pw::bytes::ConvertOrderTo( |
622 | 0 | cpp20::endian::big, static_cast<uint16_t>(uint_value_))); |
623 | 0 | pos += sizeof(uint16_t); |
624 | 0 | } else if (size_ == Size::kFourBytes) { |
625 | 0 | cursor.WriteObj(pw::bytes::ConvertOrderTo( |
626 | 0 | cpp20::endian::big, static_cast<uint32_t>(uint_value_))); |
627 | 0 | pos += sizeof(uint32_t); |
628 | 0 | } else if (size_ == Size::kEightBytes) { |
629 | 0 | uint64_t val = |
630 | 0 | pw::bytes::ConvertOrderTo(cpp20::endian::big, uint_value_); |
631 | 0 | cursor.Write(reinterpret_cast<uint8_t*>(&val), sizeof(val)); |
632 | 0 | pos += sizeof(val); |
633 | 0 | } |
634 | 0 | return pos; |
635 | 0 | } |
636 | 0 | case Type::kSignedInt: { |
637 | 0 | if (size_ == Size::kOneByte) { |
638 | 0 | int8_t val = static_cast<int8_t>(int_value_); |
639 | 0 | cursor.Write(reinterpret_cast<uint8_t*>(&val), sizeof(val)); |
640 | 0 | pos += sizeof(val); |
641 | 0 | } else if (size_ == Size::kTwoBytes) { |
642 | 0 | cursor.WriteObj(pw::bytes::ConvertOrderTo( |
643 | 0 | cpp20::endian::big, static_cast<int16_t>(int_value_))); |
644 | 0 | pos += sizeof(uint16_t); |
645 | 0 | } else if (size_ == Size::kFourBytes) { |
646 | 0 | cursor.WriteObj(pw::bytes::ConvertOrderTo( |
647 | 0 | cpp20::endian::big, static_cast<int32_t>(int_value_))); |
648 | 0 | pos += sizeof(uint32_t); |
649 | 0 | } else if (size_ == Size::kEightBytes) { |
650 | 0 | int64_t val = pw::bytes::ConvertOrderTo( |
651 | 0 | cpp20::endian::big, static_cast<int64_t>(int_value_)); |
652 | 0 | cursor.Write(reinterpret_cast<uint8_t*>(&val), sizeof(val)); |
653 | 0 | pos += sizeof(val); |
654 | 0 | } |
655 | 0 | return pos; |
656 | 0 | } |
657 | 0 | case Type::kUuid: { |
658 | 0 | size_t written = uuid_.ToBytes(&cursor); |
659 | 0 | PW_DCHECK(written); |
660 | | // SDP is big-endian, so reverse. |
661 | 0 | std::reverse(cursor.mutable_data(), cursor.mutable_data() + written); |
662 | 0 | pos += written; |
663 | 0 | return pos; |
664 | 0 | } |
665 | 0 | case Type::kString: |
666 | 0 | case Type::kUrl: { |
667 | 0 | size_t used = WriteLength(&cursor, bytes_.size()); |
668 | 0 | PW_DCHECK(used); |
669 | 0 | pos += used; |
670 | 0 | cursor.Write(bytes_.data(), bytes_.size(), used); |
671 | 0 | pos += bytes_.size(); |
672 | 0 | return pos; |
673 | 0 | } |
674 | 0 | case Type::kSequence: |
675 | 0 | case Type::kAlternative: { |
676 | 0 | size_t used = WriteLength(&cursor, AggregateSize(aggregate_)); |
677 | 0 | PW_DCHECK(used); |
678 | 0 | pos += used; |
679 | 0 | cursor = cursor.mutable_view(used); |
680 | 0 | for (const auto& elem : aggregate_) { |
681 | 0 | used = elem.Write(&cursor); |
682 | 0 | PW_DCHECK(used); |
683 | 0 | pos += used; |
684 | 0 | cursor = cursor.mutable_view(used); |
685 | 0 | } |
686 | 0 | return pos; |
687 | 0 | } |
688 | 0 | } |
689 | 0 | return 0; |
690 | 0 | } |
691 | | |
692 | 14.4k | const DataElement* DataElement::At(size_t idx) const { |
693 | 14.4k | if ((type_ != Type::kSequence && type_ != Type::kAlternative) || |
694 | 14.4k | (idx >= aggregate_.size())) { |
695 | 3.92k | return nullptr; |
696 | 3.92k | } |
697 | 10.5k | return &aggregate_[idx]; |
698 | 14.4k | } |
699 | | |
700 | 1.00M | std::string DataElement::ToString() const { |
701 | 1.00M | switch (type_) { |
702 | 857k | case Type::kNull: |
703 | 857k | return std::string("Null"); |
704 | 7.27k | case Type::kBoolean: |
705 | 7.27k | return bt_lib_cpp_string::StringPrintf("Boolean(%s)", |
706 | 7.27k | int_value_ ? "true" : "false"); |
707 | 12.6k | case Type::kUnsignedInt: |
708 | 12.6k | return bt_lib_cpp_string::StringPrintf( |
709 | 12.6k | "UnsignedInt:%zu(%" PRIu64 ")", WriteSize() - 1, uint_value_); |
710 | 5.93k | case Type::kSignedInt: |
711 | 5.93k | return bt_lib_cpp_string::StringPrintf( |
712 | 5.93k | "SignedInt:%zu(%" PRId64 ")", WriteSize() - 1, int_value_); |
713 | 32.7k | case Type::kUuid: |
714 | 32.7k | return bt_lib_cpp_string::StringPrintf("UUID(%s)", |
715 | 32.7k | uuid_.ToString().c_str()); |
716 | 44.5k | case Type::kString: |
717 | 44.5k | return bt_lib_cpp_string::StringPrintf( |
718 | 44.5k | "String(%s)", bytes_.Printable(0, bytes_.size()).c_str()); |
719 | 18.6k | case Type::kUrl: |
720 | 18.6k | return bt_lib_cpp_string::StringPrintf( |
721 | 18.6k | "Url(%s)", bytes_.Printable(0, bytes_.size()).c_str()); |
722 | 18.8k | case Type::kSequence: { |
723 | 18.8k | std::string str; |
724 | 874k | for (const auto& it : aggregate_) { |
725 | 874k | str += it.ToString() + " "; |
726 | 874k | } |
727 | 18.8k | return bt_lib_cpp_string::StringPrintf("Sequence { %s}", str.c_str()); |
728 | 0 | } |
729 | 4.55k | case Type::kAlternative: { |
730 | 4.55k | std::string str; |
731 | 122k | for (const auto& it : aggregate_) { |
732 | 122k | str += it.ToString() + " "; |
733 | 122k | } |
734 | 4.55k | return bt_lib_cpp_string::StringPrintf("Alternatives { %s}", str.c_str()); |
735 | 0 | } |
736 | 0 | default: |
737 | 0 | bt_log(TRACE, |
738 | 1.00M | "sdp", |
739 | 1.00M | "unhandled type (%hhu) in ToString()", |
740 | 1.00M | static_cast<unsigned char>(type_)); |
741 | | // Fallthrough to unknown. |
742 | 1.00M | } |
743 | | |
744 | 0 | return "(unknown)"; |
745 | 1.00M | } |
746 | | } // namespace bt::sdp |