mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 12:23:24 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1191 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			1191 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
{
 | 
						|
    This file is part of the Free Component Library (FCL)
 | 
						|
    Copyright (c) 1999-2000 by the Free Pascal development team
 | 
						|
 | 
						|
    See the file COPYING.FPC, included in this distribution,
 | 
						|
    for details about the copyright.
 | 
						|
 | 
						|
    This program is distributed in the hope that it will be useful,
 | 
						|
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 | 
						|
 | 
						|
 **********************************************************************}
 | 
						|
 | 
						|
 | 
						|
{****************************************************************************}
 | 
						|
{*                         TBinaryObjectWriter                              *}
 | 
						|
{****************************************************************************}
 | 
						|
 | 
						|
{$ifndef FPUNONE}
 | 
						|
{$IFNDEF FPC_HAS_TYPE_EXTENDED}
 | 
						|
procedure DoubleToExtended(d : double; e : pointer);
 | 
						|
var mant : qword;
 | 
						|
    exp : smallint;
 | 
						|
    sign : boolean;
 | 
						|
begin
 | 
						|
  mant:=(qword(d) and $000FFFFFFFFFFFFF) shl 12;
 | 
						|
  exp :=(qword(d) shr 52) and $7FF;
 | 
						|
  sign:=(qword(d) and $8000000000000000)<>0;
 | 
						|
  case exp of
 | 
						|
       0 : begin
 | 
						|
             if mant<>0 then  //denormalized value: hidden bit is 0. normalize it
 | 
						|
             begin
 | 
						|
               exp:=16383-1022;
 | 
						|
               while (mant and $8000000000000000)=0 do
 | 
						|
               begin
 | 
						|
                 dec(exp);
 | 
						|
                 mant:=mant shl 1;
 | 
						|
               end;
 | 
						|
               dec(exp); //don't shift, most significant bit is not hidden in extended
 | 
						|
             end;
 | 
						|
           end;
 | 
						|
    2047 : exp:=$7FFF //either infinity or NaN
 | 
						|
    else
 | 
						|
    begin
 | 
						|
      inc(exp,16383-1023);
 | 
						|
      mant:=(mant shr 1) or $8000000000000000; //unhide hidden bit
 | 
						|
    end;
 | 
						|
  end;
 | 
						|
  if sign then exp:=exp or $8000;
 | 
						|
  mant:=NtoLE(mant);
 | 
						|
  exp:=NtoLE(word(exp));
 | 
						|
  move(mant,pbyte(e)[0],8); //mantissa         : bytes 0..7
 | 
						|
  move(exp,pbyte(e)[8],2);  //exponent and sign: bytes 8..9
 | 
						|
end;
 | 
						|
{$ENDIF}
 | 
						|
{$endif}
 | 
						|
 | 
						|
procedure TBinaryObjectWriter.WriteWord(w : word); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
 | 
						|
begin
 | 
						|
  w:=NtoLE(w);
 | 
						|
  Write(w,2);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBinaryObjectWriter.WriteDWord(lw : longword); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
 | 
						|
begin
 | 
						|
  lw:=NtoLE(lw);
 | 
						|
  Write(lw,4);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBinaryObjectWriter.WriteQWord(qw : qword); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
 | 
						|
begin
 | 
						|
  qw:=NtoLE(qw);
 | 
						|
  Write(qw,8);
 | 
						|
end;
 | 
						|
 | 
						|
{$ifndef FPUNONE}
 | 
						|
procedure TBinaryObjectWriter.WriteExtended(e : extended); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
 | 
						|
{$IFNDEF FPC_HAS_TYPE_EXTENDED}
 | 
						|
var ext : array[0..9] of byte;
 | 
						|
{$ENDIF}
 | 
						|
begin
 | 
						|
{$IFNDEF FPC_HAS_TYPE_EXTENDED}
 | 
						|
  {$IFDEF FPC_DOUBLE_HILO_SWAPPED}
 | 
						|
  { SwapDoubleHiLo defined in reader.inc }
 | 
						|
  SwapDoubleHiLo(e);
 | 
						|
  {$ENDIF FPC_DOUBLE_HILO_SWAPPED}
 | 
						|
  DoubleToExtended(e,@(ext[0]));
 | 
						|
  Write(ext[0],10);
 | 
						|
{$ELSE}
 | 
						|
  Write(e,sizeof(e));
 | 
						|
{$ENDIF}
 | 
						|
end;
 | 
						|
{$endif}
 | 
						|
 | 
						|
constructor TBinaryObjectWriter.Create(Stream: TStream; BufSize: Integer);
 | 
						|
begin
 | 
						|
  inherited Create;
 | 
						|
  If (Stream=Nil) then
 | 
						|
    Raise EWriteError.Create(SEmptyStreamIllegalWriter);
 | 
						|
  FStream := Stream;
 | 
						|
  FBufSize := BufSize;
 | 
						|
  GetMem(FBuffer, BufSize);
 | 
						|
end;
 | 
						|
 | 
						|
destructor TBinaryObjectWriter.Destroy;
 | 
						|
begin
 | 
						|
  // Flush all data which hasn't been written yet
 | 
						|
  FlushBuffer;
 | 
						|
 | 
						|
  if Assigned(FBuffer) then
 | 
						|
    FreeMem(FBuffer, FBufSize);
 | 
						|
 | 
						|
  inherited Destroy;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBinaryObjectWriter.BeginCollection;
 | 
						|
begin
 | 
						|
  WriteValue(vaCollection);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBinaryObjectWriter.BeginComponent(Component: TComponent;
 | 
						|
  Flags: TFilerFlags; ChildPos: Integer);
 | 
						|
var
 | 
						|
  Prefix: Byte;
 | 
						|
