xref: /inferno-os/appl/lib/inflate.b (revision ce02cfb2169def0df6778d9be67d18545647bff4)
137da2899SCharles.Forsyth# gzip-compatible decompression filter.
237da2899SCharles.Forsyth
337da2899SCharles.Forsythimplement Filter;
437da2899SCharles.Forsyth
537da2899SCharles.Forsythinclude "sys.m";
637da2899SCharles.Forsyth	sys:	Sys;
737da2899SCharles.Forsythinclude "filter.m";
837da2899SCharles.Forsyth
937da2899SCharles.ForsythGZMAGIC1:	con byte 16r1f;
1037da2899SCharles.ForsythGZMAGIC2:	con byte 16r8b;
1137da2899SCharles.Forsyth
1237da2899SCharles.ForsythGZDEFLATE:	con byte 8;
1337da2899SCharles.Forsyth
1437da2899SCharles.ForsythGZFTEXT:	con 1 << 0;		# file is text
1537da2899SCharles.ForsythGZFHCRC:	con 1 << 1;		# crc of header included
1637da2899SCharles.ForsythGZFEXTRA:	con 1 << 2;		# extra header included
1737da2899SCharles.ForsythGZFNAME:	con 1 << 3;		# name of file included
1837da2899SCharles.ForsythGZFCOMMENT:	con 1 << 4;		# header comment included
1937da2899SCharles.ForsythGZFMASK:	con (1 << 5) - 1;	# mask of specified bits
2037da2899SCharles.Forsyth
2137da2899SCharles.ForsythGZXBEST:	con byte 2;		# used maximum compression algorithm
2237da2899SCharles.ForsythGZXFAST:	con byte 4;		# used fast algorithm little compression
2337da2899SCharles.Forsyth
2437da2899SCharles.ForsythGZOSFAT:	con byte 0;		# FAT file system
2537da2899SCharles.ForsythGZOSAMIGA:	con byte 1;		# Amiga
2637da2899SCharles.ForsythGZOSVMS:	con byte 2;		# VMS or OpenVMS
2737da2899SCharles.ForsythGZOSUNIX:	con byte 3;		# Unix
2837da2899SCharles.ForsythGZOSVMCMS:	con byte 4;		# VM/CMS
2937da2899SCharles.ForsythGZOSATARI:	con byte 5;		# Atari TOS
3037da2899SCharles.ForsythGZOSHPFS:	con byte 6;		# HPFS file system
3137da2899SCharles.ForsythGZOSMAC:	con byte 7;		# Macintosh
3237da2899SCharles.ForsythGZOSZSYS:	con byte 8;		# Z-System
3337da2899SCharles.ForsythGZOSCPM:	con byte 9;		# CP/M
3437da2899SCharles.ForsythGZOSTOPS20:	con byte 10;		# TOPS-20
3537da2899SCharles.ForsythGZOSNTFS:	con byte 11;		# NTFS file system
3637da2899SCharles.ForsythGZOSQDOS:	con byte 12;		# QDOS
3737da2899SCharles.ForsythGZOSACORN:	con byte 13;		# Acorn RISCOS
3837da2899SCharles.ForsythGZOSUNK:	con byte 255;
3937da2899SCharles.Forsyth
4037da2899SCharles.ForsythGZCRCPOLY:	con int 16redb88320;
4137da2899SCharles.ForsythGZOSINFERNO:	con GZOSUNIX;
4237da2899SCharles.Forsyth
4337da2899SCharles.Forsyth# huffman code table
4437da2899SCharles.ForsythHuff: adt
4537da2899SCharles.Forsyth{
4637da2899SCharles.Forsyth	bits:		int;		# length of the code
4737da2899SCharles.Forsyth	encode:		int;		# the code
4837da2899SCharles.Forsyth};
4937da2899SCharles.Forsyth
5037da2899SCharles.Forsyth# huffman decode table
5137da2899SCharles.ForsythDeHuff: adt
5237da2899SCharles.Forsyth{
5337da2899SCharles.Forsyth	l1:		array of L1;	# the table
5437da2899SCharles.Forsyth	nb1:		int;		# no. of bits in first level
5537da2899SCharles.Forsyth	nb2:		int;		# no. of bits in second level
5637da2899SCharles.Forsyth};
5737da2899SCharles.Forsyth
5837da2899SCharles.Forsyth# first level of decode table
5937da2899SCharles.ForsythL1: adt
6037da2899SCharles.Forsyth{
6137da2899SCharles.Forsyth	bits:		int;		# length of the code
6237da2899SCharles.Forsyth	decode:		int;		# the symbol
6337da2899SCharles.Forsyth	l2:		array of L2;
6437da2899SCharles.Forsyth};
6537da2899SCharles.Forsyth
6637da2899SCharles.Forsyth# second level
6737da2899SCharles.ForsythL2: adt
6837da2899SCharles.Forsyth{
6937da2899SCharles.Forsyth	bits:		int;		# length of the code
7037da2899SCharles.Forsyth	decode:		int;		# the symbol
7137da2899SCharles.Forsyth};
7237da2899SCharles.Forsyth
7337da2899SCharles.ForsythDeflateUnc:	con 0;			# uncompressed block
7437da2899SCharles.ForsythDeflateFix:	con 1;			# fixed huffman codes
7537da2899SCharles.ForsythDeflateDyn:	con 2;			# dynamic huffman codes
7637da2899SCharles.ForsythDeflateErr:	con 3;			# reserved BTYPE (error)
7737da2899SCharles.Forsyth
7837da2899SCharles.ForsythDeflateEob:	con 256;		# end of block code in lit/len book
7937da2899SCharles.Forsyth
8037da2899SCharles.ForsythLenStart:	con 257;		# start of length codes in litlen
8137da2899SCharles.ForsythLenEnd:		con 285;		# greatest valid length code
8237da2899SCharles.ForsythNlitlen:	con 288;		# number of litlen codes
8337da2899SCharles.ForsythNoff:		con 30;			# number of offset codes
8437da2899SCharles.ForsythNclen:		con 19;			# number of codelen codes
8537da2899SCharles.Forsyth
8637da2899SCharles.ForsythMaxHuffBits:	con 15;			# max bits in a huffman code
8737da2899SCharles.ForsythRunlenBits:	con 7;			# max bits in a run-length huffman code
8837da2899SCharles.ForsythMaxOff:		con 32*1024;		# max lempel-ziv distance
8937da2899SCharles.Forsyth
9037da2899SCharles.ForsythBlocksize: con 32 * 1024;
9137da2899SCharles.Forsyth
9237da2899SCharles.Forsyth# tables from RFC 1951, section 3.2.5
9337da2899SCharles.Forsythlitlenbase := array[Noff] of
9437da2899SCharles.Forsyth{
9537da2899SCharles.Forsyth	3, 4, 5, 6, 7, 8, 9, 10, 11, 13,
9637da2899SCharles.Forsyth	15, 17, 19, 23, 27, 31, 35, 43, 51, 59,
9737da2899SCharles.Forsyth	67, 83, 99, 115, 131, 163, 195, 227, 258
9837da2899SCharles.Forsyth};
9937da2899SCharles.Forsyth
10037da2899SCharles.Forsythlitlenextra := array[Noff] of
10137da2899SCharles.Forsyth{
10237da2899SCharles.Forsyth	0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
10337da2899SCharles.Forsyth	2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4,
10437da2899SCharles.Forsyth	5, 5, 5, 5, 0
10537da2899SCharles.Forsyth};
10637da2899SCharles.Forsyth
10737da2899SCharles.Forsythoffbase := array[Noff] of
10837da2899SCharles.Forsyth{
10937da2899SCharles.Forsyth	1, 2, 3, 4, 5, 7, 9, 13, 17, 25,
11037da2899SCharles.Forsyth	33, 49, 65, 97, 129, 193, 257, 385, 513, 769,
11137da2899SCharles.Forsyth	1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577
11237da2899SCharles.Forsyth};
11337da2899SCharles.Forsyth
11437da2899SCharles.Forsythoffextra := array[Noff] of
11537da2899SCharles.Forsyth{
11637da2899SCharles.Forsyth	0,  0,  0,  0,  1,  1,  2,  2,  3,  3,
11737da2899SCharles.Forsyth	4,  4,  5,  5,  6,  6,  7,  7,  8,  8,
11837da2899SCharles.Forsyth	9,  9,  10, 10, 11, 11, 12, 12, 13, 13
11937da2899SCharles.Forsyth};
12037da2899SCharles.Forsyth
12137da2899SCharles.Forsyth# order of run-length codes
12237da2899SCharles.Forsythclenorder := array[Nclen] of
12337da2899SCharles.Forsyth{
12437da2899SCharles.Forsyth	16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
12537da2899SCharles.Forsyth};
12637da2899SCharles.Forsyth
12737da2899SCharles.Forsyth# fixed huffman tables
12837da2899SCharles.Forsythlitlentab: array of Huff;
12937da2899SCharles.Forsythofftab: array of Huff;
13037da2899SCharles.Forsyth
13137da2899SCharles.Forsyth# their decoding table counterparts
13237da2899SCharles.Forsythlitlendec: ref DeHuff;
13337da2899SCharles.Forsythoffdec: ref DeHuff;
13437da2899SCharles.Forsyth
13537da2899SCharles.Forsythrevtab: array of byte;	# bit reversal for endian swap of huffman codes
13637da2899SCharles.Forsythmask: array of int;		# for masking low-order n bits of an int
13737da2899SCharles.Forsyth
138*ce02cfb2SCharles.ForsythHnone, Hgzip, Hzlib: con iota;  # State.headers
13937da2899SCharles.ForsythState: adt {
14037da2899SCharles.Forsyth	ibuf, obuf: array of byte;
14137da2899SCharles.Forsyth	c: chan of ref Rq;
14237da2899SCharles.Forsyth	rc: chan of int;
14337da2899SCharles.Forsyth	in: int;		# next byte to consume from input buffer
14437da2899SCharles.Forsyth	ein: int;		# valid bytes in input buffer
14537da2899SCharles.Forsyth	out: int;		# valid bytes in output buffer
14637da2899SCharles.Forsyth	hist: array of byte;	# history buffer for lempel-ziv backward references
14737da2899SCharles.Forsyth	usehist: int;		# == 1 if 'hist' is valid
14837da2899SCharles.Forsyth	crctab: array of int;
149*ce02cfb2SCharles.Forsyth	crc, tot: int;		# for gzip trailer
150*ce02cfb2SCharles.Forsyth	sum:	big;		# for zlib trailer
15137da2899SCharles.Forsyth
15237da2899SCharles.Forsyth	reg: int;		# 24-bit shift register
15337da2899SCharles.Forsyth	nbits: int;		# number of valid bits in reg
15437da2899SCharles.Forsyth	svreg: int;		# save reg for efficient ungets
15537da2899SCharles.Forsyth	svn: int;		# number of bits gotten in last call to getn()
15637da2899SCharles.Forsyth	# reg bits are consumed from right to left
15737da2899SCharles.Forsyth	# so low-order byte of reg came first in the input stream
15837da2899SCharles.Forsyth	headers: int;
15937da2899SCharles.Forsyth};
16037da2899SCharles.Forsyth
16137da2899SCharles.Forsyth
16237da2899SCharles.Forsythinit()
16337da2899SCharles.Forsyth{
16437da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
16537da2899SCharles.Forsyth
16637da2899SCharles.Forsyth	# byte reverse table
16737da2899SCharles.Forsyth	revtab = array[256] of byte;
16837da2899SCharles.Forsyth	for(i := 0; i < 256; i++){
16937da2899SCharles.Forsyth		revtab[i] = byte 0;
17037da2899SCharles.Forsyth		for(j := 0; j < 8; j++) {
17137da2899SCharles.Forsyth			if(i & (1 << j))
17237da2899SCharles.Forsyth				revtab[i] |= byte 16r80 >> j;
17337da2899SCharles.Forsyth		}
17437da2899SCharles.Forsyth	}
17537da2899SCharles.Forsyth
17637da2899SCharles.Forsyth	# bit-masking table
17737da2899SCharles.Forsyth	mask = array[MaxHuffBits+1] of int;
17837da2899SCharles.Forsyth	for(i = 0; i <= MaxHuffBits; i++)
17937da2899SCharles.Forsyth		mask[i] = (1 << i) - 1;
18037da2899SCharles.Forsyth
18137da2899SCharles.Forsyth	litlentab = array[Nlitlen] of Huff;
18237da2899SCharles.Forsyth
18337da2899SCharles.Forsyth	# static litlen bit lengths
18437da2899SCharles.Forsyth	for(i = 0; i < 144; i++)
18537da2899SCharles.Forsyth		litlentab[i].bits = 8;
18637da2899SCharles.Forsyth	for(i = 144; i < 256; i++)
18737da2899SCharles.Forsyth		litlentab[i].bits = 9;
18837da2899SCharles.Forsyth	for(i = 256; i < 280; i++)
18937da2899SCharles.Forsyth		litlentab[i].bits = 7;
19037da2899SCharles.Forsyth	for(i = 280; i < Nlitlen; i++)
19137da2899SCharles.Forsyth		litlentab[i].bits = 8;
19237da2899SCharles.Forsyth
19337da2899SCharles.Forsyth	bitcount := array[MaxHuffBits+1] of { * => 0 };
19437da2899SCharles.Forsyth	bitcount[8] += 144 - 0;
19537da2899SCharles.Forsyth	bitcount[9] += 256 - 144;
19637da2899SCharles.Forsyth	bitcount[7] += 280 - 256;
19737da2899SCharles.Forsyth	bitcount[8] += Nlitlen - 280;
19837da2899SCharles.Forsyth
19937da2899SCharles.Forsyth	hufftabinit(litlentab, Nlitlen, bitcount, 9);
20037da2899SCharles.Forsyth	litlendec = decodeinit(litlentab, Nlitlen, 9, 0);
20137da2899SCharles.Forsyth
20237da2899SCharles.Forsyth	offtab = array[Noff] of Huff;
20337da2899SCharles.Forsyth
20437da2899SCharles.Forsyth	# static offset bit lengths
20537da2899SCharles.Forsyth	for(i = 0; i < Noff; i++)
20637da2899SCharles.Forsyth		offtab[i].bits = 5;
20737da2899SCharles.Forsyth
20837da2899SCharles.Forsyth	for(i = 0; i < 5; i++)
20937da2899SCharles.Forsyth		bitcount[i] = 0;
21037da2899SCharles.Forsyth	bitcount[5] = Noff;
21137da2899SCharles.Forsyth
21237da2899SCharles.Forsyth	hufftabinit(offtab, Noff, bitcount, 5);
21337da2899SCharles.Forsyth	offdec = decodeinit(offtab, Noff, 5, 0);
21437da2899SCharles.Forsyth}
21537da2899SCharles.Forsyth
21637da2899SCharles.Forsythstart(params: string): chan of ref Rq
21737da2899SCharles.Forsyth{
21837da2899SCharles.Forsyth	s := ref State;
21937da2899SCharles.Forsyth	s.c = chan of ref Rq;
22037da2899SCharles.Forsyth	s.rc = chan of int;
22137da2899SCharles.Forsyth	s.ibuf = array[Blocksize] of byte;
22237da2899SCharles.Forsyth	s.obuf = array[Blocksize] of byte;
22337da2899SCharles.Forsyth	s.in = 0;
22437da2899SCharles.Forsyth	s.ein = 0;
22537da2899SCharles.Forsyth	s.out = 0;
22637da2899SCharles.Forsyth	s.usehist = 0;
22737da2899SCharles.Forsyth	s.reg = 0;
22837da2899SCharles.Forsyth	s.nbits = 0;
22937da2899SCharles.Forsyth	s.crc = 0;
23037da2899SCharles.Forsyth	s.tot = 0;
231*ce02cfb2SCharles.Forsyth	s.sum = big 1;
23237da2899SCharles.Forsyth	s.hist = array[Blocksize] of byte;
233*ce02cfb2SCharles.Forsyth	s.headers = Hnone;
234*ce02cfb2SCharles.Forsyth	if(params != nil) {
235*ce02cfb2SCharles.Forsyth		if(params[0] == 'h')
236*ce02cfb2SCharles.Forsyth			s.headers = Hgzip;
237*ce02cfb2SCharles.Forsyth		if(params[0] == 'z')
238*ce02cfb2SCharles.Forsyth			s.headers = Hzlib;
239*ce02cfb2SCharles.Forsyth	}
240*ce02cfb2SCharles.Forsyth	if (s.headers == Hgzip)
24137da2899SCharles.Forsyth		s.crctab = mkcrctab(GZCRCPOLY);
24237da2899SCharles.Forsyth	spawn inflate(s);
24337da2899SCharles.Forsyth	return s.c;
24437da2899SCharles.Forsyth}
24537da2899SCharles.Forsyth
24637da2899SCharles.Forsythinflate(s: ref State)
24737da2899SCharles.Forsyth{
24837da2899SCharles.Forsyth	s.c <-= ref Rq.Start(sys->pctl(0, nil));
24937da2899SCharles.Forsyth	header(s);
25037da2899SCharles.Forsyth
25137da2899SCharles.Forsyth	for(;;) {
25237da2899SCharles.Forsyth		bfinal := getn(s, 1, 0);
25337da2899SCharles.Forsyth		btype := getn(s, 2, 0);
25437da2899SCharles.Forsyth		case(btype) {
25537da2899SCharles.Forsyth		DeflateUnc =>
25637da2899SCharles.Forsyth			flushbits(s);
25737da2899SCharles.Forsyth			unclen := getb(s);
25837da2899SCharles.Forsyth			unclen |= getb(s) << 8;
25937da2899SCharles.Forsyth			nlen := getb(s);
26037da2899SCharles.Forsyth			nlen |= getb(s) << 8;
26137da2899SCharles.Forsyth			if(unclen != (~nlen & 16rFFFF))
26237da2899SCharles.Forsyth				fatal(s, "corrupted data");
26337da2899SCharles.Forsyth			for(; unclen > 0; unclen--) {
26437da2899SCharles.Forsyth				# inline putb(s, getb(s));
26537da2899SCharles.Forsyth				b := byte getb(s);
26637da2899SCharles.Forsyth				if(s.out >= MaxOff)
26737da2899SCharles.Forsyth					flushout(s);
26837da2899SCharles.Forsyth				s.obuf[s.out++] = b;
26937da2899SCharles.Forsyth			}
27037da2899SCharles.Forsyth		DeflateFix =>
27137da2899SCharles.Forsyth			decodeblock(s, litlendec, offdec);
27237da2899SCharles.Forsyth		DeflateDyn =>
27337da2899SCharles.Forsyth			dynhuff(s);
27437da2899SCharles.Forsyth		DeflateErr =>
27537da2899SCharles.Forsyth			fatal(s, "bad block type");
27637da2899SCharles.Forsyth		}
27737da2899SCharles.Forsyth		if(bfinal) {
27837da2899SCharles.Forsyth			if(s.out) {
27937da2899SCharles.Forsyth				outblock(s);
28037da2899SCharles.Forsyth				s.c <- = ref Rq.Result(s.obuf[0:s.out], s.rc);
28137da2899SCharles.Forsyth				flag := <- s.rc;
28237da2899SCharles.Forsyth				if (flag == -1)
28337da2899SCharles.Forsyth					exit;
28437da2899SCharles.Forsyth			}
28537da2899SCharles.Forsyth			flushbits(s);
28637da2899SCharles.Forsyth			footer(s);
28737da2899SCharles.Forsyth			s.c <-= ref Rq.Finished(s.ibuf[s.in - s.nbits/8:s.ein]);
28837da2899SCharles.Forsyth			exit;
28937da2899SCharles.Forsyth		}
29037da2899SCharles.Forsyth	}
29137da2899SCharles.Forsyth}
29237da2899SCharles.Forsyth
293*ce02cfb2SCharles.Forsythheadergzip(s: ref State)
29437da2899SCharles.Forsyth{
29537da2899SCharles.Forsyth	if(byte getb(s) != GZMAGIC1 || byte getb(s) != GZMAGIC2)
29637da2899SCharles.Forsyth		fatal(s, "not a gzip file");
29737da2899SCharles.Forsyth
29837da2899SCharles.Forsyth	if(byte getb(s) != GZDEFLATE)
29937da2899SCharles.Forsyth		fatal(s, "not compressed with deflate");
30037da2899SCharles.Forsyth
30137da2899SCharles.Forsyth	flags := getb(s);
30237da2899SCharles.Forsyth	if(flags & ~GZFMASK)
30337da2899SCharles.Forsyth		fatal(s, "reserved flag bits set");
30437da2899SCharles.Forsyth
30537da2899SCharles.Forsyth	# read modification time (ignored)
30637da2899SCharles.Forsyth	mtime := getb(s);
30737da2899SCharles.Forsyth	mtime |= (getb(s) << 8);
30837da2899SCharles.Forsyth	mtime |= (getb(s) << 16);
30937da2899SCharles.Forsyth	mtime |= (getb(s) << 24);
31037da2899SCharles.Forsyth	s.c <-= ref Rq.Info("mtime " + string mtime);
3119b29ac7eSCharles.Forsyth	getb(s);	# xfl
3129b29ac7eSCharles.Forsyth	getb(s);	# os
31337da2899SCharles.Forsyth
31437da2899SCharles.Forsyth	# skip optional "extra field"
31537da2899SCharles.Forsyth	if(flags & GZFEXTRA) {
31637da2899SCharles.Forsyth		skip := getb(s);
31737da2899SCharles.Forsyth		skip |= getb(s) << 8;
31837da2899SCharles.Forsyth		while (skip-- > 0)
31937da2899SCharles.Forsyth			getb(s);
32037da2899SCharles.Forsyth	}
32137da2899SCharles.Forsyth
32237da2899SCharles.Forsyth	# read optional filename (ignored)
32337da2899SCharles.Forsyth	file: string;
32437da2899SCharles.Forsyth	if(flags & GZFNAME){
32537da2899SCharles.Forsyth		n := 0;
32637da2899SCharles.Forsyth		while(c := getb(s))
32737da2899SCharles.Forsyth			file[n++] = c;
32837da2899SCharles.Forsyth		s.c <-= ref Rq.Info("file " + file);
32937da2899SCharles.Forsyth	}
33037da2899SCharles.Forsyth
33137da2899SCharles.Forsyth	# skip optional comment
33237da2899SCharles.Forsyth	if(flags & GZFCOMMENT) {
33337da2899SCharles.Forsyth		while(getb(s))
33437da2899SCharles.Forsyth			;
33537da2899SCharles.Forsyth	}
33637da2899SCharles.Forsyth
33737da2899SCharles.Forsyth	# skip optional CRC16 field
33837da2899SCharles.Forsyth	if(flags & GZFHCRC) {
33937da2899SCharles.Forsyth		getb(s);
34037da2899SCharles.Forsyth		getb(s);
34137da2899SCharles.Forsyth	}
34237da2899SCharles.Forsyth}
34337da2899SCharles.Forsyth
344*ce02cfb2SCharles.Forsythheaderzlib(s: ref State)
345*ce02cfb2SCharles.Forsyth{
346*ce02cfb2SCharles.Forsyth	Fdict:		con 1<<5;
347*ce02cfb2SCharles.Forsyth	CMshift:	con 8;
348*ce02cfb2SCharles.Forsyth	CMmask:		con (1<<4)-1;
349*ce02cfb2SCharles.Forsyth	CMdeflate:	con 8;
350*ce02cfb2SCharles.Forsyth
351*ce02cfb2SCharles.Forsyth	h := 0;
352*ce02cfb2SCharles.Forsyth	h |= getb(s)<<8;
353*ce02cfb2SCharles.Forsyth	h |= getb(s);
354*ce02cfb2SCharles.Forsyth	if(h % 31 != 0)
355*ce02cfb2SCharles.Forsyth		fatal(s, "invalid zlib header");
356*ce02cfb2SCharles.Forsyth	if(h&Fdict)
357*ce02cfb2SCharles.Forsyth		fatal(s, "preset dictionary not supported");
358*ce02cfb2SCharles.Forsyth	if(((h>>CMshift)&CMmask) != CMdeflate)
359*ce02cfb2SCharles.Forsyth		fatal(s, "zlib compression method not deflate");
360*ce02cfb2SCharles.Forsyth}
361*ce02cfb2SCharles.Forsyth
362*ce02cfb2SCharles.Forsythheader(s: ref State)
363*ce02cfb2SCharles.Forsyth{
364*ce02cfb2SCharles.Forsyth	case s.headers {
365*ce02cfb2SCharles.Forsyth	Hgzip =>	headergzip(s);
366*ce02cfb2SCharles.Forsyth	Hzlib =>	headerzlib(s);
367*ce02cfb2SCharles.Forsyth	}
368*ce02cfb2SCharles.Forsyth}
369*ce02cfb2SCharles.Forsyth
370*ce02cfb2SCharles.Forsythfootergzip(s: ref State)
37137da2899SCharles.Forsyth{
37237da2899SCharles.Forsyth	fcrc := getword(s);
37337da2899SCharles.Forsyth	if(s.crc != fcrc)
37437da2899SCharles.Forsyth		fatal(s, sys->sprint("crc mismatch: computed %ux, expected %ux", s.crc, fcrc));
37537da2899SCharles.Forsyth	ftot := getword(s);
37637da2899SCharles.Forsyth	if(s.tot != ftot)
37737da2899SCharles.Forsyth		fatal(s, sys->sprint("byte count mismatch: computed %d, expected %d", s.tot, ftot));
37837da2899SCharles.Forsyth}
37937da2899SCharles.Forsyth
380*ce02cfb2SCharles.Forsythfooterzlib(s: ref State)
381*ce02cfb2SCharles.Forsyth{
382*ce02cfb2SCharles.Forsyth	sum := big 0;
383*ce02cfb2SCharles.Forsyth	sum = (sum<<8)|big getb(s);
384*ce02cfb2SCharles.Forsyth	sum = (sum<<8)|big getb(s);
385*ce02cfb2SCharles.Forsyth	sum = (sum<<8)|big getb(s);
386*ce02cfb2SCharles.Forsyth	sum = (sum<<8)|big getb(s);
387*ce02cfb2SCharles.Forsyth	if(sum != s.sum)
388*ce02cfb2SCharles.Forsyth		fatal(s, sys->sprint("adler32 mismatch: computed %bux, expected %bux", s.sum, sum));
389*ce02cfb2SCharles.Forsyth}
390*ce02cfb2SCharles.Forsyth
391*ce02cfb2SCharles.Forsythfooter(s: ref State)
392*ce02cfb2SCharles.Forsyth{
393*ce02cfb2SCharles.Forsyth	case s.headers {
394*ce02cfb2SCharles.Forsyth	Hgzip =>	footergzip(s);
395*ce02cfb2SCharles.Forsyth	Hzlib =>	footerzlib(s);
396*ce02cfb2SCharles.Forsyth	}
397*ce02cfb2SCharles.Forsyth}
398*ce02cfb2SCharles.Forsyth
39937da2899SCharles.Forsythgetword(s: ref State): int
40037da2899SCharles.Forsyth{
40137da2899SCharles.Forsyth	n := 0;
40237da2899SCharles.Forsyth	for(i := 0; i < 4; i++)
40337da2899SCharles.Forsyth		n |= getb(s) << (8 * i);
40437da2899SCharles.Forsyth	return n;
40537da2899SCharles.Forsyth}
40637da2899SCharles.Forsyth
40737da2899SCharles.Forsyth#
40837da2899SCharles.Forsyth# uncompress a block using given huffman decoding tables
40937da2899SCharles.Forsyth#
41037da2899SCharles.Forsythdecodeblock(s: ref State, litlendec, offdec: ref DeHuff)
41137da2899SCharles.Forsyth{
41237da2899SCharles.Forsyth	b: byte;
41337da2899SCharles.Forsyth
41437da2899SCharles.Forsyth	for(;;) {
41537da2899SCharles.Forsyth		sym := decodesym(s, litlendec);
41637da2899SCharles.Forsyth		if(sym < DeflateEob) {		# literal byte
41737da2899SCharles.Forsyth			# inline putb(s, byte sym);
41837da2899SCharles.Forsyth			b = byte sym;
41937da2899SCharles.Forsyth			if(s.out >= MaxOff)
42037da2899SCharles.Forsyth				flushout(s);
42137da2899SCharles.Forsyth			s.obuf[s.out++] = b;
42237da2899SCharles.Forsyth		} else if(sym == DeflateEob) {	# End-of-block
42337da2899SCharles.Forsyth			break;
42437da2899SCharles.Forsyth		} else {			# lempel-ziv <length, distance>
42537da2899SCharles.Forsyth			if(sym > LenEnd)
42637da2899SCharles.Forsyth				fatal(s, "symbol too long");
42737da2899SCharles.Forsyth			xbits := litlenextra[sym - LenStart];
42837da2899SCharles.Forsyth			xtra := 0;
42937da2899SCharles.Forsyth			if(xbits)
43037da2899SCharles.Forsyth				xtra = getn(s, xbits, 0);
43137da2899SCharles.Forsyth			length := litlenbase[sym - LenStart] + xtra;
43237da2899SCharles.Forsyth
43337da2899SCharles.Forsyth			sym = decodesym(s, offdec);
43437da2899SCharles.Forsyth			if(sym >= Noff)
43537da2899SCharles.Forsyth				fatal(s, "symbol too long");
43637da2899SCharles.Forsyth			xbits = offextra[sym];
43737da2899SCharles.Forsyth			if(xbits)
43837da2899SCharles.Forsyth				xtra = getn(s, xbits, 0);
43937da2899SCharles.Forsyth			else
44037da2899SCharles.Forsyth				xtra = 0;
44137da2899SCharles.Forsyth			dist := offbase[sym] + xtra;
44237da2899SCharles.Forsyth			if(dist > s.out && s.usehist == 0)
44337da2899SCharles.Forsyth				fatal(s, "corrupted data");
44437da2899SCharles.Forsyth			for(i := 0; i < length; i++) {
44537da2899SCharles.Forsyth				# inline putb(lzbyte(dist));
44637da2899SCharles.Forsyth				ix := s.out - dist;
44737da2899SCharles.Forsyth				if(dist <= s.out)
44837da2899SCharles.Forsyth					b = s.obuf[ix];
44937da2899SCharles.Forsyth				else
45037da2899SCharles.Forsyth					b = s.hist[MaxOff + ix];
45137da2899SCharles.Forsyth				if(s.out >= MaxOff)
45237da2899SCharles.Forsyth					flushout(s);
45337da2899SCharles.Forsyth				s.obuf[s.out++] = b;
45437da2899SCharles.Forsyth			}
45537da2899SCharles.Forsyth		}
45637da2899SCharles.Forsyth	}
45737da2899SCharles.Forsyth}
45837da2899SCharles.Forsyth
45937da2899SCharles.Forsyth#
46037da2899SCharles.Forsyth# decode next symbol in input stream using given huffman decoding table
46137da2899SCharles.Forsyth#
46237da2899SCharles.Forsythdecodesym(s: ref State, dec: ref DeHuff): int
46337da2899SCharles.Forsyth{
46437da2899SCharles.Forsyth	code, bits, n: int;
46537da2899SCharles.Forsyth
46637da2899SCharles.Forsyth	l1 := dec.l1;
46737da2899SCharles.Forsyth	nb1 := dec.nb1;
46837da2899SCharles.Forsyth	nb2 := dec.nb2;
46937da2899SCharles.Forsyth
47037da2899SCharles.Forsyth	code = getn(s, nb1, 1);
47137da2899SCharles.Forsyth	l2 := l1[code].l2;
47237da2899SCharles.Forsyth	if(l2 == nil) {		# first level table has answer
47337da2899SCharles.Forsyth		bits = l1[code].bits;
47437da2899SCharles.Forsyth		if(bits == 0)
47537da2899SCharles.Forsyth			fatal(s, "corrupt data");
47637da2899SCharles.Forsyth		if(nb1 > bits) {
47737da2899SCharles.Forsyth			# inline ungetn(nb1 - bits);
47837da2899SCharles.Forsyth			n = nb1 - bits;
47937da2899SCharles.Forsyth			s.reg = s.svreg >> (s.svn - n);
48037da2899SCharles.Forsyth			s.nbits += n;
48137da2899SCharles.Forsyth		}
48237da2899SCharles.Forsyth		return l1[code].decode;
48337da2899SCharles.Forsyth	}
48437da2899SCharles.Forsyth	# must advance to second-level table
48537da2899SCharles.Forsyth	code = getn(s, nb2, 1);
48637da2899SCharles.Forsyth	bits = l2[code].bits;
48737da2899SCharles.Forsyth	if(bits == 0)
48837da2899SCharles.Forsyth		fatal(s, "corrupt data");
48937da2899SCharles.Forsyth	if(nb1 + nb2 > bits) {
49037da2899SCharles.Forsyth		# inline ungetn(nb1 + nb2 - bits);
49137da2899SCharles.Forsyth		n = nb1 + nb2 - bits;
49237da2899SCharles.Forsyth		s.reg = s.svreg >> (s.svn - n);
49337da2899SCharles.Forsyth		s.nbits += n;
49437da2899SCharles.Forsyth	}
49537da2899SCharles.Forsyth	return l2[code].decode;
49637da2899SCharles.Forsyth}
49737da2899SCharles.Forsyth
49837da2899SCharles.Forsyth#
49937da2899SCharles.Forsyth# uncompress a block that was encoded with dynamic huffman codes
50037da2899SCharles.Forsyth# RFC 1951, section 3.2.7
50137da2899SCharles.Forsyth#
50237da2899SCharles.Forsythdynhuff(s: ref State)
50337da2899SCharles.Forsyth{
50437da2899SCharles.Forsyth	hlit := getn(s, 5, 0) + 257;
50537da2899SCharles.Forsyth	hdist := getn(s, 5, 0) + 1;
50637da2899SCharles.Forsyth	hclen := getn(s, 4, 0) + 4;
50737da2899SCharles.Forsyth	if(hlit > Nlitlen || hlit < 257 || hdist > Noff)
50837da2899SCharles.Forsyth		fatal(s, "corrupt data");
50937da2899SCharles.Forsyth
51037da2899SCharles.Forsyth	runlentab := array[Nclen] of { * => Huff(0, 0) };
51137da2899SCharles.Forsyth	count := array[RunlenBits+1] of { * => 0 };
51237da2899SCharles.Forsyth	for(i := 0; i < hclen; i++) {
51337da2899SCharles.Forsyth		nb := getn(s, 3, 0);
51437da2899SCharles.Forsyth		if(nb) {
51537da2899SCharles.Forsyth			runlentab[clenorder[i]].bits = nb;
51637da2899SCharles.Forsyth			count[nb]++;
51737da2899SCharles.Forsyth		}
51837da2899SCharles.Forsyth	}
51937da2899SCharles.Forsyth	hufftabinit(runlentab, Nclen, count, RunlenBits);
52037da2899SCharles.Forsyth	runlendec := decodeinit(runlentab, Nclen, RunlenBits, 0);
52137da2899SCharles.Forsyth	if(runlendec == nil)
52237da2899SCharles.Forsyth		fatal(s, "corrupt data");
52337da2899SCharles.Forsyth
52437da2899SCharles.Forsyth	lengths := decodelen(s, runlendec, hlit+hdist);
52537da2899SCharles.Forsyth	if(lengths == nil)
52637da2899SCharles.Forsyth		fatal(s, "corrupt length table");
52737da2899SCharles.Forsyth
52837da2899SCharles.Forsyth	dlitlendec := decodedyn(s, lengths[0:hlit], hlit, 9);
52937da2899SCharles.Forsyth	doffdec := decodedyn(s, lengths[hlit:], hdist, 5);
53037da2899SCharles.Forsyth	decodeblock(s, dlitlendec, doffdec);
53137da2899SCharles.Forsyth}
53237da2899SCharles.Forsyth
53337da2899SCharles.Forsyth#
53437da2899SCharles.Forsyth# return the decoded combined length table for literal and distance alphabets
53537da2899SCharles.Forsyth#
53637da2899SCharles.Forsythdecodelen(s: ref State, runlendec: ref DeHuff, nlen: int): array of int
53737da2899SCharles.Forsyth{
53837da2899SCharles.Forsyth	lengths := array[nlen] of int;
53937da2899SCharles.Forsyth	for(n := 0; n < nlen;) {
54037da2899SCharles.Forsyth		nb := decodesym(s, runlendec);
54137da2899SCharles.Forsyth		nr := 1;
54237da2899SCharles.Forsyth		case nb {
54337da2899SCharles.Forsyth		0 to 15 =>
54437da2899SCharles.Forsyth			;
54537da2899SCharles.Forsyth		16 =>
54637da2899SCharles.Forsyth			nr = getn(s, 2, 0) + 3;
54737da2899SCharles.Forsyth			if(n == 0)
54837da2899SCharles.Forsyth				return nil;
54937da2899SCharles.Forsyth			nb = lengths[n-1];
55037da2899SCharles.Forsyth		17 =>
55137da2899SCharles.Forsyth			nr = getn(s, 3, 0) + 3;
55237da2899SCharles.Forsyth			nb = 0;
55337da2899SCharles.Forsyth		18 =>
55437da2899SCharles.Forsyth			nr = getn(s, 7, 0) + 11;
55537da2899SCharles.Forsyth			nb = 0;
55637da2899SCharles.Forsyth		* =>
55737da2899SCharles.Forsyth			return nil;
55837da2899SCharles.Forsyth		}
55937da2899SCharles.Forsyth		if(n+nr > nlen)
56037da2899SCharles.Forsyth			return nil;
56137da2899SCharles.Forsyth		while(--nr >= 0)
56237da2899SCharles.Forsyth			lengths[n++] = nb;
56337da2899SCharles.Forsyth	}
56437da2899SCharles.Forsyth	return lengths;
56537da2899SCharles.Forsyth}
56637da2899SCharles.Forsyth
56737da2899SCharles.Forsyth#
56837da2899SCharles.Forsyth# (1) read a dynamic huffman code from the input stream
56937da2899SCharles.Forsyth# (2) decode it using the run-length huffman code
57037da2899SCharles.Forsyth# (3) return the decode table for the dynamic huffman code
57137da2899SCharles.Forsyth#
57237da2899SCharles.Forsythdecodedyn(s: ref State, lengths: array of int, nlen, nb1: int): ref DeHuff
57337da2899SCharles.Forsyth{
57437da2899SCharles.Forsyth	hufftab := array[nlen] of Huff;
57537da2899SCharles.Forsyth	count := array[MaxHuffBits+1] of { * => 0 };
57637da2899SCharles.Forsyth
57737da2899SCharles.Forsyth	maxnb := 0;
57837da2899SCharles.Forsyth	for(n := 0; n < nlen; n++) {
57937da2899SCharles.Forsyth		c := lengths[n];
58037da2899SCharles.Forsyth		if(c) {
58137da2899SCharles.Forsyth			hufftab[n].bits = c;
58237da2899SCharles.Forsyth			count[c]++;
58337da2899SCharles.Forsyth			if(c > maxnb)
58437da2899SCharles.Forsyth				maxnb = c;
58537da2899SCharles.Forsyth		}else
58637da2899SCharles.Forsyth			hufftab[n].bits = 0;
58737da2899SCharles.Forsyth		hufftab[n].encode = 0;
58837da2899SCharles.Forsyth	}
58937da2899SCharles.Forsyth	hufftabinit(hufftab, nlen, count, maxnb);
59037da2899SCharles.Forsyth	nb2 := 0;
59137da2899SCharles.Forsyth	if(maxnb > nb1)
59237da2899SCharles.Forsyth		nb2 = maxnb - nb1;
59337da2899SCharles.Forsyth	d := decodeinit(hufftab, nlen, nb1, nb2);
59437da2899SCharles.Forsyth	if (d == nil)
59537da2899SCharles.Forsyth		fatal(s, "decodeinit failed");
59637da2899SCharles.Forsyth	return d;
59737da2899SCharles.Forsyth}
59837da2899SCharles.Forsyth
59937da2899SCharles.Forsyth#
60037da2899SCharles.Forsyth# RFC 1951, section 3.2.2
60137da2899SCharles.Forsyth#
60237da2899SCharles.Forsythhufftabinit(tab: array of Huff, n: int, bitcount: array of int, nbits: int)
60337da2899SCharles.Forsyth{
60437da2899SCharles.Forsyth	nc := array[MaxHuffBits+1] of int;
60537da2899SCharles.Forsyth
60637da2899SCharles.Forsyth	code := 0;
60737da2899SCharles.Forsyth	for(bits := 1; bits <= nbits; bits++) {
60837da2899SCharles.Forsyth		code = (code + bitcount[bits-1]) << 1;
60937da2899SCharles.Forsyth		nc[bits] = code;
61037da2899SCharles.Forsyth	}
61137da2899SCharles.Forsyth
61237da2899SCharles.Forsyth	for(i := 0; i < n; i++) {
61337da2899SCharles.Forsyth		bits = tab[i].bits;
61437da2899SCharles.Forsyth		# differences from Deflate module:
61537da2899SCharles.Forsyth		#  (1) leave huffman code right-justified in encode
61637da2899SCharles.Forsyth		#  (2) don't reverse it
61737da2899SCharles.Forsyth		if(bits != 0)
61837da2899SCharles.Forsyth			tab[i].encode = nc[bits]++;
61937da2899SCharles.Forsyth	}
62037da2899SCharles.Forsyth}
62137da2899SCharles.Forsyth
62237da2899SCharles.Forsyth#
62337da2899SCharles.Forsyth# convert 'array of Huff' produced by hufftabinit()
62437da2899SCharles.Forsyth# into 2-level lookup table for decoding
62537da2899SCharles.Forsyth#
62637da2899SCharles.Forsyth# nb1(nb2): number of bits handled by first(second)-level table
62737da2899SCharles.Forsyth#
62837da2899SCharles.Forsythdecodeinit(tab: array of Huff, n, nb1, nb2: int): ref DeHuff
62937da2899SCharles.Forsyth{
63037da2899SCharles.Forsyth	i, j, k, d: int;
63137da2899SCharles.Forsyth
63237da2899SCharles.Forsyth	dehuff := ref DeHuff(array[1<<nb1] of { * => L1(0, 0, nil) }, nb1, nb2);
63337da2899SCharles.Forsyth	l1 := dehuff.l1;
63437da2899SCharles.Forsyth	for(i = 0; i < n; i++) {
63537da2899SCharles.Forsyth		bits := tab[i].bits;
63637da2899SCharles.Forsyth		if(bits == 0)
63737da2899SCharles.Forsyth			continue;
63837da2899SCharles.Forsyth		l1x := tab[i].encode;
63937da2899SCharles.Forsyth		if(l1x >= (1 << bits))
64037da2899SCharles.Forsyth			return nil;
64137da2899SCharles.Forsyth		if(bits <= nb1) {
64237da2899SCharles.Forsyth			d = nb1 - bits;
64337da2899SCharles.Forsyth			l1x <<= d;
64437da2899SCharles.Forsyth			k = l1x + mask[d];
64537da2899SCharles.Forsyth			for(j = l1x; j <= k; j++) {
64637da2899SCharles.Forsyth				l1[j].decode = i;
64737da2899SCharles.Forsyth				l1[j].bits = bits;
64837da2899SCharles.Forsyth			}
64937da2899SCharles.Forsyth			continue;
65037da2899SCharles.Forsyth		}
65137da2899SCharles.Forsyth		# advance to second-level table
65237da2899SCharles.Forsyth		d = bits - nb1;
65337da2899SCharles.Forsyth		l2x := l1x & mask[d];
65437da2899SCharles.Forsyth		l1x >>= d;
65537da2899SCharles.Forsyth		if(l1[l1x].l2 == nil)
65637da2899SCharles.Forsyth			l1[l1x].l2 = array[1<<nb2] of { * => L2(0, 0) };
65737da2899SCharles.Forsyth		l2 := l1[l1x].l2;
65837da2899SCharles.Forsyth		d = (nb1 + nb2) - bits;
65937da2899SCharles.Forsyth		l2x <<= d;
66037da2899SCharles.Forsyth		k = l2x + mask[d];
66137da2899SCharles.Forsyth		for(j = l2x; j <= k; j++) {
66237da2899SCharles.Forsyth			l2[j].decode = i;
66337da2899SCharles.Forsyth			l2[j].bits = bits;
66437da2899SCharles.Forsyth		}
66537da2899SCharles.Forsyth	}
66637da2899SCharles.Forsyth
66737da2899SCharles.Forsyth	return dehuff;
66837da2899SCharles.Forsyth}
66937da2899SCharles.Forsyth
67037da2899SCharles.Forsyth#
67137da2899SCharles.Forsyth# get next byte from reg
67237da2899SCharles.Forsyth# assumptions:
67337da2899SCharles.Forsyth#  (1) flushbits() has been called
67437da2899SCharles.Forsyth#  (2) ungetn() won't be called after a getb()
67537da2899SCharles.Forsyth#
67637da2899SCharles.Forsythgetb(s: ref State): int
67737da2899SCharles.Forsyth{
67837da2899SCharles.Forsyth	if(s.nbits < 8)
67937da2899SCharles.Forsyth		need(s, 8);
68037da2899SCharles.Forsyth	b := byte s.reg;
68137da2899SCharles.Forsyth	s.reg >>= 8;
68237da2899SCharles.Forsyth	s.nbits -= 8;
68337da2899SCharles.Forsyth	return int b;
68437da2899SCharles.Forsyth}
68537da2899SCharles.Forsyth
68637da2899SCharles.Forsyth#
68737da2899SCharles.Forsyth# get next n bits from reg; if r != 0, reverse the bits
68837da2899SCharles.Forsyth#
68937da2899SCharles.Forsythgetn(s: ref State, n, r: int): int
69037da2899SCharles.Forsyth{
69137da2899SCharles.Forsyth	if(s.nbits < n)
69237da2899SCharles.Forsyth		need(s, n);
69337da2899SCharles.Forsyth	s.svreg = s.reg;
69437da2899SCharles.Forsyth	s.svn = n;
69537da2899SCharles.Forsyth	i := s.reg & mask[n];
69637da2899SCharles.Forsyth	s.reg >>= n;
69737da2899SCharles.Forsyth	s.nbits -= n;
69837da2899SCharles.Forsyth	if(r) {
69937da2899SCharles.Forsyth		if(n <= 8) {
70037da2899SCharles.Forsyth			i = int revtab[i];
70137da2899SCharles.Forsyth			i >>= 8 - n;
70237da2899SCharles.Forsyth		} else {
70337da2899SCharles.Forsyth			i = ((int revtab[i & 16rff]) << 8)
70437da2899SCharles.Forsyth				| (int revtab[i >> 8]);
70537da2899SCharles.Forsyth			i >>= 16 - n;
70637da2899SCharles.Forsyth		}
70737da2899SCharles.Forsyth	}
70837da2899SCharles.Forsyth	return i;
70937da2899SCharles.Forsyth}
71037da2899SCharles.Forsyth
71137da2899SCharles.Forsyth#
71237da2899SCharles.Forsyth# ensure that at least n bits are available in reg
71337da2899SCharles.Forsyth#
71437da2899SCharles.Forsythneed(s: ref State, n: int)
71537da2899SCharles.Forsyth{
71637da2899SCharles.Forsyth	while(s.nbits < n) {
71737da2899SCharles.Forsyth		if(s.in >= s.ein) {
71837da2899SCharles.Forsyth			s.c <-= ref Rq.Fill(s.ibuf, s.rc);
71937da2899SCharles.Forsyth			s.ein = <- s.rc;
72037da2899SCharles.Forsyth			if (s.ein < 0)
72137da2899SCharles.Forsyth				exit;
72237da2899SCharles.Forsyth			if (s.ein == 0)
72337da2899SCharles.Forsyth				fatal(s, "premature end of stream");
72437da2899SCharles.Forsyth			s.in = 0;
72537da2899SCharles.Forsyth		}
72637da2899SCharles.Forsyth		s.reg = ((int s.ibuf[s.in++]) << s.nbits) | s.reg;
72737da2899SCharles.Forsyth		s.nbits += 8;
72837da2899SCharles.Forsyth	}
72937da2899SCharles.Forsyth}
73037da2899SCharles.Forsyth
73137da2899SCharles.Forsyth#
73237da2899SCharles.Forsyth# if partial byte consumed from reg, dispose of remaining bits
73337da2899SCharles.Forsyth#
73437da2899SCharles.Forsythflushbits(s: ref State)
73537da2899SCharles.Forsyth{
73637da2899SCharles.Forsyth	drek := s.nbits % 8;
73737da2899SCharles.Forsyth	if(drek) {
73837da2899SCharles.Forsyth		s.reg >>= drek;
73937da2899SCharles.Forsyth		s.nbits -= drek;
74037da2899SCharles.Forsyth	}
74137da2899SCharles.Forsyth}
74237da2899SCharles.Forsyth
74337da2899SCharles.Forsyth#
74437da2899SCharles.Forsyth# output buffer is full, so flush it
74537da2899SCharles.Forsyth#
74637da2899SCharles.Forsythflushout(s: ref State)
74737da2899SCharles.Forsyth{
74837da2899SCharles.Forsyth	outblock(s);
74937da2899SCharles.Forsyth	s.c <-= ref Rq.Result(s.obuf[0:s.out], s.rc);
75037da2899SCharles.Forsyth	flag := <- s.rc;
75137da2899SCharles.Forsyth	if (flag == -1)
75237da2899SCharles.Forsyth		exit;
75337da2899SCharles.Forsyth	buf := s.hist;
75437da2899SCharles.Forsyth	s.hist = s.obuf;
75537da2899SCharles.Forsyth	s.usehist = 1;
75637da2899SCharles.Forsyth	s.obuf = buf;
75737da2899SCharles.Forsyth	s.out = 0;
75837da2899SCharles.Forsyth}
75937da2899SCharles.Forsyth
76037da2899SCharles.Forsythmkcrctab(poly: int): array of int
76137da2899SCharles.Forsyth{
76237da2899SCharles.Forsyth	crctab := array[256] of int;
76337da2899SCharles.Forsyth	for(i := 0; i < 256; i++){
76437da2899SCharles.Forsyth		crc := i;
76537da2899SCharles.Forsyth		for(j := 0; j < 8; j++){
76637da2899SCharles.Forsyth			c := crc & 1;
76737da2899SCharles.Forsyth			crc = (crc >> 1) & 16r7fffffff;
76837da2899SCharles.Forsyth			if(c)
76937da2899SCharles.Forsyth				crc ^= poly;
77037da2899SCharles.Forsyth		}
77137da2899SCharles.Forsyth		crctab[i] = crc;
77237da2899SCharles.Forsyth	}
77337da2899SCharles.Forsyth	return crctab;
77437da2899SCharles.Forsyth}
77537da2899SCharles.Forsyth
776*ce02cfb2SCharles.Forsythoutblockgzip(s: ref State)
77737da2899SCharles.Forsyth{
77837da2899SCharles.Forsyth	buf := s.obuf;
77937da2899SCharles.Forsyth	n := s.out;
78037da2899SCharles.Forsyth	crc := s.crc;
78137da2899SCharles.Forsyth	crc ^= int 16rffffffff;
78237da2899SCharles.Forsyth	for(i := 0; i < n; i++)
78337da2899SCharles.Forsyth		crc = s.crctab[int(byte crc ^ buf[i])] ^ ((crc >> 8) & 16r00ffffff);
78437da2899SCharles.Forsyth	s.crc = crc ^ int 16rffffffff;
78537da2899SCharles.Forsyth	s.tot += n;
78637da2899SCharles.Forsyth}
78737da2899SCharles.Forsyth
788*ce02cfb2SCharles.Forsythoutblockzlib(s: ref State)
789*ce02cfb2SCharles.Forsyth{
790*ce02cfb2SCharles.Forsyth	ZLADLERBASE:	con big 65521;
791*ce02cfb2SCharles.Forsyth
792*ce02cfb2SCharles.Forsyth	buf := s.obuf;
793*ce02cfb2SCharles.Forsyth	n := s.out;
794*ce02cfb2SCharles.Forsyth
795*ce02cfb2SCharles.Forsyth	s1 := s.sum & big 16rffff;
796*ce02cfb2SCharles.Forsyth	s2 := (s.sum>>16) & big 16rffff;
797*ce02cfb2SCharles.Forsyth
798*ce02cfb2SCharles.Forsyth	for(i := 0; i < n; i++) {
799*ce02cfb2SCharles.Forsyth		s1 = (s1 + big buf[i]) % ZLADLERBASE;
800*ce02cfb2SCharles.Forsyth		s2 = (s2 + s1) % ZLADLERBASE;
801*ce02cfb2SCharles.Forsyth	}
802*ce02cfb2SCharles.Forsyth	s.sum = (s2<<16) + s1;
803*ce02cfb2SCharles.Forsyth}
804*ce02cfb2SCharles.Forsyth
805*ce02cfb2SCharles.Forsythoutblock(s: ref State)
806*ce02cfb2SCharles.Forsyth{
807*ce02cfb2SCharles.Forsyth	case s.headers {
808*ce02cfb2SCharles.Forsyth	Hgzip =>	outblockgzip(s);
809*ce02cfb2SCharles.Forsyth	Hzlib =>	outblockzlib(s);
810*ce02cfb2SCharles.Forsyth	}
811*ce02cfb2SCharles.Forsyth}
812*ce02cfb2SCharles.Forsyth
81337da2899SCharles.Forsyth#
81437da2899SCharles.Forsyth# irrecoverable error; invariably denotes data corruption
81537da2899SCharles.Forsyth#
81637da2899SCharles.Forsythfatal(s: ref State, e: string)
81737da2899SCharles.Forsyth{
81837da2899SCharles.Forsyth	s.c <-= ref Rq.Error(e);
81937da2899SCharles.Forsyth	exit;
82037da2899SCharles.Forsyth}
821