blob: d932a3ee1745792f831a8bdff21085d5cef9de1a [file] [log] [blame]
// 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 GARNET_DRIVERS_BLUETOOTH_LIB_SDP_DATA_ELEMENT_H_
#define GARNET_DRIVERS_BLUETOOTH_LIB_SDP_DATA_ELEMENT_H_
#include <vector>
#include "garnet/drivers/bluetooth/lib/common/byte_buffer.h"
#include "garnet/drivers/bluetooth/lib/common/uuid.h"
namespace btlib {
namespace 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 common::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 common::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(common::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_;
common::UUID uuid_;
std::string string_;
std::vector<DataElement> aggregate_;
};
} // namespace sdp
} // namespace btlib
#endif // GARNET_DRIVERS_BLUETOOTH_LIB_SDP_DATA_ELEMENT_H_