{
Zlib – библиотека сжатия данных общего назначения. Версия 1.1.0
Это изменённая объектно-ориентированная версия библиотеки, полностью
совместимая с оригинальной библиотекой.
Copyright © 1995–2005 Jean-loup Gailly и Mark Adler
Copyright © 2000–2011 ymnk, JCraft, Inc.
Copyright © 2016, 2019, 2022–2023 Малик Разработчик
Эта библиотека поставляется «как есть», без каких-либо явных или
подразумеваемых гарантий. Ни при каких обстоятельствах авторы не
несут какой-либо ответственности в случае потери данных вследствие
использования данной библиотеки.
Разрешается всем использовать эту библиотеку для любых целей, в том
числе и для коммерческих приложений, а также изменять её и
распространять свободно при соблюдении следующих условий:
1. Оригинал библиотеки не должен быть искажён; вы не должны
заявлять, что именно вы написали оригинальную библиотеку. Если вы
используете эту библиотеку в своём программном продукте, то ссылка
на авторов библиотеки была бы желательна, но это не является
обязательным требованием.
2. Изменённые версии исходных текстов должны быть отчётливо
маркированы и не должны выдаваться за оригинал библиотеки.
3. Эти замечания не могут быть удалены либо изменены при
каком-либо варианте распространения исходных текстов.
}
unit Zlib;
{$MODE DELPHI}
interface
uses
Lang,
IOStreams;
{%region public }
const
VERSION = '1.1.0';
MAX_WBITS = int(15);
DEF_WBITS = MAX_WBITS;
DEFAULT_COMPRESSION = int(-1);
NO_COMPRESSION = int(0);
BEST_SPEED = int(1);
OPTIMAL_SPEED_COMPRESSION = int(7);
BEST_COMPRESSION = int(9);
FILTERED = int(1);
HUFFMAN_ONLY = int(2);
DEFAULT_STRATEGY = int(0);
NO_FLUSH = int(0);
PARTIAL_FLUSH = int(1);
SYNC_FLUSH = int(2);
FULL_FLUSH = int(3);
FINISH = int(4);
OK = int(0);
STREAM_END = int(1);
NEED_DICT = int(2);
ERRNO = int(-1);
STREAM_ERROR = int(-2);
DATA_ERROR = int(-3);
MEM_ERROR = int(-4);
BUF_ERROR = int(-5);
const
CHECKSUM32_GUID = '{74C86B60-AC5B-4E8D-8ACD-29A50B5C1508}';
DATA_STREAM_GUID = '{74C86B60-AC5B-4E8D-8ACD-29A50B5C1509}';
DEFLATER_GUID = '{74C86B60-AC5B-4E8D-8ACD-29A50B5C150A}';
INFLATER_GUID = '{74C86B60-AC5B-4E8D-8ACD-29A50B5C150B}';
type
Checksum32 = interface;
DataStream = interface;
Deflater = interface;
Inflater = interface;
Adler32 = class;
Crc32 = class;
Config = class;
StaticTree = class;
GZIPHeader = class;
Tree = class;
Deflate = class;
Inflate = class;
InfTree = class;
InfCodes = class;
InfBlocks = class;
ZStream = class;
Config_Array1d = array of Config;
Checksum32 = interface(_Interface) [CHECKSUM32_GUID]
procedure update(const buf: byte_Array1d; offset, length: int);
procedure reset(init: int); overload;
procedure reset(); overload;
function getValue(): int;
function copy(): Checksum32;
end;
DataStream = interface(_Interface) [DATA_STREAM_GUID]
procedure setAvailIn(availIn: int);
procedure setAvailOut(availOut: int);
procedure setNextIn(const nextIn: byte_Array1d);
procedure setNextInIndex(nextInIndex: int);
procedure setNextOut(const nextOut: byte_Array1d);
procedure setNextOutIndex(nextOutIndex: int);
procedure setInput(const data: byte_Array1d); overload;
procedure setInput(const data: byte_Array1d; append: boolean); overload;
procedure setInput(const data: byte_Array1d; offset, length: int; append: boolean); overload;
procedure setOutput(const data: byte_Array1d); overload;
procedure setOutput(const data: byte_Array1d; ofs, len: int); overload;
function getChecksum(): int;
function getAvailIn(): int;
function getAvailOut(): int;
function getNextInIndex(): int;
function getNextOutIndex(): int;
function getTotalIn(): long;
function getTotalOut(): long;
function getNextIn(): byte_Array1d;
function getNextOut(): byte_Array1d;
function getMessage(): AnsiString;
end;
Deflater = interface(DataStream) [DEFLATER_GUID]
function deflateInit(level: int): int; overload;
function deflateInit(level: int; nowrap: boolean): int; overload;
function deflateInit(level, bits: int): int; overload;
function deflateInit(level, bits, memlevel: int): int; overload;
function deflateInit(level, bits: int; nowrap: boolean): int; overload;
function deflateSetDictionary(const dictionary: byte_Array1d; dictLength: int): int;
function deflateParams(level, strategy: int): int;
function deflate(flush: int): int;
function deflateEnd(): int;
end;
Inflater = interface(DataStream) [INFLATER_GUID]
function inflateInit(): int; overload;
function inflateInit(w: int): int; overload;
function inflateInit(nowrap: boolean): int; overload;
function inflateInit(w: int; nowrap: boolean): int; overload;
function inflateSetDictionary(const dictionary: byte_Array1d; dictLength: int): int;
function inflateSync(): int;
function inflateSyncPoint(): int;
function inflate(flush: int): int;
function inflateEnd(): int;
function inflateFinished(): boolean;
end;
Adler32 = class(RefCountInterfacedObject, Checksum32)
strict private
adler: int;
public
constructor create(); overload;
constructor create(adler: int); overload;
procedure update(const buf: byte_Array1d; offset, length: int);
procedure reset(init: int); overload;
procedure reset(); overload;
function getValue(): int;
function copy(): Checksum32;
strict private const
BASE = int(65521);
NMAX = int(5552);
end;
Crc32 = class(RefCountInterfacedObject, Checksum32)
strict private
crc: int;
public
constructor create(); overload;
constructor create(crc: int); overload;
procedure update(const buf: byte_Array1d; offset, length: int);
procedure reset(init: int); overload;
procedure reset(); overload;
function getValue(): int;
function copy(): Checksum32;
strict private
TABLE: int_Array1d; static;
private
class procedure clinit();
class procedure cldone();
end;
Config = class(_Object)
private
goodLength: int;
maxLazy: int;
niceLength: int;
maxChain: int;
func: int;
public
constructor create(goodLength, maxLazy, niceLength, maxChain, func: int);
end;
StaticTree = class(_Object)
private
staticTree: int_Array1d;
extraBits: int_Array1d;
extraBase: int;
elems: int;
maxLength: int;
public
constructor create(const staticTree, extraBits: int_Array1d; extraBase, elems, maxLength: int);
strict private const
MAX_BITS = int(15);
BL_CODES = int(19);
D_CODES = int(30);
LITERALS = int(256);
LENGTH_CODES = int(29);
L_CODES = LITERALS + LENGTH_CODES + 1;
private const
MAX_BL_BITS = int(7);
private
STATIC_LTREE: int_Array1d; static;
STATIC_DTREE: int_Array1d; static;
EXTRA_LBITS: int_Array1d; static;
EXTRA_DBITS: int_Array1d; static;
EXTRA_BLBITS: int_Array1d; static;
STATIC_L_DESC: StaticTree; static;
STATIC_D_DESC: StaticTree; static;
STATIC_BL_DESC: StaticTree; static;
class procedure clinit();
class procedure cldone();
end;
GZIPHeader = class(_Object)
strict private
fhcrc: boolean;
text: boolean;
mtime: int;
private
xflags: int;
os: int;
hcrc: int;
time: int;
crc: int;
extra: byte_Array1d;
name: byte_Array1d;
comment: byte_Array1d;
procedure put(d: Deflate);
public
constructor create();
procedure setName(const name: AnsiString);
procedure setComment(const comment: AnsiString);
procedure setModifiedTime(mtime: int);
procedure setCRC(crc: int);
procedure setOS(os: int);
function getName(): AnsiString;
function getComment(): AnsiString;
function getModifiedTime(): int;
function getCRC(): int;
function getOS(): int;
end;
Tree = class(_Object)
strict private
procedure genBitlen(s: Deflate);
private
maxCode: int;
dynTree: int_Array1d;
statDesc: StaticTree;
public
constructor create();
procedure buildTree(s: Deflate);
strict private const
MAX_BITS = int(15);
LITERALS = int(256);
LENGTH_CODES = int(29);
L_CODES = LITERALS + LENGTH_CODES + 1;
HEAP_SIZE = 2 * L_CODES + 1;
strict private
class procedure genCodes(const tree: int_Array1d; maxCode: int; const blCount: int_Array1d);
class function biReverse(code, len: int): int;
end;
Deflate = class(_Object)
strict private
status: int;
pendingBufSize: int;
dataType: int;
lastFlush: int;
wSize: int;
wBits: int;
wMask: int;
windowSize: int;
insh: int;
hashSize: int;
hashBits: int;
hashMask: int;
hashShift: int;
blockStart: int;
matchLength: int;
prevMatch: int;
matchAvailable: int;
strStart: int;
matchStart: int;
lookahead: int;
prevLength: int;
maxChainLength: int;
maxLazyMatch: int;
strategy: int;
goodMatch: int;
niceMatch: int;
litBufSize: int;
lastLit: int;
matches: int;
lastEobLen: int;
lBuf: int;
dBuf: int;
biBuf: int;
biValid: int;
window: byte_Array1d;
prev: int_Array1d;
head: int_Array1d;
dynLtree: int_Array1d;
dynDtree: int_Array1d;
blTree: int_Array1d;
lDesc: Tree;
dDesc: Tree;
blDesc: Tree;
gheader: GZIPHeader;
stream: ZStream;
procedure lmInit();
procedure trInit();
procedure initBlock();
procedure scanTree(const tree: int_Array1d; maxCode: int);
procedure sendAllTrees(lcodes, dcodes, blcodes: int);
procedure sendTree(const tree: int_Array1d; maxCode: int);
procedure putShortMSB(b: int);
procedure sendCode(c: int; const tree: int_Array1d);
procedure sendBits(val, len: int);
procedure trAlign();
procedure compressBlock(const ltree, dtree: int_Array1d);
procedure setDataType();
procedure biFlush();
procedure biWindup();
procedure copyBlock(buf, len: int; header: boolean);
procedure flushBlockOnly(eof: boolean);
procedure trStoredBlock(buf, storedLen: int; eof: boolean);
procedure trFlushBlock(buf, storedLen: int; eof: boolean);
procedure fillWindow();
function trTally(dist, lc: int): boolean;
function buildBlTree(): int;
function deflateStored(flush: int): int;
function deflateFast(flush: int): int;
function deflateSlow(flush: int): int;
function deflateReset(): int;
function deflateInit(level, method, windowBits, memLevel, strategy: int): int; overload;
function longestMatch(curMatch: int): int;
function getGZIPHeader(): GZIPHeader;
private
pendingOut: int;
pending: int;
wrap: int;
level: int;
heapLen: int;
heapMax: int;
optLen: int;
staticLen: int;
blCount: int_Array1d;
heap: int_Array1d;
pendingBuf: byte_Array1d;
depth: byte_Array1d;
procedure pqDownHeap(const tree: int_Array1d; k: int);
procedure putBytes(const data: byte_Array1d; offset, length: int);
procedure putByte(c: int);
procedure putShort(w: int);
function deflateInit(level, bits, memlevel: int): int; overload;
function deflateInit(level, bits: int): int; overload;
function deflateInit(level: int): int; overload;
function deflateEnd(): int;
function deflateParams(lvl, strtg: int): int;
function deflateSetDictionary(const dictionary: byte_Array1d; dictLength: int): int;
function deflate(flush: int): int;
public
constructor create(stream: ZStream);
destructor destroy; override;
strict private const
NEED_MORE = int(0);
BLOCK_DONE = int(1);
FINISH_STARTED = int(2);
FINISH_DONE = int(3);
PRESET_DICT = int($20);
INIT_STATE = int(42);
BUSY_STATE = int(113);
FINISH_STATE = int(666);
Z_DEFLATED = int(8);
STORED_BLOCK = int(0);
STATIC_TREES = int(1);
DYN_TREES = int(2);
Z_BINARY = int(0);
Z_ASCII = int(1);
Z_UNKNOWN = int(2);
BUF_SIZE = int(8 * 2);
REP_3_6 = int(16);
REPZ_3_10 = int(17);
REPZ_11_138 = int(18);
MIN_MATCH = int(3);
MAX_MATCH = int(258);
MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1;
MAX_BITS = int(15);
D_CODES = int(30);
BL_CODES = int(19);
LENGTH_CODES = int(29);
LITERALS = int(256);
L_CODES = LITERALS + LENGTH_CODES + 1;
HEAP_SIZE = 2 * L_CODES + 1;
END_BLOCK = int(256);
MAX_MEM_LEVEL = int(9);
DEF_MEM_LEVEL = int(8);
STORED = int(0);
FAST = int(1);
SLOW = int(2);
strict private
DIST_CODE: byte_Array1d; static;
BL_ORDER: byte_Array1d; static;
LENGTH_CODE: byte_Array1d; static;
BASE_LENGTH: int_Array1d; static;
BASE_DIST: int_Array1d; static;
CONFIG_TABLE: Config_Array1d; static;
ERR_MSG: AnsiString_Array1d; static;
private
class procedure clinit();
class procedure cldone();
class function smaller(const tree: int_Array1d; n, m: int; const depth: byte_Array1d): boolean;
class function dcode(dist: int): int;
end;
Inflate = class(_Object)
strict private
readReturn: boolean;
method: int;
marker: int;
wbits: int;
was: int;
need: int;
flags: int;
needBytes: int;
crcbuf: byte_Array1d;
tmpString: ByteArrayOutputStream;
blocks: InfBlocks;
gheader: GZIPHeader;
stream: ZStream;
procedure checksum(n, v: int);
function inflateReset(): int;
function readBytes(z: ZStream; n, r, f: int): int; overload;
function readBytes(z: ZStream; r, f: int): int; overload;
function readString(z: ZStream; r, f: int): int;
private
mode: int;
wrap: int;
function inflateEnd(): int;
function inflateInit(w: int): int;
function inflate(f: int): int;
function inflateSetDictionary(const dictionary: byte_Array1d; dictLength: int): int;
function inflateSync(): int;
function inflateSyncPoint(): int;
public
constructor create(stream: ZStream);
destructor destroy; override;
strict private const
PRESET_DICT = int($20);
Z_DEFLATED = int(8);
DICT4 = int(2);
DICT3 = int(3);
DICT2 = int(4);
DICT1 = int(5);
DICT0 = int(6);
BLOCKS_ = int(7);
CHECK4 = int(8);
CHECK3 = int(9);
CHECK2 = int(10);
CHECK1 = int(11);
DONE = int(12);
BAD = int(13);
HEAD = int(14);
LENGTH_ = int(15);
TIME = int(16);
OS = int(17);
EXLEN = int(18);
EXTRA = int(19);
NAME = int(20);
COMMENT = int(21);
HCRC = int(22);
FLAGS_ = int(23);
strict private
MARK: byte_Array1d; static;
private
class procedure clinit();
class procedure cldone();
end;
InfTree = class(_Object)
strict private
hn: int_Array1d;
v: int_Array1d;
c: int_Array1d;
r: int_Array1d;
u: int_Array1d;
x: int_Array1d;
procedure initWorkArea(vsize: int);
function huftBuild(const b: int_Array1d; bindex, n, s: int; const d, e, t, m, hp, hn, v: int_Array1d): int;
private
function inflateTreesBits(const c, bb, tb, hp: int_Array1d; z: ZStream): int;
function inflateTreesDynamic(nl, nd: int; const c, bl, bd, tl, td, hp: int_Array1d; z: ZStream): int;
public
constructor create();
strict private const
MANY = int(1440);
BMAX = int(15);
FIXED_BL = int(9);
FIXED_BD = int(5);
strict private
FIXED_TL: int_Array1d; static;
FIXED_TD: int_Array1d; static;
CPLENS: int_Array1d; static;
CPLEXT: int_Array1d; static;
CPDIST: int_Array1d; static;
CPDEXT: int_Array1d; static;
private
class procedure clinit();
class procedure cldone();
class procedure inflateTreesFixed(const bl, bd: int_Array1d; const tl, td: int_Array2d);
end;
InfCodes = class(_Object)
strict private
lbits: int;
dbits: int;
mode: int;
len: int;
need: int;
lit: int;
get: int;
dist: int;
treeIndex: int;
ltreeIndex: int;
dtreeIndex: int;
tree: int_Array1d;
ltree: int_Array1d;
dtree: int_Array1d;
function inflateFast(bl, bd: int; const tl: int_Array1d; tlIndex: int; const td: int_Array1d; tdIndex: int; s: InfBlocks; z: ZStream): int;
private
procedure init(bl, bd: int; const tl: int_Array1d; tlIndex: int; const td: int_Array1d; tdIndex: int);
function proc(s: InfBlocks; z: ZStream; r: int): int;
public
constructor create();
strict private const
START = int(0);
LEN_ = int(1);
LENEXT = int(2);
DIST_ = int(3);
DISTEXT = int(4);
COPY = int(5);
LIT_ = int(6);
WASH = int(7);
END_ = int(8);
BADCODE = int(9);
strict private
INFLATE_MASK: int_Array1d; static;
private
class procedure clinit();
class procedure cldone();
end;
InfBlocks = class(_Object)
strict private
check: boolean;
mode: int;
left: int;
table: int;
index: int;
last: int;
blens: int_Array1d;
bb: int_Array1d;
tb: int_Array1d;
hufts: int_Array1d;
codes: InfCodes;
itree: InfTree;
procedure proc1();
private
bitk: int;
bitb: int;
end_: int;
read: int;
write: int;
window: byte_Array1d;
procedure reset(z: ZStream);
procedure free(z: ZStream); overload;
procedure setDictionary(const d: byte_Array1d; start, n: int);
procedure update(z: ZStream; b, k, n, p, q: int);
function proc(z: ZStream; r: int): int;
function inflateFlush(z: ZStream; r: int): int;
function syncPoint(): boolean;
public
constructor create(z: ZStream; w: int);
destructor destroy; override;
strict private const
MANY = int(1440);
TYPE_ = int(0);
LENS = int(1);
STORED = int(2);
TABLE_ = int(3);
BTREE = int(4);
DTREE = int(5);
CODES_ = int(6);
DRY = int(7);
DONE = int(8);
BAD = int(9);
strict private
INFLATE_MASK: int_Array1d; static;
BORDER: int_Array1d; static;
private
class procedure clinit();
class procedure cldone();
end;
ZStream = class(RefCountInterfacedObject, DataStream, Deflater, Inflater)
private
dataType: int;
nextInIndex: int;
availIn: int;
nextOutIndex: int;
availOut: int;
totalIn: long;
totalOut: long;
nextIn: byte_Array1d;
nextOut: byte_Array1d;
dstate: Deflate;
istate: Inflate;
adler: Checksum32;
msg: AnsiString;
procedure flushPending();
function readBuf(const dst: byte_Array1d; offset, count: int): int;
public
constructor create();
destructor destroy; override;
{ DataStream }
procedure setAvailIn(availIn: int);
procedure setAvailOut(availOut: int);
procedure setNextIn(const nextIn: byte_Array1d);
procedure setNextInIndex(nextInIndex: int);
procedure setNextOut(const nextOut: byte_Array1d);
procedure setNextOutIndex(nextOutIndex: int);
procedure setInput(const data: byte_Array1d); overload;
procedure setInput(const data: byte_Array1d; append: boolean); overload;
procedure setInput(const data: byte_Array1d; offset, length: int; append: boolean); overload;
procedure setOutput(const data: byte_Array1d); overload;
procedure setOutput(const data: byte_Array1d; offset, length: int); overload;
function getChecksum(): int;
function getAvailIn(): int;
function getAvailOut(): int;
function getNextInIndex(): int;
function getNextOutIndex(): int;
function getTotalIn(): long;
function getTotalOut(): long;
function getNextIn(): byte_Array1d;
function getNextOut(): byte_Array1d;
function getMessage(): AnsiString;
{ Deflater }
function deflateInit(level: int): int; overload;
function deflateInit(level: int; nowrap: boolean): int; overload;
function deflateInit(level, bits: int): int; overload;
function deflateInit(level, bits, memlevel: int): int; overload;
function deflateInit(level, bits: int; nowrap: boolean): int; overload;
function deflateSetDictionary(const dictionary: byte_Array1d; dictLength: int): int;
function deflateParams(level, strategy: int): int;
function deflate(flush: int): int;
function deflateEnd(): int;
{ Inflater }
function inflateInit(): int; overload;
function inflateInit(w: int): int; overload;
function inflateInit(nowrap: boolean): int; overload;
function inflateInit(w: int; nowrap: boolean): int; overload;
function inflateSetDictionary(const dictionary: byte_Array1d; dictLength: int): int;
function inflateSync(): int;
function inflateSyncPoint(): int;
function inflate(flush: int): int;
function inflateEnd(): int;
function inflateFinished(): boolean;
end;
{%endregion}
{%region routine }
function encodeISO88591(const s: UnicodeString): byte_Array1d;
function decodeISO88591(const b: byte_Array1d): UnicodeString;
function compress(const data: byte_Array1d): byte_Array1d; overload;
function compress(const data: byte_Array1d; offset, length: int): byte_Array1d; overload;
function compress(const data: byte_Array1d; defaultInit: boolean): byte_Array1d; overload;
function compress(const data: byte_Array1d; offset, length: int; defaultInit: boolean): byte_Array1d; overload;
function compress(const data: byte_Array1d; level: int): byte_Array1d; overload;
function compress(const data: byte_Array1d; offset, length, level: int): byte_Array1d; overload;
function compress(const data: byte_Array1d; level: int; defaultInit: boolean): byte_Array1d; overload;
function compress(const data: byte_Array1d; offset, length, level: int; defaultInit: boolean): byte_Array1d; overload;
function decompress(const data: byte_Array1d): byte_Array1d; overload;
function decompress(const data: byte_Array1d; offset, length: int): byte_Array1d; overload;
function decompress(const data: byte_Array1d; defaultInit: boolean): byte_Array1d; overload;
function decompress(const data: byte_Array1d; offset, length: int; defaultInit: boolean): byte_Array1d; overload;
{%endregion}
implementation
{%region routine }
function toConfigArray1d(const arr: array of Config): Config_Array1d;
begin
setLength(result, length(arr));
move(arr[0], result[0], length(result) * sizeof(_Object));
end;
function predinc(var target: int): int; inline;
begin
inc(target);
result := target;
end;
function encodeISO88591(const s: UnicodeString): byte_Array1d;
var
i: int;
c: int;
begin
result := byte_Array1d_create(length(s));
for i := 0 to length(result) - 1 do begin
c := int(s[i + 1]);
if (c >= $0000) and (c <= $00ff) then begin
result[i] := byte(c);
end else begin
result[i] := $3f;
end;
end;
end;
function decodeISO88591(const b: byte_Array1d): UnicodeString;
var
i: int;
begin
result := UnicodeString_create(length(b));
for i := 1 to length(result) do begin
result[i] := wchar(b[i - 1] and $ff);
end;
end;
function compress(const data: byte_Array1d): byte_Array1d;
begin
result := compress(data, 0, length(data), OPTIMAL_SPEED_COMPRESSION, true);
end;
function compress(const data: byte_Array1d; offset, length: int): byte_Array1d;
begin
result := compress(data, offset, length, OPTIMAL_SPEED_COMPRESSION, true);
end;
function compress(const data: byte_Array1d; defaultInit: boolean): byte_Array1d;
begin
result := compress(data, 0, length(data), OPTIMAL_SPEED_COMPRESSION, defaultInit);
end;
function compress(const data: byte_Array1d; offset, length: int; defaultInit: boolean): byte_Array1d;
begin
result := compress(data, offset, length, OPTIMAL_SPEED_COMPRESSION, defaultInit);
end;
function compress(const data: byte_Array1d; level: int): byte_Array1d;
begin
result := compress(data, 0, length(data), level, true);
end;
function compress(const data: byte_Array1d; offset, length, level: int): byte_Array1d;
begin
result := compress(data, offset, length, level, true);
end;
function compress(const data: byte_Array1d; level: int; defaultInit: boolean): byte_Array1d;
begin
result := compress(data, 0, length(data), level, defaultInit);
end;
function compress(const data: byte_Array1d; offset, length, level: int; defaultInit: boolean): byte_Array1d;
var
compressor: Deflater;
tempStream: ByteArrayOutputStream;
zlibResult: int;
totalOut: long;
begin
compressor := ZStream.create();
tempStream := ByteArrayOutputStream.create();
try
result := byte_Array1d_create($10000);
totalOut := 0;
if defaultInit then begin
compressor.deflateInit(level);
end else begin
compressor.deflateInit(level, -MAX_WBITS);
end;
compressor.setInput(data, offset, length, false);
repeat
compressor.setOutput(result);
zlibResult := compressor.deflate(FINISH);
tempStream.write(result, 0, int(compressor.getTotalOut() - totalOut));
if zlibResult = STREAM_END then begin
compressor.deflateEnd();
break;
end;
totalOut := compressor.getTotalOut();
until false;
result := tempStream.toByteArray();
finally
tempStream.free();
end;
end;
function decompress(const data: byte_Array1d): byte_Array1d;
begin
result := decompress(data, 0, length(data), true);
end;
function decompress(const data: byte_Array1d; offset, length: int): byte_Array1d;
begin
result := decompress(data, offset, length, true);
end;
function decompress(const data: byte_Array1d; defaultInit: boolean): byte_Array1d;
begin
result := decompress(data, 0, length(data), defaultInit);
end;
function decompress(const data: byte_Array1d; offset, length: int; defaultInit: boolean): byte_Array1d;
var
decompressor: Inflater;
tempStream: ByteArrayOutputStream;
zlibResult: int;
totalOut: long;
begin
decompressor := ZStream.create();
tempStream := ByteArrayOutputStream.create();
try
result := byte_Array1d_create($10000);
totalOut := 0;
if defaultInit then begin
decompressor.inflateInit();
end else begin
decompressor.inflateInit(-MAX_WBITS);
end;
decompressor.setInput(data, offset, length, false);
repeat
decompressor.setOutput(result);
zlibResult := decompressor.inflate(NO_FLUSH);
tempStream.write(result, 0, int(decompressor.getTotalOut() - totalOut));
if (zlibResult = STREAM_END) or (zlibResult < 0) then begin
decompressor.inflateEnd();
break;
end;
totalOut := decompressor.getTotalOut();
until false;
result := tempStream.toByteArray();
finally
tempStream.free();
end;
end;
{%endregion}
{%region Adler32 }
constructor Adler32.create();
begin
inherited create();
self.adler := 1;
end;
constructor Adler32.create(adler: int);
begin
inherited create();
self.adler := adler;
end;
procedure Adler32.update(const buf: byte_Array1d; offset, length: int);
var
lim: int;
len: int;
a: int;
k: int;
s1: long;
s2: long;
begin
lim := offset + length;
len := System.length(buf);
if (lim > len) or (lim < offset) or (offset < 0) or (offset > len) then begin
raise ArrayIndexOutOfBoundsException.create('Adler32.update: индекс элемента массива выходит из диапазона.');
end;
a := adler;
s1 := long(a and $ffff);
s2 := long((a shr 16) and $ffff);
while length > 0 do begin
k := min(length, NMAX);
dec(length, k);
while k > 0 do begin
dec(k);
inc(s1, buf[offset] and $ff);
inc(s2, s1);
inc(offset);
end;
divLong(s1, BASE, s1);
divLong(s2, BASE, s2);
end;
adler := int((s2 shl 16) or s1);
end;
procedure Adler32.reset(init: int);
begin
adler := init;
end;
procedure Adler32.reset();
begin
adler := 1;
end;
function Adler32.getValue(): int;
begin
result := adler;
end;
function Adler32.copy(): Checksum32;
begin
result := Adler32.create(adler);
end;
{%endregion}
{%region Crc32 }
class procedure Crc32.clinit();
var
i: int;
j: int;
c: int;
begin
TABLE := int_Array1d_create(256);
for i := 0 to 255 do begin
c := i;
for j := 7 downto 0 do begin
if (c and 1) <> 0 then begin
c := int($edb88320) xor (c shr 1);
end else begin
c := c shr 1;
end;
end;
TABLE[i] := c;
end;
end;
class procedure Crc32.cldone();
begin
TABLE := nil;
end;
constructor Crc32.create();
begin
inherited create();
self.crc := 0;
end;
constructor Crc32.create(crc: int);
begin
inherited create();
self.crc := crc;
end;
procedure Crc32.update(const buf: byte_Array1d; offset, length: int);
var
lim: int;
len: int;
c: int;
begin
lim := offset + length;
len := System.length(buf);
if (lim > len) or (lim < offset) or (offset < 0) or (offset > len) then begin
raise ArrayIndexOutOfBoundsException.create('Crc32.update: индекс элемента массива выходит из диапазона.');
end;
c := not crc;
while length > 0 do begin
dec(length);
c := TABLE[int(c xor buf[offset]) and $ff] xor (c shr 8);
inc(offset);
end;
crc := not c;
end;
procedure Crc32.reset(init: int);
begin
crc := init;
end;
procedure Crc32.reset();
begin
crc := 0;
end;
function Crc32.getValue(): int;
begin
result := crc;
end;
function Crc32.copy(): Checksum32;
begin
result := Crc32.create(crc);
end;
{%endregion}
{%region Config }
constructor Config.create(goodLength, maxLazy, niceLength, maxChain, func: int);
begin
inherited create();
self.goodLength := goodLength;
self.maxLazy := maxLazy;
self.niceLength := niceLength;
self.maxChain := maxChain;
self.func := func;
end;
{%endregion}
{%region StaticTree }
class procedure StaticTree.clinit();
begin
STATIC_LTREE := toIntArray1d([
12, 8, 140, 8, 76, 8, 204, 8, 44, 8,
172, 8, 108, 8, 236, 8, 28, 8, 156, 8,
92, 8, 220, 8, 60, 8, 188, 8, 124, 8,
252, 8, 2, 8, 130, 8, 66, 8, 194, 8,
34, 8, 162, 8, 98, 8, 226, 8, 18, 8,
146, 8, 82, 8, 210, 8, 50, 8, 178, 8,
114, 8, 242, 8, 10, 8, 138, 8, 74, 8,
202, 8, 42, 8, 170, 8, 106, 8, 234, 8,
26, 8, 154, 8, 90, 8, 218, 8, 58, 8,
186, 8, 122, 8, 250, 8, 6, 8, 134, 8,
70, 8, 198, 8, 38, 8, 166, 8, 102, 8,
230, 8, 22, 8, 150, 8, 86, 8, 214, 8,
54, 8, 182, 8, 118, 8, 246, 8, 14, 8,
142, 8, 78, 8, 206, 8, 46, 8, 174, 8,
110, 8, 238, 8, 30, 8, 158, 8, 94, 8,
222, 8, 62, 8, 190, 8, 126, 8, 254, 8,
1, 8, 129, 8, 65, 8, 193, 8, 33, 8,
161, 8, 97, 8, 225, 8, 17, 8, 145, 8,
81, 8, 209, 8, 49, 8, 177, 8, 113, 8,
241, 8, 9, 8, 137, 8, 73, 8, 201, 8,
41, 8, 169, 8, 105, 8, 233, 8, 25, 8,
153, 8, 89, 8, 217, 8, 57, 8, 185, 8,
121, 8, 249, 8, 5, 8, 133, 8, 69, 8,
197, 8, 37, 8, 165, 8, 101, 8, 229, 8,
21, 8, 149, 8, 85, 8, 213, 8, 53, 8,
181, 8, 117, 8, 245, 8, 13, 8, 141, 8,
77, 8, 205, 8, 45, 8, 173, 8, 109, 8,
237, 8, 29, 8, 157, 8, 93, 8, 221, 8,
61, 8, 189, 8, 125, 8, 253, 8, 19, 9,
275, 9, 147, 9, 403, 9, 83, 9, 339, 9,
211, 9, 467, 9, 51, 9, 307, 9, 179, 9,
435, 9, 115, 9, 371, 9, 243, 9, 499, 9,
11, 9, 267, 9, 139, 9, 395, 9, 75, 9,
331, 9, 203, 9, 459, 9, 43, 9, 299, 9,
171, 9, 427, 9, 107, 9, 363, 9, 235, 9,
491, 9, 27, 9, 283, 9, 155, 9, 411, 9,
91, 9, 347, 9, 219, 9, 475, 9, 59, 9,
315, 9, 187, 9, 443, 9, 123, 9, 379, 9,
251, 9, 507, 9, 7, 9, 263, 9, 135, 9,
391, 9, 71, 9, 327, 9, 199, 9, 455, 9,
39, 9, 295, 9, 167, 9, 423, 9, 103, 9,
359, 9, 231, 9, 487, 9, 23, 9, 279, 9,
151, 9, 407, 9, 87, 9, 343, 9, 215, 9,
471, 9, 55, 9, 311, 9, 183, 9, 439, 9,
119, 9, 375, 9, 247, 9, 503, 9, 15, 9,
271, 9, 143, 9, 399, 9, 79, 9, 335, 9,
207, 9, 463, 9, 47, 9, 303, 9, 175, 9,
431, 9, 111, 9, 367, 9, 239, 9, 495, 9,
31, 9, 287, 9, 159, 9, 415, 9, 95, 9,
351, 9, 223, 9, 479, 9, 63, 9, 319, 9,
191, 9, 447, 9, 127, 9, 383, 9, 255, 9,
511, 9, 0, 7, 64, 7, 32, 7, 96, 7,
16, 7, 80, 7, 48, 7, 112, 7, 8, 7,
72, 7, 40, 7, 104, 7, 24, 7, 88, 7,
56, 7, 120, 7, 4, 7, 68, 7, 36, 7,
100, 7, 20, 7, 84, 7, 52, 7, 116, 7,
3, 8, 131, 8, 67, 8, 195, 8, 35, 8,
163, 8, 99, 8, 227, 8
]);
STATIC_DTREE := toIntArray1d([
0, 5, 16, 5, 8, 5, 24, 5, 4, 5,
20, 5, 12, 5, 28, 5, 2, 5, 18, 5,
10, 5, 26, 5, 6, 5, 22, 5, 14, 5,
30, 5, 1, 5, 17, 5, 9, 5, 25, 5,
5, 5, 21, 5, 13, 5, 29, 5, 3, 5,
19, 5, 11, 5, 27, 5, 7, 5, 23, 5
]);
EXTRA_LBITS := toIntArray1d([
0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
4, 4, 4, 4, 5, 5, 5, 5, 0
]);
EXTRA_DBITS := toIntArray1d([
0, 0, 0, 0, 1, 1, 2, 2, 3, 3,
4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
9, 9, 10, 10, 11, 11, 12, 12, 13, 13
]);
EXTRA_BLBITS := toIntArray1d([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 2, 3, 7
]);
STATIC_L_DESC := Zlib.StaticTree.create(STATIC_LTREE, EXTRA_LBITS, LITERALS + 1, L_CODES, MAX_BITS);
STATIC_D_DESC := Zlib.StaticTree.create(STATIC_DTREE, EXTRA_DBITS, 0, D_CODES, MAX_BITS);
STATIC_BL_DESC := Zlib.StaticTree.create(nil, EXTRA_BLBITS, 0, BL_CODES, MAX_BL_BITS);
end;
class procedure StaticTree.cldone();
begin
STATIC_BL_DESC.free();
STATIC_D_DESC.free();
STATIC_L_DESC.free();
EXTRA_BLBITS := nil;
EXTRA_DBITS := nil;
EXTRA_LBITS := nil;
STATIC_DTREE := nil;
STATIC_LTREE := nil;
end;
constructor StaticTree.create(const staticTree, extraBits: int_Array1d; extraBase, elems, maxLength: int);
begin
inherited create();
self.staticTree := staticTree;
self.extraBits := extraBits;
self.extraBase := extraBase;
self.elems := elems;
self.maxLength := maxLength;
end;
{%endregion}
{%region GZIPHeader }
constructor GZIPHeader.create();
begin
inherited create();
os := 255;
end;
procedure GZIPHeader.put(d: Deflate);
var
flags: int;
xfl: int;
begin
flags := 0;
if text then begin
flags := flags or $01;
end;
if fhcrc then begin
flags := flags or $02;
end;
if extra <> nil then begin
flags := flags or $04;
end;
if name <> nil then begin
flags := flags or $08;
end;
if comment <> nil then begin
flags := flags or $10;
end;
xfl := 0;
if d.level = BEST_SPEED then begin
xfl := xfl or $04;
end else
if d.level = BEST_COMPRESSION then begin
xfl := xfl or $02;
end;
d.putShort($8b1f);
d.putByte(8);
d.putByte(flags);
d.putByte(mtime);
d.putByte(mtime shr 8);
d.putByte(mtime shr 16);
d.putByte(mtime shr 24);
d.putByte(xfl);
d.putByte(os);
if extra <> nil then begin
flags := length(extra);
d.putByte(flags);
d.putByte(flags shr 8);
d.putBytes(extra, 0, flags);
end;
if name <> nil then begin
d.putBytes(name, 0, length(name));
d.putByte(0);
end;
if comment <> nil then begin
d.putBytes(comment, 0, length(comment));
d.putByte(0);
end;
end;
procedure GZIPHeader.setName(const name: AnsiString);
begin
self.name := encodeISO88591(toUTF16String(name));
end;
procedure GZIPHeader.setComment(const comment: AnsiString);
begin
self.comment := encodeISO88591(toUTF16String(comment));
end;
procedure GZIPHeader.setModifiedTime(mtime: int);
begin
self.mtime := mtime;
end;
procedure GZIPHeader.setCRC(crc: int);
begin
self.crc := crc;
end;
procedure GZIPHeader.setOS(os: int);
begin
if ((os < 0) or (os > 13)) and (os <> 255) then begin
raise IllegalArgumentException.create('os: ' + toDecString(os));
end;
self.os := os;
end;
function GZIPHeader.getName(): AnsiString;
begin
if name <> nil then begin
result := toUTF8String(decodeISO88591(name));
end else begin
result := '';
end;
end;
function GZIPHeader.getComment(): AnsiString;
begin
if comment <> nil then begin
result := toUTF8String(decodeISO88591(comment));
end else begin
result := '';
end;
end;
function GZIPHeader.getModifiedTime(): int;
begin
result := mtime;
end;
function GZIPHeader.getCRC(): int;
begin
result := crc;
end;
function GZIPHeader.getOS(): int;
begin
result := os;
end;
{%endregion}
{%region Tree }
class procedure Tree.genCodes(const tree: int_Array1d; maxCode: int; const blCount: int_Array1d);
var
nextCode: int_Array1d;
code: int;
bits: int;
len: int;
buf: int;
n: int;
begin
nextCode := int_Array1d_create(MAX_BITS + 1);
code := 0;
for bits := 1 to MAX_BITS do begin
code := short((code + blCount[bits - 1]) shl 1);
nextCode[bits] := code;
end;
for n := 0 to maxCode do begin
len := tree[n * 2 + 1];
if len = 0 then begin
continue;
end;
buf := nextCode[len];
tree[n * 2] := short(biReverse(buf, len));
nextCode[len] := buf + 1;
end;
end;
class function Tree.biReverse(code, len: int): int;
begin
result := 0;
repeat
result := result or (code and $01);
code := code shr 1;
result := result shl 1;
dec(len);
until len <= 0;
result := result shr 1;
end;
constructor Tree.create();
begin
inherited create();
end;
procedure Tree.genBitlen(s: Deflate);
var
tree: int_Array1d;
stree: int_Array1d;
extra: int_Array1d;
f: int;
base: int;
maxLength: int;
h: int;
n: int;
m: int;
bits: int;
xbits: int;
overflow: int;
begin
tree := dynTree;
stree := statDesc.staticTree;
extra := statDesc.extraBits;
base := statDesc.extraBase;
maxLength := statDesc.maxLength;
overflow := 0;
for bits := 0 to MAX_BITS do begin
s.blCount[bits] := 0;
end;
tree[s.heap[s.heapMax] * 2 + 1] := 0;
h := s.heapMax + 1;
while h < HEAP_SIZE do begin
n := s.heap[h];
bits := tree[tree[n * 2 + 1] * 2 + 1] + 1;
if bits > maxLength then begin
bits := maxLength;
inc(overflow);
end;
tree[n * 2 + 1] := short(bits);
if n > maxCode then begin
inc(h);
continue;
end;
inc(s.blCount[bits]);
xbits := 0;
if n >= base then begin
xbits := extra[n - base];
end;
f := tree[n * 2];
inc(s.optLen, f * (bits + xbits));
if stree <> nil then begin
inc(s.staticLen, f * (stree[n * 2 + 1] + xbits));
end;
inc(h);
end;
if overflow = 0 then begin
exit;
end;
repeat
bits := maxLength - 1;
while s.blCount[bits] = 0 do begin
dec(bits);
end;
dec(s.blCount[bits]);
inc(s.blCount[bits + 1], 2);
dec(s.blCount[maxLength]);
dec(overflow, 2);
until overflow <= 0;
for bits := maxLength downto 1 do begin
n := s.blCount[bits];
while n <> 0 do begin
dec(h);
m := s.heap[h];
if m > maxCode then begin
continue;
end;
if tree[m * 2 + 1] <> bits then begin
inc(s.optLen, int((long(bits) - long(tree[m * 2 + 1])) * long(tree[m * 2])));
tree[m * 2 + 1] := short(bits);
end;
dec(n);
end;
end;
end;
procedure Tree.buildTree(s: Deflate);
var
tree: int_Array1d;
stree: int_Array1d;
elems: int;
n: int;
m: int;
maxCodeLocal: int;
node: int;
begin
tree := dynTree;
stree := statDesc.staticTree;
elems := statDesc.elems;
maxCodeLocal := -1;
s.heapLen := 0;
s.heapMax := HEAP_SIZE;
for n := 0 to elems - 1 do begin
if tree[n * 2] <> 0 then begin
inc(s.heapLen);
maxCodeLocal := n;
s.heap[s.heapLen] := n;
s.depth[n] := 0;
end else begin
tree[n * 2 + 1] := 0;
end;
end;
while s.heapLen < 2 do begin
inc(s.heapLen);
if maxCodeLocal < 2 then begin
inc(maxCodeLocal);
node := maxCodeLocal;
end else begin
node := 0;
end;
s.heap[s.heapLen] := node;
tree[node * 2] := 1;
s.depth[node] := 0;
dec(s.optLen);
if stree <> nil then begin
dec(s.staticLen, stree[node * 2 + 1]);
end;
end;
maxCode := maxCodeLocal;
for n := s.heapLen div 2 downto 1 do begin
s.pqDownHeap(tree, n);
end;
node := elems;
repeat
n := s.heap[1];
s.heap[1] := s.heap[s.heapLen];
dec(s.heapLen);
s.pqDownHeap(tree, 1);
m := s.heap[1];
dec(s.heapMax);
s.heap[s.heapMax] := n;
dec(s.heapMax);
s.heap[s.heapMax] := m;
tree[node * 2] := short(tree[n * 2] + tree[m * 2]);
s.depth[node] := byte(max(s.depth[n], s.depth[m]) + 1);
tree[n * 2 + 1] := short(node);
tree[m * 2 + 1] := short(node);
s.heap[1] := node;
inc(node);
s.pqDownHeap(tree, 1);
until s.heapLen < 2;
dec(s.heapMax);
s.heap[s.heapMax] := s.heap[1];
genBitlen(s);
genCodes(tree, maxCodeLocal, s.blCount);
end;
{%endregion}
{%region Deflate }
class procedure Deflate.clinit();
begin
DIST_CODE := toByteArray1d([
0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8,
8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17,
18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
]);
BL_ORDER := toByteArray1d([
16, 17, 18, 0, 8, 7, 9, 6, 10, 5,
11, 4, 12, 3, 13, 2, 14, 1, 15
]);
LENGTH_CODE := toByteArray1d([
0, 1, 2, 3, 4, 5, 6, 7, 8, 8,
9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
13, 13, 13, 13, 14, 14, 14, 14, 15, 15,
15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
17, 17, 17, 17, 17, 17, 17, 17, 18, 18,
18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
19, 19, 19, 19, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 28
]);
BASE_LENGTH := toIntArray1d([
0, 1, 2, 3, 4, 5, 6, 7, 8, 10,
12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
64, 80, 96, 112, 128, 160, 192, 224, 0
]);
BASE_DIST := toIntArray1d([
0, 1, 2, 3, 4, 6, 8, 12, 16, 24,
32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
]);
CONFIG_TABLE := toConfigArray1d([
Config.create(0, 0, 0, 0, STORED),
Config.create(4, 4, 8, 4, FAST),
Config.create(4, 5, 16, 8, FAST),
Config.create(4, 6, 32, 32, FAST),
Config.create(4, 4, 16, 16, SLOW),
Config.create(8, 16, 32, 32, SLOW),
Config.create(8, 16, 128, 128, SLOW),
Config.create(8, 32, 128, 256, SLOW),
Config.create(32, 128, 258, 1024, SLOW),
Config.create(32, 258, 258, 4096, SLOW)
]);
ERR_MSG := toStringArray1d([
'need dictionary',
'stream end',
'',
'file error',
'stream error',
'data error',
'insufficient memory',
'buffer error',
'incompatible version',
''
]);
end;
class procedure Deflate.cldone();
var
c: Config_Array1d;
i: int;
begin
ERR_MSG := nil;
c := CONFIG_TABLE;
for i := length(c) - 1 downto 0 do begin
c[i].free();
c[i] := nil;
end;
c := nil;
CONFIG_TABLE := nil;
BASE_DIST := nil;
BASE_LENGTH := nil;
LENGTH_CODE := nil;
BL_ORDER := nil;
DIST_CODE := nil;
end;
class function Deflate.smaller(const tree: int_Array1d; n, m: int; const depth: byte_Array1d): boolean;
var
tn2: int;
tm2: int;
begin
tn2 := tree[n * 2];
tm2 := tree[m * 2];
result := (tn2 < tm2) or ((tn2 = tm2) and (depth[n] <= depth[m]));
end;
class function Deflate.dcode(dist: int): int;
begin
if dist < 256 then begin
result := DIST_CODE[dist];
end else begin
result := DIST_CODE[256 + (dist shr 7)];
end;
end;
constructor Deflate.create(stream: ZStream);
begin
inherited create();
wrap := 1;
dynLtree := int_Array1d_create(HEAP_SIZE * 2);
dynDtree := int_Array1d_create((2 * D_CODES + 1) * 2);
blTree := int_Array1d_create((2 * BL_CODES + 1) * 2);
blCount := int_Array1d_create(MAX_BITS + 1);
heap := int_Array1d_create(2 * L_CODES + 1);
depth := byte_Array1d_create(2 * L_CODES + 1);
lDesc := Tree.create();
dDesc := Tree.create();
blDesc := Tree.create();
self.stream := stream;
end;
destructor Deflate.destroy;
begin
gheader.free();
blDesc.free();
dDesc.free();
lDesc.free();
inherited destroy;
end;
procedure Deflate.lmInit();
var
i: int;
c: Config;
begin
windowSize := 2 * wSize;
for i := 0 to hashSize - 1 do begin
head[i] := 0;
end;
c := CONFIG_TABLE[level];
maxLazyMatch := c.maxLazy;
goodMatch := c.goodLength;
niceMatch := c.niceLength;
maxChainLength := c.maxChain;
strStart := 0;
blockStart := 0;
lookahead := 0;
matchLength := MIN_MATCH - 1;
prevLength := MIN_MATCH - 1;
matchAvailable := 0;
insh := 0;
end;
procedure Deflate.trInit();
begin
lDesc.dynTree := dynLtree;
lDesc.statDesc := StaticTree.STATIC_L_DESC;
dDesc.dynTree := dynDtree;
dDesc.statDesc := StaticTree.STATIC_D_DESC;
blDesc.dynTree := blTree;
blDesc.statDesc := StaticTree.STATIC_BL_DESC;
biBuf := 0;
biValid := 0;
lastEobLen := 8;
initBlock();
end;
procedure Deflate.initBlock();
var
i: int;
begin
for i := 0 to L_CODES - 1 do begin
dynLtree[i * 2] := 0;
end;
for i := 0 to D_CODES - 1 do begin
dynDtree[i * 2] := 0;
end;
for i := 0 to BL_CODES - 1 do begin
blTree[i * 2] := 0;
end;
dynLtree[END_BLOCK * 2] := 1;
optLen := 0;
staticLen := 0;
lastLit := 0;
matches := 0;
end;
procedure Deflate.scanTree(const tree: int_Array1d; maxCode: int);
var
n: int;
prevlen: int;
currlen: int;
nextlen: int;
count: int;
maxCount: int;
minCount: int;
begin
prevlen := -1;
nextlen := tree[1];
count := 0;
maxCount := 7;
minCount := 4;
if nextlen = 0 then begin
maxCount := 138;
minCount := 3;
end;
tree[(maxCode + 1) * 2 + 1] := -1;
for n := 0 to maxCode do begin
currlen := nextlen;
nextlen := tree[(n + 1) * 2 + 1];
inc(count);
if (count < maxCount) and (currlen = nextlen) then begin
continue;
end else
if count < minCount then begin
inc(blTree[currlen * 2], count);
end else
if currlen <> 0 then begin
if currlen <> prevlen then begin
inc(blTree[currlen * 2]);
end;
inc(blTree[REP_3_6 * 2]);
end else
if count <= 10 then begin
inc(blTree[REPZ_3_10 * 2]);
end else begin
inc(blTree[REPZ_11_138 * 2]);
end;
count := 0;
prevlen := currlen;
if nextlen = 0 then begin
maxCount := 138;
minCount := 3;
end else
if currlen = nextlen then begin
maxCount := 6;
minCount := 3;
end else begin
maxCount := 7;
minCount := 4;
end;
end;
end;
procedure Deflate.sendAllTrees(lcodes, dcodes, blcodes: int);
var
rank: int;
begin
sendBits(lcodes - 257, 5);
sendBits(dcodes - 1, 5);
sendBits(blcodes - 4, 4);
for rank := 0 to blcodes - 1 do begin
sendBits(blTree[BL_ORDER[rank] * 2 + 1], 3);
end;
sendTree(dynLtree, lcodes - 1);
sendTree(dynDtree, dcodes - 1);
end;
procedure Deflate.sendTree(const tree: int_Array1d; maxCode: int);
var
n: int;
prevlen: int;
currlen: int;
nextlen: int;
count: int;
maxCount: int;
minCount: int;
begin
prevlen := -1;
nextlen := tree[1];
count := 0;
maxCount := 7;
minCount := 4;
if nextlen = 0 then begin
maxCount := 138;
minCount := 3;
end;
for n := 0 to maxCode do begin
currlen := nextlen;
nextlen := tree[(n + 1) * 2 + 1];
inc(count);
if (count < maxCount) and (currlen = nextlen) then begin
continue;
end else
if count < minCount then begin
repeat
sendCode(currlen, blTree);
dec(count);
until count = 0;
end else
if currlen <> 0 then begin
if currlen <> prevlen then begin
sendCode(currlen, blTree);
dec(count);
end;
sendCode(REP_3_6, blTree);
sendBits(count - 3, 2);
end else
if count <= 10 then begin
sendCode(REPZ_3_10, blTree);
sendBits(count - 3, 3);
end else begin
sendCode(REPZ_11_138, blTree);
sendBits(count - 11, 7);
end;
count := 0;
prevlen := currlen;
if nextlen = 0 then begin
maxCount := 138;
minCount := 3;
end else
if currlen = nextlen then begin
maxCount := 6;
minCount := 3;
end else begin
maxCount := 7;
minCount := 4;
end;
end;
end;
procedure Deflate.putShortMSB(b: int);
begin
putByte(b shr 8);
putByte(b);
end;
procedure Deflate.sendCode(c: int; const tree: int_Array1d);
var
c2: int;
begin
c2 := c * 2;
sendBits(tree[c2] and $ffff, tree[c2 + 1] and $ffff);
end;
procedure Deflate.sendBits(val, len: int);
begin
biBuf := biBuf or ((val shl biValid) and $ffff);
if biValid > BUF_SIZE - len then begin
putShort(biBuf);
biBuf := short(val shr (BUF_SIZE - biValid));
inc(biValid, len - BUF_SIZE);
end else begin
inc(biValid, len);
end;
end;
procedure Deflate.trAlign();
begin
sendBits(STATIC_TREES shl 1, 3);
sendCode(END_BLOCK, StaticTree.STATIC_LTREE);
biFlush();
if lastEobLen - biValid + 11 < 9 then begin
sendBits(STATIC_TREES shl 1, 3);
sendCode(END_BLOCK, StaticTree.STATIC_LTREE);
biFlush();
end;
lastEobLen := 7;
end;
procedure Deflate.compressBlock(const ltree, dtree: int_Array1d);
var
dist: int;
lc: int;
lx: int;
code: int;
extra: int;
begin
lx := 0;
if lastLit <> 0 then begin
repeat
dist := ((int(pendingBuf[dBuf + lx * 2]) shl 8) and $ff00) or (int(pendingBuf[dBuf + lx * 2 + 1]) and $ff);
lc := int(pendingBuf[lBuf + lx]) and $ff;
inc(lx);
if dist = 0 then begin
sendCode(lc, ltree);
end else begin
code := LENGTH_CODE[lc];
sendCode(code + (LITERALS + 1), ltree);
extra := StaticTree.EXTRA_LBITS[code];
if extra <> 0 then begin
dec(lc, BASE_LENGTH[code]);
sendBits(lc, extra);
end;
dec(dist);
code := dcode(dist);
sendCode(code, dtree);
extra := StaticTree.EXTRA_DBITS[code];
if extra <> 0 then begin
dec(dist, BASE_DIST[code]);
sendBits(dist, extra);
end;
end;
until lx >= lastLit;
end;
sendCode(END_BLOCK, ltree);
lastEobLen := ltree[END_BLOCK * 2 + 1];
end;
procedure Deflate.setDataType();
var
n: int;
asciiFreq: int;
binFreq: int;
begin
n := 0;
asciiFreq := 0;
binFreq := 0;
while n < 7 do begin
inc(binFreq, dynLtree[n * 2]);
inc(n);
end;
while n < 128 do begin
inc(asciiFreq, dynLtree[n * 2]);
inc(n);
end;
while n < LITERALS do begin
inc(binFreq, dynLtree[n * 2]);
inc(n);
end;
if binFreq > (asciiFreq shr 2) then begin
dataType := Z_BINARY;
end else begin
dataType := Z_ASCII;
end;
end;
procedure Deflate.biFlush();
begin
if biValid = 16 then begin
putShort(biBuf);
biBuf := 0;
biValid := 0;
end else
if biValid >= 8 then begin
putByte(biBuf);
biBuf := biBuf shr 8;
dec(biValid, 8);
end;
end;
procedure Deflate.biWindup();
begin
if biValid > 8 then begin
putShort(biBuf);
end else
if biValid > 0 then begin
putByte(biBuf);
end;
biBuf := 0;
biValid := 0;
end;
procedure Deflate.copyBlock(buf, len: int; header: boolean);
begin
biWindup();
lastEobLen := 8;
if header then begin
putShort(len);
putShort(not len);
end;
putBytes(window, buf, len);
end;
procedure Deflate.flushBlockOnly(eof: boolean);
begin
if blockStart >= 0 then begin
trFlushBlock(blockStart, strStart - blockStart, eof);
end else begin
trFlushBlock(-1, strStart - blockStart, eof);
end;
blockStart := strStart;
stream.flushPending();
end;
procedure Deflate.trStoredBlock(buf, storedLen: int; eof: boolean);
begin
if eof then begin
sendBits((STORED_BLOCK shl 1) + 1, 3);
end else begin
sendBits(STORED_BLOCK shl 1, 3);
end;
copyBlock(buf, storedLen, true);
end;
procedure Deflate.trFlushBlock(buf, storedLen: int; eof: boolean);
var
optLenb: int;
staticLenb: int;
maxBlindex: int;
begin
maxBlindex := 0;
if level > 0 then begin
if dataType = Z_UNKNOWN then begin
setDataType();
end;
lDesc.buildTree(self);
dDesc.buildTree(self);
maxBlindex := buildBlTree();
optLenb := (optLen + 10) shr 3;
staticLenb := (staticLen + 10) shr 3;
if staticLenb <= optLenb then begin
optLenb := staticLenb;
end;
end else begin
optLenb := storedLen + 5;
staticLenb := optLenb;
end;
if (storedLen + 4 <= optLenb) and (buf <> -1) then begin
trStoredBlock(buf, storedLen, eof);
end else
if staticLenb = optLenb then begin
if eof then begin
sendBits((STATIC_TREES shl 1) + 1, 3);
end else begin
sendBits(STATIC_TREES shl 1, 3);
end;
compressBlock(StaticTree.STATIC_LTREE, StaticTree.STATIC_DTREE);
end else begin
if eof then begin
sendBits((DYN_TREES shl 1) + 1, 3);
end else begin
sendBits(DYN_TREES shl 1, 3);
end;
sendAllTrees(lDesc.maxCode + 1, dDesc.maxCode + 1, maxBlindex + 1);
compressBlock(dynLtree, dynDtree);
end;
initBlock();
if eof then begin
biWindup();
end;
end;
procedure Deflate.fillWindow();
var
n: int;
m: int;
p: int;
more: int;
begin
repeat
more := windowSize - lookahead - strStart;
if (more = 0) and (strStart = 0) and (lookahead = 0) then begin
more := wSize;
end else
if more = -1 then begin
dec(more);
end else
if strStart >= wSize * 2 - MIN_LOOKAHEAD then begin
arraycopy(window, wSize, window, 0, wSize);
dec(matchStart, wSize);
dec(strStart, wSize);
dec(blockStart, wSize);
n := hashSize;
p := n;
repeat
dec(p);
m := head[p] and $ffff;
if m >= wSize then begin
head[p] := short(m - wSize);
end else begin
head[p] := 0;
end;
dec(n);
until n = 0;
n := wSize;
p := n;
repeat
dec(p);
m := prev[p] and $ffff;
if m >= wSize then begin
prev[p] := short(m - wSize);
end else begin
prev[p] := 0;
end;
dec(n);
until n = 0;
inc(more, wSize);
end;
if stream.availIn = 0 then begin
exit;
end;
n := stream.readBuf(window, strStart + lookahead, more);
inc(lookahead, n);
if lookahead >= MIN_MATCH then begin
insh := int(window[strStart]) and $ff;
insh := ((insh shl hashShift) xor (int(window[strStart + 1]) and $ff)) and hashMask;
end;
until (lookahead >= MIN_LOOKAHEAD) or (stream.availIn = 0);
end;
function Deflate.trTally(dist, lc: int): boolean;
var
outLength: int;
inLength: int;
dcode: int;
begin
pendingBuf[dBuf + lastLit * 2] := byte(dist shr 8);
pendingBuf[dBuf + lastLit * 2 + 1] := byte(dist);
pendingBuf[lBuf + lastLit] := byte(lc);
inc(lastLit);
if dist = 0 then begin
inc(dynLtree[lc * 2]);
end else begin
inc(matches);
dec(dist);
inc(dynLtree[(LENGTH_CODE[lc] + (LITERALS + 1)) * 2]);
inc(dynDtree[self.dcode(dist) * 2]);
end;
if ((lastLit and $1fff) = 0) and (level > 2) then begin
outLength := lastLit * 8;
inLength := strStart - blockStart;
for dcode := 0 to D_CODES - 1 do begin
inc(outLength, int(long(dynDtree[dcode * 2]) * (long(5) + long(StaticTree.EXTRA_DBITS[dcode]))));
end;
outLength := outLength shr 3;
if (matches < lastLit div 2) and (outLength < inLength div 2) then begin
result := true;
exit;
end;
end;
result := lastLit = litBufSize - 1;
end;
function Deflate.buildBlTree(): int;
begin
scanTree(dynLtree, lDesc.maxCode);
scanTree(dynDtree, dDesc.maxCode);
blDesc.buildTree(self);
result := BL_CODES - 1;
while result >= 3 do begin
if blTree[BL_ORDER[result] * 2 + 1] <> 0 then begin
break;
end;
dec(result);
end;
inc(optLen, 3 * (result + 1) + 14);
end;
function Deflate.deflateStored(flush: int): int;
var
maxBlockSize: int;
maxStart: int;
begin
maxBlockSize := $ffff;
if maxBlockSize > pendingBufSize - 5 then begin
maxBlockSize := pendingBufSize - 5;
end;
repeat
if lookahead <= 1 then begin
fillWindow();
if (lookahead = 0) and (flush = NO_FLUSH) then begin
result := NEED_MORE;
exit;
end;
if lookahead = 0 then begin
break;
end;
end;
inc(strStart, lookahead);
lookahead := 0;
maxStart := blockStart + maxBlockSize;
if (strStart = 0) or (strStart >= maxStart) then begin
lookahead := strStart - maxStart;
strStart := maxStart;
flushBlockOnly(false);
if stream.availOut = 0 then begin
result := NEED_MORE;
exit;
end;
end;
if strStart - blockStart >= wSize - MIN_LOOKAHEAD then begin
flushBlockOnly(false);
if stream.availOut = 0 then begin
result := NEED_MORE;
exit;
end;
end;
until false;
flushBlockOnly(flush = FINISH);
if stream.availOut = 0 then begin
if flush = FINISH then begin
result := FINISH_STARTED;
end else begin
result := NEED_MORE;
end;
end else begin
if flush = FINISH then begin
result := FINISH_DONE;
end else begin
result := BLOCK_DONE;
end;
end;
end;
function Deflate.deflateFast(flush: int): int;
var
hashHead: int;
bflush: boolean;
begin
hashHead := 0;
repeat
if lookahead < MIN_LOOKAHEAD then begin
fillWindow();
if (lookahead < MIN_LOOKAHEAD) and (flush = NO_FLUSH) then begin
result := NEED_MORE;
exit;
end;
if lookahead = 0 then begin
break;
end;
end;
if lookahead >= MIN_MATCH then begin
insh := ((insh shl hashShift) xor (int(window[strStart + (MIN_MATCH - 1)]) and $ff)) and hashMask;
hashHead := head[insh] and $ffff;
prev[strStart and wMask] := head[insh];
head[insh] := short(strStart);
end;
if (hashHead <> 0) and (((strStart - hashHead) and $ffff) <= wSize - MIN_LOOKAHEAD) and (strategy <> HUFFMAN_ONLY) then begin
matchLength := longestMatch(hashHead);
end;
if matchLength >= MIN_MATCH then begin
bflush := trTally(strStart - matchStart, matchLength - MIN_MATCH);
dec(lookahead, matchLength);
if (matchLength <= maxLazyMatch) and (lookahead >= MIN_MATCH) then begin
dec(matchLength);
repeat
inc(strStart);
insh := ((insh shl hashShift) xor (int(window[strStart + (MIN_MATCH - 1)]) and $ff)) and hashMask;
hashHead := head[insh] and $ffff;
prev[strStart and wMask] := head[insh];
head[insh] := short(strStart);
dec(matchLength);
until matchLength = 0;
inc(strStart);
end else begin
inc(strStart, matchLength);
matchLength := 0;
insh := int(window[strStart]) and $ff;
insh := ((insh shl hashShift) xor (int(window[strStart + 1]) and $ff)) and hashMask;
end;
end else begin
bflush := trTally(0, int(window[strStart]) and $ff);
dec(lookahead);
inc(strStart);
end;
if bflush then begin
flushBlockOnly(false);
if stream.availOut = 0 then begin
result := NEED_MORE;
exit;
end;
end;
until false;
flushBlockOnly(flush = FINISH);
if stream.availOut = 0 then begin
if flush = FINISH then begin
result := FINISH_STARTED;
end else begin
result := NEED_MORE;
end;
end else begin
if flush = FINISH then begin
result := FINISH_DONE;
end else begin
result := BLOCK_DONE;
end;
end;
end;
function Deflate.deflateSlow(flush: int): int;
var
maxInsert: int;
hashHead: int;
bflush: boolean;
begin
hashHead := 0;
repeat
if lookahead < MIN_LOOKAHEAD then begin
fillWindow();
if (lookahead < MIN_LOOKAHEAD) and (flush = NO_FLUSH) then begin
result := NEED_MORE;
exit;
end;
if lookahead = 0 then begin
break;
end;
end;
if lookahead >= MIN_MATCH then begin
insh := ((insh shl hashShift) xor (int(window[strStart + (MIN_MATCH - 1)]) and $ff)) and hashMask;
hashHead := head[insh] and $ffff;
prev[strStart and wMask] := head[insh];
head[insh] := short(strStart);
end;
prevLength := matchLength;
prevMatch := matchStart;
matchLength := MIN_MATCH - 1;
if (hashHead <> 0) and (prevLength < maxLazyMatch) and (((strStart - hashHead) and $ffff) <= wSize - MIN_LOOKAHEAD) then begin
if strategy <> HUFFMAN_ONLY then begin
matchLength := longestMatch(hashHead);
end;
if (matchLength <= 5) and ((strategy = FILTERED) or ((matchLength = MIN_MATCH) and (strStart - matchStart > $1000))) then begin
matchLength := MIN_MATCH - 1;
end;
end;
if (prevLength >= MIN_MATCH) and (matchLength <= prevLength) then begin
maxInsert := strStart + lookahead - MIN_MATCH;
bflush := trTally(strStart - prevMatch - 1, prevLength - MIN_MATCH);
dec(lookahead, prevLength - 1);
dec(prevLength, 2);
repeat
inc(strStart);
if strStart <= maxInsert then begin
insh := ((insh shl hashShift) xor (int(window[strStart + (MIN_MATCH - 1)]) and $ff)) and hashMask;
hashHead := head[insh] and $ffff;
prev[strStart and wMask] := head[insh];
head[insh] := short(strStart);
end;
dec(prevLength);
until prevLength = 0;
matchAvailable := 0;
matchLength := MIN_MATCH - 1;
inc(strStart);
if bflush then begin
flushBlockOnly(false);
if stream.availOut = 0 then begin
result := NEED_MORE;
exit;
end;
end;
end else
if matchAvailable <> 0 then begin
bflush := trTally(0, int(window[strStart - 1]) and $ff);
if bflush then begin
flushBlockOnly(false);
end;
inc(strStart);
dec(lookahead);
if stream.availOut = 0 then begin
result := NEED_MORE;
exit;
end;
end else begin
matchAvailable := 1;
inc(strStart);
dec(lookahead);
end;
until false;
if matchAvailable <> 0 then begin
trTally(0, int(window[strStart - 1]) and $ff);
matchAvailable := 0;
end;
flushBlockOnly(flush = FINISH);
if stream.availOut = 0 then begin
if flush = FINISH then begin
result := FINISH_STARTED;
end else begin
result := NEED_MORE;
end;
end else begin
if flush = FINISH then begin
result := FINISH_DONE;
end else begin
result := BLOCK_DONE;
end;
end;
end;
function Deflate.deflateReset(): int;
begin
stream.totalIn := 0;
stream.totalOut := 0;
stream.msg := '';
stream.dataType := Z_UNKNOWN;
pending := 0;
pendingOut := 0;
if wrap < 0 then begin
wrap := -wrap;
end;
if wrap = 0 then begin
status := BUSY_STATE;
end else begin
status := INIT_STATE;
end;
stream.adler.reset();
lastFlush := NO_FLUSH;
trInit();
lmInit();
result := OK;
end;
function Deflate.deflateInit(level, method, windowBits, memLevel, strategy: int): int;
var
wraplocal: int;
begin
wraplocal := 1;
stream.msg := '';
if level = DEFAULT_COMPRESSION then begin
level := 6;
end;
if windowBits < 0 then begin
wraplocal := 0;
windowBits := -windowBits;
end else
if windowBits > 15 then begin
wraplocal := 2;
dec(windowBits, 16);
stream.adler := Crc32.create();
end;
if (memLevel < 1) or (memLevel > MAX_MEM_LEVEL) or (method <> Z_DEFLATED) or (windowBits < 9) or (windowBits > 15) or (level < 0) or (level > 9) or (strategy < 0) or (strategy > HUFFMAN_ONLY) then begin
result := STREAM_ERROR;
exit;
end;
wrap := wraplocal;
wBits := windowBits;
wSize := 1 shl wBits;
wMask := wSize - 1;
hashBits := memLevel + 7;
hashSize := 1 shl hashBits;
hashMask := hashSize - 1;
hashShift := (hashBits + (MIN_MATCH - 1)) div MIN_MATCH;
window := nil;
prev := nil;
head := nil;
window := byte_Array1d_create(wSize * 2);
prev := int_Array1d_create(wSize);
head := int_Array1d_create(hashSize);
litBufSize := 1 shl (memLevel + 6);
pendingBuf := nil;
pendingBuf := byte_Array1d_create(litBufSize * 4);
pendingBufSize := litBufSize * 4;
dBuf := litBufSize div 2;
lBuf := litBufSize * 3;
self.level := level;
self.strategy := strategy;
result := deflateReset();
end;
function Deflate.longestMatch(curMatch: int): int;
var
chainLength: int;
scan: int;
match: int;
len: int;
bestLen: int;
limit: int;
niceMatchLocal: int;
wmask: int;
strend: int;
scanEnd: byte;
scanEnd1: byte;
begin
chainLength := maxChainLength;
scan := strStart;
bestLen := prevLength;
if strStart > wSize - MIN_LOOKAHEAD then begin
limit := strStart - (wSize - MIN_LOOKAHEAD);
end else begin
limit := 0;
end;
niceMatchLocal := niceMatch;
wmask := self.wMask;
strend := strStart + MAX_MATCH;
scanEnd1 := window[scan + bestLen - 1];
scanEnd := window[scan + bestLen];
if prevLength >= goodMatch then begin
chainLength := sar(chainLength, 2);
end;
if niceMatchLocal > lookahead then begin
niceMatchLocal := lookahead;
end;
repeat
match := curMatch;
if (window[match + bestLen] = scanEnd) and (window[match + bestLen - 1] = scanEnd1) and (window[match] = window[scan]) and (window[predinc(match)] = window[scan + 1]) then begin
inc(scan, 2);
inc(match);
repeat
until
(window[predinc(scan)] <> window[predinc(match)]) or (window[predinc(scan)] <> window[predinc(match)]) or (window[predinc(scan)] <> window[predinc(match)]) or
(window[predinc(scan)] <> window[predinc(match)]) or (window[predinc(scan)] <> window[predinc(match)]) or (window[predinc(scan)] <> window[predinc(match)]) or
(window[predinc(scan)] <> window[predinc(match)]) or (window[predinc(scan)] <> window[predinc(match)]) or (scan >= strend)
;
len := MAX_MATCH - (strend - scan);
scan := strend - MAX_MATCH;
if len > bestLen then begin
matchStart := curMatch;
bestLen := len;
if len >= niceMatchLocal then begin
break;
end;
scanEnd1 := window[scan + bestLen - 1];
scanEnd := window[scan + bestLen];
end;
end;
curMatch := prev[curMatch and wmask] and $ffff;
if curMatch > limit then begin
dec(chainLength);
end else begin
break;
end;
until chainLength = 0;
result := min(bestLen, lookahead);
end;
function Deflate.getGZIPHeader(): GZIPHeader;
begin
result := gheader;
if result = nil then begin
result := GZIPHeader.create();
gheader := result;
end;
end;
procedure Deflate.pqDownHeap(const tree: int_Array1d; k: int);
var
v: int;
j: int;
begin
v := heap[k];
j := k shl 1;
while j <= heapLen do begin
if (j < heapLen) and smaller(tree, heap[j + 1], heap[j], depth) then begin
inc(j);
end;
if smaller(tree, v, heap[j], depth) then begin
break;
end;
heap[k] := heap[j];
k := j;
j := j shl 1;
end;
heap[k] := v;
end;
procedure Deflate.putBytes(const data: byte_Array1d; offset, length: int);
var
lim: int;
len: int;
begin
lim := offset + length;
len := System.length(data);
if (lim > len) or (lim < offset) or (offset < 0) or (offset > len) then begin
raise ArrayIndexOutOfBoundsException.create('Deflate.putBytes: индекс элемента массива выходит из диапазона.');
end;
arraycopy(data, offset, pendingBuf, pending, length);
inc(pending, length);
end;
procedure Deflate.putByte(c: int);
begin
pendingBuf[pending] := byte(c);
inc(pending);
end;
procedure Deflate.putShort(w: int);
begin
putByte(w);
putByte(w shr 8);
end;
function Deflate.deflateInit(level, bits, memlevel: int): int;
begin
result := deflateInit(level, Z_DEFLATED, bits, memlevel, DEFAULT_STRATEGY);
end;
function Deflate.deflateInit(level, bits: int): int;
begin
result := deflateInit(level, Z_DEFLATED, bits, DEF_MEM_LEVEL, DEFAULT_STRATEGY);
end;
function Deflate.deflateInit(level: int): int;
begin
result := deflateInit(level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, DEFAULT_STRATEGY);
end;
function Deflate.deflateEnd(): int;
begin
if (status <> INIT_STATE) and (status <> BUSY_STATE) and (status <> FINISH_STATE) then begin
result := STREAM_ERROR;
exit;
end;
pendingBuf := nil;
head := nil;
prev := nil;
window := nil;
if status = BUSY_STATE then begin
result := DATA_ERROR;
end else begin
result := OK;
end;
end;
function Deflate.deflateParams(lvl, strtg: int): int;
var
c: Config;
begin
result := OK;
if lvl = DEFAULT_COMPRESSION then begin
lvl := 6;
end;
if (lvl < 0) or (lvl > 9) or (strtg < 0) or (strtg > HUFFMAN_ONLY) then begin
result := STREAM_ERROR;
exit;
end;
if (CONFIG_TABLE[level].func <> CONFIG_TABLE[lvl].func) and (stream.totalIn <> 0) then begin
result := stream.deflate(PARTIAL_FLUSH);
end;
if level <> lvl then begin
c := CONFIG_TABLE[level];
level := lvl;
maxLazyMatch := c.maxLazy;
goodMatch := c.goodLength;
niceMatch := c.niceLength;
maxChainLength := c.maxChain;
end;
strategy := strtg;
end;
function Deflate.deflateSetDictionary(const dictionary: byte_Array1d; dictLength: int): int;
var
len: int;
index: int;
n: int;
begin
if (dictionary = nil) or (status <> INIT_STATE) then begin
result := STREAM_ERROR;
exit;
end;
len := dictLength;
index := 0;
stream.adler.update(dictionary, 0, dictLength);
if len < MIN_MATCH then begin
result := OK;
exit;
end;
if len > wSize - MIN_LOOKAHEAD then begin
len := wSize - MIN_LOOKAHEAD;
index := dictLength - len;
end;
arraycopy(dictionary, index, window, 0, len);
strStart := len;
blockStart := len;
insh := int(window[0]) and $ff;
insh := ((insh shl hashShift) xor (int(window[1]) and $ff)) and hashMask;
for n := 0 to len - MIN_MATCH do begin
insh := ((insh shl hashShift) xor (int(window[n + (MIN_MATCH - 1)]) and $ff)) and hashMask;
prev[n and wMask] := head[insh];
head[insh] := short(n);
end;
result := OK;
end;
function Deflate.deflate(flush: int): int;
var
oldFlush: int;
header: int;
levelFlags: int;
bstate: int;
adler: int;
i: int;
begin
if (flush > FINISH) or (flush < 0) then begin
result := STREAM_ERROR;
exit;
end;
if (stream.nextOut = nil) or ((stream.nextIn = nil) and (stream.availIn <> 0)) or ((status = FINISH_STATE) and (flush <> FINISH)) then begin
stream.msg := ERR_MSG[NEED_DICT - STREAM_ERROR];
result := STREAM_ERROR;
exit;
end;
if stream.availOut = 0 then begin
stream.msg := ERR_MSG[NEED_DICT - BUF_ERROR];
result := BUF_ERROR;
exit;
end;
oldFlush := lastFlush;
lastFlush := flush;
if status = INIT_STATE then begin
if wrap = 2 then begin
getGZIPHeader().put(self);
status := BUSY_STATE;
stream.adler.reset();
end else begin
header := (Z_DEFLATED + ((wBits - 8) shl 4)) shl 8;
levelFlags := ((level - 1) and $ff) shr 1;
if levelFlags > 3 then begin
levelFlags := 3;
end;
header := header or (levelFlags shl 6);
if strStart <> 0 then begin
header := header or PRESET_DICT;
end;
inc(header, 31 - (header mod 31));
status := BUSY_STATE;
putShortMSB(header);
if strStart <> 0 then begin
adler := stream.adler.getValue();
putShortMSB(adler shr 16);
putShortMSB(adler);
end;
stream.adler.reset();
end;
end;
if pending <> 0 then begin
stream.flushPending();
if stream.availOut = 0 then begin
lastFlush := -1;
result := OK;
exit;
end;
end else
if (stream.availIn = 0) and (flush <= oldFlush) and (flush <> FINISH) then begin
stream.msg := ERR_MSG[NEED_DICT - BUF_ERROR];
result := BUF_ERROR;
exit;
end;
if (status = FINISH_STATE) and (stream.availIn <> 0) then begin
stream.msg := ERR_MSG[NEED_DICT - BUF_ERROR];
result := BUF_ERROR;
exit;
end;
if (stream.availIn <> 0) or (lookahead <> 0) or ((flush <> NO_FLUSH) and (status <> FINISH_STATE)) then begin
bstate := -1;
case CONFIG_TABLE[level].func of
STORED:
bstate := deflateStored(flush);
FAST:
bstate := deflateFast(flush);
SLOW:
bstate := deflateSlow(flush);
end;
if (bstate = FINISH_STARTED) or (bstate = FINISH_DONE) then begin
status := FINISH_STATE;
end;
if (bstate = NEED_MORE) or (bstate = FINISH_STARTED) then begin
if stream.availOut = 0 then begin
lastFlush := -1;
end;
result := OK;
exit;
end;
if bstate = BLOCK_DONE then begin
if flush = PARTIAL_FLUSH then begin
trAlign();
end else begin
trStoredBlock(0, 0, false);
if flush = FULL_FLUSH then begin
for i := 0 to hashSize - 1 do begin
head[i] := 0;
end;
end;
end;
stream.flushPending();
if stream.availOut = 0 then begin
lastFlush := -1;
result := OK;
exit;
end;
end;
end;
if flush <> FINISH then begin
result := OK;
exit;
end;
if wrap <= 0 then begin
result := STREAM_END;
exit;
end;
adler := stream.adler.getValue();
if wrap = 2 then begin
putByte(adler);
putByte(adler shr 8);
putByte(adler shr 16);
putByte(adler shr 24);
putByte(int(stream.totalIn));
putByte(int(stream.totalIn) shr 8);
putByte(int(stream.totalIn) shr 16);
putByte(int(stream.totalIn) shr 24);
getGZIPHeader().setCRC(adler);
end else begin
putShortMSB(adler shr 16);
putShortMSB(adler);
end;
stream.flushPending();
if wrap > 0 then begin
wrap := -wrap;
end;
if pending <> 0 then begin
result := OK;
end else begin
result := STREAM_END;
end;
end;
{%endregion}
{%region Inflate }
class procedure Inflate.clinit();
begin
MARK := toByteArray1d([0, 0, -1, -1]);
end;
class procedure Inflate.cldone();
begin
MARK := nil;
end;
constructor Inflate.create(stream: ZStream);
begin
inherited create();
needBytes := -1;
was := -1;
crcbuf := byte_Array1d_create(4);
self.stream := stream;
end;
destructor Inflate.destroy;
begin
tmpString.free();
blocks.free();
gheader.free();
inherited destroy;
end;
procedure Inflate.checksum(n, v: int);
var
i: int;
begin
for i := 0 to n - 1 do begin
crcbuf[i] := byte(v);
v := v shr 8;
end;
stream.adler.update(crcbuf, 0, n);
end;
function Inflate.inflateReset(): int;
begin
if stream = nil then begin
result := STREAM_ERROR;
exit;
end;
stream.totalIn := 0;
stream.totalOut := 0;
stream.msg := '';
mode := HEAD;
needBytes := -1;
blocks.reset(stream);
result := OK;
end;
function Inflate.readBytes(z: ZStream; n, r, f: int): int;
begin
readReturn := false;
if needBytes = -1 then begin
needBytes := n;
need := 0;
end;
while needBytes > 0 do begin
if z.availIn = 0 then begin
readReturn := true;
result := r;
exit;
end;
r := f;
dec(z.availIn);
inc(z.totalIn);
need := need or ((int(z.nextIn[z.nextInIndex]) and $ff) shl int((n - needBytes) * 8));
inc(z.nextInIndex);
dec(needBytes);
end;
if n = 2 then begin
need := need and $ffff;
end;
needBytes := -1;
result := r;
end;
function Inflate.readBytes(z: ZStream; r, f: int): int;
begin
readReturn := false;
if tmpString = nil then begin
tmpString := ByteArrayOutputStream.create();
end;
while need <> 0 do begin
if z.availIn = 0 then begin
readReturn := true;
result := r;
exit;
end;
r := f;
dec(z.availIn);
inc(z.totalIn);
tmpString.write(z.nextIn, z.nextInIndex, 1);
z.adler.update(z.nextIn, z.nextInIndex, 1);
inc(z.nextInIndex);
dec(need);
end;
result := r;
end;
function Inflate.readString(z: ZStream; r, f: int): int;
var
b: int;
begin
readReturn := false;
if tmpString = nil then begin
tmpString := ByteArrayOutputStream.create();
end;
b := 0;
repeat
if z.availIn = 0 then begin
readReturn := true;
result := r;
exit;
end;
r := f;
dec(z.availIn);
inc(z.totalIn);
b := z.nextIn[z.nextInIndex];
if b <> 0 then begin
tmpString.write(b);
end;
z.adler.update(z.nextIn, z.nextInIndex, 1);
inc(z.nextInIndex);
until b = 0;
result := r;
end;
function Inflate.inflateEnd(): int;
begin
if blocks <> nil then begin
blocks.free(stream);
end;
result := OK;
end;
function Inflate.inflateInit(w: int): int;
begin
stream.msg := '';
blocks.free();
blocks := nil;
wrap := 0;
if w < 0 then begin
w := -w;
end else begin
wrap := sar(w, 4) + 1;
if w < 48 then begin
w := w and $f;
end;
end;
if (w < 8) or (w > 15) then begin
inflateEnd();
result := STREAM_ERROR;
exit;
end;
if (blocks <> nil) and (wbits <> w) then begin
blocks.free(stream);
blocks.free();
blocks := nil;
end;
wbits := w;
blocks := InfBlocks.create(stream, 1 shl w);
inflateReset();
result := OK;
end;
function Inflate.inflate(f: int): int;
var
r: int;
b: int;
abyte: byte_Array1d;
begin
if (stream = nil) or (stream.nextIn = nil) then begin
if (f = FINISH) and (mode = HEAD) then begin
result := OK;
end else begin
result := STREAM_ERROR;
end;
exit;
end;
if f = FINISH then begin
f := BUF_ERROR;
end else begin
f := OK;
end;
r := BUF_ERROR;
repeat
case mode of
HEAD: begin
if wrap = 0 then begin
mode := BLOCKS_;
continue;
end;
r := readBytes(stream, 2, r, f);
if readReturn then begin
result := r;
exit;
end;
if ((wrap and $02) <> 0) and (need = $8b1f) then begin
stream.adler := Crc32.create();
checksum(2, need);
if gheader = nil then begin
gheader := GZIPHeader.create();
end;
mode := FLAGS_;
continue;
end;
flags := 0;
method := need and $ff;
b := (need shr 8) and $ff;
if ((wrap and $01) = 0) or ((((method shl 8) + b) mod 31) <> 0) then begin
mode := BAD;
stream.msg := 'incorrect header check';
continue;
end;
if (method and $0f) <> Z_DEFLATED then begin
mode := BAD;
stream.msg := 'unknown compression method';
continue;
end;
if sar(method, 4) + 8 > wbits then begin
mode := BAD;
stream.msg := 'invalid window size';
continue;
end;
stream.adler := Adler32.create();
if (b and PRESET_DICT) = 0 then begin
mode := BLOCKS_;
continue;
end;
mode := DICT4;
end;
DICT4: begin
if stream.availIn = 0 then begin
result := r;
exit;
end;
r := f;
dec(stream.availIn);
inc(stream.totalIn);
need := (int(stream.nextIn[stream.nextInIndex]) and $ff) shl 24;
inc(stream.nextInIndex);
mode := DICT3;
end;
DICT3: begin
if stream.availIn = 0 then begin
result := r;
exit;
end;
r := f;
dec(stream.availIn);
inc(stream.totalIn);
need := need or ((int(stream.nextIn[stream.nextInIndex]) and $ff) shl 16);
inc(stream.nextInIndex);
mode := DICT2;
end;
DICT2: begin
if stream.availIn = 0 then begin
result := r;
exit;
end;
r := f;
dec(stream.availIn);
inc(stream.totalIn);
need := need or ((int(stream.nextIn[stream.nextInIndex]) and $ff) shl 8);
inc(stream.nextInIndex);
mode := DICT1;
end;
DICT1: begin
if stream.availIn = 0 then begin
result := r;
exit;
end;
r := f;
dec(stream.availIn);
inc(stream.totalIn);
need := need or (int(stream.nextIn[stream.nextInIndex]) and $ff);
inc(stream.nextInIndex);
stream.adler.reset(need);
mode := DICT0;
result := NEED_DICT;
exit;
end;
DICT0: begin
mode := BAD;
stream.msg := 'need dictionary';
marker := 0;
result := STREAM_ERROR;
exit;
end;
BLOCKS_: begin
r := blocks.proc(stream, r);
if r = DATA_ERROR then begin
mode := BAD;
marker := 0;
continue;
end;
if r = OK then begin
r := f;
end;
if r <> STREAM_END then begin
result := r;
exit;
end;
r := f;
was := stream.adler.getValue();
blocks.reset(stream);
if wrap = 0 then begin
mode := DONE;
continue;
end;
mode := CHECK4;
end;
CHECK4: begin
if stream.availIn = 0 then begin
result := r;
exit;
end;
r := f;
dec(stream.availIn);
inc(stream.totalIn);
need := (int(stream.nextIn[stream.nextInIndex]) and $ff) shl 24;
inc(stream.nextInIndex);
mode := CHECK3;
end;
CHECK3: begin
if stream.availIn = 0 then begin
result := r;
exit;
end;
r := f;
dec(stream.availIn);
inc(stream.totalIn);
need := need or ((int(stream.nextIn[stream.nextInIndex]) and $ff) shl 16);
inc(stream.nextInIndex);
mode := CHECK2;
end;
CHECK2: begin
if stream.availIn = 0 then begin
result := r;
exit;
end;
r := f;
dec(stream.availIn);
inc(stream.totalIn);
need := need or ((int(stream.nextIn[stream.nextInIndex]) and $ff) shl 8);
inc(stream.nextInIndex);
mode := CHECK1;
end;
CHECK1: begin
if stream.availIn = 0 then begin
result := r;
exit;
end;
r := f;
dec(stream.availIn);
inc(stream.totalIn);
need := need or (int(stream.nextIn[stream.nextInIndex]) and $ff);
inc(stream.nextInIndex);
if flags <> 0 then begin
need := byteSwap(need);
end;
if was <> need then begin
stream.msg := 'incorrect data check';
end else
if (flags <> 0) and (gheader <> nil) then begin
gheader.crc := need;
end;
mode := LENGTH_;
end;
LENGTH_: begin
if (wrap <> 0) and (flags <> 0) then begin
r := readBytes(stream, 4, r, f);
if readReturn then begin
result := r;
exit;
end;
if stream.msg = 'incorrect data check' then begin
mode := BAD;
marker := 5;
continue;
end;
if need <> int(stream.totalOut) then begin
stream.msg := 'incorrect length check';
mode := BAD;
continue;
end;
stream.msg := '';
end else begin
if stream.msg = 'incorrect data check' then begin
mode := BAD;
marker := 5;
continue;
end;
end;
mode := DONE;
end;
DONE: begin
result := STREAM_END;
exit;
end;
BAD: begin
result := DATA_ERROR;
exit;
end;
FLAGS_: begin
r := readBytes(stream, 2, r, f);
if readReturn then begin
result := r;
exit;
end;
flags := need and $ffff;
if (flags and $ff) <> Z_DEFLATED then begin
stream.msg := 'unknown compression method';
mode := BAD;
continue;
end;
if (flags and $e000) <> 0 then begin
stream.msg := 'unknown header flags set';
mode := BAD;
continue;
end;
if (flags and $0200) <> 0 then begin
checksum(2, need);
end;
mode := TIME;
end;
TIME: begin
r := readBytes(stream, 4, r, f);
if readReturn then begin
result := r;
exit;
end;
if gheader <> nil then begin
gheader.time := need;
end;
if (flags and $0200) <> 0 then begin
checksum(4, need);
end;
mode := OS;
end;
OS: begin
r := readBytes(stream, 2, r, f);
if readReturn then begin
result := r;
exit;
end;
if gheader <> nil then begin
gheader.xflags := need and $ff;
gheader.os := (need shr 8) and $ff;
end;
if (flags and $0200) <> 0 then begin
checksum(2, need);
end;
mode := EXLEN;
end;
EXLEN: begin
if (flags and $0400) <> 0 then begin
r := readBytes(stream, 2, r, f);
if readReturn then begin
result := r;
exit;
end;
if gheader <> nil then begin
gheader.extra := byte_Array1d_create(need and $ffff);
end;
if (flags and $0200) <> 0 then begin
checksum(2, need);
end;
end else
if gheader <> nil then begin
gheader.extra := nil;
end;
mode := EXTRA;
end;
EXTRA: begin
if (flags and $0400) <> 0 then begin
r := readBytes(stream, r, f);
if readReturn then begin
result := r;
exit;
end;
if gheader <> nil then begin
abyte := tmpString.toByteArray();
tmpString.free();
tmpString := nil;
if length(abyte) = length(gheader.extra) then begin
arraycopy(abyte, 0, gheader.extra, 0, length(abyte));
end else begin
stream.msg := 'bad extra field length';
mode := BAD;
continue;
end;
end;
end else
if gheader <> nil then begin
gheader.extra := nil;
end;
mode := NAME;
end;
NAME: begin
if (flags and $0800) <> 0 then begin
r := readString(stream, r, f);
if readReturn then begin
result := r;
exit;
end;
if gheader <> nil then begin
gheader.name := tmpString.toByteArray();
end;
tmpString.free();
tmpString := nil;
end else
if gheader <> nil then begin
gheader.name := nil;
end;
mode := COMMENT;
end;
COMMENT: begin
if (flags and $1000) <> 0 then begin
r := readString(stream, r, f);
if readReturn then begin
result := r;
exit;
end;
if gheader <> nil then begin
gheader.comment := tmpString.toByteArray();
end;
tmpString.free();
tmpString := nil;
end else
if gheader <> nil then begin
gheader.comment := nil;
end;
mode := HCRC;
end;
HCRC: begin
if (flags and $0200) <> 0 then begin
r := readBytes(stream, 2, r, f);
if readReturn then begin
result := r;
exit;
end;
if gheader <> nil then begin
gheader.hcrc := need and $ffff;
end;
if need <> (stream.adler.getValue() and $ffff) then begin
mode := BAD;
stream.msg := 'header crc mismatch';
marker := 5;
continue;
end;
end;
stream.adler := Crc32.create();
mode := BLOCKS_;
end;
else
result := STREAM_ERROR;
exit;
end;
until false;
end;
function Inflate.inflateSetDictionary(const dictionary: byte_Array1d; dictLength: int): int;
var
index: int;
len: int;
adlerNeed: int;
adler: Checksum32;
begin
if (stream = nil) or ((mode <> DICT0) and (wrap <> 0)) then begin
result := STREAM_ERROR;
exit;
end;
index := 0;
len := dictLength;
adler := stream.adler;
if mode = DICT0 then begin
adlerNeed := adler.getValue();
adler.reset();
adler.update(dictionary, 0, dictLength);
if adler.getValue() <> adlerNeed then begin
result := DATA_ERROR;
exit;
end;
end;
adler.reset();
if len >= 1 shl wbits then begin
len := (1 shl wbits) - 1;
index := dictLength - len;
end;
blocks.setDictionary(dictionary, index, len);
mode := BLOCKS_;
result := OK;
end;
function Inflate.inflateSync(): int;
var
n: int;
p: int;
m: int;
r: long;
w: long;
begin
if stream = nil then begin
result := STREAM_ERROR;
exit;
end;
if mode <> BAD then begin
mode := BAD;
marker := 0;
end;
n := stream.availIn;
if n = 0 then begin
result := BUF_ERROR;
exit;
end;
p := stream.nextInIndex;
m := marker;
while (n <> 0) and (m < 4) do begin
if stream.nextIn[p] = MARK[m] then begin
inc(m);
end else
if stream.nextIn[p] <> 0 then begin
m := 0;
end else begin
m := 4 - m;
end;
inc(p);
dec(n);
end;
inc(stream.totalIn, long(p) - long(stream.nextInIndex));
stream.nextInIndex := p;
stream.availIn := n;
marker := m;
if m <> 4 then begin
result := DATA_ERROR;
exit;
end;
r := stream.totalIn;
w := stream.totalOut;
inflateReset();
stream.totalIn := r;
stream.totalOut := w;
mode := BLOCKS_;
result := OK;
end;
function Inflate.inflateSyncPoint(): int;
begin
if (stream = nil) or (blocks = nil) then begin
result := STREAM_ERROR;
end else
if blocks.syncPoint() then begin
result := 1;
end else begin
result := 0;
end;
end;
{%endregion}
{%region InfTree }
class procedure InfTree.clinit();
begin
FIXED_TL := toIntArray1d([
96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115,
82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, 192,
80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 160,
0, 8, 0, 0, 8, 128, 0, 8, 64, 0, 9, 224,
80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 144,
83, 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, 208,
81, 7, 17, 0, 8, 104, 0, 8, 40, 0, 9, 176,
0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 240,
80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, 227,
83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 200,
81, 7, 13, 0, 8, 100, 0, 8, 36, 0, 9, 168,
0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 232,
80, 7, 8, 0, 8, 92, 0, 8, 28, 0, 9, 152,
84, 7, 83, 0, 8, 124, 0, 8, 60, 0, 9, 216,
82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 184,
0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, 248,
80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163,
83, 7, 35, 0, 8, 114, 0, 8, 50, 0, 9, 196,
81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 164,
0, 8, 2, 0, 8, 130, 0, 8, 66, 0, 9, 228,
80, 7, 7, 0, 8, 90, 0, 8, 26, 0, 9, 148,
84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 212,
82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9, 180,
0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 244,
80, 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0,
83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 204,
81, 7, 15, 0, 8, 102, 0, 8, 38, 0, 9, 172,
0, 8, 6, 0, 8, 134, 0, 8, 70, 0, 9, 236,
80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 156,
84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, 220,
82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 188,
0, 8, 14, 0, 8, 142, 0, 8, 78, 0, 9, 252,
96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131,
82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, 194,
80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 162,
0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 226,
80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, 146,
83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 210,
81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 178,
0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 242,
80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258,
83, 7, 43, 0, 8, 117, 0, 8, 53, 0, 9, 202,
81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 170,
0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 234,
80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 154,
84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 218,
82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 186,
0, 8, 13, 0, 8, 141, 0, 8, 77, 0, 9, 250,
80, 7, 3, 0, 8, 83, 0, 8, 19, 85, 8, 195,
83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 198,
81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, 166,
0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 230,
80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 150,
84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 214,
82, 7, 19, 0, 8, 107, 0, 8, 43, 0, 9, 182,
0, 8, 11, 0, 8, 139, 0, 8, 75, 0, 9, 246,
80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0,
83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9, 206,
81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 174,
0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 238,
80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 158,
84, 7, 99, 0, 8, 127, 0, 8, 63, 0, 9, 222,
82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 190,
0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 254,
96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115,
82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, 193,
80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 161,
0, 8, 0, 0, 8, 128, 0, 8, 64, 0, 9, 225,
80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 145,
83, 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, 209,
81, 7, 17, 0, 8, 104, 0, 8, 40, 0, 9, 177,
0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 241,
80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, 227,
83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 201,
81, 7, 13, 0, 8, 100, 0, 8, 36, 0, 9, 169,
0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 233,
80, 7, 8, 0, 8, 92, 0, 8, 28, 0, 9, 153,
84, 7, 83, 0, 8, 124, 0, 8, 60, 0, 9, 217,
82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 185,
0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, 249,
80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163,
83, 7, 35, 0, 8, 114, 0, 8, 50, 0, 9, 197,
81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 165,
0, 8, 2, 0, 8, 130, 0, 8, 66, 0, 9, 229,
80, 7, 7, 0, 8, 90, 0, 8, 26, 0, 9, 149,
84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 213,
82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9, 181,
0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 245,
80, 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0,
83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 205,
81, 7, 15, 0, 8, 102, 0, 8, 38, 0, 9, 173,
0, 8, 6, 0, 8, 134, 0, 8, 70, 0, 9, 237,
80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 157,
84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, 221,
82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 189,
0, 8, 14, 0, 8, 142, 0, 8, 78, 0, 9, 253,
96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131,
82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, 195,
80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 163,
0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 227,
80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, 147,
83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 211,
81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 179,
0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 243,
80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258,
83, 7, 43, 0, 8, 117, 0, 8, 53, 0, 9, 203,
81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 171,
0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 235,
80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 155,
84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 219,
82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 187,
0, 8, 13, 0, 8, 141, 0, 8, 77, 0, 9, 251,
80, 7, 3, 0, 8, 83, 0, 8, 19, 85, 8, 195,
83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 199,
81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, 167,
0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 231,
80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 151,
84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 215,
82, 7, 19, 0, 8, 107, 0, 8, 43, 0, 9, 183,
0, 8, 11, 0, 8, 139, 0, 8, 75, 0, 9, 247,
80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0,
83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9, 207,
81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 175,
0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 239,
80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 159,
84, 7, 99, 0, 8, 127, 0, 8, 63, 0, 9, 223,
82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 191,
0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 255
]);
FIXED_TD := toIntArray1d([
80, 5, 1, 87, 5, 257, 83, 5, 17, 91, 5, 4097,
81, 5, 5, 89, 5, 1025, 85, 5, 65, 93, 5, 16385,
80, 5, 3, 88, 5, 513, 84, 5, 33, 92, 5, 8193,
82, 5, 9, 90, 5, 2049, 86, 5, 129, 192, 5, 24577,
80, 5, 2, 87, 5, 385, 83, 5, 25, 91, 5, 6145,
81, 5, 7, 89, 5, 1537, 85, 5, 97, 93, 5, 24577,
80, 5, 4, 88, 5, 769, 84, 5, 49, 92, 5, 12289,
82, 5, 13, 90, 5, 3073, 86, 5, 193, 192, 5, 24577
]);
CPLENS := toIntArray1d([
3, 4, 5, 6, 7, 8, 9, 10, 11, 13,
15, 17, 19, 23, 27, 31, 35, 43, 51, 59,
67, 83, 99, 115, 131, 163, 195, 227, 258, 0,
0
]);
CPLEXT := toIntArray1d([
0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
4, 4, 4, 4, 5, 5, 5, 5, 0, 112,
112
]);
CPDIST := toIntArray1d([
1, 2, 3, 4, 5, 7, 9, 13, 17,
25, 33, 49, 65, 97, 129, 193, 257, 385, 513,
769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385,
24577
]);
CPDEXT := toIntArray1d([
0, 0, 0, 0, 1, 1, 2, 2, 3, 3,
4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
9, 9, 10, 10, 11, 11, 12, 12, 13, 13
]);
end;
class procedure InfTree.cldone();
begin
CPDEXT := nil;
CPDIST := nil;
CPLEXT := nil;
CPLENS := nil;
FIXED_TD := nil;
FIXED_TL := nil;
end;
class procedure InfTree.inflateTreesFixed(const bl, bd: int_Array1d; const tl, td: int_Array2d);
begin
bl[0] := FIXED_BL;
bd[0] := FIXED_BD;
tl[0] := FIXED_TL;
td[0] := FIXED_TD;
end;
constructor InfTree.create();
begin
inherited create();
end;
procedure InfTree.initWorkArea(vsize: int);
var
i: int;
begin
if hn = nil then begin
hn := int_Array1d_create(1);
v := int_Array1d_create(vsize);
c := int_Array1d_create(BMAX + 1);
r := int_Array1d_create(3);
u := int_Array1d_create(BMAX);
x := int_Array1d_create(BMAX + 1);
end;
if length(v) < vsize then begin
v := int_Array1d_create(vsize);
end;
for i := 0 to length(v) - 1 do begin
v[i] := 0;
end;
for i := 0 to length(c) - 1 do begin
c[i] := 0;
end;
for i := 0 to length(r) - 1 do begin
r[i] := 0;
end;
for i := 0 to length(u) - 1 do begin
u[i] := 0;
end;
for i := 0 to length(x) - 1 do begin
x[i] := 0;
end;
end;
function InfTree.huftBuild(const b: int_Array1d; bindex, n, s: int; const d, e, t, m, hp, hn, v: int_Array1d): int;
var
a: int;
f: int;
g: int;
h: int;
i: int;
j: int;
k: int;
l: int;
p: int;
q: int;
w: int;
xp: int;
y: int;
z: int;
mask: int;
begin
p := 0;
i := n;
repeat
inc(c[b[bindex + p]]);
inc(p);
dec(i);
until i = 0;
if c[0] = n then begin
t[0] := -1;
m[0] := 0;
result := OK;
exit;
end;
l := m[0];
j := 1;
while j <= BMAX do begin
if c[j] <> 0 then begin
break;
end;
inc(j);
end;
k := j;
if l < j then begin
l := j;
end;
i := BMAX;
while i > 0 do begin
if c[i] <> 0 then begin
break;
end;
dec(i);
end;
g := i;
if l > i then begin
l := i;
end;
m[0] := l;
y := 1 shl j;
while j < i do begin
dec(y, c[j]);
if y < 0 then begin
result := DATA_ERROR;
exit;
end;
inc(j);
y := y shl 1;
end;
dec(y, c[i]);
if y < 0 then begin
result := DATA_ERROR;
exit;
end;
inc(c[i], y);
x[1] := 0;
j := 0;
p := 1;
xp := 2;
dec(i);
while i <> 0 do begin
inc(j, c[p]);
x[xp] := j;
inc(xp);
inc(p);
dec(i);
end;
i := 0;
p := 0;
repeat
j := b[bindex + p];
if j <> 0 then begin
v[x[j]] := i;
inc(x[j]);
end;
inc(p);
inc(i);
until i >= n;
n := x[g];
x[0] := 0;
i := 0;
p := 0;
h := -1;
w := -l;
u[0] := 0;
q := 0;
z := 0;
while k <= g do begin
a := c[k];
while a <> 0 do begin
dec(a);
while k > w + l do begin
inc(h);
inc(w, l);
z := g - w;
if z > l then begin
z := l;
end;
j := k - w;
f := 1 shl j;
if f > a + 1 then begin
dec(f, a + 1);
xp := k;
if j < z then begin
inc(j);
while j < z do begin
f := f shl 1;
inc(xp);
if f <= c[xp] then begin
break;
end;
dec(f, c[xp]);
inc(j);
end;
end;
end;
z := 1 shl j;
if hn[0] + z > MANY then begin
result := DATA_ERROR;
exit;
end;
q := hn[0];
u[h] := q;
inc(hn[0], z);
if h <> 0 then begin
x[h] := i;
r[0] := byte(j);
r[1] := byte(l);
j := i shr (w - l);
r[2] := q - u[h - 1] - j;
arraycopy(r, 0, hp, (u[h - 1] + j) * 3, 3);
end else begin
t[0] := q;
end;
end;
r[1] := byte(k - w);
if p >= n then begin
r[0] := 128 + 64;
end else begin
if v[p] < s then begin
if v[p] < 256 then begin
r[0] := 0;
end else begin
r[0] := 32 + 64;
end;
r[2] := v[p];
end else begin
r[0] := byte(e[v[p] - s] + (16 + 64));
r[2] := d[v[p] - s];
end;
inc(p);
end;
f := 1 shl (k - w);
j := i shr w;
while j < z do begin
arraycopy(r, 0, hp, (q + j) * 3, 3);
inc(j, f);
end;
j := 1 shl (k - 1);
while (i and j) <> 0 do begin
i := i xor j;
j := j shr 1;
end;
i := i xor j;
mask := (1 shl w) - 1;
while (i and mask) <> x[h] do begin
dec(h);
dec(w, l);
mask := (1 shl w) - 1;
end;
end;
inc(k);
end;
if (y <> 0) and (g <> 1) then begin
result := BUF_ERROR;
end else begin
result := OK;
end;
end;
function InfTree.inflateTreesBits(const c, bb, tb, hp: int_Array1d; z: ZStream): int;
begin
initWorkArea(19);
hn[0] := 0;
result := huftBuild(c, 0, 19, 19, nil, nil, tb, bb, hp, hn, v);
if result = DATA_ERROR then begin
z.msg := 'oversubscribed dynamic bit lengths tree';
end else
if (result = BUF_ERROR) or (bb[0] = 0) then begin
z.msg := 'incomplete dynamic bit lengths tree';
result := DATA_ERROR;
end;
end;
function InfTree.inflateTreesDynamic(nl, nd: int; const c, bl, bd, tl, td, hp: int_Array1d; z: ZStream): int;
begin
initWorkArea(288);
hn[0] := 0;
result := huftBuild(c, 0, nl, 257, CPLENS, CPLEXT, tl, bl, hp, hn, v);
if (result <> OK) or (bl[0] = 0) then begin
if result = DATA_ERROR then begin
z.msg := 'oversubscribed literal/length tree';
end else
if result <> MEM_ERROR then begin
z.msg := 'incomplete literal/length tree';
result := DATA_ERROR;
end;
exit;
end;
initWorkArea(288);
result := huftBuild(c, nl, nd, 0, CPDIST, CPDEXT, td, bd, hp, hn, v);
if (result <> OK) or ((bd[0] = 0) and (nl > 257)) then begin
case result of
DATA_ERROR: begin
z.msg := 'oversubscribed distance tree';
end;
BUF_ERROR: begin
z.msg := 'incomplete distance tree';
result := DATA_ERROR;
end;
else
if result <> MEM_ERROR then begin
z.msg := 'empty distance tree with lengths';
result := DATA_ERROR;
end;
end;
exit;
end;
result := OK;
end;
{%endregion}
{%region InfCodes }
class procedure InfCodes.clinit();
begin
INFLATE_MASK := toIntArray1d([
$00000000, $00000001, $00000003, $00000007, $0000000f,
$0000001f, $0000003f, $0000007f, $000000ff, $000001ff,
$000003ff, $000007ff, $00000fff, $00001fff, $00003fff,
$00007fff, $0000ffff
]);
end;
class procedure InfCodes.cldone();
begin
INFLATE_MASK := nil;
end;
constructor InfCodes.create();
begin
inherited create();
end;
function InfCodes.inflateFast(bl, bd: int; const tl: int_Array1d; tlIndex: int; const td: int_Array1d; tdIndex: int; s: InfBlocks; z: ZStream): int;
var
tp: int_Array1d;
t: int;
e: int;
b: int;
k: int;
p: int;
n: int;
q: int;
m: int;
ml: int;
md: int;
c: int;
d: int;
r: int;
tpIndex: int;
tpIndexT3: int;
begin
p := z.nextInIndex;
n := z.availIn;
b := s.bitb;
k := s.bitk;
q := s.write;
if q < s.read then begin
m := s.read - q - 1;
end else begin
m := s.end_ - q;
end;
ml := INFLATE_MASK[bl];
md := INFLATE_MASK[bd];
repeat
while k < 20 do begin
dec(n);
b := b or ((int(z.nextIn[p]) and $ff) shl k);
inc(p);
inc(k, 8);
end;
t := b and ml;
tp := tl;
tpIndex := tlIndex;
tpIndexT3 := (tpIndex + t) * 3;
e := tp[tpIndexT3];
if e = 0 then begin
b := sar(b, tp[tpIndexT3 + 1]);
dec(k, tp[tpIndexT3 + 1]);
s.window[q] := byte(tp[tpIndexT3 + 2]);
inc(q);
dec(m);
continue;
end;
repeat
b := sar(b, tp[tpIndexT3 + 1]);
dec(k, tp[tpIndexT3 + 1]);
if (e and $10) <> 0 then begin
e := e and $f;
c := tp[tpIndexT3 + 2] + (b and INFLATE_MASK[e]);
b := sar(b, e);
dec(k, e);
while k < 15 do begin
dec(n);
b := b or ((int(z.nextIn[p]) and $ff) shl k);
inc(p);
inc(k, 8);
end;
t := b and md;
tp := td;
tpIndex := tdIndex;
tpIndexT3 := (tpIndex + t) * 3;
e := tp[tpIndexT3];
repeat
b := sar(b, tp[tpIndexT3 + 1]);
dec(k, tp[tpIndexT3 + 1]);
if (e and $10) <> 0 then begin
e := e and $f;
while k < e do begin
dec(n);
b := b or ((int(z.nextIn[p]) and $ff) shl k);
inc(p);
inc(k, 8);
end;
d := tp[tpIndexT3 + 2] + (b and INFLATE_MASK[e]);
b := sar(b, e);
dec(k, e);
dec(m, c);
if q >= d then begin
r := q - d;
if d = 1 then begin
s.window[q] := s.window[r];
inc(q);
inc(r);
s.window[q] := s.window[r];
inc(q);
inc(r);
dec(c, 2);
end else begin
arraycopy(s.window, r, s.window, q, 2);
inc(q, 2);
inc(r, 2);
dec(c, 2);
end;
end else begin
r := q - d;
repeat
inc(r, s.end_);
until r >= 0;
e := s.end_ - r;
if c > e then begin
dec(c, e);
if (q - r > 0) and (q - r < e) then begin
repeat
s.window[q] := s.window[r];
inc(q);
inc(r);
dec(e);
until e = 0;
end else begin
arraycopy(s.window, r, s.window, q, e);
inc(q, e);
inc(r, e);
e := 0;
end;
r := 0;
end;
end;
if (q - r > 0) and (q - r < c) then begin
repeat
s.window[q] := s.window[r];
inc(q);
inc(r);
dec(c);
until c = 0;
end else begin
arraycopy(s.window, r, s.window, q, c);
inc(q, c);
inc(r, c);
c := 0;
end;
break;
end else
if (e and $40) = 0 then begin
inc(t, tp[tpIndexT3 + 2] + (b and INFLATE_MASK[e]));
tpIndexT3 := (tpIndex + t) * 3;
e := tp[tpIndexT3];
end else begin
z.msg := 'invalid distance code';
c := z.availIn - n;
if sar(k, 3) < c then begin
c := sar(k, 3);
end;
inc(n, c);
dec(p, c);
dec(k, c shl 3);
s.update(z, b, k, n, p, q);
result := DATA_ERROR;
exit;
end;
until false;
break;
end;
if (e and $40) = 0 then begin
inc(t, tp[tpIndexT3 + 2] + (b and INFLATE_MASK[e]));
tpIndexT3 := (tpIndex + t) * 3;
e := tp[tpIndexT3];
if e = 0 then begin
b := sar(b, tp[tpIndexT3 + 1]);
dec(k, tp[tpIndexT3 + 1]);
s.window[q] := byte(tp[tpIndexT3 + 2]);
inc(q);
dec(m);
break;
end;
end else
if (e and $20) <> 0 then begin
c := z.availIn - n;
if sar(k, 3) < c then begin
c := sar(k, 3);
end;
inc(n, c);
dec(p, c);
dec(k, c shl 3);
s.update(z, b, k, n, p, q);
result := STREAM_END;
exit;
end else begin
z.msg := 'invalid literal/length code';
c := z.availIn - n;
if sar(k, 3) < c then begin
c := sar(k, 3);
end;
inc(n, c);
dec(p, c);
dec(k, c shl 3);
s.update(z, b, k, n, p, q);
result := DATA_ERROR;
exit;
end;
until false;
until (m < 258) or (n < 10);
c := z.availIn - n;
if sar(k, 3) < c then begin
c := sar(k, 3);
end;
inc(n, c);
dec(p, c);
dec(k, c shl 3);
s.update(z, b, k, n, p, q);
result := OK;
end;
procedure InfCodes.init(bl, bd: int; const tl: int_Array1d; tlIndex: int; const td: int_Array1d; tdIndex: int);
begin
mode := START;
lbits := byte(bl);
dbits := byte(bd);
ltree := tl;
ltreeIndex := tlIndex;
dtree := td;
dtreeIndex := tdIndex;
tree := nil;
end;
function InfCodes.proc(s: InfBlocks; z: ZStream; r: int): int;
var
tindex: int;
j: int;
e: int;
b: int;
k: int;
p: int;
n: int;
q: int;
m: int;
f: int;
begin
p := z.nextInIndex;
n := z.availIn;
b := s.bitb;
k := s.bitk;
q := s.write;
if q < s.read then begin
m := s.read - q - 1;
end else begin
m := s.end_ - q;
end;
repeat
case mode of
START: begin
if (m >= 258) and (n >= 10) then begin
s.update(z, b, k, n, p, q);
r := inflateFast(lbits, dbits, ltree, ltreeIndex, dtree, dtreeIndex, s, z);
p := z.nextInIndex;
n := z.availIn;
b := s.bitb;
k := s.bitk;
q := s.write;
if q < s.read then begin
m := s.read - q - 1;
end else begin
m := s.end_ - q;
end;
if r <> OK then begin
if r = STREAM_END then begin
mode := WASH;
end else begin
mode := BADCODE;
end;
continue;
end;
end;
need := lbits;
tree := ltree;
treeIndex := ltreeIndex;
mode := LEN_;
end;
LEN_: begin
j := need;
while k < j do begin
if n <> 0 then begin
r := OK;
end else begin
s.update(z, b, k, n, p, q);
result := s.inflateFlush(z, r);
exit;
end;
dec(n);
b := b or ((int(z.nextIn[p]) and $ff) shl k);
inc(p);
inc(k, 8);
end;
tindex := (treeIndex + (b and INFLATE_MASK[j])) * 3;
b := b shr tree[tindex + 1];
dec(k, tree[tindex + 1]);
e := tree[tindex];
if e = 0 then begin
lit := tree[tindex + 2];
mode := LIT_;
continue;
end;
if (e and $10) <> 0 then begin
get := e and $0f;
len := tree[tindex + 2];
mode := LENEXT;
continue;
end;
if (e and $40) = 0 then begin
need := e;
treeIndex := (tindex div 3) + tree[tindex + 2];
continue;
end;
if (e and $20) <> 0 then begin
mode := WASH;
continue;
end;
mode := BADCODE;
z.msg := 'invalid literal/length code';
r := DATA_ERROR;
s.update(z, b, k, n, p, q);
result := s.inflateFlush(z, r);
exit;
end;
LENEXT: begin
j := get;
while k < j do begin
if n <> 0 then begin
r := OK;
end else begin
s.update(z, b, k, n, p, q);
result := s.inflateFlush(z, r);
exit;
end;
dec(n);
b := b or ((int(z.nextIn[p]) and $ff) shl k);
inc(p);
inc(k, 8);
end;
inc(len, b and INFLATE_MASK[j]);
b := sar(b, j);
dec(k, j);
need := dbits;
tree := dtree;
treeIndex := dtreeIndex;
mode := DIST_;
end;
DIST_: begin
j := need;
while k < j do begin
if n <> 0 then begin
r := OK;
end else begin
s.update(z, b, k, n, p, q);
result := s.inflateFlush(z, r);
exit;
end;
dec(n);
b := b or ((int(z.nextIn[p]) and $ff) shl k);
inc(p);
inc(k, 8);
end;
tindex := (treeIndex + (b and INFLATE_MASK[j])) * 3;
b := sar(b, tree[tindex + 1]);
dec(k, tree[tindex + 1]);
e := tree[tindex];
if (e and $10) <> 0 then begin
get := e and $f;
dist := tree[tindex + 2];
mode := DISTEXT;
continue;
end;
if (e and $40) = 0 then begin
need := e;
treeIndex := (tindex div 3) + tree[tindex + 2];
continue;
end;
mode := BADCODE;
z.msg := 'invalid distance code';
r := DATA_ERROR;
s.update(z, b, k, n, p, q);
result := s.inflateFlush(z, r);
exit;
end;
DISTEXT: begin
j := get;
while k < j do begin
if n <> 0 then begin
r := OK;
end else begin
s.update(z, b, k, n, p, q);
result := s.inflateFlush(z, r);
exit;
end;
dec(n);
b := b or ((int(z.nextIn[p]) and $ff) shl k);
inc(p);
inc(k, 8);
end;
inc(dist, b and INFLATE_MASK[j]);
b := sar(b, j);
dec(k, j);
mode := COPY;
end;
COPY: begin
f := q - dist;
while f < 0 do begin
inc(f, s.end_);
end;
while len <> 0 do begin
if m = 0 then begin
if (q = s.end_) and (s.read <> 0) then begin
q := 0;
if q < s.read then begin
m := s.read - q - 1;
end else begin
m := s.end_ - q;
end;
end;
if m = 0 then begin
s.write := q;
r := s.inflateFlush(z, r);
q := s.write;
if q < s.read then begin
m := s.read - q - 1;
end else begin
m := s.end_ - q;
end;
if (q = s.end_) and (s.read <> 0) then begin
q := 0;
if q < s.read then begin
m := s.read - q - 1;
end else begin
m := s.end_ - q;
end;
end;
if m = 0 then begin
s.update(z, b, k, n, p, q);
result := s.inflateFlush(z, r);
exit;
end;
end;
end;
s.window[q] := s.window[f];
inc(q);
inc(f);
dec(m);
if f = s.end_ then begin
f := 0;
end;
dec(len);
end;
mode := START;
end;
LIT_: begin
if m = 0 then begin
if (q = s.end_) and (s.read <> 0) then begin
q := 0;
if q < s.read then begin
m := s.read - q - 1;
end else begin
m := s.end_ - q;
end;
end;
if m = 0 then begin
s.write := q;
r := s.inflateFlush(z, r);
q := s.write;
if q < s.read then begin
m := s.read - q - 1;
end else begin
m := s.end_ - q;
end;
if (q = s.end_) and (s.read <> 0) then begin
q := 0;
if q < s.read then begin
m := s.read - q - 1;
end else begin
m := s.end_ - q;
end;
end;
if m = 0 then begin
s.update(z, b, k, n, p, q);
result := s.inflateFlush(z, r);
exit;
end;
end;
end;
r := OK;
s.window[q] := byte(lit);
inc(q);
dec(m);
mode := START;
end;
WASH: begin
if k > 7 then begin
dec(k, 8);
inc(n);
dec(p);
end;
s.write := q;
r := s.inflateFlush(z, r);
q := s.write;
if q < s.read then begin
m := s.read - q - 1;
end else begin
m := s.end_ - q;
end;
if s.read <> s.write then begin
s.update(z, b, k, n, p, q);
result := s.inflateFlush(z, r);
exit;
end;
mode := END_;
end;
END_: begin
r := STREAM_END;
s.update(z, b, k, n, p, q);
result := s.inflateFlush(z, r);
exit;
end;
BADCODE: begin
r := DATA_ERROR;
s.update(z, b, k, n, p, q);
result := s.inflateFlush(z, r);
exit;
end;
else
r := STREAM_ERROR;
s.update(z, b, k, n, p, q);
result := s.inflateFlush(z, r);
exit;
end;
until false;
end;
{%endregion}
{%region InfBlocks }
class procedure InfBlocks.clinit();
begin
INFLATE_MASK := toIntArray1d([
$0000, $0001, $0003, $0007, $000f, $001f, $003f, $007f, $00ff, $01ff,
$03ff, $07ff, $0fff, $1fff, $3fff, $7fff, $ffff
]);
BORDER := toIntArray1d([
16, 17, 18, 0, 8, 7, 9, 6, 10, 5,
11, 4, 12, 3, 13, 2, 14, 1, 15
]);
end;
class procedure InfBlocks.cldone();
begin
BORDER := nil;
INFLATE_MASK := nil;
end;
constructor InfBlocks.create(z: ZStream; w: int);
begin
inherited create();
end_ := w;
window := byte_Array1d_create(w);
check := z.istate.wrap <> 0;
mode := TYPE_;
bb := int_Array1d_create(1);
tb := int_Array1d_create(1);
hufts := int_Array1d_create(MANY * 3);
codes := InfCodes.create();
itree := InfTree.create();
reset(z);
end;
destructor InfBlocks.destroy;
begin
itree.free();
codes.free();
inherited destroy;
end;
procedure InfBlocks.proc1();
var
bl: int_Array1d;
bd: int_Array1d;
tl: int_Array2d;
td: int_Array2d;
begin
bl := int_Array1d_create(1);
bd := int_Array1d_create(1);
tl := int_Array2d_create(1);
td := int_Array2d_create(1);
InfTree.inflateTreesFixed(bl, bd, tl, td);
codes.init(bl[0], bd[0], tl[0], 0, td[0], 0);
end;
procedure InfBlocks.reset(z: ZStream);
begin
mode := TYPE_;
bitk := 0;
bitb := 0;
read := 0;
write := 0;
if check then begin
z.adler.reset();
end;
end;
procedure InfBlocks.free(z: ZStream);
begin
reset(z);
window := nil;
hufts := nil;
end;
procedure InfBlocks.setDictionary(const d: byte_Array1d; start, n: int);
begin
arraycopy(d, start, window, 0, n);
read := n;
write := n;
end;
procedure InfBlocks.update(z: ZStream; b, k, n, p, q: int);
begin
bitb := b;
bitk := k;
z.availIn := n;
inc(z.totalIn, long(p) - long(z.nextInIndex));
z.nextInIndex := p;
write := q;
end;
function InfBlocks.proc(z: ZStream; r: int): int;
var
t: int;
b: int;
k: int;
p: int;
n: int;
q: int;
m: int;
i: int;
j: int;
c: int;
bl: int_Array1d;
bd: int_Array1d;
tl: int_Array1d;
td: int_Array1d;
begin
p := z.nextInIndex;
n := z.availIn;
b := bitb;
k := bitk;
q := write;
if q < read then begin
m := read - q - 1;
end else begin
m := end_ - q;
end;
repeat
case mode of
TYPE_: begin
while k < 3 do begin
if n <> 0 then begin
r := OK;
end else begin
update(z, b, k, n, p, q);
result := inflateFlush(z, r);
exit;
end;
dec(n);
b := b or ((int(z.nextIn[p]) and $ff) shl k);
inc(p);
inc(k, 8);
end;
t := b and $07;
last := t and $01;
case t shr 1 of
0: begin
b := b shr 3;
dec(k, 3);
t := k and $07;
b := b shr t;
dec(k, t);
mode := LENS;
end;
1: begin
proc1();
b := b shr 3;
dec(k, 3);
mode := CODES_;
end;
2: begin
b := b shr 3;
dec(k, 3);
mode := TABLE_;
end;
3: begin
b := b shr 3;
dec(k, 3);
mode := BAD;
z.msg := 'invalid block type';
r := DATA_ERROR;
update(z, b, k, n, p, q);
result := inflateFlush(z, r);
exit;
end;
end;
end;
LENS: begin
while k < 32 do begin
if n <> 0 then begin
r := OK;
end else begin
update(z, b, k, n, p, q);
result := inflateFlush(z, r);
exit;
end;
dec(n);
b := b or ((int(z.nextIn[p]) and $ff) shl k);
inc(p);
inc(k, 8);
end;
if (((not b) shr 16) and $ffff) <> (b and $ffff) then begin
mode := BAD;
z.msg := 'invalid stored block lengths';
r := DATA_ERROR;
update(z, b, k, n, p, q);
result := inflateFlush(z, r);
exit;
end;
left := b and $ffff;
b := 0;
k := 0;
if left <> 0 then begin
mode := STORED;
end else begin
if last <> 0 then begin
mode := DRY;
end else begin
mode := TYPE_;
end;
end;
end;
STORED: begin
if n = 0 then begin
update(z, b, k, n, p, q);
result := inflateFlush(z, r);
exit;
end;
if m = 0 then begin
if (q = end_) and (read <> 0) then begin
q := 0;
if q < read then begin
m := read - q - 1;
end else begin
m := end_ - q;
end;
end;
if m = 0 then begin
write := q;
r := inflateFlush(z, r);
q := write;
if q < read then begin
m := read - q - 1;
end else begin
m := end_ - q;
end;
if (q = end_) and (read <> 0) then begin
q := 0;
if q < read then begin
m := read - q - 1;
end else begin
m := end_ - q;
end;
end;
if m = 0 then begin
update(z, b, k, n, p, q);
result := inflateFlush(z, r);
exit;
end;
end;
end;
r := OK;
t := left;
if t > n then begin
t := n;
end;
if t > m then begin
t := m;
end;
arraycopy(z.nextIn, p, window, q, t);
inc(p, t);
dec(n, t);
inc(q, t);
dec(m, t);
dec(left, t);
if left <> 0 then begin
continue;
end;
if last <> 0 then begin
mode := DRY;
end else begin
mode := TYPE_;
end;
end;
TABLE_: begin
while k < 14 do begin
if n <> 0 then begin
r := OK;
end else begin
update(z, b, k, n, p, q);
result := inflateFlush(z, r);
exit;
end;
dec(n);
b := b or ((int(z.nextIn[p]) and $ff) shl k);
inc(p);
inc(k, 8);
end;
t := b and $3fff;
table := t;
if ((t and $1f) > 29) or (((t shr 5) and $1f) > 29) then begin
mode := BAD;
z.msg := 'too many length or distance symbols';
r := DATA_ERROR;
update(z, b, k, n, p, q);
result := inflateFlush(z, r);
exit;
end;
t := (t and $1f) + ((t shr 5) and $1f) + 258;
if (blens = nil) or (length(blens) < t) then begin
blens := int_Array1d_create(t);
end else begin
for i := 0 to t - 1 do begin
blens[i] := 0;
end;
end;
b := b shr 14;
dec(k, 14);
index := 0;
mode := BTREE;
end;
BTREE: begin
while index < (table shr 10) + 4 do begin
while k < 3 do begin
if n <> 0 then begin
r := OK;
end else begin
update(z, b, k, n, p, q);
result := inflateFlush(z, r);
exit;
end;
dec(n);
b := b or ((int(z.nextIn[p]) and $ff) shl k);
inc(p);
inc(k, 8);
end;
blens[BORDER[index]] := b and $07;
inc(index);
b := b shr 3;
dec(k, 3);
end;
while index < 19 do begin
blens[BORDER[index]] := 0;
inc(index);
end;
bb[0] := 7;
t := itree.inflateTreesBits(blens, bb, tb, hufts, z);
if t <> OK then begin
r := t;
if r = DATA_ERROR then begin
blens := nil;
mode := BAD;
end;
update(z, b, k, n, p, q);
result := inflateFlush(z, r);
exit;
end;
index := 0;
mode := DTREE;
end;
DTREE: begin
repeat
t := table;
if index >= (t and $1f) + ((t shr 5) and $1f) + 258 then begin
break;
end;
t := bb[0];
while k < t do begin
if n <> 0 then begin
r := OK;
end else begin
update(z, b, k, n, p, q);
result := inflateFlush(z, r);
exit;
end;
dec(n);
b := b or ((int(z.nextIn[p]) and $ff) shl k);
inc(p);
inc(k, 8);
end;
t := hufts[(tb[0] + (b and INFLATE_MASK[t])) * 3 + 1];
c := hufts[(tb[0] + (b and INFLATE_MASK[t])) * 3 + 2];
if c < 16 then begin
b := b shr t;
dec(k, t);
blens[index] := c;
inc(index);
end else begin
if c = 18 then begin
i := 7;
j := 11;
end else begin
i := c - 14;
j := 3;
end;
while k < t + i do begin
if n <> 0 then begin
r := OK;
end else begin
update(z, b, k, n, p, q);
result := inflateFlush(z, r);
exit;
end;
dec(n);
b := b or ((int(z.nextIn[p]) and $ff) shl k);
inc(p);
inc(k, 8);
end;
b := b shr t;
dec(k, t);
inc(j, b and INFLATE_MASK[i]);
b := b shr i;
dec(k, i);
i := index;
t := table;
if (i + j > (t and $1f) + ((t shr 5) and $1f) + 258) or ((c = 16) and (i < 1)) then begin
blens := nil;
mode := BAD;
z.msg := 'invalid bit length repeat';
r := DATA_ERROR;
update(z, b, k, n, p, q);
result := inflateFlush(z, r);
exit;
end;
if c = 16 then begin
c := blens[i - 1];
end else begin
c := 0;
end;
repeat
blens[i] := c;
inc(i);
dec(j);
until j = 0;
index := i;
end;
until false;
tb[0] := -1;
bl := int_Array1d_create(1);
bd := int_Array1d_create(1);
tl := int_Array1d_create(1);
td := int_Array1d_create(1);
bl[0] := 9;
bd[0] := 6;
t := table;
t := itree.inflateTreesDynamic((t and $1f) + 257, ((t shr 5) and $1f) + 1, blens, bl, bd, tl, td, hufts, z);
if t <> OK then begin
if t = DATA_ERROR then begin
blens := nil;
mode := BAD;
end;
r := t;
update(z, b, k, n, p, q);
result := inflateFlush(z, r);
exit;
end;
codes.init(bl[0], bd[0], hufts, tl[0], hufts, td[0]);
mode := CODES_;
end;
CODES_: begin
update(z, b, k, n, p, q);
r := codes.proc(self, z, r);
if r <> STREAM_END then begin
result := inflateFlush(z, r);
exit;
end;
r := OK;
p := z.nextInIndex;
n := z.availIn;
b := bitb;
k := bitk;
q := write;
if q < read then begin
m := read - q - 1;
end else begin
m := end_ - q;
end;
if last = 0 then begin
mode := TYPE_;
end else begin
mode := DRY;
end;
end;
DRY: begin
write := q;
r := inflateFlush(z, r);
q := write;
if q < read then begin
m := read - q - 1;
end else begin
m := end_ - q;
end;
if read <> write then begin
update(z, b, k, n, p, q);
result := inflateFlush(z, r);
exit;
end;
mode := DONE;
end;
DONE: begin
r := STREAM_END;
update(z, b, k, n, p, q);
result := inflateFlush(z, r);
exit;
end;
BAD: begin
r := DATA_ERROR;
update(z, b, k, n, p, q);
result := inflateFlush(z, r);
exit;
end;
else
r := STREAM_ERROR;
update(z, b, k, n, p, q);
result := inflateFlush(z, r);
exit;
end;
until false;
end;
function InfBlocks.inflateFlush(z: ZStream; r: int): int;
var
n: int;
p: int;
q: int;
begin
p := z.nextOutIndex;
q := read;
if q <= write then begin
n := write - q;
end else begin
n := end_ - q;
end;
if n > z.availOut then begin
n := z.availOut;
end;
if (n <> 0) and (r = BUF_ERROR) then begin
r := OK;
end;
dec(z.availOut, n);
inc(z.totalOut, long(n));
if check then begin
z.adler.update(window, q, n);
end;
arraycopy(window, q, z.nextOut, p, n);
inc(p, n);
inc(q, n);
if q = end_ then begin
q := 0;
if write = end_ then begin
write := 0;
end;
n := write - q;
if n > z.availOut then begin
n := z.availOut;
end;
if (n <> 0) and (r = BUF_ERROR) then begin
r := OK;
end;
dec(z.availOut, n);
inc(z.totalOut, long(n));
if check then begin
z.adler.update(window, q, n);
end;
arraycopy(window, q, z.nextOut, p, n);
inc(p, n);
inc(q, n);
end;
z.nextOutIndex := p;
read := q;
result := r;
end;
function InfBlocks.syncPoint(): boolean;
begin
result := mode = LENS;
end;
{%endregion}
{%region ZStream }
constructor ZStream.create();
begin
inherited create();
adler := Adler32.create();
end;
destructor ZStream.destroy;
begin
adler := nil;
dstate.free();
istate.free();
inherited destroy;
end;
procedure ZStream.flushPending();
var
len: int;
begin
len := dstate.pending;
if len > availOut then begin
len := availOut;
end;
if len <> 0 then begin
arraycopy(dstate.pendingBuf, dstate.pendingOut, nextOut, nextOutIndex, len);
inc(nextOutIndex, len);
inc(dstate.pendingOut, len);
inc(totalOut, long(len));
dec(availOut, len);
dec(dstate.pending, len);
if dstate.pending = 0 then begin
dstate.pendingOut := 0;
end;
end;
end;
function ZStream.readBuf(const dst: byte_Array1d; offset, count: int): int;
begin
result := availIn;
if result > count then begin
result := count;
end;
if result = 0 then begin
exit;
end;
dec(availIn, result);
if dstate.wrap <> 0 then begin
adler.update(nextIn, nextInIndex, result);
end;
arraycopy(nextIn, nextInIndex, dst, offset, result);
inc(nextInIndex, result);
inc(totalIn, long(result));
end;
procedure ZStream.setAvailIn(availIn: int);
begin
self.availIn := availIn;
end;
procedure ZStream.setAvailOut(availOut: int);
begin
self.availOut := availOut;
end;
procedure ZStream.setNextIn(const nextIn: byte_Array1d);
begin
self.nextIn := nextIn;
end;
procedure ZStream.setNextInIndex(nextInIndex: int);
begin
self.nextInIndex := nextInIndex;
end;
procedure ZStream.setNextOut(const nextOut: byte_Array1d);
begin
self.nextOut := nextOut;
end;
procedure ZStream.setNextOutIndex(nextOutIndex: int);
begin
self.nextOutIndex := nextOutIndex;
end;
procedure ZStream.setInput(const data: byte_Array1d);
begin
setInput(data, 0, length(data), false);
end;
procedure ZStream.setInput(const data: byte_Array1d; append: boolean);
begin
setInput(data, 0, length(data), append);
end;
procedure ZStream.setInput(const data: byte_Array1d; offset, length: int; append: boolean);
var
lim: int;
len: int;
tmp: byte_Array1d;
begin
lim := offset + length;
len := System.length(data);
if (lim > len) or (lim < offset) or (offset < 0) or (offset > len) then begin
raise ArrayIndexOutOfBoundsException.create('ZStream.setInput: индекс элемента массива выходит из диапазона.');
end;
if (length > 0) or (not append) or (nextIn = nil) then begin
if (availIn > 0) and append then begin
tmp := byte_Array1d_create(availIn + length);
arraycopy(nextIn, nextInIndex, tmp, 0, availIn);
arraycopy(data, offset, tmp, availIn, length);
nextIn := tmp;
nextInIndex := 0;
inc(availIn, length);
end else begin
nextIn := data;
nextInIndex := offset;
availIn := length;
end;
end;
end;
procedure ZStream.setOutput(const data: byte_Array1d);
begin
setOutput(data, 0, length(data));
end;
procedure ZStream.setOutput(const data: byte_Array1d; offset, length: int);
var
lim: int;
len: int;
begin
lim := offset + length;
len := System.length(data);
if (lim > len) or (lim < offset) or (offset < 0) or (offset > len) then begin
raise ArrayIndexOutOfBoundsException.create('ZStream.setOutput: индекс элемента массива выходит из диапазона.');
end;
nextOut := data;
nextOutIndex := offset;
availOut := length;
end;
function ZStream.getChecksum(): int;
begin
result := adler.getValue();
end;
function ZStream.getAvailIn(): int;
begin
result := availIn;
end;
function ZStream.getAvailOut(): int;
begin
result := availOut;
end;
function ZStream.getNextInIndex(): int;
begin
result := nextInIndex;
end;
function ZStream.getNextOutIndex(): int;
begin
result := nextOutIndex;
end;
function ZStream.getTotalIn(): long;
begin
result := totalIn;
end;
function ZStream.getTotalOut(): long;
begin
result := totalOut;
end;
function ZStream.getNextIn(): byte_Array1d;
begin
result := nextIn;
end;
function ZStream.getNextOut(): byte_Array1d;
begin
result := nextOut;
end;
function ZStream.getMessage(): AnsiString;
begin
result := msg;
end;
function ZStream.deflateInit(level: int): int;
begin
result := deflateInit(level, MAX_WBITS, false);
end;
function ZStream.deflateInit(level: int; nowrap: boolean): int;
begin
result := deflateInit(level, MAX_WBITS, nowrap);
end;
function ZStream.deflateInit(level, bits: int): int;
begin
result := deflateInit(level, bits, false);
end;
function ZStream.deflateInit(level, bits, memlevel: int): int;
begin
dstate.free();
dstate := Zlib.Deflate.create(self);
result := dstate.deflateInit(level, bits, memlevel);
end;
function ZStream.deflateInit(level, bits: int; nowrap: boolean): int;
begin
dstate.free();
dstate := Zlib.Deflate.create(self);
if nowrap then begin
result := dstate.deflateInit(level, -bits);
end else begin
result := dstate.deflateInit(level, bits);
end;
end;
function ZStream.deflateSetDictionary(const dictionary: byte_Array1d; dictLength: int): int;
begin
if dstate = nil then begin
result := STREAM_ERROR;
end else begin
result := dstate.deflateSetDictionary(dictionary, dictLength);
end;
end;
function ZStream.deflateParams(level, strategy: int): int;
begin
if dstate = nil then begin
result := STREAM_ERROR;
end else begin
result := dstate.deflateParams(level, strategy);
end;
end;
function ZStream.deflate(flush: int): int;
begin
if dstate = nil then begin
result := STREAM_ERROR;
end else begin
result := dstate.deflate(flush);
end;
end;
function ZStream.deflateEnd(): int;
begin
if dstate = nil then begin
result := STREAM_ERROR;
exit;
end;
result := dstate.deflateEnd();
dstate.free();
dstate := nil;
end;
function ZStream.inflateInit(): int;
begin
result := inflateInit(DEF_WBITS, false);
end;
function ZStream.inflateInit(w: int): int;
begin
result := inflateInit(w, false);
end;
function ZStream.inflateInit(nowrap: boolean): int;
begin
result := inflateInit(DEF_WBITS, nowrap);
end;
function ZStream.inflateInit(w: int; nowrap: boolean): int;
begin
istate.free();
istate := Zlib.Inflate.create(self);
if nowrap then begin
result := istate.inflateInit(-w);
end else begin
result := istate.inflateInit(w);
end;
end;
function ZStream.inflateSetDictionary(const dictionary: byte_Array1d; dictLength: int): int;
begin
if istate = nil then begin
result := STREAM_ERROR;
end else begin
result := istate.inflateSetDictionary(dictionary, dictLength);
end;
end;
function ZStream.inflateSync(): int;
begin
if istate = nil then begin
result := STREAM_ERROR;
end else begin
result := istate.inflateSync();
end;
end;
function ZStream.inflateSyncPoint(): int;
begin
if istate = nil then begin
result := STREAM_ERROR;
end else begin
result := istate.inflateSyncPoint();
end;
end;
function ZStream.inflate(flush: int): int;
begin
if istate = nil then begin
result := STREAM_ERROR;
end else begin
result := istate.inflate(flush);
end;
end;
function ZStream.inflateEnd(): int;
begin
if istate = nil then begin
result := STREAM_ERROR;
end else begin
result := istate.inflateEnd();
end;
end;
function ZStream.inflateFinished(): boolean;
begin
result := (istate <> nil) and (istate.mode = 12);
end;
{%endregion}
initialization {%region}
Crc32.clinit();
StaticTree.clinit();
Deflate.clinit();
Inflate.clinit();
InfTree.clinit();
InfCodes.clinit();
InfBlocks.clinit();
{%endregion}
finalization {%region}
InfBlocks.cldone();
InfCodes.cldone();
InfTree.cldone();
Inflate.cldone();
Deflate.cldone();
StaticTree.cldone();
Crc32.cldone();
{%endregion}
end.