|
1 #! /usr/bin/env python |
|
2 # Copyright (C) 2005, Giovanni Bajo |
|
3 # Based on previous work under copyright (c) 2002 McMillan Enterprises, Inc. |
|
4 # |
|
5 # This program is free software; you can redistribute it and/or |
|
6 # modify it under the terms of the GNU General Public License |
|
7 # as published by the Free Software Foundation; either version 2 |
|
8 # of the License, or (at your option) any later version. |
|
9 # |
|
10 # This program is distributed in the hope that it will be useful, |
|
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 # GNU General Public License for more details. |
|
14 # |
|
15 # You should have received a copy of the GNU General Public License |
|
16 # along with this program; if not, write to the Free Software |
|
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|
18 |
|
19 # This code is courtesy of Thomas Heller, who |
|
20 # has kindly donated it to this project. |
|
21 RT_ICON = 3 |
|
22 RT_GROUP_ICON = 14 |
|
23 LOAD_LIBRARY_AS_DATAFILE = 2 |
|
24 |
|
25 import struct |
|
26 |
|
27 class Structure: |
|
28 def __init__ (self): |
|
29 size = self._sizeInBytes = struct.calcsize (self._format_) |
|
30 self._fields_ = list (struct.unpack (self._format_, '\000' * size)) |
|
31 indexes = self._indexes_ = {} |
|
32 for i in range (len (self._names_)): |
|
33 indexes[self._names_[i]] = i |
|
34 def dump (self): |
|
35 print "I: DUMP of", self |
|
36 for name in self._names_: |
|
37 if name[0] != '_': |
|
38 print "I: %20s = %s" % (name, getattr (self, name)) |
|
39 print |
|
40 def __getattr__ (self, name): |
|
41 if name in self._names_: |
|
42 index = self._indexes_[name] |
|
43 return self._fields_[index] |
|
44 try: |
|
45 return self.__dict__[name] |
|
46 except KeyError: |
|
47 raise AttributeError, name |
|
48 def __setattr__ (self, name, value): |
|
49 if name in self._names_: |
|
50 index = self._indexes_[name] |
|
51 self._fields_[index] = value |
|
52 else: |
|
53 self.__dict__[name] = value |
|
54 def tostring (self): |
|
55 return apply (struct.pack, [self._format_,] + self._fields_) |
|
56 def fromfile (self, file): |
|
57 data = file.read (self._sizeInBytes) |
|
58 self._fields_ = list (struct.unpack (self._format_, data)) |
|
59 |
|
60 class ICONDIRHEADER (Structure): |
|
61 _names_ = "idReserved", "idType", "idCount" |
|
62 _format_ = "hhh" |
|
63 |
|
64 class ICONDIRENTRY (Structure): |
|
65 _names_ = "bWidth", "bHeight", "bColorCount", "bReserved", "wPlanes", "wBitCount", "dwBytesInRes", "dwImageOffset" |
|
66 _format_ = "bbbbhhii" |
|
67 |
|
68 class GRPICONDIR (Structure): |
|
69 _names_ = "idReserved", "idType", "idCount" |
|
70 _format_ = "hhh" |
|
71 |
|
72 class GRPICONDIRENTRY (Structure): |
|
73 _names_ = "bWidth", "bHeight", "bColorCount", "bReserved", "wPlanes", "wBitCount", "dwBytesInRes", "nID" |
|
74 _format_ = "bbbbhhih" |
|
75 |
|
76 class IconFile: |
|
77 def __init__ (self, path): |
|
78 self.path = path |
|
79 file = open (path, "rb") |
|
80 self.entries = [] |
|
81 self.images = [] |
|
82 header = self.header = ICONDIRHEADER() |
|
83 header.fromfile (file) |
|
84 for i in range (header.idCount): |
|
85 entry = ICONDIRENTRY() |
|
86 entry.fromfile (file) |
|
87 self.entries.append (entry) |
|
88 for e in self.entries: |
|
89 file.seek (e.dwImageOffset, 0) |
|
90 self.images.append (file.read (e.dwBytesInRes)) |
|
91 |
|
92 def grp_icon_dir (self): |
|
93 return self.header.tostring() |
|
94 |
|
95 def grp_icondir_entries (self): |
|
96 data = "" |
|
97 i = 1 |
|
98 for entry in self.entries: |
|
99 e = GRPICONDIRENTRY() |
|
100 for n in e._names_[:-1]: |
|
101 setattr(e, n, getattr (entry, n)) |
|
102 e.nID = i |
|
103 i = i + 1 |
|
104 data = data + e.tostring() |
|
105 return data |
|
106 |
|
107 |
|
108 def CopyIcons_FromIco (dstpath, srcpath): |
|
109 f = IconFile (srcpath) |
|
110 print "I: Updating icons from", srcpath, "to", dstpath |
|
111 import win32api #, win32con |
|
112 hdst = win32api.BeginUpdateResource (dstpath, 0) |
|
113 data = f.grp_icon_dir() |
|
114 data = data + f.grp_icondir_entries() |
|
115 win32api.UpdateResource (hdst, RT_GROUP_ICON, 1, data) |
|
116 print "I: Writing RT_GROUP_ICON resource with %d bytes" % len (data) |
|
117 i = 1 |
|
118 for data in f.images: |
|
119 win32api.UpdateResource (hdst, RT_ICON, i, data) |
|
120 print "I: Writing RT_ICON resource with %d bytes" % len (data) |
|
121 i = i + 1 |
|
122 win32api.EndUpdateResource (hdst, 0) |
|
123 |
|
124 def CopyIcons (dstpath, srcpath): |
|
125 import os.path, string |
|
126 index = None |
|
127 try: |
|
128 srcpath, index = map (string.strip, string.split (srcpath, ',')) |
|
129 index = int (index) |
|
130 except: |
|
131 pass |
|
132 print "I: PATH, INDEX", srcpath, index |
|
133 srcext = os.path.splitext (srcpath)[1] |
|
134 if string.lower (srcext) == '.ico': |
|
135 return CopyIcons_FromIco (dstpath, srcpath) |
|
136 if index is not None: |
|
137 print "I: Updating icons from", srcpath, ", %d to" % index, dstpath |
|
138 else: |
|
139 print "I: Updating icons from", srcpath, "to", dstpath |
|
140 import win32api #, win32con |
|
141 hdst = win32api.BeginUpdateResource (dstpath, 0) |
|
142 hsrc = win32api.LoadLibraryEx (srcpath, 0, LOAD_LIBRARY_AS_DATAFILE) |
|
143 if index is None: |
|
144 grpname = win32api.EnumResourceNames (hsrc, RT_GROUP_ICON)[0] |
|
145 elif index >= 0: |
|
146 grpname = win32api.EnumResourceNames (hsrc, RT_GROUP_ICON)[index] |
|
147 else: |
|
148 grpname = -index |
|
149 data = win32api.LoadResource (hsrc, RT_GROUP_ICON, grpname) |
|
150 win32api.UpdateResource (hdst, RT_GROUP_ICON, grpname, data) |
|
151 for iconname in win32api.EnumResourceNames (hsrc, RT_ICON): |
|
152 data = win32api.LoadResource (hsrc, RT_ICON, iconname) |
|
153 win32api.UpdateResource (hdst, RT_ICON, iconname, data) |
|
154 win32api.FreeLibrary (hsrc) |
|
155 win32api.EndUpdateResource (hdst, 0) |
|
156 |