OLD | NEW |
| (Empty) |
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_chromeos.h" | |
6 | |
7 #include <bluetooth/bluetooth.h> | |
8 | |
9 #include <string> | |
10 #include <vector> | |
11 | |
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" | |
16 | |
17 namespace { | |
18 | |
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"; | |
25 | |
26 static const char* kIdAttribute = "id"; | |
27 static const char* kValueAttribute = "value"; | |
28 static const char* kValueTrue = "true"; | |
29 | |
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"; | |
35 | |
36 static const char* kProtocolRfcommUuid = "0x0003"; | |
37 static const char* kProtocolHidpUuid = "0x0011"; | |
38 | |
39 bool AdvanceToTag(XmlReader* reader, const char* node_type) { | |
40 do { | |
41 if (!reader->Read()) | |
42 return false; | |
43 } while (reader->NodeName() != node_type); | |
44 return true; | |
45 } | |
46 | |
47 bool ExtractTextValue(XmlReader* reader, std::string* value_out) { | |
48 if (AdvanceToTag(reader, kTextNode)) { | |
49 reader->NodeAttribute(kValueAttribute, value_out); | |
50 return true; | |
51 } | |
52 return false; | |
53 } | |
54 | |
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)) | |
59 return false; | |
60 *value_out = str_value == kValueTrue; | |
61 return true; | |
62 } | |
63 return false; | |
64 } | |
65 | |
66 } // namespace | |
67 | |
68 namespace chromeos { | |
69 | |
70 BluetoothServiceRecordChromeOS::BluetoothServiceRecordChromeOS( | |
71 const std::string& address, | |
72 const std::string& xml_data) { | |
73 address_ = address; | |
74 supports_rfcomm_ = false; | |
75 supports_hid_ = false; | |
76 | |
77 // For HID services the default is false when the attribute is not present. | |
78 hid_reconnect_initiate_ = false; | |
79 hid_normally_connectable_ = false; | |
80 | |
81 XmlReader reader; | |
82 if (!reader.Load(xml_data)) | |
83 return; | |
84 | |
85 while (AdvanceToTag(&reader, kAttributeNode)) { | |
86 std::string id; | |
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); | |
93 } | |
94 } else if (id == kServiceClassUuidId) { | |
95 if (AdvanceToTag(&reader, kSequenceNode)) { | |
96 ExtractServiceClassUuid(&reader); | |
97 } | |
98 } else if (id == kHidNormallyConnectableId) { | |
99 ExtractBooleanValue(&reader, &hid_normally_connectable_); | |
100 } else if (id == kHidReconnectInitiateId) { | |
101 ExtractBooleanValue(&reader, &hid_reconnect_initiate_); | |
102 } | |
103 } | |
104 // We don't care about anything else here, so find the closing tag | |
105 AdvanceToTag(&reader, kAttributeNode); | |
106 } | |
107 if (!supports_hid_) { | |
108 // For non-HID services the default is true. | |
109 hid_normally_connectable_ = true; | |
110 hid_reconnect_initiate_ = true; | |
111 } | |
112 } | |
113 | |
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); | |
119 | |
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]; | |
124 } | |
125 | |
126 void BluetoothServiceRecordChromeOS::ExtractProtocolDescriptors( | |
127 XmlReader* reader) { | |
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. | |
132 do { | |
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), | |
144 &channel_bytes)) { | |
145 if (channel_bytes.size() == 1) { | |
146 rfcomm_channel_ = channel_bytes[0]; | |
147 supports_rfcomm_ = true; | |
148 } | |
149 } | |
150 } | |
151 } | |
152 } else if (protocolUuid == kProtocolHidpUuid) { | |
153 supports_hid_ = true; | |
154 } | |
155 } | |
156 } | |
157 } | |
158 } while (AdvanceToTag(reader, kSequenceNode) && | |
159 reader->Depth() != start_depth); | |
160 } | |
161 | |
162 void BluetoothServiceRecordChromeOS::ExtractServiceClassUuid( | |
163 XmlReader* reader) { | |
164 const int start_depth = reader->Depth(); | |
165 do { | |
166 if (reader->NodeName() == kSequenceNode) { | |
167 if (AdvanceToTag(reader, kUuidNode)) { | |
168 if (!reader->NodeAttribute(kValueAttribute, &uuid_)) | |
169 uuid_.clear(); | |
170 } | |
171 } | |
172 } while (AdvanceToTag(reader, kSequenceNode) && | |
173 reader->Depth() != start_depth); | |
174 | |
175 uuid_ = device::bluetooth_utils::CanonicalUuid(uuid_); | |
176 } | |
177 | |
178 } // namespace chromeos | |
OLD | NEW |