kusano 7d535a
{*******************************************************}
kusano 7d535a
{                                                       }
kusano 7d535a
{       Borland Delphi Supplemental Components          }
kusano 7d535a
{       ZLIB Data Compression Interface Unit            }
kusano 7d535a
{                                                       }
kusano 7d535a
{       Copyright (c) 1997,99 Borland Corporation       }
kusano 7d535a
{                                                       }
kusano 7d535a
{*******************************************************}
kusano 7d535a
kusano 7d535a
{ Updated for zlib 1.2.x by Cosmin Truta <cosmint@cs.ubbcluj.ro> }</cosmint@cs.ubbcluj.ro>
kusano 7d535a
kusano 7d535a
unit ZLib;
kusano 7d535a
kusano 7d535a
interface
kusano 7d535a
kusano 7d535a
uses SysUtils, Classes;
kusano 7d535a
kusano 7d535a
type
kusano 7d535a
  TAlloc = function (AppData: Pointer; Items, Size: Integer): Pointer; cdecl;
kusano 7d535a
  TFree = procedure (AppData, Block: Pointer); cdecl;
kusano 7d535a
kusano 7d535a
  // Internal structure.  Ignore.
kusano 7d535a
  TZStreamRec = packed record
kusano 7d535a
    next_in: PChar;       // next input byte
kusano 7d535a
    avail_in: Integer;    // number of bytes available at next_in
kusano 7d535a
    total_in: Longint;    // total nb of input bytes read so far
kusano 7d535a
kusano 7d535a
    next_out: PChar;      // next output byte should be put here
kusano 7d535a
    avail_out: Integer;   // remaining free space at next_out
kusano 7d535a
    total_out: Longint;   // total nb of bytes output so far
kusano 7d535a
kusano 7d535a
    msg: PChar;           // last error message, NULL if no error
kusano 7d535a
    internal: Pointer;    // not visible by applications
kusano 7d535a
kusano 7d535a
    zalloc: TAlloc;       // used to allocate the internal state
kusano 7d535a
    zfree: TFree;         // used to free the internal state
kusano 7d535a
    AppData: Pointer;     // private data object passed to zalloc and zfree
kusano 7d535a
kusano 7d535a
    data_type: Integer;   // best guess about the data type: ascii or binary
kusano 7d535a
    adler: Longint;       // adler32 value of the uncompressed data
kusano 7d535a
    reserved: Longint;    // reserved for future use
kusano 7d535a
  end;
kusano 7d535a
kusano 7d535a
  // Abstract ancestor class
kusano 7d535a
  TCustomZlibStream = class(TStream)
kusano 7d535a
  private
kusano 7d535a
    FStrm: TStream;
kusano 7d535a
    FStrmPos: Integer;
kusano 7d535a
    FOnProgress: TNotifyEvent;
kusano 7d535a
    FZRec: TZStreamRec;
kusano 7d535a
    FBuffer: array [Word] of Char;
kusano 7d535a
  protected
kusano 7d535a
    procedure Progress(Sender: TObject); dynamic;
kusano 7d535a
    property OnProgress: TNotifyEvent read FOnProgress write FOnProgress;
kusano 7d535a
    constructor Create(Strm: TStream);
kusano 7d535a
  end;
