writer.inc 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015
  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.FlushBuffer;
  288. begin
  289. FStream.WriteBuffer(FBuffer^, FBufPos);
  290. FBufPos := 0;
  291. end;
  292. procedure TBinaryObjectWriter.Write(const Buffer; Count: LongInt);
  293. var
  294. CopyNow: LongInt;
  295. SourceBuf: PChar;
  296. begin
  297. SourceBuf:=@Buffer;
  298. while Count > 0 do
  299. begin
  300. CopyNow := Count;
  301. if CopyNow > FBufSize - FBufPos then
  302. CopyNow := FBufSize - FBufPos;
  303. Move(SourceBuf^, PChar(FBuffer)[FBufPos], CopyNow);
  304. Dec(Count, CopyNow);
  305. Inc(FBufPos, CopyNow);
  306. inc(SourceBuf, CopyNow);
  307. if FBufPos = FBufSize then
  308. FlushBuffer;
  309. end;
  310. end;
  311. procedure TBinaryObjectWriter.WriteValue(Value: TValueType);
  312. var
  313. b: byte;
  314. begin
  315. b := byte(Value);
  316. Write(b, 1);
  317. end;
  318. procedure TBinaryObjectWriter.WriteStr(const Value: String);
  319. var
  320. i: integer;
  321. b: byte;
  322. begin
  323. i := Length(Value);
  324. if i > 255 then
  325. i := 255;
  326. b := i;
  327. Write(b, 1);
  328. if i > 0 then
  329. Write(Value[1], i);
  330. end;
  331. {****************************************************************************}
  332. {* TWriter *}
  333. {****************************************************************************}
  334. constructor TWriter.Create(ADriver: TAbstractObjectWriter);
  335. begin
  336. inherited Create;
  337. FDriver := ADriver;
  338. end;
  339. constructor TWriter.Create(Stream: TStream; BufSize: Integer);
  340. begin
  341. inherited Create;
  342. If (Stream=Nil) then
  343. Raise EWriteError.Create(SEmptyStreamIllegalWriter);
  344. FDriver := CreateDriver(Stream, BufSize);
  345. FDestroyDriver := True;
  346. end;
  347. destructor TWriter.Destroy;
  348. begin
  349. if FDestroyDriver then
  350. FDriver.Free;
  351. inherited Destroy;
  352. end;
  353. function TWriter.CreateDriver(Stream: TStream; BufSize: Integer): TAbstractObjectWriter;
  354. begin
  355. Result := TBinaryObjectWriter.Create(Stream, BufSize);
  356. end;
  357. Type
  358. TPosComponent = Class(TObject)
  359. FPos : Integer;
  360. FComponent : TComponent;
  361. Constructor Create(APos : Integer; AComponent : TComponent);
  362. end;
  363. Constructor TPosComponent.Create(APos : Integer; AComponent : TComponent);
  364. begin
  365. FPos:=APos;
  366. FComponent:=AComponent;
  367. end;
  368. // Used as argument for calls to TComponent.GetChildren:
  369. procedure TWriter.AddToAncestorList(Component: TComponent);
  370. begin
  371. FAncestors.AddObject(Component.Name,TPosComponent.Create(FAncestors.Count,Component));
  372. end;
  373. procedure TWriter.DefineProperty(const Name: String;
  374. ReadData: TReaderProc; AWriteData: TWriterProc; HasData: Boolean);
  375. begin
  376. if HasData and Assigned(AWriteData) then
  377. begin
  378. // Write the property name and then the data itself
  379. Driver.BeginProperty(FPropPath + Name);
  380. AWriteData(Self);
  381. Driver.EndProperty;
  382. end;
  383. end;
  384. procedure TWriter.DefineBinaryProperty(const Name: String;
  385. ReadData, AWriteData: TStreamProc; HasData: Boolean);
  386. begin
  387. if HasData and Assigned(AWriteData) then
  388. begin
  389. // Write the property name and then the data itself
  390. Driver.BeginProperty(FPropPath + Name);
  391. WriteBinary(AWriteData);
  392. Driver.EndProperty;
  393. end;
  394. end;
  395. procedure TWriter.Write(const Buffer; Count: Longint);
  396. begin
  397. //This should give an exception if write is not implemented (i.e. TTextObjectWriter)
  398. //but should work with TBinaryObjectWriter.
  399. Driver.Write(Buffer, Count);
  400. end;
  401. procedure TWriter.SetRoot(ARoot: TComponent);
  402. begin
  403. inherited SetRoot(ARoot);
  404. // Use the new root as lookup root too
  405. FLookupRoot := ARoot;
  406. end;
  407. procedure TWriter.WriteBinary(AWriteData: TStreamProc);
  408. var
  409. MemBuffer: TMemoryStream;
  410. BufferSize: Longint;
  411. begin
  412. { First write the binary data into a memory stream, then copy this buffered
  413. stream into the writing destination. This is necessary as we have to know
  414. the size of the binary data in advance (we're assuming that seeking within
  415. the writer stream is not possible) }
  416. MemBuffer := TMemoryStream.Create;
  417. try
  418. AWriteData(MemBuffer);
  419. BufferSize := MemBuffer.Size;
  420. Driver.WriteBinary(MemBuffer.Memory^, BufferSize);
  421. finally
  422. MemBuffer.Free;
  423. end;
  424. end;
  425. procedure TWriter.WriteBoolean(Value: Boolean);
  426. begin
  427. Driver.WriteBoolean(Value);
  428. end;
  429. procedure TWriter.WriteChar(Value: Char);
  430. begin
  431. WriteString(Value);
  432. end;
  433. procedure TWriter.WriteWideChar(Value: WideChar);
  434. begin
  435. WriteWideString(Value);
  436. end;
  437. procedure TWriter.WriteCollection(Value: TCollection);
  438. var
  439. i: Integer;
  440. begin
  441. Driver.BeginCollection;
  442. if Assigned(Value) then
  443. for i := 0 to Value.Count - 1 do
  444. begin
  445. { Each collection item needs its own ListBegin/ListEnd tag, or else the
  446. reader wouldn't be able to know where an item ends and where the next
  447. one starts }
  448. WriteListBegin;
  449. WriteProperties(Value.Items[i]);
  450. WriteListEnd;
  451. end;
  452. WriteListEnd;
  453. end;
  454. procedure TWriter.DetermineAncestor(Component : TComponent);
  455. Var
  456. I : Integer;
  457. begin
  458. // Should be set only when we write an inherited with children.
  459. if Not Assigned(FAncestors) then
  460. exit;
  461. I:=FAncestors.IndexOf(Component.Name);
  462. If (I=-1) then
  463. begin
  464. FAncestor:=Nil;
  465. FAncestorPos:=-1;
  466. end
  467. else
  468. With TPosComponent(FAncestors.Objects[i]) do
  469. begin
  470. FAncestor:=FComponent;
  471. FAncestorPos:=FPos;
  472. end;
  473. end;
  474. procedure TWriter.DoFindAncestor(Component : TComponent);
  475. Var
  476. C : TComponent;
  477. begin
  478. if Assigned(FOnFindAncestor) then
  479. if (Ancestor=Nil) or (Ancestor is TComponent) then
  480. begin
  481. C:=TComponent(Ancestor);
  482. FOnFindAncestor(Self,Component,Component.Name,C,FRootAncestor);
  483. Ancestor:=C;
  484. end;
  485. end;
  486. procedure TWriter.WriteComponent(Component: TComponent);
  487. var
  488. SA : TPersistent;
  489. SR : TComponent;
  490. begin
  491. SR:=FRoot;
  492. SA:=FAncestor;
  493. Try
  494. Component.FComponentState:=Component.FComponentState+[csWriting];
  495. Try
  496. // Possibly set ancestor.
  497. DetermineAncestor(Component);
  498. DoFindAncestor(Component); // Mainly for IDE when a parent form had an ancestor renamed...
  499. // Will call WriteComponentData.
  500. Component.WriteState(Self);
  501. FDriver.EndList;
  502. Finally
  503. Component.FComponentState:=Component.FComponentState-[csWriting];
  504. end;
  505. Finally
  506. FAncestor:=SA;
  507. FRoot:=SR;
  508. end;
  509. end;
  510. procedure TWriter.WriteChildren(Component : TComponent);
  511. Var
  512. SRoot, SRootA : TComponent;
  513. SList : TStringList;
  514. SPos : Integer;
  515. I : Integer;
  516. begin
  517. // Write children list.
  518. // While writing children, the ancestor environment must be saved
  519. // This is recursive...
  520. SRoot:=FRoot;
  521. SRootA:=FRootAncestor;
  522. SList:=FAncestors;
  523. SPos:=FCurrentPos;
  524. try
  525. FAncestors:=Nil;
  526. FCurrentPos:=0;
  527. FAncestorPos:=-1;
  528. if csInline in Component.ComponentState then
  529. FRoot:=Component;
  530. if (FAncestor is TComponent) then
  531. begin
  532. FAncestors:=TStringList.Create;
  533. if csInline in TComponent(FAncestor).ComponentState then
  534. FRootAncestor := TComponent(FAncestor);
  535. TComponent(FAncestor).GetChildren(@AddToAncestorList,FRootAncestor);
  536. FAncestors.Sorted:=True;
  537. end;
  538. try
  539. Component.GetChildren(@WriteComponent, FRoot);
  540. Finally
  541. If Assigned(Fancestors) then
  542. For I:=0 to FAncestors.Count-1 do
  543. FAncestors.Objects[i].Free;
  544. FreeAndNil(FAncestors);
  545. end;
  546. finally
  547. FAncestors:=Slist;
  548. FRoot:=SRoot;
  549. FRootAncestor:=SRootA;
  550. FCurrentPos:=SPos;
  551. FAncestorPos:=Spos;
  552. end;
  553. end;
  554. procedure TWriter.WriteComponentData(Instance: TComponent);
  555. var
  556. Flags: TFilerFlags;
  557. begin
  558. Flags := [];
  559. If (Assigned(FAncestor)) and //has ancestor
  560. (not (csInline in Instance.ComponentState) or // no inline component
  561. // .. or the inline component is inherited
  562. (csAncestor in Instance.Componentstate) and (FAncestors <> nil)) then
  563. Flags:=[ffInherited]
  564. else If csInline in Instance.ComponentState then
  565. Flags:=[ffInline];
  566. If (FAncestors<>Nil) and ((FCurrentPos<>FAncestorPos) or (FAncestor=Nil)) then
  567. Include(Flags,ffChildPos);
  568. FDriver.BeginComponent(Instance,Flags,FCurrentPos);
  569. If (FAncestors<>Nil) then
  570. Inc(FCurrentPos);
  571. WriteProperties(Instance);
  572. WriteListEnd;
  573. // Needs special handling of ancestor.
  574. If not IgnoreChildren then
  575. WriteChildren(Instance);
  576. end;
  577. procedure TWriter.WriteDescendent(ARoot: TComponent; AAncestor: TComponent);
  578. begin
  579. FRoot := ARoot;
  580. FAncestor := AAncestor;
  581. FRootAncestor := AAncestor;
  582. FLookupRoot := ARoot;
  583. WriteComponent(ARoot);
  584. end;
  585. {$ifndef FPUNONE}
  586. procedure TWriter.WriteFloat(const Value: Extended);
  587. begin
  588. Driver.WriteFloat(Value);
  589. end;
  590. procedure TWriter.WriteSingle(const Value: Single);
  591. begin
  592. Driver.WriteSingle(Value);
  593. end;
  594. {$endif}
  595. procedure TWriter.WriteCurrency(const Value: Currency);
  596. begin
  597. Driver.WriteCurrency(Value);
  598. end;
  599. {$ifndef FPUNONE}
  600. procedure TWriter.WriteDate(const Value: TDateTime);
  601. begin
  602. Driver.WriteDate(Value);
  603. end;
  604. {$endif}
  605. procedure TWriter.WriteIdent(const Ident: string);
  606. begin
  607. Driver.WriteIdent(Ident);
  608. end;
  609. procedure TWriter.WriteInteger(Value: LongInt);
  610. begin
  611. Driver.WriteInteger(Value);
  612. end;
  613. procedure TWriter.WriteInteger(Value: Int64);
  614. begin
  615. Driver.WriteInteger(Value);
  616. end;
  617. procedure TWriter.WriteListBegin;
  618. begin
  619. Driver.BeginList;
  620. end;
  621. procedure TWriter.WriteListEnd;
  622. begin
  623. Driver.EndList;
  624. end;
  625. procedure TWriter.WriteProperties(Instance: TPersistent);
  626. var PropCount,i : integer;
  627. PropList : PPropList;
  628. begin
  629. PropCount:=GetPropList(Instance,PropList);
  630. if PropCount>0 then
  631. try
  632. for i := 0 to PropCount-1 do
  633. if IsStoredProp(Instance,PropList^[i]) then
  634. WriteProperty(Instance,PropList^[i]);
  635. Finally
  636. Freemem(PropList);
  637. end;
  638. Instance.DefineProperties(Self);
  639. end;
  640. procedure TWriter.WriteProperty(Instance: TPersistent; PropInfo: Pointer);
  641. var
  642. HasAncestor: Boolean;
  643. PropType: PTypeInfo;
  644. Value, DefValue: LongInt;
  645. Ident: String;
  646. IntToIdentFn: TIntToIdent;
  647. {$ifndef FPUNONE}
  648. FloatValue, DefFloatValue: Extended;
  649. {$endif}
  650. MethodValue: TMethod;
  651. DefMethodValue: TMethod;
  652. WStrValue, WDefStrValue: WideString;
  653. StrValue, DefStrValue: String;
  654. AncestorObj: TObject;
  655. Component: TComponent;
  656. ObjValue: TObject;
  657. SavedAncestor: TPersistent;
  658. SavedPropPath, Name: String;
  659. Int64Value, DefInt64Value: Int64;
  660. BoolValue, DefBoolValue: boolean;
  661. Handled: Boolean;
  662. begin
  663. // do not stream properties without getter
  664. if not Assigned(PPropInfo(PropInfo)^.GetProc) then
  665. exit;
  666. // properties without setter are only allowed, if they are subcomponents
  667. PropType := PPropInfo(PropInfo)^.PropType;
  668. if not Assigned(PPropInfo(PropInfo)^.SetProc) then begin
  669. if PropType^.Kind<>tkClass then
  670. exit;
  671. ObjValue := TObject(GetObjectProp(Instance, PropInfo));
  672. if not ObjValue.InheritsFrom(TComponent) or
  673. not (csSubComponent in TComponent(ObjValue).ComponentStyle) then
  674. exit;
  675. end;
  676. { Check if the ancestor can be used }
  677. HasAncestor := Assigned(Ancestor) and ((Instance = Root) or
  678. (Instance.ClassType = Ancestor.ClassType));
  679. case PropType^.Kind of
  680. tkInteger, tkChar, tkEnumeration, tkSet, tkWChar:
  681. begin
  682. Value := GetOrdProp(Instance, PropInfo);
  683. if HasAncestor then
  684. DefValue := GetOrdProp(Ancestor, PropInfo)
  685. else
  686. DefValue := PPropInfo(PropInfo)^.Default;
  687. //writeln(PPropInfo(PropInfo)^.Name, ', HasAncestor=', ord(HasAncestor), ', Value=', Value, ', Default=', DefValue);
  688. if (Value <> DefValue) or (DefValue=longint($80000000)) then
  689. begin
  690. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  691. case PropType^.Kind of
  692. tkInteger:
  693. begin
  694. // Check if this integer has a string identifier
  695. IntToIdentFn := FindIntToIdent(PPropInfo(PropInfo)^.PropType);
  696. if Assigned(IntToIdentFn) and IntToIdentFn(Value, Ident) then
  697. // Integer can be written a human-readable identifier
  698. WriteIdent(Ident)
  699. else
  700. // Integer has to be written just as number
  701. WriteInteger(Value);
  702. end;
  703. tkChar:
  704. WriteChar(Chr(Value));
  705. tkWChar:
  706. WriteWideChar(WideChar(Value));
  707. tkSet:
  708. Driver.WriteSet(Value, GetTypeData(PropType)^.CompType);
  709. tkEnumeration:
  710. WriteIdent(GetEnumName(PropType, Value));
  711. end;
  712. Driver.EndProperty;
  713. end;
  714. end;
  715. {$ifndef FPUNONE}
  716. tkFloat:
  717. begin
  718. FloatValue := GetFloatProp(Instance, PropInfo);
  719. if HasAncestor then
  720. DefFloatValue := GetFloatProp(Ancestor, PropInfo)
  721. else
  722. DefFloatValue := 0;
  723. if FloatValue <> DefFloatValue then
  724. begin
  725. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  726. WriteFloat(FloatValue);
  727. Driver.EndProperty;
  728. end;
  729. end;
  730. {$endif}
  731. tkMethod:
  732. begin
  733. MethodValue := GetMethodProp(Instance, PropInfo);
  734. if HasAncestor then
  735. DefMethodValue := GetMethodProp(Ancestor, PropInfo)
  736. else begin
  737. DefMethodValue.Data := nil;
  738. DefMethodValue.Code := nil;
  739. end;
  740. Handled:=false;
  741. if Assigned(OnWriteMethodProperty) then
  742. OnWriteMethodProperty(Self,Instance,PPropInfo(PropInfo),MethodValue,
  743. DefMethodValue,Handled);
  744. if (not Handled) and
  745. (MethodValue.Code <> DefMethodValue.Code) and
  746. ((not Assigned(MethodValue.Code)) or
  747. ((Length(FLookupRoot.MethodName(MethodValue.Code)) >= 0))) then
  748. begin
  749. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  750. if Assigned(MethodValue.Code) then
  751. Driver.WriteMethodName(FLookupRoot.MethodName(MethodValue.Code))
  752. else
  753. Driver.WriteMethodName('');
  754. Driver.EndProperty;
  755. end;
  756. end;
  757. tkSString, tkLString, tkAString:
  758. begin
  759. StrValue := GetStrProp(Instance, PropInfo);
  760. if HasAncestor then
  761. DefStrValue := GetStrProp(Ancestor, PropInfo)
  762. else
  763. SetLength(DefStrValue, 0);
  764. if StrValue <> DefStrValue then
  765. begin
  766. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  767. if Assigned(FOnWriteStringProperty) then
  768. FOnWriteStringProperty(Self,Instance,PropInfo,StrValue);
  769. WriteString(StrValue);
  770. Driver.EndProperty;
  771. end;
  772. end;
  773. tkWString:
  774. begin
  775. WStrValue := GetWideStrProp(Instance, PropInfo);
  776. if HasAncestor then
  777. WDefStrValue := GetWideStrProp(Ancestor, PropInfo)
  778. else
  779. SetLength(WDefStrValue, 0);
  780. if WStrValue <> WDefStrValue then
  781. begin
  782. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  783. WriteWideString(WStrValue);
  784. Driver.EndProperty;
  785. end;
  786. end;
  787. {!!!: tkVariant:}
  788. tkClass:
  789. begin
  790. ObjValue := TObject(GetObjectProp(Instance, PropInfo));
  791. if HasAncestor then
  792. begin
  793. AncestorObj := TObject(GetObjectProp(Ancestor, PropInfo));
  794. if Assigned(AncestorObj) then
  795. if Assigned(ObjValue) and
  796. (TComponent(AncestorObj).Owner = FRootAncestor) and
  797. (TComponent(ObjValue).Owner = Root) and
  798. (UpperCase(TComponent(AncestorObj).Name) = UpperCase(TComponent(ObjValue).Name)) then
  799. AncestorObj := ObjValue
  800. // else
  801. // AncestorObj := nil;
  802. end else
  803. AncestorObj := nil;
  804. if not Assigned(ObjValue) then
  805. begin
  806. if ObjValue <> AncestorObj then
  807. begin
  808. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  809. Driver.WriteIdent('NIL');
  810. Driver.EndProperty;
  811. end
  812. end
  813. else if ObjValue.InheritsFrom(TPersistent) then
  814. begin
  815. { Subcomponents are streamed the same way as persistents }
  816. if ObjValue.InheritsFrom(TComponent)
  817. and ((not (csSubComponent in TComponent(ObjValue).ComponentStyle))
  818. or ((TComponent(ObjValue).Owner<>Instance) and (TComponent(ObjValue).Owner<>Nil))) then
  819. begin
  820. Component := TComponent(ObjValue);
  821. if (ObjValue <> AncestorObj)
  822. and not (csTransient in Component.ComponentStyle) then
  823. begin
  824. { Determine the correct name of the component this property contains }
  825. if Component.Owner = LookupRoot then
  826. Name := Component.Name
  827. else if Component = LookupRoot then
  828. Name := 'Owner'
  829. else if Assigned(Component.Owner) and (Length(Component.Owner.Name) > 0)
  830. and (Length(Component.Name) > 0) then
  831. Name := Component.Owner.Name + '.' + Component.Name
  832. else if Length(Component.Name) > 0 then
  833. Name := Component.Name + '.Owner'
  834. else
  835. SetLength(Name, 0);
  836. if Length(Name) > 0 then
  837. begin
  838. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  839. WriteIdent(Name);
  840. Driver.EndProperty;
  841. end; // length Name>0
  842. end; //(ObjValue <> AncestorObj)
  843. end // ObjValue.InheritsFrom(TComponent)
  844. else if ObjValue.InheritsFrom(TCollection) then
  845. begin
  846. if (not HasAncestor) or (not CollectionsEqual(TCollection(ObjValue),
  847. TCollection(GetObjectProp(Ancestor, PropInfo)),root,rootancestor)) then
  848. begin
  849. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  850. SavedPropPath := FPropPath;
  851. try
  852. SetLength(FPropPath, 0);
  853. WriteCollection(TCollection(ObjValue));
  854. finally
  855. FPropPath := SavedPropPath;
  856. Driver.EndProperty;
  857. end;
  858. end;
  859. end // Tcollection
  860. else
  861. begin
  862. SavedAncestor := Ancestor;
  863. SavedPropPath := FPropPath;
  864. try
  865. FPropPath := FPropPath + PPropInfo(PropInfo)^.Name + '.';
  866. if HasAncestor then
  867. Ancestor := TPersistent(GetObjectProp(Ancestor, PropInfo));
  868. WriteProperties(TPersistent(ObjValue));
  869. finally
  870. Ancestor := SavedAncestor;
  871. FPropPath := SavedPropPath;
  872. end;
  873. end;
  874. end; // Inheritsfrom(TPersistent)
  875. end;
  876. tkInt64, tkQWord:
  877. begin
  878. Int64Value := GetInt64Prop(Instance, PropInfo);
  879. if HasAncestor then
  880. DefInt64Value := GetInt64Prop(Ancestor, PropInfo)
  881. else
  882. DefInt64Value := 0;
  883. if Int64Value <> DefInt64Value then
  884. begin
  885. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  886. WriteInteger(Int64Value);
  887. Driver.EndProperty;
  888. end;
  889. end;
  890. tkBool:
  891. begin
  892. BoolValue := GetOrdProp(Instance, PropInfo)<>0;
  893. if HasAncestor then
  894. DefBoolValue := GetOrdProp(Ancestor, PropInfo)<>0
  895. else
  896. DefBoolValue := PPropInfo(PropInfo)^.Default<>0;
  897. if BoolValue <> DefBoolValue then
  898. begin
  899. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  900. WriteBoolean(BoolValue);
  901. Driver.EndProperty;
  902. end;
  903. end;
  904. end;
  905. end;
  906. procedure TWriter.WriteRootComponent(ARoot: TComponent);
  907. begin
  908. WriteDescendent(ARoot, nil);
  909. end;
  910. procedure TWriter.WriteString(const Value: String);
  911. begin
  912. Driver.WriteString(Value);
  913. end;
  914. procedure TWriter.WriteWideString(const Value: WideString);
  915. begin
  916. Driver.WriteWideString(Value);
  917. end;