* Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "uuid.h"
#include <cerrno>
#define CONSTANT_ZERO 0
#define CONSTANT_FOUR 4
#define CONSTANT_EIGHT 8
#define CONSTANT_TWELVE 12
#define CONSTANT_SIXTEEN 16
#define CONSTANT_TWENTY 20
namespace {
constexpr int UUID_STRING_LENGTH = 36;
constexpr bool IS_DASH_POSITION[UUID_STRING_LENGTH] = {
0, 0, 0, 0, 0, 0, 0, 0, 1,
0, 0, 0, 0, 1,
0, 0, 0, 0, 1,
0, 0, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
}
namespace OHOS {
namespace Bluetooth {
UUID::UUID(const long mostSigBits, const long leastSigBits)
{
this->uuid_[15] = static_cast<uint8_t>(leastSigBits & 0x00000000000000FF);
this->uuid_[14] = static_cast<uint8_t>((leastSigBits & 0x000000000000FF00) >> 8);
this->uuid_[13] = static_cast<uint8_t>((leastSigBits & 0x0000000000FF0000) >> 16);
this->uuid_[12] = static_cast<uint8_t>((leastSigBits & 0x00000000FF000000) >> 24);
this->uuid_[11] = static_cast<uint8_t>((leastSigBits & 0x000000FF00000000) >> 32);
this->uuid_[10] = static_cast<uint8_t>((leastSigBits & 0x0000FF0000000000) >> 40);
this->uuid_[9] = static_cast<uint8_t>((leastSigBits & 0x00FF000000000000) >> 48);
this->uuid_[8] = static_cast<uint8_t>((leastSigBits & 0xFF00000000000000) >> 56);
this->uuid_[7] = static_cast<uint8_t>(mostSigBits & 0x00000000000000FF);
this->uuid_[6] = static_cast<uint8_t>((mostSigBits & 0x000000000000FF00) >> 8);
this->uuid_[5] = static_cast<uint8_t>((mostSigBits & 0x0000000000FF0000) >> 16);
this->uuid_[4] = static_cast<uint8_t>((mostSigBits & 0x00000000FF000000) >> 24);
this->uuid_[3] = static_cast<uint8_t>((mostSigBits & 0x000000FF00000000) >> 32);
this->uuid_[2] = static_cast<uint8_t>((mostSigBits & 0x0000FF0000000000) >> 40);
this->uuid_[1] = static_cast<uint8_t>((mostSigBits & 0x00FF000000000000) >> 48);
this->uuid_[0] = static_cast<uint8_t>((mostSigBits & 0xFF00000000000000) >> 56);
}
UUID UUID::FromString(const std::string &name)
{
UUID ret;
if (name.empty() || !IsValidUuid(name)) {
return ret;
}
std::string tmp = name;
std::size_t pos = tmp.find("-");
while (pos != std::string::npos) {
tmp.replace(pos, 1, "");
pos = tmp.find("-");
}
for (std::size_t i = 0; (i + 1) < tmp.length();) {
errno = 0;
char *endptr = nullptr;
long int num = std::strtol(tmp.substr(i, 2).c_str(), &endptr, 16);
if (errno == ERANGE) {
return ret;
}
ret.uuid_[i / 2] = static_cast<int>(num);
i += 2;
}
return ret;
}
UUID UUID::RandomUUID()
{
UUID random;
struct timeval tv;
struct timezone tz;
struct tm randomTime;
unsigned int randNum = 0;
rand_r(&randNum);
gettimeofday(&tv, &tz);
localtime_r(&tv.tv_sec, &randomTime);
random.uuid_[15] = static_cast<uint8_t>(tv.tv_usec & 0x00000000000000FF);
random.uuid_[14] = static_cast<uint8_t>((tv.tv_usec & 0x000000000000FF00) >> 8);
random.uuid_[13] = static_cast<uint8_t>((tv.tv_usec & 0x0000000000FF0000) >> 16);
random.uuid_[12] = static_cast<uint8_t>((tv.tv_usec & 0x00000000FF000000) >> 24);
random.uuid_[10] = static_cast<uint8_t>((tv.tv_usec & 0x000000FF00000000) >> 32);
random.uuid_[9] = static_cast<uint8_t>((tv.tv_usec & 0x0000FF0000000000) >> 40);
random.uuid_[8] = static_cast<uint8_t>((tv.tv_usec & 0x00FF000000000000) >> 48);
random.uuid_[7] = static_cast<uint8_t>((tv.tv_usec & 0xFF00000000000000) >> 56);
random.uuid_[6] = static_cast<uint8_t>((randomTime.tm_sec + static_cast<int>(randNum)) & 0xFF);
random.uuid_[5] = static_cast<uint8_t>((randomTime.tm_min + (randNum >> 8)) & 0xFF);
random.uuid_[4] = static_cast<uint8_t>((randomTime.tm_hour + (randNum >> 16)) & 0xFF);
random.uuid_[3] = static_cast<uint8_t>((randomTime.tm_mday + (randNum >> 24)) & 0xFF);
random.uuid_[2] = static_cast<uint8_t>(randomTime.tm_mon & 0xFF);
random.uuid_[1] = static_cast<uint8_t>(randomTime.tm_year & 0xFF);
random.uuid_[0] = static_cast<uint8_t>((randomTime.tm_year & 0xFF00) >> 8);
return random;
}
std::string UUID::ToString() const
{
std::string tmp = "";
std::string ret = "";
static const char *hex = "0123456789ABCDEF";
for (auto it = this->uuid_.begin(); it != this->uuid_.end(); it++) {
tmp.push_back(hex[(((*it) >> 4) & 0xF)]);
tmp.push_back(hex[(*it) & 0xF]);
}
ret = tmp.substr(CONSTANT_ZERO, CONSTANT_EIGHT) + "-" +
tmp.substr(CONSTANT_EIGHT, CONSTANT_FOUR) + "-" +
tmp.substr(CONSTANT_TWELVE, CONSTANT_FOUR) + "-" +
tmp.substr(CONSTANT_SIXTEEN, CONSTANT_FOUR) + "-" +
tmp.substr(CONSTANT_TWENTY);
return ret;
}
int UUID::CompareTo(const UUID &val) const
{
UUID tmp = val;
return this->ToString().compare(tmp.ToString());
}
bool UUID::Equals(const UUID &val) const
{
for (int i = 0; i < UUID::UUID128_BYTES_LEN; i++) {
if (this->uuid_[i] != val.uuid_[i]) {
return false;
}
}
return true;
}
uint64_t UUID::GetLeastSignificantBits() const
{
uint64_t leastSigBits = 0;
for (int i = UUID::UUID128_BYTES_LEN / 2; i < UUID::UUID128_BYTES_LEN; i++) {
leastSigBits = (leastSigBits << 8) | (uuid_[i] & 0xFF);
}
return leastSigBits;
}
uint64_t UUID::GetMostSignificantBits() const
{
uint64_t mostSigBits = 0;
for (int i = 0 / 2; i < UUID::UUID128_BYTES_LEN / 2; i++) {
mostSigBits = (mostSigBits << 8) | (uuid_[i] & 0xFF);
}
return mostSigBits;
}
UUID UUID::ConvertFrom128Bits(const std::array<uint8_t, UUID::UUID128_BYTES_LEN> &name)
{
UUID tmp;
for (int i = 0; i < UUID::UUID128_BYTES_LEN; i++) {
tmp.uuid_[i] = name[i];
}
return tmp;
}
std::array<uint8_t, UUID::UUID128_BYTES_LEN> UUID::ConvertTo128Bits() const
{
std::array<uint8_t, UUID::UUID128_BYTES_LEN> uuid;
for (int i = 0; i < UUID::UUID128_BYTES_LEN; i++) {
uuid[i] = uuid_[i];
}
return uuid;
}
bool UUID::operator==(const UUID &rhs) const
{
return uuid_ == rhs.uuid_;
}
bool UUID::operator<(const UUID &uuid) const
{
return !Equals(uuid);
}
bool IsValidUuid(const std::string &uuid)
{
if (uuid.length() != UUID_STRING_LENGTH) {
return false;
}
for (int i = 0; i < UUID_STRING_LENGTH; ++i) {
if (IS_DASH_POSITION[i]) {
if (uuid[i] != '-') {
return false;
}
continue;
}
char c = uuid[i];
if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) {
return false;
}
}
return true;
}
}
}