1*061da546Spatrick#!/usr/bin/env python 2*061da546Spatrick 3*061da546Spatrickimport string 4*061da546Spatrickimport struct 5*061da546Spatrickimport sys 6*061da546Spatrick 7*061da546Spatrick 8*061da546Spatrickclass FileExtract: 9*061da546Spatrick '''Decode binary data from a file''' 10*061da546Spatrick 11*061da546Spatrick def __init__(self, f, b='='): 12*061da546Spatrick '''Initialize with an open binary file and optional byte order''' 13*061da546Spatrick 14*061da546Spatrick self.file = f 15*061da546Spatrick self.byte_order = b 16*061da546Spatrick self.offsets = list() 17*061da546Spatrick 18*061da546Spatrick def set_byte_order(self, b): 19*061da546Spatrick '''Set the byte order, valid values are "big", "little", "swap", "native", "<", ">", "@", "="''' 20*061da546Spatrick if b == 'big': 21*061da546Spatrick self.byte_order = '>' 22*061da546Spatrick elif b == 'little': 23*061da546Spatrick self.byte_order = '<' 24*061da546Spatrick elif b == 'swap': 25*061da546Spatrick # swap what ever the current byte order is 26*061da546Spatrick self.byte_order = swap_unpack_char() 27*061da546Spatrick elif b == 'native': 28*061da546Spatrick self.byte_order = '=' 29*061da546Spatrick elif b == '<' or b == '>' or b == '@' or b == '=': 30*061da546Spatrick self.byte_order = b 31*061da546Spatrick else: 32*061da546Spatrick print("error: invalid byte order specified: '%s'" % b) 33*061da546Spatrick 34*061da546Spatrick def is_in_memory(self): 35*061da546Spatrick return False 36*061da546Spatrick 37*061da546Spatrick def seek(self, offset, whence=0): 38*061da546Spatrick if self.file: 39*061da546Spatrick return self.file.seek(offset, whence) 40*061da546Spatrick raise ValueError 41*061da546Spatrick 42*061da546Spatrick def tell(self): 43*061da546Spatrick if self.file: 44*061da546Spatrick return self.file.tell() 45*061da546Spatrick raise ValueError 46*061da546Spatrick 47*061da546Spatrick def read_size(self, byte_size): 48*061da546Spatrick s = self.file.read(byte_size) 49*061da546Spatrick if len(s) != byte_size: 50*061da546Spatrick return None 51*061da546Spatrick return s 52*061da546Spatrick 53*061da546Spatrick def push_offset_and_seek(self, offset): 54*061da546Spatrick '''Push the current file offset and seek to "offset"''' 55*061da546Spatrick self.offsets.append(self.file.tell()) 56*061da546Spatrick self.file.seek(offset, 0) 57*061da546Spatrick 58*061da546Spatrick def pop_offset_and_seek(self): 59*061da546Spatrick '''Pop a previously pushed file offset, or do nothing if there were no previously pushed offsets''' 60*061da546Spatrick if len(self.offsets) > 0: 61*061da546Spatrick self.file.seek(self.offsets.pop()) 62*061da546Spatrick 63*061da546Spatrick def get_sint8(self, fail_value=0): 64*061da546Spatrick '''Extract a single int8_t from the binary file at the current file position, returns a single integer''' 65*061da546Spatrick s = self.read_size(1) 66*061da546Spatrick if s: 67*061da546Spatrick v, = struct.unpack(self.byte_order + 'b', s) 68*061da546Spatrick return v 69*061da546Spatrick else: 70*061da546Spatrick return fail_value 71*061da546Spatrick 72*061da546Spatrick def get_uint8(self, fail_value=0): 73*061da546Spatrick '''Extract a single uint8_t from the binary file at the current file position, returns a single integer''' 74*061da546Spatrick s = self.read_size(1) 75*061da546Spatrick if s: 76*061da546Spatrick v, = struct.unpack(self.byte_order + 'B', s) 77*061da546Spatrick return v 78*061da546Spatrick else: 79*061da546Spatrick return fail_value 80*061da546Spatrick 81*061da546Spatrick def get_sint16(self, fail_value=0): 82*061da546Spatrick '''Extract a single int16_t from the binary file at the current file position, returns a single integer''' 83*061da546Spatrick s = self.read_size(2) 84*061da546Spatrick if s: 85*061da546Spatrick v, = struct.unpack(self.byte_order + 'h', s) 86*061da546Spatrick return v 87*061da546Spatrick else: 88*061da546Spatrick return fail_value 89*061da546Spatrick 90*061da546Spatrick def get_uint16(self, fail_value=0): 91*061da546Spatrick '''Extract a single uint16_t from the binary file at the current file position, returns a single integer''' 92*061da546Spatrick s = self.read_size(2) 93*061da546Spatrick if s: 94*061da546Spatrick v, = struct.unpack(self.byte_order + 'H', s) 95*061da546Spatrick return v 96*061da546Spatrick else: 97*061da546Spatrick return fail_value 98*061da546Spatrick 99*061da546Spatrick def get_sint32(self, fail_value=0): 100*061da546Spatrick '''Extract a single int32_t from the binary file at the current file position, returns a single integer''' 101*061da546Spatrick s = self.read_size(4) 102*061da546Spatrick if s: 103*061da546Spatrick v, = struct.unpack(self.byte_order + 'i', s) 104*061da546Spatrick return v 105*061da546Spatrick else: 106*061da546Spatrick return fail_value 107*061da546Spatrick 108*061da546Spatrick def get_uint32(self, fail_value=0): 109*061da546Spatrick '''Extract a single uint32_t from the binary file at the current file position, returns a single integer''' 110*061da546Spatrick s = self.read_size(4) 111*061da546Spatrick if s: 112*061da546Spatrick v, = struct.unpack(self.byte_order + 'I', s) 113*061da546Spatrick return v 114*061da546Spatrick else: 115*061da546Spatrick return fail_value 116*061da546Spatrick 117*061da546Spatrick def get_sint64(self, fail_value=0): 118*061da546Spatrick '''Extract a single int64_t from the binary file at the current file position, returns a single integer''' 119*061da546Spatrick s = self.read_size(8) 120*061da546Spatrick if s: 121*061da546Spatrick v, = struct.unpack(self.byte_order + 'q', s) 122*061da546Spatrick return v 123*061da546Spatrick else: 124*061da546Spatrick return fail_value 125*061da546Spatrick 126*061da546Spatrick def get_uint64(self, fail_value=0): 127*061da546Spatrick '''Extract a single uint64_t from the binary file at the current file position, returns a single integer''' 128*061da546Spatrick s = self.read_size(8) 129*061da546Spatrick if s: 130*061da546Spatrick v, = struct.unpack(self.byte_order + 'Q', s) 131*061da546Spatrick return v 132*061da546Spatrick else: 133*061da546Spatrick return fail_value 134*061da546Spatrick 135*061da546Spatrick def get_fixed_length_c_string( 136*061da546Spatrick self, 137*061da546Spatrick n, 138*061da546Spatrick fail_value='', 139*061da546Spatrick isprint_only_with_space_padding=False): 140*061da546Spatrick '''Extract a single fixed length C string from the binary file at the current file position, returns a single C string''' 141*061da546Spatrick s = self.read_size(n) 142*061da546Spatrick if s: 143*061da546Spatrick cstr, = struct.unpack(self.byte_order + ("%i" % n) + 's', s) 144*061da546Spatrick # Strip trialing NULLs 145*061da546Spatrick cstr = string.strip(cstr, "\0") 146*061da546Spatrick if isprint_only_with_space_padding: 147*061da546Spatrick for c in cstr: 148*061da546Spatrick if c in string.printable or ord(c) == 0: 149*061da546Spatrick continue 150*061da546Spatrick return fail_value 151*061da546Spatrick return cstr 152*061da546Spatrick else: 153*061da546Spatrick return fail_value 154*061da546Spatrick 155*061da546Spatrick def get_c_string(self): 156*061da546Spatrick '''Extract a single NULL terminated C string from the binary file at the current file position, returns a single C string''' 157*061da546Spatrick cstr = '' 158*061da546Spatrick byte = self.get_uint8() 159*061da546Spatrick while byte != 0: 160*061da546Spatrick cstr += "%c" % byte 161*061da546Spatrick byte = self.get_uint8() 162*061da546Spatrick return cstr 163*061da546Spatrick 164*061da546Spatrick def get_n_sint8(self, n, fail_value=0): 165*061da546Spatrick '''Extract "n" int8_t integers from the binary file at the current file position, returns a list of integers''' 166*061da546Spatrick s = self.read_size(n) 167*061da546Spatrick if s: 168*061da546Spatrick return struct.unpack(self.byte_order + ("%u" % n) + 'b', s) 169*061da546Spatrick else: 170*061da546Spatrick return (fail_value,) * n 171*061da546Spatrick 172*061da546Spatrick def get_n_uint8(self, n, fail_value=0): 173*061da546Spatrick '''Extract "n" uint8_t integers from the binary file at the current file position, returns a list of integers''' 174*061da546Spatrick s = self.read_size(n) 175*061da546Spatrick if s: 176*061da546Spatrick return struct.unpack(self.byte_order + ("%u" % n) + 'B', s) 177*061da546Spatrick else: 178*061da546Spatrick return (fail_value,) * n 179*061da546Spatrick 180*061da546Spatrick def get_n_sint16(self, n, fail_value=0): 181*061da546Spatrick '''Extract "n" int16_t integers from the binary file at the current file position, returns a list of integers''' 182*061da546Spatrick s = self.read_size(2 * n) 183*061da546Spatrick if s: 184*061da546Spatrick return struct.unpack(self.byte_order + ("%u" % n) + 'h', s) 185*061da546Spatrick else: 186*061da546Spatrick return (fail_value,) * n 187*061da546Spatrick 188*061da546Spatrick def get_n_uint16(self, n, fail_value=0): 189*061da546Spatrick '''Extract "n" uint16_t integers from the binary file at the current file position, returns a list of integers''' 190*061da546Spatrick s = self.read_size(2 * n) 191*061da546Spatrick if s: 192*061da546Spatrick return struct.unpack(self.byte_order + ("%u" % n) + 'H', s) 193*061da546Spatrick else: 194*061da546Spatrick return (fail_value,) * n 195*061da546Spatrick 196*061da546Spatrick def get_n_sint32(self, n, fail_value=0): 197*061da546Spatrick '''Extract "n" int32_t integers from the binary file at the current file position, returns a list of integers''' 198*061da546Spatrick s = self.read_size(4 * n) 199*061da546Spatrick if s: 200*061da546Spatrick return struct.unpack(self.byte_order + ("%u" % n) + 'i', s) 201*061da546Spatrick else: 202*061da546Spatrick return (fail_value,) * n 203*061da546Spatrick 204*061da546Spatrick def get_n_uint32(self, n, fail_value=0): 205*061da546Spatrick '''Extract "n" uint32_t integers from the binary file at the current file position, returns a list of integers''' 206*061da546Spatrick s = self.read_size(4 * n) 207*061da546Spatrick if s: 208*061da546Spatrick return struct.unpack(self.byte_order + ("%u" % n) + 'I', s) 209*061da546Spatrick else: 210*061da546Spatrick return (fail_value,) * n 211*061da546Spatrick 212*061da546Spatrick def get_n_sint64(self, n, fail_value=0): 213*061da546Spatrick '''Extract "n" int64_t integers from the binary file at the current file position, returns a list of integers''' 214*061da546Spatrick s = self.read_size(8 * n) 215*061da546Spatrick if s: 216*061da546Spatrick return struct.unpack(self.byte_order + ("%u" % n) + 'q', s) 217*061da546Spatrick else: 218*061da546Spatrick return (fail_value,) * n 219*061da546Spatrick 220*061da546Spatrick def get_n_uint64(self, n, fail_value=0): 221*061da546Spatrick '''Extract "n" uint64_t integers from the binary file at the current file position, returns a list of integers''' 222*061da546Spatrick s = self.read_size(8 * n) 223*061da546Spatrick if s: 224*061da546Spatrick return struct.unpack(self.byte_order + ("%u" % n) + 'Q', s) 225*061da546Spatrick else: 226*061da546Spatrick return (fail_value,) * n 227