152 lines
3.4 KiB
Python
152 lines
3.4 KiB
Python
#! /usr/bin/env python3
|
|
# encoding: utf-8
|
|
|
|
import copy
|
|
import imp
|
|
import math
|
|
import os
|
|
import sys
|
|
|
|
# --------------------------------------------------
|
|
|
|
def import_module(path):
|
|
'''
|
|
Imports a python file as a module. The path can be relative or absolute.
|
|
|
|
Based on the work of Yuval Greenfield released into the public domain.
|
|
'''
|
|
|
|
# remove the .py suffix
|
|
mod_dn = os.path.dirname(path)
|
|
mod_fn = os.path.basename(path)
|
|
|
|
if mod_fn.endswith('.py'):
|
|
mod_name = mod_fn[:-3]
|
|
else:
|
|
# packages for example
|
|
mod_name = mod_fn
|
|
|
|
fd = None
|
|
|
|
try:
|
|
data = imp.find_module(mod_name, [mod_dn])
|
|
module = imp.load_module(mod_name, *data)
|
|
fd = data[0]
|
|
|
|
finally:
|
|
if fd is not None:
|
|
fd.close()
|
|
|
|
return module
|
|
|
|
# --------------------------------------------------
|
|
|
|
def batch_gen(data, batch_size):
|
|
'''
|
|
Split data (a sequence) into sequences batch_size elements long.
|
|
'''
|
|
|
|
for i in range(0, len(data), batch_size):
|
|
yield data[i:i+batch_size]
|
|
|
|
# --------------------------------------------------
|
|
|
|
def console(locals, globals=None, tab_completion=False):
|
|
'''
|
|
Opens up a Python console.
|
|
|
|
tab_completion enables completion of object names using TAB, however note
|
|
that this will make pasting formatted snippets of code difficult
|
|
'''
|
|
|
|
import code, readline, rlcompleter
|
|
|
|
environment = copy.copy(locals)
|
|
|
|
if globals:
|
|
for key, value in globals.items():
|
|
if key not in environment:
|
|
environment[key] = value
|
|
|
|
if tab_completion:
|
|
readline.parse_and_bind('tab: complete')
|
|
|
|
c = code.InteractiveConsole(environment)
|
|
c.interact(banner='')
|
|
|
|
# --------------------------------------------------
|
|
|
|
def debugger():
|
|
'''
|
|
Drops into the Python Debugger where called.
|
|
'''
|
|
|
|
import pdb
|
|
|
|
pdb.set_trace()
|
|
|
|
# --------------------------------------------------
|
|
|
|
def hexdump(data, indent=0, offset=16, show_header=True, show_offsets=True, show_ascii=True, output=sys.stdout):
|
|
"""
|
|
Writes a hex dump of 'data' to 'output'.
|
|
|
|
The output text is indented with spaces and contains 'offset' bytes per line.
|
|
If show_header is True, a single line with byte numbers preceeds all output.
|
|
If show_offsets is True, each line is prefixed with the address of the first byte of that line.
|
|
If show_ascii is True, each line is suffixed with its ASCII representation. Unprintable characters
|
|
are replaced with a dot.
|
|
The 'output' must implement a .write(str) method.
|
|
"""
|
|
|
|
if type(data) is not bytes:
|
|
raise ValueError('data must be bytes')
|
|
|
|
offset_figures = math.ceil(math.log2(len(data)) / 8) * 2
|
|
format_str = '%%0%dx ' %(offset_figures)
|
|
ptr = 0
|
|
|
|
if show_header:
|
|
line = []
|
|
|
|
if show_offsets:
|
|
line.append('offset'[:offset_figures].ljust(offset_figures + 2))
|
|
|
|
for i in range(offset):
|
|
line.append('%2x' %(i))
|
|
|
|
if show_ascii:
|
|
line.append(' ASCII')
|
|
|
|
output.write(' '.join(line) + '\n')
|
|
|
|
while data[ptr:]:
|
|
if indent:
|
|
output.write(' ' * indent)
|
|
|
|
if show_offsets:
|
|
output.write(format_str %(ptr))
|
|
|
|
hex_bytes = []
|
|
ascii_bytes = []
|
|
|
|
for local_i, i in enumerate(range(ptr, ptr+offset)):
|
|
if i < len(data):
|
|
c = data[i]
|
|
hex_bytes.append('%02x' %(c))
|
|
|
|
if 0x20 <= c <= 0x7e:
|
|
ascii_bytes.append(chr(c))
|
|
else:
|
|
ascii_bytes.append('.')
|
|
elif i == len(data):
|
|
hex_bytes.extend([' '] * (offset - local_i))
|
|
|
|
output.write(' '.join(hex_bytes))
|
|
|
|
if show_ascii:
|
|
output.write(' |' + ''.join(ascii_bytes) + '|')
|
|
|
|
output.write('\n')
|
|
|
|
ptr += offset
|