mirror of
https://github.com/dgelessus/python-rsrcfork.git
synced 2024-11-26 11:49:23 +00:00
Refactor resource reading internals
The reading of resource name and data is now performed in the Resource class (lazily, when the respective attributes are accessed) instead of in ResourceFile._LazyResourceMap.
This commit is contained in:
parent
2193c81518
commit
5af455992b
@ -116,7 +116,10 @@ Changelog
|
|||||||
Version 1.6.1 (next version)
|
Version 1.6.1 (next version)
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
* (no changes yet)
|
* Optimized lazy loading of ``Resource`` objects. Previously, resource data would be read from disk whenever a ``Resource`` object was looked up, even if the data itself is never used. Now the resource data is only loaded once the ``data`` (or ``data_raw``) attribute is accessed.
|
||||||
|
|
||||||
|
* The same optimization applies to the ``name`` attribute, although this is unlikely to make a difference in practice.
|
||||||
|
* As a result, it is no longer possible to construct ``Resource`` objects without a resource file. This was previously possible, but had no practical use.
|
||||||
|
|
||||||
Version 1.6.0
|
Version 1.6.0
|
||||||
^^^^^^^^^^^^^
|
^^^^^^^^^^^^^
|
||||||
|
@ -97,24 +97,31 @@ class ResourceAttrs(enum.Flag):
|
|||||||
class Resource(object):
|
class Resource(object):
|
||||||
"""A single resource from a resource file."""
|
"""A single resource from a resource file."""
|
||||||
|
|
||||||
|
_resfile: "ResourceFile"
|
||||||
type: bytes
|
type: bytes
|
||||||
id: int
|
id: int
|
||||||
name: typing.Optional[bytes]
|
name_offset: int
|
||||||
|
_name: typing.Optional[bytes]
|
||||||
attributes: ResourceAttrs
|
attributes: ResourceAttrs
|
||||||
data_raw: bytes
|
data_raw_offset: int
|
||||||
|
_data_raw: bytes
|
||||||
_compressed_info: compress.common.CompressedHeaderInfo
|
_compressed_info: compress.common.CompressedHeaderInfo
|
||||||
_data_decompressed: bytes
|
_data_decompressed: bytes
|
||||||
|
|
||||||
def __init__(self, resource_type: bytes, resource_id: int, name: typing.Optional[bytes], attributes: ResourceAttrs, data_raw: bytes) -> None:
|
def __init__(self, resfile: "ResourceFile", resource_type: bytes, resource_id: int, name_offset: int, attributes: ResourceAttrs, data_raw_offset: int) -> None:
|
||||||
"""Create a new resource with the given type code, ID, name, attributes, and data."""
|
"""Create a resource object representing a resource stored in a resource file.
|
||||||
|
|
||||||
|
External code should not call this constructor manually. Resources should be looked up through a ResourceFile object instead.
|
||||||
|
"""
|
||||||
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
|
self._resfile = resfile
|
||||||
self.type = resource_type
|
self.type = resource_type
|
||||||
self.id = resource_id
|
self.id = resource_id
|
||||||
self.name = name
|
self.name_offset = name_offset
|
||||||
self.attributes = attributes
|
self.attributes = attributes
|
||||||
self.data_raw = data_raw
|
self.data_raw_offset = data_raw_offset
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
try:
|
try:
|
||||||
@ -145,6 +152,30 @@ class Resource(object):
|
|||||||
warnings.warn(DeprecationWarning("The resource_id attribute has been deprecated and will be removed in a future version. Please use the id attribute instead."))
|
warnings.warn(DeprecationWarning("The resource_id attribute has been deprecated and will be removed in a future version. Please use the id attribute instead."))
|
||||||
return self.id
|
return self.id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self) -> typing.Optional[bytes]:
|
||||||
|
try:
|
||||||
|
return self._name
|
||||||
|
except AttributeError:
|
||||||
|
if self.name_offset == 0xffff:
|
||||||
|
self._name = None
|
||||||
|
else:
|
||||||
|
self._resfile._stream.seek(self._resfile.map_offset + self._resfile.map_name_list_offset + self.name_offset)
|
||||||
|
(name_length,) = self._resfile._stream_unpack(STRUCT_RESOURCE_NAME_HEADER)
|
||||||
|
self._name = self._resfile._read_exact(name_length)
|
||||||
|
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def data_raw(self) -> bytes:
|
||||||
|
try:
|
||||||
|
return self._data_raw
|
||||||
|
except AttributeError:
|
||||||
|
self._resfile._stream.seek(self._resfile.data_offset + self.data_raw_offset)
|
||||||
|
(data_raw_length,) = self._resfile._stream_unpack(STRUCT_RESOURCE_DATA_HEADER)
|
||||||
|
self._data_raw = self._resfile._read_exact(data_raw_length)
|
||||||
|
return self._data_raw
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def compressed_info(self) -> typing.Optional[compress.common.CompressedHeaderInfo]:
|
def compressed_info(self) -> typing.Optional[compress.common.CompressedHeaderInfo]:
|
||||||
"""The compressed resource header information, or None if this resource is not compressed.
|
"""The compressed resource header information, or None if this resource is not compressed.
|
||||||
@ -238,18 +269,7 @@ class ResourceFile(typing.Mapping[bytes, typing.Mapping[int, Resource]], typing.
|
|||||||
|
|
||||||
name_offset, attributes, data_offset = self._submap[key]
|
name_offset, attributes, data_offset = self._submap[key]
|
||||||
|
|
||||||
if name_offset == 0xffff:
|
return Resource(self._resfile, self._restype, key, name_offset, attributes, data_offset)
|
||||||
name = None
|
|
||||||
else:
|
|
||||||
self._resfile._stream.seek(self._resfile.map_offset + self._resfile.map_name_list_offset + name_offset)
|
|
||||||
(name_length,) = self._resfile._stream_unpack(STRUCT_RESOURCE_NAME_HEADER)
|
|
||||||
name = self._resfile._read_exact(name_length)
|
|
||||||
|
|
||||||
self._resfile._stream.seek(self._resfile.data_offset + data_offset)
|
|
||||||
(data_length,) = self._resfile._stream_unpack(STRUCT_RESOURCE_DATA_HEADER)
|
|
||||||
data = self._resfile._read_exact(data_length)
|
|
||||||
|
|
||||||
return Resource(self._restype, key, name, attributes, data)
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
if len(self) == 1:
|
if len(self) == 1:
|
||||||
|
Loading…
Reference in New Issue
Block a user