~moody/ips

cb299c23ec8270a86863785b7b71fdb40efab2a3 — Jacob Moody 1 year, 7 months ago cc747ea
refactor and add ipsdiff
3 files changed, 130 insertions(+), 4 deletions(-)

A ipsdiff.c
R ips.c => ipspatch.c
M mkfile
A ipsdiff.c => ipsdiff.c +121 -0
@@ 0,0 1,121 @@
#include <u.h>
#include <libc.h>
#include <bio.h>

#define PUT2(p, u) (p)[0] = (u)>>8, (p)[1] = (u)
#define PUT3(p, u) (p)[0] = (u)>>16, (p)[1] = (u)>>8, (p)[2] = (u)

Biobuf *ips;
typedef struct Bin Bin;
struct Bin{
	int fd;
	long dot;
	long n, off;
	uchar data[0xFFFF];
};

static Bin base, modded;
static int dump = 0;

static long
slurp(Bin *b)
{
	long n;

	n = readn(b->fd, b->data + b->off, sizeof b->data - b->off);
	if(n < 0)
		sysfatal("read: %r");
	b->n = b->off + n;
	return n;
}

static void
emit(u32int off, uchar *data, u16int size)
{
	uchar buf[3 + 2];

	if(size == 0)
		return;
	PUT3(buf, off);
	PUT2(buf+3, size);
	if(dump)
		fprint(2, "%ud %ud\n", off, size);
	if(Bwrite(ips, buf, sizeof buf) != sizeof buf)
		sysfatal("Bwrite: %r");
	if(Bwrite(ips, data, size) != size)
		sysfatal("Bwrite: %r");
}

static void
diff(Bin *a, Bin *b)
{
	uchar *ap, *bp;
	uchar *ac, *bc;
	uchar *ae, *be;
	int x;

	ap = a->data;
	bp = b->data;
	ae = a->data + a->n;
	be = b->data + b->n;

	if(a->n != b->n)
		sysfatal("desync: %ld %ld", a->n, a->n);

	while(ap < ae && bp < be){
		if(*ap == *bp){
			ap++;
			bp++;
			continue;
		}
		// FIXME: better way of expanding diff context
		x = 32;
		for(ac = ap, bc = bp; ac < ae && bc < be; ac++, bc++){
			if(--x <= 0 && *ac == *bc)
				break;
		}
		emit(a->dot + (ap - a->data), bp, bc - bp);
		ap = ac;
		bp = bc;
	}
	a->dot += a->n;
	b->dot += b->n;
}

void
usage(void)
{
	fprint(2, "usage: %s base modified >patch.ips", argv0);
	exits("usage");
}

void
main(int argc, char **argv)
{
	ARGBEGIN{
	case 'd':
		dump++;
		break;
	default:
		usage();
	}ARGEND;
	if(argc < 2)
		usage();

	ips = Bfdopen(1, OWRITE);
	if(ips == nil)
		sysfatal("Bfdopen: %r");
	Bwrite(ips, "PATCH", 5);

	base.fd = open(argv[0], OREAD);
	modded.fd = open(argv[1], OREAD);
	if(base.fd < 0 || modded.fd < 0)
		sysfatal("open: %r");

	while(slurp(&base) != 0 && slurp(&modded) != 0)
		diff(&base, &modded);

	Bwrite(ips, "EOF", 3);
	Bflush(ips);
	exits(nil);
}

R ips.c => ipspatch.c +5 -0
@@ 12,6 12,7 @@ enum{

static uchar section[Hdrsz + 0xFFFF + RLEsz];
static Biobuf *ips;
static int dump = 0;

static int
readsect(u32int *off, u16int *sz)


@@ 37,6 38,7 @@ readsect(u32int *off, u16int *sz)
		*sz = count;
	} else if(Bread(ips, section + Hdrsz, *sz) != *sz)
		sysfatal("short read of data: %r");
	//fprint(2, "%ud %ud\n", *off, *sz);
	return 1;
}



@@ 57,6 59,9 @@ main(int argc, char **argv)
	u16int sz;

	ARGBEGIN{
	case 'd':
		dump++;
		break;
	default:
		usage();
	}ARGEND;

M mkfile => mkfile +4 -4
@@ 1,8 1,8 @@
</$objtype/mkfile

BIN=$home/bin/$objtype
TARG=ips
OFILES=\
	ips.$O\
TARG=\
	ipsdiff\
	ipspatch\

</sys/src/cmd/mkone
</sys/src/cmd/mkmany