// Copyright (c) 2013 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 "device/bluetooth/bluetooth_service_record_win.h" #include #include "base/basictypes.h" #include "base/string_number_conversions.h" #include "base/stringprintf.h" #include "device/bluetooth/bluetooth_init_win.h" #include "device/bluetooth/bluetooth_utils.h" namespace { const uint16 kProtocolDescriptorListId = 4; const uint16 kRfcommUuid = 3; const uint16 kUuidId = 1; bool AdvanceToSdpType(const SDP_ELEMENT_DATA& sequence_data, SDP_TYPE type, HBLUETOOTH_CONTAINER_ELEMENT* element, SDP_ELEMENT_DATA* sdp_data) { while (ERROR_SUCCESS == BluetoothSdpGetContainerElementData( sequence_data.data.sequence.value, sequence_data.data.sequence.length, element, sdp_data)) { if (sdp_data->type == type) { return true; } } return false; } void ExtractChannels(const SDP_ELEMENT_DATA& protocol_descriptor_list_data, bool* supports_rfcomm, uint8* rfcomm_channel) { HBLUETOOTH_CONTAINER_ELEMENT sequence_element = NULL; SDP_ELEMENT_DATA sequence_data; while (AdvanceToSdpType(protocol_descriptor_list_data, SDP_TYPE_SEQUENCE, &sequence_element, &sequence_data)) { HBLUETOOTH_CONTAINER_ELEMENT inner_sequence_element = NULL; SDP_ELEMENT_DATA inner_sequence_data; if (AdvanceToSdpType(sequence_data, SDP_TYPE_UUID, &inner_sequence_element, &inner_sequence_data) && inner_sequence_data.data.uuid32 == kRfcommUuid && AdvanceToSdpType(sequence_data, SDP_TYPE_UINT, &inner_sequence_element, &inner_sequence_data) && inner_sequence_data.specificType == SDP_ST_UINT8) { *rfcomm_channel = inner_sequence_data.data.uint8; *supports_rfcomm = true; } } } void ExtractUuid(const SDP_ELEMENT_DATA& uuid_data, std::string* uuid) { HBLUETOOTH_CONTAINER_ELEMENT inner_uuid_element = NULL; SDP_ELEMENT_DATA inner_uuid_data; if (AdvanceToSdpType(uuid_data, SDP_TYPE_UUID, &inner_uuid_element, &inner_uuid_data)) { if (inner_uuid_data.specificType == SDP_ST_UUID16) { std::string uuid_hex = base::StringPrintf("%04x", inner_uuid_data.data.uuid16); *uuid = device::bluetooth_utils::CanonicalUuid(uuid_hex); } else if (inner_uuid_data.specificType == SDP_ST_UUID32) { std::string uuid_hex = base::StringPrintf("%08x", inner_uuid_data.data.uuid32); *uuid = device::bluetooth_utils::CanonicalUuid(uuid_hex); } else if (inner_uuid_data.specificType == SDP_ST_UUID128) { *uuid = base::StringPrintf( "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", inner_uuid_data.data.uuid128.Data1, inner_uuid_data.data.uuid128.Data2, inner_uuid_data.data.uuid128.Data3, inner_uuid_data.data.uuid128.Data4[0], inner_uuid_data.data.uuid128.Data4[1], inner_uuid_data.data.uuid128.Data4[2], inner_uuid_data.data.uuid128.Data4[3], inner_uuid_data.data.uuid128.Data4[4], inner_uuid_data.data.uuid128.Data4[5], inner_uuid_data.data.uuid128.Data4[6], inner_uuid_data.data.uuid128.Data4[7]); } else { uuid->clear(); } } } BTH_ADDR ConvertToBthAddr(const std::string& address) { BTH_ADDR bth_addr = 0; std::string numbers_only; for (int i = 0; i < 6; ++i) { numbers_only += address.substr(i * 3, 2); } std::vector address_bytes; base::HexStringToBytes(numbers_only, &address_bytes); int byte_position = 0; for (std::vector::reverse_iterator iter = address_bytes.rbegin(); iter != address_bytes.rend(); ++iter) { bth_addr += *iter * pow(256.0, byte_position); byte_position++; } return bth_addr; } } // namespace namespace device { BluetoothServiceRecordWin::BluetoothServiceRecordWin( const std::string& name, const std::string& address, uint64 blob_size, uint8* blob_data) : bth_addr_(ConvertToBthAddr(address)) { name_ = name; address_ = address; supports_rfcomm_ = false; SDP_ELEMENT_DATA protocol_descriptor_list_data; if (ERROR_SUCCESS == BluetoothSdpGetAttributeValue( blob_data, blob_size, kProtocolDescriptorListId, &protocol_descriptor_list_data)) { ExtractChannels(protocol_descriptor_list_data, &supports_rfcomm_, &rfcomm_channel_); } SDP_ELEMENT_DATA uuid_data; if (ERROR_SUCCESS == BluetoothSdpGetAttributeValue( blob_data, blob_size, kUuidId, &uuid_data)) { ExtractUuid(uuid_data, &uuid_); } } } // namespace device