515bc8c155
Differential Revision: https://reviews.llvm.org/D83857
227 lines
7.9 KiB
Python
Executable File
227 lines
7.9 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
import string
|
|
import struct
|
|
import sys
|
|
|
|
|
|
class FileExtract:
|
|
'''Decode binary data from a file'''
|
|
|
|
def __init__(self, f, b='='):
|
|
'''Initialize with an open binary file and optional byte order'''
|
|
|
|
self.file = f
|
|
self.byte_order = b
|
|
self.offsets = list()
|
|
|
|
def set_byte_order(self, b):
|
|
'''Set the byte order, valid values are "big", "little", "swap", "native", "<", ">", "@", "="'''
|
|
if b == 'big':
|
|
self.byte_order = '>'
|
|
elif b == 'little':
|
|
self.byte_order = '<'
|
|
elif b == 'swap':
|
|
# swap what ever the current byte order is
|
|
self.byte_order = swap_unpack_char()
|
|
elif b == 'native':
|
|
self.byte_order = '='
|
|
elif b == '<' or b == '>' or b == '@' or b == '=':
|
|
self.byte_order = b
|
|
else:
|
|
print("error: invalid byte order specified: '%s'" % b)
|
|
|
|
def is_in_memory(self):
|
|
return False
|
|
|
|
def seek(self, offset, whence=0):
|
|
if self.file:
|
|
return self.file.seek(offset, whence)
|
|
raise ValueError
|
|
|
|
def tell(self):
|
|
if self.file:
|
|
return self.file.tell()
|
|
raise ValueError
|
|
|
|
def read_size(self, byte_size):
|
|
s = self.file.read(byte_size)
|
|
if len(s) != byte_size:
|
|
return None
|
|
return s
|
|
|
|
def push_offset_and_seek(self, offset):
|
|
'''Push the current file offset and seek to "offset"'''
|
|
self.offsets.append(self.file.tell())
|
|
self.file.seek(offset, 0)
|
|
|
|
def pop_offset_and_seek(self):
|
|
'''Pop a previously pushed file offset, or do nothing if there were no previously pushed offsets'''
|
|
if len(self.offsets) > 0:
|
|
self.file.seek(self.offsets.pop())
|
|
|
|
def get_sint8(self, fail_value=0):
|
|
'''Extract a single int8_t from the binary file at the current file position, returns a single integer'''
|
|
s = self.read_size(1)
|
|
if s:
|
|
v, = struct.unpack(self.byte_order + 'b', s)
|
|
return v
|
|
else:
|
|
return fail_value
|
|
|
|
def get_uint8(self, fail_value=0):
|
|
'''Extract a single uint8_t from the binary file at the current file position, returns a single integer'''
|
|
s = self.read_size(1)
|
|
if s:
|
|
v, = struct.unpack(self.byte_order + 'B', s)
|
|
return v
|
|
else:
|
|
return fail_value
|
|
|
|
def get_sint16(self, fail_value=0):
|
|
'''Extract a single int16_t from the binary file at the current file position, returns a single integer'''
|
|
s = self.read_size(2)
|
|
if s:
|
|
v, = struct.unpack(self.byte_order + 'h', s)
|
|
return v
|
|
else:
|
|
return fail_value
|
|
|
|
def get_uint16(self, fail_value=0):
|
|
'''Extract a single uint16_t from the binary file at the current file position, returns a single integer'''
|
|
s = self.read_size(2)
|
|
if s:
|
|
v, = struct.unpack(self.byte_order + 'H', s)
|
|
return v
|
|
else:
|
|
return fail_value
|
|
|
|
def get_sint32(self, fail_value=0):
|
|
'''Extract a single int32_t from the binary file at the current file position, returns a single integer'''
|
|
s = self.read_size(4)
|
|
if s:
|
|
v, = struct.unpack(self.byte_order + 'i', s)
|
|
return v
|
|
else:
|
|
return fail_value
|
|
|
|
def get_uint32(self, fail_value=0):
|
|
'''Extract a single uint32_t from the binary file at the current file position, returns a single integer'''
|
|
s = self.read_size(4)
|
|
if s:
|
|
v, = struct.unpack(self.byte_order + 'I', s)
|
|
return v
|
|
else:
|
|
return fail_value
|
|
|
|
def get_sint64(self, fail_value=0):
|
|
'''Extract a single int64_t from the binary file at the current file position, returns a single integer'''
|
|
s = self.read_size(8)
|
|
if s:
|
|
v, = struct.unpack(self.byte_order + 'q', s)
|
|
return v
|
|
else:
|
|
return fail_value
|
|
|
|
def get_uint64(self, fail_value=0):
|
|
'''Extract a single uint64_t from the binary file at the current file position, returns a single integer'''
|
|
s = self.read_size(8)
|
|
if s:
|
|
v, = struct.unpack(self.byte_order + 'Q', s)
|
|
return v
|
|
else:
|
|
return fail_value
|
|
|
|
def get_fixed_length_c_string(
|
|
self,
|
|
n,
|
|
fail_value='',
|
|
isprint_only_with_space_padding=False):
|
|
'''Extract a single fixed length C string from the binary file at the current file position, returns a single C string'''
|
|
s = self.read_size(n)
|
|
if s:
|
|
cstr, = struct.unpack(self.byte_order + ("%i" % n) + 's', s)
|
|
# Strip trialing NULLs
|
|
cstr = string.strip(cstr, "\0")
|
|
if isprint_only_with_space_padding:
|
|
for c in cstr:
|
|
if c in string.printable or ord(c) == 0:
|
|
continue
|
|
return fail_value
|
|
return cstr
|
|
else:
|
|
return fail_value
|
|
|
|
def get_c_string(self):
|
|
'''Extract a single NULL terminated C string from the binary file at the current file position, returns a single C string'''
|
|
cstr = ''
|
|
byte = self.get_uint8()
|
|
while byte != 0:
|
|
cstr += "%c" % byte
|
|
byte = self.get_uint8()
|
|
return cstr
|
|
|
|
def get_n_sint8(self, n, fail_value=0):
|
|
'''Extract "n" int8_t integers from the binary file at the current file position, returns a list of integers'''
|
|
s = self.read_size(n)
|
|
if s:
|
|
return struct.unpack(self.byte_order + ("%u" % n) + 'b', s)
|
|
else:
|
|
return (fail_value,) * n
|
|
|
|
def get_n_uint8(self, n, fail_value=0):
|
|
'''Extract "n" uint8_t integers from the binary file at the current file position, returns a list of integers'''
|
|
s = self.read_size(n)
|
|
if s:
|
|
return struct.unpack(self.byte_order + ("%u" % n) + 'B', s)
|
|
else:
|
|
return (fail_value,) * n
|
|
|
|
def get_n_sint16(self, n, fail_value=0):
|
|
'''Extract "n" int16_t integers from the binary file at the current file position, returns a list of integers'''
|
|
s = self.read_size(2 * n)
|
|
if s:
|
|
return struct.unpack(self.byte_order + ("%u" % n) + 'h', s)
|
|
else:
|
|
return (fail_value,) * n
|
|
|
|
def get_n_uint16(self, n, fail_value=0):
|
|
'''Extract "n" uint16_t integers from the binary file at the current file position, returns a list of integers'''
|
|
s = self.read_size(2 * n)
|
|
if s:
|
|
return struct.unpack(self.byte_order + ("%u" % n) + 'H', s)
|
|
else:
|
|
return (fail_value,) * n
|
|
|
|
def get_n_sint32(self, n, fail_value=0):
|
|
'''Extract "n" int32_t integers from the binary file at the current file position, returns a list of integers'''
|
|
s = self.read_size(4 * n)
|
|
if s:
|
|
return struct.unpack(self.byte_order + ("%u" % n) + 'i', s)
|
|
else:
|
|
return (fail_value,) * n
|
|
|
|
def get_n_uint32(self, n, fail_value=0):
|
|
'''Extract "n" uint32_t integers from the binary file at the current file position, returns a list of integers'''
|
|
s = self.read_size(4 * n)
|
|
if s:
|
|
return struct.unpack(self.byte_order + ("%u" % n) + 'I', s)
|
|
else:
|
|
return (fail_value,) * n
|
|
|
|
def get_n_sint64(self, n, fail_value=0):
|
|
'''Extract "n" int64_t integers from the binary file at the current file position, returns a list of integers'''
|
|
s = self.read_size(8 * n)
|
|
if s:
|
|
return struct.unpack(self.byte_order + ("%u" % n) + 'q', s)
|
|
else:
|
|
return (fail_value,) * n
|
|
|
|
def get_n_uint64(self, n, fail_value=0):
|
|
'''Extract "n" uint64_t integers from the binary file at the current file position, returns a list of integers'''
|
|
s = self.read_size(8 * n)
|
|
if s:
|
|
return struct.unpack(self.byte_order + ("%u" % n) + 'Q', s)
|
|
else:
|
|
return (fail_value,) * n
|