kusano 7d535a
kusano 7d535a
{ TCompressionStream compresses data on the fly as data is written to it, and
kusano 7d535a
  stores the compressed data to another stream.
kusano 7d535a
kusano 7d535a
  TCompressionStream is write-only and strictly sequential. Reading from the
kusano 7d535a
  stream will raise an exception. Using Seek to move the stream pointer
kusano 7d535a
  will raise an exception.
kusano 7d535a
kusano 7d535a
  Output data is cached internally, written to the output stream only when
kusano 7d535a
  the internal output buffer is full.  All pending output data is flushed
kusano 7d535a
  when the stream is destroyed.
kusano 7d535a
kusano 7d535a
  The Position property returns the number of uncompressed bytes of
kusano 7d535a
  data that have been written to the stream so far.
kusano 7d535a
kusano 7d535a
  CompressionRate returns the on-the-fly percentage by which the original
kusano 7d535a
  data has been compressed:  (1 - (CompressedBytes / UncompressedBytes)) * 100
kusano 7d535a
  If raw data size = 100 and compressed data size = 25, the CompressionRate
kusano 7d535a
  is 75%
kusano 7d535a
kusano 7d535a
  The OnProgress event is called each time the output buffer is filled and
kusano 7d535a
  written to the output stream.  This is useful for updating a progress
kusano 7d535a
  indicator when you are writing a large chunk of data to the compression
kusano 7d535a
  stream in a single call.}
kusano 7d535a
kusano 7d535a
kusano 7d535a
  TCompressionLevel = (clNone, clFastest, clDefault, clMax);
kusano 7d535a
kusano 7d535a
  TCompressionStream = class(TCustomZlibStream)
kusano 7d535a
  private
kusano 7d535a
    function GetCompressionRate: Single;
kusano 7d535a
  public
kusano 7d535a
    constructor Create(CompressionLevel: TCompressionLevel; Dest: TStream);
kusano 7d535a
    destructor Destroy; override;
kusano 7d535a
    function Read(var Buffer; Count: Longint): Longint; override;
kusano 7d535a
    function Write(const Buffer; Count: Longint): Longint; override;
kusano 7d535a
    function Seek(Offset: Longint; Origin: Word): Longint; override;
kusano 7d535a
    property CompressionRate: Single read GetCompressionRate;
kusano 7d535a
    property OnProgress;
kusano 7d535a
  end;
kusano 7d535a
kusano 7d535a
{ TDecompressionStream decompresses data on the fly as data is read from it.
kusano 7d535a
kusano 7d535a
  Compressed data comes from a separate source stream.  TDecompressionStream
kusano 7d535a
  is read-only and unidirectional; you can seek forward in the stream, but not
kusano 7d535a
  backwards.  The special case of setting the stream position to zero is
kusano 7d535a
  allowed.  Seeking forward decompresses data until the requested position in
kusano 7d535a
  the uncompressed data has been reached.  Seeking backwards, seeking relative
kusano 7d535a
  to the end of the stream, requesting the size of the stream, and writing to
kusano 7d535a
  the stream will raise an exception.
kusano 7d535a
kusano 7d535a
  The Position property returns the number of bytes of uncompressed data that
kusano 7d535a
  have been read from the stream so far.
kusano 7d535a
kusano 7d535a
  The OnProgress event is called each time the internal input buffer of
kusano 7d535a
  compressed data is exhausted and the next block is read from the input stream.
kusano 7d535a
  This is useful for updating a progress indicator when you are reading a
kusano 7d535a
  large chunk of data from the decompression stream in a single call.}
kusano 7d535a
kusano 7d535a
  TDecompressionStream = class(TCustomZlibStream)
kusano 7d535a
  public
kusano 7d535a
    constructor Create(Source: TStream);
kusano 7d535a
    destructor Destroy; override;
kusano 7d535a
    function Read(var Buffer; Count: Longint): Longint; override;
kusano 7d535a
    function Write(const Buffer; Count: Longint): Longint; override;
kusano 7d535a
    function Seek(Offset: Longint; Origin: Word): Longint; override;
kusano 7d535a
    property OnProgress;
kusano 7d535a
  end;
kusano 7d535a
kusano 7d535a
kusano 7d535a
kusano 7d535a
{ CompressBuf compresses data, buffer to buffer, in one call.
kusano 7d535a
   In: InBuf = ptr to compressed data
kusano 7d535a
       InBytes = number of bytes in InBuf
kusano 7d535a
  Out: OutBuf = ptr to newly allocated buffer containing decompressed data
kusano 7d535a
       OutBytes = number of bytes in OutBuf   }
