bsdiff4 1.3.0__cp312-cp312-win_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bsdiff4/__init__.py +9 -0
- bsdiff4/cli.py +94 -0
- bsdiff4/core.cp312-win_arm64.pyd +0 -0
- bsdiff4/format.py +119 -0
- bsdiff4/test_all.py +164 -0
- bsdiff4-1.3.0.dist-info/METADATA +85 -0
- bsdiff4-1.3.0.dist-info/RECORD +11 -0
- bsdiff4-1.3.0.dist-info/WHEEL +5 -0
- bsdiff4-1.3.0.dist-info/entry_points.txt +3 -0
- bsdiff4-1.3.0.dist-info/licenses/LICENSE +156 -0
- bsdiff4-1.3.0.dist-info/top_level.txt +1 -0
bsdiff4/__init__.py
ADDED
bsdiff4/cli.py
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
from __future__ import absolute_import
|
|
2
|
+
|
|
3
|
+
from os.path import getsize
|
|
4
|
+
from optparse import OptionParser
|
|
5
|
+
|
|
6
|
+
from bsdiff4.format import file_diff, file_patch, read_patch
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def display_version():
|
|
10
|
+
from bsdiff4 import __version__
|
|
11
|
+
print("bsdiff4 %s" % __version__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def human_bytes(n):
|
|
15
|
+
"""
|
|
16
|
+
return the number of bytes 'n' in more human readable form
|
|
17
|
+
"""
|
|
18
|
+
if n < 1024:
|
|
19
|
+
return '%i B' % n
|
|
20
|
+
k = (n - 1) / 1024 + 1
|
|
21
|
+
if k < 1024:
|
|
22
|
+
return '%i KB' % k
|
|
23
|
+
return '%.2f MB' % (float(n) / (2 ** 20))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def main_bsdiff4():
|
|
27
|
+
p = OptionParser(
|
|
28
|
+
usage="usage: %prog [options] SRC DST PATCH",
|
|
29
|
+
description=("generate a BSDIFF4-format PATCH from SRC to DST "
|
|
30
|
+
"and write it to PATCH"))
|
|
31
|
+
|
|
32
|
+
p.add_option('-v', "--verbose",
|
|
33
|
+
action="store_true")
|
|
34
|
+
|
|
35
|
+
p.add_option("--version",
|
|
36
|
+
action="store_true")
|
|
37
|
+
|
|
38
|
+
opts, args = p.parse_args()
|
|
39
|
+
|
|
40
|
+
if opts.version:
|
|
41
|
+
display_version()
|
|
42
|
+
return
|
|
43
|
+
|
|
44
|
+
if len(args) != 3:
|
|
45
|
+
p.error('requies 3 arguments, try -h')
|
|
46
|
+
|
|
47
|
+
file_diff(*args)
|
|
48
|
+
if opts.verbose:
|
|
49
|
+
size = [getsize(args[i]) for i in range(3)]
|
|
50
|
+
print('src: %s' % human_bytes(size[0]))
|
|
51
|
+
print('dst: %s' % human_bytes(size[1]))
|
|
52
|
+
print('patch: %s (%.2f%% of dst)' % (human_bytes(size[2]),
|
|
53
|
+
100.0 * size[2] / size[1]))
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def show_patch(patch_path):
|
|
57
|
+
s_total = getsize(patch_path)
|
|
58
|
+
fi = open(patch_path, 'rb')
|
|
59
|
+
s_control, s_diff, s_dst, tcontrol = read_patch(fi, header_only=True)
|
|
60
|
+
fi.close()
|
|
61
|
+
s_extra = s_total - 32 - s_control - s_diff
|
|
62
|
+
|
|
63
|
+
for var_name in 'total', 'control', 'diff', 'extra', 'dst':
|
|
64
|
+
size = eval('s_' + var_name)
|
|
65
|
+
print('%s size: %d (%s)' % (var_name, size, human_bytes(size)))
|
|
66
|
+
print('total / dst = %.2f%%' % (100.0 * s_total / s_dst))
|
|
67
|
+
print('number of control tuples: %d' % len(tcontrol))
|
|
68
|
+
#for t in tcontrol:
|
|
69
|
+
# print('%20d %10d %10d' % t)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def main_bspatch4():
|
|
73
|
+
p = OptionParser(
|
|
74
|
+
usage="usage: %prog [options] SRC DST PATCH",
|
|
75
|
+
description=("genertaes DST, by applying the BSDIFF4-format PATCH "
|
|
76
|
+
"file to SRC"))
|
|
77
|
+
|
|
78
|
+
p.add_option("--version",
|
|
79
|
+
action="store_true")
|
|
80
|
+
|
|
81
|
+
opts, args = p.parse_args()
|
|
82
|
+
|
|
83
|
+
if opts.version:
|
|
84
|
+
display_version()
|
|
85
|
+
return
|
|
86
|
+
|
|
87
|
+
if len(args) == 1:
|
|
88
|
+
show_patch(args[0])
|
|
89
|
+
return
|
|
90
|
+
|
|
91
|
+
if len(args) != 3:
|
|
92
|
+
p.error('requies 3 arguments, try -h')
|
|
93
|
+
|
|
94
|
+
file_patch(*args)
|
|
Binary file
|
bsdiff4/format.py
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import bz2
|
|
2
|
+
import sys
|
|
3
|
+
from io import BytesIO
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
MAGIC = b'BSDIFF40'
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
import bsdiff4.core as core
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def write_patch(fo, len_dst, tcontrol, bdiff, bextra):
|
|
13
|
+
"""write a BSDIFF4-format patch to stream 'fo'
|
|
14
|
+
"""
|
|
15
|
+
fo.write(MAGIC)
|
|
16
|
+
faux = BytesIO()
|
|
17
|
+
# write control tuples as series of offts
|
|
18
|
+
for c in tcontrol:
|
|
19
|
+
for x in c:
|
|
20
|
+
faux.write(core.encode_int64(x))
|
|
21
|
+
# compress each block
|
|
22
|
+
bcontrol = bz2.compress(faux.getvalue())
|
|
23
|
+
bdiff = bz2.compress(bdiff)
|
|
24
|
+
bextra = bz2.compress(bextra)
|
|
25
|
+
for n in len(bcontrol), len(bdiff), len_dst:
|
|
26
|
+
fo.write(core.encode_int64(n))
|
|
27
|
+
fo.write(bcontrol)
|
|
28
|
+
fo.write(bdiff)
|
|
29
|
+
fo.write(bextra)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def read_patch(fi, header_only=False):
|
|
33
|
+
"""read a BSDIFF4-format patch from stream 'fi'
|
|
34
|
+
"""
|
|
35
|
+
magic = fi.read(8)
|
|
36
|
+
if magic[:7] != MAGIC[:7]:
|
|
37
|
+
raise ValueError("incorrect magic bsdiff4 header")
|
|
38
|
+
# length headers
|
|
39
|
+
len_control = core.decode_int64(fi.read(8))
|
|
40
|
+
len_diff = core.decode_int64(fi.read(8))
|
|
41
|
+
len_dst = core.decode_int64(fi.read(8))
|
|
42
|
+
# read the control header
|
|
43
|
+
bcontrol = bz2.decompress(fi.read(len_control))
|
|
44
|
+
tcontrol = [(core.decode_int64(bcontrol[i:i + 8]),
|
|
45
|
+
core.decode_int64(bcontrol[i + 8:i + 16]),
|
|
46
|
+
core.decode_int64(bcontrol[i + 16:i + 24]))
|
|
47
|
+
for i in range(0, len(bcontrol), 24)]
|
|
48
|
+
if header_only:
|
|
49
|
+
return len_control, len_diff, len_dst, tcontrol
|
|
50
|
+
# read the diff and extra blocks
|
|
51
|
+
bdiff = bz2.decompress(fi.read(len_diff))
|
|
52
|
+
bextra = bz2.decompress(fi.read())
|
|
53
|
+
return len_dst, tcontrol, bdiff, bextra
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def read_data(path):
|
|
57
|
+
with open(path, 'rb') as fi:
|
|
58
|
+
data = fi.read()
|
|
59
|
+
return data
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def diff(src_bytes, dst_bytes):
|
|
63
|
+
"""diff(src_bytes, dst_bytes) -> bytes
|
|
64
|
+
|
|
65
|
+
Return a BSDIFF4-format patch (from src_bytes to dst_bytes) as bytes.
|
|
66
|
+
"""
|
|
67
|
+
faux = BytesIO()
|
|
68
|
+
write_patch(faux, len(dst_bytes), *core.diff(src_bytes, dst_bytes))
|
|
69
|
+
return faux.getvalue()
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def file_diff(src_path, dst_path, patch_path):
|
|
73
|
+
"""file_diff(src_path, dst_path, patch_path)
|
|
74
|
+
|
|
75
|
+
Write a BSDIFF4-format patch (from the file src_path to the file dst_path)
|
|
76
|
+
to the file patch_path.
|
|
77
|
+
"""
|
|
78
|
+
src = read_data(src_path)
|
|
79
|
+
dst = read_data(dst_path)
|
|
80
|
+
with open(patch_path, 'wb') as fo:
|
|
81
|
+
write_patch(fo, len(dst), *core.diff(src, dst))
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def patch(src_bytes, patch_bytes):
|
|
85
|
+
"""patch(src_bytes, patch_bytes) -> bytes
|
|
86
|
+
|
|
87
|
+
Apply the BSDIFF4-format patch_bytes to src_bytes and return the bytes.
|
|
88
|
+
"""
|
|
89
|
+
return core.patch(src_bytes, *read_patch(BytesIO(patch_bytes)))
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def file_patch_inplace(path, patch_path):
|
|
93
|
+
"""file_patch_inplace(path, patch_path)
|
|
94
|
+
|
|
95
|
+
Apply the BSDIFF4-format file patch_path to the file 'path' in place.
|
|
96
|
+
"""
|
|
97
|
+
with open(patch_path, 'rb') as fi:
|
|
98
|
+
with open(path, 'r+b') as fo:
|
|
99
|
+
data = fo.read()
|
|
100
|
+
fo.seek(0)
|
|
101
|
+
fo.write(core.patch(data, *read_patch(fi)))
|
|
102
|
+
fo.truncate()
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def file_patch(src_path, dst_path, patch_path):
|
|
106
|
+
"""file_patch(src_path, dst_path, patch_path)
|
|
107
|
+
|
|
108
|
+
Apply the BSDIFF4-format file patch_path to the file src_path and
|
|
109
|
+
write the result to the file dst_path.
|
|
110
|
+
"""
|
|
111
|
+
from os.path import abspath
|
|
112
|
+
|
|
113
|
+
if abspath(dst_path) == abspath(src_path):
|
|
114
|
+
file_patch_inplace(src_path, patch_path)
|
|
115
|
+
return
|
|
116
|
+
|
|
117
|
+
with open(patch_path, 'rb') as fi:
|
|
118
|
+
with open(dst_path, 'wb') as fo:
|
|
119
|
+
fo.write(core.patch(read_data(src_path), *read_patch(fi)))
|
bsdiff4/test_all.py
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
from __future__ import absolute_import
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
import random
|
|
6
|
+
import shutil
|
|
7
|
+
import unittest
|
|
8
|
+
import tempfile
|
|
9
|
+
|
|
10
|
+
import bsdiff4.core as core
|
|
11
|
+
import bsdiff4.format as format
|
|
12
|
+
from bsdiff4 import diff, patch, file_diff, file_patch, file_patch_inplace
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
N = 2 ** 63 - 1
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class TestEncode(unittest.TestCase):
|
|
19
|
+
|
|
20
|
+
def test_special_values(self):
|
|
21
|
+
for n, b in [
|
|
22
|
+
(-N, b'\xff\xff\xff\xff\xff\xff\xff\xff'),
|
|
23
|
+
(-256, b'\x00\x01\x00\x00\x00\x00\x00\x80'),
|
|
24
|
+
(-128, b'\x80\x00\x00\x00\x00\x00\x00\x80'),
|
|
25
|
+
(-1, b'\x01\x00\x00\x00\x00\x00\x00\x80'),
|
|
26
|
+
(0, b'\x00\x00\x00\x00\x00\x00\x00\x00'),
|
|
27
|
+
(1, b'\x01\x00\x00\x00\x00\x00\x00\x00'),
|
|
28
|
+
(127, b'\x7f\x00\x00\x00\x00\x00\x00\x00'),
|
|
29
|
+
(128, b'\x80\x00\x00\x00\x00\x00\x00\x00'),
|
|
30
|
+
(129, b'\x81\x00\x00\x00\x00\x00\x00\x00'),
|
|
31
|
+
(255, b'\xff\x00\x00\x00\x00\x00\x00\x00'),
|
|
32
|
+
(256, b'\x00\x01\x00\x00\x00\x00\x00\x00'),
|
|
33
|
+
(257, b'\x01\x01\x00\x00\x00\x00\x00\x00'),
|
|
34
|
+
(N, b'\xff\xff\xff\xff\xff\xff\xff\x7f'),
|
|
35
|
+
]:
|
|
36
|
+
self.assertEqual(core.encode_int64(n), b)
|
|
37
|
+
self.assertEqual(core.decode_int64(b), n)
|
|
38
|
+
|
|
39
|
+
def test_errors(self):
|
|
40
|
+
self.assertRaises(TypeError, core.encode_int64, 'x')
|
|
41
|
+
self.assertRaises(TypeError, core.decode_int64, 12345)
|
|
42
|
+
self.assertRaises(ValueError, core.decode_int64, 7 * b'a')
|
|
43
|
+
self.assertRaises(ValueError, core.decode_int64, 9 * b'b')
|
|
44
|
+
|
|
45
|
+
def test_random(self):
|
|
46
|
+
for dum in range(1000):
|
|
47
|
+
n = random.randint(-N, N)
|
|
48
|
+
b = core.encode_int64(n)
|
|
49
|
+
self.assertEqual(len(b), 8)
|
|
50
|
+
self.assertEqual(core.decode_int64(b), n)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class TestFormat(unittest.TestCase):
|
|
54
|
+
|
|
55
|
+
def round_trip(self, src, dst):
|
|
56
|
+
p = diff(src, dst)
|
|
57
|
+
#print(len(src), len(p))
|
|
58
|
+
dst2 = patch(src, p)
|
|
59
|
+
self.assertEqual(dst, dst2)
|
|
60
|
+
|
|
61
|
+
def test_zero(self):
|
|
62
|
+
self.round_trip(b'', b'')
|
|
63
|
+
|
|
64
|
+
def test_extra(self):
|
|
65
|
+
src = os.urandom(1000)
|
|
66
|
+
dst = src + os.urandom(10)
|
|
67
|
+
self.round_trip(src, dst)
|
|
68
|
+
self.round_trip(dst, src)
|
|
69
|
+
|
|
70
|
+
def test_small(self): # issue #14
|
|
71
|
+
src = b'123456789 987654321'
|
|
72
|
+
dst = b'123456789000987654321'
|
|
73
|
+
self.round_trip(src, dst)
|
|
74
|
+
self.round_trip(dst, src)
|
|
75
|
+
|
|
76
|
+
def test_random(self):
|
|
77
|
+
for _ in range(100):
|
|
78
|
+
n1 = random.randint(0, 1000)
|
|
79
|
+
n2 = random.randint(0, 1000)
|
|
80
|
+
self.round_trip(os.urandom(n1), os.urandom(n2))
|
|
81
|
+
|
|
82
|
+
def test_large(self):
|
|
83
|
+
a = os.urandom(50000)
|
|
84
|
+
b = os.urandom(40000)
|
|
85
|
+
src = a + os.urandom(100) + b
|
|
86
|
+
dst = a + os.urandom(100) + b
|
|
87
|
+
self.round_trip(src, dst)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class TestFile(unittest.TestCase):
|
|
91
|
+
|
|
92
|
+
def setUp(self):
|
|
93
|
+
self.tmpdir = tempfile.mkdtemp()
|
|
94
|
+
|
|
95
|
+
def tearDown(self):
|
|
96
|
+
shutil.rmtree(self.tmpdir)
|
|
97
|
+
|
|
98
|
+
def path(self, fn):
|
|
99
|
+
return os.path.join(self.tmpdir, fn)
|
|
100
|
+
|
|
101
|
+
def assert_same_file_content(self, fn1, fn2):
|
|
102
|
+
data1 = format.read_data(self.path(fn1))
|
|
103
|
+
data2 = format.read_data(self.path(fn2))
|
|
104
|
+
self.assertEqual(data1, data2)
|
|
105
|
+
|
|
106
|
+
def round_trip(self):
|
|
107
|
+
# write file 'patch'
|
|
108
|
+
file_diff(self.path('src'), self.path('dst'), self.path('patch'))
|
|
109
|
+
# write file 'dst2'
|
|
110
|
+
file_patch(self.path('src'), self.path('dst2'), self.path('patch'))
|
|
111
|
+
# compare files 'dst' and 'dst2'
|
|
112
|
+
self.assert_same_file_content('dst', 'dst2')
|
|
113
|
+
# patch 'src' in place
|
|
114
|
+
file_patch(self.path('src'), self.path('src'), self.path('patch'))
|
|
115
|
+
self.assert_same_file_content('src', 'dst')
|
|
116
|
+
|
|
117
|
+
def write_data(self, fn, data):
|
|
118
|
+
with open(self.path(fn), 'wb') as fo:
|
|
119
|
+
fo.write(data)
|
|
120
|
+
|
|
121
|
+
def test_wrong_header(self):
|
|
122
|
+
path = self.path('foo')
|
|
123
|
+
self.write_data(path, b"WRONG_HEADER")
|
|
124
|
+
with open(path, "rb") as fi:
|
|
125
|
+
self.assertRaises(ValueError, format.read_patch, fi)
|
|
126
|
+
|
|
127
|
+
def test_1(self):
|
|
128
|
+
a = 1000 * b'ABCDE'
|
|
129
|
+
b = 1000 * b'XYZ'
|
|
130
|
+
self.write_data('src', a + os.urandom(100) + b)
|
|
131
|
+
self.write_data('dst', a + os.urandom(100) + b)
|
|
132
|
+
self.round_trip()
|
|
133
|
+
|
|
134
|
+
def test_2(self):
|
|
135
|
+
a = 10000 * b'ABCDEFG'
|
|
136
|
+
self.write_data('src', a)
|
|
137
|
+
self.write_data('dst', a + b'extra bytes at the end')
|
|
138
|
+
self.round_trip()
|
|
139
|
+
|
|
140
|
+
def test_inplace(self):
|
|
141
|
+
a = 1000 * b'ABCDE'
|
|
142
|
+
b = 1000 * b'XYZ'
|
|
143
|
+
self.write_data('src', a + os.urandom(100) + b)
|
|
144
|
+
self.write_data('dst', a + os.urandom(100) + b)
|
|
145
|
+
file_diff(self.path('src'), self.path('dst'), self.path('patch'))
|
|
146
|
+
file_patch_inplace(self.path('src'), self.path('patch'))
|
|
147
|
+
self.assert_same_file_content('src', 'dst')
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def run(verbosity=1):
|
|
151
|
+
from . import __version__
|
|
152
|
+
print('Python version: %s' % sys.version)
|
|
153
|
+
print('bsdiff4 is installed in: %s' % os.path.dirname(__file__))
|
|
154
|
+
print('bsdiff4 version: %s' % __version__)
|
|
155
|
+
|
|
156
|
+
loader = unittest.TestLoader()
|
|
157
|
+
suite = unittest.TestSuite()
|
|
158
|
+
suite.addTests(loader.loadTestsFromModule(sys.modules[__name__]))
|
|
159
|
+
runner = unittest.TextTestRunner(verbosity=verbosity)
|
|
160
|
+
return runner.run(suite)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
if __name__ == '__main__':
|
|
164
|
+
unittest.main()
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bsdiff4
|
|
3
|
+
Version: 1.3.0
|
|
4
|
+
Summary: binary diff and patch using the BSDIFF4-format
|
|
5
|
+
Home-page: https://github.com/ilanschnell/bsdiff4
|
|
6
|
+
Author: Ilan Schnell
|
|
7
|
+
Author-email: ilanschnell@gmail.com
|
|
8
|
+
License: BSD
|
|
9
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: C
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
23
|
+
Classifier: Topic :: Utilities
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Dynamic: author
|
|
26
|
+
Dynamic: author-email
|
|
27
|
+
Dynamic: classifier
|
|
28
|
+
Dynamic: description
|
|
29
|
+
Dynamic: home-page
|
|
30
|
+
Dynamic: license
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
Dynamic: summary
|
|
33
|
+
|
|
34
|
+
=======================================================
|
|
35
|
+
bsdiff4: binary diff and patch using the BSDIFF4-format
|
|
36
|
+
=======================================================
|
|
37
|
+
|
|
38
|
+
The code is mostly derived from cx_bsdiff (written by Anthony Tuininga,
|
|
39
|
+
http://cx-bsdiff.sourceforge.net/). The cx_bsdiff code in turn was derived
|
|
40
|
+
from bsdiff, the standalone utility produced for BSD which can be found
|
|
41
|
+
at http://www.daemonology.net/bsdiff.
|
|
42
|
+
In addition to the two functions (diff and patch) cx_bsdiff provides, this
|
|
43
|
+
package includes:
|
|
44
|
+
|
|
45
|
+
* an interface to the BSDIFF4-format
|
|
46
|
+
* command line interfaces: bsdiff4 and bspatch4
|
|
47
|
+
* tests
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
The bsdiff4 package defines the following high level functions:
|
|
51
|
+
|
|
52
|
+
``diff(src_bytes, dst_bytes)`` -> bytes
|
|
53
|
+
Return a BSDIFF4-format patch (from ``src_bytes`` to ``dst_bytes``) as
|
|
54
|
+
bytes.
|
|
55
|
+
|
|
56
|
+
``patch(src_bytes, patch_bytes)`` -> bytes
|
|
57
|
+
Apply the BSDIFF4-format ``patch_bytes`` to ``src_bytes`` and return
|
|
58
|
+
the bytes.
|
|
59
|
+
|
|
60
|
+
``file_diff(src_path, dst_path, patch_path)``
|
|
61
|
+
Write a BSDIFF4-format patch (from the file ``src_path`` to the
|
|
62
|
+
file ``dst_path``) to the file ``patch_path``.
|
|
63
|
+
|
|
64
|
+
``file_patch(src_path, dst_path, patch_path)``
|
|
65
|
+
Apply the BSDIFF4-format file ``patch_path`` to the file ``src_path``
|
|
66
|
+
and write the result to the file ``dst_path``.
|
|
67
|
+
|
|
68
|
+
``file_patch_inplace(path, patch_path)``
|
|
69
|
+
Apply the BSDIFF4-format file ``patch_path`` to the file ``path``
|
|
70
|
+
in place.
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
Example:
|
|
74
|
+
|
|
75
|
+
.. code-block:: python
|
|
76
|
+
|
|
77
|
+
>>> import bsdiff4
|
|
78
|
+
>>> a = 100000 * b'a'
|
|
79
|
+
>>> b = bytearray(a)
|
|
80
|
+
>>> b[100:106] = b' diff '
|
|
81
|
+
>>> p = bsdiff4.diff(a, bytes(b))
|
|
82
|
+
>>> len(p)
|
|
83
|
+
154
|
|
84
|
+
>>> bsdiff4.patch(a, p) == b
|
|
85
|
+
True
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
bsdiff4/__init__.py,sha256=uD-wSA2liY7LD3pcPBJ_MDxlPi0jGsUDLV8NOEG6MmI,235
|
|
2
|
+
bsdiff4/cli.py,sha256=TYDrcsIHtKAnL6nIqpoJJ9iRq40lKs0EnzEBMYaZZWA,2603
|
|
3
|
+
bsdiff4/core.cp312-win_arm64.pyd,sha256=ac8RQiwDxiThTILsxTlyO3UEocDLTXeiq9rS80s772w,17920
|
|
4
|
+
bsdiff4/format.py,sha256=SLRULsyLtCjwTVhTCyOMcPsRXExZsMqay89mIhSJg_w,3604
|
|
5
|
+
bsdiff4/test_all.py,sha256=rClODbNA0YpBZIb94Twgf5VtmruGVCZQtYfHxzgTTpQ,5394
|
|
6
|
+
bsdiff4-1.3.0.dist-info/licenses/LICENSE,sha256=FuNPTpHAVJMAMJvZiD52afLpYqgpNQyqDUxRR2P4PgQ,8486
|
|
7
|
+
bsdiff4-1.3.0.dist-info/METADATA,sha256=4ydDEYd8Td5q0e_YOT4ChKW5cBcQFTEcekKtiH3_cB4,2838
|
|
8
|
+
bsdiff4-1.3.0.dist-info/WHEEL,sha256=tpnnFzlMRXtBlhRYqrPGibHbOlqmThF0q8oKK-muSzM,101
|
|
9
|
+
bsdiff4-1.3.0.dist-info/entry_points.txt,sha256=9-ctLCIhmwihoYlF4S15zv5gksMRd9UqhUqmWmLRaXs,90
|
|
10
|
+
bsdiff4-1.3.0.dist-info/top_level.txt,sha256=1upCuxINieZyLC4s1zsrmG3UqQfCi0vKqeRDmpjCk3E,8
|
|
11
|
+
bsdiff4-1.3.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
Copyright (c) 2011-2025, Ilan Schnell
|
|
2
|
+
All rights reserved.
|
|
3
|
+
|
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
|
6
|
+
|
|
7
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
8
|
+
list of conditions and the following disclaimer.
|
|
9
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
10
|
+
this list of conditions and the following disclaimer in the documentation
|
|
11
|
+
and/or other materials provided with the distribution.
|
|
12
|
+
|
|
13
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
14
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
15
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
16
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
17
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
18
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
19
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
20
|
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
21
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
22
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
23
|
+
|
|
24
|
+
The views and conclusions contained in the software and documentation are those
|
|
25
|
+
of the authors and should not be interpreted as representing official policies,
|
|
26
|
+
either expressed or implied, of the (Python) bsdiff4 project.
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
/***************************************************************************
|
|
30
|
+
* the module bsdiff4/core.c has been drived from cx_bsdiff written by *
|
|
31
|
+
* Anthony Tuininga, http://cx-bsdiff.sourceforge.net/), which was *
|
|
32
|
+
* released under the BSD Protection License below *
|
|
33
|
+
***************************************************************************/
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
BSD Protection License
|
|
37
|
+
February 2002
|
|
38
|
+
|
|
39
|
+
Preamble
|
|
40
|
+
--------
|
|
41
|
+
|
|
42
|
+
The Berkeley Software Distribution ("BSD") license has proven very effective
|
|
43
|
+
over the years at allowing for a wide spread of work throughout both
|
|
44
|
+
commercial and non-commercial products. For programmers whose primary
|
|
45
|
+
intention is to improve the general quality of available software, it is
|
|
46
|
+
arguable that there is no better license than the BSD license, as it
|
|
47
|
+
permits improvements to be used wherever they will help, without idealogical
|
|
48
|
+
or metallic constraint.
|
|
49
|
+
|
|
50
|
+
This is of particular value to those who produce reference implementations
|
|
51
|
+
of proposed standards: The case of TCP/IP clearly illustrates that freely
|
|
52
|
+
and universally available implementations leads the rapid acceptance of
|
|
53
|
+
standards -- often even being used instead of a de jure standard (eg, OSI
|
|
54
|
+
network models).
|
|
55
|
+
|
|
56
|
+
With the rapid proliferation of software licensed under the GNU General
|
|
57
|
+
Public License, however, the continued success of this role is called into
|
|
58
|
+
question. Given that the inclusion of a few lines of "GPL-tainted" work
|
|
59
|
+
into a larger body of work will result in restricted distribution -- and
|
|
60
|
+
given that further work will likely build upon the "tainted" portions,
|
|
61
|
+
making them difficult to remove at a future date -- there are inevitable
|
|
62
|
+
circumstances where authors would, in order to protect their goal of
|
|
63
|
+
providing for the widespread usage of their work, wish to guard against
|
|
64
|
+
such "GPL-taint".
|
|
65
|
+
|
|
66
|
+
In addition, one can imagine that companies which operate by producing and
|
|
67
|
+
selling (possibly closed-source) code would wish to protect themselves
|
|
68
|
+
against the rise of a GPL-licensed competitor. While under existing
|
|
69
|
+
licenses this would mean not releasing their code under any form of open
|
|
70
|
+
license, if a license existed under which they could incorporate any
|
|
71
|
+
improvements back into their own (commercial) products then they might be
|
|
72
|
+
far more willing to provide for non-closed distribution.
|
|
73
|
+
|
|
74
|
+
For the above reasons, we put forth this "BSD Protection License": A
|
|
75
|
+
license designed to retain the freedom granted by the BSD license to use
|
|
76
|
+
licensed works in a wide variety of settings, both non-commercial and
|
|
77
|
+
commercial, while protecting the work from having future contributors
|
|
78
|
+
restrict that freedom.
|
|
79
|
+
|
|
80
|
+
The precise terms and conditions for copying, distribution, and
|
|
81
|
+
modification follow.
|
|
82
|
+
|
|
83
|
+
BSD PROTECTION LICENSE
|
|
84
|
+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION, AND MODIFICATION
|
|
85
|
+
----------------------------------------------------------------
|
|
86
|
+
|
|
87
|
+
0. Definitions.
|
|
88
|
+
a) "Program", below, refers to any program or work distributed under
|
|
89
|
+
the terms of this license.
|
|
90
|
+
b) A "work based on the Program", below, refers to either the Program
|
|
91
|
+
or any derivative work under copyright law.
|
|
92
|
+
c) "Modification", below, refers to the act of creating derivative works.
|
|
93
|
+
d) "You", below, refers to each licensee.
|
|
94
|
+
|
|
95
|
+
1. Scope.
|
|
96
|
+
This license governs the copying, distribution, and modification of the
|
|
97
|
+
Program. Other activities are outside the scope of this license; The
|
|
98
|
+
act of running the Program is not restricted, and the output from the
|
|
99
|
+
Program is covered only if its contents constitute a work based on the
|
|
100
|
+
Program.
|
|
101
|
+
|
|
102
|
+
2. Verbatim copies.
|
|
103
|
+
You may copy and distribute verbatim copies of the Program as you
|
|
104
|
+
receive it, in any medium, provided that you conspicuously and
|
|
105
|
+
appropriately publish on each copy an appropriate copyright notice; keep
|
|
106
|
+
intact all the notices that refer to this License and to the absence of
|
|
107
|
+
any warranty; and give any other recipients of the Program a copy of this
|
|
108
|
+
License along with the Program.
|
|
109
|
+
|
|
110
|
+
3. Modification and redistribution under closed license.
|
|
111
|
+
You may modify your copy or copies of the Program, and distribute
|
|
112
|
+
the resulting derivative works, provided that you meet the
|
|
113
|
+
following conditions:
|
|
114
|
+
a) The copyright notice and disclaimer on the Program must be reproduced
|
|
115
|
+
and included in the source code, documentation, and/or other materials
|
|
116
|
+
provided in a manner in which such notices are normally distributed.
|
|
117
|
+
b) The derivative work must be clearly identified as such, in order that
|
|
118
|
+
it may not be confused with the original work.
|
|
119
|
+
c) The license under which the derivative work is distributed must
|
|
120
|
+
expressly prohibit the distribution of further derivative works.
|
|
121
|
+
|
|
122
|
+
4. Modification and redistribution under open license.
|
|
123
|
+
You may modify your copy or copies of the Program, and distribute
|
|
124
|
+
the resulting derivative works, provided that you meet the
|
|
125
|
+
following conditions:
|
|
126
|
+
a) The copyright notice and disclaimer on the Program must be reproduced
|
|
127
|
+
and included in the source code, documentation, and/or other materials
|
|
128
|
+
provided in a manner in which such notices are normally distributed.
|
|
129
|
+
b) You must clearly indicate the nature and date of any changes made
|
|
130
|
+
to the Program. The full details need not necessarily be included in
|
|
131
|
+
the individual modified files, provided that each modified file is
|
|
132
|
+
clearly marked as such and instructions are included on where the
|
|
133
|
+
full details of the modifications may be found.
|
|
134
|
+
c) You must cause any work that you distribute or publish, that in whole
|
|
135
|
+
or in part contains or is derived from the Program or any part
|
|
136
|
+
thereof, to be licensed as a whole at no charge to all third
|
|
137
|
+
parties under the terms of this License.
|
|
138
|
+
|
|
139
|
+
5. Implied acceptance.
|
|
140
|
+
You may not copy or distribute the Program or any derivative works except
|
|
141
|
+
as expressly provided under this license. Consequently, any such action
|
|
142
|
+
will be taken as implied acceptance of the terms of this license.
|
|
143
|
+
|
|
144
|
+
6. NO WARRANTY.
|
|
145
|
+
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
146
|
+
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
147
|
+
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
|
148
|
+
THE COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
|
149
|
+
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE FOR ANY DIRECT,
|
|
150
|
+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
151
|
+
ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING, BUT
|
|
152
|
+
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
|
153
|
+
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
154
|
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
|
155
|
+
TORT, EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
|
156
|
+
POSSIBILITY OF SUCH DAMAGES.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
bsdiff4
|