File Coverage

blib/lib/Prophet/TempUUIDTiny.pm
Criterion Covered Total %
statement 86 240 35.8
branch 0 62 0.0
condition 0 8 0.0
subroutine 29 50 58.0
pod 10 10 100.0
total 125 370 33.7


line stmt bran cond sub pod time code
1             # We're currently waiting on UUID::Tiny 1.02 or newer for the new API
2              
3             package Prophet::TempUUIDTiny;
4              
5 40     40   918 use 5.008;
  40         107  
6 40     40   177 use warnings;
  40         58  
  40         1147  
7 40     40   166 use strict;
  40         56  
  40         801  
8 40     40   302 use Carp;
  40         94  
  40         2781  
9 40     40   200 use Digest::MD5;
  40         64  
  40         1356  
10 40     40   176 use MIME::Base64;
  40         53  
  40         1802  
11 40     40   23408 use Time::HiRes;
  40         51652  
  40         169  
12 40     40   26152 use POSIX;
  40         238818  
  40         250  
13              
14             our $SHA1_CALCULATOR = undef;
15              
16             {
17             # Check for availability of SHA-1 ...
18             local $@; # don't leak an error condition
19             eval { require Digest::SHA; $SHA1_CALCULATOR = Digest::SHA->new(1)} ||
20             eval { require Digest::SHA1; $SHA1_CALCULATOR = Digest::SHA1->new() } ||
21             eval { require Digest::SHA::PurePerl; $SHA1_CALCULATOR = Digest::SHA::PurePerl->new(1)};
22             };
23              
24             our $MD5_CALCULATOR = Digest::MD5->new();
25              
26              
27              
28              
29             =head1 NAME
30              
31             UUID::Tiny - Pure Perl UUID Support With Functional Interface
32              
33             =head1 VERSION
34              
35             Version 1.01_06
36              
37             =cut
38              
39             our $VERSION = '1.01_06';
40              
41              
42             =head1 SYNOPSIS
43              
44             Create version 1, 3, 4 and 5 UUIDs:
45              
46             use UUID::Tiny;
47              
48             my $v1_mc_UUID = create_UUID();
49             my $v3_md5_UUID = create_UUID(UUID_V3, $str);
50             my $v3_md5_UUID = create_UUID(UUID_V3, UUID_NS_DNS, 'caugustin.de');
51             my $v4_rand_UUID = create_UUID(UUID_V4);
52             my $v5_sha1_UUID = create_UUID(UUID_V5, $str);
53             my $v5_with_NS_UUID = create_UUID(UUID_V5, UUID_NS_DNS, 'caugustin.de');
54              
55             my $v1_mc_UUID_string = create_UUID_as_string(UUID_V1);
56             my $v3_md5_UUID_string = UUID_to_string($v3_md5_UUID);
57              
58             if ( version_of_UUID($v1_mc_UUID) == 1 ) { ... };
59             if ( version_of_UUID($v5_sha1_UUID) == 5 ) { ... };
60             if ( is_UUID_string($v1_mc_UUID_string) ) { ... };
61             if ( equal_UUIDs($uuid1, $uuid2) ) { ... };
62              
63             my $uuid_time = time_of_UUID($v1_mc_UUID);
64             my $uuid_clk_seq = clk_seq_of_UUID($v1_mc_UUID);
65              
66             =cut
67              
68              
69             =head1 DESCRIPTION
70              
71             UUID::Tiny is a lightweight, low dependency Pure Perl module for UUID
72             creation and testing. This module provides the creation of version 1 time
73             based UUIDs (using random multicast MAC addresses), version 3 MD5 based UUIDs,
74             version 4 random UUIDs, and version 5 SHA-1 based UUIDs.
75              
76             No fancy OO interface, no plethora of different UUID representation formats
77             and transformations - just string and binary. Conversion, test and time
78             functions equally accept UUIDs and UUID strings, so don't bother to convert
79             UUIDs for them!
80              
81             All constants and public functions are exported by default, because if you
82             didn't need/want them, you wouldn't use this module ...
83              
84             UUID::Tiny deliberately uses a minimal functional interface for UUID creation
85             (and conversion/testing), because in this case OO looks like overkill to me
86             and makes the creation and use of UUIDs unnecessarily complicated.
87              
88             If you need raw performance for UUID creation, or the real MAC address in
89             version 1 UUIDs, or an OO interface, and if you can afford module compilation
90             and installation on the target system, then better look at other CPAN UUID
91             modules like L.
92              
93             This module should be thread save, because the (necessary) global variables
94             are locked in the functions that access them. (Not tested.)
95              
96             =cut
97              
98              
99             =head1 DEPENDENCIES
100              
101             This module should run from Perl 5.8 up and uses mostly standard (5.8 core)
102             modules for its job. No compilation or installation required. These are the
103             modules UUID::Tiny depends on:
104              
105             Carp
106             Digest::MD5 Perl 5.8 core
107             Digest::SHA Perl 5.10 core (OR Digest::SHA1 OR Digest::SHA::PurePerl)
108             MIME::Base64 Perl 5.8 core
109             Time::HiRes Perl 5.8 core
110             POSIX Perl 5.8 core
111              
112             =cut
113              
114              
115             =head1 ATTENTION! NEW STANDARD INTERFACE (IN PREPARATION FOR V2.00)
116              
117             After some debate I'm convinced that it is more Perlish (and far easier to
118             write) to use all-lowercase function names - without exceptions. And that it
119             is more polite to export symbols only on demand.
120              
121             While the 1.0x versions will continue to export the old, "legacy" interface on
122             default, the future standard interface is available using the C<:std> tag on
123             import from version 1.02 on:
124              
125             use UUID::Tiny ':std';
126             my $md5_uuid = create_uuid(UUID_MD5, $str);
127              
128             In preparation for the upcoming version 2.00 of UUID::Tiny you should use the
129             C<:legacy> tag if you want to stay with the version 1.0x interface:
130              
131             use UUID::Tiny ':legacy';
132             my $md5_uuid = create_UUID(UUID_V3, $str);
133              
134             =cut
135              
136 40     40   108229 use Exporter;
  40         75  
  40         6250  
