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/Core/UUID.h"
11// C Includes
12#include <string.h>
13#include <stdio.h>
14#include <ctype.h>
15
16// C++ Includes
17#include <string>
18
19// Other libraries and framework includes
20// Project includes
21#include "lldb/Core/Stream.h"
22
23namespace lldb_private {
24
25UUID::UUID() : m_num_uuid_bytes(16)
26{
27    ::memset (m_uuid, 0, sizeof(m_uuid));
28}
29
30UUID::UUID(const UUID& rhs)
31{
32    m_num_uuid_bytes = rhs.m_num_uuid_bytes;
33    ::memcpy (m_uuid, rhs.m_uuid, sizeof (m_uuid));
34}
35
36UUID::UUID (const void *uuid_bytes, uint32_t num_uuid_bytes)
37{
38    SetBytes (uuid_bytes, num_uuid_bytes);
39}
40
41const UUID&
42UUID::operator=(const UUID& rhs)
43{
44    if (this != &rhs)
45    {
46        m_num_uuid_bytes = rhs.m_num_uuid_bytes;
47        ::memcpy (m_uuid, rhs.m_uuid, sizeof (m_uuid));
48    }
49    return *this;
50}
51
52UUID::~UUID()
53{
54}
55
56void
57UUID::Clear()
58{
59    m_num_uuid_bytes = 16;
60    ::memset (m_uuid, 0, sizeof(m_uuid));
61}
62
63const void *
64UUID::GetBytes() const
65{
66    return m_uuid;
67}
68
69std::string
70UUID::GetAsString (const char *separator) const
71{
72    std::string result;
73    char buf[256];
74    if (!separator)
75        separator = "-";
76    const uint8_t *u = (const uint8_t *)GetBytes();
77    if (sizeof (buf) > (size_t)snprintf (buf,
78                            sizeof (buf),
79                            "%2.2X%2.2X%2.2X%2.2X%s%2.2X%2.2X%s%2.2X%2.2X%s%2.2X%2.2X%s%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X",
80                            u[0],u[1],u[2],u[3],separator,
81                            u[4],u[5],separator,
82                            u[6],u[7],separator,
83                            u[8],u[9],separator,
84                            u[10],u[11],u[12],u[13],u[14],u[15]))
85    {
86        result.append (buf);
87        if (m_num_uuid_bytes == 20)
88        {
89            if (sizeof (buf) > (size_t)snprintf (buf, sizeof (buf), "%s%2.2X%2.2X%2.2X%2.2X", separator,u[16],u[17],u[18],u[19]))
90                result.append (buf);
91        }
92    }
93    return result;
94}
95
96void
97UUID::Dump (Stream *s) const
98{
99    const uint8_t *u = (const uint8_t *)GetBytes();
100    s->Printf ("%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X",
101              u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7],u[8],u[9],u[10],u[11],u[12],u[13],u[14],u[15]);
102    if (m_num_uuid_bytes == 20)
103    {
104        s->Printf ("-%2.2X%2.2X%2.2X%2.2X", u[16],u[17],u[18],u[19]);
105    }
106}
107
108bool
109UUID::SetBytes (const void *uuid_bytes, uint32_t num_uuid_bytes)
110{
111    if (uuid_bytes)
112    {
113        switch (num_uuid_bytes)
114        {
115            case 20:
116                m_num_uuid_bytes = 20;
117                break;
118            case 16:
119                m_num_uuid_bytes = 16;
120                m_uuid[16] = m_uuid[17] = m_uuid[18] = m_uuid[19] = 0;
121                break;
122            default:
123                // Unsupported UUID byte size
124                m_num_uuid_bytes = 0;
125                break;
126        }
127
128        if (m_num_uuid_bytes > 0)
129        {
130            ::memcpy (m_uuid, uuid_bytes, m_num_uuid_bytes);
131            return true;
132        }
133    }
134    ::memset (m_uuid, 0, sizeof(m_uuid));
135    return false;
136}
137
138size_t
139UUID::GetByteSize()
140{
141    return m_num_uuid_bytes;
142}
143
144bool
145UUID::IsValid () const
146{
147    return  m_uuid[0]  ||
148            m_uuid[1]  ||
149            m_uuid[2]  ||
150            m_uuid[3]  ||
151            m_uuid[4]  ||
152            m_uuid[5]  ||
153            m_uuid[6]  ||
154            m_uuid[7]  ||
155            m_uuid[8]  ||
156            m_uuid[9]  ||
157            m_uuid[10] ||
158            m_uuid[11] ||
159            m_uuid[12] ||
160            m_uuid[13] ||
161            m_uuid[14] ||
162            m_uuid[15] ||
163            m_uuid[16] ||
164            m_uuid[17] ||
165            m_uuid[18] ||
166            m_uuid[19];
167}
168
169static inline int
170xdigit_to_int (char ch)
171{
172    ch = tolower(ch);
173    if (ch >= 'a' && ch <= 'f')
174        return 10 + ch - 'a';
175    return ch - '0';
176}
177
178size_t
179UUID::DecodeUUIDBytesFromCString (const char *p, ValueType &uuid_bytes, const char **end, uint32_t num_uuid_bytes)
180{
181    size_t uuid_byte_idx = 0;
182    if (p)
183    {
184        while (*p)
185        {
186            if (isxdigit(p[0]) && isxdigit(p[1]))
187            {
188                int hi_nibble = xdigit_to_int(p[0]);
189                int lo_nibble = xdigit_to_int(p[1]);
190                // Translate the two hex nibble characters into a byte
191                uuid_bytes[uuid_byte_idx] = (hi_nibble << 4) + lo_nibble;
192
193                // Skip both hex digits
194                p += 2;
195
196                // Increment the byte that we are decoding within the UUID value
197                // and break out if we are done
198                if (++uuid_byte_idx == num_uuid_bytes)
199                    break;
200            }
201            else if (*p == '-')
202            {
203                // Skip dashes
204                p++;
205            }
206            else
207            {
208                // UUID values can only consist of hex characters and '-' chars
209                break;
210            }
211        }
212    }
213    if (end)
214        *end = p;
215    // Clear trailing bytes to 0.
216    for (uint32_t i = uuid_byte_idx; i < sizeof(ValueType); i++)
217        uuid_bytes[i] = 0;
218    return uuid_byte_idx;
219}
220size_t
221UUID::SetFromCString (const char *cstr, uint32_t num_uuid_bytes)
222{
223    if (cstr == NULL)
224        return 0;
225
226    const char *p = cstr;
227
228    // Skip leading whitespace characters
229    while (isspace(*p))
230        ++p;
231
232    const size_t uuid_byte_idx = UUID::DecodeUUIDBytesFromCString (p, m_uuid, &p, num_uuid_bytes);
233
234    // If we successfully decoded a UUID, return the amount of characters that
235    // were consumed
236    if (uuid_byte_idx == num_uuid_bytes)
237        return p - cstr;
238
239    // Else return zero to indicate we were not able to parse a UUID value
240    return 0;
241}
242
243}
244
245bool
246lldb_private::operator == (const lldb_private::UUID &lhs, const lldb_private::UUID &rhs)
247{
248    return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), sizeof (lldb_private::UUID::ValueType)) == 0;
249}
250
251bool
252lldb_private::operator != (const lldb_private::UUID &lhs, const lldb_private::UUID &rhs)
253{
254    return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), sizeof (lldb_private::UUID::ValueType)) != 0;
255}
256
257bool
258lldb_private::operator <  (const lldb_private::UUID &lhs, const lldb_private::UUID &rhs)
259{
260    return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), sizeof (lldb_private::UUID::ValueType)) <  0;
261}
262
263bool
264lldb_private::operator <= (const lldb_private::UUID &lhs, const lldb_private::UUID &rhs)
265{
266    return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), sizeof (lldb_private::UUID::ValueType)) <= 0;
267}
268
269bool
270lldb_private::operator >  (const lldb_private::UUID &lhs, const lldb_private::UUID &rhs)
271{
272    return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), sizeof (lldb_private::UUID::ValueType)) >  0;
273}
274
275bool
276lldb_private::operator >= (const lldb_private::UUID &lhs, const lldb_private::UUID &rhs)
277{
278    return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), sizeof (lldb_private::UUID::ValueType)) >= 0;
279}
280