6. The realization of the method of reading parts
The methods used to read parts in the reader object are readsignature, Readprefix, Readcomponent, Readrootcomponent, and readcomponents.
Readsignature method is mainly used to read Delphi filer object tags in general, before reading a part, you use the call Readsignature method to guide the part read and write process.
Procedure Treader.readsignature;
Var
Signature:longint;
Begin
Read (Signature, SizeOf (Signature));
If Signature <> longint (filersignature) then Readerror (sinvalidimage);
End
Filersignature is the Filer object label whose value is "TPF0", which triggers a Sinvalidimage exception event if the read is not "TPF0".
The Readprefix method is used to read a flag bit before a part in the stream, indicating whether it is important to be in a form that inherits from an ancestor form and where it is positioned on the form.
Procedure Treader.readprefix (var flags:tfilerflags; var achildpos:integer);
Var
Prefix:byte;
Begin
Flags: = [];
If Byte (NextValue) and $F 0 = $F 0 Then
Begin
Prefix: = Byte (ReadValue);
Byte (Flags): = Prefix and $0f;
If Ffchildpos in Flags then achildpos: = Readinteger;
End
End
The definition of tfilerflags is this:
Tfilerflag = (ffinherited, ffchildpos);
Tfilerflags = Set of Tfilerflag;
The high four bits of the byte that act as flags are $f, and the low four bits are the values of the collection and the true meaning of the flag bit. If the Ffchildpos is set, the next integer number places the order of the part in the form.
The Readcomponent method is used to read a part from the stream of a reader object. The Component parameter specifies the object to read from the stream. function to return the part that is being read.
function Treader.readcomponent (component:tcomponent): tcomponent;
Var
Compclass, compname:string;
Flags:tfilerflags;
Position:integer;
...
Begin
Readprefix (Flags, Position);
Compclass: = Readstr;
Compname: = Readstr;
Result: = Component;
If result = Nil Then
If ffinherited in Flags then
Findexistingcomponent Else
Createcomponent;
If result <> Nil then
Try
Include (Result.fcomponentstate, csloading);
If not (ffinherited in Flags) then setcompname;
If result = Nil then Exit;
Include (Result.fcomponentstate, csreading);
Result.readstate (Self);
Exclude (Result.fcomponentstate, csreading);
If Ffchildpos in the Flags then Parent.setchildorder (result, Position);
Floaded.add (result);
Except
If componentcreated then Result.free;
Raise
End
End
The Readcompontent method first invokes the Readprefix method, reading out the part's flag bit and its creation order value (create orders). The part class name and part name are then read out separately using the Readstr method. If the component parameter is nil, two tasks are performed:
If the ffinberited position is looking for an existing part from root, the definition of the part type is found from the system's class table and created
If the result is not empty, the ReadState method of the part is used to read the various attribute values, set the Parent property of the part, and restore the order in which the parent part was created.
The main readcomponent method is to call the Readcomponent method to read a series of associated parts from the stream of the reader object and to decompose the mutual reference relationship.
Procedure Treader.readcomponents (Aowner, aparent:tcomponent;
PROC:TREADCOMPONENTSPROC);
Var
Component:tcomponent;
Begin
Root: = Aowner;
Owner: = Aowner;
Parent: = aparent;
Beginreferences;
Try
While does Endoflist do
Begin
Readsignature;
Component: = Readcomponent (nil);
Proc (Component);
End
Fixupreferences;
Finally
Endreferences;
End
End
Readcomponents first assigns values to Root,owner and parent with Aowner and aparent parameters, which are used to reconstruct the mutual reference of each part. The part is then read with a while loop and processed by the method passed in by Proc. The Beginreferences, fixupreferences, and endreferences nested patterns are used when rebuilding the reference relationship.
The Readrootcomponent method reads the part and its owning part from the stream of the reader object. If the component parameter is nil, a part of the same type is created and the part is returned:
function Treader.readrootcomponent (root:tcomponent): tcomponent;
function Finduniquename (const name:string): string;
Begin
...
End
Var
I:integer;
Flags:tfilerflags;
Begin
Readsignature;
Result: = nil;
Try
Readprefix (Flags, I);
If Root = Nil Then
Begin
Result: = Tcomponentclass (Findclass (READSTR)). Create (nil);
Result.name: = Readstr;
End Else
Begin
Result: = Root;
READSTR; {Ignore class name}
If csdesigning in Result.componentstate then
Readstr Else
Result.name: = Finduniquename (READSTR);
End
Froot: = result;
If globalloaded <> Nil Then
floaded: = globalloaded Else
floaded: = tlist.create;
Try
Floaded.add (Froot);
Fowner: = Froot;
Include (Froot.fcomponentstate, csloading);
Include (Froot.fcomponentstate, csreading);
Froot.readstate (Self);
Exclude (Froot.fcomponentstate, csreading);
If globalloaded = Nil Then
For I: = 0 to Floaded.count-1 do tcomponent (Floaded[i]). Loaded;
Finally
If globalloaded = nil then floaded.free;
floaded: = nil;
End
Globalfixupreferences;
Except
Removefixupreferences (Root, "");
If Root = nil then result.free;
Raise
End
End
Readrootcomponent first invokes Readsignature to read the Filer object tag. The read task is then performed in the Try...except loop. If the root parameter is nil, a new part is created with the class name read out by Readstr, and the Name property of the part is read out in the stream, otherwise the class name is ignored and the Name property is judged to be unique. Finally, the root ReadState method is used to read the property and its owning and handling reference relationships.