mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-16 00:42:06 +02:00
+ Initial check-in
This commit is contained in:
parent
9191989228
commit
8a74ecbcad
305
fcl/inc/bufstream.pp
Normal file
305
fcl/inc/bufstream.pp
Normal file
@ -0,0 +1,305 @@
|
||||
{
|
||||
$Id$
|
||||
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
|
||||
|
||||
{ TOwnerStream }
|
||||
TOwnerStream = Class(TStream)
|
||||
Protected
|
||||
FOwner : Boolean;
|
||||
FSource : TStream;
|
||||
Public
|
||||
Constructor Create(ASource : TStream);
|
||||
Destructor Destroy; override;
|
||||
Property Source : TStream Read FSource;
|
||||
Property SourceOwner : Boolean Read Fowner Write FOwner;
|
||||
end;
|
||||
|
||||
{ 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;
|
||||
|
||||
{ TOwnerStream }
|
||||
|
||||
constructor TOwnerStream.Create(ASource: TStream);
|
||||
begin
|
||||
FSource:=ASource;
|
||||
end;
|
||||
|
||||
destructor TOwnerStream.Destroy;
|
||||
begin
|
||||
If FOwner then
|
||||
FreeAndNil(FSource);
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
Loading…
Reference in New Issue
Block a user