1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QUUID_H
5#define QUUID_H
6
7#include <QtCore/qendian.h>
8#include <QtCore/qstring.h>
9
10#if defined(Q_OS_WIN) || defined(Q_QDOC)
11#ifndef GUID_DEFINED
12#define GUID_DEFINED
13typedef struct _GUID
14{
15 ulong Data1;
16 ushort Data2;
17 ushort Data3;
18 uchar Data4[8];
19} GUID, *REFGUID, *LPGUID;
20#endif
21#endif
22
23#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
24Q_FORWARD_DECLARE_CF_TYPE(CFUUID);
25Q_FORWARD_DECLARE_OBJC_CLASS(NSUUID);
26#endif
27
28QT_BEGIN_NAMESPACE
29
30class Q_CORE_EXPORT QUuid
31{
32 QUuid(Qt::Initialization) {}
33public:
34 enum Variant {
35 VarUnknown =-1,
36 NCS = 0, // 0 - -
37 DCE = 2, // 1 0 -
38 Microsoft = 6, // 1 1 0
39 Reserved = 7 // 1 1 1
40 };
41
42 enum Version {
43 VerUnknown =-1,
44 Time = 1, // 0 0 0 1
45 EmbeddedPOSIX = 2, // 0 0 1 0
46 Md5 = 3, // 0 0 1 1
47 Name = Md5,
48 Random = 4, // 0 1 0 0
49 Sha1 = 5 // 0 1 0 1
50 };
51
52 enum StringFormat {
53 WithBraces = 0,
54 WithoutBraces = 1,
55 Id128 = 3
56 };
57
58 union alignas(16) Id128Bytes {
59 quint8 data[16];
60 quint16 data16[8];
61 quint32 data32[4];
62 quint64 data64[2];
63#ifdef QT_SUPPORTS_INT128
64 quint128 data128[1];
65#endif
66
67 constexpr explicit operator QByteArrayView() const noexcept
68 {
69 return QByteArrayView(data, sizeof(data));
70 }
71
72 friend constexpr Id128Bytes qbswap(Id128Bytes b) noexcept
73 {
74 // 128-bit byte swap
75 auto b0 = qbswap(source: b.data64[0]);
76 auto b1 = qbswap(source: b.data64[1]);
77 b.data64[0] = b1;
78 b.data64[1] = b0;
79 return b;
80 }
81 };
82
83 constexpr QUuid() noexcept : data1(0), data2(0), data3(0), data4{0,0,0,0,0,0,0,0} {}
84
85 constexpr QUuid(uint l, ushort w1, ushort w2, uchar b1, uchar b2, uchar b3,
86 uchar b4, uchar b5, uchar b6, uchar b7, uchar b8) noexcept
87 : data1(l), data2(w1), data3(w2), data4{b1, b2, b3, b4, b5, b6, b7, b8} {}
88 explicit inline QUuid(Id128Bytes id128, QSysInfo::Endian order = QSysInfo::BigEndian) noexcept;
89
90 explicit QUuid(QAnyStringView string) noexcept
91 : QUuid{fromString(string)} {}
92 static QUuid fromString(QAnyStringView string) noexcept;
93#if QT_CORE_REMOVED_SINCE(6, 3)
94 explicit QUuid(const QString &);
95 static QUuid fromString(QStringView string) noexcept;
96 static QUuid fromString(QLatin1StringView string) noexcept;
97 explicit QUuid(const char *);
98 explicit QUuid(const QByteArray &);
99#endif
100 QString toString(StringFormat mode = WithBraces) const;
101 QByteArray toByteArray(StringFormat mode = WithBraces) const;
102 inline Id128Bytes toBytes(QSysInfo::Endian order = QSysInfo::BigEndian) const noexcept;
103 QByteArray toRfc4122() const;
104
105 static inline QUuid fromBytes(const void *bytes, QSysInfo::Endian order = QSysInfo::BigEndian);
106#if QT_CORE_REMOVED_SINCE(6, 3)
107 static QUuid fromRfc4122(const QByteArray &);
108#endif
109 static QUuid fromRfc4122(QByteArrayView) noexcept;
110
111 bool isNull() const noexcept;
112
113#ifdef QT_SUPPORTS_INT128
114 static constexpr QUuid fromUInt128(quint128 uuid, QSysInfo::Endian order = QSysInfo::BigEndian) noexcept;
115 constexpr quint128 toUInt128(QSysInfo::Endian order = QSysInfo::BigEndian) const noexcept;
116#endif
117
118 constexpr bool operator==(const QUuid &orig) const noexcept
119 {
120 if (data1 != orig.data1 || data2 != orig.data2 ||
121 data3 != orig.data3)
122 return false;
123
124 for (uint i = 0; i < 8; i++)
125 if (data4[i] != orig.data4[i])
126 return false;
127
128 return true;
129 }
130
131 constexpr bool operator!=(const QUuid &orig) const noexcept
132 {
133 return !(*this == orig);
134 }
135
136 bool operator<(const QUuid &other) const noexcept;
137 bool operator>(const QUuid &other) const noexcept;
138
139#if defined(Q_OS_WIN) || defined(Q_QDOC)
140 // On Windows we have a type GUID that is used by the platform API, so we
141 // provide convenience operators to cast from and to this type.
142 constexpr QUuid(const GUID &guid) noexcept
143 : data1(guid.Data1), data2(guid.Data2), data3(guid.Data3),
144 data4{guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
145 guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]} {}
146
147 constexpr QUuid &operator=(const GUID &guid) noexcept
148 {
149 *this = QUuid(guid);
150 return *this;
151 }
152
153 constexpr operator GUID() const noexcept
154 {
155 GUID guid = { data1, data2, data3, { data4[0], data4[1], data4[2], data4[3], data4[4], data4[5], data4[6], data4[7] } };
156 return guid;
157 }
158
159 constexpr bool operator==(const GUID &guid) const noexcept
160 {
161 return *this == QUuid(guid);
162 }
163
164 constexpr bool operator!=(const GUID &guid) const noexcept
165 {
166 return !(*this == guid);
167 }
168#endif
169 static QUuid createUuid();
170#ifndef QT_BOOTSTRAPPED
171 static QUuid createUuidV3(const QUuid &ns, const QByteArray &baseData);
172#endif
173 static QUuid createUuidV5(const QUuid &ns, const QByteArray &baseData);
174#ifndef QT_BOOTSTRAPPED
175 static inline QUuid createUuidV3(const QUuid &ns, const QString &baseData)
176 {
177 return QUuid::createUuidV3(ns, baseData: baseData.toUtf8());
178 }
179#endif
180
181 static inline QUuid createUuidV5(const QUuid &ns, const QString &baseData)
182 {
183 return QUuid::createUuidV5(ns, baseData: baseData.toUtf8());
184 }
185
186 QUuid::Variant variant() const noexcept;
187 QUuid::Version version() const noexcept;
188
189#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
190 static QUuid fromCFUUID(CFUUIDRef uuid);
191 CFUUIDRef toCFUUID() const Q_DECL_CF_RETURNS_RETAINED;
192 static QUuid fromNSUUID(const NSUUID *uuid);
193 NSUUID *toNSUUID() const Q_DECL_NS_RETURNS_AUTORELEASED;
194#endif
195
196 uint data1;
197 ushort data2;
198 ushort data3;
199 uchar data4[8];
200};
201
202Q_DECLARE_TYPEINFO(QUuid, Q_PRIMITIVE_TYPE);
203
204#ifndef QT_NO_DATASTREAM
205Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QUuid &);
206Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QUuid &);
207#endif
208
209#ifndef QT_NO_DEBUG_STREAM
210Q_CORE_EXPORT QDebug operator<<(QDebug, const QUuid &);
211#endif
212
213Q_CORE_EXPORT size_t qHash(const QUuid &uuid, size_t seed = 0) noexcept;
214
215QUuid::QUuid(Id128Bytes uuid, QSysInfo::Endian order) noexcept
216{
217 if (order == QSysInfo::LittleEndian)
218 uuid = qbswap(b: uuid);
219 data1 = qFromBigEndian<quint32>(src: &uuid.data[0]);
220 data2 = qFromBigEndian<quint16>(src: &uuid.data[4]);
221 data3 = qFromBigEndian<quint16>(src: &uuid.data[6]);
222 memcpy(dest: data4, src: &uuid.data[8], n: sizeof(data4));
223}
224
225QUuid::Id128Bytes QUuid::toBytes(QSysInfo::Endian order) const noexcept
226{
227 Id128Bytes result = {};
228 qToBigEndian(src: data1, dest: &result.data[0]);
229 qToBigEndian(src: data2, dest: &result.data[4]);
230 qToBigEndian(src: data3, dest: &result.data[6]);
231 memcpy(dest: &result.data[8], src: data4, n: sizeof(data4));
232 if (order == QSysInfo::LittleEndian)
233 return qbswap(b: result);
234 return result;
235}
236
237QUuid QUuid::fromBytes(const void *bytes, QSysInfo::Endian order)
238{
239 Id128Bytes result = {};
240 memcpy(dest: result.data, src: bytes, n: sizeof(result));
241 return QUuid(result, order);
242}
243
244#ifdef QT_SUPPORTS_INT128
245constexpr QUuid QUuid::fromUInt128(quint128 uuid, QSysInfo::Endian order) noexcept
246{
247 QUuid result = {};
248 if (order == QSysInfo::BigEndian) {
249 result.data1 = qFromBigEndian<quint32>(source: int(uuid));
250 result.data2 = qFromBigEndian<quint16>(source: ushort(uuid >> 32));
251 result.data3 = qFromBigEndian<quint16>(source: ushort(uuid >> 48));
252 for (int i = 0; i < 8; ++i)
253 result.data4[i] = uchar(uuid >> (64 + i * 8));
254 } else {
255 result.data1 = qFromLittleEndian<quint32>(source: uint(uuid >> 96));
256 result.data2 = qFromLittleEndian<quint16>(source: ushort(uuid >> 80));
257 result.data3 = qFromLittleEndian<quint16>(source: ushort(uuid >> 64));
258 for (int i = 0; i < 8; ++i)
259 result.data4[i] = uchar(uuid >> (56 - i * 8));
260 }
261 return result;
262}
263
264constexpr quint128 QUuid::toUInt128(QSysInfo::Endian order) const noexcept
265{
266 quint128 result = {};
267 if (order == QSysInfo::BigEndian) {
268 for (int i = 0; i < 8; ++i)
269 result |= quint64(data4[i]) << (i * 8);
270 result = result << 64;
271 result |= quint64(qToBigEndian<quint16>(source: data3)) << 48;
272 result |= quint64(qToBigEndian<quint16>(source: data2)) << 32;
273 result |= qToBigEndian<quint32>(source: data1);
274 } else {
275 result = qToLittleEndian<quint32>(source: data1);
276 result = result << 32;
277 result |= quint64(qToLittleEndian<quint16>(source: data2)) << 16;
278 result |= quint64(qToLittleEndian<quint16>(source: data3));
279 result = result << 64;
280 for (int i = 0; i < 8; ++i)
281 result |= quint64(data4[i]) << (56 - i * 8);
282 }
283 return result;
284}
285#endif
286
287inline bool operator<=(const QUuid &lhs, const QUuid &rhs) noexcept
288{ return !(rhs < lhs); }
289inline bool operator>=(const QUuid &lhs, const QUuid &rhs) noexcept
290{ return !(lhs < rhs); }
291
292#if defined(Q_QDOC)
293// provide fake declarations of qXXXEndian() functions, so that qDoc could
294// distinguish them from the general template
295QUuid::Id128Bytes qFromBigEndian(QUuid::Id128Bytes src);
296QUuid::Id128Bytes qFromLittleEndian(QUuid::Id128Bytes src);
297QUuid::Id128Bytes qToBigEndian(QUuid::Id128Bytes src);
298QUuid::Id128Bytes qToLittleEndian(QUuid::Id128Bytes src);
299#endif
300
301QT_END_NAMESPACE
302
303#endif // QUUID_H
304

source code of qtbase/src/corelib/plugin/quuid.h