| /* 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 <array> |
| #include <cstring> |
| |
| #include "cmCryptoHash.h" |
| |
| static const std::array<int, 5> 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(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<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(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 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; |
| } |