summaryrefslogtreecommitdiff
path: root/packages/paszlib/src
diff options
context:
space:
mode:
authorpeter <peter@3ad0048d-3df7-0310-abae-a5850022a9f2>2007-10-25 19:51:44 +0000
committerpeter <peter@3ad0048d-3df7-0310-abae-a5850022a9f2>2007-10-25 19:51:44 +0000
commit4ee2c757cfaf81e9d03c790bcc03cbee898ea1a5 (patch)
tree357293d37a93736cbc8698bcdf249e198a583460 /packages/paszlib/src
parent7feb424486c3cfa4dd9d844e8b4980a71b3b05fb (diff)
downloadfpc-4ee2c757cfaf81e9d03c790bcc03cbee898ea1a5.tar.gz
* new directory structur
git-svn-id: http://svn.freepascal.org/svn/fpc/trunk@8933 3ad0048d-3df7-0310-abae-a5850022a9f2
Diffstat (limited to 'packages/paszlib/src')
-rw-r--r--packages/paszlib/src/adler.pas111
-rw-r--r--packages/paszlib/src/gzio.pas1205
-rw-r--r--packages/paszlib/src/infblock.pas950
-rw-r--r--packages/paszlib/src/infcodes.pas573
-rw-r--r--packages/paszlib/src/inffast.pas315
-rw-r--r--packages/paszlib/src/inftrees.pas780
-rw-r--r--packages/paszlib/src/infutil.pas222
-rw-r--r--packages/paszlib/src/paszlib.pas338
-rw-r--r--packages/paszlib/src/trees.pas2204
-rw-r--r--packages/paszlib/src/unzip.pas1559
-rw-r--r--packages/paszlib/src/zbase.pas484
-rw-r--r--packages/paszlib/src/zcompres.pas118
-rw-r--r--packages/paszlib/src/zconf.inc38
-rw-r--r--packages/paszlib/src/zdeflate.pas2117
-rw-r--r--packages/paszlib/src/zinflate.pas730
-rw-r--r--packages/paszlib/src/zip.pas792
-rw-r--r--packages/paszlib/src/zipper.pp1470
-rw-r--r--packages/paszlib/src/ziputils.pas304
-rw-r--r--packages/paszlib/src/zstream.pp440
-rw-r--r--packages/paszlib/src/zuncompr.pas89
20 files changed, 14839 insertions, 0 deletions
diff --git a/packages/paszlib/src/adler.pas b/packages/paszlib/src/adler.pas
new file mode 100644
index 0000000000..4644e6a72c
--- /dev/null
+++ b/packages/paszlib/src/adler.pas
@@ -0,0 +1,111 @@
+unit adler;
+
+{
+ adler32.c -- compute the Adler-32 checksum of a data stream
+ Copyright (C) 1995-1998 Mark Adler
+
+ Pascal tranlastion
+ Copyright (C) 1998 by Jacques Nomssi Nzali
+ For conditions of distribution and use, see copyright notice in readme.txt
+}
+
+interface
+
+{$I zconf.inc}
+
+function adler32(adler : cardinal; buf : Pbyte; len : cardinal) : cardinal;
+
+{ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+ return the updated checksum. If buf is NIL, this function returns
+ the required initial value for the checksum.
+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+ much faster. Usage example:
+
+ var
+ adler : cardinal;
+ begin
+ adler := adler32(0, nil, 0);
+
+ while (read_buffer(buffer, length) <> EOF) do
+ adler := adler32(adler, buffer, length);
+
+ if (adler <> original_adler) then
+ error();
+ end;
+}
+
+implementation
+
+const
+ BASE = cardinal(65521); { largest prime smaller than 65536 }
+ {NMAX = 5552; original code with unsigned 32 bit integer }
+ { NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 }
+ NMAX = 3854; { code with signed 32 bit integer }
+ { NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^31-1 }
+ { The penalty is the time loss in the extra MOD-calls. }
+
+
+{ ========================================================================= }
+
+function adler32(adler : cardinal; buf : Pbyte; len : cardinal) : cardinal;
+var
+ s1, s2 : cardinal;
+ k : integer;
+begin
+ s1 := adler and $ffff;
+ s2 := (adler shr 16) and $ffff;
+
+ if not Assigned(buf) then
+ begin
+ adler32 := cardinal(1);
+ exit;
+ end;
+
+ while (len > 0) do
+ begin
+ if len < NMAX then
+ k := len
+ else
+ k := NMAX;
+ Dec(len, k);
+ {
+ while (k >= 16) do
+ begin
+ DO16(buf);
+ Inc(buf, 16);
+ Dec(k, 16);
+ end;
+ if (k <> 0) then
+ repeat
+ Inc(s1, buf^);
+ Inc(puf);
+ Inc(s2, s1);
+ Dec(k);
+ until (k = 0);
+ }
+ while (k > 0) do
+ begin
+ Inc(s1, buf^);
+ Inc(s2, s1);
+ Inc(buf);
+ Dec(k);
+ end;
+ s1 := s1 mod BASE;
+ s2 := s2 mod BASE;
+ end;
+ adler32 := (s2 shl 16) or s1;
+end;
+
+{
+#define DO1(buf,i)
+ begin
+ Inc(s1, buf[i]);
+ Inc(s2, s1);
+ end;
+#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf) DO8(buf,0); DO8(buf,8);
+}
+end.
+
diff --git a/packages/paszlib/src/gzio.pas b/packages/paszlib/src/gzio.pas
new file mode 100644
index 0000000000..5985719803
--- /dev/null
+++ b/packages/paszlib/src/gzio.pas
@@ -0,0 +1,1205 @@
+unit gzio;
+
+{
+ Pascal unit based on gzio.c -- IO on .gz files
+ Copyright (C) 1995-1998 Jean-loup Gailly.
+
+ Define NO_DEFLATE to compile this file without the compression code
+
+ Pascal tranlastion based on code contributed by Francisco Javier Crespo
+ Copyright (C) 1998 by Jacques Nomssi Nzali
+ For conditions of distribution and use, see copyright notice in readme.txt
+}
+
+interface
+
+{$I zconf.inc}
+
+uses
+ {$ifdef UNIX}
+ baseunix,
+ {$else}
+ dos,
+ {$endif}
+ zbase, crc, zdeflate, zinflate;
+
+type gzFile = pointer;
+type z_off_t = longint;
+
+function gzopen (path:string; mode:string) : gzFile;
+function gzread (f:gzFile; buf:pointer; len:cardinal) : integer;
+function gzgetc (f:gzfile) : integer;
+function gzgets (f:gzfile; buf:Pchar; len:integer) : Pchar;
+
+{$ifndef NO_DEFLATE}
+function gzwrite (f:gzFile; buf:pointer; len:cardinal) : integer;
+function gzputc (f:gzfile; c:char) : integer;
+function gzputs (f:gzfile; s:Pchar) : integer;
+function gzflush (f:gzFile; flush:integer) : integer;
+ {$ifdef GZ_FORMAT_STRING}
+ function gzprintf (zfile : gzFile;
+ const format : string;
+ a : array of integer); { doesn't compile }
+ {$endif}
+{$endif}
+
+function gzseek (f:gzfile; offset:z_off_t; whence:integer) : z_off_t;
+function gztell (f:gzfile) : z_off_t;
+function gzclose (f:gzFile) : integer;
+function gzerror (f:gzFile; var errnum:smallint) : string;
+function gzsetparams (f:gzfile; level:integer; strategy:integer) : integer;
+function gzrewind (f:gzFile) : integer;
+function gzeof (f:gzfile) : boolean;
+
+const
+ SEEK_SET {: z_off_t} = 0; { seek from beginning of file }
+ SEEK_CUR {: z_off_t} = 1; { seek from current position }
+ SEEK_END {: z_off_t} = 2;
+
+implementation
+
+const
+ Z_EOF = -1; { same value as in STDIO.H }
+ Z_BUFSIZE = 16384;
+ { Z_PRINTF_BUFSIZE = 4096; }
+
+
+ gz_magic : array[0..1] of byte = ($1F, $8B); { gzip magic header }
+
+ { gzip flag byte }
+
+ ASCII_FLAG = $01; { bit 0 set: file probably ascii text }
+ HEAD_CRC = $02; { bit 1 set: header CRC present }
+ EXTRA_FIELD = $04; { bit 2 set: extra field present }
+ ORIG_NAME = $08; { bit 3 set: original file name present }
+ COMMENT = $10; { bit 4 set: file comment present }
+ RESERVED = $E0; { bits 5..7: reserved }
+
+type gz_stream = record
+ stream : z_stream;
+ z_err : integer; { error code for last stream operation }
+ z_eof : boolean; { set if end of input file }
+ gzfile : file; { .gz file }
+ inbuf : Pbyte; { input buffer }
+ outbuf : Pbyte; { output buffer }
+ crc : cardinal; { crc32 of uncompressed data }
+ msg, { error message - limit 79 chars }
+ path : string[79]; { path name for debugging only - limit 79 chars }
+ transparent : boolean; { true if input file is not a .gz file }
+ mode : char; { 'w' or 'r' }
+ startpos : longint; { start of compressed data in file (header skipped) }
+end;
+
+type gz_streamp = ^gz_stream;
+
+function destroy (var s:gz_streamp) : integer; forward;
+procedure check_header(s:gz_streamp); forward;
+
+
+{ GZOPEN ====================================================================
+
+ Opens a gzip (.gz) file for reading or writing. As Pascal does not use
+ file descriptors, the code has been changed to accept only path names.
+
+ The mode parameter defaults to BINARY read or write operations ('r' or 'w')
+ but can also include a compression level ('w9') or a strategy: Z_FILTERED
+ as in 'w6f' or Z_HUFFMAN_ONLY as in 'w1h'. (See the description of
+ deflateInit2 for more information about the strategy parameter.)
+
+ gzopen can be used to open a file which is not in gzip format; in this
+ case, gzread will directly read from the file without decompression.
+
+ gzopen returns nil if the file could not be opened (non-zero IOResult)
+ or if there was insufficient memory to allocate the (de)compression state
+ (zlib error is Z_MEM_ERROR).
+
+============================================================================}
+
+function gzopen (path:string; mode:string) : gzFile;
+
+var
+
+ i : cardinal;
+ err : integer;
+ level : integer; { compression level }
+ strategy : integer; { compression strategy }
+ s : gz_streamp;
+{$ifdef UNIX}
+ info: stat;
+{$else}
+ attr: word;
+{$endif}
+
+{$IFNDEF NO_DEFLATE}
+ gzheader : array [0..9] of byte;
+{$ENDIF}
+
+begin
+
+ if (path='') or (mode='') then begin
+ gzopen := nil;
+ exit;
+ end;
+
+ GetMem (s,sizeof(gz_stream));
+ if not Assigned (s) then begin
+ gzopen := nil;
+ exit;
+ end;
+
+ level := Z_DEFAULT_COMPRESSION;
+ strategy := Z_DEFAULT_STRATEGY;
+
+ s^.stream.next_in := nil;
+ s^.stream.next_out := nil;
+ s^.stream.avail_in := 0;
+ s^.stream.avail_out := 0;
+ s^.z_err := Z_OK;
+ s^.z_eof := false;
+ s^.inbuf := nil;
+ s^.outbuf := nil;
+ s^.crc := crc32(0, nil, 0);
+ s^.msg := '';
+ s^.transparent := false;
+
+ s^.path := path; { limit to 255 chars }
+
+ s^.mode := #0;
+ for i:=1 to Length(mode) do begin
+ case mode[i] of
+ 'r' : s^.mode := 'r';
+ 'w' : s^.mode := 'w';
+ '0'..'9' : level := Ord(mode[i])-Ord('0');
+ 'f' : strategy := Z_FILTERED;
+ 'h' : strategy := Z_HUFFMAN_ONLY;
+ end;
+ end;
+ if s^.mode=#0 then begin
+ destroy(s);
+ gzopen := nil;
+ exit;
+ end;
+
+ if (s^.mode='w') then begin
+{$IFDEF NO_DEFLATE}
+ err := Z_STREAM_ERROR;
+{$ELSE}
+ err := deflateInit2 (s^.stream, level, Z_DEFLATED, -MAX_WBITS,
+ DEF_MEM_LEVEL, strategy);
+ { windowBits is passed < 0 to suppress zlib header }
+
+ GetMem (s^.outbuf, Z_BUFSIZE);
+ s^.stream.next_out := s^.outbuf;
+{$ENDIF}
+ if (err <> Z_OK) or (s^.outbuf = nil) then begin
+ destroy(s);
+ gzopen := gzFile(nil);
+ exit;
+ end;
+ end
+
+ else begin
+ GetMem (s^.inbuf, Z_BUFSIZE);
+ s^.stream.next_in := s^.inbuf;
+
+ err := inflateInit2_ (s^.stream, -MAX_WBITS, ZLIB_VERSION, sizeof(z_stream));
+ { windowBits is passed < 0 to tell that there is no zlib header }
+
+ if (err <> Z_OK) or (s^.inbuf = nil) then begin
+ destroy(s);
+ gzopen := gzFile(nil);
+ exit;
+ end;
+ end;
+
+ s^.stream.avail_out := Z_BUFSIZE;
+
+ {$IFOPT I+} {$I-} {$define IOcheck} {$ENDIF}
+ Assign (s^.gzfile, path);
+ {$ifdef unix}
+ if (fpstat(path,info)<0) and (s^.mode='w') then
+ ReWrite (s^.gzfile,1)
+ else
+ Reset (s^.gzfile,1);
+ {$else}
+ GetFAttr(s^.gzfile, Attr);
+ if (DosError <> 0) and (s^.mode='w') then
+ ReWrite (s^.gzfile,1)
+ else
+ Reset (s^.gzfile,1);
+ {$endif}
+ {$IFDEF IOCheck} {$I+} {$ENDIF}
+ if (IOResult <> 0) then begin
+ destroy(s);
+ gzopen := gzFile(nil);
+ exit;
+ end;
+
+ if (s^.mode = 'w') then begin { Write a very simple .gz header }
+{$IFNDEF NO_DEFLATE}
+ gzheader [0] := gz_magic [0];
+ gzheader [1] := gz_magic [1];
+ gzheader [2] := Z_DEFLATED; { method }
+ gzheader [3] := 0; { flags }
+ gzheader [4] := 0; { time[0] }
+ gzheader [5] := 0; { time[1] }
+ gzheader [6] := 0; { time[2] }
+ gzheader [7] := 0; { time[3] }
+ gzheader [8] := 0; { xflags }
+ gzheader [9] := 0; { OS code = MS-DOS }
+ blockwrite (s^.gzfile, gzheader, 10);
+ s^.startpos := longint(10);
+{$ENDIF}
+ end
+ else begin
+ check_header(s); { skip the .gz header }
+ s^.startpos := FilePos(s^.gzfile) - s^.stream.avail_in;
+ end;
+
+ gzopen := gzFile(s);
+end;
+
+
+{ GZSETPARAMS ===============================================================
+
+ Update the compression level and strategy.
+
+============================================================================}
+
+function gzsetparams (f:gzfile; level:integer; strategy:integer) : integer;
+
+var
+
+ s : gz_streamp;
+ written: integer;
+
+begin
+
+ s := gz_streamp(f);
+
+ if (s = nil) or (s^.mode <> 'w') then begin
+ gzsetparams := Z_STREAM_ERROR;
+ exit;
+ end;
+
+ { Make room to allow flushing }
+ if (s^.stream.avail_out = 0) then begin
+ s^.stream.next_out := s^.outbuf;
+ blockwrite(s^.gzfile, s^.outbuf^, Z_BUFSIZE, written);
+ if (written <> Z_BUFSIZE) then s^.z_err := Z_ERRNO;
+ s^.stream.avail_out := Z_BUFSIZE;
+ end;
+
+ gzsetparams := deflateParams (s^.stream, level, strategy);
+end;
+
+
+{ GET_BYTE ==================================================================
+
+ Read a byte from a gz_stream. Updates next_in and avail_in.
+ Returns EOF for end of file.
+ IN assertion: the stream s has been sucessfully opened for reading.
+
+============================================================================}
+
+function get_byte (s:gz_streamp) : integer;
+
+begin
+ if s^.z_eof then begin
+ get_byte := Z_EOF;
+ exit;
+ end;
+
+ if s^.stream.avail_in=0 then begin
+ {$I-}
+ blockread (s^.gzfile, s^.inbuf^, Z_BUFSIZE, s^.stream.avail_in);
+ {$I+}
+ if s^.stream.avail_in=0 then begin
+ s^.z_eof := true;
+ if (IOResult <> 0) then s^.z_err := Z_ERRNO;
+ get_byte := Z_EOF;
+ exit;
+ end;
+ s^.stream.next_in := s^.inbuf;
+ end;
+
+ Dec(s^.stream.avail_in);
+ get_byte := s^.stream.next_in^;
+ Inc(s^.stream.next_in);
+end;
+
+
+{ GETLONG ===================================================================
+
+ Reads a Longint in LSB order from the given gz_stream.
+
+============================================================================}
+{
+function getLong (s:gz_streamp) : cardinal;
+var
+ x : array [0..3] of byte;
+ i : byte;
+ c : integer;
+ n1 : longint;
+ n2 : longint;
+begin
+
+ for i:=0 to 3 do begin
+ c := get_byte(s);
+ if (c = Z_EOF) then s^.z_err := Z_DATA_ERROR;
+ x[i] := (c and $FF)
+ end;
+ n1 := (ush(x[3] shl 8)) or x[2];
+ n2 := (ush(x[1] shl 8)) or x[0];
+ getlong := (n1 shl 16) or n2;
+end;
+}
+function getLong(s : gz_streamp) : cardinal;
+var
+ x : packed array [0..3] of byte;
+ c : integer;
+begin
+ { x := cardinal(get_byte(s)); - you can't do this with TP, no unsigned longint }
+{$ifdef ENDIAN_BIG}
+ x[3] := Byte(get_byte(s));
+ x[2] := Byte(get_byte(s));
+ x[1] := Byte(get_byte(s));
+ c := get_byte(s);
+ x[0] := Byte(c);
+{$else}
+ x[0] := Byte(get_byte(s));
+ x[1] := Byte(get_byte(s));
+ x[2] := Byte(get_byte(s));
+ c := get_byte(s);
+ x[3] := Byte(c);
+{$endif}
+ if (c = Z_EOF) then
+ s^.z_err := Z_DATA_ERROR;
+ GetLong := cardinal(x);
+end;
+
+
+{ CHECK_HEADER ==============================================================
+
+ Check the gzip header of a gz_stream opened for reading.
+ Set the stream mode to transparent if the gzip magic header is not present.
+ Set s^.err to Z_DATA_ERROR if the magic header is present but the rest of
+ the header is incorrect.
+
+ IN assertion: the stream s has already been created sucessfully;
+ s^.stream.avail_in is zero for the first time, but may be non-zero
+ for concatenated .gz files
+
+============================================================================}
+
+procedure check_header (s:gz_streamp);
+
+var
+
+ method : integer; { method byte }
+ flags : integer; { flags byte }
+ len : cardinal;
+ c : integer;
+
+begin
+
+ { Check the gzip magic header }
+ for len := 0 to 1 do begin
+ c := get_byte(s);
+ if (c <> gz_magic[len]) then begin
+ if (len <> 0) then begin
+ Inc(s^.stream.avail_in);
+ Dec(s^.stream.next_in);
+ end;
+ if (c <> Z_EOF) then begin
+ Inc(s^.stream.avail_in);
+ Dec(s^.stream.next_in);
+ s^.transparent := TRUE;
+ end;
+ if (s^.stream.avail_in <> 0) then s^.z_err := Z_OK
+ else s^.z_err := Z_STREAM_END;
+ exit;
+ end;
+ end;
+
+ method := get_byte(s);
+ flags := get_byte(s);
+ if (method <> Z_DEFLATED) or ((flags and RESERVED) <> 0) then begin
+ s^.z_err := Z_DATA_ERROR;
+ exit;
+ end;
+
+ for len := 0 to 5 do get_byte(s); { Discard time, xflags and OS code }
+
+ if ((flags and EXTRA_FIELD) <> 0) then begin { skip the extra field }
+ len := cardinal(get_byte(s));
+ len := len + (cardinal(get_byte(s)) shr 8);
+ { len is garbage if EOF but the loop below will quit anyway }
+ while (len <> 0) and (get_byte(s) <> Z_EOF) do Dec(len);
+ end;
+
+ if ((flags and ORIG_NAME) <> 0) then begin { skip the original file name }
+ repeat
+ c := get_byte(s);
+ until (c = 0) or (c = Z_EOF);
+ end;
+
+ if ((flags and COMMENT) <> 0) then begin { skip the .gz file comment }
+ repeat
+ c := get_byte(s);
+ until (c = 0) or (c = Z_EOF);
+ end;
+
+ if ((flags and HEAD_CRC) <> 0) then begin { skip the header crc }
+ get_byte(s);
+ get_byte(s);
+ end;
+
+ if (s^.z_eof = true) then
+ s^.z_err := Z_DATA_ERROR
+ else
+ s^.z_err := Z_OK;
+
+end;
+
+
+{ DESTROY ===================================================================
+
+ Cleanup then free the given gz_stream. Return a zlib error code.
+ Try freeing in the reverse order of allocations.
+
+============================================================================}
+
+function destroy (var s:gz_streamp) : integer;
+
+begin
+
+ destroy := Z_OK;
+
+ if not Assigned (s) then begin
+ destroy := Z_STREAM_ERROR;
+ exit;
+ end;
+
+ if (s^.stream.state <> nil) then begin
+ if (s^.mode = 'w') then begin
+{$IFDEF NO_DEFLATE}
+ destroy := Z_STREAM_ERROR;
+{$ELSE}
+ destroy := deflateEnd(s^.stream);
+{$ENDIF}
+ end
+ else if (s^.mode = 'r') then begin
+ destroy := inflateEnd(s^.stream);
+ end;
+ end;
+
+ if s^.path <> '' then begin
+ {$I-}
+ close(s^.gzfile);
+ {$I+}
+ if (IOResult <> 0) then destroy := Z_ERRNO;
+ end;
+
+ if (s^.z_err < 0) then destroy := s^.z_err;
+
+ if Assigned (s^.inbuf) then
+ FreeMem(s^.inbuf, Z_BUFSIZE);
+ if Assigned (s^.outbuf) then
+ FreeMem(s^.outbuf, Z_BUFSIZE);
+ FreeMem(s, sizeof(gz_stream));
+
+end;
+
+
+{ GZREAD ====================================================================
+
+ Reads the given number of uncompressed bytes from the compressed file.
+ If the input file was not in gzip format, gzread copies the given number
+ of bytes into the buffer.
+
+ gzread returns the number of uncompressed bytes actually read
+ (0 for end of file, -1 for error).
+
+============================================================================}
+
+function gzread (f:gzFile; buf:pointer; len:cardinal) : integer;
+
+var
+
+ s : gz_streamp;
+ start : Pbyte;
+ n : cardinal;
+ crclen : cardinal; { Buffer length to update CRC32 }
+ filecrc : cardinal; { CRC32 stored in GZIP'ed file }
+ filelen : cardinal; { Total lenght of uncompressed file }
+ bytes : integer; { bytes actually read in I/O blockread }
+ total_in : cardinal;
+ total_out : cardinal;
+{$ifndef pointer_arith}
+ next_out : Pbyte;
+{$endif}
+
+begin
+
+ s := gz_streamp(f);
+ start := Pbyte(buf); { starting point for crc computation }
+
+ if (s = nil) or (s^.mode <> 'r') then begin
+ gzread := Z_STREAM_ERROR;
+ exit;
+ end;
+
+ if (s^.z_err = Z_DATA_ERROR) or (s^.z_err = Z_ERRNO) then begin
+ gzread := -1;
+ exit;
+ end;
+
+ if (s^.z_err = Z_STREAM_END) then begin
+ gzread := 0; { EOF }
+ exit;
+ end;
+
+ s^.stream.next_out := Pbyte(buf);
+ s^.stream.avail_out := len;
+
+ while (s^.stream.avail_out <> 0) do begin
+
+ if (s^.transparent = true) then begin
+ { Copy first the lookahead bytes: }
+ n := s^.stream.avail_in;
+ if (n > s^.stream.avail_out) then n := s^.stream.avail_out;
+ if (n > 0) then begin
+ move(s^.stream.next_in^,s^.stream.next_out^,n);
+ inc (s^.stream.next_out, n);
+ inc (s^.stream.next_in, n);
+ dec (s^.stream.avail_out, n);
+ dec (s^.stream.avail_in, n);
+ end;
+ if (s^.stream.avail_out > 0) then begin
+ blockread (s^.gzfile, s^.stream.next_out^, s^.stream.avail_out, bytes);
+ dec (s^.stream.avail_out, cardinal(bytes));
+ end;
+ dec (len, s^.stream.avail_out);
+ inc (s^.stream.total_in, cardinal(len));
+ inc (s^.stream.total_out, cardinal(len));
+ gzread := integer(len);
+ exit;
+ end; { IF transparent }
+
+ if (s^.stream.avail_in = 0) and (s^.z_eof = false) then begin
+ {$I-}
+ blockread (s^.gzfile, s^.inbuf^, Z_BUFSIZE, s^.stream.avail_in);
+ {$I+}
+ if (s^.stream.avail_in = 0) then begin
+ s^.z_eof := true;
+ if (IOResult <> 0) then begin
+ s^.z_err := Z_ERRNO;
+ break;
+ end;
+ end;
+ s^.stream.next_in := s^.inbuf;
+ end;
+
+ s^.z_err := inflate(s^.stream, Z_NO_FLUSH);
+
+ if (s^.z_err = Z_STREAM_END) then begin
+ {$ifdef pointer_arith}
+ crclen := 0;
+ crclen:=s^.stream.next_out-start;
+ {$else}
+ next_out := s^.stream.next_out;
+ while (next_out <> start ) do begin
+ dec (next_out);
+ inc (crclen); { Hack because Pascal cannot substract pointers }
+ end;
+ {$endif}
+ { Check CRC and original size }
+ s^.crc := crc32(s^.crc, start, crclen);
+ start := s^.stream.next_out;
+
+ filecrc := getLong (s);
+ filelen := getLong (s);
+
+ if (s^.crc <> filecrc) or (s^.stream.total_out <> filelen)
+ then s^.z_err := Z_DATA_ERROR
+ else begin
+ { Check for concatenated .gz files: }
+ check_header(s);
+ if (s^.z_err = Z_OK) then begin
+ total_in := s^.stream.total_in;
+ total_out := s^.stream.total_out;
+
+ inflateReset (s^.stream);
+ s^.stream.total_in := total_in;
+ s^.stream.total_out := total_out;
+ s^.crc := crc32 (0, nil, 0);
+ end;
+ end; {IF-THEN-ELSE}
+ end;
+
+ if (s^.z_err <> Z_OK) or (s^.z_eof = true) then break;
+
+ end; {WHILE}
+
+{$ifdef pointer_arith}
+ crclen:=s^.stream.next_out-start;
+{$else}
+ crclen := 0;
+ next_out := s^.stream.next_out;
+ while (next_out <> start ) do begin
+ dec (next_out);
+ inc (crclen); { Hack because Pascal cannot substract pointers }
+ end;
+{$endif}
+ s^.crc := crc32 (s^.crc, start, crclen);
+ gzread := integer(len - s^.stream.avail_out);
+
+end;
+
+
+{ GZGETC ====================================================================
+
+ Reads one byte from the compressed file.
+ gzgetc returns this byte or -1 in case of end of file or error.
+
+============================================================================}
+
+function gzgetc (f:gzfile) : integer;
+
+var c:byte;
+
+begin
+
+ if (gzread (f,@c,1) = 1) then gzgetc := c else gzgetc := -1;
+
+end;
+
+
+{ GZGETS ====================================================================
+
+ Reads bytes from the compressed file until len-1 characters are read,
+ or a newline character is read and transferred to buf, or an end-of-file
+ condition is encountered. The string is then Null-terminated.
+
+ gzgets returns buf, or nil in case of error.
+ The current implementation is not optimized at all.
+
+============================================================================}
+
+function gzgets (f:gzfile; buf:Pchar; len:integer) : Pchar;
+
+var
+
+ b : Pchar; { start of buffer }
+ bytes : integer; { number of bytes read by gzread }
+ gzchar : char; { char read by gzread }
+
+begin
+
+ if (buf = nil) or (len <= 0) then begin
+ gzgets := nil;
+ exit;
+ end;
+
+ b := buf;
+ repeat
+ dec (len);
+ bytes := gzread (f, buf, 1);
+ gzchar := buf^;
+ inc (buf);
+ until (len = 0) or (bytes <> 1) or (gzchar = Chr(13));
+
+ buf^ := #0;
+ if (b = buf) and (len > 0) then gzgets := nil else gzgets := b;
+
+end;
+
+
+{$IFNDEF NO_DEFLATE}
+
+{ GZWRITE ===================================================================
+
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of uncompressed bytes actually written
+ (0 in case of error).
+
+============================================================================}
+
+function gzwrite (f:gzfile; buf:pointer; len:cardinal) : integer;
+
+var
+
+ s : gz_streamp;
+ written : integer;
+
+begin
+
+ s := gz_streamp(f);
+
+ if (s = nil) or (s^.mode <> 'w') then begin
+ gzwrite := Z_STREAM_ERROR;
+ exit;
+ end;
+
+ s^.stream.next_in := Pbyte(buf);
+ s^.stream.avail_in := len;
+
+ while (s^.stream.avail_in <> 0) do begin
+
+ if (s^.stream.avail_out = 0) then begin
+ s^.stream.next_out := s^.outbuf;
+ blockwrite (s^.gzfile, s^.outbuf^, Z_BUFSIZE, written);
+ if (written <> Z_BUFSIZE) then begin
+ s^.z_err := Z_ERRNO;
+ break;
+ end;
+ s^.stream.avail_out := Z_BUFSIZE;
+ end;
+
+ s^.z_err := deflate(s^.stream, Z_NO_FLUSH);
+ if (s^.z_err <> Z_OK) then break;
+
+ end; {WHILE}
+
+ s^.crc := crc32(s^.crc, buf, len);
+ gzwrite := integer(len - s^.stream.avail_in);
+
+end;
+
+
+{ ===========================================================================
+ Converts, formats, and writes the args to the compressed file under
+ control of the format string, as in fprintf. gzprintf returns the number of
+ uncompressed bytes actually written (0 in case of error).
+}
+
+{$IFDEF GZ_FORMAT_STRING}
+function gzprintf (zfile : gzFile;
+ const format : string;
+ a : array of integer) : integer;
+var
+ buf : array[0..Z_PRINTF_BUFSIZE-1] of char;
+ len : integer;
+begin
+{$ifdef HAS_snprintf}
+ snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+{$else}
+ sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+{$endif}
+ len := strlen(buf); { old sprintf doesn't return the nb of bytes written }
+ if (len <= 0) return 0;
+
+ gzprintf := gzwrite(file, buf, len);
+end;
+{$ENDIF}
+
+
+{ GZPUTC ====================================================================
+
+ Writes c, converted to an unsigned char, into the compressed file.
+ gzputc returns the value that was written, or -1 in case of error.
+
+============================================================================}
+
+function gzputc (f:gzfile; c:char) : integer;
+begin
+ if (gzwrite (f,@c,1) = 1) then
+ {$IFDEF FPC}
+ gzputc := integer(ord(c))
+ {$ELSE}
+ gzputc := integer(c)
+ {$ENDIF}
+ else
+ gzputc := -1;
+end;
+
+
+{ GZPUTS ====================================================================
+
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+ gzputs returns the number of characters written, or -1 in case of error.
+
+============================================================================}
+
+function gzputs (f:gzfile; s:Pchar) : integer;
+begin
+ gzputs := gzwrite (f, pointer(s), strlen(s));
+end;
+
+
+{ DO_FLUSH ==================================================================
+
+ Flushes all pending output into the compressed file.
+ The parameter flush is as in the zdeflate() function.
+
+============================================================================}
+
+function do_flush (f:gzfile; flush:integer) : integer;
+var
+ len : cardinal;
+ done : boolean;
+ s : gz_streamp;
+ written : integer;
+begin
+ done := false;
+ s := gz_streamp(f);
+
+ if (s = nil) or (s^.mode <> 'w') then begin
+ do_flush := Z_STREAM_ERROR;
+ exit;
+ end;
+
+ s^.stream.avail_in := 0; { should be zero already anyway }
+
+ while true do begin
+
+ len := Z_BUFSIZE - s^.stream.avail_out;
+
+ if (len <> 0) then begin
+ {$I-}
+ blockwrite(s^.gzfile, s^.outbuf^, len, written);
+ {$I+}
+ if (written <> len) then begin
+ s^.z_err := Z_ERRNO;
+ do_flush := Z_ERRNO;
+ exit;
+ end;
+ s^.stream.next_out := s^.outbuf;
+ s^.stream.avail_out := Z_BUFSIZE;
+ end;
+
+ if (done = true) then break;
+ s^.z_err := deflate(s^.stream, flush);
+
+ { Ignore the second of two consecutive flushes: }
+ if (len = 0) and (s^.z_err = Z_BUF_ERROR) then s^.z_err := Z_OK;
+
+ { deflate has finished flushing only when it hasn't used up
+ all the available space in the output buffer: }
+
+ done := (s^.stream.avail_out <> 0) or (s^.z_err = Z_STREAM_END);
+ if (s^.z_err <> Z_OK) and (s^.z_err <> Z_STREAM_END) then break;
+
+ end; {WHILE}
+
+ if (s^.z_err = Z_STREAM_END) then do_flush:=Z_OK else do_flush:=s^.z_err;
+end;
+
+{ GZFLUSH ===================================================================
+
+ Flushes all pending output into the compressed file.
+ The parameter flush is as in the zdeflate() function.
+
+ The return value is the zlib error number (see function gzerror below).
+ gzflush returns Z_OK if the flush parameter is Z_FINISH and all output
+ could be flushed.
+
+ gzflush should be called only when strictly necessary because it can
+ degrade compression.
+
+============================================================================}
+
+function gzflush (f:gzfile; flush:integer) : integer;
+var
+ err : integer;
+ s : gz_streamp;
+begin
+ s := gz_streamp(f);
+ err := do_flush (f, flush);
+
+ if (err <> 0) then begin
+ gzflush := err;
+ exit;
+ end;
+
+ if (s^.z_err = Z_STREAM_END) then gzflush := Z_OK else gzflush := s^.z_err;
+end;
+
+{$ENDIF} (* NO DEFLATE *)
+
+
+{ GZREWIND ==================================================================
+
+ Rewinds input file.
+
+============================================================================}
+
+function gzrewind (f:gzFile) : integer;
+var
+ s:gz_streamp;
+begin
+ s := gz_streamp(f);
+
+ if (s = nil) or (s^.mode <> 'r') then begin
+ gzrewind := -1;
+ exit;
+ end;
+
+ s^.z_err := Z_OK;
+ s^.z_eof := false;
+ s^.stream.avail_in := 0;
+ s^.stream.next_in := s^.inbuf;
+
+ if (s^.startpos = 0) then begin { not a compressed file }
+ {$I-}
+ seek (s^.gzfile, 0);
+ {$I+}
+ gzrewind := 0;
+ exit;
+ end;
+
+ inflateReset(s^.stream);
+ {$I-}
+ seek (s^.gzfile, s^.startpos);
+ {$I+}
+ gzrewind := integer(IOResult);
+ exit;
+end;
+
+
+{ GZSEEK ====================================================================
+
+ Sets the starting position for the next gzread or gzwrite on the given
+ compressed file. The offset represents a number of bytes from the beginning
+ of the uncompressed stream.
+
+ gzseek returns the resulting offset, or -1 in case of error.
+ SEEK_END is not implemented, returns error.
+ In this version of the library, gzseek can be extremely slow.
+
+============================================================================}
+
+function gzseek (f:gzfile; offset:z_off_t; whence:integer) : z_off_t;
+var
+ s : gz_streamp;
+ size : cardinal;
+begin
+ s := gz_streamp(f);
+
+ if (s = nil) or (whence = SEEK_END) or (s^.z_err = Z_ERRNO)
+ or (s^.z_err = Z_DATA_ERROR) then begin
+ gzseek := z_off_t(-1);
+ exit;
+ end;
+
+ if (s^.mode = 'w') then begin
+{$IFDEF NO_DEFLATE}
+ gzseek := z_off_t(-1);
+ exit;
+{$ELSE}
+ if (whence = SEEK_SET) then dec(offset, s^.stream.total_out);
+ if (offset < 0) then begin;
+ gzseek := z_off_t(-1);
+ exit;
+ end;
+
+ { At this point, offset is the number of zero bytes to write. }
+ if s^.inbuf=nil then begin
+ getmem(s^.inbuf,Z_BUFSIZE);
+ fillchar(s^.inbuf^,Z_BUFSIZE,0);
+ end;
+
+ while (offset > 0) do begin
+ size := Z_BUFSIZE;
+ if (offset < Z_BUFSIZE) then size := cardinal(offset);
+
+ size := gzwrite(f, s^.inbuf, size);
+ if (size = 0) then begin
+ gzseek := z_off_t(-1);
+ exit;
+ end;
+
+ dec (offset,size);
+ end;
+
+ gzseek := z_off_t(s^.stream.total_in);
+ exit;
+{$ENDIF}
+ end;
+ { Rest of function is for reading only }
+
+ { compute absolute position }
+ if (whence = SEEK_CUR) then inc (offset, s^.stream.total_out);
+ if (offset < 0) then begin
+ gzseek := z_off_t(-1);
+ exit;
+ end;
+
+ if (s^.transparent = true) then begin
+ s^.stream.avail_in := 0;
+ s^.stream.next_in := s^.inbuf;
+ {$I-}
+ seek (s^.gzfile, offset);
+ {$I+}
+ if (IOResult <> 0) then begin
+ gzseek := z_off_t(-1);
+ exit;
+ end;
+
+ s^.stream.total_in := cardinal(offset);
+ s^.stream.total_out := cardinal(offset);
+ gzseek := z_off_t(offset);
+ exit;
+ end;
+
+ { For a negative seek, rewind and use positive seek }
+ if (cardinal(offset) >= s^.stream.total_out)
+ then dec (offset, s^.stream.total_out)
+ else if (gzrewind(f) <> 0) then begin
+ gzseek := z_off_t(-1);
+ exit;
+ end;
+ { offset is now the number of bytes to skip. }
+
+ if (offset <> 0) and (s^.outbuf = nil)
+ then GetMem (s^.outbuf, Z_BUFSIZE);
+
+ while (offset > 0) do begin
+ size := Z_BUFSIZE;
+ if (offset < Z_BUFSIZE) then size := integer(offset);
+
+ size := gzread (f, s^.outbuf, size);
+ if (size <= 0) then begin
+ gzseek := z_off_t(-1);
+ exit;
+ end;
+ dec(offset, size);
+ end;
+
+ gzseek := z_off_t(s^.stream.total_out);
+end;
+
+
+{ GZTELL ====================================================================
+
+ Returns the starting position for the next gzread or gzwrite on the
+ given compressed file. This position represents a number of bytes in the
+ uncompressed data stream.
+
+============================================================================}
+
+function gztell (f:gzfile) : z_off_t;
+begin
+ gztell := gzseek (f, 0, SEEK_CUR);
+end;
+
+
+{ GZEOF =====================================================================
+
+ Returns TRUE when EOF has previously been detected reading the given
+ input stream, otherwise FALSE.
+
+============================================================================}
+
+function gzeof (f:gzfile) : boolean;
+var
+ s:gz_streamp;
+begin
+ s := gz_streamp(f);
+
+ if (s=nil) or (s^.mode<>'r') then
+ gzeof := false
+ else
+ gzeof := s^.z_eof;
+end;
+
+
+{ PUTLONG ===================================================================
+
+ Outputs a Longint in LSB order to the given file
+
+============================================================================}
+
+procedure putLong (var f:file; x:cardinal);
+var
+ n : integer;
+ c : byte;
+begin
+ for n:=0 to 3 do begin
+ c := x and $FF;
+ blockwrite (f, c, 1);
+ x := x shr 8;
+ end;
+end;
+
+
+{ GZCLOSE ===================================================================
+
+ Flushes all pending output if necessary, closes the compressed file
+ and deallocates all the (de)compression state.
+
+ The return value is the zlib error number (see function gzerror below).
+
+============================================================================}
+
+function gzclose (f:gzFile) : integer;
+var
+ err : integer;
+ s : gz_streamp;
+begin
+ s := gz_streamp(f);
+ if (s = nil) then begin
+ gzclose := Z_STREAM_ERROR;
+ exit;
+ end;
+
+ if (s^.mode = 'w') then begin
+{$IFDEF NO_DEFLATE}
+ gzclose := Z_STREAM_ERROR;
+ exit;
+{$ELSE}
+ err := do_flush (f, Z_FINISH);
+ if (err <> Z_OK) then begin
+ gzclose := destroy (gz_streamp(f));
+ exit;
+ end;
+
+ putLong (s^.gzfile, s^.crc);
+ putLong (s^.gzfile, s^.stream.total_in);
+{$ENDIF}
+ end;
+
+ gzclose := destroy (gz_streamp(f));
+end;
+
+
+{ GZERROR ===================================================================
+
+ Returns the error message for the last error which occured on the
+ given compressed file. errnum is set to zlib error number. If an
+ error occured in the file system and not in the compression library,
+ errnum is set to Z_ERRNO and the application may consult errno
+ to get the exact error code.
+
+============================================================================}
+
+function gzerror (f:gzfile; var errnum:smallint) : string;
+var
+ m : string;
+ s : gz_streamp;
+begin
+ s := gz_streamp(f);
+ if (s = nil) then begin
+ errnum := Z_STREAM_ERROR;
+ gzerror := zError(Z_STREAM_ERROR);
+ end;
+
+ errnum := s^.z_err;
+ if (errnum = Z_OK) then begin
+ gzerror := zError(Z_OK);
+ exit;
+ end;
+
+ m := s^.stream.msg;
+ if (errnum = Z_ERRNO) then m := '';
+ if (m = '') then m := zError(s^.z_err);
+
+ s^.msg := s^.path+': '+m;
+ gzerror := s^.msg;
+end;
+
+end. \ No newline at end of file
diff --git a/packages/paszlib/src/infblock.pas b/packages/paszlib/src/infblock.pas
new file mode 100644
index 0000000000..274e9ebe7c
--- /dev/null
+++ b/packages/paszlib/src/infblock.pas
@@ -0,0 +1,950 @@
+unit infblock;
+
+{$goto on}
+
+{ infblock.h and
+ infblock.c -- interpret and process block types to last block
+ Copyright (C) 1995-1998 Mark Adler
+
+ Pascal tranlastion
+ Copyright (C) 1998 by Jacques Nomssi Nzali
+ For conditions of distribution and use, see copyright notice in readme.txt
+}
+
+interface
+
+{$I zconf.inc}
+
+uses
+ zbase;
+
+function inflate_blocks_new(var z : z_stream;
+ c : check_func; { check function }
+ w : cardinal { window size }
+ ) : pInflate_blocks_state;
+
+function inflate_blocks (var s : inflate_blocks_state;
+ var z : z_stream;
+ r : integer { initial return code }
+ ) : integer;
+
+procedure inflate_blocks_reset (var s : inflate_blocks_state;
+ var z : z_stream;
+ c : Pcardinal); { check value on output }
+
+
+function inflate_blocks_free(s : pInflate_blocks_state;
+ var z : z_stream) : integer;
+
+procedure inflate_set_dictionary(var s : inflate_blocks_state;
+ const d : array of byte; { dictionary }
+ n : cardinal); { dictionary length }
+
+function inflate_blocks_sync_point(var s : inflate_blocks_state) : integer;
+
+implementation
+
+uses
+ infcodes, inftrees, infutil;
+
+{ Tables for deflate from PKZIP's appnote.txt. }
+Const
+ border : array [0..18] of word { Order of the bit length code lengths }
+ = (16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15);
+
+{ Notes beyond the 1.93a appnote.txt:
+
+ 1. Distance pointers never point before the beginning of the output
+ stream.
+ 2. Distance pointers can point back across blocks, up to 32k away.
+ 3. There is an implied maximum of 7 bits for the bit length table and
+ 15 bits for the actual data.
+ 4. If only one code exists, then it is encoded using one bit. (Zero
+ would be more efficient, but perhaps a little confusing.) If two
+ codes exist, they are coded using one bit each (0 and 1).
+ 5. There is no way of sending zero distance codes--a dummy must be
+ sent if there are none. (History: a pre 2.0 version of PKZIP would
+ store blocks with no distance codes, but this was discovered to be
+ too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
+ zero distance codes, which is sent as one code of zero bits in
+ length.
+ 6. There are up to 286 literal/length codes. Code 256 represents the
+ end-of-block. Note however that the static length tree defines
+ 288 codes just to fill out the Huffman codes. Codes 286 and 287
+ cannot be used though, since there is no length base or extra bits
+ defined for them. Similarily, there are up to 30 distance codes.
+ However, static trees define 32 codes (all 5 bits) to fill out the
+ Huffman codes, but the last two had better not show up in the data.
+ 7. Unzip can check dynamic Huffman blocks for complete code sets.
+ The exception is that a single code would not be complete (see #4).
+ 8. The five bits following the block type is really the number of
+ literal codes sent minus 257.
+ 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+ (1+6+6). Therefore, to output three times the length, you output
+ three codes (1+1+1), whereas to output four times the same length,
+ you only need two codes (1+3). Hmm.
+ 10. In the tree reconstruction algorithm, Code = Code + Increment
+ only if BitLength(i) is not zero. (Pretty obvious.)
+ 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
+ 12. Note: length code 284 can represent 227-258, but length code 285
+ really is 258. The last length deserves its own, short code
+ since it gets used a lot in very redundant files. The length
+ 258 is special since 258 - 3 (the min match length) is 255.
+ 13. The literal/length and distance code bit lengths are read as a
+ single stream of lengths. It is possible (and advantageous) for
+ a repeat code (16, 17, or 18) to go across the boundary between
+ the two sets of lengths. }
+
+
+procedure inflate_blocks_reset (var s : inflate_blocks_state;
+ var z : z_stream;
+ c : Pcardinal); { check value on output }
+begin
+ if (c <> nil) then
+ c^ := s.check;
+ if (s.mode = BTREE) or (s.mode = DTREE) then
+ freemem(s.sub.trees.blens);
+ if (s.mode = CODES) then
+ inflate_codes_free(s.sub.decode.codes, z);
+
+ s.mode := ZTYPE;
+ s.bitk := 0;
+ s.bitb := 0;
+
+ s.write := s.window;
+ s.read := s.window;
+ if Assigned(s.checkfn) then
+ begin
+ s.check := s.checkfn(cardinal(0), nil, 0);
+ z.adler := s.check;
+ end;
+ {$IFDEF ZLIB_DEBUG}
+ Tracev('inflate: blocks reset');
+ {$ENDIF}
+end;
+
+
+function inflate_blocks_new(var z : z_stream;
+ c : check_func; { check function }
+ w : cardinal { window size }
+ ) : pInflate_blocks_state;
+var
+ s : pInflate_blocks_state;
+begin
+ new(s);
+ if (s = nil) then
+ begin
+ inflate_blocks_new := s;
+ exit;
+ end;
+ getmem(s^.hufts,sizeof(inflate_huft)*MANY);
+
+ if (s^.hufts = nil) then
+ begin
+ dispose(s);
+ inflate_blocks_new := nil;
+ exit;
+ end;
+
+ getmem(s^.window,w);
+ if (s^.window = nil) then
+ begin
+ freemem(s^.hufts);
+ dispose(s);
+ inflate_blocks_new := nil;
+ exit;
+ end;
+ s^.zend := s^.window;
+ Inc(s^.zend, w);
+ s^.checkfn := c;
+ s^.mode := ZTYPE;
+ {$IFDEF ZLIB_DEBUG}
+ Tracev('inflate: blocks allocated');
+ {$ENDIF}
+ inflate_blocks_reset(s^, z, nil);
+ inflate_blocks_new := s;
+end;
+
+
+function inflate_blocks (var s : inflate_blocks_state;
+ var z : z_stream;
+ r : integer) : integer; { initial return code }
+label
+ start_btree, start_dtree,
+ start_blkdone, start_dry,
+ start_codes;
+
+var
+ t : cardinal; { temporary storage }
+ b : cardinal; { bit buffer }
+ k : cardinal; { bits in bit buffer }
+ p : Pbyte; { input data pointer }
+ n : cardinal; { bytes available there }
+ q : Pbyte; { output window write pointer }
+ m : cardinal; { bytes to end of window or read pointer }
+{ fixed code blocks }
+var
+ bl, bd : cardinal;
+ tl, td : pInflate_huft;
+var
+ h : pInflate_huft;
+ i, j, c : cardinal;
+var
+ cs : pInflate_codes_state;
+begin
+ { copy input/output information to locals }
+ p := z.next_in;
+ n := z.avail_in;
+ b := s.bitb;
+ k := s.bitk;
+ q := s.write;
+ if ptruint(q) < ptruint(s.read) then
+ m := cardinal(ptruint(s.read)-ptruint(q)-1)
+ else
+ m := cardinal(ptruint(s.zend)-ptruint(q));
+
+{ decompress an inflated block }
+
+
+ { process input based on current state }
+ while True do
+ Case s.mode of
+ ZTYPE:
+ begin
+ {NEEDBITS(3);}
+ while (k < 3) do
+ begin
+ {NEEDBYTE;}
+ if (n <> 0) then
+ r :=Z_OK
+ else
+ begin
+ {UPDATE}
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p)-ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_blocks := inflate_flush(s,z,r);
+ exit;
+ end;
+ dec(n);
+ b := b or (cardinal(p^) shl k);
+ Inc(p);
+ Inc(k, 8);
+ end;
+
+ t := cardinal(b) and 7;
+ s.last := boolean(t and 1);
+ case (t shr 1) of
+ 0: { stored }
+ begin
+ {$IFDEF ZLIB_DEBUG}
+ if s.last then
+ Tracev('inflate: stored block (last)')
+ else
+ Tracev('inflate: stored block');
+ {$ENDIF}
+ {DUMPBITS(3);}
+ b := b shr 3;
+ dec(k, 3);
+
+ t := k and 7; { go to byte boundary }
+ {DUMPBITS(t);}
+ b := b shr t;
+ dec(k, t);
+
+ s.mode := LENS; { get length of stored block }
+ end;
+ 1: { fixed }
+ begin
+ begin
+ {$IFDEF ZLIB_DEBUG}
+ if s.last then
+ Tracev('inflate: fixed codes blocks (last)')
+ else
+ Tracev('inflate: fixed codes blocks');
+ {$ENDIF}
+ inflate_trees_fixed(bl, bd, tl, td, z);
+ s.sub.decode.codes := inflate_codes_new(bl, bd, tl, td, z);
+ if (s.sub.decode.codes = nil) then
+ begin
+ r := Z_MEM_ERROR;
+ { update pointers and return }
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p) - ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_blocks := inflate_flush(s,z,r);
+ exit;
+ end;
+ end;
+ {DUMPBITS(3);}
+ b := b shr 3;
+ dec(k, 3);
+
+ s.mode := CODES;
+ end;
+ 2: { dynamic }
+ begin
+ {$IFDEF ZLIB_DEBUG}
+ if s.last then
+ Tracev('inflate: dynamic codes block (last)')
+ else
+ Tracev('inflate: dynamic codes block');
+ {$ENDIF}
+ {DUMPBITS(3);}
+ b := b shr 3;
+ dec(k, 3);
+
+ s.mode := TABLE;
+ end;
+ 3:
+ begin { illegal }
+ {DUMPBITS(3);}
+ b := b shr 3;
+ dec(k, 3);
+
+ s.mode := BLKBAD;
+ z.msg := 'invalid block type';
+ r := Z_DATA_ERROR;
+ { update pointers and return }
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p) - ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_blocks := inflate_flush(s,z,r);
+ exit;
+ end;
+ end;
+ end;
+ LENS:
+ begin
+ {NEEDBITS(32);}
+ while (k < 32) do
+ begin
+ {NEEDBYTE;}
+ if (n <> 0) then
+ r :=Z_OK
+ else
+ begin
+ {UPDATE}
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p)-ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_blocks := inflate_flush(s,z,r);
+ exit;
+ end;
+ dec(n);
+ b := b or (cardinal(p^) shl k);
+ Inc(p);
+ Inc(k, 8);
+ end;
+
+ if (((not b) shr 16) and $ffff) <> (b and $ffff) then
+ begin
+ s.mode := BLKBAD;
+ z.msg := 'invalid stored block lengths';
+ r := Z_DATA_ERROR;
+ { update pointers and return }
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p) - ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_blocks := inflate_flush(s,z,r);
+ exit;
+ end;
+ s.sub.left := cardinal(b) and $ffff;
+ k := 0;
+ b := 0; { dump bits }
+ {$IFDEF ZLIB_DEBUG}
+ Tracev('inflate: stored length '+IntToStr(s.sub.left));
+ {$ENDIF}
+ if s.sub.left <> 0 then
+ s.mode := STORED
+ else
+ if s.last then
+ s.mode := DRY
+ else
+ s.mode := ZTYPE;
+ end;
+ STORED:
+ begin
+ if (n = 0) then
+ begin
+ { update pointers and return }
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p) - ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_blocks := inflate_flush(s,z,r);
+ exit;
+ end;
+ {NEEDOUT}
+ if (m = 0) then
+ begin
+ {WRAP}
+ if (q = s.zend) and (s.read <> s.window) then
+ begin
+ q := s.window;
+ if ptruint(q) < ptruint(s.read) then
+ m := cardinal(ptruint(s.read)-ptruint(q)-1)
+ else
+ m := cardinal(ptruint(s.zend)-ptruint(q));
+ end;
+
+ if (m = 0) then
+ begin
+ {FLUSH}
+ s.write := q;
+ r := inflate_flush(s,z,r);
+ q := s.write;
+ if ptruint(q) < ptruint(s.read) then
+ m := cardinal(ptruint(s.read)-ptruint(q)-1)
+ else
+ m := cardinal(ptruint(s.zend)-ptruint(q));
+
+ {WRAP}
+ if (q = s.zend) and (s.read <> s.window) then
+ begin
+ q := s.window;
+ if ptruint(q) < ptruint(s.read) then
+ m := cardinal(ptruint(s.read)-ptruint(q)-1)
+ else
+ m := cardinal(ptruint(s.zend)-ptruint(q));
+ end;
+
+ if (m = 0) then
+ begin
+ {UPDATE}
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p)-ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_blocks := inflate_flush(s,z,r);
+ exit;
+ end;
+ end;
+ end;
+ r := Z_OK;
+
+ t := s.sub.left;
+ if (t > n) then
+ t := n;
+ if (t > m) then
+ t := m;
+ move(p^,q^,t);
+ inc(p, t); dec(n, t);
+ inc(q, t); dec(m, t);
+ dec(s.sub.left, t);
+ if (s.sub.left = 0) then
+ begin
+ {$IFDEF ZLIB_DEBUG}
+ if (ptruint(q) >= ptruint(s.read)) then
+ Tracev('inflate: stored end '+
+ IntToStr(z.total_out + ptruint(q) - ptruint(s.read)) + ' total out')
+ else
+ Tracev('inflate: stored end '+
+ IntToStr(z.total_out + ptruint(s.zend) - ptruint(s.read) +
+ ptruint(q) - ptruint(s.window)) + ' total out');
+ {$ENDIF}
+ if s.last then
+ s.mode := DRY
+ else
+ s.mode := ZTYPE;
+ end;
+ end;
+ TABLE:
+ begin
+ {NEEDBITS(14);}
+ while (k < 14) do
+ begin
+ {NEEDBYTE;}
+ if (n <> 0) then
+ r :=Z_OK
+ else
+ begin
+ {UPDATE}
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p)-ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_blocks := inflate_flush(s,z,r);
+ exit;
+ end;
+ dec(n);
+ b := b or (cardinal(p^) shl k);
+ Inc(p);
+ Inc(k, 8);
+ end;
+
+ t := cardinal(b) and $3fff;
+ s.sub.trees.table := t;
+ {$ifndef PKZIP_BUG_WORKAROUND}
+ if ((t and $1f) > 29) or (((t shr 5) and $1f) > 29) then
+ begin
+ s.mode := BLKBAD;
+ z.msg := 'too many length or distance symbols';
+ r := Z_DATA_ERROR;
+ { update pointers and return }
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p) - ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_blocks := inflate_flush(s,z,r);
+ exit;
+ end;
+ {$endif}
+ t := 258 + (t and $1f) + ((t shr 5) and $1f);
+ getmem(s.sub.trees.blens,t*sizeof(cardinal));
+ if (s.sub.trees.blens = nil) then
+ begin
+ r := Z_MEM_ERROR;
+ { update pointers and return }
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p) - ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_blocks := inflate_flush(s,z,r);
+ exit;
+ end;
+ {DUMPBITS(14);}
+ b := b shr 14;
+ dec(k, 14);
+
+ s.sub.trees.index := 0;
+ {$IFDEF ZLIB_DEBUG}
+ Tracev('inflate: table sizes ok');
+ {$ENDIF}
+ s.mode := BTREE;
+ { fall trough case is handled by the while }
+ { try GOTO for speed - Nomssi }
+ goto start_btree;
+ end;
+ BTREE:
+ begin
+ start_btree:
+ while (s.sub.trees.index < 4 + (s.sub.trees.table shr 10)) do
+ begin
+ {NEEDBITS(3);}
+ while (k < 3) do
+ begin
+ {NEEDBYTE;}
+ if (n <> 0) then
+ r :=Z_OK
+ else
+ begin
+ {UPDATE}
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p)-ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_blocks := inflate_flush(s,z,r);
+ exit;
+ end;
+ dec(n);
+ b := b or (cardinal(p^) shl k);
+ Inc(p);
+ Inc(k, 8);
+ end;
+
+ s.sub.trees.blens^[border[s.sub.trees.index]] := cardinal(b) and 7;
+ Inc(s.sub.trees.index);
+ {DUMPBITS(3);}
+ b := b shr 3;
+ dec(k, 3);
+ end;
+ while (s.sub.trees.index < 19) do
+ begin
+ s.sub.trees.blens^[border[s.sub.trees.index]] := 0;
+ Inc(s.sub.trees.index);
+ end;
+ s.sub.trees.bb := 7;
+ t := inflate_trees_bits(s.sub.trees.blens^, s.sub.trees.bb,
+ s.sub.trees.tb, s.hufts^, z);
+ if (t <> Z_OK) then
+ begin
+ freemem(s.sub.trees.blens);
+ r := t;
+ if (r = Z_DATA_ERROR) then
+ s.mode := BLKBAD;
+ { update pointers and return }
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p) - ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_blocks := inflate_flush(s,z,r);
+ exit;
+ end;
+ s.sub.trees.index := 0;
+ {$IFDEF ZLIB_DEBUG}
+ Tracev('inflate: bits tree ok');
+ {$ENDIF}
+ s.mode := DTREE;
+ { fall through again }
+ goto start_dtree;
+ end;
+ DTREE:
+ begin
+ start_dtree:
+ while TRUE do
+ begin
+ t := s.sub.trees.table;
+ if not (s.sub.trees.index < 258 +
+ (t and $1f) + ((t shr 5) and $1f)) then
+ break;
+ t := s.sub.trees.bb;
+ {NEEDBITS(t);}
+ while (k < t) do
+ begin
+ {NEEDBYTE;}
+ if (n <> 0) then
+ r :=Z_OK
+ else
+ begin
+ {UPDATE}
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p)-ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_blocks := inflate_flush(s,z,r);
+ exit;
+ end;
+ dec(n);
+ b := b or (cardinal(p^) shl k);
+ Inc(p);
+ Inc(k, 8);
+ end;
+
+ h := s.sub.trees.tb;
+ Inc(h, cardinal(b) and inflate_mask[t]);
+ t := h^.Bits;
+ c := h^.Base;
+
+ if (c < 16) then
+ begin
+ {DUMPBITS(t);}
+ b := b shr t;
+ dec(k, t);
+
+ s.sub.trees.blens^[s.sub.trees.index] := c;
+ Inc(s.sub.trees.index);
+ end
+ else { c = 16..18 }
+ begin
+ if c = 18 then
+ begin
+ i := 7;
+ j := 11;
+ end
+ else
+ begin
+ i := c - 14;
+ j := 3;
+ end;
+ {NEEDBITS(t + i);}
+ while (k < t + i) do
+ begin
+ {NEEDBYTE;}
+ if (n <> 0) then
+ r :=Z_OK
+ else
+ begin
+ {UPDATE}
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p)-ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_blocks := inflate_flush(s,z,r);
+ exit;
+ end;
+ dec(n);
+ b := b or (cardinal(p^) shl k);
+ Inc(p);
+ Inc(k, 8);
+ end;
+
+ {DUMPBITS(t);}
+ b := b shr t;
+ dec(k, t);
+
+ Inc(j, cardinal(b) and inflate_mask[i]);
+ {DUMPBITS(i);}
+ b := b shr i;
+ dec(k, i);
+
+ i := s.sub.trees.index;
+ t := s.sub.trees.table;
+ if (i + j > 258 + (t and $1f) + ((t shr 5) and $1f)) or
+ ((c = 16) and (i < 1)) then
+ begin
+ freemem(s.sub.trees.blens);
+ s.mode := BLKBAD;
+ z.msg := 'invalid bit length repeat';
+ r := Z_DATA_ERROR;
+ { update pointers and return }
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p) - ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_blocks := inflate_flush(s,z,r);
+ exit;
+ end;
+ if c = 16 then
+ c := s.sub.trees.blens^[i - 1]
+ else
+ c := 0;
+ repeat
+ s.sub.trees.blens^[i] := c;
+ Inc(i);
+ dec(j);
+ until (j=0);
+ s.sub.trees.index := i;
+ end;
+ end; { while }
+ s.sub.trees.tb := nil;
+ begin
+ bl := 9; { must be <= 9 for lookahead assumptions }
+ bd := 6; { must be <= 9 for lookahead assumptions }
+ t := s.sub.trees.table;
+ t := inflate_trees_dynamic(257 + (t and $1f),
+ 1 + ((t shr 5) and $1f),
+ s.sub.trees.blens^, bl, bd, tl, td, s.hufts^, z);
+ freemem(s.sub.trees.blens);
+ if (t <> Z_OK) then
+ begin
+ if (t = cardinal(Z_DATA_ERROR)) then
+ s.mode := BLKBAD;
+ r := t;
+ { update pointers and return }
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p) - ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_blocks := inflate_flush(s,z,r);
+ exit;
+ end;
+ {$IFDEF ZLIB_DEBUG}
+ Tracev('inflate: trees ok');
+ {$ENDIF}
+ { c renamed to cs }
+ cs := inflate_codes_new(bl, bd, tl, td, z);
+ if (cs = nil) then
+ begin
+ r := Z_MEM_ERROR;
+ { update pointers and return }
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p) - ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_blocks := inflate_flush(s,z,r);
+ exit;
+ end;
+ s.sub.decode.codes := cs;
+ end;
+ s.mode := CODES;
+ { yet another falltrough }
+ goto start_codes;
+ end;
+ CODES:
+ begin
+ start_codes:
+ { update pointers }
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p) - ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+
+ r := inflate_codes(s, z, r);
+ if (r <> Z_STREAM_END) then
+ begin
+ inflate_blocks := inflate_flush(s, z, r);
+ exit;
+ end;
+ r := Z_OK;
+ inflate_codes_free(s.sub.decode.codes, z);
+ { load local pointers }
+ p := z.next_in;
+ n := z.avail_in;
+ b := s.bitb;
+ k := s.bitk;
+ q := s.write;
+ if ptruint(q) < ptruint(s.read) then
+ m := cardinal(ptruint(s.read)-ptruint(q)-1)
+ else
+ m := cardinal(ptruint(s.zend)-ptruint(q));
+ {$IFDEF ZLIB_DEBUG}
+ if (ptruint(q) >= ptruint(s.read)) then
+ Tracev('inflate: codes end '+
+ IntToStr(z.total_out + ptruint(q) - ptruint(s.read)) + ' total out')
+ else
+ Tracev('inflate: codes end '+
+ IntToStr(z.total_out + ptruint(s.zend) - ptruint(s.read) +
+ ptruint(q) - ptruint(s.window)) + ' total out');
+ {$ENDIF}
+ if (not s.last) then
+ begin
+ s.mode := ZTYPE;
+ continue; { break for switch statement in C-code }
+ end;
+ {$ifndef patch112}
+ if (k > 7) then { return unused byte, if any }
+ begin
+ {$IFDEF ZLIB_DEBUG}
+ Assert(k < 16, 'inflate_codes grabbed too many bytes');
+ {$ENDIF}
+ dec(k, 8);
+ inc(n);
+ dec(p); { can always return one }
+ end;
+ {$endif}
+ s.mode := DRY;
+ { another falltrough }
+ goto start_dry;
+ end;
+ DRY:
+ begin
+ start_dry:
+ {FLUSH}
+ s.write := q;
+ r := inflate_flush(s,z,r);
+ q := s.write;
+
+ { not needed anymore, we are done:
+ if ptruint(q) < ptruint(s.read) then
+ m := cardinal(ptruint(s.read)-ptruint(q)-1)
+ else
+ m := cardinal(ptruint(s.zend)-ptruint(q));
+ }
+
+ if (s.read <> s.write) then
+ begin
+ { update pointers and return }
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p) - ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_blocks := inflate_flush(s,z,r);
+ exit;
+ end;
+ s.mode := BLKDONE;
+ goto start_blkdone;
+ end;
+ BLKDONE:
+ begin
+ start_blkdone:
+ r := Z_STREAM_END;
+ { update pointers and return }
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p) - ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_blocks := inflate_flush(s,z,r);
+ exit;
+ end;
+ BLKBAD:
+ begin
+ r := Z_DATA_ERROR;
+ { update pointers and return }
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p) - ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_blocks := inflate_flush(s,z,r);
+ exit;
+ end;
+ else
+ begin
+ r := Z_STREAM_ERROR;
+ { update pointers and return }
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p) - ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_blocks := inflate_flush(s,z,r);
+ exit;
+ end;
+ end; { Case s.mode of }
+
+end;
+
+
+function inflate_blocks_free(s : pInflate_blocks_state;
+ var z : z_stream) : integer;
+begin
+ inflate_blocks_reset(s^, z, nil);
+ freemem(s^.window);
+ freemem(s^.hufts);
+ dispose(s);
+ {$IFDEF ZLIB_DEBUG}
+ Trace('inflate: blocks freed');
+ {$ENDIF}
+ inflate_blocks_free := Z_OK;
+end;
+
+
+procedure inflate_set_dictionary(var s : inflate_blocks_state;
+ const d : array of byte; { dictionary }
+ n : cardinal); { dictionary length }
+begin
+ move(d,s.window^,n);
+ s.write := s.window;
+ inc(s.write, n);
+ s.read := s.write;
+end;
+
+
+{ Returns true if inflate is currently at the end of a block generated
+ by Z_SYNC_FLUSH or Z_FULL_FLUSH.
+ IN assertion: s <> nil }
+
+function inflate_blocks_sync_point(var s : inflate_blocks_state) : integer;
+begin
+ inflate_blocks_sync_point := integer(s.mode = LENS);
+end;
+
+end.
diff --git a/packages/paszlib/src/infcodes.pas b/packages/paszlib/src/infcodes.pas
new file mode 100644
index 0000000000..b8006b8054
--- /dev/null
+++ b/packages/paszlib/src/infcodes.pas
@@ -0,0 +1,573 @@
+unit infcodes;
+
+{ infcodes.c -- process literals and length/distance pairs
+ Copyright (C) 1995-1998 Mark Adler
+
+ Pascal tranlastion
+ Copyright (C) 1998 by Jacques Nomssi Nzali
+ For conditions of distribution and use, see copyright notice in readme.txt
+}
+
+interface
+
+{$I zconf.inc}
+
+uses
+ zbase;
+
+function inflate_codes_new (bl : cardinal;
+ bd : cardinal;
+ tl : pInflate_huft;
+ td : pInflate_huft;
+ var z : z_stream): pInflate_codes_state;
+
+function inflate_codes(var s : inflate_blocks_state;
+ var z : z_stream;
+ r : integer) : integer;
+
+procedure inflate_codes_free(c : pInflate_codes_state;
+ var z : z_stream);
+
+implementation
+
+uses
+ infutil, inffast;
+
+
+function inflate_codes_new (bl : cardinal;
+ bd : cardinal;
+ tl : pInflate_huft;
+ td : pInflate_huft;
+ var z : z_stream): pInflate_codes_state;
+var
+ c : pInflate_codes_state;
+begin
+ new(c);
+ if c<>nil then
+ begin
+ c^.mode := START;
+ c^.lbits := Byte(bl);
+ c^.dbits := Byte(bd);
+ c^.ltree := tl;
+ c^.dtree := td;
+ {$IFDEF ZLIB_DEBUG}
+ Tracev('inflate: codes new');
+ {$ENDIF}
+ end;
+ inflate_codes_new := c;
+end;
+
+
+function inflate_codes(var s : inflate_blocks_state;
+ var z : z_stream;
+ r : integer) : integer;
+var
+ j : cardinal; { temporary storage }
+ t : pInflate_huft; { temporary pointer }
+ e : cardinal; { extra bits or operation }
+ b : cardinal; { bit buffer }
+ k : cardinal; { bits in bit buffer }
+ p : Pbyte; { input data pointer }
+ n : cardinal; { bytes available there }
+ q : Pbyte; { output window write pointer }
+ m : cardinal; { bytes to end of window or read pointer }
+ f : Pbyte; { pointer to copy strings from }
+var
+ c : pInflate_codes_state;
+begin
+ c := s.sub.decode.codes; { codes state }
+
+ { copy input/output information to locals }
+ p := z.next_in;
+ n := z.avail_in;
+ b := s.bitb;
+ k := s.bitk;
+ q := s.write;
+ if ptruint(q) < ptruint(s.read) then
+ m := cardinal(ptruint(s.read)-ptruint(q)-1)
+ else
+ m := cardinal(ptruint(s.zend)-ptruint(q));
+
+ { process input and output based on current state }
+ while True do
+ case (c^.mode) of
+ { waiting for "i:"=input, "o:"=output, "x:"=nothing }
+ START: { x: set up for LEN }
+ begin
+{$ifndef SLOW}
+ if (m >= 258) and (n >= 10) then
+ begin
+ {UPDATE}
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p)-ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+
+ r := inflate_fast(c^.lbits, c^.dbits, c^.ltree, c^.dtree, s, z);
+ {LOAD}
+ p := z.next_in;
+ n := z.avail_in;
+ b := s.bitb;
+ k := s.bitk;
+ q := s.write;
+ if ptruint(q) < ptruint(s.read) then
+ m := cardinal(ptruint(s.read)-ptruint(q)-1)
+ else
+ m := cardinal(ptruint(s.zend)-ptruint(q));
+
+ if (r <> Z_OK) then
+ begin
+ if (r = Z_STREAM_END) then
+ c^.mode := WASH
+ else
+ c^.mode := BADCODE;
+ continue; { break for switch-statement in C }
+ end;
+ end;
+{$endif} { not SLOW }
+ c^.sub.code.need := c^.lbits;
+ c^.sub.code.tree := c^.ltree;
+ c^.mode := LEN; { falltrough }
+ end;
+ LEN: { i: get length/literal/eob next }
+ begin
+ j := c^.sub.code.need;
+ {NEEDBITS(j);}
+ while (k < j) do
+ begin
+ {NEEDBYTE;}
+ if (n <> 0) then
+ r :=Z_OK
+ else
+ begin
+ {UPDATE}
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p)-ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_codes := inflate_flush(s,z,r);
+ exit;
+ end;
+ dec(n);
+ b := b or (cardinal(p^) shl k);
+ Inc(p);
+ Inc(k, 8);
+ end;
+ t := c^.sub.code.tree;
+ Inc(t, cardinal(b) and inflate_mask[j]);
+ {DUMPBITS(t^.bits);}
+ b := b shr t^.bits;
+ dec(k, t^.bits);
+
+ e := cardinal(t^.exop);
+ if (e = 0) then { literal }
+ begin
+ c^.sub.lit := t^.base;
+ {$IFDEF ZLIB_DEBUG}
+ if (t^.base >= $20) and (t^.base < $7f) then
+ Tracevv('inflate: literal '+char(t^.base))
+ else
+ Tracevv('inflate: literal '+IntToStr(t^.base));
+ {$ENDIF}
+ c^.mode := LIT;
+ continue; { break switch statement }
+ end;
+ if (e and 16 <> 0) then { length }
+ begin
+ c^.sub.copy.get := e and 15;
+ c^.len := t^.base;
+ c^.mode := LENEXT;
+ continue; { break C-switch statement }
+ end;
+ if (e and 64 = 0) then { next table }
+ begin
+ c^.sub.code.need := e;
+ c^.sub.code.tree := @huft_ptr(t)^[t^.base];
+ continue; { break C-switch statement }
+ end;
+ if (e and 32 <> 0) then { end of block }
+ begin
+ {$IFDEF ZLIB_DEBUG}
+ Tracevv('inflate: end of block');
+ {$ENDIF}
+ c^.mode := WASH;
+ continue; { break C-switch statement }
+ end;
+ c^.mode := BADCODE; { invalid code }
+ z.msg := 'invalid literal/length code';
+ r := Z_DATA_ERROR;
+ {UPDATE}
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p)-ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_codes := inflate_flush(s,z,r);
+ exit;
+ end;
+ LENEXT: { i: getting length extra (have base) }
+ begin
+ j := c^.sub.copy.get;
+ {NEEDBITS(j);}
+ while (k < j) do
+ begin
+ {NEEDBYTE;}
+ if (n <> 0) then
+ r :=Z_OK
+ else
+ begin
+ {UPDATE}
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p)-ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_codes := inflate_flush(s,z,r);
+ exit;
+ end;
+ dec(n);
+ b := b or (cardinal(p^) shl k);
+ Inc(p);
+ Inc(k, 8);
+ end;
+ Inc(c^.len, cardinal(b and inflate_mask[j]));
+ {DUMPBITS(j);}
+ b := b shr j;
+ dec(k, j);
+
+ c^.sub.code.need := c^.dbits;
+ c^.sub.code.tree := c^.dtree;
+ {$IFDEF ZLIB_DEBUG}
+ Tracevv('inflate: length '+IntToStr(c^.len));
+ {$ENDIF}
+ c^.mode := DIST;
+ { falltrough }
+ end;
+ DIST: { i: get distance next }
+ begin
+ j := c^.sub.code.need;
+ {NEEDBITS(j);}
+ while (k < j) do
+ begin
+ {NEEDBYTE;}
+ if (n <> 0) then
+ r :=Z_OK
+ else
+ begin
+ {UPDATE}
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p)-ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_codes := inflate_flush(s,z,r);
+ exit;
+ end;
+ dec(n);
+ b := b or (cardinal(p^) shl k);
+ Inc(p);
+ Inc(k, 8);
+ end;
+ t := @huft_ptr(c^.sub.code.tree)^[cardinal(b) and inflate_mask[j]];
+ {DUMPBITS(t^.bits);}
+ b := b shr t^.bits;
+ dec(k, t^.bits);
+
+ e := cardinal(t^.exop);
+ if (e and 16 <> 0) then { distance }
+ begin
+ c^.sub.copy.get := e and 15;
+ c^.sub.copy.dist := t^.base;
+ c^.mode := DISTEXT;
+ continue; { break C-switch statement }
+ end;
+ if (e and 64 = 0) then { next table }
+ begin
+ c^.sub.code.need := e;
+ c^.sub.code.tree := @huft_ptr(t)^[t^.base];
+ continue; { break C-switch statement }
+ end;
+ c^.mode := BADCODE; { invalid code }
+ z.msg := 'invalid distance code';
+ r := Z_DATA_ERROR;
+ {UPDATE}
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p)-ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_codes := inflate_flush(s,z,r);
+ exit;
+ end;
+ DISTEXT: { i: getting distance extra }
+ begin
+ j := c^.sub.copy.get;
+ {NEEDBITS(j);}
+ while (k < j) do
+ begin
+ {NEEDBYTE;}
+ if (n <> 0) then
+ r :=Z_OK
+ else
+ begin
+ {UPDATE}
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p)-ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_codes := inflate_flush(s,z,r);
+ exit;
+ end;
+ dec(n);
+ b := b or (cardinal(p^) shl k);
+ Inc(p);
+ Inc(k, 8);
+ end;
+ Inc(c^.sub.copy.dist, cardinal(b) and inflate_mask[j]);
+ {DUMPBITS(j);}
+ b := b shr j;
+ dec(k, j);
+ {$IFDEF ZLIB_DEBUG}
+ Tracevv('inflate: distance '+ IntToStr(c^.sub.copy.dist));
+ {$ENDIF}
+ c^.mode := COPY;
+ { falltrough }
+ end;
+ COPY: { o: copying bytes in window, waiting for space }
+ begin
+ f := q;
+ dec(f, c^.sub.copy.dist);
+ if (cardinal(ptruint(q) - ptruint(s.window)) < c^.sub.copy.dist) then
+ begin
+ f := s.zend;
+ dec(f, c^.sub.copy.dist - cardinal(ptruint(q) - ptruint(s.window)));
+ end;
+
+ while (c^.len <> 0) do
+ begin
+ {NEEDOUT}
+ if (m = 0) then
+ begin
+ {WRAP}
+ if (q = s.zend) and (s.read <> s.window) then
+ begin
+ q := s.window;
+ if ptruint(q) < ptruint(s.read) then
+ m := cardinal(ptruint(s.read)-ptruint(q)-1)
+ else
+ m := cardinal(ptruint(s.zend)-ptruint(q));
+ end;
+
+ if (m = 0) then
+ begin
+ {FLUSH}
+ s.write := q;
+ r := inflate_flush(s,z,r);
+ q := s.write;
+ if ptruint(q) < ptruint(s.read) then
+ m := cardinal(ptruint(s.read)-ptruint(q)-1)
+ else
+ m := cardinal(ptruint(s.zend)-ptruint(q));
+
+ {WRAP}
+ if (q = s.zend) and (s.read <> s.window) then
+ begin
+ q := s.window;
+ if ptruint(q) < ptruint(s.read) then
+ m := cardinal(ptruint(s.read)-ptruint(q)-1)
+ else
+ m := cardinal(ptruint(s.zend)-ptruint(q));
+ end;
+
+ if (m = 0) then
+ begin
+ {UPDATE}
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p)-ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_codes := inflate_flush(s,z,r);
+ exit;
+ end;
+ end;
+ end;
+ r := Z_OK;
+
+ {OUTBYTE( *f++)}
+ q^ := f^;
+ Inc(q);
+ Inc(f);
+ dec(m);
+
+ if (f = s.zend) then
+ f := s.window;
+ dec(c^.len);
+ end;
+ c^.mode := START;
+ { C-switch break; not needed }
+ end;
+ LIT: { o: got literal, waiting for output space }
+ begin
+ {NEEDOUT}
+ if (m = 0) then
+ begin
+ {WRAP}
+ if (q = s.zend) and (s.read <> s.window) then
+ begin
+ q := s.window;
+ if ptruint(q) < ptruint(s.read) then
+ m := cardinal(ptruint(s.read)-ptruint(q)-1)
+ else
+ m := cardinal(ptruint(s.zend)-ptruint(q));
+ end;
+
+ if (m = 0) then
+ begin
+ {FLUSH}
+ s.write := q;
+ r := inflate_flush(s,z,r);
+ q := s.write;
+ if ptruint(q) < ptruint(s.read) then
+ m := cardinal(ptruint(s.read)-ptruint(q)-1)
+ else
+ m := cardinal(ptruint(s.zend)-ptruint(q));
+
+ {WRAP}
+ if (q = s.zend) and (s.read <> s.window) then
+ begin
+ q := s.window;
+ if ptruint(q) < ptruint(s.read) then
+ m := cardinal(ptruint(s.read)-ptruint(q)-1)
+ else
+ m := cardinal(ptruint(s.zend)-ptruint(q));
+ end;
+
+ if (m = 0) then
+ begin
+ {UPDATE}
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p)-ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_codes := inflate_flush(s,z,r);
+ exit;
+ end;
+ end;
+ end;
+ r := Z_OK;
+
+ {OUTBYTE(c^.sub.lit);}
+ q^ := c^.sub.lit;
+ Inc(q);
+ dec(m);
+
+ c^.mode := START;
+ {break;}
+ end;
+ WASH: { o: got eob, possibly more output }
+ begin
+ {$ifdef patch112}
+ if (k > 7) then { return unused byte, if any }
+ begin
+ {$IFDEF ZLIB_DEBUG}
+ Assert(k < 16, 'inflate_codes grabbed too many bytes');
+ {$ENDIF}
+ dec(k, 8);
+ Inc(n);
+ dec(p); { can always return one }
+ end;
+ {$endif}
+ {FLUSH}
+ s.write := q;
+ r := inflate_flush(s,z,r);
+ q := s.write;
+ if ptruint(q) < ptruint(s.read) then
+ m := cardinal(ptruint(s.read)-ptruint(q)-1)
+ else
+ m := cardinal(ptruint(s.zend)-ptruint(q));
+
+ if (s.read <> s.write) then
+ begin
+ {UPDATE}
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p)-ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_codes := inflate_flush(s,z,r);
+ exit;
+ end;
+ c^.mode := ZEND;
+ { falltrough }
+ end;
+
+ ZEND:
+ begin
+ r := Z_STREAM_END;
+ {UPDATE}
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p)-ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_codes := inflate_flush(s,z,r);
+ exit;
+ end;
+ BADCODE: { x: got error }
+ begin
+ r := Z_DATA_ERROR;
+ {UPDATE}
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p)-ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_codes := inflate_flush(s,z,r);
+ exit;
+ end;
+ else
+ begin
+ r := Z_STREAM_ERROR;
+ {UPDATE}
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ Inc(z.total_in, ptruint(p)-ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_codes := inflate_flush(s,z,r);
+ exit;
+ end;
+ end;
+{NEED_DUMMY_RETURN - Delphi2+ dumb compilers complain without this }
+ inflate_codes := Z_STREAM_ERROR;
+end;
+
+
+procedure inflate_codes_free(c : pInflate_codes_state;
+ var z : z_stream);
+begin
+ dispose(c);
+ {$IFDEF ZLIB_DEBUG}
+ Tracev('inflate: codes free');
+ {$ENDIF}
+end;
+
+end. \ No newline at end of file
diff --git a/packages/paszlib/src/inffast.pas b/packages/paszlib/src/inffast.pas
new file mode 100644
index 0000000000..4a70c49cc3
--- /dev/null
+++ b/packages/paszlib/src/inffast.pas
@@ -0,0 +1,315 @@
+Unit InfFast;
+
+{
+ inffast.h and
+ inffast.c -- process literals and length/distance pairs fast
+ Copyright (C) 1995-1998 Mark Adler
+
+ Pascal tranlastion
+ Copyright (C) 1998 by Jacques Nomssi Nzali
+ For conditions of distribution and use, see copyright notice in readme.txt
+}
+
+
+interface
+
+{$I zconf.inc}
+
+uses
+ zbase;
+
+function inflate_fast( bl : cardinal;
+ bd : cardinal;
+ tl : pInflate_huft;
+ td : pInflate_huft;
+ var s : inflate_blocks_state;
+ var z : z_stream) : integer;
+
+
+implementation
+
+uses
+ infutil;
+
+
+{ Called with number of bytes left to write in window at least 258
+ (the maximum string length) and number of input bytes available
+ at least ten. The ten bytes are six bytes for the longest length/
+ distance pair plus four bytes for overloading the bit buffer. }
+
+function inflate_fast( bl : cardinal;
+ bd : cardinal;
+ tl : pInflate_huft;
+ td : pInflate_huft;
+ var s : inflate_blocks_state;
+ var z : z_stream) : integer;
+
+var
+ t : pInflate_huft; { temporary pointer }
+ e : cardinal; { extra bits or operation }
+ b : longint; { bit buffer }
+ k : cardinal; { bits in bit buffer }
+ p : Pbyte; { input data pointer }
+ n : cardinal; { bytes available there }
+ q : Pbyte; { output window write pointer }
+ m : cardinal; { bytes to end of window or read pointer }
+ ml : cardinal; { mask for literal/length tree }
+ md : cardinal; { mask for distance tree }
+ c : cardinal; { bytes to copy }
+ d : cardinal; { distance back to copy from }
+ r : Pbyte; { copy source pointer }
+begin
+ { load input, output, bit values (macro LOAD) }
+ p := z.next_in;
+ n := z.avail_in;
+ b := s.bitb;
+ k := s.bitk;
+ q := s.write;
+ if ptruint(q) < ptruint(s.read) then
+ m := cardinal(ptruint(s.read)-ptruint(q)-1)
+ else
+ m := cardinal(ptruint(s.zend)-ptruint(q));
+
+ { initialize masks }
+ ml := inflate_mask[bl];
+ md := inflate_mask[bd];
+
+ { do until not enough input or output space for fast loop }
+ repeat { assume called with (m >= 258) and (n >= 10) }
+ { get literal/length code }
+ {GRABBITS(20);} { max bits for literal/length code }
+ while (k < 20) do
+ begin
+ dec(n);
+ b := b or (longint(p^) shl k);
+ inc(p);
+ inc(k, 8);
+ end;
+
+ t := @(huft_ptr(tl)^[cardinal(b) and ml]);
+
+ e := t^.exop;
+ if (e = 0) then
+ begin
+ {DUMPBITS(t^.bits);}
+ b := b shr t^.bits;
+ dec(k, t^.bits);
+ {$IFDEF ZLIB_DEBUG}
+ if (t^.base >= $20) and (t^.base < $7f) then
+ Tracevv('inflate: * literal '+char(t^.base))
+ else
+ Tracevv('inflate: * literal '+ IntToStr(t^.base));
+ {$ENDIF}
+ q^ := Byte(t^.base);
+ inc(q);
+ dec(m);
+ continue;
+ end;
+ repeat
+ {DUMPBITS(t^.bits);}
+ b := b shr t^.bits;
+ dec(k, t^.bits);
+
+ if (e and 16 <> 0) then
+ begin
+ { get extra bits for length }
+ e := e and 15;
+ c := t^.base + (cardinal(b) and inflate_mask[e]);
+ {DUMPBITS(e);}
+ b := b shr e;
+ dec(k, e);
+ {$IFDEF ZLIB_DEBUG}
+ Tracevv('inflate: * length ' + IntToStr(c));
+ {$ENDIF}
+ { decode distance base of block to copy }
+ {GRABBITS(15);} { max bits for distance code }
+ while (k < 15) do
+ begin
+ dec(n);
+ b := b or (longint(p^) shl k);
+ inc(p);
+ inc(k, 8);
+ end;
+
+ t := @huft_ptr(td)^[cardinal(b) and md];
+ e := t^.exop;
+ repeat
+ {DUMPBITS(t^.bits);}
+ b := b shr t^.bits;
+ dec(k, t^.bits);
+
+ if (e and 16 <> 0) then
+ begin
+ { get extra bits to add to distance base }
+ e := e and 15;
+ {GRABBITS(e);} { get extra bits (up to 13) }
+ while (k < e) do
+ begin
+ dec(n);
+ b := b or (longint(p^) shl k);
+ inc(p);
+ inc(k, 8);
+ end;
+
+ d := t^.base + (cardinal(b) and inflate_mask[e]);
+ {DUMPBITS(e);}
+ b := b shr e;
+ dec(k, e);
+
+ {$IFDEF ZLIB_DEBUG}
+ Tracevv('inflate: * distance '+IntToStr(d));
+ {$ENDIF}
+ { do the copy }
+ dec(m, c);
+ if (cardinal(ptruint(q) - ptruint(s.window)) >= d) then { offset before dest }
+ begin { just copy }
+ r := q;
+ dec(r, d);
+ q^ := r^; inc(q); inc(r); dec(c); { minimum count is three, }
+ q^ := r^; inc(q); inc(r); dec(c); { so unroll loop a little }
+ end
+ else { else offset after destination }
+ begin
+ e := d - cardinal(ptruint(q) - ptruint(s.window)); { bytes from offset to end }
+ r := s.zend;
+ dec(r, e); { pointer to offset }
+ if (c > e) then { if source crosses, }
+ begin
+ dec(c, e); { copy to end of window }
+ repeat
+ q^ := r^;
+ inc(q);
+ inc(r);
+ dec(e);
+ until (e=0);
+ r := s.window; { copy rest from start of window }
+ end;
+ end;
+ repeat { copy all or what's left }
+ q^ := r^;
+ inc(q);
+ inc(r);
+ dec(c);
+ until (c = 0);
+ break;
+ end
+ else
+ if (e and 64 = 0) then
+ begin
+ inc(t, t^.base + (cardinal(b) and inflate_mask[e]));
+ e := t^.exop;
+ end
+ else
+ begin
+ z.msg := 'invalid distance code';
+ {UNGRAB}
+ c := z.avail_in-n;
+ if (k shr 3) < c then
+ c := k shr 3;
+ inc(n, c);
+ dec(p, c);
+ dec(k, c shl 3);
+ {UPDATE}
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ inc(z.total_in, ptruint(p)-ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+
+ inflate_fast := Z_DATA_ERROR;
+ exit;
+ end;
+ until FALSE;
+ break;
+ end;
+ if (e and 64 = 0) then
+ begin
+ {t += t->base;
+ e = (t += ((cardinal)b & inflate_mask[e]))->exop;}
+
+ inc(t, t^.base + (cardinal(b) and inflate_mask[e]));
+ e := t^.exop;
+ if (e = 0) then
+ begin
+ {DUMPBITS(t^.bits);}
+ b := b shr t^.bits;
+ dec(k, t^.bits);
+
+ {$IFDEF ZLIB_DEBUG}
+ if (t^.base >= $20) and (t^.base < $7f) then
+ Tracevv('inflate: * literal '+char(t^.base))
+ else
+ Tracevv('inflate: * literal '+IntToStr(t^.base));
+ {$ENDIF}
+ q^ := Byte(t^.base);
+ inc(q);
+ dec(m);
+ break;
+ end;
+ end
+ else
+ if (e and 32 <> 0) then
+ begin
+ {$IFDEF ZLIB_DEBUG}
+ Tracevv('inflate: * end of block');
+ {$ENDIF}
+ {UNGRAB}
+ c := z.avail_in-n;
+ if (k shr 3) < c then
+ c := k shr 3;
+ inc(n, c);
+ dec(p, c);
+ dec(k, c shl 3);
+ {UPDATE}
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ inc(z.total_in, ptruint(p)-ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_fast := Z_STREAM_END;
+ exit;
+ end
+ else
+ begin
+ z.msg := 'invalid literal/length code';
+ {UNGRAB}
+ c := z.avail_in-n;
+ if (k shr 3) < c then
+ c := k shr 3;
+ inc(n, c);
+ dec(p, c);
+ dec(k, c shl 3);
+ {UPDATE}
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ inc(z.total_in, ptruint(p)-ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_fast := Z_DATA_ERROR;
+ exit;
+ end;
+ until FALSE;
+ until (m < 258) or (n < 10);
+
+ { not enough input or output--restore pointers and return }
+ {UNGRAB}
+ c := z.avail_in-n;
+ if (k shr 3) < c then
+ c := k shr 3;
+ inc(n, c);
+ dec(p, c);
+ dec(k, c shl 3);
+ {UPDATE}
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ inc(z.total_in, ptruint(p)-ptruint(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ inflate_fast := Z_OK;
+end;
+
+end. \ No newline at end of file
diff --git a/packages/paszlib/src/inftrees.pas b/packages/paszlib/src/inftrees.pas
new file mode 100644
index 0000000000..1d034f4dc1
--- /dev/null
+++ b/packages/paszlib/src/inftrees.pas
@@ -0,0 +1,780 @@
+unit inftrees;
+
+{ inftrees.h -- header to use inftrees.c
+ inftrees.c -- generate Huffman trees for efficient decoding
+ Copyright (C) 1995-1998 Mark Adler
+
+ WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change.
+
+ Pascal tranlastion
+ Copyright (C) 1998 by Jacques Nomssi Nzali
+ For conditions of distribution and use, see copyright notice in readme.txt
+}
+
+interface
+
+{$I zconf.inc}
+
+uses
+ zbase;
+
+
+{ Maximum size of dynamic tree. The maximum found in a long but non-
+ exhaustive search was 1004 huft structures (850 for length/literals
+ and 154 for distances, the latter actually the result of an
+ exhaustive search). The actual maximum is not known, but the
+ value below is more than safe. }
+const
+ MANY = 1440;
+
+
+{$ifdef ZLIB_DEBUG}
+var
+ inflate_hufts : cardinal;
+{$endif}
+
+function inflate_trees_bits(
+ var c : array of cardinal; { 19 code lengths }
+ var bb : cardinal; { bits tree desired/actual depth }
+ var tb : pinflate_huft; { bits tree result }
+ var hp : array of Inflate_huft; { space for trees }
+ var z : z_stream { for messages }
+ ) : integer;
+
+function inflate_trees_dynamic(
+ nl : cardinal; { number of literal/length codes }
+ nd : cardinal; { number of distance codes }
+ var c : Array of cardinal; { that many (total) code lengths }
+ var bl : cardinal; { literal desired/actual bit depth }
+ var bd : cardinal; { distance desired/actual bit depth }
+var tl : pInflate_huft; { literal/length tree result }
+var td : pInflate_huft; { distance tree result }
+var hp : array of Inflate_huft; { space for trees }
+var z : z_stream { for messages }
+ ) : integer;
+
+function inflate_trees_fixed (
+ var bl : cardinal; { literal desired/actual bit depth }
+ var bd : cardinal; { distance desired/actual bit depth }
+ var tl : pInflate_huft; { literal/length tree result }
+ var td : pInflate_huft; { distance tree result }
+ var z : z_stream { for memory allocation }
+ ) : integer;
+
+
+implementation
+
+const
+ inflate_copyright = 'inflate 1.1.2 Copyright 1995-1998 Mark Adler';
+
+{
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+}
+
+
+const
+{ Tables for deflate from PKZIP's appnote.txt. }
+ cplens : Array [0..30] Of cardinal { Copy lengths for literal codes 257..285 }
+ = (3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0);
+ { actually lengths - 2; also see note #13 above about 258 }
+
+ invalid_code = 112;
+
+ cplext : Array [0..30] Of cardinal { Extra bits for literal codes 257..285 }
+ = (0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, invalid_code, invalid_code);
+
+ cpdist : Array [0..29] Of cardinal { Copy offsets for distance codes 0..29 }
+ = (1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577);
+
+ cpdext : Array [0..29] Of cardinal { Extra bits for distance codes }
+ = (0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13);
+
+{ Huffman code decoding is performed using a multi-level table lookup.
+ The fastest way to decode is to simply build a lookup table whose
+ size is determined by the longest code. However, the time it takes
+ to build this table can also be a factor if the data being decoded
+ is not very long. The most common codes are necessarily the
+ shortest codes, so those codes dominate the decoding time, and hence
+ the speed. The idea is you can have a shorter table that decodes the
+ shorter, more probable codes, and then point to subsidiary tables for
+ the longer codes. The time it costs to decode the longer codes is
+ then traded against the time it takes to make longer tables.
+
+ This results of this trade are in the variables lbits and dbits
+ below. lbits is the number of bits the first level table for literal/
+ length codes can decode in one step, and dbits is the same thing for
+ the distance codes. Subsequent tables are also less than or equal to
+ those sizes. These values may be adjusted either when all of the
+ codes are shorter than that, in which case the longest code length in
+ bits is used, or when the shortest code is *longer* than the requested
+ table size, in which case the length of the shortest code in bits is
+ used.
+
+ There are two different values for the two tables, since they code a
+ different number of possibilities each. The literal/length table
+ codes 286 possible values, or in a flat code, a little over eight
+ bits. The distance table codes 30 possible values, or a little less
+ than five bits, flat. The optimum values for speed end up being
+ about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+ The optimum values may differ though from machine to machine, and
+ possibly even between compilers. Your mileage may vary. }
+
+
+{ If BMAX needs to be larger than 16, then h and x[] should be uLong. }
+const
+ BMAX = 15; { maximum bit length of any code }
+
+{$DEFINE USE_PTR}
+
+function huft_build(
+var b : array of cardinal; { code lengths in bits (all assumed <= BMAX) }
+ n : cardinal; { number of codes (assumed <= N_MAX) }
+ s : cardinal; { number of simple-valued codes (0..s-1) }
+const d : array of cardinal; { list of base values for non-simple codes }
+{ array of word }
+const e : array of cardinal; { list of extra bits for non-simple codes }
+{ array of byte }
+ t : ppInflate_huft; { result: starting table }
+var m : cardinal; { maximum lookup bits, returns actual }
+var hp : array of inflate_huft; { space for trees }
+var hn : cardinal; { hufts used in space }
+var v : array of cardinal { working area: values in order of bit length }
+ ) : integer;
+{ Given a list of code lengths and a maximum table size, make a set of
+ tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR
+ if the given code set is incomplete (the tables are still built in this
+ case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
+ lengths), or Z_MEM_ERROR if not enough memory. }
+Var
+ a : cardinal; { counter for codes of length k }
+ c : Array [0..BMAX] Of cardinal; { bit length count table }
+ f : cardinal; { i repeats in table every f entries }
+ g : integer; { maximum code length }
+ h : integer; { table level }
+ i : cardinal; {register} { counter, current code }
+ j : cardinal; {register} { counter }
+ k : integer; {register} { number of bits in current code }
+ l : integer; { bits per table (returned in m) }
+ mask : cardinal; { (1 shl w) - 1, to avoid cc -O bug on HP }
+ p : ^cardinal; {register} { pointer into c[], b[], or v[] }
+ q : pInflate_huft; { points to current table }
+ r : inflate_huft; { table entry for structure assignment }
+ u : Array [0..BMAX-1] Of pInflate_huft; { table stack }
+ w : integer; {register} { bits before this table = (l*h) }
+ x : Array [0..BMAX] Of cardinal; { bit offsets, then code stack }
+ {$IFDEF USE_PTR}
+ xp : Pcardinal; { pointer into x }
+ {$ELSE}
+ xp : cardinal;
+ {$ENDIF}
+ y : integer; { number of dummy codes added }
+ z : cardinal; { number of entries in current table }
+Begin
+ { Generate counts for each bit length }
+ FillChar(c,SizeOf(c),0) ; { clear c[] }
+
+ for i := 0 to n-1 do
+ Inc (c[b[i]]); { assume all entries <= BMAX }
+
+ If (c[0] = n) Then { null input--all zero length codes }
+ Begin
+ t^ := pInflate_huft(NIL);
+ m := 0 ;
+ huft_build := Z_OK ;
+ Exit;
+ End ;
+
+ { Find minimum and maximum length, bound [m] by those }
+ l := m;
+ for j:=1 To BMAX do
+ if (c[j] <> 0) then
+ break;
+ k := j ; { minimum code length }
+ if (cardinal(l) < j) then
+ l := j;
+ for i := BMAX downto 1 do
+ if (c[i] <> 0) then
+ break ;
+ g := i ; { maximum code length }
+ if (cardinal(l) > i) then
+ l := i;
+ m := l;
+
+ { Adjust last length count to fill out codes, if needed }
+ y := 1 shl j ;
+ while (j < i) do
+ begin
+ Dec(y, c[j]) ;
+ if (y < 0) then
+ begin
+ huft_build := Z_DATA_ERROR; { bad input: more codes than bits }
+ exit;
+ end ;
+ Inc(j) ;
+ y := y shl 1
+ end;
+ Dec (y, c[i]) ;
+ if (y < 0) then
+ begin
+ huft_build := Z_DATA_ERROR; { bad input: more codes than bits }
+ exit;
+ end;
+ Inc(c[i], y);
+
+ { Generate starting offsets into the value table FOR each length }
+ {$IFDEF USE_PTR}
+ x[1] := 0;
+ j := 0;
+
+ p := @c[1];
+ xp := @x[2];
+
+ dec(i); { note that i = g from above }
+ WHILE (i > 0) DO
+ BEGIN
+ inc(j, p^);
+ xp^ := j;
+ inc(p);
+ inc(xp);
+ dec(i);
+ END;
+ {$ELSE}
+ x[1] := 0;
+ j := 0 ;
+ for i := 1 to g do
+ begin
+ x[i] := j;
+ Inc(j, c[i]);
+ end;
+ {$ENDIF}
+
+ { Make a table of values in order of bit lengths }
+ for i := 0 to n-1 do
+ begin
+ j := b[i];
+ if (j <> 0) then
+ begin
+ v[ x[j] ] := i;
+ Inc(x[j]);
+ end;
+ end;
+ n := x[g]; { set n to length of v }
+
+ { Generate the Huffman codes and for each, make the table entries }
+ i := 0 ;
+ x[0] := 0 ; { first Huffman code is zero }
+ p := @v[0] ; { grab values in bit order }
+ h := -1 ; { no tables yet--level -1 }
+ w := -l ; { bits decoded = (l*h) }
+
+ u[0] := pInflate_huft(NIL); { just to keep compilers happy }
+ q := pInflate_huft(NIL); { ditto }
+ z := 0 ; { ditto }
+
+ { go through the bit lengths (k already is bits in shortest code) }
+ while (k <= g) Do
+ begin
+ a := c[k] ;
+ while (a<>0) Do
+ begin
+ Dec (a) ;
+ { here i is the Huffman code of length k bits for value p^ }
+ { make tables up to required level }
+ while (k > w + l) do
+ begin
+
+ Inc (h) ;
+ Inc (w, l); { add bits already decoded }
+ { previous table always l bits }
+ { compute minimum size table less than or equal to l bits }
+
+ { table size upper limit }
+ z := g - w;
+ If (z > cardinal(l)) Then
+ z := l;
+
+ { try a k-w bit table }
+ j := k - w;
+ f := 1 shl j;
+ if (f > a+1) Then { too few codes for k-w bit table }
+ begin
+ Dec(f, a+1); { deduct codes from patterns left }
+ {$IFDEF USE_PTR}
+ xp := Addr(c[k]);
+
+ if (j < z) then
+ begin
+ Inc(j);
+ while (j < z) do
+ begin { try smaller tables up to z bits }
+ f := f shl 1;
+ Inc (xp) ;
+ If (f <= xp^) Then
+ break; { enough codes to use up j bits }
+ Dec(f, xp^); { else deduct codes from patterns }
+ Inc(j);
+ end;
+ end;
+ {$ELSE}
+ xp := k;
+
+ if (j < z) then
+ begin
+ Inc (j) ;
+ While (j < z) Do
+ begin { try smaller tables up to z bits }
+ f := f * 2;
+ Inc (xp) ;
+ if (f <= c[xp]) then
+ Break ; { enough codes to use up j bits }
+ Dec (f, c[xp]) ; { else deduct codes from patterns }
+ Inc (j);
+ end;
+ end;
+ {$ENDIF}
+ end;
+
+ z := 1 shl j; { table entries for j-bit table }
+
+ { allocate new table }
+ if (hn + z > MANY) then { (note: doesn't matter for fixed) }
+ begin
+ huft_build := Z_MEM_ERROR; { not enough memory }
+ exit;
+ end;
+
+ q := @hp[hn];
+ u[h] := q;
+ Inc(hn, z);
+
+ { connect to last table, if there is one }
+ if (h <> 0) then
+ begin
+ x[h] := i; { save pattern for backing up }
+ r.bits := byte(l); { bits to dump before this table }
+ r.exop := byte(j); { bits in this table }
+ j := i shr (w - l);
+ {r.base := cardinal( q - u[h-1] -j);} { offset to this table }
+ r.base := (ptruint(q) - ptruint(u[h-1]) ) div sizeof(q^) - j;
+ huft_Ptr(u[h-1])^[j] := r; { connect to last table }
+ end
+ else
+ t^ := q; { first table is returned result }
+ end;
+
+ { set up table entry in r }
+ r.bits := byte(k - w);
+
+ { C-code: if (p >= v + n) - see ZUTIL.PAS for comments }
+
+ if ptruint(p)>=ptruint(@(v[n])) then { also works under DPMI ?? }
+ r.exop := 128 + 64 { out of values--invalid code }
+ else
+ if (p^ < s) then
+ begin
+ if (p^ < 256) then { 256 is end-of-block code }
+ r.exop := 0
+ Else
+ r.exop := 32 + 64; { EOB_code; }
+ r.base := p^; { simple code is just the value }
+ Inc(p);
+ end
+ Else
+ begin
+ r.exop := byte(e[p^-s] + 16 + 64); { non-simple--look up in lists }
+ r.base := d[p^-s];
+ Inc (p);
+ end ;
+
+ { fill code-like entries with r }
+ f := 1 shl (k - w);
+ j := i shr w;
+ while (j < z) do
+ begin
+ huft_Ptr(q)^[j] := r;
+ Inc(j, f);
+ end;
+
+ { backwards increment the k-bit code i }
+ j := 1 shl (k-1) ;
+ while (i and j) <> 0 do
+ begin
+ i := i xor j; { bitwise exclusive or }
+ j := j shr 1
+ end ;
+ i := i xor j;
+
+ { backup over finished tables }
+ mask := (1 shl w) - 1; { needed on HP, cc -O bug }
+ while ((i and mask) <> x[h]) do
+ begin
+ Dec(h); { don't need to update q }
+ Dec(w, l);
+ mask := (1 shl w) - 1;
+ end;
+
+ end;
+
+ Inc(k);
+ end;
+
+ { Return Z_BUF_ERROR if we were given an incomplete table }
+ if (y <> 0) And (g <> 1) then
+ huft_build := Z_BUF_ERROR
+ else
+ huft_build := Z_OK;
+end; { huft_build}
+
+
+function inflate_trees_bits(
+ var c : array of cardinal; { 19 code lengths }
+ var bb : cardinal; { bits tree desired/actual depth }
+ var tb : pinflate_huft; { bits tree result }
+ var hp : array of Inflate_huft; { space for trees }
+ var z : z_stream { for messages }
+ ) : integer;
+var
+ r : integer;
+ hn : cardinal; { hufts used in space }
+ v : Pcardinalarray; { work area for huft_build }
+begin
+ hn := 0;
+ getmem(v,19*sizeof(cardinal));
+ if (v = nil) then
+ begin
+ inflate_trees_bits := Z_MEM_ERROR;
+ exit;
+ end;
+
+ r := huft_build(c, 19, 19, cplens, cplext,
+ {Pcardinal(nil), Pcardinal(nil),}
+ @tb, bb, hp, hn, v^);
+ if (r = Z_DATA_ERROR) then
+ z.msg := 'oversubscribed dynamic bit lengths tree'
+ else
+ if (r = Z_BUF_ERROR) or (bb = 0) then
+ begin
+ z.msg := 'incomplete dynamic bit lengths tree';
+ r := Z_DATA_ERROR;
+ end;
+ freemem(v);
+ inflate_trees_bits := r;
+end;
+
+
+function inflate_trees_dynamic(
+ nl : cardinal; { number of literal/length codes }
+ nd : cardinal; { number of distance codes }
+ var c : Array of cardinal; { that many (total) code lengths }
+ var bl : cardinal; { literal desired/actual bit depth }
+ var bd : cardinal; { distance desired/actual bit depth }
+var tl : pInflate_huft; { literal/length tree result }
+var td : pInflate_huft; { distance tree result }
+var hp : array of Inflate_huft; { space for trees }
+var z : z_stream { for messages }
+ ) : integer;
+var
+ r : integer;
+ hn : cardinal; { hufts used in space }
+ v : Pcardinalarray; { work area for huft_build }
+begin
+ hn := 0;
+ { allocate work area }
+ getmem(v,288*sizeof(cardinal));
+ if (v = nil) then
+ begin
+ inflate_trees_dynamic := Z_MEM_ERROR;
+ exit;
+ end;
+
+ { build literal/length tree }
+ r := huft_build(c, nl, 257, cplens, cplext, @tl, bl, hp, hn, v^);
+ if (r <> Z_OK) or (bl = 0) then
+ begin
+ if (r = Z_DATA_ERROR) then
+ z.msg := 'oversubscribed literal/length tree'
+ else
+ if (r <> Z_MEM_ERROR) then
+ begin
+ z.msg := 'incomplete literal/length tree';
+ r := Z_DATA_ERROR;
+ end;
+
+ freemem(v);
+ inflate_trees_dynamic := r;
+ exit;
+ end;
+
+ { build distance tree }
+ r := huft_build(Pcardinalarray(@c[nl])^, nd, 0,
+ cpdist, cpdext, @td, bd, hp, hn, v^);
+ if (r <> Z_OK) or ((bd = 0) and (nl > 257)) then
+ begin
+ if (r = Z_DATA_ERROR) then
+ z.msg := 'oversubscribed literal/length tree'
+ else
+ if (r = Z_BUF_ERROR) then
+ begin
+{$ifdef PKZIP_BUG_WORKAROUND}
+ r := Z_OK;
+ end;
+{$else}
+ z.msg := 'incomplete literal/length tree';
+ r := Z_DATA_ERROR;
+ end
+ else
+ if (r <> Z_MEM_ERROR) then
+ begin
+ z.msg := 'empty distance tree with lengths';
+ r := Z_DATA_ERROR;
+ end;
+ freemem(v);
+ inflate_trees_dynamic := r;
+ exit;
+{$endif}
+ end;
+
+ { done }
+ freemem(v);
+ inflate_trees_dynamic := Z_OK;
+end;
+
+{$UNDEF BUILDFIXED}
+
+{ build fixed tables only once--keep them here }
+{$IFNDEF BUILDFIXED}
+{ locals }
+const
+ fixed_built : Boolean = false;
+ FIXEDH = 544; { number of hufts used by fixed tables }
+var
+ fixed_mem : array[0..FIXEDH-1] of inflate_huft;
+ fixed_bl : cardinal;
+ fixed_bd : cardinal;
+ fixed_tl : pInflate_huft;
+ fixed_td : pInflate_huft;
+
+{$ELSE}
+
+{ inffixed.h -- table for decoding fixed codes }
+
+{local}
+const
+ fixed_bl = 9;
+{local}
+const
+ fixed_bd = 5;
+{local}
+const
+ fixed_tl : array [0..288-1] of inflate_huft = (
+ Exop, { number of extra bits or operation }
+ bits : byte; { number of bits in this code or subcode }
+ {pad : cardinal;} { pad structure to a power of 2 (4 bytes for }
+ { 16-bit, 8 bytes for 32-bit integer's) }
+ base : cardinal; { literal, length base, or distance base }
+ { or table offset }
+
+ ((96,7),256), ((0,8),80), ((0,8),16), ((84,8),115), ((82,7),31),
+ ((0,8),112), ((0,8),48), ((0,9),192), ((80,7),10), ((0,8),96),
+ ((0,8),32), ((0,9),160), ((0,8),0), ((0,8),128), ((0,8),64),
+ ((0,9),224), ((80,7),6), ((0,8),88), ((0,8),24), ((0,9),144),
+ ((83,7),59), ((0,8),120), ((0,8),56), ((0,9),208), ((81,7),17),
+ ((0,8),104), ((0,8),40), ((0,9),176), ((0,8),8), ((0,8),136),
+ ((0,8),72), ((0,9),240), ((80,7),4), ((0,8),84), ((0,8),20),
+ ((85,8),227), ((83,7),43), ((0,8),116), ((0,8),52), ((0,9),200),
+ ((81,7),13), ((0,8),100), ((0,8),36), ((0,9),168), ((0,8),4),
+ ((0,8),132), ((0,8),68), ((0,9),232), ((80,7),8), ((0,8),92),
+ ((0,8),28), ((0,9),152), ((84,7),83), ((0,8),124), ((0,8),60),
+ ((0,9),216), ((82,7),23), ((0,8),108), ((0,8),44), ((0,9),184),
+ ((0,8),12), ((0,8),140), ((0,8),76), ((0,9),248), ((80,7),3),
+ ((0,8),82), ((0,8),18), ((85,8),163), ((83,7),35), ((0,8),114),
+ ((0,8),50), ((0,9),196), ((81,7),11), ((0,8),98), ((0,8),34),
+ ((0,9),164), ((0,8),2), ((0,8),130), ((0,8),66), ((0,9),228),
+ ((80,7),7), ((0,8),90), ((0,8),26), ((0,9),148), ((84,7),67),
+ ((0,8),122), ((0,8),58), ((0,9),212), ((82,7),19), ((0,8),106),
+ ((0,8),42), ((0,9),180), ((0,8),10), ((0,8),138), ((0,8),74),
+ ((0,9),244), ((80,7),5), ((0,8),86), ((0,8),22), ((192,8),0),
+ ((83,7),51), ((0,8),118), ((0,8),54), ((0,9),204), ((81,7),15),
+ ((0,8),102), ((0,8),38), ((0,9),172), ((0,8),6), ((0,8),134),
+ ((0,8),70), ((0,9),236), ((80,7),9), ((0,8),94), ((0,8),30),
+ ((0,9),156), ((84,7),99), ((0,8),126), ((0,8),62), ((0,9),220),
+ ((82,7),27), ((0,8),110), ((0,8),46), ((0,9),188), ((0,8),14),
+ ((0,8),142), ((0,8),78), ((0,9),252), ((96,7),256), ((0,8),81),
+ ((0,8),17), ((85,8),131), ((82,7),31), ((0,8),113), ((0,8),49),
+ ((0,9),194), ((80,7),10), ((0,8),97), ((0,8),33), ((0,9),162),
+ ((0,8),1), ((0,8),129), ((0,8),65), ((0,9),226), ((80,7),6),
+ ((0,8),89), ((0,8),25), ((0,9),146), ((83,7),59), ((0,8),121),
+ ((0,8),57), ((0,9),210), ((81,7),17), ((0,8),105), ((0,8),41),
+ ((0,9),178), ((0,8),9), ((0,8),137), ((0,8),73), ((0,9),242),
+ ((80,7),4), ((0,8),85), ((0,8),21), ((80,8),258), ((83,7),43),
+ ((0,8),117), ((0,8),53), ((0,9),202), ((81,7),13), ((0,8),101),
+ ((0,8),37), ((0,9),170), ((0,8),5), ((0,8),133), ((0,8),69),
+ ((0,9),234), ((80,7),8), ((0,8),93), ((0,8),29), ((0,9),154),
+ ((84,7),83), ((0,8),125), ((0,8),61), ((0,9),218), ((82,7),23),
+ ((0,8),109), ((0,8),45), ((0,9),186), ((0,8),13), ((0,8),141),
+ ((0,8),77), ((0,9),250), ((80,7),3), ((0,8),83), ((0,8),19),
+ ((85,8),195), ((83,7),35), ((0,8),115), ((0,8),51), ((0,9),198),
+ ((81,7),11), ((0,8),99), ((0,8),35), ((0,9),166), ((0,8),3),
+ ((0,8),131), ((0,8),67), ((0,9),230), ((80,7),7), ((0,8),91),
+ ((0,8),27), ((0,9),150), ((84,7),67), ((0,8),123), ((0,8),59),
+ ((0,9),214), ((82,7),19), ((0,8),107), ((0,8),43), ((0,9),182),
+ ((0,8),11), ((0,8),139), ((0,8),75), ((0,9),246), ((80,7),5),
+ ((0,8),87), ((0,8),23), ((192,8),0), ((83,7),51), ((0,8),119),
+ ((0,8),55), ((0,9),206), ((81,7),15), ((0,8),103), ((0,8),39),
+ ((0,9),174), ((0,8),7), ((0,8),135), ((0,8),71), ((0,9),238),
+ ((80,7),9), ((0,8),95), ((0,8),31), ((0,9),158), ((84,7),99),
+ ((0,8),127), ((0,8),63), ((0,9),222), ((82,7),27), ((0,8),111),
+ ((0,8),47), ((0,9),190), ((0,8),15), ((0,8),143), ((0,8),79),
+ ((0,9),254), ((96,7),256), ((0,8),80), ((0,8),16), ((84,8),115),
+ ((82,7),31), ((0,8),112), ((0,8),48), ((0,9),193), ((80,7),10),
+ ((0,8),96), ((0,8),32), ((0,9),161), ((0,8),0), ((0,8),128),
+ ((0,8),64), ((0,9),225), ((80,7),6), ((0,8),88), ((0,8),24),
+ ((0,9),145), ((83,7),59), ((0,8),120), ((0,8),56), ((0,9),209),
+ ((81,7),17), ((0,8),104), ((0,8),40), ((0,9),177), ((0,8),8),
+ ((0,8),136), ((0,8),72), ((0,9),241), ((80,7),4), ((0,8),84),
+ ((0,8),20), ((85,8),227), ((83,7),43), ((0,8),116), ((0,8),52),
+ ((0,9),201), ((81,7),13), ((0,8),100), ((0,8),36), ((0,9),169),
+ ((0,8),4), ((0,8),132), ((0,8),68), ((0,9),233), ((80,7),8),
+ ((0,8),92), ((0,8),28), ((0,9),153), ((84,7),83), ((0,8),124),
+ ((0,8),60), ((0,9),217), ((82,7),23), ((0,8),108), ((0,8),44),
+ ((0,9),185), ((0,8),12), ((0,8),140), ((0,8),76), ((0,9),249),
+ ((80,7),3), ((0,8),82), ((0,8),18), ((85,8),163), ((83,7),35),
+ ((0,8),114), ((0,8),50), ((0,9),197), ((81,7),11), ((0,8),98),
+ ((0,8),34), ((0,9),165), ((0,8),2), ((0,8),130), ((0,8),66),
+ ((0,9),229), ((80,7),7), ((0,8),90), ((0,8),26), ((0,9),149),
+ ((84,7),67), ((0,8),122), ((0,8),58), ((0,9),213), ((82,7),19),
+ ((0,8),106), ((0,8),42), ((0,9),181), ((0,8),10), ((0,8),138),
+ ((0,8),74), ((0,9),245), ((80,7),5), ((0,8),86), ((0,8),22),
+ ((192,8),0), ((83,7),51), ((0,8),118), ((0,8),54), ((0,9),205),
+ ((81,7),15), ((0,8),102), ((0,8),38), ((0,9),173), ((0,8),6),
+ ((0,8),134), ((0,8),70), ((0,9),237), ((80,7),9), ((0,8),94),
+ ((0,8),30), ((0,9),157), ((84,7),99), ((0,8),126), ((0,8),62),
+ ((0,9),221), ((82,7),27), ((0,8),110), ((0,8),46), ((0,9),189),
+ ((0,8),14), ((0,8),142), ((0,8),78), ((0,9),253), ((96,7),256),
+ ((0,8),81), ((0,8),17), ((85,8),131), ((82,7),31), ((0,8),113),
+ ((0,8),49), ((0,9),195), ((80,7),10), ((0,8),97), ((0,8),33),
+ ((0,9),163), ((0,8),1), ((0,8),129), ((0,8),65), ((0,9),227),
+ ((80,7),6), ((0,8),89), ((0,8),25), ((0,9),147), ((83,7),59),
+ ((0,8),121), ((0,8),57), ((0,9),211), ((81,7),17), ((0,8),105),
+ ((0,8),41), ((0,9),179), ((0,8),9), ((0,8),137), ((0,8),73),
+ ((0,9),243), ((80,7),4), ((0,8),85), ((0,8),21), ((80,8),258),
+ ((83,7),43), ((0,8),117), ((0,8),53), ((0,9),203), ((81,7),13),
+ ((0,8),101), ((0,8),37), ((0,9),171), ((0,8),5), ((0,8),133),
+ ((0,8),69), ((0,9),235), ((80,7),8), ((0,8),93), ((0,8),29),
+ ((0,9),155), ((84,7),83), ((0,8),125), ((0,8),61), ((0,9),219),
+ ((82,7),23), ((0,8),109), ((0,8),45), ((0,9),187), ((0,8),13),
+ ((0,8),141), ((0,8),77), ((0,9),251), ((80,7),3), ((0,8),83),
+ ((0,8),19), ((85,8),195), ((83,7),35), ((0,8),115), ((0,8),51),
+ ((0,9),199), ((81,7),11), ((0,8),99), ((0,8),35), ((0,9),167),
+ ((0,8),3), ((0,8),131), ((0,8),67), ((0,9),231), ((80,7),7),
+ ((0,8),91), ((0,8),27), ((0,9),151), ((84,7),67), ((0,8),123),
+ ((0,8),59), ((0,9),215), ((82,7),19), ((0,8),107), ((0,8),43),
+ ((0,9),183), ((0,8),11), ((0,8),139), ((0,8),75), ((0,9),247),
+ ((80,7),5), ((0,8),87), ((0,8),23), ((192,8),0), ((83,7),51),
+ ((0,8),119), ((0,8),55), ((0,9),207), ((81,7),15), ((0,8),103),
+ ((0,8),39), ((0,9),175), ((0,8),7), ((0,8),135), ((0,8),71),
+ ((0,9),239), ((80,7),9), ((0,8),95), ((0,8),31), ((0,9),159),
+ ((84,7),99), ((0,8),127), ((0,8),63), ((0,9),223), ((82,7),27),
+ ((0,8),111), ((0,8),47), ((0,9),191), ((0,8),15), ((0,8),143),
+ ((0,8),79), ((0,9),255)
+ );
+
+{local}
+const
+ fixed_td : array[0..32-1] of inflate_huft = (
+(Exop:80;bits:5;base:1), (Exop:87;bits:5;base:257), (Exop:83;bits:5;base:17),
+(Exop:91;bits:5;base:4097), (Exop:81;bits:5;base), (Exop:89;bits:5;base:1025),
+(Exop:85;bits:5;base:65), (Exop:93;bits:5;base:16385), (Exop:80;bits:5;base:3),
+(Exop:88;bits:5;base:513), (Exop:84;bits:5;base:33), (Exop:92;bits:5;base:8193),
+(Exop:82;bits:5;base:9), (Exop:90;bits:5;base:2049), (Exop:86;bits:5;base:129),
+(Exop:192;bits:5;base:24577), (Exop:80;bits:5;base:2), (Exop:87;bits:5;base:385),
+(Exop:83;bits:5;base:25), (Exop:91;bits:5;base:6145), (Exop:81;bits:5;base:7),
+(Exop:89;bits:5;base:1537), (Exop:85;bits:5;base:97), (Exop:93;bits:5;base:24577),
+(Exop:80;bits:5;base:4), (Exop:88;bits:5;base:769), (Exop:84;bits:5;base:49),
+(Exop:92;bits:5;base:12289), (Exop:82;bits:5;base:13), (Exop:90;bits:5;base:3073),
+(Exop:86;bits:5;base:193), (Exop:192;bits:5;base:24577)
+ );
+{$ENDIF}
+
+function inflate_trees_fixed(
+var bl : cardinal; { literal desired/actual bit depth }
+var bd : cardinal; { distance desired/actual bit depth }
+var tl : pInflate_huft; { literal/length tree result }
+var td : pInflate_huft; { distance tree result }
+var z : z_stream { for memory allocation }
+ ) : integer;
+type
+ pFixed_table = ^fixed_table;
+ fixed_table = array[0..288-1] of cardinal;
+var
+ k : integer; { temporary variable }
+ c : pFixed_table; { length list for huft_build }
+ v : Pcardinalarray; { work area for huft_build }
+var
+ f : cardinal; { number of hufts used in fixed_mem }
+begin
+ { build fixed tables if not already (multiple overlapped executions ok) }
+ if not fixed_built then
+ begin
+ f := 0;
+
+ { allocate memory }
+ getmem(c,288*sizeof(cardinal));
+ if (c = nil) then
+ begin
+ inflate_trees_fixed := Z_MEM_ERROR;
+ exit;
+ end;
+ getmem(v,288*sizeof(cardinal));
+ if (v = nil) then
+ begin
+ freemem(c);
+ inflate_trees_fixed := Z_MEM_ERROR;
+ exit;
+ end;
+
+ { literal table }
+ for k := 0 to Pred(144) do
+ c^[k] := 8;
+ for k := 144 to Pred(256) do
+ c^[k] := 9;
+ for k := 256 to Pred(280) do
+ c^[k] := 7;
+ for k := 280 to Pred(288) do
+ c^[k] := 8;
+ fixed_bl := 9;
+ huft_build(c^, 288, 257, cplens, cplext, @fixed_tl, fixed_bl,
+ fixed_mem, f, v^);
+
+ { distance table }
+ for k := 0 to Pred(30) do
+ c^[k] := 5;
+ fixed_bd := 5;
+ huft_build(c^, 30, 0, cpdist, cpdext, @fixed_td, fixed_bd,
+ fixed_mem, f, v^);
+
+ { done }
+ freemem(v);
+ freemem(c);
+ fixed_built := True;
+ end;
+ bl := fixed_bl;
+ bd := fixed_bd;
+ tl := fixed_tl;
+ td := fixed_td;
+ inflate_trees_fixed := Z_OK;
+end; { inflate_trees_fixed }
+
+
+end.
diff --git a/packages/paszlib/src/infutil.pas b/packages/paszlib/src/infutil.pas
new file mode 100644
index 0000000000..de0b165609
--- /dev/null
+++ b/packages/paszlib/src/infutil.pas
@@ -0,0 +1,222 @@
+Unit infutil;
+
+{ types and macros common to blocks and codes
+ Copyright (C) 1995-1998 Mark Adler
+
+ WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change.
+
+ Pascal tranlastion
+ Copyright (C) 1998 by Jacques Nomssi Nzali
+ For conditions of distribution and use, see copyright notice in readme.txt
+}
+
+interface
+
+{$I zconf.inc}
+
+uses
+ zbase;
+
+{ copy as much as possible from the sliding window to the output area }
+function inflate_flush(var s : inflate_blocks_state;
+ var z : z_stream;
+ r : integer) : integer;
+
+{ And'ing with mask[n] masks the lower n bits }
+const
+ inflate_mask : array[0..17-1] of cardinal = (
+ $0000,
+ $0001, $0003, $0007, $000f, $001f, $003f, $007f, $00ff,
+ $01ff, $03ff, $07ff, $0fff, $1fff, $3fff, $7fff, $ffff);
+
+{procedure GRABBITS(j : integer);}
+{procedure DUMPBITS(j : integer);}
+{procedure NEEDBITS(j : integer);}
+
+implementation
+
+{ macros for bit input with no checking and for returning unused bytes }
+procedure GRABBITS(j : integer);
+begin
+ {while (k < j) do
+ begin
+ dec(z^.avail_in);
+ inc(z^.total_in);
+ b := b or (uLong(z^.next_in^) shl k);
+ inc(z^.next_in);
+ inc(k, 8);
+ end;}
+end;
+
+procedure DUMPBITS(j : integer);
+begin
+ {b := b shr j;
+ dec(k, j);}
+end;
+
+procedure NEEDBITS(j : integer);
+begin
+ (*
+ while (k < j) do
+ begin
+ {NEEDBYTE;}
+ if (n <> 0) then
+ r :=Z_OK
+ else
+ begin
+ {UPDATE}
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ inc(z.total_in, LongInt(p)-LongInt(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ result := inflate_flush(s,z,r);
+ exit;
+ end;
+ dec(n);
+ b := b or (uLong(p^) shl k);
+ inc(p);
+ inc(k, 8);
+ end;
+ *)
+end;
+
+procedure NEEDOUT;
+begin
+ (*
+ if (m = 0) then
+ begin
+ {WRAP}
+ if (q = s.zend) and (s.read <> s.window) then
+ begin
+ q := s.window;
+ if LongInt(q) < LongInt(s.read) then
+ m := cardinal(LongInt(s.read)-LongInt(q)-1)
+ else
+ m := cardinal(LongInt(s.zend)-LongInt(q));
+ end;
+
+ if (m = 0) then
+ begin
+ {FLUSH}
+ s.write := q;
+ r := inflate_flush(s,z,r);
+ q := s.write;
+ if LongInt(q) < LongInt(s.read) then
+ m := cardinal(LongInt(s.read)-LongInt(q)-1)
+ else
+ m := cardinal(LongInt(s.zend)-LongInt(q));
+
+ {WRAP}
+ if (q = s.zend) and (s.read <> s.window) then
+ begin
+ q := s.window;
+ if LongInt(q) < LongInt(s.read) then
+ m := cardinal(LongInt(s.read)-LongInt(q)-1)
+ else
+ m := cardinal(LongInt(s.zend)-LongInt(q));
+ end;
+
+ if (m = 0) then
+ begin
+ {UPDATE}
+ s.bitb := b;
+ s.bitk := k;
+ z.avail_in := n;
+ inc(z.total_in, LongInt(p)-LongInt(z.next_in));
+ z.next_in := p;
+ s.write := q;
+ result := inflate_flush(s,z,r);
+ exit;
+ end;
+ end;
+ end;
+ r := Z_OK;
+ *)
+end;
+
+{ copy as much as possible from the sliding window to the output area }
+function inflate_flush(var s : inflate_blocks_state;
+ var z : z_stream;
+ r : integer) : integer;
+var
+ n : cardinal;
+ p : Pbyte;
+ q : Pbyte;
+begin
+ { local copies of source and destination pointers }
+ p := z.next_out;
+ q := s.read;
+
+ { compute number of bytes to copy as far as end of window }
+ if ptruint(q) <= ptruint(s.write) then
+ n := cardinal(ptruint(s.write) - ptruint(q))
+ else
+ n := cardinal(ptruint(s.zend) - ptruint(q));
+ if (n > z.avail_out) then
+ n := z.avail_out;
+ if (n <> 0) and (r = Z_BUF_ERROR) then
+ r := Z_OK;
+
+ { update counters }
+ dec(z.avail_out, n);
+ inc(z.total_out, n);
+
+
+ { update check information }
+ if Assigned(s.checkfn) then
+ begin
+ s.check := s.checkfn(s.check, q, n);
+ z.adler := s.check;
+ end;
+
+ { copy as far as end of window }
+ move(q^,p^,n);
+ inc(p, n);
+ inc(q, n);
+
+ { see if more to copy at beginning of window }
+ if (q = s.zend) then
+ begin
+ { wrap pointers }
+ q := s.window;
+ if (s.write = s.zend) then
+ s.write := s.window;
+
+ { compute bytes to copy }
+ n := cardinal(ptruint(s.write) - ptruint(q));
+ if (n > z.avail_out) then
+ n := z.avail_out;
+ if (n <> 0) and (r = Z_BUF_ERROR) then
+ r := Z_OK;
+
+ { update counters }
+ dec( z.avail_out, n);
+ inc( z.total_out, n);
+
+ { update check information }
+ if Assigned(s.checkfn) then
+ begin
+ s.check := s.checkfn(s.check, q, n);
+ z.adler := s.check;
+ end;
+
+ { copy }
+ move(q^,p^,n);
+ inc(p, n);
+ inc(q, n);
+ end;
+
+
+ { update pointers }
+ z.next_out := p;
+ s.read := q;
+
+ { done }
+ inflate_flush := r;
+end;
+
+end.
diff --git a/packages/paszlib/src/paszlib.pas b/packages/paszlib/src/paszlib.pas
new file mode 100644
index 0000000000..d949e861fe
--- /dev/null
+++ b/packages/paszlib/src/paszlib.pas
@@ -0,0 +1,338 @@
+unit paszlib;
+
+{$inline on}
+
+interface
+
+uses
+ zbase;
+
+const
+ ZLIB_VERSION = '1.2';
+
+type
+ { Compatibility types }
+ z_off_t = longint;
+
+ TInternalState = record
+ end;
+ PInternalState = ^TInternalstate;
+
+ TZStream = z_stream;
+ PZstream = ^TZStream;
+
+ gzFile = pointer;
+
+
+const
+ Z_NO_FLUSH = 0;
+
+ Z_PARTIAL_FLUSH = 1;
+ Z_SYNC_FLUSH = 2;
+ Z_FULL_FLUSH = 3;
+ Z_FINISH = 4;
+
+ Z_OK = 0;
+ Z_STREAM_END = 1;
+ Z_NEED_DICT = 2;
+ Z_ERRNO = -(1);
+ Z_STREAM_ERROR = -(2);
+ Z_DATA_ERROR = -(3);
+ Z_MEM_ERROR = -(4);
+ Z_BUF_ERROR = -(5);
+ Z_VERSION_ERROR = -(6);
+
+ Z_NO_COMPRESSION = 0;
+ Z_BEST_SPEED = 1;
+ Z_BEST_COMPRESSION = 9;
+ Z_DEFAULT_COMPRESSION = -(1);
+
+ Z_FILTERED = 1;
+ Z_HUFFMAN_ONLY = 2;
+ Z_DEFAULT_STRATEGY = 0;
+
+ Z_BINARY = 0;
+ Z_ASCII = 1;
+ Z_UNKNOWN = 2;
+
+ Z_DEFLATED = 8;
+
+ Z_NULL = nil;
+
+function zlibVersion:string;inline;
+function deflate(var strm:TZstream; flush:longint):longint;inline;
+function deflateEnd(var strm:TZstream):longint;inline;
+function inflate(var strm:TZstream; flush:longint):longint;inline;
+function inflateEnd(var strm:TZstream):longint;inline;
+function deflateSetDictionary(var strm:TZstream;dictionary : Pchar; dictLength:cardinal):longint;inline;
+function deflateCopy(var dest,source:TZstream):longint;inline;
+function deflateReset(var strm:TZstream):longint;inline;
+function deflateParams(var strm:TZstream; level:longint; strategy:longint):longint;inline;
+function inflateSetDictionary(var strm:TZStream;dictionary : Pchar; dictLength:cardinal):longint;inline;
+function inflateSync(var strm:TZStream):longint;inline;
+function inflateReset(var strm:TZStream):longint;inline;
+function compress(dest:Pchar;var destLen:cardinal; source : Pchar; sourceLen:cardinal):longint;
+function compress2(dest:Pchar;var destLen:cardinal; source : Pchar; sourceLen:cardinal; level:longint):longint;
+function uncompress(dest:Pchar;var destLen:cardinal; source : Pchar; sourceLen:cardinal):longint;
+function gzopen(path:Pchar; mode:Pchar):gzFile;inline;
+function gzsetparams(Thefile:gzFile; level:longint; strategy:longint):longint;inline;
+function gzread(thefile:gzFile; buf : pointer; len:cardinal):longint;inline;
+function gzwrite(thefile:gzFile; buf: pointer; len:cardinal):longint;inline;
+function gzputs(thefile:gzFile; s:Pchar):longint;inline;
+function gzgets(thefile:gzFile; buf:Pchar; len:longint):Pchar;inline;
+function gzputc(thefile:gzFile; c:char):longint;inline;
+function gzgetc(thefile:gzFile):char;inline;
+function gzflush(thefile:gzFile; flush:longint):longint;inline;
+function gzseek(thefile:gzFile; offset:z_off_t; whence:longint):z_off_t;inline;
+function gzrewind(thefile:gzFile):longint;inline;
+function gztell(thefile:gzFile):z_off_t;inline;
+function gzeof(thefile:gzFile):longbool;inline;
+function gzclose(thefile:gzFile):longint;inline;
+function gzerror(thefile:gzFile; var errnum:smallint):string;inline;
+function adler32(theadler:cardinal;buf : Pchar; len:cardinal):cardinal;inline;
+function crc32(thecrc:cardinal;buf : Pchar; len:cardinal):cardinal;inline;
+function deflateInit_(var strm:TZStream; level:longint; version:Pchar; stream_size:longint):longint;inline;
+function inflateInit_(var strm:TZStream; version:Pchar; stream_size:longint):longint;inline;
+function deflateInit2_(var strm:TZStream; level:longint; method:longint; windowBits:longint; memLevel:longint;strategy:longint; version:Pchar; stream_size:longint):longint;inline;
+function inflateInit2_(var strm:TZStream; windowBits:longint; version:Pchar; stream_size:longint):longint;inline;
+function deflateInit(var strm:TZStream;level : longint) : longint;inline;
+function inflateInit(var strm:TZStream) : longint;inline;
+function deflateInit2(var strm:TZStream;level,method,windowBits,memLevel,strategy : longint) : longint;inline;
+function inflateInit2(var strm:TZStream; windowBits : longint) : longint;inline;
+function zError(err:longint):string;inline;
+function inflateSyncPoint(z:PZstream):longint;inline;
+function get_crc_table:pointer;inline;
+
+implementation
+
+uses
+ zdeflate,zinflate,zcompres,zuncompr,gzio,adler,crc;
+
+function zlibVersion:string;inline;
+begin
+ zlibversion:=zbase.zlibversion;
+end;
+
+function deflate(var strm:TZstream; flush:longint):longint;inline;
+begin
+ deflate:=zdeflate.deflate(strm,flush);
+end;
+
+function deflateEnd(var strm:TZstream):longint;inline;
+begin
+ deflateEnd:=zdeflate.deflateEnd(strm);
+end;
+
+function inflate(var strm:TZstream; flush:longint):longint;inline;
+begin
+ inflate:=zinflate.inflate(strm,flush);
+end;
+
+function inflateEnd(var strm:TZstream):longint;inline;
+begin
+ inflateEnd:=zinflate.inflateEnd(strm);
+end;
+
+function deflateSetDictionary(var strm:TZstream;dictionary : Pchar; dictLength:cardinal):longint;inline;
+begin
+ deflateSetDictionary:=zdeflate.deflateSetDictionary(strm,Pbyte(dictionary),dictlength);
+end;
+
+function deflateCopy(var dest,source:TZstream):longint;inline;
+begin
+ deflateCopy:=zdeflate.deflateCopy(@dest,@source);
+end;
+
+function deflateReset(var strm:TZstream):longint;inline;
+begin
+ deflateReset:=zdeflate.deflateReset(strm);
+end;
+
+function deflateParams(var strm:TZstream; level:longint; strategy:longint):longint;inline;
+begin
+ deflateParams:=zdeflate.deflateParams(strm,level,strategy);
+end;
+
+function inflateSetDictionary(var strm:TZStream;dictionary : Pchar; dictLength:cardinal):longint;inline;
+begin
+ inflateSetDictionary:=zinflate.inflateSetDictionary(strm,Pbyte(dictionary),dictlength);
+end;
+
+function inflateSync(var strm:TZStream):longint;inline;
+begin
+ inflateSync:=zinflate.inflateSync(strm);
+end;
+
+function inflateReset(var strm:TZStream):longint;inline;
+begin
+ inflateReset:=zinflate.inflateReset(strm);
+end;
+
+function compress(dest:Pchar;var destLen:cardinal; source : Pchar; sourceLen:cardinal):longint;
+
+type Pbytearray=^Tbytearray;
+ Tbytearray=array[0..0] of byte;
+
+begin
+ compress:=zcompres.compress(Pbyte(dest),destlen,Pbytearray(source)^,sourcelen);
+end;
+
+function compress2(dest:Pchar;var destLen:cardinal; source : Pchar; sourceLen:cardinal; level:longint):longint;
+
+type Pbytearray=^Tbytearray;
+ Tbytearray=array[0..0] of byte;
+
+begin
+ compress2:=zcompres.compress2(Pbyte(dest),destlen,Pbytearray(source)^,sourcelen,level);
+end;
+
+function uncompress(dest:Pchar;var destLen:cardinal; source : Pchar; sourceLen:cardinal):longint;
+
+type Pbytearray=^Tbytearray;
+ Tbytearray=array[0..0] of byte;
+
+begin
+ uncompress:=zuncompr.uncompress(Pbyte(dest),destlen,Pbytearray(source)^,sourcelen);
+end;
+
+function gzopen(path:Pchar; mode:Pchar):gzFile;inline;
+begin
+ gzopen:=gzio.gzopen(path,mode);
+end;
+
+function gzsetparams(Thefile:gzFile; level:longint; strategy:longint):longint;inline;
+begin
+ gzsetparams:=gzio.gzsetparams(thefile,level,strategy);
+end;
+
+function gzread(thefile:gzFile; buf : pointer; len:cardinal):longint;inline;
+begin
+ gzread:=gzio.gzread(thefile,buf,len);
+end;
+
+function gzwrite(thefile:gzFile; buf: pointer; len:cardinal):longint;inline;
+begin
+ gzwrite:=gzio.gzwrite(thefile,buf,len);
+end;
+
+function gzputs(thefile:gzFile; s:Pchar):longint;inline;
+begin
+ gzputs:=gzio.gzputs(thefile,s);
+end;
+
+function gzgets(thefile:gzFile; buf:Pchar; len:longint):Pchar;inline;
+begin
+ gzgets:=gzio.gzgets(thefile,buf,len);
+end;
+
+function gzputc(thefile:gzFile; c:char):longint;inline;
+begin
+ gzputc:=gzio.gzputc(thefile,c);
+end;
+
+function gzgetc(thefile:gzFile):char;inline;
+begin
+ gzgetc:=chr(gzio.gzgetc(thefile));
+end;
+
+function gzflush(thefile:gzFile; flush:longint):longint;inline;
+begin
+ gzflush:=gzio.gzflush(thefile,flush);
+end;
+
+function gzseek(thefile:gzFile; offset:z_off_t; whence:longint):z_off_t;inline;
+begin
+ gzseek:=gzio.gzseek(thefile,offset,whence);
+end;
+
+function gzrewind(thefile:gzFile):longint;inline;
+begin
+ gzrewind:=gzio.gzrewind(thefile);
+end;
+
+function gztell(thefile:gzFile):z_off_t;inline;
+begin
+ gztell:=gzio.gztell(thefile);
+end;
+
+function gzeof(thefile:gzFile):longbool;inline;
+begin
+ gzeof:=gzio.gzeof(thefile);
+end;
+
+function gzclose(thefile:gzFile):longint;inline;
+begin
+ gzclose:=gzio.gzclose(thefile);
+end;
+
+function gzerror(thefile:gzFile; var errnum:smallint):string;inline;
+begin
+ gzerror:=gzio.gzerror(thefile,errnum);
+end;
+
+function adler32(theadler:cardinal;buf : Pchar; len:cardinal):cardinal;inline;
+begin
+ adler32:=adler.adler32(theadler,Pbyte(buf),len);
+end;
+
+function crc32(thecrc:cardinal;buf : Pchar; len:cardinal):cardinal;inline;
+begin
+ crc32:=crc.crc32(thecrc,Pbyte(buf),len);
+end;
+
+function deflateInit_(var strm:TZStream; level:longint; version:Pchar; stream_size:longint):longint;inline;
+begin
+ deflateInit_:=zdeflate.deflateInit_(@strm,level,version,stream_size);
+end;
+
+function inflateInit_(var strm:TZStream; version:Pchar; stream_size:longint):longint;inline;
+begin
+ inflateInit_:=zinflate.inflateInit_(@strm,version,stream_size);
+end;
+
+function deflateInit2_(var strm:TZStream; level:longint; method:longint; windowBits:longint; memLevel:longint;strategy:longint; version:Pchar; stream_size:longint):longint;inline;
+begin
+ deflateInit2_:=zdeflate.deflateInit2_(strm,level,method,windowBits,memlevel,strategy,version,stream_size);
+end;
+
+function inflateInit2_(var strm:TZStream; windowBits:longint; version:Pchar; stream_size:longint):longint;inline;
+begin
+ inflateInit2_:=zinflate.inflateInit2_(strm,windowBits,version,stream_size);
+end;
+
+function deflateInit(var strm:TZStream;level : longint) : longint;inline;
+begin
+ deflateInit:=zdeflate.deflateInit(strm,level);
+end;
+
+function inflateInit(var strm:TZStream) : longint;inline;
+begin
+ inflateInit:=zinflate.inflateInit(strm);
+end;
+
+function deflateInit2(var strm:TZStream;level,method,windowBits,memLevel,strategy : longint) : longint;inline;
+begin
+ deflateInit2:=zdeflate.deflateInit2(strm,level,method,windowbits,memlevel,strategy);
+end;
+
+function inflateInit2(var strm:TZStream; windowBits : longint) : longint;inline;
+begin
+ inflateInit2:=zinflate.inflateInit2_(strm,windowBits,ZLIB_VERSION,sizeof(TZStream));
+end;
+
+function zError(err:longint):string;inline;
+begin
+ zerror:=zbase.zerror(err);
+end;
+
+function inflateSyncPoint(z:PZstream):longint;inline;
+begin
+ inflateSyncPoint:=zinflate.inflateSyncPoint(z^);
+end;
+
+function get_crc_table:pointer;inline;
+begin
+ get_crc_table:=crc.get_crc_table;
+end;
+
+end.
diff --git a/packages/paszlib/src/trees.pas b/packages/paszlib/src/trees.pas
new file mode 100644
index 0000000000..5ac1e3c80b
--- /dev/null
+++ b/packages/paszlib/src/trees.pas
@@ -0,0 +1,2204 @@
+unit trees;
+
+{$T-}
+{$define ORG_DEBUG}
+{
+ trees.c -- output deflated data using Huffman coding
+ Copyright (C) 1995-1998 Jean-loup Gailly
+
+ Pascal tranlastion
+ Copyright (C) 1998 by Jacques Nomssi Nzali
+ For conditions of distribution and use, see copyright notice in readme.txt
+}
+
+{
+ * ALGORITHM
+ *
+ * The "deflation" process uses several Huffman trees. The more
+ * common source values are represented by shorter bit sequences.
+ *
+ * Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values). The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ * Storer, James A.
+ * Data Compression: Methods and Theory, pp. 49-50.
+ * Computer Science Press, 1988. ISBN 0-7167-8156-5.
+ *
+ * Sedgewick, R.
+ * Algorithms, p290.
+ * Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ }
+
+interface
+
+{$I zconf.inc}
+
+uses
+ {$ifdef ZLIB_DEBUG}
+ sysutils,
+ {$endif}
+ zbase
+ ;
+
+{ ===========================================================================
+ Internal compression state. }
+
+const
+ LENGTH_CODES = 29;
+{ number of length codes, not counting the special END_BLOCK code }
+
+ LITERALS = 256;
+{ number of literal bytes 0..255 }
+
+ L_CODES = (LITERALS+1+LENGTH_CODES);
+{ number of Literal or Length codes, including the END_BLOCK code }
+
+ D_CODES = 30;
+{ number of distance codes }
+
+ BL_CODES = 19;
+{ number of codes used to transfer the bit lengths }
+
+ HEAP_SIZE = (2*L_CODES+1);
+{ maximum heap size }
+
+ MAX_BITS = 15;
+{ All codes must not exceed MAX_BITS bits }
+
+const
+ INIT_STATE = 42;
+ BUSY_STATE = 113;
+ FINISH_STATE = 666;
+{ Stream status }
+
+
+{ Data structure describing a single value and its code string. }
+type
+ ct_data_ptr = ^ct_data;
+ ct_data = record
+ fc : record
+ case byte of
+ 0:(freq : word); { frequency count }
+ 1:(code : word); { bit string }
+ end;
+ dl : record
+ case byte of
+ 0:(dad : word); { father node in Huffman tree }
+ 1:(len : word); { length of bit string }
+ end;
+ end;
+
+{ Freq = fc.freq
+ Code = fc.code
+ Dad = dl.dad
+ Len = dl.len }
+
+type
+ ltree_type = array[0..HEAP_SIZE-1] of ct_data; { literal and length tree }
+ dtree_type = array[0..2*D_CODES+1-1] of ct_data; { distance tree }
+ htree_type = array[0..2*BL_CODES+1-1] of ct_data; { Huffman tree for bit lengths }
+ { generic tree type }
+ tree_type = array[0..(maxint div SizeOf(ct_data))-1] of ct_data;
+
+ tree_ptr = ^ct_data;
+ ltree_ptr = ^ltree_type;
+ dtree_ptr = ^dtree_type;
+ htree_ptr = ^htree_type;
+
+
+type
+ static_tree_desc_ptr = ^static_tree_desc;
+ static_tree_desc =
+ record
+ {const} static_tree : tree_ptr; { static tree or NIL }
+ {const} extra_bits : pinteger; { extra bits for each code or NIL }
+ extra_base : integer; { base index for extra_bits }
+ elems : integer; { max number of elements in the tree }
+ max_length : integer; { max bit length for the codes }
+ end;
+
+ tree_desc_ptr = ^tree_desc;
+ tree_desc = record
+ dyn_tree : tree_ptr; { the dynamic tree }
+ max_code : integer; { largest code with non zero frequency }
+ stat_desc : static_tree_desc_ptr; { the corresponding static tree }
+ end;
+
+type
+ Pos = word;
+ Posf = Pos; {FAR}
+ IPos = cardinal;
+
+ pPosf = ^Posf;
+
+ zPosfArray = array[0..(maxint div SizeOf(Posf))-1] of Posf;
+ pzPosfArray = ^zPosfArray;
+
+{ A Pos is an index in the character window. We use short instead of integer to
+ save space in the various tables. IPos is used only for parameter passing.}
+
+type
+ deflate_state_ptr = ^deflate_state;
+ deflate_state = record
+ strm : z_streamp; { pointer back to this zlib stream }
+ status : integer; { as the name implies }
+ pending_buf : Pbytearray; { output still pending }
+ pending_buf_size : longint; { size of pending_buf }
+ pending_out : Pbyte; { next pending byte to output to the stream }
+ pending : integer; { nb of bytes in the pending buffer }
+ noheader : integer; { suppress zlib header and adler32 }
+ data_type : Byte; { UNKNOWN, BINARY or ASCII }
+ method : Byte; { STORED (for zip only) or DEFLATED }
+ last_flush : integer; { value of flush param for previous deflate call }
+
+ { used by deflate.pas: }
+
+ w_size : cardinal; { LZ77 window size (32K by default) }
+ w_bits : cardinal; { log2(w_size) (8..16) }
+ w_mask : cardinal; { w_size - 1 }
+
+ window : Pbytearray;
+ { Sliding window. Input bytes are read into the second half of the window,
+ and move to the first half later to keep a dictionary of at least wSize
+ bytes. With this organization, matches are limited to a distance of
+ wSize-MAX_MATCH bytes, but this ensures that IO is always
+ performed with a length multiple of the block size. Also, it limits
+ the window size to 64K, which is quite useful on MSDOS.
+ To do: use the user input buffer as sliding window. }
+
+ window_size : longint;
+ { Actual size of window: 2*wSize, except when the user input buffer
+ is directly used as sliding window. }
+
+ prev : pzPosfArray;
+ { Link to older string with same hash index. To limit the size of this
+ array to 64K, this link is maintained only for the last 32K strings.
+ An index in this array is thus a window index modulo 32K. }
+
+ head : pzPosfArray; { Heads of the hash chains or NIL. }
+
+ ins_h : cardinal; { hash index of string to be inserted }
+ hash_size : cardinal; { number of elements in hash table }
+ hash_bits : cardinal; { log2(hash_size) }
+ hash_mask : cardinal; { hash_size-1 }
+
+ hash_shift : cardinal;
+ { Number of bits by which ins_h must be shifted at each input
+ step. It must be such that after MIN_MATCH steps, the oldest
+ byte no longer takes part in the hash key, that is:
+ hash_shift * MIN_MATCH >= hash_bits }
+
+ block_start : longint;
+ { Window position at the beginning of the current output block. Gets
+ negative when the window is moved backwards. }
+
+ match_length : cardinal; { length of best match }
+ prev_match : IPos; { previous match }
+ match_available : boolean; { set if previous match exists }
+ strstart : cardinal; { start of string to insert }
+ match_start : cardinal; { start of matching string }
+ lookahead : cardinal; { number of valid bytes ahead in window }
+
+ prev_length : cardinal;
+ { Length of the best match at previous step. Matches not greater than this
+ are discarded. This is used in the lazy match evaluation. }
+
+ max_chain_length : cardinal;
+ { To speed up deflation, hash chains are never searched beyond this
+ length. A higher limit improves compression ratio but degrades the
+ speed. }
+
+ { moved to the end because Borland Pascal won't accept the following:
+ max_lazy_match : cardinal;
+ max_insert_length : cardinal absolute max_lazy_match;
+ }
+
+ level : integer; { compression level (1..9) }
+ strategy : integer; { favor or force Huffman coding}
+
+ good_match : cardinal;
+ { Use a faster search when the previous match is longer than this }
+
+ nice_match : integer; { Stop searching when current match exceeds this }
+
+ { used by trees.pas: }
+ { Didn't use ct_data typedef below to supress compiler warning }
+ dyn_ltree : ltree_type; { literal and length tree }
+ dyn_dtree : dtree_type; { distance tree }
+ bl_tree : htree_type; { Huffman tree for bit lengths }
+
+ l_desc : tree_desc; { desc. for literal tree }
+ d_desc : tree_desc; { desc. for distance tree }
+ bl_desc : tree_desc; { desc. for bit length tree }
+
+ bl_count : array[0..MAX_BITS+1-1] of word;
+ { number of codes at each bit length for an optimal tree }
+
+ heap : array[0..2*L_CODES+1-1] of integer; { heap used to build the Huffman trees }
+ heap_len : integer; { number of elements in the heap }
+ heap_max : integer; { element of largest frequency }
+ { The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ The same heap array is used to build all trees. }
+
+ depth : array[0..2*L_CODES+1-1] of byte;
+ { Depth of each subtree used as tie breaker for trees of equal frequency }
+
+
+ l_buf : Pbytearray; { buffer for literals or lengths }
+
+ lit_bufsize : cardinal;
+ { Size of match buffer for literals/lengths. There are 4 reasons for
+ limiting lit_bufsize to 64K:
+ - frequencies can be kept in 16 bit counters
+ - if compression is not successful for the first block, all input
+ data is still in the window so we can still emit a stored block even
+ when input comes from standard input. (This can also be done for
+ all blocks if lit_bufsize is not greater than 32K.)
+ - if compression is not successful for a file smaller than 64K, we can
+ even emit a stored file instead of a stored block (saving 5 bytes).
+ This is applicable only for zip (not gzip or zlib).
+ - creating new Huffman trees less frequently may not provide fast
+ adaptation to changes in the input data statistics. (Take for
+ example a binary file with poorly compressible code followed by
+ a highly compressible string table.) Smaller buffer sizes give
+ fast adaptation but have of course the overhead of transmitting
+ trees more frequently.
+ - I can't count above 4 }
+
+
+ last_lit : cardinal; { running index in l_buf }
+
+ d_buf : Pwordarray;
+ { Buffer for distances. To simplify the code, d_buf and l_buf have
+ the same number of elements. To use different lengths, an extra flag
+ array would be necessary. }
+
+ opt_len : longint; { bit length of current block with optimal trees }
+ static_len : longint; { bit length of current block with static trees }
+ compressed_len : longint; { total bit length of compressed file }
+ matches : cardinal; { number of string matches in current block }
+ last_eob_len : integer; { bit length of EOB code for last block }
+
+{$ifdef ZLIB_DEBUG}
+ bits_sent : longint; { bit length of the compressed data }
+{$endif}
+
+ bi_buf : word;
+ { Output buffer. bits are inserted starting at the bottom (least
+ significant bits). }
+
+ bi_valid : integer;
+ { Number of valid bits in bi_buf. All bits above the last valid bit
+ are always zero. }
+
+ case byte of
+ 0:(max_lazy_match : cardinal);
+ { Attempt to find a better match only when the current match is strictly
+ smaller than this value. This mechanism is used only for compression
+ levels >= 4. }
+
+ 1:(max_insert_length : cardinal);
+ { Insert new strings in the hash table only if the match length is not
+ greater than this length. This saves time but degrades compression.
+ max_insert_length is used only for compression levels <= 3. }
+ end;
+
+procedure _tr_init (var s : deflate_state);
+
+function _tr_tally (var s : deflate_state;
+ dist : cardinal;
+ lc : cardinal) : boolean;
+
+function _tr_flush_block (var s : deflate_state;
+ buf : Pbyte;
+ stored_len : longint;
+ eof : boolean) : longint;
+
+procedure _tr_align(var s : deflate_state);
+
+procedure _tr_stored_block(var s : deflate_state;
+ buf : Pbyte;
+ stored_len : longint;
+ eof : boolean);
+
+implementation
+
+{ #define GEN_TREES_H }
+
+{$ifndef GEN_TREES_H}
+{ header created automatically with -DGEN_TREES_H }
+
+const
+ DIST_CODE_LEN = 512; { see definition of array dist_code below }
+
+{ The static literal tree. Since the bit lengths are imposed, there is no
+ need for the L_CODES extra codes used during heap construction. However
+ The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ below). }
+const
+ static_ltree : array[0..L_CODES+2-1] of ct_data = (
+{ fc:(freq, code) dl:(dad,len) }
+(fc:(freq: 12);dl:(len: 8)), (fc:(freq:140);dl:(len: 8)), (fc:(freq: 76);dl:(len: 8)),
+(fc:(freq:204);dl:(len: 8)), (fc:(freq: 44);dl:(len: 8)), (fc:(freq:172);dl:(len: 8)),
+(fc:(freq:108);dl:(len: 8)), (fc:(freq:236);dl:(len: 8)), (fc:(freq: 28);dl:(len: 8)),
+(fc:(freq:156);dl:(len: 8)), (fc:(freq: 92);dl:(len: 8)), (fc:(freq:220);dl:(len: 8)),
+(fc:(freq: 60);dl:(len: 8)), (fc:(freq:188);dl:(len: 8)), (fc:(freq:124);dl:(len: 8)),
+(fc:(freq:252);dl:(len: 8)), (fc:(freq: 2);dl:(len: 8)), (fc:(freq:130);dl:(len: 8)),
+(fc:(freq: 66);dl:(len: 8)), (fc:(freq:194);dl:(len: 8)), (fc:(freq: 34);dl:(len: 8)),
+(fc:(freq:162);dl:(len: 8)), (fc:(freq: 98);dl:(len: 8)), (fc:(freq:226);dl:(len: 8)),
+(fc:(freq: 18);dl:(len: 8)), (fc:(freq:146);dl:(len: 8)), (fc:(freq: 82);dl:(len: 8)),
+(fc:(freq:210);dl:(len: 8)), (fc:(freq: 50);dl:(len: 8)), (fc:(freq:178);dl:(len: 8)),
+(fc:(freq:114);dl:(len: 8)), (fc:(freq:242);dl:(len: 8)), (fc:(freq: 10);dl:(len: 8)),
+(fc:(freq:138);dl:(len: 8)), (fc:(freq: 74);dl:(len: 8)), (fc:(freq:202);dl:(len: 8)),
+(fc:(freq: 42);dl:(len: 8)), (fc:(freq:170);dl:(len: 8)), (fc:(freq:106);dl:(len: 8)),
+(fc:(freq:234);dl:(len: 8)), (fc:(freq: 26);dl:(len: 8)), (fc:(freq:154);dl:(len: 8)),
+(fc:(freq: 90);dl:(len: 8)), (fc:(freq:218);dl:(len: 8)), (fc:(freq: 58);dl:(len: 8)),
+(fc:(freq:186);dl:(len: 8)), (fc:(freq:122);dl:(len: 8)), (fc:(freq:250);dl:(len: 8)),
+(fc:(freq: 6);dl:(len: 8)), (fc:(freq:134);dl:(len: 8)), (fc:(freq: 70);dl:(len: 8)),
+(fc:(freq:198);dl:(len: 8)), (fc:(freq: 38);dl:(len: 8)), (fc:(freq:166);dl:(len: 8)),
+(fc:(freq:102);dl:(len: 8)), (fc:(freq:230);dl:(len: 8)), (fc:(freq: 22);dl:(len: 8)),
+(fc:(freq:150);dl:(len: 8)), (fc:(freq: 86);dl:(len: 8)), (fc:(freq:214);dl:(len: 8)),
+(fc:(freq: 54);dl:(len: 8)), (fc:(freq:182);dl:(len: 8)), (fc:(freq:118);dl:(len: 8)),
+(fc:(freq:246);dl:(len: 8)), (fc:(freq: 14);dl:(len: 8)), (fc:(freq:142);dl:(len: 8)),
+(fc:(freq: 78);dl:(len: 8)), (fc:(freq:206);dl:(len: 8)), (fc:(freq: 46);dl:(len: 8)),
+(fc:(freq:174);dl:(len: 8)), (fc:(freq:110);dl:(len: 8)), (fc:(freq:238);dl:(len: 8)),
+(fc:(freq: 30);dl:(len: 8)), (fc:(freq:158);dl:(len: 8)), (fc:(freq: 94);dl:(len: 8)),
+(fc:(freq:222);dl:(len: 8)), (fc:(freq: 62);dl:(len: 8)), (fc:(freq:190);dl:(len: 8)),
+(fc:(freq:126);dl:(len: 8)), (fc:(freq:254);dl:(len: 8)), (fc:(freq: 1);dl:(len: 8)),
+(fc:(freq:129);dl:(len: 8)), (fc:(freq: 65);dl:(len: 8)), (fc:(freq:193);dl:(len: 8)),
+(fc:(freq: 33);dl:(len: 8)), (fc:(freq:161);dl:(len: 8)), (fc:(freq: 97);dl:(len: 8)),
+(fc:(freq:225);dl:(len: 8)), (fc:(freq: 17);dl:(len: 8)), (fc:(freq:145);dl:(len: 8)),
+(fc:(freq: 81);dl:(len: 8)), (fc:(freq:209);dl:(len: 8)), (fc:(freq: 49);dl:(len: 8)),
+(fc:(freq:177);dl:(len: 8)), (fc:(freq:113);dl:(len: 8)), (fc:(freq:241);dl:(len: 8)),
+(fc:(freq: 9);dl:(len: 8)), (fc:(freq:137);dl:(len: 8)), (fc:(freq: 73);dl:(len: 8)),
+(fc:(freq:201);dl:(len: 8)), (fc:(freq: 41);dl:(len: 8)), (fc:(freq:169);dl:(len: 8)),
+(fc:(freq:105);dl:(len: 8)), (fc:(freq:233);dl:(len: 8)), (fc:(freq: 25);dl:(len: 8)),
+(fc:(freq:153);dl:(len: 8)), (fc:(freq: 89);dl:(len: 8)), (fc:(freq:217);dl:(len: 8)),
+(fc:(freq: 57);dl:(len: 8)), (fc:(freq:185);dl:(len: 8)), (fc:(freq:121);dl:(len: 8)),
+(fc:(freq:249);dl:(len: 8)), (fc:(freq: 5);dl:(len: 8)), (fc:(freq:133);dl:(len: 8)),
+(fc:(freq: 69);dl:(len: 8)), (fc:(freq:197);dl:(len: 8)), (fc:(freq: 37);dl:(len: 8)),
+(fc:(freq:165);dl:(len: 8)), (fc:(freq:101);dl:(len: 8)), (fc:(freq:229);dl:(len: 8)),
+(fc:(freq: 21);dl:(len: 8)), (fc:(freq:149);dl:(len: 8)), (fc:(freq: 85);dl:(len: 8)),
+(fc:(freq:213);dl:(len: 8)), (fc:(freq: 53);dl:(len: 8)), (fc:(freq:181);dl:(len: 8)),
+(fc:(freq:117);dl:(len: 8)), (fc:(freq:245);dl:(len: 8)), (fc:(freq: 13);dl:(len: 8)),
+(fc:(freq:141);dl:(len: 8)), (fc:(freq: 77);dl:(len: 8)), (fc:(freq:205);dl:(len: 8)),
+(fc:(freq: 45);dl:(len: 8)), (fc:(freq:173);dl:(len: 8)), (fc:(freq:109);dl:(len: 8)),
+(fc:(freq:237);dl:(len: 8)), (fc:(freq: 29);dl:(len: 8)), (fc:(freq:157);dl:(len: 8)),
+(fc:(freq: 93);dl:(len: 8)), (fc:(freq:221);dl:(len: 8)), (fc:(freq: 61);dl:(len: 8)),
+(fc:(freq:189);dl:(len: 8)), (fc:(freq:125);dl:(len: 8)), (fc:(freq:253);dl:(len: 8)),
+(fc:(freq: 19);dl:(len: 9)), (fc:(freq:275);dl:(len: 9)), (fc:(freq:147);dl:(len: 9)),
+(fc:(freq:403);dl:(len: 9)), (fc:(freq: 83);dl:(len: 9)), (fc:(freq:339);dl:(len: 9)),
+(fc:(freq:211);dl:(len: 9)), (fc:(freq:467);dl:(len: 9)), (fc:(freq: 51);dl:(len: 9)),
+(fc:(freq:307);dl:(len: 9)), (fc:(freq:179);dl:(len: 9)), (fc:(freq:435);dl:(len: 9)),
+(fc:(freq:115);dl:(len: 9)), (fc:(freq:371);dl:(len: 9)), (fc:(freq:243);dl:(len: 9)),
+(fc:(freq:499);dl:(len: 9)), (fc:(freq: 11);dl:(len: 9)), (fc:(freq:267);dl:(len: 9)),
+(fc:(freq:139);dl:(len: 9)), (fc:(freq:395);dl:(len: 9)), (fc:(freq: 75);dl:(len: 9)),
+(fc:(freq:331);dl:(len: 9)), (fc:(freq:203);dl:(len: 9)), (fc:(freq:459);dl:(len: 9)),
+(fc:(freq: 43);dl:(len: 9)), (fc:(freq:299);dl:(len: 9)), (fc:(freq:171);dl:(len: 9)),
+(fc:(freq:427);dl:(len: 9)), (fc:(freq:107);dl:(len: 9)), (fc:(freq:363);dl:(len: 9)),
+(fc:(freq:235);dl:(len: 9)), (fc:(freq:491);dl:(len: 9)), (fc:(freq: 27);dl:(len: 9)),
+(fc:(freq:283);dl:(len: 9)), (fc:(freq:155);dl:(len: 9)), (fc:(freq:411);dl:(len: 9)),
+(fc:(freq: 91);dl:(len: 9)), (fc:(freq:347);dl:(len: 9)), (fc:(freq:219);dl:(len: 9)),
+(fc:(freq:475);dl:(len: 9)), (fc:(freq: 59);dl:(len: 9)), (fc:(freq:315);dl:(len: 9)),
+(fc:(freq:187);dl:(len: 9)), (fc:(freq:443);dl:(len: 9)), (fc:(freq:123);dl:(len: 9)),
+(fc:(freq:379);dl:(len: 9)), (fc:(freq:251);dl:(len: 9)), (fc:(freq:507);dl:(len: 9)),
+(fc:(freq: 7);dl:(len: 9)), (fc:(freq:263);dl:(len: 9)), (fc:(freq:135);dl:(len: 9)),
+(fc:(freq:391);dl:(len: 9)), (fc:(freq: 71);dl:(len: 9)), (fc:(freq:327);dl:(len: 9)),
+(fc:(freq:199);dl:(len: 9)), (fc:(freq:455);dl:(len: 9)), (fc:(freq: 39);dl:(len: 9)),
+(fc:(freq:295);dl:(len: 9)), (fc:(freq:167);dl:(len: 9)), (fc:(freq:423);dl:(len: 9)),
+(fc:(freq:103);dl:(len: 9)), (fc:(freq:359);dl:(len: 9)), (fc:(freq:231);dl:(len: 9)),
+(fc:(freq:487);dl:(len: 9)), (fc:(freq: 23);dl:(len: 9)), (fc:(freq:279);dl:(len: 9)),
+(fc:(freq:151);dl:(len: 9)), (fc:(freq:407);dl:(len: 9)), (fc:(freq: 87);dl:(len: 9)),
+(fc:(freq:343);dl:(len: 9)), (fc:(freq:215);dl:(len: 9)), (fc:(freq:471);dl:(len: 9)),
+(fc:(freq: 55);dl:(len: 9)), (fc:(freq:311);dl:(len: 9)), (fc:(freq:183);dl:(len: 9)),
+(fc:(freq:439);dl:(len: 9)), (fc:(freq:119);dl:(len: 9)), (fc:(freq:375);dl:(len: 9)),
+(fc:(freq:247);dl:(len: 9)), (fc:(freq:503);dl:(len: 9)), (fc:(freq: 15);dl:(len: 9)),
+(fc:(freq:271);dl:(len: 9)), (fc:(freq:143);dl:(len: 9)), (fc:(freq:399);dl:(len: 9)),
+(fc:(freq: 79);dl:(len: 9)), (fc:(freq:335);dl:(len: 9)), (fc:(freq:207);dl:(len: 9)),
+(fc:(freq:463);dl:(len: 9)), (fc:(freq: 47);dl:(len: 9)), (fc:(freq:303);dl:(len: 9)),
+(fc:(freq:175);dl:(len: 9)), (fc:(freq:431);dl:(len: 9)), (fc:(freq:111);dl:(len: 9)),
+(fc:(freq:367);dl:(len: 9)), (fc:(freq:239);dl:(len: 9)), (fc:(freq:495);dl:(len: 9)),
+(fc:(freq: 31);dl:(len: 9)), (fc:(freq:287);dl:(len: 9)), (fc:(freq:159);dl:(len: 9)),
+(fc:(freq:415);dl:(len: 9)), (fc:(freq: 95);dl:(len: 9)), (fc:(freq:351);dl:(len: 9)),
+(fc:(freq:223);dl:(len: 9)), (fc:(freq:479);dl:(len: 9)), (fc:(freq: 63);dl:(len: 9)),
+(fc:(freq:319);dl:(len: 9)), (fc:(freq:191);dl:(len: 9)), (fc:(freq:447);dl:(len: 9)),
+(fc:(freq:127);dl:(len: 9)), (fc:(freq:383);dl:(len: 9)), (fc:(freq:255);dl:(len: 9)),
+(fc:(freq:511);dl:(len: 9)), (fc:(freq: 0);dl:(len: 7)), (fc:(freq: 64);dl:(len: 7)),
+(fc:(freq: 32);dl:(len: 7)), (fc:(freq: 96);dl:(len: 7)), (fc:(freq: 16);dl:(len: 7)),
+(fc:(freq: 80);dl:(len: 7)), (fc:(freq: 48);dl:(len: 7)), (fc:(freq:112);dl:(len: 7)),
+(fc:(freq: 8);dl:(len: 7)), (fc:(freq: 72);dl:(len: 7)), (fc:(freq: 40);dl:(len: 7)),
+(fc:(freq:104);dl:(len: 7)), (fc:(freq: 24);dl:(len: 7)), (fc:(freq: 88);dl:(len: 7)),
+(fc:(freq: 56);dl:(len: 7)), (fc:(freq:120);dl:(len: 7)), (fc:(freq: 4);dl:(len: 7)),
+(fc:(freq: 68);dl:(len: 7)), (fc:(freq: 36);dl:(len: 7)), (fc:(freq:100);dl:(len: 7)),
+(fc:(freq: 20);dl:(len: 7)), (fc:(freq: 84);dl:(len: 7)), (fc:(freq: 52);dl:(len: 7)),
+(fc:(freq:116);dl:(len: 7)), (fc:(freq: 3);dl:(len: 8)), (fc:(freq:131);dl:(len: 8)),
+(fc:(freq: 67);dl:(len: 8)), (fc:(freq:195);dl:(len: 8)), (fc:(freq: 35);dl:(len: 8)),
+(fc:(freq:163);dl:(len: 8)), (fc:(freq: 99);dl:(len: 8)), (fc:(freq:227);dl:(len: 8))
+);
+
+
+{ The static distance tree. (Actually a trivial tree since all lens use
+ 5 bits.) }
+ static_dtree : array[0..D_CODES-1] of ct_data = (
+(fc:(freq: 0); dl:(len:5)), (fc:(freq:16); dl:(len:5)), (fc:(freq: 8); dl:(len:5)),
+(fc:(freq:24); dl:(len:5)), (fc:(freq: 4); dl:(len:5)), (fc:(freq:20); dl:(len:5)),
+(fc:(freq:12); dl:(len:5)), (fc:(freq:28); dl:(len:5)), (fc:(freq: 2); dl:(len:5)),
+(fc:(freq:18); dl:(len:5)), (fc:(freq:10); dl:(len:5)), (fc:(freq:26); dl:(len:5)),
+(fc:(freq: 6); dl:(len:5)), (fc:(freq:22); dl:(len:5)), (fc:(freq:14); dl:(len:5)),
+(fc:(freq:30); dl:(len:5)), (fc:(freq: 1); dl:(len:5)), (fc:(freq:17); dl:(len:5)),
+(fc:(freq: 9); dl:(len:5)), (fc:(freq:25); dl:(len:5)), (fc:(freq: 5); dl:(len:5)),
+(fc:(freq:21); dl:(len:5)), (fc:(freq:13); dl:(len:5)), (fc:(freq:29); dl:(len:5)),
+(fc:(freq: 3); dl:(len:5)), (fc:(freq:19); dl:(len:5)), (fc:(freq:11); dl:(len:5)),
+(fc:(freq:27); dl:(len:5)), (fc:(freq: 7); dl:(len:5)), (fc:(freq:23); dl:(len:5))
+);
+
+{ Distance codes. The first 256 values correspond to the distances
+ 3 .. 258, the last 256 values correspond to the top 8 bits of
+ the 15 bit distances. }
+ _dist_code : array[0..DIST_CODE_LEN-1] of byte = (
+ 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8,
+ 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
+10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17,
+18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+);
+
+{ length code for each normalized match length (0 == MIN_MATCH) }
+ _length_code : array[0..MAX_MATCH-MIN_MATCH+1-1] of byte = (
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
+13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+);
+
+
+{ First normalized length for each code (0 = MIN_MATCH) }
+ base_length : array[0..LENGTH_CODES-1] of integer = (
+0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+64, 80, 96, 112, 128, 160, 192, 224, 0
+);
+
+
+{ First normalized distance for each code (0 = distance of 1) }
+ base_dist : array[0..D_CODES-1] of integer = (
+ 0, 1, 2, 3, 4, 6, 8, 12, 16, 24,
+ 32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
+ 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
+);
+{$endif}
+
+{ Output a byte on the stream.
+ IN assertion: there is enough room in pending_buf.
+macro put_byte(s, c)
+begin
+ s^.pending_buf^[s^.pending] := (c);
+ inc(s^.pending);
+end
+}
+
+const
+ MIN_LOOKAHEAD = (MAX_MATCH+MIN_MATCH+1);
+{ Minimum amount of lookahead, except at the end of the input file.
+ See deflate.c for comments about the MIN_MATCH+1. }
+
+{macro d_code(dist)
+ if (dist) < 256 then
+ := _dist_code[dist]
+ else
+ := _dist_code[256+((dist) shr 7)]);
+ Mapping from a distance to a distance code. dist is the distance - 1 and
+ must not have side effects. _dist_code[256] and _dist_code[257] are never
+ used. }
+
+{$ifndef ORG_DEBUG}
+{ Inline versions of _tr_tally for speed: }
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+ extern byte _length_code[];
+ extern byte _dist_code[];
+#else
+ extern const byte _length_code[];
+ extern const byte _dist_code[];
+#endif
+
+macro _tr_tally_lit(s, c, flush)
+var
+ cc : byte;
+begin
+ cc := (c);
+ s^.d_buf[s^.last_lit] := 0;
+ s^.l_buf[s^.last_lit] := cc;
+ inc(s^.last_lit);
+ inc(s^.dyn_ltree[cc].fc.Freq);
+ flush := (s^.last_lit = s^.lit_bufsize-1);
+end;
+
+macro _tr_tally_dist(s, distance, length, flush) \
+var
+ len : byte;
+ dist : word;
+begin
+ len := (length);
+ dist := (distance);
+ s^.d_buf[s^.last_lit] := dist;
+ s^.l_buf[s^.last_lit] = len;
+ inc(s^.last_lit);
+ dec(dist);
+ inc(s^.dyn_ltree[_length_code[len]+LITERALS+1].fc.Freq);
+ inc(s^.dyn_dtree[d_code(dist)].Freq);
+ flush := (s^.last_lit = s^.lit_bufsize-1);
+end;
+
+{$endif}
+
+{ ===========================================================================
+ Constants }
+
+const
+ MAX_BL_BITS = 7;
+{ Bit length codes must not exceed MAX_BL_BITS bits }
+
+const
+ END_BLOCK = 256;
+{ end of block literal code }
+
+const
+ REP_3_6 = 16;
+{ repeat previous bit length 3-6 times (2 bits of repeat count) }
+
+const
+ REPZ_3_10 = 17;
+{ repeat a zero length 3-10 times (3 bits of repeat count) }
+
+const
+ REPZ_11_138 = 18;
+{ repeat a zero length 11-138 times (7 bits of repeat count) }
+
+{local}
+const
+ extra_lbits : array[0..LENGTH_CODES-1] of integer
+ { extra bits for each length code }
+ = (0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0);
+
+{local}
+const
+ extra_dbits : array[0..D_CODES-1] of integer
+ { extra bits for each distance code }
+ = (0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13);
+
+{local}
+const
+ extra_blbits : array[0..BL_CODES-1] of integer { extra bits for each bit length code }
+ = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7);
+
+{local}
+const
+ bl_order : array[0..BL_CODES-1] of byte
+ = (16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15);
+{ The lengths of the bit length codes are sent in order of decreasing
+ probability, to avoid transmitting the lengths for unused bit length codes.
+ }
+
+const
+ Buf_size = (8 * 2*sizeof(char));
+{ Number of bits used within bi_buf. (bi_buf might be implemented on
+ more than 16 bits on some systems.) }
+
+{ ===========================================================================
+ Local data. These are initialized only once. }
+
+
+{$ifdef GEN_TREES_H)}
+{ non ANSI compilers may not accept trees.h }
+
+const
+ DIST_CODE_LEN = 512; { see definition of array dist_code below }
+
+{local}
+var
+ static_ltree : array[0..L_CODES+2-1] of ct_data;
+{ The static literal tree. Since the bit lengths are imposed, there is no
+ need for the L_CODES extra codes used during heap construction. However
+ The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ below). }
+
+{local}
+ static_dtree : array[0..D_CODES-1] of ct_data;
+{ The static distance tree. (Actually a trivial tree since all codes use
+ 5 bits.) }
+
+ _dist_code : array[0..DIST_CODE_LEN-1] of byte;
+{ Distance codes. The first 256 values correspond to the distances
+ 3 .. 258, the last 256 values correspond to the top 8 bits of
+ the 15 bit distances. }
+
+ _length_code : array[0..MAX_MATCH-MIN_MATCH+1-1] of byte;
+{ length code for each normalized match length (0 == MIN_MATCH) }
+
+{local}
+ base_length : array[0..LENGTH_CODES-1] of integer;
+{ First normalized length for each code (0 = MIN_MATCH) }
+
+{local}
+ base_dist : array[0..D_CODES-1] of integer;
+{ First normalized distance for each code (0 = distance of 1) }
+
+{$endif} { GEN_TREES_H }
+
+{local}
+const
+ static_l_desc : static_tree_desc =
+ (static_tree: {tree_ptr}@static_ltree[0]; { pointer to array of ct_data }
+ extra_bits: {pzIntfArray}@extra_lbits[0]; { pointer to array of integer }
+ extra_base: LITERALS+1;
+ elems: L_CODES;
+ max_length: MAX_BITS);
+
+{local}
+const
+ static_d_desc : static_tree_desc =
+ (static_tree: {tree_ptr}@static_dtree[0];
+ extra_bits: {pzIntfArray}@extra_dbits[0];
+ extra_base : 0;
+ elems: D_CODES;
+ max_length: MAX_BITS);
+
+{local}
+const
+ static_bl_desc : static_tree_desc =
+ (static_tree: {tree_ptr}(NIL);
+ extra_bits: {pzIntfArray}@extra_blbits[0];
+ extra_base : 0;
+ elems: BL_CODES;
+ max_length: MAX_BL_BITS);
+
+{$ifdef GEN_TREES_H}
+{local}
+procedure gen_trees_header;
+{$endif}
+
+(*
+{ ===========================================================================
+ Output a short LSB first on the stream.
+ IN assertion: there is enough room in pendingBuf. }
+
+macro put_short(s, w)
+begin
+ {put_byte(s, (byte)((w) & 0xff));}
+ s.pending_buf^[s.pending] := byte((w) and $ff);
+ inc(s.pending);
+
+ {put_byte(s, (byte)((word)(w) >> 8));}
+ s.pending_buf^[s.pending] := byte(word(w) shr 8);;
+ inc(s.pending);
+end
+*)
+
+{ ===========================================================================
+ Send a value on a given number of bits.
+ IN assertion: length <= 16 and value fits in length bits. }
+
+{$ifdef ORG_DEBUG}
+
+{local}
+procedure send_bits(var s : deflate_state;
+ value : integer; { value to send }
+ length : integer); { number of bits }
+begin
+ {$ifdef ZLIB_DEBUG}
+ Tracevv(' l '+IntToStr(length)+ ' v '+IntToStr(value));
+ Assert((length > 0) and (length <= 15), 'invalid length');
+ inc(s.bits_sent, longint(length));
+ {$ENDIF}
+
+ { If not enough room in bi_buf, use (valid) bits from bi_buf and
+ (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+ unused bits in value. }
+ {$IFOPT Q+} {$Q-} {$DEFINE NoOverflowCheck} {$ENDIF}
+ {$IFOPT R+} {$R-} {$DEFINE NoRangeCheck} {$ENDIF}
+ if (s.bi_valid > integer(Buf_size) - length) then
+ begin
+ s.bi_buf := s.bi_buf or integer(value shl s.bi_valid);
+ {put_short(s, s.bi_buf);}
+ s.pending_buf^[s.pending] := byte(s.bi_buf and $ff);
+ inc(s.pending);
+ s.pending_buf^[s.pending] := byte(word(s.bi_buf) shr 8);;
+ inc(s.pending);
+
+ s.bi_buf := word(value) shr (Buf_size - s.bi_valid);
+ inc(s.bi_valid, length - Buf_size);
+ end
+ else
+ begin
+ s.bi_buf := s.bi_buf or integer(value shl s.bi_valid);
+ inc(s.bi_valid, length);
+ end;
+ {$IFDEF NoOverflowCheck} {$Q+} {$UNDEF NoOverflowCheck} {$ENDIF}
+ {$IFDEF NoRangeCheck} {$Q+} {$UNDEF NoRangeCheck} {$ENDIF}
+end;
+
+{$else} { !ZLIB_DEBUG }
+
+
+macro send_code(s, c, tree)
+begin
+ send_bits(s, tree[c].Code, tree[c].Len);
+ { Send a code of the given tree. c and tree must not have side effects }
+end
+
+macro send_bits(s, value, length) \
+begin integer len := length;\
+ if (s^.bi_valid > (integer)Buf_size - len) begin\
+ integer val := value;\
+ s^.bi_buf |= (val << s^.bi_valid);\
+ {put_short(s, s.bi_buf);}
+ s.pending_buf^[s.pending] := byte(s.bi_buf and $ff);
+ inc(s.pending);
+ s.pending_buf^[s.pending] := byte(word(s.bi_buf) shr 8);;
+ inc(s.pending);
+
+ s^.bi_buf := (word)val >> (Buf_size - s^.bi_valid);\
+ s^.bi_valid += len - Buf_size;\
+ end else begin\
+ s^.bi_buf |= (value) << s^.bi_valid;\
+ s^.bi_valid += len;\
+ end\
+end;
+{$endif} { ZLIB_DEBUG }
+
+{ ===========================================================================
+ Reverse the first len bits of a code, using straightforward code (a faster
+ method would use a table)
+ IN assertion: 1 <= len <= 15 }
+
+{local}
+function bi_reverse(code : cardinal; { the value to invert }
+ len : integer) : cardinal; { its bit length }
+
+var
+ res : cardinal; {register}
+begin
+ res := 0;
+ repeat
+ res := res or (code and 1);
+ code := code shr 1;
+ res := res shl 1;
+ dec(len);
+ until (len <= 0);
+ bi_reverse := res shr 1;
+end;
+
+{ ===========================================================================
+ Generate the codes for a given tree and bit counts (which need not be
+ optimal).
+ IN assertion: the array bl_count contains the bit length statistics for
+ the given tree and the field len is set for all tree elements.
+ OUT assertion: the field code is set for all tree elements of non
+ zero code length. }
+
+{local}
+procedure gen_codes(tree : tree_ptr; { the tree to decorate }
+ max_code : integer; { largest code with non zero frequency }
+ var bl_count : array of word); { number of codes at each bit length }
+
+var
+ next_code : array[0..MAX_BITS+1-1] of word; { next code value for each bit length }
+ code : word; { running code value }
+ bits : integer; { bit index }
+ n : integer; { code index }
+var
+ len : integer;
+begin
+ code := 0;
+
+ { The distribution counts are first used to generate the code values
+ without bit reversal. }
+
+ for bits := 1 to MAX_BITS do
+ begin
+ code := ((code + bl_count[bits-1]) shl 1);
+ next_code[bits] := code;
+ end;
+ { Check that the bit counts in bl_count are consistent. The last code
+ must be all ones. }
+
+ {$IFDEF ZLIB_DEBUG}
+ Assert (code + bl_count[MAX_BITS]-1 = (1 shl MAX_BITS)-1,
+ 'inconsistent bit counts');
+ Tracev(#13'gen_codes: max_code '+IntToStr(max_code));
+ {$ENDIF}
+
+ for n := 0 to max_code do
+ begin
+ len := tree[n].dl.Len;
+ if (len = 0) then
+ continue;
+ { Now reverse the bits }
+ tree[n].fc.Code := bi_reverse(next_code[len], len);
+ inc(next_code[len]);
+ {$ifdef ZLIB_DEBUG}
+ if (n>31) and (n<128) then
+ Tracecv(tree <> tree_ptr(@static_ltree),
+ (^M'n #'+IntToStr(n)+' '+char(n)+' l '+IntToStr(len)+' c '+
+ IntToStr(tree[n].fc.Code)+' ('+IntToStr(next_code[len]-1)+')'))
+ else
+ Tracecv(tree <> tree_ptr(@static_ltree),
+ (^M'n #'+IntToStr(n)+' l '+IntToStr(len)+' c '+
+ IntToStr(tree[n].fc.Code)+' ('+IntToStr(next_code[len]-1)+')'));
+ {$ENDIF}
+ end;
+end;
+
+{ ===========================================================================
+ Genererate the file trees.h describing the static trees. }
+{$ifdef GEN_TREES_H}
+
+macro SEPARATOR(i, last, width)
+ if (i) = (last) then
+ ( ^M');'^M^M
+ else \
+ if (i) mod (width) = (width)-1 then
+ ','^M
+ else
+ ', '
+
+procedure gen_trees_header;
+var
+ header : system.text;
+ i : integer;
+begin
+ system.assign(header, 'trees.inc');
+ {$I-}
+ ReWrite(header);
+ {$I+}
+ Assert (IOresult <> 0, 'Can''t open trees.h');
+ WriteLn(header,
+ '{ header created automatically with -DGEN_TREES_H }'^M);
+
+ WriteLn(header, 'local const ct_data static_ltree[L_CODES+2] := (');
+ for i := 0 to L_CODES+2-1 do
+ begin
+ WriteLn(header, '((%3u),(%3u))%s', static_ltree[i].Code,
+ static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
+ end;
+
+ WriteLn(header, 'local const ct_data static_dtree[D_CODES] := (');
+ for i := 0 to D_CODES-1 do
+ begin
+ WriteLn(header, '((%2u),(%2u))%s', static_dtree[i].Code,
+ static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
+ end;
+
+ WriteLn(header, 'const byte _dist_code[DIST_CODE_LEN] := (');
+ for i := 0 to DIST_CODE_LEN-1 do
+ begin
+ WriteLn(header, '%2u%s', _dist_code[i],
+ SEPARATOR(i, DIST_CODE_LEN-1, 20));
+ end;
+
+ WriteLn(header, 'const byte _length_code[MAX_MATCH-MIN_MATCH+1]= (');
+ for i := 0 to MAX_MATCH-MIN_MATCH+1-1 do
+ begin
+ WriteLn(header, '%2u%s', _length_code[i],
+ SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
+ end;
+
+ WriteLn(header, 'local const integer base_length[LENGTH_CODES] := (');
+ for i := 0 to LENGTH_CODES-1 do
+ begin
+ WriteLn(header, '%1u%s', base_length[i],
+ SEPARATOR(i, LENGTH_CODES-1, 20));
+ end;
+
+ WriteLn(header, 'local const integer base_dist[D_CODES] := (');
+ for i := 0 to D_CODES-1 do
+ begin
+ WriteLn(header, '%5u%s', base_dist[i],
+ SEPARATOR(i, D_CODES-1, 10));
+ end;
+
+ close(header);
+end;
+{$endif} { GEN_TREES_H }
+
+
+{ ===========================================================================
+ Initialize the various 'constant' tables. }
+
+{local}
+procedure tr_static_init;
+
+{$ifdef GEN_TREES_H}
+const
+ static_init_done : boolean = FALSE;
+var
+ n : integer; { iterates over tree elements }
+ bits : integer; { bit counter }
+ length : integer; { length value }
+ code : integer; { code value }
+ dist : integer; { distance index }
+ bl_count : array[0..MAX_BITS+1-1] of word;
+ { number of codes at each bit length for an optimal tree }
+begin
+ if (static_init_done) then
+ exit;
+
+ { Initialize the mapping length (0..255) -> length code (0..28) }
+ length := 0;
+ for code := 0 to LENGTH_CODES-1-1 do
+ begin
+ base_length[code] := length;
+ for n := 0 to (1 shl extra_lbits[code])-1 do
+ begin
+ _length_code[length] := byte(code);
+ inc(length);
+ end;
+ end;
+ Assert (length = 256, 'tr_static_init: length <> 256');
+ { Note that the length 255 (match length 258) can be represented
+ in two different ways: code 284 + 5 bits or code 285, so we
+ overwrite length_code[255] to use the best encoding: }
+
+ _length_code[length-1] := byte(code);
+
+ { Initialize the mapping dist (0..32K) -> dist code (0..29) }
+ dist := 0;
+ for code := 0 to 16-1 do
+ begin
+ base_dist[code] := dist;
+ for n := 0 to (1 shl extra_dbits[code])-1 do
+ begin
+ _dist_code[dist] := byte(code);
+ inc(dist);
+ end;
+ end;
+ Assert (dist = 256, 'tr_static_init: dist <> 256');
+ dist := dist shr 7; { from now on, all distances are divided by 128 }
+ for code := 16 to D_CODES-1 do
+ begin
+ base_dist[code] := dist shl 7;
+ for n := 0 to (1 shl (extra_dbits[code]-7))-1 do
+ begin
+ _dist_code[256 + dist] := byte(code);
+ inc(dist);
+ end;
+ end;
+ Assert (dist = 256, 'tr_static_init: 256+dist <> 512');
+
+ { Construct the codes of the static literal tree }
+ for bits := 0 to MAX_BITS do
+ bl_count[bits] := 0;
+ n := 0;
+ while (n <= 143) do
+ begin
+ static_ltree[n].dl.Len := 8;
+ inc(n);
+ inc(bl_count[8]);
+ end;
+ while (n <= 255) do
+ begin
+ static_ltree[n].dl.Len := 9;
+ inc(n);
+ inc(bl_count[9]);
+ end;
+ while (n <= 279) do
+ begin
+ static_ltree[n].dl.Len := 7;
+ inc(n);
+ inc(bl_count[7]);
+ end;
+ while (n <= 287) do
+ begin
+ static_ltree[n].dl.Len := 8;
+ inc(n);
+ inc(bl_count[8]);
+ end;
+
+ { Codes 286 and 287 do not exist, but we must include them in the
+ tree construction to get a canonical Huffman tree (longest code
+ all ones) }
+
+ gen_codes(tree_ptr(@static_ltree), L_CODES+1, bl_count);
+
+ { The static distance tree is trivial: }
+ for n := 0 to D_CODES-1 do
+ begin
+ static_dtree[n].dl.Len := 5;
+ static_dtree[n].fc.Code := bi_reverse(cardinal(n), 5);
+ end;
+ static_init_done := TRUE;
+
+ gen_trees_header; { save to include file }
+{$else}
+begin
+{$endif} { GEN_TREES_H) }
+end;
+
+{ ===========================================================================
+ Initialize a new block. }
+{local}
+
+procedure init_block(var s : deflate_state);
+var
+ n : integer; { iterates over tree elements }
+begin
+ { Initialize the trees. }
+ for n := 0 to L_CODES-1 do
+ s.dyn_ltree[n].fc.Freq := 0;
+ for n := 0 to D_CODES-1 do
+ s.dyn_dtree[n].fc.Freq := 0;
+ for n := 0 to BL_CODES-1 do
+ s.bl_tree[n].fc.Freq := 0;
+
+ s.dyn_ltree[END_BLOCK].fc.Freq := 1;
+ s.static_len := 0;
+ s.opt_len := 0;
+ s.matches := 0;
+ s.last_lit := 0;
+end;
+
+const
+ SMALLEST = 1;
+{ Index within the heap array of least frequent node in the Huffman tree }
+
+{ ===========================================================================
+ Initialize the tree data structures for a new zlib stream. }
+procedure _tr_init(var s : deflate_state);
+begin
+ tr_static_init;
+
+ s.compressed_len := 0;
+
+ s.l_desc.dyn_tree := tree_ptr(@s.dyn_ltree);
+ s.l_desc.stat_desc := @static_l_desc;
+
+ s.d_desc.dyn_tree := tree_ptr(@s.dyn_dtree);
+ s.d_desc.stat_desc := @static_d_desc;
+
+ s.bl_desc.dyn_tree := tree_ptr(@s.bl_tree);
+ s.bl_desc.stat_desc := @static_bl_desc;
+
+ s.bi_buf := 0;
+ s.bi_valid := 0;
+ s.last_eob_len := 8; { enough lookahead for inflate }
+{$ifdef ZLIB_DEBUG}
+ s.bits_sent := 0;
+{$endif}
+
+ { Initialize the first block of the first file: }
+ init_block(s);
+end;
+
+{ ===========================================================================
+ Remove the smallest element from the heap and recreate the heap with
+ one less element. Updates heap and heap_len.
+
+macro pqremove(s, tree, top)
+begin
+ top := s.heap[SMALLEST];
+ s.heap[SMALLEST] := s.heap[s.heap_len];
+ dec(s.heap_len);
+ pqdownheap(s, tree, SMALLEST);
+end
+}
+
+{ ===========================================================================
+ Compares to subtrees, using the tree depth as tie breaker when
+ the subtrees have equal frequency. This minimizes the worst case length.
+
+macro smaller(tree, n, m, depth)
+ ( (tree[n].Freq < tree[m].Freq) or
+ ((tree[n].Freq = tree[m].Freq) and (depth[n] <= depth[m])) )
+}
+
+{ ===========================================================================
+ Restore the heap property by moving down the tree starting at node k,
+ exchanging a node with the smallest of its two sons if necessary, stopping
+ when the heap property is re-established (each father smaller than its
+ two sons). }
+{local}
+
+procedure pqdownheap(var s : deflate_state;
+ tree : tree_ptr; { the tree to restore }
+ k : integer); { node to move down }
+var
+ v : integer;
+ j : integer;
+begin
+ v := s.heap[k];
+ j := k shl 1; { left son of k }
+ while (j <= s.heap_len) do
+ begin
+ { Set j to the smallest of the two sons: }
+ if (j < s.heap_len) and
+ {smaller(tree, s.heap[j+1], s.heap[j], s.depth)}
+ ( (tree[s.heap[j+1]].fc.Freq < tree[s.heap[j]].fc.Freq) or
+ ((tree[s.heap[j+1]].fc.Freq = tree[s.heap[j]].fc.Freq) and
+ (s.depth[s.heap[j+1]] <= s.depth[s.heap[j]])) ) then
+ begin
+ inc(j);
+ end;
+ { Exit if v is smaller than both sons }
+ if {(smaller(tree, v, s.heap[j], s.depth))}
+ ( (tree[v].fc.Freq < tree[s.heap[j]].fc.Freq) or
+ ((tree[v].fc.Freq = tree[s.heap[j]].fc.Freq) and
+ (s.depth[v] <= s.depth[s.heap[j]])) ) then
+ break;
+ { Exchange v with the smallest son }
+ s.heap[k] := s.heap[j];
+ k := j;
+
+ { And continue down the tree, setting j to the left son of k }
+ j := j shl 1;
+ end;
+ s.heap[k] := v;
+end;
+
+{ ===========================================================================
+ Compute the optimal bit lengths for a tree and update the total bit length
+ for the current block.
+ IN assertion: the fields freq and dad are set, heap[heap_max] and
+ above are the tree nodes sorted by increasing frequency.
+ OUT assertions: the field len is set to the optimal bit length, the
+ array bl_count contains the frequencies for each bit length.
+ The length opt_len is updated; static_len is also updated if stree is
+ not null. }
+
+{local}
+procedure gen_bitlen(var s : deflate_state;
+ var desc : tree_desc); { the tree descriptor }
+var
+ tree : tree_ptr;
+ max_code : integer;
+ stree : tree_ptr; {const}
+ extra : pinteger; {const}
+ base : integer;
+ max_length : integer;
+ h : integer; { heap index }
+ n, m : integer; { iterate over the tree elements }
+ bits : integer; { bit length }
+ xbits : integer; { extra bits }
+ f : word; { frequency }
+ overflow : integer; { number of elements with bit length too large }
+begin
+ tree := desc.dyn_tree;
+ max_code := desc.max_code;
+ stree := desc.stat_desc^.static_tree;
+ extra := desc.stat_desc^.extra_bits;
+ base := desc.stat_desc^.extra_base;
+ max_length := desc.stat_desc^.max_length;
+ overflow := 0;
+
+ for bits := 0 to MAX_BITS do
+ s.bl_count[bits] := 0;
+
+ { In a first pass, compute the optimal bit lengths (which may
+ overflow in the case of the bit length tree). }
+
+ tree[s.heap[s.heap_max]].dl.Len := 0; { root of the heap }
+
+ for h := s.heap_max+1 to HEAP_SIZE-1 do
+ begin
+ n := s.heap[h];
+ bits := tree[tree[n].dl.Dad].dl.Len + 1;
+ if (bits > max_length) then
+ begin
+ bits := max_length;
+ inc(overflow);
+ end;
+ tree[n].dl.Len := word(bits);
+ { We overwrite tree[n].dl.Dad which is no longer needed }
+
+ if (n > max_code) then
+ continue; { not a leaf node }
+
+ inc(s.bl_count[bits]);
+ xbits := 0;
+ if (n >= base) then
+ xbits := extra[n-base];
+ f := tree[n].fc.Freq;
+ inc(s.opt_len, longint(f) * (bits + xbits));
+ if (stree <> NIL) then
+ inc(s.static_len, longint(f) * (stree[n].dl.Len + xbits));
+ end;
+ if (overflow = 0) then
+ exit;
+ {$ifdef ZLIB_DEBUG}
+ Tracev(^M'bit length overflow');
+ {$endif}
+ { This happens for example on obj2 and pic of the Calgary corpus }
+
+ { Find the first bit length which could increase: }
+ repeat
+ bits := max_length-1;
+ while (s.bl_count[bits] = 0) do
+ dec(bits);
+ dec(s.bl_count[bits]); { move one leaf down the tree }
+ inc(s.bl_count[bits+1], 2); { move one overflow item as its brother }
+ dec(s.bl_count[max_length]);
+ { The brother of the overflow item also moves one step up,
+ but this does not affect bl_count[max_length] }
+
+ dec(overflow, 2);
+ until (overflow <= 0);
+
+ { Now recompute all bit lengths, scanning in increasing frequency.
+ h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+ lengths instead of fixing only the wrong ones. This idea is taken
+ from 'ar' written by Haruhiko Okumura.) }
+ h := HEAP_SIZE; { Delphi3: compiler warning w/o this }
+ for bits := max_length downto 1 do
+ begin
+ n := s.bl_count[bits];
+ while (n <> 0) do
+ begin
+ dec(h);
+ m := s.heap[h];
+ if (m > max_code) then
+ continue;
+ if (tree[m].dl.Len <> cardinal(bits)) then
+ begin
+ {$ifdef ZLIB_DEBUG}
+ Trace('code '+IntToStr(m)+' bits '+IntToStr(tree[m].dl.Len)
+ +'.'+IntToStr(bits));
+ {$ENDIF}
+ inc(s.opt_len, (cardinal(bits) - cardinal(tree[m].dl.Len))
+ * cardinal(tree[m].fc.Freq) );
+ tree[m].dl.Len := word(bits);
+ end;
+ dec(n);
+ end;
+ end;
+end;
+
+{ ===========================================================================
+ Construct one Huffman tree and assigns the code bit strings and lengths.
+ Update the total bit length for the current block.
+ IN assertion: the field freq is set for all tree elements.
+ OUT assertions: the fields len and code are set to the optimal bit length
+ and corresponding code. The length opt_len is updated; static_len is
+ also updated if stree is not null. The field max_code is set. }
+
+{local}
+procedure build_tree(var s : deflate_state;
+ var desc : tree_desc); { the tree descriptor }
+
+var
+ tree : tree_ptr;
+ stree : tree_ptr; {const}
+ elems : integer;
+ n, m : integer; { iterate over heap elements }
+ max_code : integer; { largest code with non zero frequency }
+ node : integer; { new node being created }
+begin
+ tree := desc.dyn_tree;
+ stree := desc.stat_desc^.static_tree;
+ elems := desc.stat_desc^.elems;
+ max_code := -1;
+
+ { Construct the initial heap, with least frequent element in
+ heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+ heap[0] is not used. }
+ s.heap_len := 0;
+ s.heap_max := HEAP_SIZE;
+
+ for n := 0 to elems-1 do
+ begin
+ if (tree[n].fc.Freq <> 0) then
+ begin
+ max_code := n;
+ inc(s.heap_len);
+ s.heap[s.heap_len] := n;
+ s.depth[n] := 0;
+ end
+ else
+ begin
+ tree[n].dl.Len := 0;
+ end;
+ end;
+
+ { The pkzip format requires that at least one distance code exists,
+ and that at least one bit should be sent even if there is only one
+ possible code. So to avoid special checks later on we force at least
+ two codes of non zero frequency. }
+
+ while (s.heap_len < 2) do
+ begin
+ inc(s.heap_len);
+ if (max_code < 2) then
+ begin
+ inc(max_code);
+ s.heap[s.heap_len] := max_code;
+ node := max_code;
+ end
+ else
+ begin
+ s.heap[s.heap_len] := 0;
+ node := 0;
+ end;
+ tree[node].fc.Freq := 1;
+ s.depth[node] := 0;
+ dec(s.opt_len);
+ if (stree <> NIL) then
+ dec(s.static_len, stree[node].dl.Len);
+ { node is 0 or 1 so it does not have extra bits }
+ end;
+ desc.max_code := max_code;
+
+ { The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+ establish sub-heaps of increasing lengths: }
+
+ for n := s.heap_len div 2 downto 1 do
+ pqdownheap(s, tree, n);
+
+ { Construct the Huffman tree by repeatedly combining the least two
+ frequent nodes. }
+
+ node := elems; { next internal node of the tree }
+ repeat
+ {pqremove(s, tree, n);} { n := node of least frequency }
+ n := s.heap[SMALLEST];
+ s.heap[SMALLEST] := s.heap[s.heap_len];
+ dec(s.heap_len);
+ pqdownheap(s, tree, SMALLEST);
+
+ m := s.heap[SMALLEST]; { m := node of next least frequency }
+
+ dec(s.heap_max);
+ s.heap[s.heap_max] := n; { keep the nodes sorted by frequency }
+ dec(s.heap_max);
+ s.heap[s.heap_max] := m;
+
+ { Create a new node father of n and m }
+ tree[node].fc.Freq := tree[n].fc.Freq + tree[m].fc.Freq;
+ { maximum }
+ if (s.depth[n] >= s.depth[m]) then
+ s.depth[node] := byte (s.depth[n] + 1)
+ else
+ s.depth[node] := byte (s.depth[m] + 1);
+
+ tree[m].dl.Dad := word(node);
+ tree[n].dl.Dad := word(node);
+{$ifdef DUMP_BL_TREE}
+ if (tree = tree_ptr(@s.bl_tree)) then
+ begin
+ WriteLn(#13'node ',node,'(',tree[node].fc.Freq,') sons ',n,
+ '(',tree[n].fc.Freq,') ', m, '(',tree[m].fc.Freq,')');
+ end;
+{$endif}
+ { and insert the new node in the heap }
+ s.heap[SMALLEST] := node;
+ inc(node);
+ pqdownheap(s, tree, SMALLEST);
+
+ until (s.heap_len < 2);
+
+ dec(s.heap_max);
+ s.heap[s.heap_max] := s.heap[SMALLEST];
+
+ { At this point, the fields freq and dad are set. We can now
+ generate the bit lengths. }
+
+ gen_bitlen(s, desc);
+
+ { The field len is now set, we can generate the bit codes }
+ gen_codes (tree, max_code, s.bl_count);
+end;
+
+{ ===========================================================================
+ Scan a literal or distance tree to determine the frequencies of the codes
+ in the bit length tree. }
+
+{local}
+procedure scan_tree(var s : deflate_state;
+ var tree : array of ct_data; { the tree to be scanned }
+ max_code : integer); { and its largest code of non zero frequency }
+var
+ n : integer; { iterates over all tree elements }
+ prevlen : integer; { last emitted length }
+ curlen : integer; { length of current code }
+ nextlen : integer; { length of next code }
+ count : integer; { repeat count of the current code }
+ max_count : integer; { max repeat count }
+ min_count : integer; { min repeat count }
+begin
+ prevlen := -1;
+ nextlen := tree[0].dl.Len;
+ count := 0;
+ max_count := 7;
+ min_count := 4;
+
+ if (nextlen = 0) then
+ begin
+ max_count := 138;
+ min_count := 3;
+ end;
+ tree[max_code+1].dl.Len := word($ffff); { guard }
+
+ for n := 0 to max_code do
+ begin
+ curlen := nextlen;
+ nextlen := tree[n+1].dl.Len;
+ inc(count);
+ if (count < max_count) and (curlen = nextlen) then
+ continue
+ else
+ if (count < min_count) then
+ inc(s.bl_tree[curlen].fc.Freq, count)
+ else
+ if (curlen <> 0) then
+ begin
+ if (curlen <> prevlen) then
+ inc(s.bl_tree[curlen].fc.Freq);
+ inc(s.bl_tree[REP_3_6].fc.Freq);
+ end
+ else
+ if (count <= 10) then
+ inc(s.bl_tree[REPZ_3_10].fc.Freq)
+ else
+ inc(s.bl_tree[REPZ_11_138].fc.Freq);
+
+ count := 0;
+ prevlen := curlen;
+ if (nextlen = 0) then
+ begin
+ max_count := 138;
+ min_count := 3;
+ end
+ else
+ if (curlen = nextlen) then
+ begin
+ max_count := 6;
+ min_count := 3;
+ end
+ else
+ begin
+ max_count := 7;
+ min_count := 4;
+ end;
+ end;
+end;
+
+{ ===========================================================================
+ Send a literal or distance tree in compressed form, using the codes in
+ bl_tree. }
+
+{local}
+procedure send_tree(var s : deflate_state;
+ var tree : array of ct_data; { the tree to be scanned }
+ max_code : integer); { and its largest code of non zero frequency }
+
+var
+ n : integer; { iterates over all tree elements }
+ prevlen : integer; { last emitted length }
+ curlen : integer; { length of current code }
+ nextlen : integer; { length of next code }
+ count : integer; { repeat count of the current code }
+ max_count : integer; { max repeat count }
+ min_count : integer; { min repeat count }
+begin
+ prevlen := -1;
+ nextlen := tree[0].dl.Len;
+ count := 0;
+ max_count := 7;
+ min_count := 4;
+
+ { tree[max_code+1].dl.Len := -1; } { guard already set }
+ if (nextlen = 0) then
+ begin
+ max_count := 138;
+ min_count := 3;
+ end;
+
+ for n := 0 to max_code do
+ begin
+ curlen := nextlen;
+ nextlen := tree[n+1].dl.Len;
+ inc(count);
+ if (count < max_count) and (curlen = nextlen) then
+ continue
+ else
+ if (count < min_count) then
+ begin
+ repeat
+ {$ifdef ZLIB_DEBUG}
+ Tracevvv(#13'cd '+IntToStr(curlen));
+ {$ENDIF}
+ send_bits(s, s.bl_tree[curlen].fc.Code, s.bl_tree[curlen].dl.Len);
+ dec(count);
+ until (count = 0);
+ end
+ else
+ if (curlen <> 0) then
+ begin
+ if (curlen <> prevlen) then
+ begin
+ {$ifdef ZLIB_DEBUG}
+ Tracevvv(#13'cd '+IntToStr(curlen));
+ {$ENDIF}
+ send_bits(s, s.bl_tree[curlen].fc.Code, s.bl_tree[curlen].dl.Len);
+ dec(count);
+ end;
+ {$IFDEF ZLIB_DEBUG}
+ Assert((count >= 3) and (count <= 6), ' 3_6?');
+ {$ENDIF}
+ {$ifdef ZLIB_DEBUG}
+ Tracevvv(#13'cd '+IntToStr(REP_3_6));
+ {$ENDIF}
+ send_bits(s, s.bl_tree[REP_3_6].fc.Code, s.bl_tree[REP_3_6].dl.Len);
+ send_bits(s, count-3, 2);
+ end
+ else
+ if (count <= 10) then
+ begin
+ {$ifdef ZLIB_DEBUG}
+ Tracevvv(#13'cd '+IntToStr(REPZ_3_10));
+ {$ENDIF}
+ send_bits(s, s.bl_tree[REPZ_3_10].fc.Code, s.bl_tree[REPZ_3_10].dl.Len);
+ send_bits(s, count-3, 3);
+ end
+ else
+ begin
+ {$ifdef ZLIB_DEBUG}
+ Tracevvv(#13'cd '+IntToStr(REPZ_11_138));
+ {$ENDIF}
+ send_bits(s, s.bl_tree[REPZ_11_138].fc.Code, s.bl_tree[REPZ_11_138].dl.Len);
+ send_bits(s, count-11, 7);
+ end;
+ count := 0;
+ prevlen := curlen;
+ if (nextlen = 0) then
+ begin
+ max_count := 138;
+ min_count := 3;
+ end
+ else
+ if (curlen = nextlen) then
+ begin
+ max_count := 6;
+ min_count := 3;
+ end
+ else
+ begin
+ max_count := 7;
+ min_count := 4;
+ end;
+ end;
+end;
+
+{ ===========================================================================
+ Construct the Huffman tree for the bit lengths and return the index in
+ bl_order of the last bit length code to send. }
+
+{local}
+function build_bl_tree(var s : deflate_state) : integer;
+var
+ max_blindex : integer; { index of last bit length code of non zero freq }
+begin
+ { Determine the bit length frequencies for literal and distance trees }
+ scan_tree(s, s.dyn_ltree, s.l_desc.max_code);
+ scan_tree(s, s.dyn_dtree, s.d_desc.max_code);
+
+ { Build the bit length tree: }
+ build_tree(s, s.bl_desc);
+ { opt_len now includes the length of the tree representations, except
+ the lengths of the bit lengths codes and the 5+5+4 bits for the counts. }
+
+ { Determine the number of bit length codes to send. The pkzip format
+ requires that at least 4 bit length codes be sent. (appnote.txt says
+ 3 but the actual value used is 4.) }
+
+ for max_blindex := BL_CODES-1 downto 3 do
+ begin
+ if (s.bl_tree[bl_order[max_blindex]].dl.Len <> 0) then
+ break;
+ end;
+ { Update opt_len to include the bit length tree and counts }
+ inc(s.opt_len, 3*(max_blindex+1) + 5+5+4);
+ {$ifdef ZLIB_DEBUG}
+ Tracev(^M'dyn trees: dyn %ld, stat %ld {s.opt_len, s.static_len}');
+ {$ENDIF}
+
+ build_bl_tree := max_blindex;
+end;
+
+{ ===========================================================================
+ Send the header for a block using dynamic Huffman trees: the counts, the
+ lengths of the bit length codes, the literal tree and the distance tree.
+ IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. }
+
+{local}
+procedure send_all_trees(var s : deflate_state;
+ lcodes : integer;
+ dcodes : integer;
+ blcodes : integer); { number of codes for each tree }
+var
+ rank : integer; { index in bl_order }
+begin
+ {$IFDEF ZLIB_DEBUG}
+ Assert ((lcodes >= 257) and (dcodes >= 1) and (blcodes >= 4),
+ 'not enough codes');
+ Assert ((lcodes <= L_CODES) and (dcodes <= D_CODES)
+ and (blcodes <= BL_CODES), 'too many codes');
+ Tracev(^M'bl counts: ');
+ {$ENDIF}
+ send_bits(s, lcodes-257, 5); { not +255 as stated in appnote.txt }
+ send_bits(s, dcodes-1, 5);
+ send_bits(s, blcodes-4, 4); { not -3 as stated in appnote.txt }
+ for rank := 0 to blcodes-1 do
+ begin
+ {$ifdef ZLIB_DEBUG}
+ Tracev(^M'bl code '+IntToStr(bl_order[rank]));
+ {$ENDIF}
+ send_bits(s, s.bl_tree[bl_order[rank]].dl.Len, 3);
+ end;
+ {$ifdef ZLIB_DEBUG}
+ Tracev(^M'bl tree: sent '+IntToStr(s.bits_sent));
+ {$ENDIF}
+
+ send_tree(s, s.dyn_ltree, lcodes-1); { literal tree }
+ {$ifdef ZLIB_DEBUG}
+ Tracev(^M'lit tree: sent '+IntToStr(s.bits_sent));
+ {$ENDIF}
+
+ send_tree(s, s.dyn_dtree, dcodes-1); { distance tree }
+ {$ifdef ZLIB_DEBUG}
+ Tracev(^M'dist tree: sent '+IntToStr(s.bits_sent));
+ {$ENDIF}
+end;
+
+{ ===========================================================================
+ Flush the bit buffer and align the output on a byte boundary }
+
+{local}
+procedure bi_windup(var s : deflate_state);
+begin
+ if (s.bi_valid > 8) then
+ begin
+ {put_short(s, s.bi_buf);}
+ s.pending_buf^[s.pending] := byte(s.bi_buf and $ff);
+ inc(s.pending);
+ s.pending_buf^[s.pending] := byte(word(s.bi_buf) shr 8);;
+ inc(s.pending);
+ end
+ else
+ if (s.bi_valid > 0) then
+ begin
+ {put_byte(s, (Byte)s^.bi_buf);}
+ s.pending_buf^[s.pending] := Byte(s.bi_buf);
+ inc(s.pending);
+ end;
+ s.bi_buf := 0;
+ s.bi_valid := 0;
+{$ifdef ZLIB_DEBUG}
+ s.bits_sent := (s.bits_sent+7) and (not 7);
+{$endif}
+end;
+
+{ ===========================================================================
+ Copy a stored block, storing first the length and its
+ one's complement if requested. }
+
+{local}
+procedure copy_block(var s : deflate_state;
+ buf : Pbyte; { the input data }
+ len : word; { its length }
+ header : boolean); { true if block header must be written }
+begin
+ bi_windup(s); { align on byte boundary }
+ s.last_eob_len := 8; { enough lookahead for inflate }
+
+ if (header) then
+ begin
+ {put_short(s, (word)len);}
+ s.pending_buf^[s.pending] := byte(len and $ff);
+ inc(s.pending);
+ s.pending_buf^[s.pending] := byte(len shr 8);;
+ inc(s.pending);
+ {put_short(s, (word)~len);}
+ s.pending_buf^[s.pending] := byte((not len) and $ff);
+ inc(s.pending);
+ s.pending_buf^[s.pending] := byte((not len) shr 8);;
+ inc(s.pending);
+
+{$ifdef ZLIB_DEBUG}
+ inc(s.bits_sent, 2*16);
+{$endif}
+ end;
+{$ifdef ZLIB_DEBUG}
+ inc(s.bits_sent, len shl 3);
+{$endif}
+ move(buf^,s.pending_buf^[s.pending],len);
+ inc(s.pending,len);
+end;
+
+
+{ ===========================================================================
+ Send a stored block }
+
+procedure _tr_stored_block(var s : deflate_state;
+ buf : Pbyte; { input block }
+ stored_len : longint; { length of input block }
+ eof : boolean); { true if this is the last block for a file }
+
+begin
+ send_bits(s, (STORED_BLOCK shl 1)+ord(eof), 3); { send block type }
+ s.compressed_len := (s.compressed_len + 3 + 7) and longint(not cardinal(7));
+ inc(s.compressed_len, (stored_len + 4) shl 3);
+
+ copy_block(s, buf, cardinal(stored_len), TRUE); { with header }
+end;
+
+{ ===========================================================================
+ Flush the bit buffer, keeping at most 7 bits in it. }
+
+{local}
+procedure bi_flush(var s : deflate_state);
+begin
+ if (s.bi_valid = 16) then
+ begin
+ {put_short(s, s.bi_buf);}
+ s.pending_buf^[s.pending] := byte(s.bi_buf and $ff);
+ inc(s.pending);
+ s.pending_buf^[s.pending] := byte(word(s.bi_buf) shr 8);;
+ inc(s.pending);
+
+ s.bi_buf := 0;
+ s.bi_valid := 0;
+ end
+ else
+ if (s.bi_valid >= 8) then
+ begin
+ {put_byte(s, (Byte)s^.bi_buf);}
+ s.pending_buf^[s.pending] := Byte(s.bi_buf);
+ inc(s.pending);
+
+ s.bi_buf := s.bi_buf shr 8;
+ dec(s.bi_valid, 8);
+ end;
+end;
+
+
+{ ===========================================================================
+ Send one empty static block to give enough lookahead for inflate.
+ This takes 10 bits, of which 7 may remain in the bit buffer.
+ The current inflate code requires 9 bits of lookahead. If the
+ last two codes for the previous block (real code plus EOB) were coded
+ on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ the last real code. In this case we send two empty static blocks instead
+ of one. (There are no problems if the previous block is stored or fixed.)
+ To simplify the code, we assume the worst case of last real code encoded
+ on one bit only. }
+
+procedure _tr_align(var s : deflate_state);
+begin
+ send_bits(s, STATIC_TREES shl 1, 3);
+ {$ifdef ZLIB_DEBUG}
+ Tracevvv(#13'cd '+IntToStr(END_BLOCK));
+ {$ENDIF}
+ send_bits(s, static_ltree[END_BLOCK].fc.Code, static_ltree[END_BLOCK].dl.Len);
+ inc(s.compressed_len, cardinal(10)); { 3 for block type, 7 for EOB }
+ bi_flush(s);
+ { Of the 10 bits for the empty block, we have already sent
+ (10 - bi_valid) bits. The lookahead for the last real code (before
+ the EOB of the previous block) was thus at least one plus the length
+ of the EOB plus what we have just sent of the empty static block. }
+ if (1 + s.last_eob_len + 10 - s.bi_valid < 9) then
+ begin
+ send_bits(s, STATIC_TREES shl 1, 3);
+ {$ifdef ZLIB_DEBUG}
+ Tracevvv(#13'cd '+IntToStr(END_BLOCK));
+ {$ENDIF}
+ send_bits(s, static_ltree[END_BLOCK].fc.Code, static_ltree[END_BLOCK].dl.Len);
+ inc(s.compressed_len, cardinal(10));
+ bi_flush(s);
+ end;
+ s.last_eob_len := 7;
+end;
+
+{ ===========================================================================
+ Set the data type to ASCII or BINARY, using a crude approximation:
+ binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
+ IN assertion: the fields freq of dyn_ltree are set and the total of all
+ frequencies does not exceed 64K (to fit in an integer on 16 bit machines). }
+
+{local}
+procedure set_data_type(var s : deflate_state);
+var
+ n : integer;
+ ascii_freq : cardinal;
+ bin_freq : cardinal;
+begin
+ n := 0;
+ ascii_freq := 0;
+ bin_freq := 0;
+
+ while (n < 7) do
+ begin
+ inc(bin_freq, s.dyn_ltree[n].fc.Freq);
+ inc(n);
+ end;
+ while (n < 128) do
+ begin
+ inc(ascii_freq, s.dyn_ltree[n].fc.Freq);
+ inc(n);
+ end;
+ while (n < LITERALS) do
+ begin
+ inc(bin_freq, s.dyn_ltree[n].fc.Freq);
+ inc(n);
+ end;
+ if (bin_freq > (ascii_freq shr 2)) then
+ s.data_type := Byte(Z_BINARY)
+ else
+ s.data_type := Byte(Z_ASCII);
+end;
+
+{ ===========================================================================
+ Send the block data compressed using the given Huffman trees }
+
+{local}
+procedure compress_block(var s : deflate_state;
+ var ltree : array of ct_data; { literal tree }
+ var dtree : array of ct_data); { distance tree }
+var
+ dist : cardinal; { distance of matched string }
+ lc : integer; { match length or unmatched char (if dist == 0) }
+ lx : cardinal; { running index in l_buf }
+ code : cardinal; { the code to send }
+ extra : integer; { number of extra bits to send }
+begin
+ lx := 0;
+ if (s.last_lit <> 0) then
+ repeat
+ dist := s.d_buf^[lx];
+ lc := s.l_buf^[lx];
+ inc(lx);
+ if (dist = 0) then
+ begin
+ { send a literal byte }
+ {$ifdef ZLIB_DEBUG}
+ Tracevvv(#13'cd '+IntToStr(lc));
+ Tracecv((lc > 31) and (lc < 128), ' '+char(lc)+' ');
+ {$ENDIF}
+ send_bits(s, ltree[lc].fc.Code, ltree[lc].dl.Len);
+ end
+ else
+ begin
+ { Here, lc is the match length - MIN_MATCH }
+ code := _length_code[lc];
+ { send the length code }
+ {$ifdef ZLIB_DEBUG}
+ Tracevvv(#13'cd '+IntToStr(code+LITERALS+1));
+ {$ENDIF}
+ send_bits(s, ltree[code+LITERALS+1].fc.Code, ltree[code+LITERALS+1].dl.Len);
+ extra := extra_lbits[code];
+ if (extra <> 0) then
+ begin
+ dec(lc, base_length[code]);
+ send_bits(s, lc, extra); { send the extra length bits }
+ end;
+ dec(dist); { dist is now the match distance - 1 }
+ {code := d_code(dist);}
+ if (dist < 256) then
+ code := _dist_code[dist]
+ else
+ code := _dist_code[256+(dist shr 7)];
+
+ {$IFDEF ZLIB_DEBUG}
+ Assert (code < D_CODES, 'bad d_code');
+ {$ENDIF}
+
+ { send the distance code }
+ {$ifdef ZLIB_DEBUG}
+ Tracevvv(#13'cd '+IntToStr(code));
+ {$ENDIF}
+ send_bits(s, dtree[code].fc.Code, dtree[code].dl.Len);
+ extra := extra_dbits[code];
+ if (extra <> 0) then
+ begin
+ dec(dist, base_dist[code]);
+ send_bits(s, dist, extra); { send the extra distance bits }
+ end;
+ end; { literal or match pair ? }
+
+ { Check that the overlay between pending_buf and d_buf+l_buf is ok: }
+ {$IFDEF ZLIB_DEBUG}
+ Assert(s.pending < s.lit_bufsize + 2*lx, 'pendingBuf overflow');
+ {$ENDIF}
+ until (lx >= s.last_lit);
+
+ {$ifdef ZLIB_DEBUG}
+ Tracevvv(#13'cd '+IntToStr(END_BLOCK));
+ {$ENDIF}
+ send_bits(s, ltree[END_BLOCK].fc.Code, ltree[END_BLOCK].dl.Len);
+ s.last_eob_len := ltree[END_BLOCK].dl.Len;
+end;
+
+
+{ ===========================================================================
+ Determine the best encoding for the current block: dynamic trees, static
+ trees or store, and output the encoded block to the zip file. This function
+ returns the total compressed length for the file so far. }
+
+function _tr_flush_block (var s : deflate_state;
+ buf : Pbyte; { input block, or NULL if too old }
+ stored_len : longint; { length of input block }
+ eof : boolean) : longint; { true if this is the last block for a file }
+var
+ opt_lenb, static_lenb : longint; { opt_len and static_len in bytes }
+ max_blindex : integer; { index of last bit length code of non zero freq }
+begin
+ max_blindex := 0;
+
+ { Build the Huffman trees unless a stored block is forced }
+ if (s.level > 0) then
+ begin
+ { Check if the file is ascii or binary }
+ if (s.data_type = Z_UNKNOWN) then
+ set_data_type(s);
+
+ { Construct the literal and distance trees }
+ build_tree(s, s.l_desc);
+ {$ifdef ZLIB_DEBUG}
+ Tracev(^M'lit data: dyn %ld, stat %ld {s.opt_len, s.static_len}');
+ {$ENDIF}
+
+ build_tree(s, s.d_desc);
+ {$ifdef ZLIB_DEBUG}
+ Tracev(^M'dist data: dyn %ld, stat %ld {s.opt_len, s.static_len}');
+ {$ENDIF}
+ { At this point, opt_len and static_len are the total bit lengths of
+ the compressed block data, excluding the tree representations. }
+
+ { Build the bit length tree for the above two trees, and get the index
+ in bl_order of the last bit length code to send. }
+ max_blindex := build_bl_tree(s);
+
+ { Determine the best encoding. Compute first the block length in bytes}
+ opt_lenb := (s.opt_len+3+7) shr 3;
+ static_lenb := (s.static_len+3+7) shr 3;
+
+ {$ifdef ZLIB_DEBUG}
+ Tracev(^M'opt %lu(%lu) stat %lu(%lu) stored %lu lit %u '+
+ '{opt_lenb, s.opt_len, static_lenb, s.static_len, stored_len,'+
+ 's.last_lit}');
+ {$ENDIF}
+
+ if (static_lenb <= opt_lenb) then
+ opt_lenb := static_lenb;
+
+ end
+ else
+ begin
+ {$IFDEF ZLIB_DEBUG}
+ Assert(buf <> nil, 'lost buf');
+ {$ENDIF}
+ static_lenb := stored_len + 5;
+ opt_lenb := static_lenb; { force a stored block }
+ end;
+
+ { If compression failed and this is the first and last block,
+ and if the .zip file can be seeked (to rewrite the local header),
+ the whole file is transformed into a stored file: }
+
+{$ifdef STORED_FILE_OK}
+{$ifdef FORCE_STORED_FILE}
+ if eof and (s.compressed_len = 0) then
+ begin { force stored file }
+{$else}
+ if (stored_len <= opt_lenb) and eof and (s.compressed_len=cardinal(0))
+ and seekable()) do
+ begin
+{$endif}
+ { Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: }
+ if buf=nil then
+ error ('block vanished');
+
+ copy_block(buf, cardinal(stored_len), 0); { without header }
+ s.compressed_len := stored_len shl 3;
+ s.method := STORED;
+ end
+ else
+{$endif} { STORED_FILE_OK }
+
+{$ifdef FORCE_STORED}
+ if buf<>nil then
+ begin { force stored block }
+{$else}
+ if (stored_len+4 <= opt_lenb) and (buf <> nil) then
+ begin
+ { 4: two words for the lengths }
+{$endif}
+ { The test buf <> NULL is only necessary if LIT_BUFSIZE > WSIZE.
+ Otherwise we can't have processed more than WSIZE input bytes since
+ the last block flush, because compression would have been
+ successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+ transform a block into a stored block. }
+
+ _tr_stored_block(s, buf, stored_len, eof);
+
+{$ifdef FORCE_STATIC}
+ end
+ else
+ if (static_lenb >= 0) then
+ begin { force static trees }
+{$else}
+ end
+ else
+ if (static_lenb = opt_lenb) then
+ begin
+{$endif}
+ send_bits(s, (STATIC_TREES shl 1)+ord(eof), 3);
+ compress_block(s, static_ltree, static_dtree);
+ inc(s.compressed_len, 3 + s.static_len);
+ end
+ else
+ begin
+ send_bits(s, (DYN_TREES shl 1)+ord(eof), 3);
+ send_all_trees(s, s.l_desc.max_code+1, s.d_desc.max_code+1,
+ max_blindex+1);
+ compress_block(s, s.dyn_ltree, s.dyn_dtree);
+ inc(s.compressed_len, 3 + s.opt_len);
+ end;
+ {$ifdef ZLIB_DEBUG}
+ Assert (s.compressed_len = s.bits_sent, 'bad compressed size');
+ {$ENDIF}
+ init_block(s);
+
+ if (eof) then
+ begin
+ bi_windup(s);
+ inc(s.compressed_len, 7); { align on byte boundary }
+ end;
+ {$ifdef ZLIB_DEBUG}
+ Tracev(#13'comprlen %lu(%lu) {s.compressed_len shr 3,'+
+ 's.compressed_len-7*ord(eof)}');
+ {$ENDIF}
+
+ _tr_flush_block := s.compressed_len shr 3;
+end;
+
+
+{ ===========================================================================
+ Save the match info and tally the frequency counts. Return true if
+ the current block must be flushed. }
+
+function _tr_tally (var s : deflate_state;
+ dist : cardinal; { distance of matched string }
+ lc : cardinal) : boolean; { match length-MIN_MATCH or unmatched char (if dist=0) }
+var
+ {$IFDEF ZLIB_DEBUG}
+ MAX_DIST : word;
+ {$ENDIF}
+ code : word;
+{$ifdef TRUNCATE_BLOCK}
+var
+ out_length : longint;
+ in_length : longint;
+ dcode : integer;
+{$endif}
+begin
+ s.d_buf^[s.last_lit] := word(dist);
+ s.l_buf^[s.last_lit] := byte(lc);
+ inc(s.last_lit);
+ if (dist = 0) then
+ begin
+ { lc is the unmatched char }
+ inc(s.dyn_ltree[lc].fc.Freq);
+ end
+ else
+ begin
+ inc(s.matches);
+ { Here, lc is the match length - MIN_MATCH }
+ dec(dist); { dist := match distance - 1 }
+
+ {macro d_code(dist)}
+ if (dist) < 256 then
+ code := _dist_code[dist]
+ else
+ code := _dist_code[256+(dist shr 7)];
+ {$IFDEF ZLIB_DEBUG}
+{macro MAX_DIST(s) <=> ((s)^.w_size-MIN_LOOKAHEAD)
+ In order to simplify the code, particularly on 16 bit machines, match
+ distances are limited to MAX_DIST instead of WSIZE. }
+ MAX_DIST := word(s.w_size-MIN_LOOKAHEAD);
+ Assert((dist < word(MAX_DIST)) and
+ (word(lc) <= word(MAX_MATCH-MIN_MATCH)) and
+ (word(code) < word(D_CODES)), '_tr_tally: bad match');
+ {$ENDIF}
+ inc(s.dyn_ltree[_length_code[lc]+LITERALS+1].fc.Freq);
+ {s.dyn_dtree[d_code(dist)].Freq++;}
+ inc(s.dyn_dtree[code].fc.Freq);
+ end;
+
+{$ifdef TRUNCATE_BLOCK}
+ { Try to guess if it is profitable to stop the current block here }
+ if (s.last_lit and $1fff = 0) and (s.level > 2) then
+ begin
+ { Compute an upper bound for the compressed length }
+ out_length := longint(s.last_lit)*cardinal(8);
+ in_length := longint(cardinal(s.strstart) - s.block_start);
+ for dcode := 0 to D_CODES-1 do
+ begin
+ inc(out_length, longint(s.dyn_dtree[dcode].fc.Freq *
+ (cardinal(5)+extra_dbits[dcode])) );
+ end;
+ out_length := out_length shr 3;
+ {$ifdef ZLIB_DEBUG}
+ Tracev(^M'last_lit %u, in %ld, out ~%ld(%ld%%) ');
+ { s.last_lit, in_length, out_length,
+ cardinal(100) - out_length*100 div in_length)); }
+ {$ENDIF}
+ if (s.matches < s.last_lit div 2) and (out_length < in_length div 2) then
+ begin
+ _tr_tally := TRUE;
+ exit;
+ end;
+ end;
+{$endif}
+ _tr_tally := (s.last_lit = s.lit_bufsize-1);
+ { We avoid equality with lit_bufsize because of wraparound at 64K
+ on 16 bit machines and because stored blocks are restricted to
+ 64K-1 bytes. }
+end;
+
+end.
diff --git a/packages/paszlib/src/unzip.pas b/packages/paszlib/src/unzip.pas
new file mode 100644
index 0000000000..575e59b247
--- /dev/null
+++ b/packages/paszlib/src/unzip.pas
@@ -0,0 +1,1559 @@
+unit Unzip;
+
+{ ----------------------------------------------------------------- }
+{ unzip.c -- IO on .zip files using zlib
+ Version 0.15 beta, Mar 19th, 1998,
+ unzip.h -- IO for uncompress .zip files using zlib
+ Version 0.15 beta, Mar 19th, 1998,
+
+ Copyright (C) 1998 Gilles Vollant <info@winimage.com>
+ http://www.winimage.com/zLibDll/zip.htm
+
+ This unzip package allow extract file from .ZIP file, compatible
+ with PKZip 2.04g, WinZip, InfoZip tools and compatible.
+ Encryption and multi volume ZipFile (span) are not supported.
+ Old compressions used by old PKZip 1.x are not supported
+
+ Pascal tranlastion
+ Copyright (C) 2000 by Jacques Nomssi Nzali
+ For conditions of distribution and use, see copyright notice in readme.txt }
+
+
+interface
+
+{$ifdef WIN32}
+ {$define Delphi}
+{$endif}
+
+uses
+ //zutil,
+ zbase,
+ //zLib,
+ ziputils;
+
+const
+ UNZ_OK = (0);
+ UNZ_END_OF_LIST_OF_FILE = (-100);
+ UNZ_ERRNO = (Z_ERRNO);
+ UNZ_EOF = (0);
+ UNZ_PARAMERROR = (-102);
+ UNZ_BADZIPFILE = (-103);
+ UNZ_INTERNALERROR = (-104);
+ UNZ_CRCERROR = (-105);
+(*
+{ tm_unz contain date/time info }
+type
+ tm_unz = record
+ tm_sec : integer; { seconds after the minute - [0,59] }
+ tm_min : integer; { minutes after the hour - [0,59] }
+ tm_hour : integer; { hours since midnight - [0,23] }
+ tm_mday : integer; { day of the month - [1,31] }
+ tm_mon : integer; { months since January - [0,11] }
+ tm_year : integer; { years - [1980..2044] }
+ end;
+*)
+{ unz_global_info structure contain global data about the ZIPfile
+ These data comes from the end of central dir }
+type
+ unz_global_info = record
+ number_entry: longint; { total number of entries in
+ the central dir on this disk }
+ size_comment: longint; { size of the global comment of the zipfile }
+ end;
+
+
+{ unz_file_info contain information about a file in the zipfile }
+type
+ unz_file_info = record
+ version: longint; { version made by 2 bytes }
+ version_needed: longint; { version needed to extract 2 bytes }
+ flag: longint; { general purpose bit flag 2 bytes }
+ compression_method: longint; { compression method 2 bytes }
+ dosDate: longint; { last mod file date in Dos fmt 4 bytes }
+ crc: longint; { crc-32 4 bytes }
+ compressed_size: longint; { compressed size 4 bytes }
+ uncompressed_size: longint; { uncompressed size 4 bytes }
+ size_filename: longint; { filename length 2 bytes }
+ size_file_extra: longint; { extra field length 2 bytes }
+ size_file_comment: longint; { file comment length 2 bytes }
+
+ disk_num_start: longint; { disk number start 2 bytes }
+ internal_fa: longint; { internal file attributes 2 bytes }
+ external_fa: longint; { external file attributes 4 bytes }
+
+ tmu_date: tm_unz;
+ end;
+ unz_file_info_ptr = ^unz_file_info;
+
+
+function unzStringFileNameCompare(const fileName1: PChar; const fileName2: PChar; iCaseSensitivity: longint): longint;
+{ Compare two filename (fileName1,fileName2).
+ If iCaseSenisivity = 1 (1=true),
+ comparision is case sensitive (like strcmp)
+ If iCaseSenisivity = 2 (0=false),
+ comparision is not case sensitive (like strcmpi or strcasecmp)
+ If iCaseSenisivity = 0, case sensitivity is defaut of your
+ operating system like 1 on Unix, 2 on Windows)
+}
+
+
+function unzOpen(const path: PChar): unzFile;
+
+{ Open a Zip file. path contain the full pathname (by example,
+ on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer
+ "zlib/zlib111.zip".
+ If the zipfile cannot be opened (file don't exist or in not valid), the
+ return value is NIL.
+ Else, the return value is a unzFile Handle, usable with other function
+ of this unzip package.
+}
+
+function unzClose(afile: unzFile): longint;
+
+{ Close a ZipFile opened with unzipOpen.
+ If there are files inside the .Zip opened with unzOpenCurrentFile()
+ (see later), these files MUST be closed with unzipCloseCurrentFile()
+ before a call unzipClose.
+ return UNZ_OK if there is no problem. }
+
+function unzGetGlobalInfo(afile: unzFile; var pglobal_info: unz_global_info): longint;
+
+{ Write info about the ZipFile in the *pglobal_info structure.
+ No preparation of the structure is needed
+ return UNZ_OK if there is no problem. }
+
+function unzGetGlobalComment(afile: unzFile; szComment: PChar; uSizeBuf: longint): longint;
+
+{ Get the global comment string of the ZipFile, in the szComment buffer.
+ uSizeBuf is the size of the szComment buffer.
+ return the number of byte copied or an error code <0 }
+
+ {***************************************************************************}
+ { Unzip package allow you browse the directory of the zipfile }
+
+function unzGoToFirstFile(afile: unzFile): longint;
+
+{ Set the current file of the zipfile to the first file.
+ return UNZ_OK if there is no problem }
+
+function unzGoToNextFile(afile: unzFile): longint;
+
+{ Set the current file of the zipfile to the next file.
+ return UNZ_OK if there is no problem
+ return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. }
+
+
+function unzLocateFile(afile: unzFile; const szFileName: PChar; iCaseSensitivity: longint): longint; { ZEXPORT }
+
+{ Try locate the file szFileName in the zipfile.
+ For the iCaseSensitivity signification, see unzStringFileNameCompare
+
+ return value :
+ UNZ_OK if the file is found. It becomes the current file.
+ UNZ_END_OF_LIST_OF_FILE if the file is not found }
+
+
+function unzGetCurrentFileInfo(afile: unzFile; pfile_info: unz_file_info_ptr; szFileName: PChar; fileNameBufferSize: longint; extraField: pointer; extraFieldBufferSize: longint; szComment: PChar; commentBufferSize: longint): longint; { ZEXPORT }
+
+{ Get Info about the current file
+ if pfile_info<>NIL, the pfile_info^ structure will contain somes
+ info about the current file
+ if szFileName<>NIL, the filemane string will be copied in szFileName
+ (fileNameBufferSize is the size of the buffer)
+ if extraField<>NIL, the extra field information will be copied in
+ extraField (extraFieldBufferSize is the size of the buffer).
+ This is the Central-header version of the extra field
+ if szComment<>NIL, the comment string of the file will be copied in
+ szComment (commentBufferSize is the size of the buffer) }
+
+
+{***************************************************************************}
+{* for reading the content of the current zipfile, you can open it, read data
+ from it, and close it (you can close it before reading all the file) }
+
+
+function unzOpenCurrentFile(afile: unzFile): longint; { ZEXPORT }
+
+{ Open for reading data the current file in the zipfile.
+ If there is no error, the return value is UNZ_OK. }
+
+
+function unzCloseCurrentFile(afile: unzFile): longint; { ZEXPORT }
+
+{ Close the file in zip opened with unzOpenCurrentFile
+ Return UNZ_CRCERROR if all the file was read but the CRC is not good }
+
+
+function unzReadCurrentFile(afile: unzFile; buf: pointer; len: cardinal): longint; { ZEXPORT }
+
+{ Read bytes from the current file (opened by unzOpenCurrentFile)
+ buf contain buffer where data must be copied
+ len the size of buf.
+
+ return the number of byte copied if somes bytes are copied
+ return 0 if the end of file was reached
+ return <0 with error code if there is an error
+ (UNZ_ERRNO for IO error, or zLib error for uncompress error) }
+
+function unztell(afile: unzFile): z_off_t;
+
+{ Give the current position in uncompressed data }
+
+function unzeof(afile: unzFile): longint;
+
+{ return 1 if the end of file was reached, 0 elsewhere
+ ! checks for valid params }
+
+function unzGetLocalExtrafield(afile: unzFile; buf: pointer; len: cardinal): longint;
+{ Read extra field from the current file (opened by unzOpenCurrentFile)
+ This is the local-header version of the extra field (sometimes, there is
+ more info in the local-header version than in the central-header)
+
+ if buf=NIL, it return the size of the local extra field
+
+ if buf<>NIL, len is the size of the buffer, the extra header is copied in
+ buf.
+ the return value is the number of bytes copied in buf, or (if <0)
+ the error code }
+
+
+{ ----------------------------------------------------------------- }
+
+implementation
+
+uses
+ {$ifdef Delphi}
+ SysUtils,
+ {$else}
+ strings,
+ {$endif}
+ zInflate, crc;
+
+{$ifdef unix and not def (CASESENSITIVITYDEFAULT_YES) and \
+ !defined(CASESENSITIVITYDEFAULT_NO)}
+{$define CASESENSITIVITYDEFAULT_NO}
+{$endif}
+
+
+const
+ UNZ_BUFSIZE = Z_BUFSIZE;
+ UNZ_MAXFILENAMEINZIP = Z_MAXFILENAMEINZIP;
+
+const
+ unz_copyright: PChar = ' unzip 0.15 Copyright 1998 Gilles Vollant ';
+
+{ unz_file_info_internal contain internal info about a file in zipfile }
+type
+ unz_file_info_internal = record
+ offset_curfile: longint; { relative offset of local header 4 bytes }
+ end;
+ unz_file_info_internal_ptr = ^unz_file_info_internal;
+
+
+{ file_in_zip_read_info_s contain internal information about a file
+ in zipfile, when reading and decompress it }
+type
+ file_in_zip_read_info_s = record
+ read_buffer: PChar; { internal buffer for compressed data }
+ stream: z_stream; { zLib stream structure for inflate }
+
+ pos_in_zipfile: longint; { position in byte on the zipfile, for fseek}
+ stream_initialised: boolean; { flag set if stream structure is initialised}
+
+ offset_local_extrafield: longint; { offset of the local extra field }
+ size_local_extrafield: integer; { size of the local extra field }
+ pos_local_extrafield: longint; { position in the local extra field in read}
+
+ crc32: longint; { crc32 of all data uncompressed }
+ crc32_wait: longint; { crc32 we must obtain after decompress all }
+ rest_read_compressed: longint; { number of byte to be decompressed }
+ rest_read_uncompressed: longint; {number of byte to be obtained after decomp}
+ afile: FILEptr; { io structure of the zipfile }
+ compression_method: longint; { compression method (0=store) }
+ byte_before_the_zipfile: longint; { byte before the zipfile, (>0 for sfx) }
+ end;
+ file_in_zip_read_info_s_ptr = ^file_in_zip_read_info_s;
+
+
+{ unz_s contain internal information about the zipfile }
+type
+ unz_s = record
+ afile: FILEptr; { io structore of the zipfile }
+ gi: unz_global_info; { public global information }
+ byte_before_the_zipfile: longint; { byte before the zipfile, (>0 for sfx)}
+ num_file: longint; { number of the current file in the zipfile}
+ pos_in_central_dir: longint; { pos of the current file in the central dir}
+ current_file_ok: boolean; { flag about the usability of the current file}
+ central_pos: longint; { position of the beginning of the central dir}
+
+ size_central_dir: longint; { size of the central directory }
+ offset_central_dir: longint; { offset of start of central directory with
+ respect to the starting disk number }
+
+ cur_file_info: unz_file_info; { public info about the current file in zip}
+ cur_file_info_internal: unz_file_info_internal; { private info about it}
+ pfile_in_zip_read: file_in_zip_read_info_s_ptr; { structure about the current
+ file if we are decompressing it }
+ end;
+ unz_s_ptr = ^unz_s;
+
+
+{ ===========================================================================
+ Read a byte from a gz_stream; update next_in and avail_in. Return EOF
+ for end of file.
+ IN assertion: the stream s has been sucessfully opened for reading. }
+
+
+function unzlocal_getByte(fin: FILEptr; var pi: longint): longint;
+var
+ c: byte;
+ err: longint;
+begin
+ err := fread(@c, 1, 1, fin);
+
+ if (err = 1) then
+ begin
+ pi := longint(c);
+ unzlocal_getByte := UNZ_OK;
+ {exit;}
+ end
+ else
+ if feof(fin) = 1 then {if ferror(fin) then}
+ unzlocal_getByte := UNZ_ERRNO
+ else
+ unzlocal_getByte := UNZ_EOF{exit;};
+end;
+
+
+{ ===========================================================================
+ Reads a long in LSB order from the given gz_stream. Sets }
+
+function unzlocal_getShort(fin: FILEptr; var pX: longint): longint;
+var
+ x: longint;
+ i: longint;
+ err: longint;
+begin
+ err := unzlocal_getByte(fin, i);
+ x := longint(i);
+
+ if (err = UNZ_OK) then
+ err := unzlocal_getByte(fin, i);
+ Inc(x, longint(i) shl 8);
+
+ if (err = UNZ_OK) then
+ pX := x
+ else
+ pX := 0;
+ unzlocal_getShort := err;
+end;
+
+function unzlocal_getLong(fin: FILEptr; var pX: longint): longint;
+var
+ x: longint;
+ i: longint;
+ err: longint;
+begin
+ err := unzlocal_getByte(fin, i);
+ x := longint(i);
+
+ if (err = UNZ_OK) then
+ err := unzlocal_getByte(fin, i);
+ Inc(x, longint(i) shl 8);
+
+ if (err = UNZ_OK) then
+ err := unzlocal_getByte(fin, i);
+ Inc(x, longint(i) shl 16);
+
+ if (err = UNZ_OK) then
+ err := unzlocal_getByte(fin, i);
+ Inc(x, longint(i) shl 24);
+
+ if (err = UNZ_OK) then
+ pX := x
+ else
+ pX := 0;
+ unzlocal_getLong := err;
+end;
+
+
+{ My own strcmpi / strcasecmp }
+function strcmpcasenosensitive_internal(fileName1: PChar; fileName2: PChar): longint;
+var
+ c1, c2: char;
+begin
+ repeat
+ c1 := fileName1^;
+ Inc(fileName1);
+ c2 := fileName2^;
+ Inc(fileName2);
+ if (c1 >= 'a') and (c1 <= 'z') then
+ Dec(c1, $20);
+ if (c2 >= 'a') and (c2 <= 'z') then
+ Dec(c2, $20);
+ if (c1 = #0) then
+ begin
+ if c2 = #0 then
+ strcmpcasenosensitive_internal := 0
+ else
+ strcmpcasenosensitive_internal := -1;
+ exit;
+ end;
+ if (c2 = #0) then
+ begin
+ strcmpcasenosensitive_internal := 1;
+ exit;
+ end;
+ if (c1 < c2) then
+ begin
+ strcmpcasenosensitive_internal := -1;
+ exit;
+ end;
+ if (c1 > c2) then
+ begin
+ strcmpcasenosensitive_internal := 1;
+ exit;
+ end;
+ until False;
+end;
+
+
+const
+ CASESENSITIVITYDEFAULTVALUE = 2;
+
+function unzStringFileNameCompare(const fileName1: PChar; const fileName2: PChar; iCaseSensitivity: longint): longint; { ZEXPORT }
+{ Compare two filename (fileName1,fileName2).
+ If iCaseSenisivity = 1 (1=true),
+ comparision is case sensitive (like strcmp)
+ If iCaseSenisivity = 2 (0=false),
+ comparision is not case sensitive (like strcmpi or strcasecmp)
+ If iCaseSenisivity = 0, case sensitivity is defaut of your
+ operating system like 1 on Unix, 2 on Windows)
+}
+begin
+ if (iCaseSensitivity = 0) then
+ iCaseSensitivity := CASESENSITIVITYDEFAULTVALUE;
+
+ if (iCaseSensitivity = 1) then
+ begin
+ unzStringFileNameCompare := strComp(fileName1, fileName2);
+ exit;
+ end;
+
+ unzStringFileNameCompare := strcmpcasenosensitive_internal(fileName1, fileName2);
+end;
+
+const
+ BUFREADCOMMENT = $400;
+
+{ Locate the Central directory of a zipfile (at the end, just before
+ the global comment) }
+
+function unzlocal_SearchCentralDir(fin: FILEptr): longint;
+var
+ buf: Pbytearray;
+ uSizeFile: longint;
+ uBackRead: longint;
+ uMaxBack: longint;
+ uPosFound: longint;
+var
+ uReadSize, uReadPos: longint;
+ i: longint;
+begin
+ uMaxBack := $ffff; { maximum size of global comment }
+ uPosFound := 0;
+
+ if (fseek(fin, 0, SEEK_END) <> 0) then
+ begin
+ unzlocal_SearchCentralDir := 0;
+ exit;
+ end;
+
+ uSizeFile := ftell(fin);
+
+ if (uMaxBack > uSizeFile) then
+ uMaxBack := uSizeFile;
+
+ buf := Pbytearray(AllocMem(BUFREADCOMMENT + 4));
+ if (buf = nil) then
+ begin
+ unzlocal_SearchCentralDir := 0;
+ exit;
+ end;
+
+ uBackRead := 4;
+ while (uBackRead < uMaxBack) do
+ begin
+
+ if (uBackRead + BUFREADCOMMENT > uMaxBack) then
+ uBackRead := uMaxBack
+ else
+ Inc(uBackRead, BUFREADCOMMENT);
+ uReadPos := uSizeFile - uBackRead;
+
+ if ((BUFREADCOMMENT + 4) < (uSizeFile - uReadPos)) then
+ uReadSize := (BUFREADCOMMENT + 4)
+ else
+ uReadSize := (uSizeFile - uReadPos);
+
+ if fseek(fin, uReadPos, SEEK_SET) <> 0 then
+ break;
+
+ if fread(buf, integer(uReadSize), 1, fin) <> 1 then
+ break;
+
+ i := longint(uReadSize) - 3;
+ while (i > 0) do
+ begin
+ Dec(i);
+ if (buf^[i] = $50) and (buf^[i + 1] = $4b) and { ENDHEADERMAGIC }
+ (buf^[i + 2] = $05) and (buf^[i + 3] = $06) then
+ begin
+ uPosFound := uReadPos + integer(i);
+ break;
+ end;
+ end;
+
+ if (uPosFound <> 0) then
+ break;
+ end;
+ FreeMem(buf);
+ unzlocal_SearchCentralDir := uPosFound;
+end;
+
+
+{ Open a Zip file. path contain the full pathname (by example,
+ on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer
+ "zlib/zlib111.zip".
+ If the zipfile cannot be opened (file don't exist or in not valid), the
+ return value is NIL.
+ Else, the return value is a unzFile Handle, usable with other function
+ of this unzip package.
+}
+
+function unzOpen(const path: PChar): unzFile; { ZEXPORT }
+var
+ us: unz_s;
+ s: unz_s_ptr;
+ central_pos, uL: longint;
+ fin: FILEptr;
+
+ number_disk: longint; { number of the current dist, used for spaning ZIP,
+ unsupported, always 0 }
+ number_disk_with_CD: longint; { number the the disk with central dir,
+ used for spaning ZIP, unsupported, always 0 }
+ number_entry_CD: longint; { total number of entries in the central dir
+ (same than number_entry on nospan) }
+
+ err: longint;
+begin
+ err := UNZ_OK;
+
+ if (unz_copyright[0] <> ' ') then
+ begin
+ unzOpen := nil;
+ exit;
+ end;
+
+ fin := fopen(path, fopenread);
+ if (fin = nil) then
+ begin
+ unzOpen := nil;
+ exit;
+ end;
+
+ central_pos := unzlocal_SearchCentralDir(fin);
+ if (central_pos = 0) then
+ err := UNZ_ERRNO;
+
+ if (fseek(fin, central_pos, SEEK_SET) <> 0) then
+ err := UNZ_ERRNO;
+
+ { the signature, already checked }
+ if (unzlocal_getLong(fin, uL) <> UNZ_OK) then
+ err := UNZ_ERRNO;
+
+ { number of this disk }
+ if (unzlocal_getShort(fin, number_disk) <> UNZ_OK) then
+ err := UNZ_ERRNO;
+
+ { number of the disk with the start of the central directory }
+ if (unzlocal_getShort(fin, number_disk_with_CD) <> UNZ_OK) then
+ err := UNZ_ERRNO;
+
+ { total number of entries in the central dir on this disk }
+ if (unzlocal_getShort(fin, us.gi.number_entry) <> UNZ_OK) then
+ err := UNZ_ERRNO;
+
+ { total number of entries in the central dir }
+ if (unzlocal_getShort(fin, number_entry_CD) <> UNZ_OK) then
+ err := UNZ_ERRNO;
+
+ if ((number_entry_CD <> us.gi.number_entry) or
+ (number_disk_with_CD <> 0) or
+ (number_disk <> 0)) then
+ err := UNZ_BADZIPFILE;
+
+ { size of the central directory }
+ if (unzlocal_getLong(fin, us.size_central_dir) <> UNZ_OK) then
+ err := UNZ_ERRNO;
+
+ { offset of start of central directory with respect to the
+ starting disk number }
+ if (unzlocal_getLong(fin, us.offset_central_dir) <> UNZ_OK) then
+ err := UNZ_ERRNO;
+
+ { zipfile comment length }
+ if (unzlocal_getShort(fin, us.gi.size_comment) <> UNZ_OK) then
+ err := UNZ_ERRNO;
+
+ if ((central_pos < us.offset_central_dir + us.size_central_dir) and
+ (err = UNZ_OK)) then
+ err := UNZ_BADZIPFILE;
+
+ if (err <> UNZ_OK) then
+ begin
+ fclose(fin);
+ unzOpen := nil;
+ exit;
+ end;
+
+ us.afile := fin;
+ us.byte_before_the_zipfile := central_pos -
+ (us.offset_central_dir + us.size_central_dir);
+ us.central_pos := central_pos;
+ us.pfile_in_zip_read := nil;
+
+ s := unz_s_ptr(AllocMem(sizeof(unz_s)));
+ s^ := us;
+ unzGoToFirstFile(unzFile(s));
+ unzOpen := unzFile(s);
+end;
+
+
+{ Close a ZipFile opened with unzipOpen.
+ If there are files inside the .Zip opened with unzOpenCurrentFile()
+ (see later), these files MUST be closed with unzipCloseCurrentFile()
+ before a call unzipClose.
+ return UNZ_OK if there is no problem. }
+
+function unzClose(afile: unzFile): longint; { ZEXPORT }
+var
+ s: unz_s_ptr;
+begin
+ if (afile = nil) then
+ begin
+ unzClose := UNZ_PARAMERROR;
+ exit;
+ end;
+ s := unz_s_ptr(afile);
+
+ if (s^.pfile_in_zip_read <> nil) then
+ unzCloseCurrentFile(afile);
+
+ fclose(s^.afile);
+ FreeMem(s);
+ unzClose := UNZ_OK;
+end;
+
+{ Write info about the ZipFile in the pglobal_info structure.
+ No preparation of the structure is needed
+ return UNZ_OK if there is no problem. }
+
+function unzGetGlobalInfo(afile: unzFile; var pglobal_info: unz_global_info): longint; { ZEXPORT }
+var
+ s: unz_s_ptr;
+begin
+ if (afile = nil) then
+ begin
+ unzGetGlobalInfo := UNZ_PARAMERROR;
+ exit;
+ end;
+ s := unz_s_ptr(afile);
+ pglobal_info := s^.gi;
+ unzGetGlobalInfo := UNZ_OK;
+end;
+
+
+{ Translate date/time from Dos format to tm_unz (more easily readable) }
+procedure unzlocal_DosDateToTmuDate(ulDosDate: longint; var ptm: tm_unz);
+var
+ uDate: longint;
+begin
+ uDate := longint(ulDosDate shr 16);
+ ptm.tm_mday := integer(uDate and $1f);
+ ptm.tm_mon := integer((((uDate) and $1E0) div $20) - 1);
+ ptm.tm_year := integer(((uDate and $0FE00) div $0200) + 1980);
+
+ ptm.tm_hour := integer((ulDosDate and $F800) div $800);
+ ptm.tm_min := integer((ulDosDate and $7E0) div $20);
+ ptm.tm_sec := integer(2 * (ulDosDate and $1f));
+end;
+
+{ Get Info about the current file in the zipfile, with internal only info }
+function unzlocal_GetCurrentFileInfoInternal(afile: unzFile; pfile_info: unz_file_info_ptr; pfile_info_internal: unz_file_info_internal_ptr; szFileName: PChar; fileNameBufferSize: longint; extraField: pointer; extraFieldBufferSize: longint; szComment: PChar; commentBufferSize: longint): longint;
+var
+ s: unz_s_ptr;
+ file_info: unz_file_info;
+ file_info_internal: unz_file_info_internal;
+ err: longint;
+ uMagic: longint;
+ lSeek: longint;
+var
+ uSizeRead: longint;
+begin
+ err := UNZ_OK;
+ lSeek := 0;
+ if (afile = nil) then
+ begin
+ unzlocal_GetCurrentFileInfoInternal := UNZ_PARAMERROR;
+ exit;
+ end;
+ s := unz_s_ptr(afile);
+
+ if (fseek(s^.afile,
+ s^.pos_in_central_dir + s^.byte_before_the_zipfile, SEEK_SET) <> 0) then
+ err := UNZ_ERRNO;
+
+ { we check the magic }
+ if (err = UNZ_OK) then
+ if (unzlocal_getLong(s^.afile, uMagic) <> UNZ_OK) then
+ err := UNZ_ERRNO
+ else
+ if (uMagic <> CENTRALHEADERMAGIC) then
+ err := UNZ_BADZIPFILE;
+
+ if (unzlocal_getShort(s^.afile, file_info.version) <> UNZ_OK) then
+ err := UNZ_ERRNO;
+
+ if (unzlocal_getShort(s^.afile, file_info.version_needed) <> UNZ_OK) then
+ err := UNZ_ERRNO;
+
+ if (unzlocal_getShort(s^.afile, file_info.flag) <> UNZ_OK) then
+ err := UNZ_ERRNO;
+
+ if (unzlocal_getShort(s^.afile, file_info.compression_method) <> UNZ_OK) then
+ err := UNZ_ERRNO;
+
+ if (unzlocal_getLong(s^.afile, file_info.dosDate) <> UNZ_OK) then
+ err := UNZ_ERRNO;
+
+ unzlocal_DosDateToTmuDate(file_info.dosDate, file_info.tmu_date);
+
+ if (unzlocal_getLong(s^.afile, file_info.crc) <> UNZ_OK) then
+ err := UNZ_ERRNO;
+
+ if (unzlocal_getLong(s^.afile, file_info.compressed_size) <> UNZ_OK) then
+ err := UNZ_ERRNO;
+
+ if (unzlocal_getLong(s^.afile, file_info.uncompressed_size) <> UNZ_OK) then
+ err := UNZ_ERRNO;
+
+ if (unzlocal_getShort(s^.afile, file_info.size_filename) <> UNZ_OK) then
+ err := UNZ_ERRNO;
+
+ if (unzlocal_getShort(s^.afile, file_info.size_file_extra) <> UNZ_OK) then
+ err := UNZ_ERRNO;
+
+ if (unzlocal_getShort(s^.afile, file_info.size_file_comment) <> UNZ_OK) then
+ err := UNZ_ERRNO;
+
+ if (unzlocal_getShort(s^.afile, file_info.disk_num_start) <> UNZ_OK) then
+ err := UNZ_ERRNO;
+
+ if (unzlocal_getShort(s^.afile, file_info.internal_fa) <> UNZ_OK) then
+ err := UNZ_ERRNO;
+
+ if (unzlocal_getLong(s^.afile, file_info.external_fa) <> UNZ_OK) then
+ err := UNZ_ERRNO;
+
+ if (unzlocal_getLong(s^.afile, file_info_internal.offset_curfile) <> UNZ_OK) then
+ err := UNZ_ERRNO;
+
+ Inc(lSeek, file_info.size_filename);
+ if ((err = UNZ_OK) and (szFileName <> nil)) then
+ begin
+ if (file_info.size_filename < fileNameBufferSize) then
+ begin
+ (szFileName +file_info.size_filename)^ := #0;
+ uSizeRead := file_info.size_filename;
+ end
+ else
+ uSizeRead := fileNameBufferSize;
+
+ if (file_info.size_filename > 0) and (fileNameBufferSize > 0) then
+ if fread(szFileName, integer(uSizeRead), 1, s^.afile) <> 1 then
+ err := UNZ_ERRNO;
+ Dec(lSeek, uSizeRead);
+ end;
+
+ if ((err = UNZ_OK) and (extraField <> nil)) then
+ begin
+ if (file_info.size_file_extra < extraFieldBufferSize) then
+ uSizeRead := file_info.size_file_extra
+ else
+ uSizeRead := extraFieldBufferSize;
+
+ if (lSeek <> 0) then
+ if (fseek(s^.afile, lSeek, SEEK_CUR) = 0) then
+ lSeek := 0
+ else
+ err := UNZ_ERRNO;
+
+ if ((file_info.size_file_extra > 0) and (extraFieldBufferSize > 0)) then
+ if fread(extraField, integer(uSizeRead), 1, s^.afile) <> 1 then
+ err := UNZ_ERRNO;
+ Inc(lSeek, file_info.size_file_extra - uSizeRead);
+ end
+ else
+ Inc(lSeek, file_info.size_file_extra);
+
+ if ((err = UNZ_OK) and (szComment <> nil)) then
+ begin
+ if (file_info.size_file_comment < commentBufferSize) then
+ begin
+ (szComment +file_info.size_file_comment)^ := #0;
+ uSizeRead := file_info.size_file_comment;
+ end
+ else
+ uSizeRead := commentBufferSize;
+
+ if (lSeek <> 0) then
+ if (fseek(s^.afile, lSeek, SEEK_CUR) = 0) then
+ lSeek := 0
+ else
+ err := UNZ_ERRNO;
+ if ((file_info.size_file_comment > 0) and (commentBufferSize > 0)) then
+ if fread(szComment, integer(uSizeRead), 1, s^.afile) <> 1 then
+ err := UNZ_ERRNO;
+ Inc(lSeek, file_info.size_file_comment - uSizeRead);
+ end
+ else
+ Inc(lSeek, file_info.size_file_comment);
+
+ if ((err = UNZ_OK) and (pfile_info <> nil)) then
+ pfile_info^ := file_info;
+
+ if ((err = UNZ_OK) and (pfile_info_internal <> nil)) then
+ pfile_info_internal^ := file_info_internal;
+
+ unzlocal_GetCurrentFileInfoInternal := err;
+end;
+
+
+{ Write info about the ZipFile in the *pglobal_info structure.
+ No preparation of the structure is needed
+ return UNZ_OK if there is no problem. }
+
+function unzGetCurrentFileInfo(afile: unzFile; pfile_info: unz_file_info_ptr; szFileName: PChar; fileNameBufferSize: longint; extraField: pointer; extraFieldBufferSize: longint; szComment: PChar; commentBufferSize: longint): longint; { ZEXPORT }
+
+{ Get Info about the current file
+ if pfile_info<>NIL, the pfile_info^ structure will contain somes
+ info about the current file
+ if szFileName<>NIL, the filemane string will be copied in szFileName
+ (fileNameBufferSize is the size of the buffer)
+ if extraField<>NIL, the extra field information will be copied in
+ extraField (extraFieldBufferSize is the size of the buffer).
+ This is the Central-header version of the extra field
+ if szComment<>NIL, the comment string of the file will be copied in
+ szComment (commentBufferSize is the size of the buffer) }
+
+begin
+ unzGetCurrentFileInfo := unzlocal_GetCurrentFileInfoInternal(afile,
+ pfile_info, nil, szFileName, fileNameBufferSize, extraField,
+ extraFieldBufferSize, szComment, commentBufferSize);
+end;
+
+
+{ Set the current file of the zipfile to the first file.
+ return UNZ_OK if there is no problem }
+
+function unzGoToFirstFile(afile: unzFile): longint; { ZEXPORT }
+var
+ err: longint;
+ s: unz_s_ptr;
+begin
+ if (afile = nil) then
+ begin
+ unzGoToFirstFile := UNZ_PARAMERROR;
+ exit;
+ end;
+ s := unz_s_ptr(afile);
+ s^.pos_in_central_dir := s^.offset_central_dir;
+ s^.num_file := 0;
+ err := unzlocal_GetCurrentFileInfoInternal(afile, @s^.cur_file_info, @s^.cur_file_info_internal, nil, 0, nil, 0, nil, 0);
+ s^.current_file_ok := (err = UNZ_OK);
+ unzGoToFirstFile := err;
+end;
+
+
+{ Set the current file of the zipfile to the next file.
+ return UNZ_OK if there is no problem
+ return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. }
+
+function unzGoToNextFile(afile: unzFile): longint; { ZEXPORT }
+var
+ s: unz_s_ptr;
+ err: longint;
+begin
+ if (afile = nil) then
+ begin
+ unzGoToNextFile := UNZ_PARAMERROR;
+ exit;
+ end;
+ s := unz_s_ptr(afile);
+ if not s^.current_file_ok then
+ begin
+ unzGoToNextFile := UNZ_END_OF_LIST_OF_FILE;
+ exit;
+ end;
+ if (s^.num_file + 1 = s^.gi.number_entry) then
+ begin
+ unzGoToNextFile := UNZ_END_OF_LIST_OF_FILE;
+ exit;
+ end;
+
+ Inc(s^.pos_in_central_dir,
+ SIZECENTRALDIRITEM + s^.cur_file_info.size_filename +
+ s^.cur_file_info.size_file_extra + s^.cur_file_info.size_file_comment);
+ Inc(s^.num_file);
+ err := unzlocal_GetCurrentFileInfoInternal(afile, @s^.cur_file_info, @s^.cur_file_info_internal, nil, 0, nil, 0, nil, 0);
+ s^.current_file_ok := (err = UNZ_OK);
+ unzGoToNextFile := err;
+end;
+
+
+{ Try locate the file szFileName in the zipfile.
+ For the iCaseSensitivity signification, see unzStringFileNameCompare
+
+ return value :
+ UNZ_OK if the file is found. It becomes the current file.
+ UNZ_END_OF_LIST_OF_FILE if the file is not found }
+
+function unzLocateFile(afile: unzFile; const szFileName: PChar; iCaseSensitivity: longint): longint; { ZEXPORT }
+var
+ s: unz_s_ptr;
+ err: longint;
+ num_fileSaved: longint;
+ pos_in_central_dirSaved: longint;
+var
+ szCurrentFileName: array[0..UNZ_MAXFILENAMEINZIP + 1 - 1] of char;
+begin
+ if (afile = nil) then
+ begin
+ unzLocateFile := UNZ_PARAMERROR;
+ exit;
+ end;
+
+ if (strlen(szFileName) >= UNZ_MAXFILENAMEINZIP) then
+ begin
+ unzLocateFile := UNZ_PARAMERROR;
+ exit;
+ end;
+
+ s := unz_s_ptr(afile);
+ if (not s^.current_file_ok) then
+ begin
+ unzLocateFile := UNZ_END_OF_LIST_OF_FILE;
+ exit;
+ end;
+ num_fileSaved := s^.num_file;
+ pos_in_central_dirSaved := s^.pos_in_central_dir;
+
+ err := unzGoToFirstFile(afile);
+
+ while (err = UNZ_OK) do
+ begin
+ unzGetCurrentFileInfo(afile, nil,
+ szCurrentFileName, sizeof(szCurrentFileName) - 1, nil, 0, nil, 0);
+ if (unzStringFileNameCompare(szCurrentFileName,
+ szFileName, iCaseSensitivity) = 0) then
+ begin
+ unzLocateFile := UNZ_OK;
+ exit;
+ end;
+ err := unzGoToNextFile(afile);
+ end;
+
+ s^.num_file := num_fileSaved;
+ s^.pos_in_central_dir := pos_in_central_dirSaved;
+ unzLocateFile := err;
+end;
+
+
+{ Read the local header of the current zipfile
+ Check the coherency of the local header and info in the end of central
+ directory about this file
+ store in *piSizeVar the size of extra info in local header
+ (filename and size of extra field data) }
+
+function unzlocal_CheckCurrentFileCoherencyHeader(s: unz_s_ptr; var piSizeVar: integer; var poffset_local_extrafield: longint; var psize_local_extrafield: integer): longint;
+var
+ uMagic, uData, uFlags: longint;
+ size_filename: longint;
+ size_extra_field: longint;
+ err: longint;
+begin
+ err := UNZ_OK;
+
+ piSizeVar := 0;
+ poffset_local_extrafield := 0;
+ psize_local_extrafield := 0;
+
+ if (fseek(s^.afile, s^.cur_file_info_internal.offset_curfile +
+ s^.byte_before_the_zipfile, SEEK_SET) <> 0) then
+ begin
+ unzlocal_CheckCurrentFileCoherencyHeader := UNZ_ERRNO;
+ exit;
+ end;
+
+ if (err = UNZ_OK) then
+ if (unzlocal_getLong(s^.afile, uMagic) <> UNZ_OK) then
+ err := UNZ_ERRNO
+ else
+ if (uMagic <> $04034b50) then
+ err := UNZ_BADZIPFILE;
+
+ if (unzlocal_getShort(s^.afile, uData) <> UNZ_OK) then
+ err := UNZ_ERRNO;
+{
+ else
+ if ((err=UNZ_OK) and (uData<>s^.cur_file_info.wVersion)) then
+ err := UNZ_BADZIPFILE;
+}
+ if (unzlocal_getShort(s^.afile, uFlags) <> UNZ_OK) then
+ err := UNZ_ERRNO;
+
+ if (unzlocal_getShort(s^.afile, uData) <> UNZ_OK) then
+ err := UNZ_ERRNO
+ else
+ if ((err = UNZ_OK) and (uData <> s^.cur_file_info.compression_method)) then
+ err := UNZ_BADZIPFILE;
+
+ if ((err = UNZ_OK) and (s^.cur_file_info.compression_method <> 0) and
+ (s^.cur_file_info.compression_method <> Z_DEFLATED)) then
+ err := UNZ_BADZIPFILE;
+
+ if (unzlocal_getLong(s^.afile, uData) <> UNZ_OK) then { date/time }
+ err := UNZ_ERRNO;
+
+ if (unzlocal_getLong(s^.afile, uData) <> UNZ_OK) then { crc }
+ err := UNZ_ERRNO
+ else
+ if ((err = UNZ_OK) and (uData <> s^.cur_file_info.crc) and
+ ((uFlags and 8) = 0)) then
+ err := UNZ_BADZIPFILE;
+
+ if (unzlocal_getLong(s^.afile, uData) <> UNZ_OK) then { size compr }
+ err := UNZ_ERRNO
+ else
+ if ((err = UNZ_OK) and (uData <> s^.cur_file_info.compressed_size) and
+ ((uFlags and 8) = 0)) then
+ err := UNZ_BADZIPFILE;
+
+ if (unzlocal_getLong(s^.afile, uData) <> UNZ_OK) then { size uncompr }
+ err := UNZ_ERRNO
+ else
+ if ((err = UNZ_OK) and (uData <> s^.cur_file_info.uncompressed_size) and
+ ((uFlags and 8) = 0)) then
+ err := UNZ_BADZIPFILE;
+
+
+ if (unzlocal_getShort(s^.afile, size_filename) <> UNZ_OK) then
+ err := UNZ_ERRNO
+ else
+ if ((err = UNZ_OK) and (size_filename <> s^.cur_file_info.size_filename)) then
+ err := UNZ_BADZIPFILE;
+
+ Inc(piSizeVar, integer(size_filename));
+
+ if (unzlocal_getShort(s^.afile, size_extra_field) <> UNZ_OK) then
+ err := UNZ_ERRNO;
+ poffset_local_extrafield := s^.cur_file_info_internal.offset_curfile +
+ SIZEZIPLOCALHEADER + size_filename;
+ psize_local_extrafield := integer(size_extra_field);
+
+ Inc(piSizeVar, integer(size_extra_field));
+
+ unzlocal_CheckCurrentFileCoherencyHeader := err;
+end;
+
+{ Open for reading data the current file in the zipfile.
+ If there is no error, the return value is UNZ_OK. }
+
+function unzOpenCurrentFile(afile: unzFile): longint; { ZEXPORT }
+var
+ err: longint;
+ Store: boolean;
+ iSizeVar: integer;
+ s: unz_s_ptr;
+ pfile_in_zip_read_info: file_in_zip_read_info_s_ptr;
+ offset_local_extrafield: longint; { offset of the local extra field }
+ size_local_extrafield: integer; { size of the local extra field }
+begin
+ err := UNZ_OK;
+
+ if (afile = nil) then
+ begin
+ unzOpenCurrentFile := UNZ_PARAMERROR;
+ exit;
+ end;
+ s := unz_s_ptr(afile);
+ if not s^.current_file_ok then
+ begin
+ unzOpenCurrentFile := UNZ_PARAMERROR;
+ exit;
+ end;
+
+ if (s^.pfile_in_zip_read <> nil) then
+ unzCloseCurrentFile(afile);
+
+ if (unzlocal_CheckCurrentFileCoherencyHeader(s, iSizeVar,
+ offset_local_extrafield, size_local_extrafield) <> UNZ_OK) then
+ begin
+ unzOpenCurrentFile := UNZ_BADZIPFILE;
+ exit;
+ end;
+
+ pfile_in_zip_read_info := file_in_zip_read_info_s_ptr(
+ AllocMem(sizeof(file_in_zip_read_info_s)));
+ if (pfile_in_zip_read_info = nil) then
+ begin
+ unzOpenCurrentFile := UNZ_INTERNALERROR;
+ exit;
+ end;
+
+ pfile_in_zip_read_info^.read_buffer := PChar(AllocMem(UNZ_BUFSIZE));
+ pfile_in_zip_read_info^.offset_local_extrafield := offset_local_extrafield;
+ pfile_in_zip_read_info^.size_local_extrafield := size_local_extrafield;
+ pfile_in_zip_read_info^.pos_local_extrafield := 0;
+
+ if (pfile_in_zip_read_info^.read_buffer = nil) then
+ begin
+ FreeMem(pfile_in_zip_read_info);
+ unzOpenCurrentFile := UNZ_INTERNALERROR;
+ exit;
+ end;
+
+ pfile_in_zip_read_info^.stream_initialised := False;
+
+ if ((s^.cur_file_info.compression_method <> 0) and
+ (s^.cur_file_info.compression_method <> Z_DEFLATED)) then
+ err := UNZ_BADZIPFILE;
+ Store := s^.cur_file_info.compression_method = 0;
+
+ pfile_in_zip_read_info^.crc32_wait := s^.cur_file_info.crc;
+ pfile_in_zip_read_info^.crc32 := 0;
+ pfile_in_zip_read_info^.compression_method := s^.cur_file_info.compression_method;
+ pfile_in_zip_read_info^.afile := s^.afile;
+ pfile_in_zip_read_info^.byte_before_the_zipfile := s^.byte_before_the_zipfile;
+
+ pfile_in_zip_read_info^.stream.total_out := 0;
+
+ if (not Store) then
+ begin
+ err := inflateInit2(pfile_in_zip_read_info^.stream, -MAX_WBITS);
+
+ if (err = Z_OK) then
+ pfile_in_zip_read_info^.stream_initialised := True;
+ { windowBits is passed < 0 to tell that there is no zlib header.
+ Note that in this case inflate *requires* an extra "dummy" byte
+ after the compressed stream in order to complete decompression and
+ return Z_STREAM_END.
+ In unzip, i don't wait absolutely Z_STREAM_END because I known the
+ size of both compressed and uncompressed data }
+ end;
+ pfile_in_zip_read_info^.rest_read_compressed := s^.cur_file_info.compressed_size;
+ pfile_in_zip_read_info^.rest_read_uncompressed := s^.cur_file_info.uncompressed_size;
+
+
+ pfile_in_zip_read_info^.pos_in_zipfile :=
+ s^.cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + iSizeVar;
+
+ pfile_in_zip_read_info^.stream.avail_in := integer(0);
+
+
+ s^.pfile_in_zip_read := pfile_in_zip_read_info;
+ unzOpenCurrentFile := UNZ_OK;
+end;
+
+
+{ Read bytes from the current file (opened by unzOpenCurrentFile)
+ buf contain buffer where data must be copied
+ len the size of buf.
+
+ return the number of byte copied if somes bytes are copied
+ return 0 if the end of file was reached
+ return <0 with error code if there is an error
+ (UNZ_ERRNO for IO error, or zLib error for uncompress error) }
+
+function unzReadCurrentFile(afile: unzFile; buf: pointer; len: cardinal): longint; { ZEXPORT }
+
+var
+ err: longint;
+ iRead: integer;
+ s: unz_s_ptr;
+ pfile_in_zip_read_info: file_in_zip_read_info_s_ptr;
+var
+ uReadThis: integer;
+var
+ uDoCopy, i: integer;
+var
+ uTotalOutBefore, uTotalOutAfter: longint;
+ bufBefore: pbyte;
+ uOutThis: longint;
+ flush: longint;
+begin
+ err := UNZ_OK;
+ iRead := 0;
+ if (afile = nil) then
+ begin
+ unzReadCurrentFile := UNZ_PARAMERROR;
+ exit;
+ end;
+ s := unz_s_ptr(afile);
+ pfile_in_zip_read_info := s^.pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info = nil) then
+ begin
+ unzReadCurrentFile := UNZ_PARAMERROR;
+ exit;
+ end;
+
+ if ((pfile_in_zip_read_info^.read_buffer = nil)) then
+ begin
+ unzReadCurrentFile := UNZ_END_OF_LIST_OF_FILE;
+ exit;
+ end;
+
+ if (len = 0) then
+ begin
+ unzReadCurrentFile := 0;
+ exit;
+ end;
+
+ pfile_in_zip_read_info^.stream.next_out := pbyte(buf);
+
+ pfile_in_zip_read_info^.stream.avail_out := integer(len);
+
+ if (len > pfile_in_zip_read_info^.rest_read_uncompressed) then
+ pfile_in_zip_read_info^.stream.avail_out :=
+ integer(pfile_in_zip_read_info^.rest_read_uncompressed);
+
+ while (pfile_in_zip_read_info^.stream.avail_out > 0) do
+ begin
+ if ((pfile_in_zip_read_info^.stream.avail_in = 0) and
+ (pfile_in_zip_read_info^.rest_read_compressed > 0)) then
+ begin
+ uReadThis := UNZ_BUFSIZE;
+ if (pfile_in_zip_read_info^.rest_read_compressed < uReadThis) then
+ uReadThis := integer(pfile_in_zip_read_info^.rest_read_compressed);
+ if (uReadThis = 0) then
+ begin
+ unzReadCurrentFile := UNZ_EOF;
+ exit;
+ end;
+ if (fseek(pfile_in_zip_read_info^.afile,
+ pfile_in_zip_read_info^.pos_in_zipfile +
+ pfile_in_zip_read_info^.byte_before_the_zipfile, SEEK_SET) <> 0) then
+ begin
+ unzReadCurrentFile := UNZ_ERRNO;
+ exit;
+ end;
+ if fread(pfile_in_zip_read_info^.read_buffer, uReadThis, 1,
+ pfile_in_zip_read_info^.afile) <> 1 then
+ begin
+ unzReadCurrentFile := UNZ_ERRNO;
+ exit;
+ end;
+ Inc(pfile_in_zip_read_info^.pos_in_zipfile, uReadThis);
+
+ Dec(pfile_in_zip_read_info^.rest_read_compressed, uReadThis);
+
+ pfile_in_zip_read_info^.stream.next_in :=
+ pbyte(pfile_in_zip_read_info^.read_buffer);
+ pfile_in_zip_read_info^.stream.avail_in := integer(uReadThis);
+ end;
+
+ if (pfile_in_zip_read_info^.compression_method = 0) then
+ begin
+ if (pfile_in_zip_read_info^.stream.avail_out <
+ pfile_in_zip_read_info^.stream.avail_in) then
+ uDoCopy := pfile_in_zip_read_info^.stream.avail_out
+ else
+ uDoCopy := pfile_in_zip_read_info^.stream.avail_in;
+
+ for i := 0 to uDoCopy - 1 do
+ Pbytearray(pfile_in_zip_read_info^.stream.next_out)^[i] :=
+ Pbytearray(pfile_in_zip_read_info^.stream.next_in)^[i];
+
+ pfile_in_zip_read_info^.crc32 := crc32(pfile_in_zip_read_info^.crc32,
+ pfile_in_zip_read_info^.stream.next_out, uDoCopy);
+ Dec(pfile_in_zip_read_info^.rest_read_uncompressed, uDoCopy);
+ Dec(pfile_in_zip_read_info^.stream.avail_in, uDoCopy);
+ Dec(pfile_in_zip_read_info^.stream.avail_out, uDoCopy);
+ Inc(pfile_in_zip_read_info^.stream.next_out, uDoCopy);
+ Inc(pfile_in_zip_read_info^.stream.next_in, uDoCopy);
+ Inc(pfile_in_zip_read_info^.stream.total_out, uDoCopy);
+ Inc(iRead, uDoCopy);
+ end
+ else
+ begin
+ flush := Z_SYNC_FLUSH;
+
+ uTotalOutBefore := pfile_in_zip_read_info^.stream.total_out;
+ bufBefore := pfile_in_zip_read_info^.stream.next_out;
+
+ {
+ if ((pfile_in_zip_read_info^.rest_read_uncompressed =
+ pfile_in_zip_read_info^.stream.avail_out) and
+ (pfile_in_zip_read_info^.rest_read_compressed = 0)) then
+ flush := Z_FINISH;
+ }
+ err := inflate(pfile_in_zip_read_info^.stream, flush);
+
+ uTotalOutAfter := pfile_in_zip_read_info^.stream.total_out;
+ uOutThis := uTotalOutAfter - uTotalOutBefore;
+
+ pfile_in_zip_read_info^.crc32 :=
+ crc32(pfile_in_zip_read_info^.crc32, bufBefore, integer(uOutThis));
+
+ Dec(pfile_in_zip_read_info^.rest_read_uncompressed, uOutThis);
+
+ Inc(iRead, integer(uTotalOutAfter - uTotalOutBefore));
+
+ if (err = Z_STREAM_END) then
+ begin
+ if iRead = 0 then
+ unzReadCurrentFile := UNZ_EOF
+ else
+ unzReadCurrentFile := iRead;
+ exit;
+ end;
+ if (err <> Z_OK) then
+ break;
+ end;
+ end; { while }
+
+ if (err = Z_OK) then
+ begin
+ unzReadCurrentFile := iRead;
+ exit;
+ end;
+ unzReadCurrentFile := err;
+end;
+
+{ Give the current position in uncompressed data }
+
+function unztell(afile: unzFile): z_off_t; { ZEXPORT }
+var
+ s: unz_s_ptr;
+ pfile_in_zip_read_info: file_in_zip_read_info_s_ptr;
+begin
+ if (afile = nil) then
+ begin
+ unztell := UNZ_PARAMERROR;
+ exit;
+ end;
+
+ s := unz_s_ptr(afile);
+ pfile_in_zip_read_info := s^.pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info = nil) then
+ begin
+ unztell := UNZ_PARAMERROR;
+ exit;
+ end;
+
+ unztell := z_off_t(pfile_in_zip_read_info^.stream.total_out);
+end;
+
+
+{ return 1 (TRUE) if the end of file was reached, 0 elsewhere }
+
+function unzeof(afile: unzFile): longint;
+var
+ s: unz_s_ptr;
+ pfile_in_zip_read_info: file_in_zip_read_info_s_ptr;
+begin
+ if (afile = nil) then
+ begin
+ unzeof := UNZ_PARAMERROR;
+ exit;
+ end;
+
+ s := unz_s_ptr(afile);
+ pfile_in_zip_read_info := s^.pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info = nil) then
+ begin
+ unzeof := UNZ_PARAMERROR;
+ exit;
+ end;
+
+ if (pfile_in_zip_read_info^.rest_read_uncompressed = 0) then
+ unzeof := 1
+ else
+ unzeof := 0;
+end;
+
+
+{ Read extra field from the current file (opened by unzOpenCurrentFile)
+ This is the local-header version of the extra field (sometimes, there is
+ more info in the local-header version than in the central-header)
+
+ if buf=NIL, it return the size of the local extra field
+
+ if buf<>NIL, len is the size of the buffer, the extra header is copied in
+ buf.
+ the return value is the number of bytes copied in buf, or (if <0)
+ the error code }
+
+function unzGetLocalExtrafield(afile: unzFile; buf: pointer; len: cardinal): longint;
+var
+ s: unz_s_ptr;
+ pfile_in_zip_read_info: file_in_zip_read_info_s_ptr;
+ read_now: integer;
+ size_to_read: longint;
+begin
+ if (afile = nil) then
+ begin
+ unzGetLocalExtrafield := UNZ_PARAMERROR;
+ exit;
+ end;
+
+ s := unz_s_ptr(afile);
+ pfile_in_zip_read_info := s^.pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info = nil) then
+ begin
+ unzGetLocalExtrafield := UNZ_PARAMERROR;
+ exit;
+ end;
+
+ size_to_read := (pfile_in_zip_read_info^.size_local_extrafield -
+ pfile_in_zip_read_info^.pos_local_extrafield);
+
+ if (buf = nil) then
+ begin
+ unzGetLocalExtrafield := longint(size_to_read);
+ exit;
+ end;
+
+ if (len > size_to_read) then
+ read_now := integer(size_to_read)
+ else
+ read_now := integer(len);
+
+ if (read_now = 0) then
+ begin
+ unzGetLocalExtrafield := 0;
+ exit;
+ end;
+
+ if (fseek(pfile_in_zip_read_info^.afile,
+ pfile_in_zip_read_info^.offset_local_extrafield +
+ pfile_in_zip_read_info^.pos_local_extrafield, SEEK_SET) <> 0) then
+ begin
+ unzGetLocalExtrafield := UNZ_ERRNO;
+ exit;
+ end;
+
+ if fread(buf, integer(size_to_read), 1, pfile_in_zip_read_info^.afile) <> 1 then
+ begin
+ unzGetLocalExtrafield := UNZ_ERRNO;
+ exit;
+ end;
+
+ unzGetLocalExtrafield := longint(read_now);
+end;
+
+{ Close the file in zip opened with unzOpenCurrentFile
+ Return UNZ_CRCERROR if all the file was read but the CRC is not good }
+
+function unzCloseCurrentFile(afile: unzFile): longint; { ZEXPORT }
+var
+ err: longint;
+ s: unz_s_ptr;
+ pfile_in_zip_read_info: file_in_zip_read_info_s_ptr;
+begin
+ err := UNZ_OK;
+
+ if (afile = nil) then
+ begin
+ unzCloseCurrentFile := UNZ_PARAMERROR;
+ exit;
+ end;
+ s := unz_s_ptr(afile);
+ pfile_in_zip_read_info := s^.pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info = nil) then
+ begin
+ unzCloseCurrentFile := UNZ_PARAMERROR;
+ exit;
+ end;
+
+
+ if (pfile_in_zip_read_info^.rest_read_uncompressed = 0) then
+ if (pfile_in_zip_read_info^.crc32 <> pfile_in_zip_read_info^.crc32_wait) then
+ err := UNZ_CRCERROR;
+
+
+ FreeMem(pfile_in_zip_read_info^.read_buffer);
+ pfile_in_zip_read_info^.read_buffer := nil;
+ if (pfile_in_zip_read_info^.stream_initialised) then
+ inflateEnd(pfile_in_zip_read_info^.stream);
+
+ pfile_in_zip_read_info^.stream_initialised := False;
+ FreeMem(pfile_in_zip_read_info);
+
+ s^.pfile_in_zip_read := nil;
+
+ unzCloseCurrentFile := err;
+end;
+
+
+{ Get the global comment string of the ZipFile, in the szComment buffer.
+ uSizeBuf is the size of the szComment buffer.
+ return the number of byte copied or an error code <0 }
+
+function unzGetGlobalComment(afile: unzFile; szComment: PChar; uSizeBuf: longint): longint; { ZEXPORT }
+
+var
+ s: unz_s_ptr;
+ uReadThis: longint;
+begin
+ if (afile = nil) then
+ begin
+ unzGetGlobalComment := UNZ_PARAMERROR;
+ exit;
+ end;
+ s := unz_s_ptr(afile);
+
+ uReadThis := uSizeBuf;
+ if (uReadThis > s^.gi.size_comment) then
+ uReadThis := s^.gi.size_comment;
+
+ if (fseek(s^.afile, s^.central_pos + 22, SEEK_SET) <> 0) then
+ begin
+ unzGetGlobalComment := UNZ_ERRNO;
+ exit;
+ end;
+
+ if (uReadThis > 0) then
+ begin
+ szComment^ := #0;
+ if fread(szComment, integer(uReadThis), 1, s^.afile) <> 1 then
+ begin
+ unzGetGlobalComment := UNZ_ERRNO;
+ exit;
+ end;
+ end;
+
+ if ((szComment <> nil) and (uSizeBuf > s^.gi.size_comment)) then
+ (szComment +s^.gi.size_comment)^ := #0;
+
+ unzGetGlobalComment := longint(uReadThis);
+end;
+
+end.
diff --git a/packages/paszlib/src/zbase.pas b/packages/paszlib/src/zbase.pas
new file mode 100644
index 0000000000..3193a77e8c
--- /dev/null
+++ b/packages/paszlib/src/zbase.pas
@@ -0,0 +1,484 @@
+unit zbase;
+
+
+{ Original:
+ zlib.h -- interface of the 'zlib' general purpose compression library
+ version 1.1.0, Feb 24th, 1998
+
+ Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+
+ The data format used by the zlib library is described by RFCs (Request for
+ Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
+ (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+
+
+ Pascal tranlastion
+ Copyright (C) 1998 by Jacques Nomssi Nzali
+ For conditions of distribution and use, see copyright notice in readme.txt
+}
+
+interface
+
+{$I zconf.inc}
+
+{ zconf.h -- configuration of the zlib compression library }
+{ zutil.c -- target dependent utility functions for the compression library }
+
+{ The 'zlib' compression library provides in-memory compression and
+ decompression functions, including integrity checks of the uncompressed
+ data. This version of the library supports only one compression method
+ (deflation) but other algorithms will be added later and will have the same
+ stream interface.
+
+ Compression can be done in a single step if the buffers are large
+ enough (for example if an input file is mmap'ed), or can be done by
+ repeated calls of the compression function. In the latter case, the
+ application must provide more input and/or consume the output
+ (providing more output space) before each call.
+
+ The library also supports reading and writing files in gzip (.gz) format
+ with an interface similar to that of stdio.
+
+ The library does not install any signal handler. The decoder checks
+ the consistency of the compressed data, so the library should never
+ crash even in case of corrupted input. }
+
+
+
+{ Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ than 64k bytes at a time (needed on systems with 16-bit integer). }
+
+{ Maximum value for memLevel in deflateInit2 }
+{$ifdef MAXSEG_64K}
+ {$IFDEF TP}
+ const
+ MAX_MEM_LEVEL = 7;
+ DEF_MEM_LEVEL = MAX_MEM_LEVEL; { default memLevel }
+ {$ELSE}
+ const
+ MAX_MEM_LEVEL = 8;
+ DEF_MEM_LEVEL = MAX_MEM_LEVEL; { default memLevel }
+ {$ENDIF}
+{$else}
+const
+ MAX_MEM_LEVEL = 9;
+ DEF_MEM_LEVEL = 8; { if MAX_MEM_LEVEL > 8 }
+{$endif}
+
+{ Maximum value for windowBits in deflateInit2 and inflateInit2 }
+const
+{$IFDEF TP}
+ MAX_WBITS = 14; { 32K LZ77 window }
+{$ELSE}
+ MAX_WBITS = 15; { 32K LZ77 window }
+{$ENDIF}
+
+{ default windowBits for decompression. MAX_WBITS is for compression only }
+const
+ DEF_WBITS = MAX_WBITS;
+
+
+type Pbytearray=^Tbytearray;
+ Pwordarray=^Twordarray;
+ Pcardinalarray=^Tcardinalarray;
+
+ Tbytearray = array [0..maxint div sizeof(byte)-1] of byte;
+ Twordarray = array [0..maxint div sizeof(word)-1] of word;
+ Tintegerarray = array [0..maxint div sizeof(integer)-1] of integer;
+ Tcardinalarray = array [0..maxint div sizeof(cardinal)-1] of cardinal;
+
+
+{ The memory requirements for deflate are (in bytes):
+ 1 shl (windowBits+2) + 1 shl (memLevel+9)
+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+ DMAX_WBITS=14 DMAX_MEM_LEVEL=7
+ Of course this will generally degrade compression (there's no free lunch).
+
+ The memory requirements for inflate are (in bytes) 1 shl windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects. }
+
+
+{ Huffman code lookup table entry--this entry is four bytes for machines
+ that have 16-bit pointers (e.g. PC's in the small or medium model). }
+
+type
+ pInflate_huft = ^inflate_huft;
+ inflate_huft = Record
+ Exop, { number of extra bits or operation }
+ bits : Byte; { number of bits in this code or subcode }
+ {pad : cardinal;} { pad structure to a power of 2 (4 bytes for }
+ { 16-bit, 8 bytes for 32-bit integer's) }
+ base : cardinal; { literal, length base, or distance base }
+ { or table offset }
+ End;
+
+type
+ huft_field = Array[0..(maxint div SizeOf(inflate_huft))-1] of inflate_huft;
+ huft_ptr = ^huft_field;
+type
+ ppInflate_huft = ^pInflate_huft;
+
+type
+ inflate_codes_mode = ( { waiting for "i:"=input, "o:"=output, "x:"=nothing }
+ START, { x: set up for LEN }
+ LEN, { i: get length/literal/eob next }
+ LENEXT, { i: getting length extra (have base) }
+ DIST, { i: get distance next }
+ DISTEXT, { i: getting distance extra }
+ COPY, { o: copying bytes in window, waiting for space }
+ LIT, { o: got literal, waiting for output space }
+ WASH, { o: got eob, possibly still output waiting }
+ ZEND, { x: got eob and all data flushed }
+ BADCODE); { x: got error }
+
+{ inflate codes private state }
+type
+ pInflate_codes_state = ^inflate_codes_state;
+ inflate_codes_state = record
+
+ mode : inflate_codes_mode; { current inflate_codes mode }
+
+ { mode dependent information }
+ len : cardinal;
+ sub : record { submode }
+ Case Byte of
+ 0:(code : record { if LEN or DIST, where in tree }
+ tree : pInflate_huft; { pointer into tree }
+ need : cardinal; { bits needed }
+ end);
+ 1:(lit : cardinal); { if LIT, literal }
+ 2:(copy: record { if EXT or COPY, where and how much }
+ get : cardinal; { bits to get for extra }
+ dist : cardinal; { distance back to copy from }
+ end);
+ end;
+
+ { mode independent information }
+ lbits : Byte; { ltree bits decoded per branch }
+ dbits : Byte; { dtree bits decoder per branch }
+ ltree : pInflate_huft; { literal/length/eob tree }
+ dtree : pInflate_huft; { distance tree }
+ end;
+
+type
+ check_func = function(check : cardinal;
+ buf : Pbyte;
+ {const buf : array of byte;}
+ len : cardinal) : cardinal;
+type
+ inflate_block_mode =
+ (ZTYPE, { get type bits (3, including end bit) }
+ LENS, { get lengths for stored }
+ STORED, { processing stored block }
+ TABLE, { get table lengths }
+ BTREE, { get bit lengths tree for a dynamic block }
+ DTREE, { get length, distance trees for a dynamic block }
+ CODES, { processing fixed or dynamic block }
+ DRY, { output remaining window bytes }
+ BLKDONE, { finished last block, done }
+ BLKBAD); { got a data error--stuck here }
+
+type
+ pInflate_blocks_state = ^inflate_blocks_state;
+
+{ inflate blocks semi-private state }
+ inflate_blocks_state = record
+
+ mode : inflate_block_mode; { current inflate_block mode }
+
+ { mode dependent information }
+ sub : record { submode }
+ case Byte of
+ 0:(left : cardinal); { if STORED, bytes left to copy }
+ 1:(trees : record { if DTREE, decoding info for trees }
+ table : cardinal; { table lengths (14 bits) }
+ index : cardinal; { index into blens (or border) }
+ blens : Pcardinalarray; { bit lengths of codes }
+ bb : cardinal; { bit length tree depth }
+ tb : pInflate_huft; { bit length decoding tree }
+ end);
+ 2:(decode : record { if CODES, current state }
+ tl : pInflate_huft;
+ td : pInflate_huft; { trees to free }
+ codes : pInflate_codes_state;
+ end);
+ end;
+ last : boolean; { true if this block is the last block }
+
+ { mode independent information }
+ bitk : cardinal; { bits in bit buffer }
+ bitb : cardinal; { bit buffer }
+ hufts : huft_ptr; {pInflate_huft;} { single malloc for tree space }
+ window : Pbyte; { sliding window }
+ zend : Pbyte; { one byte after sliding window }
+ read : Pbyte; { window read pointer }
+ write : Pbyte; { window write pointer }
+ checkfn : check_func; { check function }
+ check : cardinal; { check on output }
+ end;
+
+type
+ inflate_mode = (
+ METHOD, { waiting for method byte }
+ FLAG, { waiting for flag byte }
+ DICT4, { four dictionary check bytes to go }
+ DICT3, { three dictionary check bytes to go }
+ DICT2, { two dictionary check bytes to go }
+ DICT1, { one dictionary check byte to go }
+ DICT0, { waiting for inflateSetDictionary }
+ BLOCKS, { decompressing blocks }
+ CHECK4, { four check bytes to go }
+ CHECK3, { three check bytes to go }
+ CHECK2, { two check bytes to go }
+ CHECK1, { one check byte to go }
+ DONE, { finished check, done }
+ BAD); { got an error--stay here }
+
+{ inflate private state }
+type
+ pInternal_state = ^internal_state; { or point to a deflate_state record }
+ internal_state = record
+
+ mode : inflate_mode; { current inflate mode }
+
+ { mode dependent information }
+ sub : record { submode }
+ case byte of
+ 0:(method : cardinal); { if FLAGS, method byte }
+ 1:(check : record { if CHECK, check values to compare }
+ was : cardinal; { computed check value }
+ need : cardinal; { stream check value }
+ end);
+ 2:(marker : cardinal); { if BAD, inflateSync's marker bytes count }
+ end;
+
+ { mode independent information }
+ nowrap : boolean; { flag for no wrapper }
+ wbits : cardinal; { log2(window size) (8..15, defaults to 15) }
+ blocks : pInflate_blocks_state; { current inflate_blocks state }
+ end;
+
+type
+ z_streamp = ^z_stream;
+ z_stream = record
+ next_in : Pbyte; { next input byte }
+ avail_in : cardinal; { number of bytes available at next_in }
+ total_in : cardinal; { total nb of input bytes read so far }
+
+ next_out : Pbyte; { next output byte should be put there }
+ avail_out : cardinal; { remaining free space at next_out }
+ total_out : cardinal; { total nb of bytes output so far }
+
+ msg : string[255]; { last error message, '' if no error }
+ state : pInternal_state; { not visible by applications }
+
+ data_type : integer; { best guess about the data type: ascii or binary }
+ adler : cardinal; { adler32 value of the uncompressed data }
+ reserved : cardinal; { reserved for future use }
+ end;
+
+
+{ The application must update next_in and avail_in when avail_in has
+ dropped to zero. It must update next_out and avail_out when avail_out
+ has dropped to zero. The application must initialize zalloc, zfree and
+ opaque before calling the init function. All other fields are set by the
+ compression library and must not be updated by the application.
+
+ The fields total_in and total_out can be used for statistics or
+ progress reports. After compression, total_in holds the total size of
+ the uncompressed data and may be saved for use in the decompressor
+ (particularly if the decompressor wants to decompress everything in
+ a single step). }
+
+const { constants }
+ Z_NO_FLUSH = 0;
+ Z_PARTIAL_FLUSH = 1;
+ Z_SYNC_FLUSH = 2;
+ Z_FULL_FLUSH = 3;
+ Z_FINISH = 4;
+{ Allowed flush values; see deflate() below for details }
+
+ Z_OK = 0;
+ Z_STREAM_END = 1;
+ Z_NEED_DICT = 2;
+ Z_ERRNO = (-1);
+ Z_STREAM_ERROR = (-2);
+ Z_DATA_ERROR = (-3);
+ Z_MEM_ERROR = (-4);
+ Z_BUF_ERROR = (-5);
+ Z_VERSION_ERROR = (-6);
+{ Return codes for the compression/decompression functions. Negative
+ values are errors, positive values are used for special but normal events.}
+
+ Z_NO_COMPRESSION = 0;
+ Z_BEST_SPEED = 1;
+ Z_BEST_COMPRESSION = 9;
+ Z_DEFAULT_COMPRESSION = (-1);
+{ compression levels }
+
+ Z_FILTERED = 1;
+ Z_HUFFMAN_ONLY = 2;
+ Z_DEFAULT_STRATEGY = 0;
+{ compression strategy; see deflateInit2() below for details }
+
+ Z_BINARY = 0;
+ Z_ASCII = 1;
+ Z_UNKNOWN = 2;
+{ Possible values of the data_type field }
+
+ Z_DEFLATED = 8;
+{ The deflate compression method (the only one supported in this version) }
+
+ {$IFDEF GZIO}
+var
+ errno : integer;
+ {$ENDIF}
+
+ { common constants }
+
+
+{ The three kinds of block type }
+const
+ STORED_BLOCK = 0;
+ STATIC_TREES = 1;
+ DYN_TREES = 2;
+{ The minimum and maximum match lengths }
+const
+ MIN_MATCH = 3;
+{$ifdef MAX_MATCH_IS_258}
+ MAX_MATCH = 258;
+{$else}
+ MAX_MATCH = ??; { deliberate syntax error }
+{$endif}
+
+const
+ PRESET_DICT = $20; { preset dictionary flag in zlib header }
+
+
+ {$IFDEF ZLIB_DEBUG}
+ procedure Assert(cond : boolean; msg : string);
+ {$ENDIF}
+
+ procedure Trace(x : string);
+ procedure Tracev(x : string);
+ procedure Tracevv(x : string);
+ procedure Tracevvv(x : string);
+ procedure Tracec(c : boolean; x : string);
+ procedure Tracecv(c : boolean; x : string);
+
+function zlibVersion : string;
+{ The application can compare zlibVersion and ZLIB_VERSION for consistency.
+ If the first character differs, the library code actually used is
+ not compatible with the zlib.h header file used by the application.
+ This check is automatically made by deflateInit and inflateInit. }
+
+function zError(err : integer) : string;
+
+const
+ ZLIB_VERSION : string[10] = '1.1.2';
+
+const
+ z_errbase = Z_NEED_DICT;
+ z_errmsg : Array[0..9] of string[21] = { indexed by 2-zlib_error }
+ ('need dictionary', { Z_NEED_DICT 2 }
+ 'stream end', { Z_STREAM_END 1 }
+ '', { Z_OK 0 }
+ 'file error', { Z_ERRNO (-1) }
+ 'stream error', { Z_STREAM_ERROR (-2) }
+ 'data error', { Z_DATA_ERROR (-3) }
+ 'insufficient memory', { Z_MEM_ERROR (-4) }
+ 'buffer error', { Z_BUF_ERROR (-5) }
+ 'incompatible version',{ Z_VERSION_ERROR (-6) }
+ '');
+const
+ z_verbose : integer = 1;
+
+{$IFDEF ZLIB_DEBUG}
+procedure z_error (m : string);
+{$ENDIF}
+
+implementation
+
+function zError(err : integer) : string;
+begin
+ zError := z_errmsg[Z_NEED_DICT-err];
+end;
+
+function zlibVersion : string;
+begin
+ zlibVersion := ZLIB_VERSION;
+end;
+
+procedure z_error (m : string);
+begin
+ WriteLn(output, m);
+ Write('Zlib - Halt...');
+ ReadLn;
+ Halt(1);
+end;
+
+procedure Assert(cond : boolean; msg : string);
+begin
+ if not cond then
+ z_error(msg);
+end;
+
+procedure Trace(x : string);
+begin
+ WriteLn(x);
+end;
+
+procedure Tracev(x : string);
+begin
+ if (z_verbose>0) then
+ WriteLn(x);
+end;
+
+procedure Tracevv(x : string);
+begin
+ if (z_verbose>1) then
+ WriteLn(x);
+end;
+
+procedure Tracevvv(x : string);
+begin
+ if (z_verbose>2) then
+ WriteLn(x);
+end;
+
+procedure Tracec(c : boolean; x : string);
+begin
+ if (z_verbose>0) and (c) then
+ WriteLn(x);
+end;
+
+procedure Tracecv(c : boolean; x : string);
+begin
+ if (z_verbose>1) and c then
+ WriteLn(x);
+end;
+
+end. \ No newline at end of file
diff --git a/packages/paszlib/src/zcompres.pas b/packages/paszlib/src/zcompres.pas
new file mode 100644
index 0000000000..f5867b13fa
--- /dev/null
+++ b/packages/paszlib/src/zcompres.pas
@@ -0,0 +1,118 @@
+Unit zCompres;
+
+{ compress.c -- compress a memory buffer
+ Copyright (C) 1995-1998 Jean-loup Gailly.
+
+ Pascal tranlastion
+ Copyright (C) 1998 by Jacques Nomssi Nzali
+ For conditions of distribution and use, see copyright notice in readme.txt
+}
+
+interface
+
+{$I zconf.inc}
+
+uses
+ zbase, zdeflate;
+
+ { utility functions }
+
+{EXPORT}
+function compress (dest : Pbyte;
+ var destLen : cardinal;
+ const source : array of Byte;
+ sourceLen : cardinal) : integer;
+
+ { Compresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be at least 0.1% larger than
+ sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the
+ compressed buffer.
+ This function can be used to compress a whole file at once if the
+ input file is mmap'ed.
+ compress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer. }
+
+{EXPORT}
+function compress2 (dest : Pbyte;
+ var destLen : cardinal;
+ const source : array of byte;
+ sourceLen : cardinal;
+ level : integer) : integer;
+{ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least 0.1% larger than sourceLen plus
+ 12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid. }
+
+implementation
+
+{ ===========================================================================
+}
+function compress2 (dest : Pbyte;
+ var destLen : cardinal;
+ const source : array of byte;
+ sourceLen : cardinal;
+ level : integer) : integer;
+var
+ stream : z_stream;
+ err : integer;
+begin
+ stream.next_in := Pbyte(@source);
+ stream.avail_in := cardinal(sourceLen);
+{$ifdef MAXSEG_64K}
+ { Check for source > 64K on 16-bit machine: }
+ if (cardinal(stream.avail_in) <> sourceLen) then
+ begin
+ compress2 := Z_BUF_ERROR;
+ exit;
+ end;
+{$endif}
+ stream.next_out := dest;
+ stream.avail_out := cardinal(destLen);
+ if (cardinal(stream.avail_out) <> destLen) then
+ begin
+ compress2 := Z_BUF_ERROR;
+ exit;
+ end;
+
+ err := deflateInit(stream, level);
+ if (err <> Z_OK) then
+ begin
+ compress2 := err;
+ exit;
+ end;
+
+ err := deflate(stream, Z_FINISH);
+ if (err <> Z_STREAM_END) then
+ begin
+ deflateEnd(stream);
+ if err = Z_OK then
+ compress2 := Z_BUF_ERROR
+ else
+ compress2 := err;
+ exit;
+ end;
+ destLen := stream.total_out;
+
+ err := deflateEnd(stream);
+ compress2 := err;
+end;
+
+{ ===========================================================================
+ }
+function compress (dest : Pbyte;
+ var destLen : cardinal;
+ const source : array of Byte;
+ sourceLen : cardinal) : integer;
+begin
+ compress := compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
+end;
+
+
+end. \ No newline at end of file
diff --git a/packages/paszlib/src/zconf.inc b/packages/paszlib/src/zconf.inc
new file mode 100644
index 0000000000..7086daea68
--- /dev/null
+++ b/packages/paszlib/src/zconf.inc
@@ -0,0 +1,38 @@
+{ -------------------------------------------------------------------- }
+
+{$DEFINE MAX_MATCH_IS_258}
+
+{ Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ than 64k bytes at a time (needed on systems with 16-bit int). }
+
+{- $DEFINE MAXSEG_64K}
+{$IFDEF VER70}
+ {$DEFINE TP}
+ {$DEFINE MAXSEG_64K}
+{$ENDIF}
+{$IFNDEF WIN32}
+ {$DEFINE UNALIGNED_OK} { requires SizeOf(ush) = 2 ! }
+{$ENDIF}
+
+{$UNDEF DYNAMIC_CRC_TABLE}
+{$UNDEF FASTEST}
+{$define patch112} { apply patch from the zlib home page }
+{ -------------------------------------------------------------------- }
+{$IFDEF WIN32}
+ {$DEFINE Delphi32}
+ {- $DEFINE Delphi5} { keep compiler quiet }
+{$ENDIF}
+
+{$IFDEF DPMI}
+ {$DEFINE MSDOS}
+{$ENDIF}
+
+{$IFDEF FPC}
+ {$DEFINE Use32}
+ {$DEFINE pointer_arith}
+ {$UNDEF DPMI}
+ {$UNDEF MSDOS}
+ {$UNDEF UNALIGNED_OK} { requires SizeOf(ush) = 2 ! }
+ {$UNDEF MAXSEG_64K}
+ {$UNDEF Delphi32}
+{$ENDIF}
diff --git a/packages/paszlib/src/zdeflate.pas b/packages/paszlib/src/zdeflate.pas
new file mode 100644
index 0000000000..d6f39269da
--- /dev/null
+++ b/packages/paszlib/src/zdeflate.pas
@@ -0,0 +1,2117 @@
+unit zdeflate;
+
+{$goto on}
+
+{ Orginal: deflate.h -- internal compression state
+ deflate.c -- compress data using the deflation algorithm
+ Copyright (C) 1995-1996 Jean-loup Gailly.
+
+ Pascal tranlastion
+ Copyright (C) 1998 by Jacques Nomssi Nzali
+ For conditions of distribution and use, see copyright notice in readme.txt
+}
+
+
+{ ALGORITHM
+
+ The "deflation" process depends on being able to identify portions
+ of the input text which are identical to earlier input (within a
+ sliding window trailing behind the input currently being processed).
+
+ The most straightforward technique turns out to be the fastest for
+ most input files: try all possible matches and select the longest.
+ The key feature of this algorithm is that insertions into the string
+ dictionary are very simple and thus fast, and deletions are avoided
+ completely. Insertions are performed at each input character, whereas
+ string matches are performed only when the previous match ends. So it
+ is preferable to spend more time in matches to allow very fast string
+ insertions and avoid deletions. The matching algorithm for small
+ strings is inspired from that of Rabin & Karp. A brute force approach
+ is used to find longer strings when a small match has been found.
+ A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ (by Leonid Broukhis).
+ A previous version of this file used a more sophisticated algorithm
+ (by Fiala and Greene) which is guaranteed to run in linear amortized
+ time, but has a larger average cost, uses more memory and is patented.
+ However the F&G algorithm may be faster for some highly redundant
+ files if the parameter max_chain_length (described below) is too large.
+
+ ACKNOWLEDGEMENTS
+
+ The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ I found it in 'freeze' written by Leonid Broukhis.
+ Thanks to many people for bug reports and testing.
+
+ REFERENCES
+
+ Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+
+ A description of the Rabin and Karp algorithm is given in the book
+ "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+
+ Fiala,E.R., and Greene,D.H.
+ Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595}
+
+{ $Id: deflate.c,v 1.14 1996/07/02 12:40:55 me Exp $ }
+
+interface
+
+{$I zconf.inc}
+
+uses
+ zbase;
+
+
+function deflateInit_(strm : z_streamp;
+ level : integer;
+ const version : string;
+ stream_size : integer) : integer;
+
+
+function deflateInit (var strm : z_stream; level : integer) : integer;
+
+{ Initializes the internal stream state for compression.
+
+ The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+ 1 gives best speed, 9 gives best compression, 0 gives no compression at
+ all (the input data is simply copied a block at a time).
+ Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+ compression (currently equivalent to level 6).
+
+ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+ Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+ with the version assumed by the caller (ZLIB_VERSION).
+ msg is set to null if there is no error message. deflateInit does not
+ perform any compression: this will be done by deflate(). }
+
+
+{EXPORT}
+function deflate (var strm : z_stream; flush : integer) : integer;
+
+{ Performs one or both of the following actions:
+
+ - Compress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in and avail_in are updated and
+ processing will resume at this point for the next call of deflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. This action is forced if the parameter flush is non zero.
+ Forcing flush frequently degrades the compression ratio, so this parameter
+ should be set only when necessary (in interactive applications).
+ Some output may be provided even if flush is not set.
+
+ Before the call of deflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating avail_in or avail_out accordingly; avail_out
+ should never be zero before the call. The application can consume the
+ compressed output when it wants, for example when the output buffer is full
+ (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+ and with zero avail_out, it must be called again after making room in the
+ output buffer because there might be more output pending.
+
+ If the parameter flush is set to Z_PARTIAL_FLUSH, the current compression
+ block is terminated and flushed to the output buffer so that the
+ decompressor can get all input data available so far. For method 9, a future
+ variant on method 8, the current block will be flushed but not terminated.
+ Z_SYNC_FLUSH has the same effect as partial flush except that the compressed
+ output is byte aligned (the compressor can clear its internal bit buffer)
+ and the current block is always terminated; this can be useful if the
+ compressor has to be restarted from scratch after an interruption (in which
+ case the internal state of the compressor may be lost).
+ If flush is set to Z_FULL_FLUSH, the compression block is terminated, a
+ special marker is output and the compression dictionary is discarded; this
+ is useful to allow the decompressor to synchronize if one compressed block
+ has been damaged (see inflateSync below). Flushing degrades compression and
+ so should be used only when necessary. Using Z_FULL_FLUSH too often can
+ seriously degrade the compression. If deflate returns with avail_out == 0,
+ this function must be called again with the same value of the flush
+ parameter and more output space (updated avail_out), until the flush is
+ complete (deflate returns with non-zero avail_out).
+
+ If the parameter flush is set to Z_FINISH, all pending input is processed,
+ all pending output is flushed and deflate returns with Z_STREAM_END if there
+ was enough output space; if deflate returns with Z_OK, this function must be
+ called again with Z_FINISH and more output space (updated avail_out) but no
+ more input data, until it returns with Z_STREAM_END or an error. After
+ deflate has returned Z_STREAM_END, the only possible operations on the
+ stream are deflateReset or deflateEnd.
+
+ Z_FINISH can be used immediately after deflateInit if all the compression
+ is to be done in a single step. In this case, avail_out must be at least
+ 0.1% larger than avail_in plus 12 bytes. If deflate does not return
+ Z_STREAM_END, then it must be called again as described above.
+
+ deflate() may update data_type if it can make a good guess about
+ the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
+ binary. This field is only for information purposes and does not affect
+ the compression algorithm in any manner.
+
+ deflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if all input has been
+ consumed and all output has been produced (only when flush is set to
+ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+ if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible. }
+
+
+function deflateEnd (var strm : z_stream) : integer;
+
+{ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+ stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+ prematurely (some input or output was discarded). In the error case,
+ msg may be set but then points to a static string (which must not be
+ deallocated). }
+
+
+
+
+ { Advanced functions }
+
+{ The following functions are needed only in some special applications. }
+
+
+{EXPORT}
+function deflateInit2 (var strm : z_stream;
+ level : integer;
+ method : integer;
+ windowBits : integer;
+ memLevel : integer;
+ strategy : integer) : integer;
+function deflateInit2_(var strm : z_stream;
+ level : integer;
+ method : integer;
+ windowBits : integer;
+ memLevel : integer;
+ strategy : integer;
+ const version : string;
+ stream_size : integer) : integer;
+
+{ This is another version of deflateInit with more compression options. The
+ fields next_in, and opaque must be initialized before by
+ the caller.
+
+ The method parameter is the compression method. It must be Z_DEFLATED in
+ this version of the library. (Method 9 will allow a 64K history buffer and
+ partial block flushes.)
+
+ The windowBits parameter is the base two logarithm of the window size
+ (the size of the history buffer). It should be in the range 8..15 for this
+ version of the library (the value 16 will be allowed for method 9). Larger
+ values of this parameter result in better compression at the expense of
+ memory usage. The default value is 15 if deflateInit is used instead.
+
+ The memLevel parameter specifies how much memory should be allocated
+ for the internal compression state. memLevel=1 uses minimum memory but
+ is slow and reduces compression ratio; memLevel=9 uses maximum memory
+ for optimal speed. The default value is 8. See zconf.h for total memory
+ usage as a function of windowBits and memLevel.
+
+ The strategy parameter is used to tune the compression algorithm. Use the
+ value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+ filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
+ string match). Filtered data consists mostly of small values with a
+ somewhat random distribution. In this case, the compression algorithm is
+ tuned to compress them better. The effect of Z_FILTERED is to force more
+ Huffman coding and less string matching; it is somewhat intermediate
+ between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
+ the compression ratio but not the correctness of the compressed output even
+ if it is not set appropriately.
+
+ If next_in is not null, the library will use this buffer to hold also
+ some history information; the buffer must either hold the entire input
+ data, or have at least 1<<(windowBits+1) bytes and be writable. If next_in
+ is null, the library will allocate its own history buffer (and leave next_in
+ null). next_out need not be provided here but must be provided by the
+ application for the next call of deflate().
+
+ If the history buffer is provided by the application, next_in must
+ must never be changed by the application since the compressor maintains
+ information inside this buffer from call to call; the application
+ must provide more input only by increasing avail_in. next_in is always
+ reset by the library in this case.
+
+ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
+ not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
+ an invalid method). msg is set to null if there is no error message.
+ deflateInit2 does not perform any compression: this will be done by
+ deflate(). }
+
+
+{EXPORT}
+function deflateSetDictionary (var strm : z_stream;
+ dictionary : Pbyte; {const bytes}
+ dictLength : cardinal) : integer;
+
+{ Initializes the compression dictionary (history buffer) from the given
+ byte sequence without producing any compressed output. This function must
+ be called immediately after deflateInit or deflateInit2, before any call
+ of deflate. The compressor and decompressor must use exactly the same
+ dictionary (see inflateSetDictionary).
+ The dictionary should consist of strings (byte sequences) that are likely
+ to be encountered later in the data to be compressed, with the most commonly
+ used strings preferably put towards the end of the dictionary. Using a
+ dictionary is most useful when the data to be compressed is short and
+ can be predicted with good accuracy; the data can then be compressed better
+ than with the default empty dictionary. In this version of the library,
+ only the last 32K bytes of the dictionary are used.
+ Upon return of this function, strm->adler is set to the Adler32 value
+ of the dictionary; the decompressor may later use this value to determine
+ which dictionary has been used by the compressor. (The Adler32 value
+ applies to the whole dictionary even if only a subset of the dictionary is
+ actually used by the compressor.)
+
+ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state
+ is inconsistent (for example if deflate has already been called for this
+ stream). deflateSetDictionary does not perform any compression: this will
+ be done by deflate(). }
+
+{EXPORT}
+function deflateCopy (dest : z_streamp;
+ source : z_streamp) : integer;
+
+{ Sets the destination stream as a complete copy of the source stream. If
+ the source stream is using an application-supplied history buffer, a new
+ buffer is allocated for the destination stream. The compressed output
+ buffer is always application-supplied. It's the responsibility of the
+ application to provide the correct values of next_out and avail_out for the
+ next call of deflate.
+
+ This function can be useful when several compression strategies will be
+ tried, for example when there are several ways of pre-processing the input
+ data with a filter. The streams that will be discarded should then be freed
+ by calling deflateEnd. Note that deflateCopy duplicates the internal
+ compression state which can be quite large, so this strategy is slow and
+ can consume lots of memory.
+
+ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as getmem returns nil). msg is left unchanged in both source and
+ destination. }
+
+{EXPORT}
+function deflateReset (var strm : z_stream) : integer;
+
+{ This function is equivalent to deflateEnd followed by deflateInit,
+ but does not free and reallocate all the internal compression state.
+ The stream will keep the same compression level and any other attributes
+ that may have been set by deflateInit2.
+
+ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as getmem or state being NIL). }
+
+
+{EXPORT}
+function deflateParams (var strm : z_stream; level : integer; strategy : integer) : integer;
+
+{ Dynamically update the compression level and compression strategy.
+ This can be used to switch between compression and straight copy of
+ the input data, or to switch to a different kind of input data requiring
+ a different strategy. If the compression level is changed, the input
+ available so far is compressed with the old level (and may be flushed);
+ the new level will take effect only at the next call of deflate().
+
+ Before the call of deflateParams, the stream state must be set as for
+ a call of deflate(), since the currently available input may have to
+ be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+ deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+ stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+ if strm->avail_out was zero. }
+
+
+const
+ deflate_copyright : string = ' deflate 1.1.2 Copyright 1995-1998 Jean-loup Gailly ';
+
+{ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product. }
+
+implementation
+
+uses
+ trees, adler;
+
+{ ===========================================================================
+ Function prototypes. }
+
+type
+ block_state = (
+ need_more, { block not completed, need more input or more output }
+ block_done, { block flush performed }
+ finish_started, { finish started, need only more output at next deflate }
+ finish_done); { finish done, accept no more input or output }
+
+{ Compression function. Returns the block state after the call. }
+type
+ compress_func = function(var s : deflate_state; flush : integer) : block_state;
+
+{local}
+procedure fill_window(var s : deflate_state); forward;
+{local}
+function deflate_stored(var s : deflate_state; flush : integer) : block_state; far; forward;
+{local}
+function deflate_fast(var s : deflate_state; flush : integer) : block_state; far; forward;
+{local}
+function deflate_slow(var s : deflate_state; flush : integer) : block_state; far; forward;
+{local}
+procedure lm_init(var s : deflate_state); forward;
+
+{local}
+procedure putShortMSB(var s : deflate_state; b : cardinal); forward;
+{local}
+procedure flush_pending (var strm : z_stream); forward;
+{local}
+function read_buf(strm : z_streamp;
+ buf : Pbyte;
+ size : cardinal) : cardinal; forward;
+{$ifdef ASMV}
+procedure match_init; { asm code initialization }
+function longest_match(var deflate_state; cur_match : IPos) : cardinal; forward;
+{$else}
+{local}
+function longest_match(var s : deflate_state; cur_match : IPos) : cardinal;
+ forward;
+{$endif}
+
+{$ifdef ZLIB_DEBUG}
+{local}
+procedure check_match(var s : deflate_state;
+ start, match : IPos;
+ length : integer); forward;
+{$endif}
+
+{ ==========================================================================
+ local data }
+
+const
+ ZNIL = 0;
+{ Tail of hash chains }
+
+const
+ TOO_FAR = 4096;
+{ Matches of length 3 are discarded if their distance exceeds TOO_FAR }
+
+const
+ MIN_LOOKAHEAD = (MAX_MATCH+MIN_MATCH+1);
+{ Minimum amount of lookahead, except at the end of the input file.
+ See deflate.c for comments about the MIN_MATCH+1. }
+
+{macro MAX_DIST(var s : deflate_state) : cardinal;
+begin
+ MAX_DIST := (s.w_size - MIN_LOOKAHEAD);
+end;
+ In order to simplify the code, particularly on 16 bit machines, match
+ distances are limited to MAX_DIST instead of WSIZE. }
+
+
+{ Values for max_lazy_match, good_match and max_chain_length, depending on
+ the desired pack level (0..9). The values given below have been tuned to
+ exclude worst case performance for pathological files. Better values may be
+ found for specific files. }
+
+type
+ config = record
+ good_length : word; { reduce lazy search above this match length }
+ max_lazy : word; { do not perform lazy search above this match length }
+ nice_length : word; { quit search above this match length }
+ max_chain : word;
+ func : compress_func;
+ end;
+
+{local}
+const
+ configuration_table : array[0..10-1] of config = (
+{ good lazy nice chain }
+{0} (good_length:0; max_lazy:0; nice_length:0; max_chain:0; func:@deflate_stored), { store only }
+{1} (good_length:4; max_lazy:4; nice_length:8; max_chain:4; func:@deflate_fast), { maximum speed, no lazy matches }
+{2} (good_length:4; max_lazy:5; nice_length:16; max_chain:8; func:@deflate_fast),
+{3} (good_length:4; max_lazy:6; nice_length:32; max_chain:32; func:@deflate_fast),
+
+{4} (good_length:4; max_lazy:4; nice_length:16; max_chain:16; func:@deflate_slow), { lazy matches }
+{5} (good_length:8; max_lazy:16; nice_length:32; max_chain:32; func:@deflate_slow),
+{6} (good_length:8; max_lazy:16; nice_length:128; max_chain:128; func:@deflate_slow),
+{7} (good_length:8; max_lazy:32; nice_length:128; max_chain:256; func:@deflate_slow),
+{8} (good_length:32; max_lazy:128; nice_length:258; max_chain:1024; func:@deflate_slow),
+{9} (good_length:32; max_lazy:258; nice_length:258; max_chain:4096; func:@deflate_slow)); { maximum compression }
+
+{ Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ meaning. }
+
+const
+ EQUAL = 0;
+{ result of memcmp for equal strings }
+
+{ ==========================================================================
+ Update a hash value with the given input byte
+ IN assertion: all calls to to UPDATE_HASH are made with consecutive
+ input characters, so that a running hash key can be computed from the
+ previous key instead of complete recalculation each time.
+
+macro UPDATE_HASH(s,h,c)
+ h := (( (h) shl s^.hash_shift) xor (c)) and s^.hash_mask;
+}
+
+{ ===========================================================================
+ Insert string str in the dictionary and set match_head to the previous head
+ of the hash chain (the most recent string with same hash key). Return
+ the previous length of the hash chain.
+ If this file is compiled with -DFASTEST, the compression level is forced
+ to 1, and no hash chains are maintained.
+ IN assertion: all calls to to INSERT_STRING are made with consecutive
+ input characters and the first MIN_MATCH bytes of str are valid
+ (except for the last MIN_MATCH-1 bytes of the input file). }
+
+procedure INSERT_STRING(var s : deflate_state;
+ str : cardinal;
+ var match_head : IPos);
+begin
+{$ifdef FASTEST}
+ {UPDATE_HASH(s, s.ins_h, s.window[(str) + (MIN_MATCH-1)])}
+ s.ins_h := ((s.ins_h shl s.hash_shift) xor
+ (s.window^[(str) + (MIN_MATCH-1)])) and s.hash_mask;
+ match_head := s.head[s.ins_h]
+ s.head[s.ins_h] := Pos(str);
+{$else}
+ {UPDATE_HASH(s, s.ins_h, s.window[(str) + (MIN_MATCH-1)])}
+ s.ins_h := ((s.ins_h shl s.hash_shift) xor
+ (s.window^[(str) + (MIN_MATCH-1)])) and s.hash_mask;
+
+ match_head := s.head^[s.ins_h];
+ s.prev^[(str) and s.w_mask] := match_head;
+ s.head^[s.ins_h] := Pos(str);
+{$endif}
+end;
+
+{ =========================================================================
+ Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ prev[] will be initialized on the fly.
+
+macro CLEAR_HASH(s)
+ s^.head[s^.hash_size-1] := ZNIL;
+ zmemzero(Pbyte(s^.head), cardinal(s^.hash_size-1)*sizeof(s^.head^[0]));
+}
+
+{ ======================================================================== }
+
+function deflateInit2_(var strm : z_stream;
+ level : integer;
+ method : integer;
+ windowBits : integer;
+ memLevel : integer;
+ strategy : integer;
+ const version : string;
+ stream_size : integer) : integer;
+var
+ s : deflate_state_ptr;
+ noheader : integer;
+
+ overlay : Pwordarray;
+ { We overlay pending_buf and d_buf+l_buf. This works since the average
+ output size for (length,distance) codes is <= 24 bits. }
+begin
+ noheader := 0;
+ if (version = '') or (version[1] <> ZLIB_VERSION[1]) or
+ (stream_size <> sizeof(z_stream)) then
+ begin
+ deflateInit2_ := Z_VERSION_ERROR;
+ exit;
+ end;
+ {
+ if strm=nil then
+ begin
+ deflateInit2_ := Z_STREAM_ERROR;
+ exit;
+ end;
+ }
+ { SetLength(strm.msg, 255); }
+ strm.msg := '';
+
+ if (level = Z_DEFAULT_COMPRESSION) then
+ level := 6;
+{$ifdef FASTEST}
+ level := 1;
+{$endif}
+
+ if (windowBits < 0) then { undocumented feature: suppress zlib header }
+ begin
+ noheader := 1;
+ windowBits := -windowBits;
+ end;
+ if (memLevel < 1) or (memLevel > MAX_MEM_LEVEL) or (method <> Z_DEFLATED)
+ or (windowBits < 8) or (windowBits > 15) or (level < 0)
+ or (level > 9) or (strategy < 0) or (strategy > Z_HUFFMAN_ONLY) then
+ begin
+ deflateInit2_ := Z_STREAM_ERROR;
+ exit;
+ end;
+
+ getmem(s,sizeof(deflate_state));
+ if (s = nil) then
+ begin
+ deflateInit2_ := Z_MEM_ERROR;
+ exit;
+ end;
+ strm.state := pInternal_state(s);
+ s^.strm := @strm;
+
+ s^.noheader := noheader;
+ s^.w_bits := windowBits;
+ s^.w_size := 1 shl s^.w_bits;
+ s^.w_mask := s^.w_size - 1;
+
+ s^.hash_bits := memLevel + 7;
+ s^.hash_size := 1 shl s^.hash_bits;
+ s^.hash_mask := s^.hash_size - 1;
+ s^.hash_shift := ((s^.hash_bits+MIN_MATCH-1) div MIN_MATCH);
+
+ getmem(s^.window,s^.w_size*2*sizeof(byte));
+ getmem(s^.prev,s^.w_size*sizeof(pos));
+ getmem(s^.head,s^.hash_size*sizeof(pos));
+
+ s^.lit_bufsize := 1 shl (memLevel + 6); { 16K elements by default }
+
+ getmem(overlay,s^.lit_bufsize*(sizeof(word)+2));
+ s^.pending_buf := Pbytearray(overlay);
+ s^.pending_buf_size := longint(s^.lit_bufsize) * (sizeof(word)+longint(2));
+
+ if (s^.window=nil) or (s^.prev=nil) or (s^.head=nil) or
+ (s^.pending_buf=nil) then
+ begin
+ {ERR_MSG(Z_MEM_ERROR);}
+ strm.msg := z_errmsg[z_errbase-Z_MEM_ERROR];
+ deflateEnd (strm);
+ deflateInit2_ := Z_MEM_ERROR;
+ exit;
+ end;
+ s^.d_buf := Pwordarray( @overlay^[s^.lit_bufsize div sizeof(word)] );
+ s^.l_buf := Pbytearray( @s^.pending_buf^[(1+sizeof(word))*s^.lit_bufsize] );
+
+ s^.level := level;
+ s^.strategy := strategy;
+ s^.method := Byte(method);
+
+ deflateInit2_ := deflateReset(strm);
+end;
+
+{ ========================================================================= }
+
+function deflateInit2(var strm : z_stream;
+ level : integer;
+ method : integer;
+ windowBits : integer;
+ memLevel : integer;
+ strategy : integer) : integer;
+{ a macro }
+begin
+ deflateInit2 := deflateInit2_(strm, level, method, windowBits,
+ memLevel, strategy, ZLIB_VERSION, sizeof(z_stream));
+end;
+
+{ ========================================================================= }
+
+function deflateInit_(strm : z_streamp;
+ level : integer;
+ const version : string;
+ stream_size : integer) : integer;
+begin
+ if strm=nil then
+ deflateInit_ := Z_STREAM_ERROR
+ else
+ deflateInit_ := deflateInit2_(strm^, level, Z_DEFLATED, MAX_WBITS,
+ DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, version, stream_size);
+ { To do: ignore strm^.next_in if we use it as window }
+end;
+
+{ ========================================================================= }
+
+function deflateInit(var strm : z_stream; level : integer) : integer;
+{ deflateInit is a macro to allow checking the zlib version
+ and the compiler's view of z_stream: }
+begin
+ deflateInit := deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS,
+ DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, ZLIB_VERSION, sizeof(z_stream));
+end;
+
+{ ======================================================================== }
+function deflateSetDictionary (var strm : z_stream;
+ dictionary : Pbyte;
+ dictLength : cardinal) : integer;
+var
+ s : deflate_state_ptr;
+ length : cardinal;
+ n : cardinal;
+ hash_head : IPos;
+var
+ MAX_DIST : cardinal; {macro}
+begin
+ length := dictLength;
+ hash_head := 0;
+
+ if {(@strm=nil) or}
+ (strm.state=nil) or (dictionary=nil)
+ or (deflate_state_ptr(strm.state)^.status<>INIT_STATE) then
+ begin
+ deflateSetDictionary := Z_STREAM_ERROR;
+ exit;
+ end;
+
+ s := deflate_state_ptr(strm.state);
+ strm.adler := adler32(strm.adler, dictionary, dictLength);
+
+ if (length < MIN_MATCH) then
+ begin
+ deflateSetDictionary := Z_OK;
+ exit;
+ end;
+ MAX_DIST := (s^.w_size - MIN_LOOKAHEAD);
+ if (length > MAX_DIST) then
+ begin
+ length := MAX_DIST;
+{$ifndef USE_DICT_HEAD}
+ inc(dictionary, dictLength - length); { use the tail of the dictionary }
+{$endif}
+ end;
+
+ move(dictionary^,Pbyte(s^.window)^,length);
+ s^.strstart := length;
+ s^.block_start := longint(length);
+
+ { Insert all strings in the hash table (except for the last two bytes).
+ s^.lookahead stays null, so s^.ins_h will be recomputed at the next
+ call of fill_window. }
+
+ s^.ins_h := s^.window^[0];
+ {UPDATE_HASH(s, s^.ins_h, s^.window[1]);}
+ s^.ins_h := ((s^.ins_h shl s^.hash_shift) xor (s^.window^[1]))
+ and s^.hash_mask;
+
+ for n := 0 to length - MIN_MATCH do
+ INSERT_STRING(s^, n, hash_head);
+ {if (hash_head <> 0) then
+ hash_head := 0; - to make compiler happy }
+ deflateSetDictionary := Z_OK;
+end;
+
+{ ======================================================================== }
+function deflateReset (var strm : z_stream) : integer;
+var
+ s : deflate_state_ptr;
+begin
+ if {(@strm=nil) or}
+ (strm.state=nil) then
+ begin
+ deflateReset := Z_STREAM_ERROR;
+ exit;
+ end;
+
+ strm.total_out := 0;
+ strm.total_in := 0;
+ strm.msg := ''; { use freemem if we ever allocate msg dynamically }
+ strm.data_type := Z_UNKNOWN;
+
+ s := deflate_state_ptr(strm.state);
+ s^.pending := 0;
+ s^.pending_out := Pbyte(s^.pending_buf);
+
+ if (s^.noheader < 0) then
+ begin
+ s^.noheader := 0; { was set to -1 by deflate(..., Z_FINISH); }
+ end;
+ if s^.noheader <> 0 then
+ s^.status := BUSY_STATE
+ else
+ s^.status := INIT_STATE;
+ strm.adler := 1;
+ s^.last_flush := Z_NO_FLUSH;
+
+ _tr_init(s^);
+ lm_init(s^);
+
+ deflateReset := Z_OK;
+end;
+
+{ ======================================================================== }
+function deflateParams(var strm : z_stream;
+ level : integer;
+ strategy : integer) : integer;
+var
+ s : deflate_state_ptr;
+ func : compress_func;
+ err : integer;
+begin
+ err := Z_OK;
+ if {(@strm=nil) or} (strm.state=nil) then
+ begin
+ deflateParams := Z_STREAM_ERROR;
+ exit;
+ end;
+
+ s := deflate_state_ptr(strm.state);
+
+ if (level = Z_DEFAULT_COMPRESSION) then
+ begin
+ level := 6;
+ end;
+ if (level < 0) or (level > 9) or (strategy < 0)
+ or (strategy > Z_HUFFMAN_ONLY) then
+ begin
+ deflateParams := Z_STREAM_ERROR;
+ exit;
+ end;
+ func := configuration_table[s^.level].func;
+
+ if (@func <> @configuration_table[level].func)
+ and (strm.total_in <> 0) then
+ begin
+ { Flush the last buffer: }
+ err := deflate(strm, Z_PARTIAL_FLUSH);
+ end;
+ if (s^.level <> level) then
+ begin
+ s^.level := level;
+ s^.max_lazy_match := configuration_table[level].max_lazy;
+ s^.good_match := configuration_table[level].good_length;
+ s^.nice_match := configuration_table[level].nice_length;
+ s^.max_chain_length := configuration_table[level].max_chain;
+ end;
+ s^.strategy := strategy;
+ deflateParams := err;
+end;
+
+{ =========================================================================
+ Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ IN assertion: the stream state is correct and there is enough room in
+ pending_buf. }
+
+{local}
+procedure putShortMSB (var s : deflate_state; b : cardinal);
+begin
+ s.pending_buf^[s.pending] := Byte(b shr 8);
+ inc(s.pending);
+ s.pending_buf^[s.pending] := Byte(b and $ff);
+ inc(s.pending);
+end;
+
+{ =========================================================================
+ Flush as much pending output as possible. All deflate() output goes
+ through this function so some applications may wish to modify it
+ to avoid allocating a large strm^.next_out buffer and copying into it.
+ (See also read_buf()). }
+
+{local}
+procedure flush_pending(var strm : z_stream);
+var
+ len : cardinal;
+ s : deflate_state_ptr;
+begin
+ s := deflate_state_ptr(strm.state);
+ len := s^.pending;
+
+ if (len > strm.avail_out) then
+ len := strm.avail_out;
+ if (len = 0) then
+ exit;
+
+ move(s^.pending_out^,strm.next_out^,len);
+ inc(strm.next_out, len);
+ inc(s^.pending_out, len);
+ inc(strm.total_out, len);
+ dec(strm.avail_out, len);
+ dec(s^.pending, len);
+ if (s^.pending = 0) then
+ begin
+ s^.pending_out := Pbyte(s^.pending_buf);
+ end;
+end;
+
+{ ========================================================================= }
+function deflate (var strm : z_stream; flush : integer) : integer;
+var
+ old_flush : integer; { value of flush param for previous deflate call }
+ s : deflate_state_ptr;
+var
+ header : cardinal;
+ level_flags : cardinal;
+var
+ bstate : block_state;
+begin
+ if {(@strm=nil) or} (strm.state=nil)
+ or (flush > Z_FINISH) or (flush < 0) then
+ begin
+ deflate := Z_STREAM_ERROR;
+ exit;
+ end;
+ s := deflate_state_ptr(strm.state);
+
+ if (strm.next_out=nil) or
+ ((strm.next_in=nil) and (strm.avail_in<>0)) or
+ ((s^.status=FINISH_STATE) and (flush<>Z_FINISH)) then
+ begin
+ {ERR_RETURN(strm^, Z_STREAM_ERROR);}
+ strm.msg := z_errmsg[z_errbase - Z_STREAM_ERROR];
+ deflate := Z_STREAM_ERROR;
+ exit;
+ end;
+ if (strm.avail_out = 0) then
+ begin
+ {ERR_RETURN(strm^, Z_BUF_ERROR);}
+ strm.msg := z_errmsg[z_errbase - Z_BUF_ERROR];
+ deflate := Z_BUF_ERROR;
+ exit;
+ end;
+
+ s^.strm := @strm; { just in case }
+ old_flush := s^.last_flush;
+ s^.last_flush := flush;
+
+ { Write the zlib header }
+ if (s^.status = INIT_STATE) then
+ begin
+
+ header := (Z_DEFLATED + ((s^.w_bits-8) shl 4)) shl 8;
+ level_flags := (s^.level-1) shr 1;
+
+ if (level_flags > 3) then
+ level_flags := 3;
+ header := header or (level_flags shl 6);
+ if (s^.strstart <> 0) then
+ header := header or PRESET_DICT;
+ inc(header, 31 - (header mod 31));
+
+ s^.status := BUSY_STATE;
+ putShortMSB(s^, header);
+
+ { Save the adler32 of the preset dictionary: }
+ if (s^.strstart <> 0) then
+ begin
+ putShortMSB(s^, cardinal(strm.adler shr 16));
+ putShortMSB(s^, cardinal(strm.adler and $ffff));
+ end;
+ strm.adler := longint(1);
+ end;
+
+ { Flush as much pending output as possible }
+ if (s^.pending <> 0) then
+ begin
+ flush_pending(strm);
+ if (strm.avail_out = 0) then
+ begin
+ { Since avail_out is 0, deflate will be called again with
+ more output space, but possibly with both pending and
+ avail_in equal to zero. There won't be anything to do,
+ but this is not an error situation so make sure we
+ return OK instead of BUF_ERROR at next call of deflate: }
+
+ s^.last_flush := -1;
+ deflate := Z_OK;
+ exit;
+ end;
+
+ { Make sure there is something to do and avoid duplicate consecutive
+ flushes. For repeated and useless calls with Z_FINISH, we keep
+ returning Z_STREAM_END instead of Z_BUFF_ERROR. }
+
+ end
+ else
+ if (strm.avail_in = 0) and (flush <= old_flush)
+ and (flush <> Z_FINISH) then
+ begin
+ {ERR_RETURN(strm^, Z_BUF_ERROR);}
+ strm.msg := z_errmsg[z_errbase - Z_BUF_ERROR];
+ deflate := Z_BUF_ERROR;
+ exit;
+ end;
+
+ { User must not provide more input after the first FINISH: }
+ if (s^.status = FINISH_STATE) and (strm.avail_in <> 0) then
+ begin
+ {ERR_RETURN(strm^, Z_BUF_ERROR);}
+ strm.msg := z_errmsg[z_errbase - Z_BUF_ERROR];
+ deflate := Z_BUF_ERROR;
+ exit;
+ end;
+
+ { Start a new block or continue the current one. }
+ if (strm.avail_in <> 0) or (s^.lookahead <> 0)
+ or ((flush <> Z_NO_FLUSH) and (s^.status <> FINISH_STATE)) then
+ begin
+ bstate := configuration_table[s^.level].func(s^, flush);
+
+ if (bstate = finish_started) or (bstate = finish_done) then
+ s^.status := FINISH_STATE;
+
+ if (bstate = need_more) or (bstate = finish_started) then
+ begin
+ if (strm.avail_out = 0) then
+ s^.last_flush := -1; { avoid BUF_ERROR next call, see above }
+
+ deflate := Z_OK;
+ exit;
+ { If flush != Z_NO_FLUSH && avail_out == 0, the next call
+ of deflate should use the same flush parameter to make sure
+ that the flush is complete. So we don't have to output an
+ empty block here, this will be done at next call. This also
+ ensures that for a very small output buffer, we emit at most
+ one empty block. }
+ end;
+ if (bstate = block_done) then
+ begin
+ if (flush = Z_PARTIAL_FLUSH) then
+ _tr_align(s^)
+ else
+ begin { FULL_FLUSH or SYNC_FLUSH }
+ _tr_stored_block(s^, nil, 0, FALSE);
+ { For a full flush, this empty block will be recognized
+ as a special marker by inflate_sync(). }
+
+ if (flush = Z_FULL_FLUSH) then
+ begin
+ {macro CLEAR_HASH(s);} { forget history }
+ s^.head^[s^.hash_size-1] := ZNIL;
+ fillchar(Pbyte(s^.head)^,cardinal(s^.hash_size-1)*sizeof(s^.head^[0]),0);
+ end;
+ end;
+
+ flush_pending(strm);
+ if (strm.avail_out = 0) then
+ begin
+ s^.last_flush := -1; { avoid BUF_ERROR at next call, see above }
+ deflate := Z_OK;
+ exit;
+ end;
+
+ end;
+ end;
+ {$IFDEF ZLIB_DEBUG}
+ Assert(strm.avail_out > 0, 'bug2');
+ {$ENDIF}
+ if (flush <> Z_FINISH) then
+ begin
+ deflate := Z_OK;
+ exit;
+ end;
+
+ if (s^.noheader <> 0) then
+ begin
+ deflate := Z_STREAM_END;
+ exit;
+ end;
+
+ { Write the zlib trailer (adler32) }
+ putShortMSB(s^, cardinal(strm.adler shr 16));
+ putShortMSB(s^, cardinal(strm.adler and $ffff));
+ flush_pending(strm);
+ { If avail_out is zero, the application will call deflate again
+ to flush the rest. }
+
+ s^.noheader := -1; { write the trailer only once! }
+ if s^.pending <> 0 then
+ deflate := Z_OK
+ else
+ deflate := Z_STREAM_END;
+end;
+
+{ ========================================================================= }
+function deflateEnd (var strm : z_stream) : integer;
+var
+ status : integer;
+ s : deflate_state_ptr;
+begin
+ if {(@strm=nil) or} (strm.state=nil) then
+ begin
+ deflateEnd := Z_STREAM_ERROR;
+ exit;
+ end;
+
+ s := deflate_state_ptr(strm.state);
+ status := s^.status;
+ if (status <> INIT_STATE) and (status <> BUSY_STATE) and
+ (status <> FINISH_STATE) then
+ begin
+ deflateEnd := Z_STREAM_ERROR;
+ exit;
+ end;
+
+ { Deallocate in reverse order of allocations: }
+ freemem(s^.pending_buf);
+ freemem(s^.head);
+ freemem(s^.prev);
+ freemem(s^.window);
+
+ freemem(s);
+ strm.state := nil;
+
+ if status = BUSY_STATE then
+ deflateEnd := Z_DATA_ERROR
+ else
+ deflateEnd := Z_OK;
+end;
+
+{ =========================================================================
+ Copy the source state to the destination state.
+ To simplify the source, this is not supported for 16-bit MSDOS (which
+ doesn't have enough memory anyway to duplicate compression states). }
+
+
+{ ========================================================================= }
+function deflateCopy (dest, source : z_streamp) : integer;
+{$ifndef MAXSEG_64K}
+var
+ ds : deflate_state_ptr;
+ ss : deflate_state_ptr;
+ overlay : Pwordarray;
+{$endif}
+begin
+{$ifdef MAXSEG_64K}
+ deflateCopy := Z_STREAM_ERROR;
+ exit;
+{$else}
+
+ if (source=nil) or (dest=nil) or (source^.state=nil) then
+ begin
+ deflateCopy := Z_STREAM_ERROR;
+ exit;
+ end;
+ ss := deflate_state_ptr(source^.state);
+ dest^ := source^;
+
+ getmem(ds,sizeof(deflate_state));
+ if ds=nil then
+ begin
+ deflateCopy := Z_MEM_ERROR;
+ exit;
+ end;
+ dest^.state := pInternal_state(ds);
+ ds^ := ss^;
+ ds^.strm := dest;
+
+ getmem(ds^.window,ds^.w_size*2*sizeof(byte));
+ getmem(ds^.prev,ds^.w_size*sizeof(pos));
+ getmem(ds^.head,ds^.hash_size*sizeof(pos));
+ getmem(overlay,ds^.lit_bufsize*(sizeof(word)+2));
+ ds^.pending_buf := Pbytearray ( overlay );
+
+ if (ds^.window=nil) or (ds^.prev=nil) or (ds^.head=nil)
+ or (ds^.pending_buf=nil) then
+ begin
+ deflateEnd (dest^);
+ deflateCopy := Z_MEM_ERROR;
+ exit;
+ end;
+
+ move(Pbyte(ss^.window)^,Pbyte(ds^.window)^,ds^.w_size * 2 * sizeof(byte));
+ move(Pbyte(ss^.prev)^,Pbyte(ds^.prev)^,ds^.w_size * sizeof(pos));
+ move(Pbyte(ss^.head)^,Pbyte(ds^.head)^,ds^.hash_size * sizeof(pos));
+ move(Pbyte(ss^.pending_buf)^,Pbyte(ds^.pending_buf)^,cardinal(ds^.pending_buf_size));
+
+ ds^.pending_out := @ds^.pending_buf^[ptruint(ss^.pending_out) - ptruint(ss^.pending_buf)];
+ ds^.d_buf := Pwordarray(@overlay^[ds^.lit_bufsize div sizeof(word)] );
+ ds^.l_buf := Pbytearray(@ds^.pending_buf^[(1+sizeof(word))*ds^.lit_bufsize]);
+
+ ds^.l_desc.dyn_tree := tree_ptr(@ds^.dyn_ltree);
+ ds^.d_desc.dyn_tree := tree_ptr(@ds^.dyn_dtree);
+ ds^.bl_desc.dyn_tree := tree_ptr(@ds^.bl_tree);
+
+ deflateCopy := Z_OK;
+{$endif}
+end;
+
+
+{ ===========================================================================
+ Read a new buffer from the current input stream, update the adler32
+ and total number of bytes read. All deflate() input goes through
+ this function so some applications may wish to modify it to avoid
+ allocating a large strm^.next_in buffer and copying from it.
+ (See also flush_pending()). }
+
+{local}
+function read_buf(strm:z_streamp;buf:Pbyte;size:cardinal):cardinal;
+
+var len:cardinal;
+
+begin
+ len:=strm^.avail_in;
+ if len>size then
+ len:=size;
+ dec(strm^.avail_in, len);
+
+ if len<>0 then
+ begin
+ if deflate_state_ptr(strm^.state)^.noheader=0 then
+ strm^.adler:=adler32(strm^.adler,strm^.next_in,len);
+ move(strm^.next_in^,buf^,len);
+ inc(strm^.next_in,len);
+ inc(strm^.total_in,len);
+ end;
+ read_buf:=len;
+end;
+
+{ ===========================================================================
+ Initialize the "longest match" routines for a new zlib stream }
+
+{local}
+procedure lm_init (var s : deflate_state);
+begin
+ s.window_size := longint( 2*s.w_size);
+
+ {macro CLEAR_HASH(s);}
+ s.head^[s.hash_size-1] := ZNIL;
+ fillchar(Pbyte(s.head)^, cardinal(s.hash_size-1)*sizeof(s.head^[0]),0);
+
+ { Set the default configuration parameters: }
+
+ s.max_lazy_match := configuration_table[s.level].max_lazy;
+ s.good_match := configuration_table[s.level].good_length;
+ s.nice_match := configuration_table[s.level].nice_length;
+ s.max_chain_length := configuration_table[s.level].max_chain;
+
+ s.strstart := 0;
+ s.block_start := longint(0);
+ s.lookahead := 0;
+ s.prev_length := MIN_MATCH-1;
+ s.match_length := MIN_MATCH-1;
+ s.match_available := FALSE;
+ s.ins_h := 0;
+{$ifdef ASMV}
+ match_init; { initialize the asm code }
+{$endif}
+end;
+
+{ ===========================================================================
+ Set match_start to the longest match starting at the given string and
+ return its length. Matches shorter or equal to prev_length are discarded,
+ in which case the result is equal to prev_length and match_start is
+ garbage.
+ IN assertions: cur_match is the head of the hash chain for the current
+ string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ OUT assertion: the match length is not greater than s^.lookahead. }
+
+
+{$ifndef ASMV}
+{ For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ match.S. The code will be functionally equivalent. }
+
+{$ifndef FASTEST}
+
+{local}
+function longest_match(var s : deflate_state;
+ cur_match : IPos { current match }
+ ) : cardinal;
+label
+ nextstep;
+var
+ chain_length : cardinal; { max hash chain length }
+ {register} scan : Pbyte; { current string }
+ {register} match : Pbyte; { matched string }
+ {register} len : integer; { length of current match }
+ best_len : integer; { best match length so far }
+ nice_match : integer; { stop if match longint enough }
+ limit : IPos;
+
+ prev : pzPosfArray;
+ wmask : cardinal;
+{$ifdef UNALIGNED_OK}
+ {register} strend : Pbyte;
+ {register} scan_start : word;
+ {register} scan_end : word;
+{$else}
+ {register} strend : Pbyte;
+ {register} scan_end1 : Byte;
+ {register} scan_end : Byte;
+{$endif}
+var
+ MAX_DIST : cardinal;
+begin
+ chain_length := s.max_chain_length; { max hash chain length }
+ scan := @(s.window^[s.strstart]);
+ best_len := s.prev_length; { best match length so far }
+ nice_match := s.nice_match; { stop if match longint enough }
+
+
+ MAX_DIST := s.w_size - MIN_LOOKAHEAD;
+{In order to simplify the code, particularly on 16 bit machines, match
+distances are limited to MAX_DIST instead of WSIZE. }
+
+ if s.strstart > IPos(MAX_DIST) then
+ limit := s.strstart - IPos(MAX_DIST)
+ else
+ limit := ZNIL;
+ { Stop when cur_match becomes <= limit. To simplify the code,
+ we prevent matches with the string of window index 0. }
+
+ prev := s.prev;
+ wmask := s.w_mask;
+
+{$ifdef UNALIGNED_OK}
+ { Compare two bytes at a time. Note: this is not always beneficial.
+ Try with and without -DUNALIGNED_OK to check. }
+
+ strend := Pbyte(@(s.window^[s.strstart + MAX_MATCH - 1]));
+ scan_start := pushf(scan)^;
+ scan_end := Pwordarray(scan)^[best_len-1]; { fix }
+{$else}
+ strend := Pbyte(@(s.window^[s.strstart + MAX_MATCH]));
+ {$IFOPT R+} {$R-} {$DEFINE NoRangeCheck} {$ENDIF}
+ scan_end1 := Pbytearray(scan)^[best_len-1];
+ {$IFDEF NoRangeCheck} {$R+} {$UNDEF NoRangeCheck} {$ENDIF}
+ scan_end := Pbytearray(scan)^[best_len];
+{$endif}
+
+ { The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ It is easy to get rid of this optimization if necessary. }
+ {$IFDEF ZLIB_DEBUG}
+ Assert((s.hash_bits >= 8) and (MAX_MATCH = 258), 'Code too clever');
+ {$ENDIF}
+ { Do not waste too much time if we already have a good match: }
+ if (s.prev_length >= s.good_match) then
+ begin
+ chain_length := chain_length shr 2;
+ end;
+
+ { Do not look for matches beyond the end of the input. This is necessary
+ to make deflate deterministic. }
+
+ if (cardinal(nice_match) > s.lookahead) then
+ nice_match := s.lookahead;
+ {$IFDEF ZLIB_DEBUG}
+ Assert(longint(s.strstart) <= s.window_size-MIN_LOOKAHEAD, 'need lookahead');
+ {$ENDIF}
+ repeat
+ {$IFDEF ZLIB_DEBUG}
+ Assert(cur_match < s.strstart, 'no future');
+ {$ENDIF}
+ match := @(s.window^[cur_match]);
+
+ { Skip to next match if the match length cannot increase
+ or if the match length is less than 2: }
+
+{$undef DO_UNALIGNED_OK}
+{$ifdef UNALIGNED_OK}
+ {$ifdef MAX_MATCH_IS_258}
+ {$define DO_UNALIGNED_OK}
+ {$endif}
+{$endif}
+
+{$ifdef DO_UNALIGNED_OK}
+ { This code assumes sizeof(cardinal short) = 2. Do not use
+ UNALIGNED_OK if your compiler uses a different size. }
+ {$IFOPT R+} {$R-} {$DEFINE NoRangeCheck} {$ENDIF}
+ if (match[best_len-1]<>scan_end) or
+ (match^ <> scan_start) then
+ goto nextstep; {continue;}
+ {$IFDEF NoRangeCheck} {$R+} {$UNDEF NoRangeCheck} {$ENDIF}
+
+ { It is not necessary to compare scan[2] and match[2] since they are
+ always equal when the other bytes match, given that the hash keys
+ are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+ strstart+3, +5, ... up to strstart+257. We check for insufficient
+ lookahead only every 4th comparison; the 128th check will be made
+ at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+ necessary to put more guard bytes at the end of the window, or
+ to check more often for insufficient lookahead. }
+ {$IFDEF ZLIB_DEBUG}
+ Assert(pzByteArray(scan)^[2] = pzByteArray(match)^[2], 'scan[2]?');
+ {$ENDIF}
+ inc(scan);
+ inc(match);
+
+ repeat
+ inc(scan,2); inc(match,2); if scan^<>match^ then break;
+ inc(scan,2); inc(match,2); if scan^<>match^ then break;
+ inc(scan,2); inc(match,2); if scan^<>match^ then break;
+ inc(scan,2); inc(match,2); if scan^<>match^ then break;
+ until ptruint(scan)>=ptruint(strend);
+ { The funny "do while" generates better code on most compilers }
+
+ { Here, scan <= window+strstart+257 }
+ {$IFDEF ZLIB_DEBUG}
+ {$ifopt R+} {$define RangeCheck} {$endif} {$R-}
+ Assert(ptruint(scan) <=
+ ptruint(@(s.window^[cardinal(s.window_size-1)])),
+ 'wild scan');
+ {$ifdef RangeCheck} {$R+} {$undef RangeCheck} {$endif}
+ {$ENDIF}
+ if scan^=match^ then
+ inc(scan);
+
+ len := (MAX_MATCH - 1) - integer(ptruint(strend)) + integer(ptruint(scan));
+ scan := strend;
+ dec(scan, (MAX_MATCH-1));
+
+{$else} { UNALIGNED_OK }
+
+ {$IFOPT R+} {$R-} {$DEFINE NoRangeCheck} {$ENDIF}
+ if (Pbytearray(match)^[best_len] <> scan_end) or
+ (Pbytearray(match)^[best_len-1] <> scan_end1) or
+ (match^ <> scan^) then
+ goto nextstep; {continue;}
+ {$IFDEF NoRangeCheck} {$R+} {$UNDEF NoRangeCheck} {$ENDIF}
+ inc(match);
+ if (match^ <> Pbytearray(scan)^[1]) then
+ goto nextstep; {continue;}
+
+ { The check at best_len-1 can be removed because it will be made
+ again later. (This heuristic is not always a win.)
+ It is not necessary to compare scan[2] and match[2] since they
+ are always equal when the other bytes match, given that
+ the hash keys are equal and that HASH_BITS >= 8. }
+
+ inc(scan, 2);
+ inc(match);
+ {$IFDEF ZLIB_DEBUG}
+ Assert( scan^ = match^, 'match[2]?');
+ {$ENDIF}
+ { We check for insufficient lookahead only every 8th comparison;
+ the 256th check will be made at strstart+258. }
+
+ repeat
+ inc(scan); inc(match); if scan^ <> match^ then break;
+ inc(scan); inc(match); if scan^ <> match^ then break;
+ inc(scan); inc(match); if scan^ <> match^ then break;
+ inc(scan); inc(match); if scan^ <> match^ then break;
+ inc(scan); inc(match); if scan^ <> match^ then break;
+ inc(scan); inc(match); if scan^ <> match^ then break;
+ inc(scan); inc(match); if scan^ <> match^ then break;
+ inc(scan); inc(match); if scan^ <> match^ then break;
+ until ptruint(scan)>=ptruint(strend);
+
+ {$IFDEF ZLIB_DEBUG}
+ Assert(ptruint(scan) <=
+ ptruint(@(s.window^[cardinal(s.window_size-1)])),
+ 'wild scan');
+ {$ENDIF}
+
+ len := MAX_MATCH - (ptruint(strend) - ptruint(scan));
+ scan := strend;
+ dec(scan, MAX_MATCH);
+
+{$endif} { UNALIGNED_OK }
+
+ if (len > best_len) then
+ begin
+ s.match_start := cur_match;
+ best_len := len;
+ if (len >= nice_match) then
+ break;
+ {$IFOPT R+} {$R-} {$DEFINE NoRangeCheck} {$ENDIF}
+{$ifdef UNALIGNED_OK}
+ scan_end := Pbytearray(scan)^[best_len-1];
+{$else}
+ scan_end1 := Pbytearray(scan)^[best_len-1];
+ scan_end := Pbytearray(scan)^[best_len];
+{$endif}
+ {$IFDEF NoRangeCheck} {$R+} {$UNDEF NoRangeCheck} {$ENDIF}
+ end;
+ nextstep:
+ cur_match := prev^[cur_match and wmask];
+ dec(chain_length);
+ until (cur_match <= limit) or (chain_length = 0);
+
+ if (cardinal(best_len) <= s.lookahead) then
+ longest_match := cardinal(best_len)
+ else
+ longest_match := s.lookahead;
+end;
+{$endif} { ASMV }
+
+{$else} { FASTEST }
+{ ---------------------------------------------------------------------------
+ Optimized version for level = 1 only }
+
+{local}
+function longest_match(var s : deflate_state;
+ cur_match : IPos { current match }
+ ) : cardinal;
+var
+ {register} scan : Pbyte; { current string }
+ {register} match : Pbyte; { matched string }
+ {register} len : integer; { length of current match }
+ {register} strend : Pbyte;
+begin
+ scan := @s.window^[s.strstart];
+ strend := @s.window^[s.strstart + MAX_MATCH];
+
+
+ { The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ It is easy to get rid of this optimization if necessary. }
+ {$IFDEF ZLIB_DEBUG}
+ Assert((s.hash_bits >= 8) and (MAX_MATCH = 258), 'Code too clever');
+
+ Assert(longint(s.strstart) <= s.window_size-MIN_LOOKAHEAD, 'need lookahead');
+
+ Assert(cur_match < s.strstart, 'no future');
+ {$ENDIF}
+ match := s.window + cur_match;
+
+ { Return failure if the match length is less than 2: }
+
+ if (match[0] <> scan[0]) or (match[1] <> scan[1]) then
+ begin
+ longest_match := MIN_MATCH-1;
+ exit;
+ end;
+
+ { The check at best_len-1 can be removed because it will be made
+ again later. (This heuristic is not always a win.)
+ It is not necessary to compare scan[2] and match[2] since they
+ are always equal when the other bytes match, given that
+ the hash keys are equal and that HASH_BITS >= 8. }
+
+ scan += 2, match += 2;
+ Assert(scan^ = match^, 'match[2]?');
+
+ { We check for insufficient lookahead only every 8th comparison;
+ the 256th check will be made at strstart+258. }
+
+ repeat
+ inc(scan); inc(match); if scan^<>match^ then break;
+ inc(scan); inc(match); if scan^<>match^ then break;
+ inc(scan); inc(match); if scan^<>match^ then break;
+ inc(scan); inc(match); if scan^<>match^ then break;
+ inc(scan); inc(match); if scan^<>match^ then break;
+ inc(scan); inc(match); if scan^<>match^ then break;
+ inc(scan); inc(match); if scan^<>match^ then break;
+ inc(scan); inc(match); if scan^<>match^ then break;
+ until (ptruint(scan) >= ptruint(strend));
+
+ Assert(scan <= s.window+cardinal(s.window_size-1), 'wild scan');
+
+ len := MAX_MATCH - integer(strend - scan);
+
+ if (len < MIN_MATCH) then
+ begin
+ return := MIN_MATCH - 1;
+ exit;
+ end;
+
+ s.match_start := cur_match;
+ if len <= s.lookahead then
+ longest_match := len
+ else
+ longest_match := s.lookahead;
+end;
+{$endif} { FASTEST }
+
+{$ifdef ZLIB_DEBUG}
+{ ===========================================================================
+ Check that the match at match_start is indeed a match. }
+
+{local}
+procedure check_match(var s : deflate_state;
+ start, match : IPos;
+ length : integer);
+begin
+ exit;
+ { check that the match is indeed a match }
+ if (zmemcmp(Pbyte(@s.window^[match]),
+ Pbyte(@s.window^[start]), length) <> EQUAL) then
+ begin
+ WriteLn(' start ',start,', match ',match ,' length ', length);
+ repeat
+ Write(char(s.window^[match]), char(s.window^[start]));
+ inc(match);
+ inc(start);
+ dec(length);
+ Until (length = 0);
+ z_error('invalid match');
+ end;
+ if (z_verbose > 1) then
+ begin
+ Write('\\[',start-match,',',length,']');
+ repeat
+ Write(char(s.window^[start]));
+ inc(start);
+ dec(length);
+ Until (length = 0);
+ end;
+end;
+{$endif}
+
+{ ===========================================================================
+ Fill the window when the lookahead becomes insufficient.
+ Updates strstart and lookahead.
+
+ IN assertion: lookahead < MIN_LOOKAHEAD
+ OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ At least one byte has been read, or avail_in = 0; reads are
+ performed for at least two bytes (required for the zip translate_eol
+ option -- not supported here). }
+
+{local}
+procedure fill_window(var s : deflate_state);
+var
+ {register} n, m : cardinal;
+ {register} p : pPosf;
+ more : cardinal; { Amount of free space at the end of the window. }
+ wsize : cardinal;
+begin
+ wsize := s.w_size;
+ repeat
+ more := cardinal(s.window_size -longint(s.lookahead) -longint(s.strstart));
+
+ { Deal with !@#$% 64K limit: }
+ if (more = 0) and (s.strstart = 0) and (s.lookahead = 0) then
+ more := wsize
+ else
+ if (more = cardinal(-1)) then
+ begin
+ { Very unlikely, but possible on 16 bit machine if strstart = 0
+ and lookahead = 1 (input done one byte at time) }
+ dec(more);
+
+ { If the window is almost full and there is insufficient lookahead,
+ move the upper half to the lower one to make room in the upper half.}
+ end
+ else
+ if (s.strstart >= wsize+ {MAX_DIST}(wsize-MIN_LOOKAHEAD)) then
+ begin
+ move(s.window^[wsize],Pbyte(s.window)^,wsize);
+ dec(s.match_start, wsize);
+ dec(s.strstart, wsize); { we now have strstart >= MAX_DIST }
+ dec(s.block_start, longint(wsize));
+
+ { Slide the hash table (could be avoided with 32 bit values
+ at the expense of memory usage). We slide even when level = 0
+ to keep the hash table consistent if we switch back to level > 0
+ later. (Using level 0 permanently is not an optimal usage of
+ zlib, so we don't care about this pathological case.) }
+
+ n := s.hash_size;
+ p := @s.head^[n];
+ repeat
+ dec(p);
+ m := p^;
+ if (m >= wsize) then
+ p^ := Pos(m-wsize)
+ else
+ p^ := Pos(ZNIL);
+ dec(n);
+ Until (n=0);
+
+ n := wsize;
+{$ifndef FASTEST}
+ p := @s.prev^[n];
+ repeat
+ dec(p);
+ m := p^;
+ if (m >= wsize) then
+ p^ := Pos(m-wsize)
+ else
+ p^:= Pos(ZNIL);
+ { If n is not on any hash chain, prev^[n] is garbage but
+ its value will never be used. }
+ dec(n);
+ Until (n=0);
+{$endif}
+ inc(more, wsize);
+ end;
+ if (s.strm^.avail_in = 0) then
+ exit;
+
+ {* If there was no sliding:
+ * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+ * more == window_size - lookahead - strstart
+ * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+ * => more >= window_size - 2*WSIZE + 2
+ * In the BIG_MEM or MMAP case (not yet supported),
+ * window_size == input_size + MIN_LOOKAHEAD &&
+ * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+ * Otherwise, window_size == 2*WSIZE so more >= 2.
+ * If there was sliding, more >= WSIZE. So in all cases, more >= 2. }
+
+ {$IFDEF ZLIB_DEBUG}
+ Assert(more >= 2, 'more < 2');
+ {$ENDIF}
+
+ n := read_buf(s.strm, Pbyte(@(s.window^[s.strstart + s.lookahead])),
+ more);
+ inc(s.lookahead, n);
+
+ { Initialize the hash value now that we have some input: }
+ if (s.lookahead >= MIN_MATCH) then
+ begin
+ s.ins_h := s.window^[s.strstart];
+ {UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]);}
+ s.ins_h := ((s.ins_h shl s.hash_shift) xor s.window^[s.strstart+1])
+ and s.hash_mask;
+{$ifdef MIN_MATCH <> 3}
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+{$endif}
+ end;
+ { If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+ but this is not important since only literal bytes will be emitted. }
+
+ until (s.lookahead >= MIN_LOOKAHEAD) or (s.strm^.avail_in = 0);
+end;
+
+{ ===========================================================================
+ Flush the current block, with given end-of-file flag.
+ IN assertion: strstart is set to the end of the current match. }
+
+procedure FLUSH_BLOCK_ONLY(var s : deflate_state; eof : boolean); {macro}
+begin
+ if (s.block_start >= 0) then
+ _tr_flush_block(s, Pbyte(@s.window^[s.block_start]),
+ longint(longint(s.strstart) - s.block_start), eof)
+ else
+ _tr_flush_block(s, nil,
+ longint(longint(s.strstart) - s.block_start), eof);
+
+ s.block_start := s.strstart;
+ flush_pending(s.strm^);
+ {$IFDEF ZLIB_DEBUG}
+ Tracev('[FLUSH]');
+ {$ENDIF}
+end;
+
+{ Same but force premature exit if necessary.
+macro FLUSH_BLOCK(var s : deflate_state; eof : boolean) : boolean;
+var
+ result : block_state;
+begin
+ FLUSH_BLOCK_ONLY(s, eof);
+ if (s.strm^.avail_out = 0) then
+ begin
+ if eof then
+ result := finish_started
+ else
+ result := need_more;
+ exit;
+ end;
+end;
+}
+
+{ ===========================================================================
+ Copy without compression as much as possible from the input stream, return
+ the current block state.
+ This function does not insert new strings in the dictionary since
+ uncompressible data is probably not useful. This function is used
+ only for the level=0 compression option.
+ NOTE: this function should be optimized to avoid extra copying from
+ window to pending_buf. }
+
+
+{local}
+function deflate_stored(var s : deflate_state; flush : integer) : block_state;
+{ Stored blocks are limited to 0xffff bytes, pending_buf is limited
+ to pending_buf_size, and each stored block has a 5 byte header: }
+var
+ max_block_size : longint;
+ max_start : longint;
+begin
+ max_block_size := $ffff;
+ if (max_block_size > s.pending_buf_size - 5) then
+ max_block_size := s.pending_buf_size - 5;
+
+ { Copy as much as possible from input to output: }
+ while TRUE do
+ begin
+ { Fill the window as much as possible: }
+ if (s.lookahead <= 1) then
+ begin
+ {$IFDEF ZLIB_DEBUG}
+ Assert( (s.strstart < s.w_size + {MAX_DIST}s.w_size-MIN_LOOKAHEAD) or
+ (s.block_start >= longint(s.w_size)), 'slide too late');
+ {$ENDIF}
+ fill_window(s);
+ if (s.lookahead = 0) and (flush = Z_NO_FLUSH) then
+ begin
+ deflate_stored := need_more;
+ exit;
+ end;
+
+ if (s.lookahead = 0) then
+ break; { flush the current block }
+ end;
+ {$IFDEF ZLIB_DEBUG}
+ Assert(s.block_start >= 0, 'block gone');
+ {$ENDIF}
+ inc(s.strstart, s.lookahead);
+ s.lookahead := 0;
+
+ { Emit a stored block if pending_buf will be full: }
+ max_start := s.block_start + max_block_size;
+ if (s.strstart = 0) or (longint(s.strstart) >= max_start) then
+ begin
+ { strstart = 0 is possible when wraparound on 16-bit machine }
+ s.lookahead := cardinal(s.strstart) - cardinal(max_start);
+ s.strstart := cardinal(max_start);
+ {FLUSH_BLOCK(s, FALSE);}
+ FLUSH_BLOCK_ONLY(s, FALSE);
+ if (s.strm^.avail_out = 0) then
+ begin
+ deflate_stored := need_more;
+ exit;
+ end;
+ end;
+
+ { Flush if we may have to slide, otherwise block_start may become
+ negative and the data will be gone: }
+
+ if (s.strstart - cardinal(s.block_start) >= {MAX_DIST}
+ s.w_size-MIN_LOOKAHEAD) then
+ begin
+ {FLUSH_BLOCK(s, FALSE);}
+ FLUSH_BLOCK_ONLY(s, FALSE);
+ if (s.strm^.avail_out = 0) then
+ begin
+ deflate_stored := need_more;
+ exit;
+ end;
+ end;
+ end;
+
+ {FLUSH_BLOCK(s, flush = Z_FINISH);}
+ FLUSH_BLOCK_ONLY(s, flush = Z_FINISH);
+ if (s.strm^.avail_out = 0) then
+ begin
+ if flush = Z_FINISH then
+ deflate_stored := finish_started
+ else
+ deflate_stored := need_more;
+ exit;
+ end;
+
+ if flush = Z_FINISH then
+ deflate_stored := finish_done
+ else
+ deflate_stored := block_done;
+end;
+
+{ ===========================================================================
+ Compress as much as possible from the input stream, return the current
+ block state.
+ This function does not perform lazy evaluation of matches and inserts
+ new strings in the dictionary only for unmatched strings or for short
+ matches. It is used only for the fast compression options. }
+
+{local}
+function deflate_fast(var s : deflate_state; flush : integer) : block_state;
+var
+ hash_head : IPos; { head of the hash chain }
+ bflush : boolean; { set if current block must be flushed }
+begin
+ hash_head := ZNIL;
+ while TRUE do
+ begin
+ { Make sure that we always have enough lookahead, except
+ at the end of the input file. We need MAX_MATCH bytes
+ for the next match, plus MIN_MATCH bytes to insert the
+ string following the next match. }
+
+ if (s.lookahead < MIN_LOOKAHEAD) then
+ begin
+ fill_window(s);
+ if (s.lookahead < MIN_LOOKAHEAD) and (flush = Z_NO_FLUSH) then
+ begin
+ deflate_fast := need_more;
+ exit;
+ end;
+
+ if (s.lookahead = 0) then
+ break; { flush the current block }
+ end;
+
+
+ { Insert the string window[strstart .. strstart+2] in the
+ dictionary, and set hash_head to the head of the hash chain: }
+
+ if (s.lookahead >= MIN_MATCH) then
+ INSERT_STRING(s, s.strstart, hash_head);
+
+ { Find the longest match, discarding those <= prev_length.
+ At this point we have always match_length < MIN_MATCH }
+ if (hash_head <> ZNIL) and
+ (s.strstart - hash_head <= (s.w_size-MIN_LOOKAHEAD){MAX_DIST}) then
+ begin
+ { To simplify the code, we prevent matches with the string
+ of window index 0 (in particular we have to avoid a match
+ of the string with itself at the start of the input file). }
+ if (s.strategy <> Z_HUFFMAN_ONLY) then
+ begin
+ s.match_length := longest_match (s, hash_head);
+ end;
+ { longest_match() sets match_start }
+ end;
+ if (s.match_length >= MIN_MATCH) then
+ begin
+ {$IFDEF ZLIB_DEBUG}
+ check_match(s, s.strstart, s.match_start, s.match_length);
+ {$ENDIF}
+
+ {_tr_tally_dist(s, s.strstart - s.match_start,
+ s.match_length - MIN_MATCH, bflush);}
+ bflush := _tr_tally(s, s.strstart - s.match_start,
+ s.match_length - MIN_MATCH);
+
+ dec(s.lookahead, s.match_length);
+
+ { Insert new strings in the hash table only if the match length
+ is not too large. This saves time but degrades compression. }
+
+{$ifndef FASTEST}
+ if (s.match_length <= s.max_insert_length)
+ and (s.lookahead >= MIN_MATCH) then
+ begin
+ dec(s.match_length); { string at strstart already in hash table }
+ repeat
+ inc(s.strstart);
+ INSERT_STRING(s, s.strstart, hash_head);
+ { strstart never exceeds WSIZE-MAX_MATCH, so there are
+ always MIN_MATCH bytes ahead. }
+ dec(s.match_length);
+ until (s.match_length = 0);
+ inc(s.strstart);
+ end
+ else
+{$endif}
+
+ begin
+ inc(s.strstart, s.match_length);
+ s.match_length := 0;
+ s.ins_h := s.window^[s.strstart];
+ {UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]);}
+ s.ins_h := (( s.ins_h shl s.hash_shift) xor
+ s.window^[s.strstart+1]) and s.hash_mask;
+if MIN_MATCH <> 3 then { the linker removes this }
+begin
+ {Call UPDATE_HASH() MIN_MATCH-3 more times}
+end;
+
+ { If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+ matter since it will be recomputed at next deflate call. }
+
+ end;
+ end
+ else
+ begin
+ { No match, output a literal byte }
+ {$IFDEF ZLIB_DEBUG}
+ Tracevv(char(s.window^[s.strstart]));
+ {$ENDIF}
+ {_tr_tally_lit (s, 0, s.window^[s.strstart], bflush);}
+ bflush := _tr_tally (s, 0, s.window^[s.strstart]);
+
+ dec(s.lookahead);
+ inc(s.strstart);
+ end;
+ if bflush then
+ begin {FLUSH_BLOCK(s, FALSE);}
+ FLUSH_BLOCK_ONLY(s, FALSE);
+ if (s.strm^.avail_out = 0) then
+ begin
+ deflate_fast := need_more;
+ exit;
+ end;
+ end;
+ end;
+ {FLUSH_BLOCK(s, flush = Z_FINISH);}
+ FLUSH_BLOCK_ONLY(s, flush = Z_FINISH);
+ if (s.strm^.avail_out = 0) then
+ begin
+ if flush = Z_FINISH then
+ deflate_fast := finish_started
+ else
+ deflate_fast := need_more;
+ exit;
+ end;
+
+ if flush = Z_FINISH then
+ deflate_fast := finish_done
+ else
+ deflate_fast := block_done;
+end;
+
+{ ===========================================================================
+ Same as above, but achieves better compression. We use a lazy
+ evaluation for matches: a match is finally adopted only if there is
+ no better match at the next window position. }
+
+{local}
+function deflate_slow(var s : deflate_state; flush : integer) : block_state;
+var
+ hash_head : IPos; { head of hash chain }
+ bflush : boolean; { set if current block must be flushed }
+var
+ max_insert : cardinal;
+begin
+ hash_head := ZNIL;
+
+ { Process the input block. }
+ repeat
+ { Make sure that we always have enough lookahead, except
+ at the end of the input file. We need MAX_MATCH bytes
+ for the next match, plus MIN_MATCH bytes to insert the
+ string following the next match. }
+
+ if (s.lookahead < MIN_LOOKAHEAD) then
+ begin
+ fill_window(s);
+ if (s.lookahead < MIN_LOOKAHEAD) and (flush = Z_NO_FLUSH) then
+ begin
+ deflate_slow := need_more;
+ exit;
+ end;
+
+ if s.lookahead=0 then
+ break; { flush the current block }
+ end;
+
+ { Insert the string window[strstart .. strstart+2] in the
+ dictionary, and set hash_head to the head of the hash chain: }
+
+ if (s.lookahead >= MIN_MATCH) then
+ INSERT_STRING(s, s.strstart, hash_head);
+
+ { Find the longest match, discarding those <= prev_length. }
+
+ s.prev_length := s.match_length;
+ s.prev_match := s.match_start;
+ s.match_length := MIN_MATCH-1;
+
+ if (hash_head <> ZNIL) and (s.prev_length < s.max_lazy_match) and
+ (s.strstart - hash_head <= {MAX_DIST}(s.w_size-MIN_LOOKAHEAD)) then
+ begin
+ { To simplify the code, we prevent matches with the string
+ of window index 0 (in particular we have to avoid a match
+ of the string with itself at the start of the input file). }
+
+ if (s.strategy <> Z_HUFFMAN_ONLY) then
+ s.match_length := longest_match (s, hash_head);
+ { longest_match() sets match_start }
+
+ if (s.match_length <= 5) and ((s.strategy = Z_FILTERED) or
+ ((s.match_length = MIN_MATCH) and
+ (s.strstart - s.match_start > TOO_FAR))) then
+ begin
+ { If prev_match is also MIN_MATCH, match_start is garbage
+ but we will ignore the current match anyway. }
+
+ s.match_length := MIN_MATCH-1;
+ end;
+ end;
+ { If there was a match at the previous step and the current
+ match is not better, output the previous match: }
+
+ if (s.prev_length>=MIN_MATCH) and (s.match_length<=s.prev_length) then
+ begin
+ max_insert := s.strstart + s.lookahead - MIN_MATCH;
+ { Do not insert strings in hash table beyond this. }
+ {$ifdef ZLIB_DEBUG}
+ check_match(s, s.strstart-1, s.prev_match, s.prev_length);
+ {$endif}
+
+ {_tr_tally_dist(s, s->strstart -1 - s->prev_match,
+ s->prev_length - MIN_MATCH, bflush);}
+ bflush := _tr_tally(s, s.strstart -1 - s.prev_match,
+ s.prev_length - MIN_MATCH);
+
+ { Insert in hash table all strings up to the end of the match.
+ strstart-1 and strstart are already inserted. If there is not
+ enough lookahead, the last two strings are not inserted in
+ the hash table. }
+
+{$ifdef ZLIB_DEBUG}
+ if s.lookahead<s.prev_length-1 then
+ runerror(255);
+{$endif}
+ dec(s.lookahead, s.prev_length-1);
+ dec(s.prev_length, 2);
+ repeat
+ inc(s.strstart);
+ if s.strstart<=max_insert then
+ INSERT_STRING(s, s.strstart, hash_head);
+ dec(s.prev_length);
+ until s.prev_length = 0;
+ s.match_available := false;
+ s.match_length := MIN_MATCH-1;
+ inc(s.strstart);
+
+ if bflush then {FLUSH_BLOCK(s, FALSE);}
+ begin
+ FLUSH_BLOCK_ONLY(s,false);
+ if s.strm^.avail_out=0 then
+ begin
+ deflate_slow := need_more;
+ exit;
+ end;
+ end;
+ end
+ else
+ if s.match_available then
+ begin
+ { If there was no match at the previous position, output a
+ single literal. If there was a match but the current match
+ is longer, truncate the previous match to a single literal. }
+ {$IFDEF ZLIB_DEBUG}
+ Tracevv(char(s.window^[s.strstart-1]));
+ {$ENDIF}
+ bflush := _tr_tally (s, 0, s.window^[s.strstart-1]);
+
+ if bflush then
+ FLUSH_BLOCK_ONLY(s, FALSE);
+ inc(s.strstart);
+{$ifdef ZLIB_DEBUG}
+ if s.lookahead=0 then
+ runerror(255);
+{$endif}
+ dec(s.lookahead);
+ if (s.strm^.avail_out = 0) then
+ begin
+ deflate_slow := need_more;
+ exit;
+ end;
+ end
+ else
+ begin
+ { There is no previous match to compare with, wait for
+ the next step to decide. }
+
+ s.match_available := TRUE;
+ inc(s.strstart);
+{$ifdef ZLIB_DEBUG}
+ if s.lookahead=0 then
+ runerror(255);
+{$endif}
+ dec(s.lookahead);
+ end;
+ until false;
+
+ {$IFDEF ZLIB_DEBUG}
+ Assert (flush <> Z_NO_FLUSH, 'no flush?');
+ {$ENDIF}
+ if (s.match_available) then
+ begin
+ {$IFDEF ZLIB_DEBUG}
+ Tracevv(char(s.window^[s.strstart-1]));
+ bflush :=
+ {$ENDIF}
+ _tr_tally (s, 0, s.window^[s.strstart-1]);
+ s.match_available := FALSE;
+ end;
+ {FLUSH_BLOCK(s, flush = Z_FINISH);}
+ FLUSH_BLOCK_ONLY(s, flush = Z_FINISH);
+ if (s.strm^.avail_out = 0) then
+ begin
+ if flush = Z_FINISH then
+ deflate_slow := finish_started
+ else
+ deflate_slow := need_more;
+ exit;
+ end;
+ if flush = Z_FINISH then
+ deflate_slow := finish_done
+ else
+ deflate_slow := block_done;
+end;
+
+end.
diff --git a/packages/paszlib/src/zinflate.pas b/packages/paszlib/src/zinflate.pas
new file mode 100644
index 0000000000..d0239a1298
--- /dev/null
+++ b/packages/paszlib/src/zinflate.pas
@@ -0,0 +1,730 @@
+unit zinflate;
+
+{ inflate.c -- zlib interface to inflate modules
+ Copyright (C) 1995-1998 Mark Adler
+
+ Pascal tranlastion
+ Copyright (C) 1998 by Jacques Nomssi Nzali
+ For conditions of distribution and use, see copyright notice in readme.txt
+}
+
+interface
+
+{$I zconf.inc}
+
+uses
+ zbase, infblock, infutil;
+
+function inflateInit(var z : z_stream) : integer;
+
+{ Initializes the internal stream state for decompression.
+
+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_VERSION_ERROR if the zlib library version is incompatible
+ with the version assumed by the caller. msg is set to null if there is no
+ error message. inflateInit does not perform any decompression: this will be
+ done by inflate(). }
+
+
+
+function inflateInit_(z : z_streamp;
+ const version : string;
+ stream_size : integer) : integer;
+
+
+function inflateInit2_(var z: z_stream;
+ w : integer;
+ const version : string;
+ stream_size : integer) : integer;
+
+function inflateInit2(var z: z_stream;
+ windowBits : integer) : integer;
+
+{
+ This is another version of inflateInit with an extra parameter.
+
+ The windowBits parameter is the base two logarithm of the maximum window
+ size (the size of the history buffer). It should be in the range 8..15 for
+ this version of the library. The default value is 15 if inflateInit is used
+ instead. If a compressed stream with a larger window size is given as
+ input, inflate() will return with the error code Z_DATA_ERROR instead of
+ trying to allocate a larger window.
+
+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative
+ memLevel). msg is set to null if there is no error message. inflateInit2
+ does not perform any decompression apart from reading the zlib header if
+ present: this will be done by inflate(). (So next_in and avail_in may be
+ modified, but next_out and avail_out are unchanged.)
+}
+
+
+
+function inflateEnd(var z : z_stream) : integer;
+
+{
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+ was inconsistent. In the error case, msg may be set but then points to a
+ static string (which must not be deallocated).
+}
+
+function inflateReset(var z : z_stream) : integer;
+
+{
+ This function is equivalent to inflateEnd followed by inflateInit,
+ but does not free and reallocate all the internal decompression state.
+ The stream will keep attributes that may have been set by inflateInit2.
+
+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as getmem or state being NULL).
+}
+
+
+function inflate(var z : z_stream;
+ f : integer) : integer;
+{
+ inflate decompresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce
+ some output latency (reading input without producing any output)
+ except when forced to flush.
+
+ The detailed semantics are as follows. inflate performs one or both of the
+ following actions:
+
+ - Decompress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in is updated and processing
+ will resume at this point for the next call of inflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. inflate() provides as much output as possible, until there
+ is no more input data or no more space in the output buffer (see below
+ about the flush parameter).
+
+ Before the call of inflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating the next_* and avail_* values accordingly.
+ The application can consume the uncompressed output when it wants, for
+ example when the output buffer is full (avail_out == 0), or after each
+ call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+ must be called again after making room in the output buffer because there
+ might be more output pending.
+
+ If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much
+ output as possible to the output buffer. The flushing behavior of inflate is
+ not specified for values of the flush parameter other than Z_SYNC_FLUSH
+ and Z_FINISH, but the current implementation actually flushes as much output
+ as possible anyway.
+
+ inflate() should normally be called until it returns Z_STREAM_END or an
+ error. However if all decompression is to be performed in a single step
+ (a single call of inflate), the parameter flush should be set to
+ Z_FINISH. In this case all pending input is processed and all pending
+ output is flushed; avail_out must be large enough to hold all the
+ uncompressed data. (The size of the uncompressed data may have been saved
+ by the compressor for this purpose.) The next operation on this stream must
+ be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+ is never required, but can be used to inform inflate that a faster routine
+ may be used for the single inflate() call.
+
+ If a preset dictionary is needed at this point (see inflateSetDictionary
+ below), inflate sets strm-adler to the adler32 checksum of the
+ dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise
+ it sets strm->adler to the adler32 checksum of all output produced
+ so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or
+ an error code as described below. At the end of the stream, inflate()
+ checks that its computed adler32 checksum is equal to that saved by the
+ compressor and returns Z_STREAM_END only if the checksum is correct.
+
+ inflate() returns Z_OK if some progress has been made (more input processed
+ or more output produced), Z_STREAM_END if the end of the compressed data has
+ been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+ preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+ corrupted (input stream not conforming to the zlib format or incorrect
+ adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent
+ (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if no progress is possible or if there was not
+ enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR
+ case, the application may then call inflateSync to look for a good
+ compression block.
+}
+
+
+function inflateSetDictionary(var z : z_stream;
+ dictionary : Pbyte; {const array of byte}
+ dictLength : cardinal) : integer;
+
+{
+ Initializes the decompression dictionary from the given uncompressed byte
+ sequence. This function must be called immediately after a call of inflate
+ if this call returned Z_NEED_DICT. The dictionary chosen by the compressor
+ can be determined from the Adler32 value returned by this call of
+ inflate. The compressor and decompressor must use exactly the same
+ dictionary (see deflateSetDictionary).
+
+ inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+ expected one (incorrect Adler32 value). inflateSetDictionary does not
+ perform any decompression: this will be done by subsequent calls of
+ inflate().
+}
+
+function inflateSync(var z : z_stream) : integer;
+
+{
+ Skips invalid compressed data until a full flush point (see above the
+ description of deflate with Z_FULL_FLUSH) can be found, or until all
+ available input is skipped. No output is provided.
+
+ inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+ if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+ or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+ case, the application may save the current current value of total_in which
+ indicates where valid compressed data was found. In the error case, the
+ application may repeatedly call inflateSync, providing more input each time,
+ until success or end of the input data.
+}
+
+
+function inflateSyncPoint(var z : z_stream) : integer;
+
+
+implementation
+
+uses
+ adler;
+
+function inflateReset(var z : z_stream) : integer;
+begin
+ if z.state=nil then
+ begin
+ inflateReset := Z_STREAM_ERROR;
+ exit;
+ end;
+ z.total_out := 0;
+ z.total_in := 0;
+ z.msg := '';
+ if z.state^.nowrap then
+ z.state^.mode := BLOCKS
+ else
+ z.state^.mode := METHOD;
+ inflate_blocks_reset(z.state^.blocks^, z, nil);
+ {$IFDEF ZLIB_DEBUG}
+ Tracev('inflate: reset');
+ {$ENDIF}
+ inflateReset := Z_OK;
+end;
+
+
+function inflateEnd(var z : z_stream) : integer;
+begin
+ if z.state=nil then
+ begin
+ inflateEnd := Z_STREAM_ERROR;
+ exit;
+ end;
+ if z.state^.blocks<>nil then
+ inflate_blocks_free(z.state^.blocks, z);
+ dispose(z.state);
+ z.state := nil;
+ {$IFDEF ZLIB_DEBUG}
+ Tracev('inflate: end');
+ {$ENDIF}
+ inflateEnd := Z_OK;
+end;
+
+
+function inflateInit2_(var z: z_stream;
+ w : integer;
+ const version : string;
+ stream_size : integer) : integer;
+begin
+ if (version = '') or (version[1] <> ZLIB_VERSION[1]) or
+ (stream_size <> sizeof(z_stream)) then
+ begin
+ inflateInit2_ := Z_VERSION_ERROR;
+ exit;
+ end;
+ { initialize state }
+ { SetLength(strm.msg, 255); }
+ z.msg := '';
+
+ new(z.state);
+ if z.state=nil then
+ begin
+ inflateInit2_ := Z_MEM_ERROR;
+ exit;
+ end;
+
+ z.state^.blocks := nil;
+
+ { handle undocumented nowrap option (no zlib header or check) }
+ z.state^.nowrap := FALSE;
+ if (w < 0) then
+ begin
+ w := - w;
+ z.state^.nowrap := TRUE;
+ end;
+
+ { set window size }
+ if (w < 8) or (w > 15) then
+ begin
+ inflateEnd(z);
+ inflateInit2_ := Z_STREAM_ERROR;
+ exit;
+ end;
+ z.state^.wbits := cardinal(w);
+
+ { create inflate_blocks state }
+ if z.state^.nowrap then
+ z.state^.blocks := inflate_blocks_new(z, nil, cardinal(1) shl w)
+ else
+ z.state^.blocks := inflate_blocks_new(z, @adler32, cardinal(1) shl w);
+ if z.state^.blocks=nil then
+ begin
+ inflateEnd(z);
+ inflateInit2_ := Z_MEM_ERROR;
+ exit;
+ end;
+ {$IFDEF ZLIB_DEBUG}
+ Tracev('inflate: allocated');
+ {$ENDIF}
+ { reset state }
+ inflateReset(z);
+ inflateInit2_ := Z_OK;
+end;
+
+function inflateInit2(var z: z_stream; windowBits : integer) : integer;
+begin
+ inflateInit2 := inflateInit2_(z, windowBits, ZLIB_VERSION, sizeof(z_stream));
+end;
+
+
+function inflateInit(var z : z_stream) : integer;
+{ inflateInit is a macro to allow checking the zlib version
+ and the compiler's view of z_stream: }
+begin
+ inflateInit := inflateInit2_(z, DEF_WBITS, ZLIB_VERSION, sizeof(z_stream));
+end;
+
+function inflateInit_(z : z_streamp;
+ const version : string;
+ stream_size : integer) : integer;
+begin
+ { initialize state }
+ if z=nil then
+ inflateInit_ := Z_STREAM_ERROR
+ else
+ inflateInit_ := inflateInit2_(z^, DEF_WBITS, version, stream_size);
+end;
+
+function inflate(var z : z_stream;
+ f : integer) : integer;
+var
+ r : integer;
+ b : cardinal;
+begin
+ if (z.state=nil) or (z.next_in=nil) then
+ begin
+ inflate := Z_STREAM_ERROR;
+ exit;
+ end;
+ if f = Z_FINISH then
+ f := Z_BUF_ERROR
+ else
+ f := Z_OK;
+ r := Z_BUF_ERROR;
+ while True do
+ case (z.state^.mode) of
+ BLOCKS:
+ begin
+ r := inflate_blocks(z.state^.blocks^, z, r);
+ if (r = Z_DATA_ERROR) then
+ begin
+ z.state^.mode := BAD;
+ z.state^.sub.marker := 0; { can try inflateSync }
+ continue; { break C-switch }
+ end;
+ if (r = Z_OK) then
+ r := f;
+ if (r <> Z_STREAM_END) then
+ begin
+ inflate := r;
+ exit;
+ end;
+ r := f;
+ inflate_blocks_reset(z.state^.blocks^, z, @z.state^.sub.check.was);
+ if (z.state^.nowrap) then
+ begin
+ z.state^.mode := DONE;
+ continue; { break C-switch }
+ end;
+ z.state^.mode := CHECK4; { falltrough }
+ end;
+ CHECK4:
+ begin
+ {NEEDBYTE}
+ if (z.avail_in = 0) then
+ begin
+ inflate := r;
+ exit;
+ end;
+ r := f;
+
+ {z.state^.sub.check.need := cardinal(NEXTBYTE(z)) shl 24;}
+ dec(z.avail_in);
+ inc(z.total_in);
+ z.state^.sub.check.need := cardinal(z.next_in^) shl 24;
+ inc(z.next_in);
+
+ z.state^.mode := CHECK3; { falltrough }
+ end;
+ CHECK3:
+ begin
+ {NEEDBYTE}
+ if (z.avail_in = 0) then
+ begin
+ inflate := r;
+ exit;
+ end;
+ r := f;
+ {inc( z.state^.sub.check.need, cardinal(NEXTBYTE(z)) shl 16);}
+ dec(z.avail_in);
+ inc(z.total_in);
+ inc(z.state^.sub.check.need, cardinal(z.next_in^) shl 16);
+ inc(z.next_in);
+
+ z.state^.mode := CHECK2; { falltrough }
+ end;
+ CHECK2:
+ begin
+ {NEEDBYTE}
+ if (z.avail_in = 0) then
+ begin
+ inflate := r;
+ exit;
+ end;
+ r := f;
+
+ {inc( z.state^.sub.check.need, cardinal(NEXTBYTE(z)) shl 8);}
+ dec(z.avail_in);
+ inc(z.total_in);
+ inc(z.state^.sub.check.need, cardinal(z.next_in^) shl 8);
+ inc(z.next_in);
+
+ z.state^.mode := CHECK1; { falltrough }
+ end;
+ CHECK1:
+ begin
+ {NEEDBYTE}
+ if (z.avail_in = 0) then
+ begin
+ inflate := r;
+ exit;
+ end;
+ r := f;
+ {inc( z.state^.sub.check.need, cardinal(NEXTBYTE(z)) );}
+ dec(z.avail_in);
+ inc(z.total_in);
+ inc(z.state^.sub.check.need, cardinal(z.next_in^) );
+ inc(z.next_in);
+
+
+ if (z.state^.sub.check.was <> z.state^.sub.check.need) then
+ begin
+ z.state^.mode := BAD;
+ z.msg := 'incorrect data check';
+ z.state^.sub.marker := 5; { can't try inflateSync }
+ continue; { break C-switch }
+ end;
+ {$IFDEF ZLIB_DEBUG}
+ Tracev('inflate: zlib check ok');
+ {$ENDIF}
+ z.state^.mode := DONE; { falltrough }
+ end;
+ DONE:
+ begin
+ inflate := Z_STREAM_END;
+ exit;
+ end;
+ METHOD:
+ begin
+ {NEEDBYTE}
+ if (z.avail_in = 0) then
+ begin
+ inflate := r;
+ exit;
+ end;
+ r := f; {}
+
+ {z.state^.sub.method := NEXTBYTE(z);}
+ dec(z.avail_in);
+ inc(z.total_in);
+ z.state^.sub.method := z.next_in^;
+ inc(z.next_in);
+
+ if ((z.state^.sub.method and $0f) <> Z_DEFLATED) then
+ begin
+ z.state^.mode := BAD;
+ z.msg := 'unknown compression method';
+ z.state^.sub.marker := 5; { can't try inflateSync }
+ continue; { break C-switch }
+ end;
+ if ((z.state^.sub.method shr 4) + 8 > z.state^.wbits) then
+ begin
+ z.state^.mode := BAD;
+ z.msg := 'invalid window size';
+ z.state^.sub.marker := 5; { can't try inflateSync }
+ continue; { break C-switch }
+ end;
+ z.state^.mode := FLAG;
+ { fall trough }
+ end;
+ FLAG:
+ begin
+ {NEEDBYTE}
+ if (z.avail_in = 0) then
+ begin
+ inflate := r;
+ exit;
+ end;
+ r := f; {}
+ {b := NEXTBYTE(z);}
+ dec(z.avail_in);
+ inc(z.total_in);
+ b := z.next_in^;
+ inc(z.next_in);
+
+ if (((z.state^.sub.method shl 8) + b) mod 31) <> 0 then {% mod ?}
+ begin
+ z.state^.mode := BAD;
+ z.msg := 'incorrect header check';
+ z.state^.sub.marker := 5; { can't try inflateSync }
+ continue; { break C-switch }
+ end;
+ {$IFDEF ZLIB_DEBUG}
+ Tracev('inflate: zlib header ok');
+ {$ENDIF}
+ if ((b and PRESET_DICT) = 0) then
+ begin
+ z.state^.mode := BLOCKS;
+ continue; { break C-switch }
+ end;
+ z.state^.mode := DICT4;
+ { falltrough }
+ end;
+ DICT4:
+ begin
+ if (z.avail_in = 0) then
+ begin
+ inflate := r;
+ exit;
+ end;
+ r := f;
+
+ {z.state^.sub.check.need := cardinal(NEXTBYTE(z)) shl 24;}
+ dec(z.avail_in);
+ inc(z.total_in);
+ z.state^.sub.check.need := cardinal(z.next_in^) shl 24;
+ inc(z.next_in);
+
+ z.state^.mode := DICT3; { falltrough }
+ end;
+ DICT3:
+ begin
+ if (z.avail_in = 0) then
+ begin
+ inflate := r;
+ exit;
+ end;
+ r := f;
+ {inc(z.state^.sub.check.need, cardinal(NEXTBYTE(z)) shl 16);}
+ dec(z.avail_in);
+ inc(z.total_in);
+ inc(z.state^.sub.check.need, cardinal(z.next_in^) shl 16);
+ inc(z.next_in);
+
+ z.state^.mode := DICT2; { falltrough }
+ end;
+ DICT2:
+ begin
+ if (z.avail_in = 0) then
+ begin
+ inflate := r;
+ exit;
+ end;
+ r := f;
+
+ {inc(z.state^.sub.check.need, cardinal(NEXTBYTE(z)) shl 8);}
+ dec(z.avail_in);
+ inc(z.total_in);
+ inc(z.state^.sub.check.need, cardinal(z.next_in^) shl 8);
+ inc(z.next_in);
+
+ z.state^.mode := DICT1; { falltrough }
+ end;
+ DICT1:
+ begin
+ if (z.avail_in = 0) then
+ begin
+ inflate := r;
+ exit;
+ end;
+ { r := f; --- wird niemals benutzt }
+ {inc(z.state^.sub.check.need, cardinal(NEXTBYTE(z)) );}
+ dec(z.avail_in);
+ inc(z.total_in);
+ inc(z.state^.sub.check.need, cardinal(z.next_in^) );
+ inc(z.next_in);
+
+ z.adler := z.state^.sub.check.need;
+ z.state^.mode := DICT0;
+ inflate := Z_NEED_DICT;
+ exit;
+ end;
+ DICT0:
+ begin
+ z.state^.mode := BAD;
+ z.msg := 'need dictionary';
+ z.state^.sub.marker := 0; { can try inflateSync }
+ inflate := Z_STREAM_ERROR;
+ exit;
+ end;
+ BAD:
+ begin
+ inflate := Z_DATA_ERROR;
+ exit;
+ end;
+ else
+ begin
+ inflate := Z_STREAM_ERROR;
+ exit;
+ end;
+ end;
+{$ifdef NEED_DUMMY_result}
+ result := Z_STREAM_ERROR; { Some dumb compilers complain without this }
+{$endif}
+end;
+
+function inflateSetDictionary(var z : z_stream;
+ dictionary : Pbyte; {const array of byte}
+ dictLength : cardinal) : integer;
+var
+ length : cardinal;
+begin
+ length := dictLength;
+
+ if (z.state=nil) or (z.state^.mode<>DICT0) then
+ begin
+ inflateSetDictionary := Z_STREAM_ERROR;
+ exit;
+ end;
+ if (adler32(1, dictionary, dictLength) <> z.adler) then
+ begin
+ inflateSetDictionary := Z_DATA_ERROR;
+ exit;
+ end;
+ z.adler := 1;
+
+ if (length >= (1 shl z.state^.wbits)) then
+ begin
+ length := (1 shl z.state^.wbits)-1;
+ inc( dictionary, dictLength - length);
+ end;
+ inflate_set_dictionary(z.state^.blocks^, dictionary^, length);
+ z.state^.mode := BLOCKS;
+ inflateSetDictionary := Z_OK;
+end;
+
+
+function inflateSync(var z : z_stream) : integer;
+const
+ mark : packed array[0..3] of byte = (0, 0, $ff, $ff);
+var
+ n : cardinal; { number of bytes to look at }
+ p : Pbyte; { pointer to bytes }
+ m : cardinal; { number of marker bytes found in a row }
+ r, w : cardinal; { temporaries to save total_in and total_out }
+begin
+ { set up }
+ if z.state=nil then
+ begin
+ inflateSync := Z_STREAM_ERROR;
+ exit;
+ end;
+ if (z.state^.mode <> BAD) then
+ begin
+ z.state^.mode := BAD;
+ z.state^.sub.marker := 0;
+ end;
+ n := z.avail_in;
+ if (n = 0) then
+ begin
+ inflateSync := Z_BUF_ERROR;
+ exit;
+ end;
+ p := z.next_in;
+ m := z.state^.sub.marker;
+
+ { search }
+ while (n <> 0) and (m < 4) do
+ begin
+ if (p^ = mark[m]) then
+ inc(m)
+ else
+ if (p^ <> 0) then
+ m := 0
+ else
+ m := 4 - m;
+ inc(p);
+ dec(n);
+ end;
+
+ { restore }
+ inc(z.total_in, ptruint(p) - ptruint(z.next_in));
+ z.next_in := p;
+ z.avail_in := n;
+ z.state^.sub.marker := m;
+
+
+ { return no joy or set up to restart on a new block }
+ if (m <> 4) then
+ begin
+ inflateSync := Z_DATA_ERROR;
+ exit;
+ end;
+ r := z.total_in;
+ w := z.total_out;
+ inflateReset(z);
+ z.total_in := r;
+ z.total_out := w;
+ z.state^.mode := BLOCKS;
+ inflateSync := Z_OK;
+end;
+
+
+{
+ returns true if inflate is currently at the end of a block generated
+ by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+ implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
+ but removes the length bytes of the resulting empty stored block. When
+ decompressing, PPP checks that at the end of input packet, inflate is
+ waiting for these length bytes.
+}
+
+function inflateSyncPoint(var z : z_stream) : integer;
+begin
+ if (z.state = nil) or (z.state^.blocks = nil) then
+ begin
+ inflateSyncPoint := Z_STREAM_ERROR;
+ exit;
+ end;
+ inflateSyncPoint := inflate_blocks_sync_point(z.state^.blocks^);
+end;
+
+end.
diff --git a/packages/paszlib/src/zip.pas b/packages/paszlib/src/zip.pas
new file mode 100644
index 0000000000..defe160d63
--- /dev/null
+++ b/packages/paszlib/src/zip.pas
@@ -0,0 +1,792 @@
+unit zip;
+
+{ zip.c -- IO on .zip files using zlib
+ zip.h -- IO for compress .zip files using zlib
+ Version 0.15 alpha, Mar 19th, 1998,
+
+ Copyright (C) 1998 Gilles Vollant
+
+ This package allows to create .ZIP file, compatible with PKZip 2.04g
+ WinZip, InfoZip tools and compatible.
+ Encryption and multi volume ZipFile (span) are not supported.
+ Old compressions used by old PKZip 1.x are not supported
+
+ For decompression of .zip files, look at unzip.pas
+
+ Pascal tranlastion
+ Copyright (C) 2000 by Jacques Nomssi Nzali
+ For conditions of distribution and use, see copyright notice in readme.txt }
+
+
+interface
+
+{$ifdef WIN32}
+ {$define Delphi}
+{$endif}
+
+uses
+ //zutil,
+ zbase,
+ //zLib,
+ ziputils;
+
+const
+ ZIP_OK = (0);
+ ZIP_ERRNO = (Z_ERRNO);
+ ZIP_PARAMERROR = (-102);
+ ZIP_INTERNALERROR = (-104);
+ Z_DEFAULT_COMPRESSION = -(1);
+ Z_DEFLATED = 8;
+
+(*
+{ tm_zip contain date/time info }
+type
+ tm_zip = record
+ tm_sec : integer; { seconds after the minute - [0,59] }
+ tm_min : integer; { minutes after the hour - [0,59] }
+ tm_hour : integer; { hours since midnight - [0,23] }
+ tm_mday : integer; { day of the month - [1,31] }
+ tm_mon : integer; { months since January - [0,11] }
+ tm_year : integer; { years - [1980..2044] }
+ end;
+*)
+type
+ zip_fileinfo = record
+ tmz_date: tm_zip; { date in understandable format }
+ dosDate: longword; { if dos_date = 0, tmu_date is used }
+ { flag : longint; }{ general purpose bit flag 2 bytes }
+
+ internal_fa: longint; { internal file attributes 2 bytes }
+ external_fa: longint; { external file attributes 4 bytes }
+ end;
+ zip_fileinfo_ptr = ^zip_fileinfo;
+
+function zipOpen(const pathname: PChar; append: longint): zipFile; {ZEXPORT}
+{ Create a zipfile.
+ pathname contain on Windows NT a filename like "c:\\zlib\\zlib111.zip" or on
+ an Unix computer "zlib/zlib111.zip".
+ if the file pathname exist and append=1, the zip will be created at the end
+ of the file. (useful if the file contain a self extractor code)
+ If the zipfile cannot be opened, the return value is NIL.
+ Else, the return value is a zipFile Handle, usable with other function
+ of this zip package. }
+
+function zipOpenNewFileInZip(afile: zipFile;
+ {const} filename: PChar; const zipfi: zip_fileinfo_ptr; const extrafield_local: pointer; size_extrafield_local: integer; const extrafield_global: pointer; size_extrafield_global: integer; const comment: PChar; method: longint; level: longint): longint; {ZEXPORT}
+{ Open a file in the ZIP for writing.
+ filename : the filename in zip (if NIL, '-' without quote will be used
+ zipfi^ contain supplemental information
+ if extrafield_local<>NIL and size_extrafield_local>0, extrafield_local
+ contains the extrafield data the the local header
+ if extrafield_global<>NIL and size_extrafield_global>0, extrafield_global
+ contains the extrafield data the the local header
+ if comment <> NIL, comment contain the comment string
+ method contain the compression method (0 for store, Z_DEFLATED for deflate)
+ level contain the level of compression (can be Z_DEFAULT_COMPRESSION) }
+
+function zipWriteInFileInZip(afile: zipFile; const buf: pointer; len: cardinal): longint; {ZEXPORT}
+{ Write data in the zipfile }
+
+function zipCloseFileInZip(afile: zipFile): longint; {ZEXPORT}
+ { Close the current file in the zipfile }
+
+function zipClose(afile: zipFile; const global_comment: PChar): longint; {ZEXPORT}
+ { Close the zipfile }
+
+implementation
+
+uses
+ {$ifdef Delphi}
+ SysUtils,
+ {$else}
+ strings,
+ {$endif}
+ zDeflate, crc;
+
+const
+ VERSIONMADEBY = ($0); { platform depedent }
+
+const
+ zip_copyright: PChar = ' zip 0.15 Copyright 1998 Gilles Vollant ';
+
+
+const
+ SIZEDATA_INDATABLOCK = (4096 - (4 * 4));
+
+ LOCALHEADERMAGIC = $04034b50;
+ {CENTRALHEADERMAGIC = $02014b50;}
+ ENDHEADERMAGIC = $06054b50;
+
+ FLAG_LOCALHEADER_OFFSET = $06;
+ CRC_LOCALHEADER_OFFSET = $0e;
+
+ SIZECENTRALHEADER = $2e; { 46 }
+
+type
+ linkedlist_datablock_internal_ptr = ^linkedlist_datablock_internal;
+
+ linkedlist_datablock_internal = record
+ next_datablock: linkedlist_datablock_internal_ptr;
+ avail_in_this_block: longint;
+ filled_in_this_block: longint;
+ unused: longint; { for future use and alignement }
+ Data: array[0..SIZEDATA_INDATABLOCK - 1] of byte;
+ end;
+
+type
+ linkedlist_data = record
+ first_block: linkedlist_datablock_internal_ptr;
+ last_block: linkedlist_datablock_internal_ptr;
+ end;
+ linkedlist_data_ptr = ^linkedlist_data;
+
+type
+ curfile_info = record
+ stream: z_stream; { zLib stream structure for inflate }
+ stream_initialised: boolean; { TRUE is stream is initialised }
+ pos_in_buffered_data: integer; { last written byte in buffered_data }
+
+ pos_local_header: longint; { offset of the local header of the file
+ currenty writing }
+ central_header: PChar; { central header data for the current file }
+ size_centralheader: longint; { size of the central header for cur file }
+ flag: longint; { flag of the file currently writing }
+
+ method: longint; { compression method of file currenty wr.}
+ buffered_data: array[0..Z_BUFSIZE - 1] of byte;{ buffer contain compressed data to be written}
+ dosDate: longint;
+ crc32: longint;
+ end;
+
+type
+ zip_internal = record
+ filezip: FILEptr;
+ central_dir: linkedlist_data; { datablock with central dir in construction}
+ in_opened_file_inzip: boolean; { TRUE if a file in the zip is currently writ.}
+ ci: curfile_info; { info on the file curretly writing }
+
+ begin_pos: longint; { position of the beginning of the zipfile }
+ number_entry: longint;
+ end;
+ zip_internal_ptr = ^zip_internal;
+
+function allocate_new_datablock: linkedlist_datablock_internal_ptr;
+var
+ ldi: linkedlist_datablock_internal_ptr;
+begin
+ ldi := linkedlist_datablock_internal_ptr(GetMem(sizeof(linkedlist_datablock_internal)));
+ if (ldi <> nil) then
+ begin
+ ldi^.next_datablock := nil;
+ ldi^.filled_in_this_block := 0;
+ ldi^.avail_in_this_block := SIZEDATA_INDATABLOCK;
+ end;
+ allocate_new_datablock := ldi;
+end;
+
+procedure free_datablock(ldi: linkedlist_datablock_internal_ptr);
+var
+ ldinext: linkedlist_datablock_internal_ptr;
+begin
+ while (ldi <> nil) do
+ begin
+ ldinext := ldi^.next_datablock;
+ FreeMem(ldi);
+ ldi := ldinext;
+ end;
+end;
+
+procedure init_linkedlist(var ll: linkedlist_data);
+begin
+ ll.last_block := nil;
+ ll.first_block := nil;
+end;
+
+procedure free_linkedlist(var ll: linkedlist_data);
+begin
+ free_datablock(ll.first_block);
+ ll.last_block := nil;
+ ll.first_block := nil;
+end;
+
+function add_data_in_datablock(ll: linkedlist_data_ptr; const buf: pointer; len: longint): longint;
+var
+ ldi: linkedlist_datablock_internal_ptr;
+ from_copy: {const} Pbyte;
+var
+ copy_this: integer;
+ i: integer;
+ to_copy: Pbyte;
+begin
+ if (ll = nil) then
+ begin
+ add_data_in_datablock := ZIP_INTERNALERROR;
+ exit;
+ end;
+
+ if (ll^.last_block = nil) then
+ begin
+ ll^.last_block := allocate_new_datablock;
+ ll^.first_block := ll^.last_block;
+ if (ll^.first_block = nil) then
+ begin
+ add_data_in_datablock := ZIP_INTERNALERROR;
+ exit;
+ end;
+ end;
+
+ ldi := ll^.last_block;
+ from_copy := Pbyte(buf);
+
+ while (len > 0) do
+ begin
+ if (ldi^.avail_in_this_block = 0) then
+ begin
+ ldi^.next_datablock := allocate_new_datablock;
+ if (ldi^.next_datablock = nil) then
+ begin
+ add_data_in_datablock := ZIP_INTERNALERROR;
+ exit;
+ end;
+ ldi := ldi^.next_datablock;
+ ll^.last_block := ldi;
+ end;
+
+ if (ldi^.avail_in_this_block < len) then
+ copy_this := integer(ldi^.avail_in_this_block)
+ else
+ copy_this := integer(len);
+
+ to_copy := @(ldi^.Data[ldi^.filled_in_this_block]);
+
+ for i := 0 to copy_this - 1 do
+ Pbytearray(to_copy)^[i] := Pbytearray(from_copy)^[i];
+
+ Inc(ldi^.filled_in_this_block, copy_this);
+ Dec(ldi^.avail_in_this_block, copy_this);
+ Inc(from_copy, copy_this);
+ Dec(len, copy_this);
+ end;
+ add_data_in_datablock := ZIP_OK;
+end;
+
+
+function write_datablock(fout: FILEptr; ll: linkedlist_data_ptr): longint;
+var
+ ldi: linkedlist_datablock_internal_ptr;
+begin
+ ldi := ll^.first_block;
+ while (ldi <> nil) do
+ begin
+ if (ldi^.filled_in_this_block > 0) then
+ if (fwrite(@ldi^.Data, integer(ldi^.filled_in_this_block), 1, fout) <> 1) then
+ begin
+ write_datablock := ZIP_ERRNO;
+ exit;
+ end;
+ ldi := ldi^.next_datablock;
+ end;
+ write_datablock := ZIP_OK;
+end;
+
+{**************************************************************************}
+
+{ ===========================================================================
+ Outputs a long in LSB order to the given file
+ nbByte = 1, 2 or 4 (byte, short or long) }
+
+function ziplocal_putValue(afile: FILEptr; x: longint; nbByte: longint): longint;
+var
+ buf: array[0..4 - 1] of byte;
+ n: longint;
+begin
+ for n := 0 to nbByte - 1 do
+ begin
+ buf[n] := byte(x and $ff);
+ x := x shr 8;
+ end;
+ if (fwrite(@buf, nbByte, 1, afile) <> 1) then
+ ziplocal_putValue := ZIP_ERRNO
+ else
+ ziplocal_putValue := ZIP_OK;
+end;
+
+procedure ziplocal_putValue_inmemory(dest: pointer; x: longint; nbByte: longint);
+var
+ buf: Pbytearray;
+ n: longint;
+begin
+ buf := Pbytearray(dest);
+ for n := 0 to nbByte - 1 do
+ begin
+ buf^[n] := Byte(x and $ff);
+ x := x shr 8;
+ end;
+end;
+
+{**************************************************************************}
+
+
+function ziplocal_TmzDateToDosDate(var ptm: tm_zip; dosDate: longint): longint;
+var
+ year: longint;
+begin
+ year := longint(ptm.tm_year);
+ if (year > 1980) then
+ Dec(year, 1980)
+ else
+ if (year > 80) then
+ Dec(year, 80);
+ ziplocal_TmzDateToDosDate := longint(
+ ((ptm.tm_mday) + (32 * (ptm.tm_mon + 1)) + (512 * year)) shl 16) or
+ ((ptm.tm_sec div 2) + (32 * ptm.tm_min) + (2048 * longint(ptm.tm_hour)));
+end;
+
+
+{**************************************************************************}
+
+function zipOpen(const pathname: PChar; append: longint): zipFile; {ZEXPORT}
+var
+ ziinit: zip_internal;
+ zi: zip_internal_ptr;
+begin
+ if (append = 0) then
+ ziinit.filezip := fopen(pathname, fopenwrite)
+ else
+ ziinit.filezip := fopen(pathname, fappendwrite);
+
+ if (ziinit.filezip = nil) then
+ begin
+ zipOpen := nil;
+ exit;
+ end;
+ ziinit.begin_pos := ftell(ziinit.filezip);
+ ziinit.in_opened_file_inzip := False;
+ ziinit.ci.stream_initialised := False;
+ ziinit.number_entry := 0;
+ init_linkedlist(ziinit.central_dir);
+
+ zi := zip_internal_ptr(AllocMem(sizeof(zip_internal)));
+ if (zi = nil) then
+ begin
+ fclose(ziinit.filezip);
+ zipOpen := nil;
+ exit;
+ end;
+
+ zi^ := ziinit;
+ zipOpen := zipFile(zi);
+end;
+
+function zipOpenNewFileInZip(afile: zipFile;
+ {const} filename: PChar; const zipfi: zip_fileinfo_ptr; const extrafield_local: pointer; size_extrafield_local: integer; const extrafield_global: pointer; size_extrafield_global: integer; const comment: PChar; method: longint; level: longint): longint; {ZEXPORT}
+var
+ zi: zip_internal_ptr;
+ size_filename: integer;
+ size_comment: integer;
+ i: integer;
+ err: longint;
+begin
+ err := ZIP_OK;
+ if (afile = nil) then
+ begin
+ zipOpenNewFileInZip := ZIP_PARAMERROR;
+ exit;
+ end;
+ if ((method <> 0) and (method <> Z_DEFLATED)) then
+ begin
+ zipOpenNewFileInZip := ZIP_PARAMERROR;
+ exit;
+ end;
+
+ zi := zip_internal_ptr(afile);
+
+ if (zi^.in_opened_file_inzip = True) then
+ begin
+ err := zipCloseFileInZip(afile);
+ if (err <> ZIP_OK) then
+ begin
+ zipOpenNewFileInZip := err;
+ exit;
+ end;
+ end;
+
+ if (filename = nil) then
+ filename := '-';
+
+ if (comment = nil) then
+ size_comment := 0
+ else
+ size_comment := strlen(comment);
+
+ size_filename := strlen(filename);
+
+ if (zipfi = nil) then
+ zi^.ci.dosDate := 0
+ else
+ if (zipfi^.dosDate <> 0) then
+ zi^.ci.dosDate := zipfi^.dosDate
+ else
+ zi^.ci.dosDate := ziplocal_TmzDateToDosDate(zipfi^.tmz_date, zipfi^.dosDate);
+ zi^.ci.flag := 0;
+ if ((level = 8) or (level = 9)) then
+ zi^.ci.flag := zi^.ci.flag or 2;
+ if ((level = 2)) then
+ zi^.ci.flag := zi^.ci.flag or 4;
+ if ((level = 1)) then
+ zi^.ci.flag := zi^.ci.flag or 6;
+
+ zi^.ci.crc32 := 0;
+ zi^.ci.method := method;
+ zi^.ci.stream_initialised := False;
+ zi^.ci.pos_in_buffered_data := 0;
+ zi^.ci.pos_local_header := ftell(zi^.filezip);
+ zi^.ci.size_centralheader := SIZECENTRALHEADER + size_filename +
+ size_extrafield_global + size_comment;
+ zi^.ci.central_header := PChar(AllocMem(integer(zi^.ci.size_centralheader)));
+
+ ziplocal_putValue_inmemory(zi^.ci.central_header, longint(CENTRALHEADERMAGIC), 4);
+ { version info }
+ ziplocal_putValue_inmemory(zi^.ci.central_header + 4, longint(VERSIONMADEBY), 2);
+ ziplocal_putValue_inmemory(zi^.ci.central_header + 6, longint(20), 2);
+ ziplocal_putValue_inmemory(zi^.ci.central_header + 8, longint(zi^.ci.flag), 2);
+ ziplocal_putValue_inmemory(zi^.ci.central_header + 10, longint(zi^.ci.method), 2);
+ ziplocal_putValue_inmemory(zi^.ci.central_header + 12, longint(zi^.ci.dosDate), 4);
+ ziplocal_putValue_inmemory(zi^.ci.central_header + 16, longint(0), 4); {crc}
+ ziplocal_putValue_inmemory(zi^.ci.central_header + 20, longint(0), 4); {compr size}
+ ziplocal_putValue_inmemory(zi^.ci.central_header + 24, longint(0), 4); {uncompr size}
+ ziplocal_putValue_inmemory(zi^.ci.central_header + 28, longint(size_filename), 2);
+ ziplocal_putValue_inmemory(zi^.ci.central_header + 30, longint(size_extrafield_global), 2);
+ ziplocal_putValue_inmemory(zi^.ci.central_header + 32, longint(size_comment), 2);
+ ziplocal_putValue_inmemory(zi^.ci.central_header + 34, longint(0), 2); {disk nm start}
+
+ if (zipfi = nil) then
+ ziplocal_putValue_inmemory(zi^.ci.central_header + 36, longint(0), 2)
+ else
+ ziplocal_putValue_inmemory(zi^.ci.central_header + 36, longint(zipfi^.internal_fa), 2);
+
+ if (zipfi = nil) then
+ ziplocal_putValue_inmemory(zi^.ci.central_header + 38, longint(0), 4)
+ else
+ ziplocal_putValue_inmemory(zi^.ci.central_header + 38, longint(zipfi^.external_fa), 4);
+
+ ziplocal_putValue_inmemory(zi^.ci.central_header + 42, longint(zi^.ci.pos_local_header), 4);
+
+ i := 0;
+ while (i < size_filename) do
+ begin
+ (zi^.ci.central_header +SIZECENTRALHEADER + i)^ := (filename + i)^;
+ Inc(i);
+ end;
+
+ i := 0;
+ while (i < size_extrafield_global) do
+ begin
+ (zi^.ci.central_header +SIZECENTRALHEADER + size_filename + i)^ :=
+ ({const} PChar(extrafield_global) + i)^;
+ Inc(i);
+ end;
+
+ i := 0;
+ while (i < size_comment) do
+ begin
+ (zi^.ci.central_header +SIZECENTRALHEADER + size_filename + size_extrafield_global + i)^ := (filename + i)^;
+ Inc(i);
+ end;
+ if (zi^.ci.central_header = nil) then
+ begin
+ zipOpenNewFileInZip := ZIP_INTERNALERROR;
+ exit;
+ end;
+
+ { write the local header }
+ err := ziplocal_putValue(zi^.filezip, longint(LOCALHEADERMAGIC), 4);
+
+ if (err = ZIP_OK) then
+ err := ziplocal_putValue(zi^.filezip, longint(20), 2); { version needed to extract }
+ if (err = ZIP_OK) then
+ err := ziplocal_putValue(zi^.filezip, longint(zi^.ci.flag), 2);
+
+ if (err = ZIP_OK) then
+ err := ziplocal_putValue(zi^.filezip, longint(zi^.ci.method), 2);
+
+ if (err = ZIP_OK) then
+ err := ziplocal_putValue(zi^.filezip, longint(zi^.ci.dosDate), 4);
+
+ if (err = ZIP_OK) then
+ err := ziplocal_putValue(zi^.filezip, longint(0), 4); { crc 32, unknown }
+ if (err = ZIP_OK) then
+ err := ziplocal_putValue(zi^.filezip, longint(0), 4); { compressed size, unknown }
+ if (err = ZIP_OK) then
+ err := ziplocal_putValue(zi^.filezip, longint(0), 4); { uncompressed size, unknown }
+
+ if (err = ZIP_OK) then
+ err := ziplocal_putValue(zi^.filezip, longint(size_filename), 2);
+
+ if (err = ZIP_OK) then
+ err := ziplocal_putValue(zi^.filezip, longint(size_extrafield_local), 2);
+
+ if ((err = ZIP_OK) and (size_filename > 0)) then
+ if (fwrite(filename, integer(size_filename), 1, zi^.filezip) <> 1) then
+ err := ZIP_ERRNO;
+
+ if ((err = ZIP_OK) and (size_extrafield_local > 0)) then
+ if (fwrite(extrafield_local, integer(size_extrafield_local), 1, zi^.filezip) <> 1) then
+ err := ZIP_ERRNO;
+
+ zi^.ci.stream.avail_in := integer(0);
+ zi^.ci.stream.avail_out := integer(Z_BUFSIZE);
+ zi^.ci.stream.next_out := Pbyte(@zi^.ci.buffered_data);
+ zi^.ci.stream.total_in := 0;
+ zi^.ci.stream.total_out := 0;
+
+ if ((err = ZIP_OK) and (zi^.ci.method = Z_DEFLATED)) then
+ begin
+ err := deflateInit2(zi^.ci.stream, level,
+ Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, 0);
+
+ if (err = Z_OK) then
+ zi^.ci.stream_initialised := True;
+ end;
+
+ if (err = Z_OK) then
+ zi^.in_opened_file_inzip := True;
+ zipOpenNewFileInZip := err;
+end;
+
+function zipWriteInFileInZip(afile: zipFile; const buf: pointer; len: cardinal): longint; {ZEXPORT}
+var
+ zi: zip_internal_ptr;
+ err: longint;
+var
+ uTotalOutBefore: longint;
+var
+ copy_this, i: integer;
+begin
+ err := ZIP_OK;
+
+ if (afile = nil) then
+ begin
+ zipWriteInFileInZip := ZIP_PARAMERROR;
+ exit;
+ end;
+ zi := zip_internal_ptr(afile);
+
+ if (zi^.in_opened_file_inzip = False) then
+ begin
+ zipWriteInFileInZip := ZIP_PARAMERROR;
+ exit;
+ end;
+
+ zi^.ci.stream.next_in := buf;
+ zi^.ci.stream.avail_in := len;
+ zi^.ci.crc32 := crc32(zi^.ci.crc32, buf, len);
+
+ while ((err = ZIP_OK) and (zi^.ci.stream.avail_in > 0)) do
+ begin
+ if (zi^.ci.stream.avail_out = 0) then
+ begin
+ if fwrite(@zi^.ci.buffered_data, integer(zi^.ci.pos_in_buffered_data), 1, zi^.filezip) <> 1 then
+ err := ZIP_ERRNO;
+ zi^.ci.pos_in_buffered_data := 0;
+ zi^.ci.stream.avail_out := integer(Z_BUFSIZE);
+ zi^.ci.stream.next_out := Pbyte(@zi^.ci.buffered_data);
+ end;
+
+ if (zi^.ci.method = Z_DEFLATED) then
+ begin
+ uTotalOutBefore := zi^.ci.stream.total_out;
+ err := deflate(zi^.ci.stream, Z_NO_FLUSH);
+ Inc(zi^.ci.pos_in_buffered_data, integer(zi^.ci.stream.total_out - uTotalOutBefore));
+ end
+ else
+ begin
+ if (zi^.ci.stream.avail_in < zi^.ci.stream.avail_out) then
+ copy_this := zi^.ci.stream.avail_in
+ else
+ copy_this := zi^.ci.stream.avail_out;
+
+ for i := 0 to copy_this - 1 do
+ (PChar(zi^.ci.stream.next_out) +i)^ :=
+ ( {const} PChar(zi^.ci.stream.next_in) + i)^;
+
+
+ Dec(zi^.ci.stream.avail_in, copy_this);
+ Dec(zi^.ci.stream.avail_out, copy_this);
+ Inc(zi^.ci.stream.next_in, copy_this);
+ Inc(zi^.ci.stream.next_out, copy_this);
+ Inc(zi^.ci.stream.total_in, copy_this);
+ Inc(zi^.ci.stream.total_out, copy_this);
+ Inc(zi^.ci.pos_in_buffered_data, copy_this);
+ end;
+ end;
+
+ zipWriteInFileInZip := 0;
+end;
+
+function zipCloseFileInZip(afile: zipFile): longint; {ZEXPORT}
+var
+ zi: zip_internal_ptr;
+ err: longint;
+var
+ uTotalOutBefore: longint;
+var
+ cur_pos_inzip: longint;
+begin
+ err := ZIP_OK;
+
+ if (afile = nil) then
+ begin
+ zipCloseFileInZip := ZIP_PARAMERROR;
+ exit;
+ end;
+ zi := zip_internal_ptr(afile);
+
+ if (zi^.in_opened_file_inzip = False) then
+ begin
+ zipCloseFileInZip := ZIP_PARAMERROR;
+ exit;
+ end;
+ zi^.ci.stream.avail_in := 0;
+
+ if (zi^.ci.method = Z_DEFLATED) then
+ while (err = ZIP_OK) do
+ begin
+ if (zi^.ci.stream.avail_out = 0) then
+ begin
+ if fwrite(@zi^.ci.buffered_data, integer(zi^.ci.pos_in_buffered_data), 1, zi^.filezip) <> 1 then
+ err := ZIP_ERRNO;
+ zi^.ci.pos_in_buffered_data := 0;
+ zi^.ci.stream.avail_out := integer(Z_BUFSIZE);
+ zi^.ci.stream.next_out := Pbyte(@zi^.ci.buffered_data);
+ end;
+ uTotalOutBefore := zi^.ci.stream.total_out;
+ err := deflate(zi^.ci.stream, Z_FINISH);
+ Inc(zi^.ci.pos_in_buffered_data, integer(zi^.ci.stream.total_out - uTotalOutBefore));
+ end;
+
+ if (err = Z_STREAM_END) then
+ err := ZIP_OK; { this is normal }
+
+ if (zi^.ci.pos_in_buffered_data > 0) and (err = ZIP_OK) then
+ if fwrite(@zi^.ci.buffered_data, integer(zi^.ci.pos_in_buffered_data), 1, zi^.filezip) <> 1 then
+ err := ZIP_ERRNO;
+
+ if ((zi^.ci.method = Z_DEFLATED) and (err = ZIP_OK)) then
+ begin
+ err := deflateEnd(zi^.ci.stream);
+ zi^.ci.stream_initialised := False;
+ end;
+
+ ziplocal_putValue_inmemory(zi^.ci.central_header + 16, longint(zi^.ci.crc32), 4); {crc}
+ ziplocal_putValue_inmemory(zi^.ci.central_header + 20, longint(zi^.ci.stream.total_out), 4); {compr size}
+ ziplocal_putValue_inmemory(zi^.ci.central_header + 24, longint(zi^.ci.stream.total_in), 4); {uncompr size}
+
+ if (err = ZIP_OK) then
+ err := add_data_in_datablock(@zi^.central_dir, zi^.ci.central_header, longint(zi^.ci.size_centralheader));
+
+ FreeMem(zi^.ci.central_header);
+
+ if (err = ZIP_OK) then
+ begin
+ cur_pos_inzip := ftell(zi^.filezip);
+ if fseek(zi^.filezip, zi^.ci.pos_local_header + 14, SEEK_SET) <> 0 then
+ err := ZIP_ERRNO;
+
+ if (err = ZIP_OK) then
+ err := ziplocal_putValue(zi^.filezip, longint(zi^.ci.crc32), 4); { crc 32, unknown }
+
+ if (err = ZIP_OK) then { compressed size, unknown }
+ err := ziplocal_putValue(zi^.filezip, longint(zi^.ci.stream.total_out), 4);
+
+ if (err = ZIP_OK) then { uncompressed size, unknown }
+ err := ziplocal_putValue(zi^.filezip, longint(zi^.ci.stream.total_in), 4);
+
+ if fseek(zi^.filezip, cur_pos_inzip, SEEK_SET) <> 0 then
+ err := ZIP_ERRNO;
+ end;
+
+ Inc(zi^.number_entry);
+ zi^.in_opened_file_inzip := False;
+
+ zipCloseFileInZip := err;
+end;
+
+function zipClose(afile: zipFile; const global_comment: PChar): longint; {ZEXPORT}
+var
+ zi: zip_internal_ptr;
+ err: longint;
+ size_centraldir: longint;
+ centraldir_pos_inzip: longint;
+ size_global_comment: integer;
+var
+ ldi: linkedlist_datablock_internal_ptr;
+begin
+ err := 0;
+ size_centraldir := 0;
+ if (afile = nil) then
+ begin
+ zipClose := ZIP_PARAMERROR;
+ exit;
+ end;
+ zi := zip_internal_ptr(afile);
+
+ if (zi^.in_opened_file_inzip = True) then
+ err := zipCloseFileInZip(afile);
+
+ if (global_comment = nil) then
+ size_global_comment := 0
+ else
+ size_global_comment := strlen(global_comment);
+
+ centraldir_pos_inzip := ftell(zi^.filezip);
+ if (err = ZIP_OK) then
+ begin
+ ldi := zi^.central_dir.first_block;
+ while (ldi <> nil) do
+ begin
+ if ((err = ZIP_OK) and (ldi^.filled_in_this_block > 0)) then
+ if fwrite(@ldi^.Data, integer(ldi^.filled_in_this_block), 1, zi^.filezip) <> 1 then
+ err := ZIP_ERRNO;
+
+ Inc(size_centraldir, ldi^.filled_in_this_block);
+ ldi := ldi^.next_datablock;
+ end;
+ end;
+ free_datablock(zi^.central_dir.first_block);
+
+ if (err = ZIP_OK) then { Magic End }
+ err := ziplocal_putValue(zi^.filezip, longint(ENDHEADERMAGIC), 4);
+
+ if (err = ZIP_OK) then { number of this disk }
+ err := ziplocal_putValue(zi^.filezip, longint(0), 2);
+
+ if (err = ZIP_OK) then { number of the disk with the start of the central directory }
+ err := ziplocal_putValue(zi^.filezip, longint(0), 2);
+
+ if (err = ZIP_OK) then { total number of entries in the central dir on this disk }
+ err := ziplocal_putValue(zi^.filezip, longint(zi^.number_entry), 2);
+
+ if (err = ZIP_OK) then { total number of entries in the central dir }
+ err := ziplocal_putValue(zi^.filezip, longint(zi^.number_entry), 2);
+
+ if (err = ZIP_OK) then { size of the central directory }
+ err := ziplocal_putValue(zi^.filezip, longint(size_centraldir), 4);
+
+ if (err = ZIP_OK) then { offset of start of central directory with respect to the
+ starting disk number }
+ err := ziplocal_putValue(zi^.filezip, longint(centraldir_pos_inzip), 4);
+
+ if (err = ZIP_OK) then { zipfile comment length }
+ err := ziplocal_putValue(zi^.filezip, longint(size_global_comment), 2);
+
+ if ((err = ZIP_OK) and (size_global_comment > 0)) then
+ if fwrite(global_comment, integer(size_global_comment), 1, zi^.filezip) <> 1 then
+ err := ZIP_ERRNO;
+ fclose(zi^.filezip);
+ FreeMem(zi);
+
+ zipClose := err;
+end;
+
+end.
diff --git a/packages/paszlib/src/zipper.pp b/packages/paszlib/src/zipper.pp
new file mode 100644
index 0000000000..5048bf8824
--- /dev/null
+++ b/packages/paszlib/src/zipper.pp
@@ -0,0 +1,1470 @@
+{
+ $Id: header,v 1.1 2000/07/13 06:33:45 michael Exp $
+ This file is part of the Free Component Library (FCL)
+ Copyright (c) 1999-2000 by the Free Pascal development team
+
+ See the file COPYING.FPC, included in this distribution,
+ for details about the copyright.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+{$mode objfpc}
+{$h+}
+unit zipper;
+
+Interface
+
+Uses
+ SysUtils,Classes,ZStream;
+
+
+Const
+ { Signatures }
+{$ifdef FPC_BIG_ENDIAN}
+ END_OF_CENTRAL_DIR_SIGNATURE = $504B0506;
+ LOCAL_FILE_HEADER_SIGNATURE = $504B0304;
+ CENTRAL_FILE_HEADER_SIGNATURE = $504B0102;
+{$else FPC_BIG_ENDIAN}
+ END_OF_CENTRAL_DIR_SIGNATURE = $06054B50;
+ LOCAL_FILE_HEADER_SIGNATURE = $04034B50;
+ CENTRAL_FILE_HEADER_SIGNATURE = $02014B50;
+{$endif FPC_BIG_ENDIAN}
+
+Type
+ Local_File_Header_Type = Packed Record
+ Signature : LongInt;
+ Extract_Version_Reqd : Word;
+ Bit_Flag : Word;
+ Compress_Method : Word;
+ Last_Mod_Time : Word;
+ Last_Mod_Date : Word;
+ Crc32 : LongWord;
+ Compressed_Size : LongInt;
+ Uncompressed_Size : LongInt;
+ Filename_Length : Word;
+ Extra_Field_Length : Word;
+ end;
+
+ { Define the Central Directory record types }
+
+ Central_File_Header_Type = Packed Record
+ Signature : LongInt;
+ MadeBy_Version : Word;
+ Extract_Version_Reqd : Word;
+ Bit_Flag : Word;
+ Compress_Method : Word;
+ Last_Mod_Time : Word;
+ Last_Mod_Date : Word;
+ Crc32 : LongWord;
+ Compressed_Size : LongInt;
+ Uncompressed_Size : LongInt;
+ Filename_Length : Word;
+ Extra_Field_Length : Word;
+ File_Comment_Length : Word;
+ Starting_Disk_Num : Word;
+ Internal_Attributes : Word;
+ External_Attributes : LongInt;
+ Local_Header_Offset : LongInt;
+ End;
+
+ End_of_Central_Dir_Type = Packed Record
+ Signature : LongInt;
+ Disk_Number : Word;
+ Central_Dir_Start_Disk : Word;
+ Entries_This_Disk : Word;
+ Total_Entries : Word;
+ Central_Dir_Size : LongInt;
+ Start_Disk_Offset : LongInt;
+ ZipFile_Comment_Length : Word;
+ end;
+
+Const
+ Crc_32_Tab : Array[0..255] of LongWord = (
+ $00000000, $77073096, $ee0e612c, $990951ba, $076dc419, $706af48f, $e963a535, $9e6495a3,
+ $0edb8832, $79dcb8a4, $e0d5e91e, $97d2d988, $09b64c2b, $7eb17cbd, $e7b82d07, $90bf1d91,
+ $1db71064, $6ab020f2, $f3b97148, $84be41de, $1adad47d, $6ddde4eb, $f4d4b551, $83d385c7,
+ $136c9856, $646ba8c0, $fd62f97a, $8a65c9ec, $14015c4f, $63066cd9, $fa0f3d63, $8d080df5,
+ $3b6e20c8, $4c69105e, $d56041e4, $a2677172, $3c03e4d1, $4b04d447, $d20d85fd, $a50ab56b,
+ $35b5a8fa, $42b2986c, $dbbbc9d6, $acbcf940, $32d86ce3, $45df5c75, $dcd60dcf, $abd13d59,
+ $26d930ac, $51de003a, $c8d75180, $bfd06116, $21b4f4b5, $56b3c423, $cfba9599, $b8bda50f,
+ $2802b89e, $5f058808, $c60cd9b2, $b10be924, $2f6f7c87, $58684c11, $c1611dab, $b6662d3d,
+ $76dc4190, $01db7106, $98d220bc, $efd5102a, $71b18589, $06b6b51f, $9fbfe4a5, $e8b8d433,
+ $7807c9a2, $0f00f934, $9609a88e, $e10e9818, $7f6a0dbb, $086d3d2d, $91646c97, $e6635c01,
+ $6b6b51f4, $1c6c6162, $856530d8, $f262004e, $6c0695ed, $1b01a57b, $8208f4c1, $f50fc457,
+ $65b0d9c6, $12b7e950, $8bbeb8ea, $fcb9887c, $62dd1ddf, $15da2d49, $8cd37cf3, $fbd44c65,
+ $4db26158, $3ab551ce, $a3bc0074, $d4bb30e2, $4adfa541, $3dd895d7, $a4d1c46d, $d3d6f4fb,
+ $4369e96a, $346ed9fc, $ad678846, $da60b8d0, $44042d73, $33031de5, $aa0a4c5f, $dd0d7cc9,
+ $5005713c, $270241aa, $be0b1010, $c90c2086, $5768b525, $206f85b3, $b966d409, $ce61e49f,
+ $5edef90e, $29d9c998, $b0d09822, $c7d7a8b4, $59b33d17, $2eb40d81, $b7bd5c3b, $c0ba6cad,
+ $edb88320, $9abfb3b6, $03b6e20c, $74b1d29a, $ead54739, $9dd277af, $04db2615, $73dc1683,
+ $e3630b12, $94643b84, $0d6d6a3e, $7a6a5aa8, $e40ecf0b, $9309ff9d, $0a00ae27, $7d079eb1,
+ $f00f9344, $8708a3d2, $1e01f268, $6906c2fe, $f762575d, $806567cb, $196c3671, $6e6b06e7,
+ $fed41b76, $89d32be0, $10da7a5a, $67dd4acc, $f9b9df6f, $8ebeeff9, $17b7be43, $60b08ed5,
+ $d6d6a3e8, $a1d1937e, $38d8c2c4, $4fdff252, $d1bb67f1, $a6bc5767, $3fb506dd, $48b2364b,
+ $d80d2bda, $af0a1b4c, $36034af6, $41047a60, $df60efc3, $a867df55, $316e8eef, $4669be79,
+ $cb61b38c, $bc66831a, $256fd2a0, $5268e236, $cc0c7795, $bb0b4703, $220216b9, $5505262f,
+ $c5ba3bbe, $b2bd0b28, $2bb45a92, $5cb36a04, $c2d7ffa7, $b5d0cf31, $2cd99e8b, $5bdeae1d,
+ $9b64c2b0, $ec63f226, $756aa39c, $026d930a, $9c0906a9, $eb0e363f, $72076785, $05005713,
+ $95bf4a82, $e2b87a14, $7bb12bae, $0cb61b38, $92d28e9b, $e5d5be0d, $7cdcefb7, $0bdbdf21,
+ $86d3d2d4, $f1d4e242, $68ddb3f8, $1fda836e, $81be16cd, $f6b9265b, $6fb077e1, $18b74777,
+ $88085ae6, $ff0f6a70, $66063bca, $11010b5c, $8f659eff, $f862ae69, $616bffd3, $166ccf45,
+ $a00ae278, $d70dd2ee, $4e048354, $3903b3c2, $a7672661, $d06016f7, $4969474d, $3e6e77db,
+ $aed16a4a, $d9d65adc, $40df0b66, $37d83bf0, $a9bcae53, $debb9ec5, $47b2cf7f, $30b5ffe9,
+ $bdbdf21c, $cabac28a, $53b39330, $24b4a3a6, $bad03605, $cdd70693, $54de5729, $23d967bf,
+ $b3667a2e, $c4614ab8, $5d681b02, $2a6f2b94, $b40bbe37, $c30c8ea1, $5a05df1b, $2d02ef8d
+ );
+
+Type
+
+ TZipItem = Class(TObject)
+ Path : String;
+ Name : String;
+ Size : LongInt;
+ DateTime : TDateTime;
+ HdrPos : Longint;
+ end;
+
+ TProgressEvent = Procedure(Sender : TObject; Const Pct : Double) of object;
+ TOnEndOfFileEvent = Procedure(Sender : TObject; Const Ratio : Double) of object;
+ TOnStartFileEvent = Procedure(Sender : TObject; Const AFileName : String) of object;
+
+Type
+
+ { TCompressor }
+ TCompressor = Class(TObject)
+ Protected
+ FInFile : TStream; { I/O file variables }
+ FOutFile : TStream;
+ FCrc32Val : LongWord; { CRC calculation variable }
+ FBufferSize : LongWord;
+ FOnPercent : Integer;
+ FOnProgress : TProgressEvent;
+ Procedure UpdC32(Octet: Byte);
+ Public
+ Constructor Create(AInFile, AOutFile : TStream; ABufSize : LongWord); virtual;
+ Procedure Compress; Virtual; Abstract;
+ Class Function ZipID : Word; virtual; Abstract;
+ Property BufferSize : LongWord read FBufferSize;
+ Property OnPercent : Integer Read FOnPercent Write FOnPercent;
+ Property OnProgress : TProgressEvent Read FOnProgress Write FOnProgress;
+ Property Crc32Val : LongWord Read FCrc32Val Write FCrc32Val;
+ end;
+
+ { TDeCompressor }
+ TDeCompressor = Class(TObject)
+ Protected
+ FInFile : TStream; { I/O file variables }
+ FOutFile : TStream;
+ FCrc32Val : LongWord; { CRC calculation variable }
+ FBufferSize : LongWord;
+ FOnPercent : Integer;
+ FOnProgress : TProgressEvent;
+ Procedure UpdC32(Octet: Byte);
+ Public
+ Constructor Create(AInFile, AOutFile : TStream; ABufSize : LongWord); virtual;
+ Procedure DeCompress; Virtual; Abstract;
+ Class Function ZipID : Word; virtual; Abstract;
+ Property BufferSize : LongWord read FBufferSize;
+ Property OnPercent : Integer Read FOnPercent Write FOnPercent;
+ Property OnProgress : TProgressEvent Read FOnProgress Write FOnProgress;
+ Property Crc32Val : LongWord Read FCrc32Val Write FCrc32Val;
+ end;
+
+ { TShrinker }
+
+Const
+ TABLESIZE = 8191;
+ FIRSTENTRY = 257;
+
+Type
+ CodeRec = Packed Record
+ Child : Smallint;
+ Sibling : Smallint;
+ Suffix : Byte;
+ end;
+ CodeArray = Array[0..TABLESIZE] of CodeRec;
+ TablePtr = ^CodeArray;
+
+ FreeListPtr = ^FreeListArray;
+ FreeListArray = Array[FIRSTENTRY..TABLESIZE] of Word;
+
+ BufPtr = PByte;
+
+ TShrinker = Class(TCompressor)
+ Private
+ FBufSize : LongWord;
+ MaxInBufIdx : LongWord; { Count of valid chars in input buffer }
+ InputEof : Boolean; { End of file indicator }
+ CodeTable : TablePtr; { Points to code table for LZW compression }
+ FreeList : FreeListPtr; { Table of free code table entries }
+ NextFree : Word; { Index into free list table }
+
+ ClearList : Array[0..1023] of Byte; { Bit mapped structure used in }
+ { during adaptive resets }
+ CodeSize : Byte; { Size of codes (in bits) currently being written }
+ MaxCode : Word; { Largest code that can be written in CodeSize bits }
+ InBufIdx, { Points to next char in buffer to be read }
+ OutBufIdx : LongWord; { Points to next free space in output buffer }
+ InBuf, { I/O buffers }
+ OutBuf : BufPtr;
+ FirstCh : Boolean; { Flag indicating the START of a shrink operation }
+ TableFull : Boolean; { Flag indicating a full symbol table }
+ SaveByte : Byte; { Output code buffer }
+ BitsUsed : Byte; { Index into output code buffer }
+ BytesIn : LongInt; { Count of input file bytes processed }
+ BytesOut : LongInt; { Count of output bytes }
+ FOnBytes : Longint;
+ Procedure FillInputBuffer;
+ Procedure WriteOutputBuffer;
+ Procedure FlushOutput;
+ Procedure PutChar(B : Byte);
+ procedure PutCode(Code : Smallint);
+ Procedure InitializeCodeTable;
+ Procedure Prune(Parent : Word);
+ Procedure Clear_Table;
+ Procedure Table_Add(Prefix : Word; Suffix : Byte);
+ function Table_Lookup(TargetPrefix : Smallint;
+ TargetSuffix : Byte;
+ Out FoundAt : Smallint) : Boolean;
+ Procedure Shrink(Suffix : Smallint);
+ Procedure ProcessLine(Const Source : String);
+ Procedure DoOnProgress(Const Pct : Double); Virtual;
+ Public
+ Constructor Create(AInFile, AOutFile : TStream; ABufSize : LongWord); override;
+ Destructor Destroy; override;
+ Procedure Compress; override;
+ Class Function ZipID : Word; override;
+ end;
+
+ { TDeflater }
+
+ TDeflater = Class(TCompressor)
+ private
+ FCompressionLevel: TCompressionlevel;
+ Public
+ Constructor Create(AInFile, AOutFile : TStream; ABufSize : LongWord);override;
+ Procedure Compress; override;
+ Class Function ZipID : Word; override;
+ Property CompressionLevel : TCompressionlevel Read FCompressionLevel Write FCompressionLevel;
+ end;
+
+ { TInflater }
+
+ TInflater = Class(TDeCompressor)
+ Public
+ Constructor Create(AInFile, AOutFile : TStream; ABufSize : LongWord);override;
+ Procedure DeCompress; override;
+ Class Function ZipID : Word; override;
+ end;
+
+ { TZipper }
+
+ TZipper = Class(TObject)
+ Private
+ FZipping : Boolean;
+ FBufSize : LongWord;
+ FFileName : String; { Name of resulting Zip file }
+ FFiles : TStrings;
+ FInMemSize : Integer;
+ FOutFile : TFileStream;
+ FInFile : TFileStream; { I/O file variables }
+ LocalHdr : Local_File_Header_Type;
+ CentralHdr : Central_File_Header_Type;
+ EndHdr : End_of_Central_Dir_Type;
+ FOnPercent : LongInt;
+ FOnProgress : TProgressEvent;
+ FOnEndOfFile : TOnEndOfFileEvent;
+ FOnStartFile : TOnStartFileEvent;
+ Protected
+ Procedure OpenOutput;
+ Procedure CloseOutput;
+ Procedure CloseInput;
+ Procedure StartZipFile(Item : TZipItem);
+ Function UpdateZipHeader(Item : TZipItem; FZip : TStream; ACRC : LongWord;AMethod : Word) : Boolean;
+ Procedure BuildZipDirectory;
+ Procedure DoEndOfFile;
+ Procedure ZipOneFile(Item : TZipItem); virtual;
+ Function OpenInput(InFileName : String) : Boolean;
+ Procedure GetFileInfo;
+ Procedure SetBufSize(Value : LongWord);
+ Procedure SetFileName(Value : String);
+ Function CreateCompressor(Item : TZipItem; AinFile,AZipStream : TStream) : TCompressor; virtual;
+ Public
+ Constructor Create;
+ Destructor Destroy;override;
+ Procedure ZipAllFiles; virtual;
+ Procedure ZipFiles(AFileName : String; FileList : TStrings);
+ Procedure Clear;
+ Public
+ Property BufferSize : LongWord Read FBufSize Write SetBufSize;
+ Property OnPercent : Integer Read FOnPercent Write FOnPercent;
+ Property OnProgress : TProgressEvent Read FOnProgress Write FOnProgress;
+ Property OnStartFile : TOnStartFileEvent Read FOnStartFile Write FOnStartFile;
+ Property OnEndFile : TOnEndOfFileEvent Read FOnEndOfFile Write FOnEndOfFile;
+ Property FileName : String Read FFileName Write SetFileName;
+ Property Files : TStrings Read FFiles;
+ Property InMemSize : Integer Read FInMemSize Write FInMemSize;
+ end;
+
+ { TYbZipper }
+
+ { TUnZipper }
+
+ TUnZipper = Class(TObject)
+ Private
+ FUnZipping : Boolean;
+ FBufSize : LongWord;
+ FFileName : String; { Name of resulting Zip file }
+ FOutputPath : String;
+ FFiles : TStrings;
+ FZipEntries : TFPList; { don't use TFPObjectList, becuase of Contnrs dependency }
+ FOutFile : TFileStream;
+ FZipFile : TFileStream; { I/O file variables }
+ LocalHdr : Local_File_Header_Type;
+ CentralHdr : Central_File_Header_Type;
+ EndHdr : End_of_Central_Dir_Type;
+
+ FOnPercent : LongInt;
+ FOnProgress : TProgressEvent;
+ FOnEndOfFile : TOnEndOfFileEvent;
+ FOnStartFile : TOnStartFileEvent;
+ Protected
+ Procedure OpenInput;
+ Procedure CloseOutput;
+ Procedure CloseInput;
+ Procedure ReadZipHeader(Item : TZipItem; out ACRC : LongWord;out AMethod : Word);
+ Procedure ReadZipDirectory;
+ Procedure DoEndOfFile;
+ Procedure UnZipOneFile(Item : TZipItem); virtual;
+ Function OpenOutput(OutFileName : String) : Boolean;
+ Procedure SetBufSize(Value : LongWord);
+ Procedure SetFileName(Value : String);
+ Procedure SetOutputPath(Value:String);
+ Function CreateDeCompressor(Item : TZipItem; AMethod : Word;AZipFile,AOutFile : TStream) : TDeCompressor; virtual;
+ Public
+ Constructor Create;
+ Destructor Destroy;override;
+ Procedure UnZipAllFiles; virtual;
+ Procedure UnZipFiles(AFileName : String; FileList : TStrings);
+ Procedure UnZipAllFiles(AFileName : String);
+ Procedure Clear;
+ Public
+ Property BufferSize : LongWord Read FBufSize Write SetBufSize;
+ Property OnPercent : Integer Read FOnPercent Write FOnPercent;
+ Property OnProgress : TProgressEvent Read FOnProgress Write FOnProgress;
+ Property OnStartFile : TOnStartFileEvent Read FOnStartFile Write FOnStartFile;
+ Property OnEndFile : TOnEndOfFileEvent Read FOnEndOfFile Write FOnEndOfFile;
+ Property FileName : String Read FFileName Write SetFileName;
+ Property OutputPath : String Read FOutputPath Write SetOutputPath;
+ Property Files : TStrings Read FFiles;
+ end;
+
+ EZipError = Class(Exception);
+
+Implementation
+
+ResourceString
+ SErrBufsizeChange = 'Changing buffer size is not allowed while (un)zipping';
+ SErrFileChange = 'Changing output file name is not allowed while (un)zipping';
+ SErrInvalidCRC = 'Invalid CRC checksum while unzipping %s';
+ SErrCorruptZIP = 'Corrupt ZIP file %s';
+ SErrUnsupportedCompressionFormat = 'Unsupported compression format %d';
+
+{ ---------------------------------------------------------------------
+ Auxiliary
+ ---------------------------------------------------------------------}
+
+Procedure DateTimeToZipDateTime(DT : TDateTime; out ZD,ZT : Word);
+
+Var
+ Y,M,D,H,N,S,MS : Word;
+
+begin
+ DecodeDate(DT,Y,M,D);
+ DecodeTime(DT,H,N,S,MS);
+ Y:=Y-1980;
+ ZD:=d+(32*M)+(512*Y);
+ ZT:=(S div 2)+(32*N)+(2048*h);
+end;
+
+Procedure ZipDateTimeToDateTime(ZD,ZT : Word;out DT : TDateTime);
+
+Var
+ Y,M,D,H,N,S,MS : Word;
+
+begin
+ MS:=0;
+ S:=(ZT and 31) shl 1;
+ N:=(ZT shr 5) and 63;
+ H:=(ZT shr 12) and 31;
+ D:=ZD and 31;
+ M:=(ZD shr 5) and 15;
+ Y:=((ZD shr 9) and 127)+1980;
+ DT:=ComposeDateTime(EncodeDate(Y,M,D),EncodeTime(H,N,S,MS));
+end;
+
+{ ---------------------------------------------------------------------
+ TDeCompressor
+ ---------------------------------------------------------------------}
+
+
+Procedure TDeCompressor.UpdC32(Octet: Byte);
+
+Begin
+ FCrc32Val := Crc_32_Tab[Byte(FCrc32Val XOR LongInt(Octet))] XOR ((FCrc32Val SHR 8) AND $00FFFFFF);
+end;
+
+constructor TDeCompressor.Create(AInFile, AOutFile: TStream; ABufSize: LongWord);
+begin
+ FinFile:=AInFile;
+ FoutFile:=AOutFile;
+ FBufferSize:=ABufSize;
+ CRC32Val:=$FFFFFFFF;
+end;
+
+
+{ ---------------------------------------------------------------------
+ TCompressor
+ ---------------------------------------------------------------------}
+
+
+Procedure TCompressor.UpdC32(Octet: Byte);
+
+Begin
+ FCrc32Val := Crc_32_Tab[Byte(FCrc32Val XOR LongInt(Octet))] XOR ((FCrc32Val SHR 8) AND $00FFFFFF);
+end;
+
+constructor TCompressor.Create(AInFile, AOutFile: TStream; ABufSize: LongWord);
+begin
+ FinFile:=AInFile;
+ FoutFile:=AOutFile;
+ FBufferSize:=ABufSize;
+ CRC32Val:=$FFFFFFFF;
+end;
+
+
+{ ---------------------------------------------------------------------
+ TDeflater
+ ---------------------------------------------------------------------}
+
+constructor TDeflater.Create(AInFile, AOutFile: TStream; ABufSize: LongWord);
+begin
+ Inherited;
+ FCompressionLevel:=clDefault;
+end;
+
+
+procedure TDeflater.Compress;
+
+Var
+ Buf : PByte;
+ I,Count,NewCount : Integer;
+ C : TCompressionStream;
+
+begin
+ CRC32Val:=$FFFFFFFF;
+ Buf:=GetMem(FBufferSize);
+ Try
+ C:=TCompressionStream.Create(FCompressionLevel,FOutFile,True);
+ Try
+ Repeat
+ Count:=FInFile.Read(Buf^,FBufferSize);
+ For I:=0 to Count-1 do
+ UpdC32(Buf[i]);
+ NewCount:=Count;
+ While (NewCount>0) do
+ NewCount:=NewCount-C.Write(Buf^,NewCount);
+ Until (Count=0);
+ Finally
+ C.Free;
+ end;
+ Finally
+ FreeMem(Buf);
+ end;
+ Crc32Val:=NOT Crc32Val;
+end;
+
+class function TDeflater.ZipID: Word;
+begin
+ Result:=8;
+end;
+
+{ ---------------------------------------------------------------------
+ TInflater
+ ---------------------------------------------------------------------}
+
+constructor TInflater.Create(AInFile, AOutFile: TStream; ABufSize: LongWord);
+begin
+ Inherited;
+end;
+
+
+procedure TInflater.DeCompress;
+
+Var
+ Buf : PByte;
+ I,Count : Integer;
+ C : TDeCompressionStream;
+
+begin
+ CRC32Val:=$FFFFFFFF;
+ Buf:=GetMem(FBufferSize);
+ Try
+ C:=TDeCompressionStream.Create(FInFile,True);
+ Try
+ Repeat
+ Count:=C.Read(Buf^,FBufferSize);
+ For I:=0 to Count-1 do
+ UpdC32(Buf[i]);
+ FOutFile.Write(Buf^,Count);
+ Until (Count=0);
+ Finally
+ C.Free;
+ end;
+ Finally
+ FreeMem(Buf);
+ end;
+ Crc32Val:=NOT Crc32Val;
+end;
+
+class function TInflater.ZipID: Word;
+begin
+ Result:=8;
+end;
+
+
+{ ---------------------------------------------------------------------
+ TShrinker
+ ---------------------------------------------------------------------}
+
+Const
+ DefaultInMemSize = 256*1024; { Files larger than 256k are processed on disk }
+ DefaultBufSize = 16384; { Use 16K file buffers }
+ MINBITS = 9; { Starting code size of 9 bits }
+ MAXBITS = 13; { Maximum code size of 13 bits }
+ SPECIAL = 256; { Special function code }
+ INCSIZE = 1; { Code indicating a jump in code size }
+ CLEARCODE = 2; { Code indicating code table has been cleared }
+ STDATTR = $23; { Standard file attribute for DOS Find First/Next }
+
+constructor TShrinker.Create(AInFile, AOutFile : TStream; ABufSize : LongWord);
+begin
+ Inherited;
+ FBufSize:=ABufSize;
+ InBuf:=GetMem(FBUFSIZE);
+ OutBuf:=GetMem(FBUFSIZE);
+ CodeTable:=GetMem(SizeOf(CodeTable^));
+ FreeList:=GetMem(SizeOf(FreeList^));
+end;
+
+destructor TShrinker.Destroy;
+begin
+ FreeMem(CodeTable);
+ FreeMem(FreeList);
+ FreeMem(InBuf);
+ FreeMem(OutBuf);
+ inherited Destroy;
+end;
+
+Procedure TShrinker.Compress;
+
+Var
+ OneString : String;
+ Remaining : Word;
+
+begin
+ BytesIn := 1;
+ BytesOut := 1;
+ InitializeCodeTable;
+ FillInputBuffer;
+ FirstCh:= TRUE;
+ Crc32Val:=$FFFFFFFF;
+ FOnBytes:=Round((FInFile.Size * FOnPercent) / 100);
+ While NOT InputEof do
+ begin
+ Remaining:=Succ(MaxInBufIdx - InBufIdx);
+ If Remaining>255 then
+ Remaining:=255;
+ If Remaining=0 then
+ FillInputBuffer
+ else
+ begin
+ SetLength(OneString,Remaining);
+ Move(InBuf[InBufIdx], OneString[1], Remaining);
+ Inc(InBufIdx, Remaining);
+ ProcessLine(OneString);
+ end;
+ end;
+ Crc32Val := NOT Crc32Val;
+ ProcessLine('');
+end;
+
+class function TShrinker.ZipID: Word;
+begin
+ Result:=1;
+end;
+
+
+Procedure TShrinker.DoOnProgress(Const Pct: Double);
+
+begin
+ If Assigned(FOnProgress) then
+ FOnProgress(Self,Pct);
+end;
+
+
+Procedure TShrinker.FillInputBuffer;
+
+Begin
+ MaxInbufIDx:=FInfile.Read(InBuf[0], FBufSize);
+ If MaxInbufIDx=0 then
+ InputEof := TRUE
+ else
+ InputEOF := FALSE;
+ InBufIdx := 0;
+end;
+
+
+Procedure TShrinker.WriteOutputBuffer;
+Begin
+ FOutFile.WriteBuffer(OutBuf[0], OutBufIdx);
+ OutBufIdx := 0;
+end;
+
+
+Procedure TShrinker.PutChar(B : Byte);
+
+Begin
+ OutBuf[OutBufIdx] := B;
+ Inc(OutBufIdx);
+ If OutBufIdx>=FBufSize then
+ WriteOutputBuffer;
+ Inc(BytesOut);
+end;
+
+Procedure TShrinker.FlushOutput;
+Begin
+ If OutBufIdx>0 then
+ WriteOutputBuffer;
+End;
+
+
+procedure TShrinker.PutCode(Code : Smallint);
+
+var
+ ACode : LongInt;
+ XSize : Smallint;
+
+begin
+ if (Code=-1) then
+ begin
+ if BitsUsed>0 then
+ PutChar(SaveByte);
+ end
+ else
+ begin
+ ACode := Longint(Code);
+ XSize := CodeSize+BitsUsed;
+ ACode := (ACode shl BitsUsed) or SaveByte;
+ while (XSize div 8) > 0 do
+ begin
+ PutChar(Lo(ACode));
+ ACode := ACode shr 8;
+ Dec(XSize,8);
+ end;
+ BitsUsed := XSize;
+ SaveByte := Lo(ACode);
+ end;
+end;
+
+
+Procedure TShrinker.InitializeCodeTable;
+
+Var
+ I : Word;
+Begin
+ For I := 0 to TableSize do
+ begin
+ With CodeTable^[I] do
+ begin
+ Child := -1;
+ Sibling := -1;
+ If (I<=255) then
+ Suffix := I;
+ end;
+ If (I>=257) then
+ FreeList^[I] := I;
+ end;
+ NextFree := FIRSTENTRY;
+ TableFull := FALSE;
+end;
+
+
+Procedure TShrinker.Prune(Parent : Word);
+
+Var
+ CurrChild : Smallint;
+ NextSibling : Smallint;
+Begin
+ CurrChild := CodeTable^[Parent].Child;
+ { Find first Child that has descendants .. clear any that don't }
+ While (CurrChild <> -1) AND (CodeTable^[CurrChild].Child = -1) do
+ begin
+ CodeTable^[Parent].Child := CodeTable^[CurrChild].Sibling;
+ CodeTable^[CurrChild].Sibling := -1;
+ { Turn on ClearList bit to indicate a cleared entry }
+ ClearList[CurrChild DIV 8] := (ClearList[CurrChild DIV 8] OR (1 SHL (CurrChild MOD 8)));
+ CurrChild := CodeTable^[Parent].Child;
+ end;
+ If CurrChild <> -1 then
+ begin { If there are any children left ...}
+ Prune(CurrChild);
+ NextSibling := CodeTable^[CurrChild].Sibling;
+ While NextSibling <> -1 do
+ begin
+ If CodeTable^[NextSibling].Child = -1 then
+ begin
+ CodeTable^[CurrChild].Sibling := CodeTable^[NextSibling].Sibling;
+ CodeTable^[NextSibling].Sibling := -1;
+ { Turn on ClearList bit to indicate a cleared entry }
+ ClearList[NextSibling DIV 8] := (ClearList[NextSibling DIV 8] OR (1 SHL (NextSibling MOD 8)));
+ NextSibling := CodeTable^[CurrChild].Sibling;
+ end
+ else
+ begin
+ CurrChild := NextSibling;
+ Prune(CurrChild);
+ NextSibling := CodeTable^[CurrChild].Sibling;
+ end;
+ end;
+ end;
+end;
+
+
+Procedure TShrinker.Clear_Table;
+Var
+ Node : Word;
+Begin
+ FillChar(ClearList, SizeOf(ClearList), $00);
+ For Node := 0 to 255 do
+ Prune(Node);
+ NextFree := Succ(TABLESIZE);
+ For Node := TABLESIZE downto FIRSTENTRY do
+ begin
+ If (ClearList[Node DIV 8] AND (1 SHL (Node MOD 8))) <> 0 then
+ begin
+ Dec(NextFree);
+ FreeList^[NextFree] := Node;
+ end;
+ end;
+ If NextFree <= TABLESIZE then
+ TableFull := FALSE;
+end;
+
+
+Procedure TShrinker.Table_Add(Prefix : Word; Suffix : Byte);
+Var
+ FreeNode : Word;
+Begin
+ If NextFree <= TABLESIZE then
+ begin
+ FreeNode := FreeList^[NextFree];
+ Inc(NextFree);
+ CodeTable^[FreeNode].Child := -1;
+ CodeTable^[FreeNode].Sibling := -1;
+ CodeTable^[FreeNode].Suffix := Suffix;
+ If CodeTable^[Prefix].Child = -1 then
+ CodeTable^[Prefix].Child := FreeNode
+ else
+ begin
+ Prefix := CodeTable^[Prefix].Child;
+ While CodeTable^[Prefix].Sibling <> -1 do
+ Prefix := CodeTable^[Prefix].Sibling;
+ CodeTable^[Prefix].Sibling := FreeNode;
+ end;
+ end;
+ if NextFree > TABLESIZE then
+ TableFull := TRUE;
+end;
+
+function TShrinker.Table_Lookup( TargetPrefix : Smallint;
+ TargetSuffix : Byte;
+ Out FoundAt : Smallint ) : Boolean;
+
+var TempPrefix : Smallint;
+
+begin
+ TempPrefix := TargetPrefix;
+ Table_lookup := False;
+ if CodeTable^[TempPrefix].Child <> -1 then
+ begin
+ TempPrefix := CodeTable^[TempPrefix].Child;
+ repeat
+ if CodeTable^[TempPrefix].Suffix = TargetSuffix then
+ begin
+ Table_lookup := True;
+ break;
+ end;
+ if CodeTable^[TempPrefix].Sibling = -1 then
+ break;
+ TempPrefix := CodeTable^[TempPrefix].Sibling;
+ until False;
+ end;
+ if Table_Lookup then
+ FoundAt := TempPrefix
+ else
+ FoundAt := -1;
+end;
+
+Procedure TShrinker.Shrink(Suffix : Smallint);
+
+Const
+ LastCode : Smallint = 0;
+
+Var
+ WhereFound : Smallint;
+
+Begin
+ If FirstCh then
+ begin
+ SaveByte := $00;
+ BitsUsed := 0;
+ CodeSize := MINBITS;
+ MaxCode := (1 SHL CodeSize) - 1;
+ LastCode := Suffix;
+ FirstCh := FALSE;
+ end
+ else
+ begin
+ If Suffix <> -1 then
+ begin
+ If TableFull then
+ begin
+ Putcode(LastCode);
+ PutCode(SPECIAL);
+ Putcode(CLEARCODE);
+ Clear_Table;
+ Table_Add(LastCode, Suffix);
+ LastCode := Suffix;
+ end
+ else
+ begin
+ If Table_Lookup(LastCode, Suffix, WhereFound) then
+ begin
+ LastCode := WhereFound;
+ end
+ else
+ begin
+ PutCode(LastCode);
+ Table_Add(LastCode, Suffix);
+ LastCode := Suffix;
+ If (FreeList^[NextFree] > MaxCode) and (CodeSize < MaxBits) then
+ begin
+ PutCode(SPECIAL);
+ PutCode(INCSIZE);
+ Inc(CodeSize);
+ MaxCode := (1 SHL CodeSize) -1;
+ end;
+ end;
+ end;
+ end
+ else
+ begin
+ PutCode(LastCode);
+ PutCode(-1);
+ FlushOutput;
+ end;
+ end;
+end;
+
+Procedure TShrinker.ProcessLine(Const Source : String);
+
+Var
+ I : Word;
+
+Begin
+ If Source = '' then
+ Shrink(-1)
+ else
+ For I := 1 to Length(Source) do
+ begin
+ Inc(BytesIn);
+ If (Pred(BytesIn) MOD FOnBytes) = 0 then
+ DoOnProgress(100 * ( BytesIn / FInFile.Size));
+ UpdC32(Ord(Source[I]));
+ Shrink(Ord(Source[I]));
+ end;
+end;
+
+{ ---------------------------------------------------------------------
+ TZipper
+ ---------------------------------------------------------------------}
+
+
+Procedure TZipper.GetFileInfo;
+
+Var
+ Info : TSearchRec;
+ I : Longint;
+ NewNode : TZipItem;
+
+
+Begin
+ For I := 0 to FFiles.Count-1 do
+ begin
+ If FindFirst(FFiles[I], STDATTR, Info)=0 then
+ try
+ NewNode:=TZipItem.Create;
+ NewNode.Path := ExtractFilePath(FFiles[i]);
+ NewNode.Name := Info.Name;
+ NewNode.Size := Info.Size;
+ NewNode.DateTime:=FileDateToDateTime(Info.Time);
+ FFiles.Objects[i]:=NewNode;
+ finally
+ FindClose(Info);
+ end;
+ end;
+end;
+
+Procedure TZipper.OpenOutput;
+
+Begin
+ FOutFile:=TFileStream.Create(FFileName,fmCreate);
+End;
+
+
+Function TZipper.OpenInput(InFileName : String) : Boolean;
+
+Begin
+ FInFile:=TFileStream.Create(InFileName,fmOpenRead);
+ Result:=True;
+ If Assigned(FOnStartFile) then
+ FOnStartFile(Self,InFileName);
+End;
+
+
+Procedure TZipper.CloseOutput;
+
+Begin
+ FreeAndNil(FOutFile);
+end;
+
+
+Procedure TZipper.CloseInput;
+
+Begin
+ FreeAndNil(FInFile);
+end;
+
+
+Procedure TZipper.StartZipFile(Item : TZipItem);
+
+Begin
+ FillChar(LocalHdr,SizeOf(LocalHdr),0);
+ With LocalHdr do
+ begin
+ Signature := LOCAL_FILE_HEADER_SIGNATURE;
+ Extract_Version_Reqd := 10;
+ Bit_Flag := 0;
+ Compress_Method := 1;
+ DateTimeToZipDateTime(Item.DateTime,Last_Mod_Date,Last_Mod_Time);
+ Crc32 := 0;
+ Compressed_Size := 0;
+ Uncompressed_Size := Item.Size;
+ FileName_Length := 0;
+ Extra_Field_Length := 0;
+ end ;
+End;
+
+
+Function TZipper.UpdateZipHeader(Item : TZipItem; FZip : TStream; ACRC : LongWord; AMethod : Word) : Boolean;
+var
+ ZFileName : ShortString;
+Begin
+ ZFileName:=Item.Path+Item.Name;
+ With LocalHdr do
+ begin
+ FileName_Length := Length(ZFileName);
+ Compressed_Size := FZip.Size;
+ Crc32 := ACRC;
+ Compress_method:=AMethod;
+ Result:=Not (Compressed_Size >= Uncompressed_Size);
+ If Not Result then
+ begin { No... }
+ Compress_Method := 0; { ...change stowage type }
+ Compressed_Size := Uncompressed_Size; { ...update compressed size }
+ end;
+ end;
+ FOutFile.WriteBuffer(LocalHdr,SizeOf(LocalHdr));
+ FOutFile.WriteBuffer(ZFileName[1],Length(ZFileName));
+End;
+
+
+Procedure TZipper.BuildZipDirectory;
+
+Var
+ SavePos : LongInt;
+ HdrPos : LongInt;
+ CenDirPos : LongInt;
+ Entries : Word;
+ ZFileName : ShortString;
+
+Begin
+ Entries := 0;
+ CenDirPos := FOutFile.Position;
+ FOutFile.Seek(0,soFrombeginning); { Rewind output file }
+ HdrPos := FOutFile.Position;
+ FOutFile.ReadBuffer(LocalHdr, SizeOf(LocalHdr));
+ Repeat
+ SetLength(ZFileName,LocalHdr.FileName_Length);
+ FOutFile.ReadBuffer(ZFileName[1], LocalHdr.FileName_Length);
+ SavePos := FOutFile.Position;
+ FillChar(CentralHdr,SizeOf(CentralHdr),0);
+ With CentralHdr do
+ begin
+ Signature := CENTRAL_FILE_HEADER_SIGNATURE;
+ MadeBy_Version := LocalHdr.Extract_Version_Reqd;
+ Move(LocalHdr.Extract_Version_Reqd, Extract_Version_Reqd, 26);
+ Last_Mod_Time:=localHdr.Last_Mod_Time;
+ Last_Mod_Date:=localHdr.Last_Mod_Date;
+ File_Comment_Length := 0;
+ Starting_Disk_Num := 0;
+ Internal_Attributes := 0;
+ External_Attributes := faARCHIVE;
+ Local_Header_Offset := HdrPos;
+ end;
+ FOutFile.Seek(0,soFromEnd);
+ FOutFile.WriteBuffer(CentralHdr,SizeOf(CentralHdr));
+ FOutFile.WriteBuffer(ZFileName[1],Length(ZFileName));
+ Inc(Entries);
+ FOutFile.Seek(SavePos + LocalHdr.Compressed_Size,soFromBeginning);
+ HdrPos:=FOutFile.Position;
+ FOutFile.ReadBuffer(LocalHdr, SizeOf(LocalHdr));
+ Until LocalHdr.Signature = CENTRAL_FILE_HEADER_SIGNATURE;
+ FOutFile.Seek(0,soFromEnd);
+ FillChar(EndHdr,SizeOf(EndHdr),0);
+ With EndHdr do
+ begin
+ Signature := END_OF_CENTRAL_DIR_SIGNATURE;
+ Disk_Number := 0;
+ Central_Dir_Start_Disk := 0;
+ Entries_This_Disk := Entries;
+ Total_Entries := Entries;
+ Central_Dir_Size := FOutFile.Size-CenDirPos;
+ Start_Disk_Offset := CenDirPos;
+ ZipFile_Comment_Length := 0;
+ FOutFile.WriteBuffer(EndHdr, SizeOf(EndHdr));
+ end;
+end;
+
+Function TZipper.CreateCompressor(Item : TZipItem; AInFile,AZipStream : TStream) : TCompressor;
+
+begin
+ Result:=TDeflater.Create(AinFile,AZipStream,FBufSize);
+end;
+
+Procedure TZipper.ZipOneFile(Item : TZipItem);
+
+Var
+ CRC : LongWord;
+ ZMethod : Word;
+ ZipStream : TStream;
+ TmpFileName : String;
+
+Begin
+ OpenInput(Item.Path+Item.Name);
+ Try
+ StartZipFile(Item);
+ If (FInfile.Size<=FInMemSize) then
+ ZipStream:=TMemoryStream.Create
+ else
+ begin
+ TmpFileName:=ChangeFileExt(FFileName,'.tmp');
+ ZipStream:=TFileStream.Create(TmpFileName,fmCreate);
+ end;
+ Try
+ With CreateCompressor(Item, FinFile,ZipStream) do
+ Try
+ OnProgress:=Self.OnProgress;
+ OnPercent:=Self.OnPercent;
+ Compress;
+ CRC:=Crc32Val;
+ ZMethod:=ZipID;
+ Finally
+ Free;
+ end;
+ If UpdateZipHeader(Item,ZipStream,CRC,ZMethod) then
+ // Compressed file smaller than original file.
+ FOutFile.CopyFrom(ZipStream,0)
+ else
+ begin
+ // Original file smaller than compressed file.
+ FInfile.Seek(0,soFromBeginning);
+ FOutFile.CopyFrom(FInFile,0);
+ end;
+ finally
+ ZipStream.Free;
+ If (TmpFileName<>'') then
+ DeleteFile(TmpFileName);
+ end;
+ Finally
+ CloseInput;
+ end;
+end;
+
+Procedure TZipper.ZipAllFiles;
+Var
+ Item : TZipItem;
+ I : Integer;
+ filecnt : integer;
+Begin
+ if FFiles.Count=0 then
+ exit;
+ FZipping:=True;
+ Try
+ GetFileInfo;
+ OpenOutput;
+ Try
+ filecnt:=0;
+ For I:=0 to FFiles.Count-1 do
+ begin
+ Item:=FFiles.Objects[i] as TZipItem;
+ if assigned(Item) then
+ begin
+ ZipOneFile(Item);
+ inc(filecnt);
+ end;
+ end;
+ if filecnt>0 then
+ BuildZipDirectory;
+ finally
+ CloseOutput;
+ end;
+ finally
+ FZipping:=False;
+ end;
+end;
+
+
+Procedure TZipper.SetBufSize(Value : LongWord);
+
+begin
+ If FZipping then
+ Raise EZipError.Create(SErrBufsizeChange);
+ If Value>=DefaultBufSize then
+ FBufSize:=Value;
+end;
+
+Procedure TZipper.SetFileName(Value : String);
+
+begin
+ If FZipping then
+ Raise EZipError.Create(SErrFileChange);
+ FFileName:=Value;
+end;
+
+Procedure TZipper.ZipFiles(AFileName : String; FileList : TStrings);
+
+begin
+ FFiles.Assign(FileList);
+ FFileName:=AFileName;
+ ZipAllFiles;
+end;
+
+Procedure TZipper.DoEndOfFile;
+
+Var
+ ComprPct : Double;
+
+begin
+ If (LocalHdr.Uncompressed_Size>0) then
+ ComprPct := (100.0 * (LocalHdr.Uncompressed_Size - LocalHdr.Compressed_Size)) / LocalHdr.Uncompressed_Size
+ else
+ ComprPct := 0;
+ If Assigned(FOnEndOfFile) then
+ FOnEndOfFile(Self,ComprPct);
+end;
+
+Constructor TZipper.Create;
+
+begin
+ FBufSize:=DefaultBufSize;
+ FInMemSize:=DefaultInMemSize;
+ FFiles:=TStringList.Create;
+ TStringlist(FFiles).Sorted:=True;
+ FOnPercent:=1;
+end;
+
+Procedure TZipper.Clear;
+
+Var
+ I : Integer;
+
+begin
+ For I:=0 to FFiles.Count-1 do
+ FFiles.Objects[i].Free;
+ FFiles.Clear;
+end;
+
+Destructor TZipper.Destroy;
+
+begin
+ Clear;
+ FreeAndNil(FFiles);
+ Inherited;
+end;
+
+
+{ ---------------------------------------------------------------------
+ TUnZipper
+ ---------------------------------------------------------------------}
+
+Procedure TUnZipper.OpenInput;
+
+Begin
+ FZipFile:=TFileStream.Create(FFileName,fmOpenRead);
+End;
+
+
+Function TUnZipper.OpenOutput(OutFileName : String) : Boolean;
+
+Begin
+ FOutFile:=TFileStream.Create(OutFileName,fmCreate);
+ Result:=True;
+ If Assigned(FOnStartFile) then
+ FOnStartFile(Self,OutFileName);
+End;
+
+
+Procedure TUnZipper.CloseOutput;
+
+Begin
+ FreeAndNil(FOutFile);
+end;
+
+
+Procedure TUnZipper.CloseInput;
+
+Begin
+ FreeAndNil(FZipFile);
+end;
+
+
+Procedure TUnZipper.ReadZipHeader(Item : TZipItem; out ACRC : LongWord; out AMethod : Word);
+
+Begin
+ FZipFile.Seek(Item.HdrPos,soFromBeginning);
+ FZipFile.ReadBuffer(LocalHdr,SizeOf(LocalHdr));
+ With LocalHdr do
+ begin
+ SetLength(Item.Name,Filename_Length);
+ FZipFile.ReadBuffer(Item.Name[1],Filename_Length);
+ FZipFile.Seek(Extra_Field_Length,soCurrent);
+ Item.Size:=Uncompressed_Size;
+ ZipDateTimeToDateTime(Last_Mod_Date,Last_Mod_Time,Item.DateTime);
+ ACrc:=Crc32;
+ AMethod:=Compress_method;
+ end;
+End;
+
+
+Procedure TUnZipper.ReadZipDirectory;
+
+Var
+ i,
+ EndHdrPos,
+ CenDirPos : LongInt;
+ NewNode : TZipItem;
+Begin
+ EndHdrPos:=FZipFile.Size-SizeOf(EndHdr);
+ if EndHdrPos < 0 then
+ raise EZipError.CreateFmt(SErrCorruptZIP,[FZipFile.FileName]);
+ FZipFile.Seek(EndHdrPos,soFromBeginning);
+ FZipFile.ReadBuffer(EndHdr, SizeOf(EndHdr));
+ With EndHdr do
+ begin
+ if Signature <> END_OF_CENTRAL_DIR_SIGNATURE then
+ raise EZipError.CreateFmt(SErrCorruptZIP,[FZipFile.FileName]);
+ CenDirPos:=Start_Disk_Offset;
+ end;
+ FZipFile.Seek(CenDirPos,soFrombeginning);
+ for i:=0 to EndHdr.Entries_This_Disk-1 do
+ begin
+ FZipFile.ReadBuffer(CentralHdr, SizeOf(CentralHdr));
+ With CentralHdr do
+ begin
+ if Signature<>CENTRAL_FILE_HEADER_SIGNATURE then
+ raise EZipError.CreateFmt(SErrCorruptZIP,[FZipFile.FileName]);
+ NewNode:=TZipItem.Create;
+ NewNode.HdrPos := Local_Header_Offset;
+ SetLength(NewNode.Name,Filename_Length);
+ FZipFile.ReadBuffer(NewNode.Name[1],Filename_Length);
+ FZipFile.Seek(Extra_Field_Length+File_Comment_Length,soCurrent);
+ FZipEntries.Add(NewNode);
+ end;
+ end;
+end;
+
+Function TUnZipper.CreateDeCompressor(Item : TZipItem; AMethod : Word;AZipFile,AOutFile : TStream) : TDeCompressor;
+begin
+ case AMethod of
+ 8 :
+ Result:=TInflater.Create(AZipFile,AOutFile,FBufSize);
+ else
+ raise EZipError.CreateFmt(SErrUnsupportedCompressionFormat,[AMethod]);
+ end;
+end;
+
+Procedure TUnZipper.UnZipOneFile(Item : TZipItem);
+
+Var
+ Count : Longint;
+ CRC : LongWord;
+ ZMethod : Word;
+ OutputFileName : string;
+Begin
+ Try
+ ReadZipHeader(Item,CRC,ZMethod);
+ OutputFileName:=Item.Name;
+ if FOutputPath<>'' then
+ OutputFileName:=IncludeTrailingPathDelimiter(FOutputPath)+OutputFileName;
+ OpenOutput(OutputFileName);
+ if ZMethod=0 then
+ begin
+ Count:=FOutFile.CopyFrom(FZipFile,LocalHdr.Compressed_Size);
+{$warning TODO: Implement CRC Check}
+ end
+ else
+ With CreateDecompressor(Item, ZMethod, FZipFile, FOutFile) do
+ Try
+ OnProgress:=Self.OnProgress;
+ OnPercent:=Self.OnPercent;
+ DeCompress;
+ if CRC<>Crc32Val then
+ raise EZipError.CreateFmt(SErrInvalidCRC,[Item.Name]);
+ Finally
+ Free;
+ end;
+ Finally
+ CloseOutput;
+ end;
+end;
+
+
+Procedure TUnZipper.UnZipAllFiles;
+Var
+ Item : TZipItem;
+ I : Integer;
+
+Begin
+ FUnZipping:=True;
+ Try
+ OpenInput;
+ Try
+ ReadZipDirectory;
+ For I:=0 to FZipEntries.Count-1 do
+ begin
+ Item:=TZipItem(FZipEntries[i]);
+ if (FFiles=nil) or
+ (FFiles.IndexOf(Item.Name)<>-1) then
+ UnZipOneFile(Item);
+ end;
+ Finally
+ CloseInput;
+ end;
+ finally
+ FUnZipping:=False;
+ end;
+end;
+
+
+Procedure TUnZipper.SetBufSize(Value : LongWord);
+
+begin
+ If FUnZipping then
+ Raise EZipError.Create(SErrBufsizeChange);
+ If Value>=DefaultBufSize then
+ FBufSize:=Value;
+end;
+
+Procedure TUnZipper.SetFileName(Value : String);
+
+begin
+ If FUnZipping then
+ Raise EZipError.Create(SErrFileChange);
+ FFileName:=Value;
+end;
+
+Procedure TUnZipper.SetOutputPath(Value:String);
+begin
+ If FUnZipping then
+ Raise EZipError.Create(SErrFileChange);
+ FOutputPath:=Value;
+end;
+
+Procedure TUnZipper.UnZipFiles(AFileName : String; FileList : TStrings);
+
+begin
+ FFiles.Assign(FileList);
+ FFileName:=AFileName;
+ UnZipAllFiles;
+end;
+
+Procedure TUnZipper.UnZipAllFiles(AFileName : String);
+
+begin
+ FFileName:=AFileName;
+ UnZipAllFiles;
+end;
+
+Procedure TUnZipper.DoEndOfFile;
+
+Var
+ ComprPct : Double;
+
+begin
+ If (LocalHdr.Uncompressed_Size>0) then
+ ComprPct := (100.0 * (LocalHdr.Uncompressed_Size - LocalHdr.Compressed_Size)) / LocalHdr.Uncompressed_Size
+ else
+ ComprPct := 0;
+ If Assigned(FOnEndOfFile) then
+ FOnEndOfFile(Self,ComprPct);
+end;
+
+Constructor TUnZipper.Create;
+
+begin
+ FBufSize:=DefaultBufSize;
+ FFiles:=TStringList.Create;
+ FZipEntries:=TFPList.Create;
+ TStringlist(FFiles).Sorted:=True;
+ FOnPercent:=1;
+end;
+
+Procedure TUnZipper.Clear;
+
+Var
+ I : Integer;
+
+begin
+ For I:=0 to FFiles.Count-1 do
+ FFiles.Objects[i].Free;
+ FFiles.Clear;
+ For I:=0 to FZipEntries.Count-1 do
+ TZipItem(FZipEntries[i]).Free;
+ FZipEntries.Clear;
+end;
+
+Destructor TUnZipper.Destroy;
+
+begin
+ Clear;
+ FreeAndNil(FFiles);
+ FreeAndNil(FZipEntries);
+ Inherited;
+end;
+
+End.
diff --git a/packages/paszlib/src/ziputils.pas b/packages/paszlib/src/ziputils.pas
new file mode 100644
index 0000000000..234efee435
--- /dev/null
+++ b/packages/paszlib/src/ziputils.pas
@@ -0,0 +1,304 @@
+unit ziputils;
+
+{ ziputils.pas - IO on .zip files using zlib
+ - definitions, declarations and routines used by both
+ zip.pas and unzip.pas
+ The file IO is implemented here.
+
+ based on work by Gilles Vollant
+
+ March 23th, 2000,
+ Copyright (C) 2000 Jacques Nomssi Nzali }
+
+interface
+
+{$undef UseStream}
+
+{$ifdef WIN32}
+ {$define Delphi}
+ {$ifdef UseStream}
+ {$define Streams}
+ {$endif}
+{$endif}
+
+//uses Classes, SysUtils;
+
+{ -------------------------------------------------------------- }
+{$ifdef Streams}
+type
+ FILEptr = TFileStream;
+{$else}
+type
+ FILEptr = ^file;
+{$endif}
+
+type
+ seek_mode = (SEEK_SET, SEEK_CUR, SEEK_END);
+ open_mode = (fopenread, fopenwrite, fappendwrite);
+
+function fopen(filename: PChar; mode: open_mode): FILEptr;
+
+procedure fclose(fp: FILEptr);
+
+function fseek(fp: FILEptr; recPos: longint; mode: seek_mode): longint;
+
+function fread(buf: pointer; recSize: longint; recCount: longint; fp: FILEptr): longint;
+
+function fwrite(buf: pointer; recSize: longint; recCount: longint; fp: FILEptr): longint;
+
+function ftell(fp: FILEptr): longint; { ZIP }
+
+function feof(fp: FILEptr): longint; { MiniZIP }
+
+{ ------------------------------------------------------------------- }
+
+type
+ zipFile = pointer;
+ unzFile = pointer;
+
+type
+ z_off_t = longint;
+
+{ tm_zip contain date/time info }
+type
+ tm_zip = record
+ tm_sec: longint; { seconds after the minute - [0,59] }
+ tm_min: longint; { minutes after the hour - [0,59] }
+ tm_hour: longint; { hours since midnight - [0,23] }
+ tm_mday: longint; { day of the month - [1,31] }
+ tm_mon: longint; { months since January - [0,11] }
+ tm_year: longint; { years - [1980..2044] }
+ end;
+
+ tm_unz = tm_zip;
+
+const
+ Z_BUFSIZE = (16384);
+ Z_MAXFILENAMEINZIP = (256);
+
+const
+ CENTRALHEADERMAGIC = $02014b50;
+
+const
+ SIZECENTRALDIRITEM = $2e;
+ SIZEZIPLOCALHEADER = $1e;
+
+const
+ Paszip_copyright: PChar = ' Paszip Copyright 2000 Jacques Nomssi Nzali ';
+
+implementation
+
+{$ifdef Streams}
+{ ---------------------------------------------------------------- }
+
+function fopen(filename: PChar; mode: open_mode): FILEptr;
+var
+ fp: FILEptr;
+begin
+ fp := nil;
+ try
+ case mode of
+ fopenread: fp := TFileStream.Create(filename, fmOpenRead);
+ fopenwrite: fp := TFileStream.Create(filename, fmCreate);
+ fappendwrite:
+ begin
+ fp := TFileStream.Create(filename, fmOpenReadWrite);
+ fp.Seek(soFromEnd, 0);
+ end;
+ end;
+ except
+ on EFOpenError do
+ fp := nil;
+ end;
+ fopen := fp;
+end;
+
+procedure fclose(fp: FILEptr);
+begin
+ fp.Free;
+end;
+
+function fread(buf: pointer; recSize: longint; recCount: longint; fp: FILEptr): longint;
+var
+ totalSize, readcount: longint;
+begin
+ if Assigned(buf) then
+ begin
+ totalSize := recCount * longint(recSize);
+ readCount := fp.Read(buf^, totalSize);
+ if (readcount <> totalSize) then
+ fread := readcount div recSize
+ else
+ fread := recCount;
+ end
+ else
+ fread := 0;
+end;
+
+function fwrite(buf: pointer; recSize: longint; recCount: longint; fp: FILEptr): longint;
+var
+ totalSize, written: longint;
+begin
+ if Assigned(buf) then
+ begin
+ totalSize := recCount * longint(recSize);
+ written := fp.Write(buf^, totalSize);
+ if (written <> totalSize) then
+ fwrite := written div recSize
+ else
+ fwrite := recCount;
+ end
+ else
+ fwrite := 0;
+end;
+
+function fseek(fp: FILEptr; recPos: longint; mode: seek_mode): int;
+const
+ fsmode: array[seek_mode] of word = (soFromBeginning, soFromCurrent, soFromEnd);
+begin
+ fp.Seek(recPos, fsmode[mode]);
+ fseek := 0; { = 0 for success }
+end;
+
+function ftell(fp: FILEptr): longint;
+begin
+ ftell := fp.Position;
+end;
+
+function feof(fp: FILEptr): longint;
+begin
+ feof := 0;
+ if Assigned(fp) then
+ if fp.Position = fp.Size then
+ feof := 1
+ else
+ feof := 0;
+end;
+
+{$else}
+{ ---------------------------------------------------------------- }
+
+function fopen(filename : PChar; mode : open_mode) : FILEptr;
+var
+ fp : FILEptr;
+ OldFileMode : byte;
+begin
+ fp := NIL;
+ OldFileMode := FileMode;
+
+ GetMem(fp, SizeOf(file));
+ Assign(fp^, filename);
+ {$i-}
+ Case mode of
+ fopenread:
+ begin
+ FileMode := 0;
+ Reset(fp^, 1);
+ end;
+ fopenwrite:
+ begin
+ FileMode := 1;
+ ReWrite(fp^, 1);
+ end;
+ fappendwrite :
+ begin
+ FileMode := 2;
+ Reset(fp^, 1);
+ Seek(fp^, FileSize(fp^));
+ end;
+ end;
+ FileMode := OldFileMode;
+ if IOresult<>0 then
+ begin
+ FreeMem(fp, SizeOf(file));
+ fp := NIL;
+ end;
+
+ fopen := fp;
+end;
+
+procedure fclose(fp : FILEptr);
+begin
+ if Assigned(fp) then
+ begin
+ {$i-}
+ system.close(fp^);
+ if IOresult=0 then;
+ FreeMem(fp, SizeOf(file));
+ end;
+end;
+
+function fread(buf : pointer;
+ recSize : LongInt;
+ recCount : LongInt;
+ fp : FILEptr) : LongInt;
+var
+ totalSize, readcount : LongInt;
+begin
+ if Assigned(buf) then
+ begin
+ totalSize := recCount * LongInt(recSize);
+ {$i-}
+ system.BlockRead(fp^, buf^, totalSize, readcount);
+ if (readcount <> totalSize) then
+ fread := readcount div recSize
+ else
+ fread := recCount;
+ end
+ else
+ fread := 0;
+end;
+
+function fwrite(buf : pointer;
+ recSize : LongInt;
+ recCount : LongInt;
+ fp : FILEptr) : LongInt;
+var
+ totalSize, written : LongInt;
+begin
+ if Assigned(buf) then
+ begin
+ totalSize := recCount * LongInt(recSize);
+ {$i-}
+ system.BlockWrite(fp^, buf^, totalSize, written);
+ if (written <> totalSize) then
+ fwrite := written div recSize
+ else
+ fwrite := recCount;
+ end
+ else
+ fwrite := 0;
+end;
+
+function fseek(fp : FILEptr;
+ recPos : LongInt;
+ mode : seek_mode) : longint;
+begin
+ {$i-}
+ case mode of
+ SEEK_SET : system.Seek(fp^, recPos);
+ SEEK_CUR : system.Seek(fp^, FilePos(fp^)+recPos);
+ SEEK_END : system.Seek(fp^, FileSize(fp^)-1-recPos); { ?? check }
+ end;
+ fseek := IOresult; { = 0 for success }
+end;
+
+function ftell(fp : FILEptr) : LongInt;
+begin
+ ftell := FilePos(fp^);
+end;
+
+function feof(fp : FILEptr) : LongInt;
+begin
+ feof := 0;
+ if Assigned(fp) then
+ if eof(fp^) then
+ feof := 1
+ else
+ feof := 0;
+end;
+
+{$endif}
+{ ---------------------------------------------------------------- }
+
+end.
diff --git a/packages/paszlib/src/zstream.pp b/packages/paszlib/src/zstream.pp
new file mode 100644
index 0000000000..6246fa0234
--- /dev/null
+++ b/packages/paszlib/src/zstream.pp
@@ -0,0 +1,440 @@
+{
+ This file is part of the Free Pascal run time library.
+ Copyright (c) 1999-2000 by the Free Pascal development team
+
+ Implementation of compression streams.
+
+ See the file COPYING.FPC, included in this distribution,
+ for details about the copyright.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+{$mode objfpc}
+
+unit zstream;
+
+
+{ ---------------------------------------------------------------------
+ For linux and freebsd it's also possible to use ZLib instead
+ of paszlib. You need to undefine 'usepaszlib'.
+ ---------------------------------------------------------------------}
+
+{$define usepaszlib}
+
+
+interface
+
+uses
+ Sysutils, Classes
+{$ifdef usepaszlib}
+ ,paszlib,zbase
+{$else}
+ ,zlib
+{$endif}
+ ;
+
+{$H+}
+
+type
+ // Error reporting.
+ EZlibError = class(EStreamError);
+ ECompressionError = class(EZlibError);
+ EDecompressionError = class(EZlibError);
+
+ TCustomZlibStream = class(TOwnerStream)
+ private
+ FStrmPos: Integer;
+ FOnProgress: TNotifyEvent;
+ FZRec: TZStream;
+ FBuffer: array [Word] of Byte;
+ protected
+ procedure Progress(Sender: TObject); dynamic;
+ property OnProgress: TNotifyEvent read FOnProgress write FOnProgress;
+ public
+ constructor Create(Strm: TStream);
+ end;
+
+ TCompressionLevel = (clNone, clFastest, clDefault, clMax);
+
+ TCompressionStream = class(TCustomZlibStream)
+ private
+ function GetCompressionRate: extended;
+ function CompressionCheck(code: Integer): Integer;
+ procedure CompressBuf(const InBuf: Pointer; InBytes: Integer;
+ var OutBuf: Pointer; var OutBytes: Integer);
+ public
+ constructor Create(CompressionLevel: TCompressionLevel; Dest: TStream; ASkipHeader : Boolean = False);
+ destructor Destroy; override;
+ function Read(var Buffer; Count: Longint): Longint; override;
+ function Write(const Buffer; Count: Longint): Longint; override;
+ function Seek(Offset: Longint; Origin: Word): Longint; override;
+ property CompressionRate: extended read GetCompressionRate;
+ property OnProgress;
+ end;
+
+ TDecompressionStream = class(TCustomZlibStream)
+ private
+ function DecompressionCheck(code: Integer): Integer;
+ procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer;
+ OutEstimate: Integer; var OutBuf: Pointer; var OutBytes: Integer);
+ public
+ constructor Create(ASource: TStream; ASkipHeader : Boolean = False);
+ destructor Destroy; override;
+ function Read(var Buffer; Count: Longint): Longint; override;
+ function Write(const Buffer; Count: Longint): Longint; override;
+ function Seek(Offset: Longint; Origin: Word): Longint; override;
+ property OnProgress;
+ end;
+
+ TGZOpenMode = (gzOpenRead,gzOpenWrite);
+
+ TGZFileStream = Class(TStream)
+ Private
+ FOpenMode : TGZOpenmode;
+ FFIle : gzfile;
+ Public
+ Constructor Create(FileName: String;FileMode: TGZOpenMode);
+ Destructor Destroy;override;
+ Function Read(Var Buffer; Count : longint): longint;override;
+ function Write(const Buffer; Count: Longint): Longint; override;
+ function Seek(Offset: Longint; Origin: Word): Longint; override;
+ end;
+
+
+implementation
+
+Const
+ ErrorStrings : array [0..6] of string =
+ ('Unknown error %d','Z_ERRNO','Z_STREAM_ERROR',
+ 'Z_DATA_ERROR','Z_MEM_ERROR','Z_BUF_ERROR','Z_VERSION_ERROR');
+ SCouldntOpenFile = 'Couldn''t open file : %s';
+ SReadOnlyStream = 'Decompression streams are read-only';
+ SWriteOnlyStream = 'Compression streams are write-only';
+ SSeekError = 'Compression stream seek error';
+ SInvalidSeek = 'Invalid Compression seek operation';
+
+procedure TCompressionStream.CompressBuf(const InBuf: Pointer; InBytes: Integer;
+ var OutBuf: Pointer; var OutBytes: Integer);
+var
+ strm: TZStream;
+ P: Pointer;
+begin
+ FillChar(strm, sizeof(strm), 0);
+ OutBytes := ((InBytes + (InBytes div 10) + 12) + 255) and not 255;
+ OutBuf:=GetMem(OutBytes);
+ try
+ strm.next_in := InBuf;
+ strm.avail_in := InBytes;
+ strm.next_out := OutBuf;
+ strm.avail_out := OutBytes;
+ CompressionCheck(deflateInit(strm, Z_BEST_COMPRESSION));
+ try
+ while CompressionCheck(deflate(strm, Z_FINISH)) <> Z_STREAM_END do
+ begin
+ P := OutBuf;
+ Inc(OutBytes, 256);
+ ReallocMem(OutBuf,OutBytes);
+ strm.next_out := PByte(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P)));
+ strm.avail_out := 256;
+ end;
+ finally
+ CompressionCheck(deflateEnd(strm));
+ end;
+ ReallocMem(OutBuf,strm.total_out);
+ OutBytes := strm.total_out;
+ except
+ FreeMem(OutBuf);
+ raise;
+ end;
+end;
+
+
+procedure TDecompressionStream.DecompressBuf(const InBuf: Pointer; InBytes: Integer;
+ OutEstimate: Integer; var OutBuf: Pointer; var OutBytes: Integer);
+var
+ strm: TZStream;
+ P: Pointer;
+ BufInc: Integer;
+Type
+ PByte = ^Byte;
+begin
+ FillChar(strm, sizeof(strm), 0);
+ BufInc := (InBytes + 255) and not 255;
+ if OutEstimate = 0 then
+ OutBytes := BufInc
+ else
+ OutBytes := OutEstimate;
+ OutBuf:=GetMem(OutBytes);
+ try
+ strm.next_in := InBuf;
+ strm.avail_in := InBytes;
+ strm.next_out := OutBuf;
+ strm.avail_out := OutBytes;
+ DecompressionCheck(inflateInit(strm));
+ try
+ while DecompressionCheck(inflate(strm, Z_FINISH)) <> Z_STREAM_END do
+ begin
+ P := OutBuf;
+ Inc(OutBytes, BufInc);
+ ReallocMem(OutBuf, OutBytes);
+ strm.next_out := PByte(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P)));
+ strm.avail_out := BufInc;
+ end;
+ finally
+ DecompressionCheck(inflateEnd(strm));
+ end;
+ ReallocMem(OutBuf, strm.total_out);
+ OutBytes := strm.total_out;
+ except
+ FreeMem(OutBuf);
+ raise;
+ end;
+end;
+
+
+// TCustomZlibStream
+
+constructor TCustomZLibStream.Create(Strm: TStream);
+begin
+ inherited Create(Strm);
+ FStrmPos := Strm.Position;
+end;
+
+procedure TCustomZLibStream.Progress(Sender: TObject);
+begin
+ if Assigned(FOnProgress) then FOnProgress(Sender);
+end;
+
+
+// TCompressionStream
+
+constructor TCompressionStream.Create(CompressionLevel: TCompressionLevel;
+ Dest: TStream; ASkipHeader : Boolean = False);
+const
+ Levels: array [TCompressionLevel] of ShortInt =
+ (Z_NO_COMPRESSION, Z_BEST_SPEED, Z_DEFAULT_COMPRESSION, Z_BEST_COMPRESSION);
+begin
+ inherited Create(Dest);
+ FZRec.next_out := @FBuffer[0];
+ FZRec.avail_out := sizeof(FBuffer);
+ If ASkipHeader then
+ CompressionCheck(deflateInit2(FZRec, Levels[CompressionLevel],Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, 0))
+ else
+ CompressionCheck(deflateInit(FZRec, Levels[CompressionLevel]));
+end;
+
+destructor TCompressionStream.Destroy;
+begin
+ FZRec.next_in := nil;
+ FZRec.avail_in := 0;
+ try
+ if Source.Position <> FStrmPos then Source.Position := FStrmPos;
+ while (CompressionCheck(deflate(FZRec, Z_FINISH)) <> Z_STREAM_END)
+ and (FZRec.avail_out = 0) do
+ begin
+ Source.WriteBuffer(FBuffer, sizeof(FBuffer));
+ FZRec.next_out := @FBuffer[0];
+ FZRec.avail_out := sizeof(FBuffer);
+ end;
+ if FZRec.avail_out < sizeof(FBuffer) then
+ Source.WriteBuffer(FBuffer, sizeof(FBuffer) - FZRec.avail_out);
+ finally
+ deflateEnd(FZRec);
+ end;
+ inherited Destroy;
+end;
+
+function TCompressionStream.CompressionCheck(code: Integer): Integer;
+begin
+ Result := code;
+ if (code < 0) then
+ if code < -6 then
+ raise ECompressionError.CreateFmt(Errorstrings[0],[Code])
+ else
+ raise ECompressionError.Create(ErrorStrings[Abs(Code)]);
+end;
+
+
+function TCompressionStream.Read(var Buffer; Count: Longint): Longint;
+begin
+ raise ECompressionError.Create('Invalid stream operation');
+ result:=0;
+end;
+
+function TCompressionStream.Write(const Buffer; Count: Longint): Longint;
+begin
+ FZRec.next_in := @Buffer;
+ FZRec.avail_in := Count;
+ if Source.Position <> FStrmPos then Source.Position := FStrmPos;
+ while (FZRec.avail_in > 0) do
+ begin
+ CompressionCheck(deflate(FZRec, 0));
+ if FZRec.avail_out = 0 then
+ begin
+ Source.WriteBuffer(FBuffer, sizeof(FBuffer));
+ FZRec.next_out := @FBuffer[0];
+ FZRec.avail_out := sizeof(FBuffer);
+ FStrmPos := Source.Position;
+ Progress(Self);
+ end;
+ end;
+ Result := Count;
+end;
+
+function TCompressionStream.Seek(Offset: Longint; Origin: Word): Longint;
+begin
+ if (Offset = 0) and (Origin = soFromCurrent) then
+ Result := FZRec.total_in
+ else
+ raise ECompressionError.Create(SInvalidSeek);
+end;
+
+function TCompressionStream.GetCompressionRate: extended;
+begin
+ Result:=0.0;
+{ With FZrec do
+ if total_in = 0 then
+ GetCompressionRate:=0.0
+ else
+ GetCompressionRate:=1.0E2*(1.0E0-(total_out/total_in));
+}
+end;
+
+
+// TDecompressionStream
+
+constructor TDecompressionStream.Create(ASource: TStream; ASkipHeader : Boolean = False);
+begin
+ inherited Create(ASource);
+ FZRec.next_in := @FBuffer[0];
+ If ASkipHeader then
+ DeCompressionCheck(inflateInit2(FZRec,-MAX_WBITS))
+ else
+ DeCompressionCheck(inflateInit(FZRec));
+end;
+
+destructor TDecompressionStream.Destroy;
+begin
+ if FZRec.avail_in <> 0 then
+ Source.Seek(-FZRec.avail_in, soFromCurrent);
+ inflateEnd(FZRec);
+ inherited Destroy;
+end;
+
+function TDecompressionStream.DecompressionCheck(code: Integer): Integer;
+begin
+ Result := code;
+ If Code<0 then
+ if code < -6 then
+ raise EDecompressionError.CreateFmt(Errorstrings[0],[Code])
+ else
+ raise EDecompressionError.Create(ErrorStrings[Abs(Code)]);
+end;
+
+function TDecompressionStream.Read(var Buffer; Count: Longint): Longint;
+begin
+ FZRec.next_out := @Buffer;
+ FZRec.avail_out := Count;
+ if Source.Position <> FStrmPos then Source.Position := FStrmPos;
+ while (FZRec.avail_out > 0) do
+ begin
+ if FZRec.avail_in = 0 then
+ begin
+ FZRec.avail_in := Source.Read(FBuffer, sizeof(FBuffer));
+ if FZRec.avail_in = 0 then
+ begin
+ Result := Count - FZRec.avail_out;
+ Exit;
+ end;
+ FZRec.next_in := @FBuffer[0];
+ FStrmPos := Source.Position;
+ Progress(Self);
+ end;
+ if DeCompressionCheck(inflate(FZRec, 0)) = Z_STREAM_END then
+ begin
+ Result := Count - FZRec.avail_out;
+ Exit;
+ end;
+ end;
+ Result := Count;
+end;
+
+function TDecompressionStream.Write(const Buffer; Count: Longint): Longint;
+begin
+ raise EDecompressionError.Create('Invalid stream operation');
+ result:=0;
+end;
+
+function TDecompressionStream.Seek(Offset: Longint; Origin: Word): Longint;
+var
+ I: Integer;
+ Buf: array [0..4095] of Char;
+begin
+ if (Offset = 0) and (Origin = soFromBeginning) then
+ begin
+ DecompressionCheck(inflateReset(FZRec));
+ FZRec.next_in := @FBuffer[0];
+ FZRec.avail_in := 0;
+ Source.Position := 0;
+ FStrmPos := 0;
+ end
+ else if ( (Offset >= 0) and (Origin = soFromCurrent)) or
+ ( ((Offset - FZRec.total_out) > 0) and (Origin = soFromBeginning)) then
+ begin
+ if Origin = soFromBeginning then Dec(Offset, FZRec.total_out);
+ if Offset > 0 then
+ begin
+ for I := 1 to Offset div sizeof(Buf) do
+ ReadBuffer(Buf, sizeof(Buf));
+ ReadBuffer(Buf, Offset mod sizeof(Buf));
+ end;
+ end
+ else
+ raise EDecompressionError.Create(SInvalidSeek);
+ Result := FZRec.total_out;
+end;
+
+// TGZFileStream
+
+Constructor TGZFileStream.Create(FileName: String;FileMode: TGZOpenMode);
+
+Const OpenStrings : array[TGZOpenMode] of pchar = ('rb','wb');
+
+begin
+ FOpenMode:=FileMode;
+ FFile:=gzopen (PChar(FileName),Openstrings[FileMode]);
+ If FFile=Nil then
+ Raise ezlibError.CreateFmt (SCouldntOpenFIle,[FileName]);
+end;
+
+Destructor TGZFileStream.Destroy;
+begin
+ gzclose(FFile);
+ Inherited Destroy;
+end;
+
+Function TGZFileStream.Read(Var Buffer; Count : longint): longint;
+begin
+ If FOpenMode=gzOpenWrite then
+ Raise ezliberror.create(SWriteOnlyStream);
+ Result:=gzRead(FFile,@Buffer,Count);
+end;
+
+function TGZFileStream.Write(const Buffer; Count: Longint): Longint;
+begin
+ If FOpenMode=gzOpenRead then
+ Raise EzlibError.Create(SReadonlyStream);
+ Result:=gzWrite(FFile,@Buffer,Count);
+end;
+
+function TGZFileStream.Seek(Offset: Longint; Origin: Word): Longint;
+begin
+ Result:=gzseek(FFile,Offset,Origin);
+ If Result=-1 then
+ Raise eZlibError.Create(SSeekError);
+end;
+
+end.
diff --git a/packages/paszlib/src/zuncompr.pas b/packages/paszlib/src/zuncompr.pas
new file mode 100644
index 0000000000..18a608ff86
--- /dev/null
+++ b/packages/paszlib/src/zuncompr.pas
@@ -0,0 +1,89 @@
+unit zuncompr;
+
+{ uncompr.c -- decompress a memory buffer
+ Copyright (C) 1995-1998 Jean-loup Gailly.
+
+ Pascal tranlastion
+ Copyright (C) 1998 by Jacques Nomssi Nzali
+ For conditions of distribution and use, see copyright notice in readme.txt
+}
+
+interface
+
+{$I zconf.inc}
+
+uses
+ zbase, zinflate;
+
+{ ===========================================================================
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+ This function can be used to decompress a whole file at once if the
+ input file is mmap'ed.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted.
+}
+
+function uncompress (dest : Pbyte;
+ var destLen : cardinal;
+ const source : array of byte;
+ sourceLen : cardinal) : integer;
+
+implementation
+
+function uncompress (dest : Pbyte;
+ var destLen : cardinal;
+ const source : array of byte;
+ sourceLen : cardinal) : integer;
+var
+ stream : z_stream;
+ err : integer;
+begin
+ stream.next_in := Pbyte(@source);
+ stream.avail_in := cardinal(sourceLen);
+ { Check for source > 64K on 16-bit machine: }
+ if (cardinal(stream.avail_in) <> sourceLen) then
+ begin
+ uncompress := Z_BUF_ERROR;
+ exit;
+ end;
+
+ stream.next_out := dest;
+ stream.avail_out := cardinal(destLen);
+ if (cardinal(stream.avail_out) <> destLen) then
+ begin
+ uncompress := Z_BUF_ERROR;
+ exit;
+ end;
+
+ err := inflateInit(stream);
+ if (err <> Z_OK) then
+ begin
+ uncompress := err;
+ exit;
+ end;
+
+ err := inflate(stream, Z_FINISH);
+ if (err <> Z_STREAM_END) then
+ begin
+ inflateEnd(stream);
+ if err = Z_OK then
+ uncompress := Z_BUF_ERROR
+ else
+ uncompress := err;
+ exit;
+ end;
+ destLen := stream.total_out;
+
+ err := inflateEnd(stream);
+ uncompress := err;
+end;
+
+end. \ No newline at end of file