1 //===-- UUID.cpp ------------------------------------------------*- C++ -*-===//
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
GetAsString(llvm::StringRef separator) const38 std::string UUID::GetAsString(llvm::StringRef separator) const {
39 std::string result;
40 llvm::raw_string_ostream os(result);
41
42 for (auto B : llvm::enumerate(GetBytes())) {
43 if (separate(B.index()))
44 os << separator;
45
46 os << llvm::format_hex_no_prefix(B.value(), 2, true);
47 }
48 os.flush();
49
50 return result;
51 }
52
Dump(Stream * s) const53 void UUID::Dump(Stream *s) const { s->PutCString(GetAsString()); }
54
xdigit_to_int(char ch)55 static inline int xdigit_to_int(char ch) {
56 ch = tolower(ch);
57 if (ch >= 'a' && ch <= 'f')
58 return 10 + ch - 'a';
59 return ch - '0';
60 }
61
62 llvm::StringRef
DecodeUUIDBytesFromString(llvm::StringRef p,llvm::SmallVectorImpl<uint8_t> & uuid_bytes,uint32_t num_uuid_bytes)63 UUID::DecodeUUIDBytesFromString(llvm::StringRef p,
64 llvm::SmallVectorImpl<uint8_t> &uuid_bytes,
65 uint32_t num_uuid_bytes) {
66 uuid_bytes.clear();
67 while (!p.empty()) {
68 if (isxdigit(p[0]) && isxdigit(p[1])) {
69 int hi_nibble = xdigit_to_int(p[0]);
70 int lo_nibble = xdigit_to_int(p[1]);
71 // Translate the two hex nibble characters into a byte
72 uuid_bytes.push_back((hi_nibble << 4) + lo_nibble);
73
74 // Skip both hex digits
75 p = p.drop_front(2);
76
77 // Increment the byte that we are decoding within the UUID value and
78 // break out if we are done
79 if (uuid_bytes.size() == num_uuid_bytes)
80 break;
81 } else if (p.front() == '-') {
82 // Skip dashes
83 p = p.drop_front();
84 } else {
85 // UUID values can only consist of hex characters and '-' chars
86 break;
87 }
88 }
89 return p;
90 }
91
SetFromStringRef(llvm::StringRef str,uint32_t num_uuid_bytes)92 size_t UUID::SetFromStringRef(llvm::StringRef str, uint32_t num_uuid_bytes) {
93 llvm::StringRef p = str;
94
95 // Skip leading whitespace characters
96 p = p.ltrim();
97
98 llvm::SmallVector<uint8_t, 20> bytes;
99 llvm::StringRef rest =
100 UUID::DecodeUUIDBytesFromString(p, bytes, num_uuid_bytes);
101
102 // If we successfully decoded a UUID, return the amount of characters that
103 // were consumed
104 if (bytes.size() == num_uuid_bytes) {
105 *this = fromData(bytes);
106 return str.size() - rest.size();
107 }
108
109 // Else return zero to indicate we were not able to parse a UUID value
110 return 0;
111 }
112
SetFromOptionalStringRef(llvm::StringRef str,uint32_t num_uuid_bytes)113 size_t UUID::SetFromOptionalStringRef(llvm::StringRef str,
114 uint32_t num_uuid_bytes) {
115 size_t num_chars_consumed = SetFromStringRef(str, num_uuid_bytes);
116 if (num_chars_consumed) {
117 if (llvm::all_of(m_bytes, [](uint8_t b) { return b == 0; }))
118 Clear();
119 }
120
121 return num_chars_consumed;
122 }
123
124