📄 winskinini.pas
字号:
unit WinSkinIni;
{$B-}
interface
uses Classes,winconvert;
type
{ TQuickIni class }
TQuickIni = class(TObject)
private
FAuto : boolean;
FFileName: String;
FIniFile : TStrings;
function GetName(const Line: String): String;
function GetValue(const Line, Name: String): String;
function GetSectionIndex(const Section: String): Integer;
function IsSection(const Line: String): Boolean;
procedure SetFileName(Value: string);
procedure SetIniFile(Value: TStrings);
protected
FSections: TStrings;
procedure Compress(source,dest:TStream);
procedure Decompress(source,Dest:TStream);
public
constructor Create;
destructor Destroy; override;
procedure LoadFromFile(aname:string);
procedure SaveToFile(aname:string);
procedure LoadFromStream(Stream: TStream);
procedure SaveToStream(Stream:Tstream);
procedure LoadFromZip(aname:string);
procedure SavetoZip(aname:string);
procedure DeleteKey(const Section, Ident: String);
procedure EraseSection(const Section: String);
function ReadBool(const Section, Ident: String; Default: Boolean): Boolean;
function ReadInteger(const Section, Ident: String; Default: Longint): Longint;
procedure ReadSection(const Section: String; Strings: TStrings);
procedure ReadSections(Strings: TStrings);
procedure ReadSectionValues(const Section: String; Strings: TStrings);
function ReadString(const Section, Ident: String; Default: String): String;
procedure RebuildSections;
procedure WriteBool(const Section, Ident: String; Value: Boolean);
procedure WriteInteger(const Section, Ident: String; Value: Longint);
procedure WriteString(const Section, Ident: String; Value: String);
property FileName: String read FFileName write SetFileName;
property AutoSaveLoad: boolean read FAuto write FAuto;
property IniFile: TStrings read FIniFile write SetIniFile;
procedure Clear;
end;
implementation
uses SysUtils;
const
SStringsUnassignedError = 'The parameter Strings is unassigned!';
StartBracket = '[';
EndBracket = ']';
Separator = '=';
{ TQuickIni }
constructor TQuickIni.Create;
begin
FAuto := False;
FIniFile := TStringList.Create;
FSections := TStringList.Create;
// if FileExists(FileName) then
// LoadFromFile;
end;
destructor TQuickIni.Destroy;
begin
FSections.Free;
FIniFile.Free;
// Finalize(FFileName);
end;
function TQuickIni.GetName(const Line: String): String;
var
I: Integer;
begin
I := Pos(Separator, Line);
if I <> 0 then
Result := Trim(Copy(Line, 1, I-1))
else
Result := EmptyStr;
result:=lowercase(result);
end;
function TQuickIni.GetValue(const Line, Name: String): String;
var
I: Integer;
begin
Result := EmptyStr;
if (Line <> EmptyStr) and (Name <> EmptyStr) then
begin
I := Pos(Separator, Line);
if (Name = GetName(Line)) and (I <> 0) then
Result := Trim(System.Copy(Line, I+1, Maxint));
end;
end;
function TQuickIni.IsSection(const Line: String): Boolean;
var
S: String;
begin
Result := False;
if Line <> EmptyStr then
begin
S := Trim(Line);
if (S[1] = StartBracket) and (S[System.Length(S)] = EndBracket) then
Result := True;
end;
end;
function TQuickIni.GetSectionIndex(const Section: String): Integer;
begin
Result := FSections.IndexOf(StartBracket + Section + EndBracket);
if Result >= 0 then
Result := Integer(FSections.Objects[Result])
else
Result := -1;
end;
procedure TQuickIni.Decompress(source,Dest:TStream);
var
LZH: TLZH;
Size, Bytes: Longint;
begin
// Decompress in memory blob.
LZH := TLZH.Create;
try
LZH.StreamIn:= source;
LZH.StreamOut:=dest;
LZH.StreamIn.Position := 0;
LZH.StreamOut.Position := 0;
// Uncompressed file size
LZH.StreamIn.Read(size, sizeof(Longint));
Bytes := Size;
// Decompress rest of stream.
LZH.LZHUnpack(Bytes, LZH.GetBlockStream, LZH.PutBlockStream);
finally
LZH.Free;
end;
end;
procedure TQuickIni.compress(source,dest:TStream);
var
LZH: TLZH;
Size, Bytes: Longint;
begin
// Decompress in memory blob.
LZH := TLZH.Create;
try
LZH.StreamIn := Source;
LZH.StreamOut := dest;
LZH.StreamIn.Position := 0;
LZH.StreamOut.Position := 0;
//write uncompressed size
Size := LZH.StreamIn.Size;
LZH.StreamOut.Write(Size, sizeof(Longint));
// Compress stream.
LZH.LZHPack(Bytes, LZH.GetBlockStream, LZH.PutBlockStream);
finally
LZH.Free;
end;
end;
procedure TQuickIni.LoadFromZip(aname:string);
var
r,r2: TMemoryStream;
begin
r:=Tmemorystream.create;
r2:=Tmemorystream.create;
try
r2.loadfromfile(aname);
Decompress(r2,r);
r.Seek(0,soFromBeginning);
loadfromstream(r);
finally
r.free;
r2.free;
end;
end;
procedure TQuickIni.SavetoZip(aname:string);
var
m,m2: TMemoryStream;
begin
m:=Tmemorystream.create;
m2:=Tmemorystream.create;
try
savetostream(m);
compress(m,m2);
m2.savetofile(aname);
finally
m.free;
m2.free;
end;
end;
procedure TQuickIni.LoadFromFile(aname:string);
var
Stream: TStream;
Ptr, Start: PChar;
StmStr,Str: string;
Size : integer;
I : integer;
begin
Stream := TFileStream.Create(aname, fmOpenRead or fmShareDenyWrite);
LoadFromStream(Stream);
Stream.Free;
end;
procedure TQuickIni.LoadFromStream(Stream: TStream);
var
Ptr, Start: PChar;
StmStr,Str: string;
Size : integer;
I : integer;
begin
if not assigned(Stream) then exit;
FIniFile.BeginUpdate;
FSections.BeginUpdate;
try
Size := Stream.Size - Stream.Position;
SetString(StmStr, nil, Size);
Stream.Read(Pointer(StmStr)^, Size);
FIniFile.Clear;
FSections.Clear;
Ptr := Pointer(StmStr);
I := 0;
if Ptr <> nil then
while Ptr^ <> #0 do
begin
Start := Ptr;
while not (Ptr^ in [#0, #10, #13]) do
Inc(Ptr);
SetString(Str, Start, Ptr - Start);
Str := Trim(Str);
if (Str <> '') and (Str[1] <> ';') then
begin
FIniFile.Add(Str);
if (Str[1] = '[') and (Str[Length(Str)] = ']') then
begin
FSections.AddObject(Trim(Str),TObject(I));
end;
inc(I);
end;
if Ptr^ = #13 then Inc(Ptr);
if Ptr^ = #10 then Inc(Ptr);
end;
finally
FSections.EndUpdate;
FIniFile.EndUpdate;
end;
end;
procedure TQuickIni.SaveToFile(aname:string);
begin
// if AutoSaveLoad then
FIniFile.SaveToFile(aname);
end;
procedure TQuickIni.SaveToStream(Stream:Tstream);
begin
// if AutoSaveLoad then
if assigned(stream) then
FIniFile.SaveTostream(stream);
end;
{ Read all Names of one Section }
procedure TQuickIni.ReadSection(const Section: String; Strings: TStrings);
var
I: Integer;
N: String;
begin
Assert(Assigned(Strings), SStringsUnassignedError);
Strings.BeginUpdate;
try
Strings.Clear;
if FIniFile.Count > 0 then
begin
I := GetSectionIndex(Section);
if I <> -1 then
begin
Inc(I);
while (I < FIniFile.Count) and not IsSection(FIniFile[I]) do
begin
N := GetName(FIniFile[I]);
if N <> EmptyStr then Strings.Add(N);
Inc(I);
end;
end;
end;
finally
Strings.EndUpdate;
end;
end;
{ Read all Sections of the Ini-File }
procedure TQuickIni.ReadSections(Strings: TStrings);
var
I: Integer;
Section: String;
begin
Assert(Assigned(Strings), SStringsUnassignedError);
Strings.Assign(FSections);
I := 0;
while I < Strings.Count do
begin
Strings.Objects[I] := Nil;
Section := Trim(Strings.Strings[I]);
System.Delete(Section, 1, 1);
System.Delete(Section, System.Length(Section), 1);
Strings.Strings[I] := Trim(Section);
Inc(I);
end;
end;
{ Reads a String-Value of Ident in one Section.
The result is Default if
o Section doesn't exists
o Ident doesn't exists
o Ident doesn't have any assigned value }
function TQuickIni.ReadString(const Section, Ident: String; Default: String): String;
var
I: Integer;
V,s: String;
begin
Result := Default;
s:=lowercase(ident);
if FIniFile.Count > 0 then
begin
I := GetSectionIndex(Section);
if I <> -1 then
begin
Inc(I);
while (I < FIniFile.Count) and not IsSection(FIniFile[I]) do
begin
if GetName(FIniFile[I]) = s then
begin
V := GetValue(FIniFile[I], s);
if V <> EmptyStr then
Result := V;
break;
end;
Inc(I);
end;
end;
end;
end;
{ Reads an Integer-Value of Ident in one Section }
function TQuickIni.ReadInteger(const Section, Ident: String; Default: Longint): Longint;
var
IntStr: string;
begin
IntStr := ReadString(Section, Ident, '');
// convert a Hex-Value
if (Length(IntStr) > 2) and (IntStr[1] = '0') and ((IntStr[2] = 'X') or (IntStr[2] = 'x')) then
IntStr := '$' + System.Copy(IntStr, 3, Maxint);
Result := StrToIntDef(IntStr, Default);
end;
{ Reads a Bool-Value of Ident in one Section }
function TQuickIni.ReadBool(const Section, Ident: String; Default: Boolean): Boolean;
begin
Result := ReadInteger(Section, Ident, Ord(Default)) <> 0;
end;
{ Reads all Names + Values of one Section }
procedure TQuickIni.ReadSectionValues(const Section: String; Strings: TStrings);
var
I: Integer;
begin
Assert(Assigned(Strings), SStringsUnassignedError);
Strings.BeginUpdate;
try
Strings.Clear;
if FIniFile.Count > 0 then
begin
I := GetSectionIndex(Section);
if I <> -1 then
begin
Inc(I);
while (I < FIniFile.Count) and not IsSection(FIniFile[I]) do
begin
if (FIniFile[I] <> '') then
Strings.Add(FIniFile[I]);
Inc(I);
end;
end;
end;
finally
Strings.EndUpdate;
end;
end;
{ Writes a String-Value for Ident in one Section.
Note: If Section and/or Ident don't exist, they will be placed in the Ini-File }
procedure TQuickIni.WriteString(const Section, Ident: String; Value: String);
var
I: Integer;
Q : integer;
s:string;
begin
I := GetSectionIndex(Section);
s:=lowercase(ident);
// Section exists
if I >= 0 then
begin
Inc(I);
while (I < FIniFile.Count) and not IsSection(FIniFile[I])
and (GetName(FIniFile[I]) <> s) do
begin
Inc(I);
end;
// End of File or Ident doesn't exists in the Section
if (I >= FIniFile.Count) then
begin
if Ident <> EmptyStr then
begin
FIniFile.Add(Ident + Separator + Value);
end
end
else if (I < FIniFile.Count) and IsSection(FIniFile[I]) then
begin
if Ident <> EmptyStr then
begin
FIniFile.Insert(I,Ident + Separator + Value);
Inc(I);
Q := FSections.IndexOf(FIniFile[I]);
FSections.Objects[Q] := TObject(I+1);
end
end
// Ident does exists in the section
else if Ident <> EmptyStr then
begin
FIniFile[I] := Ident + Separator + Value;
end;
end
// Section doesn't exists, so add new [Section] with Ident=Value
else
begin
I := FIniFile.Add(StartBracket + Section + EndBracket);
FSections.AddObject(StartBracket + Section + EndBracket,TObject(I));
if Ident <> EmptyStr then
begin
FIniFile.Add(Ident + Separator + Value);
end;
end;
// SaveToFile;
end;
{ Writes an Integer-Value for Ident in one Section }
procedure TQuickIni.WriteInteger(const Section, Ident: String; Value: Longint);
begin
WriteString(Section, Ident, IntToStr(Value));
end;
{ Writes a Bool-Value for Ident in one Section }
procedure TQuickIni.WriteBool(const Section, Ident: String; Value: Boolean);
const
Values: array[Boolean] of string = ('0', '1');
begin
WriteString(Section, Ident, Values[Value]);
end;
{ Deletes the Value of Ident in one Section.
Note: Only if Section and Ident exist, the Value of Ident will be set to NULL }
procedure TQuickIni.DeleteKey(const Section, Ident: String);
var
I: Integer;
begin
I := GetSectionIndex(Section);
if I <> -1 then
begin
Inc(I);
while (I < FIniFile.Count) and not IsSection(FIniFile[I]) and
(GetName(FIniFile[I]) <> Ident) do Inc(I);
// Ident does exists
if not (I >= FIniFile.Count) and not IsSection(FIniFile[I]) then
begin
FIniFile.Delete(I);
// SaveToFile;
end;
end;
end;
procedure TQuickIni.EraseSection(const Section: String);
var
I: Integer;
begin
I := GetSectionIndex(Section);
if I <> -1 then
begin
// Delete Section-Header
FIniFile.Delete(I);
// Delete Section-Items
while (I < FIniFile.Count) and not IsSection(FIniFile[I]) do
FIniFile.Delete(I);
if I > 0 then FIniFile.Insert(I, EmptyStr);
// SaveToFile;
end;
end;
procedure TQuickIni.SetFileName(Value: string);
begin
if Value <> FFileName then
begin
FFileName := Value;
// if FileExists(Value) and FAuto then
// LoadFromFile;
end;
end;
procedure TQuickIni.SetIniFile(Value: TStrings);
begin
FIniFile.Assign(Value);
RebuildSections;
end;
procedure TQuickIni.RebuildSections;
Var
I : integer;
Count : integer;
begin
FSections.Clear;
I := 0;
Count := FIniFile.Count;
while I < Count do
begin
if (FIniFile[I] <> '') and (FIniFile[I][1] = '[') and (FIniFile[I][Length(FIniFile[I])] = ']') then
begin
if assigned(FSections) then
FSections.AddObject(Trim(FIniFile[I]),TObject(I));
end;
inc(I);
end;
end;
procedure TQuickIni.Clear;
begin
FIniFile.Clear;
FSections.Clear;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -