source: trunk/src/corelib/plugin/quuid.cpp@ 1023

Last change on this file since 1023 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 18.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtCore module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "quuid.h"
43
44#include "qdatastream.h"
45
46QT_BEGIN_NAMESPACE
47
48/*!
49 \class QUuid
50 \brief The QUuid class stores a Universally Unique Identifier (UUID).
51
52 \reentrant
53
54 Using \e{U}niversally \e{U}nique \e{ID}entifiers (UUID) is a
55 standard way to uniquely identify entities in a distributed
56 computing environment. A UUID is a 16-byte (128-bit) number
57 generated by some algorithm that is meant to guarantee that the
58 UUID will be unique in the distributed computing environment where
59 it is used. The acronym GUID is often used instead, \e{G}lobally
60 \e{U}nique \e{ID}entifiers, but it refers to the same thing.
61
62 \target Variant field
63 Actually, the GUID is one \e{variant} of UUID. Multiple variants
64 are in use. Each UUID contains a bit field that specifies which
65 type (variant) of UUID it is. Call variant() to discover which
66 type of UUID an instance of QUuid contains. It extracts the three
67 most signifcant bits of byte 8 of the 16 bytes. In QUuid, byte 8
68 is \c{QUuid::data4[0]}. If you create instances of QUuid using the
69 constructor that accepts all the numeric values as parameters, use
70 the following table to set the three most significant bits of
71 parameter \c{b1}, which becomes \c{QUuid::data4[0]} and contains
72 the variant field in its three most significant bits. In the
73 table, 'x' means \e {don't care}.
74
75 \table
76 \header
77 \o msb0
78 \o msb1
79 \o msb2
80 \o Variant
81
82 \row
83 \o 0
84 \o x
85 \o x
86 \o NCS (Network Computing System)
87
88 \row
89 \o 1
90 \o 0
91 \o x
92 \o DCE (Distributed Computing Environment)
93
94 \row
95 \o 1
96 \o 1
97 \o 0
98 \o Microsoft (GUID)
99
100 \row
101 \o 1
102 \o 1
103 \o 1
104 \o Reserved for future expansion
105
106 \endtable
107
108 \target Version field
109 If variant() returns QUuid::DCE, the UUID also contains a
110 \e{version} field in the four most significant bits of
111 \c{QUuid::data3}, and you can call version() to discover which
112 version your QUuid contains. If you create instances of QUuid
113 using the constructor that accepts all the numeric values as
114 parameters, use the following table to set the four most
115 significant bits of parameter \c{w2}, which becomes
116 \c{QUuid::data3} and contains the version field in its four most
117 significant bits.
118
119 \table
120 \header
121 \o msb0
122 \o msb1
123 \o msb2
124 \o msb3
125 \o Version
126
127 \row
128 \o 0
129 \o 0
130 \o 0
131 \o 1
132 \o Time
133
134 \row
135 \o 0
136 \o 0
137 \o 1
138 \o 0
139 \o Embedded POSIX
140
141 \row
142 \o 0
143 \o 0
144 \o 1
145 \o 1
146 \o Name
147
148 \row
149 \o 0
150 \o 1
151 \o 0
152 \o 0
153 \o Random
154
155 \endtable
156
157 The field layouts for the DCE versions listed in the table above
158 are specified in the \l{http://www.ietf.org/rfc/rfc4122.txt}
159 {Network Working Group UUID Specification}.
160
161 Most platforms provide a tool for generating new UUIDs, e.g. \c
162 uuidgen and \c guidgen. You can also use createUuid(). UUIDs
163 generated by createUuid() are of the random type. Their
164 QUuid::Version bits are set to QUuid::Random, and their
165 QUuid::Variant bits are set to QUuid::DCE. The rest of the UUID is
166 composed of random numbers. Theoretically, this means there is a
167 small chance that a UUID generated by createUuid() will not be
168 unique. But it is
169 \l{http://en.wikipedia.org/wiki/Universally_Unique_Identifier#Random_UUID_probability_of_duplicates}
170 {a \e{very} small chance}.
171
172 UUIDs can be constructed from numeric values or from strings, or
173 using the static createUuid() function. They can be converted to a
174 string with toString(). UUIDs have a variant() and a version(),
175 and null UUIDs return true from isNull().
176*/
177
178/*!
179 \fn QUuid::QUuid(const GUID &guid)
180
181 Casts a Windows \a guid to a Qt QUuid.
182
183 \warning This function is only for Windows platforms.
184*/
185
186/*!
187 \fn QUuid &QUuid::operator=(const GUID &guid)
188
189 Assigns a Windows \a guid to a Qt QUuid.
190
191 \warning This function is only for Windows platforms.
192*/
193
194/*!
195 \fn QUuid::operator GUID() const
196
197 Returns a Windows GUID from a QUuid.
198
199 \warning This function is only for Windows platforms.
200*/
201
202/*!
203 \fn QUuid::QUuid()
204
205 Creates the null UUID. toString() will output the null UUID
206 as "{00000000-0000-0000-0000-000000000000}".
207*/
208
209/*!
210 \fn QUuid::QUuid(uint l, ushort w1, ushort w2, uchar b1, uchar b2, uchar b3, uchar b4, uchar b5, uchar b6, uchar b7, uchar b8)
211
212 Creates a UUID with the value specified by the parameters, \a l,
213 \a w1, \a w2, \a b1, \a b2, \a b3, \a b4, \a b5, \a b6, \a b7, \a
214 b8.
215
216 Example:
217 \snippet doc/src/snippets/code/src_corelib_plugin_quuid.cpp 0
218*/
219
220#ifndef QT_NO_QUUID_STRING
221/*!
222 Creates a QUuid object from the string \a text, which must be
223 formatted as five hex fields separated by '-', e.g.,
224 "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" where 'x' is a hex
225 digit. The curly braces shown here are optional, but it is normal to
226 include them. If the conversion fails, a null UUID is created. See
227 toString() for an explanation of how the five hex fields map to the
228 public data members in QUuid.
229
230 \sa toString(), QUuid()
231*/
232QUuid::QUuid(const QString &text)
233{
234 bool ok;
235 if (text.isEmpty()) {
236 *this = QUuid();
237 return;
238 }
239 QString temp = text.toUpper();
240 if (temp[0] != QLatin1Char('{'))
241 temp = QLatin1Char('{') + text;
242 if (text[(int)text.length()-1] != QLatin1Char('}'))
243 temp += QLatin1Char('}');
244
245 data1 = temp.mid(1, 8).toULongLong(&ok, 16);
246 if (!ok) {
247 *this = QUuid();
248 return;
249 }
250
251 data2 = temp.mid(10, 4).toUInt(&ok, 16);
252 if (!ok) {
253 *this = QUuid();
254 return;
255 }
256 data3 = temp.mid(15, 4).toUInt(&ok, 16);
257 if (!ok) {
258 *this = QUuid();
259 return;
260 }
261 data4[0] = temp.mid(20, 2).toUInt(&ok, 16);
262 if (!ok) {
263 *this = QUuid();
264 return;
265 }
266 data4[1] = temp.mid(22, 2).toUInt(&ok, 16);
267 if (!ok) {
268 *this = QUuid();
269 return;
270 }
271 for (int i = 2; i<8; i++) {
272 data4[i] = temp.mid(25 + (i-2)*2, 2).toUShort(&ok, 16);
273 if (!ok) {
274 *this = QUuid();
275 return;
276 }
277 }
278}
279
280/*!
281 \internal
282*/
283QUuid::QUuid(const char *text)
284{
285 *this = QUuid(QString::fromLatin1(text));
286}
287#endif
288
289/*!
290 \fn bool QUuid::operator==(const QUuid &other) const
291
292 Returns true if this QUuid and the \a other QUuid are identical;
293 otherwise returns false.
294*/
295
296/*!
297 \fn bool QUuid::operator!=(const QUuid &other) const
298
299 Returns true if this QUuid and the \a other QUuid are different;
300 otherwise returns false.
301*/
302#ifndef QT_NO_QUUID_STRING
303/*!
304 \fn QUuid::operator QString() const
305
306 Returns the string representation of the uuid.
307
308 \sa toString()
309*/
310
311static QString uuidhex(uint data, int digits)
312{
313 return QString::number(data, 16).rightJustified(digits, QLatin1Char('0'));
314}
315
316/*!
317 Returns the string representation of this QUuid. The string is
318 formatted as five hex fields separated by '-' and enclosed in
319 curly braces, i.e., "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" where
320 'x' is a hex digit. From left to right, the five hex fields are
321 obtained from the four public data members in QUuid as follows:
322
323 \table
324 \header
325 \o Field #
326 \o Source
327
328 \row
329 \o 1
330 \o data1
331
332 \row
333 \o 2
334 \o data2
335
336 \row
337 \o 3
338 \o data3
339
340 \row
341 \o 4
342 \o data4[0] .. data4[1]
343
344 \row
345 \o 5
346 \o data4[2] .. data4[7]
347
348 \endtable
349*/
350QString QUuid::toString() const
351{
352 QString result;
353
354 QChar dash = QLatin1Char('-');
355 result = QLatin1Char('{') + uuidhex(data1,8);
356 result += dash;
357 result += uuidhex(data2,4);
358 result += dash;
359 result += uuidhex(data3,4);
360 result += dash;
361 result += uuidhex(data4[0],2);
362 result += uuidhex(data4[1],2);
363 result += dash;
364 for (int i = 2; i < 8; i++)
365 result += uuidhex(data4[i],2);
366
367 return result + QLatin1Char('}');
368}
369#endif
370
371#ifndef QT_NO_DATASTREAM
372/*!
373 \relates QUuid
374 Writes the UUID \a id to the data stream \a s.
375*/
376QDataStream &operator<<(QDataStream &s, const QUuid &id)
377{
378 s << (quint32)id.data1;
379 s << (quint16)id.data2;
380 s << (quint16)id.data3;
381 for (int i = 0; i < 8; i++)
382 s << (quint8)id.data4[i];
383 return s;
384}
385
386/*!
387 \relates QUuid
388 Reads a UUID from the stream \a s into \a id.
389*/
390QDataStream &operator>>(QDataStream &s, QUuid &id)
391{
392 quint32 u32;
393 quint16 u16;
394 quint8 u8;
395 s >> u32;
396 id.data1 = u32;
397 s >> u16;
398 id.data2 = u16;
399 s >> u16;
400 id.data3 = u16;
401 for (int i = 0; i < 8; i++) {
402 s >> u8;
403 id.data4[i] = u8;
404 }
405 return s;
406}
407#endif // QT_NO_DATASTREAM
408
409/*!
410 Returns true if this is the null UUID
411 {00000000-0000-0000-0000-000000000000}; otherwise returns false.
412*/
413bool QUuid::isNull() const
414{
415 return data4[0] == 0 && data4[1] == 0 && data4[2] == 0 && data4[3] == 0 &&
416 data4[4] == 0 && data4[5] == 0 && data4[6] == 0 && data4[7] == 0 &&
417 data1 == 0 && data2 == 0 && data3 == 0;
418}
419
420/*!
421 \enum QUuid::Variant
422
423 This enum defines the values used in the \l{Variant field}
424 {variant field} of the UUID. The value in the variant field
425 determines the layout of the 128-bit value.
426
427 \value VarUnknown Variant is unknown
428 \value NCS Reserved for NCS (Network Computing System) backward compatibility
429 \value DCE Distributed Computing Environment, the scheme used by QUuid
430 \value Microsoft Reserved for Microsoft backward compatibility (GUID)
431 \value Reserved Reserved for future definition
432*/
433
434/*!
435 \enum QUuid::Version
436
437 This enum defines the values used in the \l{Version field}
438 {version field} of the UUID. The version field is meaningful
439 only if the value in the \l{Variant field} {variant field}
440 is QUuid::DCE.
441
442 \value VerUnknown Version is unknown
443 \value Time Time-based, by using timestamp, clock sequence, and
444 MAC network card address (if available) for the node sections
445 \value EmbeddedPOSIX DCE Security version, with embedded POSIX UUIDs
446 \value Name Name-based, by using values from a name for all sections
447 \value Random Random-based, by using random numbers for all sections
448*/
449
450/*!
451 \fn QUuid::Variant QUuid::variant() const
452
453 Returns the value in the \l{Variant field} {variant field} of the
454 UUID. If the return value is QUuid::DCE, call version() to see
455 which layout it uses. The null UUID is considered to be of an
456 unknown variant.
457
458 \sa version()
459*/
460QUuid::Variant QUuid::variant() const
461{
462 if (isNull())
463 return VarUnknown;
464 // Check the 3 MSB of data4[0]
465 if ((data4[0] & 0x80) == 0x00) return NCS;
466 else if ((data4[0] & 0xC0) == 0x80) return DCE;
467 else if ((data4[0] & 0xE0) == 0xC0) return Microsoft;
468 else if ((data4[0] & 0xE0) == 0xE0) return Reserved;
469 return VarUnknown;
470}
471
472/*!
473 \fn QUuid::Version QUuid::version() const
474
475 Returns the \l{Version field} {version field} of the UUID, if the
476 UUID's \l{Variant field} {variant field} is QUuid::DCE. Otherwise
477 it returns QUuid::VerUnknown.
478
479 \sa variant()
480*/
481QUuid::Version QUuid::version() const
482{
483 // Check the 4 MSB of data3
484 Version ver = (Version)(data3>>12);
485 if (isNull()
486 || (variant() != DCE)
487 || ver < Time
488 || ver > Random)
489 return VerUnknown;
490 return ver;
491}
492
493/*!
494 \fn bool QUuid::operator<(const QUuid &other) const
495
496 Returns true if this QUuid has the same \l{Variant field}
497 {variant field} as the \a other QUuid and is lexicographically
498 \e{before} the \a other QUuid. If the \a other QUuid has a
499 different variant field, the return value is determined by
500 comparing the two \l{QUuid::Variant} {variants}.
501
502 \sa variant()
503*/
504#define ISLESS(f1, f2) if (f1!=f2) return (f1<f2);
505bool QUuid::operator<(const QUuid &other) const
506{
507 if (variant() != other.variant())
508 return variant() < other.variant();
509
510 ISLESS(data1, other.data1);
511 ISLESS(data2, other.data2);
512 ISLESS(data3, other.data3);
513 for (int n = 0; n < 8; n++) {
514 ISLESS(data4[n], other.data4[n]);
515 }
516 return false;
517}
518
519/*!
520 \fn bool QUuid::operator>(const QUuid &other) const
521
522 Returns true if this QUuid has the same \l{Variant field}
523 {variant field} as the \a other QUuid and is lexicographically
524 \e{after} the \a other QUuid. If the \a other QUuid has a
525 different variant field, the return value is determined by
526 comparing the two \l{QUuid::Variant} {variants}.
527
528 \sa variant()
529*/
530#define ISMORE(f1, f2) if (f1!=f2) return (f1>f2);
531bool QUuid::operator>(const QUuid &other) const
532{
533 if (variant() != other.variant())
534 return variant() > other.variant();
535
536 ISMORE(data1, other.data1);
537 ISMORE(data2, other.data2);
538 ISMORE(data3, other.data3);
539 for (int n = 0; n < 8; n++) {
540 ISMORE(data4[n], other.data4[n]);
541 }
542 return false;
543}
544
545/*!
546 \fn QUuid QUuid::createUuid()
547
548 On any platform other than Windows, this function returns a new
549 UUID with variant QUuid::DCE and version QUuid::Random. If
550 the /dev/urandom device exists, then the numbers used to construct
551 the UUID will be of cryptographic quality, which will make the UUID
552 unique. Otherwise, the numbers of the UUID will be obtained from
553 the local pseudo-random number generator (qrand(), which is seeded
554 by qsrand()) which is usually not of cryptograhic quality, which
555 means that the UUID can't be guaranteed to be unique.
556
557 On a Windows platform, a GUID is generated, which almost certainly
558 \e{will} be unique, on this or any other system, networked or not.
559
560 \sa variant(), version()
561*/
562#if defined(Q_OS_WIN32) && ! defined(Q_CC_MWERKS)
563
564QT_BEGIN_INCLUDE_NAMESPACE
565#include <objbase.h> // For CoCreateGuid
566QT_END_INCLUDE_NAMESPACE
567
568QUuid QUuid::createUuid()
569{
570 GUID guid;
571 CoCreateGuid(&guid);
572 QUuid result = guid;
573 return result;
574}
575
576#else // !Q_OS_WIN32
577
578QT_BEGIN_INCLUDE_NAMESPACE
579#include "qdatetime.h"
580#include "qfile.h"
581#include "qthreadstorage.h"
582#include <stdlib.h> // for RAND_MAX
583QT_END_INCLUDE_NAMESPACE
584
585#if !defined(QT_BOOTSTRAPPED) && defined(Q_OS_UNIX)
586Q_GLOBAL_STATIC(QThreadStorage<QFile *>, devUrandomStorage);
587#endif
588
589QUuid QUuid::createUuid()
590{
591 QUuid result;
592 uint *data = &(result.data1);
593
594#if defined(Q_OS_UNIX)
595 QFile *devUrandom;
596# if !defined(QT_BOOTSTRAPPED)
597 devUrandom = devUrandomStorage()->localData();
598 if (!devUrandom) {
599 devUrandom = new QFile(QLatin1String("/dev/urandom"));
600 devUrandom->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
601 devUrandomStorage()->setLocalData(devUrandom);
602 }
603# else
604 QFile file(QLatin1String("/dev/urandom"));
605 devUrandom = &file;
606 devUrandom->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
607# endif
608 enum { AmountToRead = 4 * sizeof(uint) };
609 if (devUrandom->isOpen()
610 && devUrandom->read((char *) data, AmountToRead) == AmountToRead) {
611 // we got what we wanted, nothing more to do
612 ;
613 } else
614#endif
615 {
616 static const int intbits = sizeof(int)*8;
617 static int randbits = 0;
618 if (!randbits) {
619 int r = 0;
620 int max = RAND_MAX;
621 do { ++r; } while ((max=max>>1));
622 randbits = r;
623 }
624
625 // Seed the PRNG once per thread with a combination of current time, a
626 // stack address and a serial counter (since thread stack addresses are
627 // re-used).
628#ifndef QT_BOOTSTRAPPED
629 static QThreadStorage<int *> uuidseed;
630 if (!uuidseed.hasLocalData())
631 {
632 int *pseed = new int;
633 static QBasicAtomicInt serial = Q_BASIC_ATOMIC_INITIALIZER(2);
634 qsrand(*pseed = QDateTime::currentDateTime().toTime_t()
635 + quintptr(&pseed)
636 + serial.fetchAndAddRelaxed(1));
637 uuidseed.setLocalData(pseed);
638 }
639#else
640 static bool seeded = false;
641 if (!seeded)
642 qsrand(QDateTime::currentDateTime().toTime_t()
643 + quintptr(&seeded));
644#endif
645
646 int chunks = 16 / sizeof(uint);
647 while (chunks--) {
648 uint randNumber = 0;
649 for (int filled = 0; filled < intbits; filled += randbits)
650 randNumber |= qrand()<<filled;
651 *(data+chunks) = randNumber;
652 }
653 }
654
655 result.data4[0] = (result.data4[0] & 0x3F) | 0x80; // UV_DCE
656 result.data3 = (result.data3 & 0x0FFF) | 0x4000; // UV_Random
657
658 return result;
659}
660#endif // !Q_OS_WIN32
661
662/*!
663 \fn bool QUuid::operator==(const GUID &guid) const
664
665 Returns true if this UUID is equal to the Windows GUID \a guid;
666 otherwise returns false.
667*/
668
669/*!
670 \fn bool QUuid::operator!=(const GUID &guid) const
671
672 Returns true if this UUID is not equal to the Windows GUID \a
673 guid; otherwise returns false.
674*/
675
676QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.