43
38
def add_copy(self, start_byte, end_byte):
44
39
# The data stream allows >64kB in a copy, but to match the compiled
45
40
# code, we will also limit it to a 64kB copy
46
for start_byte in range(start_byte, end_byte, 64*1024):
41
for start_byte in xrange(start_byte, end_byte, 64*1024):
47
42
num_bytes = min(64*1024, end_byte - start_byte)
48
43
copy_bytes = encode_copy_instruction(start_byte, num_bytes)
49
44
self.out_lines.append(copy_bytes)
55
50
if self.cur_insert_len > 127:
56
51
raise AssertionError('We cannot insert more than 127 bytes'
58
self.out_lines.append(int2byte(self.cur_insert_len))
53
self.out_lines.append(chr(self.cur_insert_len))
59
54
self.index_lines.append(False)
60
55
self.out_lines.extend(self.cur_insert_lines)
61
56
if self.cur_insert_len < self.min_len_to_index:
69
64
# Flush out anything pending
70
65
self._flush_insert()
71
66
line_len = len(line)
72
for start_index in range(0, line_len, 127):
67
for start_index in xrange(0, line_len, 127):
73
68
next_len = min(127, line_len - start_index)
74
self.out_lines.append(int2byte(next_len))
69
self.out_lines.append(chr(next_len))
75
70
self.index_lines.append(False)
76
71
self.out_lines.append(line[start_index:start_index+next_len])
77
72
# We don't index long lines, because we won't be able to match
133
128
matches[line].add(start_idx + idx)
135
matches[line] = {start_idx + idx}
130
matches[line] = set([start_idx + idx])
137
132
def get_matches(self, line):
138
133
"""Return the lines which match the line in right."""
258
253
def _flush_insert(self, start_linenum, end_linenum,
259
254
new_lines, out_lines, index_lines):
260
255
"""Add an 'insert' request to the data stream."""
261
bytes_to_insert = b''.join(new_lines[start_linenum:end_linenum])
256
bytes_to_insert = ''.join(new_lines[start_linenum:end_linenum])
262
257
insert_length = len(bytes_to_insert)
263
258
# Each insert instruction is at most 127 bytes long
264
for start_byte in range(0, insert_length, 127):
259
for start_byte in xrange(0, insert_length, 127):
265
260
insert_count = min(insert_length - start_byte, 127)
266
out_lines.append(int2byte(insert_count))
261
out_lines.append(chr(insert_count))
267
262
# Don't index the 'insert' instruction
268
263
index_lines.append(False)
269
264
insert = bytes_to_insert[start_byte:start_byte+insert_count]
281
276
num_bytes = stop_byte - first_byte
282
277
# The data stream allows >64kB in a copy, but to match the compiled
283
278
# code, we will also limit it to a 64kB copy
284
for start_byte in range(first_byte, stop_byte, 64*1024):
279
for start_byte in xrange(first_byte, stop_byte, 64*1024):
285
280
num_bytes = min(64*1024, stop_byte - start_byte)
286
281
copy_bytes = encode_copy_instruction(start_byte, num_bytes)
287
282
out_lines.append(copy_bytes)
292
287
if bytes_length is None:
293
288
bytes_length = sum(map(len, new_lines))
294
289
# reserved for content type, content length
295
out_lines = [b'', b'', encode_base128_int(bytes_length)]
290
out_lines = ['', '', encode_base128_int(bytes_length)]
296
291
index_lines = [False, False, False]
297
292
output_handler = _OutputHandler(out_lines, index_lines,
298
293
self._MIN_MATCH_BYTES)
319
314
def encode_base128_int(val):
320
315
"""Convert an integer into a 7-bit lsb encoding."""
323
318
while val >= 0x80:
324
data.append((val | 0x80) & 0xFF)
319
bytes.append(chr((val | 0x80) & 0xFF))
330
def decode_base128_int(data):
321
bytes.append(chr(val))
322
return ''.join(bytes)
325
def decode_base128_int(bytes):
331
326
"""Decode an integer from a 7-bit lsb encoding."""
335
bval = indexbytes(data, offset)
330
bval = ord(bytes[offset])
336
331
while bval >= 0x80:
337
332
val |= (bval & 0x7F) << shift
340
bval = indexbytes(data, offset)
335
bval = ord(bytes[offset])
341
336
val |= bval << shift
343
338
return val, offset
367
362
base_byte = length & 0xff
369
364
copy_command |= copy_bit
370
copy_bytes.append(int2byte(base_byte))
365
copy_bytes.append(chr(base_byte))
372
copy_bytes[0] = int2byte(copy_command)
373
return b''.join(copy_bytes)
367
copy_bytes[0] = chr(copy_command)
368
return ''.join(copy_bytes)
376
371
def decode_copy_instruction(bytes, cmd, pos):
395
offset = indexbytes(bytes, pos)
390
offset = ord(bytes[pos])
398
offset = offset | (indexbytes(bytes, pos) << 8)
393
offset = offset | (ord(bytes[pos]) << 8)
401
offset = offset | (indexbytes(bytes, pos) << 16)
396
offset = offset | (ord(bytes[pos]) << 16)
404
offset = offset | (indexbytes(bytes, pos) << 24)
399
offset = offset | (ord(bytes[pos]) << 24)
407
length = indexbytes(bytes, pos)
402
length = ord(bytes[pos])
410
length = length | (indexbytes(bytes, pos) << 8)
405
length = length | (ord(bytes[pos]) << 8)
413
length = length | (indexbytes(bytes, pos) << 16)
408
length = length | (ord(bytes[pos]) << 16)
420
415
def make_delta(source_bytes, target_bytes):
421
416
"""Create a delta from source to target."""
422
if not isinstance(source_bytes, bytes):
423
raise TypeError('source is not bytes')
424
if not isinstance(target_bytes, bytes):
425
raise TypeError('target is not bytes')
417
if type(source_bytes) is not str:
418
raise TypeError('source is not a str')
419
if type(target_bytes) is not str:
420
raise TypeError('target is not a str')
426
421
line_locations = LinesDeltaIndex(osutils.split_lines(source_bytes))
427
422
delta, _ = line_locations.make_delta(osutils.split_lines(target_bytes),
428
423
bytes_length=len(target_bytes))
429
return b''.join(delta)
424
return ''.join(delta)
432
427
def apply_delta(basis, delta):
433
428
"""Apply delta to this object to become new_version_id."""
434
if not isinstance(basis, bytes):
435
raise TypeError('basis is not bytes')
436
if not isinstance(delta, bytes):
437
raise TypeError('delta is not bytes')
429
if type(basis) is not str:
430
raise TypeError('basis is not a str')
431
if type(delta) is not str:
432
raise TypeError('delta is not a str')
438
433
target_length, pos = decode_base128_int(delta)
440
435
len_delta = len(delta)
441
436
while pos < len_delta:
442
cmd = indexbytes(delta, pos)
437
cmd = ord(delta[pos])
445
440
offset, length, pos = decode_copy_instruction(delta, cmd, pos)
453
448
raise ValueError('Command == 0 not supported yet')
454
449
lines.append(delta[pos:pos+cmd])
456
data = b''.join(lines)
457
if len(data) != target_length:
451
bytes = ''.join(lines)
452
if len(bytes) != target_length:
458
453
raise ValueError('Delta claimed to be %d long, but ended up'
459
454
' %d long' % (target_length, len(bytes)))
463
458
def apply_delta_to_source(source, delta_start, delta_end):