Fixed DevStudio 2003 build with memory check code.
[pwlib.git] / src / ptclib / guid.cxx
blob6b0f8798ef6d14ed7aa254c08332391f3b361ab5
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.2 2007/07/20 01:40:23 csoutheren
28 * Ignore spaces in GUID strings
30 * Revision 1.1 2006/09/20 05:03:41 csoutheren
31 * Migrated GUID functions to PWLib
33 * Revision 2.4 2004/02/19 10:47:06 rjongbloed
34 * Merged OpenH323 version 1.13.1 changes.
36 * Revision 2.3 2002/11/10 11:33:19 robertj
37 * Updated to OpenH323 v1.10.3
39 * Revision 2.2 2002/09/04 06:01:49 robertj
40 * Updated to OpenH323 v1.9.6
42 * Revision 2.1 2001/10/05 00:22:14 robertj
43 * Updated to PWLib 1.2.0 and OpenH323 1.7.0
45 * Revision 2.0 2001/07/27 15:48:25 robertj
46 * Conversion of OpenH323 to Open Phone Abstraction Library (OPAL)
48 * Revision 1.15 2003/04/15 03:04:08 robertj
49 * Fixed string constructor being able to build non null GUID.
51 * Revision 1.14 2002/10/10 05:33:18 robertj
52 * VxWorks port, thanks Martijn Roest
54 * Revision 1.13 2002/08/05 10:03:47 robertj
55 * Cosmetic changes to normalise the usage of pragma interface/implementation.
57 * Revision 1.12 2001/10/03 03:18:29 robertj
58 * Changed to only get (or fake) MAC address once.
60 * Revision 1.11 2001/04/05 01:45:13 robertj
61 * Fixed MSVC warning.
63 * Revision 1.10 2001/04/04 07:46:13 robertj
64 * Fixed erros in rading GUID hex string.
66 * Revision 1.9 2001/04/04 06:46:39 robertj
67 * Fixed errors in time calculation used in GUID.
69 * Revision 1.8 2001/03/19 05:52:24 robertj
70 * Fixed problem with reading a GUID if there is leading white space.
71 * If get error reading GUID then set the stream fail bit.
73 * Revision 1.7 2001/03/15 00:25:12 robertj
74 * Fixed problem with hex output sign extending unsigned values.
76 * Revision 1.6 2001/03/14 05:03:37 robertj
77 * Fixed printing of GUID to have bytes as hex instead of characters.
79 * Revision 1.5 2001/03/03 00:54:48 yurik
80 * Proper fix for filetime routines used in guid calc done for WinCE
82 * Revision 1.4 2001/03/02 23:25:49 yurik
83 * fixed typo
85 * Revision 1.3 2001/03/02 22:50:37 yurik
86 * Used PTime for WinCE port instead of non-portable function
88 * Revision 1.2 2001/03/02 07:17:41 robertj
89 * Compensated for stupid GNU compiler bug.
91 * Revision 1.1 2001/03/02 06:59:59 robertj
92 * Enhanced the globally unique identifier class.
96 #include <ptlib.h>
98 #ifdef __GNUC__
99 #pragma implementation "guid.h"
100 #endif
102 #include <ptclib/guid.h>
104 #include <ptlib/sockets.h>
105 #include <ptclib/random.h>
106 #include <ptclib/asner.h>
109 #define new PNEW
111 #define GUID_SIZE 16
114 ///////////////////////////////////////////////////////////////////////////////
116 PGloballyUniqueID::PGloballyUniqueID()
117 : PBYTEArray(GUID_SIZE)
119 // Want time of UTC in 0.1 microseconds since 15 Oct 1582.
120 PInt64 timestamp;
121 static PInt64 deltaTime = PInt64(10000000)*24*60*60*
122 ( 16 // Days from 15th October
123 + 31 // Days in December 1583
124 + 30 // Days in November 1583
125 #ifdef _WIN32
126 + (1601-1583)*365 // Whole years
127 + (1601-1583)/4); // Leap days
129 // Get nanoseconds since 1601
130 #ifndef _WIN32_WCE
131 GetSystemTimeAsFileTime((LPFILETIME)&timestamp);
132 #else
133 SYSTEMTIME SystemTime;
134 GetSystemTime(&SystemTime);
135 SystemTimeToFileTime(&SystemTime, (LPFILETIME)&timestamp);
136 #endif // _WIN32_WCE
138 timestamp /= 100;
139 #else // _WIN32
140 + (1970-1583)*365 // Days in years
141 + (1970-1583)/4 // Leap days
142 - 3); // Allow for 1700, 1800, 1900 not leap years
144 #ifdef P_VXWORKS
145 struct timespec ts;
146 clock_gettime(0,&ts);
147 timestamp = (ts.tv_sec*(PInt64)1000000 + ts.tv_nsec*1000)*10;
148 #else
149 struct timeval tv;
150 gettimeofday(&tv, NULL);
151 timestamp = (tv.tv_sec*(PInt64)1000000 + tv.tv_usec)*10;
152 #endif // P_VXWORKS
153 #endif // _WIN32
155 timestamp += deltaTime;
157 theArray[0] = (BYTE)(timestamp&0xff);
158 theArray[1] = (BYTE)((timestamp>>8)&0xff);
159 theArray[2] = (BYTE)((timestamp>>16)&0xff);
160 theArray[3] = (BYTE)((timestamp>>24)&0xff);
161 theArray[4] = (BYTE)((timestamp>>32)&0xff);
162 theArray[5] = (BYTE)((timestamp>>40)&0xff);
163 theArray[6] = (BYTE)((timestamp>>48)&0xff);
164 theArray[7] = (BYTE)(((timestamp>>56)&0x0f) + 0x10); // Version number is 1
166 static WORD clockSequence = (WORD)PRandom::Number();
167 static PInt64 lastTimestamp = 0;
168 if (lastTimestamp < timestamp)
169 lastTimestamp = timestamp;
170 else
171 clockSequence++;
173 theArray[8] = (BYTE)(((clockSequence>>8)&0x1f) | 0x80); // DCE compatible GUID
174 theArray[9] = (BYTE)clockSequence;
176 static PEthSocket::Address macAddress;
177 static BOOL needMacAddress = TRUE;
178 if (needMacAddress) {
179 PIPSocket::InterfaceTable interfaces;
180 if (PIPSocket::GetInterfaceTable(interfaces)) {
181 for (PINDEX i = 0; i < interfaces.GetSize(); i++) {
182 PString macAddrStr = interfaces[i].GetMACAddress();
183 if (!macAddrStr && macAddrStr != "44-45-53-54-00-00") { /* not Win32 PPP device */
184 macAddress = macAddrStr;
185 if (macAddress != NULL) {
186 needMacAddress = FALSE;
187 break;
193 if (needMacAddress) {
194 PRandom rand;
195 macAddress.ls.l = rand;
196 macAddress.ls.s = (WORD)rand;
197 macAddress.b[0] |= '\x80';
199 needMacAddress = FALSE;
203 memcpy(theArray+10, macAddress.b, 6);
207 PGloballyUniqueID::PGloballyUniqueID(const char * cstr)
208 : PBYTEArray(GUID_SIZE)
210 if (cstr != NULL && *cstr != '\0') {
211 PStringStream strm(cstr);
212 ReadFrom(strm);
217 PGloballyUniqueID::PGloballyUniqueID(const PString & str)
218 : PBYTEArray(GUID_SIZE)
220 PStringStream strm(str);
221 ReadFrom(strm);
225 PGloballyUniqueID::PGloballyUniqueID(const PASN_OctetString & newId)
226 : PBYTEArray(newId)
228 PAssert(GetSize() == GUID_SIZE, PInvalidParameter);
229 SetSize(GUID_SIZE);
233 PObject * PGloballyUniqueID::Clone() const
235 PAssert(GetSize() == GUID_SIZE, "PGloballyUniqueID is invalid size");
237 return new PGloballyUniqueID(*this);
241 PINDEX PGloballyUniqueID::HashFunction() const
243 PAssert(GetSize() == GUID_SIZE, "PGloballyUniqueID is invalid size");
245 DWORD * words = (DWORD *)theArray;
246 DWORD sum = words[0] + words[1] + words[2] + words[3];
247 return ((sum >> 25)+(sum >> 15)+sum)%23;
251 void PGloballyUniqueID::PrintOn(ostream & strm) const
253 PAssert(GetSize() == GUID_SIZE, "PGloballyUniqueID is invalid size");
255 char fillchar = strm.fill();
256 strm << hex << setfill('0')
257 << setw(2) << (unsigned)(BYTE)theArray[0]
258 << setw(2) << (unsigned)(BYTE)theArray[1]
259 << setw(2) << (unsigned)(BYTE)theArray[2]
260 << setw(2) << (unsigned)(BYTE)theArray[3] << '-'
261 << setw(2) << (unsigned)(BYTE)theArray[4]
262 << setw(2) << (unsigned)(BYTE)theArray[5] << '-'
263 << setw(2) << (unsigned)(BYTE)theArray[6]
264 << setw(2) << (unsigned)(BYTE)theArray[7] << '-'
265 << setw(2) << (unsigned)(BYTE)theArray[8]
266 << setw(2) << (unsigned)(BYTE)theArray[9] << '-'
267 << setw(2) << (unsigned)(BYTE)theArray[10]
268 << setw(2) << (unsigned)(BYTE)theArray[11]
269 << setw(2) << (unsigned)(BYTE)theArray[12]
270 << setw(2) << (unsigned)(BYTE)theArray[13]
271 << setw(2) << (unsigned)(BYTE)theArray[14]
272 << setw(2) << (unsigned)(BYTE)theArray[15]
273 << dec << setfill(fillchar);
277 void PGloballyUniqueID::ReadFrom(istream & strm)
279 PAssert(GetSize() == GUID_SIZE, "PGloballyUniqueID is invalid size");
280 SetSize(16);
282 strm >> ws;
284 PINDEX count = 0;
286 while (count < 2*GUID_SIZE) {
287 if (isxdigit(strm.peek())) {
288 char digit = (char)(strm.get() - '0');
289 if (digit >= 10) {
290 digit -= 'A'-('9'+1);
291 if (digit >= 16)
292 digit -= 'a'-'A';
294 theArray[count/2] = (BYTE)((theArray[count/2] << 4) | digit);
295 count++;
297 else if (strm.peek() == '-') {
298 if (count != 8 && count != 12 && count != 16 && count != 20)
299 break;
300 strm.get(); // Ignore the dash if it was in the right place
302 else if (strm.peek() == ' ')
303 strm.get(); // Ignore spaces
304 else
305 break;
308 if (count < 2*GUID_SIZE) {
309 memset(theArray, 0, GUID_SIZE);
310 strm.clear(ios::failbit);
315 PString PGloballyUniqueID::AsString() const
317 PStringStream strm;
318 PrintOn(strm);
319 return strm;
323 BOOL PGloballyUniqueID::IsNULL() const
325 PAssert(GetSize() == GUID_SIZE, "PGloballyUniqueID is invalid size");
327 return memcmp(theArray, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0;
331 /////////////////////////////////////////////////////////////////////////////