dissect.ole 3.9.dev3__tar.gz → 3.10.dev1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (20) hide show
  1. {dissect_ole-3.9.dev3/dissect.ole.egg-info → dissect_ole-3.10.dev1}/PKG-INFO +2 -2
  2. {dissect_ole-3.9.dev3 → dissect_ole-3.10.dev1}/dissect/ole/c_ole.py +3 -1
  3. {dissect_ole-3.9.dev3 → dissect_ole-3.10.dev1}/dissect/ole/ole.py +44 -40
  4. {dissect_ole-3.9.dev3 → dissect_ole-3.10.dev1/dissect.ole.egg-info}/PKG-INFO +2 -2
  5. {dissect_ole-3.9.dev3 → dissect_ole-3.10.dev1}/pyproject.toml +48 -5
  6. {dissect_ole-3.9.dev3 → dissect_ole-3.10.dev1}/tox.ini +5 -18
  7. {dissect_ole-3.9.dev3 → dissect_ole-3.10.dev1}/COPYRIGHT +0 -0
  8. {dissect_ole-3.9.dev3 → dissect_ole-3.10.dev1}/LICENSE +0 -0
  9. {dissect_ole-3.9.dev3 → dissect_ole-3.10.dev1}/MANIFEST.in +0 -0
  10. {dissect_ole-3.9.dev3 → dissect_ole-3.10.dev1}/README.md +0 -0
  11. {dissect_ole-3.9.dev3 → dissect_ole-3.10.dev1}/dissect/ole/__init__.py +0 -0
  12. {dissect_ole-3.9.dev3 → dissect_ole-3.10.dev1}/dissect/ole/exceptions.py +0 -0
  13. {dissect_ole-3.9.dev3 → dissect_ole-3.10.dev1}/dissect.ole.egg-info/SOURCES.txt +0 -0
  14. {dissect_ole-3.9.dev3 → dissect_ole-3.10.dev1}/dissect.ole.egg-info/dependency_links.txt +0 -0
  15. {dissect_ole-3.9.dev3 → dissect_ole-3.10.dev1}/dissect.ole.egg-info/requires.txt +0 -0
  16. {dissect_ole-3.9.dev3 → dissect_ole-3.10.dev1}/dissect.ole.egg-info/top_level.txt +0 -0
  17. {dissect_ole-3.9.dev3 → dissect_ole-3.10.dev1}/setup.cfg +0 -0
  18. {dissect_ole-3.9.dev3 → dissect_ole-3.10.dev1}/tests/docs/Makefile +0 -0
  19. {dissect_ole-3.9.dev3 → dissect_ole-3.10.dev1}/tests/docs/conf.py +0 -0
  20. {dissect_ole-3.9.dev3 → dissect_ole-3.10.dev1}/tests/docs/index.rst +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: dissect.ole
3
- Version: 3.9.dev3
3
+ Version: 3.10.dev1
4
4
  Summary: A Dissect module implementing a parser for the Object Linking & Embedding (OLE) format, commonly used by document editors on Windows operating systems
5
5
  Author-email: Dissect Team <dissect@fox-it.com>
6
6
  License: Affero General Public License v3
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from dissect.cstruct import cstruct
2
4
 
