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.
5 #include "device/bluetooth/bluetooth_service_record_chromeos.h"
7 #include <bluetooth/bluetooth.h>
12 #include "base/logging.h"
13 #include "base/string_number_conversions.h"
14 #include "device/bluetooth/bluetooth_utils.h"
15 #include "third_party/libxml/chromium/libxml_utils.h"
19 static const char* kAttributeNode
= "attribute";
20 static const char* kBooleanNode
= "boolean";
21 static const char* kSequenceNode
= "sequence";
22 static const char* kTextNode
= "text";
23 static const char* kUint8Node
= "uint8";
24 static const char* kUuidNode
= "uuid";
26 static const char* kIdAttribute
= "id";
27 static const char* kValueAttribute
= "value";
28 static const char* kValueTrue
= "true";
30 static const char* kHidNormallyConnectableId
= "0x020d";
31 static const char* kHidReconnectInitiateId
= "0x0205";
32 static const char* kProtocolDescriptorListId
= "0x0004";
33 static const char* kSdpNameId
= "0x0100";
34 static const char* kServiceClassUuidId
= "0x0001";
36 static const char* kProtocolRfcommUuid
= "0x0003";
37 static const char* kProtocolHidpUuid
= "0x0011";
39 bool AdvanceToTag(XmlReader
* reader
, const char* node_type
) {
43 } while (reader
->NodeName() != node_type
);
47 bool ExtractTextValue(XmlReader
* reader
, std::string
* value_out
) {
48 if (AdvanceToTag(reader
, kTextNode
)) {
49 reader
->NodeAttribute(kValueAttribute
, value_out
);
55 bool ExtractBooleanValue(XmlReader
* reader
, bool* value_out
) {
56 if (AdvanceToTag(reader
, kBooleanNode
)) {
57 std::string str_value
;
58 if (!reader
->NodeAttribute(kValueAttribute
, &str_value
))
60 *value_out
= str_value
== kValueTrue
;
70 BluetoothServiceRecordChromeOS::BluetoothServiceRecordChromeOS(
71 const std::string
& address
,
72 const std::string
& xml_data
) {
74 supports_rfcomm_
= false;
75 supports_hid_
= false;
77 // For HID services the default is false when the attribute is not present.
78 hid_reconnect_initiate_
= false;
79 hid_normally_connectable_
= false;
82 if (!reader
.Load(xml_data
))
85 while (AdvanceToTag(&reader
, kAttributeNode
)) {
87 if (reader
.NodeAttribute(kIdAttribute
, &id
)) {
88 if (id
== kSdpNameId
) {
89 ExtractTextValue(&reader
, &name_
);
90 } else if (id
== kProtocolDescriptorListId
) {
91 if (AdvanceToTag(&reader
, kSequenceNode
)) {
92 ExtractProtocolDescriptors(&reader
);
94 } else if (id
== kServiceClassUuidId
) {
95 if (AdvanceToTag(&reader
, kSequenceNode
)) {
96 ExtractServiceClassUuid(&reader
);
98 } else if (id
== kHidNormallyConnectableId
) {
99 ExtractBooleanValue(&reader
, &hid_normally_connectable_
);
100 } else if (id
== kHidReconnectInitiateId
) {
101 ExtractBooleanValue(&reader
, &hid_reconnect_initiate_
);
104 // We don't care about anything else here, so find the closing tag
105 AdvanceToTag(&reader
, kAttributeNode
);
107 if (!supports_hid_
) {
108 // For non-HID services the default is true.
109 hid_normally_connectable_
= true;
110 hid_reconnect_initiate_
= true;
114 void BluetoothServiceRecordChromeOS::GetBluetoothAddress(
115 bdaddr_t
* out_address
) const {
116 std::string numbers_only
;
117 for (int i
= 0; i
< 6; ++i
)
118 numbers_only
+= address_
.substr(i
* 3, 2);
120 std::vector
<uint8
> address_bytes
;
121 base::HexStringToBytes(numbers_only
, &address_bytes
);
122 for (int i
= 0; i
< 6; ++i
)
123 out_address
->b
[5 - i
] = address_bytes
[i
];
126 void BluetoothServiceRecordChromeOS::ExtractProtocolDescriptors(
128 const int start_depth
= reader
->Depth();
129 // The ProtocolDescriptorList can have one or more sequence of sequence of
130 // stack, where each stack starts with an UUID and the remaining tags (if
131 // present) are protocol-specific.
133 if (reader
->NodeName() == kSequenceNode
) {
134 if (AdvanceToTag(reader
, kUuidNode
)) {
135 std::string protocolUuid
;
136 if (reader
->NodeAttribute(kValueAttribute
, &protocolUuid
)) {
137 // Per protocol parameters parsing.
138 if (protocolUuid
== kProtocolRfcommUuid
) {
139 if (AdvanceToTag(reader
, kUint8Node
)) {
140 std::string channel_string
;
141 if (reader
->NodeAttribute(kValueAttribute
, &channel_string
)) {
142 std::vector
<uint8
> channel_bytes
;
143 if (base::HexStringToBytes(channel_string
.substr(2),
145 if (channel_bytes
.size() == 1) {
146 rfcomm_channel_
= channel_bytes
[0];
147 supports_rfcomm_
= true;
152 } else if (protocolUuid
== kProtocolHidpUuid
) {
153 supports_hid_
= true;
158 } while (AdvanceToTag(reader
, kSequenceNode
) &&
159 reader
->Depth() != start_depth
);
162 void BluetoothServiceRecordChromeOS::ExtractServiceClassUuid(
164 const int start_depth
= reader
->Depth();
166 if (reader
->NodeName() == kSequenceNode
) {
167 if (AdvanceToTag(reader
, kUuidNode
)) {
168 if (!reader
->NodeAttribute(kValueAttribute
, &uuid_
))
172 } while (AdvanceToTag(reader
, kSequenceNode
) &&
173 reader
->Depth() != start_depth
);
175 uuid_
= device::bluetooth_utils::CanonicalUuid(uuid_
);
178 } // namespace chromeos