137             our @ISA = qw(Exporter);
138             our @EXPORT;
139             our @EXPORT_OK;
140             our %EXPORT_TAGS = (
141             std => [qw(
142             UUID_NIL
143             UUID_NS_DNS UUID_NS_URL UUID_NS_OID UUID_NS_X500
144             UUID_V1 UUID_TIME
145             UUID_V3 UUID_MD5
146             UUID_V4 UUID_RANDOM
147             UUID_V5 UUID_SHA1
148             UUID_SHA1_AVAIL
149             create_uuid create_uuid_as_string
150             is_uuid_string
151             uuid_to_string string_to_uuid
152             version_of_uuid time_of_uuid clk_seq_of_uuid
153             equal_uuids
154             )],
155             legacy => [qw(
156             UUID_NIL
157             UUID_NS_DNS UUID_NS_URL UUID_NS_OID UUID_NS_X500
158             UUID_V1
159             UUID_V3
160             UUID_V4
161             UUID_V5
162             UUID_SHA1_AVAIL
163             create_UUID create_UUID_as_string
164             is_UUID_string
165             UUID_to_string string_to_UUID
166             version_of_UUID time_of_UUID clk_seq_of_UUID
167             equal_UUIDs
168             )],
169             );
170              
171             Exporter::export_tags('legacy');
172             Exporter::export_ok_tags('std');
173              
174              
175             =head1 CONSTANTS
176              
177             =cut
178              
179             =over 4
180              
181             =item B
182              
183             This module provides the NIL UUID (shown with its string representation):
184              
185             UUID_NIL: '00000000-0000-0000-0000-000000000000'
186              
187             =cut
188              
189 40     40   215 use constant UUID_NIL => "\x00" x 16;
  40         55  
  40         3561  
