1// Copyright 2018 Google Inc. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package uuid 6 7import ( 8 "bytes" 9 "crypto/rand" 10 "encoding/hex" 11 "errors" 12 "fmt" 13 "io" 14 "strings" 15) 16 17// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC 18// 4122. 19type UUID [16]byte 20 21// A Version represents a UUID's version. 22type Version byte 23 24// A Variant represents a UUID's variant. 25type Variant byte 26 27// Constants returned by Variant. 28const ( 29 Invalid = Variant(iota) // Invalid UUID 30 RFC4122 // The variant specified in RFC4122 31 Reserved // Reserved, NCS backward compatibility. 32 Microsoft // Reserved, Microsoft Corporation backward compatibility. 33 Future // Reserved for future definition. 34) 35 36var rander = rand.Reader // random function 37 38// Parse decodes s into a UUID or returns an error. Both the standard UUID 39// forms of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and 40// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded as well as the 41// Microsoft encoding {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} and the raw hex 42// encoding: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. 43func Parse(s string) (UUID, error) { 44 var uuid UUID 45 switch len(s) { 46 // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 47 case 36: 48 49 // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 50 case 36 + 9: 51 if strings.ToLower(s[:9]) != "urn:uuid:" { 52 return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9]) 53 } 54 s = s[9:] 55 56 // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} 57 case 36 + 2: 58 s = s[1:] 59 60 // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 61 case 32: 62 var ok bool 63 for i := range uuid { 64 uuid[i], ok = xtob(s[i*2], s[i*2+1]) 65 if !ok { 66 return uuid, errors.New("invalid UUID format") 67 } 68 } 69 return uuid, nil 70 default: 71 return uuid, fmt.Errorf("invalid UUID length: %d", len(s)) 72 } 73 // s is now at least 36 bytes long 74 // it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 75 if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { 76 return uuid, errors.New("invalid UUID format") 77 } 78 for i, x := range [16]int{ 79 0, 2, 4, 6, 80 9, 11, 81 14, 16, 82 19, 21, 83 24, 26, 28, 30, 32, 34} { 84 v, ok := xtob(s[x], s[x+1]) 85 if !ok { 86 return uuid, errors.New("invalid UUID format") 87 } 88 uuid[i] = v 89 } 90 return uuid, nil 91} 92 93// ParseBytes is like Parse, except it parses a byte slice instead of a string. 94func ParseBytes(b []byte) (UUID, error) { 95 var uuid UUID 96 switch len(b) { 97 case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 98 case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 99 if !bytes.Equal(bytes.ToLower(b[:9]), []byte("urn:uuid:")) { 100 return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9]) 101 } 102 b = b[9:] 103 case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} 104 b = b[1:] 105 case 32: // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 106 var ok bool 107 for i := 0; i < 32; i += 2 { 108 uuid[i/2], ok = xtob(b[i], b[i+1]) 109 if !ok { 110 return uuid, errors.New("invalid UUID format") 111 } 112 } 113 return uuid, nil 114 default: 115 return uuid, fmt.Errorf("invalid UUID length: %d", len(b)) 116 } 117 // s is now at least 36 bytes long 118 // it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 119 if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' { 120 return uuid, errors.New("invalid UUID format") 121 } 122 for i, x := range [16]int{ 123 0, 2, 4, 6, 124 9, 11, 125 14, 16, 126 19, 21, 127 24, 26, 28, 30, 32, 34} { 128 v, ok := xtob(b[x], b[x+1]) 129 if !ok { 130 return uuid, errors.New("invalid UUID format") 131 } 132 uuid[i] = v 133 } 134 return uuid, nil 135} 136 137// MustParse is like Parse but panics if the string cannot be parsed. 138// It simplifies safe initialization of global variables holding compiled UUIDs. 139func MustParse(s string) UUID { 140 uuid, err := Parse(s) 141 if err != nil { 142 panic(`uuid: Parse(` + s + `): ` + err.Error()) 143 } 144 return uuid 145} 146 147// FromBytes creates a new UUID from a byte slice. Returns an error if the slice 148// does not have a length of 16. The bytes are copied from the slice. 149func FromBytes(b []byte) (uuid UUID, err error) { 150 err = uuid.UnmarshalBinary(b) 151 return uuid, err 152} 153 154// Must returns uuid if err is nil and panics otherwise. 155func Must(uuid UUID, err error) UUID { 156 if err != nil { 157 panic(err) 158 } 159 return uuid 160} 161 162// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 163// , or "" if uuid is invalid. 164func (uuid UUID) String() string { 165 var buf [36]byte 166 encodeHex(buf[:], uuid) 167 return string(buf[:]) 168} 169 170// URN returns the RFC 2141 URN form of uuid, 171// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid. 172func (uuid UUID) URN() string { 173 var buf [36 + 9]byte 174 copy(buf[:], "urn:uuid:") 175 encodeHex(buf[9:], uuid) 176 return string(buf[:]) 177} 178 179func encodeHex(dst []byte, uuid UUID) { 180 hex.Encode(dst, uuid[:4]) 181 dst[8] = '-' 182 hex.Encode(dst[9:13], uuid[4:6]) 183 dst[13] = '-' 184 hex.Encode(dst[14:18], uuid[6:8]) 185 dst[18] = '-' 186 hex.Encode(dst[19:23], uuid[8:10]) 187 dst[23] = '-' 188 hex.Encode(dst[24:], uuid[10:]) 189} 190 191// Variant returns the variant encoded in uuid. 192func (uuid UUID) Variant() Variant { 193 switch { 194 case (uuid[8] & 0xc0) == 0x80: 195 return RFC4122 196 case (uuid[8] & 0xe0) == 0xc0: 197 return Microsoft 198 case (uuid[8] & 0xe0) == 0xe0: 199 return Future 200 default: 201 return Reserved 202 } 203} 204 205// Version returns the version of uuid. 206func (uuid UUID) Version() Version { 207 return Version(uuid[6] >> 4) 208} 209 210func (v Version) String() string { 211 if v > 15 { 212 return fmt.Sprintf("BAD_VERSION_%d", v) 213 } 214 return fmt.Sprintf("VERSION_%d", v) 215} 216 217func (v Variant) String() string { 218 switch v { 219 case RFC4122: 220 return "RFC4122" 221 case Reserved: 222 return "Reserved" 223 case Microsoft: 224 return "Microsoft" 225 case Future: 226 return "Future" 227 case Invalid: 228 return "Invalid" 229 } 230 return fmt.Sprintf("BadVariant%d", int(v)) 231} 232 233// SetRand sets the random number generator to r, which implements io.Reader. 234// If r.Read returns an error when the package requests random data then 235// a panic will be issued. 236// 237// Calling SetRand with nil sets the random number generator to the default 238// generator. 239func SetRand(r io.Reader) { 240 if r == nil { 241 rander = rand.Reader 242 return 243 } 244 rander = r 245} 246