xref: /plan9-contrib/sys/src/nboot/bitsy/inflate.c (revision 529c1f209803c78c4f2cda11b13818a57f01c872)
1*529c1f20SDavid du Colombier #include "u.h"
2*529c1f20SDavid du Colombier #include "lib.h"
3*529c1f20SDavid du Colombier #include "mem.h"
4*529c1f20SDavid du Colombier #include "dat.h"
5*529c1f20SDavid du Colombier #include "fns.h"
6*529c1f20SDavid du Colombier #include "io.h"
7*529c1f20SDavid du Colombier #include <flate.h>
8*529c1f20SDavid du Colombier 
9*529c1f20SDavid du Colombier typedef struct Biobuf	Biobuf;
10*529c1f20SDavid du Colombier 
11*529c1f20SDavid du Colombier struct Biobuf
12*529c1f20SDavid du Colombier {
13*529c1f20SDavid du Colombier 	uchar *bp;
14*529c1f20SDavid du Colombier 	uchar *p;
15*529c1f20SDavid du Colombier 	uchar *ep;
16*529c1f20SDavid du Colombier };
17*529c1f20SDavid du Colombier 
18*529c1f20SDavid du Colombier static int	header(Biobuf*);
19*529c1f20SDavid du Colombier static int	trailer(Biobuf*, Biobuf*);
20*529c1f20SDavid du Colombier static int	getc(void*);
21*529c1f20SDavid du Colombier static ulong	offset(Biobuf*);
22*529c1f20SDavid du Colombier static int	crcwrite(void *out, void *buf, int n);
23*529c1f20SDavid du Colombier static ulong	get4(Biobuf *b);
24*529c1f20SDavid du Colombier static ulong	Boffset(Biobuf *bp);
25*529c1f20SDavid du Colombier 
26*529c1f20SDavid du Colombier /* GZIP flags */
27*529c1f20SDavid du Colombier enum {
28*529c1f20SDavid du Colombier 	Ftext=		(1<<0),
29*529c1f20SDavid du Colombier 	Fhcrc=		(1<<1),
30*529c1f20SDavid du Colombier 	Fextra=		(1<<2),
31*529c1f20SDavid du Colombier 	Fname=		(1<<3),
32*529c1f20SDavid du Colombier 	Fcomment=	(1<<4),
33*529c1f20SDavid du Colombier 
34*529c1f20SDavid du Colombier 	GZCRCPOLY	= 0xedb88320UL,
35*529c1f20SDavid du Colombier };
36*529c1f20SDavid du Colombier 
37*529c1f20SDavid du Colombier static ulong	*crctab;
38*529c1f20SDavid du Colombier static ulong	crc;
39*529c1f20SDavid du Colombier 
40*529c1f20SDavid du Colombier int
gunzip(uchar * out,int outn,uchar * in,int inn)41*529c1f20SDavid du Colombier gunzip(uchar *out, int outn, uchar *in, int inn)
42*529c1f20SDavid du Colombier {
43*529c1f20SDavid du Colombier 	Biobuf bin, bout;
44*529c1f20SDavid du Colombier 	int err;
45*529c1f20SDavid du Colombier 
46*529c1f20SDavid du Colombier 	crc = 0;
47*529c1f20SDavid du Colombier 	crctab = mkcrctab(GZCRCPOLY);
48*529c1f20SDavid du Colombier 	err = inflateinit();
49*529c1f20SDavid du Colombier 	if(err != FlateOk)
50*529c1f20SDavid du Colombier 		print("inflateinit failed: %s\n", flateerr(err));
51*529c1f20SDavid du Colombier 
52*529c1f20SDavid du Colombier 	bin.bp = bin.p = in;
53*529c1f20SDavid du Colombier 	bin.ep = in+inn;
54*529c1f20SDavid du Colombier 	bout.bp = bout.p = out;
55*529c1f20SDavid du Colombier 	bout.ep = out+outn;
56*529c1f20SDavid du Colombier 
57*529c1f20SDavid du Colombier 	err = header(&bin);
58*529c1f20SDavid du Colombier 	if(err != FlateOk)
59*529c1f20SDavid du Colombier 		return err;
60*529c1f20SDavid du Colombier 
61*529c1f20SDavid du Colombier 	err = inflate(&bout, crcwrite, &bin, getc);
62*529c1f20SDavid du Colombier 	if(err != FlateOk)
63*529c1f20SDavid du Colombier 		print("inflate failed: %s\n", flateerr(err));
64*529c1f20SDavid du Colombier 
65*529c1f20SDavid du Colombier 	err = trailer(&bout, &bin);
66*529c1f20SDavid du Colombier 	if(err != FlateOk)
67*529c1f20SDavid du Colombier 		return err;
68*529c1f20SDavid du Colombier 
69*529c1f20SDavid du Colombier 	return Boffset(&bout);
70*529c1f20SDavid du Colombier }
71*529c1f20SDavid du Colombier 
72*529c1f20SDavid du Colombier static int
header(Biobuf * bin)73*529c1f20SDavid du Colombier header(Biobuf *bin)
74*529c1f20SDavid du Colombier {
75*529c1f20SDavid du Colombier 	int i, flag;
76*529c1f20SDavid du Colombier 
77*529c1f20SDavid du Colombier 	if(getc(bin) != 0x1f || getc(bin) != 0x8b){
78*529c1f20SDavid du Colombier 		print("bad magic\n");
79*529c1f20SDavid du Colombier 		return FlateCorrupted;
80*529c1f20SDavid du Colombier 	}
81*529c1f20SDavid du Colombier 	if(getc(bin) != 8){
82*529c1f20SDavid du Colombier 		print("unknown compression type\n");
83*529c1f20SDavid du Colombier 		return FlateCorrupted;
84*529c1f20SDavid du Colombier 	}
85*529c1f20SDavid du Colombier 
86*529c1f20SDavid du Colombier 	flag = getc(bin);
87*529c1f20SDavid du Colombier 
88*529c1f20SDavid du Colombier 	/* mod time */
89*529c1f20SDavid du Colombier 	get4(bin);
90*529c1f20SDavid du Colombier 
91*529c1f20SDavid du Colombier 	/* extra flags */
92*529c1f20SDavid du Colombier 	getc(bin);
93*529c1f20SDavid du Colombier 
94*529c1f20SDavid du Colombier 	/* OS type */
95*529c1f20SDavid du Colombier 	getc(bin);
96*529c1f20SDavid du Colombier 
97*529c1f20SDavid du Colombier 	if(flag & Fextra)
98*529c1f20SDavid du Colombier 		for(i=getc(bin); i>0; i--)
99*529c1f20SDavid du Colombier 			getc(bin);
100*529c1f20SDavid du Colombier 
101*529c1f20SDavid du Colombier 	/* name */
102*529c1f20SDavid du Colombier 	if(flag&Fname)
103*529c1f20SDavid du Colombier 		while(getc(bin) != 0)
104*529c1f20SDavid du Colombier 			;
105*529c1f20SDavid du Colombier 
106*529c1f20SDavid du Colombier 	/* comment */
107*529c1f20SDavid du Colombier 	if(flag&Fcomment)
108*529c1f20SDavid du Colombier 		while(getc(bin) != 0)
109*529c1f20SDavid du Colombier 			;
110*529c1f20SDavid du Colombier 
111*529c1f20SDavid du Colombier 	/* crc16 */
112*529c1f20SDavid du Colombier 	if(flag&Fhcrc) {
113*529c1f20SDavid du Colombier 		getc(bin);
114*529c1f20SDavid du Colombier 		getc(bin);
115*529c1f20SDavid du Colombier 	}
116*529c1f20SDavid du Colombier 
117*529c1f20SDavid du Colombier 	return FlateOk;
118*529c1f20SDavid du Colombier }
119*529c1f20SDavid du Colombier 
120*529c1f20SDavid du Colombier static int
trailer(Biobuf * bout,Biobuf * bin)121*529c1f20SDavid du Colombier trailer(Biobuf *bout, Biobuf *bin)
122*529c1f20SDavid du Colombier {
123*529c1f20SDavid du Colombier 	/* crc32 */
124*529c1f20SDavid du Colombier 	ulong x;
125*529c1f20SDavid du Colombier 
126*529c1f20SDavid du Colombier 	x = get4(bin);
127*529c1f20SDavid du Colombier 	if(crc != x){
128*529c1f20SDavid du Colombier 		print("crc mismatch %lux %lux\n", crc, x);
129*529c1f20SDavid du Colombier 		return FlateCorrupted;
130*529c1f20SDavid du Colombier 	}
131*529c1f20SDavid du Colombier 
132*529c1f20SDavid du Colombier 	/* length */
133*529c1f20SDavid du Colombier 	if(get4(bin) != Boffset(bout)){
134*529c1f20SDavid du Colombier 		print("bad output len\n");
135*529c1f20SDavid du Colombier 		return FlateCorrupted;
136*529c1f20SDavid du Colombier 	}
137*529c1f20SDavid du Colombier 	return FlateOk;
138*529c1f20SDavid du Colombier }
139*529c1f20SDavid du Colombier 
140*529c1f20SDavid du Colombier static ulong
get4(Biobuf * b)141*529c1f20SDavid du Colombier get4(Biobuf *b)
142*529c1f20SDavid du Colombier {
143*529c1f20SDavid du Colombier 	ulong v;
144*529c1f20SDavid du Colombier 	int i, c;
145*529c1f20SDavid du Colombier 
146*529c1f20SDavid du Colombier 	v = 0;
147*529c1f20SDavid du Colombier 	for(i = 0; i < 4; i++){
148*529c1f20SDavid du Colombier 		c = getc(b);
149*529c1f20SDavid du Colombier 		v |= c << (i * 8);
150*529c1f20SDavid du Colombier 	}
151*529c1f20SDavid du Colombier 	return v;
152*529c1f20SDavid du Colombier }
153*529c1f20SDavid du Colombier 
154*529c1f20SDavid du Colombier static int
getc(void * in)155*529c1f20SDavid du Colombier getc(void *in)
156*529c1f20SDavid du Colombier {
157*529c1f20SDavid du Colombier 	Biobuf *bp = in;
158*529c1f20SDavid du Colombier 
159*529c1f20SDavid du Colombier 	if((bp->p - bp->bp) % 10000 == 0)
160*529c1f20SDavid du Colombier 		print(".");
161*529c1f20SDavid du Colombier 	if(bp->p >= bp->ep)
162*529c1f20SDavid du Colombier 		return -1;
163*529c1f20SDavid du Colombier 	return *bp->p++;
164*529c1f20SDavid du Colombier }
165*529c1f20SDavid du Colombier 
166*529c1f20SDavid du Colombier static ulong
Boffset(Biobuf * bp)167*529c1f20SDavid du Colombier Boffset(Biobuf *bp)
168*529c1f20SDavid du Colombier {
169*529c1f20SDavid du Colombier 	return bp->p - bp->bp;
170*529c1f20SDavid du Colombier }
171*529c1f20SDavid du Colombier 
172*529c1f20SDavid du Colombier static int
crcwrite(void * out,void * buf,int n)173*529c1f20SDavid du Colombier crcwrite(void *out, void *buf, int n)
174*529c1f20SDavid du Colombier {
175*529c1f20SDavid du Colombier 	Biobuf *bp;
176*529c1f20SDavid du Colombier 
177*529c1f20SDavid du Colombier 	crc = blockcrc(crctab, crc, buf, n);
178*529c1f20SDavid du Colombier 	bp = out;
179*529c1f20SDavid du Colombier 	if(n > bp->ep-bp->p)
180*529c1f20SDavid du Colombier 		n = bp->ep-bp->p;
181*529c1f20SDavid du Colombier 	memmove(bp->p, buf, n);
182*529c1f20SDavid du Colombier 	bp->p += n;
183*529c1f20SDavid du Colombier 	return n;
184*529c1f20SDavid du Colombier }
185*529c1f20SDavid du Colombier 
186*529c1f20SDavid du Colombier #undef malloc
187*529c1f20SDavid du Colombier #undef free
188*529c1f20SDavid du Colombier 
189*529c1f20SDavid du Colombier static ulong ibrkp = ~0;
190*529c1f20SDavid du Colombier 
191*529c1f20SDavid du Colombier void *
malloc(ulong n)192*529c1f20SDavid du Colombier malloc(ulong n)
193*529c1f20SDavid du Colombier {
194*529c1f20SDavid du Colombier 	ulong rv;
195*529c1f20SDavid du Colombier 
196*529c1f20SDavid du Colombier 	if(ibrkp == ~0)
197*529c1f20SDavid du Colombier 		ibrkp = ((ulong)end)+1024*1024;
198*529c1f20SDavid du Colombier 	n = (n+3)>>2;
199*529c1f20SDavid du Colombier 	n <<= 2;
200*529c1f20SDavid du Colombier 	rv = ibrkp;
201*529c1f20SDavid du Colombier 	ibrkp += n;
202*529c1f20SDavid du Colombier 	return (void*)rv;
203*529c1f20SDavid du Colombier }
204*529c1f20SDavid du Colombier 
205*529c1f20SDavid du Colombier void
free(void *)206*529c1f20SDavid du Colombier free(void *)
207*529c1f20SDavid du Colombier {
208*529c1f20SDavid du Colombier }
209