Skip to content

Instantly share code, notes, and snippets.

@zvodd
Last active March 24, 2020 02:51
Show Gist options
  • Save zvodd/03fb43b755416d297dec69f8a38c2d0f to your computer and use it in GitHub Desktop.
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
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