writer.inc 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059
  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.BeginComponent(Component: TComponent;
  106. Flags: TFilerFlags; ChildPos: Integer);
  107. var
  108. Prefix: Byte;
  109. begin
  110. if not FSignatureWritten then
  111. begin
  112. Write(FilerSignature, SizeOf(FilerSignature));
  113. FSignatureWritten := True;
  114. end;
  115. { Only write the flags if they are needed! }
  116. if Flags <> [] then
  117. begin
  118. Prefix := Integer(Flags) or $f0;
  119. Write(Prefix, 1);
  120. if ffChildPos in Flags then
  121. WriteInteger(ChildPos);
  122. end;
  123. WriteStr(Component.ClassName);
  124. WriteStr(Component.Name);
  125. end;
  126. procedure TBinaryObjectWriter.BeginList;
  127. begin
  128. WriteValue(vaList);
  129. end;
  130. procedure TBinaryObjectWriter.EndList;
  131. begin
  132. WriteValue(vaNull);
  133. end;
  134. procedure TBinaryObjectWriter.BeginProperty(const PropName: String);
  135. begin
  136. WriteStr(PropName);
  137. end;
  138. procedure TBinaryObjectWriter.EndProperty;
  139. begin
  140. end;
  141. procedure TBinaryObjectWriter.WriteBinary(const Buffer; Count: LongInt);
  142. begin
  143. WriteValue(vaBinary);
  144. WriteDWord(longword(Count));
  145. Write(Buffer, Count);
  146. end;
  147. procedure TBinaryObjectWriter.WriteBoolean(Value: Boolean);
  148. begin
  149. if Value then
  150. WriteValue(vaTrue)
  151. else
  152. WriteValue(vaFalse);
  153. end;
  154. {$ifndef FPUNONE}
  155. procedure TBinaryObjectWriter.WriteFloat(const Value: Extended);
  156. begin
  157. WriteValue(vaExtended);
  158. WriteExtended(Value);
  159. end;
  160. procedure TBinaryObjectWriter.WriteSingle(const Value: Single);
  161. begin
  162. WriteValue(vaSingle);
  163. WriteDWord(longword(Value));
  164. end;
  165. {$endif}
  166. procedure TBinaryObjectWriter.WriteCurrency(const Value: Currency);
  167. begin
  168. WriteValue(vaCurrency);
  169. WriteQWord(qword(Value));
  170. end;
  171. {$ifndef FPUNONE}
  172. procedure TBinaryObjectWriter.WriteDate(const Value: TDateTime);
  173. begin
  174. WriteValue(vaDate);
  175. WriteQWord(qword(Value));
  176. end;
  177. {$endif}
  178. procedure TBinaryObjectWriter.WriteIdent(const Ident: string);
  179. begin
  180. { Check if Ident is a special identifier before trying to just write
  181. Ident directly }
  182. if UpperCase(Ident) = 'NIL' then
  183. WriteValue(vaNil)
  184. else if UpperCase(Ident) = 'FALSE' then
  185. WriteValue(vaFalse)
  186. else if UpperCase(Ident) = 'TRUE' then
  187. WriteValue(vaTrue)
  188. else if UpperCase(Ident) = 'NULL' then
  189. WriteValue(vaNull) else
  190. begin
  191. WriteValue(vaIdent);
  192. WriteStr(Ident);
  193. end;
  194. end;
  195. procedure TBinaryObjectWriter.WriteInteger(Value: Int64);
  196. var
  197. s: ShortInt;
  198. i: SmallInt;
  199. l: Longint;
  200. begin
  201. { Use the smallest possible integer type for the given value: }
  202. if (Value >= -128) and (Value <= 127) then
  203. begin
  204. WriteValue(vaInt8);
  205. s := Value;
  206. Write(s, 1);
  207. end else if (Value >= -32768) and (Value <= 32767) then
  208. begin
  209. WriteValue(vaInt16);
  210. i := Value;
  211. WriteWord(word(i));
  212. end else if (Value >= -$80000000) and (Value <= $7fffffff) then
  213. begin
  214. WriteValue(vaInt32);
  215. l := Value;
  216. WriteDWord(longword(l));
  217. end else
  218. begin
  219. WriteValue(vaInt64);
  220. WriteQWord(qword(Value));
  221. end;
  222. end;
  223. procedure TBinaryObjectWriter.WriteMethodName(const Name: String);
  224. begin
  225. if Length(Name) > 0 then
  226. begin
  227. WriteValue(vaIdent);
  228. WriteStr(Name);
  229. end else
  230. WriteValue(vaNil);
  231. end;
  232. procedure TBinaryObjectWriter.WriteSet(Value: LongInt; SetType: Pointer);
  233. type
  234. tset = set of 0..31;
  235. var
  236. i: Integer;
  237. begin
  238. WriteValue(vaSet);
  239. for i := 0 to 31 do
  240. begin
  241. if (i in tset(Value)) then
  242. WriteStr(GetEnumName(PTypeInfo(SetType), i));
  243. end;
  244. WriteStr('');
  245. end;
  246. procedure TBinaryObjectWriter.WriteString(const Value: String);
  247. var
  248. i: Integer;
  249. b: byte;
  250. begin
  251. i := Length(Value);
  252. if i <= 255 then
  253. begin
  254. WriteValue(vaString);
  255. b := i;
  256. Write(b, 1);
  257. end else
  258. begin
  259. WriteValue(vaLString);
  260. WriteDWord(longword(i));
  261. end;
  262. if i > 0 then
  263. Write(Value[1], i);
  264. end;
  265. procedure TBinaryObjectWriter.WriteWideString(const Value: WideString);
  266. var len : longword;
  267. {$IFDEF ENDIAN_BIG}
  268. i : integer;
  269. ws : widestring;
  270. {$ENDIF}
  271. begin
  272. WriteValue(vaWString);
  273. len:=Length(Value);
  274. WriteDWord(len);
  275. if len > 0 then
  276. begin
  277. {$IFDEF ENDIAN_BIG}
  278. setlength(ws,len);
  279. for i:=1 to len do
  280. ws[i]:=widechar(SwapEndian(word(Value[i])));
  281. Write(ws[1], len*sizeof(widechar));
  282. {$ELSE}
  283. Write(Value[1], len*sizeof(widechar));
  284. {$ENDIF}
  285. end;
  286. end;
  287. procedure TBinaryObjectWriter.WriteUnicodeString(const Value: UnicodeString);
  288. var len : longword;
  289. {$IFDEF ENDIAN_BIG}
  290. i : integer;
  291. us : UnicodeString;
  292. {$ENDIF}
  293. begin
  294. WriteValue(vaUString);
  295. len:=Length(Value);
  296. WriteDWord(len);
  297. if len > 0 then
  298. begin
  299. {$IFDEF ENDIAN_BIG}
  300. setlength(us,len);
  301. for i:=1 to len do
  302. us[i]:=widechar(SwapEndian(word(Value[i])));
  303. Write(us[1], len*sizeof(UnicodeChar));
  304. {$ELSE}
  305. Write(Value[1], len*sizeof(UnicodeChar));
  306. {$ENDIF}
  307. end;
  308. end;
  309. procedure TBinaryObjectWriter.FlushBuffer;
  310. begin
  311. FStream.WriteBuffer(FBuffer^, FBufPos);
  312. FBufPos := 0;
  313. end;
  314. procedure TBinaryObjectWriter.Write(const Buffer; Count: LongInt);
  315. var
  316. CopyNow: LongInt;
  317. SourceBuf: PChar;
  318. begin
  319. SourceBuf:=@Buffer;
  320. while Count > 0 do
  321. begin
  322. CopyNow := Count;
  323. if CopyNow > FBufSize - FBufPos then
  324. CopyNow := FBufSize - FBufPos;
  325. Move(SourceBuf^, PChar(FBuffer)[FBufPos], CopyNow);
  326. Dec(Count, CopyNow);
  327. Inc(FBufPos, CopyNow);
  328. inc(SourceBuf, CopyNow);
  329. if FBufPos = FBufSize then
  330. FlushBuffer;
  331. end;
  332. end;
  333. procedure TBinaryObjectWriter.WriteValue(Value: TValueType);
  334. var
  335. b: byte;
  336. begin
  337. b := byte(Value);
  338. Write(b, 1);
  339. end;
  340. procedure TBinaryObjectWriter.WriteStr(const Value: String);
  341. var
  342. i: integer;
  343. b: byte;
  344. begin
  345. i := Length(Value);
  346. if i > 255 then
  347. i := 255;
  348. b := i;
  349. Write(b, 1);
  350. if i > 0 then
  351. Write(Value[1], i);
  352. end;
  353. {****************************************************************************}
  354. {* TWriter *}
  355. {****************************************************************************}
  356. constructor TWriter.Create(ADriver: TAbstractObjectWriter);
  357. begin
  358. inherited Create;
  359. FDriver := ADriver;
  360. end;
  361. constructor TWriter.Create(Stream: TStream; BufSize: Integer);
  362. begin
  363. inherited Create;
  364. If (Stream=Nil) then
  365. Raise EWriteError.Create(SEmptyStreamIllegalWriter);
  366. FDriver := CreateDriver(Stream, BufSize);
  367. FDestroyDriver := True;
  368. end;
  369. destructor TWriter.Destroy;
  370. begin
  371. if FDestroyDriver then
  372. FDriver.Free;
  373. inherited Destroy;
  374. end;
  375. function TWriter.CreateDriver(Stream: TStream; BufSize: Integer): TAbstractObjectWriter;
  376. begin
  377. Result := TBinaryObjectWriter.Create(Stream, BufSize);
  378. end;
  379. Type
  380. TPosComponent = Class(TObject)
  381. FPos : Integer;
  382. FComponent : TComponent;
  383. Constructor Create(APos : Integer; AComponent : TComponent);
  384. end;
  385. Constructor TPosComponent.Create(APos : Integer; AComponent : TComponent);
  386. begin
  387. FPos:=APos;
  388. FComponent:=AComponent;
  389. end;
  390. // Used as argument for calls to TComponent.GetChildren:
  391. procedure TWriter.AddToAncestorList(Component: TComponent);
  392. begin
  393. FAncestors.AddObject(Component.Name,TPosComponent.Create(FAncestors.Count,Component));
  394. end;
  395. procedure TWriter.DefineProperty(const Name: String;
  396. ReadData: TReaderProc; AWriteData: TWriterProc; HasData: Boolean);
  397. begin
  398. if HasData and Assigned(AWriteData) then
  399. begin
  400. // Write the property name and then the data itself
  401. Driver.BeginProperty(FPropPath + Name);
  402. AWriteData(Self);
  403. Driver.EndProperty;
  404. end;
  405. end;
  406. procedure TWriter.DefineBinaryProperty(const Name: String;
  407. ReadData, AWriteData: TStreamProc; HasData: Boolean);
  408. begin
  409. if HasData and Assigned(AWriteData) then
  410. begin
  411. // Write the property name and then the data itself
  412. Driver.BeginProperty(FPropPath + Name);
  413. WriteBinary(AWriteData);
  414. Driver.EndProperty;
  415. end;
  416. end;
  417. procedure TWriter.Write(const Buffer; Count: Longint);
  418. begin
  419. //This should give an exception if write is not implemented (i.e. TTextObjectWriter)
  420. //but should work with TBinaryObjectWriter.
  421. Driver.Write(Buffer, Count);
  422. end;
  423. procedure TWriter.SetRoot(ARoot: TComponent);
  424. begin
  425. inherited SetRoot(ARoot);
  426. // Use the new root as lookup root too
  427. FLookupRoot := ARoot;
  428. end;
  429. procedure TWriter.WriteBinary(AWriteData: TStreamProc);
  430. var
  431. MemBuffer: TMemoryStream;
  432. BufferSize: Longint;
  433. begin
  434. { First write the binary data into a memory stream, then copy this buffered
  435. stream into the writing destination. This is necessary as we have to know
  436. the size of the binary data in advance (we're assuming that seeking within
  437. the writer stream is not possible) }
  438. MemBuffer := TMemoryStream.Create;
  439. try
  440. AWriteData(MemBuffer);
  441. BufferSize := MemBuffer.Size;
  442. Driver.WriteBinary(MemBuffer.Memory^, BufferSize);
  443. finally
  444. MemBuffer.Free;
  445. end;
  446. end;
  447. procedure TWriter.WriteBoolean(Value: Boolean);
  448. begin
  449. Driver.WriteBoolean(Value);
  450. end;
  451. procedure TWriter.WriteChar(Value: Char);
  452. begin
  453. WriteString(Value);
  454. end;
  455. procedure TWriter.WriteWideChar(Value: WideChar);
  456. begin
  457. WriteWideString(Value);
  458. end;
  459. procedure TWriter.WriteCollection(Value: TCollection);
  460. var
  461. i: Integer;
  462. begin
  463. Driver.BeginCollection;
  464. if Assigned(Value) then
  465. for i := 0 to Value.Count - 1 do
  466. begin
  467. { Each collection item needs its own ListBegin/ListEnd tag, or else the
  468. reader wouldn't be able to know where an item ends and where the next
  469. one starts }
  470. WriteListBegin;
  471. WriteProperties(Value.Items[i]);
  472. WriteListEnd;
  473. end;
  474. WriteListEnd;
  475. end;
  476. procedure TWriter.DetermineAncestor(Component : TComponent);
  477. Var
  478. I : Integer;
  479. begin
  480. // Should be set only when we write an inherited with children.
  481. if Not Assigned(FAncestors) then
  482. exit;
  483. I:=FAncestors.IndexOf(Component.Name);
  484. If (I=-1) then
  485. begin
  486. FAncestor:=Nil;
  487. FAncestorPos:=-1;
  488. end
  489. else
  490. With TPosComponent(FAncestors.Objects[i]) do
  491. begin
  492. FAncestor:=FComponent;
  493. FAncestorPos:=FPos;
  494. end;
  495. end;
  496. procedure TWriter.DoFindAncestor(Component : TComponent);
  497. Var
  498. C : TComponent;
  499. begin
  500. if Assigned(FOnFindAncestor) then
  501. if (Ancestor=Nil) or (Ancestor is TComponent) then
  502. begin
  503. C:=TComponent(Ancestor);
  504. FOnFindAncestor(Self,Component,Component.Name,C,FRootAncestor);
  505. Ancestor:=C;
  506. end;
  507. end;
  508. procedure TWriter.WriteComponent(Component: TComponent);
  509. var
  510. SA : TPersistent;
  511. SR : TComponent;
  512. begin
  513. SR:=FRoot;
  514. SA:=FAncestor;
  515. Try
  516. Component.FComponentState:=Component.FComponentState+[csWriting];
  517. Try
  518. // Possibly set ancestor.
  519. DetermineAncestor(Component);
  520. DoFindAncestor(Component); // Mainly for IDE when a parent form had an ancestor renamed...
  521. // Will call WriteComponentData.
  522. Component.WriteState(Self);
  523. FDriver.EndList;
  524. Finally
  525. Component.FComponentState:=Component.FComponentState-[csWriting];
  526. end;
  527. Finally
  528. FAncestor:=SA;
  529. FRoot:=SR;
  530. end;
  531. end;
  532. procedure TWriter.WriteChildren(Component : TComponent);
  533. Var
  534. SRoot, SRootA : TComponent;
  535. SList : TStringList;
  536. SPos : Integer;
  537. I : Integer;
  538. begin
  539. // Write children list.
  540. // While writing children, the ancestor environment must be saved
  541. // This is recursive...
  542. SRoot:=FRoot;
  543. SRootA:=FRootAncestor;
  544. SList:=FAncestors;
  545. SPos:=FCurrentPos;
  546. try
  547. FAncestors:=Nil;
  548. FCurrentPos:=0;
  549. FAncestorPos:=-1;
  550. if csInline in Component.ComponentState then
  551. FRoot:=Component;
  552. if (FAncestor is TComponent) then
  553. begin
  554. FAncestors:=TStringList.Create;
  555. if csInline in TComponent(FAncestor).ComponentState then
  556. FRootAncestor := TComponent(FAncestor);
  557. TComponent(FAncestor).GetChildren(@AddToAncestorList,FRootAncestor);
  558. FAncestors.Sorted:=True;
  559. end;
  560. try
  561. Component.GetChildren(@WriteComponent, FRoot);
  562. Finally
  563. If Assigned(Fancestors) then
  564. For I:=0 to FAncestors.Count-1 do
  565. FAncestors.Objects[i].Free;
  566. FreeAndNil(FAncestors);
  567. end;
  568. finally
  569. FAncestors:=Slist;
  570. FRoot:=SRoot;
  571. FRootAncestor:=SRootA;
  572. FCurrentPos:=SPos;
  573. FAncestorPos:=Spos;
  574. end;
  575. end;
  576. procedure TWriter.WriteComponentData(Instance: TComponent);
  577. var
  578. Flags: TFilerFlags;
  579. begin
  580. Flags := [];
  581. If (Assigned(FAncestor)) and //has ancestor
  582. (not (csInline in Instance.ComponentState) or // no inline component
  583. // .. or the inline component is inherited
  584. (csAncestor in Instance.Componentstate) and (FAncestors <> nil)) then
  585. Flags:=[ffInherited]
  586. else If csInline in Instance.ComponentState then
  587. Flags:=[ffInline];
  588. If (FAncestors<>Nil) and ((FCurrentPos<>FAncestorPos) or (FAncestor=Nil)) then
  589. Include(Flags,ffChildPos);
  590. FDriver.BeginComponent(Instance,Flags,FCurrentPos);
  591. If (FAncestors<>Nil) then
  592. Inc(FCurrentPos);
  593. WriteProperties(Instance);
  594. WriteListEnd;
  595. // Needs special handling of ancestor.
  596. If not IgnoreChildren then
  597. WriteChildren(Instance);
  598. end;
  599. procedure TWriter.WriteDescendent(ARoot: TComponent; AAncestor: TComponent);
  600. begin
  601. FRoot := ARoot;
  602. FAncestor := AAncestor;
  603. FRootAncestor := AAncestor;
  604. FLookupRoot := ARoot;
  605. WriteComponent(ARoot);
  606. end;
  607. {$ifndef FPUNONE}
  608. procedure TWriter.WriteFloat(const Value: Extended);
  609. begin
  610. Driver.WriteFloat(Value);
  611. end;
  612. procedure TWriter.WriteSingle(const Value: Single);
  613. begin
  614. Driver.WriteSingle(Value);
  615. end;
  616. {$endif}
  617. procedure TWriter.WriteCurrency(const Value: Currency);
  618. begin
  619. Driver.WriteCurrency(Value);
  620. end;
  621. {$ifndef FPUNONE}
  622. procedure TWriter.WriteDate(const Value: TDateTime);
  623. begin
  624. Driver.WriteDate(Value);
  625. end;
  626. {$endif}
  627. procedure TWriter.WriteIdent(const Ident: string);
  628. begin
  629. Driver.WriteIdent(Ident);
  630. end;
  631. procedure TWriter.WriteInteger(Value: LongInt);
  632. begin
  633. Driver.WriteInteger(Value);
  634. end;
  635. procedure TWriter.WriteInteger(Value: Int64);
  636. begin
  637. Driver.WriteInteger(Value);
  638. end;
  639. procedure TWriter.WriteListBegin;
  640. begin
  641. Driver.BeginList;
  642. end;
  643. procedure TWriter.WriteListEnd;
  644. begin
  645. Driver.EndList;
  646. end;
  647. procedure TWriter.WriteProperties(Instance: TPersistent);
  648. var PropCount,i : integer;
  649. PropList : PPropList;
  650. begin
  651. PropCount:=GetPropList(Instance,PropList);
  652. if PropCount>0 then
  653. try
  654. for i := 0 to PropCount-1 do
  655. if IsStoredProp(Instance,PropList^[i]) then
  656. WriteProperty(Instance,PropList^[i]);
  657. Finally
  658. Freemem(PropList);
  659. end;
  660. Instance.DefineProperties(Self);
  661. end;
  662. procedure TWriter.WriteProperty(Instance: TPersistent; PropInfo: Pointer);
  663. var
  664. HasAncestor: Boolean;
  665. PropType: PTypeInfo;
  666. Value, DefValue: LongInt;
  667. Ident: String;
  668. IntToIdentFn: TIntToIdent;
  669. {$ifndef FPUNONE}
  670. FloatValue, DefFloatValue: Extended;
  671. {$endif}
  672. MethodValue: TMethod;
  673. DefMethodValue: TMethod;
  674. WStrValue, WDefStrValue: WideString;
  675. StrValue, DefStrValue: String;
  676. UStrValue, UDefStrValue: UnicodeString;
  677. AncestorObj: TObject;
  678. Component: TComponent;
  679. ObjValue: TObject;
  680. SavedAncestor: TPersistent;
  681. SavedPropPath, Name: String;
  682. Int64Value, DefInt64Value: Int64;
  683. BoolValue, DefBoolValue: boolean;
  684. Handled: Boolean;
  685. begin
  686. // do not stream properties without getter
  687. if not Assigned(PPropInfo(PropInfo)^.GetProc) then
  688. exit;
  689. // properties without setter are only allowed, if they are subcomponents
  690. PropType := PPropInfo(PropInfo)^.PropType;
  691. if not Assigned(PPropInfo(PropInfo)^.SetProc) then begin
  692. if PropType^.Kind<>tkClass then
  693. exit;
  694. ObjValue := TObject(GetObjectProp(Instance, PropInfo));
  695. if not ObjValue.InheritsFrom(TComponent) or
  696. not (csSubComponent in TComponent(ObjValue).ComponentStyle) then
  697. exit;
  698. end;
  699. { Check if the ancestor can be used }
  700. HasAncestor := Assigned(Ancestor) and ((Instance = Root) or
  701. (Instance.ClassType = Ancestor.ClassType));
  702. case PropType^.Kind of
  703. tkInteger, tkChar, tkEnumeration, tkSet, tkWChar:
  704. begin
  705. Value := GetOrdProp(Instance, PropInfo);
  706. if HasAncestor then
  707. DefValue := GetOrdProp(Ancestor, PropInfo)
  708. else
  709. DefValue := PPropInfo(PropInfo)^.Default;
  710. //writeln(PPropInfo(PropInfo)^.Name, ', HasAncestor=', ord(HasAncestor), ', Value=', Value, ', Default=', DefValue);
  711. if (Value <> DefValue) or (DefValue=longint($80000000)) then
  712. begin
  713. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  714. case PropType^.Kind of
  715. tkInteger:
  716. begin
  717. // Check if this integer has a string identifier
  718. IntToIdentFn := FindIntToIdent(PPropInfo(PropInfo)^.PropType);
  719. if Assigned(IntToIdentFn) and IntToIdentFn(Value, Ident) then
  720. // Integer can be written a human-readable identifier
  721. WriteIdent(Ident)
  722. else
  723. // Integer has to be written just as number
  724. WriteInteger(Value);
  725. end;
  726. tkChar:
  727. WriteChar(Chr(Value));
  728. tkWChar:
  729. WriteWideChar(WideChar(Value));
  730. tkSet:
  731. Driver.WriteSet(Value, GetTypeData(PropType)^.CompType);
  732. tkEnumeration:
  733. WriteIdent(GetEnumName(PropType, Value));
  734. end;
  735. Driver.EndProperty;
  736. end;
  737. end;
  738. {$ifndef FPUNONE}
  739. tkFloat:
  740. begin
  741. FloatValue := GetFloatProp(Instance, PropInfo);
  742. if HasAncestor then
  743. DefFloatValue := GetFloatProp(Ancestor, PropInfo)
  744. else
  745. DefFloatValue := PPropInfo(PropInfo)^.Default;
  746. if (FloatValue<>DefFloatValue) or (DefValue=longint($80000000)) then
  747. begin
  748. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  749. WriteFloat(FloatValue);
  750. Driver.EndProperty;
  751. end;
  752. end;
  753. {$endif}
  754. tkMethod:
  755. begin
  756. MethodValue := GetMethodProp(Instance, PropInfo);
  757. if HasAncestor then
  758. DefMethodValue := GetMethodProp(Ancestor, PropInfo)
  759. else begin
  760. DefMethodValue.Data := nil;
  761. DefMethodValue.Code := nil;
  762. end;
  763. Handled:=false;
  764. if Assigned(OnWriteMethodProperty) then
  765. OnWriteMethodProperty(Self,Instance,PPropInfo(PropInfo),MethodValue,
  766. DefMethodValue,Handled);
  767. if (not Handled) and
  768. (MethodValue.Code <> DefMethodValue.Code) and
  769. ((not Assigned(MethodValue.Code)) or
  770. ((Length(FLookupRoot.MethodName(MethodValue.Code)) >= 0))) then
  771. begin
  772. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  773. if Assigned(MethodValue.Code) then
  774. Driver.WriteMethodName(FLookupRoot.MethodName(MethodValue.Code))
  775. else
  776. Driver.WriteMethodName('');
  777. Driver.EndProperty;
  778. end;
  779. end;
  780. tkSString, tkLString, tkAString:
  781. begin
  782. StrValue := GetStrProp(Instance, PropInfo);
  783. if HasAncestor then
  784. DefStrValue := GetStrProp(Ancestor, PropInfo)
  785. else
  786. SetLength(DefStrValue, 0);
  787. if StrValue <> DefStrValue then
  788. begin
  789. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  790. if Assigned(FOnWriteStringProperty) then
  791. FOnWriteStringProperty(Self,Instance,PropInfo,StrValue);
  792. WriteString(StrValue);
  793. Driver.EndProperty;
  794. end;
  795. end;
  796. tkWString:
  797. begin
  798. WStrValue := GetWideStrProp(Instance, PropInfo);
  799. if HasAncestor then
  800. WDefStrValue := GetWideStrProp(Ancestor, PropInfo)
  801. else
  802. SetLength(WDefStrValue, 0);
  803. if WStrValue <> WDefStrValue then
  804. begin
  805. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  806. WriteWideString(WStrValue);
  807. Driver.EndProperty;
  808. end;
  809. end;
  810. tkUString:
  811. begin
  812. UStrValue := GetUnicodeStrProp(Instance, PropInfo);
  813. if HasAncestor then
  814. UDefStrValue := GetUnicodeStrProp(Ancestor, PropInfo)
  815. else
  816. SetLength(UDefStrValue, 0);
  817. if UStrValue <> UDefStrValue then
  818. begin
  819. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  820. WriteUnicodeString(UStrValue);
  821. Driver.EndProperty;
  822. end;
  823. end;
  824. {!!!: tkVariant:}
  825. tkClass:
  826. begin
  827. ObjValue := TObject(GetObjectProp(Instance, PropInfo));
  828. if HasAncestor then
  829. begin
  830. AncestorObj := TObject(GetObjectProp(Ancestor, PropInfo));
  831. if Assigned(AncestorObj) then
  832. if Assigned(ObjValue) and
  833. (TComponent(AncestorObj).Owner = FRootAncestor) and
  834. (TComponent(ObjValue).Owner = Root) and
  835. (UpperCase(TComponent(AncestorObj).Name) = UpperCase(TComponent(ObjValue).Name)) then
  836. AncestorObj := ObjValue
  837. // else
  838. // AncestorObj := nil;
  839. end else
  840. AncestorObj := nil;
  841. if not Assigned(ObjValue) then
  842. begin
  843. if ObjValue <> AncestorObj then
  844. begin
  845. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  846. Driver.WriteIdent('NIL');
  847. Driver.EndProperty;
  848. end
  849. end
  850. else if ObjValue.InheritsFrom(TPersistent) then
  851. begin
  852. { Subcomponents are streamed the same way as persistents }
  853. if ObjValue.InheritsFrom(TComponent)
  854. and ((not (csSubComponent in TComponent(ObjValue).ComponentStyle))
  855. or ((TComponent(ObjValue).Owner<>Instance) and (TComponent(ObjValue).Owner<>Nil))) then
  856. begin
  857. Component := TComponent(ObjValue);
  858. if (ObjValue <> AncestorObj)
  859. and not (csTransient in Component.ComponentStyle) then
  860. begin
  861. { Determine the correct name of the component this property contains }
  862. if Component.Owner = LookupRoot then
  863. Name := Component.Name
  864. else if Component = LookupRoot then
  865. Name := 'Owner'
  866. else if Assigned(Component.Owner) and (Length(Component.Owner.Name) > 0)
  867. and (Length(Component.Name) > 0) then
  868. Name := Component.Owner.Name + '.' + Component.Name
  869. else if Length(Component.Name) > 0 then
  870. Name := Component.Name + '.Owner'
  871. else
  872. SetLength(Name, 0);
  873. if Length(Name) > 0 then
  874. begin
  875. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  876. WriteIdent(Name);
  877. Driver.EndProperty;
  878. end; // length Name>0
  879. end; //(ObjValue <> AncestorObj)
  880. end // ObjValue.InheritsFrom(TComponent)
  881. else if ObjValue.InheritsFrom(TCollection) then
  882. begin
  883. if (not HasAncestor) or (not CollectionsEqual(TCollection(ObjValue),
  884. TCollection(GetObjectProp(Ancestor, PropInfo)),root,rootancestor)) then
  885. begin
  886. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  887. SavedPropPath := FPropPath;
  888. try
  889. SetLength(FPropPath, 0);
  890. WriteCollection(TCollection(ObjValue));
  891. finally
  892. FPropPath := SavedPropPath;
  893. Driver.EndProperty;
  894. end;
  895. end;
  896. end // Tcollection
  897. else
  898. begin
  899. SavedAncestor := Ancestor;
  900. SavedPropPath := FPropPath;
  901. try
  902. FPropPath := FPropPath + PPropInfo(PropInfo)^.Name + '.';
  903. if HasAncestor then
  904. Ancestor := TPersistent(GetObjectProp(Ancestor, PropInfo));
  905. WriteProperties(TPersistent(ObjValue));
  906. finally
  907. Ancestor := SavedAncestor;
  908. FPropPath := SavedPropPath;
  909. end;
  910. end;
  911. end; // Inheritsfrom(TPersistent)
  912. end;
  913. tkInt64, tkQWord:
  914. begin
  915. Int64Value := GetInt64Prop(Instance, PropInfo);
  916. if HasAncestor then
  917. DefInt64Value := GetInt64Prop(Ancestor, PropInfo)
  918. else
  919. DefInt64Value := 0;
  920. if Int64Value <> DefInt64Value then
  921. begin
  922. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  923. WriteInteger(Int64Value);
  924. Driver.EndProperty;
  925. end;
  926. end;
  927. tkBool:
  928. begin
  929. BoolValue := GetOrdProp(Instance, PropInfo)<>0;
  930. if HasAncestor then
  931. DefBoolValue := GetOrdProp(Ancestor, PropInfo)<>0
  932. else
  933. DefBoolValue := PPropInfo(PropInfo)^.Default<>0;
  934. if BoolValue <> DefBoolValue then
  935. begin
  936. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  937. WriteBoolean(BoolValue);
  938. Driver.EndProperty;
  939. end;
  940. end;
  941. end;
  942. end;
  943. procedure TWriter.WriteRootComponent(ARoot: TComponent);
  944. begin
  945. WriteDescendent(ARoot, nil);
  946. end;
  947. procedure TWriter.WriteString(const Value: String);
  948. begin
  949. Driver.WriteString(Value);
  950. end;
  951. procedure TWriter.WriteWideString(const Value: WideString);
  952. begin
  953. Driver.WriteWideString(Value);
  954. end;
  955. procedure TWriter.WriteUnicodeString(const Value: UnicodeString);
  956. begin
  957. Driver.WriteUnicodeString(Value);
  958. end;