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 | #if defined(__SIZEOF_INT128__) |
64 | QT_WARNING_PUSH |
65 | QT_WARNING_DISABLE_GCC("-Wpedantic" ) // ISO C++ does not support ‘__int128’ for ‘data128’ |
66 | unsigned __int128 data128[1]; |
67 | QT_WARNING_POP |
68 | #elif defined(QT_SUPPORTS_INT128) |
69 | # error "struct QUuid::Id128Bytes should not depend on QT_SUPPORTS_INT128 for ABI reasons." |
70 | # error "Adjust the declaration of the `data128` member above so it is always defined if it's " \ |
71 | "supported by the current compiler/architecture in any configuration." |
72 | #endif |
73 | |
74 | constexpr explicit operator QByteArrayView() const noexcept |
75 | { |
76 | return QByteArrayView(data, sizeof(data)); |
77 | } |
78 | |
79 | friend constexpr Id128Bytes qbswap(Id128Bytes b) noexcept |
80 | { |
81 | // 128-bit byte swap |
82 | auto b0 = qbswap(source: b.data64[0]); |
83 | auto b1 = qbswap(source: b.data64[1]); |
84 | b.data64[0] = b1; |
85 | b.data64[1] = b0; |
86 | return b; |
87 | } |
88 | }; |
89 | |
90 | constexpr QUuid() noexcept : data1(0), data2(0), data3(0), data4{0,0,0,0,0,0,0,0} {} |
91 | |
92 | constexpr QUuid(uint l, ushort w1, ushort w2, uchar b1, uchar b2, uchar b3, |
93 | uchar b4, uchar b5, uchar b6, uchar b7, uchar b8) noexcept |
94 | : data1(l), data2(w1), data3(w2), data4{b1, b2, b3, b4, b5, b6, b7, b8} {} |
95 | explicit inline QUuid(Id128Bytes id128, QSysInfo::Endian order = QSysInfo::BigEndian) noexcept; |
96 | |
97 | explicit QUuid(QAnyStringView string) noexcept |
98 | : QUuid{fromString(string)} {} |
99 | static QUuid fromString(QAnyStringView string) noexcept; |
100 | #if QT_CORE_REMOVED_SINCE(6, 3) |
101 | explicit QUuid(const QString &); |
102 | static QUuid fromString(QStringView string) noexcept; |
103 | static QUuid fromString(QLatin1StringView string) noexcept; |
104 | explicit QUuid(const char *); |
105 | explicit QUuid(const QByteArray &); |
106 | #endif |
107 | QString toString(StringFormat mode = WithBraces) const; |
108 | QByteArray toByteArray(StringFormat mode = WithBraces) const; |
109 | inline Id128Bytes toBytes(QSysInfo::Endian order = QSysInfo::BigEndian) const noexcept; |
110 | QByteArray toRfc4122() const; |
111 | |
112 | static inline QUuid fromBytes(const void *bytes, QSysInfo::Endian order = QSysInfo::BigEndian); |
113 | #if QT_CORE_REMOVED_SINCE(6, 3) |
114 | static QUuid fromRfc4122(const QByteArray &); |
115 | #endif |
116 | static QUuid fromRfc4122(QByteArrayView) noexcept; |
117 | |
118 | bool isNull() const noexcept; |
119 | |
120 | #ifdef QT_SUPPORTS_INT128 |
121 | static constexpr QUuid fromUInt128(quint128 uuid, QSysInfo::Endian order = QSysInfo::BigEndian) noexcept; |
122 | constexpr quint128 toUInt128(QSysInfo::Endian order = QSysInfo::BigEndian) const noexcept; |
123 | #endif |
124 | |
125 | constexpr bool operator==(const QUuid &orig) const noexcept |
126 | { |
127 | if (data1 != orig.data1 || data2 != orig.data2 || |
128 | data3 != orig.data3) |
129 | return false; |
130 | |
131 | for (uint i = 0; i < 8; i++) |
132 | if (data4[i] != orig.data4[i]) |
133 | return false; |
134 | |
135 | return true; |
136 | } |
137 | |
138 | constexpr bool operator!=(const QUuid &orig) const noexcept |
139 | { |
140 | return !(*this == orig); |
141 | } |
142 | |
143 | bool operator<(const QUuid &other) const noexcept; |
144 | bool operator>(const QUuid &other) const noexcept; |
145 | |
146 | #if defined(Q_OS_WIN) || defined(Q_QDOC) |
147 | // On Windows we have a type GUID that is used by the platform API, so we |
148 | // provide convenience operators to cast from and to this type. |
149 | constexpr QUuid(const GUID &guid) noexcept |
150 | : data1(guid.Data1), data2(guid.Data2), data3(guid.Data3), |
151 | data4{guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], |
152 | guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]} {} |
153 | |
154 | constexpr QUuid &operator=(const GUID &guid) noexcept |
155 | { |
156 | *this = QUuid(guid); |
157 | return *this; |
158 | } |
159 | |
160 | constexpr operator GUID() const noexcept |
161 | { |
162 | GUID guid = { data1, data2, data3, { data4[0], data4[1], data4[2], data4[3], data4[4], data4[5], data4[6], data4[7] } }; |
163 | return guid; |
164 | } |
165 | |
166 | constexpr bool operator==(const GUID &guid) const noexcept |
167 | { |
168 | return *this == QUuid(guid); |
169 | } |
170 | |
171 | constexpr bool operator!=(const GUID &guid) const noexcept |
172 | { |
173 | return !(*this == guid); |
174 | } |
175 | #endif |
176 | static QUuid createUuid(); |
177 | #ifndef QT_BOOTSTRAPPED |
178 | static QUuid createUuidV3(const QUuid &ns, const QByteArray &baseData); |
179 | #endif |
180 | static QUuid createUuidV5(const QUuid &ns, const QByteArray &baseData); |
181 | #ifndef QT_BOOTSTRAPPED |
182 | static inline QUuid createUuidV3(const QUuid &ns, const QString &baseData) |
183 | { |
184 | return QUuid::createUuidV3(ns, baseData: baseData.toUtf8()); |
185 | } |
186 | #endif |
187 | |
188 | static inline QUuid createUuidV5(const QUuid &ns, const QString &baseData) |
189 | { |
190 | return QUuid::createUuidV5(ns, baseData: baseData.toUtf8()); |
191 | } |
192 | |
193 | QUuid::Variant variant() const noexcept; |
194 | QUuid::Version version() const noexcept; |
195 | |
196 | #if defined(Q_OS_DARWIN) || defined(Q_QDOC) |
197 | static QUuid fromCFUUID(CFUUIDRef uuid); |
198 | CFUUIDRef toCFUUID() const Q_DECL_CF_RETURNS_RETAINED; |
199 | static QUuid fromNSUUID(const NSUUID *uuid); |
200 | NSUUID *toNSUUID() const Q_DECL_NS_RETURNS_AUTORELEASED; |
201 | #endif |
202 | |
203 | uint data1; |
204 | ushort data2; |
205 | ushort data3; |
206 | uchar data4[8]; |
207 | }; |
208 | |
209 | Q_DECLARE_TYPEINFO(QUuid, Q_PRIMITIVE_TYPE); |
210 | |
211 | #ifndef QT_NO_DATASTREAM |
212 | Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QUuid &); |
213 | Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QUuid &); |
214 | #endif |
215 | |
216 | #ifndef QT_NO_DEBUG_STREAM |
217 | Q_CORE_EXPORT QDebug operator<<(QDebug, const QUuid &); |
218 | #endif |
219 | |
220 | Q_CORE_EXPORT size_t qHash(const QUuid &uuid, size_t seed = 0) noexcept; |
221 | |
222 | QUuid::QUuid(Id128Bytes uuid, QSysInfo::Endian order) noexcept |
223 | { |
224 | if (order == QSysInfo::LittleEndian) |
225 | uuid = qbswap(b: uuid); |
226 | data1 = qFromBigEndian<quint32>(src: &uuid.data[0]); |
227 | data2 = qFromBigEndian<quint16>(src: &uuid.data[4]); |
228 | data3 = qFromBigEndian<quint16>(src: &uuid.data[6]); |
229 | memcpy(dest: data4, src: &uuid.data[8], n: sizeof(data4)); |
230 | } |
231 | |
232 | QUuid::Id128Bytes QUuid::toBytes(QSysInfo::Endian order) const noexcept |
233 | { |
234 | Id128Bytes result = {}; |
235 | qToBigEndian(src: data1, dest: &result.data[0]); |
236 | qToBigEndian(src: data2, dest: &result.data[4]); |
237 | qToBigEndian(src: data3, dest: &result.data[6]); |
238 | memcpy(dest: &result.data[8], src: data4, n: sizeof(data4)); |
239 | if (order == QSysInfo::LittleEndian) |
240 | return qbswap(b: result); |
241 | return result; |
242 | } |
243 | |
244 | QUuid QUuid::fromBytes(const void *bytes, QSysInfo::Endian order) |
245 | { |
246 | Id128Bytes result = {}; |
247 | memcpy(dest: result.data, src: bytes, n: sizeof(result)); |
248 | return QUuid(result, order); |
249 | } |
250 | |
251 | #ifdef QT_SUPPORTS_INT128 |
252 | constexpr QUuid QUuid::fromUInt128(quint128 uuid, QSysInfo::Endian order) noexcept |
253 | { |
254 | QUuid result = {}; |
255 | if (order == QSysInfo::BigEndian) { |
256 | result.data1 = qFromBigEndian<quint32>(source: int(uuid)); |
257 | result.data2 = qFromBigEndian<quint16>(source: ushort(uuid >> 32)); |
258 | result.data3 = qFromBigEndian<quint16>(source: ushort(uuid >> 48)); |
259 | for (int i = 0; i < 8; ++i) |
260 | result.data4[i] = uchar(uuid >> (64 + i * 8)); |
261 | } else { |
262 | result.data1 = qFromLittleEndian<quint32>(source: uint(uuid >> 96)); |
263 | result.data2 = qFromLittleEndian<quint16>(source: ushort(uuid >> 80)); |
264 | result.data3 = qFromLittleEndian<quint16>(source: ushort(uuid >> 64)); |
265 | for (int i = 0; i < 8; ++i) |
266 | result.data4[i] = uchar(uuid >> (56 - i * 8)); |
267 | } |
268 | return result; |
269 | } |
270 | |
271 | constexpr quint128 QUuid::toUInt128(QSysInfo::Endian order) const noexcept |
272 | { |
273 | quint128 result = {}; |
274 | if (order == QSysInfo::BigEndian) { |
275 | for (int i = 0; i < 8; ++i) |
276 | result |= quint64(data4[i]) << (i * 8); |
277 | result = result << 64; |
278 | result |= quint64(qToBigEndian<quint16>(source: data3)) << 48; |
279 | result |= quint64(qToBigEndian<quint16>(source: data2)) << 32; |
280 | result |= qToBigEndian<quint32>(source: data1); |
281 | } else { |
282 | result = qToLittleEndian<quint32>(source: data1); |
283 | result = result << 32; |
284 | result |= quint64(qToLittleEndian<quint16>(source: data2)) << 16; |
285 | result |= quint64(qToLittleEndian<quint16>(source: data3)); |
286 | result = result << 64; |
287 | for (int i = 0; i < 8; ++i) |
288 | result |= quint64(data4[i]) << (56 - i * 8); |
289 | } |
290 | return result; |
291 | } |
292 | #endif |
293 | |
294 | inline bool operator<=(const QUuid &lhs, const QUuid &rhs) noexcept |
295 | { return !(rhs < lhs); } |
296 | inline bool operator>=(const QUuid &lhs, const QUuid &rhs) noexcept |
297 | { return !(lhs < rhs); } |
298 | |
299 | #if defined(Q_QDOC) |
300 | // provide fake declarations of qXXXEndian() functions, so that qDoc could |
301 | // distinguish them from the general template |
302 | QUuid::Id128Bytes qFromBigEndian(QUuid::Id128Bytes src); |
303 | QUuid::Id128Bytes qFromLittleEndian(QUuid::Id128Bytes src); |
304 | QUuid::Id128Bytes qToBigEndian(QUuid::Id128Bytes src); |
305 | QUuid::Id128Bytes qToLittleEndian(QUuid::Id128Bytes src); |
306 | #endif |
307 | |
308 | QT_END_NAMESPACE |
309 | |
310 | #endif // QUUID_H |
311 | |