~ubuntu-branches/ubuntu/utopic/gnustep-base/utopic

« back to all changes in this revision

Viewing changes to Source/NSUUID.m

  • Committer: Package Import Robot
  • Author(s): Paul Gevers
  • Date: 2014-07-19 13:02:18 UTC
  • mfrom: (20.1.6 utopic-proposed)
  • Revision ID: package-import@ubuntu.com-20140719130218-pn967l7wzjjf90yi
Tags: 1.24.6-2ubuntu1
* debian/rules:
  - Print the config.log if configure fails to debug
    powerpc/ppc64el FTBFS. (LP: #1277975)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/** NSUUID - Representation of universally unique identifiers.
 
2
   Copyright (C) 2013 Free Software Foundation, Inc.
 
3
 
 
4
   Written by:  Graham Lee <graham@iamleeg.com>
 
5
   Created: November 2013
 
6
 
 
7
   This file is part of the GNUstep Base Library.
 
8
 
 
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.
 
13
 
 
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.
 
18
 
 
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,
 
22
   Boston, MA 02111 USA.
 
23
 
 
24
   */
 
25
 
 
26
#import "common.h"
 
27
#import "Foundation/NSCoder.h"
 
28
#import "Foundation/NSUUID.h"
 
29
 
 
30
#if     defined(__MINGW32__)
 
31
#include <wincrypt.h>
 
32
#else
 
33
#include <fcntl.h>
 
34
#endif
 
35
 
 
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);
 
39
 
 
40
static const int kUUIDStringLength = 36;
 
41
static const int kUnformattedUUIDStringLength = 32;
 
42
static const int kUUIDByteCount = 16;
 
43
 
 
44
 
 
45
/**
 
46
 * A representation of universally unique identifiers (UUIDs).
 
47
 */
 
48
@implementation NSUUID
 
49
 
 
50
+ (id) UUID
 
51
{
 
52
  id    u;
 
53
 
 
54
  u = [[self alloc] init];
 
55
  return AUTORELEASE(u);
 
56
}
 
57
 
 
58
- (id) init
 
59
{
 
60
  gsuuid_t      localUUID;
 
61
  int           result;
 
62
 
 
63
  result = random_uuid(localUUID);
 
64
  if (result != 0)
 
65
    {
 
66
      DESTROY(self);
 
67
      return nil;
 
68
    }
 
69
  return [self initWithUUIDBytes: localUUID];
 
70
}
 
71
 
 
72
- (id) initWithUUIDString: (NSString *)string
 
73
{
 
74
  gsuuid_t      localUUID;
 
75
  const char    *cString;
 
76
  int           parseResult;
 
77
 
 
78
  cString = [string cStringUsingEncoding: NSASCIIStringEncoding];
 
79
  parseResult = uuid_from_string(cString, localUUID);
 
80
  if (parseResult != 0)
 
81
    {
 
82
      DESTROY(self);
 
83
      return nil;
 
84
    }
 
85
  return [self initWithUUIDBytes: localUUID];
 
86
}
 
87
 
 
88
- (id) initWithUUIDBytes: (gsuuid_t)bytes
 
89
{
 
90
  if (nil != (self = [super init]))
 
91
    {
 
92
      memcpy(self->uuid, bytes, kUUIDByteCount);
 
93
    }
 
94
  return self;
 
95
}
 
96
 
 
97
- (NSString *)UUIDString
 
98
{
 
99
  char           uuidChars[kUUIDStringLength + 1];
 
100
  NSString      *string;
 
101
 
 
102
  string_from_uuid(uuid, uuidChars);
 
103
  string = [[NSString alloc] initWithCString: uuidChars
 
104
                                    encoding: NSASCIIStringEncoding];
 
105
  return AUTORELEASE(string);
 
106
}
 
107
 
 
108
- (void) getUUIDBytes: (gsuuid_t)bytes
 
109
{
 
110
  memcpy(bytes, uuid, kUUIDByteCount);
 
111
}
 
112
 
 
113
- (BOOL) isEqual: (NSUUID *)other
 
114
{
 
115
  int comparison;
 
116
 
 
117
  if (![other isKindOfClass: [NSUUID class]])
 
118
    {
 
119
      return NO;
 
120
    }
 
121
  comparison = memcmp(self->uuid, other->uuid, kUUIDByteCount);
 
122
  return (comparison == 0) ? YES : NO;
 
123
}
 
124
 
 
125
- (NSUInteger) hash
 
126
{
 
127
  // more expensive than casting but that's not alignment-safe
 
128
  NSUInteger    uintegerArray[kUUIDByteCount/sizeof(NSUInteger)];
 
129
  NSUInteger    hash = 0;
 
130
  int           i;
 
131
 
 
132
  memcpy(uintegerArray, uuid, kUUIDByteCount);
 
133
  for (i = 0; i < kUUIDByteCount/sizeof(NSUInteger); i++)
 
134
    {
 
135
      hash ^= uintegerArray[i];
 
136
    }
 
137
  return hash;
 
138
}
 
139
 
 
140
- (id) copyWithZone: (NSZone *)zone
 
141
{
 
142
  return RETAIN(self);
 
143
}
 
144
 
 
145
static NSString *uuidKey = @"uuid";
 
146
 
 
147
- (void) encodeWithCoder: (NSCoder *)aCoder
 
148
{
 
149
  if ([aCoder allowsKeyedCoding])
 
150
    {
 
151
      [aCoder encodeBytes: uuid length: kUUIDByteCount forKey: uuidKey];
 
152
    }
 
153
  else
 
154
    {
 
155
      [aCoder encodeBytes: uuid length: kUUIDByteCount];
 
156
    }
 
157
}
 
