#include <u.h>
#include <libc.h>
#include <flate.h>
#include "load.h"
typedef struct Biobuf Biobuf;
struct Biobuf
{
uchar *bp;
uchar *p;
uchar *ep;
};
static int header(Biobuf*);
static int trailer(Biobuf*, Biobuf*);
static int getc(void*);
static ulong offset(Biobuf*);
static int crcwrite(void *out, void *buf, int n);
static ulong get4(Biobuf *b);
static ulong Boffset(Biobuf *bp);
/* GZIP flags */
enum {
Ftext= (1<<0),
Fhcrc= (1<<1),
Fextra= (1<<2),
Fname= (1<<3),
Fcomment= (1<<4),
GZCRCPOLY = 0xedb88320UL,
};
static ulong *crctab;
static ulong crc;
int
gunzip(uchar *out, int outn, uchar *in, int inn)
{
Biobuf bin, bout;
int err;
crc = 0;
crctab = mkcrctab(GZCRCPOLY);
err = inflateinit();
if(err != FlateOk)
print("inflateinit failed: %s\n", flateerr(err));
bin.bp = bin.p = in;
bin.ep = in+inn;
bout.bp = bout.p = out;
bout.ep = out+outn;
err = header(&bin);
if(err != FlateOk)
return err;
err = inflate(&bout, crcwrite, &bin, getc);
if(err != FlateOk)
print("inflate failed: %s\n", flateerr(err));
err = trailer(&bout, &bin);
if(err != FlateOk)
return err;
return Boffset(&bout);
}
static int
header(Biobuf *bin)
{
int i, flag;
if(getc(bin) != 0x1f || getc(bin) != 0x8b){
print("bad magic\n");
return FlateCorrupted;
}
if(getc(bin) != 8){
print("unknown compression type\n");
return FlateCorrupted;
}
flag = getc(bin);
/* mod time */
get4(bin);
/* extra flags */
getc(bin);
/* OS type */
getc(bin);
if(flag & Fextra)
for(i=getc(bin); i>0; i--)
getc(bin);
/* name */
if(flag&Fname)
while(getc(bin) != 0)
;
/* comment */
if(flag&Fcomment)
while(getc(bin) != 0)
;
/* crc16 */
if(flag&Fhcrc) {
getc(bin);
getc(bin);
}
return FlateOk;
}
static int
trailer(Biobuf *bout, Biobuf *bin)
{
/* crc32 */
if(crc != get4(bin)){
print("crc mismatch\n");
return FlateCorrupted;
}
/* length */
if(get4(bin) != Boffset(bout)){
print("bad output len\n");
return FlateCorrupted;
}
return FlateOk;
}
static ulong
get4(Biobuf *b)
{
ulong v;
int i, c;
v = 0;
for(i = 0; i < 4; i++){
c = getc(b);
v |= c << (i * 8);
}
return v;
}
static int
getc(void *in)
{
Biobuf *bp = in;
// if((bp->p - bp->bp) % 10000 == 0)
// print(".");
if(bp->p >= bp->ep){
print("EOF");
return -1;
}
return *bp->p++;
}
static ulong
Boffset(Biobuf *bp)
{
return bp->p - bp->bp;
}
static int
crcwrite(void *out, void *buf, int n)
{
Biobuf *bp;
int nn;
crc = blockcrc(crctab, crc, buf, n);
bp = out;
nn = n;
if(nn > bp->ep-bp->p)
nn = bp->ep-bp->p;
if(nn > 0)
memmove(bp->p, buf, nn);
bp->p += n;
return n;
}
|