mirror of
				https://gitlab.com/freepascal.org/lazarus/lazarus.git
				synced 2025-11-04 05:59:49 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			991 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			991 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{
 | 
						|
 **********************************************************************
 | 
						|
  This file is part of LazUtils.
 | 
						|
  It is copied from Free Component Library and adapted to use
 | 
						|
  UTF8 strings instead of widestrings.
 | 
						|
 | 
						|
  See the file COPYING.modifiedLGPL.txt, included in this distribution,
 | 
						|
  for details about the license.
 | 
						|
 **********************************************************************
 | 
						|
 | 
						|
  Implementation of TXMLConfig class
 | 
						|
  Copyright (c) 1999 - 2001 by Sebastian Guenther, sg@freepascal.org
 | 
						|
 | 
						|
  TXMLConfig enables applications to use XML files for storing their
 | 
						|
  configuration data
 | 
						|
}
 | 
						|
 | 
						|
{$MODE objfpc}
 | 
						|
{$H+}
 | 
						|
 | 
						|
unit Laz2_XMLCfg;
 | 
						|
 | 
						|
interface
 | 
						|
 | 
						|
{off $DEFINE MEM_CHECK}
 | 
						|
 | 
						|
uses
 | 
						|
  {$IFDEF MEM_CHECK}MemCheck,{$ENDIF}
 | 
						|
  Classes, sysutils, LazFileCache,
 | 
						|
  Laz2_DOM, Laz2_XMLRead, Laz2_XMLWrite, LazUtilities,
 | 
						|
  typinfo;
 | 
						|
 | 
						|
type
 | 
						|
 | 
						|
  {"APath" is the path and name of a value: A XML configuration file is
 | 
						|
   hierachical. "/" is the path delimiter, the part after the last "/"
 | 
						|
   is the name of the value. The path components will be mapped to XML
 | 
						|
   elements, the name will be an element attribute.}
 | 
						|
 | 
						|
  { TXMLConfig }
 | 
						|
 | 
						|
  TXMLConfig = class(TComponent)
 | 
						|
  private
 | 
						|
    FFilename: String;
 | 
						|
    FReadFlags: TXMLReaderFlags;
 | 
						|
    FWriteFlags: TXMLWriterFlags;
 | 
						|
    FPointSettings: TFormatSettings;
 | 
						|
    procedure CreateConfigNode;
 | 
						|
    procedure InitFormatSettings;
 | 
						|
    procedure SetFilename(const AFilename: String);
 | 
						|
  protected
 | 
						|
    type
 | 
						|
      TNodeCache = record
 | 
						|
        Node: TDomNode;
 | 
						|
        ChildrenValid: boolean;
 | 
						|
        Children: array of TDomNode; // nodes with NodeName<>'' and sorted
 | 
						|
      end;
 | 
						|
  protected
 | 
						|
    doc: TXMLDocument;
 | 
						|
    FModified: Boolean;
 | 
						|
    fDoNotLoadFromFile: boolean;
 | 
						|
    fAutoLoadFromSource: string;
 | 
						|
    fPathCache: string;
 | 
						|
    fPathNodeCache: array of TNodeCache; // starting with doc.DocumentElement, then first child node of first sub path
 | 
						|
    procedure Loaded; override;
 | 
						|
    function ExtendedToStr(const e: extended): string;
 | 
						|
    function StrToExtended(const s: string; const ADefault: extended): extended;
 | 
						|
    procedure ReadXMLFile(out ADoc: TXMLDocument; const AFilename: String); virtual;
 | 
						|
    procedure WriteXMLFile(ADoc: TXMLDocument; const AFileName: String); virtual;
 | 
						|
    procedure FreeDoc; virtual;
 | 
						|
    procedure SetPathNodeCache(Index: integer; aNode: TDomNode);
 | 
						|
    function GetCachedPathNode(Index: integer): TDomNode; inline;
 | 
						|
    procedure InvalidateCacheTilEnd(StartIndex: integer);
 | 
						|
    function InternalFindNode(const APath: String; PathLen: integer;
 | 
						|
                              CreateNodes: boolean = false): TDomNode;
 | 
						|
    procedure InternalCleanNode(Node: TDomNode);
 | 
						|
    function FindChildNode(PathIndex: integer; const aName: string): TDomNode;
 | 
						|
  public
 | 
						|
    constructor Create(AOwner: TComponent); override; overload;
 | 
						|
    constructor Create(const AFilename: String); overload; // create and load
 | 
						|
    constructor CreateClean(const AFilename: String); // create new
 | 
						|
    constructor CreateWithSource(const AFilename, Source: String); // create new and load from Source
 | 
						|
    destructor Destroy; override;
 | 
						|
    procedure Clear;
 | 
						|
    procedure Flush;    // Writes the XML file
 | 
						|
    procedure ReadFromStream(s: TStream);
 | 
						|
    procedure WriteToStream(s: TStream);
 | 
						|
 | 
						|
    function  GetValue(const APath, ADefault: String): String;
 | 
						|
    function  GetValue(const APath: String; ADefault: Integer): Integer;
 | 
						|
    function  GetValue(const APath: String; ADefault: Boolean): Boolean;
 | 
						|
    function  GetExtendedValue(const APath: String;
 | 
						|
                               const ADefault: extended): extended;
 | 
						|
    procedure SetValue(const APath, AValue: String);
 | 
						|
    procedure SetDeleteValue(const APath, AValue, DefValue: String);
 | 
						|
    procedure SetValue(const APath: String; AValue: Integer);
 | 
						|
    procedure SetDeleteValue(const APath: String; AValue, DefValue: Integer);
 | 
						|
    procedure SetValue(const APath: String; AValue: Boolean);
 | 
						|
    procedure SetDeleteValue(const APath: String; AValue, DefValue: Boolean);
 | 
						|
    procedure GetValue(const APath: String; out ARect: TRect;
 | 
						|
                       const ADefault: TRect);
 | 
						|
    procedure SetDeleteValue(const APath: String; const AValue, DefValue: TRect);
 | 
						|
    procedure SetExtendedValue(const APath: String; const AValue: extended);
 | 
						|
    procedure SetDeleteExtendedValue(const APath: String;
 | 
						|
                                     const AValue, DefValue: extended);
 | 
						|
    procedure DeletePath(const APath: string);
 | 
						|
    procedure DeleteValue(const APath: string);
 | 
						|
    function FindNode(const APath: String; PathHasValue: boolean): TDomNode;
 | 
						|
    function HasPath(const APath: string; PathHasValue: boolean): boolean; // checks if the path has values, set PathHasValue=true to skip the last part
 | 
						|
    function HasChildPaths(const APath: string): boolean;
 | 
						|
    property Modified: Boolean read FModified write FModified;
 | 
						|
    procedure InvalidatePathCache;
 | 
						|
  published
 | 
						|
    property Filename: String read FFilename write SetFilename;
 | 
						|
    property Document: TXMLDocument read doc;
 | 
						|
    property ReadFlags: TXMLReaderFlags read FReadFlags write FReadFlags;
 | 
						|
    property WriteFlags: TXMLWriterFlags read FWriteFlags write FWriteFlags;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TRttiXMLConfig }
 | 
						|
 | 
						|
  TRttiXMLConfig = class(TXMLConfig)
 | 
						|
  protected
 | 
						|
    procedure WriteProperty(Path: String; Instance: TPersistent;
 | 
						|
                            PropInfo: Pointer; DefInstance: TPersistent = nil;
 | 
						|
                            OnlyProperty: String= '');
 | 
						|
    procedure ReadProperty(Path: String; Instance: TPersistent;
 | 
						|
                            PropInfo: Pointer; DefInstance: TPersistent = nil;
 | 
						|
                            OnlyProperty: String= '');
 | 
						|
  public
 | 
						|
    procedure WriteObject(Path: String; Obj: TPersistent;
 | 
						|
                          DefObject: TPersistent= nil; OnlyProperty: String= '');
 | 
						|
    procedure ReadObject(Path: String; Obj: TPersistent;
 | 
						|
                          DefObject: TPersistent= nil; OnlyProperty: String= '');
 | 
						|
  end;
 | 
						|
 | 
						|
 | 
						|
