bencode2 0.3.28__py3-none-any.whl → 0.3.30__py3-none-any.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.
- bencode2/__decoder.py +12 -1
- bencode2/decode.cpp +33 -19
- bencode2/encode.cpp +12 -0
- {bencode2-0.3.28.dist-info → bencode2-0.3.30.dist-info}/METADATA +3 -4
- {bencode2-0.3.28.dist-info → bencode2-0.3.30.dist-info}/RECORD +7 -7
- {bencode2-0.3.28.dist-info → bencode2-0.3.30.dist-info}/WHEEL +0 -0
- {bencode2-0.3.28.dist-info → bencode2-0.3.30.dist-info}/licenses/LICENSE +0 -0
bencode2/__decoder.py
CHANGED
|
@@ -13,6 +13,8 @@ char_9: Final = ord("9")
|
|
|
13
13
|
char_dash: Final = ord("-")
|
|
14
14
|
char_colon: Final = ord(":")
|
|
15
15
|
|
|
16
|
+
_MAX_DECODE_DEPTH: Final = 4096
|
|
17
|
+
|
|
16
18
|
|
|
17
19
|
class BencodeDecodeError(ValueError):
|
|
18
20
|
"""Bencode decode error."""
|
|
@@ -28,7 +30,7 @@ class Decoder:
|
|
|
28
30
|
index: int
|
|
29
31
|
size: int
|
|
30
32
|
|
|
31
|
-
__slots__ = ("value", "index", "size")
|
|
33
|
+
__slots__ = ("value", "index", "size", "_depth")
|
|
32
34
|
|
|
33
35
|
def __init__(self, value: memoryview) -> None:
|
|
34
36
|
self.size = len(value)
|
|
@@ -37,6 +39,7 @@ class Decoder:
|
|
|
37
39
|
|
|
38
40
|
self.value = value
|
|
39
41
|
self.index = 0
|
|
42
|
+
self._depth = 0
|
|
40
43
|
|
|
41
44
|
def decode(self) -> object:
|
|
42
45
|
data = self.__decode()
|
|
@@ -47,6 +50,10 @@ class Decoder:
|
|
|
47
50
|
return data
|
|
48
51
|
|
|
49
52
|
def __decode(self) -> object:
|
|
53
|
+
self._depth += 1
|
|
54
|
+
if self._depth > _MAX_DECODE_DEPTH:
|
|
55
|
+
raise BencodeDecodeError("exceeded maximum decode depth")
|
|
56
|
+
|
|
50
57
|
if char_0 <= self.value[self.index] <= char_9:
|
|
51
58
|
return self.__decode_bytes()
|
|
52
59
|
if self.value[self.index] == char_i:
|
|
@@ -81,6 +88,10 @@ class Decoder:
|
|
|
81
88
|
if self.value[self.index] == char_dash:
|
|
82
89
|
n = -1
|
|
83
90
|
offset = 1
|
|
91
|
+
if self.index + offset >= index_end:
|
|
92
|
+
raise BencodeDecodeError(
|
|
93
|
+
f"invalid int, '-' with no digits at {self.index}"
|
|
94
|
+
)
|
|
84
95
|
|
|
85
96
|
total: int = 0
|
|
86
97
|
for c in self.value[self.index + offset : index_end]:
|
bencode2/decode.cpp
CHANGED
|
@@ -13,10 +13,18 @@
|
|
|
13
13
|
|
|
14
14
|
namespace nb = nanobind;
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
#define BENCODE_MAX_DECODE_DEPTH 4096
|
|
17
|
+
|
|
18
|
+
nb::object decodeAny(const char *buf, Py_ssize_t &index, Py_ssize_t size, uint_fast32_t depth);
|
|
17
19
|
|
|
18
20
|
#define decoderError(f, ...) throw DecodeError(fmt::format(f, ##__VA_ARGS__))
|
|
19
21
|
|
|
22
|
+
static inline void checkDepth(uint_fast32_t depth) {
|
|
23
|
+
if (depth > BENCODE_MAX_DECODE_DEPTH) {
|
|
24
|
+
throw DecodeError("exceeded maximum decode depth");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
20
28
|
nb::object decodeInt(const char *buf, Py_ssize_t &index, Py_ssize_t size) {
|
|
21
29
|
Py_ssize_t index_e = 0;
|
|
22
30
|
for (Py_ssize_t i = index + 1; i < size; i++) {
|
|
@@ -27,7 +35,7 @@ nb::object decodeInt(const char *buf, Py_ssize_t &index, Py_ssize_t size) {
|
|
|
27
35
|
}
|
|
28
36
|
|
|
29
37
|
if (index_e == 0) {
|
|
30
|
-
|
|
38
|
+
decoderError("invalid int, missing 'e': {}", index);
|
|
31
39
|
}
|
|
32
40
|
|
|
33
41
|
// malformed 'ie'
|
|
@@ -44,16 +52,17 @@ nb::object decodeInt(const char *buf, Py_ssize_t &index, Py_ssize_t size) {
|
|
|
44
52
|
Py_ssize_t num_start = index;
|
|
45
53
|
|
|
46
54
|
if (buf[index] == '-') {
|
|
47
|
-
if (buf[index + 1] == '0') {
|
|
48
|
-
decoderError("invalid int, '-0' found at %zd", index);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
55
|
num_start = 1 + index;
|
|
56
|
+
if (num_start >= index_e) {
|
|
57
|
+
decoderError("invalid int, '-' with no digits at {}", index);
|
|
58
|
+
}
|
|
59
|
+
if (buf[num_start] == '0') {
|
|
60
|
+
decoderError("invalid int, '-0' found at {}", index);
|
|
61
|
+
}
|
|
52
62
|
sign = -1;
|
|
53
63
|
} else if (buf[index] == '0') {
|
|
54
64
|
if (index + 1 != index_e) {
|
|
55
|
-
decoderError("invalid int, non-zero int should not start with '0'. found at
|
|
56
|
-
index);
|
|
65
|
+
decoderError("invalid int, non-zero int should not start with '0'. found at {}", index);
|
|
57
66
|
}
|
|
58
67
|
}
|
|
59
68
|
|
|
@@ -121,7 +130,6 @@ __OverFlow:;
|
|
|
121
130
|
}
|
|
122
131
|
|
|
123
132
|
// there is no bytes/Str in bencode, they only have 1 type for both of them.
|
|
124
|
-
// TODO: check byte length overflow ssize_t
|
|
125
133
|
static std::string_view decodeAsView(const char *buf, Py_ssize_t &index, Py_ssize_t size) {
|
|
126
134
|
Py_ssize_t index_sep = 0;
|
|
127
135
|
for (Py_ssize_t i = index; i < size; i++) {
|
|
@@ -132,7 +140,7 @@ static std::string_view decodeAsView(const char *buf, Py_ssize_t &index, Py_ssiz
|
|
|
132
140
|
}
|
|
133
141
|
|
|
134
142
|
if (index_sep == 0) {
|
|
135
|
-
decoderError("invalid string, missing length: index
|
|
143
|
+
decoderError("invalid string, missing length: index {}", index);
|
|
136
144
|
}
|
|
137
145
|
|
|
138
146
|
if (buf[index] == '0' && index + 1 != index_sep) {
|
|
@@ -142,7 +150,10 @@ static std::string_view decodeAsView(const char *buf, Py_ssize_t &index, Py_ssiz
|
|
|
142
150
|
Py_ssize_t len = 0;
|
|
143
151
|
for (Py_ssize_t i = index; i < index_sep; i++) {
|
|
144
152
|
if (buf[i] < '0' || buf[i] > '9') {
|
|
145
|
-
decoderError("invalid bytes length, found '
|
|
153
|
+
decoderError("invalid bytes length, found '{:c}' at {}", buf[i], i);
|
|
154
|
+
}
|
|
155
|
+
if (len > (PY_SSIZE_T_MAX - 9) / 10) {
|
|
156
|
+
decoderError("bytes length overflow, index {}", index);
|
|
146
157
|
}
|
|
147
158
|
len = len * 10 + (buf[i] - '0');
|
|
148
159
|
}
|
|
@@ -162,7 +173,7 @@ static nb::bytes decodeBytes(const char *buf, Py_ssize_t &index, Py_ssize_t size
|
|
|
162
173
|
return nb::bytes(s.data(), s.length());
|
|
163
174
|
}
|
|
164
175
|
|
|
165
|
-
nb::object decodeList(const char *buf, Py_ssize_t &index, Py_ssize_t size) {
|
|
176
|
+
nb::object decodeList(const char *buf, Py_ssize_t &index, Py_ssize_t size, uint_fast32_t depth) {
|
|
166
177
|
index = index + 1;
|
|
167
178
|
|
|
168
179
|
nb::list l = nb::list();
|
|
@@ -176,7 +187,7 @@ nb::object decodeList(const char *buf, Py_ssize_t &index, Py_ssize_t size) {
|
|
|
176
187
|
break;
|
|
177
188
|
}
|
|
178
189
|
|
|
179
|
-
nb::object obj = decodeAny(buf, index, size);
|
|
190
|
+
nb::object obj = decodeAny(buf, index, size, depth);
|
|
180
191
|
|
|
181
192
|
l.append(obj);
|
|
182
193
|
}
|
|
@@ -186,7 +197,7 @@ nb::object decodeList(const char *buf, Py_ssize_t &index, Py_ssize_t size) {
|
|
|
186
197
|
return l;
|
|
187
198
|
}
|
|
188
199
|
|
|
189
|
-
nb::object decodeDict(const char *buf, Py_ssize_t &index, Py_ssize_t size) {
|
|
200
|
+
nb::object decodeDict(const char *buf, Py_ssize_t &index, Py_ssize_t size, uint_fast32_t depth) {
|
|
190
201
|
index = index + 1;
|
|
191
202
|
std::optional<std::string_view> lastKey = std::nullopt;
|
|
192
203
|
|
|
@@ -207,7 +218,7 @@ nb::object decodeDict(const char *buf, Py_ssize_t &index, Py_ssize_t size) {
|
|
|
207
218
|
}
|
|
208
219
|
|
|
209
220
|
auto key = decodeAsView(buf, index, size);
|
|
210
|
-
auto obj = decodeAny(buf, index, size);
|
|
221
|
+
auto obj = decodeAny(buf, index, size, depth);
|
|
211
222
|
|
|
212
223
|
// skip first key
|
|
213
224
|
if (lastKey.has_value()) {
|
|
@@ -228,7 +239,10 @@ nb::object decodeDict(const char *buf, Py_ssize_t &index, Py_ssize_t size) {
|
|
|
228
239
|
return d;
|
|
229
240
|
}
|
|
230
241
|
|
|
231
|
-
nb::object decodeAny(const char *buf, Py_ssize_t &index, Py_ssize_t size) {
|
|
242
|
+
nb::object decodeAny(const char *buf, Py_ssize_t &index, Py_ssize_t size, uint_fast32_t depth) {
|
|
243
|
+
depth++;
|
|
244
|
+
checkDepth(depth);
|
|
245
|
+
|
|
232
246
|
// int
|
|
233
247
|
if (buf[index] == 'i') {
|
|
234
248
|
return decodeInt(buf, index, size);
|
|
@@ -241,12 +255,12 @@ nb::object decodeAny(const char *buf, Py_ssize_t &index, Py_ssize_t size) {
|
|
|
241
255
|
|
|
242
256
|
// list
|
|
243
257
|
if (buf[index] == 'l') {
|
|
244
|
-
return decodeList(buf, index, size);
|
|
258
|
+
return decodeList(buf, index, size, depth);
|
|
245
259
|
}
|
|
246
260
|
|
|
247
261
|
// dict
|
|
248
262
|
if (buf[index] == 'd') {
|
|
249
|
-
return decodeDict(buf, index, size);
|
|
263
|
+
return decodeDict(buf, index, size, depth);
|
|
250
264
|
}
|
|
251
265
|
|
|
252
266
|
decoderError("invalid bencode prefix '{:c}', index {}", buf[index], index);
|
|
@@ -275,7 +289,7 @@ nb::object bdecode(nb::object b) {
|
|
|
275
289
|
|
|
276
290
|
nb::object o;
|
|
277
291
|
try {
|
|
278
|
-
o = decodeAny(buf, index, size);
|
|
292
|
+
o = decodeAny(buf, index, size, 0);
|
|
279
293
|
} catch (std::exception &e) {
|
|
280
294
|
PyBuffer_Release(&view);
|
|
281
295
|
throw e;
|
bencode2/encode.cpp
CHANGED
|
@@ -22,15 +22,20 @@ static bool cmp(std::pair<std::string_view, nb::handle> &a,
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
static std::string_view py_string_view(nb::handle obj) {
|
|
25
|
+
#ifndef Py_LIMITED_API
|
|
25
26
|
// fast path for pure ascii string
|
|
26
27
|
if (PyUnicode_IS_COMPACT_ASCII(obj.ptr())) {
|
|
27
28
|
const char *s = (char *)PyUnicode_DATA(obj.ptr());
|
|
28
29
|
Py_ssize_t size = ((PyASCIIObject *)(obj.ptr()))->length;
|
|
29
30
|
return std::string_view(s, size);
|
|
30
31
|
}
|
|
32
|
+
#endif
|
|
31
33
|
|
|
32
34
|
Py_ssize_t size = 0;
|
|
33
35
|
const char *s = PyUnicode_AsUTF8AndSize(obj.ptr(), &size);
|
|
36
|
+
if (s == nullptr) {
|
|
37
|
+
throw nb::python_error();
|
|
38
|
+
}
|
|
34
39
|
return std::string_view(s, size);
|
|
35
40
|
}
|
|
36
41
|
|
|
@@ -242,6 +247,7 @@ void encodeComposeObject(EncodeContext *ctx, nb::handle obj, Encode encode) {
|
|
|
242
247
|
void encodeStr(EncodeContext *ctx, const nb::handle obj) {
|
|
243
248
|
debug_print("encode str");
|
|
244
249
|
|
|
250
|
+
#ifndef Py_LIMITED_API
|
|
245
251
|
// fast path for pure ascii string
|
|
246
252
|
if (PyUnicode_IS_COMPACT_ASCII(obj.ptr())) {
|
|
247
253
|
const char *s = (char *)PyUnicode_DATA(obj.ptr());
|
|
@@ -254,9 +260,13 @@ void encodeStr(EncodeContext *ctx, const nb::handle obj) {
|
|
|
254
260
|
ctx->write(s, size);
|
|
255
261
|
return;
|
|
256
262
|
}
|
|
263
|
+
#endif
|
|
257
264
|
|
|
258
265
|
Py_ssize_t size = 0;
|
|
259
266
|
const char *s = PyUnicode_AsUTF8AndSize(obj.ptr(), &size);
|
|
267
|
+
if (s == nullptr) {
|
|
268
|
+
throw nb::python_error();
|
|
269
|
+
}
|
|
260
270
|
|
|
261
271
|
debug_print("write length");
|
|
262
272
|
ctx->writeSize_t(size);
|
|
@@ -331,6 +341,7 @@ void encodeAny(EncodeContext *ctx, const nb::handle obj) {
|
|
|
331
341
|
return;
|
|
332
342
|
}
|
|
333
343
|
|
|
344
|
+
#ifndef Py_LIMITED_API
|
|
334
345
|
// fast path for memoryview
|
|
335
346
|
if (PyMemoryView_Check(obj.ptr())) {
|
|
336
347
|
Py_buffer *buf = PyMemoryView_GET_BUFFER(obj.ptr());
|
|
@@ -340,6 +351,7 @@ void encodeAny(EncodeContext *ctx, const nb::handle obj) {
|
|
|
340
351
|
|
|
341
352
|
return;
|
|
342
353
|
}
|
|
354
|
+
#endif
|
|
343
355
|
|
|
344
356
|
if (PyObject_CheckBuffer(obj.ptr())) {
|
|
345
357
|
Py_buffer buf;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bencode2
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.30
|
|
4
4
|
Summary: A fast and correct bencode serialize/deserialize library
|
|
5
5
|
Keywords: bencode,bittorrent,bit-torrent,serialize,deserialize,p2p
|
|
6
6
|
Author-email: trim21 <trim21me@gmail.com>
|
|
7
|
-
Requires-Python: >=3.10
|
|
7
|
+
Requires-Python: >=3.10
|
|
8
8
|
Description-Content-Type: text/markdown
|
|
9
9
|
Classifier: Development Status :: 5 - Production/Stable
|
|
10
10
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -21,7 +21,6 @@ Project-URL: Repository, https://github.com/trim21/bencode-py
|
|
|
21
21
|
|
|
22
22
|
[](https://pypi.org/project/bencode2/)
|
|
23
23
|
[](https://github.com/trim21/bencode-py/actions/workflows/tests.yaml)
|
|
24
|
-
[](https://dl.circleci.com/status-badge/redirect/gh/trim21/bencode-py/tree/master)
|
|
25
24
|
[](https://pypi.org/project/bencode2/)
|
|
26
25
|
[](https://codecov.io/gh/Trim21/bencode-py/branch/master)
|
|
27
26
|
|
|
@@ -111,7 +110,7 @@ bencode2 will decode bencode string to python `bytes`.
|
|
|
111
110
|
| `bytes`, `bytearray`,`memoryview` | string |
|
|
112
111
|
| `list`, `tuple`, `NamedTuple` | array |
|
|
113
112
|
| `dict`, `OrderedDict` | dictionary |
|
|
114
|
-
| `types.
|
|
113
|
+
| `types.MappingProxy` | dictionary |
|
|
115
114
|
| dataclasses | dictionary |
|
|
116
115
|
|
|
117
116
|
## free threading
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
bencode2/__bencode.pyi,sha256=R11h4PI4pSxBQgxslVunDxzx5sjrTcHq-_RpclDTlpY,137
|
|
2
|
-
bencode2/__decoder.py,sha256=
|
|
2
|
+
bencode2/__decoder.py,sha256=WWHd_HCdxxoJwYs7m22KOj5qrEBuCzEZEBWiYVK-tdY,6579
|
|
3
3
|
bencode2/__encoder.py,sha256=ky4hMgkpZNe7PtoqYaTroyTsoH9ZDKLqxYICQpL-kbk,4196
|
|
4
4
|
bencode2/__init__.py,sha256=H7VTW80hlELobN5j9dhyUi2l0pUuOon8ibTW2kVG78Y,383
|
|
5
5
|
bencode2/__init__.pyi,sha256=rFe9L4Kof8XKp1CVLJj6zZeNRifRVLwVN7Ag4kRQndI,237
|
|
6
6
|
bencode2/bencode.cpp,sha256=sn12w9hvaBdAdEMAJZjQdPM3pjPyfHVlhFIc-wlNNJ4,710
|
|
7
7
|
bencode2/common.hpp,sha256=liOfMvppYm1Es8ki7G2UjVNkOP5pVuvZvNCyQ_cRAqA,1791
|
|
8
|
-
bencode2/decode.cpp,sha256=
|
|
9
|
-
bencode2/encode.cpp,sha256=
|
|
8
|
+
bencode2/decode.cpp,sha256=smagKRJzWth8_L56OxPDyI8lBnlRDq6_XG2eCN6u8jk,7777
|
|
9
|
+
bencode2/encode.cpp,sha256=IGNlXzr-gs4Mk0UMKetbjn8UISzdzOpwy_paM1u1Tc0,11308
|
|
10
10
|
bencode2/encode_ctx.hpp,sha256=_CO3bHSsx6DYJBSnUeoCDqtZFFR3jOyIQJdv5YG0J44,1254
|
|
11
11
|
bencode2/overflow.hpp,sha256=n3W-45ErhBf5ZGKKn03ll9j6bB5jY0R4eybbzTPKMnc,701
|
|
12
12
|
bencode2/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
-
bencode2-0.3.
|
|
14
|
-
bencode2-0.3.
|
|
15
|
-
bencode2-0.3.
|
|
16
|
-
bencode2-0.3.
|
|
13
|
+
bencode2-0.3.30.dist-info/licenses/LICENSE,sha256=WraLL2GWym7_6EnkH1Zi8kU_-2iPhXGv7yegTIEX3E8,1085
|
|
14
|
+
bencode2-0.3.30.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
15
|
+
bencode2-0.3.30.dist-info/METADATA,sha256=Q27Lrz4VwtE2-crVnOjalvnay2NVeKfYLJs18ZaCJEE,5106
|
|
16
|
+
bencode2-0.3.30.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|