uuid.go 6.1 KB

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