StrHlder.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:20k
源码类别:

Delphi控件源码

开发平台:

Delphi

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