| // 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 <string> |
| |
| #include "base/basictypes.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/stringprintf.h" |
| #include "device/bluetooth/bluetooth_init_win.h" |
| #include "device/bluetooth/bluetooth_uuid.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, |
| device::BluetoothUUID* 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::BluetoothUUID(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::BluetoothUUID(uuid_hex); |
| } else if (inner_uuid_data.specificType == SDP_ST_UUID128) { |
| *uuid = device::BluetoothUUID(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 = device::BluetoothUUID(); |
| } |
| } |
| } |
| |
| 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<uint8> address_bytes; |
| base::HexStringToBytes(numbers_only, &address_bytes); |
| int byte_position = 0; |
| for (std::vector<uint8>::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& device_address, |
| const std::string& name, |
| const std::vector<uint8>& sdp_bytes, |
| const BluetoothUUID& gatt_uuid) |
| : device_bth_addr_(ConvertToBthAddr(device_address)), |
| device_address_(device_address), |
| name_(name), |
| uuid_(gatt_uuid), |
| supports_rfcomm_(false), |
| rfcomm_channel_(0xFF) { |
| // Bluetooth 2.0 |
| if (sdp_bytes.size() > 0) { |
| LPBYTE blob_data = const_cast<LPBYTE>(&sdp_bytes[0]); |
| ULONG blob_size = static_cast<ULONG>(sdp_bytes.size()); |
| 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_); |
| } |
| } |
| } |
| |
| bool BluetoothServiceRecordWin::IsEqual( |
| const BluetoothServiceRecordWin& other) { |
| return device_address_ == other.device_address_ && name_ == other.name_ && |
| uuid_ == other.uuid_ && supports_rfcomm_ == other.supports_rfcomm_ && |
| rfcomm_channel_ == other.rfcomm_channel_; |
| } |
| |
| } // namespace device |