1package ole
2
3var (
4	// IID_NULL is null Interface ID, used when no other Interface ID is known.
5	IID_NULL = NewGUID("{00000000-0000-0000-0000-000000000000}")
6
7	// IID_IUnknown is for IUnknown interfaces.
8	IID_IUnknown = NewGUID("{00000000-0000-0000-C000-000000000046}")
9
10	// IID_IDispatch is for IDispatch interfaces.
11	IID_IDispatch = NewGUID("{00020400-0000-0000-C000-000000000046}")
12
13	// IID_IEnumVariant is for IEnumVariant interfaces
14	IID_IEnumVariant = NewGUID("{00020404-0000-0000-C000-000000000046}")
15
16	// IID_IConnectionPointContainer is for IConnectionPointContainer interfaces.
17	IID_IConnectionPointContainer = NewGUID("{B196B284-BAB4-101A-B69C-00AA00341D07}")
18
19	// IID_IConnectionPoint is for IConnectionPoint interfaces.
20	IID_IConnectionPoint = NewGUID("{B196B286-BAB4-101A-B69C-00AA00341D07}")
21
22	// IID_IInspectable is for IInspectable interfaces.
23	IID_IInspectable = NewGUID("{AF86E2E0-B12D-4C6A-9C5A-D7AA65101E90}")
24
25	// IID_IProvideClassInfo is for IProvideClassInfo interfaces.
26	IID_IProvideClassInfo = NewGUID("{B196B283-BAB4-101A-B69C-00AA00341D07}")
27)
28
29// These are for testing and not part of any library.
30var (
31	// IID_ICOMTestString is for ICOMTestString interfaces.
32	//
33	// {E0133EB4-C36F-469A-9D3D-C66B84BE19ED}
34	IID_ICOMTestString = NewGUID("{E0133EB4-C36F-469A-9D3D-C66B84BE19ED}")
35
36	// IID_ICOMTestInt8 is for ICOMTestInt8 interfaces.
37	//
38	// {BEB06610-EB84-4155-AF58-E2BFF53680B4}
39	IID_ICOMTestInt8 = NewGUID("{BEB06610-EB84-4155-AF58-E2BFF53680B4}")
40
41	// IID_ICOMTestInt16 is for ICOMTestInt16 interfaces.
42	//
43	// {DAA3F9FA-761E-4976-A860-8364CE55F6FC}
44	IID_ICOMTestInt16 = NewGUID("{DAA3F9FA-761E-4976-A860-8364CE55F6FC}")
45
46	// IID_ICOMTestInt32 is for ICOMTestInt32 interfaces.
47	//
48	// {E3DEDEE7-38A2-4540-91D1-2EEF1D8891B0}
49	IID_ICOMTestInt32 = NewGUID("{E3DEDEE7-38A2-4540-91D1-2EEF1D8891B0}")
50
51	// IID_ICOMTestInt64 is for ICOMTestInt64 interfaces.
52	//
53	// {8D437CBC-B3ED-485C-BC32-C336432A1623}
54	IID_ICOMTestInt64 = NewGUID("{8D437CBC-B3ED-485C-BC32-C336432A1623}")
55
56	// IID_ICOMTestFloat is for ICOMTestFloat interfaces.
57	//
58	// {BF1ED004-EA02-456A-AA55-2AC8AC6B054C}
59	IID_ICOMTestFloat = NewGUID("{BF1ED004-EA02-456A-AA55-2AC8AC6B054C}")
60
61	// IID_ICOMTestDouble is for ICOMTestDouble interfaces.
62	//
63	// {BF908A81-8687-4E93-999F-D86FAB284BA0}
64	IID_ICOMTestDouble = NewGUID("{BF908A81-8687-4E93-999F-D86FAB284BA0}")
65
66	// IID_ICOMTestBoolean is for ICOMTestBoolean interfaces.
67	//
68	// {D530E7A6-4EE8-40D1-8931-3D63B8605010}
69	IID_ICOMTestBoolean = NewGUID("{D530E7A6-4EE8-40D1-8931-3D63B8605010}")
70
71	// IID_ICOMEchoTestObject is for ICOMEchoTestObject interfaces.
72	//
73	// {6485B1EF-D780-4834-A4FE-1EBB51746CA3}
74	IID_ICOMEchoTestObject = NewGUID("{6485B1EF-D780-4834-A4FE-1EBB51746CA3}")
75
76	// IID_ICOMTestTypes is for ICOMTestTypes interfaces.
77	//
78	// {CCA8D7AE-91C0-4277-A8B3-FF4EDF28D3C0}
79	IID_ICOMTestTypes = NewGUID("{CCA8D7AE-91C0-4277-A8B3-FF4EDF28D3C0}")
80
81	// CLSID_COMEchoTestObject is for COMEchoTestObject class.
82	//
83	// {3C24506A-AE9E-4D50-9157-EF317281F1B0}
84	CLSID_COMEchoTestObject = NewGUID("{3C24506A-AE9E-4D50-9157-EF317281F1B0}")
85
86	// CLSID_COMTestScalarClass is for COMTestScalarClass class.
87	//
88	// {865B85C5-0334-4AC6-9EF6-AACEC8FC5E86}
89	CLSID_COMTestScalarClass = NewGUID("{865B85C5-0334-4AC6-9EF6-AACEC8FC5E86}")
90)
91
92const hextable = "0123456789ABCDEF"
93const emptyGUID = "{00000000-0000-0000-0000-000000000000}"
94
95// GUID is Windows API specific GUID type.
96//
97// This exists to match Windows GUID type for direct passing for COM.
98// Format is in xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx.
99type GUID struct {
100	Data1 uint32
101	Data2 uint16
102	Data3 uint16
103	Data4 [8]byte
104}
105
106// NewGUID converts the given string into a globally unique identifier that is
107// compliant with the Windows API.
108//
109// The supplied string may be in any of these formats:
110//
111//  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
112//  XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
113//  {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
114//
115// The conversion of the supplied string is not case-sensitive.
116func NewGUID(guid string) *GUID {
117	d := []byte(guid)
118	var d1, d2, d3, d4a, d4b []byte
119
120	switch len(d) {
121	case 38:
122		if d[0] != '{' || d[37] != '}' {
123			return nil
124		}
125		d = d[1:37]
126		fallthrough
127	case 36:
128		if d[8] != '-' || d[13] != '-' || d[18] != '-' || d[23] != '-' {
129			return nil
130		}
131		d1 = d[0:8]
132		d2 = d[9:13]
133		d3 = d[14:18]
134		d4a = d[19:23]
135		d4b = d[24:36]
136	case 32:
137		d1 = d[0:8]
138		d2 = d[8:12]
139		d3 = d[12:16]
140		d4a = d[16:20]
141		d4b = d[20:32]
142	default:
143		return nil
144	}
145
146	var g GUID
147	var ok1, ok2, ok3, ok4 bool
148	g.Data1, ok1 = decodeHexUint32(d1)
149	g.Data2, ok2 = decodeHexUint16(d2)
150	g.Data3, ok3 = decodeHexUint16(d3)
151	g.Data4, ok4 = decodeHexByte64(d4a, d4b)
152	if ok1 && ok2 && ok3 && ok4 {
153		return &g
154	}
155	return nil
156}
157
158func decodeHexUint32(src []byte) (value uint32, ok bool) {
159	var b1, b2, b3, b4 byte
160	var ok1, ok2, ok3, ok4 bool
161	b1, ok1 = decodeHexByte(src[0], src[1])
162	b2, ok2 = decodeHexByte(src[2], src[3])
163	b3, ok3 = decodeHexByte(src[4], src[5])
164	b4, ok4 = decodeHexByte(src[6], src[7])
165	value = (uint32(b1) << 24) | (uint32(b2) << 16) | (uint32(b3) << 8) | uint32(b4)
166	ok = ok1 && ok2 && ok3 && ok4
167	return
168}
169
170func decodeHexUint16(src []byte) (value uint16, ok bool) {
171	var b1, b2 byte
172	var ok1, ok2 bool
173	b1, ok1 = decodeHexByte(src[0], src[1])
174	b2, ok2 = decodeHexByte(src[2], src[3])
175	value = (uint16(b1) << 8) | uint16(b2)
176	ok = ok1 && ok2
177	return
178}
179
180func decodeHexByte64(s1 []byte, s2 []byte) (value [8]byte, ok bool) {
181	var ok1, ok2, ok3, ok4, ok5, ok6, ok7, ok8 bool
182	value[0], ok1 = decodeHexByte(s1[0], s1[1])
183	value[1], ok2 = decodeHexByte(s1[2], s1[3])
184	value[2], ok3 = decodeHexByte(s2[0], s2[1])
185	value[3], ok4 = decodeHexByte(s2[2], s2[3])
186	value[4], ok5 = decodeHexByte(s2[4], s2[5])
187	value[5], ok6 = decodeHexByte(s2[6], s2[7])
188	value[6], ok7 = decodeHexByte(s2[8], s2[9])
189	value[7], ok8 = decodeHexByte(s2[10], s2[11])
190	ok = ok1 && ok2 && ok3 && ok4 && ok5 && ok6 && ok7 && ok8
191	return
192}
193
194func decodeHexByte(c1, c2 byte) (value byte, ok bool) {
195	var n1, n2 byte
196	var ok1, ok2 bool
197	n1, ok1 = decodeHexChar(c1)
198	n2, ok2 = decodeHexChar(c2)
199	value = (n1 << 4) | n2
200	ok = ok1 && ok2
201	return
202}
203
204func decodeHexChar(c byte) (byte, bool) {
205	switch {
206	case '0' <= c && c <= '9':
207		return c - '0', true
208	case 'a' <= c && c <= 'f':
209		return c - 'a' + 10, true
210	case 'A' <= c && c <= 'F':
211		return c - 'A' + 10, true
212	}
213
214	return 0, false
215}
216
217// String converts the GUID to string form. It will adhere to this pattern:
218//
219//  {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
220//
221// If the GUID is nil, the string representation of an empty GUID is returned:
222//
223//  {00000000-0000-0000-0000-000000000000}
224func (guid *GUID) String() string {
225	if guid == nil {
226		return emptyGUID
227	}
228
229	var c [38]byte
230	c[0] = '{'
231	putUint32Hex(c[1:9], guid.Data1)
232	c[9] = '-'
233	putUint16Hex(c[10:14], guid.Data2)
234	c[14] = '-'
235	putUint16Hex(c[15:19], guid.Data3)
236	c[19] = '-'
237	putByteHex(c[20:24], guid.Data4[0:2])
238	c[24] = '-'
239	putByteHex(c[25:37], guid.Data4[2:8])
240	c[37] = '}'
241	return string(c[:])
242}
243
244func putUint32Hex(b []byte, v uint32) {
245	b[0] = hextable[byte(v>>24)>>4]
246	b[1] = hextable[byte(v>>24)&0x0f]
247	b[2] = hextable[byte(v>>16)>>4]
248	b[3] = hextable[byte(v>>16)&0x0f]
249	b[4] = hextable[byte(v>>8)>>4]
250	b[5] = hextable[byte(v>>8)&0x0f]
251	b[6] = hextable[byte(v)>>4]
252	b[7] = hextable[byte(v)&0x0f]
253}
254
255func putUint16Hex(b []byte, v uint16) {
256	b[0] = hextable[byte(v>>8)>>4]
257	b[1] = hextable[byte(v>>8)&0x0f]
258	b[2] = hextable[byte(v)>>4]
259	b[3] = hextable[byte(v)&0x0f]
260}
261
262func putByteHex(dst, src []byte) {
263	for i := 0; i < len(src); i++ {
264		dst[i*2] = hextable[src[i]>>4]
265		dst[i*2+1] = hextable[src[i]&0x0f]
266	}
267}
268
269// IsEqualGUID compares two GUID.
270//
271// Not constant time comparison.
272func IsEqualGUID(guid1 *GUID, guid2 *GUID) bool {
273	return guid1.Data1 == guid2.Data1 &&
274		guid1.Data2 == guid2.Data2 &&
275		guid1.Data3 == guid2.Data3 &&
276		guid1.Data4[0] == guid2.Data4[0] &&
277		guid1.Data4[1] == guid2.Data4[1] &&
278		guid1.Data4[2] == guid2.Data4[2] &&
279		guid1.Data4[3] == guid2.Data4[3] &&
280		guid1.Data4[4] == guid2.Data4[4] &&
281		guid1.Data4[5] == guid2.Data4[5] &&
282		guid1.Data4[6] == guid2.Data4[6] &&
283		guid1.Data4[7] == guid2.Data4[7]
284}
285