Utilise new MergeSym feature to no longer overwrite the source .DEF file when buildin...
[openh323.git] / src / guid.cxx
blobaf30663cfb671ae784ea883a8bf8b10512e175b5
1 /*
2 * guid.cxx
4 * Globally Unique Identifier
6 * Open H323 Library
8 * Copyright (c) 1998-2001 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
20 * The Original Code is Open H323 Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): ______________________________________.
26 * $Log$
27 * Revision 1.15 2003/04/15 03:04:08 robertj
28 * Fixed string constructor being able to build non null GUID.
30 * Revision 1.14 2002/10/10 05:33:18 robertj
31 * VxWorks port, thanks Martijn Roest
33 * Revision 1.13 2002/08/05 10:03:47 robertj
34 * Cosmetic changes to normalise the usage of pragma interface/implementation.
36 * Revision 1.12 2001/10/03 03:18:29 robertj
37 * Changed to only get (or fake) MAC address once.
39 * Revision 1.11 2001/04/05 01:45:13 robertj
40 * Fixed MSVC warning.
42 * Revision 1.10 2001/04/04 07:46:13 robertj
43 * Fixed erros in rading GUID hex string.
45 * Revision 1.9 2001/04/04 06:46:39 robertj
46 * Fixed errors in time calculation used in GUID.
48 * Revision 1.8 2001/03/19 05:52:24 robertj
49 * Fixed problem with reading a GUID if there is leading white space.
50 * If get error reading GUID then set the stream fail bit.
52 * Revision 1.7 2001/03/15 00:25:12 robertj
53 * Fixed problem with hex output sign extending unsigned values.
55 * Revision 1.6 2001/03/14 05:03:37 robertj
56 * Fixed printing of GUID to have bytes as hex instead of characters.
58 * Revision 1.5 2001/03/03 00:54:48 yurik
59 * Proper fix for filetime routines used in guid calc done for WinCE
61 * Revision 1.4 2001/03/02 23:25:49 yurik
62 * fixed typo
64 * Revision 1.3 2001/03/02 22:50:37 yurik
65 * Used PTime for WinCE port instead of non-portable function
67 * Revision 1.2 2001/03/02 07:17:41 robertj
68 * Compensated for stupid GNU compiler bug.
70 * Revision 1.1 2001/03/02 06:59:59 robertj
71 * Enhanced the globally unique identifier class.
75 #include <ptlib.h>
77 #ifdef __GNUC__
78 #pragma implementation "guid.h"
79 #endif
81 #include "guid.h"
83 #include <ptlib/sockets.h>
84 #include <ptclib/random.h>
85 #include <ptclib/asner.h>
88 #define GUID_SIZE 16
91 ///////////////////////////////////////////////////////////////////////////////
93 OpalGloballyUniqueID::OpalGloballyUniqueID()
94 : PBYTEArray(GUID_SIZE)
96 // Want time of UTC in 0.1 microseconds since 15 Oct 1582.
97 PInt64 timestamp;
98 static PInt64 deltaTime = PInt64(10000000)*24*60*60*
99 ( 16 // Days from 15th October
100 + 31 // Days in December 1583
101 + 30 // Days in November 1583
102 #ifdef _WIN32
103 + (1601-1583)*365 // Whole years
104 + (1601-1583)/4); // Leap days
106 // Get nanoseconds since 1601
107 #ifndef _WIN32_WCE
108 GetSystemTimeAsFileTime((LPFILETIME)&timestamp);
109 #else
110 SYSTEMTIME SystemTime;
111 GetSystemTime(&SystemTime);
112 SystemTimeToFileTime(&SystemTime, (LPFILETIME)&timestamp);
113 #endif // _WIN32_WCE
115 timestamp /= 100;
116 #else // _WIN32
117 + (1970-1583)*365 // Days in years
118 + (1970-1583)/4 // Leap days
119 - 3); // Allow for 1700, 1800, 1900 not leap years
121 #ifdef P_VXWORKS
122 struct timespec ts;
123 clock_gettime(0,&ts);
124 timestamp = (ts.tv_sec*(PInt64)1000000 + ts.tv_nsec*1000)*10;
125 #else
126 struct timeval tv;
127 gettimeofday(&tv, NULL);
128 timestamp = (tv.tv_sec*(PInt64)1000000 + tv.tv_usec)*10;
129 #endif // P_VXWORKS
130 #endif // _WIN32
132 timestamp += deltaTime;
134 theArray[0] = (BYTE)(timestamp&0xff);
135 theArray[1] = (BYTE)((timestamp>>8)&0xff);
136 theArray[2] = (BYTE)((timestamp>>16)&0xff);
137 theArray[3] = (BYTE)((timestamp>>24)&0xff);
138 theArray[4] = (BYTE)((timestamp>>32)&0xff);
139 theArray[5] = (BYTE)((timestamp>>40)&0xff);
140 theArray[6] = (BYTE)((timestamp>>48)&0xff);
141 theArray[7] = (BYTE)(((timestamp>>56)&0x0f) + 0x10); // Version number is 1
143 static WORD clockSequence = (WORD)PRandom::Number();
144 static PInt64 lastTimestamp = 0;
145 if (lastTimestamp < timestamp)
146 lastTimestamp = timestamp;
147 else
148 clockSequence++;
150 theArray[8] = (BYTE)(((clockSequence>>8)&0x1f) | 0x80); // DCE compatible GUID
151 theArray[9] = (BYTE)clockSequence;
153 static PEthSocket::Address macAddress;
154 static BOOL needMacAddress = TRUE;
155 if (needMacAddress) {
156 PIPSocket::InterfaceTable interfaces;
157 if (PIPSocket::GetInterfaceTable(interfaces)) {
158 for (PINDEX i = 0; i < interfaces.GetSize(); i++) {
159 PString macAddrStr = interfaces[i].GetMACAddress();
160 if (!macAddrStr && macAddrStr != "44-45-53-54-00-00") { /* not Win32 PPP device */
161 macAddress = macAddrStr;
162 if (macAddress != NULL) {
163 needMacAddress = FALSE;
164 break;
170 if (needMacAddress) {
171 PRandom rand;
172 macAddress.ls.l = rand;
173 macAddress.ls.s = (WORD)rand;
174 macAddress.b[0] |= '\x80';
176 needMacAddress = FALSE;
180 memcpy(theArray+10, macAddress.b, 6);
184 OpalGloballyUniqueID::OpalGloballyUniqueID(const char * cstr)
185 : PBYTEArray(GUID_SIZE)
187 if (cstr != NULL && *cstr != '\0') {
188 PStringStream strm(cstr);
189 ReadFrom(strm);
194 OpalGloballyUniqueID::OpalGloballyUniqueID(const PString & str)
195 : PBYTEArray(GUID_SIZE)
197 PStringStream strm(str);
198 ReadFrom(strm);
202 OpalGloballyUniqueID::OpalGloballyUniqueID(const PASN_OctetString & newId)
203 : PBYTEArray(newId)
205 PAssert(GetSize() == GUID_SIZE, PInvalidParameter);
206 SetSize(GUID_SIZE);
210 PObject * OpalGloballyUniqueID::Clone() const
212 PAssert(GetSize() == GUID_SIZE, "OpalGloballyUniqueID is invalid size");
214 return new OpalGloballyUniqueID(*this);
218 PINDEX OpalGloballyUniqueID::HashFunction() const
220 PAssert(GetSize() == GUID_SIZE, "OpalGloballyUniqueID is invalid size");
222 DWORD * words = (DWORD *)theArray;
223 DWORD sum = words[0] + words[1] + words[2] + words[3];
224 return ((sum >> 25)+(sum >> 15)+sum)%23;
228 void OpalGloballyUniqueID::PrintOn(ostream & strm) const
230 PAssert(GetSize() == GUID_SIZE, "OpalGloballyUniqueID is invalid size");
232 char fillchar = strm.fill();
233 strm << hex << setfill('0')
234 << setw(2) << (unsigned)(BYTE)theArray[0]
235 << setw(2) << (unsigned)(BYTE)theArray[1]
236 << setw(2) << (unsigned)(BYTE)theArray[2]
237 << setw(2) << (unsigned)(BYTE)theArray[3] << '-'
238 << setw(2) << (unsigned)(BYTE)theArray[4]
239 << setw(2) << (unsigned)(BYTE)theArray[5] << '-'
240 << setw(2) << (unsigned)(BYTE)theArray[6]
241 << setw(2) << (unsigned)(BYTE)theArray[7] << '-'
242 << setw(2) << (unsigned)(BYTE)theArray[8]
243 << setw(2) << (unsigned)(BYTE)theArray[9] << '-'
244 << setw(2) << (unsigned)(BYTE)theArray[10]
245 << setw(2) << (unsigned)(BYTE)theArray[11]
246 << setw(2) << (unsigned)(BYTE)theArray[12]
247 << setw(2) << (unsigned)(BYTE)theArray[13]
248 << setw(2) << (unsigned)(BYTE)theArray[14]
249 << setw(2) << (unsigned)(BYTE)theArray[15]
250 << dec << setfill(fillchar);
254 void OpalGloballyUniqueID::ReadFrom(istream & strm)
256 PAssert(GetSize() == GUID_SIZE, "OpalGloballyUniqueID is invalid size");
257 SetSize(16);
259 strm >> ws;
261 PINDEX count = 0;
263 while (count < 2*GUID_SIZE) {
264 if (isxdigit(strm.peek())) {
265 char digit = (char)(strm.get() - '0');
266 if (digit >= 10) {
267 digit -= 'A'-('9'+1);
268 if (digit >= 16)
269 digit -= 'a'-'A';
271 theArray[count/2] = (BYTE)((theArray[count/2] << 4) | digit);
272 count++;
274 else if (strm.peek() == '-') {
275 if (count != 8 && count != 12 && count != 16 && count != 20)
276 break;
277 strm.get(); // Ignore the dash if it was in the right place
279 else
280 break;
283 if (count < 2*GUID_SIZE) {
284 memset(theArray, 0, GUID_SIZE);
285 strm.clear(ios::failbit);
290 PString OpalGloballyUniqueID::AsString() const
292 PStringStream strm;
293 PrintOn(strm);
294 return strm;
298 BOOL OpalGloballyUniqueID::IsNULL() const
300 PAssert(GetSize() == GUID_SIZE, "OpalGloballyUniqueID is invalid size");
302 return memcmp(theArray, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0;
306 /////////////////////////////////////////////////////////////////////////////