123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- {
- This file is part of the Free Component Library.
- Copyright (c) 1999-2000 by the Free Pascal development team
- Implement a buffered stream.
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- {$mode objfpc}
- {$H+}
- unit bufstream;
- interface
- uses
- Classes, SysUtils;
- Const
- DefaultBufferCapacity : Integer = 16; // Default buffer capacity in Kb.
- Type
- { TBufStream }
- TBufStream = Class(TOwnerStream)
- Private
- FTotalPos : Int64;
- Fbuffer: Pointer;
- FBufPos: Integer;
- FBufSize: Integer;
- FCapacity: Integer;
- procedure SetCapacity(const AValue: Integer);
- Protected
- procedure BufferError(Msg : String);
- Procedure FillBuffer; Virtual;
- Procedure FlushBuffer; Virtual;
- Public
- Constructor Create(ASource : TStream; ACapacity: Integer);
- Constructor Create(ASource : TStream);
- Destructor Destroy; override;
- Property Buffer : Pointer Read Fbuffer;
- Property Capacity : Integer Read FCapacity Write SetCapacity;
- Property BufferPos : Integer Read FBufPos; // 0 based.
- Property BufferSize : Integer Read FBufSize; // Number of bytes in buffer.
- end;
- { TReadBufStream }
- TReadBufStream = Class(TBufStream)
- Public
- Function Seek(Offset: Longint; Origin: Word): Longint; override;
- Function Read(var ABuffer; ACount : LongInt) : Integer; override;
- Function Write(Const ABuffer; ACount : LongInt) : Integer; override;
- end;
- { TWriteBufStream }
- TWriteBufStream = Class(TBufStream)
- Public
- Destructor Destroy; override;
- Function Seek(Offset: Longint; Origin: Word): Longint; override;
- Function Read(var ABuffer; ACount : LongInt) : Integer; override;
- Function Write(Const ABuffer; ACount : LongInt) : Integer; override;
- end;
- implementation
- Resourcestring
- SErrCapacityTooSmall = 'Capacity is less than actual buffer size.';
- SErrCouldNotFLushBuffer = 'Could not flush buffer';
- SErrWriteOnlyStream = 'Illegal stream operation: Only writing is allowed.';
- SErrReadOnlyStream = 'Illegal stream operation: Only reading is allowed.';
- SErrInvalidSeek = 'Invalid buffer seek operation';
- { TBufStream }
- procedure TBufStream.SetCapacity(const AValue: Integer);
- begin
- if (FCapacity<>AValue) then
- begin
- If (AValue<FBufSize) then
- BufferError(SErrCapacityTooSmall);
- ReallocMem(FBuffer,AValue);
- FCapacity:=AValue;
- end;
- end;
- procedure TBufStream.BufferError(Msg: String);
- begin
- Raise EStreamError.Create(Msg);
- end;
- procedure TBufStream.FillBuffer;
- Var
- RCount : Integer;
- P : PChar;
- begin
- P:=Pchar(FBuffer);
- // Reset at beginning if empty.
- If (FBufSize-FBufPos)<=0 then
- begin
- FBufSize:=0;
- FBufPos:=0;
- end;
- Inc(P,FBufSize);
- RCount:=1;
- while (RCount<>0) and (FBufSize<FCapacity) do
- begin
- RCount:=FSource.Read(P^,FCapacity-FBufSize);
- Inc(P,RCount);
- Inc(FBufSize,RCount);
- end;
- end;
- procedure TBufStream.FlushBuffer;
- Var
- WCount : Integer;
- P : PChar;
- begin
- P:=Pchar(FBuffer);
- Inc(P,FBufPos);
- WCount:=1;
- While (WCount<>0) and ((FBufSize-FBufPos)>0) do
- begin
- WCount:=FSource.Write(P^,FBufSize-FBufPos);
- Inc(P,WCount);
- Inc(FBufPos,WCount);
- end;
- If ((FBufSize-FBufPos)<=0) then
- begin
- FBufPos:=0;
- FBufSize:=0;
- end
- else
- BufferError(SErrCouldNotFLushBuffer);
- end;
- constructor TBufStream.Create(ASource: TStream; ACapacity: Integer);
- begin
- Inherited Create(ASource);
- SetCapacity(ACapacity);
- end;
- constructor TBufStream.Create(ASource: TStream);
- begin
- Create(ASource,DefaultBufferCapacity*1024);
- end;
- destructor TBufStream.Destroy;
- begin
- FBufSize:=0;
- SetCapacity(0);
- inherited Destroy;
- end;
- { TReadBufStream }
- function TReadBufStream.Seek(Offset: Longint; Origin: Word): Longint;
- var
- I: Integer;
- Buf: array [0..4095] of Char;
- begin
- // Emulate forward seek if possible.
- if ((Offset>=0) and (Origin = soFromCurrent)) or
- (((Offset-FTotalPos)>=0) and (Origin = soFromBeginning)) then
- begin
- if (Origin=soFromBeginning) then
- Dec(Offset,FTotalPos);
- if (Offset>0) then
- begin
- for I:=1 to (Offset div sizeof(Buf)) do
- ReadBuffer(Buf,sizeof(Buf));
- ReadBuffer(Buf, Offset mod sizeof(Buf));
- end;
- Result:=FTotalPos;
- end
- else
- BufferError(SErrInvalidSeek);
- end;
- function TReadBufStream.Read(var ABuffer; ACount: LongInt): Integer;
- Var
- P,PB : PChar;
- Avail,MSize,RCount : Integer;
- begin
- Result:=0;
- P:=PChar(@ABuffer);
- Avail:=1;
- While (Result<ACount) and (Avail>0) do
- begin
- If (FBufSize-FBufPos<=0) then
- FillBuffer;
- Avail:=FBufSize-FBufPos;
- If (Avail>0) then
- begin
- MSize:=ACount-Result;
- If (MSize>Avail) then
- MSize:=Avail;
- PB:=PChar(FBuffer);
- Inc(PB,FBufPos);
- Move(PB^,P^,MSIze);
- Inc(FBufPos,MSize);
- Inc(P,MSize);
- Inc(Result,MSize);
- end;
- end;
- Inc(FTotalPos,Result);
- end;
- function TReadBufStream.Write(const ABuffer; ACount: LongInt): Integer;
- begin
- BufferError(SErrReadOnlyStream);
- end;
- { TWriteBufStream }
- destructor TWriteBufStream.Destroy;
- begin
- FlushBuffer;
- inherited Destroy;
- end;
- function TWriteBufStream.Seek(Offset: Longint; Origin: Word): Longint;
- begin
- if (Offset=0) and (Origin=soFromCurrent) then
- Result := FTotalPos
- else
- BufferError(SErrInvalidSeek);
- end;
- function TWriteBufStream.Read(var ABuffer; ACount: LongInt): Integer;
- begin
- BufferError(SErrWriteOnlyStream);
- end;
- function TWriteBufStream.Write(const ABuffer; ACount: LongInt): Integer;
- Var
- P,PB : PChar;
- Avail,MSize,RCount : Integer;
- begin
- Result:=0;
- P:=PChar(@ABuffer);
- While (Result<ACount) do
- begin
- If (FBufSize=FCapacity) then
- FlushBuffer;
- Avail:=FCapacity-FBufSize;
- MSize:=ACount-Result;
- If (MSize>Avail) then
- MSize:=Avail;
- PB:=PChar(FBuffer);
- Inc(PB,FBufSize);
- Move(P^,PB^,MSIze);
- Inc(FBufSize,MSize);
- Inc(P,MSize);
- Inc(Result,MSize);
- end;
- Inc(FTotalPos,Result);
- end;
- end.
|