kusano 7d535a
procedure CompressBuf(const InBuf: Pointer; InBytes: Integer;
kusano 7d535a
                      out OutBuf: Pointer; out OutBytes: Integer);
kusano 7d535a
kusano 7d535a
kusano 7d535a
{ DecompressBuf decompresses data, buffer to buffer, in one call.
kusano 7d535a
   In: InBuf = ptr to compressed data
kusano 7d535a
       InBytes = number of bytes in InBuf
kusano 7d535a
       OutEstimate = zero, or est. size of the decompressed data
kusano 7d535a
  Out: OutBuf = ptr to newly allocated buffer containing decompressed data
kusano 7d535a
       OutBytes = number of bytes in OutBuf   }
kusano 7d535a
procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer;
kusano 7d535a
 OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer);
kusano 7d535a
kusano 7d535a
{ DecompressToUserBuf decompresses data, buffer to buffer, in one call.
kusano 7d535a
   In: InBuf = ptr to compressed data
kusano 7d535a
       InBytes = number of bytes in InBuf
kusano 7d535a
  Out: OutBuf = ptr to user-allocated buffer to contain decompressed data
kusano 7d535a
       BufSize = number of bytes in OutBuf   }
kusano 7d535a
procedure DecompressToUserBuf(const InBuf: Pointer; InBytes: Integer;
kusano 7d535a
  const OutBuf: Pointer; BufSize: Integer);
kusano 7d535a
kusano 7d535a
const
kusano 7d535a
  zlib_version = '1.2.7';
kusano 7d535a
kusano 7d535a
type
kusano 7d535a
  EZlibError = class(Exception);
kusano 7d535a
  ECompressionError = class(EZlibError);
kusano 7d535a
  EDecompressionError = class(EZlibError);
kusano 7d535a
kusano 7d535a
implementation
kusano 7d535a
kusano 7d535a
uses ZLibConst;
kusano 7d535a
kusano 7d535a
const
kusano 7d535a
  Z_NO_FLUSH      = 0;
kusano 7d535a
  Z_PARTIAL_FLUSH = 1;
kusano 7d535a
  Z_SYNC_FLUSH    = 2;
kusano 7d535a
  Z_FULL_FLUSH    = 3;
kusano 7d535a
  Z_FINISH        = 4;
kusano 7d535a
kusano 7d535a
  Z_OK            = 0;
kusano 7d535a
  Z_STREAM_END    = 1;
kusano 7d535a
  Z_NEED_DICT     = 2;
kusano 7d535a
  Z_ERRNO         = (-1);
kusano 7d535a
  Z_STREAM_ERROR  = (-2);
kusano 7d535a
  Z_DATA_ERROR    = (-3);
kusano 7d535a
  Z_MEM_ERROR     = (-4);
kusano 7d535a
  Z_BUF_ERROR     = (-5);
kusano 7d535a
  Z_VERSION_ERROR = (-6);
kusano 7d535a
kusano 7d535a
  Z_NO_COMPRESSION       =   0;
kusano 7d535a
  Z_BEST_SPEED           =   1;
kusano 7d535a
  Z_BEST_COMPRESSION     =   9;
kusano 7d535a
  Z_DEFAULT_COMPRESSION  = (-1);
kusano 7d535a
kusano 7d535a
  Z_FILTERED            = 1;
kusano 7d535a
  Z_HUFFMAN_ONLY        = 2;
kusano 7d535a
  Z_RLE                 = 3;
kusano 7d535a
  Z_DEFAULT_STRATEGY    = 0;
kusano 7d535a
kusano 7d535a
  Z_BINARY   = 0;
kusano 7d535a
  Z_ASCII    = 1;
kusano 7d535a
  Z_UNKNOWN  = 2;
kusano 7d535a
kusano 7d535a
  Z_DEFLATED = 8;
