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