mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-20 20:29:27 +02:00
841 lines
22 KiB
PHP
841 lines
22 KiB
PHP
{
|
|
$Id$
|
|
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 *}
|
|
{****************************************************************************}
|
|
|
|
constructor TBinaryObjectWriter.Create(Stream: TStream; BufSize: Integer);
|
|
begin
|
|
inherited Create;
|
|
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);
|
|
Write(Count, 4);
|
|
Write(Buffer, Count);
|
|
end;
|
|
|
|
procedure TBinaryObjectWriter.WriteBoolean(Value: Boolean);
|
|
begin
|
|
if Value then
|
|
WriteValue(vaTrue)
|
|
else
|
|
WriteValue(vaFalse);
|
|
end;
|
|
|
|
procedure TBinaryObjectWriter.WriteFloat(const Value: Extended);
|
|
begin
|
|
WriteValue(vaExtended);
|
|
Write(Value, SizeOf(Value));
|
|
end;
|
|
|
|
procedure TBinaryObjectWriter.WriteSingle(const Value: Single);
|
|
begin
|
|
WriteValue(vaSingle);
|
|
Write(Value, SizeOf(Value));
|
|
end;
|
|
|
|
{!!!: procedure TBinaryObjectWriter.WriteCurrency(const Value: Currency);
|
|
begin
|
|
WriteValue(vaCurrency);
|
|
Write(Value, SizeOf(Value));
|
|
end;}
|
|
|
|
procedure TBinaryObjectWriter.WriteDate(const Value: TDateTime);
|
|
begin
|
|
WriteValue(vaDate);
|
|
Write(Value, SizeOf(Value));
|
|
end;
|
|
|
|
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);
|
|
begin
|
|
{ Use the smallest possible integer type for the given value: }
|
|
if (Value >= -128) and (Value <= 127) then
|
|
begin
|
|
WriteValue(vaInt8);
|
|
Write(Value, 1);
|
|
end else if (Value >= -32768) and (Value <= 32767) then
|
|
begin
|
|
WriteValue(vaInt16);
|
|
Write(Value, 2);
|
|
end else if (Value >= -$80000000) and (Value <= $7fffffff) then
|
|
begin
|
|
WriteValue(vaInt32);
|
|
Write(Value, 4);
|
|
end else
|
|
begin
|
|
WriteValue(vaInt64);
|
|
Write(Value, 8);
|
|
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);
|
|
var
|
|
i: Integer;
|
|
Mask: LongInt;
|
|
begin
|
|
WriteValue(vaSet);
|
|
Mask := 1;
|
|
for i := 0 to 31 do
|
|
begin
|
|
if (Value and Mask) <> 0 then
|
|
WriteStr(GetEnumName(PTypeInfo(SetType), i));
|
|
Mask := Mask shl 1;
|
|
end;
|
|
WriteStr('');
|
|
end;
|
|
|
|
procedure TBinaryObjectWriter.WriteString(const Value: String);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
i := Length(Value);
|
|
if i <= 255 then
|
|
begin
|
|
WriteValue(vaString);
|
|
Write(i, 1);
|
|
end else
|
|
begin
|
|
WriteValue(vaLString);
|
|
Write(i, 4);
|
|
end;
|
|
if i > 0 then
|
|
Write(Value[1], i);
|
|
end;
|
|
|
|
{!!!: procedure TBinaryObjectWriter.WriteWideString(const Value: WideString);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
WriteValue(vaWString);
|
|
i := Length(Value);
|
|
Write(i, 4);
|
|
Write(Value[1], i * 2);
|
|
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);
|
|
begin
|
|
Write(Value, 1);
|
|
end;
|
|
|
|
procedure TBinaryObjectWriter.WriteStr(const Value: String);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
i := Length(Value);
|
|
if i > 255 then
|
|
i := 255;
|
|
Write(i, 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;
|
|
FDriver := TBinaryObjectWriter.Create(Stream, BufSize);
|
|
FDestroyDriver := True;
|
|
end;
|
|
|
|
destructor TWriter.Destroy;
|
|
begin
|
|
if FDestroyDriver then
|
|
FDriver.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
// Used as argument for calls to TComponent.GetChildren:
|
|
procedure TWriter.AddToAncestorList(Component: TComponent);
|
|
begin
|
|
FAncestorList.Add(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.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.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.WriteComponent(Component: TComponent);
|
|
var
|
|
SavedAncestor: TPersistent;
|
|
SavedRootAncestor, AncestorComponent, CurAncestor: TComponent;
|
|
i: Integer;
|
|
s: String;
|
|
begin
|
|
SavedAncestor := Ancestor;
|
|
SavedRootAncestor := RootAncestor;
|
|
|
|
try
|
|
// The component has to know that it is being written now...
|
|
Include(Component.FComponentState, csWriting);
|
|
|
|
// Locate the component in the ancestor list, if necessary
|
|
if Assigned(FAncestorList) then
|
|
begin
|
|
Ancestor := nil;
|
|
s := UpperCase(Component.Name);
|
|
for i := 0 to FAncestorList.Count - 1 do
|
|
begin
|
|
CurAncestor := TComponent(FAncestorList[i]);
|
|
if UpperCase(CurAncestor.Name) = s then
|
|
begin
|
|
Ancestor := CurAncestor;
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// Do we have to call the OnFindAncestor callback?
|
|
if Assigned(FOnFindAncestor) and
|
|
((not Assigned(Ancestor)) or Ancestor.InheritsFrom(TComponent)) then
|
|
begin
|
|
AncestorComponent := TComponent(Ancestor);
|
|
FOnFindAncestor(Self, Component, Component.Name,
|
|
AncestorComponent, FRootAncestor);
|
|
Ancestor := AncestorComponent;
|
|
end;
|
|
|
|
// Finally write the component state
|
|
Component.WriteState(Self);
|
|
|
|
// The writing has been finished now...
|
|
Exclude(Component.FComponentState, csWriting);
|
|
|
|
finally
|
|
Ancestor := SavedAncestor;
|
|
FRootAncestor := SavedRootAncestor;
|
|
end;
|
|
end;
|
|
|
|
procedure TWriter.WriteComponentData(Instance: TComponent);
|
|
var
|
|
SavedAncestorList: TList;
|
|
SavedRoot, SavedRootAncestor: TComponent;
|
|
SavedAncestorPos, SavedChildPos: Integer;
|
|
Flags: TFilerFlags;
|
|
begin
|
|
// Determine the filer flags to store
|
|
if Assigned(Ancestor) and ((not (csInline in Instance.ComponentState)) or
|
|
((csAncestor in Instance.ComponentState) and Assigned(FAncestorList))) then
|
|
Flags := [ffInherited]
|
|
else if csInline in Instance.ComponentState then
|
|
Flags := [ffInline]
|
|
else
|
|
Flags := [];
|
|
|
|
if Assigned(FAncestorList) and (FAncestorPos < FAncestorList.Count) and
|
|
((not Assigned(Ancestor)) or
|
|
(TPersistent(FAncestorList[FAncestorPos]) <> Ancestor)) then
|
|
Include(Flags, ffChildPos);
|
|
|
|
Driver.BeginComponent(Instance, Flags, FChildPos);
|
|
|
|
if Assigned(FAncestorList) and (FAncestorPos < FAncestorList.Count) then
|
|
begin
|
|
if Assigned(Ancestor) then
|
|
Inc(FAncestorPos);
|
|
Inc(FChildPos);
|
|
end;
|
|
|
|
// Write property list
|
|
WriteProperties(Instance);
|
|
WriteListEnd;
|
|
|
|
// Write children list
|
|
SavedAncestorList := FAncestorList;
|
|
SavedAncestorPos := FAncestorPos;
|
|
SavedChildPos := FChildPos;
|
|
SavedRoot := FRoot;
|
|
SavedRootAncestor := FRootAncestor;
|
|
try
|
|
FAncestorList := nil;
|
|
FAncestorPos := 0;
|
|
FChildPos := 0;
|
|
if not IgnoreChildren then
|
|
try
|
|
// Set up the ancestor list if we have an ancestor
|
|
if FAncestor is TComponent then
|
|
begin
|
|
if csInline in TComponent(FAncestor).ComponentState then
|
|
FRootAncestor := TComponent(FAncestor);
|
|
FAncestorList := TList.Create;
|
|
TComponent(FAncestor).GetChildren(@AddToAncestorList, FRootAncestor);
|
|
end;
|
|
|
|
if csInline in Instance.ComponentState then
|
|
FRoot := Instance;
|
|
|
|
Instance.GetChildren(@WriteComponent, FRoot);
|
|
|
|
finally
|
|
FAncestorList.Free;
|
|
end;
|
|
|
|
finally
|
|
FAncestorList := SavedAncestorList;
|
|
FAncestorPos := SavedAncestorPos;
|
|
FChildPos := SavedChildPos;
|
|
FRoot := SavedRoot;
|
|
FRootAncestor := SavedRootAncestor;
|
|
end;
|
|
|
|
WriteListEnd;
|
|
end;
|
|
|
|
procedure TWriter.WriteDescendent(ARoot: TComponent; AAncestor: TComponent);
|
|
begin
|
|
FRoot := ARoot;
|
|
FAncestor := AAncestor;
|
|
FRootAncestor := AAncestor;
|
|
FLookupRoot := ARoot;
|
|
|
|
WriteComponent(ARoot);
|
|
end;
|
|
|
|
procedure TWriter.WriteFloat(const Value: Extended);
|
|
begin
|
|
Driver.WriteFloat(Value);
|
|
end;
|
|
|
|
procedure TWriter.WriteSingle(const Value: Single);
|
|
begin
|
|
Driver.WriteSingle(Value);
|
|
end;
|
|
|
|
{!!!: procedure TWriter.WriteCurrency(const Value: Currency);
|
|
begin
|
|
Driver.WriteCurrency(Value);
|
|
end;}
|
|
|
|
procedure TWriter.WriteDate(const Value: TDateTime);
|
|
begin
|
|
Driver.WriteDate(Value);
|
|
end;
|
|
|
|
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.WriteListBegin;
|
|
begin
|
|
Driver.BeginList;
|
|
end;
|
|
|
|
procedure TWriter.WriteListEnd;
|
|
begin
|
|
Driver.EndList;
|
|
end;
|
|
|
|
procedure TWriter.WriteProperties(Instance: TPersistent);
|
|
var
|
|
i, PropCount: Integer;
|
|
PropInfo: PPropInfo;
|
|
PropList: PPropList;
|
|
begin
|
|
{ First step: Write the properties given by the RTTI for Instance }
|
|
PropCount := GetTypeData(Instance.ClassInfo)^.PropCount;
|
|
if PropCount > 0 then
|
|
begin
|
|
GetMem(PropList, PropCount * SizeOf(PPropInfo));
|
|
try
|
|
GetPropInfos(Instance.ClassInfo, PropList);
|
|
for i := 0 to PropCount - 1 do
|
|
begin
|
|
PropInfo := PropList^[i];
|
|
if IsStoredProp(Instance, PropInfo) then
|
|
WriteProperty(Instance, PropInfo);
|
|
end;
|
|
finally
|
|
FreeMem(PropList);
|
|
end;
|
|
end;
|
|
|
|
{ Second step: Give Instance the chance to write its own private data }
|
|
Instance.DefineProperties(Self);
|
|
end;
|
|
|
|
procedure TWriter.WriteProperty(Instance: TPersistent; PropInfo: Pointer);
|
|
var
|
|
HasAncestor: Boolean;
|
|
PropType: PTypeInfo;
|
|
Value, DefValue: LongInt;
|
|
Ident: String;
|
|
IntToIdentFn: TIntToIdent;
|
|
FloatValue, DefFloatValue: Extended;
|
|
MethodValue: TMethod;
|
|
DefMethodCodeValue: Pointer;
|
|
StrValue, DefStrValue: String;
|
|
AncestorObj: TObject;
|
|
Component: TComponent;
|
|
ObjValue: TObject;
|
|
SavedAncestor: TPersistent;
|
|
SavedPropPath, Name: String;
|
|
Int64Value, DefInt64Value: Int64;
|
|
BoolValue, DefBoolValue: boolean;
|
|
Handled: Boolean;
|
|
|
|
begin
|
|
|
|
if (not Assigned(PPropInfo(PropInfo)^.SetProc)) or
|
|
(not Assigned(PPropInfo(PropInfo)^.GetProc)) then
|
|
exit;
|
|
|
|
{ Check if the ancestor can be used }
|
|
HasAncestor := Assigned(Ancestor) and ((Instance = Root) or
|
|
(Instance.ClassType = Ancestor.ClassType));
|
|
|
|
PropType := PPropInfo(PropInfo)^.PropType;
|
|
case PropType^.Kind of
|
|
tkInteger, tkChar, tkEnumeration, tkSet:
|
|
begin
|
|
Value := GetOrdProp(Instance, PropInfo);
|
|
if HasAncestor then
|
|
DefValue := GetOrdProp(Ancestor, PropInfo)
|
|
else
|
|
DefValue := PPropInfo(PropInfo)^.Default;
|
|
|
|
if Value <> DefValue 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));
|
|
tkSet:
|
|
Driver.WriteSet(Value, GetTypeData(PropType)^.CompType);
|
|
tkEnumeration:
|
|
WriteIdent(GetEnumName(PropType, Value));
|
|
end;
|
|
Driver.EndProperty;
|
|
end;
|
|
end;
|
|
tkFloat:
|
|
begin
|
|
FloatValue := GetFloatProp(Instance, PropInfo);
|
|
if HasAncestor then
|
|
DefFloatValue := GetFloatProp(Ancestor, PropInfo)
|
|
else
|
|
DefFloatValue := 0;
|
|
if FloatValue <> DefFloatValue then
|
|
begin
|
|
Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
|
|
WriteFloat(FloatValue);
|
|
Driver.EndProperty;
|
|
end;
|
|
end;
|
|
tkMethod:
|
|
begin
|
|
MethodValue := GetMethodProp(Instance, PropInfo);
|
|
if HasAncestor then
|
|
DefMethodCodeValue := GetMethodProp(Ancestor, PropInfo).Code
|
|
else
|
|
DefMethodCodeValue := nil;
|
|
|
|
Handled:=false;
|
|
if Assigned(OnWriteMethodProperty) then
|
|
OnWriteMethodProperty(Self,Instance,PPropInfo(PropInfo),MethodValue,
|
|
DefMethodCodeValue,Handled);
|
|
if (not Handled) and
|
|
(MethodValue.Code <> DefMethodCodeValue) 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, tkWString:
|
|
// !!!: Can we really handle WideStrings here?
|
|
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;
|
|
{!!!: tkVariant:}
|
|
tkClass:
|
|
begin
|
|
ObjValue := TObject(GetOrdProp(Instance, PropInfo));
|
|
if HasAncestor then
|
|
begin
|
|
AncestorObj := TObject(GetOrdProp(Ancestor, PropInfo));
|
|
if Assigned(AncestorObj) then
|
|
if Assigned(ObjValue) and
|
|
(TComponent(AncestorObj).Owner = FRootAncestor) and
|
|
(TComponent(ObjValue).Owner = Root) and
|
|
(UpperCase(TComponent(AncestorObj).Name) = UpperCase(TComponent(ObjValue).Name)) then
|
|
AncestorObj := ObjValue
|
|
else
|
|
AncestorObj := nil;
|
|
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
|
|
if ObjValue.InheritsFrom(TComponent) then
|
|
begin
|
|
Component := TComponent(ObjValue);
|
|
if ObjValue <> AncestorObj 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;
|
|
end;
|
|
end else if ObjValue.InheritsFrom(TCollection) then
|
|
begin
|
|
if (not HasAncestor) or (not CollectionsEqual(TCollection(ObjValue),
|
|
TCollection(GetOrdProp(Ancestor, PropInfo)))) 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 else
|
|
begin
|
|
SavedAncestor := Ancestor;
|
|
SavedPropPath := FPropPath;
|
|
try
|
|
FPropPath := FPropPath + PPropInfo(PropInfo)^.Name + '.';
|
|
if HasAncestor then
|
|
Ancestor := TPersistent(GetOrdProp(Ancestor, PropInfo));
|
|
WriteProperties(TPersistent(ObjValue));
|
|
finally
|
|
Ancestor := SavedAncestor;
|
|
FPropPath := SavedPropPath;
|
|
end;
|
|
end;
|
|
end;
|
|
tkInt64:
|
|
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
|
|
DefBoolValue := PPropInfo(PropInfo)^.Default<>0;
|
|
if BoolValue <> DefBoolValue 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;}
|
|
|
|
|
|
{
|
|
$Log$
|
|
Revision 1.3 2005-02-14 17:13:11 peter
|
|
* truncate log
|
|
|
|
}
|