writer.inc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831
  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 Assigned(FAncestor) and FAncestor.InheritsFrom(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. begin
  519. if (not Assigned(PPropInfo(PropInfo)^.SetProc)) or
  520. (not Assigned(PPropInfo(PropInfo)^.GetProc)) then
  521. exit;
  522. { Check if the ancestor can be used }
  523. HasAncestor := Assigned(Ancestor) and ((Instance = Root) or
  524. (Instance.ClassType = Ancestor.ClassType));
  525. PropType := PPropInfo(PropInfo)^.PropType;
  526. case PropType^.Kind of
  527. tkInteger, tkChar, tkEnumeration, tkSet:
  528. begin
  529. Value := GetOrdProp(Instance, PropInfo);
  530. if HasAncestor then
  531. DefValue := GetOrdProp(Ancestor, PropInfo)
  532. else
  533. DefValue := PPropInfo(PropInfo)^.Default;
  534. if Value <> DefValue then
  535. begin
  536. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  537. case PropType^.Kind of
  538. tkInteger:
  539. begin
  540. // Check if this integer has a string identifier
  541. IntToIdentFn := FindIntToIdent(PPropInfo(PropInfo)^.PropType);
  542. if Assigned(IntToIdentFn) and IntToIdentFn(Value, Ident) then
  543. // Integer can be written a human-readable identifier
  544. WriteIdent(Ident)
  545. else
  546. // Integer has to be written just as number
  547. WriteInteger(Value);
  548. end;
  549. tkChar:
  550. WriteChar(Chr(Value));
  551. tkSet:
  552. Driver.WriteSet(Value, GetTypeData(PropType)^.CompType);
  553. tkEnumeration:
  554. WriteIdent(GetEnumName(PropType, Value));
  555. end;
  556. Driver.EndProperty;
  557. end;
  558. end;
  559. tkFloat:
  560. begin
  561. FloatValue := GetFloatProp(Instance, PropInfo);
  562. if HasAncestor then
  563. DefFloatValue := GetFloatProp(Ancestor, PropInfo)
  564. else
  565. DefFloatValue := 0;
  566. if FloatValue <> DefFloatValue then
  567. begin
  568. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  569. WriteFloat(FloatValue);
  570. Driver.EndProperty;
  571. end;
  572. end;
  573. tkMethod:
  574. begin
  575. MethodValue := GetMethodProp(Instance, PropInfo);
  576. if HasAncestor then
  577. DefMethodCodeValue := GetMethodProp(Ancestor, PropInfo).Code
  578. else
  579. DefMethodCodeValue := nil;
  580. if (MethodValue.Code <> DefMethodCodeValue) and
  581. ((not Assigned(MethodValue.Code)) or
  582. ((Length(FLookupRoot.MethodName(MethodValue.Code)) >= 0))) then
  583. begin
  584. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  585. if Assigned(MethodValue.Code) then
  586. Driver.WriteMethodName(FLookupRoot.MethodName(MethodValue.Code))
  587. else
  588. Driver.WriteMethodName('');
  589. Driver.EndProperty;
  590. end;
  591. end;
  592. tkSString, tkLString, tkAString, tkWString:
  593. // !!!: Can we really handle WideStrings here?
  594. begin
  595. StrValue := GetStrProp(Instance, PropInfo);
  596. if HasAncestor then
  597. DefStrValue := GetStrProp(Ancestor, PropInfo)
  598. else
  599. SetLength(DefStrValue, 0);
  600. if StrValue <> DefStrValue then
  601. begin
  602. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  603. WriteString(StrValue);
  604. Driver.EndProperty;
  605. end;
  606. end;
  607. {!!!: tkVariant:}
  608. tkClass:
  609. begin
  610. ObjValue := TObject(GetOrdProp(Instance, PropInfo));
  611. if HasAncestor then
  612. begin
  613. AncestorObj := TObject(GetOrdProp(Ancestor, PropInfo));
  614. if Assigned(AncestorObj) then
  615. if Assigned(ObjValue) and
  616. (TComponent(AncestorObj).Owner = FRootAncestor) and
  617. (TComponent(ObjValue).Owner = Root) and
  618. (UpperCase(TComponent(AncestorObj).Name) = UpperCase(TComponent(ObjValue).Name)) then
  619. AncestorObj := ObjValue
  620. else
  621. AncestorObj := nil;
  622. end else
  623. AncestorObj := nil;
  624. if (not Assigned(ObjValue)) and (ObjValue <> AncestorObj) then
  625. begin
  626. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  627. Driver.WriteIdent('NIL');
  628. Driver.EndProperty;
  629. end else if ObjValue.InheritsFrom(TPersistent) then
  630. if ObjValue.InheritsFrom(TComponent) then
  631. begin
  632. Component := TComponent(ObjValue);
  633. if ObjValue <> AncestorObj then
  634. begin
  635. { Determine the correct name of the component this property contains }
  636. if Component.Owner = LookupRoot then
  637. Name := Component.Name
  638. else if Component = LookupRoot then
  639. Name := 'Owner'
  640. else if Assigned(Component.Owner) and (Length(Component.Owner.Name) > 0)
  641. and (Length(Component.Name) > 0) then
  642. Name := Component.Owner.Name + '.' + Component.Name
  643. else if Length(Component.Name) > 0 then
  644. Name := Component.Name + '.Owner'
  645. else
  646. SetLength(Name, 0);
  647. if Length(Name) > 0 then
  648. begin
  649. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  650. WriteIdent(Name);
  651. Driver.EndProperty;
  652. end;
  653. end;
  654. end else if ObjValue.InheritsFrom(TCollection) then
  655. begin
  656. if (not HasAncestor) or (not CollectionsEqual(TCollection(ObjValue),
  657. TCollection(GetOrdProp(Ancestor, PropInfo)))) then
  658. begin
  659. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  660. SavedPropPath := FPropPath;
  661. try
  662. SetLength(FPropPath, 0);
  663. WriteCollection(TCollection(ObjValue));
  664. finally
  665. FPropPath := SavedPropPath;
  666. Driver.EndProperty;
  667. end;
  668. end;
  669. end else
  670. begin
  671. SavedAncestor := Ancestor;
  672. SavedPropPath := FPropPath;
  673. try
  674. FPropPath := FPropPath + PPropInfo(PropInfo)^.Name + '.';
  675. if HasAncestor then
  676. Ancestor := TPersistent(GetOrdProp(Ancestor, PropInfo));
  677. WriteProperties(TPersistent(ObjValue));
  678. finally
  679. Ancestor := SavedAncestor;
  680. FPropPath := SavedPropPath;
  681. end;
  682. end;
  683. end;
  684. tkInt64:
  685. begin
  686. Int64Value := GetInt64Prop(Instance, PropInfo);
  687. if HasAncestor then
  688. DefInt64Value := GetInt64Prop(Ancestor, PropInfo)
  689. else
  690. DefInt64Value := 0;
  691. if Int64Value <> DefInt64Value then
  692. begin
  693. Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
  694. WriteInteger(Int64Value);
  695. Driver.EndProperty;
  696. end;
  697. end;
  698. end;
  699. end;
  700. procedure TWriter.WriteRootComponent(ARoot: TComponent);
  701. begin
  702. WriteDescendent(ARoot, nil);
  703. end;
  704. procedure TWriter.WriteString(const Value: String);
  705. begin
  706. Driver.WriteString(Value);
  707. end;
  708. {!!!: procedure TWriter.WriteWideString(const Value: WideString);
  709. begin
  710. Driver.WriteWideString(Value);
  711. end;}
  712. {
  713. $Log$
  714. Revision 1.1 2000-07-13 06:31:32 michael
  715. + Initial import
  716. Revision 1.7 2000/06/29 16:29:23 sg
  717. * Implemented streaming. Note: The writer driver interface is stable, but
  718. the reader interface is not final yet!
  719. Revision 1.6 2000/01/07 01:24:33 peter
  720. * updated copyright to 2000
  721. Revision 1.5 2000/01/06 01:20:33 peter
  722. * moved out of packages/ back to topdir
  723. Revision 1.2 2000/01/04 18:07:16 michael
  724. + Streaming implemented
  725. Revision 1.3 1999/09/13 08:35:16 fcl
  726. * Changed some argument names (Root->ARoot etc.) because the new compiler
  727. now performs more ambiguity checks (sg)
  728. Revision 1.2 1999/04/08 10:18:58 peter
  729. * makefile updates
  730. }