blob: 93e2283a2305ec38ddf052997b9b35c84ea29ef2 [file] [log] [blame]
#! /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()