// ===================================================================
 | 
						|
 | 
						|
function CompareDomNodeNames(DOMNode1, DOMNode2: Pointer): integer;
 | 
						|
 | 
						|
implementation
 | 
						|
 | 
						|
function CompareDomNodeNames(DOMNode1, DOMNode2: Pointer): integer;
 | 
						|
var
 | 
						|
  Node1: TDOMNode absolute DomNode1;
 | 
						|
  Node2: TDOMNode absolute DomNode2;
 | 
						|
begin
 | 
						|
  Result:=CompareStr(Node1.NodeName,Node2.NodeName);
 | 
						|
end;
 | 
						|
 | 
						|
// inline
 | 
						|
function TXMLConfig.GetCachedPathNode(Index: integer): TDomNode;
 | 
						|
begin
 | 
						|
  if Index<length(fPathNodeCache) then
 | 
						|
    Result:=fPathNodeCache[Index].Node
 | 
						|
  else
 | 
						|
    Result:=nil;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TXMLConfig.Create(const AFilename: String);
 | 
						|
begin
 | 
						|
  //DebugLn(['TXMLConfig.Create ',AFilename]);
 | 
						|
  Create(nil);
 | 
						|
  SetFilename(AFilename);
 | 
						|
end;
 | 
						|
 | 
						|
constructor TXMLConfig.CreateClean(const AFilename: String);
 | 
						|
begin
 | 
						|
  //DebugLn(['TXMLConfig.CreateClean ',AFilename]);
 | 
						|
  fDoNotLoadFromFile:=true;
 | 
						|
  Create(AFilename);
 | 
						|
  FModified:=FileExistsCached(AFilename);
 | 
						|
end;
 | 
						|
 | 
						|
constructor TXMLConfig.CreateWithSource(const AFilename, Source: String);
 | 
						|
begin
 | 
						|
  fAutoLoadFromSource:=Source;
 | 
						|
  try
 | 
						|
    CreateClean(AFilename);
 | 
						|
  finally
 | 
						|
    fAutoLoadFromSource:='';
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
destructor TXMLConfig.Destroy;
 | 
						|
begin
 | 
						|
  if Assigned(doc) then
 | 
						|
  begin
 | 
						|
    Flush;
 | 
						|
    FreeDoc;
 | 
						|
  end;
 | 
						|
  inherited Destroy;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TXMLConfig.Clear;
 | 
						|
var
 | 
						|
  cfg: TDOMElement;
 | 
						|
begin
 | 
						|
  // free old document
 | 
						|
  FreeDoc;
 | 
						|
  // create new document
 | 
						|
  doc := TXMLDocument.Create;
 | 
						|
  cfg :=TDOMElement(doc.FindNode('CONFIG'));
 | 
						|
  if not Assigned(cfg) then begin
 | 
						|
    cfg := doc.CreateElement('CONFIG');
 | 
						|
    doc.AppendChild(cfg);
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TXMLConfig.Flush;
 | 
						|
begin
 | 
						|
  if Modified and (Filename<>'') then
 | 
						|
  begin
 | 
						|
    //DebugLn(['TXMLConfig.Flush ',Filename]);
 | 
						|
    WriteXMLFile(Doc,Filename);
 | 
						|
    FModified := False;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TXMLConfig.ReadFromStream(s: TStream);
 | 
						|
begin
 | 
						|
  FreeDoc;
 | 
						|
  Laz2_XMLRead.ReadXMLFile(Doc,s,ReadFlags);
 | 
						|
  if Doc=nil then
 | 
						|
    Clear;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TXMLConfig.WriteToStream(s: TStream);
 | 
						|
begin
 | 
						|
  if Doc=nil then
 | 
						|
    CreateConfigNode;
 | 
						|
  Laz2_XMLWrite.WriteXMLFile(Doc,s,WriteFlags);
 | 
						|
end;
 | 
						|
 | 
						|
function TXMLConfig.GetValue(const APath, ADefault: String): String;
 | 
						|
