github.com/linuxboot/fiano@v1.2.0/pkg/guid/guid.go (about) 1 // Copyright 2018 the LinuxBoot Authors. 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 5 // Package guid implements the mixed-endian GUID as implemented by Microsoft. 6 package guid 7 8 import ( 9 "encoding/hex" 10 "encoding/json" 11 "fmt" 12 "strings" 13 14 "github.com/linuxboot/fiano/pkg/log" 15 ) 16 17 const ( 18 // Size represents number of bytes in a GUID 19 Size = 16 20 // UExample is a example of a string GUID 21 UExample = "01234567-89AB-CDEF-0123-456789ABCDEF" 22 strFormat = "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X" 23 ) 24 25 var ( 26 fields = [...]int{4, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1} 27 ) 28 29 // GUID represents a unique identifier. 30 type GUID [Size]byte 31 32 func reverse(b []byte) { 33 for i := 0; i < len(b)/2; i++ { 34 other := len(b) - i - 1 35 b[other], b[i] = b[i], b[other] 36 } 37 } 38 39 // Parse parses a guid string. 40 func Parse(s string) (*GUID, error) { 41 // remove all hyphens to make it easier to parse. 42 stripped := strings.Replace(s, "-", "", -1) 43 decoded, err := hex.DecodeString(stripped) 44 if err != nil { 45 return nil, fmt.Errorf("guid string not correct, need string of the format \n%v\n, got \n%v", 46 UExample, s) 47 } 48 49 if len(decoded) != Size { 50 return nil, fmt.Errorf("guid string has incorrect length, need string of the format \n%v\n, got \n%v", 51 UExample, s) 52 } 53 54 u := GUID{} 55 i := 0 56 copy(u[:], decoded[:]) 57 // Correct for endianness. 58 for _, fieldlen := range fields { 59 reverse(u[i : i+fieldlen]) 60 i += fieldlen 61 } 62 return &u, nil 63 } 64 65 // MustParse parses a guid string or panics. 66 func MustParse(s string) *GUID { 67 guid, err := Parse(s) 68 if err != nil { 69 log.Fatalf("%v", err) 70 } 71 return guid 72 } 73 74 func (u GUID) String() string { 75 // Not a pointer receiver so we don't have to manually copy. 76 i := 0 77 // reverse endianness. 78 for _, fieldlen := range fields { 79 reverse(u[i : i+fieldlen]) 80 i += fieldlen 81 } 82 // Convert to []interface{} for easy printing. 83 b := make([]interface{}, Size) 84 for i := range u[:] { 85 b[i] = u[i] 86 } 87 return fmt.Sprintf(strFormat, b...) 88 } 89 90 // MarshalJSON implements the marshaller interface. 91 // This allows us to actually read and edit the json file 92 func (u *GUID) MarshalJSON() ([]byte, error) { 93 return []byte(`{"GUID" : "` + u.String() + `"}`), nil 94 } 95 96 // UnmarshalJSON implements the unmarshaller interface. 97 // This allows us to actually read and edit the json file 98 func (u *GUID) UnmarshalJSON(b []byte) error { 99 j := make(map[string]string) 100 101 if err := json.Unmarshal(b, &j); err != nil { 102 return err 103 } 104 g, err := Parse(j["GUID"]) 105 if err != nil { 106 return err 107 } 108 copy(u[:], g[:]) 109 return nil 110 }