1212397c6Schristos {*******************************************************}
2212397c6Schristos { }
3212397c6Schristos { Borland Delphi Supplemental Components }
4212397c6Schristos { ZLIB Data Compression Interface Unit }
5212397c6Schristos { }
6212397c6Schristos { Copyright (c) 1997,99 Borland Corporation }
7212397c6Schristos { }
8212397c6Schristos {*******************************************************}
9212397c6Schristos
10212397c6Schristos { Updated for zlib 1.2.x by Cosmin Truta <cosmint@cs.ubbcluj.ro> }
11212397c6Schristos
12212397c6Schristos unit ZLib;
13212397c6Schristos
14212397c6Schristos interface
15212397c6Schristos
16212397c6Schristos uses SysUtils, Classes;
17212397c6Schristos
18212397c6Schristos type
ppData()19212397c6Schristos TAlloc = function (AppData: Pointer; Items, Size: Integer): Pointer; cdecl;
20212397c6Schristos TFree = procedure (AppData, Block: Pointer); cdecl;
21212397c6Schristos
22212397c6Schristos // Internal structure. Ignore.
23212397c6Schristos TZStreamRec = packed record
24212397c6Schristos next_in: PChar; // next input byte
25212397c6Schristos avail_in: Integer; // number of bytes available at next_in
26212397c6Schristos total_in: Longint; // total nb of input bytes read so far
27212397c6Schristos
28212397c6Schristos next_out: PChar; // next output byte should be put here
29212397c6Schristos avail_out: Integer; // remaining free space at next_out
30212397c6Schristos total_out: Longint; // total nb of bytes output so far
31212397c6Schristos
32212397c6Schristos msg: PChar; // last error message, NULL if no error
33212397c6Schristos internal: Pointer; // not visible by applications
34212397c6Schristos
35212397c6Schristos zalloc: TAlloc; // used to allocate the internal state
36212397c6Schristos zfree: TFree; // used to free the internal state
37212397c6Schristos AppData: Pointer; // private data object passed to zalloc and zfree
38212397c6Schristos
39212397c6Schristos data_type: Integer; // best guess about the data type: ascii or binary
40212397c6Schristos adler: Longint; // adler32 value of the uncompressed data
41212397c6Schristos reserved: Longint; // reserved for future use
42212397c6Schristos end;
43212397c6Schristos
44212397c6Schristos // Abstract ancestor class
45212397c6Schristos TCustomZlibStream = class(TStream)
46212397c6Schristos private
47212397c6Schristos FStrm: TStream;
48212397c6Schristos FStrmPos: Integer;
49212397c6Schristos FOnProgress: TNotifyEvent;
50212397c6Schristos FZRec: TZStreamRec;
51212397c6Schristos FBuffer: array [Word] of Char;
52212397c6Schristos protected
53212397c6Schristos procedure Progress(Sender: TObject); dynamic;
54212397c6Schristos property OnProgress: TNotifyEvent read FOnProgress write FOnProgress;
55212397c6Schristos constructor Create(Strm: TStream);
56212397c6Schristos end;
57212397c6Schristos
58212397c6Schristos { TCompressionStream compresses data on the fly as data is written to it, and
59212397c6Schristos stores the compressed data to another stream.
60212397c6Schristos
61212397c6Schristos TCompressionStream is write-only and strictly sequential. Reading from the
62212397c6Schristos stream will raise an exception. Using Seek to move the stream pointer
63212397c6Schristos will raise an exception.
64212397c6Schristos
65212397c6Schristos Output data is cached internally, written to the output stream only when
66212397c6Schristos the internal output buffer is full. All pending output data is flushed
67212397c6Schristos when the stream is destroyed.
68212397c6Schristos
69212397c6Schristos The Position property returns the number of uncompressed bytes of
70212397c6Schristos data that have been written to the stream so far.
71212397c6Schristos
72212397c6Schristos CompressionRate returns the on-the-fly percentage by which the original
73212397c6Schristos data has been compressed: (1 - (CompressedBytes / UncompressedBytes)) * 100
74212397c6Schristos If raw data size = 100 and compressed data size = 25, the CompressionRate
75212397c6Schristos is 75%
76212397c6Schristos
77212397c6Schristos The OnProgress event is called each time the output buffer is filled and
78212397c6Schristos written to the output stream. This is useful for updating a progress
79212397c6Schristos indicator when you are writing a large chunk of data to the compression
80212397c6Schristos stream in a single call.}
81212397c6Schristos
82212397c6Schristos
83212397c6Schristos TCompressionLevel = (clNone, clFastest, clDefault, clMax);
84212397c6Schristos
85212397c6Schristos TCompressionStream = class(TCustomZlibStream)
86212397c6Schristos private
GetCompressionRate()87212397c6Schristos function GetCompressionRate: Single;
88212397c6Schristos public
89212397c6Schristos constructor Create(CompressionLevel: TCompressionLevel; Dest: TStream);
90212397c6Schristos destructor Destroy; override;
Read(var Buffer; Count: Longint)91212397c6Schristos function Read(var Buffer; Count: Longint): Longint; override;
Write(const Buffer; Count: Longint)92212397c6Schristos function Write(const Buffer; Count: Longint): Longint; override;
Seek(Offset: Longint; Origin: Word)93212397c6Schristos function Seek(Offset: Longint; Origin: Word): Longint; override;
94212397c6Schristos property CompressionRate: Single read GetCompressionRate;
95212397c6Schristos property OnProgress;
96212397c6Schristos end;
97212397c6Schristos
98212397c6Schristos { TDecompressionStream decompresses data on the fly as data is read from it.
99212397c6Schristos
100212397c6Schristos Compressed data comes from a separate source stream. TDecompressionStream
101212397c6Schristos is read-only and unidirectional; you can seek forward in the stream, but not
102212397c6Schristos backwards. The special case of setting the stream position to zero is
103212397c6Schristos allowed. Seeking forward decompresses data until the requested position in
104212397c6Schristos the uncompressed data has been reached. Seeking backwards, seeking relative
105212397c6Schristos to the end of the stream, requesting the size of the stream, and writing to
106212397c6Schristos the stream will raise an exception.
107212397c6Schristos
108212397c6Schristos The Position property returns the number of bytes of uncompressed data that
109212397c6Schristos have been read from the stream so far.
110212397c6Schristos
111212397c6Schristos The OnProgress event is called each time the internal input buffer of
112212397c6Schristos compressed data is exhausted and the next block is read from the input stream.
113212397c6Schristos This is useful for updating a progress indicator when you are reading a
114212397c6Schristos large chunk of data from the decompression stream in a single call.}
115212397c6Schristos
116212397c6Schristos TDecompressionStream = class(TCustomZlibStream)
117212397c6Schristos public
118212397c6Schristos constructor Create(Source: TStream);
119212397c6Schristos destructor Destroy; override;
Read(var Buffer; Count: Longint)120212397c6Schristos function Read(var Buffer; Count: Longint): Longint; override;
Write(const Buffer; Count: Longint)121212397c6Schristos function Write(const Buffer; Count: Longint): Longint; override;
Seek(Offset: Longint; Origin: Word)122212397c6Schristos function Seek(Offset: Longint; Origin: Word): Longint; override;
123212397c6Schristos property OnProgress;
124212397c6Schristos end;
125212397c6Schristos
126212397c6Schristos
127212397c6Schristos
128212397c6Schristos { CompressBuf compresses data, buffer to buffer, in one call.
129212397c6Schristos In: InBuf = ptr to compressed data
130212397c6Schristos InBytes = number of bytes in InBuf
131212397c6Schristos Out: OutBuf = ptr to newly allocated buffer containing decompressed data
132212397c6Schristos OutBytes = number of bytes in OutBuf }
133212397c6Schristos procedure CompressBuf(const InBuf: Pointer; InBytes: Integer;
134212397c6Schristos out OutBuf: Pointer; out OutBytes: Integer);
135212397c6Schristos
136212397c6Schristos
137212397c6Schristos { DecompressBuf decompresses data, buffer to buffer, in one call.
138212397c6Schristos In: InBuf = ptr to compressed data
139212397c6Schristos InBytes = number of bytes in InBuf
140212397c6Schristos OutEstimate = zero, or est. size of the decompressed data
141212397c6Schristos Out: OutBuf = ptr to newly allocated buffer containing decompressed data
142212397c6Schristos OutBytes = number of bytes in OutBuf }
143212397c6Schristos procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer;
144212397c6Schristos OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer);
145212397c6Schristos
146212397c6Schristos { DecompressToUserBuf decompresses data, buffer to buffer, in one call.
147212397c6Schristos In: InBuf = ptr to compressed data
148212397c6Schristos InBytes = number of bytes in InBuf
149212397c6Schristos Out: OutBuf = ptr to user-allocated buffer to contain decompressed data
150212397c6Schristos BufSize = number of bytes in OutBuf }
151212397c6Schristos procedure DecompressToUserBuf(const InBuf: Pointer; InBytes: Integer;
152212397c6Schristos const OutBuf: Pointer; BufSize: Integer);
153212397c6Schristos
154212397c6Schristos const
155*4b169a6bSchristos zlib_version = '1.2.12';
156212397c6Schristos
157212397c6Schristos type
158212397c6Schristos EZlibError = class(Exception);
159212397c6Schristos ECompressionError = class(EZlibError);
160212397c6Schristos EDecompressionError = class(EZlibError);
161212397c6Schristos
162212397c6Schristos implementation
163212397c6Schristos
164212397c6Schristos uses ZLibConst;
165212397c6Schristos
166212397c6Schristos const
167212397c6Schristos Z_NO_FLUSH = 0;
168212397c6Schristos Z_PARTIAL_FLUSH = 1;
169212397c6Schristos Z_SYNC_FLUSH = 2;
170212397c6Schristos Z_FULL_FLUSH = 3;
171212397c6Schristos Z_FINISH = 4;
172212397c6Schristos
173212397c6Schristos Z_OK = 0;
174212397c6Schristos Z_STREAM_END = 1;
175212397c6Schristos Z_NEED_DICT = 2;
176212397c6Schristos Z_ERRNO = (-1);
177212397c6Schristos Z_STREAM_ERROR = (-2);
178212397c6Schristos Z_DATA_ERROR = (-3);
179212397c6Schristos Z_MEM_ERROR = (-4);
180212397c6Schristos Z_BUF_ERROR = (-5);
181212397c6Schristos Z_VERSION_ERROR = (-6);
182212397c6Schristos
183212397c6Schristos Z_NO_COMPRESSION = 0;
184212397c6Schristos Z_BEST_SPEED = 1;
185212397c6Schristos Z_BEST_COMPRESSION = 9;
186212397c6Schristos Z_DEFAULT_COMPRESSION = (-1);
187212397c6Schristos
188212397c6Schristos Z_FILTERED = 1;
189212397c6Schristos Z_HUFFMAN_ONLY = 2;
190212397c6Schristos Z_RLE = 3;
191212397c6Schristos Z_DEFAULT_STRATEGY = 0;
192212397c6Schristos
193212397c6Schristos Z_BINARY = 0;
194212397c6Schristos Z_ASCII = 1;
195212397c6Schristos Z_UNKNOWN = 2;
196212397c6Schristos
197212397c6Schristos Z_DEFLATED = 8;
198212397c6Schristos
199212397c6Schristos
200212397c6Schristos {$L adler32.obj}
201212397c6Schristos {$L compress.obj}
202212397c6Schristos {$L crc32.obj}
203212397c6Schristos {$L deflate.obj}
204212397c6Schristos {$L infback.obj}
205212397c6Schristos {$L inffast.obj}
206212397c6Schristos {$L inflate.obj}
207212397c6Schristos {$L inftrees.obj}
208212397c6Schristos {$L trees.obj}
209212397c6Schristos {$L uncompr.obj}
210212397c6Schristos {$L zutil.obj}
211212397c6Schristos
212212397c6Schristos procedure adler32; external;
213212397c6Schristos procedure compressBound; external;
214212397c6Schristos procedure crc32; external;
215212397c6Schristos procedure deflateInit2_; external;
216212397c6Schristos procedure deflateParams; external;
217212397c6Schristos
_malloc(Size: Integer)218212397c6Schristos function _malloc(Size: Integer): Pointer; cdecl;
219212397c6Schristos begin
220212397c6Schristos Result := AllocMem(Size);
221212397c6Schristos end;
222212397c6Schristos
223212397c6Schristos procedure _free(Block: Pointer); cdecl;
224212397c6Schristos begin
225212397c6Schristos FreeMem(Block);
226212397c6Schristos end;
227212397c6Schristos
228212397c6Schristos procedure _memset(P: Pointer; B: Byte; count: Integer); cdecl;
229212397c6Schristos begin
230212397c6Schristos FillChar(P^, count, B);
231212397c6Schristos end;
232212397c6Schristos
233212397c6Schristos procedure _memcpy(dest, source: Pointer; count: Integer); cdecl;
234212397c6Schristos begin
235212397c6Schristos Move(source^, dest^, count);
236212397c6Schristos end;
237212397c6Schristos
238212397c6Schristos
239212397c6Schristos
240212397c6Schristos // deflate compresses data
deflateInit_(var strm: TZStreamRec; level: Integer; version: PChar;241212397c6Schristos function deflateInit_(var strm: TZStreamRec; level: Integer; version: PChar;
242212397c6Schristos recsize: Integer): Integer; external;
deflate(var strm: TZStreamRec; flush: Integer)243212397c6Schristos function deflate(var strm: TZStreamRec; flush: Integer): Integer; external;
deflateEnd(var strm: TZStreamRec)244212397c6Schristos function deflateEnd(var strm: TZStreamRec): Integer; external;
245212397c6Schristos
246212397c6Schristos // inflate decompresses data
inflateInit_(var strm: TZStreamRec; version: PChar;247212397c6Schristos function inflateInit_(var strm: TZStreamRec; version: PChar;
248212397c6Schristos recsize: Integer): Integer; external;
inflate(var strm: TZStreamRec; flush: Integer)249212397c6Schristos function inflate(var strm: TZStreamRec; flush: Integer): Integer; external;
inflateEnd(var strm: TZStreamRec)250212397c6Schristos function inflateEnd(var strm: TZStreamRec): Integer; external;
inflateReset(var strm: TZStreamRec)251212397c6Schristos function inflateReset(var strm: TZStreamRec): Integer; external;
252212397c6Schristos
253212397c6Schristos
zlibAllocMem(AppData: Pointer; Items, Size: Integer)254212397c6Schristos function zlibAllocMem(AppData: Pointer; Items, Size: Integer): Pointer; cdecl;
255212397c6Schristos begin
256212397c6Schristos // GetMem(Result, Items*Size);
257212397c6Schristos Result := AllocMem(Items * Size);
258212397c6Schristos end;
259212397c6Schristos
260212397c6Schristos procedure zlibFreeMem(AppData, Block: Pointer); cdecl;
261212397c6Schristos begin
262212397c6Schristos FreeMem(Block);
263212397c6Schristos end;
264212397c6Schristos
265212397c6Schristos {function zlibCheck(code: Integer): Integer;
266212397c6Schristos begin
267212397c6Schristos Result := code;
268212397c6Schristos if code < 0 then
269212397c6Schristos raise EZlibError.Create('error'); //!!
270212397c6Schristos end;}
271212397c6Schristos
CCheck(code: Integer)272212397c6Schristos function CCheck(code: Integer): Integer;
273212397c6Schristos begin
274212397c6Schristos Result := code;
275212397c6Schristos if code < 0 then
276212397c6Schristos raise ECompressionError.Create('error'); //!!
277212397c6Schristos end;
278212397c6Schristos
DCheck(code: Integer)279212397c6Schristos function DCheck(code: Integer): Integer;
280212397c6Schristos begin
281212397c6Schristos Result := code;
282212397c6Schristos if code < 0 then
283212397c6Schristos raise EDecompressionError.Create('error'); //!!
284212397c6Schristos end;
285212397c6Schristos
286212397c6Schristos procedure CompressBuf(const InBuf: Pointer; InBytes: Integer;
287212397c6Schristos out OutBuf: Pointer; out OutBytes: Integer);
288212397c6Schristos var
289212397c6Schristos strm: TZStreamRec;
290212397c6Schristos P: Pointer;
291212397c6Schristos begin
292212397c6Schristos FillChar(strm, sizeof(strm), 0);
293212397c6Schristos strm.zalloc := zlibAllocMem;
294212397c6Schristos strm.zfree := zlibFreeMem;
295212397c6Schristos OutBytes := ((InBytes + (InBytes div 10) + 12) + 255) and not 255;
296212397c6Schristos GetMem(OutBuf, OutBytes);
297212397c6Schristos try
298212397c6Schristos strm.next_in := InBuf;
299212397c6Schristos strm.avail_in := InBytes;
300212397c6Schristos strm.next_out := OutBuf;
301212397c6Schristos strm.avail_out := OutBytes;
302212397c6Schristos CCheck(deflateInit_(strm, Z_BEST_COMPRESSION, zlib_version, sizeof(strm)));
303212397c6Schristos try
304212397c6Schristos while CCheck(deflate(strm, Z_FINISH)) <> Z_STREAM_END do
305212397c6Schristos begin
306212397c6Schristos P := OutBuf;
307212397c6Schristos Inc(OutBytes, 256);
308212397c6Schristos ReallocMem(OutBuf, OutBytes);
309212397c6Schristos strm.next_out := PChar(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P)));
310212397c6Schristos strm.avail_out := 256;
311212397c6Schristos end;
312212397c6Schristos finally
313212397c6Schristos CCheck(deflateEnd(strm));
314212397c6Schristos end;
315212397c6Schristos ReallocMem(OutBuf, strm.total_out);
316212397c6Schristos OutBytes := strm.total_out;
317212397c6Schristos except
318212397c6Schristos FreeMem(OutBuf);
319212397c6Schristos raise
320212397c6Schristos end;
321212397c6Schristos end;
322212397c6Schristos
323212397c6Schristos
324212397c6Schristos procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer;
325212397c6Schristos OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer);
326212397c6Schristos var
327212397c6Schristos strm: TZStreamRec;
328212397c6Schristos P: Pointer;
329212397c6Schristos BufInc: Integer;
330212397c6Schristos begin
331212397c6Schristos FillChar(strm, sizeof(strm), 0);
332212397c6Schristos strm.zalloc := zlibAllocMem;
333212397c6Schristos strm.zfree := zlibFreeMem;
334212397c6Schristos BufInc := (InBytes + 255) and not 255;
335212397c6Schristos if OutEstimate = 0 then
336212397c6Schristos OutBytes := BufInc
337212397c6Schristos else
338212397c6Schristos OutBytes := OutEstimate;
339212397c6Schristos GetMem(OutBuf, OutBytes);
340212397c6Schristos try
341212397c6Schristos strm.next_in := InBuf;
342212397c6Schristos strm.avail_in := InBytes;
343212397c6Schristos strm.next_out := OutBuf;
344212397c6Schristos strm.avail_out := OutBytes;
345212397c6Schristos DCheck(inflateInit_(strm, zlib_version, sizeof(strm)));
346212397c6Schristos try
347212397c6Schristos while DCheck(inflate(strm, Z_NO_FLUSH)) <> Z_STREAM_END do
348212397c6Schristos begin
349212397c6Schristos P := OutBuf;
350212397c6Schristos Inc(OutBytes, BufInc);
351212397c6Schristos ReallocMem(OutBuf, OutBytes);
352212397c6Schristos strm.next_out := PChar(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P)));
353212397c6Schristos strm.avail_out := BufInc;
354212397c6Schristos end;
355212397c6Schristos finally
356212397c6Schristos DCheck(inflateEnd(strm));
357212397c6Schristos end;
358212397c6Schristos ReallocMem(OutBuf, strm.total_out);
359212397c6Schristos OutBytes := strm.total_out;
360212397c6Schristos except
361212397c6Schristos FreeMem(OutBuf);
362212397c6Schristos raise
363212397c6Schristos end;
364212397c6Schristos end;
365212397c6Schristos
366212397c6Schristos procedure DecompressToUserBuf(const InBuf: Pointer; InBytes: Integer;
367212397c6Schristos const OutBuf: Pointer; BufSize: Integer);
368212397c6Schristos var
369212397c6Schristos strm: TZStreamRec;
370212397c6Schristos begin
371212397c6Schristos FillChar(strm, sizeof(strm), 0);
372212397c6Schristos strm.zalloc := zlibAllocMem;
373212397c6Schristos strm.zfree := zlibFreeMem;
374212397c6Schristos strm.next_in := InBuf;
375212397c6Schristos strm.avail_in := InBytes;
376212397c6Schristos strm.next_out := OutBuf;
377212397c6Schristos strm.avail_out := BufSize;
378212397c6Schristos DCheck(inflateInit_(strm, zlib_version, sizeof(strm)));
379212397c6Schristos try
380212397c6Schristos if DCheck(inflate(strm, Z_FINISH)) <> Z_STREAM_END then
381212397c6Schristos raise EZlibError.CreateRes(@sTargetBufferTooSmall);
382212397c6Schristos finally
383212397c6Schristos DCheck(inflateEnd(strm));
384212397c6Schristos end;
385212397c6Schristos end;
386212397c6Schristos
387212397c6Schristos // TCustomZlibStream
388212397c6Schristos
389212397c6Schristos constructor TCustomZLibStream.Create(Strm: TStream);
390212397c6Schristos begin
391212397c6Schristos inherited Create;
392212397c6Schristos FStrm := Strm;
393212397c6Schristos FStrmPos := Strm.Position;
394212397c6Schristos FZRec.zalloc := zlibAllocMem;
395212397c6Schristos FZRec.zfree := zlibFreeMem;
396212397c6Schristos end;
397212397c6Schristos
398212397c6Schristos procedure TCustomZLibStream.Progress(Sender: TObject);
399212397c6Schristos begin
400212397c6Schristos if Assigned(FOnProgress) then FOnProgress(Sender);
401212397c6Schristos end;
402212397c6Schristos
403212397c6Schristos
404212397c6Schristos // TCompressionStream
405212397c6Schristos
406212397c6Schristos constructor TCompressionStream.Create(CompressionLevel: TCompressionLevel;
407212397c6Schristos Dest: TStream);
408212397c6Schristos const
409212397c6Schristos Levels: array [TCompressionLevel] of ShortInt =
410212397c6Schristos (Z_NO_COMPRESSION, Z_BEST_SPEED, Z_DEFAULT_COMPRESSION, Z_BEST_COMPRESSION);
411212397c6Schristos begin
412212397c6Schristos inherited Create(Dest);
413212397c6Schristos FZRec.next_out := FBuffer;
414212397c6Schristos FZRec.avail_out := sizeof(FBuffer);
415212397c6Schristos CCheck(deflateInit_(FZRec, Levels[CompressionLevel], zlib_version, sizeof(FZRec)));
416212397c6Schristos end;
417212397c6Schristos
418212397c6Schristos destructor TCompressionStream.Destroy;
419212397c6Schristos begin
420212397c6Schristos FZRec.next_in := nil;
421212397c6Schristos FZRec.avail_in := 0;
422212397c6Schristos try
423212397c6Schristos if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos;
424212397c6Schristos while (CCheck(deflate(FZRec, Z_FINISH)) <> Z_STREAM_END)
425212397c6Schristos and (FZRec.avail_out = 0) do
426212397c6Schristos begin
427212397c6Schristos FStrm.WriteBuffer(FBuffer, sizeof(FBuffer));
428212397c6Schristos FZRec.next_out := FBuffer;
429212397c6Schristos FZRec.avail_out := sizeof(FBuffer);
430212397c6Schristos end;
431212397c6Schristos if FZRec.avail_out < sizeof(FBuffer) then
432212397c6Schristos FStrm.WriteBuffer(FBuffer, sizeof(FBuffer) - FZRec.avail_out);
433212397c6Schristos finally
434212397c6Schristos deflateEnd(FZRec);
435212397c6Schristos end;
436212397c6Schristos inherited Destroy;
437212397c6Schristos end;
438212397c6Schristos
Readnull439212397c6Schristos function TCompressionStream.Read(var Buffer; Count: Longint): Longint;
440212397c6Schristos begin
441212397c6Schristos raise ECompressionError.CreateRes(@sInvalidStreamOp);
442212397c6Schristos end;
443212397c6Schristos
Writenull444212397c6Schristos function TCompressionStream.Write(const Buffer; Count: Longint): Longint;
445212397c6Schristos begin
446212397c6Schristos FZRec.next_in := @Buffer;
447212397c6Schristos FZRec.avail_in := Count;
448212397c6Schristos if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos;
449212397c6Schristos while (FZRec.avail_in > 0) do
450212397c6Schristos begin
451212397c6Schristos CCheck(deflate(FZRec, 0));
452212397c6Schristos if FZRec.avail_out = 0 then
453212397c6Schristos begin
454212397c6Schristos FStrm.WriteBuffer(FBuffer, sizeof(FBuffer));
455212397c6Schristos FZRec.next_out := FBuffer;
456212397c6Schristos FZRec.avail_out := sizeof(FBuffer);
457212397c6Schristos FStrmPos := FStrm.Position;
458212397c6Schristos Progress(Self);
459212397c6Schristos end;
460212397c6Schristos end;
461212397c6Schristos Result := Count;
462212397c6Schristos end;
463212397c6Schristos
TCompressionStream.Seek(Offset: Longint; Origin: Word)464212397c6Schristos function TCompressionStream.Seek(Offset: Longint; Origin: Word): Longint;
465212397c6Schristos begin
466212397c6Schristos if (Offset = 0) and (Origin = soFromCurrent) then
467212397c6Schristos Result := FZRec.total_in
468212397c6Schristos else
469212397c6Schristos raise ECompressionError.CreateRes(@sInvalidStreamOp);
470212397c6Schristos end;
471212397c6Schristos
TCompressionStream.GetCompressionRate()472212397c6Schristos function TCompressionStream.GetCompressionRate: Single;
473212397c6Schristos begin
474212397c6Schristos if FZRec.total_in = 0 then
475212397c6Schristos Result := 0
476212397c6Schristos else
477212397c6Schristos Result := (1.0 - (FZRec.total_out / FZRec.total_in)) * 100.0;
478212397c6Schristos end;
479212397c6Schristos
480212397c6Schristos
481212397c6Schristos // TDecompressionStream
482212397c6Schristos
483212397c6Schristos constructor TDecompressionStream.Create(Source: TStream);
484212397c6Schristos begin
485212397c6Schristos inherited Create(Source);
486212397c6Schristos FZRec.next_in := FBuffer;
487212397c6Schristos FZRec.avail_in := 0;
488212397c6Schristos DCheck(inflateInit_(FZRec, zlib_version, sizeof(FZRec)));
489212397c6Schristos end;
490212397c6Schristos
491212397c6Schristos destructor TDecompressionStream.Destroy;
492212397c6Schristos begin
493212397c6Schristos FStrm.Seek(-FZRec.avail_in, 1);
494212397c6Schristos inflateEnd(FZRec);
495212397c6Schristos inherited Destroy;
496212397c6Schristos end;
497212397c6Schristos
Readnull498212397c6Schristos function TDecompressionStream.Read(var Buffer; Count: Longint): Longint;
499212397c6Schristos begin
500212397c6Schristos FZRec.next_out := @Buffer;
501212397c6Schristos FZRec.avail_out := Count;
502212397c6Schristos if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos;
503212397c6Schristos while (FZRec.avail_out > 0) do
504212397c6Schristos begin
505212397c6Schristos if FZRec.avail_in = 0 then
506212397c6Schristos begin
507212397c6Schristos FZRec.avail_in := FStrm.Read(FBuffer, sizeof(FBuffer));
508212397c6Schristos if FZRec.avail_in = 0 then
509212397c6Schristos begin
510212397c6Schristos Result := Count - FZRec.avail_out;
511212397c6Schristos Exit;
512212397c6Schristos end;
513212397c6Schristos FZRec.next_in := FBuffer;
514212397c6Schristos FStrmPos := FStrm.Position;
515212397c6Schristos Progress(Self);
516212397c6Schristos end;
517212397c6Schristos CCheck(inflate(FZRec, 0));
518212397c6Schristos end;
519212397c6Schristos Result := Count;
520212397c6Schristos end;
521212397c6Schristos
Writenull522212397c6Schristos function TDecompressionStream.Write(const Buffer; Count: Longint): Longint;
523212397c6Schristos begin
524212397c6Schristos raise EDecompressionError.CreateRes(@sInvalidStreamOp);
525212397c6Schristos end;
526212397c6Schristos
Seeknull527212397c6Schristos function TDecompressionStream.Seek(Offset: Longint; Origin: Word): Longint;
528212397c6Schristos var
529212397c6Schristos I: Integer;
530212397c6Schristos Buf: array [0..4095] of Char;
531212397c6Schristos begin
532212397c6Schristos if (Offset = 0) and (Origin = soFromBeginning) then
533212397c6Schristos begin
534212397c6Schristos DCheck(inflateReset(FZRec));
535212397c6Schristos FZRec.next_in := FBuffer;
536212397c6Schristos FZRec.avail_in := 0;
537212397c6Schristos FStrm.Position := 0;
538212397c6Schristos FStrmPos := 0;
539212397c6Schristos end
540212397c6Schristos else if ( (Offset >= 0) and (Origin = soFromCurrent)) or
541212397c6Schristos ( ((Offset - FZRec.total_out) > 0) and (Origin = soFromBeginning)) then
542212397c6Schristos begin
543212397c6Schristos if Origin = soFromBeginning then Dec(Offset, FZRec.total_out);
544212397c6Schristos if Offset > 0 then
545212397c6Schristos begin
546212397c6Schristos for I := 1 to Offset div sizeof(Buf) do
547212397c6Schristos ReadBuffer(Buf, sizeof(Buf));
548212397c6Schristos ReadBuffer(Buf, Offset mod sizeof(Buf));
549212397c6Schristos end;
550212397c6Schristos end
551212397c6Schristos else
552212397c6Schristos raise EDecompressionError.CreateRes(@sInvalidStreamOp);
553212397c6Schristos Result := FZRec.total_out;
554212397c6Schristos end;
555212397c6Schristos
556212397c6Schristos
557212397c6Schristos end.
558