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