writer.inc 31 KB

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