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