Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#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;
}