srcanamdw/codescanner/pyinstaller/versionInfo.py
changeset 1 22878952f6e2
equal deleted inserted replaced
0:509e4801c378 1:22878952f6e2
       
     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