190              
191              
192             =item B
193              
194             This module provides the common pre-defined namespace UUIDs (shown with their
195             string representation):
196              
197             UUID_NS_DNS: '6ba7b810-9dad-11d1-80b4-00c04fd430c8'
198             UUID_NS_URL: '6ba7b811-9dad-11d1-80b4-00c04fd430c8'
199             UUID_NS_OID: '6ba7b812-9dad-11d1-80b4-00c04fd430c8'
200             UUID_NS_X500: '6ba7b814-9dad-11d1-80b4-00c04fd430c8'
201              
202             =cut
203              
204 40         2144 use constant UUID_NS_DNS =>
205 40     40   188 "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8";
  40         57  
206 40         2092 use constant UUID_NS_URL =>
207 40     40   166 "\x6b\xa7\xb8\x11\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8";
  40         59  
208 40         2043 use constant UUID_NS_OID =>
209 40     40   168 "\x6b\xa7\xb8\x12\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8";
  40         52  
210 40         1905 use constant UUID_NS_X500 =>
211 40     40   168 "\x6b\xa7\xb8\x14\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8";
  40         63  
212              
213              
214             =item B
215              
216             This module provides the UUID version numbers as constants:
217              
218             UUID_V1
219             UUID_V3
220             UUID_V4
221             UUID_V5
222              
223             With C you get additional, "speaking" constants:
224              
225             UUID_TIME
226             UUID_MD5
227             UUID_RANDOM
228             UUID_SHA1
229              
230             =cut
231              
232 40     40   172 use constant UUID_V1 => 1; use constant UUID_TIME => 1;
  40     40   60  
  40         1807  
  40         217  
  40         53  
  40         1782  
233 40     40   173 use constant UUID_V3 => 3; use constant UUID_MD5 => 3;
  40     40   50  
  40         1848  
  40         166  
  40         53  
  40         1700  
234 40     40   167 use constant UUID_V4 => 4; use constant UUID_RANDOM => 4;
  40     40   56  
  40         1569  
  40         161  
  40         56  
  40         1629  
235 40     40   187 use constant UUID_V5 => 5; use constant UUID_SHA1 => 5;
  40     40   51  
  40         1680  
  40         161  
  40         54  
  40         4210  
