home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 September / Chip_2002-09_cd1.bin / zkuste / delphi / experti / d456 / BROMBSCT.ZIP / BigIni.pas next >
Pascal/Delphi Source File  |  2002-06-27  |  65KB  |  1,635 lines

  1. { BigIni.PAS  v 4.11 - see bottom of file for details                        }
  2. { -------------------------------------------------------------------------- }
  3. unit BigIni;
  4.  
  5. // activate the following line, if you want to access lines longer than 255 chars:
  6. { $ DEFINE UseShortStrings}
  7.  
  8. {$IFDEF UseShortStrings}
  9. {$H-} {using short strings in old pascal style increases speed}
  10. {$ENDIF}
  11.  
  12. interface
  13.  
  14.  
  15. uses classes, Windows, SysUtils, Forms, Graphics;
  16.  
  17. const
  18.   IniTextBufferSize = $7000;
  19.                      {Note [1]: don't use more than $7FFFF - it's an integer}
  20.  
  21.   cIniCount = 'Count'; {count keyword}
  22.  
  23. type
  24.   TEraseSectionCallback = function(const sectionName: string; const sl1, sl2: TStringList): Boolean
  25.     of object;
  26.  
  27. {
  28. TCommaSeparatedInfo is a Tool-Class to read and write multiple parameters/values
  29. from a single, comma-separated string. These parameters are positional.
  30.  
  31. Please see descendant TCSIFont for some useful example.
  32. }
  33.   TCommaSeparatedInfo = class
  34.   private
  35.     FValues: TStringList;
  36.     function GetValue: string;
  37.     function GetElement(index: Integer): string;
  38.     function GetInteger(index: Integer): Integer;
  39.     function GetBoolean(index: Integer): Boolean;
  40.     function GetColor(index: Integer): TColor;
  41.     procedure SetValue(const Value: string);
  42.     procedure SetBoolean(index: Integer; const Value: Boolean);
  43.     procedure SetElement(index: Integer; const Value: string);
  44.     procedure SetInteger(index: Integer; const Value: Integer);
  45.     procedure SetColor(const Index: Integer; const Value: TColor);
  46.   public
  47.     constructor Create;
  48.     destructor Destroy; override;
  49.     property Value: string read GetValue write SetValue;
  50.     property Element[index: Integer]: string read GetElement write SetElement; default;
  51.     property AsInteger[index: Integer]: Integer read GetInteger write SetInteger;
  52.     property AsBoolean[index: Integer]: Boolean read GetBoolean write SetBoolean;
  53.   end;
  54.  
  55.   TCSIFont = class(TCommaSeparatedInfo)
  56.   private
  57.     function GetFontStyle: TFontStyles;
  58.     procedure SetFontStyle(const Value: TFontStyles);
  59.   public
  60.     property FontName: string index 0 read GetElement write SetElement;
  61.     property FontSize: Integer index 1 read GetInteger write SetInteger;
  62.     property FontStyle: TFontStyles read GetFontStyle write SetFontStyle;
  63.     property FontColor: TColor index 6 read GetColor write SetColor;
  64.     property FontCharset: Integer index 7 read GetInteger write SetInteger;
  65.     property FontPitch: Integer index 8 read GetInteger write SetInteger;
  66.   end;
  67.  
  68. {
  69. TSectionList is a Tool-Class for TBigIniFile
  70. It's a descendant of TStringList with "enhanced" IndexOf function (and others)
  71. }
  72.   TSectionList = class(TStringList)
  73.   private
  74.     FPrevIndex: Integer;
  75.   public
  76.     constructor Create;
  77.     function EraseDuplicates(callBackProc: TEraseSectionCallback): Boolean;
  78.     function GetSectionItems(index: Integer): TStringList;
  79.     function IndexOf(const S: AnsiString): Integer; override;
  80.     function IndexOfName(const name: string): Integer; virtual;
  81.     property SectionItems[index: Integer]: TStringList read GetSectionItems;
  82.   end;
  83.  
  84.   TBigIniFile = class(TObject)
  85.   private
  86.     FEraseSectionCallback: TEraseSectionCallback;
  87.     FFileName: string;
  88.     FPrevSectionIndex: Integer;
  89.     FFlagClearOnReadSectionValues, {set true if clearing wanted}
  90.       FFlagDropCommentLines, {set false to keep lines starting with ';'}
  91.       FFlagFilterOutInvalid, {set false to keep lines without '='      }
  92.       FFlagDropWhiteSpace, {set false to keep white space around '='}
  93.       FFlagDropApostrophes, {set false to keep apostrophes around key }
  94.       FFlagTrimRight: Boolean; {set false to keep white space at end of line}
  95.     FHasChanged: Boolean;
  96.     FSectionList: TSectionList;
  97.     FTextBufferSize: Integer;
  98.  
  99.     function FindItemIndex(const aSection, aKey: string; CreateNew: Boolean;
  100.       var FoundStringList: TStringList): Integer;
  101.     procedure SetFileName(const aName: string);
  102.     procedure ClearSectionList;
  103.   public
  104.     constructor Create(const FileName: string);
  105.     destructor Destroy; override;
  106.  
  107.     procedure AppendFromFile(const aName: string); virtual;
  108.     procedure Clear; virtual;
  109.     procedure DeleteKey(const aSection, aKey: string); virtual;
  110.     procedure EraseSection(const aSection: string); virtual;
  111.     procedure FlushFile; virtual;
  112.     function HasSection(const aSection: string): Boolean; virtual;
  113.     function ReadAnsiString(const aSection, aKey, aDefault: string): AnsiString; virtual;
  114.     procedure ReadAll(aStrings: TStrings); virtual;
  115.     function ReadBool(const aSection, aKey: string; aDefault: Boolean): Boolean; virtual;
  116.     function ReadDate(const aSection, aKey: string; aDefault: TDateTime): TDateTime; virtual;
  117.     function ReadDateTime(const aSection, aKey: string; aDefault: TDateTime): TDateTime; virtual;
  118.     function ReadFloat(const aSection, aKey: string; aDefault: Double): Double; virtual;
  119.     function ReadInteger(const aSection, aKey: string; aDefault: Longint): Longint; virtual;
  120.     procedure ReadSection(const aSection: string; aStrings: TStrings); virtual;
  121.     procedure ReadSections(aStrings: TStrings); virtual;
  122.     procedure ReadSectionValues(const aSection: string; aStrings: TStrings); virtual;
  123.     function ReadString(const aSection, aKey, aDefault: string): string; virtual;
  124.     function ReadTime(const aSection, aKey: string; aDefault: TDateTime): TDateTime; virtual;
  125.     function SectionExists(const aSection: string): Boolean; virtual;
  126.     procedure UpdateFile; virtual;
  127.     function ValueExists(const aSection, aValue: string): Boolean; virtual;
  128.     procedure WriteAnsiString(const aSection, aKey, aValue: AnsiString); virtual;
  129.     procedure WriteBool(const aSection, aKey: string; aValue: Boolean); virtual;
  130.     procedure WriteDate(const aSection, aKey: string; aValue: TDateTime); virtual;
  131.     procedure WriteDateTime(const aSection, aKey: string; aValue: TDateTime); virtual;
  132.     procedure WriteFloat(const aSection, aKey: string; aValue: Double); virtual;
  133.     procedure WriteInteger(const aSection, aKey: string; aValue: Longint); virtual;
  134.     procedure WriteString(const aSection, aKey, aValue: string); virtual;
  135.     procedure WriteTime(const aSection, aKey: string; aValue: TDateTime); virtual;
  136.  
  137.     property EraseSectionCallback: TEraseSectionCallback read FEraseSectionCallback write
  138.       FEraseSectionCallback;
  139.     property FlagClearOnReadSectionValues: Boolean read FFlagClearOnReadSectionValues write
  140.       FFlagClearOnReadSectionValues;
  141.     property FlagDropApostrophes: Boolean read FFlagDropApostrophes write FFlagDropApostrophes;
  142.     property FlagDropCommentLines: Boolean read FFlagDropCommentLines write FFlagDropCommentLines;
  143.     property FlagDropWhiteSpace: Boolean read FFlagDropWhiteSpace write FFlagDropWhiteSpace;
  144.     property FlagFilterOutInvalid: Boolean read FFlagFilterOutInvalid write FFlagFilterOutInvalid;
  145.     property FlagTrimRight: Boolean read FFlagTrimRight write FFlagTrimRight;
  146.     property FileName: string read FFileName write SetFileName;
  147.     property SectionNames: TSectionList read FSectionList;
  148.   end;
  149.  
  150.   TBiggerIniFile = class(TBigIniFile)
  151.   public
  152.     function ReadBinaryData(const aSection, aKey: string; var Buffer; BufSize: Integer): Integer;
  153.       virtual;
  154.     function ReadColor(const aSection,
  155.       aKey: string;
  156.       aDefault: TColor): TColor; virtual;
  157.     function ReadFont(const aSection, aKey: string; aFont: TFont): TFont; virtual;
  158.     procedure ReadNumberedList(const Section: string;
  159.       aStrings: TStrings;
  160.       Deflt: string;
  161.       aPrefix: string = '';
  162.       IndexStart: Integer = 1); virtual;
  163.     procedure RenameKey(const aSection, OldKey, NewKey: string); virtual;
  164.     procedure RenameSection(const OldSection, NewSection: string); virtual;
  165.     procedure WriteBinaryData(const aSection, aKey: string; var Buffer; BufSize: Integer); virtual;
  166.     procedure WriteColor(const aSection,
  167.       aKey: string;
  168.       aValue: TColor); virtual;
  169.     procedure WriteFont(const aSection, aKey: string; aFont: TFont); virtual;
  170.     procedure WriteNumberedList(const Section: string;
  171.       aStrings: TStrings;
  172.       aPrefix: string = '';
  173.       IndexStart: Integer = 1); virtual;
  174.     procedure WriteSectionValues(const aSection: string; const aStrings: TStrings); virtual;
  175.  
  176.     property HasChanged: Boolean read FHasChanged write FHasChanged;
  177.     property TextBufferSize: Integer read FTextBufferSize write FTextBufferSize;
  178.   end;
  179.  
  180.   TAppIniFile = class(TBiggerIniFile)
  181.     constructor Create;
  182.   end;
  183.  
  184.   TLibIniFile = class(TBiggerIniFile)
  185.     constructor Create;
  186.   end;
  187.  
  188. function ModuleName(getLibraryName: Boolean): string;
  189.  
  190. { -------------------------------------------------------------------------- }
  191. implementation
  192. { -------------------------------------------------------------------------- }
  193.  
  194. {........................................................................... }
  195. { classless functions/procedures                                             }
  196. {........................................................................... }
  197.  
  198. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  199. { function ModuleName
  200.   purpose : get the full path of the current module
  201.   - if flag getLibraryName is set (and the module is a library) then the library
  202.     name is returned. Otherwise the applications name is returned.
  203.   - the result is in proper mixed case (the similar function Application.ExeName
  204.     returns all in uppercase chars)
  205.  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  206.  
  207. function ModuleName(getLibraryName: Boolean): string;
  208. var
  209.   Buffer: array[0..260] of Char;
  210.   aHandle: THandle;
  211.   thePath: string;
  212.   theSearchRec: TSearchRec;
  213. begin
  214.   if getLibraryName then aHandle := HInstance
  215.   else aHandle := 0;
  216.   SetString(Result, Buffer, GetModuleFileName(aHandle, Buffer, SizeOf(Buffer)));
  217.   { GetModuleFileName returns a result in uppercase letters only }
  218.   { The following FindFirst construct returns the mixed case name }
  219.   thePath := ExtractFilePath(Result);
  220.   if FindFirst(Result, faAnyFile, theSearchRec) = 0 then
  221.   begin
  222.     Result := thePath + theSearchRec.name;
  223.   end;
  224.   FindClose(theSearchRec);
  225. end;
  226.  
  227. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  228.  
  229. function max(a, b: Integer): Integer;
  230. begin
  231.   if a > b then Result := a
  232.   else Result := b;
  233. end;
  234.  
  235. //------------------------------------------------------------------------------
  236. // check if two StringLists contain identical strings
  237. //------------------------------------------------------------------------------
  238.  
  239. function ListIdentical(l1, l2: TStringList): Boolean;
  240. var
  241.   ix: Integer;
  242. begin
  243.   Result := False;
  244.   if l1.count = l2.count then
  245.   begin
  246.     for ix := 0 to l1.count - 1 do
  247.     begin
  248.       if (l1[ix] <> l2[ix]) then Exit;
  249.     end;
  250.     Result := True;
  251.   end;
  252. end;
  253.  
  254. {........................................................................... }
  255. { class TCommaSeparatedInfo                                                  }
  256. {........................................................................... }
  257.  
  258. constructor TCommaSeparatedInfo.Create;
  259. begin
  260.   FValues := TStringList.Create;
  261. end;
  262.  
  263. destructor TCommaSeparatedInfo.Destroy;
  264. begin
  265.   FValues.Free;
  266.   inherited;
  267. end;
  268.  
  269. function TCommaSeparatedInfo.GetBoolean(index: Integer): Boolean;
  270. begin
  271.   // '1' stands for 'true', any other value for 'false'
  272.   Result := (Element[index] = '1');
  273. end;
  274.  
  275. function TCommaSeparatedInfo.GetColor(index: Integer): TColor;
  276. begin
  277.   Result := StrToIntDef('$' + Element[index], -1);
  278.   if result = -1 then
  279.   begin
  280.     try
  281.       Result := StringToColor(Element[index]);
  282.     except
  283.       result := clBlack;
  284.     end;
  285.   end;
  286. end;
  287.  
  288. function TCommaSeparatedInfo.GetElement(index: Integer): string;
  289. begin
  290.   result := FValues[index];
  291. end;
  292.  
  293. function TCommaSeparatedInfo.GetInteger(index: Integer): Integer;
  294. begin
  295.   Result := StrToIntDef(Element[index], -1);
  296. end;
  297.  
  298. function TCommaSeparatedInfo.GetValue: string;
  299. begin
  300.   result := FValues.CommaText;
  301. end;
  302.  
  303. procedure TCommaSeparatedInfo.SetBoolean(index: Integer;
  304.   const Value: Boolean);
  305. const
  306.   BoolText: array[Boolean] of string[1] = ('', '1');
  307. begin
  308.   SetElement(index, BoolText[Value]);
  309. end;
  310.  
  311. procedure TCommaSeparatedInfo.SetElement(index: Integer;
  312.   const Value: string);
  313. begin
  314.   while (FValues.Count - 1) < Index do FValues.Add('');
  315.   FValues[index] := Value;
  316. end;
  317.  
  318. procedure TCommaSeparatedInfo.SetInteger(index: Integer;
  319.   const Value: Integer);
  320. begin
  321.   SetElement(index, IntToStr(Value));
  322. end;
  323.  
  324. procedure TCommaSeparatedInfo.SetValue(const Value: string);
  325. begin
  326.   FValues.CommaText := Value;
  327. end;
  328.  
  329. procedure TCommaSeparatedInfo.SetColor(const Index: Integer; const Value: TColor);
  330. begin
  331.   Element[index] := ColorToString(Value);
  332. end;
  333.  
  334. {........................................................................... }
  335. { class TCSIFont                                                             }
  336. {........................................................................... }
  337.  
  338. function TCSIFont.GetFontStyle: TFontStyles;
  339. begin
  340.   result := [];
  341.   if AsBoolean[2] then result := result + [fsBold];
  342.   if AsBoolean[3] then result := result + [fsItalic];
  343.   if AsBoolean[4] then result := result + [fsUnderline];
  344.   if AsBoolean[5] then result := result + [fsStrikeOut];
  345. end;
  346.  
  347. procedure TCSIFont.SetFontStyle(const Value: TFontStyles);
  348. begin
  349.   AsBoolean[2] := fsBold in Value;
  350.   AsBoolean[3] := fsItalic in Value;
  351.   AsBoolean[4] := fsUnderline in Value;
  352.   AsBoolean[5] := fsStrikeOut in Value;
  353. end;
  354.  
  355. {........................................................................... }
  356. { class TSectionList                                                         }
  357. {........................................................................... }
  358.  
  359. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  360. { create new instance                                                        }
  361. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  362.  
  363. constructor TSectionList.Create;
  364. begin
  365.   inherited Create;
  366.   FPrevIndex := 0;
  367. end;
  368. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  369. { access to property SectionItems                                            }
  370. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  371.  
  372. function TSectionList.GetSectionItems(index: Integer): TStringList;
  373. begin
  374.   Result := TStringList(Objects[index]);
  375. end;
  376. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  377. { erase duplicate entries                                                    }
  378. { results TRUE if changes were made                                          }
  379. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  380.  
  381. function TSectionList.EraseDuplicates(callBackProc: TEraseSectionCallback): Boolean;
  382. var
  383.   slDuplicateTracking: TStringList;
  384.   idxToDelete,
  385.     ixLow,
  386.     ixHigh,
  387.     ix: Integer;
  388.  
  389.   { swap two integer variables }
  390.  
  391.   procedure SwapInt(var a, b: Integer);
  392.   var
  393.     c: Integer;
  394.   begin
  395.     c := a;
  396.     a := b;
  397.     b := c;
  398.   end;
  399. begin
  400.   Result := False; { no changes made yet }
  401.  
  402.   if count > 1 then
  403.   begin
  404.     slDuplicateTracking := TStringList.Create;
  405.     slDuplicateTracking.Assign(Self);
  406.     { store current position in the objects field: }
  407.     for ix := 0 to slDuplicateTracking.count - 1 do slDuplicateTracking.Objects[ix] := Pointer(ix);
  408.     { sort the list to find out duplicates }
  409.     slDuplicateTracking.Sort;
  410.     ixLow := 0;
  411.     for ix := 1 to slDuplicateTracking.count - 1 do
  412.     begin
  413.       if (AnsiCompareText(slDuplicateTracking.STRINGS[ixLow],
  414.         slDuplicateTracking.STRINGS[ix]) <> 0) then
  415.       begin
  416.         ixLow := ix;
  417.       end else
  418.       begin
  419.         ixHigh := ix;
  420.         { find the previous entry (with lower integer number) }
  421.         if Integer(slDuplicateTracking.Objects[ixLow]) >
  422.           Integer(slDuplicateTracking.Objects[ixHigh]) then SwapInt(ixHigh, ixLow);
  423.  
  424.         if Assigned(callBackProc) then
  425.         begin
  426.           { ask callback/user wether to delete the higher (=true)
  427.             or the lower one (=false)}
  428.           if not callBackProc(slDuplicateTracking.STRINGS[ix],
  429.             SectionItems[Integer(slDuplicateTracking.Objects[ixLow])],
  430.             SectionItems[Integer(slDuplicateTracking.Objects[ixHigh])]) then SwapInt(ixHigh, ixLow);
  431.         end;
  432.         idxToDelete := Integer(slDuplicateTracking.Objects[ixHigh]);
  433.  
  434.         { free associated object and mark it as unassigned }
  435.         SectionItems[idxToDelete].Free;
  436.         Objects[idxToDelete] := nil;
  437.         Result := True; { list had been changed }
  438.       end {if};
  439.     end {for};
  440.  
  441.     ix := 0;
  442.     while ix < count do
  443.     begin
  444.       if Objects[ix] = nil then Delete(ix)
  445.       else Inc(ix);
  446.     end;
  447.     slDuplicateTracking.Free;
  448.   end {if};
  449.  
  450. end;
  451. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  452. { search string                                                              }
  453. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  454.  
  455. function TSectionList.IndexOf(const S: AnsiString): Integer;
  456. var
  457.   ix,
  458.     LastIX: Integer;
  459.   { This routine doesn't search from the first item each time,
  460.     but from the last successful item. It is likely that the
  461.     next item is to be found downward. }
  462. begin
  463.   Result := -1;
  464.   if count = 0 then Exit;
  465.  
  466.   LastIX := FPrevIndex;
  467.   { Search from last successful point to the end: }
  468.   for ix := LastIX to count - 1 do
  469.   begin
  470.     if (AnsiCompareText(Get(ix), S) = 0) then begin
  471.       Result := ix;
  472.       FPrevIndex := ix;
  473.       Exit;
  474.     end;
  475.   end;
  476.   { Not found yet? Search from beginning to last successful point: }
  477.   for ix := 0 to LastIX - 1 do
  478.   begin
  479.     if (AnsiCompareText(Get(ix), S) = 0) then begin
  480.       Result := ix;
  481.       FPrevIndex := ix;
  482.       Exit;
  483.     end;
  484.   end;
  485. end;
  486.  
  487. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  488.  
  489. function TSectionList.IndexOfName(const name: string): Integer;
  490. var
  491.   P: Integer;
  492.   s1,
  493.     s2: AnsiString;
  494. begin
  495.   s2 := name;
  496.   for Result := 0 to GetCount - 1 do
  497.   begin
  498.     s1 := Get(Result);
  499.     P := AnsiPos('=', s1);
  500.     SetLength(s1, P - 1);
  501.     if (P <> 0) and (
  502.       CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  503.       PChar(s1), -1,
  504.       PChar(s2), -1)
  505.       = 2) then Exit;
  506.   end;
  507.   Result := -1;
  508. end;
  509.  
  510. {........................................................................... }
  511. { class TBigIniFile                                                          }
  512. {........................................................................... }
  513.  
  514. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  515. { create new instance                                                        }
  516. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  517.  
  518. constructor TBigIniFile.Create(const FileName: string);
  519. begin
  520.   FSectionList := TSectionList.Create;
  521.   FTextBufferSize := IniTextBufferSize; { you may set to zero to switch off }
  522.   FFlagDropCommentLines := False; { change this aDefaults if needed }
  523.   FFlagFilterOutInvalid := False;
  524.   FFlagDropWhiteSpace := False;
  525.   FFlagDropApostrophes := False;
  526.   FFlagTrimRight := False;
  527.   FFlagClearOnReadSectionValues := False;
  528.   FFileName := '';
  529.   FPrevSectionIndex := 0;
  530.   FEraseSectionCallback := nil;
  531.   SetFileName(FileName);
  532. end;
  533. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  534. { destructor                                                                 }
  535. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  536.  
  537. destructor TBigIniFile.Destroy;
  538. begin
  539.   FlushFile;
  540.   ClearSectionList;
  541.   FSectionList.Free;
  542.   inherited Destroy;
  543. end;
  544. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  545. { clean up                                                                   }
  546. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  547.  
  548. procedure TBigIniFile.ClearSectionList;
  549. var
  550.   ixSections: Integer;
  551. begin
  552.   with FSectionList do
  553.   begin
  554.     for ixSections := 0 to count - 1 do
  555.     begin
  556.       SectionItems[ixSections].Free;
  557.     end;
  558.     Clear;
  559.     FPrevIndex := 0;
  560.   end;
  561. end;
  562. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  563. { Erases all data from the INI file                                          }
  564. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  565.  
  566. procedure TBigIniFile.Clear;
  567. begin
  568.   ClearSectionList;
  569. end;
  570. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  571. { Append from File                                                           }
  572. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  573.  
  574. procedure TBigIniFile.AppendFromFile(const aName: string);
  575. var
  576.   CurrStringList: TStringList;
  577.   CurrSectionName: string;
  578.   lpTextBuffer: Pointer;
  579.   Source: TextFile;
  580.   OneLine: string;
  581.   LL: Integer;
  582.   LastPos,
  583.     EqPos: Integer;
  584.   nospace: Boolean;
  585. begin
  586.   CurrStringList := nil;
  587.   lpTextBuffer := nil; {only to avoid compiler warnings}
  588.   FPrevSectionIndex := 0;
  589.   if FileExists(aName) then
  590.   begin
  591.     Assign(Source, aName);
  592.     if FTextBufferSize > 0 then
  593.     begin
  594.       GetMem(lpTextBuffer, FTextBufferSize);
  595.       SetTextBuf(Source, lpTextBuffer^, FTextBufferSize);
  596.     end;
  597.     Reset(Source);
  598.     while not Eof(Source) do
  599.     begin
  600.       ReadLn(Source, OneLine);
  601.       if OneLine = #$1A {EOF} then OneLine := '';
  602.       { drop lines with leading ';' : }
  603.       if FFlagDropCommentLines then if OneLine <> '' then if (OneLine[1] = ';') then OneLine := '';
  604.       { drop lines without '=' }
  605.       if OneLine <> '' then begin
  606.         LL := Length(OneLine);
  607.         if (OneLine[1] = '[') and (OneLine[LL] = ']') then
  608.         begin
  609.           CurrSectionName := Copy(OneLine, 2, LL - 2);
  610.           CurrStringList := TStringList.Create;
  611.           FSectionList.AddObject(CurrSectionName, CurrStringList);
  612.         end
  613.         else begin
  614.           if FFlagDropWhiteSpace then
  615.           begin
  616.             nospace := False;
  617.             repeat
  618.               { delete white space left to equal sign }
  619.               EqPos := AnsiPos('=', OneLine);
  620.               if EqPos > 1 then begin
  621.                 if OneLine[EqPos - 1] in [' ', #9] then
  622.                   Delete(OneLine, EqPos - 1, 1)
  623.                 else
  624.                   nospace := True;
  625.               end
  626.               else
  627.                 nospace := True;
  628.             until nospace;
  629.             nospace := False;
  630.             EqPos := AnsiPos('=', OneLine);
  631.             if EqPos > 1 then begin
  632.               repeat
  633.                 { delete white space right to equal sign }
  634.                 if EqPos < Length(OneLine) then begin
  635.                   if OneLine[EqPos + 1] in [' ', #9] then
  636.                     Delete(OneLine, EqPos + 1, 1)
  637.                   else
  638.                     nospace := True;
  639.                 end
  640.                 else
  641.                   nospace := True;
  642.               until nospace;
  643.             end;
  644.           end; {FFlagDropWhiteSpace}
  645.           if FFlagDropApostrophes then
  646.           begin
  647.             EqPos := AnsiPos('=', OneLine);
  648.             if EqPos > 1 then begin
  649.               LL := Length(OneLine);
  650.               { filter out the apostrophes }
  651.               if EqPos < LL - 1 then begin
  652.                 if (OneLine[EqPos + 1] = OneLine[LL]) and (OneLine[LL] in ['"', #39]) then
  653.                 begin
  654.                   Delete(OneLine, LL, 1);
  655.                   Delete(OneLine, EqPos + 1, 1);
  656.                 end;
  657.               end;
  658.             end;
  659.           end; {FFlagDropApostrophes}
  660.           if FFlagTrimRight then
  661.           begin
  662.             LastPos := Length(OneLine);
  663.             while ((LastPos > 0) and (OneLine[LastPos] < #33)) do Dec(LastPos);
  664.             OneLine := Copy(OneLine, 1, LastPos);
  665.           end; {FFlagTrimRight}
  666.           if (not FFlagFilterOutInvalid) or (AnsiPos('=', OneLine) > 0) then
  667.           begin
  668.             if Assigned(CurrStringList) then CurrStringList.Add(OneLine);
  669.           end;
  670.         end;
  671.       end;
  672.     end;
  673.  
  674.     if FSectionList.EraseDuplicates(FEraseSectionCallback) then FHasChanged := True;
  675.  
  676.     Close(Source);
  677.     if FTextBufferSize > 0 then
  678.     begin
  679.       FreeMem(lpTextBuffer, FTextBufferSize);
  680.     end;
  681.   end;
  682. end;
  683. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  684. { Set or change FileName                                                     }
  685. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  686.  
  687. procedure TBigIniFile.SetFileName(const aName: string);
  688. begin
  689.   FlushFile;
  690.   ClearSectionList;
  691.   FFileName := aName;
  692.   if aName <> '' then AppendFromFile(aName);
  693.   FHasChanged := False;
  694. end;
  695.  
  696. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  697. { find item in specified section                                             }
  698. { depending on CreateNew-flag, the section is created, if not existing       }
  699. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  700.  
  701. function TBigIniFile.FindItemIndex(const aSection, aKey: string; CreateNew: Boolean;
  702.   var FoundStringList: TStringList): Integer;
  703. var
  704.   SectionIndex: Integer;
  705.   LastIX: Integer;
  706. begin
  707.   SectionIndex := -1;
  708.  
  709.   if FSectionList.count > 0 then
  710.   begin
  711.     LastIX := FPrevSectionIndex - 1;
  712.     if LastIX < 0 then LastIX := FSectionList.count - 1;
  713.     while (AnsiCompareText(aSection, FSectionList[FPrevSectionIndex]) <> 0)
  714.       and (FPrevSectionIndex <> LastIX) do
  715.     begin
  716.       Inc(FPrevSectionIndex);
  717.       if FPrevSectionIndex = FSectionList.count then FPrevSectionIndex := 0;
  718.     end;
  719.     if AnsiCompareText(aSection, FSectionList[FPrevSectionIndex]) = 0 then
  720.     begin
  721.       SectionIndex := FPrevSectionIndex;
  722.     end;
  723.   end;
  724.  
  725.   if SectionIndex = -1 then
  726.   begin
  727.     if CreateNew then begin
  728.       FoundStringList := TStringList.Create;
  729.       FPrevSectionIndex := FSectionList.AddObject(aSection, FoundStringList);
  730.     end
  731.     else begin
  732.       FoundStringList := nil;
  733.     end;
  734.     Result := -1;
  735.   end
  736.   else begin
  737.     FoundStringList := FSectionList.SectionItems[SectionIndex];
  738.     Result := FoundStringList.IndexOfName(aKey);
  739.   end;
  740. end;
  741. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  742. { the basic function: return single string                                   }
  743. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  744.  
  745. function TBigIniFile.ReadString(const aSection, aKey, aDefault: string): string;
  746. var
  747.   ItemIndex: Integer;
  748.   CurrStringList: TStringList;
  749. begin
  750.   ItemIndex := FindItemIndex(aSection, aKey, False, CurrStringList);
  751.   if ItemIndex = -1 then
  752.   begin
  753.     Result := aDefault
  754.   end
  755.   else begin
  756.     Result := Copy(CurrStringList[ItemIndex], Length(aKey) + 2, MaxInt);
  757.   end;
  758. end;
  759. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  760. { same as ReadString, but returns AnsiString type                            }
  761. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  762.  
  763. function TBigIniFile.ReadAnsiString(const aSection, aKey, aDefault: string): AnsiString;
  764. var
  765.   ItemIndex: Integer;
  766.   CurrStringList: TStringList;
  767. begin
  768.   ItemIndex := FindItemIndex(aSection, aKey, False, CurrStringList);
  769.   if ItemIndex = -1 then
  770.   begin
  771.     Result := aDefault
  772.   end
  773.   else begin
  774.     Result := CurrStringList.Values[aKey];
  775.   end;
  776. end;
  777. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  778. { here is the one to write the string                                        }
  779. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  780.  
  781. procedure TBigIniFile.WriteString(const aSection, aKey, aValue: string);
  782. var
  783.   ItemIndex: Integer;
  784.   CurrStringList: TStringList;
  785.   newLine: string;
  786. begin
  787.   if aKey = '' then
  788.   begin
  789.     {behaviour of WritePrivateProfileString: if all parameters are null strings,
  790.      the file is flushed to disk. Otherwise, if key name is a null string,
  791.      the entire Section is to be deleted}
  792.     if (aSection = '') and (aValue = '') then FlushFile
  793.     else EraseSection(aSection);
  794.   end
  795.   else begin
  796.     newLine := aKey + '=' + aValue;
  797.     ItemIndex := FindItemIndex(aSection, aKey, True, CurrStringList);
  798.     if ItemIndex = -1 then begin
  799.       CurrStringList.Add(newLine);
  800.       FHasChanged := True;
  801.     end
  802.     else begin
  803.       if (CurrStringList[ItemIndex] <> newLine) then
  804.       begin
  805.         FHasChanged := True;
  806.         CurrStringList[ItemIndex] := newLine;
  807.       end;
  808.     end;
  809.   end;
  810. end;
  811. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  812. { Same as writestring, but processes AnsiString type                         }
  813. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  814.  
  815. procedure TBigIniFile.WriteAnsiString(const aSection, aKey, aValue: AnsiString);
  816. var
  817.   ItemIndex: Integer;
  818.   CurrStringList: TStringList;
  819.   newLine: AnsiString;
  820. begin
  821.   if aKey = '' then
  822.   begin
  823.     {behaviour of WritePrivateProfileString: if all parameters are null strings,
  824.      the file is flushed to disk. Otherwise, if key name is a null string,
  825.      the entire Section is to be deleted}
  826.     if (aSection = '') and (aValue = '') then FlushFile
  827.     else EraseSection(aSection);
  828.   end
  829.   else begin
  830.     newLine := aKey + '=' + aValue;
  831.     ItemIndex := FindItemIndex(aSection, aKey, True, CurrStringList);
  832.     if ItemIndex = -1 then begin
  833.       CurrStringList.Add(newLine);
  834.       FHasChanged := True;
  835.     end
  836.     else begin
  837.       if (CurrStringList[ItemIndex] <> newLine) then
  838.       begin
  839.         FHasChanged := True;
  840.         CurrStringList[ItemIndex] := newLine;
  841.       end;
  842.     end;
  843.   end;
  844. end;
  845. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  846. { read integer value                                                         }
  847. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  848.  
  849. function TBigIniFile.ReadInteger(const aSection, aKey: string;
  850.   aDefault: Longint): Longint;
  851. var
  852.   IStr: string;
  853. begin
  854.   IStr := ReadString(aSection, aKey, '');
  855.   if CompareText(Copy(IStr, 1, 2), '0x') = 0 then
  856.     IStr := '$' + Copy(IStr, 3, 255);
  857.   Result := StrToIntDef(IStr, aDefault);
  858. end;
  859. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  860. { Yes, you guessed right: this procedure writes an integer value             }
  861. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  862.  
  863. procedure TBigIniFile.WriteInteger(const aSection, aKey: string; aValue: Longint);
  864. begin
  865.   WriteString(aSection, aKey, IntToStr(aValue));
  866. end;
  867. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  868. { read boolean value                                                         }
  869. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  870.  
  871. function TBigIniFile.ReadBool(const aSection, aKey: string;
  872.   aDefault: Boolean): Boolean;
  873. begin
  874.   Result := ReadInteger(aSection, aKey, Ord(aDefault)) <> 0;
  875. end;
  876. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  877. { write boolean value                                                        }
  878. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  879.  
  880. procedure TBigIniFile.WriteBool(const aSection, aKey: string; aValue: Boolean);
  881. const
  882.   BoolText: array[Boolean] of string[1] = ('0', '1');
  883. begin
  884.   WriteString(aSection, aKey, BoolText[aValue]);
  885. end;
  886. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  887. { read date value                                                            }
  888. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  889.  
  890. function TBigIniFile.ReadDate(const aSection, aKey: string; aDefault: TDateTime): TDateTime;
  891. var
  892.   DateStr: string;
  893. begin
  894.   DateStr := ReadString(aSection, aKey, '');
  895.   Result := aDefault;
  896.   if DateStr <> '' then
  897.   try
  898.     Result := StrToDate(DateStr);
  899.   except
  900.     on EConvertError do
  901.   else raise;
  902.   end;
  903. end;
  904. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  905. { write date value                                                           }
  906. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  907.  
  908. procedure TBigIniFile.WriteDate(const aSection, aKey: string; aValue: TDateTime);
  909. begin
  910.   WriteString(aSection, aKey, DateToStr(aValue));
  911. end;
  912. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  913. { read DateTime value                                                        }
  914. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  915.  
  916. function TBigIniFile.ReadDateTime(const aSection, aKey: string; aDefault: TDateTime): TDateTime;
  917. var
  918.   DateStr: string;
  919. begin
  920.   DateStr := ReadString(aSection, aKey, '');
  921.   Result := aDefault;
  922.   if DateStr <> '' then
  923.   try
  924.     Result := StrToDateTime(DateStr);
  925.   except
  926.     on EConvertError do
  927.   else raise;
  928.   end;
  929. end;
  930. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  931. { write DateTime value                                                       }
  932. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  933.  
  934. procedure TBigIniFile.WriteDateTime(const aSection, aKey: string; aValue: TDateTime);
  935. begin
  936.   WriteString(aSection, aKey, DateTimeToStr(aValue));
  937. end;
  938. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  939. { read Float value                                                           }
  940. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  941.  
  942. function TBigIniFile.ReadFloat(const aSection, aKey: string; aDefault: Double): Double;
  943. var
  944.   FloatStr: string;
  945. begin
  946.   FloatStr := ReadString(aSection, aKey, '');
  947.   Result := aDefault;
  948.   if FloatStr <> '' then
  949.   try
  950.     Result := StrToFloat(FloatStr);
  951.   except
  952.     on EConvertError do
  953.   else raise;
  954.   end;
  955. end;
  956. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  957. { write Float value                                                          }
  958. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  959.  
  960. procedure TBigIniFile.WriteFloat(const aSection, aKey: string; aValue: Double);
  961. begin
  962.   WriteString(aSection, aKey, FloatToStr(aValue));
  963. end;
  964. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  965. { read Time value                                                            }
  966. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  967.  
  968. function TBigIniFile.ReadTime(const aSection, aKey: string; aDefault: TDateTime): TDateTime;
  969. var
  970.   TimeStr: string;
  971. begin
  972.   TimeStr := ReadString(aSection, aKey, '');
  973.   Result := aDefault;
  974.   if TimeStr <> '' then
  975.   try
  976.     Result := StrToTime(TimeStr);
  977.   except
  978.     on EConvertError do
  979.   else raise;
  980.   end;
  981. end;
  982. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  983. { write Time value                                                           }
  984. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  985.  
  986. procedure TBigIniFile.WriteTime(const aSection, aKey: string; aValue: TDateTime);
  987. begin
  988.   WriteString(aSection, aKey, TimeToStr(aValue));
  989. end;
  990. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  991. { read entire section (hoho, only the item names)                            }
  992. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  993.  
  994. procedure TBigIniFile.ReadSection(const aSection: string; aStrings: TStrings);
  995. var
  996.   SectionIndex: Integer;
  997.   CurrStringList: TStringList;
  998.   ix: Integer;
  999. begin
  1000.   SectionIndex := FSectionList.IndexOf(aSection);
  1001.   if SectionIndex <> -1 then
  1002.   begin
  1003.     aStrings.BeginUpdate;
  1004.     CurrStringList := FSectionList.SectionItems[SectionIndex];
  1005.     for ix := 0 to CurrStringList.count - 1 do
  1006.     begin
  1007.       if CurrStringList.Names[IX] = '' then continue;
  1008.       if FFlagDropCommentLines and (CurrStringList.Names[IX][1] = ';') then continue;
  1009.       aStrings.Add(CurrStringList.Names[ix]);
  1010.     end;
  1011.     aStrings.EndUpdate;
  1012.   end;
  1013. end;
  1014. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1015. { copy all section names to TStrings object                                  }
  1016. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1017.  
  1018. procedure TBigIniFile.ReadSections(aStrings: TStrings);
  1019. begin
  1020.   aStrings.Assign(SectionNames);
  1021. end;
  1022. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1023. { read entire section                                                        }
  1024. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1025.  
  1026. procedure TBigIniFile.ReadSectionValues(const aSection: string; aStrings: TStrings);
  1027. var
  1028.   SectionIndex: Integer;
  1029. begin
  1030.   SectionIndex := FSectionList.IndexOf(aSection);
  1031.   if SectionIndex <> -1 then
  1032.   begin
  1033.     aStrings.BeginUpdate;
  1034.     {In prior versions of TIniFile the target-Strings were _not_ cleared
  1035.     That's why my procedure didn't either. Meanwhile, Borland changed their
  1036.     mind and I added the following line for D5 compatibility.
  1037.     Use ReadAppendSectionValues if needed}
  1038.     if FFlagClearOnReadSectionValues then aStrings.Clear; // new since 3.09,3.10
  1039.     aStrings.AddStrings(FSectionList.SectionItems[SectionIndex]);
  1040.     aStrings.EndUpdate;
  1041.   end;
  1042. end;
  1043. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1044. { copy all 'lines' to TStrings-object                                        }
  1045. { Note [2]: under Delphi 1, ReadAll may cause errors when a TMemo.Lines      }
  1046. {      array is destination and source is greater than 64 KB                 }
  1047. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1048.  
  1049. procedure TBigIniFile.ReadAll(aStrings: TStrings);
  1050. var
  1051.   ixSections: Integer;
  1052.   CurrStringList: TStringList;
  1053. begin
  1054.   aStrings.BeginUpdate;
  1055.   with FSectionList do
  1056.   begin
  1057.     for ixSections := 0 to count - 1 do
  1058.     begin
  1059.       CurrStringList := SectionItems[ixSections];
  1060.       if CurrStringList.count > 0 then
  1061.       begin
  1062.         aStrings.Add('[' + STRINGS[ixSections] + ']');
  1063.         aStrings.AddStrings(CurrStringList);
  1064.         aStrings.Add('');
  1065.       end;
  1066.     end;
  1067.   end;
  1068.   aStrings.EndUpdate;
  1069. end;
  1070. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1071. { flush (save) data to disk                                                  }
  1072. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1073.  
  1074. procedure TBigIniFile.FlushFile;
  1075. var
  1076.   CurrStringList: TStringList;
  1077.   lpTextBuffer: Pointer;
  1078.   Destin: TextFile;
  1079.   ix,
  1080.     ixSections: Integer;
  1081. begin
  1082.   lpTextBuffer := nil; {only to avoid compiler warnings}
  1083.   if FHasChanged then
  1084.   begin
  1085.     if FFileName <> '' then
  1086.     begin
  1087.       Assign(Destin, FFileName);
  1088.       if FTextBufferSize > 0 then
  1089.       begin
  1090.         GetMem(lpTextBuffer, FTextBufferSize);
  1091.         SetTextBuf(Destin, lpTextBuffer^, FTextBufferSize);
  1092.       end;
  1093.       Rewrite(Destin);
  1094.  
  1095.       with FSectionList do
  1096.       begin
  1097.         for ixSections := 0 to count - 1 do
  1098.         begin
  1099.           CurrStringList := SectionItems[ixSections];
  1100.           if CurrStringList.count > 0 then
  1101.           begin
  1102.             WriteLn(Destin, '[', STRINGS[ixSections], ']');
  1103.             for ix := 0 to CurrStringList.count - 1 do
  1104.             begin
  1105.               WriteLn(Destin, CurrStringList[ix]);
  1106.             end;
  1107.             WriteLn(Destin);
  1108.           end;
  1109.         end;
  1110.       end;
  1111.  
  1112.       Close(Destin);
  1113.       if FTextBufferSize > 0 then
  1114.       begin
  1115.         FreeMem(lpTextBuffer, FTextBufferSize);
  1116.       end;
  1117.     end;
  1118.     FHasChanged := False;
  1119.   end;
  1120. end;
  1121. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1122. { Flushes buffered INI file data to disk                                     }
  1123. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1124.  
  1125. procedure TBigIniFile.UpdateFile;
  1126. begin
  1127.   FlushFile;
  1128. end;
  1129. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1130. { erase specified section                                                    }
  1131. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1132.  
  1133. procedure TBigIniFile.EraseSection(const aSection: string);
  1134. var
  1135.   SectionIndex: Integer;
  1136. begin
  1137.   SectionIndex := FSectionList.IndexOf(aSection);
  1138.   if SectionIndex <> -1 then
  1139.   begin
  1140.     FSectionList.SectionItems[SectionIndex].Free;
  1141.     FSectionList.Delete(SectionIndex);
  1142.     FSectionList.FPrevIndex := 0;
  1143.     FHasChanged := True;
  1144.     if FPrevSectionIndex >= FSectionList.count then FPrevSectionIndex := 0;
  1145.   end;
  1146. end;
  1147. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1148. { remove a single key                                                        }
  1149. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1150.  
  1151. procedure TBigIniFile.DeleteKey(const aSection, aKey: string);
  1152. var
  1153.   ItemIndex: Integer;
  1154.   CurrStringList: TStringList;
  1155. begin
  1156.   ItemIndex := FindItemIndex(aSection, aKey, True, CurrStringList);
  1157.   if ItemIndex > -1 then begin
  1158.     FHasChanged := True;
  1159.     CurrStringList.Delete(ItemIndex);
  1160.   end;
  1161. end;
  1162.  
  1163. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1164. { check for existance of a section                                           }
  1165. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1166.  
  1167. function TBigIniFile.HasSection(const aSection: string): Boolean;
  1168. begin
  1169.   Result := (FSectionList.IndexOf(aSection) > -1)
  1170. end;
  1171.  
  1172. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1173. { Indicates whether a section exists                                         }
  1174. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1175.  
  1176. function TBigIniFile.SectionExists(const aSection: string): Boolean;
  1177. begin
  1178.   Result := HasSection(aSection);
  1179. end;
  1180.  
  1181. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1182. { Indicates whether a key exists                                             }
  1183. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1184.  
  1185. function TBigIniFile.ValueExists(const aSection, aValue: string): Boolean;
  1186. var
  1187.   S: TStringList;
  1188. begin
  1189.   S := TStringList.Create;
  1190.   try
  1191.     ReadSection(aSection, S);
  1192.     Result := S.IndexOf(aValue) > -1;
  1193.   finally
  1194.     S.Free;
  1195.   end;
  1196. end;
  1197.  
  1198. {........................................................................... }
  1199. { class TBiggerIniFile                                                       }
  1200. {........................................................................... }
  1201.  
  1202. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1203. { write/replace complete section                                             }
  1204. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1205.  
  1206. procedure TBiggerIniFile.WriteSectionValues(const aSection: string; const aStrings: TStrings);
  1207. var
  1208.   SectionIndex: Integer;
  1209.   FoundStringList: TStringList;
  1210.   ix: Integer;
  1211. begin
  1212.   SectionIndex := FSectionList.IndexOf(aSection);
  1213.   if SectionIndex = -1 then
  1214.   begin
  1215.     { create new section }
  1216.     FoundStringList := TStringList.Create;
  1217.     FSectionList.AddObject(aSection, FoundStringList);
  1218.     FoundStringList.AddStrings(aStrings);
  1219.     FHasChanged := True;
  1220.   end
  1221.   else begin
  1222.     { compare existing section }
  1223.     FoundStringList := FSectionList.SectionItems[SectionIndex];
  1224.     if FoundStringList.count <> aStrings.count then
  1225.     begin
  1226.       { if count differs, replace complete section }
  1227.       FoundStringList.Clear;
  1228.       FoundStringList.AddStrings(aStrings);
  1229.       FHasChanged := True;
  1230.     end
  1231.     else begin
  1232.       { compare line by line }
  1233.       for ix := 0 to FoundStringList.count - 1 do
  1234.       begin
  1235.         if FoundStringList[ix] <> aStrings[ix] then
  1236.         begin
  1237.           FoundStringList[ix] := aStrings[ix];
  1238.           FHasChanged := True;
  1239.         end;
  1240.       end;
  1241.     end;
  1242.   end;
  1243. end;
  1244. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1245. { read a numbered list                                                       }
  1246. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1247.  
  1248. procedure TBiggerIniFile.ReadNumberedList(const Section: string;
  1249.   aStrings: TStrings;
  1250.   Deflt: string;
  1251.   aPrefix: string = '';
  1252.   IndexStart: Integer = 1);
  1253. var
  1254.   maxEntries: Integer;
  1255.   ix: Integer;
  1256. begin
  1257.   maxEntries := ReadInteger(Section, aPrefix + cIniCount, 0);
  1258.   aStrings.BeginUpdate;
  1259.   for ix := 0 to maxEntries - 1 do begin
  1260.     aStrings.Add(ReadString(Section, aPrefix + IntToStr(ix + IndexStart), Deflt));
  1261.   end;
  1262.   aStrings.EndUpdate;
  1263. end;
  1264. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1265. { write a numbered list (TStrings contents)                                  }
  1266. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1267.  
  1268. procedure TBiggerIniFile.WriteNumberedList(const Section: string;
  1269.   aStrings: TStrings;
  1270.   aPrefix: string = '';
  1271.   IndexStart: Integer = 1);
  1272. var
  1273.   prevCount,
  1274.     ix: Integer;
  1275.   prevHasChanged: Boolean;
  1276.   oldSectionValues,
  1277.     newSectionValues: TStringList;
  1278. begin
  1279.   oldSectionValues := TStringList.Create;
  1280.   newSectionValues := TStringList.Create;
  1281.  
  1282.   try
  1283.     { store previous entries }
  1284.     ReadSectionValues(Section, oldSectionValues);
  1285.  
  1286.     prevCount := ReadInteger(Section, aPrefix + cIniCount, 0);
  1287.     WriteInteger(Section, aPrefix + cIniCount, aStrings.count);
  1288.     prevHasChanged := HasChanged;
  1289.  
  1290.     { remove all previous lines to get new ones together }
  1291.     for ix := 0 to prevCount - 1 do begin
  1292.       DeleteKey(Section, aPrefix + IntToStr(ix + IndexStart));
  1293.     end;
  1294.     for ix := 0 to aStrings.count - 1 do begin
  1295.       WriteString(Section, aPrefix + IntToStr(ix + IndexStart), aStrings[ix]);
  1296.     end;
  1297.  
  1298.     { check if entries really had changed }
  1299.     if not prevHasChanged then
  1300.     begin
  1301.       { read new entries and compare with old }
  1302.       ReadSectionValues(Section, newSectionValues);
  1303.       HasChanged := not ListIdentical(newSectionValues, oldSectionValues);
  1304.     end;
  1305.   finally
  1306.     oldSectionValues.Free;
  1307.     newSectionValues.Free;
  1308.   end;
  1309. end;
  1310.  
  1311. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1312. { read a TColor value stored as hex-string                                   }
  1313. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1314.  
  1315. function TBiggerIniFile.ReadColor(const aSection, aKey: string; aDefault: TColor): TColor;
  1316. begin
  1317.   ReadColor := StrToInt('$' + ReadString(aSection, aKey, IntToHex(aDefault, 8)));
  1318. end;
  1319.  
  1320. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1321. { write TColor as hex-string in the form 00bbggrr                            }
  1322. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1323.  
  1324. procedure TBiggerIniFile.WriteColor(const aSection, aKey: string; aValue: TColor);
  1325. begin
  1326.   WriteString(aSection, aKey, IntToHex(aValue, 8));
  1327. end;
  1328.  
  1329. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1330. { read a font's properties                                                   }
  1331. { example: ReadFont('Fonts','Label1',Label1.Font);                           }
  1332. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1333.  
  1334. function TBiggerIniFile.ReadFont(const aSection, aKey: string; aFont: TFont): TFont;
  1335. begin
  1336.   with TCSIFont.Create do begin
  1337.     Value := ReadString(aSection, aKey, '');
  1338.     aFont.Name := FontName;
  1339.     aFont.Size := FontSize;
  1340.     aFont.Style := FontStyle;
  1341.     aFont.Color := FontColor;
  1342.     aFont.Charset := FontCharset;
  1343.     aFont.Pitch := TFontPitch(FontPitch);
  1344.     Free;
  1345.   end;
  1346.   result := aFont;
  1347. end;
  1348.  
  1349. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1350. { writes a font's properties                                                 }
  1351. { example: WriteFont('Fonts','Label1',Label1.Font);                          }
  1352. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1353.  
  1354. procedure TBiggerIniFile.WriteFont(const aSection, aKey: string; aFont: TFont);
  1355. begin
  1356.   with TCSIFont.Create do begin
  1357.     FontName := aFont.Name;
  1358.     FontSize := aFont.Size;
  1359.     FontStyle := aFont.Style;
  1360.     FontColor := aFont.Color;
  1361.     FontCharset := aFont.Charset;
  1362.     FontPitch := Ord(aFont.Pitch);
  1363.     WriteString(aSection, aKey, Value);
  1364.     Free;
  1365.   end;
  1366. end;
  1367.  
  1368. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1369. { renames a section                                                          }
  1370. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1371.  
  1372. procedure TBiggerIniFile.RenameSection(const OldSection, NewSection: string);
  1373. var
  1374.   SectionIndex: Integer;
  1375. begin
  1376.   if NewSection <> OldSection then
  1377.   begin
  1378.     SectionIndex := FSectionList.IndexOf(OldSection);
  1379.     if SectionIndex <> -1 then
  1380.     begin
  1381.       FSectionList[SectionIndex] := NewSection;
  1382.     end;
  1383.     FHasChanged := True;
  1384.   end;
  1385. end;
  1386.  
  1387. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1388. { renames a key                                                              }
  1389. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1390.  
  1391. procedure TBiggerIniFile.RenameKey(const aSection, OldKey, NewKey: string);
  1392. var
  1393.   ItemIndex: Integer;
  1394.   CurrStringList: TStringList;
  1395. begin
  1396.   if NewKey <> OldKey then
  1397.   begin
  1398.     ItemIndex := FindItemIndex(aSection, OldKey, False, CurrStringList);
  1399.     if ItemIndex <> -1 then
  1400.     begin
  1401.       WriteString(aSection, NewKey, ReadString(aSection, OldKey, ''));
  1402.       DeleteKey(aSection, OldKey);
  1403.     end;
  1404.   end;
  1405. end;
  1406.  
  1407. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1408. { reads data into a buffer                                                   }
  1409. { result: actually read bytes                                                }
  1410. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1411.  
  1412. function TBiggerIniFile.ReadBinaryData(const aSection, aKey: string; var Buffer; BufSize: Integer):
  1413.   Integer;
  1414. var
  1415.   ix: Integer;
  1416.   bufPtr: PChar;
  1417.   hexDump: AnsiString;
  1418. begin
  1419.   hexDump := ReadAnsiString(aSection, aKey, '');
  1420.   result := Length(hexDump) div 2;
  1421.   if result > BufSize then result := BufSize;
  1422.  
  1423.   bufPtr := Pointer(Buffer);
  1424.   for ix := 0 to result - 1 do
  1425.   begin
  1426.     Byte(bufPtr[ix]) := StrToIntDef('$' + Copy(hexDump, 1 + ix * 2, 2), 0);
  1427.   end;
  1428. end;
  1429.  
  1430. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1431. { writes data from a buffer                                                  }
  1432. { each represented byte is stored as hexadecimal string                      }
  1433. {. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }
  1434.  
  1435. procedure TBiggerIniFile.WriteBinaryData(const aSection, aKey: string; var Buffer; BufSize:
  1436.   Integer);
  1437. var
  1438.   ix: Integer;
  1439.   bufPtr: PChar;
  1440.   hexDump: AnsiString;
  1441. begin
  1442.   hexDump := '';
  1443.   bufPtr := Pointer(Buffer);
  1444.   for ix := 0 to BufSize - 1 do
  1445.   begin
  1446.     hexDump := hexDump + IntToHex(Byte(bufPtr[ix]), 2);
  1447.   end;
  1448.   WriteAnsiString(aSection, aKey, hexDump);
  1449. end;
  1450.  
  1451. {........................................................................... }
  1452. { class TAppIniFile                                                          }
  1453. {........................................................................... }
  1454.  
  1455. constructor TAppIniFile.Create;
  1456. begin
  1457.   inherited Create(ChangeFileExt(ModuleName(False), '.ini'));
  1458. end;
  1459.  
  1460. {........................................................................... }
  1461. { class TLibIniFile                                                          }
  1462. {........................................................................... }
  1463.  
  1464. constructor TLibIniFile.Create;
  1465. begin
  1466.   inherited Create(ChangeFileExt(ModuleName(True), '.ini'));
  1467. end;
  1468.  
  1469. end.
  1470. { -------------------------------------------------------------------------- }
  1471. { BigIni.PAS                                                   eh 2002-04-14 }
  1472. { Version 4.11                                                               }
  1473. {    Delphi 3/4/5 version                                                    }
  1474. {    for a Delphi 1/2 version, please see homepage URL below                 }
  1475. { Unit to read/write *.ini files even greater than 64 kB                     }
  1476. { (till today, the KERNEL.DLL and KERNEL32.DLL do it NOT).                   }
  1477.  
  1478. { (c) Edy Hinzen 1996-2002 - Freeware                                        }
  1479. { Mailto:Edy@Hinzen.de                 (thanks for the resonance yet!)       }
  1480. { http://www.Hinzen.de                 (where you find the latest version)   }
  1481.  
  1482. { -------------------------------------------------------------------------- }
  1483. { The TBigIniFile object is designed to work like TIniFile from the Borland  }
  1484. { unit called IniFiles.                                                      }
  1485. { The following procedures/functions were added:                             }
  1486. {    procedure FlushFile              write data to disk                     }
  1487. {    procedure ReadAll                copy entire contents to TStrings-object}
  1488. {    procedure AppendFromFile         appends from other *.ini               }
  1489. {    property  SectionNames                                                  }
  1490. {    procedure WriteAnsiString        writes AnsiString types                }
  1491. {    function  ReadAnsiString         reads AnsiString types                 }
  1492.  
  1493. { -------------------------------------------------------------------------- }
  1494. { The TBiggerIniFile object is a child object with some functions that came  }
  1495. { in handy at my projects:                                                   }
  1496. {    property  TextBufferSize                                                }
  1497. {    procedure WriteSectionValues(const aSection: string;                    }
  1498. {                                 const aStrings: TStrings);                 }
  1499. {              analog to ReadSectionValues, replace/write all lines from     }
  1500. {              aStrings into specified section                               }
  1501. {    procedure ReadNumberedList(const Section: string;                       }
  1502. {                              aStrings: TStrings;                           }
  1503. {                              Deflt: String);                               }
  1504. {    procedure WriteNumberedList(const Section: string;                      }
  1505. {                                aStrings: TStrings);                        }
  1506. {    function  ReadColor(const aSection, aKey: string;                       }
  1507. {                        aDefault: TColor): TColor;                          }
  1508. {    procedure WriteColor(const aSection, aKey: string;                      }
  1509. {                         aValue: TColor); virtual;                          }
  1510. {    function  ReadFont(const aSection, aKey: string;                        }
  1511. {                       aFont: TFont): TFont;                                }
  1512. {    procedure WriteFont(const aSection, aKey: string;                       }
  1513. {                          aFont: TFont);                                    }
  1514. {    function  ReadBinaryData(const aSection, aKey: String;                  }
  1515. {                             var Buffer; BufSize: Integer): Integer;        }
  1516. {    procedure WriteBinaryData(const aSection, aKey: String;                 }
  1517. {                              var Buffer; BufSize: Integer);                }
  1518. {    procedure RenameSection(const OldSection, NewSection : String);         }
  1519. {    procedure RenameKey(const aSection, OldKey, NewKey : String);           }
  1520.  
  1521. { -------------------------------------------------------------------------- }
  1522. { The TAppIniFile object is a child again.                                   }
  1523. { It's constructor create has no parameters. The filename is the             }
  1524. { application's exename with with extension '.ini' (instead of '.exe').      }
  1525. {    constructor Create;                                                     }
  1526. { -------------------------------------------------------------------------- }
  1527. { The TLibIniFile object very similar to TAppIniFile.                        }
  1528. { But if the module is a library (e.g. DLL) the library name is used.        }
  1529. {    constructor Create;                                                     }
  1530. { -------------------------------------------------------------------------- }
  1531.  
  1532. { ========================================================================== }
  1533. {   This program is distributed in the hope that it will be useful,          }
  1534. {   but WITHOUT ANY WARRANTY; without even the implied warranty of           }
  1535. {   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                     }
  1536. { ========================================================================== }
  1537.  
  1538. { Programmer's note:                                                         }
  1539. { Okay, this is NOT the fastest code of the world... (the kernel-functions   }
  1540. { xxxxPrivateProfileString aren't, either!). I wrote it as a subproject of   }
  1541. { my EditCdPlayer.EXE which never seems to become finished ...               }
  1542. { Meanwhile, I hope that Microsoft will write new KERNEL routines.           }
  1543.  
  1544. { Version history                                                            }
  1545. { 1.10 faster read by replaceing TStringlist with simple ReadLn instructions }
  1546. {      improved FindItemIndex by storing last results                        }
  1547. { 1.20 Ignore duplicate sections                                             }
  1548. {      improved (for this use) TStringList child TSectionList                }
  1549. { 1.21 fixed 1.20 bug in case of empty file                                  }
  1550. { 1.22 added ReadNumberedList and WriteNumberedList                          }
  1551. { 1.23 Delphi 1.0 backward compatibility e.g. local class TStringList        }
  1552. { 1.24 added AppendFromFile                                                  }
  1553. { 2.00 Changed compare-routines of aSection Parameters to AnsiCompareText    }
  1554. {      to handle case insensitive search in languages with special chars;    }
  1555. {      some efforts to increase speed                                        }
  1556. {      * new web and e-mail address *                                        }
  1557. { 2.01 implemented modifications/suggestions from Gyula MΘszßros,            }
  1558. {      Budapest, Hungary - 100263.1465@compuserve.com                        }
  1559. {procedure TIniFile.ReadSections(aStrings: TStrings);                        }
  1560. {    - The extra 16K file buffer is removeable                               }
  1561. {      see property TextBufferSize                                           }
  1562. {    - comment lines (beginning with ';') can be ignored                     }
  1563. {      set property FlagDropCommentLines to True                             }
  1564. {    - invalid lines (which do not contain an '=' sign) can be ignored       }
  1565. {      set property FlagFilterOutInvalid to True                             }
  1566. {    - white spaces around the '='-sign can be dropped                       }
  1567. {      set property FlagDropWhiteSpace to True                               }
  1568. {    - surrounding single or double apostrophes from keys can be dropped     }
  1569. {      set property FlagDropApostrophes to True                              }
  1570. { 2.01 (continued)                                                           }
  1571. {      property SectionNames is now part of TBigIni (instead of TBiggerIni   }
  1572. {      added procedure ReadSections (seems new in Delphi 3)                  }
  1573. { 2.02 fixed WriteNumberedList bug                                           }
  1574. {      added DeleteKey                                                       }
  1575. {      changed Pos() calls to AnsiPos()                                      }
  1576. { 2.03 minor corrections                                                     }
  1577. { 2.04 new flag FlagTrimRight                                                }
  1578. {      set it true to strip off white spaces at end of line                  }
  1579. { 2.05 fixed bug in EraseSection                                             }
  1580. { 2.06 For Win32 apps, TAppIniFile now creates ini-filename in correct mixed }
  1581. {      case                                                                  }
  1582. {      added HasChanged-check routine in WriteNumberedList                   }
  1583. { 2.07 added note [1] and [2]                                                }
  1584. {      used new function ListIdentical instead of property named text within }
  1585. {      WriteNumberedList for backward-compatibility                          }
  1586. { 3.01 fixed another bug in EraseSection (variable FPrevSectionIndex)        }
  1587. { 3.02 dropped some $IFDEFS related to prior (Delphi 1/2) compatibility code }
  1588. { 3.03 added ReadColor / WriteColor                                          }
  1589. { 3.04 added notice about incombatibility with TMemIniFile.ReadSectionValues }
  1590. { 3.05 fixed TTextBufferSize vs. IniBufferSize bug                           }
  1591. { 3.06 added TBigIniFile.HasSection                                          }
  1592. { 3.07 fixed ClearSectionList bug (variable FPrevIndex)                      }
  1593. { 3.08 fixed EraseDuplicates memory-bug                                      }
  1594. { 3.09 inproved ReadSection: empty and commented tags are removed            }
  1595. {      ReadSectionValues now clears target TStrings (if flag set, see 3.10)  }
  1596. {      improved handling of TStrings by using BeginUpdate, EndUpdate         }
  1597. { 3.10 partly revided 3.09 change by adding FFlagClearOnReadSectionValues    }
  1598. { 3.11 added TLibIniFile and ModuleName                                      }
  1599. { 3.20 new Methods (for Delphi 5 IniFiles compatibility):                    }
  1600. {      clear,                                                                }
  1601. {      UpdateFile (same as FlushFile),                                       }
  1602. {      SectionExists (same as HasSection),                                   }
  1603. {      ReadDate, WriteDate, ReadDateTime, WriteDateTime,                     }
  1604. {      ReadFloat, WriteFloat, ReadTime, WriteTime                            }
  1605. { 3.21 Added some exception-handling                                         }
  1606. { 4.00 Introduced tool-class TCommaSeparatedInfo                             }
  1607. {      Added TBigIniFile.ReadFont, TBigIniFile.WriteFont                     }
  1608. { 4.01 Added TBigIniFile.ReadAnsiString,TBigIniFile.WriteAnsiString          }
  1609. {      added TBiggerIniFile.RenameSection,TBiggerIniFile.RenameKey           }
  1610. {      added TBiggerIniFile.ReadBinaryData,TBiggerIniFile.WriteBinaryData    }
  1611. { 4.02 Added compiler directive "$DEFINE UseShortStrings"                    }
  1612. { 4.03 improved ReadString performance                                       }
  1613. { 4.04 Added TBigIniFile.ValueExists                                         }
  1614. { 4.05 fixed HasChanged-bug in RenameSection                                 }
  1615. { 4.10 $DEFINE UseShortStrings deactivated; now uses wide strings as default }
  1616. { 4.11 ReadNumberedList, WriteNumberedList have new (defaulted) parameters   }
  1617. { -------------------------------------------------------------------------- }
  1618.  
  1619. { -------------------------------------------------------------------------- }
  1620. { Question: how can I set these properties _before_ the file is opened?      }
  1621. { Answer: call create with empty filename, look at this sample:              }
  1622. {       myIniFile := TBigIniFile.Create('');                                 }
  1623. {       myIniFile.FlagDropCommentLines := True;                              }
  1624. {       myIniFile.FileName := ('my.ini');                                    }
  1625. {........................................................................... }
  1626. { Question: how can I write comment lines into the file?                     }
  1627. { Answer: like this:                                                         }
  1628. {       tempStringList := TStringList.Create;                                }
  1629. {       tempStringList.Add('; this is a comment line.');                     }
  1630. {       BiggerIniFile.WriteSectionValues('important note',TempStringList);   }
  1631. {       BiggerIniFile.FlushFile;                                             }
  1632. {       tempStringList.Free;                                                 }
  1633. { -------------------------------------------------------------------------- }
  1634.  
  1635.