1 //===-- UUID.cpp ------------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/Utility/UUID.h"
11 
12 #include "lldb/Utility/Stream.h"
13 #include "llvm/ADT/StringRef.h"
14 #include "llvm/Support/Format.h"
15 
16 #include <ctype.h>
17 #include <stdio.h>
18 #include <string.h>
19 
20 using namespace lldb_private;
21 
22 // Whether to put a separator after count uuid bytes.
23 // For the first 16 bytes we follow the traditional UUID format. After that, we
24 // simply put a dash after every 6 bytes.
25 static inline bool separate(size_t count) {
26   if (count >= 10)
27     return (count - 10) % 6 == 0;
28 
29   switch (count) {
30   case 4:
31   case 6:
32   case 8:
33     return true;
34   default:
35     return false;
36   }
37 }
38 
39 std::string UUID::GetAsString(llvm::StringRef separator) const {
40   std::string result;
41   llvm::raw_string_ostream os(result);
42 
43   for (auto B : llvm::enumerate(GetBytes())) {
44     if (separate(B.index()))
45       os << separator;
46 
47     os << llvm::format_hex_no_prefix(B.value(), 2, true);
48   }
49   os.flush();
50 
51   return result;
52 }
53 
54 void UUID::Dump(Stream *s) const {
55   s->PutCString(GetAsString().c_str());
56 }
57 
58 static inline int xdigit_to_int(char ch) {
59   ch = tolower(ch);
60   if (ch >= 'a' && ch <= 'f')
61     return 10 + ch - 'a';
62   return ch - '0';
63 }
64 
65 llvm::StringRef
66 UUID::DecodeUUIDBytesFromString(llvm::StringRef p,
67                                 llvm::SmallVectorImpl<uint8_t> &uuid_bytes,
68                                 uint32_t num_uuid_bytes) {
69   uuid_bytes.clear();
70   while (!p.empty()) {
71     if (isxdigit(p[0]) && isxdigit(p[1])) {
72       int hi_nibble = xdigit_to_int(p[0]);
73       int lo_nibble = xdigit_to_int(p[1]);
74       // Translate the two hex nibble characters into a byte
75       uuid_bytes.push_back((hi_nibble << 4) + lo_nibble);
76 
77       // Skip both hex digits
78       p = p.drop_front(2);
79 
80       // Increment the byte that we are decoding within the UUID value and
81       // break out if we are done
82       if (uuid_bytes.size() == num_uuid_bytes)
83         break;
84     } else if (p.front() == '-') {
85       // Skip dashes
86       p = p.drop_front();
87     } else {
88       // UUID values can only consist of hex characters and '-' chars
89       break;
90     }
91   }
92   return p;
93 }
94 
95 size_t UUID::SetFromStringRef(llvm::StringRef str, uint32_t num_uuid_bytes) {
96   llvm::StringRef p = str;
97 
98   // Skip leading whitespace characters
99   p = p.ltrim();
100 
101   llvm::SmallVector<uint8_t, 20> bytes;
102   llvm::StringRef rest =
103       UUID::DecodeUUIDBytesFromString(p, bytes, num_uuid_bytes);
104 
105   // If we successfully decoded a UUID, return the amount of characters that
106   // were consumed
107   if (bytes.size() == num_uuid_bytes) {
108     *this = fromData(bytes);
109     return str.size() - rest.size();
110   }
111 
112   // Else return zero to indicate we were not able to parse a UUID value
113   return 0;
114 }
115