var
 | 
						|
  Node, Attr: TDOMNode;
 | 
						|
  NodeName: String;
 | 
						|
  StartPos: integer;
 | 
						|
begin
 | 
						|
  //CheckHeapWrtMemCnt('TXMLConfig.GetValue A '+APath);
 | 
						|
  Result:=ADefault;
 | 
						|
 | 
						|
  // skip root
 | 
						|
  StartPos:=length(APath)+1;
 | 
						|
  while (StartPos>1) and (APath[StartPos-1]<>'/') do dec(StartPos);
 | 
						|
  if StartPos>length(APath) then exit;
 | 
						|
  // find sub node
 | 
						|
  Node:=InternalFindNode(APath,StartPos-1);
 | 
						|
  if Node=nil then
 | 
						|
    exit;
 | 
						|
  //CheckHeapWrtMemCnt('TXMLConfig.GetValue E');
 | 
						|
  NodeName:=copy(APath,StartPos,length(APath));
 | 
						|
  //CheckHeapWrtMemCnt('TXMLConfig.GetValue G');
 | 
						|
  Attr := Node.Attributes.GetNamedItem(NodeName);
 | 
						|
  if Assigned(Attr) then
 | 
						|
    Result := Attr.NodeValue;
 | 
						|
  //writeln('TXMLConfig.GetValue END Result="',Result,'"');
 | 
						|
end;
 | 
						|
 | 
						|
function TXMLConfig.GetValue(const APath: String; ADefault: Integer): Integer;
 | 
						|
begin
 | 
						|
  Result := StrToIntDef(GetValue(APath, ''),ADefault);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TXMLConfig.GetValue(const APath: String; out ARect: TRect;
 | 
						|
  const ADefault: TRect);
 | 
						|
begin
 | 
						|
  ARect.Left:=GetValue(APath+'Left',ADefault.Left);
 | 
						|
  ARect.Top:=GetValue(APath+'Top',ADefault.Top);
 | 
						|
  ARect.Right:=GetValue(APath+'Right',ADefault.Right);
 | 
						|
  ARect.Bottom:=GetValue(APath+'Bottom',ADefault.Bottom);
 | 
						|
end;
 | 
						|
 | 
						|
function TXMLConfig.GetValue(const APath: String; ADefault: Boolean): Boolean;
 | 
						|
var
 | 
						|
  s: String;
 | 
						|
begin
 | 
						|
  s := GetValue(APath, '');
 | 
						|
 | 
						|
  if SameText(s, 'True') then
 | 
						|
    Result := True
 | 
						|
  else if SameText(s, 'False') then
 | 
						|
    Result := False
 | 
						|
  else
 | 
						|
    Result := ADefault;
 | 
						|
end;
 | 
						|
 | 
						|
function TXMLConfig.GetExtendedValue(const APath: String;
 | 
						|
  const ADefault: extended): extended;
 | 
						|
begin
 | 
						|
  Result:=StrToExtended(GetValue(APath,''),ADefault);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TXMLConfig.SetValue(const APath, AValue: String);
 | 
						|
var
 | 
						|
  Node: TDOMNode;
 | 
						|
  NodeName: String;
 | 
						|
  StartPos: integer;
 | 
						|
begin
 | 
						|
  StartPos:=length(APath)+1;
 | 
						|
  while (StartPos>1) and (APath[StartPos-1]<>'/') do dec(StartPos);
 | 
						|
  if StartPos>length(APath) then exit;
 | 
						|
  if Doc=nil then
 | 
						|
    CreateConfigNode;
 | 
						|
  Node:=InternalFindNode(APath,StartPos-1,true);
 | 
						|
  if Node=nil then
 | 
						|
    exit;
 | 
						|
  NodeName:=copy(APath,StartPos,length(APath));
 | 
						|
  if (not Assigned(TDOMElement(Node).GetAttributeNode(NodeName))) or
 | 
						|
    (TDOMElement(Node)[NodeName] <> AValue) then
 | 
						|
  begin
 | 
						|
    TDOMElement(Node)[NodeName] := AValue;
 | 
						|
    FModified := True;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TXMLConfig.SetDeleteValue(const APath, AValue, DefValue: String);
 | 
						|
begin
 | 
						|
  if AValue=DefValue then
 | 
						|
    DeleteValue(APath)
 | 
						|
  else
 | 
						|
    SetValue(APath,AValue);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TXMLConfig.SetValue(const APath: String; AValue: Integer);
 | 
						|
begin
 | 
						|
  SetValue(APath, IntToStr(AValue));
 | 
						|
end;
 | 
						|
 | 
						|
procedure TXMLConfig.SetDeleteValue(const APath: String; AValue,
 | 
						|
  DefValue: Integer);
 | 
						|
begin
 | 
						|
  if AValue=DefValue then
 | 
						|
    DeleteValue(APath)
 | 
						|
  else
 | 
						|
    SetValue(APath,AValue);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TXMLConfig.SetDeleteValue(const APath: String; const AValue,
 | 
						|
  DefValue: TRect);
 | 
						|
begin
 | 
						|
  SetDeleteValue(APath+'Left',AValue.Left,DefValue.Left);
 | 
						|
  SetDeleteValue(APath+'Top',AValue.Top,DefValue.Top);
 | 
						|
  SetDeleteValue(APath+'Right',AValue.Right,DefValue.Right);
 | 
						|
  SetDeleteValue(APath+'Bottom',AValue.Bottom,DefValue.Bottom);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TXMLConfig.SetValue(const APath: String; AValue: Boolean);
 | 
						|
begin
 | 
						|
  if AValue then
 | 
						|
    SetValue(APath, 'True')
 | 
						|
  else
 | 
						|
    SetValue(APath, 'False');
 | 
						|
end;
 | 
						|
 | 
						|
procedure TXMLConfig.SetDeleteValue(const APath: String; AValue,
 | 
						|
  DefValue: Boolean);
 | 
						|
begin
 | 
						|
  if AValue=DefValue then
 | 
						|
    DeleteValue(APath)
 | 
						|
  else
 | 
						|
    SetValue(APath,AValue);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TXMLConfig.SetExtendedValue(const APath: String;
 | 
						|
  const AValue: extended);
 | 
						|
