Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TUUID.cxx
Go to the documentation of this file.
1 // @(#)root/base:$Id$
2 // Author: Fons Rademakers 30/9/2001
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2001, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /** \class TUUID
13 \ingroup Base
14 
15 This class defines a UUID (Universally Unique IDentifier), also
16 known as GUIDs (Globally Unique IDentifier). A UUID is 128 bits
17 long, and if generated according to this algorithm, is either
18 guaranteed to be different from all other UUIDs/GUIDs generated
19 until 3400 A.D. or extremely likely to be different. UUIDs were
20 originally used in the Network Computing System (NCS) and
21 later in the Open Software Foundation's (OSF) Distributed Computing
22 Environment (DCE).
23 
24 Structure of universal unique IDs (UUIDs).
25 
26 Depending on the network data representation, the multi-
27 octet unsigned integer fields are subject to byte swapping
28 when communicated between dissimilar endian machines.
29 ~~~ {.cpp}
30 +-----------------------------------+
31 | low 32 bits of time | 0-3 .fTimeLow
32 +-------------------------------+----
33 | mid 16 bits of time | 4-5 .fTimeMid
34 +-------+-----------------------+
35 | vers. | hi 12 bits of time | 6-7 .fTimeHiAndVersion
36 +-------+-------+---------------+
37 |Res | clkSeqHi | 8 .fClockSeqHiAndReserved
38 +---------------+
39 | clkSeqLow | 9 .fClockSeqLow
40 +---------------+------------------+
41 | node ID | 10-15 .fNode
42 +----------------------------------+
43 ~~~
44 
45 The adjusted time stamp is split into three fields, and the
46 clockSeq is split into two fields.
47 
48 The timestamp is a 60-bit value. For UUID version 1, this
49 is represented by Coordinated Universal Time (UTC/GMT) as
50 a count of 100-nanosecond intervals since 00:00:00.00,
51 15 October 1582 (the date of Gregorian reform to the
52 Christian calendar).
53 
54 The version number is multiplexed in the 4 most significant
55 bits of the 'fTimeHiAndVersion' field. There are two defined
56 versions:
57 ~~~ {.cpp}
58  MSB <---
59 Version 4-Bit Code Description
60 ------------------------------------------------------------
61 | 1 0 0 0 1 DCE version, as specified herein.
62 | 2 0 0 1 0 DCE Security version, with
63 | embedded POSIX UIDs.
64 | 3 0 0 1 1 node id is a random value
65 ------------------------------------------------------------
66 ~~~
67 
68 ## Clock Sequence
69 
70 The clock sequence value must be changed whenever:
71 
72  The UUID generator detects that the local value of UTC
73  has gone backward; this may be due to re-syncing of the system
74  clock.
75 
76 While a node is operational, the UUID service always saves
77 the last UTC used to create a UUID. Each time a new UUID
78 is created, the current UTC is compared to the saved value
79 and if either the current value is less or the saved value
80 was lost, then the clock sequence is incremented modulo
81 16,384, thus avoiding production of duplicated UUIDs.
82 
83 The clock sequence must be initialized to a random number
84 to minimize the correlation across system. This provides
85 maximum protection against node identifiers that may move
86 or switch from system to system rapidly.
87 
88 ## Clock Adjustment
89 
90 UUIDs may be created at a rate greater than the system clock
91 resolution. Therefore, the system must also maintain an
92 adjustment value to be added to the lower-order bits of the
93 time. Logically, each time the system clock ticks, the
94 adjustment value is cleared. Every time a UUID is generated,
95 the current adjustment value is read and incremented, and
96 then added to the UTC time field of the UUID.
97 
98 ## Clock Overrun
99 
100 The 100-nanosecond granularity of time should prove sufficient
101 even for bursts of UUID production in the next generation of
102 high-performance multiprocessors. If a system overruns the
103 clock adjustment by requesting too many UUIDs within a single
104 system clock tick, the UUID generator will stall until the
105 system clock catches up.
106 */
107 
108 #include "TROOT.h"
109 #include "TUUID.h"
110 #include "TError.h"
111 #include "TSystem.h"
112 #include "TInetAddress.h"
113 #include "TMD5.h"
114 #include "Bytes.h"
115 #include "TVirtualMutex.h"
116 #include "ThreadLocalStorage.h"
117 #include <string.h>
118 #include <stdlib.h>
119 #ifdef R__WIN32
120 #include "Windows4Root.h"
121 #include <Iphlpapi.h>
122 #include <process.h>
123 #define getpid() _getpid()
124 #define srandom(seed) srand(seed)
125 #define random() rand()
126 #else
127 #include <unistd.h>
128 #include <sys/time.h>
129 #if defined(R__LINUX) && !defined(R__WINGCC)
130 #include <sys/sysinfo.h>
131 #endif
132 #include <ifaddrs.h>
133 #include <netinet/in.h>
134 #endif
135 #include <chrono>
136 
137 ClassImp(TUUID);
138 
139 ////////////////////////////////////////////////////////////////////////////////
140 /// Create a UUID.
141 
142 TUUID::TUUID()
143 {
144  TTHREAD_TLS(uuid_time_t) time_last;
145  TTHREAD_TLS(UShort_t) clockseq(0);
146  TTHREAD_TLS(Bool_t) firstTime(kTRUE);
147  uuid_time_t *time_last_ptr = TTHREAD_TLS_PTR(time_last);
148 
149  if (firstTime) {
150  R__LOCKGUARD(gROOTMutex); // rand and random are not thread safe.
151 
152  UInt_t seed;
153  if (gSystem) {
154  // try to get a unique seed per process
155  seed = (UInt_t)(Long64_t(gSystem->Now()) + gSystem->GetPid());
156  } else {
157  using namespace std::chrono;
158  system_clock::time_point today = system_clock::now();
159  seed = (UInt_t)(system_clock::to_time_t ( today )) + ::getpid();
160  }
161  srandom(seed);
162  GetCurrentTime(time_last_ptr);
163  clockseq = 1+(UShort_t)(65536*random()/(RAND_MAX+1.0));
164  firstTime = kFALSE;
165  }
166 
167  uuid_time_t timestamp;
168 
169  // get current time
170  GetCurrentTime(&timestamp);
171 
172  // if clock went backward change clockseq
173  if (CmpTime(&timestamp, time_last_ptr) == -1) {
174  clockseq = (clockseq + 1) & 0x3FFF;
175  if (clockseq == 0) clockseq++;
176  }
177 
178  Format(clockseq, timestamp);
179 
180  time_last = timestamp;
181  fUUIDIndex = 1<<30;
182 }
183 
184 ////////////////////////////////////////////////////////////////////////////////
185 /// delete this TUUID
186 
187 TUUID::~TUUID()
188 {
189  //gROOT->GetUUIDs()->RemoveUUID(fUUIDIndex);
190 }
191 
192 ////////////////////////////////////////////////////////////////////////////////
193 /// Compare two time values.
194 
195 Int_t TUUID::CmpTime(uuid_time_t *t1, uuid_time_t *t2)
196 {
197  if (t1->high < t2->high) return -1;
198  if (t1->high > t2->high) return 1;
199  if (t1->low < t2->low) return -1;
200  if (t1->low > t2->low) return 1;
201  return 0;
202 }
203 
204 ////////////////////////////////////////////////////////////////////////////////
205 /// Set this UUID to the value specified in uuid ((which must be in
206 /// TUUID::AsString() format).
207 
208 void TUUID::SetFromString(const char *uuid)
209 {
210  // Format is tttttttt-tttt-cccc-cccc-nnnnnnnnnnnn.
211  Long_t timeLo;
212  int timeMid;
213  int timeHiAndVersion;
214  int clockSeqHiAndRes;
215  int clockSeqLo;
216  int node[6];
217 
218  sscanf(uuid, "%8lx-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x",
219  &timeLo,
220  &timeMid,
221  &timeHiAndVersion,
222  &clockSeqHiAndRes,
223  &clockSeqLo,
224  &node[0], &node[1], &node[2], &node[3], &node[4], &node[5]);
225 
226  // Note that we're going through this agony because scanf is
227  // defined to know only to scan into "int"s or "long"s.
228  fTimeLow = (UInt_t) timeLo;
229  fTimeMid = (UShort_t) timeMid;
230  fTimeHiAndVersion = (UShort_t) timeHiAndVersion;
231  fClockSeqHiAndReserved = (UChar_t) clockSeqHiAndRes;
232  fClockSeqLow = (UChar_t) clockSeqLo;
233  fNode[0] = (UChar_t) node[0];
234  fNode[1] = (UChar_t) node[1];
235  fNode[2] = (UChar_t) node[2];
236  fNode[3] = (UChar_t) node[3];
237  fNode[4] = (UChar_t) node[4];
238  fNode[5] = (UChar_t) node[5];
239  fUUIDIndex = 1<<30;
240 }
241 
242 ////////////////////////////////////////////////////////////////////////////////
243 /// Initialize a TUUID with uuid (which must be in TUUID::AsString() format).
244 
245 TUUID::TUUID(const char *uuid)
246 {
247  fTimeLow = 0;
248  fTimeMid = 0;
249  fTimeHiAndVersion = 0;
250  fClockSeqHiAndReserved = 0;
251  fClockSeqLow = 0;
252  fNode[0] = 0;
253  fUUIDIndex = 0;
254 
255  if (!uuid || !*uuid)
256  Error("TUUID", "null string not allowed");
257  else
258  SetFromString(uuid);
259 }
260 
261 ////////////////////////////////////////////////////////////////////////////////
262 /// Stream UUID into output buffer.
263 
264 void TUUID::FillBuffer(char *&buffer)
265 {
266  Version_t version = TUUID::Class_Version();
267  tobuf(buffer, version);
268  tobuf(buffer, fTimeLow);
269  tobuf(buffer, fTimeMid);
270  tobuf(buffer, fTimeHiAndVersion);
271  tobuf(buffer, fClockSeqHiAndReserved);
272  tobuf(buffer, fClockSeqLow);
273  for (Int_t i = 0; i < 6; i++)
274  tobuf(buffer, fNode[i]);
275 }
276 
277 ////////////////////////////////////////////////////////////////////////////////
278 /// Stream UUID from input buffer.
279 
280 void TUUID::ReadBuffer(char *&buffer)
281 {
282  Version_t version;
283  frombuf(buffer, &version);
284  frombuf(buffer, &fTimeLow);
285  frombuf(buffer, &fTimeMid);
286  frombuf(buffer, &fTimeHiAndVersion);
287  frombuf(buffer, &fClockSeqHiAndReserved);
288  frombuf(buffer, &fClockSeqLow);
289  for (Int_t i = 0; i < 6; i++)
290  frombuf(buffer, &fNode[i]);
291 }
292 
293 ////////////////////////////////////////////////////////////////////////////////
294 /// Stream UUID from input buffer.
295 /// This function is for the exclusive use of TDirectory::Streamer() to
296 /// read a non-versioned version of TUUID.
297 
298 void TUUID::StreamerV1(TBuffer &b)
299 {
300  b >> fTimeLow;
301  b >> fTimeMid;
302  b >> fTimeHiAndVersion;
303  b >> fClockSeqHiAndReserved;
304  b >> fClockSeqLow;
305  for (UInt_t i = 0; i < 6; i++) {
306  b >> fNode[i];
307  }
308 }
309 
310 ////////////////////////////////////////////////////////////////////////////////
311 /// Make a UUID from timestamp, clockseq and node id.
312 
313 void TUUID::Format(UShort_t clockseq, uuid_time_t ts)
314 {
315  fTimeLow = ts.low;
316  fTimeMid = (UShort_t)(ts.high & 0xFFFF);
317  fTimeHiAndVersion = (UShort_t)((ts.high >> 16) & 0x0FFF);
318  fTimeHiAndVersion |= (1 << 12);
319  fClockSeqLow = clockseq & 0xFF;
320  fClockSeqHiAndReserved = (clockseq & 0x3F00) >> 8;
321  fClockSeqHiAndReserved |= 0x80;
322  GetNodeIdentifier();
323 }
324 
325 ////////////////////////////////////////////////////////////////////////////////
326 /// Get current time as 60 bit 100ns ticks since whenever.
327 /// Compensate for the fact that real clock resolution is less
328 /// than 100ns.
329 
330 void TUUID::GetCurrentTime(uuid_time_t *timestamp)
331 {
332  const UShort_t uuids_per_tick = 1024;
333 
334  TTHREAD_TLS(uuid_time_t) time_last;
335  TTHREAD_TLS(UShort_t) uuids_this_tick(0);
336  TTHREAD_TLS(Bool_t) init(kFALSE);
337 
338  uuid_time_t *time_last_ptr = TTHREAD_TLS_PTR(time_last);
339 
340  if (!init) {
341  GetSystemTime(time_last_ptr);
342  uuids_this_tick = uuids_per_tick;
343  init = kTRUE;
344  }
345 
346  uuid_time_t time_now;
347 
348  while (1) {
349  GetSystemTime(&time_now);
350 
351  // if clock reading changed since last UUID generated
352  if (CmpTime(time_last_ptr, &time_now)) {
353  // reset count of uuid's generated with this clock reading
354  uuids_this_tick = 0;
355  break;
356  }
357  if (uuids_this_tick < uuids_per_tick) {
358  uuids_this_tick++;
359  break;
360  }
361  // going too fast for our clock; spin
362  }
363 
364  time_last = time_now;
365 
366  if (uuids_this_tick != 0) {
367  if (time_now.low & 0x80000000) {
368  time_now.low += uuids_this_tick;
369  if (!(time_now.low & 0x80000000))
370  time_now.high++;
371  } else
372  time_now.low += uuids_this_tick;
373  }
374 
375  timestamp->high = time_now.high;
376  timestamp->low = time_now.low;
377 }
378 
379 ////////////////////////////////////////////////////////////////////////////////
380 /// Get system time with 100ns precision. Time is since Oct 15, 1582.
381 
382 void TUUID::GetSystemTime(uuid_time_t *timestamp)
383 {
384 #ifdef R__WIN32
385  ULARGE_INTEGER time;
386  GetSystemTimeAsFileTime((FILETIME *)&time);
387  // NT keeps time in FILETIME format which is 100ns ticks since
388  // Jan 1, 1601. UUIDs use time in 100ns ticks since Oct 15, 1582.
389  // The difference is 17 Days in Oct + 30 (Nov) + 31 (Dec)
390  // + 18 years and 5 leap days.
391  time.QuadPart +=
392  (unsigned __int64) (1000*1000*10) // seconds
393  * (unsigned __int64) (60 * 60 * 24) // days
394  * (unsigned __int64) (17+30+31+365*18+5); // # of days
395 
396  timestamp->high = time.HighPart;
397  timestamp->low = time.LowPart;
398 #else
399  struct timeval tp;
400  gettimeofday(&tp, 0);
401  // Offset between UUID formatted times and Unix formatted times.
402  // UUID UTC base time is October 15, 1582.
403  // Unix base time is January 1, 1970.
404  ULong64_t uuid_time = ((ULong64_t)tp.tv_sec * 10000000) + (tp.tv_usec * 10) +
405  0x01B21DD213814000LL;
406  timestamp->high = (UInt_t) (uuid_time >> 32);
407  timestamp->low = (UInt_t) (uuid_time & 0xFFFFFFFF);
408 #endif
409 }
410 
411 ////////////////////////////////////////////////////////////////////////////////
412 /// Get node identifier. Try first to get network address, if no
413 /// network interface try random info based on some machine parameters.
414 
415 void TUUID::GetNodeIdentifier()
416 {
417  static UInt_t adr = 0;
418 
419  if (gSystem) {
420 #ifndef R__WIN32
421  if (!adr) {
422  UInt_t addr = 0;
423 
424  struct ifaddrs *ifAddrStruct = nullptr;
425  struct ifaddrs *ifa = nullptr;
426 
427  if (getifaddrs(&ifAddrStruct) != 0) {
428  adr = 1;
429  } else {
430  for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
431  if (!ifa->ifa_addr) {
432  continue;
433  }
434  if (ifa->ifa_addr->sa_family != AF_INET) { // check only IP4
435  continue;
436  }
437  if (strncmp(ifa->ifa_name,"lo",2) == 0) { // skip loop back.
438  continue;
439  }
440  addr = ntohl(((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr);
441  break;
442  }
443  }
444 
445  if (ifAddrStruct != nullptr)
446  freeifaddrs(ifAddrStruct);
447 
448  if (addr)
449  adr = addr;
450  else
451  adr = 1; // illegal address
452  }
453 #else
454  // this way to get the machine's IP address is needed because
455  // GetHostByName() on Win32 contacts the DNS which we don't want
456  // as firewall tools like ZoneAlarm are likely to catch it and
457  // alarm the user
458  if (!adr) {
459  PIP_ADAPTER_INFO ainfo = (PIP_ADAPTER_INFO) malloc(sizeof(IP_ADAPTER_INFO));
460  ULONG buflen = sizeof(IP_ADAPTER_INFO);
461  DWORD stat = GetAdaptersInfo(ainfo, &buflen);
462  if (stat == ERROR_BUFFER_OVERFLOW) {
463  free(ainfo);
464  ainfo = (PIP_ADAPTER_INFO) malloc(buflen);
465  stat = GetAdaptersInfo(ainfo, &buflen);
466  }
467  if (stat != ERROR_SUCCESS)
468  adr = 1; // illegal address
469  else {
470  // take address of first adapter
471  PIP_ADAPTER_INFO adapter = ainfo;
472  int a, b, c, d;
473  sscanf(adapter->IpAddressList.IpAddress.String, "%d.%d.%d.%d",
474  &a, &b, &c, &d);
475  adr = (a << 24) | (b << 16) | (c << 8) | d;
476  }
477  free(ainfo);
478  }
479 #endif
480  if (adr > 2) {
481  memcpy(fNode, &adr, 4);
482  fNode[4] = 0xbe;
483  fNode[5] = 0xef;
484  return;
485  }
486  }
487  static UChar_t seed[16];
488  if (adr < 2) {
489  GetRandomInfo(seed);
490  seed[0] |= 0x80;
491  if (gSystem) adr = 2; // illegal address
492  }
493  memcpy(fNode, seed, sizeof(fNode));
494  fTimeHiAndVersion |= (3 << 12); // version == 3: random node info
495 }
496 
497 ////////////////////////////////////////////////////////////////////////////////
498 /// Get random info based on some machine parameters.
499 
500 void TUUID::GetRandomInfo(UChar_t seed[16])
501 {
502 #ifdef R__WIN32
503  struct randomness {
504  MEMORYSTATUS m;
505  SYSTEM_INFO s;
506  FILETIME t;
507  LARGE_INTEGER pc;
508  DWORD tc;
509  DWORD l;
510  char hostname[MAX_COMPUTERNAME_LENGTH + 1];
511  };
512  randomness r;
513  memset(&r, 0, sizeof(r)); // zero also padding bytes
514 
515  // memory usage stats
516  GlobalMemoryStatus(&r.m);
517  // random system stats
518  GetSystemInfo(&r.s);
519  // 100ns resolution time of day
520  GetSystemTimeAsFileTime(&r.t);
521  // high resolution performance counter
522  QueryPerformanceCounter(&r.pc);
523  // milliseconds since last boot
524  r.tc = GetTickCount();
525  r.l = MAX_COMPUTERNAME_LENGTH + 1;
526  GetComputerName(r.hostname, &r.l);
527 #else
528  struct randomness {
529 #if defined(R__LINUX) && !defined(R__WINGCC)
530  struct sysinfo s;
531 #endif
532  struct timeval t;
533  char hostname[257];
534  };
535  randomness r;
536  memset(&r, 0, sizeof(r)); // zero also padding bytes
537 
538 #if defined(R__LINUX) && !defined(R__WINGCC)
539  sysinfo(&r.s);
540 #endif
541  gettimeofday(&r.t, 0);
542  gethostname(r.hostname, 256);
543 #endif
544  TMD5 md5;
545  md5.Update((UChar_t *)&r, sizeof(randomness));
546  md5.Final(seed);
547 }
548 
549 ////////////////////////////////////////////////////////////////////////////////
550 /// Print UUID.
551 
552 void TUUID::Print() const
553 {
554  printf("%s\n", AsString());
555 }
556 
557 ////////////////////////////////////////////////////////////////////////////////
558 /// Return UUID as string. Copy string immediately since it will be reused.
559 
560 const char *TUUID::AsString() const
561 {
562  static char uuid[40];
563 
564  snprintf(uuid,40, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
565  fTimeLow, fTimeMid, fTimeHiAndVersion, fClockSeqHiAndReserved,
566  fClockSeqLow, fNode[0], fNode[1], fNode[2], fNode[3], fNode[4],
567  fNode[5]);
568 
569  return uuid;
570 }
571 
572 ////////////////////////////////////////////////////////////////////////////////
573 /// Compute 16-bit hash value of the UUID.
574 
575 UShort_t TUUID::Hash() const
576 {
577  Short_t c0 = 0, c1 = 0, x, y;
578  char *c = (char *) &fTimeLow;
579 
580  // For speed lets unroll the following loop:
581  // for (i = 0; i < 16; i++) {
582  // c0 += *c++;
583  // c1 += c0;
584  // }
585 
586  c0 += *c++; c1 += c0;
587  c0 += *c++; c1 += c0;
588  c0 += *c++; c1 += c0;
589  c0 += *c++; c1 += c0;
590 
591  c0 += *c++; c1 += c0;
592  c0 += *c++; c1 += c0;
593  c0 += *c++; c1 += c0;
594  c0 += *c++; c1 += c0;
595 
596  c0 += *c++; c1 += c0;
597  c0 += *c++; c1 += c0;
598  c0 += *c++; c1 += c0;
599  c0 += *c++; c1 += c0;
600 
601  c0 += *c++; c1 += c0;
602  c0 += *c++; c1 += c0;
603  c0 += *c++; c1 += c0;
604  c0 += *c++; c1 += c0;
605 
606  // Calculate the value for "First octet" of the hash
607  x = -c1 % 255;
608  if (x < 0)
609  x += 255;
610 
611  // Calculate the value for "second octet" of the hash
612  y = (c1 - c0) % 255;
613  if (y < 0)
614  y += 255;
615 
616  return UShort_t((y << 8) + x);
617 }
618 
619 ////////////////////////////////////////////////////////////////////////////////
620 /// Compare two UUIDs "lexically" and return
621 /// - -1 this is lexically before u
622 /// - 0 this is equal to u
623 /// - 1 this is lexically after u
624 
625 Int_t TUUID::Compare(const TUUID &u) const
626 {
627 #define CHECK(f1, f2) if (f1 != f2) return f1 < f2 ? -1 : 1;
628  CHECK(fTimeLow, u.fTimeLow)
629  CHECK(fTimeMid, u.fTimeMid)
630  CHECK(fTimeHiAndVersion, u.fTimeHiAndVersion)
631  CHECK(fClockSeqHiAndReserved, u.fClockSeqHiAndReserved)
632  CHECK(fClockSeqLow, u.fClockSeqLow)
633  for (int i = 0; i < 6; i++) {
634  if (fNode[i] < u.fNode[i])
635  return -1;
636  if (fNode[i] > u.fNode[i])
637  return 1;
638  }
639  return 0;
640 }
641 
642 ////////////////////////////////////////////////////////////////////////////////
643 /// Get address of host encoded in UUID. If host id is not an ethernet
644 /// address, but random info, then the returned TInetAddress is not valid.
645 
646 TInetAddress TUUID::GetHostAddress() const
647 {
648  if ((fTimeHiAndVersion >> 12) == 1) {
649  UInt_t addr;
650  memcpy(&addr, fNode, 4);
651  return TInetAddress("????", addr, 0);
652  }
653  return TInetAddress();
654 }
655 
656 ////////////////////////////////////////////////////////////////////////////////
657 /// Get time from UUID.
658 
659 TDatime TUUID::GetTime() const
660 {
661  TDatime dt;
662  uuid_time_t ts;
663 
664  ts.low = fTimeLow;
665  ts.high = (UInt_t)fTimeMid;
666  ts.high |= (UInt_t)((fTimeHiAndVersion & 0x0FFF) << 16);
667 
668  // Offset between UUID formatted times and Unix formatted times.
669  // UUID UTC base time is October 15, 1582.
670  // Unix base time is January 1, 1970.
671  ULong64_t high = ts.high;
672  ULong64_t uuid_time = (high << 32) + ts.low;
673  uuid_time -= 0x01B21DD213814000LL;
674  uuid_time /= 10000000LL;
675  UInt_t tt = (UInt_t) uuid_time;
676  dt.Set(tt);
677 
678  return dt;
679 }
680 
681 ////////////////////////////////////////////////////////////////////////////////
682 /// Return uuid in specified buffer (16 byte = 128 bits).
683 
684 void TUUID::GetUUID(UChar_t uuid[16]) const
685 {
686  memcpy(uuid, &fTimeLow, 16);
687 }
688 
689 ////////////////////////////////////////////////////////////////////////////////
690 /// Set this UUID to the value specified in uuid ((which must be in
691 /// TUUID::AsString() format).
692 
693 void TUUID::SetUUID(const char *uuid)
694 {
695  if (!uuid || !*uuid)
696  Error("SetUUID", "null string not allowed");
697  else
698  SetFromString(uuid);
699 }
700 
701 ////////////////////////////////////////////////////////////////////////////////
702 /// Input operator. Delegate to Streamer.
703 
704 TBuffer &operator<<(TBuffer &buf, const TUUID &uuid)
705 {
706  R__ASSERT( buf.IsWriting() );
707 
708  const_cast<TUUID&>(uuid).Streamer(buf);
709  return buf;
710 }