/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmUuid.h" #include #include #include "cmCryptoHash.h" static const std::array kUuidGroups = { { 4, 2, 2, 2, 6 } }; std::string cmUuid::FromMd5(std::vector const& uuidNamespace, std::string const& name) const { std::vector hashInput; this->CreateHashInput(uuidNamespace, name, hashInput); cmCryptoHash md5(cmCryptoHash::AlgoMD5); md5.Initialize(); md5.Append(hashInput.data(), hashInput.size()); std::vector digest = md5.Finalize(); return this->FromDigest(digest.data(), 3); } std::string cmUuid::FromSha1(std::vector const& uuidNamespace, std::string const& name) const { std::vector hashInput; this->CreateHashInput(uuidNamespace, name, hashInput); cmCryptoHash sha1(cmCryptoHash::AlgoSHA1); sha1.Initialize(); sha1.Append(hashInput.data(), hashInput.size()); std::vector digest = sha1.Finalize(); return this->FromDigest(digest.data(), 5); } void cmUuid::CreateHashInput(std::vector const& uuidNamespace, std::string const& name, std::vector& output) const { output = uuidNamespace; if (!name.empty()) { output.resize(output.size() + name.size()); memcpy(output.data() + uuidNamespace.size(), name.c_str(), name.size()); } } std::string cmUuid::FromDigest(const unsigned char* digest, unsigned char version) const { using byte_t = unsigned char; byte_t uuid[16] = { 0 }; memcpy(uuid, digest, 16); uuid[6] &= 0xF; uuid[6] |= static_cast(version << 4); uuid[8] &= 0x3F; uuid[8] |= 0x80; return this->BinaryToString(uuid); } bool cmUuid::StringToBinary(std::string const& input, std::vector& output) const { output.clear(); output.reserve(16); if (input.length() != 36) { return false; } size_t index = 0; for (size_t i = 0; i < kUuidGroups.size(); ++i) { if (i != 0 && input[index++] != '-') { return false; } size_t digits = kUuidGroups[i] * 2; if (!this->StringToBinaryImpl(input.substr(index, digits), output)) { return false; } index += digits; } return true; } std::string cmUuid::BinaryToString(const unsigned char* input) const { std::string output; size_t inputIndex = 0; for (size_t i = 0; i < kUuidGroups.size(); ++i) { if (i != 0) { output += '-'; } size_t bytes = kUuidGroups[i]; for (size_t j = 0; j < bytes; ++j) { unsigned char byte = input[inputIndex++]; output += this->ByteToHex(byte); } } return output; } std::string cmUuid::ByteToHex(unsigned char byte) const { std::string result(" "); for (int i = 0; i < 2; ++i) { unsigned char rest = byte % 16; byte /= 16; char c = (rest < 0xA) ? static_cast('0' + rest) : static_cast('a' + (rest - 0xA)); result.at(1 - i) = c; } return result; } bool cmUuid::StringToBinaryImpl(std::string const& input, std::vector& output) const { if (input.size() % 2) { return false; } for (size_t i = 0; i < input.size(); i += 2) { char c1 = 0; if (!this->IntFromHexDigit(input[i], c1)) { return false; } char c2 = 0; if (!this->IntFromHexDigit(input[i + 1], c2)) { return false; } output.push_back(static_cast(c1 << 4 | c2)); } return true; } bool cmUuid::IntFromHexDigit(char input, char& output) const { if (input >= '0' && input <= '9') { output = static_cast(input - '0'); return true; } if (input >= 'a' && input <= 'f') { output = static_cast(input - 'a' + 0xA); return true; } if (input >= 'A' && input <= 'F') { output = static_cast(input - 'A' + 0xA); return true; } return false; }