{****************************************************************************
This is a source file of FreeVision
Copyright (c) 1992,96 by FP Klaempfl
Copyright (c) 1995 by MH Spiegel
****************************************************************************}
{$E-}
{$define NOEXCEPTIONS}
{$define SSTRING}
unit objects;
interface
const
maxcollectionsize = 16*1024*1024; { maybe for the next five years ;-) }
coindexerror = -1;
cooverflow = -2;
{$ifdef VER060}
vmtheadersize = 12;
{$endif}
type
tcharset = set of char;
pcharset = ^tcharset;
tbytearray = array[0..16*1024*1024-1] of byte;
pbytearray = ^tbytearray;
twordarray = array[0..16*1024*1024-1] of word;
pwordarray = ^twordarray;
wordrec = record
lo,hi : byte;
end;
longrec = record
lo,hi : word;
end;
{ this is a problem }
ptrrec = record
ofs,seg : word;
end;
pstring = ^string;
plongint = ^longint;
pword = ^word;
pbyte = ^byte;
fnamestr = string; { for linux, OS/2 ... }
ppoint = ^tpoint;
tpoint = record
x,y : longint;
end;
prect = ^trect;
trect = object
a,b : tpoint;
procedure assign(xa,ya,xb,yb : longint);
procedure copy(r : trect);
procedure move(adx,ady : longint);
procedure grow(adx,ady : longint);
procedure intersect(r : trect);
procedure union(r : trect);
procedure checkempty;
function contains(p : tpoint) : boolean;
function equals(r : trect) : boolean;
function empty : boolean;
end;
pobject = ^tobject;
tobject = object
constructor init;
destructor done;virtual;
procedure free;virtual;
end;
pstreamrec = ^tstreamrec;
tstreamrec = record
{ we never need really this, but ...}
objtype : longint;
vmtlink : pointer;
load : pointer;
store : pointer;
next : pointer;
end;
pstream = ^tstream;
tstream = object(tobject)
errorinfo : longint;
status : longint;
procedure copyfrom(var s : tstream;count : longint);
procedure error(code,info : longint);virtual;
procedure flush;virtual;
function get : pobject;
function getpos : longint;virtual;
function getsize : longint;virtual;
procedure put(p : pobject);
procedure read(var buf;count : longint);virtual;
function readstr : pstring;
procedure reset;
procedure seek(pos : longint);virtual;
procedure truncate;virtual;
procedure write(var buf;count : longint);virtual;
procedure writestr(p : pstring);
end;
pdosstream = ^tdosstream;
tdosstream = object(tstream)
handle : file;
constructor init(const filename : fnamestr;mode : word);
destructor done;virtual;
function getpos : longint;virtual;
function getsize : longint;virtual;
procedure read(var buf;count : longint);virtual;
procedure seek(pos : longint);virtual;
procedure truncate;virtual;
procedure write(var buf;count : longint);virtual;
end;
titemlist = array[0..maxcollectionsize-1] of pointer;
pitemlist = ^titemlist;
pcollection = ^tcollection;
tcollection = object(tobject)
{ don't modify this !!! }
count : longint;
limit : longint;
delta : longint;
items : pitemlist;
constructor init(alimit,adelta : longint);
constructor load(var s : tstream);
destructor done;virtual;
function at(index : longint) : pointer;
procedure atdelete(index : longint);
procedure atfree(index : longint);
procedure atinsert(index : longint;item : pointer);
procedure atput(index : longint;item : pointer);
procedure delete(item : pointer);
procedure deleteall;
procedure error(code,info : longint);virtual;
function firstthat(test : pointer) : pointer;
procedure foreach(action : pointer);
procedure free(item : pointer);
procedure freeall;
procedure freeitem(item : pointer);virtual;
function getitem(var s : tstream) : pointer;virtual;
function indexof(item : pointer) : longint;virtual;
procedure insert(item : pointer);virtual;
function lastthat(test : pointer) : pointer;
procedure pack;
procedure putitem(var s : tstream;item : pointer);virtual;
procedure setlimit(alimit : longint);virtual;
procedure store(var s : tstream);
end;
psortedcollection = ^tsortedcollection;
tsortedcollection = object(tcollection)
duplicates : boolean;
constructor load(var s : tstream);
function compare(key1,key2 : pointer) : integer;virtual;
function indexof(item : pointer) : longint;virtual;
procedure insert(item : pointer);virtual;
function keyof(item : pointer) : pointer;virtual;
function search(key : pointer;var index : longint) : boolean;virtual;
procedure store(var s : tstream);
end;
pstringcollection = ^tstringcollection;
tstringcollection = object(tsortedcollection)
function compare(key1,key2 : pointer) : integer;virtual;
procedure freeitem(item : pointer);virtual;
function getitem(var s : tstream) : pointer;virtual;
procedure putitem(var s : tstream;item : pointer);virtual;
end;
presourcecollection = ^tresourcecollection;
tresourcecollection = object(tstringcollection)
procedure freeitem(item : pointer);virtual;
function getitem(var s : tstream) : pointer;virtual;
function keyof(item : pointer) : pointer;virtual;
procedure putitem(var s : tstream;item : pointer);virtual;
end;
procedure registertype(var s : tstreamrec);
procedure registerobjects;
function newstr(const s : string) : pstring;
procedure disposestr(p : pstring);
function longmul(x,y : longint) : longint;
function longdiv(x,y : longint) : longint;
procedure abstract;
const
{ stream consts }
stcreate = $3c00;
stopenread = $3d00;
stopenwrite = $3d01;
stopen = $3d02;
stok = 0;
sterror = -1;
stiniterror = -2;
streaderror = -3;
stwriteerror = -4;
stgeterror = -5;
stputerror = -6;
{ only for backward compatibality }
emscurhandle : word = $ffff;
emscurpage : word = $ffff;
streamerror : pointer = nil;
rcollection : tstreamrec = (
objtype : 50;
{!!!!!!!}
);
rstringcollection : tstreamrec = (
objtype : 51;
{!!!!!!!}
);
rstringlist : tstreamrec = (
objtype : 52;
{!!!!!!!}
);
rstrlistmaker : tstreamrec = (
objtype : 53;
{!!!!!!!}
);
implementation
const
streamrecs : pstreamrec = nil;
procedure registertype(var s : tstreamrec);
begin
s.next:=streamrecs;
{ better do a type conversation }
streamrecs:=pstreamrec(@s);
end;
procedure registerobjects;
begin
registertype(rcollection);
registertype(rstringcollection);
registertype(rstringlist);
registertype(rstrlistmaker);
end;
procedure abstract;
begin
runerror(211);
end;
function newstr(const s : string) : pstring;
var
p : pstring;
begin
getmem(p,length(s)+1);
p^:=s;
newstr:=p;
end;
procedure disposestr(p : pstring);
begin
if assigned(p) then
freemem(p,length(p^)+1);
end;
function longmul(x,y : longint) : longint;
begin
exit(x*y);
end;
function longdiv(x,y : longint) : longint;
begin
exit(x div y);
end;
{****************************************************************************
TRECT
****************************************************************************}
procedure trect.checkempty;
begin
if (a.x>b.x) or (a.y>b.y) then
begin
a.x:=0;
a.y:=0;
b.x:=0;
b.y:=0;
end;
end;
procedure trect.assign(xa,ya,xb,yb : longint);
begin
a.x:=xa;
a.y:=ya;
b.x:=xb;
b.y:=yb;
end;
procedure trect.copy(r : trect);
begin
a:=r.a;
b:=r.b;
end;
procedure trect.move(adx,ady : longint);
begin
inc(a.x,adx);
inc(a.y,ady);
inc(b.x,adx);
inc(b.y,ady);
end;
procedure trect.grow(adx,ady : longint);
begin
dec(a.x,adx);
dec(a.y,ady);
inc(b.x,adx);
inc(b.y,ady);
checkempty;
end;
procedure trect.intersect(r : trect);
begin
if r.a.x>a.x then
a.x:=r.a.x;
if r.a.y>a.y then
a.y:=r.a.y;
if r.b.x<=b.x then
b.x:=r.b.x;
if r.b.y<=b.y then
b.y:=r.b.y;
checkempty;
end;
procedure trect.union(r : trect);
begin
if r.a.x<a.x then
a.x:=r.a.x;
if r.a.y<a.y then
a.y:=r.a.y;
if r.b.x>b.x then
b.x:=r.b.x;
if r.b.y>b.y then
b.y:=r.b.y;
end;
function trect.contains(p: tpoint) : boolean;
begin
contains:=(p.x>=a.x) and (p.x<=b.x) and (p.y>=a.y) and (p.y<=b.y);
end;
function trect.equals(r : trect) : boolean;
begin
equals:=(a.x=r.a.x) and (a.y=r.a.y) and (b.x=r.b.x) and (b.y=r.b.y);
end;
function trect.empty : boolean;
begin
empty:=(a.x=b.x) and (a.y=b.y);
end;
{****************************************************************************
TOBJECT
****************************************************************************}
constructor tobject.init;
begin
{ init mem }
fillchar((@self+4)^,sizeof(self)-4,0);
end;
destructor tobject.done;
begin
end;
procedure tobject.free;
begin
{ stupid: }
dispose(@self,done);
{ (and generates stupid code) }
end;
{****************************************************************************
TSTREAM
****************************************************************************}
procedure tstream.copyfrom(var s : tstream;count : longint);
var
oldpos : longint;
p : pbytearray;
begin
if status<>stok then
exit;
{ alloc the buffer }
{ may be this defragments the heap }
getmem(p,count);
{ don't modify the source stream }
{ really ?? }
oldpos:=s.getpos;
s.read(p^,count);
s.seek(oldpos);
if s.status=stok then
write(p^,count)
else
error(sterror,s.status);
freemem(p,count);
end;
procedure tstream.error(code,info : longint);
type
tstreamerrorproc = procedure;
begin
status:=code;
errorinfo:=info;
if assigned(streamerror) then
begin
tstreamerrorproc(streamerror)();
end;
end;
procedure tstream.flush;
begin
abstract;
end;
function loadmethod(cons,vmt_link,stream : pointer) : pobject;
begin
asm
// push stream var
pushl 16(%ebp)
// call get mem
pushl $0
// vmt link
pushl 12(%ebp)
// do call
movl %eax,8(%ebp)
call (%eax)
movl %esi,%eax
leave
ret $12
end;
end;
function tstream.get : pobject;
var
l : longint;
hp : pstreamrec;
p : pobject;
begin
if status<>stok then
exit;
read(l,4);
if status<>stok then
exit;
if l=0 then
exit(nil);
hp:=streamrecs;
while hp^.objtype<>l do
begin
if hp=nil then
begin
error(stgeterror,l);
exit(nil);
end;
hp:=hp^.next;
end;
{ load object }
{ call constructor direct }
get:=loadmethod(hp^.load,hp^.vmtlink,@self);
end;
function tstream.getpos : longint;
begin
abstract;
end;
function tstream.getsize : longint;
begin
abstract;
end;
type
tstoremethod = procedure(_self : pointer;_stream : pointer);
procedure tstream.put(p : pobject);
var
hp : pstreamrec;
l : longint;
begin
if status<>stok then
exit;
{ may be write nil }
if p=nil then
begin
l:=0;
write(l,4);
exit;
end;
{ search object registration }
hp:=streamrecs;
while hp^.vmtlink<>typeof(p^) do
begin
if hp=nil then
begin
error(stputerror,longint(typeof(p^)));
exit;
end;
hp:=hp^.next;
end;
write(hp^.objtype,4);
if status<>stok then
exit;
{ you can call a method explicit too }
tstoremethod(hp^.store)(p,@self);
end;
procedure tstream.read(var buf;count : longint);
begin
abstract;
end;
function tstream.readstr : pstring;
{$ifdef SSTRING}
var
len : byte;
{$endif}
p : pstring;
begin
if status<>stok then
exit;
read(len,1);
getmem(p,len+1);
length(p^):=len;
read((p+1)^,len);
readstr:=p;
end;
procedure tstream.reset;
begin
status:=stok;
errorinfo:=0;
end;
procedure tstream.seek(pos : longint);
begin
abstract;
end;
procedure tstream.truncate;
begin
abstract;
end;
procedure tstream.write(var buf;count : longint);
begin
abstract;
end;
procedure tstream.writestr(p : pstring);
begin
if status<>stok then
exit;
write(p^,length(p^)+1);
end;
{****************************************************************************
TDOSSTREAM
****************************************************************************}
constructor tdosstream.init(const filename : fnamestr;mode : word);
begin
inherited init;
{!!!!!!!}
end;
destructor tdosstream.done;
begin
{!!!!!!!}
inherited done;
end;
function tdosstream.getpos : longint;
begin
{!!!!!!!}
end;
function tdosstream.getsize : longint;
begin
{!!!!!!!}
end;
procedure tdosstream.read(var buf;count : longint);
begin
{!!!!!!!}
end;
procedure tdosstream.seek(pos : longint);
begin
{!!!!!!!}
end;
procedure tdosstream.truncate;
begin
{!!!!!!!}
end;
procedure tdosstream.write(var buf;count : longint);
begin
{!!!!!!!}
end;
{****************************************************************************
TCOLLECTION
****************************************************************************}
constructor tcollection.init(alimit,adelta : longint);
begin
inherited init;
count:=0;
limit:=alimit;
delta:=adelta;
getmem(items,limit*sizeof(pointer));
end;
constructor tcollection.load(var s : tstream);
begin
{!!!!!!}
end;
destructor tcollection.done;
begin
freeall;
freemem(items,limit*sizeof(pointer));
inherited done;
end;
function tcollection.at(index : longint) : pointer;
begin
if (index<0) or (index>=count) then
begin
error(coindexerror,index);
at:=nil;
end
else
at:=items^[index];
end;
procedure tcollection.atdelete(index : longint);
begin
if (index<0) or (index>=count) then
error(coindexerror,index)
else
{ system.move tests for zero count }
begin
move(items^[index+1],items^[index],
(count-index-1)*sizeof(pointer));
dec(count);
end;
end;
procedure tcollection.atfree(index : longint);
var
p : pointer;
begin
p:=at(index);
if assigned(p) then
begin
atdelete(index);
freeitem(p);
end;
end;
procedure tcollection.atinsert(index : longint;item : pointer);
var
p : pitemlist;
begin
{!!!!!!!! use setlimit v---- this test ???? }
if (index<0) or (index>count) then
error(coindexerror,index)
else
begin
{ maybe extent the collection }
if count=limit then
begin
if (limit+delta>maxcollectionsize) or (delta=0) then
error(cooverflow,0)
else
begin
getmem(p,(limit+delta)*sizeof(pointer));
if assigned(p) then
begin
{ system.move checks count for zero }
move(items^[0],p^[0],index*sizeof(pointer));
p^[index]:=item;
inc(count);
move(items^[index],p^[index+1],
(count-index-2)*sizeof(pointer));
freemem(items,limit*sizeof(pointer));
inc(limit,delta);
items:=p;
end
else
error(cooverflow,0);
end;
end
else
{ insert with no extent }
begin
move(items^[index],items^[index+1],
(count-index-1)*sizeof(pointer));
items^[index]:=item;
inc(count);
end;
end;
end;
procedure tcollection.atput(index : longint;item : pointer);
begin
if (index<0) or (index>=count) then
error(coindexerror,index)
else
items^[index]:=item;
end;
procedure tcollection.delete(item : pointer);
begin
atdelete(indexof(item));
end;
procedure tcollection.deleteall;
begin
count:=0;
end;
procedure tcollection.error(code,info : longint);
begin
{ makes run error 213 and 214 }
runerror(212-code);
end;
function tcollection.firstthat(test : pointer) : pointer;
begin
{ sorry, but this doesn't work without asm }
asm
movl 12(%ebp),%ebx
{ !!!! load count }
movl 4(%esi),%ecx
leave
ret $4
end;
end;
procedure tcollection.foreach(action : pointer);
begin
{!!!!!}
end;
procedure tcollection.free(item : pointer);
begin
delete(item);
freeitem(item);
end;
procedure tcollection.freeall;
var
i : longint;
begin
for i:=0 to count-1 do
freeitem(items^[i]);
count:=0;
end;
procedure tcollection.freeitem(item : pointer);
begin
{!!!!!!! crashs the compiler
if assigned(item) then
dispose(pobject(item),done); }
end;
function tcollection.getitem(var s : tstream) : pointer;
begin
{!!!!!!!!}
end;
function tcollection.indexof(item : pointer) : longint;
var
i : longint;
begin
for i:=0 to count-1 do
begin
if items^[i]=item then
begin
indexof:=i;
exit;
end;
end;
indexof:=-1;
end;
procedure tcollection.insert(item : pointer);
begin
atinsert(count,item);
end;
function tcollection.lastthat(test : pointer) : pointer;
begin
{!!!!!!!}
end;
procedure tcollection.pack;
var
i : longint;
begin
while i<count do
begin
if items^[i]=nil then
atdelete(i)
else
inc(i);
end;
end;
procedure tcollection.putitem(var s : tstream;item : pointer);
begin
s.put(pobject(item));
end;
procedure tcollection.setlimit(alimit : longint);
begin
if alimit>count then
alimit:=count;
if alimit>maxcollectionsize then
alimit:=maxcollectionsize;
{!!!!!!!!}
end;
procedure tcollection.store(var s : tstream);
begin
end;
{****************************************************************************
TSORTEDCOLLECTION
****************************************************************************}
constructor tsortedcollection.load(var s : tstream);
begin
inherited load(s);
s.read(duplicates,1);
end;
function tsortedcollection.compare(key1,key2 : pointer) : integer;
begin
abstract;
end;
function tsortedcollection.indexof(item : pointer) : longint;
var
i : longint;
begin
indexof:=-1;
if search(keyof(item),i) then
begin
if duplicates then
begin
while (i<count) and
(compare(keyof(items^[i]),keyof(item))=0) do
begin
if items^[i]=item then
begin
indexof:=i;
exit;
end;
inc(i);
end;
end
else
begin
if items^[i]=item then
indexof:=-1;
end;
end;
end;
procedure tsortedcollection.insert(item : pointer);
begin
{!!!!!!}
end;
function tsortedcollection.keyof(item : pointer) : pointer;
begin
keyof:=item;
end;
function tsortedcollection.search(key : pointer;var index : longint) : boolean;
var
i : longint;
begin
end;
procedure tsortedcollection.store(var s : tstream);
begin
inherited store(s);
s.write(duplicates,1);
end;
{****************************************************************************
TSTRINGCOLLECTION
****************************************************************************}
function tstringcollection.compare(key1,key2 : pointer) : integer;
begin
if pstring(key1)^<pstring(key2)^ then
compare:=-1
else if pstring(key1)^>pstring(key2)^ then
compare:=1
else
compare:=0;
end;
procedure tstringcollection.freeitem(item : pointer);
begin
disposestr(pstring(item));
end;
function tstringcollection.getitem(var s : tstream) : pointer;
begin
getitem:=s.readstr;
end;
procedure tstringcollection.putitem(var s : tstream;item : pointer);
begin
s.writestr(pstring(item));
end;
{****************************************************************************
TRESOURCECOLLECTION
****************************************************************************}
type
presourceindexitem = ^tresourceindexitem;
tresourceindexitem = record
name : pstring;
pos : longint;
end;
procedure tresourcecollection.freeitem(item : pointer);
begin
disposestr(presourceindexitem(item)^.name);
dispose(presourceindexitem(item));
end;
function tresourcecollection.getitem(var s : tstream) : pointer;
var
p : presourceindexitem;
begin
new(p);
p^.name:=s.readstr;
s.read(p^.pos,sizeof(p^.pos));
getitem:=p;
end;
function tresourcecollection.keyof(item : pointer) : pointer;
begin
keyof:=presourceindexitem(item)^.name;
end;
procedure tresourcecollection.putitem(var s : tstream;item : pointer);
begin
s.writestr(presourceindexitem(item)^.name);
s.write(presourceindexitem(item)^.pos,
sizeof(presourceindexitem(item)^.pos));
end;
end.