blob: 9581d5138fccb4220c9e927c47bf58f7acfc8252 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <cctype>
#include <iomanip>
#include <ios>
#include <memory>
#include <sstream>
#include <string>
#include <vector>
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "components/arc/bluetooth/bluetooth_type_converters.h"
#include "device/bluetooth/bluetooth_gatt_service.h"
#include "device/bluetooth/bluetooth_uuid.h"
namespace {
constexpr size_t kAddressSize = 6;
constexpr char kInvalidAddress[] = "00:00:00:00:00:00";
// SDP Service attribute IDs.
constexpr uint16_t kServiceClassIDList = 0x0001;
constexpr uint16_t kProtocolDescriptorList = 0x0004;
constexpr uint16_t kBrowseGroupList = 0x0005;
constexpr uint16_t kBluetoothProfileDescriptorList = 0x0009;
constexpr uint16_t kServiceName = 0x0100;
bool IsNonHex(char c) {
return !isxdigit(c);
}
std::string StripNonHex(const std::string& str) {
std::string result = str;
base::EraseIf(result, IsNonHex);
return result;
}
} // namespace
namespace mojo {
// static
arc::mojom::BluetoothAddressPtr
TypeConverter<arc::mojom::BluetoothAddressPtr, std::string>::Convert(
const std::string& address) {
arc::mojom::BluetoothAddressPtr mojo_addr =
arc::mojom::BluetoothAddress::New();
base::HexStringToBytes(StripNonHex(address), &mojo_addr->address);
return mojo_addr;
}
// static
std::string TypeConverter<std::string, arc::mojom::BluetoothAddress>::Convert(
const arc::mojom::BluetoothAddress& address) {
std::ostringstream addr_stream;
addr_stream << std::setfill('0') << std::hex << std::uppercase;
const std::vector<uint8_t>& bytes = address.address;
if (address.address.size() != kAddressSize)
return std::string(kInvalidAddress);
for (size_t k = 0; k < bytes.size(); k++) {
addr_stream << std::setw(2) << (unsigned int)bytes[k];
addr_stream << ((k == bytes.size() - 1) ? "" : ":");
}
return addr_stream.str();
}
// static
arc::mojom::BluetoothSdpAttributePtr
TypeConverter<arc::mojom::BluetoothSdpAttributePtr,
bluez::BluetoothServiceAttributeValueBlueZ>::
Convert(const bluez::BluetoothServiceAttributeValueBlueZ& attr_bluez,
size_t depth) {
auto result = arc::mojom::BluetoothSdpAttribute::New();
result->type = attr_bluez.type();
result->type_size = 0;
switch (result->type) {
case bluez::BluetoothServiceAttributeValueBlueZ::NULLTYPE:
case bluez::BluetoothServiceAttributeValueBlueZ::UINT:
case bluez::BluetoothServiceAttributeValueBlueZ::INT:
case bluez::BluetoothServiceAttributeValueBlueZ::UUID:
case bluez::BluetoothServiceAttributeValueBlueZ::STRING:
case bluez::BluetoothServiceAttributeValueBlueZ::URL:
case bluez::BluetoothServiceAttributeValueBlueZ::BOOL: {
result->type_size = attr_bluez.size();
std::string json;
base::JSONWriter::Write(attr_bluez.value(), &json);
result->json_value = std::move(json);
break;
}
case bluez::BluetoothServiceAttributeValueBlueZ::SEQUENCE:
if (depth + 1 >= arc::kBluetoothSDPMaxDepth) {
result->type = bluez::BluetoothServiceAttributeValueBlueZ::NULLTYPE;
result->type_size = 0;
return result;
}
for (const auto& child : attr_bluez.sequence()) {
result->sequence.push_back(Convert(child, depth + 1));
}
result->type_size = result->sequence.size();
break;
default:
NOTREACHED();
}
return result;
}
// static
bluez::BluetoothServiceAttributeValueBlueZ
TypeConverter<bluez::BluetoothServiceAttributeValueBlueZ,
arc::mojom::BluetoothSdpAttributePtr>::
Convert(const arc::mojom::BluetoothSdpAttributePtr& attr, size_t depth) {
bluez::BluetoothServiceAttributeValueBlueZ::Type type = attr->type;
switch (type) {
case bluez::BluetoothServiceAttributeValueBlueZ::NULLTYPE:
case bluez::BluetoothServiceAttributeValueBlueZ::UINT:
case bluez::BluetoothServiceAttributeValueBlueZ::INT:
case bluez::BluetoothServiceAttributeValueBlueZ::UUID:
case bluez::BluetoothServiceAttributeValueBlueZ::STRING:
case bluez::BluetoothServiceAttributeValueBlueZ::URL:
case bluez::BluetoothServiceAttributeValueBlueZ::BOOL: {
if (!attr->json_value.has_value()) {
return bluez::BluetoothServiceAttributeValueBlueZ(
bluez::BluetoothServiceAttributeValueBlueZ::NULLTYPE, 0,
std::make_unique<base::Value>());
}
return bluez::BluetoothServiceAttributeValueBlueZ(
type, static_cast<size_t>(attr->type_size),
base::JSONReader::Read(attr->json_value.value()));
}
case bluez::BluetoothServiceAttributeValueBlueZ::SEQUENCE: {
if (depth + 1 >= arc::kBluetoothSDPMaxDepth || attr->sequence.empty()) {
return bluez::BluetoothServiceAttributeValueBlueZ(
bluez::BluetoothServiceAttributeValueBlueZ::NULLTYPE, 0,
std::make_unique<base::Value>());
}
auto bluez_sequence = std::make_unique<
bluez::BluetoothServiceAttributeValueBlueZ::Sequence>();
for (const auto& child : attr->sequence) {
bluez_sequence->push_back(Convert(child, depth + 1));
}
return bluez::BluetoothServiceAttributeValueBlueZ(
std::move(bluez_sequence));
break;
}
default:
NOTREACHED();
}
return bluez::BluetoothServiceAttributeValueBlueZ(
bluez::BluetoothServiceAttributeValueBlueZ::NULLTYPE, 0,
std::make_unique<base::Value>());
}
// static
arc::mojom::BluetoothSdpRecordPtr
TypeConverter<arc::mojom::BluetoothSdpRecordPtr,
bluez::BluetoothServiceRecordBlueZ>::
Convert(const bluez::BluetoothServiceRecordBlueZ& record_bluez) {
arc::mojom::BluetoothSdpRecordPtr result =
arc::mojom::BluetoothSdpRecord::New();
for (auto id : record_bluez.GetAttributeIds()) {
switch (id) {
case kServiceClassIDList:
case kProtocolDescriptorList:
case kBrowseGroupList:
case kBluetoothProfileDescriptorList:
case kServiceName:
result->attrs[id] = arc::mojom::BluetoothSdpAttribute::From(
record_bluez.GetAttributeValue(id));
break;
default:
// Android does not support this.
break;
}
}
return result;
}
// static
bluez::BluetoothServiceRecordBlueZ
TypeConverter<bluez::BluetoothServiceRecordBlueZ,
arc::mojom::BluetoothSdpRecordPtr>::
Convert(const arc::mojom::BluetoothSdpRecordPtr& record) {
bluez::BluetoothServiceRecordBlueZ record_bluez;
for (const auto& pair : record->attrs) {
switch (pair.first) {
case kServiceClassIDList:
case kProtocolDescriptorList:
case kBrowseGroupList:
case kBluetoothProfileDescriptorList:
case kServiceName:
record_bluez.AddRecordEntry(
pair.first,
pair.second.To<bluez::BluetoothServiceAttributeValueBlueZ>());
break;
default:
NOTREACHED();
break;
}
}
return record_bluez;
}
} // namespace mojo