xref: /netbsd-src/common/dist/zlib/contrib/delphi/ZLib.pas (revision b175d1c2a0d8a7ee59df83b5ae5f0bd11632ced6)
1aaf4ece6Schristos {*******************************************************}
2aaf4ece6Schristos {                                                       }
3aaf4ece6Schristos {       Borland Delphi Supplemental Components          }
4aaf4ece6Schristos {       ZLIB Data Compression Interface Unit            }
5aaf4ece6Schristos {                                                       }
6aaf4ece6Schristos {       Copyright (c) 1997,99 Borland Corporation       }
7aaf4ece6Schristos {                                                       }
8aaf4ece6Schristos {*******************************************************}
9aaf4ece6Schristos 
10aaf4ece6Schristos { Updated for zlib 1.2.x by Cosmin Truta <cosmint@cs.ubbcluj.ro> }
11aaf4ece6Schristos 
12aaf4ece6Schristos unit ZLib;
13aaf4ece6Schristos 
14aaf4ece6Schristos interface
15aaf4ece6Schristos 
16aaf4ece6Schristos uses SysUtils, Classes;
17aaf4ece6Schristos 
18aaf4ece6Schristos type
19aaf4ece6Schristos   TAlloc = function (AppData: Pointer; Items, Size: Integer): Pointer; cdecl;
20aaf4ece6Schristos   TFree = procedure (AppData, Block: Pointer); cdecl;
21aaf4ece6Schristos 
22aaf4ece6Schristos   // Internal structure.  Ignore.
23aaf4ece6Schristos   TZStreamRec = packed record
24aaf4ece6Schristos     next_in: PChar;       // next input byte
25aaf4ece6Schristos     avail_in: Integer;    // number of bytes available at next_in
26aaf4ece6Schristos     total_in: Longint;    // total nb of input bytes read so far
27aaf4ece6Schristos 
28aaf4ece6Schristos     next_out: PChar;      // next output byte should be put here
29aaf4ece6Schristos     avail_out: Integer;   // remaining free space at next_out
30aaf4ece6Schristos     total_out: Longint;   // total nb of bytes output so far
31aaf4ece6Schristos 
32aaf4ece6Schristos     msg: PChar;           // last error message, NULL if no error
33aaf4ece6Schristos     internal: Pointer;    // not visible by applications
34aaf4ece6Schristos 
35aaf4ece6Schristos     zalloc: TAlloc;       // used to allocate the internal state
36aaf4ece6Schristos     zfree: TFree;         // used to free the internal state
37aaf4ece6Schristos     AppData: Pointer;     // private data object passed to zalloc and zfree
38aaf4ece6Schristos 
39aaf4ece6Schristos     data_type: Integer;   // best guess about the data type: ascii or binary
40aaf4ece6Schristos     adler: Longint;       // adler32 value of the uncompressed data
41aaf4ece6Schristos     reserved: Longint;    // reserved for future use
42aaf4ece6Schristos   end;
43aaf4ece6Schristos 
44aaf4ece6Schristos   // Abstract ancestor class
45aaf4ece6Schristos   TCustomZlibStream = class(TStream)
46aaf4ece6Schristos   private
47aaf4ece6Schristos     FStrm: TStream;
48aaf4ece6Schristos     FStrmPos: Integer;
49aaf4ece6Schristos     FOnProgress: TNotifyEvent;
50aaf4ece6Schristos     FZRec: TZStreamRec;
51aaf4ece6Schristos     FBuffer: array [Word] of Char;
52aaf4ece6Schristos   protected
53aaf4ece6Schristos     procedure Progress(Sender: TObject); dynamic;
54aaf4ece6Schristos     property OnProgress: TNotifyEvent read FOnProgress write FOnProgress;
55aaf4ece6Schristos     constructor Create(Strm: TStream);
56aaf4ece6Schristos   end;
57aaf4ece6Schristos 
58aaf4ece6Schristos { TCompressionStream compresses data on the fly as data is written to it, and
59aaf4ece6Schristos   stores the compressed data to another stream.
60aaf4ece6Schristos 
61aaf4ece6Schristos   TCompressionStream is write-only and strictly sequential. Reading from the
62aaf4ece6Schristos   stream will raise an exception. Using Seek to move the stream pointer
63aaf4ece6Schristos   will raise an exception.
64aaf4ece6Schristos 
65aaf4ece6Schristos   Output data is cached internally, written to the output stream only when
66aaf4ece6Schristos   the internal output buffer is full.  All pending output data is flushed
67aaf4ece6Schristos   when the stream is destroyed.
68aaf4ece6Schristos 
69aaf4ece6Schristos   The Position property returns the number of uncompressed bytes of
70aaf4ece6Schristos   data that have been written to the stream so far.
71aaf4ece6Schristos 
72aaf4ece6Schristos   CompressionRate returns the on-the-fly percentage by which the original
73aaf4ece6Schristos   data has been compressed:  (1 - (CompressedBytes / UncompressedBytes)) * 100
74aaf4ece6Schristos   If raw data size = 100 and compressed data size = 25, the CompressionRate
75aaf4ece6Schristos   is 75%
76aaf4ece6Schristos 
77aaf4ece6Schristos   The OnProgress event is called each time the output buffer is filled and
78aaf4ece6Schristos   written to the output stream.  This is useful for updating a progress
79aaf4ece6Schristos   indicator when you are writing a large chunk of data to the compression
80aaf4ece6Schristos   stream in a single call.}
81aaf4ece6Schristos 
82aaf4ece6Schristos 
83aaf4ece6Schristos   TCompressionLevel = (clNone, clFastest, clDefault, clMax);
84aaf4ece6Schristos 
85aaf4ece6Schristos   TCompressionStream = class(TCustomZlibStream)
86aaf4ece6Schristos   private
87aaf4ece6Schristos     function GetCompressionRate: Single;
88aaf4ece6Schristos   public
89aaf4ece6Schristos     constructor Create(CompressionLevel: TCompressionLevel; Dest: TStream);
90aaf4ece6Schristos     destructor Destroy; override;
91aaf4ece6Schristos     function Read(var Buffer; Count: Longint): Longint; override;
92aaf4ece6Schristos     function Write(const Buffer; Count: Longint): Longint; override;
93aaf4ece6Schristos     function Seek(Offset: Longint; Origin: Word): Longint; override;
94aaf4ece6Schristos     property CompressionRate: Single read GetCompressionRate;
95aaf4ece6Schristos     property OnProgress;
96aaf4ece6Schristos   end;
97aaf4ece6Schristos 
98aaf4ece6Schristos { TDecompressionStream decompresses data on the fly as data is read from it.
99aaf4ece6Schristos 
100aaf4ece6Schristos   Compressed data comes from a separate source stream.  TDecompressionStream
101aaf4ece6Schristos   is read-only and unidirectional; you can seek forward in the stream, but not
102aaf4ece6Schristos   backwards.  The special case of setting the stream position to zero is
103aaf4ece6Schristos   allowed.  Seeking forward decompresses data until the requested position in
104aaf4ece6Schristos   the uncompressed data has been reached.  Seeking backwards, seeking relative
105aaf4ece6Schristos   to the end of the stream, requesting the size of the stream, and writing to
106aaf4ece6Schristos   the stream will raise an exception.
107aaf4ece6Schristos 
108aaf4ece6Schristos   The Position property returns the number of bytes of uncompressed data that
109aaf4ece6Schristos   have been read from the stream so far.
110aaf4ece6Schristos 
111aaf4ece6Schristos   The OnProgress event is called each time the internal input buffer of
112aaf4ece6Schristos   compressed data is exhausted and the next block is read from the input stream.
113aaf4ece6Schristos   This is useful for updating a progress indicator when you are reading a
114aaf4ece6Schristos   large chunk of data from the decompression stream in a single call.}
115aaf4ece6Schristos 
116aaf4ece6Schristos   TDecompressionStream = class(TCustomZlibStream)
117aaf4ece6Schristos   public
118aaf4ece6Schristos     constructor Create(Source: TStream);
119aaf4ece6Schristos     destructor Destroy; override;
120aaf4ece6Schristos     function Read(var Buffer; Count: Longint): Longint; override;
121aaf4ece6Schristos     function Write(const Buffer; Count: Longint): Longint; override;
122aaf4ece6Schristos     function Seek(Offset: Longint; Origin: Word): Longint; override;
123aaf4ece6Schristos     property OnProgress;
124aaf4ece6Schristos   end;
125aaf4ece6Schristos 
126aaf4ece6Schristos 
127aaf4ece6Schristos 
128aaf4ece6Schristos { CompressBuf compresses data, buffer to buffer, in one call.
129aaf4ece6Schristos    In: InBuf = ptr to compressed data
130aaf4ece6Schristos        InBytes = number of bytes in InBuf
131aaf4ece6Schristos   Out: OutBuf = ptr to newly allocated buffer containing decompressed data
132aaf4ece6Schristos        OutBytes = number of bytes in OutBuf   }
133aaf4ece6Schristos procedure CompressBuf(const InBuf: Pointer; InBytes: Integer;
134aaf4ece6Schristos                       out OutBuf: Pointer; out OutBytes: Integer);
135aaf4ece6Schristos 
136aaf4ece6Schristos 
137aaf4ece6Schristos { DecompressBuf decompresses data, buffer to buffer, in one call.
138aaf4ece6Schristos    In: InBuf = ptr to compressed data
139aaf4ece6Schristos        InBytes = number of bytes in InBuf
140aaf4ece6Schristos        OutEstimate = zero, or est. size of the decompressed data
141aaf4ece6Schristos   Out: OutBuf = ptr to newly allocated buffer containing decompressed data
142aaf4ece6Schristos        OutBytes = number of bytes in OutBuf   }
143aaf4ece6Schristos procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer;
144aaf4ece6Schristos  OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer);
145aaf4ece6Schristos 
146aaf4ece6Schristos { DecompressToUserBuf decompresses data, buffer to buffer, in one call.
147aaf4ece6Schristos    In: InBuf = ptr to compressed data
148aaf4ece6Schristos        InBytes = number of bytes in InBuf
149aaf4ece6Schristos   Out: OutBuf = ptr to user-allocated buffer to contain decompressed data
150aaf4ece6Schristos        BufSize = number of bytes in OutBuf   }
151aaf4ece6Schristos procedure DecompressToUserBuf(const InBuf: Pointer; InBytes: Integer;
152aaf4ece6Schristos   const OutBuf: Pointer; BufSize: Integer);
153aaf4ece6Schristos 
154aaf4ece6Schristos const
155*b175d1c2Schristos   zlib_version = '1.3.1';
156aaf4ece6Schristos 
157aaf4ece6Schristos type
158aaf4ece6Schristos   EZlibError = class(Exception);
159aaf4ece6Schristos   ECompressionError = class(EZlibError);
160aaf4ece6Schristos   EDecompressionError = class(EZlibError);
161aaf4ece6Schristos 
162aaf4ece6Schristos implementation
163aaf4ece6Schristos 
164aaf4ece6Schristos uses ZLibConst;
165aaf4ece6Schristos 
166aaf4ece6Schristos const
167aaf4ece6Schristos   Z_NO_FLUSH      = 0;
168aaf4ece6Schristos   Z_PARTIAL_FLUSH = 1;
169aaf4ece6Schristos   Z_SYNC_FLUSH    = 2;
170aaf4ece6Schristos   Z_FULL_FLUSH    = 3;
171aaf4ece6Schristos   Z_FINISH        = 4;
172aaf4ece6Schristos 
173aaf4ece6Schristos   Z_OK            = 0;
174aaf4ece6Schristos   Z_STREAM_END    = 1;
175aaf4ece6Schristos   Z_NEED_DICT     = 2;
176aaf4ece6Schristos   Z_ERRNO         = (-1);
177aaf4ece6Schristos   Z_STREAM_ERROR  = (-2);
178aaf4ece6Schristos   Z_DATA_ERROR    = (-3);
179aaf4ece6Schristos   Z_MEM_ERROR     = (-4);
180aaf4ece6Schristos   Z_BUF_ERROR     = (-5);
181aaf4ece6Schristos   Z_VERSION_ERROR = (-6);
182aaf4ece6Schristos 
183aaf4ece6Schristos   Z_NO_COMPRESSION       =   0;
184aaf4ece6Schristos   Z_BEST_SPEED           =   1;
185aaf4ece6Schristos   Z_BEST_COMPRESSION     =   9;
186aaf4ece6Schristos   Z_DEFAULT_COMPRESSION  = (-1);
187aaf4ece6Schristos 
188aaf4ece6Schristos   Z_FILTERED            = 1;
189aaf4ece6Schristos   Z_HUFFMAN_ONLY        = 2;
190aaf4ece6Schristos   Z_RLE                 = 3;
191aaf4ece6Schristos   Z_DEFAULT_STRATEGY    = 0;
192aaf4ece6Schristos 
193aaf4ece6Schristos   Z_BINARY   = 0;
194aaf4ece6Schristos   Z_ASCII    = 1;
195aaf4ece6Schristos   Z_UNKNOWN  = 2;
196aaf4ece6Schristos 
197aaf4ece6Schristos   Z_DEFLATED = 8;
198aaf4ece6Schristos 
199aaf4ece6Schristos 
200aaf4ece6Schristos {$L adler32.obj}
201aaf4ece6Schristos {$L compress.obj}
202aaf4ece6Schristos {$L crc32.obj}
203aaf4ece6Schristos {$L deflate.obj}
204aaf4ece6Schristos {$L infback.obj}
205aaf4ece6Schristos {$L inffast.obj}
206aaf4ece6Schristos {$L inflate.obj}
207aaf4ece6Schristos {$L inftrees.obj}
208aaf4ece6Schristos {$L trees.obj}
209aaf4ece6Schristos {$L uncompr.obj}
210aaf4ece6Schristos {$L zutil.obj}
211aaf4ece6Schristos 
212aaf4ece6Schristos procedure adler32; external;
213aaf4ece6Schristos procedure compressBound; external;
214aaf4ece6Schristos procedure crc32; external;
215aaf4ece6Schristos procedure deflateInit2_; external;
216aaf4ece6Schristos procedure deflateParams; external;
217aaf4ece6Schristos 
218aaf4ece6Schristos function _malloc(Size: Integer): Pointer; cdecl;
219aaf4ece6Schristos begin
220aaf4ece6Schristos   Result := AllocMem(Size);
221aaf4ece6Schristos end;
222aaf4ece6Schristos 
223aaf4ece6Schristos procedure _free(Block: Pointer); cdecl;
224aaf4ece6Schristos begin
225aaf4ece6Schristos   FreeMem(Block);
226aaf4ece6Schristos end;
227aaf4ece6Schristos 
228aaf4ece6Schristos procedure _memset(P: Pointer; B: Byte; count: Integer); cdecl;
229aaf4ece6Schristos begin
230aaf4ece6Schristos   FillChar(P^, count, B);
231aaf4ece6Schristos end;
232aaf4ece6Schristos 
233aaf4ece6Schristos procedure _memcpy(dest, source: Pointer; count: Integer); cdecl;
234aaf4ece6Schristos begin
235aaf4ece6Schristos   Move(source^, dest^, count);
236aaf4ece6Schristos end;
237aaf4ece6Schristos 
238aaf4ece6Schristos 
239aaf4ece6Schristos 
240aaf4ece6Schristos // deflate compresses data
241aaf4ece6Schristos function deflateInit_(var strm: TZStreamRec; level: Integer; version: PChar;
242aaf4ece6Schristos   recsize: Integer): Integer; external;
243aaf4ece6Schristos function deflate(var strm: TZStreamRec; flush: Integer): Integer; external;
244aaf4ece6Schristos function deflateEnd(var strm: TZStreamRec): Integer; external;
245aaf4ece6Schristos 
246aaf4ece6Schristos // inflate decompresses data
247aaf4ece6Schristos function inflateInit_(var strm: TZStreamRec; version: PChar;
248aaf4ece6Schristos   recsize: Integer): Integer; external;
249aaf4ece6Schristos function inflate(var strm: TZStreamRec; flush: Integer): Integer; external;
250aaf4ece6Schristos function inflateEnd(var strm: TZStreamRec): Integer; external;
251aaf4ece6Schristos function inflateReset(var strm: TZStreamRec): Integer; external;
252aaf4ece6Schristos 
253aaf4ece6Schristos 
254aaf4ece6Schristos function zlibAllocMem(AppData: Pointer; Items, Size: Integer): Pointer; cdecl;
255aaf4ece6Schristos begin
256aaf4ece6Schristos //  GetMem(Result, Items*Size);
257aaf4ece6Schristos   Result := AllocMem(Items * Size);
258aaf4ece6Schristos end;
259aaf4ece6Schristos 
260aaf4ece6Schristos procedure zlibFreeMem(AppData, Block: Pointer); cdecl;
261aaf4ece6Schristos begin
262aaf4ece6Schristos   FreeMem(Block);
263aaf4ece6Schristos end;
264aaf4ece6Schristos 
265aaf4ece6Schristos {function zlibCheck(code: Integer): Integer;
266aaf4ece6Schristos begin
267aaf4ece6Schristos   Result := code;
268aaf4ece6Schristos   if code < 0 then
269aaf4ece6Schristos     raise EZlibError.Create('error');    //!!
270aaf4ece6Schristos end;}
271aaf4ece6Schristos 
272aaf4ece6Schristos function CCheck(code: Integer): Integer;
273aaf4ece6Schristos begin
274aaf4ece6Schristos   Result := code;
275aaf4ece6Schristos   if code < 0 then
276aaf4ece6Schristos     raise ECompressionError.Create('error'); //!!
277aaf4ece6Schristos end;
278aaf4ece6Schristos 
279aaf4ece6Schristos function DCheck(code: Integer): Integer;
280aaf4ece6Schristos begin
281aaf4ece6Schristos   Result := code;
282aaf4ece6Schristos   if code < 0 then
283aaf4ece6Schristos     raise EDecompressionError.Create('error');  //!!
284aaf4ece6Schristos end;
285aaf4ece6Schristos 
286aaf4ece6Schristos procedure CompressBuf(const InBuf: Pointer; InBytes: Integer;
287aaf4ece6Schristos                       out OutBuf: Pointer; out OutBytes: Integer);
288aaf4ece6Schristos var
289aaf4ece6Schristos   strm: TZStreamRec;
290aaf4ece6Schristos   P: Pointer;
291aaf4ece6Schristos begin
292aaf4ece6Schristos   FillChar(strm, sizeof(strm), 0);
293aaf4ece6Schristos   strm.zalloc := zlibAllocMem;
294aaf4ece6Schristos   strm.zfree := zlibFreeMem;
295aaf4ece6Schristos   OutBytes := ((InBytes + (InBytes div 10) + 12) + 255) and not 255;
296aaf4ece6Schristos   GetMem(OutBuf, OutBytes);
297aaf4ece6Schristos   try
298aaf4ece6Schristos     strm.next_in := InBuf;
299aaf4ece6Schristos     strm.avail_in := InBytes;
300aaf4ece6Schristos     strm.next_out := OutBuf;
301aaf4ece6Schristos     strm.avail_out := OutBytes;
302aaf4ece6Schristos     CCheck(deflateInit_(strm, Z_BEST_COMPRESSION, zlib_version, sizeof(strm)));
303aaf4ece6Schristos     try
304aaf4ece6Schristos       while CCheck(deflate(strm, Z_FINISH)) <> Z_STREAM_END do
305aaf4ece6Schristos       begin
306aaf4ece6Schristos         P := OutBuf;
307aaf4ece6Schristos         Inc(OutBytes, 256);
308aaf4ece6Schristos         ReallocMem(OutBuf, OutBytes);
309aaf4ece6Schristos         strm.next_out := PChar(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P)));
310aaf4ece6Schristos         strm.avail_out := 256;
311aaf4ece6Schristos       end;
312aaf4ece6Schristos     finally
313aaf4ece6Schristos       CCheck(deflateEnd(strm));
314aaf4ece6Schristos     end;
315aaf4ece6Schristos     ReallocMem(OutBuf, strm.total_out);
316aaf4ece6Schristos     OutBytes := strm.total_out;
317aaf4ece6Schristos   except
318aaf4ece6Schristos     FreeMem(OutBuf);
319aaf4ece6Schristos     raise
320aaf4ece6Schristos   end;
321aaf4ece6Schristos end;
322aaf4ece6Schristos 
323aaf4ece6Schristos 
324aaf4ece6Schristos procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer;
325aaf4ece6Schristos   OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer);
326aaf4ece6Schristos var
327aaf4ece6Schristos   strm: TZStreamRec;
328aaf4ece6Schristos   P: Pointer;
329aaf4ece6Schristos   BufInc: Integer;
330aaf4ece6Schristos begin
331aaf4ece6Schristos   FillChar(strm, sizeof(strm), 0);
332aaf4ece6Schristos   strm.zalloc := zlibAllocMem;
333aaf4ece6Schristos   strm.zfree := zlibFreeMem;
334aaf4ece6Schristos   BufInc := (InBytes + 255) and not 255;
335aaf4ece6Schristos   if OutEstimate = 0 then
336aaf4ece6Schristos     OutBytes := BufInc
337aaf4ece6Schristos   else
338aaf4ece6Schristos     OutBytes := OutEstimate;
339aaf4ece6Schristos   GetMem(OutBuf, OutBytes);
340aaf4ece6Schristos   try
341aaf4ece6Schristos     strm.next_in := InBuf;
342aaf4ece6Schristos     strm.avail_in := InBytes;
343aaf4ece6Schristos     strm.next_out := OutBuf;
344aaf4ece6Schristos     strm.avail_out := OutBytes;
345aaf4ece6Schristos     DCheck(inflateInit_(strm, zlib_version, sizeof(strm)));
346aaf4ece6Schristos     try
347aaf4ece6Schristos       while DCheck(inflate(strm, Z_NO_FLUSH)) <> Z_STREAM_END do
348aaf4ece6Schristos       begin
349aaf4ece6Schristos         P := OutBuf;
350aaf4ece6Schristos         Inc(OutBytes, BufInc);
351aaf4ece6Schristos         ReallocMem(OutBuf, OutBytes);
352aaf4ece6Schristos         strm.next_out := PChar(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P)));
353aaf4ece6Schristos         strm.avail_out := BufInc;
354aaf4ece6Schristos       end;
355aaf4ece6Schristos     finally
356aaf4ece6Schristos       DCheck(inflateEnd(strm));
357aaf4ece6Schristos     end;
358aaf4ece6Schristos     ReallocMem(OutBuf, strm.total_out);
359aaf4ece6Schristos     OutBytes := strm.total_out;
360aaf4ece6Schristos   except
361aaf4ece6Schristos     FreeMem(OutBuf);
362aaf4ece6Schristos     raise
363aaf4ece6Schristos   end;
364aaf4ece6Schristos end;
365aaf4ece6Schristos 
366aaf4ece6Schristos procedure DecompressToUserBuf(const InBuf: Pointer; InBytes: Integer;
367aaf4ece6Schristos   const OutBuf: Pointer; BufSize: Integer);
368aaf4ece6Schristos var
369aaf4ece6Schristos   strm: TZStreamRec;
370aaf4ece6Schristos begin
371aaf4ece6Schristos   FillChar(strm, sizeof(strm), 0);
372aaf4ece6Schristos   strm.zalloc := zlibAllocMem;
373aaf4ece6Schristos   strm.zfree := zlibFreeMem;
374aaf4ece6Schristos   strm.next_in := InBuf;
375aaf4ece6Schristos   strm.avail_in := InBytes;
376aaf4ece6Schristos   strm.next_out := OutBuf;
377aaf4ece6Schristos   strm.avail_out := BufSize;
378aaf4ece6Schristos   DCheck(inflateInit_(strm, zlib_version, sizeof(strm)));
379aaf4ece6Schristos   try
380aaf4ece6Schristos     if DCheck(inflate(strm, Z_FINISH)) <> Z_STREAM_END then
381aaf4ece6Schristos       raise EZlibError.CreateRes(@sTargetBufferTooSmall);
382aaf4ece6Schristos   finally
383aaf4ece6Schristos     DCheck(inflateEnd(strm));
384aaf4ece6Schristos   end;
385aaf4ece6Schristos end;
386aaf4ece6Schristos 
387aaf4ece6Schristos // TCustomZlibStream
388aaf4ece6Schristos 
389aaf4ece6Schristos constructor TCustomZLibStream.Create(Strm: TStream);
390aaf4ece6Schristos begin
391aaf4ece6Schristos   inherited Create;
392aaf4ece6Schristos   FStrm := Strm;
393aaf4ece6Schristos   FStrmPos := Strm.Position;
394aaf4ece6Schristos   FZRec.zalloc := zlibAllocMem;
395aaf4ece6Schristos   FZRec.zfree := zlibFreeMem;
396aaf4ece6Schristos end;
397aaf4ece6Schristos 
398aaf4ece6Schristos procedure TCustomZLibStream.Progress(Sender: TObject);
399aaf4ece6Schristos begin
400aaf4ece6Schristos   if Assigned(FOnProgress) then FOnProgress(Sender);
401aaf4ece6Schristos end;
402aaf4ece6Schristos 
403aaf4ece6Schristos 
404aaf4ece6Schristos // TCompressionStream
405aaf4ece6Schristos 
406aaf4ece6Schristos constructor TCompressionStream.Create(CompressionLevel: TCompressionLevel;
407aaf4ece6Schristos   Dest: TStream);
408aaf4ece6Schristos const
409aaf4ece6Schristos   Levels: array [TCompressionLevel] of ShortInt =
410aaf4ece6Schristos     (Z_NO_COMPRESSION, Z_BEST_SPEED, Z_DEFAULT_COMPRESSION, Z_BEST_COMPRESSION);
411aaf4ece6Schristos begin
412aaf4ece6Schristos   inherited Create(Dest);
413aaf4ece6Schristos   FZRec.next_out := FBuffer;
414aaf4ece6Schristos   FZRec.avail_out := sizeof(FBuffer);
415aaf4ece6Schristos   CCheck(deflateInit_(FZRec, Levels[CompressionLevel], zlib_version, sizeof(FZRec)));
416aaf4ece6Schristos end;
417aaf4ece6Schristos 
418aaf4ece6Schristos destructor TCompressionStream.Destroy;
419aaf4ece6Schristos begin
420aaf4ece6Schristos   FZRec.next_in := nil;
421aaf4ece6Schristos   FZRec.avail_in := 0;
422aaf4ece6Schristos   try
423aaf4ece6Schristos     if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos;
424aaf4ece6Schristos     while (CCheck(deflate(FZRec, Z_FINISH)) <> Z_STREAM_END)
425aaf4ece6Schristos       and (FZRec.avail_out = 0) do
426aaf4ece6Schristos     begin
427aaf4ece6Schristos       FStrm.WriteBuffer(FBuffer, sizeof(FBuffer));
428aaf4ece6Schristos       FZRec.next_out := FBuffer;
429aaf4ece6Schristos       FZRec.avail_out := sizeof(FBuffer);
430aaf4ece6Schristos     end;
431aaf4ece6Schristos     if FZRec.avail_out < sizeof(FBuffer) then
432aaf4ece6Schristos       FStrm.WriteBuffer(FBuffer, sizeof(FBuffer) - FZRec.avail_out);
433aaf4ece6Schristos   finally
434aaf4ece6Schristos     deflateEnd(FZRec);
435aaf4ece6Schristos   end;
436aaf4ece6Schristos   inherited Destroy;
437aaf4ece6Schristos end;
438aaf4ece6Schristos 
439aaf4ece6Schristos function TCompressionStream.Read(var Buffer; Count: Longint): Longint;
440aaf4ece6Schristos begin
441aaf4ece6Schristos   raise ECompressionError.CreateRes(@sInvalidStreamOp);
442aaf4ece6Schristos end;
443aaf4ece6Schristos 
444aaf4ece6Schristos function TCompressionStream.Write(const Buffer; Count: Longint): Longint;
445aaf4ece6Schristos begin
446aaf4ece6Schristos   FZRec.next_in := @Buffer;
447aaf4ece6Schristos   FZRec.avail_in := Count;
448aaf4ece6Schristos   if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos;
449aaf4ece6Schristos   while (FZRec.avail_in > 0) do
450aaf4ece6Schristos   begin
451aaf4ece6Schristos     CCheck(deflate(FZRec, 0));
452aaf4ece6Schristos     if FZRec.avail_out = 0 then
453aaf4ece6Schristos     begin
454aaf4ece6Schristos       FStrm.WriteBuffer(FBuffer, sizeof(FBuffer));
455aaf4ece6Schristos       FZRec.next_out := FBuffer;
456aaf4ece6Schristos       FZRec.avail_out := sizeof(FBuffer);
457aaf4ece6Schristos       FStrmPos := FStrm.Position;
458aaf4ece6Schristos       Progress(Self);
459aaf4ece6Schristos     end;
460aaf4ece6Schristos   end;
461aaf4ece6Schristos   Result := Count;
462aaf4ece6Schristos end;
463aaf4ece6Schristos 
464aaf4ece6Schristos function TCompressionStream.Seek(Offset: Longint; Origin: Word): Longint;
465aaf4ece6Schristos begin
466aaf4ece6Schristos   if (Offset = 0) and (Origin = soFromCurrent) then
467aaf4ece6Schristos     Result := FZRec.total_in
468aaf4ece6Schristos   else
469aaf4ece6Schristos     raise ECompressionError.CreateRes(@sInvalidStreamOp);
470aaf4ece6Schristos end;
471aaf4ece6Schristos 
472aaf4ece6Schristos function TCompressionStream.GetCompressionRate: Single;
473aaf4ece6Schristos begin
474aaf4ece6Schristos   if FZRec.total_in = 0 then
475aaf4ece6Schristos     Result := 0
476aaf4ece6Schristos   else
477aaf4ece6Schristos     Result := (1.0 - (FZRec.total_out / FZRec.total_in)) * 100.0;
478aaf4ece6Schristos end;
479aaf4ece6Schristos 
480aaf4ece6Schristos 
481aaf4ece6Schristos // TDecompressionStream
482aaf4ece6Schristos 
483aaf4ece6Schristos constructor TDecompressionStream.Create(Source: TStream);
484aaf4ece6Schristos begin
485aaf4ece6Schristos   inherited Create(Source);
486aaf4ece6Schristos   FZRec.next_in := FBuffer;
487aaf4ece6Schristos   FZRec.avail_in := 0;
488aaf4ece6Schristos   DCheck(inflateInit_(FZRec, zlib_version, sizeof(FZRec)));
489aaf4ece6Schristos end;
490aaf4ece6Schristos 
491aaf4ece6Schristos destructor TDecompressionStream.Destroy;
492aaf4ece6Schristos begin
493aaf4ece6Schristos   FStrm.Seek(-FZRec.avail_in, 1);
494aaf4ece6Schristos   inflateEnd(FZRec);
495aaf4ece6Schristos   inherited Destroy;
496aaf4ece6Schristos end;
497aaf4ece6Schristos 
498aaf4ece6Schristos function TDecompressionStream.Read(var Buffer; Count: Longint): Longint;
499aaf4ece6Schristos begin
500aaf4ece6Schristos   FZRec.next_out := @Buffer;
501aaf4ece6Schristos   FZRec.avail_out := Count;
502aaf4ece6Schristos   if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos;
503aaf4ece6Schristos   while (FZRec.avail_out > 0) do
504aaf4ece6Schristos   begin
505aaf4ece6Schristos     if FZRec.avail_in = 0 then
506aaf4ece6Schristos     begin
507aaf4ece6Schristos       FZRec.avail_in := FStrm.Read(FBuffer, sizeof(FBuffer));
508aaf4ece6Schristos       if FZRec.avail_in = 0 then
509aaf4ece6Schristos       begin
510aaf4ece6Schristos         Result := Count - FZRec.avail_out;
511aaf4ece6Schristos         Exit;
512aaf4ece6Schristos       end;
513aaf4ece6Schristos       FZRec.next_in := FBuffer;
514aaf4ece6Schristos       FStrmPos := FStrm.Position;
515aaf4ece6Schristos       Progress(Self);
516aaf4ece6Schristos     end;
517aaf4ece6Schristos     CCheck(inflate(FZRec, 0));
518aaf4ece6Schristos   end;
519aaf4ece6Schristos   Result := Count;
520aaf4ece6Schristos end;
521aaf4ece6Schristos 
522aaf4ece6Schristos function TDecompressionStream.Write(const Buffer; Count: Longint): Longint;
523aaf4ece6Schristos begin
524aaf4ece6Schristos   raise EDecompressionError.CreateRes(@sInvalidStreamOp);
525aaf4ece6Schristos end;
526aaf4ece6Schristos 
527aaf4ece6Schristos function TDecompressionStream.Seek(Offset: Longint; Origin: Word): Longint;
528aaf4ece6Schristos var
529aaf4ece6Schristos   I: Integer;
530aaf4ece6Schristos   Buf: array [0..4095] of Char;
531aaf4ece6Schristos begin
532aaf4ece6Schristos   if (Offset = 0) and (Origin = soFromBeginning) then
533aaf4ece6Schristos   begin
534aaf4ece6Schristos     DCheck(inflateReset(FZRec));
535aaf4ece6Schristos     FZRec.next_in := FBuffer;
536aaf4ece6Schristos     FZRec.avail_in := 0;
537aaf4ece6Schristos     FStrm.Position := 0;
538aaf4ece6Schristos     FStrmPos := 0;
539aaf4ece6Schristos   end
540aaf4ece6Schristos   else if ( (Offset >= 0) and (Origin = soFromCurrent)) or
541aaf4ece6Schristos           ( ((Offset - FZRec.total_out) > 0) and (Origin = soFromBeginning)) then
542aaf4ece6Schristos   begin
543aaf4ece6Schristos     if Origin = soFromBeginning then Dec(Offset, FZRec.total_out);
544aaf4ece6Schristos     if Offset > 0 then
545aaf4ece6Schristos     begin
546aaf4ece6Schristos       for I := 1 to Offset div sizeof(Buf) do
547aaf4ece6Schristos         ReadBuffer(Buf, sizeof(Buf));
548aaf4ece6Schristos       ReadBuffer(Buf, Offset mod sizeof(Buf));
549aaf4ece6Schristos     end;
550aaf4ece6Schristos   end
551aaf4ece6Schristos   else
552aaf4ece6Schristos     raise EDecompressionError.CreateRes(@sInvalidStreamOp);
553aaf4ece6Schristos   Result := FZRec.total_out;
554aaf4ece6Schristos end;
555aaf4ece6Schristos 
556aaf4ece6Schristos 
557aaf4ece6Schristos end.
558