mirror of
				https://gitlab.com/freepascal.org/lazarus/lazarus.git
				synced 2025-11-04 13:29:26 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1619 lines
		
	
	
		
			50 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			1619 lines
		
	
	
		
			50 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{
 | 
						|
 *****************************************************************************
 | 
						|
  This file is part of the Lazarus Component Library (LCL)
 | 
						|
 | 
						|
  See the file COPYING.modifiedLGPL.txt, included in this distribution,
 | 
						|
  for details about the license.
 | 
						|
 *****************************************************************************
 | 
						|
 | 
						|
Component serialisation into Pascal.
 | 
						|
 | 
						|
Author: Mattias Gaertner
 | 
						|
 | 
						|
Working:
 | 
						|
- signature begin, end, version
 | 
						|
- boolean, set of boolean
 | 
						|
- char, widechar, custom char, set of custom char
 | 
						|
- integers, custom int, set of custom int
 | 
						|
- strings, codepage system and UTF8
 | 
						|
- float, currency
 | 
						|
- enum, custom enum range
 | 
						|
- set of enum, set of custom enum range
 | 
						|
- variant: integers, boolean, string, floats, currency
 | 
						|
- method
 | 
						|
- persistent
 | 
						|
- component children, use SetParentComponent or optional Parent:=
 | 
						|
- collection
 | 
						|
- IInterfaceComponentReference
 | 
						|
- with ancestor
 | 
						|
- ancestor: change ComponentIndex -> call SetChildPos
 | 
						|
- reference foreign root, reference foreign component
 | 
						|
- create components before setting properties to avoid having to set references
 | 
						|
  later
 | 
						|
- inline component, csInline, call SetInline, inherited inline, inline on inherited
 | 
						|
- TComponent.Left/Right via DesignInfo
 | 
						|
- DefineProperties
 | 
						|
- RegisterDefinePropertiesPas
 | 
						|
}
 | 
						|
 | 
						|
unit CompWriterPas;
 | 
						|
 | 
						|
{$mode objfpc}{$H+}
 | 
						|
 | 
						|
{off $DEFINE VerboseCompWriterPas}
 | 
						|
 | 
						|
interface
 | 
						|
 | 
						|
uses
 | 
						|
  Classes, SysUtils, typinfo, RtlConsts, contnrs, LazLoggerBase, LazUTF8;
 | 
						|
 | 
						|
const
 | 
						|
  // Component serialized as Pascal
 | 
						|
  CSPVersion = 1;
 | 
						|
  CSPDefaultSignature = '// Component serialized as Pascal';
 | 
						|
  CSPDefaultSignatureBegin = CSPDefaultSignature+' - Begin';
 | 
						|
  CSPDefaultSignatureEnd = CSPDefaultSignature+' - End';
 | 
						|
  CSPDefaultAccessClass = 'TPasStreamAccess';
 | 
						|
  CSPDefaultExecCustomProc = 'ExecCustomCSP';
 | 
						|
  CSPDefaultExecCustomProcUnit = 'LazPasReadUtil';
 | 
						|
  CSPDefaultMaxColumn = 80;
 | 
						|
  CSPDefaultAssignOp = ':=';
 | 
						|
  CWPSkipParentName = '-';
 | 
						|
type
 | 
						|
  TCompWriterPas = class;
 | 
						|
  TCWPFindAncestorEvent = procedure(Writer: TCompWriterPas; Component: TComponent;
 | 
						|
    const Name: string; var Ancestor, RootAncestor: TComponent) of object;
 | 
						|
  TCWPGetMethodName = procedure(Writer: TCompWriterPas; Instance: TPersistent;
 | 
						|
    PropInfo: PPropInfo; out Name: String) of object;
 | 
						|
  TCWPGetParentPropertyEvent = procedure(Writer: TCompWriterPas;
 | 
						|
    Component: TComponent; var PropName: string) of object;
 | 
						|
  TCWPDefinePropertiesEvent = procedure(Writer: TCompWriterPas;
 | 
						|
    Instance: TPersistent; const Identifier: string; var Handled: boolean) of object;
 | 
						|
 | 
						|
  TCWPOption = (
 | 
						|
    cwpoNoSignature,     // do not write Begin, End signatures
 | 
						|
    cwpoNoSelf,          // enclose in "with LookupRootname do begin"
 | 
						|
    cwpoSetParentFirst,  // add "SetParentComponent" before setting properties, default: after
 | 
						|
    cwpoSrcCodepageUTF8, // target unit uses $codepage utf-8, aka do not convert UTF-8 string literals
 | 
						|
    cwpoNoWithBlocks,    // do not use with-do
 | 
						|
    cwpoNoFinalLineBreak
 | 
						|
    );
 | 
						|
  TCWPOptions = set of TCWPOption;
 | 
						|
 | 
						|
  TCWPChildrenStep = (
 | 
						|
    cwpcsCreate,
 | 
						|
    cwpcsProperties
 | 
						|
  );
 | 
						|
 | 
						|
  { TCompWriterPas }
 | 
						|
 | 
						|
  TCompWriterPas = class
 | 
						|
  private
 | 
						|
    FAccessClass: string;
 | 
						|
    FAncestor: TPersistent;
 | 
						|
    FAncestorPos: Integer;
 | 
						|
    FAncestors: TStringListUTF8Fast;
 | 
						|
    FAssignOp: String;
 | 
						|
    FCurIndent: integer;
 | 
						|
    FCurrentPos: Integer;
 | 
						|
    FDefaultDefineProperties: CodePointer;
 | 
						|
    FExecCustomProc: string;
 | 
						|
    FExecCustomProcUnit: string;
 | 
						|
    FIgnoreChildren: Boolean;
 | 
						|
    FIndentStep: integer;
 | 
						|
    FLineEnding: string;
 | 
						|
    FLookupRoot: TComponent;
 | 
						|
    FMaxColumn: integer;
 | 
						|
    FNeedAccessClass: boolean;
 | 
						|
    FNeededUnits: TStrings;
 | 
						|
    FOnDefineProperties: TCWPDefinePropertiesEvent;
 | 
						|
    FOnFindAncestor: TCWPFindAncestorEvent;
 | 
						|
    FOnGetMethodName: TCWPGetMethodName;
 | 
						|
    FOnGetParentProperty: TCWPGetParentPropertyEvent;
 | 
						|
    FOnWriteMethodProperty: TWriteMethodPropertyEvent;
 | 
						|
    FOnWriteStringProperty: TReadWriteStringPropertyEvent;
 | 
						|
    FOptions: TCWPOptions;
 | 
						|
    FParent: TComponent;
 | 
						|
    FPropPath: string;
 | 
						|
    FRoot: TComponent;
 | 
						|
    FRootAncestor: TComponent;
 | 
						|
    FSignatureBegin: String;
 | 
						|
    FSignatureEnd: String;
 | 
						|
    FStream: TStream;
 | 
						|
  protected
 | 
						|
    procedure AddToAncestorList(Component: TComponent); virtual;
 | 
						|
    procedure DetermineAncestor(Component: TComponent); virtual;
 | 
						|
    procedure SetNeededUnits(const AValue: TStrings); virtual;
 | 
						|
    procedure SetRoot(const AValue: TComponent); virtual;
 | 
						|
    procedure WriteComponentData(Instance: TComponent); virtual;
 | 
						|
    procedure WriteChildren(Component: TComponent; Step: TCWPChildrenStep); virtual;
 | 
						|
    procedure WriteProperty(Instance: TPersistent; PropInfo: PPropInfo); virtual;
 | 
						|
    procedure WriteProperties(Instance: TPersistent); virtual;
 | 
						|
    procedure WriteDefineProperties(Instance: TPersistent); virtual;
 | 
						|
    procedure WriteCollection(PropName: string; Collection: TCollection); virtual;
 | 
						|
    function ShortenFloat(s: string): string; virtual;
 | 
						|
  public
 | 
						|
    constructor Create(AStream: TStream); virtual;
 | 
						|
    destructor Destroy; override;
 | 
						|
    // stream a component:
 | 
						|
    procedure WriteDescendant(ARoot: TComponent; AnAncestor: TComponent = nil); virtual;
 | 
						|
    // utility functions:
 | 
						|
    procedure WriteComponentCreate(Component: TComponent); virtual;
 | 
						|
    procedure WriteComponent(Component: TComponent); virtual;
 | 
						|
    procedure WriteIndent; virtual;
 | 
						|
    procedure Write(const s: string); virtual;
 | 
						|
    procedure WriteLn; virtual;
 | 
						|
    procedure WriteStatement(const s: string); virtual;
 | 
						|
    procedure WriteAssign(const LHS, RHS: string); virtual;
 | 
						|
    procedure WriteWithDo(const Expr: string); virtual;
 | 
						|
    procedure WriteWithEnd; virtual;
 | 
						|
    function GetComponentPath(Component: TComponent): string; virtual;
 | 
						|
    function GetBoolLiteral(b: boolean): string; virtual;
 | 
						|
    function GetCharLiteral(c: integer): string; virtual;
 | 
						|
    function GetWideCharLiteral(c: integer): string; virtual;
 | 
						|
    function GetStringLiteral(const s: string): string; virtual;
 | 
						|
    function GetWStringLiteral(p: PWideChar; Count: integer): string; virtual;
 | 
						|
    function GetFloatLiteral(const e: Extended): string; virtual;
 | 
						|
    function GetCurrencyLiteral(const c: currency): string; virtual;
 | 
						|
    function GetEnumExpr(TypeInfo: PTypeInfo; Value: integer;
 | 
						|
      AllowOutOfRange: boolean): string; virtual;
 | 
						|
    function GetVersionStatement: string; virtual;
 | 
						|
    function CreatedByAncestor(Component: TComponent): boolean; virtual;
 | 
						|
    procedure AddNeededUnit(const AnUnitName: string); virtual;
 | 
						|
    procedure Indent; virtual;
 | 
						|
    procedure Unindent; virtual;
 | 
						|
    property Stream: TStream read FStream;
 | 
						|
    property Root: TComponent read FRoot write SetRoot;
 | 
						|
    property LookupRoot: TComponent read FLookupRoot;
 | 
						|
    property Ancestor: TPersistent read FAncestor write FAncestor;
 | 
						|
    property RootAncestor: TComponent read FRootAncestor write FRootAncestor;
 | 
						|
    property Parent: TComponent read FParent;
 | 
						|
    property OnFindAncestor: TCWPFindAncestorEvent read FOnFindAncestor write FOnFindAncestor;
 | 
						|
    property OnGetMethodName: TCWPGetMethodName read FOnGetMethodName write FOnGetMethodName;
 | 
						|
    property PropertyPath: string read FPropPath;
 | 
						|
    property CurIndent: integer read FCurIndent write FCurIndent;
 | 
						|
    property IndentStep: integer read FIndentStep write FIndentStep;
 | 
						|
    property Options: TCWPOptions read FOptions write FOptions;
 | 
						|
    property IgnoreChildren: Boolean read FIgnoreChildren write FIgnoreChildren;
 | 
						|
    property OnGetParentProperty: TCWPGetParentPropertyEvent read FOnGetParentProperty write FOnGetParentProperty;
 | 
						|
  public
 | 
						|
    // for custom DefineProperties
 | 
						|
    property OnWriteMethodProperty: TWriteMethodPropertyEvent read FOnWriteMethodProperty write FOnWriteMethodProperty;
 | 
						|
    property OnWriteStringProperty: TReadWriteStringPropertyEvent read FOnWriteStringProperty write FOnWriteStringProperty;
 | 
						|
    property OnDefineProperties: TCWPDefinePropertiesEvent read FOnDefineProperties write FOnDefineProperties;
 | 
						|
  public
 | 
						|
    // code snippets
 | 
						|
    property LineEnding: string read FLineEnding write FLineEnding; // default: system.LineEnding
 | 
						|
    property AssignOp: String read FAssignOp write FAssignOp; // default CSPDefaultAssignOp;
 | 
						|
    property SignatureBegin: String read FSignatureBegin write FSignatureBegin; // default CSPDefaultSignatureBegin
 | 
						|
    property SignatureEnd: String read FSignatureEnd write FSignatureEnd; // default CSPDefaultSignatureEnd
 | 
						|
    property AccessClass: string read FAccessClass
 | 
						|
      write FAccessClass; // classname used to access protected TComponent members like SetChildOrder
 | 
						|
    property ExecCustomProc: string read FExecCustomProc write FExecCustomProc; // default CSPDefaultExecCustomProc
 | 
						|
    property ExecCustomProcUnit: string read FExecCustomProcUnit write FExecCustomProcUnit; // default CSPDefaultExecCustomProcUnit
 | 
						|
    property MaxColumn: integer read FMaxColumn write FMaxColumn default CSPDefaultMaxColumn;
 | 
						|
  public
 | 
						|
    // set automatically when writing
 | 
						|
    property NeedAccessClass: boolean read FNeedAccessClass write FNeedAccessClass; // some property needed AccessClass
 | 
						|
    property NeededUnits: TStrings read FNeededUnits write SetNeededUnits;
 | 
						|
  end;
 | 
						|
 | 
						|
