1
# Copyright (C) 2008, 2009, 2010 Canonical Ltd
1
# Copyright (C) 2009 Canonical Ltd
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
20
20
cdef extern from "python-compat.h":
21
ctypedef int Py_ssize_t # Required for older pyrex versions
24
24
cdef extern from "Python.h":
25
ctypedef int Py_ssize_t # Required for older pyrex versions
26
25
int PyString_CheckExact(object)
27
26
char * PyString_AS_STRING(object)
28
27
Py_ssize_t PyString_GET_SIZE(object)
32
31
cdef extern from *:
33
32
ctypedef unsigned long size_t
34
void * malloc(size_t) nogil
35
void * realloc(void *, size_t) nogil
36
void free(void *) nogil
37
void memcpy(void *, void *, size_t) nogil
34
void * realloc(void *, size_t)
36
void memcpy(void *, void *, size_t)
40
39
cdef extern from "delta.h":
44
43
unsigned long agg_offset
45
44
struct delta_index:
47
delta_index * create_delta_index(source_info *src, delta_index *old) nogil
46
delta_index * create_delta_index(source_info *src, delta_index *old)
48
47
delta_index * create_delta_index_from_delta(source_info *delta,
49
delta_index *old) nogil
50
void free_delta_index(delta_index *index) nogil
49
void free_delta_index(delta_index *index)
51
50
void *create_delta(delta_index *indexes,
52
51
void *buf, unsigned long bufsize,
53
unsigned long *delta_size, unsigned long max_delta_size) nogil
52
unsigned long *delta_size, unsigned long max_delta_size)
54
53
unsigned long get_delta_hdr_size(unsigned char **datap,
55
unsigned char *top) nogil
56
55
Py_ssize_t DELTA_SIZE_MIN
56
void *patch_delta(void *src_buf, unsigned long src_size,
57
void *delta_buf, unsigned long delta_size,
58
unsigned long *dst_size)
59
61
cdef void *safe_malloc(size_t count) except NULL:
145
144
src.buf = c_delta
146
145
src.size = c_delta_size
147
146
src.agg_offset = self._source_offset + unadded_bytes
149
index = create_delta_index_from_delta(src, self._index)
147
index = create_delta_index_from_delta(src, self._index)
150
148
self._source_offset = src.agg_offset + src.size
151
149
if index != NULL:
152
150
free_delta_index(self._index)
172
170
source_location = len(self._sources)
173
171
if source_location >= self._max_num_sources:
174
172
self._expand_sources()
175
if source_location != 0 and self._index == NULL:
176
# We were lazy about populating the index, create it now
177
self._populate_first_index()
178
173
self._sources.append(source)
179
174
c_source = PyString_AS_STRING(source)
180
175
c_source_size = PyString_GET_SIZE(source)
183
178
src.size = c_source_size
185
180
src.agg_offset = self._source_offset + unadded_bytes
181
index = create_delta_index(src, self._index)
186
182
self._source_offset = src.agg_offset + src.size
187
# We delay creating the index on the first insert
188
if source_location != 0:
190
index = create_delta_index(src, self._index)
192
free_delta_index(self._index)
195
cdef _populate_first_index(self):
196
cdef delta_index *index
197
if len(self._sources) != 1 or self._index != NULL:
198
raise AssertionError('_populate_first_index should only be'
199
' called when we have a single source and no index yet')
201
# We know that self._index is already NULL, so whatever
202
# create_delta_index returns is fine
204
self._index = create_delta_index(&self._source_infos[0], NULL)
205
assert self._index != NULL
184
free_delta_index(self._index)
207
187
cdef _expand_sources(self):
208
188
raise RuntimeError('if we move self._source_infos, then we need to'
218
198
cdef Py_ssize_t target_size
219
199
cdef void * delta
220
200
cdef unsigned long delta_size
221
cdef unsigned long c_max_delta_size
223
202
if self._index == NULL:
224
if len(self._sources) == 0:
226
# We were just lazy about generating the index
227
self._populate_first_index()
229
205
if not PyString_CheckExact(target_bytes):
230
206
raise TypeError('target is not a str')
235
211
# TODO: inline some of create_delta so we at least don't have to double
236
212
# malloc, and can instead use PyString_FromStringAndSize, to
237
213
# allocate the bytes into the final string
238
c_max_delta_size = max_delta_size
240
delta = create_delta(self._index,
242
&delta_size, c_max_delta_size)
214
delta = create_delta(self._index,
216
&delta_size, max_delta_size)
245
219
result = PyString_FromStringAndSize(<char *>delta, delta_size)
281
255
cdef unsigned char *_decode_copy_instruction(unsigned char *bytes,
282
unsigned char cmd, unsigned int *offset,
283
unsigned int *length) nogil: # cannot_raise
256
unsigned char cmd, unsigned int *offset, unsigned int *length):
284
257
"""Decode a copy instruction from the next few bytes.
286
259
A copy instruction is a variable number of bytes, so we will parse the
340
312
result = PyString_FromStringAndSize(NULL, size)
341
313
dst_buf = <unsigned char*>PyString_AS_STRING(result)
351
data = _decode_copy_instruction(data, cmd, &cp_off, &cp_size)
352
if (cp_off + cp_size < cp_size or
353
cp_off + cp_size > source_size or
357
memcpy(out, source + cp_off, cp_size)
359
size = size - cp_size
363
# cmd == 0 is reserved for future encoding
364
# extensions. In the mean time we must fail when
365
# encountering them (might be data corruption).
371
memcpy(out, data, cmd)
377
raise ValueError('Something wrong with:'
378
' cp_off = %s, cp_size = %s'
379
' source_size = %s, size = %s'
380
% (cp_off, cp_size, source_size, size))
382
raise ValueError('Got delta opcode: 0, not supported')
384
raise ValueError('Insert instruction longer than remaining'
385
' bytes: %d > %d' % (cmd, size))
321
data = _decode_copy_instruction(data, cmd, &cp_off, &cp_size)
322
if (cp_off + cp_size < cp_size or
323
cp_off + cp_size > source_size or
325
raise RuntimeError('Something wrong with:'
326
' cp_off = %s, cp_size = %s'
327
' source_size = %s, size = %s'
328
% (cp_off, cp_size, source_size, size))
329
memcpy(out, source + cp_off, cp_size)
331
size = size - cp_size
335
# cmd == 0 is reserved for future encoding
336
# extensions. In the mean time we must fail when
337
# encountering them (might be data corruption).
338
raise RuntimeError('Got delta opcode: 0, not supported')
340
raise RuntimeError('Insert instruction longer than remaining'
341
' bytes: %d > %d' % (cmd, size))
342
memcpy(out, data, cmd)
388
348
if (data != top or size != 0):