begin
 | 
						|
  if not FSignatureWritten then
 | 
						|
  begin
 | 
						|
    Write(FilerSignature, SizeOf(FilerSignature));
 | 
						|
    FSignatureWritten := True;
 | 
						|
  end;
 | 
						|
 | 
						|
  { Only write the flags if they are needed! }
 | 
						|
  if Flags <> [] then
 | 
						|
  begin
 | 
						|
    Prefix := Integer(Flags) or $f0;
 | 
						|
    Write(Prefix, 1);
 | 
						|
    if ffChildPos in Flags then
 | 
						|
      WriteInteger(ChildPos);
 | 
						|
  end;
 | 
						|
 | 
						|
  WriteStr(Component.ClassName);
 | 
						|
  WriteStr(Component.Name);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBinaryObjectWriter.BeginList;
 | 
						|
begin
 | 
						|
  WriteValue(vaList);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBinaryObjectWriter.EndList;
 | 
						|
begin
 | 
						|
  WriteValue(vaNull);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBinaryObjectWriter.BeginProperty(const PropName: String);
 | 
						|
begin
 | 
						|
  WriteStr(PropName);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBinaryObjectWriter.EndProperty;
 | 
						|
begin
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBinaryObjectWriter.WriteBinary(const Buffer; Count: LongInt);
 | 
						|
begin
 | 
						|
  WriteValue(vaBinary);
 | 
						|
  WriteDWord(longword(Count));
 | 
						|
  Write(Buffer, Count);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBinaryObjectWriter.WriteBoolean(Value: Boolean);
 | 
						|
begin
 | 
						|
  if Value then
 | 
						|
    WriteValue(vaTrue)
 | 
						|
  else
 | 
						|
    WriteValue(vaFalse);
 | 
						|
end;
 | 
						|
 | 
						|
{$ifndef FPUNONE}
 | 
						|
procedure TBinaryObjectWriter.WriteFloat(const Value: Extended);
 | 
						|
begin
 | 
						|
  WriteValue(vaExtended);
 | 
						|
  WriteExtended(Value);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBinaryObjectWriter.WriteSingle(const Value: Single);
 | 
						|
begin
 | 
						|
  WriteValue(vaSingle);
 | 
						|
  WriteDWord(longword(Value));
 | 
						|
end;
 | 
						|
{$endif}
 | 
						|
 | 
						|
procedure TBinaryObjectWriter.WriteCurrency(const Value: Currency);
 | 
						|
begin
 | 
						|
  WriteValue(vaCurrency);
 | 
						|
  WriteQWord(qword(Value));
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
{$ifndef FPUNONE}
 | 
						|
procedure TBinaryObjectWriter.WriteDate(const Value: TDateTime);
 | 
						|
begin
 | 
						|
  WriteValue(vaDate);
 | 
						|
  WriteQWord(qword(Value));
 | 
						|
end;
 | 
						|
{$endif}
 | 
						|
 | 
						|
procedure TBinaryObjectWriter.WriteIdent(const Ident: string);
 | 
						|
begin
 | 
						|
  { Check if Ident is a special identifier before trying to just write
 | 
						|
    Ident directly }
 | 
						|
  if UpperCase(Ident) = 'NIL' then
 | 
						|
    WriteValue(vaNil)
 | 
						|
  else if UpperCase(Ident) = 'FALSE' then
 | 
						|
    WriteValue(vaFalse)
 | 
						|
  else if UpperCase(Ident) = 'TRUE' then
 | 
						|
    WriteValue(vaTrue)
 | 
						|
  else if UpperCase(Ident) = 'NULL' then
 | 
						|
    WriteValue(vaNull) else
 | 
						|
  begin
 | 
						|
    WriteValue(vaIdent);
 | 
						|
    WriteStr(Ident);
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBinaryObjectWriter.WriteInteger(Value: Int64);
 | 
						|
var
 | 
						|
  s: ShortInt;
 | 
						|
  i: SmallInt;
 | 
						|
  l: Longint;
 | 
						|
begin
 | 
						|
  { Use the smallest possible integer type for the given value: }
 | 
						|
  if (Value >= -128) and (Value <= 127) then
 | 
						|
  begin
 | 
						|
    WriteValue(vaInt8);
 | 
						|
    s := Value;
 | 
						|
    Write(s, 1);
 | 
						|
  end else if (Value >= -32768) and (Value <= 32767) then
 | 
						|
  begin
 | 
						|
    WriteValue(vaInt16);
 | 
						|
    i := Value;
 | 
						|
    WriteWord(word(i));
 | 
						|
  end else if (Value >= -$80000000) and (Value <= $7fffffff) then
 | 
						|
  begin
 | 
						|
    WriteValue(vaInt32);
 | 
						|
    l := Value;
 | 
						|
    WriteDWord(longword(l));
 | 
						|
  end else
 | 
						|
  begin
 | 
						|
    WriteValue(vaInt64);
 | 
						|
    WriteQWord(qword(Value));
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBinaryObjectWriter.WriteUInt64(Value: QWord);
 | 
						|
var
 | 
						|
  s: ShortInt;
 | 
						|
  i: SmallInt;
 | 
						|
  l: Longint;
 | 
						|
begin
 | 
						|
  { Use the smallest possible integer type for the given value: }
 | 
						|
  if (Value <= 127) then
 | 
						|
  begin
 | 
						|
    WriteValue(vaInt8);
 | 
						|
    s := Value;
 | 
						|
    Write(s, 1);
 | 
						|
  end else if (Value <= 32767) then
 | 
						|
  begin
 | 
						|
    WriteValue(vaInt16);
 | 
						|
    i := Value;
 | 
						|
    WriteWord(word(i));
 | 
						|
  end else if (Value <= $7fffffff) then
 | 
						|
  begin
 | 
						|
    WriteValue(vaInt32);
 | 
						|
    l := Value;
 | 
						|
    WriteDWord(longword(l));
 | 
						|
  end else
 | 
						|
  begin
 | 
						|
    WriteValue(vaQWord);
 | 
						|
    WriteQWord(Value);
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure TBinaryObjectWriter.WriteMethodName(const Name: String);
 | 
						|
