From e6779b021aff027d4dfe174635c674a64355a2ba Mon Sep 17 00:00:00 2001 From: dgelessus Date: Sat, 31 Aug 2019 20:07:26 +0200 Subject: [PATCH] Replace rsrcfork.open's rsrcfork parameter with a more usable version The new fork parameter accepts strings, which are more understandable than the old None/True/False values, and can be extended in the future. --- README.rst | 4 ++++ rsrcfork/__main__.py | 4 +--- rsrcfork/api.py | 33 +++++++++++++++++++++++++++------ 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/README.rst b/README.rst index f2ffb69..691d3da 100644 --- a/README.rst +++ b/README.rst @@ -144,6 +144,10 @@ Version 1.2.0 (next version) * This fixes reading certain system files with resource data in their data fork (such as HIToolbox.rsrc in HIToolbox.framework, or .dfont fonts) on recent macOS versions (at least macOS 10.14, possibly earlier). Although these files have no resource fork, recent macOS versions will successfully open the resource fork and return garbage data for it. This behavior is now detected and handled by using the data fork instead. +* Replaced the ``rsrcfork`` parameter of ``rsrcfork.open``/``ResourceFork.open`` with a new ``fork`` parameter. ``fork`` accepts string values (like the command line ``--fork`` option) rather than ``rsrcfork``'s hard to understand ``None``/``True``/``False``. + + * 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``. * 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. diff --git a/rsrcfork/__main__.py b/rsrcfork/__main__.py index 742ac45..aba582c 100644 --- a/rsrcfork/__main__.py +++ b/rsrcfork/__main__.py @@ -196,8 +196,6 @@ def main(): ns = ap.parse_args() - ns.fork = {"auto": None, "data": False, "rsrc": True}[ns.fork] - if ns.file == "-": if ns.fork is not None: print("Cannot specify an explicit fork when reading from stdin", file=sys.stderr) @@ -205,7 +203,7 @@ def main(): rf = api.ResourceFile(sys.stdin.buffer) else: - rf = api.ResourceFile.open(ns.file, rsrcfork=ns.fork) + rf = api.ResourceFile.open(ns.file, fork=ns.fork) with rf: if ns.header_system or ns.header_application: diff --git a/rsrcfork/api.py b/rsrcfork/api.py index 38eebac..1a5d2f3 100644 --- a/rsrcfork/api.py +++ b/rsrcfork/api.py @@ -5,6 +5,7 @@ import io import os import struct import typing +import warnings from . import compress @@ -199,11 +200,16 @@ class ResourceFile(collections.abc.Mapping): return f"<{type(self).__module__}.{type(self).__qualname__} at {id(self):#x} containing {len(self)} resources with IDs: {list(self)}>" @classmethod - def open(cls, filename: typing.Union[str, bytes, os.PathLike], *, rsrcfork: typing.Optional[bool]=None, **kwargs) -> "ResourceFile": + def open(cls, filename: typing.Union[str, bytes, os.PathLike], *, fork: str="auto", **kwargs) -> "ResourceFile": """Open the file at the given path as a ResourceFile. - If rsrcfork is not None, it is treated as boolean and controls whether the data or resource fork of the file should be opened. (On systems other than macOS, opening resource forks will not work of course, since they don't exist.) - If rsrcfork is None, the resource fork is opened if it exists and contains valid resource data, otherwise the data fork is opened instead. + The fork parameter controls which fork of the file the resource data will be read from. It accepts the following values: + + * "auto" (the default): Automatically select the correct fork. The resource fork will be used if the file has one and it contains valid resource data. Otherwise the data fork will be used. + * "rsrc": Force use of the resource fork and never fall back to the data fork. This will not work on systems other than macOS, because they do not support resource forks natively. + * "data": Force use of the data fork, even if a resource fork is present. + + The rsrcfork parameter is deprecated and will be removed in the future. It has the same purpose as the fork parameter, but accepts different argument values: None stands for "auto", True stands for "rsrc", and False stands for "data". These argument values are less understandable than the string versions and are not easily extensible in the future, which is why the parameter has been deprecated. """ if "close" in kwargs: @@ -211,7 +217,20 @@ class ResourceFile(collections.abc.Mapping): kwargs["close"] = True - if rsrcfork is None: + if "rsrcfork" in kwargs: + if fork != "auto": + raise TypeError("The fork and rsrcfork parameters cannot be used together. Please use only the fork parameter; it replaces the deprecated rsrcfork parameter.") + + if kwargs["rsrcfork"] is None: + fork = "auto" + elif kwargs["rsrcfork"]: + fork = "rsrc" + else: + fork = "data" + warnings.warn(DeprecationWarning(f"The rsrcfork parameter has been deprecated and will be removed in a future version. Please use fork={fork!r} instead of rsrcfork={kwargs['rsrcfork']!r}.")) + del kwargs["rsrcfork"] + + if fork == "auto": # Determine whether the file has a usable resource fork. try: # Try to open the resource fork. @@ -231,12 +250,14 @@ class ResourceFile(collections.abc.Mapping): except BaseException: f.close() raise - elif rsrcfork: + elif fork == "rsrc": # Force use of the resource fork. return cls(open(os.path.join(filename, "..namedfork", "rsrc"), "rb"), **kwargs) - else: + elif fork == "data": # Force use of the data fork. return cls(open(filename, "rb"), **kwargs) + else: + raise ValueError(f"Unsupported value for the fork parameter: {fork!r}") def __init__(self, stream: typing.io.BinaryIO, *, close: bool=False): """Create a ResourceFile wrapping the given byte stream.