1 //===-- UUID.cpp ----------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "lldb/Utility/UUID.h"
10 
11 #include "lldb/Utility/Stream.h"
12 #include "llvm/ADT/StringRef.h"
13 #include "llvm/Support/Format.h"
14 
15 #include <cctype>
16 #include <cstdio>
17 #include <cstring>
18 
19 using namespace lldb_private;
20 
21 // Whether to put a separator after count uuid bytes.
22 // For the first 16 bytes we follow the traditional UUID format. After that, we
23 // simply put a dash after every 6 bytes.
24 static inline bool separate(size_t count) {
25   if (count >= 10)
26     return (count - 10) % 6 == 0;
27 
28   switch (count) {
29   case 4:
30   case 6:
31   case 8:
32     return true;
33   default:
34     return false;
35   }
36 }
37 
38 UUID::UUID(UUID::CvRecordPdb70 debug_info) {
39   llvm::sys::swapByteOrder(debug_info.Uuid.Data1);
40   llvm::sys::swapByteOrder(debug_info.Uuid.Data2);
41   llvm::sys::swapByteOrder(debug_info.Uuid.Data3);
42   llvm::sys::swapByteOrder(debug_info.Age);
43   if (debug_info.Age)
44     *this = UUID(&debug_info, sizeof(debug_info));
45   else
46     *this = UUID(&debug_info.Uuid, sizeof(debug_info.Uuid));
47 }
48 
49 std::string UUID::GetAsString(llvm::StringRef separator) const {
50   std::string result;
51   llvm::raw_string_ostream os(result);
52 
53   for (auto B : llvm::enumerate(GetBytes())) {
54     if (separate(B.index()))
55       os << separator;
56 
57     os << llvm::format_hex_no_prefix(B.value(), 2, true);
58   }
59   os.flush();
60 
61   return result;
62 }
63 
64 void UUID::Dump(Stream &s) const { s.PutCString(GetAsString()); }
65 
66 static inline int xdigit_to_int(char ch) {
67   ch = tolower(ch);
68   if (ch >= 'a' && ch <= 'f')
69     return 10 + ch - 'a';
70   return ch - '0';
71 }
72 
73 llvm::StringRef
74 UUID::DecodeUUIDBytesFromString(llvm::StringRef p,
75                                 llvm::SmallVectorImpl<uint8_t> &uuid_bytes) {
76   uuid_bytes.clear();
77   while (p.size() >= 2) {
78     if (isxdigit(p[0]) && isxdigit(p[1])) {
79       int hi_nibble = xdigit_to_int(p[0]);
80       int lo_nibble = xdigit_to_int(p[1]);
81       // Translate the two hex nibble characters into a byte
82       uuid_bytes.push_back((hi_nibble << 4) + lo_nibble);
83 
84       // Skip both hex digits
85       p = p.drop_front(2);
86     } else if (p.front() == '-') {
87       // Skip dashes
88       p = p.drop_front();
89     } else {
90       // UUID values can only consist of hex characters and '-' chars
91       break;
92     }
93   }
94   return p;
95 }
96 
97 bool UUID::SetFromStringRef(llvm::StringRef str) {
98   llvm::StringRef p = str;
99 
100   // Skip leading whitespace characters
101   p = p.ltrim();
102 
103   llvm::SmallVector<uint8_t, 20> bytes;
104   llvm::StringRef rest = UUID::DecodeUUIDBytesFromString(p, bytes);
105 
106   // Return false if we could not consume the entire string or if the parsed
107   // UUID is empty.
108   if (!rest.empty() || bytes.empty())
109     return false;
110 
111   *this = UUID(bytes);
112   return true;
113 }
114