writer.inc 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304
  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. if Version=TBinaryObjectReader.TBOVersion.boVersion1 then
  108. Write(FilerSignature1, SizeOf(FilerSignature1))
  109. else
  110. Write(FilerSignature, SizeOf(FilerSignature));
  111. end;
  112. procedure TBinaryObjectWriter.BeginComponent(Component: TComponent;
  113. Flags: TFilerFlags; ChildPos: Integer);
  114. var
  115. Prefix: Byte;
  116. begin
  117. { Only write the flags if they are needed! }
  118. if Flags <> [] then
  119. begin
  120. Prefix := TFilerFlagsInt(Flags) or $f0;
  121. Write(Prefix, 1);
  122. if ffChildPos in Flags then
  123. WriteInteger(ChildPos);
  124. end;
  125. if Version=TBinaryObjectReader.TBOVersion.boVersion1 then
  126. WriteString(Component.UnitName+TBinaryObjectReader.UnitnameSeparator+Component.ClassName)
  127. else
  128. WriteStr(Component.ClassName);
  129. WriteStr(Component.Name);
  130. end;
  131. procedure TBinaryObjectWriter.BeginList;
  132. begin
  133. WriteValue(vaList);
  134. end;
  135. procedure TBinaryObjectWriter.EndList;
  136. begin
  137. WriteValue(vaNull);
  138. end;
  139. procedure TBinaryObjectWriter.BeginProperty(const PropName: String);
  140. begin
  141. WriteStr(PropName);
  142. end;
  143. procedure TBinaryObjectWriter.EndProperty;
  144. begin
  145. end;
  146. procedure TBinaryObjectWriter.WriteBinary(const Buffer; Count: LongInt);
  147. begin
  148. WriteValue(vaBinary);
  149. WriteDWord(longword(Count));
  150. Write(Buffer, Count);
  151. end;
  152. procedure TBinaryObjectWriter.WriteBoolean(Value: Boolean);
  153. begin
  154. if Value then
  155. WriteValue(vaTrue)
  156. else
  157. WriteValue(vaFalse);
  158. end;
  159. {$ifndef FPUNONE}
  160. procedure TBinaryObjectWriter.WriteFloat(const Value: Extended);
  161. begin
  162. WriteValue(vaExtended);
  163. WriteExtended(Value);
  164. end;
  165. procedure TBinaryObjectWriter.WriteSingle(const Value: Single);
  166. begin
  167. WriteValue(vaSingle);
  168. WriteDWord(longword(Value));
  169. end;
  170. {$endif}
  171. procedure TBinaryObjectWriter.WriteCurrency(const Value: Currency);
  172. begin
  173. WriteValue(vaCurrency);
  174. WriteQWord(qword(Value));
  175. end;
  176. {$ifndef FPUNONE}
  177. procedure TBinaryObjectWriter.WriteDate(const Value: TDateTime);
  178. begin
  179. WriteValue(vaDate);
  180. WriteQWord(qword(Value));
  181. end;
  182. {$endif}
  183. procedure TBinaryObjectWriter.WriteIdent(const Ident: string);
  184. begin
  185. Case UpperCase(Ident) of
  186. 'NIL' : WriteValue(vaNil);
  187. 'FALSE' : WriteValue(vaFalse);
  188. 'TRUE' : WriteValue(vaTrue);
  189. 'NULL' : WriteValue(vaNull);
  190. else
  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. { The variant manager will handle varbyref and vararray transparently for us
  340. }
  341. case (tvardata(VarValue).vtype and varTypeMask) of
  342. varEmpty:
  343. begin
  344. WriteValue(vaNil);
  345. end;
  346. varNull:
  347. begin
  348. WriteValue(vaNull);
  349. end;
  350. { all integer sizes must be split for big endian systems }
  351. varShortInt,varSmallInt,varInteger,varInt64:
  352. begin
  353. WriteInteger(VarValue);
  354. end;
  355. varQWord:
  356. begin
  357. WriteUInt64(VarValue);
  358. end;
  359. varBoolean:
  360. begin
  361. WriteBoolean(VarValue);
  362. end;
  363. varCurrency:
  364. begin
  365. WriteCurrency(VarValue);
  366. end;
  367. {$ifndef fpunone}
  368. varSingle:
  369. begin
  370. WriteSingle(VarValue);
  371. end;
  372. varDouble:
  373. begin
  374. WriteFloat(VarValue);
  375. end;
  376. varDate:
  377. begin
  378. WriteDate(VarValue);
  379. end;
  380. {$endif fpunone}
  381. varOleStr,varString:
  382. begin
  383. WriteWideString(VarValue);
  384. end;
  385. else
  386. raise EWriteError.CreateFmt(SUnsupportedPropertyVariantType, [Ord(tvardata(VarValue).vtype)]);
  387. end;
  388. end;
  389. procedure TBinaryObjectWriter.FlushBuffer;
  390. begin
  391. FStream.WriteBuffer(FBuffer^, FBufPos);
  392. FBufPos := 0;
  393. end;
  394. procedure TBinaryObjectWriter.Write(const Buffer; Count: Longint);
  395. var
  396. CopyNow: LongInt;
  397. SourceBuf: PChar;
  398. begin
  399. SourceBuf:=@Buffer;
  400. while Count > 0 do
  401. begin
  402. CopyNow := Count;
  403. if CopyNow > FBufSize - FBufPos then
  404. CopyNow := FBufSize - FBufPos;
  405. Move(SourceBuf^, PChar(FBuffer)[FBufPos], CopyNow);
  406. Dec(Count, CopyNow);
  407. Inc(FBufPos, CopyNow);
  408. inc(SourceBuf, CopyNow);
  409. if FBufPos = FBufSize then
  410. FlushBuffer;
  411. end;
  412. end;
  413. procedure TBinaryObjectWriter.WriteValue(Value: TValueType);
  414. var
  415. b: byte;
  416. begin
  417. b := byte(Value);
  418. Write(b, 1);
  419. end;
  420. procedure TBinaryObjectWriter.WriteStr(const Value: String);
  421. var
  422. i: integer;
  423. b: byte;
  424. begin
  425. i := Length(Value);
  426. if i > 255 then
  427. i := 255;
  428. b := i;
  429. Write(b, 1);
  430. if i > 0 then
  431. Write(Value[1], i);
  432. end;
  433. {****************************************************************************}
  434. {* TWriter *}
  435. {****************************************************************************}
  436. constructor TWriter.Create(ADriver: TAbstractObjectWriter);
  437. begin
  438. inherited Create;
  439. FDriver := ADriver;
  440. end;
  441. constructor TWriter.Create(Stream: TStream; BufSize: Integer);
  442. begin
  443. inherited Create;
  444. If (Stream=Nil) then
  445. Raise EWriteError.Create(SEmptyStreamIllegalWriter);
  446. FDriver := CreateDriver(Stream, BufSize);
  447. FDestroyDriver := True;
  448. end;
  449. destructor TWriter.Destroy;
  450. begin
  451. if FDestroyDriver then
  452. FDriver.Free;
  453. inherited Destroy;
  454. end;
  455. procedure TWriter.FlushBuffer;
  456. begin
  457. Driver.FlushBuffer;
  458. end;
  459. function TWriter.CreateDriver(Stream: TStream; BufSize: Integer): TAbstractObjectWriter;
  460. begin
  461. Result := TBinaryObjectWriter.Create(Stream, BufSize);
  462. end;
  463. Type
  464. TPosComponent = Class(TObject)
  465. FPos : Integer;
  466. FComponent : TComponent;
  467. Constructor Create(APos : Integer; AComponent : TComponent);
  468. end;
  469. Constructor TPosComponent.Create(APos : Integer; AComponent : TComponent);
  470. begin
  471. FPos:=APos;
  472. FComponent:=AComponent;
  473. end;
  474. // Used as argument for calls to TComponent.GetChildren:
  475. procedure TWriter.AddToAncestorList(Component: TComponent);
  476. begin
  477. FAncestors.AddObject(Component.Name,TPosComponent.Create(FAncestors.Count,Component));
  478. end;
  479. procedure TWriter.DefineProperty(const Name: string; ReadData: TReaderProc;
  480. AWriteData: TWriterProc; HasData: Boolean);
  481. begin
  482. if HasData and Assigned(AWriteData) then
  483. begin
  484. // Write the property name and then the data itself
  485. Driver.BeginProperty(FPropPath + Name);
  486. AWriteData(Self);
  487. Driver.EndProperty;
  488. end;
  489. end;
  490. procedure TWriter.DefineBinaryProperty(const Name: string; ReadData,
  491. AWriteData: TStreamProc; HasData: Boolean);
  492. begin
  493. if HasData and Assigned(AWriteData) then
  494. begin
  495. // Write the property name and then the data itself
  496. Driver.BeginProperty(FPropPath + Name);
  497. WriteBinary(AWriteData);
  498. Driver.EndProperty;
  499. end;
  500. end;
  501. procedure TWriter.Write(const Buffer; Count: Longint);
  502. begin
  503. //This should give an exception if write is not implemented (i.e. TTextObjectWriter)
  504. //but should work with TBinaryObjectWriter.
  505. Driver.Write(Buffer, Count);
  506. end;
  507. procedure TWriter.SetRoot(ARoot: TComponent);
  508. begin
  509. inherited SetRoot(ARoot);
  510. // Use the new root as lookup root too
  511. FLookupRoot := ARoot;
  512. end;
  513. procedure TWriter.WriteSignature;
  514. begin
  515. FDriver.WriteSignature;
  516. end;
  517. procedure TWriter.WriteBinary(AWriteData: TStreamProc);
  518. var
  519. MemBuffer: TMemoryStream;
  520. BufferSize: Longint;
  521. begin
  522. { First write the binary data into a memory stream, then copy this buffered
  523. stream into the writing destination. This is necessary as we have to know
  524. the size of the binary data in advance (we're assuming that seeking within
  525. the writer stream is not possible) }
  526. MemBuffer := TMemoryStream.Create;
  527. try
  528. AWriteData(MemBuffer);
  529. BufferSize := MemBuffer.Size;
  530. Driver.WriteBinary(MemBuffer.Memory^, BufferSize);
  531. finally
  532. MemBuffer.Free;
  533. end;
  534. end;
  535. procedure TWriter.WriteBoolean(Value: Boolean);
  536. begin
  537. Driver.WriteBoolean(Value);
  538. end;
  539. procedure TWriter.WriteChar(Value: Char);
  540. begin
  541. WriteString(Value);
  542. end;
  543. procedure TWriter.WriteWideChar(Value: WideChar);
  544. begin
  545. WriteWideString(Value);
  546. end;
  547. procedure TWriter.WriteCollection(Value: TCollection);
  548. var
  549. i: Integer;
  550. begin
  551. Driver.BeginCollection;
  552. if Assigned(Value) then
  553. for i := 0 to Value.Count - 1 do
  554. begin
  555. { Each collection item needs its own ListBegin/ListEnd tag, or else the
  556. reader wouldn't be able to know where an item ends and where the next
  557. one starts }
  558. WriteListBegin;
  559. WriteProperties(Value.Items[i]);
  560. WriteListEnd;
  561. end;
  562. WriteListEnd;
  563. end;
  564. procedure TWriter.DetermineAncestor(Component : TComponent);
  565. Var
  566. I : Integer;
  567. begin
  568. // Should be set only when we write an inherited with children.
  569. if Not Assigned(FAncestors) then
  570. exit;
  571. I:=FAncestors.IndexOf(Component.Name);
  572. If (I=-1) then
  573. begin
  574. FAncestor:=Nil;
  575. FAncestorPos:=-1;
  576. end
  577. else
  578. With TPosComponent(FAncestors.Objects[i]) do
  579. begin
  580. FAncestor:=FComponent;
  581. FAncestorPos:=FPos;
  582. end;
  583. end;
  584. procedure TWriter.DoFindAncestor(Component : TComponent);
  585. Var
  586. C : TComponent;
  587. begin
  588. if Assigned(FOnFindAncestor) then
  589. if (Ancestor=Nil) or (Ancestor is TComponent) then
  590. begin
  591. C:=TComponent(Ancestor);
  592. FOnFindAncestor(Self,Component,Component.Name,C,FRootAncestor);
  593. Ancestor:=C;
  594. end;
  595. end;
  596. procedure TWriter.WriteComponent(Component: TComponent);
  597. var
  598. SA : TPersistent;
  599. SR, SRA : TComponent;
  600. begin
  601. SR:=FRoot;
  602. SA:=FAncestor;
  603. SRA:=FRootAncestor;
  604. Try
  605. Component.FComponentState:=Component.FComponentState+[csWriting];
  606. Try
  607. // Possibly set ancestor.
  608. DetermineAncestor(Component);
  609. DoFindAncestor(Component); // Mainly for IDE when a parent form had an ancestor renamed...
  610. // Will call WriteComponentData.
  611. Component.WriteState(Self);
  612. FDriver.EndList;
  613. Finally
  614. Component.FComponentState:=Component.FComponentState-[csWriting];
  615. end;
  616. Finally
  617. FAncestor:=SA;
  618. FRoot:=SR;
  619. FRootAncestor:=SRA;
  620. end;
  621. end;
  622. procedure TWriter.WriteChildren(Component : TComponent);
  623. Var
  624. SRoot, SRootA : TComponent;
  625. SList : TStringList;
  626. SPos, I , SAncestorPos: Integer;
  627. begin
  628. // Write children list.
  629. // While writing children, the ancestor environment must be saved
  630. // This is recursive...
  631. SRoot:=FRoot;
  632. SRootA:=FRootAncestor;
  633. SList:=FAncestors;
  634. SPos:=FCurrentPos;
  635. SAncestorPos:=FAncestorPos;
  636. try
  637. FAncestors:=Nil;
  638. FCurrentPos:=0;
  639. FAncestorPos:=-1;
  640. if csInline in Component.ComponentState then
  641. FRoot:=Component;
  642. if (FAncestor is TComponent) then
  643. begin
  644. FAncestors:=TStringList.Create;
  645. if csInline in TComponent(FAncestor).ComponentState then
  646. FRootAncestor := TComponent(FAncestor);
  647. TComponent(FAncestor).GetChildren(@AddToAncestorList,FRootAncestor);
  648. FAncestors.Sorted:=True;
  649. end;
  650. try
  651. Component.GetChildren(@WriteComponent, FRoot);
  652. Finally
  653. If Assigned(Fancestors) then
  654. For I:=0 to FAncestors.Count-1 do
  655. FAncestors.Objects[i].Free;
  656. FreeAndNil(FAncestors);
  657. end;
  658. finally
  659. FAncestors:=Slist;
  660. FRoot:=SRoot;
  661. FRootAncestor:=SRootA;
  662. FCurrentPos:=SPos;
  663. FAncestorPos:=SAncestorPos;
  664. end;
  665. end;
  666. procedure TWriter.WriteComponentData(Instance: TComponent);
  667. var
  668. Flags: TFilerFlags;
  669. begin
  670. Flags := [];
  671. If (Assigned(FAncestor)) and //has ancestor
  672. (not (csInline in Instance.ComponentState) or // no inline component
  673. // .. or the inline component is inherited
  674. (csAncestor in Instance.Componentstate) and (FAncestors <> nil)) then
  675. Flags:=[ffInherited]
  676. else If csInline in Instance.ComponentState then
  677. Flags:=[ffInline];
  678. If (FAncestors<>Nil) and ((FCurrentPos<>FAncestorPos) or (FAncestor=Nil)) then
  679. Include(Flags,ffChildPos);
  680. FDriver.BeginComponent(Instance,Flags,FCurrentPos);
  681. If (FAncestors<>Nil) then
  682. Inc(FCurrentPos);
  683. WriteProperties(Instance);
  684. WriteListEnd;
  685. // Needs special handling of ancestor.
  686. If not IgnoreChildren then
  687. WriteChildren(Instance);
  688. end;
  689. procedure TWriter.WriteDescendent(ARoot: TComponent; AAncestor: TComponent);
  690. begin
  691. FRoot := ARoot;
  692. FAncestor := AAncestor;
  693. FRootAncestor := AAncestor;
  694. FLookupRoot := ARoot;
  695. WriteSignature;
  696. WriteComponent(ARoot);
  697. end;
  698. {$ifndef FPUNONE}
  699. procedure TWriter.WriteFloat(const Value: Extended);
  700. begin
  701. Driver.WriteFloat(Value);
  702. end;
  703. procedure TWriter.WriteSingle(const Value: Single);
  704. begin
  705. Driver.WriteSingle(Value);
  706. end;
  707. {$endif}
  708. procedure TWriter.WriteCurrency(const Value: Currency);
  709. begin
  710. Driver.WriteCurrency(Value);
  711. end;
  712. {$ifndef FPUNONE}
  713. procedure TWriter.WriteDate(const Value: TDateTime);
  714. begin
  715. Driver.WriteDate(Value);
  716. end;
  717. {$endif}
  718. procedure TWriter.WriteIdent(const Ident: string);
  719. begin
  720. Driver.WriteIdent(Ident);
  721. end;
  722. procedure TWriter.WriteInteger(Value: Longint);
  723. begin
  724. Driver.WriteInteger(Value);
  725. end;
  726. procedure TWriter.WriteInteger(Value: Int64);
  727. begin
  728. Driver.WriteInteger(Value);
  729. end;
  730. procedure TWriter.WriteSet(Value: Longint; SetType: Pointer);
  731. begin
  732. Driver.WriteSet(Value,SetType);
  733. end;
  734. procedure TWriter.WriteVariant(const VarValue: Variant);
  735. begin
  736. Driver.WriteVariant(VarValue);
  737. end;
  738. procedure TWriter.WriteListBegin;
  739. begin
  740. Driver.BeginList;
  741. end;
  742. procedure TWriter.WriteListEnd;
  743. begin
  744. Driver.EndList;
  745. end;
  746. procedure TWriter.WriteProperties(Instance: TPersistent);
  747. var PropCount,i : integer;
  748. PropList : PPropList;
  749. begin
  750. PropCount:=GetPropList(Instance,PropList);
  751. if PropCount>0 then
  752. try
  753. for i := 0 to PropCount-1 do
  754. if IsStoredProp(Instance,PropList^[i]) then
  755. WriteProperty(Instance,PropList^[i]);
  756. Finally
  757. Freemem(PropList);
  758. end;
  759. Instance.DefineProperties(Self);
  760. end;
  761. procedure TWriter.WriteProperty(Instance: TPersistent; PropInfo: Pointer);
  762. var
  763. HasAncestor: Boolean;
  764. PropType: PTypeInfo;
  765. Value, DefValue: LongInt;
  766. Ident: String;
  767. IntToIdentFn: TIntToIdent;
  768. {$ifndef FPUNONE}
  769. FloatValue, DefFloatValue: Extended;
  770. {$endif}
  771. MethodValue: TMethod;
  772. DefMethodValue: TMethod;
  773. WStrValue, WDefStrValue: WideString;
  774. StrValue, DefStrValue: String;
  775. UStrValue, UDefStrValue: UnicodeString;
  776. AncestorObj: TObject;
  777. C,Component: TComponent;
  778. ObjValue: TObject;
  779. SavedAncestor: TPersistent;
  780. SavedPropPath, Name: String;
  781. Int64Value, DefInt64Value: Int64;
  782. VarValue, DefVarValue : tvardata;
  783. BoolValue, DefBoolValue: boolean;
  784. Handled: Boolean;
  785. IntfValue: IInterface;
  786. CompRef: IInterfaceComponentReference;
  787. begin
  788. // do not stream properties without getter
  789. if not Assigned(PPropInfo(PropInfo)^.GetProc) then
  790. exit;
  791. // properties without setter are only allowed, if they are subcomponents
  792. PropType := PPropInfo(PropInfo)^.PropType;
  793. if not Assigned(PPropInfo(PropInfo)^.SetProc) then begin
  794. if PropType^.Kind<>tkClass then
  795. exit;
  796. ObjValue := TObject(GetObjectProp(Instance, PropInfo));
  797. if not (assigned(ObjValue) and
  798. ObjValue.InheritsFrom(TComponent) and
  799. (csSubComponent in TComponent(ObjValue).ComponentStyle)) then
  800. exit;
  801. end;
  802. { Check if the ancestor can be used }
  803. HasAncestor := Assigned(Ancestor) and ((Instance = Root) or
  804. (Instance.ClassType = Ancestor.ClassType));
  805. //writeln('TWriter.WriteProperty Name=',PropType^.Name,' Kind=',GetEnumName(TypeInfo(TTypeKind),ord(PropType^.Kind)),' HasAncestor=',HasAncestor);
  806. case PropType^.Kind of
  807. tkInteger, tkChar, tkEnumeration, tkSet, tkWChar:
  808. begin
  809. Value := GetOrdProp(Instance, PropInfo);
  810. if HasAncestor then
  811. DefValue := GetOrdProp(Ancestor, PropInfo)
  812. else
  813. DefValue := PPropInfo(PropInfo)^.Default;
  814. // writeln(PPropInfo(PropInfo)^.Name, ', HasAncestor=', ord(HasAncestor), ', Value=', Value, ', Default=', DefValue);
  815. if (Value <> DefValue) or (DefValue=longint($80000000)) then
  816. begin
  817. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  818. case PropType^.Kind of
  819. tkInteger:
  820. begin
  821. // Check if this integer has a string identifier
  822. IntToIdentFn := FindIntToIdent(PPropInfo(PropInfo)^.PropType);
  823. if Assigned(IntToIdentFn) and IntToIdentFn(Value, Ident) then
  824. // Integer can be written a human-readable identifier
  825. WriteIdent(Ident)
  826. else
  827. // Integer has to be written just as number
  828. WriteInteger(Value);
  829. end;
  830. tkChar:
  831. WriteChar(Chr(Value));
  832. tkWChar:
  833. WriteWideChar(WideChar(Value));
  834. tkSet:
  835. Driver.WriteSet(Value, GetTypeData(PropType)^.CompType);
  836. tkEnumeration:
  837. WriteIdent(GetEnumName(PropType, Value));
  838. end;
  839. Driver.EndProperty;
  840. end;
  841. end;
  842. {$ifndef FPUNONE}
  843. tkFloat:
  844. begin
  845. FloatValue := GetFloatProp(Instance, PropInfo);
  846. if HasAncestor then
  847. DefFloatValue := GetFloatProp(Ancestor, PropInfo)
  848. else
  849. begin
  850. DefValue :=PPropInfo(PropInfo)^.Default;
  851. DefFloatValue:=PSingle(@PPropInfo(PropInfo)^.Default)^;
  852. end;
  853. if (FloatValue<>DefFloatValue) or (not HasAncestor and (DefValue=longint($80000000))) then
  854. begin
  855. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  856. WriteFloat(FloatValue);
  857. Driver.EndProperty;
  858. end;
  859. end;
  860. {$endif}
  861. tkMethod:
  862. begin
  863. MethodValue := GetMethodProp(Instance, PropInfo);
  864. if HasAncestor then
  865. DefMethodValue := GetMethodProp(Ancestor, PropInfo)
  866. else begin
  867. DefMethodValue.Data := nil;
  868. DefMethodValue.Code := nil;
  869. end;
  870. Handled:=false;
  871. if Assigned(OnWriteMethodProperty) then
  872. OnWriteMethodProperty(Self,Instance,PPropInfo(PropInfo),MethodValue,
  873. DefMethodValue,Handled);
  874. if (not Handled) and
  875. (MethodValue.Code <> DefMethodValue.Code) and
  876. ((not Assigned(MethodValue.Code)) or
  877. ((Length(FLookupRoot.MethodName(MethodValue.Code)) > 0))) then
  878. begin
  879. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  880. if Assigned(MethodValue.Code) then
  881. Driver.WriteMethodName(FLookupRoot.MethodName(MethodValue.Code))
  882. else
  883. Driver.WriteMethodName('');
  884. Driver.EndProperty;
  885. end;
  886. end;
  887. tkSString, tkLString, tkAString:
  888. begin
  889. StrValue := GetStrProp(Instance, PropInfo);
  890. if HasAncestor then
  891. DefStrValue := GetStrProp(Ancestor, PropInfo)
  892. else
  893. begin
  894. DefValue :=PPropInfo(PropInfo)^.Default;
  895. SetLength(DefStrValue, 0);
  896. end;
  897. if (StrValue<>DefStrValue) or (not HasAncestor and (DefValue=longint($80000000))) then
  898. begin
  899. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  900. if Assigned(FOnWriteStringProperty) then
  901. FOnWriteStringProperty(Self,Instance,PropInfo,StrValue);
  902. WriteString(StrValue);
  903. Driver.EndProperty;
  904. end;
  905. end;
  906. tkWString:
  907. begin
  908. WStrValue := GetWideStrProp(Instance, PropInfo);
  909. if HasAncestor then
  910. WDefStrValue := GetWideStrProp(Ancestor, PropInfo)
  911. else
  912. begin
  913. DefValue :=PPropInfo(PropInfo)^.Default;
  914. SetLength(WDefStrValue, 0);
  915. end;
  916. if (WStrValue<>WDefStrValue) or (not HasAncestor and (DefValue=longint($80000000))) then
  917. begin
  918. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  919. WriteWideString(WStrValue);
  920. Driver.EndProperty;
  921. end;
  922. end;
  923. tkUString:
  924. begin
  925. UStrValue := GetUnicodeStrProp(Instance, PropInfo);
  926. if HasAncestor then
  927. UDefStrValue := GetUnicodeStrProp(Ancestor, PropInfo)
  928. else
  929. begin
  930. DefValue :=PPropInfo(PropInfo)^.Default;
  931. SetLength(UDefStrValue, 0);
  932. end;
  933. if (UStrValue<>UDefStrValue) or (not HasAncestor and (DefValue=longint($80000000))) then
  934. begin
  935. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  936. WriteUnicodeString(UStrValue);
  937. Driver.EndProperty;
  938. end;
  939. end;
  940. tkVariant:
  941. begin
  942. { Ensure that a Variant manager is installed }
  943. if not assigned(VarClearProc) then
  944. raise EWriteError.Create(SErrNoVariantSupport);
  945. VarValue := tvardata(GetVariantProp(Instance, PropInfo));
  946. if HasAncestor then
  947. DefVarValue := tvardata(GetVariantProp(Ancestor, PropInfo))
  948. else
  949. FillChar(DefVarValue,sizeof(DefVarValue),0);
  950. if (CompareByte(VarValue,DefVarValue,sizeof(VarValue)) <> 0) then
  951. begin
  952. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  953. { can't use variant() typecast, pulls in variants unit }
  954. WriteVariant(pvariant(@VarValue)^);
  955. Driver.EndProperty;
  956. end;
  957. end;
  958. tkClass:
  959. begin
  960. ObjValue := TObject(GetObjectProp(Instance, PropInfo));
  961. if HasAncestor then
  962. begin
  963. AncestorObj := TObject(GetObjectProp(Ancestor, PropInfo));
  964. if (AncestorObj is TComponent) and
  965. (ObjValue is TComponent) then
  966. begin
  967. //writeln('TWriter.WriteProperty AncestorObj=',TComponent(AncestorObj).Name,' OwnerFit=',TComponent(AncestorObj).Owner = FRootAncestor,' ',TComponent(ObjValue).Name,' OwnerFit=',TComponent(ObjValue).Owner = Root);
  968. if (AncestorObj<> ObjValue) and
  969. (TComponent(AncestorObj).Owner = FRootAncestor) and
  970. (TComponent(ObjValue).Owner = Root) and
  971. (UpperCase(TComponent(AncestorObj).Name) = UpperCase(TComponent(ObjValue).Name)) then
  972. begin
  973. // different components, but with the same name
  974. // treat it like an override
  975. AncestorObj := ObjValue;
  976. end;
  977. end;
  978. end else
  979. AncestorObj := nil;
  980. if not Assigned(ObjValue) then
  981. begin
  982. if ObjValue <> AncestorObj then
  983. begin
  984. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  985. Driver.WriteIdent('NIL');
  986. Driver.EndProperty;
  987. end
  988. end
  989. else if ObjValue.InheritsFrom(TPersistent) then
  990. begin
  991. { Subcomponents are streamed the same way as persistents }
  992. if ObjValue.InheritsFrom(TComponent)
  993. and ((not (csSubComponent in TComponent(ObjValue).ComponentStyle))
  994. or ((TComponent(ObjValue).Owner<>Instance) and (TComponent(ObjValue).Owner<>Nil))) then
  995. begin
  996. Component := TComponent(ObjValue);
  997. if (ObjValue <> AncestorObj)
  998. and not (csTransient in Component.ComponentStyle) then
  999. begin
  1000. Name:= '';
  1001. C:= Component;
  1002. While (C<>Nil) and (C.Name<>'') do
  1003. begin
  1004. If (Name<>'') Then
  1005. Name:='.'+Name;
  1006. if C.Owner = LookupRoot then
  1007. begin
  1008. Name := C.Name+Name;
  1009. break;
  1010. end
  1011. else if C = LookupRoot then
  1012. begin
  1013. Name := 'Owner' + Name;
  1014. break;
  1015. end;
  1016. Name:=C.Name + Name;
  1017. C:= C.Owner;
  1018. end;
  1019. if (C=nil) and (Component.Owner=nil) then
  1020. if (Name<>'') then //foreign root
  1021. Name:=Name+'.Owner';
  1022. if Length(Name) > 0 then
  1023. begin
  1024. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  1025. WriteIdent(Name);
  1026. Driver.EndProperty;
  1027. end; // length Name>0
  1028. end; //(ObjValue <> AncestorObj)
  1029. end // ObjValue.InheritsFrom(TComponent)
  1030. else
  1031. begin
  1032. SavedAncestor := Ancestor;
  1033. SavedPropPath := FPropPath;
  1034. try
  1035. FPropPath := FPropPath + PPropInfo(PropInfo)^.Name + '.';
  1036. if HasAncestor then
  1037. Ancestor := TPersistent(GetObjectProp(Ancestor, PropInfo));
  1038. WriteProperties(TPersistent(ObjValue));
  1039. finally
  1040. Ancestor := SavedAncestor;
  1041. FPropPath := SavedPropPath;
  1042. end;
  1043. if ObjValue.InheritsFrom(TCollection) then
  1044. begin
  1045. if (not HasAncestor) or (not CollectionsEqual(TCollection(ObjValue),
  1046. TCollection(GetObjectProp(Ancestor, PropInfo)),root,rootancestor)) then
  1047. begin
  1048. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  1049. SavedPropPath := FPropPath;
  1050. try
  1051. SetLength(FPropPath, 0);
  1052. WriteCollection(TCollection(ObjValue));
  1053. finally
  1054. FPropPath := SavedPropPath;
  1055. Driver.EndProperty;
  1056. end;
  1057. end;
  1058. end // Tcollection
  1059. end;
  1060. end; // Inheritsfrom(TPersistent)
  1061. end;
  1062. tkInt64, tkQWord:
  1063. begin
  1064. Int64Value := GetInt64Prop(Instance, PropInfo);
  1065. if HasAncestor then
  1066. DefInt64Value := GetInt64Prop(Ancestor, PropInfo)
  1067. else
  1068. DefInt64Value := PPropInfo(PropInfo)^.Default;
  1069. if (Int64Value <> DefInt64Value) or (DefInt64Value=longint($80000000)) then
  1070. begin
  1071. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  1072. WriteInteger(Int64Value);
  1073. Driver.EndProperty;
  1074. end;
  1075. end;
  1076. tkBool:
  1077. begin
  1078. BoolValue := GetOrdProp(Instance, PropInfo)<>0;
  1079. if HasAncestor then
  1080. DefBoolValue := GetOrdProp(Ancestor, PropInfo)<>0
  1081. else
  1082. begin
  1083. DefBoolValue := PPropInfo(PropInfo)^.Default<>0;
  1084. DefValue:=PPropInfo(PropInfo)^.Default;
  1085. end;
  1086. // writeln(PPropInfo(PropInfo)^.Name, ', HasAncestor=', ord(HasAncestor), ', Value=', Value, ', Default=', DefBoolValue);
  1087. if (BoolValue<>DefBoolValue) or (DefValue=longint($80000000)) then
  1088. begin
  1089. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  1090. WriteBoolean(BoolValue);
  1091. Driver.EndProperty;
  1092. end;
  1093. end;
  1094. tkInterface:
  1095. begin
  1096. IntfValue := GetInterfaceProp(Instance, PropInfo);
  1097. if Assigned(IntfValue) and Supports(IntfValue, IInterfaceComponentReference, CompRef) then
  1098. begin
  1099. Component := CompRef.GetComponent;
  1100. if HasAncestor then
  1101. begin
  1102. AncestorObj := TObject(GetObjectProp(Ancestor, PropInfo));
  1103. if (AncestorObj is TComponent) then
  1104. begin
  1105. //writeln('TWriter.WriteProperty AncestorObj=',TComponent(AncestorObj).Name,' OwnerFit=',TComponent(AncestorObj).Owner = FRootAncestor,' ',TComponent(ObjValue).Name,' OwnerFit=',TComponent(ObjValue).Owner = Root);
  1106. if (AncestorObj<> Component) and
  1107. (TComponent(AncestorObj).Owner = FRootAncestor) and
  1108. (Component.Owner = Root) and
  1109. (UpperCase(TComponent(AncestorObj).Name) = UpperCase(Component.Name)) then
  1110. begin
  1111. // different components, but with the same name
  1112. // treat it like an override
  1113. AncestorObj := Component;
  1114. end;
  1115. end;
  1116. end else
  1117. AncestorObj := nil;
  1118. if not Assigned(Component) then
  1119. begin
  1120. if Component <> AncestorObj then
  1121. begin
  1122. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  1123. Driver.WriteIdent('NIL');
  1124. Driver.EndProperty;
  1125. end
  1126. end
  1127. else if ((not (csSubComponent in Component.ComponentStyle))
  1128. or ((Component.Owner<>Instance) and (Component.Owner<>Nil))) then
  1129. begin
  1130. if (Component <> AncestorObj)
  1131. and not (csTransient in Component.ComponentStyle) then
  1132. begin
  1133. Name:= '';
  1134. C:= Component;
  1135. While (C<>Nil) and (C.Name<>'') do
  1136. begin
  1137. If (Name<>'') Then
  1138. Name:='.'+Name;
  1139. if C.Owner = LookupRoot then
  1140. begin
  1141. Name := C.Name+Name;
  1142. break;
  1143. end
  1144. else if C = LookupRoot then
  1145. begin
  1146. Name := 'Owner' + Name;
  1147. break;
  1148. end;
  1149. Name:=C.Name + Name;
  1150. C:= C.Owner;
  1151. end;
  1152. if (C=nil) and (Component.Owner=nil) then
  1153. if (Name<>'') then //foreign root
  1154. Name:=Name+'.Owner';
  1155. if Length(Name) > 0 then
  1156. begin
  1157. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  1158. WriteIdent(Name);
  1159. Driver.EndProperty;
  1160. end; // length Name>0
  1161. end; //(Component <> AncestorObj)
  1162. end;
  1163. end; //Assigned(IntfValue) and Supports(IntfValue,..
  1164. //else write NIL ?
  1165. end;
  1166. end;
  1167. end;
  1168. procedure TWriter.WriteRootComponent(ARoot: TComponent);
  1169. begin
  1170. WriteDescendent(ARoot, nil);
  1171. end;
  1172. procedure TWriter.WriteString(const Value: String);
  1173. begin
  1174. Driver.WriteString(Value);
  1175. end;
  1176. procedure TWriter.WriteWideString(const Value: WideString);
  1177. begin
  1178. Driver.WriteWideString(Value);
  1179. end;
  1180. procedure TWriter.WriteUnicodeString(const Value: UnicodeString);
  1181. begin
  1182. Driver.WriteUnicodeString(Value);
  1183. end;
  1184. { TAbstractObjectWriter }
  1185. procedure TAbstractObjectWriter.FlushBuffer;
  1186. begin
  1187. // Do nothing
  1188. end;