home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 September / Chip_2001-09_cd1.bin / zkuste / delphi / kolekce / d6 / RX275D6.ZIP / Units / StrHlder.pas < prev    next >
Pascal/Delphi Source File  |  2001-06-24  |  20KB  |  771 lines

  1. {*******************************************************}
  2. {                                                       }
  3. {         Delphi VCL Extensions (RX)                    }
  4. {                                                       }
  5. {         Copyright (c) 1996 AO ROSNO                   }
  6. {         Copyright (c) 1997, 1998 Master-Bank          }
  7. {                                                       }
  8. {*******************************************************}
  9.  
  10. unit StrHlder;
  11.  
  12. interface
  13.  
  14. {$I RX.INC}
  15.  
  16. uses SysUtils, Classes, Variants, RTLConsts;
  17.  
  18. type
  19.  
  20. {$IFDEF RX_D3}
  21.  
  22. { TMacro }
  23.  
  24.   TMacros = class;
  25.   TMacroTextEvent = procedure(Sender: TObject; Data: Variant; 
  26.     var Text: string) of object;
  27.   
  28.   TMacro = class(TCollectionItem)
  29.   private
  30.     FName: string;
  31.     FData: Variant;
  32.     FOnGetText: TMacroTextEvent;
  33.     function IsMacroStored: Boolean;
  34.     function GetText: string;
  35.     function GetMacros: TMacros;
  36.   protected
  37.     function GetDisplayName: string; override;
  38.     procedure SetDisplayName(const Value: string); override;
  39.     procedure GetMacroText(var AText: string);
  40.     function GetAsVariant: Variant;
  41.     procedure SetAsVariant(Value: Variant);
  42.   public
  43.     constructor Create(Collection: TCollection); override;
  44.     procedure Assign(Source: TPersistent); override;
  45.     procedure Clear;
  46.     function IsEqual(Value: TMacro): Boolean;
  47.     property Macros: TMacros read GetMacros;
  48.     property Text: string read GetText;
  49.   published
  50.     property Name: string read FName write SetDisplayName;
  51.     property Value: Variant read GetAsVariant write SetAsVariant stored IsMacroStored;
  52.     property OnGetText: TMacroTextEvent read FOnGetText write FOnGetText;
  53.   end;
  54.  
  55. { TMacros }
  56.  
  57.   TMacros = class({$IFDEF RX_D4}TOwnedCollection{$ELSE}TCollection{$ENDIF})
  58.   private
  59.     function GetMacroValue(const MacroName: string): Variant;
  60.     procedure SetMacroValue(const MacroName: string;
  61.       const Value: Variant);
  62.     function GetItem(Index: Integer): TMacro;
  63.     procedure SetItem(Index: Integer; Value: TMacro);
  64.   public
  65. {$IFDEF RX_D4}
  66.     constructor Create(AOwner: TPersistent);
  67. {$ELSE}
  68.     constructor Create;
  69. {$ENDIF}
  70.     procedure AssignValues(Value: TMacros);
  71.     procedure AddMacro(Value: TMacro);
  72.     procedure RemoveMacro(Value: TMacro);
  73.     function CreateMacro(const MacroName: string): TMacro;
  74.     procedure GetMacroList(List: TList; const MacroNames: string);
  75.     function IndexOf(const AName: string): Integer;
  76.     function IsEqual(Value: TMacros): Boolean;
  77.     function ParseString(const Value: string; DoCreate: Boolean; 
  78.       SpecialChar: Char): string;
  79.     function MacroByName(const Value: string): TMacro;
  80.     function FindMacro(const Value: string): TMacro;
  81.     property Items[Index: Integer]: TMacro read GetItem write SetItem; default;
  82.     property MacroValues[const MacroName: string]: Variant read GetMacroValue write SetMacroValue;
  83.   end;
  84.  
  85. {$ENDIF RX_D3}
  86.  
  87. { TStrHolder }
  88.  
  89.   TStrHolder = class(TComponent)
  90.   private
  91.     FStrings: TStrings;
  92.     FXorKey: string;
  93.     FReserved: Integer;
  94. {$IFDEF RX_D3}
  95.     FMacros: TMacros;
  96.     FMacroChar: Char;
  97.     FOnExpandMacros: TNotifyEvent;
  98. {$ENDIF}
  99.     FOnChange: TNotifyEvent;
  100.     FOnChanging: TNotifyEvent;
  101.     function GetDuplicates: TDuplicates;
  102.     procedure SetDuplicates(Value: TDuplicates);
  103.     function GetSorted: Boolean;
  104.     procedure SetSorted(Value: Boolean);
  105.     procedure SetStrings(Value: TStrings);
  106.     procedure StringsChanged(Sender: TObject);
  107.     procedure StringsChanging(Sender: TObject);
  108.     procedure ReadStrings(Reader: TReader);
  109.     procedure WriteStrings(Writer: TWriter);
  110.     procedure ReadVersion(Reader: TReader);
  111.     procedure WriteVersion(Writer: TWriter);
  112. {$IFDEF WIN32}
  113.     function GetCommaText: string;
  114.     procedure SetCommaText(const Value: string);
  115. {$ENDIF}
  116. {$IFDEF RX_D3}
  117.     function GetCapacity: Integer;
  118.     procedure SetCapacity(NewCapacity: Integer);
  119. {$ENDIF}
  120. {$IFDEF RX_D3}
  121.     procedure SetMacros(Value: TMacros);
  122.     procedure RecreateMacros;
  123.     procedure SetMacroChar(Value: Char);
  124. {$ENDIF}
  125.   protected
  126.     procedure AssignTo(Dest: TPersistent); override;
  127.     procedure DefineProperties(Filer: TFiler); override;
  128.     procedure Changed; dynamic;
  129.     procedure Changing; dynamic;
  130. {$IFDEF RX_D3}
  131.     procedure BeforeExpandMacros; dynamic;
  132. {$ENDIF}
  133.   public
  134.     constructor Create(AOwner: TComponent); override;
  135.     destructor Destroy; override;
  136.     procedure Assign(Source: TPersistent); override;
  137.     procedure Clear;
  138. {$IFDEF RX_D3}
  139.     function MacroCount: Integer;
  140.     function MacroByName(const MacroName: string): TMacro;
  141.     function ExpandMacros: string;
  142. {$ENDIF}
  143. {$IFDEF WIN32}
  144.     property CommaText: string read GetCommaText write SetCommaText;
  145. {$ENDIF}
  146.   published
  147. {$IFDEF RX_D3}
  148.     property Capacity: Integer read GetCapacity write SetCapacity default 0;
  149.     property MacroChar: Char read FMacroChar write SetMacroChar default '%';
  150.     property Macros: TMacros read FMacros write SetMacros;
  151.     property OnExpandMacros: TNotifyEvent read FOnExpandMacros write FOnExpandMacros;
  152. {$ENDIF}
  153.     property Duplicates: TDuplicates read GetDuplicates write SetDuplicates
  154.       default dupIgnore;
  155.     property KeyString: string read FXorKey write FXorKey stored False;
  156.     property Sorted: Boolean read GetSorted write SetSorted default False;
  157.     property Strings: TStrings read FStrings write SetStrings stored False;
  158.     property OnChange: TNotifyEvent read FOnChange write FOnChange;
  159.     property OnChanging: TNotifyEvent read FOnChanging write FOnChanging;
  160.   end;
  161.  
  162. implementation
  163.  
  164. uses
  165. {$IFDEF RX_D3}
  166.   Consts,
  167. {$ENDIF}
  168.   rxStrUtils;
  169.  
  170. const
  171.   XorVersion = 1;
  172.  
  173. {$IFDEF RX_D3}
  174.  
  175. function ExtractName(const Items: string; var Pos: Integer): string;
  176. var
  177.   I: Integer;
  178. begin
  179.   I := Pos;
  180.   while (I <= Length(Items)) and (Items[I] <> ';') do Inc(I);
  181.   Result := Trim(Copy(Items, Pos, I - Pos));
  182.   if (I <= Length(Items)) and (Items[I] = ';') then Inc(I);
  183.   Pos := I;
  184. end;
  185.  
  186. function NameDelimiter(C: Char; Delims: TCharSet): Boolean;
  187. begin
  188.   Result := (C in [' ', ',', ';', ')', #13, #10]) or (C in Delims);
  189. end;
  190.  
  191. function IsLiteral(C: Char): Boolean;
  192. begin
  193.   Result := C in ['''', '"'];
  194. end;
  195.  
  196. procedure CreateMacros(List: TMacros; const Value: PChar; SpecialChar: Char; Delims: TCharSet);
  197. var
  198.   CurPos, StartPos: PChar;
  199.   CurChar: Char;
  200.   Literal: Boolean;
  201.   EmbeddedLiteral: Boolean;
  202.   Name: string;
  203.  
  204.   function StripLiterals(Buffer: PChar): string;
  205.   var
  206.     Len: Word;
  207.     TempBuf: PChar;
  208.  
  209.     procedure StripChar(Value: Char);
  210.     begin
  211.       if TempBuf^ = Value then
  212.         StrMove(TempBuf, TempBuf + 1, Len - 1);
  213.       if TempBuf[StrLen(TempBuf) - 1] = Value then
  214.         TempBuf[StrLen(TempBuf) - 1] := #0;
  215.     end;
  216.  
  217.   begin
  218.     Len := StrLen(Buffer) + 1;
  219.     TempBuf := AllocMem(Len);
  220.     Result := '';
  221.     try
  222.       StrCopy(TempBuf, Buffer);
  223.       StripChar('''');
  224.       StripChar('"');
  225.       Result := StrPas(TempBuf);
  226.     finally
  227.       FreeMem(TempBuf, Len);
  228.     end;
  229.   end;
  230.  
  231. begin
  232.   if SpecialChar = #0 then Exit;
  233.   CurPos := Value;
  234.   Literal := False;
  235.   EmbeddedLiteral := False;
  236.   repeat
  237.     CurChar := CurPos^;
  238.     if (CurChar = SpecialChar) and not Literal and ((CurPos + 1)^ <> SpecialChar) then
  239.     begin
  240.       StartPos := CurPos;
  241.       while (CurChar <> #0) and (Literal or not NameDelimiter(CurChar, Delims)) do begin
  242.         Inc(CurPos);
  243.         CurChar := CurPos^;
  244.         if IsLiteral(CurChar) then begin
  245.           Literal := Literal xor True;
  246.           if CurPos = StartPos + 1 then EmbeddedLiteral := True;
  247.         end;
  248.       end;
  249.       CurPos^ := #0;
  250.       if EmbeddedLiteral then begin
  251.         Name := StripLiterals(StartPos + 1);
  252.         EmbeddedLiteral := False;
  253.       end
  254.       else Name := StrPas(StartPos + 1);
  255.       if Assigned(List) then begin
  256.         if List.FindMacro(Name) = nil then
  257.           List.CreateMacro(Name);
  258.       end;
  259.       CurPos^ := CurChar;
  260.       StartPos^ := '?';
  261.       Inc(StartPos);
  262.       StrMove(StartPos, CurPos, StrLen(CurPos) + 1);
  263.       CurPos := StartPos;
  264.     end
  265.     else if (CurChar = SpecialChar) and not Literal and ((CurPos + 1)^ = SpecialChar) then
  266.       StrMove(CurPos, CurPos + 1, StrLen(CurPos) + 1)
  267.     else if IsLiteral(CurChar) then Literal := Literal xor True;
  268.     Inc(CurPos);
  269.   until CurChar = #0;
  270. end;
  271.  
  272. { TMacro }
  273.  
  274. constructor TMacro.Create(Collection: TCollection);
  275. begin
  276.   inherited Create(Collection);
  277.   FData := Unassigned;
  278. end;
  279.  
  280. procedure TMacro.Assign(Source: TPersistent);
  281. begin
  282.   if (Source is TMacro) and (Source <> nil) then begin
  283.     if VarIsEmpty(TMacro(Source).FData) then Clear
  284.     else Value := TMacro(Source).FData;
  285.     Name := TMacro(Source).Name;
  286.   end;
  287. end;
  288.  
  289. function TMacro.GetDisplayName: string;
  290. begin
  291.   if FName = '' then 
  292.     Result := inherited GetDisplayName 
  293.   else 
  294.     Result := FName;
  295. end;
  296.  
  297. procedure TMacro.SetDisplayName(const Value: string);
  298. begin
  299.   if (Value <> '') and (AnsiCompareText(Value, FName) <> 0) and
  300.     (Collection is TMacros) and (TMacros(Collection).IndexOf(Value) >= 0) then
  301.     raise Exception.Create(SDuplicateString);    
  302.   FName := Value;
  303.   inherited;
  304. end;
  305.  
  306. procedure TMacro.GetMacroText(var AText: string);
  307. begin
  308.   if Assigned(FOnGetText) then FOnGetText(Self, FData, AText);
  309. end;
  310.  
  311. function TMacro.GetText: string;
  312. begin
  313.   Result := FData;
  314.   GetMacroText(Result);
  315. end;
  316.  
  317. function TMacro.GetMacros: TMacros;
  318. begin
  319.   if Collection is TMacros then 
  320.     Result := TMacros(Collection)
  321.   else 
  322.     Result := nil;
  323. end;
  324.  
  325. procedure TMacro.Clear;
  326. begin
  327.   FData := Unassigned;
  328. end;
  329.  
  330. function TMacro.IsMacroStored: Boolean;
  331. begin
  332.   Result := not VarIsEmpty(FData);
  333. end;
  334.  
  335. function TMacro.GetAsVariant: Variant;
  336. begin
  337.   Result := FData;
  338. end;
  339.  
  340. procedure TMacro.SetAsVariant(Value: Variant);
  341. begin
  342.   FData := Value;
  343. end;
  344.  
  345. function TMacro.IsEqual(Value: TMacro): Boolean;
  346. begin
  347.   Result := (VarType(FData) = VarType(Value.FData)) and
  348.     (VarIsEmpty(FData) or (FData = Value.FData)) and
  349.     (Name = Value.Name);
  350. end;
  351.  
  352. { TMacros }
  353.  
  354. {$IFDEF RX_D4}
  355. constructor TMacros.Create(AOwner: TPersistent);
  356. begin
  357.   inherited Create(AOwner, TMacro);
  358. end;
  359. {$ELSE}
  360. constructor TMacros.Create;
  361. begin
  362.   inherited Create(TMacro);
  363. end;
  364. {$ENDIF}
  365.  
  366. function TMacros.IndexOf(const AName: string): Integer;
  367. begin
  368.   for Result := 0 to Count - 1 do
  369.     if AnsiCompareText(TMacro(Items[Result]).Name, AName) = 0 then Exit;
  370.   Result := -1;
  371. end;
  372.  
  373. function TMacros.GetItem(Index: Integer): TMacro;
  374. begin
  375.   Result := TMacro(inherited Items[Index]);
  376. end;
  377.  
  378. procedure TMacros.SetItem(Index: Integer; Value: TMacro);
  379. begin
  380.   inherited SetItem(Index, TCollectionItem(Value));
  381. end;
  382.  
  383. procedure TMacros.AddMacro(Value: TMacro);
  384. begin
  385.   Value.Collection := Self;
  386. end;
  387.  
  388. procedure TMacros.RemoveMacro(Value: TMacro);
  389. begin
  390.   if Value.Collection = Self then
  391.     Value.Collection := nil;
  392. end;
  393.  
  394. function TMacros.CreateMacro(const MacroName: string): TMacro;
  395. begin
  396.   Result := Add as TMacro;
  397.   Result.Name := MacroName;
  398. end;
  399.  
  400. function TMacros.IsEqual(Value: TMacros): Boolean;
  401. var
  402.   I: Integer;
  403. begin
  404.   Result := Count = Value.Count;
  405.   if Result then
  406.     for I := 0 to Count - 1 do begin
  407.       Result := Items[I].IsEqual(Value.Items[I]);
  408.       if not Result then Break;
  409.     end;
  410. end;
  411.  
  412. function TMacros.MacroByName(const Value: string): TMacro;
  413. begin
  414.   Result := FindMacro(Value);
  415.   if Result = nil then
  416.     raise Exception.Create(SInvalidPropertyValue);
  417. end;
  418.  
  419. function TMacros.FindMacro(const Value: string): TMacro;
  420. var
  421.   I: Integer;
  422. begin
  423.   for I := 0 to Count - 1 do begin
  424.     Result := TMacro(inherited Items[I]);
  425.     if AnsiCompareText(Result.Name, Value) = 0 then Exit;
  426.   end;
  427.   Result := nil;
  428. end;
  429.  
  430. procedure TMacros.AssignValues(Value: TMacros);
  431. var
  432.   I: Integer;
  433.   P: TMacro;
  434. begin
  435.   BeginUpdate;
  436.   try
  437.     for I := 0 to Value.Count - 1 do begin
  438.       P := FindMacro(Value[I].Name);
  439.       if P <> nil then P.Assign(Value[I]);
  440.     end;
  441.   finally
  442.     EndUpdate;
  443.   end;
  444. end;
  445.  
  446. function TMacros.ParseString(const Value: string; DoCreate: Boolean; 
  447.   SpecialChar: Char): string;
  448. var
  449.   Macros: TMacros;
  450. begin
  451.   Result := Value;
  452.   Macros := TMacros.Create{$IFDEF RX_D4}(Self.GetOwner){$ENDIF};
  453.   try
  454.     CreateMacros(Macros, PChar(Result), SpecialChar, ['.']);
  455.     if DoCreate then begin
  456.       Macros.AssignValues(Self);
  457.       Self.Assign(Macros);
  458.     end;
  459.   finally
  460.     Macros.Free;
  461.   end;
  462. end;
  463.  
  464. function TMacros.GetMacroValue(const MacroName: string): Variant;
  465. var
  466.   I: Integer;
  467.   Macros: TList;
  468. begin
  469.   if Pos(';', MacroName) <> 0 then begin
  470.     Macros := TList.Create;
  471.     try
  472.       GetMacroList(Macros, MacroName);
  473.       Result := VarArrayCreate([0, Macros.Count - 1], varVariant);
  474.       for I := 0 to Macros.Count - 1 do
  475.         Result[I] := TMacro(Macros[I]).Value;
  476.     finally
  477.       Macros.Free;
  478.     end;
  479.   end 
  480.   else Result := MacroByName(MacroName).Value;
  481. end;
  482.  
  483. procedure TMacros.SetMacroValue(const MacroName: string;
  484.   const Value: Variant);
  485. var
  486.   I: Integer;
  487.   Macros: TList;
  488. begin
  489.   if Pos(';', MacroName) <> 0 then begin
  490.     Macros := TList.Create;
  491.     try
  492.       GetMacroList(Macros, MacroName);
  493.       for I := 0 to Macros.Count - 1 do
  494.         TMacro(Macros[I]).Value := Value[I];
  495.     finally
  496.       Macros.Free;
  497.     end;
  498.   end 
  499.   else MacroByName(MacroName).Value := Value;
  500. end;
  501.  
  502. procedure TMacros.GetMacroList(List: TList; const MacroNames: string);
  503. var
  504.   Pos: Integer;
  505. begin
  506.   Pos := 1;
  507.   while Pos <= Length(MacroNames) do
  508.     List.Add(MacroByName(ExtractName(MacroNames, Pos)));
  509. end;
  510.  
  511. {$ENDIF RX_D3}
  512.  
  513. { TStrHolder }
  514.  
  515. constructor TStrHolder.Create(AOwner: TComponent);
  516. begin
  517.   inherited Create(AOwner);
  518.   FStrings := TStringList.Create;
  519. {$IFDEF RX_D3}
  520.   FMacros := TMacros.Create{$IFDEF RX_D4}(Self){$ENDIF};
  521.   FMacroChar := '%';
  522. {$ENDIF}
  523.   TStringList(FStrings).OnChange := StringsChanged;
  524.   TStringList(FStrings).OnChanging := StringsChanging;
  525. end;
  526.  
  527. destructor TStrHolder.Destroy;
  528. begin
  529.   FOnChange := nil;
  530.   FOnChanging := nil;
  531. {$IFDEF RX_D3}
  532.   FMacros.Free;
  533. {$ENDIF}
  534.   FStrings.Free;
  535.   inherited Destroy;
  536. end;
  537.  
  538. procedure TStrHolder.Assign(Source: TPersistent);
  539. begin
  540.   if Source is TStrings then
  541.     FStrings.Assign(Source)
  542.   else if Source is TStrHolder then
  543.     FStrings.Assign(TStrHolder(Source).Strings)
  544.   else
  545.     inherited Assign(Source);
  546. end;
  547.  
  548. procedure TStrHolder.AssignTo(Dest: TPersistent);
  549. begin
  550.   if Dest is TStrings then
  551.     Dest.Assign(Strings)
  552.   else
  553.     inherited AssignTo(Dest);
  554. end;
  555.  
  556. procedure TStrHolder.Changed;
  557. begin
  558.   if Assigned(FOnChange) then FOnChange(Self);
  559. end;
  560.  
  561. procedure TStrHolder.Changing;
  562. begin
  563.   if Assigned(FOnChanging) then FOnChanging(Self);
  564. end;
  565.  
  566. procedure TStrHolder.Clear;
  567. begin
  568.   FStrings.Clear;
  569. end;
  570.  
  571. {$IFDEF WIN32}
  572. function TStrHolder.GetCommaText: string;
  573. begin
  574.   Result := FStrings.CommaText;
  575. end;
  576.  
  577. procedure TStrHolder.SetCommaText(const Value: string);
  578. begin
  579.   FStrings.CommaText := Value;
  580. end;
  581. {$ENDIF WIN32}
  582.  
  583. {$IFDEF RX_D3}
  584. function TStrHolder.GetCapacity: Integer;
  585. begin
  586.   Result := FStrings.Capacity;
  587. end;
  588.  
  589. procedure TStrHolder.SetCapacity(NewCapacity: Integer);
  590. begin
  591.   FStrings.Capacity := NewCapacity;
  592. end;
  593. {$ENDIF RX_D3}
  594.  
  595. {$IFDEF RX_D3}
  596. procedure TStrHolder.BeforeExpandMacros;
  597. begin
  598.   if Assigned(FOnExpandMacros) then FOnExpandMacros(Self);
  599. end;
  600.  
  601. procedure TStrHolder.SetMacros(Value: TMacros);
  602. begin
  603.   FMacros.AssignValues(Value);
  604. end;
  605.  
  606. procedure TStrHolder.RecreateMacros;
  607. begin
  608.   if not (csReading in ComponentState) then
  609.     Macros.ParseString(FStrings.Text, True, MacroChar);
  610. end;
  611.  
  612. procedure TStrHolder.SetMacroChar(Value: Char); 
  613. begin
  614.   if Value <> FMacroChar then begin
  615.     FMacroChar := Value;
  616.     RecreateMacros;
  617.   end;
  618. end;
  619.  
  620. function TStrHolder.MacroCount: Integer;
  621. begin
  622.   Result := Macros.Count;
  623. end;
  624.  
  625. function TStrHolder.MacroByName(const MacroName: string): TMacro;
  626. begin
  627.   Result := Macros.MacroByName(MacroName);
  628. end;
  629.  
  630. function TStrHolder.ExpandMacros: string;
  631. var
  632.   I, J, P, LiteralChars: Integer;
  633.   Macro: TMacro;
  634.   Found: Boolean;
  635. begin
  636.   BeforeExpandMacros;
  637.   Result := FStrings.Text;
  638.   for I := Macros.Count - 1 downto 0 do begin
  639.     Macro := Macros[I];
  640.     if VarIsEmpty(Macro.FData) then Continue;
  641.     repeat
  642.       P := Pos(MacroChar + Macro.Name, Result);
  643.       Found := (P > 0) and ((Length(Result) = P + Length(Macro.Name)) or
  644.         NameDelimiter(Result[P + Length(Macro.Name) + 1], ['.']));
  645.       if Found then begin
  646.         LiteralChars := 0;
  647.         for J := 1 to P - 1 do
  648.           if IsLiteral(Result[J]) then Inc(LiteralChars);
  649.         Found := LiteralChars mod 2 = 0;
  650.         if Found then begin
  651.           Result := Copy(Result, 1, P - 1) + Macro.Text + Copy(Result,
  652.             P + Length(Macro.Name) + 1, MaxInt);
  653.         end;
  654.       end;
  655.     until not Found;
  656.   end;
  657. end;
  658. {$ENDIF RX_D3}
  659.  
  660. procedure TStrHolder.DefineProperties(Filer: TFiler);
  661.  
  662.   function DoWrite: Boolean;
  663. {$IFDEF WIN32}
  664.   var
  665.     I: Integer;
  666.     Ancestor: TStrHolder;
  667. {$ENDIF}
  668.   begin
  669. {$IFDEF WIN32}
  670.     Ancestor := TStrHolder(Filer.Ancestor);
  671.     Result := False;
  672.     if (Ancestor <> nil) and (Ancestor.FStrings.Count = FStrings.Count) and
  673.       (KeyString = Ancestor.KeyString) and (FStrings.Count > 0) then
  674.       for I := 0 to FStrings.Count - 1 do begin
  675.         Result := CompareText(FStrings[I], Ancestor.FStrings[I]) <> 0;
  676.         if Result then Break;
  677.       end
  678.     else Result := (FStrings.Count > 0) or (Length(KeyString) > 0);
  679. {$ELSE}
  680.     Result := (FStrings.Count > 0) or (Length(KeyString) > 0);
  681. {$ENDIF}
  682.   end;
  683.  
  684. begin
  685.   inherited DefineProperties(Filer);
  686.   { for backward compatibility }
  687.   Filer.DefineProperty('InternalVer', ReadVersion, WriteVersion,
  688.     {$IFDEF WIN32} Filer.Ancestor = nil {$ELSE} False {$ENDIF});
  689.   Filer.DefineProperty('StrData', ReadStrings, WriteStrings, DoWrite);
  690. end;
  691.  
  692. function TStrHolder.GetSorted: Boolean;
  693. begin
  694.   Result := TStringList(FStrings).Sorted;
  695. end;
  696.  
  697. function TStrHolder.GetDuplicates: TDuplicates;
  698. begin
  699.   Result := TStringList(FStrings).Duplicates;
  700. end;
  701.  
  702. procedure TStrHolder.ReadStrings(Reader: TReader);
  703. begin
  704.   Reader.ReadListBegin;
  705.   if not Reader.EndOfList then KeyString := Reader.ReadString;
  706.   FStrings.Clear;
  707.   while not Reader.EndOfList do
  708.     if FReserved >= XorVersion then
  709.       FStrings.Add(XorDecode(KeyString, Reader.ReadString))
  710.     else
  711.       FStrings.Add(XorString(KeyString, Reader.ReadString));
  712.   Reader.ReadListEnd;
  713. end;
  714.  
  715. procedure TStrHolder.SetDuplicates(Value: TDuplicates);
  716. begin
  717.   TStringList(FStrings).Duplicates := Value;
  718. end;
  719.  
  720. procedure TStrHolder.SetSorted(Value: Boolean);
  721. begin
  722.   TStringList(FStrings).Sorted := Value;
  723. end;
  724.  
  725. procedure TStrHolder.SetStrings(Value: TStrings);
  726. begin
  727.   FStrings.Assign(Value);
  728. end;
  729.  
  730. procedure TStrHolder.StringsChanged(Sender: TObject);
  731. begin
  732. {$IFDEF RX_D3}
  733.   RecreateMacros;
  734. {$ENDIF}
  735.   if not (csReading in ComponentState) then Changed;
  736. end;
  737.  
  738. procedure TStrHolder.StringsChanging(Sender: TObject);
  739. begin
  740.   if not (csReading in ComponentState) then Changing;
  741. end;
  742.  
  743. procedure TStrHolder.WriteStrings(Writer: TWriter);
  744. var
  745.   I: Integer;
  746. begin
  747.   Writer.WriteListBegin;
  748.   Writer.WriteString(KeyString);
  749.   for I := 0 to FStrings.Count - 1 do
  750. {$IFDEF WIN32}
  751.     Writer.WriteString(XorEncode(KeyString, FStrings[I]));
  752. {$ELSE}
  753.     Writer.WriteString(XorString(KeyString, FStrings[I]));
  754. {$ENDIF}
  755.   Writer.WriteListEnd;
  756. end;
  757.  
  758. procedure TStrHolder.ReadVersion(Reader: TReader);
  759. begin
  760.   FReserved := Reader.ReadInteger;
  761. end;
  762.  
  763. procedure TStrHolder.WriteVersion(Writer: TWriter);
  764. begin
  765. {$IFDEF WIN32}
  766.   Writer.WriteInteger(XorVersion);
  767. {$ENDIF}
  768. end;
  769.  
  770. end.
  771.