16a23d212SGreg Clayton#!/usr/bin/env python 26a23d212SGreg Clayton 36a23d212SGreg Claytonimport string 46a23d212SGreg Claytonimport struct 56a23d212SGreg Claytonimport sys 66a23d212SGreg Clayton 7b9c1b51eSKate Stone 86a23d212SGreg Claytonclass FileExtract: 96a23d212SGreg Clayton '''Decode binary data from a file''' 106a23d212SGreg Clayton 116a23d212SGreg Clayton def __init__(self, f, b='='): 126a23d212SGreg Clayton '''Initialize with an open binary file and optional byte order''' 136a23d212SGreg Clayton 146a23d212SGreg Clayton self.file = f 156a23d212SGreg Clayton self.byte_order = b 166a23d212SGreg Clayton self.offsets = list() 176a23d212SGreg Clayton 186a23d212SGreg Clayton def set_byte_order(self, b): 196a23d212SGreg Clayton '''Set the byte order, valid values are "big", "little", "swap", "native", "<", ">", "@", "="''' 206a23d212SGreg Clayton if b == 'big': 216a23d212SGreg Clayton self.byte_order = '>' 226a23d212SGreg Clayton elif b == 'little': 236a23d212SGreg Clayton self.byte_order = '<' 246a23d212SGreg Clayton elif b == 'swap': 256a23d212SGreg Clayton # swap what ever the current byte order is 266a23d212SGreg Clayton self.byte_order = swap_unpack_char() 276a23d212SGreg Clayton elif b == 'native': 286a23d212SGreg Clayton self.byte_order = '=' 296a23d212SGreg Clayton elif b == '<' or b == '>' or b == '@' or b == '=': 306a23d212SGreg Clayton self.byte_order = b 316a23d212SGreg Clayton else: 32*525cd59fSSerge Guelton print("error: invalid byte order specified: '%s'" % b) 336a23d212SGreg Clayton 346a23d212SGreg Clayton def is_in_memory(self): 356a23d212SGreg Clayton return False 366a23d212SGreg Clayton 376a23d212SGreg Clayton def seek(self, offset, whence=0): 386a23d212SGreg Clayton if self.file: 396a23d212SGreg Clayton return self.file.seek(offset, whence) 406a23d212SGreg Clayton raise ValueError 416a23d212SGreg Clayton 426a23d212SGreg Clayton def tell(self): 436a23d212SGreg Clayton if self.file: 446a23d212SGreg Clayton return self.file.tell() 456a23d212SGreg Clayton raise ValueError 466a23d212SGreg Clayton 476a23d212SGreg Clayton def read_size(self, byte_size): 486a23d212SGreg Clayton s = self.file.read(byte_size) 496a23d212SGreg Clayton if len(s) != byte_size: 506a23d212SGreg Clayton return None 516a23d212SGreg Clayton return s 526a23d212SGreg Clayton 536a23d212SGreg Clayton def push_offset_and_seek(self, offset): 546a23d212SGreg Clayton '''Push the current file offset and seek to "offset"''' 556a23d212SGreg Clayton self.offsets.append(self.file.tell()) 566a23d212SGreg Clayton self.file.seek(offset, 0) 576a23d212SGreg Clayton 586a23d212SGreg Clayton def pop_offset_and_seek(self): 596a23d212SGreg Clayton '''Pop a previously pushed file offset, or do nothing if there were no previously pushed offsets''' 606a23d212SGreg Clayton if len(self.offsets) > 0: 616a23d212SGreg Clayton self.file.seek(self.offsets.pop()) 626a23d212SGreg Clayton 636a23d212SGreg Clayton def get_sint8(self, fail_value=0): 646a23d212SGreg Clayton '''Extract a single int8_t from the binary file at the current file position, returns a single integer''' 656a23d212SGreg Clayton s = self.read_size(1) 666a23d212SGreg Clayton if s: 676a23d212SGreg Clayton v, = struct.unpack(self.byte_order + 'b', s) 686a23d212SGreg Clayton return v 696a23d212SGreg Clayton else: 706a23d212SGreg Clayton return fail_value 716a23d212SGreg Clayton 726a23d212SGreg Clayton def get_uint8(self, fail_value=0): 736a23d212SGreg Clayton '''Extract a single uint8_t from the binary file at the current file position, returns a single integer''' 746a23d212SGreg Clayton s = self.read_size(1) 756a23d212SGreg Clayton if s: 766a23d212SGreg Clayton v, = struct.unpack(self.byte_order + 'B', s) 776a23d212SGreg Clayton return v 786a23d212SGreg Clayton else: 796a23d212SGreg Clayton return fail_value 806a23d212SGreg Clayton 816a23d212SGreg Clayton def get_sint16(self, fail_value=0): 826a23d212SGreg Clayton '''Extract a single int16_t from the binary file at the current file position, returns a single integer''' 836a23d212SGreg Clayton s = self.read_size(2) 846a23d212SGreg Clayton if s: 856a23d212SGreg Clayton v, = struct.unpack(self.byte_order + 'h', s) 866a23d212SGreg Clayton return v 876a23d212SGreg Clayton else: 886a23d212SGreg Clayton return fail_value 896a23d212SGreg Clayton 906a23d212SGreg Clayton def get_uint16(self, fail_value=0): 916a23d212SGreg Clayton '''Extract a single uint16_t from the binary file at the current file position, returns a single integer''' 926a23d212SGreg Clayton s = self.read_size(2) 936a23d212SGreg Clayton if s: 946a23d212SGreg Clayton v, = struct.unpack(self.byte_order + 'H', s) 956a23d212SGreg Clayton return v 966a23d212SGreg Clayton else: 976a23d212SGreg Clayton return fail_value 986a23d212SGreg Clayton 996a23d212SGreg Clayton def get_sint32(self, fail_value=0): 1006a23d212SGreg Clayton '''Extract a single int32_t from the binary file at the current file position, returns a single integer''' 1016a23d212SGreg Clayton s = self.read_size(4) 1026a23d212SGreg Clayton if s: 1036a23d212SGreg Clayton v, = struct.unpack(self.byte_order + 'i', s) 1046a23d212SGreg Clayton return v 1056a23d212SGreg Clayton else: 1066a23d212SGreg Clayton return fail_value 1076a23d212SGreg Clayton 1086a23d212SGreg Clayton def get_uint32(self, fail_value=0): 1096a23d212SGreg Clayton '''Extract a single uint32_t from the binary file at the current file position, returns a single integer''' 1106a23d212SGreg Clayton s = self.read_size(4) 1116a23d212SGreg Clayton if s: 1126a23d212SGreg Clayton v, = struct.unpack(self.byte_order + 'I', s) 1136a23d212SGreg Clayton return v 1146a23d212SGreg Clayton else: 1156a23d212SGreg Clayton return fail_value 1166a23d212SGreg Clayton 1176a23d212SGreg Clayton def get_sint64(self, fail_value=0): 1186a23d212SGreg Clayton '''Extract a single int64_t from the binary file at the current file position, returns a single integer''' 1196a23d212SGreg Clayton s = self.read_size(8) 1206a23d212SGreg Clayton if s: 1216a23d212SGreg Clayton v, = struct.unpack(self.byte_order + 'q', s) 1226a23d212SGreg Clayton return v 1236a23d212SGreg Clayton else: 1246a23d212SGreg Clayton return fail_value 1256a23d212SGreg Clayton 1266a23d212SGreg Clayton def get_uint64(self, fail_value=0): 1276a23d212SGreg Clayton '''Extract a single uint64_t from the binary file at the current file position, returns a single integer''' 1286a23d212SGreg Clayton s = self.read_size(8) 1296a23d212SGreg Clayton if s: 1306a23d212SGreg Clayton v, = struct.unpack(self.byte_order + 'Q', s) 1316a23d212SGreg Clayton return v 1326a23d212SGreg Clayton else: 1336a23d212SGreg Clayton return fail_value 1346a23d212SGreg Clayton 135b9c1b51eSKate Stone def get_fixed_length_c_string( 136b9c1b51eSKate Stone self, 137b9c1b51eSKate Stone n, 138b9c1b51eSKate Stone fail_value='', 139b9c1b51eSKate Stone isprint_only_with_space_padding=False): 1406a23d212SGreg Clayton '''Extract a single fixed length C string from the binary file at the current file position, returns a single C string''' 1416a23d212SGreg Clayton s = self.read_size(n) 1426a23d212SGreg Clayton if s: 1436a23d212SGreg Clayton cstr, = struct.unpack(self.byte_order + ("%i" % n) + 's', s) 1446a23d212SGreg Clayton # Strip trialing NULLs 1456a23d212SGreg Clayton cstr = string.strip(cstr, "\0") 1466a23d212SGreg Clayton if isprint_only_with_space_padding: 1476a23d212SGreg Clayton for c in cstr: 1486a23d212SGreg Clayton if c in string.printable or ord(c) == 0: 1496a23d212SGreg Clayton continue 1506a23d212SGreg Clayton return fail_value 1516a23d212SGreg Clayton return cstr 1526a23d212SGreg Clayton else: 1536a23d212SGreg Clayton return fail_value 1546a23d212SGreg Clayton 1556a23d212SGreg Clayton def get_c_string(self): 1566a23d212SGreg Clayton '''Extract a single NULL terminated C string from the binary file at the current file position, returns a single C string''' 1576a23d212SGreg Clayton cstr = '' 1586a23d212SGreg Clayton byte = self.get_uint8() 1596a23d212SGreg Clayton while byte != 0: 1606a23d212SGreg Clayton cstr += "%c" % byte 1616a23d212SGreg Clayton byte = self.get_uint8() 1626a23d212SGreg Clayton return cstr 1636a23d212SGreg Clayton 1646a23d212SGreg Clayton def get_n_sint8(self, n, fail_value=0): 1656a23d212SGreg Clayton '''Extract "n" int8_t integers from the binary file at the current file position, returns a list of integers''' 1666a23d212SGreg Clayton s = self.read_size(n) 1676a23d212SGreg Clayton if s: 1686a23d212SGreg Clayton return struct.unpack(self.byte_order + ("%u" % n) + 'b', s) 1696a23d212SGreg Clayton else: 1706a23d212SGreg Clayton return (fail_value,) * n 1716a23d212SGreg Clayton 1726a23d212SGreg Clayton def get_n_uint8(self, n, fail_value=0): 1736a23d212SGreg Clayton '''Extract "n" uint8_t integers from the binary file at the current file position, returns a list of integers''' 1746a23d212SGreg Clayton s = self.read_size(n) 1756a23d212SGreg Clayton if s: 1766a23d212SGreg Clayton return struct.unpack(self.byte_order + ("%u" % n) + 'B', s) 1776a23d212SGreg Clayton else: 1786a23d212SGreg Clayton return (fail_value,) * n 1796a23d212SGreg Clayton 1806a23d212SGreg Clayton def get_n_sint16(self, n, fail_value=0): 1816a23d212SGreg Clayton '''Extract "n" int16_t integers from the binary file at the current file position, returns a list of integers''' 1826a23d212SGreg Clayton s = self.read_size(2 * n) 1836a23d212SGreg Clayton if s: 1846a23d212SGreg Clayton return struct.unpack(self.byte_order + ("%u" % n) + 'h', s) 1856a23d212SGreg Clayton else: 1866a23d212SGreg Clayton return (fail_value,) * n 1876a23d212SGreg Clayton 1886a23d212SGreg Clayton def get_n_uint16(self, n, fail_value=0): 1896a23d212SGreg Clayton '''Extract "n" uint16_t integers from the binary file at the current file position, returns a list of integers''' 1906a23d212SGreg Clayton s = self.read_size(2 * n) 1916a23d212SGreg Clayton if s: 1926a23d212SGreg Clayton return struct.unpack(self.byte_order + ("%u" % n) + 'H', s) 1936a23d212SGreg Clayton else: 1946a23d212SGreg Clayton return (fail_value,) * n 1956a23d212SGreg Clayton 1966a23d212SGreg Clayton def get_n_sint32(self, n, fail_value=0): 1976a23d212SGreg Clayton '''Extract "n" int32_t integers from the binary file at the current file position, returns a list of integers''' 1986a23d212SGreg Clayton s = self.read_size(4 * n) 1996a23d212SGreg Clayton if s: 2006a23d212SGreg Clayton return struct.unpack(self.byte_order + ("%u" % n) + 'i', s) 2016a23d212SGreg Clayton else: 2026a23d212SGreg Clayton return (fail_value,) * n 2036a23d212SGreg Clayton 2046a23d212SGreg Clayton def get_n_uint32(self, n, fail_value=0): 2056a23d212SGreg Clayton '''Extract "n" uint32_t integers from the binary file at the current file position, returns a list of integers''' 2066a23d212SGreg Clayton s = self.read_size(4 * n) 2076a23d212SGreg Clayton if s: 2086a23d212SGreg Clayton return struct.unpack(self.byte_order + ("%u" % n) + 'I', s) 2096a23d212SGreg Clayton else: 2106a23d212SGreg Clayton return (fail_value,) * n 2116a23d212SGreg Clayton 2126a23d212SGreg Clayton def get_n_sint64(self, n, fail_value=0): 2136a23d212SGreg Clayton '''Extract "n" int64_t integers from the binary file at the current file position, returns a list of integers''' 2146a23d212SGreg Clayton s = self.read_size(8 * n) 2156a23d212SGreg Clayton if s: 2166a23d212SGreg Clayton return struct.unpack(self.byte_order + ("%u" % n) + 'q', s) 2176a23d212SGreg Clayton else: 2186a23d212SGreg Clayton return (fail_value,) * n 2196a23d212SGreg Clayton 2206a23d212SGreg Clayton def get_n_uint64(self, n, fail_value=0): 2216a23d212SGreg Clayton '''Extract "n" uint64_t integers from the binary file at the current file position, returns a list of integers''' 2226a23d212SGreg Clayton s = self.read_size(8 * n) 2236a23d212SGreg Clayton if s: 2246a23d212SGreg Clayton return struct.unpack(self.byte_order + ("%u" % n) + 'Q', s) 2256a23d212SGreg Clayton else: 2266a23d212SGreg Clayton return (fail_value,) * n 227