|
|
@@ -26,16 +26,21 @@ import sys
|
|
|
|
|
|
import re
|
|
|
|
|
|
+
|
|
|
def make_re(mask):
|
|
|
"""Makes a regex from an iterable of characters."""
|
|
|
as_string = "".join(mask)
|
|
|
r = '[^' + re.escape(as_string) + ']'
|
|
|
return re.compile(r)
|
|
|
|
|
|
-# All the printable characters, without tabs and newlines, but including spaces.
|
|
|
-NON_FANCY_PRINTABLE = make_re(set(string.printable).difference(string.whitespace).union(" "))
|
|
|
+
|
|
|
+# All the printable characters, without tabs and newlines,
|
|
|
+# but including spaces.
|
|
|
+NON_FANCY_PRINTABLE = make_re(
|
|
|
+ set(string.printable).difference(string.whitespace).union(" "))
|
|
|
PRINTABLE = make_re(string.printable)
|
|
|
|
|
|
+
|
|
|
def mask_not_printable(contents, mask_re=PRINTABLE):
|
|
|
"""
|
|
|
Replaces non-printable characters with "."
|
|
|
@@ -44,12 +49,14 @@ def mask_not_printable(contents, mask_re=PRINTABLE):
|
|
|
out, cnt = mask_re.subn('.', contents)
|
|
|
return cnt, out
|
|
|
|
|
|
+
|
|
|
def mask_not_alphanumeric(data):
|
|
|
"""
|
|
|
Same as above, except also masks out tab and newline.
|
|
|
"""
|
|
|
return mask_not_printable(data, NON_FANCY_PRINTABLE)
|
|
|
|
|
|
+
|
|
|
def xxd(shift, data, bytes_per_line, bytes_per_sentence):
|
|
|
"""
|
|
|
A generator of (offset, [[byte ordinal]], printable) strings,
|
|
|
@@ -69,15 +76,17 @@ def xxd(shift, data, bytes_per_line, bytes_per_sentence):
|
|
|
# Convert bytes object back to string object if the
|
|
|
# data is a bytes object
|
|
|
if isinstance(data, (bytes, bytearray)):
|
|
|
- line = "".join( chr(x) for x in bytearray(line))
|
|
|
+ line = "".join(chr(x) for x in bytearray(line))
|
|
|
|
|
|
line_printable = mask_not_alphanumeric(line)[1]
|
|
|
line_ordinals = list(map(ord, str(line)))
|
|
|
offsets = list(range(0, len(line_ordinals), bytes_per_sentence))
|
|
|
- line_ordinal_words = [ line_ordinals[x:x+bytes_per_sentence] for x in offsets ]
|
|
|
+ line_ordinal_words = [
|
|
|
+ line_ordinals[x:x+bytes_per_sentence] for x in offsets]
|
|
|
|
|
|
yield (shift + current, line_ordinal_words, line_printable)
|
|
|
|
|
|
+
|
|
|
def main(input, output):
|
|
|
"""
|
|
|
Prints out input just as xxd would do it.
|
|
|
@@ -86,23 +95,26 @@ def main(input, output):
|
|
|
bytes_per_line = 16
|
|
|
bytes_per_sentence = 2
|
|
|
|
|
|
- # Must be multiple of bytes_per_line
|
|
|
- input_chunk = bytes_per_line * 10
|
|
|
-
|
|
|
while True:
|
|
|
data = input.read(bytes_per_line)
|
|
|
if data == '':
|
|
|
return
|
|
|
|
|
|
- for off, ordinals, printable in xxd(offset, data, bytes_per_line, bytes_per_sentence):
|
|
|
+ for off, ordinals, printable in xxd(offset, data,
|
|
|
+ bytes_per_line,
|
|
|
+ bytes_per_sentence):
|
|
|
def ashex(ord):
|
|
|
return "%02x" % ord
|
|
|
- hex = " ".join([ "".join(map(ashex, sentence)) for sentence in ordinals])
|
|
|
- # 2 characters per byte, 1 extra for spacing, and 1 extra at the end.
|
|
|
- hex = hex.ljust(bytes_per_line*2 + int(math.floor(bytes_per_line / bytes_per_sentence)) - 1)
|
|
|
+ hex = " ".join(
|
|
|
+ ["".join(map(ashex, sentence)) for sentence in ordinals])
|
|
|
+ # 2 characters per byte, 1 extra for spacing,
|
|
|
+ # and 1 extra at the end.
|
|
|
+ hex = hex.ljust(bytes_per_line*2 + int(
|
|
|
+ math.floor(bytes_per_line / bytes_per_sentence)) - 1)
|
|
|
output.write("%07x: %s %s\n" % (off, hex, printable))
|
|
|
|
|
|
offset += len(data)
|
|
|
|
|
|
+
|
|
|
if __name__ == "__main__":
|
|
|
main(sys.stdin, sys.stdout)
|