110 lines
1.6 KiB
C
110 lines
1.6 KiB
C
#include <u.h>
|
|
#include <libc.h>
|
|
#include <bio.h>
|
|
|
|
void
|
|
usage(void)
|
|
{
|
|
fprint(2, "usage: unbflz [file]\n");
|
|
exits("usage");
|
|
}
|
|
|
|
int
|
|
Bgetint(Biobuf *b)
|
|
{
|
|
uchar p[4];
|
|
|
|
if(Bread(b, p, 4) != 4)
|
|
sysfatal("short read");
|
|
return (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
|
|
}
|
|
|
|
/*
|
|
* memmove but make sure overlap works properly.
|
|
*/
|
|
void
|
|
copy(uchar *dst, uchar *src, int n)
|
|
{
|
|
while(n-- > 0)
|
|
*dst++ = *src++;
|
|
}
|
|
|
|
void
|
|
main(int argc, char **argv)
|
|
{
|
|
Biobuf *b, bin;
|
|
char buf[5];
|
|
uchar *data;
|
|
ulong *blk, l;
|
|
int nblk, mblk;
|
|
int sum;
|
|
int i, j, length, m, n, o;
|
|
|
|
ARGBEGIN{
|
|
default:
|
|
usage();
|
|
}ARGEND
|
|
|
|
switch(argc){
|
|
default:
|
|
usage();
|
|
case 0:
|
|
Binit(&bin, 0, OREAD);
|
|
b = &bin;
|
|
break;
|
|
case 1:
|
|
if((b = Bopen(argv[0], OREAD)) == nil)
|
|
sysfatal("open %s: %r", argv[0]);
|
|
break;
|
|
}
|
|
|
|
if(Bread(b, buf, 4) != 4)
|
|
sysfatal("short read");
|
|
|
|
if(memcmp(buf, "BLZ\n", 4) != 0)
|
|
sysfatal("bad header");
|
|
|
|
length = Bgetint(b);
|
|
data = malloc(length);
|
|
if(data == nil)
|
|
sysfatal("out of memory");
|
|
sum = 0;
|
|
nblk = 0;
|
|
mblk = 0;
|
|
blk = nil;
|
|
while(sum < length){
|
|
if(nblk>=mblk){
|
|
mblk += 16384;
|
|
blk = realloc(blk, (mblk+1)*sizeof(blk[0]));
|
|
if(blk == nil)
|
|
sysfatal("out of memory");
|
|
}
|
|
l = Bgetint(b);
|
|
blk[nblk++] = l;
|
|
if(l&(1<<31))
|
|
l &= ~(1<<31);
|
|
else
|
|
blk[nblk++] = Bgetint(b);
|
|
sum += l;
|
|
}
|
|
if(sum != length)
|
|
sysfatal("bad compressed data %d %d", sum, length);
|
|
i = 0;
|
|
j = 0;
|
|
while(i < length){
|
|
assert(j < nblk);
|
|
n = blk[j++];
|
|
if(n&(1<<31)){
|
|
n &= ~(1<<31);
|
|
if((m=Bread(b, data+i, n)) != n)
|
|
sysfatal("short read %d %d", n, m);
|
|
}else{
|
|
o = blk[j++];
|
|
copy(data+i, data+o, n);
|
|
}
|
|
i += n;
|
|
}
|
|
write(1, data, length);
|
|
exits(nil);
|
|
}
|