272 lines
6.1 KiB
Python
272 lines
6.1 KiB
Python
#! /bin/env python
|
|
""" Dump data about a Metrowerks archive file.
|
|
|
|
$Id$
|
|
|
|
Based on reverse-engineering the library file format.
|
|
|
|
Copyright (C) 1997 Chris Herborth (chrish@qnx.com)
|
|
"""
|
|
|
|
# ----------------------------------------------------------------------
|
|
# Standard modules
|
|
import sys
|
|
import getopt
|
|
import string
|
|
import time
|
|
|
|
# ----------------------------------------------------------------------
|
|
def usage():
|
|
""" Display a usage message and exit.
|
|
"""
|
|
print "dumpar [-v] library1 [library2 ... libraryn]"
|
|
print
|
|
print "Attempt to display some useful information about the contents"
|
|
print "of the given Metrowerks library file(s)."
|
|
print
|
|
print "-v Be verbose (displays offsets along with the data)"
|
|
raise SystemExit
|
|
|
|
# ----------------------------------------------------------------------
|
|
def mk_long( str ):
|
|
""" convert a 4-byte string into a number
|
|
|
|
Assumes big-endian!
|
|
"""
|
|
if len( str ) < 4:
|
|
raise ValueError, "str must be 4 bytes long"
|
|
|
|
num = ord( str[3] )
|
|
num = num + ord( str[2] ) * 0x100
|
|
num = num + ord( str[1] ) * 0x10000
|
|
num = num + ord( str[0] ) * 0x1000000
|
|
|
|
return num
|
|
|
|
# ----------------------------------------------------------------------
|
|
def str2hex( str ):
|
|
""" convert a string into a string of hex numbers
|
|
"""
|
|
ret = []
|
|
for c in str:
|
|
h = hex( ord( c ) )
|
|
ret.append( string.zfill( "%s" % ( h[2:] ), 2 ) )
|
|
|
|
return string.join( ret )
|
|
|
|
# ----------------------------------------------------------------------
|
|
def print_offset( offset ):
|
|
""" print the offset nicely
|
|
"""
|
|
|
|
# Turn the offset into a hex number and strip off the leading "0x".
|
|
val = "%s" % ( hex( offset ) )
|
|
val = val[2:]
|
|
|
|
out = "0x" + string.zfill( val, 8 )
|
|
|
|
print out,
|
|
|
|
# ----------------------------------------------------------------------
|
|
def get_string( data ):
|
|
""" dig a C string out of a data stream
|
|
|
|
returns the string
|
|
"""
|
|
len = 0
|
|
while data[len] != '\0':
|
|
len = len + 1
|
|
|
|
return data[:len]
|
|
|
|
# ----------------------------------------------------------------------
|
|
def dump_lib( file, verbose ):
|
|
""" dump information about a Metrowerks library file
|
|
"""
|
|
offset = 0
|
|
|
|
print "Dumping library:", file
|
|
|
|
# Attempt to read the data.
|
|
try:
|
|
data = open( file ).read()
|
|
except IOError, retval:
|
|
print "*** Unable to open file %s: %s" % ( file, retval[1] )
|
|
return
|
|
|
|
# Check the magic number.
|
|
if verbose:
|
|
print_offset( offset )
|
|
print "Magic:",
|
|
magic = data[offset:offset + 8]
|
|
print "'%s'" % ( magic )
|
|
if magic != "MWOBPPC ":
|
|
print "*** Invalid magic number!"
|
|
return
|
|
|
|
offset = offset + 8
|
|
|
|
# File flags
|
|
if verbose:
|
|
print_offset( offset )
|
|
print "file flags:",
|
|
print mk_long( data[offset:offset + 4] )
|
|
offset = offset + 4
|
|
|
|
if verbose:
|
|
print_offset( offset )
|
|
print "file version:",
|
|
print mk_long( data[offset:offset + 4] )
|
|
offset = offset + 4
|
|
|
|
# code size
|
|
if verbose:
|
|
print_offset( offset )
|
|
print "code size:", mk_long( data[offset:offset + 4] )
|
|
offset = offset + 4
|
|
|
|
# data size
|
|
if verbose:
|
|
print_offset( offset )
|
|
print "data size:", mk_long( data[offset:offset + 4] )
|
|
offset = offset + 4
|
|
|
|
# number of objects
|
|
if verbose:
|
|
print_offset( offset )
|
|
print "number of objects:",
|
|
num_objs = mk_long( data[offset:offset + 4] )
|
|
print num_objs
|
|
|
|
offset = offset + 4
|
|
|
|
print
|
|
|
|
# Now loop through the objects.
|
|
obj_sizes = [ 0, ] * num_objs
|
|
obj_data_offsets = [ 0, ] * num_objs
|
|
|
|
for obj in range( num_objs ):
|
|
# Magic?
|
|
if verbose:
|
|
print_offset( offset )
|
|
print "modification time:",
|
|
modtime = mk_long( data[offset:offset + 4] )
|
|
print "[%s]" % ( ( time.localtime( modtime ), ) )
|
|
|
|
offset = offset + 4
|
|
|
|
# Offsets?
|
|
if verbose:
|
|
print_offset( offset )
|
|
print "file name offset 1:",
|
|
file_offset1 = mk_long( data[offset:offset + 4] )
|
|
unknown = "%s" % ( hex( file_offset1 ) )
|
|
print "%s (%s)" % ( unknown, str2hex( data[offset:offset + 4] ) )
|
|
|
|
offset = offset + 4
|
|
|
|
if verbose:
|
|
print_offset( offset )
|
|
print "file name offset 2:",
|
|
file_offset2 = mk_long( data[offset:offset + 4] )
|
|
unknown = "%s" % ( hex( file_offset2 ) )
|
|
print "%s (%s)" % ( unknown, str2hex( data[offset:offset + 4] ) )
|
|
|
|
offset = offset + 4
|
|
|
|
# Extra -1 for NUL character.
|
|
print " >>>> File name should be %s characters." % \
|
|
( file_offset2 - file_offset1 - 1)
|
|
|
|
if verbose:
|
|
print_offset( offset )
|
|
print "object data offset:",
|
|
file_data_offset = mk_long( data[offset:offset + 4] )
|
|
unknown = "%s" % ( hex( file_data_offset ) )
|
|
print "%s (%s)" % ( unknown, str2hex( data[offset:offset + 4] ) )
|
|
|
|
obj_data_offsets[obj] = file_data_offset
|
|
|
|
offset = offset + 4
|
|
|
|
# object size
|
|
if verbose:
|
|
print_offset( offset )
|
|
print "object size:",
|
|
obj_sizes[obj] = mk_long( data[offset:offset + 4] )
|
|
print "%s bytes" % ( obj_sizes[obj] )
|
|
|
|
offset = offset + 4
|
|
|
|
print
|
|
|
|
# Now loop through the object names.
|
|
for obj in range( num_objs ):
|
|
# First name
|
|
if verbose:
|
|
print_offset( offset )
|
|
print "object",
|
|
print obj,
|
|
print "name 1:",
|
|
name1 = get_string( data[offset:] )
|
|
print "[%s] %s chars" % ( name1, len( name1 ) )
|
|
|
|
offset = offset + len( name1 ) + 1
|
|
|
|
# Second name
|
|
if verbose:
|
|
print_offset( offset )
|
|
print "object",
|
|
print obj,
|
|
print "name 2:",
|
|
name2 = get_string( data[offset:] )
|
|
print "[%s] %s chars" % ( name2, len( name1 ) )
|
|
|
|
offset = offset + len( name2 ) + 1
|
|
|
|
# See if we've got a magic cookie in the object data
|
|
if verbose:
|
|
print_offset( obj_data_offsets[obj] )
|
|
|
|
cookie = data[obj_data_offsets[obj]:obj_data_offsets[obj] + 8]
|
|
print "object",
|
|
print obj,
|
|
print "cookie: '%s'" % ( cookie )
|
|
|
|
print
|
|
|
|
# Now loop through the data and check for magic numbers there.
|
|
return
|
|
|
|
# ----------------------------------------------------------------------
|
|
def main():
|
|
""" mainline
|
|
"""
|
|
|
|
# Set up some defaults
|
|
be_verbose = 0
|
|
|
|
# First, check the command-line arguments
|
|
try:
|
|
opt, args = getopt.getopt( sys.argv[1:], "vh?" )
|
|
except getopt.error:
|
|
print "*** Error parsing command-line options!"
|
|
usage()
|
|
|
|
for o in opt:
|
|
if o[0] == "-h" or o[0] == "-?":
|
|
usage()
|
|
elif o[0] == "-v":
|
|
be_verbose = 1
|
|
else:
|
|
print "*** Unknown command-line option!"
|
|
usage()
|
|
|
|
# Now we can attempt to dump info about the arguments.
|
|
for lib in args:
|
|
dump_lib( lib, be_verbose )
|
|
|
|
if __name__ == "__main__":
|
|
main()
|