dissect.util 3.23.dev6__tar.gz → 3.23.dev8__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.

Potentially problematic release.


This version of dissect.util might be problematic. Click here for more details.

Files changed (89) hide show
  1. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/PKG-INFO +1 -1
  2. dissect_util-3.23.dev8/dissect/util/ldap.py +237 -0
  3. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect.util.egg-info/PKG-INFO +1 -1
  4. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect.util.egg-info/SOURCES.txt +14 -2
  5. dissect_util-3.23.dev8/tests/compression/__init__.py +0 -0
  6. dissect_util-3.23.dev8/tests/compression/test_lz4.py +77 -0
  7. dissect_util-3.23.dev8/tests/compression/test_lzbitmap.py +89 -0
  8. dissect_util-3.23.dev8/tests/compression/test_lzfse.py +75 -0
  9. dissect_util-3.23.dev8/tests/compression/test_lznt1.py +260 -0
  10. dissect_util-3.23.dev8/tests/compression/test_lzo.py +237 -0
  11. dissect_util-3.23.dev8/tests/compression/test_lzvn.py +81 -0
  12. dissect_util-3.23.dev8/tests/compression/test_lzxpress.py +75 -0
  13. dissect_util-3.23.dev8/tests/compression/test_lzxpress_huffman.py +95 -0
  14. dissect_util-3.23.dev8/tests/compression/test_sevenbit.py +46 -0
  15. dissect_util-3.23.dev8/tests/compression/test_xz.py +24 -0
  16. dissect_util-3.23.dev8/tests/test_ldap.py +652 -0
  17. dissect_util-3.23.dev6/tests/test_compression.py +0 -501
  18. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/.devcontainer/devcontainer.json +0 -0
  19. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/COPYRIGHT +0 -0
  20. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/LICENSE +0 -0
  21. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/MANIFEST.in +0 -0
  22. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/README.md +0 -0
  23. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/__init__.py +0 -0
  24. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/_build.py +0 -0
  25. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/_native/__init__.pyi +0 -0
  26. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/_native/compression/__init__.pyi +0 -0
  27. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/_native/compression/lz4.pyi +0 -0
  28. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/_native/compression/lzo.pyi +0 -0
  29. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/_native/hash/__init__.py +0 -0
  30. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/_native/hash/crc32c.py +0 -0
  31. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/_native.src/Cargo.lock +0 -0
  32. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/_native.src/Cargo.toml +0 -0
  33. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/_native.src/src/compression/lz4.rs +0 -0
  34. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/_native.src/src/compression/lzo.rs +0 -0
  35. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/_native.src/src/compression.rs +0 -0
  36. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/_native.src/src/hash/crc32c.rs +0 -0
  37. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/_native.src/src/hash.rs +0 -0
  38. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/_native.src/src/lib.rs +0 -0
  39. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/compression/__init__.py +0 -0
  40. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/compression/lz4.py +0 -0
  41. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/compression/lzbitmap.py +0 -0
  42. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/compression/lzfse.py +0 -0
  43. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/compression/lznt1.py +0 -0
  44. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/compression/lzo.py +0 -0
  45. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/compression/lzvn.py +0 -0
  46. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/compression/lzxpress.py +0 -0
  47. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/compression/lzxpress_huffman.py +0 -0
  48. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/compression/sevenbit.py +0 -0
  49. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/compression/xz.py +0 -0
  50. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/cpio.py +0 -0
  51. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/encoding/__init__.py +0 -0
  52. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/encoding/surrogateescape.py +0 -0
  53. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/exceptions.py +0 -0
  54. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/feature.py +0 -0
  55. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/hash/__init__.py +0 -0
  56. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/hash/crc32c.py +0 -0
  57. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/hash/jenkins.py +0 -0
  58. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/plist.py +0 -0
  59. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/sid.py +0 -0
  60. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/stream.py +0 -0
  61. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/tools/__init__.py +0 -0
  62. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/tools/dump_nskeyedarchiver.py +0 -0
  63. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/ts.py +0 -0
  64. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect/util/xmemoryview.py +0 -0
  65. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect.util.egg-info/dependency_links.txt +0 -0
  66. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect.util.egg-info/entry_points.txt +0 -0
  67. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/dissect.util.egg-info/top_level.txt +0 -0
  68. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/pyproject.toml +0 -0
  69. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/setup.cfg +0 -0
  70. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/tests/__init__.py +0 -0
  71. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/tests/_data/bin.cpio.gz +0 -0
  72. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/tests/_data/crc.cpio.gz +0 -0
  73. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/tests/_data/hpbin.cpio.gz +0 -0
  74. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/tests/_data/hpodc.cpio.gz +0 -0
  75. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/tests/_data/newc.cpio.gz +0 -0
  76. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/tests/_data/odc.cpio.gz +0 -0
  77. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/tests/_docs/Makefile +0 -0
  78. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/tests/_docs/conf.py +0 -0
  79. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/tests/_docs/index.rst +0 -0
  80. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/tests/conftest.py +0 -0
  81. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/tests/test_cpio.py +0 -0
  82. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/tests/test_feature.py +0 -0
  83. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/tests/test_hash.py +0 -0
  84. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/tests/test_plist.py +0 -0
  85. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/tests/test_sid.py +0 -0
  86. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/tests/test_stream.py +0 -0
  87. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/tests/test_ts.py +0 -0
  88. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/tests/test_xmemoryview.py +0 -0
  89. {dissect_util-3.23.dev6 → dissect_util-3.23.dev8}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dissect.util
