1f678e45dSDimitry Andric //===-- UUID.cpp ------------------------------------------------*- C++ -*-===//
2f678e45dSDimitry Andric //
3f678e45dSDimitry Andric //                     The LLVM Compiler Infrastructure
4f678e45dSDimitry Andric //
5f678e45dSDimitry Andric // This file is distributed under the University of Illinois Open Source
6f678e45dSDimitry Andric // License. See LICENSE.TXT for details.
7f678e45dSDimitry Andric //
8f678e45dSDimitry Andric //===----------------------------------------------------------------------===//
9f678e45dSDimitry Andric 
10f678e45dSDimitry Andric #include "lldb/Utility/UUID.h"
11f678e45dSDimitry Andric 
12f678e45dSDimitry Andric #include "lldb/Utility/Stream.h"
13f678e45dSDimitry Andric #include "llvm/ADT/StringRef.h"
144ba319b5SDimitry Andric #include "llvm/Support/Format.h"
15f678e45dSDimitry Andric 
16f678e45dSDimitry Andric #include <ctype.h>
17f678e45dSDimitry Andric #include <stdio.h>
18f678e45dSDimitry Andric #include <string.h>
19f678e45dSDimitry Andric 
204ba319b5SDimitry Andric using namespace lldb_private;
21f678e45dSDimitry Andric 
224ba319b5SDimitry Andric // Whether to put a separator after count uuid bytes.
234ba319b5SDimitry Andric // For the first 16 bytes we follow the traditional UUID format. After that, we
244ba319b5SDimitry Andric // simply put a dash after every 6 bytes.
separate(size_t count)254ba319b5SDimitry Andric static inline bool separate(size_t count) {
264ba319b5SDimitry Andric   if (count >= 10)
274ba319b5SDimitry Andric     return (count - 10) % 6 == 0;
28f678e45dSDimitry Andric 
294ba319b5SDimitry Andric   switch (count) {
304ba319b5SDimitry Andric   case 4:
314ba319b5SDimitry Andric   case 6:
324ba319b5SDimitry Andric   case 8:
334ba319b5SDimitry Andric     return true;
344ba319b5SDimitry Andric   default:
354ba319b5SDimitry Andric     return false;
364ba319b5SDimitry Andric   }
37f678e45dSDimitry Andric }
38f678e45dSDimitry Andric 
GetAsString(llvm::StringRef separator) const394ba319b5SDimitry Andric std::string UUID::GetAsString(llvm::StringRef separator) const {
40f678e45dSDimitry Andric   std::string result;
414ba319b5SDimitry Andric   llvm::raw_string_ostream os(result);
424ba319b5SDimitry Andric 
434ba319b5SDimitry Andric   for (auto B : llvm::enumerate(GetBytes())) {
444ba319b5SDimitry Andric     if (separate(B.index()))
454ba319b5SDimitry Andric       os << separator;
464ba319b5SDimitry Andric 
474ba319b5SDimitry Andric     os << llvm::format_hex_no_prefix(B.value(), 2, true);
48f678e45dSDimitry Andric   }
494ba319b5SDimitry Andric   os.flush();
504ba319b5SDimitry Andric 
51f678e45dSDimitry Andric   return result;
52f678e45dSDimitry Andric }
53f678e45dSDimitry Andric 
Dump(Stream * s) const54*b5893f02SDimitry Andric void UUID::Dump(Stream *s) const { s->PutCString(GetAsString()); }
55f678e45dSDimitry Andric 
xdigit_to_int(char ch)56f678e45dSDimitry Andric static inline int xdigit_to_int(char ch) {
57f678e45dSDimitry Andric   ch = tolower(ch);
58f678e45dSDimitry Andric   if (ch >= 'a' && ch <= 'f')
59f678e45dSDimitry Andric     return 10 + ch - 'a';
60f678e45dSDimitry Andric   return ch - '0';
61f678e45dSDimitry Andric }
62f678e45dSDimitry Andric 
634ba319b5SDimitry Andric llvm::StringRef
DecodeUUIDBytesFromString(llvm::StringRef p,llvm::SmallVectorImpl<uint8_t> & uuid_bytes,uint32_t num_uuid_bytes)644ba319b5SDimitry Andric UUID::DecodeUUIDBytesFromString(llvm::StringRef p,
654ba319b5SDimitry Andric                                 llvm::SmallVectorImpl<uint8_t> &uuid_bytes,
66f678e45dSDimitry Andric                                 uint32_t num_uuid_bytes) {
674ba319b5SDimitry Andric   uuid_bytes.clear();
68f678e45dSDimitry Andric   while (!p.empty()) {
69f678e45dSDimitry Andric     if (isxdigit(p[0]) && isxdigit(p[1])) {
70f678e45dSDimitry Andric       int hi_nibble = xdigit_to_int(p[0]);
71f678e45dSDimitry Andric       int lo_nibble = xdigit_to_int(p[1]);
72f678e45dSDimitry Andric       // Translate the two hex nibble characters into a byte
734ba319b5SDimitry Andric       uuid_bytes.push_back((hi_nibble << 4) + lo_nibble);
74f678e45dSDimitry Andric 
75f678e45dSDimitry Andric       // Skip both hex digits
76f678e45dSDimitry Andric       p = p.drop_front(2);
77f678e45dSDimitry Andric 
784ba319b5SDimitry Andric       // Increment the byte that we are decoding within the UUID value and
794ba319b5SDimitry Andric       // break out if we are done
804ba319b5SDimitry Andric       if (uuid_bytes.size() == num_uuid_bytes)
81f678e45dSDimitry Andric         break;
82f678e45dSDimitry Andric     } else if (p.front() == '-') {
83f678e45dSDimitry Andric       // Skip dashes
84f678e45dSDimitry Andric       p = p.drop_front();
85f678e45dSDimitry Andric     } else {
86f678e45dSDimitry Andric       // UUID values can only consist of hex characters and '-' chars
87f678e45dSDimitry Andric       break;
88f678e45dSDimitry Andric     }
89f678e45dSDimitry Andric   }
90f678e45dSDimitry Andric   return p;
91f678e45dSDimitry Andric }
92f678e45dSDimitry Andric 
SetFromStringRef(llvm::StringRef str,uint32_t num_uuid_bytes)935517e702SDimitry Andric size_t UUID::SetFromStringRef(llvm::StringRef str, uint32_t num_uuid_bytes) {
945517e702SDimitry Andric   llvm::StringRef p = str;
95f678e45dSDimitry Andric 
96f678e45dSDimitry Andric   // Skip leading whitespace characters
97f678e45dSDimitry Andric   p = p.ltrim();
98f678e45dSDimitry Andric 
994ba319b5SDimitry Andric   llvm::SmallVector<uint8_t, 20> bytes;
100f678e45dSDimitry Andric   llvm::StringRef rest =
1014ba319b5SDimitry Andric       UUID::DecodeUUIDBytesFromString(p, bytes, num_uuid_bytes);
102f678e45dSDimitry Andric 
103f678e45dSDimitry Andric   // If we successfully decoded a UUID, return the amount of characters that
104f678e45dSDimitry Andric   // were consumed
1054ba319b5SDimitry Andric   if (bytes.size() == num_uuid_bytes) {
1064ba319b5SDimitry Andric     *this = fromData(bytes);
1075517e702SDimitry Andric     return str.size() - rest.size();
108f678e45dSDimitry Andric   }
109f678e45dSDimitry Andric 
110f678e45dSDimitry Andric   // Else return zero to indicate we were not able to parse a UUID value
111f678e45dSDimitry Andric   return 0;
112f678e45dSDimitry Andric }
113