writer.inc 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290
  1. {
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 1999-2000 by the Free Pascal development team
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. {****************************************************************************}
  11. {* TBinaryObjectWriter *}
  12. {****************************************************************************}
  13. {$ifndef FPUNONE}
  14. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  15. procedure DoubleToExtended(d : double; e : pointer);
  16. var mant : qword;
  17. exp : smallint;
  18. sign : boolean;
  19. begin
  20. mant:=(qword(d) and $000FFFFFFFFFFFFF) shl 12;
  21. exp :=(qword(d) shr 52) and $7FF;
  22. sign:=(qword(d) and $8000000000000000)<>0;
  23. case exp of
  24. 0 : begin
  25. if mant<>0 then //denormalized value: hidden bit is 0. normalize it
  26. begin
  27. exp:=16383-1022;
  28. while (mant and $8000000000000000)=0 do
  29. begin
  30. dec(exp);
  31. mant:=mant shl 1;
  32. end;
  33. dec(exp); //don't shift, most significant bit is not hidden in extended
  34. end;
  35. end;
  36. 2047 : exp:=$7FFF //either infinity or NaN
  37. else
  38. begin
  39. inc(exp,16383-1023);
  40. mant:=(mant shr 1) or $8000000000000000; //unhide hidden bit
  41. end;
  42. end;
  43. if sign then exp:=exp or $8000;
  44. mant:=NtoLE(mant);
  45. exp:=NtoLE(word(exp));
  46. move(mant,pbyte(e)[0],8); //mantissa : bytes 0..7
  47. move(exp,pbyte(e)[8],2); //exponent and sign: bytes 8..9
  48. end;
  49. {$ENDIF}
  50. {$endif}
  51. procedure TBinaryObjectWriter.WriteWord(w : word); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  52. begin
  53. w:=NtoLE(w);
  54. Write(w,2);
  55. end;
  56. procedure TBinaryObjectWriter.WriteDWord(lw : longword); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  57. begin
  58. lw:=NtoLE(lw);
  59. Write(lw,4);
  60. end;
  61. procedure TBinaryObjectWriter.WriteQWord(qw : qword); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  62. begin
  63. qw:=NtoLE(qw);
  64. Write(qw,8);
  65. end;
  66. {$ifndef FPUNONE}
  67. procedure TBinaryObjectWriter.WriteExtended(e : extended); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  68. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  69. var ext : array[0..9] of byte;
  70. {$ENDIF}
  71. begin
  72. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  73. {$IFDEF FPC_DOUBLE_HILO_SWAPPED}
  74. { SwapDoubleHiLo defined in reader.inc }
  75. SwapDoubleHiLo(e);
  76. {$ENDIF FPC_DOUBLE_HILO_SWAPPED}
  77. DoubleToExtended(e,@(ext[0]));
  78. Write(ext[0],10);
  79. {$ELSE}
  80. Write(e,sizeof(e));
  81. {$ENDIF}
  82. end;
  83. {$endif}
  84. constructor TBinaryObjectWriter.Create(Stream: TStream; BufSize: Integer);
  85. begin
  86. inherited Create;
  87. If (Stream=Nil) then
  88. Raise EWriteError.Create(SEmptyStreamIllegalWriter);
  89. FStream := Stream;
  90. FBufSize := BufSize;
  91. GetMem(FBuffer, BufSize);
  92. end;
  93. destructor TBinaryObjectWriter.Destroy;
  94. begin
  95. // Flush all data which hasn't been written yet
  96. FlushBuffer;
  97. if Assigned(FBuffer) then
  98. FreeMem(FBuffer, FBufSize);
  99. inherited Destroy;
  100. end;
  101. procedure TBinaryObjectWriter.BeginCollection;
  102. begin
  103. WriteValue(vaCollection);
  104. end;
  105. procedure TBinaryObjectWriter.WriteSignature;
  106. begin
  107. Write(FilerSignature, SizeOf(FilerSignature));
  108. end;
  109. procedure TBinaryObjectWriter.BeginComponent(Component: TComponent;
  110. Flags: TFilerFlags; ChildPos: Integer);
  111. var
  112. Prefix: Byte;
  113. begin
  114. { Only write the flags if they are needed! }
  115. if Flags <> [] then
  116. begin
  117. Prefix := TFilerFlagsInt(Flags) or $f0;
  118. Write(Prefix, 1);
  119. if ffChildPos in Flags then
  120. WriteInteger(ChildPos);
  121. end;
  122. WriteStr(Component.ClassName);
  123. WriteStr(Component.Name);
  124. end;
  125. procedure TBinaryObjectWriter.BeginList;
  126. begin
  127. WriteValue(vaList);
  128. end;
  129. procedure TBinaryObjectWriter.EndList;
  130. begin
  131. WriteValue(vaNull);
  132. end;
  133. procedure TBinaryObjectWriter.BeginProperty(const PropName: String);
  134. begin
  135. WriteStr(PropName);
  136. end;
  137. procedure TBinaryObjectWriter.EndProperty;
  138. begin
  139. end;
  140. procedure TBinaryObjectWriter.WriteBinary(const Buffer; Count: LongInt);
  141. begin
  142. WriteValue(vaBinary);
  143. WriteDWord(longword(Count));
  144. Write(Buffer, Count);
  145. end;
  146. procedure TBinaryObjectWriter.WriteBoolean(Value: Boolean);
  147. begin
  148. if Value then
  149. WriteValue(vaTrue)
  150. else
  151. WriteValue(vaFalse);
  152. end;
  153. {$ifndef FPUNONE}
  154. procedure TBinaryObjectWriter.WriteFloat(const Value: Extended);
  155. begin
  156. WriteValue(vaExtended);
  157. WriteExtended(Value);
  158. end;
  159. procedure TBinaryObjectWriter.WriteSingle(const Value: Single);
  160. begin
  161. WriteValue(vaSingle);
  162. WriteDWord(longword(Value));
  163. end;
  164. {$endif}
  165. procedure TBinaryObjectWriter.WriteCurrency(const Value: Currency);
  166. begin
  167. WriteValue(vaCurrency);
  168. WriteQWord(qword(Value));
  169. end;
  170. {$ifndef FPUNONE}
  171. procedure TBinaryObjectWriter.WriteDate(const Value: TDateTime);
  172. begin
  173. WriteValue(vaDate);
  174. WriteQWord(qword(Value));
  175. end;
  176. {$endif}
  177. procedure TBinaryObjectWriter.WriteIdent(const Ident: string);
  178. begin
  179. { Check if Ident is a special identifier before trying to just write
  180. Ident directly }
  181. if UpperCase(Ident) = 'NIL' then
  182. WriteValue(vaNil)
  183. else if UpperCase(Ident) = 'FALSE' then
  184. WriteValue(vaFalse)
  185. else if UpperCase(Ident) = 'TRUE' then
  186. WriteValue(vaTrue)
  187. else if UpperCase(Ident) = 'NULL' then
  188. WriteValue(vaNull) else
  189. begin
  190. WriteValue(vaIdent);
  191. WriteStr(Ident);
  192. end;
  193. end;
  194. procedure TBinaryObjectWriter.WriteInteger(Value: Int64);
  195. var
  196. s: ShortInt;
  197. i: SmallInt;
  198. l: Longint;
  199. begin
  200. { Use the smallest possible integer type for the given value: }
  201. if (Value >= -128) and (Value <= 127) then
  202. begin
  203. WriteValue(vaInt8);
  204. s := Value;
  205. Write(s, 1);
  206. end else if (Value >= -32768) and (Value <= 32767) then
  207. begin
  208. WriteValue(vaInt16);
  209. i := Value;
  210. WriteWord(word(i));
  211. end else if (Value >= -$80000000) and (Value <= $7fffffff) then
  212. begin
  213. WriteValue(vaInt32);
  214. l := Value;
  215. WriteDWord(longword(l));
  216. end else
  217. begin
  218. WriteValue(vaInt64);
  219. WriteQWord(qword(Value));
  220. end;
  221. end;
  222. procedure TBinaryObjectWriter.WriteUInt64(Value: QWord);
  223. var
  224. s: ShortInt;
  225. i: SmallInt;
  226. l: Longint;
  227. begin
  228. { Use the smallest possible integer type for the given value: }
  229. if (Value <= 127) then
  230. begin
  231. WriteValue(vaInt8);
  232. s := Value;
  233. Write(s, 1);
  234. end else if (Value <= 32767) then
  235. begin
  236. WriteValue(vaInt16);
  237. i := Value;
  238. WriteWord(word(i));
  239. end else if (Value <= $7fffffff) then
  240. begin
  241. WriteValue(vaInt32);
  242. l := Value;
  243. WriteDWord(longword(l));
  244. end else
  245. begin
  246. WriteValue(vaQWord);
  247. WriteQWord(Value);
  248. end;
  249. end;
  250. procedure TBinaryObjectWriter.WriteMethodName(const Name: String);
  251. begin
  252. if Length(Name) > 0 then
  253. begin
  254. WriteValue(vaIdent);
  255. WriteStr(Name);
  256. end else
  257. WriteValue(vaNil);
  258. end;
  259. procedure TBinaryObjectWriter.WriteSet(Value: LongInt; SetType: Pointer);
  260. type
  261. tset = set of 0..31;
  262. var
  263. i: Integer;
  264. begin
  265. WriteValue(vaSet);
  266. for i := 0 to 31 do
  267. begin
  268. if (i in tset(Value)) then
  269. WriteStr(GetEnumName(PTypeInfo(SetType), i));
  270. end;
  271. WriteStr('');
  272. end;
  273. procedure TBinaryObjectWriter.WriteString(const Value: String);
  274. var
  275. i: Integer;
  276. b: byte;
  277. begin
  278. i := Length(Value);
  279. if i <= 255 then
  280. begin
  281. WriteValue(vaString);
  282. b := i;
  283. Write(b, 1);
  284. end else
  285. begin
  286. WriteValue(vaLString);
  287. WriteDWord(longword(i));
  288. end;
  289. if i > 0 then
  290. Write(Value[1], i);
  291. end;
  292. procedure TBinaryObjectWriter.WriteWideString(const Value: WideString);
  293. var len : longword;
  294. {$IFDEF ENDIAN_BIG}
  295. i : integer;
  296. ws : widestring;
  297. {$ENDIF}
  298. begin
  299. WriteValue(vaWString);
  300. len:=Length(Value);
  301. WriteDWord(len);
  302. if len > 0 then
  303. begin
  304. {$IFDEF ENDIAN_BIG}
  305. setlength(ws,len);
  306. for i:=1 to len do
  307. ws[i]:=widechar(SwapEndian(word(Value[i])));
  308. Write(ws[1], len*sizeof(widechar));
  309. {$ELSE}
  310. Write(Value[1], len*sizeof(widechar));
  311. {$ENDIF}
  312. end;
  313. end;
  314. procedure TBinaryObjectWriter.WriteUnicodeString(const Value: UnicodeString);
  315. var len : longword;
  316. {$IFDEF ENDIAN_BIG}
  317. i : integer;
  318. us : UnicodeString;
  319. {$ENDIF}
  320. begin
  321. WriteValue(vaUString);
  322. len:=Length(Value);
  323. WriteDWord(len);
  324. if len > 0 then
  325. begin
  326. {$IFDEF ENDIAN_BIG}
  327. setlength(us,len);
  328. for i:=1 to len do
  329. us[i]:=widechar(SwapEndian(word(Value[i])));
  330. Write(us[1], len*sizeof(UnicodeChar));
  331. {$ELSE}
  332. Write(Value[1], len*sizeof(UnicodeChar));
  333. {$ENDIF}
  334. end;
  335. end;
  336. procedure TBinaryObjectWriter.WriteVariant(const VarValue: variant);
  337. begin
  338. { The variant manager will handle varbyref and vararray transparently for us
  339. }
  340. case (tvardata(VarValue).vtype and varTypeMask) of
  341. varEmpty:
  342. begin
  343. WriteValue(vaNil);
  344. end;
  345. varNull:
  346. begin
  347. WriteValue(vaNull);
  348. end;
  349. { all integer sizes must be split for big endian systems }
  350. varShortInt,varSmallInt,varInteger,varInt64:
  351. begin
  352. WriteInteger(VarValue);
  353. end;
  354. varQWord:
  355. begin
  356. WriteUInt64(VarValue);
  357. end;
  358. varBoolean:
  359. begin
  360. WriteBoolean(VarValue);
  361. end;
  362. varCurrency:
  363. begin
  364. WriteCurrency(VarValue);
  365. end;
  366. {$ifndef fpunone}
  367. varSingle:
  368. begin
  369. WriteSingle(VarValue);
  370. end;
  371. varDouble:
  372. begin
  373. WriteFloat(VarValue);
  374. end;
  375. varDate:
  376. begin
  377. WriteDate(VarValue);
  378. end;
  379. {$endif fpunone}
  380. varOleStr,varString:
  381. begin
  382. WriteWideString(VarValue);
  383. end;
  384. else
  385. raise EWriteError.CreateFmt(SUnsupportedPropertyVariantType, [Ord(tvardata(VarValue).vtype)]);
  386. end;
  387. end;
  388. procedure TBinaryObjectWriter.FlushBuffer;
  389. begin
  390. FStream.WriteBuffer(FBuffer^, FBufPos);
  391. FBufPos := 0;
  392. end;
  393. procedure TBinaryObjectWriter.Write(const Buffer; Count: LongInt);
  394. var
  395. CopyNow: LongInt;
  396. SourceBuf: PChar;
  397. begin
  398. SourceBuf:=@Buffer;
  399. while Count > 0 do
  400. begin
  401. CopyNow := Count;
  402. if CopyNow > FBufSize - FBufPos then
  403. CopyNow := FBufSize - FBufPos;
  404. Move(SourceBuf^, PChar(FBuffer)[FBufPos], CopyNow);
  405. Dec(Count, CopyNow);
  406. Inc(FBufPos, CopyNow);
  407. inc(SourceBuf, CopyNow);
  408. if FBufPos = FBufSize then
  409. FlushBuffer;
  410. end;
  411. end;
  412. procedure TBinaryObjectWriter.WriteValue(Value: TValueType);
  413. var
  414. b: byte;
  415. begin
  416. b := byte(Value);
  417. Write(b, 1);
  418. end;
  419. procedure TBinaryObjectWriter.WriteStr(const Value: String);
  420. var
  421. i: integer;
  422. b: byte;
  423. begin
  424. i := Length(Value);
  425. if i > 255 then
  426. i := 255;
  427. b := i;
  428. Write(b, 1);
  429. if i > 0 then
  430. Write(Value[1], i);
  431. end;
  432. {****************************************************************************}
  433. {* TWriter *}
  434. {****************************************************************************}
  435. constructor TWriter.Create(ADriver: TAbstractObjectWriter);
  436. begin
  437. inherited Create;
  438. FDriver := ADriver;
  439. end;
  440. constructor TWriter.Create(Stream: TStream; BufSize: Integer);
  441. begin
  442. inherited Create;
  443. If (Stream=Nil) then
  444. Raise EWriteError.Create(SEmptyStreamIllegalWriter);
  445. FDriver := CreateDriver(Stream, BufSize);
  446. FDestroyDriver := True;
  447. end;
  448. destructor TWriter.Destroy;
  449. begin
  450. if FDestroyDriver then
  451. FDriver.Free;
  452. inherited Destroy;
  453. end;
  454. function TWriter.CreateDriver(Stream: TStream; BufSize: Integer): TAbstractObjectWriter;
  455. begin
  456. Result := TBinaryObjectWriter.Create(Stream, BufSize);
  457. end;
  458. Type
  459. TPosComponent = Class(TObject)
  460. FPos : Integer;
  461. FComponent : TComponent;
  462. Constructor Create(APos : Integer; AComponent : TComponent);
  463. end;
  464. Constructor TPosComponent.Create(APos : Integer; AComponent : TComponent);
  465. begin
  466. FPos:=APos;
  467. FComponent:=AComponent;
  468. end;
  469. // Used as argument for calls to TComponent.GetChildren:
  470. procedure TWriter.AddToAncestorList(Component: TComponent);
  471. begin
  472. FAncestors.AddObject(Component.Name,TPosComponent.Create(FAncestors.Count,Component));
  473. end;
  474. procedure TWriter.DefineProperty(const Name: String;
  475. ReadData: TReaderProc; AWriteData: TWriterProc; HasData: Boolean);
  476. begin
  477. if HasData and Assigned(AWriteData) then
  478. begin
  479. // Write the property name and then the data itself
  480. Driver.BeginProperty(FPropPath + Name);
  481. AWriteData(Self);
  482. Driver.EndProperty;
  483. end;
  484. end;
  485. procedure TWriter.DefineBinaryProperty(const Name: String;
  486. ReadData, AWriteData: TStreamProc; HasData: Boolean);
  487. begin
  488. if HasData and Assigned(AWriteData) then
  489. begin
  490. // Write the property name and then the data itself
  491. Driver.BeginProperty(FPropPath + Name);
  492. WriteBinary(AWriteData);
  493. Driver.EndProperty;
  494. end;
  495. end;
  496. procedure TWriter.Write(const Buffer; Count: Longint);
  497. begin
  498. //This should give an exception if write is not implemented (i.e. TTextObjectWriter)
  499. //but should work with TBinaryObjectWriter.
  500. Driver.Write(Buffer, Count);
  501. end;
  502. procedure TWriter.SetRoot(ARoot: TComponent);
  503. begin
  504. inherited SetRoot(ARoot);
  505. // Use the new root as lookup root too
  506. FLookupRoot := ARoot;
  507. end;
  508. procedure TWriter.WriteSignature;
  509. begin
  510. FDriver.WriteSignature;
  511. end;
  512. procedure TWriter.WriteBinary(AWriteData: TStreamProc);
  513. var
  514. MemBuffer: TMemoryStream;
  515. BufferSize: Longint;
  516. begin
  517. { First write the binary data into a memory stream, then copy this buffered
  518. stream into the writing destination. This is necessary as we have to know
  519. the size of the binary data in advance (we're assuming that seeking within
  520. the writer stream is not possible) }
  521. MemBuffer := TMemoryStream.Create;
  522. try
  523. AWriteData(MemBuffer);
  524. BufferSize := MemBuffer.Size;
  525. Driver.WriteBinary(MemBuffer.Memory^, BufferSize);
  526. finally
  527. MemBuffer.Free;
  528. end;
  529. end;
  530. procedure TWriter.WriteBoolean(Value: Boolean);
  531. begin
  532. Driver.WriteBoolean(Value);
  533. end;
  534. procedure TWriter.WriteChar(Value: Char);
  535. begin
  536. WriteString(Value);
  537. end;
  538. procedure TWriter.WriteWideChar(Value: WideChar);
  539. begin
  540. WriteWideString(Value);
  541. end;
  542. procedure TWriter.WriteCollection(Value: TCollection);
  543. var
  544. i: Integer;
  545. begin
  546. Driver.BeginCollection;
  547. if Assigned(Value) then
  548. for i := 0 to Value.Count - 1 do
  549. begin
  550. { Each collection item needs its own ListBegin/ListEnd tag, or else the
  551. reader wouldn't be able to know where an item ends and where the next
  552. one starts }
  553. WriteListBegin;
  554. WriteProperties(Value.Items[i]);
  555. WriteListEnd;
  556. end;
  557. WriteListEnd;
  558. end;
  559. procedure TWriter.DetermineAncestor(Component : TComponent);
  560. Var
  561. I : Integer;
  562. begin
  563. // Should be set only when we write an inherited with children.
  564. if Not Assigned(FAncestors) then
  565. exit;
  566. I:=FAncestors.IndexOf(Component.Name);
  567. If (I=-1) then
  568. begin
  569. FAncestor:=Nil;
  570. FAncestorPos:=-1;
  571. end
  572. else
  573. With TPosComponent(FAncestors.Objects[i]) do
  574. begin
  575. FAncestor:=FComponent;
  576. FAncestorPos:=FPos;
  577. end;
  578. end;
  579. procedure TWriter.DoFindAncestor(Component : TComponent);
  580. Var
  581. C : TComponent;
  582. begin
  583. if Assigned(FOnFindAncestor) then
  584. if (Ancestor=Nil) or (Ancestor is TComponent) then
  585. begin
  586. C:=TComponent(Ancestor);
  587. FOnFindAncestor(Self,Component,Component.Name,C,FRootAncestor);
  588. Ancestor:=C;
  589. end;
  590. end;
  591. procedure TWriter.WriteComponent(Component: TComponent);
  592. var
  593. SA : TPersistent;
  594. SR, SRA : TComponent;
  595. begin
  596. SR:=FRoot;
  597. SA:=FAncestor;
  598. SRA:=FRootAncestor;
  599. Try
  600. Component.FComponentState:=Component.FComponentState+[csWriting];
  601. Try
  602. // Possibly set ancestor.
  603. DetermineAncestor(Component);
  604. DoFindAncestor(Component); // Mainly for IDE when a parent form had an ancestor renamed...
  605. // Will call WriteComponentData.
  606. Component.WriteState(Self);
  607. FDriver.EndList;
  608. Finally
  609. Component.FComponentState:=Component.FComponentState-[csWriting];
  610. end;
  611. Finally
  612. FAncestor:=SA;
  613. FRoot:=SR;
  614. FRootAncestor:=SRA;
  615. end;
  616. end;
  617. procedure TWriter.WriteChildren(Component : TComponent);
  618. Var
  619. SRoot, SRootA : TComponent;
  620. SList : TStringList;
  621. SPos, I , SAncestorPos: Integer;
  622. begin
  623. // Write children list.
  624. // While writing children, the ancestor environment must be saved
  625. // This is recursive...
  626. SRoot:=FRoot;
  627. SRootA:=FRootAncestor;
  628. SList:=FAncestors;
  629. SPos:=FCurrentPos;
  630. SAncestorPos:=FAncestorPos;
  631. try
  632. FAncestors:=Nil;
  633. FCurrentPos:=0;
  634. FAncestorPos:=-1;
  635. if csInline in Component.ComponentState then
  636. FRoot:=Component;
  637. if (FAncestor is TComponent) then
  638. begin
  639. FAncestors:=TStringList.Create;
  640. if csInline in TComponent(FAncestor).ComponentState then
  641. FRootAncestor := TComponent(FAncestor);
  642. TComponent(FAncestor).GetChildren(@AddToAncestorList,FRootAncestor);
  643. FAncestors.Sorted:=True;
  644. end;
  645. try
  646. Component.GetChildren(@WriteComponent, FRoot);
  647. Finally
  648. If Assigned(Fancestors) then
  649. For I:=0 to FAncestors.Count-1 do
  650. FAncestors.Objects[i].Free;
  651. FreeAndNil(FAncestors);
  652. end;
  653. finally
  654. FAncestors:=Slist;
  655. FRoot:=SRoot;
  656. FRootAncestor:=SRootA;
  657. FCurrentPos:=SPos;
  658. FAncestorPos:=SAncestorPos;
  659. end;
  660. end;
  661. procedure TWriter.WriteComponentData(Instance: TComponent);
  662. var
  663. Flags: TFilerFlags;
  664. begin
  665. Flags := [];
  666. If (Assigned(FAncestor)) and //has ancestor
  667. (not (csInline in Instance.ComponentState) or // no inline component
  668. // .. or the inline component is inherited
  669. (csAncestor in Instance.Componentstate) and (FAncestors <> nil)) then
  670. Flags:=[ffInherited]
  671. else If csInline in Instance.ComponentState then
  672. Flags:=[ffInline];
  673. If (FAncestors<>Nil) and ((FCurrentPos<>FAncestorPos) or (FAncestor=Nil)) then
  674. Include(Flags,ffChildPos);
  675. FDriver.BeginComponent(Instance,Flags,FCurrentPos);
  676. If (FAncestors<>Nil) then
  677. Inc(FCurrentPos);
  678. WriteProperties(Instance);
  679. WriteListEnd;
  680. // Needs special handling of ancestor.
  681. If not IgnoreChildren then
  682. WriteChildren(Instance);
  683. end;
  684. procedure TWriter.WriteDescendent(ARoot: TComponent; AAncestor: TComponent);
  685. begin
  686. FRoot := ARoot;
  687. FAncestor := AAncestor;
  688. FRootAncestor := AAncestor;
  689. FLookupRoot := ARoot;
  690. WriteSignature;
  691. WriteComponent(ARoot);
  692. end;
  693. {$ifndef FPUNONE}
  694. procedure TWriter.WriteFloat(const Value: Extended);
  695. begin
  696. Driver.WriteFloat(Value);
  697. end;
  698. procedure TWriter.WriteSingle(const Value: Single);
  699. begin
  700. Driver.WriteSingle(Value);
  701. end;
  702. {$endif}
  703. procedure TWriter.WriteCurrency(const Value: Currency);
  704. begin
  705. Driver.WriteCurrency(Value);
  706. end;
  707. {$ifndef FPUNONE}
  708. procedure TWriter.WriteDate(const Value: TDateTime);
  709. begin
  710. Driver.WriteDate(Value);
  711. end;
  712. {$endif}
  713. procedure TWriter.WriteIdent(const Ident: string);
  714. begin
  715. Driver.WriteIdent(Ident);
  716. end;
  717. procedure TWriter.WriteInteger(Value: LongInt);
  718. begin
  719. Driver.WriteInteger(Value);
  720. end;
  721. procedure TWriter.WriteInteger(Value: Int64);
  722. begin
  723. Driver.WriteInteger(Value);
  724. end;
  725. procedure TWriter.WriteSet(Value: LongInt; SetType: Pointer);
  726. begin
  727. Driver.WriteSet(Value,SetType);
  728. end;
  729. procedure TWriter.WriteVariant(const VarValue: Variant);
  730. begin
  731. Driver.WriteVariant(VarValue);
  732. end;
  733. procedure TWriter.WriteListBegin;
  734. begin
  735. Driver.BeginList;
  736. end;
  737. procedure TWriter.WriteListEnd;
  738. begin
  739. Driver.EndList;
  740. end;
  741. procedure TWriter.WriteProperties(Instance: TPersistent);
  742. var PropCount,i : integer;
  743. PropList : PPropList;
  744. begin
  745. PropCount:=GetPropList(Instance,PropList);
  746. if PropCount>0 then
  747. try
  748. for i := 0 to PropCount-1 do
  749. if IsStoredProp(Instance,PropList^[i]) then
  750. WriteProperty(Instance,PropList^[i]);
  751. Finally
  752. Freemem(PropList);
  753. end;
  754. Instance.DefineProperties(Self);
  755. end;
  756. procedure TWriter.WriteProperty(Instance: TPersistent; PropInfo: Pointer);
  757. var
  758. HasAncestor: Boolean;
  759. PropType: PTypeInfo;
  760. Value, DefValue: LongInt;
  761. Ident: String;
  762. IntToIdentFn: TIntToIdent;
  763. {$ifndef FPUNONE}
  764. FloatValue, DefFloatValue: Extended;
  765. {$endif}
  766. MethodValue: TMethod;
  767. DefMethodValue: TMethod;
  768. WStrValue, WDefStrValue: WideString;
  769. StrValue, DefStrValue: String;
  770. UStrValue, UDefStrValue: UnicodeString;
  771. AncestorObj: TObject;
  772. C,Component: TComponent;
  773. ObjValue: TObject;
  774. SavedAncestor: TPersistent;
  775. SavedPropPath, Name: String;
  776. Int64Value, DefInt64Value: Int64;
  777. VarValue, DefVarValue : tvardata;
  778. BoolValue, DefBoolValue: boolean;
  779. Handled: Boolean;
  780. IntfValue: IInterface;
  781. CompRef: IInterfaceComponentReference;
  782. begin
  783. // do not stream properties without getter
  784. if not Assigned(PPropInfo(PropInfo)^.GetProc) then
  785. exit;
  786. // properties without setter are only allowed, if they are subcomponents
  787. PropType := PPropInfo(PropInfo)^.PropType;
  788. if not Assigned(PPropInfo(PropInfo)^.SetProc) then begin
  789. if PropType^.Kind<>tkClass then
  790. exit;
  791. ObjValue := TObject(GetObjectProp(Instance, PropInfo));
  792. if not ObjValue.InheritsFrom(TComponent) or
  793. not (csSubComponent in TComponent(ObjValue).ComponentStyle) then
  794. exit;
  795. end;
  796. { Check if the ancestor can be used }
  797. HasAncestor := Assigned(Ancestor) and ((Instance = Root) or
  798. (Instance.ClassType = Ancestor.ClassType));
  799. //writeln('TWriter.WriteProperty Name=',PropType^.Name,' Kind=',GetEnumName(TypeInfo(TTypeKind),ord(PropType^.Kind)),' HasAncestor=',HasAncestor);
  800. case PropType^.Kind of
  801. tkInteger, tkChar, tkEnumeration, tkSet, tkWChar:
  802. begin
  803. Value := GetOrdProp(Instance, PropInfo);
  804. if HasAncestor then
  805. DefValue := GetOrdProp(Ancestor, PropInfo)
  806. else
  807. DefValue := PPropInfo(PropInfo)^.Default;
  808. // writeln(PPropInfo(PropInfo)^.Name, ', HasAncestor=', ord(HasAncestor), ', Value=', Value, ', Default=', DefValue);
  809. if (Value <> DefValue) or (DefValue=longint($80000000)) then
  810. begin
  811. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  812. case PropType^.Kind of
  813. tkInteger:
  814. begin
  815. // Check if this integer has a string identifier
  816. IntToIdentFn := FindIntToIdent(PPropInfo(PropInfo)^.PropType);
  817. if Assigned(IntToIdentFn) and IntToIdentFn(Value, Ident) then
  818. // Integer can be written a human-readable identifier
  819. WriteIdent(Ident)
  820. else
  821. // Integer has to be written just as number
  822. WriteInteger(Value);
  823. end;
  824. tkChar:
  825. WriteChar(Chr(Value));
  826. tkWChar:
  827. WriteWideChar(WideChar(Value));
  828. tkSet:
  829. Driver.WriteSet(Value, GetTypeData(PropType)^.CompType);
  830. tkEnumeration:
  831. WriteIdent(GetEnumName(PropType, Value));
  832. end;
  833. Driver.EndProperty;
  834. end;
  835. end;
  836. {$ifndef FPUNONE}
  837. tkFloat:
  838. begin
  839. FloatValue := GetFloatProp(Instance, PropInfo);
  840. if HasAncestor then
  841. DefFloatValue := GetFloatProp(Ancestor, PropInfo)
  842. else
  843. begin
  844. DefValue :=PPropInfo(PropInfo)^.Default;
  845. DefFloatValue:=PSingle(@PPropInfo(PropInfo)^.Default)^;
  846. end;
  847. if (FloatValue<>DefFloatValue) or (not HasAncestor and (DefValue=longint($80000000))) then
  848. begin
  849. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  850. WriteFloat(FloatValue);
  851. Driver.EndProperty;
  852. end;
  853. end;
  854. {$endif}
  855. tkMethod:
  856. begin
  857. MethodValue := GetMethodProp(Instance, PropInfo);
  858. if HasAncestor then
  859. DefMethodValue := GetMethodProp(Ancestor, PropInfo)
  860. else begin
  861. DefMethodValue.Data := nil;
  862. DefMethodValue.Code := nil;
  863. end;
  864. Handled:=false;
  865. if Assigned(OnWriteMethodProperty) then
  866. OnWriteMethodProperty(Self,Instance,PPropInfo(PropInfo),MethodValue,
  867. DefMethodValue,Handled);
  868. if (not Handled) and
  869. (MethodValue.Code <> DefMethodValue.Code) and
  870. ((not Assigned(MethodValue.Code)) or
  871. ((Length(FLookupRoot.MethodName(MethodValue.Code)) > 0))) then
  872. begin
  873. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  874. if Assigned(MethodValue.Code) then
  875. Driver.WriteMethodName(FLookupRoot.MethodName(MethodValue.Code))
  876. else
  877. Driver.WriteMethodName('');
  878. Driver.EndProperty;
  879. end;
  880. end;
  881. tkSString, tkLString, tkAString:
  882. begin
  883. StrValue := GetStrProp(Instance, PropInfo);
  884. if HasAncestor then
  885. DefStrValue := GetStrProp(Ancestor, PropInfo)
  886. else
  887. begin
  888. DefValue :=PPropInfo(PropInfo)^.Default;
  889. SetLength(DefStrValue, 0);
  890. end;
  891. if (StrValue<>DefStrValue) or (not HasAncestor and (DefValue=longint($80000000))) then
  892. begin
  893. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  894. if Assigned(FOnWriteStringProperty) then
  895. FOnWriteStringProperty(Self,Instance,PropInfo,StrValue);
  896. WriteString(StrValue);
  897. Driver.EndProperty;
  898. end;
  899. end;
  900. tkWString:
  901. begin
  902. WStrValue := GetWideStrProp(Instance, PropInfo);
  903. if HasAncestor then
  904. WDefStrValue := GetWideStrProp(Ancestor, PropInfo)
  905. else
  906. begin
  907. DefValue :=PPropInfo(PropInfo)^.Default;
  908. SetLength(WDefStrValue, 0);
  909. end;
  910. if (WStrValue<>WDefStrValue) or (not HasAncestor and (DefValue=longint($80000000))) then
  911. begin
  912. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  913. WriteWideString(WStrValue);
  914. Driver.EndProperty;
  915. end;
  916. end;
  917. tkUString:
  918. begin
  919. UStrValue := GetUnicodeStrProp(Instance, PropInfo);
  920. if HasAncestor then
  921. UDefStrValue := GetUnicodeStrProp(Ancestor, PropInfo)
  922. else
  923. begin
  924. DefValue :=PPropInfo(PropInfo)^.Default;
  925. SetLength(UDefStrValue, 0);
  926. end;
  927. if (UStrValue<>UDefStrValue) or (not HasAncestor and (DefValue=longint($80000000))) then
  928. begin
  929. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  930. WriteUnicodeString(UStrValue);
  931. Driver.EndProperty;
  932. end;
  933. end;
  934. tkVariant:
  935. begin
  936. { Ensure that a Variant manager is installed }
  937. if not assigned(VarClearProc) then
  938. raise EWriteError.Create(SErrNoVariantSupport);
  939. VarValue := tvardata(GetVariantProp(Instance, PropInfo));
  940. if HasAncestor then
  941. DefVarValue := tvardata(GetVariantProp(Ancestor, PropInfo))
  942. else
  943. FillChar(DefVarValue,sizeof(DefVarValue),0);
  944. if (CompareByte(VarValue,DefVarValue,sizeof(VarValue)) <> 0) then
  945. begin
  946. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  947. { can't use variant() typecast, pulls in variants unit }
  948. WriteVariant(pvariant(@VarValue)^);
  949. Driver.EndProperty;
  950. end;
  951. end;
  952. tkClass:
  953. begin
  954. ObjValue := TObject(GetObjectProp(Instance, PropInfo));
  955. if HasAncestor then
  956. begin
  957. AncestorObj := TObject(GetObjectProp(Ancestor, PropInfo));
  958. if (AncestorObj is TComponent) and
  959. (ObjValue is TComponent) then
  960. begin
  961. //writeln('TWriter.WriteProperty AncestorObj=',TComponent(AncestorObj).Name,' OwnerFit=',TComponent(AncestorObj).Owner = FRootAncestor,' ',TComponent(ObjValue).Name,' OwnerFit=',TComponent(ObjValue).Owner = Root);
  962. if (AncestorObj<> ObjValue) and
  963. (TComponent(AncestorObj).Owner = FRootAncestor) and
  964. (TComponent(ObjValue).Owner = Root) and
  965. (UpperCase(TComponent(AncestorObj).Name) = UpperCase(TComponent(ObjValue).Name)) then
  966. begin
  967. // different components, but with the same name
  968. // treat it like an override
  969. AncestorObj := ObjValue;
  970. end;
  971. end;
  972. end else
  973. AncestorObj := nil;
  974. if not Assigned(ObjValue) then
  975. begin
  976. if ObjValue <> AncestorObj then
  977. begin
  978. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  979. Driver.WriteIdent('NIL');
  980. Driver.EndProperty;
  981. end
  982. end
  983. else if ObjValue.InheritsFrom(TPersistent) then
  984. begin
  985. { Subcomponents are streamed the same way as persistents }
  986. if ObjValue.InheritsFrom(TComponent)
  987. and ((not (csSubComponent in TComponent(ObjValue).ComponentStyle))
  988. or ((TComponent(ObjValue).Owner<>Instance) and (TComponent(ObjValue).Owner<>Nil))) then
  989. begin
  990. Component := TComponent(ObjValue);
  991. if (ObjValue <> AncestorObj)
  992. and not (csTransient in Component.ComponentStyle) then
  993. begin
  994. Name:= '';
  995. C:= Component;
  996. While (C<>Nil) and (C.Name<>'') do
  997. begin
  998. If (Name<>'') Then
  999. Name:='.'+Name;
  1000. if C.Owner = LookupRoot then
  1001. begin
  1002. Name := C.Name+Name;
  1003. break;
  1004. end
  1005. else if C = LookupRoot then
  1006. begin
  1007. Name := 'Owner' + Name;
  1008. break;
  1009. end;
  1010. Name:=C.Name + Name;
  1011. C:= C.Owner;
  1012. end;
  1013. if (C=nil) and (Component.Owner=nil) then
  1014. if (Name<>'') then //foreign root
  1015. Name:=Name+'.Owner';
  1016. if Length(Name) > 0 then
  1017. begin
  1018. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  1019. WriteIdent(Name);
  1020. Driver.EndProperty;
  1021. end; // length Name>0
  1022. end; //(ObjValue <> AncestorObj)
  1023. end // ObjValue.InheritsFrom(TComponent)
  1024. else
  1025. begin
  1026. SavedAncestor := Ancestor;
  1027. SavedPropPath := FPropPath;
  1028. try
  1029. FPropPath := FPropPath + PPropInfo(PropInfo)^.Name + '.';
  1030. if HasAncestor then
  1031. Ancestor := TPersistent(GetObjectProp(Ancestor, PropInfo));
  1032. WriteProperties(TPersistent(ObjValue));
  1033. finally
  1034. Ancestor := SavedAncestor;
  1035. FPropPath := SavedPropPath;
  1036. end;
  1037. if ObjValue.InheritsFrom(TCollection) then
  1038. begin
  1039. if (not HasAncestor) or (not CollectionsEqual(TCollection(ObjValue),
  1040. TCollection(GetObjectProp(Ancestor, PropInfo)),root,rootancestor)) then
  1041. begin
  1042. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  1043. SavedPropPath := FPropPath;
  1044. try
  1045. SetLength(FPropPath, 0);
  1046. WriteCollection(TCollection(ObjValue));
  1047. finally
  1048. FPropPath := SavedPropPath;
  1049. Driver.EndProperty;
  1050. end;
  1051. end;
  1052. end // Tcollection
  1053. end;
  1054. end; // Inheritsfrom(TPersistent)
  1055. end;
  1056. tkInt64, tkQWord:
  1057. begin
  1058. Int64Value := GetInt64Prop(Instance, PropInfo);
  1059. if HasAncestor then
  1060. DefInt64Value := GetInt64Prop(Ancestor, PropInfo)
  1061. else
  1062. DefInt64Value := 0;
  1063. if Int64Value <> DefInt64Value then
  1064. begin
  1065. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  1066. WriteInteger(Int64Value);
  1067. Driver.EndProperty;
  1068. end;
  1069. end;
  1070. tkBool:
  1071. begin
  1072. BoolValue := GetOrdProp(Instance, PropInfo)<>0;
  1073. if HasAncestor then
  1074. DefBoolValue := GetOrdProp(Ancestor, PropInfo)<>0
  1075. else
  1076. begin
  1077. DefBoolValue := PPropInfo(PropInfo)^.Default<>0;
  1078. DefValue:=PPropInfo(PropInfo)^.Default;
  1079. end;
  1080. // writeln(PPropInfo(PropInfo)^.Name, ', HasAncestor=', ord(HasAncestor), ', Value=', Value, ', Default=', DefBoolValue);
  1081. if (BoolValue<>DefBoolValue) or (DefValue=longint($80000000)) then
  1082. begin
  1083. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  1084. WriteBoolean(BoolValue);
  1085. Driver.EndProperty;
  1086. end;
  1087. end;
  1088. tkInterface:
  1089. begin
  1090. IntfValue := GetInterfaceProp(Instance, PropInfo);
  1091. if Assigned(IntfValue) and Supports(IntfValue, IInterfaceComponentReference, CompRef) then
  1092. begin
  1093. Component := CompRef.GetComponent;
  1094. if HasAncestor then
  1095. begin
  1096. AncestorObj := TObject(GetObjectProp(Ancestor, PropInfo));
  1097. if (AncestorObj is TComponent) then
  1098. begin
  1099. //writeln('TWriter.WriteProperty AncestorObj=',TComponent(AncestorObj).Name,' OwnerFit=',TComponent(AncestorObj).Owner = FRootAncestor,' ',TComponent(ObjValue).Name,' OwnerFit=',TComponent(ObjValue).Owner = Root);
  1100. if (AncestorObj<> Component) and
  1101. (TComponent(AncestorObj).Owner = FRootAncestor) and
  1102. (Component.Owner = Root) and
  1103. (UpperCase(TComponent(AncestorObj).Name) = UpperCase(Component.Name)) then
  1104. begin
  1105. // different components, but with the same name
  1106. // treat it like an override
  1107. AncestorObj := Component;
  1108. end;
  1109. end;
  1110. end else
  1111. AncestorObj := nil;
  1112. if not Assigned(Component) then
  1113. begin
  1114. if Component <> AncestorObj then
  1115. begin
  1116. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  1117. Driver.WriteIdent('NIL');
  1118. Driver.EndProperty;
  1119. end
  1120. end
  1121. else if ((not (csSubComponent in Component.ComponentStyle))
  1122. or ((Component.Owner<>Instance) and (Component.Owner<>Nil))) then
  1123. begin
  1124. if (Component <> AncestorObj)
  1125. and not (csTransient in Component.ComponentStyle) then
  1126. begin
  1127. Name:= '';
  1128. C:= Component;
  1129. While (C<>Nil) and (C.Name<>'') do
  1130. begin
  1131. If (Name<>'') Then
  1132. Name:='.'+Name;
  1133. if C.Owner = LookupRoot then
  1134. begin
  1135. Name := C.Name+Name;
  1136. break;
  1137. end
  1138. else if C = LookupRoot then
  1139. begin
  1140. Name := 'Owner' + Name;
  1141. break;
  1142. end;
  1143. Name:=C.Name + Name;
  1144. C:= C.Owner;
  1145. end;
  1146. if (C=nil) and (Component.Owner=nil) then
  1147. if (Name<>'') then //foreign root
  1148. Name:=Name+'.Owner';
  1149. if Length(Name) > 0 then
  1150. begin
  1151. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  1152. WriteIdent(Name);
  1153. Driver.EndProperty;
  1154. end; // length Name>0
  1155. end; //(Component <> AncestorObj)
  1156. end;
  1157. end; //Assigned(IntfValue) and Supports(IntfValue,..
  1158. //else write NIL ?
  1159. end;
  1160. end;
  1161. end;
  1162. procedure TWriter.WriteRootComponent(ARoot: TComponent);
  1163. begin
  1164. WriteDescendent(ARoot, nil);
  1165. end;
  1166. procedure TWriter.WriteString(const Value: String);
  1167. begin
  1168. Driver.WriteString(Value);
  1169. end;
  1170. procedure TWriter.WriteWideString(const Value: WideString);
  1171. begin
  1172. Driver.WriteWideString(Value);
  1173. end;
  1174. procedure TWriter.WriteUnicodeString(const Value: UnicodeString);
  1175. begin
  1176. Driver.WriteUnicodeString(Value);
  1177. end;