writer.inc 36 KB

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