package UUID;
require 5.005;
use strict;
use warnings;

require Exporter;
require DynaLoader;

use vars qw(@ISA %EXPORT_TAGS @EXPORT_OK $VERSION);
@ISA = qw(DynaLoader);

$VERSION = '0.32_05';

%EXPORT_TAGS = (
    'all' => [qw(
        &clear &compare &copy &generate &generate_random &generate_time
        &generate_v1 &generate_v4 &is_null &parse &time &type &unparse
        &unparse_lower &unparse_upper &uuid &uuid1 &uuid4 &variant
    )],
);

@EXPORT_OK = ( @{$EXPORT_TAGS{'all'}}, '&randnext' );

bootstrap UUID $VERSION;

sub import {
    for (my $i=scalar(@_)-1 ; $i>0 ; --$i) {
        my $v = $_[$i];
        # :persist=FOO
        if (length($v) > 9 and substr($v,0,9) eq ':persist=') {
            _persist(substr($v, 9));
            splice @_, $i, 1;
            next;
        }
        # :mac=random
        if (length($v) == 11 and $v eq ':mac=random') {
            _hide_mac();
            splice @_, $i, 1;
            next;
        }
        # :mac=unique
        if (length($v) == 11 and $v eq ':mac=unique') {
            _hide_always();
            splice @_, $i, 1;
            next;
        }
    }
    goto &Exporter::import;
}

# Preloaded methods go here.

1;
__END__

=head1 NAME

UUID - Universally Unique Identifier library for Perl

=head1 SYNOPSIS

    use UUID 'uuid';

    $string = uuid();   # generate UUID string, prefer v4, fallback v1
    $string = uuid1();  # generate UUID string, always v1
    $string = uuid4();  # generate UUID string, always v4

    UUID::generate_v1($uuid);            # new version 1 binary UUID
    UUID::generate_v4($uuid);            # new version 4 binary UUID

    UUID::generate($uuid);               # new binary UUID; prefer v4
    UUID::generate_time($uuid);          # alias for generate_v1()
    UUID::generate_random($uuid);        # alias for generate_v4()

    UUID::unparse($uuid, $string);       # stringify $uuid; system casing
    UUID::unparse_lower($uuid, $string); # force lowercase stringify
    UUID::unparse_upper($uuid, $string); # force uppercase stringify

    $rc = UUID::parse($string, $uuid);   # map string to UUID; -1 on error

    UUID::copy($dst, $src);              # copy binary UUID from $src to $dst
    UUID::compare($uuid1, $uuid2);       # compare binary UUIDs

    UUID::clear( $uuid );                # set binary UUID to NULL
    UUID::is_null( $uuid );              # compare binary UUID to NULL

    UUID::type( $uuid );                 # return UUID type
    UUID::variant( $uuid );              # return UUID variant

    UUID::time( $uuid );                 # return internal UUID time


=head1 DESCRIPTION

The UUID library is used to generate unique identifiers for objects that
may be accessible beyond the local system. For instance, they could be
used to generate unique HTTP cookies across multiple web servers without
communication between the servers, and without fear of a name clash.

The generated UUIDs can be reasonably expected to be unique within a
system, and unique across all systems, and are compatible with those
created by the Open Software Foundation (OSF) Distributed Computing
Environment (DCE).

All generated UUIDs are either version 1 from B<generate_v1()>, or
version 4 from B<generate_v4()>. And all are variant 1, meaning
compliant with the OSF DCE standard as described in RFC4122.

=head1 FUNCTIONS

Most of the UUID functions expose the underlying I<libuuid> C interface
rather directly. That is, many return their values in their parameters
and nothing else.

Not very Perlish, is it? It's been like that for a long time though, so
not very likely to change any time soon.

All take or return UUIDs in either binary or string format. The string
format resembles the following:

    21b081a3-de83-4480-a14f-e89a1dcf8f0f

Or, in terms of printf(3) format:

    "%08x-%04x-%04x-%04x-%012x"

The binary form is simply a packed 16 byte binary value.

