You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
239 lines
7.1 KiB
239 lines
7.1 KiB
/*
|
|
* Copyright 2018 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "data_element_reader.h"
|
|
|
|
#include <base/logging.h>
|
|
#include <type_traits>
|
|
|
|
#include "sdp_logging_helper.h"
|
|
|
|
// A helper macro that can verify that there is enough data remaining in the
|
|
// reader to extract without overflowing. end_ - it_ should never be negative
|
|
// so casting it to a size_t is always safe. If it does fail, set it_ to end_
|
|
// so that all additional readings fail.
|
|
#define CHECK_REMAINING_LEN(x) \
|
|
do { \
|
|
if ((size_t)(end_ - it_) < x) { \
|
|
LOG(WARNING) << __func__ << ": Extract would read past end of data."; \
|
|
return ParseFail(); \
|
|
} \
|
|
} while (0)
|
|
|
|
namespace bluetooth {
|
|
namespace sdp {
|
|
|
|
DataElementReader::DataElement DataElementReader::ReadNext() {
|
|
if (it_ > end_) LOG(FATAL) << "Beginning of buffer is past end of buffer.";
|
|
if (it_ == end_) return std::monostate();
|
|
|
|
uint8_t descriptor = *it_++;
|
|
DataElementType type = static_cast<DataElementType>(descriptor >> 3);
|
|
DataElementSize size = static_cast<DataElementSize>(descriptor & 0b00000111);
|
|
|
|
// All types with a value greater than URL are currently reserved.
|
|
if (type > DataElementType::MAX_VALUE) {
|
|
LOG(WARNING) << __func__ << ": Trying to use a reserved data element type";
|
|
return ParseFail();
|
|
}
|
|
|
|
switch (type) {
|
|
case DataElementType::BOOLEAN:
|
|
if (size != DataElementSize::BYTE1) {
|
|
LOG(WARNING) << __func__ << ": Invalid size for bool: " << size;
|
|
return ParseFail();
|
|
}
|
|
|
|
CHECK_REMAINING_LEN(1);
|
|
return (it_.extract<uint8_t>() != 0);
|
|
case DataElementType::SIGNED_INT:
|
|
return ReadSignedInt(size);
|
|
case DataElementType::UNSIGNED_INT:
|
|
return ReadUnsignedInt(size);
|
|
case DataElementType::UUID:
|
|
return ReadUuid(size);
|
|
case DataElementType::STRING:
|
|
return ReadString(size);
|
|
case DataElementType::DATA_ELEMENT_SEQUENCE:
|
|
return ReadSequence(size);
|
|
default:
|
|
// TODO: The other data element types are never used in the previous SDP
|
|
// implementation. We should properly handle them in the future though
|
|
// for completeness.
|
|
LOG(ERROR) << __func__ << ": Unhandled Data Element Type: " << type;
|
|
}
|
|
|
|
return ParseFail();
|
|
}
|
|
|
|
DataElementReader::DataElement DataElementReader::ParseFail() {
|
|
it_ = end_;
|
|
return std::monostate();
|
|
}
|
|
|
|
template <class IntegerType>
|
|
DataElementReader::DataElement DataElementReader::ReadInteger() {
|
|
static_assert(std::is_integral<IntegerType>::value,
|
|
"ReadInteger requires an integral type.");
|
|
|
|
CHECK_REMAINING_LEN(sizeof(IntegerType));
|
|
return it_.extractBE<IntegerType>();
|
|
}
|
|
|
|
DataElementReader::DataElement DataElementReader::ReadLargeInt() {
|
|
CHECK_REMAINING_LEN(16);
|
|
|
|
std::array<uint8_t, 16> array;
|
|
for (size_t i = 0; i < sizeof(uint8_t[16]); i++) {
|
|
array[i] = it_.extract<uint8_t>();
|
|
}
|
|
|
|
return array;
|
|
}
|
|
|
|
DataElementReader::DataElement DataElementReader::ReadSignedInt(
|
|
DataElementSize size) {
|
|
switch (size) {
|
|
case DataElementSize::BYTE1:
|
|
return ReadInteger<int8_t>();
|
|
case DataElementSize::BYTE2:
|
|
return ReadInteger<int16_t>();
|
|
case DataElementSize::BYTE4:
|
|
return ReadInteger<int32_t>();
|
|
case DataElementSize::BYTE8:
|
|
return ReadInteger<int64_t>();
|
|
case DataElementSize::BYTE16:
|
|
return ReadLargeInt();
|
|
default:
|
|
LOG(WARNING) << __func__ << ": Invalid size for int: " << size;
|
|
}
|
|
|
|
return ParseFail();
|
|
}
|
|
|
|
DataElementReader::DataElement DataElementReader::ReadUnsignedInt(
|
|
DataElementSize size) {
|
|
switch (size) {
|
|
case DataElementSize::BYTE1:
|
|
return ReadInteger<uint8_t>();
|
|
case DataElementSize::BYTE2:
|
|
return ReadInteger<uint16_t>();
|
|
case DataElementSize::BYTE4:
|
|
return ReadInteger<uint32_t>();
|
|
case DataElementSize::BYTE8:
|
|
return ReadInteger<uint64_t>();
|
|
case DataElementSize::BYTE16:
|
|
return ReadLargeInt();
|
|
default:
|
|
LOG(WARNING) << __func__ << ": Invalid size for uint: " << size;
|
|
}
|
|
|
|
return ParseFail();
|
|
}
|
|
|
|
DataElementReader::DataElement DataElementReader::ReadUuid(
|
|
DataElementSize size) {
|
|
if (size == DataElementSize::BYTE2) {
|
|
CHECK_REMAINING_LEN(2);
|
|
return Uuid::From16Bit(it_.extractBE<uint16_t>());
|
|
}
|
|
|
|
if (size == DataElementSize::BYTE4) {
|
|
CHECK_REMAINING_LEN(4);
|
|
return Uuid::From32Bit(it_.extractBE<uint32_t>());
|
|
}
|
|
|
|
if (size == DataElementSize::BYTE16) {
|
|
CHECK_REMAINING_LEN(16);
|
|
|
|
Uuid::UUID128Bit uuid_array;
|
|
for (int i = 0; i < 16; i++) {
|
|
uuid_array[i] = it_.extract<uint8_t>();
|
|
}
|
|
|
|
return Uuid::From128BitBE(uuid_array);
|
|
}
|
|
|
|
LOG(WARNING) << __func__ << ": Invalid size for UUID: " << size;
|
|
return ParseFail();
|
|
}
|
|
|
|
DataElementReader::DataElement DataElementReader::ReadString(
|
|
DataElementSize size) {
|
|
uint32_t num_bytes = 0;
|
|
|
|
switch (size) {
|
|
case DataElementSize::ADDITIONAL_8BIT:
|
|
CHECK_REMAINING_LEN(1);
|
|
num_bytes = it_.extractBE<uint8_t>();
|
|
break;
|
|
case DataElementSize::ADDITIONAL_16BIT:
|
|
CHECK_REMAINING_LEN(2);
|
|
num_bytes = it_.extractBE<uint16_t>();
|
|
break;
|
|
case DataElementSize::ADDITIONAL_32BIT:
|
|
CHECK_REMAINING_LEN(4);
|
|
num_bytes = it_.extractBE<uint32_t>();
|
|
break;
|
|
default:
|
|
LOG(WARNING) << __func__ << ": Invalid size for string: " << size;
|
|
return ParseFail();
|
|
}
|
|
|
|
CHECK_REMAINING_LEN(num_bytes);
|
|
|
|
std::string str;
|
|
for (uint32_t i = 0; i < num_bytes; i++) {
|
|
str.push_back(it_.extractBE<uint8_t>());
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
DataElementReader::DataElement DataElementReader::ReadSequence(
|
|
DataElementSize size) {
|
|
uint32_t num_bytes = 0;
|
|
|
|
switch (size) {
|
|
case DataElementSize::ADDITIONAL_8BIT:
|
|
CHECK_REMAINING_LEN(1);
|
|
num_bytes = it_.extractBE<uint8_t>();
|
|
break;
|
|
case DataElementSize::ADDITIONAL_16BIT:
|
|
CHECK_REMAINING_LEN(2);
|
|
num_bytes = it_.extractBE<uint16_t>();
|
|
break;
|
|
case DataElementSize::ADDITIONAL_32BIT:
|
|
CHECK_REMAINING_LEN(4);
|
|
num_bytes = it_.extractBE<uint32_t>();
|
|
break;
|
|
default:
|
|
LOG(WARNING) << __func__ << ": Invalid size for string: " << size;
|
|
return ParseFail();
|
|
}
|
|
|
|
CHECK_REMAINING_LEN(num_bytes);
|
|
|
|
// Create a parser that points to the beginning of the next sequence and move
|
|
// the iterator to past the end of the new sequence.
|
|
auto&& temp = DataElementReader(it_, it_ + num_bytes);
|
|
it_ += num_bytes;
|
|
return std::move(temp);
|
|
}
|
|
|
|
} // namespace sdp
|
|
} // namespace bluetooth
|