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 #pragma once 16 #include <vector> 17 18 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h" 19 #include "pw_bluetooth_sapphire/internal/host/common/uuid.h" 20 21 namespace bt::sdp { 22 23 // See Bluetooth Core Spec v5.0, Vol 3, Part B, Sec 3.1. 24 // 25 // Each Data element has a header and a data field. The header field contains a 26 // type descriptor and a size descriptor. The header field is of variable 27 // length, which is determined by the size descriptor. 28 // 29 // DataElements all start as the Null type, and then can be set to any type. 30 // 31 // Examples: 32 // DataElement elem; // A null type 33 // uint32_t seymour = 0xFEED; 34 // elem.Set(seymour); 35 // PW_DCHECK(elem.type() == DataElement::Type::kUnsignedInt); 36 // PW_DCHECK(elem.Get<uint32_t>()); 37 // PW_DCHECK(*elem.Get<uint32_t>() == seymour); 38 // 39 // std::vector<DataElement> service_class_ids; 40 // DataElement uuid; 41 // uuid.Set(UUID(sdp::ServiceClass::kAudioSource)); 42 // service_class_ids.emplace_back(std::move(uuid)); 43 // elem.Set(service_class_ids); 44 // PW_DCHECK(e.type() == DataElement::Type::kSequence); 45 // PW_DCHECK(!e.Get<uint32_t>()); 46 class DataElement { 47 public: 48 // Type Descriptors. Only the top 5 bits are used, see kTypeMask in Bluetooth 49 // Core Spec v5.0, Vol 3, Part B, Sec 3.2. 50 enum class Type : uint8_t { 51 kNull = (0 << 3), 52 kUnsignedInt = (1 << 3), 53 kSignedInt = (2 << 3), 54 kUuid = (3 << 3), 55 kString = (4 << 3), 56 kBoolean = (5 << 3), 57 kSequence = (6 << 3), 58 kAlternative = (7 << 3), 59 kUrl = (8 << 3), 60 }; 61 constexpr static uint8_t kTypeMask = 0xF8; 62 63 // Size Descriptor describing the size of the data following. 64 // 65 // Only three bits are used. For 0-4, the size is 2^(value) except in the case 66 // of kNull, in which case the size is 0. otherwise, the size is described in 67 // 2^(5-value) extra bytes following. 68 // 69 // v45.0, Vol 3, Part B, Sec 3.3 70 enum class Size : uint8_t { 71 kOneByte = 0, 72 kTwoBytes = 1, 73 kFourBytes = 2, 74 kEightBytes = 3, 75 kSixteenBytes = 4, 76 kNextOne = 5, 77 kNextTwo = 6, 78 kNextFour = 7, 79 }; 80 constexpr static uint8_t kSizeMask = 0x07; 81 82 // Constructs a Null data element. 83 DataElement(); 84 ~DataElement() = default; 85 86 // Default move constructor and move-assignment 87 DataElement(DataElement&&) = default; 88 DataElement& operator=(DataElement&&) = default; 89 DataElement(const bt::DynamicByteBuffer & value)90 explicit DataElement(const bt::DynamicByteBuffer& value) { Set(value); } DataElement(const std::string & value)91 explicit DataElement(const std::string& value) { Set(value); } DataElement(std::vector<DataElement> && value)92 explicit DataElement(std::vector<DataElement>&& value) { 93 Set(std::move(value)); 94 } 95 96 // Convenience constructor to create a DataElement from a basic type. 97 template <typename T> DataElement(T value)98 explicit DataElement(T value) { 99 Set<T>(std::move(value)); 100 } 101 102 // Make a deep copy of this element. Clone()103 DataElement Clone() const { return DataElement(*this); } 104 105 // Reads a DataElement from |buffer|, replacing any data that was in |elem|. 106 // Returns the amount of space occupied on |buffer| by the data element, or 107 // zero if no element could be read. 108 static size_t Read(DataElement* elem, const ByteBuffer& buffer); 109 110 // The type of this element. type()111 Type type() const { return type_; } 112 113 // The size of this element. size()114 Size size() const { return size_; } 115 116 // Sets the value of this element to |value|. 117 // 118 // Defined specializations: 119 // typename - type() 120 // std::nullptr_t - kNull 121 // uint8_t, .., uint64_t - kUnsignedInt 122 // int8_t .. int64_t - kSignedInt 123 // const UUID& - kUuid 124 // const bt::DynamicByteBuffer or std::string - kString 125 // bool - kBoolean 126 // std::vector<DataElement> - kSequence 127 // (Use SetUrl()) - kUrl 128 template <typename T> 129 void Set(T value); 130 void Set(const bt::DynamicByteBuffer& value); 131 void Set(const std::string& value); 132 void Set(std::vector<DataElement>&& value); 133 134 // Sets this element's value to an alternative of the items in |items| 135 void SetAlternative(std::vector<DataElement>&& items); 136 137 // Sets this element's value to the provided |url|. No-op if |url| contains 138 // invalid URI characters as defined in [RFC 139 // 3986](https://www.rfc-editor.org/rfc/rfc3986). 140 void SetUrl(const std::string& url); 141 142 // Get the URL value of this element. Returns an optional without a value if 143 // the wrong type is stored. 144 std::optional<std::string> GetUrl() const; 145 146 // Get the value of this element. Has the same defined specializations as 147 // Set(). Returns an optional without a value if the wrong type is stored. 148 template <typename T> 149 std::optional<T> Get() const; 150 151 // Get a pointer to an element in a DataElement Sequence. Returns nullptr if 152 // type() is not kSequence or the index is invalid. Only valid as long as the 153 // containing sequence is valid. 154 const DataElement* At(size_t idx) const; 155 156 // Calculates the number of bytes that this DataElement will use if it's 157 // written using Write(). 158 size_t WriteSize() const; 159 160 // Writes this DataElement to |buffer|. Returns the number of bytes used for 161 // writing this element. 162 size_t Write(MutableByteBuffer* buffer) const; 163 164 // Debug representation of this element (including it's type and size) in a 165 // string, i.e. UnsignedInt:4(15) or Sequence { UUID(1567), UUID(2502) } 166 std::string ToString() const; 167 168 private: 169 // Copy constructor for Clone(), no assignment operator. 170 DataElement(const DataElement&); 171 DataElement& operator=(const DataElement&) = delete; 172 173 // Sets the size type based on a variable size (Next one, two, or four) 174 void SetVariableSize(size_t length); 175 176 Type type_; 177 Size size_; 178 179 // Various types for the stored value. These are only valid if the type_ is 180 // set correctly. 181 int64_t int_value_; 182 uint64_t uint_value_; 183 UUID uuid_; 184 bt::DynamicByteBuffer bytes_; 185 std::vector<DataElement> aggregate_; 186 }; 187 188 } // namespace bt::sdp 189