writer.inc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835
  1. {
  2. $Id$
  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. constructor TBinaryObjectWriter.Create(Stream: TStream; BufSize: Integer);
  15. begin
  16. inherited Create;
  17. FStream := Stream;
  18. FBufSize := BufSize;
  19. GetMem(FBuffer, BufSize);
  20. end;
  21. destructor TBinaryObjectWriter.Destroy;
  22. begin
  23. // Flush all data which hasn't been written yet
  24. FlushBuffer;
  25. if Assigned(FBuffer) then
  26. FreeMem(FBuffer, FBufSize);
  27. inherited Destroy;
  28. end;
  29. procedure TBinaryObjectWriter.BeginCollection;
  30. begin
  31. WriteValue(vaCollection);
  32. end;
  33. procedure TBinaryObjectWriter.BeginComponent(Component: TComponent;
  34. Flags: TFilerFlags; ChildPos: Integer);
  35. var
  36. Prefix: Byte;
  37. begin
  38. if not FSignatureWritten then
  39. begin
  40. Write(FilerSignature, SizeOf(FilerSignature));
  41. FSignatureWritten := True;
  42. end;
  43. { Only write the flags if they are needed! }
  44. if Flags <> [] then
  45. begin
  46. Prefix := Integer(Flags) or $f0;
  47. Write(Prefix, 1);
  48. if ffChildPos in Flags then
  49. WriteInteger(ChildPos);
  50. end;
  51. WriteStr(Component.ClassName);
  52. WriteStr(Component.Name);
  53. end;
  54. procedure TBinaryObjectWriter.BeginList;
  55. begin
  56. WriteValue(vaList);
  57. end;
  58. procedure TBinaryObjectWriter.EndList;
  59. begin
  60. WriteValue(vaNull);
  61. end;
  62. procedure TBinaryObjectWriter.BeginProperty(const PropName: String);
  63. begin
  64. WriteStr(PropName);
  65. end;
  66. procedure TBinaryObjectWriter.EndProperty;
  67. begin
  68. end;
  69. procedure TBinaryObjectWriter.WriteBinary(const Buffer; Count: LongInt);
  70. begin
  71. WriteValue(vaBinary);
  72. Write(Count, 4);
  73. Write(Buffer, Count);
  74. end;
  75. procedure TBinaryObjectWriter.WriteBoolean(Value: Boolean);
  76. begin
  77. if Value then
  78. WriteValue(vaTrue)
  79. else
  80. WriteValue(vaFalse);
  81. end;
  82. procedure TBinaryObjectWriter.WriteFloat(const Value: Extended);
  83. begin
  84. WriteValue(vaExtended);
  85. Write(Value, SizeOf(Value));
  86. end;
  87. procedure TBinaryObjectWriter.WriteSingle(const Value: Single);
  88. begin
  89. WriteValue(vaSingle);
  90. Write(Value, SizeOf(Value));
  91. end;
  92. {!!!: procedure TBinaryObjectWriter.WriteCurrency(const Value: Currency);
  93. begin
  94. WriteValue(vaCurrency);
  95. Write(Value, SizeOf(Value));
  96. end;}
  97. procedure TBinaryObjectWriter.WriteDate(const Value: TDateTime);
  98. begin
  99. WriteValue(vaDate);
  100. Write(Value, SizeOf(Value));
  101. end;
  102. procedure TBinaryObjectWriter.WriteIdent(const Ident: string);
  103. begin
  104. { Check if Ident is a special identifier before trying to just write
  105. Ident directly }
  106. if UpperCase(Ident) = 'NIL' then
  107. WriteValue(vaNil)
  108. else if UpperCase(Ident) = 'FALSE' then
  109. WriteValue(vaFalse)
  110. else if UpperCase(Ident) = 'TRUE' then
  111. WriteValue(vaTrue)
  112. else if UpperCase(Ident) = 'NULL' then
  113. WriteValue(vaNull) else
  114. begin
  115. WriteValue(vaIdent);
  116. WriteStr(Ident);
  117. end;
  118. end;
  119. procedure TBinaryObjectWriter.WriteInteger(Value: Int64);
  120. begin
  121. { Use the smallest possible integer type for the given value: }
  122. if (Value >= -128) and (Value <= 127) then
  123. begin
  124. WriteValue(vaInt8);
  125. Write(Value, 1);
  126. end else if (Value >= -32768) and (Value <= 32767) then
  127. begin
  128. WriteValue(vaInt16);
  129. Write(Value, 2);
  130. end else if (Value >= -$80000000) and (Value <= $7fffffff) then
  131. begin
  132. WriteValue(vaInt32);
  133. Write(Value, 4);
  134. end else
  135. begin
  136. WriteValue(vaInt64);
  137. Write(Value, 8);
  138. end;
  139. end;
  140. procedure TBinaryObjectWriter.WriteMethodName(const Name: String);
  141. begin
  142. if Length(Name) > 0 then
  143. begin
  144. WriteValue(vaIdent);
  145. WriteStr(Name);
  146. end else
  147. WriteValue(vaNil);
  148. end;
  149. procedure TBinaryObjectWriter.WriteSet(Value: LongInt; SetType: Pointer);
  150. var
  151. i: Integer;
  152. Mask: LongInt;
  153. begin
  154. WriteValue(vaSet);
  155. Mask := 1;
  156. for i := 0 to 31 do
  157. begin
  158. if (Value and Mask) <> 0 then
  159. WriteStr(GetEnumName(PTypeInfo(SetType), i));
  160. Mask := Mask shl 1;
  161. end;
  162. WriteStr('');
  163. end;
  164. procedure TBinaryObjectWriter.WriteString(const Value: String);
  165. var
  166. i: Integer;
  167. begin
  168. i := Length(Value);
  169. if i <= 255 then
  170. begin
  171. WriteValue(vaString);
  172. Write(i, 1);
  173. end else
  174. begin
  175. WriteValue(vaLString);
  176. Write(i, 4);
  177. end;
  178. if i > 0 then
  179. Write(Value[1], i);
  180. end;
  181. {!!!: procedure TBinaryObjectWriter.WriteWideString(const Value: WideString);
  182. var
  183. i: Integer;
  184. begin
  185. WriteValue(vaWString);
  186. i := Length(Value);
  187. Write(i, 4);
  188. Write(Value[1], i * 2);
  189. end;}
  190. procedure TBinaryObjectWriter.FlushBuffer;
  191. begin
  192. FStream.WriteBuffer(FBuffer^, FBufPos);
  193. FBufPos := 0;
  194. end;
  195. procedure TBinaryObjectWriter.Write(const Buffer; Count: LongInt);
  196. var
  197. CopyNow: LongInt;
  198. begin
  199. while Count > 0 do
  200. begin
  201. CopyNow := Count;
  202. if CopyNow > FBufSize - FBufPos then
  203. CopyNow := FBufSize - FBufPos;
  204. Move(Buffer, PChar(FBuffer)[FBufPos], CopyNow);
  205. Dec(Count, CopyNow);
  206. Inc(FBufPos, CopyNow);
  207. if FBufPos = FBufSize then
  208. FlushBuffer;
  209. end;
  210. end;
  211. procedure TBinaryObjectWriter.WriteValue(Value: TValueType);
  212. begin
  213. Write(Value, 1);
  214. end;
  215. procedure TBinaryObjectWriter.WriteStr(const Value: String);
  216. var
  217. i: Integer;
  218. begin
  219. i := Length(Value);
  220. if i > 255 then
  221. i := 255;
  222. Write(i, 1);
  223. if i > 0 then
  224. Write(Value[1], i);
  225. end;
  226. {****************************************************************************}
  227. {* TWriter *}
  228. {****************************************************************************}
  229. constructor TWriter.Create(ADriver: TAbstractObjectWriter);
  230. begin
  231. inherited Create;
  232. FDriver := ADriver;
  233. end;
  234. constructor TWriter.Create(Stream: TStream; BufSize: Integer);
  235. begin
  236. inherited Create;
  237. FDriver := TBinaryObjectWriter.Create(Stream, BufSize);
  238. FDestroyDriver := True;
  239. end;
  240. destructor TWriter.Destroy;
  241. begin
  242. if FDestroyDriver then
  243. FDriver.Free;
  244. inherited Destroy;
  245. end;
  246. // Used as argument for calls to TComponent.GetChildren:
  247. procedure TWriter.AddToAncestorList(Component: TComponent);
  248. begin
  249. FAncestorList.Add(Component);
  250. end;
  251. procedure TWriter.DefineProperty(const Name: String;
  252. ReadData: TReaderProc; AWriteData: TWriterProc; HasData: Boolean);
  253. begin
  254. if HasData and Assigned(AWriteData) then
  255. begin
  256. // Write the property name and then the data itself
  257. Driver.BeginProperty(FPropPath + Name);
  258. AWriteData(Self);
  259. Driver.EndProperty;
  260. end;
  261. end;
  262. procedure TWriter.DefineBinaryProperty(const Name: String;
  263. ReadData, AWriteData: TStreamProc; HasData: Boolean);
  264. begin
  265. if HasData and Assigned(AWriteData) then
  266. begin
  267. // Write the property name and then the data itself
  268. Driver.BeginProperty(FPropPath + Name);
  269. WriteBinary(AWriteData);
  270. Driver.EndProperty;
  271. end;
  272. end;
  273. procedure TWriter.SetRoot(ARoot: TComponent);
  274. begin
  275. inherited SetRoot(ARoot);
  276. // Use the new root as lookup root too
  277. FLookupRoot := ARoot;
  278. end;
  279. procedure TWriter.WriteBinary(AWriteData: TStreamProc);
  280. var
  281. MemBuffer: TMemoryStream;
  282. BufferSize: Longint;
  283. begin
  284. { First write the binary data into a memory stream, then copy this buffered
  285. stream into the writing destination. This is necessary as we have to know
  286. the size of the binary data in advance (we're assuming that seeking within
  287. the writer stream is not possible) }
  288. MemBuffer := TMemoryStream.Create;
  289. try
  290. AWriteData(MemBuffer);
  291. BufferSize := MemBuffer.Size;
  292. Driver.WriteBinary(MemBuffer.Memory^, BufferSize);
  293. finally
  294. MemBuffer.Free;
  295. end;
  296. end;
  297. procedure TWriter.WriteBoolean(Value: Boolean);
  298. begin
  299. Driver.WriteBoolean(Value);
  300. end;
  301. procedure TWriter.WriteChar(Value: Char);
  302. begin
  303. WriteString(Value);
  304. end;
  305. procedure TWriter.WriteCollection(Value: TCollection);
  306. var
  307. i: Integer;
  308. begin
  309. Driver.BeginCollection;
  310. if Assigned(Value) then
  311. for i := 0 to Value.Count - 1 do
  312. begin
  313. { Each collection item needs its own ListBegin/ListEnd tag, or else the
  314. reader wouldn't be able to know where an item ends and where the next
  315. one starts }
  316. WriteListBegin;
  317. WriteProperties(Value.Items[i]);
  318. WriteListEnd;
  319. end;
  320. WriteListEnd;
  321. end;
  322. procedure TWriter.WriteComponent(Component: TComponent);
  323. var
  324. SavedAncestor: TPersistent;
  325. SavedRootAncestor, AncestorComponent, CurAncestor: TComponent;
  326. i: Integer;
  327. s: String;
  328. begin
  329. SavedAncestor := Ancestor;
  330. SavedRootAncestor := RootAncestor;
  331. try
  332. // The component has to know that it is being written now...
  333. Include(Component.FComponentState, csWriting);
  334. // Locate the component in the ancestor list, if necessary
  335. if Assigned(FAncestorList) then
  336. begin
  337. Ancestor := nil;
  338. s := UpperCase(Component.Name);
  339. for i := 0 to FAncestorList.Count - 1 do
  340. begin
  341. CurAncestor := TComponent(FAncestorList[i]);
  342. if UpperCase(CurAncestor.Name) = s then
  343. begin
  344. Ancestor := CurAncestor;
  345. break;
  346. end;
  347. end;
  348. end;
  349. // Do we have to call the OnFindAncestor callback?
  350. if Assigned(FOnFindAncestor) and
  351. ((not Assigned(Ancestor)) or Ancestor.InheritsFrom(TComponent)) then
  352. begin
  353. AncestorComponent := TComponent(Ancestor);
  354. FOnFindAncestor(Self, Component, Component.Name,
  355. AncestorComponent, FRootAncestor);
  356. Ancestor := AncestorComponent;
  357. end;
  358. // Finally write the component state
  359. Component.WriteState(Self);
  360. // The writing has been finished now...
  361. Exclude(Component.FComponentState, csWriting);
  362. finally
  363. Ancestor := SavedAncestor;
  364. FRootAncestor := SavedRootAncestor;
  365. end;
  366. end;
  367. procedure TWriter.WriteComponentData(Instance: TComponent);
  368. var
  369. SavedAncestorList: TList;
  370. SavedRoot, SavedRootAncestor: TComponent;
  371. SavedAncestorPos, SavedChildPos: Integer;
  372. Flags: TFilerFlags;
  373. begin
  374. // Determine the filer flags to store
  375. if Assigned(Ancestor) and ((not (csInline in Instance.ComponentState)) or
  376. ((csAncestor in Instance.ComponentState) and Assigned(FAncestorList))) then
  377. Flags := [ffInherited]
  378. else if csInline in Instance.ComponentState then
  379. Flags := [ffInline]
  380. else
  381. Flags := [];
  382. if Assigned(FAncestorList) and (FAncestorPos < FAncestorList.Count) and
  383. ((not Assigned(Ancestor)) or
  384. (TPersistent(FAncestorList[FAncestorPos]) <> Ancestor)) then
  385. Include(Flags, ffChildPos);
  386. Driver.BeginComponent(Instance, Flags, FChildPos);
  387. if Assigned(FAncestorList) and (FAncestorPos < FAncestorList.Count) then
  388. begin
  389. if Assigned(Ancestor) then
  390. Inc(FAncestorPos);
  391. Inc(FChildPos);
  392. end;
  393. // Write property list
  394. WriteProperties(Instance);
  395. WriteListEnd;
  396. // Write children list
  397. SavedAncestorList := FAncestorList;
  398. SavedAncestorPos := FAncestorPos;
  399. SavedChildPos := FChildPos;
  400. SavedRoot := FRoot;
  401. SavedRootAncestor := FRootAncestor;
  402. try
  403. FAncestorList := nil;
  404. FAncestorPos := 0;
  405. FChildPos := 0;
  406. if not IgnoreChildren then
  407. try
  408. // Set up the ancestor list if we have an ancestor
  409. if FAncestor is TComponent then
  410. begin
  411. if csInline in TComponent(FAncestor).ComponentState then
  412. FRootAncestor := TComponent(FAncestor);
  413. FAncestorList := TList.Create;
  414. TComponent(FAncestor).GetChildren(@AddToAncestorList, FRootAncestor);
  415. end;
  416. if csInline in Instance.ComponentState then
  417. FRoot := Instance;
  418. Instance.GetChildren(@WriteComponent, FRoot);
  419. finally
  420. FAncestorList.Free;
  421. end;
  422. finally
  423. FAncestorList := SavedAncestorList;
  424. FAncestorPos := SavedAncestorPos;
  425. FChildPos := SavedChildPos;
  426. FRoot := SavedRoot;
  427. FRootAncestor := SavedRootAncestor;
  428. end;
  429. WriteListEnd;
  430. end;
  431. procedure TWriter.WriteDescendent(ARoot: TComponent; AAncestor: TComponent);
  432. begin
  433. FRoot := ARoot;
  434. FAncestor := AAncestor;
  435. FRootAncestor := AAncestor;
  436. FLookupRoot := ARoot;
  437. WriteComponent(ARoot);
  438. end;
  439. procedure TWriter.WriteFloat(const Value: Extended);
  440. begin
  441. Driver.WriteFloat(Value);
  442. end;
  443. procedure TWriter.WriteSingle(const Value: Single);
  444. begin
  445. Driver.WriteSingle(Value);
  446. end;
  447. {!!!: procedure TWriter.WriteCurrency(const Value: Currency);
  448. begin
  449. Driver.WriteCurrency(Value);
  450. end;}
  451. procedure TWriter.WriteDate(const Value: TDateTime);
  452. begin
  453. Driver.WriteDate(Value);
  454. end;
  455. procedure TWriter.WriteIdent(const Ident: string);
  456. begin
  457. Driver.WriteIdent(Ident);
  458. end;
  459. procedure TWriter.WriteInteger(Value: LongInt);
  460. begin
  461. Driver.WriteInteger(Value);
  462. end;
  463. procedure TWriter.WriteInteger(Value: Int64);
  464. begin
  465. Driver.WriteInteger(Value);
  466. end;
  467. procedure TWriter.WriteListBegin;
  468. begin
  469. Driver.BeginList;
  470. end;
  471. procedure TWriter.WriteListEnd;
  472. begin
  473. Driver.EndList;
  474. end;
  475. procedure TWriter.WriteProperties(Instance: TPersistent);
  476. var
  477. i, PropCount: Integer;
  478. PropInfo: PPropInfo;
  479. PropList: PPropList;
  480. begin
  481. { First step: Write the properties given by the RTTI for Instance }
  482. PropCount := GetTypeData(Instance.ClassInfo)^.PropCount;
  483. if PropCount > 0 then
  484. begin
  485. GetMem(PropList, PropCount * SizeOf(PPropInfo));
  486. try
  487. GetPropInfos(Instance.ClassInfo, PropList);
  488. for i := 0 to PropCount - 1 do
  489. begin
  490. PropInfo := PropList^[i];
  491. if IsStoredProp(Instance, PropInfo) then
  492. WriteProperty(Instance, PropInfo);
  493. end;
  494. finally
  495. FreeMem(PropList);
  496. end;
  497. end;
  498. { Second step: Give Instance the chance to write its own private data }
  499. Instance.DefineProperties(Self);
  500. end;
  501. procedure TWriter.WriteProperty(Instance: TPersistent; PropInfo: Pointer);
  502. var
  503. HasAncestor: Boolean;
  504. PropType: PTypeInfo;
  505. Value, DefValue: LongInt;
  506. Ident: String;
  507. IntToIdentFn: TIntToIdent;
  508. FloatValue, DefFloatValue: Extended;
  509. MethodValue: TMethod;
  510. DefMethodCodeValue: Pointer;
  511. StrValue, DefStrValue: String;
  512. AncestorObj: TObject;
  513. Component: TComponent;
  514. ObjValue: TObject;
  515. SavedAncestor: TPersistent;
  516. SavedPropPath, Name: String;
  517. Int64Value, DefInt64Value: Int64;
  518. BoolValue, DefBoolValue: boolean;
  519. begin
  520. if (not Assigned(PPropInfo(PropInfo)^.SetProc)) or
  521. (not Assigned(PPropInfo(PropInfo)^.GetProc)) then
  522. exit;
  523. { Check if the ancestor can be used }
  524. HasAncestor := Assigned(Ancestor) and ((Instance = Root) or
  525. (Instance.ClassType = Ancestor.ClassType));
  526. PropType := PPropInfo(PropInfo)^.PropType;
  527. case PropType^.Kind of
  528. tkInteger, tkChar, tkEnumeration, tkSet:
  529. begin
  530. Value := GetOrdProp(Instance, PropInfo);
  531. if HasAncestor then
  532. DefValue := GetOrdProp(Ancestor, PropInfo)
  533. else
  534. DefValue := PPropInfo(PropInfo)^.Default;
  535. if Value <> DefValue then
  536. begin
  537. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  538. case PropType^.Kind of
  539. tkInteger:
  540. begin
  541. // Check if this integer has a string identifier
  542. IntToIdentFn := FindIntToIdent(PPropInfo(PropInfo)^.PropType);
  543. if Assigned(IntToIdentFn) and IntToIdentFn(Value, Ident) then
  544. // Integer can be written a human-readable identifier
  545. WriteIdent(Ident)
  546. else
  547. // Integer has to be written just as number
  548. WriteInteger(Value);
  549. end;
  550. tkChar:
  551. WriteChar(Chr(Value));
  552. tkSet:
  553. Driver.WriteSet(Value, GetTypeData(PropType)^.CompType);
  554. tkEnumeration:
  555. WriteIdent(GetEnumName(PropType, Value));
  556. end;
  557. Driver.EndProperty;
  558. end;
  559. end;
  560. tkFloat:
  561. begin
  562. FloatValue := GetFloatProp(Instance, PropInfo);
  563. if HasAncestor then
  564. DefFloatValue := GetFloatProp(Ancestor, PropInfo)
  565. else
  566. DefFloatValue := 0;
  567. if FloatValue <> DefFloatValue then
  568. begin
  569. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  570. WriteFloat(FloatValue);
  571. Driver.EndProperty;
  572. end;
  573. end;
  574. tkMethod:
  575. begin
  576. MethodValue := GetMethodProp(Instance, PropInfo);
  577. if HasAncestor then
  578. DefMethodCodeValue := GetMethodProp(Ancestor, PropInfo).Code
  579. else
  580. DefMethodCodeValue := nil;
  581. if (MethodValue.Code <> DefMethodCodeValue) and
  582. ((not Assigned(MethodValue.Code)) or
  583. ((Length(FLookupRoot.MethodName(MethodValue.Code)) >= 0))) then
  584. begin
  585. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  586. if Assigned(MethodValue.Code) then
  587. Driver.WriteMethodName(FLookupRoot.MethodName(MethodValue.Code))
  588. else
  589. Driver.WriteMethodName('');
  590. Driver.EndProperty;
  591. end;
  592. end;
  593. tkSString, tkLString, tkAString, tkWString:
  594. // !!!: Can we really handle WideStrings here?
  595. begin
  596. StrValue := GetStrProp(Instance, PropInfo);
  597. if HasAncestor then
  598. DefStrValue := GetStrProp(Ancestor, PropInfo)
  599. else
  600. SetLength(DefStrValue, 0);
  601. if StrValue <> DefStrValue then
  602. begin
  603. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  604. WriteString(StrValue);
  605. Driver.EndProperty;
  606. end;
  607. end;
  608. {!!!: tkVariant:}
  609. tkClass:
  610. begin
  611. ObjValue := TObject(GetOrdProp(Instance, PropInfo));
  612. if HasAncestor then
  613. begin
  614. AncestorObj := TObject(GetOrdProp(Ancestor, PropInfo));
  615. if Assigned(AncestorObj) then
  616. if Assigned(ObjValue) and
  617. (TComponent(AncestorObj).Owner = FRootAncestor) and
  618. (TComponent(ObjValue).Owner = Root) and
  619. (UpperCase(TComponent(AncestorObj).Name) = UpperCase(TComponent(ObjValue).Name)) then
  620. AncestorObj := ObjValue
  621. else
  622. AncestorObj := nil;
  623. end else
  624. AncestorObj := nil;
  625. if not Assigned(ObjValue) then
  626. begin
  627. if ObjValue <> AncestorObj then
  628. begin
  629. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  630. Driver.WriteIdent('NIL');
  631. Driver.EndProperty;
  632. end
  633. end else if ObjValue.InheritsFrom(TPersistent) then
  634. if ObjValue.InheritsFrom(TComponent) then
  635. begin
  636. Component := TComponent(ObjValue);
  637. if ObjValue <> AncestorObj then
  638. begin
  639. { Determine the correct name of the component this property contains }
  640. if Component.Owner = LookupRoot then
  641. Name := Component.Name
  642. else if Component = LookupRoot then
  643. Name := 'Owner'
  644. else if Assigned(Component.Owner) and (Length(Component.Owner.Name) > 0)
  645. and (Length(Component.Name) > 0) then
  646. Name := Component.Owner.Name + '.' + Component.Name
  647. else if Length(Component.Name) > 0 then
  648. Name := Component.Name + '.Owner'
  649. else
  650. SetLength(Name, 0);
  651. if Length(Name) > 0 then
  652. begin
  653. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  654. WriteIdent(Name);
  655. Driver.EndProperty;
  656. end;
  657. end;
  658. end else if ObjValue.InheritsFrom(TCollection) then
  659. begin
  660. if (not HasAncestor) or (not CollectionsEqual(TCollection(ObjValue),
  661. TCollection(GetOrdProp(Ancestor, PropInfo)))) then
  662. begin
  663. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  664. SavedPropPath := FPropPath;
  665. try
  666. SetLength(FPropPath, 0);
  667. WriteCollection(TCollection(ObjValue));
  668. finally
  669. FPropPath := SavedPropPath;
  670. Driver.EndProperty;
  671. end;
  672. end;
  673. end else
  674. begin
  675. SavedAncestor := Ancestor;
  676. SavedPropPath := FPropPath;
  677. try
  678. FPropPath := FPropPath + PPropInfo(PropInfo)^.Name + '.';
  679. if HasAncestor then
  680. Ancestor := TPersistent(GetOrdProp(Ancestor, PropInfo));
  681. WriteProperties(TPersistent(ObjValue));
  682. finally
  683. Ancestor := SavedAncestor;
  684. FPropPath := SavedPropPath;
  685. end;
  686. end;
  687. end;
  688. tkInt64:
  689. begin
  690. Int64Value := GetInt64Prop(Instance, PropInfo);
  691. if HasAncestor then
  692. DefInt64Value := GetInt64Prop(Ancestor, PropInfo)
  693. else
  694. DefInt64Value := 0;
  695. if Int64Value <> DefInt64Value then
  696. begin
  697. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  698. WriteInteger(Int64Value);
  699. Driver.EndProperty;
  700. end;
  701. end;
  702. tkBool:
  703. begin
  704. BoolValue := GetOrdProp(Instance, PropInfo)<>0;
  705. if HasAncestor then
  706. DefBoolValue := GetOrdProp(Ancestor, PropInfo)<>0
  707. else
  708. DefBoolValue := PPropInfo(PropInfo)^.Default<>0;
  709. if BoolValue <> DefBoolValue then
  710. begin
  711. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  712. WriteBoolean(BoolValue);
  713. Driver.EndProperty;
  714. end;
  715. end;
  716. end;
  717. end;
  718. procedure TWriter.WriteRootComponent(ARoot: TComponent);
  719. begin
  720. WriteDescendent(ARoot, nil);
  721. end;
  722. procedure TWriter.WriteString(const Value: String);
  723. begin
  724. Driver.WriteString(Value);
  725. end;
  726. {!!!: procedure TWriter.WriteWideString(const Value: WideString);
  727. begin
  728. Driver.WriteWideString(Value);
  729. end;}
  730. {
  731. $Log$
  732. Revision 1.6 2002-09-07 15:15:26 peter
  733. * old logs removed and tabs fixed
  734. Revision 1.5 2002/09/04 13:33:58 michael
  735. Fix from Mattias Gaertner, boolean streaming now respects default
  736. Revision 1.4 2002/09/03 06:02:57 michael
  737. + Applied patch from Matthias Gaertner to stream booleans
  738. }