diff options
| author | Charles.Forsyth <devnull@localhost> | 2009-04-30 12:31:57 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2009-04-30 12:31:57 +0000 |
| commit | ce02cfb2169def0df6778d9be67d18545647bff4 (patch) | |
| tree | 5f6102b8d264209a0d78eff1442b836dc4604eca | |
| parent | 7d6ec01dec52f09685e39668de087d857e96c840 (diff) | |
20090430-1331
| -rw-r--r-- | appl/lib/deflate.b | 122 | ||||
| -rw-r--r-- | appl/lib/inflate.b | 103 | ||||
| -rw-r--r-- | dis/lib/deflate.dis | bin | 12044 -> 12760 bytes | |||
| -rw-r--r-- | dis/lib/inflate.dis | bin | 7114 -> 7993 bytes | |||
| -rw-r--r-- | include/version.h | 2 | ||||
| -rw-r--r-- | man/2/filter-deflate | 16 |
6 files changed, 208 insertions, 35 deletions
diff --git a/appl/lib/deflate.b b/appl/lib/deflate.b index ccfeafbe..500b3797 100644 --- a/appl/lib/deflate.b +++ b/appl/lib/deflate.b @@ -42,6 +42,7 @@ GZCRCPOLY: con int 16redb88320; GZOSINFERNO: con GZOSUNIX; +Hnone, Hgzip, Hzlib: con iota; # LZstate.headers LZstate: adt { hist: array of byte; # [HistSize]; @@ -56,11 +57,13 @@ LZstate: adt prevoff: int; maxchars: int; # compressor tuning maxdefer: int; + level: int; - crctab: array of int; + crctab: array of int; # for gzip trailer crc: int; tot: int; - headers: int; + sum: big; # for zlib trailer + headers: int; # which header to print, if any outbuf: array of byte; # current output buffer; out: int; # current position in the output buffer @@ -287,22 +290,27 @@ start(param: string): chan of ref Rq { # param contains flags: # [0-9] - compression level + # h gzip header/trailer + # z zlib header/trailer # v verbose # d debug lz := ref LZstate; - level := 6; + lz.level = 6; lz.verbose = lz.debug = 0; - lz.headers = 0; + lz.headers = Hnone; lz.crc = lz.tot = 0; + lz.sum = big 1; # XXX could also put filename and modification time in param for (i := 0; i < len param; i++) { case param[i] { '0' to '9' => - level = param[i] - '0'; + lz.level = param[i] - '0'; 'v' => lz.verbose = 1; 'h' => - lz.headers = 1; + lz.headers = Hgzip; + 'z' => + lz.headers = Hzlib; 'd' => lz.debug = 1; } @@ -345,17 +353,17 @@ start(param: string): chan of ref Rq lz.dot = lz.me; lz.bits = 0; lz.nbits = 0; - if(level < 5) { + if(lz.level < 5) { lz.maxchars = 1; lz.maxdefer = 0; - } else if(level == 9) { + } else if(lz.level == 9) { lz.maxchars = 4000; lz.maxdefer = MaxMatch; } else { lz.maxchars = 200; lz.maxdefer = MaxMatch / 4; } - if (lz.headers) + if (lz.headers == Hgzip) lz.crctab = mkcrctab(GZCRCPOLY); lz.c = chan of ref Rq; lz.rc = chan of int; @@ -383,8 +391,7 @@ deflate(lz: ref LZstate) { lz.c <-= ref Rq.Start(sys->pctl(0, nil)); - if (lz.headers) - header(lz); + header(lz); buf := array[DeflateBlock] of byte; out := array[DeflateBlock + DeflateOut] of byte; eof := 0; @@ -393,8 +400,7 @@ deflate(lz: ref LZstate) nbuf := 0; if (!eof) { (eof, nbuf) = fillbuf(lz, buf); - if (lz.headers) # added by Roman Joel Pacheco - inblock(lz, buf[0:nbuf]); + inblock(lz, buf[0:nbuf]); } if(eof && nbuf == 0 && nslop == 0) { if(lz.nbits) { @@ -405,8 +411,7 @@ deflate(lz: ref LZstate) exit; continue; } - if (lz.headers) - footer(lz); + footer(lz); lz.c <-= ref Rq.Finished(nil); exit; } @@ -538,7 +543,7 @@ deflate(lz: ref LZstate) } } -header(lz: ref LZstate) +headergzip(lz: ref LZstate) { buf := array[20] of byte; i := 0; @@ -569,7 +574,44 @@ header(lz: ref LZstate) exit; } -footer(lz: ref LZstate) +headerzlib(lz: ref LZstate) +{ + CIshift: con 12; + CMdeflate: con 8; + CMshift: con 8; + LVshift: con 6; + LVfastest, LVfast, LVnormal, LVbest: con iota; + + level := LVnormal; + if(lz.level < 6) + level = LVfastest; + else if(lz.level >= 9) + level = LVbest; + + h := 0; + h |= 7<<CIshift; # value is: (log2 of window size)-8 + h |= CMdeflate<<CMshift; + h |= level<<LVshift; + h += 31-(h%31); + + buf := array[2] of byte; + buf[0] = byte (h>>8); + buf[1] = byte (h>>0); + + lz.c <-= ref Rq.Result(buf, lz.rc); + if (<-lz.rc == -1) + exit; +} + +header(lz: ref LZstate) +{ + case lz.headers { + Hgzip => headergzip(lz); + Hzlib => headerzlib(lz); + } +} + +footergzip(lz: ref LZstate) { buf := array[8] of byte; i := 0; @@ -587,6 +629,28 @@ footer(lz: ref LZstate) exit; } +footerzlib(lz: ref LZstate) +{ + buf := array[4] of byte; + i := 0; + buf[i++] = byte (lz.sum>>24); + buf[i++] = byte (lz.sum>>16); + buf[i++] = byte (lz.sum>>8); + buf[i++] = byte (lz.sum>>0); + + lz.c <-= ref Rq.Result(buf, lz.rc); + if(<-lz.rc == -1) + exit; +} + +footer(lz: ref LZstate) +{ + case lz.headers { + Hgzip => footergzip(lz); + Hzlib => footerzlib(lz); + } +} + lzput(lz: ref LZstate, bits, nbits: int): int { bits = (bits << lz.nbits) | lz.bits; @@ -1349,7 +1413,7 @@ mkcrctab(poly: int): array of int return crctab; } -inblock(lz: ref LZstate, buf: array of byte) +inblockcrc(lz: ref LZstate, buf: array of byte) { crc := lz.crc; n := len buf; @@ -1360,6 +1424,28 @@ inblock(lz: ref LZstate, buf: array of byte) lz.tot += n; } +inblockadler(lz: ref LZstate, buf: array of byte) +{ + ZLADLERBASE: con big 65521; + + s1 := lz.sum & big 16rffff; + s2 := (lz.sum>>16) & big 16rffff; + + for(i := 0; i < len buf; i++) { + s1 = (s1 + big buf[i]) % ZLADLERBASE; + s2 = (s2 + s1) % ZLADLERBASE; + } + lz.sum = (s2<<16) + s1; +} + +inblock(lz: ref LZstate, buf: array of byte) +{ + case lz.headers { + Hgzip => inblockcrc(lz, buf); + Hzlib => inblockadler(lz, buf); + } +} + fatal(lz: ref LZstate, s: string) { lz.c <-= ref Rq.Error(s); 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 # diff --git a/dis/lib/deflate.dis b/dis/lib/deflate.dis Binary files differindex c3941ac7..4c0624ac 100644 --- a/dis/lib/deflate.dis +++ b/dis/lib/deflate.dis diff --git a/dis/lib/inflate.dis b/dis/lib/inflate.dis Binary files differindex 89c844bb..4c316b68 100644 --- a/dis/lib/inflate.dis +++ b/dis/lib/inflate.dis diff --git a/include/version.h b/include/version.h index 2ef40a47..61c9db13 100644 --- a/include/version.h +++ b/include/version.h @@ -1 +1 @@ -#define VERSION "Fourth Edition (20090427)" +#define VERSION "Fourth Edition (20090430)" diff --git a/man/2/filter-deflate b/man/2/filter-deflate index 34b320fb..6de01912 100644 --- a/man/2/filter-deflate +++ b/man/2/filter-deflate @@ -44,6 +44,10 @@ Add a gzip header and footer to the data. With this flag, the data after filtering will be in exactly the same format as a gzip file, with accompanying checksum. .TP +.RB ` z ' +Add a zlib header and footer to the data. The footer contains a +checksum. +.TP .RB ` 0 '\ to\ ` 9 ' Specifies the level of compression to be used (9 highest). See .IR gzip (1). @@ -59,8 +63,10 @@ argument to begins with the character .RB ` h ' then the input to the filter is assumed to be in the -standard gzip file format; the output will be checked -for integrity. While processing, the +standard gzip file format; if it starts with the character +.RB ` z ' +it is assumed to be in zlib format; the output will be checked +for integrity in both cases. While processing a gzip stream, the .B Rq.Info message is used to transmit some information; the type of information is determined by the first word of @@ -87,3 +93,9 @@ original file before compression. .SH SEE ALSO .IR gzip (1), .IR filter (2) +.br +Internet RFCs +.IR RFC1950 , +.IR RFC1951 , +and +.IR RFC1952 . |
