unit ULZOutWindow;

{$IFDEF FPC}
{$MODE Delphi}
{$ENDIF}

interface

uses KOL;

type PLZOutWindow = ^TLZOutWindow;
     TLZOutWindow=object(TObj)
       public
         buffer: array of byte;
         pos:integer;
         windowSize:integer;
         streamPos:integer;
         stream:PStream;
         procedure _Create(const AwindowSize:integer);
         procedure SetStream(const Astream:PStream);
         procedure ReleaseStream;
         procedure _Init(const Asolid:boolean);
         procedure Flush;
         procedure CopyBlock(const Adistance:integer; Alen:integer);
         procedure PutByte(const Ab:byte);
         function GetByte(const Adistance:integer):byte;
       end;

implementation

procedure TLZOutWindow._Create(const AwindowSize:integer);
begin
if (length(buffer)=0) or (self.windowSize <> AwindowSize) then
   setlength(buffer,AwindowSize);
self.windowSize := AwindowSize;
pos := 0;
streamPos := 0;
end;

procedure TLZOutWindow.SetStream(const Astream:PStream);
begin
ReleaseStream;
self.stream:=Astream;
end;

procedure TLZOutWindow.ReleaseStream;
begin
flush;
self.stream:=nil;
end;

procedure TLZOutWindow._Init(const Asolid:boolean);
begin
if not Asolid then begin
   streamPos:=0;
   Pos:=0;
   end;
end;

procedure TLZOutWindow.Flush;
var size:integer;
begin
size := pos - streamPos;
if (size = 0) then
   exit;
stream.write(buffer[streamPos], size);
if (pos >= windowSize) then
   pos := 0;
streamPos := pos;
end;

procedure TLZOutWindow.CopyBlock(const Adistance:integer;Alen:integer);
var _pos:integer;
begin
_pos := self.pos - Adistance - 1;
if _pos < 0 then
   _pos := _pos + windowSize;
while Alen<>0 do begin
      if _pos >= windowSize then
         _pos := 0;
      buffer[self.pos] := buffer[_pos];
      inc(self.pos);
      inc(_pos);
      if self.pos >= windowSize then
         Flush();
    dec(Alen);
    end;
end;

procedure TLZOutWindow.PutByte(const Ab:byte);
begin
buffer[pos] := Ab;
inc(pos);
if (pos >= windowSize) then
   Flush();
end;

function TLZOutWindow.GetByte(const Adistance:integer):byte;
var _pos:integer;
begin
_pos := self.pos - Adistance - 1;
if (_pos < 0) then
   _pos := _pos + windowSize;
result:=buffer[_pos];
end;

end.
