1 /* included by expand and 9boot with different header files */
2
3 typedef struct Biobuf Biobuf;
4
5 struct Biobuf
6 {
7 uchar *bp;
8 uchar *p;
9 uchar *ep;
10 };
11
12 static ulong Boffset(Biobuf *bp);
13 static int crcwrite(void *out, void *buf, int n);
14 static ulong get4(Biobuf *b);
15 static int getc(void*);
16 static int header(Biobuf*);
17 static ulong offset(Biobuf*);
18 static int trailer(Biobuf*, Biobuf*);
19
20 /* GZIP flags */
21 enum {
22 Ftext= (1<<0),
23 Fhcrc= (1<<1),
24 Fextra= (1<<2),
25 Fname= (1<<3),
26 Fcomment= (1<<4),
27
28 GZCRCPOLY = 0xedb88320UL,
29 };
30
31 static ulong *crctab;
32 static ulong crc;
33
34 int
gunzip(uchar * out,int outn,uchar * in,int inn)35 gunzip(uchar *out, int outn, uchar *in, int inn)
36 {
37 Biobuf bin, bout;
38 int err;
39
40 crc = 0;
41 crctab = mkcrctab(GZCRCPOLY);
42 err = inflateinit();
43 if(err != FlateOk)
44 print("inflateinit failed: %s\n", flateerr(err));
45
46 bin.bp = bin.p = in;
47 bin.ep = in+inn;
48 bout.bp = bout.p = out;
49 bout.ep = out+outn;
50
51 err = header(&bin);
52 if(err != FlateOk)
53 return err;
54
55 err = inflate(&bout, crcwrite, &bin, getc);
56 if(err != FlateOk)
57 print("inflate failed: %s\n", flateerr(err));
58
59 err = trailer(&bout, &bin);
60 if(err != FlateOk)
61 return err;
62
63 return Boffset(&bout);
64 }
65
66 static int
header(Biobuf * bin)67 header(Biobuf *bin)
68 {
69 int i, flag;
70
71 if(getc(bin) != 0x1f || getc(bin) != 0x8b){
72 print("bad magic\n");
73 return FlateCorrupted;
74 }
75 if(getc(bin) != 8){
76 print("unknown compression type\n");
77 return FlateCorrupted;
78 }
79
80 flag = getc(bin);
81
82 /* mod time */
83 get4(bin);
84
85 /* extra flags */
86 getc(bin);
87
88 /* OS type */
89 getc(bin);
90
91 if(flag & Fextra)
92 for(i=getc(bin); i>0; i--)
93 getc(bin);
94
95 /* name */
96 if(flag&Fname)
97 while(getc(bin) != 0)
98 ;
99
100 /* comment */
101 if(flag&Fcomment)
102 while(getc(bin) != 0)
103 ;
104
105 /* crc16 */
106 if(flag&Fhcrc) {
107 getc(bin);
108 getc(bin);
109 }
110
111 return FlateOk;
112 }
113
114 static int
trailer(Biobuf * bout,Biobuf * bin)115 trailer(Biobuf *bout, Biobuf *bin)
116 {
117 /* crc32 */
118 if(crc != get4(bin)){
119 print("crc mismatch\n");
120 return FlateCorrupted;
121 }
122
123 /* length */
124 if(get4(bin) != Boffset(bout)){
125 print("bad output len\n");
126 return FlateCorrupted;
127 }
128 return FlateOk;
129 }
130
131 static ulong
get4(Biobuf * b)132 get4(Biobuf *b)
133 {
134 ulong v;
135 int i, c;
136
137 v = 0;
138 for(i = 0; i < 4; i++){
139 c = getc(b);
140 v |= c << (i * 8);
141 }
142 return v;
143 }
144
145 static int
getc(void * in)146 getc(void *in)
147 {
148 Biobuf *bp = in;
149
150 // if((bp->p - bp->bp) % 10000 == 0)
151 // print(".");
152 if(bp->p >= bp->ep){
153 print("EOF");
154 return -1;
155 }
156 return *bp->p++;
157 }
158
159 static ulong
Boffset(Biobuf * bp)160 Boffset(Biobuf *bp)
161 {
162 return bp->p - bp->bp;
163 }
164
165 static int
crcwrite(void * out,void * buf,int n)166 crcwrite(void *out, void *buf, int n)
167 {
168 Biobuf *bp;
169 int nn;
170
171 crc = blockcrc(crctab, crc, buf, n);
172 bp = out;
173 nn = n;
174 if(nn > bp->ep-bp->p)
175 nn = bp->ep-bp->p;
176 if(nn > 0)
177 memmove(bp->p, buf, nn);
178 bp->p += n;
179 return n;
180 }
181