123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302 |
- {
- 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.WriteSignature;
- begin
- Write(FilerSignature, SizeOf(FilerSignature));
- end;
- procedure TBinaryObjectWriter.BeginComponent(Component: TComponent;
- Flags: TFilerFlags; ChildPos: Integer);
- var
- Prefix: Byte;
- begin
- { Only write the flags if they are needed! }
- if Flags <> [] then
- begin
- Prefix := TFilerFlagsInt(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;
- procedure TWriter.FlushBuffer;
- begin
- Driver.FlushBuffer;
- 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.WriteSignature;
- begin
- FDriver.WriteSignature;
- 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, 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;
- 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:=SAncestorPos;
- 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;
- WriteSignature;
- 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;
- C,Component: TComponent;
- ObjValue: TObject;
- SavedAncestor: TPersistent;
- SavedPropPath, Name: String;
- Int64Value, DefInt64Value: Int64;
- VarValue, DefVarValue : tvardata;
- BoolValue, DefBoolValue: boolean;
- Handled: Boolean;
- IntfValue: IInterface;
- CompRef: IInterfaceComponentReference;
- 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 (not HasAncestor and (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
- begin
- DefValue :=PPropInfo(PropInfo)^.Default;
- SetLength(DefStrValue, 0);
- end;
- if (StrValue<>DefStrValue) or (not HasAncestor and (DefValue=longint($80000000))) 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
- begin
- DefValue :=PPropInfo(PropInfo)^.Default;
- SetLength(WDefStrValue, 0);
- end;
- if (WStrValue<>WDefStrValue) or (not HasAncestor and (DefValue=longint($80000000))) 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
- begin
- DefValue :=PPropInfo(PropInfo)^.Default;
- SetLength(UDefStrValue, 0);
- end;
- if (UStrValue<>UDefStrValue) or (not HasAncestor and (DefValue=longint($80000000))) 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
- Name:= '';
- C:= Component;
- While (C<>Nil) and (C.Name<>'') do
- begin
- If (Name<>'') Then
- Name:='.'+Name;
- if C.Owner = LookupRoot then
- begin
- Name := C.Name+Name;
- break;
- end
- else if C = LookupRoot then
- begin
- Name := 'Owner' + Name;
- break;
- end;
- Name:=C.Name + Name;
- C:= C.Owner;
- end;
- if (C=nil) and (Component.Owner=nil) then
- if (Name<>'') then //foreign root
- Name:=Name+'.Owner';
- 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
- 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;
- 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
- end;
- end; // Inheritsfrom(TPersistent)
- end;
- tkInt64, tkQWord:
- begin
- Int64Value := GetInt64Prop(Instance, PropInfo);
- if HasAncestor then
- DefInt64Value := GetInt64Prop(Ancestor, PropInfo)
- else
- DefInt64Value := PPropInfo(PropInfo)^.Default;
- if (Int64Value <> DefInt64Value) or (DefInt64Value=longint($80000000)) 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;
- tkInterface:
- begin
- IntfValue := GetInterfaceProp(Instance, PropInfo);
- if Assigned(IntfValue) and Supports(IntfValue, IInterfaceComponentReference, CompRef) then
- begin
- Component := CompRef.GetComponent;
- if HasAncestor then
- begin
- AncestorObj := TObject(GetObjectProp(Ancestor, PropInfo));
- if (AncestorObj 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<> Component) and
- (TComponent(AncestorObj).Owner = FRootAncestor) and
- (Component.Owner = Root) and
- (UpperCase(TComponent(AncestorObj).Name) = UpperCase(Component.Name)) then
- begin
- // different components, but with the same name
- // treat it like an override
- AncestorObj := Component;
- end;
- end;
- end else
- AncestorObj := nil;
- if not Assigned(Component) then
- begin
- if Component <> AncestorObj then
- begin
- Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
- Driver.WriteIdent('NIL');
- Driver.EndProperty;
- end
- end
- else if ((not (csSubComponent in Component.ComponentStyle))
- or ((Component.Owner<>Instance) and (Component.Owner<>Nil))) then
- begin
- if (Component <> AncestorObj)
- and not (csTransient in Component.ComponentStyle) then
- begin
- Name:= '';
- C:= Component;
- While (C<>Nil) and (C.Name<>'') do
- begin
- If (Name<>'') Then
- Name:='.'+Name;
- if C.Owner = LookupRoot then
- begin
- Name := C.Name+Name;
- break;
- end
- else if C = LookupRoot then
- begin
- Name := 'Owner' + Name;
- break;
- end;
- Name:=C.Name + Name;
- C:= C.Owner;
- end;
- if (C=nil) and (Component.Owner=nil) then
- if (Name<>'') then //foreign root
- Name:=Name+'.Owner';
- if Length(Name) > 0 then
- begin
- Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
- WriteIdent(Name);
- Driver.EndProperty;
- end; // length Name>0
- end; //(Component <> AncestorObj)
- end;
- end; //Assigned(IntfValue) and Supports(IntfValue,..
- //else write NIL ?
- 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;
- { TAbstractObjectWriter }
- procedure TAbstractObjectWriter.FlushBuffer;
- begin
- // Do nothing
- end;
|