245
245
return _apply_delta(source, source_size, delta, delta_size)
248
cdef unsigned char *_decode_copy_instruction(unsigned char *bytes,
249
unsigned char cmd, unsigned int *offset, unsigned int *length):
250
"""Decode a copy instruction from the next few bytes.
252
A copy instruction is a variable number of bytes, so we will parse the
253
bytes we care about, and return the new position, as well as the offset and
254
length referred to in the bytes.
256
:param bytes: Pointer to the start of bytes after cmd
257
:param cmd: The command code
258
:return: Pointer to the bytes just after the last decode byte
260
cdef unsigned int off, size, count
268
off = off | (bytes[count] << 8)
271
off = off | (bytes[count] << 16)
274
off = off | (bytes[count] << 24)
280
size = size | (bytes[count] << 8)
283
size = size | (bytes[count] << 16)
248
292
cdef object _apply_delta(char *source, Py_ssize_t source_size,
249
293
char *delta, Py_ssize_t delta_size):
250
294
"""common functionality between apply_delta and apply_delta_to_source."""
251
295
cdef unsigned char *data, *top
252
296
cdef unsigned char *dst_buf, *out, cmd
253
297
cdef Py_ssize_t size
254
cdef unsigned long cp_off, cp_size
298
cdef unsigned int cp_off, cp_size
256
300
data = <unsigned char *>delta
257
301
top = data + delta_size
260
304
size = get_delta_hdr_size(&data, top)
261
305
result = PyString_FromStringAndSize(NULL, size)
262
306
dst_buf = <unsigned char*>PyString_AS_STRING(result)
263
# XXX: The original code added a trailing null here, but this shouldn't be
264
# necessary when using PyString_FromStringAndSize
268
309
while (data < top):
277
cp_off = cp_off | (data[0] << 8)
280
cp_off = cp_off | (data[0] << 16)
283
cp_off = cp_off | (data[0] << 24)
289
cp_size = cp_size | (data[0] << 8)
292
cp_size = cp_size | (data[0] << 16)
314
data = _decode_copy_instruction(data, cmd, &cp_off, &cp_size)
296
315
if (cp_off + cp_size < cp_size or
297
316
cp_off + cp_size > source_size or
303
322
memcpy(out, source + cp_off, cp_size)
304
323
out = out + cp_size
305
324
size = size - cp_size
328
# cmd == 0 is reserved for future encoding
329
# extensions. In the mean time we must fail when
330
# encountering them (might be data corruption).
331
raise RuntimeError('Got delta opcode: 0, not supported')
308
333
raise RuntimeError('Insert instruction longer than remaining'
309
334
' bytes: %d > %d' % (cmd, size))
312
337
data = data + cmd
313
338
size = size - cmd
316
# * cmd == 0 is reserved for future encoding
317
# * extensions. In the mean time we must fail when
318
# * encountering them (might be data corruption).
320
## /* XXX: error("unexpected delta opcode 0"); */
321
raise RuntimeError('Got delta opcode: 0, not supported')
324
341
if (data != top or size != 0):
325
## /* XXX: error("delta replay has gone wild"); */
326
342
raise RuntimeError('Did not extract the number of bytes we expected'
327
343
' we were left with %d bytes in "size", and top - data = %d'
328
344
% (size, <int>(top - data)))
331
347
# *dst_size = out - dst_buf;
332
assert (out - dst_buf) == PyString_GET_SIZE(result)
348
if (out - dst_buf) != PyString_GET_SIZE(result):
349
raise RuntimeError('Number of bytes extracted did not match the'
350
' size encoded in the delta header.')