24
24
void memcpy(void *, void *, size_t)
26
26
cdef extern from "delta.h":
30
unsigned long agg_offset
27
31
struct delta_index:
28
32
unsigned long memsize
30
34
unsigned long src_size
31
35
unsigned int hash_mask
32
36
# struct index_entry *hash[]
33
delta_index * create_delta_index(void *buf, unsigned long bufsize, unsigned
37
delta_index * create_delta_index(source_info *src)
35
38
void free_delta_index(delta_index *index)
36
39
void *create_delta(delta_index **indexes,
37
40
unsigned int num_indexes,
84
87
# isn't performance critical
85
88
# cdef readonly list _sources
86
89
cdef readonly object _sources
90
cdef source_info *_source_infos
87
91
cdef delta_index **_indexes
88
92
cdef readonly unsigned int _num_indexes
89
93
cdef readonly unsigned int _max_num_indexes
94
cdef readonly unsigned int _max_num_sources
90
95
cdef public unsigned long _source_offset
92
97
def __repr__(self):
108
116
def __dealloc__(self):
109
117
self._ensure_no_indexes()
118
safe_free(<void **>&self._source_infos)
111
120
def add_source(self, source, unadded_bytes):
112
121
"""Add a new bit of source text to the delta indexes.
118
127
cdef char *c_source
119
128
cdef Py_ssize_t c_source_size
120
129
cdef delta_index *index
130
cdef unsigned int source_location
131
cdef source_info *src
121
132
cdef unsigned int num_indexes
122
cdef unsigned long agg_src_offset
124
134
if not PyString_CheckExact(source):
125
135
raise TypeError('source is not a str')
137
source_location = len(self._sources)
138
if source_location >= self._max_num_sources:
139
self._expand_sources()
127
140
self._sources.append(source)
128
141
c_source = PyString_AS_STRING(source)
129
142
c_source_size = PyString_GET_SIZE(source)
143
src = self._source_infos + source_location
145
src.size = c_source_size
131
147
# TODO: Are usage is ultimately going to be different than the one that
132
148
# was originally designed. Specifically, we are going to want to
134
150
# fit just fine into the structure. But for now, we just wrap
135
151
# create_delta_index (For example, we could always reserve enough
136
152
# space to hash a 4MB string, etc.)
137
agg_src_offset = self._source_offset + unadded_bytes
138
index = create_delta_index(c_source, c_source_size, agg_src_offset)
139
self._source_offset = agg_src_offset + c_source_size
153
src.agg_offset = self._source_offset + unadded_bytes
154
index = create_delta_index(src)
155
self._source_offset = src.agg_offset + src.size
140
156
if index != NULL:
141
157
num_indexes = self._num_indexes + 1
142
158
if num_indexes >= self._max_num_indexes:
150
166
sizeof(delta_index *)
151
167
* self._max_num_indexes)
169
cdef _expand_sources(self):
170
self._max_num_sources = self._max_num_sources * 2
171
self._source_infos = <source_info *>safe_realloc(self._source_infos,
173
* self._max_num_sources)
153
175
cdef _ensure_no_indexes(self):
194
216
def make_delta(source_bytes, target_bytes):
195
"""Create a delta from source_bytes => target_bytes."""
197
cdef Py_ssize_t source_size
199
cdef Py_ssize_t target_size
200
cdef delta_index *index
202
cdef unsigned long delta_size
203
cdef unsigned long max_delta_size
205
max_delta_size = 0 # Unlimited
207
if not PyString_CheckExact(source_bytes):
208
raise TypeError('source is not a str')
209
if not PyString_CheckExact(target_bytes):
210
raise TypeError('target is not a str')
212
source = PyString_AS_STRING(source_bytes)
213
source_size = PyString_GET_SIZE(source_bytes)
214
target = PyString_AS_STRING(target_bytes)
215
target_size = PyString_GET_SIZE(target_bytes)
218
index = create_delta_index(source, source_size, 0)
220
delta = create_delta(&index, 1, target, target_size,
221
&delta_size, max_delta_size)
222
free_delta_index(index);
224
result = PyString_FromStringAndSize(<char *>delta, delta_size)
217
"""Create a delta, this is a wrapper around DeltaIndex.make_delta."""
218
di = DeltaIndex(source_bytes)
219
return di.make_delta(target_bytes)
229
222
def apply_delta(source_bytes, delta_bytes):
341
334
# *dst_size = out - dst_buf;
342
335
assert (out - dst_buf) == PyString_GET_SIZE(result)
346
def apply_delta2(source_bytes, delta_bytes):
347
"""Apply a delta generated by make_delta to source_bytes."""
348
# This defers to the patch-delta code rather than implementing it here
349
# If this is faster, we can bring the memory allocation and error handling
350
# into apply_delta(), and leave the primary loop in a separate C func.
351
cdef char *source, *delta, *target
352
cdef Py_ssize_t source_size, delta_size
353
cdef unsigned long target_size
355
if not PyString_CheckExact(source_bytes):
356
raise TypeError('source is not a str')
357
if not PyString_CheckExact(delta_bytes):
358
raise TypeError('delta is not a str')
360
source = PyString_AS_STRING(source_bytes)
361
source_size = PyString_GET_SIZE(source_bytes)
362
delta = PyString_AS_STRING(delta_bytes)
363
delta_size = PyString_GET_SIZE(delta_bytes)
365
target = <char *>patch_delta(source, source_size,
370
result = PyString_FromStringAndSize(target, target_size)