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