dissect.util 3.23.dev12__pp311-pypy311_pp73-win_amd64.whl
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.
Potentially problematic release.
This version of dissect.util might be problematic. Click here for more details.
- dissect/util/__init__.py +20 -0
- dissect/util/_build.py +17 -0
- dissect/util/_native/__init__.pyi +3 -0
- dissect/util/_native/compression/__init__.pyi +3 -0
- dissect/util/_native/compression/lz4.pyi +7 -0
- dissect/util/_native/compression/lzo.pyi +3 -0
- dissect/util/_native/hash/__init__.py +3 -0
- dissect/util/_native/hash/crc32c.py +2 -0
- dissect/util/_native.pypy311-pp73-win_amd64.pyd +0 -0
- dissect/util/compression/__init__.py +45 -0
- dissect/util/compression/lz4.py +95 -0
- dissect/util/compression/lzbitmap.py +130 -0
- dissect/util/compression/lzfse.py +467 -0
- dissect/util/compression/lznt1.py +92 -0
- dissect/util/compression/lzo.py +118 -0
- dissect/util/compression/lzvn.py +241 -0
- dissect/util/compression/lzxpress.py +80 -0
- dissect/util/compression/lzxpress_huffman.py +184 -0
- dissect/util/compression/sevenbit.py +77 -0
- dissect/util/compression/xz.py +112 -0
- dissect/util/cpio.py +226 -0
- dissect/util/encoding/__init__.py +0 -0
- dissect/util/encoding/surrogateescape.py +21 -0
- dissect/util/exceptions.py +6 -0
- dissect/util/hash/__init__.py +28 -0
- dissect/util/hash/crc32.py +55 -0
- dissect/util/hash/crc32c.py +60 -0
- dissect/util/hash/jenkins.py +102 -0
- dissect/util/ldap.py +237 -0
- dissect/util/plist.py +156 -0
- dissect/util/sid.py +50 -0
- dissect/util/stream.py +671 -0
- dissect/util/tools/__init__.py +0 -0
- dissect/util/tools/dump_nskeyedarchiver.py +61 -0
- dissect/util/ts.py +295 -0
- dissect/util/xmemoryview.py +117 -0
- dissect_util-3.23.dev12.dist-info/METADATA +89 -0
- dissect_util-3.23.dev12.dist-info/RECORD +43 -0
- dissect_util-3.23.dev12.dist-info/WHEEL +5 -0
- dissect_util-3.23.dev12.dist-info/entry_points.txt +2 -0
- dissect_util-3.23.dev12.dist-info/licenses/COPYRIGHT +5 -0
- dissect_util-3.23.dev12.dist-info/licenses/LICENSE +201 -0
- dissect_util-3.23.dev12.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from dissect.util.plist import NSKeyedArchiver, NSObject
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def main() -> None:
|
|
10
|
+
parser = argparse.ArgumentParser()
|
|
11
|
+
parser.add_argument("file", type=argparse.FileType("rb"), help="NSKeyedArchiver plist file to dump")
|
|
12
|
+
args = parser.parse_args()
|
|
13
|
+
|
|
14
|
+
with args.file as fh:
|
|
15
|
+
try:
|
|
16
|
+
obj = NSKeyedArchiver(fh)
|
|
17
|
+
except ValueError as e:
|
|
18
|
+
parser.exit(str(e))
|
|
19
|
+
|
|
20
|
+
print(obj)
|
|
21
|
+
print_object(obj.top)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def print_object(obj: Any, indent: int = 0, seen: set | None = None) -> None:
|
|
25
|
+
if seen is None:
|
|
26
|
+
seen = set()
|
|
27
|
+
|
|
28
|
+
try:
|
|
29
|
+
if obj in seen:
|
|
30
|
+
print(fmt(f"Recursive -> {obj}", indent))
|
|
31
|
+
return
|
|
32
|
+
except Exception:
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
if isinstance(obj, list):
|
|
36
|
+
for i, v in enumerate(obj):
|
|
37
|
+
print(fmt(f"[{i}]:", indent))
|
|
38
|
+
print_object(v, indent + 1, seen)
|
|
39
|
+
|
|
40
|
+
elif isinstance(obj, dict | NSObject):
|
|
41
|
+
if isinstance(obj, NSObject):
|
|
42
|
+
print(fmt(obj, indent))
|
|
43
|
+
try:
|
|
44
|
+
seen.add(obj)
|
|
45
|
+
except TypeError:
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
for k in sorted(obj.keys()):
|
|
49
|
+
print(fmt(f"{k}:", indent + 1))
|
|
50
|
+
print_object(obj[k], indent + 2, seen)
|
|
51
|
+
|
|
52
|
+
else:
|
|
53
|
+
print(fmt(obj, indent))
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def fmt(obj: Any, indent: int) -> str:
|
|
57
|
+
return f"{' ' * (indent * 4)}{obj}"
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
if __name__ == "__main__":
|
|
61
|
+
main()
|
dissect/util/ts.py
ADDED
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import struct
|
|
4
|
+
from datetime import datetime, timedelta, timezone
|
|
5
|
+
|
|
6
|
+
# Python on Windows and WASM (Emscripten) have problems calculating timestamps before 1970 (Unix epoch)
|
|
7
|
+
# Calculating relatively from the epoch is required on these platforms
|
|
8
|
+
# This method is slower, so we split the implementation between Windows, WASM and other platforms
|
|
9
|
+
# This used to be a platform comparison, but that was not reliable enough, so ducktype it instead
|
|
10
|
+
try:
|
|
11
|
+
datetime.fromtimestamp(-6969696969, tz=timezone.utc)
|
|
12
|
+
|
|
13
|
+
def _calculate_timestamp(ts: float) -> datetime:
|
|
14
|
+
"""Calculate timestamps normally."""
|
|
15
|
+
return datetime.fromtimestamp(ts, tz=timezone.utc)
|
|
16
|
+
except (OSError, OverflowError):
|
|
17
|
+
_EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
|
|
18
|
+
|
|
19
|
+
def _calculate_timestamp(ts: float) -> datetime:
|
|
20
|
+
"""Calculate timestamps relative from Unix epoch."""
|
|
21
|
+
return _EPOCH + timedelta(seconds=ts)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def now() -> datetime:
|
|
25
|
+
"""Return an aware datetime object of the current time in UTC."""
|
|
26
|
+
return datetime.now(timezone.utc)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def unix_now() -> int:
|
|
30
|
+
"""Return a Unix timestamp of the current time."""
|
|
31
|
+
return to_unix(now())
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def unix_now_ms() -> int:
|
|
35
|
+
"""Return a Unix millisecond timestamp of the current time."""
|
|
36
|
+
return to_unix_ms(now())
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def unix_now_us() -> int:
|
|
40
|
+
"""Return a Unix microsecond timestamp of the current time."""
|
|
41
|
+
return to_unix_us(now())
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def unix_now_ns() -> int:
|
|
45
|
+
"""Return a Unix nanosecond timestamp of the current time."""
|
|
46
|
+
return to_unix_ns(now())
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def to_unix(dt: datetime) -> int:
|
|
50
|
+
"""Converts datetime objects into Unix timestamps.
|
|
51
|
+
|
|
52
|
+
This is a convenience method.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
dt: The datetime object.
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
Unix timestamp from the passed datetime object.
|
|
59
|
+
"""
|
|
60
|
+
return int(dt.timestamp())
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def to_unix_ms(dt: datetime) -> int:
|
|
64
|
+
"""Converts datetime objects into Unix millisecond timestamps.
|
|
65
|
+
|
|
66
|
+
This is a convenience method.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
dt: The datetime object.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
Unix millisecond timestamp from the passed datetime object.
|
|
73
|
+
"""
|
|
74
|
+
return int(dt.timestamp() * 1e3)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def to_unix_us(dt: datetime) -> int:
|
|
78
|
+
"""Converts datetime objects into Unix microsecond timestamps.
|
|
79
|
+
|
|
80
|
+
This is a convenience method.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
dt: The datetime object.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
Unix microsecond timestamp from the passed datetime object.
|
|
87
|
+
"""
|
|
88
|
+
return int(dt.timestamp() * 1e6)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def to_unix_ns(dt: datetime) -> int:
|
|
92
|
+
"""Converts datetime objects into Unix nanosecond timestamps.
|
|
93
|
+
|
|
94
|
+
This is a convenience method.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
dt: The datetime object.
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
Unix nanosecond timestamp from the passed datetime object.
|
|
101
|
+
"""
|
|
102
|
+
return to_unix_us(dt) * 1000
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def from_unix(ts: float) -> datetime:
|
|
106
|
+
"""Converts Unix timestamps to aware datetime objects in UTC.
|
|
107
|
+
|
|
108
|
+
This is a convenience method.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
ts: The Unix timestamp.
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
Datetime object from the passed timestamp.
|
|
115
|
+
"""
|
|
116
|
+
return _calculate_timestamp(ts)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def from_unix_ms(ts: float) -> datetime:
|
|
120
|
+
"""Converts Unix timestamps in milliseconds to aware datetime objects in UTC.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
ts: The Unix timestamp in milliseconds.
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
Datetime object from the passed timestamp.
|
|
127
|
+
"""
|
|
128
|
+
return from_unix(float(ts) * 1e-3)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def from_unix_us(ts: float) -> datetime:
|
|
132
|
+
"""Converts Unix timestamps in microseconds to aware datetime objects in UTC.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
ts: The Unix timestamp in microseconds.
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
Datetime object from the passed timestamp.
|
|
139
|
+
"""
|
|
140
|
+
return from_unix(float(ts) * 1e-6)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def from_unix_ns(ts: float) -> datetime:
|
|
144
|
+
"""Converts Unix timestamps in nanoseconds to aware datetime objects in UTC.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
ts: The Unix timestamp in nanoseconds.
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
Datetime object from the passed timestamp.
|
|
151
|
+
"""
|
|
152
|
+
return from_unix(float(ts) * 1e-9)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def xfstimestamp(seconds: int, nano: int) -> datetime:
|
|
156
|
+
"""Converts XFS timestamps to aware datetime objects in UTC.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
seconds: The XFS timestamp seconds component
|
|
160
|
+
nano: The XFS timestamp nano seconds component
|
|
161
|
+
Returns:
|
|
162
|
+
Datetime object from the passed timestamp.
|
|
163
|
+
"""
|
|
164
|
+
return _calculate_timestamp(float(seconds) + (1e-9 * nano))
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
ufstimestamp = xfstimestamp
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def wintimestamp(ts: int | tuple[int, int]) -> datetime:
|
|
171
|
+
"""Converts Windows ``FILETIME`` timestamps to aware datetime objects in UTC.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
ts: The Windows timestamp integer or a tuple of integers (``dwLowDateTime``, ``dwHighDateTime``)
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
Datetime object from the passed timestamp.
|
|
178
|
+
|
|
179
|
+
Resources:
|
|
180
|
+
- https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
|
|
181
|
+
"""
|
|
182
|
+
if isinstance(ts, tuple):
|
|
183
|
+
if len(ts) != 2:
|
|
184
|
+
raise ValueError(f"Expected (dwLowDateTime, dwHighDateTime) tuple but got {ts!r}")
|
|
185
|
+
ts = (ts[1] << 32) + ts[0]
|
|
186
|
+
|
|
187
|
+
return _calculate_timestamp(float(ts) * 1e-7 - 11_644_473_600) # Thanks FireEye
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def oatimestamp(ts: float) -> datetime:
|
|
191
|
+
"""Converts OLE Automation timestamps to aware datetime objects in UTC.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
ts: The OLE Automation timestamp.
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
Datetime object from the passed timestamp.
|
|
198
|
+
"""
|
|
199
|
+
if not isinstance(ts, float):
|
|
200
|
+
# Convert from int to float
|
|
201
|
+
(ts,) = struct.unpack("<d", struct.pack("<Q", ts & 0xFFFFFFFFFFFFFFFF))
|
|
202
|
+
return _calculate_timestamp((ts - 25569) * 86400)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def webkittimestamp(ts: int) -> datetime:
|
|
206
|
+
"""Converts WebKit timestamps to aware datetime objects in UTC.
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
ts: The WebKit timestamp.
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
Datetime object from the passed timestamp.
|
|
213
|
+
"""
|
|
214
|
+
return _calculate_timestamp(float(ts) * 1e-6 - 11644473600)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def cocoatimestamp(ts: int) -> datetime:
|
|
218
|
+
"""Converts Apple Cocoa Core Data timestamps to aware datetime objects in UTC.
|
|
219
|
+
|
|
220
|
+
Args:
|
|
221
|
+
ts: The Apple Cocoa Core Data timestamp.
|
|
222
|
+
|
|
223
|
+
Returns:
|
|
224
|
+
Datetime object from the passed timestamp.
|
|
225
|
+
"""
|
|
226
|
+
return _calculate_timestamp(float(ts) + 978307200)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def uuid1timestamp(ts: int) -> datetime:
|
|
230
|
+
"""Converts UUID version 1 timestamps to aware datetime objects in UTC.
|
|
231
|
+
|
|
232
|
+
UUID v1 timestamps have an epoch of 1582-10-15 00:00:00.
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
ts: The UUID version 1 timestamp
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
Datetime object from the passed timestamp.
|
|
239
|
+
"""
|
|
240
|
+
return _calculate_timestamp(float(ts) * 1e-7 - 12219292800)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
DOS_EPOCH_YEAR = 1980
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def dostimestamp(ts: int, centiseconds: int = 0, swap: bool = False) -> datetime:
|
|
247
|
+
"""Converts MS-DOS timestamps to naive datetime objects.
|
|
248
|
+
|
|
249
|
+
MS-DOS timestamps are recorded in local time, so we leave it up to the caller to add optional timezone information.
|
|
250
|
+
|
|
251
|
+
References:
|
|
252
|
+
- https://web.archive.org/web/20180311003959/http://www.vsft.com/hal/dostime.htm
|
|
253
|
+
|
|
254
|
+
Args:
|
|
255
|
+
ts: MS-DOS timestamp
|
|
256
|
+
centiseconds: Optional ExFAT centisecond offset. Yes centisecond...
|
|
257
|
+
swap: Optional swap flag if date and time bytes are swapped.
|
|
258
|
+
|
|
259
|
+
Returns:
|
|
260
|
+
Datetime object from the passed timestamp.
|
|
261
|
+
"""
|
|
262
|
+
# MS-DOS Date Time Format is actually 2 UINT16_T's first 16 bits are the time, second 16 bits are date
|
|
263
|
+
# the year is an offset of the MS-DOS epoch year, which is 1980
|
|
264
|
+
|
|
265
|
+
if swap:
|
|
266
|
+
year = ((ts >> 9) & 0x7F) + DOS_EPOCH_YEAR
|
|
267
|
+
month = (ts >> 5) & 0x0F
|
|
268
|
+
day = ts & 0x1F
|
|
269
|
+
|
|
270
|
+
hours = (ts >> 27) & 0x1F
|
|
271
|
+
minutes = (ts >> 21) & 0x3F
|
|
272
|
+
seconds = ((ts >> 16) & 0x1F) * 2
|
|
273
|
+
else: # non-swapped way
|
|
274
|
+
year = ((ts >> 25) & 0x7F) + DOS_EPOCH_YEAR
|
|
275
|
+
month = (ts >> 21) & 0x0F
|
|
276
|
+
day = (ts >> 16) & 0x1F
|
|
277
|
+
|
|
278
|
+
hours = (ts >> 11) & 0x1F
|
|
279
|
+
minutes = (ts >> 5) & 0x3F
|
|
280
|
+
seconds = (ts & 0x1F) * 2
|
|
281
|
+
|
|
282
|
+
# Note that according to the standard, centiseconds can be at most 199, so
|
|
283
|
+
# extra_seconds will be at most 1.
|
|
284
|
+
extra_seconds, centiseconds = divmod(centiseconds, 100)
|
|
285
|
+
microseconds = centiseconds * 10000
|
|
286
|
+
|
|
287
|
+
return datetime( # noqa: DTZ001
|
|
288
|
+
year,
|
|
289
|
+
month or 1,
|
|
290
|
+
day or 1,
|
|
291
|
+
hours,
|
|
292
|
+
minutes,
|
|
293
|
+
seconds + extra_seconds,
|
|
294
|
+
microseconds,
|
|
295
|
+
)
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import struct
|
|
4
|
+
import sys
|
|
5
|
+
from typing import TYPE_CHECKING, Any
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from collections.abc import Iterator
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def xmemoryview(view: bytes, format: str) -> memoryview | _xmemoryview:
|
|
12
|
+
"""Cast a memoryview to the specified format, including endianness.
|
|
13
|
+
|
|
14
|
+
The regular ``memoryview.cast()`` method only supports host endianness. While that should be fine 99% of the time
|
|
15
|
+
(most of the world runs on little endian systems), we'd rather it be fine 100% of the time. This utility method
|
|
16
|
+
ensures that by transparently converting between endianness if it doesn't match the host endianness.
|
|
17
|
+
|
|
18
|
+
If the host endianness matches the requested endianness, this simply returns a regular ``memoryview.cast()``.
|
|
19
|
+
|
|
20
|
+
See ``memoryview.cast()`` for more details on what that actually does.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
view: The bytes object or memoryview to cast.
|
|
24
|
+
format: The format to cast to in ``struct`` format syntax.
|
|
25
|
+
|
|
26
|
+
Raises:
|
|
27
|
+
ValueError: If the format is invalid.
|
|
28
|
+
TypeError: If the view is of an invalid type.
|
|
29
|
+
"""
|
|
30
|
+
if len(format) != 2:
|
|
31
|
+
raise ValueError("Invalid format specification")
|
|
32
|
+
|
|
33
|
+
if isinstance(view, bytes | bytearray):
|
|
34
|
+
view = memoryview(view)
|
|
35
|
+
|
|
36
|
+
if not isinstance(view, memoryview):
|
|
37
|
+
raise TypeError("view must be a memoryview, bytes or bytearray object")
|
|
38
|
+
|
|
39
|
+
endian = format[0]
|
|
40
|
+
view = view.cast(format[1])
|
|
41
|
+
|
|
42
|
+
if (
|
|
43
|
+
endian in ("@", "=")
|
|
44
|
+
or (sys.byteorder == "little" and endian == "<")
|
|
45
|
+
or (sys.byteorder == "big" and endian in (">", "!"))
|
|
46
|
+
):
|
|
47
|
+
# Native endianness, don't need to do anything
|
|
48
|
+
return view
|
|
49
|
+
|
|
50
|
+
# Non-native endianness
|
|
51
|
+
return _xmemoryview(view, format)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class _xmemoryview: # noqa: N801
|
|
55
|
+
"""Wrapper for memoryview that converts between host and a different destination endianness.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
view: The (already casted) memoryview to wrap.
|
|
59
|
+
format: The format to convert to.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
def __init__(self, view: memoryview, format: str):
|
|
63
|
+
self._format = format
|
|
64
|
+
|
|
65
|
+
fmt = format[1]
|
|
66
|
+
self._view = view
|
|
67
|
+
self._struct_frm = struct.Struct(f"={fmt}")
|
|
68
|
+
self._struct_to = struct.Struct(format)
|
|
69
|
+
|
|
70
|
+
def tolist(self) -> list[int]:
|
|
71
|
+
return self._convert_from_native(self._view.tolist())
|
|
72
|
+
|
|
73
|
+
def _convert_from_native(self, value: list[int] | int) -> int:
|
|
74
|
+
if isinstance(value, list):
|
|
75
|
+
endian = self._format[0]
|
|
76
|
+
fmt = self._format[1]
|
|
77
|
+
pck = f"{len(value)}{fmt}"
|
|
78
|
+
return list(struct.unpack(f"{endian}{pck}", struct.pack(f"={pck}", *value)))
|
|
79
|
+
return self._struct_to.unpack(self._struct_frm.pack(value))[0]
|
|
80
|
+
|
|
81
|
+
def _convert_to_native(self, value: list[int] | int) -> int:
|
|
82
|
+
if isinstance(value, list):
|
|
83
|
+
endian = self._format[0]
|
|
84
|
+
fmt = self._format[1]
|
|
85
|
+
pck = f"{len(value)}{fmt}"
|
|
86
|
+
return list(struct.unpack(f"={pck}", struct.pack(f"{endian}{pck}", *value)))
|
|
87
|
+
return self._struct_frm.unpack(self._struct_to.pack(value))[0]
|
|
88
|
+
|
|
89
|
+
def __getitem__(self, idx: int | slice) -> int | bytes:
|
|
90
|
+
value = self._view[idx]
|
|
91
|
+
if isinstance(idx, int):
|
|
92
|
+
return self._convert_from_native(value)
|
|
93
|
+
if isinstance(idx, slice):
|
|
94
|
+
return _xmemoryview(self._view[idx], self._format)
|
|
95
|
+
|
|
96
|
+
raise TypeError("Invalid index type")
|
|
97
|
+
|
|
98
|
+
def __setitem__(self, idx: int | slice, value: list[int] | int) -> None:
|
|
99
|
+
if isinstance(idx, int | slice):
|
|
100
|
+
self._view[idx] = self._convert_to_native(value)
|
|
101
|
+
else:
|
|
102
|
+
raise TypeError("Invalid index type")
|
|
103
|
+
|
|
104
|
+
def __len__(self) -> int:
|
|
105
|
+
return len(self._view)
|
|
106
|
+
|
|
107
|
+
def __eq__(self, other: memoryview | _xmemoryview) -> bool:
|
|
108
|
+
if isinstance(other, _xmemoryview):
|
|
109
|
+
other = other._view
|
|
110
|
+
return self._view.__eq__(other)
|
|
111
|
+
|
|
112
|
+
def __iter__(self) -> Iterator[int]:
|
|
113
|
+
for value in self._view:
|
|
114
|
+
yield self._convert_from_native(value)
|
|
115
|
+
|
|
116
|
+
def __getattr__(self, attr: str) -> Any:
|
|
117
|
+
return getattr(self._view, attr)
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dissect.util
|
|
3
|
+
Version: 3.23.dev12
|
|
4
|
+
Summary: A Dissect module implementing various utility functions for the other Dissect modules
|
|
5
|
+
Author-email: Dissect Team <dissect@fox-it.com>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: homepage, https://dissect.tools
|
|
8
|
+
Project-URL: documentation, https://docs.dissect.tools/en/latest/projects/dissect.util
|
|
9
|
+
Project-URL: repository, https://github.com/fox-it/dissect.util
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Information Technology
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Topic :: Internet :: Log Analysis
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
18
|
+
Classifier: Topic :: Security
|
|
19
|
+
Classifier: Topic :: Utilities
|
|
20
|
+
Requires-Python: >=3.10.0
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
License-File: COPYRIGHT
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
|
|
26
|
+
# dissect.util
|
|
27
|
+
|
|
28
|
+
A Dissect module implementing various utility functions for the other Dissect modules. For more information, please see
|
|
29
|
+
[the documentation](https://docs.dissect.tools/en/latest/projects/dissect.util/index.html).
|
|
30
|
+
|
|
31
|
+
## Requirements
|
|
32
|
+
|
|
33
|
+
This project is part of the Dissect framework and requires Python.
|
|
34
|
+
|
|
35
|
+
Information on the supported Python versions can be found in the Getting Started section of [the documentation](https://docs.dissect.tools/en/latest/index.html#getting-started).
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
`dissect.util` is available on [PyPI](https://pypi.org/project/dissect.util/).
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install dissect.util
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`dissect.util` includes both a pure Python implementation as well as a faster native Rust implementation of the LZ4 and LZO decompression algorithms.
|
|
46
|
+
Pre-build wheels are available for most common platforms and the native implementation will automatically be used.
|
|
47
|
+
In the rare case that a pre-build wheel is not available, the pure Python implementation will automatically be used instead.
|
|
48
|
+
If you wish to build your own wheel in the case a pre-build one is not available for your platform, you can do so by running the following command:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
tox -e build-native
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Note that you'll need to bring your own Rust toolchain for the target platform you wish to build a wheel for. For example, using [rustup](https://rustup.rs).
|
|
55
|
+
|
|
56
|
+
## Build and test instructions
|
|
57
|
+
|
|
58
|
+
This project uses `tox` to build source and wheel distributions. Run the following command from the root folder to build
|
|
59
|
+
these:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
tox -e build
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The build artifacts can be found in the `dist/` directory.
|
|
66
|
+
|
|
67
|
+
`tox` is also used to run linting and unit tests in a self-contained environment. To run both linting and unit tests
|
|
68
|
+
using the default installed Python version, run:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
tox
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
For a more elaborate explanation on how to build and test the project, please see [the
|
|
75
|
+
documentation](https://docs.dissect.tools/en/latest/contributing/tooling.html).
|
|
76
|
+
|
|
77
|
+
## Contributing
|
|
78
|
+
|
|
79
|
+
The Dissect project encourages any contribution to the codebase. To make your contribution fit into the project, please
|
|
80
|
+
refer to [the development guide](https://docs.dissect.tools/en/latest/contributing/developing.html).
|
|
81
|
+
|
|
82
|
+
## Copyright and license
|
|
83
|
+
|
|
84
|
+
Dissect is released as open source by Fox-IT (<https://www.fox-it.com>) part of NCC Group Plc
|
|
85
|
+
(<https://www.nccgroup.com>).
|
|
86
|
+
|
|
87
|
+
Developed by the Dissect Team (<dissect@fox-it.com>) and made available at <https://github.com/fox-it/dissect>.
|
|
88
|
+
|
|
89
|
+
License terms: Apache License 2.0 (<https://www.apache.org/licenses/LICENSE-2.0>). For more information, see the LICENSE file.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
dissect/util/__init__.py,sha256=2EmJK2xNRhU4r1ewXiqqNI5fb5ScklZrV5buMtwFoO8,321
|
|
2
|
+
dissect/util/_build.py,sha256=oKs1ddUIdmhGC5BmtRZCdWdFpJv6mkubjQLSBfp4LSo,642
|
|
3
|
+
dissect/util/_native.pypy311-pp73-win_amd64.pyd,sha256=R-0BxXl55Uh5vwMAz7SvR8c_w9WhxVPg6agnXecSLDA,246272
|
|
4
|
+
dissect/util/cpio.py,sha256=D9FUMR-cxdyg1Sscry5PsGz6RPFcR5jDjx9FVBZxUSI,7802
|
|
5
|
+
dissect/util/exceptions.py,sha256=Jbb9aXOQMp1-z_5mReptEZ9dNFbGzS3iiZ6d83Xu53U,81
|
|
6
|
+
dissect/util/ldap.py,sha256=P1tIkEh64UeiD6j3bEU_-w_V5yB7n7W-yV-2fUB7TDQ,7601
|
|
7
|
+
dissect/util/plist.py,sha256=NJzPwgqm-Z2FZvs1_5sG5orRWOcTj94RLS6u4bbpLpg,4707
|
|
8
|
+
dissect/util/sid.py,sha256=OV-jEJxKcgrtqaMKL8KTwzJ-Z1ihnczKKN1gNrtVKP0,1608
|
|
9
|
+
dissect/util/stream.py,sha256=VWsg9KPqgntYwLamkm6f55CaOTDs3JZwSot7vzrVA9Q,23784
|
|
10
|
+
dissect/util/ts.py,sha256=iDSIXpp9zmKGLTUEIBrn_FVTQlUiV-6-9S2PwusqFg4,8498
|
|
11
|
+
dissect/util/xmemoryview.py,sha256=C2_3hGSMHWgorQunnx7fy2Qo2ZVCstQgZR7RO4S_6_0,4202
|
|
12
|
+
dissect/util/_native/__init__.pyi,sha256=UaRPrAxT1xeI8C9CWWtSCVgn_ln54V9BlWEr0oqKK7k,89
|
|
13
|
+
dissect/util/_native/compression/__init__.pyi,sha256=0Lf8MLWvxxU6FvPO-7v7jHP-1w4I9y17ekCVWuoQ4ls,83
|
|
14
|
+
dissect/util/_native/compression/lz4.pyi,sha256=V1ref_7dBUc1GQRuPeUnRooTuPUG2kiyKTuPqyJuZjY,184
|
|
15
|
+
dissect/util/_native/compression/lzo.pyi,sha256=-Rpuc-O5qBOeUBIu3FpqkX4ltj5OUmtmcu7_l1IpODM,123
|
|
16
|
+
dissect/util/_native/hash/__init__.py,sha256=ZX-FQAxBHhLiA5joncU5j2SxZNMVqv0UU4QCMJFrS0M,70
|
|
17
|
+
dissect/util/_native/hash/crc32c.py,sha256=zZIqijdLzz6EOcs5qft3Ku0My2vgq7tZsm7qIocxgYE,100
|
|
18
|
+
dissect/util/compression/__init__.py,sha256=hESjRzmD37Rg80d2ICRwBQTL2XMPaBUZjRPMP7lsnsY,1326
|
|
19
|
+
dissect/util/compression/lz4.py,sha256=AzzuEUAgscvUqlnWZd2hiOaTh8Z7Rx-gWjrWukwe5y4,2846
|
|
20
|
+
dissect/util/compression/lzbitmap.py,sha256=NgwrwkmZtUHPZm61ru3Hf5Yd9xTRQf07brvf1PdXItM,4630
|
|
21
|
+
dissect/util/compression/lzfse.py,sha256=MBG9fSBrcKcw7950DhsGpS_96UVL2F2dsfiaxXxVvPg,16572
|
|
22
|
+
dissect/util/compression/lznt1.py,sha256=xOmlEwOk9D63CwWcly3JLPQuvrsJYgg4I2qk2Lupf64,2775
|
|
23
|
+
dissect/util/compression/lzo.py,sha256=a6JRP-5c94MBglbbOv98z--n69JRyR5itZzd-nmAK2A,3865
|
|
24
|
+
dissect/util/compression/lzvn.py,sha256=jKcjofse-elDPji8Bh21tdEJEHTYlDfO0q0tXsy2axk,8208
|
|
25
|
+
dissect/util/compression/lzxpress.py,sha256=Uf5yZGCq9dpm07_x-Ak8PNtSJQyZ8-Y5Oi6ZCJ8cZg4,2564
|
|
26
|
+
dissect/util/compression/lzxpress_huffman.py,sha256=3sFzO7zttpj0aXAdIb5uay3iVpRFI5AN9nnAIbl_crM,4867
|
|
27
|
+
dissect/util/compression/sevenbit.py,sha256=JB1cHOQJl6iZAU7xEKQyECKh2Fugtqg293bYDCy7b-I,1587
|
|
28
|
+
dissect/util/compression/xz.py,sha256=dPz_bGejRdXs6tI6qPS9wUSytCrVloC-7V8dC48IAjA,3891
|
|
29
|
+
dissect/util/encoding/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
30
|
+
dissect/util/encoding/surrogateescape.py,sha256=ycL9JF_XW6zBYU6T48WRvdgJxCWEltO2suRd2b4nq6g,513
|
|
31
|
+
dissect/util/hash/__init__.py,sha256=4ECmH1rT25Kjw0Bd8CcE3NdxKR9qQNVi-XyEliZXy6M,767
|
|
32
|
+
dissect/util/hash/crc32.py,sha256=5o_7Xbzh3MN17Aj51jZfRW1f30YLsBKGJSEPQcIVJ_Q,2035
|
|
33
|
+
dissect/util/hash/crc32c.py,sha256=vtdb5dP9DKcPp__64e74ns6bbV2gPhPtR9s0frxcamg,3978
|
|
34
|
+
dissect/util/hash/jenkins.py,sha256=JWmFzOAy7TL0DiFTi8FYdQsNrLEmqDlE2fCFXavioPs,3629
|
|
35
|
+
dissect/util/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
36
|
+
dissect/util/tools/dump_nskeyedarchiver.py,sha256=D-fyHtRznOaxAXXHfX1zQV6O9cv1-4adenkZ11yFZmg,1515
|
|
37
|
+
dissect_util-3.23.dev12.dist-info/licenses/COPYRIGHT,sha256=S_KncaHsPtWbl45lU6Af9AXZKYkbGqYksHkTMwutG8o,318
|
|
38
|
+
dissect_util-3.23.dev12.dist-info/licenses/LICENSE,sha256=p-DRQtYicr7hWv7iyiM44c2B6-b3BMu8N5H5s0h82ts,11542
|
|
39
|
+
dissect_util-3.23.dev12.dist-info/METADATA,sha256=ewOw6Z7UFG9ugkI5HIt2cp_5XvIetfJoHS2hhVm0yow,3704
|
|
40
|
+
dissect_util-3.23.dev12.dist-info/WHEEL,sha256=mDTLi-lcRey7JEenATTEcfpRSN3DewF3dJqTvlZbDhU,108
|
|
41
|
+
dissect_util-3.23.dev12.dist-info/entry_points.txt,sha256=3mwSDD1MUdj0nnTcl2qYFMeu6KYMTycUQS0rlp5CQHI,86
|
|
42
|
+
dissect_util-3.23.dev12.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
|
|
43
|
+
dissect_util-3.23.dev12.dist-info/RECORD,,
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
Dissect is released as open source by Fox-IT (https://www.fox-it.com) part of NCC Group Plc (https://www.nccgroup.com)
|
|
2
|
+
|
|
3
|
+
Developed by the Dissect Team (dissect@fox-it.com) and made available at https://github.com/fox-it/dissect.util
|
|
4
|
+
|
|
5
|
+
License terms: Apache License 2.0 (https://www.apache.org/licenses/LICENSE-2.0)
|