1// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "device/bluetooth/bluetooth_service_record_win.h"
6
7#include <string>
8
9#include "base/basictypes.h"
10#include "base/strings/string_number_conversions.h"
11#include "base/strings/stringprintf.h"
12#include "device/bluetooth/bluetooth_init_win.h"
13#include "device/bluetooth/bluetooth_uuid.h"
14
15namespace {
16
17const uint16 kProtocolDescriptorListId = 4;
18const uint16 kRfcommUuid = 3;
19const uint16 kUuidId = 1;
20
21bool AdvanceToSdpType(const SDP_ELEMENT_DATA& sequence_data,
22                      SDP_TYPE type,
23                      HBLUETOOTH_CONTAINER_ELEMENT* element,
24                      SDP_ELEMENT_DATA* sdp_data) {
25  while (ERROR_SUCCESS == BluetoothSdpGetContainerElementData(
26      sequence_data.data.sequence.value,
27      sequence_data.data.sequence.length,
28      element,
29      sdp_data)) {
30    if (sdp_data->type == type) {
31      return true;
32    }
33  }
34  return false;
35}
36
37void ExtractChannels(const SDP_ELEMENT_DATA& protocol_descriptor_list_data,
38                     bool* supports_rfcomm,
39                     uint8* rfcomm_channel) {
40  HBLUETOOTH_CONTAINER_ELEMENT sequence_element = NULL;
41  SDP_ELEMENT_DATA sequence_data;
42  while (AdvanceToSdpType(protocol_descriptor_list_data,
43                          SDP_TYPE_SEQUENCE,
44                          &sequence_element,
45                          &sequence_data)) {
46    HBLUETOOTH_CONTAINER_ELEMENT inner_sequence_element = NULL;
47    SDP_ELEMENT_DATA inner_sequence_data;
48    if (AdvanceToSdpType(sequence_data,
49                         SDP_TYPE_UUID,
50                         &inner_sequence_element,
51                         &inner_sequence_data) &&
52        inner_sequence_data.data.uuid32 == kRfcommUuid &&
53        AdvanceToSdpType(sequence_data,
54                         SDP_TYPE_UINT,
55                         &inner_sequence_element,
56                         &inner_sequence_data) &&
57        inner_sequence_data.specificType == SDP_ST_UINT8) {
58      *rfcomm_channel = inner_sequence_data.data.uint8;
59      *supports_rfcomm = true;
60    }
61  }
62}
63
64void ExtractUuid(const SDP_ELEMENT_DATA& uuid_data,
65                 device::BluetoothUUID* uuid) {
66  HBLUETOOTH_CONTAINER_ELEMENT inner_uuid_element = NULL;
67  SDP_ELEMENT_DATA inner_uuid_data;
68  if (AdvanceToSdpType(uuid_data,
69                       SDP_TYPE_UUID,
70                       &inner_uuid_element,
71                       &inner_uuid_data)) {
72    if (inner_uuid_data.specificType == SDP_ST_UUID16) {
73      std::string uuid_hex =
74          base::StringPrintf("%04x", inner_uuid_data.data.uuid16);
75      *uuid = device::BluetoothUUID(uuid_hex);
76    } else if (inner_uuid_data.specificType == SDP_ST_UUID32) {
77      std::string uuid_hex =
78          base::StringPrintf("%08x", inner_uuid_data.data.uuid32);
79      *uuid = device::BluetoothUUID(uuid_hex);
80    } else if (inner_uuid_data.specificType == SDP_ST_UUID128) {
81      *uuid = device::BluetoothUUID(base::StringPrintf(
82          "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
83          inner_uuid_data.data.uuid128.Data1,
84          inner_uuid_data.data.uuid128.Data2,
85          inner_uuid_data.data.uuid128.Data3,
86          inner_uuid_data.data.uuid128.Data4[0],
87          inner_uuid_data.data.uuid128.Data4[1],
88          inner_uuid_data.data.uuid128.Data4[2],
89          inner_uuid_data.data.uuid128.Data4[3],
90          inner_uuid_data.data.uuid128.Data4[4],
91          inner_uuid_data.data.uuid128.Data4[5],
92          inner_uuid_data.data.uuid128.Data4[6],
93          inner_uuid_data.data.uuid128.Data4[7]));
94    } else {
95      *uuid = device::BluetoothUUID();
96    }
97  }
98}
99
100BTH_ADDR ConvertToBthAddr(const std::string& address) {
101  BTH_ADDR bth_addr = 0;
102  std::string numbers_only;
103  for (int i = 0; i < 6; ++i) {
104    numbers_only += address.substr(i * 3, 2);
105  }
106
107  std::vector<uint8> address_bytes;
108  base::HexStringToBytes(numbers_only, &address_bytes);
109  int byte_position = 0;
110  for (std::vector<uint8>::reverse_iterator iter = address_bytes.rbegin();
111      iter != address_bytes.rend();
112      ++iter) {
113    bth_addr += *iter * pow(256.0, byte_position);
114    byte_position++;
115  }
116  return bth_addr;
117}
118
119}  // namespace
120
121namespace device {
122
123BluetoothServiceRecordWin::BluetoothServiceRecordWin(
124    const std::string& device_address,
125    const std::string& name,
126    const std::vector<uint8>& sdp_bytes,
127    const BluetoothUUID& gatt_uuid)
128    : device_bth_addr_(ConvertToBthAddr(device_address)),
129      device_address_(device_address),
130      name_(name),
131      uuid_(gatt_uuid),
132      supports_rfcomm_(false),
133      rfcomm_channel_(0xFF) {
134  // Bluetooth 2.0
135  if (sdp_bytes.size() > 0) {
136    LPBYTE blob_data = const_cast<LPBYTE>(&sdp_bytes[0]);
137    ULONG blob_size = static_cast<ULONG>(sdp_bytes.size());
138    SDP_ELEMENT_DATA protocol_descriptor_list_data;
139    if (ERROR_SUCCESS ==
140        BluetoothSdpGetAttributeValue(blob_data,
141                                      blob_size,
142                                      kProtocolDescriptorListId,
143                                      &protocol_descriptor_list_data)) {
144      ExtractChannels(
145          protocol_descriptor_list_data, &supports_rfcomm_, &rfcomm_channel_);
146    }
147    SDP_ELEMENT_DATA uuid_data;
148    if (ERROR_SUCCESS == BluetoothSdpGetAttributeValue(
149                             blob_data, blob_size, kUuidId, &uuid_data)) {
150      ExtractUuid(uuid_data, &uuid_);
151    }
152  }
153}
154
155bool BluetoothServiceRecordWin::IsEqual(
156    const BluetoothServiceRecordWin& other) {
157  return device_address_ == other.device_address_ && name_ == other.name_ &&
158         uuid_ == other.uuid_ && supports_rfcomm_ == other.supports_rfcomm_ &&
159         rfcomm_channel_ == other.rfcomm_channel_;
160}
161
162}  // namespace device
163