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