begin
 | 
						|
  SetValue(APath,ExtendedToStr(AValue));
 | 
						|
end;
 | 
						|
 | 
						|
procedure TXMLConfig.SetDeleteExtendedValue(const APath: String; const AValue,
 | 
						|
  DefValue: extended);
 | 
						|
begin
 | 
						|
  if AValue=DefValue then
 | 
						|
    DeleteValue(APath)
 | 
						|
  else
 | 
						|
    SetExtendedValue(APath,AValue);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TXMLConfig.DeletePath(const APath: string);
 | 
						|
var
 | 
						|
  Node: TDOMNode;
 | 
						|
  ParentNode: TDOMNode;
 | 
						|
begin
 | 
						|
  Node:=InternalFindNode(APath,length(APath));
 | 
						|
  if (Node=nil) or (Node.ParentNode=nil) then exit;
 | 
						|
  ParentNode:=Node.ParentNode;
 | 
						|
  ParentNode.RemoveChild(Node);
 | 
						|
  FModified:=true;
 | 
						|
  InvalidatePathCache;
 | 
						|
  InternalCleanNode(ParentNode);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TXMLConfig.DeleteValue(const APath: string);
 | 
						|
var
 | 
						|
  Node: TDomNode;
 | 
						|
  StartPos: integer;
 | 
						|
  NodeName: string;
 | 
						|
begin
 | 
						|
  Node:=FindNode(APath,true);
 | 
						|
  if (Node=nil) then exit;
 | 
						|
  StartPos:=length(APath);
 | 
						|
  while (StartPos>0) and (APath[StartPos]<>'/') do dec(StartPos);
 | 
						|
  NodeName:=copy(APath,StartPos+1,length(APath)-StartPos);
 | 
						|
  if Assigned(TDOMElement(Node).GetAttributeNode(NodeName)) then begin
 | 
						|
    TDOMElement(Node).RemoveAttribute(NodeName);
 | 
						|
    FModified := True;
 | 
						|
  end;
 | 
						|
  InternalCleanNode(Node);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TXMLConfig.Loaded;
 | 
						|
begin
 | 
						|
  inherited Loaded;
 | 
						|
  if Length(Filename) > 0 then
 | 
						|
    SetFilename(Filename);              // Load the XML config file
 | 
						|
end;
 | 
						|
 | 
						|
function TXMLConfig.FindNode(const APath: String; PathHasValue: boolean): TDomNode;
 | 
						|
var
 | 
						|
  PathLen: Integer;
 | 
						|
begin
 | 
						|
  PathLen:=length(APath);
 | 
						|
  if PathHasValue then begin
 | 
						|
    while (PathLen>0) and (APath[PathLen]<>'/') do dec(PathLen);
 | 
						|
    while (PathLen>0) and (APath[PathLen]='/') do dec(PathLen);
 | 
						|
  end;
 | 
						|
  Result:=InternalFindNode(APath,PathLen);
 | 
						|
end;
 | 
						|
 | 
						|
function TXMLConfig.HasPath(const APath: string; PathHasValue: boolean): boolean;
 | 
						|
begin
 | 
						|
  Result:=FindNode(APath,PathHasValue)<>nil;
 | 
						|
end;
 | 
						|
 | 
						|
function TXMLConfig.HasChildPaths(const APath: string): boolean;
 | 
						|
var
 | 
						|
  Node: TDOMNode;
 | 
						|
begin
 | 
						|
  Node:=FindNode(APath,false);
 | 
						|
  Result:=(Node<>nil) and Node.HasChildNodes;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TXMLConfig.InvalidatePathCache;
 | 
						|
begin
 | 
						|
  fPathCache:='';
 | 
						|
  InvalidateCacheTilEnd(0);
 | 
						|
end;
 | 
						|
 | 
						|
function TXMLConfig.ExtendedToStr(const e: extended): string;
 | 
						|
begin
 | 
						|
  Result := FloatToStr(e, FPointSettings);
 | 
						|
end;
 | 
						|
 | 
						|
function TXMLConfig.StrToExtended(const s: string; const ADefault: extended): extended;
 | 
						|
begin
 | 
						|
  Result := StrToFloatDef(s, ADefault, FPointSettings);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TXMLConfig.ReadXMLFile(out ADoc: TXMLDocument; const AFilename: String);
 | 
						|
begin
 | 
						|
  InvalidatePathCache;
 | 
						|
  Laz2_XMLRead.ReadXMLFile(ADoc,AFilename,ReadFlags);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TXMLConfig.WriteXMLFile(ADoc: TXMLDocument; const AFileName: String);
 | 
						|
begin
 | 
						|
  Laz2_XMLWrite.WriteXMLFile(ADoc,AFileName,WriteFlags);
 | 
						|
  InvalidateFileStateCache(AFileName);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TXMLConfig.FreeDoc;
 | 
						|
begin
 | 
						|
  InvalidatePathCache;
 | 
						|
  FreeAndNil(doc);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TXMLConfig.SetPathNodeCache(Index: integer; aNode: TDomNode);
 | 
						|
var
 | 
						|
  OldLength, NewLength: Integer;
 | 
						|
begin
 | 
						|
  OldLength:=length(fPathNodeCache);
 | 
						|
  if OldLength<=Index then begin
 | 
						|
    if OldLength<8 then
 | 
						|
      NewLength:=8
 | 
						|
    else
 | 
						|
      NewLength:=OldLength*2;
 | 
						|
    if NewLength<Index then NewLength:=Index;
 | 
						|
    SetLength(fPathNodeCache,NewLength);
 | 
						|
    FillByte(fPathNodeCache[OldLength],SizeOf(TNodeCache)*(NewLength-OldLength),0);
 | 
						|
  end else if fPathNodeCache[Index].Node=aNode then
 | 
						|
    exit
 | 
						|
  else
 | 
						|
    InvalidateCacheTilEnd(Index+1);
 | 
						|
  with fPathNodeCache[Index] do begin
 | 
						|
    Node:=aNode;
 | 
						|
    ChildrenValid:=false;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TXMLConfig.InvalidateCacheTilEnd(StartIndex: integer);
 | 
						|
