* Copyright (c) Huawei Technologies Co., Ltd. 2022. All rights reserved.
*
* 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.
*/
* Description: Generator for uuid.
*/
#include "datasystem/common/util/uuid_generator.h"
#include <cstdint>
#include <cstdlib>
#include <iomanip>
#include <random>
#include <securec.h>
#include "datasystem/common/util/random_data.h"
#include "datasystem/common/log/log.h"
namespace datasystem {
std::string GetBytesUuid()
{
static thread_local std::mt19937 gen(RandomData::GetRandomSeed());
uint8_t random[UUID_SIZE];
std::uniform_int_distribution<> dist(0, UINT8_MAX);
for (size_t i = 0; i < UUID_SIZE; i++) {
random[i] = dist(gen);
}
random[UUID_VERSION_BYTEINDEX] &= 0x4F;
random[UUID_VERSION_BYTEINDEX] |= 0x40;
random[UUID_VARIANT_BYTEINDEX] &= 0xBF;
random[UUID_VARIANT_BYTEINDEX] |= 0x80;
return std::string(reinterpret_cast<char *>(random), sizeof(random));
}
std::string GetStringUuid()
{
return BytesUuidToString(GetBytesUuid());
}
std::string BytesUuidToString(const std::string &bytesUuid)
{
if (bytesUuid.size() != UUID_SIZE) {
DLOG(ERROR) << "Converting non-standard UUID, has length " << bytesUuid.size() << " skipping...";
return bytesUuid;
}
std::stringstream result;
result << std::setfill('0');
constexpr uint32_t hexWidth = 2;
auto *p = reinterpret_cast<const uint8_t *>(bytesUuid.data());
for (size_t i = 0; i < bytesUuid.size(); p++, i++) {
result << std::setw(hexWidth) << std::hex << +*p;
if (i == 3 || i == 5 || i == 7 || i == 9) {
result << "-";
}
}
return result.str();
}
Status IndexUuidGenerator(const uint64_t uuidNumber, std::string &stringUuid)
{
std::stringstream ss;
const auto dataLen4 = 4;
const auto dataLen12 = 12;
const uint64_t power16 = 10000000000000000;
const uint64_t power12 = 1000000000000;
const uint64_t power4 = 10000;
ss << "00000000-0000-" << std::setw(dataLen4) << std::setfill('0') << (uuidNumber / power16) << "-"
<< std::setw(dataLen4) << std::setfill('0') << (uuidNumber / power12 % power4) << "-" << std::setw(dataLen12)
<< std::setfill('0') << (uuidNumber % power12);
stringUuid = ss.str();
return Status::OK();
}
Status StringUuidToBytes(const std::string &stringUuid, std::string &byteUuid)
{
const auto inputLength = 36;
const auto four = 4;
const auto len16 = 16;
const auto offset8 = 8;
const auto offset13 = 13;
const auto offset18 = 18;
const auto offset23 = 23;
CHECK_FAIL_RETURN_STATUS(stringUuid.size() == inputLength, StatusCode::K_INVALID,
"The size of string uuid should be 36.");
char res[16];
auto inputOffset = 0;
auto outputOffset = 0;
bool shift = true;
uint8_t hi = 0;
uint8_t lo = 0;
const int diffLowerLetter = 0x57;
const int diffUpperLetter = 0x37;
while (inputOffset < inputLength) {
if (stringUuid[inputOffset] >= '0' && stringUuid[inputOffset] <= '9') {
lo = stringUuid[inputOffset] - '0';
} else if (stringUuid[inputOffset] >= 'a' && stringUuid[inputOffset] <= 'f') {
lo = stringUuid[inputOffset] - diffLowerLetter;
} else if (stringUuid[inputOffset] >= 'A' && stringUuid[inputOffset] <= 'F') {
lo = stringUuid[inputOffset] - diffUpperLetter;
} else {
RETURN_STATUS(StatusCode::K_INVALID, "Invalid input character");
}
if (shift) {
hi = lo << four;
shift = false;
} else {
res[outputOffset] = hi + lo;
++outputOffset;
shift = true;
}
++inputOffset;
if (inputOffset == offset8 || inputOffset == offset13 || inputOffset == offset18 || inputOffset == offset23) {
++inputOffset;
shift = true;
}
}
byteUuid = std::string(res, len16);
return Status::OK();
}
}