Commits

Christoph Schindler committed 1511142

Add simple hexdump tool.

Comments (0)

Files changed (1)

contrib/dump_plist

+#!/usr/bin/env python
+"""Make an annotated hexdump of a binary property list file."""
+
+import argparse
+import math
+import string
+from sys import argv, stdin, stderr
+from os.path import basename
+from struct import unpack
+from itertools import izip_longest
+
+def log(msg):
+    stderr.write("%s: %s\n" % (basename(argv[0]), msg))
+
+def dump(pos, data, fmt, comment):
+    xdata = ('%02x' % ord(c) for c in data)
+    xdata = izip_longest(xdata, xdata, fillvalue='  ')
+    xdata = ' '.join(''.join(t) for t in xdata)
+
+    cdata, = unpack(fmt, data)
+
+    visible = string.printable[:-5]
+    if isinstance(cdata, str):
+        cdata = ''.join(c if c in visible else '.' for c in cdata)
+
+    print("%08x: %- 20s %- 8s  # %s" % (pos, xdata[:20], str(cdata)[:8], comment))
+    for i in range(1, int(math.ceil(len(data)/8.0))):
+        print("%08x: %- 20s %- 8s" % (pos+i*8, xdata[i*20:(i+1)*20], str(cdata)[i*8:(i+1)*8]))
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument('infile', nargs='?', default='-')
+
+    args = parser.parse_args()
+
+    try:
+        if args.infile == '-':
+            plist = stdin.read()
+        else:
+            fp = open(args.infile, 'rb')
+            plist = fp.read()
+            fp.close()
+    except IOError as e:
+        log("%s: %s" % (args.infile, e.strerror))
+        exit(2)
+
+    # check the magic
+    magic_number, version = plist[:6], plist[6:8]
+
+    if magic_number != 'bplist':
+        log("Magic number not found!")
+        exit(3)
+
+    print "HEADER"
+    print "======"
+    dump(0, magic_number, '6s', "magic number")
+    dump(6, version, '2s', "plist version")
+
+    offset_table_offset, = unpack('>Q', plist[-8:])
+    payloadlen = offset_table_offset - 8
+    objrefsize, = unpack('B', plist[-25:-24])
+
+    print
+    print "OBJECT TABLE"
+    print "============"
+
+    dump(8, plist[8:offset_table_offset], '%is' % (payloadlen), 'objects')
+
+    print
+    print "OFFSET TABLE"
+    print "============"
+
+    offset = offset_table_offset
+    offsettable = iter(plist[offset:-32])
+    it = izip_longest(*([offsettable] * objrefsize))
+    for t in it:
+        dump(offset, ''.join(t), '%is' % objrefsize, 'object refs')
+        offset += objrefsize
+
+    print
+    print "TRAILER"
+    print "======="
+
+    end = len(plist)
+    dump(end - 32, plist[-32:-26], '6s', 'padding')
+    dump(end - 26, plist[-26:-25], 'B', 'offset size')
+    dump(end - 25, plist[-25:-24], 'B', 'object reference size')
+    dump(end - 24, plist[-24:-16], '>Q', 'number of objects')
+    dump(end - 16, plist[-16:-8], '>Q', 'position of root object')
+    dump(end - 8, plist[-8:], '>Q', 'offset table offset')
+