unit ULZInWindow; {$IFDEF FPC} {$MODE Delphi} {$ENDIF} interface uses KOL; type TLZInWindow= object(TObj) public bufferBase: array of byte;// pointer to buffer with data stream:PStream; posLimit:integer; // offset (from _buffer) of first byte when new block reading must be done streamEndWasReached:boolean; // if (true) then _streamPos shows real end of stream pointerToLastSafePosition:integer; bufferOffset:integer; blockSize:integer; // Size of Allocated memory block pos:integer; // offset (from _buffer) of curent byte keepSizeBefore:integer; // how many BYTEs must be kept in buffer before _pos keepSizeAfter:integer; // how many BYTEs must be kept buffer after _pos streamPos:integer; // offset (from _buffer) of first not read byte from Stream procedure MoveBlock; procedure ReadBlock; procedure _Free; procedure _Create(const AkeepSizeBefore, AkeepSizeAfter, AkeepSizeReserv:integer); procedure SetStream(const Astream:PStream); procedure ReleaseStream; procedure _Init;virtual; procedure MovePos;virtual; function GetIndexByte(const Aindex:integer):byte; // index + limit have not to exceed _keepSizeAfter; function GetMatchLen(const Aindex:integer;Adistance,Alimit:integer):integer; function GetNumAvailableBytes:integer; procedure ReduceOffsets(const AsubValue:integer); end; implementation procedure TLZInWindow.MoveBlock; var offset,numbytes,i:integer; begin offset := bufferOffset + pos - keepSizeBefore; // we need one additional byte, since MovePos moves on 1 byte. if (offset > 0) then dec(offset); numBytes := bufferOffset + streamPos - offset; // check negative offset ???? for i := 0 to numBytes -1 do bufferBase[i] := bufferBase[offset + i]; bufferOffset := bufferOffset - offset; end; procedure TLZInWindow.ReadBlock; var size,numreadbytes,pointerToPostion:integer; begin if streamEndWasReached then exit; while (true) do begin size := (0 - bufferOffset) + blockSize - streamPos; if size = 0 then exit; numReadBytes := stream.Read(bufferBase[bufferOffset + streamPos], size); if (numReadBytes = 0) then begin posLimit := streamPos; pointerToPostion := bufferOffset + posLimit; if (pointerToPostion > pointerToLastSafePosition) then posLimit := pointerToLastSafePosition - bufferOffset; streamEndWasReached := true; exit; end; streamPos := streamPos + numReadBytes; if (streamPos >= pos + keepSizeAfter) then posLimit := streamPos - keepSizeAfter; end; end; procedure TLZInWindow._Free; begin setlength(bufferBase,0); end; procedure TLZInWindow._Create(const AkeepSizeBefore, AkeepSizeAfter, AkeepSizeReserv:integer); var _blocksize:integer; begin self.keepSizeBefore := AkeepSizeBefore; self.keepSizeAfter := AkeepSizeAfter; _blocksize := AkeepSizeBefore + AkeepSizeAfter + AkeepSizeReserv; if (length(bufferBase) = 0) or (self.blockSize <> _blocksize) then begin _Free; self.blockSize := _blocksize; setlength(bufferBase,self.blockSize); end; pointerToLastSafePosition := self.blockSize - AkeepSizeAfter; end; procedure TLZInWindow.SetStream(const Astream:PStream); begin self.stream:=Astream; end; procedure TLZInWindow.ReleaseStream; begin stream:=nil; end; procedure TLZInWindow._Init; begin bufferOffset := 0; pos := 0; streamPos := 0; streamEndWasReached := false; ReadBlock; end; procedure TLZInWindow.MovePos; var pointerToPostion:integer; begin inc(pos); if pos > posLimit then begin pointerToPostion := bufferOffset + pos; if pointerToPostion > pointerToLastSafePosition then MoveBlock; ReadBlock; end; end; function TLZInWindow.GetIndexByte(const Aindex:integer):byte; begin result:=bufferBase[bufferOffset + pos + Aindex]; end; function TLZInWindow.GetMatchLen(const Aindex:integer;Adistance,Alimit:integer):integer; var pby,i:integer; begin if streamEndWasReached then if (pos + Aindex) + Alimit > streamPos then Alimit := streamPos - (pos + Aindex); inc(Adistance); // Byte *pby = _buffer + (size_t)_pos + Aindex; pby := bufferOffset + pos + Aindex; i:=0; while (i