=head2 B<clear(> I<$uuid> B<)>

Sets I<$uuid> equal to the value of the NULL UUID.

=head2 B<copy(> I<$dst>B<,> I<$src> B<)>

Copies the binary I<$src> UUID to I<$dst>.

If I<$src> isn't a UUID, I<$dst> is set to the NULL UUID.

=head2 B<compare(> I<$uuid1>B<,> I<$uuid2> B<)>

Compares two binary UUIDs.

Returns an integer less than, equal to, or greater than zero if
I<$uuid1> is less than, equal to, or greater than I<$uuid2>.

However, if either operand is not a UUID, falls back to a simple string
comparison returning similar values.

=head2 B<generate(> I<$uuid> B<)>

Generates a new version 4 binary UUID based on high quality randomness
from I</dev/urandom> or I</dev/random>, if available.

If not, a new version 1 binary UUID is returned.

The previous content of I<$uuid>, if any, is lost.

=head2 B<generate_random(> I<$uuid> B<)>

Generates a new version 4 binary UUID even if a high-quality random
number generator (e.g., I</dev/urandom>) is not available, in which case
a pseudo-random generator is used.

Note that the use of a pseudo-random generator may compromise the
uniqueness of UUIDs generated in this fashion.

If I</dev/urandom> and/or I</dev/random> are present, the system calls
I<get_random()> and/or I<get_entropy()> are used first, if available.

If the system calls are not available, randomness is read directly from
the random devices, preferring I</dev/urandom> but falling back to
I</dev/random> in non-blocking mode.

=head2 B<generate_time(> I<$uuid> B<)>

Generates a new version 1 binary UUID using the current time and the
local ethernet MAC address, if available.

If the MAC address is not available at startup, or a randomized address
is requested (see B<:mac> in B<EXPORTS>), a random address is used. The
multicast bit of this address is set to avoid conflict with addresses
returned from network cards.

This algorithm used to be the default for generating UUIDs, but because
of privacy concerns, the B<generate()> function only uses it if a
high-quality source of randomness is not available.

=head2 B<generate_v1(> I<$uuid> B<)>

Alias for B<generate_time()>.

=head2 B<generate_v4(> I<$uuid> B<)>

Alias for B<generate_random()>.

=head2 B<is_null(> I<$uuid> B<)>

Compares the value of I<$uuid> to the NULL UUID.

Returns 1 if NULL, and 0 otherwise.

=head2 B<parse(> I<$string>B<,> I<$uuid> B<)>

Converts the string format UUID in I<$string> to binary and returns in
I<$uuid>. The previous content of I<$uuid>, if any, is lost.

Returns 0 on success and -1 on failure. Additionally on failure, the
content of I<$uuid> is unchanged.

=head2 B<time(> I<$uuid> B<)>

Returns the time element of a binary UUID in seconds since the epoch,
the same as I<Perl>'s B<time> function.

Keep in mind this only works for type 1 UUIDs. Values returned from
other types range from non-standardized to totally random.

=head2 B<type(> I<$uuid> B<)>

Returns the type of binary I<$uuid>.

This module only generates type 1 (time) and type 4 (random) UUIDs, but
others may be found in the wild.

Known types:
    1  a.k.a. Version 1 - date/time and MAC address
    2  a.k.a. Version 2 - date/time and MAC address, security version
    3  a.k.a. Version 3 - namespace based, MD5 hash
    4  a.k.a. Version 4 - random
    5  a.k.a. Version 5 - namespace based, SHA-1 hash

=head2 B<unparse(> I<$uuid>B<,> I<$string> B<)>

Converts the binary UUID in I<$uuid> to string format and returns in
I<$string>. The previous content of I<$string>, if any, is lost.

Prior to version 0.32, casing of the return value was system-dependent.
Later versions are lower case, per RFC4122.

=head2 B<unparse_lower(> I<$uuid>B<,> I<$string> B<)>

Same as B<unparse()>.

=head2 B<unparse_upper(> I<$uuid>B<,> I<$string> B<)>

