15ffd83dbSDimitry Andric //===-- UUID.cpp ----------------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "lldb/Utility/UUID.h"
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
120b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
130b57cec5SDimitry Andric #include "llvm/Support/Format.h"
140b57cec5SDimitry Andric 
15*5f7ddb14SDimitry Andric #include <cctype>
16*5f7ddb14SDimitry Andric #include <cstdio>
17*5f7ddb14SDimitry Andric #include <cstring>
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric using namespace lldb_private;
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric // Whether to put a separator after count uuid bytes.
220b57cec5SDimitry Andric // For the first 16 bytes we follow the traditional UUID format. After that, we
230b57cec5SDimitry Andric // simply put a dash after every 6 bytes.
separate(size_t count)240b57cec5SDimitry Andric static inline bool separate(size_t count) {
250b57cec5SDimitry Andric   if (count >= 10)
260b57cec5SDimitry Andric     return (count - 10) % 6 == 0;
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric   switch (count) {
290b57cec5SDimitry Andric   case 4:
300b57cec5SDimitry Andric   case 6:
310b57cec5SDimitry Andric   case 8:
320b57cec5SDimitry Andric     return true;
330b57cec5SDimitry Andric   default:
340b57cec5SDimitry Andric     return false;
350b57cec5SDimitry Andric   }
360b57cec5SDimitry Andric }
370b57cec5SDimitry Andric 
fromCvRecord(UUID::CvRecordPdb70 debug_info)38af732203SDimitry Andric UUID UUID::fromCvRecord(UUID::CvRecordPdb70 debug_info) {
39af732203SDimitry Andric   llvm::sys::swapByteOrder(debug_info.Uuid.Data1);
40af732203SDimitry Andric   llvm::sys::swapByteOrder(debug_info.Uuid.Data2);
41af732203SDimitry Andric   llvm::sys::swapByteOrder(debug_info.Uuid.Data3);
42af732203SDimitry Andric   llvm::sys::swapByteOrder(debug_info.Age);
43af732203SDimitry Andric   if (debug_info.Age)
44af732203SDimitry Andric     return UUID::fromOptionalData(&debug_info, sizeof(debug_info));
45af732203SDimitry Andric   return UUID::fromOptionalData(&debug_info.Uuid, sizeof(debug_info.Uuid));
46af732203SDimitry Andric }
47af732203SDimitry Andric 
GetAsString(llvm::StringRef separator) const480b57cec5SDimitry Andric std::string UUID::GetAsString(llvm::StringRef separator) const {
490b57cec5SDimitry Andric   std::string result;
500b57cec5SDimitry Andric   llvm::raw_string_ostream os(result);
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric   for (auto B : llvm::enumerate(GetBytes())) {
530b57cec5SDimitry Andric     if (separate(B.index()))
540b57cec5SDimitry Andric       os << separator;
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric     os << llvm::format_hex_no_prefix(B.value(), 2, true);
570b57cec5SDimitry Andric   }
580b57cec5SDimitry Andric   os.flush();
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric   return result;
610b57cec5SDimitry Andric }
620b57cec5SDimitry Andric 
Dump(Stream * s) const630b57cec5SDimitry Andric void UUID::Dump(Stream *s) const { s->PutCString(GetAsString()); }
640b57cec5SDimitry Andric 
xdigit_to_int(char ch)650b57cec5SDimitry Andric static inline int xdigit_to_int(char ch) {
660b57cec5SDimitry Andric   ch = tolower(ch);
670b57cec5SDimitry Andric   if (ch >= 'a' && ch <= 'f')
680b57cec5SDimitry Andric     return 10 + ch - 'a';
690b57cec5SDimitry Andric   return ch - '0';
700b57cec5SDimitry Andric }
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric llvm::StringRef
DecodeUUIDBytesFromString(llvm::StringRef p,llvm::SmallVectorImpl<uint8_t> & uuid_bytes)730b57cec5SDimitry Andric UUID::DecodeUUIDBytesFromString(llvm::StringRef p,
745ffd83dbSDimitry Andric                                 llvm::SmallVectorImpl<uint8_t> &uuid_bytes) {
750b57cec5SDimitry Andric   uuid_bytes.clear();
765ffd83dbSDimitry Andric   while (p.size() >= 2) {
770b57cec5SDimitry Andric     if (isxdigit(p[0]) && isxdigit(p[1])) {
780b57cec5SDimitry Andric       int hi_nibble = xdigit_to_int(p[0]);
790b57cec5SDimitry Andric       int lo_nibble = xdigit_to_int(p[1]);
800b57cec5SDimitry Andric       // Translate the two hex nibble characters into a byte
810b57cec5SDimitry Andric       uuid_bytes.push_back((hi_nibble << 4) + lo_nibble);
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric       // Skip both hex digits
840b57cec5SDimitry Andric       p = p.drop_front(2);
850b57cec5SDimitry Andric     } else if (p.front() == '-') {
860b57cec5SDimitry Andric       // Skip dashes
870b57cec5SDimitry Andric       p = p.drop_front();
880b57cec5SDimitry Andric     } else {
890b57cec5SDimitry Andric       // UUID values can only consist of hex characters and '-' chars
900b57cec5SDimitry Andric       break;
910b57cec5SDimitry Andric     }
920b57cec5SDimitry Andric   }
930b57cec5SDimitry Andric   return p;
940b57cec5SDimitry Andric }
950b57cec5SDimitry Andric 
SetFromStringRef(llvm::StringRef str)965ffd83dbSDimitry Andric bool UUID::SetFromStringRef(llvm::StringRef str) {
970b57cec5SDimitry Andric   llvm::StringRef p = str;
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric   // Skip leading whitespace characters
1000b57cec5SDimitry Andric   p = p.ltrim();
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric   llvm::SmallVector<uint8_t, 20> bytes;
1035ffd83dbSDimitry Andric   llvm::StringRef rest = UUID::DecodeUUIDBytesFromString(p, bytes);
1040b57cec5SDimitry Andric 
1055ffd83dbSDimitry Andric   // Return false if we could not consume the entire string or if the parsed
1065ffd83dbSDimitry Andric   // UUID is empty.
1075ffd83dbSDimitry Andric   if (!rest.empty() || bytes.empty())
1085ffd83dbSDimitry Andric     return false;
1095ffd83dbSDimitry Andric 
1100b57cec5SDimitry Andric   *this = fromData(bytes);
1115ffd83dbSDimitry Andric   return true;
1120b57cec5SDimitry Andric }
1130b57cec5SDimitry Andric 
SetFromOptionalStringRef(llvm::StringRef str)1145ffd83dbSDimitry Andric bool UUID::SetFromOptionalStringRef(llvm::StringRef str) {
1155ffd83dbSDimitry Andric   bool result = SetFromStringRef(str);
1165ffd83dbSDimitry Andric   if (result) {
1170b57cec5SDimitry Andric     if (llvm::all_of(m_bytes, [](uint8_t b) { return b == 0; }))
1180b57cec5SDimitry Andric         Clear();
1190b57cec5SDimitry Andric   }
1200b57cec5SDimitry Andric 
1215ffd83dbSDimitry Andric   return result;
1220b57cec5SDimitry Andric }
123