123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287 |
- {
- $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.
- **********************************************************************}
- {****************************************************************************}
- {* TBinaryObjectReader *}
- {****************************************************************************}
- constructor TBinaryObjectReader.Create(Stream: TStream; BufSize: Integer);
- begin
- inherited Create;
- FStream := Stream;
- FBufSize := BufSize;
- GetMem(FBuffer, BufSize);
- end;
- destructor TBinaryObjectReader.Destroy;
- begin
- { Seek back the amount of bytes that we didn't process until now: }
- FStream.Seek(Integer(FBufPos) - Integer(FBufEnd), soFromCurrent);
- if Assigned(FBuffer) then
- FreeMem(FBuffer, FBufSize);
- inherited Destroy;
- end;
- function TBinaryObjectReader.ReadValue: TValueType;
- begin
- Result := vaNull; { Necessary in FPC as TValueType is larger than 1 byte! }
- Read(Result, 1);
- end;
- function TBinaryObjectReader.NextValue: TValueType;
- begin
- Result := ReadValue;
- { We only 'peek' at the next value, so seek back to unget the read value: }
- Dec(FBufPos);
- end;
- procedure TBinaryObjectReader.BeginRootComponent;
- var
- Signature: LongInt;
- begin
- { Read filer signature }
- Read(Signature, 4);
- if Signature <> LongInt(FilerSignature) then
- raise EReadError.Create(SInvalidImage);
- end;
- procedure TBinaryObjectReader.BeginComponent(var Flags: TFilerFlags;
- var AChildPos: Integer; var CompClassName, CompName: String);
- var
- Prefix: Byte;
- ValueType: TValueType;
- begin
- { Every component can start with a special prefix: }
- Flags := [];
- if (Byte(NextValue) and $f0) = $f0 then
- begin
- Prefix := Byte(ReadValue);
- Flags := TFilerFlags(Prefix and $0f);
- if ffChildPos in Flags then
- begin
- ValueType := NextValue;
- case ValueType of
- vaInt8:
- AChildPos := ReadInt8;
- vaInt16:
- AChildPos := ReadInt16;
- vaInt32:
- AChildPos := ReadInt32;
- else
- raise EReadError.Create(SInvalidPropertyValue);
- end;
- end;
- end;
- CompClassName := ReadStr;
- CompName := ReadStr;
- end;
- function TBinaryObjectReader.BeginProperty: String;
- begin
- Result := ReadStr;
- end;
- procedure TBinaryObjectReader.ReadBinary(const DestData: TMemoryStream);
- var
- BinSize: LongInt;
- begin
- Read(BinSize, 4);
- DestData.Size := BinSize;
- Read(DestData.Memory^, BinSize);
- end;
- function TBinaryObjectReader.ReadFloat: Extended;
- begin
- Read(Result, SizeOf(Extended))
- end;
- function TBinaryObjectReader.ReadSingle: Single;
- begin
- Read(Result, SizeOf(Single))
- end;
- {!!!: function TBinaryObjectReader.ReadCurrency: Currency;
- begin
- Read(Result, SizeOf(Currency))
- end;}
- function TBinaryObjectReader.ReadDate: TDateTime;
- begin
- Read(Result, SizeOf(TDateTime))
- end;
- function TBinaryObjectReader.ReadIdent(ValueType: TValueType): String;
- var
- i: Byte;
- begin
- case ValueType of
- vaIdent:
- begin
- Read(i, 1);
- SetLength(Result, i);
- Read(Pointer(@Result[1])^, i);
- end;
- vaNil:
- Result := 'nil';
- vaFalse:
- Result := 'False';
- vaTrue:
- Result := 'True';
- vaNull:
- Result := 'Null';
- end;
- end;
- function TBinaryObjectReader.ReadInt8: ShortInt;
- begin
- Read(Result, 1);
- end;
- function TBinaryObjectReader.ReadInt16: SmallInt;
- begin
- Read(Result, 2);
- end;
- function TBinaryObjectReader.ReadInt32: LongInt;
- begin
- Read(Result, 4);
- end;
- function TBinaryObjectReader.ReadInt64: Int64;
- begin
- Read(Result, 8);
- end;
- function TBinaryObjectReader.ReadSet(EnumType: Pointer): Integer;
- var
- Name: String;
- Value: Integer;
- begin
- try
- Result := 0;
- while True do
- begin
- Name := ReadStr;
- if Length(Name) = 0 then
- break;
- Value := GetEnumValue(PTypeInfo(EnumType), Name);
- if Value = -1 then
- raise EReadError.Create(SInvalidPropertyValue);
- Result := Result or (1 shl Value);
- end;
- except
- SkipSetBody;
- raise;
- end;
- end;
- function TBinaryObjectReader.ReadStr: String;
- var
- i: Byte;
- begin
- Read(i, 1);
- SetLength(Result, i);
- Read(Pointer(@Result[1])^, i);
- end;
- function TBinaryObjectReader.ReadString(StringType: TValueType): String;
- var
- i: Integer;
- begin
- case StringType of
- vaString:
- begin
- i := 0;
- Read(i, 1);
- end;
- vaLString:
- Read(i, 4);
- end;
- SetLength(Result, i);
- if i > 0 then
- Read(Pointer(@Result[1])^, i);
- end;
- {!!!: function TBinaryObjectReader.ReadWideString: WideString;
- var
- i: Integer;
- begin
- FDriver.Read(i, 4);
- SetLength(Result, i);
- if i > 0 then
- Read(PWideChar(Result), i * 2);
- end;}
- procedure TBinaryObjectReader.SkipComponent(SkipComponentInfos: Boolean);
- var
- Flags: TFilerFlags;
- Dummy: Integer;
- CompClassName, CompName: String;
- begin
- if SkipComponentInfos then
- { Skip prefix, component class name and component object name }
- BeginComponent(Flags, Dummy, CompClassName, CompName);
- { Skip properties }
- while NextValue <> vaNull do
- SkipProperty;
- ReadValue;
- { Skip children }
- while NextValue <> vaNull do
- SkipComponent(True);
- ReadValue;
- end;
- procedure TBinaryObjectReader.SkipValue;
- procedure SkipBytes(Count: LongInt);
- var
- Dummy: array[0..1023] of Byte;
- SkipNow: Integer;
- begin
- while Count > 0 do
- begin
- if Count > 1024 then
- SkipNow := 1024
- else
- SkipNow := Count;
- Read(Dummy, SkipNow);
- Dec(Count, SkipNow);
- end;
- end;
- var
- Count: LongInt;
- begin
- case ReadValue of
- vaNull, vaFalse, vaTrue, vaNil: ;
- vaList:
- begin
- while NextValue <> vaNull do
- SkipValue;
- ReadValue;
- end;
- vaInt8:
- SkipBytes(1);
- vaInt16:
- SkipBytes(2);
- vaInt32:
- SkipBytes(4);
- vaExtended:
- SkipBytes(SizeOf(Extended));
- vaString, vaIdent:
- ReadStr;
- vaBinary, vaLString, vaWString:
- begin
- Read(Count, 4);
- SkipBytes(Count);
- end;
- vaSet:
- SkipSetBody;
- vaCollection:
- begin
- while NextValue <> vaNull do
- begin
- { Skip the order value if present }
- if NextValue in [vaInt8, vaInt16, vaInt32] then
- SkipValue;
- SkipBytes(1);
- while NextValue <> vaNull do
- SkipProperty;
- ReadValue;
- end;
- ReadValue;
- end;
- vaSingle:
- SkipBytes(Sizeof(Single));
- {!!!: vaCurrency:
- SkipBytes(SizeOf(Currency));}
- vaDate:
- SkipBytes(Sizeof(TDateTime));
- vaInt64:
- SkipBytes(8);
- end;
- end;
- { private methods }
- procedure TBinaryObjectReader.Read(var Buf; Count: LongInt);
- var
- CopyNow: LongInt;
- Dest: Pointer;
- begin
- Dest := @Buf;
- while Count > 0 do
- begin
- if FBufPos >= FBufEnd then
- begin
- FBufEnd := FStream.Read(FBuffer^, FBufSize);
- if FBufEnd = 0 then
- raise EReadError.Create(SReadError);
- FBufPos := 0;
- end;
- CopyNow := FBufEnd - FBufPos;
- if CopyNow > Count then
- CopyNow := Count;
- Move(PChar(FBuffer)[FBufPos], Dest^, CopyNow);
- Inc(FBufPos, CopyNow);
- Inc(Dest, CopyNow);
- Dec(Count, CopyNow);
- end;
- end;
- procedure TBinaryObjectReader.SkipProperty;
- begin
- { Skip property name, then the property value }
- ReadStr;
- SkipValue;
- end;
- procedure TBinaryObjectReader.SkipSetBody;
- begin
- while Length(ReadStr) > 0 do;
- end;
- {****************************************************************************}
- {* TREADER *}
- {****************************************************************************}
- // This may be better put somewhere else:
- type
- TFieldInfo = packed record
- FieldOffset: LongWord;
- ClassTypeIndex: Word;
- Name: ShortString;
- end;
- PFieldClassTable = ^TFieldClassTable;
- TFieldClassTable = packed record
- Count: Word;
- Entries: array[Word] of TPersistentClass;
- end;
- PFieldTable = ^TFieldTable;
- TFieldTable = packed record
- FieldCount: Word;
- ClassTable: PFieldClassTable;
- // Fields: array[Word] of TFieldInfo; Elements have variant size!
- end;
- function GetFieldClass(Instance: TObject; const ClassName: string): TPersistentClass;
- var
- UClassName: String;
- ClassType: TClass;
- ClassTable: PFieldClassTable;
- i: Integer;
- FieldTable: PFieldTable;
- begin
- // At first, try to locate the class in the class tables
- UClassName := UpperCase(ClassName);
- ClassType := Instance.ClassType;
- while ClassType <> TPersistent do
- begin
- FieldTable := PFieldTable((Pointer(ClassType) + vmtFieldTable)^);
- ClassTable := PFieldTable((Pointer(ClassType) + vmtFieldTable)^)^.ClassTable;
- if Assigned(ClassTable) then
- for i := 0 to ClassTable^.Count - 1 do
- begin
- Result := ClassTable^.Entries[i];
- if UpperCase(Result.ClassName) = UClassName then
- exit;
- end;
- // Try again with the parent class type
- ClassType := ClassType.ClassParent;
- end;
- Result := Classes.GetClass(ClassName);
- end;
- constructor TReader.Create(Stream: TStream; BufSize: Integer);
- begin
- inherited Create;
- FDriver := TBinaryObjectReader.Create(Stream, BufSize);
- end;
- destructor TReader.Destroy;
- begin
- FDriver.Free;
- inherited Destroy;
- end;
- procedure TReader.BeginReferences;
- begin
- FLoaded := TList.Create;
- try
- FFixups := TList.Create;
- except
- FLoaded.Free;
- raise;
- end;
- end;
- procedure TReader.CheckValue(Value: TValueType);
- begin
- if FDriver.NextValue <> Value then
- raise EReadError.Create(SInvalidPropertyValue)
- else
- FDriver.ReadValue;
- end;
- procedure TReader.DefineProperty(const Name: String; AReadData: TReaderProc;
- WriteData: TWriterProc; HasData: Boolean);
- begin
- if Assigned(AReadData) and (UpperCase(Name) = UpperCase(FPropName)) then
- begin
- AReadData(Self);
- SetLength(FPropName, 0);
- end;
- end;
- procedure TReader.DefineBinaryProperty(const Name: String;
- AReadData, WriteData: TStreamProc; HasData: Boolean);
- var
- MemBuffer: TMemoryStream;
- begin
- if Assigned(AReadData) and (UpperCase(Name) = UpperCase(FPropName)) then
- begin
- { Check if the next property really is a binary property}
- if FDriver.NextValue <> vaBinary then
- begin
- FDriver.SkipValue;
- FCanHandleExcepts := True;
- raise EReadError.Create(SInvalidPropertyValue);
- end else
- FDriver.ReadValue;
- MemBuffer := TMemoryStream.Create;
- try
- FDriver.ReadBinary(MemBuffer);
- FCanHandleExcepts := True;
- AReadData(MemBuffer);
- finally
- MemBuffer.Free;
- end;
- SetLength(FPropName, 0);
- end;
- end;
- function TReader.EndOfList: Boolean;
- begin
- Result := FDriver.NextValue = vaNull;
- end;
- procedure TReader.EndReferences;
- begin
- FreeFixups;
- FLoaded.Free;
- FLoaded := nil;
- end;
- function TReader.Error(const Message: String): Boolean;
- begin
- Result := False;
- if Assigned(FOnError) then
- FOnError(Self, Message, Result);
- end;
- function TReader.FindMethod(ARoot: TComponent; const AMethodName: String): Pointer;
- var
- ErrorResult: Boolean;
- begin
- Result := ARoot.MethodAddress(AMethodName);
- ErrorResult := Result = nil;
- { always give the OnFindMethod callback a chance to locate the method }
- if Assigned(FOnFindMethod) then
- FOnFindMethod(Self, AMethodName, Result, ErrorResult);
- if ErrorResult then
- raise EReadError.Create(SInvalidPropertyValue);
- end;
- procedure RemoveGlobalFixup(Fixup: TPropFixup);
- var
- i: Integer;
- begin
- with GlobalFixupList.LockList do
- try
- for i := Count - 1 downto 0 do
- with TPropFixup(Items[i]) do
- if (FInstance = Fixup.FInstance) and
- (FPropInfo = Fixup.FPropInfo) then
- begin
- Free;
- Delete(i);
- end;
- finally
- GlobalFixupList.UnlockList;
- end;
- end;
- procedure TReader.DoFixupReferences;
- var
- i: Integer;
- CurFixup: TPropFixup;
- CurName: String;
- Target: Pointer;
- begin
- if Assigned(FFixups) then
- try
- for i := 0 to FFixups.Count - 1 do
- begin
- CurFixup := TPropFixup(FFixups[i]);
- CurName := CurFixup.FName;
- if Assigned(FOnReferenceName) then
- FOnReferenceName(Self, CurName);
- Target := FindNestedComponent(CurFixup.FInstanceRoot, CurName);
- RemoveGlobalFixup(CurFixup);
- if (not Assigned(Target)) and CurFixup.MakeGlobalReference then
- begin
- GlobalFixupList.Add(CurFixup);
- FFixups[i] := nil;
- end else
- SetOrdProp(CurFixup.FInstance, CurFixup.FPropInfo, LongInt(Target));
- end;
- finally
- FreeFixups;
- end;
- end;
- procedure TReader.FixupReferences;
- var
- i: Integer;
- begin
- DoFixupReferences;
- GlobalFixupReferences;
- for i := 0 to FLoaded.Count - 1 do
- TComponent(FLoaded[I]).Loaded;
- end;
- procedure TReader.FreeFixups;
- var
- i: Integer;
- begin
- if Assigned(FFixups) then
- begin
- for i := 0 to FFixups.Count - 1 do
- TPropFixup(FFixups[I]).Free;
- FFixups.Free;
- FFixups := nil;
- end;
- end;
- function TReader.NextValue: TValueType;
- begin
- Result := FDriver.NextValue;
- end;
- procedure TReader.PropertyError;
- begin
- FDriver.SkipValue;
- raise EReadError.Create(SUnknownProperty);
- end;
- function TReader.ReadBoolean: Boolean;
- var
- ValueType: TValueType;
- begin
- ValueType := FDriver.ReadValue;
- if ValueType = vaTrue then
- Result := True
- else if ValueType = vaFalse then
- Result := False
- else
- raise EReadError.Create(SInvalidPropertyValue);
- end;
- function TReader.ReadChar: Char;
- var
- s: String;
- begin
- s := ReadString;
- if Length(s) = 1 then
- Result := s[1]
- else
- raise EReadError.Create(SInvalidPropertyValue);
- end;
- procedure TReader.ReadCollection(Collection: TCollection);
- var
- Item: TPersistent;
- begin
- Collection.BeginUpdate;
- try
- if not EndOfList then
- Collection.Clear;
- while not EndOfList do
- begin
- if FDriver.NextValue in [vaInt8, vaInt16, vaInt32] then
- ReadInteger; { Skip order value }
- Item := Collection.Add;
- ReadListBegin;
- while not EndOfList do
- ReadProperty(Item);
- ReadListEnd;
- end;
- ReadListEnd;
- finally
- Collection.EndUpdate;
- end;
- end;
- function TReader.ReadComponent(Component: TComponent): TComponent;
- var
- Flags: TFilerFlags;
- function Recover(var Component: TComponent): Boolean;
- begin
- Result := False;
- if ExceptObject.InheritsFrom(Exception) then
- begin
- if not ((ffInherited in Flags) or Assigned(Component)) then
- Component.Free;
- Component := nil;
- FDriver.SkipComponent(False);
- Result := Error(Exception(ExceptObject).Message);
- end;
- end;
- var
- CompClassName, Name: String;
- ChildPos: Integer;
- SavedParent, SavedLookupRoot: TComponent;
- ComponentClass: TComponentClass;
- NewComponent: TComponent;
- begin
- FDriver.BeginComponent(Flags, ChildPos, CompClassName, Name);
- SavedParent := Parent;
- SavedLookupRoot := FLookupRoot;
- try
- Result := Component;
- if not Assigned(Result) then
- try
- if ffInherited in Flags then
- begin
- { Try to locate the existing ancestor component }
- if Assigned(FLookupRoot) then
- Result := FLookupRoot.FindComponent(Name)
- else
- Result := nil;
- if not Assigned(Result) then
- begin
- if Assigned(FOnAncestorNotFound) then
- FOnAncestorNotFound(Self, Name,
- FindComponentClass(CompClassName), Result);
- if not Assigned(Result) then
- raise EReadError.CreateFmt(SAncestorNotFound, [Name]);
- end;
- Parent := Result.GetParentComponent;
- if not Assigned(Parent) then
- Parent := Root;
- end else
- begin
- Result := nil;
- ComponentClass := FindComponentClass(CompClassName);
- if Assigned(FOnCreateComponent) then
- FOnCreateComponent(Self, ComponentClass, Result);
- if not Assigned(Result) then
- begin
- NewComponent := TComponent(ComponentClass.NewInstance);
- if ffInline in Flags then
- NewComponent.FComponentState :=
- NewComponent.FComponentState + [csLoading, csInline];
- NewComponent.Create(Owner);
- { Don't set Result earlier because else we would come in trouble
- with the exception recover mechanism! (Result should be NIL if
- an error occured) }
- Result := NewComponent;
- end;
- Include(Result.FComponentState, csLoading);
- end;
- except
- if not Recover(Result) then
- raise;
- end;
- if Assigned(Result) then
- try
- Include(Result.FComponentState, csLoading);
- if not (ffInherited in Flags) then
- try
- Result.SetParentComponent(Parent);
- if Assigned(FOnSetName) then
- FOnSetName(Self, Result, Name);
- Result.Name := Name;
- if Assigned(FindGlobalComponent) and
- (FindGlobalComponent(Name) = Result) then
- Include(Result.FComponentState, csInline);
- except
- if not Recover(Result) then
- raise;
- end;
- if not Assigned(Result) then
- exit;
- if csInline in Result.ComponentState then
- FLookupRoot := Result;
- { Read the component state }
- Include(Result.FComponentState, csReading);
- Result.ReadState(Self);
- Exclude(Result.FComponentState, csReading);
- if ffChildPos in Flags then
- Parent.SetChildOrder(Result, ChildPos);
- { Add component to list of loaded components, if necessary }
- if (not ((ffInherited in Flags) or (csInline in Result.ComponentState))) or
- (FLoaded.IndexOf(Result) < 0) then
- FLoaded.Add(Result);
- except
- if ((ffInherited in Flags) or Assigned(Component)) then
- Result.Free;
- raise;
- end;
- finally
- Parent := SavedParent;
- FLookupRoot := SavedLookupRoot;
- end;
- end;
- procedure TReader.ReadData(Instance: TComponent);
- var
- DoFreeFixups: Boolean;
- SavedOwner, SavedParent: TComponent;
- begin
- if not Assigned(FFixups) then
- begin
- FFixups := TList.Create;
- DoFreeFixups := True;
- end else
- DoFreeFixups := False;
- try
- { Read properties }
- while not EndOfList do
- ReadProperty(Instance);
- ReadListEnd;
- { Read children }
- SavedOwner := Owner;
- SavedParent := Parent;
- try
- Owner := Instance.GetChildOwner;
- if not Assigned(Owner) then
- Owner := Root;
- Parent := Instance.GetChildParent;
- while not EndOfList do
- ReadComponent(nil);
- ReadListEnd;
- finally
- Owner := SavedOwner;
- Parent := SavedParent;
- end;
- { Fixup references if necessary (normally only if this is the root) }
- if DoFreeFixups then
- DoFixupReferences;
- finally
- if DoFreeFixups then
- FreeFixups;
- end;
- end;
- function TReader.ReadFloat: Extended;
- begin
- if FDriver.NextValue = vaExtended then
- begin
- ReadValue;
- Result := FDriver.ReadFloat
- end else
- Result := ReadInteger;
- end;
- function TReader.ReadSingle: Single;
- begin
- if FDriver.NextValue = vaSingle then
- begin
- FDriver.ReadValue;
- Result := FDriver.ReadSingle;
- end else
- Result := ReadInteger;
- end;
- {!!!: function TReader.ReadCurrency: Currency;
- begin
- if FDriver.NextValue = vaCurrency then
- begin
- FDriver.ReadValue;
- Result := FDriver.ReadCurrency;
- end else
- Result := ReadInteger;
- end;}
- function TReader.ReadDate: TDateTime;
- begin
- if FDriver.NextValue = vaDate then
- begin
- FDriver.ReadValue;
- Result := FDriver.ReadDate;
- end else
- Result := ReadInteger;
- end;
- function TReader.ReadIdent: String;
- var
- ValueType: TValueType;
- begin
- ValueType := FDriver.ReadValue;
- if ValueType in [vaIdent, vaNil, vaFalse, vaTrue, vaNull] then
- Result := FDriver.ReadIdent(ValueType)
- else
- raise EReadError.Create(SInvalidPropertyValue);
- end;
- function TReader.ReadInteger: LongInt;
- begin
- case FDriver.ReadValue of
- vaInt8:
- Result := FDriver.ReadInt8;
- vaInt16:
- Result := FDriver.ReadInt16;
- vaInt32:
- Result := FDriver.ReadInt32;
- else
- raise EReadError.Create(SInvalidPropertyValue);
- end;
- end;
- function TReader.ReadInt64: Int64;
- begin
- if FDriver.NextValue = vaInt64 then
- begin
- FDriver.ReadValue;
- Result := FDriver.ReadInt64;
- end else
- Result := ReadInteger;
- end;
- procedure TReader.ReadListBegin;
- begin
- CheckValue(vaList);
- end;
- procedure TReader.ReadListEnd;
- begin
- CheckValue(vaNull);
- end;
- procedure TReader.ReadProperty(AInstance: TPersistent);
- var
- Path: String;
- Instance: TPersistent;
- DotPos, NextPos: PChar;
- PropInfo: PPropInfo;
- Obj: TObject;
- Name: String;
- begin
- try
- Path := FDriver.BeginProperty;
- try
- Instance := AInstance;
- FCanHandleExcepts := True;
- DotPos := PChar(Path);
- while True do
- begin
- NextPos := StrScan(DotPos, '.');
- if Assigned(NextPos) then
- FPropName := Copy(String(DotPos), 1, Integer(NextPos - DotPos))
- else
- begin
- FPropName := DotPos;
- break;
- end;
- DotPos := NextPos + 1;
- PropInfo := GetPropInfo(Instance.ClassInfo, FPropName);
- if not Assigned(PropInfo) then
- PropertyError;
- if PropInfo^.PropType^.Kind = tkClass then
- Obj := TObject(GetOrdProp(Instance, PropInfo))
- else
- Obj := nil;
- if not Obj.InheritsFrom(TPersistent) then
- begin
- { All path elements must be persistent objects! }
- FDriver.SkipValue;
- raise EReadError.Create(SInvalidPropertyPath);
- end;
- Instance := TPersistent(Obj);
- end;
- PropInfo := GetPropInfo(Instance.ClassInfo, FPropName);
- if Assigned(PropInfo) then
- ReadPropValue(Instance, PropInfo)
- else
- begin
- FCanHandleExcepts := False;
- Instance.DefineProperties(Self);
- FCanHandleExcepts := True;
- if Length(FPropName) > 0 then
- PropertyError;
- end;
- except
- on e: Exception do
- begin
- SetLength(Name, 0);
- if AInstance.InheritsFrom(TComponent) then
- Name := TComponent(AInstance).Name;
- if Length(Name) = 0 then
- Name := AInstance.ClassName;
- raise EReadError.CreateFmt(SPropertyException,
- [Name, DotSep, Path, e.Message]);
- end;
- end;
- except
- on e: Exception do
- if not FCanHandleExcepts or not Error(E.Message) then
- raise;
- end;
- end;
- procedure TReader.ReadPropValue(Instance: TPersistent; PropInfo: Pointer);
- const
- NullMethod: TMethod = (Code: nil; Data: nil);
- var
- PropType: PTypeInfo;
- Value: LongInt;
- IdentToIntFn: TIdentToInt;
- Ident: String;
- Method: TMethod;
- begin
- if not Assigned(PPropInfo(PropInfo)^.SetProc) then
- raise EReadError.Create(SReadOnlyProperty);
- PropType := PPropInfo(PropInfo)^.PropType;
- case PropType^.Kind of
- tkInteger:
- if FDriver.NextValue = vaIdent then
- begin
- IdentToIntFn := FindIdentToInt(PPropInfo(PropInfo)^.PropType);
- Ident := ReadIdent;
- if Assigned(IdentToIntFn) and IdentToIntFn(Ident, Value) then
- SetOrdProp(Instance, PropInfo, Value)
- else
- raise EReadError.Create(SInvalidPropertyValue);
- end else
- SetOrdProp(Instance, PropInfo, ReadInteger);
- tkBool:
- SetOrdProp(Instance, PropInfo, Ord(ReadBoolean));
- tkChar:
- SetOrdProp(Instance, PropInfo, Ord(ReadChar));
- tkEnumeration:
- begin
- Value := GetEnumValue(PropType, ReadIdent);
- if Value = -1 then
- raise EReadError.Create(SInvalidPropertyValue);
- SetOrdProp(Instance, PropInfo, Value);
- end;
- tkFloat:
- SetFloatProp(Instance, PropInfo, ReadFloat);
- tkSet:
- begin
- CheckValue(vaSet);
- SetOrdProp(Instance, PropInfo,
- FDriver.ReadSet(GetTypeData(PropType)^.CompType));
- end;
- tkMethod:
- if FDriver.NextValue = vaNil then
- begin
- FDriver.ReadValue;
- SetMethodProp(Instance, PropInfo, NullMethod);
- end else
- begin
- Method.Code := FindMethod(Root, ReadIdent);
- Method.Data := Root;
- if Assigned(Method.Code) then
- SetMethodProp(Instance, PropInfo, Method);
- end;
- tkSString, tkLString, tkAString, tkWString:
- SetStrProp(Instance, PropInfo, ReadString);
- {!!!: tkVariant}
- tkClass:
- case FDriver.NextValue of
- vaNil:
- begin
- FDriver.ReadValue;
- SetOrdProp(Instance, PropInfo, 0)
- end;
- vaCollection:
- begin
- FDriver.ReadValue;
- ReadCollection(TCollection(GetOrdProp(Instance, PropInfo)));
- end
- else
- FFixups.Add(TPropFixup.Create(Instance, Root, PropInfo, '', ReadIdent));
- end;
- tkInt64: SetInt64Prop(Instance, PropInfo, ReadInt64);
- else
- raise EReadError.CreateFmt(SUnknownPropertyType, [Ord(PropType^.Kind)]);
- end;
- end;
- function TReader.ReadRootComponent(ARoot: TComponent): TComponent;
- var
- Dummy, i: Integer;
- Flags: TFilerFlags;
- CompClassName, CompName, ResultName: String;
- begin
- FDriver.BeginRootComponent;
- Result := nil;
- {!!!: GlobalNameSpace.BeginWrite; // Loading from stream adds to name space
- try}
- try
- FDriver.BeginComponent(Flags, Dummy, CompClassName, CompName);
- if not Assigned(ARoot) then
- begin
- { Read the class name and the object name and create a new object: }
- Result := TComponentClass(FindClass(CompClassName)).Create(nil);
- Result.Name := CompName;
- end else
- begin
- Result := ARoot;
- if not (csDesigning in Result.ComponentState) then
- begin
- Result.FComponentState :=
- Result.FComponentState + [csLoading, csReading];
- if Assigned(FindGlobalComponent) then
- begin
- { We need an unique name }
- i := 0;
- { Don't use Result.Name directly, as this would influence
- FindGlobalComponent in successive loop runs }
- ResultName := CompName;
- while Assigned(FindGlobalComponent(ResultName)) do
- begin
- Inc(i);
- ResultName := CompName + '_' + IntToStr(i);
- end;
- Result.Name := ResultName;
- end else
- Result.Name := '';
- end;
- end;
- FRoot := Result;
- FLookupRoot := Result;
- if Assigned(GlobalLoaded) then
- FLoaded := GlobalLoaded
- else
- FLoaded := TList.Create;
- try
- if FLoaded.IndexOf(FRoot) < 0 then
- FLoaded.Add(FRoot);
- FOwner := FRoot;
- FRoot.FComponentState := FRoot.FComponentState + [csLoading, csReading];
- FRoot.ReadState(Self);
- Exclude(FRoot.FComponentState, csReading);
- if not Assigned(GlobalLoaded) then
- for i := 0 to FLoaded.Count - 1 do
- TComponent(FLoaded[i]).Loaded;
- finally
- if not Assigned(GlobalLoaded) then
- FLoaded.Free;
- FLoaded := nil;
- end;
- GlobalFixupReferences;
- except
- RemoveFixupReferences(ARoot, '');
- if not Assigned(ARoot) then
- Result.Free;
- raise;
- end;
- {finally
- GlobalNameSpace.EndWrite;
- end;}
- end;
- procedure TReader.ReadComponents(AOwner, AParent: TComponent;
- Proc: TReadComponentsProc);
- var
- Component: TComponent;
- begin
- Root := AOwner;
- Owner := AOwner;
- Parent := AParent;
- BeginReferences;
- try
- while not EndOfList do
- begin
- FDriver.BeginRootComponent;
- Component := ReadComponent(nil);
- if Assigned(Proc) then
- Proc(Component);
- end;
- ReadListEnd;
- FixupReferences;
- finally
- EndReferences;
- end;
- end;
- function TReader.ReadString: String;
- var
- StringType: TValueType;
- begin
- StringType := FDriver.ReadValue;
- if StringType in [vaString, vaLString] then
- Result := FDriver.ReadString(StringType)
- else
- raise EReadError.Create(SInvalidPropertyValue);
- end;
- {!!!: function TReader.ReadWideString: WideString;
- begin
- CheckValue(vaWString);
- Result := FDriver.ReadWideString;
- end;}
- function TReader.ReadValue: TValueType;
- begin
- Result := FDriver.ReadValue;
- end;
- procedure TReader.CopyValue(Writer: TWriter);
- procedure CopyBytes(Count: Integer);
- var
- Buffer: array[0..1023] of Byte;
- begin
- {!!!: while Count > 1024 do
- begin
- FDriver.Read(Buffer, 1024);
- Writer.Driver.Write(Buffer, 1024);
- Dec(Count, 1024);
- end;
- if Count > 0 then
- begin
- FDriver.Read(Buffer, Count);
- Writer.Driver.Write(Buffer, Count);
- end;}
- end;
- var
- s: String;
- Count: LongInt;
- begin
- case FDriver.NextValue of
- vaNull:
- Writer.WriteIdent('NULL');
- vaFalse:
- Writer.WriteIdent('FALSE');
- vaTrue:
- Writer.WriteIdent('TRUE');
- vaNil:
- Writer.WriteIdent('NIL');
- {!!!: vaList, vaCollection:
- begin
- Writer.WriteValue(FDriver.ReadValue);
- while not EndOfList do
- CopyValue(Writer);
- ReadListEnd;
- Writer.WriteListEnd;
- end;}
- vaInt8, vaInt16, vaInt32:
- Writer.WriteInteger(ReadInteger);
- vaExtended:
- Writer.WriteFloat(ReadFloat);
- {!!!: vaString:
- Writer.WriteStr(ReadStr);}
- vaIdent:
- Writer.WriteIdent(ReadIdent);
- {!!!: vaBinary, vaLString, vaWString:
- begin
- Writer.WriteValue(FDriver.ReadValue);
- FDriver.Read(Count, SizeOf(Count));
- Writer.Driver.Write(Count, SizeOf(Count));
- CopyBytes(Count);
- end;}
- {!!!: vaSet:
- Writer.WriteSet(ReadSet);}
- vaSingle:
- Writer.WriteSingle(ReadSingle);
- {!!!: vaCurrency:
- Writer.WriteCurrency(ReadCurrency);}
- vaDate:
- Writer.WriteDate(ReadDate);
- vaInt64:
- Writer.WriteInteger(ReadInt64);
- end;
- end;
- function TReader.FindComponentClass(const AClassName: String): TComponentClass;
- begin
- TPersistentClass(Result) := GetFieldClass(Root, AClassName);
- if not Assigned(Result) and Assigned(FLookupRoot) and (FLookupRoot <> Root) then
- TPersistentClass(Result) := GetFieldClass(FLookupRoot, AClassName);
- if Assigned(FOnFindComponentClass) then
- FOnFindComponentClass(Self, AClassName, Result);
- if not (Assigned(Result) and Result.InheritsFrom(TComponent)) then
- raise EClassNotFound.CreateFmt(SClassNotFound, [AClassName]);
- end;
- {
- $Log$
- Revision 1.5 2001-07-14 13:19:05 sg
- * Simplified TBinaryObjectReader.ReadString
- * TReader.ReadComponent now uses ComponentClass.NewInstance for creating
- a new component instance
- Revision 1.4 2001/03/08 19:32:22 michael
- Fixes merged
- Revision 1.3 2000/12/21 09:08:09 sg
- * Applied bugfixes by Mattias Gaertner for TBinaryObjectReader.ReadSet
- (uninitialized result and missing bit shifting) and
- TReader.ReadRootComponent (finding an unique component name)
- (merged from fixbranch)
- Revision 1.2 2000/07/13 11:33:00 michael
- + removed logs
-
- }
|