51
51
cdef extern from "python-compat.h":
52
52
int snprintf(char* buffer, size_t nsize, char* fmt, ...)
55
"""Base class for both Decoder and Encoder"""
57
cdef readonly char *tail
58
cdef readonly int size
60
57
cdef extern from "_bencode_pyx.h":
61
void UPDATE_TAIL(Coder, int n)
66
cdef class Decoder(Coder):
58
void D_UPDATE_TAIL(Decoder, int n)
59
void E_UPDATE_TAIL(Encoder, int n)
67
63
"""Bencode decoder"""
65
cdef readonly char *tail
66
cdef readonly int size
69
67
cdef readonly int _yield_tuples
102
100
ch = self.tail[0]
102
D_UPDATE_TAIL(self, 1)
105
103
return self._decode_int()
106
104
elif c'0' <= ch <= c'9':
107
105
return self._decode_string()
107
D_UPDATE_TAIL(self, 1)
110
108
return self._decode_list()
110
D_UPDATE_TAIL(self, 1)
113
111
return self._decode_dict()
115
113
raise ValueError('unknown object type identifier %r' % ch)
117
115
Py_LeaveRecursiveCall()
119
cdef void _update_tail(self, int n):
120
"""Update tail pointer and resulting size by n characters"""
121
self.size = self.size - n
122
self.tail = self.tail + n
124
117
cdef int _read_digits(self, char stop_char) except -1:
127
while ((self.tail[i] >= c'0' and self.tail[i] <= c'9') or
120
while ((self.tail[i] >= c'0' and self.tail[i] <= c'9') or
128
121
self.tail[i] == c'-') and i < self.size:
147
140
ret = PyInt_FromString(self.tail, NULL, 10)
149
142
self.tail[i] = c'e'
150
UPDATE_TAIL(self, i+1)
143
D_UPDATE_TAIL(self, i+1)
153
146
cdef object _decode_string(self):
155
148
i = self._read_digits(c':')
156
149
n = strtol(self.tail, NULL, 10)
157
UPDATE_TAIL(self, i+1)
150
D_UPDATE_TAIL(self, i+1)
160
153
if n > self.size:
285
280
self.tail = &new_buffer[self.size]
288
cdef void _update_tail(self, int n):
289
"""Update tail pointer and resulting size by n characters"""
290
self.size = self.size + n
291
self.tail = &self.tail[n]
293
283
cdef int _encode_int(self, int x) except 0:
294
284
"""Encode int to bencode string iNNNe
295
285
@param x: value to encode
299
289
n = snprintf(self.tail, INT_BUF_SIZE, "i%de", x)
301
291
raise MemoryError('int %d too big to encode' % x)
292
E_UPDATE_TAIL(self, n)
305
295
cdef int _encode_long(self, x) except 0:
306
296
return self._append_string(''.join(('i', str(x), 'e')))
308
298
cdef int _append_string(self, s) except 0:
309
self._ensure_buffer(PyString_GET_SIZE(s))
310
memcpy(self.tail, PyString_AS_STRING(s), PyString_GET_SIZE(s))
311
UPDATE_TAIL(self, PyString_GET_SIZE(s))
300
n = PyString_GET_SIZE(s)
301
self._ensure_buffer(n)
302
memcpy(self.tail, PyString_AS_STRING(s), n)
303
E_UPDATE_TAIL(self, n)
314
306
cdef int _encode_string(self, x) except 0:
316
self._ensure_buffer(PyString_GET_SIZE(x) + INT_BUF_SIZE)
317
n = snprintf(self.tail, INT_BUF_SIZE, '%d:', PyString_GET_SIZE(x))
308
cdef Py_ssize_t x_len
309
x_len = PyString_GET_SIZE(x)
310
self._ensure_buffer(x_len + INT_BUF_SIZE)
311
n = snprintf(self.tail, INT_BUF_SIZE, '%d:', x_len)
319
313
raise MemoryError('string %s too big to encode' % x)
320
memcpy(<void *>(self.tail+n), PyString_AS_STRING(x),
321
PyString_GET_SIZE(x))
322
UPDATE_TAIL(self, n+PyString_GET_SIZE(x))
314
memcpy(<void *>(self.tail+n), PyString_AS_STRING(x), x_len)
315
E_UPDATE_TAIL(self, n + x_len)
325
318
cdef int _encode_list(self, x) except 0:
326
self._ensure_buffer(2)
319
self._ensure_buffer(1)
327
320
self.tail[0] = c'l'
321
E_UPDATE_TAIL(self, 1)
326
self._ensure_buffer(1)
333
327
self.tail[0] = c'e'
328
E_UPDATE_TAIL(self, 1)
337
331
cdef int _encode_dict(self, x) except 0:
338
self._ensure_buffer(2)
332
self._ensure_buffer(1)
339
333
self.tail[0] = c'd'
334
E_UPDATE_TAIL(self, 1)