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 |
13 | typedef 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) |
24 | Q_FORWARD_DECLARE_CF_TYPE(CFUUID); |
25 | Q_FORWARD_DECLARE_OBJC_CLASS(NSUUID); |
26 | #endif |
27 | |
28 | QT_BEGIN_NAMESPACE |
29 | |
30 | class Q_CORE_EXPORT QUuid |
31 | { |
32 | QUuid(Qt::Initialization) {} |
33 | public: |
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 | |
202 | Q_DECLARE_TYPEINFO(QUuid, Q_PRIMITIVE_TYPE); |
203 | |
204 | #ifndef QT_NO_DATASTREAM |
205 | Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QUuid &); |
206 | Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QUuid &); |
207 | #endif |
208 | |
209 | #ifndef QT_NO_DEBUG_STREAM |
210 | Q_CORE_EXPORT QDebug operator<<(QDebug, const QUuid &); |
211 | #endif |
212 | |
213 | Q_CORE_EXPORT size_t qHash(const QUuid &uuid, size_t seed = 0) noexcept; |
214 | |
215 | QUuid::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 | |
225 | QUuid::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 | |
237 | QUuid 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 |
245 | constexpr 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 | |
264 | constexpr 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 | |
287 | inline bool operator<=(const QUuid &lhs, const QUuid &rhs) noexcept |
288 | { return !(rhs < lhs); } |
289 | inline 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 |
295 | QUuid::Id128Bytes qFromBigEndian(QUuid::Id128Bytes src); |
296 | QUuid::Id128Bytes qFromLittleEndian(QUuid::Id128Bytes src); |
297 | QUuid::Id128Bytes qToBigEndian(QUuid::Id128Bytes src); |
298 | QUuid::Id128Bytes qToLittleEndian(QUuid::Id128Bytes src); |
299 | #endif |
300 | |
301 | QT_END_NAMESPACE |
302 | |
303 | #endif // QUUID_H |
304 | |