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