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 <ctype.h>
16 #include <stdio.h>
17 #include <string.h>
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.
separate(size_t count)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
fromCvRecord(UUID::CvRecordPdb70 debug_info)38 UUID UUID::fromCvRecord(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 return UUID::fromOptionalData(&debug_info, sizeof(debug_info));
45 return UUID::fromOptionalData(&debug_info.Uuid, sizeof(debug_info.Uuid));
46 }
47
GetAsString(llvm::StringRef separator) const48 std::string UUID::GetAsString(llvm::StringRef separator) const {
49 std::string result;
50 llvm::raw_string_ostream os(result);
51
52 for (auto B : llvm::enumerate(GetBytes())) {
53 if (separate(B.index()))
54 os << separator;
55
56 os << llvm::format_hex_no_prefix(B.value(), 2, true);
57 }
58 os.flush();
59
60 return result;
61 }
62
Dump(Stream * s) const63 void UUID::Dump(Stream *s) const { s->PutCString(GetAsString()); }
64
xdigit_to_int(char ch)65 static inline int xdigit_to_int(char ch) {
66 ch = tolower(ch);
67 if (ch >= 'a' && ch <= 'f')
68 return 10 + ch - 'a';
69 return ch - '0';
70 }
71
72 llvm::StringRef
DecodeUUIDBytesFromString(llvm::StringRef p,llvm::SmallVectorImpl<uint8_t> & uuid_bytes)73 UUID::DecodeUUIDBytesFromString(llvm::StringRef p,
74 llvm::SmallVectorImpl<uint8_t> &uuid_bytes) {
75 uuid_bytes.clear();
76 while (p.size() >= 2) {
77 if (isxdigit(p[0]) && isxdigit(p[1])) {
78 int hi_nibble = xdigit_to_int(p[0]);
79 int lo_nibble = xdigit_to_int(p[1]);
80 // Translate the two hex nibble characters into a byte
81 uuid_bytes.push_back((hi_nibble << 4) + lo_nibble);
82
83 // Skip both hex digits
84 p = p.drop_front(2);
85 } else if (p.front() == '-') {
86 // Skip dashes
87 p = p.drop_front();
88 } else {
89 // UUID values can only consist of hex characters and '-' chars
90 break;
91 }
92 }
93 return p;
94 }
95
SetFromStringRef(llvm::StringRef str)96 bool UUID::SetFromStringRef(llvm::StringRef str) {
97 llvm::StringRef p = str;
98
99 // Skip leading whitespace characters
100 p = p.ltrim();
101
102 llvm::SmallVector<uint8_t, 20> bytes;
103 llvm::StringRef rest = UUID::DecodeUUIDBytesFromString(p, bytes);
104
105 // Return false if we could not consume the entire string or if the parsed
106 // UUID is empty.
107 if (!rest.empty() || bytes.empty())
108 return false;
109
110 *this = fromData(bytes);
111 return true;
112 }
113
SetFromOptionalStringRef(llvm::StringRef str)114 bool UUID::SetFromOptionalStringRef(llvm::StringRef str) {
115 bool result = SetFromStringRef(str);
116 if (result) {
117 if (llvm::all_of(m_bytes, [](uint8_t b) { return b == 0; }))
118 Clear();
119 }
120
121 return result;
122 }
123