TDxfToken =
class
public
GroupCode: integer;
StrValue:
string;
FloatValue: double;
IntValue: integer;
Childs: TList;
procedure Clear;
constructor Create;
destructor Destroy;
override;
end;
TDxfTokenizer =
class
public
Tokens: TList;
function TablesSubsection(
const Value:
string): boolean;
function BlocksSubsection(
const Value:
string): boolean;
function EntitiesSubsection(
const Value:
string): boolean;
procedure LoadFromFile(
const FileName:
string);
procedure Clear;
constructor Create;
destructor Destroy;
override;
end;
procedure TDxfTokenizer.LoadFromFile(
const FileName:
string);
var
I: integer;
StrSectionGroupCode, StrSectionName:
string;
IntSectionGroupCode: integer;
CurTokenBase, NextTokenBase, SectionTokenBase, LastBlockToken: TList;
NewToken: TDxfToken;
ParserState: integer;
SL: TStringList;
begin
if FileExists(FileName)
then
begin
SL := TStringList.Create;
try
Tokens.Clear;
SL.LoadFromFile(FileName);
CurTokenBase := Tokens;
NextTokenBase := Tokens;
I := 0;
ParserState := 0;
while I < SL.Count - 1
do
begin
CurTokenBase := NextTokenBase;
// Now read and process the section name
StrSectionGroupCode := SL.Strings[I];
IntSectionGroupCode := StrToInt(Trim(StrSectionGroupCode));
StrSectionName := SL.Strings[I + 1];
NewToken := TDxfToken.Create;
NewToken.GroupCode := IntSectionGroupCode;
NewToken.StrValue := StrSectionName;
// Waiting for a section
if ParserState = 0
then
begin
if (StrSectionName = '
SECTION')
then
begin
ParserState := 1;
NextTokenBase := NewToken.Childs;
end
else
if (StrSectionName = '
EOF')
then
begin
Exit;
end
// Comments can be in the beginning of the file and start with 999
else
if (IntSectionGroupCode = 999)
then
begin
// nothing to be done, let it add the token
end
else
begin
raise Exception.Create(Format(
'
TDxfTokenizer.ReadFromStrings: Expected SECTION, but got: %s', [StrSectionname]));
end;
end
// Processing the section name
else
if ParserState = 1
then
begin
if (StrSectionName = '
HEADER')
or
(StrSectionName = '
CLASSES')
or
(StrSectionName = '
OBJECTS')
or
(StrSectionName = '
THUMBNAILIMAGE')
then
begin
ParserState := 2;
SectionTokenBase := CurTokenBase;
end
else
if (StrSectionName = '
BLOCKS')
or (StrSectionName = '
TABLES')
then
begin
ParserState := 4;
SectionTokenBase := CurTokenBase;
end
else
if (StrSectionName = '
ENTITIES')
then
begin
ParserState := 3;
SectionTokenBase := CurTokenBase;
end
else
begin
raise Exception.Create(Format(
'
TDxfTokenizer.ReadFromStrings: Invalid section name: %s', [StrSectionname]));
end;
end
// Reading a generic section
else
if ParserState = 2
then
begin
if StrSectionName = '
ENDSEC'
then
begin
ParserState := 0;
CurTokenBase := SectionTokenBase;
NextTokenBase := Tokens;
end;
end
// Reading the ENTITIES section
else
if ParserState = 3
then
begin
if EntitiesSubsection(StrSectionName)
then
begin
CurTokenBase := SectionTokenBase;
NextTokenBase := NewToken.Childs;
end
else
if StrSectionName = '
ENDSEC'
then
begin
ParserState := 0;
CurTokenBase := SectionTokenBase;
NextTokenBase := Tokens;
end;
end
// Reading the TABLES or BLOCKS sections
else
if ParserState = 4
then
begin
// This orders the blocks themselves
if TablesSubsection(StrSectionName)
or BlocksSubsection(StrSectionName)
then
begin
CurTokenBase := SectionTokenBase;
NextTokenBase := NewToken.Childs;
LastBlockToken := NewToken.Childs;
end
// This orders the entities inside blocks
else
if EntitiesSubsection(StrSectionName)
and (LastBlockToken <>
nil)
then
begin
CurTokenBase := LastBlockToken;
NextTokenBase := NewToken.Childs;
end
else
if StrSectionName = '
ENDSEC'
then
begin
ParserState := 0;
CurTokenBase := SectionTokenBase;
NextTokenBase := Tokens;
end;
end;
CurTokenBase.Add(NewToken);
Inc(I, 2);
end;
finally
SL.Free;
end;
end;
end;