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(Value&: debug_info.Uuid.Data1); |
40 | llvm::sys::swapByteOrder(Value&: debug_info.Uuid.Data2); |
41 | llvm::sys::swapByteOrder(Value&: debug_info.Uuid.Data3); |
42 | llvm::sys::swapByteOrder(Value&: 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(First: GetBytes())) { |
54 | if (separate(count: B.index())) |
55 | os << separator; |
56 | |
57 | os << llvm::format_hex_no_prefix(N: B.value(), Width: 2, Upper: true); |
58 | } |
59 | os.flush(); |
60 | |
61 | return result; |
62 | } |
63 | |
64 | void UUID::Dump(Stream &s) const { s.PutCString(cstr: GetAsString()); } |
65 | |
66 | static inline int xdigit_to_int(char ch) { |
67 | ch = tolower(c: 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(ch: p[0]); |
80 | int lo_nibble = xdigit_to_int(ch: p[1]); |
81 | // Translate the two hex nibble characters into a byte |
82 | uuid_bytes.push_back(Elt: (hi_nibble << 4) + lo_nibble); |
83 | |
84 | // Skip both hex digits |
85 | p = p.drop_front(N: 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, uuid_bytes&: 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 |