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