begin
 | 
						|
  if Length(Name) > 0 then
 | 
						|
  begin
 | 
						|
    WriteValue(vaIdent);
 | 
						|
    WriteStr(Name);
 | 
						|
  end else
 | 
						|
    WriteValue(vaNil);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBinaryObjectWriter.WriteSet(Value: LongInt; SetType: Pointer);
 | 
						|
type
 | 
						|
  tset = set of 0..31;
 | 
						|
var
 | 
						|
  i: Integer;
 | 
						|
begin
 | 
						|
  WriteValue(vaSet);
 | 
						|
  for i := 0 to 31 do
 | 
						|
  begin
 | 
						|
    if (i in tset(Value)) then
 | 
						|
      WriteStr(GetEnumName(PTypeInfo(SetType), i));
 | 
						|
  end;
 | 
						|
  WriteStr('');
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBinaryObjectWriter.WriteString(const Value: String);
 | 
						|
var
 | 
						|
  i: Integer;
 | 
						|
  b: byte;
 | 
						|
begin
 | 
						|
  i := Length(Value);
 | 
						|
  if i <= 255 then
 | 
						|
  begin
 | 
						|
    WriteValue(vaString);
 | 
						|
    b := i;
 | 
						|
    Write(b, 1);
 | 
						|
  end else
 | 
						|
  begin
 | 
						|
    WriteValue(vaLString);
 | 
						|
    WriteDWord(longword(i));
 | 
						|
  end;
 | 
						|
  if i > 0 then
 | 
						|
    Write(Value[1], i);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBinaryObjectWriter.WriteWideString(const Value: WideString);
 | 
						|
var len : longword;
 | 
						|
{$IFDEF ENDIAN_BIG}
 | 
						|
    i : integer;
 | 
						|
    ws : widestring;
 | 
						|
{$ENDIF}
 | 
						|
begin
 | 
						|
  WriteValue(vaWString);
 | 
						|
  len:=Length(Value);
 | 
						|
  WriteDWord(len);
 | 
						|
  if len > 0 then
 | 
						|
  begin
 | 
						|
    {$IFDEF ENDIAN_BIG}
 | 
						|
    setlength(ws,len);
 | 
						|
    for i:=1 to len do
 | 
						|
      ws[i]:=widechar(SwapEndian(word(Value[i])));
 | 
						|
    Write(ws[1], len*sizeof(widechar));
 | 
						|
    {$ELSE}
 | 
						|
    Write(Value[1], len*sizeof(widechar));
 | 
						|
    {$ENDIF}
 | 
						|
  end;
 | 
						|
end;
 | 
						|
                      
 | 
						|
procedure TBinaryObjectWriter.WriteUnicodeString(const Value: UnicodeString);
 | 
						|
var len : longword;
 | 
						|
{$IFDEF ENDIAN_BIG}
 | 
						|
    i : integer;
 | 
						|
    us : UnicodeString;
 | 
						|
{$ENDIF}
 | 
						|
begin
 | 
						|
  WriteValue(vaUString);
 | 
						|
  len:=Length(Value);
 | 
						|
  WriteDWord(len);
 | 
						|
  if len > 0 then
 | 
						|
  begin
 | 
						|
    {$IFDEF ENDIAN_BIG}
 | 
						|
    setlength(us,len);
 | 
						|
    for i:=1 to len do
 | 
						|
      us[i]:=widechar(SwapEndian(word(Value[i])));
 | 
						|
    Write(us[1], len*sizeof(UnicodeChar));
 | 
						|
    {$ELSE}
 | 
						|
    Write(Value[1], len*sizeof(UnicodeChar));
 | 
						|
    {$ENDIF}
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBinaryObjectWriter.WriteVariant(const VarValue: variant);
 | 
						|
begin
 | 
						|
  { The variant manager will handle varbyref and vararray transparently for us
 | 
						|
  }
 | 
						|
  case (tvardata(VarValue).vtype and varTypeMask) of
 | 
						|
    varEmpty:
 | 
						|
      begin
 | 
						|
        WriteValue(vaNil);
 | 
						|
      end;
 | 
						|
    varNull:
 | 
						|
      begin
 | 
						|
        WriteValue(vaNull);
 | 
						|
      end;
 | 
						|
    { all integer sizes must be split for big endian systems }
 | 
						|
    varShortInt,varSmallInt,varInteger,varInt64:
 | 
						|
      begin
 | 
						|
        WriteInteger(VarValue);
 | 
						|
      end;
 | 
						|
    varQWord:
 | 
						|
      begin
 | 
						|
        WriteUInt64(VarValue);
 | 
						|
      end;
 | 
						|
    varBoolean:
 | 
						|
      begin
 | 
						|
        WriteBoolean(VarValue);
 | 
						|
      end;
 | 
						|
    varCurrency:
 | 
						|
      begin
 | 
						|
        WriteCurrency(VarValue);
 | 
						|
      end;
 | 
						|
{$ifndef fpunone}
 | 
						|
    varSingle:
 | 
						|
      begin
 | 
						|
        WriteSingle(VarValue);
 | 
						|
      end;
 | 
						|
    varDouble:
 | 
						|
      begin
 | 
						|
        WriteFloat(VarValue);
 | 
						|
      end;
 | 
						|
    varDate:
 | 
						|
      begin
 | 
						|
        WriteDate(VarValue);
 | 
						|
      end;
 | 
						|
{$endif fpunone}
 | 
						|
    varOleStr,varString:
 | 
						|
      begin
 | 
						|
        WriteWideString(VarValue);
 | 
						|
      end;
 | 
						|
    else
 | 
						|
      raise EWriteError.CreateFmt(SUnsupportedPropertyVariantType, [Ord(tvardata(VarValue).vtype)]);
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure TBinaryObjectWriter.FlushBuffer;
 | 
						|
