forked from josephspurrier/goversioninfo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
structbuild.go
330 lines (260 loc) · 7.46 KB
/
structbuild.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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
package goversioninfo
import (
"reflect"
)
// *****************************************************************************
// Structure Building
// *****************************************************************************
/*
Version Information Structures
http://msdn.microsoft.com/en-us/library/windows/desktop/ff468916.aspx
VersionInfo Names
http://msdn.microsoft.com/en-us/library/windows/desktop/aa381058.aspx#string-name
Translation: LangID
http://msdn.microsoft.com/en-us/library/windows/desktop/aa381058.aspx#langid
Translation: CharsetID
http://msdn.microsoft.com/en-us/library/windows/desktop/aa381058.aspx#charsetid
*/
// VSVersionInfo is the top level version container.
type VSVersionInfo struct {
WLength uint16
WValueLength uint16
WType uint16
SzKey []byte
Padding1 []byte
Value VSFixedFileInfo
Padding2 []byte
Children VSStringFileInfo
Children2 VSVarFileInfo
}
// VSFixedFileInfo - most of these should be left at the defaults.
type VSFixedFileInfo struct {
DwSignature uint32
DwStrucVersion uint32
DwFileVersionMS uint32
DwFileVersionLS uint32
DwProductVersionMS uint32
DwProductVersionLS uint32
DwFileFlagsMask uint32
DwFileFlags uint32
DwFileOS uint32
DwFileType uint32
DwFileSubtype uint32
DwFileDateMS uint32
DwFileDateLS uint32
}
// VSStringFileInfo holds multiple collections of keys and values,
// only allows for 1 collection in this package.
type VSStringFileInfo struct {
WLength uint16
WValueLength uint16
WType uint16
SzKey []byte
Padding []byte
Children VSStringTable
}
// VSStringTable holds a collection of string keys and values.
type VSStringTable struct {
WLength uint16
WValueLength uint16
WType uint16
SzKey []byte
Padding []byte
Children []VSString
}
// VSString holds the keys and values.
type VSString struct {
WLength uint16
WValueLength uint16
WType uint16
SzKey []byte
Padding []byte
Value []byte
}
// VSVarFileInfo holds the translation collection of 1.
type VSVarFileInfo struct {
WLength uint16
WValueLength uint16
WType uint16
SzKey []byte
Padding []byte
Value VSVar
}
// VSVar holds the translation key.
type VSVar struct {
WLength uint16
WValueLength uint16
WType uint16
SzKey []byte
Padding []byte
Value uint32
}
func buildString(i int, v reflect.Value) (VSString, bool) {
sValue := string(v.Field(i).Interface().(string))
sName := v.Type().Field(i).Name
ss := VSString{}
// If the value is set
if sValue != "" {
// 0 for binary, 1 for text
ss.WType = 0x01
// Create key
ss.SzKey = padString(sName, 0)
// Align to 32-bit boundary
soFar := 2
for (len(ss.SzKey)+6+soFar)%4 != 0 {
soFar += 2
}
ss.Padding = padBytes(soFar)
soFar += len(ss.SzKey)
// Align zeros to 32-bit boundary
zeros := 2
for (6+soFar+(len(padString(sValue, 0)))+zeros)%4 != 0 {
zeros += 2
}
// Create value
ss.Value = padString(sValue, zeros)
// Length of text in words (2 bytes) plus zero terminate word
ss.WValueLength = uint16(len(padString(sValue, 0))/2) + 1
// Length of structure
//ss.WLength = 6 + uint16(soFar) + (ss.WValueLength * 2)
ss.WLength = uint16(6 + soFar + len(ss.Value))
return ss, true
}
return ss, false
}
func buildStringTable(vi *VersionInfo) VSStringTable {
st := VSStringTable{}
// Always set to 0
st.WValueLength = 0x00
// 0 for binary, 1 for text
st.WType = 0x01
// Language identifier and Code page
st.SzKey = padString(vi.VarFileInfo.Translation.getTranslationString(), 0)
// Align to 32-bit boundary
soFar := 2
for (len(st.SzKey)+6+soFar)%4 != 0 {
soFar += 2
}
st.Padding = padBytes(soFar)
soFar += len(st.SzKey)
// Loop through the struct fields
v := reflect.ValueOf(vi.StringFileInfo)
for i := 0; i < v.NumField(); i++ {
// If the struct is valid
if r, ok := buildString(i, v); ok {
st.Children = append(st.Children, r)
st.WLength += r.WLength
}
}
st.WLength += 6 + uint16(soFar)
return st
}
func buildStringFileInfo(vi *VersionInfo) VSStringFileInfo {
sf := VSStringFileInfo{}
// Always set to 0
sf.WValueLength = 0x00
// 0 for binary, 1 for text
sf.WType = 0x01
sf.SzKey = padString("StringFileInfo", 0)
// Align to 32-bit boundary
soFar := 2
for (len(sf.SzKey)+6+soFar)%4 != 0 {
soFar += 2
}
sf.Padding = padBytes(soFar)
soFar += len(sf.SzKey)
// Allows for more than one string table
st := buildStringTable(vi)
sf.Children = st
sf.WLength = 6 + uint16(soFar) + st.WLength
return sf
}
func buildVar(vfi VarFileInfo) VSVar {
vs := VSVar{}
// 0 for binary, 1 for text
vs.WType = 0x00
// Create key
vs.SzKey = padString("Translation", 0)
// Align to 32-bit boundary
soFar := 2
for (len(vs.SzKey)+6+soFar)%4 != 0 {
soFar += 2
}
vs.Padding = padBytes(soFar)
soFar += len(vs.SzKey)
// Create value
vs.Value = str2Uint32(vfi.Translation.getTranslation())
// Length of text in bytes
vs.WValueLength = 4
// Length of structure
vs.WLength = 6 + vs.WValueLength + uint16(soFar)
return vs
}
func buildVarFileInfo(vfi VarFileInfo) VSVarFileInfo {
vf := VSVarFileInfo{}
// Always set to 0
vf.WValueLength = 0x00
// 0 for binary, 1 for text
vf.WType = 0x01
vf.SzKey = padString("VarFileInfo", 0)
// Align to 32-bit boundary
soFar := 2
for (len(vf.SzKey)+6+soFar)%4 != 0 {
soFar += 2
}
vf.Padding = padBytes(soFar)
soFar += len(vf.SzKey)
// TODO Allow for more than one var table
st := buildVar(vfi)
vf.Value = st
vf.WLength = 6 + st.WLength + uint16(soFar)
return vf
}
func buildFixedFileInfo(vi *VersionInfo) VSFixedFileInfo {
ff := VSFixedFileInfo{}
ff.DwSignature = 0xFEEF04BD
ff.DwStrucVersion = 0x00010000
ff.DwFileVersionMS = str2Uint32(vi.FixedFileInfo.FileVersion.getVersionHighString())
ff.DwFileVersionLS = str2Uint32(vi.FixedFileInfo.FileVersion.getVersionLowString())
ff.DwProductVersionMS = str2Uint32(vi.FixedFileInfo.ProductVersion.getVersionHighString())
ff.DwProductVersionLS = str2Uint32(vi.FixedFileInfo.ProductVersion.getVersionLowString())
ff.DwFileFlagsMask = str2Uint32(vi.FixedFileInfo.FileFlagsMask)
ff.DwFileFlags = str2Uint32(vi.FixedFileInfo.FileFlags)
ff.DwFileOS = str2Uint32(vi.FixedFileInfo.FileOS)
ff.DwFileType = str2Uint32(vi.FixedFileInfo.FileType)
ff.DwFileSubtype = str2Uint32(vi.FixedFileInfo.FileSubType)
// According to the spec, these should be zero...ugh
/*if vi.Timestamp {
now := syscall.NsecToFiletime(time.Now().UnixNano())
ff.DwFileDateMS = now.HighDateTime
ff.DwFileDateLS = now.LowDateTime
}*/
return ff
}
// Build fills the structs with data from the config file
func (v *VersionInfo) Build() {
vi := VSVersionInfo{}
// 0 for binary, 1 for text
vi.WType = 0x00
vi.SzKey = padString("VS_VERSION_INFO", 0)
// Align to 32-bit boundary
// 6 is for the size of WLength, WValueLength, and WType (each is 1 word or 2 bytes: FF FF)
soFar := 2
for (len(vi.SzKey)+6+soFar)%4 != 0 {
soFar += 2
}
vi.Padding1 = padBytes(soFar)
soFar += len(vi.SzKey)
vi.Value = buildFixedFileInfo(v)
// Length of VSFixedFileInfo (always the same)
vi.WValueLength = 0x34
// Never needs padding, not included in WLength
vi.Padding2 = []byte{}
// Build strings
vi.Children = buildStringFileInfo(v)
// Build translation
vi.Children2 = buildVarFileInfo(v.VarFileInfo)
// Calculate the total size
vi.WLength += 6 + uint16(soFar) + vi.WValueLength + vi.Children.WLength + vi.Children2.WLength
v.Structure = vi
}