|
1 #!/usr/bin/env python |
|
2 # -*- coding: utf-8 -*- |
|
3 |
|
4 ############################################################################## |
|
5 # cmd_signsis.py - Ensymble command line tool, altere32 command |
|
6 # Copyright 2006, 2007, 2008 Jussi Ylänen |
|
7 # |
|
8 # This file is part of Ensymble developer utilities for Symbian OS(TM). |
|
9 # |
|
10 # Ensymble is free software; you can redistribute it and/or modify |
|
11 # it under the terms of the GNU General Public License as published by |
|
12 # the Free Software Foundation; either version 2 of the License, or |
|
13 # (at your option) any later version. |
|
14 # |
|
15 # Ensymble is distributed in the hope that it will be useful, |
|
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
18 # GNU General Public License for more details. |
|
19 # |
|
20 # You should have received a copy of the GNU General Public License |
|
21 # along with Ensymble; if not, write to the Free Software |
|
22 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
|
23 ############################################################################## |
|
24 |
|
25 import sys |
|
26 import os |
|
27 import getopt |
|
28 import locale |
|
29 import struct |
|
30 |
|
31 import symbianutil |
|
32 |
|
33 |
|
34 ############################################################################## |
|
35 # Help texts |
|
36 ############################################################################## |
|
37 |
|
38 shorthelp = 'Alter the IDs and capabilities of e32image files (EXEs, DLLs)' |
|
39 longhelp = '''altere32 |
|
40 [--uid=0x01234567] [--secureid=0x01234567] [--vendorid=0x01234567] |
|
41 [--caps=Cap1+Cap2+...] [--heapsize=min,max] [--inplace] |
|
42 [--encoding=terminal,filesystem] [--verbose] |
|
43 <infile> [outfile] |
|
44 |
|
45 Alter the IDs, capabilities and heap sizes of e32image files (Symbian OS |
|
46 EXEs and DLLs). |
|
47 |
|
48 Options: |
|
49 infile - Path of the original e32image file (or many, if --inplace set) |
|
50 outfile - Path of the modified e32image file (not used with --inplace) |
|
51 uid - Symbian OS UID for the e32image |
|
52 secureid - Secure ID for the e32image (should normally be same as UID) |
|
53 vendorid - Vendor ID for the e32image |
|
54 caps - Capability names, separated by "+" |
|
55 heapsize - Heap size, minimum and/or maximum (not altered by default) |
|
56 inplace - Allow more than one input file, modify input files in-place |
|
57 encoding - Local character encodings for terminal and filesystem |
|
58 verbose - Print extra statistics |
|
59 |
|
60 When modifying the UID, the secure ID should be modified accordingly. |
|
61 Modifying UIDs of application EXEs is generally not possible, because |
|
62 applications usually include the UID in program code as well. |
|
63 ''' |
|
64 |
|
65 |
|
66 ############################################################################## |
|
67 # Parameters |
|
68 ############################################################################## |
|
69 |
|
70 MAXE32FILESIZE = 1024 * 1024 * 8 # Eight megabytes |
|
71 |
|
72 |
|
73 ############################################################################## |
|
74 # Global variables |
|
75 ############################################################################## |
|
76 |
|
77 debug = False |
|
78 |
|
79 |
|
80 ############################################################################## |
|
81 # Public module-level functions |
|
82 ############################################################################## |
|
83 |
|
84 def run(pgmname, argv): |
|
85 global debug |
|
86 |
|
87 # Determine system character encodings. |
|
88 try: |
|
89 # getdefaultlocale() may sometimes return None. |
|
90 # Fall back to ASCII encoding in that case. |
|
91 terminalenc = locale.getdefaultlocale()[1] + "" |
|
92 except TypeError: |
|
93 # Invalid locale, fall back to ASCII terminal encoding. |
|
94 terminalenc = "ascii" |
|
95 |
|
96 try: |
|
97 # sys.getfilesystemencoding() was introduced in Python v2.3 and |
|
98 # it can sometimes return None. Fall back to ASCII if something |
|
99 # goes wrong. |
|
100 filesystemenc = sys.getfilesystemencoding() + "" |
|
101 except (AttributeError, TypeError): |
|
102 filesystemenc = "ascii" |
|
103 |
|
104 try: |
|
105 gopt = getopt.gnu_getopt |
|
106 except: |
|
107 # Python <v2.3, GNU-style parameter ordering not supported. |
|
108 gopt = getopt.getopt |
|
109 |
|
110 # Parse command line arguments. |
|
111 short_opts = "u:s:r:b:H:ie:vh" |
|
112 long_opts = [ |
|
113 "uid=", "secureid=", "vendorid=", "caps=", "heapsize=", |
|
114 "inplace", "encoding=", "verbose", "debug", "help" |
|
115 ] |
|
116 args = gopt(argv, short_opts, long_opts) |
|
117 |
|
118 opts = dict(args[0]) |
|
119 pargs = args[1] |
|
120 |
|
121 if len(pargs) == 0: |
|
122 raise ValueError("no input e32image file name given") |
|
123 |
|
124 # Override character encoding of command line and filesystem. |
|
125 encs = opts.get("--encoding", opts.get("-e", "%s,%s" % (terminalenc, |
|
126 filesystemenc))) |
|
127 try: |
|
128 terminalenc, filesystemenc = encs.split(",") |
|
129 except (ValueError, TypeError): |
|
130 raise ValueError("invalid encoding string '%s'" % encs) |
|
131 |
|
132 # Get UID3. |
|
133 uid3 = opts.get("--uid", opts.get("-u", None)) |
|
134 if uid3 != None: |
|
135 uid3 = parseuid(pgmname, uid3) |
|
136 |
|
137 # Get secure ID. |
|
138 secureid = opts.get("--secureid", opts.get("-s", None)) |
|
139 if secureid != None: |
|
140 secureid = parseuid(pgmname, secureid) |
|
141 |
|
142 # Get vendor ID. |
|
143 vendorid = opts.get("--vendorid", opts.get("-r", None)) |
|
144 if vendorid != None: |
|
145 vendorid = parseuid(pgmname, vendorid) |
|
146 |
|
147 # Get capabilities and normalize the names. |
|
148 caps = opts.get("--caps", opts.get("-b", None)) |
|
149 if caps != None: |
|
150 capmask = symbianutil.capstringtomask(caps) |
|
151 caps = symbianutil.capmasktostring(capmask, True) |
|
152 else: |
|
153 capmask = None |
|
154 |
|
155 # Get heap sizes. |
|
156 heapsize = opts.get("--heapsize", opts.get("-H", None)) |
|
157 if heapsize != None: |
|
158 try: |
|
159 heapsize = heapsize.split(",", 1) |
|
160 heapsizemin = symbianutil.parseintmagnitude(heapsize[0]) |
|
161 if len(heapsize) == 1: |
|
162 # Only one size given, use it as both. |
|
163 heapsizemax = heapsizemin |
|
164 else: |
|
165 heapsizemax = symbianutil.parseintmagnitude(heapsize[1]) |
|
166 except (ValueError, TypeError, IndexError): |
|
167 raise ValueError("%s: invalid heap size, one or two values expected" |
|
168 % ",".join(heapsize)) |
|
169 |
|
170 # Warn if the minimum heap size is larger than the maximum heap size. |
|
171 # Resulting e32image file will probably prevent any SIS from installing. |
|
172 if heapsizemin > heapsizemax: |
|
173 print ("%s: warning: minimum heap size larger than " |
|
174 "maximum heap size" % pgmname) |
|
175 else: |
|
176 heapsizemin = None |
|
177 heapsizemax = None |
|
178 |
|
179 # Determine parameter format. Modifying files in-place or not. |
|
180 inplace = False |
|
181 if "--inplace" in opts.keys() or "-i" in opts.keys(): |
|
182 inplace = True |
|
183 |
|
184 # Determine e32image input / output file names. |
|
185 files = [name.decode(terminalenc).encode(filesystemenc) for name in pargs] |
|
186 if not inplace: |
|
187 if len(files) == 2: |
|
188 if os.path.isdir(files[1]): |
|
189 # Output to directory, use input file name. |
|
190 files[1] = os.path.join(files[1], os.path.basename(files[0])) |
|
191 else: |
|
192 raise ValueError("wrong number of arguments") |
|
193 |
|
194 # Determine verbosity. |
|
195 verbose = False |
|
196 if "--verbose" in opts.keys() or "-v" in opts.keys(): |
|
197 verbose = True |
|
198 |
|
199 # Determine if debug output is requested. |
|
200 if "--debug" in opts.keys(): |
|
201 debug = True |
|
202 |
|
203 # Ingredients for successful e32image file alteration: |
|
204 # |
|
205 # terminalenc Terminal character encoding (autodetected) |
|
206 # filesystemenc File system name encoding (autodetected) |
|
207 # files File names of e32image files, filesystemenc encoded |
|
208 # uid3 Application UID3, long integer or None |
|
209 # secureid Secure ID, long integer or None |
|
210 # vendorid Vendor ID, long integer or None |
|
211 # caps, capmask Capability names and bitmask or None |
|
212 # heapsizemin Heap that must be available for the app. to start or None |
|
213 # heapsizemax Maximum amount of heap the app. can allocate or None |
|
214 # inplace Multiple input files or single input / output pair |
|
215 # verbose Boolean indicating verbose terminal output |
|
216 |
|
217 if verbose: |
|
218 print |
|
219 if not inplace: |
|
220 print "Input e32image file %s" % ( |
|
221 files[0].decode(filesystemenc).encode(terminalenc)) |
|
222 print "Output e32image file %s" % ( |
|
223 files[1].decode(filesystemenc).encode(terminalenc)) |
|
224 else: |
|
225 print "Input e32image file(s) %s" % " ".join( |
|
226 [f.decode(filesystemenc).encode(terminalenc) for f in files]) |
|
227 if uid3 != None: |
|
228 print "UID 0x%08x" % uid3 |
|
229 else: |
|
230 print "UID <not set>" |
|
231 if secureid != None: |
|
232 print "Secure ID 0x%08x" % secureid |
|
233 else: |
|
234 print "Secure ID <not set>" |
|
235 if vendorid != None: |
|
236 print "Vendor ID 0x%08x" % vendorid |
|
237 else: |
|
238 print "Vendor ID <not set>" |
|
239 if caps != None: |
|
240 print "Capabilities 0x%x (%s)" % (capmask, caps) |
|
241 else: |
|
242 print "Capabilities <not set>" |
|
243 if heapsizemin != None: |
|
244 print "Heap size in bytes %d, %d" % (heapsizemin, heapsizemax) |
|
245 else: |
|
246 print "Heap size in bytes <not set>" |
|
247 print |
|
248 |
|
249 if ((uid3, secureid, vendorid, caps, heapsizemin) == |
|
250 (None, None, None, None, None)): |
|
251 print "%s: no options set, doing nothing" % pgmname |
|
252 return |
|
253 |
|
254 for infile in files: |
|
255 # Read input e32image file. |
|
256 f = file(infile, "rb") |
|
257 instring = f.read(MAXE32FILESIZE + 1) |
|
258 f.close() |
|
259 |
|
260 if len(instring) > MAXE32FILESIZE: |
|
261 raise ValueError("input e32image file too large") |
|
262 |
|
263 # Modify the e32image header. |
|
264 try: |
|
265 outstring = symbianutil.e32imagecrc(instring, uid3, |
|
266 secureid, vendorid, heapsizemin, |
|
267 heapsizemax, capmask) |
|
268 except ValueError: |
|
269 raise ValueError("%s: not a valid e32image file" % infile) |
|
270 |
|
271 if not inplace: |
|
272 outfile = files[1] |
|
273 else: |
|
274 outfile = infile |
|
275 |
|
276 # Write output e32image file. |
|
277 f = file(outfile, "wb") |
|
278 f.write(outstring) |
|
279 f.close() |
|
280 |
|
281 if not inplace: |
|
282 # While --inplace is not in effect, files[1] is the output |
|
283 # file name, so must stop after one iteration. |
|
284 break |
|
285 |
|
286 |
|
287 ############################################################################## |
|
288 # Module-level functions which are normally only used by this module |
|
289 ############################################################################## |
|
290 |
|
291 def parseuid(pgmname, uid): |
|
292 if uid.lower().startswith("0x"): |
|
293 # Prefer hex UIDs with leading "0x". |
|
294 uid = long(uid, 16) |
|
295 else: |
|
296 try: |
|
297 if len(uid) == 8: |
|
298 # Assuming hex UID even without leading "0x". |
|
299 print ('%s: warning: assuming hex UID even ' |
|
300 'without leading "0x"' % pgmname) |
|
301 uid = long(uid, 16) |
|
302 else: |
|
303 # Decimal UID. |
|
304 uid = long(uid) |
|
305 print ('%s: warning: decimal UID converted to 0x%08x' % |
|
306 (pgmname, uid)) |
|
307 except ValueError: |
|
308 raise ValueError("invalid UID string '%s'" % uid) |
|
309 return uid |