begin
 | 
						|
  FStream.WriteBuffer(FBuffer^, FBufPos);
 | 
						|
  FBufPos := 0;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBinaryObjectWriter.Write(const Buffer; Count: LongInt);
 | 
						|
var
 | 
						|
  CopyNow: LongInt;
 | 
						|
  SourceBuf: PChar;
 | 
						|
begin
 | 
						|
  SourceBuf:=@Buffer;
 | 
						|
  while Count > 0 do
 | 
						|
  begin
 | 
						|
    CopyNow := Count;
 | 
						|
    if CopyNow > FBufSize - FBufPos then
 | 
						|
      CopyNow := FBufSize - FBufPos;
 | 
						|
    Move(SourceBuf^, PChar(FBuffer)[FBufPos], CopyNow);
 | 
						|
    Dec(Count, CopyNow);
 | 
						|
    Inc(FBufPos, CopyNow);
 | 
						|
    inc(SourceBuf, CopyNow);
 | 
						|
    if FBufPos = FBufSize then
 | 
						|
      FlushBuffer;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBinaryObjectWriter.WriteValue(Value: TValueType);
 | 
						|
var
 | 
						|
  b: byte;
 | 
						|
begin
 | 
						|
  b := byte(Value);
 | 
						|
  Write(b, 1);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBinaryObjectWriter.WriteStr(const Value: String);
 | 
						|
var
 | 
						|
  i: integer;
 | 
						|
  b: byte;
 | 
						|
begin
 | 
						|
  i := Length(Value);
 | 
						|
  if i > 255 then
 | 
						|
    i := 255;
 | 
						|
  b := i;
 | 
						|
  Write(b, 1);
 | 
						|
  if i > 0 then
 | 
						|
    Write(Value[1], i);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
{****************************************************************************}
 | 
						|
{*                             TWriter                                      *}
 | 
						|
{****************************************************************************}
 | 
						|
 | 
						|
 | 
						|
constructor TWriter.Create(ADriver: TAbstractObjectWriter);
 | 
						|
begin
 | 
						|
  inherited Create;
 | 
						|
  FDriver := ADriver;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TWriter.Create(Stream: TStream; BufSize: Integer);
 | 
						|
begin
 | 
						|
  inherited Create;
 | 
						|
  If (Stream=Nil) then
 | 
						|
    Raise EWriteError.Create(SEmptyStreamIllegalWriter);
 | 
						|
  FDriver := CreateDriver(Stream, BufSize);
 | 
						|
  FDestroyDriver := True;
 | 
						|
end;
 | 
						|
 | 
						|
destructor TWriter.Destroy;
 | 
						|
begin
 | 
						|
  if FDestroyDriver then
 | 
						|
    FDriver.Free;
 | 
						|
  inherited Destroy;
 | 
						|
end;
 | 
						|
 | 
						|
function TWriter.CreateDriver(Stream: TStream; BufSize: Integer): TAbstractObjectWriter;
 | 
						|
begin
 | 
						|
  Result := TBinaryObjectWriter.Create(Stream, BufSize);
 | 
						|
end;
 | 
						|
 | 
						|
Type
 | 
						|
  TPosComponent = Class(TObject)
 | 
						|
    FPos : Integer;
 | 
						|
    FComponent : TComponent;
 | 
						|
    Constructor Create(APos : Integer; AComponent : TComponent);
 | 
						|
  end;
 | 
						|
 | 
						|
Constructor TPosComponent.Create(APos : Integer; AComponent : TComponent);
 | 
						|
 | 
						|
begin
 | 
						|
  FPos:=APos;
 | 
						|
  FComponent:=AComponent;
 | 
						|
end;
 | 
						|
 | 
						|
// Used as argument for calls to TComponent.GetChildren:
 | 
						|
procedure TWriter.AddToAncestorList(Component: TComponent);
 | 
						|
begin
 | 
						|
  FAncestors.AddObject(Component.Name,TPosComponent.Create(FAncestors.Count,Component));
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWriter.DefineProperty(const Name: String;
 | 
						|
  ReadData: TReaderProc; AWriteData: TWriterProc; HasData: Boolean);
 | 
						|
begin
 | 
						|
  if HasData and Assigned(AWriteData) then
 | 
						|
  begin
 | 
						|
    // Write the property name and then the data itself
 | 
						|
    Driver.BeginProperty(FPropPath + Name);
 | 
						|
    AWriteData(Self);
 | 
						|
    Driver.EndProperty;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWriter.DefineBinaryProperty(const Name: String;
 | 
						|
  ReadData, AWriteData: TStreamProc; HasData: Boolean);
 | 
						|
begin
 | 
						|
  if HasData and Assigned(AWriteData) then
 | 
						|
  begin
 | 
						|
    // Write the property name and then the data itself
 | 
						|
    Driver.BeginProperty(FPropPath + Name);
 | 
						|
    WriteBinary(AWriteData);
 | 
						|
    Driver.EndProperty;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWriter.Write(const Buffer; Count: Longint);
 | 
						|
begin
 | 
						|
  //This should give an exception if write is not implemented (i.e. TTextObjectWriter)
 | 
						|
  //but should work with TBinaryObjectWriter.
 | 
						|
  Driver.Write(Buffer, Count);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWriter.SetRoot(ARoot: TComponent);
 | 
						|
