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