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
34
32
cdef extern from *:
35
33
ctypedef unsigned long size_t
36
void * malloc(size_t) nogil
37
void * realloc(void *, size_t) nogil
38
void free(void *) nogil
39
void memcpy(void *, void *, size_t) nogil
35
void * realloc(void *, size_t)
37
void memcpy(void *, void *, size_t)
42
40
cdef extern from "delta.h":
46
44
unsigned long agg_offset
47
45
struct delta_index:
49
delta_index * create_delta_index(source_info *src, delta_index *old) nogil
47
delta_index * create_delta_index(source_info *src, delta_index *old)
50
48
delta_index * create_delta_index_from_delta(source_info *delta,
51
delta_index *old) nogil
52
void free_delta_index(delta_index *index) nogil
50
void free_delta_index(delta_index *index)
53
51
void *create_delta(delta_index *indexes,
54
52
void *buf, unsigned long bufsize,
55
unsigned long *delta_size, unsigned long max_delta_size) nogil
53
unsigned long *delta_size, unsigned long max_delta_size)
56
54
unsigned long get_delta_hdr_size(unsigned char **datap,
57
unsigned char *top) nogil
58
unsigned long sizeof_delta_index(delta_index *index)
59
56
Py_ssize_t DELTA_SIZE_MIN
57
void *patch_delta(void *src_buf, unsigned long src_size,
58
void *delta_buf, unsigned long delta_size,
59
unsigned long *dst_size)
62
62
cdef void *safe_malloc(size_t count) except NULL:
94
94
cdef readonly object _sources
95
95
cdef source_info *_source_infos
96
96
cdef delta_index *_index
97
cdef readonly unsigned int _max_num_sources
97
98
cdef public unsigned long _source_offset
98
cdef readonly unsigned int _max_num_sources
100
100
def __init__(self, source=None):
101
101
self._sources = []
108
108
if source is not None:
109
109
self.add_source(source, 0)
111
def __sizeof__(self):
112
# We want to track the _source_infos allocations, but the referenced
113
# void* are actually tracked in _sources itself.
114
# XXX: Cython is capable of doing sizeof(class) and returning the size
115
# of the underlying struct. Pyrex (<= 0.9.9) refuses, so we need
116
# to do it manually. *sigh* Note that we might get it wrong
117
# because of alignment issues.
119
# PyObject start, vtable *, 3 object pointers, 2 C ints
120
size = ((sizeof(PyObject) + sizeof(void*) + 3*sizeof(PyObject*)
121
+ sizeof(unsigned long)
122
+ sizeof(unsigned int))
123
+ (sizeof(source_info) * self._max_num_sources)
124
+ sizeof_delta_index(self._index))
127
111
def __repr__(self):
128
112
return '%s(%d, %d)' % (self.__class__.__name__,
129
113
len(self._sources), self._source_offset)
164
148
src.buf = c_delta
165
149
src.size = c_delta_size
166
150
src.agg_offset = self._source_offset + unadded_bytes
168
index = create_delta_index_from_delta(src, self._index)
151
index = create_delta_index_from_delta(src, self._index)
169
152
self._source_offset = src.agg_offset + src.size
170
153
if index != NULL:
171
154
free_delta_index(self._index)
205
188
self._source_offset = src.agg_offset + src.size
206
189
# We delay creating the index on the first insert
207
190
if source_location != 0:
209
index = create_delta_index(src, self._index)
191
index = create_delta_index(src, self._index)
210
192
if index != NULL:
211
193
free_delta_index(self._index)
212
194
self._index = index
220
202
# We know that self._index is already NULL, so whatever
221
203
# create_delta_index returns is fine
223
self._index = create_delta_index(&self._source_infos[0], NULL)
204
self._index = create_delta_index(&self._source_infos[0], NULL)
224
205
assert self._index != NULL
226
207
cdef _expand_sources(self):
254
234
# TODO: inline some of create_delta so we at least don't have to double
255
235
# malloc, and can instead use PyString_FromStringAndSize, to
256
236
# allocate the bytes into the final string
257
c_max_delta_size = max_delta_size
259
delta = create_delta(self._index,
261
&delta_size, c_max_delta_size)
237
delta = create_delta(self._index,
239
&delta_size, max_delta_size)
264
242
result = PyString_FromStringAndSize(<char *>delta, delta_size)
300
278
cdef unsigned char *_decode_copy_instruction(unsigned char *bytes,
301
unsigned char cmd, unsigned int *offset,
302
unsigned int *length) nogil: # cannot_raise
279
unsigned char cmd, unsigned int *offset, unsigned int *length):
303
280
"""Decode a copy instruction from the next few bytes.
305
282
A copy instruction is a variable number of bytes, so we will parse the
359
335
result = PyString_FromStringAndSize(NULL, size)
360
336
dst_buf = <unsigned char*>PyString_AS_STRING(result)
370
data = _decode_copy_instruction(data, cmd, &cp_off, &cp_size)
371
if (cp_off + cp_size < cp_size or
372
cp_off + cp_size > source_size or
376
memcpy(out, source + cp_off, cp_size)
378
size = size - cp_size
382
# cmd == 0 is reserved for future encoding
383
# extensions. In the mean time we must fail when
384
# encountering them (might be data corruption).
390
memcpy(out, data, cmd)
396
raise ValueError('Something wrong with:'
397
' cp_off = %s, cp_size = %s'
398
' source_size = %s, size = %s'
399
% (cp_off, cp_size, source_size, size))
401
raise ValueError('Got delta opcode: 0, not supported')
403
raise ValueError('Insert instruction longer than remaining'
404
' bytes: %d > %d' % (cmd, size))
344
data = _decode_copy_instruction(data, cmd, &cp_off, &cp_size)
345
if (cp_off + cp_size < cp_size or
346
cp_off + cp_size > source_size or
348
raise RuntimeError('Something wrong with:'
349
' cp_off = %s, cp_size = %s'
350
' source_size = %s, size = %s'
351
% (cp_off, cp_size, source_size, size))
352
memcpy(out, source + cp_off, cp_size)
354
size = size - cp_size
358
# cmd == 0 is reserved for future encoding
359
# extensions. In the mean time we must fail when
360
# encountering them (might be data corruption).
361
raise RuntimeError('Got delta opcode: 0, not supported')
363
raise RuntimeError('Insert instruction longer than remaining'
364
' bytes: %d > %d' % (cmd, size))
365
memcpy(out, data, cmd)
407
371
if (data != top or size != 0):