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