17
17
"""Pyrex implementation for bencode coder/decoder"""
19
from __future__ import absolute_import
21
from cpython.bool cimport (
24
from cpython.bytes cimport (
26
PyBytes_FromStringAndSize,
30
from cpython.dict cimport (
33
from cpython.int cimport (
37
from cpython.list cimport (
41
from cpython.long cimport (
44
from cpython.mem cimport (
49
from cpython.tuple cimport (
53
from libc.stdlib cimport (
56
from libc.string cimport (
20
cdef extern from "stddef.h":
21
ctypedef unsigned int size_t
23
cdef extern from "Python.h":
24
ctypedef int Py_ssize_t
25
int PyInt_CheckExact(object o)
26
int PyLong_CheckExact(object o)
27
int PyString_CheckExact(object o)
28
int PyTuple_CheckExact(object o)
29
int PyList_CheckExact(object o)
30
int PyDict_CheckExact(object o)
31
int PyBool_Check(object o)
32
object PyString_FromStringAndSize(char *v, Py_ssize_t len)
33
char *PyString_AS_STRING(object o) except NULL
34
Py_ssize_t PyString_GET_SIZE(object o) except -1
35
object PyInt_FromString(char *str, char **pend, int base)
36
int Py_GetRecursionLimit()
37
int Py_EnterRecursiveCall(char *)
38
void Py_LeaveRecursiveCall()
40
int PyList_Append(object, object) except -1
42
cdef extern from "stdlib.h":
43
void free(void *memblock)
44
void *malloc(size_t size)
45
void *realloc(void *memblock, size_t size)
46
long strtol(char *, char **, int)
48
cdef extern from "string.h":
49
void *memcpy(void *dest, void *src, size_t count)
60
51
cdef extern from "python-compat.h":
61
52
int snprintf(char* buffer, size_t nsize, char* fmt, ...)
62
# Use wrapper with inverted error return so Cython can propogate
63
int BrzPy_EnterRecursiveCall(char *) except 0
65
cdef extern from "Python.h":
66
void Py_LeaveRecursiveCall()
72
58
void D_UPDATE_TAIL(Decoder, int n)
73
59
void E_UPDATE_TAIL(Encoder, int n)
75
from ._static_tuple_c cimport StaticTuple, StaticTuple_CheckExact, \
61
# To maintain compatibility with older versions of pyrex, we have to use the
62
# relative import here, rather than 'bzrlib._static_tuple_c'
63
from _static_tuple_c cimport StaticTuple, StaticTuple_CheckExact, \
76
64
import_static_tuple_c
78
66
import_static_tuple_c()
90
78
"""Initialize decoder engine.
91
79
@param s: Python string.
93
if not PyBytes_CheckExact(s):
94
raise TypeError("bytes required")
81
if not PyString_CheckExact(s):
82
raise TypeError("String required")
97
self.tail = PyBytes_AS_STRING(s)
98
self.size = PyBytes_GET_SIZE(s)
85
self.tail = PyString_AS_STRING(s)
86
self.size = PyString_GET_SIZE(s)
99
87
self._yield_tuples = int(yield_tuples)
176
166
raise ValueError('leading zeros are not allowed')
177
167
D_UPDATE_TAIL(self, next_tail - self.tail + 1)
180
170
if n > self.size:
181
171
raise ValueError('stream underflow')
183
173
raise ValueError('string size below zero: %d' % n)
185
result = PyBytes_FromStringAndSize(self.tail, n)
175
result = PyString_FromStringAndSize(self.tail, n)
186
176
D_UPDATE_TAIL(self, n)
281
271
def __dealloc__(self):
282
PyMem_Free(self.buffer)
283
273
self.buffer = NULL
287
277
if self.buffer != NULL and self.size != 0:
288
return PyBytes_FromStringAndSize(self.buffer, self.size)
278
return PyString_FromStringAndSize(self.buffer, self.size)
291
282
cdef int _ensure_buffer(self, int required) except 0:
292
283
"""Ensure that tail of CharTail buffer has enough size.
319
310
self._ensure_buffer(INT_BUF_SIZE)
320
n = snprintf(self.tail, INT_BUF_SIZE, b"i%de", x)
311
n = snprintf(self.tail, INT_BUF_SIZE, "i%de", x)
322
313
raise MemoryError('int %d too big to encode' % x)
323
314
E_UPDATE_TAIL(self, n)
326
317
cdef int _encode_long(self, x) except 0:
327
return self._append_string(b'i%de' % x)
318
return self._append_string(''.join(('i', str(x), 'e')))
329
320
cdef int _append_string(self, s) except 0:
330
321
cdef Py_ssize_t n
331
n = PyBytes_GET_SIZE(s)
322
n = PyString_GET_SIZE(s)
332
323
self._ensure_buffer(n)
333
memcpy(self.tail, PyBytes_AS_STRING(s), n)
324
memcpy(self.tail, PyString_AS_STRING(s), n)
334
325
E_UPDATE_TAIL(self, n)
337
328
cdef int _encode_string(self, x) except 0:
339
330
cdef Py_ssize_t x_len
340
x_len = PyBytes_GET_SIZE(x)
331
x_len = PyString_GET_SIZE(x)
341
332
self._ensure_buffer(x_len + INT_BUF_SIZE)
342
n = snprintf(self.tail, INT_BUF_SIZE, b'%ld:', x_len)
333
n = snprintf(self.tail, INT_BUF_SIZE, '%d:', x_len)
344
335
raise MemoryError('string %s too big to encode' % x)
345
memcpy(<void *>(self.tail+n), PyBytes_AS_STRING(x), x_len)
336
memcpy(<void *>(self.tail+n), PyString_AS_STRING(x), x_len)
346
337
E_UPDATE_TAIL(self, n + x_len)
375
368
E_UPDATE_TAIL(self, 1)
378
cpdef object process(self, object x):
379
BrzPy_EnterRecursiveCall(" while bencode encoding")
371
def process(self, object x):
372
if Py_EnterRecursiveCall("encode"):
373
raise RuntimeError("too deeply nested")
381
if PyBytes_CheckExact(x):
375
if PyString_CheckExact(x):
382
376
self._encode_string(x)
383
elif PyInt_CheckExact(x) and x.bit_length() < 32:
377
elif PyInt_CheckExact(x):
384
378
self._encode_int(x)
385
379
elif PyLong_CheckExact(x):
386
380
self._encode_long(x)
387
381
elif (PyList_CheckExact(x) or PyTuple_CheckExact(x)
388
or isinstance(x, StaticTuple)):
382
or StaticTuple_CheckExact(x)):
389
383
self._encode_list(x)
390
384
elif PyDict_CheckExact(x):
391
385
self._encode_dict(x)