Files
kolmck/Addons/UBufferedFS.pas
dkolmck 8a71ebf5bc addons update
git-svn-id: https://svn.code.sf.net/p/kolmck/code@67 91bb2d04-0c0c-4d2d-88a5-bbb6f4c1fa07
2010-10-04 12:58:59 +00:00

175 lines
4.6 KiB
ObjectPascal

unit UBufferedFS;
{$IFDEF FPC}
{$MODE Delphi}
{$ENDIF}
interface
uses KOL;
type PBufferedFS = PStream;
{
const BufferSize=$10000;//64K
type TBFSMode=(BFMRead,BFMWrite);
TBufferedFS=class(TFileStream)
private
membuffer:array [0..BufferSize-1] of byte;
bytesinbuffer:integer;
bufferpos:integer;
bufferdirty:boolean;
Mode:TBFSMode;
procedure _Init;
procedure Flush;
procedure ReadBuffer;
public
constructor Create(const FileName: string; Mode: Word); overload;
constructor Create(const FileName: string; Mode: Word; Rights: Cardinal); overload;
destructor Destroy; override;
function Read(var Buffer; Count: Longint): Longint; override;
function Write(const Buffer; Count: Longint): Longint; override;
function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
end;
type TByteArray = array of byte;
PByteArray = ^TByteArray;
}
implementation
{
function MovePointer(const P:pointer;const dist:integer):pointer;
begin
result:=pointer(integer(p)+dist);
end;
procedure TBufferedFS.Init;
begin
bytesinbuffer:=0;
bufferpos:=0;
bufferdirty:=false;
mode:=BFMWrite;
end;
procedure TBufferedFS.Flush;
begin
if bufferdirty then
inherited Write(membuffer[0],bufferpos);
bufferdirty:=false;
bytesinbuffer:=0;
bufferpos:=0;
end;
constructor TBufferedFS.Create(const FileName: string; Mode: Word);
begin
inherited;
init;
end;
constructor TBufferedFS.Create(const FileName: string; Mode: Word; Rights: Cardinal);
begin
inherited;
init;
end;
destructor TBufferedFS.Destroy;
begin
flush;
inherited;
end;
procedure TBufferedFS.ReadBuffer;
begin
flush;
bytesinbuffer:=inherited Read(membuffer,buffersize);
bufferpos:=0;
end;
function TBufferedFS.Read(var Buffer; Count: Longint): Longint;
var p:PByteArray;
bytestoread:integer;
b:integer;
begin
if Mode=BFMWrite then flush;
mode:=BFMRead;
result:=0;
if count<=bytesinbuffer then begin
//all data already in buffer
move(membuffer[bufferpos],buffer,count);
bytesinbuffer:=bytesinbuffer-count;
bufferpos:=bufferpos+count;
result:=count;
end else begin
bytestoread:=count;
if (bytestoread<>0)and(bytesinbuffer<>0) then begin
//read data remaining in buffer and increment data pointer
b:=Read(buffer,bytesinbuffer);
p:=PByteArray(@(TByteArray(buffer)[b]));
bytestoread:=bytestoread-b;
result:=b;
end else p:=@buffer;
if bytestoread>=BufferSize then begin
//data to read is larger than the buffer, read it directly
result:=result+inherited Read(p^,bytestoread);
end else begin
//refill buffer
ReadBuffer;
//recurse
result:=result+Read(p^,math.Min(bytestoread,bytesinbuffer));
end;
end;
end;
function TBufferedFS.Write(const Buffer; Count: Longint): Longint;
var p:pointer;
bytestowrite:integer;
b:integer;
begin
if mode=BFMRead then begin
seek(-BufferSize+bufferpos,soFromCurrent);
bytesinbuffer:=0;
bufferpos:=0;
end;
mode:=BFMWrite;
result:=0;
if count<=BufferSize-bytesinbuffer then begin
//all data fits in buffer
bufferdirty:=true;
move(buffer,membuffer[bufferpos],count);
bytesinbuffer:=bytesinbuffer+count;
bufferpos:=bufferpos+count;
result:=count;
end else begin
bytestowrite:=count;
if (bytestowrite<>0)and(bytesinbuffer<>BufferSize)and(bytesinbuffer<>0) then begin
//write data to remaining space in buffer and increment data pointer
b:=Write(buffer,BufferSize-bytesinbuffer);
p:=MovePointer(@buffer,b);
bytestowrite:=bytestowrite-b;
result:=b;
end else p:=@buffer;
if bytestowrite>=BufferSize then begin
//empty buffer
Flush;
//data to write is larger than the buffer, write it directly
result:=result+inherited Write(p^,bytestowrite);
end else begin
//empty buffer
Flush;
//recurse
result:=result+Write(p^,bytestowrite);
end;
end;
end;
function TBufferedFS.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
begin
if (Origin=soCurrent)and(Offset=0) then result:=inherited seek(Offset,origin)+bufferpos
else begin
flush;
result:=inherited Seek(offset,origin);
end;
end;
}
end.