180814287SRaphael Isemann //===-- UUID.cpp ----------------------------------------------------------===//
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 
15*76e47d48SRaphael Isemann #include <cctype>
16*76e47d48SRaphael Isemann #include <cstdio>
17*76e47d48SRaphael Isemann #include <cstring>
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.
separate(size_t count)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 
fromCvRecord(UUID::CvRecordPdb70 debug_info)384348e0eeSZequan Wu UUID UUID::fromCvRecord(UUID::CvRecordPdb70 debug_info) {
394348e0eeSZequan Wu   llvm::sys::swapByteOrder(debug_info.Uuid.Data1);
404348e0eeSZequan Wu   llvm::sys::swapByteOrder(debug_info.Uuid.Data2);
414348e0eeSZequan Wu   llvm::sys::swapByteOrder(debug_info.Uuid.Data3);
424348e0eeSZequan Wu   llvm::sys::swapByteOrder(debug_info.Age);
434348e0eeSZequan Wu   if (debug_info.Age)
444348e0eeSZequan Wu     return UUID::fromOptionalData(&debug_info, sizeof(debug_info));
454348e0eeSZequan Wu   return UUID::fromOptionalData(&debug_info.Uuid, sizeof(debug_info.Uuid));
464348e0eeSZequan Wu }
474348e0eeSZequan Wu 
GetAsString(llvm::StringRef separator) const4877c397f4SPavel Labath std::string UUID::GetAsString(llvm::StringRef separator) const {
490e1d52aeSZachary Turner   std::string result;
5077c397f4SPavel Labath   llvm::raw_string_ostream os(result);
5177c397f4SPavel Labath 
5277c397f4SPavel Labath   for (auto B : llvm::enumerate(GetBytes())) {
5377c397f4SPavel Labath     if (separate(B.index()))
5477c397f4SPavel Labath       os << separator;
5577c397f4SPavel Labath 
5677c397f4SPavel Labath     os << llvm::format_hex_no_prefix(B.value(), 2, true);
570e1d52aeSZachary Turner   }
5877c397f4SPavel Labath   os.flush();
5977c397f4SPavel Labath 
600e1d52aeSZachary Turner   return result;
610e1d52aeSZachary Turner }
620e1d52aeSZachary Turner 
Dump(Stream * s) const6365e5e278SJonas Devlieghere void UUID::Dump(Stream *s) const { s->PutCString(GetAsString()); }
640e1d52aeSZachary Turner 
xdigit_to_int(char ch)650e1d52aeSZachary Turner static inline int xdigit_to_int(char ch) {
660e1d52aeSZachary Turner   ch = tolower(ch);
670e1d52aeSZachary Turner   if (ch >= 'a' && ch <= 'f')
680e1d52aeSZachary Turner     return 10 + ch - 'a';
690e1d52aeSZachary Turner   return ch - '0';
700e1d52aeSZachary Turner }
710e1d52aeSZachary Turner 
7277c397f4SPavel Labath llvm::StringRef
DecodeUUIDBytesFromString(llvm::StringRef p,llvm::SmallVectorImpl<uint8_t> & uuid_bytes)7377c397f4SPavel Labath UUID::DecodeUUIDBytesFromString(llvm::StringRef p,
741beffc18SJaroslav Sevcik                                 llvm::SmallVectorImpl<uint8_t> &uuid_bytes) {
7577c397f4SPavel Labath   uuid_bytes.clear();
761beffc18SJaroslav Sevcik   while (p.size() >= 2) {
770e1d52aeSZachary Turner     if (isxdigit(p[0]) && isxdigit(p[1])) {
780e1d52aeSZachary Turner       int hi_nibble = xdigit_to_int(p[0]);
790e1d52aeSZachary Turner       int lo_nibble = xdigit_to_int(p[1]);
800e1d52aeSZachary Turner       // Translate the two hex nibble characters into a byte
8177c397f4SPavel Labath       uuid_bytes.push_back((hi_nibble << 4) + lo_nibble);
820e1d52aeSZachary Turner 
830e1d52aeSZachary Turner       // Skip both hex digits
840e1d52aeSZachary Turner       p = p.drop_front(2);
850e1d52aeSZachary Turner     } else if (p.front() == '-') {
860e1d52aeSZachary Turner       // Skip dashes
870e1d52aeSZachary Turner       p = p.drop_front();
880e1d52aeSZachary Turner     } else {
890e1d52aeSZachary Turner       // UUID values can only consist of hex characters and '-' chars
900e1d52aeSZachary Turner       break;
910e1d52aeSZachary Turner     }
920e1d52aeSZachary Turner   }
930e1d52aeSZachary Turner   return p;
940e1d52aeSZachary Turner }
950e1d52aeSZachary Turner 
SetFromStringRef(llvm::StringRef str)961beffc18SJaroslav Sevcik bool UUID::SetFromStringRef(llvm::StringRef str) {
972833321fSZachary Turner   llvm::StringRef p = str;
980e1d52aeSZachary Turner 
990e1d52aeSZachary Turner   // Skip leading whitespace characters
1000e1d52aeSZachary Turner   p = p.ltrim();
1010e1d52aeSZachary Turner 
10277c397f4SPavel Labath   llvm::SmallVector<uint8_t, 20> bytes;
1031beffc18SJaroslav Sevcik   llvm::StringRef rest = UUID::DecodeUUIDBytesFromString(p, bytes);
1040e1d52aeSZachary Turner 
1051beffc18SJaroslav Sevcik   // Return false if we could not consume the entire string or if the parsed
1061beffc18SJaroslav Sevcik   // UUID is empty.
1071beffc18SJaroslav Sevcik   if (!rest.empty() || bytes.empty())
1081beffc18SJaroslav Sevcik     return false;
1091beffc18SJaroslav Sevcik 
11077c397f4SPavel Labath   *this = fromData(bytes);
1111beffc18SJaroslav Sevcik   return true;
1120e1d52aeSZachary Turner }
1130e1d52aeSZachary Turner 
SetFromOptionalStringRef(llvm::StringRef str)1141beffc18SJaroslav Sevcik bool UUID::SetFromOptionalStringRef(llvm::StringRef str) {
1151beffc18SJaroslav Sevcik   bool result = SetFromStringRef(str);
1161beffc18SJaroslav Sevcik   if (result) {
117f3ecbfc1SJim Ingham     if (llvm::all_of(m_bytes, [](uint8_t b) { return b == 0; }))
118f3ecbfc1SJim Ingham         Clear();
119f3ecbfc1SJim Ingham   }
120f3ecbfc1SJim Ingham 
1211beffc18SJaroslav Sevcik   return result;
122f3ecbfc1SJim Ingham }
123