Coverage Report

Created: 2026-03-12 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}