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