| //===-- UUID.cpp ----------------------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "lldb/Utility/UUID.h" |
| |
| #include "lldb/Utility/Stream.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/Support/Format.h" |
| |
| #include <cctype> |
| #include <cstdio> |
| #include <cstring> |
| |
| using namespace lldb_private; |
| |
| // Whether to put a separator after count uuid bytes. |
| // For the first 16 bytes we follow the traditional UUID format. After that, we |
| // simply put a dash after every 6 bytes. |
| static inline bool separate(size_t count) { |
| if (count >= 10) |
| return (count - 10) % 6 == 0; |
| |
| switch (count) { |
| case 4: |
| case 6: |
| case 8: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| UUID UUID::fromCvRecord(UUID::CvRecordPdb70 debug_info) { |
| llvm::sys::swapByteOrder(debug_info.Uuid.Data1); |
| llvm::sys::swapByteOrder(debug_info.Uuid.Data2); |
| llvm::sys::swapByteOrder(debug_info.Uuid.Data3); |
| llvm::sys::swapByteOrder(debug_info.Age); |
| if (debug_info.Age) |
| return UUID::fromOptionalData(&debug_info, sizeof(debug_info)); |
| return UUID::fromOptionalData(&debug_info.Uuid, sizeof(debug_info.Uuid)); |
| } |
| |
| std::string UUID::GetAsString(llvm::StringRef separator) const { |
| std::string result; |
| llvm::raw_string_ostream os(result); |
| |
| for (auto B : llvm::enumerate(GetBytes())) { |
| if (separate(B.index())) |
| os << separator; |
| |
| os << llvm::format_hex_no_prefix(B.value(), 2, true); |
| } |
| os.flush(); |
| |
| return result; |
| } |
| |
| void UUID::Dump(Stream *s) const { s->PutCString(GetAsString()); } |
| |
| static inline int xdigit_to_int(char ch) { |
| ch = tolower(ch); |
| if (ch >= 'a' && ch <= 'f') |
| return 10 + ch - 'a'; |
| return ch - '0'; |
| } |
| |
| llvm::StringRef |
| UUID::DecodeUUIDBytesFromString(llvm::StringRef p, |
| llvm::SmallVectorImpl<uint8_t> &uuid_bytes) { |
| uuid_bytes.clear(); |
| while (p.size() >= 2) { |
| if (isxdigit(p[0]) && isxdigit(p[1])) { |
| int hi_nibble = xdigit_to_int(p[0]); |
| int lo_nibble = xdigit_to_int(p[1]); |
| // Translate the two hex nibble characters into a byte |
| uuid_bytes.push_back((hi_nibble << 4) + lo_nibble); |
| |
| // Skip both hex digits |
| p = p.drop_front(2); |
| } else if (p.front() == '-') { |
| // Skip dashes |
| p = p.drop_front(); |
| } else { |
| // UUID values can only consist of hex characters and '-' chars |
| break; |
| } |
| } |
| return p; |
| } |
| |
| bool UUID::SetFromStringRef(llvm::StringRef str) { |
| llvm::StringRef p = str; |
| |
| // Skip leading whitespace characters |
| p = p.ltrim(); |
| |
| llvm::SmallVector<uint8_t, 20> bytes; |
| llvm::StringRef rest = UUID::DecodeUUIDBytesFromString(p, bytes); |
| |
| // Return false if we could not consume the entire string or if the parsed |
| // UUID is empty. |
| if (!rest.empty() || bytes.empty()) |
| return false; |
| |
| *this = fromData(bytes); |
| return true; |
| } |
| |
| bool UUID::SetFromOptionalStringRef(llvm::StringRef str) { |
| bool result = SetFromStringRef(str); |
| if (result) { |
| if (llvm::all_of(m_bytes, [](uint8_t b) { return b == 0; })) |
| Clear(); |
| } |
| |
| return result; |
| } |