blob: 93e2283a2305ec38ddf052997b9b35c84ea29ef2 [file] [log] [blame]
Guido van Rossumd8eb2111998-08-04 17:57:28 +00001#! /bin/env python
2""" Dump data about a Metrowerks archive file.
3
4$Id$
5
6Based on reverse-engineering the library file format.
7
8Copyright (C) 1997 Chris Herborth (chrish@qnx.com)
9"""
10
11# ----------------------------------------------------------------------
12# Standard modules
13import sys
14import getopt
15import string
16import time
17
18# ----------------------------------------------------------------------
19def usage():
20 """ Display a usage message and exit.
21 """
22 print "dumpar [-v] library1 [library2 ... libraryn]"
23 print
24 print "Attempt to display some useful information about the contents"
25 print "of the given Metrowerks library file(s)."
26 print
27 print "-v Be verbose (displays offsets along with the data)"
28 raise SystemExit
29
30# ----------------------------------------------------------------------
31def mk_long( str ):
32 """ convert a 4-byte string into a number
33
34 Assumes big-endian!
35 """
36 if len( str ) < 4:
37 raise ValueError, "str must be 4 bytes long"
38
39 num = ord( str[3] )
40 num = num + ord( str[2] ) * 0x100
41 num = num + ord( str[1] ) * 0x10000
42 num = num + ord( str[0] ) * 0x1000000
43
44 return num
45
46# ----------------------------------------------------------------------
47def str2hex( str ):
48 """ convert a string into a string of hex numbers
49 """
50 ret = []
51 for c in str:
52 h = hex( ord( c ) )
53 ret.append( string.zfill( "%s" % ( h[2:] ), 2 ) )
54
55 return string.join( ret )
56
57# ----------------------------------------------------------------------
58def print_offset( offset ):
59 """ print the offset nicely
60 """
61
62 # Turn the offset into a hex number and strip off the leading "0x".
63 val = "%s" % ( hex( offset ) )
64 val = val[2:]
65
66 out = "0x" + string.zfill( val, 8 )
67
68 print out,
69
70# ----------------------------------------------------------------------
71def get_string( data ):
72 """ dig a C string out of a data stream
73
74 returns the string
75 """
76 len = 0
77 while data[len] != '\0':
78 len = len + 1
79
80 return data[:len]
81
82# ----------------------------------------------------------------------
83def dump_lib( file, verbose ):
84 """ dump information about a Metrowerks library file
85 """
86 offset = 0
87
88 print "Dumping library:", file
89
90 # Attempt to read the data.
91 try:
92 data = open( file ).read()
93 except IOError, retval:
94 print "*** Unable to open file %s: %s" % ( file, retval[1] )
95 return
96
97 # Check the magic number.
98 if verbose:
99 print_offset( offset )
100 print "Magic:",
101 magic = data[offset:offset + 8]
102 print "'%s'" % ( magic )
103 if magic != "MWOBPPC ":
104 print "*** Invalid magic number!"
105 return
106
107 offset = offset + 8
108
109 # File flags
110 if verbose:
111 print_offset( offset )
112 print "file flags:",
113 print mk_long( data[offset:offset + 4] )
114 offset = offset + 4
115
116 if verbose:
117 print_offset( offset )
118 print "file version:",
119 print mk_long( data[offset:offset + 4] )
120 offset = offset + 4
121
122 # code size
123 if verbose:
124 print_offset( offset )
125 print "code size:", mk_long( data[offset:offset + 4] )
126 offset = offset + 4
127
128 # data size
129 if verbose:
130 print_offset( offset )
131 print "data size:", mk_long( data[offset:offset + 4] )
132 offset = offset + 4
133
134 # number of objects
135 if verbose:
136 print_offset( offset )
137 print "number of objects:",
138 num_objs = mk_long( data[offset:offset + 4] )
139 print num_objs
140
141 offset = offset + 4
142
143 print
144
145 # Now loop through the objects.
146 obj_sizes = [ 0, ] * num_objs
147 obj_data_offsets = [ 0, ] * num_objs
148
149 for obj in range( num_objs ):
150 # Magic?
151 if verbose:
152 print_offset( offset )
153 print "modification time:",
154 modtime = mk_long( data[offset:offset + 4] )
155 print "[%s]" % ( ( time.localtime( modtime ), ) )
156
157 offset = offset + 4
158
159 # Offsets?
160 if verbose:
161 print_offset( offset )
162 print "file name offset 1:",
163 file_offset1 = mk_long( data[offset:offset + 4] )
164 unknown = "%s" % ( hex( file_offset1 ) )
165 print "%s (%s)" % ( unknown, str2hex( data[offset:offset + 4] ) )
166
167 offset = offset + 4
168
169 if verbose:
170 print_offset( offset )
171 print "file name offset 2:",
172 file_offset2 = mk_long( data[offset:offset + 4] )
173 unknown = "%s" % ( hex( file_offset2 ) )
174 print "%s (%s)" % ( unknown, str2hex( data[offset:offset + 4] ) )
175
176 offset = offset + 4
177
178 # Extra -1 for NUL character.
179 print " >>>> File name should be %s characters." % \
180 ( file_offset2 - file_offset1 - 1)
181
182 if verbose:
183 print_offset( offset )
184 print "object data offset:",
185 file_data_offset = mk_long( data[offset:offset + 4] )
186 unknown = "%s" % ( hex( file_data_offset ) )
187 print "%s (%s)" % ( unknown, str2hex( data[offset:offset + 4] ) )
188
189 obj_data_offsets[obj] = file_data_offset
190
191 offset = offset + 4
192
193 # object size
194 if verbose:
195 print_offset( offset )
196 print "object size:",
197 obj_sizes[obj] = mk_long( data[offset:offset + 4] )
198 print "%s bytes" % ( obj_sizes[obj] )
199
200 offset = offset + 4
201
202 print
203
204 # Now loop through the object names.
205 for obj in range( num_objs ):
206 # First name
207 if verbose:
208 print_offset( offset )
209 print "object",
210 print obj,
211 print "name 1:",
212 name1 = get_string( data[offset:] )
213 print "[%s] %s chars" % ( name1, len( name1 ) )
214
215 offset = offset + len( name1 ) + 1
216
217 # Second name
218 if verbose:
219 print_offset( offset )
220 print "object",
221 print obj,
222 print "name 2:",
223 name2 = get_string( data[offset:] )
224 print "[%s] %s chars" % ( name2, len( name1 ) )
225
226 offset = offset + len( name2 ) + 1
227
228 # See if we've got a magic cookie in the object data
229 if verbose:
230 print_offset( obj_data_offsets[obj] )
231
232 cookie = data[obj_data_offsets[obj]:obj_data_offsets[obj] + 8]
233 print "object",
234 print obj,
235 print "cookie: '%s'" % ( cookie )
236
237 print
238
239 # Now loop through the data and check for magic numbers there.
240 return
241
242# ----------------------------------------------------------------------
243def main():
244 """ mainline
245 """
246
247 # Set up some defaults
248 be_verbose = 0
249
250 # First, check the command-line arguments
251 try:
252 opt, args = getopt.getopt( sys.argv[1:], "vh?" )
253 except getopt.error:
254 print "*** Error parsing command-line options!"
255 usage()
256
257 for o in opt:
258 if o[0] == "-h" or o[0] == "-?":
259 usage()
260 elif o[0] == "-v":
261 be_verbose = 1
262 else:
263 print "*** Unknown command-line option!"
264 usage()
265
266 # Now we can attempt to dump info about the arguments.
267 for lib in args:
268 dump_lib( lib, be_verbose )
269
270if __name__ == "__main__":
271 main()