1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693 |
- {
- 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 *}
- {****************************************************************************}
- {$ifndef FPUNONE}
- {$IFNDEF FPC_HAS_TYPE_EXTENDED}
- function ExtendedToDouble(e : pointer) : double;
- var mant : qword;
- exp : smallint;
- sign : boolean;
- d : qword;
- begin
- move(pbyte(e)[0],mant,8); //mantissa : bytes 0..7
- move(pbyte(e)[8],exp,2); //exponent and sign: bytes 8..9
- mant:=LEtoN(mant);
- exp:=LEtoN(word(exp));
- sign:=(exp and $8000)<>0;
- if sign then exp:=exp and $7FFF;
- case exp of
- 0 : mant:=0; //if denormalized, value is too small for double,
- //so it's always zero
- $7FFF : exp:=2047 //either infinity or NaN
- else
- begin
- dec(exp,16383-1023);
- if (exp>=-51) and (exp<=0) then //can be denormalized
- begin
- mant:=mant shr (-exp);
- exp:=0;
- end
- else
- if (exp<-51) or (exp>2046) then //exponent too large.
- begin
- Result:=0;
- exit;
- end
- else //normalized value
- mant:=mant shl 1; //hide most significant bit
- end;
- end;
- d:=word(exp);
- d:=d shl 52;
- mant:=mant shr 12;
- d:=d or mant;
- if sign then d:=d or $8000000000000000;
- Result:=pdouble(@d)^;
- end;
- {$ENDIF}
- {$endif}
- function TBinaryObjectReader.ReadWord : word; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
- begin
- Read(Result,2);
- Result:=LEtoN(Result);
- end;
- function TBinaryObjectReader.ReadDWord : longword; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
- begin
- Read(Result,4);
- Result:=LEtoN(Result);
- end;
- function TBinaryObjectReader.ReadQWord : qword; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
- begin
- Read(Result,8);
- Result:=LEtoN(Result);
- end;
- {$IFDEF FPC_DOUBLE_HILO_SWAPPED}
- procedure SwapDoubleHiLo(var avalue: double); {$ifdef CLASSESINLINE}inline{$endif CLASSESINLINE}
- var dwo1 : dword;
- type tdoublerec = array[0..1] of dword;
- begin
- dwo1:= tdoublerec(avalue)[0];
- tdoublerec(avalue)[0]:=tdoublerec(avalue)[1];
- tdoublerec(avalue)[1]:=dwo1;
- end;
- {$ENDIF FPC_DOUBLE_HILO_SWAPPED}
- {$ifndef FPUNONE}
- function TBinaryObjectReader.ReadExtended : 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}
- Read(ext[0],10);
- Result:=ExtendedToDouble(@(ext[0]));
- {$IFDEF FPC_DOUBLE_HILO_SWAPPED}
- SwapDoubleHiLo(result);
- {$ENDIF}
- {$ELSE}
- Read(Result,sizeof(Result));
- {$ENDIF}
- end;
- {$endif}
- constructor TBinaryObjectReader.Create(Stream: TStream; BufSize: Integer);
- begin
- inherited Create;
- If (Stream=Nil) then
- Raise EReadError.Create(SEmptyStreamIllegalReader);
- 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;
- var
- b: byte;
- begin
- Read(b, 1);
- Result := TValueType(b);
- 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(unaligned(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(longint(Prefix and $0f));
- if ffChildPos in Flags then
- begin
- ValueType := ReadValue;
- 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
- BinSize:=LongInt(ReadDWord);
- DestData.Size := BinSize;
- Read(DestData.Memory^, BinSize);
- end;
- {$ifndef FPUNONE}
- function TBinaryObjectReader.ReadFloat: Extended;
- begin
- Result:=ReadExtended;
- end;
- function TBinaryObjectReader.ReadSingle: Single;
- begin
- Result:=single(ReadDWord);
- end;
- {$endif}
- function TBinaryObjectReader.ReadCurrency: Currency;
- begin
- Result:=currency(ReadQWord);
- end;
- {$ifndef FPUNONE}
- function TBinaryObjectReader.ReadDate: TDateTime;
- begin
- Result:=TDateTime(ReadQWord);
- end;
- {$endif}
- 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
- Result:=SmallInt(ReadWord);
- end;
- function TBinaryObjectReader.ReadInt32: LongInt;
- begin
- Result:=LongInt(ReadDWord);
- end;
- function TBinaryObjectReader.ReadInt64: Int64;
- begin
- Result:=Int64(ReadQWord);
- end;
- function TBinaryObjectReader.ReadSet(EnumType: Pointer): Integer;
- type
- tset = set of 0..31;
- 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);
- include(tset(result),Value);
- end;
- except
- SkipSetBody;
- raise;
- end;
- end;
- function TBinaryObjectReader.ReadStr: String;
- var
- i: Byte;
- begin
- Read(i, 1);
- SetLength(Result, i);
- if i > 0 then
- Read(Pointer(@Result[1])^, i);
- end;
- function TBinaryObjectReader.ReadString(StringType: TValueType): String;
- var
- b: Byte;
- i: Integer;
- begin
- case StringType of
- vaLString, vaUTF8String:
- i:=ReadDWord;
- else
- //vaString:
- begin
- Read(b, 1);
- i := b;
- end;
- end;
- SetLength(Result, i);
- if i > 0 then
- Read(Pointer(@Result[1])^, i);
- end;
- function TBinaryObjectReader.ReadWideString: WideString;
- var
- len: DWord;
- {$IFDEF ENDIAN_BIG}
- i : integer;
- {$ENDIF}
- begin
- len := ReadDWord;
- SetLength(Result, len);
- if (len > 0) then
- begin
- Read(Pointer(@Result[1])^, len*2);
- {$IFDEF ENDIAN_BIG}
- for i:=1 to len do
- Result[i]:=widechar(SwapEndian(word(Result[i])));
- {$ENDIF}
- end;
- end;
- function TBinaryObjectReader.ReadUnicodeString: UnicodeString;
- var
- len: DWord;
- {$IFDEF ENDIAN_BIG}
- i : integer;
- {$ENDIF}
- begin
- len := ReadDWord;
- SetLength(Result, len);
- if (len > 0) then
- begin
- Read(Pointer(@Result[1])^, len*2);
- {$IFDEF ENDIAN_BIG}
- for i:=1 to len do
- Result[i]:=UnicodeChar(SwapEndian(word(Result[i])));
- {$ENDIF}
- end;
- 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(10);
- vaString, vaIdent:
- ReadStr;
- vaBinary, vaLString:
- begin
- Count:=LongInt(ReadDWord);
- SkipBytes(Count);
- end;
- vaWString:
- begin
- Count:=LongInt(ReadDWord);
- SkipBytes(Count*sizeof(widechar));
- end;
- vaUString:
- begin
- Count:=LongInt(ReadDWord);
- SkipBytes(Count*sizeof(widechar));
- 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:
- {$ifndef FPUNONE}
- SkipBytes(Sizeof(Single));
- {$else}
- SkipBytes(4);
- {$endif}
- {!!!: vaCurrency:
- SkipBytes(SizeOf(Currency));}
- vaDate, 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 *}
- {****************************************************************************}
- type
- TFieldInfo = packed record
- FieldOffset: LongWord;
- ClassTypeIndex: Word;
- Name: ShortString;
- end;
- PFieldClassTable = ^TFieldClassTable;
- TFieldClassTable =
- {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
- packed
- {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
- record
- Count: Word;
- Entries: array[Word] of TPersistentClass;
- end;
- PFieldTable = ^TFieldTable;
- TFieldTable =
- {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
- packed
- {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
- 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;
- If (Stream=Nil) then
- Raise EReadError.Create(SEmptyStreamIllegalReader);
- FDriver := CreateDriver(Stream, BufSize);
- end;
- destructor TReader.Destroy;
- begin
- FDriver.Free;
- inherited Destroy;
- end;
- function TReader.CreateDriver(Stream: TStream; BufSize: Integer): TAbstractObjectReader;
- begin
- Result := TBinaryObjectReader.Create(Stream, BufSize);
- end;
- procedure TReader.BeginReferences;
- begin
- FLoaded := TFpList.Create;
- 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
- 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 TReader.DoFixupReferences;
- Var
- R,RN : TLocalUnresolvedReference;
- G : TUnresolvedInstance;
- Ref : String;
- C : TComponent;
- P : integer;
- L : TLinkedList;
-
- begin
- If Assigned(FFixups) then
- begin
- L:=TLinkedList(FFixups);
- R:=TLocalUnresolvedReference(L.Root);
- While (R<>Nil) do
- begin
- RN:=TLocalUnresolvedReference(R.Next);
- Ref:=R.FRelative;
- If Assigned(FOnReferenceName) then
- FOnReferenceName(Self,Ref);
- C:=FindNestedComponent(R.FRoot,Ref);
- If Assigned(C) then
- SetObjectProp(R.FInstance,R.FPropInfo,C)
- else
- begin
- P:=Pos('.',R.FRelative);
- If (P<>0) then
- begin
- G:=AddToResolveList(R.FInstance);
- G.Addreference(R.FRoot,R.FPropInfo,Copy(R.FRelative,1,P-1),Copy(R.FRelative,P+1,Length(R.FRelative)-P));
- end;
- end;
- L.RemoveItem(R,True);
- R:=RN;
- end;
- FreeAndNil(FFixups);
- end;
- end;
- procedure TReader.FixupReferences;
- var
- i: Integer;
- begin
- DoFixupReferences;
- GlobalFixupReferences;
- for i := 0 to FLoaded.Count - 1 do
- TComponent(FLoaded[I]).Loaded;
- end;
- function TReader.NextValue: TValueType;
- begin
- Result := FDriver.NextValue;
- end;
- procedure TReader.Read(var Buf; Count: LongInt);
- begin
- //This should give an exception if read is not implemented (i.e. TTextObjectReader)
- //but should work with TBinaryObjectReader.
- Driver.Read(Buf, Count);
- end;
- procedure TReader.PropertyError;
- begin
- FDriver.SkipValue;
- raise EReadError.CreateFmt(SUnknownProperty,[FPropName]);
- 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;
- function TReader.ReadWideChar: WideChar;
- var
- W: WideString;
-
- begin
- W := ReadWideString;
- if Length(W) = 1 then
- Result := W[1]
- else
- raise EReadError.Create(SInvalidPropertyValue);
- end;
-
- function TReader.ReadUnicodeChar: UnicodeChar;
- var
- U: UnicodeString;
-
- begin
- U := ReadUnicodeString;
- if Length(U) = 1 then
- Result := U[1]
- else
- raise EReadError.Create(SInvalidPropertyValue);
- end;
-
- procedure TReader.ReadCollection(Collection: TCollection);
- var
- Item: TCollectionItem;
- begin
- Collection.BeginUpdate;
- if not EndOfList then
- Collection.Clear;
- while not EndOfList do begin
- ReadListBegin;
- Item := Collection.Add;
- while NextValue<>vaNull do
- ReadProperty(Item);
- ReadListEnd;
- end;
- Collection.EndUpdate;
- ReadListEnd;
- 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;
- n, ChildPos: Integer;
- SavedParent, SavedLookupRoot: TComponent;
- ComponentClass: TComponentClass;
- C, NewComponent: TComponent;
- SubComponents: TList;
- begin
- FDriver.BeginComponent(Flags, ChildPos, CompClassName, Name);
- SavedParent := Parent;
- SavedLookupRoot := FLookupRoot;
- SubComponents := nil;
- 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);
- { create list of subcomponents and set loading}
- SubComponents := TList.Create;
- for n := 0 to Result.ComponentCount - 1 do
- begin
- C := Result.Components[n];
- if csSubcomponent in C.ComponentStyle
- then begin
- SubComponents.Add(C);
- Include(C.FComponentState, csLoading);
- end;
- end;
- if not (ffInherited in Flags) then
- try
- Result.SetParentComponent(Parent);
- if Assigned(FOnSetName) then
- FOnSetName(Self, Result, Name);
- Result.Name := Name;
- if 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);
- for n := 0 to Subcomponents.Count - 1 do
- Include(TComponent(Subcomponents[n]).FComponentState, csReading);
- Result.ReadState(Self);
- Exclude(Result.FComponentState, csReading);
- for n := 0 to Subcomponents.Count - 1 do
- Exclude(TComponent(Subcomponents[n]).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 begin
- for n := 0 to Subcomponents.Count - 1 do
- FLoaded.Add(Subcomponents[n]);
- FLoaded.Add(Result);
- end;
- except
- if ((ffInherited in Flags) or Assigned(Component)) then
- Result.Free;
- raise;
- end;
- finally
- Parent := SavedParent;
- FLookupRoot := SavedLookupRoot;
- Subcomponents.Free;
- end;
- end;
- procedure TReader.ReadData(Instance: TComponent);
- var
- SavedOwner, SavedParent: TComponent;
-
- begin
- { 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 (Instance=FRoot) then
- DoFixupReferences;
- end;
- {$ifndef FPUNONE}
- 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;
- {$endif}
- function TReader.ReadCurrency: Currency;
- begin
- if FDriver.NextValue = vaCurrency then
- begin
- FDriver.ReadValue;
- Result := FDriver.ReadCurrency;
- end else
- Result := ReadInteger;
- end;
- {$ifndef FPUNONE}
- function TReader.ReadDate: TDateTime;
- begin
- if FDriver.NextValue = vaDate then
- begin
- FDriver.ReadValue;
- Result := FDriver.ReadDate;
- end else
- Result := ReadInteger;
- end;
- {$endif}
- 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;
- function TReader.ReadSet(EnumType: Pointer): Integer;
- begin
- if FDriver.NextValue = vaSet then
- begin
- FDriver.ReadValue;
- Result := FDriver.ReadSet(enumtype);
- end
- else
- Result := ReadInteger;
- end;
- procedure TReader.ReadListBegin;
- begin
- CheckValue(vaList);
- end;
- procedure TReader.ReadListEnd;
- begin
- CheckValue(vaNull);
- end;
- function TReader.ReadVariant: variant;
- var
- nv: TValueType;
- begin
- { Ensure that a Variant manager is installed }
- if not Assigned(VarClearProc) then
- raise EReadError.Create(SErrNoVariantSupport);
- FillChar(Result,sizeof(Result),0);
- nv:=NextValue;
- case nv of
- vaNil:
- begin
- Result:=system.unassigned;
- end;
- vaNull:
- begin
- Result:=system.null;
- end;
- { all integer sizes must be split for big endian systems }
- vaInt8,vaInt16,vaInt32:
- begin
- Result:=ReadInteger;
- end;
- vaInt64:
- begin
- Result:=ReadInt64;
- end;
- vaQWord:
- begin
- Result:=QWord(ReadInt64);
- end;
- vaFalse,vaTrue:
- begin
- Result:=(nv<>vaFalse);
- end;
- vaCurrency:
- begin
- Result:=ReadCurrency;
- end;
- {$ifndef fpunone}
- vaSingle:
- begin
- Result:=ReadSingle;
- end;
- vaExtended:
- begin
- Result:=ReadFloat;
- end;
- vaDate:
- begin
- Result:=ReadDate;
- end;
- {$endif fpunone}
- vaWString,vaUTF8String:
- begin
- Result:=ReadWideString;
- end;
- vaString:
- begin
- Result:=ReadString;
- end;
- vaUString:
- begin
- Result:=ReadUnicodeString;
- end;
- else
- raise EReadError.CreateFmt(SUnsupportedPropertyVariantType, [Ord(nv)]);
- end;
- end;
- procedure TReader.ReadProperty(AInstance: TPersistent);
- var
- Path: String;
- Instance: TPersistent;
- DotPos, NextPos: PChar;
- PropInfo: PPropInfo;
- Obj: TObject;
- Name: String;
- Skip: Boolean;
- Handled: Boolean;
- OldPropName: String;
- function HandleMissingProperty(IsPath: Boolean): boolean;
- begin
- Result:=true;
- if Assigned(OnPropertyNotFound) then begin
- // user defined property error handling
- OldPropName:=FPropName;
- Handled:=false;
- Skip:=false;
- OnPropertyNotFound(Self,Instance,FPropName,IsPath,Handled,Skip);
- if Handled and (not Skip) and (OldPropName<>FPropName) then
- // try alias property
- PropInfo := GetPropInfo(Instance.ClassInfo, FPropName);
- if Skip then begin
- FDriver.SkipValue;
- Result:=false;
- exit;
- end;
- end;
- end;
- 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 begin
- if not HandleMissingProperty(true) then exit;
- if not Assigned(PropInfo) then
- PropertyError;
- end;
- if PropInfo^.PropType^.Kind = tkClass then
- Obj := TObject(GetObjectProp(Instance, PropInfo))
- else
- Obj := nil;
- if not (Obj is 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 begin
- if not HandleMissingProperty(false) then exit;
- if not Assigned(PropInfo) then
- PropertyError;
- end;
- 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;
- Handled: Boolean;
- TmpStr: String;
- 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
- Ident := ReadIdent;
- if GlobalIdentToInt(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));
- tkWChar,tkUChar:
- SetOrdProp(Instance, PropInfo, Ord(ReadWideChar));
- tkEnumeration:
- begin
- Value := GetEnumValue(PropType, ReadIdent);
- if Value = -1 then
- raise EReadError.Create(SInvalidPropertyValue);
- SetOrdProp(Instance, PropInfo, Value);
- end;
- {$ifndef FPUNONE}
- tkFloat:
- SetFloatProp(Instance, PropInfo, ReadFloat);
- {$endif}
- 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
- Handled:=false;
- Ident:=ReadIdent;
- if Assigned(OnSetMethodProperty) then
- OnSetMethodProperty(Self,Instance,PPropInfo(PropInfo),Ident,
- Handled);
- if not Handled then begin
- Method.Code := FindMethod(Root, Ident);
- Method.Data := Root;
- if Assigned(Method.Code) then
- SetMethodProp(Instance, PropInfo, Method);
- end;
- end;
- tkSString, tkLString, tkAString:
- begin
- TmpStr:=ReadString;
- if Assigned(FOnReadStringProperty) then
- FOnReadStringProperty(Self,Instance,PropInfo,TmpStr);
- SetStrProp(Instance, PropInfo, TmpStr);
- end;
- tkUstring:
- SetUnicodeStrProp(Instance,PropInfo,ReadUnicodeString);
- tkWString:
- SetWideStrProp(Instance,PropInfo,ReadWideString);
- tkVariant:
- begin
- SetVariantProp(Instance,PropInfo,ReadVariant);
- end;
- tkClass:
- case FDriver.NextValue of
- vaNil:
- begin
- FDriver.ReadValue;
- SetOrdProp(Instance, PropInfo, 0)
- end;
- vaCollection:
- begin
- FDriver.ReadValue;
- ReadCollection(TCollection(GetObjectProp(Instance, PropInfo)));
- end
- else
- begin
- If Not Assigned(FFixups) then
- FFixups:=TLinkedList.Create(TLocalUnresolvedReference);
- With TLocalUnresolvedReference(TLinkedList(FFixups).Add) do
- begin
- FInstance:=Instance;
- FRoot:=Root;
- FPropInfo:=PropInfo;
- FRelative:=ReadIdent;
- end;
- end;
- end;
- tkInt64, tkQWord: 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];
- { 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;
- end;
- FRoot := Result;
- FLookupRoot := Result;
- if Assigned(GlobalLoaded) then
- FLoaded := GlobalLoaded
- else
- FLoaded := TFpList.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,vaUTF8String] then
- begin
- Result := FDriver.ReadString(StringType);
- if (StringType=vaUTF8String) then
- Result:=utf8Decode(Result);
- end
- else if StringType in [vaWString] then
- Result:= FDriver.ReadWidestring
- else if StringType in [vaUString] then
- Result:= FDriver.ReadUnicodeString
- else
- raise EReadError.Create(SInvalidPropertyValue);
- end;
- function TReader.ReadWideString: WideString;
- var
- s: String;
- i: Integer;
- vt:TValueType;
- begin
- if NextValue in [vaWString,vaUString,vaUTF8String] then
- //vaUTF8String needs conversion? 2008-09-06 mse, YES!! AntonK
- begin
- vt:=ReadValue;
- if vt=vaUTF8String then
- Result := utf8decode(fDriver.ReadString(vaLString))
- else
- Result := FDriver.ReadWideString
- end
- else
- begin
- //data probable from ObjectTextToBinary
- s := ReadString;
- setlength(result,length(s));
- for i:= 1 to length(s) do begin
- result[i]:= widechar(ord(s[i])); //no code conversion
- end;
- end;
- end;
- function TReader.ReadUnicodeString: UnicodeString;
- var
- s: String;
- i: Integer;
- vt:TValueType;
- begin
- if NextValue in [vaWString,vaUString,vaUTF8String] then
- //vaUTF8String needs conversion? 2008-09-06 mse, YES!! AntonK
- begin
- vt:=ReadValue;
- if vt=vaUTF8String then
- Result := utf8decode(fDriver.ReadString(vaLString))
- else
- Result := FDriver.ReadWideString
- end
- else
- begin
- //data probable from ObjectTextToBinary
- s := ReadString;
- setlength(result,length(s));
- for i:= 1 to length(s) do begin
- result[i]:= UnicodeChar(ord(s[i])); //no code conversion
- end;
- end;
- 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);
- {$ifndef FPUNONE}
- vaExtended:
- Writer.WriteFloat(ReadFloat);
- {$endif}
- {!!!: 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);}
- {$ifndef FPUNONE}
- vaSingle:
- Writer.WriteSingle(ReadSingle);
- {$endif}
- {!!!: vaCurrency:
- Writer.WriteCurrency(ReadCurrency);}
- {$ifndef FPUNONE}
- vaDate:
- Writer.WriteDate(ReadDate);
- {$endif}
- vaInt64:
- Writer.WriteInteger(ReadInt64);
- end;
- end;
- function TReader.FindComponentClass(const AClassName: String): TComponentClass;
- var
- PersistentClass: TPersistentClass;
- UClassName: shortstring;
- procedure FindInFieldTable(RootComponent: TComponent);
- var
- FieldClassTable: PFieldClassTable;
- Entry: TPersistentClass;
- i: Integer;
- ComponentClassType: TClass;
- begin
- ComponentClassType := RootComponent.ClassType;
- // it is not necessary to look in the FieldTable of TComponent,
- // because TComponent doesn't have published properties that are
- // descendants of TComponent
- while ComponentClassType<>TComponent do begin
- FieldClassTable :=
- PFieldTable((Pointer(ComponentClassType)+vmtFieldTable)^)^.ClassTable;
- if assigned(FieldClassTable) then begin
- for i := 0 to FieldClassTable^.Count -1 do begin
- Entry := FieldClassTable^.Entries[i];
- //writeln(format('Looking for %s in field table of class %s. Found %s',
- //[AClassName, ComponentClassType.ClassName, Entry.ClassName]));
- if (UpperCase(Entry.ClassName)=UClassName) and
- (Entry.InheritsFrom(TComponent)) then begin
- Result := TComponentClass(Entry);
- Exit;
- end;
- end;
- end;
- // look in parent class
- ComponentClassType := ComponentClassType.ClassParent;
- end;
- end;
-
- begin
- Result := nil;
- UClassName:=UpperCase(AClassName);
- FindInFieldTable(Root);
-
- if (Result=nil) and assigned(LookupRoot) and (LookupRoot<>Root) then
- FindInFieldTable(LookupRoot);
- if (Result=nil) then begin
- PersistentClass := GetClass(AClassName);
- if PersistentClass.InheritsFrom(TComponent) then
- Result := TComponentClass(PersistentClass);
- end;
-
- if (Result=nil) and assigned(OnFindComponentClass) then
- OnFindComponentClass(Self, AClassName, Result);
- if (Result=nil) or (not Result.InheritsFrom(TComponent)) then
- raise EClassNotFound.CreateFmt(SClassNotFound, [AClassName]);
- end;
|