158
 
 
159
- (id) initWithCoder: (NSCoder *)aDecoder
 
160
{
 
161
  if (nil != (self = [super init]))
 
162
    {
 
163
      NSUInteger        decodedLength = 0;
 
164
      const uint8_t     *decodedUUID;
 
165
 
 
166
      if ([aDecoder allowsKeyedCoding])
 
167
        {
 
168
          decodedUUID = [aDecoder decodeBytesForKey: uuidKey
 
169
                                     returnedLength: &decodedLength];
 
170
        }
 
171
      else
 
172
        {
 
173
          decodedUUID
 
174
            = [aDecoder decodeBytesWithReturnedLength: &decodedLength];
 
175
        }
 
176
      if (decodedLength == kUUIDByteCount)
 
177
        {
 
178
          memcpy(uuid, decodedUUID, kUUIDByteCount);
 
179
        }
 
180
      else
 
181
        {
 
182
          DESTROY(self);
 
183
          return nil;
 
184
        }
 
185
    }
 
186
  return self;
 
187
}
 
188
@end
 
189
 
 
190
static int uuid_from_string(const char *string, unsigned char *uuid)
 
191
{
 
192
  char  unformatted[kUnformattedUUIDStringLength];
 
193
  int   i;
 
194
 
 
195
  if (strlen(string) != kUUIDStringLength)
 
196
    {
 
197
      return -1;
 
198
    }
 
199
  for (i = 0; i < kUUIDStringLength; i++)
 
200
    {
 
201
      char c = string[i];
 
202
 
 
203
      if ((i == 8) || (i == 13) || (i == 18) || (i == 23))
 
204
        {
 
205
          if (c != '-') 
 
206
            {
 
207
              return -1;
 
208
            }
 
209
        }
 
210
      else
 
211
        {
 
212
          if (!isxdigit(c))
 
213
            {
 
214
              return -1;
 
215
            }
 
216
        }
 
217
    }
 
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);
 
223
 
 
224
  for (i = 0; i < kUUIDByteCount; i++)
 
225
    {
 
226
      {
 
227
        char thisDigit[3];
 
228
        thisDigit[0] = unformatted[2*i];
 
229
        thisDigit[1] = unformatted[2*i+1];
 
230
        thisDigit[2] = 0;
 
231
        uuid[i] = strtoul(thisDigit, NULL, kUUIDByteCount);
 
232
      }
 
233
    }
 
234
  return 0;
 
235
}
 
236
 
 
237
static void string_from_uuid(const unsigned char *uuid, char *string)
 
238
{
 
239
  char  unformatted[kUnformattedUUIDStringLength];
 
240
  int   i;
 
241
 
 
242
  for (i = 0; i < kUUIDByteCount; i++)
 
243
    {
 
244
      unsigned char byte = uuid[i];
 
245
      char thisPair[3];
 
246
      snprintf(thisPair, 3, "%02X", byte);
 
247
      strncpy(unformatted + 2*i, thisPair, 2);
 
248
    }
 
249
  strncpy(string, unformatted, 8);
 
250
  string[8] = '-';
 
251
  strncpy(string + 9, unformatted + 8, 4);
 
252
  string[13] = '-';
 
253
  strncpy(string + 14, unformatted + 12, 4);
 
254
  string[18] = '-';
 
255
  strncpy(string + 19, unformatted + 16, 4);
 
256
  string[23] = '-';
 
257
  strncpy(string + 24, unformatted + 20, 12);
 
258
  string[kUUIDStringLength] = '\0';
 
259
}
 
260
 
 
261
static int random_uuid(unsigned char *uuid)
 
262
{
 
263
  unsigned char timeByte;
 
264
  unsigned char sequenceByte;
 
265
 
 
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...)
 
269
   */
 
270
 
 
271
#if     defined(__MINGW32__)
 
272
 
 
273
  HCRYPTPROV hProvider = 0;
 
274
 
 
275
  if (!CryptAcquireContextW(&hProvider, 0, 0,
 
276
    PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
 
277
    {
 
278
      return -1;
 
279
    }
 
280
 
 
281
  if (!CryptGenRandom(hProvider, kUUIDByteCount, uuid))
 
282
    {
 
283
      CryptReleaseContext(hProvider, 0);
 
284
      return -1;
 
285
    }
 
286
 
 
287
  CryptReleaseContext(hProvider, 0);
 
288
#else
 
289
 
 
290
  int           devUrandom;
 
291
  ssize_t       bytesRead;
 
292
 
 
293
  devUrandom = open("/dev/urandom", O_RDONLY);
 
294
  if (devUrandom == -1)
 
295
    {
 
296
      return -1;
 
297
    }
 
298
  bytesRead = read(devUrandom, uuid, kUUIDByteCount);
 
299
  close(devUrandom);
 
300
  if (bytesRead != kUUIDByteCount)
 
301
    {
 
302
      return -1;
 
303
    }
 
304
#endif
 
305
 
 
306
  /* as required by the RFC, bits 48-51 should contain 0b0100 (4)
 
307
   * and bits 64-65 should contain 0b01 (1)
 
308
   */
 
309
  timeByte = uuid[6];
 
310
  timeByte = (4 << 8) + (timeByte & 0x0f);
 
311
  uuid[7] = timeByte;
 
312
 
 
313
  sequenceByte = uuid[8];
 
314
  sequenceByte = (1 << 6) + (sequenceByte & 0x3f);
 
315
  uuid[8] = sequenceByte;
 
316
 
 
317
  return 0;
 
318
}