1
|
1 |
# Copyright (C) 2005, Giovanni Bajo
|
|
2 |
# Based on previous work under copyright (c) 2001, 2002 McMillan Enterprises, Inc.
|
|
3 |
#
|
|
4 |
# This program is free software; you can redistribute it and/or
|
|
5 |
# modify it under the terms of the GNU General Public License
|
|
6 |
# as published by the Free Software Foundation; either version 2
|
|
7 |
# of the License, or (at your option) any later version.
|
|
8 |
#
|
|
9 |
# This program is distributed in the hope that it will be useful,
|
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12 |
# GNU General Public License for more details.
|
|
13 |
#
|
|
14 |
# You should have received a copy of the GNU General Public License
|
|
15 |
# along with this program; if not, write to the Free Software
|
|
16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
17 |
import win32api
|
|
18 |
import struct
|
|
19 |
import pywintypes
|
|
20 |
import string
|
|
21 |
import pprint
|
|
22 |
|
|
23 |
TEST=0
|
|
24 |
|
|
25 |
LOAD_LIBRARY_AS_DATAFILE = 2
|
|
26 |
RT_VERSION = 16
|
|
27 |
|
|
28 |
def getRaw0(o):
|
|
29 |
return o.raw
|
|
30 |
def getRaw1(o):
|
|
31 |
return str(buffer(o))
|
|
32 |
import sys
|
|
33 |
if hasattr(sys, "version_info"):
|
|
34 |
pyvers = sys.version_info[0]*10 + sys.version_info[1]
|
|
35 |
else:
|
|
36 |
toks = string.split(sys.version, '.', 2)
|
|
37 |
pyvers = int(toks[0])*10 + int(toks[1])
|
|
38 |
if pyvers < 20:
|
|
39 |
getRaw = getRaw0
|
|
40 |
else:
|
|
41 |
getRaw = getRaw1
|
|
42 |
|
|
43 |
|
|
44 |
##VS_VERSION_INFO {
|
|
45 |
## WORD wLength; // Specifies the length of the VS_VERSION_INFO structure
|
|
46 |
## WORD wValueLength; // Specifies the length of the Value member
|
|
47 |
## WORD wType; // 1 means text, 0 means binary
|
|
48 |
## WCHAR szKey[]; // Contains the Unicode string "VS_VERSION_INFO".
|
|
49 |
## WORD Padding1[];
|
|
50 |
## VS_FIXEDFILEINFO Value;
|
|
51 |
## WORD Padding2[];
|
|
52 |
## WORD Children[]; // Specifies a list of zero or more StringFileInfo or VarFileInfo structures (or both) that are children of the current version structure.
|
|
53 |
##};
|
|
54 |
def decode(pathnm):
|
|
55 |
h = win32api.LoadLibraryEx(pathnm, 0, LOAD_LIBRARY_AS_DATAFILE)
|
|
56 |
nm = win32api.EnumResourceNames(h, RT_VERSION)[0]
|
|
57 |
data = win32api.LoadResource(h, RT_VERSION, nm)
|
|
58 |
vs = VSVersionInfo()
|
|
59 |
j = vs.fromRaw(data)
|
|
60 |
if TEST:
|
|
61 |
print vs
|
|
62 |
if data[:j] != vs.toRaw():
|
|
63 |
print "AAAAAGGHHHH"
|
|
64 |
txt = repr(vs)
|
|
65 |
glbls = {}
|
|
66 |
glbls['VSVersionInfo'] = VSVersionInfo
|
|
67 |
glbls['FixedFileInfo'] = FixedFileInfo
|
|
68 |
glbls['StringFileInfo'] = StringFileInfo
|
|
69 |
glbls['StringTable'] = StringTable
|
|
70 |
glbls['StringStruct'] = StringStruct
|
|
71 |
glbls['VarFileInfo'] = VarFileInfo
|
|
72 |
glbls['VarStruct'] = VarStruct
|
|
73 |
vs2 = eval(txt+'\n', glbls)
|
|
74 |
if vs.toRaw() != vs2.toRaw():
|
|
75 |
print
|
|
76 |
print 'reconstruction not the same!'
|
|
77 |
print vs2
|
|
78 |
win32api.FreeLibrary(h)
|
|
79 |
return vs
|
|
80 |
|
|
81 |
class VSVersionInfo:
|
|
82 |
def __init__(self, ffi=None, kids=None):
|
|
83 |
self.ffi = ffi
|
|
84 |
self.kids = kids
|
|
85 |
if kids is None:
|
|
86 |
self.kids = []
|
|
87 |
def fromRaw(self, data):
|
|
88 |
i, (sublen, vallen, wType, nm) = parseCommon(data)
|
|
89 |
#vallen is length of the ffi, typ is 0, nm is 'VS_VERSION_INFO'
|
|
90 |
i = ((i + 3) / 4) * 4
|
|
91 |
# now a VS_FIXEDFILEINFO
|
|
92 |
self.ffi = FixedFileInfo()
|
|
93 |
j = self.ffi.fromRaw(data, i)
|
|
94 |
#print ffi
|
|
95 |
if TEST:
|
|
96 |
if data[i:j] != self.ffi.toRaw():
|
|
97 |
print "raw:", `data[i:j]`
|
|
98 |
print "ffi:", `self.ffi.toRaw()`
|
|
99 |
i = j
|
|
100 |
while i < sublen:
|
|
101 |
j = i
|
|
102 |
i, (csublen, cvallen, ctyp, nm) = parseCommon(data, i)
|
|
103 |
if string.strip(str(nm)) == "StringFileInfo":
|
|
104 |
sfi = StringFileInfo()
|
|
105 |
k = sfi.fromRaw(csublen, cvallen, nm, data, i, j+csublen)
|
|
106 |
if TEST:
|
|
107 |
if data[j:k] != sfi.toRaw():
|
|
108 |
rd = data[j:k]
|
|
109 |
sd = sfi.toRaw()
|
|
110 |
for x in range(0, len(rd), 16):
|
|
111 |
rds = rd[x:x+16]
|
|
112 |
sds = sd[x:x+16]
|
|
113 |
if rds != sds:
|
|
114 |
print "rd[%s:%s+16]: %s" % (x, x, `rds`)
|
|
115 |
print "sd[%s:%s+16]: %s" % (x, x, `sds`)
|
|
116 |
print
|
|
117 |
print "raw: len %d, wLength %d" % (len(rd), struct.unpack('h', rd[:2])[0])
|
|
118 |
print "sfi: len %d, wLength %d" % (len(sd), struct.unpack('h', sd[:2])[0])
|
|
119 |
self.kids.append(sfi)
|
|
120 |
i = k
|
|
121 |
else:
|
|
122 |
vfi = VarFileInfo()
|
|
123 |
k = vfi.fromRaw(csublen, cvallen, nm, data, i, j+csublen)
|
|
124 |
self.kids.append(vfi)
|
|
125 |
if TEST:
|
|
126 |
if data[j:k] != vfi.toRaw():
|
|
127 |
print "raw:", `data[j:k]`
|
|
128 |
print "vfi:", `vfi.toRaw()`
|
|
129 |
i = k
|
|
130 |
i = j + csublen
|
|
131 |
i = ((i + 3) / 4) * 4
|
|
132 |
return i
|
|
133 |
def toRaw(self):
|
|
134 |
nm = pywintypes.Unicode('VS_VERSION_INFO')
|
|
135 |
rawffi = self.ffi.toRaw()
|
|
136 |
vallen = len(rawffi)
|
|
137 |
typ = 0
|
|
138 |
sublen = 6 + 2*len(nm) + 2
|
|
139 |
pad = ''
|
|
140 |
if sublen % 4:
|
|
141 |
pad = '\000\000'
|
|
142 |
sublen = sublen + len(pad) + vallen
|
|
143 |
pad2 = ''
|
|
144 |
if sublen % 4:
|
|
145 |
pad2 = '\000\000'
|
|
146 |
tmp = []
|
|
147 |
for kid in self.kids:
|
|
148 |
tmp.append(kid.toRaw())
|
|
149 |
tmp = string.join(tmp, '')
|
|
150 |
sublen = sublen + len(pad2) + len(tmp)
|
|
151 |
return struct.pack('hhh', sublen, vallen, typ) + getRaw(nm) + '\000\000' + pad + rawffi + pad2 + tmp
|
|
152 |
def __repr__(self, indent=''):
|
|
153 |
tmp = []
|
|
154 |
newindent = indent + ' '
|
|
155 |
for kid in self.kids:
|
|
156 |
tmp.append(kid.__repr__(newindent+' '))
|
|
157 |
tmp = string.join(tmp, ', \n')
|
|
158 |
return "VSVersionInfo(\n%sffi=%s,\n%skids=[\n%s\n%s]\n)" % (newindent, self.ffi.__repr__(newindent), newindent, tmp, newindent)
|
|
159 |
|
|
160 |
def parseCommon(data, start=0):
|
|
161 |
i = start + 6
|
|
162 |
(wLength, wValueLength, wType) = struct.unpack('3h', data[start:i])
|
|
163 |
#print "wLength, wValueLength, wType, i:", wLength, wValueLength, wType, i
|
|
164 |
i, szKey = parseUString(data, i, i+wLength)
|
|
165 |
#i = ((i + 3) / 4) * 4
|
|
166 |
#print `data[start+6:start+wLength]`
|
|
167 |
return i, (wLength, wValueLength, wType, szKey)
|
|
168 |
|
|
169 |
def parseUString(data, start, limit):
|
|
170 |
i = start
|
|
171 |
while i < limit:
|
|
172 |
if data[i:i+2] == '\000\000':
|
|
173 |
break
|
|
174 |
i = i + 2
|
|
175 |
szKey = pywintypes.UnicodeFromRaw(data[start:i])
|
|
176 |
i = i + 2
|
|
177 |
#print "szKey:", '"'+str(szKey)+'"', "(consumed", i-start, "bytes - to", i, ")"
|
|
178 |
return i, szKey
|
|
179 |
|
|
180 |
##VS_FIXEDFILEINFO { // vsffi
|
|
181 |
## DWORD dwSignature; //Contains the value 0xFEEFO4BD
|
|
182 |
## DWORD dwStrucVersion; //Specifies the binary version number of this structure. The high-order word of this member contains the major version number, and the low-order word contains the minor version number.
|
|
183 |
## DWORD dwFileVersionMS; // Specifies the most significant 32 bits of the file's binary version number
|
|
184 |
## DWORD dwFileVersionLS; //
|
|
185 |
## DWORD dwProductVersionMS; // Specifies the most significant 32 bits of the binary version number of the product with which this file was distributed
|
|
186 |
## DWORD dwProductVersionLS; //
|
|
187 |
## DWORD dwFileFlagsMask; // Contains a bitmask that specifies the valid bits in dwFileFlags. A bit is valid only if it was defined when the file was created.
|
|
188 |
## DWORD dwFileFlags; // VS_FF_DEBUG, VS_FF_PATCHED etc.
|
|
189 |
## DWORD dwFileOS; // VOS_NT, VOS_WINDOWS32 etc.
|
|
190 |
## DWORD dwFileType; // VFT_APP etc.
|
|
191 |
## DWORD dwFileSubtype; // 0 unless VFT_DRV or VFT_FONT or VFT_VXD
|
|
192 |
## DWORD dwFileDateMS;
|
|
193 |
## DWORD dwFileDateLS;
|
|
194 |
##};
|
|
195 |
|
|
196 |
class FixedFileInfo:
|
|
197 |
def __init__(self, filevers=(0, 0, 0, 0), prodvers=(0, 0, 0, 0), mask=0x3f, flags=0x0, OS=0x40004, fileType=0x1, subtype=0x0, date=(0, 0)):
|
|
198 |
self.sig = 0xfeef04bdL
|
|
199 |
self.strucVersion = 0x10000
|
|
200 |
self.fileVersionMS = (filevers[0] << 16) | (filevers[1] & 0xffff)
|
|
201 |
self.fileVersionLS = (filevers[2] << 16) | (filevers[3] & 0xffff)
|
|
202 |
self.productVersionMS = (prodvers[0] << 16) | (prodvers[1] & 0xffff)
|
|
203 |
self.productVersionLS = (prodvers[2] << 16) | (prodvers[3] & 0xffff)
|
|
204 |
self.fileFlagsMask = mask
|
|
205 |
self.fileFlags = flags
|
|
206 |
self.fileOS = OS
|
|
207 |
self.fileType = fileType
|
|
208 |
self.fileSubtype = subtype
|
|
209 |
self.fileDateMS = date[0]
|
|
210 |
self.fileDateLS = date[1]
|
|
211 |
def fromRaw(self, data, i):
|
|
212 |
(self.sig,
|
|
213 |
self.strucVersion,
|
|
214 |
self.fileVersionMS,
|
|
215 |
self.fileVersionLS,
|
|
216 |
self.productVersionMS,
|
|
217 |
self.productVersionLS,
|
|
218 |
self.fileFlagsMask,
|
|
219 |
self.fileFlags,
|
|
220 |
self.fileOS,
|
|
221 |
self.fileType,
|
|
222 |
self.fileSubtype,
|
|
223 |
self.fileDateMS,
|
|
224 |
self.fileDateLS) = struct.unpack('13l', data[i:i+52])
|
|
225 |
return i+52
|
|
226 |
def toRaw(self):
|
|
227 |
return struct.pack('L12l', self.sig,
|
|
228 |
self.strucVersion,
|
|
229 |
self.fileVersionMS,
|
|
230 |
self.fileVersionLS,
|
|
231 |
self.productVersionMS,
|
|
232 |
self.productVersionLS,
|
|
233 |
self.fileFlagsMask,
|
|
234 |
self.fileFlags,
|
|
235 |
self.fileOS,
|
|
236 |
self.fileType,
|
|
237 |
self.fileSubtype,
|
|
238 |
self.fileDateMS,
|
|
239 |
self.fileDateLS)
|
|
240 |
def __repr__(self, indent=''):
|
|
241 |
fv = (self.fileVersionMS >> 16, self.fileVersionMS & 0xffff, self.fileVersionLS >> 16, self.fileVersionLS & 0xFFFF)
|
|
242 |
pv = (self.productVersionMS >> 16, self.productVersionMS & 0xffff, self.productVersionLS >> 16, self.productVersionLS & 0xFFFF)
|
|
243 |
fd = (self.fileDateMS, self.fileDateLS)
|
|
244 |
tmp = ["FixedFileInfo(",
|
|
245 |
"filevers=%s," % (fv,),
|
|
246 |
"prodvers=%s," % (pv,),
|
|
247 |
"mask=%s," % hex(self.fileFlagsMask),
|
|
248 |
"flags=%s," % hex(self.fileFlags),
|
|
249 |
"OS=%s," % hex(self.fileOS),
|
|
250 |
"fileType=%s," % hex(self.fileType),
|
|
251 |
"subtype=%s," % hex(self.fileSubtype),
|
|
252 |
"date=%s" % (fd,),
|
|
253 |
")"
|
|
254 |
]
|
|
255 |
return string.join(tmp, '\n'+indent+' ')
|
|
256 |
|
|
257 |
##StringFileInfo {
|
|
258 |
## WORD wLength; // Specifies the length of the version resource
|
|
259 |
## WORD wValueLength; // Specifies the length of the Value member in the current VS_VERSION_INFO structure
|
|
260 |
## WORD wType; // 1 means text, 0 means binary
|
|
261 |
## WCHAR szKey[]; // Contains the Unicode string "StringFileInfo".
|
|
262 |
## WORD Padding[];
|
|
263 |
## StringTable Children[]; // Specifies a list of zero or more String structures
|
|
264 |
##};
|
|
265 |
|
|
266 |
class StringFileInfo:
|
|
267 |
def __init__(self, kids=None):
|
|
268 |
self.name = "StringFileInfo"
|
|
269 |
if kids is None:
|
|
270 |
self.kids = []
|
|
271 |
else:
|
|
272 |
self.kids = kids
|
|
273 |
def fromRaw(self, sublen, vallen, name, data, i, limit):
|
|
274 |
self.name = name
|
|
275 |
while i < limit:
|
|
276 |
st = StringTable()
|
|
277 |
j = st.fromRaw(data, i, limit)
|
|
278 |
if TEST:
|
|
279 |
if data[i:j] != st.toRaw():
|
|
280 |
rd = data[i:j]
|
|
281 |
sd = st.toRaw()
|
|
282 |
for x in range(0, len(rd), 16):
|
|
283 |
rds = rd[x:x+16]
|
|
284 |
sds = sd[x:x+16]
|
|
285 |
if rds != sds:
|
|
286 |
print "rd[%s:%s+16]: %s" % (x, x, `rds`)
|
|
287 |
print "sd[%s:%s+16]: %s" % (x, x, `sds`)
|
|
288 |
print
|
|
289 |
print "raw: len %d, wLength %d" % (len(rd), struct.unpack('h', rd[:2])[0])
|
|
290 |
print " st: len %d, wLength %d" % (len(sd), struct.unpack('h', sd[:2])[0])
|
|
291 |
self.kids.append(st)
|
|
292 |
i = j
|
|
293 |
return i
|
|
294 |
def toRaw(self):
|
|
295 |
if type(self.name) is STRINGTYPE:
|
|
296 |
self.name = pywintypes.Unicode(self.name)
|
|
297 |
vallen = 0
|
|
298 |
typ = 1
|
|
299 |
sublen = 6 + 2*len(self.name) + 2
|
|
300 |
pad = ''
|
|
301 |
if sublen % 4:
|
|
302 |
pad = '\000\000'
|
|
303 |
tmp = []
|
|
304 |
for kid in self.kids:
|
|
305 |
tmp.append(kid.toRaw())
|
|
306 |
tmp = string.join(tmp, '')
|
|
307 |
sublen = sublen + len(pad) + len(tmp)
|
|
308 |
if tmp[-2:] == '\000\000':
|
|
309 |
sublen = sublen - 2
|
|
310 |
return struct.pack('hhh', sublen, vallen, typ) + getRaw(self.name) + '\000\000' + pad + tmp
|
|
311 |
def __repr__(self, indent=''):
|
|
312 |
tmp = []
|
|
313 |
newindent = indent + ' '
|
|
314 |
for kid in self.kids:
|
|
315 |
tmp.append(kid.__repr__(newindent))
|
|
316 |
tmp = string.join(tmp, ', \n')
|
|
317 |
return "%sStringFileInfo(\n%s[\n%s\n%s])" % (indent, newindent, tmp, newindent)
|
|
318 |
|
|
319 |
##StringTable {
|
|
320 |
## WORD wLength;
|
|
321 |
## WORD wValueLength;
|
|
322 |
## WORD wType;
|
|
323 |
## WCHAR szKey[];
|
|
324 |
## String Children[]; // Specifies a list of zero or more String structures.
|
|
325 |
##};
|
|
326 |
|
|
327 |
class StringTable:
|
|
328 |
def __init__(self, name=None, kids=None):
|
|
329 |
self.name = name
|
|
330 |
self.kids = kids
|
|
331 |
if name is None:
|
|
332 |
self.name = ''
|
|
333 |
if kids is None:
|
|
334 |
self.kids = []
|
|
335 |
def fromRaw(self, data, i, limit):
|
|
336 |
#print "Parsing StringTable"
|
|
337 |
i, (cpsublen, cpwValueLength, cpwType, self.name) = parseCodePage(data, i, limit) # should be code page junk
|
|
338 |
#i = ((i + 3) / 4) * 4
|
|
339 |
while i < limit:
|
|
340 |
ss = StringStruct()
|
|
341 |
j = ss.fromRaw(data, i, limit)
|
|
342 |
if TEST:
|
|
343 |
if data[i:j] != ss.toRaw():
|
|
344 |
print "raw:", `data[i:j]`
|
|
345 |
print " ss:", `ss.toRaw()`
|
|
346 |
i = j
|
|
347 |
self.kids.append(ss)
|
|
348 |
i = ((i + 3) / 4) * 4
|
|
349 |
return i
|
|
350 |
def toRaw(self):
|
|
351 |
if type(self.name) is STRINGTYPE:
|
|
352 |
self.name = pywintypes.Unicode(self.name)
|
|
353 |
vallen = 0
|
|
354 |
typ = 1
|
|
355 |
sublen = 6 + 2*len(self.name) + 2
|
|
356 |
tmp = []
|
|
357 |
for kid in self.kids:
|
|
358 |
raw = kid.toRaw()
|
|
359 |
if len(raw) % 4:
|
|
360 |
raw = raw + '\000\000'
|
|
361 |
tmp.append(raw)
|
|
362 |
tmp = string.join(tmp, '')
|
|
363 |
sublen = sublen + len(tmp)
|
|
364 |
if tmp[-2:] == '\000\000':
|
|
365 |
sublen = sublen - 2
|
|
366 |
return struct.pack('hhh', sublen, vallen, typ) + getRaw(self.name) + '\000\000' + tmp
|
|
367 |
def __repr__(self, indent=''):
|
|
368 |
tmp = []
|
|
369 |
newindent = indent + ' '
|
|
370 |
for kid in self.kids:
|
|
371 |
tmp.append(repr(kid))
|
|
372 |
tmp = string.join(tmp, ',\n%s' % newindent)
|
|
373 |
return "%sStringTable(\n%s'%s', \n%s[%s])" % (indent, newindent, str(self.name), newindent, tmp)
|
|
374 |
|
|
375 |
##String {
|
|
376 |
## WORD wLength;
|
|
377 |
## WORD wValueLength;
|
|
378 |
## WORD wType;
|
|
379 |
## WCHAR szKey[];
|
|
380 |
## WORD Padding[];
|
|
381 |
## String Value[];
|
|
382 |
##};
|
|
383 |
|
|
384 |
class StringStruct:
|
|
385 |
def __init__(self, name=None, val=None):
|
|
386 |
self.name = name
|
|
387 |
self.val = val
|
|
388 |
if name is None:
|
|
389 |
self.name = ''
|
|
390 |
if val is None:
|
|
391 |
self.val = ''
|
|
392 |
def fromRaw(self, data, i, limit):
|
|
393 |
i, (sublen, vallen, typ, self.name) = parseCommon(data, i)
|
|
394 |
limit = i + sublen
|
|
395 |
i = ((i + 3) / 4) * 4
|
|
396 |
i, self.val = parseUString(data, i, limit)
|
|
397 |
return i
|
|
398 |
def toRaw(self):
|
|
399 |
if type(self.name) is STRINGTYPE:
|
|
400 |
self.name = pywintypes.Unicode(self.name)
|
|
401 |
if type(self.val) is STRINGTYPE:
|
|
402 |
self.val = pywintypes.Unicode(self.val)
|
|
403 |
vallen = len(self.val) + 1
|
|
404 |
typ = 1
|
|
405 |
sublen = 6 + 2*len(self.name) + 2
|
|
406 |
pad = ''
|
|
407 |
if sublen % 4:
|
|
408 |
pad = '\000\000'
|
|
409 |
sublen = sublen + len(pad) + 2*vallen
|
|
410 |
return struct.pack('hhh', sublen, vallen, typ) + getRaw(self.name) + '\000\000' + pad + getRaw(self.val) + '\000\000'
|
|
411 |
def __repr__(self, indent=''):
|
|
412 |
if pyvers < 20:
|
|
413 |
return "StringStruct('%s', '%s')" % (str(self.name), str(self.val))
|
|
414 |
else:
|
|
415 |
return "StringStruct('%s', '%s')" % (self.name, self.val)
|
|
416 |
|
|
417 |
def parseCodePage(data, i, limit):
|
|
418 |
#print "Parsing CodePage"
|
|
419 |
i, (sublen, wValueLength, wType, nm) = parseCommon(data, i)
|
|
420 |
#i = ((i + 3) / 4) * 4
|
|
421 |
return i, (sublen, wValueLength, wType, nm)
|
|
422 |
|
|
423 |
##VarFileInfo {
|
|
424 |
## WORD wLength; // Specifies the length of the version resource
|
|
425 |
## WORD wValueLength; // Specifies the length of the Value member in the current VS_VERSION_INFO structure
|
|
426 |
## WORD wType; // 1 means text, 0 means binary
|
|
427 |
## WCHAR szKey[]; // Contains the Unicode string "VarFileInfo".
|
|
428 |
## WORD Padding[];
|
|
429 |
## Var Children[]; // Specifies a list of zero or more Var structures
|
|
430 |
##};
|
|
431 |
|
|
432 |
class VarFileInfo:
|
|
433 |
def __init__(self, kids=None):
|
|
434 |
if kids is None:
|
|
435 |
self.kids = []
|
|
436 |
else:
|
|
437 |
self.kids = kids
|
|
438 |
def fromRaw(self, sublen, vallen, name, data, i, limit):
|
|
439 |
self.sublen = sublen
|
|
440 |
self.vallen = vallen
|
|
441 |
self.name = name
|
|
442 |
i = ((i + 3) / 4) * 4
|
|
443 |
while i < limit:
|
|
444 |
vs = VarStruct()
|
|
445 |
j = vs.fromRaw(data, i, limit)
|
|
446 |
self.kids.append(vs)
|
|
447 |
if TEST:
|
|
448 |
if data[i:j] != vs.toRaw():
|
|
449 |
print "raw:", `data[i:j]`
|
|
450 |
print "cmp:", `vs.toRaw()`
|
|
451 |
i = j
|
|
452 |
return i
|
|
453 |
def toRaw(self):
|
|
454 |
self.vallen = 0
|
|
455 |
self.wType = 1
|
|
456 |
self.name = pywintypes.Unicode('VarFileInfo')
|
|
457 |
sublen = 6 + 2*len(self.name) + 2
|
|
458 |
pad = ''
|
|
459 |
if sublen % 4:
|
|
460 |
pad = '\000\000'
|
|
461 |
tmp = []
|
|
462 |
for kid in self.kids:
|
|
463 |
tmp.append(kid.toRaw())
|
|
464 |
tmp = string.join(tmp, '')
|
|
465 |
self.sublen = sublen + len(pad) + len(tmp)
|
|
466 |
return struct.pack('hhh', self.sublen, self.vallen, self.wType) + getRaw(self.name) + '\000\000' + pad + tmp
|
|
467 |
def __repr__(self, indent=''):
|
|
468 |
tmp = map(repr, self.kids)
|
|
469 |
return "%sVarFileInfo([%s])" % (indent, string.join(tmp, ', '))
|
|
470 |
|
|
471 |
##Var {
|
|
472 |
## WORD wLength; // Specifies the length of the version resource
|
|
473 |
## WORD wValueLength; // Specifies the length of the Value member in the current VS_VERSION_INFO structure
|
|
474 |
## WORD wType; // 1 means text, 0 means binary
|
|
475 |
## WCHAR szKey[]; // Contains the Unicode string "Translation" or a user-defined key string value
|
|
476 |
## WORD Padding[]; //
|
|
477 |
## WORD Value[]; // Specifies a list of one or more values that are language and code-page identifiers
|
|
478 |
##};
|
|
479 |
|
|
480 |
STRINGTYPE = type('')
|
|
481 |
|
|
482 |
class VarStruct:
|
|
483 |
def __init__(self, name=None, kids=None):
|
|
484 |
self.name = name
|
|
485 |
self.kids = kids
|
|
486 |
if name is None:
|
|
487 |
self.name = ''
|
|
488 |
if kids is None:
|
|
489 |
self.kids = []
|
|
490 |
def fromRaw(self, data, i, limit):
|
|
491 |
i, (self.sublen, self.wValueLength, self.wType, self.name) = parseCommon(data, i)
|
|
492 |
i = ((i + 3) / 4) * 4
|
|
493 |
for j in range(self.wValueLength/2):
|
|
494 |
kid = struct.unpack('h', data[i:i+2])[0]
|
|
495 |
self.kids.append(kid)
|
|
496 |
i = i + 2
|
|
497 |
return i
|
|
498 |
def toRaw(self):
|
|
499 |
self.wValueLength = len(self.kids) * 2
|
|
500 |
self.wType = 0
|
|
501 |
if type(self.name) is STRINGTYPE:
|
|
502 |
self.name = pywintypes.Unicode(self.name)
|
|
503 |
sublen = 6 + 2*len(self.name) + 2
|
|
504 |
pad = ''
|
|
505 |
if sublen % 4:
|
|
506 |
pad = '\000\000'
|
|
507 |
self.sublen = sublen + len(pad) + self.wValueLength
|
|
508 |
tmp = []
|
|
509 |
for kid in self.kids:
|
|
510 |
tmp.append(struct.pack('h', kid))
|
|
511 |
tmp = string.join(tmp, '')
|
|
512 |
return struct.pack('hhh', self.sublen, self.wValueLength, self.wType) + getRaw(self.name) + '\000\000' + pad + tmp
|
|
513 |
def __repr__(self, indent=''):
|
|
514 |
return "VarStruct('%s', %s)" % (str(self.name), repr(self.kids))
|
|
515 |
|
|
516 |
def SetVersion(exenm, versionfile):
|
|
517 |
txt = open(versionfile, 'r').read()
|
|
518 |
vs = eval(txt+'\n', globals())
|
|
519 |
hdst = win32api.BeginUpdateResource(exenm, 0)
|
|
520 |
win32api.UpdateResource(hdst, RT_VERSION, 1, vs.toRaw())
|
|
521 |
win32api.EndUpdateResource (hdst, 0)
|
|
522 |
|
|
523 |
if __name__ == '__main__':
|
|
524 |
import sys
|
|
525 |
TEST = 1
|
|
526 |
if len(sys.argv) < 2:
|
|
527 |
decode('c:/Program Files/Netscape/Communicator/Program/netscape.exe')
|
|
528 |
else:
|
|
529 |
print "Examining", sys.argv[1]
|
|
530 |
decode(sys.argv[1])
|
|
531 |
|