kusano 7d535a
kusano 7d535a
kusano 7d535a
{$L adler32.obj}
kusano 7d535a
{$L compress.obj}
kusano 7d535a
{$L crc32.obj}
kusano 7d535a
{$L deflate.obj}
kusano 7d535a
{$L infback.obj}
kusano 7d535a
{$L inffast.obj}
kusano 7d535a
{$L inflate.obj}
kusano 7d535a
{$L inftrees.obj}
kusano 7d535a
{$L trees.obj}
kusano 7d535a
{$L uncompr.obj}
kusano 7d535a
{$L zutil.obj}
kusano 7d535a
kusano 7d535a
procedure adler32; external;
kusano 7d535a
procedure compressBound; external;
kusano 7d535a
procedure crc32; external;
kusano 7d535a
procedure deflateInit2_; external;
kusano 7d535a
procedure deflateParams; external;
kusano 7d535a
kusano 7d535a
function _malloc(Size: Integer): Pointer; cdecl;
kusano 7d535a
begin
kusano 7d535a
  Result := AllocMem(Size);
kusano 7d535a
end;
kusano 7d535a
kusano 7d535a
procedure _free(Block: Pointer); cdecl;
kusano 7d535a
begin
kusano 7d535a
  FreeMem(Block);
kusano 7d535a
end;
kusano 7d535a
kusano 7d535a
procedure _memset(P: Pointer; B: Byte; count: Integer); cdecl;
kusano 7d535a
begin
kusano 7d535a
  FillChar(P^, count, B);
kusano 7d535a
end;
kusano 7d535a
kusano 7d535a
procedure _memcpy(dest, source: Pointer; count: Integer); cdecl;
kusano 7d535a
begin
kusano 7d535a
  Move(source^, dest^, count);
kusano 7d535a
end;
kusano 7d535a
kusano 7d535a
kusano 7d535a
kusano 7d535a
// deflate compresses data
kusano 7d535a
function deflateInit_(var strm: TZStreamRec; level: Integer; version: PChar;
kusano 7d535a
  recsize: Integer): Integer; external;
kusano 7d535a
function deflate(var strm: TZStreamRec; flush: Integer): Integer; external;
kusano 7d535a
function deflateEnd(var strm: TZStreamRec): Integer; external;
kusano 7d535a
kusano 7d535a
// inflate decompresses data
kusano 7d535a
function inflateInit_(var strm: TZStreamRec; version: PChar;
kusano 7d535a
  recsize: Integer): Integer; external;
kusano 7d535a
function inflate(var strm: TZStreamRec; flush: Integer): Integer; external;
kusano 7d535a
function inflateEnd(var strm: TZStreamRec): Integer; external;
kusano 7d535a
function inflateReset(var strm: TZStreamRec): Integer; external;
kusano 7d535a
kusano 7d535a
kusano 7d535a
function zlibAllocMem(AppData: Pointer; Items, Size: Integer): Pointer; cdecl;
kusano 7d535a
begin
kusano 7d535a
//  GetMem(Result, Items*Size);
kusano 7d535a
  Result := AllocMem(Items * Size);
kusano 7d535a
end;
kusano 7d535a
kusano 7d535a
procedure zlibFreeMem(AppData, Block: Pointer); cdecl;
kusano 7d535a
begin
kusano 7d535a
  FreeMem(Block);
kusano 7d535a
end;
kusano 7d535a
kusano 7d535a
{function zlibCheck(code: Integer): Integer;
kusano 7d535a
begin
kusano 7d535a
  Result := code;
kusano 7d535a
  if code < 0 then
kusano 7d535a
    raise EZlibError.Create('error');    //!!
kusano 7d535a
end;}
kusano 7d535a
kusano 7d535a
function CCheck(code: Integer): Integer;
kusano 7d535a
begin
kusano 7d535a
  Result := code;
kusano 7d535a
  if code < 0 then