procedure WriteComponentToPasStream(AComponent: TComponent; AStream: TStream);
 | 
						|
 | 
						|
type
 | 
						|
  TCWPDefinePropertiesProc = procedure(Sender: TCompWriterPas;
 | 
						|
    Instance: TPersistent; const Identifier: string; var Handled: boolean);
 | 
						|
 | 
						|
procedure RegisterDefinePropertiesPas(aClass: TPersistentClass;
 | 
						|
  const OnDefineProperties: TCWPDefinePropertiesProc);
 | 
						|
procedure UnregisterDefinePropertiesPas(
 | 
						|
  const OnDefineProperties: TCWPDefinePropertiesProc);
 | 
						|
procedure CallDefinePropertiesPas(Writer: TCompWriterPas; Instance: TPersistent;
 | 
						|
  const Identifier: string; var Handled: boolean);
 | 
						|
 | 
						|
implementation
 | 
						|
 | 
						|
type
 | 
						|
  TDefinePropertiesPas = class
 | 
						|
    BaseClass: TPersistentClass;
 | 
						|
    Event: TCWPDefinePropertiesProc;
 | 
						|
  end;
 | 
						|
 | 
						|
var
 | 
						|
  DefinePropertiesEvents: TObjectList = nil;
 | 
						|
 | 
						|
procedure WriteComponentToPasStream(AComponent: TComponent; AStream: TStream);
 | 
						|
var
 | 
						|
  Writer: TCompWriterPas;
 | 
						|
begin
 | 
						|
  Writer:=TCompWriterPas.Create(AStream);
 | 
						|
  try
 | 
						|
    Writer.WriteDescendant(AComponent);
 | 
						|
  finally
 | 
						|
    Writer.Free;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure RegisterDefinePropertiesPas(aClass: TPersistentClass;
 | 
						|
  const OnDefineProperties: TCWPDefinePropertiesProc);
 | 
						|
var
 | 
						|
  i, Cnt: Integer;
 | 
						|
  E: TDefinePropertiesPas;
 | 
						|
begin
 | 
						|
  if not Assigned(OnDefineProperties) then
 | 
						|
    raise Exception.Create('');
 | 
						|
  if not Assigned(aClass) then
 | 
						|
    raise Exception.Create('');
 | 
						|
  if DefinePropertiesEvents=nil then
 | 
						|
    DefinePropertiesEvents:=TObjectList.Create(true);
 | 
						|
  Cnt:=DefinePropertiesEvents.Count;
 | 
						|
  i:=0;
 | 
						|
  while i<Cnt do
 | 
						|
  begin
 | 
						|
    E:=TDefinePropertiesPas(DefinePropertiesEvents[i]);
 | 
						|
    if E.BaseClass.InheritsFrom(aClass) then
 | 
						|
      break;
 | 
						|
    inc(Cnt);
 | 
						|
  end;
 | 
						|
  E:=TDefinePropertiesPas.Create;
 | 
						|
  E.BaseClass:=aClass;
 | 
						|
  E.Event:=OnDefineProperties;
 | 
						|
  DefinePropertiesEvents.Insert(i,E);
 | 
						|
end;
 | 
						|
 | 
						|
procedure UnregisterDefinePropertiesPas(
 | 
						|
  const OnDefineProperties: TCWPDefinePropertiesProc);
 | 
						|
var
 | 
						|
  i: Integer;
 | 
						|
  E: TDefinePropertiesPas;
 | 
						|
begin
 | 
						|
  for i:=DefinePropertiesEvents.Count-1 downto 0 do
 | 
						|
  begin
 | 
						|
    E:=TDefinePropertiesPas(DefinePropertiesEvents[i]);
 | 
						|
    if E.Event=OnDefineProperties then
 | 
						|
      DefinePropertiesEvents.Delete(i);
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure CallDefinePropertiesPas(Writer: TCompWriterPas;
 | 
						|
  Instance: TPersistent; const Identifier: string; var Handled: boolean);
 | 
						|
var
 | 
						|
  i: Integer;
 | 
						|
  E: TDefinePropertiesPas;
 | 
						|
begin
 | 
						|
  if DefinePropertiesEvents=nil then exit;
 | 
						|
  for i:=0 to DefinePropertiesEvents.Count-1 do begin
 | 
						|
    E:=TDefinePropertiesPas(DefinePropertiesEvents[i]);
 | 
						|
    if not Instance.InheritsFrom(E.BaseClass) then
 | 
						|
      continue;
 | 
						|
    E.Event(Writer,Instance,Identifier,Handled);
 | 
						|
    if Handled then exit;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
function IsValidUTF8(p: PChar): integer;
 | 
						|
var
 | 
						|
  c: Char;
 | 
						|
begin
 | 
						|
  c:=p^;
 | 
						|
  if ord(c)<%10000000 then begin
 | 
						|
    // regular single byte ASCII character (#0 is a character, this is Pascal ;)
 | 
						|
    Result:=1;
 | 
						|
  end else if ord(c)<=%11000001 then begin
 | 
						|
    // single byte character, between valid UTF-8 encodings
 | 
						|
    // %11000000 and %11000001 map 2 byte to #0..#128, which is invalid and used for XSS attacks
 | 
						|
    Result:=0;
 | 
						|
  end else if ord(c)<=%11011111 then begin
 | 
						|
    // could be 2 byte character (%110xxxxx %10xxxxxx)
 | 
						|
    if ((ord(p[1]) and %11000000) = %10000000) then
 | 
						|
      Result:=2
 | 
						|
    else
 | 
						|
      Result:=0; // missing following bytes
 | 
						|
  end
 | 
						|
  else if ord(c)<=%11101111 then begin
 | 
						|
    // could be 3 byte character (%1110xxxx %10xxxxxx %10xxxxxx)
 | 
						|
    if ((ord(p[1]) and %11000000) = %10000000)
 | 
						|
    and ((ord(p[2]) and %11000000) = %10000000) then begin
 | 
						|
      if (ord(c)=%11100000) and (ord(p[1])<=%10011111) then
 | 
						|
        Result:=0; // XSS attack: 3 bytes are mapped to the 1 or 2 byte codes
 | 
						|
      Result:=3;
 | 
						|
    end else
 | 
						|
      Result:=0; // missing following bytes
 | 
						|
  end
 | 
						|
  else if ord(c)<=%11110111 then begin
 | 
						|
    // could be 4 byte character (%11110xxx %10xxxxxx %10xxxxxx %10xxxxxx)
 | 
						|
    if ((ord(p[1]) and %11000000) = %10000000)
 | 
						|
    and ((ord(p[2]) and %11000000) = %10000000)
 | 
						|
    and ((ord(p[3]) and %11000000) = %10000000) then begin
 | 
						|
      if (ord(c)=%11110000) and (ord(p[1])<=%10001111) then
 | 
						|
        Result:=0; // XSS attack: 4 bytes are mapped to the 1-3 byte codes
 | 
						|
      Result:=4;
 | 
						|
    end else
 | 
						|
      Result:=0; // missing following bytes
 | 
						|
  end
 | 
						|
  else begin
 | 
						|
    Result:=0;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
function IsValidUTF16(p: PWideChar): integer;
 | 
						|
var
 | 
						|
  c: WideChar;
 | 
						|
