20.3.1.4 DFM file and standard text file (TXT file) of the mutual conversion
In the Delphi visual design environment, programmers are allowed to browse and modify the DFM file content in the Code Editor by text. When you open the DFM file directly with the File/open command, or when you select the view as Text command on the pop-up menu of the Form Design window, information in the form of text appears in the editor. Let's call this text form a form design script. Delphi provides this kind of script editing function is to Delphi visual design a big supplement. Of course, this script editing ability is limited, for example, can not arbitrarily add and delete parts in the script, because the code and DFM scripts are closely linked, arbitrary additions and modifications can lead to inconsistencies. However, there is no such limitation in the dynamically generated DFM file, and the application of DFM dynamic generation technology will be introduced later.
In fact, the DFM file content is binary data, its script is automatically transformed through the Delphi development environment, and Delphi VCL in the Classes Library unit in the binary flow of the document DFM and its script of the mutual transformation process. They are objectbinarytotext and objecttextbinary, Objectresourcetotext and Objecttexttoresource.
The objectbinarytotext process converts parts stored in binary streams into text-based representations, which can be processed using text-processing functions, and can be searched and substituted using text editors, which can then be converted to parts in binary streams.
The main program for the Objectbinarytotext process is this:
Procedure Objectbinarytotext (Input, Output:tstream);
Var
Nestinglevel:integer;
Saveseparator:char;
Reader:treader;
Writer:twriter;
Procedure Writeindent;
Const
Blanks:array[0..1] of Char = ';
Var
I:integer;
Begin
For I: = 1 to NestingLevel do writer.write (Blanks, SizeOf (blanks));
End
Procedure Writestr (const s:string);
Begin
Writer.write (S[1], Length (S));
End
Procedure newline;
Begin
Writestr (#13 #10);
Writeindent;
End
Procedure Convertheader;
Begin
...
End
Procedure Convertbinary;
Begin
...
End
Procedure Convertvalue;
Begin
...
End
Procedure Convertproperty;
Begin
...
End
Procedure Convertobject;
Begin
...
End
Begin
NestingLevel: = 0;
Reader: = Treader.create (Input, 4096);
Saveseparator: = DecimalSeparator;
DecimalSeparator: = '. ';
Try
Writer: = Twriter.create (Output, 4096);
Try
Reader.readsignature;
Convertobject;
Finally
Writer.free;
End
Finally
DecimalSeparator: = Saveseparator;
Reader.free;
End
End
The Convertobject procedure called in the procedure is a recursive process that converts each part in the DFM file into text. Because of the ownership of the parts, the parts are nested, and recursion is the best way:
Procedure Convertobject;
Begin
Convertheader;
INC (NestingLevel);
While does reader.endoflist do convertproperty;
Reader.readlistend;
While does reader.endoflist do convertobject;
Reader.readlistend;
Dec (NestingLevel);
Writeindent;
Writestr (' End ' #13 #10);
End
The Neststinglevel variable represents the nesting level of the part. Writeindent is the space before the start character of each line is written, and the Convertheader process is the inheritance flag information that handles the part. The converted header message text has two forms.
Inherited Testform1:ttestform[2]
Or:
Object Testform1:ttestform
The former is ffinherited and Ffchildpos, and there are no places behind it.
The Convertproperty process is used to convert attributes.
Procedure Convertproperty;
Begin
Writeindent;
Writestr (READER.READSTR);
Writestr (' = ');
Convertvalue;
Writestr (#13 #10);
End
The Writeindent statement writes the space before the property name, and the WRITESTR (READER.READSTR) statement writes the property name Convertvalue The process converts the property value to a string based on the type of the property and then writes to the stream.
The function of objecttexttobinary process is opposite to objectbinarytotext, the TXT file is converted to a part in binary stream, and as long as the writing of TXT file content conforms to DFM script syntax, Objecttexttobinary can convert any program generated TXT file into a part, this function also for DFM file dynamic generation and edit laid the foundation. The main procedures for the objecttexttobinary process are as follows:
Procedure Objecttexttobinary (Input, Output:tstream);
Var
Saveseparator:char;
Parser:tparser;
Writer:twriter;
...
Begin
Parser: = Tparser.create (Input);
Saveseparator: = DecimalSeparator;
DecimalSeparator: = '. ';
Try
Writer: = Twriter.create (Output, 4096);
Try
Writer.writesignature;
Convertobject;
Finally
Writer.free;
End
Finally
DecimalSeparator: = Saveseparator;
Parser.free;
End
End
The process and structure of the program is similar to Objectbinarytotext. Convertobject is also a recursive process:
Procedure Convertobject;
Var
Inheritedobject:boolean;
Begin
Inheritedobject: = False;
If Parser.tokensymbolis (' inherited ') then
Inheritedobject: = True
Else
Parser.checktokensymbol (' OBJECT ');
Parser.nexttoken;
Convertheader (Inheritedobject);
While isn't Parser.tokensymbolis (' end ') and
Not Parser.tokensymbolis (' OBJECT ') and
Not Parser.tokensymbolis (' inherited ') do convertproperty;
Writer.writelistend;
While not Parser.tokensymbolis (' end ') does convertobject;
Writer.writelistend;
Parser.nexttoken;
End
The task of converting the DFM file to the DFM scripting language is accomplished by the Objectresourcetotext and Objexttexttoresource two processes.
Procedure Objectresourcetotext (Input, Output:tstream);
Begin
Input.readresheader;
Objectbinarytotext (Input, Output);
End
The Objecttexttoresource process is more complex because the DFM file resource header contains the inheritance flag information, so after calling Objecttexttobinary, it reads the flag information and writes the resource header.
Procedure Objecttexttoresource (Input, Output:tstream);
Var
Len:byte;
Tmp:longint;
Memorystream:tmemorystream;
Memorysize:longint;
HEADER:ARRAY[0..79] of Char;
Begin
MemoryStream: = tmemorystream.create;
Try
Objecttexttobinary (Input, MemoryStream);
Memorysize: = memorystream.size;
Fillchar (header, SizeOf (header), 0);
Memorystream.position: = SizeOf (Longint); {Skip Header}
Memorystream.read (Len, 1);
If Len and $F 0 = $F 0 Then
Begin
If Ffchildpos in Tfilerflags ((Len and $F 0)) Then
Begin
Memorystream.read (Len, 1);
Case Tvaluetype (Len) of
Vaint8:len: = 1;
Vaint16:len: = 2;
Vaint32:len: = 4;
End
Memorystream.read (TMP, Len);
End
Memorystream.read (Len, 1);
End
Memorystream.read (Header[3], Len);
Strupper (@Header [3]);
Byte ((@Header [0]) ^): = $FF;
Word (@Header [1]) ^): = 10;
Word (@Header [Len + 4]) ^): = $1030;
Longint ((@Header [Len + 6]) ^): = Memorysize;
Output.write (Header, Len + 10);
Output.write (memorystream.memory^, memorysize);
Finally
Memorystream.free;
End
End