forked from ajkhoury/pdbfetch
-
Notifications
You must be signed in to change notification settings - Fork 0
/
guid.go
180 lines (159 loc) · 4.37 KB
/
guid.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
package pe
import (
"encoding"
"encoding/binary"
"errors"
"fmt"
"strconv"
)
// GUID represents a GUID/UUID. It has the same structure as
// golang.org/x/sys/windows.GUID, without the need for golang.org/x/sys/windows
// as a dependency to allow compilation on linux. It is also so that it can
// be used with functions expecting that type. It is defined as its own type
// so that stringification and marshaling can be supported. The representation
// matches that used by native Windows code.
type GUID struct {
Data1 uint32
Data2 uint16
Data3 uint16
Data4 [8]byte
}
var _ = (encoding.TextMarshaler)(GUID{})
var _ = (encoding.TextUnmarshaler)(&GUID{})
func fromArray(b [16]byte, order binary.ByteOrder) GUID {
var g GUID
g.Data1 = order.Uint32(b[0:4])
g.Data2 = order.Uint16(b[4:6])
g.Data3 = order.Uint16(b[6:8])
copy(g.Data4[:], b[8:16])
return g
}
func (g GUID) toArray(order binary.ByteOrder) [16]byte {
b := [16]byte{}
order.PutUint32(b[0:4], g.Data1)
order.PutUint16(b[4:6], g.Data2)
order.PutUint16(b[6:8], g.Data3)
copy(b[8:16], g.Data4[:])
return b
}
// FromArray constructs a GUID from a big-endian encoding array of 16 bytes.
func GuidFromArray(b [16]byte) GUID {
return fromArray(b, binary.BigEndian)
}
// ToArray returns an array of 16 bytes representing the GUID in big-endian
// encoding.
func (g GUID) ToArray() [16]byte {
return g.toArray(binary.BigEndian)
}
// FromWindowsArray constructs a GUID from a Windows encoding array of bytes.
func GuidFromWindowsArray(b [16]byte) GUID {
return fromArray(b, binary.LittleEndian)
}
// ToWindowsArray returns an array of 16 bytes representing the GUID in Windows encoding.
func (g GUID) ToWindowsArray() [16]byte {
return g.toArray(binary.LittleEndian)
}
// ToString returns a string representation of the value of this instance of the Guid structure.
// A single format specifier can be used to indicate how to format the value of this Guid.
// The format parameter can be "N", "D", "B", "P", or "X". If format is an empty string (""), "D" is used.
func (g GUID) ToString(format string) (string, error) {
if format == "" || format == "D" {
return fmt.Sprintf(
"%08x-%04x-%04x-%04x-%012x",
g.Data1,
g.Data2,
g.Data3,
g.Data4[:2],
g.Data4[2:]), nil
}
if format == "N" {
return fmt.Sprintf(
"%08x%04x%04x%04x%012x",
g.Data1,
g.Data2,
g.Data3,
g.Data4[:2],
g.Data4[2:]), nil
}
if format == "B" {
return fmt.Sprintf(
"{%08x-%04x-%04x-%04x-%012x}",
g.Data1,
g.Data2,
g.Data3,
g.Data4[:2],
g.Data4[2:]), nil
}
if format == "P" {
return fmt.Sprintf(
"(%08x-%04x-%04x-%04x-%012x)",
g.Data1,
g.Data2,
g.Data3,
g.Data4[:2],
g.Data4[2:]), nil
}
if format == "X" {
return fmt.Sprintf(
"(%08x-%04x-%04x-%04x-%012x)",
g.Data1,
g.Data2,
g.Data3,
g.Data4[:2],
g.Data4[2:]), nil
}
return "", errors.New("invalid format specified")
}
func (g GUID) String() string {
guidStr, _ := g.ToString("")
return guidStr
}
// FromString parses a string containing a GUID and returns the GUID. The only
// format currently supported is the `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
// format.
func GuidFromString(s string) (GUID, error) {
if len(s) != 36 {
return GUID{}, fmt.Errorf("invalid GUID %q", s)
}
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
return GUID{}, fmt.Errorf("invalid GUID %q", s)
}
var g GUID
data1, err := strconv.ParseUint(s[0:8], 16, 32)
if err != nil {
return GUID{}, fmt.Errorf("invalid GUID %q", s)
}
g.Data1 = uint32(data1)
data2, err := strconv.ParseUint(s[9:13], 16, 16)
if err != nil {
return GUID{}, fmt.Errorf("invalid GUID %q", s)
}
g.Data2 = uint16(data2)
data3, err := strconv.ParseUint(s[14:18], 16, 16)
if err != nil {
return GUID{}, fmt.Errorf("invalid GUID %q", s)
}
g.Data3 = uint16(data3)
for i, x := range []int{19, 21, 24, 26, 28, 30, 32, 34} {
v, err := strconv.ParseUint(s[x:x+2], 16, 8)
if err != nil {
return GUID{}, fmt.Errorf("invalid GUID %q", s)
}
g.Data4[i] = uint8(v)
}
return g, nil
}
// MarshalText returns the textual representation of the GUID.
func (g GUID) MarshalText() ([]byte, error) {
return []byte(g.String()), nil
}
// UnmarshalText takes the textual representation of a GUID, and unmarhals it
// into this GUID.
func (g *GUID) UnmarshalText(text []byte) error {
g2, err := GuidFromString(string(text))
if err != nil {
return err
}
*g = g2
return nil
}