begin
 | 
						|
  c:=p^;
 | 
						|
  if c<=#$DC7F then
 | 
						|
    exit(1)
 | 
						|
  else if c<=#$DBFF then begin
 | 
						|
    c:=p[1];
 | 
						|
    if (c>=#$DC00) and (c<=#$DFFF) then
 | 
						|
      exit(2)
 | 
						|
    else
 | 
						|
      exit(0);
 | 
						|
  end else if c<=#$Dfff then begin
 | 
						|
    exit(0);
 | 
						|
  end else
 | 
						|
    exit(1);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
type
 | 
						|
  TAccessComp = class(TComponent); // to access TComponent protected members
 | 
						|
 | 
						|
  { TPosComponent }
 | 
						|
 | 
						|
  TPosComponent = class(TObject)
 | 
						|
    FPos: Integer;
 | 
						|
    FComponent: TComponent;
 | 
						|
    constructor Create(APos: Integer; AComponent: TComponent);
 | 
						|
  end;
 | 
						|
 | 
						|
{ TPosComponent }
 | 
						|
 | 
						|
constructor TPosComponent.Create(APos: Integer; AComponent: TComponent);
 | 
						|
begin
 | 
						|
  FPos:=APos;
 | 
						|
  FComponent:=AComponent;
 | 
						|
end;
 | 
						|
 | 
						|
{ TCompWriterPas }
 | 
						|
 | 
						|
procedure TCompWriterPas.AddToAncestorList(Component: TComponent);
 | 
						|
begin
 | 
						|
  FAncestors.AddObject(Component.Name,TPosComponent.Create(FAncestors.Count,Component));
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCompWriterPas.DetermineAncestor(Component: TComponent);
 | 
						|
var
 | 
						|
  i : Integer;
 | 
						|
  C: TComponent;
 | 
						|
begin
 | 
						|
  if Assigned(FAncestors) then
 | 
						|
  begin
 | 
						|
    i:=FAncestors.IndexOf(Component.Name);
 | 
						|
    if i<0 then
 | 
						|
    begin
 | 
						|
      FAncestor:=nil;
 | 
						|
      FAncestorPos:=-1;
 | 
						|
    end
 | 
						|
    else
 | 
						|
      With TPosComponent(FAncestors.Objects[i]) do
 | 
						|
      begin
 | 
						|
        FAncestor:=FComponent;
 | 
						|
        FAncestorPos:=FPos;
 | 
						|
      end;
 | 
						|
  end;
 | 
						|
  if Assigned(FOnFindAncestor) then
 | 
						|
    if (Ancestor=Nil) or (Ancestor is TComponent) then
 | 
						|
    begin
 | 
						|
      C:=TComponent(Ancestor);
 | 
						|
      FOnFindAncestor(Self,Component,Component.Name,C,FRootAncestor);
 | 
						|
      Ancestor:=C;
 | 
						|
    end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCompWriterPas.SetNeededUnits(const AValue: TStrings);
 | 
						|
begin
 | 
						|
  if FNeededUnits=AValue then Exit;
 | 
						|
  FNeededUnits.Assign(AValue);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCompWriterPas.SetRoot(const AValue: TComponent);
 | 
						|
begin
 | 
						|
  FRoot:=AValue;
 | 
						|
  FLookupRoot:=FRoot;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCompWriterPas.WriteComponentData(Instance: TComponent);
 | 
						|
var
 | 
						|
  HasAncestor: Boolean;
 | 
						|
  SavedPropPath: String;
 | 
						|
 | 
						|
  procedure WriteSetParent;
 | 
						|
  var
 | 
						|
    PropName: String;
 | 
						|
  begin
 | 
						|
    if Parent=nil then exit;
 | 
						|
    if Instance.GetParentComponent=nil then exit;
 | 
						|
    if CreatedByAncestor(Instance) then begin
 | 
						|
      // ancestor creates the component
 | 
						|
      // and descendants cannot change parent
 | 
						|
      exit;
 | 
						|
    end;
 | 
						|
    PropName:='';
 | 
						|
    if Assigned(OnGetParentProperty) then
 | 
						|
      OnGetParentProperty(Self,Instance,PropName);
 | 
						|
    if PropName=CWPSkipParentName then
 | 
						|
    else if PropName<>'' then
 | 
						|
      WriteAssign(PropertyPath+PropName,GetComponentPath(Parent))
 | 
						|
    else begin
 | 
						|
      NeedAccessClass:=true;
 | 
						|
      WriteStatement(AccessClass+'(TComponent('+Instance.Name+')).SetParentComponent('+GetComponentPath(Parent)+');');
 | 
						|
    end;
 | 
						|
  end;
 | 
						|
 | 
						|
begin
 | 
						|
  HasAncestor := Assigned(Ancestor) and ((Instance = Root) or
 | 
						|
    (Instance.ClassType = Ancestor.ClassType));
 | 
						|
  SavedPropPath:=FPropPath;
 | 
						|
  try
 | 
						|
    if Instance=LookupRoot then begin
 | 
						|
      WriteAssign('Name',''''+Instance.Name+'''');
 | 
						|
      WriteChildren(Instance,cwpcsCreate);
 | 
						|
    end
 | 
						|
    else begin
 | 
						|
      WriteWithDo(Instance.Name);
 | 
						|
      if cwpoNoWithBlocks in Options then
 | 
						|
        FPropPath:=GetComponentPath(Instance)+'.';
 | 
						|
      if not CreatedByAncestor(Instance) then
 | 
						|
        WriteAssign(PropertyPath+'Name',''''+Instance.Name+'''');
 | 
						|
      if cwpoSetParentFirst in Options then
 | 
						|
        WriteSetParent;
 | 
						|
    end;
 | 
						|
 | 
						|
    WriteProperties(Instance);
 | 
						|
 | 
						|
    if not (cwpoSetParentFirst in Options) then
 | 
						|
      WriteSetParent;
 | 
						|
 | 
						|
    if not IgnoreChildren then
 | 
						|
      WriteChildren(Instance,cwpcsProperties);
 | 
						|
    if Instance<>LookupRoot then
 | 
						|
      WriteWithEnd;
 | 
						|
  finally
 | 
						|
    FPropPath:=SavedPropPath;
 | 
						|
  end;
 | 
						|
  if HasAncestor and (Ancestor<>FRootAncestor)
 | 
						|
      and (FCurrentPos<>FAncestorPos) then
 | 
						|
  begin
 | 
						|
    if (Parent=LookupRoot) and not (cwpoNoSelf in Options) then
 | 
						|
      WriteStatement('SetChildOrder('+GetComponentPath(Instance)+','+IntToStr(FCurrentPos)+');')
 | 
						|
    else begin
 | 
						|
      NeedAccessClass:=true;
 | 
						|
      WriteStatement(AccessClass+'(TComponent('+GetComponentPath(Parent)+')).SetChildOrder('+GetComponentPath(Instance)+','+IntToStr(FCurrentPos)+');');
 | 
						|
    end;
 | 
						|
  end;
 | 
						|
  Inc(FCurrentPos);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCompWriterPas.WriteChildren(Component: TComponent;
 | 
						|
  Step: TCWPChildrenStep);
 | 
						|
var
 | 
						|
  SRoot, SRootA, SParent: TComponent;
 | 
						|
  SList: TStringListUTF8Fast;
 | 
						|
  SPos, i, SAncestorPos: Integer;
 | 
						|
begin
 | 
						|
  // Write children list.
 | 
						|
  // While writing children, the ancestor environment must be saved
 | 
						|
  // This is recursive...
 | 
						|
  SRoot:=FRoot;
 | 
						|
  SRootA:=FRootAncestor;
 | 
						|
  SList:=FAncestors;
 | 
						|
  SPos:=FCurrentPos;
 | 
						|
  SAncestorPos:=FAncestorPos;
 | 
						|
  SParent:=Parent;
 | 
						|
  try
 | 
						|
    FAncestors:=Nil;
 | 
						|
    FCurrentPos:=0;
 | 
						|
    FAncestorPos:=-1;
 | 
						|
    FParent:=Component;
 | 
						|
    if csInline in Component.ComponentState then
 | 
						|
      FRoot:=Component;
 | 
						|
    if (FAncestor is TComponent) then
 | 
						|
    begin
 | 
						|
      FAncestors:=TStringListUTF8Fast.Create;
 | 
						|
      if csInline in TComponent(FAncestor).ComponentState then
 | 
						|
        FRootAncestor := TComponent(FAncestor);
 | 
						|
      TAccessComp(FAncestor).GetChildren(@AddToAncestorList,FRootAncestor);
 | 
						|
      FAncestors.Sorted:=True;
 | 
						|
    end;
 | 
						|
    try
 | 
						|
      case Step of
 | 
						|
      cwpcsCreate:
 | 
						|
        TAccessComp(Component).GetChildren(@WriteComponentCreate, FRoot);
 | 
						|
      cwpcsProperties:
 | 
						|
        TAccessComp(Component).GetChildren(@WriteComponent, FRoot);
 | 
						|
      end;
 | 
						|
    finally
 | 
						|
      if Assigned(FAncestor) then
 | 
						|
        for i:=0 to FAncestors.Count-1 do
 | 
						|
          FAncestors.Objects[i].Free;
 | 
						|
      FreeAndNil(FAncestors);
 | 
						|
    end;
 | 
						|
  finally
 | 
						|
    FParent:=SParent;
 | 
						|
    FAncestors:=SList;
 | 
						|
    FRoot:=SRoot;
 | 
						|
    FRootAncestor:=SRootA;
 | 
						|
    FCurrentPos:=SPos;
 | 
						|
    FAncestorPos:=SAncestorPos;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCompWriterPas.WriteProperty(Instance: TPersistent;
 | 
						|
  PropInfo: PPropInfo);
 | 
						|
type
 | 
						|
  TSet = set of 0..31;
 | 
						|
var
 | 
						|
  PropType, CompType: PTypeInfo;
 | 
						|
  ObjValue, AncestorObj: TObject;
 | 
						|
  HasAncestor, BoolValue, DefBoolValue: Boolean;
 | 
						|
  Int32Value, DefValue: longint;
 | 
						|
  PropName, Ident, s, StrValue, DefStrValue, Name, SavedPropPath: String;
 | 
						|
  IntToIdentFn: TIntToIdent;
 | 
						|
  i, j: Integer;
 | 
						|
  Int64Value, DefInt64Value: Int64;
 | 
						|
  FloatValue, DefFloatValue: Extended;
 | 
						|
  MethodValue, DefMethodValue: TMethod;
 | 
						|
  WStrValue, WDefStrValue: WideString;
 | 
						|
  UStrValue, UDefStrValue: UnicodeString;
 | 
						|
  VarValue, DefVarValue: tvardata;
 | 
						|
  aTypeData: PTypeData;
 | 
						|
  Component, AncestorComponent: TComponent;
 | 
						|
  SavedAncestor: TPersistent;
 | 
						|
  IntfValue, AncestorIntf: IInterface;
 | 
						|
  CompRef: IInterfaceComponentReference;
 | 
						|
begin
 | 
						|
  // do not stream properties without getter
 | 
						|
  if not Assigned(PropInfo^.GetProc) then
 | 
						|
    exit;
 | 
						|
 | 
						|
  // properties without setter are only allowed, if they are csSubComponent
 | 
						|
  PropType := PropInfo^.PropType;
 | 
						|
  if not Assigned(PropInfo^.SetProc) then begin
 | 
						|
    if PropType^.Kind<>tkClass then
 | 
						|
      exit;
 | 
						|
    ObjValue := TObject(GetObjectProp(Instance, PropInfo));
 | 
						|
    if not (ObjValue is TComponent) or
 | 
						|
       not (csSubComponent in TComponent(ObjValue).ComponentStyle) then
 | 
						|
      exit;
 | 
						|
  end;
 | 
						|
 | 
						|
  { Check if the ancestor can be used }
 | 
						|
  HasAncestor := Assigned(Ancestor) and ((Instance = Root) or
 | 
						|
    (Instance.ClassType = Ancestor.ClassType));
 | 
						|
  PropName:=FPropPath + PropInfo^.Name;
 | 
						|
  {$IFDEF VerboseCompWriterPas}
 | 
						|
  debugln(['TWriter.WriteProperty PropName="',PropName,'" TypeName=',PropType^.Name,' Kind=',GetEnumName(TypeInfo(TTypeKind),ord(PropType^.Kind)),' HasAncestor=',HasAncestor]);
 | 
						|
  {$ENDIF}
 | 
						|
 | 
						|
  case PropType^.Kind of
 | 
						|
    tkInteger, tkChar, tkEnumeration, tkSet, tkWChar:
 | 
						|
      begin
 | 
						|
        Int32Value := GetOrdProp(Instance, PropInfo);
 | 
						|
        if HasAncestor then
 | 
						|
          DefValue := GetOrdProp(Ancestor, PropInfo)
 | 
						|
        else
 | 
						|
          DefValue := PPropInfo(PropInfo)^.Default;
 | 
						|
        //debugln([PropInfo^.Name,', HasAncestor=',HasAncestor,', Value=',Int32Value,', Default=',DefValue]);
 | 
						|
        if (Int32Value <> DefValue) or (DefValue=longint($80000000)) then
 | 
						|
        begin
 | 
						|
          case PropType^.Kind of
 | 
						|
            tkInteger:
 | 
						|
              begin
 | 
						|
                // Check if this integer has a string identifier
 | 
						|
                IntToIdentFn := FindIntToIdent(PropInfo^.PropType);
 | 
						|
                Ident:='';
 | 
						|
                if Assigned(IntToIdentFn) and IntToIdentFn(Int32Value, Ident) then
 | 
						|
                  // Integer with a custom identifier
 | 
						|
                  // ToDo: check if this is an actual Pascal constant and remember the unit
 | 
						|
                  WriteAssign(PropName,Ident)
 | 
						|
                else begin
 | 
						|
                  // Integer has to be written just as number
 | 
						|
                  case PropType^.Name of
 | 
						|
                  'ByteBool': WriteAssign(PropName,GetBoolLiteral(ByteBool(Int32Value)));
 | 
						|
                  'WordBool': WriteAssign(PropName,GetBoolLiteral(WordBool(Int32Value)));
 | 
						|
                  'LongBool': WriteAssign(PropName,GetBoolLiteral(LongBool(Int32Value)));
 | 
						|
                  else
 | 
						|
                    aTypeData:=GetTypeData(PropInfo^.PropType);
 | 
						|
                    if aTypeData^.MinValue>=0 then
 | 
						|
                      WriteAssign(PropName,IntToStr(longword(Int32Value)))
 | 
						|
                    else
 | 
						|
                      WriteAssign(PropName,IntToStr(Int32Value));
 | 
						|
                  end;
 | 
						|
                end;
 | 
						|
              end;
 | 
						|
            tkChar:
 | 
						|
              WriteAssign(PropName,GetCharLiteral(Int32Value));
 | 
						|
            tkWChar:
 | 
						|
              WriteAssign(PropName,GetWideCharLiteral(Int32Value));
 | 
						|
            tkSet:
 | 
						|
              begin
 | 
						|
              s:='';
 | 
						|
              CompType:=GetTypeData(PropType)^.CompType;
 | 
						|
              i:=0;
 | 
						|
              while i<32 do
 | 
						|
              begin
 | 
						|
                if i in TSet(Int32Value) then
 | 
						|
                begin
 | 
						|
                  if s<>'' then s:=s+',';
 | 
						|
                  // ToDo: store needed unit
 | 
						|
                  s:=s+GetEnumExpr(CompType, i,false);
 | 
						|
                  j:=i;
 | 
						|
                  while (i<31) and (byte(i+1) in TSet(Int32Value)) do
 | 
						|
                    inc(i);
 | 
						|
                  if i>j then
 | 
						|
                    s:=s+'..'+GetEnumExpr(CompType, i,false);
 | 
						|
                end;
 | 
						|
                inc(i);
 | 
						|
              end;
 | 
						|
              WriteAssign(PropName,'['+s+']');
 | 
						|
              end;
 | 
						|
            tkEnumeration:
 | 
						|
              // ToDo: store needed unit
 | 
						|
              WriteAssign(PropName,GetEnumExpr(PropType, Int32Value,true));
 | 
						|
          end;
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
    tkFloat:
 | 
						|
      begin
 | 
						|
        FloatValue := GetFloatProp(Instance, PropInfo);
 | 
						|
        if HasAncestor then
 | 
						|
          DefFloatValue := GetFloatProp(Ancestor, PropInfo)
 | 
						|
        else
 | 
						|
          begin
 | 
						|
          DefValue :=PropInfo^.Default;
 | 
						|
          DefFloatValue:=PSingle(@PropInfo^.Default)^;
 | 
						|
          end;
 | 
						|
        if (FloatValue<>DefFloatValue) or (DefValue=longint($80000000)) then
 | 
						|
          WriteAssign(PropName,GetFloatLiteral(FloatValue));
 | 
						|
      end;
 | 
						|
    tkMethod:
 | 
						|
      begin
 | 
						|
        MethodValue := GetMethodProp(Instance, PropInfo);
 | 
						|
        if HasAncestor then
 | 
						|
          DefMethodValue := GetMethodProp(Ancestor, PropInfo)
 | 
						|
        else begin
 | 
						|
          DefMethodValue.Data := nil;
 | 
						|
          DefMethodValue.Code := nil;
 | 
						|
        end;
 | 
						|
 | 
						|
        //debugln(['TCompWriterPas.WriteProperty ',dbgs(MethodValue.Data),' ',dbgs(MethodValue.Code),' ',dbgs(DefMethodValue.Data),' ',dbgs(DefMethodValue.Code)]);
 | 
						|
        if Assigned(OnGetMethodName) then
 | 
						|
        begin
 | 
						|
          if (MethodValue.Code <> DefMethodValue.Code) or
 | 
						|
            (MethodValue.Data <> DefMethodValue.Data) then
 | 
						|
          begin
 | 
						|
            OnGetMethodName(Self,Instance,PropInfo,Ident);
 | 
						|
            s:='';
 | 
						|
            if HasAncestor then
 | 
						|
              OnGetMethodName(Self,Ancestor,PropInfo,s);
 | 
						|
            if Ident<>s then
 | 
						|
            begin
 | 
						|
              if Ident='' then
 | 
						|
                WriteAssign(PropName,'nil')
 | 
						|
              else
 | 
						|
                // ToDo: check nameclash of Ident with current with-do block
 | 
						|
                WriteAssign(PropName,'@'+Ident);
 | 
						|
            end;
 | 
						|
          end;
 | 
						|
        end else begin
 | 
						|
          if (MethodValue.Code <> DefMethodValue.Code) then
 | 
						|
          begin
 | 
						|
            if not Assigned(MethodValue.Code) then
 | 
						|
              Ident:=''
 | 
						|
            else
 | 
						|
              Ident:=FLookupRoot.MethodName(MethodValue.Code);
 | 
						|
            if Ident='' then
 | 
						|
              WriteAssign(PropName,'nil')
 | 
						|
            else
 | 
						|
              // ToDo: check nameclash of Ident with current with-do block
 | 
						|
              WriteAssign(PropName,'@'+Ident);
 | 
						|
          end;
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
    tkSString, tkLString, tkAString:
 | 
						|
      begin
 | 
						|
        StrValue := GetStrProp(Instance, PropInfo);
 | 
						|
        if HasAncestor then
 | 
						|
          DefStrValue := GetStrProp(Ancestor, PropInfo)
 | 
						|
        else
 | 
						|
          SetLength(DefStrValue, 0);
 | 
						|
 | 
						|
        if StrValue <> DefStrValue then
 | 
						|
          WriteAssign(PropName,GetStringLiteral(StrValue));
 | 
						|
      end;
 | 
						|
    tkWString:
 | 
						|
      begin
 | 
						|
        WStrValue := GetWideStrProp(Instance, PropInfo);
 | 
						|
        if HasAncestor then
 | 
						|
          WDefStrValue := GetWideStrProp(Ancestor, PropInfo)
 | 
						|
        else
 | 
						|
          WDefStrValue := '';
 | 
						|
 | 
						|
        if WStrValue <> WDefStrValue then
 | 
						|
          WriteAssign(PropName,GetWStringLiteral(PWideChar(WStrValue),length(WStrValue)));
 | 
						|
      end;
 | 
						|
    tkUString:
 | 
						|
      begin
 | 
						|
        UStrValue := GetUnicodeStrProp(Instance, PropInfo);
 | 
						|
        if HasAncestor then
 | 
						|
          UDefStrValue := GetUnicodeStrProp(Ancestor, PropInfo)
 | 
						|
        else
 | 
						|
          SetLength(UDefStrValue, 0);
 | 
						|
 | 
						|
        if UStrValue <> UDefStrValue then
 | 
						|
          WriteAssign(PropName,GetWStringLiteral(PWideChar(UStrValue),length(UStrValue)));
 | 
						|
      end;
 | 
						|
    tkVariant:
 | 
						|
      begin
 | 
						|
        // Ensure that a Variant manager is installed
 | 
						|
        if not Assigned(VarClearProc) then
 | 
						|
          raise EWriteError.Create(SErrNoVariantSupport);
 | 
						|
 | 
						|
        VarValue := tvardata(GetVariantProp(Instance, PropInfo));
 | 
						|
        if HasAncestor then
 | 
						|
          DefVarValue := tvardata(GetVariantProp(Ancestor, PropInfo))
 | 
						|
        else
 | 
						|
          FillChar(DefVarValue,sizeof(DefVarValue),0);
 | 
						|
 | 
						|
        if (CompareByte(VarValue,DefVarValue,sizeof(VarValue)) <> 0) then
 | 
						|
          begin
 | 
						|
            // can't use variant() typecast, pulls in variants unit
 | 
						|
            case VarValue.vtype of
 | 
						|
            varsmallint : WriteAssign(PropName,'SmallInt('+IntToStr(VarValue.vsmallint)+')');
 | 
						|
            varinteger : WriteAssign(PropName,'LongInt('+IntToStr(VarValue.vinteger)+')');
 | 
						|
            varsingle : WriteAssign(PropName,'Single('+GetFloatLiteral(VarValue.vsingle)+')');
 | 
						|
            vardouble : WriteAssign(PropName,'Double('+GetFloatLiteral(VarValue.vdouble)+')');
 | 
						|
            vardate : WriteAssign(PropName,'TDateTime('+GetFloatLiteral(VarValue.vdate)+')');
 | 
						|
            varcurrency : WriteAssign(PropName,'Currency('+GetCurrencyLiteral(VarValue.vcurrency)+')');
 | 
						|
            //varolestr : (volestr : pwidechar);
 | 
						|
            //vardispatch : (vdispatch : pointer);
 | 
						|
            //varerror : (verror : hresult);
 | 
						|
            varboolean : WriteAssign(PropName,GetBoolLiteral(VarValue.vboolean));
 | 
						|
            //varunknown : (vunknown : pointer);
 | 
						|
            // vardecimal : ( : );
 | 
						|
            varshortint : WriteAssign(PropName,'ShortInt('+IntToStr(VarValue.vshortint)+')');
 | 
						|
            varbyte : WriteAssign(PropName,'Byte('+IntToStr(VarValue.vbyte)+')');
 | 
						|
            varword : WriteAssign(PropName,'Word('+IntToStr(VarValue.vword)+')');
 | 
						|
            varlongword : WriteAssign(PropName,'LongWord('+IntToStr(VarValue.vlongword)+')');
 | 
						|
            varint64 : WriteAssign(PropName,'Int64('+IntToStr(VarValue.vint64)+')');
 | 
						|
            varqword : WriteAssign(PropName,'QWord('+IntToStr(VarValue.vqword)+')');
 | 
						|
            // duplicate: varword64
 | 
						|
            varstring : WriteAssign(PropName,GetStringLiteral(AnsiString(VarValue.vstring)));
 | 
						|
            //varany :  (vany : pointer);
 | 
						|
            //vararray : (varray : pvararray);
 | 
						|
            //varbyref : (vpointer : pointer);
 | 
						|
            //varrecord : (vrecord : pointer;precinfo : pointer);
 | 
						|
            else
 | 
						|
              {$IFDEF VerboseCompWriterPas}
 | 
						|
              debugln(['TCompWriterPas.WriteProperty Property="',PropName,'" Kind=',PropType^.Kind,' vtype=',VarValue.vtype]);
 | 
						|
              raise EWriteError.Create('proptype not supported: '+GetEnumName(TypeInfo(PropType^.Kind),ord(PropType^.Kind))+' vtype='+dbgs(VarValue.vtype));
 | 
						|
              {$ENDIF}
 | 
						|
            end;
 | 
						|
            //ToDo WriteVariant(pvariant(@VarValue)^);
 | 
						|
          end;
 | 
						|
      end;
 | 
						|
    tkClass:
 | 
						|
      begin
 | 
						|
        ObjValue := TObject(GetObjectProp(Instance, PropInfo));
 | 
						|
        if HasAncestor then
 | 
						|
        begin
 | 
						|
          AncestorObj := TObject(GetObjectProp(Ancestor, PropInfo));
 | 
						|
          if (AncestorObj is TComponent) and
 | 
						|
             (ObjValue is TComponent) then
 | 
						|
          begin
 | 
						|
            //debugln(['TWriter.WriteProperty AncestorObj=',TComponent(AncestorObj).Name,' OwnerFit=',TComponent(AncestorObj).Owner = FRootAncestor,' ',TComponent(ObjValue).Name,' OwnerFit=',TComponent(ObjValue).Owner = Root]);
 | 
						|
            if (AncestorObj<>ObjValue) and
 | 
						|
               (TComponent(AncestorObj).Owner = FRootAncestor) and
 | 
						|
               (TComponent(ObjValue).Owner = Root) and
 | 
						|
               SameText(TComponent(AncestorObj).Name,TComponent(ObjValue).Name) then
 | 
						|
            begin
 | 
						|
              // value is a component, and it is the same as in the ancestor
 | 
						|
              // Note: a descendant has new instances with same names
 | 
						|
              AncestorObj := ObjValue;
 | 
						|
            end;
 | 
						|
          end;
 | 
						|
        end else
 | 
						|
          AncestorObj := nil;
 | 
						|
 | 
						|
        if not Assigned(ObjValue) then
 | 
						|
        begin
 | 
						|
          if ObjValue <> AncestorObj then
 | 
						|
            WriteAssign(PropName,'Nil');
 | 
						|
        end
 | 
						|
        else if ObjValue.InheritsFrom(TPersistent) then
 | 
						|
        begin
 | 
						|
          // Subcomponents are streamed the same way as persistents
 | 
						|
          if ObjValue.InheritsFrom(TComponent)
 | 
						|
            and ((not (csSubComponent in TComponent(ObjValue).ComponentStyle))
 | 
						|
                 or ((TComponent(ObjValue).Owner<>Instance) and (TComponent(ObjValue).Owner<>Nil))) then
 | 
						|
          begin
 | 
						|
            Component := TComponent(ObjValue);
 | 
						|
            if (ObjValue <> AncestorObj)
 | 
						|
                and not (csTransient in Component.ComponentStyle) then
 | 
						|
            begin
 | 
						|
              // set property value
 | 
						|
              Name:=GetComponentPath(Component);
 | 
						|
              if Name='' then
 | 
						|
                raise EWriteError.Create('cannot write property "'+DbgSName(Instance)+'.'+PropName+'"');
 | 
						|
              WriteAssign(PropName,Name);
 | 
						|
            end; //(ObjValue <> AncestorObj)
 | 
						|
          end // ObjValue.InheritsFrom(TComponent)
 | 
						|
          else
 | 
						|
          begin
 | 
						|
            // keep property value, set sub properties recursively with full path
 | 
						|
            // e.g. Font.Size:=5;
 | 
						|
            SavedAncestor := Ancestor;
 | 
						|
            SavedPropPath := FPropPath;
 | 
						|
            try
 | 
						|
              FPropPath := FPropPath + PPropInfo(PropInfo)^.Name + '.';
 | 
						|
              if HasAncestor then
 | 
						|
                Ancestor := TPersistent(GetObjectProp(Ancestor, PropInfo));
 | 
						|
              WriteProperties(TPersistent(ObjValue));
 | 
						|
            finally
 | 
						|
              Ancestor := SavedAncestor;
 | 
						|
              FPropPath := SavedPropPath;
 | 
						|
            end;
 | 
						|
            if ObjValue.InheritsFrom(TCollection) then
 | 
						|
            begin
 | 
						|
              if (not HasAncestor) or (not CollectionsEqual(TCollection(ObjValue),
 | 
						|
                TCollection(GetObjectProp(Ancestor, PropInfo)),Root,RootAncestor)) then
 | 
						|
              begin
 | 
						|
                // create collection items
 | 
						|
                SavedPropPath := FPropPath;
 | 
						|
                try
 | 
						|
                  if cwpoNoWithBlocks in Options then
 | 
						|
                    FPropPath:=PropName+'.'
 | 
						|
                  else
 | 
						|
                    FPropPath:='';
 | 
						|
                  WriteCollection(PropName,TCollection(ObjValue));
 | 
						|
                finally
 | 
						|
                  FPropPath := SavedPropPath;
 | 
						|
                end;
 | 
						|
              end;
 | 
						|
            end // TCollection
 | 
						|
          end;
 | 
						|
        end; // Inheritsfrom(TPersistent)
 | 
						|
      end;
 | 
						|
    tkInt64, tkQWord:
 | 
						|
      begin
 | 
						|
        Int64Value := GetInt64Prop(Instance, PropInfo);
 | 
						|
        if HasAncestor then
 | 
						|
          DefInt64Value := GetInt64Prop(Ancestor, PropInfo)
 | 
						|
        else
 | 
						|
          DefInt64Value := 0;
 | 
						|
        if Int64Value <> DefInt64Value then
 | 
						|
          if PropType^.Kind=tkInt64 then
 | 
						|
            WriteAssign(PropName,IntToStr(Int64Value))
 | 
						|
          else
 | 
						|
            WriteAssign(PropName,IntToStr(QWord(Int64Value)));
 | 
						|
      end;
 | 
						|
    tkBool:
 | 
						|
      begin
 | 
						|
        BoolValue := GetOrdProp(Instance, PropInfo)<>0;
 | 
						|
        if HasAncestor then
 | 
						|
          DefBoolValue := GetOrdProp(Ancestor, PropInfo)<>0
 | 
						|
        else
 | 
						|
          DefBoolValue := PropInfo^.Default<>0;
 | 
						|
        DefValue:=PropInfo^.Default;
 | 
						|
        //debugln([PropInfo^.Name,', HasAncestor=',HasAncestor,', BoolValue=',BoolValue,', DefBoolValue=',DefBoolValue,' Default=',DefValue]);
 | 
						|
        if (BoolValue<>DefBoolValue) or (DefValue=longint($80000000)) then
 | 
						|
          WriteAssign(PropName,GetBoolLiteral(BoolValue));
 | 
						|
      end;
 | 
						|
    tkInterface:
 | 
						|
      begin
 | 
						|
        IntfValue := GetInterfaceProp(Instance, PropInfo);
 | 
						|
        if not Assigned(IntfValue) then
 | 
						|
          WriteAssign(PropName,'Nil')
 | 
						|
        else if Supports(IntfValue, IInterfaceComponentReference, CompRef) then
 | 
						|
        begin
 | 
						|
          Component := CompRef.GetComponent;
 | 
						|
          AncestorComponent := nil;
 | 
						|
          if HasAncestor then
 | 
						|
          begin
 | 
						|
            AncestorIntf := GetInterfaceProp(Instance, PropInfo);
 | 
						|
            if Supports(AncestorIntf, IInterfaceComponentReference, CompRef) then
 | 
						|
            begin
 | 
						|
              AncestorComponent := CompRef.GetComponent;
 | 
						|
              if (AncestorComponent<>Component) and
 | 
						|
                 (AncestorComponent.Owner = FRootAncestor) and
 | 
						|
                 (Component.Owner = Root) and
 | 
						|
                 SameText(AncestorComponent.Name,Component.Name) then
 | 
						|
              begin
 | 
						|
                // value is a component, and it is the same as in the ancestor
 | 
						|
                // Note: a descendant has new instances with same names
 | 
						|
                AncestorComponent := Component;
 | 
						|
              end;
 | 
						|
            end;
 | 
						|
          end;
 | 
						|
 | 
						|
          if Component<>AncestorComponent then
 | 
						|
          begin
 | 
						|
            Name:=GetComponentPath(Component);
 | 
						|
            if Name='' then
 | 
						|
              raise EWriteError.Create('cannot write property "'+DbgSName(Instance)+'.'+PropName+'"');
 | 
						|
            WriteAssign(PropName,Name);
 | 
						|
          end;
 | 
						|
        end else
 | 
						|
          raise EWriteError.Create('interface property "'+PropName+'" does not support IInterfaceComponentReference');
 | 
						|
      end;
 | 
						|
  else
 | 
						|
    {$IFDEF VerboseCompWriterPas}
 | 
						|
    debugln(['TCompWriterPas.WriteProperty Property="',PropName,'" Kind=',PropType^.Kind]);
 | 
						|
    raise EWriteError.Create('proptype not supported: '+GetEnumName(TypeInfo(PropType^.Kind),ord(PropType^.Kind)));
 | 
						|
    {$ENDIF}
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCompWriterPas.WriteProperties(Instance: TPersistent);
 | 
						|
var
 | 
						|
  PropCount, i: integer;
 | 
						|
  PropList: PPropList;
 | 
						|
begin
 | 
						|
  PropCount:=GetPropList(Instance,PropList);
 | 
						|
  if PropCount>0 then
 | 
						|
    try
 | 
						|
      for i := 0 to PropCount-1 do
 | 
						|
        if IsStoredProp(Instance,PropList^[i]) then
 | 
						|
          WriteProperty(Instance,PropList^[i]);
 | 
						|
    finally
 | 
						|
      Freemem(PropList);
 | 
						|
    end;
 | 
						|
  WriteDefineProperties(Instance);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCompWriterPas.WriteDefineProperties(Instance: TPersistent);
 | 
						|
var
 | 
						|
  Col: Integer;
 | 
						|
  InLit, NeedComma: boolean;
 | 
						|
  InstancePath: String;
 | 
						|
 | 
						|
  function CheckCol(aCol: integer): boolean;
 | 
						|
  begin
 | 
						|
    if (Col<=CurIndent+1) or (aCol<=MaxColumn) then exit(true);
 | 
						|
    Result:=false;
 | 
						|
    if NeedComma then
 | 
						|
      Write(',');
 | 
						|
    WriteLn;
 | 
						|
    WriteIndent;
 | 
						|
    Col:=CurIndent+1;
 | 
						|
    NeedComma:=false;
 | 
						|
  end;
 | 
						|
 | 
						|
  function GetPath: string;
 | 
						|
  begin
 | 
						|
    if InstancePath='' then
 | 
						|
    begin
 | 
						|
      if PropertyPath<>'' then
 | 
						|
      begin
 | 
						|
        InstancePath:=PropertyPath;
 | 
						|
        Delete(InstancePath,length(InstancePath),1); // chomp '.'
 | 
						|
      end
 | 
						|
      else if Instance is TComponent then
 | 
						|
        InstancePath:=GetComponentPath(TComponent(Instance))
 | 
						|
      else
 | 
						|
        InstancePath:='';
 | 
						|
      if InstancePath='' then
 | 
						|
        raise EWriteError.Create('cannot write DefineProperties of "'+DbgSName(Instance)+'"');
 | 
						|
    end;
 | 
						|
    Result:=InstancePath;
 | 
						|
  end;
 | 
						|
 | 
						|
var
 | 
						|
  HasAncestor, Handled: Boolean;
 | 
						|
  DefValue, Value: LongInt;
 | 
						|
  aStream: TMemoryStream;
 | 
						|
  BinWriter: TWriter;
 | 
						|
  s: String;
 | 
						|
  p: PChar;
 | 
						|
  c: Char;
 | 
						|
  i: Integer;
 | 
						|
begin
 | 
						|
  InstancePath:='';
 | 
						|
 | 
						|
  Handled:=false;
 | 
						|
  if Assigned(OnDefineProperties) then
 | 
						|
  begin
 | 
						|
    s:=GetPath;
 | 
						|
    OnDefineProperties(Self,Instance,s,Handled);
 | 
						|
    if Handled then exit;
 | 
						|
  end;
 | 
						|
  if DefinePropertiesEvents<>nil then
 | 
						|
  begin
 | 
						|
    s:=GetPath;
 | 
						|
    CallDefinePropertiesPas(Self,Instance,s,Handled);
 | 
						|
    if Handled then exit;
 | 
						|
  end;
 | 
						|
 | 
						|
  if Instance is TComponent then
 | 
						|
  begin
 | 
						|
    HasAncestor := Assigned(Ancestor) and ((Instance = Root) or
 | 
						|
      (Instance.ClassType = Ancestor.ClassType));
 | 
						|
    if HasAncestor then
 | 
						|
      DefValue := TComponent(Ancestor).DesignInfo
 | 
						|
    else
 | 
						|
      DefValue := 0;
 | 
						|
    Value:=TComponent(Instance).DesignInfo;
 | 
						|
    if Value<>DefValue then
 | 
						|
    begin
 | 
						|
      // Note: DesignInfo contains Left/Top. On BigEndian systems the order
 | 
						|
      // is reversed, which is already handled in TComponent.DefineProperties
 | 
						|
      // -> it is the same longint value on Little and BigEndian system
 | 
						|
      s:=GetPath;
 | 
						|
      if s<>'' then
 | 
						|
      begin
 | 
						|
        if SameText(s,'Self') then
 | 
						|
          s:=''
 | 
						|
        else
 | 
						|
          s:=s+'.';
 | 
						|
      end;
 | 
						|
      WriteAssign(s + 'DesignInfo',IntToStr(Value));
 | 
						|
    end;
 | 
						|
  end;
 | 
						|
 | 
						|
  if TMethod(@TAccessComp(Instance).DefineProperties).Code<>FDefaultDefineProperties
 | 
						|
  then begin
 | 
						|
    // this class has overriden DefineProperties
 | 
						|
    aStream:=TMemoryStream.Create;
 | 
						|
    BinWriter:=TWriter.Create(aStream,1024);
 | 
						|
    try
 | 
						|
      BinWriter.Root:=Root;
 | 
						|
      BinWriter.RootAncestor:=RootAncestor;
 | 
						|
      BinWriter.Ancestor:=Ancestor;
 | 
						|
      BinWriter.IgnoreChildren:=IgnoreChildren;
 | 
						|
      BinWriter.OnWriteMethodProperty:=OnWriteMethodProperty;
 | 
						|
      BinWriter.OnWriteStringProperty:=OnWriteStringProperty;
 | 
						|
      TAccessComp(Instance).DefineProperties(BinWriter);
 | 
						|
      BinWriter.WriteListEnd;
 | 
						|
      FreeAndNil(BinWriter); // flush buffer to stream
 | 
						|
      if aStream.Size>1 then
 | 
						|
      begin
 | 
						|
        WriteIndent;
 | 
						|
        s:=GetPath;
 | 
						|
        s:=ExecCustomProc+'('+s+',[';
 | 
						|
        Write(s);
 | 
						|
        AddNeededUnit(ExecCustomProcUnit);
 | 
						|
        Col:=CurIndent+length(s)+1;
 | 
						|
        Indent;
 | 
						|
        NeedComma:=false;
 | 
						|
        CheckCol(Col);
 | 
						|
        InLit:=false;
 | 
						|
        p:=PChar(aStream.Memory);
 | 
						|
        for i:=0 to aStream.Size-1 do
 | 
						|
        begin
 | 
						|
          c:=p^;
 | 
						|
          if c in [#32..#126] then
 | 
						|
          begin
 | 
						|
            if (not InLit) or (Col+2>MaxColumn) then
 | 
						|
            begin
 | 
						|
              if InLit then
 | 
						|
                Write('''');
 | 
						|
              CheckCol(Col+3);
 | 
						|
              InLit:=true;
 | 
						|
              Write('''');
 | 
						|
              inc(Col);
 | 
						|
            end;
 | 
						|
            Write(c);
 | 
						|
            inc(Col);
 | 
						|
            NeedComma:=true;
 | 
						|
          end else begin
 | 
						|
            if InLit then
 | 
						|
            begin
 | 
						|
              Write('''');
 | 
						|
              inc(Col);
 | 
						|
              InLit:=false;
 | 
						|
            end;
 | 
						|
            s:='#'+IntToStr(ord(c));
 | 
						|
            CheckCol(Col+length(s));
 | 
						|
            Write(s);
 | 
						|
            inc(Col,length(s));
 | 
						|
            NeedComma:=true;
 | 
						|
          end;
 | 
						|
          inc(p);
 | 
						|
        end;
 | 
						|
        if InLit then
 | 
						|
          Write('''');
 | 
						|
        Write(']);');
 | 
						|
        WriteLn;
 | 
						|
        Unindent;
 | 
						|
      end;
 | 
						|
    finally
 | 
						|
      BinWriter.Free;
 | 
						|
      aStream.Free;
 | 
						|
    end;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCompWriterPas.WriteCollection(PropName: string;
 | 
						|
  Collection: TCollection);
 | 
						|
var
 | 
						|
  i: Integer;
 | 
						|
  Item: TCollectionItem;
 | 
						|
begin
 | 
						|
  WriteStatement(PropName+'.Clear;');
 | 
						|
  for i:=0 to Collection.Count-1 do
 | 
						|
  begin
 | 
						|
    Item:=Collection.Items[i];
 | 
						|
    WriteWithDo(Item.ClassName+'('+PropName+'.Add)');
 | 
						|
    WriteProperties(Item);
 | 
						|
    WriteWithEnd;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
function TCompWriterPas.GetComponentPath(Component: TComponent): string;
 | 
						|
var
 | 
						|
  Name: String;
 | 
						|
  C: TComponent;
 | 
						|
begin
 | 
						|
  if Component=nil then
 | 
						|
    Result:='Nil'
 | 
						|
  else if Component=LookupRoot then
 | 
						|
  begin
 | 
						|
    if cwpoNoSelf in Options then
 | 
						|
      Result:=LookupRoot.Name
 | 
						|
    else
 | 
						|
      Result:='Self';
 | 
						|
  end
 | 
						|
  else begin
 | 
						|
    Name:= '';
 | 
						|
    C:=Component;
 | 
						|
    While (C<>Nil) do
 | 
						|
    begin
 | 
						|
      if (Name<>'') Then
 | 
						|
        Name:='.'+Name;
 | 
						|
      if C.Owner = LookupRoot then
 | 
						|
      begin
 | 
						|
        Name := C.Name+Name;
 | 
						|
        if (cwpoNoWithBlocks in Options) then
 | 
						|
        begin
 | 
						|
          if cwpoNoSelf in Options then
 | 
						|
            Name := C.Owner.Name+'.'+Name;
 | 
						|
        end;
 | 
						|
        break;
 | 
						|
      end
 | 
						|
      else if C = LookupRoot then
 | 
						|
      begin
 | 
						|
        if cwpoNoSelf in Options then
 | 
						|
          Name := C.Name+Name
 | 
						|
        else
 | 
						|
          Name := 'Self'+Name;
 | 
						|
        break;
 | 
						|
      end else if C.Name='' then
 | 
						|
        exit('');
 | 
						|
      Name:=C.Name+Name;
 | 
						|
      // ToDo: store used unit
 | 
						|
      C:=C.Owner;
 | 
						|
    end;
 | 
						|
    Result:=Name;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
function TCompWriterPas.GetBoolLiteral(b: boolean): string;
 | 
						|
begin
 | 
						|
  if b then
 | 
						|
    Result:='True'
 | 
						|
  else
 | 
						|
    Result:='False';
 | 
						|
end;
 | 
						|
 | 
						|
function TCompWriterPas.GetCharLiteral(c: integer): string;
 | 
						|
begin
 | 
						|
  case c of
 | 
						|
  32..126: Result:=''''+chr(c)+'''';
 | 
						|
  else     Result:='#'+IntToStr(c);
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
function TCompWriterPas.GetWideCharLiteral(c: integer): string;
 | 
						|
begin
 | 
						|
  case c of
 | 
						|
  32..126:
 | 
						|
    Result:=''''+Chr(c)+'''';
 | 
						|
  0..31,127..255,$D800..$DFFF:
 | 
						|
    Result:='#'+IntToStr(c);
 | 
						|
  else
 | 
						|
    if cwpoSrcCodepageUTF8 in Options then
 | 
						|
      Result:=''''+UTF16ToUTF8(WideChar(c))+''''
 | 
						|
    else
 | 
						|
      Result:='#'+IntToStr(c);
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
function TCompWriterPas.GetStringLiteral(const s: string): string;
 | 
						|
 | 
						|
  function IsSpecialChar(p: PChar): boolean;
 | 
						|
  const
 | 
						|
    SpecialChars = [#0..#31,#127,#255];
 | 
						|
  begin
 | 
						|
    Result:=(p^ in SpecialChars) or (IsValidUTF8(p)=0);
 | 
						|
  end;
 | 
						|
 | 
						|
var
 | 
						|
  InLit: Boolean;
 | 
						|
  p, StartP: PChar;
 | 
						|
  c: Char;
 | 
						|
begin
 | 
						|
  Result:='';
 | 
						|
  if s='' then exit;
 | 
						|
  InLit:=false;
 | 
						|
  p:=PChar(s);
 | 
						|
  repeat
 | 
						|
    c:=p^;
 | 
						|
    if (c=#0) and (p-PChar(s)=length(s)) then
 | 
						|
      break
 | 
						|
    else if IsSpecialChar(p) then
 | 
						|
    begin
 | 
						|
      if InLit then begin
 | 
						|
        InLit:=false;
 | 
						|
        Result:=Result+'''';
 | 
						|
      end;
 | 
						|
      Result:=Result+'#'+IntToStr(ord(c));
 | 
						|
      inc(p);
 | 
						|
    end else begin
 | 
						|
      if not InLit then begin
 | 
						|
        InLit:=true;
 | 
						|
        Result:=Result+'''';
 | 
						|
      end;
 | 
						|
      if c='''' then begin
 | 
						|
        Result:=Result+'''''';
 | 
						|
        inc(p);
 | 
						|
      end else begin
 | 
						|
        StartP:=p;
 | 
						|
        repeat
 | 
						|
          inc(p,IsValidUTF8(p));
 | 
						|
          c:=p^;
 | 
						|
        until ((c=#0) and (p-PChar(s)=length(s))) or IsSpecialChar(p) or (c='''');
 | 
						|
        Result:=Result+copy(s,StartP-PChar(s)+1,p-StartP);
 | 
						|
      end;
 | 
						|
    end;
 | 
						|
  until false;
 | 
						|
  if InLit then
 | 
						|
    Result:=Result+'''';
 | 
						|
end;
 | 
						|
 | 
						|
function TCompWriterPas.GetWStringLiteral(p: PWideChar; Count: integer): string;
 | 
						|
 | 
						|
  function IsSpecialChar(w: PWideChar): boolean;
 | 
						|
  const
 | 
						|
    SpecialChars = [#0..#31,#127];
 | 
						|
  begin
 | 
						|
    if w^ in SpecialChars then exit(true);
 | 
						|
    if cwpoSrcCodepageUTF8 in FOptions then begin
 | 
						|
      Result:=IsValidUTF16(w)=0;
 | 
						|
    end else begin
 | 
						|
      Result:=w^>=#$7f;
 | 
						|
    end;
 | 
						|
  end;
 | 
						|
 | 
						|
var
 | 
						|
  InLit: Boolean;
 | 
						|
  c: WideChar;
 | 
						|
  FirstP, StartP: PWideChar;
 | 
						|
  AddLen: SizeUInt;
 | 
						|
  s: string;
 | 
						|
  OldLen: Integer;
 | 
						|
begin
 | 
						|
  Result:='';
 | 
						|
  if Count=0 then exit;
 | 
						|
  FirstP:=p;
 | 
						|
  InLit:=false;
 | 
						|
  s:='';
 | 
						|
  repeat
 | 
						|
    c:=p^;
 | 
						|
    if (c=#0) and (p-FirstP=Count) then
 | 
						|
      break
 | 
						|
    else if IsSpecialChar(p) then
 | 
						|
    begin
 | 
						|
      if InLit then begin
 | 
						|
        InLit:=false;
 | 
						|
        Result:=Result+'''';
 | 
						|
      end;
 | 
						|
      Result:=Result+'#'+Format('%.4d',[ord(c)]);
 | 
						|
      inc(p);
 | 
						|
    end else begin
 | 
						|
      if not InLit then begin
 | 
						|
        InLit:=true;
 | 
						|
        Result:=Result+'''';
 | 
						|
      end;
 | 
						|
      if c='''' then begin
 | 
						|
        Result:=Result+'''''';
 | 
						|
        inc(p);
 | 
						|
      end else begin
 | 
						|
        StartP:=p;
 | 
						|
        repeat
 | 
						|
          inc(p,IsValidUTF16(p));
 | 
						|
          c:=p^;
 | 
						|
        until ((c=#0) and (p-FirstP=Count)) or IsSpecialChar(p) or (c='''');
 | 
						|
        AddLen:=p-StartP;
 | 
						|
        if length(s)<AddLen*3 then SetLength(s,AddLen*3);
 | 
						|
        if ConvertUTF16ToUTF8(@s[1],length(s),StartP,AddLen,
 | 
						|
            [toInvalidCharError,toUnfinishedCharError],AddLen)=trNoError then
 | 
						|
          dec(AddLen); // omit #0
 | 
						|
        OldLen:=length(Result);
 | 
						|
        SetLength(Result,OldLen+AddLen);
 | 
						|
        System.Move(s[1],Result[OldLen+1],AddLen);
 | 
						|
      end;
 | 
						|
    end;
 | 
						|
  until false;
 | 
						|
  if InLit then
 | 
						|
    Result:=Result+'''';
 | 
						|
end;
 | 
						|
 | 
						|
function TCompWriterPas.GetFloatLiteral(const e: Extended): string;
 | 
						|
var
 | 
						|
  s: String;
 | 
						|
begin
 | 
						|
  s:='';
 | 
						|
  str(e,s);
 | 
						|
  Result:=ShortenFloat(s);
 | 
						|
end;
 | 
						|
 | 
						|
function TCompWriterPas.GetCurrencyLiteral(const c: currency): string;
 | 
						|
var
 | 
						|
  i: int64 absolute c;
 | 
						|
var
 | 
						|
  s: String;
 | 
						|
begin
 | 
						|
  if i mod 10000=0 then
 | 
						|
    s:=IntToStr(i div 10000)
 | 
						|
  else begin
 | 
						|
    s:=IntToStr(i);
 | 
						|
    while length(s)<4 do
 | 
						|
      s:='0'+s;
 | 
						|
    if length(s)=4 then
 | 
						|
      s:='0.'+s
 | 
						|
    else
 | 
						|
      system.insert('.',s,length(s)-3);
 | 
						|
  end;
 | 
						|
  Result:=s;
 | 
						|
end;
 | 
						|
 | 
						|
function TCompWriterPas.ShortenFloat(s: string): string;
 | 
						|
var
 | 
						|
  p, i: SizeInt;
 | 
						|
begin
 | 
						|
  // remove unneeded leading 0 of exponent
 | 
						|
  p:=Pos('E',s);
 | 
						|
  if p<1 then exit(s);
 | 
						|
  i:=p;
 | 
						|
  if s[i+1]='+' then inc(i);
 | 
						|
  while (i<length(s)) and (s[i+1]='0') do
 | 
						|
    inc(i);
 | 
						|
  if i>p then
 | 
						|
    if i=length(s) then
 | 
						|
      Delete(s,p,i-p+1) // delete whole exponent
 | 
						|
    else
 | 
						|
      Delete(s,p+1,i-p);
 | 
						|
  // remove trailing 0 of base
 | 
						|
  i:=p;
 | 
						|
  while (i>2) and (s[i-1]='0') do
 | 
						|
    dec(i);
 | 
						|
  if not (s[i-1] in ['0'..'9']) then inc(i);
 | 
						|
  if i<p then
 | 
						|
    Delete(s,i,p-i);
 | 
						|
  // remove leading space
 | 
						|
  if s[1]=' ' then
 | 
						|
    Delete(s,1,1);
 | 
						|
  Result:=s;
 | 
						|
end;
 | 
						|
 | 
						|
function TCompWriterPas.GetEnumExpr(TypeInfo: PTypeInfo; Value: integer;
 | 
						|
  AllowOutOfRange: boolean): string;
 | 
						|
var
 | 
						|
  PT: PTypeData;
 | 
						|
begin
 | 
						|
  PT:=GetTypeData(TypeInfo);
 | 
						|
  if (Value>=PT^.MinValue) and (Value<=PT^.MaxValue) then
 | 
						|
    case TypeInfo^.Kind of
 | 
						|
    tkBool: Result:=GetBoolLiteral(Value=ord(true));
 | 
						|
    tkChar: Result:=GetCharLiteral(Value);
 | 
						|
    tkEnumeration: Result:=GetEnumName(TypeInfo,Value);
 | 
						|
    else Result:=IntToStr(Value);
 | 
						|
    end
 | 
						|
  else if AllowOutOfRange then
 | 
						|
    Result:=TypeInfo^.Name+'('+IntToStr(Value)+')'
 | 
						|
  else
 | 
						|
    raise EWriteError.Create('enum '+IntToStr(Value)+' is out of range of type "'+TypeInfo^.Name+'"');
 | 
						|
end;
 | 
						|
 | 
						|
function TCompWriterPas.GetVersionStatement: string;
 | 
						|
begin
 | 
						|
  Result:='// Format version '+IntToStr(CSPVersion);
 | 
						|
end;
 | 
						|
 | 
						|
constructor TCompWriterPas.Create(AStream: TStream);
 | 
						|
var
 | 
						|
  C: TAccessComp;
 | 
						|
begin
 | 
						|
  FIndentStep:=2;
 | 
						|
  FStream:=AStream;
 | 
						|
  FLineEnding:=system.LineEnding;
 | 
						|
  FAssignOp:=CSPDefaultAssignOp;
 | 
						|
  FSignatureBegin:=CSPDefaultSignatureBegin;
 | 
						|
  FSignatureEnd:=CSPDefaultSignatureEnd;
 | 
						|
  FMaxColumn:=CSPDefaultMaxColumn;
 | 
						|
  FExecCustomProc:=CSPDefaultExecCustomProc;
 | 
						|
  FExecCustomProcUnit:=CSPDefaultExecCustomProcUnit;
 | 
						|
  FNeededUnits:=TStringListUTF8Fast.Create;
 | 
						|
  FAccessClass:=CSPDefaultAccessClass;
 | 
						|
  C:=TAccessComp.Create(nil);
 | 
						|
  FDefaultDefineProperties:=TMethod(@C.DefineProperties).Code;
 | 
						|
  C.Free;
 | 
						|
end;
 | 
						|
 | 
						|
destructor TCompWriterPas.Destroy;
 | 
						|
begin
 | 
						|
  FreeAndNil(FNeededUnits);
 | 
						|
  inherited Destroy;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCompWriterPas.WriteComponentCreate(Component: TComponent);
 | 
						|
var
 | 
						|
  OldAncestor: TPersistent;
 | 
						|
  OldRoot, OldRootAncestor: TComponent;
 | 
						|
  HasAncestor: boolean;
 | 
						|
begin
 | 
						|
  if (Component=LookupRoot) then exit;
 | 
						|
  OldRoot:=FRoot;
 | 
						|
  OldAncestor:=FAncestor;
 | 
						|
  OldRootAncestor:=FRootAncestor;
 | 
						|
  Try
 | 
						|
    DetermineAncestor(Component);
 | 
						|
    HasAncestor:=FAncestor is TComponent;
 | 
						|
    if not CreatedByAncestor(Component) then
 | 
						|
      WriteAssign(Component.Name,Component.ClassName+'.Create('+GetComponentPath(Root)+')');
 | 
						|
    if HasAncestor then begin
 | 
						|
      if (csInline in Component.ComponentState)
 | 
						|
      and not (csInline in TComponent(Ancestor).ComponentState) then
 | 
						|
      begin
 | 
						|
        NeedAccessClass:=true;
 | 
						|
        WriteStatement(AccessClass+'(TComponent('+Component.Name+')).SetInline('+GetBoolLiteral(true)+');');
 | 
						|
      end;
 | 
						|
      if (csAncestor in Component.ComponentState)
 | 
						|
      and not (csAncestor in TComponent(Ancestor).ComponentState) then
 | 
						|
      begin
 | 
						|
        NeedAccessClass:=true;
 | 
						|
        WriteStatement(AccessClass+'(TComponent('+Component.Name+')).SetAncestor('+GetBoolLiteral(true)+');');
 | 
						|
      end;
 | 
						|
    end;
 | 
						|
    if not IgnoreChildren then
 | 
						|
      WriteChildren(Component,cwpcsCreate);
 | 
						|
  finally
 | 
						|
    FAncestor:=OldAncestor;
 | 
						|
    FRoot:=OldRoot;
 | 
						|
    FRootAncestor:=OldRootAncestor;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCompWriterPas.WriteComponent(Component: TComponent);
 | 
						|
var
 | 
						|
  OldAncestor : TPersistent;
 | 
						|
  OldRoot, OldRootAncestor : TComponent;
 | 
						|
begin
 | 
						|
  OldRoot:=FRoot;
 | 
						|
  OldAncestor:=FAncestor;
 | 
						|
  OldRootAncestor:=FRootAncestor;
 | 
						|
  Try
 | 
						|
    // Component.ComponentState:=Component.FComponentState+[csWriting];
 | 
						|
    DetermineAncestor(Component);
 | 
						|
    WriteComponentData(Component);
 | 
						|
  finally
 | 
						|
    FAncestor:=OldAncestor;
 | 
						|
    FRoot:=OldRoot;
 | 
						|
    FRootAncestor:=OldRootAncestor;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCompWriterPas.WriteDescendant(ARoot: TComponent; AnAncestor: TComponent);
 | 
						|
begin
 | 
						|
  FRoot := ARoot;
 | 
						|
  FAncestor := AnAncestor;
 | 
						|
  FRootAncestor := AnAncestor;
 | 
						|
  FLookupRoot := ARoot;
 | 
						|
  FNeedAccessClass := false;
 | 
						|
  if not (cwpoNoSignature in Options) then
 | 
						|
    WriteStatement(SignatureBegin);
 | 
						|
  WriteStatement(GetVersionStatement);
 | 
						|
  if cwpoNoSelf in Options then
 | 
						|
    WriteWithDo(ARoot.Name);
 | 
						|
  WriteComponent(ARoot);
 | 
						|
  if cwpoNoSelf in Options then
 | 
						|
    WriteWithEnd;
 | 
						|
  if not (cwpoNoSignature in Options) then begin
 | 
						|
    if cwpoNoFinalLineBreak in Options then
 | 
						|
      begin
 | 
						|
      WriteIndent;
 | 
						|
      Write(SignatureEnd);
 | 
						|
      end
 | 
						|
    else
 | 
						|
      WriteStatement(SignatureEnd);
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCompWriterPas.WriteIndent;
 | 
						|
begin
 | 
						|
  Write(StringOfChar(' ',CurIndent));
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCompWriterPas.Write(const s: string);
 | 
						|
begin
 | 
						|
  if s='' then exit;
 | 
						|
  FStream.Write(s[1],length(s));
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCompWriterPas.WriteLn;
 | 
						|
begin
 | 
						|
  Write(LineEnding);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCompWriterPas.WriteStatement(const s: string);
 | 
						|
begin
 | 
						|
  WriteIndent;
 | 
						|
  Write(s);
 | 
						|
  WriteLn;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCompWriterPas.WriteAssign(const LHS, RHS: string);
 | 
						|
begin
 | 
						|
  WriteIndent;
 | 
						|
  Write(LHS);
 | 
						|
  Write(AssignOp);
 | 
						|
  Write(RHS);
 | 
						|
  Write(';');
 | 
						|
  WriteLn;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCompWriterPas.WriteWithDo(const Expr: string);
 | 
						|
begin
 | 
						|
  if not (cwpoNoWithBlocks in Options) then
 | 
						|
    WriteStatement('with '+Expr+' do begin');
 | 
						|
  Indent;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCompWriterPas.WriteWithEnd;
 | 
						|
begin
 | 
						|
  Unindent;
 | 
						|
  if not (cwpoNoWithBlocks in Options) then
 | 
						|
    WriteStatement('end;');
 | 
						|
end;
 | 
						|
 | 
						|
function TCompWriterPas.CreatedByAncestor(Component: TComponent): boolean;
 | 
						|
begin
 | 
						|
  Result:=(FAncestor is TComponent)
 | 
						|
    and (TComponent(FAncestor).Owner = FRootAncestor)
 | 
						|
    and (Component.Owner = Root)
 | 
						|
    and SameText(Component.Name,TComponent(FAncestor).Name)
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCompWriterPas.AddNeededUnit(const AnUnitName: string);
 | 
						|
begin
 | 
						|
  if FNeededUnits.IndexOf(AnUnitName)>=0 then exit;
 | 
						|
  FNeededUnits.Add(AnUnitName);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCompWriterPas.Indent;
 | 
						|
begin
 | 
						|
  CurIndent:=CurIndent+IndentStep;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCompWriterPas.Unindent;
 | 
						|
begin
 | 
						|
  CurIndent:=CurIndent-IndentStep;
 | 
						|
end;
 | 
						|
 | 
						|
finalization
 | 
						|
  DefinePropertiesEvents.Free;
 | 
						|
 | 
						|
end.
 | 
						|
 |