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 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 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 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 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 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 160 Boffset(Biobuf *bp) 161 { 162 return bp->p - bp->bp; 163 } 164 165 static int 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