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