• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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