summaryrefslogtreecommitdiff
path: root/appl/lib/inflate.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/lib/inflate.b')
-rw-r--r--appl/lib/inflate.b103
1 files changed, 89 insertions, 14 deletions
diff --git a/appl/lib/inflate.b b/appl/lib/inflate.b
index 0f4d6ba7..3ee2503a 100644
--- a/appl/lib/inflate.b
+++ b/appl/lib/inflate.b
@@ -135,6 +135,7 @@ offdec: ref DeHuff;
revtab: array of byte; # bit reversal for endian swap of huffman codes
mask: array of int; # for masking low-order n bits of an int
+Hnone, Hgzip, Hzlib: con iota; # State.headers
State: adt {
ibuf, obuf: array of byte;
c: chan of ref Rq;
@@ -145,7 +146,8 @@ State: adt {
hist: array of byte; # history buffer for lempel-ziv backward references
usehist: int; # == 1 if 'hist' is valid
crctab: array of int;
- crc, tot: int;
+ crc, tot: int; # for gzip trailer
+ sum: big; # for zlib trailer
reg: int; # 24-bit shift register
nbits: int; # number of valid bits in reg
@@ -226,9 +228,16 @@ start(params: string): chan of ref Rq
s.nbits = 0;
s.crc = 0;
s.tot = 0;
+ s.sum = big 1;
s.hist = array[Blocksize] of byte;
- s.headers = (params != nil && params[0] == 'h');
- if (s.headers)
+ s.headers = Hnone;
+ if(params != nil) {
+ if(params[0] == 'h')
+ s.headers = Hgzip;
+ if(params[0] == 'z')
+ s.headers = Hzlib;
+ }
+ if (s.headers == Hgzip)
s.crctab = mkcrctab(GZCRCPOLY);
spawn inflate(s);
return s.c;
@@ -237,8 +246,7 @@ start(params: string): chan of ref Rq
inflate(s: ref State)
{
s.c <-= ref Rq.Start(sys->pctl(0, nil));
- if (s.headers)
- header(s);
+ header(s);
for(;;) {
bfinal := getn(s, 1, 0);
@@ -268,23 +276,21 @@ inflate(s: ref State)
}
if(bfinal) {
if(s.out) {
- if (s.headers)
- outblock(s);
+ outblock(s);
s.c <- = ref Rq.Result(s.obuf[0:s.out], s.rc);
flag := <- s.rc;
if (flag == -1)
exit;
}
flushbits(s);
- if (s.headers)
- footer(s);
+ footer(s);
s.c <-= ref Rq.Finished(s.ibuf[s.in - s.nbits/8:s.ein]);
exit;
}
}
}
-header(s: ref State)
+headergzip(s: ref State)
{
if(byte getb(s) != GZMAGIC1 || byte getb(s) != GZMAGIC2)
fatal(s, "not a gzip file");
@@ -335,7 +341,33 @@ header(s: ref State)
}
}
-footer(s: ref State)
+headerzlib(s: ref State)
+{
+ Fdict: con 1<<5;
+ CMshift: con 8;
+ CMmask: con (1<<4)-1;
+ CMdeflate: con 8;
+
+ h := 0;
+ h |= getb(s)<<8;
+ h |= getb(s);
+ if(h % 31 != 0)
+ fatal(s, "invalid zlib header");
+ if(h&Fdict)
+ fatal(s, "preset dictionary not supported");
+ if(((h>>CMshift)&CMmask) != CMdeflate)
+ fatal(s, "zlib compression method not deflate");
+}
+
+header(s: ref State)
+{
+ case s.headers {
+ Hgzip => headergzip(s);
+ Hzlib => headerzlib(s);
+ }
+}
+
+footergzip(s: ref State)
{
fcrc := getword(s);
if(s.crc != fcrc)
@@ -345,6 +377,25 @@ footer(s: ref State)
fatal(s, sys->sprint("byte count mismatch: computed %d, expected %d", s.tot, ftot));
}
+footerzlib(s: ref State)
+{
+ sum := big 0;
+ sum = (sum<<8)|big getb(s);
+ sum = (sum<<8)|big getb(s);
+ sum = (sum<<8)|big getb(s);
+ sum = (sum<<8)|big getb(s);
+ if(sum != s.sum)
+ fatal(s, sys->sprint("adler32 mismatch: computed %bux, expected %bux", s.sum, sum));
+}
+
+footer(s: ref State)
+{
+ case s.headers {
+ Hgzip => footergzip(s);
+ Hzlib => footerzlib(s);
+ }
+}
+
getword(s: ref State): int
{
n := 0;
@@ -694,8 +745,7 @@ flushbits(s: ref State)
#
flushout(s: ref State)
{
- if (s.headers)
- outblock(s);
+ outblock(s);
s.c <-= ref Rq.Result(s.obuf[0:s.out], s.rc);
flag := <- s.rc;
if (flag == -1)
@@ -723,7 +773,7 @@ mkcrctab(poly: int): array of int
return crctab;
}
-outblock(s: ref State)
+outblockgzip(s: ref State)
{
buf := s.obuf;
n := s.out;
@@ -735,6 +785,31 @@ outblock(s: ref State)
s.tot += n;
}
+outblockzlib(s: ref State)
+{
+ ZLADLERBASE: con big 65521;
+
+ buf := s.obuf;
+ n := s.out;
+
+ s1 := s.sum & big 16rffff;
+ s2 := (s.sum>>16) & big 16rffff;
+
+ for(i := 0; i < n; i++) {
+ s1 = (s1 + big buf[i]) % ZLADLERBASE;
+ s2 = (s2 + s1) % ZLADLERBASE;
+ }
+ s.sum = (s2<<16) + s1;
+}
+
+outblock(s: ref State)
+{
+ case s.headers {
+ Hgzip => outblockgzip(s);
+ Hzlib => outblockzlib(s);
+ }
+}
+
#
# irrecoverable error; invariably denotes data corruption
#