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