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