Same as B<unparse()> but I<$string> is forced to upper case.

=head2 B<uuid()>

Creates a new string format UUID and returns it in a more Perlish way.

Functionally the equivalent of calling B<generate()> and then B<unparse()>, but
throwing away the intermediate binary UUID.

=head2 B<uuid1()>

Same as B<uuid()> but always version 1.

=head2 B<uuid4()>

Same as B<uuid()> but always version 4.

=head2 B<variant(> I<$uuid> B<)>

Returns the variant of binary I<$uuid>.

This module only generates variant 1 UUIDs, but others may be found in
the wild.

Known variants:

    0  NCS
    1  DCE
    2  Microsoft
    3  Other

=head1 MAINTAINING STATE

Internal state is optionally maintained for version 1 UUIDs via a file
designated by the B<:persist> export tag (see EXPORTS), if the path
exists and the user running the process has read/write access.

If the file doesn't exist, it will be created if the directory path
exists.

The file records various internal states at the time the last UUID is
generated, preventing future instances from overlapping the prior UUID
sequence. This allows the sequence to absolutely survive reboots and,
more importantly, backwards resetting of system time.

If B<:persist> is not used, time resets will still be detected while the
module is loaded, and handled accordingly. And since startup in this
case is randomized anyway, the chance of overlap is low but still exists
since the randomized clock_seq field is only 14 bits wide.

Note that use of this feature incurs a serious performance penalty,
upwards of 90% on tested platforms.

Note too that use of a random MAC greatly reduces the chance of overlap,
making the randomized parts 62 bits wide at start.

=head1 EXPORTS

None by default. All functions may be imported in the usual manner,
either individually or all at once using the B<:all> tag.

=head2 B<:mac>=I<mode>

The MAC address used for v1 UUIDS is forced to always be random in
one of two modes:

=over 4

I<random> The MAC address is generated once at startup and used
throughout the lifetime of the process. This is the default if the real
MAC cannot be found.

I<unique> A new MAC address is generated for each new UUID. It is not
guaranteed to be unique beyond the probability of randomness.

=back

=head2 B<:persist>=F<path/to/state.txt>

Path to version 1 state maintenance file. (See B<MAINTAINING STATE>.)
The path may be either relative or absolute.

If the file does not exist, it will be created provided the path
exists.

If the file cannot be opened, cannot be created, or is a symlink, UUID
will ignore it. No state will be maintained.

B<WARNING>: Do not B<:persist> in a public directory. See CVE-2013-4184.
UUID attempts to avoid this, but nothing is foolproof. Only YOU can
prevent symlink attacks!

=head1 THREAD SAFETY

This module is believed to be thread safe.

=head1 UUID LIBRARY

Releases prior to UUID-0.32 required libuuid or similar be installed
first. This is no longer the case. UUID now builds against a bundled
copy of the e2fsprogs UUID code.

=head1 COPYRIGHT AND LICENSE

This software is Copyright (c) 2014-2024 by Rick Myers.

This is free software, licensed under:

  The Artistic License 2.0 (GPL Compatible)

Details of this license can be found within the 'LICENSE' text file.

=head1 AUTHOR

Current maintainer:

  Rick Myers <jrm@cpan.org>.

Authors and/or previous maintainers:

  Lukas Zapletal <lzap@cpan.org>

  Joseph N. Hall <joseph.nathan.hall@gmail.com>

  Colin Faber <cfaber@clusterfs.com>

  Peter J. Braam <braam@mountainviewdata.com>

=head1 CONTRIBUTORS

David E. Wheeler

William Faulk

gregor herrmann

Slaven Rezic

twata

=head1 SEE ALSO

RFC4122

B<uuid(3)>, B<uuid_clear(3)>, B<uuid_compare(3)>, B<uuid_copy(3)>,
B<uuid_generate(3)>, B<uuid_is_null(3)>, B<uuid_parse(3)>,
B<uuid_unparse(3)>, B<perl(1)>.

=cut
