writer.inc 26 KB

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