Last active
August 30, 2024 11:19
-
-
Save abrasive/b858be553ac6985eed75d1c194964901 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python3 | |
| # Interpret a bsdiff output file. | |
| # Public domain. Authored by abrasive, 2018 | |
| import bz2 | |
| import struct | |
| import sys | |
| import subprocess | |
| if len(sys.argv) != 2: | |
| print("usage: %s bsdiff_output_file" % sys.argv[0]) | |
| sys.exit(1) | |
| inname = sys.argv[1] | |
| fp = open(inname, 'rb') | |
| magic = fp.read(8) | |
| if magic != b"BSDIFF40": | |
| raise IOError("Bad magic") | |
| x, y = struct.unpack('QQ', fp.read(16)) | |
| fp.seek(32, 0) | |
| control = bz2.decompress(fp.read(x)) | |
| diff = bz2.decompress(fp.read(y)) | |
| insert = bz2.decompress(fp.read()) | |
| diff_nonzeros = sum(map(bool, diff)) | |
| print("Total length: %d" % len(diff)) | |
| print("Control bytes: %d" % x) | |
| print("Nonzero diff bytes: %d" % diff_nonzeros) | |
| print("Insert bytes: %d" % len(insert)) | |
| # from the bspatch source: | |
| # ... control block a set of triples (x,y,z) meaning "add x bytes | |
| # from oldfile to x bytes from the diff block; copy y bytes from the | |
| # extra block; seek forwards in oldfile by z bytes". | |
| in_offset = 0 | |
| out_offset = 0 | |
| def offtin(data): | |
| # this is not twos-complement | |
| raw = struct.unpack('<Q', data)[0] | |
| sign = raw >> 63 | |
| masked = raw & ((1<<63)-1) | |
| if sign: | |
| return -masked | |
| else: | |
| return masked | |
| def takeofft(control): | |
| while len(control): | |
| next_word = control[:8] | |
| control = control[8:] | |
| yield offtin(next_word) | |
| def taketuple(control): | |
| offt = takeofft(control) | |
| out = [] | |
| for word in offt: | |
| out.append(word) | |
| if len(out) == 3: | |
| yield tuple(out) | |
| out = [] | |
| for n_copy, n_insert, n_skip in taketuple(control): | |
| if n_copy: | |
| print("in: %08x out: %08x copy %x" % (in_offset, out_offset, n_copy)) | |
| in_offset += n_copy | |
| out_offset += n_copy | |
| if n_insert: | |
| print("in: %08x out: %08x insert:" % (in_offset, out_offset)) | |
| data = insert[:n_insert] | |
| insert = insert[n_insert:] | |
| out_offset += len(data) | |
| subprocess.run(["hexdump", "-C"], input=data).check_returncode() | |
| if n_skip: | |
| print("in: %08x out: %08x skip %x" % (in_offset, out_offset, n_skip)) | |
| in_offset += n_skip |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment