Skip to content

Commit

Permalink
Change linter to Ruff (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
Schamper authored Jan 23, 2025
1 parent c38995e commit 6c81fb0
Show file tree
Hide file tree
Showing 15 changed files with 185 additions and 129 deletions.
6 changes: 3 additions & 3 deletions dissect/thumbcache/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
__all__ = [
"Error",
"IndexEntry",
"ThumbnailIndex",
"ThumbcacheFile",
"ThumbcacheEntry",
"Thumbcache",
"ThumbcacheEntry",
"ThumbcacheFile",
"ThumbnailIndex",
]
6 changes: 4 additions & 2 deletions dissect/thumbcache/c_thumbcache.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from __future__ import annotations

from dissect.cstruct import cstruct

thumbcache_index_def = """
thumbcache_def = """
struct INDEX_HEADER_V1 {
char Signature[4]; // 0x00
uint32 Version; // 0x04
Expand Down Expand Up @@ -75,4 +77,4 @@
uint32 Unknown; // 0x28
}; // 0x2C
"""
c_thumbcache_index = cstruct().load(thumbcache_index_def)
c_thumbcache = cstruct().load(thumbcache_def)
8 changes: 0 additions & 8 deletions dissect/thumbcache/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,14 @@
class Error(Exception):
"""A generic exception for the thumbcache module."""

pass


class NotAnIndexFileError(Error):
"""Raises if a thumbnail index signature could not be found."""

pass


class InvalidSignatureError(Error):
"""Raises if the signature does not match the expected value."""

pass


class UnknownThumbnailTypeError(Error):
"""Raises if an unknown thumbnail type was found."""

pass
53 changes: 27 additions & 26 deletions dissect/thumbcache/index.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
from __future__ import annotations

from datetime import datetime
from typing import BinaryIO, Iterator
from typing import TYPE_CHECKING, BinaryIO

from dissect.util import ts

from dissect.thumbcache.c_thumbcache import c_thumbcache_index
from dissect.thumbcache.c_thumbcache import c_thumbcache
from dissect.thumbcache.exceptions import NotAnIndexFileError
from dissect.thumbcache.util import ThumbnailType

if TYPE_CHECKING:
from collections.abc import Iterator
from datetime import datetime

INDEX_ENTRIES = {
ThumbnailType.WINDOWS_7: 5,
ThumbnailType.WINDOWS_81: 11,
Expand All @@ -29,12 +32,12 @@ def __init__(self, fh: BinaryIO) -> None:
self._header = None

@property
def header(self) -> c_thumbcache_index.INDEX_HEADER_V1 | c_thumbcache_index.INDEX_HEADER_V2:
def header(self) -> c_thumbcache.INDEX_HEADER_V1 | c_thumbcache.INDEX_HEADER_V2:
if self._header is None:
self._header = self._find_header(self.fh)
return self._header

def _find_header(self, fh: BinaryIO) -> c_thumbcache_index.INDEX_HEADER_V1 | c_thumbcache_index.INDEX_HEADER_V2:
def _find_header(self, fh: BinaryIO) -> c_thumbcache.INDEX_HEADER_V1 | c_thumbcache.INDEX_HEADER_V2:
"""Searches for the header signature, and puts ``fh`` at the correct position.
From Windows 8.1 onward, the two fields seem to use a 64-bit format field
Expand All @@ -44,19 +47,19 @@ def _find_header(self, fh: BinaryIO) -> c_thumbcache_index.INDEX_HEADER_V1 | c_t
fh: The file to read the header and indexes from.
Returns:
A c_thumbcache_index.INDEX_HEADER structure.
A c_thumbcache.INDEX_HEADER structure.
Raises:
NotAThumbnailIndexFileError: If the ``IMMM`` signature could not be found.
"""
position = fh.tell()
buffer = fh.read(len(c_thumbcache_index.INDEX_HEADER_V1))
buffer = fh.read(len(c_thumbcache.INDEX_HEADER_V1))
offset = buffer.find(self._signature)

if offset == MAX_IMM_OFFSET:
fh.seek(position)

header = c_thumbcache_index.INDEX_HEADER_V2(fh)
header = c_thumbcache.INDEX_HEADER_V2(fh)
# From looking at the index files, it has a specific amount of information.
# It is alligned in the follwing way:
# INDEX_HEADER_V2
Expand All @@ -68,19 +71,18 @@ def _find_header(self, fh: BinaryIO) -> c_thumbcache_index.INDEX_HEADER_V1 | c_t

# Read one index entry from the file till only zero bytes
entry = IndexEntry(fh, header.Version)
entry.header
entry.cache_offsets
_ = entry.header
_ = entry.cache_offsets

# Read offset to first entry
zero_bytes = len(entry.header) + INDEX_ENTRIES.get(header.Version) * BYTES_IN_NUMBER - len(header)
fh.read(zero_bytes)
return header
elif offset == 0:
return c_thumbcache_index.INDEX_HEADER_V1(buffer)
else:
raise NotAnIndexFileError(
f"The index file signature {self._signature!r} could not be found at the expected location."
)
if offset == 0:
return c_thumbcache.INDEX_HEADER_V1(buffer)
raise NotAnIndexFileError(
f"The index file signature {self._signature!r} could not be found at the expected location."
)

@property
def version(self) -> int:
Expand All @@ -102,8 +104,8 @@ def entries(self) -> Iterator[IndexEntry]:
"""Returns all index entries that are actually used."""
for _ in range(self.total_entries):
entry = IndexEntry(self.fh, self.type)
entry.header
entry.cache_offsets
_ = entry.header
_ = entry.cache_offsets

if entry.in_use():
yield entry
Expand All @@ -119,21 +121,20 @@ def __init__(self, fh: BinaryIO, type: ThumbnailType) -> None:
@property
def header(
self,
) -> c_thumbcache_index.VISTA_ENTRY | c_thumbcache_index.WINDOWS7_ENTRY | c_thumbcache_index.WINDOWS8_ENTRY:
) -> c_thumbcache.VISTA_ENTRY | c_thumbcache.WINDOWS7_ENTRY | c_thumbcache.WINDOWS8_ENTRY:
if not self._header:
self._header = self._select_header()
return self._header

def _select_header(
self,
) -> c_thumbcache_index.VISTA_ENTRY | c_thumbcache_index.WINDOWS7_ENTRY | c_thumbcache_index.WINDOWS8_ENTRY:
) -> c_thumbcache.VISTA_ENTRY | c_thumbcache.WINDOWS7_ENTRY | c_thumbcache.WINDOWS8_ENTRY:
"""Selects header version according to the thumbnailtype."""
if self.type == ThumbnailType.WINDOWS_VISTA:
return c_thumbcache_index.VISTA_ENTRY(self.fh)
elif self.type == ThumbnailType.WINDOWS_7:
return c_thumbcache_index.WINDOWS7_ENTRY(self.fh)
else:
return c_thumbcache_index.WINDOWS8_ENTRY(self.fh)
return c_thumbcache.VISTA_ENTRY(self.fh)
if self.type == ThumbnailType.WINDOWS_7:
return c_thumbcache.WINDOWS7_ENTRY(self.fh)
return c_thumbcache.WINDOWS8_ENTRY(self.fh)

def in_use(self) -> bool:
return self.identifier != b"\x00" * IDENTIFIER_BYTES
Expand All @@ -156,7 +157,7 @@ def cache_offsets(self) -> list[int]:
"""
if not self._data:
size = INDEX_ENTRIES.get(self.type)
self._data = c_thumbcache_index.uint32[size](self.fh)
self._data = c_thumbcache.uint32[size](self.fh)
if self.type > ThumbnailType.WINDOWS_7:
# Alignment step
self.fh.read((size % 2) * BYTES_IN_NUMBER)
Expand Down
12 changes: 8 additions & 4 deletions dissect/thumbcache/thumbcache.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
from pathlib import Path
from typing import Iterator
from __future__ import annotations

from typing import TYPE_CHECKING

from dissect.thumbcache.index import IndexEntry, ThumbnailIndex
from dissect.thumbcache.thumbcache_file import ThumbcacheEntry, ThumbcacheFile

if TYPE_CHECKING:
from collections.abc import Iterator
from pathlib import Path


class Thumbcache:
"""This class combines the thumbnailindex and thumbcachefile.
Expand Down Expand Up @@ -50,8 +55,7 @@ def entries(self) -> Iterator[tuple[Path, ThumbcacheEntry]]:
def index_entries(self) -> Iterator[IndexEntry]:
"""Iterates through all the index entries that are in use."""
with self.index_file.open("rb") as i_file:
for entry in ThumbnailIndex(i_file).entries():
yield entry
yield from ThumbnailIndex(i_file).entries()

def _entries_from_offsets(self, offsets: list[int]) -> Iterator[tuple[Path, ThumbcacheEntry]]:
"""Retrieves Thumbcache entries from a ThumbcacheFile using offsets."""
Expand Down
49 changes: 25 additions & 24 deletions dissect/thumbcache/thumbcache_file.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
from __future__ import annotations

from typing import Any, BinaryIO
from typing import TYPE_CHECKING, Any, BinaryIO

from dissect.thumbcache.c_thumbcache import c_thumbcache_index
from dissect.thumbcache.c_thumbcache import c_thumbcache
from dissect.thumbcache.exceptions import (
InvalidSignatureError,
UnknownThumbnailTypeError,
)
from dissect.thumbcache.util import ThumbnailType, seek_and_return

if TYPE_CHECKING:
from collections.abc import Iterator

UNKNOWN_BYTES = 8


class ThumbcacheFile:
__slots__ = [
"fh",
"_cached_entries",
"_entries",
"_header",
"fh",
"offset",
"signature",
"type",
"size",
"offset",
"_entries",
"_cached_entries",
"type",
]

"""
Expand All @@ -39,21 +42,20 @@ def __init__(self, fh: BinaryIO) -> None:
self._header = self._get_header_type(self.fh)
self._cached_entries: dict[int, ThumbcacheEntry] = {}

def _get_header_type(self, fh: BinaryIO) -> c_thumbcache_index.CACHE_HEADER_VISTA | c_thumbcache_index.CACHE_HEADER:
tmp_header = c_thumbcache_index.CACHE_HEADER(fh)
def _get_header_type(self, fh: BinaryIO) -> c_thumbcache.CACHE_HEADER_VISTA | c_thumbcache.CACHE_HEADER:
tmp_header = c_thumbcache.CACHE_HEADER(fh)

if self._signature != tmp_header.Signature:
raise InvalidSignatureError(
f"The signature {tmp_header.Signature!r} does not match the expected {self._signature!r}"
)

if tmp_header.Version <= ThumbnailType.WINDOWS_7:
return c_thumbcache_index.CACHE_HEADER_VISTA(tmp_header.dumps())
else:
return tmp_header
return c_thumbcache.CACHE_HEADER_VISTA(tmp_header.dumps())
return tmp_header

@property
def header(self) -> c_thumbcache_index.CACHE_HEADER_VISTA | c_thumbcache_index.CACHE_HEADER:
def header(self) -> c_thumbcache.CACHE_HEADER_VISTA | c_thumbcache.CACHE_HEADER:
return self._header

@property
Expand All @@ -72,15 +74,15 @@ def __getitem__(self, key: int) -> ThumbcacheEntry:
self._cached_entries[key] = item
return item

def __getattribute__(self, __name: str) -> Any:
def __getattribute__(self, name: str) -> Any:
try:
return object.__getattribute__(self, __name)
return object.__getattribute__(self, name)
except AttributeError:
pass

return getattr(self.header, __name.capitalize())
return getattr(self.header, name.capitalize())

def entries(self) -> list[ThumbcacheEntry]:
def entries(self) -> Iterator[ThumbcacheEntry]:
with seek_and_return(self.fh, self.fh.tell()):
try:
while True:
Expand Down Expand Up @@ -123,22 +125,21 @@ def __init__(self, fh: BinaryIO, type: ThumbnailType) -> None:
fh.read(UNKNOWN_BYTES)
additional_bytes += UNKNOWN_BYTES

self.data_checksum: bytes = c_thumbcache_index.char[8](fh)
self.header_checksum: bytes = c_thumbcache_index.char[8](fh)
self.data_checksum: bytes = c_thumbcache.char[8](fh)
self.header_checksum: bytes = c_thumbcache.char[8](fh)

self.identifier: str = c_thumbcache_index.wchar[self._header.IdentifierSize // 2](fh)
self.identifier: str = c_thumbcache.wchar[self._header.IdentifierSize // 2](fh)

header_size = len(self._header) + self._header.IdentifierSize + additional_bytes

self._data = fh.read(self._header.Size - header_size)

def _get_header(
self, thumbnail_type: ThumbnailType
) -> type[c_thumbcache_index.CACHE_ENTRY_VISTA | c_thumbcache_index.CACHE_ENTRY]:
) -> type[c_thumbcache.CACHE_ENTRY_VISTA | c_thumbcache.CACHE_ENTRY]:
if thumbnail_type == ThumbnailType.WINDOWS_VISTA:
return c_thumbcache_index.CACHE_ENTRY_VISTA
else:
return c_thumbcache_index.CACHE_ENTRY
return c_thumbcache.CACHE_ENTRY_VISTA
return c_thumbcache.CACHE_ENTRY

@property
def hash(self) -> str:
Expand Down
10 changes: 7 additions & 3 deletions dissect/thumbcache/tools/extract_images.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
#!/bin/python3
from __future__ import annotations

from pathlib import Path
from typing import TYPE_CHECKING

from dissect.thumbcache.exceptions import Error
from dissect.thumbcache.thumbcache_file import ThumbcacheFile
from dissect.thumbcache.tools.utils import create_argument_parser, write_entry

if TYPE_CHECKING:
from pathlib import Path

def dump_entry_data(path: Path, output_dir: Path):

def dump_entry_data(path: Path, output_dir: Path) -> None:
with path.open("rb") as file:
try:
cache_file = ThumbcacheFile(file)
Expand All @@ -18,7 +22,7 @@ def dump_entry_data(path: Path, output_dir: Path):
print(e)


def main():
def main() -> None:
parser = create_argument_parser("extract raw thumbcache entries")
args = parser.parse_args()
path: Path = args.cache_path
Expand Down
11 changes: 8 additions & 3 deletions dissect/thumbcache/tools/extract_with_index.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
from pathlib import Path
from __future__ import annotations

from typing import TYPE_CHECKING

from dissect.thumbcache.exceptions import Error
from dissect.thumbcache.thumbcache import Thumbcache
from dissect.thumbcache.tools.utils import create_argument_parser, write_entry

if TYPE_CHECKING:
from pathlib import Path


def dump_entry_data_through_index(path: Path, output_dir: Path, prefix: str):
def dump_entry_data_through_index(path: Path, output_dir: Path, prefix: str) -> None:
cache = Thumbcache(path=path, prefix=prefix)
try:
for location_path, entry in cache.entries():
Expand All @@ -15,7 +20,7 @@ def dump_entry_data_through_index(path: Path, output_dir: Path, prefix: str):
print(e)


def main():
def main() -> None:
parser = create_argument_parser("extract indexed entries")
parser.add_argument(
"--prefix",
Expand Down
Loading

0 comments on commit 6c81fb0

Please sign in to comment.