221 lines
5 KiB
Python
221 lines
5 KiB
Python
#! /usr/bin/env python3
|
|
# encoding: utf-8
|
|
|
|
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.
|
|
|
|
@while importing a module
|
|
"""
|
|
|
|
import imp
|
|
import os
|
|
|
|
path = os.path.expanduser(path)
|
|
|
|
# remove the .py suffix
|
|
mod_dirname = os.path.dirname(path)
|
|
mod_filename = os.path.basename(path)
|
|
|
|
if mod_filename.endswith(".py"):
|
|
mod_name = mod_filename[:-3]
|
|
else:
|
|
# packages for example
|
|
mod_name = mod_filename
|
|
|
|
fd = None
|
|
|
|
try:
|
|
data = imp.find_module(mod_name, [mod_dirname])
|
|
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 update_dict(A, B, overwrite=False):
|
|
"""
|
|
Shallow-copies items from B to A.
|
|
|
|
Iff `overwrite`, keys that already exist in A will be overwritten.
|
|
Otherwise, only keys that aren't in A will be set.
|
|
"""
|
|
|
|
for key, value in B.items():
|
|
if key not in A:
|
|
A[key] = value
|
|
|
|
# --------------------------------------------------
|
|
|
|
def console(override_environment=None, tab_completion=True):
|
|
"""
|
|
Opens up a Python console.
|
|
|
|
If no `override_environment` is passed, the environment of the calling stack frame (and all parent stack frames) will be used.
|
|
"""
|
|
|
|
import code
|
|
import copy
|
|
import inspect
|
|
import readline
|
|
import rlcompleter
|
|
|
|
if override_environment:
|
|
environment = override_environment
|
|
else:
|
|
environment = {}
|
|
frame = inspect.currentframe()
|
|
|
|
while frame:
|
|
update_dict(environment, frame.f_locals)
|
|
frame = frame.f_back
|
|
|
|
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, width=16, show_header=True, show_offsets=True, show_ascii=True, use_colors=True, initial_offset=0, output=sys.stdout):
|
|
"""
|
|
Writes a hex dump of `data` to `output`.
|
|
|
|
The output text is indented with spaces and contains `width` 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 x) method. If `output` is None, the string is returned instead.
|
|
|
|
@while creating a hex dump
|
|
"""
|
|
|
|
import io
|
|
import math
|
|
from . import text
|
|
|
|
output_io = io.StringIO() if not output else output
|
|
|
|
try:
|
|
data = bytes(data)
|
|
except:
|
|
raise ValueError("data must be bytes or similar")
|
|
|
|
offset_figures = math.ceil(math.log2(len(data)) / 8) * 2 if data else 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(width):
|
|
line.append("%2x" %(i))
|
|
|
|
if show_ascii:
|
|
line.append(" *{0}*".format("ASCII".center(width, "-")))
|
|
|
|
output_io.write(" ".join(line) + "\n")
|
|
|
|
while data[ptr:]:
|
|
if indent:
|
|
output_io.write(" " * indent)
|
|
|
|
if show_offsets:
|
|
output_io.write(format_str %(initial_offset + ptr))
|
|
|
|
hex_bytes = []
|
|
ascii_bytes = []
|
|
|
|
for local_i, i in enumerate(range(ptr, ptr+width)):
|
|
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([" "] * (width - local_i))
|
|
|
|
if use_colors: output_io.write(text.render("<W>"))
|
|
output_io.write(" ".join(hex_bytes))
|
|
if use_colors: output_io.write(text.render("<.>"))
|
|
|
|
if show_ascii:
|
|
output_io.write(text.render(" | <W>") if use_colors else " |")
|
|
output_io.write("".join(ascii_bytes))
|
|
output_io.write(text.render("<.>|") if use_colors else "|")
|
|
|
|
output_io.write("\n")
|
|
|
|
ptr += width
|
|
|
|
if not output:
|
|
output_io.seek(0)
|
|
return output_io.read()
|
|
|
|
# --------------------------------------------------
|
|
|
|
def raw_to_hex(raw, spaces=True):
|
|
"""
|
|
Converts a bytearray (or bytes) into its textual hexadecimal representation.
|
|
"""
|
|
|
|
output = []
|
|
|
|
for o in raw:
|
|
output.append(hex(o)[2:].zfill(2))
|
|
|
|
return (" " if spaces else "").join(output)
|
|
|
|
def hex_to_raw(text):
|
|
"""
|
|
Converts a hexadecimal representation of a byte array into a bytearray.
|
|
"""
|
|
|
|
output = []
|
|
|
|
text = text.replace(" ", "")
|
|
|
|
for i in range(len(text)//2):
|
|
output.append(int(text[2*i:2*i+2], 16))
|
|
|
|
return bytearray(output)
|