1 //===-- UUID.cpp ------------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/Utility/UUID.h"
11 
12 // Other libraries and framework includes
13 // Project includes
14 #include "lldb/Utility/Stream.h"
15 
16 #include "llvm/ADT/StringRef.h"
17 
18 // C Includes
19 #include <ctype.h>
20 #include <stdio.h>
21 #include <string.h>
22 
23 // C++ Includes
24 #include <string>
25 
26 namespace lldb_private {
27 
28 UUID::UUID() : m_num_uuid_bytes(16) { ::memset(m_uuid, 0, sizeof(m_uuid)); }
29 
30 UUID::UUID(const UUID &rhs) {
31   m_num_uuid_bytes = rhs.m_num_uuid_bytes;
32   ::memcpy(m_uuid, rhs.m_uuid, sizeof(m_uuid));
33 }
34 
35 UUID::UUID(const void *uuid_bytes, uint32_t num_uuid_bytes) {
36   SetBytes(uuid_bytes, num_uuid_bytes);
37 }
38 
39 const UUID &UUID::operator=(const UUID &rhs) {
40   if (this != &rhs) {
41     m_num_uuid_bytes = rhs.m_num_uuid_bytes;
42     ::memcpy(m_uuid, rhs.m_uuid, sizeof(m_uuid));
43   }
44   return *this;
45 }
46 
47 UUID::~UUID() {}
48 
49 void UUID::Clear() {
50   m_num_uuid_bytes = 16;
51   ::memset(m_uuid, 0, sizeof(m_uuid));
52 }
53 
54 const void *UUID::GetBytes() const { return m_uuid; }
55 
56 std::string UUID::GetAsString(const char *separator) const {
57   std::string result;
58   char buf[256];
59   if (!separator)
60     separator = "-";
61   const uint8_t *u = (const uint8_t *)GetBytes();
62   if (sizeof(buf) >
63       (size_t)snprintf(buf, sizeof(buf), "%2.2X%2.2X%2.2X%2.2X%s%2.2X%2.2X%s%2."
64                                          "2X%2.2X%s%2.2X%2.2X%s%2.2X%2.2X%2.2X%"
65                                          "2.2X%2.2X%2.2X",
66                        u[0], u[1], u[2], u[3], separator, u[4], u[5], separator,
67                        u[6], u[7], separator, u[8], u[9], separator, u[10],
68                        u[11], u[12], u[13], u[14], u[15])) {
69     result.append(buf);
70     if (m_num_uuid_bytes == 20) {
71       if (sizeof(buf) > (size_t)snprintf(buf, sizeof(buf),
72                                          "%s%2.2X%2.2X%2.2X%2.2X", separator,
73                                          u[16], u[17], u[18], u[19]))
74         result.append(buf);
75     }
76   }
77   return result;
78 }
79 
80 void UUID::Dump(Stream *s) const {
81   const uint8_t *u = (const uint8_t *)GetBytes();
82   s->Printf("%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X%"
83             "2.2X%2.2X%2.2X%2.2X",
84             u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7], u[8], u[9], u[10],
85             u[11], u[12], u[13], u[14], u[15]);
86   if (m_num_uuid_bytes == 20) {
87     s->Printf("-%2.2X%2.2X%2.2X%2.2X", u[16], u[17], u[18], u[19]);
88   }
89 }
90 
91 bool UUID::SetBytes(const void *uuid_bytes, uint32_t num_uuid_bytes) {
92   if (uuid_bytes) {
93     switch (num_uuid_bytes) {
94     case 20:
95       m_num_uuid_bytes = 20;
96       break;
97     case 16:
98       m_num_uuid_bytes = 16;
99       m_uuid[16] = m_uuid[17] = m_uuid[18] = m_uuid[19] = 0;
100       break;
101     default:
102       // Unsupported UUID byte size
103       m_num_uuid_bytes = 0;
104       break;
105     }
106 
107     if (m_num_uuid_bytes > 0) {
108       ::memcpy(m_uuid, uuid_bytes, m_num_uuid_bytes);
109       return true;
110     }
111   }
112   ::memset(m_uuid, 0, sizeof(m_uuid));
113   return false;
114 }
115 
116 size_t UUID::GetByteSize() { return m_num_uuid_bytes; }
117 
118 bool UUID::IsValid() const {
119   return m_uuid[0] || m_uuid[1] || m_uuid[2] || m_uuid[3] || m_uuid[4] ||
120          m_uuid[5] || m_uuid[6] || m_uuid[7] || m_uuid[8] || m_uuid[9] ||
121          m_uuid[10] || m_uuid[11] || m_uuid[12] || m_uuid[13] || m_uuid[14] ||
122          m_uuid[15] || m_uuid[16] || m_uuid[17] || m_uuid[18] || m_uuid[19];
123 }
124 
125 static inline int xdigit_to_int(char ch) {
126   ch = tolower(ch);
127   if (ch >= 'a' && ch <= 'f')
128     return 10 + ch - 'a';
129   return ch - '0';
130 }
131 
132 llvm::StringRef UUID::DecodeUUIDBytesFromString(llvm::StringRef p,
133                                                 ValueType &uuid_bytes,
134                                                 uint32_t &bytes_decoded,
135                                                 uint32_t num_uuid_bytes) {
136   ::memset(uuid_bytes, 0, sizeof(uuid_bytes));
137   size_t uuid_byte_idx = 0;
138   while (!p.empty()) {
139     if (isxdigit(p[0]) && isxdigit(p[1])) {
140       int hi_nibble = xdigit_to_int(p[0]);
141       int lo_nibble = xdigit_to_int(p[1]);
142       // Translate the two hex nibble characters into a byte
143       uuid_bytes[uuid_byte_idx] = (hi_nibble << 4) + lo_nibble;
144 
145       // Skip both hex digits
146       p = p.drop_front(2);
147 
148       // Increment the byte that we are decoding within the UUID value
149       // and break out if we are done
150       if (++uuid_byte_idx == num_uuid_bytes)
151         break;
152     } else if (p.front() == '-') {
153       // Skip dashes
154       p = p.drop_front();
155     } else {
156       // UUID values can only consist of hex characters and '-' chars
157       break;
158     }
159   }
160 
161   // Clear trailing bytes to 0.
162   for (uint32_t i = uuid_byte_idx; i < sizeof(ValueType); i++)
163     uuid_bytes[i] = 0;
164   bytes_decoded = uuid_byte_idx;
165   return p;
166 }
167 size_t UUID::SetFromCString(const char *cstr, uint32_t num_uuid_bytes) {
168   if (cstr == NULL)
169     return 0;
170 
171   llvm::StringRef orig(cstr);
172   llvm::StringRef p = orig;
173 
174   // Skip leading whitespace characters
175   p = p.ltrim();
176 
177   uint32_t bytes_decoded = 0;
178   llvm::StringRef rest =
179       UUID::DecodeUUIDBytesFromString(p, m_uuid, bytes_decoded, num_uuid_bytes);
180 
181   // If we successfully decoded a UUID, return the amount of characters that
182   // were consumed
183   if (bytes_decoded == num_uuid_bytes) {
184     m_num_uuid_bytes = num_uuid_bytes;
185     return orig.size() - rest.size();
186   }
187 
188   // Else return zero to indicate we were not able to parse a UUID value
189   return 0;
190 }
191 }
192 
193 bool lldb_private::operator==(const lldb_private::UUID &lhs,
194                               const lldb_private::UUID &rhs) {
195   return ::memcmp(lhs.GetBytes(), rhs.GetBytes(),
196                   sizeof(lldb_private::UUID::ValueType)) == 0;
197 }
198 
199 bool lldb_private::operator!=(const lldb_private::UUID &lhs,
200                               const lldb_private::UUID &rhs) {
201   return ::memcmp(lhs.GetBytes(), rhs.GetBytes(),
202                   sizeof(lldb_private::UUID::ValueType)) != 0;
203 }
204 
205 bool lldb_private::operator<(const lldb_private::UUID &lhs,
206                              const lldb_private::UUID &rhs) {
207   return ::memcmp(lhs.GetBytes(), rhs.GetBytes(),
208                   sizeof(lldb_private::UUID::ValueType)) < 0;
209 }
210 
211 bool lldb_private::operator<=(const lldb_private::UUID &lhs,
212                               const lldb_private::UUID &rhs) {
213   return ::memcmp(lhs.GetBytes(), rhs.GetBytes(),
214                   sizeof(lldb_private::UUID::ValueType)) <= 0;
215 }
216 
217 bool lldb_private::operator>(const lldb_private::UUID &lhs,
218                              const lldb_private::UUID &rhs) {
219   return ::memcmp(lhs.GetBytes(), rhs.GetBytes(),
220                   sizeof(lldb_private::UUID::ValueType)) > 0;
221 }
222 
223 bool lldb_private::operator>=(const lldb_private::UUID &lhs,
224                               const lldb_private::UUID &rhs) {
225   return ::memcmp(lhs.GetBytes(), rhs.GetBytes(),
226                   sizeof(lldb_private::UUID::ValueType)) >= 0;
227 }
228