begin
 | 
						|
  inherited SetRoot(ARoot);
 | 
						|
  // Use the new root as lookup root too
 | 
						|
  FLookupRoot := ARoot;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWriter.WriteBinary(AWriteData: TStreamProc);
 | 
						|
var
 | 
						|
  MemBuffer: TMemoryStream;
 | 
						|
  BufferSize: Longint;
 | 
						|
begin
 | 
						|
  { First write the binary data into a memory stream, then copy this buffered
 | 
						|
    stream into the writing destination. This is necessary as we have to know
 | 
						|
    the size of the binary data in advance (we're assuming that seeking within
 | 
						|
    the writer stream is not possible) }
 | 
						|
  MemBuffer := TMemoryStream.Create;
 | 
						|
  try
 | 
						|
    AWriteData(MemBuffer);
 | 
						|
    BufferSize := MemBuffer.Size;
 | 
						|
    Driver.WriteBinary(MemBuffer.Memory^, BufferSize);
 | 
						|
  finally
 | 
						|
    MemBuffer.Free;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWriter.WriteBoolean(Value: Boolean);
 | 
						|
begin
 | 
						|
  Driver.WriteBoolean(Value);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWriter.WriteChar(Value: Char);
 | 
						|
begin
 | 
						|
  WriteString(Value);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWriter.WriteWideChar(Value: WideChar);
 | 
						|
begin
 | 
						|
  WriteWideString(Value);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWriter.WriteCollection(Value: TCollection);
 | 
						|
var
 | 
						|
  i: Integer;
 | 
						|
begin
 | 
						|
  Driver.BeginCollection;
 | 
						|
  if Assigned(Value) then
 | 
						|
    for i := 0 to Value.Count - 1 do
 | 
						|
    begin
 | 
						|
      { Each collection item needs its own ListBegin/ListEnd tag, or else the
 | 
						|
        reader wouldn't be able to know where an item ends and where the next
 | 
						|
        one starts }
 | 
						|
      WriteListBegin;
 | 
						|
      WriteProperties(Value.Items[i]);
 | 
						|
      WriteListEnd;
 | 
						|
    end;
 | 
						|
  WriteListEnd;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWriter.DetermineAncestor(Component : TComponent);
 | 
						|
 | 
						|
Var
 | 
						|
  I : Integer;
 | 
						|
 | 
						|
begin
 | 
						|
  // Should be set only when we write an inherited with children.
 | 
						|
  if Not Assigned(FAncestors) then
 | 
						|
    exit;
 | 
						|
  I:=FAncestors.IndexOf(Component.Name);
 | 
						|
  If (I=-1) then
 | 
						|
    begin
 | 
						|
    FAncestor:=Nil;
 | 
						|
    FAncestorPos:=-1;
 | 
						|
    end
 | 
						|
  else
 | 
						|
    With TPosComponent(FAncestors.Objects[i]) do
 | 
						|
      begin
 | 
						|
      FAncestor:=FComponent;
 | 
						|
      FAncestorPos:=FPos;
 | 
						|
      end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWriter.DoFindAncestor(Component : TComponent);
 | 
						|
 | 
						|
Var
 | 
						|
  C : TComponent;
 | 
						|
 | 
						|
begin
 | 
						|
  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 TWriter.WriteComponent(Component: TComponent);
 | 
						|
 | 
						|
var
 | 
						|
  SA : TPersistent;
 | 
						|
  SR, SRA : TComponent;
 | 
						|
begin
 | 
						|
  SR:=FRoot;
 | 
						|
  SA:=FAncestor;
 | 
						|
  SRA:=FRootAncestor;
 | 
						|
  Try
 | 
						|
    Component.FComponentState:=Component.FComponentState+[csWriting];
 | 
						|
    Try
 | 
						|
      // Possibly set ancestor.
 | 
						|
      DetermineAncestor(Component);
 | 
						|
      DoFindAncestor(Component); // Mainly for IDE when a parent form had an ancestor renamed...
 | 
						|
      // Will call WriteComponentData.
 | 
						|
      Component.WriteState(Self);
 | 
						|
      FDriver.EndList;
 | 
						|
    Finally
 | 
						|
      Component.FComponentState:=Component.FComponentState-[csWriting];
 | 
						|
    end;
 | 
						|
  Finally
 | 
						|
    FAncestor:=SA;
 | 
						|
    FRoot:=SR;
 | 
						|
    FRootAncestor:=SRA;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWriter.WriteChildren(Component : TComponent);
 | 
						|
 | 
						|
Var
 | 
						|
  SRoot, SRootA : TComponent;
 | 
						|
  SList : TStringList;
 | 
						|
  SPos : Integer;
 | 
						|
  I : 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;
 | 
						|
  try
 | 
						|
    FAncestors:=Nil;
 | 
						|
    FCurrentPos:=0;
 | 
						|
    FAncestorPos:=-1;
 | 
						|
    if csInline in Component.ComponentState then
 | 
						|
       FRoot:=Component;
 | 
						|
    if (FAncestor is TComponent) then
 | 
						|
       begin
 | 
						|
       FAncestors:=TStringList.Create;
 | 
						|
       if csInline in TComponent(FAncestor).ComponentState then
 | 
						|
         FRootAncestor := TComponent(FAncestor);
 | 
						|
       TComponent(FAncestor).GetChildren(@AddToAncestorList,FRootAncestor);
 | 
						|
       FAncestors.Sorted:=True;
 | 
						|
       end;
 | 
						|
    try
 | 
						|
      Component.GetChildren(@WriteComponent, FRoot);
 | 
						|
    Finally
 | 
						|
      If Assigned(Fancestors) then
 | 
						|
        For I:=0 to FAncestors.Count-1 do 
 | 
						|
          FAncestors.Objects[i].Free;
 | 
						|
      FreeAndNil(FAncestors);
 | 
						|
    end;    
 | 
						|
  finally
 | 
						|
    FAncestors:=Slist;
 | 
						|
    FRoot:=SRoot;
 | 
						|
    FRootAncestor:=SRootA;
 | 
						|
    FCurrentPos:=SPos;
 | 
						|
    FAncestorPos:=Spos;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWriter.WriteComponentData(Instance: TComponent);
 | 
						|
