Skip to content

Instantly share code, notes, and snippets.

@ryonsherman
Last active August 29, 2015 14:22
Show Gist options
  • Save ryonsherman/0792f8ef03424e12c132 to your computer and use it in GitHub Desktop.
Save ryonsherman/0792f8ef03424e12c132 to your computer and use it in GitHub Desktop.
Binary diff + yEnc encoding
% ./usenetpatch.py --help
usage: usenetpatch.py [-h] {diff,patch} ...
positional arguments:
{diff,patch} mode
diff diff mode
patch patch mode
optional arguments:
-h, --help show this help message and exit
% md5sum a.png
2c953dc7ba29ecd119f05bd97d4ef584 a.png
% md5sum b.png
c1576f1ee3b7ea5569707bd4e732fc9c b.png
% ./usenetpatch.py diff a.png b.png c.patch
Writing 365666 bytes to c.patch - crc32: 9d30f5cb
% ./usenetpatch.py patch a.png c.patch c.png
Writing 370128 bytes to c.png
% md5sum c.png
c1576f1ee3b7ea5569707bd4e732fc9c c.png
#!/usr/bin/python3
import os
import io
import yenc
import bsdiff4
import argparse
# define 'diff' method
def diff(file_1, file_2):
file_1 = bytes(open(file_1, 'rb').read())
file_2 = bytes(open(file_2, 'rb').read())
diff = io.BytesIO(bsdiff4.diff(file_1, file_2))
patch = io.BytesIO()
size, crc = yenc.encode(diff, patch)
patch.seek(0)
return patch, size, crc
# define 'patch' method
def patch(file_1, file_2, crc=None):
file_1 = bytes(open(file_1, 'rb').read())
patch = io.BytesIO()
yenc.decode(open(args.patch, 'rb'), patch, crc_in=crc)
patch.seek(0)
patch = bytes(patch.read())
file_2 = bsdiff4.patch(file_1, patch)
return file_2, len(file_2)
# initialize argument parser
parser = argparse.ArgumentParser()
# initialize 'mode' argument parser
subparsers = parser.add_subparsers(dest='mode', help='mode')
# initialize 'diff' mode parser
diff_parser = subparsers.add_parser('diff', help='diff mode')
diff_parser.add_argument('file_1', help='original file')
diff_parser.add_argument('file_2', help='modified file')
diff_parser.add_argument('patch', help='patch file')
# initialize 'patch' mode parser
patch_parser = subparsers.add_parser('patch', help='patch mode')
patch_parser.add_argument('file_1', help='original file')
patch_parser.add_argument('patch', help='patch file')
patch_parser.add_argument('file_2', help='modified file')
patch_parser.add_argument('--crc', help='crc checksum')
# parse arguments
args = parser.parse_args()
# perform 'diff' method
if args.mode == 'diff':
patch, size, crc = diff(args.file_1, args.file_2)
with open(args.patch, 'wb') as f:
f.write(patch.read())
print("Writing %s bytes to %s - crc32: %s" % (size, args.patch, crc))
# perform 'patch' method
elif args.mode == 'patch':
diff, size = patch(args.file_1, args.patch, args.crc)
with open(args.file_2, 'wb') as f:
f.write(diff)
print("Writing %s bytes to %s" % (size, args.file_2))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment