1027 lines
25 KiB
Plaintext
1027 lines
25 KiB
Plaintext
(* ImageEn Build 7.0.0.06.2637 @ 7-4-17 14:58:42.679 *)
|
|
(*
|
|
Copyright (c) 1998-2017 by Carlotta Calandra. All rights reserved.
|
|
Copyright (c) 2011-2017 by Xequte Software.
|
|
|
|
This software comes without express or implied warranty.
|
|
In no case shall the author be liable for any damage or unwanted behavior of any
|
|
computer hardware and/or software.
|
|
|
|
Author grants you the right to include the component
|
|
in your application, whether COMMERCIAL, SHAREWARE, or FREEWARE.
|
|
|
|
ImageEn, IEvolution and ImageEn ActiveX may not be included in any
|
|
commercial, shareware or freeware libraries or components.
|
|
|
|
www.ImageEn.com
|
|
*)
|
|
|
|
(*
|
|
File version 1005
|
|
*)
|
|
|
|
unit iezlib;
|
|
|
|
{$R-}
|
|
{$Q-}
|
|
|
|
{$I ie.inc}
|
|
|
|
{$IFNDEF IEUSEVCLZLIB}
|
|
|
|
{$IFDEF IEINCLUDEZLIB}
|
|
|
|
|
|
interface
|
|
|
|
uses
|
|
Windows, Graphics, classes, sysutils, ImageEnProc, ImageEnIO, hyiedefs;
|
|
|
|
|
|
type
|
|
|
|
// portions of ZLib
|
|
|
|
EZLibError = class(Exception);
|
|
|
|
EZCompressionError = class(EZLibError);
|
|
EZDecompressionError = class(EZLibError);
|
|
|
|
TZAlloc = function(opaque: Pointer; items, size: Integer): Pointer;
|
|
TZFree = procedure(opaque, block: Pointer);
|
|
TZCompressionLevel = (zcNone, zcFastest, zcDefault, zcMax);
|
|
|
|
TZStreamRec = packed record
|
|
next_in: PAnsiChar; // next input byte
|
|
avail_in: Longint; // number of bytes available at next_in
|
|
total_in: Longint; // total nb of input bytes read so far
|
|
|
|
next_out: PAnsiChar; // next output byte should be put here
|
|
avail_out: Longint; // remaining free space at next_out
|
|
total_out: Longint; // total nb of bytes output so far
|
|
|
|
msg: PAnsiChar; // last error message, NULL if no error
|
|
state: Pointer; // not visible by applications
|
|
|
|
zalloc: TZAlloc; // used to allocate the internal state
|
|
zfree: TZFree; // used to free the internal state
|
|
opaque: Pointer; // private data object passed to zalloc and zfree
|
|
|
|
data_type: Integer; // best guess about the data type: ascii or binary
|
|
adler: Longint; // adler32 value of the uncompressed data
|
|
reserved: Longint; // reserved for future use
|
|
end;
|
|
|
|
TCustomZStream = class(TStream)
|
|
private
|
|
FStream: TStream;
|
|
FStreamPos: Int64;
|
|
FOnProgress: TNotifyEvent;
|
|
|
|
FZStream: TZStreamRec;
|
|
FBuffer: array[Word] of AnsiChar;
|
|
protected
|
|
constructor Create(stream: TStream);
|
|
|
|
procedure DoProgress; dynamic;
|
|
|
|
property OnProgress: TNotifyEvent read FOnProgress write FOnProgress;
|
|
end;
|
|
|
|
TZCompressionStream = class(TCustomZStream)
|
|
private
|
|
function GetCompressionRate: Single;
|
|
public
|
|
constructor Create(dest: TStream; compressionLevel: TZCompressionLevel; windowBits: integer = 15);
|
|
destructor Destroy; override;
|
|
|
|
function Read(var buffer; count: Longint): Longint; override;
|
|
function Write(const buffer; count: Longint): Longint; override;
|
|
function Seek(offset: Longint; origin: Word): Longint; override;
|
|
|
|
property CompressionRate: Single read GetCompressionRate;
|
|
property OnProgress;
|
|
end;
|
|
|
|
TZDecompressionStream = class(TCustomZStream)
|
|
public
|
|
constructor Create(source: TStream);
|
|
destructor Destroy; override;
|
|
|
|
function Read(var buffer; count: Longint): Longint; override;
|
|
function Write(const buffer; count: Longint): Longint; override;
|
|
function Seek(offset: Longint; origin: Word): Longint; override;
|
|
|
|
property OnProgress;
|
|
end;
|
|
|
|
|
|
procedure ZCompress(const inBuffer: Pointer; inSize: Integer; out outBuffer: Pointer; out outSize: Integer; level: TZCompressionLevel);
|
|
procedure ZDecompress(const inBuffer: Pointer; inSize: Integer; out outBuffer: Pointer; out outSize: Integer; outEstimate: Integer);
|
|
function ZCompressStr(const s: AnsiString; level: TZCompressionLevel): AnsiString;
|
|
function ZDecompressStr(const s: AnsiString): AnsiString;
|
|
procedure ZCompressStream(inStream, outStream: TStream; level: TZCompressionLevel);
|
|
procedure ZDecompressStream(inStream, outStream: TStream);
|
|
|
|
procedure IEZDecompress(const inBuffer: Pointer; inSize: Integer; out outBuffer: Pointer; out outSize: Integer; outEstimate: Integer);
|
|
|
|
|
|
|
|
procedure _abort; cdecl; forward;
|
|
function _memcmp(buf1, buf2: pbyte; count: integer): integer; cdecl; forward;
|
|
procedure memset(P: Pointer; B: Byte; count: Integer); cdecl; forward;
|
|
procedure memcpy(dest, source: Pointer; count: Integer); cdecl; forward;
|
|
function _malloc(size: Integer): Pointer; cdecl; forward;
|
|
procedure _free(P: Pointer); cdecl; forward;
|
|
function _fabs(v: double): double; cdecl; forward;
|
|
function _pow(Base, Exponent: double): double; cdecl; forward;
|
|
function __ftol: Integer; cdecl; forward;
|
|
function _strlen(s: PAnsiChar): cardinal; cdecl; forward;
|
|
function _strtod(s: PAnsiChar; var vp: PAnsiChar): double; cdecl;
|
|
|
|
procedure crc32; cdecl; external;
|
|
function deflateInit_(var strm: TZStreamRec; level: Integer; version: PAnsiChar; recsize: Integer): Integer; cdecl; external;
|
|
function deflate(var strm: TZStreamRec; flush: Integer): Integer; cdecl; external;
|
|
function deflateEnd(var strm: TZStreamRec): Integer; cdecl; external;
|
|
function inflateInit_(var strm: TZStreamRec; version: PAnsiChar; recsize: Integer): Integer; cdecl; external;
|
|
function inflate(var strm: TZStreamRec; flush: Integer): Integer; cdecl; external;
|
|
function inflateEnd(var strm: TZStreamRec): Integer; cdecl; external;
|
|
function inflateReset(var strm: TZStreamRec): Integer; cdecl; external;
|
|
procedure deflateInit2_; cdecl; external;
|
|
procedure deflateReset; cdecl; external;
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
math, hyieutils;
|
|
|
|
{$R-}
|
|
|
|
|
|
|
|
|
|
const
|
|
ZLIB_VERSION: AnsiString = '1.2.3';
|
|
|
|
const
|
|
Z_NO_FLUSH = 0;
|
|
Z_PARTIAL_FLUSH = 1;
|
|
Z_SYNC_FLUSH = 2;
|
|
Z_FULL_FLUSH = 3;
|
|
Z_FINISH = 4;
|
|
Z_OK = 0;
|
|
Z_STREAM_END = 1;
|
|
Z_NEED_DICT = 2;
|
|
Z_ERRNO = (-1);
|
|
Z_STREAM_ERROR = (-2);
|
|
Z_DATA_ERROR = (-3);
|
|
Z_MEM_ERROR = (-4);
|
|
Z_BUF_ERROR = (-5);
|
|
Z_VERSION_ERROR = (-6);
|
|
Z_NO_COMPRESSION = 0;
|
|
Z_BEST_SPEED = 1;
|
|
Z_BEST_COMPRESSION = 9;
|
|
Z_DEFAULT_COMPRESSION = (-1);
|
|
Z_FILTERED = 1;
|
|
Z_HUFFMAN_ONLY = 2;
|
|
Z_DEFAULT_STRATEGY = 0;
|
|
Z_BINARY = 0;
|
|
Z_ASCII = 1;
|
|
Z_UNKNOWN = 2;
|
|
Z_DEFLATED = 8;
|
|
z_errmsg: array[0..9] of PWideChar = (
|
|
'need dictionary', // Z_NEED_DICT (2)
|
|
'stream end', // Z_STREAM_END (1)
|
|
'', // Z_OK (0)
|
|
'file error', // Z_ERRNO (-1)
|
|
'stream error', // Z_STREAM_ERROR (-2)
|
|
'data error', // Z_DATA_ERROR (-3)
|
|
'insufficient memory', // Z_MEM_ERROR (-4)
|
|
'buffer error', // Z_BUF_ERROR (-5)
|
|
'incompatible version', // Z_VERSION_ERROR (-6)
|
|
''
|
|
);
|
|
|
|
// Compatibility with ZipForge (3.0.4)
|
|
_z_errmsg: array[0..9] of PAnsiChar = (
|
|
'need dictionary', // Z_NEED_DICT (2)
|
|
'stream end', // Z_STREAM_END (1)
|
|
'', // Z_OK (0)
|
|
'file error', // Z_ERRNO (-1)
|
|
'stream error', // Z_STREAM_ERROR (-2)
|
|
'data error', // Z_DATA_ERROR (-3)
|
|
'insufficient memory', // Z_MEM_ERROR (-4)
|
|
'buffer error', // Z_BUF_ERROR (-5)
|
|
'incompatible version', // Z_VERSION_ERROR (-6)
|
|
''
|
|
);
|
|
|
|
ZLevels: array[TZCompressionLevel] of Shortint = (
|
|
Z_NO_COMPRESSION,
|
|
Z_BEST_SPEED,
|
|
Z_DEFAULT_COMPRESSION,
|
|
Z_BEST_COMPRESSION
|
|
);
|
|
|
|
SZInvalid = 'Invalid ZStream operation!';
|
|
|
|
(*
|
|
{$L deflate.obj}
|
|
{$L inflate.obj}
|
|
{$L infblock.obj}
|
|
{$L inftrees.obj}
|
|
{$L infcodes.obj}
|
|
{$L infutil.obj}
|
|
{$L inffast.obj}
|
|
{$L trees.obj}
|
|
{$L adler32.obj}
|
|
{$L crc32.obj}
|
|
*)
|
|
|
|
{$L deflate.obj}
|
|
{$L inflate.obj}
|
|
{$L inftrees.obj}
|
|
{$L infback.obj}
|
|
{$L inffast.obj}
|
|
{$L trees.obj}
|
|
{$L adler32.obj}
|
|
{$L crc32.obj}
|
|
{$L compress.obj}
|
|
|
|
function zcalloc(opaque: Pointer; items, size: Integer): Pointer; cdecl;
|
|
begin
|
|
GetMem(result, items * size);
|
|
end;
|
|
|
|
procedure zcfree(opaque, block: Pointer); cdecl;
|
|
begin
|
|
FreeMem(block);
|
|
end;
|
|
|
|
function DeflateInit(var stream: TZStreamRec; level: Integer): Integer; cdecl;
|
|
begin
|
|
result := DeflateInit_(stream, level, PAnsiChar(ZLIB_VERSION), SizeOf(TZStreamRec));
|
|
end;
|
|
|
|
function InflateInit(var stream: TZStreamRec): Integer; cdecl;
|
|
begin
|
|
result := InflateInit_(stream, PAnsiChar(ZLIB_VERSION), SizeOf(TZStreamRec));
|
|
end;
|
|
|
|
procedure memset(P: Pointer; B: Byte; count: Integer); cdecl;
|
|
begin
|
|
FillChar(P^, count, B);
|
|
end;
|
|
|
|
// compatibility with ZipForge (3.0.4)
|
|
procedure _memset(P: Pointer; B: byte; Count: integer); cdecl;
|
|
begin
|
|
FillChar(P^, Count, B);
|
|
end;
|
|
|
|
function _memcmp(buf1, buf2: pbyte; count: integer): integer; cdecl;
|
|
begin
|
|
if count = 0 then
|
|
result := 0
|
|
else
|
|
begin
|
|
while true do
|
|
begin
|
|
dec(count);
|
|
if (count=0) or (buf1^<>buf2^) then
|
|
break;
|
|
inc(buf1);
|
|
inc(buf2);
|
|
end;
|
|
result := buf1^ - buf2^;
|
|
end;
|
|
end;
|
|
|
|
|
|
function _strtod(s: PAnsiChar; var vp: PAnsiChar): double; cdecl;
|
|
begin
|
|
vp := @s[IEStrLen(s) - 1]; // !!
|
|
result := IEStrToFloatDefA(s, 0);
|
|
end;
|
|
|
|
procedure _abort; cdecl;
|
|
begin
|
|
end;
|
|
|
|
procedure memcpy(dest, source: Pointer; count: Integer); cdecl;
|
|
begin
|
|
Move(source^, dest^, count);
|
|
end;
|
|
|
|
// Compatibility with ZipForge (3.0.4)
|
|
procedure _memcpy(dest, Source: Pointer; Count: integer); cdecl;
|
|
begin
|
|
Move(Source^, dest^, Count);
|
|
end;
|
|
|
|
function _malloc(size: Integer): Pointer; cdecl;
|
|
begin
|
|
GetMem(Result, size);
|
|
end;
|
|
|
|
procedure _free(P: Pointer); cdecl;
|
|
begin
|
|
FreeMem(P);
|
|
end;
|
|
|
|
function _fabs(v: double): double; cdecl;
|
|
begin
|
|
result := abs(v);
|
|
end;
|
|
|
|
|
|
function _pow(Base, Exponent: double): double; cdecl;
|
|
begin
|
|
if Exponent = 0.0 then
|
|
Result := 1.0 { n**0 = 1 }
|
|
else
|
|
if (Base = 0.0) and (Exponent > 0.0) then
|
|
Result := 0.0 { 0**n = 0, n > 0 }
|
|
else
|
|
if (Frac(Exponent) = 0.0) and (Abs(Exponent) <= MaxInt) then
|
|
Result := IntPower(Base, Trunc(Exponent))
|
|
else
|
|
Result := Exp(Exponent * Ln(Base))
|
|
end;
|
|
|
|
function __ftol: Integer; cdecl;
|
|
var
|
|
f: double;
|
|
begin
|
|
asm
|
|
lea eax, f // BC++ passes floats on the FPU stack
|
|
fstp qword ptr [eax] // Delphi passes floats on the CPU stack
|
|
end;
|
|
Result := Trunc(f);
|
|
end;
|
|
|
|
function _strlen(s: PAnsiChar): cardinal; cdecl;
|
|
begin
|
|
result := IEStrLen(s);
|
|
end;
|
|
|
|
var
|
|
__turboFloat: LongBool = False;
|
|
|
|
|
|
function ZCompressCheck(code: Integer): Integer;
|
|
begin
|
|
result := code;
|
|
|
|
if code < 0 then
|
|
begin
|
|
raise EZCompressionError.Create(z_errmsg[2 - code]);
|
|
end;
|
|
end;
|
|
|
|
function ZDecompressCheck(code: Integer): Integer;
|
|
begin
|
|
Result := code;
|
|
|
|
if code < 0 then
|
|
begin
|
|
raise EZDecompressionError.Create(z_errmsg[2 - code]);
|
|
end;
|
|
end;
|
|
|
|
procedure ZCompress(const inBuffer: Pointer; inSize: Integer;
|
|
out outBuffer: Pointer; out outSize: Integer;
|
|
level: TZCompressionLevel);
|
|
const
|
|
delta = 256;
|
|
var
|
|
zstream: TZStreamRec;
|
|
begin
|
|
FillChar(zstream, SizeOf(TZStreamRec), 0);
|
|
|
|
outSize := ((inSize + (inSize div 10) + 12) + 255) and not 255;
|
|
GetMem(outBuffer, outSize);
|
|
|
|
try
|
|
zstream.next_in := inBuffer;
|
|
zstream.avail_in := inSize;
|
|
zstream.next_out := outBuffer;
|
|
zstream.avail_out := outSize;
|
|
|
|
ZCompressCheck(DeflateInit(zstream, ZLevels[level]));
|
|
|
|
try
|
|
while ZCompressCheck(deflate(zstream, Z_FINISH)) <> Z_STREAM_END do
|
|
begin
|
|
Inc(outSize, delta);
|
|
ReallocMem(outBuffer, outSize);
|
|
|
|
zstream.next_out := PAnsiChar(uint64(outBuffer) + zstream.total_out);
|
|
zstream.avail_out := delta;
|
|
end;
|
|
finally
|
|
ZCompressCheck(deflateEnd(zstream));
|
|
end;
|
|
|
|
ReallocMem(outBuffer, zstream.total_out);
|
|
outSize := zstream.total_out;
|
|
except
|
|
FreeMem(outBuffer);
|
|
raise;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure IEZDecompress(const inBuffer: Pointer; inSize: Integer; out outBuffer: Pointer; out outSize: Integer; outEstimate: Integer);
|
|
begin
|
|
ZDecompress(inBuffer, inSize, outBuffer, outSize, outEstimate);
|
|
end;
|
|
|
|
procedure ZDecompress(const inBuffer: Pointer; inSize: Integer; out outBuffer: Pointer; out outSize: Integer; outEstimate: Integer);
|
|
var
|
|
zstream: TZStreamRec;
|
|
delta: Integer;
|
|
chk: Integer;
|
|
begin
|
|
FillChar(zstream, SizeOf(TZStreamRec), 0);
|
|
|
|
delta := (inSize + 255) and not 255;
|
|
|
|
if outEstimate = 0 then
|
|
outSize := delta
|
|
else
|
|
outSize := outEstimate;
|
|
|
|
GetMem(outBuffer, outSize);
|
|
|
|
try
|
|
zstream.next_in := inBuffer;
|
|
zstream.avail_in := inSize;
|
|
zstream.next_out := outBuffer;
|
|
zstream.avail_out := outSize;
|
|
|
|
ZDecompressCheck(InflateInit(zstream));
|
|
|
|
try
|
|
while true do
|
|
begin
|
|
chk := inflate(zstream, Z_NO_FLUSH);
|
|
if (chk = Z_STREAM_END) or (chk = Z_DATA_ERROR) or (chk = Z_NEED_DICT) or (chk = Z_MEM_ERROR) then
|
|
break;
|
|
ZDecompressCheck(chk); // may raise exception for the cases not covered by previous check
|
|
|
|
Inc(outSize, delta);
|
|
ReallocMem(outBuffer, outSize);
|
|
|
|
zstream.next_out := PAnsiChar(uint64(outBuffer) + zstream.total_out);
|
|
zstream.avail_out := delta;
|
|
end;
|
|
finally
|
|
ZDecompressCheck(inflateEnd(zstream));
|
|
end;
|
|
|
|
ReallocMem(outBuffer, zstream.total_out);
|
|
outSize := zstream.total_out;
|
|
except
|
|
FreeMem(outBuffer);
|
|
raise;
|
|
end;
|
|
end;
|
|
|
|
{** string routines *********************************************************}
|
|
|
|
function ZCompressStr(const s: AnsiString; level: TZCompressionLevel): AnsiString;
|
|
var
|
|
buffer: Pointer;
|
|
size: Integer;
|
|
begin
|
|
ZCompress(PAnsiChar(s), Length(s), buffer, size, level);
|
|
|
|
SetLength(result, size);
|
|
Move(buffer^, result[1], size);
|
|
|
|
FreeMem(buffer);
|
|
end;
|
|
|
|
function ZDecompressStr(const s: AnsiString): AnsiString;
|
|
var
|
|
buffer: Pointer;
|
|
size: Integer;
|
|
begin
|
|
ZDecompress(PAnsiChar(s), Length(s), buffer, size, 0);
|
|
|
|
SetLength(result, size);
|
|
Move(buffer^, result[1], size);
|
|
|
|
FreeMem(buffer);
|
|
end;
|
|
|
|
{** stream routines *********************************************************}
|
|
|
|
procedure ZCompressStream(inStream, outStream: TStream;
|
|
level: TZCompressionLevel);
|
|
const
|
|
bufferSize = 32768;
|
|
var
|
|
zstream: TZStreamRec;
|
|
zresult: Integer;
|
|
inBuffer: array[0..bufferSize - 1] of AnsiChar;
|
|
outBuffer: array[0..bufferSize - 1] of AnsiChar;
|
|
inSize: Integer;
|
|
outSize: Integer;
|
|
begin
|
|
FillChar(zstream, SizeOf(TZStreamRec), 0);
|
|
|
|
ZCompressCheck(DeflateInit(zstream, ZLevels[level]));
|
|
|
|
inSize := inStream.Read(inBuffer, bufferSize);
|
|
|
|
while inSize > 0 do
|
|
begin
|
|
zstream.next_in := inBuffer;
|
|
zstream.avail_in := inSize;
|
|
|
|
repeat
|
|
zstream.next_out := outBuffer;
|
|
zstream.avail_out := bufferSize;
|
|
|
|
ZCompressCheck(deflate(zstream, Z_NO_FLUSH));
|
|
|
|
// outSize := zstream.next_out - outBuffer;
|
|
outSize := bufferSize - zstream.avail_out;
|
|
|
|
outStream.Write(outBuffer, outSize);
|
|
until (zstream.avail_in = 0) and (zstream.avail_out > 0);
|
|
|
|
inSize := inStream.Read(inBuffer, bufferSize);
|
|
end;
|
|
|
|
repeat
|
|
zstream.next_out := outBuffer;
|
|
zstream.avail_out := bufferSize;
|
|
|
|
zresult := ZCompressCheck(deflate(zstream, Z_FINISH));
|
|
|
|
// outSize := zstream.next_out - outBuffer;
|
|
outSize := bufferSize - zstream.avail_out;
|
|
|
|
outStream.Write(outBuffer, outSize);
|
|
until (zresult = Z_STREAM_END) and (zstream.avail_out > 0);
|
|
|
|
ZCompressCheck(deflateEnd(zstream));
|
|
end;
|
|
|
|
procedure ZDecompressStream(inStream, outStream: TStream);
|
|
const
|
|
bufferSize = 32768;
|
|
var
|
|
zstream: TZStreamRec;
|
|
zresult: Integer;
|
|
inBuffer: array[0..bufferSize - 1] of AnsiChar;
|
|
outBuffer: array[0..bufferSize - 1] of AnsiChar;
|
|
inSize: Integer;
|
|
outSize: Integer;
|
|
begin
|
|
FillChar(zstream, SizeOf(TZStreamRec), 0);
|
|
|
|
ZCompressCheck(InflateInit(zstream));
|
|
|
|
inSize := inStream.Read(inBuffer, bufferSize);
|
|
|
|
while inSize > 0 do
|
|
begin
|
|
zstream.next_in := inBuffer;
|
|
zstream.avail_in := inSize;
|
|
|
|
repeat
|
|
zstream.next_out := outBuffer;
|
|
zstream.avail_out := bufferSize;
|
|
|
|
ZCompressCheck(inflate(zstream, Z_NO_FLUSH));
|
|
|
|
// outSize := zstream.next_out - outBuffer;
|
|
outSize := bufferSize - zstream.avail_out;
|
|
|
|
outStream.Write(outBuffer, outSize);
|
|
until (zstream.avail_in = 0) and (zstream.avail_out > 0);
|
|
|
|
inSize := inStream.Read(inBuffer, bufferSize);
|
|
end;
|
|
|
|
repeat
|
|
zstream.next_out := outBuffer;
|
|
zstream.avail_out := bufferSize;
|
|
|
|
zresult := ZCompressCheck(inflate(zstream, Z_FINISH));
|
|
|
|
// outSize := zstream.next_out - outBuffer;
|
|
outSize := bufferSize - zstream.avail_out;
|
|
|
|
outStream.Write(outBuffer, outSize);
|
|
until (zresult = Z_STREAM_END) and (zstream.avail_out > 0);
|
|
|
|
ZCompressCheck(inflateEnd(zstream));
|
|
end;
|
|
|
|
{** TCustomZStream **********************************************************}
|
|
|
|
constructor TCustomZStream.Create(stream: TStream);
|
|
begin
|
|
inherited Create;
|
|
|
|
FStream := stream;
|
|
FStreamPos := stream.Position;
|
|
end;
|
|
|
|
procedure TCustomZStream.DoProgress;
|
|
begin
|
|
if Assigned(FOnProgress) then
|
|
FOnProgress(Self);
|
|
end;
|
|
|
|
{** TZCompressionStream *****************************************************}
|
|
|
|
// windowBits = not used
|
|
constructor TZCompressionStream.Create(dest: TStream; compressionLevel: TZCompressionLevel; windowBits: integer);
|
|
begin
|
|
inherited Create(dest);
|
|
|
|
FZStream.next_out := FBuffer;
|
|
FZStream.avail_out := SizeOf(FBuffer);
|
|
|
|
ZCompressCheck(DeflateInit(FZStream, ZLevels[compressionLevel]));
|
|
end;
|
|
|
|
destructor TZCompressionStream.Destroy;
|
|
begin
|
|
FZStream.next_in := nil;
|
|
FZStream.avail_in := 0;
|
|
|
|
try
|
|
if FStream.Position <> FStreamPos then
|
|
FStream.Position := FStreamPos;
|
|
|
|
while ZCompressCheck(deflate(FZStream, Z_FINISH)) <> Z_STREAM_END do
|
|
begin
|
|
FStream.WriteBuffer(FBuffer, SizeOf(FBuffer) - FZStream.avail_out);
|
|
|
|
FZStream.next_out := FBuffer;
|
|
FZStream.avail_out := SizeOf(FBuffer);
|
|
end;
|
|
|
|
if FZStream.avail_out < SizeOf(FBuffer) then
|
|
begin
|
|
FStream.WriteBuffer(FBuffer, SizeOf(FBuffer) - FZStream.avail_out);
|
|
end;
|
|
finally
|
|
deflateEnd(FZStream);
|
|
end;
|
|
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TZCompressionStream.Read(var buffer; count: Longint): Longint;
|
|
begin
|
|
raise EZCompressionError.Create(SZInvalid);
|
|
end;
|
|
|
|
function TZCompressionStream.Write(const buffer; count: Longint): Longint;
|
|
begin
|
|
FZStream.next_in := @buffer;
|
|
FZStream.avail_in := count;
|
|
|
|
if FStream.Position <> FStreamPos then
|
|
FStream.Position := FStreamPos;
|
|
|
|
while FZStream.avail_in > 0 do
|
|
begin
|
|
ZCompressCheck(deflate(FZStream, Z_NO_FLUSH));
|
|
|
|
if FZStream.avail_out = 0 then
|
|
begin
|
|
FStream.WriteBuffer(FBuffer, SizeOf(FBuffer));
|
|
|
|
FZStream.next_out := FBuffer;
|
|
FZStream.avail_out := SizeOf(FBuffer);
|
|
|
|
FStreamPos := FStream.Position;
|
|
|
|
DoProgress;
|
|
end;
|
|
end;
|
|
|
|
result := Count;
|
|
end;
|
|
|
|
// 3.0.1
|
|
function TZCompressionStream.Seek(offset: Longint; origin: Word): Longint;
|
|
begin
|
|
result := FZStream.total_in;
|
|
end;
|
|
|
|
function TZCompressionStream.GetCompressionRate: Single;
|
|
begin
|
|
if FZStream.total_in = 0 then
|
|
result := 0
|
|
else
|
|
result := (1.0 - (FZStream.total_out / FZStream.total_in)) * 100.0;
|
|
end;
|
|
|
|
{** TZDecompressionStream ***************************************************}
|
|
|
|
constructor TZDecompressionStream.Create(source: TStream);
|
|
begin
|
|
inherited Create(source);
|
|
|
|
FZStream.next_in := FBuffer;
|
|
FZStream.avail_in := 0;
|
|
|
|
ZDecompressCheck(InflateInit(FZStream));
|
|
end;
|
|
|
|
destructor TZDecompressionStream.Destroy;
|
|
begin
|
|
inflateEnd(FZStream);
|
|
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TZDecompressionStream.Read(var buffer; count: Longint): Longint;
|
|
var
|
|
zresult: Integer;
|
|
begin
|
|
FZStream.next_out := @buffer;
|
|
FZStream.avail_out := count;
|
|
|
|
if FStream.Position <> FStreamPos then
|
|
FStream.Position := FStreamPos;
|
|
|
|
zresult := Z_OK;
|
|
|
|
while (FZStream.avail_out > 0) and (zresult <> Z_STREAM_END) do
|
|
begin
|
|
if FZStream.avail_in = 0 then
|
|
begin
|
|
FZStream.avail_in := FStream.Read(FBuffer, SizeOf(FBuffer));
|
|
|
|
if FZStream.avail_in = 0 then
|
|
begin
|
|
result := count - FZStream.avail_out;
|
|
|
|
Exit;
|
|
end;
|
|
|
|
FZStream.next_in := FBuffer;
|
|
FStreamPos := FStream.Position;
|
|
|
|
DoProgress;
|
|
end;
|
|
|
|
zresult := ZDecompressCheck(inflate(FZStream, Z_NO_FLUSH));
|
|
end;
|
|
|
|
if (zresult = Z_STREAM_END) and (FZStream.avail_in > 0) then
|
|
begin
|
|
FStream.Position := FStream.Position - FZStream.avail_in;
|
|
FStreamPos := FStream.Position;
|
|
|
|
FZStream.avail_in := 0;
|
|
end;
|
|
|
|
result := count - FZStream.avail_out;
|
|
end;
|
|
|
|
function TZDecompressionStream.Write(const Buffer; Count: Longint): Longint;
|
|
begin
|
|
raise EZDecompressionError.Create(SZInvalid);
|
|
end;
|
|
|
|
function TZDecompressionStream.Seek(Offset: Longint; Origin: Word): Longint;
|
|
var
|
|
buf: array[0..8191] of AnsiChar;
|
|
i: Integer;
|
|
begin
|
|
if (offset = 0) and (origin = soFromBeginning) then
|
|
begin
|
|
ZDecompressCheck(inflateReset(FZStream));
|
|
|
|
FZStream.next_in := FBuffer;
|
|
FZStream.avail_in := 0;
|
|
|
|
FStream.Position := 0;
|
|
FStreamPos := 0;
|
|
end
|
|
else
|
|
if ((offset >= 0) and (origin = soFromCurrent)) or
|
|
(((offset - FZStream.total_out) > 0) and (origin = soFromBeginning)) then
|
|
begin
|
|
if origin = soFromBeginning then
|
|
Dec(offset, FZStream.total_out);
|
|
|
|
if offset > 0 then
|
|
begin
|
|
for i := 1 to offset div SizeOf(buf) do
|
|
ReadBuffer(buf, SizeOf(buf));
|
|
ReadBuffer(buf, offset mod SizeOf(buf));
|
|
end;
|
|
end
|
|
else
|
|
if (offset = 0) and (origin = soFromEnd) then
|
|
begin
|
|
while Read(buf, SizeOf(buf)) > 0 do
|
|
;
|
|
end
|
|
else
|
|
raise EZDecompressionError.Create(SZInvalid);
|
|
|
|
result := FZStream.total_out;
|
|
end;
|
|
|
|
|
|
|
|
{$else} // IEINCLUDEZLIB
|
|
|
|
|
|
|
|
interface
|
|
|
|
uses
|
|
Windows, Graphics, classes, sysutils, ImageEnProc, ImageEnIO, hyiedefs, hyieutils;
|
|
|
|
type
|
|
|
|
TZCompressionLevel = (zcNone, zcFastest, zcDefault, zcMax);
|
|
|
|
TZCompressionStream = class(TStream)
|
|
private
|
|
fDest: TStream;
|
|
public
|
|
constructor Create(dest: TStream; compressionLevel: TZCompressionLevel; windowBits: integer = 15);
|
|
destructor Destroy; override;
|
|
|
|
function Read(var buffer; count: Longint): Longint; override;
|
|
function Write(const buffer; count: Longint): Longint; override;
|
|
function Seek(offset: Longint; origin: Word): Longint; override;
|
|
|
|
end;
|
|
|
|
TZDecompressionStream = class(TStream)
|
|
private
|
|
fSource: TStream;
|
|
public
|
|
constructor Create(source: TStream);
|
|
destructor Destroy; override;
|
|
|
|
function Read(var buffer; count: Longint): Longint; override;
|
|
function Write(const buffer; count: Longint): Longint; override;
|
|
function Seek(offset: Longint; origin: Word): Longint; override;
|
|
|
|
end;
|
|
|
|
|
|
implementation
|
|
|
|
constructor TZCompressionStream.Create(dest: TStream; compressionLevel: TZCompressionLevel; windowBits: integer = 15);
|
|
begin
|
|
inherited Create;
|
|
fDest := dest;
|
|
end;
|
|
|
|
destructor TZCompressionStream.Destroy;
|
|
begin
|
|
inherited;
|
|
end;
|
|
|
|
function TZCompressionStream.Read(var buffer; count: Longint): Longint;
|
|
begin
|
|
result := fDest.Read(buffer, count);
|
|
end;
|
|
|
|
function TZCompressionStream.Write(const buffer; count: Longint): Longint;
|
|
begin
|
|
result := fDest.Write(buffer, count);
|
|
end;
|
|
|
|
function TZCompressionStream.Seek(offset: Longint; origin: Word): Longint;
|
|
begin
|
|
result := fDest.Seek(offset, origin);
|
|
end;
|
|
|
|
///////////////////
|
|
|
|
constructor TZDecompressionStream.Create(source: TStream);
|
|
begin
|
|
inherited Create;
|
|
fSource := source;
|
|
end;
|
|
|
|
destructor TZDecompressionStream.Destroy;
|
|
begin
|
|
inherited;
|
|
end;
|
|
|
|
function TZDecompressionStream.Read(var buffer; count: Longint): Longint;
|
|
begin
|
|
result := fSource.Read(buffer, count);
|
|
end;
|
|
|
|
function TZDecompressionStream.Write(const buffer; count: Longint): Longint;
|
|
begin
|
|
result := fSource.Write(buffer, count);
|
|
end;
|
|
|
|
function TZDecompressionStream.Seek(offset: Longint; origin: Word): Longint;
|
|
begin
|
|
result := fSource.Seek(offset, origin);
|
|
end;
|
|
|
|
|
|
{$endif} // IEINCLUDEZLIB
|
|
|
|
{$else} // IEUSEVCLZLIB
|
|
|
|
interface
|
|
|
|
procedure IEZDecompress(const inBuffer: Pointer; inSize: Integer; out outBuffer: Pointer; out outSize: Integer; outEstimate: Integer);
|
|
|
|
implementation
|
|
|
|
uses zlib;
|
|
|
|
|
|
|
|
function ZDecompressCheck(code: Integer): Integer;
|
|
begin
|
|
Result := code;
|
|
if code < 0 then
|
|
begin
|
|
raise EZDecompressionError.Create('Error');
|
|
end;
|
|
end;
|
|
|
|
procedure IEZDecompress(const inBuffer: Pointer; inSize: Integer; out outBuffer: Pointer; out outSize: Integer; outEstimate: Integer);
|
|
var
|
|
zstream: TZStreamRec;
|
|
delta: Integer;
|
|
chk: Integer;
|
|
begin
|
|
FillChar(zstream, SizeOf(TZStreamRec), 0);
|
|
|
|
delta := (inSize + 255) and not 255;
|
|
|
|
if outEstimate = 0 then
|
|
outSize := delta
|
|
else
|
|
outSize := outEstimate;
|
|
|
|
GetMem(outBuffer, outSize);
|
|
|
|
try
|
|
zstream.next_in := inBuffer;
|
|
zstream.avail_in := inSize;
|
|
zstream.next_out := outBuffer;
|
|
zstream.avail_out := outSize;
|
|
|
|
ZDecompressCheck(InflateInit(zstream));
|
|
|
|
try
|
|
while true do
|
|
begin
|
|
chk := inflate(zstream, Z_NO_FLUSH);
|
|
if (chk = Z_STREAM_END) or (chk = Z_DATA_ERROR) or (chk = Z_NEED_DICT) or (chk = Z_MEM_ERROR) then
|
|
break;
|
|
ZDecompressCheck(chk); // may raise exception for the cases not covered by previous check
|
|
|
|
Inc(outSize, delta);
|
|
ReallocMem(outBuffer, outSize);
|
|
|
|
zstream.next_out := PByte(uint64(outBuffer) + zstream.total_out);
|
|
zstream.avail_out := delta;
|
|
end;
|
|
finally
|
|
ZDecompressCheck(inflateEnd(zstream));
|
|
end;
|
|
|
|
ReallocMem(outBuffer, zstream.total_out);
|
|
outSize := zstream.total_out;
|
|
except
|
|
FreeMem(outBuffer);
|
|
raise;
|
|
end;
|
|
end;
|
|
|
|
|
|
{$endif} // IEUSEVCLZLIB
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|