758 lines
24 KiB
ObjectPascal

{
Double Commander
-------------------------------------------------------------------------
Implementation of configuration file in XML.
Based on XmlConf from fcl-xml package.
Copyright (C) 2010 Przemyslaw Nagay (cobines@gmail.com)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
}
unit DCXmlConfig;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, DOM, XMLRead, XMLWrite;
type
// Define type aliases so we don't have to include DOM if we want to use config.
TXmlNode = TDOMNode;
TXmlPath = DOMString;
{ TXmlConfig }
TXmlConfig = class
private
FFileName: UTF8String;
FDoc: TXMLDocument;
function GetRootNode: TXmlNode;
procedure SplitPathToNodeAndAttr(const Path: DOMString; out NodePath: DOMString; out AttrName: DOMString);
public
constructor Create; virtual;
constructor Create(const AFileName: UTF8String; AutoLoad: Boolean = False); virtual;
destructor Destroy; override;
procedure Clear;
function AddNode(const RootNode: TDOMNode; const ValueName: DOMString): TDOMNode;
procedure DeleteNode(const RootNode: TDOMNode; const Path: DOMString);
procedure DeleteNode(const Node: TDOMNode);
procedure ClearNode(const Node: TDOMNode);
function FindNode(const RootNode: TDOMNode; const Path: DOMString; bCreate: Boolean = False): TDOMNode;
function GetContent(const Node: TDOMNode): UTF8String;
function IsEmpty: Boolean;
procedure SetContent(const Node: TDOMNode; const AValue: UTF8String);
// ------------------------------------------------------------------------
function GetAttr(const RootNode: TDOMNode; const Path: DOMString; const ADefault: UTF8String): UTF8String;
function GetAttr(const RootNode: TDOMNode; const Path: DOMString; const ADefault: Boolean): Boolean;
function GetAttr(const RootNode: TDOMNode; const Path: DOMString; const ADefault: Integer): Integer;
function GetAttr(const RootNode: TDOMNode; const Path: DOMString; const ADefault: Int64): Int64;
function GetAttr(const RootNode: TDOMNode; const Path: DOMString; const ADefault: Double): Double;
function GetValue(const RootNode: TDOMNode; const Path: DOMString; const ADefault: UTF8String): UTF8String;
function GetValue(const RootNode: TDOMNode; const Path: DOMString; const ADefault: Boolean): Boolean;
function GetValue(const RootNode: TDOMNode; const Path: DOMString; const ADefault: Integer): Integer;
function GetValue(const RootNode: TDOMNode; const Path: DOMString; const ADefault: Int64): Int64;
function GetValue(const RootNode: TDOMNode; const Path: DOMString; const ADefault: Double): Double;
// The Try... functions return True if the attribute/node was found and only then set AValue.
function TryGetAttr(const RootNode: TDOMNode; const Path: DOMString; out AValue: UTF8String): Boolean;
function TryGetAttr(const RootNode: TDOMNode; const Path: DOMString; out AValue: Boolean): Boolean;
function TryGetAttr(const RootNode: TDOMNode; const Path: DOMString; out AValue: Integer): Boolean;
function TryGetAttr(const RootNode: TDOMNode; const Path: DOMString; out AValue: Int64): Boolean;
function TryGetAttr(const RootNode: TDOMNode; const Path: DOMString; out AValue: Double): Boolean;
function TryGetValue(const RootNode: TDOMNode; const Path: DOMString; out AValue: UTF8String): Boolean;
function TryGetValue(const RootNode: TDOMNode; const Path: DOMString; out AValue: Boolean): Boolean;
function TryGetValue(const RootNode: TDOMNode; const Path: DOMString; out AValue: Integer): Boolean;
function TryGetValue(const RootNode: TDOMNode; const Path: DOMString; out AValue: Int64): Boolean;
function TryGetValue(const RootNode: TDOMNode; const Path: DOMString; out AValue: Double): Boolean;
// ------------------------------------------------------------------------
// AddValue functions always add a new node.
procedure AddValue(const RootNode: TDOMNode; const ValueName: DOMString; const AValue: String);
procedure AddValue(const RootNode: TDOMNode; const ValueName: DOMString; const AValue: Boolean);
procedure AddValue(const RootNode: TDOMNode; const ValueName: DOMString; const AValue: Integer);
procedure AddValue(const RootNode: TDOMNode; const ValueName: DOMString; const AValue: Int64);
procedure AddValue(const RootNode: TDOMNode; const ValueName: DOMString; const AValue: Double);
procedure AddValueDef(const RootNode: TDOMNode; const ValueName: DOMString; const AValue, DefaultValue: String);
procedure AddValueDef(const RootNode: TDOMNode; const ValueName: DOMString; const AValue, DefaultValue: Boolean);
procedure AddValueDef(const RootNode: TDOMNode; const ValueName: DOMString; const AValue, DefaultValue: Integer);
procedure AddValueDef(const RootNode: TDOMNode; const ValueName: DOMString; const AValue, DefaultValue: Int64);
procedure AddValueDef(const RootNode: TDOMNode; const ValueName: DOMString; const AValue, DefaultValue: Double);
// SetValue functions can only set values for unique paths.
procedure SetAttr(const RootNode: TDOMNode; const Path: DOMString; const AValue: UTF8String);
procedure SetAttr(const RootNode: TDOMNode; const Path: DOMString; const AValue: Boolean);
procedure SetAttr(const RootNode: TDOMNode; const Path: DOMString; const AValue: Integer);
procedure SetAttr(const RootNode: TDOMNode; const Path: DOMString; const AValue: Int64);
procedure SetAttr(const RootNode: TDOMNode; const Path: DOMString; const AValue: Double);
procedure SetValue(const RootNode: TDOMNode; const Path: DOMString; const AValue: String);
procedure SetValue(const RootNode: TDOMNode; const Path: DOMString; const AValue: Boolean);
procedure SetValue(const RootNode: TDOMNode; const Path: DOMString; const AValue: Integer);
procedure SetValue(const RootNode: TDOMNode; const Path: DOMString; const AValue: Int64);
procedure SetValue(const RootNode: TDOMNode; const Path: DOMString; const AValue: Double);
// ------------------------------------------------------------------------
procedure GetFont(const aNode: TXmlNode; Path: TXmlPath;
out Name: UTF8String; out Size: Integer; out Style: Integer;
const DefName: UTF8String; const DefSize: Integer; const DefStyle: Integer);
procedure SetFont(const aNode: TXmlNode; Path: TXmlPath;
const Name: UTF8String; const Size: Integer; const Style: Integer);
// ------------------------------------------------------------------------
procedure ReadFromFile(const AFilename: UTF8String);
procedure ReadFromStream(AStream: TStream);
procedure WriteToFile(const AFilename: UTF8String);
procedure WriteToStream(AStream: TStream);
function Load: Boolean;
function LoadBypassingErrors: Boolean;
function Save: Boolean;
{en
Get path of form "<RootNodeName>/<Child1NodeName>/<Child2NodeName>...".
}
function GetPathFromNode(aNode: TDOMNode): String;
property FileName: UTF8String read FFileName write FFileName;
property RootNode: TXmlNode read GetRootNode;
end;
EXmlConfigEmpty = class(EFilerError);
EXmlConfigNotFound = class(EFilerError);
implementation
uses
LazUTF8, LazLogger, DCOSUtils, DCClassesUtf8, URIParser;
const
BoolStrings: array[Boolean] of DOMString = ('False', 'True');
constructor TXmlConfig.Create;
begin
Clear;
end;
constructor TXmlConfig.Create(const AFileName: UTF8String; AutoLoad: Boolean);
begin
FFileName := AFileName;
if not (AutoLoad and LoadBypassingErrors) then
Clear;
end;
destructor TXmlConfig.Destroy;
begin
FreeAndNil(FDoc);
inherited Destroy;
end;
procedure TXmlConfig.Clear;
begin
FreeAndNil(FDoc);
FDoc := TXMLDocument.Create;
FDoc.AppendChild(FDoc.CreateElement(ApplicationName));
end;
function TXmlConfig.GetRootNode: TXmlNode;
begin
Result := FDoc.DocumentElement;
end;
// ------------------------------------------------------------------------
function TXmlConfig.GetAttr(const RootNode: TDOMNode; const Path: DOMString; const ADefault: UTF8String): UTF8String;
begin
if not TryGetAttr(RootNode, Path, Result) then
Result := ADefault;
end;
function TXmlConfig.GetAttr(const RootNode: TDOMNode; const Path: DOMString; const ADefault: Boolean): Boolean;
begin
if not TryGetAttr(RootNode, Path, Result) then
Result := ADefault;
end;
function TXmlConfig.GetAttr(const RootNode: TDOMNode; const Path: DOMString; const ADefault: Integer): Integer;
begin
if not TryGetAttr(RootNode, Path, Result) then
Result := ADefault;
end;
function TXmlConfig.GetAttr(const RootNode: TDOMNode; const Path: DOMString; const ADefault: Int64): Int64;
begin
if not TryGetAttr(RootNode, Path, Result) then
Result := ADefault;
end;
function TXmlConfig.GetAttr(const RootNode: TDOMNode; const Path: DOMString; const ADefault: Double): Double;
begin
if not TryGetAttr(RootNode, Path, Result) then
Result := ADefault;
end;
function TXmlConfig.TryGetAttr(const RootNode: TDOMNode; const Path: DOMString; out AValue: UTF8String): Boolean;
var
Node: TDOMNode;
Attr: TDOMAttr;
NodePath, AttrName: DOMString;
begin
SplitPathToNodeAndAttr(Path, NodePath, AttrName);
if NodePath <> EmptyWideStr then
begin
Node := FindNode(RootNode, NodePath, False);
if not Assigned(Node) then
Exit(False);
end
else
Node := RootNode;
Attr := TDOMElement(Node).GetAttributeNode(AttrName);
Result := Assigned(Attr);
if Result then
AValue := UTF16ToUTF8(Attr.Value);
end;
function TXmlConfig.TryGetAttr(const RootNode: TDOMNode; const Path: DOMString; out AValue: Boolean): Boolean;
var
sValue: UTF8String;
begin
Result := TryGetAttr(RootNode, Path, sValue);
if Result then
begin
if SameText(sValue, 'TRUE') then
AValue := True
else if SameText(sValue, 'FALSE') then
AValue := False
else
Result := False; // If other text then return not found.
end;
end;
function TXmlConfig.TryGetAttr(const RootNode: TDOMNode; const Path: DOMString; out AValue: Integer): Boolean;
var
sValue: UTF8String;
begin
Result := TryGetAttr(RootNode, Path, sValue) and TryStrToInt(sValue, AValue);
end;
function TXmlConfig.TryGetAttr(const RootNode: TDOMNode; const Path: DOMString; out AValue: Int64): Boolean;
var
sValue: UTF8String;
begin
Result := TryGetAttr(RootNode, Path, sValue) and TryStrToInt64(sValue, AValue);
end;
function TXmlConfig.TryGetAttr(const RootNode: TDOMNode; const Path: DOMString; out AValue: Double): Boolean;
var
sValue: UTF8String;
begin
Result := TryGetAttr(RootNode, Path, sValue) and TryStrToFloat(sValue, AValue);
end;
function TXmlConfig.GetValue(const RootNode: TDOMNode; const Path: DOMString; const ADefault: UTF8String): UTF8String;
var
Node: TDOMNode;
begin
Node := FindNode(RootNode, Path, False);
if Assigned(Node) then
Result := UTF16ToUTF8(Node.TextContent)
else
Result := ADefault;
end;
function TXmlConfig.IsEmpty: Boolean;
begin
Result := RootNode.ChildNodes.Count = 0;
end;
function TXmlConfig.GetValue(const RootNode: TDOMNode; const Path: DOMString; const ADefault: Boolean): Boolean;
var
sValue: UTF8String;
begin
sValue := GetValue(RootNode, Path, '');
if SameText(sValue, 'TRUE') then
Result := True
else if SameText(sValue, 'FALSE') then
Result := False
else
Result := ADefault;
end;
function TXmlConfig.GetValue(const RootNode: TDOMNode; const Path: DOMString; const ADefault: Integer): Integer;
begin
Result := StrToIntDef(GetValue(RootNode, Path, ''), ADefault);
end;
function TXmlConfig.GetValue(const RootNode: TDOMNode; const Path: DOMString; const ADefault: Int64): Int64;
begin
Result := StrToInt64Def(GetValue(RootNode, Path, ''), ADefault);
end;
function TXmlConfig.GetValue(const RootNode: TDOMNode; const Path: DOMString; const ADefault: Double): Double;
begin
Result := StrToFloatDef(GetValue(RootNode, Path, ''), ADefault);
end;
function TXmlConfig.TryGetValue(const RootNode: TDOMNode; const Path: DOMString; out AValue: UTF8String): Boolean;
var
Node: TDOMNode;
begin
Node := FindNode(RootNode, Path, False);
Result := Assigned(Node);
if Result then
AValue := UTF16ToUTF8(Node.TextContent);
end;
function TXmlConfig.TryGetValue(const RootNode: TDOMNode; const Path: DOMString; out AValue: Boolean): Boolean;
var
sValue: UTF8String;
begin
Result := TryGetValue(RootNode, Path, sValue);
if Result then
begin
if SameText(sValue, 'TRUE') then
AValue := True
else if SameText(sValue, 'FALSE') then
AValue := False
else
Result := False; // If other text then return not found.
end;
end;
function TXmlConfig.TryGetValue(const RootNode: TDOMNode; const Path: DOMString; out AValue: Integer): Boolean;
var
sValue: UTF8String;
begin
Result := TryGetValue(RootNode, Path, sValue) and TryStrToInt(sValue, AValue);
end;
function TXmlConfig.TryGetValue(const RootNode: TDOMNode; const Path: DOMString; out AValue: Int64): Boolean;
var
sValue: UTF8String;
begin
Result := TryGetValue(RootNode, Path, sValue) and TryStrToInt64(sValue, AValue);
end;
function TXmlConfig.TryGetValue(const RootNode: TDOMNode; const Path: DOMString; out AValue: Double): Boolean;
var
sValue: UTF8String;
begin
Result := TryGetValue(RootNode, Path, sValue) and TryStrToFloat(sValue, AValue);
end;
// ----------------------------------------------------------------------------
procedure TXmlConfig.AddValue(const RootNode: TDOMNode; const ValueName: DOMString; const AValue: String);
var
Node: TDOMNode;
begin
Node := RootNode.AppendChild(FDoc.CreateElement(ValueName));
Node.TextContent := UTF8ToUTF16(AValue);
end;
procedure TXmlConfig.AddValueDef(const RootNode: TDOMNode; const ValueName: DOMString; const AValue, DefaultValue: Boolean);
begin
if AValue <> DefaultValue then
AddValue(RootNode, ValueName, AValue);
end;
procedure TXmlConfig.AddValueDef(const RootNode: TDOMNode; const ValueName: DOMString; const AValue, DefaultValue: Double);
begin
if AValue <> DefaultValue then
AddValue(RootNode, ValueName, AValue);
end;
procedure TXmlConfig.AddValueDef(const RootNode: TDOMNode; const ValueName: DOMString; const AValue, DefaultValue: Int64);
begin
if AValue <> DefaultValue then
AddValue(RootNode, ValueName, AValue);
end;
procedure TXmlConfig.AddValueDef(const RootNode: TDOMNode; const ValueName: DOMString; const AValue, DefaultValue: Integer);
begin
if AValue <> DefaultValue then
AddValue(RootNode, ValueName, AValue);
end;
procedure TXmlConfig.AddValueDef(const RootNode: TDOMNode; const ValueName: DOMString; const AValue, DefaultValue: String);
begin
if AValue <> DefaultValue then
AddValue(RootNode, ValueName, AValue);
end;
procedure TXmlConfig.AddValue(const RootNode: TDOMNode; const ValueName: DOMString; const AValue: Boolean);
begin
AddValue(RootNode, ValueName, BoolStrings[AValue]);
end;
procedure TXmlConfig.AddValue(const RootNode: TDOMNode; const ValueName: DOMString; const AValue: Integer);
begin
AddValue(RootNode, ValueName, IntToStr(AValue));
end;
procedure TXmlConfig.AddValue(const RootNode: TDOMNode; const ValueName: DOMString; const AValue: Int64);
begin
AddValue(RootNode, ValueName, IntToStr(AValue));
end;
procedure TXmlConfig.AddValue(const RootNode: TDOMNode; const ValueName: DOMString; const AValue: Double);
begin
AddValue(RootNode, ValueName, FloatToStr(AValue));
end;
procedure TXmlConfig.SetAttr(const RootNode: TDOMNode; const Path: DOMString; const AValue: UTF8String);
var
Node: TDOMNode;
NodePath, AttrName: DOMString;
begin
SplitPathToNodeAndAttr(Path, NodePath, AttrName);
if NodePath <> EmptyWideStr then
begin
Node := FindNode(RootNode, NodePath, True);
TDOMElement(Node)[AttrName] := UTF8ToUTF16(AValue);
end
else
TDOMElement(RootNode)[AttrName] := UTF8ToUTF16(AValue);
end;
procedure TXmlConfig.SetAttr(const RootNode: TDOMNode; const Path: DOMString; const AValue: Boolean);
begin
SetAttr(RootNode, Path, BoolStrings[AValue]);
end;
procedure TXmlConfig.SetAttr(const RootNode: TDOMNode; const Path: DOMString; const AValue: Integer);
begin
SetAttr(RootNode, Path, IntToStr(AValue));
end;
procedure TXmlConfig.SetAttr(const RootNode: TDOMNode; const Path: DOMString; const AValue: Int64);
begin
SetAttr(RootNode, Path, IntToStr(AValue));
end;
procedure TXmlConfig.SetAttr(const RootNode: TDOMNode; const Path: DOMString; const AValue: Double);
begin
SetAttr(RootNode, Path, FloatToStr(AValue));
end;
procedure TXmlConfig.SetValue(const RootNode: TDOMNode; const Path: DOMString; const AValue: String);
var
Node: TDOMNode;
begin
Node := FindNode(RootNode, Path, True);
Node.TextContent := UTF8ToUTF16(AValue);
end;
procedure TXmlConfig.SetValue(const RootNode: TDOMNode; const Path: DOMString; const AValue: Boolean);
begin
SetValue(RootNode, Path, BoolStrings[AValue]);
end;
procedure TXmlConfig.SetValue(const RootNode: TDOMNode; const Path: DOMString; const AValue: Integer);
begin
SetValue(RootNode, Path, IntToStr(AValue));
end;
procedure TXmlConfig.SetValue(const RootNode: TDOMNode; const Path: DOMString; const AValue: Int64);
begin
SetValue(RootNode, Path, IntToStr(AValue));
end;
procedure TXmlConfig.SetValue(const RootNode: TDOMNode; const Path: DOMString; const AValue: Double);
begin
SetValue(RootNode, Path, FloatToStr(AValue));
end;
// ----------------------------------------------------------------------------
procedure TXmlConfig.ReadFromFile(const AFilename: UTF8String);
var
FileStream: TStream;
TmpDoc: TXMLDocument;
begin
FileStream := TFileStreamEx.Create(AFilename, fmOpenRead or fmShareDenyWrite);
try
if FileStream.Size = 0 then
raise EXmlConfigEmpty.Create('');
ReadXMLFile(TmpDoc, FileStream, FilenameToURI(AFilename));
if TmpDoc.DocumentElement.NodeName <> ApplicationName then
raise EXMLReadError.Create('Root element is not <' + ApplicationName + '>.');
FDoc.Free;
FDoc := TmpDoc;
finally
FileStream.Free;
end;
end;
procedure TXmlConfig.ReadFromStream(AStream: TStream);
var
TmpDoc: TXMLDocument;
begin
if AStream.Size = 0 then
raise EXmlConfigEmpty.Create('');
ReadXMLFile(TmpDoc, AStream);
FDoc.Free;
FDoc := TmpDoc;
end;
procedure TXmlConfig.WriteToFile(const AFilename: UTF8String);
var
FileStream: TStream;
begin
FileStream := TFileStreamEx.Create(AFilename, fmCreate or fmShareDenyWrite);
try
WriteXMLFile(FDoc, FileStream);
finally
FileStream.Free;
end;
end;
procedure TXmlConfig.WriteToStream(AStream: TStream);
begin
WriteXMLFile(FDoc, AStream);
end;
function TXmlConfig.Load: Boolean;
begin
Result := False;
if FFileName = '' then
Exit;
if not mbFileExists(FileName) then
raise EXmlConfigNotFound.Create('');
if not mbFileAccess(FileName, fmOpenRead or fmShareDenyWrite) then
raise EFOpenError.Create(SysErrorMessage(GetLastOSError));
ReadFromFile(FileName);
Result := True;
end;
function TXmlConfig.LoadBypassingErrors: Boolean;
var
ErrMsg: String;
begin
try
Result := Load;
except
on e: Exception do
begin
ErrMsg := 'Error loading configuration file ' + FileName;
if e.Message <> EmptyStr then
ErrMsg := ErrMsg + ': ' + e.Message;
DebugLogger.DebugLn(ErrMsg);
Result := False;
end;
end;
end;
function TXmlConfig.Save: Boolean;
var
sTmpConfigFileName: String;
begin
Result := False;
if FFileName = '' then
Exit;
// Write to temporary file and if successfully written rename to proper name.
if (not mbFileExists(FileName)) or mbFileAccess(FileName, fmOpenWrite or fmShareDenyWrite) then
begin
sTmpConfigFileName := GetTempName(FileName);
try
WriteToFile(sTmpConfigFileName);
if not mbRenameFile(sTmpConfigFileName, FileName) then
begin
mbDeleteFile(sTmpConfigFileName);
DebugLogger.Debugln('Cannot save configuration file ', FileName);
end
else
Result := True;
except
on e: EStreamError do
begin
mbDeleteFile(sTmpConfigFileName);
DebugLogger.Debugln('Error saving configuration file ', FileName, ': ' + e.Message);
end;
end;
end
else
begin
DebugLogger.Debugln('Cannot save configuration file ', FileName, ' - check permissions');
end;
end;
procedure TXmlConfig.SplitPathToNodeAndAttr(const Path: DOMString; out NodePath: DOMString; out AttrName: DOMString);
var
AttrSepPos: Integer;
begin
// Last part of the path is the attr name.
AttrSepPos := Length(Path);
while (AttrSepPos > 0) and (Path[AttrSepPos] <> '/') do
Dec(AttrSepPos);
if (AttrSepPos = 0) or (AttrSepPos = Length(Path)) then
begin
NodePath := EmptyWideStr;
AttrName := Path;
end
else
begin
NodePath := Copy(Path, 1, AttrSepPos - 1);
AttrName := Copy(Path, AttrSepPos + 1, Length(Path) - AttrSepPos);
end;
end;
function TXmlConfig.AddNode(const RootNode: TDOMNode; const ValueName: DOMString): TDOMNode;
begin
Result := RootNode.AppendChild(FDoc.CreateElement(ValueName));
end;
procedure TXmlConfig.DeleteNode(const RootNode: TDOMNode; const Path: DOMString);
begin
DeleteNode(FindNode(RootNode, Path, False));
end;
procedure TXmlConfig.DeleteNode(const Node: TDOMNode);
begin
if Assigned(Node) and Assigned(Node.ParentNode) then
Node.ParentNode.DetachChild(Node);
end;
procedure TXmlConfig.ClearNode(const Node: TDOMNode);
var
Attr: TDOMAttr;
begin
while Assigned(Node.FirstChild) do
Node.RemoveChild(Node.FirstChild);
if Node.HasAttributes then
begin
Attr := TDOMAttr(Node.Attributes[0]);
while Assigned(Attr) do
begin
TDOMElement(Node).RemoveAttributeNode(Attr);
Attr := TDOMAttr(Attr.NextSibling);
end;
end;
end;
function TXmlConfig.FindNode(const RootNode: TDOMNode; const Path: DOMString; bCreate: Boolean = False): TDOMNode;
var
StartPos, EndPos: Integer;
PathLen: Integer;
Child: TDOMNode;
function CompareDOMStrings(const s1, s2: DOMPChar; l1, l2: integer): integer;
var i: integer;
begin
Result:=l1-l2;
i:=0;
while (i<l1) and (Result=0) do begin
Result:=ord(s1[i])-ord(s2[i]);
inc(i);
end;
end;
begin
Result := RootNode;
PathLen := Length(Path);
if PathLen = 0 then
Exit;
StartPos := 1;
while Assigned(Result) do
begin
EndPos := StartPos;
while (EndPos <= PathLen) and (Path[EndPos] <> '/') do
Inc(EndPos);
Child := Result.FirstChild;
while Assigned(Child) and not ((Child.NodeType = ELEMENT_NODE)
and (0 = CompareDOMStrings(DOMPChar(Child.NodeName), @Path[StartPos],
Length(Child.NodeName), EndPos-StartPos))) do
Child := Child.NextSibling;
if not Assigned(Child) and bCreate then
begin
Child := FDoc.CreateElementBuf(@Path[StartPos], EndPos-StartPos);
Result.AppendChild(Child);
end;
Result := Child;
StartPos := EndPos + 1;
if StartPos > PathLen then
Break;
end;
end;
function TXmlConfig.GetContent(const Node: TDOMNode): UTF8String;
begin
Result := UTF16ToUTF8(Node.TextContent);
end;
procedure TXmlConfig.SetContent(const Node: TDOMNode; const AValue: UTF8String);
begin
Node.TextContent := UTF8ToUTF16(AValue);
end;
function TXmlConfig.GetPathFromNode(aNode: TDOMNode): String;
begin
Result := aNode.NodeName;
aNode := aNode.ParentNode;
while Assigned(aNode) and (aNode <> RootNode) do
begin
Result := aNode.NodeName + '/' + Result;
aNode := aNode.ParentNode;
end;
end;
procedure TXmlConfig.GetFont(const aNode: TXmlNode; Path: TXmlPath;
out Name: UTF8String; out Size: Integer; out Style: Integer;
const DefName: UTF8String; const DefSize: Integer; const DefStyle: Integer);
begin
if Path <> '' then
Path := Path + '/';
Name := GetValue(aNode, Path + 'Name', DefName);
Size := GetValue(aNode, Path + 'Size', DefSize);
Style := GetValue(aNode, Path + 'Style', DefStyle);
end;
procedure TXmlConfig.SetFont(const aNode: TXmlNode; Path: TXmlPath;
const Name: UTF8String; const Size: Integer; const Style: Integer);
begin
if Path <> '' then
Path := Path + '/';
SetValue(aNode, Path + 'Name', Name);
SetValue(aNode, Path + 'Size', Size);
SetValue(aNode, Path + 'Style', Style);
end;
end.