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