1
/** NSUUID - Representation of universally unique identifiers.
2
Copyright (C) 2013 Free Software Foundation, Inc.
4
Written by: Graham Lee <graham@iamleeg.com>
7
This file is part of the GNUstep Base Library.
9
This library is free software; you can redistribute it and/or
10
modify it under the terms of the GNU Lesser General Public
11
License as published by the Free Software Foundation; either
12
version 2 of the License, or (at your option) any later version.
14
This library is distributed in the hope that it will be useful,
15
but WITHOUT ANY WARRANTY; without even the implied warranty of
16
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
Library General Public License for more details.
19
You should have received a copy of the GNU Lesser General Public
20
License along with this library; if not, write to the Free
21
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27
#import "Foundation/NSCoder.h"
28
#import "Foundation/NSUUID.h"
30
#if defined(__MINGW32__)
36
static int uuid_from_string(const char *string, unsigned char *uuid);
37
static void string_from_uuid(const unsigned char *uuid, char *string);
38
static int random_uuid(unsigned char *uuid);
40
static const int kUUIDStringLength = 36;
41
static const int kUnformattedUUIDStringLength = 32;
42
static const int kUUIDByteCount = 16;
46
* A representation of universally unique identifiers (UUIDs).
48
@implementation NSUUID
54
u = [[self alloc] init];
55
return AUTORELEASE(u);
63
result = random_uuid(localUUID);
69
return [self initWithUUIDBytes: localUUID];
72
- (id) initWithUUIDString: (NSString *)string
78
cString = [string cStringUsingEncoding: NSASCIIStringEncoding];
79
parseResult = uuid_from_string(cString, localUUID);
85
return [self initWithUUIDBytes: localUUID];
88
- (id) initWithUUIDBytes: (gsuuid_t)bytes
90
if (nil != (self = [super init]))
92
memcpy(self->uuid, bytes, kUUIDByteCount);
97
- (NSString *)UUIDString
99
char uuidChars[kUUIDStringLength + 1];
102
string_from_uuid(uuid, uuidChars);
103
string = [[NSString alloc] initWithCString: uuidChars
104
encoding: NSASCIIStringEncoding];
105
return AUTORELEASE(string);
108
- (void) getUUIDBytes: (gsuuid_t)bytes
110
memcpy(bytes, uuid, kUUIDByteCount);
113
- (BOOL) isEqual: (NSUUID *)other
117
if (![other isKindOfClass: [NSUUID class]])
121
comparison = memcmp(self->uuid, other->uuid, kUUIDByteCount);
122
return (comparison == 0) ? YES : NO;
127
// more expensive than casting but that's not alignment-safe
128
NSUInteger uintegerArray[kUUIDByteCount/sizeof(NSUInteger)];
132
memcpy(uintegerArray, uuid, kUUIDByteCount);
133
for (i = 0; i < kUUIDByteCount/sizeof(NSUInteger); i++)
135
hash ^= uintegerArray[i];
140
- (id) copyWithZone: (NSZone *)zone
145
static NSString *uuidKey = @"uuid";
147
- (void) encodeWithCoder: (NSCoder *)aCoder
149
if ([aCoder allowsKeyedCoding])
151
[aCoder encodeBytes: uuid length: kUUIDByteCount forKey: uuidKey];
155
[aCoder encodeBytes: uuid length: kUUIDByteCount];
159
- (id) initWithCoder: (NSCoder *)aDecoder
161
if (nil != (self = [super init]))
163
NSUInteger decodedLength = 0;
164
const uint8_t *decodedUUID;
166
if ([aDecoder allowsKeyedCoding])
168
decodedUUID = [aDecoder decodeBytesForKey: uuidKey
169
returnedLength: &decodedLength];
174
= [aDecoder decodeBytesWithReturnedLength: &decodedLength];
176
if (decodedLength == kUUIDByteCount)
178
memcpy(uuid, decodedUUID, kUUIDByteCount);
190
static int uuid_from_string(const char *string, unsigned char *uuid)
192
char unformatted[kUnformattedUUIDStringLength];
195
if (strlen(string) != kUUIDStringLength)
199
for (i = 0; i < kUUIDStringLength; i++)
203
if ((i == 8) || (i == 13) || (i == 18) || (i == 23))
218
strncpy(unformatted, string, 8);
219
strncpy(unformatted+8, string+9, 4);
220
strncpy(unformatted+12, string+14, 4);
221
strncpy(unformatted+16, string+19, 4);
222
strncpy(unformatted+20, string+24, 12);
224
for (i = 0; i < kUUIDByteCount; i++)
228
thisDigit[0] = unformatted[2*i];
229
thisDigit[1] = unformatted[2*i+1];
231
uuid[i] = strtoul(thisDigit, NULL, kUUIDByteCount);
237
static void string_from_uuid(const unsigned char *uuid, char *string)
239
char unformatted[kUnformattedUUIDStringLength];
242
for (i = 0; i < kUUIDByteCount; i++)
244
unsigned char byte = uuid[i];
246
snprintf(thisPair, 3, "%02X", byte);
247
strncpy(unformatted + 2*i, thisPair, 2);
249
strncpy(string, unformatted, 8);
251
strncpy(string + 9, unformatted + 8, 4);
253
strncpy(string + 14, unformatted + 12, 4);
255
strncpy(string + 19, unformatted + 16, 4);
257
strncpy(string + 24, unformatted + 20, 12);
258
string[kUUIDStringLength] = '\0';
261
static int random_uuid(unsigned char *uuid)
263
unsigned char timeByte;
264
unsigned char sequenceByte;
266
/* Only supporting Version 4 UUIDs (see RFC4412, section 4.4),
267
* consistent with Apple. Other variants suffer from privacy
268
* problems (and are more work...)
271
#if defined(__MINGW32__)
273
HCRYPTPROV hProvider = 0;
275
if (!CryptAcquireContextW(&hProvider, 0, 0,
276
PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
281
if (!CryptGenRandom(hProvider, kUUIDByteCount, uuid))
283
CryptReleaseContext(hProvider, 0);
287
CryptReleaseContext(hProvider, 0);
293
devUrandom = open("/dev/urandom", O_RDONLY);
294
if (devUrandom == -1)
298
bytesRead = read(devUrandom, uuid, kUUIDByteCount);
300
if (bytesRead != kUUIDByteCount)
306
/* as required by the RFC, bits 48-51 should contain 0b0100 (4)
307
* and bits 64-65 should contain 0b01 (1)
310
timeByte = (4 << 8) + (timeByte & 0x0f);
313
sequenceByte = uuid[8];
314
sequenceByte = (1 << 6) + (sequenceByte & 0x3f);
315
uuid[8] = sequenceByte;