/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/_bencode_pyx.pyx

  • Committer: John Arbash Meinel
  • Date: 2009-06-03 14:14:31 UTC
  • mto: This revision was merged to the branch mainline in revision 4410.
  • Revision ID: john@arbash-meinel.com-20090603141431-zeurvzs2iezwzdn5
A bit of code restructuring.
Move bzrlib/_bencode_py.py back to bzrlib/util/_bencode_py.py
Leaving it as _bencode_py.py so that people don't accidentally
import the old version.
Renaming _bencode_c.pyx => _bencode_pyx.pyx to conform to new naming scheme.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007, 2009, 2010 Canonical Ltd
 
1
# Copyright (C) 2007,2009 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
"""Pyrex implementation for bencode coder/decoder"""
18
18
 
37
37
    int Py_EnterRecursiveCall(char *)
38
38
    void Py_LeaveRecursiveCall()
39
39
 
40
 
    int PyList_Append(object, object) except -1
41
 
 
42
40
cdef extern from "stdlib.h":
43
41
    void free(void *memblock)
44
42
    void *malloc(size_t size)
51
49
cdef extern from "python-compat.h":
52
50
    int snprintf(char* buffer, size_t nsize, char* fmt, ...)
53
51
 
54
 
cdef class Decoder
55
 
cdef class Encoder
56
 
 
57
 
cdef extern from "_bencode_pyx.h":
58
 
    void D_UPDATE_TAIL(Decoder, int n)
59
 
    void E_UPDATE_TAIL(Encoder, int n)
60
 
 
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, \
64
 
    import_static_tuple_c
65
 
 
66
 
import_static_tuple_c()
67
 
 
68
52
 
69
53
cdef class Decoder:
70
54
    """Bencode decoder"""
87
71
        self._yield_tuples = int(yield_tuples)
88
72
 
89
73
    def decode(self):
90
 
        result = self._decode_object()
 
74
        result = self.decode_object()
91
75
        if self.size != 0:
92
76
            raise ValueError('junk in stream')
93
77
        return result
94
78
 
95
79
    def decode_object(self):
96
 
        return self._decode_object()
97
 
 
98
 
    cdef object _decode_object(self):
99
80
        cdef char ch
100
81
 
101
82
        if 0 == self.size:
102
83
            raise ValueError('stream underflow')
103
84
 
104
 
        if Py_EnterRecursiveCall("_decode_object"):
 
85
        if Py_EnterRecursiveCall("decode_object"):
105
86
            raise RuntimeError("too deeply nested")
106
87
        try:
107
88
            ch = self.tail[0]
108
 
            if c'0' <= ch <= c'9':
 
89
            if ch == c'i':
 
90
                self._update_tail(1)
 
91
                return self._decode_int()
 
92
            elif c'0' <= ch <= c'9':
109
93
                return self._decode_string()
110
94
            elif ch == c'l':
111
 
                D_UPDATE_TAIL(self, 1)
 
95
                self._update_tail(1)
112
96
                return self._decode_list()
113
 
            elif ch == c'i':
114
 
                D_UPDATE_TAIL(self, 1)
115
 
                return self._decode_int()
116
97
            elif ch == c'd':
117
 
                D_UPDATE_TAIL(self, 1)
 
98
                self._update_tail(1)
118
99
                return self._decode_dict()
119
100
            else:
120
101
                raise ValueError('unknown object type identifier %r' % ch)
121
102
        finally:
122
103
            Py_LeaveRecursiveCall()
123
104
 
 
105
    cdef void _update_tail(self, int n):
 
106
        """Update tail pointer and resulting size by n characters"""
 
107
        self.size = self.size - n
 
108
        self.tail = &self.tail[n]
 
109
 
124
110
    cdef int _read_digits(self, char stop_char) except -1:
125
111
        cdef int i
126
112
        i = 0
127
 
        while ((self.tail[i] >= c'0' and self.tail[i] <= c'9') or
 
113
        while ((self.tail[i] >= c'0' and self.tail[i] <= c'9') or 
128
114
               self.tail[i] == c'-') and i < self.size:
129
115
            i = i + 1
130
116
 
147
133
            ret = PyInt_FromString(self.tail, NULL, 10)
148
134
        finally:
149
135
            self.tail[i] = c'e'
150
 
        D_UPDATE_TAIL(self, i+1)
 
136
        self._update_tail(i+1)
151
137
        return ret
152
138
 
153
139
    cdef object _decode_string(self):
154
 
        cdef int n
155
 
        cdef char *next_tail
156
 
        # strtol allows leading whitespace, negatives, and leading zeros
157
 
        # however, all callers have already checked that '0' <= tail[0] <= '9'
158
 
        # or they wouldn't have called _decode_string
159
 
        # strtol will stop at trailing whitespace, etc
160
 
        n = strtol(self.tail, &next_tail, 10)
161
 
        if next_tail == NULL or next_tail[0] != c':':
162
 
            raise ValueError('string len not terminated by ":"')
163
 
        # strtol allows leading zeros, so validate that we don't have that
164
 
        if (self.tail[0] == c'0'
165
 
            and (n != 0 or (next_tail - self.tail != 1))):
166
 
            raise ValueError('leading zeros are not allowed')
167
 
        D_UPDATE_TAIL(self, next_tail - self.tail + 1)
 
140
        cdef int n, i
 
141
        i = self._read_digits(c':')
 
142
        n = strtol(self.tail, NULL, 10)
 
143
        self._update_tail(i+1)
168
144
        if n == 0:
169
145
            return ''
170
146
        if n > self.size:
173
149
            raise ValueError('string size below zero: %d' % n)
174
150
 
175
151
        result = PyString_FromStringAndSize(self.tail, n)
176
 
        D_UPDATE_TAIL(self, n)
 
152
        self._update_tail(n)
177
153
        return result
178
154
 
179
155
    cdef object _decode_list(self):
181
157
 
182
158
        while self.size > 0:
183
159
            if self.tail[0] == c'e':
184
 
                D_UPDATE_TAIL(self, 1)
 
160
                self._update_tail(1)
185
161
                if self._yield_tuples:
186
162
                    return tuple(result)
187
163
                else:
188
164
                    return result
189
165
            else:
190
 
                # As a quick shortcut, check to see if the next object is a
191
 
                # string, since we know that won't be creating recursion
192
 
                # if self.tail[0] >= c'0' and self.tail[0] <= c'9':
193
 
                PyList_Append(result, self._decode_object())
 
166
                result.append(self.decode_object())
194
167
 
195
168
        raise ValueError('malformed list')
196
169
 
203
176
        while self.size > 0:
204
177
            ch = self.tail[0]
205
178
            if ch == c'e':
206
 
                D_UPDATE_TAIL(self, 1)
 
179
                self._update_tail(1)
207
180
                return result
208
181
            else:
209
182
                # keys should be strings only
210
 
                if self.tail[0] < c'0' or self.tail[0] > c'9':
211
 
                    raise ValueError('key was not a simple string.')
212
183
                key = self._decode_string()
213
184
                if lastkey >= key:
214
185
                    raise ValueError('dict keys disordered')
215
186
                else:
216
187
                    lastkey = key
217
 
                value = self._decode_object()
 
188
                value = self.decode_object()
218
189
                result[key] = value
219
190
 
220
191
        raise ValueError('malformed dict')
245
216
cdef class Encoder:
246
217
    """Bencode encoder"""
247
218
 
248
 
    cdef readonly char *tail
249
 
    cdef readonly int size
250
219
    cdef readonly char *buffer
251
220
    cdef readonly int maxsize
 
221
    cdef readonly char *tail
 
222
    cdef readonly int size
252
223
 
253
224
    def __init__(self, int maxsize=INITSIZE):
254
225
        """Initialize encoder engine
268
239
        self.maxsize = maxsize
269
240
        self.tail = p
270
241
 
271
 
    def __dealloc__(self):
 
242
    def __del__(self):
272
243
        free(self.buffer)
273
244
        self.buffer = NULL
274
245
        self.maxsize = 0
302
273
        self.tail = &new_buffer[self.size]
303
274
        return 1
304
275
 
 
276
    cdef void _update_tail(self, int n):
 
277
        """Update tail pointer and resulting size by n characters"""
 
278
        self.size = self.size + n
 
279
        self.tail = &self.tail[n]
 
280
 
305
281
    cdef int _encode_int(self, int x) except 0:
306
282
        """Encode int to bencode string iNNNe
307
283
        @param  x:  value to encode
311
287
        n = snprintf(self.tail, INT_BUF_SIZE, "i%de", x)
312
288
        if n < 0:
313
289
            raise MemoryError('int %d too big to encode' % x)
314
 
        E_UPDATE_TAIL(self, n)
 
290
        self._update_tail(n)
315
291
        return 1
316
292
 
317
293
    cdef int _encode_long(self, x) except 0:
318
294
        return self._append_string(''.join(('i', str(x), 'e')))
319
295
 
320
296
    cdef int _append_string(self, s) except 0:
321
 
        cdef Py_ssize_t n
322
 
        n = PyString_GET_SIZE(s)
323
 
        self._ensure_buffer(n)
324
 
        memcpy(self.tail, PyString_AS_STRING(s), n)
325
 
        E_UPDATE_TAIL(self, n)
 
297
        self._ensure_buffer(PyString_GET_SIZE(s))
 
298
        memcpy(self.tail, PyString_AS_STRING(s), PyString_GET_SIZE(s))
 
299
        self._update_tail(PyString_GET_SIZE(s))
326
300
        return 1
327
301
 
328
302
    cdef int _encode_string(self, x) except 0:
329
303
        cdef int n
330
 
        cdef Py_ssize_t x_len
331
 
        x_len = PyString_GET_SIZE(x)
332
 
        self._ensure_buffer(x_len + INT_BUF_SIZE)
333
 
        n = snprintf(self.tail, INT_BUF_SIZE, '%d:', x_len)
 
304
        self._ensure_buffer(PyString_GET_SIZE(x) + 32)
 
305
        n = snprintf(self.tail, 32, '%d:', PyString_GET_SIZE(x))
334
306
        if n < 0:
335
307
            raise MemoryError('string %s too big to encode' % x)
336
 
        memcpy(<void *>(self.tail+n), PyString_AS_STRING(x), x_len)
337
 
        E_UPDATE_TAIL(self, n + x_len)
 
308
        memcpy(<void *>(self.tail+n), PyString_AS_STRING(x),
 
309
               PyString_GET_SIZE(x))
 
310
        self._update_tail(n+PyString_GET_SIZE(x))
338
311
        return 1
339
312
 
340
313
    cdef int _encode_list(self, x) except 0:
341
 
        self._ensure_buffer(1)
 
314
        self._ensure_buffer(2)
342
315
        self.tail[0] = c'l'
343
 
        E_UPDATE_TAIL(self, 1)
 
316
        self._update_tail(1)
344
317
 
345
318
        for i in x:
346
319
            self.process(i)
347
320
 
348
 
        self._ensure_buffer(1)
349
321
        self.tail[0] = c'e'
350
 
        E_UPDATE_TAIL(self, 1)
 
322
        self._update_tail(1)
351
323
        return 1
352
324
 
353
325
    cdef int _encode_dict(self, x) except 0:
354
 
        self._ensure_buffer(1)
 
326
        self._ensure_buffer(2)
355
327
        self.tail[0] = c'd'
356
 
        E_UPDATE_TAIL(self, 1)
 
328
        self._update_tail(1)
357
329
 
358
330
        keys = x.keys()
359
331
        keys.sort()
363
335
            self._encode_string(k)
364
336
            self.process(x[k])
365
337
 
366
 
        self._ensure_buffer(1)
367
338
        self.tail[0] = c'e'
368
 
        E_UPDATE_TAIL(self, 1)
 
339
        self._update_tail(1)
369
340
        return 1
370
341
 
371
342
    def process(self, object x):
378
349
                self._encode_int(x)
379
350
            elif PyLong_CheckExact(x):
380
351
                self._encode_long(x)
381
 
            elif (PyList_CheckExact(x) or PyTuple_CheckExact(x)
382
 
                  or StaticTuple_CheckExact(x)):
 
352
            elif PyList_CheckExact(x) or PyTuple_CheckExact(x):
383
353
                self._encode_list(x)
384
354
            elif PyDict_CheckExact(x):
385
355
                self._encode_dict(x)