Last active
March 24, 2020 02:51
-
-
Save zvodd/03fb43b755416d297dec69f8a38c2d0f to your computer and use it in GitHub Desktop.
Extracts a slice of bytes from file or stdin, outputs binary to file/stdout. "-x" to dump hex to STDERR
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
import os | |
import argparse | |
from io import BytesIO | |
from textwrap import wrap | |
class DummyWriter(object): | |
def write(self, x): | |
pass | |
def close(): | |
pass | |
class IntParserActionPos(argparse.Action): | |
"""Parse Positive Interger base 10 or hex""" | |
def __call__(self, parser, namespace, values, option_string=None): | |
v = values | |
if values.startswith('0x'): | |
v = int(values, 16) | |
else: | |
v = int(values) | |
if v < 0: | |
ValueError("Must be greater than zero") | |
setattr(namespace, self.dest, v) | |
class IntParserAction(argparse.Action): | |
"""Parse Interger base 10 or hex""" | |
def __call__(self, parser, namespace, values, option_string=None): | |
v = values | |
if values.startswith('0x') or values.startswith('-0x'): | |
v = int(values, 16) | |
else: | |
v = int(values) | |
setattr(namespace, self.dest, v) | |
class InFileAction(argparse.Action): | |
"""Handles a filename or buffers STDIN, | |
creating a "$(name)_size" value in namespace""" | |
def __call__(self, parser, namespace, values, option_string=None): | |
fh = None | |
filesize = 0 | |
if values == "-": | |
fh = BytesIO(sys.stdin.buffer.read()) | |
filesize = fh.seek(0, 2) | |
fh.seek(0, 0) | |
else: | |
fh = open(values, 'rb') | |
filesize = os.path.getsize(values) | |
setattr(namespace, self.dest + "_size", filesize) | |
setattr(namespace, self.dest, fh) | |
class OutFileAction(argparse.Action): | |
def __call__(self, parser, namespace, values, option_string=None): | |
v = None | |
if values == "-": | |
v = sys.stdout.buffer | |
elif values is None: | |
v = DummyWriter() | |
else: | |
v = open(values, 'wb') | |
setattr(namespace, self.dest, v) | |
def main(): | |
parser = argparse.ArgumentParser() | |
parser.add_argument('-b', '--begin', default=0, | |
action=IntParserActionPos, | |
help='Start position of bytes - positive integer "0x"\ | |
for hex or base10.') | |
group = parser.add_mutually_exclusive_group() | |
group.add_argument('-e', '--end', default=None, action=IntParserAction, | |
help='End position of bytes - integer "0x" for hex or\ | |
base10.') | |
group.add_argument('-l', '--length', default=None, | |
action=IntParserActionPos, | |
help='Length of bytes - positive integer "0x" for hex\ | |
or base10.') | |
parser.add_argument('-x', '--print-hex', action='store_true', | |
help='prints extracted bytes to STDERR in hex') | |
parser.add_argument('infile', action=InFileAction, | |
help='"-" for STDIN or filename') | |
parser.add_argument('outfile', nargs="?", action=OutFileAction, | |
help='Blank for no output, "-" for STDOUT, or\ | |
filename') | |
args = parser.parse_args() | |
# print("infile", type(args.infile), args.infile) | |
# print("outfile", type(args.outfile), args.outfile) | |
filesize = args.infile_size | |
start = args.begin | |
end = args.end | |
if end is not None: | |
if end == 0: | |
end = filesize - start | |
elif end < 0: | |
end = (filesize - start) + end | |
else: | |
end = end | |
elif args.length is not None: | |
end = start + args.length | |
else: | |
end = filesize | |
ifh = args.infile | |
ofh = args.outfile | |
ifh.seek(start) | |
pos = ifh.tell() | |
while ifh.tell() < end: | |
readn = min(end - pos, 32) | |
haveread = ifh.read(readn) | |
pos = ifh.tell() | |
if args.print_hex: | |
echo = haveread.hex() | |
print(" ".join(wrap(echo, 8)), file=sys.stderr) | |
ofh.write(haveread) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment