Initial commit

This commit is contained in:
René Mathieu
2026-01-17 13:49:51 +01:00
commit 0fef8d96c5
1897 changed files with 396119 additions and 0 deletions

View File

@@ -0,0 +1,135 @@
# Copyright 2008-2021 pydicom authors. See LICENSE file for details.
"""Utility functions used in debugging writing and reading"""
from io import BytesIO
import os
import sys
from typing import BinaryIO, TYPE_CHECKING
from pydicom.valuerep import VR
if TYPE_CHECKING: # pragma: no cover
from pydicom.dataset import Dataset
def print_character(ordchr: int) -> str:
"""Return a printable character, or '.' for non-printable ones."""
if 31 < ordchr < 126 and ordchr != 92:
return chr(ordchr)
return "."
def filedump(
filename: str | bytes | os.PathLike,
start_address: int = 0,
stop_address: int | None = None,
) -> str:
"""Dump out the contents of a file to a standard hex dump 16 bytes wide"""
with open(filename, "rb") as f:
return hexdump(f, start_address, stop_address)
def datadump(
data: bytes, start_address: int = 0, stop_address: int | None = None
) -> str:
"""Return a hex string representation of `data`."""
return hexdump(BytesIO(data), start_address, stop_address)
def hexdump(
f: BinaryIO,
start_address: int = 0,
stop_address: int | None = None,
show_address: bool = True,
) -> str:
"""Return a formatted string of hex bytes and characters in data.
This is a utility function for debugging file writing.
Parameters
----------
f : BinaryIO
The file-like to dump.
start_address : int, optional
The offset where the dump should start (default ``0``)
stop_address : int, optional
The offset where the dump should end, by default the entire file will
be dumped.
show_address : bool, optional
If ``True`` (default) then include the offset of each line of output.
Returns
-------
str
"""
s = []
# Determine the maximum number of characters for the offset
max_offset_len = len(f"{f.seek(0, 2):X}")
if stop_address:
max_offset_len = len(f"{stop_address:X}")
f.seek(start_address)
while True:
offset = f.tell()
if stop_address and offset > stop_address:
break
data = f.read(16)
if not data:
break
current = []
if show_address:
# Offset at the start of the current line
current.append(f"{offset:0{max_offset_len}X} ")
# Add hex version of the current line
b = " ".join([f"{x:02X}" for x in data])
current.append(f"{b:<49}") # if fewer than 16 bytes, pad out to length
# Append the ASCII version of the current line (or . if not ASCII)
current.append("".join([print_character(x) for x in data]))
s.append("".join(current))
return "\n".join(s)
def pretty_print(
ds: "Dataset", indent_level: int = 0, indent_chars: str = " "
) -> None:
"""Print a dataset directly, with indented levels.
This is just like Dataset._pretty_str, but more useful for debugging as it
prints each item immediately rather than composing a string, making it
easier to immediately see where an error in processing a dataset starts.
"""
indent = indent_chars * indent_level
next_indent = indent_chars * (indent_level + 1)
for elem in ds:
if elem.VR == VR.SQ: # a sequence
print(f"{indent}{elem.tag} {elem.name} -- {len(elem.value)} item(s)")
for dataset in elem.value:
pretty_print(dataset, indent_level + 1)
print(next_indent + "---------")
else:
print(indent + repr(elem))
if __name__ == "__main__": # pragma: no cover
filename = sys.argv[1]
start_address = 0
stop_address = None
if len(sys.argv) > 2: # then have start address
start_address = eval(sys.argv[2])
if len(sys.argv) > 3:
stop_address = eval(sys.argv[3])
print(filedump(filename, start_address, stop_address))