3
- Version: 3.23.dev6
3
+ Version: 3.23.dev8
4
4
  Summary: A Dissect module implementing various utility functions for the other Dissect modules
5
5
  Author-email: Dissect Team <dissect@fox-it.com>
6
6
  License-Expression: Apache-2.0
@@ -0,0 +1,237 @@
1
+ from __future__ import annotations
2
+
3
+ import operator
4
+ import re
5
+ from enum import Enum
6
+
7
+ from dissect.util.exceptions import Error
8
+
9
+
10
+ class InvalidQueryError(Error):
11
+ pass
12
+
13
+
14
+ class LogicalOperator(Enum):
15
+ AND = "&"
16
+ OR = "|"
17
+ NOT = "!"
18
+
19
+
20
+ _LOGICAL_OPERATORS = tuple(op.value for op in LogicalOperator)
21
+
22
+
23
+ class ComparisonOperator(Enum):
24
+ GE = ">="
25
+ LE = "<="
26
+ GT = ">"
27
+ LT = "<"
28
+ EQ = "="
29
+ APPROX = "~="
30
+ BIT = ":="
31
+ EXTENDED = ":"
32
+
33
+
34
+ _NORMAL_COMPARISON_OPERATORS = [op for op in ComparisonOperator if op != ComparisonOperator.EXTENDED]
35
+ _SORTED_COMPARISON_OPERATORS = sorted(_NORMAL_COMPARISON_OPERATORS, key=lambda op: len(op.value), reverse=True)
36
+
37
+ _RE_EXTENDED = re.compile(r"(.+?):(.+?):=(.+)?")
38
+
39
+
40
+ class SearchFilter:
41
+ """Represents an LDAP search filter (simple or nested).
42
+
43
+ Args:
44
+ query: The LDAP search filter string.
45
+ """
46
+
47
+ def __init__(self, query: str) -> None:
48
+ self.query: str = query
49
+
50
+ self.children: list[SearchFilter] = []
51
+ self.operator: LogicalOperator | ComparisonOperator | None = None
52
+ self.attribute: str | None = None
53
+ self.value: str | None = None
54
+ self._extended_rule: str | None = None
55
+
56
+ _validate_syntax(query)
57
+
58
+ if query[1:-1].startswith(_LOGICAL_OPERATORS):
59
+ self._parse_nested()
60
+ else:
61
+ self._parse_simple()
62
+
63
+ def __repr__(self) -> str:
64
+ if self.is_nested():
65
+ return f"<SearchFilter nested operator={self.operator.value!r} children={self.children}>"
66
+ return f"<SearchFilter attribute={self.attribute!r} operator={self.operator.value!r} value={self.value}>"
67
+
68
+ @classmethod
69
+ def parse(cls, query: str, optimize: bool = True) -> SearchFilter:
70
+ """Parse an LDAP query into a filter object, with optional optimization."""
71
+ result = cls(query)
72
+ if optimize:
73
+ return optimize_ldap_query(result)[0]
74
+ return result
75
+
76
+ def is_nested(self) -> bool:
77
+ """Return whether the filter is nested (i.e., contains logical operators and child filters)."""
78
+ return isinstance(self.operator, LogicalOperator)
79
+
80
+ def format(self) -> str:
81
+ """Format the search filter back into an LDAP query string."""
82
+ if self.is_nested():
83
+ childs = "".join([child.format() for child in self.children])
84
+ return f"({self.operator.value}{childs})"
85
+
86
+ if self.operator == ComparisonOperator.EXTENDED:
87
+ return f"({self.attribute}:{self._extended_rule}:={self.value})"
88
+
89
+ return f"({self.attribute}{self.operator.value}{self.value})"
90
+
91
+ def _parse_simple(self) -> None:
92
+ """Parse simple filter."""
93
+ query = self.query[1:-1]
94
+
95
+ # Check for extended matching rules first
96
+ if ":" in query and (match := _RE_EXTENDED.match(query)):
97
+ self.operator = ComparisonOperator.EXTENDED
98
+ self.attribute, self._extended_rule, self.value = match.groups()
99
+ return
100
+
101
+ # Regular operator parsing
102
+ test = query
103
+ operators: list[ComparisonOperator] = []
104
+ for op in _SORTED_COMPARISON_OPERATORS:
105
+ if op.value not in test:
106
+ continue
107
+
108
+ if test.count(op.value) > 1:
109
+ raise InvalidQueryError(f"Comparison operator {op.value} found multiple times in query: {self.query}")
110
+
111
+ operators.append(op)
112
+ test = test.replace(op.value, "")
113
+
114
+ if len(operators) == 0:
115
+ raise InvalidQueryError(
116
+ f"No comparison operator found in query: {self.query}. "
117
+ f"Expected one of {[op.value for op in _NORMAL_COMPARISON_OPERATORS]}."
118
+ )
119
+
120
+ if len(operators) > 1:
121
+ raise InvalidQueryError(
122
+ f"Multiple comparison operators found in query: {self.query} -> {[o.value for o in operators]} "
123
+ f"Expected only one of {[op.value for op in _NORMAL_COMPARISON_OPERATORS]}."
124
+ )
125
+
126
+ self.operator = operators[0]
127
+ self.attribute, _, self.value = query.partition(self.operator.value)
128
+
129
+ def _parse_nested(self) -> None:
130
+ """Parse nested filter."""
131
+ query = self.query[1:-1]
132
+ self.operator = LogicalOperator(query[0])
133
+
134
+ start = 1
135
+ while start < len(query):
136
+ end = start + 1
137
+ depth = 1
138
+
139
+ while end < len(query) and depth > 0:
140
+ if query[end] == "(":
141
+ depth += 1
142
+ elif query[end] == ")":
143
+ depth -= 1
144
+ end += 1
145
+
146
+ self.children.append(SearchFilter(query[start:end]))
147
+ start = end
148
+
149
+
150
+ _ATTRIBUTE_WEIGHTS = {
151
+ "objectGUID": 1,
152
+ "distinguishedName": 1,
153
+ "sAMAccountName": 2,
154
+ "userPrincipalName": 2,
155
+ "mail": 2,
156
+ "sAMAccountType": 3,
157
+ "servicePrincipalName": 3,
158
+ "userAccountControl": 4,
159
+ "memberOf": 5,
160
+ "member": 5,
161
+ "pwdLastSet": 5,
162
+ "primaryGroupID": 6,
163
+ "whenCreated": 6,
164
+ "ou": 6,
165
+ "lastLogonTimestamp": 6,
166
+ "cn": 7,
167
+ "givenName": 7,
168
+ "name": 7,
169
+ "telephoneNumber": 7,
170
+ "objectCategory": 8,
171
+ "description": 9,
172
+ "objectClass": 10,
173
+ }
174
+
175
+
176
+ def optimize_ldap_query(query: SearchFilter) -> tuple[SearchFilter, int]:
177
+ """Optimize an LDAP query in-place.
178
+
179
+ Removes redundant conditions and sorts filters and conditions based on how specific they are.
180
+
181
+ Args:
182
+ query: The LDAP query to optimize.
183
+
184
+ Returns:
185
+ A tuple containing the optimized LDAP query and its weight.
186
+ """
187
+ # Simplify single-child AND/OR
188
+ if query.is_nested() and len(query.children) == 1 and query.operator in (LogicalOperator.AND, LogicalOperator.OR):
189
+ return optimize_ldap_query(query.children[0])
190
+
191
+ # Sort nested children by weight
192
+ if query.is_nested() and len(query.children) > 1:
193
+ children = sorted((optimize_ldap_query(child) for child in query.children), key=operator.itemgetter(1))
194
+
195
+ query.children = [child for child, _ in children]
196
+ query.query = query.format()
197
+
198
+ return query, max(weight for _, weight in children)
199
+
200
+ # Handle NOT
201
+ if query.is_nested() and len(query.children) == 1 and query.operator == LogicalOperator.NOT:
202
+ child, weight = optimize_ldap_query(query.children[0])
203
+
204
+ query.children[0] = child
205
+ query.query = query.format()
206
+
207
+ return query, weight
208
+
209
+ # Base case: simple filter
210
+ if not query.is_nested():
211
+ return query, _ATTRIBUTE_WEIGHTS.get(query.attribute, max(_ATTRIBUTE_WEIGHTS.values()))
212
+
213
+ return query, max(_ATTRIBUTE_WEIGHTS.values())
214
+
215
+
216
+ def _validate_syntax(query: str) -> None:
217
+ """Validate basic LDAP query syntax.
218
+
219
+ Args:
220
+ query: The LDAP query to validate.
221
+ """
222
+ if not query:
223
+ raise InvalidQueryError("Empty query")
224
+
225
+ if not query.startswith("(") or not query.endswith(")"):
226
+ raise InvalidQueryError(f"Query must be wrapped in parentheses: {query}")
227
+
228
+ if query.count("(") != query.count(")"):
229
+ raise InvalidQueryError(f"Unbalanced parentheses in query: {query}")
230
+
231
+ # Check for empty parentheses
232
+ if "()" in query:
233
+ raise InvalidQueryError(f"Empty parentheses found in query: {query}")
234
+
235
+ # Check for queries that start with double opening parentheses
236
+ if query.startswith("(("):
237
+ raise InvalidQueryError(f"Invalid query structure: {query}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dissect.util
3
- Version: 3.23.dev6
3
+ Version: 3.23.dev8
4
4
  Summary: A Dissect module implementing various utility functions for the other Dissect modules
5
5
  Author-email: Dissect Team <dissect@fox-it.com>
6
6
  License-Expression: Apache-2.0
@@ -15,6 +15,7 @@ dissect/util/_build.py
15
15
  dissect/util/cpio.py
16
16
  dissect/util/exceptions.py
17
17
  dissect/util/feature.py
18
+ dissect/util/ldap.py
18
19
  dissect/util/plist.py
19
20
  dissect/util/sid.py
20
21
  dissect/util/stream.py
@@ -54,10 +55,10 @@ dissect/util/tools/__init__.py
54
55
  dissect/util/tools/dump_nskeyedarchiver.py
55
56
  tests/__init__.py
56
57
  tests/conftest.py
57
- tests/test_compression.py
58
58
  tests/test_cpio.py
59
59
  tests/test_feature.py
60
60
  tests/test_hash.py
61
+ tests/test_ldap.py
61
62
  tests/test_plist.py
62
63
  tests/test_sid.py
63
64
  tests/test_stream.py
@@ -71,4 +72,15 @@ tests/_data/newc.cpio.gz
71
72
  tests/_data/odc.cpio.gz
72
73
  tests/_docs/Makefile
73
74
  tests/_docs/conf.py
74
- tests/_docs/index.rst
75
+ tests/_docs/index.rst
76
+ tests/compression/__init__.py
77
+ tests/compression/test_lz4.py
78
+ tests/compression/test_lzbitmap.py
79
+ tests/compression/test_lzfse.py
80
+ tests/compression/test_lznt1.py
81
+ tests/compression/test_lzo.py
82
+ tests/compression/test_lzvn.py
83
+ tests/compression/test_lzxpress.py
84
+ tests/compression/test_lzxpress_huffman.py
85
+ tests/compression/test_sevenbit.py
86
+ tests/compression/test_xz.py
File without changes
@@ -0,0 +1,77 @@
1
+ from __future__ import annotations
2
+
3
+ import hashlib
4
+ from typing import TYPE_CHECKING
5
+
6
+ import pytest
7
+
8
+ if TYPE_CHECKING:
9
+ from types import ModuleType
10
+
11
+ from pytest_benchmark.fixture import BenchmarkFixture
12
+
13
+
14
+ @pytest.mark.parametrize(
15
+ ("data", "digest"),
16
+ [
17
+ pytest.param(
18
+ "ff0c4c5a3420636f6d7072657373696f6e207465737420737472696e671b00db507472696e67",
19
+ "5ec59b1b60247178b260e145ae888c318e1fa3ee4466cf0e145de8f24c4b1501",
20
+ id="basic",
21
+ ),
22
+ pytest.param(
23
+ "ffffa94c6f72656d20697073756d20646f6c6f722073697420616d657420636f"
24
+ "6e73656374657475722061646970697363696e6720656c69742e205175697371"
25
+ "75652066617563696275732065782073617069656e2076697461652070656c6c"
26
+ "656e7465737175652073656d20706c6163657261742e20496e20696420637572"
27
+ "737573206d69207072657469756d2074656c6c7573206475697320636f6e7661"
28
+ "6c6c69732e2054656d707573206c656f2065752061656e65616e207365642064"
29
+ "69616d2075726e612074656d706f722e2050756c76696e617220766976616d75"
30
+ "73206672696e67696c6c61206c61637573206e6563206d657475732062696265"
31
+ "6e64756d20656765737461732e20496163756c6973206d61737361206e69736c"
32
+ "206d616c657375616461206c6163696e696120696e7465676572206e756e6320"
33
+ "706f73756572652e2055742068656e6472657269742073656d7065722076656c"
34
+ "20636c61737320617074656e742074616369746920736f63696f7371752e2041"
35
+ "64206c69746f726120746f727175656e742070657220636f6e75626961206e6f"
36
+ "7374726120696e636570746f732068696d656e61656f732e0a0ab701ffffffff"
37
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
38
+ "ffffffffffffffffffffffffffffffffff4550656f732e0a",
39
+ "73d3dd96ca2e2f0144a117019256d770ee7c6febeaee09b24956c723ae22b529",
40
+ id="large",
41
+ ),
42
+ ],
43
+ )
44
+ def test_lz4_decompress(lz4: ModuleType, data: str, digest: str) -> None:
45
+ assert hashlib.sha256(lz4.decompress(bytes.fromhex(data))).hexdigest() == digest
46
+
47
+
48
+ @pytest.mark.benchmark
49
+ def test_benchmark_lz4_decompress(lz4: ModuleType, benchmark: BenchmarkFixture) -> None:
50
+ buf = bytes.fromhex("ff0c4c5a3420636f6d7072657373696f6e207465737420737472696e671b00db507472696e67")
51
+ assert benchmark(lz4.decompress, buf) == b"LZ4 compression test string" * 10
52
+
53
+
54
+ @pytest.mark.benchmark
55
+ def test_benchmark_large_lz4_decompress(lz4: ModuleType, benchmark: BenchmarkFixture) -> None:
56
+ buf = bytes.fromhex(
57
+ "ffffa94c6f72656d20697073756d20646f6c6f722073697420616d657420636f"
58
+ "6e73656374657475722061646970697363696e6720656c69742e205175697371"
59
+ "75652066617563696275732065782073617069656e2076697461652070656c6c"
60
+ "656e7465737175652073656d20706c6163657261742e20496e20696420637572"
61
+ "737573206d69207072657469756d2074656c6c7573206475697320636f6e7661"
62
+ "6c6c69732e2054656d707573206c656f2065752061656e65616e207365642064"
63
+ "69616d2075726e612074656d706f722e2050756c76696e617220766976616d75"
64
+ "73206672696e67696c6c61206c61637573206e6563206d657475732062696265"
65
+ "6e64756d20656765737461732e20496163756c6973206d61737361206e69736c"
66
+ "206d616c657375616461206c6163696e696120696e7465676572206e756e6320"
67
+ "706f73756572652e2055742068656e6472657269742073656d7065722076656c"
68
+ "20636c61737320617074656e742074616369746920736f63696f7371752e2041"
69
+ "64206c69746f726120746f727175656e742070657220636f6e75626961206e6f"
70
+ "7374726120696e636570746f732068696d656e61656f732e0a0ab701ffffffff"
71
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
72
+ "ffffffffffffffffffffffffffffffffff4550656f732e0a"
73
+ )
74
+ assert (
75
+ hashlib.sha256(benchmark(lz4.decompress, buf)).hexdigest()
76
+ == "73d3dd96ca2e2f0144a117019256d770ee7c6febeaee09b24956c723ae22b529"
77
+ )
@@ -0,0 +1,89 @@
1
+ from __future__ import annotations
2
+
3
+ import hashlib
4
+ from typing import TYPE_CHECKING
5
+
6
+ import pytest
7
+
8
+ from dissect.util.compression import lzbitmap
9
+
10
+ if TYPE_CHECKING:
11
+ from pytest_benchmark.fixture import BenchmarkFixture
12
+
13
+
14
+ @pytest.mark.parametrize(
15
+ ("data", "digest"),
16
+ [
17
+ pytest.param(
18
+ "5a424d093100002b0000536d616c6c2066696c657320646f6e2774206765"
19
+ "7420636f6d7072657373656420617420616c6c2e2e2e0a060000000000",
20
+ "8c929efb5fd28b5b82385b67b408f5e775a4756d7cc6373eebddb8668343ad40",
21
+ id="uncompressed",
22
+ ),
23
+ pytest.param(
24
+ "5a424d092d0000a0000018000018000018000061616161616161617835ef"
25
+ "340f0000f10f00000000000000000000000000060000000000",
26
+ "ef56118ff333a8bfeffc346c4987a1a178762570b3eb1d704a2c1e9b3a877561",
27
+ id="small",
28
+ ),
29
+ pytest.param(
30
+ "5a424d09d80100df36002301005001007601004c6f72656d20697073756d"
31
+ "20646f6c6f722073742061657420636e7365636574757220616469706973"
32
+ "696e67656c69742e517573716566617563627520657820736170656e7661"
33
+ "6570656c6c6e6573656d6c61637261496e20696475727573206d69707269"
34
+ "74656c757364206f76616c7354656d7075206c656f7561656e6561646469"
35
+ "6d206e2074656d706f72506c6e7276697675736672696c61206c636e636d"
36
+ "657473626962656e64756d67657461732e496c696d6173206e6c6d616c75"
37
+ "64616c696e616e746567726e6e63707365722e5574206864726572697473"
38
+ "6d7072766c637373207074656e74747469736f6f73712e41646c696f7261"
39
+ "6f7175657465727562696f74726370746f686d6f732e0a0a4c0d2c341b41"
40
+ "3e26113c5f6e805b6b7c65529d967ec4b310edb922ca7b1deca5faf4434a"
41
+ "fbfa52fb8272b2ffb7016f7fcbc1b9f1373af99e3eb4e94fa9b3bafe39d3"
42
+ "6959add6f36b55eecdb59d2ec3d1d029fc0055a9cbed016111718114103f"
43
+ "480147110116011040f125f3ffffffffffffffffffffffffffffffffffff"
44
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
45
+ "ffffffffffffffff1f002cf68f57d9c576d73bfd7cd3d756000006000000"
46
+ "0000",
47
+ "73d3dd96ca2e2f0144a117019256d770ee7c6febeaee09b24956c723ae22b529",
48
+ id="large",
49
+ ),
50
+ ],
51
+ )
52
+ def test_lzbitmap_decompress(data: str, digest: str) -> None:
53
+ assert hashlib.sha256(lzbitmap.decompress(bytes.fromhex(data))).hexdigest() == digest
54
+
55
+
56
+ @pytest.mark.benchmark
57
+ def test_benchmark_lzbitmap_decompress(benchmark: BenchmarkFixture) -> None:
58
+ buf = bytes.fromhex(
59
+ "5a424d092d0000a0000018000018000018000061616161616161617835ef"
60
+ "340f0000f10f00000000000000000000000000060000000000",
61
+ )
62
+ assert benchmark(lzbitmap.decompress, buf) == b"a" * 158 + b"xa"
63
+
64
+
65
+ @pytest.mark.benchmark
66
+ def test_benchmark_large_lzbitmap_decompress(benchmark: BenchmarkFixture) -> None:
67
+ buf = bytes.fromhex(
68
+ "5a424d09d80100df36002301005001007601004c6f72656d20697073756d"
69
+ "20646f6c6f722073742061657420636e7365636574757220616469706973"
70
+ "696e67656c69742e517573716566617563627520657820736170656e7661"
71
+ "6570656c6c6e6573656d6c61637261496e20696475727573206d69707269"
72
+ "74656c757364206f76616c7354656d7075206c656f7561656e6561646469"
73
+ "6d206e2074656d706f72506c6e7276697675736672696c61206c636e636d"
74
+ "657473626962656e64756d67657461732e496c696d6173206e6c6d616c75"
75
+ "64616c696e616e746567726e6e63707365722e5574206864726572697473"
76
+ "6d7072766c637373207074656e74747469736f6f73712e41646c696f7261"
77
+ "6f7175657465727562696f74726370746f686d6f732e0a0a4c0d2c341b41"
78
+ "3e26113c5f6e805b6b7c65529d967ec4b310edb922ca7b1deca5faf4434a"
79
+ "fbfa52fb8272b2ffb7016f7fcbc1b9f1373af99e3eb4e94fa9b3bafe39d3"
80
+ "6959add6f36b55eecdb59d2ec3d1d029fc0055a9cbed016111718114103f"
81
+ "480147110116011040f125f3ffffffffffffffffffffffffffffffffffff"
82
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
83
+ "ffffffffffffffff1f002cf68f57d9c576d73bfd7cd3d756000006000000"
84
+ "0000",
85
+ )
86
+ assert (
87
+ hashlib.sha256(benchmark(lzbitmap.decompress, buf)).hexdigest()
88
+ == "73d3dd96ca2e2f0144a117019256d770ee7c6febeaee09b24956c723ae22b529"
89
+ )
@@ -0,0 +1,75 @@
1
+ from __future__ import annotations
2
+
3
+ import hashlib
4
+ from typing import TYPE_CHECKING
5
+
6
+ import pytest
7
+
8
+ from dissect.util.compression import lzfse
9
+
10
+ if TYPE_CHECKING:
11
+ from pytest_benchmark.fixture import BenchmarkFixture
12
+
13
+
14
+ @pytest.mark.parametrize(
15
+ ("data", "digest"),
16
+ [
17
+ pytest.param(
18
+ "6276786e2c01000013000000c803616263f0fff005e163060000000000000062767824",
19
+ "d9f5aeb06abebb3be3f38adec9a2e3b94228d52193be923eb4e24c9b56ee0930",
20
+ id="basic",
21
+ ),
22
+ pytest.param(
23
+ "62767832df360000a401200e000d0030b92c8bef56220070a50000003984"
24
+ "70085f00b0000000383e59c0f1090000005fc027710c0000fc031c1f03c7"
25
+ "700cc70000000000000000006c00003600000000005f07000000e7000000"
26
+ "00100060418004120000e06338f9061e8067629dacdf013e836fe041f807"
27
+ "be80fd14fc0e3fc29f704700000000000000000000000000000000000000"
28
+ "000000000000000000000000000000000000101288d24318d9f446277ac6"
29
+ "885a4b5dea360854e4c4616262d667f9f1ff53187e598fe2f5ddf7b768f4"
30
+ "bcc1f6441b9e55e0d1be84b4b91544337f11c4d0d615068c79817f5d19f2"
31
+ "09c83975cf9669b7f3d1024d9cc795e8ac449090696a7660585fac1a891c"
32
+ "40557bb46c1b62a35ab2608d574e82ba9f3956d0f811370c78d69b24240f"
33
+ "fd80ec4eccb6dc1e7f1c6f2f276a71e9c73183844c3dce83088eeed6c77c"
34
+ "3e35316f414db430fcd2e22d0c07998d601addd5907f852df080386fe69e"
35
+ "b78675198704b4bf5361caaf482e9333c6de0d46fbf87b4387fc6ac57116"
36
+ "0300000000000000000066b7fffffff3fffa3ff7ff1fd2273e1f85c5f04f"
37
+ "0f4945ab8462767824",
38
+ "73d3dd96ca2e2f0144a117019256d770ee7c6febeaee09b24956c723ae22b529",
39
+ id="large",
40
+ ),
41
+ ],
42
+ )
43
+ def test_lzfse_decompress(data: str, digest: str) -> None:
44
+ assert hashlib.sha256(lzfse.decompress(bytes.fromhex(data))).hexdigest() == digest
45
+
46
+
47
+ @pytest.mark.benchmark
48
+ def test_benchmark_lzfse_decompress(benchmark: BenchmarkFixture) -> None:
49
+ buf = bytes.fromhex("6276786e2c01000013000000c803616263f0fff005e163060000000000000062767824")
50
+ assert benchmark(lzfse.decompress, buf) == b"abc" * 100
51
+
52
+
53
+ @pytest.mark.benchmark
54
+ def test_benchmark_large_lzfse_decompress(benchmark: BenchmarkFixture) -> None:
55
+ buf = bytes.fromhex(
56
+ "62767832df360000a401200e000d0030b92c8bef56220070a50000003984"
57
+ "70085f00b0000000383e59c0f1090000005fc027710c0000fc031c1f03c7"
58
+ "700cc70000000000000000006c00003600000000005f07000000e7000000"
59
+ "00100060418004120000e06338f9061e8067629dacdf013e836fe041f807"
60
+ "be80fd14fc0e3fc29f704700000000000000000000000000000000000000"
61
+ "000000000000000000000000000000000000101288d24318d9f446277ac6"
62
+ "885a4b5dea360854e4c4616262d667f9f1ff53187e598fe2f5ddf7b768f4"
63
+ "bcc1f6441b9e55e0d1be84b4b91544337f11c4d0d615068c79817f5d19f2"
64
+ "09c83975cf9669b7f3d1024d9cc795e8ac449090696a7660585fac1a891c"
65
+ "40557bb46c1b62a35ab2608d574e82ba9f3956d0f811370c78d69b24240f"
66
+ "fd80ec4eccb6dc1e7f1c6f2f276a71e9c73183844c3dce83088eeed6c77c"
67
+ "3e35316f414db430fcd2e22d0c07998d601addd5907f852df080386fe69e"
68
+ "b78675198704b4bf5361caaf482e9333c6de0d46fbf87b4387fc6ac57116"
69
+ "0300000000000000000066b7fffffff3fffa3ff7ff1fd2273e1f85c5f04f"
70
+ "0f4945ab8462767824"
71
+ )
72
+ assert (
73
+ hashlib.sha256(benchmark(lzfse.decompress, buf)).hexdigest()
74
+ == "73d3dd96ca2e2f0144a117019256d770ee7c6febeaee09b24956c723ae22b529"
75
+ )