/src/CMake/Source/cmUuid.cxx
Line | Count | Source |
1 | | /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
2 | | file LICENSE.rst or https://cmake.org/licensing for details. */ |
3 | | #include "cmUuid.h" |
4 | | |
5 | | #include <array> |
6 | | #include <cstring> |
7 | | |
8 | | #include "cmCryptoHash.h" |
9 | | |
10 | | static std::array<int, 5> const kUuidGroups = { { 4, 2, 2, 2, 6 } }; |
11 | | |
12 | | std::string cmUuid::FromMd5(std::vector<unsigned char> const& uuidNamespace, |
13 | | cm::string_view name) const |
14 | 0 | { |
15 | 0 | std::vector<unsigned char> hashInput; |
16 | 0 | this->CreateHashInput(uuidNamespace, name, hashInput); |
17 | |
|
18 | 0 | cmCryptoHash md5(cmCryptoHash::AlgoMD5); |
19 | 0 | md5.Initialize(); |
20 | 0 | md5.Append(hashInput.data(), hashInput.size()); |
21 | 0 | std::vector<unsigned char> digest = md5.Finalize(); |
22 | |
|
23 | 0 | return this->FromDigest(digest.data(), 3); |
24 | 0 | } |
25 | | |
26 | | std::string cmUuid::FromSha1(std::vector<unsigned char> const& uuidNamespace, |
27 | | cm::string_view name) const |
28 | 0 | { |
29 | 0 | std::vector<unsigned char> hashInput; |
30 | 0 | this->CreateHashInput(uuidNamespace, name, hashInput); |
31 | |
|
32 | 0 | cmCryptoHash sha1(cmCryptoHash::AlgoSHA1); |
33 | 0 | sha1.Initialize(); |
34 | 0 | sha1.Append(hashInput.data(), hashInput.size()); |
35 | 0 | std::vector<unsigned char> digest = sha1.Finalize(); |
36 | |
|
37 | 0 | return this->FromDigest(digest.data(), 5); |
38 | 0 | } |
39 | | |
40 | | void cmUuid::CreateHashInput(std::vector<unsigned char> const& uuidNamespace, |
41 | | cm::string_view name, |
42 | | std::vector<unsigned char>& output) const |
43 | 0 | { |
44 | 0 | output = uuidNamespace; |
45 | |
|
46 | 0 | if (!name.empty()) { |
47 | 0 | output.resize(output.size() + name.size()); |
48 | |
|
49 | 0 | memcpy(output.data() + uuidNamespace.size(), name.data(), name.size()); |
50 | 0 | } |
51 | 0 | } |
52 | | |
53 | | std::string cmUuid::FromDigest(unsigned char const* digest, |
54 | | unsigned char version) const |
55 | 0 | { |
56 | 0 | using byte_t = unsigned char; |
57 | |
|
58 | 0 | byte_t uuid[16] = { 0 }; |
59 | 0 | memcpy(uuid, digest, 16); |
60 | |
|
61 | 0 | uuid[6] &= 0xF; |
62 | 0 | uuid[6] |= static_cast<byte_t>(version << 4); |
63 | |
|
64 | 0 | uuid[8] &= 0x3F; |
65 | 0 | uuid[8] |= 0x80; |
66 | |
|
67 | 0 | return this->BinaryToString(uuid); |
68 | 0 | } |
69 | | |
70 | | bool cmUuid::StringToBinary(cm::string_view input, |
71 | | std::vector<unsigned char>& output) const |
72 | 0 | { |
73 | 0 | output.clear(); |
74 | 0 | output.reserve(16); |
75 | |
|
76 | 0 | if (input.length() != 36) { |
77 | 0 | return false; |
78 | 0 | } |
79 | 0 | size_t index = 0; |
80 | 0 | for (size_t i = 0; i < kUuidGroups.size(); ++i) { |
81 | 0 | if (i != 0 && input[index++] != '-') { |
82 | 0 | return false; |
83 | 0 | } |
84 | 0 | size_t digits = kUuidGroups[i] * 2; |
85 | 0 | if (!this->StringToBinaryImpl(input.substr(index, digits), output)) { |
86 | 0 | return false; |
87 | 0 | } |
88 | | |
89 | 0 | index += digits; |
90 | 0 | } |
91 | | |
92 | 0 | return true; |
93 | 0 | } |
94 | | |
95 | | std::string cmUuid::BinaryToString(unsigned char const* input) const |
96 | 0 | { |
97 | 0 | std::string output; |
98 | |
|
99 | 0 | size_t inputIndex = 0; |
100 | 0 | for (size_t i = 0; i < kUuidGroups.size(); ++i) { |
101 | 0 | if (i != 0) { |
102 | 0 | output += '-'; |
103 | 0 | } |
104 | |
|
105 | 0 | size_t bytes = kUuidGroups[i]; |
106 | 0 | for (size_t j = 0; j < bytes; ++j) { |
107 | 0 | unsigned char inputByte = input[inputIndex++]; |
108 | 0 | output += this->ByteToHex(inputByte); |
109 | 0 | } |
110 | 0 | } |
111 | |
|
112 | 0 | return output; |
113 | 0 | } |
114 | | |
115 | | std::string cmUuid::ByteToHex(unsigned char inputByte) const |
116 | 0 | { |
117 | 0 | std::string result(" "); |
118 | 0 | for (int i = 0; i < 2; ++i) { |
119 | 0 | unsigned char rest = inputByte % 16; |
120 | 0 | inputByte /= 16; |
121 | 0 | char c = (rest < 0xA) ? static_cast<char>('0' + rest) |
122 | 0 | : static_cast<char>('a' + (rest - 0xA)); |
123 | 0 | result.at(1 - i) = c; |
124 | 0 | } |
125 | |
|
126 | 0 | return result; |
127 | 0 | } |
128 | | |
129 | | bool cmUuid::StringToBinaryImpl(cm::string_view input, |
130 | | std::vector<unsigned char>& output) const |
131 | 0 | { |
132 | 0 | if (input.size() % 2) { |
133 | 0 | return false; |
134 | 0 | } |
135 | | |
136 | 0 | for (size_t i = 0; i < input.size(); i += 2) { |
137 | 0 | char c1 = 0; |
138 | 0 | if (!this->IntFromHexDigit(input[i], c1)) { |
139 | 0 | return false; |
140 | 0 | } |
141 | | |
142 | 0 | char c2 = 0; |
143 | 0 | if (!this->IntFromHexDigit(input[i + 1], c2)) { |
144 | 0 | return false; |
145 | 0 | } |
146 | | |
147 | 0 | output.push_back(static_cast<char>(c1 << 4 | c2)); |
148 | 0 | } |
149 | | |
150 | 0 | return true; |
151 | 0 | } |
152 | | |
153 | | bool cmUuid::IntFromHexDigit(char input, char& output) const |
154 | 0 | { |
155 | 0 | if (input >= '0' && input <= '9') { |
156 | 0 | output = static_cast<char>(input - '0'); |
157 | 0 | return true; |
158 | 0 | } |
159 | 0 | if (input >= 'a' && input <= 'f') { |
160 | 0 | output = static_cast<char>(input - 'a' + 0xA); |
161 | 0 | return true; |
162 | 0 | } |
163 | 0 | if (input >= 'A' && input <= 'F') { |
164 | 0 | output = static_cast<char>(input - 'A' + 0xA); |
165 | 0 | return true; |
166 | 0 | } |
167 | 0 | return false; |
168 | 0 | } |