var
 | 
						|
  i: LongInt;
 | 
						|
begin
 | 
						|
  for i:=StartIndex to length(fPathNodeCache)-1 do begin
 | 
						|
    with fPathNodeCache[i] do begin
 | 
						|
      if Node=nil then break;
 | 
						|
      Node:=nil;
 | 
						|
      ChildrenValid:=false;
 | 
						|
    end;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
function TXMLConfig.InternalFindNode(const APath: String; PathLen: integer;
 | 
						|
  CreateNodes: boolean): TDomNode;
 | 
						|
var
 | 
						|
  NodePath: String;
 | 
						|
  StartPos, EndPos: integer;
 | 
						|
  PathIndex: Integer;
 | 
						|
  Parent: TDOMNode;
 | 
						|
  NdName: DOMString;
 | 
						|
  NameLen: Integer;
 | 
						|
begin
 | 
						|
  //debugln(['TXMLConfig.InternalFindNode APath="',copy(APath,1,PathLen),'" CreateNodes=',CreateNodes]);
 | 
						|
  PathIndex:=0;
 | 
						|
  Result:=GetCachedPathNode(PathIndex);
 | 
						|
  if (Result=nil) and (doc<>nil) then begin
 | 
						|
    Result:=TDOMElement(doc.FindNode('CONFIG'));
 | 
						|
    SetPathNodeCache(PathIndex,Result);
 | 
						|
  end;
 | 
						|
  if PathLen=0 then exit;
 | 
						|
  StartPos:=1;
 | 
						|
  while (Result<>nil) do begin
 | 
						|
    EndPos:=StartPos;
 | 
						|
    while (EndPos<=PathLen) and (APath[EndPos]<>'/') do inc(EndPos);
 | 
						|
    NameLen:=EndPos-StartPos;
 | 
						|
    if NameLen=0 then break;
 | 
						|
    inc(PathIndex);
 | 
						|
    Parent:=Result;
 | 
						|
    Result:=GetCachedPathNode(PathIndex);
 | 
						|
    if Result<>nil then
 | 
						|
      NdName:=Result.NodeName;
 | 
						|
    if (Result=nil) or (length(NdName)<>NameLen)
 | 
						|
    or not CompareMem(PChar(NdName),@APath[StartPos],NameLen) then begin
 | 
						|
      // different path => search
 | 
						|
      NodePath:=copy(APath,StartPos,NameLen);
 | 
						|
      Result:=FindChildNode(PathIndex-1,NodePath);
 | 
						|
      if Result=nil then begin
 | 
						|
        if not CreateNodes then exit;
 | 
						|
        // create missing node
 | 
						|
        Result:=Doc.CreateElement(NodePath);
 | 
						|
        Parent.AppendChild(Result);
 | 
						|
        fPathNodeCache[PathIndex-1].ChildrenValid:=false;
 | 
						|
        InvalidateCacheTilEnd(PathIndex);
 | 
						|
        if EndPos>PathLen then exit;
 | 
						|
      end;
 | 
						|
      SetPathNodeCache(PathIndex,Result);
 | 
						|
    end;
 | 
						|
    StartPos:=EndPos+1;
 | 
						|
    if StartPos>PathLen then exit;
 | 
						|
  end;
 | 
						|
  Result:=nil;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TXMLConfig.InternalCleanNode(Node: TDomNode);
 | 
						|
var
 | 
						|
  ParentNode: TDOMNode;
 | 
						|
begin
 | 
						|
  if (Node=nil) then exit;
 | 
						|
  while (Node.FirstChild=nil) and (Node.ParentNode<>nil)
 | 
						|
  and (Node.ParentNode.ParentNode<>nil) do begin
 | 
						|
    if (Node is TDOMElement) and (not TDOMElement(Node).IsEmpty) then break;
 | 
						|
    ParentNode:=Node.ParentNode;
 | 
						|
    ParentNode.RemoveChild(Node);
 | 
						|
    InvalidatePathCache;
 | 
						|
    Node:=ParentNode;
 | 
						|
    FModified := True;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
function TXMLConfig.FindChildNode(PathIndex: integer; const aName: string
 | 
						|
  ): TDomNode;
 | 
						|
var
 | 
						|
  aParent, aChild: TDOMNode;
 | 
						|
  aCount: Integer;
 | 
						|
  NewLength: Integer;
 | 
						|
  l, r, m: Integer;
 | 
						|
  cmp: Integer;
 | 
						|
begin
 | 
						|
  with fPathNodeCache[PathIndex] do begin
 | 
						|
    if not ChildrenValid then begin
 | 
						|
      // collect all children and sort
 | 
						|
      aParent:=Node;
 | 
						|
      aCount:=0;
 | 
						|
      aChild:=aParent.FirstChild;
 | 
						|
      while aChild<>nil do begin
 | 
						|
        if aChild.NodeName<>'' then begin
 | 
						|
          if aCount=length(Children) then begin
 | 
						|
            NewLength:=length(Children);
 | 
						|
            if NewLength<8 then
 | 
						|
              NewLength:=8
 | 
						|
            else
 | 
						|
              NewLength:=NewLength*2;
 | 
						|
            SetLength(Children,NewLength);
 | 
						|
          end;
 | 
						|
          Children[aCount]:=aChild;
 | 
						|
          inc(aCount);
 | 
						|
        end;
 | 
						|
        aChild:=aChild.NextSibling;
 | 
						|
      end;
 | 
						|
      SetLength(Children,aCount);
 | 
						|
      if aCount>1 then
 | 
						|
        MergeSort(@Children[0],aCount,@CompareDomNodeNames); // sort ascending [0]<[1]
 | 
						|
      for m:=0 to aCount-2 do
 | 
						|
        if Children[m].NodeName=Children[m+1].NodeName then begin
 | 
						|
          // duplicate found: nodes with same name
 | 
						|
          // -> use only the first
 | 
						|
          Children[m+1]:=Children[m];
 | 
						|
        end;
 | 
						|
      ChildrenValid:=true;
 | 
						|
    end;
 | 
						|
 | 
						|
    // binary search
 | 
						|
    l:=0;
 | 
						|
    r:=length(Children)-1;
 | 
						|
    while l<=r do begin
 | 
						|
      m:=(l+r) shr 1;
 | 
						|
      cmp:=CompareStr(aName,Children[m].NodeName);
 | 
						|
      if cmp<0 then
 | 
						|
        r:=m-1
 | 
						|
      else if cmp>0 then
 | 
						|
        l:=m+1
 | 
						|
      else
 | 
						|
        exit(Children[m]);
 | 
						|
    end;
 | 
						|
    Result:=nil;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TXMLConfig.Create(AOwner: TComponent);
 | 
						|
