Hex dump: Difference between revisions
Content deleted Content added
→{{header|Wren}}: Rewritten to cater for more bases. |
m →{{header|Python}}: Fix offset and final byte count when skipping bytes. Show example of using offset and length. |
||
Line 571: | Line 571: | ||
import math |
import math |
||
from io import BufferedIOBase |
from io import BufferedIOBase |
||
from io import SEEK_END |
|||
from itertools import islice |
from itertools import islice |
||
from typing import Iterable |
from typing import Iterable |
||
Line 586: | Line 587: | ||
@abc.abstractmethod |
@abc.abstractmethod |
||
def |
def format(self, data: Sequence[int]) -> str: |
||
"""""" |
"""Return _data_ formatted for output on one line.""" |
||
@property |
@property |
||
@abc.abstractmethod |
@abc.abstractmethod |
||
def bytes_per_line(self) -> int: |
def bytes_per_line(self) -> int: |
||
"""""" |
"""The number of bytes to display per line of output.""" |
||
Line 598: | Line 599: | ||
bytes_per_line = 16 |
bytes_per_line = 16 |
||
def |
def format(self, data: Sequence[int]) -> str: |
||
assert len(data) <= 16 |
assert len(data) <= 16 |
||
hex = f"{bytes(data[:8]).hex(' ')} {bytes(data[8:]).hex(' ')}".ljust(48) |
hex = f"{bytes(data[:8]).hex(' ')} {bytes(data[8:]).hex(' ')}".ljust(48) |
||
Line 608: | Line 609: | ||
bytes_per_line = 6 |
bytes_per_line = 6 |
||
def |
def format(self, data: Sequence[int]) -> str: |
||
assert len(data) <= 6 |
assert len(data) <= 6 |
||
bits = " ".join(bin(b)[2:].rjust(8, "0") for b in data).ljust(53) |
bits = " ".join(bin(b)[2:].rjust(8, "0") for b in data).ljust(53) |
||
Line 639: | Line 640: | ||
skip: int = 0, |
skip: int = 0, |
||
length: int = math.inf, # type: ignore |
length: int = math.inf, # type: ignore |
||
formatter: Formatter = canonicalFormatter, |
|||
) -> Iterator[str]: |
) -> Iterator[str]: |
||
"""Generate a textual representation of bytes in _f_, one line at a time.""" |
"""Generate a textual representation of bytes in _f_, one line at a time.""" |
||
f.seek(skip) |
f.seek(skip) |
||
offset = |
offset = skip |
||
byte_count = 0 |
byte_count = 0 |
||
previous_line = "" |
previous_line = "" |
||
squeezing = False # True if the last output line was squeezed |
|||
identical_chunk = False |
|||
assert length > 0 |
|||
while byte_count < length: |
while byte_count < length: |
||
Line 661: | Line 664: | ||
# One line per chunk |
# One line per chunk |
||
for chunk in group(data, |
for chunk in group(data, formatter.bytes_per_line): |
||
line = format(chunk) |
line = formatter.format(chunk) |
||
if previous_line == line: |
if previous_line == line: |
||
if |
if squeezing is False: |
||
squeezing = True |
|||
yield "*" |
yield "*" |
||
else: |
else: |
||
previous_line = line |
previous_line = line |
||
squeezing = False |
|||
yield f"{offset:0>8x} {line}" |
yield f"{offset:0>8x} {line}" |
||
offset += |
offset += formatter.bytes_per_line |
||
byte_count += len(chunk) |
byte_count += len(chunk) |
||
# Final byte count |
# Final byte count |
||
bytes_in_f = f.seek(0, SEEK_END) |
|||
yield f"{byte_count:0>8x}" |
yield f"{min(byte_count + skip, bytes_in_f):0>8x}" |
||
Line 722: | Line 726: | ||
for line in hex_dump( |
for line in hex_dump( |
||
args.file, |
args.file, |
||
formatter=formatter, |
|||
skip=args.skip, |
skip=args.skip, |
||
length=args.length, |
length=args.length, |
||
Line 740: | Line 744: | ||
00000060 20 00 3d d8 00 de 2e 00 | .=.....| |
00000060 20 00 3d d8 00 de 2e 00 | .=.....| |
||
00000068 |
00000068 |
||
</pre> |
|||
<pre>$ python hex_dump.py example_utf16.txt -s 20 -n 25</pre> |
|||
<pre> |
|||
00000014 6f 00 64 00 65 00 20 00 69 00 73 00 20 00 61 00 |o.d.e. .i.s. .a.| |
|||
00000024 20 00 70 00 72 00 6f 00 67 | .p.r.o.g| |
|||
0000002d |
|||
</pre> |
</pre> |
||
<pre>$ python hex_dump.py example_utf16.txt -b</pre> |
<pre>$ python hex_dump.py example_utf16.txt -b</pre> |