kusano 7d535a
    raise ECompressionError.Create('error'); //!!
kusano 7d535a
end;
kusano 7d535a
kusano 7d535a
function DCheck(code: Integer): Integer;
kusano 7d535a
begin
kusano 7d535a
  Result := code;
kusano 7d535a
  if code < 0 then
kusano 7d535a
    raise EDecompressionError.Create('error');  //!!
kusano 7d535a
end;
kusano 7d535a
kusano 7d535a
procedure CompressBuf(const InBuf: Pointer; InBytes: Integer;
kusano 7d535a
                      out OutBuf: Pointer; out OutBytes: Integer);
kusano 7d535a
var
kusano 7d535a
  strm: TZStreamRec;
kusano 7d535a
  P: Pointer;
kusano 7d535a
begin
kusano 7d535a
  FillChar(strm, sizeof(strm), 0);
kusano 7d535a
  strm.zalloc := zlibAllocMem;
kusano 7d535a
  strm.zfree := zlibFreeMem;
kusano 7d535a
  OutBytes := ((InBytes + (InBytes div 10) + 12) + 255) and not 255;
kusano 7d535a
  GetMem(OutBuf, OutBytes);
kusano 7d535a
  try
kusano 7d535a
    strm.next_in := InBuf;
kusano 7d535a
    strm.avail_in := InBytes;
kusano 7d535a
    strm.next_out := OutBuf;
kusano 7d535a
    strm.avail_out := OutBytes;
kusano 7d535a
    CCheck(deflateInit_(strm, Z_BEST_COMPRESSION, zlib_version, sizeof(strm)));
kusano 7d535a
    try
kusano 7d535a
      while CCheck(deflate(strm, Z_FINISH)) <> Z_STREAM_END do
kusano 7d535a
      begin
kusano 7d535a
        P := OutBuf;
kusano 7d535a
        Inc(OutBytes, 256);
kusano 7d535a
        ReallocMem(OutBuf, OutBytes);
kusano 7d535a
        strm.next_out := PChar(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P)));
kusano 7d535a
        strm.avail_out := 256;
kusano 7d535a
      end;
kusano 7d535a
    finally
kusano 7d535a
      CCheck(deflateEnd(strm));
kusano 7d535a
    end;
kusano 7d535a
    ReallocMem(OutBuf, strm.total_out);
kusano 7d535a
    OutBytes := strm.total_out;
kusano 7d535a
  except
kusano 7d535a
    FreeMem(OutBuf);
kusano 7d535a
    raise
kusano 7d535a
  end;
kusano 7d535a
end;
kusano 7d535a
kusano 7d535a
kusano 7d535a
procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer;
kusano 7d535a
  OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer);
kusano 7d535a
var
kusano 7d535a
  strm: TZStreamRec;
kusano 7d535a
  P: Pointer;
kusano 7d535a
  BufInc: Integer;
kusano 7d535a
begin
kusano 7d535a
  FillChar(strm, sizeof(strm), 0);
kusano 7d535a
  strm.zalloc := zlibAllocMem;
kusano 7d535a
  strm.zfree := zlibFreeMem;
kusano 7d535a
  BufInc := (InBytes + 255) and not 255;
kusano 7d535a
  if OutEstimate = 0 then
kusano 7d535a
    OutBytes := BufInc
kusano 7d535a
  else
kusano 7d535a
    OutBytes := OutEstimate;
kusano 7d535a
  GetMem(OutBuf, OutBytes);
kusano 7d535a
  try
kusano 7d535a
    strm.next_in := InBuf;
kusano 7d535a
    strm.avail_in := InBytes;
kusano 7d535a
    strm.next_out := OutBuf;
kusano 7d535a
    strm.avail_out := OutBytes;
kusano 7d535a
    DCheck(inflateInit_(strm, zlib_version, sizeof(strm)));
kusano 7d535a
    try