3
5
  ole_def = """
@@ -34,7 +36,7 @@ struct StructuredStorageHeader { // [offset from start in bytes, length in by
34
36
  char _abSig[8]; // [000H,08] 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1
35
37
  // for current version, was 0x0e, 0x11, 0xfc, 0x0d,
36
38
  // 0xd0, 0xcf, 0x11, 0xe0 on old, beta 2 files
37
- // (late 92) which are also supported by the
39
+ // (late '92) which are also supported by the
38
40
  // reference implementation
39
41
  char _clid[16]; // [008H,16] class id (set with WriteClassStg, retrieved with
40
42
  // GetClassFile/ReadClassStg)
@@ -1,12 +1,19 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, BinaryIO
4
+
1
5
  from dissect.util.stream import AlignedStream
2
6
  from dissect.util.ts import wintimestamp
3
7
 
4
8
  from dissect.ole.c_ole import DECOLOR, SIGNATURE, SIGNATURE_BETA, STGTY, c_ole
5
9
  from dissect.ole.exceptions import Error, InvalidFileError, NotFoundError
6
10
 
11
+ if TYPE_CHECKING:
12
+ from collections.abc import Iterator
13
+
7
14
 
8
15
  class OLE:
9
- def __init__(self, fh):
16
+ def __init__(self, fh: BinaryIO):
10
17
  self.fh = fh
11
18
  self.header = c_ole.StructuredStorageHeader(fh)
12
19
 
@@ -37,7 +44,7 @@ class OLE:
37
44
  self.root = self.directory(0)
38
45
  self.ministream = self.root.open()
39
46
 
40
- def get(self, path, root=None):
47
+ def get(self, path: str, root: DirectoryEntry | None = None) -> DirectoryEntry:
41
48
  root = root or self.root
42
49
 
43
50
  search_path = path.replace("\\", "/")
@@ -56,7 +63,7 @@ class OLE:
56
63
 
57
64
  return node
58
65
 
59
- def directory(self, sid):
66
+ def directory(self, sid: int) -> DirectoryEntry:
60
67
  try:
61
68
  return self._dircache[sid]
62
69
  except KeyError:
@@ -64,7 +71,7 @@ class OLE:
64
71
  self._dircache[sid] = entry
65
72
  return entry
66
73
 
67
- def fat(self, sect):
74
+ def fat(self, sect: int) -> int:
68
75
  idx, offset = divmod(sect, self.num_fat_entries)
69
76
 
70
77
  try:
@@ -107,10 +114,10 @@ class OLE:
107
114
 
108
115
  return table[offset]
109
116
 
110
- def minifat(self, sect):
117
+ def minifat(self, sect: int) -> int:
111
118
  return self._minifat[sect]
112
119
 
113
- def chain(self, sect, size=None):
120
+ def chain(self, sect: int, size: int | None = None) -> MiniChain:
114
121
  try:
115
122
  return self._chaincache[sect]
116
123
  except KeyError:
@@ -118,7 +125,7 @@ class OLE:
118
125
  self._chaincache[sect] = chain
119
126
  return chain
120
127
 
121
- def minichain(self, sect, size=None):
128
+ def minichain(self, sect: int, size: int | None = None) -> MiniChain:
122
129
  try:
123
130
  return self._minichaincache[sect]
124
131
  except KeyError:
@@ -128,7 +135,7 @@ class OLE:
128
135
 
129
136
 
130
137
  class DirectoryEntry:
131
- def __init__(self, ole, sid):
138
+ def __init__(self, ole: OLE, sid: int):
132
139
  self.ole = ole
133
140
  self.sid = sid
134
141
 
@@ -152,20 +159,20 @@ class DirectoryEntry:
152
159
 
153
160
  self._dirlist = {}
154
161
 
155
- def __repr__(self):
156
- return "<DirectoryEntry sid={} name={} type={} size=0x{:x}>".format(self.sid, self.name, self.type, self.size)
162
+ def __repr__(self) -> str:
163
+ return f"<DirectoryEntry sid={self.sid} name={self.name} type={self.type} size=0x{self.size:x}>"
157
164
 
158
- def open(self):
165
+ def open(self) -> ChainStream:
159
166
  return self.chain.open()
160
167
 
161
- def listdir(self):
168
+ def listdir(self) -> dict[str, DirectoryEntry]:
162
169
  if not self._dirlist:
163
170
  for entry in self.walk():
164
171
  self._dirlist[entry.name] = entry
165
172
 
166
173
  return self._dirlist
167
174
 
168
- def walk(self):
175
+ def walk(self) -> Iterator[DirectoryEntry]:
169
176
  if self.has_left_sibling:
170
177
  yield self.left_sibling
171
178
  yield from self.left_sibling.walk()
@@ -181,77 +188,77 @@ class DirectoryEntry:
181
188
  yield from self.child.walk()
182
189
 
183
190
  @property
184
- def child(self):
191
+ def child(self) -> DirectoryEntry | None:
185
192
  if not self.has_child:
186
193
  return None
187
194
  return self.ole.directory(self.entry._sidChild)
188
195
 
189
196
  @property
190
- def left_sibling(self):
197
+ def left_sibling(self) -> DirectoryEntry | None:
191
198
  if not self.has_left_sibling:
192
199
  return None
193
200
  return self.ole.directory(self.entry._sidLeftSib)
194
201
 
195
202
  @property
196
- def right_sibling(self):
203
+ def right_sibling(self) -> DirectoryEntry | None:
197
204
  if not self.has_right_sibling:
198
205
  return None
199
206
  return self.ole.directory(self.entry._sidRightSib)
200
207
 
201
208
  @property
202
- def has_child(self):
209
+ def has_child(self) -> bool:
203
210
  return self.entry._sidChild != 0xFFFFFFFF
204
211
 
205
212
  @property
206
- def has_left_sibling(self):
213
+ def has_left_sibling(self) -> bool:
207
214
  return self.entry._sidLeftSib != 0xFFFFFFFF
208
215
 
209
216
  @property
210
- def has_right_sibling(self):
217
+ def has_right_sibling(self) -> bool:
211
218
  return self.entry._sidRightSib != 0xFFFFFFFF
212
219
 
213
220
  @property
214
- def is_minifat(self):
221
+ def is_minifat(self) -> bool:
215
222
  return self.is_stream and self.size < self.ole.mini_cutoff
216
223
 
217
224
  @property
218
- def is_red(self):
225
+ def is_red(self) -> bool:
219
226
  return self.entry._bflags == DECOLOR.DE_RED
220
227
 
221
228
  @property
222
- def is_black(self):
229
+ def is_black(self) -> bool:
223
230
  return self.entry._bflags == DECOLOR.DE_BLACK
224
231
 
225
232
  @property
226
- def is_valid(self):
233
+ def is_valid(self) -> bool:
227
234
  return self.entry._mse == STGTY.STGTY_INVALID
228
235
 
229
236
  @property
230
- def is_stream(self):
237
+ def is_stream(self) -> bool:
231
238
  return self.entry._mse == STGTY.STGTY_STREAM
232
239
 
233
240
  @property
234
- def is_storage(self):
241
+ def is_storage(self) -> bool:
235
242
  return self.entry._mse == STGTY.STGTY_STORAGE
236
243
 
237
244
 
238
245
  class Chain:
239
- def __init__(self, ole, sect, size=None):
246
+ def __init__(self, ole: OLE, sect: int, size: int | None = None):
240
247
  self.ole = ole
241
248
  self.sect = sect
242
249
  self.size = size
243
250
  self.chain = [sect]
244
251
  self.ended = False
245
252
 
246
- def __len__(self):
253
+ def __len__(self) -> int:
247
254
  self.fill()
248
255
  return len(self.chain)
249
256
 
250
- def __iter__(self):
257
+ def __iter__(self) -> Iterator[int]:
251
258
  self.fill()
252
259
  return iter(self.chain)
253
260
 
254
- def __getitem__(self, i):
261
+ def __getitem__(self, i: int) -> int:
255
262
  cur = len(self.chain)
256
263
  tail = self.chain[-1]
257
264
 
@@ -271,10 +278,10 @@ class Chain:
271
278
 
272
279
  return self.chain[i]
273
280
 
274
- def open(self):
281
+ def open(self) -> ChainStream:
275
282
  return ChainStream(self.ole.fh, self, self.ole.sector_size, offset=self.ole.sector_size)
276
283
 
277
- def fill(self):
284
+ def fill(self) -> None:
278
285
  if self.ended:
279
286
  return
280
287
 
@@ -283,20 +290,20 @@ class Chain:
283
290
  except IndexError:
284
291
  pass
285
292
 
286
- def _lookup(self, sect):
293
+ def _lookup(self, sect: int) -> int:
287
294
  return self.ole.fat(sect)
288
295
 
289
296
 
290
297
  class MiniChain(Chain):
291
- def open(self):
298
+ def open(self) -> ChainStream:
292
299
  return ChainStream(self.ole.ministream, self, self.ole.mini_sector_size)
293
300
 
294
- def _lookup(self, sect):
301
+ def _lookup(self, sect: int) -> int:
295
302
  return self.ole.minifat(sect)
296
303
 
297
304
 
298
305
  class ChainStream(AlignedStream):
299
- def __init__(self, stream, chain, sector_size, offset=0):
306
+ def __init__(self, stream: BinaryIO, chain: Chain, sector_size: int, offset: int = 0):
300
307
  self._fh = stream
301
308
  self.chain = chain
302
309
  self.sector_size = sector_size
@@ -304,7 +311,7 @@ class ChainStream(AlignedStream):
304
311
 
305
312
  super().__init__(chain.size)
306
313
 
307
- def _read(self, offset, length):
314
+ def _read(self, offset: int, length: int) -> bytes:
308
315
  r = []
309
316
 
310
317
  if not self.size and length == -1:
@@ -321,10 +328,7 @@ class ChainStream(AlignedStream):
321
328
  except IndexError:
322
329
  break
323
330
 
324
- if self.size:
325
- sectread = min(self.size - offset, sector_size)
326
- else:
327
- sectread = sector_size
331
+ sectread = min(self.size - offset, sector_size) if self.size else sector_size
328
332
  fileoffset = self.offset + sectnum * sector_size
329
333
 
330
334
  self._fh.seek(fileoffset)
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: dissect.ole
3
- Version: 3.9.dev3
3
+ Version: 3.10.dev1
4
4
  Summary: A Dissect module implementing a parser for the Object Linking & Embedding (OLE) format, commonly used by document editors on Windows operating systems
5
5
  Author-email: Dissect Team <dissect@fox-it.com>
6
6
  License: Affero General Public License v3
@@ -41,13 +41,56 @@ dev = [
41
41
  "dissect.util>=3.0.dev,<4.0.dev",
42
42
  ]
43
43
 
44
- [tool.black]
44
+ [tool.ruff]
45
45
  line-length = 120
46
+ required-version = ">=0.9.0"
46
47
 
47
- [tool.isort]
48
- profile = "black"
49
- known_first_party = ["dissect.ole"]
50
- known_third_party = ["dissect"]
48
+ [tool.ruff.format]
49
+ docstring-code-format = true
50
+
51
+ [tool.ruff.lint]
52
+ select = [
53
+ "F",
54
+ "E",
55
+ "W",
56
+ "I",
57
+ "UP",
58
+ "YTT",
59
+ "ANN",
60
+ "B",
61
+ "C4",
62
+ "DTZ",
63
+ "T10",
64
+ "FA",
65
+ "ISC",
66
+ "G",
67
+ "INP",
68
+ "PIE",
69
+ "PYI",
70
+ "PT",
71
+ "Q",
72
+ "RSE",
73
+ "RET",
74
+ "SLOT",
75
+ "SIM",
76
+ "TID",
77
+ "TCH",
78
+ "PTH",
79
+ "PLC",
80
+ "TRY",
81
+ "FLY",
82
+ "PERF",
83
+ "FURB",
84
+ "RUF",
85
+ ]
86
+ ignore = ["E203", "B904", "UP024", "ANN002", "ANN003", "ANN204", "ANN401", "SIM105", "TRY003"]
87
+
88
+ [tool.ruff.lint.per-file-ignores]
89
+ "tests/docs/**" = ["INP001"]
90
+
91
+ [tool.ruff.lint.isort]
92
+ known-first-party = ["dissect.ole"]
93
+ known-third-party = ["dissect"]
51
94
 
52
95
  [tool.setuptools]
53
96
  license-files = ["LICENSE", "COPYRIGHT"]
@@ -32,31 +32,18 @@ commands =
32
32
  [testenv:fix]
33
33
  package = skip
34
34
  deps =
35
- black==23.1.0
36
- isort==5.11.4
35
+ ruff==0.9.2
37
36
  commands =
38
- black dissect
39
- isort dissect
37
+ ruff format dissect tests
40
38
 
41
39
  [testenv:lint]
42
40
  package = skip
43
41
  deps =
44
- black==23.1.0
45
- flake8
46
- flake8-black
47
- flake8-isort
48
- isort==5.11.4
42
+ ruff==0.9.2
49
43
  vermin
50
44
  commands =
51
- flake8 dissect
52
- vermin -t=3.9- --no-tips --lint dissect
53
-
54
- [flake8]
55
- max-line-length = 120
56
- extend-ignore =
57
- # See https://github.com/PyCQA/pycodestyle/issues/373
58
- E203,
59
- statistics = True
45
+ ruff check dissect tests
46
+ vermin -t=3.9- --no-tips --lint dissect tests
60
47
 
61
48
  [testenv:docs-build]
62
49
  allowlist_externals = make
File without changes