writer.inc 36 KB

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