1 // Copyright 2014 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_uuid.h"
6
7 #include <stddef.h>
8
9 #include "base/logging.h"
10 #include "base/strings/string_piece.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13
14 #if defined(OS_WIN)
15 #include <objbase.h>
16
17 #include "base/strings/string16.h"
18 #endif // defined(OS_WIN)
19
20 namespace device {
21
22 namespace {
23
24 const char kCommonUuidPostfix[] = "-0000-1000-8000-00805f9b34fb";
25 const char kCommonUuidPrefix[] = "0000";
26
27 // Returns the canonical, 128-bit canonical, and the format of the UUID
28 // in |canonical|, |canonical_128|, and |format| based on |uuid|.
GetCanonicalUuid(std::string uuid,std::string * canonical,std::string * canonical_128,BluetoothUUID::Format * format)29 void GetCanonicalUuid(std::string uuid,
30 std::string* canonical,
31 std::string* canonical_128,
32 BluetoothUUID::Format* format) {
33 // Initialize the values for the failure case.
34 canonical->clear();
35 canonical_128->clear();
36 *format = BluetoothUUID::kFormatInvalid;
37
38 if (uuid.empty())
39 return;
40
41 if (uuid.size() < 11 &&
42 base::StartsWith(uuid, "0x", base::CompareCase::SENSITIVE)) {
43 uuid = uuid.substr(2);
44 }
45
46 if (!(uuid.size() == 4 || uuid.size() == 8 || uuid.size() == 36))
47 return;
48
49 for (size_t i = 0; i < uuid.size(); ++i) {
50 if (i == 8 || i == 13 || i == 18 || i == 23) {
51 if (uuid[i] != '-')
52 return;
53 } else {
54 if (!base::IsHexDigit(uuid[i]))
55 return;
56 uuid[i] = base::ToLowerASCII(uuid[i]);
57 }
58 }
59
60 canonical->assign(uuid);
61 if (uuid.size() == 4) {
62 canonical_128->assign(kCommonUuidPrefix + uuid + kCommonUuidPostfix);
63 *format = BluetoothUUID::kFormat16Bit;
64 } else if (uuid.size() == 8) {
65 canonical_128->assign(uuid + kCommonUuidPostfix);
66 *format = BluetoothUUID::kFormat32Bit;
67 } else {
68 canonical_128->assign(uuid);
69 *format = BluetoothUUID::kFormat128Bit;
70 }
71 }
72
73 } // namespace
74
75
BluetoothUUID(const std::string & uuid)76 BluetoothUUID::BluetoothUUID(const std::string& uuid) {
77 GetCanonicalUuid(uuid, &value_, &canonical_value_, &format_);
78 }
79
80 #if defined(OS_WIN)
BluetoothUUID(GUID uuid)81 BluetoothUUID::BluetoothUUID(GUID uuid) {
82 // 36 chars for UUID + 2 chars for braces + 1 char for null-terminator.
83 constexpr int kBufferSize = 39;
84 wchar_t buffer[kBufferSize];
85 int result = ::StringFromGUID2(uuid, buffer, kBufferSize);
86 DCHECK_EQ(kBufferSize, result);
87 DCHECK_EQ('{', buffer[0]);
88 DCHECK_EQ('}', buffer[37]);
89
90 GetCanonicalUuid(base::WideToUTF8(base::WStringPiece(buffer).substr(1, 36)),
91 &value_, &canonical_value_, &format_);
92 DCHECK_EQ(kFormat128Bit, format_);
93 }
94 #endif // defined(OS_WIN)
95
BluetoothUUID()96 BluetoothUUID::BluetoothUUID() : format_(kFormatInvalid) {
97 }
98
99 BluetoothUUID::~BluetoothUUID() = default;
100
101 #if defined(OS_WIN)
102 // static
GetCanonicalValueAsGUID(base::StringPiece uuid)103 GUID BluetoothUUID::GetCanonicalValueAsGUID(base::StringPiece uuid) {
104 DCHECK_EQ(36u, uuid.size());
105 base::string16 braced_uuid = L'{' + base::UTF8ToWide(uuid) + L'}';
106 GUID guid;
107 CHECK_EQ(NOERROR, ::CLSIDFromString(braced_uuid.data(), &guid));
108 return guid;
109 }
110 #endif // defined(OS_WIN)
111
IsValid() const112 bool BluetoothUUID::IsValid() const {
113 return format_ != kFormatInvalid;
114 }
115
operator <(const BluetoothUUID & uuid) const116 bool BluetoothUUID::operator<(const BluetoothUUID& uuid) const {
117 return canonical_value_ < uuid.canonical_value_;
118 }
119
operator ==(const BluetoothUUID & uuid) const120 bool BluetoothUUID::operator==(const BluetoothUUID& uuid) const {
121 return canonical_value_ == uuid.canonical_value_;
122 }
123
operator !=(const BluetoothUUID & uuid) const124 bool BluetoothUUID::operator!=(const BluetoothUUID& uuid) const {
125 return canonical_value_ != uuid.canonical_value_;
126 }
127
PrintTo(const BluetoothUUID & uuid,std::ostream * out)128 void PrintTo(const BluetoothUUID& uuid, std::ostream* out) {
129 *out << uuid.canonical_value();
130 }
131
132 } // namespace device
133