Attribute VB_Name = "UUID"
Option Explicit
Option Base 0

' $Id: UUID.bas $
' $Date: 2012-09-09 07:47Z $
' $Revision: 1.0 $
' $Author: dai $

' *************************** COPYRIGHT NOTICE ******************************
' This code was originally written by David Ireland and is copyright
' (C) 2012 DI Management Services Pty Ltd <www.di-mgt.com.au>.
' Provided "as is". No warranties. Use at your own risk. You must make your
' own assessment of its accuracy and suitability for your own purposes.
' It is not to be altered or distributed, except as part of an application.
' You are free to use it in any application, provided this copyright notice
' is left unchanged.
' ************************ END OF COPYRIGHT NOTICE **************************

' This module uses functions from the CryptoSys (tm) PKI Toolkit available from
' <www.cryptosys.net/pki/>.
' Include the module `basCrPKI` in your project.

' REFERENCE:
' RFC 4122 "A Universally Unique IDentifier (UUID) URN Namespace", P. Leach et al,
' July 2005, <http://www.ietf.org/rfc/rfc4122.txt>.
'
' This creates a UUID (Universally Unique IDentifier) according to RFC 4122 version 4.

' 4.4.  Algorithms for Creating a UUID from Truly Random or
'       Pseudo-Random Numbers
'
'    The version 4 UUID is meant for generating UUIDs from truly-random or
'    pseudo-random numbers.
'
'    The algorithm is as follows:
'
'    o  Set the two most significant bits (bits 6 and 7) of the
'       clock_seq_hi_and_reserved to zero and one, respectively.
'
'    o  Set the four most significant bits (bits 12 through 15) of the
'       time_hi_and_version field to the 4-bit version number from
'       Section 4.1.3. [i.e. to the number 4]
'
'    o  Set all the other bits to randomly (or pseudo-randomly) chosen
'       values.


Public Function UUID_Make() As String
'                                           12345678 9012 3456 7890 123456789012
' Returns a 36-character string in the form XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
' where "X" is an "upper-case" hexadecimal digit [0-9A-F].
' Use the LCase function if you want lower-case letters.

    Dim abData() As Byte
    Dim nDataLen As Long
    Dim StrHex As String
    
    ' 1. Generate 16 random bytes = 128 bits
    nDataLen = 16
    ReDim abData(nDataLen - 1)
    Call RNG_Bytes(abData(0), nDataLen, "", 0)
    ' DEBUGGING...
    ''Debug.Print "RNG=" & cnvHexStrFromBytes(abData)
    
    ' 2. Adjust certain bits according to RFC 4122 section 4.4.
    ' This just means do the following
    ' (a) set the high nibble of the 7th byte equal to 4 and
    ' (b) set the two most significant bits of the 9th byte to 10'B,
    '     so the high nibble will be one of {8,9,A,B}.
    abData(6) = &H40 Or (abData(6) And &HF)
    abData(8) = &H80 Or (abData(8) And &H3F)
    
    ' 3. Convert the adjusted bytes to hex values
    StrHex = cnvHexStrFromBytes(abData)
    ' DEBUGGING...
    ''Debug.Print "ADJ=" & cnvHexStrFromBytes(abData)
    ''Debug.Print "                ^   ^" ' point to the nibbles we've changed
    
    ' 4. Add four hyphen '-' characters
    StrHex = Left$(StrHex, 8) & "-" & Mid$(StrHex, 9, 4) & "-" & Mid$(StrHex, 13, 4) _
        & "-" & Mid$(StrHex, 17, 4) & "-" & Right$(StrHex, 12)
    
    ' Return the UUID string
    UUID_Make = StrHex
End Function

Public Sub Test_UUID()
    Dim i As Integer
    Dim strUuid As String
    For i = 1 To 10
        strUuid = UUID_Make()
        Debug.Print strUuid
    Next
End Sub