From c373b9fe2852ff0ee0a627054d974f8d4499e33e Mon Sep 17 00:00:00 2001 From: dgelessus Date: Tue, 3 Sep 2019 01:27:41 +0200 Subject: [PATCH] Clean up resource descriptions in listings and dumps Previously, when some aspect of a resource's metadata was not present (e. g. a resource with no name), the description would explicitly point this out (and e. g. say "unnamed"). Now missing parts of the metadata are simply omitted from the description, resulting in cleaner output in many cases. The resource description formats used by the listings and dumps have also been unified. Previously the descriptions were structured slightly differently in each case; this is now no longer the case. --- README.rst | 2 ++ rsrcfork/__main__.py | 86 +++++++++++++++++++------------------------- 2 files changed, 39 insertions(+), 49 deletions(-) diff --git a/README.rst b/README.rst index 691d3da..d103068 100644 --- a/README.rst +++ b/README.rst @@ -149,6 +149,8 @@ Version 1.2.0 (next version) * The old ``rsrcfork`` parameter has been deprecated and will be removed in the future, but for now it still works as before. * Added an explanatory message when a resource filter on the command line doesn't match any resources in the resource file. Previously there would either be no output or a confusing error, depending on the selected ``--format``. +* Cleaned up the resource descriptions in listings and dumps to improve readability. Previously they included some redundant or unnecessary information - for example, each resource with no attributes set would be explicitly marked as "no attributes". +* Unified the formats of resource descriptions in listings and dumps, which were previously slightly different from each other. * Improved error messages when attempting to read multiple resources using ``--format=hex`` or ``--format=raw``. * Fixed reading from non-seekable streams not working for some resource files. * Removed the ``allow_seek`` parameter of ``ResourceFork.__init__`` and the ``--read-mode`` command line option. They are no longer necessary, and were already practically useless before due to non-seekable stream reading being broken. diff --git a/rsrcfork/__main__.py b/rsrcfork/__main__.py index aba582c..3826c2f 100644 --- a/rsrcfork/__main__.py +++ b/rsrcfork/__main__.py @@ -160,6 +160,40 @@ def _raw_hexdump(data: bytes): for i in range(0, len(data), 16): print(" ".join(f"{byte:02x}" for byte in data[i:i + 16])) +def _describe_resource(res: api.Resource, *, include_type: bool, decompress: bool) -> str: + id_desc_parts = [f"{res.resource_id}"] + + if res.name is not None: + name = _bytes_escape(res.name, quote='"') + id_desc_parts.append(f'"{name}"') + + id_desc = ", ".join(id_desc_parts) + + content_desc_parts = [] + + if decompress and api.ResourceAttrs.resCompressed in res.attributes: + try: + res.data + except compress.DecompressError: + length_desc = f"decompression failed ({len(res.data_raw)} bytes compressed)" + else: + length_desc = f"{len(res.data)} bytes ({len(res.data_raw)} bytes compressed)" + else: + length_desc = f"{len(res.data_raw)} bytes" + content_desc_parts.append(length_desc) + + attrs = _decompose_flags(res.attributes) + if attrs: + content_desc_parts.append(" | ".join(attr.name for attr in attrs)) + + content_desc = ", ".join(content_desc_parts) + + desc = f"({id_desc}): {content_desc}" + if include_type: + restype = _bytes_escape(res.resource_type, quote="'") + desc = f"'{restype}' {desc}" + return desc + def main(): ap = argparse.ArgumentParser( add_help=False, @@ -253,26 +287,8 @@ def main(): if ns.format == "dump": # Human-readable info and hex dump - - if res.name is None: - name = "unnamed" - else: - name = _bytes_escape(res.name, quote='"') - name = f'name "{name}"' - - attrs = _decompose_flags(res.attributes) - if attrs: - attrdesc = "attributes: " + " | ".join(attr.name for attr in attrs) - else: - attrdesc = "no attributes" - - if ns.decompress: - length_desc = f"{len(res.data)} bytes (stored in {len(res.data_raw)} bytes)" - else: - length_desc = f"{len(data)} bytes" - - restype = _bytes_escape(res.resource_type, quote="'") - print(f"Resource '{restype}' ({res.resource_id}), {name}, {attrdesc}, {length_desc}:") + desc = _describe_resource(res, include_type=True, decompress=ns.decompress) + print(f"Resource {desc}:") _hexdump(data) print() elif ns.format == "hex": @@ -332,20 +348,14 @@ def main(): if rf.header_system_data != bytes(len(rf.header_system_data)): print("Header system data:") _hexdump(rf.header_system_data) - else: - print("No header system data") if rf.header_application_data != bytes(len(rf.header_application_data)): print("Header application data:") _hexdump(rf.header_application_data) - else: - print("No header application data") attrs = _decompose_flags(rf.file_attributes) if attrs: print("File attributes: " + " | ".join(attr.name for attr in attrs)) - else: - print("No file attributes") if len(rf) > 0: print(f"{len(rf)} resource types:") @@ -353,29 +363,7 @@ def main(): restype = _bytes_escape(typecode, quote="'") print(f"'{restype}': {len(resources)} resources:") for resid, res in rf[typecode].items(): - if res.name is None: - name = "unnamed" - else: - name = _bytes_escape(res.name, quote='"') - name = f'name "{name}"' - - attrs = _decompose_flags(res.attributes) - if attrs: - attrdesc = " | ".join(attr.name for attr in attrs) - else: - attrdesc = "no attributes" - - if ns.decompress and api.ResourceAttrs.resCompressed in attrs: - try: - res.data - except compress.DecompressError: - length_desc = f"decompression failed ({len(res.data_raw)} bytes compressed)" - else: - length_desc = f"{len(res.data)} bytes ({len(res.data_raw)} bytes compressed)" - else: - length_desc = f"{len(res.data_raw)} bytes" - - print(f"({resid}), {name}, {attrdesc}, {length_desc}") + print(_describe_resource(res, include_type=False, decompress=ns.decompress)) print() else: print("No resource types (empty resource file)")