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