Skip to content

Commit 16b507e

Browse files
authored
Change hexdump_iter to not rely on the length of its input file (#850)
We cannot determine the length of the file if passed e.g. a tube or a pipe or PTY or character device (e.g. stdin or /dev/null). Supercedes: 9c2f0f4 (cherry picked from commit 14f717b)
1 parent 53f041a commit 16b507e

1 file changed

Lines changed: 20 additions & 23 deletions

File tree

pwnlib/util/fiddling.py

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from ..context import context
1212
from ..log import getLogger
1313
from ..term import text
14-
from .cyclic import cyclic
14+
from .cyclic import de_bruijn
1515
from .cyclic import cyclic_find
1616

1717
log = getLogger(__name__)
@@ -560,13 +560,15 @@ def _hexiichar(c):
560560
}
561561

562562
cyclic_pregen = ''
563+
de_bruijn_gen = de_bruijn()
563564

564565
def sequential_lines(a,b):
565566
return (a+b) in cyclic_pregen
566567

567568
def update_cyclic_pregenerated(size):
568569
global cyclic_pregen
569-
cyclic_pregen = cyclic(size)
570+
while size > len(cyclic_pregen):
571+
cyclic_pregen += de_bruijn_gen.next()
570572

571573
def hexdump_iter(fd, width=16, skip=True, hexii=False, begin=0, style=None,
572574
highlight=None, cyclic=False):
@@ -609,23 +611,6 @@ def hexdump_iter(fd, width=16, skip=True, hexii=False, begin=0, style=None,
609611
spacer = ' '
610612
marker = (style.get('marker') or (lambda s:s))('│')
611613

612-
# Total length of the input stream
613-
total = 0
614-
615-
if hasattr(fd, 'len'):
616-
total = fd.len
617-
else:
618-
# Save the current file offset
619-
cur = fd.tell()
620-
621-
# Determine the total size of the file
622-
fd.seek(0, os.SEEK_END)
623-
total = fd.tell() - cur
624-
625-
# Restore the file offset, and
626-
fd.seek(cur or 0, os.SEEK_SET)
627-
628-
629614
if hexii:
630615
column_sep = ''
631616
line_fmt = '%%(offset)08x %%(hexbytes)-%is│' % (len(column_sep)+(width*byte_width))
@@ -645,17 +630,29 @@ def style_byte(b):
645630
return hbyte, abyte
646631
cache = [style_byte(chr(b)) for b in range(256)]
647632

648-
if cyclic:
649-
update_cyclic_pregenerated(total)
650-
651633
numb = 0
652634
while True:
653635
offset = begin + numb
654-
chunk = fd.read(width)
636+
637+
# If a tube is passed in as fd, it will raise EOFError when it runs
638+
# out of data, unlike a file or StringIO object, which return an empty
639+
# string.
640+
try:
641+
chunk = fd.read(width)
642+
except EOFError:
643+
chunk = ''
644+
645+
# We have run out of data, exit the loop
655646
if chunk == '':
656647
break
648+
649+
# Advance the cursor by the number of bytes we actually read
657650
numb += len(chunk)
658651

652+
# Update the cyclic pattern in case
653+
if cyclic:
654+
update_cyclic_pregenerated(numb)
655+
659656
# If this chunk is the same as the last unique chunk,
660657
# use a '*' instead.
661658
if skip and last_unique:

0 commit comments

Comments
 (0)