10e1d52aeSZachary Turner //===-- UUID.cpp ------------------------------------------------*- C++ -*-===// 20e1d52aeSZachary Turner // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60e1d52aeSZachary Turner // 70e1d52aeSZachary Turner //===----------------------------------------------------------------------===// 80e1d52aeSZachary Turner 90e1d52aeSZachary Turner #include "lldb/Utility/UUID.h" 100e1d52aeSZachary Turner 11666cc0b2SZachary Turner #include "lldb/Utility/Stream.h" 12666cc0b2SZachary Turner #include "llvm/ADT/StringRef.h" 1377c397f4SPavel Labath #include "llvm/Support/Format.h" 14666cc0b2SZachary Turner 150e1d52aeSZachary Turner #include <ctype.h> 160e1d52aeSZachary Turner #include <stdio.h> 170e1d52aeSZachary Turner #include <string.h> 180e1d52aeSZachary Turner 19a174bcbfSPavel Labath using namespace lldb_private; 200e1d52aeSZachary Turner 2177c397f4SPavel Labath // Whether to put a separator after count uuid bytes. 2277c397f4SPavel Labath // For the first 16 bytes we follow the traditional UUID format. After that, we 2377c397f4SPavel Labath // simply put a dash after every 6 bytes. 2477c397f4SPavel Labath static inline bool separate(size_t count) { 2577c397f4SPavel Labath if (count >= 10) 2677c397f4SPavel Labath return (count - 10) % 6 == 0; 270e1d52aeSZachary Turner 2877c397f4SPavel Labath switch (count) { 2977c397f4SPavel Labath case 4: 3077c397f4SPavel Labath case 6: 3177c397f4SPavel Labath case 8: 3277c397f4SPavel Labath return true; 3377c397f4SPavel Labath default: 3477c397f4SPavel Labath return false; 3577c397f4SPavel Labath } 360e1d52aeSZachary Turner } 370e1d52aeSZachary Turner 3877c397f4SPavel Labath std::string UUID::GetAsString(llvm::StringRef separator) const { 390e1d52aeSZachary Turner std::string result; 4077c397f4SPavel Labath llvm::raw_string_ostream os(result); 4177c397f4SPavel Labath 4277c397f4SPavel Labath for (auto B : llvm::enumerate(GetBytes())) { 4377c397f4SPavel Labath if (separate(B.index())) 4477c397f4SPavel Labath os << separator; 4577c397f4SPavel Labath 4677c397f4SPavel Labath os << llvm::format_hex_no_prefix(B.value(), 2, true); 470e1d52aeSZachary Turner } 4877c397f4SPavel Labath os.flush(); 4977c397f4SPavel Labath 500e1d52aeSZachary Turner return result; 510e1d52aeSZachary Turner } 520e1d52aeSZachary Turner 5365e5e278SJonas Devlieghere void UUID::Dump(Stream *s) const { s->PutCString(GetAsString()); } 540e1d52aeSZachary Turner 550e1d52aeSZachary Turner static inline int xdigit_to_int(char ch) { 560e1d52aeSZachary Turner ch = tolower(ch); 570e1d52aeSZachary Turner if (ch >= 'a' && ch <= 'f') 580e1d52aeSZachary Turner return 10 + ch - 'a'; 590e1d52aeSZachary Turner return ch - '0'; 600e1d52aeSZachary Turner } 610e1d52aeSZachary Turner 6277c397f4SPavel Labath llvm::StringRef 6377c397f4SPavel Labath UUID::DecodeUUIDBytesFromString(llvm::StringRef p, 6477c397f4SPavel Labath llvm::SmallVectorImpl<uint8_t> &uuid_bytes, 650e1d52aeSZachary Turner uint32_t num_uuid_bytes) { 6677c397f4SPavel Labath uuid_bytes.clear(); 670e1d52aeSZachary Turner while (!p.empty()) { 680e1d52aeSZachary Turner if (isxdigit(p[0]) && isxdigit(p[1])) { 690e1d52aeSZachary Turner int hi_nibble = xdigit_to_int(p[0]); 700e1d52aeSZachary Turner int lo_nibble = xdigit_to_int(p[1]); 710e1d52aeSZachary Turner // Translate the two hex nibble characters into a byte 7277c397f4SPavel Labath uuid_bytes.push_back((hi_nibble << 4) + lo_nibble); 730e1d52aeSZachary Turner 740e1d52aeSZachary Turner // Skip both hex digits 750e1d52aeSZachary Turner p = p.drop_front(2); 760e1d52aeSZachary Turner 7705097246SAdrian Prantl // Increment the byte that we are decoding within the UUID value and 7805097246SAdrian Prantl // break out if we are done 7977c397f4SPavel Labath if (uuid_bytes.size() == num_uuid_bytes) 800e1d52aeSZachary Turner break; 810e1d52aeSZachary Turner } else if (p.front() == '-') { 820e1d52aeSZachary Turner // Skip dashes 830e1d52aeSZachary Turner p = p.drop_front(); 840e1d52aeSZachary Turner } else { 850e1d52aeSZachary Turner // UUID values can only consist of hex characters and '-' chars 860e1d52aeSZachary Turner break; 870e1d52aeSZachary Turner } 880e1d52aeSZachary Turner } 890e1d52aeSZachary Turner return p; 900e1d52aeSZachary Turner } 910e1d52aeSZachary Turner 922833321fSZachary Turner size_t UUID::SetFromStringRef(llvm::StringRef str, uint32_t num_uuid_bytes) { 932833321fSZachary Turner llvm::StringRef p = str; 940e1d52aeSZachary Turner 950e1d52aeSZachary Turner // Skip leading whitespace characters 960e1d52aeSZachary Turner p = p.ltrim(); 970e1d52aeSZachary Turner 9877c397f4SPavel Labath llvm::SmallVector<uint8_t, 20> bytes; 990e1d52aeSZachary Turner llvm::StringRef rest = 10077c397f4SPavel Labath UUID::DecodeUUIDBytesFromString(p, bytes, num_uuid_bytes); 1010e1d52aeSZachary Turner 1020e1d52aeSZachary Turner // If we successfully decoded a UUID, return the amount of characters that 1030e1d52aeSZachary Turner // were consumed 10477c397f4SPavel Labath if (bytes.size() == num_uuid_bytes) { 10577c397f4SPavel Labath *this = fromData(bytes); 1062833321fSZachary Turner return str.size() - rest.size(); 1070e1d52aeSZachary Turner } 1080e1d52aeSZachary Turner 1090e1d52aeSZachary Turner // Else return zero to indicate we were not able to parse a UUID value 1100e1d52aeSZachary Turner return 0; 1110e1d52aeSZachary Turner } 112*f3ecbfc1SJim Ingham 113*f3ecbfc1SJim Ingham size_t UUID::SetFromOptionalStringRef(llvm::StringRef str, 114*f3ecbfc1SJim Ingham uint32_t num_uuid_bytes) { 115*f3ecbfc1SJim Ingham size_t num_chars_consumed = SetFromStringRef(str, num_uuid_bytes); 116*f3ecbfc1SJim Ingham if (num_chars_consumed) { 117*f3ecbfc1SJim Ingham if (llvm::all_of(m_bytes, [](uint8_t b) { return b == 0; })) 118*f3ecbfc1SJim Ingham Clear(); 119*f3ecbfc1SJim Ingham } 120*f3ecbfc1SJim Ingham 121*f3ecbfc1SJim Ingham return num_chars_consumed; 122*f3ecbfc1SJim Ingham } 123*f3ecbfc1SJim Ingham 124