kusano 7d535a
      while DCheck(inflate(strm, Z_NO_FLUSH)) <> Z_STREAM_END do
kusano 7d535a
      begin
kusano 7d535a
        P := OutBuf;
kusano 7d535a
        Inc(OutBytes, BufInc);
kusano 7d535a
        ReallocMem(OutBuf, OutBytes);
kusano 7d535a
        strm.next_out := PChar(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P)));
kusano 7d535a
        strm.avail_out := BufInc;
kusano 7d535a
      end;
kusano 7d535a
    finally
kusano 7d535a
      DCheck(inflateEnd(strm));
kusano 7d535a
    end;
kusano 7d535a
    ReallocMem(OutBuf, strm.total_out);
kusano 7d535a
    OutBytes := strm.total_out;
kusano 7d535a
  except
kusano 7d535a
    FreeMem(OutBuf);
kusano 7d535a
    raise
kusano 7d535a
  end;
kusano 7d535a
end;
kusano 7d535a
kusano 7d535a
procedure DecompressToUserBuf(const InBuf: Pointer; InBytes: Integer;
kusano 7d535a
  const OutBuf: Pointer; BufSize: Integer);
kusano 7d535a
var
kusano 7d535a
  strm: TZStreamRec;
kusano 7d535a
begin
kusano 7d535a
  FillChar(strm, sizeof(strm), 0);
kusano 7d535a
  strm.zalloc := zlibAllocMem;
kusano 7d535a
  strm.zfree := zlibFreeMem;
kusano 7d535a
  strm.next_in := InBuf;
kusano 7d535a
  strm.avail_in := InBytes;
kusano 7d535a
  strm.next_out := OutBuf;
kusano 7d535a
  strm.avail_out := BufSize;
kusano 7d535a
  DCheck(inflateInit_(strm, zlib_version, sizeof(strm)));
kusano 7d535a
  try
kusano 7d535a
    if DCheck(inflate(strm, Z_FINISH)) <> Z_STREAM_END then
kusano 7d535a
      raise EZlibError.CreateRes(@sTargetBufferTooSmall);
kusano 7d535a
  finally
kusano 7d535a
    DCheck(inflateEnd(strm));
kusano 7d535a
  end;
kusano 7d535a
end;
kusano 7d535a
kusano 7d535a
// TCustomZlibStream
kusano 7d535a
kusano 7d535a
constructor TCustomZLibStream.Create(Strm: TStream);
kusano 7d535a
begin
kusano 7d535a
  inherited Create;
kusano 7d535a
  FStrm := Strm;
kusano 7d535a
  FStrmPos := Strm.Position;
kusano 7d535a
  FZRec.zalloc := zlibAllocMem;
kusano 7d535a
  FZRec.zfree := zlibFreeMem;
kusano 7d535a
end;
kusano 7d535a
kusano 7d535a
procedure TCustomZLibStream.Progress(Sender: TObject);
kusano 7d535a
begin
kusano 7d535a
  if Assigned(FOnProgress) then FOnProgress(Sender);
kusano 7d535a
end;
kusano 7d535a
kusano 7d535a
kusano 7d535a
// TCompressionStream
kusano 7d535a
kusano 7d535a
constructor TCompressionStream.Create(CompressionLevel: TCompressionLevel;
kusano 7d535a
  Dest: TStream);
kusano 7d535a
const
kusano 7d535a
  Levels: array [TCompressionLevel] of ShortInt =
kusano 7d535a
    (Z_NO_COMPRESSION, Z_BEST_SPEED, Z_DEFAULT_COMPRESSION, Z_BEST_COMPRESSION);
kusano 7d535a
begin
kusano 7d535a
  inherited Create(Dest);
kusano 7d535a
  FZRec.next_out := FBuffer;
kusano 7d535a
  FZRec.avail_out := sizeof(FBuffer);
kusano 7d535a
  CCheck(deflateInit_(FZRec, Levels[CompressionLevel], zlib_version, sizeof(FZRec)));