var 
 | 
						|
  Flags: TFilerFlags;
 | 
						|
begin
 | 
						|
  Flags := [];
 | 
						|
  If (Assigned(FAncestor)) and  //has ancestor
 | 
						|
     (not (csInline in Instance.ComponentState) or // no inline component
 | 
						|
      // .. or the inline component is inherited
 | 
						|
      (csAncestor in Instance.Componentstate) and (FAncestors <> nil)) then
 | 
						|
    Flags:=[ffInherited]
 | 
						|
  else If csInline in Instance.ComponentState then
 | 
						|
    Flags:=[ffInline];
 | 
						|
  If (FAncestors<>Nil) and ((FCurrentPos<>FAncestorPos) or (FAncestor=Nil)) then
 | 
						|
    Include(Flags,ffChildPos);
 | 
						|
  FDriver.BeginComponent(Instance,Flags,FCurrentPos);
 | 
						|
  If (FAncestors<>Nil) then
 | 
						|
    Inc(FCurrentPos);
 | 
						|
  WriteProperties(Instance);
 | 
						|
  WriteListEnd;
 | 
						|
  // Needs special handling of ancestor.
 | 
						|
  If not IgnoreChildren then
 | 
						|
    WriteChildren(Instance);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWriter.WriteDescendent(ARoot: TComponent; AAncestor: TComponent);
 | 
						|
begin
 | 
						|
  FRoot := ARoot;
 | 
						|
  FAncestor := AAncestor;
 | 
						|
  FRootAncestor := AAncestor;
 | 
						|
  FLookupRoot := ARoot;
 | 
						|
 | 
						|
  WriteComponent(ARoot);
 | 
						|
end;
 | 
						|
 | 
						|
{$ifndef FPUNONE}
 | 
						|
procedure TWriter.WriteFloat(const Value: Extended);
 | 
						|
begin
 | 
						|
  Driver.WriteFloat(Value);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWriter.WriteSingle(const Value: Single);
 | 
						|
begin
 | 
						|
  Driver.WriteSingle(Value);
 | 
						|
end;
 | 
						|
{$endif}
 | 
						|
 | 
						|
procedure TWriter.WriteCurrency(const Value: Currency);
 | 
						|
begin
 | 
						|
  Driver.WriteCurrency(Value);
 | 
						|
end;
 | 
						|
 | 
						|
{$ifndef FPUNONE}
 | 
						|
procedure TWriter.WriteDate(const Value: TDateTime);
 | 
						|
begin
 | 
						|
  Driver.WriteDate(Value);
 | 
						|
end;
 | 
						|
{$endif}
 | 
						|
 | 
						|
procedure TWriter.WriteIdent(const Ident: string);
 | 
						|
begin
 | 
						|
  Driver.WriteIdent(Ident);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWriter.WriteInteger(Value: LongInt);
 | 
						|
begin
 | 
						|
  Driver.WriteInteger(Value);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWriter.WriteInteger(Value: Int64);
 | 
						|
begin
 | 
						|
  Driver.WriteInteger(Value);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWriter.WriteSet(Value: LongInt; SetType: Pointer); 
 | 
						|
 | 
						|
begin
 | 
						|
  Driver.WriteSet(Value,SetType);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWriter.WriteVariant(const VarValue: Variant);
 | 
						|
begin
 | 
						|
  Driver.WriteVariant(VarValue);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWriter.WriteListBegin;
 | 
						|
begin
 | 
						|
  Driver.BeginList;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWriter.WriteListEnd;
 | 
						|
begin
 | 
						|
  Driver.EndList;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWriter.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;
 | 
						|
  Instance.DefineProperties(Self);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure TWriter.WriteProperty(Instance: TPersistent; PropInfo: Pointer);
 | 
						|
var
 | 
						|
  HasAncestor: Boolean;
 | 
						|
  PropType: PTypeInfo;
 | 
						|
  Value, DefValue: LongInt;
 | 
						|
  Ident: String;
 | 
						|
  IntToIdentFn: TIntToIdent;
 | 
						|
{$ifndef FPUNONE}
 | 
						|
  FloatValue, DefFloatValue: Extended;
 | 
						|
{$endif}
 | 
						|
  MethodValue: TMethod;
 | 
						|
  DefMethodValue: TMethod;
 | 
						|
  WStrValue, WDefStrValue: WideString;
 | 
						|
  StrValue, DefStrValue: String;
 | 
						|
  UStrValue, UDefStrValue: UnicodeString;
 | 
						|
  AncestorObj: TObject;
 | 
						|
  Component: TComponent;
 | 
						|
  ObjValue: TObject;
 | 
						|
  SavedAncestor: TPersistent;
 | 
						|
  SavedPropPath, Name: String;
 | 
						|
  Int64Value, DefInt64Value: Int64;
 | 
						|
  VarValue, DefVarValue : tvardata;
 | 
						|
  BoolValue, DefBoolValue: boolean;
 | 
						|
  Handled: Boolean;
 | 
						|
 | 
						|
