writer.inc 31 KB

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