123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797 |
- {
- 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;
- begin
- { Read filer signature }
- ReadSignature;
- 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(TFilerFlagsInt(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;
- var
- r: record
- case byte of
- 1: (d: dword);
- 2: (s: single);
- end;
- begin
- r.d:=ReadDWord;
- Result:=r.s;
- end;
- {$endif}
- function TBinaryObjectReader.ReadCurrency: Currency;
- var
- r: record
- case byte of
- 1: (q: qword);
- 2: (c: currency);
- end;
- begin
- r.c:=ReadQWord;
- Result:=r.c;
- end;
- {$ifndef FPUNONE}
- function TBinaryObjectReader.ReadDate: TDateTime;
- var
- r: record
- case byte of
- 1: (q: qword);
- 2: (d: TDateTime);
- end;
- begin
- r.q:=ReadQWord;
- Result:=r.d;
- 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
- {$packset 1}
- tset = set of 0..(SizeOf(Integer)*8-1);
- {$packset default}
- 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;
- procedure TBinaryObjectReader.ReadSignature;
- var
- Signature: LongInt;
- begin
- Read(Signature, 4);
- if Signature <> LongInt(unaligned(FilerSignature)) then
- raise EReadError.Create(SInvalidImage);
- 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;
- {$ifdef VER3_0}
- PersistentClassRef = TPersistentClass;
- {$else VER3_0}
- PPersistentClass = ^TPersistentClass;
- PersistentClassRef = PPersistentClass;
- {$endif VER3_0}
- PFieldClassTable = ^TFieldClassTable;
- TFieldClassTable =
- {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
- packed
- {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
- record
- Count: Word;
- Entries: array[{$ifdef cpu16}0..16384 div sizeof(PersistentClassRef){$else}Word{$endif}] of PersistentClassRef;
- 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
- ShortClassName: shortstring;
- ClassType: TClass;
- ClassTable: PFieldClassTable;
- i: Integer;
- FieldTable: PFieldTable;
- begin
- // At first, try to locate the class in the class tables
- ShortClassName := ClassName;
- ClassType := Instance.ClassType;
- while ClassType <> TPersistent do
- begin
- FieldTable := PFieldTable(PVmt(ClassType)^.vFieldTable);
- if Assigned(FieldTable) then
- begin
- ClassTable := FieldTable^.ClassTable;
- for i := 0 to ClassTable^.Count - 1 do
- begin
- Result := ClassTable^.Entries[i]{$ifndef VER3_0}^{$endif};
- if Result.ClassNameIs(ShortClassName) then
- exit;
- end;
- 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);
- {$ifdef FPC_HAS_FEATURE_THREADING}
- InitCriticalSection(FLock);
- {$ENDIF}
- end;
- destructor TReader.Destroy;
- begin
- {$ifdef FPC_HAS_FEATURE_THREADING}
- DoneCriticalSection(FLock);
- {$ENDIF}
- FDriver.Free;
- inherited Destroy;
- end;
- procedure TReader.Lock;
- begin
- {$ifdef FPC_HAS_FEATURE_THREADING}
- EnterCriticalSection(FLock);
- {$ENDIF}
- end;
- procedure TReader.Unlock;
- begin
- {$ifdef FPC_HAS_FEATURE_THREADING}
- LeaveCriticalSection(FLock);
- {$ENDIF}
- end;
- procedure TReader.FlushBuffer;
- begin
- Driver.FlushBuffer;
- 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): CodePointer;
- 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;
- RI: Pointer; // raw interface
- IIDStr: ShortString;
-
- 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
- if R.FPropInfo^.PropType^.Kind = tkInterface then
- SetInterfaceProp(R.FInstance,R.FPropInfo,C)
- else if R.FPropInfo^.PropType^.Kind = tkInterfaceRaw then
- begin
- IIDStr := GetTypeData(R.FPropInfo^.PropType)^.IIDStr;
- if IIDStr = '' then
- raise EReadError.CreateFmt(SInterfaceNoIIDStr, [R.FPropInfo^.PropType^.Name]);
- if C.GetInterface(IIDStr, RI) then
- SetRawInterfaceProp(R.FInstance,R.FPropInfo,RI)
- else
- raise EReadError.CreateFmt(SComponentDoesntImplement, [C.ClassName, IIDStr]);
- end
- else
- 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 aComponent: TComponent): Boolean;
- begin
- Result := False;
- if ExceptObject.InheritsFrom(Exception) then
- begin
- if not ((ffInherited in Flags) or Assigned(Component)) then
- aComponent.Free;
- aComponent := 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 occurred) }
- 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 := ReadInt64;
- end;
- procedure TReader.ReadSignature;
- begin
- FDriver.ReadSignature;
- 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;
- readvalue;
- end;
- vaNull:
- begin
- Result:=system.null;
- readvalue;
- 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);
- readValue;
- 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 if PropInfo^.PropType^.Kind = tkInterface then
- // Obj := TObject(GetInterfaceProp(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, tkInterface, tkInterfaceRaw:
- 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;
- Lock;
- try
- while Assigned(FindGlobalComponent(ResultName)) do
- begin
- Inc(i);
- ResultName := CompName + '_' + IntToStr(i);
- end;
- Result.Name := ResultName;
- finally
- Unlock;
- end;
- 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:=string(utf8Decode(Result));
- end
- else if StringType in [vaWString] then
- Result:= string(FDriver.ReadWidestring)
- else if StringType in [vaUString] then
- Result:= string(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;
- ShortClassName: shortstring;
- procedure FindInFieldTable(RootComponent: TComponent);
- var
- FieldTable: PFieldTable;
- 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
- FieldTable:=PVmt(ComponentClassType)^.vFieldTable;
- if assigned(FieldTable) then
- begin
- FieldClassTable := FieldTable^.ClassTable;
- for i := 0 to FieldClassTable^.Count -1 do
- begin
- Entry := FieldClassTable^.Entries[i]{$ifndef VER3_0}^{$endif};
- //writeln(format('Looking for %s in field table of class %s. Found %s',
- //[AClassName, ComponentClassType.ClassName, Entry.ClassName]));
- if Entry.ClassNameIs(ShortClassName) 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;
- ShortClassName:=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;
- { TAbstractObjectReader }
- procedure TAbstractObjectReader.FlushBuffer;
- begin
- // Do nothing
- end;
|