begin
 | 
						|
  // do not stream properties without getter
 | 
						|
  if not Assigned(PPropInfo(PropInfo)^.GetProc) then
 | 
						|
    exit;
 | 
						|
  // properties without setter are only allowed, if they are subcomponents
 | 
						|
  PropType := PPropInfo(PropInfo)^.PropType;
 | 
						|
  if not Assigned(PPropInfo(PropInfo)^.SetProc) then begin
 | 
						|
    if PropType^.Kind<>tkClass then
 | 
						|
      exit;
 | 
						|
    ObjValue := TObject(GetObjectProp(Instance, PropInfo));
 | 
						|
    if not ObjValue.InheritsFrom(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));
 | 
						|
  //writeln('TWriter.WriteProperty Name=',PropType^.Name,' Kind=',GetEnumName(TypeInfo(TTypeKind),ord(PropType^.Kind)),' HasAncestor=',HasAncestor);
 | 
						|
 | 
						|
  case PropType^.Kind of
 | 
						|
    tkInteger, tkChar, tkEnumeration, tkSet, tkWChar:
 | 
						|
      begin
 | 
						|
        Value := GetOrdProp(Instance, PropInfo);
 | 
						|
        if HasAncestor then
 | 
						|
          DefValue := GetOrdProp(Ancestor, PropInfo)
 | 
						|
        else
 | 
						|
          DefValue := PPropInfo(PropInfo)^.Default;
 | 
						|
        // writeln(PPropInfo(PropInfo)^.Name, ', HasAncestor=', ord(HasAncestor), ', Value=', Value, ', Default=', DefValue);
 | 
						|
        if (Value <> DefValue) or (DefValue=longint($80000000)) then
 | 
						|
        begin
 | 
						|
          Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
 | 
						|
          case PropType^.Kind of
 | 
						|
            tkInteger:
 | 
						|
              begin
 | 
						|
                // Check if this integer has a string identifier
 | 
						|
                IntToIdentFn := FindIntToIdent(PPropInfo(PropInfo)^.PropType);
 | 
						|
                if Assigned(IntToIdentFn) and IntToIdentFn(Value, Ident) then
 | 
						|
                  // Integer can be written a human-readable identifier
 | 
						|
                  WriteIdent(Ident)
 | 
						|
                else
 | 
						|
                  // Integer has to be written just as number
 | 
						|
                  WriteInteger(Value);
 | 
						|
              end;
 | 
						|
            tkChar:
 | 
						|
              WriteChar(Chr(Value));
 | 
						|
            tkWChar:
 | 
						|
              WriteWideChar(WideChar(Value));
 | 
						|
            tkSet:
 | 
						|
              Driver.WriteSet(Value, GetTypeData(PropType)^.CompType);
 | 
						|
            tkEnumeration:
 | 
						|
              WriteIdent(GetEnumName(PropType, Value));
 | 
						|
          end;
 | 
						|
          Driver.EndProperty;
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
{$ifndef FPUNONE}
 | 
						|
    tkFloat:
 | 
						|
      begin
 | 
						|
        FloatValue := GetFloatProp(Instance, PropInfo);
 | 
						|
        if HasAncestor then
 | 
						|
          DefFloatValue := GetFloatProp(Ancestor, PropInfo)
 | 
						|
        else
 | 
						|
          begin
 | 
						|
          DefValue :=PPropInfo(PropInfo)^.Default;
 | 
						|
          DefFloatValue:=PSingle(@PPropInfo(PropInfo)^.Default)^;
 | 
						|
          end;
 | 
						|
        if (FloatValue<>DefFloatValue) or (DefValue=longint($80000000)) then
 | 
						|
        begin
 | 
						|
          Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
 | 
						|
          WriteFloat(FloatValue);
 | 
						|
          Driver.EndProperty;
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
{$endif}
 | 
						|
    tkMethod:
 | 
						|
      begin
 | 
						|
        MethodValue := GetMethodProp(Instance, PropInfo);
 | 
						|
        if HasAncestor then
 | 
						|
          DefMethodValue := GetMethodProp(Ancestor, PropInfo)
 | 
						|
        else begin
 | 
						|
          DefMethodValue.Data := nil;
 | 
						|
          DefMethodValue.Code := nil;
 | 
						|
        end;
 | 
						|
 | 
						|
        Handled:=false;
 | 
						|
        if Assigned(OnWriteMethodProperty) then
 | 
						|
          OnWriteMethodProperty(Self,Instance,PPropInfo(PropInfo),MethodValue,
 | 
						|
            DefMethodValue,Handled);
 | 
						|
        if (not Handled) and
 | 
						|
          (MethodValue.Code <> DefMethodValue.Code) and
 | 
						|
          ((not Assigned(MethodValue.Code)) or
 | 
						|
          ((Length(FLookupRoot.MethodName(MethodValue.Code)) > 0))) then
 | 
						|
        begin
 | 
						|
          Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
 | 
						|
          if Assigned(MethodValue.Code) then
 | 
						|
            Driver.WriteMethodName(FLookupRoot.MethodName(MethodValue.Code))
 | 
						|
          else
 | 
						|
            Driver.WriteMethodName('');
 | 
						|
          Driver.EndProperty;
 | 
						|
        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
 | 
						|
        begin
 | 
						|
          Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
 | 
						|
          if Assigned(FOnWriteStringProperty) then
 | 
						|
            FOnWriteStringProperty(Self,Instance,PropInfo,StrValue);
 | 
						|
          WriteString(StrValue);
 | 
						|
          Driver.EndProperty;
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
    tkWString:
 | 
						|
      begin
 | 
						|
        WStrValue := GetWideStrProp(Instance, PropInfo);
 | 
						|
        if HasAncestor then
 | 
						|
          WDefStrValue := GetWideStrProp(Ancestor, PropInfo)
 | 
						|
        else
 | 
						|
          SetLength(WDefStrValue, 0);
 | 
						|
 | 
						|
        if WStrValue <> WDefStrValue then
 | 
						|
        begin
 | 
						|
          Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
 | 
						|
          WriteWideString(WStrValue);
 | 
						|
          Driver.EndProperty;
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
    tkUString:
 | 
						|
      begin
 | 
						|
        UStrValue := GetUnicodeStrProp(Instance, PropInfo);
 | 
						|
        if HasAncestor then
 | 
						|
          UDefStrValue := GetUnicodeStrProp(Ancestor, PropInfo)
 | 
						|
        else
 | 
						|
          SetLength(UDefStrValue, 0);
 | 
						|
 | 
						|
        if UStrValue <> UDefStrValue then
 | 
						|
        begin
 | 
						|
          Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
 | 
						|
          WriteUnicodeString(UStrValue);
 | 
						|
          Driver.EndProperty;
 | 
						|
        end;
 | 
						|
      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
 | 
						|
            Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
 | 
						|
            { can't use variant() typecast, pulls in variants unit }
 | 
						|
            WriteVariant(pvariant(@VarValue)^);
 | 
						|
            Driver.EndProperty;
 | 
						|
          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
 | 
						|
            //writeln('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
 | 
						|
             (UpperCase(TComponent(AncestorObj).Name) = UpperCase(TComponent(ObjValue).Name)) then
 | 
						|
            begin
 | 
						|
              // different components, but with the same name
 | 
						|
              // treat it like an override
 | 
						|
              AncestorObj := ObjValue;
 | 
						|
            end;
 | 
						|
          end;
 | 
						|
        end else
 | 
						|
          AncestorObj := nil;
 | 
						|
 | 
						|
        if not Assigned(ObjValue) then
 | 
						|
          begin
 | 
						|
          if ObjValue <> AncestorObj then
 | 
						|
            begin
 | 
						|
            Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
 | 
						|
            Driver.WriteIdent('NIL');
 | 
						|
            Driver.EndProperty;
 | 
						|
            end
 | 
						|
          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
 | 
						|
              { Determine the correct name of the component this property contains }
 | 
						|
              if Component.Owner = LookupRoot then
 | 
						|
                Name := Component.Name
 | 
						|
              else if Component = LookupRoot then
 | 
						|
                Name := 'Owner'
 | 
						|
              else if Assigned(Component.Owner) and (Length(Component.Owner.Name) > 0)
 | 
						|
                and (Length(Component.Name) > 0) then
 | 
						|
                Name := Component.Owner.Name + '.' + Component.Name
 | 
						|
              else if Length(Component.Name) > 0 then
 | 
						|
                Name := Component.Name + '.Owner'
 | 
						|
              else
 | 
						|
                SetLength(Name, 0);
 | 
						|
 | 
						|
              if Length(Name) > 0 then
 | 
						|
                begin
 | 
						|
                Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
 | 
						|
                WriteIdent(Name);
 | 
						|
                Driver.EndProperty;
 | 
						|
                end;  // length Name>0
 | 
						|
              end; //(ObjValue <> AncestorObj)
 | 
						|
            end // ObjValue.InheritsFrom(TComponent)
 | 
						|
          else if ObjValue.InheritsFrom(TCollection) then
 | 
						|
            begin
 | 
						|
            if (not HasAncestor) or (not CollectionsEqual(TCollection(ObjValue),
 | 
						|
              TCollection(GetObjectProp(Ancestor, PropInfo)),root,rootancestor)) then
 | 
						|
              begin
 | 
						|
              Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
 | 
						|
              SavedPropPath := FPropPath;
 | 
						|
              try
 | 
						|
                SetLength(FPropPath, 0);
 | 
						|
                WriteCollection(TCollection(ObjValue));
 | 
						|
              finally
 | 
						|
                FPropPath := SavedPropPath;
 | 
						|
                Driver.EndProperty;
 | 
						|
              end;
 | 
						|
              end;
 | 
						|
            end // Tcollection
 | 
						|
          else
 | 
						|
            begin
 | 
						|
            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;
 | 
						|
            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
 | 
						|
        begin
 | 
						|
          Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
 | 
						|
          WriteInteger(Int64Value);
 | 
						|
          Driver.EndProperty;
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
    tkBool:
 | 
						|
      begin
 | 
						|
        BoolValue := GetOrdProp(Instance, PropInfo)<>0;
 | 
						|
        if HasAncestor then
 | 
						|
          DefBoolValue := GetOrdProp(Ancestor, PropInfo)<>0
 | 
						|
        else
 | 
						|
          begin
 | 
						|
          DefBoolValue := PPropInfo(PropInfo)^.Default<>0;
 | 
						|
          DefValue:=PPropInfo(PropInfo)^.Default;
 | 
						|
          end;
 | 
						|
        // writeln(PPropInfo(PropInfo)^.Name, ', HasAncestor=', ord(HasAncestor), ', Value=', Value, ', Default=', DefBoolValue);
 | 
						|
        if (BoolValue<>DefBoolValue) or (DefValue=longint($80000000)) then
 | 
						|
          begin
 | 
						|
          Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
 | 
						|
          WriteBoolean(BoolValue);
 | 
						|
          Driver.EndProperty;
 | 
						|
          end;
 | 
						|
      end;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWriter.WriteRootComponent(ARoot: TComponent);
 | 
						|
begin
 | 
						|
  WriteDescendent(ARoot, nil);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWriter.WriteString(const Value: String);
 | 
						|
begin
 | 
						|
  Driver.WriteString(Value);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWriter.WriteWideString(const Value: WideString);
 | 
						|
begin
 | 
						|
  Driver.WriteWideString(Value);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWriter.WriteUnicodeString(const Value: UnicodeString);
 | 
						|
begin
 | 
						|
  Driver.WriteUnicodeString(Value);
 | 
						|
end;
 | 
						|
 |