plan9fox/sys/src/cmd/bzfs/unbflz.c

109 lines
1.7 KiB
C

#include <u.h>
#include <libc.h>
#include <bio.h>
#include "bzfs.h"
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++;
}
int
unbflz(int in)
{
int rv, out, p[2];
Biobuf *b, bin;
char buf[5];
uchar *data;
int i, j, length, n, m, o, sum;
ulong *blk;
int nblk, mblk;
if(pipe(p) < 0)
sysfatal("pipe: %r");
rv = p[0];
out = p[1];
switch(rfork(RFPROC|RFFDG|RFNOTEG|RFMEM)){
case -1:
sysfatal("fork: %r");
case 0:
close(rv);
break;
default:
close(in);
close(out);
return rv;
}
Binit(&bin, in, OREAD);
b = &bin;
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");
}
n = Bgetint(b);
blk[nblk++] = n;
if(n&(1<<31))
n &= ~(1<<31);
else
blk[nblk++] = Bgetint(b);
sum += n;
}
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(out, data, length);
close(in);
close(out);
_exits(0);
return -1;
}