home *** CD-ROM | disk | FTP | other *** search
/ Delphi Anthology / aDELPHI.iso / Runimage / Delphi50 / Source / Vcl / inifiles.pas < prev    next >
Pascal/Delphi Source File  |  1999-08-11  |  15KB  |  561 lines

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Borland Delphi Visual Component Library         }
  5. {                                                       }
  6. {       Copyright (c) 1995,99 Inprise Corporation       }
  7. {                                                       }
  8. {*******************************************************}
  9.  
  10. unit IniFiles;
  11.  
  12. {$R-,T-,H+,X+}
  13.  
  14. interface
  15.  
  16. uses Windows, SysUtils, Classes;
  17.  
  18. type
  19.   TCustomIniFile = class(TObject)
  20.   private
  21.     FFileName: string;
  22.   public
  23.     constructor Create(const FileName: string);
  24.     function SectionExists(const Section: string): Boolean;
  25.     function ReadString(const Section, Ident, Default: string): string; virtual; abstract;
  26.     procedure WriteString(const Section, Ident, Value: String); virtual; abstract;
  27.     function ReadInteger(const Section, Ident: string; Default: Longint): Longint; virtual;
  28.     procedure WriteInteger(const Section, Ident: string; Value: Longint); virtual;
  29.     function ReadBool(const Section, Ident: string; Default: Boolean): Boolean; virtual;
  30.     procedure WriteBool(const Section, Ident: string; Value: Boolean); virtual;
  31.     function ReadDate(const Section, Name: string; Default: TDateTime): TDateTime; virtual;
  32.     function ReadDateTime(const Section, Name: string; Default: TDateTime): TDateTime; virtual;
  33.     function ReadFloat(const Section, Name: string; Default: Double): Double; virtual;
  34.     function ReadTime(const Section, Name: string; Default: TDateTime): TDateTime; virtual;
  35.     procedure WriteDate(const Section, Name: string; Value: TDateTime); virtual;
  36.     procedure WriteDateTime(const Section, Name: string; Value: TDateTime); virtual;
  37.     procedure WriteFloat(const Section, Name: string; Value: Double); virtual;
  38.     procedure WriteTime(const Section, Name: string; Value: TDateTime); virtual;
  39.     procedure ReadSection(const Section: string; Strings: TStrings); virtual; abstract;
  40.     procedure ReadSections(Strings: TStrings); virtual; abstract;
  41.     procedure ReadSectionValues(const Section: string; Strings: TStrings); virtual; abstract;
  42.     procedure EraseSection(const Section: string); virtual; abstract;
  43.     procedure DeleteKey(const Section, Ident: String); virtual; abstract;
  44.     procedure UpdateFile; virtual; abstract;
  45.     function ValueExists(const Section, Ident: string): Boolean;
  46.     property FileName: string read FFileName;
  47.   end;
  48.  
  49.   { TIniFile - Encapsulates the Windows INI file interface
  50.     (Get/SetPrivateProfileXXX functions) }
  51.  
  52.   TIniFile = class(TCustomIniFile)
  53.   public
  54.     function ReadString(const Section, Ident, Default: string): string; override;
  55.     procedure WriteString(const Section, Ident, Value: String); override;
  56.     procedure ReadSection(const Section: string; Strings: TStrings); override;
  57.     procedure ReadSections(Strings: TStrings); override;
  58.     procedure ReadSectionValues(const Section: string; Strings: TStrings); override;
  59.     procedure EraseSection(const Section: string); override;
  60.     procedure DeleteKey(const Section, Ident: String); override;
  61.     procedure UpdateFile; override;
  62.   end;
  63.  
  64.   { TMemIniFile - loads and entire ini file into memory and allows all
  65.     operations to be performed on the memory image.  The image can then
  66.     be written out to the disk file }
  67.  
  68.   TMemIniFile = class(TCustomIniFile)
  69.   private
  70.     FSections: TStringList;
  71.     function AddSection(const Section: string): TStrings;
  72.     procedure LoadValues;
  73.   public
  74.     constructor Create(const FileName: string);
  75.     destructor Destroy; override;
  76.     procedure Clear;
  77.     procedure DeleteKey(const Section, Ident: String); override;
  78.     procedure EraseSection(const Section: string); override;
  79.     procedure GetStrings(List: TStrings);
  80.     procedure ReadSection(const Section: string; Strings: TStrings); override;
  81.     procedure ReadSections(Strings: TStrings); override;
  82.     procedure ReadSectionValues(const Section: string; Strings: TStrings); override;
  83.     function ReadString(const Section, Ident, Default: string): string; override;
  84.     procedure Rename(const FileName: string; Reload: Boolean);
  85.     procedure SetStrings(List: TStrings);
  86.     procedure UpdateFile; override;
  87.     procedure WriteString(const Section, Ident, Value: String); override;
  88.   end;
  89.  
  90. implementation
  91.  
  92. uses Consts;
  93.  
  94. { TCustomIniFile }
  95.  
  96. constructor TCustomIniFile.Create(const FileName: string);
  97. begin
  98.   FFileName := FileName;
  99. end;
  100.  
  101. function TCustomIniFile.SectionExists(const Section: string): Boolean;
  102. var
  103.   S: TStrings;
  104. begin
  105.   S := TStringList.Create;
  106.   try
  107.     ReadSection(Section, S);
  108.     Result := S.Count > 0;
  109.   finally
  110.     S.Free;
  111.   end;
  112. end;
  113.  
  114. function TCustomIniFile.ReadInteger(const Section, Ident: string;
  115.   Default: Longint): Longint;
  116. var
  117.   IntStr: string;
  118. begin
  119.   IntStr := ReadString(Section, Ident, '');
  120.   if (Length(IntStr) > 2) and (IntStr[1] = '0') and
  121.     ((IntStr[2] = 'X') or (IntStr[2] = 'x')) then
  122.     IntStr := '$' + Copy(IntStr, 3, Maxint);
  123.   Result := StrToIntDef(IntStr, Default);
  124. end;
  125.  
  126. procedure TCustomIniFile.WriteInteger(const Section, Ident: string; Value: Longint);
  127. begin
  128.   WriteString(Section, Ident, IntToStr(Value));
  129. end;
  130.  
  131. function TCustomIniFile.ReadBool(const Section, Ident: string;
  132.   Default: Boolean): Boolean;
  133. begin
  134.   Result := ReadInteger(Section, Ident, Ord(Default)) <> 0;
  135. end;
  136.  
  137. function TCustomIniFile.ReadDate(const Section, Name: string; Default: TDateTime): TDateTime;
  138. var
  139.   DateStr: string;
  140. begin
  141.   DateStr := ReadString(Section, Name, '');
  142.   Result := Default;
  143.   if DateStr <> '' then
  144.   try
  145.     Result := StrToDate(DateStr);
  146.   except
  147.     on EConvertError do
  148.     else raise;
  149.   end;
  150. end;
  151.  
  152. function TCustomIniFile.ReadDateTime(const Section, Name: string; Default: TDateTime): TDateTime;
  153. var
  154.   DateStr: string;
  155. begin
  156.   DateStr := ReadString(Section, Name, '');
  157.   Result := Default;
  158.   if DateStr <> '' then
  159.   try
  160.     Result := StrToDateTime(DateStr);
  161.   except
  162.     on EConvertError do
  163.     else raise;
  164.   end;
  165. end;
  166.  
  167. function TCustomIniFile.ReadFloat(const Section, Name: string; Default: Double): Double;
  168. var
  169.   FloatStr: string;
  170. begin
  171.   FloatStr := ReadString(Section, Name, '');
  172.   Result := Default;
  173.   if FloatStr <> '' then
  174.   try
  175.     Result := StrToFloat(FloatStr);
  176.   except
  177.     on EConvertError do
  178.     else raise;
  179.   end;
  180. end;
  181.  
  182. function TCustomIniFile.ReadTime(const Section, Name: string; Default: TDateTime): TDateTime;
  183. var
  184.   TimeStr: string;
  185. begin
  186.   TimeStr := ReadString(Section, Name, '');
  187.   Result := Default;
  188.   if TimeStr <> '' then
  189.   try
  190.     Result := StrToTime(TimeStr);
  191.   except
  192.     on EConvertError do
  193.     else raise;
  194.   end;
  195. end;
  196.  
  197. procedure TCustomIniFile.WriteDate(const Section, Name: string; Value: TDateTime);
  198. begin
  199.   WriteString(Section, Name, DateToStr(Value));
  200. end;
  201.  
  202. procedure TCustomIniFile.WriteDateTime(const Section, Name: string; Value: TDateTime);
  203. begin
  204.   WriteString(Section, Name, DateTimeToStr(Value));
  205. end;
  206.  
  207. procedure TCustomIniFile.WriteFloat(const Section, Name: string; Value: Double);
  208. begin
  209.   WriteString(Section, Name, FloatToStr(Value));
  210. end;
  211.  
  212. procedure TCustomIniFile.WriteTime(const Section, Name: string; Value: TDateTime);
  213. begin
  214.   WriteString(Section, Name, TimeToStr(Value));
  215. end;
  216.  
  217. procedure TCustomIniFile.WriteBool(const Section, Ident: string; Value: Boolean);
  218. const
  219.   Values: array[Boolean] of string = ('0', '1');
  220. begin
  221.   WriteString(Section, Ident, Values[Value]);
  222. end;
  223.  
  224. function TCustomIniFile.ValueExists(const Section, Ident: string): Boolean;
  225. var
  226.   S: TStrings;
  227. begin
  228.   S := TStringList.Create;
  229.   try
  230.     ReadSection(Section, S);
  231.     Result := S.IndexOf(Ident) > -1;
  232.   finally
  233.     S.Free;
  234.   end;
  235. end;
  236.  
  237. { TIniFile }
  238.  
  239. function TIniFile.ReadString(const Section, Ident, Default: string): string;
  240. var
  241.   Buffer: array[0..2047] of Char;
  242. begin
  243.   SetString(Result, Buffer, GetPrivateProfileString(PChar(Section),
  244.     PChar(Ident), PChar(Default), Buffer, SizeOf(Buffer), PChar(FFileName)));
  245. end;
  246.  
  247. procedure TIniFile.WriteString(const Section, Ident, Value: string);
  248. begin
  249.   if not WritePrivateProfileString(PChar(Section), PChar(Ident),
  250.     PChar(Value), PChar(FFileName)) then
  251.     raise Exception.CreateResFmt(@SIniFileWriteError, [FileName]);
  252. end;
  253.  
  254. procedure TIniFile.ReadSections(Strings: TStrings);
  255. const
  256.   BufSize = 16384;
  257. var
  258.   Buffer, P: PChar;
  259. begin
  260.   GetMem(Buffer, BufSize);
  261.   try
  262.     Strings.BeginUpdate;
  263.     try
  264.       Strings.Clear;
  265.       if GetPrivateProfileString(nil, nil, nil, Buffer, BufSize,
  266.         PChar(FFileName)) <> 0 then
  267.       begin
  268.         P := Buffer;
  269.         while P^ <> #0 do
  270.         begin
  271.           Strings.Add(P);
  272.           Inc(P, StrLen(P) + 1);
  273.         end;
  274.       end;
  275.     finally
  276.       Strings.EndUpdate;
  277.     end;
  278.   finally
  279.     FreeMem(Buffer, BufSize);
  280.   end;
  281. end;
  282.  
  283. procedure TIniFile.ReadSection(const Section: string; Strings: TStrings);
  284. const
  285.   BufSize = 16384;
  286. var
  287.   Buffer, P: PChar;
  288. begin
  289.   GetMem(Buffer, BufSize);
  290.   try
  291.     Strings.BeginUpdate;
  292.     try
  293.       Strings.Clear;
  294.       if GetPrivateProfileString(PChar(Section), nil, nil, Buffer, BufSize,
  295.         PChar(FFileName)) <> 0 then
  296.       begin
  297.         P := Buffer;
  298.         while P^ <> #0 do
  299.         begin
  300.           Strings.Add(P);
  301.           Inc(P, StrLen(P) + 1);
  302.         end;
  303.       end;
  304.     finally
  305.       Strings.EndUpdate;
  306.     end;
  307.   finally
  308.     FreeMem(Buffer, BufSize);
  309.   end;
  310. end;
  311.  
  312. procedure TIniFile.ReadSectionValues(const Section: string; Strings: TStrings);
  313. var
  314.   KeyList: TStringList;
  315.   I: Integer;
  316. begin
  317.   KeyList := TStringList.Create;
  318.   try
  319.     ReadSection(Section, KeyList);
  320.     Strings.BeginUpdate;
  321.     try
  322.       for I := 0 to KeyList.Count - 1 do
  323.         Strings.Values[KeyList[I]] := ReadString(Section, KeyList[I], '');
  324.     finally
  325.       Strings.EndUpdate;
  326.     end;
  327.   finally
  328.     KeyList.Free;
  329.   end;
  330. end;
  331.  
  332. procedure TIniFile.EraseSection(const Section: string);
  333. begin
  334.   if not WritePrivateProfileString(PChar(Section), nil, nil,
  335.     PChar(FFileName)) then
  336.     raise Exception.CreateResFmt(@SIniFileWriteError, [FileName]);
  337. end;
  338.  
  339. procedure TIniFile.DeleteKey(const Section, Ident: String);
  340. begin
  341.   WritePrivateProfileString(PChar(Section), PChar(Ident), nil,
  342.      PChar(FFileName));
  343. end;
  344.  
  345. procedure TIniFile.UpdateFile;
  346. begin
  347.   WritePrivateProfileString(nil, nil, nil, PChar(FFileName));
  348. end;
  349.  
  350. { TMemIniFile }
  351.  
  352. constructor TMemIniFile.Create(const FileName: string);
  353. begin
  354.   inherited Create(FileName);
  355.   FSections := TStringList.Create;
  356.   LoadValues;
  357. end;
  358.  
  359. destructor TMemIniFile.Destroy;
  360. begin
  361.   if FSections <> nil then Clear;
  362.   FSections.Free;
  363.   inherited;
  364. end;
  365.  
  366. function TMemIniFile.AddSection(const Section: string): TStrings;
  367. begin
  368.   Result := TStringList.Create;
  369.   try
  370.     FSections.AddObject(Section, Result);
  371.   except
  372.     Result.Free;
  373.   end;
  374. end;
  375.  
  376. procedure TMemIniFile.Clear;
  377. var
  378.   I: Integer;
  379. begin
  380.   for I := 0 to FSections.Count - 1 do
  381.     TStrings(FSections.Objects[I]).Free;
  382.   FSections.Clear;
  383. end;
  384.  
  385. procedure TMemIniFile.DeleteKey(const Section, Ident: String);
  386. var
  387.   I, J: Integer;
  388.   Strings: TStrings;
  389. begin
  390.   I := FSections.IndexOf(Section);
  391.   if I >= 0 then
  392.   begin
  393.     Strings := TStrings(FSections.Objects[I]);
  394.     J := Strings.IndexOfName(Ident);
  395.     if J >= 0 then Strings.Delete(J);
  396.   end;
  397. end;
  398.  
  399. procedure TMemIniFile.EraseSection(const Section: string);
  400. var
  401.   I: Integer;
  402. begin
  403.   I := FSections.IndexOf(Section);
  404.   if I >= 0 then
  405.   begin
  406.     TStrings(FSections.Objects[I]).Free;
  407.     FSections.Delete(I);
  408.   end;
  409. end;
  410.  
  411. procedure TMemIniFile.GetStrings(List: TStrings);
  412. var
  413.   I, J: Integer;
  414.   Strings: TStrings;
  415. begin
  416.   List.BeginUpdate;
  417.   try
  418.     for I := 0 to FSections.Count - 1 do
  419.     begin
  420.       List.Add('[' + FSections[I] + ']');
  421.       Strings := TStrings(FSections.Objects[I]);
  422.       for J := 0 to Strings.Count - 1 do List.Add(Strings[J]);
  423.       List.Add('');
  424.     end;
  425.   finally
  426.     List.EndUpdate;
  427.   end;
  428. end;
  429.  
  430. procedure TMemIniFile.LoadValues;
  431. var
  432.   List: TStringList;
  433. begin
  434.   if (FileName <> '') and FileExists(FileName) then
  435.   begin
  436.     List := TStringList.Create;
  437.     try
  438.       List.LoadFromFile(FileName);
  439.       SetStrings(List);
  440.     finally
  441.       List.Free;
  442.     end;
  443.   end else Clear;
  444. end;
  445.  
  446. procedure TMemIniFile.ReadSection(const Section: string;
  447.   Strings: TStrings);
  448. var
  449.   I, J: Integer;
  450.   SectionStrings: TStrings;
  451. begin
  452.   Strings.BeginUpdate;
  453.   try
  454.     Strings.Clear;
  455.     I := FSections.IndexOf(Section);
  456.     if I >= 0 then
  457.     begin
  458.       SectionStrings := TStrings(FSections.Objects[I]);
  459.       for J := 0 to SectionStrings.Count - 1 do
  460.         Strings.Add(SectionStrings.Names[J]);
  461.     end;
  462.   finally
  463.     Strings.EndUpdate;
  464.   end;
  465. end;
  466.  
  467. procedure TMemIniFile.ReadSections(Strings: TStrings);
  468. begin
  469.   Strings.Assign(FSections);
  470. end;
  471.  
  472. procedure TMemIniFile.ReadSectionValues(const Section: string;
  473.   Strings: TStrings);
  474. var
  475.   I: Integer;
  476. begin
  477.   Strings.BeginUpdate;
  478.   try
  479.     Strings.Clear;
  480.     I := FSections.IndexOf(Section);
  481.     if I >= 0 then Strings.Assign(TStrings(FSections.Objects[I]));
  482.   finally
  483.     Strings.EndUpdate;
  484.   end;
  485. end;
  486.  
  487. function TMemIniFile.ReadString(const Section, Ident,
  488.   Default: string): string;
  489. var
  490.   I: Integer;
  491.   Strings: TStrings;
  492. begin
  493.   I := FSections.IndexOf(Section);
  494.   if I >= 0 then
  495.   begin
  496.     Strings := TStrings(FSections.Objects[I]);
  497.     I := Strings.IndexOfName(Ident);
  498.     if I >= 0 then
  499.     begin
  500.       Result := Copy(Strings[I], Length(Ident) + 2, Maxint);
  501.       Exit;
  502.     end;
  503.   end;
  504.   Result := Default;
  505. end;
  506.  
  507. procedure TMemIniFile.Rename(const FileName: string; Reload: Boolean);
  508. begin
  509.   FFileName := FileName;
  510.   if Reload then LoadValues;
  511. end;
  512.  
  513. procedure TMemIniFile.SetStrings(List: TStrings);
  514. var
  515.   I: Integer;
  516.   S: string;
  517.   Strings: TStrings;
  518. begin
  519.   Clear;
  520.   Strings := nil;
  521.   for I := 0 to List.Count - 1 do
  522.   begin
  523.     S := List[I];
  524.     if (S <> '') and (S[1] <> ';') then
  525.       if (S[1] = '[') and (S[Length(S)] = ']') then
  526.         Strings := AddSection(Copy(S, 2, Length(S) - 2))
  527.       else
  528.         if Strings <> nil then Strings.Add(S);
  529.   end;
  530. end;
  531.  
  532. procedure TMemIniFile.UpdateFile;
  533. var
  534.   List: TStringList;
  535. begin
  536.   List := TStringList.Create;
  537.   try
  538.     GetStrings(List);
  539.     List.SaveToFile(FFileName);
  540.   finally
  541.     List.Free;
  542.   end;
  543. end;
  544.  
  545. procedure TMemIniFile.WriteString(const Section, Ident, Value: String);
  546. var
  547.   I: Integer;
  548.   S: string;
  549.   Strings: TStrings;
  550. begin
  551.   I := FSections.IndexOf(Section);
  552.   if I >= 0 then
  553.     Strings := TStrings(FSections.Objects[I]) else
  554.     Strings := AddSection(Section);
  555.   S := Ident + '=' + Value;
  556.   I := Strings.IndexOfName(Ident);
  557.   if I >= 0 then Strings[I] := S else Strings.Add(S);
  558. end;
  559.  
  560. end.
  561.