~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/_bencode_pyx.pyx

  • Committer: John Arbash Meinel
  • Date: 2009-06-04 16:50:33 UTC
  • mto: This revision was merged to the branch mainline in revision 4410.
  • Revision ID: john@arbash-meinel.com-20090604165033-bfdo0lyf4yt4vjcz
We don't need a base Coder class, because Decoder._update_tail is different than Encoder._update_tail.
(one adds, one subtracts from self.size).
So we now have 2 versions of the macro, and the test suite stops crashing... :)

Show diffs side-by-side

added added

removed removed

Lines of Context:
51
51
cdef extern from "python-compat.h":
52
52
    int snprintf(char* buffer, size_t nsize, char* fmt, ...)
53
53
 
54
 
cdef class Coder:
55
 
    """Base class for both Decoder and Encoder"""
56
 
 
57
 
    cdef readonly char *tail
58
 
    cdef readonly int size
 
54
cdef class Decoder
 
55
cdef class Encoder
59
56
 
60
57
cdef extern from "_bencode_pyx.h":
61
 
    void UPDATE_TAIL(Coder, int n)
62
 
    int MAX_INT_AS_STR
63
 
 
64
 
 
65
 
 
66
 
cdef class Decoder(Coder):
 
58
    void D_UPDATE_TAIL(Decoder, int n)
 
59
    void E_UPDATE_TAIL(Encoder, int n)
 
60
 
 
61
 
 
62
cdef class Decoder:
67
63
    """Bencode decoder"""
68
64
 
 
65
    cdef readonly char *tail
 
66
    cdef readonly int size
69
67
    cdef readonly int _yield_tuples
70
68
    cdef object text
71
69
 
101
99
        try:
102
100
            ch = self.tail[0]
103
101
            if ch == c'i':
104
 
                UPDATE_TAIL(self, 1)
 
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()
108
106
            elif ch == c'l':
109
 
                UPDATE_TAIL(self, 1)
 
107
                D_UPDATE_TAIL(self, 1)
110
108
                return self._decode_list()
111
109
            elif ch == c'd':
112
 
                UPDATE_TAIL(self, 1)
 
110
                D_UPDATE_TAIL(self, 1)
113
111
                return self._decode_dict()
114
112
            else:
115
113
                raise ValueError('unknown object type identifier %r' % ch)
116
114
        finally:
117
115
            Py_LeaveRecursiveCall()
118
116
 
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
123
 
 
124
117
    cdef int _read_digits(self, char stop_char) except -1:
125
118
        cdef int i
126
119
        i = 0
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:
129
122
            i = i + 1
130
123
 
147
140
            ret = PyInt_FromString(self.tail, NULL, 10)
148
141
        finally:
149
142
            self.tail[i] = c'e'
150
 
        UPDATE_TAIL(self, i+1)
 
143
        D_UPDATE_TAIL(self, i+1)
151
144
        return ret
152
145
 
153
146
    cdef object _decode_string(self):
154
147
        cdef int n, i
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)
158
151
        if n == 0:
159
152
            return ''
160
153
        if n > self.size:
163
156
            raise ValueError('string size below zero: %d' % n)
164
157
 
165
158
        result = PyString_FromStringAndSize(self.tail, n)
166
 
        UPDATE_TAIL(self, n)
 
159
        D_UPDATE_TAIL(self, n)
167
160
        return result
168
161
 
169
162
    cdef object _decode_list(self):
171
164
 
172
165
        while self.size > 0:
173
166
            if self.tail[0] == c'e':
174
 
                UPDATE_TAIL(self, 1)
 
167
                D_UPDATE_TAIL(self, 1)
175
168
                if self._yield_tuples:
176
169
                    return tuple(result)
177
170
                else:
190
183
        while self.size > 0:
191
184
            ch = self.tail[0]
192
185
            if ch == c'e':
193
 
                UPDATE_TAIL(self, 1)
 
186
                D_UPDATE_TAIL(self, 1)
194
187
                return result
195
188
            else:
196
189
                # keys should be strings only
227
220
    INT_BUF_SIZE = 32
228
221
 
229
222
 
230
 
cdef class Encoder(Coder):
 
223
cdef class Encoder:
231
224
    """Bencode encoder"""
232
225
 
 
226
    cdef readonly char *tail
 
227
    cdef readonly int size
233
228
    cdef readonly char *buffer
234
229
    cdef readonly int maxsize
235
230
 
285
280
        self.tail = &new_buffer[self.size]
286
281
        return 1
287
282
 
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]
292
 
 
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)
300
290
        if n < 0:
301
291
            raise MemoryError('int %d too big to encode' % x)
302
 
        UPDATE_TAIL(self, n)
 
292
        E_UPDATE_TAIL(self, n)
303
293
        return 1
304
294
 
305
295
    cdef int _encode_long(self, x) except 0:
306
296
        return self._append_string(''.join(('i', str(x), 'e')))
307
297
 
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))
 
299
        cdef Py_ssize_t n
 
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)
312
304
        return 1
313
305
 
314
306
    cdef int _encode_string(self, x) except 0:
315
307
        cdef int n
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)
318
312
        if n < 0:
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)
323
316
        return 1
324
317
 
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'
328
 
        UPDATE_TAIL(self, 1)
 
321
        E_UPDATE_TAIL(self, 1)
329
322
 
330
323
        for i in x:
331
324
            self.process(i)
332
325
 
 
326
        self._ensure_buffer(1)
333
327
        self.tail[0] = c'e'
334
 
        UPDATE_TAIL(self, 1)
 
328
        E_UPDATE_TAIL(self, 1)
335
329
        return 1
336
330
 
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'
340
 
        UPDATE_TAIL(self, 1)
 
334
        E_UPDATE_TAIL(self, 1)
341
335
 
342
336
        keys = x.keys()
343
337
        keys.sort()
347
341
            self._encode_string(k)
348
342
            self.process(x[k])
349
343
 
 
344
        self._ensure_buffer(1)
350
345
        self.tail[0] = c'e'
351
 
        UPDATE_TAIL(self, 1)
 
346
        E_UPDATE_TAIL(self, 1)
352
347
        return 1
353
348
 
354
349
    def process(self, object x):