[go: nahoru, domu]

blob: 7a52c9f157179a45a65226bb0aa32cadea8c8dd0 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
#include <stddef.h>
#include <string>
#include "base/check_op.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#if defined(OS_WIN)
#include <objbase.h>
#include "base/strings/string16.h"
#include "base/win/win_util.h"
#endif // defined(OS_WIN)
namespace device {
namespace {
const char kCommonUuidPostfix[] = "-0000-1000-8000-00805f9b34fb";
const char kCommonUuidPrefix[] = "0000";
// Returns the canonical, 128-bit canonical, and the format of the UUID
// in |canonical|, |canonical_128|, and |format| based on |uuid|.
void GetCanonicalUuid(std::string uuid,
std::string* canonical,
std::string* canonical_128,
BluetoothUUID::Format* format) {
// Initialize the values for the failure case.
canonical->clear();
canonical_128->clear();
*format = BluetoothUUID::kFormatInvalid;
if (uuid.empty())
return;
if (uuid.size() < 11 &&
base::StartsWith(uuid, "0x", base::CompareCase::SENSITIVE)) {
uuid = uuid.substr(2);
}
if (!(uuid.size() == 4 || uuid.size() == 8 || uuid.size() == 36))
return;
for (size_t i = 0; i < uuid.size(); ++i) {
if (i == 8 || i == 13 || i == 18 || i == 23) {
if (uuid[i] != '-')
return;
} else {
if (!base::IsHexDigit(uuid[i]))
return;
uuid[i] = base::ToLowerASCII(uuid[i]);
}
}
canonical->assign(uuid);
if (uuid.size() == 4) {
canonical_128->assign(kCommonUuidPrefix + uuid + kCommonUuidPostfix);
*format = BluetoothUUID::kFormat16Bit;
} else if (uuid.size() == 8) {
canonical_128->assign(uuid + kCommonUuidPostfix);
*format = BluetoothUUID::kFormat32Bit;
} else {
canonical_128->assign(uuid);
*format = BluetoothUUID::kFormat128Bit;
}
}
} // namespace
BluetoothUUID::BluetoothUUID(const std::string& uuid) {
GetCanonicalUuid(uuid, &value_, &canonical_value_, &format_);
}
#if defined(OS_WIN)
BluetoothUUID::BluetoothUUID(GUID uuid) {
auto buffer = base::win::WStringFromGUID(uuid);
DCHECK_EQ('{', buffer[0]);
DCHECK_EQ('}', buffer[37]);
GetCanonicalUuid(base::WideToUTF8(buffer.substr(1, 36)), &value_,
&canonical_value_, &format_);
DCHECK_EQ(kFormat128Bit, format_);
}
#endif // defined(OS_WIN)
BluetoothUUID::BluetoothUUID() : format_(kFormatInvalid) {}
BluetoothUUID::~BluetoothUUID() = default;
#if defined(OS_WIN)
// static
GUID BluetoothUUID::GetCanonicalValueAsGUID(base::StringPiece uuid) {
DCHECK_EQ(36u, uuid.size());
std::u16string braced_uuid = u'{' + base::UTF8ToUTF16(uuid) + u'}';
GUID guid;
CHECK_EQ(NOERROR, ::CLSIDFromString(base::as_wcstr(braced_uuid), &guid));
return guid;
}
#endif // defined(OS_WIN)
bool BluetoothUUID::IsValid() const {
return format_ != kFormatInvalid;
}
std::vector<uint8_t> BluetoothUUID::GetBytes() const {
if (!IsValid())
return std::vector<uint8_t>();
base::StringPiece input(canonical_value());
std::vector<uint8_t> bytes(16);
base::span<uint8_t> out(bytes);
// 0 1 2 3
// 012345678901234567890123456789012345
// Example: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
// 12345678-1234-5678-9abc-def123456789
bool success =
(input.size() == 36) && (input[8] == '-') && (input[13] == '-') &&
(input[18] == '-') && (input[23] == '-') &&
base::HexStringToSpan(input.substr(0, 8), out.subspan<0, 4>()) &&
base::HexStringToSpan(input.substr(9, 4), out.subspan<4, 2>()) &&
base::HexStringToSpan(input.substr(14, 4), out.subspan<6, 2>()) &&
base::HexStringToSpan(input.substr(19, 4), out.subspan<8, 2>()) &&
base::HexStringToSpan(input.substr(24, 12), out.subspan<10, 6>());
DCHECK(success);
return bytes;
}
bool BluetoothUUID::operator<(const BluetoothUUID& uuid) const {
return canonical_value_ < uuid.canonical_value_;
}
bool BluetoothUUID::operator==(const BluetoothUUID& uuid) const {
return canonical_value_ == uuid.canonical_value_;
}
bool BluetoothUUID::operator!=(const BluetoothUUID& uuid) const {
return canonical_value_ != uuid.canonical_value_;
}
void PrintTo(const BluetoothUUID& uuid, std::ostream* out) {
*out << uuid.canonical_value();
}
} // namespace device