613 lines
12 KiB
Plaintext
613 lines
12 KiB
Plaintext
// HRBuffers v0.3.1 (03.Aug.2000)
|
|
// Simple buffer classes
|
|
// by Colin A Ridgewell
|
|
//
|
|
// Copyright (C) 1999,2000 Hayden-R Ltd
|
|
// http://www.haydenr.com
|
|
//
|
|
// This program is free software; you can redistribute it and/or modify it
|
|
// under the terms of the GNU General Public License as published by the
|
|
// Free Software Foundation; either version 2 of the License, or (at your
|
|
// option) any later version.
|
|
//
|
|
// 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. See the GNU General Public License for
|
|
// more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License along
|
|
// with this program (gnu_license.htm); if not, write to the
|
|
//
|
|
// Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
//
|
|
// To contact us via e-mail use the following addresses...
|
|
//
|
|
// bug@haydenr.u-net.com - to report a bug
|
|
// support@haydenr.u-net.com - for general support
|
|
// wishlist@haydenr.u-net.com - add new requirement to wish list
|
|
//
|
|
unit HRBuffers;
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils;
|
|
|
|
type
|
|
{Base buffer.}
|
|
THRBuffer=class(TObject)
|
|
private
|
|
FBuffer:PChar;
|
|
FSize:LongInt;
|
|
procedure SetSize(Value:LongInt);
|
|
procedure CreateBuffer(const Size:LongInt);
|
|
procedure ResizeBuffer(const Size:LongInt);
|
|
procedure FreeBuffer;
|
|
protected
|
|
function GetItems(Index:LongInt):Char; virtual;
|
|
procedure SetItems(Index:LongInt;Value:Char); virtual;
|
|
public
|
|
constructor Create; virtual;
|
|
destructor Destroy; override;
|
|
property Buffer:PChar read FBuffer;
|
|
property Size:Longint read FSize write SetSize;
|
|
property Items[Index:LongInt]:Char read GetItems write SetItems; default;
|
|
end;
|
|
|
|
{Base buffer with EOB.}
|
|
THRBufferEOB=class(THRBuffer)
|
|
private
|
|
protected
|
|
function GetEOB:Boolean; virtual;
|
|
public
|
|
property EOB:Boolean read GetEOB;
|
|
end;
|
|
|
|
|
|
{Buffer for holding a series of char.}
|
|
THRBufferChar=class(THRBufferEOB)
|
|
private
|
|
FEOB:Boolean;
|
|
FPosition:Longint;
|
|
protected
|
|
function GetEOB:Boolean; override;
|
|
function GetItems(Index:LongInt):Char; override;
|
|
procedure SetItems(Index:LongInt;Value:Char); override;
|
|
function GetAsPChar:PChar;
|
|
procedure SetAsPChar(Value:PChar);
|
|
function GetAsString:string;
|
|
procedure SetAsString(Value:string);
|
|
public
|
|
constructor Create; override;
|
|
destructor Destroy; override;
|
|
property Buffer;
|
|
property Position:Longint read FPosition write FPosition;
|
|
procedure Write(const Value:Char);
|
|
function Read:Char;
|
|
procedure WritePChar(const Str:PChar);
|
|
procedure WriteString(const Str:String);
|
|
property AsPChar:PChar read GetAsPChar write SetAsPChar;
|
|
property AsString:string read GetAsString write SetAsString;
|
|
end;
|
|
|
|
|
|
{Buffer for reading from a stream.}
|
|
THRBufferStream=class(THRBufferEOB)
|
|
private
|
|
FEOB:Boolean;
|
|
FStream:TStream;
|
|
FStreamSize:Longint;
|
|
FFirstPosInBuffer:LongInt;
|
|
protected
|
|
function GetEOB:Boolean; override;
|
|
function GetItems(Index:LongInt):Char; override;
|
|
procedure SetItems(Index:LongInt;Value:Char); override;
|
|
procedure SetStream(Value:TStream);
|
|
public
|
|
constructor Create; override;
|
|
destructor Destroy; override;
|
|
property Stream:TStream read FStream write SetStream;
|
|
end;
|
|
|
|
{A buffer containing a list of smaller buffers in one piece of contiguous memory.}
|
|
THRBufferList=class(THRBuffer)
|
|
private
|
|
function GetItemPos(const Index:Integer):Integer;
|
|
function GetCount:Integer;
|
|
function GetItemSize(Index:Integer):Integer;
|
|
procedure SetItemSize(Index:Integer;Value:Integer);
|
|
function GetItemBuffer(Index:Integer):PChar;
|
|
public
|
|
constructor Create; override;
|
|
destructor Destroy; override;
|
|
procedure Add(const Index,ItemSize:Integer);
|
|
procedure Delete(const Index:Integer);
|
|
property Count:Integer read GetCount;
|
|
property ItemSize[Index:Integer]:Integer read GetItemSize write SetItemSize;
|
|
property ItemBuffer[Index:Integer]:PChar read GetItemBuffer;
|
|
end;
|
|
|
|
|
|
implementation
|
|
|
|
|
|
{ T H R B u f f e r }
|
|
|
|
constructor THRBuffer.Create;
|
|
begin
|
|
FBuffer:=nil;
|
|
FSize:=0;
|
|
end;
|
|
|
|
destructor THRBuffer.Destroy;
|
|
begin
|
|
FreeBuffer;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
|
|
procedure THRBuffer.SetSize(Value:LongInt);
|
|
begin
|
|
if FBuffer=nil
|
|
then
|
|
CreateBuffer(Value)
|
|
else
|
|
if Value>0
|
|
then
|
|
ResizeBuffer(Value)
|
|
else
|
|
FreeBuffer;
|
|
end;
|
|
|
|
|
|
function THRBuffer.GetItems(Index:LongInt):Char;
|
|
begin
|
|
Result:=#0;
|
|
end;
|
|
|
|
|
|
procedure THRBuffer.SetItems(Index:LongInt;Value:Char);
|
|
begin
|
|
end;
|
|
|
|
|
|
procedure THRBuffer.CreateBuffer(const Size:LongInt);
|
|
begin
|
|
if FBuffer=nil
|
|
then
|
|
begin
|
|
FSize:=Size;
|
|
GetMem(FBuffer,FSize+1);
|
|
{Null terminate end of buffer.}
|
|
FBuffer[FSize]:=#0;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure THRBuffer.ResizeBuffer(const Size:LongInt);
|
|
var
|
|
New:PChar;
|
|
MoveSize:LongInt;
|
|
begin
|
|
if FBuffer<>nil
|
|
then
|
|
begin
|
|
GetMem(New,Size+1);
|
|
if FSize>Size then MoveSize:=Size else MoveSize:=FSize;
|
|
Move(FBuffer[0],New[0],MoveSize);
|
|
FreeMem(FBuffer,FSize+1);
|
|
FBuffer:=New;
|
|
FSize:=Size;
|
|
FBuffer[FSize]:=#0;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure THRBuffer.FreeBuffer;
|
|
begin
|
|
if FBuffer<>nil
|
|
then
|
|
begin
|
|
FreeMem(FBuffer,FSize+1);
|
|
FBuffer:=nil;
|
|
FSize:=0;
|
|
end;
|
|
end;
|
|
|
|
|
|
{ T H R B u f f e r E O B }
|
|
|
|
function THRBufferEOB.GetEOB:Boolean;
|
|
begin
|
|
Result:=True;
|
|
end;
|
|
|
|
|
|
{ T H R B u f f e r C h a r }
|
|
|
|
constructor THRBufferChar.Create;
|
|
begin
|
|
inherited Create;
|
|
FEOB:=False;
|
|
end;
|
|
|
|
|
|
destructor THRBufferChar.Destroy;
|
|
begin
|
|
inherited Destroy;
|
|
end;
|
|
|
|
|
|
function THRBufferChar.GetEOB:Boolean;
|
|
begin
|
|
Result:=FEOB;
|
|
end;
|
|
|
|
|
|
function THRBufferChar.GetItems(Index:LongInt):Char;
|
|
begin
|
|
if Index<FSize
|
|
then
|
|
begin
|
|
Result:=FBuffer[Index];
|
|
FEOB:=False;
|
|
end
|
|
else
|
|
begin
|
|
Result:=#0;
|
|
FEOB:=True;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure THRBufferChar.SetItems(Index:LongInt;Value:Char);
|
|
begin
|
|
if Index<FSize
|
|
then
|
|
begin
|
|
FBuffer[Index]:=Value;
|
|
FEOB:=False;
|
|
end
|
|
else
|
|
begin
|
|
FEOB:=True;
|
|
end;
|
|
end;
|
|
|
|
|
|
function THRBufferChar.Read:Char;
|
|
begin
|
|
if FPosition<FSize
|
|
then
|
|
begin
|
|
Result:=FBuffer[FPosition];
|
|
Inc(FPosition);
|
|
FEOB:=False;
|
|
end
|
|
else
|
|
begin
|
|
Result:=#0;
|
|
FEOB:=True;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure THRBufferChar.Write(const Value:Char);
|
|
begin
|
|
if FPosition<FSize
|
|
then
|
|
begin
|
|
FBuffer[FPosition]:=Value;
|
|
Inc(FPosition);
|
|
FEOB:=False;
|
|
end
|
|
else
|
|
begin
|
|
FEOB:=True;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure THRBufferChar.WritePChar(const Str:PChar);
|
|
var
|
|
i:Integer;
|
|
begin
|
|
for i:=0 to StrLen(Str)-1 do Write(Str[i]);
|
|
end;
|
|
|
|
|
|
procedure THRBufferChar.WriteString(const Str:String);
|
|
var
|
|
i:Integer;
|
|
begin
|
|
for i:=1 to Length(Str) do Write(Str[i]);
|
|
end;
|
|
|
|
|
|
function THRBufferChar.GetAsPChar:PChar;
|
|
begin
|
|
Result:=FBuffer;
|
|
end;
|
|
|
|
|
|
procedure THRBufferChar.SetAsPChar(Value:PChar);
|
|
var
|
|
L:Integer;
|
|
begin
|
|
L:=StrLen(Value);
|
|
if L<=FSize
|
|
then
|
|
begin
|
|
{Copies from value buffer to FBuffer.}
|
|
StrMove(FBuffer,Value,L);
|
|
FEOB:=False;
|
|
end
|
|
else
|
|
begin
|
|
FEOB:=True;
|
|
end;
|
|
end;
|
|
|
|
|
|
function THRBufferChar.GetAsString:string;
|
|
begin
|
|
Result:='';
|
|
end;
|
|
|
|
|
|
procedure THRBufferChar.SetAsString(Value:string);
|
|
begin
|
|
end;
|
|
|
|
|
|
|
|
|
|
{ T H R B u f f e r S t r e a m }
|
|
|
|
|
|
constructor THRBufferStream.Create;
|
|
begin
|
|
inherited Create;
|
|
FStream:=nil;
|
|
FFirstPosInBuffer:=-1;
|
|
end;
|
|
|
|
|
|
destructor THRBufferStream.Destroy;
|
|
begin
|
|
inherited Destroy;
|
|
end;
|
|
|
|
|
|
procedure THRBufferStream.SetStream(Value:TStream);
|
|
begin
|
|
if Value<>FStream
|
|
then
|
|
begin
|
|
FStream:=Value;
|
|
FStreamSize:=FStream.Size;
|
|
FFirstPosInBuffer:=-1;
|
|
end;
|
|
end;
|
|
|
|
|
|
function THRBufferStream.GetEOB:Boolean;
|
|
begin
|
|
Result:=FEOB;
|
|
end;
|
|
|
|
|
|
function THRBufferStream.GetItems(Index:LongInt):Char;
|
|
begin
|
|
if Index<FStreamSize
|
|
then
|
|
begin
|
|
if (Index>=FFirstPosInBuffer+FSize) or
|
|
(Index<FFirstPosInBuffer) or
|
|
(FFirstPosInBuffer=-1)
|
|
then
|
|
begin
|
|
{Read next block from stream into buffer.}
|
|
FStream.Position:=Index;
|
|
FStream.Read(FBuffer[0],FSize);
|
|
FFirstPosInBuffer:=Index;
|
|
end;
|
|
{Read from buffer}
|
|
Result:=FBuffer[Index-FFirstPosInBuffer];
|
|
FEOB:=False;
|
|
end
|
|
else
|
|
begin
|
|
{EOB}
|
|
Result:=#0;
|
|
FEOB:=True;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure THRBufferStream.SetItems(Index:LongInt;Value:Char);
|
|
begin
|
|
end;
|
|
|
|
|
|
{ T H R B u f f e r L i s t }
|
|
|
|
type
|
|
PHRInteger=^Integer;
|
|
|
|
|
|
constructor THRBufferList.Create;
|
|
begin
|
|
inherited Create;
|
|
{Set count to zero.}
|
|
Size:=SizeOf(Integer);
|
|
PHRInteger(Buffer)^:=0;
|
|
end;
|
|
|
|
|
|
destructor THRBufferList.Destroy;
|
|
begin
|
|
inherited Destroy;
|
|
end;
|
|
|
|
|
|
function THRBufferList.GetItemPos(const Index:Integer):Integer;
|
|
var
|
|
PosIndex:Integer;
|
|
Pos:Integer;
|
|
PosItemSize:Integer;
|
|
begin
|
|
{Check for out of bounds index.}
|
|
Assert(Index<PHRInteger(Buffer)^,'Index out of bounds');
|
|
{Step past count.}
|
|
Pos:=SizeOf(Integer);
|
|
{Loop thought items.}
|
|
PosIndex:=0;
|
|
while PosIndex<Index do
|
|
begin
|
|
{Get item size.}
|
|
PosItemSize:=PHRInteger(Buffer+Pos)^;
|
|
{Step over item.}
|
|
Pos:=Pos+SizeOf(Integer)+PosItemSize;
|
|
Inc(PosIndex);
|
|
end;
|
|
Result:=Pos;
|
|
end;
|
|
|
|
|
|
function THRBufferList.GetCount:Integer;
|
|
begin
|
|
Result:=PHRInteger(Buffer)^;
|
|
end;
|
|
|
|
|
|
function THRBufferList.GetItemSize(Index:Integer):Integer;
|
|
begin
|
|
Result:=PHRInteger(Buffer+GetItemPos(Index))^;
|
|
end;
|
|
|
|
|
|
procedure THRBufferList.SetItemSize(Index:Integer;Value:Integer);
|
|
var
|
|
Pos:Integer;
|
|
ItemSize:Integer;
|
|
Diff:Integer;
|
|
OldSize:Integer;
|
|
S,D:PChar;
|
|
C:Integer;
|
|
begin
|
|
Pos:=GetItemPos(Index);
|
|
|
|
{Calc diff is size.}
|
|
ItemSize:=PHRInteger(Buffer+Pos)^;
|
|
Diff:=Value-ItemSize;
|
|
|
|
{No change in size.}
|
|
if Diff=0 then Exit;
|
|
|
|
if Diff<0
|
|
then
|
|
begin
|
|
{Shrink buffer}
|
|
{Move items > index down buffer.}
|
|
S:=Buffer+Pos+SizeOf(Integer)+ItemSize;
|
|
D:=S+Diff;
|
|
C:=Size-(Pos+SizeOf(Integer)+ItemSize);
|
|
Move(S[0],D[0],C);
|
|
{Dec buffer size}
|
|
Size:=Size+Diff;
|
|
end
|
|
else
|
|
begin
|
|
{Grow buffer}
|
|
OldSize:=Size;
|
|
{Inc buffer size}
|
|
Size:=Size+Diff;
|
|
{Move items > index up buffer.}
|
|
S:=Buffer+Pos+SizeOf(Integer)+ItemSize;
|
|
D:=S+Diff;
|
|
C:=OldSize-(Pos+SizeOf(Integer)+ItemSize);
|
|
Move(S[0],D[0],C);
|
|
end;
|
|
|
|
{Set items new size.}
|
|
PHRInteger(Buffer+Pos)^:=Value;
|
|
end;
|
|
|
|
|
|
function THRBufferList.GetItemBuffer(Index:Integer):PChar;
|
|
begin
|
|
Result:=Buffer+GetItemPos(Index)+SizeOf(Integer);
|
|
end;
|
|
|
|
|
|
procedure THRBufferList.Add(const Index,ItemSize:Integer);
|
|
var
|
|
PosIndex:Integer;
|
|
Pos:Integer;
|
|
PosItemSize:Integer;
|
|
OldSize:Integer;
|
|
S,D:PChar;
|
|
C:Integer;
|
|
begin
|
|
{Step past count.}
|
|
Pos:=SizeOf(Integer);
|
|
|
|
{Step thought list until up to index or end list.}
|
|
PosIndex:=0;
|
|
while (PosIndex<Index)and(PosIndex<=PHRInteger(Buffer)^-1) do
|
|
begin
|
|
{Get item size.}
|
|
PosItemSize:=PHRInteger(Buffer+Pos)^;
|
|
{Step over item.}
|
|
Pos:=Pos+SizeOf(Integer)+PosItemSize;
|
|
Inc(PosIndex);
|
|
end;
|
|
|
|
{Pad list with empty items up to index.}
|
|
while (PosIndex<Index) do
|
|
begin
|
|
{Add item.}
|
|
Size:=Size+SizeOf(Integer);
|
|
{Set size of item to zero.}
|
|
PHRInteger(Buffer+Pos)^:=0;
|
|
{Inc count}
|
|
Inc(PHRInteger(Buffer)^);
|
|
{Step over item.}
|
|
Pos:=Pos+SizeOf(Integer);
|
|
Inc(PosIndex);
|
|
end;
|
|
|
|
{Resize buffer to accomodate new item.}
|
|
OldSize:=Size;
|
|
Size:=Size+SizeOf(Integer)+ItemSize;
|
|
|
|
{Push any items > index up buffer.}
|
|
if PosIndex<=PHRInteger(Buffer)^-1
|
|
then
|
|
begin
|
|
S:=Buffer+Pos;
|
|
D:=Buffer+Pos+SizeOf(Integer)+ItemSize;
|
|
C:=OldSize-Pos;
|
|
Move(S[0],D[0],C);
|
|
end;
|
|
|
|
{Set size of item.}
|
|
PHRInteger(Buffer+Pos)^:=ItemSize;
|
|
{Inc count.}
|
|
Inc(PHRInteger(Buffer)^);
|
|
end;
|
|
|
|
|
|
procedure THRBufferList.Delete(const Index:Integer);
|
|
begin
|
|
// find index
|
|
// get size
|
|
// move everthing > index down by sizeof(Integer) + index[size]
|
|
// dec buffer size by sizeof(Integer) + index[size]
|
|
// dec count
|
|
end;
|
|
|
|
|
|
end.
|