kusano 7d535a
end;
kusano 7d535a
kusano 7d535a
destructor TCompressionStream.Destroy;
kusano 7d535a
begin
kusano 7d535a
  FZRec.next_in := nil;
kusano 7d535a
  FZRec.avail_in := 0;
kusano 7d535a
  try
kusano 7d535a
    if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos;
kusano 7d535a
    while (CCheck(deflate(FZRec, Z_FINISH)) <> Z_STREAM_END)
kusano 7d535a
      and (FZRec.avail_out = 0) do
kusano 7d535a
    begin
kusano 7d535a
      FStrm.WriteBuffer(FBuffer, sizeof(FBuffer));
kusano 7d535a
      FZRec.next_out := FBuffer;
kusano 7d535a
      FZRec.avail_out := sizeof(FBuffer);
kusano 7d535a
    end;
kusano 7d535a
    if FZRec.avail_out < sizeof(FBuffer) then
kusano 7d535a
      FStrm.WriteBuffer(FBuffer, sizeof(FBuffer) - FZRec.avail_out);
kusano 7d535a
  finally
kusano 7d535a
    deflateEnd(FZRec);
kusano 7d535a
  end;
kusano 7d535a
  inherited Destroy;
kusano 7d535a
end;
kusano 7d535a
kusano 7d535a
function TCompressionStream.Read(var Buffer; Count: Longint): Longint;
kusano 7d535a
begin
kusano 7d535a
  raise ECompressionError.CreateRes(@sInvalidStreamOp);
kusano 7d535a
end;
kusano 7d535a
kusano 7d535a
function TCompressionStream.Write(const Buffer; Count: Longint): Longint;
kusano 7d535a
begin
kusano 7d535a
  FZRec.next_in := @Buffer;
kusano 7d535a
  FZRec.avail_in := Count;
kusano 7d535a
  if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos;
kusano 7d535a
  while (FZRec.avail_in > 0) do
kusano 7d535a
  begin
kusano 7d535a
    CCheck(deflate(FZRec, 0));
kusano 7d535a
    if FZRec.avail_out = 0 then
kusano 7d535a
    begin
kusano 7d535a
      FStrm.WriteBuffer(FBuffer, sizeof(FBuffer));
kusano 7d535a
      FZRec.next_out := FBuffer;
kusano 7d535a
      FZRec.avail_out := sizeof(FBuffer);
kusano 7d535a
      FStrmPos := FStrm.Position;
kusano 7d535a
      Progress(Self);
kusano 7d535a
    end;
kusano 7d535a
  end;
kusano 7d535a
  Result := Count;
kusano 7d535a
end;
kusano 7d535a
kusano 7d535a
function TCompressionStream.Seek(Offset: Longint; Origin: Word): Longint;
kusano 7d535a
begin
kusano 7d535a
  if (Offset = 0) and (Origin = soFromCurrent) then
kusano 7d535a
    Result := FZRec.total_in
kusano 7d535a
  else
kusano 7d535a
    raise ECompressionError.CreateRes(@sInvalidStreamOp);
kusano 7d535a
end;
kusano 7d535a
kusano 7d535a
function TCompressionStream.GetCompressionRate: Single;
kusano 7d535a
begin
kusano 7d535a
  if FZRec.total_in = 0 then
kusano 7d535a
    Result := 0
kusano 7d535a
  else
kusano 7d535a
    Result := (1.0 - (FZRec.total_out / FZRec.total_in)) * 100.0;
kusano 7d535a
end;
kusano 7d535a
kusano 7d535a
kusano 7d535a
// TDecompressionStream
kusano 7d535a
kusano 7d535a
constructor TDecompressionStream.Create(Source: TStream);
kusano 7d535a
begin
kusano 7d535a
  inherited Create(Source);
kusano 7d535a
  FZRec.next_in := FBuffer;
