Coverage Report

Created: 2025-03-11 06:23

/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