MODULE ZlibDeflate;
IMPORT
SYSTEM, Zlib, ZlibBuffers;
CONST
Ok* = Zlib.Ok; StreamEnd* = Zlib.StreamEnd;
StreamError* = Zlib.StreamError;DataError* = Zlib.DataError; MemError* = Zlib.MemError; BufError* = Zlib.BufError;
NoFlush* = Zlib.NoFlush; PartialFlush = Zlib.PartialFlush; SyncFlush* = Zlib.SyncFlush; FullFlush* = Zlib.FullFlush; Finish* = Zlib.Finish;
DefaultCompression* = Zlib.DefaultCompression; NoCompression* = Zlib.NoCompression;
BestSpeed* = Zlib.BestSpeed; BestCompression* = Zlib.BestCompression;
DefaultStrategy* = Zlib.DefaultStrategy; Filtered* = Zlib.Filtered; HuffmanOnly* = Zlib.HuffmanOnly;
Binary* = Zlib.Binary; Ascii* = Zlib.Ascii; Unknown* = Zlib.Unknown;
InitState = 1; BusyState = 2; FinishState = 3;
NeedMore = 1; BlockDone = 2; FinishStarted = 3; FinishDone = 4;
StoredBlock = 0; StaticTrees = 1; DynamicTrees = 2;
Deflated = 8;
PresetDict = 20H;
LengthCodes = 29; Literals = 256; LitLenCodes = Literals + 1 + LengthCodes; DistCodes = 30; BitCodes = 19;
HeapSize = 2 * LitLenCodes + 1; MaxBits = 15; MaxBitLenBits = 7; DistCodeLen = 512; EndBlock = 256; BitBufSize = 16;
Rep3To6 = 16; RepZero3To10 = 17; RepZero11To138 = 18;
WindowBits = 15; WindowSize = ASH(1, WindowBits);
MinMatch = 3; MaxMatch = 258;
MinLookAhead = MinMatch + MaxMatch + 1; MaxDist = WindowSize - MinLookAhead;
TooFar = 4096;
MemLevel = 8;
HashBits = MemLevel + 7; HashSize = ASH(1, HashBits);
HashShift = (HashBits + (MinMatch - 1)) DIV MinMatch;
LitBufSize = ASH(1, MemLevel + 6);
PendingBufSize = ASH(LitBufSize, 2);
TYPE
Node = RECORD
freqOrCode: INTEGER;
dadOrLen: INTEGER
END;
Nodes = POINTER TO ARRAY OF Node;
Bits = POINTER TO ARRAY OF INTEGER;
StaticTree = RECORD
node: Nodes;
bits: Bits;
base: INTEGER;
elems: INTEGER;
maxLength: INTEGER
END;
Tree = RECORD
node: Nodes;
maxCode: INTEGER;
static: StaticTree
END;
Window = ARRAY 2 * WindowSize OF CHAR;
PendingBuffer = RECORD
buf: POINTER TO ARRAY PendingBufSize OF CHAR;
beg: LONGINT;
end: LONGINT
END;
Stream* = RECORD
in*, out*: ZlibBuffers.Buffer;
res-: LONGINT;
level-: SHORTINT;
strategy-: SHORTINT;
dataType-: SHORTINT;
wrapper-: BOOLEAN;
open-: BOOLEAN;
trailerDone: BOOLEAN;
lastFlush: SHORTINT;
status: SHORTINT;
adler: LONGINT;
window: POINTER TO Window;
block: LONGINT;
hash: LONGINT;
prev: POINTER TO ARRAY WindowSize OF LONGINT;
head: POINTER TO ARRAY HashSize OF LONGINT;
string: LONGINT;
lookAhead: LONGINT;
match: LONGINT;
matchLen: LONGINT;
prevMatch: LONGINT;
prevLen: LONGINT;
prevAvail: BOOLEAN;
pend: PendingBuffer;
ltree, dtree, btree: Tree;
lnode, dnode, bnode: Nodes;
bitLenCount: ARRAY MaxBits + 1 OF INTEGER;
heap: ARRAY HeapSize OF INTEGER;
heapLen: INTEGER;
heapMax: INTEGER;
depth: ARRAY HeapSize OF INTEGER;
lbuf: POINTER TO ARRAY LitBufSize OF CHAR;
dbuf: POINTER TO ARRAY LitBufSize OF INTEGER;
lastLit: LONGINT;
buf: LONGINT;
bits: INTEGER;
lastEobLen: INTEGER;
optLen: LONGINT;
staticLen: LONGINT;
END;
Compressor = PROCEDURE (VAR s: Stream; flush: SHORTINT): SHORTINT;
VAR
ExtraLenBits, ExtraDistBits, ExtraBitBits: Bits;
LTree, DTree, BTree: StaticTree;
BaseLength: ARRAY LengthCodes OF INTEGER;
BaseDist: ARRAY DistCodes OF INTEGER;
LengthCode: ARRAY MaxMatch - MinMatch + 1 OF CHAR;
DistCode: ARRAY DistCodeLen OF CHAR;
BitOrder: ARRAY BitCodes OF SHORTINT;
ConfigTable: ARRAY 10 OF RECORD
GoodLen: INTEGER;
MaxLazy: INTEGER;
NiceLen: INTEGER;
MaxChain: INTEGER;
Compress: Compressor;
END;
PROCEDURE PutChar(VAR pend: PendingBuffer; c: CHAR);
BEGIN
pend.buf[pend.end] := c;
INC(pend.end)
END PutChar;
PROCEDURE Put16BitsLSB(VAR pend: PendingBuffer; b: LONGINT);
BEGIN
PutChar(pend, CHR(b MOD 100H));
PutChar(pend, CHR((b DIV 100H) MOD 100H))
END Put16BitsLSB;
PROCEDURE Put16BitsMSB(VAR pend: PendingBuffer; b: LONGINT);
BEGIN
PutChar(pend, CHR((b DIV 100H) MOD 100H));
PutChar(pend, CHR(b MOD 100H))
END Put16BitsMSB;
PROCEDURE Put32BitsMSB(VAR pend: PendingBuffer; b: LONGINT);
BEGIN
Put16BitsMSB(pend, (b DIV 10000H) MOD 10000H);
Put16BitsMSB(pend, b MOD 10000H)
END Put32BitsMSB;
PROCEDURE ReverseBits(code, len: INTEGER): INTEGER;
VAR
res: INTEGER;
BEGIN
res := 0;
REPEAT
res := res * 2; INC(res, code MOD 2);
code := code DIV 2; DEC(len)
UNTIL len = 0;
RETURN res
END ReverseBits;
PROCEDURE SendBits(VAR stream: Stream; val: LONGINT; len: INTEGER);
BEGIN
INC(stream.buf, ASH(val, stream.bits)); INC(stream.bits, len);
IF stream.bits > BitBufSize THEN
Put16BitsLSB(stream.pend, stream.buf);
stream.buf := SYSTEM.LSH(stream.buf, -BitBufSize); DEC(stream.bits, BitBufSize)
END
END SendBits;
PROCEDURE SendCode(VAR stream: Stream; VAR node: Node);
BEGIN
SendBits(stream, node.freqOrCode, node.dadOrLen)
END SendCode;
PROCEDURE FlushBits(VAR stream: Stream);
BEGIN
IF stream.bits = BitBufSize THEN
Put16BitsLSB(stream.pend, stream.buf);
stream.buf := 0; stream.bits := 0
ELSIF stream.bits >= 8 THEN
PutChar(stream.pend, CHR(stream.buf));
stream.buf := SYSTEM.LSH(stream.buf, -8); DEC(stream.bits, 8)
END
END FlushBits;
PROCEDURE FlushPending(VAR pend: PendingBuffer; VAR out: ZlibBuffers.Buffer);
VAR
len: LONGINT;
BEGIN
len := pend.end - pend.beg;
IF len > out.avail THEN len := out.avail END;
IF len > 0 THEN
ZlibBuffers.WriteBytes(out, pend.buf^, pend.beg, len);
INC(pend.beg, len);
IF pend.beg = pend.end THEN
pend.beg := 0; pend.end := 0
END
END
END FlushPending;
PROCEDURE WindupBits(VAR stream: Stream);
BEGIN
IF stream.bits > 8 THEN
Put16BitsLSB(stream.pend, stream.buf)
ELSIF stream.bits > 0 THEN
PutChar(stream.pend, CHR(stream.buf))
END;
stream.buf := 0; stream.bits := 0
END WindupBits;
PROCEDURE SetDataType(VAR stream: Stream);
VAR
n, ascii, bin: LONGINT;
BEGIN
WHILE n < 7 DO INC(bin, LONG(stream.lnode[n].freqOrCode)); INC(n) END;
WHILE n < 128 DO INC(ascii, LONG(stream.lnode[n].freqOrCode)); INC(n) END;
WHILE n < Literals DO INC(bin, LONG(stream.lnode[n].freqOrCode)); INC(n) END;
IF (4 * bin) > ascii THEN stream.dataType := Binary ELSE stream.dataType := Ascii END
END SetDataType;
PROCEDURE GenCodes(VAR node: Nodes; maxCode: INTEGER; VAR count: ARRAY OF INTEGER);
VAR
nextCode: ARRAY MaxBits + 1 OF INTEGER;
code, bits, n, len : INTEGER;
BEGIN
code := 0;
FOR bits := 1 TO MaxBits DO
code := INTEGER(ASH(code + count[bits - 1], 1));
nextCode[bits] := code
END;
ASSERT(code + count[MaxBits] - 1 = ASH(1, MaxBits) - 1, 110);
FOR n := 0 TO maxCode DO
len := node[n].dadOrLen;
IF len # 0 THEN
node[n].freqOrCode := ReverseBits(nextCode[len], len); INC(nextCode[len])
END
END
END GenCodes;
PROCEDURE GenBitLen(VAR stream: Stream; VAR tree: Tree);
VAR
node: Nodes;
stree: StaticTree;
bits, h, n, m, overflow, xbits : INTEGER;
freq: LONGINT;
BEGIN
node := tree.node;
stree := tree.static;
overflow := 0;
FOR bits := 0 TO MaxBits DO stream.bitLenCount[bits] := 0 END;
node[stream.heap[stream.heapMax]].dadOrLen := 0;
FOR h := stream.heapMax + 1 TO HeapSize - 1 DO
n := stream.heap[h];
bits := node[node[n].dadOrLen].dadOrLen + 1;
IF bits > stree.maxLength THEN
bits := stree.maxLength; INC(overflow)
END;
node[n].dadOrLen := bits;
IF n <= tree.maxCode THEN
INC(stream.bitLenCount[bits]);
IF n >= stree.base THEN xbits := stree.bits[n - stree.base] ELSE xbits := 0 END;
freq := node[n].freqOrCode;
INC(stream.optLen, freq * (bits + xbits));
IF stree.node # NIL THEN INC(stream.staticLen, freq * (stree.node[n].dadOrLen + xbits)) END
END
END;
IF overflow # 0 THEN
REPEAT
bits := stree.maxLength - 1;
WHILE stream.bitLenCount[bits] = 0 DO DEC(bits) END;
DEC(stream.bitLenCount[bits]);
INC(stream.bitLenCount[bits + 1], 2);
DEC(stream.bitLenCount[stree.maxLength]); DEC(overflow, 2)
UNTIL overflow <= 0;
bits := stree.maxLength;
WHILE bits > 0 DO
n := stream.bitLenCount[bits];
WHILE n # 0 DO
DEC(h); m := stream.heap[h];
IF m <= tree.maxCode THEN
IF node[m].dadOrLen # bits THEN
INC(stream.optLen, (bits - node[m].dadOrLen) * LONG(node[m].freqOrCode));
node[m].dadOrLen := bits
END;
DEC(n)
END
END;
DEC(bits)
END
END
END GenBitLen;
PROCEDURE Sift(VAR stream: Stream; VAR node: Nodes; k: INTEGER);
VAR
v, i: INTEGER;
PROCEDURE Smaller(n, m: INTEGER): BOOLEAN;
BEGIN
RETURN (node[n].freqOrCode < node[m].freqOrCode) OR
((node[n].freqOrCode = node[m].freqOrCode) & (stream.depth[n] <= stream.depth[m]))
END Smaller;
BEGIN
v := stream.heap[k];
i := k * 2;
WHILE (i <= stream.heapLen) DO
IF (i < stream.heapLen) & Smaller(stream.heap[i + 1], stream.heap[i]) THEN INC(i) END;
IF Smaller(v, stream.heap[i]) THEN
stream.heap[k] := v; RETURN
ELSE
stream.heap[k] := stream.heap[i]; k := i;
i := i * 2
END
END;
stream.heap[k] := v
END Sift;
PROCEDURE BuildTree(VAR stream: Stream; VAR tree: Tree);
VAR
node: Nodes;
stree: StaticTree;
n, m, maxCode, next: INTEGER;
BEGIN
node := tree.node; stree := tree.static; maxCode := -1;
stream.heapLen := 0; stream.heapMax := HeapSize;
FOR n := 0 TO stree.elems - 1 DO
IF node[n].freqOrCode # 0 THEN
maxCode := n;
INC(stream.heapLen); stream.heap[stream.heapLen] := n;
stream.depth[n] := 0
ELSE
node[n].dadOrLen := 0
END
END;
WHILE stream.heapLen < 2 DO
INC(stream.heapLen);
IF maxCode < 2 THEN INC(maxCode); n := maxCode ELSE n := 0 END;
stream.heap[stream.heapLen] := n;
node[n].freqOrCode := 1;
stream.depth[n] := 0;
DEC(stream.optLen);
IF stree.node # NIL THEN DEC(stream.staticLen, LONG(stree.node[n].dadOrLen)) END;
END;
tree.maxCode := maxCode;
FOR n := stream.heapLen DIV 2 TO 1 BY -1 DO
Sift(stream, node, n)
END;
next := stree.elems;
REPEAT
n := stream.heap[1];
stream.heap[1] := stream.heap[stream.heapLen];
DEC(stream.heapLen);
Sift(stream, node, 1);
m := stream.heap[1];
DEC(stream.heapMax); stream.heap[stream.heapMax] := n;
DEC(stream.heapMax); stream.heap[stream.heapMax] := m;
node[next].freqOrCode := node[n].freqOrCode + node[m].freqOrCode;
IF stream.depth[n] > stream.depth[m] THEN stream.depth[next] := stream.depth[n] + 1
ELSE stream.depth[next] := stream.depth[m] + 1
END;
node[n].dadOrLen := next; node[m].dadOrLen := next;
stream.heap[1] := next; INC(next);
Sift(stream, node, 1);
UNTIL stream.heapLen < 2;
DEC(stream.heapMax); stream.heap[stream.heapMax] := stream.heap[1];
GenBitLen(stream, tree);
GenCodes(node, maxCode, stream.bitLenCount)
END BuildTree;
PROCEDURE ScanTree(VAR stream: Stream; node: Nodes; max: INTEGER);
VAR
n, prevLen, curLen, nextLen, count, maxCount, minCount: INTEGER;
BEGIN
prevLen := -1; nextLen := node[0].dadOrLen; count := 0;
IF nextLen = 0 THEN maxCount := 138; minCount := 3
ELSE maxCount := 7; minCount := 4
END;
node[max + 1].dadOrLen := MAX(INTEGER);
FOR n := 0 TO max DO
curLen := nextLen; nextLen := node[n + 1].dadOrLen;
INC(count);
IF (count >= maxCount) OR (curLen # nextLen) THEN
IF count < minCount THEN
INC(stream.bnode[curLen].freqOrCode, count);
ELSIF curLen # 0 THEN
IF curLen # prevLen THEN INC(stream.bnode[curLen].freqOrCode) END;
INC(stream.bnode[Rep3To6].freqOrCode)
ELSIF count <= 10 THEN
INC(stream.bnode[RepZero3To10].freqOrCode)
ELSE
INC(stream.bnode[RepZero11To138].freqOrCode)
END;
count := 0; prevLen := curLen;
IF nextLen = 0 THEN maxCount := 138; minCount := 3
ELSIF curLen = nextLen THEN maxCount := 6; minCount := 3
ELSE maxCount := 7; minCount := 4
END
END
END
END ScanTree;
PROCEDURE BuildBitLenTree(VAR stream: Stream): INTEGER;
VAR
max: INTEGER;
BEGIN
ScanTree(stream, stream.ltree.node, stream.ltree.maxCode);
ScanTree(stream, stream.dtree.node, stream.dtree.maxCode);
BuildTree(stream, stream.btree);
max := BitCodes - 1;
WHILE (max >= 3) & (stream.bnode[BitOrder[max]].dadOrLen = 0) DO DEC(max) END;
INC(stream.optLen, LONG(3 * (max + 1) + 5 + 5 + 4));
RETURN max
END BuildBitLenTree;
PROCEDURE SendTree(VAR stream: Stream; node: Nodes; max: INTEGER);
VAR
n, prevLen, curLen, nextLen, count, maxCount, minCount: INTEGER;
BEGIN
prevLen := -1; nextLen := node[0].dadOrLen; count := 0;
IF nextLen = 0 THEN maxCount := 138; minCount := 3
ELSE maxCount := 7; minCount := 4 END;
node[max + 1].dadOrLen := MAX(INTEGER);
FOR n := 0 TO max DO
curLen := nextLen; nextLen := node[n + 1].dadOrLen;
INC(count);
IF (count >= maxCount) OR (curLen # nextLen) THEN
IF count < minCount THEN
REPEAT
SendCode(stream, stream.bnode[curLen]);
DEC(count)
UNTIL count = 0
ELSIF curLen # 0 THEN
IF curLen # prevLen THEN
SendCode(stream, stream.bnode[curLen]); DEC(count)
END;
ASSERT((3 <= count) & (count <= 6), 110);
SendCode(stream, stream.bnode[Rep3To6]); SendBits(stream, count - 3, 2)
ELSIF count <= 10 THEN
SendCode(stream, stream.bnode[RepZero3To10]); SendBits(stream, count - 3, 3)
ELSE
SendCode(stream, stream.bnode[RepZero11To138]); SendBits(stream, count - 11, 7)
END;
count := 0; prevLen := curLen;
IF nextLen = 0 THEN maxCount := 138; minCount := 3
ELSIF curLen = nextLen THEN maxCount := 6; minCount := 3
ELSE maxCount := 7; minCount := 4
END
END
END
END SendTree;
PROCEDURE SendAllTrees(VAR stream: Stream; lcodes, dcodes, blcodes: INTEGER);
VAR
rank: INTEGER;
BEGIN
ASSERT((lcodes >= 257) & (dcodes >= 1) & (blcodes >= 4), 100);
ASSERT((lcodes <= LitLenCodes) & (dcodes <= DistCodes) & (blcodes <= BitCodes), 101);
SendBits(stream, lcodes - 257, 5); SendBits(stream, dcodes - 1, 5); SendBits(stream, blcodes - 4, 4);
FOR rank := 0 TO blcodes - 1 DO
SendBits(stream, stream.bnode[BitOrder[rank]].dadOrLen, 3)
END;
SendTree(stream, stream.lnode, lcodes - 1);
SendTree(stream, stream.dnode, dcodes - 1)
END SendAllTrees;
PROCEDURE InitStaticTrees;
VAR
n, code: LONGINT;
length, dist: INTEGER;
count: ARRAY MaxBits + 1 OF INTEGER;
BEGIN
NEW(ExtraLenBits, LengthCodes);
FOR n := 0 TO 3 DO ExtraLenBits[n] := 0 END;
FOR n := 4 TO LengthCodes - 2 DO ExtraLenBits[n] := SHORT((n - 4) DIV 4) END;
ExtraLenBits[LengthCodes - 1] := 0;
NEW(ExtraDistBits, DistCodes);
FOR n := 0 TO 1 DO ExtraDistBits[n] := 0 END;
FOR n := 2 TO DistCodes - 1 DO ExtraDistBits[n] := SHORT((n - 2) DIV 2) END;
NEW(ExtraBitBits, BitCodes);
FOR n := 0 TO BitCodes - 4 DO ExtraBitBits[n] := 0 END;
ExtraBitBits[BitCodes - 3] := 2; ExtraBitBits[BitCodes - 2] := 3; ExtraBitBits[BitCodes - 1] := 7;
BitOrder[0] := 16; BitOrder[1] := 17; BitOrder[2] := 18; BitOrder[3] := 0; BitOrder[4] := 8; BitOrder[5] := 7; BitOrder[6] := 9;
BitOrder[7] := 6; BitOrder[8] := 10; BitOrder[9] := 5; BitOrder[10] := 11; BitOrder[11] := 4; BitOrder[12] := 12; BitOrder[13] := 3;
BitOrder[14] := 13; BitOrder[15] := 2; BitOrder[16] := 14; BitOrder[17] := 1; BitOrder[18] := 15;
length := 0;
FOR code := 0 TO LengthCodes - 2 DO
BaseLength[code] := length;
FOR n := 0 TO ASH(1, ExtraLenBits[code]) - 1 DO
LengthCode[length] := CHR(code); INC(length)
END
END;
ASSERT(length = 256, 110);
LengthCode[length - 1] := CHR(code);
dist := 0;
FOR code := 0 TO 15 DO
BaseDist[code] := dist;
FOR n := 0 TO ASH(1, ExtraDistBits[code]) - 1 DO
DistCode[dist] := CHR(code); INC(dist)
END
END;
ASSERT(dist = 256, 111);
dist := INTEGER(ASH(dist, -7));
FOR code := 16 TO DistCodes - 1 DO
BaseDist[code] := INTEGER(ASH(dist, 7));
FOR n := 0 TO ASH(1, ExtraDistBits[code] - 7) - 1 DO
DistCode[256 + dist] := CHR(code); INC(dist)
END
END;
ASSERT(dist = 256, 112);
NEW(LTree.node, LitLenCodes + 2);
LTree.bits := ExtraLenBits; LTree.base := Literals + 1; LTree.elems := LitLenCodes; LTree.maxLength := MaxBits;
FOR n := 0 TO MaxBits DO count[n] := 0 END;
FOR n := 0 TO 143 DO LTree.node[n].dadOrLen := 8 END; INC(count[8], 143 - (-1));
FOR n := 144 TO 255 DO LTree.node[n].dadOrLen := 9 END; INC(count[9], 255 - 143);
FOR n := 256 TO 279 DO LTree.node[n].dadOrLen := 7 END; INC(count[7], 279 - 255);
FOR n := 280 TO 287 DO LTree.node[n].dadOrLen := 8 END; INC(count[8], 287 - 279);
GenCodes(LTree.node, LitLenCodes + 1, count);
NEW(DTree.node, DistCodes);
DTree.bits := ExtraDistBits; DTree.base := 0; DTree.elems := DistCodes; DTree.maxLength := MaxBits;
FOR n := 0 TO DistCodes - 1 DO
DTree.node[n].dadOrLen := 5;
DTree.node[n].freqOrCode := ReverseBits(SHORT(n), 5)
END;
BTree.node := NIL;
BTree.bits := ExtraBitBits; BTree.base := 0; BTree.elems := BitCodes; BTree.maxLength := MaxBitLenBits;
END InitStaticTrees;
PROCEDURE InitBlock(VAR stream: Stream);
VAR
n: LONGINT;
BEGIN
FOR n := 0 TO LitLenCodes - 1 DO stream.lnode[n].freqOrCode := 0 END;
FOR n := 0 TO DistCodes - 1 DO stream.dnode[n].freqOrCode := 0 END;
FOR n := 0 TO BitCodes - 1 DO stream.bnode[n].freqOrCode := 0 END;
stream.lnode[EndBlock].freqOrCode := 1;
stream.optLen := 0; stream.staticLen := 0;
stream.lastLit := 0
END InitBlock;
PROCEDURE InitTrees(VAR stream: Stream);
BEGIN
NEW(stream.lnode, HeapSize); NEW(stream.dnode, 2 * DistCodes + 1); NEW(stream.bnode, 2 * BitCodes + 1);
stream.ltree.node := stream.lnode; stream.dtree.node := stream.dnode; stream.btree.node := stream.bnode;
stream.ltree.static := LTree; stream.dtree.static := DTree; stream.btree.static := BTree;
stream.buf := 0; stream.bits := 0; stream.lastEobLen := 8;
InitBlock(stream)
END InitTrees;
PROCEDURE FreeTrees(VAR stream: Stream);
BEGIN
stream.lnode := NIL; stream.dnode := NIL; stream.bnode := NIL
END FreeTrees;
PROCEDURE AlignTrees(VAR stream: Stream);
BEGIN
SendBits(stream, ASH(StaticTrees, 1), 3);
SendCode(stream, LTree.node[EndBlock]);
FlushBits(stream);
IF (1 + stream.lastEobLen + 10 - stream.bits) < 9 THEN
SendBits(stream, ASH(StaticTrees, 1), 3);
SendCode(stream, LTree.node[EndBlock]);
FlushBits(stream)
END;
stream.lastEobLen := 7
END AlignTrees;
PROCEDURE CopyBlock(VAR stream: Stream; VAR buf: ARRAY OF CHAR; offset, len: LONGINT; header: BOOLEAN);
VAR
BEGIN
WindupBits(stream);
stream.lastEobLen := 8;
IF header THEN
Put16BitsLSB(stream.pend, len);
Put16BitsLSB(stream.pend, -(len + 1));
END;
WHILE len > 0 DO
PutChar(stream.pend, buf[offset]);
INC(offset); DEC(len)
END
END CopyBlock;
PROCEDURE StoreBlock(VAR stream: Stream; VAR buf: ARRAY OF CHAR; offset, len: LONGINT; eof: BOOLEAN);
VAR
value: LONGINT;
BEGIN
value := ASH(StoredBlock, 1);
IF eof THEN INC(value) END;
SendBits(stream, value, 3);
CopyBlock(stream, buf, offset, len, TRUE);
END StoreBlock;
PROCEDURE CompressBlock(VAR stream: Stream; lnode, dnode: Nodes);
VAR
dist: INTEGER;
lc: INTEGER;
code: INTEGER;
extra: INTEGER;
lx: LONGINT;
BEGIN
IF stream.lastLit # 0 THEN
lx := 0;
REPEAT
dist := stream.dbuf[lx];
lc := ORD(stream.lbuf[lx]);
INC(lx);
IF dist = 0 THEN
SendCode(stream, lnode[lc]);
ELSE
code := ORD(LengthCode[lc]);
SendCode(stream, lnode[code + Literals + 1]);
extra := ExtraLenBits[code];
IF extra # 0 THEN
DEC(lc, BaseLength[code]);
SendBits(stream, lc, extra)
END;
DEC(dist);
IF dist < 256 THEN code := ORD(DistCode[dist]);
ELSE code := ORD(DistCode[256 + ASH(dist, -7)])
END;
ASSERT(code < DistCodes, 110);
SendCode(stream, dnode[code]);
extra := ExtraDistBits[code];
IF extra # 0 THEN
DEC(dist, BaseDist[code]);
SendBits(stream, dist, extra)
END
END
UNTIL lx = stream.lastLit
END;
SendCode(stream, lnode[EndBlock]);
stream.lastEobLen := lnode[EndBlock].dadOrLen
END CompressBlock;
PROCEDURE FlushBlock(VAR stream: Stream; VAR buf: ARRAY OF CHAR; pos, len: LONGINT; eof: BOOLEAN);
VAR
max: INTEGER;
optLen, staticLen: LONGINT;
value: LONGINT;
BEGIN
IF stream.level > 0 THEN
IF stream.dataType = Unknown THEN SetDataType(stream) END;
BuildTree(stream, stream.ltree);
BuildTree(stream, stream.dtree);
max := BuildBitLenTree(stream);
optLen := (stream.optLen + 3 + 7) DIV 8;
staticLen := (stream.staticLen + 3 + 7) DIV 8;
IF staticLen < optLen THEN optLen := staticLen END;
ELSE
ASSERT(pos >= 0, 110);
optLen := len + 5;
staticLen := optLen
END;
IF len + 4 <= optLen THEN
ASSERT(pos >= 0, 111);
StoreBlock(stream, buf, pos, len, eof);
ELSIF staticLen = optLen THEN
value := ASH(StaticTrees, 1);
IF eof THEN INC(value) END;
SendBits(stream, value, 3);
CompressBlock(stream, LTree.node, DTree.node)
ELSE
value := ASH(DynamicTrees, 1);
IF eof THEN INC(value) END;
SendBits(stream, value, 3);
SendAllTrees(stream, stream.ltree.maxCode + 1, stream.dtree.maxCode + 1, max + 1);
CompressBlock(stream, stream.lnode, stream.dnode);
END;
InitBlock(stream);
IF eof THEN
WindupBits(stream)
END
END FlushBlock;
PROCEDURE TallyLit(VAR stream: Stream; ch: CHAR): BOOLEAN;
BEGIN
stream.lbuf[stream.lastLit] := ch;
stream.dbuf[stream.lastLit] := 0;
INC(stream.lastLit);
INC(stream.lnode[ORD(ch)].freqOrCode);
RETURN (stream.lastLit = LitBufSize - 1)
END TallyLit;
PROCEDURE TallyDistLen(VAR stream: Stream; dist, len: INTEGER): BOOLEAN;
BEGIN
ASSERT(len < 256, 99);
stream.lbuf[stream.lastLit] := CHR(len);
stream.dbuf[stream.lastLit] := dist;
INC(stream.lastLit);
DEC(dist);
INC(stream.lnode[ORD(LengthCode[len]) + Literals + 1].freqOrCode);
IF dist < 256 THEN dist := ORD(DistCode[dist])
ELSE dist := ORD(DistCode[256 + ASH(dist, -7)])
END;
INC(stream.dnode[dist].freqOrCode);
RETURN (stream.lastLit = LitBufSize - 1)
END TallyDistLen;
PROCEDURE ClearHash(VAR stream: Stream);
VAR
i: LONGINT;
BEGIN
FOR i := 0 TO HashSize - 1 DO
stream.head[i] := 0
END
END ClearHash;
PROCEDURE UpdateHash(VAR h: LONGINT; ch: CHAR);
BEGIN
h := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, ASH(h, HashShift)) / SYSTEM.VAL(SET, LONG(ORD(ch)))) MOD HashSize
END UpdateHash;
PROCEDURE InsertString(VAR stream: Stream; pos: LONGINT; VAR head: LONGINT);
BEGIN
UpdateHash(stream.hash, stream.window[pos + MinMatch - 1]);
head := stream.head[stream.hash];
stream.prev[pos MOD WindowSize] := head;
stream.head[stream.hash] := pos
END InsertString;
PROCEDURE InitMatches(VAR stream: Stream);
BEGIN
ClearHash(stream);
stream.string := 0; stream.block := 0; stream.lookAhead := 0;
stream.matchLen := MinMatch - 1; stream.prevLen := MinMatch - 1;
stream.prevAvail := FALSE; stream.hash := 0;
END InitMatches;
PROCEDURE LongestMatch(VAR stream: Stream; cur: LONGINT): LONGINT;
VAR
chainLen: LONGINT;
scan: LONGINT;
match: LONGINT;
len: LONGINT;
bestLen: LONGINT;
niceLen: LONGINT;
limit: LONGINT;
strend: LONGINT;
scanEnd1, scanEnd: CHAR;
BEGIN
bestLen := stream.prevLen;
IF bestLen >= ConfigTable[stream.level].GoodLen THEN
chainLen := ConfigTable[stream.level].MaxChain DIV 4
ELSE
chainLen := ConfigTable[stream.level].MaxChain;
END;
IF ConfigTable[stream.level].NiceLen > stream.lookAhead THEN
niceLen := stream.lookAhead
ELSE
niceLen := ConfigTable[stream.level].NiceLen
END;
scan := stream.string;
IF scan > MaxDist THEN limit := scan - MaxDist ELSE limit := 0 END;
strend := scan + MaxMatch;
scanEnd1 := stream.window[scan + bestLen - 1];
scanEnd := stream.window[scan + bestLen];
ASSERT(scan <= 2 * WindowSize - MinLookAhead, 110);
len := -1;
REPEAT
IF cur >= stream.string THEN RETURN 0 END;
match := cur;
IF (stream.window[match + bestLen] = scanEnd) & (stream.window[match + bestLen - 1] = scanEnd1) &
(stream.window[match] = stream.window[scan]) & (stream.window[match + 1] = stream.window[scan + 1]) THEN
INC(scan, 2); INC(match, 2);
ASSERT(stream.window[match] = stream.window[scan], 112);
REPEAT
INC(match); INC(scan)
UNTIL (stream.window[match] # stream.window[scan]) OR (scan >= strend);
ASSERT(scan <= 2 * WindowSize - 1, 113);
len := MaxMatch - (strend - scan);
scan := strend - MaxMatch;
IF len > bestLen THEN
stream.match := cur;
bestLen := len;
scanEnd1 := stream.window[scan + bestLen - 1];
scanEnd := stream.window[scan + bestLen]
END
END;
cur := stream.prev[cur MOD WindowSize];
DEC(chainLen)
UNTIL (len >= niceLen) OR (cur <= limit) OR (chainLen = 0);
IF bestLen > MaxMatch THEN bestLen := MaxMatch END;
IF bestLen <= stream.lookAhead THEN
RETURN bestLen
ELSE
RETURN stream.lookAhead
END
END LongestMatch;
PROCEDURE CheckMatch(VAR stream: Stream; start, match, len: LONGINT);
BEGIN
WHILE len # 0 DO
ASSERT(stream.window[match] = stream.window[start]);
INC(match); INC(start); DEC(len)
END
END CheckMatch;
PROCEDURE FillWindow(VAR stream: Stream);
VAR
n, len: LONGINT;
more: LONGINT;
BEGIN
more := 2 * WindowSize - (stream.lookAhead + stream.string);
REPEAT
IF stream.string >= WindowSize + MaxDist THEN
SYSTEM.MOVE(SYSTEM.ADR(stream.window[WindowSize]), SYSTEM.ADR(stream.window[0]), WindowSize);
DEC(stream.match, WindowSize); DEC(stream.string, WindowSize); DEC(stream.block, WindowSize);
n := HashSize;
REPEAT
DEC(n);
IF stream.head[n] >= WindowSize THEN
DEC(stream.head[n], WindowSize)
ELSE
stream.head[n] := 0
END
UNTIL n = 0;
n := WindowSize;
REPEAT
DEC(n);
IF stream.prev[n] >= WindowSize THEN
DEC(stream.prev[n], WindowSize)
ELSE
stream.prev[n] := 0
END
UNTIL n = 0;
INC(more, WindowSize)
END;
len := stream.in.avail;
IF len = 0 THEN RETURN END;
ASSERT(more >= 2, 110);
IF len > more THEN len := more END;
ZlibBuffers.ReadBytes(stream.in, stream.window^, stream.string + stream.lookAhead, len);
IF stream.wrapper THEN
stream.adler := Zlib.Adler32(stream.adler, stream.window^, stream.string + stream.lookAhead, len);
END;
INC(stream.lookAhead, len); DEC(more, len);
IF stream.lookAhead >= MinMatch THEN
stream.hash := LONG(ORD(stream.window[stream.string]));
UpdateHash(stream.hash, stream.window[stream.string + 1]);
END
UNTIL (stream.lookAhead >= MinLookAhead) OR (stream.in.avail = 0)
END FillWindow;
PROCEDURE CompressStored(VAR stream: Stream; flush: SHORTINT): SHORTINT;
CONST
MaxBlockSize = PendingBufSize - 5;
BEGIN
ASSERT(PendingBufSize - 5 < 0FFFFH, 110);
LOOP
IF stream.lookAhead <= 1 THEN
ASSERT((stream.string < (WindowSize + MaxDist)) OR (stream.block >= WindowSize), 111);
FillWindow(stream);
IF stream.lookAhead = 0 THEN
IF flush = NoFlush THEN RETURN NeedMore
ELSE EXIT
END
END
END;
ASSERT(stream.block >= 0, 112);
INC(stream.string, stream.lookAhead);
stream.lookAhead := 0;
ASSERT(stream.string < stream.block + MaxBlockSize, 113);
IF (stream.string - stream.block) >= MaxDist THEN
FlushBlock(stream, stream.window^, stream.block, stream.string - stream.block, FALSE);
stream.block := stream.string;
FlushPending(stream.pend, stream.out);
IF stream.out.avail = 0 THEN RETURN NeedMore
END
END
END;
FlushBlock(stream, stream.window^, stream.block, stream.string - stream.block, flush = Finish);
stream.block := stream.string;
FlushPending(stream.pend, stream.out);
IF (stream.out.avail = 0) & (flush = Finish) THEN RETURN FinishStarted
ELSIF stream.out.avail = 0 THEN RETURN NeedMore
ELSIF flush = Finish THEN RETURN FinishDone
ELSE RETURN BlockDone
END
END CompressStored;
PROCEDURE CompressFast(VAR stream: Stream; flush: SHORTINT): SHORTINT;
VAR
head: LONGINT;
mustFlush: BOOLEAN;
BEGIN
head := 0;
LOOP
IF stream.lookAhead < MinLookAhead THEN
FillWindow(stream);
IF (stream.lookAhead < MinLookAhead) & (flush = NoFlush) THEN RETURN NeedMore
ELSIF stream.lookAhead = 0 THEN EXIT
END
END;
IF stream.lookAhead >= MinMatch THEN
InsertString(stream, stream.string, head)
END;
IF (head # 0) & ((stream.string - head) <= MaxDist) THEN
IF stream.strategy # HuffmanOnly THEN
stream.matchLen := LongestMatch(stream, head)
END
END;
IF stream.matchLen >= MinMatch THEN
CheckMatch(stream, stream.string, stream.match, stream.matchLen);
mustFlush := TallyDistLen(stream, SHORT(stream.string - stream.match), SHORT(stream.matchLen - MinMatch));
DEC(stream.lookAhead, stream.matchLen);
IF (stream.matchLen <= ConfigTable[stream.level].MaxLazy) & (stream.lookAhead >= MinMatch) THEN
DEC(stream.matchLen);
REPEAT
INC(stream.string);
InsertString(stream, stream.string, head);
DEC(stream.matchLen)
UNTIL stream.matchLen = 0;
INC(stream.string);
ELSE
INC(stream.string, stream.matchLen);
stream.matchLen := 0;
stream.hash := ORD(stream.window[stream.string]);
UpdateHash(stream.hash, stream.window[stream.string + 1])
END
ELSE
mustFlush := TallyLit(stream, stream.window[stream.string]);
DEC(stream.lookAhead);
INC(stream.string)
END;
IF mustFlush THEN
FlushBlock(stream, stream.window^, stream.block, stream.string - stream.block, FALSE);
stream.block := stream.string;
FlushPending(stream.pend, stream.out);
IF stream.out.avail = 0 THEN RETURN NeedMore
END
END
END;
FlushBlock(stream, stream.window^, stream.block, stream.string - stream.block, flush = Finish);
stream.block := stream.string;
FlushPending(stream.pend, stream.out);
IF (stream.out.avail = 0) & (flush = Finish) THEN RETURN FinishStarted
ELSIF stream.out.avail = 0 THEN RETURN NeedMore
ELSIF flush = Finish THEN RETURN FinishDone
ELSE RETURN BlockDone
END
END CompressFast;
PROCEDURE CompressSlow(VAR stream: Stream; flush: SHORTINT): SHORTINT;
VAR
head: LONGINT;
maxIns: LONGINT;
mustFlush: BOOLEAN;
BEGIN
head := 0;
LOOP
IF stream.lookAhead < MinLookAhead THEN
FillWindow(stream);
IF (stream.lookAhead < MinLookAhead) & (flush = NoFlush) THEN RETURN NeedMore
ELSIF stream.lookAhead = 0 THEN EXIT
END
END;
IF stream.lookAhead >= MinMatch THEN
InsertString(stream, stream.string, head);
END;
stream.prevLen := stream.matchLen;
stream.prevMatch := stream.match;
stream.matchLen := MinMatch - 1;
IF (head # 0) & (stream.prevLen < ConfigTable[stream.level].MaxLazy) & (stream.string - head <= MaxDist) THEN
IF stream.strategy # HuffmanOnly THEN
stream.matchLen := LongestMatch(stream, head);
END;
IF (stream.matchLen <= 5) &
((stream.strategy = Filtered) OR ((stream.matchLen = MinMatch) & ((stream.string - stream.match) > TooFar))) THEN
stream.matchLen := MinMatch - 1
END
END;
IF (stream.prevLen >= MinMatch) & (stream.matchLen <= stream.prevLen) THEN
maxIns := stream.string + stream.lookAhead - MinMatch;
CheckMatch(stream, stream.string - 1, stream.prevMatch, stream.prevLen);
mustFlush := TallyDistLen(stream, SHORT(stream.string - 1 - stream.prevMatch), SHORT(stream.prevLen - MinMatch));
DEC(stream.lookAhead, stream.prevLen - 1);
DEC(stream.prevLen, 2);
REPEAT
INC(stream.string);
IF stream.string <= maxIns THEN
InsertString(stream, stream.string, head)
END;
DEC(stream.prevLen);
UNTIL stream.prevLen = 0;
stream.prevAvail := FALSE;
stream.matchLen := MinMatch - 1;
INC(stream.string);
IF mustFlush THEN
FlushBlock(stream, stream.window^, stream.block, stream.string - stream.block, FALSE);
stream.block := stream.string;
FlushPending(stream.pend, stream.out);
IF stream.out.avail = 0 THEN RETURN NeedMore
END
END
ELSIF stream.prevAvail THEN
mustFlush := TallyLit(stream, stream.window[stream.string - 1]);
IF mustFlush THEN
FlushBlock(stream, stream.window^, stream.block, stream.string - stream.block, FALSE);
stream.block := stream.string;
FlushPending(stream.pend, stream.out)
END;
INC(stream.string);
DEC(stream.lookAhead);
IF stream.out.avail = 0 THEN RETURN NeedMore
END
ELSE
stream.prevAvail := TRUE;
INC(stream.string);
DEC(stream.lookAhead)
END
END;
ASSERT(flush # NoFlush, 110);
IF stream.prevAvail THEN
mustFlush := TallyLit(stream, stream.window[stream.string - 1]);
stream.prevAvail := FALSE
END;
FlushBlock(stream, stream.window^, stream.block, stream.string - stream.block, flush = Finish);
stream.block := stream.string;
FlushPending(stream.pend, stream.out);
IF (stream.out.avail = 0) & (flush = Finish) THEN RETURN FinishStarted
ELSIF stream.out.avail = 0 THEN RETURN NeedMore
ELSIF flush = Finish THEN RETURN FinishDone
ELSE RETURN BlockDone
END
END CompressSlow;
PROCEDURE Reset*(VAR stream: Stream);
BEGIN
IF ~stream.open THEN
stream.res := StreamError;
ELSE
ZlibBuffers.Reset(stream.in); ZlibBuffers.Reset(stream.out);
stream.dataType := Unknown;
stream.pend.beg := 0; stream.pend.end := 0;
stream.trailerDone := FALSE;
IF stream.wrapper THEN
stream.status := InitState
ELSE
stream.status := BusyState
END;
stream.adler := 1;
stream.lastFlush := NoFlush;
InitTrees(stream);
InitMatches(stream);
stream.res := Ok;
END
END Reset;
PROCEDURE Close*(VAR stream: Stream);
BEGIN
IF stream.open THEN
stream.window := NIL; stream.prev := NIL; stream.head := NIL;
stream.pend.buf := NIL; stream.lbuf := NIL; stream.dbuf := NIL;
FreeTrees(stream);
stream.open := FALSE; stream.res := Ok
ELSE
stream.res := StreamError
END
END Close;
PROCEDURE Open*(VAR stream: Stream; level, strategy: SHORTINT; wrapper: BOOLEAN);
BEGIN
IF level = DefaultCompression THEN level := 6 END;
IF (0 <= level) & (level <= 9) & (DefaultStrategy <= strategy) & (strategy <= HuffmanOnly) THEN
NEW(stream.window); NEW(stream.prev); NEW(stream.head);
NEW(stream.pend.buf); NEW(stream.lbuf); NEW(stream.dbuf);
IF (stream.window # NIL) & (stream.prev # NIL) & (stream.head # NIL)
& (stream.pend.buf # NIL) & (stream.lbuf # NIL) & (stream.dbuf # NIL) THEN
stream.level := level; stream.strategy := strategy; stream.wrapper := wrapper; stream.open := TRUE;
Reset(stream)
ELSE
stream.open := FALSE;
Close(stream);
stream.res := MemError
END
ELSE
stream.open := FALSE;
stream.res := StreamError
END
END Open;
PROCEDURE SetDictionary*(VAR stream: Stream; VAR dict: ARRAY OF CHAR; len: LONGINT);
VAR
offset, i, head: LONGINT;
BEGIN
IF ~stream.open OR (stream.status # InitState) THEN
stream.res := StreamError;
RETURN
END;
stream.adler := Zlib.Adler32(stream.adler, dict, 0, len);
IF len >= MinMatch THEN
IF len > MaxDist THEN
offset := len - MaxDist;
len := MaxDist
ELSE
offset := 0
END;
SYSTEM.MOVE(SYSTEM.ADR(dict[offset]), SYSTEM.ADR(stream.window[0]), len);
stream.string := len; stream.block := len;
stream.hash := ORD(stream.window[0]);
UpdateHash(stream.hash, stream.window[1]);
FOR i := 0 TO (len - MinMatch) DO
InsertString(stream, i, head)
END
END;
stream.res := Ok
END SetDictionary;
PROCEDURE Deflate*(VAR stream: Stream; flush: SHORTINT);
VAR
lastFlush, bstate: SHORTINT;
header: LONGINT;
buf: ARRAY 1 OF CHAR;
BEGIN
IF ~stream.open OR (flush < NoFlush) OR (flush > Finish) OR ((stream.status = FinishState) & (flush # Finish)) THEN
stream.res := StreamError;
RETURN
END;
IF stream.out.avail = 0 THEN
stream.res := BufError;
RETURN
END;
lastFlush := stream.lastFlush; stream.lastFlush := flush;
IF stream.status = InitState THEN
header := (((WindowBits - 8) * 10H) + Deflated) * 100H;
IF stream.level >= 7 THEN INC(header, 0C0H)
ELSIF stream.level >= 5 THEN INC(header, 80H)
ELSIF stream.level >= 3 THEN INC(header, 40H)
END;
IF stream.string # 0 THEN
INC(header, PresetDict)
END;
INC(header, 31 - (header MOD 31));
stream.status := BusyState;
Put16BitsMSB(stream.pend, header);
IF stream.string # 0 THEN
Put32BitsMSB(stream.pend, stream.adler)
END;
stream.adler := 1;
END;
IF stream.pend.end # 0 THEN
FlushPending(stream.pend, stream.out);
IF stream.out.avail = 0 THEN
stream.lastFlush := -1;
stream.res := Ok;
RETURN
END
ELSIF (stream.in.avail = 0) & (flush <= lastFlush) & (flush # Finish) THEN
stream.res := BufError;
RETURN
END;
IF (stream.status = Finish) & (stream.in.avail # 0) THEN
stream.res := BufError;
RETURN
END;
IF (stream.in.avail # 0) OR (stream.lookAhead # 0) OR ((flush # NoFlush) & (stream.status # FinishState)) THEN
bstate := ConfigTable[stream.level].Compress(stream, flush);
IF bstate IN {FinishStarted, FinishDone} THEN
stream.status := FinishState
END;
IF bstate IN {NeedMore, FinishStarted} THEN
IF stream.out.avail = 0 THEN
stream.lastFlush := -1
END;
stream.res := Ok;
RETURN
ELSIF bstate = BlockDone THEN
IF flush = PartialFlush THEN
AlignTrees(stream)
ELSE
StoreBlock(stream, buf, 0, 0, FALSE);
IF flush = FullFlush THEN
ClearHash(stream)
END
END;
FlushPending(stream.pend, stream.out);
IF stream.out.avail = 0 THEN
stream.lastFlush := -1;
stream.res := Ok;
RETURN
END
END
END;
ASSERT(stream.out.avail > 0, 111);
IF flush # Finish THEN
stream.res := Ok
ELSIF ~stream.wrapper OR stream.trailerDone THEN
stream.res := StreamEnd
ELSE
Put32BitsMSB(stream.pend, stream.adler);
FlushPending(stream.pend, stream.out);
stream.trailerDone := TRUE;
IF stream.pend.end = 0 THEN
stream.res := StreamEnd
ELSE
stream.res := Ok
END
END
END Deflate;
PROCEDURE SetParams*(VAR stream: Stream; level, strategy: SHORTINT);
BEGIN
IF level = DefaultCompression THEN
level := 6
END;
IF ~stream.open OR (level < 0) OR (9 < level) OR (strategy < DefaultStrategy) OR (HuffmanOnly < strategy) THEN
stream.res := StreamError
ELSE
IF (ConfigTable[level].Compress # ConfigTable[stream.level].Compress) & (stream.in.totalIn # 0) THEN
Deflate(stream, PartialFlush)
END;
stream.level := level;
stream.strategy := strategy
END
END SetParams;
PROCEDURE Compress* (VAR src, dst: ARRAY OF CHAR; srcoffset, srclen, dstoffset, dstlen: LONGINT; level, strategy: SHORTINT; VAR len: LONGINT; VAR res: LONGINT);
VAR s: Stream;
BEGIN
ZlibBuffers.Init(s.in, src, srcoffset, srclen, srclen);
ZlibBuffers.Init(s.out, dst, dstoffset, dstlen, dstlen);
Open(s, level, strategy, TRUE);
IF s.res = Ok THEN
Deflate(s, Finish);
IF s.res = StreamEnd THEN
len := s.out.totalOut;
Close(s);
res := s.res
ELSE
res := s.res;
IF res = Ok THEN res := BufError END;
Close(s)
END
ELSE
res := s.res
END
END Compress;
BEGIN
InitStaticTrees();
ConfigTable[0].GoodLen := 0; ConfigTable[0].MaxLazy := 0; ConfigTable[0].NiceLen := 0;
ConfigTable[0].MaxChain := 0; ConfigTable[0].Compress := CompressStored;
ConfigTable[1].GoodLen := 4; ConfigTable[1].MaxLazy := 4; ConfigTable[1].NiceLen := 8;
ConfigTable[1].MaxChain := 4; ConfigTable[1].Compress := CompressFast;
ConfigTable[2].GoodLen := 4; ConfigTable[2].MaxLazy := 5; ConfigTable[2].NiceLen := 16;
ConfigTable[2].MaxChain := 8; ConfigTable[2].Compress := CompressFast;
ConfigTable[3].GoodLen := 4; ConfigTable[3].MaxLazy := 6; ConfigTable[3].NiceLen := 32;
ConfigTable[3].MaxChain := 32; ConfigTable[3].Compress := CompressFast;
ConfigTable[4].GoodLen := 4; ConfigTable[4].MaxLazy := 4; ConfigTable[4].NiceLen := 16;
ConfigTable[4].MaxChain := 16; ConfigTable[4].Compress := CompressSlow;
ConfigTable[5].GoodLen := 8; ConfigTable[5].MaxLazy := 16; ConfigTable[5].NiceLen := 32;
ConfigTable[5].MaxChain := 32; ConfigTable[5].Compress := CompressSlow;
ConfigTable[6].GoodLen := 8; ConfigTable[6].MaxLazy := 16; ConfigTable[6].NiceLen := 128;
ConfigTable[6].MaxChain := 128; ConfigTable[6].Compress := CompressSlow;
ConfigTable[7].GoodLen := 8; ConfigTable[7].MaxLazy := 32; ConfigTable[7].NiceLen := 128;
ConfigTable[7].MaxChain := 256; ConfigTable[7].Compress := CompressSlow;
ConfigTable[8].GoodLen := 32; ConfigTable[8].MaxLazy := 128; ConfigTable[8].NiceLen := 258;
ConfigTable[8].MaxChain := 1024; ConfigTable[8].Compress := CompressSlow;
ConfigTable[9].GoodLen := 32; ConfigTable[9].MaxLazy := 128; ConfigTable[9].NiceLen := 258;
ConfigTable[9].MaxChain := 4096; ConfigTable[9].Compress := CompressSlow;
END ZlibDeflate.