kusano 7d535a
  FZRec.avail_in := 0;
kusano 7d535a
  DCheck(inflateInit_(FZRec, zlib_version, sizeof(FZRec)));
kusano 7d535a
end;
kusano 7d535a
kusano 7d535a
destructor TDecompressionStream.Destroy;
kusano 7d535a
begin
kusano 7d535a
  FStrm.Seek(-FZRec.avail_in, 1);
kusano 7d535a
  inflateEnd(FZRec);
kusano 7d535a
  inherited Destroy;
kusano 7d535a
end;
kusano 7d535a
kusano 7d535a
function TDecompressionStream.Read(var Buffer; Count: Longint): Longint;
kusano 7d535a
begin
kusano 7d535a
  FZRec.next_out := @Buffer;
kusano 7d535a
  FZRec.avail_out := Count;
kusano 7d535a
  if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos;
kusano 7d535a
  while (FZRec.avail_out > 0) do
kusano 7d535a
  begin
kusano 7d535a
    if FZRec.avail_in = 0 then
kusano 7d535a
    begin
kusano 7d535a
      FZRec.avail_in := FStrm.Read(FBuffer, sizeof(FBuffer));
kusano 7d535a
      if FZRec.avail_in = 0 then
kusano 7d535a
      begin
kusano 7d535a
        Result := Count - FZRec.avail_out;
kusano 7d535a
        Exit;
kusano 7d535a
      end;
kusano 7d535a
      FZRec.next_in := FBuffer;
kusano 7d535a
      FStrmPos := FStrm.Position;
kusano 7d535a
      Progress(Self);
kusano 7d535a
    end;
kusano 7d535a
    CCheck(inflate(FZRec, 0));
kusano 7d535a
  end;
kusano 7d535a
  Result := Count;
kusano 7d535a
end;
kusano 7d535a
kusano 7d535a
function TDecompressionStream.Write(const Buffer; Count: Longint): Longint;
kusano 7d535a
begin
kusano 7d535a
  raise EDecompressionError.CreateRes(@sInvalidStreamOp);
kusano 7d535a
end;
kusano 7d535a
kusano 7d535a
function TDecompressionStream.Seek(Offset: Longint; Origin: Word): Longint;
kusano 7d535a
var
kusano 7d535a
  I: Integer;
kusano 7d535a
  Buf: array [0..4095] of Char;
kusano 7d535a
begin
kusano 7d535a
  if (Offset = 0) and (Origin = soFromBeginning) then
kusano 7d535a
  begin
kusano 7d535a
    DCheck(inflateReset(FZRec));
kusano 7d535a
    FZRec.next_in := FBuffer;
kusano 7d535a
    FZRec.avail_in := 0;
kusano 7d535a
    FStrm.Position := 0;
kusano 7d535a
    FStrmPos := 0;
kusano 7d535a
  end
kusano 7d535a
  else if ( (Offset >= 0) and (Origin = soFromCurrent)) or
kusano 7d535a
          ( ((Offset - FZRec.total_out) > 0) and (Origin = soFromBeginning)) then
kusano 7d535a
  begin
kusano 7d535a
    if Origin = soFromBeginning then Dec(Offset, FZRec.total_out);
kusano 7d535a
    if Offset > 0 then
kusano 7d535a
    begin
kusano 7d535a
      for I := 1 to Offset div sizeof(Buf) do
kusano 7d535a
        ReadBuffer(Buf, sizeof(Buf));
kusano 7d535a
      ReadBuffer(Buf, Offset mod sizeof(Buf));
kusano 7d535a
    end;
kusano 7d535a
  end
kusano 7d535a
  else
kusano 7d535a
    raise EDecompressionError.CreateRes(@sInvalidStreamOp);
kusano 7d535a
  Result := FZRec.total_out;
kusano 7d535a
end;
kusano 7d535a
kusano 7d535a
kusano 7d535a
end.