| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_SDP_DATA_ELEMENT_H_ |
| #define SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_SDP_DATA_ELEMENT_H_ |
| |
| #include <vector> |
| |
| #include "src/connectivity/bluetooth/core/bt-host/common/byte_buffer.h" |
| #include "src/connectivity/bluetooth/core/bt-host/common/uuid.h" |
| |
| namespace bt::sdp { |
| |
| // See v5.0, Vol 3, Part B, Sec 3.1. |
| // Each Data element has a header and a data field. |
| // The header field contains a type descriptor and a size descriptor. |
| // The header field is of variable length, which is determined by the size |
| // descriptor. |
| // |
| // DataElements all start as the Null type, and then can be set to any type. |
| // Examples: |
| // DataElement elem; // A null type |
| // uint32_t seymour = 0xFEED; |
| // elem.Set(seymour); |
| // ZX_DEBUG_ASSERT(elem.type() == DataElement::Type::kUnsignedInt); |
| // ZX_DEBUG_ASSERT(elem.Get<uint32_t>()); |
| // ZX_DEBUG_ASSERT(*elem.Get<uint32_t>() == seymour); |
| // |
| // std::vector<DataElement> service_class_ids; |
| // DataElement uuid; |
| // uuid.Set(UUID(sdp::ServiceClass::kAudioSource)); |
| // service_class_ids.emplace_back(std::move(uuid)); |
| // elem.Set(service_class_ids); |
| // ZX_DEBUG_ASSERT(e.type() == DataElement::Type::kSeqeuence); |
| // ZX_DEBUG_ASSERT(!e.Get<uint32_t>()); |
| class DataElement { |
| public: |
| // Type Descriptors. Only the top 5 bits are used, see kTypeMask |
| // v5.0, Vol 3, Part B, Sec 3.2. |
| enum class Type : uint8_t { |
| kNull = (0 << 3), |
| kUnsignedInt = (1 << 3), |
| kSignedInt = (2 << 3), |
| kUuid = (3 << 3), |
| kString = (4 << 3), |
| kBoolean = (5 << 3), |
| kSequence = (6 << 3), |
| kAlternative = (7 << 3), |
| kUrl = (8 << 3), |
| }; |
| constexpr static uint8_t kTypeMask = 0xF8; |
| |
| // Size Descriptor describing the size of the data following. |
| // Only three bits are used. |
| // For 0-4, the size is 2^(value) except in the case of kNull, in which |
| // case the size is 0. |
| // otherwise, the size is described in 2^(5-value) extra bytes following. |
| // v45.0, Vol 3, Part B, Sec 3.3 |
| enum class Size : uint8_t { |
| kOneByte = 0, |
| kTwoBytes = 1, |
| kFourBytes = 2, |
| kEightBytes = 3, |
| kSixteenBytes = 4, |
| kNextOne = 5, |
| kNextTwo = 6, |
| kNextFour = 7, |
| }; |
| constexpr static uint8_t kSizeMask = 0x07; |
| |
| // Constructs a Null data element. |
| DataElement(); |
| ~DataElement() = default; |
| |
| // Default move constructor and move-assigment |
| DataElement(DataElement&&) = default; |
| DataElement& operator=(DataElement&&) = default; |
| |
| // Convenience constructor to create a DataElement from a basic type. |
| template <typename T> |
| explicit DataElement(T value) { |
| Set<T>(std::move(value)); |
| } |
| |
| // Make a deep copy of this element. |
| DataElement Clone() const { return DataElement(*this); } |
| |
| // Reads a DataElement from |buffer|, replacing any data that was in |elem|. |
| // Returns the amount of space occupied on |buffer| by the data element, or |
| // zero if no element could be read. |
| static size_t Read(DataElement* elem, const ByteBuffer& buffer); |
| |
| // The type of this element. |
| Type type() const { return type_; } |
| |
| // The size of this element. |
| Size size() const { return size_; } |
| |
| // Sets the value of this element to |value|. |
| // Defined specializations: |
| // typename - type() |
| // std::nullptr_t - kNull |
| // uint8_t, .., uint64_t - kUnsignedInt |
| // int8_t .. int64_t - kSignedInt |
| // const UUID& - kUuid |
| // const std::string& - kString |
| // bool - kBoolean |
| // std::vector<DataElemnt> - kSequence |
| // (not available) - kUrl (not used in any known profiles) |
| template <typename T> |
| void Set(T value); |
| |
| // Sets this element's value to an alternative of the items in |items| |
| void SetAlternative(std::vector<DataElement> items); |
| |
| // Get the value of this element. |
| // Has the same defined specializations as Set(). |
| // Returns an optional without a value if the wrong type is stored. |
| template <typename T> |
| std::optional<T> Get() const; |
| |
| // Get a pointer to an element in a DataElement Sequence. |
| // Returns nullptr if type() is not kSequence or the index is invalid. |
| // Only valid as long as the containing sequence is valid. |
| const DataElement* At(size_t idx) const; |
| |
| // Calculates the number of bytes that this DataElement will use if it's |
| // written using Write(). |
| size_t WriteSize() const; |
| |
| // Writes this DataElement to |buffer|. |
| // Returns the number of bytes used for writing this element. |
| size_t Write(MutableByteBuffer* buffer) const; |
| |
| // Debug representation of this element (including it's type and size) in a |
| // string, i.e. UnsignedInt:4(15) or Sequence { UUID(1567), UUID(2502) } |
| std::string ToString() const; |
| |
| private: |
| // Copy constructor for Clone(), no assignment operator. |
| DataElement(const DataElement&); |
| DataElement& operator=(const DataElement&) = delete; |
| // Sets the size type based on a variable size (Next one, two, or four) |
| void SetVariableSize(size_t length); |
| |
| Type type_; |
| Size size_; |
| |
| // Various types for the stored value. These are only valid if the type_ is |
| // set correctly. |
| int64_t int_value_; |
| uint64_t uint_value_; |
| UUID uuid_; |
| std::string string_; |
| std::vector<DataElement> aggregate_; |
| }; |
| |
| } // namespace bt::sdp |
| |
| #endif // SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_SDP_DATA_ELEMENT_H_ |