236              
237              
238             =item B
239              
240             my $uuid = create_UUID( UUID_SHA1_AVAIL? UUID_V5 : UUID_V3, $str );
241              
242             This function returns a positive value if a module to create SHA-1 digests
243             could be loaded, 0 otherwise.
244              
245             UUID::Tiny (since version 1.02) tries to load
246             Digest::SHA (1), Digest::SHA1 (2) or Digest::SHA::PurePerl (3), but does not
247             die if none of them is found. Instead C and
248             C die when trying to create an SHA-1 based UUID
249             without an appropriate module available.
250              
251             =cut
252              
253             sub UUID_SHA1_AVAIL {
254 0 0   0 1   return defined $SHA1_CALCULATOR ? 1 :0;
255             }
256              
257             =back
258              
259             =cut
260              
261             =head1 FUNCTIONS
262              
263             All public functions are exported by default (they should not collide with
264             other functions).
265              
266             C creates standard binary UUIDs in network byte order
267             (MSB first), C creates the standard string
268             represantion of UUIDs.
269              
270             All query and test functions (except C) accept both
271             representations.
272              
273             =over 4
274              
275             =cut
276              
277             =item B, B (:std)
278              
279             my $v1_mc_UUID = create_UUID();
280             my $v1_mc_UUID = create_UUID(UUID_V1);
281             my $v3_md5_UUID = create_UUID(UUID_V3, $ns_uuid, $name_or_filehandle);
282             my $v3_md5_UUID = create_UUID(UUID_V3, $name_or_filehandle);
283             my $v4_rand_UUID = create_UUID(UUID_V4);
284             my $v5_sha1_UUID = create_UUID(UUID_V5, $ns_uuid $name_or_filehandle);
285             my $v5_sha1_UUID = create_UUID(UUID_V5, $name_or_filehandle);
286              
287             Creates a binary UUID in network byte order (MSB first). For v3 and v5 UUIDs a
288             C (normally a string), C ("classic" file handle) or C object
289             (i.e. C) can be used; files have to be opened for reading.
290              
291             I found no hint if and how UUIDs should be created from file content. It seems
292             to be undefined, but it is useful - so I would suggest to use UUID_NIL as the
293             namespace UUID, because no "real name" is used; UUID_NIL is used by default if
294             a namespace UUID is missing (only 2 arguments are used).
295              
296             =cut
297              
298             sub create_uuid {
299 40     40   28199 use bytes;
  40         389  
  40         198  
300 0   0 0 1   my ($v, $arg2, $arg3) = (shift || UUID_V1, shift, shift);
301 0           my $uuid = UUID_NIL;
302 0 0         my $ns_uuid = string_to_uuid(defined $arg3 ? $arg2 : UUID_NIL);
303 0 0         my $name = defined $arg3 ? $arg3 : $arg2;
304              
305 0 0         if ($v == UUID_V1) {
    0          
    0          
    0          
306 0           $uuid = _create_v1_uuid();
307             }
308             elsif ($v == UUID_V3 ) {
309 0           $uuid = _create_v3_uuid($ns_uuid, $name);
310             }
311             elsif ($v == UUID_V4) {
312 0           $uuid = _create_v4_uuid();
313             }
314             elsif ($v == UUID_V5) {
315 0           $uuid = _create_v5_uuid($ns_uuid, $name);
316             }
317             else {
318 0           croak __PACKAGE__ . "::create_uuid(): Invalid UUID version '$v'!";
319             }
320              
321             # Set variant 2 in UUID ...
322 0           substr $uuid, 8, 1, chr(ord(substr $uuid, 8, 1) & 0x3f | 0x80);
323              
324 0           return $uuid;
325             }
326             *create_UUID = \&create_uuid;
327              
328             sub _create_v1_uuid {
329 0     0     my $uuid = '';
330              
331             # Create time and clock sequence ...
332 0           my $timestamp = Time::HiRes::time();
333 0           my $clk_seq = _get_clk_seq($timestamp);
334              
335             # hi = time mod (1000000 / 0x100000000)
336 0           my $hi = floor( $timestamp / 65536.0 / 512 * 78125 );
337 0           $timestamp -= $hi * 512.0 * 65536 / 78125;
338 0           my $low = floor( $timestamp * 10000000.0 + 0.5 );
339              
340             # MAGIC offset: 01B2-1DD2-13814000
341 0 0         if ( $low < 0xec7ec000 ) {
342 0           $low += 0x13814000;
343             } else {
344 0           $low -= 0xec7ec000;
345 0           $hi++;
346             }
347              
348 0 0         if ( $hi < 0x0e4de22e ) {
349 0           $hi += 0x01b21dd2;
350             } else {
351 0           $hi -= 0x0e4de22e; # wrap around
352             }
353              
354             # Set time in UUID ...
355 0           substr $uuid, 0, 4, pack( 'N', $low ); # set time low
356 0           substr $uuid, 4, 2, pack( 'n', $hi & 0xffff ); # set time mid
357 0           substr $uuid, 6, 2, pack( 'n', ( $hi >> 16 ) & 0x0fff ); # set time high
358              
359             # Set clock sequence in UUID ...
360 0           substr $uuid, 8, 2, pack( 'n', $clk_seq );
361              
362             # Set random node in UUID ...
363 0           substr $uuid, 10, 6, _random_node_id();
364              
365 0           return _set_uuid_version($uuid => 0x10);
366             }
367              
368             sub _create_v3_uuid {
369 0     0     my $ns_uuid = shift;
370 0           my $name = shift;
371 0           my $uuid = '';
372              
373             # Create digest in UUID ...
374 0           $MD5_CALCULATOR->reset();
375 0           $MD5_CALCULATOR->add($ns_uuid);
376              
377 0 0         if ( ref($name) =~ m/^(?:GLOB|IO::)/ ) {
    0          
    0          
378 0           $MD5_CALCULATOR->addfile($name);
379             } elsif ( ref $name ) {
380 0           croak __PACKAGE__ . '::create_uuid(): Name for v3 UUID' . ' has to be SCALAR, GLOB or IO object, not '.ref($name).'!';
381             } elsif ( defined $name ) {
382 0           $MD5_CALCULATOR->add($name);
383             } else {
384 0           croak __PACKAGE__ . '::create_uuid(): Name for v3 UUID is not defined!';
385             }
386              
387 0           $uuid = substr( $MD5_CALCULATOR->digest(), 0, 16 ); # Use only first 16 Bytes
388              
389 0           return _set_uuid_version( $uuid => 0x30 );
390             }
391              
392             sub _create_v4_uuid {
393              
394             # Create random value in UUID ...
395 0     0     my $uuid = '';
396 0           for ( 1 .. 4 ) {
397 0           $uuid .= pack 'I', _rand_32bit();
398             }
399              
400 0           return _set_uuid_version($uuid => 0x40);
401             }
402              
403             sub _create_v5_uuid {
404 0     0     my $ns_uuid = shift;
405 0           my $name = shift;
406 0           my $uuid = '';
407              
408 0 0         if (!$SHA1_CALCULATOR) {
409 0           croak __PACKAGE__
410             . '::create_uuid(): No SHA-1 implementation available! '
411             . 'Please install Digest::SHA1, Digest::SHA or '
412             . 'Digest::SHA::PurePerl to use SHA-1 based UUIDs.';
413             }
414              
415              
416 0           $SHA1_CALCULATOR->reset();
417 0           $SHA1_CALCULATOR->add($ns_uuid);
418              
419              
420 0 0         if ( ref($name) =~ m/^(?:GLOB|IO::)/ ) {
    0          
    0          
421 0           $SHA1_CALCULATOR->addfile($name);
422             } elsif ( ref $name ) {
423 0           croak __PACKAGE__ . '::create_uuid(): Name for v5 UUID' . ' has to be SCALAR, GLOB or IO object, not '.ref($name).'!';
424             } elsif ( defined $name ) {
425 0           $SHA1_CALCULATOR->add($name);
426             } else {
427 0           croak __PACKAGE__ . '::create_uuid(): Name for v5 UUID is not defined!';
428             }
429              
430 0           $uuid = substr( $SHA1_CALCULATOR->digest(), 0, 16 ); # Use only first 16 Bytes
431              
432 0           return _set_uuid_version($uuid => 0x50);
433             }
434              
435             sub _set_uuid_version {
436 0     0     my $uuid = shift;
437 0           my $version = shift;
438 0           substr $uuid, 6, 1, chr( ord( substr( $uuid, 6, 1 ) ) & 0x0f | $version );
439              
440 0           return $uuid;
441              
442             }
443              
444             =item B, B (:std)
445              
446             Similar to C, but creates a UUID string.
447              
448             =cut
449              
450             sub create_uuid_as_string {
451 0     0 1   return uuid_to_string(create_uuid(@_));
452             }
453              
454             *create_UUID_as_string = \&create_uuid_as_string;
455              
456              
457             =item B, B (:std)
458              
459             my $bool = is_UUID_string($str);
460              
461             =cut
462              
463             our $IS_UUID_STRING = qr/^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/is;
464             our $IS_UUID_HEX = qr/^[0-9a-f]{32}$/is;
465             our $IS_UUID_Base64 = qr/^[+\/0-9A-Za-z]{22}(?:==)?$/s;
466              
467             sub is_uuid_string {
468 0     0 1   my $uuid = shift;
469 0           return $uuid =~ m/$IS_UUID_STRING/;
470             }
471              
472             *is_UUID_string = \&is_uuid_string;
473              
474              
475             =item B, B (:std)
476              
477             my $uuid_str = UUID_to_string($uuid);
478              
479             This function returns C<$uuid> unchanged if it is a UUID string already.
480              
481             =cut
482              
483             sub uuid_to_string {
484 0     0 1   my $uuid = shift;
485 40     40   43167 use bytes;
  40         67  
  40         163  
486 0 0         return $uuid
487             if $uuid =~ m/$IS_UUID_STRING/;
488 0 0         croak __PACKAGE__ . "::uuid_to_string(): Invalid UUID!"
489             unless length $uuid == 16;
490             return join q{-},
491 0           map { unpack 'H*', $_ }
492 0           map { substr $uuid, 0, $_, q{} }
  0            
493             ( 4, 2, 2, 2, 6 );
494             }
495              
496             *UUID_to_string = \&uuid_to_string;
497              
498              
499             =item B, B (:std)
500              
501             my $uuid = string_to_UUID($uuid_str);
502              
503             This function returns C<$uuid_str> unchanged if it is a UUID already.
504              
505             In addition to the standard UUID string representation and its URN forms
506             (starting with C or C), this function accepts 32 digit hex
507             strings, variants with different positions of C<-> and Base64 encoded UUIDs.
508              
509             Throws an exception if string can't be interpreted as a UUID.
510              
511             If you want to make shure to have a "pure" standard UUID representation, check
512             with C!
513              
514             =cut
515              
516             sub string_to_uuid {
517 0     0 1   my $uuid = shift;
518              
519 40     40   5307 use bytes;
  40         83  
  40         157  
520 0 0         return $uuid if length $uuid == 16;
521 0 0         return decode_base64($uuid) if ($uuid =~ m/$IS_UUID_Base64/);
522 0           my $str = $uuid;
523 0           $uuid =~ s/^(?:urn:)?(?:uuid:)?//io;
524 0           $uuid =~ tr/-//d;
525 0 0         return pack 'H*', $uuid if $uuid =~ m/$IS_UUID_HEX/;
526 0           croak __PACKAGE__ . "::string_to_uuid(): '$str' is no UUID string!";
527             }
528              
529             *string_to_UUID = \&string_to_uuid;
530              
531              
532             =item B, B (:std)
533              
534             my $version = version_of_UUID($uuid);
535              
536             This function accepts binary and string UUIDs.
537              
538             =cut
539              
540             sub version_of_uuid {
541 0     0 1   my $uuid = shift;
542 40     40   6808 use bytes;
  40         67  
  40         145  
543 0           $uuid = string_to_uuid($uuid);
544 0           return (ord(substr($uuid, 6, 1)) & 0xf0) >> 4;
545             }
546              
547             *version_of_UUID = \&version_of_uuid;
548              
549              
550             =item B, B (:std)
551              
552             my $uuid_time = time_of_UUID($uuid);
553              
554             This function accepts UUIDs and UUID strings. Returns the time as a floating
555             point value, so use C to get a C compatible value.
556              
557             Returns C if the UUID is not version 1.
558              
559             =cut
560              
561             sub time_of_uuid {
562 0     0 1   my $uuid = shift;
563 40     40   3176 use bytes;
  40         79  
  40         156  
564 0           $uuid = string_to_uuid($uuid);
565 0 0         return unless version_of_uuid($uuid) == 1;
566            
567 0           my $low = unpack 'N', substr($uuid, 0, 4);
568 0           my $mid = unpack 'n', substr($uuid, 4, 2);
569 0           my $high = unpack('n', substr($uuid, 6, 2)) & 0x0fff;
570              
571 0           my $hi = $mid | $high << 16;
572              
573             # MAGIC offset: 01B2-1DD2-13814000
574 0 0         if ($low >= 0x13814000) {
575 0           $low -= 0x13814000;
576             }
577             else {
578 0           $low += 0xec7ec000;
579 0           $hi --;
580             }
581              
582 0 0         if ($hi >= 0x01b21dd2) {
583 0           $hi -= 0x01b21dd2;
584             }
585             else {
586 0           $hi += 0x0e4de22e; # wrap around
587             }
588              
589 0           $low /= 10000000.0;
590 0           $hi /= 78125.0 / 512 / 65536; # / 1000000 * 0x10000000
591              
592 0           return $hi + $low;
593             }
594              
595             *time_of_UUID = \&time_of_uuid;
596              
597              
598             =item B, B (:std)
599              
600             my $uuid_clk_seq = clk_seq_of_UUID($uuid);
601              
602             This function accepts UUIDs and UUID strings. Returns the clock sequence for a
603             version 1 UUID. Returns C if UUID is not version 1.
604              
605             =cut
606              
607             sub clk_seq_of_uuid {
608 40     40   7032 use bytes;
  40         63  
  40         147  
609 0     0 1   my $uuid = shift;
610 0           $uuid = string_to_uuid($uuid);
611 0 0         return unless version_of_uuid($uuid) == 1;
612              
613 0           my $r = unpack 'n', substr($uuid, 8, 2);
614 0           my $v = $r >> 13;
615 0 0         my $w = ($v >= 6) ? 3 # 11x
    0          
616             : ($v >= 4) ? 2 # 10-
617             : 1 # 0--
618             ;
619 0           $w = 16 - $w;
620              
621 0           return $r & ((1 << $w) - 1);
622             }
623              
624             *clk_seq_of_UUID = \&clk_seq_of_uuid;
625              
626              
627             =item B, B (:std)
628              
629             my $bool = equal_UUIDs($uuid1, $uuid2);
630              
631             Returns true if the provided UUIDs are equal. Accepts UUIDs and UUID strings
632             (can be mixed).
633              
634             =cut
635              
636             sub equal_uuids {
637 0     0 1   my ($u1, $u2) = @_;
638 0 0 0       return unless defined $u1 && defined $u2;
639 0           return string_to_uuid($u1) eq string_to_uuid($u2);
640             }
641              
642             *equal_UUIDs = \&equal_uuids;
643              
644              
645             #
646             # Private functions ...
647             #
648              
649             my $last_timestamp;
650             my $clk_seq;
651              
652             sub _get_clk_seq {
653 0     0     my $ts = shift;
654 0           lock $last_timestamp;
655 0           lock $clk_seq;
656              
657 0 0         $clk_seq = _generate_clk_seq() if !defined $clk_seq;
658              
659 0 0 0       if (!defined $last_timestamp || $ts <= $last_timestamp) {
660 0           $clk_seq = ($clk_seq + 1) % 65536;
661             }
662 0           $last_timestamp = $ts;
663              
664 0           return $clk_seq & 0x03ff;
665             }
666              
667             sub _generate_clk_seq {
668 0     0     my $self = shift;
669              
670 0           my @data;
671 0           push @data, q{} . $$;
672 0           push @data, q{:} . Time::HiRes::time();
673              
674             # 16 bit digest
675 0           return unpack 'n', _digest_as_octets(2, @data);
676             }
677              
678             sub _random_node_id {
679 0     0     my $self = shift;
680              
681 0           my $r1 = _rand_32bit();
682 0           my $r2 = _rand_32bit();
683              
684 0           my $hi = ($r1 >> 8) ^ ($r2 & 0xff);
685 0           my $lo = ($r2 >> 8) ^ ($r1 & 0xff);
686              
687 0           $hi |= 0x80;
688              
689 0           my $id = substr pack('V', $hi), 0, 3;
690 0           $id .= substr pack('V', $lo), 0, 3;
691              
692 0           return $id;
693             }
694              
695             sub _rand_32bit {
696 0     0     my $v1 = int(rand(65536)) % 65536;
697 0           my $v2 = int(rand(65536)) % 65536;
698 0           return ($v1 << 16) | $v2;
699             }
700              
701             sub _fold_into_octets {
702 40     40   16943 use bytes;
  40         73  
  40         139  
703 0     0     my ($num_octets, $s) = @_;
704              
705 0           my $x = "\x0" x $num_octets;
706              
707 0           while (length $s > 0) {
708 0           my $n = q{};
709 0           while (length $x > 0) {
710 0           my $c = ord(substr $x, -1, 1, q{}) ^ ord(substr $s, -1, 1, q{});
711 0           $n = chr($c) . $n;
712 0 0         last if length $s <= 0;
713             }
714 0           $n = $x . $n;
715              
716 0           $x = $n;
717             }
718              
719 0           return $x;
720             }
721              
722             sub _digest_as_octets {
723 0     0     my $num_octets = shift;
724              
725 0           $MD5_CALCULATOR->reset();
726 0           $MD5_CALCULATOR->add($_) for @_;
727              
728 0           return _fold_into_octets($num_octets, $MD5_CALCULATOR->digest);
729             }
730              
731              
732             =back
733              
734             =cut
735              
736              
737             =head1 DISCUSSION
738              
739             =over
740              
741             =item B
742              
743             The random multi-cast MAC address gives privacy, and getting the real MAC
744             address with Perl is really dirty (and slow);
745              
746             =item B
747              
748             Using SHA-1 reduces the probabillity of collisions and provides a better
749             "randomness" of the resulting UUID compared to MD5. Version 5 is recommended
750             in RFC 4122 if backward compatibility is not an issue.
751              
752             Using MD5 (version 3) has a better performance. This could be important with
753             creating UUIDs from file content rather than names.
754              
755             =back
756              
757              
758             =head1 UUID DEFINITION
759              
760             See RFC 4122 (L) for technical details on
761             UUIDs.
762              
763              
764             =head1 AUTHOR
765              
766             Much of this code is borrowed from UUID::Generator by ITO Nobuaki
767             Ebanb@cpan.orgE. But that module is announced to be marked as
768             "deprecated" in the future and it is much too complicated for my liking.
769              
770             So I decided to reduce it to the necessary parts and to re-implement those
771             parts with a functional interface ...
772              
773             Christian Augustin, C<< >>
774              
775              
776             =head1 BUGS
777              
778             Please report any bugs or feature requests to C,
779             or through the web interface at
780             L.
781             I will be notified, and then you'll automatically be notified of progress on
782             your bug as I make changes.
783              
784              
785             =head1 SUPPORT
786              
787             You can find documentation for this module with the perldoc command.
788              
789             perldoc UUID::Tiny
790              
791             You can also look for information at:
792              
793             =over 4
794              
795             =item * RT: CPAN's request tracker
796              
797             L
798              
799             =item * AnnoCPAN: Annotated CPAN documentation
800              
801             L
802              
803             =item * CPAN Ratings
804              
805             L
806              
807             =item * Search CPAN
808              
809             L
810              
811             =back
812              
813              
814             =head1 ACKNOWLEDGEMENTS
815              
816             Kudos to ITO Nobuaki Ebanb@cpan.orgE for his UUID::Generator::PurePerl
817             module! My work is based on his code, and without it I would've been lost with
818             all those incomprehensible RFC texts and C codes ...
819              
820             Thanks to Jesse Vincent for his feedback and tips.
821              
822              
823             =head1 COPYRIGHT & LICENSE
824              
825             Copyright 2009 Christian Augustin, all rights reserved.
826              
827             This program is free software; you can redistribute it and/or modify it
828             under the same terms as Perl itself.
829              
830              
831             =cut
832              
833             1; # End of UUID::Tiny