Skip to content

Instantly share code, notes, and snippets.

@abrasive
Last active August 30, 2024 11:19
Show Gist options
  • Select an option

  • Save abrasive/b858be553ac6985eed75d1c194964901 to your computer and use it in GitHub Desktop.

Select an option

Save abrasive/b858be553ac6985eed75d1c194964901 to your computer and use it in GitHub Desktop.
#!/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