writer.inc 35 KB

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