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. 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 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 53 void UUID::Dump(Stream *s) const { s->PutCString(GetAsString()); } 54 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 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 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 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