mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-30 08:21:25 +00:00
iUUID for unix by leeg
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@37480 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
9944f1823f
commit
9b99122b0f
6 changed files with 506 additions and 0 deletions
280
Source/NSUUID.m
Normal file
280
Source/NSUUID.m
Normal file
|
@ -0,0 +1,280 @@
|
|||
/** NSUUID - Representation of universally unique identifiers.
|
||||
Copyright (C) 2013 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Graham Lee <graham@iamleeg.com>
|
||||
Created: November 2013
|
||||
|
||||
This file is part of the GNUstep Base Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02111 USA.
|
||||
|
||||
*/
|
||||
|
||||
#import "common.h"
|
||||
#import "Foundation/NSCoder.h"
|
||||
#import "Foundation/NSUUID.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
static int uuid_from_string(const char *string, unsigned char *uuid);
|
||||
static void string_from_uuid(const unsigned char *uuid, char *string);
|
||||
static int random_uuid(unsigned char *uuid);
|
||||
|
||||
static const int kUUIDStringLength = 36;
|
||||
static const int kUnformattedUUIDStringLength = 32;
|
||||
static const int kUUIDByteCount = 16;
|
||||
|
||||
|
||||
/**
|
||||
* A representation of universally unique identifiers (UUIDs).
|
||||
*/
|
||||
@implementation NSUUID
|
||||
|
||||
+ (id) UUID
|
||||
{
|
||||
id u;
|
||||
|
||||
u = [[self alloc] init];
|
||||
return AUTORELEASE(u);
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
uuid_t localUUID;
|
||||
int result;
|
||||
|
||||
result = random_uuid(localUUID);
|
||||
if (result != 0)
|
||||
{
|
||||
DESTROY(self);
|
||||
return nil;
|
||||
}
|
||||
return [self initWithUUIDBytes: localUUID];
|
||||
}
|
||||
|
||||
- (id) initWithUUIDString: (NSString *)string
|
||||
{
|
||||
uuid_t localUUID;
|
||||
const char *cString;
|
||||
int parseResult;
|
||||
|
||||
cString = [string cStringUsingEncoding: NSASCIIStringEncoding];
|
||||
parseResult = uuid_from_string(cString, localUUID);
|
||||
if (parseResult != 0)
|
||||
{
|
||||
DESTROY(self);
|
||||
return nil;
|
||||
}
|
||||
return [self initWithUUIDBytes: localUUID];
|
||||
}
|
||||
|
||||
- (id) initWithUUIDBytes: (uuid_t)bytes
|
||||
{
|
||||
if (nil != (self = [super init]))
|
||||
{
|
||||
memcpy(self->uuid, bytes, kUUIDByteCount);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)UUIDString
|
||||
{
|
||||
char uuidChars[kUUIDStringLength + 1];
|
||||
NSString *string;
|
||||
|
||||
string_from_uuid(uuid, uuidChars);
|
||||
string = [[NSString alloc] initWithCString: uuidChars
|
||||
encoding: NSASCIIStringEncoding];
|
||||
return AUTORELEASE(string);
|
||||
}
|
||||
|
||||
- (void) getUUIDBytes: (uuid_t)bytes
|
||||
{
|
||||
memcpy(bytes, uuid, kUUIDByteCount);
|
||||
}
|
||||
|
||||
- (BOOL) isEqual: (NSUUID *)other
|
||||
{
|
||||
if (![other isKindOfClass: [NSUUID class]])
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
int comparison = memcmp(self->uuid, other->uuid, kUUIDByteCount);
|
||||
return (comparison == 0) ? YES : NO;
|
||||
}
|
||||
|
||||
- (NSUInteger) hash
|
||||
{
|
||||
// more expensive than casting but that's not alignment-safe
|
||||
NSUInteger uintegerArray[kUUIDByteCount/sizeof(NSUInteger)];
|
||||
NSUInteger hash = 0;
|
||||
|
||||
memcpy(uintegerArray, uuid, kUUIDByteCount);
|
||||
for (int i = 0; i < kUUIDByteCount/sizeof(NSUInteger); i++)
|
||||
{
|
||||
hash ^= uintegerArray[i];
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
- (id) copyWithZone: (NSZone *)zone
|
||||
{
|
||||
return RETAIN(self);
|
||||
}
|
||||
|
||||
static NSString *uuidKey = @"uuid";
|
||||
|
||||
- (void) encodeWithCoder: (NSCoder *)aCoder
|
||||
{
|
||||
if ([aCoder allowsKeyedCoding])
|
||||
{
|
||||
[aCoder encodeBytes: uuid length: kUUIDByteCount forKey: uuidKey];
|
||||
}
|
||||
else
|
||||
{
|
||||
[aCoder encodeBytes: uuid length: kUUIDByteCount];
|
||||
}
|
||||
}
|
||||
|
||||
- (id) initWithCoder: (NSCoder *)aDecoder
|
||||
{
|
||||
if (nil != (self = [super init]))
|
||||
{
|
||||
NSUInteger decodedLength = 0;
|
||||
const uint8_t *decodedUUID;
|
||||
|
||||
if ([aDecoder allowsKeyedCoding])
|
||||
{
|
||||
decodedUUID = [aDecoder decodeBytesForKey: uuidKey
|
||||
returnedLength: &decodedLength];
|
||||
}
|
||||
else
|
||||
{
|
||||
decodedUUID
|
||||
= [aDecoder decodeBytesWithReturnedLength: &decodedLength];
|
||||
}
|
||||
if (decodedLength == kUUIDByteCount)
|
||||
{
|
||||
memcpy(uuid, decodedUUID, kUUIDByteCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
DESTROY(self);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
|
||||
static int uuid_from_string(const char *string, unsigned char *uuid)
|
||||
{
|
||||
char unformatted[kUnformattedUUIDStringLength];
|
||||
|
||||
if (strlen(string) != kUUIDStringLength)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
for (int i = 0; i < kUUIDStringLength; i++)
|
||||
{
|
||||
char c = string[i];
|
||||
|
||||
if ((i == 8) || (i == 13) || (i == 18) || (i == 23))
|
||||
{
|
||||
if (c != '-')
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!isxdigit(c))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
strncpy(unformatted, string, 8);
|
||||
strncpy(unformatted+8, string+9, 4);
|
||||
strncpy(unformatted+12, string+14, 4);
|
||||
strncpy(unformatted+16, string+19, 4);
|
||||
strncpy(unformatted+20, string+24, 12);
|
||||
|
||||
for (int i = 0; i < kUUIDByteCount; i++)
|
||||
{
|
||||
{
|
||||
char thisDigit[3];
|
||||
thisDigit[0] = unformatted[2*i];
|
||||
thisDigit[1] = unformatted[2*i+1];
|
||||
thisDigit[2] = 0;
|
||||
uuid[i] = strtoul(thisDigit, NULL, kUUIDByteCount);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void string_from_uuid(const unsigned char *uuid, char *string)
|
||||
{
|
||||
char unformatted[kUnformattedUUIDStringLength];
|
||||
|
||||
for (int i = 0; i < kUUIDByteCount; i++)
|
||||
{
|
||||
unsigned char byte = uuid[i];
|
||||
char thisPair[3];
|
||||
snprintf(thisPair, 3, "%02X", byte);
|
||||
strncpy(unformatted + 2*i, thisPair, 2);
|
||||
}
|
||||
strncpy(string, unformatted, 8);
|
||||
string[8] = '-';
|
||||
strncpy(string + 9, unformatted + 8, 4);
|
||||
string[13] = '-';
|
||||
strncpy(string + 14, unformatted + 12, 4);
|
||||
string[18] = '-';
|
||||
strncpy(string + 19, unformatted + 16, 4);
|
||||
string[23] = '-';
|
||||
strncpy(string + 24, unformatted + 20, 12);
|
||||
string[kUUIDStringLength] = '\0';
|
||||
}
|
||||
|
||||
static int random_uuid(unsigned char *uuid)
|
||||
{
|
||||
/*Only supporting Version 4 UUIDs (see RFC4412, section 4.4),
|
||||
*consistent with Apple. Other variants suffer from privacy
|
||||
*problems (and are more work...)
|
||||
*/
|
||||
int devUrandom = open("/dev/urandom", O_RDONLY);
|
||||
if (devUrandom == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
ssize_t bytesRead = read(devUrandom, uuid, kUUIDByteCount);
|
||||
close(devUrandom);
|
||||
if (bytesRead != kUUIDByteCount)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
// as required by the RFC, bits 48-51 should contain 0b0100 (4)
|
||||
// and bits 64-65 should contain 0b01 (1)
|
||||
unsigned char timeByte = uuid[6];
|
||||
timeByte = (4 << 8) + (timeByte & 0x0f);
|
||||
uuid[7] = timeByte;
|
||||
|
||||
unsigned char sequenceByte = uuid[8];
|
||||
sequenceByte = (1 << 6) + (sequenceByte & 0x3f);
|
||||
uuid[8] = sequenceByte;
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue