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|. 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 76 BluetoothUUID::BluetoothUUID(const std::string& uuid) { 77 GetCanonicalUuid(uuid, &value_, &canonical_value_, &format_); 78 } 79 80 #if defined(OS_WIN) 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 96 BluetoothUUID::BluetoothUUID() : format_(kFormatInvalid) { 97 } 98 99 BluetoothUUID::~BluetoothUUID() = default; 100 101 #if defined(OS_WIN) 102 // static 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 112 bool BluetoothUUID::IsValid() const { 113 return format_ != kFormatInvalid; 114 } 115 116 bool BluetoothUUID::operator<(const BluetoothUUID& uuid) const { 117 return canonical_value_ < uuid.canonical_value_; 118 } 119 120 bool BluetoothUUID::operator==(const BluetoothUUID& uuid) const { 121 return canonical_value_ == uuid.canonical_value_; 122 } 123 124 bool BluetoothUUID::operator!=(const BluetoothUUID& uuid) const { 125 return canonical_value_ != uuid.canonical_value_; 126 } 127 128 void PrintTo(const BluetoothUUID& uuid, std::ostream* out) { 129 *out << uuid.canonical_value(); 130 } 131 132 } // namespace device 133