begin
 | 
						|
  // for compatibility with old TXMLConfig, which wrote #13 as #13, not as &xD;
 | 
						|
  FReadFlags:=[xrfAllowLowerThanInAttributeValue,xrfAllowSpecialCharsInAttributeValue];
 | 
						|
  FWriteFlags:=[xwfSpecialCharsInAttributeValue];
 | 
						|
  inherited Create(AOwner);
 | 
						|
  InitFormatSettings;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TXMLConfig.SetFilename(const AFilename: String);
 | 
						|
var
 | 
						|
  ms: TMemoryStream;
 | 
						|
begin
 | 
						|
  {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt('TXMLConfig.SetFilename A '+AFilename);{$ENDIF}
 | 
						|
  if FFilename = AFilename then exit;
 | 
						|
  FFilename := AFilename;
 | 
						|
  InvalidatePathCache;
 | 
						|
 | 
						|
  if csLoading in ComponentState then
 | 
						|
    exit;
 | 
						|
 | 
						|
  if Assigned(doc) then
 | 
						|
  begin
 | 
						|
    Flush;
 | 
						|
    FreeDoc;
 | 
						|
  end;
 | 
						|
 | 
						|
  doc:=nil;
 | 
						|
  //debugln(['TXMLConfig.SetFilename Load=',not fDoNotLoadFromFile,' FileExists=',FileExistsCached(Filename),' File=',Filename]);
 | 
						|
  if (not fDoNotLoadFromFile) and FileExistsCached(Filename) then
 | 
						|
    Laz2_XMLRead.ReadXMLFile(doc,Filename,ReadFlags)
 | 
						|
  else if fAutoLoadFromSource<>'' then begin
 | 
						|
    ms:=TMemoryStream.Create;
 | 
						|
    try
 | 
						|
      ms.Write(fAutoLoadFromSource[1],length(fAutoLoadFromSource));
 | 
						|
      ms.Position:=0;
 | 
						|
      Laz2_XMLRead.ReadXMLFile(doc,ms,ReadFlags);
 | 
						|
    finally
 | 
						|
      ms.Free;
 | 
						|
    end;
 | 
						|
  end;
 | 
						|
 | 
						|
  CreateConfigNode;
 | 
						|
  {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt('TXMLConfig.SetFilename END');{$ENDIF}
 | 
						|
end;
 | 
						|
 | 
						|
procedure TXMLConfig.CreateConfigNode;
 | 
						|
var
 | 
						|
  cfg: TDOMElement;
 | 
						|
begin
 | 
						|
  if not Assigned(doc) then
 | 
						|
    doc := TXMLDocument.Create;
 | 
						|
 | 
						|
  cfg :=TDOMElement(doc.FindNode('CONFIG'));
 | 
						|
  if not Assigned(cfg) then begin
 | 
						|
    cfg := doc.CreateElement('CONFIG');
 | 
						|
    doc.AppendChild(cfg);
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TXMLConfig.InitFormatSettings;
 | 
						|
begin
 | 
						|
  FPointSettings := DefaultFormatSettings;
 | 
						|
  FPointSettings.DecimalSeparator := '.';
 | 
						|
  FPointSettings.ThousandSeparator := ',';
 | 
						|
end;
 | 
						|
 | 
						|
{ TRttiXMLConfig }
 | 
						|
 | 
						|
procedure TRttiXMLConfig.WriteObject(Path: String; Obj: TPersistent;
 | 
						|
  DefObject: TPersistent; OnlyProperty: String = '');
 | 
						|
var
 | 
						|
  PropCount,i : integer;
 | 
						|
  PropList  : PPropList;
 | 
						|
begin
 | 
						|
  PropCount:=GetPropList(Obj,PropList);
 | 
						|
  if PropCount>0 then begin
 | 
						|
    try
 | 
						|
      for i := 0 to PropCount-1 do
 | 
						|
        WriteProperty(Path, Obj, PropList^[i], DefObject, OnlyProperty);
 | 
						|
    finally
 | 
						|
      Freemem(PropList);
 | 
						|
    end;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
// based on FPC TWriter
 | 
						|
procedure TRttiXMLConfig.WriteProperty(Path: String; Instance: TPersistent;
 | 
						|
  PropInfo: Pointer; DefInstance: TPersistent; OnlyProperty: String= '');
 | 
						|
type
 | 
						|
  tset = set of 0..31;
 | 
						|
var
 | 
						|
  i: Integer;
 | 
						|
  PropType: PTypeInfo;
 | 
						|
  Value, DefValue: LongInt;
 | 
						|
  Ident: String;
 | 
						|
  IntToIdentFn: TIntToIdent;
 | 
						|
  SetType: Pointer;
 | 
						|
  FloatValue, DefFloatValue: Extended;
 | 
						|
  //WStrValue, WDefStrValue: WideString;
 | 
						|
  StrValue, DefStrValue: String;
 | 
						|
  //Int64Value, DefInt64Value: Int64;
 | 
						|
  BoolValue, DefBoolValue: boolean;
 | 
						|
 | 
						|
begin
 | 
						|
  // do not stream properties without getter and setter
 | 
						|
  if not (Assigned(PPropInfo(PropInfo)^.GetProc) and
 | 
						|
          Assigned(PPropInfo(PropInfo)^.SetProc)) then
 | 
						|
    exit;
 | 
						|
 | 
						|
  PropType := PPropInfo(PropInfo)^.PropType;
 | 
						|
  Path := Path + PPropInfo(PropInfo)^.Name;
 | 
						|
  if (OnlyProperty <> '') and (OnlyProperty <> PPropInfo(PropInfo)^.Name) then
 | 
						|
    exit;
 | 
						|
 | 
						|
  case PropType^.Kind of
 | 
						|
    tkInteger, tkChar, tkEnumeration, tkSet, tkWChar:
 | 
						|
      begin
 | 
						|
        Value := GetOrdProp(Instance, PropInfo);
 | 
						|
        if (DefInstance <> nil) then
 | 
						|
          DefValue := GetOrdProp(DefInstance, PropInfo);
 | 
						|
        if (DefInstance <> nil)  and (Value = DefValue) then
 | 
						|
          DeleteValue(Path)
 | 
						|
        else begin
 | 
						|
          case PropType^.Kind of
 | 
						|
            tkInteger:
 | 
						|
              begin                      // Check if this integer has a string identifier
 | 
						|
                IntToIdentFn := FindIntToIdent(PPropInfo(PropInfo)^.PropType);
 | 
						|
                if Assigned(IntToIdentFn) and IntToIdentFn(Value, Ident{%H-}) then
 | 
						|
                  SetValue(Path, Ident) // Integer can be written a human-readable identifier
 | 
						|
                else
 | 
						|
                  SetValue(Path, Value); // Integer has to be written just as number
 | 
						|
              end;
 | 
						|
            tkChar:
 | 
						|
              SetValue(Path, Chr(Value));
 | 
						|
            tkWChar:
 | 
						|
              SetValue(Path, Value);
 | 
						|
            tkSet:
 | 
						|
              begin
 | 
						|
                SetType := GetTypeData(PropType)^.CompType;
 | 
						|
                Ident := '';
 | 
						|
                for i := 0 to 31 do
 | 
						|
                  if (i in tset(Value)) then begin
 | 
						|
                    if Ident <> '' then Ident := Ident + ',';
 | 
						|
                    Ident := Ident + GetEnumName(PTypeInfo(SetType), i);
 | 
						|
                  end;
 | 
						|
                SetValue(Path, Ident);
 | 
						|
              end;
 | 
						|
            tkEnumeration:
 | 
						|
              SetValue(Path, GetEnumName(PropType, Value));
 | 
						|
          end;
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
    tkFloat:
 | 
						|
      begin
 | 
						|
        FloatValue := GetFloatProp(Instance, PropInfo);
 | 
						|
        if (DefInstance <> nil) then
 | 
						|
         DefFloatValue := GetFloatProp(DefInstance, PropInfo);
 | 
						|
        if (DefInstance <> nil)  and (DefFloatValue = FloatValue) then
 | 
						|
          DeleteValue(Path)
 | 
						|
        else
 | 
						|
          SetValue(Path, FloatToStr(FloatValue));
 | 
						|
      end;
 | 
						|
    tkSString, tkLString, tkAString:
 | 
						|
      begin
 | 
						|
        StrValue := GetStrProp(Instance, PropInfo);
 | 
						|
        if (DefInstance <> nil) then
 | 
						|
           DefStrValue := GetStrProp(DefInstance, PropInfo);
 | 
						|
        if (DefInstance <> nil)  and (DefStrValue = StrValue) then
 | 
						|
          DeleteValue(Path)
 | 
						|
        else
 | 
						|
          SetValue(Path, StrValue);
 | 
						|
      end;
 | 
						|
(*    tkWString:
 | 
						|
      begin
 | 
						|
        WStrValue := GetWideStrProp(Instance, PropInfo);
 | 
						|
        if (DefInstance <> nil) then
 | 
						|
           WDefStrValue := GetWideStrProp(DefInstance, PropInfo);
 | 
						|
        if (DefInstance <> nil)  and (WDefStrValue = WStrValue) then
 | 
						|
          DeleteValue(Path)
 | 
						|
        else
 | 
						|
          SetValue(Path, WStrValue);
 | 
						|
      end;*)
 | 
						|
(*    tkInt64, tkQWord:
 | 
						|
      begin
 | 
						|
        Int64Value := GetInt64Prop(Instance, PropInfo);
 | 
						|
        if (DefInstance <> nil) then
 | 
						|
          DefInt64Value := GetInt64Prop(DefInstance, PropInfo)
 | 
						|
        if (DefInstance <> nil) and (Int64Value = DefInt64Value) then
 | 
						|
          DeleteValue(Path, Path)
 | 
						|
        else
 | 
						|
          SetValue(StrValue);
 | 
						|
      end;*)
 | 
						|
    tkBool:
 | 
						|
      begin
 | 
						|
        BoolValue := GetOrdProp(Instance, PropInfo)<>0;
 | 
						|
        if (DefInstance <> nil) then
 | 
						|
          DefBoolValue := GetOrdProp(DefInstance, PropInfo)<>0;
 | 
						|
        if (DefInstance <> nil) and (BoolValue = DefBoolValue) then
 | 
						|
          DeleteValue(Path)
 | 
						|
        else
 | 
						|
          SetValue(Path, BoolValue);
 | 
						|
      end;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TRttiXMLConfig.ReadProperty(Path: String; Instance: TPersistent; PropInfo: Pointer;
 | 
						|
  DefInstance: TPersistent; OnlyProperty: String);
 | 
						|
type
 | 
						|
  tset = set of 0..31;
 | 
						|
var
 | 
						|
  i, j: Integer;
 | 
						|
  PropType: PTypeInfo;
 | 
						|
  Value, DefValue: LongInt;
 | 
						|
  Ident, s: String;
 | 
						|
  IdentToIntFn: TIdentToInt;
 | 
						|
  SetType: Pointer;
 | 
						|
  FloatValue, DefFloatValue: Extended;
 | 
						|
  //WStrValue, WDefStrValue: WideString;
 | 
						|
  StrValue, DefStrValue: String;
 | 
						|
  //Int64Value, DefInt64Value: Int64;
 | 
						|
  BoolValue, DefBoolValue: boolean;
 | 
						|
 | 
						|
begin
 | 
						|
  // do not stream properties without getter and setter
 | 
						|
  if not (Assigned(PPropInfo(PropInfo)^.GetProc) and
 | 
						|
          Assigned(PPropInfo(PropInfo)^.SetProc)) then
 | 
						|
    exit;
 | 
						|
 | 
						|
  PropType := PPropInfo(PropInfo)^.PropType;
 | 
						|
  Path := Path + PPropInfo(PropInfo)^.Name;
 | 
						|
  if (OnlyProperty <> '') and (OnlyProperty <> PPropInfo(PropInfo)^.Name) then
 | 
						|
    exit;
 | 
						|
  if DefInstance = nil then
 | 
						|
    DefInstance := Instance;
 | 
						|
 | 
						|
  case PropType^.Kind of
 | 
						|
    tkInteger, tkChar, tkEnumeration, tkSet, tkWChar:
 | 
						|
      begin
 | 
						|
        DefValue := GetOrdProp(DefInstance, PropInfo);
 | 
						|
        case PropType^.Kind of
 | 
						|
          tkInteger:
 | 
						|
            begin                      // Check if this integer has a string identifier
 | 
						|
              Ident := GetValue(Path, IntToStr(DefValue));
 | 
						|
              IdentToIntFn := FindIdentToInt(PPropInfo(PropInfo)^.PropType);
 | 
						|
              if TryStrToInt(Ident, Value) then
 | 
						|
                SetOrdProp(Instance, PropInfo, Value)
 | 
						|
              else if Assigned(IdentToIntFn) and IdentToIntFn(Ident, Value) then
 | 
						|
                SetOrdProp(Instance, PropInfo, Value)
 | 
						|
              else
 | 
						|
                SetOrdProp(Instance, PropInfo, DefValue)
 | 
						|
            end;
 | 
						|
          tkChar:
 | 
						|
            begin
 | 
						|
              Ident := GetValue(Path, chr(DefValue));
 | 
						|
              if Length(Ident) > 0 then
 | 
						|
                SetOrdProp(Instance, PropInfo, ord(Ident[1]))
 | 
						|
              else
 | 
						|
                SetOrdProp(Instance, PropInfo, DefValue);
 | 
						|
            end;
 | 
						|
          tkWChar:
 | 
						|
            SetOrdProp(Instance, PropInfo, GetValue(Path, DefValue));
 | 
						|
          tkSet:
 | 
						|
            begin
 | 
						|
              SetType := GetTypeData(PropType)^.CompType;
 | 
						|
              Ident := GetValue(Path, '-');
 | 
						|
              If Ident = '-' then
 | 
						|
                Value := DefValue
 | 
						|
              else begin
 | 
						|
                Value := 0;
 | 
						|
                while length(Ident) > 0 do begin
 | 
						|
                  i := Pos(',', Ident);
 | 
						|
                  if i < 1 then
 | 
						|
                    i := length(Ident) + 1;
 | 
						|
                  s := copy(Ident, 1, i-1);
 | 
						|
                  Ident := copy(Ident, i+1, length(Ident));
 | 
						|
                  j := GetEnumValue(PTypeInfo(SetType), s);
 | 
						|
                  if j <> -1 then
 | 
						|
                    include(tset(Value), j)
 | 
						|
                  else Begin
 | 
						|
                    Value := DefValue;
 | 
						|
                    break;
 | 
						|
                  end;
 | 
						|
                end;
 | 
						|
              end;
 | 
						|
              SetOrdProp(Instance, PropInfo, Value);
 | 
						|
            end;
 | 
						|
          tkEnumeration:
 | 
						|
            begin
 | 
						|
              Ident := GetValue(Path, '-');
 | 
						|
              If Ident = '-' then
 | 
						|
                Value := DefValue
 | 
						|
              else
 | 
						|
                Value := GetEnumValue(PropType, Ident);
 | 
						|
              if Value <> -1 then
 | 
						|
                SetOrdProp(Instance, PropInfo, Value)
 | 
						|
              else
 | 
						|
                SetOrdProp(Instance, PropInfo, DefValue);
 | 
						|
            end;
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
    tkFloat:
 | 
						|
      begin
 | 
						|
        DefFloatValue := GetFloatProp(DefInstance, PropInfo);
 | 
						|
        Ident := GetValue(Path, FloatToStr(DefFloatValue));
 | 
						|
        if TryStrToFloat(Ident, FloatValue) then
 | 
						|
          SetFloatProp(Instance, PropInfo, FloatValue)
 | 
						|
        else
 | 
						|
          SetFloatProp(Instance, PropInfo, DefFloatValue)
 | 
						|
      end;
 | 
						|
    tkSString, tkLString, tkAString:
 | 
						|
      begin
 | 
						|
        DefStrValue := GetStrProp(DefInstance, PropInfo);
 | 
						|
        StrValue := GetValue(Path, DefStrValue);
 | 
						|
        SetStrProp(Instance, PropInfo, StrValue)
 | 
						|
      end;
 | 
						|
(*    tkWString:
 | 
						|
      begin
 | 
						|
      end;*)
 | 
						|
(*    tkInt64, tkQWord:
 | 
						|
      begin
 | 
						|
      end;*)
 | 
						|
    tkBool:
 | 
						|
      begin
 | 
						|
        DefBoolValue := GetOrdProp(DefInstance, PropInfo) <> 0;
 | 
						|
        BoolValue := GetValue(Path, DefBoolValue);
 | 
						|
        SetOrdProp(Instance, PropInfo, ord(BoolValue));
 | 
						|
      end;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TRttiXMLConfig.ReadObject(Path: String; Obj: TPersistent; DefObject: TPersistent;
 | 
						|
  OnlyProperty: String);
 | 
						|
var
 | 
						|
  PropCount,i : integer;
 | 
						|
  PropList  : PPropList;
 | 
						|
begin
 | 
						|
  PropCount:=GetPropList(Obj,PropList);
 | 
						|
  if PropCount>0 then begin
 | 
						|
    try
 | 
						|
      for i := 0 to PropCount-1 do
 | 
						|
        ReadProperty(Path, Obj, PropList^[i], DefObject, OnlyProperty);
 | 
						|
    finally
 | 
						|
      Freemem(PropList);
 | 
						|
    end;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
end.
 |