123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747 |
- {$mode objfpc}
- {$h+}
- unit xmlreg;
- Interface
- uses
- sysutils,classes,dom,xmlread,xmlwrite;
- Type
- TDataType = (dtUnknown,dtDWORD,dtString,dtBinary);
- TDataInfo = record
- DataType : TDataType;
- DataSize : Integer;
- end;
- TKeyInfo = record
- SubKeys,
- SubKeyLen,
- Values,
- ValueLen,
- DataLen : Integer;
- FTime : TDateTime;
- end;
- TXmlRegistry = Class(TObject)
- Private
- FAutoFlush,
- FDirty : Boolean;
- FFileName : String;
- FRootKey : String;
- FDocument : TXMLDocument;
- FCurrentElement : TDomElement;
- FCurrentKey : String;
- Procedure SetFileName(Value : String);
- Protected
- Procedure LoadFromStream(S : TStream);
- Function NormalizeKey(KeyPath : String) : String;
- Procedure CreateEmptyDoc;
- Function FindKey (S : String) : TDomElement;
- Function FindSubKey (S : String; N : TDomElement) : TDomElement;
- Function CreateSubKey (S : String; N : TDomElement) : TDomElement;
- Function FindValueKey (S : String) : TDomElement;
- Function CreateValueKey (S : String) : TDomElement;
- Function BufToHex(Const Buf; Len : Integer) : String;
- Function hexToBuf(Const Str : String; Var Buf; Var Len : Integer ) : Integer;
- Procedure MaybeFlush;
- Property Document : TXMLDocument Read FDocument;
- Property Dirty : Boolean Read FDirty write FDirty;
- Public
- Constructor Create(AFileName : String);
- Function SetKey(KeyPath : String; AllowCreate : Boolean) : Boolean ;
- Procedure SetRootKey(Value : String);
- Function DeleteKey(KeyPath : String) : Boolean;
- Function CreateKey(KeyPath : String) : Boolean;
- Function GetValueSize(Name : String) : Integer;
- Function GetValueType(Name : String) : TDataType;
- Function GetValueInfo(Name : String; Var Info : TDataInfo) : Boolean;
- Function GetKeyInfo(Var Info : TKeyInfo) : Boolean;
- Function EnumSubKeys(List : TStrings) : Integer;
- Function EnumValues(List : TStrings) : Integer;
- Function KeyExists(KeyPath : String) : Boolean;
- Function ValueExists(ValueName : String) : Boolean;
- Function RenameValue(Const OldName,NewName : String) : Boolean;
- Function DeleteValue(S : String) : Boolean;
- Procedure Flush;
- Procedure Load;
- Function GetValueData(Name : String; Var DataType : TDataType; Var Data; Var DataSize : Integer) : Boolean;
- Function SetValueData(Name : String; DataType : TDataType; Const Data; DataSize : Integer) : Boolean;
- Property FileName : String Read FFileName Write SetFileName;
- Property RootKey : String Read FRootKey Write SetRootkey;
- Property AutoFlush : Boolean Read FAutoFlush Write FAutoFlush;
- end;
- // used Key types
- Const
- SXmlReg = 'XMLReg';
- SKey = 'Key';
- SValue = 'Value';
- SName = 'Name';
- SType = 'Type';
- SData = 'Data';
- Implementation
- Constructor TXmlRegistry.Create(AFileName : String);
- begin
- FFileName:=AFileName;
- FautoFlush:=True;
- If (AFileName<>'') then
- Load
- else
- CreateEmptyDoc;
- end;
- Procedure TXmlRegistry.SetFileName(Value : String);
- begin
- If Value<>FFileName then
- begin
- FFilename:=Value;
- Flush;
- end;
- end;
- Procedure TXmlRegistry.CreateEmptyDoc;
- Const
- template = '<?xml version="1.0" encoding="ISO8859-1"?>'+LineEnding+
- '<'+SXMLReg+'>'+LineEnding+
- '</'+SXMLReg+'>'+LineEnding;
- Var
- S : TStream;
- begin
- S:=TStringStream.Create(Template);
- S.Seek(0,soFromBeginning);
- Try
- LoadFromStream(S);
- Finally
- S.Free;
- end;
- end;
- Function TXmlRegistry.NormalizeKey(KeyPath : String) : String;
- Var
- L : Integer;
- begin
- Result:=StringReplace(KeyPath,'\','/',[rfReplaceAll]);
- L:=Length(Result);
- If (L>0) and (Result[L]<>'/') then
- Result:=Result+'/';
- end;
- Function TXmlRegistry.SetKey(KeyPath : String; AllowCreate : Boolean) : boolean;
- Var
- SubKey,ResultKey : String;
- P : Integer;
- Node,Node2 : TDomElement;
- begin
- Result:=(Length(KeyPath)>0);
- If Not Result then
- Exit;
- KeyPath:=NormalizeKey(KeyPath);
- If (KeyPath[1]<>'/') then
- begin
- Node:=FCurrentElement;
- Resultkey:=FCurrentKey;
- end
- else
- begin
- Delete(Keypath,1,1);
- Node:=FDocument.DocumentElement;
- If (FRootKey<>'') then
- KeyPath:=FRootKey+KeyPath;
- ResultKey:='';
- end;
- Result:=True;
- repeat
- P:=Pos('/',KeyPath);
- If (P<>0) then
- begin
- SubKey:=Copy(KeyPath,1,P-1);
- Delete(KeyPath,1,P);
- Node2:=FindSubKey(SubKey,Node);
- Result:=(Node2<>Nil);
- If Result then
- Node:=Node2
- else
- begin
- If AllowCreate then
- Begin
- Node2:=CreateSubKey(SubKey,Node);
- Result:=Node2<>Nil;
- If Result Then
- Node:=Node2;
- end;
- end;
- If Result then
- ResultKey:=ResultKey+SubKey+'/';
- end;
- Until (Not Result) or (Length(KeyPath)=0);
- If Result then
- begin
- FCurrentkey:=ResultKey;
- FCurrentElement:=Node;
- end;
- MaybeFlush;
- end;
- Procedure TXmlRegistry.SetRootKey(Value : String);
- begin
- FRootKey:=NormalizeKey(Value);
- If (Length(FRootKey)>1) and (FRootKey[1]='/') then
- Delete(FRootKey,1,1);
- FCurrentKey:='';
- FCurrentElement:=Nil;
- end;
- Function TXmlRegistry.DeleteKey(KeyPath : String) : Boolean;
- Var
- N : TDomElement;
- begin
- N:=FindKey(KeyPath);
- Result:=(N<>Nil);
- If Result then
- begin
- (N.ParentNode as TDomElement).RemoveChild(N);
- FDirty:=True;
- MaybeFlush;
- end;
- end;
- Function TXmlRegistry.CreateKey(KeyPath : String) : Boolean;
- Var
- SubKey : String;
- P : Integer;
- Node,Node2 : TDomElement;
- begin
- Result:=(Length(KeyPath)>0);
- If Not Result then
- Exit;
- KeyPath:=NormalizeKey(KeyPath);
- If (KeyPath[1]<>'/') then
- Node:=FCurrentElement
- else
- begin
- Delete(Keypath,1,1);
- Node:=FDocument.DocumentElement;
- If (FRootKey<>'') then
- KeyPath:=FRootKey+KeyPath;
- end;
- Result:=True;
- repeat
- P:=Pos('/',KeyPath);
- If (P<>0) then
- begin
- SubKey:=Copy(KeyPath,1,P-1);
- Delete(KeyPath,1,P);
- Node2:=FindSubKey(SubKey,Node);
- Result:=(Node2<>Nil);
- If Result then
- Node:=Node2
- else
- begin
- Node2:=CreateSubKey(SubKey,Node);
- Result:=Node2<>Nil;
- Node:=Node2
- end;
- end;
- Until (Not Result) or (Length(KeyPath)=0);
- MaybeFlush;
- end;
- Function TXmlRegistry.GetValueData(Name : String; Var DataType : TDataType; Var Data; Var DataSize : Integer) : Boolean;
- Type
- PCardinal = ^Cardinal;
- Var
- Node : TDomElement;
- DataNode : TDomNode;
- ND : Integer;
- Dt : TDataType;
- S : AnsiString;
- begin
- Node:=FindValueKey(Name);
- Result:=Node<>Nil;
- If Result then
- begin
- DataNode:=Node.FirstChild;
- Result:=(DataNode<>Nil) and (DataNode is TDomText);
- If Result then
- begin
- ND:=StrToIntDef(Node[Stype],0);
- Result:=ND<=Ord(High(TDataType));
- If Result then
- begin
- DataType:=TDataType(StrToIntDef(Node[Stype],0));
- Case DataType of
- dtDWORD : begin
- PCardinal(@Data)^:=StrToIntDef(DataNode.NodeValue,0);
- DataSize:=SizeOf(Cardinal);
- end;
- dtString : begin
- S:=DataNode.NodeValue; // Convert to ansistring
- DataSize:=Length(S);
- If (DataSize>0) then
- Move(S[1],Data,DataSize);
- end;
- dtBinary : begin
- DataSize:=Length(DataNode.NodeValue);
- If (DataSize>0) then
- HexToBuf(DataNode.NodeValue,Data,DataSize);
- end;
- end;
- end;
- end;
- end;
- end;
- Function TXmlRegistry.SetValueData(Name : String; DataType : TDataType; Const Data; DataSize : Integer) : Boolean;
- Type
- PCardinal = ^Cardinal;
- Var
- Node : TDomElement;
- DataNode : TDomNode;
- ND : Integer;
- Dt : TDataType;
- S : String;
- begin
- Node:=FindValueKey(Name);
- If Node=Nil then
- Node:=CreateValueKey(Name);
- Result:=(Node<>Nil);
- If Result then
- begin
- Node[SType]:=IntToStr(Ord(DataType));
- DataNode:=Node.FirstChild;
- Case DataType of
- dtDWORD : DataNode.NodeValue:=IntToStr(PCardinal(@Data)^);
- dtString : begin
- SetLength(S,DataSize);
- If (DataSize>0) then
- Move(Data,S[1],DataSize);
- DataNode.NodeValue:=S;
- end;
- dtBinary : begin
- S:=BufToHex(Data,DataSize);
- DataNode.NodeValue:=S;
- end;
- end;
- end;
- If Result then
- begin
- FDirty:=True;
- MaybeFlush;
- end;
- end;
- Function TXmlRegistry.FindSubKey (S : String; N : TDomElement) : TDomElement;
- Var
- Node : TDOMNode;
- begin
- Result:=Nil;
- If N<>Nil then
- begin
- Node:=N.FirstChild;
- While (Result=Nil) and (Assigned(Node)) do
- begin
- If (Node.NodeType=ELEMENT_NODE) and (Node.NodeName=SKey) then
- If CompareText(TDomElement(Node)[SName],S)=0 then
- Result:=TDomElement(Node);
- Node:=Node.NextSibling;
- end;
- end;
- end;
- Function TXmlRegistry.CreateSubKey (S : String; N : TDomElement) : TDomElement;
- begin
- Result:=FDocument.CreateElement(SKey);
- Result[SName]:=S;
- N.AppendChild(Result);
- FDirty:=True;
- end;
- Function TXmlRegistry.FindValueKey (S : String) : TDomElement;
- Var
- Node : TDOMNode;
- begin
- If FCurrentElement<>Nil then
- begin
- Node:=FCurrentElement.FirstChild;
- Result:=Nil;
- While (Result=Nil) and (Assigned(Node)) do
- begin
- If (Node.NodeType=ELEMENT_NODE) and (Node.NodeName=SValue) then
- If CompareText(TDomElement(Node)[SName],S)=0 then
- Result:=TDomElement(Node);
- Node:=Node.NextSibling;
- end;
- end;
- end;
- Function TXmlRegistry.CreateValueKey (S : String) : TDomElement;
- begin
- If Assigned(FCurrentElement) then
- begin
- Result:=FDocument.CreateElement(SValue);
- Result[SName]:=S;
- // textnode to hold the value;
- Result.AppendChild(FDocument.CreateTextNode(''));
- FCurrentElement.AppendChild(Result);
- FDirty:=True;
- end
- else
- Result:=Nil;
- end;
- Procedure TXMLregistry.MaybeFlush;
- begin
- If FAutoFlush then
- Flush;
- end;
- Procedure TXmlRegistry.Flush;
- Var
- S : TStream;
- begin
- If FDirty then
- begin
- S:=TFileStream.Create(FFileName,fmCreate);
- Try
- WriteXMLFile(FDocument,S);
- FDirty:=False;
- finally
- S.Free;
- end;
- end;
- end;
- Procedure TXmlRegistry.Load;
- Var
- S : TStream;
- begin
- If Not FileExists(FFileName) then
- CreateEmptyDoc
- else
- begin
- S:=TFileStream.Create(FFileName,fmOpenReadWrite);
- try
- LoadFromStream(S);
- finally
- S.Free;
- end;
- end;
- end;
- Procedure TXmlRegistry.LoadFromStream(S : TStream);
- begin
- If Assigned(FDocument) then
- begin
- FDocument.Free;
- FDocument:=Nil;
- end;
- ReadXMLFile(FDocument,S);
- if (FDocument=Nil) then
- CreateEmptyDoc;
- FCurrentElement:=Nil;
- FCurrentKey:='';
- FRootKey:='';
- FDirty:=False;
- end;
- Function TXmlRegistry.BufToHex(Const Buf; Len : Integer) : String;
- Var
- P : PByte;
- S : String;
- I : Integer;
- begin
- SetLength(Result,Len*2);
- P:=@Buf;
- For I:=0 to Len-1 do
- begin
- S:=HexStr(P[I],2);
- Move(S[1],Result[I*2+1],2);
- end;
- end;
- Function TXMLRegistry.hexToBuf(Const Str : String; Var Buf; Var Len : Integer ) : Integer;
- Var
- I : Integer;
- P : PByte;
- S : String;
- B : Byte;
- Code : Integer;
- begin
- P:=@Buf;
- Len:= Length(Str) div 2;
- For I:=0 to Len-1 do
- begin
- S:='$'+Copy(Str,(I*2)+1,2);
- Val(S,B,Code);
- If Code<>0 then
- begin
- Inc(Result);
- B:=0;
- end;
- P[I]:=B;
- end;
- end;
- Function TXMLRegistry.DeleteValue(S : String) : Boolean;
- Var
- N : TDomElement;
- begin
- N:=FindValueKey(S);
- Result:=(N<>Nil);
- If Result then
- begin
- FCurrentElement.RemoveChild(N);
- FDirty:=True;
- MaybeFlush;
- end;
- end;
- Function TXMLRegistry.GetValueSize(Name : String) : Integer;
- Var
- Info : TDataInfo;
- begin
- If GetValueInfo(Name,Info) then
- Result:=Info.DataSize
- else
- Result:=-1;
- end;
- Function TXMLRegistry.GetValueType(Name : String) : TDataType;
- Var
- Info : TDataInfo;
- begin
- If GetValueInfo(Name,Info) then
- Result:=Info.DataType
- else
- Result:=dtUnknown;
- end;
- Function TXMLRegistry.GetValueInfo(Name : String; Var Info : TDataInfo) : Boolean;
- Var
- N : TDomElement;
- DN : TDomNode;
- begin
- N:=FindValueKey(Name);
- Result:=(N<>Nil);
- If Result then
- begin
- DN:=N.FirstChild;
- Result:=DN<>Nil;
- If Result then
- With Info do
- begin
- DataType:=TDataType(StrToIntDef(N[SType],0));
- Case DataType of
- dtUnknown : DataSize:=0;
- dtDword : Datasize:=SizeOf(Cardinal);
- dtString : DataSize:=Length(DN.NodeValue);
- dtBinary : DataSize:=Length(DN.NodeValue) div 2;
- end;
- end;
- end;
- end;
- Function TXMLRegistry.GetKeyInfo(Var Info : TKeyInfo) : Boolean;
- Var
- Node,DataNode : TDOMNode;
- L : Integer;
- begin
- FillChar(Info,SizeOf(Info),0);
- Result:=FCurrentElement<>Nil;
- If Result then
- With Info do
- begin
- If (FFileName<>'') Then
- FTime:=FileAge(FFileName);
- Node:=FCurrentElement.FirstChild;
- While Assigned(Node) do
- begin
- If (Node.NodeType=ELEMENT_NODE) then
- If (Node.NodeName=SKey) then
- begin
- Inc(SubKeys);
- L:=Length(TDomElement(Node)[SName]);
- If (L>SubKeyLen) then
- SubKeyLen:=L;
- end
- else if (Node.NodeName=SValue) then
- begin
- Inc(Values);
- L:=Length(TDomElement(Node)[SName]);
- If (L>ValueLen) then
- ValueLen:=L;
- DataNode:=TDomElement(Node).FirstChild;
- If (DataNode<>Nil) and (DataNode is TDomText) then
- Case TDataType(StrToIntDef(TDomElement(Node)[SType],0)) of
- dtUnknown : L:=0;
- dtDWord : L:=4;
- DtString : L:=Length(DataNode.NodeValue);
- dtBinary : L:=Length(DataNode.NodeValue) div 2;
- end
- else
- L:=0;
- If (L>DataLen) Then
- DataLen:=L;
- end;
- Node:=Node.NextSibling;
- end;
- end;
- end;
- Function TXMLRegistry.EnumSubKeys(List : TStrings) : Integer;
- Var
- Node : TDOMNode;
- begin
- List.Clear;
- Result:=0;
- If FCurrentElement<>Nil then
- begin
- Node:=FCurrentElement.FirstChild;
- While Assigned(Node) do
- begin
- If (Node.NodeType=ELEMENT_NODE) and (Node.NodeName=SKey) then
- List.Add(TDomElement(Node)[SName]);
- Node:=Node.NextSibling;
- end;
- Result:=List.Count;
- end;
- end;
- Function TXMLRegistry.EnumValues(List : TStrings) : Integer;
- Var
- Node : TDOMNode;
- begin
- List.Clear;
- Result:=0;
- If FCurrentElement<>Nil then
- begin
- Node:=FCurrentElement.FirstChild;
- While Assigned(Node) do
- begin
- If (Node.NodeType=ELEMENT_NODE) and (Node.NodeName=SValue) then
- List.Add(TDomElement(Node)[SName]);
- Node:=Node.NextSibling;
- end;
- Result:=List.Count;
- end;
- end;
- Function TXMLRegistry.KeyExists(KeyPath : String) : Boolean;
- begin
- Result:=FindKey(KeyPath)<>Nil;
- end;
- Function TXMLRegistry.RenameValue(Const OldName,NewName : String) : Boolean;
- Var
- N : TDomElement;
- begin
- N:=FindValueKey(OldName);
- If (N<>Nil) then
- begin
- N[SName]:=NewName;
- FDirty:=True;
- MaybeFlush;
- end;
- end;
- Function TXMLRegistry.FindKey (S : String) : TDomElement;
- Var
- SubKey : String;
- P : Integer;
- Node : TDomElement;
- begin
- Result:=Nil;
- If (Length(S)=0) then
- Exit;
- S:=NormalizeKey(S);
- If (S[1]<>'/') then
- Node:=FCurrentElement
- else
- begin
- Delete(S,1,1);
- Node:=FDocument.DocumentElement;
- If (FRootKey<>'') then
- S:=FRootKey+S;
- end;
- repeat
- P:=Pos('/',S);
- If (P<>0) then
- begin
- SubKey:=Copy(S,1,P-1);
- Delete(S,1,P);
- Result:=FindSubKey(SubKey,Node);
- Node:=Result;
- end;
- Until (Result=Nil) or (Length(S)=0);
- end;
- Function TXmlRegistry.ValueExists(ValueName : String) : Boolean;
- begin
- Result:=FindValueKey(ValueName)<>Nil;
- end;
- end.
|